[llvm] r358552 - Revert "Temporarily Revert "Add basic loop fusion pass.""

Eric Christopher via llvm-commits llvm-commits at lists.llvm.org
Tue Apr 16 21:53:01 PDT 2019


Added: llvm/trunk/test/Transforms/InstCombine/icmp-range.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/icmp-range.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/icmp-range.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/icmp-range.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,150 @@
+; RUN: opt < %s -instcombine -S | FileCheck %s
+; These should be InstSimplify checks, but most of the code
+; is currently only in InstCombine.  TODO: move supporting code
+
+; Definitely out of range
+define i1 @test_nonzero(i32* nocapture readonly %arg) {
+; CHECK-LABEL:test_nonzero
+; CHECK: ret i1 true
+  %val = load i32, i32* %arg, !range !0
+  %rval = icmp ne i32 %val, 0
+  ret i1 %rval
+}
+define i1 @test_nonzero2(i32* nocapture readonly %arg) {
+; CHECK-LABEL:test_nonzero2
+; CHECK: ret i1 false
+  %val = load i32, i32* %arg, !range !0
+  %rval = icmp eq i32 %val, 0
+  ret i1 %rval
+}
+
+; Potentially in range
+define i1 @test_nonzero3(i32* nocapture readonly %arg) {
+; CHECK-LABEL: test_nonzero3
+; Check that this does not trigger - it wouldn't be legal
+; CHECK: icmp
+  %val = load i32, i32* %arg, !range !1
+  %rval = icmp ne i32 %val, 0
+  ret i1 %rval
+}
+
+; Definitely in range
+define i1 @test_nonzero4(i8* nocapture readonly %arg) {
+; CHECK-LABEL: test_nonzero4
+; CHECK: ret i1 false
+  %val = load i8, i8* %arg, !range !2
+  %rval = icmp ne i8 %val, 0
+  ret i1 %rval
+}
+
+define i1 @test_nonzero5(i8* nocapture readonly %arg) {
+; CHECK-LABEL: test_nonzero5
+; CHECK: ret i1 false
+  %val = load i8, i8* %arg, !range !2
+  %rval = icmp ugt i8 %val, 0
+  ret i1 %rval
+}
+
+; Cheaper checks (most values in range meet requirements)
+define i1 @test_nonzero6(i8* %argw) {
+; CHECK-LABEL: test_nonzero6
+; CHECK: icmp ne i8 %val, 0
+  %val = load i8, i8* %argw, !range !3
+  %rval = icmp sgt i8 %val, 0
+  ret i1 %rval
+}
+
+; Constant not in range, should return true.
+define i1 @test_not_in_range(i32* nocapture readonly %arg) {
+; CHECK-LABEL: test_not_in_range
+; CHECK: ret i1 true
+  %val = load i32, i32* %arg, !range !0
+  %rval = icmp ne i32 %val, 6
+  ret i1 %rval
+}
+
+; Constant in range, can not fold.
+define i1 @test_in_range(i32* nocapture readonly %arg) {
+; CHECK-LABEL: test_in_range
+; CHECK: icmp ne i32 %val, 3
+  %val = load i32, i32* %arg, !range !0
+  %rval = icmp ne i32 %val, 3
+  ret i1 %rval
+}
+
+; Values in range greater than constant.
+define i1 @test_range_sgt_constant(i32* nocapture readonly %arg) {
+; CHECK-LABEL: test_range_sgt_constant
+; CHECK: ret i1 true
+  %val = load i32, i32* %arg, !range !0
+  %rval = icmp sgt i32 %val, 0
+  ret i1 %rval
+}
+
+; Values in range less than constant.
+define i1 @test_range_slt_constant(i32* nocapture readonly %arg) {
+; CHECK-LABEL: test_range_slt_constant
+; CHECK: ret i1 false
+  %val = load i32, i32* %arg, !range !0
+  %rval = icmp sgt i32 %val, 6
+  ret i1 %rval
+}
+
+; Values in union of multiple sub ranges not equal to constant.
+define i1 @test_multi_range1(i32* nocapture readonly %arg) {
+; CHECK-LABEL: test_multi_range1
+; CHECK: ret i1 true
+  %val = load i32, i32* %arg, !range !4
+  %rval = icmp ne i32 %val, 0
+  ret i1 %rval
+}
+
+; Values in multiple sub ranges not equal to constant, but in
+; union of sub ranges could possibly equal to constant. This
+; in theory could also be folded and might be implemented in 
+; the future if shown profitable in practice.
+define i1 @test_multi_range2(i32* nocapture readonly %arg) {
+; CHECK-LABEL: test_multi_range2
+; CHECK: icmp ne i32 %val, 7
+  %val = load i32, i32* %arg, !range !4
+  %rval = icmp ne i32 %val, 7
+  ret i1 %rval
+}
+
+; Values' ranges overlap each other, so it can not be simplified.
+define i1 @test_two_ranges(i32* nocapture readonly %arg1, i32* nocapture readonly %arg2) {
+; CHECK-LABEL: test_two_ranges
+; CHECK: icmp ult i32 %val2, %val1
+  %val1 = load i32, i32* %arg1, !range !5
+  %val2 = load i32, i32* %arg2, !range !6
+  %rval = icmp ult i32 %val2, %val1
+  ret i1 %rval
+}
+
+; Values' ranges do not overlap each other, so it can simplified to false.
+define i1 @test_two_ranges2(i32* nocapture readonly %arg1, i32* nocapture readonly %arg2) {
+; CHECK-LABEL: test_two_ranges2
+; CHECK: ret i1 false
+  %val1 = load i32, i32* %arg1, !range !0
+  %val2 = load i32, i32* %arg2, !range !6
+  %rval = icmp ult i32 %val2, %val1
+  ret i1 %rval
+}
+
+; Values' ranges do not overlap each other, so it can simplified to true.
+define i1 @test_two_ranges3(i32* nocapture readonly %arg1, i32* nocapture readonly %arg2) {
+; CHECK-LABEL: test_two_ranges3
+; CHECK: ret i1 true
+  %val1 = load i32, i32* %arg1, !range !0
+  %val2 = load i32, i32* %arg2, !range !6
+  %rval = icmp ugt i32 %val2, %val1
+  ret i1 %rval
+}
+
+!0 = !{i32 1, i32 6} 
+!1 = !{i32 0, i32 6} 
+!2 = !{i8 0, i8 1} 
+!3 = !{i8 0, i8 6} 
+!4 = !{i32 1, i32 6, i32 8, i32 10}
+!5 = !{i32 5, i32 10} 
+!6 = !{i32 8, i32 16} 

Added: llvm/trunk/test/Transforms/InstCombine/icmp-shl-nsw.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/icmp-shl-nsw.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/icmp-shl-nsw.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/icmp-shl-nsw.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,356 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt < %s -instcombine -S | FileCheck %s
+
+; If the (shl x, C) preserved the sign and this is a sign test,
+; compare the LHS operand instead
+
+define i1 @icmp_shl_nsw_sgt(i32 %x) {
+; CHECK-LABEL: @icmp_shl_nsw_sgt(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt i32 %x, 0
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %shl = shl nsw i32 %x, 21
+  %cmp = icmp sgt i32 %shl, 0
+  ret i1 %cmp
+}
+
+define i1 @icmp_shl_nsw_sge0(i32 %x) {
+; CHECK-LABEL: @icmp_shl_nsw_sge0(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt i32 %x, -1
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %shl = shl nsw i32 %x, 21
+  %cmp = icmp sge i32 %shl, 0
+  ret i1 %cmp
+}
+
+define i1 @icmp_shl_nsw_sge1(i32 %x) {
+; CHECK-LABEL: @icmp_shl_nsw_sge1(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt i32 %x, 0
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %shl = shl nsw i32 %x, 21
+  %cmp = icmp sge i32 %shl, 1
+  ret i1 %cmp
+}
+
+define <2 x i1> @icmp_shl_nsw_sge1_vec(<2 x i32> %x) {
+; CHECK-LABEL: @icmp_shl_nsw_sge1_vec(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt <2 x i32> %x, zeroinitializer
+; CHECK-NEXT:    ret <2 x i1> [[CMP]]
+;
+  %shl = shl nsw <2 x i32> %x, <i32 21, i32 21>
+  %cmp = icmp sge <2 x i32> %shl, <i32 1, i32 1>
+  ret <2 x i1> %cmp
+}
+
+; Checks for icmp (eq|ne) (shl x, C), 0
+
+define i1 @icmp_shl_nsw_eq(i32 %x) {
+; CHECK-LABEL: @icmp_shl_nsw_eq(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 %x, 0
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %mul = shl nsw i32 %x, 5
+  %cmp = icmp eq i32 %mul, 0
+  ret i1 %cmp
+}
+
+define <2 x i1> @icmp_shl_nsw_eq_vec(<2 x i32> %x) {
+; CHECK-LABEL: @icmp_shl_nsw_eq_vec(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq <2 x i32> %x, zeroinitializer
+; CHECK-NEXT:    ret <2 x i1> [[CMP]]
+;
+  %mul = shl nsw <2 x i32> %x, <i32 5, i32 5>
+  %cmp = icmp eq <2 x i32> %mul, zeroinitializer
+  ret <2 x i1> %cmp
+}
+
+; icmp sgt with shl nsw with a constant compare operand and constant
+; shift amount can always be reduced to icmp sgt alone.
+
+; Known bits analysis turns this into an equality predicate.
+
+define i1 @icmp_sgt1(i8 %x) {
+; CHECK-LABEL: @icmp_sgt1(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ne i8 %x, -64
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %shl = shl nsw i8 %x, 1
+  %cmp = icmp sgt i8 %shl, -128
+  ret i1 %cmp
+}
+
+define i1 @icmp_sgt2(i8 %x) {
+; CHECK-LABEL: @icmp_sgt2(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt i8 %x, -64
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %shl = shl nsw i8 %x, 1
+  %cmp = icmp sgt i8 %shl, -127
+  ret i1 %cmp
+}
+
+define i1 @icmp_sgt3(i8 %x) {
+; CHECK-LABEL: @icmp_sgt3(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt i8 %x, -8
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %shl = shl nsw i8 %x, 1
+  %cmp = icmp sgt i8 %shl, -16
+  ret i1 %cmp
+}
+
+define i1 @icmp_sgt4(i8 %x) {
+; CHECK-LABEL: @icmp_sgt4(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt i8 %x, -1
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %shl = shl nsw i8 %x, 1
+  %cmp = icmp sgt i8 %shl, -2
+  ret i1 %cmp
+}
+
+; x >s -1 is a sign bit test.
+; x >s 0 is a sign bit test.
+
+define i1 @icmp_sgt5(i8 %x) {
+; CHECK-LABEL: @icmp_sgt5(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt i8 %x, 0
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %shl = shl nsw i8 %x, 1
+  %cmp = icmp sgt i8 %shl, 1
+  ret i1 %cmp
+}
+
+define i1 @icmp_sgt6(i8 %x) {
+; CHECK-LABEL: @icmp_sgt6(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt i8 %x, 8
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %shl = shl nsw i8 %x, 1
+  %cmp = icmp sgt i8 %shl, 16
+  ret i1 %cmp
+}
+
+define i1 @icmp_sgt7(i8 %x) {
+; CHECK-LABEL: @icmp_sgt7(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt i8 %x, 62
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %shl = shl nsw i8 %x, 1
+  %cmp = icmp sgt i8 %shl, 124
+  ret i1 %cmp
+}
+
+; Known bits analysis turns this into an equality predicate.
+
+define i1 @icmp_sgt8(i8 %x) {
+; CHECK-LABEL: @icmp_sgt8(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i8 %x, 63
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %shl = shl nsw i8 %x, 1
+  %cmp = icmp sgt i8 %shl, 125
+  ret i1 %cmp
+}
+
+; Compares with 126 and 127 are recognized as always false.
+
+; Known bits analysis turns this into an equality predicate.
+
+define i1 @icmp_sgt9(i8 %x) {
+; CHECK-LABEL: @icmp_sgt9(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ne i8 %x, -1
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %shl = shl nsw i8 %x, 7
+  %cmp = icmp sgt i8 %shl, -128
+  ret i1 %cmp
+}
+
+define i1 @icmp_sgt10(i8 %x) {
+; CHECK-LABEL: @icmp_sgt10(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt i8 %x, -1
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %shl = shl nsw i8 %x, 7
+  %cmp = icmp sgt i8 %shl, -127
+  ret i1 %cmp
+}
+
+define i1 @icmp_sgt11(i8 %x) {
+; CHECK-LABEL: @icmp_sgt11(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt i8 %x, -1
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %shl = shl nsw i8 %x, 7
+  %cmp = icmp sgt i8 %shl, -2
+  ret i1 %cmp
+}
+
+; Splat vector version should fold the same way.
+
+define <2 x i1> @icmp_sgt11_vec(<2 x i8> %x) {
+; CHECK-LABEL: @icmp_sgt11_vec(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt <2 x i8> %x, <i8 -1, i8 -1>
+; CHECK-NEXT:    ret <2 x i1> [[CMP]]
+;
+  %shl = shl nsw <2 x i8> %x, <i8 7, i8 7>
+  %cmp = icmp sgt <2 x i8> %shl, <i8 -2, i8 -2>
+  ret <2 x i1> %cmp
+}
+
+; Known bits analysis returns false for compares with >=0.
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;
+; Repeat the shl nsw + sgt tests with predicate changed to 'sle'.
+;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+; Known bits analysis turns this into an equality predicate.
+
+define i1 @icmp_sle1(i8 %x) {
+; CHECK-LABEL: @icmp_sle1(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i8 %x, -64
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %shl = shl nsw i8 %x, 1
+  %cmp = icmp sle i8 %shl, -128
+  ret i1 %cmp
+}
+
+define i1 @icmp_sle2(i8 %x) {
+; CHECK-LABEL: @icmp_sle2(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i8 %x, -63
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %shl = shl nsw i8 %x, 1
+  %cmp = icmp sle i8 %shl, -127
+  ret i1 %cmp
+}
+
+define i1 @icmp_sle3(i8 %x) {
+; CHECK-LABEL: @icmp_sle3(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i8 %x, -7
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %shl = shl nsw i8 %x, 1
+  %cmp = icmp sle i8 %shl, -16
+  ret i1 %cmp
+}
+
+define i1 @icmp_sle4(i8 %x) {
+; CHECK-LABEL: @icmp_sle4(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i8 %x, 0
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %shl = shl nsw i8 %x, 1
+  %cmp = icmp sle i8 %shl, -2
+  ret i1 %cmp
+}
+
+; x <=s -1 is a sign bit test.
+; x <=s 0 is a sign bit test.
+
+define i1 @icmp_sle5(i8 %x) {
+; CHECK-LABEL: @icmp_sle5(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i8 %x, 1
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %shl = shl nsw i8 %x, 1
+  %cmp = icmp sle i8 %shl, 1
+  ret i1 %cmp
+}
+
+define i1 @icmp_sle6(i8 %x) {
+; CHECK-LABEL: @icmp_sle6(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i8 %x, 9
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %shl = shl nsw i8 %x, 1
+  %cmp = icmp sle i8 %shl, 16
+  ret i1 %cmp
+}
+
+define i1 @icmp_sle7(i8 %x) {
+; CHECK-LABEL: @icmp_sle7(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i8 %x, 63
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %shl = shl nsw i8 %x, 1
+  %cmp = icmp sle i8 %shl, 124
+  ret i1 %cmp
+}
+
+; Known bits analysis turns this into an equality predicate.
+
+define i1 @icmp_sle8(i8 %x) {
+; CHECK-LABEL: @icmp_sle8(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ne i8 %x, 63
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %shl = shl nsw i8 %x, 1
+  %cmp = icmp sle i8 %shl, 125
+  ret i1 %cmp
+}
+
+; Compares with 126 and 127 are recognized as always true.
+
+; Known bits analysis turns this into an equality predicate.
+
+define i1 @icmp_sle9(i8 %x) {
+; CHECK-LABEL: @icmp_sle9(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i8 %x, -1
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %shl = shl nsw i8 %x, 7
+  %cmp = icmp sle i8 %shl, -128
+  ret i1 %cmp
+}
+
+define i1 @icmp_sle10(i8 %x) {
+; CHECK-LABEL: @icmp_sle10(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i8 %x, 0
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %shl = shl nsw i8 %x, 7
+  %cmp = icmp sle i8 %shl, -127
+  ret i1 %cmp
+}
+
+define i1 @icmp_sle11(i8 %x) {
+; CHECK-LABEL: @icmp_sle11(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i8 %x, 0
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %shl = shl nsw i8 %x, 7
+  %cmp = icmp sle i8 %shl, -2
+  ret i1 %cmp
+}
+
+; Some of the earlier sgt/sle tests are transformed to eq/ne, but try a couple
+; of those explicitly, so we know no intermediate transforms are necessary.
+
+define i1 @icmp_eq1(i8 %x) {
+; CHECK-LABEL: @icmp_eq1(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i8 %x, 6
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %shl = shl nsw i8 %x, 1
+  %cmp = icmp eq i8 %shl, 12
+  ret i1 %cmp
+}
+
+define i1 @icmp_ne1(i8 %x) {
+; CHECK-LABEL: @icmp_ne1(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ne i8 %x, -2
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %shl = shl nsw i8 %x, 6
+  %cmp = icmp ne i8 %shl, -128
+  ret i1 %cmp
+}
+

Added: llvm/trunk/test/Transforms/InstCombine/icmp-shl-nuw.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/icmp-shl-nuw.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/icmp-shl-nuw.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/icmp-shl-nuw.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,92 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt %s -instcombine -S | FileCheck %s
+
+define i1 @icmp_ugt_32(i64) {
+; CHECK-LABEL: @icmp_ugt_32(
+; CHECK-NEXT:    [[D:%.*]] = icmp ne i64 %0, 0
+; CHECK-NEXT:    ret i1 [[D]]
+;
+  %c = shl nuw i64 %0, 32
+  %d = icmp ugt i64 %c, 4294967295
+  ret i1 %d
+}
+
+define i1 @icmp_ule_64(i128) {
+; CHECK-LABEL: @icmp_ule_64(
+; CHECK-NEXT:    [[D:%.*]] = icmp eq i128 %0, 0
+; CHECK-NEXT:    ret i1 [[D]]
+;
+  %c = shl nuw i128 %0, 64
+  %d = icmp ule i128 %c, 18446744073709551615
+  ret i1 %d
+}
+
+define i1 @icmp_ugt_16(i64) {
+; CHECK-LABEL: @icmp_ugt_16(
+; CHECK-NEXT:    [[D:%.*]] = icmp ugt i64 %0, 15
+; CHECK-NEXT:    ret i1 [[D]]
+;
+  %c = shl nuw i64 %0, 16
+  %d = icmp ugt i64 %c, 1048575 ; 0x0f_ffff
+  ret i1 %d
+}
+
+define <2 x i1> @icmp_ule_16x2(<2 x i64>) {
+; CHECK-LABEL: @icmp_ule_16x2(
+; CHECK-NEXT:    [[D:%.*]] = icmp eq <2 x i64> %0, zeroinitializer
+; CHECK-NEXT:    ret <2 x i1> [[D]]
+;
+  %c = shl nuw <2 x i64> %0, <i64 16, i64 16>
+  %d = icmp ule <2 x i64> %c, <i64 65535, i64 65535>
+  ret <2 x i1> %d
+}
+
+define <2 x i1> @icmp_ule_16x2_nonzero(<2 x i64>) {
+; CHECK-LABEL: @icmp_ule_16x2_nonzero(
+; CHECK-NEXT:    [[D:%.*]] = icmp ult <2 x i64> %0, <i64 4, i64 4>
+; CHECK-NEXT:    ret <2 x i1> [[D]]
+;
+  %c = shl nuw <2 x i64> %0, <i64 16, i64 16>
+  %d = icmp ule <2 x i64> %c, <i64 196608, i64 196608>  ; 0x03_0000
+  ret <2 x i1> %d
+}
+
+define <2 x i1> @icmp_ule_12x2(<2 x i64>) {
+; CHECK-LABEL: @icmp_ule_12x2(
+; CHECK-NEXT:    [[D:%.*]] = icmp ult <2 x i64> %0, <i64 4, i64 4>
+; CHECK-NEXT:    ret <2 x i1> [[D]]
+;
+  %c = shl nuw <2 x i64> %0, <i64 12, i64 12>
+  %d = icmp ule <2 x i64> %c, <i64 12288, i64 12288>  ; 0x3000
+  ret <2 x i1> %d
+}
+
+define i1 @icmp_ult_8(i64) {
+; CHECK-LABEL: @icmp_ult_8(
+; CHECK-NEXT:    [[D:%.*]] = icmp ult i64 %0, 16
+; CHECK-NEXT:    ret i1 [[D]]
+;
+  %c = shl nuw i64 %0, 8
+  %d = icmp ult i64 %c, 4095 ; 0x0fff
+  ret i1 %d
+}
+
+define <2 x i1> @icmp_uge_8x2(<2 x i16>) {
+; CHECK-LABEL: @icmp_uge_8x2(
+; CHECK-NEXT:    [[D:%.*]] = icmp ugt <2 x i16> %0, <i16 15, i16 15>
+; CHECK-NEXT:    ret <2 x i1> [[D]]
+;
+  %c = shl nuw <2 x i16> %0, <i16 8, i16 8>
+  %d = icmp uge <2 x i16> %c, <i16 4095, i16 4095>
+  ret <2 x i1> %d
+}
+
+define <2 x i1> @icmp_ugt_16x2(<2 x i32>) {
+; CHECK-LABEL: @icmp_ugt_16x2(
+; CHECK-NEXT:    [[D:%.*]] = icmp ugt <2 x i32> %0, <i32 15, i32 15>
+; CHECK-NEXT:    ret <2 x i1> [[D]]
+;
+  %c = shl nuw <2 x i32> %0, <i32 16, i32 16>
+  %d = icmp ugt <2 x i32> %c, <i32 1048575, i32 1048575>
+  ret <2 x i1> %d
+}

Added: llvm/trunk/test/Transforms/InstCombine/icmp-shr-lt-gt.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/icmp-shr-lt-gt.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/icmp-shr-lt-gt.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/icmp-shr-lt-gt.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,3546 @@
+; RUN: opt < %s -instcombine -S | FileCheck %s
+
+define i1 @lshrugt_01_00(i4 %x) {
+; CHECK-LABEL: @lshrugt_01_00(
+; CHECK-NEXT:    [[C:%.*]] = icmp ugt i4 %x, 1
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %s = lshr i4 %x, 1
+  %c = icmp ugt i4 %s, 0
+  ret i1 %c
+}
+
+define i1 @lshrugt_01_01(i4 %x) {
+; CHECK-LABEL: @lshrugt_01_01(
+; CHECK-NEXT:    [[C:%.*]] = icmp ugt i4 %x, 3
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %s = lshr i4 %x, 1
+  %c = icmp ugt i4 %s, 1
+  ret i1 %c
+}
+
+define i1 @lshrugt_01_02(i4 %x) {
+; CHECK-LABEL: @lshrugt_01_02(
+; CHECK-NEXT:    [[C:%.*]] = icmp ugt i4 %x, 5
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %s = lshr i4 %x, 1
+  %c = icmp ugt i4 %s, 2
+  ret i1 %c
+}
+
+define i1 @lshrugt_01_03(i4 %x) {
+; CHECK-LABEL: @lshrugt_01_03(
+; CHECK-NEXT:    [[C:%.*]] = icmp slt i4 %x, 0
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %s = lshr i4 %x, 1
+  %c = icmp ugt i4 %s, 3
+  ret i1 %c
+}
+
+define i1 @lshrugt_01_04(i4 %x) {
+; CHECK-LABEL: @lshrugt_01_04(
+; CHECK-NEXT:    [[C:%.*]] = icmp ugt i4 %x, -7
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %s = lshr i4 %x, 1
+  %c = icmp ugt i4 %s, 4
+  ret i1 %c
+}
+
+define i1 @lshrugt_01_05(i4 %x) {
+; CHECK-LABEL: @lshrugt_01_05(
+; CHECK-NEXT:    [[C:%.*]] = icmp ugt i4 %x, -5
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %s = lshr i4 %x, 1
+  %c = icmp ugt i4 %s, 5
+  ret i1 %c
+}
+
+define i1 @lshrugt_01_06(i4 %x) {
+; CHECK-LABEL: @lshrugt_01_06(
+; CHECK-NEXT:    [[C:%.*]] = icmp ugt i4 %x, -3
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %s = lshr i4 %x, 1
+  %c = icmp ugt i4 %s, 6
+  ret i1 %c
+}
+
+define i1 @lshrugt_01_07(i4 %x) {
+; CHECK-LABEL: @lshrugt_01_07(
+; CHECK-NEXT:    ret i1 false
+;
+  %s = lshr i4 %x, 1
+  %c = icmp ugt i4 %s, 7
+  ret i1 %c
+}
+
+define i1 @lshrugt_01_08(i4 %x) {
+; CHECK-LABEL: @lshrugt_01_08(
+; CHECK-NEXT:    ret i1 false
+;
+  %s = lshr i4 %x, 1
+  %c = icmp ugt i4 %s, 8
+  ret i1 %c
+}
+
+define i1 @lshrugt_01_09(i4 %x) {
+; CHECK-LABEL: @lshrugt_01_09(
+; CHECK-NEXT:    ret i1 false
+;
+  %s = lshr i4 %x, 1
+  %c = icmp ugt i4 %s, 9
+  ret i1 %c
+}
+
+define i1 @lshrugt_01_10(i4 %x) {
+; CHECK-LABEL: @lshrugt_01_10(
+; CHECK-NEXT:    ret i1 false
+;
+  %s = lshr i4 %x, 1
+  %c = icmp ugt i4 %s, 10
+  ret i1 %c
+}
+
+define i1 @lshrugt_01_11(i4 %x) {
+; CHECK-LABEL: @lshrugt_01_11(
+; CHECK-NEXT:    ret i1 false
+;
+  %s = lshr i4 %x, 1
+  %c = icmp ugt i4 %s, 11
+  ret i1 %c
+}
+
+define i1 @lshrugt_01_12(i4 %x) {
+; CHECK-LABEL: @lshrugt_01_12(
+; CHECK-NEXT:    ret i1 false
+;
+  %s = lshr i4 %x, 1
+  %c = icmp ugt i4 %s, 12
+  ret i1 %c
+}
+
+define i1 @lshrugt_01_13(i4 %x) {
+; CHECK-LABEL: @lshrugt_01_13(
+; CHECK-NEXT:    ret i1 false
+;
+  %s = lshr i4 %x, 1
+  %c = icmp ugt i4 %s, 13
+  ret i1 %c
+}
+
+define i1 @lshrugt_01_14(i4 %x) {
+; CHECK-LABEL: @lshrugt_01_14(
+; CHECK-NEXT:    ret i1 false
+;
+  %s = lshr i4 %x, 1
+  %c = icmp ugt i4 %s, 14
+  ret i1 %c
+}
+
+define i1 @lshrugt_01_15(i4 %x) {
+; CHECK-LABEL: @lshrugt_01_15(
+; CHECK-NEXT:    ret i1 false
+;
+  %s = lshr i4 %x, 1
+  %c = icmp ugt i4 %s, 15
+  ret i1 %c
+}
+
+define i1 @lshrugt_02_00(i4 %x) {
+; CHECK-LABEL: @lshrugt_02_00(
+; CHECK-NEXT:    [[C:%.*]] = icmp ugt i4 %x, 3
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %s = lshr i4 %x, 2
+  %c = icmp ugt i4 %s, 0
+  ret i1 %c
+}
+
+define i1 @lshrugt_02_01(i4 %x) {
+; CHECK-LABEL: @lshrugt_02_01(
+; CHECK-NEXT:    [[C:%.*]] = icmp slt i4 %x, 0
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %s = lshr i4 %x, 2
+  %c = icmp ugt i4 %s, 1
+  ret i1 %c
+}
+
+define i1 @lshrugt_02_02(i4 %x) {
+; CHECK-LABEL: @lshrugt_02_02(
+; CHECK-NEXT:    [[C:%.*]] = icmp ugt i4 %x, -5
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %s = lshr i4 %x, 2
+  %c = icmp ugt i4 %s, 2
+  ret i1 %c
+}
+
+define i1 @lshrugt_02_03(i4 %x) {
+; CHECK-LABEL: @lshrugt_02_03(
+; CHECK-NEXT:    ret i1 false
+;
+  %s = lshr i4 %x, 2
+  %c = icmp ugt i4 %s, 3
+  ret i1 %c
+}
+
+define i1 @lshrugt_02_04(i4 %x) {
+; CHECK-LABEL: @lshrugt_02_04(
+; CHECK-NEXT:    ret i1 false
+;
+  %s = lshr i4 %x, 2
+  %c = icmp ugt i4 %s, 4
+  ret i1 %c
+}
+
+define i1 @lshrugt_02_05(i4 %x) {
+; CHECK-LABEL: @lshrugt_02_05(
+; CHECK-NEXT:    ret i1 false
+;
+  %s = lshr i4 %x, 2
+  %c = icmp ugt i4 %s, 5
+  ret i1 %c
+}
+
+define i1 @lshrugt_02_06(i4 %x) {
+; CHECK-LABEL: @lshrugt_02_06(
+; CHECK-NEXT:    ret i1 false
+;
+  %s = lshr i4 %x, 2
+  %c = icmp ugt i4 %s, 6
+  ret i1 %c
+}
+
+define i1 @lshrugt_02_07(i4 %x) {
+; CHECK-LABEL: @lshrugt_02_07(
+; CHECK-NEXT:    ret i1 false
+;
+  %s = lshr i4 %x, 2
+  %c = icmp ugt i4 %s, 7
+  ret i1 %c
+}
+
+define i1 @lshrugt_02_08(i4 %x) {
+; CHECK-LABEL: @lshrugt_02_08(
+; CHECK-NEXT:    ret i1 false
+;
+  %s = lshr i4 %x, 2
+  %c = icmp ugt i4 %s, 8
+  ret i1 %c
+}
+
+define i1 @lshrugt_02_09(i4 %x) {
+; CHECK-LABEL: @lshrugt_02_09(
+; CHECK-NEXT:    ret i1 false
+;
+  %s = lshr i4 %x, 2
+  %c = icmp ugt i4 %s, 9
+  ret i1 %c
+}
+
+define i1 @lshrugt_02_10(i4 %x) {
+; CHECK-LABEL: @lshrugt_02_10(
+; CHECK-NEXT:    ret i1 false
+;
+  %s = lshr i4 %x, 2
+  %c = icmp ugt i4 %s, 10
+  ret i1 %c
+}
+
+define i1 @lshrugt_02_11(i4 %x) {
+; CHECK-LABEL: @lshrugt_02_11(
+; CHECK-NEXT:    ret i1 false
+;
+  %s = lshr i4 %x, 2
+  %c = icmp ugt i4 %s, 11
+  ret i1 %c
+}
+
+define i1 @lshrugt_02_12(i4 %x) {
+; CHECK-LABEL: @lshrugt_02_12(
+; CHECK-NEXT:    ret i1 false
+;
+  %s = lshr i4 %x, 2
+  %c = icmp ugt i4 %s, 12
+  ret i1 %c
+}
+
+define i1 @lshrugt_02_13(i4 %x) {
+; CHECK-LABEL: @lshrugt_02_13(
+; CHECK-NEXT:    ret i1 false
+;
+  %s = lshr i4 %x, 2
+  %c = icmp ugt i4 %s, 13
+  ret i1 %c
+}
+
+define i1 @lshrugt_02_14(i4 %x) {
+; CHECK-LABEL: @lshrugt_02_14(
+; CHECK-NEXT:    ret i1 false
+;
+  %s = lshr i4 %x, 2
+  %c = icmp ugt i4 %s, 14
+  ret i1 %c
+}
+
+define i1 @lshrugt_02_15(i4 %x) {
+; CHECK-LABEL: @lshrugt_02_15(
+; CHECK-NEXT:    ret i1 false
+;
+  %s = lshr i4 %x, 2
+  %c = icmp ugt i4 %s, 15
+  ret i1 %c
+}
+
+define i1 @lshrugt_03_00(i4 %x) {
+; CHECK-LABEL: @lshrugt_03_00(
+; CHECK-NEXT:    [[C:%.*]] = icmp slt i4 %x, 0
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %s = lshr i4 %x, 3
+  %c = icmp ugt i4 %s, 0
+  ret i1 %c
+}
+
+define i1 @lshrugt_03_01(i4 %x) {
+; CHECK-LABEL: @lshrugt_03_01(
+; CHECK-NEXT:    ret i1 false
+;
+  %s = lshr i4 %x, 3
+  %c = icmp ugt i4 %s, 1
+  ret i1 %c
+}
+
+define i1 @lshrugt_03_02(i4 %x) {
+; CHECK-LABEL: @lshrugt_03_02(
+; CHECK-NEXT:    ret i1 false
+;
+  %s = lshr i4 %x, 3
+  %c = icmp ugt i4 %s, 2
+  ret i1 %c
+}
+
+define i1 @lshrugt_03_03(i4 %x) {
+; CHECK-LABEL: @lshrugt_03_03(
+; CHECK-NEXT:    ret i1 false
+;
+  %s = lshr i4 %x, 3
+  %c = icmp ugt i4 %s, 3
+  ret i1 %c
+}
+
+define i1 @lshrugt_03_04(i4 %x) {
+; CHECK-LABEL: @lshrugt_03_04(
+; CHECK-NEXT:    ret i1 false
+;
+  %s = lshr i4 %x, 3
+  %c = icmp ugt i4 %s, 4
+  ret i1 %c
+}
+
+define i1 @lshrugt_03_05(i4 %x) {
+; CHECK-LABEL: @lshrugt_03_05(
+; CHECK-NEXT:    ret i1 false
+;
+  %s = lshr i4 %x, 3
+  %c = icmp ugt i4 %s, 5
+  ret i1 %c
+}
+
+define i1 @lshrugt_03_06(i4 %x) {
+; CHECK-LABEL: @lshrugt_03_06(
+; CHECK-NEXT:    ret i1 false
+;
+  %s = lshr i4 %x, 3
+  %c = icmp ugt i4 %s, 6
+  ret i1 %c
+}
+
+define i1 @lshrugt_03_07(i4 %x) {
+; CHECK-LABEL: @lshrugt_03_07(
+; CHECK-NEXT:    ret i1 false
+;
+  %s = lshr i4 %x, 3
+  %c = icmp ugt i4 %s, 7
+  ret i1 %c
+}
+
+define i1 @lshrugt_03_08(i4 %x) {
+; CHECK-LABEL: @lshrugt_03_08(
+; CHECK-NEXT:    ret i1 false
+;
+  %s = lshr i4 %x, 3
+  %c = icmp ugt i4 %s, 8
+  ret i1 %c
+}
+
+define i1 @lshrugt_03_09(i4 %x) {
+; CHECK-LABEL: @lshrugt_03_09(
+; CHECK-NEXT:    ret i1 false
+;
+  %s = lshr i4 %x, 3
+  %c = icmp ugt i4 %s, 9
+  ret i1 %c
+}
+
+define i1 @lshrugt_03_10(i4 %x) {
+; CHECK-LABEL: @lshrugt_03_10(
+; CHECK-NEXT:    ret i1 false
+;
+  %s = lshr i4 %x, 3
+  %c = icmp ugt i4 %s, 10
+  ret i1 %c
+}
+
+define i1 @lshrugt_03_11(i4 %x) {
+; CHECK-LABEL: @lshrugt_03_11(
+; CHECK-NEXT:    ret i1 false
+;
+  %s = lshr i4 %x, 3
+  %c = icmp ugt i4 %s, 11
+  ret i1 %c
+}
+
+define i1 @lshrugt_03_12(i4 %x) {
+; CHECK-LABEL: @lshrugt_03_12(
+; CHECK-NEXT:    ret i1 false
+;
+  %s = lshr i4 %x, 3
+  %c = icmp ugt i4 %s, 12
+  ret i1 %c
+}
+
+define i1 @lshrugt_03_13(i4 %x) {
+; CHECK-LABEL: @lshrugt_03_13(
+; CHECK-NEXT:    ret i1 false
+;
+  %s = lshr i4 %x, 3
+  %c = icmp ugt i4 %s, 13
+  ret i1 %c
+}
+
+define i1 @lshrugt_03_14(i4 %x) {
+; CHECK-LABEL: @lshrugt_03_14(
+; CHECK-NEXT:    ret i1 false
+;
+  %s = lshr i4 %x, 3
+  %c = icmp ugt i4 %s, 14
+  ret i1 %c
+}
+
+define i1 @lshrugt_03_15(i4 %x) {
+; CHECK-LABEL: @lshrugt_03_15(
+; CHECK-NEXT:    ret i1 false
+;
+  %s = lshr i4 %x, 3
+  %c = icmp ugt i4 %s, 15
+  ret i1 %c
+}
+
+define i1 @lshrult_01_00(i4 %x) {
+; CHECK-LABEL: @lshrult_01_00(
+; CHECK-NEXT:    ret i1 false
+;
+  %s = lshr i4 %x, 1
+  %c = icmp ult i4 %s, 0
+  ret i1 %c
+}
+
+define i1 @lshrult_01_01(i4 %x) {
+; CHECK-LABEL: @lshrult_01_01(
+; CHECK-NEXT:    [[C:%.*]] = icmp ult i4 %x, 2
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %s = lshr i4 %x, 1
+  %c = icmp ult i4 %s, 1
+  ret i1 %c
+}
+
+define i1 @lshrult_01_02(i4 %x) {
+; CHECK-LABEL: @lshrult_01_02(
+; CHECK-NEXT:    [[C:%.*]] = icmp ult i4 %x, 4
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %s = lshr i4 %x, 1
+  %c = icmp ult i4 %s, 2
+  ret i1 %c
+}
+
+define i1 @lshrult_01_03(i4 %x) {
+; CHECK-LABEL: @lshrult_01_03(
+; CHECK-NEXT:    [[C:%.*]] = icmp ult i4 %x, 6
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %s = lshr i4 %x, 1
+  %c = icmp ult i4 %s, 3
+  ret i1 %c
+}
+
+define i1 @lshrult_01_04(i4 %x) {
+; CHECK-LABEL: @lshrult_01_04(
+; CHECK-NEXT:    [[C:%.*]] = icmp sgt i4 %x, -1
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %s = lshr i4 %x, 1
+  %c = icmp ult i4 %s, 4
+  ret i1 %c
+}
+
+define i1 @lshrult_01_05(i4 %x) {
+; CHECK-LABEL: @lshrult_01_05(
+; CHECK-NEXT:    [[C:%.*]] = icmp ult i4 %x, -6
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %s = lshr i4 %x, 1
+  %c = icmp ult i4 %s, 5
+  ret i1 %c
+}
+
+define i1 @lshrult_01_06(i4 %x) {
+; CHECK-LABEL: @lshrult_01_06(
+; CHECK-NEXT:    [[C:%.*]] = icmp ult i4 %x, -4
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %s = lshr i4 %x, 1
+  %c = icmp ult i4 %s, 6
+  ret i1 %c
+}
+
+define i1 @lshrult_01_07(i4 %x) {
+; CHECK-LABEL: @lshrult_01_07(
+; CHECK-NEXT:    [[C:%.*]] = icmp ult i4 %x, -2
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %s = lshr i4 %x, 1
+  %c = icmp ult i4 %s, 7
+  ret i1 %c
+}
+
+define i1 @lshrult_01_08(i4 %x) {
+; CHECK-LABEL: @lshrult_01_08(
+; CHECK-NEXT:    ret i1 true
+;
+  %s = lshr i4 %x, 1
+  %c = icmp ult i4 %s, 8
+  ret i1 %c
+}
+
+define i1 @lshrult_01_09(i4 %x) {
+; CHECK-LABEL: @lshrult_01_09(
+; CHECK-NEXT:    ret i1 true
+;
+  %s = lshr i4 %x, 1
+  %c = icmp ult i4 %s, 9
+  ret i1 %c
+}
+
+define i1 @lshrult_01_10(i4 %x) {
+; CHECK-LABEL: @lshrult_01_10(
+; CHECK-NEXT:    ret i1 true
+;
+  %s = lshr i4 %x, 1
+  %c = icmp ult i4 %s, 10
+  ret i1 %c
+}
+
+define i1 @lshrult_01_11(i4 %x) {
+; CHECK-LABEL: @lshrult_01_11(
+; CHECK-NEXT:    ret i1 true
+;
+  %s = lshr i4 %x, 1
+  %c = icmp ult i4 %s, 11
+  ret i1 %c
+}
+
+define i1 @lshrult_01_12(i4 %x) {
+; CHECK-LABEL: @lshrult_01_12(
+; CHECK-NEXT:    ret i1 true
+;
+  %s = lshr i4 %x, 1
+  %c = icmp ult i4 %s, 12
+  ret i1 %c
+}
+
+define i1 @lshrult_01_13(i4 %x) {
+; CHECK-LABEL: @lshrult_01_13(
+; CHECK-NEXT:    ret i1 true
+;
+  %s = lshr i4 %x, 1
+  %c = icmp ult i4 %s, 13
+  ret i1 %c
+}
+
+define i1 @lshrult_01_14(i4 %x) {
+; CHECK-LABEL: @lshrult_01_14(
+; CHECK-NEXT:    ret i1 true
+;
+  %s = lshr i4 %x, 1
+  %c = icmp ult i4 %s, 14
+  ret i1 %c
+}
+
+define i1 @lshrult_01_15(i4 %x) {
+; CHECK-LABEL: @lshrult_01_15(
+; CHECK-NEXT:    ret i1 true
+;
+  %s = lshr i4 %x, 1
+  %c = icmp ult i4 %s, 15
+  ret i1 %c
+}
+
+define i1 @lshrult_02_00(i4 %x) {
+; CHECK-LABEL: @lshrult_02_00(
+; CHECK-NEXT:    ret i1 false
+;
+  %s = lshr i4 %x, 2
+  %c = icmp ult i4 %s, 0
+  ret i1 %c
+}
+
+define i1 @lshrult_02_01(i4 %x) {
+; CHECK-LABEL: @lshrult_02_01(
+; CHECK-NEXT:    [[C:%.*]] = icmp ult i4 %x, 4
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %s = lshr i4 %x, 2
+  %c = icmp ult i4 %s, 1
+  ret i1 %c
+}
+
+define i1 @lshrult_02_02(i4 %x) {
+; CHECK-LABEL: @lshrult_02_02(
+; CHECK-NEXT:    [[C:%.*]] = icmp sgt i4 %x, -1
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %s = lshr i4 %x, 2
+  %c = icmp ult i4 %s, 2
+  ret i1 %c
+}
+
+define i1 @lshrult_02_03(i4 %x) {
+; CHECK-LABEL: @lshrult_02_03(
+; CHECK-NEXT:    [[C:%.*]] = icmp ult i4 %x, -4
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %s = lshr i4 %x, 2
+  %c = icmp ult i4 %s, 3
+  ret i1 %c
+}
+
+define i1 @lshrult_02_04(i4 %x) {
+; CHECK-LABEL: @lshrult_02_04(
+; CHECK-NEXT:    ret i1 true
+;
+  %s = lshr i4 %x, 2
+  %c = icmp ult i4 %s, 4
+  ret i1 %c
+}
+
+define i1 @lshrult_02_05(i4 %x) {
+; CHECK-LABEL: @lshrult_02_05(
+; CHECK-NEXT:    ret i1 true
+;
+  %s = lshr i4 %x, 2
+  %c = icmp ult i4 %s, 5
+  ret i1 %c
+}
+
+define i1 @lshrult_02_06(i4 %x) {
+; CHECK-LABEL: @lshrult_02_06(
+; CHECK-NEXT:    ret i1 true
+;
+  %s = lshr i4 %x, 2
+  %c = icmp ult i4 %s, 6
+  ret i1 %c
+}
+
+define i1 @lshrult_02_07(i4 %x) {
+; CHECK-LABEL: @lshrult_02_07(
+; CHECK-NEXT:    ret i1 true
+;
+  %s = lshr i4 %x, 2
+  %c = icmp ult i4 %s, 7
+  ret i1 %c
+}
+
+define i1 @lshrult_02_08(i4 %x) {
+; CHECK-LABEL: @lshrult_02_08(
+; CHECK-NEXT:    ret i1 true
+;
+  %s = lshr i4 %x, 2
+  %c = icmp ult i4 %s, 8
+  ret i1 %c
+}
+
+define i1 @lshrult_02_09(i4 %x) {
+; CHECK-LABEL: @lshrult_02_09(
+; CHECK-NEXT:    ret i1 true
+;
+  %s = lshr i4 %x, 2
+  %c = icmp ult i4 %s, 9
+  ret i1 %c
+}
+
+define i1 @lshrult_02_10(i4 %x) {
+; CHECK-LABEL: @lshrult_02_10(
+; CHECK-NEXT:    ret i1 true
+;
+  %s = lshr i4 %x, 2
+  %c = icmp ult i4 %s, 10
+  ret i1 %c
+}
+
+define i1 @lshrult_02_11(i4 %x) {
+; CHECK-LABEL: @lshrult_02_11(
+; CHECK-NEXT:    ret i1 true
+;
+  %s = lshr i4 %x, 2
+  %c = icmp ult i4 %s, 11
+  ret i1 %c
+}
+
+define i1 @lshrult_02_12(i4 %x) {
+; CHECK-LABEL: @lshrult_02_12(
+; CHECK-NEXT:    ret i1 true
+;
+  %s = lshr i4 %x, 2
+  %c = icmp ult i4 %s, 12
+  ret i1 %c
+}
+
+define i1 @lshrult_02_13(i4 %x) {
+; CHECK-LABEL: @lshrult_02_13(
+; CHECK-NEXT:    ret i1 true
+;
+  %s = lshr i4 %x, 2
+  %c = icmp ult i4 %s, 13
+  ret i1 %c
+}
+
+define i1 @lshrult_02_14(i4 %x) {
+; CHECK-LABEL: @lshrult_02_14(
+; CHECK-NEXT:    ret i1 true
+;
+  %s = lshr i4 %x, 2
+  %c = icmp ult i4 %s, 14
+  ret i1 %c
+}
+
+define i1 @lshrult_02_15(i4 %x) {
+; CHECK-LABEL: @lshrult_02_15(
+; CHECK-NEXT:    ret i1 true
+;
+  %s = lshr i4 %x, 2
+  %c = icmp ult i4 %s, 15
+  ret i1 %c
+}
+
+define i1 @lshrult_03_00(i4 %x) {
+; CHECK-LABEL: @lshrult_03_00(
+; CHECK-NEXT:    ret i1 false
+;
+  %s = lshr i4 %x, 3
+  %c = icmp ult i4 %s, 0
+  ret i1 %c
+}
+
+define i1 @lshrult_03_01(i4 %x) {
+; CHECK-LABEL: @lshrult_03_01(
+; CHECK-NEXT:    [[C:%.*]] = icmp sgt i4 %x, -1
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %s = lshr i4 %x, 3
+  %c = icmp ult i4 %s, 1
+  ret i1 %c
+}
+
+define i1 @lshrult_03_02(i4 %x) {
+; CHECK-LABEL: @lshrult_03_02(
+; CHECK-NEXT:    ret i1 true
+;
+  %s = lshr i4 %x, 3
+  %c = icmp ult i4 %s, 2
+  ret i1 %c
+}
+
+define i1 @lshrult_03_03(i4 %x) {
+; CHECK-LABEL: @lshrult_03_03(
+; CHECK-NEXT:    ret i1 true
+;
+  %s = lshr i4 %x, 3
+  %c = icmp ult i4 %s, 3
+  ret i1 %c
+}
+
+define i1 @lshrult_03_04(i4 %x) {
+; CHECK-LABEL: @lshrult_03_04(
+; CHECK-NEXT:    ret i1 true
+;
+  %s = lshr i4 %x, 3
+  %c = icmp ult i4 %s, 4
+  ret i1 %c
+}
+
+define i1 @lshrult_03_05(i4 %x) {
+; CHECK-LABEL: @lshrult_03_05(
+; CHECK-NEXT:    ret i1 true
+;
+  %s = lshr i4 %x, 3
+  %c = icmp ult i4 %s, 5
+  ret i1 %c
+}
+
+define i1 @lshrult_03_06(i4 %x) {
+; CHECK-LABEL: @lshrult_03_06(
+; CHECK-NEXT:    ret i1 true
+;
+  %s = lshr i4 %x, 3
+  %c = icmp ult i4 %s, 6
+  ret i1 %c
+}
+
+define i1 @lshrult_03_07(i4 %x) {
+; CHECK-LABEL: @lshrult_03_07(
+; CHECK-NEXT:    ret i1 true
+;
+  %s = lshr i4 %x, 3
+  %c = icmp ult i4 %s, 7
+  ret i1 %c
+}
+
+define i1 @lshrult_03_08(i4 %x) {
+; CHECK-LABEL: @lshrult_03_08(
+; CHECK-NEXT:    ret i1 true
+;
+  %s = lshr i4 %x, 3
+  %c = icmp ult i4 %s, 8
+  ret i1 %c
+}
+
+define i1 @lshrult_03_09(i4 %x) {
+; CHECK-LABEL: @lshrult_03_09(
+; CHECK-NEXT:    ret i1 true
+;
+  %s = lshr i4 %x, 3
+  %c = icmp ult i4 %s, 9
+  ret i1 %c
+}
+
+define i1 @lshrult_03_10(i4 %x) {
+; CHECK-LABEL: @lshrult_03_10(
+; CHECK-NEXT:    ret i1 true
+;
+  %s = lshr i4 %x, 3
+  %c = icmp ult i4 %s, 10
+  ret i1 %c
+}
+
+define i1 @lshrult_03_11(i4 %x) {
+; CHECK-LABEL: @lshrult_03_11(
+; CHECK-NEXT:    ret i1 true
+;
+  %s = lshr i4 %x, 3
+  %c = icmp ult i4 %s, 11
+  ret i1 %c
+}
+
+define i1 @lshrult_03_12(i4 %x) {
+; CHECK-LABEL: @lshrult_03_12(
+; CHECK-NEXT:    ret i1 true
+;
+  %s = lshr i4 %x, 3
+  %c = icmp ult i4 %s, 12
+  ret i1 %c
+}
+
+define i1 @lshrult_03_13(i4 %x) {
+; CHECK-LABEL: @lshrult_03_13(
+; CHECK-NEXT:    ret i1 true
+;
+  %s = lshr i4 %x, 3
+  %c = icmp ult i4 %s, 13
+  ret i1 %c
+}
+
+define i1 @lshrult_03_14(i4 %x) {
+; CHECK-LABEL: @lshrult_03_14(
+; CHECK-NEXT:    ret i1 true
+;
+  %s = lshr i4 %x, 3
+  %c = icmp ult i4 %s, 14
+  ret i1 %c
+}
+
+define i1 @lshrult_03_15(i4 %x) {
+; CHECK-LABEL: @lshrult_03_15(
+; CHECK-NEXT:    ret i1 true
+;
+  %s = lshr i4 %x, 3
+  %c = icmp ult i4 %s, 15
+  ret i1 %c
+}
+
+define i1 @ashrsgt_01_00(i4 %x) {
+; CHECK-LABEL: @ashrsgt_01_00(
+; CHECK-NEXT:    [[C:%.*]] = icmp sgt i4 %x, 1
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %s = ashr i4 %x, 1
+  %c = icmp sgt i4 %s, 0
+  ret i1 %c
+}
+
+define i1 @ashrsgt_01_01(i4 %x) {
+; CHECK-LABEL: @ashrsgt_01_01(
+; CHECK-NEXT:    [[C:%.*]] = icmp sgt i4 %x, 3
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %s = ashr i4 %x, 1
+  %c = icmp sgt i4 %s, 1
+  ret i1 %c
+}
+
+define i1 @ashrsgt_01_02(i4 %x) {
+; CHECK-LABEL: @ashrsgt_01_02(
+; CHECK-NEXT:    [[C:%.*]] = icmp sgt i4 %x, 5
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %s = ashr i4 %x, 1
+  %c = icmp sgt i4 %s, 2
+  ret i1 %c
+}
+
+define i1 @ashrsgt_01_03(i4 %x) {
+; CHECK-LABEL: @ashrsgt_01_03(
+; CHECK-NEXT:    ret i1 false
+;
+  %s = ashr i4 %x, 1
+  %c = icmp sgt i4 %s, 3
+  ret i1 %c
+}
+
+define i1 @ashrsgt_01_04(i4 %x) {
+; CHECK-LABEL: @ashrsgt_01_04(
+; CHECK-NEXT:    ret i1 false
+;
+  %s = ashr i4 %x, 1
+  %c = icmp sgt i4 %s, 4
+  ret i1 %c
+}
+
+define i1 @ashrsgt_01_05(i4 %x) {
+; CHECK-LABEL: @ashrsgt_01_05(
+; CHECK-NEXT:    ret i1 false
+;
+  %s = ashr i4 %x, 1
+  %c = icmp sgt i4 %s, 5
+  ret i1 %c
+}
+
+define i1 @ashrsgt_01_06(i4 %x) {
+; CHECK-LABEL: @ashrsgt_01_06(
+; CHECK-NEXT:    ret i1 false
+;
+  %s = ashr i4 %x, 1
+  %c = icmp sgt i4 %s, 6
+  ret i1 %c
+}
+
+define i1 @ashrsgt_01_07(i4 %x) {
+; CHECK-LABEL: @ashrsgt_01_07(
+; CHECK-NEXT:    ret i1 false
+;
+  %s = ashr i4 %x, 1
+  %c = icmp sgt i4 %s, 7
+  ret i1 %c
+}
+
+define i1 @ashrsgt_01_08(i4 %x) {
+; CHECK-LABEL: @ashrsgt_01_08(
+; CHECK-NEXT:    ret i1 true
+;
+  %s = ashr i4 %x, 1
+  %c = icmp sgt i4 %s, 8
+  ret i1 %c
+}
+
+define i1 @ashrsgt_01_09(i4 %x) {
+; CHECK-LABEL: @ashrsgt_01_09(
+; CHECK-NEXT:    ret i1 true
+;
+  %s = ashr i4 %x, 1
+  %c = icmp sgt i4 %s, 9
+  ret i1 %c
+}
+
+define i1 @ashrsgt_01_10(i4 %x) {
+; CHECK-LABEL: @ashrsgt_01_10(
+; CHECK-NEXT:    ret i1 true
+;
+  %s = ashr i4 %x, 1
+  %c = icmp sgt i4 %s, 10
+  ret i1 %c
+}
+
+define i1 @ashrsgt_01_11(i4 %x) {
+; CHECK-LABEL: @ashrsgt_01_11(
+; CHECK-NEXT:    ret i1 true
+;
+  %s = ashr i4 %x, 1
+  %c = icmp sgt i4 %s, 11
+  ret i1 %c
+}
+
+define i1 @ashrsgt_01_12(i4 %x) {
+; CHECK-LABEL: @ashrsgt_01_12(
+; CHECK-NEXT:    [[C:%.*]] = icmp sgt i4 %x, -7
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %s = ashr i4 %x, 1
+  %c = icmp sgt i4 %s, 12
+  ret i1 %c
+}
+
+define i1 @ashrsgt_01_13(i4 %x) {
+; CHECK-LABEL: @ashrsgt_01_13(
+; CHECK-NEXT:    [[C:%.*]] = icmp sgt i4 %x, -5
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %s = ashr i4 %x, 1
+  %c = icmp sgt i4 %s, 13
+  ret i1 %c
+}
+
+define i1 @ashrsgt_01_14(i4 %x) {
+; CHECK-LABEL: @ashrsgt_01_14(
+; CHECK-NEXT:    [[C:%.*]] = icmp sgt i4 %x, -3
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %s = ashr i4 %x, 1
+  %c = icmp sgt i4 %s, 14
+  ret i1 %c
+}
+
+define i1 @ashrsgt_01_15(i4 %x) {
+; CHECK-LABEL: @ashrsgt_01_15(
+; CHECK-NEXT:    [[C:%.*]] = icmp sgt i4 %x, -1
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %s = ashr i4 %x, 1
+  %c = icmp sgt i4 %s, 15
+  ret i1 %c
+}
+
+define i1 @ashrsgt_02_00(i4 %x) {
+; CHECK-LABEL: @ashrsgt_02_00(
+; CHECK-NEXT:    [[C:%.*]] = icmp sgt i4 %x, 3
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %s = ashr i4 %x, 2
+  %c = icmp sgt i4 %s, 0
+  ret i1 %c
+}
+
+define i1 @ashrsgt_02_01(i4 %x) {
+; CHECK-LABEL: @ashrsgt_02_01(
+; CHECK-NEXT:    ret i1 false
+;
+  %s = ashr i4 %x, 2
+  %c = icmp sgt i4 %s, 1
+  ret i1 %c
+}
+
+define i1 @ashrsgt_02_02(i4 %x) {
+; CHECK-LABEL: @ashrsgt_02_02(
+; CHECK-NEXT:    ret i1 false
+;
+  %s = ashr i4 %x, 2
+  %c = icmp sgt i4 %s, 2
+  ret i1 %c
+}
+
+define i1 @ashrsgt_02_03(i4 %x) {
+; CHECK-LABEL: @ashrsgt_02_03(
+; CHECK-NEXT:    ret i1 false
+;
+  %s = ashr i4 %x, 2
+  %c = icmp sgt i4 %s, 3
+  ret i1 %c
+}
+
+define i1 @ashrsgt_02_04(i4 %x) {
+; CHECK-LABEL: @ashrsgt_02_04(
+; CHECK-NEXT:    ret i1 false
+;
+  %s = ashr i4 %x, 2
+  %c = icmp sgt i4 %s, 4
+  ret i1 %c
+}
+
+define i1 @ashrsgt_02_05(i4 %x) {
+; CHECK-LABEL: @ashrsgt_02_05(
+; CHECK-NEXT:    ret i1 false
+;
+  %s = ashr i4 %x, 2
+  %c = icmp sgt i4 %s, 5
+  ret i1 %c
+}
+
+define i1 @ashrsgt_02_06(i4 %x) {
+; CHECK-LABEL: @ashrsgt_02_06(
+; CHECK-NEXT:    ret i1 false
+;
+  %s = ashr i4 %x, 2
+  %c = icmp sgt i4 %s, 6
+  ret i1 %c
+}
+
+define i1 @ashrsgt_02_07(i4 %x) {
+; CHECK-LABEL: @ashrsgt_02_07(
+; CHECK-NEXT:    ret i1 false
+;
+  %s = ashr i4 %x, 2
+  %c = icmp sgt i4 %s, 7
+  ret i1 %c
+}
+
+define i1 @ashrsgt_02_08(i4 %x) {
+; CHECK-LABEL: @ashrsgt_02_08(
+; CHECK-NEXT:    ret i1 true
+;
+  %s = ashr i4 %x, 2
+  %c = icmp sgt i4 %s, 8
+  ret i1 %c
+}
+
+define i1 @ashrsgt_02_09(i4 %x) {
+; CHECK-LABEL: @ashrsgt_02_09(
+; CHECK-NEXT:    ret i1 true
+;
+  %s = ashr i4 %x, 2
+  %c = icmp sgt i4 %s, 9
+  ret i1 %c
+}
+
+define i1 @ashrsgt_02_10(i4 %x) {
+; CHECK-LABEL: @ashrsgt_02_10(
+; CHECK-NEXT:    ret i1 true
+;
+  %s = ashr i4 %x, 2
+  %c = icmp sgt i4 %s, 10
+  ret i1 %c
+}
+
+define i1 @ashrsgt_02_11(i4 %x) {
+; CHECK-LABEL: @ashrsgt_02_11(
+; CHECK-NEXT:    ret i1 true
+;
+  %s = ashr i4 %x, 2
+  %c = icmp sgt i4 %s, 11
+  ret i1 %c
+}
+
+define i1 @ashrsgt_02_12(i4 %x) {
+; CHECK-LABEL: @ashrsgt_02_12(
+; CHECK-NEXT:    ret i1 true
+;
+  %s = ashr i4 %x, 2
+  %c = icmp sgt i4 %s, 12
+  ret i1 %c
+}
+
+define i1 @ashrsgt_02_13(i4 %x) {
+; CHECK-LABEL: @ashrsgt_02_13(
+; CHECK-NEXT:    ret i1 true
+;
+  %s = ashr i4 %x, 2
+  %c = icmp sgt i4 %s, 13
+  ret i1 %c
+}
+
+define i1 @ashrsgt_02_14(i4 %x) {
+; CHECK-LABEL: @ashrsgt_02_14(
+; CHECK-NEXT:    [[C:%.*]] = icmp sgt i4 %x, -5
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %s = ashr i4 %x, 2
+  %c = icmp sgt i4 %s, 14
+  ret i1 %c
+}
+
+define i1 @ashrsgt_02_15(i4 %x) {
+; CHECK-LABEL: @ashrsgt_02_15(
+; CHECK-NEXT:    [[C:%.*]] = icmp sgt i4 %x, -1
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %s = ashr i4 %x, 2
+  %c = icmp sgt i4 %s, 15
+  ret i1 %c
+}
+
+define i1 @ashrsgt_03_00(i4 %x) {
+; CHECK-LABEL: @ashrsgt_03_00(
+; CHECK-NEXT:    ret i1 false
+;
+  %s = ashr i4 %x, 3
+  %c = icmp sgt i4 %s, 0
+  ret i1 %c
+}
+
+define i1 @ashrsgt_03_01(i4 %x) {
+; CHECK-LABEL: @ashrsgt_03_01(
+; CHECK-NEXT:    ret i1 false
+;
+  %s = ashr i4 %x, 3
+  %c = icmp sgt i4 %s, 1
+  ret i1 %c
+}
+
+define i1 @ashrsgt_03_02(i4 %x) {
+; CHECK-LABEL: @ashrsgt_03_02(
+; CHECK-NEXT:    ret i1 false
+;
+  %s = ashr i4 %x, 3
+  %c = icmp sgt i4 %s, 2
+  ret i1 %c
+}
+
+define i1 @ashrsgt_03_03(i4 %x) {
+; CHECK-LABEL: @ashrsgt_03_03(
+; CHECK-NEXT:    ret i1 false
+;
+  %s = ashr i4 %x, 3
+  %c = icmp sgt i4 %s, 3
+  ret i1 %c
+}
+
+define i1 @ashrsgt_03_04(i4 %x) {
+; CHECK-LABEL: @ashrsgt_03_04(
+; CHECK-NEXT:    ret i1 false
+;
+  %s = ashr i4 %x, 3
+  %c = icmp sgt i4 %s, 4
+  ret i1 %c
+}
+
+define i1 @ashrsgt_03_05(i4 %x) {
+; CHECK-LABEL: @ashrsgt_03_05(
+; CHECK-NEXT:    ret i1 false
+;
+  %s = ashr i4 %x, 3
+  %c = icmp sgt i4 %s, 5
+  ret i1 %c
+}
+
+define i1 @ashrsgt_03_06(i4 %x) {
+; CHECK-LABEL: @ashrsgt_03_06(
+; CHECK-NEXT:    ret i1 false
+;
+  %s = ashr i4 %x, 3
+  %c = icmp sgt i4 %s, 6
+  ret i1 %c
+}
+
+define i1 @ashrsgt_03_07(i4 %x) {
+; CHECK-LABEL: @ashrsgt_03_07(
+; CHECK-NEXT:    ret i1 false
+;
+  %s = ashr i4 %x, 3
+  %c = icmp sgt i4 %s, 7
+  ret i1 %c
+}
+
+define i1 @ashrsgt_03_08(i4 %x) {
+; CHECK-LABEL: @ashrsgt_03_08(
+; CHECK-NEXT:    ret i1 true
+;
+  %s = ashr i4 %x, 3
+  %c = icmp sgt i4 %s, 8
+  ret i1 %c
+}
+
+define i1 @ashrsgt_03_09(i4 %x) {
+; CHECK-LABEL: @ashrsgt_03_09(
+; CHECK-NEXT:    ret i1 true
+;
+  %s = ashr i4 %x, 3
+  %c = icmp sgt i4 %s, 9
+  ret i1 %c
+}
+
+define i1 @ashrsgt_03_10(i4 %x) {
+; CHECK-LABEL: @ashrsgt_03_10(
+; CHECK-NEXT:    ret i1 true
+;
+  %s = ashr i4 %x, 3
+  %c = icmp sgt i4 %s, 10
+  ret i1 %c
+}
+
+define i1 @ashrsgt_03_11(i4 %x) {
+; CHECK-LABEL: @ashrsgt_03_11(
+; CHECK-NEXT:    ret i1 true
+;
+  %s = ashr i4 %x, 3
+  %c = icmp sgt i4 %s, 11
+  ret i1 %c
+}
+
+define i1 @ashrsgt_03_12(i4 %x) {
+; CHECK-LABEL: @ashrsgt_03_12(
+; CHECK-NEXT:    ret i1 true
+;
+  %s = ashr i4 %x, 3
+  %c = icmp sgt i4 %s, 12
+  ret i1 %c
+}
+
+define i1 @ashrsgt_03_13(i4 %x) {
+; CHECK-LABEL: @ashrsgt_03_13(
+; CHECK-NEXT:    ret i1 true
+;
+  %s = ashr i4 %x, 3
+  %c = icmp sgt i4 %s, 13
+  ret i1 %c
+}
+
+define i1 @ashrsgt_03_14(i4 %x) {
+; CHECK-LABEL: @ashrsgt_03_14(
+; CHECK-NEXT:    ret i1 true
+;
+  %s = ashr i4 %x, 3
+  %c = icmp sgt i4 %s, 14
+  ret i1 %c
+}
+
+define i1 @ashrsgt_03_15(i4 %x) {
+; CHECK-LABEL: @ashrsgt_03_15(
+; CHECK-NEXT:    [[C:%.*]] = icmp sgt i4 %x, -1
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %s = ashr i4 %x, 3
+  %c = icmp sgt i4 %s, 15
+  ret i1 %c
+}
+
+define i1 @ashrslt_01_00(i4 %x) {
+; CHECK-LABEL: @ashrslt_01_00(
+; CHECK-NEXT:    [[C:%.*]] = icmp slt i4 %x, 0
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %s = ashr i4 %x, 1
+  %c = icmp slt i4 %s, 0
+  ret i1 %c
+}
+
+define i1 @ashrslt_01_01(i4 %x) {
+; CHECK-LABEL: @ashrslt_01_01(
+; CHECK-NEXT:    [[C:%.*]] = icmp slt i4 %x, 2
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %s = ashr i4 %x, 1
+  %c = icmp slt i4 %s, 1
+  ret i1 %c
+}
+
+define i1 @ashrslt_01_02(i4 %x) {
+; CHECK-LABEL: @ashrslt_01_02(
+; CHECK-NEXT:    [[C:%.*]] = icmp slt i4 %x, 4
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %s = ashr i4 %x, 1
+  %c = icmp slt i4 %s, 2
+  ret i1 %c
+}
+
+define i1 @ashrslt_01_03(i4 %x) {
+; CHECK-LABEL: @ashrslt_01_03(
+; CHECK-NEXT:    [[C:%.*]] = icmp slt i4 %x, 6
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %s = ashr i4 %x, 1
+  %c = icmp slt i4 %s, 3
+  ret i1 %c
+}
+
+define i1 @ashrslt_01_04(i4 %x) {
+; CHECK-LABEL: @ashrslt_01_04(
+; CHECK-NEXT:    ret i1 true
+;
+  %s = ashr i4 %x, 1
+  %c = icmp slt i4 %s, 4
+  ret i1 %c
+}
+
+define i1 @ashrslt_01_05(i4 %x) {
+; CHECK-LABEL: @ashrslt_01_05(
+; CHECK-NEXT:    ret i1 true
+;
+  %s = ashr i4 %x, 1
+  %c = icmp slt i4 %s, 5
+  ret i1 %c
+}
+
+define i1 @ashrslt_01_06(i4 %x) {
+; CHECK-LABEL: @ashrslt_01_06(
+; CHECK-NEXT:    ret i1 true
+;
+  %s = ashr i4 %x, 1
+  %c = icmp slt i4 %s, 6
+  ret i1 %c
+}
+
+define i1 @ashrslt_01_07(i4 %x) {
+; CHECK-LABEL: @ashrslt_01_07(
+; CHECK-NEXT:    ret i1 true
+;
+  %s = ashr i4 %x, 1
+  %c = icmp slt i4 %s, 7
+  ret i1 %c
+}
+
+define i1 @ashrslt_01_08(i4 %x) {
+; CHECK-LABEL: @ashrslt_01_08(
+; CHECK-NEXT:    ret i1 false
+;
+  %s = ashr i4 %x, 1
+  %c = icmp slt i4 %s, 8
+  ret i1 %c
+}
+
+define i1 @ashrslt_01_09(i4 %x) {
+; CHECK-LABEL: @ashrslt_01_09(
+; CHECK-NEXT:    ret i1 false
+;
+  %s = ashr i4 %x, 1
+  %c = icmp slt i4 %s, 9
+  ret i1 %c
+}
+
+define i1 @ashrslt_01_10(i4 %x) {
+; CHECK-LABEL: @ashrslt_01_10(
+; CHECK-NEXT:    ret i1 false
+;
+  %s = ashr i4 %x, 1
+  %c = icmp slt i4 %s, 10
+  ret i1 %c
+}
+
+define i1 @ashrslt_01_11(i4 %x) {
+; CHECK-LABEL: @ashrslt_01_11(
+; CHECK-NEXT:    ret i1 false
+;
+  %s = ashr i4 %x, 1
+  %c = icmp slt i4 %s, 11
+  ret i1 %c
+}
+
+define i1 @ashrslt_01_12(i4 %x) {
+; CHECK-LABEL: @ashrslt_01_12(
+; CHECK-NEXT:    ret i1 false
+;
+  %s = ashr i4 %x, 1
+  %c = icmp slt i4 %s, 12
+  ret i1 %c
+}
+
+define i1 @ashrslt_01_13(i4 %x) {
+; CHECK-LABEL: @ashrslt_01_13(
+; CHECK-NEXT:    [[C:%.*]] = icmp slt i4 %x, -6
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %s = ashr i4 %x, 1
+  %c = icmp slt i4 %s, 13
+  ret i1 %c
+}
+
+define i1 @ashrslt_01_14(i4 %x) {
+; CHECK-LABEL: @ashrslt_01_14(
+; CHECK-NEXT:    [[C:%.*]] = icmp slt i4 %x, -4
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %s = ashr i4 %x, 1
+  %c = icmp slt i4 %s, 14
+  ret i1 %c
+}
+
+define i1 @ashrslt_01_15(i4 %x) {
+; CHECK-LABEL: @ashrslt_01_15(
+; CHECK-NEXT:    [[C:%.*]] = icmp slt i4 %x, -2
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %s = ashr i4 %x, 1
+  %c = icmp slt i4 %s, 15
+  ret i1 %c
+}
+
+define i1 @ashrslt_02_00(i4 %x) {
+; CHECK-LABEL: @ashrslt_02_00(
+; CHECK-NEXT:    [[C:%.*]] = icmp slt i4 %x, 0
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %s = ashr i4 %x, 2
+  %c = icmp slt i4 %s, 0
+  ret i1 %c
+}
+
+define i1 @ashrslt_02_01(i4 %x) {
+; CHECK-LABEL: @ashrslt_02_01(
+; CHECK-NEXT:    [[C:%.*]] = icmp slt i4 %x, 4
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %s = ashr i4 %x, 2
+  %c = icmp slt i4 %s, 1
+  ret i1 %c
+}
+
+define i1 @ashrslt_02_02(i4 %x) {
+; CHECK-LABEL: @ashrslt_02_02(
+; CHECK-NEXT:    ret i1 true
+;
+  %s = ashr i4 %x, 2
+  %c = icmp slt i4 %s, 2
+  ret i1 %c
+}
+
+define i1 @ashrslt_02_03(i4 %x) {
+; CHECK-LABEL: @ashrslt_02_03(
+; CHECK-NEXT:    ret i1 true
+;
+  %s = ashr i4 %x, 2
+  %c = icmp slt i4 %s, 3
+  ret i1 %c
+}
+
+define i1 @ashrslt_02_04(i4 %x) {
+; CHECK-LABEL: @ashrslt_02_04(
+; CHECK-NEXT:    ret i1 true
+;
+  %s = ashr i4 %x, 2
+  %c = icmp slt i4 %s, 4
+  ret i1 %c
+}
+
+define i1 @ashrslt_02_05(i4 %x) {
+; CHECK-LABEL: @ashrslt_02_05(
+; CHECK-NEXT:    ret i1 true
+;
+  %s = ashr i4 %x, 2
+  %c = icmp slt i4 %s, 5
+  ret i1 %c
+}
+
+define i1 @ashrslt_02_06(i4 %x) {
+; CHECK-LABEL: @ashrslt_02_06(
+; CHECK-NEXT:    ret i1 true
+;
+  %s = ashr i4 %x, 2
+  %c = icmp slt i4 %s, 6
+  ret i1 %c
+}
+
+define i1 @ashrslt_02_07(i4 %x) {
+; CHECK-LABEL: @ashrslt_02_07(
+; CHECK-NEXT:    ret i1 true
+;
+  %s = ashr i4 %x, 2
+  %c = icmp slt i4 %s, 7
+  ret i1 %c
+}
+
+define i1 @ashrslt_02_08(i4 %x) {
+; CHECK-LABEL: @ashrslt_02_08(
+; CHECK-NEXT:    ret i1 false
+;
+  %s = ashr i4 %x, 2
+  %c = icmp slt i4 %s, 8
+  ret i1 %c
+}
+
+define i1 @ashrslt_02_09(i4 %x) {
+; CHECK-LABEL: @ashrslt_02_09(
+; CHECK-NEXT:    ret i1 false
+;
+  %s = ashr i4 %x, 2
+  %c = icmp slt i4 %s, 9
+  ret i1 %c
+}
+
+define i1 @ashrslt_02_10(i4 %x) {
+; CHECK-LABEL: @ashrslt_02_10(
+; CHECK-NEXT:    ret i1 false
+;
+  %s = ashr i4 %x, 2
+  %c = icmp slt i4 %s, 10
+  ret i1 %c
+}
+
+define i1 @ashrslt_02_11(i4 %x) {
+; CHECK-LABEL: @ashrslt_02_11(
+; CHECK-NEXT:    ret i1 false
+;
+  %s = ashr i4 %x, 2
+  %c = icmp slt i4 %s, 11
+  ret i1 %c
+}
+
+define i1 @ashrslt_02_12(i4 %x) {
+; CHECK-LABEL: @ashrslt_02_12(
+; CHECK-NEXT:    ret i1 false
+;
+  %s = ashr i4 %x, 2
+  %c = icmp slt i4 %s, 12
+  ret i1 %c
+}
+
+define i1 @ashrslt_02_13(i4 %x) {
+; CHECK-LABEL: @ashrslt_02_13(
+; CHECK-NEXT:    ret i1 false
+;
+  %s = ashr i4 %x, 2
+  %c = icmp slt i4 %s, 13
+  ret i1 %c
+}
+
+define i1 @ashrslt_02_14(i4 %x) {
+; CHECK-LABEL: @ashrslt_02_14(
+; CHECK-NEXT:    ret i1 false
+;
+  %s = ashr i4 %x, 2
+  %c = icmp slt i4 %s, 14
+  ret i1 %c
+}
+
+define i1 @ashrslt_02_15(i4 %x) {
+; CHECK-LABEL: @ashrslt_02_15(
+; CHECK-NEXT:    [[C:%.*]] = icmp slt i4 %x, -4
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %s = ashr i4 %x, 2
+  %c = icmp slt i4 %s, 15
+  ret i1 %c
+}
+
+define i1 @ashrslt_03_00(i4 %x) {
+; CHECK-LABEL: @ashrslt_03_00(
+; CHECK-NEXT:    [[C:%.*]] = icmp slt i4 %x, 0
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %s = ashr i4 %x, 3
+  %c = icmp slt i4 %s, 0
+  ret i1 %c
+}
+
+define i1 @ashrslt_03_01(i4 %x) {
+; CHECK-LABEL: @ashrslt_03_01(
+; CHECK-NEXT:    ret i1 true
+;
+  %s = ashr i4 %x, 3
+  %c = icmp slt i4 %s, 1
+  ret i1 %c
+}
+
+define i1 @ashrslt_03_02(i4 %x) {
+; CHECK-LABEL: @ashrslt_03_02(
+; CHECK-NEXT:    ret i1 true
+;
+  %s = ashr i4 %x, 3
+  %c = icmp slt i4 %s, 2
+  ret i1 %c
+}
+
+define i1 @ashrslt_03_03(i4 %x) {
+; CHECK-LABEL: @ashrslt_03_03(
+; CHECK-NEXT:    ret i1 true
+;
+  %s = ashr i4 %x, 3
+  %c = icmp slt i4 %s, 3
+  ret i1 %c
+}
+
+define i1 @ashrslt_03_04(i4 %x) {
+; CHECK-LABEL: @ashrslt_03_04(
+; CHECK-NEXT:    ret i1 true
+;
+  %s = ashr i4 %x, 3
+  %c = icmp slt i4 %s, 4
+  ret i1 %c
+}
+
+define i1 @ashrslt_03_05(i4 %x) {
+; CHECK-LABEL: @ashrslt_03_05(
+; CHECK-NEXT:    ret i1 true
+;
+  %s = ashr i4 %x, 3
+  %c = icmp slt i4 %s, 5
+  ret i1 %c
+}
+
+define i1 @ashrslt_03_06(i4 %x) {
+; CHECK-LABEL: @ashrslt_03_06(
+; CHECK-NEXT:    ret i1 true
+;
+  %s = ashr i4 %x, 3
+  %c = icmp slt i4 %s, 6
+  ret i1 %c
+}
+
+define i1 @ashrslt_03_07(i4 %x) {
+; CHECK-LABEL: @ashrslt_03_07(
+; CHECK-NEXT:    ret i1 true
+;
+  %s = ashr i4 %x, 3
+  %c = icmp slt i4 %s, 7
+  ret i1 %c
+}
+
+define i1 @ashrslt_03_08(i4 %x) {
+; CHECK-LABEL: @ashrslt_03_08(
+; CHECK-NEXT:    ret i1 false
+;
+  %s = ashr i4 %x, 3
+  %c = icmp slt i4 %s, 8
+  ret i1 %c
+}
+
+define i1 @ashrslt_03_09(i4 %x) {
+; CHECK-LABEL: @ashrslt_03_09(
+; CHECK-NEXT:    ret i1 false
+;
+  %s = ashr i4 %x, 3
+  %c = icmp slt i4 %s, 9
+  ret i1 %c
+}
+
+define i1 @ashrslt_03_10(i4 %x) {
+; CHECK-LABEL: @ashrslt_03_10(
+; CHECK-NEXT:    ret i1 false
+;
+  %s = ashr i4 %x, 3
+  %c = icmp slt i4 %s, 10
+  ret i1 %c
+}
+
+define i1 @ashrslt_03_11(i4 %x) {
+; CHECK-LABEL: @ashrslt_03_11(
+; CHECK-NEXT:    ret i1 false
+;
+  %s = ashr i4 %x, 3
+  %c = icmp slt i4 %s, 11
+  ret i1 %c
+}
+
+define i1 @ashrslt_03_12(i4 %x) {
+; CHECK-LABEL: @ashrslt_03_12(
+; CHECK-NEXT:    ret i1 false
+;
+  %s = ashr i4 %x, 3
+  %c = icmp slt i4 %s, 12
+  ret i1 %c
+}
+
+define i1 @ashrslt_03_13(i4 %x) {
+; CHECK-LABEL: @ashrslt_03_13(
+; CHECK-NEXT:    ret i1 false
+;
+  %s = ashr i4 %x, 3
+  %c = icmp slt i4 %s, 13
+  ret i1 %c
+}
+
+define i1 @ashrslt_03_14(i4 %x) {
+; CHECK-LABEL: @ashrslt_03_14(
+; CHECK-NEXT:    ret i1 false
+;
+  %s = ashr i4 %x, 3
+  %c = icmp slt i4 %s, 14
+  ret i1 %c
+}
+
+define i1 @ashrslt_03_15(i4 %x) {
+; CHECK-LABEL: @ashrslt_03_15(
+; CHECK-NEXT:    ret i1 false
+;
+  %s = ashr i4 %x, 3
+  %c = icmp slt i4 %s, 15
+  ret i1 %c
+}
+
+define i1 @lshrugt_01_00_exact(i4 %x) {
+; CHECK-LABEL: @lshrugt_01_00_exact(
+; CHECK-NEXT:    [[C:%.*]] = icmp ne i4 %x, 0
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %s = lshr exact i4 %x, 1
+  %c = icmp ugt i4 %s, 0
+  ret i1 %c
+}
+
+define i1 @lshrugt_01_01_exact(i4 %x) {
+; CHECK-LABEL: @lshrugt_01_01_exact(
+; CHECK-NEXT:    [[C:%.*]] = icmp ugt i4 %x, 2
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %s = lshr exact i4 %x, 1
+  %c = icmp ugt i4 %s, 1
+  ret i1 %c
+}
+
+define i1 @lshrugt_01_02_exact(i4 %x) {
+; CHECK-LABEL: @lshrugt_01_02_exact(
+; CHECK-NEXT:    [[C:%.*]] = icmp ugt i4 %x, 4
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %s = lshr exact i4 %x, 1
+  %c = icmp ugt i4 %s, 2
+  ret i1 %c
+}
+
+define i1 @lshrugt_01_03_exact(i4 %x) {
+; CHECK-LABEL: @lshrugt_01_03_exact(
+; CHECK-NEXT:    [[C:%.*]] = icmp ugt i4 %x, 6
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %s = lshr exact i4 %x, 1
+  %c = icmp ugt i4 %s, 3
+  ret i1 %c
+}
+
+define i1 @lshrugt_01_04_exact(i4 %x) {
+; CHECK-LABEL: @lshrugt_01_04_exact(
+; CHECK-NEXT:    [[C:%.*]] = icmp ugt i4 %x, -8
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %s = lshr exact i4 %x, 1
+  %c = icmp ugt i4 %s, 4
+  ret i1 %c
+}
+
+define i1 @lshrugt_01_05_exact(i4 %x) {
+; CHECK-LABEL: @lshrugt_01_05_exact(
+; CHECK-NEXT:    [[C:%.*]] = icmp ugt i4 %x, -6
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %s = lshr exact i4 %x, 1
+  %c = icmp ugt i4 %s, 5
+  ret i1 %c
+}
+
+define i1 @lshrugt_01_06_exact(i4 %x) {
+; CHECK-LABEL: @lshrugt_01_06_exact(
+; CHECK-NEXT:    [[C:%.*]] = icmp eq i4 %x, -2
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %s = lshr exact i4 %x, 1
+  %c = icmp ugt i4 %s, 6
+  ret i1 %c
+}
+
+define i1 @lshrugt_01_07_exact(i4 %x) {
+; CHECK-LABEL: @lshrugt_01_07_exact(
+; CHECK-NEXT:    ret i1 false
+;
+  %s = lshr exact i4 %x, 1
+  %c = icmp ugt i4 %s, 7
+  ret i1 %c
+}
+
+define i1 @lshrugt_01_08_exact(i4 %x) {
+; CHECK-LABEL: @lshrugt_01_08_exact(
+; CHECK-NEXT:    ret i1 false
+;
+  %s = lshr exact i4 %x, 1
+  %c = icmp ugt i4 %s, 8
+  ret i1 %c
+}
+
+define i1 @lshrugt_01_09_exact(i4 %x) {
+; CHECK-LABEL: @lshrugt_01_09_exact(
+; CHECK-NEXT:    ret i1 false
+;
+  %s = lshr exact i4 %x, 1
+  %c = icmp ugt i4 %s, 9
+  ret i1 %c
+}
+
+define i1 @lshrugt_01_10_exact(i4 %x) {
+; CHECK-LABEL: @lshrugt_01_10_exact(
+; CHECK-NEXT:    ret i1 false
+;
+  %s = lshr exact i4 %x, 1
+  %c = icmp ugt i4 %s, 10
+  ret i1 %c
+}
+
+define i1 @lshrugt_01_11_exact(i4 %x) {
+; CHECK-LABEL: @lshrugt_01_11_exact(
+; CHECK-NEXT:    ret i1 false
+;
+  %s = lshr exact i4 %x, 1
+  %c = icmp ugt i4 %s, 11
+  ret i1 %c
+}
+
+define i1 @lshrugt_01_12_exact(i4 %x) {
+; CHECK-LABEL: @lshrugt_01_12_exact(
+; CHECK-NEXT:    ret i1 false
+;
+  %s = lshr exact i4 %x, 1
+  %c = icmp ugt i4 %s, 12
+  ret i1 %c
+}
+
+define i1 @lshrugt_01_13_exact(i4 %x) {
+; CHECK-LABEL: @lshrugt_01_13_exact(
+; CHECK-NEXT:    ret i1 false
+;
+  %s = lshr exact i4 %x, 1
+  %c = icmp ugt i4 %s, 13
+  ret i1 %c
+}
+
+define i1 @lshrugt_01_14_exact(i4 %x) {
+; CHECK-LABEL: @lshrugt_01_14_exact(
+; CHECK-NEXT:    ret i1 false
+;
+  %s = lshr exact i4 %x, 1
+  %c = icmp ugt i4 %s, 14
+  ret i1 %c
+}
+
+define i1 @lshrugt_01_15_exact(i4 %x) {
+; CHECK-LABEL: @lshrugt_01_15_exact(
+; CHECK-NEXT:    ret i1 false
+;
+  %s = lshr exact i4 %x, 1
+  %c = icmp ugt i4 %s, 15
+  ret i1 %c
+}
+
+define i1 @lshrugt_02_00_exact(i4 %x) {
+; CHECK-LABEL: @lshrugt_02_00_exact(
+; CHECK-NEXT:    [[C:%.*]] = icmp ne i4 %x, 0
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %s = lshr exact i4 %x, 2
+  %c = icmp ugt i4 %s, 0
+  ret i1 %c
+}
+
+define i1 @lshrugt_02_01_exact(i4 %x) {
+; CHECK-LABEL: @lshrugt_02_01_exact(
+; CHECK-NEXT:    [[C:%.*]] = icmp ugt i4 %x, 4
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %s = lshr exact i4 %x, 2
+  %c = icmp ugt i4 %s, 1
+  ret i1 %c
+}
+
+define i1 @lshrugt_02_02_exact(i4 %x) {
+; CHECK-LABEL: @lshrugt_02_02_exact(
+; CHECK-NEXT:    [[C:%.*]] = icmp eq i4 %x, -4
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %s = lshr exact i4 %x, 2
+  %c = icmp ugt i4 %s, 2
+  ret i1 %c
+}
+
+define i1 @lshrugt_02_03_exact(i4 %x) {
+; CHECK-LABEL: @lshrugt_02_03_exact(
+; CHECK-NEXT:    ret i1 false
+;
+  %s = lshr exact i4 %x, 2
+  %c = icmp ugt i4 %s, 3
+  ret i1 %c
+}
+
+define i1 @lshrugt_02_04_exact(i4 %x) {
+; CHECK-LABEL: @lshrugt_02_04_exact(
+; CHECK-NEXT:    ret i1 false
+;
+  %s = lshr exact i4 %x, 2
+  %c = icmp ugt i4 %s, 4
+  ret i1 %c
+}
+
+define i1 @lshrugt_02_05_exact(i4 %x) {
+; CHECK-LABEL: @lshrugt_02_05_exact(
+; CHECK-NEXT:    ret i1 false
+;
+  %s = lshr exact i4 %x, 2
+  %c = icmp ugt i4 %s, 5
+  ret i1 %c
+}
+
+define i1 @lshrugt_02_06_exact(i4 %x) {
+; CHECK-LABEL: @lshrugt_02_06_exact(
+; CHECK-NEXT:    ret i1 false
+;
+  %s = lshr exact i4 %x, 2
+  %c = icmp ugt i4 %s, 6
+  ret i1 %c
+}
+
+define i1 @lshrugt_02_07_exact(i4 %x) {
+; CHECK-LABEL: @lshrugt_02_07_exact(
+; CHECK-NEXT:    ret i1 false
+;
+  %s = lshr exact i4 %x, 2
+  %c = icmp ugt i4 %s, 7
+  ret i1 %c
+}
+
+define i1 @lshrugt_02_08_exact(i4 %x) {
+; CHECK-LABEL: @lshrugt_02_08_exact(
+; CHECK-NEXT:    ret i1 false
+;
+  %s = lshr exact i4 %x, 2
+  %c = icmp ugt i4 %s, 8
+  ret i1 %c
+}
+
+define i1 @lshrugt_02_09_exact(i4 %x) {
+; CHECK-LABEL: @lshrugt_02_09_exact(
+; CHECK-NEXT:    ret i1 false
+;
+  %s = lshr exact i4 %x, 2
+  %c = icmp ugt i4 %s, 9
+  ret i1 %c
+}
+
+define i1 @lshrugt_02_10_exact(i4 %x) {
+; CHECK-LABEL: @lshrugt_02_10_exact(
+; CHECK-NEXT:    ret i1 false
+;
+  %s = lshr exact i4 %x, 2
+  %c = icmp ugt i4 %s, 10
+  ret i1 %c
+}
+
+define i1 @lshrugt_02_11_exact(i4 %x) {
+; CHECK-LABEL: @lshrugt_02_11_exact(
+; CHECK-NEXT:    ret i1 false
+;
+  %s = lshr exact i4 %x, 2
+  %c = icmp ugt i4 %s, 11
+  ret i1 %c
+}
+
+define i1 @lshrugt_02_12_exact(i4 %x) {
+; CHECK-LABEL: @lshrugt_02_12_exact(
+; CHECK-NEXT:    ret i1 false
+;
+  %s = lshr exact i4 %x, 2
+  %c = icmp ugt i4 %s, 12
+  ret i1 %c
+}
+
+define i1 @lshrugt_02_13_exact(i4 %x) {
+; CHECK-LABEL: @lshrugt_02_13_exact(
+; CHECK-NEXT:    ret i1 false
+;
+  %s = lshr exact i4 %x, 2
+  %c = icmp ugt i4 %s, 13
+  ret i1 %c
+}
+
+define i1 @lshrugt_02_14_exact(i4 %x) {
+; CHECK-LABEL: @lshrugt_02_14_exact(
+; CHECK-NEXT:    ret i1 false
+;
+  %s = lshr exact i4 %x, 2
+  %c = icmp ugt i4 %s, 14
+  ret i1 %c
+}
+
+define i1 @lshrugt_02_15_exact(i4 %x) {
+; CHECK-LABEL: @lshrugt_02_15_exact(
+; CHECK-NEXT:    ret i1 false
+;
+  %s = lshr exact i4 %x, 2
+  %c = icmp ugt i4 %s, 15
+  ret i1 %c
+}
+
+define i1 @lshrugt_03_00_exact(i4 %x) {
+; CHECK-LABEL: @lshrugt_03_00_exact(
+; CHECK-NEXT:    [[C:%.*]] = icmp ne i4 %x, 0
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %s = lshr exact i4 %x, 3
+  %c = icmp ugt i4 %s, 0
+  ret i1 %c
+}
+
+define i1 @lshrugt_03_01_exact(i4 %x) {
+; CHECK-LABEL: @lshrugt_03_01_exact(
+; CHECK-NEXT:    ret i1 false
+;
+  %s = lshr exact i4 %x, 3
+  %c = icmp ugt i4 %s, 1
+  ret i1 %c
+}
+
+define i1 @lshrugt_03_02_exact(i4 %x) {
+; CHECK-LABEL: @lshrugt_03_02_exact(
+; CHECK-NEXT:    ret i1 false
+;
+  %s = lshr exact i4 %x, 3
+  %c = icmp ugt i4 %s, 2
+  ret i1 %c
+}
+
+define i1 @lshrugt_03_03_exact(i4 %x) {
+; CHECK-LABEL: @lshrugt_03_03_exact(
+; CHECK-NEXT:    ret i1 false
+;
+  %s = lshr exact i4 %x, 3
+  %c = icmp ugt i4 %s, 3
+  ret i1 %c
+}
+
+define i1 @lshrugt_03_04_exact(i4 %x) {
+; CHECK-LABEL: @lshrugt_03_04_exact(
+; CHECK-NEXT:    ret i1 false
+;
+  %s = lshr exact i4 %x, 3
+  %c = icmp ugt i4 %s, 4
+  ret i1 %c
+}
+
+define i1 @lshrugt_03_05_exact(i4 %x) {
+; CHECK-LABEL: @lshrugt_03_05_exact(
+; CHECK-NEXT:    ret i1 false
+;
+  %s = lshr exact i4 %x, 3
+  %c = icmp ugt i4 %s, 5
+  ret i1 %c
+}
+
+define i1 @lshrugt_03_06_exact(i4 %x) {
+; CHECK-LABEL: @lshrugt_03_06_exact(
+; CHECK-NEXT:    ret i1 false
+;
+  %s = lshr exact i4 %x, 3
+  %c = icmp ugt i4 %s, 6
+  ret i1 %c
+}
+
+define i1 @lshrugt_03_07_exact(i4 %x) {
+; CHECK-LABEL: @lshrugt_03_07_exact(
+; CHECK-NEXT:    ret i1 false
+;
+  %s = lshr exact i4 %x, 3
+  %c = icmp ugt i4 %s, 7
+  ret i1 %c
+}
+
+define i1 @lshrugt_03_08_exact(i4 %x) {
+; CHECK-LABEL: @lshrugt_03_08_exact(
+; CHECK-NEXT:    ret i1 false
+;
+  %s = lshr exact i4 %x, 3
+  %c = icmp ugt i4 %s, 8
+  ret i1 %c
+}
+
+define i1 @lshrugt_03_09_exact(i4 %x) {
+; CHECK-LABEL: @lshrugt_03_09_exact(
+; CHECK-NEXT:    ret i1 false
+;
+  %s = lshr exact i4 %x, 3
+  %c = icmp ugt i4 %s, 9
+  ret i1 %c
+}
+
+define i1 @lshrugt_03_10_exact(i4 %x) {
+; CHECK-LABEL: @lshrugt_03_10_exact(
+; CHECK-NEXT:    ret i1 false
+;
+  %s = lshr exact i4 %x, 3
+  %c = icmp ugt i4 %s, 10
+  ret i1 %c
+}
+
+define i1 @lshrugt_03_11_exact(i4 %x) {
+; CHECK-LABEL: @lshrugt_03_11_exact(
+; CHECK-NEXT:    ret i1 false
+;
+  %s = lshr exact i4 %x, 3
+  %c = icmp ugt i4 %s, 11
+  ret i1 %c
+}
+
+define i1 @lshrugt_03_12_exact(i4 %x) {
+; CHECK-LABEL: @lshrugt_03_12_exact(
+; CHECK-NEXT:    ret i1 false
+;
+  %s = lshr exact i4 %x, 3
+  %c = icmp ugt i4 %s, 12
+  ret i1 %c
+}
+
+define i1 @lshrugt_03_13_exact(i4 %x) {
+; CHECK-LABEL: @lshrugt_03_13_exact(
+; CHECK-NEXT:    ret i1 false
+;
+  %s = lshr exact i4 %x, 3
+  %c = icmp ugt i4 %s, 13
+  ret i1 %c
+}
+
+define i1 @lshrugt_03_14_exact(i4 %x) {
+; CHECK-LABEL: @lshrugt_03_14_exact(
+; CHECK-NEXT:    ret i1 false
+;
+  %s = lshr exact i4 %x, 3
+  %c = icmp ugt i4 %s, 14
+  ret i1 %c
+}
+
+define i1 @lshrugt_03_15_exact(i4 %x) {
+; CHECK-LABEL: @lshrugt_03_15_exact(
+; CHECK-NEXT:    ret i1 false
+;
+  %s = lshr exact i4 %x, 3
+  %c = icmp ugt i4 %s, 15
+  ret i1 %c
+}
+
+define i1 @lshrult_01_00_exact(i4 %x) {
+; CHECK-LABEL: @lshrult_01_00_exact(
+; CHECK-NEXT:    ret i1 false
+;
+  %s = lshr exact i4 %x, 1
+  %c = icmp ult i4 %s, 0
+  ret i1 %c
+}
+
+define i1 @lshrult_01_01_exact(i4 %x) {
+; CHECK-LABEL: @lshrult_01_01_exact(
+; CHECK-NEXT:    [[C:%.*]] = icmp eq i4 %x, 0
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %s = lshr exact i4 %x, 1
+  %c = icmp ult i4 %s, 1
+  ret i1 %c
+}
+
+define i1 @lshrult_01_02_exact(i4 %x) {
+; CHECK-LABEL: @lshrult_01_02_exact(
+; CHECK-NEXT:    [[C:%.*]] = icmp ult i4 %x, 4
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %s = lshr exact i4 %x, 1
+  %c = icmp ult i4 %s, 2
+  ret i1 %c
+}
+
+define i1 @lshrult_01_03_exact(i4 %x) {
+; CHECK-LABEL: @lshrult_01_03_exact(
+; CHECK-NEXT:    [[C:%.*]] = icmp ult i4 %x, 6
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %s = lshr exact i4 %x, 1
+  %c = icmp ult i4 %s, 3
+  ret i1 %c
+}
+
+define i1 @lshrult_01_04_exact(i4 %x) {
+; CHECK-LABEL: @lshrult_01_04_exact(
+; CHECK-NEXT:    [[C:%.*]] = icmp sgt i4 %x, -1
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %s = lshr exact i4 %x, 1
+  %c = icmp ult i4 %s, 4
+  ret i1 %c
+}
+
+define i1 @lshrult_01_05_exact(i4 %x) {
+; CHECK-LABEL: @lshrult_01_05_exact(
+; CHECK-NEXT:    [[C:%.*]] = icmp ult i4 %x, -6
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %s = lshr exact i4 %x, 1
+  %c = icmp ult i4 %s, 5
+  ret i1 %c
+}
+
+define i1 @lshrult_01_06_exact(i4 %x) {
+; CHECK-LABEL: @lshrult_01_06_exact(
+; CHECK-NEXT:    [[C:%.*]] = icmp ult i4 %x, -4
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %s = lshr exact i4 %x, 1
+  %c = icmp ult i4 %s, 6
+  ret i1 %c
+}
+
+define i1 @lshrult_01_07_exact(i4 %x) {
+; CHECK-LABEL: @lshrult_01_07_exact(
+; CHECK-NEXT:    [[C:%.*]] = icmp ne i4 %x, -2
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %s = lshr exact i4 %x, 1
+  %c = icmp ult i4 %s, 7
+  ret i1 %c
+}
+
+define i1 @lshrult_01_08_exact(i4 %x) {
+; CHECK-LABEL: @lshrult_01_08_exact(
+; CHECK-NEXT:    ret i1 true
+;
+  %s = lshr exact i4 %x, 1
+  %c = icmp ult i4 %s, 8
+  ret i1 %c
+}
+
+define i1 @lshrult_01_09_exact(i4 %x) {
+; CHECK-LABEL: @lshrult_01_09_exact(
+; CHECK-NEXT:    ret i1 true
+;
+  %s = lshr exact i4 %x, 1
+  %c = icmp ult i4 %s, 9
+  ret i1 %c
+}
+
+define i1 @lshrult_01_10_exact(i4 %x) {
+; CHECK-LABEL: @lshrult_01_10_exact(
+; CHECK-NEXT:    ret i1 true
+;
+  %s = lshr exact i4 %x, 1
+  %c = icmp ult i4 %s, 10
+  ret i1 %c
+}
+
+define i1 @lshrult_01_11_exact(i4 %x) {
+; CHECK-LABEL: @lshrult_01_11_exact(
+; CHECK-NEXT:    ret i1 true
+;
+  %s = lshr exact i4 %x, 1
+  %c = icmp ult i4 %s, 11
+  ret i1 %c
+}
+
+define i1 @lshrult_01_12_exact(i4 %x) {
+; CHECK-LABEL: @lshrult_01_12_exact(
+; CHECK-NEXT:    ret i1 true
+;
+  %s = lshr exact i4 %x, 1
+  %c = icmp ult i4 %s, 12
+  ret i1 %c
+}
+
+define i1 @lshrult_01_13_exact(i4 %x) {
+; CHECK-LABEL: @lshrult_01_13_exact(
+; CHECK-NEXT:    ret i1 true
+;
+  %s = lshr exact i4 %x, 1
+  %c = icmp ult i4 %s, 13
+  ret i1 %c
+}
+
+define i1 @lshrult_01_14_exact(i4 %x) {
+; CHECK-LABEL: @lshrult_01_14_exact(
+; CHECK-NEXT:    ret i1 true
+;
+  %s = lshr exact i4 %x, 1
+  %c = icmp ult i4 %s, 14
+  ret i1 %c
+}
+
+define i1 @lshrult_01_15_exact(i4 %x) {
+; CHECK-LABEL: @lshrult_01_15_exact(
+; CHECK-NEXT:    ret i1 true
+;
+  %s = lshr exact i4 %x, 1
+  %c = icmp ult i4 %s, 15
+  ret i1 %c
+}
+
+define i1 @lshrult_02_00_exact(i4 %x) {
+; CHECK-LABEL: @lshrult_02_00_exact(
+; CHECK-NEXT:    ret i1 false
+;
+  %s = lshr exact i4 %x, 2
+  %c = icmp ult i4 %s, 0
+  ret i1 %c
+}
+
+define i1 @lshrult_02_01_exact(i4 %x) {
+; CHECK-LABEL: @lshrult_02_01_exact(
+; CHECK-NEXT:    [[C:%.*]] = icmp eq i4 %x, 0
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %s = lshr exact i4 %x, 2
+  %c = icmp ult i4 %s, 1
+  ret i1 %c
+}
+
+define i1 @lshrult_02_02_exact(i4 %x) {
+; CHECK-LABEL: @lshrult_02_02_exact(
+; CHECK-NEXT:    [[C:%.*]] = icmp sgt i4 %x, -1
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %s = lshr exact i4 %x, 2
+  %c = icmp ult i4 %s, 2
+  ret i1 %c
+}
+
+define i1 @lshrult_02_03_exact(i4 %x) {
+; CHECK-LABEL: @lshrult_02_03_exact(
+; CHECK-NEXT:    [[C:%.*]] = icmp ne i4 %x, -4
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %s = lshr exact i4 %x, 2
+  %c = icmp ult i4 %s, 3
+  ret i1 %c
+}
+
+define i1 @lshrult_02_04_exact(i4 %x) {
+; CHECK-LABEL: @lshrult_02_04_exact(
+; CHECK-NEXT:    ret i1 true
+;
+  %s = lshr exact i4 %x, 2
+  %c = icmp ult i4 %s, 4
+  ret i1 %c
+}
+
+define i1 @lshrult_02_05_exact(i4 %x) {
+; CHECK-LABEL: @lshrult_02_05_exact(
+; CHECK-NEXT:    ret i1 true
+;
+  %s = lshr exact i4 %x, 2
+  %c = icmp ult i4 %s, 5
+  ret i1 %c
+}
+
+define i1 @lshrult_02_06_exact(i4 %x) {
+; CHECK-LABEL: @lshrult_02_06_exact(
+; CHECK-NEXT:    ret i1 true
+;
+  %s = lshr exact i4 %x, 2
+  %c = icmp ult i4 %s, 6
+  ret i1 %c
+}
+
+define i1 @lshrult_02_07_exact(i4 %x) {
+; CHECK-LABEL: @lshrult_02_07_exact(
+; CHECK-NEXT:    ret i1 true
+;
+  %s = lshr exact i4 %x, 2
+  %c = icmp ult i4 %s, 7
+  ret i1 %c
+}
+
+define i1 @lshrult_02_08_exact(i4 %x) {
+; CHECK-LABEL: @lshrult_02_08_exact(
+; CHECK-NEXT:    ret i1 true
+;
+  %s = lshr exact i4 %x, 2
+  %c = icmp ult i4 %s, 8
+  ret i1 %c
+}
+
+define i1 @lshrult_02_09_exact(i4 %x) {
+; CHECK-LABEL: @lshrult_02_09_exact(
+; CHECK-NEXT:    ret i1 true
+;
+  %s = lshr exact i4 %x, 2
+  %c = icmp ult i4 %s, 9
+  ret i1 %c
+}
+
+define i1 @lshrult_02_10_exact(i4 %x) {
+; CHECK-LABEL: @lshrult_02_10_exact(
+; CHECK-NEXT:    ret i1 true
+;
+  %s = lshr exact i4 %x, 2
+  %c = icmp ult i4 %s, 10
+  ret i1 %c
+}
+
+define i1 @lshrult_02_11_exact(i4 %x) {
+; CHECK-LABEL: @lshrult_02_11_exact(
+; CHECK-NEXT:    ret i1 true
+;
+  %s = lshr exact i4 %x, 2
+  %c = icmp ult i4 %s, 11
+  ret i1 %c
+}
+
+define i1 @lshrult_02_12_exact(i4 %x) {
+; CHECK-LABEL: @lshrult_02_12_exact(
+; CHECK-NEXT:    ret i1 true
+;
+  %s = lshr exact i4 %x, 2
+  %c = icmp ult i4 %s, 12
+  ret i1 %c
+}
+
+define i1 @lshrult_02_13_exact(i4 %x) {
+; CHECK-LABEL: @lshrult_02_13_exact(
+; CHECK-NEXT:    ret i1 true
+;
+  %s = lshr exact i4 %x, 2
+  %c = icmp ult i4 %s, 13
+  ret i1 %c
+}
+
+define i1 @lshrult_02_14_exact(i4 %x) {
+; CHECK-LABEL: @lshrult_02_14_exact(
+; CHECK-NEXT:    ret i1 true
+;
+  %s = lshr exact i4 %x, 2
+  %c = icmp ult i4 %s, 14
+  ret i1 %c
+}
+
+define i1 @lshrult_02_15_exact(i4 %x) {
+; CHECK-LABEL: @lshrult_02_15_exact(
+; CHECK-NEXT:    ret i1 true
+;
+  %s = lshr exact i4 %x, 2
+  %c = icmp ult i4 %s, 15
+  ret i1 %c
+}
+
+define i1 @lshrult_03_00_exact(i4 %x) {
+; CHECK-LABEL: @lshrult_03_00_exact(
+; CHECK-NEXT:    ret i1 false
+;
+  %s = lshr exact i4 %x, 3
+  %c = icmp ult i4 %s, 0
+  ret i1 %c
+}
+
+define i1 @lshrult_03_01_exact(i4 %x) {
+; CHECK-LABEL: @lshrult_03_01_exact(
+; CHECK-NEXT:    [[C:%.*]] = icmp ne i4 %x, -8
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %s = lshr exact i4 %x, 3
+  %c = icmp ult i4 %s, 1
+  ret i1 %c
+}
+
+define i1 @lshrult_03_02_exact(i4 %x) {
+; CHECK-LABEL: @lshrult_03_02_exact(
+; CHECK-NEXT:    ret i1 true
+;
+  %s = lshr exact i4 %x, 3
+  %c = icmp ult i4 %s, 2
+  ret i1 %c
+}
+
+define i1 @lshrult_03_03_exact(i4 %x) {
+; CHECK-LABEL: @lshrult_03_03_exact(
+; CHECK-NEXT:    ret i1 true
+;
+  %s = lshr exact i4 %x, 3
+  %c = icmp ult i4 %s, 3
+  ret i1 %c
+}
+
+define i1 @lshrult_03_04_exact(i4 %x) {
+; CHECK-LABEL: @lshrult_03_04_exact(
+; CHECK-NEXT:    ret i1 true
+;
+  %s = lshr exact i4 %x, 3
+  %c = icmp ult i4 %s, 4
+  ret i1 %c
+}
+
+define i1 @lshrult_03_05_exact(i4 %x) {
+; CHECK-LABEL: @lshrult_03_05_exact(
+; CHECK-NEXT:    ret i1 true
+;
+  %s = lshr exact i4 %x, 3
+  %c = icmp ult i4 %s, 5
+  ret i1 %c
+}
+
+define i1 @lshrult_03_06_exact(i4 %x) {
+; CHECK-LABEL: @lshrult_03_06_exact(
+; CHECK-NEXT:    ret i1 true
+;
+  %s = lshr exact i4 %x, 3
+  %c = icmp ult i4 %s, 6
+  ret i1 %c
+}
+
+define i1 @lshrult_03_07_exact(i4 %x) {
+; CHECK-LABEL: @lshrult_03_07_exact(
+; CHECK-NEXT:    ret i1 true
+;
+  %s = lshr exact i4 %x, 3
+  %c = icmp ult i4 %s, 7
+  ret i1 %c
+}
+
+define i1 @lshrult_03_08_exact(i4 %x) {
+; CHECK-LABEL: @lshrult_03_08_exact(
+; CHECK-NEXT:    ret i1 true
+;
+  %s = lshr exact i4 %x, 3
+  %c = icmp ult i4 %s, 8
+  ret i1 %c
+}
+
+define i1 @lshrult_03_09_exact(i4 %x) {
+; CHECK-LABEL: @lshrult_03_09_exact(
+; CHECK-NEXT:    ret i1 true
+;
+  %s = lshr exact i4 %x, 3
+  %c = icmp ult i4 %s, 9
+  ret i1 %c
+}
+
+define i1 @lshrult_03_10_exact(i4 %x) {
+; CHECK-LABEL: @lshrult_03_10_exact(
+; CHECK-NEXT:    ret i1 true
+;
+  %s = lshr exact i4 %x, 3
+  %c = icmp ult i4 %s, 10
+  ret i1 %c
+}
+
+define i1 @lshrult_03_11_exact(i4 %x) {
+; CHECK-LABEL: @lshrult_03_11_exact(
+; CHECK-NEXT:    ret i1 true
+;
+  %s = lshr exact i4 %x, 3
+  %c = icmp ult i4 %s, 11
+  ret i1 %c
+}
+
+define i1 @lshrult_03_12_exact(i4 %x) {
+; CHECK-LABEL: @lshrult_03_12_exact(
+; CHECK-NEXT:    ret i1 true
+;
+  %s = lshr exact i4 %x, 3
+  %c = icmp ult i4 %s, 12
+  ret i1 %c
+}
+
+define i1 @lshrult_03_13_exact(i4 %x) {
+; CHECK-LABEL: @lshrult_03_13_exact(
+; CHECK-NEXT:    ret i1 true
+;
+  %s = lshr exact i4 %x, 3
+  %c = icmp ult i4 %s, 13
+  ret i1 %c
+}
+
+define i1 @lshrult_03_14_exact(i4 %x) {
+; CHECK-LABEL: @lshrult_03_14_exact(
+; CHECK-NEXT:    ret i1 true
+;
+  %s = lshr exact i4 %x, 3
+  %c = icmp ult i4 %s, 14
+  ret i1 %c
+}
+
+define i1 @lshrult_03_15_exact(i4 %x) {
+; CHECK-LABEL: @lshrult_03_15_exact(
+; CHECK-NEXT:    ret i1 true
+;
+  %s = lshr exact i4 %x, 3
+  %c = icmp ult i4 %s, 15
+  ret i1 %c
+}
+
+define i1 @ashrsgt_01_00_exact(i4 %x) {
+; CHECK-LABEL: @ashrsgt_01_00_exact(
+; CHECK-NEXT:    [[C:%.*]] = icmp sgt i4 %x, 0
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %s = ashr exact i4 %x, 1
+  %c = icmp sgt i4 %s, 0
+  ret i1 %c
+}
+
+define i1 @ashrsgt_01_01_exact(i4 %x) {
+; CHECK-LABEL: @ashrsgt_01_01_exact(
+; CHECK-NEXT:    [[C:%.*]] = icmp sgt i4 %x, 2
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %s = ashr exact i4 %x, 1
+  %c = icmp sgt i4 %s, 1
+  ret i1 %c
+}
+
+define i1 @ashrsgt_01_02_exact(i4 %x) {
+; CHECK-LABEL: @ashrsgt_01_02_exact(
+; CHECK-NEXT:    [[C:%.*]] = icmp sgt i4 %x, 4
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %s = ashr exact i4 %x, 1
+  %c = icmp sgt i4 %s, 2
+  ret i1 %c
+}
+
+define i1 @ashrsgt_01_03_exact(i4 %x) {
+; CHECK-LABEL: @ashrsgt_01_03_exact(
+; CHECK-NEXT:    ret i1 false
+;
+  %s = ashr exact i4 %x, 1
+  %c = icmp sgt i4 %s, 3
+  ret i1 %c
+}
+
+define i1 @ashrsgt_01_04_exact(i4 %x) {
+; CHECK-LABEL: @ashrsgt_01_04_exact(
+; CHECK-NEXT:    ret i1 false
+;
+  %s = ashr exact i4 %x, 1
+  %c = icmp sgt i4 %s, 4
+  ret i1 %c
+}
+
+define i1 @ashrsgt_01_05_exact(i4 %x) {
+; CHECK-LABEL: @ashrsgt_01_05_exact(
+; CHECK-NEXT:    ret i1 false
+;
+  %s = ashr exact i4 %x, 1
+  %c = icmp sgt i4 %s, 5
+  ret i1 %c
+}
+
+define i1 @ashrsgt_01_06_exact(i4 %x) {
+; CHECK-LABEL: @ashrsgt_01_06_exact(
+; CHECK-NEXT:    ret i1 false
+;
+  %s = ashr exact i4 %x, 1
+  %c = icmp sgt i4 %s, 6
+  ret i1 %c
+}
+
+define i1 @ashrsgt_01_07_exact(i4 %x) {
+; CHECK-LABEL: @ashrsgt_01_07_exact(
+; CHECK-NEXT:    ret i1 false
+;
+  %s = ashr exact i4 %x, 1
+  %c = icmp sgt i4 %s, 7
+  ret i1 %c
+}
+
+define i1 @ashrsgt_01_08_exact(i4 %x) {
+; CHECK-LABEL: @ashrsgt_01_08_exact(
+; CHECK-NEXT:    ret i1 true
+;
+  %s = ashr exact i4 %x, 1
+  %c = icmp sgt i4 %s, 8
+  ret i1 %c
+}
+
+define i1 @ashrsgt_01_09_exact(i4 %x) {
+; CHECK-LABEL: @ashrsgt_01_09_exact(
+; CHECK-NEXT:    ret i1 true
+;
+  %s = ashr exact i4 %x, 1
+  %c = icmp sgt i4 %s, 9
+  ret i1 %c
+}
+
+define i1 @ashrsgt_01_10_exact(i4 %x) {
+; CHECK-LABEL: @ashrsgt_01_10_exact(
+; CHECK-NEXT:    ret i1 true
+;
+  %s = ashr exact i4 %x, 1
+  %c = icmp sgt i4 %s, 10
+  ret i1 %c
+}
+
+define i1 @ashrsgt_01_11_exact(i4 %x) {
+; CHECK-LABEL: @ashrsgt_01_11_exact(
+; CHECK-NEXT:    ret i1 true
+;
+  %s = ashr exact i4 %x, 1
+  %c = icmp sgt i4 %s, 11
+  ret i1 %c
+}
+
+define i1 @ashrsgt_01_12_exact(i4 %x) {
+; CHECK-LABEL: @ashrsgt_01_12_exact(
+; CHECK-NEXT:    [[C:%.*]] = icmp ne i4 %x, -8
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %s = ashr exact i4 %x, 1
+  %c = icmp sgt i4 %s, 12
+  ret i1 %c
+}
+
+define i1 @ashrsgt_01_13_exact(i4 %x) {
+; CHECK-LABEL: @ashrsgt_01_13_exact(
+; CHECK-NEXT:    [[C:%.*]] = icmp sgt i4 %x, -6
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %s = ashr exact i4 %x, 1
+  %c = icmp sgt i4 %s, 13
+  ret i1 %c
+}
+
+define i1 @ashrsgt_01_14_exact(i4 %x) {
+; CHECK-LABEL: @ashrsgt_01_14_exact(
+; CHECK-NEXT:    [[C:%.*]] = icmp sgt i4 %x, -4
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %s = ashr exact i4 %x, 1
+  %c = icmp sgt i4 %s, 14
+  ret i1 %c
+}
+
+define i1 @ashrsgt_01_15_exact(i4 %x) {
+; CHECK-LABEL: @ashrsgt_01_15_exact(
+; CHECK-NEXT:    [[C:%.*]] = icmp sgt i4 %x, -1
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %s = ashr exact i4 %x, 1
+  %c = icmp sgt i4 %s, 15
+  ret i1 %c
+}
+
+define i1 @ashrsgt_02_00_exact(i4 %x) {
+; CHECK-LABEL: @ashrsgt_02_00_exact(
+; CHECK-NEXT:    [[C:%.*]] = icmp sgt i4 %x, 0
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %s = ashr exact i4 %x, 2
+  %c = icmp sgt i4 %s, 0
+  ret i1 %c
+}
+
+define i1 @ashrsgt_02_01_exact(i4 %x) {
+; CHECK-LABEL: @ashrsgt_02_01_exact(
+; CHECK-NEXT:    ret i1 false
+;
+  %s = ashr exact i4 %x, 2
+  %c = icmp sgt i4 %s, 1
+  ret i1 %c
+}
+
+define i1 @ashrsgt_02_02_exact(i4 %x) {
+; CHECK-LABEL: @ashrsgt_02_02_exact(
+; CHECK-NEXT:    ret i1 false
+;
+  %s = ashr exact i4 %x, 2
+  %c = icmp sgt i4 %s, 2
+  ret i1 %c
+}
+
+define i1 @ashrsgt_02_03_exact(i4 %x) {
+; CHECK-LABEL: @ashrsgt_02_03_exact(
+; CHECK-NEXT:    ret i1 false
+;
+  %s = ashr exact i4 %x, 2
+  %c = icmp sgt i4 %s, 3
+  ret i1 %c
+}
+
+define i1 @ashrsgt_02_04_exact(i4 %x) {
+; CHECK-LABEL: @ashrsgt_02_04_exact(
+; CHECK-NEXT:    ret i1 false
+;
+  %s = ashr exact i4 %x, 2
+  %c = icmp sgt i4 %s, 4
+  ret i1 %c
+}
+
+define i1 @ashrsgt_02_05_exact(i4 %x) {
+; CHECK-LABEL: @ashrsgt_02_05_exact(
+; CHECK-NEXT:    ret i1 false
+;
+  %s = ashr exact i4 %x, 2
+  %c = icmp sgt i4 %s, 5
+  ret i1 %c
+}
+
+define i1 @ashrsgt_02_06_exact(i4 %x) {
+; CHECK-LABEL: @ashrsgt_02_06_exact(
+; CHECK-NEXT:    ret i1 false
+;
+  %s = ashr exact i4 %x, 2
+  %c = icmp sgt i4 %s, 6
+  ret i1 %c
+}
+
+define i1 @ashrsgt_02_07_exact(i4 %x) {
+; CHECK-LABEL: @ashrsgt_02_07_exact(
+; CHECK-NEXT:    ret i1 false
+;
+  %s = ashr exact i4 %x, 2
+  %c = icmp sgt i4 %s, 7
+  ret i1 %c
+}
+
+define i1 @ashrsgt_02_08_exact(i4 %x) {
+; CHECK-LABEL: @ashrsgt_02_08_exact(
+; CHECK-NEXT:    ret i1 true
+;
+  %s = ashr exact i4 %x, 2
+  %c = icmp sgt i4 %s, 8
+  ret i1 %c
+}
+
+define i1 @ashrsgt_02_09_exact(i4 %x) {
+; CHECK-LABEL: @ashrsgt_02_09_exact(
+; CHECK-NEXT:    ret i1 true
+;
+  %s = ashr exact i4 %x, 2
+  %c = icmp sgt i4 %s, 9
+  ret i1 %c
+}
+
+define i1 @ashrsgt_02_10_exact(i4 %x) {
+; CHECK-LABEL: @ashrsgt_02_10_exact(
+; CHECK-NEXT:    ret i1 true
+;
+  %s = ashr exact i4 %x, 2
+  %c = icmp sgt i4 %s, 10
+  ret i1 %c
+}
+
+define i1 @ashrsgt_02_11_exact(i4 %x) {
+; CHECK-LABEL: @ashrsgt_02_11_exact(
+; CHECK-NEXT:    ret i1 true
+;
+  %s = ashr exact i4 %x, 2
+  %c = icmp sgt i4 %s, 11
+  ret i1 %c
+}
+
+define i1 @ashrsgt_02_12_exact(i4 %x) {
+; CHECK-LABEL: @ashrsgt_02_12_exact(
+; CHECK-NEXT:    ret i1 true
+;
+  %s = ashr exact i4 %x, 2
+  %c = icmp sgt i4 %s, 12
+  ret i1 %c
+}
+
+define i1 @ashrsgt_02_13_exact(i4 %x) {
+; CHECK-LABEL: @ashrsgt_02_13_exact(
+; CHECK-NEXT:    ret i1 true
+;
+  %s = ashr exact i4 %x, 2
+  %c = icmp sgt i4 %s, 13
+  ret i1 %c
+}
+
+define i1 @ashrsgt_02_14_exact(i4 %x) {
+; CHECK-LABEL: @ashrsgt_02_14_exact(
+; CHECK-NEXT:    [[C:%.*]] = icmp ne i4 %x, -8
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %s = ashr exact i4 %x, 2
+  %c = icmp sgt i4 %s, 14
+  ret i1 %c
+}
+
+define i1 @ashrsgt_02_15_exact(i4 %x) {
+; CHECK-LABEL: @ashrsgt_02_15_exact(
+; CHECK-NEXT:    [[C:%.*]] = icmp sgt i4 %x, -1
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %s = ashr exact i4 %x, 2
+  %c = icmp sgt i4 %s, 15
+  ret i1 %c
+}
+
+define i1 @ashrsgt_03_00_exact(i4 %x) {
+; CHECK-LABEL: @ashrsgt_03_00_exact(
+; CHECK-NEXT:    ret i1 false
+;
+  %s = ashr exact i4 %x, 3
+  %c = icmp sgt i4 %s, 0
+  ret i1 %c
+}
+
+define i1 @ashrsgt_03_01_exact(i4 %x) {
+; CHECK-LABEL: @ashrsgt_03_01_exact(
+; CHECK-NEXT:    ret i1 false
+;
+  %s = ashr exact i4 %x, 3
+  %c = icmp sgt i4 %s, 1
+  ret i1 %c
+}
+
+define i1 @ashrsgt_03_02_exact(i4 %x) {
+; CHECK-LABEL: @ashrsgt_03_02_exact(
+; CHECK-NEXT:    ret i1 false
+;
+  %s = ashr exact i4 %x, 3
+  %c = icmp sgt i4 %s, 2
+  ret i1 %c
+}
+
+define i1 @ashrsgt_03_03_exact(i4 %x) {
+; CHECK-LABEL: @ashrsgt_03_03_exact(
+; CHECK-NEXT:    ret i1 false
+;
+  %s = ashr exact i4 %x, 3
+  %c = icmp sgt i4 %s, 3
+  ret i1 %c
+}
+
+define i1 @ashrsgt_03_04_exact(i4 %x) {
+; CHECK-LABEL: @ashrsgt_03_04_exact(
+; CHECK-NEXT:    ret i1 false
+;
+  %s = ashr exact i4 %x, 3
+  %c = icmp sgt i4 %s, 4
+  ret i1 %c
+}
+
+define i1 @ashrsgt_03_05_exact(i4 %x) {
+; CHECK-LABEL: @ashrsgt_03_05_exact(
+; CHECK-NEXT:    ret i1 false
+;
+  %s = ashr exact i4 %x, 3
+  %c = icmp sgt i4 %s, 5
+  ret i1 %c
+}
+
+define i1 @ashrsgt_03_06_exact(i4 %x) {
+; CHECK-LABEL: @ashrsgt_03_06_exact(
+; CHECK-NEXT:    ret i1 false
+;
+  %s = ashr exact i4 %x, 3
+  %c = icmp sgt i4 %s, 6
+  ret i1 %c
+}
+
+define i1 @ashrsgt_03_07_exact(i4 %x) {
+; CHECK-LABEL: @ashrsgt_03_07_exact(
+; CHECK-NEXT:    ret i1 false
+;
+  %s = ashr exact i4 %x, 3
+  %c = icmp sgt i4 %s, 7
+  ret i1 %c
+}
+
+define i1 @ashrsgt_03_08_exact(i4 %x) {
+; CHECK-LABEL: @ashrsgt_03_08_exact(
+; CHECK-NEXT:    ret i1 true
+;
+  %s = ashr exact i4 %x, 3
+  %c = icmp sgt i4 %s, 8
+  ret i1 %c
+}
+
+define i1 @ashrsgt_03_09_exact(i4 %x) {
+; CHECK-LABEL: @ashrsgt_03_09_exact(
+; CHECK-NEXT:    ret i1 true
+;
+  %s = ashr exact i4 %x, 3
+  %c = icmp sgt i4 %s, 9
+  ret i1 %c
+}
+
+define i1 @ashrsgt_03_10_exact(i4 %x) {
+; CHECK-LABEL: @ashrsgt_03_10_exact(
+; CHECK-NEXT:    ret i1 true
+;
+  %s = ashr exact i4 %x, 3
+  %c = icmp sgt i4 %s, 10
+  ret i1 %c
+}
+
+define i1 @ashrsgt_03_11_exact(i4 %x) {
+; CHECK-LABEL: @ashrsgt_03_11_exact(
+; CHECK-NEXT:    ret i1 true
+;
+  %s = ashr exact i4 %x, 3
+  %c = icmp sgt i4 %s, 11
+  ret i1 %c
+}
+
+define i1 @ashrsgt_03_12_exact(i4 %x) {
+; CHECK-LABEL: @ashrsgt_03_12_exact(
+; CHECK-NEXT:    ret i1 true
+;
+  %s = ashr exact i4 %x, 3
+  %c = icmp sgt i4 %s, 12
+  ret i1 %c
+}
+
+define i1 @ashrsgt_03_13_exact(i4 %x) {
+; CHECK-LABEL: @ashrsgt_03_13_exact(
+; CHECK-NEXT:    ret i1 true
+;
+  %s = ashr exact i4 %x, 3
+  %c = icmp sgt i4 %s, 13
+  ret i1 %c
+}
+
+define i1 @ashrsgt_03_14_exact(i4 %x) {
+; CHECK-LABEL: @ashrsgt_03_14_exact(
+; CHECK-NEXT:    ret i1 true
+;
+  %s = ashr exact i4 %x, 3
+  %c = icmp sgt i4 %s, 14
+  ret i1 %c
+}
+
+define i1 @ashrsgt_03_15_exact(i4 %x) {
+; CHECK-LABEL: @ashrsgt_03_15_exact(
+; CHECK-NEXT:    [[C:%.*]] = icmp sgt i4 %x, -1
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %s = ashr exact i4 %x, 3
+  %c = icmp sgt i4 %s, 15
+  ret i1 %c
+}
+
+define i1 @ashrslt_01_00_exact(i4 %x) {
+; CHECK-LABEL: @ashrslt_01_00_exact(
+; CHECK-NEXT:    [[C:%.*]] = icmp slt i4 %x, 0
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %s = ashr exact i4 %x, 1
+  %c = icmp slt i4 %s, 0
+  ret i1 %c
+}
+
+define i1 @ashrslt_01_01_exact(i4 %x) {
+; CHECK-LABEL: @ashrslt_01_01_exact(
+; CHECK-NEXT:    [[C:%.*]] = icmp slt i4 %x, 2
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %s = ashr exact i4 %x, 1
+  %c = icmp slt i4 %s, 1
+  ret i1 %c
+}
+
+define i1 @ashrslt_01_02_exact(i4 %x) {
+; CHECK-LABEL: @ashrslt_01_02_exact(
+; CHECK-NEXT:    [[C:%.*]] = icmp slt i4 %x, 4
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %s = ashr exact i4 %x, 1
+  %c = icmp slt i4 %s, 2
+  ret i1 %c
+}
+
+define i1 @ashrslt_01_03_exact(i4 %x) {
+; CHECK-LABEL: @ashrslt_01_03_exact(
+; CHECK-NEXT:    [[C:%.*]] = icmp slt i4 %x, 6
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %s = ashr exact i4 %x, 1
+  %c = icmp slt i4 %s, 3
+  ret i1 %c
+}
+
+define i1 @ashrslt_01_04_exact(i4 %x) {
+; CHECK-LABEL: @ashrslt_01_04_exact(
+; CHECK-NEXT:    ret i1 true
+;
+  %s = ashr exact i4 %x, 1
+  %c = icmp slt i4 %s, 4
+  ret i1 %c
+}
+
+define i1 @ashrslt_01_05_exact(i4 %x) {
+; CHECK-LABEL: @ashrslt_01_05_exact(
+; CHECK-NEXT:    ret i1 true
+;
+  %s = ashr exact i4 %x, 1
+  %c = icmp slt i4 %s, 5
+  ret i1 %c
+}
+
+define i1 @ashrslt_01_06_exact(i4 %x) {
+; CHECK-LABEL: @ashrslt_01_06_exact(
+; CHECK-NEXT:    ret i1 true
+;
+  %s = ashr exact i4 %x, 1
+  %c = icmp slt i4 %s, 6
+  ret i1 %c
+}
+
+define i1 @ashrslt_01_07_exact(i4 %x) {
+; CHECK-LABEL: @ashrslt_01_07_exact(
+; CHECK-NEXT:    ret i1 true
+;
+  %s = ashr exact i4 %x, 1
+  %c = icmp slt i4 %s, 7
+  ret i1 %c
+}
+
+define i1 @ashrslt_01_08_exact(i4 %x) {
+; CHECK-LABEL: @ashrslt_01_08_exact(
+; CHECK-NEXT:    ret i1 false
+;
+  %s = ashr exact i4 %x, 1
+  %c = icmp slt i4 %s, 8
+  ret i1 %c
+}
+
+define i1 @ashrslt_01_09_exact(i4 %x) {
+; CHECK-LABEL: @ashrslt_01_09_exact(
+; CHECK-NEXT:    ret i1 false
+;
+  %s = ashr exact i4 %x, 1
+  %c = icmp slt i4 %s, 9
+  ret i1 %c
+}
+
+define i1 @ashrslt_01_10_exact(i4 %x) {
+; CHECK-LABEL: @ashrslt_01_10_exact(
+; CHECK-NEXT:    ret i1 false
+;
+  %s = ashr exact i4 %x, 1
+  %c = icmp slt i4 %s, 10
+  ret i1 %c
+}
+
+define i1 @ashrslt_01_11_exact(i4 %x) {
+; CHECK-LABEL: @ashrslt_01_11_exact(
+; CHECK-NEXT:    ret i1 false
+;
+  %s = ashr exact i4 %x, 1
+  %c = icmp slt i4 %s, 11
+  ret i1 %c
+}
+
+define i1 @ashrslt_01_12_exact(i4 %x) {
+; CHECK-LABEL: @ashrslt_01_12_exact(
+; CHECK-NEXT:    ret i1 false
+;
+  %s = ashr exact i4 %x, 1
+  %c = icmp slt i4 %s, 12
+  ret i1 %c
+}
+
+define i1 @ashrslt_01_13_exact(i4 %x) {
+; CHECK-LABEL: @ashrslt_01_13_exact(
+; CHECK-NEXT:    [[C:%.*]] = icmp slt i4 %x, -6
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %s = ashr exact i4 %x, 1
+  %c = icmp slt i4 %s, 13
+  ret i1 %c
+}
+
+define i1 @ashrslt_01_14_exact(i4 %x) {
+; CHECK-LABEL: @ashrslt_01_14_exact(
+; CHECK-NEXT:    [[C:%.*]] = icmp slt i4 %x, -4
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %s = ashr exact i4 %x, 1
+  %c = icmp slt i4 %s, 14
+  ret i1 %c
+}
+
+define i1 @ashrslt_01_15_exact(i4 %x) {
+; CHECK-LABEL: @ashrslt_01_15_exact(
+; CHECK-NEXT:    [[C:%.*]] = icmp slt i4 %x, -2
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %s = ashr exact i4 %x, 1
+  %c = icmp slt i4 %s, 15
+  ret i1 %c
+}
+
+define i1 @ashrslt_02_00_exact(i4 %x) {
+; CHECK-LABEL: @ashrslt_02_00_exact(
+; CHECK-NEXT:    [[C:%.*]] = icmp slt i4 %x, 0
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %s = ashr exact i4 %x, 2
+  %c = icmp slt i4 %s, 0
+  ret i1 %c
+}
+
+define i1 @ashrslt_02_01_exact(i4 %x) {
+; CHECK-LABEL: @ashrslt_02_01_exact(
+; CHECK-NEXT:    [[C:%.*]] = icmp slt i4 %x, 4
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %s = ashr exact i4 %x, 2
+  %c = icmp slt i4 %s, 1
+  ret i1 %c
+}
+
+define i1 @ashrslt_02_02_exact(i4 %x) {
+; CHECK-LABEL: @ashrslt_02_02_exact(
+; CHECK-NEXT:    ret i1 true
+;
+  %s = ashr exact i4 %x, 2
+  %c = icmp slt i4 %s, 2
+  ret i1 %c
+}
+
+define i1 @ashrslt_02_03_exact(i4 %x) {
+; CHECK-LABEL: @ashrslt_02_03_exact(
+; CHECK-NEXT:    ret i1 true
+;
+  %s = ashr exact i4 %x, 2
+  %c = icmp slt i4 %s, 3
+  ret i1 %c
+}
+
+define i1 @ashrslt_02_04_exact(i4 %x) {
+; CHECK-LABEL: @ashrslt_02_04_exact(
+; CHECK-NEXT:    ret i1 true
+;
+  %s = ashr exact i4 %x, 2
+  %c = icmp slt i4 %s, 4
+  ret i1 %c
+}
+
+define i1 @ashrslt_02_05_exact(i4 %x) {
+; CHECK-LABEL: @ashrslt_02_05_exact(
+; CHECK-NEXT:    ret i1 true
+;
+  %s = ashr exact i4 %x, 2
+  %c = icmp slt i4 %s, 5
+  ret i1 %c
+}
+
+define i1 @ashrslt_02_06_exact(i4 %x) {
+; CHECK-LABEL: @ashrslt_02_06_exact(
+; CHECK-NEXT:    ret i1 true
+;
+  %s = ashr exact i4 %x, 2
+  %c = icmp slt i4 %s, 6
+  ret i1 %c
+}
+
+define i1 @ashrslt_02_07_exact(i4 %x) {
+; CHECK-LABEL: @ashrslt_02_07_exact(
+; CHECK-NEXT:    ret i1 true
+;
+  %s = ashr exact i4 %x, 2
+  %c = icmp slt i4 %s, 7
+  ret i1 %c
+}
+
+define i1 @ashrslt_02_08_exact(i4 %x) {
+; CHECK-LABEL: @ashrslt_02_08_exact(
+; CHECK-NEXT:    ret i1 false
+;
+  %s = ashr exact i4 %x, 2
+  %c = icmp slt i4 %s, 8
+  ret i1 %c
+}
+
+define i1 @ashrslt_02_09_exact(i4 %x) {
+; CHECK-LABEL: @ashrslt_02_09_exact(
+; CHECK-NEXT:    ret i1 false
+;
+  %s = ashr exact i4 %x, 2
+  %c = icmp slt i4 %s, 9
+  ret i1 %c
+}
+
+define i1 @ashrslt_02_10_exact(i4 %x) {
+; CHECK-LABEL: @ashrslt_02_10_exact(
+; CHECK-NEXT:    ret i1 false
+;
+  %s = ashr exact i4 %x, 2
+  %c = icmp slt i4 %s, 10
+  ret i1 %c
+}
+
+define i1 @ashrslt_02_11_exact(i4 %x) {
+; CHECK-LABEL: @ashrslt_02_11_exact(
+; CHECK-NEXT:    ret i1 false
+;
+  %s = ashr exact i4 %x, 2
+  %c = icmp slt i4 %s, 11
+  ret i1 %c
+}
+
+define i1 @ashrslt_02_12_exact(i4 %x) {
+; CHECK-LABEL: @ashrslt_02_12_exact(
+; CHECK-NEXT:    ret i1 false
+;
+  %s = ashr exact i4 %x, 2
+  %c = icmp slt i4 %s, 12
+  ret i1 %c
+}
+
+define i1 @ashrslt_02_13_exact(i4 %x) {
+; CHECK-LABEL: @ashrslt_02_13_exact(
+; CHECK-NEXT:    ret i1 false
+;
+  %s = ashr exact i4 %x, 2
+  %c = icmp slt i4 %s, 13
+  ret i1 %c
+}
+
+define i1 @ashrslt_02_14_exact(i4 %x) {
+; CHECK-LABEL: @ashrslt_02_14_exact(
+; CHECK-NEXT:    ret i1 false
+;
+  %s = ashr exact i4 %x, 2
+  %c = icmp slt i4 %s, 14
+  ret i1 %c
+}
+
+define i1 @ashrslt_02_15_exact(i4 %x) {
+; CHECK-LABEL: @ashrslt_02_15_exact(
+; CHECK-NEXT:    [[C:%.*]] = icmp slt i4 %x, -4
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %s = ashr exact i4 %x, 2
+  %c = icmp slt i4 %s, 15
+  ret i1 %c
+}
+
+define i1 @ashrslt_03_00_exact(i4 %x) {
+; CHECK-LABEL: @ashrslt_03_00_exact(
+; CHECK-NEXT:    [[C:%.*]] = icmp slt i4 %x, 0
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %s = ashr exact i4 %x, 3
+  %c = icmp slt i4 %s, 0
+  ret i1 %c
+}
+
+define i1 @ashrslt_03_01_exact(i4 %x) {
+; CHECK-LABEL: @ashrslt_03_01_exact(
+; CHECK-NEXT:    ret i1 true
+;
+  %s = ashr exact i4 %x, 3
+  %c = icmp slt i4 %s, 1
+  ret i1 %c
+}
+
+define i1 @ashrslt_03_02_exact(i4 %x) {
+; CHECK-LABEL: @ashrslt_03_02_exact(
+; CHECK-NEXT:    ret i1 true
+;
+  %s = ashr exact i4 %x, 3
+  %c = icmp slt i4 %s, 2
+  ret i1 %c
+}
+
+define i1 @ashrslt_03_03_exact(i4 %x) {
+; CHECK-LABEL: @ashrslt_03_03_exact(
+; CHECK-NEXT:    ret i1 true
+;
+  %s = ashr exact i4 %x, 3
+  %c = icmp slt i4 %s, 3
+  ret i1 %c
+}
+
+define i1 @ashrslt_03_04_exact(i4 %x) {
+; CHECK-LABEL: @ashrslt_03_04_exact(
+; CHECK-NEXT:    ret i1 true
+;
+  %s = ashr exact i4 %x, 3
+  %c = icmp slt i4 %s, 4
+  ret i1 %c
+}
+
+define i1 @ashrslt_03_05_exact(i4 %x) {
+; CHECK-LABEL: @ashrslt_03_05_exact(
+; CHECK-NEXT:    ret i1 true
+;
+  %s = ashr exact i4 %x, 3
+  %c = icmp slt i4 %s, 5
+  ret i1 %c
+}
+
+define i1 @ashrslt_03_06_exact(i4 %x) {
+; CHECK-LABEL: @ashrslt_03_06_exact(
+; CHECK-NEXT:    ret i1 true
+;
+  %s = ashr exact i4 %x, 3
+  %c = icmp slt i4 %s, 6
+  ret i1 %c
+}
+
+define i1 @ashrslt_03_07_exact(i4 %x) {
+; CHECK-LABEL: @ashrslt_03_07_exact(
+; CHECK-NEXT:    ret i1 true
+;
+  %s = ashr exact i4 %x, 3
+  %c = icmp slt i4 %s, 7
+  ret i1 %c
+}
+
+define i1 @ashrslt_03_08_exact(i4 %x) {
+; CHECK-LABEL: @ashrslt_03_08_exact(
+; CHECK-NEXT:    ret i1 false
+;
+  %s = ashr exact i4 %x, 3
+  %c = icmp slt i4 %s, 8
+  ret i1 %c
+}
+
+define i1 @ashrslt_03_09_exact(i4 %x) {
+; CHECK-LABEL: @ashrslt_03_09_exact(
+; CHECK-NEXT:    ret i1 false
+;
+  %s = ashr exact i4 %x, 3
+  %c = icmp slt i4 %s, 9
+  ret i1 %c
+}
+
+define i1 @ashrslt_03_10_exact(i4 %x) {
+; CHECK-LABEL: @ashrslt_03_10_exact(
+; CHECK-NEXT:    ret i1 false
+;
+  %s = ashr exact i4 %x, 3
+  %c = icmp slt i4 %s, 10
+  ret i1 %c
+}
+
+define i1 @ashrslt_03_11_exact(i4 %x) {
+; CHECK-LABEL: @ashrslt_03_11_exact(
+; CHECK-NEXT:    ret i1 false
+;
+  %s = ashr exact i4 %x, 3
+  %c = icmp slt i4 %s, 11
+  ret i1 %c
+}
+
+define i1 @ashrslt_03_12_exact(i4 %x) {
+; CHECK-LABEL: @ashrslt_03_12_exact(
+; CHECK-NEXT:    ret i1 false
+;
+  %s = ashr exact i4 %x, 3
+  %c = icmp slt i4 %s, 12
+  ret i1 %c
+}
+
+define i1 @ashrslt_03_13_exact(i4 %x) {
+; CHECK-LABEL: @ashrslt_03_13_exact(
+; CHECK-NEXT:    ret i1 false
+;
+  %s = ashr exact i4 %x, 3
+  %c = icmp slt i4 %s, 13
+  ret i1 %c
+}
+
+define i1 @ashrslt_03_14_exact(i4 %x) {
+; CHECK-LABEL: @ashrslt_03_14_exact(
+; CHECK-NEXT:    ret i1 false
+;
+  %s = ashr exact i4 %x, 3
+  %c = icmp slt i4 %s, 14
+  ret i1 %c
+}
+
+define i1 @ashrslt_03_15_exact(i4 %x) {
+; CHECK-LABEL: @ashrslt_03_15_exact(
+; CHECK-NEXT:    ret i1 false
+;
+  %s = ashr exact i4 %x, 3
+  %c = icmp slt i4 %s, 15
+  ret i1 %c
+}
+

Added: llvm/trunk/test/Transforms/InstCombine/icmp-shr.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/icmp-shr.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/icmp-shr.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/icmp-shr.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,509 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt < %s -instcombine -S | FileCheck %s
+
+target datalayout = "e-p:64:64:64-p1:16:16:16-p2:32:32:32-p3: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"
+
+define i1 @lshr_eq_msb_low_last_zero(i8 %a) {
+; CHECK-LABEL: @lshr_eq_msb_low_last_zero(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ugt i8 %a, 6
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %shr = lshr i8 127, %a
+  %cmp = icmp eq i8 %shr, 0
+  ret i1 %cmp
+}
+
+define <2 x i1> @lshr_eq_msb_low_last_zero_vec(<2 x i8> %a) {
+; CHECK-LABEL: @lshr_eq_msb_low_last_zero_vec(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ugt <2 x i8> %a, <i8 6, i8 6>
+; CHECK-NEXT:    ret <2 x i1> [[CMP]]
+;
+  %shr = lshr <2 x i8> <i8 127, i8 127>, %a
+  %cmp = icmp eq <2 x i8> %shr, zeroinitializer
+  ret <2 x i1> %cmp
+}
+
+define i1 @ashr_eq_msb_low_second_zero(i8 %a) {
+; CHECK-LABEL: @ashr_eq_msb_low_second_zero(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ugt i8 %a, 6
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %shr = ashr i8 127, %a
+  %cmp = icmp eq i8 %shr, 0
+  ret i1 %cmp
+}
+
+define i1 @lshr_ne_msb_low_last_zero(i8 %a) {
+; CHECK-LABEL: @lshr_ne_msb_low_last_zero(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i8 %a, 7
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %shr = lshr i8 127, %a
+  %cmp = icmp ne i8 %shr, 0
+  ret i1 %cmp
+}
+
+define i1 @ashr_ne_msb_low_second_zero(i8 %a) {
+; CHECK-LABEL: @ashr_ne_msb_low_second_zero(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i8 %a, 7
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %shr = ashr i8 127, %a
+  %cmp = icmp ne i8 %shr, 0
+  ret i1 %cmp
+}
+
+define i1 @ashr_eq_both_equal(i8 %a) {
+; CHECK-LABEL: @ashr_eq_both_equal(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i8 %a, 0
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %shr = ashr i8 128, %a
+  %cmp = icmp eq i8 %shr, 128
+  ret i1 %cmp
+}
+
+define i1 @ashr_ne_both_equal(i8 %a) {
+; CHECK-LABEL: @ashr_ne_both_equal(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ne i8 %a, 0
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %shr = ashr i8 128, %a
+  %cmp = icmp ne i8 %shr, 128
+  ret i1 %cmp
+}
+
+define i1 @lshr_eq_both_equal(i8 %a) {
+; CHECK-LABEL: @lshr_eq_both_equal(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i8 %a, 0
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %shr = lshr i8 127, %a
+  %cmp = icmp eq i8 %shr, 127
+  ret i1 %cmp
+}
+
+define i1 @lshr_ne_both_equal(i8 %a) {
+; CHECK-LABEL: @lshr_ne_both_equal(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ne i8 %a, 0
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %shr = lshr i8 127, %a
+  %cmp = icmp ne i8 %shr, 127
+  ret i1 %cmp
+}
+
+define i1 @exact_ashr_eq_both_equal(i8 %a) {
+; CHECK-LABEL: @exact_ashr_eq_both_equal(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i8 %a, 0
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %shr = ashr exact i8 128, %a
+  %cmp = icmp eq i8 %shr, 128
+  ret i1 %cmp
+}
+
+define i1 @exact_ashr_ne_both_equal(i8 %a) {
+; CHECK-LABEL: @exact_ashr_ne_both_equal(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ne i8 %a, 0
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %shr = ashr exact i8 128, %a
+  %cmp = icmp ne i8 %shr, 128
+  ret i1 %cmp
+}
+
+define i1 @exact_lshr_eq_both_equal(i8 %a) {
+; CHECK-LABEL: @exact_lshr_eq_both_equal(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i8 %a, 0
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %shr = lshr exact i8 126, %a
+  %cmp = icmp eq i8 %shr, 126
+  ret i1 %cmp
+}
+
+define i1 @exact_lshr_ne_both_equal(i8 %a) {
+; CHECK-LABEL: @exact_lshr_ne_both_equal(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ne i8 %a, 0
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %shr = lshr exact i8 126, %a
+  %cmp = icmp ne i8 %shr, 126
+  ret i1 %cmp
+}
+
+define i1 @exact_lshr_eq_opposite_msb(i8 %a) {
+; CHECK-LABEL: @exact_lshr_eq_opposite_msb(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i8 %a, 7
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %shr = lshr exact i8 -128, %a
+  %cmp = icmp eq i8 %shr, 1
+  ret i1 %cmp
+}
+
+define i1 @lshr_eq_opposite_msb(i8 %a) {
+; CHECK-LABEL: @lshr_eq_opposite_msb(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i8 %a, 7
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %shr = lshr i8 -128, %a
+  %cmp = icmp eq i8 %shr, 1
+  ret i1 %cmp
+}
+
+define i1 @exact_lshr_ne_opposite_msb(i8 %a) {
+; CHECK-LABEL: @exact_lshr_ne_opposite_msb(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ne i8 %a, 7
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %shr = lshr exact i8 -128, %a
+  %cmp = icmp ne i8 %shr, 1
+  ret i1 %cmp
+}
+
+define i1 @lshr_ne_opposite_msb(i8 %a) {
+; CHECK-LABEL: @lshr_ne_opposite_msb(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ne i8 %a, 7
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %shr = lshr i8 -128, %a
+  %cmp = icmp ne i8 %shr, 1
+  ret i1 %cmp
+}
+
+define i1 @exact_ashr_eq(i8 %a) {
+; CHECK-LABEL: @exact_ashr_eq(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i8 %a, 7
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %shr = ashr exact i8 -128, %a
+  %cmp = icmp eq i8 %shr, -1
+  ret i1 %cmp
+}
+
+define i1 @exact_ashr_ne(i8 %a) {
+; CHECK-LABEL: @exact_ashr_ne(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ne i8 %a, 7
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %shr = ashr exact i8 -128, %a
+  %cmp = icmp ne i8 %shr, -1
+  ret i1 %cmp
+}
+
+define i1 @exact_lshr_eq(i8 %a) {
+; CHECK-LABEL: @exact_lshr_eq(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i8 %a, 2
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %shr = lshr exact i8 4, %a
+  %cmp = icmp eq i8 %shr, 1
+  ret i1 %cmp
+}
+
+define i1 @exact_lshr_ne(i8 %a) {
+; CHECK-LABEL: @exact_lshr_ne(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ne i8 %a, 2
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %shr = lshr exact i8 4, %a
+  %cmp = icmp ne i8 %shr, 1
+  ret i1 %cmp
+}
+
+define i1 @nonexact_ashr_eq(i8 %a) {
+; CHECK-LABEL: @nonexact_ashr_eq(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i8 %a, 7
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %shr = ashr i8 -128, %a
+  %cmp = icmp eq i8 %shr, -1
+  ret i1 %cmp
+}
+
+define i1 @nonexact_ashr_ne(i8 %a) {
+; CHECK-LABEL: @nonexact_ashr_ne(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ne i8 %a, 7
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %shr = ashr i8 -128, %a
+  %cmp = icmp ne i8 %shr, -1
+  ret i1 %cmp
+}
+
+define i1 @nonexact_lshr_eq(i8 %a) {
+; CHECK-LABEL: @nonexact_lshr_eq(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i8 %a, 2
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %shr = lshr i8 4, %a
+  %cmp = icmp eq i8 %shr, 1
+  ret i1 %cmp
+}
+
+define i1 @nonexact_lshr_ne(i8 %a) {
+; CHECK-LABEL: @nonexact_lshr_ne(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ne i8 %a, 2
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %shr = lshr i8 4, %a
+  %cmp = icmp ne i8 %shr, 1
+  ret i1 %cmp
+}
+
+define i1 @exact_lshr_eq_exactdiv(i8 %a) {
+; CHECK-LABEL: @exact_lshr_eq_exactdiv(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i8 %a, 4
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %shr = lshr exact i8 80, %a
+  %cmp = icmp eq i8 %shr, 5
+  ret i1 %cmp
+}
+
+define i1 @exact_lshr_ne_exactdiv(i8 %a) {
+; CHECK-LABEL: @exact_lshr_ne_exactdiv(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ne i8 %a, 4
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %shr = lshr exact i8 80, %a
+  %cmp = icmp ne i8 %shr, 5
+  ret i1 %cmp
+}
+
+define i1 @nonexact_lshr_eq_exactdiv(i8 %a) {
+; CHECK-LABEL: @nonexact_lshr_eq_exactdiv(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i8 %a, 4
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %shr = lshr i8 80, %a
+  %cmp = icmp eq i8 %shr, 5
+  ret i1 %cmp
+}
+
+define i1 @nonexact_lshr_ne_exactdiv(i8 %a) {
+; CHECK-LABEL: @nonexact_lshr_ne_exactdiv(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ne i8 %a, 4
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %shr = lshr i8 80, %a
+  %cmp = icmp ne i8 %shr, 5
+  ret i1 %cmp
+}
+
+define i1 @exact_ashr_eq_exactdiv(i8 %a) {
+; CHECK-LABEL: @exact_ashr_eq_exactdiv(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i8 %a, 4
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %shr = ashr exact i8 -80, %a
+  %cmp = icmp eq i8 %shr, -5
+  ret i1 %cmp
+}
+
+define i1 @exact_ashr_ne_exactdiv(i8 %a) {
+; CHECK-LABEL: @exact_ashr_ne_exactdiv(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ne i8 %a, 4
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %shr = ashr exact i8 -80, %a
+  %cmp = icmp ne i8 %shr, -5
+  ret i1 %cmp
+}
+
+define i1 @nonexact_ashr_eq_exactdiv(i8 %a) {
+; CHECK-LABEL: @nonexact_ashr_eq_exactdiv(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i8 %a, 4
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %shr = ashr i8 -80, %a
+  %cmp = icmp eq i8 %shr, -5
+  ret i1 %cmp
+}
+
+define i1 @nonexact_ashr_ne_exactdiv(i8 %a) {
+; CHECK-LABEL: @nonexact_ashr_ne_exactdiv(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ne i8 %a, 4
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %shr = ashr i8 -80, %a
+  %cmp = icmp ne i8 %shr, -5
+  ret i1 %cmp
+}
+
+define i1 @exact_lshr_eq_noexactdiv(i8 %a) {
+; CHECK-LABEL: @exact_lshr_eq_noexactdiv(
+; CHECK-NEXT:    ret i1 false
+;
+  %shr = lshr exact i8 80, %a
+  %cmp = icmp eq i8 %shr, 31
+  ret i1 %cmp
+}
+
+define i1 @exact_lshr_ne_noexactdiv(i8 %a) {
+; CHECK-LABEL: @exact_lshr_ne_noexactdiv(
+; CHECK-NEXT:    ret i1 true
+;
+  %shr = lshr exact i8 80, %a
+  %cmp = icmp ne i8 %shr, 31
+  ret i1 %cmp
+}
+
+define i1 @nonexact_lshr_eq_noexactdiv(i8 %a) {
+; CHECK-LABEL: @nonexact_lshr_eq_noexactdiv(
+; CHECK-NEXT:    ret i1 false
+;
+  %shr = lshr i8 80, %a
+  %cmp = icmp eq i8 %shr, 31
+  ret i1 %cmp
+}
+
+define i1 @nonexact_lshr_ne_noexactdiv(i8 %a) {
+; CHECK-LABEL: @nonexact_lshr_ne_noexactdiv(
+; CHECK-NEXT:    ret i1 true
+;
+  %shr = lshr i8 80, %a
+  %cmp = icmp ne i8 %shr, 31
+  ret i1 %cmp
+}
+
+define i1 @exact_ashr_eq_noexactdiv(i8 %a) {
+; CHECK-LABEL: @exact_ashr_eq_noexactdiv(
+; CHECK-NEXT:    ret i1 false
+;
+  %shr = ashr exact i8 -80, %a
+  %cmp = icmp eq i8 %shr, -31
+  ret i1 %cmp
+}
+
+define i1 @exact_ashr_ne_noexactdiv(i8 %a) {
+; CHECK-LABEL: @exact_ashr_ne_noexactdiv(
+; CHECK-NEXT:    ret i1 true
+;
+  %shr = ashr exact i8 -80, %a
+  %cmp = icmp ne i8 %shr, -31
+  ret i1 %cmp
+}
+
+define i1 @nonexact_ashr_eq_noexactdiv(i8 %a) {
+; CHECK-LABEL: @nonexact_ashr_eq_noexactdiv(
+; CHECK-NEXT:    ret i1 false
+;
+  %shr = ashr i8 -80, %a
+  %cmp = icmp eq i8 %shr, -31
+  ret i1 %cmp
+}
+
+define i1 @nonexact_ashr_ne_noexactdiv(i8 %a) {
+; CHECK-LABEL: @nonexact_ashr_ne_noexactdiv(
+; CHECK-NEXT:    ret i1 true
+;
+  %shr = ashr i8 -80, %a
+  %cmp = icmp ne i8 %shr, -31
+  ret i1 %cmp
+}
+
+define i1 @nonexact_lshr_eq_noexactlog(i8 %a) {
+; CHECK-LABEL: @nonexact_lshr_eq_noexactlog(
+; CHECK-NEXT:    ret i1 false
+;
+  %shr = lshr i8 90, %a
+  %cmp = icmp eq i8 %shr, 30
+  ret i1 %cmp
+}
+
+define i1 @nonexact_lshr_ne_noexactlog(i8 %a) {
+; CHECK-LABEL: @nonexact_lshr_ne_noexactlog(
+; CHECK-NEXT:    ret i1 true
+;
+  %shr = lshr i8 90, %a
+  %cmp = icmp ne i8 %shr, 30
+  ret i1 %cmp
+}
+
+define i1 @nonexact_ashr_eq_noexactlog(i8 %a) {
+; CHECK-LABEL: @nonexact_ashr_eq_noexactlog(
+; CHECK-NEXT:    ret i1 false
+;
+  %shr = ashr i8 -90, %a
+  %cmp = icmp eq i8 %shr, -30
+  ret i1 %cmp
+}
+
+define i1 @nonexact_ashr_ne_noexactlog(i8 %a) {
+; CHECK-LABEL: @nonexact_ashr_ne_noexactlog(
+; CHECK-NEXT:    ret i1 true
+;
+  %shr = ashr i8 -90, %a
+  %cmp = icmp ne i8 %shr, -30
+  ret i1 %cmp
+}
+
+; Don't try to fold the entire body of function @PR20945 into a
+; single `ret i1 true` statement.
+; If %B is equal to 1, then this function would return false.
+; As a consequence, the instruction combiner is not allowed to fold %cmp
+; to 'true'. Instead, it should replace %cmp with a simpler comparison
+; between %B and 1.
+
+define i1 @PR20945(i32 %B) {
+; CHECK-LABEL: @PR20945(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ne i32 %B, 1
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %shr = ashr i32 -9, %B
+  %cmp = icmp ne i32 %shr, -5
+  ret i1 %cmp
+}
+
+define i1 @PR21222(i32 %B) {
+; CHECK-LABEL: @PR21222(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 %B, 6
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %shr = ashr i32 -93, %B
+  %cmp = icmp eq i32 %shr, -2
+  ret i1 %cmp
+}
+
+define i1 @PR24873(i64 %V) {
+; CHECK-LABEL: @PR24873(
+; CHECK-NEXT:    [[ICMP:%.*]] = icmp ugt i64 %V, 61
+; CHECK-NEXT:    ret i1 [[ICMP]]
+;
+  %ashr = ashr i64 -4611686018427387904, %V
+  %icmp = icmp eq i64 %ashr, -1
+  ret i1 %icmp
+}
+
+declare void @foo(i32)
+
+define i1 @exact_multiuse(i32 %x) {
+; CHECK-LABEL: @exact_multiuse(
+; CHECK-NEXT:    [[SH:%.*]] = lshr exact i32 %x, 7
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 %x, 131072
+; CHECK-NEXT:    call void @foo(i32 [[SH]])
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %sh = lshr exact i32 %x, 7
+  %cmp = icmp eq i32 %sh, 1024
+  call void @foo(i32 %sh)
+  ret i1 %cmp
+}
+
+declare void @foo2(<2 x i32>)
+define <2 x i1> @exact_eq0_multiuse(<2 x i32> %x, <2 x i32> %y) {
+; CHECK-LABEL: @exact_eq0_multiuse(
+; CHECK-NEXT:    [[SH:%.*]] = ashr exact <2 x i32> %x, %y
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq <2 x i32> [[SH]], zeroinitializer
+; CHECK-NEXT:    call void @foo2(<2 x i32> [[SH]])
+; CHECK-NEXT:    ret <2 x i1> [[CMP]]
+;
+  %sh = ashr exact <2 x i32> %x, %y
+  %cmp = icmp eq <2 x i32> %sh, zeroinitializer
+  call void @foo2(<2 x i32> %sh)
+  ret <2 x i1> %cmp
+}
+

Added: llvm/trunk/test/Transforms/InstCombine/icmp-sub.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/icmp-sub.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/icmp-sub.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/icmp-sub.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,86 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt < %s -instcombine -S | FileCheck %s
+
+define i1 @test_nuw_and_unsigned_pred(i64 %x) {
+; CHECK-LABEL: @test_nuw_and_unsigned_pred(
+; CHECK-NEXT:    [[Z:%.*]] = icmp ugt i64 [[X:%.*]], 7
+; CHECK-NEXT:    ret i1 [[Z]]
+;
+  %y = sub nuw i64 10, %x
+  %z = icmp ult i64 %y, 3
+  ret i1 %z
+}
+
+define i1 @test_nsw_and_signed_pred(i64 %x) {
+; CHECK-LABEL: @test_nsw_and_signed_pred(
+; CHECK-NEXT:    [[Z:%.*]] = icmp slt i64 [[X:%.*]], -7
+; CHECK-NEXT:    ret i1 [[Z]]
+;
+  %y = sub nsw i64 3, %x
+  %z = icmp sgt i64 %y, 10
+  ret i1 %z
+}
+
+define i1 @test_nuw_nsw_and_unsigned_pred(i64 %x) {
+; CHECK-LABEL: @test_nuw_nsw_and_unsigned_pred(
+; CHECK-NEXT:    [[Z:%.*]] = icmp ugt i64 [[X:%.*]], 6
+; CHECK-NEXT:    ret i1 [[Z]]
+;
+  %y = sub nuw nsw i64 10, %x
+  %z = icmp ule i64 %y, 3
+  ret i1 %z
+}
+
+define i1 @test_nuw_nsw_and_signed_pred(i64 %x) {
+; CHECK-LABEL: @test_nuw_nsw_and_signed_pred(
+; CHECK-NEXT:    [[Z:%.*]] = icmp sgt i64 [[X:%.*]], 7
+; CHECK-NEXT:    ret i1 [[Z]]
+;
+  %y = sub nuw nsw i64 10, %x
+  %z = icmp slt i64 %y, 3
+  ret i1 %z
+}
+
+define i1 @test_negative_nuw_and_signed_pred(i64 %x) {
+; CHECK-LABEL: @test_negative_nuw_and_signed_pred(
+; CHECK-NEXT:    [[Y:%.*]] = sub nuw i64 10, [[X:%.*]]
+; CHECK-NEXT:    [[Z:%.*]] = icmp slt i64 [[Y]], 3
+; CHECK-NEXT:    ret i1 [[Z]]
+;
+  %y = sub nuw i64 10, %x
+  %z = icmp slt i64 %y, 3
+  ret i1 %z
+}
+
+define i1 @test_negative_nsw_and_unsigned_pred(i64 %x) {
+; CHECK-LABEL: @test_negative_nsw_and_unsigned_pred(
+; CHECK-NEXT:    [[Y:%.*]] = sub nsw i64 10, [[X:%.*]]
+; CHECK-NEXT:    [[Z:%.*]] = icmp ult i64 [[Y]], 3
+; CHECK-NEXT:    ret i1 [[Z]]
+;
+  %y = sub nsw i64 10, %x
+  %z = icmp ult i64 %y, 3
+  ret i1 %z
+}
+
+define i1 @test_negative_combined_sub_unsigned_overflow(i64 %x) {
+; CHECK-LABEL: @test_negative_combined_sub_unsigned_overflow(
+; CHECK-NEXT:    [[Y:%.*]] = sub nuw i64 10, [[X:%.*]]
+; CHECK-NEXT:    [[Z:%.*]] = icmp ult i64 [[Y]], 11
+; CHECK-NEXT:    ret i1 [[Z]]
+;
+  %y = sub nuw i64 10, %x
+  %z = icmp ult i64 %y, 11
+  ret i1 %z
+}
+
+define i1 @test_negative_combined_sub_signed_overflow(i8 %x) {
+; CHECK-LABEL: @test_negative_combined_sub_signed_overflow(
+; CHECK-NEXT:    [[Y:%.*]] = sub nsw i8 127, [[X:%.*]]
+; CHECK-NEXT:    [[Z:%.*]] = icmp slt i8 [[Y]], -1
+; CHECK-NEXT:    ret i1 [[Z]]
+;
+  %y = sub nsw i8 127, %x
+  %z = icmp slt i8 %y, -1
+  ret i1 %z
+}

Added: llvm/trunk/test/Transforms/InstCombine/icmp-uge-of-add-of-shl-one-by-bits-to-allones-and-val-to-icmp-eq-of-lshr-val-by-bits-and-0.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/icmp-uge-of-add-of-shl-one-by-bits-to-allones-and-val-to-icmp-eq-of-lshr-val-by-bits-and-0.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/icmp-uge-of-add-of-shl-one-by-bits-to-allones-and-val-to-icmp-eq-of-lshr-val-by-bits-and-0.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/icmp-uge-of-add-of-shl-one-by-bits-to-allones-and-val-to-icmp-eq-of-lshr-val-by-bits-and-0.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,260 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt < %s -instcombine -S | FileCheck %s
+
+; https://bugs.llvm.org/show_bug.cgi?id=38708
+
+; Pattern:
+;   ((1 << bits)+(-1)) u>= val
+; Should be transformed into:
+;   (val l>> bits) == 0
+
+; NOTE: the innermost shl is not one-use. Else canonicalization happens.
+
+declare void @use8(i8)
+declare void @use2i8(<2 x i8>)
+declare void @use3i8(<3 x i8>)
+
+; ============================================================================ ;
+; Basic positive tests
+; ============================================================================ ;
+
+define i1 @p0(i8 %val, i8 %bits) {
+; CHECK-LABEL: @p0(
+; CHECK-NEXT:    [[T0:%.*]] = shl i8 1, [[BITS:%.*]]
+; CHECK-NEXT:    call void @use8(i8 [[T0]])
+; CHECK-NEXT:    [[VAL_HIGHBITS:%.*]] = lshr i8 [[VAL:%.*]], [[BITS]]
+; CHECK-NEXT:    [[R:%.*]] = icmp eq i8 [[VAL_HIGHBITS]], 0
+; CHECK-NEXT:    ret i1 [[R]]
+;
+  %t0 = shl i8 1, %bits
+  call void @use8(i8 %t0)
+  %t1 = add i8 %t0, -1
+  %r = icmp uge i8 %t1, %val
+  ret i1 %r
+}
+
+; ============================================================================ ;
+; Vector tests
+; ============================================================================ ;
+
+define <2 x i1> @p1_vec(<2 x i8> %val, <2 x i8> %bits) {
+; CHECK-LABEL: @p1_vec(
+; CHECK-NEXT:    [[T0:%.*]] = shl <2 x i8> <i8 1, i8 1>, [[BITS:%.*]]
+; CHECK-NEXT:    call void @use2i8(<2 x i8> [[T0]])
+; CHECK-NEXT:    [[VAL_HIGHBITS:%.*]] = lshr <2 x i8> [[VAL:%.*]], [[BITS]]
+; CHECK-NEXT:    [[R:%.*]] = icmp eq <2 x i8> [[VAL_HIGHBITS]], zeroinitializer
+; CHECK-NEXT:    ret <2 x i1> [[R]]
+;
+  %t0 = shl <2 x i8> <i8 1, i8 1>, %bits
+  call void @use2i8(<2 x i8> %t0)
+  %t1 = add <2 x i8> %t0, <i8 -1, i8 -1>
+  %r = icmp uge <2 x i8> %t1, %val
+  ret <2 x i1> %r
+}
+
+define <3 x i1> @p2_vec_undef0(<3 x i8> %val, <3 x i8> %bits) {
+; CHECK-LABEL: @p2_vec_undef0(
+; CHECK-NEXT:    [[T0:%.*]] = shl <3 x i8> <i8 1, i8 undef, i8 1>, [[BITS:%.*]]
+; CHECK-NEXT:    call void @use3i8(<3 x i8> [[T0]])
+; CHECK-NEXT:    [[VAL_HIGHBITS:%.*]] = lshr <3 x i8> [[VAL:%.*]], [[BITS]]
+; CHECK-NEXT:    [[R:%.*]] = icmp eq <3 x i8> [[VAL_HIGHBITS]], zeroinitializer
+; CHECK-NEXT:    ret <3 x i1> [[R]]
+;
+  %t0 = shl <3 x i8> <i8 1, i8 undef, i8 1>, %bits
+  call void @use3i8(<3 x i8> %t0)
+  %t1 = add <3 x i8> %t0, <i8 -1, i8 -1, i8 -1>
+  %r = icmp uge <3 x i8> %t1, %val
+  ret <3 x i1> %r
+}
+
+define <3 x i1> @p2_vec_undef1(<3 x i8> %val, <3 x i8> %bits) {
+; CHECK-LABEL: @p2_vec_undef1(
+; CHECK-NEXT:    [[T0:%.*]] = shl <3 x i8> <i8 1, i8 1, i8 1>, [[BITS:%.*]]
+; CHECK-NEXT:    call void @use3i8(<3 x i8> [[T0]])
+; CHECK-NEXT:    [[VAL_HIGHBITS:%.*]] = lshr <3 x i8> [[VAL:%.*]], [[BITS]]
+; CHECK-NEXT:    [[R:%.*]] = icmp eq <3 x i8> [[VAL_HIGHBITS]], zeroinitializer
+; CHECK-NEXT:    ret <3 x i1> [[R]]
+;
+  %t0 = shl <3 x i8> <i8 1, i8 1, i8 1>, %bits
+  call void @use3i8(<3 x i8> %t0)
+  %t1 = add <3 x i8> %t0, <i8 -1, i8 undef, i8 -1>
+  %r = icmp uge <3 x i8> %t1, %val
+  ret <3 x i1> %r
+}
+
+define <3 x i1> @p2_vec_undef2(<3 x i8> %val, <3 x i8> %bits) {
+; CHECK-LABEL: @p2_vec_undef2(
+; CHECK-NEXT:    [[T0:%.*]] = shl <3 x i8> <i8 1, i8 undef, i8 1>, [[BITS:%.*]]
+; CHECK-NEXT:    call void @use3i8(<3 x i8> [[T0]])
+; CHECK-NEXT:    [[VAL_HIGHBITS:%.*]] = lshr <3 x i8> [[VAL:%.*]], [[BITS]]
+; CHECK-NEXT:    [[R:%.*]] = icmp eq <3 x i8> [[VAL_HIGHBITS]], zeroinitializer
+; CHECK-NEXT:    ret <3 x i1> [[R]]
+;
+  %t0 = shl <3 x i8> <i8 1, i8 undef, i8 1>, %bits
+  call void @use3i8(<3 x i8> %t0)
+  %t1 = add <3 x i8> %t0, <i8 -1, i8 undef, i8 -1>
+  %r = icmp uge <3 x i8> %t1, %val
+  ret <3 x i1> %r
+}
+
+; ============================================================================ ;
+; Commutativity tests.
+; ============================================================================ ;
+
+declare i8 @gen8()
+
+define i1 @c0(i8 %bits) {
+; CHECK-LABEL: @c0(
+; CHECK-NEXT:    [[T0:%.*]] = shl i8 1, [[BITS:%.*]]
+; CHECK-NEXT:    call void @use8(i8 [[T0]])
+; CHECK-NEXT:    [[VAL:%.*]] = call i8 @gen8()
+; CHECK-NEXT:    [[VAL_HIGHBITS:%.*]] = lshr i8 [[VAL]], [[BITS]]
+; CHECK-NEXT:    [[R:%.*]] = icmp eq i8 [[VAL_HIGHBITS]], 0
+; CHECK-NEXT:    ret i1 [[R]]
+;
+  %t0 = shl i8 1, %bits
+  call void @use8(i8 %t0)
+  %t1 = add i8 %t0, -1
+  %val = call i8 @gen8()
+  %r = icmp ule i8 %val, %t1 ; swapped order and predicate
+  ret i1 %r
+}
+
+; What if we have the same pattern on both sides?
+define i1 @both(i8 %bits0, i8 %bits1) {
+; CHECK-LABEL: @both(
+; CHECK-NEXT:    [[T0:%.*]] = shl i8 1, [[BITS0:%.*]]
+; CHECK-NEXT:    call void @use8(i8 [[T0]])
+; CHECK-NEXT:    [[T2:%.*]] = shl i8 1, [[BITS1:%.*]]
+; CHECK-NEXT:    call void @use8(i8 [[T2]])
+; CHECK-NEXT:    [[T3:%.*]] = add i8 [[T2]], -1
+; CHECK-NEXT:    [[T3_HIGHBITS:%.*]] = lshr i8 [[T3]], [[BITS0]]
+; CHECK-NEXT:    [[R:%.*]] = icmp eq i8 [[T3_HIGHBITS]], 0
+; CHECK-NEXT:    ret i1 [[R]]
+;
+  %t0 = shl i8 1, %bits0
+  call void @use8(i8 %t0)
+  %t1 = add i8 %t0, -1
+  %t2 = shl i8 1, %bits1
+  call void @use8(i8 %t2)
+  %t3 = add i8 %t2, -1
+  %r = icmp uge i8 %t1, %t3
+  ret i1 %r
+}
+
+; ============================================================================ ;
+; One-use tests.
+; ============================================================================ ;
+
+define i1 @oneuse(i8 %val, i8 %bits) {
+; CHECK-LABEL: @oneuse(
+; CHECK-NEXT:    [[T0:%.*]] = shl i8 1, [[BITS:%.*]]
+; CHECK-NEXT:    call void @use8(i8 [[T0]])
+; CHECK-NEXT:    [[T1:%.*]] = add i8 [[T0]], -1
+; CHECK-NEXT:    call void @use8(i8 [[T1]])
+; CHECK-NEXT:    [[R:%.*]] = icmp uge i8 [[T1]], [[VAL:%.*]]
+; CHECK-NEXT:    ret i1 [[R]]
+;
+  %t0 = shl i8 1, %bits
+  call void @use8(i8 %t0) ; this is needed anyway
+  %t1 = add i8 %t0, -1
+  call void @use8(i8 %t1)
+  %r = icmp uge i8 %t1, %val
+  ret i1 %r
+}
+
+; ============================================================================ ;
+; Negative tests
+; ============================================================================ ;
+
+define i1 @n0(i8 %val, i8 %bits) {
+; CHECK-LABEL: @n0(
+; CHECK-NEXT:    [[T0:%.*]] = shl i8 -1, [[BITS:%.*]]
+; CHECK-NEXT:    call void @use8(i8 [[T0]])
+; CHECK-NEXT:    [[T1:%.*]] = add i8 [[T0]], -1
+; CHECK-NEXT:    [[R:%.*]] = icmp uge i8 [[T1]], [[VAL:%.*]]
+; CHECK-NEXT:    ret i1 [[R]]
+;
+  %t0 = shl i8 -1, %bits ; constant is not 1
+  call void @use8(i8 %t0)
+  %t1 = add i8 %t0, -1
+  %r = icmp uge i8 %t1, %val
+  ret i1 %r
+}
+
+define i1 @n1(i8 %val, i8 %bits) {
+; CHECK-LABEL: @n1(
+; CHECK-NEXT:    [[T0:%.*]] = shl i8 1, [[BITS:%.*]]
+; CHECK-NEXT:    call void @use8(i8 [[T0]])
+; CHECK-NEXT:    [[T1:%.*]] = add i8 [[T0]], 1
+; CHECK-NEXT:    [[R:%.*]] = icmp uge i8 [[T1]], [[VAL:%.*]]
+; CHECK-NEXT:    ret i1 [[R]]
+;
+  %t0 = shl i8 1, %bits
+  call void @use8(i8 %t0)
+  %t1 = add i8 %t0, 1 ; constant is not -1
+  %r = icmp uge i8 %t1, %val
+  ret i1 %r
+}
+
+define <2 x i1> @n2_vec_nonsplat(<2 x i8> %val, <2 x i8> %bits) {
+; CHECK-LABEL: @n2_vec_nonsplat(
+; CHECK-NEXT:    [[T0:%.*]] = shl <2 x i8> <i8 1, i8 -1>, [[BITS:%.*]]
+; CHECK-NEXT:    call void @use2i8(<2 x i8> [[T0]])
+; CHECK-NEXT:    [[T1:%.*]] = add <2 x i8> [[T0]], <i8 -1, i8 -1>
+; CHECK-NEXT:    [[R:%.*]] = icmp uge <2 x i8> [[T1]], [[VAL:%.*]]
+; CHECK-NEXT:    ret <2 x i1> [[R]]
+;
+  %t0 = shl <2 x i8> <i8 1, i8 -1>, %bits ; again, wrong constant
+  call void @use2i8(<2 x i8> %t0)
+  %t1 = add <2 x i8> %t0, <i8 -1, i8 -1>
+  %r = icmp uge <2 x i8> %t1, %val
+  ret <2 x i1> %r
+}
+
+define <2 x i1> @n3_vec_nonsplat(<2 x i8> %val, <2 x i8> %bits) {
+; CHECK-LABEL: @n3_vec_nonsplat(
+; CHECK-NEXT:    [[T0:%.*]] = shl <2 x i8> <i8 1, i8 1>, [[BITS:%.*]]
+; CHECK-NEXT:    call void @use2i8(<2 x i8> [[T0]])
+; CHECK-NEXT:    [[T1:%.*]] = add <2 x i8> [[T0]], <i8 -1, i8 1>
+; CHECK-NEXT:    [[R:%.*]] = icmp uge <2 x i8> [[T1]], [[VAL:%.*]]
+; CHECK-NEXT:    ret <2 x i1> [[R]]
+;
+  %t0 = shl <2 x i8> <i8 1, i8 1>, %bits
+  call void @use2i8(<2 x i8> %t0)
+  %t1 = add <2 x i8> %t0, <i8 -1, i8 1> ; again, wrong constant
+  %r = icmp uge <2 x i8> %t1, %val
+  ret <2 x i1> %r
+}
+
+define i1 @n3(i8 %val, i8 %bits) {
+; CHECK-LABEL: @n3(
+; CHECK-NEXT:    [[T0:%.*]] = shl i8 1, [[BITS:%.*]]
+; CHECK-NEXT:    call void @use8(i8 [[T0]])
+; CHECK-NEXT:    [[T1:%.*]] = add i8 [[T0]], -1
+; CHECK-NEXT:    [[R:%.*]] = icmp ugt i8 [[T1]], [[VAL:%.*]]
+; CHECK-NEXT:    ret i1 [[R]]
+;
+  %t0 = shl i8 1, %bits
+  call void @use8(i8 %t0)
+  %t1 = add i8 %t0, -1
+  %r = icmp ugt i8 %t1, %val ; wrong predicate
+  ret i1 %r
+}
+
+define i1 @n4(i8 %bits) {
+; CHECK-LABEL: @n4(
+; CHECK-NEXT:    [[T0:%.*]] = shl i8 1, [[BITS:%.*]]
+; CHECK-NEXT:    call void @use8(i8 [[T0]])
+; CHECK-NEXT:    [[T1:%.*]] = add i8 [[T0]], -1
+; CHECK-NEXT:    [[VAL:%.*]] = call i8 @gen8()
+; CHECK-NEXT:    [[R:%.*]] = icmp ult i8 [[VAL]], [[T1]]
+; CHECK-NEXT:    ret i1 [[R]]
+;
+  %t0 = shl i8 1, %bits
+  call void @use8(i8 %t0)
+  %t1 = add i8 %t0, -1
+  %val = call i8 @gen8()
+  %r = icmp ult i8 %val, %t1 ; swapped order and [wrong] predicate
+  ret i1 %r
+}

Added: llvm/trunk/test/Transforms/InstCombine/icmp-uge-of-not-of-shl-allones-by-bits-and-val-to-icmp-eq-of-lshr-val-by-bits-and-0.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/icmp-uge-of-not-of-shl-allones-by-bits-and-val-to-icmp-eq-of-lshr-val-by-bits-and-0.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/icmp-uge-of-not-of-shl-allones-by-bits-and-val-to-icmp-eq-of-lshr-val-by-bits-and-0.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/icmp-uge-of-not-of-shl-allones-by-bits-and-val-to-icmp-eq-of-lshr-val-by-bits-and-0.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,250 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt < %s -instcombine -S | FileCheck %s
+
+; https://bugs.llvm.org/show_bug.cgi?id=38708
+
+; Pattern:
+;   ~(-1 << bits) u>= val
+; Should be transformed into:
+;   (val l>> bits) == 0
+
+; ============================================================================ ;
+; Basic positive tests
+; ============================================================================ ;
+
+define i1 @p0(i8 %val, i8 %bits) {
+; CHECK-LABEL: @p0(
+; CHECK-NEXT:    [[VAL_HIGHBITS:%.*]] = lshr i8 [[VAL:%.*]], [[BITS:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = icmp eq i8 [[VAL_HIGHBITS]], 0
+; CHECK-NEXT:    ret i1 [[R]]
+;
+  %t0 = shl i8 -1, %bits
+  %t1 = xor i8 %t0, -1
+  %r = icmp uge i8 %t1, %val
+  ret i1 %r
+}
+
+; ============================================================================ ;
+; Vector tests
+; ============================================================================ ;
+
+define <2 x i1> @p1_vec(<2 x i8> %val, <2 x i8> %bits) {
+; CHECK-LABEL: @p1_vec(
+; CHECK-NEXT:    [[VAL_HIGHBITS:%.*]] = lshr <2 x i8> [[VAL:%.*]], [[BITS:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = icmp eq <2 x i8> [[VAL_HIGHBITS]], zeroinitializer
+; CHECK-NEXT:    ret <2 x i1> [[R]]
+;
+  %t0 = shl <2 x i8> <i8 -1, i8 -1>, %bits
+  %t1 = xor <2 x i8> %t0, <i8 -1, i8 -1>
+  %r = icmp uge <2 x i8> %t1, %val
+  ret <2 x i1> %r
+}
+
+define <3 x i1> @p2_vec_undef0(<3 x i8> %val, <3 x i8> %bits) {
+; CHECK-LABEL: @p2_vec_undef0(
+; CHECK-NEXT:    [[VAL_HIGHBITS:%.*]] = lshr <3 x i8> [[VAL:%.*]], [[BITS:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = icmp eq <3 x i8> [[VAL_HIGHBITS]], zeroinitializer
+; CHECK-NEXT:    ret <3 x i1> [[R]]
+;
+  %t0 = shl <3 x i8> <i8 -1, i8 undef, i8 -1>, %bits
+  %t1 = xor <3 x i8> %t0, <i8 -1, i8 -1, i8 -1>
+  %r = icmp uge <3 x i8> %t1, %val
+  ret <3 x i1> %r
+}
+
+define <3 x i1> @p2_vec_undef1(<3 x i8> %val, <3 x i8> %bits) {
+; CHECK-LABEL: @p2_vec_undef1(
+; CHECK-NEXT:    [[VAL_HIGHBITS:%.*]] = lshr <3 x i8> [[VAL:%.*]], [[BITS:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = icmp eq <3 x i8> [[VAL_HIGHBITS]], zeroinitializer
+; CHECK-NEXT:    ret <3 x i1> [[R]]
+;
+  %t0 = shl <3 x i8> <i8 -1, i8 -1, i8 -1>, %bits
+  %t1 = xor <3 x i8> %t0, <i8 -1, i8 undef, i8 -1>
+  %r = icmp uge <3 x i8> %t1, %val
+  ret <3 x i1> %r
+}
+
+define <3 x i1> @p2_vec_undef2(<3 x i8> %val, <3 x i8> %bits) {
+; CHECK-LABEL: @p2_vec_undef2(
+; CHECK-NEXT:    [[VAL_HIGHBITS:%.*]] = lshr <3 x i8> [[VAL:%.*]], [[BITS:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = icmp eq <3 x i8> [[VAL_HIGHBITS]], zeroinitializer
+; CHECK-NEXT:    ret <3 x i1> [[R]]
+;
+  %t0 = shl <3 x i8> <i8 -1, i8 undef, i8 -1>, %bits
+  %t1 = xor <3 x i8> %t0, <i8 -1, i8 undef, i8 -1>
+  %r = icmp uge <3 x i8> %t1, %val
+  ret <3 x i1> %r
+}
+
+; ============================================================================ ;
+; Commutativity tests.
+; ============================================================================ ;
+
+declare i8 @gen8()
+
+define i1 @c0(i8 %bits) {
+; CHECK-LABEL: @c0(
+; CHECK-NEXT:    [[VAL:%.*]] = call i8 @gen8()
+; CHECK-NEXT:    [[VAL_HIGHBITS:%.*]] = lshr i8 [[VAL]], [[BITS:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = icmp eq i8 [[VAL_HIGHBITS]], 0
+; CHECK-NEXT:    ret i1 [[R]]
+;
+  %t0 = shl i8 -1, %bits
+  %t1 = xor i8 %t0, -1
+  %val = call i8 @gen8()
+  %r = icmp ule i8 %val, %t1 ; swapped order and predicate
+  ret i1 %r
+}
+
+; What if we have the same pattern on both sides?
+define i1 @both(i8 %bits0, i8 %bits1) {
+; CHECK-LABEL: @both(
+; CHECK-NEXT:    [[T0:%.*]] = shl i8 -1, [[BITS0:%.*]]
+; CHECK-NEXT:    [[T2:%.*]] = shl i8 -1, [[BITS1:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = icmp uge i8 [[T2]], [[T0]]
+; CHECK-NEXT:    ret i1 [[R]]
+;
+  %t0 = shl i8 -1, %bits0
+  %t1 = xor i8 %t0, -1
+  %t2 = shl i8 -1, %bits1
+  %t3 = xor i8 %t2, -1
+  %r = icmp uge i8 %t1, %t3
+  ret i1 %r
+}
+
+; ============================================================================ ;
+; One-use tests.
+; ============================================================================ ;
+
+declare void @use8(i8)
+
+define i1 @oneuse0(i8 %val, i8 %bits) {
+; CHECK-LABEL: @oneuse0(
+; CHECK-NEXT:    [[T0:%.*]] = shl i8 -1, [[BITS:%.*]]
+; CHECK-NEXT:    call void @use8(i8 [[T0]])
+; CHECK-NEXT:    [[VAL_HIGHBITS:%.*]] = lshr i8 [[VAL:%.*]], [[BITS]]
+; CHECK-NEXT:    [[R:%.*]] = icmp eq i8 [[VAL_HIGHBITS]], 0
+; CHECK-NEXT:    ret i1 [[R]]
+;
+  %t0 = shl i8 -1, %bits
+  call void @use8(i8 %t0)
+  %t1 = xor i8 %t0, -1
+  %r = icmp uge i8 %t1, %val
+  ret i1 %r
+}
+
+define i1 @oneuse1(i8 %val, i8 %bits) {
+; CHECK-LABEL: @oneuse1(
+; CHECK-NEXT:    [[T0:%.*]] = shl i8 -1, [[BITS:%.*]]
+; CHECK-NEXT:    [[T1:%.*]] = xor i8 [[T0]], -1
+; CHECK-NEXT:    call void @use8(i8 [[T1]])
+; CHECK-NEXT:    [[R:%.*]] = icmp uge i8 [[T1]], [[VAL:%.*]]
+; CHECK-NEXT:    ret i1 [[R]]
+;
+  %t0 = shl i8 -1, %bits
+  %t1 = xor i8 %t0, -1
+  call void @use8(i8 %t1)
+  %r = icmp uge i8 %t1, %val
+  ret i1 %r
+}
+
+define i1 @oneuse2(i8 %val, i8 %bits) {
+; CHECK-LABEL: @oneuse2(
+; CHECK-NEXT:    [[T0:%.*]] = shl i8 -1, [[BITS:%.*]]
+; CHECK-NEXT:    call void @use8(i8 [[T0]])
+; CHECK-NEXT:    [[T1:%.*]] = xor i8 [[T0]], -1
+; CHECK-NEXT:    call void @use8(i8 [[T1]])
+; CHECK-NEXT:    [[R:%.*]] = icmp uge i8 [[T1]], [[VAL:%.*]]
+; CHECK-NEXT:    ret i1 [[R]]
+;
+  %t0 = shl i8 -1, %bits
+  call void @use8(i8 %t0)
+  %t1 = xor i8 %t0, -1
+  call void @use8(i8 %t1)
+  %r = icmp uge i8 %t1, %val
+  ret i1 %r
+}
+
+; ============================================================================ ;
+; Negative tests
+; ============================================================================ ;
+
+define i1 @n0(i8 %val, i8 %bits) {
+; CHECK-LABEL: @n0(
+; CHECK-NEXT:    [[T0:%.*]] = shl i8 1, [[BITS:%.*]]
+; CHECK-NEXT:    [[T1:%.*]] = xor i8 [[T0]], -1
+; CHECK-NEXT:    [[R:%.*]] = icmp uge i8 [[T1]], [[VAL:%.*]]
+; CHECK-NEXT:    ret i1 [[R]]
+;
+  %t0 = shl i8 1, %bits ; constant is not -1
+  %t1 = xor i8 %t0, -1
+  %r = icmp uge i8 %t1, %val
+  ret i1 %r
+}
+
+define i1 @n1(i8 %val, i8 %bits) {
+; CHECK-LABEL: @n1(
+; CHECK-NEXT:    [[T0:%.*]] = shl i8 -1, [[BITS:%.*]]
+; CHECK-NEXT:    [[T1:%.*]] = xor i8 [[T0]], 1
+; CHECK-NEXT:    [[R:%.*]] = icmp uge i8 [[T1]], [[VAL:%.*]]
+; CHECK-NEXT:    ret i1 [[R]]
+;
+  %t0 = shl i8 -1, %bits
+  %t1 = xor i8 %t0, 1 ; not 'not'
+  %r = icmp uge i8 %t1, %val
+  ret i1 %r
+}
+
+define <2 x i1> @n2_vec_nonsplat(<2 x i8> %val, <2 x i8> %bits) {
+; CHECK-LABEL: @n2_vec_nonsplat(
+; CHECK-NEXT:    [[T0:%.*]] = shl <2 x i8> <i8 -1, i8 1>, [[BITS:%.*]]
+; CHECK-NEXT:    [[T1:%.*]] = xor <2 x i8> [[T0]], <i8 -1, i8 -1>
+; CHECK-NEXT:    [[R:%.*]] = icmp uge <2 x i8> [[T1]], [[VAL:%.*]]
+; CHECK-NEXT:    ret <2 x i1> [[R]]
+;
+  %t0 = shl <2 x i8> <i8 -1, i8 1>, %bits ; again, wrong constant
+  %t1 = xor <2 x i8> %t0, <i8 -1, i8 -1>
+  %r = icmp uge <2 x i8> %t1, %val
+  ret <2 x i1> %r
+}
+
+define <2 x i1> @n3_vec_nonsplat(<2 x i8> %val, <2 x i8> %bits) {
+; CHECK-LABEL: @n3_vec_nonsplat(
+; CHECK-NEXT:    [[T0:%.*]] = shl <2 x i8> <i8 -1, i8 -1>, [[BITS:%.*]]
+; CHECK-NEXT:    [[T1:%.*]] = xor <2 x i8> [[T0]], <i8 -1, i8 1>
+; CHECK-NEXT:    [[R:%.*]] = icmp uge <2 x i8> [[T1]], [[VAL:%.*]]
+; CHECK-NEXT:    ret <2 x i1> [[R]]
+;
+  %t0 = shl <2 x i8> <i8 -1, i8 -1>, %bits
+  %t1 = xor <2 x i8> %t0, <i8 -1, i8 1> ; again, wrong constant
+  %r = icmp uge <2 x i8> %t1, %val
+  ret <2 x i1> %r
+}
+
+define i1 @n3(i8 %val, i8 %bits) {
+; CHECK-LABEL: @n3(
+; CHECK-NEXT:    [[T0:%.*]] = shl i8 -1, [[BITS:%.*]]
+; CHECK-NEXT:    [[T1:%.*]] = xor i8 [[T0]], -1
+; CHECK-NEXT:    [[R:%.*]] = icmp ugt i8 [[T1]], [[VAL:%.*]]
+; CHECK-NEXT:    ret i1 [[R]]
+;
+  %t0 = shl i8 -1, %bits
+  %t1 = xor i8 %t0, -1
+  %r = icmp ugt i8 %t1, %val ; wrong predicate
+  ret i1 %r
+}
+
+define i1 @n4(i8 %bits) {
+; CHECK-LABEL: @n4(
+; CHECK-NEXT:    [[T0:%.*]] = shl i8 -1, [[BITS:%.*]]
+; CHECK-NEXT:    [[T1:%.*]] = xor i8 [[T0]], -1
+; CHECK-NEXT:    [[VAL:%.*]] = call i8 @gen8()
+; CHECK-NEXT:    [[R:%.*]] = icmp ult i8 [[VAL]], [[T1]]
+; CHECK-NEXT:    ret i1 [[R]]
+;
+  %t0 = shl i8 -1, %bits
+  %t1 = xor i8 %t0, -1
+  %val = call i8 @gen8()
+  %r = icmp ult i8 %val, %t1 ; swapped order and [wrong] predicate
+  ret i1 %r
+}

Added: llvm/trunk/test/Transforms/InstCombine/icmp-ugt-of-shl-1-by-bits-and-val-to-icmp-eq-of-lshr-val-by-bits-and-0.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/icmp-ugt-of-shl-1-by-bits-and-val-to-icmp-eq-of-lshr-val-by-bits-and-0.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/icmp-ugt-of-shl-1-by-bits-and-val-to-icmp-eq-of-lshr-val-by-bits-and-0.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/icmp-ugt-of-shl-1-by-bits-and-val-to-icmp-eq-of-lshr-val-by-bits-and-0.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,152 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt < %s -instcombine -S | FileCheck %s
+
+; https://bugs.llvm.org/show_bug.cgi?id=38708
+
+; Pattern:
+;   (1 << bits) u> val
+; Should be transformed into:
+;   (val l>> bits) == 0
+
+; ============================================================================ ;
+; Basic positive tests
+; ============================================================================ ;
+
+define i1 @p0(i8 %val, i8 %bits) {
+; CHECK-LABEL: @p0(
+; CHECK-NEXT:    [[VAL_HIGHBITS:%.*]] = lshr i8 [[VAL:%.*]], [[BITS:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = icmp eq i8 [[VAL_HIGHBITS]], 0
+; CHECK-NEXT:    ret i1 [[R]]
+;
+  %t0 = shl i8 1, %bits
+  %r = icmp ugt i8 %t0, %val
+  ret i1 %r
+}
+
+; ============================================================================ ;
+; Vector tests
+; ============================================================================ ;
+
+define <2 x i1> @p1_vec(<2 x i8> %val, <2 x i8> %bits) {
+; CHECK-LABEL: @p1_vec(
+; CHECK-NEXT:    [[VAL_HIGHBITS:%.*]] = lshr <2 x i8> [[VAL:%.*]], [[BITS:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = icmp eq <2 x i8> [[VAL_HIGHBITS]], zeroinitializer
+; CHECK-NEXT:    ret <2 x i1> [[R]]
+;
+  %t0 = shl <2 x i8> <i8 1, i8 1>, %bits
+  %r = icmp ugt <2 x i8> %t0, %val
+  ret <2 x i1> %r
+}
+
+define <3 x i1> @p2_vec_undef(<3 x i8> %val, <3 x i8> %bits) {
+; CHECK-LABEL: @p2_vec_undef(
+; CHECK-NEXT:    [[VAL_HIGHBITS:%.*]] = lshr <3 x i8> [[VAL:%.*]], [[BITS:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = icmp eq <3 x i8> [[VAL_HIGHBITS]], zeroinitializer
+; CHECK-NEXT:    ret <3 x i1> [[R]]
+;
+  %t0 = shl <3 x i8> <i8 1, i8 undef, i8 1>, %bits
+  %r = icmp ugt <3 x i8> %t0, %val
+  ret <3 x i1> %r
+}
+
+; ============================================================================ ;
+; Commutativity tests.
+; ============================================================================ ;
+
+declare i8 @gen8()
+
+define i1 @c0(i8 %bits) {
+; CHECK-LABEL: @c0(
+; CHECK-NEXT:    [[VAL:%.*]] = call i8 @gen8()
+; CHECK-NEXT:    [[VAL_HIGHBITS:%.*]] = lshr i8 [[VAL]], [[BITS:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = icmp eq i8 [[VAL_HIGHBITS]], 0
+; CHECK-NEXT:    ret i1 [[R]]
+;
+  %t0 = shl i8 1, %bits
+  %val = call i8 @gen8()
+  %r = icmp ult i8 %val, %t0 ; swapped order and predicate
+  ret i1 %r
+}
+
+; What if we have the same pattern on both sides?
+define i1 @both(i8 %bits0, i8 %bits1) {
+; CHECK-LABEL: @both(
+; CHECK-NEXT:    [[T1:%.*]] = shl i8 1, [[BITS1:%.*]]
+; CHECK-NEXT:    [[T1_HIGHBITS:%.*]] = lshr i8 [[T1]], [[BITS0:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = icmp eq i8 [[T1_HIGHBITS]], 0
+; CHECK-NEXT:    ret i1 [[R]]
+;
+  %t0 = shl i8 1, %bits0
+  %t1 = shl i8 1, %bits1
+  %r = icmp ugt i8 %t0, %t1
+  ret i1 %r
+}
+
+; ============================================================================ ;
+; One-use tests.
+; ============================================================================ ;
+
+declare void @use8(i8)
+
+define i1 @oneuse0(i8 %val, i8 %bits) {
+; CHECK-LABEL: @oneuse0(
+; CHECK-NEXT:    [[T0:%.*]] = shl i8 1, [[BITS:%.*]]
+; CHECK-NEXT:    call void @use8(i8 [[T0]])
+; CHECK-NEXT:    [[R:%.*]] = icmp ugt i8 [[T0]], [[VAL:%.*]]
+; CHECK-NEXT:    ret i1 [[R]]
+;
+  %t0 = shl i8 1, %bits
+  call void @use8(i8 %t0)
+  %r = icmp ugt i8 %t0, %val
+  ret i1 %r
+}
+
+; ============================================================================ ;
+; Negative tests
+; ============================================================================ ;
+
+define i1 @n0(i8 %val, i8 %bits) {
+; CHECK-LABEL: @n0(
+; CHECK-NEXT:    [[T0:%.*]] = shl i8 2, [[BITS:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = icmp ugt i8 [[T0]], [[VAL:%.*]]
+; CHECK-NEXT:    ret i1 [[R]]
+;
+  %t0 = shl i8 2, %bits ; constant is not 1
+  %r = icmp ugt i8 %t0, %val
+  ret i1 %r
+}
+
+define <2 x i1> @n1_vec_nonsplat(<2 x i8> %val, <2 x i8> %bits) {
+; CHECK-LABEL: @n1_vec_nonsplat(
+; CHECK-NEXT:    [[T0:%.*]] = shl <2 x i8> <i8 1, i8 2>, [[BITS:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = icmp ugt <2 x i8> [[T0]], [[VAL:%.*]]
+; CHECK-NEXT:    ret <2 x i1> [[R]]
+;
+  %t0 = shl <2 x i8> <i8 1, i8 2>, %bits ; again, wrong constant
+  %r = icmp ugt <2 x i8> %t0, %val
+  ret <2 x i1> %r
+}
+
+define i1 @n2(i8 %val, i8 %bits) {
+; CHECK-LABEL: @n2(
+; CHECK-NEXT:    [[T0:%.*]] = shl i8 1, [[BITS:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = icmp uge i8 [[T0]], [[VAL:%.*]]
+; CHECK-NEXT:    ret i1 [[R]]
+;
+  %t0 = shl i8 1, %bits
+  %r = icmp uge i8 %t0, %val ; wrong predicate
+  ret i1 %r
+}
+
+define i1 @n3(i8 %bits) {
+; CHECK-LABEL: @n3(
+; CHECK-NEXT:    [[T0:%.*]] = shl i8 1, [[BITS:%.*]]
+; CHECK-NEXT:    [[VAL:%.*]] = call i8 @gen8()
+; CHECK-NEXT:    [[R:%.*]] = icmp ule i8 [[VAL]], [[T0]]
+; CHECK-NEXT:    ret i1 [[R]]
+;
+  %t0 = shl i8 1, %bits
+  %val = call i8 @gen8()
+  %r = icmp ule i8 %val, %t0 ; swapped order and [wrong] predicate
+  ret i1 %r
+}

Added: llvm/trunk/test/Transforms/InstCombine/icmp-ule-of-shl-1-by-bits-and-val-to-icmp-ne-of-lshr-val-by-bits-and-0.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/icmp-ule-of-shl-1-by-bits-and-val-to-icmp-ne-of-lshr-val-by-bits-and-0.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/icmp-ule-of-shl-1-by-bits-and-val-to-icmp-ne-of-lshr-val-by-bits-and-0.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/icmp-ule-of-shl-1-by-bits-and-val-to-icmp-ne-of-lshr-val-by-bits-and-0.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,152 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt < %s -instcombine -S | FileCheck %s
+
+; https://bugs.llvm.org/show_bug.cgi?id=38708
+
+; Pattern:
+;   (1 << bits) u<= val
+; Should be transformed into:
+;   (val l>> bits) != 0
+
+; ============================================================================ ;
+; Basic positive tests
+; ============================================================================ ;
+
+define i1 @p0(i8 %val, i8 %bits) {
+; CHECK-LABEL: @p0(
+; CHECK-NEXT:    [[VAL_HIGHBITS:%.*]] = lshr i8 [[VAL:%.*]], [[BITS:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = icmp ne i8 [[VAL_HIGHBITS]], 0
+; CHECK-NEXT:    ret i1 [[R]]
+;
+  %t0 = shl i8 1, %bits
+  %r = icmp ule i8 %t0, %val
+  ret i1 %r
+}
+
+; ============================================================================ ;
+; Vector tests
+; ============================================================================ ;
+
+define <2 x i1> @p1_vec(<2 x i8> %val, <2 x i8> %bits) {
+; CHECK-LABEL: @p1_vec(
+; CHECK-NEXT:    [[VAL_HIGHBITS:%.*]] = lshr <2 x i8> [[VAL:%.*]], [[BITS:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = icmp ne <2 x i8> [[VAL_HIGHBITS]], zeroinitializer
+; CHECK-NEXT:    ret <2 x i1> [[R]]
+;
+  %t0 = shl <2 x i8> <i8 1, i8 1>, %bits
+  %r = icmp ule <2 x i8> %t0, %val
+  ret <2 x i1> %r
+}
+
+define <3 x i1> @p2_vec_undef(<3 x i8> %val, <3 x i8> %bits) {
+; CHECK-LABEL: @p2_vec_undef(
+; CHECK-NEXT:    [[VAL_HIGHBITS:%.*]] = lshr <3 x i8> [[VAL:%.*]], [[BITS:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = icmp ne <3 x i8> [[VAL_HIGHBITS]], zeroinitializer
+; CHECK-NEXT:    ret <3 x i1> [[R]]
+;
+  %t0 = shl <3 x i8> <i8 1, i8 undef, i8 1>, %bits
+  %r = icmp ule <3 x i8> %t0, %val
+  ret <3 x i1> %r
+}
+
+; ============================================================================ ;
+; Commutativity tests.
+; ============================================================================ ;
+
+declare i8 @gen8()
+
+define i1 @c0(i8 %bits) {
+; CHECK-LABEL: @c0(
+; CHECK-NEXT:    [[VAL:%.*]] = call i8 @gen8()
+; CHECK-NEXT:    [[VAL_HIGHBITS:%.*]] = lshr i8 [[VAL]], [[BITS:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = icmp ne i8 [[VAL_HIGHBITS]], 0
+; CHECK-NEXT:    ret i1 [[R]]
+;
+  %t0 = shl i8 1, %bits
+  %val = call i8 @gen8()
+  %r = icmp uge i8 %val, %t0 ; swapped order and predicate
+  ret i1 %r
+}
+
+; What if we have the same pattern on both sides?
+define i1 @both(i8 %bits0, i8 %bits1) {
+; CHECK-LABEL: @both(
+; CHECK-NEXT:    [[T1:%.*]] = shl i8 1, [[BITS1:%.*]]
+; CHECK-NEXT:    [[T1_HIGHBITS:%.*]] = lshr i8 [[T1]], [[BITS0:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = icmp ne i8 [[T1_HIGHBITS]], 0
+; CHECK-NEXT:    ret i1 [[R]]
+;
+  %t0 = shl i8 1, %bits0
+  %t1 = shl i8 1, %bits1
+  %r = icmp ule i8 %t0, %t1
+  ret i1 %r
+}
+
+; ============================================================================ ;
+; One-use tests.
+; ============================================================================ ;
+
+declare void @use8(i8)
+
+define i1 @oneuse0(i8 %val, i8 %bits) {
+; CHECK-LABEL: @oneuse0(
+; CHECK-NEXT:    [[T0:%.*]] = shl i8 1, [[BITS:%.*]]
+; CHECK-NEXT:    call void @use8(i8 [[T0]])
+; CHECK-NEXT:    [[R:%.*]] = icmp ule i8 [[T0]], [[VAL:%.*]]
+; CHECK-NEXT:    ret i1 [[R]]
+;
+  %t0 = shl i8 1, %bits
+  call void @use8(i8 %t0)
+  %r = icmp ule i8 %t0, %val
+  ret i1 %r
+}
+
+; ============================================================================ ;
+; Negative tests
+; ============================================================================ ;
+
+define i1 @n0(i8 %val, i8 %bits) {
+; CHECK-LABEL: @n0(
+; CHECK-NEXT:    [[T0:%.*]] = shl i8 2, [[BITS:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = icmp ule i8 [[T0]], [[VAL:%.*]]
+; CHECK-NEXT:    ret i1 [[R]]
+;
+  %t0 = shl i8 2, %bits ; constant is not 1
+  %r = icmp ule i8 %t0, %val
+  ret i1 %r
+}
+
+define <2 x i1> @n1_vec_nonsplat(<2 x i8> %val, <2 x i8> %bits) {
+; CHECK-LABEL: @n1_vec_nonsplat(
+; CHECK-NEXT:    [[T0:%.*]] = shl <2 x i8> <i8 1, i8 2>, [[BITS:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = icmp ule <2 x i8> [[T0]], [[VAL:%.*]]
+; CHECK-NEXT:    ret <2 x i1> [[R]]
+;
+  %t0 = shl <2 x i8> <i8 1, i8 2>, %bits ; again, wrong constant
+  %r = icmp ule <2 x i8> %t0, %val
+  ret <2 x i1> %r
+}
+
+define i1 @n2(i8 %val, i8 %bits) {
+; CHECK-LABEL: @n2(
+; CHECK-NEXT:    [[T0:%.*]] = shl i8 1, [[BITS:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = icmp ult i8 [[T0]], [[VAL:%.*]]
+; CHECK-NEXT:    ret i1 [[R]]
+;
+  %t0 = shl i8 1, %bits
+  %r = icmp ult i8 %t0, %val ; wrong predicate
+  ret i1 %r
+}
+
+define i1 @n3(i8 %bits) {
+; CHECK-LABEL: @n3(
+; CHECK-NEXT:    [[T0:%.*]] = shl i8 1, [[BITS:%.*]]
+; CHECK-NEXT:    [[VAL:%.*]] = call i8 @gen8()
+; CHECK-NEXT:    [[R:%.*]] = icmp ugt i8 [[VAL]], [[T0]]
+; CHECK-NEXT:    ret i1 [[R]]
+;
+  %t0 = shl i8 1, %bits
+  %val = call i8 @gen8()
+  %r = icmp ugt i8 %val, %t0 ; swapped order and [wrong] predicate
+  ret i1 %r
+}

Added: llvm/trunk/test/Transforms/InstCombine/icmp-ult-of-add-of-shl-one-by-bits-to-allones-and-val-to-icmp-ne-of-lshr-val-by-bits-and-0.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/icmp-ult-of-add-of-shl-one-by-bits-to-allones-and-val-to-icmp-ne-of-lshr-val-by-bits-and-0.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/icmp-ult-of-add-of-shl-one-by-bits-to-allones-and-val-to-icmp-ne-of-lshr-val-by-bits-and-0.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/icmp-ult-of-add-of-shl-one-by-bits-to-allones-and-val-to-icmp-ne-of-lshr-val-by-bits-and-0.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,260 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt < %s -instcombine -S | FileCheck %s
+
+; https://bugs.llvm.org/show_bug.cgi?id=38708
+
+; Pattern:
+;   ((1 << bits)+(-1)) u< val
+; Should be transformed into:
+;   (val l>> bits) != 0
+
+; NOTE: the innermost shl is not one-use. Else canonicalization happens.
+
+declare void @use8(i8)
+declare void @use2i8(<2 x i8>)
+declare void @use3i8(<3 x i8>)
+
+; ============================================================================ ;
+; Basic positive tests
+; ============================================================================ ;
+
+define i1 @p0(i8 %val, i8 %bits) {
+; CHECK-LABEL: @p0(
+; CHECK-NEXT:    [[T0:%.*]] = shl i8 1, [[BITS:%.*]]
+; CHECK-NEXT:    call void @use8(i8 [[T0]])
+; CHECK-NEXT:    [[VAL_HIGHBITS:%.*]] = lshr i8 [[VAL:%.*]], [[BITS]]
+; CHECK-NEXT:    [[R:%.*]] = icmp ne i8 [[VAL_HIGHBITS]], 0
+; CHECK-NEXT:    ret i1 [[R]]
+;
+  %t0 = shl i8 1, %bits
+  call void @use8(i8 %t0)
+  %t1 = add i8 %t0, -1
+  %r = icmp ult i8 %t1, %val
+  ret i1 %r
+}
+
+; ============================================================================ ;
+; Vector tests
+; ============================================================================ ;
+
+define <2 x i1> @p1_vec(<2 x i8> %val, <2 x i8> %bits) {
+; CHECK-LABEL: @p1_vec(
+; CHECK-NEXT:    [[T0:%.*]] = shl <2 x i8> <i8 1, i8 1>, [[BITS:%.*]]
+; CHECK-NEXT:    call void @use2i8(<2 x i8> [[T0]])
+; CHECK-NEXT:    [[VAL_HIGHBITS:%.*]] = lshr <2 x i8> [[VAL:%.*]], [[BITS]]
+; CHECK-NEXT:    [[R:%.*]] = icmp ne <2 x i8> [[VAL_HIGHBITS]], zeroinitializer
+; CHECK-NEXT:    ret <2 x i1> [[R]]
+;
+  %t0 = shl <2 x i8> <i8 1, i8 1>, %bits
+  call void @use2i8(<2 x i8> %t0)
+  %t1 = add <2 x i8> %t0, <i8 -1, i8 -1>
+  %r = icmp ult <2 x i8> %t1, %val
+  ret <2 x i1> %r
+}
+
+define <3 x i1> @p2_vec_undef0(<3 x i8> %val, <3 x i8> %bits) {
+; CHECK-LABEL: @p2_vec_undef0(
+; CHECK-NEXT:    [[T0:%.*]] = shl <3 x i8> <i8 1, i8 undef, i8 1>, [[BITS:%.*]]
+; CHECK-NEXT:    call void @use3i8(<3 x i8> [[T0]])
+; CHECK-NEXT:    [[VAL_HIGHBITS:%.*]] = lshr <3 x i8> [[VAL:%.*]], [[BITS]]
+; CHECK-NEXT:    [[R:%.*]] = icmp ne <3 x i8> [[VAL_HIGHBITS]], zeroinitializer
+; CHECK-NEXT:    ret <3 x i1> [[R]]
+;
+  %t0 = shl <3 x i8> <i8 1, i8 undef, i8 1>, %bits
+  call void @use3i8(<3 x i8> %t0)
+  %t1 = add <3 x i8> %t0, <i8 -1, i8 -1, i8 -1>
+  %r = icmp ult <3 x i8> %t1, %val
+  ret <3 x i1> %r
+}
+
+define <3 x i1> @p2_vec_undef1(<3 x i8> %val, <3 x i8> %bits) {
+; CHECK-LABEL: @p2_vec_undef1(
+; CHECK-NEXT:    [[T0:%.*]] = shl <3 x i8> <i8 1, i8 1, i8 1>, [[BITS:%.*]]
+; CHECK-NEXT:    call void @use3i8(<3 x i8> [[T0]])
+; CHECK-NEXT:    [[VAL_HIGHBITS:%.*]] = lshr <3 x i8> [[VAL:%.*]], [[BITS]]
+; CHECK-NEXT:    [[R:%.*]] = icmp ne <3 x i8> [[VAL_HIGHBITS]], zeroinitializer
+; CHECK-NEXT:    ret <3 x i1> [[R]]
+;
+  %t0 = shl <3 x i8> <i8 1, i8 1, i8 1>, %bits
+  call void @use3i8(<3 x i8> %t0)
+  %t1 = add <3 x i8> %t0, <i8 -1, i8 undef, i8 -1>
+  %r = icmp ult <3 x i8> %t1, %val
+  ret <3 x i1> %r
+}
+
+define <3 x i1> @p2_vec_undef2(<3 x i8> %val, <3 x i8> %bits) {
+; CHECK-LABEL: @p2_vec_undef2(
+; CHECK-NEXT:    [[T0:%.*]] = shl <3 x i8> <i8 1, i8 undef, i8 1>, [[BITS:%.*]]
+; CHECK-NEXT:    call void @use3i8(<3 x i8> [[T0]])
+; CHECK-NEXT:    [[VAL_HIGHBITS:%.*]] = lshr <3 x i8> [[VAL:%.*]], [[BITS]]
+; CHECK-NEXT:    [[R:%.*]] = icmp ne <3 x i8> [[VAL_HIGHBITS]], zeroinitializer
+; CHECK-NEXT:    ret <3 x i1> [[R]]
+;
+  %t0 = shl <3 x i8> <i8 1, i8 undef, i8 1>, %bits
+  call void @use3i8(<3 x i8> %t0)
+  %t1 = add <3 x i8> %t0, <i8 -1, i8 undef, i8 -1>
+  %r = icmp ult <3 x i8> %t1, %val
+  ret <3 x i1> %r
+}
+
+; ============================================================================ ;
+; Commutativity tests.
+; ============================================================================ ;
+
+declare i8 @gen8()
+
+define i1 @c0(i8 %bits) {
+; CHECK-LABEL: @c0(
+; CHECK-NEXT:    [[T0:%.*]] = shl i8 1, [[BITS:%.*]]
+; CHECK-NEXT:    call void @use8(i8 [[T0]])
+; CHECK-NEXT:    [[VAL:%.*]] = call i8 @gen8()
+; CHECK-NEXT:    [[VAL_HIGHBITS:%.*]] = lshr i8 [[VAL]], [[BITS]]
+; CHECK-NEXT:    [[R:%.*]] = icmp ne i8 [[VAL_HIGHBITS]], 0
+; CHECK-NEXT:    ret i1 [[R]]
+;
+  %t0 = shl i8 1, %bits
+  call void @use8(i8 %t0)
+  %t1 = add i8 %t0, -1
+  %val = call i8 @gen8()
+  %r = icmp ugt i8 %val, %t1 ; swapped order and predicate
+  ret i1 %r
+}
+
+; What if we have the same pattern on both sides?
+define i1 @both(i8 %bits0, i8 %bits1) {
+; CHECK-LABEL: @both(
+; CHECK-NEXT:    [[T0:%.*]] = shl i8 1, [[BITS0:%.*]]
+; CHECK-NEXT:    call void @use8(i8 [[T0]])
+; CHECK-NEXT:    [[T2:%.*]] = shl i8 1, [[BITS1:%.*]]
+; CHECK-NEXT:    call void @use8(i8 [[T2]])
+; CHECK-NEXT:    [[T3:%.*]] = add i8 [[T2]], -1
+; CHECK-NEXT:    [[T3_HIGHBITS:%.*]] = lshr i8 [[T3]], [[BITS0]]
+; CHECK-NEXT:    [[R:%.*]] = icmp ne i8 [[T3_HIGHBITS]], 0
+; CHECK-NEXT:    ret i1 [[R]]
+;
+  %t0 = shl i8 1, %bits0
+  call void @use8(i8 %t0)
+  %t1 = add i8 %t0, -1
+  %t2 = shl i8 1, %bits1
+  call void @use8(i8 %t2)
+  %t3 = add i8 %t2, -1
+  %r = icmp ult i8 %t1, %t3
+  ret i1 %r
+}
+
+; ============================================================================ ;
+; One-use tests.
+; ============================================================================ ;
+
+define i1 @oneuse(i8 %val, i8 %bits) {
+; CHECK-LABEL: @oneuse(
+; CHECK-NEXT:    [[T0:%.*]] = shl i8 1, [[BITS:%.*]]
+; CHECK-NEXT:    call void @use8(i8 [[T0]])
+; CHECK-NEXT:    [[T1:%.*]] = add i8 [[T0]], -1
+; CHECK-NEXT:    call void @use8(i8 [[T1]])
+; CHECK-NEXT:    [[R:%.*]] = icmp ult i8 [[T1]], [[VAL:%.*]]
+; CHECK-NEXT:    ret i1 [[R]]
+;
+  %t0 = shl i8 1, %bits
+  call void @use8(i8 %t0) ; this is needed anyway
+  %t1 = add i8 %t0, -1
+  call void @use8(i8 %t1)
+  %r = icmp ult i8 %t1, %val
+  ret i1 %r
+}
+
+; ============================================================================ ;
+; Negative tests
+; ============================================================================ ;
+
+define i1 @n0(i8 %val, i8 %bits) {
+; CHECK-LABEL: @n0(
+; CHECK-NEXT:    [[T0:%.*]] = shl i8 -1, [[BITS:%.*]]
+; CHECK-NEXT:    call void @use8(i8 [[T0]])
+; CHECK-NEXT:    [[T1:%.*]] = add i8 [[T0]], -1
+; CHECK-NEXT:    [[R:%.*]] = icmp ult i8 [[T1]], [[VAL:%.*]]
+; CHECK-NEXT:    ret i1 [[R]]
+;
+  %t0 = shl i8 -1, %bits ; constant is not 1
+  call void @use8(i8 %t0)
+  %t1 = add i8 %t0, -1
+  %r = icmp ult i8 %t1, %val
+  ret i1 %r
+}
+
+define i1 @n1(i8 %val, i8 %bits) {
+; CHECK-LABEL: @n1(
+; CHECK-NEXT:    [[T0:%.*]] = shl i8 1, [[BITS:%.*]]
+; CHECK-NEXT:    call void @use8(i8 [[T0]])
+; CHECK-NEXT:    [[T1:%.*]] = add i8 [[T0]], 1
+; CHECK-NEXT:    [[R:%.*]] = icmp ult i8 [[T1]], [[VAL:%.*]]
+; CHECK-NEXT:    ret i1 [[R]]
+;
+  %t0 = shl i8 1, %bits
+  call void @use8(i8 %t0)
+  %t1 = add i8 %t0, 1 ; constant is not -1
+  %r = icmp ult i8 %t1, %val
+  ret i1 %r
+}
+
+define <2 x i1> @n2_vec_nonsplat(<2 x i8> %val, <2 x i8> %bits) {
+; CHECK-LABEL: @n2_vec_nonsplat(
+; CHECK-NEXT:    [[T0:%.*]] = shl <2 x i8> <i8 1, i8 -1>, [[BITS:%.*]]
+; CHECK-NEXT:    call void @use2i8(<2 x i8> [[T0]])
+; CHECK-NEXT:    [[T1:%.*]] = add <2 x i8> [[T0]], <i8 -1, i8 -1>
+; CHECK-NEXT:    [[R:%.*]] = icmp ult <2 x i8> [[T1]], [[VAL:%.*]]
+; CHECK-NEXT:    ret <2 x i1> [[R]]
+;
+  %t0 = shl <2 x i8> <i8 1, i8 -1>, %bits ; again, wrong constant
+  call void @use2i8(<2 x i8> %t0)
+  %t1 = add <2 x i8> %t0, <i8 -1, i8 -1>
+  %r = icmp ult <2 x i8> %t1, %val
+  ret <2 x i1> %r
+}
+
+define <2 x i1> @n3_vec_nonsplat(<2 x i8> %val, <2 x i8> %bits) {
+; CHECK-LABEL: @n3_vec_nonsplat(
+; CHECK-NEXT:    [[T0:%.*]] = shl <2 x i8> <i8 1, i8 1>, [[BITS:%.*]]
+; CHECK-NEXT:    call void @use2i8(<2 x i8> [[T0]])
+; CHECK-NEXT:    [[T1:%.*]] = add <2 x i8> [[T0]], <i8 -1, i8 1>
+; CHECK-NEXT:    [[R:%.*]] = icmp ult <2 x i8> [[T1]], [[VAL:%.*]]
+; CHECK-NEXT:    ret <2 x i1> [[R]]
+;
+  %t0 = shl <2 x i8> <i8 1, i8 1>, %bits
+  call void @use2i8(<2 x i8> %t0)
+  %t1 = add <2 x i8> %t0, <i8 -1, i8 1> ; again, wrong constant
+  %r = icmp ult <2 x i8> %t1, %val
+  ret <2 x i1> %r
+}
+
+define i1 @n3(i8 %val, i8 %bits) {
+; CHECK-LABEL: @n3(
+; CHECK-NEXT:    [[T0:%.*]] = shl i8 1, [[BITS:%.*]]
+; CHECK-NEXT:    call void @use8(i8 [[T0]])
+; CHECK-NEXT:    [[T1:%.*]] = add i8 [[T0]], -1
+; CHECK-NEXT:    [[R:%.*]] = icmp ule i8 [[T1]], [[VAL:%.*]]
+; CHECK-NEXT:    ret i1 [[R]]
+;
+  %t0 = shl i8 1, %bits
+  call void @use8(i8 %t0)
+  %t1 = add i8 %t0, -1
+  %r = icmp ule i8 %t1, %val ; wrong predicate
+  ret i1 %r
+}
+
+define i1 @n4(i8 %bits) {
+; CHECK-LABEL: @n4(
+; CHECK-NEXT:    [[T0:%.*]] = shl i8 1, [[BITS:%.*]]
+; CHECK-NEXT:    call void @use8(i8 [[T0]])
+; CHECK-NEXT:    [[T1:%.*]] = add i8 [[T0]], -1
+; CHECK-NEXT:    [[VAL:%.*]] = call i8 @gen8()
+; CHECK-NEXT:    [[R:%.*]] = icmp uge i8 [[VAL]], [[T1]]
+; CHECK-NEXT:    ret i1 [[R]]
+;
+  %t0 = shl i8 1, %bits
+  call void @use8(i8 %t0)
+  %t1 = add i8 %t0, -1
+  %val = call i8 @gen8()
+  %r = icmp uge i8 %val, %t1 ; swapped order and [wrong] predicate
+  ret i1 %r
+}

Added: llvm/trunk/test/Transforms/InstCombine/icmp-ult-of-not-of-shl-allones-by-bits-and-val-to-icmp-ne-of-lshr-val-by-bits-and-0.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/icmp-ult-of-not-of-shl-allones-by-bits-and-val-to-icmp-ne-of-lshr-val-by-bits-and-0.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/icmp-ult-of-not-of-shl-allones-by-bits-and-val-to-icmp-ne-of-lshr-val-by-bits-and-0.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/icmp-ult-of-not-of-shl-allones-by-bits-and-val-to-icmp-ne-of-lshr-val-by-bits-and-0.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,250 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt < %s -instcombine -S | FileCheck %s
+
+; https://bugs.llvm.org/show_bug.cgi?id=38708
+
+; Pattern:
+;   ~(-1 << bits) u< val
+; Should be transformed into:
+;   (val l>> bits) != 0
+
+; ============================================================================ ;
+; Basic positive tests
+; ============================================================================ ;
+
+define i1 @p0(i8 %val, i8 %bits) {
+; CHECK-LABEL: @p0(
+; CHECK-NEXT:    [[VAL_HIGHBITS:%.*]] = lshr i8 [[VAL:%.*]], [[BITS:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = icmp ne i8 [[VAL_HIGHBITS]], 0
+; CHECK-NEXT:    ret i1 [[R]]
+;
+  %t0 = shl i8 -1, %bits
+  %t1 = xor i8 %t0, -1
+  %r = icmp ult i8 %t1, %val
+  ret i1 %r
+}
+
+; ============================================================================ ;
+; Vector tests
+; ============================================================================ ;
+
+define <2 x i1> @p1_vec(<2 x i8> %val, <2 x i8> %bits) {
+; CHECK-LABEL: @p1_vec(
+; CHECK-NEXT:    [[VAL_HIGHBITS:%.*]] = lshr <2 x i8> [[VAL:%.*]], [[BITS:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = icmp ne <2 x i8> [[VAL_HIGHBITS]], zeroinitializer
+; CHECK-NEXT:    ret <2 x i1> [[R]]
+;
+  %t0 = shl <2 x i8> <i8 -1, i8 -1>, %bits
+  %t1 = xor <2 x i8> %t0, <i8 -1, i8 -1>
+  %r = icmp ult <2 x i8> %t1, %val
+  ret <2 x i1> %r
+}
+
+define <3 x i1> @p2_vec_undef0(<3 x i8> %val, <3 x i8> %bits) {
+; CHECK-LABEL: @p2_vec_undef0(
+; CHECK-NEXT:    [[VAL_HIGHBITS:%.*]] = lshr <3 x i8> [[VAL:%.*]], [[BITS:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = icmp ne <3 x i8> [[VAL_HIGHBITS]], zeroinitializer
+; CHECK-NEXT:    ret <3 x i1> [[R]]
+;
+  %t0 = shl <3 x i8> <i8 -1, i8 undef, i8 -1>, %bits
+  %t1 = xor <3 x i8> %t0, <i8 -1, i8 -1, i8 -1>
+  %r = icmp ult <3 x i8> %t1, %val
+  ret <3 x i1> %r
+}
+
+define <3 x i1> @p2_vec_undef1(<3 x i8> %val, <3 x i8> %bits) {
+; CHECK-LABEL: @p2_vec_undef1(
+; CHECK-NEXT:    [[VAL_HIGHBITS:%.*]] = lshr <3 x i8> [[VAL:%.*]], [[BITS:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = icmp ne <3 x i8> [[VAL_HIGHBITS]], zeroinitializer
+; CHECK-NEXT:    ret <3 x i1> [[R]]
+;
+  %t0 = shl <3 x i8> <i8 -1, i8 -1, i8 -1>, %bits
+  %t1 = xor <3 x i8> %t0, <i8 -1, i8 undef, i8 -1>
+  %r = icmp ult <3 x i8> %t1, %val
+  ret <3 x i1> %r
+}
+
+define <3 x i1> @p2_vec_undef2(<3 x i8> %val, <3 x i8> %bits) {
+; CHECK-LABEL: @p2_vec_undef2(
+; CHECK-NEXT:    [[VAL_HIGHBITS:%.*]] = lshr <3 x i8> [[VAL:%.*]], [[BITS:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = icmp ne <3 x i8> [[VAL_HIGHBITS]], zeroinitializer
+; CHECK-NEXT:    ret <3 x i1> [[R]]
+;
+  %t0 = shl <3 x i8> <i8 -1, i8 undef, i8 -1>, %bits
+  %t1 = xor <3 x i8> %t0, <i8 -1, i8 undef, i8 -1>
+  %r = icmp ult <3 x i8> %t1, %val
+  ret <3 x i1> %r
+}
+
+; ============================================================================ ;
+; Commutativity tests.
+; ============================================================================ ;
+
+declare i8 @gen8()
+
+define i1 @c0(i8 %bits) {
+; CHECK-LABEL: @c0(
+; CHECK-NEXT:    [[VAL:%.*]] = call i8 @gen8()
+; CHECK-NEXT:    [[VAL_HIGHBITS:%.*]] = lshr i8 [[VAL]], [[BITS:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = icmp ne i8 [[VAL_HIGHBITS]], 0
+; CHECK-NEXT:    ret i1 [[R]]
+;
+  %t0 = shl i8 -1, %bits
+  %t1 = xor i8 %t0, -1
+  %val = call i8 @gen8()
+  %r = icmp ugt i8 %val, %t1 ; swapped order and predicate
+  ret i1 %r
+}
+
+; What if we have the same pattern on both sides?
+define i1 @both(i8 %bits0, i8 %bits1) {
+; CHECK-LABEL: @both(
+; CHECK-NEXT:    [[T0:%.*]] = shl i8 -1, [[BITS0:%.*]]
+; CHECK-NEXT:    [[T2:%.*]] = shl i8 -1, [[BITS1:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = icmp ult i8 [[T2]], [[T0]]
+; CHECK-NEXT:    ret i1 [[R]]
+;
+  %t0 = shl i8 -1, %bits0
+  %t1 = xor i8 %t0, -1
+  %t2 = shl i8 -1, %bits1
+  %t3 = xor i8 %t2, -1
+  %r = icmp ult i8 %t1, %t3
+  ret i1 %r
+}
+
+; ============================================================================ ;
+; One-use tests.
+; ============================================================================ ;
+
+declare void @use8(i8)
+
+define i1 @oneuse0(i8 %val, i8 %bits) {
+; CHECK-LABEL: @oneuse0(
+; CHECK-NEXT:    [[T0:%.*]] = shl i8 -1, [[BITS:%.*]]
+; CHECK-NEXT:    call void @use8(i8 [[T0]])
+; CHECK-NEXT:    [[VAL_HIGHBITS:%.*]] = lshr i8 [[VAL:%.*]], [[BITS]]
+; CHECK-NEXT:    [[R:%.*]] = icmp ne i8 [[VAL_HIGHBITS]], 0
+; CHECK-NEXT:    ret i1 [[R]]
+;
+  %t0 = shl i8 -1, %bits
+  call void @use8(i8 %t0)
+  %t1 = xor i8 %t0, -1
+  %r = icmp ult i8 %t1, %val
+  ret i1 %r
+}
+
+define i1 @oneuse1(i8 %val, i8 %bits) {
+; CHECK-LABEL: @oneuse1(
+; CHECK-NEXT:    [[T0:%.*]] = shl i8 -1, [[BITS:%.*]]
+; CHECK-NEXT:    [[T1:%.*]] = xor i8 [[T0]], -1
+; CHECK-NEXT:    call void @use8(i8 [[T1]])
+; CHECK-NEXT:    [[R:%.*]] = icmp ult i8 [[T1]], [[VAL:%.*]]
+; CHECK-NEXT:    ret i1 [[R]]
+;
+  %t0 = shl i8 -1, %bits
+  %t1 = xor i8 %t0, -1
+  call void @use8(i8 %t1)
+  %r = icmp ult i8 %t1, %val
+  ret i1 %r
+}
+
+define i1 @oneuse2(i8 %val, i8 %bits) {
+; CHECK-LABEL: @oneuse2(
+; CHECK-NEXT:    [[T0:%.*]] = shl i8 -1, [[BITS:%.*]]
+; CHECK-NEXT:    call void @use8(i8 [[T0]])
+; CHECK-NEXT:    [[T1:%.*]] = xor i8 [[T0]], -1
+; CHECK-NEXT:    call void @use8(i8 [[T1]])
+; CHECK-NEXT:    [[R:%.*]] = icmp ult i8 [[T1]], [[VAL:%.*]]
+; CHECK-NEXT:    ret i1 [[R]]
+;
+  %t0 = shl i8 -1, %bits
+  call void @use8(i8 %t0)
+  %t1 = xor i8 %t0, -1
+  call void @use8(i8 %t1)
+  %r = icmp ult i8 %t1, %val
+  ret i1 %r
+}
+
+; ============================================================================ ;
+; Negative tests
+; ============================================================================ ;
+
+define i1 @n0(i8 %val, i8 %bits) {
+; CHECK-LABEL: @n0(
+; CHECK-NEXT:    [[T0:%.*]] = shl i8 1, [[BITS:%.*]]
+; CHECK-NEXT:    [[T1:%.*]] = xor i8 [[T0]], -1
+; CHECK-NEXT:    [[R:%.*]] = icmp ult i8 [[T1]], [[VAL:%.*]]
+; CHECK-NEXT:    ret i1 [[R]]
+;
+  %t0 = shl i8 1, %bits ; constant is not -1
+  %t1 = xor i8 %t0, -1
+  %r = icmp ult i8 %t1, %val
+  ret i1 %r
+}
+
+define i1 @n1(i8 %val, i8 %bits) {
+; CHECK-LABEL: @n1(
+; CHECK-NEXT:    [[T0:%.*]] = shl i8 -1, [[BITS:%.*]]
+; CHECK-NEXT:    [[T1:%.*]] = xor i8 [[T0]], 1
+; CHECK-NEXT:    [[R:%.*]] = icmp ult i8 [[T1]], [[VAL:%.*]]
+; CHECK-NEXT:    ret i1 [[R]]
+;
+  %t0 = shl i8 -1, %bits
+  %t1 = xor i8 %t0, 1 ; not 'not'
+  %r = icmp ult i8 %t1, %val
+  ret i1 %r
+}
+
+define <2 x i1> @n2_vec_nonsplat(<2 x i8> %val, <2 x i8> %bits) {
+; CHECK-LABEL: @n2_vec_nonsplat(
+; CHECK-NEXT:    [[T0:%.*]] = shl <2 x i8> <i8 -1, i8 1>, [[BITS:%.*]]
+; CHECK-NEXT:    [[T1:%.*]] = xor <2 x i8> [[T0]], <i8 -1, i8 -1>
+; CHECK-NEXT:    [[R:%.*]] = icmp ult <2 x i8> [[T1]], [[VAL:%.*]]
+; CHECK-NEXT:    ret <2 x i1> [[R]]
+;
+  %t0 = shl <2 x i8> <i8 -1, i8 1>, %bits ; again, wrong constant
+  %t1 = xor <2 x i8> %t0, <i8 -1, i8 -1>
+  %r = icmp ult <2 x i8> %t1, %val
+  ret <2 x i1> %r
+}
+
+define <2 x i1> @n3_vec_nonsplat(<2 x i8> %val, <2 x i8> %bits) {
+; CHECK-LABEL: @n3_vec_nonsplat(
+; CHECK-NEXT:    [[T0:%.*]] = shl <2 x i8> <i8 -1, i8 -1>, [[BITS:%.*]]
+; CHECK-NEXT:    [[T1:%.*]] = xor <2 x i8> [[T0]], <i8 -1, i8 1>
+; CHECK-NEXT:    [[R:%.*]] = icmp ult <2 x i8> [[T1]], [[VAL:%.*]]
+; CHECK-NEXT:    ret <2 x i1> [[R]]
+;
+  %t0 = shl <2 x i8> <i8 -1, i8 -1>, %bits
+  %t1 = xor <2 x i8> %t0, <i8 -1, i8 1> ; again, wrong constant
+  %r = icmp ult <2 x i8> %t1, %val
+  ret <2 x i1> %r
+}
+
+define i1 @n3(i8 %val, i8 %bits) {
+; CHECK-LABEL: @n3(
+; CHECK-NEXT:    [[T0:%.*]] = shl i8 -1, [[BITS:%.*]]
+; CHECK-NEXT:    [[T1:%.*]] = xor i8 [[T0]], -1
+; CHECK-NEXT:    [[R:%.*]] = icmp ule i8 [[T1]], [[VAL:%.*]]
+; CHECK-NEXT:    ret i1 [[R]]
+;
+  %t0 = shl i8 -1, %bits
+  %t1 = xor i8 %t0, -1
+  %r = icmp ule i8 %t1, %val ; wrong predicate
+  ret i1 %r
+}
+
+define i1 @n4(i8 %bits) {
+; CHECK-LABEL: @n4(
+; CHECK-NEXT:    [[T0:%.*]] = shl i8 -1, [[BITS:%.*]]
+; CHECK-NEXT:    [[T1:%.*]] = xor i8 [[T0]], -1
+; CHECK-NEXT:    [[VAL:%.*]] = call i8 @gen8()
+; CHECK-NEXT:    [[R:%.*]] = icmp uge i8 [[VAL]], [[T1]]
+; CHECK-NEXT:    ret i1 [[R]]
+;
+  %t0 = shl i8 -1, %bits
+  %t1 = xor i8 %t0, -1
+  %val = call i8 @gen8()
+  %r = icmp uge i8 %val, %t1 ; swapped order and [wrong] predicate
+  ret i1 %r
+}

Added: llvm/trunk/test/Transforms/InstCombine/icmp-vec.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/icmp-vec.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/icmp-vec.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/icmp-vec.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,282 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt < %s -instcombine -S | FileCheck %s
+
+; Canonicalize vector ge/le comparisons with constants to gt/lt.
+
+; Normal types are ConstantDataVectors. Test the constant values adjacent to the
+; min/max values that we're not allowed to transform.
+
+define <2 x i1> @sge(<2 x i8> %x) {
+; CHECK-LABEL: @sge(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt <2 x i8> [[X:%.*]], <i8 -128, i8 126>
+; CHECK-NEXT:    ret <2 x i1> [[CMP]]
+;
+  %cmp = icmp sge <2 x i8> %x, <i8 -127, i8 -129>
+  ret <2 x i1> %cmp
+}
+
+define <2 x i1> @uge(<2 x i8> %x) {
+; CHECK-LABEL: @uge(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ugt <2 x i8> [[X:%.*]], <i8 -2, i8 0>
+; CHECK-NEXT:    ret <2 x i1> [[CMP]]
+;
+  %cmp = icmp uge <2 x i8> %x, <i8 -1, i8 1>
+  ret <2 x i1> %cmp
+}
+
+define <2 x i1> @sle(<2 x i8> %x) {
+; CHECK-LABEL: @sle(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp slt <2 x i8> [[X:%.*]], <i8 127, i8 -127>
+; CHECK-NEXT:    ret <2 x i1> [[CMP]]
+;
+  %cmp = icmp sle <2 x i8> %x, <i8 126, i8 128>
+  ret <2 x i1> %cmp
+}
+
+define <2 x i1> @ule(<2 x i8> %x) {
+; CHECK-LABEL: @ule(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ult <2 x i8> [[X:%.*]], <i8 -1, i8 1>
+; CHECK-NEXT:    ret <2 x i1> [[CMP]]
+;
+  %cmp = icmp ule <2 x i8> %x, <i8 254, i8 0>
+  ret <2 x i1> %cmp
+}
+
+define <2 x i1> @ult_min_signed_value(<2 x i8> %x) {
+; CHECK-LABEL: @ult_min_signed_value(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt <2 x i8> [[X:%.*]], <i8 -1, i8 -1>
+; CHECK-NEXT:    ret <2 x i1> [[CMP]]
+;
+  %cmp = icmp ult <2 x i8> %x, <i8 128, i8 128>
+  ret <2 x i1> %cmp
+}
+
+; Zeros are special: they're ConstantAggregateZero.
+
+define <2 x i1> @sge_zero(<2 x i8> %x) {
+; CHECK-LABEL: @sge_zero(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt <2 x i8> [[X:%.*]], <i8 -1, i8 -1>
+; CHECK-NEXT:    ret <2 x i1> [[CMP]]
+;
+  %cmp = icmp sge <2 x i8> %x, <i8 0, i8 0>
+  ret <2 x i1> %cmp
+}
+
+define <2 x i1> @uge_zero(<2 x i8> %x) {
+; CHECK-LABEL: @uge_zero(
+; CHECK-NEXT:    ret <2 x i1> <i1 true, i1 true>
+;
+  %cmp = icmp uge <2 x i8> %x, <i8 0, i8 0>
+  ret <2 x i1> %cmp
+}
+
+define <2 x i1> @sle_zero(<2 x i8> %x) {
+; CHECK-LABEL: @sle_zero(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp slt <2 x i8> [[X:%.*]], <i8 1, i8 1>
+; CHECK-NEXT:    ret <2 x i1> [[CMP]]
+;
+  %cmp = icmp sle <2 x i8> %x, <i8 0, i8 0>
+  ret <2 x i1> %cmp
+}
+
+define <2 x i1> @ule_zero(<2 x i8> %x) {
+; CHECK-LABEL: @ule_zero(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq <2 x i8> [[X:%.*]], zeroinitializer
+; CHECK-NEXT:    ret <2 x i1> [[CMP]]
+;
+  %cmp = icmp ule <2 x i8> %x, <i8 0, i8 0>
+  ret <2 x i1> %cmp
+}
+
+; Weird types are ConstantVectors, not ConstantDataVectors. For an i3 type:
+; Signed min = -4
+; Unsigned min = 0
+; Signed max = 3
+; Unsigned max = 7
+
+define <3 x i1> @sge_weird(<3 x i3> %x) {
+; CHECK-LABEL: @sge_weird(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt <3 x i3> [[X:%.*]], <i3 -4, i3 2, i3 -1>
+; CHECK-NEXT:    ret <3 x i1> [[CMP]]
+;
+  %cmp = icmp sge <3 x i3> %x, <i3 -3, i3 -5, i3 0>
+  ret <3 x i1> %cmp
+}
+
+define <3 x i1> @uge_weird(<3 x i3> %x) {
+; CHECK-LABEL: @uge_weird(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ugt <3 x i3> [[X:%.*]], <i3 -2, i3 0, i3 1>
+; CHECK-NEXT:    ret <3 x i1> [[CMP]]
+;
+  %cmp = icmp uge <3 x i3> %x, <i3 -1, i3 1, i3 2>
+  ret <3 x i1> %cmp
+}
+
+define <3 x i1> @sle_weird(<3 x i3> %x) {
+; CHECK-LABEL: @sle_weird(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp slt <3 x i3> [[X:%.*]], <i3 3, i3 -3, i3 1>
+; CHECK-NEXT:    ret <3 x i1> [[CMP]]
+;
+  %cmp = icmp sle <3 x i3> %x, <i3 2, i3 4, i3 0>
+  ret <3 x i1> %cmp
+}
+
+define <3 x i1> @ule_weird(<3 x i3> %x) {
+; CHECK-LABEL: @ule_weird(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ult <3 x i3> [[X:%.*]], <i3 -1, i3 1, i3 2>
+; CHECK-NEXT:    ret <3 x i1> [[CMP]]
+;
+  %cmp = icmp ule <3 x i3> %x, <i3 6, i3 0, i3 1>
+  ret <3 x i1> %cmp
+}
+
+; We can't do the transform if any constants are already at the limits.
+
+define <2 x i1> @sge_min(<2 x i3> %x) {
+; CHECK-LABEL: @sge_min(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp sge <2 x i3> [[X:%.*]], <i3 -4, i3 1>
+; CHECK-NEXT:    ret <2 x i1> [[CMP]]
+;
+  %cmp = icmp sge <2 x i3> %x, <i3 -4, i3 1>
+  ret <2 x i1> %cmp
+}
+
+define <2 x i1> @uge_min(<2 x i3> %x) {
+; CHECK-LABEL: @uge_min(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp uge <2 x i3> [[X:%.*]], <i3 1, i3 0>
+; CHECK-NEXT:    ret <2 x i1> [[CMP]]
+;
+  %cmp = icmp uge <2 x i3> %x, <i3 1, i3 0>
+  ret <2 x i1> %cmp
+}
+
+define <2 x i1> @sle_max(<2 x i3> %x) {
+; CHECK-LABEL: @sle_max(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp sle <2 x i3> [[X:%.*]], <i3 1, i3 3>
+; CHECK-NEXT:    ret <2 x i1> [[CMP]]
+;
+  %cmp = icmp sle <2 x i3> %x, <i3 1, i3 3>
+  ret <2 x i1> %cmp
+}
+
+define <2 x i1> @ule_max(<2 x i3> %x) {
+; CHECK-LABEL: @ule_max(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ule <2 x i3> [[X:%.*]], <i3 -1, i3 1>
+; CHECK-NEXT:    ret <2 x i1> [[CMP]]
+;
+  %cmp = icmp ule <2 x i3> %x, <i3 7, i3 1>
+  ret <2 x i1> %cmp
+}
+
+define <2 x i1> @PR27756_1(<2 x i8> %a) {
+; CHECK-LABEL: @PR27756_1(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp slt <2 x i8> [[A:%.*]], <i8 34, i8 1>
+; CHECK-NEXT:    ret <2 x i1> [[CMP]]
+;
+  %cmp = icmp sle <2 x i8> %a, <i8 bitcast (<2 x i4> <i4 1, i4 2> to i8), i8 0>
+  ret <2 x i1> %cmp
+}
+
+; Undef elements don't prevent the transform of the comparison.
+
+define <2 x i1> @PR27756_2(<2 x i8> %a) {
+; CHECK-LABEL: @PR27756_2(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp slt <2 x i8> [[A:%.*]], <i8 undef, i8 1>
+; CHECK-NEXT:    ret <2 x i1> [[CMP]]
+;
+  %cmp = icmp sle <2 x i8> %a, <i8 undef, i8 0>
+  ret <2 x i1> %cmp
+}
+
+ at someglobal = global i32 0
+
+define <2 x i1> @PR27786(<2 x i8> %a) {
+; CHECK-LABEL: @PR27786(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp sle <2 x i8> [[A:%.*]], bitcast (i16 ptrtoint (i32* @someglobal to i16) to <2 x i8>)
+; CHECK-NEXT:    ret <2 x i1> [[CMP]]
+;
+  %cmp = icmp sle <2 x i8> %a, bitcast (i16 ptrtoint (i32* @someglobal to i16) to <2 x i8>)
+  ret <2 x i1> %cmp
+}
+
+; This is similar to a transform for shuffled binops: compare first, shuffle after.
+
+define <4 x i1> @same_shuffle_inputs_icmp(<4 x i8> %x, <4 x i8> %y) {
+; CHECK-LABEL: @same_shuffle_inputs_icmp(
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp sgt <4 x i8> [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    [[CMP:%.*]] = shufflevector <4 x i1> [[TMP1]], <4 x i1> undef, <4 x i32> <i32 3, i32 3, i32 2, i32 0>
+; CHECK-NEXT:    ret <4 x i1> [[CMP]]
+;
+  %shufx = shufflevector <4 x i8> %x, <4 x i8> undef, <4 x i32> < i32 3, i32 3, i32 2, i32 0 >
+  %shufy = shufflevector <4 x i8> %y, <4 x i8> undef, <4 x i32> < i32 3, i32 3, i32 2, i32 0 >
+  %cmp = icmp sgt <4 x i8> %shufx, %shufy
+  ret <4 x i1> %cmp
+}
+
+; fcmp and size-changing shuffles are ok too.
+
+define <5 x i1> @same_shuffle_inputs_fcmp(<4 x float> %x, <4 x float> %y) {
+; CHECK-LABEL: @same_shuffle_inputs_fcmp(
+; CHECK-NEXT:    [[TMP1:%.*]] = fcmp oeq <4 x float> [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    [[CMP:%.*]] = shufflevector <4 x i1> [[TMP1]], <4 x i1> undef, <5 x i32> <i32 0, i32 1, i32 3, i32 2, i32 0>
+; CHECK-NEXT:    ret <5 x i1> [[CMP]]
+;
+  %shufx = shufflevector <4 x float> %x, <4 x float> undef, <5 x i32> < i32 0, i32 1, i32 3, i32 2, i32 0 >
+  %shufy = shufflevector <4 x float> %y, <4 x float> undef, <5 x i32> < i32 0, i32 1, i32 3, i32 2, i32 0 >
+  %cmp = fcmp oeq <5 x float> %shufx, %shufy
+  ret <5 x i1> %cmp
+}
+
+declare void @use_v4i8(<4 x i8>)
+
+define <4 x i1> @same_shuffle_inputs_icmp_extra_use1(<4 x i8> %x, <4 x i8> %y) {
+; CHECK-LABEL: @same_shuffle_inputs_icmp_extra_use1(
+; CHECK-NEXT:    [[SHUFX:%.*]] = shufflevector <4 x i8> [[X:%.*]], <4 x i8> undef, <4 x i32> <i32 3, i32 3, i32 3, i32 3>
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp ugt <4 x i8> [[X]], [[Y:%.*]]
+; CHECK-NEXT:    [[CMP:%.*]] = shufflevector <4 x i1> [[TMP1]], <4 x i1> undef, <4 x i32> <i32 3, i32 3, i32 3, i32 3>
+; CHECK-NEXT:    call void @use_v4i8(<4 x i8> [[SHUFX]])
+; CHECK-NEXT:    ret <4 x i1> [[CMP]]
+;
+  %shufx = shufflevector <4 x i8> %x, <4 x i8> undef, <4 x i32> < i32 3, i32 3, i32 3, i32 3 >
+  %shufy = shufflevector <4 x i8> %y, <4 x i8> undef, <4 x i32> < i32 3, i32 3, i32 3, i32 3 >
+  %cmp = icmp ugt <4 x i8> %shufx, %shufy
+  call void @use_v4i8(<4 x i8> %shufx)
+  ret <4 x i1> %cmp
+}
+
+declare void @use_v2i8(<2 x i8>)
+
+define <2 x i1> @same_shuffle_inputs_icmp_extra_use2(<4 x i8> %x, <4 x i8> %y) {
+; CHECK-LABEL: @same_shuffle_inputs_icmp_extra_use2(
+; CHECK-NEXT:    [[SHUFY:%.*]] = shufflevector <4 x i8> [[Y:%.*]], <4 x i8> undef, <2 x i32> <i32 3, i32 2>
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp eq <4 x i8> [[X:%.*]], [[Y]]
+; CHECK-NEXT:    [[CMP:%.*]] = shufflevector <4 x i1> [[TMP1]], <4 x i1> undef, <2 x i32> <i32 3, i32 2>
+; CHECK-NEXT:    call void @use_v2i8(<2 x i8> [[SHUFY]])
+; CHECK-NEXT:    ret <2 x i1> [[CMP]]
+;
+  %shufx = shufflevector <4 x i8> %x, <4 x i8> undef, <2 x i32> < i32 3, i32 2 >
+  %shufy = shufflevector <4 x i8> %y, <4 x i8> undef, <2 x i32> < i32 3, i32 2 >
+  %cmp = icmp eq <2 x i8> %shufx, %shufy
+  call void @use_v2i8(<2 x i8> %shufy)
+  ret <2 x i1> %cmp
+}
+
+; Negative test: if both shuffles have extra uses, don't transform because that would increase instruction count.
+
+define <2 x i1> @same_shuffle_inputs_icmp_extra_use3(<4 x i8> %x, <4 x i8> %y) {
+; CHECK-LABEL: @same_shuffle_inputs_icmp_extra_use3(
+; CHECK-NEXT:    [[SHUFX:%.*]] = shufflevector <4 x i8> [[X:%.*]], <4 x i8> undef, <2 x i32> zeroinitializer
+; CHECK-NEXT:    [[SHUFY:%.*]] = shufflevector <4 x i8> [[Y:%.*]], <4 x i8> undef, <2 x i32> zeroinitializer
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq <2 x i8> [[SHUFX]], [[SHUFY]]
+; CHECK-NEXT:    call void @use_v2i8(<2 x i8> [[SHUFX]])
+; CHECK-NEXT:    call void @use_v2i8(<2 x i8> [[SHUFY]])
+; CHECK-NEXT:    ret <2 x i1> [[CMP]]
+;
+  %shufx = shufflevector <4 x i8> %x, <4 x i8> undef, <2 x i32> < i32 0, i32 0 >
+  %shufy = shufflevector <4 x i8> %y, <4 x i8> undef, <2 x i32> < i32 0, i32 0 >
+  %cmp = icmp eq <2 x i8> %shufx, %shufy
+  call void @use_v2i8(<2 x i8> %shufx)
+  call void @use_v2i8(<2 x i8> %shufy)
+  ret <2 x i1> %cmp
+}
+

Added: llvm/trunk/test/Transforms/InstCombine/icmp-xor-signbit.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/icmp-xor-signbit.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/icmp-xor-signbit.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/icmp-xor-signbit.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,219 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt < %s -instcombine -S | FileCheck %s
+
+; icmp u/s (a ^ signmask), (b ^ signmask) --> icmp s/u a, b
+
+define i1 @slt_to_ult(i8 %x, i8 %y) {
+; CHECK-LABEL: @slt_to_ult(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i8 %x, %y
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %a = xor i8 %x, 128
+  %b = xor i8 %y, 128
+  %cmp = icmp slt i8 %a, %b
+  ret i1 %cmp
+}
+
+; PR33138 - https://bugs.llvm.org/show_bug.cgi?id=33138
+
+define <2 x i1> @slt_to_ult_splat(<2 x i8> %x, <2 x i8> %y) {
+; CHECK-LABEL: @slt_to_ult_splat(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ult <2 x i8> %x, %y
+; CHECK-NEXT:    ret <2 x i1> [[CMP]]
+;
+  %a = xor <2 x i8> %x, <i8 128, i8 128>
+  %b = xor <2 x i8> %y, <i8 128, i8 128>
+  %cmp = icmp slt <2 x i8> %a, %b
+  ret <2 x i1> %cmp
+}
+
+; Make sure that unsigned -> signed works too.
+
+define i1 @ult_to_slt(i8 %x, i8 %y) {
+; CHECK-LABEL: @ult_to_slt(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i8 %x, %y
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %a = xor i8 %x, 128
+  %b = xor i8 %y, 128
+  %cmp = icmp ult i8 %a, %b
+  ret i1 %cmp
+}
+
+define <2 x i1> @ult_to_slt_splat(<2 x i8> %x, <2 x i8> %y) {
+; CHECK-LABEL: @ult_to_slt_splat(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp slt <2 x i8> %x, %y
+; CHECK-NEXT:    ret <2 x i1> [[CMP]]
+;
+  %a = xor <2 x i8> %x, <i8 128, i8 128>
+  %b = xor <2 x i8> %y, <i8 128, i8 128>
+  %cmp = icmp ult <2 x i8> %a, %b
+  ret <2 x i1> %cmp
+}
+
+; icmp u/s (a ^ maxsignval), (b ^ maxsignval) --> icmp s/u' a, b
+
+define i1 @slt_to_ugt(i8 %x, i8 %y) {
+; CHECK-LABEL: @slt_to_ugt(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ugt i8 %x, %y
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %a = xor i8 %x, 127
+  %b = xor i8 %y, 127
+  %cmp = icmp slt i8 %a, %b
+  ret i1 %cmp
+}
+
+define <2 x i1> @slt_to_ugt_splat(<2 x i8> %x, <2 x i8> %y) {
+; CHECK-LABEL: @slt_to_ugt_splat(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ugt <2 x i8> %x, %y
+; CHECK-NEXT:    ret <2 x i1> [[CMP]]
+;
+  %a = xor <2 x i8> %x, <i8 127, i8 127>
+  %b = xor <2 x i8> %y, <i8 127, i8 127>
+  %cmp = icmp slt <2 x i8> %a, %b
+  ret <2 x i1> %cmp
+}
+
+; Make sure that unsigned -> signed works too.
+
+define i1 @ult_to_sgt(i8 %x, i8 %y) {
+; CHECK-LABEL: @ult_to_sgt(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt i8 %x, %y
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %a = xor i8 %x, 127
+  %b = xor i8 %y, 127
+  %cmp = icmp ult i8 %a, %b
+  ret i1 %cmp
+}
+
+define <2 x i1> @ult_to_sgt_splat(<2 x i8> %x, <2 x i8> %y) {
+; CHECK-LABEL: @ult_to_sgt_splat(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt <2 x i8> %x, %y
+; CHECK-NEXT:    ret <2 x i1> [[CMP]]
+;
+  %a = xor <2 x i8> %x, <i8 127, i8 127>
+  %b = xor <2 x i8> %y, <i8 127, i8 127>
+  %cmp = icmp ult <2 x i8> %a, %b
+  ret <2 x i1> %cmp
+}
+
+; icmp u/s (a ^ signmask), C --> icmp s/u a, C'
+
+define i1 @sge_to_ugt(i8 %x) {
+; CHECK-LABEL: @sge_to_ugt(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ugt i8 %x, -114
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %a = xor i8 %x, 128
+  %cmp = icmp sge i8 %a, 15
+  ret i1 %cmp
+}
+
+define <2 x i1> @sge_to_ugt_splat(<2 x i8> %x) {
+; CHECK-LABEL: @sge_to_ugt_splat(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ugt <2 x i8> %x, <i8 -114, i8 -114>
+; CHECK-NEXT:    ret <2 x i1> [[CMP]]
+;
+  %a = xor <2 x i8> %x, <i8 128, i8 128>
+  %cmp = icmp sge <2 x i8> %a, <i8 15, i8 15>
+  ret <2 x i1> %cmp
+}
+
+; Make sure that unsigned -> signed works too.
+
+define i1 @uge_to_sgt(i8 %x) {
+; CHECK-LABEL: @uge_to_sgt(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt i8 %x, -114
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %a = xor i8 %x, 128
+  %cmp = icmp uge i8 %a, 15
+  ret i1 %cmp
+}
+
+define <2 x i1> @uge_to_sgt_splat(<2 x i8> %x) {
+; CHECK-LABEL: @uge_to_sgt_splat(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt <2 x i8> %x, <i8 -114, i8 -114>
+; CHECK-NEXT:    ret <2 x i1> [[CMP]]
+;
+  %a = xor <2 x i8> %x, <i8 128, i8 128>
+  %cmp = icmp uge <2 x i8> %a, <i8 15, i8 15>
+  ret <2 x i1> %cmp
+}
+
+; icmp u/s (a ^ maxsignval), C --> icmp s/u' a, C'
+
+define i1 @sge_to_ult(i8 %x) {
+; CHECK-LABEL: @sge_to_ult(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i8 %x, 113
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %a = xor i8 %x, 127
+  %cmp = icmp sge i8 %a, 15
+  ret i1 %cmp
+}
+
+define <2 x i1> @sge_to_ult_splat(<2 x i8> %x) {
+; CHECK-LABEL: @sge_to_ult_splat(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ult <2 x i8> %x, <i8 113, i8 113>
+; CHECK-NEXT:    ret <2 x i1> [[CMP]]
+;
+  %a = xor <2 x i8> %x, <i8 127, i8 127>
+  %cmp = icmp sge <2 x i8> %a, <i8 15, i8 15>
+  ret <2 x i1> %cmp
+}
+
+; Make sure that unsigned -> signed works too.
+
+define i1 @uge_to_slt(i8 %x) {
+; CHECK-LABEL: @uge_to_slt(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i8 %x, 113
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %a = xor i8 %x, 127
+  %cmp = icmp uge i8 %a, 15
+  ret i1 %cmp
+}
+
+define <2 x i1> @uge_to_slt_splat(<2 x i8> %x) {
+; CHECK-LABEL: @uge_to_slt_splat(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp slt <2 x i8> %x, <i8 113, i8 113>
+; CHECK-NEXT:    ret <2 x i1> [[CMP]]
+;
+  %a = xor <2 x i8> %x, <i8 127, i8 127>
+  %cmp = icmp uge <2 x i8> %a, <i8 15, i8 15>
+  ret <2 x i1> %cmp
+}
+
+; PR33138, part 2: https://bugs.llvm.org/show_bug.cgi?id=33138
+; Bitcast canonicalization ensures that we recognize the signbit constant.
+
+define <8 x i1> @sgt_to_ugt_bitcasted_splat(<2 x i32> %x, <2 x i32> %y) {
+; CHECK-LABEL: @sgt_to_ugt_bitcasted_splat(
+; CHECK-NEXT:    [[TMP1:%.*]] = bitcast <2 x i32> %x to <8 x i8>
+; CHECK-NEXT:    [[TMP2:%.*]] = bitcast <2 x i32> %y to <8 x i8>
+; CHECK-NEXT:    [[E:%.*]] = icmp ugt <8 x i8> [[TMP1]], [[TMP2]]
+; CHECK-NEXT:    ret <8 x i1> [[E]]
+;
+  %a = xor <2 x i32> %x, <i32 2155905152, i32 2155905152> ; 0x80808080
+  %b = xor <2 x i32> %y, <i32 2155905152, i32 2155905152>
+  %c = bitcast <2 x i32> %a to <8 x i8>
+  %d = bitcast <2 x i32> %b to <8 x i8>
+  %e = icmp sgt <8 x i8> %c, %d
+  ret <8 x i1> %e
+}
+
+; Bitcast canonicalization ensures that we recognize the signbit constant.
+
+define <2 x i1> @negative_simplify_splat(<4 x i8> %x) {
+; CHECK-LABEL: @negative_simplify_splat(
+; CHECK-NEXT:    ret <2 x i1> zeroinitializer
+;
+  %a = or <4 x i8> %x, <i8 0, i8 128, i8 0, i8 128>
+  %b = bitcast <4 x i8> %a to <2 x i16>
+  %c = icmp sgt <2 x i16> %b, zeroinitializer
+  ret <2 x i1> %c
+}
+

Added: llvm/trunk/test/Transforms/InstCombine/icmp.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/icmp.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/icmp.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/icmp.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,3477 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt < %s -instcombine -S | FileCheck %s
+
+target datalayout = "e-p:64:64:64-p1:16:16:16-p2:32:32:32-p3: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"
+
+define i32 @test1(i32 %X) {
+; CHECK-LABEL: @test1(
+; CHECK-NEXT:    [[X_LOBIT:%.*]] = lshr i32 [[X:%.*]], 31
+; CHECK-NEXT:    ret i32 [[X_LOBIT]]
+;
+  %a = icmp slt i32 %X, 0
+  %b = zext i1 %a to i32
+  ret i32 %b
+}
+
+define <2 x i32> @test1vec(<2 x i32> %X) {
+; CHECK-LABEL: @test1vec(
+; CHECK-NEXT:    [[X_LOBIT:%.*]] = lshr <2 x i32> [[X:%.*]], <i32 31, i32 31>
+; CHECK-NEXT:    ret <2 x i32> [[X_LOBIT]]
+;
+  %a = icmp slt <2 x i32> %X, zeroinitializer
+  %b = zext <2 x i1> %a to <2 x i32>
+  ret <2 x i32> %b
+}
+
+define i32 @test2(i32 %X) {
+; CHECK-LABEL: @test2(
+; CHECK-NEXT:    [[X_LOBIT:%.*]] = lshr i32 [[X:%.*]], 31
+; CHECK-NEXT:    [[X_LOBIT_NOT:%.*]] = xor i32 [[X_LOBIT]], 1
+; CHECK-NEXT:    ret i32 [[X_LOBIT_NOT]]
+;
+  %a = icmp ult i32 %X, -2147483648
+  %b = zext i1 %a to i32
+  ret i32 %b
+}
+
+define <2 x i32> @test2vec(<2 x i32> %X) {
+; CHECK-LABEL: @test2vec(
+; CHECK-NEXT:    [[X_LOBIT:%.*]] = lshr <2 x i32> [[X:%.*]], <i32 31, i32 31>
+; CHECK-NEXT:    [[X_LOBIT_NOT:%.*]] = xor <2 x i32> [[X_LOBIT]], <i32 1, i32 1>
+; CHECK-NEXT:    ret <2 x i32> [[X_LOBIT_NOT]]
+;
+  %a = icmp ult <2 x i32> %X, <i32 -2147483648, i32 -2147483648>
+  %b = zext <2 x i1> %a to <2 x i32>
+  ret <2 x i32> %b
+}
+
+define i32 @test3(i32 %X) {
+; CHECK-LABEL: @test3(
+; CHECK-NEXT:    [[X_LOBIT:%.*]] = ashr i32 [[X:%.*]], 31
+; CHECK-NEXT:    ret i32 [[X_LOBIT]]
+;
+  %a = icmp slt i32 %X, 0
+  %b = sext i1 %a to i32
+  ret i32 %b
+}
+
+define i32 @test4(i32 %X) {
+; CHECK-LABEL: @test4(
+; CHECK-NEXT:    [[X_LOBIT:%.*]] = ashr i32 [[X:%.*]], 31
+; CHECK-NEXT:    [[X_LOBIT_NOT:%.*]] = xor i32 [[X_LOBIT]], -1
+; CHECK-NEXT:    ret i32 [[X_LOBIT_NOT]]
+;
+  %a = icmp ult i32 %X, -2147483648
+  %b = sext i1 %a to i32
+  ret i32 %b
+}
+
+; PR4837
+define <2 x i1> @test5_eq(<2 x i64> %x) {
+; CHECK-LABEL: @test5_eq(
+; CHECK-NEXT:    ret <2 x i1> undef
+;
+  %V = icmp eq <2 x i64> %x, undef
+  ret <2 x i1> %V
+}
+define <2 x i1> @test5_ne(<2 x i64> %x) {
+; CHECK-LABEL: @test5_ne(
+; CHECK-NEXT:    ret <2 x i1> undef
+;
+  %V = icmp ne <2 x i64> %x, undef
+  ret <2 x i1> %V
+}
+define <2 x i1> @test5_ugt(<2 x i64> %x) {
+; CHECK-LABEL: @test5_ugt(
+; CHECK-NEXT:    ret <2 x i1> zeroinitializer
+;
+  %V = icmp ugt <2 x i64> %x, undef
+  ret <2 x i1> %V
+}
+define <2 x i1> @test5_zero() {
+; CHECK-LABEL: @test5_zero(
+; CHECK-NEXT:    ret <2 x i1> undef
+;
+  %V = icmp eq <2 x i64> zeroinitializer, undef
+  ret <2 x i1> %V
+}
+
+define i32 @test6(i32 %a, i32 %b) {
+; CHECK-LABEL: @test6(
+; CHECK-NEXT:    [[E:%.*]] = ashr i32 [[A:%.*]], 31
+; CHECK-NEXT:    [[F:%.*]] = and i32 [[E]], [[B:%.*]]
+; CHECK-NEXT:    ret i32 [[F]]
+;
+  %c = icmp sle i32 %a, -1
+  %d = zext i1 %c to i32
+  %e = sub i32 0, %d
+  %f = and i32 %e, %b
+  ret i32 %f
+}
+
+
+define i1 @test7(i32 %x) {
+; CHECK-LABEL: @test7(
+; CHECK-NEXT:    [[B:%.*]] = icmp ne i32 [[X:%.*]], 0
+; CHECK-NEXT:    ret i1 [[B]]
+;
+  %a = add i32 %x, -1
+  %b = icmp ult i32 %a, %x
+  ret i1 %b
+}
+
+define <2 x i1> @test7_vec(<2 x i32> %x) {
+; CHECK-LABEL: @test7_vec(
+; CHECK-NEXT:    [[B:%.*]] = icmp ne <2 x i32> [[X:%.*]], zeroinitializer
+; CHECK-NEXT:    ret <2 x i1> [[B]]
+;
+  %a = add <2 x i32> %x, <i32 -1, i32 -1>
+  %b = icmp ult <2 x i32> %a, %x
+  ret <2 x i1> %b
+}
+
+define i1 @test8(i32 %x) {
+; CHECK-LABEL: @test8(
+; CHECK-NEXT:    ret i1 false
+;
+  %a = add i32 %x, -1
+  %b = icmp eq i32 %a, %x
+  ret i1 %b
+}
+
+define <2 x i1> @test8_vec(<2 x i32> %x) {
+; CHECK-LABEL: @test8_vec(
+; CHECK-NEXT:    ret <2 x i1> zeroinitializer
+;
+  %a = add <2 x i32> %x, <i32 -1, i32 -1>
+  %b = icmp eq <2 x i32> %a, %x
+  ret <2 x i1> %b
+}
+
+define i1 @test9(i32 %x) {
+; CHECK-LABEL: @test9(
+; CHECK-NEXT:    [[B:%.*]] = icmp ugt i32 [[X:%.*]], 1
+; CHECK-NEXT:    ret i1 [[B]]
+;
+  %a = add i32 %x, -2
+  %b = icmp ugt i32 %x, %a
+  ret i1 %b
+}
+
+define <2 x i1> @test9_vec(<2 x i32> %x) {
+; CHECK-LABEL: @test9_vec(
+; CHECK-NEXT:    [[B:%.*]] = icmp ugt <2 x i32> [[X:%.*]], <i32 1, i32 1>
+; CHECK-NEXT:    ret <2 x i1> [[B]]
+;
+  %a = add <2 x i32> %x, <i32 -2, i32 -2>
+  %b = icmp ugt <2 x i32> %x, %a
+  ret <2 x i1> %b
+}
+
+define i1 @test9b(i32 %x) {
+; CHECK-LABEL: @test9b(
+; CHECK-NEXT:    [[B:%.*]] = icmp ult i32 [[X:%.*]], 2
+; CHECK-NEXT:    ret i1 [[B]]
+;
+  %a = add i32 %x, -2
+  %b = icmp ugt i32 %a, %x
+  ret i1 %b
+}
+
+define <2 x i1> @test9b_vec(<2 x i32> %x) {
+; CHECK-LABEL: @test9b_vec(
+; CHECK-NEXT:    [[B:%.*]] = icmp ult <2 x i32> [[X:%.*]], <i32 2, i32 2>
+; CHECK-NEXT:    ret <2 x i1> [[B]]
+;
+  %a = add <2 x i32> %x, <i32 -2, i32 -2>
+  %b = icmp ugt <2 x i32> %a, %x
+  ret <2 x i1> %b
+}
+
+define i1 @test10(i32 %x) {
+; CHECK-LABEL: @test10(
+; CHECK-NEXT:    [[B:%.*]] = icmp ne i32 [[X:%.*]], -2147483648
+; CHECK-NEXT:    ret i1 [[B]]
+;
+  %a = add i32 %x, -1
+  %b = icmp slt i32 %a, %x
+  ret i1 %b
+}
+
+define <2 x i1> @test10_vec(<2 x i32> %x) {
+; CHECK-LABEL: @test10_vec(
+; CHECK-NEXT:    [[B:%.*]] = icmp ne <2 x i32> [[X:%.*]], <i32 -2147483648, i32 -2147483648>
+; CHECK-NEXT:    ret <2 x i1> [[B]]
+;
+  %a = add <2 x i32> %x, <i32 -1, i32 -1>
+  %b = icmp slt <2 x i32> %a, %x
+  ret <2 x i1> %b
+}
+
+define i1 @test10b(i32 %x) {
+; CHECK-LABEL: @test10b(
+; CHECK-NEXT:    [[B:%.*]] = icmp eq i32 [[X:%.*]], -2147483648
+; CHECK-NEXT:    ret i1 [[B]]
+;
+  %a = add i32 %x, -1
+  %b = icmp sgt i32 %a, %x
+  ret i1 %b
+}
+
+define <2 x i1> @test10b_vec(<2 x i32> %x) {
+; CHECK-LABEL: @test10b_vec(
+; CHECK-NEXT:    [[B:%.*]] = icmp eq <2 x i32> [[X:%.*]], <i32 -2147483648, i32 -2147483648>
+; CHECK-NEXT:    ret <2 x i1> [[B]]
+;
+  %a = add <2 x i32> %x, <i32 -1, i32 -1>
+  %b = icmp sgt <2 x i32> %a, %x
+  ret <2 x i1> %b
+}
+
+define i1 @test11(i32 %x) {
+; CHECK-LABEL: @test11(
+; CHECK-NEXT:    ret i1 true
+;
+  %a = add nsw i32 %x, 8
+  %b = icmp slt i32 %x, %a
+  ret i1 %b
+}
+
+define <2 x i1> @test11_vec(<2 x i32> %x) {
+; CHECK-LABEL: @test11_vec(
+; CHECK-NEXT:    ret <2 x i1> <i1 true, i1 true>
+;
+  %a = add nsw <2 x i32> %x, <i32 8, i32 8>
+  %b = icmp slt <2 x i32> %x, %a
+  ret <2 x i1> %b
+}
+
+; PR6195
+define i1 @test12(i1 %A) {
+; CHECK-LABEL: @test12(
+; CHECK-NEXT:    [[NOT_A:%.*]] = xor i1 [[A:%.*]], true
+; CHECK-NEXT:    ret i1 [[NOT_A]]
+;
+  %S = select i1 %A, i64 -4294967295, i64 8589934591
+  %B = icmp ne i64 bitcast (<2 x i32> <i32 1, i32 -1> to i64), %S
+  ret i1 %B
+}
+
+; PR6481
+define i1 @test13(i8 %X) {
+; CHECK-LABEL: @test13(
+; CHECK-NEXT:    ret i1 false
+;
+  %cmp = icmp slt i8 undef, %X
+  ret i1 %cmp
+}
+
+define i1 @test14(i8 %X) {
+; CHECK-LABEL: @test14(
+; CHECK-NEXT:    ret i1 false
+;
+  %cmp = icmp slt i8 undef, -128
+  ret i1 %cmp
+}
+
+define i1 @test15() {
+; CHECK-LABEL: @test15(
+; CHECK-NEXT:    ret i1 undef
+;
+  %cmp = icmp eq i8 undef, -128
+  ret i1 %cmp
+}
+
+define i1 @test16() {
+; CHECK-LABEL: @test16(
+; CHECK-NEXT:    ret i1 undef
+;
+  %cmp = icmp ne i8 undef, -128
+  ret i1 %cmp
+}
+
+define i1 @test17(i32 %x) {
+; CHECK-LABEL: @test17(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ne i32 [[X:%.*]], 3
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %shl = shl i32 1, %x
+  %and = and i32 %shl, 8
+  %cmp = icmp eq i32 %and, 0
+  ret i1 %cmp
+}
+
+define <2 x i1> @test17vec(<2 x i32> %x) {
+; CHECK-LABEL: @test17vec(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ne <2 x i32> [[X:%.*]], <i32 3, i32 3>
+; CHECK-NEXT:    ret <2 x i1> [[CMP]]
+;
+  %shl = shl <2 x i32> <i32 1, i32 1>, %x
+  %and = and <2 x i32> %shl, <i32 8, i32 8>
+  %cmp = icmp eq <2 x i32> %and, zeroinitializer
+  ret <2 x i1> %cmp
+}
+
+define i1 @test17a(i32 %x) {
+; CHECK-LABEL: @test17a(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ugt i32 [[X:%.*]], 2
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %shl = shl i32 1, %x
+  %and = and i32 %shl, 7
+  %cmp = icmp eq i32 %and, 0
+  ret i1 %cmp
+}
+
+define <2 x i1> @test17a_vec(<2 x i32> %x) {
+; CHECK-LABEL: @test17a_vec(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ugt <2 x i32> [[X:%.*]], <i32 2, i32 2>
+; CHECK-NEXT:    ret <2 x i1> [[CMP]]
+;
+  %shl = shl <2 x i32> <i32 1, i32 1>, %x
+  %and = and <2 x i32> %shl, <i32 7, i32 7>
+  %cmp = icmp eq <2 x i32> %and, zeroinitializer
+  ret <2 x i1> %cmp
+}
+
+define i1 @test18_eq(i32 %x) {
+; CHECK-LABEL: @test18_eq(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ne i32 [[X:%.*]], 3
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %sh = lshr i32 8, %x
+  %and = and i32 %sh, 1
+  %cmp = icmp eq i32 %and, 0
+  ret i1 %cmp
+}
+
+define <2 x i1> @test18_eq_vec(<2 x i32> %x) {
+; CHECK-LABEL: @test18_eq_vec(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ne <2 x i32> [[X:%.*]], <i32 3, i32 3>
+; CHECK-NEXT:    ret <2 x i1> [[CMP]]
+;
+  %sh = lshr <2 x i32> <i32 8, i32 8>, %x
+  %and = and <2 x i32> %sh, <i32 1, i32 1>
+  %cmp = icmp eq <2 x i32> %and, zeroinitializer
+  ret <2 x i1> %cmp
+}
+
+define i1 @test18_ne(i32 %x) {
+; CHECK-LABEL: @test18_ne(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[X:%.*]], 3
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %sh = lshr i32 8, %x
+  %and = and i32 %sh, 1
+  %cmp = icmp ne i32 %and, 0
+  ret i1 %cmp
+}
+
+define <2 x i1> @test18_ne_vec(<2 x i32> %x) {
+; CHECK-LABEL: @test18_ne_vec(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq <2 x i32> [[X:%.*]], <i32 3, i32 3>
+; CHECK-NEXT:    ret <2 x i1> [[CMP]]
+;
+  %sh = lshr <2 x i32> <i32 8, i32 8>, %x
+  %and = and <2 x i32> %sh, <i32 1, i32 1>
+  %cmp = icmp ne <2 x i32> %and, zeroinitializer
+  ret <2 x i1> %cmp
+}
+
+define i1 @test19(i32 %x) {
+; CHECK-LABEL: @test19(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[X:%.*]], 3
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %shl = shl i32 1, %x
+  %and = and i32 %shl, 8
+  %cmp = icmp eq i32 %and, 8
+  ret i1 %cmp
+}
+
+define <2 x i1> @test19vec(<2 x i32> %x) {
+; CHECK-LABEL: @test19vec(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq <2 x i32> [[X:%.*]], <i32 3, i32 3>
+; CHECK-NEXT:    ret <2 x i1> [[CMP]]
+;
+  %shl = shl <2 x i32> <i32 1, i32 1>, %x
+  %and = and <2 x i32> %shl, <i32 8, i32 8>
+  %cmp = icmp eq <2 x i32> %and, <i32 8, i32 8>
+  ret <2 x i1> %cmp
+}
+
+define <2 x i1> @cmp_and_signbit_vec(<2 x i3> %x) {
+; CHECK-LABEL: @cmp_and_signbit_vec(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp slt <2 x i3> [[X:%.*]], zeroinitializer
+; CHECK-NEXT:    ret <2 x i1> [[CMP]]
+;
+  %and = and <2 x i3> %x, <i3 4, i3 4>
+  %cmp = icmp ne <2 x i3> %and, zeroinitializer
+  ret <2 x i1> %cmp
+}
+
+define i1 @test20(i32 %x) {
+; CHECK-LABEL: @test20(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[X:%.*]], 3
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %shl = shl i32 1, %x
+  %and = and i32 %shl, 8
+  %cmp = icmp ne i32 %and, 0
+  ret i1 %cmp
+}
+
+define <2 x i1> @test20vec(<2 x i32> %x) {
+; CHECK-LABEL: @test20vec(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq <2 x i32> [[X:%.*]], <i32 3, i32 3>
+; CHECK-NEXT:    ret <2 x i1> [[CMP]]
+;
+  %shl = shl <2 x i32> <i32 1, i32 1>, %x
+  %and = and <2 x i32> %shl, <i32 8, i32 8>
+  %cmp = icmp ne <2 x i32> %and, zeroinitializer
+  ret <2 x i1> %cmp
+}
+
+define i1 @test20a(i32 %x) {
+; CHECK-LABEL: @test20a(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i32 [[X:%.*]], 3
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %shl = shl i32 1, %x
+  %and = and i32 %shl, 7
+  %cmp = icmp ne i32 %and, 0
+  ret i1 %cmp
+}
+
+define <2 x i1> @test20a_vec(<2 x i32> %x) {
+; CHECK-LABEL: @test20a_vec(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ult <2 x i32> [[X:%.*]], <i32 3, i32 3>
+; CHECK-NEXT:    ret <2 x i1> [[CMP]]
+;
+  %shl = shl <2 x i32> <i32 1, i32 1>, %x
+  %and = and <2 x i32> %shl, <i32 7, i32 7>
+  %cmp = icmp ne <2 x i32> %and, zeroinitializer
+  ret <2 x i1> %cmp
+}
+
+define i1 @test21(i8 %x, i8 %y) {
+; CHECK-LABEL: @test21(
+; CHECK-NEXT:    [[B:%.*]] = icmp ugt i8 [[X:%.*]], 3
+; CHECK-NEXT:    ret i1 [[B]]
+;
+  %A = or i8 %x, 1
+  %B = icmp ugt i8 %A, 3
+  ret i1 %B
+}
+
+define i1 @test22(i8 %x, i8 %y) {
+; CHECK-LABEL: @test22(
+; CHECK-NEXT:    [[B:%.*]] = icmp ult i8 [[X:%.*]], 4
+; CHECK-NEXT:    ret i1 [[B]]
+;
+  %A = or i8 %x, 1
+  %B = icmp ult i8 %A, 4
+  ret i1 %B
+}
+
+; PR2740
+define i1 @test23(i32 %x) {
+; CHECK-LABEL: @test23(
+; CHECK-NEXT:    [[I4:%.*]] = icmp sgt i32 [[X:%.*]], 1328634634
+; CHECK-NEXT:    ret i1 [[I4]]
+;
+  %i3 = sdiv i32 %x, -1328634635
+  %i4 = icmp eq i32 %i3, -1
+  ret i1 %i4
+}
+
+define <2 x i1> @test23vec(<2 x i32> %x) {
+; CHECK-LABEL: @test23vec(
+; CHECK-NEXT:    [[I4:%.*]] = icmp sgt <2 x i32> [[X:%.*]], <i32 1328634634, i32 1328634634>
+; CHECK-NEXT:    ret <2 x i1> [[I4]]
+;
+  %i3 = sdiv <2 x i32> %x, <i32 -1328634635, i32 -1328634635>
+  %i4 = icmp eq <2 x i32> %i3, <i32 -1, i32 -1>
+  ret <2 x i1> %i4
+}
+
+ at X = global [1000 x i32] zeroinitializer
+
+; PR8882
+define i1 @test24(i64 %i) {
+; CHECK-LABEL: @test24(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i64 [[I:%.*]], 1000
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %p1 = getelementptr inbounds i32, i32* getelementptr inbounds ([1000 x i32], [1000 x i32]* @X, i64 0, i64 0), i64 %i
+  %cmp = icmp eq i32* %p1, getelementptr inbounds ([1000 x i32], [1000 x i32]* @X, i64 1, i64 0)
+  ret i1 %cmp
+}
+
+ at X_as1 = addrspace(1) global [1000 x i32] zeroinitializer
+
+define i1 @test24_as1(i64 %i) {
+; CHECK-LABEL: @test24_as1(
+; CHECK-NEXT:    [[TMP1:%.*]] = trunc i64 [[I:%.*]] to i16
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i16 [[TMP1]], 1000
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %p1 = getelementptr inbounds i32, i32 addrspace(1)* getelementptr inbounds ([1000 x i32], [1000 x i32] addrspace(1)* @X_as1, i64 0, i64 0), i64 %i
+  %cmp = icmp eq i32 addrspace(1)* %p1, getelementptr inbounds ([1000 x i32], [1000 x i32] addrspace(1)* @X_as1, i64 1, i64 0)
+  ret i1 %cmp
+}
+
+define i1 @test25(i32 %x, i32 %y, i32 %z) {
+; CHECK-LABEL: @test25(
+; CHECK-NEXT:    [[C:%.*]] = icmp sgt i32 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %lhs = add nsw i32 %x, %z
+  %rhs = add nsw i32 %y, %z
+  %c = icmp sgt i32 %lhs, %rhs
+  ret i1 %c
+}
+
+; X + Z > Y + Z -> X > Y if there is no overflow.
+define i1 @test26(i32 %x, i32 %y, i32 %z) {
+; CHECK-LABEL: @test26(
+; CHECK-NEXT:    [[C:%.*]] = icmp ugt i32 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %lhs = add nuw i32 %x, %z
+  %rhs = add nuw i32 %y, %z
+  %c = icmp ugt i32 %lhs, %rhs
+  ret i1 %c
+}
+
+; X - Z > Y - Z -> X > Y if there is no overflow.
+define i1 @test27(i32 %x, i32 %y, i32 %z) {
+; CHECK-LABEL: @test27(
+; CHECK-NEXT:    [[C:%.*]] = icmp sgt i32 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %lhs = sub nsw i32 %x, %z
+  %rhs = sub nsw i32 %y, %z
+  %c = icmp sgt i32 %lhs, %rhs
+  ret i1 %c
+}
+
+; X - Z > Y - Z -> X > Y if there is no overflow.
+define i1 @test28(i32 %x, i32 %y, i32 %z) {
+; CHECK-LABEL: @test28(
+; CHECK-NEXT:    [[C:%.*]] = icmp ugt i32 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %lhs = sub nuw i32 %x, %z
+  %rhs = sub nuw i32 %y, %z
+  %c = icmp ugt i32 %lhs, %rhs
+  ret i1 %c
+}
+
+; X + Y > X -> Y > 0 if there is no overflow.
+define i1 @test29(i32 %x, i32 %y) {
+; CHECK-LABEL: @test29(
+; CHECK-NEXT:    [[C:%.*]] = icmp sgt i32 [[Y:%.*]], 0
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %lhs = add nsw i32 %x, %y
+  %c = icmp sgt i32 %lhs, %x
+  ret i1 %c
+}
+
+; X + Y > X -> Y > 0 if there is no overflow.
+define i1 @test30(i32 %x, i32 %y) {
+; CHECK-LABEL: @test30(
+; CHECK-NEXT:    [[C:%.*]] = icmp ne i32 [[Y:%.*]], 0
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %lhs = add nuw i32 %x, %y
+  %c = icmp ugt i32 %lhs, %x
+  ret i1 %c
+}
+
+; X > X + Y -> 0 > Y if there is no overflow.
+define i1 @test31(i32 %x, i32 %y) {
+; CHECK-LABEL: @test31(
+; CHECK-NEXT:    [[C:%.*]] = icmp slt i32 [[Y:%.*]], 0
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %rhs = add nsw i32 %x, %y
+  %c = icmp sgt i32 %x, %rhs
+  ret i1 %c
+}
+
+; X > X + Y -> 0 > Y if there is no overflow.
+define i1 @test32(i32 %x, i32 %y) {
+; CHECK-LABEL: @test32(
+; CHECK-NEXT:    ret i1 false
+;
+  %rhs = add nuw i32 %x, %y
+  %c = icmp ugt i32 %x, %rhs
+  ret i1 %c
+}
+
+; X - Y > X -> 0 > Y if there is no overflow.
+define i1 @test33(i32 %x, i32 %y) {
+; CHECK-LABEL: @test33(
+; CHECK-NEXT:    [[C:%.*]] = icmp slt i32 [[Y:%.*]], 0
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %lhs = sub nsw i32 %x, %y
+  %c = icmp sgt i32 %lhs, %x
+  ret i1 %c
+}
+
+; X - Y > X -> 0 > Y if there is no overflow.
+define i1 @test34(i32 %x, i32 %y) {
+; CHECK-LABEL: @test34(
+; CHECK-NEXT:    ret i1 false
+;
+  %lhs = sub nuw i32 %x, %y
+  %c = icmp ugt i32 %lhs, %x
+  ret i1 %c
+}
+
+; X > X - Y -> Y > 0 if there is no overflow.
+define i1 @test35(i32 %x, i32 %y) {
+; CHECK-LABEL: @test35(
+; CHECK-NEXT:    [[C:%.*]] = icmp sgt i32 [[Y:%.*]], 0
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %rhs = sub nsw i32 %x, %y
+  %c = icmp sgt i32 %x, %rhs
+  ret i1 %c
+}
+
+; X > X - Y -> Y > 0 if there is no overflow.
+define i1 @test36(i32 %x, i32 %y) {
+; CHECK-LABEL: @test36(
+; CHECK-NEXT:    [[C:%.*]] = icmp ne i32 [[Y:%.*]], 0
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %rhs = sub nuw i32 %x, %y
+  %c = icmp ugt i32 %x, %rhs
+  ret i1 %c
+}
+
+; PR36969 - https://bugs.llvm.org/show_bug.cgi?id=36969
+
+define i1 @ugt_sub(i32 %xsrc, i32 %y) {
+; CHECK-LABEL: @ugt_sub(
+; CHECK-NEXT:    [[X:%.*]] = udiv i32 [[XSRC:%.*]], 42
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i32 [[X]], [[Y:%.*]]
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %x = udiv i32 %xsrc, 42 ; thwart complexity-based canonicalization
+  %sub = sub i32 %x, %y
+  %cmp = icmp ugt i32 %sub, %x
+  ret i1 %cmp
+}
+
+; Swap operands and predicate. Try a vector type to verify that works too.
+
+define <2 x i1> @ult_sub(<2 x i8> %xsrc, <2 x i8> %y) {
+; CHECK-LABEL: @ult_sub(
+; CHECK-NEXT:    [[X:%.*]] = udiv <2 x i8> [[XSRC:%.*]], <i8 42, i8 -42>
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ult <2 x i8> [[X]], [[Y:%.*]]
+; CHECK-NEXT:    ret <2 x i1> [[CMP]]
+;
+  %x = udiv <2 x i8> %xsrc, <i8 42, i8 -42> ; thwart complexity-based canonicalization
+  %sub = sub <2 x i8> %x, %y
+  %cmp = icmp ult <2 x i8> %x, %sub
+  ret <2 x i1> %cmp
+}
+
+; X - Y > X - Z -> Z > Y if there is no overflow.
+define i1 @test37(i32 %x, i32 %y, i32 %z) {
+; CHECK-LABEL: @test37(
+; CHECK-NEXT:    [[C:%.*]] = icmp sgt i32 [[Z:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %lhs = sub nsw i32 %x, %y
+  %rhs = sub nsw i32 %x, %z
+  %c = icmp sgt i32 %lhs, %rhs
+  ret i1 %c
+}
+
+; X - Y > X - Z -> Z > Y if there is no overflow.
+define i1 @test38(i32 %x, i32 %y, i32 %z) {
+; CHECK-LABEL: @test38(
+; CHECK-NEXT:    [[C:%.*]] = icmp ugt i32 [[Z:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %lhs = sub nuw i32 %x, %y
+  %rhs = sub nuw i32 %x, %z
+  %c = icmp ugt i32 %lhs, %rhs
+  ret i1 %c
+}
+
+; PR9343 #1
+define i1 @test39(i32 %X, i32 %Y) {
+; CHECK-LABEL: @test39(
+; CHECK-NEXT:    [[B:%.*]] = icmp eq i32 [[X:%.*]], 0
+; CHECK-NEXT:    ret i1 [[B]]
+;
+  %A = ashr exact i32 %X, %Y
+  %B = icmp eq i32 %A, 0
+  ret i1 %B
+}
+
+define <2 x i1> @test39vec(<2 x i32> %X, <2 x i32> %Y) {
+; CHECK-LABEL: @test39vec(
+; CHECK-NEXT:    [[B:%.*]] = icmp eq <2 x i32> [[X:%.*]], zeroinitializer
+; CHECK-NEXT:    ret <2 x i1> [[B]]
+;
+  %A = ashr exact <2 x i32> %X, %Y
+  %B = icmp eq <2 x i32> %A, zeroinitializer
+  ret <2 x i1> %B
+}
+
+define i1 @test40(i32 %X, i32 %Y) {
+; CHECK-LABEL: @test40(
+; CHECK-NEXT:    [[B:%.*]] = icmp ne i32 [[X:%.*]], 0
+; CHECK-NEXT:    ret i1 [[B]]
+;
+  %A = lshr exact i32 %X, %Y
+  %B = icmp ne i32 %A, 0
+  ret i1 %B
+}
+
+define <2 x i1> @test40vec(<2 x i32> %X, <2 x i32> %Y) {
+; CHECK-LABEL: @test40vec(
+; CHECK-NEXT:    [[B:%.*]] = icmp ne <2 x i32> [[X:%.*]], zeroinitializer
+; CHECK-NEXT:    ret <2 x i1> [[B]]
+;
+  %A = lshr exact <2 x i32> %X, %Y
+  %B = icmp ne <2 x i32> %A, zeroinitializer
+  ret <2 x i1> %B
+}
+
+define i1 @shr_exact(i132 %x) {
+; CHECK-LABEL: @shr_exact(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i132 [[X:%.*]], 32
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %sh = ashr exact i132 %x, 4
+  %cmp = icmp eq i132 %sh, 2
+  ret i1 %cmp
+}
+
+define <2 x i1> @shr_exact_vec(<2 x i132> %x) {
+; CHECK-LABEL: @shr_exact_vec(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ne <2 x i132> [[X:%.*]], <i132 32, i132 32>
+; CHECK-NEXT:    ret <2 x i1> [[CMP]]
+;
+  %sh = lshr exact <2 x i132> %x, <i132 4, i132 4>
+  %cmp = icmp ne <2 x i132> %sh, <i132 2, i132 2>
+  ret <2 x i1> %cmp
+}
+
+; PR9343 #3
+define i1 @test41(i32 %X, i32 %Y) {
+; CHECK-LABEL: @test41(
+; CHECK-NEXT:    ret i1 true
+;
+  %A = urem i32 %X, %Y
+  %B = icmp ugt i32 %Y, %A
+  ret i1 %B
+}
+
+define i1 @test42(i32 %X, i32 %Y) {
+; CHECK-LABEL: @test42(
+; CHECK-NEXT:    [[B:%.*]] = icmp sgt i32 [[Y:%.*]], -1
+; CHECK-NEXT:    ret i1 [[B]]
+;
+  %A = srem i32 %X, %Y
+  %B = icmp slt i32 %A, %Y
+  ret i1 %B
+}
+
+define i1 @test43(i32 %X, i32 %Y) {
+; CHECK-LABEL: @test43(
+; CHECK-NEXT:    [[B:%.*]] = icmp slt i32 [[Y:%.*]], 0
+; CHECK-NEXT:    ret i1 [[B]]
+;
+  %A = srem i32 %X, %Y
+  %B = icmp slt i32 %Y, %A
+  ret i1 %B
+}
+
+define i1 @test44(i32 %X, i32 %Y) {
+; CHECK-LABEL: @test44(
+; CHECK-NEXT:    [[B:%.*]] = icmp sgt i32 [[Y:%.*]], -1
+; CHECK-NEXT:    ret i1 [[B]]
+;
+  %A = srem i32 %X, %Y
+  %B = icmp slt i32 %A, %Y
+  ret i1 %B
+}
+
+define i1 @test45(i32 %X, i32 %Y) {
+; CHECK-LABEL: @test45(
+; CHECK-NEXT:    [[B:%.*]] = icmp slt i32 [[Y:%.*]], 0
+; CHECK-NEXT:    ret i1 [[B]]
+;
+  %A = srem i32 %X, %Y
+  %B = icmp slt i32 %Y, %A
+  ret i1 %B
+}
+
+; PR9343 #4
+define i1 @test46(i32 %X, i32 %Y, i32 %Z) {
+; CHECK-LABEL: @test46(
+; CHECK-NEXT:    [[C:%.*]] = icmp ult i32 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %A = ashr exact i32 %X, %Z
+  %B = ashr exact i32 %Y, %Z
+  %C = icmp ult i32 %A, %B
+  ret i1 %C
+}
+
+; PR9343 #5
+define i1 @test47(i32 %X, i32 %Y, i32 %Z) {
+; CHECK-LABEL: @test47(
+; CHECK-NEXT:    [[C:%.*]] = icmp ugt i32 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %A = ashr exact i32 %X, %Z
+  %B = ashr exact i32 %Y, %Z
+  %C = icmp ugt i32 %A, %B
+  ret i1 %C
+}
+
+; PR9343 #8
+define i1 @test48(i32 %X, i32 %Y, i32 %Z) {
+; CHECK-LABEL: @test48(
+; CHECK-NEXT:    [[C:%.*]] = icmp eq i32 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %A = sdiv exact i32 %X, %Z
+  %B = sdiv exact i32 %Y, %Z
+  %C = icmp eq i32 %A, %B
+  ret i1 %C
+}
+
+; The above transform only works for equality predicates.
+
+define i1 @PR32949(i32 %X, i32 %Y, i32 %Z) {
+; CHECK-LABEL: @PR32949(
+; CHECK-NEXT:    [[A:%.*]] = sdiv exact i32 [[X:%.*]], [[Z:%.*]]
+; CHECK-NEXT:    [[B:%.*]] = sdiv exact i32 [[Y:%.*]], [[Z]]
+; CHECK-NEXT:    [[C:%.*]] = icmp sgt i32 [[A]], [[B]]
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %A = sdiv exact i32 %X, %Z
+  %B = sdiv exact i32 %Y, %Z
+  %C = icmp sgt i32 %A, %B
+  ret i1 %C
+}
+
+; PR8469
+define <2 x i1> @test49(<2 x i32> %tmp3) {
+; CHECK-LABEL: @test49(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    ret <2 x i1> <i1 true, i1 true>
+;
+entry:
+  %tmp11 = and <2 x i32> %tmp3, <i32 3, i32 3>
+  %cmp = icmp ult <2 x i32> %tmp11, <i32 4, i32 4>
+  ret <2 x i1> %cmp
+}
+
+; PR9343 #7
+define i1 @test50(i16 %X, i32 %Y) {
+; CHECK-LABEL: @test50(
+; CHECK-NEXT:    ret i1 true
+;
+  %A = zext i16 %X to i32
+  %B = srem i32 %A, %Y
+  %C = icmp sgt i32 %B, -1
+  ret i1 %C
+}
+
+define i1 @test51(i32 %X, i32 %Y) {
+; CHECK-LABEL: @test51(
+; CHECK-NEXT:    [[A:%.*]] = and i32 [[X:%.*]], -2147483648
+; CHECK-NEXT:    [[B:%.*]] = srem i32 [[A]], [[Y:%.*]]
+; CHECK-NEXT:    [[C:%.*]] = icmp sgt i32 [[B]], -1
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %A = and i32 %X, 2147483648
+  %B = srem i32 %A, %Y
+  %C = icmp sgt i32 %B, -1
+  ret i1 %C
+}
+
+define i1 @test52(i32 %x1) {
+; CHECK-LABEL: @test52(
+; CHECK-NEXT:    [[TMP1:%.*]] = and i32 [[X1:%.*]], 16711935
+; CHECK-NEXT:    [[TMP2:%.*]] = icmp eq i32 [[TMP1]], 4980863
+; CHECK-NEXT:    ret i1 [[TMP2]]
+;
+  %conv = and i32 %x1, 255
+  %cmp = icmp eq i32 %conv, 127
+  %tmp2 = lshr i32 %x1, 16
+  %tmp3 = trunc i32 %tmp2 to i8
+  %cmp15 = icmp eq i8 %tmp3, 76
+
+  %A = and i1 %cmp, %cmp15
+  ret i1 %A
+}
+
+define i1 @test52b(i128 %x1) {
+; CHECK-LABEL: @test52b(
+; CHECK-NEXT:    [[TMP1:%.*]] = and i128 [[X1:%.*]], 16711935
+; CHECK-NEXT:    [[TMP2:%.*]] = icmp eq i128 [[TMP1]], 4980863
+; CHECK-NEXT:    ret i1 [[TMP2]]
+;
+  %conv = and i128 %x1, 255
+  %cmp = icmp eq i128 %conv, 127
+  %tmp2 = lshr i128 %x1, 16
+  %tmp3 = trunc i128 %tmp2 to i8
+  %cmp15 = icmp eq i8 %tmp3, 76
+
+  %A = and i1 %cmp, %cmp15
+  ret i1 %A
+}
+
+; PR9838
+define i1 @test53(i32 %a, i32 %b) {
+; CHECK-LABEL: @test53(
+; CHECK-NEXT:    [[X:%.*]] = sdiv exact i32 [[A:%.*]], 30
+; CHECK-NEXT:    [[Y:%.*]] = sdiv i32 [[B:%.*]], 30
+; CHECK-NEXT:    [[Z:%.*]] = icmp eq i32 [[X]], [[Y]]
+; CHECK-NEXT:    ret i1 [[Z]]
+;
+  %x = sdiv exact i32 %a, 30
+  %y = sdiv i32 %b, 30
+  %z = icmp eq i32 %x, %y
+  ret i1 %z
+}
+
+define i1 @test54(i8 %a) {
+; CHECK-LABEL: @test54(
+; CHECK-NEXT:    [[TMP1:%.*]] = and i8 [[A:%.*]], -64
+; CHECK-NEXT:    [[RET:%.*]] = icmp eq i8 [[TMP1]], -128
+; CHECK-NEXT:    ret i1 [[RET]]
+;
+  %ext = zext i8 %a to i32
+  %and = and i32 %ext, 192
+  %ret = icmp eq i32 %and, 128
+  ret i1 %ret
+}
+
+define i1 @test55(i32 %a) {
+; CHECK-LABEL: @test55(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[A:%.*]], -123
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %sub = sub i32 0, %a
+  %cmp = icmp eq i32 %sub, 123
+  ret i1 %cmp
+}
+
+define <2 x i1> @test55vec(<2 x i32> %a) {
+; CHECK-LABEL: @test55vec(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq <2 x i32> [[A:%.*]], <i32 -123, i32 -123>
+; CHECK-NEXT:    ret <2 x i1> [[CMP]]
+;
+  %sub = sub <2 x i32> zeroinitializer, %a
+  %cmp = icmp eq <2 x i32> %sub, <i32 123, i32 123>
+  ret <2 x i1> %cmp
+}
+
+define i1 @test56(i32 %a) {
+; CHECK-LABEL: @test56(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[A:%.*]], -113
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %sub = sub i32 10, %a
+  %cmp = icmp eq i32 %sub, 123
+  ret i1 %cmp
+}
+
+define <2 x i1> @test56vec(<2 x i32> %a) {
+; CHECK-LABEL: @test56vec(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq <2 x i32> [[A:%.*]], <i32 -113, i32 -113>
+; CHECK-NEXT:    ret <2 x i1> [[CMP]]
+;
+  %sub = sub <2 x i32> <i32 10, i32 10>, %a
+  %cmp = icmp eq <2 x i32> %sub, <i32 123, i32 123>
+  ret <2 x i1> %cmp
+}
+
+; PR10267 Don't make icmps more expensive when no other inst is subsumed.
+declare void @foo(i32)
+define i1 @test57(i32 %a) {
+; CHECK-LABEL: @test57(
+; CHECK-NEXT:    [[AND:%.*]] = and i32 [[A:%.*]], -2
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ne i32 [[AND]], 0
+; CHECK-NEXT:    call void @foo(i32 [[AND]])
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %and = and i32 %a, -2
+  %cmp = icmp ne i32 %and, 0
+  call void @foo(i32 %and)
+  ret i1 %cmp
+}
+
+; rdar://problem/10482509
+define zeroext i1 @cmpabs1(i64 %val) {
+; CHECK-LABEL: @cmpabs1(
+; CHECK-NEXT:    [[TOBOOL:%.*]] = icmp ne i64 [[VAL:%.*]], 0
+; CHECK-NEXT:    ret i1 [[TOBOOL]]
+;
+  %sub = sub nsw i64 0, %val
+  %cmp = icmp slt i64 %val, 0
+  %sub.val = select i1 %cmp, i64 %sub, i64 %val
+  %tobool = icmp ne i64 %sub.val, 0
+  ret i1 %tobool
+}
+
+define zeroext i1 @cmpabs2(i64 %val) {
+; CHECK-LABEL: @cmpabs2(
+; CHECK-NEXT:    [[TOBOOL:%.*]] = icmp ne i64 [[VAL:%.*]], 0
+; CHECK-NEXT:    ret i1 [[TOBOOL]]
+;
+  %sub = sub nsw i64 0, %val
+  %cmp = icmp slt i64 %val, 0
+  %sub.val = select i1 %cmp, i64 %val, i64 %sub
+  %tobool = icmp ne i64 %sub.val, 0
+  ret i1 %tobool
+}
+
+define void @test58() {
+; CHECK-LABEL: @test58(
+; CHECK-NEXT:    [[CALL:%.*]] = call i32 @test58_d(i64 36029346783166592)
+; CHECK-NEXT:    ret void
+;
+  %cast = bitcast <1 x i64> <i64 36029346783166592> to i64
+  %call = call i32 @test58_d( i64 %cast)
+  ret void
+}
+declare i32 @test58_d(i64)
+
+define i1 @test59(i8* %foo) {
+; CHECK-LABEL: @test59(
+; CHECK-NEXT:    [[GEP1:%.*]] = getelementptr inbounds i8, i8* [[FOO:%.*]], i64 8
+; CHECK-NEXT:    [[USE:%.*]] = ptrtoint i8* [[GEP1]] to i64
+; CHECK-NEXT:    [[CALL:%.*]] = call i32 @test58_d(i64 [[USE]])
+; CHECK-NEXT:    ret i1 true
+;
+  %bit = bitcast i8* %foo to i32*
+  %gep1 = getelementptr inbounds i32, i32* %bit, i64 2
+  %gep2 = getelementptr inbounds i8, i8* %foo, i64 10
+  %cast1 = bitcast i32* %gep1 to i8*
+  %cmp = icmp ult i8* %cast1, %gep2
+  %use = ptrtoint i8* %cast1 to i64
+  %call = call i32 @test58_d(i64 %use)
+  ret i1 %cmp
+}
+
+define i1 @test59_as1(i8 addrspace(1)* %foo) {
+; CHECK-LABEL: @test59_as1(
+; CHECK-NEXT:    [[GEP1:%.*]] = getelementptr inbounds i8, i8 addrspace(1)* [[FOO:%.*]], i16 8
+; CHECK-NEXT:    [[TMP1:%.*]] = ptrtoint i8 addrspace(1)* [[GEP1]] to i16
+; CHECK-NEXT:    [[USE:%.*]] = zext i16 [[TMP1]] to i64
+; CHECK-NEXT:    [[CALL:%.*]] = call i32 @test58_d(i64 [[USE]])
+; CHECK-NEXT:    ret i1 true
+;
+  %bit = bitcast i8 addrspace(1)* %foo to i32 addrspace(1)*
+  %gep1 = getelementptr inbounds i32, i32 addrspace(1)* %bit, i64 2
+  %gep2 = getelementptr inbounds i8, i8 addrspace(1)* %foo, i64 10
+  %cast1 = bitcast i32 addrspace(1)* %gep1 to i8 addrspace(1)*
+  %cmp = icmp ult i8 addrspace(1)* %cast1, %gep2
+  %use = ptrtoint i8 addrspace(1)* %cast1 to i64
+  %call = call i32 @test58_d(i64 %use)
+  ret i1 %cmp
+}
+
+define i1 @test60(i8* %foo, i64 %i, i64 %j) {
+; CHECK-LABEL: @test60(
+; CHECK-NEXT:    [[GEP1_IDX:%.*]] = shl nuw i64 [[I:%.*]], 2
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp slt i64 [[GEP1_IDX]], [[J:%.*]]
+; CHECK-NEXT:    ret i1 [[TMP1]]
+;
+  %bit = bitcast i8* %foo to i32*
+  %gep1 = getelementptr inbounds i32, i32* %bit, i64 %i
+  %gep2 = getelementptr inbounds i8, i8* %foo, i64 %j
+  %cast1 = bitcast i32* %gep1 to i8*
+  %cmp = icmp ult i8* %cast1, %gep2
+  ret i1 %cmp
+}
+
+define i1 @test60_as1(i8 addrspace(1)* %foo, i64 %i, i64 %j) {
+; CHECK-LABEL: @test60_as1(
+; CHECK-NEXT:    [[TMP1:%.*]] = trunc i64 [[I:%.*]] to i16
+; CHECK-NEXT:    [[TMP2:%.*]] = trunc i64 [[J:%.*]] to i16
+; CHECK-NEXT:    [[GEP1_IDX:%.*]] = shl nuw i16 [[TMP1]], 2
+; CHECK-NEXT:    [[TMP3:%.*]] = icmp slt i16 [[GEP1_IDX]], [[TMP2]]
+; CHECK-NEXT:    ret i1 [[TMP3]]
+;
+  %bit = bitcast i8 addrspace(1)* %foo to i32 addrspace(1)*
+  %gep1 = getelementptr inbounds i32, i32 addrspace(1)* %bit, i64 %i
+  %gep2 = getelementptr inbounds i8, i8 addrspace(1)* %foo, i64 %j
+  %cast1 = bitcast i32 addrspace(1)* %gep1 to i8 addrspace(1)*
+  %cmp = icmp ult i8 addrspace(1)* %cast1, %gep2
+  ret i1 %cmp
+}
+
+; Same as test60, but look through an addrspacecast instead of a
+; bitcast. This uses the same sized addrspace.
+define i1 @test60_addrspacecast(i8* %foo, i64 %i, i64 %j) {
+; CHECK-LABEL: @test60_addrspacecast(
+; CHECK-NEXT:    [[GEP1_IDX:%.*]] = shl nuw i64 [[I:%.*]], 2
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp slt i64 [[GEP1_IDX]], [[J:%.*]]
+; CHECK-NEXT:    ret i1 [[TMP1]]
+;
+  %bit = addrspacecast i8* %foo to i32 addrspace(3)*
+  %gep1 = getelementptr inbounds i32, i32 addrspace(3)* %bit, i64 %i
+  %gep2 = getelementptr inbounds i8, i8* %foo, i64 %j
+  %cast1 = addrspacecast i32 addrspace(3)* %gep1 to i8*
+  %cmp = icmp ult i8* %cast1, %gep2
+  ret i1 %cmp
+}
+
+define i1 @test60_addrspacecast_smaller(i8* %foo, i16 %i, i64 %j) {
+; CHECK-LABEL: @test60_addrspacecast_smaller(
+; CHECK-NEXT:    [[GEP1_IDX:%.*]] = shl nuw i16 [[I:%.*]], 2
+; CHECK-NEXT:    [[TMP1:%.*]] = trunc i64 [[J:%.*]] to i16
+; CHECK-NEXT:    [[TMP2:%.*]] = icmp slt i16 [[GEP1_IDX]], [[TMP1]]
+; CHECK-NEXT:    ret i1 [[TMP2]]
+;
+  %bit = addrspacecast i8* %foo to i32 addrspace(1)*
+  %gep1 = getelementptr inbounds i32, i32 addrspace(1)* %bit, i16 %i
+  %gep2 = getelementptr inbounds i8, i8* %foo, i64 %j
+  %cast1 = addrspacecast i32 addrspace(1)* %gep1 to i8*
+  %cmp = icmp ult i8* %cast1, %gep2
+  ret i1 %cmp
+}
+
+define i1 @test60_addrspacecast_larger(i8 addrspace(1)* %foo, i32 %i, i16 %j) {
+; CHECK-LABEL: @test60_addrspacecast_larger(
+; CHECK-NEXT:    [[I_TR:%.*]] = trunc i32 [[I:%.*]] to i16
+; CHECK-NEXT:    [[TMP1:%.*]] = shl i16 [[I_TR]], 2
+; CHECK-NEXT:    [[TMP2:%.*]] = icmp slt i16 [[TMP1]], [[J:%.*]]
+; CHECK-NEXT:    ret i1 [[TMP2]]
+;
+  %bit = addrspacecast i8 addrspace(1)* %foo to i32 addrspace(2)*
+  %gep1 = getelementptr inbounds i32, i32 addrspace(2)* %bit, i32 %i
+  %gep2 = getelementptr inbounds i8, i8 addrspace(1)* %foo, i16 %j
+  %cast1 = addrspacecast i32 addrspace(2)* %gep1 to i8 addrspace(1)*
+  %cmp = icmp ult i8 addrspace(1)* %cast1, %gep2
+  ret i1 %cmp
+}
+
+define i1 @test61(i8* %foo, i64 %i, i64 %j) {
+; CHECK-LABEL: @test61(
+; CHECK-NEXT:    [[BIT:%.*]] = bitcast i8* [[FOO:%.*]] to i32*
+; CHECK-NEXT:    [[GEP1:%.*]] = getelementptr i32, i32* [[BIT]], i64 [[I:%.*]]
+; CHECK-NEXT:    [[GEP2:%.*]] = getelementptr i8, i8* [[FOO]], i64 [[J:%.*]]
+; CHECK-NEXT:    [[CAST1:%.*]] = bitcast i32* [[GEP1]] to i8*
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ugt i8* [[GEP2]], [[CAST1]]
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %bit = bitcast i8* %foo to i32*
+  %gep1 = getelementptr i32, i32* %bit, i64 %i
+  %gep2 = getelementptr  i8,  i8* %foo, i64 %j
+  %cast1 = bitcast i32* %gep1 to i8*
+  %cmp = icmp ult i8* %cast1, %gep2
+  ret i1 %cmp
+; Don't transform non-inbounds GEPs.
+}
+
+define i1 @test61_as1(i8 addrspace(1)* %foo, i16 %i, i16 %j) {
+; CHECK-LABEL: @test61_as1(
+; CHECK-NEXT:    [[BIT:%.*]] = bitcast i8 addrspace(1)* [[FOO:%.*]] to i32 addrspace(1)*
+; CHECK-NEXT:    [[GEP1:%.*]] = getelementptr i32, i32 addrspace(1)* [[BIT]], i16 [[I:%.*]]
+; CHECK-NEXT:    [[GEP2:%.*]] = getelementptr i8, i8 addrspace(1)* [[FOO]], i16 [[J:%.*]]
+; CHECK-NEXT:    [[CAST1:%.*]] = bitcast i32 addrspace(1)* [[GEP1]] to i8 addrspace(1)*
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ugt i8 addrspace(1)* [[GEP2]], [[CAST1]]
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %bit = bitcast i8 addrspace(1)* %foo to i32 addrspace(1)*
+  %gep1 = getelementptr i32, i32 addrspace(1)* %bit, i16 %i
+  %gep2 = getelementptr i8, i8 addrspace(1)* %foo, i16 %j
+  %cast1 = bitcast i32 addrspace(1)* %gep1 to i8 addrspace(1)*
+  %cmp = icmp ult i8 addrspace(1)* %cast1, %gep2
+  ret i1 %cmp
+; Don't transform non-inbounds GEPs.
+}
+
+define i1 @test62(i8* %a) {
+; CHECK-LABEL: @test62(
+; CHECK-NEXT:    ret i1 true
+;
+  %arrayidx1 = getelementptr inbounds i8, i8* %a, i64 1
+  %arrayidx2 = getelementptr inbounds i8, i8* %a, i64 10
+  %cmp = icmp slt i8* %arrayidx1, %arrayidx2
+  ret i1 %cmp
+}
+
+define i1 @test62_as1(i8 addrspace(1)* %a) {
+; CHECK-LABEL: @test62_as1(
+; CHECK-NEXT:    ret i1 true
+;
+  %arrayidx1 = getelementptr inbounds i8, i8 addrspace(1)* %a, i64 1
+  %arrayidx2 = getelementptr inbounds i8, i8 addrspace(1)* %a, i64 10
+  %cmp = icmp slt i8 addrspace(1)* %arrayidx1, %arrayidx2
+  ret i1 %cmp
+}
+
+define i1 @test63(i8 %a, i32 %b) {
+; CHECK-LABEL: @test63(
+; CHECK-NEXT:    [[TMP1:%.*]] = trunc i32 [[B:%.*]] to i8
+; CHECK-NEXT:    [[C:%.*]] = icmp eq i8 [[TMP1]], [[A:%.*]]
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %z = zext i8 %a to i32
+  %t = and i32 %b, 255
+  %c = icmp eq i32 %z, %t
+  ret i1 %c
+}
+
+define i1 @test64(i8 %a, i32 %b) {
+; CHECK-LABEL: @test64(
+; CHECK-NEXT:    [[TMP1:%.*]] = trunc i32 [[B:%.*]] to i8
+; CHECK-NEXT:    [[C:%.*]] = icmp eq i8 [[TMP1]], [[A:%.*]]
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %t = and i32 %b, 255
+  %z = zext i8 %a to i32
+  %c = icmp eq i32 %t, %z
+  ret i1 %c
+}
+
+define i1 @test65(i64 %A, i64 %B) {
+; CHECK-LABEL: @test65(
+; CHECK-NEXT:    ret i1 true
+;
+  %s1 = add i64 %A, %B
+  %s2 = add i64 %A, %B
+  %cmp = icmp eq i64 %s1, %s2
+  ret i1 %cmp
+}
+
+define i1 @test66(i64 %A, i64 %B) {
+; CHECK-LABEL: @test66(
+; CHECK-NEXT:    ret i1 true
+;
+  %s1 = add i64 %A, %B
+  %s2 = add i64 %B, %A
+  %cmp = icmp eq i64 %s1, %s2
+  ret i1 %cmp
+}
+
+define i1 @test67(i32 %x) {
+; CHECK-LABEL: @test67(
+; CHECK-NEXT:    [[AND:%.*]] = and i32 [[X:%.*]], 96
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ne i32 [[AND]], 0
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %and = and i32 %x, 127
+  %cmp = icmp sgt i32 %and, 31
+  ret i1 %cmp
+}
+
+define i1 @test67inverse(i32 %x) {
+; CHECK-LABEL: @test67inverse(
+; CHECK-NEXT:    [[AND:%.*]] = and i32 [[X:%.*]], 96
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[AND]], 0
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %and = and i32 %x, 127
+  %cmp = icmp sle i32 %and, 31
+  ret i1 %cmp
+}
+
+; The test above relies on 3 different folds.
+; This test only checks the last of those (icmp ugt -> icmp ne).
+
+define <2 x i1> @test67vec(<2 x i32> %x) {
+; CHECK-LABEL: @test67vec(
+; CHECK-NEXT:    [[AND:%.*]] = and <2 x i32> [[X:%.*]], <i32 96, i32 96>
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ne <2 x i32> [[AND]], zeroinitializer
+; CHECK-NEXT:    ret <2 x i1> [[CMP]]
+;
+  %and = and <2 x i32> %x, <i32 96, i32 96>
+  %cmp = icmp ugt <2 x i32> %and, <i32 31, i32 31>
+  ret <2 x i1> %cmp
+}
+
+define <2 x i1> @test67vec2(<2 x i32> %x) {
+; CHECK-LABEL: @test67vec2(
+; CHECK-NEXT:    [[AND:%.*]] = and <2 x i32> [[X:%.*]], <i32 96, i32 96>
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ne <2 x i32> [[AND]], zeroinitializer
+; CHECK-NEXT:    ret <2 x i1> [[CMP]]
+;
+  %and = and <2 x i32> %x, <i32 127, i32 127>
+  %cmp = icmp ugt <2 x i32> %and, <i32 31, i32 31>
+  ret <2 x i1> %cmp
+}
+
+define <2 x i1> @test67vecinverse(<2 x i32> %x) {
+; CHECK-LABEL: @test67vecinverse(
+; CHECK-NEXT:    [[AND:%.*]] = and <2 x i32> [[X:%.*]], <i32 96, i32 96>
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq <2 x i32> [[AND]], zeroinitializer
+; CHECK-NEXT:    ret <2 x i1> [[CMP]]
+;
+  %and = and <2 x i32> %x, <i32 96, i32 96>
+  %cmp = icmp sle <2 x i32> %and, <i32 31, i32 31>
+  ret <2 x i1> %cmp
+}
+
+define i1 @test68(i32 %x) {
+; CHECK-LABEL: @test68(
+; CHECK-NEXT:    [[AND:%.*]] = and i32 [[X:%.*]], 127
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ugt i32 [[AND]], 30
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %and = and i32 %x, 127
+  %cmp = icmp sgt i32 %and, 30
+  ret i1 %cmp
+}
+
+; PR15940
+define i1 @test70(i32 %X) {
+; CHECK-LABEL: @test70(
+; CHECK-NEXT:    [[A:%.*]] = srem i32 5, [[X:%.*]]
+; CHECK-NEXT:    [[C:%.*]] = icmp ne i32 [[A]], 2
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %A = srem i32 5, %X
+  %B = add i32 %A, 2
+  %C = icmp ne i32 %B, 4
+  ret i1 %C
+}
+
+define <2 x i1> @test70vec(<2 x i32> %X) {
+; CHECK-LABEL: @test70vec(
+; CHECK-NEXT:    [[C:%.*]] = icmp ne <2 x i32> [[X:%.*]], <i32 2, i32 2>
+; CHECK-NEXT:    ret <2 x i1> [[C]]
+;
+  %B = add <2 x i32> %X, <i32 2, i32 2>
+  %C = icmp ne <2 x i32> %B, <i32 4, i32 4>
+  ret <2 x i1> %C
+}
+
+define i1 @icmp_sext16trunc(i32 %x) {
+; CHECK-LABEL: @icmp_sext16trunc(
+; CHECK-NEXT:    [[TMP1:%.*]] = trunc i32 [[X:%.*]] to i16
+; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i16 [[TMP1]], 36
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %trunc = trunc i32 %x to i16
+  %sext = sext i16 %trunc to i32
+  %cmp = icmp slt i32 %sext, 36
+  ret i1 %cmp
+}
+
+define i1 @icmp_sext8trunc(i32 %x) {
+; CHECK-LABEL: @icmp_sext8trunc(
+; CHECK-NEXT:    [[TMP1:%.*]] = trunc i32 [[X:%.*]] to i8
+; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i8 [[TMP1]], 36
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %trunc = trunc i32 %x to i8
+  %sext = sext i8 %trunc to i32
+  %cmp = icmp slt i32 %sext, 36
+  ret i1 %cmp
+}
+
+; Vectors should fold the same way.
+define <2 x i1> @icmp_sext8trunc_vec(<2 x i32> %x) {
+; CHECK-LABEL: @icmp_sext8trunc_vec(
+; CHECK-NEXT:    [[TMP1:%.*]] = trunc <2 x i32> [[X:%.*]] to <2 x i8>
+; CHECK-NEXT:    [[CMP:%.*]] = icmp slt <2 x i8> [[TMP1]], <i8 36, i8 36>
+; CHECK-NEXT:    ret <2 x i1> [[CMP]]
+;
+  %trunc = trunc <2 x i32> %x to <2 x i8>
+  %sext = sext <2 x i8> %trunc to <2 x i32>
+  %cmp = icmp slt <2 x i32> %sext, <i32 36, i32 36>
+  ret <2 x i1> %cmp
+}
+
+define i1 @icmp_shl16(i32 %x) {
+; CHECK-LABEL: @icmp_shl16(
+; CHECK-NEXT:    [[TMP1:%.*]] = trunc i32 [[X:%.*]] to i16
+; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i16 [[TMP1]], 36
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %shl = shl i32 %x, 16
+  %cmp = icmp slt i32 %shl, 2359296
+  ret i1 %cmp
+}
+
+; D25952: Don't create illegal types like i15 in InstCombine
+
+define i1 @icmp_shl17(i32 %x) {
+; CHECK-LABEL: @icmp_shl17(
+; CHECK-NEXT:    [[SHL:%.*]] = shl i32 [[X:%.*]], 17
+; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i32 [[SHL]], 2359296
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %shl = shl i32 %x, 17
+  %cmp = icmp slt i32 %shl, 2359296
+  ret i1 %cmp
+}
+
+define <2 x i1> @icmp_shl16_vec(<2 x i32> %x) {
+; CHECK-LABEL: @icmp_shl16_vec(
+; CHECK-NEXT:    [[TMP1:%.*]] = trunc <2 x i32> [[X:%.*]] to <2 x i16>
+; CHECK-NEXT:    [[CMP:%.*]] = icmp slt <2 x i16> [[TMP1]], <i16 36, i16 36>
+; CHECK-NEXT:    ret <2 x i1> [[CMP]]
+;
+  %shl = shl <2 x i32> %x, <i32 16, i32 16>
+  %cmp = icmp slt <2 x i32> %shl, <i32 2359296, i32 2359296>
+  ret <2 x i1> %cmp
+}
+
+define i1 @icmp_shl24(i32 %x) {
+; CHECK-LABEL: @icmp_shl24(
+; CHECK-NEXT:    [[TMP1:%.*]] = trunc i32 [[X:%.*]] to i8
+; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i8 [[TMP1]], 36
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %shl = shl i32 %x, 24
+  %cmp = icmp slt i32 %shl, 603979776
+  ret i1 %cmp
+}
+
+define i1 @icmp_shl_eq(i32 %x) {
+; CHECK-LABEL: @icmp_shl_eq(
+; CHECK-NEXT:    [[MUL_MASK:%.*]] = and i32 [[X:%.*]], 134217727
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[MUL_MASK]], 0
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %mul = shl i32 %x, 5
+  %cmp = icmp eq i32 %mul, 0
+  ret i1 %cmp
+}
+
+define <2 x i1> @icmp_shl_eq_vec(<2 x i32> %x) {
+; CHECK-LABEL: @icmp_shl_eq_vec(
+; CHECK-NEXT:    [[MUL_MASK:%.*]] = and <2 x i32> [[X:%.*]], <i32 134217727, i32 134217727>
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq <2 x i32> [[MUL_MASK]], zeroinitializer
+; CHECK-NEXT:    ret <2 x i1> [[CMP]]
+;
+  %mul = shl <2 x i32> %x, <i32 5, i32 5>
+  %cmp = icmp eq <2 x i32> %mul, zeroinitializer
+  ret <2 x i1> %cmp
+}
+
+define i1 @icmp_shl_nsw_ne(i32 %x) {
+; CHECK-LABEL: @icmp_shl_nsw_ne(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ne i32 [[X:%.*]], 0
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %mul = shl nsw i32 %x, 7
+  %cmp = icmp ne i32 %mul, 0
+  ret i1 %cmp
+}
+
+define <2 x i1> @icmp_shl_nsw_ne_vec(<2 x i32> %x) {
+; CHECK-LABEL: @icmp_shl_nsw_ne_vec(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ne <2 x i32> [[X:%.*]], zeroinitializer
+; CHECK-NEXT:    ret <2 x i1> [[CMP]]
+;
+  %mul = shl nsw <2 x i32> %x, <i32 7, i32 7>
+  %cmp = icmp ne <2 x i32> %mul, zeroinitializer
+  ret <2 x i1> %cmp
+}
+
+define i1 @icmp_shl_ne(i32 %x) {
+; CHECK-LABEL: @icmp_shl_ne(
+; CHECK-NEXT:    [[MUL_MASK:%.*]] = and i32 [[X:%.*]], 33554431
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ne i32 [[MUL_MASK]], 0
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %mul = shl i32 %x, 7
+  %cmp = icmp ne i32 %mul, 0
+  ret i1 %cmp
+}
+
+define <2 x i1> @icmp_shl_ne_vec(<2 x i32> %x) {
+; CHECK-LABEL: @icmp_shl_ne_vec(
+; CHECK-NEXT:    [[MUL_MASK:%.*]] = and <2 x i32> [[X:%.*]], <i32 33554431, i32 33554431>
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ne <2 x i32> [[MUL_MASK]], zeroinitializer
+; CHECK-NEXT:    ret <2 x i1> [[CMP]]
+;
+  %mul = shl <2 x i32> %x, <i32 7, i32 7>
+  %cmp = icmp ne <2 x i32> %mul, zeroinitializer
+  ret <2 x i1> %cmp
+}
+
+define <2 x i1> @icmp_shl_nuw_ne_vec(<2 x i32> %x) {
+; CHECK-LABEL: @icmp_shl_nuw_ne_vec(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ne <2 x i32> [[X:%.*]], <i32 2, i32 2>
+; CHECK-NEXT:    ret <2 x i1> [[CMP]]
+;
+  %shl = shl nuw <2 x i32> %x, <i32 7, i32 7>
+  %cmp = icmp ne <2 x i32> %shl, <i32 256, i32 256>
+  ret <2 x i1> %cmp
+}
+
+; If the (mul x, C) preserved the sign and this is sign test,
+; compare the LHS operand instead
+define i1 @icmp_mul_nsw(i32 %x) {
+; CHECK-LABEL: @icmp_mul_nsw(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt i32 [[X:%.*]], 0
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %mul = mul nsw i32 %x, 12
+  %cmp = icmp sgt i32 %mul, 0
+  ret i1 %cmp
+}
+
+define i1 @icmp_mul_nsw1(i32 %x) {
+; CHECK-LABEL: @icmp_mul_nsw1(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i32 [[X:%.*]], 0
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %mul = mul nsw i32 %x, 12
+  %cmp = icmp sle i32 %mul, -1
+  ret i1 %cmp
+}
+
+define i1 @icmp_mul_nsw_neg(i32 %x) {
+; CHECK-LABEL: @icmp_mul_nsw_neg(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i32 [[X:%.*]], 1
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %mul = mul nsw i32 %x, -12
+  %cmp = icmp sge i32 %mul, 0
+  ret i1 %cmp
+}
+
+define i1 @icmp_mul_nsw_neg1(i32 %x) {
+; CHECK-LABEL: @icmp_mul_nsw_neg1(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i32 [[X:%.*]], 0
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %mul = mul nsw i32 %x, -12
+  %cmp = icmp sge i32 %mul, 1
+  ret i1 %cmp
+}
+
+define <2 x i1> @icmp_mul_nsw_neg1_vec(<2 x i32> %x) {
+; CHECK-LABEL: @icmp_mul_nsw_neg1_vec(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp slt <2 x i32> [[X:%.*]], zeroinitializer
+; CHECK-NEXT:    ret <2 x i1> [[CMP]]
+;
+  %mul = mul nsw <2 x i32> %x, <i32 -12, i32 -12>
+  %cmp = icmp sge <2 x i32> %mul, <i32 1, i32 1>
+  ret <2 x i1> %cmp
+}
+
+define i1 @icmp_mul_nsw_0(i32 %x) {
+; CHECK-LABEL: @icmp_mul_nsw_0(
+; CHECK-NEXT:    ret i1 false
+;
+  %mul = mul nsw i32 %x, 0
+  %cmp = icmp sgt i32 %mul, 0
+  ret i1 %cmp
+}
+
+define i1 @icmp_mul(i32 %x) {
+; CHECK-LABEL: @icmp_mul(
+; CHECK-NEXT:    [[MUL:%.*]] = mul i32 [[X:%.*]], -12
+; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt i32 [[MUL]], -1
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %mul = mul i32 %x, -12
+  %cmp = icmp sge i32 %mul, 0
+  ret i1 %cmp
+}
+
+; Checks for icmp (eq|ne) (mul x, C), 0
+define i1 @icmp_mul_neq0(i32 %x) {
+; CHECK-LABEL: @icmp_mul_neq0(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ne i32 [[X:%.*]], 0
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %mul = mul nsw i32 %x, -12
+  %cmp = icmp ne i32 %mul, 0
+  ret i1 %cmp
+}
+
+define <2 x i1> @icmp_mul_neq0_vec(<2 x i32> %x) {
+; CHECK-LABEL: @icmp_mul_neq0_vec(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ne <2 x i32> [[X:%.*]], zeroinitializer
+; CHECK-NEXT:    ret <2 x i1> [[CMP]]
+;
+  %mul = mul nsw <2 x i32> %x, <i32 -12, i32 -12>
+  %cmp = icmp ne <2 x i32> %mul, zeroinitializer
+  ret <2 x i1> %cmp
+}
+
+define i1 @icmp_mul_eq0(i32 %x) {
+; CHECK-LABEL: @icmp_mul_eq0(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[X:%.*]], 0
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %mul = mul nsw i32 %x, 12
+  %cmp = icmp eq i32 %mul, 0
+  ret i1 %cmp
+}
+
+define i1 @icmp_mul0_eq0(i32 %x) {
+; CHECK-LABEL: @icmp_mul0_eq0(
+; CHECK-NEXT:    ret i1 true
+;
+  %mul = mul i32 %x, 0
+  %cmp = icmp eq i32 %mul, 0
+  ret i1 %cmp
+}
+
+define i1 @icmp_mul0_ne0(i32 %x) {
+; CHECK-LABEL: @icmp_mul0_ne0(
+; CHECK-NEXT:    ret i1 false
+;
+  %mul = mul i32 %x, 0
+  %cmp = icmp ne i32 %mul, 0
+  ret i1 %cmp
+}
+
+define i1 @icmp_sub1_sge(i32 %x, i32 %y) {
+; CHECK-LABEL: @icmp_sub1_sge(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt i32 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %sub = add nsw i32 %x, -1
+  %cmp = icmp sge i32 %sub, %y
+  ret i1 %cmp
+}
+
+define i1 @icmp_add1_sgt(i32 %x, i32 %y) {
+; CHECK-LABEL: @icmp_add1_sgt(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp sge i32 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %add = add nsw i32 %x, 1
+  %cmp = icmp sgt i32 %add, %y
+  ret i1 %cmp
+}
+
+define i1 @icmp_sub1_slt(i32 %x, i32 %y) {
+; CHECK-LABEL: @icmp_sub1_slt(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp sle i32 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %sub = add nsw i32 %x, -1
+  %cmp = icmp slt i32 %sub, %y
+  ret i1 %cmp
+}
+
+define i1 @icmp_add1_sle(i32 %x, i32 %y) {
+; CHECK-LABEL: @icmp_add1_sle(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i32 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %add = add nsw i32 %x, 1
+  %cmp = icmp sle i32 %add, %y
+  ret i1 %cmp
+}
+
+define i1 @icmp_add20_sge_add57(i32 %x, i32 %y) {
+; CHECK-LABEL: @icmp_add20_sge_add57(
+; CHECK-NEXT:    [[TMP1:%.*]] = add nsw i32 [[Y:%.*]], 37
+; CHECK-NEXT:    [[CMP:%.*]] = icmp sle i32 [[TMP1]], [[X:%.*]]
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %1 = add nsw i32 %x, 20
+  %2 = add nsw i32 %y, 57
+  %cmp = icmp sge i32 %1, %2
+  ret i1 %cmp
+}
+
+define i1 @icmp_sub57_sge_sub20(i32 %x, i32 %y) {
+; CHECK-LABEL: @icmp_sub57_sge_sub20(
+; CHECK-NEXT:    [[TMP1:%.*]] = add nsw i32 [[X:%.*]], -37
+; CHECK-NEXT:    [[CMP:%.*]] = icmp sge i32 [[TMP1]], [[Y:%.*]]
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %1 = add nsw i32 %x, -57
+  %2 = add nsw i32 %y, -20
+  %cmp = icmp sge i32 %1, %2
+  ret i1 %cmp
+}
+
+define i1 @icmp_and_shl_neg_ne_0(i32 %A, i32 %B) {
+; CHECK-LABEL: @icmp_and_shl_neg_ne_0(
+; CHECK-NEXT:    [[SHL:%.*]] = shl i32 1, [[B:%.*]]
+; CHECK-NEXT:    [[TMP1:%.*]] = and i32 [[SHL]], [[A:%.*]]
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[TMP1]], 0
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %neg = xor i32 %A, -1
+  %shl = shl i32 1, %B
+  %and = and i32 %shl, %neg
+  %cmp = icmp ne i32 %and, 0
+  ret i1 %cmp
+}
+
+define i1 @icmp_and_shl_neg_eq_0(i32 %A, i32 %B) {
+; CHECK-LABEL: @icmp_and_shl_neg_eq_0(
+; CHECK-NEXT:    [[SHL:%.*]] = shl i32 1, [[B:%.*]]
+; CHECK-NEXT:    [[TMP1:%.*]] = and i32 [[SHL]], [[A:%.*]]
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ne i32 [[TMP1]], 0
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %neg = xor i32 %A, -1
+  %shl = shl i32 1, %B
+  %and = and i32 %shl, %neg
+  %cmp = icmp eq i32 %and, 0
+  ret i1 %cmp
+}
+
+define i1 @icmp_add_and_shr_ne_0(i32 %X) {
+; CHECK-LABEL: @icmp_add_and_shr_ne_0(
+; CHECK-NEXT:    [[AND:%.*]] = and i32 [[X:%.*]], 240
+; CHECK-NEXT:    [[TOBOOL:%.*]] = icmp ne i32 [[AND]], 224
+; CHECK-NEXT:    ret i1 [[TOBOOL]]
+;
+  %shr = lshr i32 %X, 4
+  %and = and i32 %shr, 15
+  %add = add i32 %and, -14
+  %tobool = icmp ne i32 %add, 0
+  ret i1 %tobool
+}
+
+define <2 x i1> @icmp_add_and_shr_ne_0_vec(<2 x i32> %X) {
+; CHECK-LABEL: @icmp_add_and_shr_ne_0_vec(
+; CHECK-NEXT:    [[AND:%.*]] = and <2 x i32> [[X:%.*]], <i32 240, i32 240>
+; CHECK-NEXT:    [[TOBOOL:%.*]] = icmp ne <2 x i32> [[AND]], <i32 224, i32 224>
+; CHECK-NEXT:    ret <2 x i1> [[TOBOOL]]
+;
+  %shr = lshr <2 x i32> %X, <i32 4, i32 4>
+  %and = and <2 x i32> %shr, <i32 15, i32 15>
+  %add = add <2 x i32> %and, <i32 -14, i32 -14>
+  %tobool = icmp ne <2 x i32> %add, zeroinitializer
+  ret <2 x i1> %tobool
+}
+
+; Variation of the above with an extra use of the shift
+define i1 @icmp_and_shr_multiuse(i32 %X) {
+; CHECK-LABEL: @icmp_and_shr_multiuse(
+; CHECK-NEXT:    [[AND:%.*]] = and i32 [[X:%.*]], 240
+; CHECK-NEXT:    [[AND2:%.*]] = and i32 [[X]], 496
+; CHECK-NEXT:    [[TOBOOL:%.*]] = icmp ne i32 [[AND]], 224
+; CHECK-NEXT:    [[TOBOOL2:%.*]] = icmp ne i32 [[AND2]], 432
+; CHECK-NEXT:    [[AND3:%.*]] = and i1 [[TOBOOL]], [[TOBOOL2]]
+; CHECK-NEXT:    ret i1 [[AND3]]
+;
+  %shr = lshr i32 %X, 4
+  %and = and i32 %shr, 15
+  %and2 = and i32 %shr, 31 ; second use of the shift
+  %tobool = icmp ne i32 %and, 14
+  %tobool2 = icmp ne i32 %and2, 27
+  %and3 = and i1 %tobool, %tobool2
+  ret i1 %and3
+}
+
+; Variation of the above with an ashr
+define i1 @icmp_and_ashr_multiuse(i32 %X) {
+; CHECK-LABEL: @icmp_and_ashr_multiuse(
+; CHECK-NEXT:    [[AND:%.*]] = and i32 [[X:%.*]], 240
+; CHECK-NEXT:    [[AND2:%.*]] = and i32 [[X]], 496
+; CHECK-NEXT:    [[TOBOOL:%.*]] = icmp ne i32 [[AND]], 224
+; CHECK-NEXT:    [[TOBOOL2:%.*]] = icmp ne i32 [[AND2]], 432
+; CHECK-NEXT:    [[AND3:%.*]] = and i1 [[TOBOOL]], [[TOBOOL2]]
+; CHECK-NEXT:    ret i1 [[AND3]]
+;
+  %shr = ashr i32 %X, 4
+  %and = and i32 %shr, 15
+  %and2 = and i32 %shr, 31 ; second use of the shift
+  %tobool = icmp ne i32 %and, 14
+  %tobool2 = icmp ne i32 %and2, 27
+  %and3 = and i1 %tobool, %tobool2
+  ret i1 %and3
+}
+
+define i1 @icmp_lshr_and_overshift(i8 %X) {
+; CHECK-LABEL: @icmp_lshr_and_overshift(
+; CHECK-NEXT:    [[TOBOOL:%.*]] = icmp ugt i8 [[X:%.*]], 31
+; CHECK-NEXT:    ret i1 [[TOBOOL]]
+;
+  %shr = lshr i8 %X, 5
+  %and = and i8 %shr, 15
+  %tobool = icmp ne i8 %and, 0
+  ret i1 %tobool
+}
+
+; We shouldn't simplify this because the and uses bits that are shifted in.
+define i1 @icmp_ashr_and_overshift(i8 %X) {
+; CHECK-LABEL: @icmp_ashr_and_overshift(
+; CHECK-NEXT:    [[SHR:%.*]] = ashr i8 [[X:%.*]], 5
+; CHECK-NEXT:    [[AND:%.*]] = and i8 [[SHR]], 15
+; CHECK-NEXT:    [[TOBOOL:%.*]] = icmp ne i8 [[AND]], 0
+; CHECK-NEXT:    ret i1 [[TOBOOL]]
+;
+  %shr = ashr i8 %X, 5
+  %and = and i8 %shr, 15
+  %tobool = icmp ne i8 %and, 0
+  ret i1 %tobool
+}
+
+; PR16244
+define i1 @test71(i8* %x) {
+; CHECK-LABEL: @test71(
+; CHECK-NEXT:    ret i1 false
+;
+  %a = getelementptr i8, i8* %x, i64 8
+  %b = getelementptr inbounds i8, i8* %x, i64 8
+  %c = icmp ugt i8* %a, %b
+  ret i1 %c
+}
+
+define i1 @test71_as1(i8 addrspace(1)* %x) {
+; CHECK-LABEL: @test71_as1(
+; CHECK-NEXT:    ret i1 false
+;
+  %a = getelementptr i8, i8 addrspace(1)* %x, i64 8
+  %b = getelementptr inbounds i8, i8 addrspace(1)* %x, i64 8
+  %c = icmp ugt i8 addrspace(1)* %a, %b
+  ret i1 %c
+}
+
+define i1 @icmp_shl_1_V_ult_32(i32 %V) {
+; CHECK-LABEL: @icmp_shl_1_V_ult_32(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i32 [[V:%.*]], 5
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %shl = shl i32 1, %V
+  %cmp = icmp ult i32 %shl, 32
+  ret i1 %cmp
+}
+
+define <2 x i1> @icmp_shl_1_V_ult_32_vec(<2 x i32> %V) {
+; CHECK-LABEL: @icmp_shl_1_V_ult_32_vec(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ult <2 x i32> [[V:%.*]], <i32 5, i32 5>
+; CHECK-NEXT:    ret <2 x i1> [[CMP]]
+;
+  %shl = shl <2 x i32> <i32 1, i32 1>, %V
+  %cmp = icmp ult <2 x i32> %shl, <i32 32, i32 32>
+  ret <2 x i1> %cmp
+}
+
+define i1 @icmp_shl_1_V_eq_32(i32 %V) {
+; CHECK-LABEL: @icmp_shl_1_V_eq_32(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[V:%.*]], 5
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %shl = shl i32 1, %V
+  %cmp = icmp eq i32 %shl, 32
+  ret i1 %cmp
+}
+
+define <2 x i1> @icmp_shl_1_V_eq_32_vec(<2 x i32> %V) {
+; CHECK-LABEL: @icmp_shl_1_V_eq_32_vec(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq <2 x i32> [[V:%.*]], <i32 5, i32 5>
+; CHECK-NEXT:    ret <2 x i1> [[CMP]]
+;
+  %shl = shl <2 x i32> <i32 1, i32 1>, %V
+  %cmp = icmp eq <2 x i32> %shl, <i32 32, i32 32>
+  ret <2 x i1> %cmp
+}
+
+define i1 @icmp_shl_1_V_ult_30(i32 %V) {
+; CHECK-LABEL: @icmp_shl_1_V_ult_30(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i32 [[V:%.*]], 5
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %shl = shl i32 1, %V
+  %cmp = icmp ult i32 %shl, 30
+  ret i1 %cmp
+}
+
+define <2 x i1> @icmp_shl_1_V_ult_30_vec(<2 x i32> %V) {
+; CHECK-LABEL: @icmp_shl_1_V_ult_30_vec(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ult <2 x i32> [[V:%.*]], <i32 5, i32 5>
+; CHECK-NEXT:    ret <2 x i1> [[CMP]]
+;
+  %shl = shl <2 x i32> <i32 1, i32 1>, %V
+  %cmp = icmp ult <2 x i32> %shl, <i32 30, i32 30>
+  ret <2 x i1> %cmp
+}
+
+define i1 @icmp_shl_1_V_ugt_30(i32 %V) {
+; CHECK-LABEL: @icmp_shl_1_V_ugt_30(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ugt i32 [[V:%.*]], 4
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %shl = shl i32 1, %V
+  %cmp = icmp ugt i32 %shl, 30
+  ret i1 %cmp
+}
+
+define <2 x i1> @icmp_shl_1_V_ugt_30_vec(<2 x i32> %V) {
+; CHECK-LABEL: @icmp_shl_1_V_ugt_30_vec(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ugt <2 x i32> [[V:%.*]], <i32 4, i32 4>
+; CHECK-NEXT:    ret <2 x i1> [[CMP]]
+;
+  %shl = shl <2 x i32> <i32 1, i32 1>, %V
+  %cmp = icmp ugt <2 x i32> %shl, <i32 30, i32 30>
+  ret <2 x i1> %cmp
+}
+
+define i1 @icmp_shl_1_V_ule_30(i32 %V) {
+; CHECK-LABEL: @icmp_shl_1_V_ule_30(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i32 [[V:%.*]], 5
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %shl = shl i32 1, %V
+  %cmp = icmp ule i32 %shl, 30
+  ret i1 %cmp
+}
+
+define <2 x i1> @icmp_shl_1_V_ule_30_vec(<2 x i32> %V) {
+; CHECK-LABEL: @icmp_shl_1_V_ule_30_vec(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ult <2 x i32> [[V:%.*]], <i32 5, i32 5>
+; CHECK-NEXT:    ret <2 x i1> [[CMP]]
+;
+  %shl = shl <2 x i32> <i32 1, i32 1>, %V
+  %cmp = icmp ule <2 x i32> %shl, <i32 30, i32 30>
+  ret <2 x i1> %cmp
+}
+
+define i1 @icmp_shl_1_V_uge_30(i32 %V) {
+; CHECK-LABEL: @icmp_shl_1_V_uge_30(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ugt i32 [[V:%.*]], 4
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %shl = shl i32 1, %V
+  %cmp = icmp uge i32 %shl, 30
+  ret i1 %cmp
+}
+
+define <2 x i1> @icmp_shl_1_V_uge_30_vec(<2 x i32> %V) {
+; CHECK-LABEL: @icmp_shl_1_V_uge_30_vec(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ugt <2 x i32> [[V:%.*]], <i32 4, i32 4>
+; CHECK-NEXT:    ret <2 x i1> [[CMP]]
+;
+  %shl = shl <2 x i32> <i32 1, i32 1>, %V
+  %cmp = icmp uge <2 x i32> %shl, <i32 30, i32 30>
+  ret <2 x i1> %cmp
+}
+
+define i1 @icmp_shl_1_V_uge_2147483648(i32 %V) {
+; CHECK-LABEL: @icmp_shl_1_V_uge_2147483648(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[V:%.*]], 31
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %shl = shl i32 1, %V
+  %cmp = icmp uge i32 %shl, 2147483648
+  ret i1 %cmp
+}
+
+define <2 x i1> @icmp_shl_1_V_uge_2147483648_vec(<2 x i32> %V) {
+; CHECK-LABEL: @icmp_shl_1_V_uge_2147483648_vec(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq <2 x i32> [[V:%.*]], <i32 31, i32 31>
+; CHECK-NEXT:    ret <2 x i1> [[CMP]]
+;
+  %shl = shl <2 x i32> <i32 1, i32 1>, %V
+  %cmp = icmp uge <2 x i32> %shl, <i32 2147483648, i32 2147483648>
+  ret <2 x i1> %cmp
+}
+
+define i1 @icmp_shl_1_V_ult_2147483648(i32 %V) {
+; CHECK-LABEL: @icmp_shl_1_V_ult_2147483648(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ne i32 [[V:%.*]], 31
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %shl = shl i32 1, %V
+  %cmp = icmp ult i32 %shl, 2147483648
+  ret i1 %cmp
+}
+
+define <2 x i1> @icmp_shl_1_V_ult_2147483648_vec(<2 x i32> %V) {
+; CHECK-LABEL: @icmp_shl_1_V_ult_2147483648_vec(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ne <2 x i32> [[V:%.*]], <i32 31, i32 31>
+; CHECK-NEXT:    ret <2 x i1> [[CMP]]
+;
+  %shl = shl <2 x i32> <i32 1, i32 1>, %V
+  %cmp = icmp ult <2 x i32> %shl, <i32 2147483648, i32 2147483648>
+  ret <2 x i1> %cmp
+}
+
+define i1 @or_icmp_eq_B_0_icmp_ult_A_B(i64 %a, i64 %b) {
+; CHECK-LABEL: @or_icmp_eq_B_0_icmp_ult_A_B(
+; CHECK-NEXT:    [[TMP1:%.*]] = add i64 [[B:%.*]], -1
+; CHECK-NEXT:    [[TMP2:%.*]] = icmp uge i64 [[TMP1]], [[A:%.*]]
+; CHECK-NEXT:    ret i1 [[TMP2]]
+;
+  %1 = icmp eq i64 %b, 0
+  %2 = icmp ult i64 %a, %b
+  %3 = or i1 %1, %2
+  ret i1 %3
+}
+
+define i1 @icmp_add_ult_2(i32 %X) {
+; CHECK-LABEL: @icmp_add_ult_2(
+; CHECK-NEXT:    [[TMP1:%.*]] = and i32 [[X:%.*]], -2
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[TMP1]], 14
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %add = add i32 %X, -14
+  %cmp = icmp ult i32 %add, 2
+  ret i1 %cmp
+}
+
+define <2 x i1> @icmp_add_X_-14_ult_2_vec(<2 x i32> %X) {
+; CHECK-LABEL: @icmp_add_X_-14_ult_2_vec(
+; CHECK-NEXT:    [[TMP1:%.*]] = and <2 x i32> [[X:%.*]], <i32 -2, i32 -2>
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq <2 x i32> [[TMP1]], <i32 14, i32 14>
+; CHECK-NEXT:    ret <2 x i1> [[CMP]]
+;
+  %add = add <2 x i32> %X, <i32 -14, i32 -14>
+  %cmp = icmp ult <2 x i32> %add, <i32 2, i32 2>
+  ret <2 x i1> %cmp
+}
+
+define i1 @icmp_sub_3_X_ult_2(i32 %X) {
+; CHECK-LABEL: @icmp_sub_3_X_ult_2(
+; CHECK-NEXT:    [[TMP1:%.*]] = or i32 [[X:%.*]], 1
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[TMP1]], 3
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %add = sub i32 3, %X
+  %cmp = icmp ult i32 %add, 2
+  ret i1 %cmp
+}
+
+define <2 x i1> @icmp_sub_3_X_ult_2_vec(<2 x i32> %X) {
+; CHECK-LABEL: @icmp_sub_3_X_ult_2_vec(
+; CHECK-NEXT:    [[TMP1:%.*]] = or <2 x i32> [[X:%.*]], <i32 1, i32 1>
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq <2 x i32> [[TMP1]], <i32 3, i32 3>
+; CHECK-NEXT:    ret <2 x i1> [[CMP]]
+;
+  %add = sub <2 x i32> <i32 3, i32 3>, %X
+  %cmp = icmp ult <2 x i32> %add, <i32 2, i32 2>
+  ret <2 x i1> %cmp
+}
+
+define i1 @icmp_add_X_-14_uge_2(i32 %X) {
+; CHECK-LABEL: @icmp_add_X_-14_uge_2(
+; CHECK-NEXT:    [[TMP1:%.*]] = and i32 [[X:%.*]], -2
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ne i32 [[TMP1]], 14
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %add = add i32 %X, -14
+  %cmp = icmp uge i32 %add, 2
+  ret i1 %cmp
+}
+
+define <2 x i1> @icmp_add_X_-14_uge_2_vec(<2 x i32> %X) {
+; CHECK-LABEL: @icmp_add_X_-14_uge_2_vec(
+; CHECK-NEXT:    [[TMP1:%.*]] = and <2 x i32> [[X:%.*]], <i32 -2, i32 -2>
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ne <2 x i32> [[TMP1]], <i32 14, i32 14>
+; CHECK-NEXT:    ret <2 x i1> [[CMP]]
+;
+  %add = add <2 x i32> %X, <i32 -14, i32 -14>
+  %cmp = icmp uge <2 x i32> %add, <i32 2, i32 2>
+  ret <2 x i1> %cmp
+}
+
+define i1 @icmp_sub_3_X_uge_2(i32 %X) {
+; CHECK-LABEL: @icmp_sub_3_X_uge_2(
+; CHECK-NEXT:    [[TMP1:%.*]] = or i32 [[X:%.*]], 1
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ne i32 [[TMP1]], 3
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %add = sub i32 3, %X
+  %cmp = icmp uge i32 %add, 2
+  ret i1 %cmp
+}
+
+define <2 x i1> @icmp_sub_3_X_uge_2_vec(<2 x i32> %X) {
+; CHECK-LABEL: @icmp_sub_3_X_uge_2_vec(
+; CHECK-NEXT:    [[TMP1:%.*]] = or <2 x i32> [[X:%.*]], <i32 1, i32 1>
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ne <2 x i32> [[TMP1]], <i32 3, i32 3>
+; CHECK-NEXT:    ret <2 x i1> [[CMP]]
+;
+  %add = sub <2 x i32> <i32 3, i32 3>, %X
+  %cmp = icmp uge <2 x i32> %add, <i32 2, i32 2>
+  ret <2 x i1> %cmp
+}
+
+define i1 @icmp_and_X_-16_eq-16(i32 %X) {
+; CHECK-LABEL: @icmp_and_X_-16_eq-16(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ugt i32 [[X:%.*]], -17
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %and = and i32 %X, -16
+  %cmp = icmp eq i32 %and, -16
+  ret i1 %cmp
+}
+
+define <2 x i1> @icmp_and_X_-16_eq-16_vec(<2 x i32> %X) {
+; CHECK-LABEL: @icmp_and_X_-16_eq-16_vec(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ugt <2 x i32> [[X:%.*]], <i32 -17, i32 -17>
+; CHECK-NEXT:    ret <2 x i1> [[CMP]]
+;
+  %and = and <2 x i32> %X, <i32 -16, i32 -16>
+  %cmp = icmp eq <2 x i32> %and, <i32 -16, i32 -16>
+  ret <2 x i1> %cmp
+}
+
+define i1 @icmp_and_X_-16_ne-16(i32 %X) {
+; CHECK-LABEL: @icmp_and_X_-16_ne-16(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i32 [[X:%.*]], -16
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %and = and i32 %X, -16
+  %cmp = icmp ne i32 %and, -16
+  ret i1 %cmp
+}
+
+define <2 x i1> @icmp_and_X_-16_ne-16_vec(<2 x i32> %X) {
+; CHECK-LABEL: @icmp_and_X_-16_ne-16_vec(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ult <2 x i32> [[X:%.*]], <i32 -16, i32 -16>
+; CHECK-NEXT:    ret <2 x i1> [[CMP]]
+;
+  %and = and <2 x i32> %X, <i32 -16, i32 -16>
+  %cmp = icmp ne <2 x i32> %and, <i32 -16, i32 -16>
+  ret <2 x i1> %cmp
+}
+
+; PR32524: https://bugs.llvm.org/show_bug.cgi?id=32524
+; X | C == C --> X <=u C (when C+1 is PowerOf2).
+
+define i1 @or1_eq1(i32 %x) {
+; CHECK-LABEL: @or1_eq1(
+; CHECK-NEXT:    [[T1:%.*]] = icmp ult i32 [[X:%.*]], 2
+; CHECK-NEXT:    ret i1 [[T1]]
+;
+  %t0 = or i32 %x, 1
+  %t1 = icmp eq i32 %t0, 1
+  ret i1 %t1
+}
+
+; X | C == C --> X <=u C (when C+1 is PowerOf2).
+
+define <2 x i1> @or3_eq3_vec(<2 x i8> %x) {
+; CHECK-LABEL: @or3_eq3_vec(
+; CHECK-NEXT:    [[T1:%.*]] = icmp ult <2 x i8> [[X:%.*]], <i8 4, i8 4>
+; CHECK-NEXT:    ret <2 x i1> [[T1]]
+;
+  %t0 = or <2 x i8> %x, <i8 3, i8 3>
+  %t1 = icmp eq <2 x i8> %t0, <i8 3, i8 3>
+  ret <2 x i1> %t1
+}
+
+; X | C != C --> X >u C (when C+1 is PowerOf2).
+
+define i1 @or7_ne7(i32 %x) {
+; CHECK-LABEL: @or7_ne7(
+; CHECK-NEXT:    [[T1:%.*]] = icmp ugt i32 [[X:%.*]], 7
+; CHECK-NEXT:    ret i1 [[T1]]
+;
+  %t0 = or i32 %x, 7
+  %t1 = icmp ne i32 %t0, 7
+  ret i1 %t1
+}
+
+; X | C != C --> X >u C (when C+1 is PowerOf2).
+
+define <2 x i1> @or63_ne63_vec(<2 x i8> %x) {
+; CHECK-LABEL: @or63_ne63_vec(
+; CHECK-NEXT:    [[T1:%.*]] = icmp ugt <2 x i8> [[X:%.*]], <i8 63, i8 63>
+; CHECK-NEXT:    ret <2 x i1> [[T1]]
+;
+  %t0 = or <2 x i8> %x, <i8 63, i8 63>
+  %t1 = icmp ne <2 x i8> %t0, <i8 63, i8 63>
+  ret <2 x i1> %t1
+}
+
+; PR40611: https://bugs.llvm.org/show_bug.cgi?id=40611
+; X | C == C --> (X & ~C) == 0
+
+define i1 @orC_eqC(i32 %x) {
+; CHECK-LABEL: @orC_eqC(
+; CHECK-NEXT:    [[TMP1:%.*]] = and i32 [[X:%.*]], -43
+; CHECK-NEXT:    [[T1:%.*]] = icmp eq i32 [[TMP1]], 0
+; CHECK-NEXT:    ret i1 [[T1]]
+;
+  %t0 = or i32 %x, 42
+  %t1 = icmp eq i32 %t0, 42
+  ret i1 %t1
+}
+
+; X | C == C --> (X & ~C) == 0
+
+define <2 x i1> @orC_eqC_vec(<2 x i8> %x) {
+; CHECK-LABEL: @orC_eqC_vec(
+; CHECK-NEXT:    [[TMP1:%.*]] = and <2 x i8> [[X:%.*]], <i8 -44, i8 -44>
+; CHECK-NEXT:    [[T1:%.*]] = icmp eq <2 x i8> [[TMP1]], zeroinitializer
+; CHECK-NEXT:    ret <2 x i1> [[T1]]
+;
+  %t0 = or <2 x i8> %x, <i8 43, i8 43>
+  %t1 = icmp eq <2 x i8> %t0, <i8 43, i8 43>
+  ret <2 x i1> %t1
+}
+
+; X | C != C --> (X & ~C) != 0
+
+define i1 @orC_neC(i32 %x) {
+; CHECK-LABEL: @orC_neC(
+; CHECK-NEXT:    [[TMP1:%.*]] = and i32 [[X:%.*]], 41
+; CHECK-NEXT:    [[T1:%.*]] = icmp ne i32 [[TMP1]], 0
+; CHECK-NEXT:    ret i1 [[T1]]
+;
+  %t0 = or i32 %x, -42
+  %t1 = icmp ne i32 %t0, -42
+  ret i1 %t1
+}
+
+; X | C != C --> (X & ~C) != 0
+
+define <2 x i1> @orC_neC_vec(<2 x i8> %x) {
+; CHECK-LABEL: @orC_neC_vec(
+; CHECK-NEXT:    [[TMP1:%.*]] = and <2 x i8> [[X:%.*]], <i8 42, i8 42>
+; CHECK-NEXT:    [[T1:%.*]] = icmp ne <2 x i8> [[TMP1]], zeroinitializer
+; CHECK-NEXT:    ret <2 x i1> [[T1]]
+;
+  %t0 = or <2 x i8> %x, <i8 -43, i8 -43>
+  %t1 = icmp ne <2 x i8> %t0, <i8 -43, i8 -43>
+  ret <2 x i1> %t1
+}
+
+define i1 @shrink_constant(i32 %X) {
+; CHECK-LABEL: @shrink_constant(
+; CHECK-NEXT:    [[XOR:%.*]] = xor i32 [[X:%.*]], -12
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i32 [[XOR]], 4
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %xor = xor i32 %X, -9
+  %cmp = icmp ult i32 %xor, 4
+  ret i1 %cmp
+}
+
+define <2 x i1> @shrink_constant_vec(<2 x i32> %X) {
+; CHECK-LABEL: @shrink_constant_vec(
+; CHECK-NEXT:    [[XOR:%.*]] = xor <2 x i32> [[X:%.*]], <i32 -12, i32 -12>
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ult <2 x i32> [[XOR]], <i32 4, i32 4>
+; CHECK-NEXT:    ret <2 x i1> [[CMP]]
+;
+  %xor = xor <2 x i32> %X, <i32 -9, i32 -9>
+  %cmp = icmp ult <2 x i32> %xor, <i32 4, i32 4>
+  ret <2 x i1> %cmp
+}
+
+; This test requires 3 different transforms to get to the result.
+define i1 @icmp_sub_-1_X_ult_4(i32 %X) {
+; CHECK-LABEL: @icmp_sub_-1_X_ult_4(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ugt i32 [[X:%.*]], -5
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %sub = sub i32 -1, %X
+  %cmp = icmp ult i32 %sub, 4
+  ret i1 %cmp
+}
+
+define <2 x i1> @icmp_xor_neg4_X_ult_4_vec(<2 x i32> %X) {
+; CHECK-LABEL: @icmp_xor_neg4_X_ult_4_vec(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ugt <2 x i32> [[X:%.*]], <i32 -5, i32 -5>
+; CHECK-NEXT:    ret <2 x i1> [[CMP]]
+;
+  %xor = xor <2 x i32> %X, <i32 -4, i32 -4>
+  %cmp = icmp ult <2 x i32> %xor, <i32 4, i32 4>
+  ret <2 x i1> %cmp
+}
+
+define i1 @icmp_sub_-1_X_uge_4(i32 %X) {
+; CHECK-LABEL: @icmp_sub_-1_X_uge_4(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i32 [[X:%.*]], -4
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %sub = sub i32 -1, %X
+  %cmp = icmp uge i32 %sub, 4
+  ret i1 %cmp
+}
+
+define <2 x i1> @icmp_xor_neg4_X_uge_4_vec(<2 x i32> %X) {
+; CHECK-LABEL: @icmp_xor_neg4_X_uge_4_vec(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ult <2 x i32> [[X:%.*]], <i32 -4, i32 -4>
+; CHECK-NEXT:    ret <2 x i1> [[CMP]]
+;
+  %xor = xor <2 x i32> %X, <i32 -4, i32 -4>
+  %cmp = icmp uge <2 x i32> %xor, <i32 4, i32 4>
+  ret <2 x i1> %cmp
+}
+
+define <2 x i1> @xor_ult(<2 x i8> %x) {
+; CHECK-LABEL: @xor_ult(
+; CHECK-NEXT:    [[R:%.*]] = icmp ugt <2 x i8> [[X:%.*]], <i8 3, i8 3>
+; CHECK-NEXT:    ret <2 x i1> [[R]]
+;
+  %xor = xor <2 x i8> %x, <i8 -4, i8 -4>
+  %r = icmp ult <2 x i8> %xor, <i8 -4, i8 -4>
+  ret <2 x i1> %r
+}
+
+define i1 @xor_ult_extra_use(i8 %x, i8* %p) {
+; CHECK-LABEL: @xor_ult_extra_use(
+; CHECK-NEXT:    [[XOR:%.*]] = xor i8 [[X:%.*]], -32
+; CHECK-NEXT:    store i8 [[XOR]], i8* [[P:%.*]], align 1
+; CHECK-NEXT:    [[R:%.*]] = icmp ugt i8 [[X]], 31
+; CHECK-NEXT:    ret i1 [[R]]
+;
+  %xor = xor i8 %x, -32
+  store i8 %xor, i8* %p
+  %r = icmp ult i8 %xor, -32
+  ret i1 %r
+}
+
+define <2 x i1> @xor_ugt(<2 x i8> %x) {
+; CHECK-LABEL: @xor_ugt(
+; CHECK-NEXT:    [[R:%.*]] = icmp ugt <2 x i8> [[X:%.*]], <i8 7, i8 7>
+; CHECK-NEXT:    ret <2 x i1> [[R]]
+;
+  %xor = xor <2 x i8> %x, <i8 7, i8 7>
+  %r = icmp ugt <2 x i8> %xor, <i8 7, i8 7>
+  ret <2 x i1> %r
+}
+
+define i1 @xor_ugt_extra_use(i8 %x, i8* %p) {
+; CHECK-LABEL: @xor_ugt_extra_use(
+; CHECK-NEXT:    [[XOR:%.*]] = xor i8 [[X:%.*]], 63
+; CHECK-NEXT:    store i8 [[XOR]], i8* [[P:%.*]], align 1
+; CHECK-NEXT:    [[R:%.*]] = icmp ugt i8 [[X]], 63
+; CHECK-NEXT:    ret i1 [[R]]
+;
+  %xor = xor i8 %x, 63
+  store i8 %xor, i8* %p
+  %r = icmp ugt i8 %xor, 63
+  ret i1 %r
+}
+
+define i1 @icmp_swap_operands_for_cse(i32 %X, i32 %Y) {
+; CHECK-LABEL: @icmp_swap_operands_for_cse(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[SUB:%.*]] = sub i32 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i32 [[X]], [[Y]]
+; CHECK-NEXT:    br i1 [[CMP]], label [[TRUE:%.*]], label [[FALSE:%.*]]
+; CHECK:       true:
+; CHECK-NEXT:    [[TMP0:%.*]] = and i32 [[SUB]], 1
+; CHECK-NEXT:    br label [[END:%.*]]
+; CHECK:       false:
+; CHECK-NEXT:    [[TMP1:%.*]] = and i32 [[SUB]], 16
+; CHECK-NEXT:    br label [[END]]
+; CHECK:       end:
+; CHECK-NEXT:    [[RES_IN:%.*]] = phi i32 [ [[TMP0]], [[TRUE]] ], [ [[TMP1]], [[FALSE]] ]
+; CHECK-NEXT:    [[RES:%.*]] = icmp ne i32 [[RES_IN]], 0
+; CHECK-NEXT:    ret i1 [[RES]]
+;
+entry:
+  %sub = sub i32 %X, %Y
+  %cmp = icmp ugt i32 %Y, %X
+  br i1 %cmp, label %true, label %false
+true:
+  %restrue = trunc i32 %sub to i1
+  br label %end
+false:
+  %shift = lshr i32 %sub, 4
+  %resfalse = trunc i32 %shift to i1
+  br label %end
+end:
+  %res = phi i1 [%restrue, %true], [%resfalse, %false]
+  ret i1 %res
+}
+
+define i1 @icmp_swap_operands_for_cse2(i32 %X, i32 %Y) {
+; CHECK-LABEL: @icmp_swap_operands_for_cse2(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i32 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    br i1 [[CMP]], label [[TRUE:%.*]], label [[FALSE:%.*]]
+; CHECK:       true:
+; CHECK-NEXT:    [[SUB:%.*]] = sub i32 [[X]], [[Y]]
+; CHECK-NEXT:    [[SUB1:%.*]] = sub i32 [[X]], [[Y]]
+; CHECK-NEXT:    [[ADD:%.*]] = add i32 [[SUB]], [[SUB1]]
+; CHECK-NEXT:    br label [[END:%.*]]
+; CHECK:       false:
+; CHECK-NEXT:    [[SUB2:%.*]] = sub i32 [[Y]], [[X]]
+; CHECK-NEXT:    br label [[END]]
+; CHECK:       end:
+; CHECK-NEXT:    [[RES_IN_IN:%.*]] = phi i32 [ [[ADD]], [[TRUE]] ], [ [[SUB2]], [[FALSE]] ]
+; CHECK-NEXT:    [[RES_IN:%.*]] = and i32 [[RES_IN_IN]], 1
+; CHECK-NEXT:    [[RES:%.*]] = icmp ne i32 [[RES_IN]], 0
+; CHECK-NEXT:    ret i1 [[RES]]
+;
+entry:
+  %cmp = icmp ugt i32 %Y, %X
+  br i1 %cmp, label %true, label %false
+true:
+  %sub = sub i32 %X, %Y
+  %sub1 = sub i32 %X, %Y
+  %add = add i32 %sub, %sub1
+  %restrue = trunc i32 %add to i1
+  br label %end
+false:
+  %sub2 = sub i32 %Y, %X
+  %resfalse = trunc i32 %sub2 to i1
+  br label %end
+end:
+  %res = phi i1 [%restrue, %true], [%resfalse, %false]
+  ret i1 %res
+}
+
+define i1 @icmp_do_not_swap_operands_for_cse(i32 %X, i32 %Y) {
+; CHECK-LABEL: @icmp_do_not_swap_operands_for_cse(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ugt i32 [[Y:%.*]], [[X:%.*]]
+; CHECK-NEXT:    br i1 [[CMP]], label [[TRUE:%.*]], label [[FALSE:%.*]]
+; CHECK:       true:
+; CHECK-NEXT:    [[SUB:%.*]] = sub i32 [[X]], [[Y]]
+; CHECK-NEXT:    br label [[END:%.*]]
+; CHECK:       false:
+; CHECK-NEXT:    [[SUB2:%.*]] = sub i32 [[Y]], [[X]]
+; CHECK-NEXT:    br label [[END]]
+; CHECK:       end:
+; CHECK-NEXT:    [[RES_IN_IN:%.*]] = phi i32 [ [[SUB]], [[TRUE]] ], [ [[SUB2]], [[FALSE]] ]
+; CHECK-NEXT:    [[RES_IN:%.*]] = and i32 [[RES_IN_IN]], 1
+; CHECK-NEXT:    [[RES:%.*]] = icmp ne i32 [[RES_IN]], 0
+; CHECK-NEXT:    ret i1 [[RES]]
+;
+entry:
+  %cmp = icmp ugt i32 %Y, %X
+  br i1 %cmp, label %true, label %false
+true:
+  %sub = sub i32 %X, %Y
+  %restrue = trunc i32 %sub to i1
+  br label %end
+false:
+  %sub2 = sub i32 %Y, %X
+  %resfalse = trunc i32 %sub2 to i1
+  br label %end
+end:
+  %res = phi i1 [%restrue, %true], [%resfalse, %false]
+  ret i1 %res
+}
+
+define i1 @icmp_lshr_lshr_eq(i32 %a, i32 %b) {
+; CHECK-LABEL: @icmp_lshr_lshr_eq(
+; CHECK-NEXT:    [[Z_UNSHIFTED:%.*]] = xor i32 [[A:%.*]], [[B:%.*]]
+; CHECK-NEXT:    [[Z:%.*]] = icmp ult i32 [[Z_UNSHIFTED]], 1073741824
+; CHECK-NEXT:    ret i1 [[Z]]
+;
+  %x = lshr i32 %a, 30
+  %y = lshr i32 %b, 30
+  %z = icmp eq i32 %x, %y
+  ret i1 %z
+}
+
+define i1 @icmp_ashr_ashr_ne(i32 %a, i32 %b) {
+; CHECK-LABEL: @icmp_ashr_ashr_ne(
+; CHECK-NEXT:    [[Z_UNSHIFTED:%.*]] = xor i32 [[A:%.*]], [[B:%.*]]
+; CHECK-NEXT:    [[Z:%.*]] = icmp ugt i32 [[Z_UNSHIFTED]], 255
+; CHECK-NEXT:    ret i1 [[Z]]
+;
+  %x = ashr i32 %a, 8
+  %y = ashr i32 %b, 8
+  %z = icmp ne i32 %x, %y
+  ret i1 %z
+}
+
+define i1 @icmp_neg_cst_slt(i32 %a) {
+; CHECK-LABEL: @icmp_neg_cst_slt(
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp sgt i32 [[A:%.*]], 10
+; CHECK-NEXT:    ret i1 [[TMP1]]
+;
+  %1 = sub nsw i32 0, %a
+  %2 = icmp slt i32 %1, -10
+  ret i1 %2
+}
+
+define i1 @icmp_and_or_lshr(i32 %x, i32 %y) {
+; CHECK-LABEL: @icmp_and_or_lshr(
+; CHECK-NEXT:    [[SHF1:%.*]] = shl nuw i32 1, [[Y:%.*]]
+; CHECK-NEXT:    [[OR2:%.*]] = or i32 [[SHF1]], 1
+; CHECK-NEXT:    [[AND3:%.*]] = and i32 [[OR2]], [[X:%.*]]
+; CHECK-NEXT:    [[RET:%.*]] = icmp ne i32 [[AND3]], 0
+; CHECK-NEXT:    ret i1 [[RET]]
+;
+  %shf = lshr i32 %x, %y
+  %or = or i32 %shf, %x
+  %and = and i32 %or, 1
+  %ret = icmp ne i32 %and, 0
+  ret i1 %ret
+}
+
+define <2 x i1> @icmp_and_or_lshr_vec(<2 x i32> %x, <2 x i32> %y) {
+; CHECK-LABEL: @icmp_and_or_lshr_vec(
+; CHECK-NEXT:    [[SHF:%.*]] = lshr <2 x i32> [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    [[OR:%.*]] = or <2 x i32> [[SHF]], [[X]]
+; CHECK-NEXT:    [[RET:%.*]] = trunc <2 x i32> [[OR]] to <2 x i1>
+; CHECK-NEXT:    ret <2 x i1> [[RET]]
+;
+  %shf = lshr <2 x i32> %x, %y
+  %or = or <2 x i32> %shf, %x
+  %and = and <2 x i32> %or, <i32 1, i32 1>
+  %ret = icmp ne <2 x i32> %and, zeroinitializer
+  ret <2 x i1> %ret
+}
+
+define <2 x i1> @icmp_and_or_lshr_vec_commute(<2 x i32> %xp, <2 x i32> %y) {
+; CHECK-LABEL: @icmp_and_or_lshr_vec_commute(
+; CHECK-NEXT:    [[X:%.*]] = srem <2 x i32> [[XP:%.*]], <i32 42, i32 42>
+; CHECK-NEXT:    [[SHF:%.*]] = lshr <2 x i32> [[X]], [[Y:%.*]]
+; CHECK-NEXT:    [[OR:%.*]] = or <2 x i32> [[X]], [[SHF]]
+; CHECK-NEXT:    [[RET:%.*]] = trunc <2 x i32> [[OR]] to <2 x i1>
+; CHECK-NEXT:    ret <2 x i1> [[RET]]
+;
+  %x = srem <2 x i32> %xp, <i32 42, i32 -42> ; prevent complexity-based canonicalization
+  %shf = lshr <2 x i32> %x, %y
+  %or = or <2 x i32> %x, %shf
+  %and = and <2 x i32> %or, <i32 1, i32 1>
+  %ret = icmp ne <2 x i32> %and, zeroinitializer
+  ret <2 x i1> %ret
+}
+
+define i1 @icmp_and_or_lshr_cst(i32 %x) {
+; CHECK-LABEL: @icmp_and_or_lshr_cst(
+; CHECK-NEXT:    [[AND1:%.*]] = and i32 [[X:%.*]], 3
+; CHECK-NEXT:    [[RET:%.*]] = icmp ne i32 [[AND1]], 0
+; CHECK-NEXT:    ret i1 [[RET]]
+;
+  %shf = lshr i32 %x, 1
+  %or = or i32 %shf, %x
+  %and = and i32 %or, 1
+  %ret = icmp ne i32 %and, 0
+  ret i1 %ret
+}
+
+define <2 x i1> @icmp_and_or_lshr_cst_vec(<2 x i32> %x) {
+; CHECK-LABEL: @icmp_and_or_lshr_cst_vec(
+; CHECK-NEXT:    [[TMP1:%.*]] = and <2 x i32> [[X:%.*]], <i32 3, i32 3>
+; CHECK-NEXT:    [[RET:%.*]] = icmp ne <2 x i32> [[TMP1]], zeroinitializer
+; CHECK-NEXT:    ret <2 x i1> [[RET]]
+;
+  %shf = lshr <2 x i32> %x, <i32 1, i32 1>
+  %or = or <2 x i32> %shf, %x
+  %and = and <2 x i32> %or, <i32 1, i32 1>
+  %ret = icmp ne <2 x i32> %and, zeroinitializer
+  ret <2 x i1> %ret
+}
+
+define <2 x i1> @icmp_and_or_lshr_cst_vec_commute(<2 x i32> %xp) {
+; CHECK-LABEL: @icmp_and_or_lshr_cst_vec_commute(
+; CHECK-NEXT:    [[X:%.*]] = srem <2 x i32> [[XP:%.*]], <i32 42, i32 42>
+; CHECK-NEXT:    [[TMP1:%.*]] = and <2 x i32> [[X]], <i32 3, i32 3>
+; CHECK-NEXT:    [[RET:%.*]] = icmp ne <2 x i32> [[TMP1]], zeroinitializer
+; CHECK-NEXT:    ret <2 x i1> [[RET]]
+;
+  %x = srem <2 x i32> %xp, <i32 42, i32 -42> ; prevent complexity-based canonicalization
+  %shf = lshr <2 x i32> %x, <i32 1, i32 1>
+  %or = or <2 x i32> %x, %shf
+  %and = and <2 x i32> %or, <i32 1, i32 1>
+  %ret = icmp ne <2 x i32> %and, zeroinitializer
+  ret <2 x i1> %ret
+}
+
+define i1 @shl_ap1_zero_ap2_non_zero_2(i32 %a) {
+; CHECK-LABEL: @shl_ap1_zero_ap2_non_zero_2(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ugt i32 [[A:%.*]], 29
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %shl = shl i32 4, %a
+  %cmp = icmp eq i32 %shl, 0
+  ret i1 %cmp
+}
+
+define <2 x i1> @shl_ap1_zero_ap2_non_zero_2_vec(<2 x i32> %a) {
+; CHECK-LABEL: @shl_ap1_zero_ap2_non_zero_2_vec(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ugt <2 x i32> [[A:%.*]], <i32 29, i32 29>
+; CHECK-NEXT:    ret <2 x i1> [[CMP]]
+;
+  %shl = shl <2 x i32> <i32 4, i32 4>, %a
+  %cmp = icmp eq <2 x i32> %shl, zeroinitializer
+  ret <2 x i1> %cmp
+}
+
+define i1 @shl_ap1_zero_ap2_non_zero_4(i32 %a) {
+; CHECK-LABEL: @shl_ap1_zero_ap2_non_zero_4(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ugt i32 [[A:%.*]], 30
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %shl = shl i32 -2, %a
+  %cmp = icmp eq i32 %shl, 0
+  ret i1 %cmp
+}
+
+define i1 @shl_ap1_non_zero_ap2_non_zero_both_positive(i32 %a) {
+; CHECK-LABEL: @shl_ap1_non_zero_ap2_non_zero_both_positive(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[A:%.*]], 0
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %shl = shl i32 50, %a
+  %cmp = icmp eq i32 %shl, 50
+  ret i1 %cmp
+}
+
+define i1 @shl_ap1_non_zero_ap2_non_zero_both_negative(i32 %a) {
+; CHECK-LABEL: @shl_ap1_non_zero_ap2_non_zero_both_negative(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[A:%.*]], 0
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %shl = shl i32 -50, %a
+  %cmp = icmp eq i32 %shl, -50
+  ret i1 %cmp
+}
+
+define i1 @shl_ap1_non_zero_ap2_non_zero_ap1_1(i32 %a) {
+; CHECK-LABEL: @shl_ap1_non_zero_ap2_non_zero_ap1_1(
+; CHECK-NEXT:    ret i1 false
+;
+  %shl = shl i32 50, %a
+  %cmp = icmp eq i32 %shl, 25
+  ret i1 %cmp
+}
+
+define i1 @shl_ap1_non_zero_ap2_non_zero_ap1_2(i32 %a) {
+; CHECK-LABEL: @shl_ap1_non_zero_ap2_non_zero_ap1_2(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[A:%.*]], 1
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %shl = shl i32 25, %a
+  %cmp = icmp eq i32 %shl, 50
+  ret i1 %cmp
+}
+
+define i1 @shl_ap1_non_zero_ap2_non_zero_ap1_3(i32 %a) {
+; CHECK-LABEL: @shl_ap1_non_zero_ap2_non_zero_ap1_3(
+; CHECK-NEXT:    ret i1 false
+;
+  %shl = shl i32 26, %a
+  %cmp = icmp eq i32 %shl, 50
+  ret i1 %cmp
+}
+
+define i1 @icmp_sgt_zero_add_nsw(i32 %a) {
+; CHECK-LABEL: @icmp_sgt_zero_add_nsw(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt i32 [[A:%.*]], -1
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %add = add nsw i32 %a, 1
+  %cmp = icmp sgt i32 %add, 0
+  ret i1 %cmp
+}
+
+define i1 @icmp_sge_zero_add_nsw(i32 %a) {
+; CHECK-LABEL: @icmp_sge_zero_add_nsw(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt i32 [[A:%.*]], -2
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %add = add nsw i32 %a, 1
+  %cmp = icmp sge i32 %add, 0
+  ret i1 %cmp
+}
+
+define i1 @icmp_sle_zero_add_nsw(i32 %a) {
+; CHECK-LABEL: @icmp_sle_zero_add_nsw(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i32 [[A:%.*]], 0
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %add = add nsw i32 %a, 1
+  %cmp = icmp sle i32 %add, 0
+  ret i1 %cmp
+}
+
+define zeroext i1 @icmp_cmpxchg_strong(i32* %sc, i32 %old_val, i32 %new_val) {
+; CHECK-LABEL: @icmp_cmpxchg_strong(
+; CHECK-NEXT:    [[XCHG:%.*]] = cmpxchg i32* [[SC:%.*]], i32 [[OLD_VAL:%.*]], i32 [[NEW_VAL:%.*]] seq_cst seq_cst
+; CHECK-NEXT:    [[ICMP:%.*]] = extractvalue { i32, i1 } [[XCHG]], 1
+; CHECK-NEXT:    ret i1 [[ICMP]]
+;
+  %xchg = cmpxchg i32* %sc, i32 %old_val, i32 %new_val seq_cst seq_cst
+  %xtrc = extractvalue { i32, i1 } %xchg, 0
+  %icmp = icmp eq i32 %xtrc, %old_val
+  ret i1 %icmp
+}
+
+define i1 @f1(i64 %a, i64 %b) {
+; CHECK-LABEL: @f1(
+; CHECK-NEXT:    [[V:%.*]] = icmp sge i64 [[A:%.*]], [[B:%.*]]
+; CHECK-NEXT:    ret i1 [[V]]
+;
+  %t = sub nsw i64 %a, %b
+  %v = icmp sge i64 %t, 0
+  ret i1 %v
+}
+
+define <2 x i1> @f1_vec(<2 x i64> %a, <2 x i64> %b) {
+; CHECK-LABEL: @f1_vec(
+; CHECK-NEXT:    [[V:%.*]] = icmp sge <2 x i64> [[A:%.*]], [[B:%.*]]
+; CHECK-NEXT:    ret <2 x i1> [[V]]
+;
+  %t = sub nsw <2 x i64> %a, %b
+  %v = icmp sgt <2 x i64> %t, <i64 -1, i64 -1>
+  ret <2 x i1> %v
+}
+
+define i1 @f2(i64 %a, i64 %b) {
+; CHECK-LABEL: @f2(
+; CHECK-NEXT:    [[V:%.*]] = icmp sgt i64 [[A:%.*]], [[B:%.*]]
+; CHECK-NEXT:    ret i1 [[V]]
+;
+  %t = sub nsw i64 %a, %b
+  %v = icmp sgt i64 %t, 0
+  ret i1 %v
+}
+
+define <2 x i1> @f2_vec(<2 x i64> %a, <2 x i64> %b) {
+; CHECK-LABEL: @f2_vec(
+; CHECK-NEXT:    [[V:%.*]] = icmp sgt <2 x i64> [[A:%.*]], [[B:%.*]]
+; CHECK-NEXT:    ret <2 x i1> [[V]]
+;
+  %t = sub nsw <2 x i64> %a, %b
+  %v = icmp sgt <2 x i64> %t, zeroinitializer
+  ret <2 x i1> %v
+}
+
+define i1 @f3(i64 %a, i64 %b) {
+; CHECK-LABEL: @f3(
+; CHECK-NEXT:    [[V:%.*]] = icmp slt i64 [[A:%.*]], [[B:%.*]]
+; CHECK-NEXT:    ret i1 [[V]]
+;
+  %t = sub nsw i64 %a, %b
+  %v = icmp slt i64 %t, 0
+  ret i1 %v
+}
+
+define <2 x i1> @f3_vec(<2 x i64> %a, <2 x i64> %b) {
+; CHECK-LABEL: @f3_vec(
+; CHECK-NEXT:    [[V:%.*]] = icmp slt <2 x i64> [[A:%.*]], [[B:%.*]]
+; CHECK-NEXT:    ret <2 x i1> [[V]]
+;
+  %t = sub nsw <2 x i64> %a, %b
+  %v = icmp slt <2 x i64> %t, zeroinitializer
+  ret <2 x i1> %v
+}
+
+define i1 @f4(i64 %a, i64 %b) {
+; CHECK-LABEL: @f4(
+; CHECK-NEXT:    [[V:%.*]] = icmp sle i64 [[A:%.*]], [[B:%.*]]
+; CHECK-NEXT:    ret i1 [[V]]
+;
+  %t = sub nsw i64 %a, %b
+  %v = icmp sle i64 %t, 0
+  ret i1 %v
+}
+
+define <2 x i1> @f4_vec(<2 x i64> %a, <2 x i64> %b) {
+; CHECK-LABEL: @f4_vec(
+; CHECK-NEXT:    [[V:%.*]] = icmp sle <2 x i64> [[A:%.*]], [[B:%.*]]
+; CHECK-NEXT:    ret <2 x i1> [[V]]
+;
+  %t = sub nsw <2 x i64> %a, %b
+  %v = icmp slt <2 x i64> %t, <i64 1, i64 1>
+  ret <2 x i1> %v
+}
+
+define i32 @f5(i8 %a, i8 %b) {
+; CHECK-LABEL: @f5(
+; CHECK-NEXT:    [[CONV:%.*]] = zext i8 [[A:%.*]] to i32
+; CHECK-NEXT:    [[CONV3:%.*]] = zext i8 [[B:%.*]] to i32
+; CHECK-NEXT:    [[SUB:%.*]] = sub nsw i32 [[CONV]], [[CONV3]]
+; CHECK-NEXT:    [[CMP4:%.*]] = icmp slt i32 [[SUB]], 0
+; CHECK-NEXT:    [[SUB7:%.*]] = sub nsw i32 0, [[SUB]]
+; CHECK-NEXT:    [[SUB7_SUB:%.*]] = select i1 [[CMP4]], i32 [[SUB7]], i32 [[SUB]]
+; CHECK-NEXT:    ret i32 [[SUB7_SUB]]
+;
+  %conv = zext i8 %a to i32
+  %conv3 = zext i8 %b to i32
+  %sub = sub nsw i32 %conv, %conv3
+  %cmp4 = icmp slt i32 %sub, 0
+  %sub7 = sub nsw i32 0, %sub
+  %sub7.sub = select i1 %cmp4, i32 %sub7, i32 %sub
+  ret i32 %sub7.sub
+}
+
+define i32 @f6(i32 %a, i32 %b) {
+; CHECK-LABEL: @f6(
+; CHECK-NEXT:    [[CMP_UNSHIFTED:%.*]] = xor i32 [[A:%.*]], [[B:%.*]]
+; CHECK-NEXT:    [[CMP_MASK:%.*]] = and i32 [[CMP_UNSHIFTED]], 255
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[CMP_MASK]], 0
+; CHECK-NEXT:    [[S:%.*]] = select i1 [[CMP]], i32 10000, i32 0
+; CHECK-NEXT:    ret i32 [[S]]
+;
+  %sext = shl i32 %a, 24
+  %conv = ashr i32 %sext, 24
+  %sext6 = shl i32 %b, 24
+  %conv4 = ashr i32 %sext6, 24
+  %cmp = icmp eq i32 %conv, %conv4
+  %s = select i1 %cmp, i32 10000, i32 0
+  ret i32 %s
+}
+
+define i32 @f7(i32 %a, i32 %b) {
+; CHECK-LABEL: @f7(
+; CHECK-NEXT:    [[CMP_UNSHIFTED:%.*]] = xor i32 [[A:%.*]], [[B:%.*]]
+; CHECK-NEXT:    [[CMP_MASK:%.*]] = and i32 [[CMP_UNSHIFTED]], 511
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[CMP_MASK]], 0
+; CHECK-NEXT:    [[S:%.*]] = select i1 [[CMP]], i32 0, i32 10000
+; CHECK-NEXT:    ret i32 [[S]]
+;
+  %sext = shl i32 %a, 23
+  %sext6 = shl i32 %b, 23
+  %cmp = icmp ne i32 %sext, %sext6
+  %s = select i1 %cmp, i32 10000, i32 0
+  ret i32 %s
+}
+
+define i1 @f8(i32 %val, i32 %lim) {
+; CHECK-LABEL: @f8(
+; CHECK-NEXT:    [[R:%.*]] = icmp ne i32 [[LIM:%.*]], 0
+; CHECK-NEXT:    ret i1 [[R]]
+;
+  %lim.sub = add i32 %lim, -1
+  %val.and = and i32 %val, %lim.sub
+  %r = icmp ult i32 %val.and, %lim
+  ret i1 %r
+}
+
+define i1 @f9(i32 %val, i32 %lim) {
+; CHECK-LABEL: @f9(
+; CHECK-NEXT:    [[R:%.*]] = icmp ne i32 [[LIM:%.*]], 0
+; CHECK-NEXT:    ret i1 [[R]]
+;
+  %lim.sub = sub i32 %lim, 1
+  %val.and = and i32 %val, %lim.sub
+  %r = icmp ult i32 %val.and, %lim
+  ret i1 %r
+}
+
+define i1 @f10(i16 %p) {
+; CHECK-LABEL: @f10(
+; CHECK-NEXT:    [[CMP580:%.*]] = icmp uge i16 [[P:%.*]], mul (i16 zext (i8 ptrtoint (i1 (i16)* @f10 to i8) to i16), i16 zext (i8 ptrtoint (i1 (i16)* @f10 to i8) to i16))
+; CHECK-NEXT:    ret i1 [[CMP580]]
+;
+  %cmp580 = icmp ule i16 mul (i16 zext (i8 ptrtoint (i1 (i16)* @f10 to i8) to i16), i16 zext (i8 ptrtoint (i1 (i16)* @f10 to i8) to i16)), %p
+  ret i1 %cmp580
+}
+
+; Note: fptosi is used in various tests below to ensure that operand complexity
+; canonicalization does not kick in, which would make some of the tests
+; equivalent to one another.
+
+define i1 @cmp_sgt_rhs_dec(float %x, i32 %i) {
+; CHECK-LABEL: @cmp_sgt_rhs_dec(
+; CHECK-NEXT:    [[CONV:%.*]] = fptosi float [[X:%.*]] to i32
+; CHECK-NEXT:    [[CMP:%.*]] = icmp sge i32 [[CONV]], [[I:%.*]]
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %conv = fptosi float %x to i32
+  %dec = sub nsw i32 %i, 1
+  %cmp = icmp sgt i32 %conv, %dec
+  ret i1 %cmp
+}
+
+define i1 @cmp_sle_rhs_dec(float %x, i32 %i) {
+; CHECK-LABEL: @cmp_sle_rhs_dec(
+; CHECK-NEXT:    [[CONV:%.*]] = fptosi float [[X:%.*]] to i32
+; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i32 [[CONV]], [[I:%.*]]
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %conv = fptosi float %x to i32
+  %dec = sub nsw i32 %i, 1
+  %cmp = icmp sle i32 %conv, %dec
+  ret i1 %cmp
+}
+
+define i1 @cmp_sge_rhs_inc(float %x, i32 %i) {
+; CHECK-LABEL: @cmp_sge_rhs_inc(
+; CHECK-NEXT:    [[CONV:%.*]] = fptosi float [[X:%.*]] to i32
+; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt i32 [[CONV]], [[I:%.*]]
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %conv = fptosi float %x to i32
+  %inc = add nsw i32 %i, 1
+  %cmp = icmp sge i32 %conv, %inc
+  ret i1 %cmp
+}
+
+define i1 @cmp_slt_rhs_inc(float %x, i32 %i) {
+; CHECK-LABEL: @cmp_slt_rhs_inc(
+; CHECK-NEXT:    [[CONV:%.*]] = fptosi float [[X:%.*]] to i32
+; CHECK-NEXT:    [[CMP:%.*]] = icmp sle i32 [[CONV]], [[I:%.*]]
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %conv = fptosi float %x to i32
+  %inc = add nsw i32 %i, 1
+  %cmp = icmp slt i32 %conv, %inc
+  ret i1 %cmp
+}
+
+define i1 @PR26407(i32 %x, i32 %y) {
+; CHECK-LABEL: @PR26407(
+; CHECK-NEXT:    [[ADDX:%.*]] = add i32 [[X:%.*]], 2147483647
+; CHECK-NEXT:    [[ADDY:%.*]] = add i32 [[Y:%.*]], 2147483647
+; CHECK-NEXT:    [[CMP:%.*]] = icmp uge i32 [[ADDX]], [[ADDY]]
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %addx = add i32 %x, 2147483647
+  %addy = add i32 %y, 2147483647
+  %cmp = icmp uge i32 %addx, %addy
+  ret i1 %cmp
+}
+
+define i1 @cmp_inverse_mask_bits_set_eq(i32 %x) {
+; CHECK-LABEL: @cmp_inverse_mask_bits_set_eq(
+; CHECK-NEXT:    [[TMP1:%.*]] = and i32 [[X:%.*]], -43
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[TMP1]], -43
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %or = or i32 %x, 42
+  %cmp = icmp eq i32 %or, -1
+  ret i1 %cmp
+}
+
+define <2 x i1> @cmp_inverse_mask_bits_set_eq_vec(<2 x i32> %x) {
+; CHECK-LABEL: @cmp_inverse_mask_bits_set_eq_vec(
+; CHECK-NEXT:    [[TMP1:%.*]] = and <2 x i32> [[X:%.*]], <i32 -43, i32 -43>
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq <2 x i32> [[TMP1]], <i32 -43, i32 -43>
+; CHECK-NEXT:    ret <2 x i1> [[CMP]]
+;
+  %or = or <2 x i32> %x, <i32 42, i32 42>
+  %cmp = icmp eq <2 x i32> %or, <i32 -1, i32 -1>
+  ret <2 x i1> %cmp
+}
+
+define i1 @cmp_inverse_mask_bits_set_ne(i32 %x) {
+; CHECK-LABEL: @cmp_inverse_mask_bits_set_ne(
+; CHECK-NEXT:    [[TMP1:%.*]] = and i32 [[X:%.*]], -43
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ne i32 [[TMP1]], -43
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %or = or i32 %x, 42
+  %cmp = icmp ne i32 %or, -1
+  ret i1 %cmp
+}
+
+; When canonicalizing to 'gt/lt', make sure the constant is correct.
+
+define i1 @PR27792(i128 %a) {
+; CHECK-LABEL: @PR27792(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt i128 [[A:%.*]], -1
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %cmp = icmp sge i128 %a, 0
+  ret i1 %cmp
+}
+
+define i1 @PR27792_2(i128 %a) {
+; CHECK-LABEL: @PR27792_2(
+; CHECK-NEXT:    [[B:%.*]] = icmp ne i128 [[A:%.*]], 0
+; CHECK-NEXT:    ret i1 [[B]]
+;
+  %b = icmp uge i128 %a, 1
+  ret i1 %b
+}
+
+define i1 @ugtMaxSignedVal(i8 %a) {
+; CHECK-LABEL: @ugtMaxSignedVal(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i8 [[A:%.*]], 0
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %cmp = icmp ugt i8 %a, 127
+  ret i1 %cmp
+}
+
+define <2 x i1> @ugtMaxSignedValVec(<2 x i8> %a) {
+; CHECK-LABEL: @ugtMaxSignedValVec(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp slt <2 x i8> [[A:%.*]], zeroinitializer
+; CHECK-NEXT:    ret <2 x i1> [[CMP]]
+;
+  %cmp = icmp ugt <2 x i8> %a, <i8 127, i8 127>
+  ret <2 x i1> %cmp
+}
+
+define i1 @ugtKnownBits(i8 %a) {
+; CHECK-LABEL: @ugtKnownBits(
+; CHECK-NEXT:    [[B:%.*]] = and i8 [[A:%.*]], 17
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i8 [[B]], 17
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %b = and i8 %a, 17
+  %cmp = icmp ugt i8 %b, 16
+  ret i1 %cmp
+}
+
+define <2 x i1> @ugtKnownBitsVec(<2 x i8> %a) {
+; CHECK-LABEL: @ugtKnownBitsVec(
+; CHECK-NEXT:    [[B:%.*]] = and <2 x i8> [[A:%.*]], <i8 17, i8 17>
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq <2 x i8> [[B]], <i8 17, i8 17>
+; CHECK-NEXT:    ret <2 x i1> [[CMP]]
+;
+  %b = and <2 x i8> %a, <i8 17, i8 17>
+  %cmp = icmp ugt <2 x i8> %b, <i8 16, i8 16>
+  ret <2 x i1> %cmp
+}
+
+define i1 @or_ptrtoint_mismatch(i8* %p, i32* %q) {
+; CHECK-LABEL: @or_ptrtoint_mismatch(
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp eq i8* [[P:%.*]], null
+; CHECK-NEXT:    [[TMP2:%.*]] = icmp eq i32* [[Q:%.*]], null
+; CHECK-NEXT:    [[B:%.*]] = and i1 [[TMP1]], [[TMP2]]
+; CHECK-NEXT:    ret i1 [[B]]
+;
+
+  %pp = ptrtoint i8* %p to i64
+  %qq = ptrtoint i32* %q to i64
+  %o = or i64 %pp, %qq
+  %b = icmp eq i64 %o, 0
+  ret i1 %b
+}
+
+define i1 @icmp_add1_ugt(i32 %x, i32 %y) {
+; CHECK-LABEL: @icmp_add1_ugt(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp uge i32 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %add = add nuw i32 %x, 1
+  %cmp = icmp ugt i32 %add, %y
+  ret i1 %cmp
+}
+
+define i1 @icmp_add1_ule(i32 %x, i32 %y) {
+; CHECK-LABEL: @icmp_add1_ule(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i32 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %add = add nuw i32 %x, 1
+  %cmp = icmp ule i32 %add, %y
+  ret i1 %cmp
+}
+
+define i1 @cmp_uge_rhs_inc(float %x, i32 %i) {
+; CHECK-LABEL: @cmp_uge_rhs_inc(
+; CHECK-NEXT:    [[CONV:%.*]] = fptosi float [[X:%.*]] to i32
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ugt i32 [[CONV]], [[I:%.*]]
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %conv = fptosi float %x to i32
+  %inc = add nuw i32 %i, 1
+  %cmp = icmp uge i32 %conv, %inc
+  ret i1 %cmp
+}
+
+define i1 @cmp_ult_rhs_inc(float %x, i32 %i) {
+; CHECK-LABEL: @cmp_ult_rhs_inc(
+; CHECK-NEXT:    [[CONV:%.*]] = fptosi float [[X:%.*]] to i32
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ule i32 [[CONV]], [[I:%.*]]
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %conv = fptosi float %x to i32
+  %inc = add nuw i32 %i, 1
+  %cmp = icmp ult i32 %conv, %inc
+  ret i1 %cmp
+}
+
+define i1 @cmp_sge_lhs_inc(i32 %x, i32 %y) {
+; CHECK-LABEL: @cmp_sge_lhs_inc(
+; CHECK-NEXT:    [[INC:%.*]] = add nsw i32 [[X:%.*]], 1
+; CHECK-NEXT:    [[CMP:%.*]] = icmp sge i32 [[INC]], [[Y:%.*]]
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %inc = add nsw i32 %x, 1
+  %cmp = icmp sge i32 %inc, %y
+  ret i1 %cmp
+}
+
+define i1 @cmp_uge_lhs_inc(i32 %x, i32 %y) {
+; CHECK-LABEL: @cmp_uge_lhs_inc(
+; CHECK-NEXT:    [[INC:%.*]] = add nuw i32 [[X:%.*]], 1
+; CHECK-NEXT:    [[CMP:%.*]] = icmp uge i32 [[INC]], [[Y:%.*]]
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %inc = add nuw i32 %x, 1
+  %cmp = icmp uge i32 %inc, %y
+  ret i1 %cmp
+}
+
+define i1 @cmp_sgt_lhs_dec(i32 %x, i32 %y) {
+; CHECK-LABEL: @cmp_sgt_lhs_dec(
+; CHECK-NEXT:    [[DEC:%.*]] = add nsw i32 [[X:%.*]], -1
+; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt i32 [[DEC]], [[Y:%.*]]
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %dec = sub nsw i32 %x, 1
+  %cmp = icmp sgt i32 %dec, %y
+  ret i1 %cmp
+}
+
+define i1 @cmp_ugt_lhs_dec(i32 %x, i32 %y) {
+; CHECK-LABEL: @cmp_ugt_lhs_dec(
+; CHECK-NEXT:    [[DEC:%.*]] = add i32 [[X:%.*]], -1
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ugt i32 [[DEC]], [[Y:%.*]]
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %dec = sub nuw i32 %x, 1
+  %cmp = icmp ugt i32 %dec, %y
+  ret i1 %cmp
+}
+
+define i1 @cmp_sle_rhs_inc(float %x, i32 %y) {
+; CHECK-LABEL: @cmp_sle_rhs_inc(
+; CHECK-NEXT:    [[CONV:%.*]] = fptosi float [[X:%.*]] to i32
+; CHECK-NEXT:    [[INC:%.*]] = add nsw i32 [[Y:%.*]], 1
+; CHECK-NEXT:    [[CMP:%.*]] = icmp sge i32 [[INC]], [[CONV]]
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %conv = fptosi float %x to i32
+  %inc = add nsw i32 %y, 1
+  %cmp = icmp sle i32 %conv, %inc
+  ret i1 %cmp
+}
+
+define i1 @cmp_ule_rhs_inc(float %x, i32 %y) {
+; CHECK-LABEL: @cmp_ule_rhs_inc(
+; CHECK-NEXT:    [[CONV:%.*]] = fptosi float [[X:%.*]] to i32
+; CHECK-NEXT:    [[INC:%.*]] = add nuw i32 [[Y:%.*]], 1
+; CHECK-NEXT:    [[CMP:%.*]] = icmp uge i32 [[INC]], [[CONV]]
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %conv = fptosi float %x to i32
+  %inc = add nuw i32 %y, 1
+  %cmp = icmp ule i32 %conv, %inc
+  ret i1 %cmp
+}
+
+define i1 @cmp_slt_rhs_dec(float %x, i32 %y) {
+; CHECK-LABEL: @cmp_slt_rhs_dec(
+; CHECK-NEXT:    [[CONV:%.*]] = fptosi float [[X:%.*]] to i32
+; CHECK-NEXT:    [[DEC:%.*]] = add nsw i32 [[Y:%.*]], -1
+; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt i32 [[DEC]], [[CONV]]
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %conv = fptosi float %x to i32
+  %dec = sub nsw i32 %y, 1
+  %cmp = icmp slt i32 %conv, %dec
+  ret i1 %cmp
+}
+
+define i1 @cmp_ult_rhs_dec(float %x, i32 %y) {
+; CHECK-LABEL: @cmp_ult_rhs_dec(
+; CHECK-NEXT:    [[CONV:%.*]] = fptosi float [[X:%.*]] to i32
+; CHECK-NEXT:    [[DEC:%.*]] = add i32 [[Y:%.*]], -1
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ugt i32 [[DEC]], [[CONV]]
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %conv = fptosi float %x to i32
+  %dec = sub nuw i32 %y, 1
+  %cmp = icmp ult i32 %conv, %dec
+  ret i1 %cmp
+}
+
+define i1 @eq_add_constants(i32 %x, i32 %y) {
+; CHECK-LABEL: @eq_add_constants(
+; CHECK-NEXT:    [[C:%.*]] = icmp eq i32 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %A = add i32 %x, 5
+  %B = add i32 %y, 5
+  %C = icmp eq i32 %A, %B
+  ret i1 %C
+}
+
+define i1 @eq_mul_constants(i32 %x, i32 %y) {
+; CHECK-LABEL: @eq_mul_constants(
+; CHECK-NEXT:    [[C:%.*]] = icmp eq i32 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %A = mul i32 %x, 5
+  %B = mul i32 %y, 5
+  %C = icmp eq i32 %A, %B
+  ret i1 %C
+}
+
+define <2 x i1> @eq_mul_constants_splat(<2 x i32> %x, <2 x i32> %y) {
+; CHECK-LABEL: @eq_mul_constants_splat(
+; CHECK-NEXT:    [[C:%.*]] = icmp ne <2 x i32> [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    ret <2 x i1> [[C]]
+;
+  %A = mul <2 x i32> %x, <i32 5, i32 5>
+  %B = mul <2 x i32> %y, <i32 5, i32 5>
+  %C = icmp ne <2 x i32> %A, %B
+  ret <2 x i1> %C
+}
+
+; If the multiply constant has any trailing zero bits, we get something completely different.
+; We mask off the high bits of each input and then convert:
+; (X&Z) == (Y&Z) -> (X^Y) & Z == 0
+
+define i1 @eq_mul_constants_with_tz(i32 %x, i32 %y) {
+; CHECK-LABEL: @eq_mul_constants_with_tz(
+; CHECK-NEXT:    [[TMP1:%.*]] = xor i32 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    [[TMP2:%.*]] = and i32 [[TMP1]], 1073741823
+; CHECK-NEXT:    [[C:%.*]] = icmp ne i32 [[TMP2]], 0
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %A = mul i32 %x, 12
+  %B = mul i32 %y, 12
+  %C = icmp ne i32 %A, %B
+  ret i1 %C
+}
+
+define <2 x i1> @eq_mul_constants_with_tz_splat(<2 x i32> %x, <2 x i32> %y) {
+; CHECK-LABEL: @eq_mul_constants_with_tz_splat(
+; CHECK-NEXT:    [[TMP1:%.*]] = xor <2 x i32> [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    [[TMP2:%.*]] = and <2 x i32> [[TMP1]], <i32 1073741823, i32 1073741823>
+; CHECK-NEXT:    [[C:%.*]] = icmp eq <2 x i32> [[TMP2]], zeroinitializer
+; CHECK-NEXT:    ret <2 x i1> [[C]]
+;
+  %A = mul <2 x i32> %x, <i32 12, i32 12>
+  %B = mul <2 x i32> %y, <i32 12, i32 12>
+  %C = icmp eq <2 x i32> %A, %B
+  ret <2 x i1> %C
+}
+
+declare i32 @llvm.bswap.i32(i32)
+
+define i1 @bswap_ne(i32 %x, i32 %y) {
+; CHECK-LABEL: @bswap_ne(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ne i32 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %swapx = call i32 @llvm.bswap.i32(i32 %x)
+  %swapy = call i32 @llvm.bswap.i32(i32 %y)
+  %cmp = icmp ne i32 %swapx, %swapy
+  ret i1 %cmp
+}
+
+declare <8 x i16> @llvm.bswap.v8i16(<8 x i16>)
+
+define <8 x i1> @bswap_vec_eq(<8 x i16> %x, <8 x i16> %y) {
+; CHECK-LABEL: @bswap_vec_eq(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq <8 x i16> [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    ret <8 x i1> [[CMP]]
+;
+  %swapx = call <8 x i16> @llvm.bswap.v8i16(<8 x i16> %x)
+  %swapy = call <8 x i16> @llvm.bswap.v8i16(<8 x i16> %y)
+  %cmp = icmp eq <8 x i16> %swapx, %swapy
+  ret <8 x i1> %cmp
+}
+
+declare i64 @llvm.bitreverse.i64(i64)
+
+define i1 @bitreverse_eq(i64 %x, i64 %y) {
+; CHECK-LABEL: @bitreverse_eq(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i64 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %revx = call i64 @llvm.bitreverse.i64(i64 %x)
+  %revy = call i64 @llvm.bitreverse.i64(i64 %y)
+  %cmp = icmp eq i64 %revx, %revy
+  ret i1 %cmp
+}
+
+declare <8 x i16> @llvm.bitreverse.v8i16(<8 x i16>)
+
+define <8 x i1> @bitreverse_vec_ne(<8 x i16> %x, <8 x i16> %y) {
+; CHECK-LABEL: @bitreverse_vec_ne(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ne <8 x i16> [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    ret <8 x i1> [[CMP]]
+;
+  %revx = call <8 x i16> @llvm.bitreverse.v8i16(<8 x i16> %x)
+  %revy = call <8 x i16> @llvm.bitreverse.v8i16(<8 x i16> %y)
+  %cmp = icmp ne <8 x i16> %revx, %revy
+  ret <8 x i1> %cmp
+}
+
+; These perform a comparison of a value known to be between 4 and 5 with a value between 5 and 7.
+; They should all simplify to equality compares.
+define i1 @knownbits1(i8 %a, i8 %b) {
+; CHECK-LABEL: @knownbits1(
+; CHECK-NEXT:    [[A1:%.*]] = and i8 [[A:%.*]], 1
+; CHECK-NEXT:    [[A2:%.*]] = or i8 [[A1]], 4
+; CHECK-NEXT:    [[B1:%.*]] = and i8 [[B:%.*]], 2
+; CHECK-NEXT:    [[B2:%.*]] = or i8 [[B1]], 5
+; CHECK-NEXT:    [[C:%.*]] = icmp eq i8 [[A2]], [[B2]]
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %a1 = and i8 %a, 5
+  %a2 = or i8 %a1, 4
+  %b1 = and i8 %b, 7
+  %b2 = or i8 %b1, 5
+  %c = icmp uge i8 %a2, %b2
+  ret i1 %c
+}
+
+define i1 @knownbits2(i8 %a, i8 %b) {
+; CHECK-LABEL: @knownbits2(
+; CHECK-NEXT:    [[A1:%.*]] = and i8 [[A:%.*]], 1
+; CHECK-NEXT:    [[A2:%.*]] = or i8 [[A1]], 4
+; CHECK-NEXT:    [[B1:%.*]] = and i8 [[B:%.*]], 2
+; CHECK-NEXT:    [[B2:%.*]] = or i8 [[B1]], 5
+; CHECK-NEXT:    [[C:%.*]] = icmp ne i8 [[A2]], [[B2]]
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %a1 = and i8 %a, 5
+  %a2 = or i8 %a1, 4
+  %b1 = and i8 %b, 7
+  %b2 = or i8 %b1, 5
+  %c = icmp ult i8 %a2, %b2
+  ret i1 %c
+}
+
+define i1 @knownbits3(i8 %a, i8 %b) {
+; CHECK-LABEL: @knownbits3(
+; CHECK-NEXT:    [[A1:%.*]] = and i8 [[A:%.*]], 1
+; CHECK-NEXT:    [[A2:%.*]] = or i8 [[A1]], 4
+; CHECK-NEXT:    [[B1:%.*]] = and i8 [[B:%.*]], 2
+; CHECK-NEXT:    [[B2:%.*]] = or i8 [[B1]], 5
+; CHECK-NEXT:    [[C:%.*]] = icmp eq i8 [[B2]], [[A2]]
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %a1 = and i8 %a, 5
+  %a2 = or i8 %a1, 4
+  %b1 = and i8 %b, 7
+  %b2 = or i8 %b1, 5
+  %c = icmp ule i8 %b2, %a2
+  ret i1 %c
+}
+
+define <2 x i1> @knownbits4(<2 x i8> %a, <2 x i8> %b) {
+; CHECK-LABEL: @knownbits4(
+; CHECK-NEXT:    [[A1:%.*]] = and <2 x i8> [[A:%.*]], <i8 1, i8 1>
+; CHECK-NEXT:    [[A2:%.*]] = or <2 x i8> [[A1]], <i8 4, i8 4>
+; CHECK-NEXT:    [[B1:%.*]] = and <2 x i8> [[B:%.*]], <i8 2, i8 2>
+; CHECK-NEXT:    [[B2:%.*]] = or <2 x i8> [[B1]], <i8 5, i8 5>
+; CHECK-NEXT:    [[C:%.*]] = icmp ne <2 x i8> [[B2]], [[A2]]
+; CHECK-NEXT:    ret <2 x i1> [[C]]
+;
+  %a1 = and <2 x i8> %a, <i8 5, i8 5>
+  %a2 = or <2 x i8> %a1, <i8 4, i8 4>
+  %b1 = and <2 x i8> %b, <i8 7, i8 7>
+  %b2 = or <2 x i8> %b1, <i8 5, i8 5>
+  %c = icmp ugt <2 x i8> %b2, %a2
+  ret <2 x i1> %c
+}
+
+; These are the signed versions of the above. One value is less than or equal to 5, but maybe negative.
+; The other is known to be a value 5-7. These should simplify to equality comparisons.
+define i1 @knownbits5(i8 %a, i8 %b) {
+; CHECK-LABEL: @knownbits5(
+; CHECK-NEXT:    [[A1:%.*]] = and i8 [[A:%.*]], -127
+; CHECK-NEXT:    [[A2:%.*]] = or i8 [[A1]], 4
+; CHECK-NEXT:    [[B1:%.*]] = and i8 [[B:%.*]], 2
+; CHECK-NEXT:    [[B2:%.*]] = or i8 [[B1]], 5
+; CHECK-NEXT:    [[C:%.*]] = icmp eq i8 [[A2]], [[B2]]
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %a1 = and i8 %a, 133
+  %a2 = or i8 %a1, 4
+  %b1 = and i8 %b, 7
+  %b2 = or i8 %b1, 5
+  %c = icmp sge i8 %a2, %b2
+  ret i1 %c
+}
+
+define i1 @knownbits6(i8 %a, i8 %b) {
+; CHECK-LABEL: @knownbits6(
+; CHECK-NEXT:    [[A1:%.*]] = and i8 [[A:%.*]], -127
+; CHECK-NEXT:    [[A2:%.*]] = or i8 [[A1]], 4
+; CHECK-NEXT:    [[B1:%.*]] = and i8 [[B:%.*]], 2
+; CHECK-NEXT:    [[B2:%.*]] = or i8 [[B1]], 5
+; CHECK-NEXT:    [[C:%.*]] = icmp ne i8 [[A2]], [[B2]]
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %a1 = and i8 %a, 133
+  %a2 = or i8 %a1, 4
+  %b1 = and i8 %b, 7
+  %b2 = or i8 %b1, 5
+  %c = icmp slt i8 %a2, %b2
+  ret i1 %c
+}
+
+define <2 x i1> @knownbits7(<2 x i8> %a, <2 x i8> %b) {
+; CHECK-LABEL: @knownbits7(
+; CHECK-NEXT:    [[A1:%.*]] = and <2 x i8> [[A:%.*]], <i8 -127, i8 -127>
+; CHECK-NEXT:    [[A2:%.*]] = or <2 x i8> [[A1]], <i8 4, i8 4>
+; CHECK-NEXT:    [[B1:%.*]] = and <2 x i8> [[B:%.*]], <i8 2, i8 2>
+; CHECK-NEXT:    [[B2:%.*]] = or <2 x i8> [[B1]], <i8 5, i8 5>
+; CHECK-NEXT:    [[C:%.*]] = icmp eq <2 x i8> [[B2]], [[A2]]
+; CHECK-NEXT:    ret <2 x i1> [[C]]
+;
+  %a1 = and <2 x i8> %a, <i8 133, i8 133>
+  %a2 = or <2 x i8> %a1, <i8 4, i8 4>
+  %b1 = and <2 x i8> %b, <i8 7, i8 7>
+  %b2 = or <2 x i8> %b1, <i8 5, i8 5>
+  %c = icmp sle <2 x i8> %b2, %a2
+  ret <2 x i1> %c
+}
+
+define i1 @knownbits8(i8 %a, i8 %b) {
+; CHECK-LABEL: @knownbits8(
+; CHECK-NEXT:    [[A1:%.*]] = and i8 [[A:%.*]], -127
+; CHECK-NEXT:    [[A2:%.*]] = or i8 [[A1]], 4
+; CHECK-NEXT:    [[B1:%.*]] = and i8 [[B:%.*]], 2
+; CHECK-NEXT:    [[B2:%.*]] = or i8 [[B1]], 5
+; CHECK-NEXT:    [[C:%.*]] = icmp ne i8 [[B2]], [[A2]]
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %a1 = and i8 %a, 133
+  %a2 = or i8 %a1, 4
+  %b1 = and i8 %b, 7
+  %b2 = or i8 %b1, 5
+  %c = icmp sgt i8 %b2, %a2
+  ret i1 %c
+}
+
+; Make sure InstCombine doesn't try too hard to simplify the icmp and break the abs idiom
+define i32 @abs_preserve(i32 %x) {
+; CHECK-LABEL: @abs_preserve(
+; CHECK-NEXT:    [[A:%.*]] = shl nsw i32 [[X:%.*]], 1
+; CHECK-NEXT:    [[C:%.*]] = icmp slt i32 [[A]], 0
+; CHECK-NEXT:    [[NEGA:%.*]] = sub i32 0, [[A]]
+; CHECK-NEXT:    [[ABS:%.*]] = select i1 [[C]], i32 [[NEGA]], i32 [[A]]
+; CHECK-NEXT:    ret i32 [[ABS]]
+;
+  %a = mul nsw i32 %x, 2
+  %c = icmp sge i32 %a, 0
+  %nega = sub i32 0, %a
+  %abs = select i1 %c, i32 %a, i32 %nega
+  ret i32 %abs
+}
+
+; Don't crash by assuming the compared values are integers.
+
+declare void @llvm.assume(i1)
+define i1 @PR35794(i32* %a) {
+; CHECK-LABEL: @PR35794(
+; CHECK-NEXT:    [[MASKCOND:%.*]] = icmp eq i32* [[A:%.*]], null
+; CHECK-NEXT:    tail call void @llvm.assume(i1 [[MASKCOND]])
+; CHECK-NEXT:    ret i1 true
+;
+  %cmp = icmp sgt i32* %a, inttoptr (i64 -1 to i32*)
+  %maskcond = icmp eq i32* %a, null
+  tail call void @llvm.assume(i1 %maskcond)
+  ret i1 %cmp
+}
+
+; Don't crash by assuming the compared values are integers.
+define <2 x i1> @PR36583(<2 x i8*>)  {
+; CHECK-LABEL: @PR36583(
+; CHECK-NEXT:    [[RES:%.*]] = icmp eq <2 x i8*> [[TMP0:%.*]], zeroinitializer
+; CHECK-NEXT:    ret <2 x i1> [[RES]]
+;
+  %cast = ptrtoint <2 x i8*> %0 to <2 x i64>
+  %res = icmp eq <2 x i64> %cast, zeroinitializer
+  ret <2 x i1> %res
+}
+
+; fold (icmp pred (sub (0, X)) C1) for vec type
+define <2 x i32> @Op1Negated_Vec(<2 x i32> %x) {
+; CHECK-LABEL: @Op1Negated_Vec(
+; CHECK-NEXT:    [[SUB:%.*]] = sub nsw <2 x i32> zeroinitializer, [[X:%.*]]
+; CHECK-NEXT:    [[CMP:%.*]] = icmp slt <2 x i32> [[X]], zeroinitializer
+; CHECK-NEXT:    [[COND:%.*]] = select <2 x i1> [[CMP]], <2 x i32> [[SUB]], <2 x i32> [[X]]
+; CHECK-NEXT:    ret <2 x i32> [[COND]]
+;
+  %sub = sub nsw <2 x i32> zeroinitializer, %x
+  %cmp = icmp sgt <2 x i32> %sub, <i32 -1, i32 -1>
+  %cond = select <2 x i1> %cmp, <2 x i32> %sub, <2 x i32> %x
+  ret <2 x i32> %cond
+}

Added: llvm/trunk/test/Transforms/InstCombine/icmp_sdiv_with_and_without_range.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/icmp_sdiv_with_and_without_range.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/icmp_sdiv_with_and_without_range.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/icmp_sdiv_with_and_without_range.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,32 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt -instcombine -S < %s | FileCheck %s
+
+; Test that presence of range does not cause unprofitable transforms with bit
+; arithmetics, and instcombine behaves exactly the same as without the range.
+
+define i1 @without_range(i32* %A) {
+; CHECK-LABEL: @without_range(
+; CHECK-NEXT:    [[A_VAL:%.*]] = load i32, i32* [[A:%.*]], align 8
+; CHECK-NEXT:    [[C:%.*]] = icmp slt i32 [[A_VAL]], 2
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %A.val = load i32, i32* %A, align 8
+  %B = sdiv i32 %A.val, 2
+  %C = icmp sge i32 0, %B
+  ret i1 %C
+}
+
+define i1 @with_range(i32* %A) {
+; CHECK-LABEL: @with_range(
+; CHECK-NEXT:    [[A_VAL:%.*]] = load i32, i32* [[A:%.*]], align 8, !range !0
+; CHECK-NEXT:    [[B_MASK:%.*]] = and i32 [[A_VAL]], 2147483646
+; CHECK-NEXT:    [[C:%.*]] = icmp eq i32 [[B_MASK]], 0
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %A.val = load i32, i32* %A, align 8, !range !0
+  %B = sdiv i32 %A.val, 2
+  %C = icmp sge i32 0, %B
+  ret i1 %C
+}
+
+!0 = !{i32 0, i32 2147483647}

Added: llvm/trunk/test/Transforms/InstCombine/idioms.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/idioms.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/idioms.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/idioms.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,32 @@
+; RUN: opt -instcombine -S < %s | FileCheck %s
+
+; Check that code corresponding to the following C function is
+; simplified into a single ASR operation:
+;
+; int test_asr(int a, int b) {
+;   return a < 0 ? -(-a - 1 >> b) - 1 : a >> b;
+; }
+;
+define i32 @test_asr(i32 %a, i32 %b) {
+entry:
+	%c = icmp slt i32 %a, 0
+	br i1 %c, label %bb2, label %bb3
+
+bb2:
+	%t1 = sub i32 0, %a
+	%not = sub i32 %t1, 1
+	%d = ashr i32 %not, %b
+	%t2 = sub i32 0, %d
+	%not2 = sub i32 %t2, 1
+	br label %bb4
+bb3:
+	%e = ashr i32 %a, %b
+	br label %bb4
+bb4:
+        %f = phi i32 [ %not2, %bb2 ], [ %e, %bb3 ]
+	ret i32 %f
+; CHECK-LABEL: @test_asr(
+; CHECK: bb4:
+; CHECK: %f = ashr i32 %a, %b
+; CHECK: ret i32 %f
+}

Added: llvm/trunk/test/Transforms/InstCombine/indexed-gep-compares.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/indexed-gep-compares.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/indexed-gep-compares.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/indexed-gep-compares.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,207 @@
+; RUN: opt -instcombine -S  < %s | FileCheck %s
+
+target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:32-f32:32:32-f64:32:32-v64:64:64-v128:128:128-a0:0:64"
+
+define i32 *@test1(i32* %A, i32 %Offset) {
+entry:
+  %tmp = getelementptr inbounds i32, i32* %A, i32 %Offset
+  br label %bb
+
+bb:
+  %RHS = phi i32* [ %RHS.next, %bb ], [ %tmp, %entry ]
+  %LHS = getelementptr inbounds i32, i32* %A, i32 100
+  %RHS.next = getelementptr inbounds i32, i32* %RHS, i64 1
+  %cond = icmp ult i32 * %LHS, %RHS
+  br i1 %cond, label %bb2, label %bb
+
+bb2:
+  ret i32* %RHS
+
+; CHECK-LABEL: @test1(
+; CHECK:  %[[INDEX:[0-9A-Za-z.]+]] = phi i32 [ %[[ADD:[0-9A-Za-z.]+]], %bb ], [ %Offset, %entry ]
+; CHECK:  %[[ADD]] = add nsw i32 %[[INDEX]], 1
+; CHECK:  %cond = icmp sgt i32 %[[INDEX]], 100
+; CHECK:  br i1 %cond, label %bb2, label %bb
+; CHECK:  %[[PTR:[0-9A-Za-z.]+]] = getelementptr inbounds i32, i32* %A, i32 %[[INDEX]]
+; CHECK:  ret i32* %[[PTR]]
+}
+
+define i32 *@test2(i32 %A, i32 %Offset) {
+entry:
+  %A.ptr = inttoptr i32 %A to i32*
+  %tmp = getelementptr inbounds i32, i32* %A.ptr, i32 %Offset
+  br label %bb
+
+bb:
+  %RHS = phi i32* [ %RHS.next, %bb ], [ %tmp, %entry ]
+  %LHS = getelementptr inbounds i32, i32* %A.ptr, i32 100
+  %RHS.next = getelementptr inbounds i32, i32* %RHS, i64 1
+  %cmp0 = ptrtoint i32 *%LHS to i32
+  %cmp1 = ptrtoint i32 *%RHS to i32
+  %cond = icmp ult i32 %cmp0, %cmp1
+  br i1 %cond, label %bb2, label %bb
+
+bb2:
+  ret i32* %RHS
+
+; CHECK-LABEL: @test2(
+; CHECK:  %[[INDEX:[0-9A-Za-z.]+]] = phi i32 [ %[[ADD:[0-9A-Za-z.]+]], %bb ], [ %Offset, %entry ]
+; CHECK:  %[[ADD]] = add nsw i32 %[[INDEX]], 1
+; CHECK:  %cond = icmp sgt i32 %[[INDEX]], 100
+; CHECK:  br i1 %cond, label %bb2, label %bb
+; CHECK:  %[[TOPTR:[0-9A-Za-z.]+]] = inttoptr i32 %[[ADD:[0-9A-Za-z.]+]] to i32*
+; CHECK:  %[[PTR:[0-9A-Za-z.]+]] = getelementptr inbounds i32, i32* %[[TOPTR]], i32 %[[INDEX]]
+; CHECK:  ret i32* %[[PTR]]
+}
+
+; Perform the transformation only if we know that the GEPs used are inbounds.
+define i32 *@test3(i32* %A, i32 %Offset) {
+entry:
+  %tmp = getelementptr i32, i32* %A, i32 %Offset
+  br label %bb
+
+bb:
+  %RHS = phi i32* [ %RHS.next, %bb ], [ %tmp, %entry ]
+  %LHS = getelementptr i32, i32* %A, i32 100
+  %RHS.next = getelementptr i32, i32* %RHS, i64 1
+  %cond = icmp ult i32 * %LHS, %RHS
+  br i1 %cond, label %bb2, label %bb
+
+bb2:
+  ret i32* %RHS
+
+; CHECK-LABEL: @test3(
+; CHECK-NOT:  %cond = icmp sgt i32 %{{[0-9A-Za-z.]+}}, 100
+}
+
+; An inttoptr that requires an extension or truncation will be opaque when determining
+; the base pointer. In this case we can still perform the transformation by considering
+; A.ptr as being the base pointer.
+define i32 *@test4(i16 %A, i32 %Offset) {
+entry:
+  %A.ptr = inttoptr i16 %A to i32*
+  %tmp = getelementptr inbounds i32, i32* %A.ptr, i32 %Offset
+  br label %bb
+
+bb:
+  %RHS = phi i32* [ %RHS.next, %bb ], [ %tmp, %entry ]
+  %LHS = getelementptr inbounds i32, i32* %A.ptr, i32 100
+  %RHS.next = getelementptr inbounds i32, i32* %RHS, i64 1
+  %cmp0 = ptrtoint i32 *%LHS to i32
+  %cmp1 = ptrtoint i32 *%RHS to i32
+  %cond = icmp ult i32 %cmp0, %cmp1
+  br i1 %cond, label %bb2, label %bb
+
+bb2:
+  ret i32* %RHS
+
+; CHECK-LABEL: @test4(
+; CHECK:  %cond = icmp sgt i32 %{{[0-9A-Za-z.]+}}, 100
+}
+
+declare i32* @fun_ptr()
+
+define i32 *@test5(i32 %Offset) personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) {
+entry:
+ %A = invoke i32 *@fun_ptr() to label %cont unwind label %lpad
+
+cont:
+  %tmp = getelementptr inbounds i32, i32* %A, i32 %Offset
+  br label %bb
+
+bb:
+  %RHS = phi i32* [ %RHS.next, %bb ], [ %tmp, %cont ]
+  %LHS = getelementptr inbounds i32, i32* %A, i32 100
+  %RHS.next = getelementptr inbounds i32, i32* %RHS, i64 1
+  %cond = icmp ult i32 * %LHS, %RHS
+  br i1 %cond, label %bb2, label %bb
+
+bb2:
+  ret i32* %RHS
+
+lpad:
+  %l = landingpad { i8*, i32 } cleanup
+  ret i32* null
+
+; CHECK-LABEL: @test5(
+; CHECK:  %[[INDEX:[0-9A-Za-z.]+]] = phi i32 [ %[[ADD:[0-9A-Za-z.]+]], %bb ], [ %Offset, %cont ]
+; CHECK:  %[[ADD]] = add nsw i32 %[[INDEX]], 1
+; CHECK:  %cond = icmp sgt i32 %[[INDEX]], 100
+; CHECK:  br i1 %cond, label %bb2, label %bb
+; CHECK:  %[[PTR:[0-9A-Za-z.]+]] = getelementptr inbounds i32, i32* %A, i32 %[[INDEX]]
+; CHECK:  ret i32* %[[PTR]]
+}
+
+declare i32 @fun_i32()
+
+define i32 *@test6(i32 %Offset) personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) {
+entry:
+ %A = invoke i32 @fun_i32() to label %cont unwind label %lpad
+
+cont:
+  %A.ptr = inttoptr i32 %A to i32*
+  %tmp = getelementptr inbounds i32, i32* %A.ptr, i32 %Offset
+  br label %bb
+
+bb:
+  %RHS = phi i32* [ %RHS.next, %bb ], [ %tmp, %cont ]
+  %LHS = getelementptr inbounds i32, i32* %A.ptr, i32 100
+  %RHS.next = getelementptr inbounds i32, i32* %RHS, i64 1
+  %cond = icmp ult i32 * %LHS, %RHS
+  br i1 %cond, label %bb2, label %bb
+
+bb2:
+  ret i32* %RHS
+
+lpad:
+  %l = landingpad { i8*, i32 } cleanup
+  ret i32* null
+
+; CHECK-LABEL: @test6(
+; CHECK:  %[[INDEX:[0-9A-Za-z.]+]] = phi i32 [ %[[ADD:[0-9A-Za-z.]+]], %bb ], [ %Offset, %cont ]
+; CHECK:  %[[ADD]] = add nsw i32 %[[INDEX]], 1
+; CHECK:  %cond = icmp sgt i32 %[[INDEX]], 100
+; CHECK:  br i1 %cond, label %bb2, label %bb
+; CHECK:  %[[TOPTR:[0-9A-Za-z.]+]] = inttoptr i32 %[[ADD:[0-9A-Za-z.]+]] to i32*
+; CHECK:  %[[PTR:[0-9A-Za-z.]+]] = getelementptr inbounds i32, i32* %[[TOPTR]], i32 %[[INDEX]]
+; CHECK:  ret i32* %[[PTR]]
+}
+
+
+ at pr30402 = constant i64 3
+define i1 @test7() {
+entry:
+  br label %bb7
+
+bb7:                                              ; preds = %bb10, %entry-block
+  %phi = phi i64* [ @pr30402, %entry ], [ getelementptr inbounds (i64, i64* @pr30402, i32 1), %bb7 ]
+  %cmp = icmp eq i64* %phi, getelementptr inbounds (i64, i64* @pr30402, i32 1)
+  br i1 %cmp, label %bb10, label %bb7
+
+bb10:
+  ret i1 %cmp
+}
+; CHECK-LABEL: @test7(
+; CHECK:  %[[phi:.*]] = phi i64* [ @pr30402, %entry ], [ getelementptr inbounds (i64, i64* @pr30402, i32 1), %bb7 ]
+; CHECK:  %[[cmp:.*]] = icmp eq i64* %[[phi]], getelementptr inbounds (i64, i64* @pr30402, i32 1)
+; CHECK: ret i1 %[[cmp]]
+
+
+declare i32 @__gxx_personality_v0(...)
+
+define i1 @test8(i64* %in, i64 %offset) {
+entry:
+
+ %ld = load i64, i64* %in, align 8
+ %casti8 = inttoptr i64 %ld to i8*
+ %gepi8 = getelementptr inbounds i8, i8* %casti8, i64 %offset
+ %cast = bitcast i8* %gepi8 to i32**
+ %ptrcast = inttoptr i64 %ld to i32**
+ %gepi32 = getelementptr inbounds i32*, i32** %ptrcast, i64 1
+ %cmp = icmp eq i32** %gepi32, %cast
+ ret i1 %cmp
+
+
+; CHECK-LABEL: @test8(
+; CHECK-NOT: icmp eq i32 %{{[0-9A-Za-z.]+}}, 1
+}

Added: llvm/trunk/test/Transforms/InstCombine/inline-intrinsic-assert.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/inline-intrinsic-assert.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/inline-intrinsic-assert.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/inline-intrinsic-assert.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,28 @@
+; RUN: opt < %s -inline -instcombine -S | FileCheck %s
+
+; PR22857: http://llvm.org/bugs/show_bug.cgi?id=22857
+; The inliner should not add an edge to an intrinsic and
+; then assert that it did not add an edge to an intrinsic!
+
+define float @foo(float %f1) {
+  %call = call float @bar(float %f1)
+  ret float %call
+
+; CHECK-LABEL: @foo(
+; CHECK-NEXT: call fast float @llvm.fabs.f32
+; CHECK-NEXT: ret float
+}
+
+define float @bar(float %f1) {
+  %call = call float @sqr(float %f1)
+  %call1 = call fast float @sqrtf(float %call)
+  ret float %call1
+}
+
+define float @sqr(float %f) {
+  %mul = fmul fast float %f, %f
+  ret float %mul
+}
+
+declare float @sqrtf(float)
+

Added: llvm/trunk/test/Transforms/InstCombine/inselt-binop.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/inselt-binop.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/inselt-binop.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/inselt-binop.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,635 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt -S -instcombine %s | FileCheck %s
+
+define <2 x i8> @add_constant(i8 %x) {
+; CHECK-LABEL: @add_constant(
+; CHECK-NEXT:    [[INS:%.*]] = insertelement <2 x i8> undef, i8 [[X:%.*]], i32 0
+; CHECK-NEXT:    [[BO:%.*]] = add <2 x i8> [[INS]], <i8 42, i8 undef>
+; CHECK-NEXT:    ret <2 x i8> [[BO]]
+;
+  %ins = insertelement <2 x i8> undef, i8 %x, i32 0
+  %bo = add <2 x i8> %ins, <i8 42, i8 undef>
+  ret <2 x i8> %bo
+}
+
+define <2 x i8> @add_constant_not_undef_lane(i8 %x) {
+; CHECK-LABEL: @add_constant_not_undef_lane(
+; CHECK-NEXT:    [[INS:%.*]] = insertelement <2 x i8> undef, i8 [[X:%.*]], i32 0
+; CHECK-NEXT:    [[BO:%.*]] = add <2 x i8> [[INS]], <i8 42, i8 -42>
+; CHECK-NEXT:    ret <2 x i8> [[BO]]
+;
+  %ins = insertelement <2 x i8> undef, i8 %x, i32 0
+  %bo = add <2 x i8> %ins, <i8 42, i8 -42>
+  ret <2 x i8> %bo
+}
+
+; IR flags are not required, but they should propagate.
+
+define <2 x i8> @sub_constant_op0(i8 %x) {
+; CHECK-LABEL: @sub_constant_op0(
+; CHECK-NEXT:    [[INS:%.*]] = insertelement <2 x i8> undef, i8 [[X:%.*]], i32 1
+; CHECK-NEXT:    [[BO:%.*]] = sub nuw nsw <2 x i8> <i8 undef, i8 -42>, [[INS]]
+; CHECK-NEXT:    ret <2 x i8> [[BO]]
+;
+  %ins = insertelement <2 x i8> undef, i8 %x, i32 1
+  %bo = sub nsw nuw <2 x i8> <i8 undef, i8 -42>, %ins
+  ret <2 x i8> %bo
+}
+
+define <2 x i8> @sub_constant_op0_not_undef_lane(i8 %x) {
+; CHECK-LABEL: @sub_constant_op0_not_undef_lane(
+; CHECK-NEXT:    [[INS:%.*]] = insertelement <2 x i8> undef, i8 [[X:%.*]], i32 1
+; CHECK-NEXT:    [[BO:%.*]] = sub nuw <2 x i8> <i8 42, i8 -42>, [[INS]]
+; CHECK-NEXT:    ret <2 x i8> [[BO]]
+;
+  %ins = insertelement <2 x i8> undef, i8 %x, i32 1
+  %bo = sub nuw <2 x i8> <i8 42, i8 -42>, %ins
+  ret <2 x i8> %bo
+}
+
+define <2 x i8> @sub_constant_op1(i8 %x) {
+; CHECK-LABEL: @sub_constant_op1(
+; CHECK-NEXT:    [[INS:%.*]] = insertelement <2 x i8> undef, i8 [[X:%.*]], i32 0
+; CHECK-NEXT:    [[BO:%.*]] = add <2 x i8> [[INS]], <i8 -42, i8 undef>
+; CHECK-NEXT:    ret <2 x i8> [[BO]]
+;
+  %ins = insertelement <2 x i8> undef, i8 %x, i32 0
+  %bo = sub nuw <2 x i8> %ins, <i8 42, i8 undef>
+  ret <2 x i8> %bo
+}
+
+define <2 x i8> @sub_constant_op1_not_undef_lane(i8 %x) {
+; CHECK-LABEL: @sub_constant_op1_not_undef_lane(
+; CHECK-NEXT:    [[INS:%.*]] = insertelement <2 x i8> undef, i8 [[X:%.*]], i32 0
+; CHECK-NEXT:    [[BO:%.*]] = add <2 x i8> [[INS]], <i8 -42, i8 42>
+; CHECK-NEXT:    ret <2 x i8> [[BO]]
+;
+  %ins = insertelement <2 x i8> undef, i8 %x, i32 0
+  %bo = sub nuw <2 x i8> %ins, <i8 42, i8 -42>
+  ret <2 x i8> %bo
+}
+
+define <3 x i8> @mul_constant(i8 %x) {
+; CHECK-LABEL: @mul_constant(
+; CHECK-NEXT:    [[INS:%.*]] = insertelement <3 x i8> undef, i8 [[X:%.*]], i32 2
+; CHECK-NEXT:    [[BO:%.*]] = mul <3 x i8> [[INS]], <i8 undef, i8 undef, i8 -42>
+; CHECK-NEXT:    ret <3 x i8> [[BO]]
+;
+  %ins = insertelement <3 x i8> undef, i8 %x, i32 2
+  %bo = mul <3 x i8> %ins, <i8 undef, i8 undef, i8 -42>
+  ret <3 x i8> %bo
+}
+
+define <3 x i8> @mul_constant_not_undef_lane(i8 %x) {
+; CHECK-LABEL: @mul_constant_not_undef_lane(
+; CHECK-NEXT:    [[INS:%.*]] = insertelement <3 x i8> undef, i8 [[X:%.*]], i32 2
+; CHECK-NEXT:    [[BO:%.*]] = mul <3 x i8> [[INS]], <i8 42, i8 undef, i8 -42>
+; CHECK-NEXT:    ret <3 x i8> [[BO]]
+;
+  %ins = insertelement <3 x i8> undef, i8 %x, i32 2
+  %bo = mul <3 x i8> %ins, <i8 42, i8 undef, i8 -42>
+  ret <3 x i8> %bo
+}
+
+define <2 x i8> @shl_constant_op0(i8 %x) {
+; CHECK-LABEL: @shl_constant_op0(
+; CHECK-NEXT:    [[INS:%.*]] = insertelement <2 x i8> undef, i8 [[X:%.*]], i32 1
+; CHECK-NEXT:    [[BO:%.*]] = shl <2 x i8> <i8 undef, i8 2>, [[INS]]
+; CHECK-NEXT:    ret <2 x i8> [[BO]]
+;
+  %ins = insertelement <2 x i8> undef, i8 %x, i32 1
+  %bo = shl <2 x i8> <i8 undef, i8 2>, %ins
+  ret <2 x i8> %bo
+}
+
+define <2 x i8> @shl_constant_op0_not_undef_lane(i8 %x) {
+; CHECK-LABEL: @shl_constant_op0_not_undef_lane(
+; CHECK-NEXT:    [[INS:%.*]] = insertelement <2 x i8> undef, i8 [[X:%.*]], i32 1
+; CHECK-NEXT:    [[BO:%.*]] = shl <2 x i8> <i8 5, i8 2>, [[INS]]
+; CHECK-NEXT:    ret <2 x i8> [[BO]]
+;
+  %ins = insertelement <2 x i8> undef, i8 %x, i32 1
+  %bo = shl <2 x i8> <i8 5, i8 2>, %ins
+  ret <2 x i8> %bo
+}
+
+define <2 x i8> @shl_constant_op1(i8 %x) {
+; CHECK-LABEL: @shl_constant_op1(
+; CHECK-NEXT:    [[INS:%.*]] = insertelement <2 x i8> undef, i8 [[X:%.*]], i32 0
+; CHECK-NEXT:    [[BO:%.*]] = shl nuw <2 x i8> [[INS]], <i8 5, i8 undef>
+; CHECK-NEXT:    ret <2 x i8> [[BO]]
+;
+  %ins = insertelement <2 x i8> undef, i8 %x, i32 0
+  %bo = shl nuw <2 x i8> %ins, <i8 5, i8 undef>
+  ret <2 x i8> %bo
+}
+
+define <2 x i8> @shl_constant_op1_not_undef_lane(i8 %x) {
+; CHECK-LABEL: @shl_constant_op1_not_undef_lane(
+; CHECK-NEXT:    [[INS:%.*]] = insertelement <2 x i8> undef, i8 [[X:%.*]], i32 0
+; CHECK-NEXT:    [[BO:%.*]] = shl nuw <2 x i8> [[INS]], <i8 5, i8 2>
+; CHECK-NEXT:    ret <2 x i8> [[BO]]
+;
+  %ins = insertelement <2 x i8> undef, i8 %x, i32 0
+  %bo = shl nuw <2 x i8> %ins, <i8 5, i8 2>
+  ret <2 x i8> %bo
+}
+
+define <2 x i8> @ashr_constant_op0(i8 %x) {
+; CHECK-LABEL: @ashr_constant_op0(
+; CHECK-NEXT:    [[INS:%.*]] = insertelement <2 x i8> undef, i8 [[X:%.*]], i32 1
+; CHECK-NEXT:    [[BO:%.*]] = ashr exact <2 x i8> <i8 undef, i8 2>, [[INS]]
+; CHECK-NEXT:    ret <2 x i8> [[BO]]
+;
+  %ins = insertelement <2 x i8> undef, i8 %x, i32 1
+  %bo = ashr exact <2 x i8> <i8 undef, i8 2>, %ins
+  ret <2 x i8> %bo
+}
+
+define <2 x i8> @ashr_constant_op0_not_undef_lane(i8 %x) {
+; CHECK-LABEL: @ashr_constant_op0_not_undef_lane(
+; CHECK-NEXT:    [[INS:%.*]] = insertelement <2 x i8> undef, i8 [[X:%.*]], i32 1
+; CHECK-NEXT:    [[BO:%.*]] = lshr <2 x i8> <i8 5, i8 2>, [[INS]]
+; CHECK-NEXT:    ret <2 x i8> [[BO]]
+;
+  %ins = insertelement <2 x i8> undef, i8 %x, i32 1
+  %bo = ashr exact <2 x i8> <i8 5, i8 2>, %ins
+  ret <2 x i8> %bo
+}
+
+define <2 x i8> @ashr_constant_op1(i8 %x) {
+; CHECK-LABEL: @ashr_constant_op1(
+; CHECK-NEXT:    [[INS:%.*]] = insertelement <2 x i8> undef, i8 [[X:%.*]], i32 0
+; CHECK-NEXT:    [[BO:%.*]] = ashr <2 x i8> [[INS]], <i8 5, i8 undef>
+; CHECK-NEXT:    ret <2 x i8> [[BO]]
+;
+  %ins = insertelement <2 x i8> undef, i8 %x, i32 0
+  %bo = ashr <2 x i8> %ins, <i8 5, i8 undef>
+  ret <2 x i8> %bo
+}
+
+define <2 x i8> @ashr_constant_op1_not_undef_lane(i8 %x) {
+; CHECK-LABEL: @ashr_constant_op1_not_undef_lane(
+; CHECK-NEXT:    [[INS:%.*]] = insertelement <2 x i8> undef, i8 [[X:%.*]], i32 0
+; CHECK-NEXT:    [[BO:%.*]] = ashr <2 x i8> [[INS]], <i8 5, i8 2>
+; CHECK-NEXT:    ret <2 x i8> [[BO]]
+;
+  %ins = insertelement <2 x i8> undef, i8 %x, i32 0
+  %bo = ashr <2 x i8> %ins, <i8 5, i8 2>
+  ret <2 x i8> %bo
+}
+
+define <2 x i8> @lshr_constant_op0(i8 %x) {
+; CHECK-LABEL: @lshr_constant_op0(
+; CHECK-NEXT:    [[INS:%.*]] = insertelement <2 x i8> undef, i8 [[X:%.*]], i32 0
+; CHECK-NEXT:    [[BO:%.*]] = lshr <2 x i8> <i8 5, i8 undef>, [[INS]]
+; CHECK-NEXT:    ret <2 x i8> [[BO]]
+;
+  %ins = insertelement <2 x i8> undef, i8 %x, i32 0
+  %bo = lshr <2 x i8> <i8 5, i8 undef>, %ins
+  ret <2 x i8> %bo
+}
+
+define <2 x i8> @lshr_constant_op0_not_undef_lane(i8 %x) {
+; CHECK-LABEL: @lshr_constant_op0_not_undef_lane(
+; CHECK-NEXT:    [[INS:%.*]] = insertelement <2 x i8> undef, i8 [[X:%.*]], i32 0
+; CHECK-NEXT:    [[BO:%.*]] = lshr <2 x i8> <i8 5, i8 2>, [[INS]]
+; CHECK-NEXT:    ret <2 x i8> [[BO]]
+;
+  %ins = insertelement <2 x i8> undef, i8 %x, i32 0
+  %bo = lshr <2 x i8> <i8 5, i8 2>, %ins
+  ret <2 x i8> %bo
+}
+
+define <2 x i8> @lshr_constant_op1(i8 %x) {
+; CHECK-LABEL: @lshr_constant_op1(
+; CHECK-NEXT:    [[INS:%.*]] = insertelement <2 x i8> undef, i8 [[X:%.*]], i32 1
+; CHECK-NEXT:    [[BO:%.*]] = lshr exact <2 x i8> [[INS]], <i8 undef, i8 2>
+; CHECK-NEXT:    ret <2 x i8> [[BO]]
+;
+  %ins = insertelement <2 x i8> undef, i8 %x, i32 1
+  %bo = lshr exact <2 x i8> %ins, <i8 undef, i8 2>
+  ret <2 x i8> %bo
+}
+
+define <2 x i8> @lshr_constant_op1_not_undef_lane(i8 %x) {
+; CHECK-LABEL: @lshr_constant_op1_not_undef_lane(
+; CHECK-NEXT:    [[INS:%.*]] = insertelement <2 x i8> undef, i8 [[X:%.*]], i32 1
+; CHECK-NEXT:    [[BO:%.*]] = lshr exact <2 x i8> [[INS]], <i8 5, i8 2>
+; CHECK-NEXT:    ret <2 x i8> [[BO]]
+;
+  %ins = insertelement <2 x i8> undef, i8 %x, i32 1
+  %bo = lshr exact <2 x i8> %ins, <i8 5, i8 2>
+  ret <2 x i8> %bo
+}
+
+define <2 x i8> @urem_constant_op0(i8 %x) {
+; CHECK-LABEL: @urem_constant_op0(
+; CHECK-NEXT:    [[INS:%.*]] = insertelement <2 x i8> undef, i8 [[X:%.*]], i32 0
+; CHECK-NEXT:    [[BO:%.*]] = urem <2 x i8> <i8 5, i8 undef>, [[INS]]
+; CHECK-NEXT:    ret <2 x i8> [[BO]]
+;
+  %ins = insertelement <2 x i8> undef, i8 %x, i32 0
+  %bo = urem <2 x i8> <i8 5, i8 undef>, %ins
+  ret <2 x i8> %bo
+}
+
+define <2 x i8> @urem_constant_op0_not_undef_lane(i8 %x) {
+; CHECK-LABEL: @urem_constant_op0_not_undef_lane(
+; CHECK-NEXT:    [[INS:%.*]] = insertelement <2 x i8> undef, i8 [[X:%.*]], i32 0
+; CHECK-NEXT:    [[BO:%.*]] = urem <2 x i8> <i8 5, i8 2>, [[INS]]
+; CHECK-NEXT:    ret <2 x i8> [[BO]]
+;
+  %ins = insertelement <2 x i8> undef, i8 %x, i32 0
+  %bo = urem <2 x i8> <i8 5, i8 2>, %ins
+  ret <2 x i8> %bo
+}
+
+define <2 x i8> @urem_constant_op1(i8 %x) {
+; CHECK-LABEL: @urem_constant_op1(
+; CHECK-NEXT:    ret <2 x i8> undef
+;
+  %ins = insertelement <2 x i8> undef, i8 %x, i32 1
+  %bo = urem <2 x i8> %ins, <i8 undef, i8 2>
+  ret <2 x i8> %bo
+}
+
+define <2 x i8> @urem_constant_op1_not_undef_lane(i8 %x) {
+; CHECK-LABEL: @urem_constant_op1_not_undef_lane(
+; CHECK-NEXT:    [[INS:%.*]] = insertelement <2 x i8> undef, i8 [[X:%.*]], i32 1
+; CHECK-NEXT:    [[BO:%.*]] = urem <2 x i8> [[INS]], <i8 5, i8 2>
+; CHECK-NEXT:    ret <2 x i8> [[BO]]
+;
+  %ins = insertelement <2 x i8> undef, i8 %x, i32 1
+  %bo = urem <2 x i8> %ins, <i8 5, i8 2>
+  ret <2 x i8> %bo
+}
+
+define <2 x i8> @srem_constant_op0(i8 %x) {
+; CHECK-LABEL: @srem_constant_op0(
+; CHECK-NEXT:    [[INS:%.*]] = insertelement <2 x i8> undef, i8 [[X:%.*]], i32 0
+; CHECK-NEXT:    [[BO:%.*]] = srem <2 x i8> <i8 5, i8 undef>, [[INS]]
+; CHECK-NEXT:    ret <2 x i8> [[BO]]
+;
+  %ins = insertelement <2 x i8> undef, i8 %x, i32 0
+  %bo = srem <2 x i8> <i8 5, i8 undef>, %ins
+  ret <2 x i8> %bo
+}
+
+define <2 x i8> @srem_constant_op0_not_undef_lane(i8 %x) {
+; CHECK-LABEL: @srem_constant_op0_not_undef_lane(
+; CHECK-NEXT:    [[INS:%.*]] = insertelement <2 x i8> undef, i8 [[X:%.*]], i32 0
+; CHECK-NEXT:    [[BO:%.*]] = srem <2 x i8> <i8 5, i8 2>, [[INS]]
+; CHECK-NEXT:    ret <2 x i8> [[BO]]
+;
+  %ins = insertelement <2 x i8> undef, i8 %x, i32 0
+  %bo = srem <2 x i8> <i8 5, i8 2>, %ins
+  ret <2 x i8> %bo
+}
+
+define <2 x i8> @srem_constant_op1(i8 %x) {
+; CHECK-LABEL: @srem_constant_op1(
+; CHECK-NEXT:    ret <2 x i8> undef
+;
+  %ins = insertelement <2 x i8> undef, i8 %x, i32 1
+  %bo = srem <2 x i8> %ins, <i8 undef, i8 2>
+  ret <2 x i8> %bo
+}
+
+define <2 x i8> @srem_constant_op1_not_undef_lane(i8 %x) {
+; CHECK-LABEL: @srem_constant_op1_not_undef_lane(
+; CHECK-NEXT:    [[INS:%.*]] = insertelement <2 x i8> undef, i8 [[X:%.*]], i32 1
+; CHECK-NEXT:    [[BO:%.*]] = srem <2 x i8> [[INS]], <i8 5, i8 2>
+; CHECK-NEXT:    ret <2 x i8> [[BO]]
+;
+  %ins = insertelement <2 x i8> undef, i8 %x, i32 1
+  %bo = srem <2 x i8> %ins, <i8 5, i8 2>
+  ret <2 x i8> %bo
+}
+
+define <2 x i8> @udiv_constant_op0(i8 %x) {
+; CHECK-LABEL: @udiv_constant_op0(
+; CHECK-NEXT:    [[INS:%.*]] = insertelement <2 x i8> undef, i8 [[X:%.*]], i32 0
+; CHECK-NEXT:    [[BO:%.*]] = udiv exact <2 x i8> <i8 5, i8 undef>, [[INS]]
+; CHECK-NEXT:    ret <2 x i8> [[BO]]
+;
+  %ins = insertelement <2 x i8> undef, i8 %x, i32 0
+  %bo = udiv exact <2 x i8> <i8 5, i8 undef>, %ins
+  ret <2 x i8> %bo
+}
+
+define <2 x i8> @udiv_constant_op0_not_undef_lane(i8 %x) {
+; CHECK-LABEL: @udiv_constant_op0_not_undef_lane(
+; CHECK-NEXT:    [[INS:%.*]] = insertelement <2 x i8> undef, i8 [[X:%.*]], i32 0
+; CHECK-NEXT:    [[BO:%.*]] = udiv exact <2 x i8> <i8 5, i8 2>, [[INS]]
+; CHECK-NEXT:    ret <2 x i8> [[BO]]
+;
+  %ins = insertelement <2 x i8> undef, i8 %x, i32 0
+  %bo = udiv exact <2 x i8> <i8 5, i8 2>, %ins
+  ret <2 x i8> %bo
+}
+
+define <2 x i8> @udiv_constant_op1(i8 %x) {
+; CHECK-LABEL: @udiv_constant_op1(
+; CHECK-NEXT:    ret <2 x i8> undef
+;
+  %ins = insertelement <2 x i8> undef, i8 %x, i32 1
+  %bo = udiv <2 x i8> %ins, <i8 undef, i8 2>
+  ret <2 x i8> %bo
+}
+
+define <2 x i8> @udiv_constant_op1_not_undef_lane(i8 %x) {
+; CHECK-LABEL: @udiv_constant_op1_not_undef_lane(
+; CHECK-NEXT:    [[INS:%.*]] = insertelement <2 x i8> undef, i8 [[X:%.*]], i32 1
+; CHECK-NEXT:    [[BO:%.*]] = udiv <2 x i8> [[INS]], <i8 5, i8 2>
+; CHECK-NEXT:    ret <2 x i8> [[BO]]
+;
+  %ins = insertelement <2 x i8> undef, i8 %x, i32 1
+  %bo = udiv <2 x i8> %ins, <i8 5, i8 2>
+  ret <2 x i8> %bo
+}
+
+define <2 x i8> @sdiv_constant_op0(i8 %x) {
+; CHECK-LABEL: @sdiv_constant_op0(
+; CHECK-NEXT:    [[INS:%.*]] = insertelement <2 x i8> undef, i8 [[X:%.*]], i32 0
+; CHECK-NEXT:    [[BO:%.*]] = sdiv <2 x i8> <i8 5, i8 undef>, [[INS]]
+; CHECK-NEXT:    ret <2 x i8> [[BO]]
+;
+  %ins = insertelement <2 x i8> undef, i8 %x, i32 0
+  %bo = sdiv <2 x i8> <i8 5, i8 undef>, %ins
+  ret <2 x i8> %bo
+}
+
+define <2 x i8> @sdiv_constant_op0_not_undef_lane(i8 %x) {
+; CHECK-LABEL: @sdiv_constant_op0_not_undef_lane(
+; CHECK-NEXT:    [[INS:%.*]] = insertelement <2 x i8> undef, i8 [[X:%.*]], i32 0
+; CHECK-NEXT:    [[BO:%.*]] = sdiv <2 x i8> <i8 5, i8 2>, [[INS]]
+; CHECK-NEXT:    ret <2 x i8> [[BO]]
+;
+  %ins = insertelement <2 x i8> undef, i8 %x, i32 0
+  %bo = sdiv <2 x i8> <i8 5, i8 2>, %ins
+  ret <2 x i8> %bo
+}
+
+define <2 x i8> @sdiv_constant_op1(i8 %x) {
+; CHECK-LABEL: @sdiv_constant_op1(
+; CHECK-NEXT:    ret <2 x i8> undef
+;
+  %ins = insertelement <2 x i8> undef, i8 %x, i32 1
+  %bo = sdiv exact <2 x i8> %ins, <i8 undef, i8 2>
+  ret <2 x i8> %bo
+}
+
+define <2 x i8> @sdiv_constant_op1_not_undef_lane(i8 %x) {
+; CHECK-LABEL: @sdiv_constant_op1_not_undef_lane(
+; CHECK-NEXT:    [[INS:%.*]] = insertelement <2 x i8> undef, i8 [[X:%.*]], i32 1
+; CHECK-NEXT:    [[BO:%.*]] = sdiv exact <2 x i8> [[INS]], <i8 5, i8 2>
+; CHECK-NEXT:    ret <2 x i8> [[BO]]
+;
+  %ins = insertelement <2 x i8> undef, i8 %x, i32 1
+  %bo = sdiv exact <2 x i8> %ins, <i8 5, i8 2>
+  ret <2 x i8> %bo
+}
+
+define <2 x i8> @and_constant(i8 %x) {
+; CHECK-LABEL: @and_constant(
+; CHECK-NEXT:    [[INS:%.*]] = insertelement <2 x i8> undef, i8 [[X:%.*]], i32 0
+; CHECK-NEXT:    [[BO:%.*]] = and <2 x i8> [[INS]], <i8 42, i8 undef>
+; CHECK-NEXT:    ret <2 x i8> [[BO]]
+;
+  %ins = insertelement <2 x i8> undef, i8 %x, i32 0
+  %bo = and <2 x i8> %ins, <i8 42, i8 undef>
+  ret <2 x i8> %bo
+}
+
+define <2 x i8> @and_constant_not_undef_lane(i8 %x) {
+; CHECK-LABEL: @and_constant_not_undef_lane(
+; CHECK-NEXT:    [[INS:%.*]] = insertelement <2 x i8> undef, i8 [[X:%.*]], i32 0
+; CHECK-NEXT:    [[BO:%.*]] = and <2 x i8> [[INS]], <i8 42, i8 -42>
+; CHECK-NEXT:    ret <2 x i8> [[BO]]
+;
+  %ins = insertelement <2 x i8> undef, i8 %x, i32 0
+  %bo = and <2 x i8> %ins, <i8 42, i8 -42>
+  ret <2 x i8> %bo
+}
+
+define <2 x i8> @or_constant(i8 %x) {
+; CHECK-LABEL: @or_constant(
+; CHECK-NEXT:    [[INS:%.*]] = insertelement <2 x i8> undef, i8 [[X:%.*]], i32 1
+; CHECK-NEXT:    [[BO:%.*]] = or <2 x i8> [[INS]], <i8 undef, i8 -42>
+; CHECK-NEXT:    ret <2 x i8> [[BO]]
+;
+  %ins = insertelement <2 x i8> undef, i8 %x, i32 1
+  %bo = or <2 x i8> %ins, <i8 undef, i8 -42>
+  ret <2 x i8> %bo
+}
+
+define <2 x i8> @or_constant_not_undef_lane(i8 %x) {
+; CHECK-LABEL: @or_constant_not_undef_lane(
+; CHECK-NEXT:    [[INS:%.*]] = insertelement <2 x i8> undef, i8 [[X:%.*]], i32 1
+; CHECK-NEXT:    [[BO:%.*]] = or <2 x i8> [[INS]], <i8 42, i8 -42>
+; CHECK-NEXT:    ret <2 x i8> [[BO]]
+;
+  %ins = insertelement <2 x i8> undef, i8 %x, i32 1
+  %bo = or <2 x i8> %ins, <i8 42, i8 -42>
+  ret <2 x i8> %bo
+}
+
+define <2 x i8> @xor_constant(i8 %x) {
+; CHECK-LABEL: @xor_constant(
+; CHECK-NEXT:    [[INS:%.*]] = insertelement <2 x i8> undef, i8 [[X:%.*]], i32 0
+; CHECK-NEXT:    [[BO:%.*]] = xor <2 x i8> [[INS]], <i8 42, i8 undef>
+; CHECK-NEXT:    ret <2 x i8> [[BO]]
+;
+  %ins = insertelement <2 x i8> undef, i8 %x, i32 0
+  %bo = xor <2 x i8> %ins, <i8 42, i8 undef>
+  ret <2 x i8> %bo
+}
+
+define <2 x i8> @xor_constant_not_undef_lane(i8 %x) {
+; CHECK-LABEL: @xor_constant_not_undef_lane(
+; CHECK-NEXT:    [[INS:%.*]] = insertelement <2 x i8> undef, i8 [[X:%.*]], i32 0
+; CHECK-NEXT:    [[BO:%.*]] = xor <2 x i8> [[INS]], <i8 42, i8 -42>
+; CHECK-NEXT:    ret <2 x i8> [[BO]]
+;
+  %ins = insertelement <2 x i8> undef, i8 %x, i32 0
+  %bo = xor <2 x i8> %ins, <i8 42, i8 -42>
+  ret <2 x i8> %bo
+}
+
+define <2 x float> @fadd_constant(float %x) {
+; CHECK-LABEL: @fadd_constant(
+; CHECK-NEXT:    [[INS:%.*]] = insertelement <2 x float> undef, float [[X:%.*]], i32 0
+; CHECK-NEXT:    [[BO:%.*]] = fadd <2 x float> [[INS]], <float 4.200000e+01, float undef>
+; CHECK-NEXT:    ret <2 x float> [[BO]]
+;
+  %ins = insertelement <2 x float> undef, float %x, i32 0
+  %bo = fadd <2 x float> %ins, <float 42.0, float undef>
+  ret <2 x float> %bo
+}
+
+define <2 x float> @fadd_constant_not_undef_lane(float %x) {
+; CHECK-LABEL: @fadd_constant_not_undef_lane(
+; CHECK-NEXT:    [[INS:%.*]] = insertelement <2 x float> undef, float [[X:%.*]], i32 1
+; CHECK-NEXT:    [[BO:%.*]] = fadd <2 x float> [[INS]], <float 4.200000e+01, float -4.200000e+01>
+; CHECK-NEXT:    ret <2 x float> [[BO]]
+;
+  %ins = insertelement <2 x float> undef, float %x, i32 1
+  %bo = fadd <2 x float> %ins, <float 42.0, float -42.0>
+  ret <2 x float> %bo
+}
+
+define <2 x float> @fsub_constant_op0(float %x) {
+; CHECK-LABEL: @fsub_constant_op0(
+; CHECK-NEXT:    [[INS:%.*]] = insertelement <2 x float> undef, float [[X:%.*]], i32 0
+; CHECK-NEXT:    [[BO:%.*]] = fsub fast <2 x float> <float 4.200000e+01, float undef>, [[INS]]
+; CHECK-NEXT:    ret <2 x float> [[BO]]
+;
+  %ins = insertelement <2 x float> undef, float %x, i32 0
+  %bo = fsub fast <2 x float> <float 42.0, float undef>, %ins
+  ret <2 x float> %bo
+}
+
+define <2 x float> @fsub_constant_op0_not_undef_lane(float %x) {
+; CHECK-LABEL: @fsub_constant_op0_not_undef_lane(
+; CHECK-NEXT:    [[INS:%.*]] = insertelement <2 x float> undef, float [[X:%.*]], i32 1
+; CHECK-NEXT:    [[BO:%.*]] = fsub nsz <2 x float> <float 4.200000e+01, float -4.200000e+01>, [[INS]]
+; CHECK-NEXT:    ret <2 x float> [[BO]]
+;
+  %ins = insertelement <2 x float> undef, float %x, i32 1
+  %bo = fsub nsz <2 x float> <float 42.0, float -42.0>, %ins
+  ret <2 x float> %bo
+}
+
+define <2 x float> @fsub_constant_op1(float %x) {
+; CHECK-LABEL: @fsub_constant_op1(
+; CHECK-NEXT:    [[INS:%.*]] = insertelement <2 x float> undef, float [[X:%.*]], i32 1
+; CHECK-NEXT:    [[BO:%.*]] = fadd <2 x float> [[INS]], <float 0x7FF8000000000000, float -4.200000e+01>
+; CHECK-NEXT:    ret <2 x float> [[BO]]
+;
+  %ins = insertelement <2 x float> undef, float %x, i32 1
+  %bo = fsub <2 x float> %ins, <float undef, float 42.0>
+  ret <2 x float> %bo
+}
+
+define <2 x float> @fsub_constant_op1_not_undef_lane(float %x) {
+; CHECK-LABEL: @fsub_constant_op1_not_undef_lane(
+; CHECK-NEXT:    [[INS:%.*]] = insertelement <2 x float> undef, float [[X:%.*]], i32 0
+; CHECK-NEXT:    [[BO:%.*]] = fadd <2 x float> [[INS]], <float -4.200000e+01, float 4.200000e+01>
+; CHECK-NEXT:    ret <2 x float> [[BO]]
+;
+  %ins = insertelement <2 x float> undef, float %x, i32 0
+  %bo = fsub <2 x float> %ins, <float 42.0, float -42.0>
+  ret <2 x float> %bo
+}
+
+define <2 x float> @fmul_constant(float %x) {
+; CHECK-LABEL: @fmul_constant(
+; CHECK-NEXT:    [[INS:%.*]] = insertelement <2 x float> undef, float [[X:%.*]], i32 0
+; CHECK-NEXT:    [[BO:%.*]] = fmul reassoc <2 x float> [[INS]], <float 4.200000e+01, float undef>
+; CHECK-NEXT:    ret <2 x float> [[BO]]
+;
+  %ins = insertelement <2 x float> undef, float %x, i32 0
+  %bo = fmul reassoc <2 x float> %ins, <float 42.0, float undef>
+  ret <2 x float> %bo
+}
+
+define <2 x float> @fmul_constant_not_undef_lane(float %x) {
+; CHECK-LABEL: @fmul_constant_not_undef_lane(
+; CHECK-NEXT:    [[INS:%.*]] = insertelement <2 x float> undef, float [[X:%.*]], i32 1
+; CHECK-NEXT:    [[BO:%.*]] = fmul <2 x float> [[INS]], <float 4.200000e+01, float -4.200000e+01>
+; CHECK-NEXT:    ret <2 x float> [[BO]]
+;
+  %ins = insertelement <2 x float> undef, float %x, i32 1
+  %bo = fmul <2 x float> %ins, <float 42.0, float -42.0>
+  ret <2 x float> %bo
+}
+
+define <2 x float> @fdiv_constant_op0(float %x) {
+; CHECK-LABEL: @fdiv_constant_op0(
+; CHECK-NEXT:    [[INS:%.*]] = insertelement <2 x float> undef, float [[X:%.*]], i32 1
+; CHECK-NEXT:    [[BO:%.*]] = fdiv nnan <2 x float> <float undef, float 4.200000e+01>, [[INS]]
+; CHECK-NEXT:    ret <2 x float> [[BO]]
+;
+  %ins = insertelement <2 x float> undef, float %x, i32 1
+  %bo = fdiv nnan <2 x float> <float undef, float 42.0>, %ins
+  ret <2 x float> %bo
+}
+
+define <2 x float> @fdiv_constant_op0_not_undef_lane(float %x) {
+; CHECK-LABEL: @fdiv_constant_op0_not_undef_lane(
+; CHECK-NEXT:    [[INS:%.*]] = insertelement <2 x float> undef, float [[X:%.*]], i32 0
+; CHECK-NEXT:    [[BO:%.*]] = fdiv ninf <2 x float> <float 4.200000e+01, float -4.200000e+01>, [[INS]]
+; CHECK-NEXT:    ret <2 x float> [[BO]]
+;
+  %ins = insertelement <2 x float> undef, float %x, i32 0
+  %bo = fdiv ninf <2 x float> <float 42.0, float -42.0>, %ins
+  ret <2 x float> %bo
+}
+
+define <2 x float> @fdiv_constant_op1(float %x) {
+; CHECK-LABEL: @fdiv_constant_op1(
+; CHECK-NEXT:    [[INS:%.*]] = insertelement <2 x float> undef, float [[X:%.*]], i32 0
+; CHECK-NEXT:    [[BO:%.*]] = fdiv <2 x float> [[INS]], <float 4.200000e+01, float undef>
+; CHECK-NEXT:    ret <2 x float> [[BO]]
+;
+  %ins = insertelement <2 x float> undef, float %x, i32 0
+  %bo = fdiv <2 x float> %ins, <float 42.0, float undef>
+  ret <2 x float> %bo
+}
+
+define <2 x float> @fdiv_constant_op1_not_undef_lane(float %x) {
+; CHECK-LABEL: @fdiv_constant_op1_not_undef_lane(
+; CHECK-NEXT:    [[INS:%.*]] = insertelement <2 x float> undef, float [[X:%.*]], i32 0
+; CHECK-NEXT:    [[BO:%.*]] = fdiv <2 x float> [[INS]], <float 4.200000e+01, float -4.200000e+01>
+; CHECK-NEXT:    ret <2 x float> [[BO]]
+;
+  %ins = insertelement <2 x float> undef, float %x, i32 0
+  %bo = fdiv <2 x float> %ins, <float 42.0, float -42.0>
+  ret <2 x float> %bo
+}
+
+define <2 x float> @frem_constant_op0(float %x) {
+; CHECK-LABEL: @frem_constant_op0(
+; CHECK-NEXT:    [[INS:%.*]] = insertelement <2 x float> undef, float [[X:%.*]], i32 0
+; CHECK-NEXT:    [[BO:%.*]] = frem fast <2 x float> <float 4.200000e+01, float undef>, [[INS]]
+; CHECK-NEXT:    ret <2 x float> [[BO]]
+;
+  %ins = insertelement <2 x float> undef, float %x, i32 0
+  %bo = frem fast <2 x float> <float 42.0, float undef>, %ins
+  ret <2 x float> %bo
+}
+
+define <2 x float> @frem_constant_op0_not_undef_lane(float %x) {
+; CHECK-LABEL: @frem_constant_op0_not_undef_lane(
+; CHECK-NEXT:    [[INS:%.*]] = insertelement <2 x float> undef, float [[X:%.*]], i32 1
+; CHECK-NEXT:    [[BO:%.*]] = frem <2 x float> <float 4.200000e+01, float -4.200000e+01>, [[INS]]
+; CHECK-NEXT:    ret <2 x float> [[BO]]
+;
+  %ins = insertelement <2 x float> undef, float %x, i32 1
+  %bo = frem <2 x float> <float 42.0, float -42.0>, %ins
+  ret <2 x float> %bo
+}
+
+define <2 x float> @frem_constant_op1(float %x) {
+; CHECK-LABEL: @frem_constant_op1(
+; CHECK-NEXT:    [[INS:%.*]] = insertelement <2 x float> undef, float [[X:%.*]], i32 1
+; CHECK-NEXT:    [[BO:%.*]] = frem ninf <2 x float> [[INS]], <float undef, float 4.200000e+01>
+; CHECK-NEXT:    ret <2 x float> [[BO]]
+;
+  %ins = insertelement <2 x float> undef, float %x, i32 1
+  %bo = frem ninf <2 x float> %ins, <float undef, float 42.0>
+  ret <2 x float> %bo
+}
+
+define <2 x float> @frem_constant_op1_not_undef_lane(float %x) {
+; CHECK-LABEL: @frem_constant_op1_not_undef_lane(
+; CHECK-NEXT:    [[INS:%.*]] = insertelement <2 x float> undef, float [[X:%.*]], i32 0
+; CHECK-NEXT:    [[BO:%.*]] = frem nnan <2 x float> [[INS]], <float 4.200000e+01, float -4.200000e+01>
+; CHECK-NEXT:    ret <2 x float> [[BO]]
+;
+  %ins = insertelement <2 x float> undef, float %x, i32 0
+  %bo = frem nnan <2 x float> %ins, <float 42.0, float -42.0>
+  ret <2 x float> %bo
+}
+

Added: llvm/trunk/test/Transforms/InstCombine/insert-const-shuf.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/insert-const-shuf.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/insert-const-shuf.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/insert-const-shuf.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,118 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt -S -instcombine %s | FileCheck %s
+
+; Eliminate the insertelement.
+
+define <4 x float> @PR29126(<4 x float> %x) {
+; CHECK-LABEL: @PR29126(
+; CHECK-NEXT:    [[INS:%.*]] = shufflevector <4 x float> %x, <4 x float> <float undef, float 1.000000e+00, float 2.000000e+00, float 4.200000e+01>, <4 x i32> <i32 0, i32 5, i32 6, i32 7>
+; CHECK-NEXT:    ret <4 x float> [[INS]]
+;
+  %shuf = shufflevector <4 x float> %x, <4 x float> <float undef, float 1.0, float 2.0, float undef>, <4 x i32> <i32 0, i32 5, i32 6, i32 3>
+  %ins = insertelement <4 x float> %shuf, float 42.0, i32 3
+  ret <4 x float> %ins
+}
+
+; A chain of inserts should collapse.
+
+define <4 x float> @twoInserts(<4 x float> %x) {
+; CHECK-LABEL: @twoInserts(
+; CHECK-NEXT:    [[INS2:%.*]] = shufflevector <4 x float> %x, <4 x float> <float undef, float 0.000000e+00, float 4.200000e+01, float 1.100000e+01>, <4 x i32> <i32 0, i32 5, i32 6, i32 7>
+; CHECK-NEXT:    ret <4 x float> [[INS2]]
+;
+  %shuf = shufflevector <4 x float> %x, <4 x float> zeroinitializer, <4 x i32> <i32 0, i32 5, i32 6, i32 3>
+  %ins1 = insertelement <4 x float> %shuf, float 42.0, i32 2
+  %ins2 = insertelement <4 x float> %ins1, float 11.0, i32 3
+  ret <4 x float> %ins2
+}
+
+define <4 x i32> @shuffleRetain(<4 x i32> %base) {
+; CHECK-LABEL: @shuffleRetain(
+; CHECK-NEXT:  [[SHUF:%.*]] = shufflevector <4 x i32> %base, <4 x i32> <i32 undef, i32 undef, i32 undef, i32 1>, <4 x i32> <i32 1, i32 2, i32 undef, i32 7>
+; CHECK-NEXT:  ret <4 x i32> [[SHUF]]
+;
+  %shuf = shufflevector <4 x i32> %base, <4 x i32> <i32 4, i32 3, i32 2, i32 1>, <4 x i32> <i32 1, i32 2, i32 undef, i32 7>
+  ret <4 x i32> %shuf
+}
+
+; TODO: Transform an arbitrary shuffle with constant into a shuffle that is equivalant to a vector select.
+
+define <4 x float> @disguisedSelect(<4 x float> %x) {
+; CHECK-LABEL: @disguisedSelect(
+; CHECK-NEXT:    [[SHUF:%.*]] = shufflevector <4 x float> %x, <4 x float> <float undef, float 1.000000e+00, float 2.000000e+00, float undef>, <4 x i32> <i32 undef, i32 6, i32 5, i32 3>
+; CHECK-NEXT:    [[INS:%.*]] = insertelement <4 x float> [[SHUF]], float 4.000000e+00, i32 0
+; CHECK-NEXT:    ret <4 x float> [[INS]]
+;
+  %shuf = shufflevector <4 x float> %x, <4 x float> <float undef, float 1.0, float 2.0, float 3.0>, <4 x i32> <i32 7, i32 6, i32 5, i32 3>
+  %ins = insertelement <4 x float> %shuf, float 4.0, i32 0
+  ret <4 x float> %ins
+}
+
+; TODO: Fold arbitrary (non-select-equivalent) shuffles if the new shuffle would have the same shuffle mask.
+
+define <4 x float> @notSelectButNoMaskDifference(<4 x float> %x) {
+; CHECK-LABEL: @notSelectButNoMaskDifference(
+; CHECK-NEXT:    [[SHUF:%.*]] = shufflevector <4 x float> %x, <4 x float> <float undef, float 1.000000e+00, float 2.000000e+00, float undef>, <4 x i32> <i32 1, i32 5, i32 6, i32 undef>
+; CHECK-NEXT:    [[INS:%.*]] = insertelement <4 x float> [[SHUF]], float 4.000000e+00, i32 3
+; CHECK-NEXT:    ret <4 x float> [[INS]]
+;
+  %shuf = shufflevector <4 x float> %x, <4 x float> <float undef, float 1.0, float 2.0, float 3.0>, <4 x i32> <i32 1, i32 5, i32 6, i32 3>
+  %ins = insertelement <4 x float> %shuf, float 4.0, i32 3
+  ret <4 x float> %ins
+}
+
+; We purposely do not touch arbitrary (non-select-equivalent) shuffles because folding the insert may create a more expensive shuffle.
+
+define <4 x float> @tooRisky(<4 x float> %x) {
+; CHECK-LABEL: @tooRisky(
+; CHECK-NEXT:    [[SHUF:%.*]] = shufflevector <4 x float> %x, <4 x float> <float 1.000000e+00, float undef, float undef, float undef>, <4 x i32> <i32 1, i32 4, i32 4, i32 undef>
+; CHECK-NEXT:    [[INS:%.*]] = insertelement <4 x float> [[SHUF]], float 4.000000e+00, i32 3
+; CHECK-NEXT:    ret <4 x float> [[INS]]
+;
+  %shuf = shufflevector <4 x float> %x, <4 x float> <float 1.0, float undef, float undef, float undef>, <4 x i32> <i32 1, i32 4, i32 4, i32 4>
+  %ins = insertelement <4 x float> %shuf, float 4.0, i32 3
+  ret <4 x float> %ins
+}
+
+; Don't transform insert to shuffle if the original shuffle is not removed.
+; TODO: Ease the one-use restriction if the insert scalar would simplify the shuffle to a full vector constant?
+
+define <3 x float> @twoShufUses(<3 x float> %x) {
+; CHECK-LABEL: @twoShufUses(
+; CHECK-NEXT:    [[SHUF:%.*]] = shufflevector <3 x float> %x, <3 x float> <float undef, float 1.000000e+00, float 2.000000e+00>, <3 x i32> <i32 0, i32 4, i32 5>
+; CHECK-NEXT:    [[INS:%.*]] = insertelement <3 x float> [[SHUF]], float 4.200000e+01, i2 1
+; CHECK-NEXT:    [[ADD:%.*]] = fadd <3 x float> [[SHUF]], [[INS]]
+; CHECK-NEXT:    ret <3 x float> [[ADD]]
+;
+  %shuf = shufflevector <3 x float> %x, <3 x float> <float undef, float 1.0, float 2.0>, <3 x i32> <i32 0, i32 4, i32 5>
+  %ins = insertelement <3 x float> %shuf, float 42.0, i2 1
+  %add = fadd <3 x float> %shuf, %ins
+  ret <3 x float> %add
+}
+
+; The inserted scalar constant index is out-of-bounds for the shuffle vector constant.
+
+define <5 x i8> @longerMask(<3 x i8> %x) {
+; CHECK-LABEL: @longerMask(
+; CHECK-NEXT:    [[SHUF:%.*]] = shufflevector <3 x i8> %x, <3 x i8> <i8 undef, i8 1, i8 undef>, <5 x i32> <i32 2, i32 1, i32 4, i32 undef, i32 undef>
+; CHECK-NEXT:    [[INS:%.*]] = insertelement <5 x i8> [[SHUF]], i8 42, i17 4
+; CHECK-NEXT:    ret <5 x i8> [[INS]]
+;
+  %shuf = shufflevector <3 x i8> %x, <3 x i8> <i8 undef, i8 1, i8 2>, <5 x i32> <i32 2, i32 1, i32 4, i32 3, i32 0>
+  %ins = insertelement <5 x i8> %shuf, i8 42, i17 4
+  ret <5 x i8> %ins
+}
+
+; TODO: The inserted constant could get folded into the shuffle vector constant.
+
+define <3 x i8> @shorterMask(<5 x i8> %x) {
+; CHECK-LABEL: @shorterMask(
+; CHECK-NEXT:    [[SHUF:%.*]] = shufflevector <5 x i8> %x, <5 x i8> undef, <3 x i32> <i32 undef, i32 1, i32 4>
+; CHECK-NEXT:    [[INS:%.*]] = insertelement <3 x i8> [[SHUF]], i8 42, i21 0
+; CHECK-NEXT:    ret <3 x i8> [[INS]]
+;
+  %shuf = shufflevector <5 x i8> %x, <5 x i8> <i8 undef, i8 1, i8 2, i8 3, i8 4>, <3 x i32> <i32 2, i32 1, i32 4>
+  %ins = insertelement <3 x i8> %shuf, i8 42, i21 0
+  ret <3 x i8> %ins
+}
+

Added: llvm/trunk/test/Transforms/InstCombine/insert-extract-shuffle.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/insert-extract-shuffle.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/insert-extract-shuffle.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/insert-extract-shuffle.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,427 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt -S -instcombine %s | FileCheck %s
+
+define <1 x i8> @test1(<8 x i8> %in) {
+; CHECK-LABEL: @test1(
+; CHECK-NEXT:    [[VEC:%.*]] = shufflevector <8 x i8> [[IN:%.*]], <8 x i8> undef, <1 x i32> <i32 5>
+; CHECK-NEXT:    ret <1 x i8> [[VEC]]
+;
+  %val = extractelement <8 x i8> %in, i32 5
+  %vec = insertelement <1 x i8> undef, i8 %val, i32 0
+  ret <1 x i8> %vec
+}
+
+define <4 x i16> @test2(<8 x i16> %in, <8 x i16> %in2) {
+; CHECK-LABEL: @test2(
+; CHECK-NEXT:    [[VEC_3:%.*]] = shufflevector <8 x i16> [[IN2:%.*]], <8 x i16> [[IN:%.*]], <4 x i32> <i32 11, i32 9, i32 0, i32 10>
+; CHECK-NEXT:    ret <4 x i16> [[VEC_3]]
+;
+  %elt0 = extractelement <8 x i16> %in, i32 3
+  %elt1 = extractelement <8 x i16> %in, i32 1
+  %elt2 = extractelement <8 x i16> %in2, i32 0
+  %elt3 = extractelement <8 x i16> %in, i32 2
+
+  %vec.0 = insertelement <4 x i16> undef, i16 %elt0, i32 0
+  %vec.1 = insertelement <4 x i16> %vec.0, i16 %elt1, i32 1
+  %vec.2 = insertelement <4 x i16> %vec.1, i16 %elt2, i32 2
+  %vec.3 = insertelement <4 x i16> %vec.2, i16 %elt3, i32 3
+
+  ret <4 x i16> %vec.3
+}
+
+define <2 x i64> @test_vcopyq_lane_p64(<2 x i64> %a, <1 x i64> %b) {
+; CHECK-LABEL: @test_vcopyq_lane_p64(
+; CHECK-NEXT:    [[TMP1:%.*]] = shufflevector <1 x i64> [[B:%.*]], <1 x i64> undef, <2 x i32> <i32 0, i32 undef>
+; CHECK-NEXT:    [[RES:%.*]] = shufflevector <2 x i64> [[A:%.*]], <2 x i64> [[TMP1]], <2 x i32> <i32 0, i32 2>
+; CHECK-NEXT:    ret <2 x i64> [[RES]]
+;
+  %elt = extractelement <1 x i64> %b, i32 0
+  %res = insertelement <2 x i64> %a, i64 %elt, i32 1
+  ret <2 x i64> %res
+}
+
+; PR2109: https://llvm.org/bugs/show_bug.cgi?id=2109
+
+define <4 x float> @widen_extract2(<4 x float> %ins, <2 x float> %ext) {
+; CHECK-LABEL: @widen_extract2(
+; CHECK-NEXT:    [[TMP1:%.*]] = shufflevector <2 x float> [[EXT:%.*]], <2 x float> undef, <4 x i32> <i32 0, i32 1, i32 undef, i32 undef>
+; CHECK-NEXT:    [[I2:%.*]] = shufflevector <4 x float> [[INS:%.*]], <4 x float> [[TMP1]], <4 x i32> <i32 0, i32 4, i32 2, i32 5>
+; CHECK-NEXT:    ret <4 x float> [[I2]]
+;
+  %e1 = extractelement <2 x float> %ext, i32 0
+  %e2 = extractelement <2 x float> %ext, i32 1
+  %i1 = insertelement <4 x float> %ins, float %e1, i32 1
+  %i2 = insertelement <4 x float> %i1, float %e2, i32 3
+  ret <4 x float> %i2
+}
+
+define <4 x float> @widen_extract3(<4 x float> %ins, <3 x float> %ext) {
+; CHECK-LABEL: @widen_extract3(
+; CHECK-NEXT:    [[TMP1:%.*]] = shufflevector <3 x float> [[EXT:%.*]], <3 x float> undef, <4 x i32> <i32 0, i32 1, i32 2, i32 undef>
+; CHECK-NEXT:    [[I3:%.*]] = shufflevector <4 x float> [[INS:%.*]], <4 x float> [[TMP1]], <4 x i32> <i32 6, i32 5, i32 4, i32 3>
+; CHECK-NEXT:    ret <4 x float> [[I3]]
+;
+  %e1 = extractelement <3 x float> %ext, i32 0
+  %e2 = extractelement <3 x float> %ext, i32 1
+  %e3 = extractelement <3 x float> %ext, i32 2
+  %i1 = insertelement <4 x float> %ins, float %e1, i32 2
+  %i2 = insertelement <4 x float> %i1, float %e2, i32 1
+  %i3 = insertelement <4 x float> %i2, float %e3, i32 0
+  ret <4 x float> %i3
+}
+
+define <8 x float> @widen_extract4(<8 x float> %ins, <2 x float> %ext) {
+; CHECK-LABEL: @widen_extract4(
+; CHECK-NEXT:    [[TMP1:%.*]] = shufflevector <2 x float> [[EXT:%.*]], <2 x float> undef, <8 x i32> <i32 0, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef>
+; CHECK-NEXT:    [[I1:%.*]] = shufflevector <8 x float> [[INS:%.*]], <8 x float> [[TMP1]], <8 x i32> <i32 0, i32 1, i32 8, i32 3, i32 4, i32 5, i32 6, i32 7>
+; CHECK-NEXT:    ret <8 x float> [[I1]]
+;
+  %e1 = extractelement <2 x float> %ext, i32 0
+  %i1 = insertelement <8 x float> %ins, float %e1, i32 2
+  ret <8 x float> %i1
+}
+
+; PR26015: https://llvm.org/bugs/show_bug.cgi?id=26015
+; The widening shuffle must be inserted before any uses.
+
+define <8 x i16> @pr26015(<4 x i16> %t0) {
+; CHECK-LABEL: @pr26015(
+; CHECK-NEXT:    [[TMP1:%.*]] = shufflevector <4 x i16> [[T0:%.*]], <4 x i16> undef, <8 x i32> <i32 undef, i32 undef, i32 2, i32 3, i32 undef, i32 undef, i32 undef, i32 undef>
+; CHECK-NEXT:    [[T5:%.*]] = shufflevector <8 x i16> <i16 0, i16 0, i16 0, i16 undef, i16 0, i16 0, i16 0, i16 undef>, <8 x i16> [[TMP1]], <8 x i32> <i32 0, i32 1, i32 2, i32 10, i32 4, i32 5, i32 6, i32 11>
+; CHECK-NEXT:    ret <8 x i16> [[T5]]
+;
+  %t1 = extractelement <4 x i16> %t0, i32 2
+  %t2 = insertelement <8 x i16> zeroinitializer, i16 %t1, i32 3
+  %t3 = insertelement <8 x i16> %t2, i16 0, i32 6
+  %t4 = extractelement <4 x i16> %t0, i32 3
+  %t5 = insertelement <8 x i16> %t3, i16 %t4, i32 7
+  ret <8 x i16> %t5
+}
+
+; PR25999: https://llvm.org/bugs/show_bug.cgi?id=25999
+; TODO: The widening shuffle could be inserted at the start of the function to allow the first extract to use it.
+
+define <8 x i16> @pr25999(<4 x i16> %t0, i1 %b) {
+; CHECK-LABEL: @pr25999(
+; CHECK-NEXT:    [[T1:%.*]] = extractelement <4 x i16> [[T0:%.*]], i32 2
+; CHECK-NEXT:    br i1 [[B:%.*]], label [[IF:%.*]], label [[END:%.*]]
+; CHECK:       if:
+; CHECK-NEXT:    [[TMP1:%.*]] = shufflevector <4 x i16> [[T0]], <4 x i16> undef, <8 x i32> <i32 undef, i32 undef, i32 undef, i32 3, i32 undef, i32 undef, i32 undef, i32 undef>
+; CHECK-NEXT:    [[T3:%.*]] = insertelement <8 x i16> <i16 0, i16 0, i16 0, i16 undef, i16 0, i16 0, i16 0, i16 undef>, i16 [[T1]], i32 3
+; CHECK-NEXT:    [[T5:%.*]] = shufflevector <8 x i16> [[T3]], <8 x i16> [[TMP1]], <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 11>
+; CHECK-NEXT:    ret <8 x i16> [[T5]]
+; CHECK:       end:
+; CHECK-NEXT:    [[A1:%.*]] = add i16 [[T1]], 4
+; CHECK-NEXT:    [[T6:%.*]] = insertelement <8 x i16> <i16 undef, i16 0, i16 0, i16 0, i16 0, i16 0, i16 0, i16 0>, i16 [[A1]], i32 0
+; CHECK-NEXT:    ret <8 x i16> [[T6]]
+;
+
+  %t1 = extractelement <4 x i16> %t0, i32 2
+  br i1 %b, label %if, label %end
+
+if:
+  %t2 = insertelement <8 x i16> zeroinitializer, i16 %t1, i32 3
+  %t3 = insertelement <8 x i16> %t2, i16 0, i32 6
+  %t4 = extractelement <4 x i16> %t0, i32 3
+  %t5 = insertelement <8 x i16> %t3, i16 %t4, i32 7
+  ret <8 x i16> %t5
+
+end:
+  %a1 = add i16 %t1, 4
+  %t6 = insertelement <8 x i16> zeroinitializer, i16 %a1, i32 0
+  ret <8 x i16> %t6
+}
+
+; The widening shuffle must be inserted at a valid point (after the PHIs).
+
+define <4 x double> @pr25999_phis1(i1 %c, <2 x double> %a, <4 x double> %b) {
+; CHECK-LABEL: @pr25999_phis1(
+; CHECK-NEXT:  bb1:
+; CHECK-NEXT:    br i1 [[C:%.*]], label [[BB2:%.*]], label [[BB3:%.*]]
+; CHECK:       bb2:
+; CHECK-NEXT:    [[R:%.*]] = call <2 x double> @dummy(<2 x double> [[A:%.*]])
+; CHECK-NEXT:    br label [[BB3]]
+; CHECK:       bb3:
+; CHECK-NEXT:    [[TMP1:%.*]] = phi <2 x double> [ [[A]], [[BB1:%.*]] ], [ [[R]], [[BB2]] ]
+; CHECK-NEXT:    [[TMP2:%.*]] = phi <4 x double> [ [[B:%.*]], [[BB1]] ], [ zeroinitializer, [[BB2]] ]
+; CHECK-NEXT:    [[TMP0:%.*]] = shufflevector <2 x double> [[TMP1]], <2 x double> undef, <4 x i32> <i32 0, i32 undef, i32 undef, i32 undef>
+; CHECK-NEXT:    [[TMP4:%.*]] = shufflevector <4 x double> [[TMP2]], <4 x double> [[TMP0]], <4 x i32> <i32 0, i32 1, i32 4, i32 3>
+; CHECK-NEXT:    ret <4 x double> [[TMP4]]
+;
+bb1:
+  br i1 %c, label %bb2, label %bb3
+
+bb2:
+  %r = call <2 x double> @dummy(<2 x double> %a)
+  br label %bb3
+
+bb3:
+  %tmp1 = phi <2 x double> [ %a, %bb1 ], [ %r, %bb2 ]
+  %tmp2 = phi <4 x double> [ %b, %bb1 ], [ zeroinitializer, %bb2 ]
+  %tmp3 = extractelement <2 x double> %tmp1, i32 0
+  %tmp4 = insertelement <4 x double> %tmp2, double %tmp3, i32 2
+  ret <4 x double> %tmp4
+}
+
+declare <2 x double> @dummy(<2 x double>)
+
+define <4 x double> @pr25999_phis2(i1 %c, <2 x double> %a, <4 x double> %b) {
+; CHECK-LABEL: @pr25999_phis2(
+; CHECK-NEXT:  bb1:
+; CHECK-NEXT:    br i1 [[C:%.*]], label [[BB2:%.*]], label [[BB3:%.*]]
+; CHECK:       bb2:
+; CHECK-NEXT:    [[R:%.*]] = call <2 x double> @dummy(<2 x double> [[A:%.*]])
+; CHECK-NEXT:    br label [[BB3]]
+; CHECK:       bb3:
+; CHECK-NEXT:    [[TMP1:%.*]] = phi <2 x double> [ [[A]], [[BB1:%.*]] ], [ [[R]], [[BB2]] ]
+; CHECK-NEXT:    [[TMP2:%.*]] = phi <4 x double> [ [[B:%.*]], [[BB1]] ], [ zeroinitializer, [[BB2]] ]
+; CHECK-NEXT:    [[D:%.*]] = fadd <2 x double> [[TMP1]], [[TMP1]]
+; CHECK-NEXT:    [[TMP0:%.*]] = shufflevector <2 x double> [[D]], <2 x double> undef, <4 x i32> <i32 0, i32 undef, i32 undef, i32 undef>
+; CHECK-NEXT:    [[TMP4:%.*]] = shufflevector <4 x double> [[TMP2]], <4 x double> [[TMP0]], <4 x i32> <i32 0, i32 1, i32 4, i32 3>
+; CHECK-NEXT:    ret <4 x double> [[TMP4]]
+;
+bb1:
+  br i1 %c, label %bb2, label %bb3
+
+bb2:
+  %r = call <2 x double> @dummy(<2 x double> %a)
+  br label %bb3
+
+bb3:
+  %tmp1 = phi <2 x double> [ %a, %bb1 ], [ %r, %bb2 ]
+  %tmp2 = phi <4 x double> [ %b, %bb1 ], [ zeroinitializer, %bb2 ]
+  %d = fadd <2 x double> %tmp1, %tmp1
+  %tmp3 = extractelement <2 x double> %d, i32 0
+  %tmp4 = insertelement <4 x double> %tmp2, double %tmp3, i32 2
+  ret <4 x double> %tmp4
+}
+
+; PR26354: https://llvm.org/bugs/show_bug.cgi?id=26354
+; Don't create a shufflevector if we know that we're not going to replace the insertelement.
+
+define double @pr26354(<2 x double>* %tmp, i1 %B) {
+; CHECK-LABEL: @pr26354(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[LD:%.*]] = load <2 x double>, <2 x double>* [[TMP:%.*]], align 16
+; CHECK-NEXT:    [[E1:%.*]] = extractelement <2 x double> [[LD]], i32 0
+; CHECK-NEXT:    br i1 [[B:%.*]], label [[IF:%.*]], label [[END:%.*]]
+; CHECK:       if:
+; CHECK-NEXT:    [[E2:%.*]] = extractelement <2 x double> [[LD]], i32 1
+; CHECK-NEXT:    [[I1:%.*]] = insertelement <4 x double> <double 0.000000e+00, double 0.000000e+00, double 0.000000e+00, double undef>, double [[E2]], i32 3
+; CHECK-NEXT:    br label [[END]]
+; CHECK:       end:
+; CHECK-NEXT:    [[PH:%.*]] = phi <4 x double> [ undef, [[ENTRY:%.*]] ], [ [[I1]], [[IF]] ]
+; CHECK-NEXT:    [[E3:%.*]] = extractelement <4 x double> [[PH]], i32 1
+; CHECK-NEXT:    [[MU:%.*]] = fmul double [[E1]], [[E3]]
+; CHECK-NEXT:    ret double [[MU]]
+;
+
+entry:
+  %ld = load <2 x double>, <2 x double>* %tmp
+  %e1 = extractelement <2 x double> %ld, i32 0
+  %e2 = extractelement <2 x double> %ld, i32 1
+  br i1 %B, label %if, label %end
+
+if:
+  %i1 = insertelement <4 x double> zeroinitializer, double %e2, i32 3
+  br label %end
+
+end:
+  %ph = phi <4 x double> [ undef, %entry ], [ %i1, %if ]
+  %e3 = extractelement <4 x double> %ph, i32 1
+  %mu = fmul double %e1, %e3
+  ret double %mu
+}
+
+; https://llvm.org/bugs/show_bug.cgi?id=30923
+; Delete the widening shuffle if we're not going to reduce the extract/insert to a shuffle.
+
+define <4 x float> @PR30923(<2 x float> %x) {
+; CHECK-LABEL: @PR30923(
+; CHECK-NEXT:  bb1:
+; CHECK-NEXT:    [[EXT1:%.*]] = extractelement <2 x float> [[X:%.*]], i32 1
+; CHECK-NEXT:    store float [[EXT1]], float* undef, align 4
+; CHECK-NEXT:    br label [[BB2:%.*]]
+; CHECK:       bb2:
+; CHECK-NEXT:    [[EXT2:%.*]] = extractelement <2 x float> [[X]], i32 0
+; CHECK-NEXT:    [[INS1:%.*]] = insertelement <4 x float> <float 0.000000e+00, float 0.000000e+00, float undef, float undef>, float [[EXT2]], i32 2
+; CHECK-NEXT:    [[INS2:%.*]] = insertelement <4 x float> [[INS1]], float [[EXT1]], i32 3
+; CHECK-NEXT:    ret <4 x float> [[INS2]]
+;
+bb1:
+  %ext1 = extractelement <2 x float> %x, i32 1
+  store float %ext1, float* undef, align 4
+  br label %bb2
+
+bb2:
+  %widen = shufflevector <2 x float> %x, <2 x float> undef, <4 x i32> <i32 0, i32 1, i32 undef, i32 undef>
+  %ext2 = extractelement <4 x float> %widen, i32 0
+  %ins1 = insertelement <4 x float> <float 0.0, float 0.0, float undef, float undef>, float %ext2, i32 2
+  %ins2 = insertelement <4 x float> %ins1, float %ext1, i32 3
+  ret <4 x float> %ins2
+}
+
+; Don't insert extractelements from the wider vector before the def of the index operand.
+
+define <4 x i32> @extractelt_insertion(<2 x i32> %x, i32 %y) {
+; CHECK-LABEL: @extractelt_insertion(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[TMP0:%.*]] = shufflevector <2 x i32> [[X:%.*]], <2 x i32> undef, <4 x i32> <i32 0, i32 1, i32 undef, i32 undef>
+; CHECK-NEXT:    [[B:%.*]] = shufflevector <4 x i32> <i32 0, i32 0, i32 0, i32 undef>, <4 x i32> [[TMP0]], <4 x i32> <i32 0, i32 1, i32 2, i32 5>
+; CHECK-NEXT:    [[C:%.*]] = add i32 [[Y:%.*]], 3
+; CHECK-NEXT:    [[TMP1:%.*]] = extractelement <4 x i32> [[TMP0]], i32 [[C]]
+; CHECK-NEXT:    [[E:%.*]] = icmp eq i32 [[TMP1]], 0
+; CHECK-NEXT:    [[RET:%.*]] = select i1 [[E]], <4 x i32> [[B]], <4 x i32> zeroinitializer
+; CHECK-NEXT:    ret <4 x i32> [[RET]]
+;
+entry:
+  %a = extractelement <2 x i32> %x, i32 1
+  %b = insertelement <4 x i32> zeroinitializer, i32 %a, i64 3
+  %c = add i32 %y, 3
+  %d = extractelement <2 x i32> %x, i32 %c
+  %e = icmp eq i32 %d, 0
+  %ret = select i1 %e, <4 x i32> %b, <4 x i32> zeroinitializer
+  ret <4 x i32> %ret
+}
+
+; PR34724: https://bugs.llvm.org/show_bug.cgi?id=34724
+
+define <4 x float> @collectShuffleElts(<2 x float> %x, float %y) {
+; CHECK-LABEL: @collectShuffleElts(
+; CHECK-NEXT:    [[X0:%.*]] = extractelement <2 x float> [[X:%.*]], i32 0
+; CHECK-NEXT:    [[X1:%.*]] = extractelement <2 x float> [[X]], i32 1
+; CHECK-NEXT:    [[V1:%.*]] = insertelement <4 x float> undef, float [[X0]], i32 1
+; CHECK-NEXT:    [[V2:%.*]] = insertelement <4 x float> [[V1]], float [[X1]], i32 2
+; CHECK-NEXT:    [[V3:%.*]] = insertelement <4 x float> [[V2]], float [[Y:%.*]], i32 3
+; CHECK-NEXT:    ret <4 x float> [[V3]]
+;
+  %x0 = extractelement <2 x float> %x, i32 0
+  %x1 = extractelement <2 x float> %x, i32 1
+  %v1 = insertelement <4 x float> undef, float %x0, i32 1
+  %v2 = insertelement <4 x float> %v1, float %x1, i32 2
+  %v3 = insertelement <4 x float> %v2, float %y, i32 3
+  ret <4 x float> %v3
+}
+
+; Simplest case - insert scalar into undef, then shuffle that value in place into another vector.
+
+define <4 x float> @insert_shuffle(float %x, <4 x float> %y) {
+; CHECK-LABEL: @insert_shuffle(
+; CHECK-NEXT:    [[R:%.*]] = insertelement <4 x float> [[Y:%.*]], float [[X:%.*]], i32 0
+; CHECK-NEXT:    ret <4 x float> [[R]]
+;
+  %xv = insertelement <4 x float> undef, float %x, i32 0
+  %r = shufflevector <4 x float> %xv, <4 x float> %y, <4 x i32> <i32 0, i32 5, i32 6, i32 7>
+  ret <4 x float> %r
+}
+
+; Insert scalar into some element of a dummy vector, then move it to a different element in another vector.
+
+define <4 x float> @insert_shuffle_translate(float %x, <4 x float> %y) {
+; CHECK-LABEL: @insert_shuffle_translate(
+; CHECK-NEXT:    [[R:%.*]] = insertelement <4 x float> [[Y:%.*]], float [[X:%.*]], i32 1
+; CHECK-NEXT:    ret <4 x float> [[R]]
+;
+  %xv = insertelement <4 x float> undef, float %x, i32 0
+  %r = shufflevector <4 x float> %xv, <4 x float> %y, <4 x i32> <i32 4, i32 0, i32 6, i32 7>
+  ret <4 x float> %r
+}
+
+; The vector operand of the insert is irrelevant.
+
+define <4 x float> @insert_not_undef_shuffle_translate(float %x, <4 x float> %y, <4 x float> %q) {
+; CHECK-LABEL: @insert_not_undef_shuffle_translate(
+; CHECK-NEXT:    [[R:%.*]] = insertelement <4 x float> [[Y:%.*]], float [[X:%.*]], i32 2
+; CHECK-NEXT:    ret <4 x float> [[R]]
+;
+  %xv = insertelement <4 x float> %q, float %x, i32 3
+  %r = shufflevector <4 x float> %xv, <4 x float> %y, <4 x i32> <i32 4, i32 5, i32 3, i32 7>
+  ret <4 x float> %r
+}
+
+; The insert may be the 2nd operand of the shuffle. The shuffle mask can include undef elements.
+
+define <4 x float> @insert_not_undef_shuffle_translate_commute(float %x, <4 x float> %y, <4 x float> %q) {
+; CHECK-LABEL: @insert_not_undef_shuffle_translate_commute(
+; CHECK-NEXT:    [[R:%.*]] = insertelement <4 x float> [[Y:%.*]], float [[X:%.*]], i32 1
+; CHECK-NEXT:    ret <4 x float> [[R]]
+;
+  %xv = insertelement <4 x float> %q, float %x, i32 2
+  %r = shufflevector <4 x float> %y, <4 x float> %xv, <4 x i32> <i32 0, i32 6, i32 2, i32 undef>
+  ret <4 x float> %r
+}
+
+; Both shuffle operands may be inserts - choose the correct side.
+
+define <4 x float> @insert_insert_shuffle_translate(float %x1, float %x2, <4 x float> %q) {
+; CHECK-LABEL: @insert_insert_shuffle_translate(
+; CHECK-NEXT:    [[XV2:%.*]] = insertelement <4 x float> [[Q:%.*]], float [[X2:%.*]], i32 2
+; CHECK-NEXT:    [[R:%.*]] = insertelement <4 x float> [[XV2]], float [[X1:%.*]], i32 1
+; CHECK-NEXT:    ret <4 x float> [[R]]
+;
+  %xv1 = insertelement <4 x float> %q, float %x1, i32 0
+  %xv2 = insertelement <4 x float> %q, float %x2, i32 2
+  %r = shufflevector <4 x float> %xv1, <4 x float> %xv2, <4 x i32> <i32 4, i32 0, i32 6, i32 7>
+  ret <4 x float> %r
+}
+
+; Both shuffle operands may be inserts - choose the correct side.
+
+define <4 x float> @insert_insert_shuffle_translate_commute(float %x1, float %x2, <4 x float> %q) {
+; CHECK-LABEL: @insert_insert_shuffle_translate_commute(
+; CHECK-NEXT:    [[XV1:%.*]] = insertelement <4 x float> [[Q:%.*]], float [[X1:%.*]], i32 0
+; CHECK-NEXT:    [[R:%.*]] = insertelement <4 x float> [[XV1]], float [[X2:%.*]], i32 1
+; CHECK-NEXT:    ret <4 x float> [[R]]
+;
+  %xv1 = insertelement <4 x float> %q, float %x1, i32 0
+  %xv2 = insertelement <4 x float> %q, float %x2, i32 2
+  %r = shufflevector <4 x float> %xv1, <4 x float> %xv2, <4 x i32> <i32 0, i32 6, i32 2, i32 3>
+  ret <4 x float> %r
+}
+
+; Negative test - this only works if the shuffle is choosing exactly 1 element from 1 of the inputs.
+; TODO: But this could be a special-case because we're inserting into the same base vector.
+
+define <4 x float> @insert_insert_shuffle_translate_wrong_mask(float %x1, float %x2, <4 x float> %q) {
+; CHECK-LABEL: @insert_insert_shuffle_translate_wrong_mask(
+; CHECK-NEXT:    [[XV1:%.*]] = insertelement <4 x float> [[Q:%.*]], float [[X1:%.*]], i32 0
+; CHECK-NEXT:    [[XV2:%.*]] = insertelement <4 x float> [[Q]], float [[X2:%.*]], i32 2
+; CHECK-NEXT:    [[R:%.*]] = shufflevector <4 x float> [[XV1]], <4 x float> [[XV2]], <4 x i32> <i32 0, i32 6, i32 2, i32 7>
+; CHECK-NEXT:    ret <4 x float> [[R]]
+;
+  %xv1 = insertelement <4 x float> %q, float %x1, i32 0
+  %xv2 = insertelement <4 x float> %q, float %x2, i32 2
+  %r = shufflevector <4 x float> %xv1, <4 x float> %xv2, <4 x i32> <i32 0, i32 6, i32 2, i32 7>
+  ret <4 x float> %r
+}
+
+; The insert may have other uses.
+
+declare void @use(<4 x float>)
+
+define <4 x float> @insert_not_undef_shuffle_translate_commute_uses(float %x, <4 x float> %y, <4 x float> %q) {
+; CHECK-LABEL: @insert_not_undef_shuffle_translate_commute_uses(
+; CHECK-NEXT:    [[XV:%.*]] = insertelement <4 x float> [[Q:%.*]], float [[X:%.*]], i32 2
+; CHECK-NEXT:    call void @use(<4 x float> [[XV]])
+; CHECK-NEXT:    [[R:%.*]] = insertelement <4 x float> [[Y:%.*]], float [[X]], i32 0
+; CHECK-NEXT:    ret <4 x float> [[R]]
+;
+  %xv = insertelement <4 x float> %q, float %x, i32 2
+  call void @use(<4 x float> %xv)
+  %r = shufflevector <4 x float> %y, <4 x float> %xv, <4 x i32> <i32 6, i32 undef, i32 2, i32 3>
+  ret <4 x float> %r
+}
+
+; Negative test - size-changing shuffle.
+
+define <5 x float> @insert_not_undef_shuffle_translate_commute_lengthen(float %x, <4 x float> %y, <4 x float> %q) {
+; CHECK-LABEL: @insert_not_undef_shuffle_translate_commute_lengthen(
+; CHECK-NEXT:    [[XV:%.*]] = insertelement <4 x float> undef, float [[X:%.*]], i32 2
+; CHECK-NEXT:    [[R:%.*]] = shufflevector <4 x float> [[Y:%.*]], <4 x float> [[XV]], <5 x i32> <i32 0, i32 6, i32 2, i32 undef, i32 undef>
+; CHECK-NEXT:    ret <5 x float> [[R]]
+;
+  %xv = insertelement <4 x float> %q, float %x, i32 2
+  %r = shufflevector <4 x float> %y, <4 x float> %xv, <5 x i32> <i32 0, i32 6, i32 2, i32 undef, i32 undef>
+  ret <5 x float> %r
+}
+

Added: llvm/trunk/test/Transforms/InstCombine/insert-val-extract-elem.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/insert-val-extract-elem.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/insert-val-extract-elem.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/insert-val-extract-elem.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,74 @@
+; RUN: opt -S -instcombine %s | FileCheck %s
+
+; CHECK-LABEL: julia_2xdouble
+; CHECK-NOT: insertvalue
+; CHECK-NOT: extractelement
+; CHECK: store <2 x double>
+define void @julia_2xdouble([2 x double]* sret, <2 x double>*) {
+top:
+  %x = load <2 x double>, <2 x double>* %1
+  %x0 = extractelement <2 x double> %x, i32 0
+  %i0 = insertvalue [2 x double] undef, double %x0, 0
+  %x1 = extractelement <2 x double> %x, i32 1
+  %i1 = insertvalue [2 x double] %i0, double %x1, 1
+  store [2 x double] %i1, [2 x double]* %0, align 4
+  ret void
+}
+
+; Test with two inserts to the same index
+; CHECK-LABEL: julia_2xi64
+; CHECK-NOT: insertvalue
+; CHECK-NOT: extractelement
+; CHECK: store <2 x i64>
+define void @julia_2xi64([2 x i64]* sret, <2 x i64>*) {
+top:
+  %x = load <2 x i64>, <2 x i64>* %1
+  %x0 = extractelement <2 x i64> %x, i32 1
+  %i0 = insertvalue [2 x i64] undef, i64 %x0, 0
+  %x1 = extractelement <2 x i64> %x, i32 1
+  %i1 = insertvalue [2 x i64] %i0, i64 %x1, 1
+  %x2 = extractelement <2 x i64> %x, i32 0
+  %i2 = insertvalue [2 x i64] %i1, i64 %x2, 0
+  store [2 x i64] %i2, [2 x i64]* %0, align 4
+  ret void
+}
+
+; CHECK-LABEL: julia_4xfloat
+; CHECK-NOT: insertvalue
+; CHECK-NOT: extractelement
+; CHECK: store <4 x float>
+define void @julia_4xfloat([4 x float]* sret, <4 x float>*) {
+top:
+  %x = load <4 x float>, <4 x float>* %1
+  %x0 = extractelement <4 x float> %x, i32 0
+  %i0 = insertvalue [4 x float] undef, float %x0, 0
+  %x1 = extractelement <4 x float> %x, i32 1
+  %i1 = insertvalue [4 x float] %i0, float %x1, 1
+  %x2 = extractelement <4 x float> %x, i32 2
+  %i2 = insertvalue [4 x float] %i1, float %x2, 2
+  %x3 = extractelement <4 x float> %x, i32 3
+  %i3 = insertvalue [4 x float] %i2, float %x3, 3
+  store [4 x float] %i3, [4 x float]* %0, align 4
+  ret void
+}
+
+%pseudovec = type { float, float, float, float }
+
+; CHECK-LABEL: julia_pseudovec
+; CHECK-NOT: insertvalue
+; CHECK-NOT: extractelement
+; CHECK: store <4 x float>
+define void @julia_pseudovec(%pseudovec* sret, <4 x float>*) {
+top:
+  %x = load <4 x float>, <4 x float>* %1
+  %x0 = extractelement <4 x float> %x, i32 0
+  %i0 = insertvalue %pseudovec undef, float %x0, 0
+  %x1 = extractelement <4 x float> %x, i32 1
+  %i1 = insertvalue %pseudovec %i0, float %x1, 1
+  %x2 = extractelement <4 x float> %x, i32 2
+  %i2 = insertvalue %pseudovec %i1, float %x2, 2
+  %x3 = extractelement <4 x float> %x, i32 3
+  %i3 = insertvalue %pseudovec %i2, float %x3, 3
+  store %pseudovec %i3, %pseudovec* %0, align 4
+  ret void
+}

Added: llvm/trunk/test/Transforms/InstCombine/int_sideeffect.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/int_sideeffect.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/int_sideeffect.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/int_sideeffect.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,14 @@
+; RUN: opt -S < %s -instcombine | FileCheck %s
+
+declare void @llvm.sideeffect()
+
+; Store-to-load forwarding across a @llvm.sideeffect.
+
+; CHECK-LABEL: s2l
+; CHECK-NOT: load
+define float @s2l(float* %p) {
+    store float 0.0, float* %p
+    call void @llvm.sideeffect()
+    %t = load float, float* %p
+    ret float %t
+}

Added: llvm/trunk/test/Transforms/InstCombine/intersect-accessgroup.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/intersect-accessgroup.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/intersect-accessgroup.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/intersect-accessgroup.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,113 @@
+; RUN: opt -instcombine -S < %s | FileCheck %s
+;
+; void func(long n, double A[static const restrict n]) {
+; 	for (int i = 0; i <  n; i+=1)
+; 		for (int j = 0; j <  n;j+=1)
+; 			for (int k = 0; k < n; k += 1)
+; 				for (int l = 0; l < n; l += 1) {
+; 					double *p = &A[i + j + k + l];
+; 					double x = *p;
+; 					double y = *p;
+; 					arg(x + y);
+; 				}
+; }
+;
+; Check for correctly merging access group metadata for instcombine
+; (only common loops are parallel == intersection)
+; Note that combined load would be parallel to loop !16 since both
+; origin loads are parallel to it, but it references two access groups
+; (!8 and !9), neither of which contain both loads. As such, the
+; information that the combined load is parallel to !16 is lost.
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+declare void @arg(double)
+
+define void @func(i64 %n, double* noalias nonnull %A) {
+entry:
+  br label %for.cond
+
+for.cond:
+  %i.0 = phi i32 [ 0, %entry ], [ %add31, %for.inc30 ]
+  %conv = sext i32 %i.0 to i64
+  %cmp = icmp slt i64 %conv, %n
+  br i1 %cmp, label %for.cond2, label %for.end32
+
+for.cond2:
+  %j.0 = phi i32 [ %add28, %for.inc27 ], [ 0, %for.cond ]
+  %conv3 = sext i32 %j.0 to i64
+  %cmp4 = icmp slt i64 %conv3, %n
+  br i1 %cmp4, label %for.cond8, label %for.inc30
+
+for.cond8:
+  %k.0 = phi i32 [ %add25, %for.inc24 ], [ 0, %for.cond2 ]
+  %conv9 = sext i32 %k.0 to i64
+  %cmp10 = icmp slt i64 %conv9, %n
+  br i1 %cmp10, label %for.cond14, label %for.inc27
+
+for.cond14:
+  %l.0 = phi i32 [ %add23, %for.body19 ], [ 0, %for.cond8 ]
+  %conv15 = sext i32 %l.0 to i64
+  %cmp16 = icmp slt i64 %conv15, %n
+  br i1 %cmp16, label %for.body19, label %for.inc24
+
+for.body19:
+  %add = add nsw i32 %i.0, %j.0
+  %add20 = add nsw i32 %add, %k.0
+  %add21 = add nsw i32 %add20, %l.0
+  %idxprom = sext i32 %add21 to i64
+  %arrayidx = getelementptr inbounds double, double* %A, i64 %idxprom
+  %0 = load double, double* %arrayidx, align 8, !llvm.access.group !1
+  %1 = load double, double* %arrayidx, align 8, !llvm.access.group !2
+  %add22 = fadd double %0, %1
+  call void @arg(double %add22), !llvm.access.group !3
+  %add23 = add nsw i32 %l.0, 1
+  br label %for.cond14, !llvm.loop !11
+
+for.inc24:
+  %add25 = add nsw i32 %k.0, 1
+  br label %for.cond8, !llvm.loop !14
+
+for.inc27:
+  %add28 = add nsw i32 %j.0, 1
+  br label %for.cond2, !llvm.loop !16
+
+for.inc30:
+  %add31 = add nsw i32 %i.0, 1
+  br label %for.cond, !llvm.loop !18
+
+for.end32:
+  ret void
+}
+
+
+; access groups
+!7 = distinct !{}
+!8 = distinct !{}
+!9 = distinct !{}
+
+; access group lists
+!1 = !{!7, !9}
+!2 = !{!7, !8}
+!3 = !{!7, !8, !9}
+
+!11 = distinct !{!11, !13}
+!13 = !{!"llvm.loop.parallel_accesses", !7}
+
+!14 = distinct !{!14, !15}
+!15 = !{!"llvm.loop.parallel_accesses", !8}
+
+!16 = distinct !{!16, !17}
+!17 = !{!"llvm.loop.parallel_accesses", !8, !9}
+
+!18 = distinct !{!18, !19}
+!19 = !{!"llvm.loop.parallel_accesses", !9}
+
+
+; CHECK: load double, {{.*}} !llvm.access.group ![[ACCESSGROUP_0:[0-9]+]]
+; CHECK: br label %for.cond14, !llvm.loop ![[LOOP_4:[0-9]+]]
+
+; CHECK: ![[ACCESSGROUP_0]] = distinct !{}
+
+; CHECK: ![[LOOP_4]] = distinct !{![[LOOP_4]], ![[PARALLEL_ACCESSES_5:[0-9]+]]}
+; CHECK: ![[PARALLEL_ACCESSES_5]] = !{!"llvm.loop.parallel_accesses", ![[ACCESSGROUP_0]]}

Added: llvm/trunk/test/Transforms/InstCombine/intptr1.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/intptr1.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/intptr1.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/intptr1.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,193 @@
+; RUN: opt < %s  -instcombine  -S | FileCheck %s
+
+define void @test1(float* %a, float* readnone %a_end, i64* %b.i64) {
+; CHECK-LABEL: @test1
+entry:
+  %cmp1 = icmp ult float* %a, %a_end
+  br i1 %cmp1, label %for.body.preheader, label %for.end
+
+for.body.preheader:                               ; preds = %entry
+  %b = load i64, i64* %b.i64, align 8
+; CHECK: load float*, float**
+  br label %for.body
+
+for.body:                                         ; preds = %for.body, %for.body.preheader
+  %a.addr.03 = phi float* [ %incdec.ptr, %for.body ], [ %a, %for.body.preheader ]
+  %b.addr.02 = phi i64 [ %add.int, %for.body ], [ %b, %for.body.preheader ]
+
+; CHECK: %a.addr.03 = phi float* [ %incdec.ptr, %for.body ], [ %a, %for.body.preheader ]
+; CHECK: %b.addr.02.ptr = phi float* [ %add, %for.body ],
+; CHECK-NOT: %b.addr.02 = phi i64
+
+  %tmp = inttoptr i64 %b.addr.02 to float*
+; CHECK-NOT: inttoptr i64
+  %tmp1 = load float, float* %tmp, align 4
+; CHECK: = load
+  %mul.i = fmul float %tmp1, 4.200000e+01
+  store float %mul.i, float* %a.addr.03, align 4
+  %add = getelementptr inbounds float, float* %tmp, i64 1
+  %add.int = ptrtoint float* %add to i64
+; CHECK %add = getelementptr
+; CHECK-NOT: ptrtoint float*
+  %incdec.ptr = getelementptr inbounds float, float* %a.addr.03, i64 1
+; CHECK: %incdec.ptr = 
+  %cmp = icmp ult float* %incdec.ptr, %a_end
+  br i1 %cmp, label %for.body, label %for.end
+
+for.end:                                          ; preds = %for.body, %entry
+  ret void
+}
+
+define void @test1_neg(float* %a, float* readnone %a_end, i64* %b.i64) {
+; CHECK-LABEL: @test1_neg
+entry:
+  %cmp1 = icmp ult float* %a, %a_end
+  br i1 %cmp1, label %for.body.preheader, label %for.end
+
+for.body.preheader:                               ; preds = %entry
+  %b = load i64, i64* %b.i64, align 8
+  br label %for.body
+
+for.body:                                         ; preds = %for.body, %for.body.preheader
+  %a.addr.03 = phi float* [ %incdec.ptr, %bb ], [ %a, %for.body.preheader ]
+  %b.addr.02 = phi i64 [ %add.int, %bb ], [ %b, %for.body.preheader ]
+
+; CHECK: %a.addr.03 = phi float* [ %incdec.ptr, %bb ], [ %a, %for.body.preheader ]
+; CHECK: %b.addr.02 = phi i64
+
+  %tmp = inttoptr i64 %b.addr.02 to float*
+; CHECK: inttoptr i64
+  %ptrcmp = icmp ult float* %tmp, %a_end
+  br i1 %ptrcmp, label %for.end, label %bb
+
+bb:
+  %tmp1 = load float, float* %a, align 4
+  %mul.i = fmul float %tmp1, 4.200000e+01
+  store float %mul.i, float* %a.addr.03, align 4
+  %add = getelementptr inbounds float, float* %a, i64 1
+  %add.int = ptrtoint float* %add to i64
+; CHECK: ptrtoint float*
+  %incdec.ptr = getelementptr inbounds float, float* %a.addr.03, i64 1
+  %cmp = icmp ult float* %incdec.ptr, %a_end
+  br i1 %cmp, label %for.body, label %for.end
+
+for.end:                                          ; preds = %for.body, %entry
+  ret void
+}
+
+
+define void @test2(float* %a, float* readnone %a_end, float** %b.float) {
+; CHECK-LABEL: @test2
+entry:
+  %cmp1 = icmp ult float* %a, %a_end
+  br i1 %cmp1, label %for.body.preheader, label %for.end
+
+for.body.preheader:                               ; preds = %entry
+  %b.i64 = bitcast float** %b.float to i64*
+  %b = load i64, i64* %b.i64, align 8
+; CHECK: load float*, float**
+  br label %for.body
+
+for.body:                                         ; preds = %for.body, %for.body.preheader
+  %a.addr.03 = phi float* [ %incdec.ptr, %for.body ], [ %a, %for.body.preheader ]
+  %b.addr.02 = phi i64 [ %add.int, %for.body ], [ %b, %for.body.preheader ]
+
+; CHECK: %a.addr.03 = phi float* [ %incdec.ptr, %for.body ], [ %a, %for.body.preheader ]
+; CHECK: %b.addr.02.ptr = phi float* [ %add, %for.body ],
+; CHECK-NOT: %b.addr.02 = phi i64
+
+  %tmp = inttoptr i64 %b.addr.02 to float*
+; CHECK-NOT: inttoptr i64
+  %tmp1 = load float, float* %tmp, align 4
+; CHECK: = load
+  %mul.i = fmul float %tmp1, 4.200000e+01
+  store float %mul.i, float* %a.addr.03, align 4
+  %add = getelementptr inbounds float, float* %tmp, i64 1
+; CHECK: %add = 
+  %add.int = ptrtoint float* %add to i64
+; CHECK-NOT: ptrtoint float*
+  %incdec.ptr = getelementptr inbounds float, float* %a.addr.03, i64 1
+; CHECK: %incdec.ptr = 
+  %cmp = icmp ult float* %incdec.ptr, %a_end
+  br i1 %cmp, label %for.body, label %for.end
+
+for.end:                                          ; preds = %for.body, %entry
+  ret void
+}
+
+
+define void @test3(float* %a, float* readnone %a_end, i8** %b.i8p) {
+; CHECK-LABEL: @test3
+entry:
+  %cmp1 = icmp ult float* %a, %a_end
+  br i1 %cmp1, label %for.body.preheader, label %for.end
+
+for.body.preheader:                               ; preds = %entry
+  %b.i64 = bitcast i8** %b.i8p to i64*
+  %b = load i64, i64* %b.i64, align 8
+; CHECK: load float*, float**
+  br label %for.body
+
+for.body:                                         ; preds = %for.body, %for.body.preheader
+  %a.addr.03 = phi float* [ %incdec.ptr, %for.body ], [ %a, %for.body.preheader ]
+  %b.addr.02 = phi i64 [ %add.int, %for.body ], [ %b, %for.body.preheader ]
+
+; CHECK: %a.addr.03 = phi float* [ %incdec.ptr, %for.body ], [ %a, %for.body.preheader ]
+; CHECK: %b.addr.02.ptr = phi float* [ %add, %for.body ],
+; CHECK-NOT: %b.addr.02 = phi i64
+
+  %tmp = inttoptr i64 %b.addr.02 to float*
+; CHECK-NOT: inttoptr i64
+  %tmp1 = load float, float* %tmp, align 4
+; CHECK: = load
+  %mul.i = fmul float %tmp1, 4.200000e+01
+  store float %mul.i, float* %a.addr.03, align 4
+  %add = getelementptr inbounds float, float* %tmp, i64 1
+; CHECK: %add = getelementptr
+  %add.int = ptrtoint float* %add to i64
+; CHECK-NOT: ptrtoint float*
+  %incdec.ptr = getelementptr inbounds float, float* %a.addr.03, i64 1
+; CHECK: %incdec.ptr = 
+  %cmp = icmp ult float* %incdec.ptr, %a_end
+  br i1 %cmp, label %for.body, label %for.end
+
+for.end:                                          ; preds = %for.body, %entry
+  ret void
+}
+
+
+define void @test4(float* %a, float* readnone %a_end, float** %b.float) {
+entry:
+; CHECK-LABEL: @test4
+  %cmp1 = icmp ult float* %a, %a_end
+  br i1 %cmp1, label %for.body.preheader, label %for.end
+
+for.body.preheader:                               ; preds = %entry
+  %b.f = load float*, float** %b.float, align 8
+  %b = ptrtoint float* %b.f to i64
+; CHECK: load float*, float**
+; CHECK-NOT: ptrtoint float*
+  br label %for.body
+; CHECK: br label %for.body
+
+for.body:                                         ; preds = %for.body, %for.body.preheader
+  %a.addr.03 = phi float* [ %incdec.ptr, %for.body ], [ %a, %for.body.preheader ]
+  %b.addr.02 = phi i64 [ %add.int, %for.body ], [ %b, %for.body.preheader ]
+  %tmp = inttoptr i64 %b.addr.02 to float*
+; CHECK-NOT: inttoptr i64
+  %tmp1 = load float, float* %tmp, align 4
+; CHECK: = load
+  %mul.i = fmul float %tmp1, 4.200000e+01
+  store float %mul.i, float* %a.addr.03, align 4
+  %add = getelementptr inbounds float, float* %tmp, i64 1
+; CHECK: %add = 
+  %add.int = ptrtoint float* %add to i64
+; CHECK-NOT: ptrtoint float*
+  %incdec.ptr = getelementptr inbounds float, float* %a.addr.03, i64 1
+; CHECK: %incdec.ptr =
+  %cmp = icmp ult float* %incdec.ptr, %a_end
+  br i1 %cmp, label %for.body, label %for.end
+
+for.end:                                          ; preds = %for.body, %entry
+  ret void
+}

Added: llvm/trunk/test/Transforms/InstCombine/intptr2.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/intptr2.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/intptr2.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/intptr2.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,39 @@
+; RUN: opt < %s  -instcombine -S | FileCheck %s
+
+define void @test1(float* %a, float* readnone %a_end, i32* %b.i) {
+; CHECK-LABEL: @test1
+entry:
+  %cmp1 = icmp ult float* %a, %a_end
+  br i1 %cmp1, label %for.body.preheader, label %for.end
+
+for.body.preheader:                               ; preds = %entry
+  %b = ptrtoint i32 * %b.i to i64
+; CHECK: bitcast
+; CHECK-NOT: ptrtoint
+  br label %for.body
+; CHECK: br label %for.body
+
+for.body:                                         ; preds = %for.body, %for.body.preheader
+  %a.addr.03 = phi float* [ %incdec.ptr, %for.body ], [ %a, %for.body.preheader ]
+  %b.addr.02 = phi i64 [ %add.int, %for.body ], [ %b, %for.body.preheader ]
+; CHECK:  %a.addr.03 = phi float* [ %incdec.ptr, %for.body ], [ %a, %for.body.preheader ]
+; CHECK-NOT: phi i64 
+  %tmp = inttoptr i64 %b.addr.02 to float*
+; CHECK-NOT: inttoptr
+  %tmp1 = load float, float* %tmp, align 4
+; CHECK: = load
+  %mul.i = fmul float %tmp1, 4.200000e+01
+  store float %mul.i, float* %a.addr.03, align 4
+  %add = getelementptr inbounds float, float* %tmp, i64 1
+; CHECK: %add = 
+  %add.int = ptrtoint float* %add to i64
+; CHECK-NOT: ptrtoint
+  %incdec.ptr = getelementptr inbounds float, float* %a.addr.03, i64 1
+; CHECK: %incdec.ptr = 
+  %cmp = icmp ult float* %incdec.ptr, %a_end
+  br i1 %cmp, label %for.body, label %for.end
+
+for.end:                                          ; preds = %for.body, %entry
+  ret void
+}
+

Added: llvm/trunk/test/Transforms/InstCombine/intptr3.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/intptr3.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/intptr3.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/intptr3.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,39 @@
+; RUN: opt < %s  -instcombine -S | FileCheck %s
+
+define  void @test(float* %a, float* readnone %a_end, i64 %b) unnamed_addr  {
+entry:
+  %cmp1 = icmp ult float* %a, %a_end
+  br i1 %cmp1, label %for.body.preheader, label %for.end
+
+for.body.preheader:                               ; preds = %entry
+  %b.float = inttoptr i64 %b to float*
+  br label %for.body
+
+for.body:                                         ; preds = %for.body.preheader, %for.body
+  %a.addr.03 = phi float* [ %incdec.ptr, %for.body ], [ %a, %for.body.preheader ]
+  %b.addr.float = phi float* [ %b.addr.float.inc, %for.body ], [ %b.float, %for.body.preheader ]
+  %b.addr.i64 = phi i64 [ %b.addr.i64.inc, %for.body ], [ %b, %for.body.preheader ]
+; CHECK: %a.addr.03 = phi float* [ %incdec.ptr, %for.body ], [ %a, %for.body.preheader ]
+; CHECK-NEXT:  %b.addr.float = phi float* [ %b.addr.float.inc, %for.body ], [ %b.float, %for.body.preheader ]
+; CHECK-NEXT: = load float
+  %l = load float, float* %b.addr.float, align 4 
+  %mul.i = fmul float %l, 4.200000e+01
+  store float %mul.i, float* %a.addr.03, align 4
+; CHECK: store float
+  %b.addr.float.2 = inttoptr i64 %b.addr.i64 to float*
+; CHECK-NOT: inttoptr
+  %b.addr.float.inc = getelementptr inbounds float, float* %b.addr.float.2, i64 1
+; CHECK: %b.addr.float.inc = 
+  %b.addr.i64.inc = ptrtoint float* %b.addr.float.inc to i64
+; CHECK-NOT: ptrtoint
+  %incdec.ptr = getelementptr inbounds float, float* %a.addr.03, i64 1
+; CHECK: %incdec.ptr = 
+  %cmp = icmp ult float* %incdec.ptr, %a_end
+  br i1 %cmp, label %for.body, label %for.end
+
+for.end:                                          ; preds = %for.body, %entry
+  ret void
+}
+
+
+

Added: llvm/trunk/test/Transforms/InstCombine/intptr4.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/intptr4.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/intptr4.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/intptr4.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,53 @@
+; RUN: opt < %s  -instcombine -S | FileCheck %s
+
+define  void @test(float* %a, float* readnone %a_end, i64 %b, float* %bf) unnamed_addr  {
+entry:
+  %cmp1 = icmp ult float* %a, %a_end
+  %b.float = inttoptr i64 %b to float*
+  br i1 %cmp1, label %bb1, label %bb2
+
+bb1:
+ br label %for.body.preheader
+bb2:
+ %bfi = ptrtoint float* %bf to i64
+ br label %for.body.preheader
+
+for.body.preheader:                               ; preds = %entry
+  %b.phi = phi i64 [%b, %bb1], [%bfi, %bb2]
+  br label %for.body
+; CHECK: for.body.preheader
+; CHECK: %b.phi = phi
+; CHECK: %b.phi.ptr =
+; CHECK: br label %for.body
+
+for.body:                                         ; preds = %for.body.preheader, %for.body
+; CHECK: for.body
+  %a.addr.03 = phi float* [ %incdec.ptr, %for.body ], [ %a, %for.body.preheader ]
+  %b.addr.float = phi float* [ %b.addr.float.inc, %for.body ], [ %b.float, %for.body.preheader ]
+  %b.addr.i64 = phi i64 [ %b.addr.i64.inc, %for.body ], [ %b.phi, %for.body.preheader ]
+; CHECK: %a.addr.03 = phi float* [ %incdec.ptr, %for.body ], [ %a, %for.body.preheader ]
+; CHECK-NEXT: %b.addr.float = phi float* [ %b.addr.float.inc, %for.body ], [ %b.float, %for.body.preheader ]
+; CHECK-NEXT: %b.addr.i64.ptr = phi
+; CHECK-NOT:  = phi i64
+; CHECK: = load
+  %l = load float, float* %b.addr.float, align 4 
+  %mul.i = fmul float %l, 4.200000e+01
+  store float %mul.i, float* %a.addr.03, align 4
+  %b.addr.float.2 = inttoptr i64 %b.addr.i64 to float*
+  %b.addr.float.inc = getelementptr inbounds float, float* %b.addr.float.2, i64 1
+; CHECK: store float %mul.i
+; CHECK-NOT: inttoptr
+; CHECK: %b.addr.float.inc =
+  %b.addr.i64.inc = ptrtoint float* %b.addr.float.inc to i64
+; CHECK-NOT: ptrtoint
+  %incdec.ptr = getelementptr inbounds float, float* %a.addr.03, i64 1
+; CHECK: %incdec.ptr = 
+  %cmp = icmp ult float* %incdec.ptr, %a_end
+  br i1 %cmp, label %for.body, label %for.end
+
+for.end:                                          ; preds = %for.body, %entry
+  ret void
+}
+
+
+

Added: llvm/trunk/test/Transforms/InstCombine/intptr5.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/intptr5.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/intptr5.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/intptr5.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,56 @@
+; RUN: opt < %s  -instcombine -S | FileCheck %s
+
+define  void @test(float* %a, float* readnone %a_end, i64 %b, float* %bf) unnamed_addr  {
+entry:
+  %cmp1 = icmp ult float* %a, %a_end
+  %b.float = inttoptr i64 %b to float*
+  br i1 %cmp1, label %bb1, label %bb2
+
+bb1:
+ br label %for.body.preheader
+bb2:
+ %bfi = ptrtoint float* %bf to i64
+ br label %for.body.preheader
+
+for.body.preheader:                               ; preds = %entry
+  %b.phi = phi i64 [%b, %bb1], [%bfi, %bb2]
+  switch i64 %b, label %for.body [
+    i64 1, label %for.body
+  ]
+; CHECK: for.body.preheader
+; CHECK: %b.phi = phi
+; CHECK: %b.phi.ptr =
+; CHECK-NOT: %b.phi.ptr2 =
+; CHECK: switch
+
+for.body:                                         ; preds = %for.body.preheader, %for.body
+; CHECK: for.body
+  %a.addr.03 = phi float* [ %incdec.ptr, %for.body ], [ %a, %for.body.preheader ], [%a, %for.body.preheader]
+  %b.addr.float = phi float* [ %b.addr.float.inc, %for.body ], [ %b.float, %for.body.preheader ], [%b.float, %for.body.preheader]
+  %b.addr.i64 = phi i64 [ %b.addr.i64.inc, %for.body ], [ %b.phi, %for.body.preheader ], [ %b.phi, %for.body.preheader]
+; CHECK: %a.addr.03 = phi float* [ %incdec.ptr, %for.body ], [ %a, %for.body.preheader ]
+; CHECK-NEXT: %b.addr.float = phi float* [ %b.addr.float.inc, %for.body ], [ %b.float, %for.body.preheader ]
+; CHECK-NEXT: %b.addr.i64.ptr = phi 
+; CHECK-NOT: = %b.addr.i64
+; CHECK: = load
+  %l = load float, float* %b.addr.float, align 4 
+  %mul.i = fmul float %l, 4.200000e+01
+  store float %mul.i, float* %a.addr.03, align 4
+  %b.addr.float.2 = inttoptr i64 %b.addr.i64 to float*
+  %b.addr.float.inc = getelementptr inbounds float, float* %b.addr.float.2, i64 1
+; CHECK: store float %mul.i
+; CHECK-NOT: inttoptr
+; CHECK: %b.addr.float.inc =
+  %b.addr.i64.inc = ptrtoint float* %b.addr.float.inc to i64
+; CHECK-NOT: ptrtoint
+  %incdec.ptr = getelementptr inbounds float, float* %a.addr.03, i64 1
+; CHECK: %incdec.ptr = 
+  %cmp = icmp ult float* %incdec.ptr, %a_end
+  br i1 %cmp, label %for.body, label %for.end
+
+for.end:                                          ; preds = %for.body, %entry
+  ret void
+}
+
+
+

Added: llvm/trunk/test/Transforms/InstCombine/intptr6.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/intptr6.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/intptr6.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/intptr6.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,90 @@
+; RUN: opt < %s  -instcombine -S 
+; no crash
+
+%A = type { %B }
+%B = type { %C *}
+%C = type <{ i32 (...)**, i32, [4 x i8] }>
+
+$foo = comdat any
+
+ at bar= external thread_local global %A, align 8
+
+declare i32 @__gxx_personality_v0(...)
+
+; Function Attrs: inlinehint sanitize_memory uwtable
+define void @foo() local_unnamed_addr #0 comdat align 2 personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) {
+entry:
+  %0 = load %C*, %C** getelementptr inbounds (%A, %A* @bar, i64 0, i32 0, i32 0), align 8
+  %1 = ptrtoint %C* %0 to i64
+  %count.i.i.i23 = getelementptr inbounds %C, %C* %0, i64 0, i32 1
+  store i32 0, i32* %count.i.i.i23, align 8
+  %2 = invoke i8* @_Znwm() #3
+          to label %invoke.cont unwind label %lpad
+
+invoke.cont:                                      ; preds = %entry
+  %call.i25 = invoke i8* @_Znwm() #3
+          to label %call.i.noexc unwind label %lpad4
+
+call.i.noexc:                                     ; preds = %invoke.cont
+  invoke void @lazy()
+          to label %invoke.cont5 unwind label %lpad.i
+
+lpad.i:                                           ; preds = %call.i.noexc
+  %3 = landingpad { i8*, i32 }
+          cleanup
+  br label %ehcleanup
+
+invoke.cont5:                                     ; preds = %call.i.noexc
+  %4 = ptrtoint i8* %call.i25 to i64
+  invoke void @scale()
+          to label %invoke.cont16 unwind label %lpad15
+
+invoke.cont16:                                    ; preds = %invoke.cont5
+  ret void
+
+lpad:                                             ; preds = %entry
+  %5 = landingpad { i8*, i32 }
+          cleanup
+  unreachable
+
+lpad4:                                            ; preds = %invoke.cont
+  %6 = landingpad { i8*, i32 }
+          cleanup
+  unreachable
+
+ehcleanup:                                        ; preds = %lpad.i
+  br label %ehcleanup21
+
+lpad15:                                           ; preds = %invoke.cont5
+  %7 = landingpad { i8*, i32 }
+          cleanup
+  br label %ehcleanup21
+
+ehcleanup21:                                      ; preds = %lpad15, %ehcleanup
+  %actual_other.sroa.0.0 = phi i64 [ %1, %ehcleanup ], [ %4, %lpad15 ]
+  %8 = inttoptr i64 %actual_other.sroa.0.0 to %C*
+  br i1 undef, label %_ZN4CGAL6HandleD2Ev.exit, label %land.lhs.true.i
+
+land.lhs.true.i:                                  ; preds = %ehcleanup21
+  %count.i = getelementptr inbounds %C, %C* %8, i64 0, i32 1
+  %9 = load i32, i32* %count.i, align 8
+  unreachable
+
+_ZN4CGAL6HandleD2Ev.exit:                         ; preds = %ehcleanup21
+  resume { i8*, i32 } undef
+}
+
+; Function Attrs: nobuiltin
+declare noalias nonnull i8* @_Znwm() local_unnamed_addr #1
+
+; Function Attrs: sanitize_memory uwtable
+declare void @scale() local_unnamed_addr #2 align 2
+
+; Function Attrs: sanitize_memory uwtable
+declare void @lazy() unnamed_addr #2 align 2
+
+attributes #0 = { inlinehint sanitize_memory uwtable}
+attributes #1 = { nobuiltin } 
+attributes #2 = { sanitize_memory uwtable } 
+attributes #3 = { builtin }
+

Added: llvm/trunk/test/Transforms/InstCombine/intptr7.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/intptr7.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/intptr7.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/intptr7.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,58 @@
+; RUN: opt < %s  -instcombine -S | FileCheck %s
+
+define void @matching_phi(i64 %a, float* %b, i1 %cond) {
+; CHECK-LABEL: @matching_phi
+entry:
+  %cmp1 = icmp  eq i1 %cond, 0
+  %add.int = add i64 %a, 1
+  %add = inttoptr i64 %add.int to float *
+
+  %addb = getelementptr inbounds float, float* %b, i64 2
+  %addb.int = ptrtoint float* %addb to i64
+  br i1 %cmp1, label %A, label %B
+A:
+  br label %C
+B:
+  store float 1.0e+01, float* %add, align 4
+  br label %C
+
+C:
+  %a.addr.03 = phi float* [ %addb, %A ], [ %add, %B ]
+  %b.addr.02 = phi i64 [ %addb.int, %A ], [ %add.int, %B ]
+  %tmp = inttoptr i64 %b.addr.02 to float*
+; CHECK: %a.addr.03 = phi
+; CHECK-NEXT: = load
+  %tmp1 = load float, float* %tmp, align 4
+  %mul.i = fmul float %tmp1, 4.200000e+01
+  store float %mul.i, float* %a.addr.03, align 4
+  ret void
+}
+
+define void @no_matching_phi(i64 %a, float* %b, i1 %cond) {
+; CHECK-LABEL: @no_matching_phi
+entry:
+  %cmp1 = icmp  eq i1 %cond, 0
+  %add.int = add i64 %a, 1
+  %add = inttoptr i64 %add.int to float *
+
+  %addb = getelementptr inbounds float, float* %b, i64 2
+  %addb.int = ptrtoint float* %addb to i64
+  br i1 %cmp1, label %A, label %B
+A:
+  br label %C
+B:
+  store float 1.0e+01, float* %add, align 4
+  br label %C
+
+C:
+  %a.addr.03 = phi float* [ %addb, %A ], [ %add, %B ]
+  %b.addr.02 = phi i64 [ %addb.int, %B ], [ %add.int, %A ]
+  %tmp = inttoptr i64 %b.addr.02 to float*
+  %tmp1 = load float, float* %tmp, align 4
+; CHECK: %a.addr.03 = phi
+; CHECK-NEXT: %b.addr.02.ptr = phi
+; CHECK-NEXT: = load
+  %mul.i = fmul float %tmp1, 4.200000e+01
+  store float %mul.i, float* %a.addr.03, align 4
+  ret void
+}

Added: llvm/trunk/test/Transforms/InstCombine/intrinsics.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/intrinsics.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/intrinsics.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/intrinsics.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,427 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt -instcombine -S < %s | FileCheck %s
+
+declare double @llvm.powi.f64(double, i32) nounwind readonly
+declare i32 @llvm.cttz.i32(i32, i1) nounwind readnone
+declare i32 @llvm.ctlz.i32(i32, i1) nounwind readnone
+declare i1 @llvm.cttz.i1(i1, i1) nounwind readnone
+declare i1 @llvm.ctlz.i1(i1, i1) nounwind readnone
+declare i32 @llvm.ctpop.i32(i32) nounwind readnone
+declare <2 x i32> @llvm.cttz.v2i32(<2 x i32>, i1) nounwind readnone
+declare <2 x i32> @llvm.ctlz.v2i32(<2 x i32>, i1) nounwind readnone
+declare <2 x i32> @llvm.ctpop.v2i32(<2 x i32>) nounwind readnone
+declare i8 @llvm.ctlz.i8(i8, i1) nounwind readnone
+declare <2 x i8> @llvm.ctlz.v2i8(<2 x i8>, i1) nounwind readnone
+declare double @llvm.cos.f64(double %Val) nounwind readonly
+declare double @llvm.sin.f64(double %Val) nounwind readonly
+declare double @llvm.floor.f64(double %Val) nounwind readonly
+declare double @llvm.ceil.f64(double %Val) nounwind readonly
+declare double @llvm.trunc.f64(double %Val) nounwind readonly
+declare double @llvm.rint.f64(double %Val) nounwind readonly
+declare double @llvm.nearbyint.f64(double %Val) nounwind readonly
+
+define void @powi(double %V, double *%P) {
+  %A = tail call double @llvm.powi.f64(double %V, i32 -1) nounwind
+  store volatile double %A, double* %P
+
+  %D = tail call double @llvm.powi.f64(double %V, i32 2) nounwind
+  store volatile double %D, double* %P
+  ret void
+; CHECK-LABEL: @powi(
+; CHECK: %A = fdiv double 1.0{{.*}}, %V
+; CHECK: store volatile double %A,
+; CHECK: %D = fmul double %V, %V
+; CHECK: store volatile double %D
+}
+
+define i32 @cttz(i32 %a) {
+; CHECK-LABEL: @cttz(
+; CHECK-NEXT:    ret i32 3
+;
+  %or = or i32 %a, 8
+  %and = and i32 %or, -8
+  %count = tail call i32 @llvm.cttz.i32(i32 %and, i1 true) nounwind readnone
+  ret i32 %count
+}
+
+define <2 x i32> @cttz_vec(<2 x i32> %a) {
+; CHECK-LABEL: @cttz_vec(
+; CHECK-NEXT:    ret <2 x i32> <i32 3, i32 3>
+;
+  %or = or <2 x i32> %a, <i32 8, i32 8>
+  %and = and <2 x i32> %or, <i32 -8, i32 -8>
+  %count = tail call <2 x i32> @llvm.cttz.v2i32(<2 x i32> %and, i1 true) nounwind readnone
+  ret <2 x i32> %count
+}
+
+; Make sure we don't add range metadata to i1 cttz.
+define i1 @cttz_i1(i1 %arg) {
+; CHECK-LABEL: @cttz_i1(
+; CHECK-NEXT:    [[CNT:%.*]] = call i1 @llvm.cttz.i1(i1 [[ARG:%.*]], i1 false) #2
+; CHECK-NEXT:    ret i1 [[CNT]]
+;
+  %cnt = call i1 @llvm.cttz.i1(i1 %arg, i1 false) nounwind readnone
+  ret i1 %cnt
+}
+
+define i1 @cttz_knownbits(i32 %arg) {
+; CHECK-LABEL: @cttz_knownbits(
+; CHECK-NEXT:    ret i1 false
+;
+  %or = or i32 %arg, 4
+  %cnt = call i32 @llvm.cttz.i32(i32 %or, i1 true) nounwind readnone
+  %res = icmp eq i32 %cnt, 4
+  ret i1 %res
+}
+
+define <2 x i1> @cttz_knownbits_vec(<2 x i32> %arg) {
+; CHECK-LABEL: @cttz_knownbits_vec(
+; CHECK-NEXT:    ret <2 x i1> zeroinitializer
+;
+  %or = or <2 x i32> %arg, <i32 4, i32 4>
+  %cnt = call <2 x i32> @llvm.cttz.v2i32(<2 x i32> %or, i1 true) nounwind readnone
+  %res = icmp eq <2 x i32> %cnt, <i32 4, i32 4>
+  ret <2 x i1> %res
+}
+
+define i32 @cttz_knownbits2(i32 %arg) {
+; CHECK-LABEL: @cttz_knownbits2(
+; CHECK-NEXT:    [[OR:%.*]] = or i32 [[ARG:%.*]], 4
+; CHECK-NEXT:    [[CNT:%.*]] = call i32 @llvm.cttz.i32(i32 [[OR]], i1 true) #2, !range ![[$CTTZ_RANGE:[0-9]+]]
+; CHECK-NEXT:    ret i32 [[CNT]]
+;
+  %or = or i32 %arg, 4
+  %cnt = call i32 @llvm.cttz.i32(i32 %or, i1 true) nounwind readnone
+  ret i32 %cnt
+}
+
+define <2 x i32> @cttz_knownbits2_vec(<2 x i32> %arg) {
+; CHECK-LABEL: @cttz_knownbits2_vec(
+; CHECK-NEXT:    [[OR:%.*]] = or <2 x i32> [[ARG:%.*]], <i32 4, i32 4>
+; CHECK-NEXT:    [[CNT:%.*]] = call <2 x i32> @llvm.cttz.v2i32(<2 x i32> [[OR]], i1 true)
+; CHECK-NEXT:    ret <2 x i32> [[CNT]]
+;
+  %or = or <2 x i32> %arg, <i32 4, i32 4>
+  %cnt = call <2 x i32> @llvm.cttz.v2i32(<2 x i32> %or, i1 true) nounwind readnone
+  ret <2 x i32> %cnt
+}
+
+define i1 @cttz_knownbits3(i32 %arg) {
+; CHECK-LABEL: @cttz_knownbits3(
+; CHECK-NEXT:    ret i1 false
+;
+  %or = or i32 %arg, 4
+  %cnt = call i32 @llvm.cttz.i32(i32 %or, i1 true) nounwind readnone
+  %res = icmp eq i32 %cnt, 3
+  ret i1 %res
+}
+
+define <2 x i1> @cttz_knownbits3_vec(<2 x i32> %arg) {
+; CHECK-LABEL: @cttz_knownbits3_vec(
+; CHECK-NEXT:    ret <2 x i1> zeroinitializer
+;
+  %or = or <2 x i32> %arg, <i32 4, i32 4>
+  %cnt = call <2 x i32> @llvm.cttz.v2i32(<2 x i32> %or, i1 true) nounwind readnone
+  %res = icmp eq <2 x i32> %cnt, <i32 3, i32 3>
+  ret <2 x i1> %res
+}
+
+define i8 @ctlz(i8 %a) {
+; CHECK-LABEL: @ctlz(
+; CHECK-NEXT:    ret i8 2
+;
+  %or = or i8 %a, 32
+  %and = and i8 %or, 63
+  %count = tail call i8 @llvm.ctlz.i8(i8 %and, i1 true) nounwind readnone
+  ret i8 %count
+}
+
+define <2 x i8> @ctlz_vec(<2 x i8> %a) {
+; CHECK-LABEL: @ctlz_vec(
+; CHECK-NEXT:    ret <2 x i8> <i8 2, i8 2>
+;
+  %or = or <2 x i8> %a, <i8 32, i8 32>
+  %and = and <2 x i8> %or, <i8 63, i8 63>
+  %count = tail call <2 x i8> @llvm.ctlz.v2i8(<2 x i8> %and, i1 true) nounwind readnone
+  ret <2 x i8> %count
+}
+
+; Make sure we don't add range metadata to i1 ctlz.
+define i1 @ctlz_i1(i1 %arg) {
+; CHECK-LABEL: @ctlz_i1(
+; CHECK-NEXT:    [[CNT:%.*]] = call i1 @llvm.ctlz.i1(i1 [[ARG:%.*]], i1 false) #2
+; CHECK-NEXT:    ret i1 [[CNT]]
+;
+  %cnt = call i1 @llvm.ctlz.i1(i1 %arg, i1 false) nounwind readnone
+  ret i1 %cnt
+}
+
+define i1 @ctlz_knownbits(i8 %arg) {
+; CHECK-LABEL: @ctlz_knownbits(
+; CHECK-NEXT:    ret i1 false
+;
+  %or = or i8 %arg, 32
+  %cnt = call i8 @llvm.ctlz.i8(i8 %or, i1 true) nounwind readnone
+  %res = icmp eq i8 %cnt, 4
+  ret i1 %res
+}
+
+define <2 x i1> @ctlz_knownbits_vec(<2 x i8> %arg) {
+; CHECK-LABEL: @ctlz_knownbits_vec(
+; CHECK-NEXT:    ret <2 x i1> zeroinitializer
+;
+  %or = or <2 x i8> %arg, <i8 32, i8 32>
+  %cnt = call <2 x i8> @llvm.ctlz.v2i8(<2 x i8> %or, i1 true) nounwind readnone
+  %res = icmp eq <2 x i8> %cnt, <i8 4, i8 4>
+  ret <2 x i1> %res
+}
+
+define i8 @ctlz_knownbits2(i8 %arg) {
+; CHECK-LABEL: @ctlz_knownbits2(
+; CHECK-NEXT:    [[OR:%.*]] = or i8 [[ARG:%.*]], 32
+; CHECK-NEXT:    [[CNT:%.*]] = call i8 @llvm.ctlz.i8(i8 [[OR]], i1 true) #2, !range ![[$CTLZ_RANGE:[0-9]+]]
+; CHECK-NEXT:    ret i8 [[CNT]]
+;
+  %or = or i8 %arg, 32
+  %cnt = call i8 @llvm.ctlz.i8(i8 %or, i1 true) nounwind readnone
+  ret i8 %cnt
+}
+
+define <2 x i8> @ctlz_knownbits2_vec(<2 x i8> %arg) {
+; CHECK-LABEL: @ctlz_knownbits2_vec(
+; CHECK-NEXT:    [[OR:%.*]] = or <2 x i8> [[ARG:%.*]], <i8 32, i8 32>
+; CHECK-NEXT:    [[CNT:%.*]] = call <2 x i8> @llvm.ctlz.v2i8(<2 x i8> [[OR]], i1 true)
+; CHECK-NEXT:    ret <2 x i8> [[CNT]]
+;
+  %or = or <2 x i8> %arg, <i8 32, i8 32>
+  %cnt = call <2 x i8> @llvm.ctlz.v2i8(<2 x i8> %or, i1 true) nounwind readnone
+  ret <2 x i8> %cnt
+}
+
+define i1 @ctlz_knownbits3(i8 %arg) {
+; CHECK-LABEL: @ctlz_knownbits3(
+; CHECK-NEXT:    ret i1 false
+;
+  %or = or i8 %arg, 32
+  %cnt = call i8 @llvm.ctlz.i8(i8 %or, i1 true) nounwind readnone
+  %res = icmp eq i8 %cnt, 3
+  ret i1 %res
+}
+
+define <2 x i1> @ctlz_knownbits3_vec(<2 x i8> %arg) {
+; CHECK-LABEL: @ctlz_knownbits3_vec(
+; CHECK-NEXT:    ret <2 x i1> zeroinitializer
+;
+  %or = or <2 x i8> %arg, <i8 32, i8 32>
+  %cnt = call <2 x i8> @llvm.ctlz.v2i8(<2 x i8> %or, i1 true) nounwind readnone
+  %res = icmp eq <2 x i8> %cnt, <i8 3, i8 3>
+  ret <2 x i1> %res
+}
+
+define i32 @ctlz_undef(i32 %Value) {
+; CHECK-LABEL: @ctlz_undef(
+; CHECK-NEXT:    ret i32 undef
+;
+  %ctlz = call i32 @llvm.ctlz.i32(i32 0, i1 true)
+  ret i32 %ctlz
+}
+
+define <2 x i32> @ctlz_undef_vec(<2 x i32> %Value) {
+; CHECK-LABEL: @ctlz_undef_vec(
+; CHECK-NEXT:    ret <2 x i32> undef
+;
+  %ctlz = call <2 x i32> @llvm.ctlz.v2i32(<2 x i32> zeroinitializer, i1 true)
+  ret <2 x i32> %ctlz
+}
+
+define i32 @ctlz_make_undef(i32 %a) {
+  %or = or i32 %a, 8
+  %ctlz = tail call i32 @llvm.ctlz.i32(i32 %or, i1 false)
+  ret i32 %ctlz
+; CHECK-LABEL: @ctlz_make_undef(
+; CHECK-NEXT: %or = or i32 %a, 8
+; CHECK-NEXT: %ctlz = tail call i32 @llvm.ctlz.i32(i32 %or, i1 true)
+; CHECK-NEXT: ret i32 %ctlz
+}
+
+define <2 x i32> @ctlz_make_undef_vec(<2 x i32> %a) {
+; CHECK-LABEL: @ctlz_make_undef_vec(
+; CHECK-NEXT:    [[OR:%.*]] = or <2 x i32> [[A:%.*]], <i32 8, i32 8>
+; CHECK-NEXT:    [[CTLZ:%.*]] = tail call <2 x i32> @llvm.ctlz.v2i32(<2 x i32> [[OR]], i1 true)
+; CHECK-NEXT:    ret <2 x i32> [[CTLZ]]
+;
+  %or = or <2 x i32> %a, <i32 8, i32 8>
+  %ctlz = tail call <2 x i32> @llvm.ctlz.v2i32(<2 x i32> %or, i1 false)
+  ret <2 x i32> %ctlz
+}
+
+define i32 @cttz_undef(i32 %Value) nounwind {
+; CHECK-LABEL: @cttz_undef(
+; CHECK-NEXT:    ret i32 undef
+;
+  %cttz = call i32 @llvm.cttz.i32(i32 0, i1 true)
+  ret i32 %cttz
+}
+
+define <2 x i32> @cttz_undef_vec(<2 x i32> %Value) nounwind {
+; CHECK-LABEL: @cttz_undef_vec(
+; CHECK-NEXT:    ret <2 x i32> undef
+;
+  %cttz = call <2 x i32> @llvm.cttz.v2i32(<2 x i32> zeroinitializer, i1 true)
+  ret <2 x i32> %cttz
+}
+
+define i32 @cttz_make_undef(i32 %a) {
+  %or = or i32 %a, 8
+  %cttz = tail call i32 @llvm.cttz.i32(i32 %or, i1 false)
+  ret i32 %cttz
+; CHECK-LABEL: @cttz_make_undef(
+; CHECK-NEXT: %or = or i32 %a, 8
+; CHECK-NEXT: %cttz = tail call i32 @llvm.cttz.i32(i32 %or, i1 true)
+; CHECK-NEXT: ret i32 %cttz
+}
+
+define <2 x i32> @cttz_make_undef_vec(<2 x i32> %a) {
+; CHECK-LABEL: @cttz_make_undef_vec(
+; CHECK-NEXT:    [[OR:%.*]] = or <2 x i32> [[A:%.*]], <i32 8, i32 8>
+; CHECK-NEXT:    [[CTTZ:%.*]] = tail call <2 x i32> @llvm.cttz.v2i32(<2 x i32> [[OR]], i1 true)
+; CHECK-NEXT:    ret <2 x i32> [[CTTZ]]
+;
+  %or = or <2 x i32> %a, <i32 8, i32 8>
+  %cttz = tail call <2 x i32> @llvm.cttz.v2i32(<2 x i32> %or, i1 false)
+  ret <2 x i32> %cttz
+}
+
+define i32 @ctlz_select(i32 %Value) nounwind {
+; CHECK-LABEL: @ctlz_select(
+; CHECK-NEXT:    [[TMP1:%.*]] = call i32 @llvm.ctlz.i32(i32 %Value, i1 false)
+; CHECK-NEXT:    ret i32 [[TMP1]]
+;
+  %tobool = icmp ne i32 %Value, 0
+  %ctlz = call i32 @llvm.ctlz.i32(i32 %Value, i1 true)
+  %s = select i1 %tobool, i32 %ctlz, i32 32
+  ret i32 %s
+}
+
+define <2 x i32> @ctlz_select_vec(<2 x i32> %Value) nounwind {
+; CHECK-LABEL: @ctlz_select_vec(
+; CHECK-NEXT:    [[TMP1:%.*]] = call <2 x i32> @llvm.ctlz.v2i32(<2 x i32> [[VALUE:%.*]], i1 false)
+; CHECK-NEXT:    ret <2 x i32> [[TMP1]]
+;
+  %tobool = icmp ne <2 x i32> %Value, zeroinitializer
+  %ctlz = call <2 x i32> @llvm.ctlz.v2i32(<2 x i32> %Value, i1 true)
+  %s = select <2 x i1> %tobool, <2 x i32> %ctlz, <2 x i32> <i32 32, i32 32>
+  ret <2 x i32> %s
+}
+
+define i32 @cttz_select(i32 %Value) nounwind {
+; CHECK-LABEL: @cttz_select(
+; CHECK-NEXT:    [[TMP1:%.*]] = call i32 @llvm.cttz.i32(i32 %Value, i1 false)
+; CHECK-NEXT:    ret i32 [[TMP1]]
+;
+  %tobool = icmp ne i32 %Value, 0
+  %cttz = call i32 @llvm.cttz.i32(i32 %Value, i1 true)
+  %s = select i1 %tobool, i32 %cttz, i32 32
+  ret i32 %s
+}
+
+define <2 x i32> @cttz_select_vec(<2 x i32> %Value) nounwind {
+; CHECK-LABEL: @cttz_select_vec(
+; CHECK-NEXT:    [[TMP1:%.*]] = call <2 x i32> @llvm.cttz.v2i32(<2 x i32> [[VALUE:%.*]], i1 false)
+; CHECK-NEXT:    ret <2 x i32> [[TMP1]]
+;
+  %tobool = icmp ne <2 x i32> %Value, zeroinitializer
+  %cttz = call <2 x i32> @llvm.cttz.v2i32(<2 x i32> %Value, i1 true)
+  %s = select <2 x i1> %tobool, <2 x i32> %cttz, <2 x i32> <i32 32, i32 32>
+  ret <2 x i32> %s
+}
+
+define void @cos(double *%P) {
+; CHECK-LABEL: @cos(
+; CHECK-NEXT:    store volatile double 1.000000e+00, double* %P, align 8
+; CHECK-NEXT:    ret void
+;
+  %B = tail call double @llvm.cos.f64(double 0.0) nounwind
+  store volatile double %B, double* %P
+
+  ret void
+}
+
+define void @sin(double *%P) {
+; CHECK-LABEL: @sin(
+; CHECK-NEXT:    store volatile double 0.000000e+00, double* %P, align 8
+; CHECK-NEXT:    ret void
+;
+  %B = tail call double @llvm.sin.f64(double 0.0) nounwind
+  store volatile double %B, double* %P
+
+  ret void
+}
+
+define void @floor(double *%P) {
+; CHECK-LABEL: @floor(
+; CHECK-NEXT:    store volatile double 1.000000e+00, double* %P, align 8
+; CHECK-NEXT:    store volatile double -2.000000e+00, double* %P, align 8
+; CHECK-NEXT:    ret void
+;
+  %B = tail call double @llvm.floor.f64(double 1.5) nounwind
+  store volatile double %B, double* %P
+  %C = tail call double @llvm.floor.f64(double -1.5) nounwind
+  store volatile double %C, double* %P
+  ret void
+}
+
+define void @ceil(double *%P) {
+; CHECK-LABEL: @ceil(
+; CHECK-NEXT:    store volatile double 2.000000e+00, double* %P, align 8
+; CHECK-NEXT:    store volatile double -1.000000e+00, double* %P, align 8
+; CHECK-NEXT:    ret void
+;
+  %B = tail call double @llvm.ceil.f64(double 1.5) nounwind
+  store volatile double %B, double* %P
+  %C = tail call double @llvm.ceil.f64(double -1.5) nounwind
+  store volatile double %C, double* %P
+  ret void
+}
+
+define void @trunc(double *%P) {
+; CHECK-LABEL: @trunc(
+; CHECK-NEXT:    store volatile double 1.000000e+00, double* %P, align 8
+; CHECK-NEXT:    store volatile double -1.000000e+00, double* %P, align 8
+; CHECK-NEXT:    ret void
+;
+  %B = tail call double @llvm.trunc.f64(double 1.5) nounwind
+  store volatile double %B, double* %P
+  %C = tail call double @llvm.trunc.f64(double -1.5) nounwind
+  store volatile double %C, double* %P
+  ret void
+}
+
+define void @rint(double *%P) {
+; CHECK-LABEL: @rint(
+; CHECK-NEXT:    store volatile double 2.000000e+00, double* %P, align 8
+; CHECK-NEXT:    store volatile double -2.000000e+00, double* %P, align 8
+; CHECK-NEXT:    ret void
+;
+  %B = tail call double @llvm.rint.f64(double 1.5) nounwind
+  store volatile double %B, double* %P
+  %C = tail call double @llvm.rint.f64(double -1.5) nounwind
+  store volatile double %C, double* %P
+  ret void
+}
+
+define void @nearbyint(double *%P) {
+; CHECK-LABEL: @nearbyint(
+; CHECK-NEXT:    store volatile double 2.000000e+00, double* %P, align 8
+; CHECK-NEXT:    store volatile double -2.000000e+00, double* %P, align 8
+; CHECK-NEXT:    ret void
+;
+  %B = tail call double @llvm.nearbyint.f64(double 1.5) nounwind
+  store volatile double %B, double* %P
+  %C = tail call double @llvm.nearbyint.f64(double -1.5) nounwind
+  store volatile double %C, double* %P
+  ret void
+}
+
+; CHECK: [[$CTTZ_RANGE]] = !{i32 0, i32 3}
+; CHECK: [[$CTLZ_RANGE]] = !{i8 0, i8 3}

Added: llvm/trunk/test/Transforms/InstCombine/invariant.group.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/invariant.group.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/invariant.group.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/invariant.group.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,150 @@
+; RUN: opt -instcombine -early-cse -S < %s | FileCheck %s
+
+
+; CHECK-LABEL: define i8* @simplifyNullLaunder()
+define i8* @simplifyNullLaunder() {
+; CHECK-NEXT: ret i8* null
+  %b2 = call i8* @llvm.launder.invariant.group.p0i8(i8* null)
+  ret i8* %b2
+}
+
+; CHECK-LABEL: define i8* @dontSimplifyNullLaunderNoNullOpt()
+define i8* @dontSimplifyNullLaunderNoNullOpt() #0 {
+; CHECK-NEXT: call i8* @llvm.launder.invariant.group.p0i8(i8* null)
+  %b2 = call i8* @llvm.launder.invariant.group.p0i8(i8* null)
+  ret i8* %b2
+}
+
+; CHECK-LABEL: define i8 addrspace(42)* @dontsimplifyNullLaunderForDifferentAddrspace()
+define i8 addrspace(42)* @dontsimplifyNullLaunderForDifferentAddrspace() {
+; CHECK: %b2 = call i8 addrspace(42)* @llvm.launder.invariant.group.p42i8(i8 addrspace(42)* null)
+; CHECK: ret i8 addrspace(42)* %b2
+  %b2 = call i8 addrspace(42)* @llvm.launder.invariant.group.p42i8(i8 addrspace(42)* null)
+  ret i8 addrspace(42)* %b2
+}
+
+; CHECK-LABEL: define i8* @simplifyUndefLaunder()
+define i8* @simplifyUndefLaunder() {
+; CHECK-NEXT: ret i8* undef
+  %b2 = call i8* @llvm.launder.invariant.group.p0i8(i8* undef)
+  ret i8* %b2
+}
+
+; CHECK-LABEL: define i8 addrspace(42)* @simplifyUndefLaunder2()
+define i8 addrspace(42)* @simplifyUndefLaunder2() {
+; CHECK-NEXT: ret i8 addrspace(42)* undef
+  %b2 = call i8 addrspace(42)* @llvm.launder.invariant.group.p42i8(i8 addrspace(42)* undef)
+  ret i8 addrspace(42)* %b2
+}
+
+; CHECK-LABEL: define i8* @simplifyNullStrip()
+define i8* @simplifyNullStrip() {
+; CHECK-NEXT: ret i8* null
+  %b2 = call i8* @llvm.strip.invariant.group.p0i8(i8* null)
+  ret i8* %b2
+}
+
+; CHECK-LABEL: define i8* @dontSimplifyNullStripNonNullOpt()
+define i8* @dontSimplifyNullStripNonNullOpt() #0 {
+; CHECK-NEXT: call i8* @llvm.strip.invariant.group.p0i8(i8* null)
+  %b2 = call i8* @llvm.strip.invariant.group.p0i8(i8* null)
+  ret i8* %b2
+}
+
+; CHECK-LABEL: define i8 addrspace(42)* @dontsimplifyNullStripForDifferentAddrspace()
+define i8 addrspace(42)* @dontsimplifyNullStripForDifferentAddrspace() {
+; CHECK: %b2 = call i8 addrspace(42)* @llvm.strip.invariant.group.p42i8(i8 addrspace(42)* null)
+; CHECK: ret i8 addrspace(42)* %b2
+  %b2 = call i8 addrspace(42)* @llvm.strip.invariant.group.p42i8(i8 addrspace(42)* null)
+  ret i8 addrspace(42)* %b2
+}
+
+; CHECK-LABEL: define i8* @simplifyUndefStrip()
+define i8* @simplifyUndefStrip() {
+; CHECK-NEXT: ret i8* undef
+  %b2 = call i8* @llvm.strip.invariant.group.p0i8(i8* undef)
+  ret i8* %b2
+}
+
+; CHECK-LABEL: define i8 addrspace(42)* @simplifyUndefStrip2()
+define i8 addrspace(42)* @simplifyUndefStrip2() {
+; CHECK-NEXT: ret i8 addrspace(42)* undef
+  %b2 = call i8 addrspace(42)* @llvm.strip.invariant.group.p42i8(i8 addrspace(42)* undef)
+  ret i8 addrspace(42)* %b2
+}
+
+; CHECK-LABEL: define i8* @simplifyLaunderOfLaunder(
+define i8* @simplifyLaunderOfLaunder(i8* %a) {
+; CHECK:   call i8* @llvm.launder.invariant.group.p0i8(i8* %a)
+; CHECK-NOT: llvm.launder.invariant.group
+  %a2 = call i8* @llvm.launder.invariant.group.p0i8(i8* %a)
+  %a3 = call i8* @llvm.launder.invariant.group.p0i8(i8* %a2)
+  ret i8* %a3
+}
+
+; CHECK-LABEL: define i8* @simplifyStripOfLaunder(
+define i8* @simplifyStripOfLaunder(i8* %a) {
+; CHECK-NOT: llvm.launder.invariant.group
+; CHECK:   call i8* @llvm.strip.invariant.group.p0i8(i8* %a)
+  %a2 = call i8* @llvm.launder.invariant.group.p0i8(i8* %a)
+  %a3 = call i8* @llvm.strip.invariant.group.p0i8(i8* %a2)
+  ret i8* %a3
+}
+
+; CHECK-LABEL: define i1 @simplifyForCompare(
+define i1 @simplifyForCompare(i8* %a) {
+  %a2 = call i8* @llvm.launder.invariant.group.p0i8(i8* %a)
+
+  %a3 = call i8* @llvm.strip.invariant.group.p0i8(i8* %a2)
+  %b2 = call i8* @llvm.strip.invariant.group.p0i8(i8* %a)
+  %c = icmp eq i8* %a3, %b2
+; CHECK: ret i1 true
+  ret i1 %c
+}
+
+; CHECK-LABEL: define i16* @skipWithDifferentTypes(
+define i16* @skipWithDifferentTypes(i8* %a) {
+  %a2 = call i8* @llvm.launder.invariant.group.p0i8(i8* %a)
+  %c1 = bitcast i8* %a2 to i16*
+
+  ; CHECK: %[[b:.*]] = call i8* @llvm.strip.invariant.group.p0i8(i8* %a)
+  %a3 = call i16* @llvm.strip.invariant.group.p0i16(i16* %c1)
+  ; CHECK-NEXT: %[[r:.*]] = bitcast i8* %[[b]] to i16*
+  ; CHECK-NEXT: ret i16* %[[r]]
+  ret i16* %a3
+}
+
+; CHECK-LABEL: define i16 addrspace(42)* @skipWithDifferentTypesAddrspace(
+define i16 addrspace(42)* @skipWithDifferentTypesAddrspace(i8 addrspace(42)* %a) {
+  %a2 = call i8 addrspace(42)* @llvm.launder.invariant.group.p42i8(i8 addrspace(42)* %a)
+  %c1 = bitcast i8 addrspace(42)* %a2 to i16 addrspace(42)*
+
+  ; CHECK: %[[b:.*]] = call i8 addrspace(42)* @llvm.strip.invariant.group.p42i8(i8 addrspace(42)* %a)
+  %a3 = call i16 addrspace(42)* @llvm.strip.invariant.group.p42i16(i16 addrspace(42)* %c1)
+  ; CHECK-NEXT: %[[r:.*]] = bitcast i8 addrspace(42)* %[[b]] to i16 addrspace(42)*
+  ; CHECK-NEXT: ret i16 addrspace(42)* %[[r]]
+  ret i16 addrspace(42)* %a3
+}
+
+; CHECK-LABEL: define i16 addrspace(42)* @skipWithDifferentTypesDifferentAddrspace(
+define i16 addrspace(42)* @skipWithDifferentTypesDifferentAddrspace(i8* %a) {
+  %cast = addrspacecast i8* %a to i8 addrspace(42)*
+  %a2 = call i8 addrspace(42)* @llvm.launder.invariant.group.p42i8(i8 addrspace(42)* %cast)
+  %c1 = bitcast i8 addrspace(42)* %a2 to i16 addrspace(42)*
+
+  ; CHECK: %[[b:.*]] = call i8* @llvm.strip.invariant.group.p0i8(i8* %a)
+  %a3 = call i16 addrspace(42)* @llvm.strip.invariant.group.p42i16(i16 addrspace(42)* %c1)
+  ; CHECK-NEXT: %[[r:.*]] = bitcast i8* %[[b]] to i16*
+  ; CHECK-NEXT: %[[r2:.*]] = addrspacecast i16* %[[r]] to i16 addrspace(42)*
+  ; CHECK-NEXT: ret i16 addrspace(42)* %[[r2]]
+  ret i16 addrspace(42)* %a3
+}
+
+declare i8* @llvm.launder.invariant.group.p0i8(i8*)
+declare i8 addrspace(42)* @llvm.launder.invariant.group.p42i8(i8 addrspace(42)*)
+declare i8* @llvm.strip.invariant.group.p0i8(i8*)
+declare i8 addrspace(42)* @llvm.strip.invariant.group.p42i8(i8 addrspace(42)*)
+declare i16* @llvm.strip.invariant.group.p0i16(i16* %c1)
+declare i16 addrspace(42)* @llvm.strip.invariant.group.p42i16(i16 addrspace(42)* %c1)
+
+attributes #0 = { "null-pointer-is-valid"="true" }

Added: llvm/trunk/test/Transforms/InstCombine/invariant.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/invariant.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/invariant.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/invariant.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,28 @@
+; Test to make sure unused llvm.invariant.start calls are not trivially eliminated
+; RUN: opt < %s -instcombine -S | FileCheck %s
+
+declare void @g(i8*)
+declare void @g_addr1(i8 addrspace(1)*)
+
+declare {}* @llvm.invariant.start.p0i8(i64, i8* nocapture) nounwind readonly
+declare {}* @llvm.invariant.start.p1i8(i64, i8 addrspace(1)* nocapture) nounwind readonly
+
+define i8 @f() {
+  %a = alloca i8                                  ; <i8*> [#uses=4]
+  store i8 0, i8* %a
+  %i = call {}* @llvm.invariant.start.p0i8(i64 1, i8* %a) ; <{}*> [#uses=0]
+  ; CHECK: call {}* @llvm.invariant.start.p0i8
+  call void @g(i8* %a)
+  %r = load i8, i8* %a                                ; <i8> [#uses=1]
+  ret i8 %r
+}
+
+; make sure llvm.invariant.call in non-default addrspace are also not eliminated.
+define i8 @f_addrspace1(i8 addrspace(1)* %a) {
+  store i8 0, i8 addrspace(1)* %a
+  %i = call {}* @llvm.invariant.start.p1i8(i64 1, i8 addrspace(1)* %a) ; <{}*> [#uses=0]
+  ; CHECK: call {}* @llvm.invariant.start.p1i8
+  call void @g_addr1(i8 addrspace(1)* %a)
+  %r = load i8, i8 addrspace(1)* %a                                ; <i8> [#uses=1]
+  ret i8 %r
+}

Added: llvm/trunk/test/Transforms/InstCombine/invert-variable-mask-in-masked-merge-scalar.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/invert-variable-mask-in-masked-merge-scalar.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/invert-variable-mask-in-masked-merge-scalar.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/invert-variable-mask-in-masked-merge-scalar.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,318 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt < %s -instcombine -S | FileCheck %s
+
+; If we have a masked merge, in the form of: (M is not constant)
+;   ((x ^ y) & ~M) ^ y
+; We can de-invert the M:
+;   ((x ^ y) & M) ^ x
+
+define i4 @scalar (i4 %x, i4 %y, i4 %m) {
+; CHECK-LABEL: @scalar(
+; CHECK-NEXT:    [[N0:%.*]] = xor i4 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    [[TMP1:%.*]] = and i4 [[N0]], [[M:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = xor i4 [[TMP1]], [[X]]
+; CHECK-NEXT:    ret i4 [[R]]
+;
+  %im = xor i4 %m, -1
+  %n0 = xor i4 %x, %y
+  %n1 = and i4 %n0, %im
+  %r  = xor i4 %n1, %y
+  ret i4 %r
+}
+
+; ============================================================================ ;
+; Various cases with %x and/or %y being a constant
+; ============================================================================ ;
+
+define i4 @in_constant_varx_mone_invmask(i4 %x, i4 %mask) {
+; CHECK-LABEL: @in_constant_varx_mone_invmask(
+; CHECK-NEXT:    [[N1_DEMORGAN:%.*]] = or i4 [[X:%.*]], [[MASK:%.*]]
+; CHECK-NEXT:    ret i4 [[N1_DEMORGAN]]
+;
+  %notmask = xor i4 %mask, -1
+  %n0 = xor i4 %x, -1 ; %x
+  %n1 = and i4 %n0, %notmask
+  %r = xor i4 %n1, -1
+  ret i4 %r
+}
+
+define i4 @in_constant_varx_6_invmask(i4 %x, i4 %mask) {
+; CHECK-LABEL: @in_constant_varx_6_invmask(
+; CHECK-NEXT:    [[N0:%.*]] = xor i4 [[X:%.*]], 6
+; CHECK-NEXT:    [[TMP1:%.*]] = and i4 [[N0]], [[MASK:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = xor i4 [[TMP1]], [[X]]
+; CHECK-NEXT:    ret i4 [[R]]
+;
+  %notmask = xor i4 %mask, -1
+  %n0 = xor i4 %x, 6 ; %x
+  %n1 = and i4 %n0, %notmask
+  %r = xor i4 %n1, 6
+  ret i4 %r
+}
+
+define i4 @in_constant_mone_vary_invmask(i4 %y, i4 %mask) {
+; CHECK-LABEL: @in_constant_mone_vary_invmask(
+; CHECK-NEXT:    [[N1_DEMORGAN:%.*]] = or i4 [[Y:%.*]], [[MASK:%.*]]
+; CHECK-NEXT:    [[N1:%.*]] = xor i4 [[N1_DEMORGAN]], -1
+; CHECK-NEXT:    [[R:%.*]] = xor i4 [[N1]], [[Y]]
+; CHECK-NEXT:    ret i4 [[R]]
+;
+  %notmask = xor i4 %mask, -1
+  %n0 = xor i4 -1, %y ; %x
+  %n1 = and i4 %n0, %notmask
+  %r = xor i4 %n1, %y
+  ret i4 %r
+}
+
+define i4 @in_constant_6_vary_invmask(i4 %y, i4 %mask) {
+; CHECK-LABEL: @in_constant_6_vary_invmask(
+; CHECK-NEXT:    [[N0:%.*]] = xor i4 [[Y:%.*]], 6
+; CHECK-NEXT:    [[TMP1:%.*]] = and i4 [[N0]], [[MASK:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = xor i4 [[TMP1]], 6
+; CHECK-NEXT:    ret i4 [[R]]
+;
+  %notmask = xor i4 %mask, -1
+  %n0 = xor i4 %y, 6 ; %x
+  %n1 = and i4 %n0, %notmask
+  %r = xor i4 %n1, %y
+  ret i4 %r
+}
+
+; ============================================================================ ;
+; Commutativity
+; ============================================================================ ;
+
+; Used to make sure that the IR complexity sorting does not interfere.
+declare i4 @gen4()
+
+; FIXME: should the  %n1 = and i4 %im, %n0  swapped order pattern be tested?
+
+define i4 @c_1_0_0 (i4 %x, i4 %y, i4 %m) {
+; CHECK-LABEL: @c_1_0_0(
+; CHECK-NEXT:    [[N0:%.*]] = xor i4 [[Y:%.*]], [[X:%.*]]
+; CHECK-NEXT:    [[TMP1:%.*]] = and i4 [[N0]], [[M:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = xor i4 [[TMP1]], [[X]]
+; CHECK-NEXT:    ret i4 [[R]]
+;
+  %im = xor i4 %m, -1
+  %n0 = xor i4 %y, %x ; swapped order
+  %n1 = and i4 %n0, %im
+  %r  = xor i4 %n1, %y
+  ret i4 %r
+}
+
+define i4 @c_0_1_0 (i4 %x, i4 %y, i4 %m) {
+; CHECK-LABEL: @c_0_1_0(
+; CHECK-NEXT:    [[N0:%.*]] = xor i4 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    [[TMP1:%.*]] = and i4 [[N0]], [[M:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = xor i4 [[TMP1]], [[Y]]
+; CHECK-NEXT:    ret i4 [[R]]
+;
+  %im = xor i4 %m, -1
+  %n0 = xor i4 %x, %y
+  %n1 = and i4 %n0, %im
+  %r  = xor i4 %n1, %x ; %x instead of %y
+  ret i4 %r
+}
+
+define i4 @c_0_0_1 (i4 %m) {
+; CHECK-LABEL: @c_0_0_1(
+; CHECK-NEXT:    [[X:%.*]] = call i4 @gen4()
+; CHECK-NEXT:    [[Y:%.*]] = call i4 @gen4()
+; CHECK-NEXT:    [[N0:%.*]] = xor i4 [[X]], [[Y]]
+; CHECK-NEXT:    [[TMP1:%.*]] = and i4 [[N0]], [[M:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = xor i4 [[TMP1]], [[X]]
+; CHECK-NEXT:    ret i4 [[R]]
+;
+  %im = xor i4 %m, -1
+  %x  = call i4 @gen4()
+  %y  = call i4 @gen4()
+  %n0 = xor i4 %x, %y
+  %n1 = and i4 %n0, %im
+  %r  = xor i4 %y, %n1 ; swapped order
+  ret i4 %r
+}
+
+define i4 @c_1_1_0 (i4 %x, i4 %y, i4 %m) {
+; CHECK-LABEL: @c_1_1_0(
+; CHECK-NEXT:    [[N0:%.*]] = xor i4 [[Y:%.*]], [[X:%.*]]
+; CHECK-NEXT:    [[TMP1:%.*]] = and i4 [[N0]], [[M:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = xor i4 [[TMP1]], [[Y]]
+; CHECK-NEXT:    ret i4 [[R]]
+;
+  %im = xor i4 %m, -1
+  %n0 = xor i4 %y, %x ; swapped order
+  %n1 = and i4 %n0, %im
+  %r  = xor i4 %n1, %x ; %x instead of %y
+  ret i4 %r
+}
+
+define i4 @c_1_0_1 (i4 %x, i4 %m) {
+; CHECK-LABEL: @c_1_0_1(
+; CHECK-NEXT:    [[Y:%.*]] = call i4 @gen4()
+; CHECK-NEXT:    [[N0:%.*]] = xor i4 [[Y]], [[X:%.*]]
+; CHECK-NEXT:    [[TMP1:%.*]] = and i4 [[N0]], [[M:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = xor i4 [[TMP1]], [[X]]
+; CHECK-NEXT:    ret i4 [[R]]
+;
+  %im = xor i4 %m, -1
+  %y  = call i4 @gen4()
+  %n0 = xor i4 %y, %x ; swapped order
+  %n1 = and i4 %n0, %im
+  %r  = xor i4 %y, %n1 ; swapped order
+  ret i4 %r
+}
+
+define i4 @c_0_1_1 (i4 %y, i4 %m) {
+; CHECK-LABEL: @c_0_1_1(
+; CHECK-NEXT:    [[X:%.*]] = call i4 @gen4()
+; CHECK-NEXT:    [[N0:%.*]] = xor i4 [[X]], [[Y:%.*]]
+; CHECK-NEXT:    [[TMP1:%.*]] = and i4 [[N0]], [[M:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = xor i4 [[TMP1]], [[Y]]
+; CHECK-NEXT:    ret i4 [[R]]
+;
+  %im = xor i4 %m, -1
+  %x  = call i4 @gen4()
+  %n0 = xor i4 %x, %y
+  %n1 = and i4 %n0, %im
+  %r  = xor i4 %x, %n1 ; swapped order, %x instead of %y
+  ret i4 %r
+}
+
+define i4 @c_1_1_1 (i4 %m) {
+; CHECK-LABEL: @c_1_1_1(
+; CHECK-NEXT:    [[X:%.*]] = call i4 @gen4()
+; CHECK-NEXT:    [[Y:%.*]] = call i4 @gen4()
+; CHECK-NEXT:    [[N0:%.*]] = xor i4 [[Y]], [[X]]
+; CHECK-NEXT:    [[TMP1:%.*]] = and i4 [[N0]], [[M:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = xor i4 [[TMP1]], [[Y]]
+; CHECK-NEXT:    ret i4 [[R]]
+;
+  %im = xor i4 %m, -1
+  %x  = call i4 @gen4()
+  %y  = call i4 @gen4()
+  %n0 = xor i4 %y, %x ; swapped order
+  %n1 = and i4 %n0, %im
+  %r  = xor i4 %x, %n1 ; swapped order, %x instead of %y
+  ret i4 %r
+}
+
+define i4 @commutativity_constant_varx_6_invmask(i4 %x, i4 %mask) {
+; CHECK-LABEL: @commutativity_constant_varx_6_invmask(
+; CHECK-NEXT:    [[N0:%.*]] = xor i4 [[X:%.*]], 6
+; CHECK-NEXT:    [[TMP1:%.*]] = and i4 [[N0]], [[MASK:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = xor i4 [[TMP1]], [[X]]
+; CHECK-NEXT:    ret i4 [[R]]
+;
+  %notmask = xor i4 %mask, -1
+  %n0 = xor i4 %x, 6 ; %x
+  %n1 = and i4 %notmask, %n0 ; swapped
+  %r = xor i4 %n1, 6
+  ret i4 %r
+}
+
+define i4 @commutativity_constant_6_vary_invmask(i4 %y, i4 %mask) {
+; CHECK-LABEL: @commutativity_constant_6_vary_invmask(
+; CHECK-NEXT:    [[N0:%.*]] = xor i4 [[Y:%.*]], 6
+; CHECK-NEXT:    [[TMP1:%.*]] = and i4 [[N0]], [[MASK:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = xor i4 [[TMP1]], 6
+; CHECK-NEXT:    ret i4 [[R]]
+;
+  %notmask = xor i4 %mask, -1
+  %n0 = xor i4 %y, 6 ; %x
+  %n1 = and i4 %notmask, %n0 ; swapped
+  %r = xor i4 %n1, %y
+  ret i4 %r
+}
+
+; ============================================================================ ;
+; Negative tests. Should not be folded.
+; ============================================================================ ;
+
+; One use only.
+
+declare void @use4(i4)
+
+define i4 @n_oneuse_D_is_ok (i4 %x, i4 %y, i4 %m) {
+; CHECK-LABEL: @n_oneuse_D_is_ok(
+; CHECK-NEXT:    [[N0:%.*]] = xor i4 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    [[TMP1:%.*]] = and i4 [[N0]], [[M:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = xor i4 [[TMP1]], [[X]]
+; CHECK-NEXT:    call void @use4(i4 [[N0]])
+; CHECK-NEXT:    ret i4 [[R]]
+;
+  %im = xor i4 %m, -1
+  %n0 = xor i4 %x, %y ; two uses of %n0, THIS IS OK!
+  %n1 = and i4 %n0, %im
+  %r  = xor i4 %n1, %y
+  call void @use4(i4 %n0)
+  ret i4 %r
+}
+
+define i4 @n_oneuse_A (i4 %x, i4 %y, i4 %m) {
+; CHECK-LABEL: @n_oneuse_A(
+; CHECK-NEXT:    [[IM:%.*]] = xor i4 [[M:%.*]], -1
+; CHECK-NEXT:    [[N0:%.*]] = xor i4 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    [[N1:%.*]] = and i4 [[N0]], [[IM]]
+; CHECK-NEXT:    [[R:%.*]] = xor i4 [[N1]], [[Y]]
+; CHECK-NEXT:    call void @use4(i4 [[N1]])
+; CHECK-NEXT:    ret i4 [[R]]
+;
+  %im = xor i4 %m, -1
+  %n0 = xor i4 %x, %y
+  %n1 = and i4 %n0, %im ; two uses of %n1, which is going to be replaced
+  %r  = xor i4 %n1, %y
+  call void @use4(i4 %n1)
+  ret i4 %r
+}
+
+define i4 @n_oneuse_AD (i4 %x, i4 %y, i4 %m) {
+; CHECK-LABEL: @n_oneuse_AD(
+; CHECK-NEXT:    [[IM:%.*]] = xor i4 [[M:%.*]], -1
+; CHECK-NEXT:    [[N0:%.*]] = xor i4 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    [[N1:%.*]] = and i4 [[N0]], [[IM]]
+; CHECK-NEXT:    [[R:%.*]] = xor i4 [[N1]], [[Y]]
+; CHECK-NEXT:    call void @use4(i4 [[N0]])
+; CHECK-NEXT:    call void @use4(i4 [[N1]])
+; CHECK-NEXT:    ret i4 [[R]]
+;
+  %im = xor i4 %m, -1
+  %n0 = xor i4 %x, %y
+  %n1 = and i4 %n0, %im ; two uses of %n1, which is going to be replaced
+  %r  = xor i4 %n1, %y
+  call void @use4(i4 %n0)
+  call void @use4(i4 %n1)
+  ret i4 %r
+}
+
+; Some third variable is used
+
+define i4 @n_third_var (i4 %x, i4 %y, i4 %z, i4 %m) {
+; CHECK-LABEL: @n_third_var(
+; CHECK-NEXT:    [[IM:%.*]] = xor i4 [[M:%.*]], -1
+; CHECK-NEXT:    [[N0:%.*]] = xor i4 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    [[N1:%.*]] = and i4 [[N0]], [[IM]]
+; CHECK-NEXT:    [[R:%.*]] = xor i4 [[N1]], [[Z:%.*]]
+; CHECK-NEXT:    ret i4 [[R]]
+;
+  %im = xor i4 %m, -1
+  %n0 = xor i4 %x, %y
+  %n1 = and i4 %n0, %im
+  %r  = xor i4 %n1, %z ; not %x or %y
+  ret i4 %r
+}
+
+define i4 @n_badxor (i4 %x, i4 %y, i4 %m) {
+; CHECK-LABEL: @n_badxor(
+; CHECK-NEXT:    [[IM:%.*]] = xor i4 [[M:%.*]], 1
+; CHECK-NEXT:    [[N0:%.*]] = xor i4 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    [[N1:%.*]] = and i4 [[N0]], [[IM]]
+; CHECK-NEXT:    [[R:%.*]] = xor i4 [[N1]], [[Y]]
+; CHECK-NEXT:    ret i4 [[R]]
+;
+  %im = xor i4 %m, 1 ; not -1
+  %n0 = xor i4 %x, %y
+  %n1 = and i4 %n0, %im
+  %r  = xor i4 %n1, %y
+  ret i4 %r
+}

Added: llvm/trunk/test/Transforms/InstCombine/invert-variable-mask-in-masked-merge-vector.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/invert-variable-mask-in-masked-merge-vector.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/invert-variable-mask-in-masked-merge-vector.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/invert-variable-mask-in-masked-merge-vector.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,421 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt < %s -instcombine -S | FileCheck %s
+
+; If we have a masked merge, in the form of: (M is not constant)
+;   ((x ^ y) & ~M) ^ y
+; We can de-invert the M:
+;   ((x ^ y) & M) ^ x
+
+define <2 x i4> @vector (<2 x i4> %x, <2 x i4> %y, <2 x i4> %m) {
+; CHECK-LABEL: @vector(
+; CHECK-NEXT:    [[N0:%.*]] = xor <2 x i4> [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    [[TMP1:%.*]] = and <2 x i4> [[N0]], [[M:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = xor <2 x i4> [[TMP1]], [[X]]
+; CHECK-NEXT:    ret <2 x i4> [[R]]
+;
+  %im = xor <2 x i4> %m, <i4 -1, i4 -1>
+  %n0 = xor <2 x i4> %x, %y
+  %n1 = and <2 x i4> %n0, %im
+  %r  = xor <2 x i4> %n1, %y
+  ret <2 x i4> %r
+}
+
+define <3 x i4> @vector_undef (<3 x i4> %x, <3 x i4> %y, <3 x i4> %m) {
+; CHECK-LABEL: @vector_undef(
+; CHECK-NEXT:    [[N0:%.*]] = xor <3 x i4> [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    [[TMP1:%.*]] = and <3 x i4> [[N0]], [[M:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = xor <3 x i4> [[TMP1]], [[X]]
+; CHECK-NEXT:    ret <3 x i4> [[R]]
+;
+  %im = xor <3 x i4> %m, <i4 -1, i4 undef, i4 -1>
+  %n0 = xor <3 x i4> %x, %y
+  %n1 = and <3 x i4> %n0, %im
+  %r  = xor <3 x i4> %n1, %y
+  ret <3 x i4> %r
+}
+
+; ============================================================================ ;
+; Various cases with %x and/or %y being a constant
+; ============================================================================ ;
+
+define <2 x i4> @in_constant_varx_mone_invmask(<2 x i4> %x, <2 x i4> %mask) {
+; CHECK-LABEL: @in_constant_varx_mone_invmask(
+; CHECK-NEXT:    [[N1_DEMORGAN:%.*]] = or <2 x i4> [[X:%.*]], [[MASK:%.*]]
+; CHECK-NEXT:    ret <2 x i4> [[N1_DEMORGAN]]
+;
+  %notmask = xor <2 x i4> %mask, <i4 -1, i4 -1>
+  %n0 = xor <2 x i4> %x, <i4 -1, i4 -1> ; %x
+  %n1 = and <2 x i4> %n0, %notmask
+  %r = xor <2 x i4> %n1, <i4 -1, i4 -1>
+  ret <2 x i4> %r
+}
+
+define <2 x i4> @in_constant_varx_6_invmask(<2 x i4> %x, <2 x i4> %mask) {
+; CHECK-LABEL: @in_constant_varx_6_invmask(
+; CHECK-NEXT:    [[N0:%.*]] = xor <2 x i4> [[X:%.*]], <i4 6, i4 6>
+; CHECK-NEXT:    [[TMP1:%.*]] = and <2 x i4> [[N0]], [[MASK:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = xor <2 x i4> [[TMP1]], [[X]]
+; CHECK-NEXT:    ret <2 x i4> [[R]]
+;
+  %notmask = xor <2 x i4> %mask, <i4 -1, i4 -1>
+  %n0 = xor <2 x i4> %x, <i4 6, i4 6> ; %x
+  %n1 = and <2 x i4> %n0, %notmask
+  %r = xor <2 x i4> %n1, <i4 6, i4 6>
+  ret <2 x i4> %r
+}
+
+define <2 x i4> @in_constant_varx_6_invmask_nonsplat(<2 x i4> %x, <2 x i4> %mask) {
+; CHECK-LABEL: @in_constant_varx_6_invmask_nonsplat(
+; CHECK-NEXT:    [[N0:%.*]] = xor <2 x i4> [[X:%.*]], <i4 6, i4 7>
+; CHECK-NEXT:    [[TMP1:%.*]] = and <2 x i4> [[N0]], [[MASK:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = xor <2 x i4> [[TMP1]], [[X]]
+; CHECK-NEXT:    ret <2 x i4> [[R]]
+;
+  %notmask = xor <2 x i4> %mask, <i4 -1, i4 -1>
+  %n0 = xor <2 x i4> %x, <i4 6, i4 7> ; %x
+  %n1 = and <2 x i4> %n0, %notmask
+  %r = xor <2 x i4> %n1, <i4 6, i4 7>
+  ret <2 x i4> %r
+}
+
+define <3 x i4> @in_constant_varx_6_invmask_undef(<3 x i4> %x, <3 x i4> %mask) {
+; CHECK-LABEL: @in_constant_varx_6_invmask_undef(
+; CHECK-NEXT:    [[N0:%.*]] = xor <3 x i4> [[X:%.*]], <i4 6, i4 undef, i4 7>
+; CHECK-NEXT:    [[TMP1:%.*]] = and <3 x i4> [[N0]], [[MASK:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = xor <3 x i4> [[TMP1]], [[X]]
+; CHECK-NEXT:    ret <3 x i4> [[R]]
+;
+  %notmask = xor <3 x i4> %mask, <i4 -1, i4 undef, i4 -1>
+  %n0 = xor <3 x i4> %x, <i4 6, i4 undef, i4 7> ; %x
+  %n1 = and <3 x i4> %n0, %notmask
+  %r = xor <3 x i4> %n1, <i4 6, i4 undef, i4 7>
+  ret <3 x i4> %r
+}
+
+define <2 x i4> @in_constant_mone_vary_invmask(<2 x i4> %y, <2 x i4> %mask) {
+; CHECK-LABEL: @in_constant_mone_vary_invmask(
+; CHECK-NEXT:    [[N1_DEMORGAN:%.*]] = or <2 x i4> [[Y:%.*]], [[MASK:%.*]]
+; CHECK-NEXT:    [[N1:%.*]] = xor <2 x i4> [[N1_DEMORGAN]], <i4 -1, i4 -1>
+; CHECK-NEXT:    [[R:%.*]] = xor <2 x i4> [[N1]], [[Y]]
+; CHECK-NEXT:    ret <2 x i4> [[R]]
+;
+  %notmask = xor <2 x i4> %mask, <i4 -1, i4 -1>
+  %n0 = xor <2 x i4> <i4 -1, i4 -1>, %y ; %x
+  %n1 = and <2 x i4> %n0, %notmask
+  %r = xor <2 x i4> %n1, %y
+  ret <2 x i4> %r
+}
+
+define <2 x i4> @in_constant_6_vary_invmask(<2 x i4> %y, <2 x i4> %mask) {
+; CHECK-LABEL: @in_constant_6_vary_invmask(
+; CHECK-NEXT:    [[N0:%.*]] = xor <2 x i4> [[Y:%.*]], <i4 6, i4 6>
+; CHECK-NEXT:    [[TMP1:%.*]] = and <2 x i4> [[N0]], [[MASK:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = xor <2 x i4> [[TMP1]], <i4 6, i4 6>
+; CHECK-NEXT:    ret <2 x i4> [[R]]
+;
+  %notmask = xor <2 x i4> %mask, <i4 -1, i4 -1>
+  %n0 = xor <2 x i4> %y, <i4 6, i4 6> ; %x
+  %n1 = and <2 x i4> %n0, %notmask
+  %r = xor <2 x i4> %n1, %y
+  ret <2 x i4> %r
+}
+
+define <2 x i4> @in_constant_6_vary_invmask_nonsplat(<2 x i4> %y, <2 x i4> %mask) {
+; CHECK-LABEL: @in_constant_6_vary_invmask_nonsplat(
+; CHECK-NEXT:    [[N0:%.*]] = xor <2 x i4> [[Y:%.*]], <i4 6, i4 7>
+; CHECK-NEXT:    [[TMP1:%.*]] = and <2 x i4> [[N0]], [[MASK:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = xor <2 x i4> [[TMP1]], <i4 6, i4 7>
+; CHECK-NEXT:    ret <2 x i4> [[R]]
+;
+  %notmask = xor <2 x i4> %mask, <i4 -1, i4 -1>
+  %n0 = xor <2 x i4> %y, <i4 6, i4 7> ; %x
+  %n1 = and <2 x i4> %n0, %notmask
+  %r = xor <2 x i4> %n1, %y
+  ret <2 x i4> %r
+}
+
+define <3 x i4> @in_constant_6_vary_invmask_undef(<3 x i4> %y, <3 x i4> %mask) {
+; CHECK-LABEL: @in_constant_6_vary_invmask_undef(
+; CHECK-NEXT:    [[N0:%.*]] = xor <3 x i4> [[Y:%.*]], <i4 6, i4 undef, i4 6>
+; CHECK-NEXT:    [[TMP1:%.*]] = and <3 x i4> [[N0]], [[MASK:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = xor <3 x i4> [[TMP1]], <i4 6, i4 undef, i4 6>
+; CHECK-NEXT:    ret <3 x i4> [[R]]
+;
+  %notmask = xor <3 x i4> %mask, <i4 -1, i4 undef, i4 -1>
+  %n0 = xor <3 x i4> %y, <i4 6, i4 undef, i4 6> ; %x
+  %n1 = and <3 x i4> %n0, %notmask
+  %r = xor <3 x i4> %n1, %y
+  ret <3 x i4> %r
+}
+
+; ============================================================================ ;
+; Commutativity
+; ============================================================================ ;
+
+; Used to make sure that the IR complexity sorting does not interfere.
+declare <2 x i4> @gen4()
+
+; FIXME: should  %n1 = and <2 x i4> %im, %n0  swapped order pattern be tested?
+
+define <2 x i4> @c_1_0_0 (<2 x i4> %x, <2 x i4> %y, <2 x i4> %m) {
+; CHECK-LABEL: @c_1_0_0(
+; CHECK-NEXT:    [[N0:%.*]] = xor <2 x i4> [[Y:%.*]], [[X:%.*]]
+; CHECK-NEXT:    [[TMP1:%.*]] = and <2 x i4> [[N0]], [[M:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = xor <2 x i4> [[TMP1]], [[X]]
+; CHECK-NEXT:    ret <2 x i4> [[R]]
+;
+  %im = xor <2 x i4> %m, <i4 -1, i4 -1>
+  %n0 = xor <2 x i4> %y, %x ; swapped order
+  %n1 = and <2 x i4> %n0, %im
+  %r  = xor <2 x i4> %n1, %y
+  ret <2 x i4> %r
+}
+
+define <2 x i4> @c_0_1_0 (<2 x i4> %x, <2 x i4> %y, <2 x i4> %m) {
+; CHECK-LABEL: @c_0_1_0(
+; CHECK-NEXT:    [[N0:%.*]] = xor <2 x i4> [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    [[TMP1:%.*]] = and <2 x i4> [[N0]], [[M:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = xor <2 x i4> [[TMP1]], [[Y]]
+; CHECK-NEXT:    ret <2 x i4> [[R]]
+;
+  %im = xor <2 x i4> %m, <i4 -1, i4 -1>
+  %n0 = xor <2 x i4> %x, %y
+  %n1 = and <2 x i4> %n0, %im
+  %r  = xor <2 x i4> %n1, %x ; %x instead of %y
+  ret <2 x i4> %r
+}
+
+define <2 x i4> @c_0_0_1 (<2 x i4> %m) {
+; CHECK-LABEL: @c_0_0_1(
+; CHECK-NEXT:    [[X:%.*]] = call <2 x i4> @gen4()
+; CHECK-NEXT:    [[Y:%.*]] = call <2 x i4> @gen4()
+; CHECK-NEXT:    [[N0:%.*]] = xor <2 x i4> [[X]], [[Y]]
+; CHECK-NEXT:    [[TMP1:%.*]] = and <2 x i4> [[N0]], [[M:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = xor <2 x i4> [[TMP1]], [[X]]
+; CHECK-NEXT:    ret <2 x i4> [[R]]
+;
+  %im = xor <2 x i4> %m, <i4 -1, i4 -1>
+  %x  = call <2 x i4> @gen4()
+  %y  = call <2 x i4> @gen4()
+  %n0 = xor <2 x i4> %x, %y
+  %n1 = and <2 x i4> %n0, %im
+  %r  = xor <2 x i4> %y, %n1 ; swapped order
+  ret <2 x i4> %r
+}
+
+define <2 x i4> @c_1_1_0 (<2 x i4> %x, <2 x i4> %y, <2 x i4> %m) {
+; CHECK-LABEL: @c_1_1_0(
+; CHECK-NEXT:    [[N0:%.*]] = xor <2 x i4> [[Y:%.*]], [[X:%.*]]
+; CHECK-NEXT:    [[TMP1:%.*]] = and <2 x i4> [[N0]], [[M:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = xor <2 x i4> [[TMP1]], [[Y]]
+; CHECK-NEXT:    ret <2 x i4> [[R]]
+;
+  %im = xor <2 x i4> %m, <i4 -1, i4 -1>
+  %n0 = xor <2 x i4> %y, %x ; swapped order
+  %n1 = and <2 x i4> %n0, %im
+  %r  = xor <2 x i4> %n1, %x ; %x instead of %y
+  ret <2 x i4> %r
+}
+
+define <2 x i4> @c_1_0_1 (<2 x i4> %x, <2 x i4> %m) {
+; CHECK-LABEL: @c_1_0_1(
+; CHECK-NEXT:    [[Y:%.*]] = call <2 x i4> @gen4()
+; CHECK-NEXT:    [[N0:%.*]] = xor <2 x i4> [[Y]], [[X:%.*]]
+; CHECK-NEXT:    [[TMP1:%.*]] = and <2 x i4> [[N0]], [[M:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = xor <2 x i4> [[TMP1]], [[X]]
+; CHECK-NEXT:    ret <2 x i4> [[R]]
+;
+  %im = xor <2 x i4> %m, <i4 -1, i4 -1>
+  %y  = call <2 x i4> @gen4()
+  %n0 = xor <2 x i4> %y, %x ; swapped order
+  %n1 = and <2 x i4> %n0, %im
+  %r  = xor <2 x i4> %y, %n1 ; swapped order
+  ret <2 x i4> %r
+}
+
+define <2 x i4> @c_0_1_1 (<2 x i4> %y, <2 x i4> %m) {
+; CHECK-LABEL: @c_0_1_1(
+; CHECK-NEXT:    [[X:%.*]] = call <2 x i4> @gen4()
+; CHECK-NEXT:    [[N0:%.*]] = xor <2 x i4> [[X]], [[Y:%.*]]
+; CHECK-NEXT:    [[TMP1:%.*]] = and <2 x i4> [[N0]], [[M:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = xor <2 x i4> [[TMP1]], [[Y]]
+; CHECK-NEXT:    ret <2 x i4> [[R]]
+;
+  %im = xor <2 x i4> %m, <i4 -1, i4 -1>
+  %x  = call <2 x i4> @gen4()
+  %n0 = xor <2 x i4> %x, %y
+  %n1 = and <2 x i4> %n0, %im
+  %r  = xor <2 x i4> %x, %n1 ; swapped order, %x instead of %y
+  ret <2 x i4> %r
+}
+
+define <2 x i4> @c_1_1_1 (<2 x i4> %m) {
+; CHECK-LABEL: @c_1_1_1(
+; CHECK-NEXT:    [[X:%.*]] = call <2 x i4> @gen4()
+; CHECK-NEXT:    [[Y:%.*]] = call <2 x i4> @gen4()
+; CHECK-NEXT:    [[N0:%.*]] = xor <2 x i4> [[Y]], [[X]]
+; CHECK-NEXT:    [[TMP1:%.*]] = and <2 x i4> [[N0]], [[M:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = xor <2 x i4> [[TMP1]], [[Y]]
+; CHECK-NEXT:    ret <2 x i4> [[R]]
+;
+  %im = xor <2 x i4> %m, <i4 -1, i4 -1>
+  %x  = call <2 x i4> @gen4()
+  %y  = call <2 x i4> @gen4()
+  %n0 = xor <2 x i4> %y, %x ; swapped order
+  %n1 = and <2 x i4> %n0, %im
+  %r  = xor <2 x i4> %x, %n1 ; swapped order, %x instead of %y
+  ret <2 x i4> %r
+}
+
+define <2 x i4> @commutativity_constant_varx_6_invmask(<2 x i4> %x, <2 x i4> %mask) {
+; CHECK-LABEL: @commutativity_constant_varx_6_invmask(
+; CHECK-NEXT:    [[N0:%.*]] = xor <2 x i4> [[X:%.*]], <i4 6, i4 6>
+; CHECK-NEXT:    [[TMP1:%.*]] = and <2 x i4> [[N0]], [[MASK:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = xor <2 x i4> [[TMP1]], [[X]]
+; CHECK-NEXT:    ret <2 x i4> [[R]]
+;
+  %notmask = xor <2 x i4> %mask, <i4 -1, i4 -1>
+  %n0 = xor <2 x i4> %x, <i4 6, i4 6> ; %x
+  %n1 = and <2 x i4> %notmask, %n0 ; swapped
+  %r = xor <2 x i4> %n1, <i4 6, i4 6>
+  ret <2 x i4> %r
+}
+
+define <2 x i4> @commutativity_constant_6_vary_invmask(<2 x i4> %y, <2 x i4> %mask) {
+; CHECK-LABEL: @commutativity_constant_6_vary_invmask(
+; CHECK-NEXT:    [[N0:%.*]] = xor <2 x i4> [[Y:%.*]], <i4 6, i4 6>
+; CHECK-NEXT:    [[TMP1:%.*]] = and <2 x i4> [[N0]], [[MASK:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = xor <2 x i4> [[TMP1]], <i4 6, i4 6>
+; CHECK-NEXT:    ret <2 x i4> [[R]]
+;
+  %notmask = xor <2 x i4> %mask, <i4 -1, i4 -1>
+  %n0 = xor <2 x i4> %y, <i4 6, i4 6> ; %x
+  %n1 = and <2 x i4> %notmask, %n0 ; swapped
+  %r = xor <2 x i4> %n1, %y
+  ret <2 x i4> %r
+}
+
+; ============================================================================ ;
+; Negative tests. Should not be folded.
+; ============================================================================ ;
+
+; One use only.
+
+declare void @use4(<2 x i4>)
+
+define <2 x i4> @n_oneuse_D_is_ok (<2 x i4> %x, <2 x i4> %y, <2 x i4> %m) {
+; CHECK-LABEL: @n_oneuse_D_is_ok(
+; CHECK-NEXT:    [[N0:%.*]] = xor <2 x i4> [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    [[TMP1:%.*]] = and <2 x i4> [[N0]], [[M:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = xor <2 x i4> [[TMP1]], [[X]]
+; CHECK-NEXT:    call void @use4(<2 x i4> [[N0]])
+; CHECK-NEXT:    ret <2 x i4> [[R]]
+;
+  %im = xor <2 x i4> %m, <i4 -1, i4 -1>
+  %n0 = xor <2 x i4> %x, %y ; two uses of %n0, THIS IS OK!
+  %n1 = and <2 x i4> %n0, %im
+  %r  = xor <2 x i4> %n1, %y
+  call void @use4(<2 x i4> %n0)
+  ret <2 x i4> %r
+}
+
+define <2 x i4> @n_oneuse_A (<2 x i4> %x, <2 x i4> %y, <2 x i4> %m) {
+; CHECK-LABEL: @n_oneuse_A(
+; CHECK-NEXT:    [[IM:%.*]] = xor <2 x i4> [[M:%.*]], <i4 -1, i4 -1>
+; CHECK-NEXT:    [[N0:%.*]] = xor <2 x i4> [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    [[N1:%.*]] = and <2 x i4> [[N0]], [[IM]]
+; CHECK-NEXT:    [[R:%.*]] = xor <2 x i4> [[N1]], [[Y]]
+; CHECK-NEXT:    call void @use4(<2 x i4> [[N1]])
+; CHECK-NEXT:    ret <2 x i4> [[R]]
+;
+  %im = xor <2 x i4> %m, <i4 -1, i4 -1>
+  %n0 = xor <2 x i4> %x, %y
+  %n1 = and <2 x i4> %n0, %im ; two uses of %n1, which is going to be replaced
+  %r  = xor <2 x i4> %n1, %y
+  call void @use4(<2 x i4> %n1)
+  ret <2 x i4> %r
+}
+
+define <2 x i4> @n_oneuse_AD (<2 x i4> %x, <2 x i4> %y, <2 x i4> %m) {
+; CHECK-LABEL: @n_oneuse_AD(
+; CHECK-NEXT:    [[IM:%.*]] = xor <2 x i4> [[M:%.*]], <i4 -1, i4 -1>
+; CHECK-NEXT:    [[N0:%.*]] = xor <2 x i4> [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    [[N1:%.*]] = and <2 x i4> [[N0]], [[IM]]
+; CHECK-NEXT:    [[R:%.*]] = xor <2 x i4> [[N1]], [[Y]]
+; CHECK-NEXT:    call void @use4(<2 x i4> [[N0]])
+; CHECK-NEXT:    call void @use4(<2 x i4> [[N1]])
+; CHECK-NEXT:    ret <2 x i4> [[R]]
+;
+  %im = xor <2 x i4> %m, <i4 -1, i4 -1>
+  %n0 = xor <2 x i4> %x, %y ; two uses of %n0 IS OK
+  %n1 = and <2 x i4> %n0, %im ; two uses of %n1, which is going to be replaced
+  %r  = xor <2 x i4> %n1, %y
+  call void @use4(<2 x i4> %n0)
+  call void @use4(<2 x i4> %n1)
+  ret <2 x i4> %r
+}
+
+; Some third variable is used
+
+define <2 x i4> @n_third_var (<2 x i4> %x, <2 x i4> %y, <2 x i4> %z, <2 x i4> %m) {
+; CHECK-LABEL: @n_third_var(
+; CHECK-NEXT:    [[IM:%.*]] = xor <2 x i4> [[M:%.*]], <i4 -1, i4 -1>
+; CHECK-NEXT:    [[N0:%.*]] = xor <2 x i4> [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    [[N1:%.*]] = and <2 x i4> [[N0]], [[IM]]
+; CHECK-NEXT:    [[R:%.*]] = xor <2 x i4> [[N1]], [[Z:%.*]]
+; CHECK-NEXT:    ret <2 x i4> [[R]]
+;
+  %im = xor <2 x i4> %m, <i4 -1, i4 -1>
+  %n0 = xor <2 x i4> %x, %y
+  %n1 = and <2 x i4> %n0, %im
+  %r  = xor <2 x i4> %n1, %z ; not %x or %y
+  ret <2 x i4> %r
+}
+
+
+define <2 x i4> @n_third_var_const(<2 x i4> %x, <2 x i4> %y, <2 x i4> %mask) {
+; CHECK-LABEL: @n_third_var_const(
+; CHECK-NEXT:    [[NOTMASK:%.*]] = xor <2 x i4> [[MASK:%.*]], <i4 -1, i4 -1>
+; CHECK-NEXT:    [[N0:%.*]] = xor <2 x i4> [[X:%.*]], <i4 6, i4 7>
+; CHECK-NEXT:    [[N1:%.*]] = and <2 x i4> [[N0]], [[NOTMASK]]
+; CHECK-NEXT:    [[R:%.*]] = xor <2 x i4> [[N1]], <i4 7, i4 6>
+; CHECK-NEXT:    ret <2 x i4> [[R]]
+;
+  %notmask = xor <2 x i4> %mask, <i4 -1, i4 -1>
+  %n0 = xor <2 x i4> %x, <i4 6, i4 7> ; %x
+  %n1 = and <2 x i4> %n0, %notmask
+  %r = xor <2 x i4> %n1, <i4 7, i4 6>
+  ret <2 x i4> %r
+}
+
+; Bad xor
+
+define <2 x i4> @n_badxor_splat (<2 x i4> %x, <2 x i4> %y, <2 x i4> %m) {
+; CHECK-LABEL: @n_badxor_splat(
+; CHECK-NEXT:    [[IM:%.*]] = xor <2 x i4> [[M:%.*]], <i4 1, i4 1>
+; CHECK-NEXT:    [[N0:%.*]] = xor <2 x i4> [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    [[N1:%.*]] = and <2 x i4> [[N0]], [[IM]]
+; CHECK-NEXT:    [[R:%.*]] = xor <2 x i4> [[N1]], [[Y]]
+; CHECK-NEXT:    ret <2 x i4> [[R]]
+;
+  %im = xor <2 x i4> %m, <i4 1, i4 1> ; not -1
+  %n0 = xor <2 x i4> %x, %y
+  %n1 = and <2 x i4> %n0, %im ; two uses of %n1, which is going to be replaced
+  %r  = xor <2 x i4> %n1, %y
+  ret <2 x i4> %r
+}
+
+define <2 x i4> @n_badxor (<2 x i4> %x, <2 x i4> %y, <2 x i4> %m) {
+; CHECK-LABEL: @n_badxor(
+; CHECK-NEXT:    [[IM:%.*]] = xor <2 x i4> [[M:%.*]], <i4 -1, i4 1>
+; CHECK-NEXT:    [[N0:%.*]] = xor <2 x i4> [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    [[N1:%.*]] = and <2 x i4> [[N0]], [[IM]]
+; CHECK-NEXT:    [[R:%.*]] = xor <2 x i4> [[N1]], [[Y]]
+; CHECK-NEXT:    ret <2 x i4> [[R]]
+;
+  %im = xor <2 x i4> %m, <i4 -1, i4 1> ; not -1
+  %n0 = xor <2 x i4> %x, %y
+  %n1 = and <2 x i4> %n0, %im ; two uses of %n1, which is going to be replaced
+  %r  = xor <2 x i4> %n1, %y
+  ret <2 x i4> %r
+}

Added: llvm/trunk/test/Transforms/InstCombine/invoke.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/invoke.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/invoke.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/invoke.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,86 @@
+; RUN: opt < %s -instcombine -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"
+
+declare i32 @__gxx_personality_v0(...)
+declare void @__cxa_call_unexpected(i8*)
+declare i64 @llvm.objectsize.i64(i8*, i1) nounwind readonly
+declare i8* @_Znwm(i64)
+
+
+; CHECK-LABEL: @f1(
+define i64 @f1() nounwind uwtable ssp personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) {
+entry:
+; CHECK: nvoke noalias i8* undef()
+  %call = invoke noalias i8* undef()
+          to label %invoke.cont unwind label %lpad
+
+invoke.cont:
+; CHECK: ret i64 0
+  %0 = tail call i64 @llvm.objectsize.i64(i8* %call, i1 false)
+  ret i64 %0
+
+lpad:
+  %1 = landingpad { i8*, i32 }
+          filter [0 x i8*] zeroinitializer
+  %2 = extractvalue { i8*, i32 } %1, 0
+  tail call void @__cxa_call_unexpected(i8* %2) noreturn nounwind
+  unreachable
+}
+
+; CHECK-LABEL: @f2(
+define i64 @f2() nounwind uwtable ssp personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) {
+entry:
+; CHECK: nvoke noalias i8* null()
+  %call = invoke noalias i8* null()
+          to label %invoke.cont unwind label %lpad
+
+invoke.cont:
+; CHECK: ret i64 0
+  %0 = tail call i64 @llvm.objectsize.i64(i8* %call, i1 false)
+  ret i64 %0
+
+lpad:
+  %1 = landingpad { i8*, i32 }
+          filter [0 x i8*] zeroinitializer
+  %2 = extractvalue { i8*, i32 } %1, 0
+  tail call void @__cxa_call_unexpected(i8* %2) noreturn nounwind
+  unreachable
+}
+
+; CHECK-LABEL: @f2_no_null_opt(
+define i64 @f2_no_null_opt() nounwind uwtable ssp #0 personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) {
+entry:
+; CHECK: invoke noalias i8* null()
+  %call = invoke noalias i8* null()
+          to label %invoke.cont unwind label %lpad
+
+invoke.cont:
+; CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %call, i1 false, i1 false, i1 false)
+  %0 = tail call i64 @llvm.objectsize.i64(i8* %call, i1 false)
+  ret i64 %0
+
+lpad:
+  %1 = landingpad { i8*, i32 }
+          filter [0 x i8*] zeroinitializer
+  %2 = extractvalue { i8*, i32 } %1, 0
+  tail call void @__cxa_call_unexpected(i8* %2) noreturn nounwind
+  unreachable
+}
+attributes #0 = { "null-pointer-is-valid"="true" }
+
+; CHECK-LABEL: @f3(
+define void @f3() nounwind uwtable ssp personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) {
+; CHECK: invoke void @llvm.donothing()
+  %call = invoke noalias i8* @_Znwm(i64 13)
+          to label %invoke.cont unwind label %lpad
+
+invoke.cont:
+  ret void
+
+lpad:
+  %1 = landingpad { i8*, i32 }
+          filter [0 x i8*] zeroinitializer
+  %2 = extractvalue { i8*, i32 } %1, 0
+  tail call void @__cxa_call_unexpected(i8* %2) noreturn nounwind
+  unreachable
+}

Added: llvm/trunk/test/Transforms/InstCombine/isascii-1.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/isascii-1.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/isascii-1.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/isascii-1.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,32 @@
+; Test that the isascii library call simplifier works correctly.
+;
+; RUN: opt < %s -instcombine -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:128:128"
+
+declare i32 @isascii(i32)
+
+; Check isascii(c) -> c <u 128.
+
+define i32 @test_simplify1() {
+; CHECK-LABEL: @test_simplify1(
+  %ret = call i32 @isascii(i32 127)
+  ret i32 %ret
+; CHECK-NEXT: ret i32 1
+}
+
+define i32 @test_simplify2() {
+; CHECK-LABEL: @test_simplify2(
+  %ret = call i32 @isascii(i32 128)
+  ret i32 %ret
+; CHECK-NEXT: ret i32 0
+}
+
+define i32 @test_simplify3(i32 %x) {
+; CHECK-LABEL: @test_simplify3(
+  %ret = call i32 @isascii(i32 %x)
+; CHECK-NEXT: [[CMP:%[a-z0-9]+]] = icmp ult i32 %x, 128
+; CHECK-NEXT: [[ZEXT:%[a-z0-9]+]] = zext i1 [[CMP]] to i32
+  ret i32 %ret
+; CHECK-NEXT: ret i32 [[ZEXT]]
+}

Added: llvm/trunk/test/Transforms/InstCombine/isdigit-1.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/isdigit-1.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/isdigit-1.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/isdigit-1.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,48 @@
+; Test that the isdigit library call simplifier works correctly.
+;
+; RUN: opt < %s -instcombine -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:128:128"
+
+declare i32 @isdigit(i32)
+
+; Check isdigit(c) -> (c - '0') <u 10;
+
+define i32 @test_simplify1() {
+; CHECK-LABEL: @test_simplify1(
+  %ret = call i32 @isdigit(i32 47)
+  ret i32 %ret
+; CHECK-NEXT: ret i32 0
+}
+
+define i32 @test_simplify2() {
+; CHECK-LABEL: @test_simplify2(
+  %ret = call i32 @isdigit(i32 48)
+  ret i32 %ret
+; CHECK-NEXT: ret i32 1
+}
+
+define i32 @test_simplify3() {
+; CHECK-LABEL: @test_simplify3(
+  %ret = call i32 @isdigit(i32 57)
+  ret i32 %ret
+; CHECK-NEXT: ret i32 1
+}
+
+define i32 @test_simplify4() {
+; CHECK-LABEL: @test_simplify4(
+  %ret = call i32 @isdigit(i32 58)
+  ret i32 %ret
+; CHECK-NEXT: ret i32 0
+}
+
+define i32 @test_simplify5(i32 %x) {
+; CHECK-LABEL: @test_simplify5(
+
+  %ret = call i32 @isdigit(i32 %x)
+; CHECK-NEXT: [[ADD:%[a-z0-9]+]] = add i32 %x, -48
+; CHECK-NEXT: [[CMP:%[a-z0-9]+]] = icmp ult i32 [[ADD]], 10
+; CHECK-NEXT: [[ZEXT:%[a-z0-9]+]] = zext i1 [[CMP]] to i32
+  ret i32 %ret
+; CHECK-NEXT: ret i32 [[ZEXT]]
+}

Added: llvm/trunk/test/Transforms/InstCombine/known-never-nan.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/known-never-nan.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/known-never-nan.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/known-never-nan.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,196 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt < %s -S -instcombine | FileCheck %s
+
+; This file used to contain more tests that folded to true/false,
+; but those are all tested identically in InstSimplify now.
+; If any remaining tests are made to return true/false, that
+; functionality/testing may be better housed in InstSimplify
+; rather than InstCombine.
+
+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 ord double [[OP]], 0.000000e+00
+; CHECK-NEXT:    ret i1 [[TMP]]
+;
+  %fabs = call double @llvm.fabs.f64(double %arg0)
+  %op = call double @llvm.sqrt.f64(double %fabs)
+  %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 ord double [[OP]], 0.000000e+00
+; CHECK-NEXT:    ret i1 [[TMP]]
+;
+  %rhs = fadd nnan double %arg1, 1.0
+  %op = select i1 %cond, double %lhs, double %rhs
+  %tmp = fcmp ord 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]], 0.000000e+00
+; 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 ord double [[OP]], 0.000000e+00
+; 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 ord 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 [[NNAN_ARG1]], [[ARG0:%.*]]
+; CHECK-NEXT:    [[TMP:%.*]] = fcmp ord double [[OP]], 0.000000e+00
+; 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 ord double [[OP]], 0.000000e+00
+; CHECK-NEXT:    ret i1 [[TMP]]
+;
+  %nnan.arg0 = fadd nnan double %arg0, 1.0
+  %op = fadd double %nnan.arg0, %arg1
+  %tmp = fcmp ord 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]], 0.000000e+00
+; 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 ord double [[OP]], 0.000000e+00
+; 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 ord double %op, %op
+  ret i1 %tmp
+}
+
+declare double @func()
+
+define i1 @nnan_fneg() {
+; CHECK-LABEL: @nnan_fneg(
+; CHECK-NEXT:    [[NNAN:%.*]] = call nnan double @func()
+; CHECK-NEXT:    ret i1 true
+;
+  %nnan = call nnan double @func()
+  %op = fsub double -0.0, %nnan
+  %tmp = fcmp ord double %op, %op
+  ret i1 %tmp
+}
+
+define i1 @fpext_maybe_nan(float %arg0) {
+; CHECK-LABEL: @fpext_maybe_nan(
+; CHECK-NEXT:    [[TMP:%.*]] = fcmp ord float [[ARG0:%.*]], 0.000000e+00
+; CHECK-NEXT:    ret i1 [[TMP]]
+;
+  %op = fpext float %arg0 to double
+  %tmp = fcmp ord double %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]], 0.000000e+00
+; 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 ord double [[OP]], 0.000000e+00
+; 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 ord 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]], 0.000000e+00
+; 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)
+

Added: llvm/trunk/test/Transforms/InstCombine/known_align.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/known_align.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/known_align.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/known_align.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,27 @@
+; RUN: opt < %s -instcombine -S | grep "align 1"
+; END.
+
+	%struct.p = type <{ i8, i32 }>
+ at t = global %struct.p <{ i8 1, i32 10 }>		; <%struct.p*> [#uses=1]
+ at u = weak global %struct.p zeroinitializer		; <%struct.p*> [#uses=1]
+
+define i32 @main() {
+entry:
+	%retval = alloca i32, align 4		; <i32*> [#uses=2]
+	%tmp = alloca i32, align 4		; <i32*> [#uses=2]
+	%tmp1 = alloca i32, align 4		; <i32*> [#uses=3]
+	%"alloca point" = bitcast i32 0 to i32		; <i32> [#uses=0]
+	%tmp3 = load i32, i32* getelementptr (%struct.p, %struct.p* @t, i32 0, i32 1), align 1		; <i32> [#uses=1]
+	store i32 %tmp3, i32* %tmp1, align 4
+	%tmp5 = load i32, i32* %tmp1, align 4		; <i32> [#uses=1]
+	store i32 %tmp5, i32* getelementptr (%struct.p, %struct.p* @u, i32 0, i32 1), align 1
+	%tmp6 = load i32, i32* %tmp1, align 4		; <i32> [#uses=1]
+	store i32 %tmp6, i32* %tmp, align 4
+	%tmp7 = load i32, i32* %tmp, align 4		; <i32> [#uses=1]
+	store i32 %tmp7, i32* %retval, align 4
+	br label %return
+
+return:		; preds = %entry
+	%retval8 = load i32, i32* %retval		; <i32> [#uses=1]
+	ret i32 %retval8
+}

Added: llvm/trunk/test/Transforms/InstCombine/lifetime-asan.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/lifetime-asan.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/lifetime-asan.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/lifetime-asan.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,49 @@
+; RUN: opt < %s -instcombine -S | FileCheck %s
+
+declare void @llvm.lifetime.start.p0i8(i64, i8* nocapture)
+declare void @llvm.lifetime.end.p0i8(i64, i8* nocapture)
+declare void @foo(i8* nocapture)
+
+define void @asan() sanitize_address {
+entry:
+  ; CHECK-LABEL: @asan(
+  %text = alloca i8, align 1
+
+  call void @llvm.lifetime.start.p0i8(i64 1, i8* %text)
+  call void @llvm.lifetime.end.p0i8(i64 1, i8* %text)
+  ; CHECK: call void @llvm.lifetime.start
+  ; CHECK-NEXT: call void @llvm.lifetime.end
+
+  call void @foo(i8* %text) ; Keep alloca alive
+
+  ret void
+}
+
+define void @hwasan() sanitize_hwaddress {
+entry:
+  ; CHECK-LABEL: @hwasan(
+  %text = alloca i8, align 1
+
+  call void @llvm.lifetime.start.p0i8(i64 1, i8* %text)
+  call void @llvm.lifetime.end.p0i8(i64 1, i8* %text)
+  ; CHECK: call void @llvm.lifetime.start
+  ; CHECK-NEXT: call void @llvm.lifetime.end
+
+  call void @foo(i8* %text) ; Keep alloca alive
+
+  ret void
+}
+
+define void @no_asan() {
+entry:
+  ; CHECK-LABEL: @no_asan(
+  %text = alloca i8, align 1
+
+  call void @llvm.lifetime.start.p0i8(i64 1, i8* %text)
+  call void @llvm.lifetime.end.p0i8(i64 1, i8* %text)
+  ; CHECK-NO: call void @llvm.lifetime
+
+  call void @foo(i8* %text) ; Keep alloca alive
+
+  ret void
+}

Added: llvm/trunk/test/Transforms/InstCombine/lifetime-no-null-opt.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/lifetime-no-null-opt.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/lifetime-no-null-opt.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/lifetime-no-null-opt.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,94 @@
+; RUN: opt < %s -instcombine -S | FileCheck %s
+
+declare void @llvm.dbg.declare(metadata, metadata, metadata)
+declare void @llvm.lifetime.start.p0i8(i64, i8* nocapture)
+declare void @llvm.lifetime.end.p0i8(i64, i8* nocapture)
+declare void @foo(i8* nocapture, i8* nocapture)
+
+define void @bar(i1 %flag) #0 !dbg !4 {
+entry:
+; CHECK-LABEL: @bar(
+; CHECK: %[[T:[^ ]+]] = getelementptr inbounds [1 x i8], [1 x i8]* %text
+; CHECK: %[[B:[^ ]+]] = getelementptr inbounds [1 x i8], [1 x i8]* %buff
+; CHECK: if:
+; CHECK-NEXT: br label %bb2
+; CHECK: bb2:
+; CHECK-NEXT: br label %bb3
+; CHECK: bb3:
+; CHECK-NEXT: call void @llvm.dbg.declare
+; CHECK-NEXT: br label %fin
+; CHECK: call void @llvm.lifetime.start.p0i8(i64 1, i8* %[[T]])
+; CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* %[[B]])
+; CHECK-NEXT: call void @foo(i8* %[[B]], i8* %[[T]])
+; CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* %[[B]])
+; CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* %[[T]])
+  %text = alloca [1 x i8], align 1
+  %buff = alloca [1 x i8], align 1
+  %0 = getelementptr inbounds [1 x i8], [1 x i8]* %text, i64 0, i64 0
+  %1 = getelementptr inbounds [1 x i8], [1 x i8]* %buff, i64 0, i64 0
+  br i1 %flag, label %if, label %else
+
+if:
+  call void @llvm.lifetime.start.p0i8(i64 1, i8* %0)
+  call void @llvm.lifetime.start.p0i8(i64 1, i8* %1)
+  call void @llvm.lifetime.end.p0i8(i64 1, i8* %1)
+  call void @llvm.lifetime.end.p0i8(i64 1, i8* %0)
+  br label %bb2
+
+bb2:
+  call void @llvm.lifetime.start.p0i8(i64 1, i8* %0)
+  call void @llvm.lifetime.start.p0i8(i64 1, i8* %1)
+  call void @llvm.lifetime.end.p0i8(i64 1, i8* %0)
+  call void @llvm.lifetime.end.p0i8(i64 1, i8* %1)
+  br label %bb3
+
+bb3:
+  call void @llvm.lifetime.start.p0i8(i64 1, i8* %0)
+  call void @llvm.dbg.declare(metadata [1 x i8]* %text, metadata !14, metadata !25), !dbg !26
+  call void @llvm.lifetime.end.p0i8(i64 1, i8* %0)
+  br label %fin
+
+else:
+  call void @llvm.lifetime.start.p0i8(i64 1, i8* %0)
+  call void @llvm.lifetime.start.p0i8(i64 1, i8* %1)
+  call void @foo(i8* %1, i8* %0)
+  call void @llvm.lifetime.end.p0i8(i64 1, i8* %1)
+  call void @llvm.lifetime.end.p0i8(i64 1, i8* %0)
+  br  label %fin
+
+fin:
+  ret void
+}
+
+attributes #0 = { "null-pointer-is-valid"="true" }
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!22, !23}
+!llvm.ident = !{!24}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !1, producer: "clang version 3.8.0 (trunk 248826) (llvm/trunk 248827)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2)
+!1 = !DIFile(filename: "test.cpp", directory: "/home/user")
+!2 = !{}
+!4 = distinct !DISubprogram(name: "bar", linkageName: "bar", scope: !1, file: !1, line: 2, type: !5, isLocal: false, isDefinition: true, scopeLine: 2, flags: DIFlagPrototyped, isOptimized: true, unit: !0, retainedNodes: !8)
+!5 = !DISubroutineType(types: !6)
+!6 = !{null, !7}
+!7 = !DIBasicType(name: "bool", size: 8, align: 8, encoding: DW_ATE_boolean)
+!8 = !{!9, !11, !12, !14, !21}
+!9 = !DILocalVariable(name: "Size", arg: 1, scope: !4, file: !1, line: 2, type: !10)
+!10 = !DIBasicType(name: "int", size: 32, align: 32, encoding: DW_ATE_signed)
+!11 = !DILocalVariable(name: "flag", arg: 2, scope: !4, file: !1, line: 2, type: !7)
+!12 = !DILocalVariable(name: "i", scope: !13, file: !1, line: 3, type: !10)
+!13 = distinct !DILexicalBlock(scope: !4, file: !1, line: 3, column: 3)
+!14 = !DILocalVariable(name: "text", scope: !15, file: !1, line: 4, type: !17)
+!15 = distinct !DILexicalBlock(scope: !16, file: !1, line: 3, column: 30)
+!16 = distinct !DILexicalBlock(scope: !13, file: !1, line: 3, column: 3)
+!17 = !DICompositeType(tag: DW_TAG_array_type, baseType: !18, size: 8, align: 8, elements: !19)
+!18 = !DIBasicType(name: "char", size: 8, align: 8, encoding: DW_ATE_signed_char)
+!19 = !{!20}
+!20 = !DISubrange(count: 1)
+!21 = !DILocalVariable(name: "buff", scope: !15, file: !1, line: 5, type: !17)
+!22 = !{i32 2, !"Dwarf Version", i32 4}
+!23 = !{i32 2, !"Debug Info Version", i32 3}
+!24 = !{!"clang version 3.8.0 (trunk 248826) (llvm/trunk 248827)"}
+!25 = !DIExpression()
+!26 = !DILocation(line: 4, column: 10, scope: !15)

Added: llvm/trunk/test/Transforms/InstCombine/lifetime.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/lifetime.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/lifetime.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/lifetime.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,92 @@
+; RUN: opt < %s -instcombine -S | FileCheck %s
+
+declare void @llvm.dbg.declare(metadata, metadata, metadata)
+declare void @llvm.lifetime.start.p0i8(i64, i8* nocapture)
+declare void @llvm.lifetime.end.p0i8(i64, i8* nocapture)
+declare void @foo(i8* nocapture, i8* nocapture)
+
+define void @bar(i1 %flag) !dbg !4 {
+entry:
+; CHECK-LABEL: @bar(
+; CHECK: %[[T:[^ ]+]] = getelementptr inbounds [1 x i8], [1 x i8]* %text
+; CHECK: %[[B:[^ ]+]] = getelementptr inbounds [1 x i8], [1 x i8]* %buff
+; CHECK: if:
+; CHECK-NEXT: br label %bb2
+; CHECK: bb2:
+; CHECK-NEXT: br label %bb3
+; CHECK: bb3:
+; CHECK-NEXT: call void @llvm.dbg.declare
+; CHECK-NEXT: br label %fin
+; CHECK: call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull %[[T]])
+; CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull %[[B]])
+; CHECK-NEXT: call void @foo(i8* nonnull %[[B]], i8* nonnull %[[T]])
+; CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull %[[B]])
+; CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull %[[T]])
+  %text = alloca [1 x i8], align 1
+  %buff = alloca [1 x i8], align 1
+  %0 = getelementptr inbounds [1 x i8], [1 x i8]* %text, i64 0, i64 0
+  %1 = getelementptr inbounds [1 x i8], [1 x i8]* %buff, i64 0, i64 0
+  br i1 %flag, label %if, label %else
+
+if:
+  call void @llvm.lifetime.start.p0i8(i64 1, i8* %0)
+  call void @llvm.lifetime.start.p0i8(i64 1, i8* %1)
+  call void @llvm.lifetime.end.p0i8(i64 1, i8* %1)
+  call void @llvm.lifetime.end.p0i8(i64 1, i8* %0)
+  br label %bb2
+
+bb2:
+  call void @llvm.lifetime.start.p0i8(i64 1, i8* %0)
+  call void @llvm.lifetime.start.p0i8(i64 1, i8* %1)
+  call void @llvm.lifetime.end.p0i8(i64 1, i8* %0)
+  call void @llvm.lifetime.end.p0i8(i64 1, i8* %1)
+  br label %bb3
+
+bb3:
+  call void @llvm.lifetime.start.p0i8(i64 1, i8* %0)
+  call void @llvm.dbg.declare(metadata [1 x i8]* %text, metadata !14, metadata !25), !dbg !26
+  call void @llvm.lifetime.end.p0i8(i64 1, i8* %0)
+  br label %fin
+
+else:
+  call void @llvm.lifetime.start.p0i8(i64 1, i8* %0)
+  call void @llvm.lifetime.start.p0i8(i64 1, i8* %1)
+  call void @foo(i8* %1, i8* %0)
+  call void @llvm.lifetime.end.p0i8(i64 1, i8* %1)
+  call void @llvm.lifetime.end.p0i8(i64 1, i8* %0)
+  br  label %fin
+
+fin:
+  ret void
+}
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!22, !23}
+!llvm.ident = !{!24}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !1, producer: "clang version 3.8.0 (trunk 248826) (llvm/trunk 248827)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2)
+!1 = !DIFile(filename: "test.cpp", directory: "/home/user")
+!2 = !{}
+!4 = distinct !DISubprogram(name: "bar", linkageName: "bar", scope: !1, file: !1, line: 2, type: !5, isLocal: false, isDefinition: true, scopeLine: 2, flags: DIFlagPrototyped, isOptimized: true, unit: !0, retainedNodes: !8)
+!5 = !DISubroutineType(types: !6)
+!6 = !{null, !7}
+!7 = !DIBasicType(name: "bool", size: 8, align: 8, encoding: DW_ATE_boolean)
+!8 = !{!9, !11, !12, !14, !21}
+!9 = !DILocalVariable(name: "Size", arg: 1, scope: !4, file: !1, line: 2, type: !10)
+!10 = !DIBasicType(name: "int", size: 32, align: 32, encoding: DW_ATE_signed)
+!11 = !DILocalVariable(name: "flag", arg: 2, scope: !4, file: !1, line: 2, type: !7)
+!12 = !DILocalVariable(name: "i", scope: !13, file: !1, line: 3, type: !10)
+!13 = distinct !DILexicalBlock(scope: !4, file: !1, line: 3, column: 3)
+!14 = !DILocalVariable(name: "text", scope: !15, file: !1, line: 4, type: !17)
+!15 = distinct !DILexicalBlock(scope: !16, file: !1, line: 3, column: 30)
+!16 = distinct !DILexicalBlock(scope: !13, file: !1, line: 3, column: 3)
+!17 = !DICompositeType(tag: DW_TAG_array_type, baseType: !18, size: 8, align: 8, elements: !19)
+!18 = !DIBasicType(name: "char", size: 8, align: 8, encoding: DW_ATE_signed_char)
+!19 = !{!20}
+!20 = !DISubrange(count: 1)
+!21 = !DILocalVariable(name: "buff", scope: !15, file: !1, line: 5, type: !17)
+!22 = !{i32 2, !"Dwarf Version", i32 4}
+!23 = !{i32 2, !"Debug Info Version", i32 3}
+!24 = !{!"clang version 3.8.0 (trunk 248826) (llvm/trunk 248827)"}
+!25 = !DIExpression()
+!26 = !DILocation(line: 4, column: 10, scope: !15)

Added: llvm/trunk/test/Transforms/InstCombine/load-bitcast-select.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/load-bitcast-select.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/load-bitcast-select.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/load-bitcast-select.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,104 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt < %s -instcombine -S -data-layout="e-m:e-i64:64-f80:128-n8:16:32:64-S128" | FileCheck %s
+
+ at a = global [1000 x float] zeroinitializer, align 16
+ at b = global [1000 x float] zeroinitializer, align 16
+
+define void @_Z3foov() {
+; CHECK-LABEL: @_Z3foov(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    br label [[FOR_COND:%.*]]
+; CHECK:       for.cond:
+; CHECK-NEXT:    [[I_0:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[INC:%.*]], [[FOR_BODY:%.*]] ]
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i32 [[I_0]], 1000
+; CHECK-NEXT:    br i1 [[CMP]], label [[FOR_BODY]], label [[FOR_COND_CLEANUP:%.*]]
+; CHECK:       for.cond.cleanup:
+; CHECK-NEXT:    ret void
+; CHECK:       for.body:
+; CHECK-NEXT:    [[TMP0:%.*]] = zext i32 [[I_0]] to i64
+; CHECK-NEXT:    [[ARRAYIDX:%.*]] = getelementptr inbounds [1000 x float], [1000 x float]* @a, i64 0, i64 [[TMP0]]
+; CHECK-NEXT:    [[ARRAYIDX2:%.*]] = getelementptr inbounds [1000 x float], [1000 x float]* @b, i64 0, i64 [[TMP0]]
+; CHECK-NEXT:    [[TMP1:%.*]] = load float, float* [[ARRAYIDX]], align 4
+; CHECK-NEXT:    [[TMP2:%.*]] = load float, float* [[ARRAYIDX2]], align 4
+; CHECK-NEXT:    [[CMP_I:%.*]] = fcmp fast olt float [[TMP1]], [[TMP2]]
+; CHECK-NEXT:    [[TMP3:%.*]] = select i1 [[CMP_I]], float [[TMP2]], float [[TMP1]]
+; CHECK-NEXT:    store float [[TMP3]], float* [[ARRAYIDX]], align 4
+; CHECK-NEXT:    [[INC]] = add nuw nsw i32 [[I_0]], 1
+; CHECK-NEXT:    br label [[FOR_COND]]
+;
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.body, %entry
+  %i.0 = phi i32 [ 0, %entry ], [ %inc, %for.body ]
+  %cmp = icmp ult i32 %i.0, 1000
+  br i1 %cmp, label %for.body, label %for.cond.cleanup
+
+for.cond.cleanup:                                 ; preds = %for.cond
+  ret void
+
+for.body:                                         ; preds = %for.cond
+  %0 = zext i32 %i.0 to i64
+  %arrayidx = getelementptr inbounds [1000 x float], [1000 x float]* @a, i64 0, i64 %0
+  %arrayidx2 = getelementptr inbounds [1000 x float], [1000 x float]* @b, i64 0, i64 %0
+  %1 = load float, float* %arrayidx, align 4
+  %2 = load float, float* %arrayidx2, align 4
+  %cmp.i = fcmp fast olt float %1, %2
+  %__b.__a.i = select i1 %cmp.i, float* %arrayidx2, float* %arrayidx
+  %3 = bitcast float* %__b.__a.i to i32*
+  %4 = load i32, i32* %3, align 4
+  %5 = bitcast float* %arrayidx to i32*
+  store i32 %4, i32* %5, align 4
+  %inc = add nuw nsw i32 %i.0, 1
+  br label %for.cond
+}
+
+define i32 @store_bitcasted_load(i1 %cond, float* dereferenceable(4) %addr1, float* dereferenceable(4) %addr2) {
+; CHECK-LABEL: @store_bitcasted_load(
+; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[COND:%.*]], float* [[ADDR1:%.*]], float* [[ADDR2:%.*]]
+; CHECK-NEXT:    [[BC1:%.*]] = bitcast float* [[SEL]] to i32*
+; CHECK-NEXT:    [[LD:%.*]] = load i32, i32* [[BC1]], align 4
+; CHECK-NEXT:    ret i32 [[LD]]
+;
+  %sel = select i1 %cond, float* %addr1, float* %addr2
+  %bc1 = bitcast float* %sel to i32*
+  %ld = load i32, i32* %bc1
+  ret i32 %ld
+}
+
+define void @bitcasted_store(i1 %cond, float* %loadaddr1, float* %loadaddr2, float* %storeaddr) {
+; CHECK-LABEL: @bitcasted_store(
+; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[COND:%.*]], float* [[LOADADDR1:%.*]], float* [[LOADADDR2:%.*]]
+; CHECK-NEXT:    [[INT_LOAD_ADDR:%.*]] = bitcast float* [[SEL]] to i32*
+; CHECK-NEXT:    [[LD:%.*]] = load i32, i32* [[INT_LOAD_ADDR]], align 4
+; CHECK-NEXT:    [[INT_STORE_ADDR:%.*]] = bitcast float* [[STOREADDR:%.*]] to i32*
+; CHECK-NEXT:    store i32 [[LD]], i32* [[INT_STORE_ADDR]], align 4
+; CHECK-NEXT:    ret void
+;
+  %sel = select i1 %cond, float* %loadaddr1, float* %loadaddr2
+  %int_load_addr = bitcast float* %sel to i32*
+  %ld = load i32, i32* %int_load_addr
+  %int_store_addr = bitcast float* %storeaddr to i32*
+  store i32 %ld, i32* %int_store_addr
+  ret void
+}
+
+define void @bitcasted_minmax_with_select_of_pointers(float* %loadaddr1, float* %loadaddr2, float* %storeaddr) {
+; CHECK-LABEL: @bitcasted_minmax_with_select_of_pointers(
+; CHECK-NEXT:    [[LD1:%.*]] = load float, float* [[LOADADDR1:%.*]], align 4
+; CHECK-NEXT:    [[LD2:%.*]] = load float, float* [[LOADADDR2:%.*]], align 4
+; CHECK-NEXT:    [[COND:%.*]] = fcmp ogt float [[LD1]], [[LD2]]
+; CHECK-NEXT:    [[LD3:%.*]] = select i1 [[COND]], float [[LD1]], float [[LD2]]
+; CHECK-NEXT:    store float [[LD3]], float* [[STOREADDR:%.*]], align 4
+; CHECK-NEXT:    ret void
+;
+  %ld1 = load float, float* %loadaddr1, align 4
+  %ld2 = load float, float* %loadaddr2, align 4
+  %cond = fcmp ogt float %ld1, %ld2
+  %sel = select i1 %cond, float* %loadaddr1, float* %loadaddr2
+  %int_load_addr = bitcast float* %sel to i32*
+  %ld = load i32, i32* %int_load_addr, align 4
+  %int_store_addr = bitcast float* %storeaddr to i32*
+  store i32 %ld, i32* %int_store_addr, align 4
+  ret void
+}

Added: llvm/trunk/test/Transforms/InstCombine/load-bitcast32.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/load-bitcast32.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/load-bitcast32.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/load-bitcast32.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,79 @@
+; RUN: opt -instcombine -S < %s | FileCheck %s
+
+target datalayout = "p:32:32:32"
+
+
+define i64* @test1(i8* %x) {
+entry:
+; CHECK-LABEL: @test1(
+; CHECK: load i64, i64*
+; CHECK: ret
+  %a = bitcast i8* %x to i64*
+  %b = load i64, i64* %a
+  %c = inttoptr i64 %b to i64*
+
+  ret i64* %c
+}
+
+define i32* @test2(i8* %x) {
+entry:
+; CHECK-LABEL: @test2(
+; CHECK: load i32*, i32**
+; CHECK: ret
+  %a = bitcast i8* %x to i32*
+  %b = load i32, i32* %a
+  %c = inttoptr i32 %b to i32*
+
+  ret i32* %c
+}
+
+define i64* @test3(i8* %x) {
+entry:
+; CHECK-LABEL: @test3(
+; CHECK: load i64*, i64**
+; CHECK: ret
+  %a = bitcast i8* %x to i32*
+  %b = load i32, i32* %a
+  %c = inttoptr i32 %b to i64*
+
+  ret i64* %c
+}
+
+define i64 @test4(i8* %x) {
+entry:
+; CHECK-LABEL: @test4(
+; CHECK: load i32, i32*
+; CHECK: zext
+; CHECK: ret
+  %a = bitcast i8* %x to i64**
+  %b = load i64*, i64** %a
+  %c = ptrtoint i64* %b to i64
+
+  ret i64 %c
+}
+
+define i32 @test5(i8* %x) {
+entry:
+; CHECK-LABEL: @test5(
+; CHECK: load i32, i32*
+; CHECK: ret
+  %a = bitcast i8* %x to i32**
+  %b = load i32*, i32** %a
+  %c = ptrtoint i32* %b to i32
+
+  ret i32 %c
+}
+
+define i64 @test6(i8* %x) {
+entry:
+; CHECK-LABEL: @test6(
+; CHECK: load i32, i32*
+; CHECK: zext
+; CHECK: ret
+  %a = bitcast i8* %x to i32**
+  %b = load i32*, i32** %a
+  %c = ptrtoint i32* %b to i64
+
+  ret i64 %c
+}
+

Added: llvm/trunk/test/Transforms/InstCombine/load-bitcast64.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/load-bitcast64.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/load-bitcast64.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/load-bitcast64.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,78 @@
+; RUN: opt -instcombine -S < %s | FileCheck %s
+
+target datalayout = "p:64:64:64"
+
+
+define i64* @test1(i8* %x) {
+entry:
+; CHECK-LABEL: @test1(
+; CHECK: load i64*, i64**
+; CHECK: ret
+  %a = bitcast i8* %x to i64*
+  %b = load i64, i64* %a
+  %c = inttoptr i64 %b to i64*
+
+  ret i64* %c
+}
+
+define i32* @test2(i8* %x) {
+entry:
+; CHECK-LABEL: @test2(
+; CHECK: load i32, i32*
+; CHECK: ret
+  %a = bitcast i8* %x to i32*
+  %b = load i32, i32* %a
+  %c = inttoptr i32 %b to i32*
+
+  ret i32* %c
+}
+
+define i64* @test3(i8* %x) {
+entry:
+; CHECK-LABEL: @test3(
+; CHECK: load i32, i32*
+; CHECK: ret
+  %a = bitcast i8* %x to i32*
+  %b = load i32, i32* %a
+  %c = inttoptr i32 %b to i64*
+
+  ret i64* %c
+}
+
+define i64 @test4(i8* %x) {
+entry:
+; CHECK-LABEL: @test4(
+; CHECK: load i64, i64*
+; CHECK: ret
+  %a = bitcast i8* %x to i64**
+  %b = load i64*, i64** %a
+  %c = ptrtoint i64* %b to i64
+
+  ret i64 %c
+}
+
+define i32 @test5(i8* %x) {
+entry:
+; CHECK-LABEL: @test5(
+; CHECK: load i64, i64*
+; CHECK: trunc
+; CHECK: ret
+  %a = bitcast i8* %x to i32**
+  %b = load i32*, i32** %a
+  %c = ptrtoint i32* %b to i32
+
+  ret i32 %c
+}
+
+define i64 @test6(i8* %x) {
+entry:
+; CHECK-LABEL: @test6(
+; CHECK: load i64, i64*
+; CHECK: ret
+  %a = bitcast i8* %x to i32**
+  %b = load i32*, i32** %a
+  %c = ptrtoint i32* %b to i64
+
+  ret i64 %c
+}
+

Added: llvm/trunk/test/Transforms/InstCombine/load-cmp.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/load-cmp.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/load-cmp.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/load-cmp.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,316 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt -instcombine -S -data-layout="p:32:32:32-p1:16:16:16-n8:16:32:64" < %s | FileCheck %s
+
+ at G16 = internal constant [10 x i16] [i16 35, i16 82, i16 69, i16 81, i16 85,
+                                     i16 73, i16 82, i16 69, i16 68, i16 0]
+
+ at G16_as1 = internal addrspace(1) constant [10 x i16] [i16 35, i16 82, i16 69, i16 81, i16 85,
+                                                      i16 73, i16 82, i16 69, i16 68, i16 0]
+
+ at GD = internal constant [6 x double]
+   [double -10.0, double 1.0, double 4.0, double 2.0, double -20.0, double -40.0]
+
+%Foo = type { i32, i32, i32, i32 }
+
+ at GS = internal constant %Foo { i32 1, i32 4, i32 9, i32 14 }
+
+ at GStructArr = internal constant [4 x %Foo] [ %Foo { i32 1, i32 4, i32 9, i32 14 },
+                                             %Foo { i32 5, i32 4, i32 6, i32 11 },
+                                             %Foo { i32 6, i32 5, i32 9, i32 20 },
+                                             %Foo { i32 12, i32 3, i32 9, i32 8 } ]
+
+
+define i1 @test1(i32 %X) {
+; CHECK-LABEL: @test1(
+; CHECK-NEXT:    [[R:%.*]] = icmp eq i32 %X, 9
+; CHECK-NEXT:    ret i1 [[R]]
+;
+  %P = getelementptr inbounds [10 x i16], [10 x i16]* @G16, i32 0, i32 %X
+  %Q = load i16, i16* %P
+  %R = icmp eq i16 %Q, 0
+  ret i1 %R
+}
+
+define i1 @test1_noinbounds(i32 %X) {
+; CHECK-LABEL: @test1_noinbounds(
+; CHECK-NEXT:    [[R:%.*]] = icmp eq i32 %X, 9
+; CHECK-NEXT:    ret i1 [[R]]
+;
+  %P = getelementptr [10 x i16], [10 x i16]* @G16, i32 0, i32 %X
+  %Q = load i16, i16* %P
+  %R = icmp eq i16 %Q, 0
+  ret i1 %R
+}
+
+define i1 @test1_noinbounds_i64(i64 %X) {
+; CHECK-LABEL: @test1_noinbounds_i64(
+; CHECK-NEXT:    [[TMP1:%.*]] = trunc i64 %X to i32
+; CHECK-NEXT:    [[R:%.*]] = icmp eq i32 [[TMP1]], 9
+; CHECK-NEXT:    ret i1 [[R]]
+;
+  %P = getelementptr [10 x i16], [10 x i16]* @G16, i64 0, i64 %X
+  %Q = load i16, i16* %P
+  %R = icmp eq i16 %Q, 0
+  ret i1 %R
+}
+
+define i1 @test1_noinbounds_as1(i32 %x) {
+; CHECK-LABEL: @test1_noinbounds_as1(
+; CHECK-NEXT:    [[TMP1:%.*]] = trunc i32 %x to i16
+; CHECK-NEXT:    [[R:%.*]] = icmp eq i16 [[TMP1]], 9
+; CHECK-NEXT:    ret i1 [[R]]
+;
+  %p = getelementptr [10 x i16], [10 x i16] addrspace(1)* @G16_as1, i16 0, i32 %x
+  %q = load i16, i16 addrspace(1)* %p
+  %r = icmp eq i16 %q, 0
+  ret i1 %r
+
+}
+
+define i1 @test2(i32 %X) {
+; CHECK-LABEL: @test2(
+; CHECK-NEXT:    [[R:%.*]] = icmp ne i32 %X, 4
+; CHECK-NEXT:    ret i1 [[R]]
+;
+  %P = getelementptr inbounds [10 x i16], [10 x i16]* @G16, i32 0, i32 %X
+  %Q = load i16, i16* %P
+  %R = icmp slt i16 %Q, 85
+  ret i1 %R
+}
+
+define i1 @test3(i32 %X) {
+; CHECK-LABEL: @test3(
+; CHECK-NEXT:    [[R:%.*]] = icmp eq i32 %X, 1
+; CHECK-NEXT:    ret i1 [[R]]
+;
+  %P = getelementptr inbounds [6 x double], [6 x double]* @GD, i32 0, i32 %X
+  %Q = load double, double* %P
+  %R = fcmp oeq double %Q, 1.0
+  ret i1 %R
+
+}
+
+define i1 @test4(i32 %X) {
+; CHECK-LABEL: @test4(
+; CHECK-NEXT:    [[TMP1:%.*]] = lshr i32 933, %X
+; CHECK-NEXT:    [[TMP2:%.*]] = and i32 [[TMP1]], 1
+; CHECK-NEXT:    [[R:%.*]] = icmp ne i32 [[TMP2]], 0
+; CHECK-NEXT:    ret i1 [[R]]
+;
+  %P = getelementptr inbounds [10 x i16], [10 x i16]* @G16, i32 0, i32 %X
+  %Q = load i16, i16* %P
+  %R = icmp sle i16 %Q, 73
+  ret i1 %R
+}
+
+define i1 @test4_i16(i16 %X) {
+; CHECK-LABEL: @test4_i16(
+; CHECK-NEXT:    [[TMP1:%.*]] = sext i16 %X to i32
+; CHECK-NEXT:    [[TMP2:%.*]] = lshr i32 933, [[TMP1]]
+; CHECK-NEXT:    [[TMP3:%.*]] = and i32 [[TMP2]], 1
+; CHECK-NEXT:    [[R:%.*]] = icmp ne i32 [[TMP3]], 0
+; CHECK-NEXT:    ret i1 [[R]]
+;
+  %P = getelementptr inbounds [10 x i16], [10 x i16]* @G16, i32 0, i16 %X
+  %Q = load i16, i16* %P
+  %R = icmp sle i16 %Q, 73
+  ret i1 %R
+}
+
+define i1 @test5(i32 %X) {
+; CHECK-LABEL: @test5(
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp eq i32 %X, 2
+; CHECK-NEXT:    [[TMP2:%.*]] = icmp eq i32 %X, 7
+; CHECK-NEXT:    [[R:%.*]] = or i1 [[TMP1]], [[TMP2]]
+; CHECK-NEXT:    ret i1 [[R]]
+;
+  %P = getelementptr inbounds [10 x i16], [10 x i16]* @G16, i32 0, i32 %X
+  %Q = load i16, i16* %P
+  %R = icmp eq i16 %Q, 69
+  ret i1 %R
+}
+
+define i1 @test6(i32 %X) {
+; CHECK-LABEL: @test6(
+; CHECK-NEXT:    [[TMP1:%.*]] = add i32 %X, -1
+; CHECK-NEXT:    [[R:%.*]] = icmp ult i32 [[TMP1]], 3
+; CHECK-NEXT:    ret i1 [[R]]
+;
+  %P = getelementptr inbounds [6 x double], [6 x double]* @GD, i32 0, i32 %X
+  %Q = load double, double* %P
+  %R = fcmp ogt double %Q, 0.0
+  ret i1 %R
+}
+
+define i1 @test7(i32 %X) {
+; CHECK-LABEL: @test7(
+; CHECK-NEXT:    [[TMP1:%.*]] = add i32 %X, -1
+; CHECK-NEXT:    [[R:%.*]] = icmp ugt i32 [[TMP1]], 2
+; CHECK-NEXT:    ret i1 [[R]]
+;
+  %P = getelementptr inbounds [6 x double], [6 x double]* @GD, i32 0, i32 %X
+  %Q = load double, double* %P
+  %R = fcmp olt double %Q, 0.0
+  ret i1 %R
+}
+
+define i1 @test8(i32 %X) {
+; CHECK-LABEL: @test8(
+; CHECK-NEXT:    [[TMP1:%.*]] = or i32 %X, 1
+; CHECK-NEXT:    [[TMP2:%.*]] = icmp eq i32 [[TMP1]], 9
+; CHECK-NEXT:    ret i1 [[TMP2]]
+;
+  %P = getelementptr inbounds [10 x i16], [10 x i16]* @G16, i32 0, i32 %X
+  %Q = load i16, i16* %P
+  %R = and i16 %Q, 3
+  %S = icmp eq i16 %R, 0
+  ret i1 %S
+}
+
+ at GA = internal constant [4 x { i32, i32 } ] [
+  { i32, i32 } { i32 1, i32 0 },
+  { i32, i32 } { i32 2, i32 1 },
+  { i32, i32 } { i32 3, i32 1 },
+  { i32, i32 } { i32 4, i32 0 }
+]
+
+define i1 @test9(i32 %X) {
+; CHECK-LABEL: @test9(
+; CHECK-NEXT:    [[X_OFF:%.*]] = add i32 %X, -1
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp ult i32 [[X_OFF]], 2
+; CHECK-NEXT:    ret i1 [[TMP1]]
+;
+  %P = getelementptr inbounds [4 x { i32, i32 } ], [4 x { i32, i32 } ]* @GA, i32 0, i32 %X, i32 1
+  %Q = load i32, i32* %P
+  %R = icmp eq i32 %Q, 1
+  ret i1 %R
+}
+
+define i1 @test10_struct(i32 %x) {
+; CHECK-LABEL: @test10_struct(
+; CHECK-NEXT:    ret i1 false
+;
+  %p = getelementptr inbounds %Foo, %Foo* @GS, i32 %x, i32 0
+  %q = load i32, i32* %p
+  %r = icmp eq i32 %q, 9
+  ret i1 %r
+}
+
+define i1 @test10_struct_noinbounds(i32 %x) {
+; CHECK-LABEL: @test10_struct_noinbounds(
+; CHECK-NEXT:    [[P:%.*]] = getelementptr %Foo, %Foo* @GS, i32 %x, i32 0
+; CHECK-NEXT:    [[Q:%.*]] = load i32, i32* [[P]], align 8
+; CHECK-NEXT:    [[R:%.*]] = icmp eq i32 [[Q]], 9
+; CHECK-NEXT:    ret i1 [[R]]
+;
+  %p = getelementptr %Foo, %Foo* @GS, i32 %x, i32 0
+  %q = load i32, i32* %p
+  %r = icmp eq i32 %q, 9
+  ret i1 %r
+}
+
+; Test that the GEP indices are converted before we ever get here
+; Index < ptr size
+define i1 @test10_struct_i16(i16 %x){
+; CHECK-LABEL: @test10_struct_i16(
+; CHECK-NEXT:    ret i1 false
+;
+  %p = getelementptr inbounds %Foo, %Foo* @GS, i16 %x, i32 0
+  %q = load i32, i32* %p
+  %r = icmp eq i32 %q, 0
+  ret i1 %r
+}
+
+; Test that the GEP indices are converted before we ever get here
+; Index > ptr size
+define i1 @test10_struct_i64(i64 %x){
+; CHECK-LABEL: @test10_struct_i64(
+; CHECK-NEXT:    ret i1 false
+;
+  %p = getelementptr inbounds %Foo, %Foo* @GS, i64 %x, i32 0
+  %q = load i32, i32* %p
+  %r = icmp eq i32 %q, 0
+  ret i1 %r
+}
+
+define i1 @test10_struct_noinbounds_i16(i16 %x) {
+; CHECK-LABEL: @test10_struct_noinbounds_i16(
+; CHECK-NEXT:    [[TMP1:%.*]] = sext i16 %x to i32
+; CHECK-NEXT:    [[P:%.*]] = getelementptr %Foo, %Foo* @GS, i32 [[TMP1]], i32 0
+; CHECK-NEXT:    [[Q:%.*]] = load i32, i32* [[P]], align 8
+; CHECK-NEXT:    [[R:%.*]] = icmp eq i32 [[Q]], 0
+; CHECK-NEXT:    ret i1 [[R]]
+;
+  %p = getelementptr %Foo, %Foo* @GS, i16 %x, i32 0
+  %q = load i32, i32* %p
+  %r = icmp eq i32 %q, 0
+  ret i1 %r
+}
+
+define i1 @test10_struct_arr(i32 %x) {
+; CHECK-LABEL: @test10_struct_arr(
+; CHECK-NEXT:    [[R:%.*]] = icmp ne i32 %x, 1
+; CHECK-NEXT:    ret i1 [[R]]
+;
+  %p = getelementptr inbounds [4 x %Foo], [4 x %Foo]* @GStructArr, i32 0, i32 %x, i32 2
+  %q = load i32, i32* %p
+  %r = icmp eq i32 %q, 9
+  ret i1 %r
+}
+
+define i1 @test10_struct_arr_noinbounds(i32 %x) {
+; CHECK-LABEL: @test10_struct_arr_noinbounds(
+; CHECK-NEXT:    [[R:%.*]] = icmp ne i32 %x, 1
+; CHECK-NEXT:    ret i1 [[R]]
+;
+  %p = getelementptr [4 x %Foo], [4 x %Foo]* @GStructArr, i32 0, i32 %x, i32 2
+  %q = load i32, i32* %p
+  %r = icmp eq i32 %q, 9
+  ret i1 %r
+}
+
+define i1 @test10_struct_arr_i16(i16 %x) {
+; CHECK-LABEL: @test10_struct_arr_i16(
+; CHECK-NEXT:    [[R:%.*]] = icmp ne i16 %x, 1
+; CHECK-NEXT:    ret i1 [[R]]
+;
+  %p = getelementptr inbounds [4 x %Foo], [4 x %Foo]* @GStructArr, i16 0, i16 %x, i32 2
+  %q = load i32, i32* %p
+  %r = icmp eq i32 %q, 9
+  ret i1 %r
+}
+
+define i1 @test10_struct_arr_i64(i64 %x) {
+; CHECK-LABEL: @test10_struct_arr_i64(
+; CHECK-NEXT:    [[TMP1:%.*]] = trunc i64 %x to i32
+; CHECK-NEXT:    [[R:%.*]] = icmp ne i32 [[TMP1]], 1
+; CHECK-NEXT:    ret i1 [[R]]
+;
+  %p = getelementptr inbounds [4 x %Foo], [4 x %Foo]* @GStructArr, i64 0, i64 %x, i32 2
+  %q = load i32, i32* %p
+  %r = icmp eq i32 %q, 9
+  ret i1 %r
+}
+
+define i1 @test10_struct_arr_noinbounds_i16(i16 %x) {
+; CHECK-LABEL: @test10_struct_arr_noinbounds_i16(
+; CHECK-NEXT:    [[R:%.*]] = icmp ne i16 %x, 1
+; CHECK-NEXT:    ret i1 [[R]]
+;
+  %p = getelementptr [4 x %Foo], [4 x %Foo]* @GStructArr, i32 0, i16 %x, i32 2
+  %q = load i32, i32* %p
+  %r = icmp eq i32 %q, 9
+  ret i1 %r
+}
+
+define i1 @test10_struct_arr_noinbounds_i64(i64 %x) {
+; CHECK-LABEL: @test10_struct_arr_noinbounds_i64(
+; CHECK-NEXT:    [[TMP1:%.*]] = trunc i64 %x to i32
+; CHECK-NEXT:    [[R:%.*]] = icmp ne i32 [[TMP1]], 1
+; CHECK-NEXT:    ret i1 [[R]]
+;
+  %p = getelementptr [4 x %Foo], [4 x %Foo]* @GStructArr, i32 0, i64 %x, i32 2
+  %q = load i32, i32* %p
+  %r = icmp eq i32 %q, 9
+  ret i1 %r
+}

Added: llvm/trunk/test/Transforms/InstCombine/load-combine-metadata-2.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/load-combine-metadata-2.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/load-combine-metadata-2.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/load-combine-metadata-2.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,20 @@
+; RUN: opt -instcombine -S < %s | FileCheck %s
+
+target datalayout = "e-m:e-p:64:64:64-i64:64-f80:128-n8:16:32:64-S128"
+
+; CHECK-LABEL: @test_load_load_combine_metadata(
+; Check that align metadata is combined
+; CHECK: load i32*, i32** %0
+; CHECK-SAME: !align ![[ALIGN:[0-9]+]]
+define void @test_load_load_combine_metadata(i32**, i32**, i32**) {
+  %a = load i32*, i32** %0, !align !0
+  %b = load i32*, i32** %0, !align !1
+  store i32 0, i32* %a
+  store i32 0, i32* %b
+  ret void
+}
+
+; CHECK: ![[ALIGN]] = !{i64 4}
+
+!0 = !{i64 4}
+!1 = !{i64 8}
\ No newline at end of file

Added: llvm/trunk/test/Transforms/InstCombine/load-combine-metadata-3.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/load-combine-metadata-3.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/load-combine-metadata-3.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/load-combine-metadata-3.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,20 @@
+; RUN: opt -instcombine -S < %s | FileCheck %s
+
+target datalayout = "e-m:e-p:64:64:64-i64:64-f80:128-n8:16:32:64-S128"
+
+; CHECK-LABEL: @test_load_load_combine_metadata(
+; Check that dereferenceable metadata is combined
+; CHECK: load i32*, i32** %0
+; CHECK-SAME: !dereferenceable ![[DEREF:[0-9]+]]
+define void @test_load_load_combine_metadata(i32**, i32**, i32**) {
+  %a = load i32*, i32** %0, !dereferenceable !0
+  %b = load i32*, i32** %0, !dereferenceable !1
+  store i32 0, i32* %a
+  store i32 0, i32* %b
+  ret void
+}
+
+; CHECK: ![[DEREF]] = !{i64 4}
+
+!0 = !{i64 4}
+!1 = !{i64 8}
\ No newline at end of file

Added: llvm/trunk/test/Transforms/InstCombine/load-combine-metadata-4.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/load-combine-metadata-4.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/load-combine-metadata-4.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/load-combine-metadata-4.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,20 @@
+; RUN: opt -instcombine -S < %s | FileCheck %s
+
+target datalayout = "e-m:e-p:64:64:64-i64:64-f80:128-n8:16:32:64-S128"
+
+; CHECK-LABEL: @test_load_load_combine_metadata(
+; Check that dereferenceable_or_null metadata is combined
+; CHECK: load i32*, i32** %0
+; CHECK-SAME: !dereferenceable_or_null ![[DEREF:[0-9]+]]
+define void @test_load_load_combine_metadata(i32**, i32**, i32**) {
+  %a = load i32*, i32** %0, !dereferenceable_or_null !0
+  %b = load i32*, i32** %0, !dereferenceable_or_null !1
+  store i32 0, i32* %a
+  store i32 0, i32* %b
+  ret void
+}
+
+; CHECK: ![[DEREF]] = !{i64 4}
+
+!0 = !{i64 4}
+!1 = !{i64 8}

Added: llvm/trunk/test/Transforms/InstCombine/load-combine-metadata-dominance.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/load-combine-metadata-dominance.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/load-combine-metadata-dominance.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/load-combine-metadata-dominance.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,44 @@
+; RUN: opt -instcombine -S < %s | FileCheck %s
+
+target datalayout = "e-m:e-p:64:64:64-i64:64-f80:128-n8:16:32:64-S128"
+
+; Check that nonnull metadata is propagated from dominating load.
+; CHECK-LABEL: @combine_metadata_dominance1(
+; CHECK-LABEL: bb1:
+; CHECK: load i32*, i32** %p, align 8, !nonnull !0
+; CHECK-NOT: load i32*, i32** %p
+define void @combine_metadata_dominance1(i32** %p) {
+entry:
+  %a = load i32*, i32** %p, !nonnull !0
+  br label %bb1
+
+bb1:
+  %b = load i32*, i32** %p
+  store i32 0, i32* %a
+  store i32 0, i32* %b
+  ret void
+}
+
+declare i32 @use(i32*, i32) readonly
+
+; Check that nonnull from the dominated load does not get propagated.
+; There are some cases where it would be safe to keep it.
+; CHECK-LABEL: @combine_metadata_dominance2(
+; CHECK-NOT: nonnull
+define void @combine_metadata_dominance2(i32** %p) {
+entry:
+  %a = load i32*, i32** %p
+  br i1 undef, label %bb1, label %bb2
+
+bb1:
+  %b = load i32*, i32** %p, !nonnull !0
+  store i32 0, i32* %a
+  store i32 0, i32* %b
+  ret void
+
+bb2:
+  ret void
+}
+
+
+!0 = !{}

Added: llvm/trunk/test/Transforms/InstCombine/load-combine-metadata.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/load-combine-metadata.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/load-combine-metadata.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/load-combine-metadata.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,30 @@
+; RUN: opt -instcombine -S < %s | FileCheck %s
+
+target datalayout = "e-m:e-p:64:64:64-i64:64-f80:128-n8:16:32:64-S128"
+
+; CHECK-LABEL: @test_load_load_combine_metadata(
+; Check that range and AA metadata is combined
+; CHECK: %[[V:.*]] = load i32, i32* %0
+; CHECK-SAME: !tbaa !{{[0-9]+}}
+; CHECK-SAME: !range ![[RANGE:[0-9]+]]
+; CHECK: store i32 %[[V]], i32* %1
+; CHECK: store i32 %[[V]], i32* %2
+define void @test_load_load_combine_metadata(i32*, i32*, i32*) {
+  %a = load i32, i32* %0, !tbaa !8, !range !0, !alias.scope !5, !noalias !6
+  %b = load i32, i32* %0, !tbaa !8, !range !1
+  store i32 %a, i32* %1
+  store i32 %b, i32* %2
+  ret void
+}
+
+; CHECK: ![[RANGE]] = !{i32 0, i32 5}
+!0 = !{ i32 0, i32 5 }
+!1 = !{ i32 7, i32 9 }
+!2 = !{!2}
+!3 = !{!3, !2}
+!4 = !{!4, !2}
+!5 = !{!3}
+!6 = !{!4}
+!7 = !{ !"tbaa root" }
+!8 = !{ !9, !9, i64 0 }
+!9 = !{ !"scalar type", !7}

Added: llvm/trunk/test/Transforms/InstCombine/load-select.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/load-select.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/load-select.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/load-select.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,16 @@
+; RUN: opt < %s -instcombine -S | FileCheck %s
+
+target datalayout = "e-p:32:32:32-i1:8:32-i8:8:32-i16:16:32-i32:32:32-i64:32:32-f32:32:32-f64:32:32-v64:64:64-v128:128:128-a0:0:32-n32"
+
+ at a = constant [2 x i32] [i32 3, i32 6]            ; <[2 x i32]*> [#uses=2]
+
+define i32 @b(i32 %y) nounwind readonly {
+; CHECK-LABEL: @b(
+; CHECK-NOT: load
+; CHECK: ret i32
+entry:
+  %0 = icmp eq i32 %y, 0                          ; <i1> [#uses=1]
+  %storemerge = select i1 %0, i32* getelementptr inbounds ([2 x i32], [2 x i32]* @a, i32 0, i32 1), i32* getelementptr inbounds ([2 x i32], [2 x i32]* @a, i32 0, i32 0) ; <i32*> [#uses=1]
+  %1 = load i32, i32* %storemerge, align 4             ; <i32> [#uses=1]
+  ret i32 %1
+}

Added: llvm/trunk/test/Transforms/InstCombine/load.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/load.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/load.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/load.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,302 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt -instcombine -S < %s | FileCheck %s
+; RUN: opt -passes=instcombine -S < %s | FileCheck %s
+
+target datalayout = "e-m:e-p:64:64:64-i64:64-f80:128-n8:16:32:64-S128"
+
+ at X = constant i32 42		; <i32*> [#uses=2]
+ at X2 = constant i32 47		; <i32*> [#uses=1]
+ at Y = constant [2 x { i32, float }] [ { i32, float } { i32 12, float 1.000000e+00 }, { i32, float } { i32 37, float 0x3FF3B2FEC0000000 } ]		; <[2 x { i32, float }]*> [#uses=2]
+ at Z = constant [2 x { i32, float }] zeroinitializer		; <[2 x { i32, float }]*> [#uses=1]
+
+ at GLOBAL = internal constant [4 x i32] zeroinitializer
+
+
+define i32 @test1() {
+; CHECK-LABEL: @test1(
+; CHECK-NEXT:    ret i32 42
+;
+  %B = load i32, i32* @X		; <i32> [#uses=1]
+  ret i32 %B
+}
+
+define float @test2() {
+; CHECK-LABEL: @test2(
+; CHECK-NEXT:    ret float 0x3FF3B2FEC0000000
+;
+  %A = getelementptr [2 x { i32, float }], [2 x { i32, float }]* @Y, i64 0, i64 1, i32 1		; <float*> [#uses=1]
+  %B = load float, float* %A		; <float> [#uses=1]
+  ret float %B
+}
+
+define i32 @test3() {
+; CHECK-LABEL: @test3(
+; CHECK-NEXT:    ret i32 12
+;
+  %A = getelementptr [2 x { i32, float }], [2 x { i32, float }]* @Y, i64 0, i64 0, i32 0		; <i32*> [#uses=1]
+  %B = load i32, i32* %A		; <i32> [#uses=1]
+  ret i32 %B
+}
+
+define i32 @test4() {
+; CHECK-LABEL: @test4(
+; CHECK-NEXT:    ret i32 0
+;
+  %A = getelementptr [2 x { i32, float }], [2 x { i32, float }]* @Z, i64 0, i64 1, i32 0		; <i32*> [#uses=1]
+  %B = load i32, i32* %A		; <i32> [#uses=1]
+  ret i32 %B
+}
+
+define i32 @test5(i1 %C) {
+; CHECK-LABEL: @test5(
+; CHECK-NEXT:    [[Z:%.*]] = select i1 [[C:%.*]], i32 42, i32 47
+; CHECK-NEXT:    ret i32 [[Z]]
+;
+  %Y = select i1 %C, i32* @X, i32* @X2		; <i32*> [#uses=1]
+  %Z = load i32, i32* %Y		; <i32> [#uses=1]
+  ret i32 %Z
+}
+
+define i32 @test7(i32 %X) {
+; CHECK-LABEL: @test7(
+; CHECK-NEXT:    store i32 undef, i32* null, align 536870912
+; CHECK-NEXT:    ret i32 undef
+;
+  %V = getelementptr i32, i32* null, i32 %X		; <i32*> [#uses=1]
+  %R = load i32, i32* %V		; <i32> [#uses=1]
+  ret i32 %R
+}
+
+define i32 @test7_no_null_opt(i32 %X) #0 {
+; CHECK-LABEL: @test7_no_null_opt(
+; CHECK-NEXT:    [[TMP1:%.*]] = sext i32 [[X:%.*]] to i64
+; CHECK-NEXT:    [[V:%.*]] = getelementptr i32, i32* null, i64 [[TMP1]]
+; CHECK-NEXT:    [[R:%.*]] = load i32, i32* [[V]], align 4
+; CHECK-NEXT:    ret i32 [[R]]
+;
+  %V = getelementptr i32, i32* null, i32 %X               ; <i32*> [#uses=1]
+  %R = load i32, i32* %V          ; <i32> [#uses=1]
+  ret i32 %R
+}
+attributes #0 = { "null-pointer-is-valid"="true" }
+
+define i32 @test8(i32* %P) {
+; CHECK-LABEL: @test8(
+; CHECK-NEXT:    store i32 1, i32* [[P:%.*]], align 4
+; CHECK-NEXT:    ret i32 1
+;
+  store i32 1, i32* %P
+  %X = load i32, i32* %P		; <i32> [#uses=1]
+  ret i32 %X
+}
+
+define i32 @test9(i32* %P) {
+; CHECK-LABEL: @test9(
+; CHECK-NEXT:    ret i32 0
+;
+  %X = load i32, i32* %P		; <i32> [#uses=1]
+  %Y = load i32, i32* %P		; <i32> [#uses=1]
+  %Z = sub i32 %X, %Y		; <i32> [#uses=1]
+  ret i32 %Z
+}
+
+define i32 @test10(i1 %C.upgrd.1, i32* %P, i32* %Q) {
+; CHECK-LABEL: @test10(
+; CHECK-NEXT:    br i1 [[C_UPGRD_1:%.*]], label [[T:%.*]], label [[F:%.*]]
+; CHECK:       T:
+; CHECK-NEXT:    store i32 1, i32* [[Q:%.*]], align 4
+; CHECK-NEXT:    br label [[C:%.*]]
+; CHECK:       F:
+; CHECK-NEXT:    br label [[C]]
+; CHECK:       C:
+; CHECK-NEXT:    store i32 0, i32* [[P:%.*]], align 4
+; CHECK-NEXT:    ret i32 0
+;
+  br i1 %C.upgrd.1, label %T, label %F
+T:		; preds = %0
+  store i32 1, i32* %Q
+  store i32 0, i32* %P
+  br label %C
+F:		; preds = %0
+  store i32 0, i32* %P
+  br label %C
+C:		; preds = %F, %T
+  %V = load i32, i32* %P		; <i32> [#uses=1]
+  ret i32 %V
+}
+
+define double @test11(double* %p) {
+; CHECK-LABEL: @test11(
+; CHECK-NEXT:    [[T0:%.*]] = getelementptr double, double* [[P:%.*]], i64 1
+; CHECK-NEXT:    store double 2.000000e+00, double* [[T0]], align 8
+; CHECK-NEXT:    ret double 2.000000e+00
+;
+  %t0 = getelementptr double, double* %p, i32 1
+  store double 2.0, double* %t0
+  %t1 = getelementptr double, double* %p, i32 1
+  %x = load double, double* %t1
+  ret double %x
+}
+
+define i32 @test12(i32* %P) {
+; CHECK-LABEL: @test12(
+; CHECK-NEXT:    ret i32 123
+;
+  %A = alloca i32
+  store i32 123, i32* %A
+  ; Cast the result of the load not the source
+  %Q = bitcast i32* %A to i32*
+  %V = load i32, i32* %Q
+  ret i32 %V
+}
+
+define <16 x i8> @test13(<2 x i64> %x) {
+; CHECK-LABEL: @test13(
+; CHECK-NEXT:    ret <16 x i8> zeroinitializer
+;
+  %tmp = load <16 x i8>, <16 x i8>* bitcast ([4 x i32]* @GLOBAL to <16 x i8>*)
+  ret <16 x i8> %tmp
+}
+
+; This test must not have the store of %x forwarded to the load -- there is an
+; intervening store if %y. However, the intervening store occurs with a different
+; type and size and to a different pointer value. This is ensuring that none of
+; those confuse the analysis into thinking that the second store does not alias
+; the first.
+
+define i8 @test14(i8 %x, i32 %y) {
+; CHECK-LABEL: @test14(
+; CHECK-NEXT:    [[A:%.*]] = alloca i32, align 4
+; CHECK-NEXT:    [[A_I8:%.*]] = bitcast i32* [[A]] to i8*
+; CHECK-NEXT:    store i8 [[X:%.*]], i8* [[A_I8]], align 4
+; CHECK-NEXT:    store i32 [[Y:%.*]], i32* [[A]], align 4
+; CHECK-NEXT:    [[R:%.*]] = load i8, i8* [[A_I8]], align 4
+; CHECK-NEXT:    ret i8 [[R]]
+;
+  %a = alloca i32
+  %a.i8 = bitcast i32* %a to i8*
+  store i8 %x, i8* %a.i8
+  store i32 %y, i32* %a
+  %r = load i8, i8* %a.i8
+  ret i8 %r
+}
+
+ at test15_global = external global i32
+
+; Same test as @test14 essentially, but using a global instead of an alloca.
+
+define i8 @test15(i8 %x, i32 %y) {
+; CHECK-LABEL: @test15(
+; CHECK-NEXT:    store i8 [[X:%.*]], i8* bitcast (i32* @test15_global to i8*), align 4
+; CHECK-NEXT:    store i32 [[Y:%.*]], i32* @test15_global, align 4
+; CHECK-NEXT:    [[R:%.*]] = load i8, i8* bitcast (i32* @test15_global to i8*), align 4
+; CHECK-NEXT:    ret i8 [[R]]
+;
+  %g.i8 = bitcast i32* @test15_global to i8*
+  store i8 %x, i8* %g.i8
+  store i32 %y, i32* @test15_global
+  %r = load i8, i8* %g.i8
+  ret i8 %r
+}
+
+; Check that we canonicalize loads which are only stored to use integer types
+; when there is a valid integer type.
+
+define void @test16(i8* %x, i8* %a, i8* %b, i8* %c) {
+; CHECK-LABEL: @test16(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[C_CAST:%.*]] = bitcast i8* [[C:%.*]] to i32*
+; CHECK-NEXT:    [[TMP0:%.*]] = bitcast i8* [[X:%.*]] to i32*
+; CHECK-NEXT:    [[X11:%.*]] = load i32, i32* [[TMP0]], align 4
+; CHECK-NEXT:    [[TMP1:%.*]] = bitcast i8* [[A:%.*]] to i32*
+; CHECK-NEXT:    store i32 [[X11]], i32* [[TMP1]], align 4
+; CHECK-NEXT:    [[TMP2:%.*]] = bitcast i8* [[B:%.*]] to i32*
+; CHECK-NEXT:    store i32 [[X11]], i32* [[TMP2]], align 4
+; CHECK-NEXT:    [[TMP3:%.*]] = bitcast i8* [[X]] to i32*
+; CHECK-NEXT:    [[X22:%.*]] = load i32, i32* [[TMP3]], align 4
+; CHECK-NEXT:    [[TMP4:%.*]] = bitcast i8* [[B]] to i32*
+; CHECK-NEXT:    store i32 [[X22]], i32* [[TMP4]], align 4
+; CHECK-NEXT:    store i32 [[X22]], i32* [[C_CAST]], align 4
+; CHECK-NEXT:    ret void
+;
+entry:
+  %x.cast = bitcast i8* %x to float*
+  %a.cast = bitcast i8* %a to float*
+  %b.cast = bitcast i8* %b to float*
+  %c.cast = bitcast i8* %c to i32*
+
+  %x1 = load float, float* %x.cast
+  store float %x1, float* %a.cast
+  store float %x1, float* %b.cast
+
+  %x2 = load float, float* %x.cast
+  store float %x2, float* %b.cast
+  %x2.cast = bitcast float %x2 to i32
+  store i32 %x2.cast, i32* %c.cast
+
+  ret void
+}
+
+; Check that in cases similar to @test16 we don't try to rewrite a load when
+; its only use is a store but it is used as the pointer to that store rather
+; than the value.
+
+define void @test17(i8** %x, i8 %y) {
+; CHECK-LABEL: @test17(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[X_LOAD:%.*]] = load i8*, i8** [[X:%.*]], align 8
+; CHECK-NEXT:    store i8 [[Y:%.*]], i8* [[X_LOAD]], align 1
+; CHECK-NEXT:    ret void
+;
+entry:
+  %x.load = load i8*, i8** %x
+  store i8 %y, i8* %x.load
+
+  ret void
+}
+
+; Check that we don't try change the type of the load by inserting a bitcast
+; generating invalid IR.
+%swift.error = type opaque
+declare void @useSwiftError(%swift.error** swifterror)
+
+define void @test18(%swift.error** swifterror %err) {
+; CHECK-LABEL: @test18(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[SWIFTERROR:%.*]] = alloca swifterror %swift.error*, align 8
+; CHECK-NEXT:    store %swift.error* null, %swift.error** [[SWIFTERROR]], align 8
+; CHECK-NEXT:    call void @useSwiftError(%swift.error** nonnull swifterror [[SWIFTERROR]])
+; CHECK-NEXT:    [[ERR_RES:%.*]] = load %swift.error*, %swift.error** [[SWIFTERROR]], align 8
+; CHECK-NEXT:    store %swift.error* [[ERR_RES]], %swift.error** [[ERR:%.*]], align 8
+; CHECK-NEXT:    ret void
+;
+entry:
+  %swifterror = alloca swifterror %swift.error*, align 8
+  store %swift.error* null, %swift.error** %swifterror, align 8
+  call void @useSwiftError(%swift.error** nonnull swifterror %swifterror)
+  %err.res = load %swift.error*, %swift.error** %swifterror, align 8
+  store %swift.error* %err.res, %swift.error** %err, align 8
+  ret void
+}
+
+; Make sure we preseve the type of the store to a swifterror pointer.
+
+declare void @initi8(i8**)
+define void @test19(%swift.error** swifterror %err) {
+; CHECK-LABEL: @test19(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[TMP:%.*]] = alloca i8*, align 8
+; CHECK-NEXT:    call void @initi8(i8** nonnull [[TMP]])
+; CHECK-NEXT:    [[SWIFTERROR:%.*]] = bitcast i8** [[TMP]] to %swift.error**
+; CHECK-NEXT:    [[ERR_RES:%.*]] = load %swift.error*, %swift.error** [[SWIFTERROR]], align 8
+; CHECK-NEXT:    store %swift.error* [[ERR_RES]], %swift.error** [[ERR:%.*]], align 8
+; CHECK-NEXT:    ret void
+;
+entry:
+  %tmp = alloca i8*, align 8
+  call void @initi8(i8** %tmp)
+  %swifterror = bitcast i8** %tmp to %swift.error**
+  %err.res = load %swift.error*, %swift.error** %swifterror, align 8
+  store %swift.error* %err.res, %swift.error** %err, align 8
+  ret void
+}

Added: llvm/trunk/test/Transforms/InstCombine/load3.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/load3.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/load3.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/load3.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,46 @@
+; RUN: opt < %s -instcombine -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:128:128-n8:16:32-S128"
+target triple = "i386-apple-macosx10.0.0"
+
+; Instcombine should be able to do trivial CSE of loads.
+
+define i32 @test1(i32* %p) {
+  %t0 = getelementptr i32, i32* %p, i32 1
+  %y = load i32, i32* %t0
+  %t1 = getelementptr i32, i32* %p, i32 1
+  %x = load i32, i32* %t1
+  %a = sub i32 %y, %x
+  ret i32 %a
+; CHECK-LABEL: @test1(
+; CHECK: ret i32 0
+}
+
+
+; PR7429
+ at .str = private constant [4 x i8] c"XYZ\00"
+define float @test2() {
+  %tmp = load float, float* bitcast ([4 x i8]* @.str to float*), align 1
+  ret float %tmp
+  
+; CHECK-LABEL: @test2(
+; CHECK: ret float 0x3806965600000000
+}
+
+ at rslts32 = global [36 x i32] zeroinitializer, align 4
+
+ at expect32 = internal constant [36 x i32][ i32 1, i32 2, i32 0, i32 100, i32 3,
+i32 4, i32 0, i32 -7, i32 4, i32 4, i32 8, i32 8, i32 1, i32 3, i32 8, i32 3,
+i32 4, i32 -2, i32 2, i32 8, i32 83, i32 77, i32 8, i32 17, i32 77, i32 88, i32
+22, i32 33, i32 44, i32 88, i32 77, i32 4, i32 4, i32 7, i32 -7, i32 -8] ,
+align 4
+
+; PR14986
+define void @test3() nounwind {
+; This is a weird way of computing zero.
+  %l = load i32, i32* getelementptr ([36 x i32], [36 x i32]* @expect32, i32 29826161, i32 28), align 4
+  store i32 %l, i32* getelementptr ([36 x i32], [36 x i32]* @rslts32, i32 29826161, i32 28), align 4
+  ret void
+
+; CHECK-LABEL: @test3(
+; CHECK: store i32 1, i32* getelementptr inbounds ([36 x i32], [36 x i32]* @rslts32, i32 0, i32 0)
+}

Added: llvm/trunk/test/Transforms/InstCombine/load_combine_aa.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/load_combine_aa.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/load_combine_aa.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/load_combine_aa.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,15 @@
+; RUN: opt -basicaa -instcombine -S < %s | FileCheck %s
+
+; CHECK-LABEL: @test_load_combine_aa(
+; CHECK: %[[V:.*]] = load i32, i32* %0
+; CHECK: store i32 0, i32* %3
+; CHECK: store i32 %[[V]], i32* %1
+; CHECK: store i32 %[[V]], i32* %2
+define void @test_load_combine_aa(i32*, i32*, i32*, i32* noalias) {
+  %a = load i32, i32* %0
+  store i32 0, i32* %3
+  %b = load i32, i32* %0
+  store i32 %a, i32* %1
+  store i32 %b, i32* %2
+  ret void
+}

Added: llvm/trunk/test/Transforms/InstCombine/loadstore-alignment.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/loadstore-alignment.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/loadstore-alignment.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/loadstore-alignment.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,90 @@
+; RUN: opt -instcombine -S < %s | FileCheck %s
+target datalayout = "E-p:64:64:64-p1:64:64:64-p2:32:32:32-a0:0:8-f32:32:32-f64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-v64:64:64-v128:128:128"
+
+ at x = external global <2 x i64>, align 16
+ at xx = external global [13 x <2 x i64>], align 16
+
+ at x.as2 = external addrspace(2) global <2 x i64>, align 16
+
+; CHECK-LABEL: @static_hem(
+; CHECK: , align 16
+define <2 x i64> @static_hem() {
+  %t = getelementptr <2 x i64>, <2 x i64>* @x, i32 7
+  %tmp1 = load <2 x i64>, <2 x i64>* %t, align 1
+  ret <2 x i64> %tmp1
+}
+
+; CHECK-LABEL: @hem(
+; CHECK: , align 16
+define <2 x i64> @hem(i32 %i) {
+  %t = getelementptr <2 x i64>, <2 x i64>* @x, i32 %i
+  %tmp1 = load <2 x i64>, <2 x i64>* %t, align 1
+  ret <2 x i64> %tmp1
+}
+
+; CHECK-LABEL: @hem_2d(
+; CHECK: , align 16
+define <2 x i64> @hem_2d(i32 %i, i32 %j) {
+  %t = getelementptr [13 x <2 x i64>], [13 x <2 x i64>]* @xx, i32 %i, i32 %j
+  %tmp1 = load <2 x i64>, <2 x i64>* %t, align 1
+  ret <2 x i64> %tmp1
+}
+
+; CHECK-LABEL: @foo(
+; CHECK: , align 16
+define <2 x i64> @foo() {
+  %tmp1 = load <2 x i64>, <2 x i64>* @x, align 1
+  ret <2 x i64> %tmp1
+}
+
+; CHECK-LABEL: @bar(
+; CHECK: , align 16
+; CHECK: , align 16
+define <2 x i64> @bar() {
+  %t = alloca <2 x i64>
+  call void @kip(<2 x i64>* %t)
+  %tmp1 = load <2 x i64>, <2 x i64>* %t, align 1
+  ret <2 x i64> %tmp1
+}
+
+; CHECK-LABEL: @static_hem_store(
+; CHECK: , align 16
+define void @static_hem_store(<2 x i64> %y) {
+  %t = getelementptr <2 x i64>, <2 x i64>* @x, i32 7
+  store <2 x i64> %y, <2 x i64>* %t, align 1
+  ret void
+}
+
+; CHECK-LABEL: @hem_store(
+; CHECK: , align 16
+define void @hem_store(i32 %i, <2 x i64> %y) {
+  %t = getelementptr <2 x i64>, <2 x i64>* @x, i32 %i
+  store <2 x i64> %y, <2 x i64>* %t, align 1
+  ret void
+}
+
+; CHECK-LABEL: @hem_2d_store(
+; CHECK: , align 16
+define void @hem_2d_store(i32 %i, i32 %j, <2 x i64> %y) {
+  %t = getelementptr [13 x <2 x i64>], [13 x <2 x i64>]* @xx, i32 %i, i32 %j
+  store <2 x i64> %y, <2 x i64>* %t, align 1
+  ret void
+}
+
+; CHECK-LABEL: @foo_store(
+; CHECK: , align 16
+define void @foo_store(<2 x i64> %y) {
+  store <2 x i64> %y, <2 x i64>* @x, align 1
+  ret void
+}
+
+; CHECK-LABEL: @bar_store(
+; CHECK: , align 16
+define void @bar_store(<2 x i64> %y) {
+  %t = alloca <2 x i64>
+  call void @kip(<2 x i64>* %t)
+  store <2 x i64> %y, <2 x i64>* %t, align 1
+  ret void
+}
+
+declare void @kip(<2 x i64>* %t)

Added: llvm/trunk/test/Transforms/InstCombine/loadstore-metadata.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/loadstore-metadata.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/loadstore-metadata.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/loadstore-metadata.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,150 @@
+; RUN: opt -instcombine -S < %s | FileCheck %s
+
+target datalayout = "e-m:e-p:64:64:64-i64:64-f80:128-n8:16:32:64-S128"
+
+define i32 @test_load_cast_combine_tbaa(float* %ptr) {
+; Ensure (cast (load (...))) -> (load (cast (...))) preserves TBAA.
+; CHECK-LABEL: @test_load_cast_combine_tbaa(
+; CHECK: load i32, i32* %{{.*}}, !tbaa !0
+entry:
+  %l = load float, float* %ptr, !tbaa !0
+  %c = bitcast float %l to i32
+  ret i32 %c
+}
+
+define i32 @test_load_cast_combine_noalias(float* %ptr) {
+; Ensure (cast (load (...))) -> (load (cast (...))) preserves no-alias metadata.
+; CHECK-LABEL: @test_load_cast_combine_noalias(
+; CHECK: load i32, i32* %{{.*}}, !alias.scope !3, !noalias !4
+entry:
+  %l = load float, float* %ptr, !alias.scope !3, !noalias !4
+  %c = bitcast float %l to i32
+  ret i32 %c
+}
+
+define float @test_load_cast_combine_range(i32* %ptr) {
+; Ensure (cast (load (...))) -> (load (cast (...))) drops range metadata. It
+; would be nice to preserve or update it somehow but this is hard when moving
+; between types.
+; CHECK-LABEL: @test_load_cast_combine_range(
+; CHECK: load float, float* %{{.*}}
+; CHECK-NOT: !range
+; CHECK: ret float
+entry:
+  %l = load i32, i32* %ptr, !range !5
+  %c = bitcast i32 %l to float
+  ret float %c
+}
+
+define i32 @test_load_cast_combine_invariant(float* %ptr) {
+; Ensure (cast (load (...))) -> (load (cast (...))) preserves invariant metadata.
+; CHECK-LABEL: @test_load_cast_combine_invariant(
+; CHECK: load i32, i32* %{{.*}}, !invariant.load !7
+entry:
+  %l = load float, float* %ptr, !invariant.load !6
+  %c = bitcast float %l to i32
+  ret i32 %c
+}
+
+define i32 @test_load_cast_combine_nontemporal(float* %ptr) {
+; Ensure (cast (load (...))) -> (load (cast (...))) preserves nontemporal
+; metadata.
+; CHECK-LABEL: @test_load_cast_combine_nontemporal(
+; CHECK: load i32, i32* %{{.*}}, !nontemporal !8
+entry:
+  %l = load float, float* %ptr, !nontemporal !7
+  %c = bitcast float %l to i32
+  ret i32 %c
+}
+
+define i8* @test_load_cast_combine_align(i32** %ptr) {
+; Ensure (cast (load (...))) -> (load (cast (...))) preserves align
+; metadata.
+; CHECK-LABEL: @test_load_cast_combine_align(
+; CHECK: load i8*, i8** %{{.*}}, !align !9
+entry:
+  %l = load i32*, i32** %ptr, !align !8
+  %c = bitcast i32* %l to i8*
+  ret i8* %c
+}
+
+define i8* @test_load_cast_combine_deref(i32** %ptr) {
+; Ensure (cast (load (...))) -> (load (cast (...))) preserves dereferenceable
+; metadata.
+; CHECK-LABEL: @test_load_cast_combine_deref(
+; CHECK: load i8*, i8** %{{.*}}, !dereferenceable !9
+entry:
+  %l = load i32*, i32** %ptr, !dereferenceable !8
+  %c = bitcast i32* %l to i8*
+  ret i8* %c
+}
+
+define i8* @test_load_cast_combine_deref_or_null(i32** %ptr) {
+; Ensure (cast (load (...))) -> (load (cast (...))) preserves
+; dereferenceable_or_null metadata.
+; CHECK-LABEL: @test_load_cast_combine_deref_or_null(
+; CHECK: load i8*, i8** %{{.*}}, !dereferenceable_or_null !9
+entry:
+  %l = load i32*, i32** %ptr, !dereferenceable_or_null !8
+  %c = bitcast i32* %l to i8*
+  ret i8* %c
+}
+
+define void @test_load_cast_combine_loop(float* %src, i32* %dst, i32 %n) {
+; Ensure (cast (load (...))) -> (load (cast (...))) preserves loop access
+; metadata.
+; CHECK-LABEL: @test_load_cast_combine_loop(
+; CHECK: load i32, i32* %{{.*}}, !llvm.access.group !6
+entry:
+  br label %loop
+
+loop:
+  %i = phi i32 [ 0, %entry ], [ %i.next, %loop ]
+  %src.gep = getelementptr inbounds float, float* %src, i32 %i
+  %dst.gep = getelementptr inbounds i32, i32* %dst, i32 %i
+  %l = load float, float* %src.gep, !llvm.access.group !9
+  %c = bitcast float %l to i32
+  store i32 %c, i32* %dst.gep
+  %i.next = add i32 %i, 1
+  %cmp = icmp slt i32 %i.next, %n
+  br i1 %cmp, label %loop, label %exit, !llvm.loop !1
+
+exit:
+  ret void
+}
+
+define void @test_load_cast_combine_nonnull(float** %ptr) {
+; We can't preserve nonnull metadata when converting a load of a pointer to
+; a load of an integer. Instead, we translate it to range metadata.
+; FIXME: We should also transform range metadata back into nonnull metadata.
+; FIXME: This test is very fragile. If any LABEL lines are added after
+; this point, the test will fail, because this test depends on a metadata tuple,
+; which is always emitted at the end of the file. At some point, we should
+; consider an option to the IR printer to emit MD tuples after the function
+; that first uses them--this will allow us to refer to them like this and not
+; have the tests break. For now, this function must always come last in this
+; file, and no LABEL lines are to be added after this point.
+;
+; CHECK-LABEL: @test_load_cast_combine_nonnull(
+; CHECK: %[[V:.*]] = load i64, i64* %{{.*}}, !range ![[MD:[0-9]+]]
+; CHECK-NOT: !nonnull
+; CHECK: store i64 %[[V]], i64*
+entry:
+  %p = load float*, float** %ptr, !nonnull !6
+  %gep = getelementptr float*, float** %ptr, i32 42
+  store float* %p, float** %gep
+  ret void
+}
+
+; This is the metadata tuple that we reference above:
+; CHECK: ![[MD]] = !{i64 1, i64 0}
+!0 = !{!1, !1, i64 0}
+!1 = !{!"scalar type", !2}
+!2 = !{!"root"}
+!3 = distinct !{!3, !4}
+!4 = distinct !{!4, !{!"llvm.loop.parallel_accesses", !9}}
+!5 = !{i32 0, i32 42}
+!6 = !{}
+!7 = !{i32 1}
+!8 = !{i64 8}
+!9 = distinct !{}

Added: llvm/trunk/test/Transforms/InstCombine/log-pow-nofastmath.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/log-pow-nofastmath.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/log-pow-nofastmath.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/log-pow-nofastmath.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,30 @@
+; RUN: opt < %s -instcombine -S | FileCheck %s
+
+define double @mylog(double %x, double %y) {
+entry:
+  %pow = call double @llvm.pow.f64(double %x, double %y)
+  %call = call double @log(double %pow)
+  ret double %call
+}
+
+; CHECK-LABEL: define double @mylog(
+; CHECK:   %pow = call double @llvm.pow.f64(double %x, double %y)
+; CHECK:   %call = call double @log(double %pow)
+; CHECK:   ret double %call
+; CHECK: }
+
+define double @test3(double %x) {
+  %call2 = call double @exp2(double %x)
+  %call3 = call double @log(double %call2)
+  ret double %call3
+}
+
+; CHECK-LABEL: @test3
+; CHECK:   %call2 = call double @exp2(double %x)
+; CHECK:   %call3 = call double @log(double %call2)
+; CHECK:   ret double %call3
+; CHECK: }
+
+declare double @log(double)
+declare double @exp2(double)
+declare double @llvm.pow.f64(double, double)

Added: llvm/trunk/test/Transforms/InstCombine/log-pow.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/log-pow.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/log-pow.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/log-pow.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,62 @@
+; RUN: opt < %s -instcombine -S | FileCheck %s
+
+define double @log_pow(double %x, double %y) {
+  %pow = call fast double @llvm.pow.f64(double %x, double %y)
+  %call = call fast double @log(double %pow)
+  ret double %call
+}
+
+; CHECK-LABEL: define double @log_pow(
+; CHECK-NEXT:  %log = call fast double @log(double %x)
+; CHECK-NEXT:  %mul = fmul fast double %log, %y
+; CHECK-NEXT:  ret double %mul
+
+define double @log_pow_not_fast(double %x, double %y) {
+  %pow = call double @llvm.pow.f64(double %x, double %y)
+  %call = call fast double @log(double %pow)
+  ret double %call
+}
+
+; CHECK-LABEL: define double @log_pow_not_fast(
+; CHECK-NEXT:  %pow = call double @llvm.pow.f64(double %x, double %y)
+; CHECK-NEXT:  %call = call fast double @log(double %pow)
+; CHECK-NEXT:  ret double %call
+
+define double @function_pointer(double ()* %fptr, double %p1) {
+  %call1 = call double %fptr()
+  %pow = call double @log(double %call1)
+  ret double %pow
+}
+
+; CHECK-LABEL: @function_pointer
+; CHECK-NEXT:  %call1 = call double %fptr()
+; CHECK-NEXT:  %pow = call double @log(double %call1)
+; CHECK-NEXT:  ret double %pow
+
+define double @log_exp2(double %x) {
+  %call2 = call fast double @exp2(double %x)
+  %call3 = call fast double @log(double %call2)
+  ret double %call3
+}
+
+; CHECK-LABEL: @log_exp2
+; CHECK-NEXT:  %call2 = call fast double @exp2(double %x)
+; CHECK-NEXT:  %logmul = fmul fast double %x, 0x3FE62E42FEFA39EF
+; CHECK-NEXT:  ret double %logmul
+
+define double @log_exp2_not_fast(double %x) {
+  %call2 = call double @exp2(double %x)
+  %call3 = call fast double @log(double %call2)
+  ret double %call3
+}
+
+; CHECK-LABEL: @log_exp2_not_fast
+; CHECK-NEXT:  %call2 = call double @exp2(double %x)
+; CHECK-NEXT:  %call3 = call fast double @log(double %call2)
+; CHECK-NEXT:  ret double %call3
+
+declare double @log(double) #0
+declare double @exp2(double)
+declare double @llvm.pow.f64(double, double)
+
+attributes #0 = { nounwind readnone }

Added: llvm/trunk/test/Transforms/InstCombine/logical-select.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/logical-select.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/logical-select.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/logical-select.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,637 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt < %s -instcombine -S | FileCheck %s
+
+
+define i32 @foo(i32 %a, i32 %b, i32 %c, i32 %d) {
+; CHECK-LABEL: @foo(
+; CHECK-NEXT:    [[E:%.*]] = icmp slt i32 [[A:%.*]], [[B:%.*]]
+; CHECK-NEXT:    [[TMP1:%.*]] = select i1 [[E]], i32 [[C:%.*]], i32 [[D:%.*]]
+; CHECK-NEXT:    ret i32 [[TMP1]]
+;
+  %e = icmp slt i32 %a, %b
+  %f = sext i1 %e to i32
+  %g = and i32 %c, %f
+  %h = xor i32 %f, -1
+  %i = and i32 %d, %h
+  %j = or i32 %g, %i
+  ret i32 %j
+}
+
+define i32 @bar(i32 %a, i32 %b, i32 %c, i32 %d) {
+; CHECK-LABEL: @bar(
+; CHECK-NEXT:    [[E:%.*]] = icmp slt i32 [[A:%.*]], [[B:%.*]]
+; CHECK-NEXT:    [[TMP1:%.*]] = select i1 [[E]], i32 [[C:%.*]], i32 [[D:%.*]]
+; CHECK-NEXT:    ret i32 [[TMP1]]
+;
+  %e = icmp slt i32 %a, %b
+  %f = sext i1 %e to i32
+  %g = and i32 %c, %f
+  %h = xor i32 %f, -1
+  %i = and i32 %d, %h
+  %j = or i32 %i, %g
+  ret i32 %j
+}
+
+define i32 @goo(i32 %a, i32 %b, i32 %c, i32 %d) {
+; CHECK-LABEL: @goo(
+; CHECK-NEXT:    [[T0:%.*]] = icmp slt i32 [[A:%.*]], [[B:%.*]]
+; CHECK-NEXT:    [[TMP1:%.*]] = select i1 [[T0]], i32 [[C:%.*]], i32 [[D:%.*]]
+; CHECK-NEXT:    ret i32 [[TMP1]]
+;
+  %t0 = icmp slt i32 %a, %b
+  %iftmp.0.0 = select i1 %t0, i32 -1, i32 0
+  %t1 = and i32 %iftmp.0.0, %c
+  %not = xor i32 %iftmp.0.0, -1
+  %t2 = and i32 %not, %d
+  %t3 = or i32 %t1, %t2
+  ret i32 %t3
+}
+
+define i32 @poo(i32 %a, i32 %b, i32 %c, i32 %d) {
+; CHECK-LABEL: @poo(
+; CHECK-NEXT:    [[T0:%.*]] = icmp slt i32 [[A:%.*]], [[B:%.*]]
+; CHECK-NEXT:    [[T3:%.*]] = select i1 [[T0]], i32 [[C:%.*]], i32 [[D:%.*]]
+; CHECK-NEXT:    ret i32 [[T3]]
+;
+  %t0 = icmp slt i32 %a, %b
+  %iftmp.0.0 = select i1 %t0, i32 -1, i32 0
+  %t1 = and i32 %iftmp.0.0, %c
+  %iftmp = select i1 %t0, i32 0, i32 -1
+  %t2 = and i32 %iftmp, %d
+  %t3 = or i32 %t1, %t2
+  ret i32 %t3
+}
+
+; PR32791 - https://bugs.llvm.org//show_bug.cgi?id=32791
+; The 2nd compare/select are canonicalized, so CSE and another round of instcombine or some other pass will fold this.
+
+define i32 @fold_inverted_icmp_preds(i32 %a, i32 %b, i32 %c, i32 %d) {
+; CHECK-LABEL: @fold_inverted_icmp_preds(
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp slt i32 [[A:%.*]], [[B:%.*]]
+; CHECK-NEXT:    [[SEL1:%.*]] = select i1 [[CMP1]], i32 [[C:%.*]], i32 0
+; CHECK-NEXT:    [[CMP2:%.*]] = icmp slt i32 [[A]], [[B]]
+; CHECK-NEXT:    [[SEL2:%.*]] = select i1 [[CMP2]], i32 0, i32 [[D:%.*]]
+; CHECK-NEXT:    [[OR:%.*]] = or i32 [[SEL1]], [[SEL2]]
+; CHECK-NEXT:    ret i32 [[OR]]
+;
+  %cmp1 = icmp slt i32 %a, %b
+  %sel1 = select i1 %cmp1, i32 %c, i32 0
+  %cmp2 = icmp sge i32 %a, %b
+  %sel2 = select i1 %cmp2, i32 %d, i32 0
+  %or = or i32 %sel1, %sel2
+  ret i32 %or
+}
+
+; The 2nd compare/select are canonicalized, so CSE and another round of instcombine or some other pass will fold this.
+
+define i32 @fold_inverted_icmp_preds_reverse(i32 %a, i32 %b, i32 %c, i32 %d) {
+; CHECK-LABEL: @fold_inverted_icmp_preds_reverse(
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp slt i32 [[A:%.*]], [[B:%.*]]
+; CHECK-NEXT:    [[SEL1:%.*]] = select i1 [[CMP1]], i32 0, i32 [[C:%.*]]
+; CHECK-NEXT:    [[CMP2:%.*]] = icmp slt i32 [[A]], [[B]]
+; CHECK-NEXT:    [[SEL2:%.*]] = select i1 [[CMP2]], i32 [[D:%.*]], i32 0
+; CHECK-NEXT:    [[OR:%.*]] = or i32 [[SEL1]], [[SEL2]]
+; CHECK-NEXT:    ret i32 [[OR]]
+;
+  %cmp1 = icmp slt i32 %a, %b
+  %sel1 = select i1 %cmp1, i32 0, i32 %c
+  %cmp2 = icmp sge i32 %a, %b
+  %sel2 = select i1 %cmp2, i32 0, i32 %d
+  %or = or i32 %sel1, %sel2
+  ret i32 %or
+}
+
+; TODO: Should fcmp have the same sort of predicate canonicalization as icmp?
+
+define i32 @fold_inverted_fcmp_preds(float %a, float %b, i32 %c, i32 %d) {
+; CHECK-LABEL: @fold_inverted_fcmp_preds(
+; CHECK-NEXT:    [[CMP1:%.*]] = fcmp olt float [[A:%.*]], [[B:%.*]]
+; CHECK-NEXT:    [[SEL1:%.*]] = select i1 [[CMP1]], i32 [[C:%.*]], i32 0
+; CHECK-NEXT:    [[CMP2:%.*]] = fcmp uge float [[A]], [[B]]
+; CHECK-NEXT:    [[SEL2:%.*]] = select i1 [[CMP2]], i32 [[D:%.*]], i32 0
+; CHECK-NEXT:    [[OR:%.*]] = or i32 [[SEL1]], [[SEL2]]
+; CHECK-NEXT:    ret i32 [[OR]]
+;
+  %cmp1 = fcmp olt float %a, %b
+  %sel1 = select i1 %cmp1, i32 %c, i32 0
+  %cmp2 = fcmp uge float %a, %b
+  %sel2 = select i1 %cmp2, i32 %d, i32 0
+  %or = or i32 %sel1, %sel2
+  ret i32 %or
+}
+
+; The 2nd compare/select are canonicalized, so CSE and another round of instcombine or some other pass will fold this.
+
+define <2 x i32> @fold_inverted_icmp_vector_preds(<2 x i32> %a, <2 x i32> %b, <2 x i32> %c, <2 x i32> %d) {
+; CHECK-LABEL: @fold_inverted_icmp_vector_preds(
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp eq <2 x i32> [[A:%.*]], [[B:%.*]]
+; CHECK-NEXT:    [[SEL1:%.*]] = select <2 x i1> [[CMP1]], <2 x i32> zeroinitializer, <2 x i32> [[C:%.*]]
+; CHECK-NEXT:    [[CMP2:%.*]] = icmp eq <2 x i32> [[A]], [[B]]
+; CHECK-NEXT:    [[SEL2:%.*]] = select <2 x i1> [[CMP2]], <2 x i32> [[D:%.*]], <2 x i32> zeroinitializer
+; CHECK-NEXT:    [[OR:%.*]] = or <2 x i32> [[SEL1]], [[SEL2]]
+; CHECK-NEXT:    ret <2 x i32> [[OR]]
+;
+  %cmp1 = icmp ne <2 x i32> %a, %b
+  %sel1 = select <2 x i1> %cmp1, <2 x i32> %c, <2 x i32> <i32 0, i32 0>
+  %cmp2 = icmp eq <2 x i32> %a, %b
+  %sel2 = select <2 x i1> %cmp2, <2 x i32> %d, <2 x i32> <i32 0, i32 0>
+  %or = or <2 x i32> %sel1, %sel2
+  ret <2 x i32> %or
+}
+
+define i32 @par(i32 %a, i32 %b, i32 %c, i32 %d) {
+; CHECK-LABEL: @par(
+; CHECK-NEXT:    [[T0:%.*]] = icmp slt i32 [[A:%.*]], [[B:%.*]]
+; CHECK-NEXT:    [[TMP1:%.*]] = select i1 [[T0]], i32 [[C:%.*]], i32 [[D:%.*]]
+; CHECK-NEXT:    ret i32 [[TMP1]]
+;
+  %t0 = icmp slt i32 %a, %b
+  %iftmp.1.0 = select i1 %t0, i32 -1, i32 0
+  %t1 = and i32 %iftmp.1.0, %c
+  %not = xor i32 %iftmp.1.0, -1
+  %t2 = and i32 %not, %d
+  %t3 = or i32 %t1, %t2
+  ret i32 %t3
+}
+
+; In the following tests (8 commutation variants), verify that a bitcast doesn't get
+; in the way of a select transform. These bitcasts are common in SSE/AVX and possibly
+; other vector code because of canonicalization to i64 elements for vectors.
+
+; The fptosi instructions are included to avoid commutation canonicalization based on
+; operator weight. Using another cast operator ensures that both operands of all logic
+; ops are equally weighted, and this ensures that we're testing all commutation
+; possibilities.
+
+define <2 x i64> @bitcast_select_swap0(<4 x i1> %cmp, <2 x double> %a, <2 x double> %b) {
+; CHECK-LABEL: @bitcast_select_swap0(
+; CHECK-NEXT:    [[SIA:%.*]] = fptosi <2 x double> [[A:%.*]] to <2 x i64>
+; CHECK-NEXT:    [[SIB:%.*]] = fptosi <2 x double> [[B:%.*]] to <2 x i64>
+; CHECK-NEXT:    [[TMP1:%.*]] = bitcast <2 x i64> [[SIA]] to <4 x i32>
+; CHECK-NEXT:    [[TMP2:%.*]] = bitcast <2 x i64> [[SIB]] to <4 x i32>
+; CHECK-NEXT:    [[TMP3:%.*]] = select <4 x i1> [[CMP:%.*]], <4 x i32> [[TMP1]], <4 x i32> [[TMP2]]
+; CHECK-NEXT:    [[TMP4:%.*]] = bitcast <4 x i32> [[TMP3]] to <2 x i64>
+; CHECK-NEXT:    ret <2 x i64> [[TMP4]]
+;
+  %sia = fptosi <2 x double> %a to <2 x i64>
+  %sib = fptosi <2 x double> %b to <2 x i64>
+  %sext = sext <4 x i1> %cmp to <4 x i32>
+  %bc1 = bitcast <4 x i32> %sext to <2 x i64>
+  %and1 = and <2 x i64> %bc1, %sia
+  %neg = xor <4 x i32> %sext, <i32 -1, i32 -1, i32 -1, i32 -1>
+  %bc2 = bitcast <4 x i32> %neg to <2 x i64>
+  %and2 = and <2 x i64> %bc2, %sib
+  %or = or <2 x i64> %and1, %and2
+  ret <2 x i64> %or
+}
+
+define <2 x i64> @bitcast_select_swap1(<4 x i1> %cmp, <2 x double> %a, <2 x double> %b) {
+; CHECK-LABEL: @bitcast_select_swap1(
+; CHECK-NEXT:    [[SIA:%.*]] = fptosi <2 x double> [[A:%.*]] to <2 x i64>
+; CHECK-NEXT:    [[SIB:%.*]] = fptosi <2 x double> [[B:%.*]] to <2 x i64>
+; CHECK-NEXT:    [[TMP1:%.*]] = bitcast <2 x i64> [[SIA]] to <4 x i32>
+; CHECK-NEXT:    [[TMP2:%.*]] = bitcast <2 x i64> [[SIB]] to <4 x i32>
+; CHECK-NEXT:    [[TMP3:%.*]] = select <4 x i1> [[CMP:%.*]], <4 x i32> [[TMP1]], <4 x i32> [[TMP2]]
+; CHECK-NEXT:    [[TMP4:%.*]] = bitcast <4 x i32> [[TMP3]] to <2 x i64>
+; CHECK-NEXT:    ret <2 x i64> [[TMP4]]
+;
+  %sia = fptosi <2 x double> %a to <2 x i64>
+  %sib = fptosi <2 x double> %b to <2 x i64>
+  %sext = sext <4 x i1> %cmp to <4 x i32>
+  %bc1 = bitcast <4 x i32> %sext to <2 x i64>
+  %and1 = and <2 x i64> %bc1, %sia
+  %neg = xor <4 x i32> %sext, <i32 -1, i32 -1, i32 -1, i32 -1>
+  %bc2 = bitcast <4 x i32> %neg to <2 x i64>
+  %and2 = and <2 x i64> %bc2, %sib
+  %or = or <2 x i64> %and2, %and1
+  ret <2 x i64> %or
+}
+
+define <2 x i64> @bitcast_select_swap2(<4 x i1> %cmp, <2 x double> %a, <2 x double> %b) {
+; CHECK-LABEL: @bitcast_select_swap2(
+; CHECK-NEXT:    [[SIA:%.*]] = fptosi <2 x double> [[A:%.*]] to <2 x i64>
+; CHECK-NEXT:    [[SIB:%.*]] = fptosi <2 x double> [[B:%.*]] to <2 x i64>
+; CHECK-NEXT:    [[TMP1:%.*]] = bitcast <2 x i64> [[SIA]] to <4 x i32>
+; CHECK-NEXT:    [[TMP2:%.*]] = bitcast <2 x i64> [[SIB]] to <4 x i32>
+; CHECK-NEXT:    [[TMP3:%.*]] = select <4 x i1> [[CMP:%.*]], <4 x i32> [[TMP1]], <4 x i32> [[TMP2]]
+; CHECK-NEXT:    [[TMP4:%.*]] = bitcast <4 x i32> [[TMP3]] to <2 x i64>
+; CHECK-NEXT:    ret <2 x i64> [[TMP4]]
+;
+  %sia = fptosi <2 x double> %a to <2 x i64>
+  %sib = fptosi <2 x double> %b to <2 x i64>
+  %sext = sext <4 x i1> %cmp to <4 x i32>
+  %bc1 = bitcast <4 x i32> %sext to <2 x i64>
+  %and1 = and <2 x i64> %bc1, %sia
+  %neg = xor <4 x i32> %sext, <i32 -1, i32 -1, i32 -1, i32 -1>
+  %bc2 = bitcast <4 x i32> %neg to <2 x i64>
+  %and2 = and <2 x i64> %sib, %bc2
+  %or = or <2 x i64> %and1, %and2
+  ret <2 x i64> %or
+}
+
+define <2 x i64> @bitcast_select_swap3(<4 x i1> %cmp, <2 x double> %a, <2 x double> %b) {
+; CHECK-LABEL: @bitcast_select_swap3(
+; CHECK-NEXT:    [[SIA:%.*]] = fptosi <2 x double> [[A:%.*]] to <2 x i64>
+; CHECK-NEXT:    [[SIB:%.*]] = fptosi <2 x double> [[B:%.*]] to <2 x i64>
+; CHECK-NEXT:    [[TMP1:%.*]] = bitcast <2 x i64> [[SIA]] to <4 x i32>
+; CHECK-NEXT:    [[TMP2:%.*]] = bitcast <2 x i64> [[SIB]] to <4 x i32>
+; CHECK-NEXT:    [[TMP3:%.*]] = select <4 x i1> [[CMP:%.*]], <4 x i32> [[TMP1]], <4 x i32> [[TMP2]]
+; CHECK-NEXT:    [[TMP4:%.*]] = bitcast <4 x i32> [[TMP3]] to <2 x i64>
+; CHECK-NEXT:    ret <2 x i64> [[TMP4]]
+;
+  %sia = fptosi <2 x double> %a to <2 x i64>
+  %sib = fptosi <2 x double> %b to <2 x i64>
+  %sext = sext <4 x i1> %cmp to <4 x i32>
+  %bc1 = bitcast <4 x i32> %sext to <2 x i64>
+  %and1 = and <2 x i64> %bc1, %sia
+  %neg = xor <4 x i32> %sext, <i32 -1, i32 -1, i32 -1, i32 -1>
+  %bc2 = bitcast <4 x i32> %neg to <2 x i64>
+  %and2 = and <2 x i64> %sib, %bc2
+  %or = or <2 x i64> %and2, %and1
+  ret <2 x i64> %or
+}
+
+define <2 x i64> @bitcast_select_swap4(<4 x i1> %cmp, <2 x double> %a, <2 x double> %b) {
+; CHECK-LABEL: @bitcast_select_swap4(
+; CHECK-NEXT:    [[SIA:%.*]] = fptosi <2 x double> [[A:%.*]] to <2 x i64>
+; CHECK-NEXT:    [[SIB:%.*]] = fptosi <2 x double> [[B:%.*]] to <2 x i64>
+; CHECK-NEXT:    [[TMP1:%.*]] = bitcast <2 x i64> [[SIA]] to <4 x i32>
+; CHECK-NEXT:    [[TMP2:%.*]] = bitcast <2 x i64> [[SIB]] to <4 x i32>
+; CHECK-NEXT:    [[TMP3:%.*]] = select <4 x i1> [[CMP:%.*]], <4 x i32> [[TMP1]], <4 x i32> [[TMP2]]
+; CHECK-NEXT:    [[TMP4:%.*]] = bitcast <4 x i32> [[TMP3]] to <2 x i64>
+; CHECK-NEXT:    ret <2 x i64> [[TMP4]]
+;
+  %sia = fptosi <2 x double> %a to <2 x i64>
+  %sib = fptosi <2 x double> %b to <2 x i64>
+  %sext = sext <4 x i1> %cmp to <4 x i32>
+  %bc1 = bitcast <4 x i32> %sext to <2 x i64>
+  %and1 = and <2 x i64> %sia, %bc1
+  %neg = xor <4 x i32> %sext, <i32 -1, i32 -1, i32 -1, i32 -1>
+  %bc2 = bitcast <4 x i32> %neg to <2 x i64>
+  %and2 = and <2 x i64> %bc2, %sib
+  %or = or <2 x i64> %and1, %and2
+  ret <2 x i64> %or
+}
+
+define <2 x i64> @bitcast_select_swap5(<4 x i1> %cmp, <2 x double> %a, <2 x double> %b) {
+; CHECK-LABEL: @bitcast_select_swap5(
+; CHECK-NEXT:    [[SIA:%.*]] = fptosi <2 x double> [[A:%.*]] to <2 x i64>
+; CHECK-NEXT:    [[SIB:%.*]] = fptosi <2 x double> [[B:%.*]] to <2 x i64>
+; CHECK-NEXT:    [[TMP1:%.*]] = bitcast <2 x i64> [[SIA]] to <4 x i32>
+; CHECK-NEXT:    [[TMP2:%.*]] = bitcast <2 x i64> [[SIB]] to <4 x i32>
+; CHECK-NEXT:    [[TMP3:%.*]] = select <4 x i1> [[CMP:%.*]], <4 x i32> [[TMP1]], <4 x i32> [[TMP2]]
+; CHECK-NEXT:    [[TMP4:%.*]] = bitcast <4 x i32> [[TMP3]] to <2 x i64>
+; CHECK-NEXT:    ret <2 x i64> [[TMP4]]
+;
+  %sia = fptosi <2 x double> %a to <2 x i64>
+  %sib = fptosi <2 x double> %b to <2 x i64>
+  %sext = sext <4 x i1> %cmp to <4 x i32>
+  %bc1 = bitcast <4 x i32> %sext to <2 x i64>
+  %and1 = and <2 x i64> %sia, %bc1
+  %neg = xor <4 x i32> %sext, <i32 -1, i32 -1, i32 -1, i32 -1>
+  %bc2 = bitcast <4 x i32> %neg to <2 x i64>
+  %and2 = and <2 x i64> %bc2, %sib
+  %or = or <2 x i64> %and2, %and1
+  ret <2 x i64> %or
+}
+
+define <2 x i64> @bitcast_select_swap6(<4 x i1> %cmp, <2 x double> %a, <2 x double> %b) {
+; CHECK-LABEL: @bitcast_select_swap6(
+; CHECK-NEXT:    [[SIA:%.*]] = fptosi <2 x double> [[A:%.*]] to <2 x i64>
+; CHECK-NEXT:    [[SIB:%.*]] = fptosi <2 x double> [[B:%.*]] to <2 x i64>
+; CHECK-NEXT:    [[TMP1:%.*]] = bitcast <2 x i64> [[SIA]] to <4 x i32>
+; CHECK-NEXT:    [[TMP2:%.*]] = bitcast <2 x i64> [[SIB]] to <4 x i32>
+; CHECK-NEXT:    [[TMP3:%.*]] = select <4 x i1> [[CMP:%.*]], <4 x i32> [[TMP1]], <4 x i32> [[TMP2]]
+; CHECK-NEXT:    [[TMP4:%.*]] = bitcast <4 x i32> [[TMP3]] to <2 x i64>
+; CHECK-NEXT:    ret <2 x i64> [[TMP4]]
+;
+  %sia = fptosi <2 x double> %a to <2 x i64>
+  %sib = fptosi <2 x double> %b to <2 x i64>
+  %sext = sext <4 x i1> %cmp to <4 x i32>
+  %bc1 = bitcast <4 x i32> %sext to <2 x i64>
+  %and1 = and <2 x i64> %sia, %bc1
+  %neg = xor <4 x i32> %sext, <i32 -1, i32 -1, i32 -1, i32 -1>
+  %bc2 = bitcast <4 x i32> %neg to <2 x i64>
+  %and2 = and <2 x i64> %sib, %bc2
+  %or = or <2 x i64> %and1, %and2
+  ret <2 x i64> %or
+}
+
+define <2 x i64> @bitcast_select_swap7(<4 x i1> %cmp, <2 x double> %a, <2 x double> %b) {
+; CHECK-LABEL: @bitcast_select_swap7(
+; CHECK-NEXT:    [[SIA:%.*]] = fptosi <2 x double> [[A:%.*]] to <2 x i64>
+; CHECK-NEXT:    [[SIB:%.*]] = fptosi <2 x double> [[B:%.*]] to <2 x i64>
+; CHECK-NEXT:    [[TMP1:%.*]] = bitcast <2 x i64> [[SIA]] to <4 x i32>
+; CHECK-NEXT:    [[TMP2:%.*]] = bitcast <2 x i64> [[SIB]] to <4 x i32>
+; CHECK-NEXT:    [[TMP3:%.*]] = select <4 x i1> [[CMP:%.*]], <4 x i32> [[TMP1]], <4 x i32> [[TMP2]]
+; CHECK-NEXT:    [[TMP4:%.*]] = bitcast <4 x i32> [[TMP3]] to <2 x i64>
+; CHECK-NEXT:    ret <2 x i64> [[TMP4]]
+;
+  %sia = fptosi <2 x double> %a to <2 x i64>
+  %sib = fptosi <2 x double> %b to <2 x i64>
+  %sext = sext <4 x i1> %cmp to <4 x i32>
+  %bc1 = bitcast <4 x i32> %sext to <2 x i64>
+  %and1 = and <2 x i64> %sia, %bc1
+  %neg = xor <4 x i32> %sext, <i32 -1, i32 -1, i32 -1, i32 -1>
+  %bc2 = bitcast <4 x i32> %neg to <2 x i64>
+  %and2 = and <2 x i64> %sib, %bc2
+  %or = or <2 x i64> %and2, %and1
+  ret <2 x i64> %or
+}
+
+define <2 x i64> @bitcast_select_multi_uses(<4 x i1> %cmp, <2 x i64> %a, <2 x i64> %b) {
+; CHECK-LABEL: @bitcast_select_multi_uses(
+; CHECK-NEXT:    [[SEXT:%.*]] = sext <4 x i1> [[CMP:%.*]] to <4 x i32>
+; CHECK-NEXT:    [[BC1:%.*]] = bitcast <4 x i32> [[SEXT]] to <2 x i64>
+; CHECK-NEXT:    [[AND1:%.*]] = and <2 x i64> [[BC1]], [[A:%.*]]
+; CHECK-NEXT:    [[TMP1:%.*]] = bitcast <4 x i32> [[SEXT]] to <2 x i64>
+; CHECK-NEXT:    [[BC2:%.*]] = xor <2 x i64> [[TMP1]], <i64 -1, i64 -1>
+; CHECK-NEXT:    [[AND2:%.*]] = and <2 x i64> [[BC2]], [[B:%.*]]
+; CHECK-NEXT:    [[OR:%.*]] = or <2 x i64> [[AND2]], [[AND1]]
+; CHECK-NEXT:    [[ADD:%.*]] = add <2 x i64> [[AND2]], [[BC2]]
+; CHECK-NEXT:    [[SUB:%.*]] = sub <2 x i64> [[OR]], [[ADD]]
+; CHECK-NEXT:    ret <2 x i64> [[SUB]]
+;
+  %sext = sext <4 x i1> %cmp to <4 x i32>
+  %bc1 = bitcast <4 x i32> %sext to <2 x i64>
+  %and1 = and <2 x i64> %a, %bc1
+  %neg = xor <4 x i32> %sext, <i32 -1, i32 -1, i32 -1, i32 -1>
+  %bc2 = bitcast <4 x i32> %neg to <2 x i64>
+  %and2 = and <2 x i64> %b, %bc2
+  %or = or <2 x i64> %and2, %and1
+  %add = add <2 x i64> %and2, %bc2
+  %sub = sub <2 x i64> %or, %add
+  ret <2 x i64> %sub
+}
+
+define i1 @bools(i1 %a, i1 %b, i1 %c) {
+; CHECK-LABEL: @bools(
+; CHECK-NEXT:    [[TMP1:%.*]] = select i1 [[C:%.*]], i1 [[B:%.*]], i1 [[A:%.*]]
+; CHECK-NEXT:    ret i1 [[TMP1]]
+;
+  %not = xor i1 %c, -1
+  %and1 = and i1 %not, %a
+  %and2 = and i1 %c, %b
+  %or = or i1 %and1, %and2
+  ret i1 %or
+}
+
+; Form a select if we know we can get replace 2 simple logic ops.
+
+define i1 @bools_multi_uses1(i1 %a, i1 %b, i1 %c) {
+; CHECK-LABEL: @bools_multi_uses1(
+; CHECK-NEXT:    [[NOT:%.*]] = xor i1 [[C:%.*]], true
+; CHECK-NEXT:    [[AND1:%.*]] = and i1 [[NOT]], [[A:%.*]]
+; CHECK-NEXT:    [[TMP1:%.*]] = select i1 [[C]], i1 [[B:%.*]], i1 [[A]]
+; CHECK-NEXT:    [[XOR:%.*]] = xor i1 [[TMP1]], [[AND1]]
+; CHECK-NEXT:    ret i1 [[XOR]]
+;
+  %not = xor i1 %c, -1
+  %and1 = and i1 %not, %a
+  %and2 = and i1 %c, %b
+  %or = or i1 %and1, %and2
+  %xor = xor i1 %or, %and1
+  ret i1 %xor
+}
+
+; Don't replace a cheap logic op with a potentially expensive select
+; unless we can also eliminate one of the other original ops.
+
+define i1 @bools_multi_uses2(i1 %a, i1 %b, i1 %c) {
+; CHECK-LABEL: @bools_multi_uses2(
+; CHECK-NEXT:    [[TMP1:%.*]] = select i1 [[C:%.*]], i1 [[B:%.*]], i1 [[A:%.*]]
+; CHECK-NEXT:    ret i1 [[TMP1]]
+;
+  %not = xor i1 %c, -1
+  %and1 = and i1 %not, %a
+  %and2 = and i1 %c, %b
+  %or = or i1 %and1, %and2
+  %add = add i1 %and1, %and2
+  %and3 = and i1 %or, %add
+  ret i1 %and3
+}
+
+define <4 x i1> @vec_of_bools(<4 x i1> %a, <4 x i1> %b, <4 x i1> %c) {
+; CHECK-LABEL: @vec_of_bools(
+; CHECK-NEXT:    [[TMP1:%.*]] = select <4 x i1> [[C:%.*]], <4 x i1> [[B:%.*]], <4 x i1> [[A:%.*]]
+; CHECK-NEXT:    ret <4 x i1> [[TMP1]]
+;
+  %not = xor <4 x i1> %c, <i1 true, i1 true, i1 true, i1 true>
+  %and1 = and <4 x i1> %not, %a
+  %and2 = and <4 x i1> %b, %c
+  %or = or <4 x i1> %and2, %and1
+  ret <4 x i1> %or
+}
+
+define i4 @vec_of_casted_bools(i4 %a, i4 %b, <4 x i1> %c) {
+; CHECK-LABEL: @vec_of_casted_bools(
+; CHECK-NEXT:    [[TMP1:%.*]] = bitcast i4 [[A:%.*]] to <4 x i1>
+; CHECK-NEXT:    [[TMP2:%.*]] = bitcast i4 [[B:%.*]] to <4 x i1>
+; CHECK-NEXT:    [[TMP3:%.*]] = select <4 x i1> [[C:%.*]], <4 x i1> [[TMP2]], <4 x i1> [[TMP1]]
+; CHECK-NEXT:    [[TMP4:%.*]] = bitcast <4 x i1> [[TMP3]] to i4
+; CHECK-NEXT:    ret i4 [[TMP4]]
+;
+  %not = xor <4 x i1> %c, <i1 true, i1 true, i1 true, i1 true>
+  %bc1 = bitcast <4 x i1> %not to i4
+  %bc2 = bitcast <4 x i1> %c to i4
+  %and1 = and i4 %a, %bc1
+  %and2 = and i4 %bc2, %b
+  %or = or i4 %and1, %and2
+  ret i4 %or
+}
+
+; Inverted 'and' constants mean this is a select which is canonicalized to a shuffle.
+
+define <4 x i32> @vec_sel_consts(<4 x i32> %a, <4 x i32> %b) {
+; CHECK-LABEL: @vec_sel_consts(
+; CHECK-NEXT:    [[TMP1:%.*]] = shufflevector <4 x i32> [[A:%.*]], <4 x i32> [[B:%.*]], <4 x i32> <i32 0, i32 5, i32 6, i32 3>
+; CHECK-NEXT:    ret <4 x i32> [[TMP1]]
+;
+  %and1 = and <4 x i32> %a, <i32 -1, i32 0, i32 0, i32 -1>
+  %and2 = and <4 x i32> %b, <i32 0, i32 -1, i32 -1, i32 0>
+  %or = or <4 x i32> %and1, %and2
+  ret <4 x i32> %or
+}
+
+define <3 x i129> @vec_sel_consts_weird(<3 x i129> %a, <3 x i129> %b) {
+; CHECK-LABEL: @vec_sel_consts_weird(
+; CHECK-NEXT:    [[TMP1:%.*]] = shufflevector <3 x i129> [[A:%.*]], <3 x i129> [[B:%.*]], <3 x i32> <i32 0, i32 4, i32 2>
+; CHECK-NEXT:    ret <3 x i129> [[TMP1]]
+;
+  %and1 = and <3 x i129> %a, <i129 -1, i129 0, i129 -1>
+  %and2 = and <3 x i129> %b, <i129 0, i129 -1, i129 0>
+  %or = or <3 x i129> %and2, %and1
+  ret <3 x i129> %or
+}
+
+; The mask elements must be inverted for this to be a select.
+
+define <4 x i32> @vec_not_sel_consts(<4 x i32> %a, <4 x i32> %b) {
+; CHECK-LABEL: @vec_not_sel_consts(
+; CHECK-NEXT:    [[AND1:%.*]] = and <4 x i32> [[A:%.*]], <i32 -1, i32 0, i32 0, i32 0>
+; CHECK-NEXT:    [[AND2:%.*]] = and <4 x i32> [[B:%.*]], <i32 0, i32 -1, i32 0, i32 -1>
+; CHECK-NEXT:    [[OR:%.*]] = or <4 x i32> [[AND1]], [[AND2]]
+; CHECK-NEXT:    ret <4 x i32> [[OR]]
+;
+  %and1 = and <4 x i32> %a, <i32 -1, i32 0, i32 0, i32 0>
+  %and2 = and <4 x i32> %b, <i32 0, i32 -1, i32 0, i32 -1>
+  %or = or <4 x i32> %and1, %and2
+  ret <4 x i32> %or
+}
+
+define <4 x i32> @vec_not_sel_consts_undef_elts(<4 x i32> %a, <4 x i32> %b) {
+; CHECK-LABEL: @vec_not_sel_consts_undef_elts(
+; CHECK-NEXT:    [[AND1:%.*]] = and <4 x i32> [[A:%.*]], <i32 -1, i32 undef, i32 0, i32 0>
+; CHECK-NEXT:    [[AND2:%.*]] = and <4 x i32> [[B:%.*]], <i32 0, i32 -1, i32 0, i32 undef>
+; CHECK-NEXT:    [[OR:%.*]] = or <4 x i32> [[AND1]], [[AND2]]
+; CHECK-NEXT:    ret <4 x i32> [[OR]]
+;
+  %and1 = and <4 x i32> %a, <i32 -1, i32 undef, i32 0, i32 0>
+  %and2 = and <4 x i32> %b, <i32 0, i32 -1, i32 0, i32 undef>
+  %or = or <4 x i32> %and1, %and2
+  ret <4 x i32> %or
+}
+
+; The inverted constants may be operands of xor instructions.
+
+define <4 x i32> @vec_sel_xor(<4 x i32> %a, <4 x i32> %b, <4 x i1> %c) {
+; CHECK-LABEL: @vec_sel_xor(
+; CHECK-NEXT:    [[TMP1:%.*]] = xor <4 x i1> [[C:%.*]], <i1 false, i1 true, i1 true, i1 true>
+; CHECK-NEXT:    [[TMP2:%.*]] = select <4 x i1> [[TMP1]], <4 x i32> [[A:%.*]], <4 x i32> [[B:%.*]]
+; CHECK-NEXT:    ret <4 x i32> [[TMP2]]
+;
+  %mask = sext <4 x i1> %c to <4 x i32>
+  %mask_flip1 = xor <4 x i32> %mask, <i32 -1, i32 0, i32 0, i32 0>
+  %not_mask_flip1 = xor <4 x i32> %mask, <i32 0, i32 -1, i32 -1, i32 -1>
+  %and1 = and <4 x i32> %not_mask_flip1, %a
+  %and2 = and <4 x i32> %mask_flip1, %b
+  %or = or <4 x i32> %and1, %and2
+  ret <4 x i32> %or
+}
+
+; Allow the transform even if the mask values have multiple uses because
+; there's still a net reduction of instructions from removing the and/and/or.
+
+define <4 x i32> @vec_sel_xor_multi_use(<4 x i32> %a, <4 x i32> %b, <4 x i1> %c) {
+; CHECK-LABEL: @vec_sel_xor_multi_use(
+; CHECK-NEXT:    [[TMP1:%.*]] = xor <4 x i1> [[C:%.*]], <i1 true, i1 false, i1 false, i1 false>
+; CHECK-NEXT:    [[TMP2:%.*]] = xor <4 x i1> [[C]], <i1 false, i1 true, i1 true, i1 true>
+; CHECK-NEXT:    [[TMP3:%.*]] = select <4 x i1> [[TMP2]], <4 x i32> [[A:%.*]], <4 x i32> [[B:%.*]]
+; CHECK-NEXT:    [[TMP4:%.*]] = zext <4 x i1> [[TMP1]] to <4 x i32>
+; CHECK-NEXT:    [[ADD:%.*]] = sub <4 x i32> [[TMP3]], [[TMP4]]
+; CHECK-NEXT:    ret <4 x i32> [[ADD]]
+;
+  %mask = sext <4 x i1> %c to <4 x i32>
+  %mask_flip1 = xor <4 x i32> %mask, <i32 -1, i32 0, i32 0, i32 0>
+  %not_mask_flip1 = xor <4 x i32> %mask, <i32 0, i32 -1, i32 -1, i32 -1>
+  %and1 = and <4 x i32> %not_mask_flip1, %a
+  %and2 = and <4 x i32> %mask_flip1, %b
+  %or = or <4 x i32> %and1, %and2
+  %add = add <4 x i32> %or, %mask_flip1
+  ret <4 x i32> %add
+}
+
+; The 'ashr' guarantees that we have a bitmask, so this is select with truncated condition.
+
+define i32 @allSignBits(i32 %cond, i32 %tval, i32 %fval) {
+; CHECK-LABEL: @allSignBits(
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp slt i32 [[COND:%.*]], 0
+; CHECK-NEXT:    [[TMP2:%.*]] = select i1 [[TMP1]], i32 [[TVAL:%.*]], i32 [[FVAL:%.*]]
+; CHECK-NEXT:    ret i32 [[TMP2]]
+;
+  %bitmask = ashr i32 %cond, 31
+  %not_bitmask = xor i32 %bitmask, -1
+  %a1 = and i32 %tval, %bitmask
+  %a2 = and i32 %not_bitmask, %fval
+  %sel = or i32 %a1, %a2
+  ret i32 %sel
+}
+
+define <4 x i8> @allSignBits_vec(<4 x i8> %cond, <4 x i8> %tval, <4 x i8> %fval) {
+; CHECK-LABEL: @allSignBits_vec(
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp sgt <4 x i8> [[COND:%.*]], <i8 -1, i8 -1, i8 -1, i8 -1>
+; CHECK-NEXT:    [[TMP2:%.*]] = select <4 x i1> [[TMP1]], <4 x i8> [[FVAL:%.*]], <4 x i8> [[TVAL:%.*]]
+; CHECK-NEXT:    ret <4 x i8> [[TMP2]]
+;
+  %bitmask = ashr <4 x i8> %cond, <i8 7, i8 7, i8 7, i8 7>
+  %not_bitmask = xor <4 x i8> %bitmask, <i8 -1, i8 -1, i8 -1, i8 -1>
+  %a1 = and <4 x i8> %tval, %bitmask
+  %a2 = and <4 x i8> %fval, %not_bitmask
+  %sel = or <4 x i8> %a2, %a1
+  ret <4 x i8> %sel
+}
+
+; Negative test - make sure that bitcasts from FP do not cause a crash.
+
+define <2 x i64> @fp_bitcast(<4 x i1> %cmp, <2 x double> %a, <2 x double> %b) {
+; CHECK-LABEL: @fp_bitcast(
+; CHECK-NEXT:    [[SIA:%.*]] = fptosi <2 x double> [[A:%.*]] to <2 x i64>
+; CHECK-NEXT:    [[SIB:%.*]] = fptosi <2 x double> [[B:%.*]] to <2 x i64>
+; CHECK-NEXT:    [[BC1:%.*]] = bitcast <2 x double> [[A]] to <2 x i64>
+; CHECK-NEXT:    [[AND1:%.*]] = and <2 x i64> [[SIA]], [[BC1]]
+; CHECK-NEXT:    [[BC2:%.*]] = bitcast <2 x double> [[B]] to <2 x i64>
+; CHECK-NEXT:    [[AND2:%.*]] = and <2 x i64> [[SIB]], [[BC2]]
+; CHECK-NEXT:    [[OR:%.*]] = or <2 x i64> [[AND2]], [[AND1]]
+; CHECK-NEXT:    ret <2 x i64> [[OR]]
+;
+  %sia = fptosi <2 x double> %a to <2 x i64>
+  %sib = fptosi <2 x double> %b to <2 x i64>
+  %bc1 = bitcast <2 x double> %a to <2 x i64>
+  %and1 = and <2 x i64> %sia, %bc1
+  %bc2 = bitcast <2 x double> %b to <2 x i64>
+  %and2 = and <2 x i64> %sib, %bc2
+  %or = or <2 x i64> %and2, %and1
+  ret <2 x i64> %or
+}
+
+define <4 x i32> @computesignbits_through_shuffles(<4 x float> %x, <4 x float> %y, <4 x float> %z) {
+; CHECK-LABEL: @computesignbits_through_shuffles(
+; CHECK-NEXT:    [[CMP:%.*]] = fcmp ole <4 x float> [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    [[SEXT:%.*]] = sext <4 x i1> [[CMP]] to <4 x i32>
+; CHECK-NEXT:    [[S1:%.*]] = shufflevector <4 x i32> [[SEXT]], <4 x i32> undef, <4 x i32> <i32 0, i32 0, i32 1, i32 1>
+; CHECK-NEXT:    [[S2:%.*]] = shufflevector <4 x i32> [[SEXT]], <4 x i32> undef, <4 x i32> <i32 2, i32 2, i32 3, i32 3>
+; CHECK-NEXT:    [[SHUF_OR1:%.*]] = or <4 x i32> [[S1]], [[S2]]
+; CHECK-NEXT:    [[S3:%.*]] = shufflevector <4 x i32> [[SHUF_OR1]], <4 x i32> undef, <4 x i32> <i32 0, i32 0, i32 1, i32 1>
+; CHECK-NEXT:    [[S4:%.*]] = shufflevector <4 x i32> [[SHUF_OR1]], <4 x i32> undef, <4 x i32> <i32 2, i32 2, i32 3, i32 3>
+; CHECK-NEXT:    [[SHUF_OR2:%.*]] = or <4 x i32> [[S3]], [[S4]]
+; CHECK-NEXT:    [[TMP1:%.*]] = trunc <4 x i32> [[SHUF_OR2]] to <4 x i1>
+; CHECK-NEXT:    [[DOTV:%.*]] = select <4 x i1> [[TMP1]], <4 x float> [[Z:%.*]], <4 x float> [[X]]
+; CHECK-NEXT:    [[TMP2:%.*]] = bitcast <4 x float> [[DOTV]] to <4 x i32>
+; CHECK-NEXT:    ret <4 x i32> [[TMP2]]
+;
+  %cmp = fcmp ole <4 x float> %x, %y
+  %sext = sext <4 x i1> %cmp to <4 x i32>
+  %s1 = shufflevector <4 x i32> %sext, <4 x i32> undef, <4 x i32> <i32 0, i32 0, i32 1, i32 1>
+  %s2 = shufflevector <4 x i32> %sext, <4 x i32> undef, <4 x i32> <i32 2, i32 2, i32 3, i32 3>
+  %shuf_or1 = or <4 x i32> %s1, %s2
+  %s3 = shufflevector <4 x i32> %shuf_or1, <4 x i32> undef, <4 x i32> <i32 0, i32 0, i32 1, i32 1>
+  %s4 = shufflevector <4 x i32> %shuf_or1, <4 x i32> undef, <4 x i32> <i32 2, i32 2, i32 3, i32 3>
+  %shuf_or2 = or <4 x i32> %s3, %s4
+  %not_or2 = xor <4 x i32> %shuf_or2, <i32 -1, i32 -1, i32 -1, i32 -1>
+  %xbc = bitcast <4 x float> %x to <4 x i32>
+  %zbc = bitcast <4 x float> %z to <4 x i32>
+  %and1 = and <4 x i32> %not_or2, %xbc
+  %and2 = and <4 x i32> %shuf_or2, %zbc
+  %sel = or <4 x i32> %and1, %and2
+  ret <4 x i32> %sel
+}
+
+define <4 x i32> @computesignbits_through_two_input_shuffle(<4 x i32> %x, <4 x i32> %y, <4 x i1> %cond1, <4 x i1> %cond2) {
+; CHECK-LABEL: @computesignbits_through_two_input_shuffle(
+; CHECK-NEXT:    [[SEXT1:%.*]] = sext <4 x i1> [[COND1:%.*]] to <4 x i32>
+; CHECK-NEXT:    [[SEXT2:%.*]] = sext <4 x i1> [[COND2:%.*]] to <4 x i32>
+; CHECK-NEXT:    [[COND:%.*]] = shufflevector <4 x i32> [[SEXT1]], <4 x i32> [[SEXT2]], <4 x i32> <i32 0, i32 2, i32 4, i32 6>
+; CHECK-NEXT:    [[TMP1:%.*]] = trunc <4 x i32> [[COND]] to <4 x i1>
+; CHECK-NEXT:    [[TMP2:%.*]] = select <4 x i1> [[TMP1]], <4 x i32> [[Y:%.*]], <4 x i32> [[X:%.*]]
+; CHECK-NEXT:    ret <4 x i32> [[TMP2]]
+;
+  %sext1 = sext <4 x i1> %cond1 to <4 x i32>
+  %sext2 = sext <4 x i1> %cond2 to <4 x i32>
+  %cond = shufflevector <4 x i32> %sext1, <4 x i32> %sext2, <4 x i32> <i32 0, i32 2, i32 4, i32 6>
+  %notcond = xor <4 x i32> %cond, <i32 -1, i32 -1, i32 -1, i32 -1>
+  %and1 = and <4 x i32> %notcond, %x
+  %and2 = and <4 x i32> %cond, %y
+  %sel = or <4 x i32> %and1, %and2
+  ret <4 x i32> %sel
+}
+

Added: llvm/trunk/test/Transforms/InstCombine/lower-dbg-declare.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/lower-dbg-declare.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/lower-dbg-declare.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/lower-dbg-declare.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,183 @@
+; RUN: opt -instcombine < %s -S | FileCheck %s
+
+; This tests dbg.declare lowering for CallInst users of an alloca. The
+; resulting dbg.value expressions should add a deref to the declare's expression.
+
+; Hand-reduced from this example (-g -Og -fsanitize=address):
+
+;   static volatile int sink;
+;   struct OneElementVector {
+;     int Element;
+;     OneElementVector(int Element) : Element(Element) { sink = Element; }
+;     bool empty() const { return false; }
+;   };
+;   using container = OneElementVector;
+;   static void escape(container &c) { sink = c.Element; }
+;   int main() {
+;     container d1 = {42};
+;     while (!d1.empty())
+;       escape(d1);
+;     return 0;
+;   }
+
+target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-apple-macosx10.13.0"
+
+%struct.OneElementVector = type { i32 }
+
+define i1 @escape(%struct.OneElementVector* %d1) {
+  ret i1 false
+}
+
+; CHECK-LABEL: @main
+define i32 @main() !dbg !15 {
+entry:
+  %d1 = alloca %struct.OneElementVector, align 4
+  %0 = bitcast %struct.OneElementVector* %d1 to i8*, !dbg !34
+
+; CHECK: dbg.value(metadata %struct.OneElementVector* [[var:%.*]], metadata !DIExpression(DW_OP_deref))
+; CHECK-NEXT: call i1 @escape
+  call void @llvm.dbg.declare(metadata %struct.OneElementVector* %d1, metadata !19, metadata !DIExpression()), !dbg !35
+  call i1 @escape(%struct.OneElementVector* %d1)
+  br label %while.cond, !dbg !37
+
+while.cond:                                       ; preds = %while.body, %entry
+; CHECK: dbg.value(metadata %struct.OneElementVector* [[var]], metadata !DIExpression(DW_OP_deref))
+; CHECK-NEXT: call i1 @escape
+  %call = call i1 @escape(%struct.OneElementVector* %d1), !dbg !38
+  %lnot = xor i1 %call, true, !dbg !39
+  br i1 %lnot, label %while.body, label %while.end, !dbg !37
+
+while.body:                                       ; preds = %while.cond
+; CHECK: dbg.value(metadata %struct.OneElementVector* [[var]], metadata !DIExpression(DW_OP_deref))
+; CHECK-NEXT: call i1 @escape
+  call i1 @escape(%struct.OneElementVector* %d1)
+  br label %while.cond, !dbg !37, !llvm.loop !42
+
+while.end:                                        ; preds = %while.cond
+  ret i32 0, !dbg !45
+}
+
+; CHECK-LABEL: @main2
+define i32 @main2() {
+entry:
+  %d1 = alloca %struct.OneElementVector, align 4
+  %0 = bitcast %struct.OneElementVector* %d1 to i8*, !dbg !34
+
+; CHECK: dbg.value(metadata %struct.OneElementVector* [[var:%.*]], metadata !DIExpression(DW_OP_lit0, DW_OP_mul, DW_OP_deref))
+; CHECK-NEXT: call i1 @escape
+  call void @llvm.dbg.declare(metadata %struct.OneElementVector* %d1, metadata !19, metadata !DIExpression(DW_OP_lit0, DW_OP_mul)), !dbg !35
+  call i1 @escape(%struct.OneElementVector* %d1)
+  br label %while.cond, !dbg !37
+
+while.cond:                                       ; preds = %while.body, %entry
+; CHECK: dbg.value(metadata %struct.OneElementVector* [[var]], metadata !DIExpression(DW_OP_lit0, DW_OP_mul, DW_OP_deref))
+; CHECK-NEXT: call i1 @escape
+  %call = call i1 @escape(%struct.OneElementVector* %d1), !dbg !38
+  %lnot = xor i1 %call, true, !dbg !39
+  br i1 %lnot, label %while.body, label %while.end, !dbg !37
+
+while.body:                                       ; preds = %while.cond
+; CHECK: dbg.value(metadata %struct.OneElementVector* [[var]], metadata !DIExpression(DW_OP_lit0, DW_OP_mul, DW_OP_deref))
+; CHECK-NEXT: call i1 @escape
+  call i1 @escape(%struct.OneElementVector* %d1)
+  br label %while.cond, !dbg !37, !llvm.loop !42
+
+while.end:                                        ; preds = %while.cond
+  ret i32 0, !dbg !45
+}
+
+declare void @llvm.dbg.declare(metadata, metadata, metadata)
+
+!llvm.dbg.cu = !{!2}
+!llvm.asan.globals = !{!8}
+!llvm.module.flags = !{!10, !11, !12, !13}
+!llvm.ident = !{!14}
+
+!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression())
+!1 = distinct !DIGlobalVariable(name: "sink", linkageName: "_ZL4sink", scope: !2, file: !3, line: 1, type: !6, isLocal: true, isDefinition: true)
+!2 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !3, producer: "clang version 7.0.0 (trunk 337207) (llvm/trunk 337204)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !5)
+!3 = !DIFile(filename: "test.cc", directory: "/Users/vsk/src/builds/llvm.org-master-RA")
+!4 = !{}
+!5 = !{!0}
+!6 = !DIDerivedType(tag: DW_TAG_volatile_type, baseType: !7)
+!7 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!8 = !{}
+!9 = !{!"test.cc", i32 1, i32 21}
+!10 = !{i32 2, !"Dwarf Version", i32 4}
+!11 = !{i32 2, !"Debug Info Version", i32 3}
+!12 = !{i32 1, !"wchar_size", i32 4}
+!13 = !{i32 7, !"PIC Level", i32 2}
+!14 = !{!"clang version 7.0.0 (trunk 337207) (llvm/trunk 337204)"}
+!15 = distinct !DISubprogram(name: "main", scope: !3, file: !3, line: 18, type: !16, isLocal: false, isDefinition: true, scopeLine: 18, flags: DIFlagPrototyped, isOptimized: true, unit: !2, retainedNodes: !18)
+!16 = !DISubroutineType(types: !17)
+!17 = !{!7}
+!18 = !{!19}
+!19 = !DILocalVariable(name: "d1", scope: !15, file: !3, line: 21, type: !20)
+!20 = !DIDerivedType(tag: DW_TAG_typedef, name: "container", file: !3, line: 12, baseType: !21)
+!21 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "OneElementVector", file: !3, line: 3, size: 32, flags: DIFlagTypePassByValue, elements: !22, identifier: "_ZTS16OneElementVector")
+!22 = !{!23, !24, !28}
+!23 = !DIDerivedType(tag: DW_TAG_member, name: "Element", scope: !21, file: !3, line: 4, baseType: !7, size: 32)
+!24 = !DISubprogram(name: "OneElementVector", scope: !21, file: !3, line: 6, type: !25, isLocal: false, isDefinition: false, scopeLine: 6, flags: DIFlagPrototyped, isOptimized: true)
+!25 = !DISubroutineType(types: !26)
+!26 = !{null, !27, !7}
+!27 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !21, size: 64, flags: DIFlagArtificial | DIFlagObjectPointer)
+!28 = !DISubprogram(name: "empty", linkageName: "_ZNK16OneElementVector5emptyEv", scope: !21, file: !3, line: 8, type: !29, isLocal: false, isDefinition: false, scopeLine: 8, flags: DIFlagPrototyped, isOptimized: true)
+!29 = !DISubroutineType(types: !30)
+!30 = !{!31, !32}
+!31 = !DIBasicType(name: "bool", size: 8, encoding: DW_ATE_boolean)
+!32 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !33, size: 64, flags: DIFlagArtificial | DIFlagObjectPointer)
+!33 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !21)
+!34 = !DILocation(line: 21, column: 3, scope: !15)
+!35 = !DILocation(line: 21, column: 13, scope: !15)
+!36 = !DILocation(line: 21, column: 18, scope: !15)
+!37 = !DILocation(line: 22, column: 3, scope: !15)
+!38 = !DILocation(line: 22, column: 14, scope: !15)
+!39 = !DILocation(line: 22, column: 10, scope: !15)
+!40 = !DILocation(line: 23, column: 5, scope: !41)
+!41 = distinct !DILexicalBlock(scope: !15, file: !3, line: 22, column: 23)
+!42 = distinct !{!42, !37, !43}
+!43 = !DILocation(line: 24, column: 3, scope: !15)
+!44 = !DILocation(line: 26, column: 1, scope: !15)
+!45 = !DILocation(line: 25, column: 3, scope: !15)
+!46 = distinct !DISubprogram(name: "OneElementVector", linkageName: "_ZN16OneElementVectorC1Ei", scope: !21, file: !3, line: 6, type: !25, isLocal: false, isDefinition: true, scopeLine: 6, flags: DIFlagPrototyped, isOptimized: true, unit: !2, declaration: !24, retainedNodes: !47)
+!47 = !{!48, !50}
+!48 = !DILocalVariable(name: "this", arg: 1, scope: !46, type: !49, flags: DIFlagArtificial | DIFlagObjectPointer)
+!49 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !21, size: 64)
+!50 = !DILocalVariable(name: "Element", arg: 2, scope: !46, file: !3, line: 6, type: !7)
+!51 = !DILocation(line: 0, scope: !46)
+!52 = !DILocation(line: 6, column: 24, scope: !46)
+!53 = !DILocation(line: 6, column: 52, scope: !46)
+!54 = !DILocation(line: 6, column: 70, scope: !46)
+!55 = distinct !DISubprogram(name: "empty", linkageName: "_ZNK16OneElementVector5emptyEv", scope: !21, file: !3, line: 8, type: !29, isLocal: false, isDefinition: true, scopeLine: 8, flags: DIFlagPrototyped, isOptimized: true, unit: !2, declaration: !28, retainedNodes: !56)
+!56 = !{!57}
+!57 = !DILocalVariable(name: "this", arg: 1, scope: !55, type: !58, flags: DIFlagArtificial | DIFlagObjectPointer)
+!58 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !33, size: 64)
+!59 = !DILocation(line: 0, scope: !55)
+!60 = !DILocation(line: 8, column: 24, scope: !55)
+!61 = distinct !DISubprogram(name: "escape", linkageName: "_ZL6escapeR16OneElementVector", scope: !3, file: !3, line: 14, type: !62, isLocal: true, isDefinition: true, scopeLine: 14, flags: DIFlagPrototyped, isOptimized: true, unit: !2, retainedNodes: !65)
+!62 = !DISubroutineType(types: !63)
+!63 = !{null, !64}
+!64 = !DIDerivedType(tag: DW_TAG_reference_type, baseType: !20, size: 64)
+!65 = !{!66}
+!66 = !DILocalVariable(name: "c", arg: 1, scope: !61, file: !3, line: 14, type: !64)
+!67 = !DILocation(line: 14, column: 31, scope: !61)
+!68 = !DILocation(line: 15, column: 12, scope: !61)
+!69 = !{!70, !71, i64 0}
+!70 = !{!"_ZTS16OneElementVector", !71, i64 0}
+!71 = !{!"int", !72, i64 0}
+!72 = !{!"omnipotent char", !73, i64 0}
+!73 = !{!"Simple C++ TBAA"}
+!74 = !DILocation(line: 15, column: 8, scope: !61)
+!75 = !{!71, !71, i64 0}
+!76 = !DILocation(line: 16, column: 1, scope: !61)
+!77 = distinct !DISubprogram(name: "OneElementVector", linkageName: "_ZN16OneElementVectorC2Ei", scope: !21, file: !3, line: 6, type: !25, isLocal: false, isDefinition: true, scopeLine: 6, flags: DIFlagPrototyped, isOptimized: true, unit: !2, declaration: !24, retainedNodes: !78)
+!78 = !{!79, !80}
+!79 = !DILocalVariable(name: "this", arg: 1, scope: !77, type: !49, flags: DIFlagArtificial | DIFlagObjectPointer)
+!80 = !DILocalVariable(name: "Element", arg: 2, scope: !77, file: !3, line: 6, type: !7)
+!81 = !DILocation(line: 0, scope: !77)
+!82 = !DILocation(line: 6, column: 24, scope: !77)
+!83 = !DILocation(line: 6, column: 35, scope: !77)
+!84 = !DILocation(line: 6, column: 59, scope: !85)
+!85 = distinct !DILexicalBlock(scope: !77, file: !3, line: 6, column: 52)
+!86 = !DILocation(line: 6, column: 70, scope: !77)

Added: llvm/trunk/test/Transforms/InstCombine/lshr-phi.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/lshr-phi.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/lshr-phi.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/lshr-phi.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,57 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt < %s -instcombine -S | FileCheck %s
+
+; Instcombine should be able to eliminate the lshr, because only
+; bits in the operand which might be non-zero will be shifted
+; off the end.
+
+define i32 @hash_string(i8* nocapture %key) nounwind readonly {
+; CHECK-LABEL: @hash_string(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[T0:%.*]] = load i8, i8* [[KEY:%.*]], align 1
+; CHECK-NEXT:    [[T1:%.*]] = icmp eq i8 [[T0]], 0
+; CHECK-NEXT:    br i1 [[T1]], label [[BB2:%.*]], label [[BB:%.*]]
+; CHECK:       bb:
+; CHECK-NEXT:    [[INDVAR:%.*]] = phi i64 [ 0, [[ENTRY:%.*]] ], [ [[T:%.*]], [[BB]] ]
+; CHECK-NEXT:    [[K_04:%.*]] = phi i32 [ 0, [[ENTRY]] ], [ [[T8:%.*]], [[BB]] ]
+; CHECK-NEXT:    [[CP_05:%.*]] = getelementptr i8, i8* [[KEY]], i64 [[INDVAR]]
+; CHECK-NEXT:    [[T2:%.*]] = shl nuw nsw i32 [[K_04]], 1
+; CHECK-NEXT:    [[T5:%.*]] = load i8, i8* [[CP_05]], align 1
+; CHECK-NEXT:    [[T6:%.*]] = sext i8 [[T5]] to i32
+; CHECK-NEXT:    [[T7:%.*]] = xor i32 [[T2]], [[T6]]
+; CHECK-NEXT:    [[T8]] = and i32 [[T7]], 16383
+; CHECK-NEXT:    [[T]] = add i64 [[INDVAR]], 1
+; CHECK-NEXT:    [[SCEVGEP:%.*]] = getelementptr i8, i8* [[KEY]], i64 [[T]]
+; CHECK-NEXT:    [[T9:%.*]] = load i8, i8* [[SCEVGEP]], align 1
+; CHECK-NEXT:    [[T10:%.*]] = icmp eq i8 [[T9]], 0
+; CHECK-NEXT:    br i1 [[T10]], label [[BB2]], label [[BB]]
+; CHECK:       bb2:
+; CHECK-NEXT:    [[K_0_LCSSA:%.*]] = phi i32 [ 0, [[ENTRY]] ], [ [[T8]], [[BB]] ]
+; CHECK-NEXT:    ret i32 [[K_0_LCSSA]]
+;
+entry:
+  %t0 = load i8, i8* %key, align 1
+  %t1 = icmp eq i8 %t0, 0
+  br i1 %t1, label %bb2, label %bb
+
+bb:
+  %indvar = phi i64 [ 0, %entry ], [ %t, %bb ]
+  %k.04 = phi i32 [ 0, %entry ], [ %t8, %bb ]
+  %cp.05 = getelementptr i8, i8* %key, i64 %indvar
+  %t2 = shl i32 %k.04, 1
+  %t3 = lshr i32 %k.04, 14
+  %t4 = add i32 %t2, %t3
+  %t5 = load i8, i8* %cp.05, align 1
+  %t6 = sext i8 %t5 to i32
+  %t7 = xor i32 %t6, %t4
+  %t8 = and i32 %t7, 16383
+  %t = add i64 %indvar, 1
+  %scevgep = getelementptr i8, i8* %key, i64 %t
+  %t9 = load i8, i8* %scevgep, align 1
+  %t10 = icmp eq i8 %t9, 0
+  br i1 %t10, label %bb2, label %bb
+
+bb2:
+  %k.0.lcssa = phi i32 [ 0, %entry ], [ %t8, %bb ]
+  ret i32 %k.0.lcssa
+}

Added: llvm/trunk/test/Transforms/InstCombine/lshr.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/lshr.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/lshr.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/lshr.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,205 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt -instcombine -S < %s | FileCheck %s
+
+target datalayout = "e-m:e-i64:64-n8:16:32:64"
+
+declare i32 @llvm.cttz.i32(i32, i1) nounwind readnone
+declare i32 @llvm.ctlz.i32(i32, i1) nounwind readnone
+declare i32 @llvm.ctpop.i32(i32) 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
+declare <2 x i8> @llvm.ctpop.v2i8(<2 x i8>) nounwind readnone
+
+define i32 @lshr_ctlz_zero_is_not_undef(i32 %x) {
+; CHECK-LABEL: @lshr_ctlz_zero_is_not_undef(
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp eq i32 %x, 0
+; CHECK-NEXT:    [[SH:%.*]] = zext i1 [[TMP1]] to i32
+; CHECK-NEXT:    ret i32 [[SH]]
+;
+  %ct = call i32 @llvm.ctlz.i32(i32 %x, i1 false)
+  %sh = lshr i32 %ct, 5
+  ret i32 %sh
+}
+
+define i32 @lshr_cttz_zero_is_not_undef(i32 %x) {
+; CHECK-LABEL: @lshr_cttz_zero_is_not_undef(
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp eq i32 %x, 0
+; CHECK-NEXT:    [[SH:%.*]] = zext i1 [[TMP1]] to i32
+; CHECK-NEXT:    ret i32 [[SH]]
+;
+  %ct = call i32 @llvm.cttz.i32(i32 %x, i1 false)
+  %sh = lshr i32 %ct, 5
+  ret i32 %sh
+}
+
+define i32 @lshr_ctpop(i32 %x) {
+; CHECK-LABEL: @lshr_ctpop(
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp eq i32 %x, -1
+; CHECK-NEXT:    [[SH:%.*]] = zext i1 [[TMP1]] to i32
+; CHECK-NEXT:    ret i32 [[SH]]
+;
+  %ct = call i32 @llvm.ctpop.i32(i32 %x)
+  %sh = lshr i32 %ct, 5
+  ret i32 %sh
+}
+
+define <2 x i8> @lshr_ctlz_zero_is_not_undef_splat_vec(<2 x i8> %x) {
+; CHECK-LABEL: @lshr_ctlz_zero_is_not_undef_splat_vec(
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp eq <2 x i8> %x, zeroinitializer
+; CHECK-NEXT:    [[SH:%.*]] = zext <2 x i1> [[TMP1]] to <2 x i8>
+; CHECK-NEXT:    ret <2 x i8> [[SH]]
+;
+  %ct = call <2 x i8> @llvm.ctlz.v2i8(<2 x i8> %x, i1 false)
+  %sh = lshr <2 x i8> %ct, <i8 3, i8 3>
+  ret <2 x i8> %sh
+}
+
+define <2 x i8> @lshr_cttz_zero_is_not_undef_splat_vec(<2 x i8> %x) {
+; CHECK-LABEL: @lshr_cttz_zero_is_not_undef_splat_vec(
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp eq <2 x i8> %x, zeroinitializer
+; CHECK-NEXT:    [[SH:%.*]] = zext <2 x i1> [[TMP1]] to <2 x i8>
+; CHECK-NEXT:    ret <2 x i8> [[SH]]
+;
+  %ct = call <2 x i8> @llvm.cttz.v2i8(<2 x i8> %x, i1 false)
+  %sh = lshr <2 x i8> %ct, <i8 3, i8 3>
+  ret <2 x i8> %sh
+}
+
+define <2 x i8> @lshr_ctpop_splat_vec(<2 x i8> %x) {
+; CHECK-LABEL: @lshr_ctpop_splat_vec(
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp eq <2 x i8> %x, <i8 -1, i8 -1>
+; CHECK-NEXT:    [[SH:%.*]] = zext <2 x i1> [[TMP1]] to <2 x i8>
+; CHECK-NEXT:    ret <2 x i8> [[SH]]
+;
+  %ct = call <2 x i8> @llvm.ctpop.v2i8(<2 x i8> %x)
+  %sh = lshr <2 x i8> %ct, <i8 3, i8 3>
+  ret <2 x i8> %sh
+}
+
+define i8 @lshr_exact(i8 %x) {
+; CHECK-LABEL: @lshr_exact(
+; CHECK-NEXT:    [[SHL:%.*]] = shl i8 %x, 2
+; CHECK-NEXT:    [[ADD:%.*]] = add i8 [[SHL]], 4
+; CHECK-NEXT:    [[LSHR:%.*]] = lshr exact i8 [[ADD]], 2
+; CHECK-NEXT:    ret i8 [[LSHR]]
+;
+  %shl = shl i8 %x, 2
+  %add = add i8 %shl, 4
+  %lshr = lshr i8 %add, 2
+  ret i8 %lshr
+}
+
+define <2 x i8> @lshr_exact_splat_vec(<2 x i8> %x) {
+; CHECK-LABEL: @lshr_exact_splat_vec(
+; CHECK-NEXT:    [[SHL:%.*]] = shl <2 x i8> %x, <i8 2, i8 2>
+; CHECK-NEXT:    [[ADD:%.*]] = add <2 x i8> [[SHL]], <i8 4, i8 4>
+; CHECK-NEXT:    [[LSHR:%.*]] = lshr exact <2 x i8> [[ADD]], <i8 2, i8 2>
+; CHECK-NEXT:    ret <2 x i8> [[LSHR]]
+;
+  %shl = shl <2 x i8> %x, <i8 2, i8 2>
+  %add = add <2 x i8> %shl, <i8 4, i8 4>
+  %lshr = lshr <2 x i8> %add, <i8 2, i8 2>
+  ret <2 x i8> %lshr
+}
+
+define i16 @bool_zext(i1 %x) {
+; CHECK-LABEL: @bool_zext(
+; CHECK-NEXT:    [[HIBIT:%.*]] = zext i1 %x to i16
+; CHECK-NEXT:    ret i16 [[HIBIT]]
+;
+  %sext = sext i1 %x to i16
+  %hibit = lshr i16 %sext, 15
+  ret i16 %hibit
+}
+
+define <2 x i8> @bool_zext_splat(<2 x i1> %x) {
+; CHECK-LABEL: @bool_zext_splat(
+; CHECK-NEXT:    [[HIBIT:%.*]] = zext <2 x i1> %x to <2 x i8>
+; CHECK-NEXT:    ret <2 x i8> [[HIBIT]]
+;
+  %sext = sext <2 x i1> %x to <2 x i8>
+  %hibit = lshr <2 x i8> %sext, <i8 7, i8 7>
+  ret <2 x i8> %hibit
+}
+
+define i32 @smear_sign_and_widen(i8 %x) {
+; CHECK-LABEL: @smear_sign_and_widen(
+; CHECK-NEXT:    [[TMP1:%.*]] = ashr i8 %x, 7
+; CHECK-NEXT:    [[HIBIT:%.*]] = zext i8 [[TMP1]] to i32
+; CHECK-NEXT:    ret i32 [[HIBIT]]
+;
+  %sext = sext i8 %x to i32
+  %hibit = lshr i32 %sext, 24
+  ret i32 %hibit
+}
+
+define i16 @smear_sign_and_widen_should_not_change_type(i4 %x) {
+; CHECK-LABEL: @smear_sign_and_widen_should_not_change_type(
+; CHECK-NEXT:    [[SEXT:%.*]] = sext i4 %x to i16
+; CHECK-NEXT:    [[HIBIT:%.*]] = lshr i16 [[SEXT]], 12
+; CHECK-NEXT:    ret i16 [[HIBIT]]
+;
+  %sext = sext i4 %x to i16
+  %hibit = lshr i16 %sext, 12
+  ret i16 %hibit
+}
+
+define <2 x i8> @smear_sign_and_widen_splat(<2 x i6> %x) {
+; CHECK-LABEL: @smear_sign_and_widen_splat(
+; CHECK-NEXT:    [[TMP1:%.*]] = ashr <2 x i6> %x, <i6 2, i6 2>
+; CHECK-NEXT:    [[HIBIT:%.*]] = zext <2 x i6> [[TMP1]] to <2 x i8>
+; CHECK-NEXT:    ret <2 x i8> [[HIBIT]]
+;
+  %sext = sext <2 x i6> %x to <2 x i8>
+  %hibit = lshr <2 x i8> %sext, <i8 2, i8 2>
+  ret <2 x i8> %hibit
+}
+
+define i18 @fake_sext(i3 %x) {
+; CHECK-LABEL: @fake_sext(
+; CHECK-NEXT:    [[TMP1:%.*]] = lshr i3 %x, 2
+; CHECK-NEXT:    [[SH:%.*]] = zext i3 [[TMP1]] to i18
+; CHECK-NEXT:    ret i18 [[SH]]
+;
+  %sext = sext i3 %x to i18
+  %sh = lshr i18 %sext, 17
+  ret i18 %sh
+}
+
+; Avoid the transform if it would change the shift from a legal to illegal type.
+
+define i32 @fake_sext_but_should_not_change_type(i3 %x) {
+; CHECK-LABEL: @fake_sext_but_should_not_change_type(
+; CHECK-NEXT:    [[SEXT:%.*]] = sext i3 %x to i32
+; CHECK-NEXT:    [[SH:%.*]] = lshr i32 [[SEXT]], 31
+; CHECK-NEXT:    ret i32 [[SH]]
+;
+  %sext = sext i3 %x to i32
+  %sh = lshr i32 %sext, 31
+  ret i32 %sh
+}
+
+define <2 x i8> @fake_sext_splat(<2 x i3> %x) {
+; CHECK-LABEL: @fake_sext_splat(
+; CHECK-NEXT:    [[TMP1:%.*]] = lshr <2 x i3> %x, <i3 2, i3 2>
+; CHECK-NEXT:    [[SH:%.*]] = zext <2 x i3> [[TMP1]] to <2 x i8>
+; CHECK-NEXT:    ret <2 x i8> [[SH]]
+;
+  %sext = sext <2 x i3> %x to <2 x i8>
+  %sh = lshr <2 x i8> %sext, <i8 7, i8 7>
+  ret <2 x i8> %sh
+}
+
+; Use a narrow shift: lshr (zext iM X to iN), C --> zext (lshr X, C) to iN
+
+define <2 x i32> @narrow_lshr_constant(<2 x i8> %x, <2 x i8> %y) {
+; CHECK-LABEL: @narrow_lshr_constant(
+; CHECK-NEXT:    [[TMP1:%.*]] = lshr <2 x i8> %x, <i8 3, i8 3>
+; CHECK-NEXT:    [[SH:%.*]] = zext <2 x i8> [[TMP1]] to <2 x i32>
+; CHECK-NEXT:    ret <2 x i32> [[SH]]
+;
+  %zx = zext <2 x i8> %x to <2 x i32>
+  %sh = lshr <2 x i32> %zx, <i32 3, i32 3>
+  ret <2 x i32> %sh
+}
+

Added: llvm/trunk/test/Transforms/InstCombine/malloc-free-delete.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/malloc-free-delete.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/malloc-free-delete.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/malloc-free-delete.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,288 @@
+; RUN: opt < %s -instcombine -S | FileCheck %s
+; PR1201
+define i32 @main(i32 %argc, i8** %argv) {
+; CHECK-LABEL: @main(
+    %c_19 = alloca i8*
+    %malloc_206 = tail call i8* @malloc(i32 mul (i32 ptrtoint (i8* getelementptr (i8, i8* null, i32 1) to i32), i32 10))
+    store i8* %malloc_206, i8** %c_19
+    %tmp_207 = load i8*, i8** %c_19
+    tail call void @free(i8* %tmp_207)
+    ret i32 0
+; CHECK-NEXT: ret i32 0
+}
+
+declare noalias i8* @calloc(i32, i32) nounwind
+declare noalias i8* @malloc(i32)
+declare void @free(i8*)
+
+define i1 @foo() {
+; CHECK-LABEL: @foo(
+; CHECK-NEXT: ret i1 false
+  %m = call i8* @malloc(i32 1)
+  %z = icmp eq i8* %m, null
+  call void @free(i8* %m)
+  ret i1 %z
+}
+
+declare void @llvm.lifetime.start.p0i8(i64, i8*)
+declare void @llvm.lifetime.end.p0i8(i64, i8*)
+declare i64 @llvm.objectsize.i64(i8*, i1)
+declare void @llvm.memcpy.p0i8.p0i8.i32(i8* nocapture, i8* nocapture, i32, i1) nounwind
+declare void @llvm.memmove.p0i8.p0i8.i32(i8* nocapture, i8* nocapture, i32, i1) nounwind
+declare void @llvm.memset.p0i8.i32(i8*, i8, i32, i1) nounwind
+
+define void @test3(i8* %src) {
+; CHECK-LABEL: @test3(
+; CHECK-NEXT: ret void
+  %a = call noalias i8* @malloc(i32 10)
+  call void @llvm.lifetime.start.p0i8(i64 10, i8* %a)
+  call void @llvm.lifetime.end.p0i8(i64 10, i8* %a)
+  %size = call i64 @llvm.objectsize.i64(i8* %a, i1 true)
+  store i8 42, i8* %a
+  call void @llvm.memcpy.p0i8.p0i8.i32(i8* %a, i8* %src, i32 32, i1 false)
+  call void @llvm.memmove.p0i8.p0i8.i32(i8* %a, i8* %src, i32 32, i1 false)
+  call void @llvm.memset.p0i8.i32(i8* %a, i8 5, i32 32, i1 false)
+  %alloc2 = call noalias i8* @calloc(i32 5, i32 7) nounwind
+  %z = icmp ne i8* %alloc2, null
+  ret void
+}
+
+;; This used to crash.
+define void @test4() {
+; CHECK-LABEL: @test4(
+; CHECK-NEXT: ret void
+  %A = call i8* @malloc(i32 16000)
+  %B = bitcast i8* %A to double*
+  %C = bitcast double* %B to i8*
+  call void @free(i8* %C)
+  ret void
+}
+
+; CHECK-LABEL: @test5(
+define void @test5(i8* %ptr, i8** %esc) {
+; CHECK-NEXT: call i8* @malloc
+; CHECK-NEXT: call i8* @malloc
+; CHECK-NEXT: call i8* @malloc
+; CHECK-NEXT: call i8* @malloc
+; CHECK-NEXT: call i8* @malloc
+; CHECK-NEXT: call i8* @malloc
+; CHECK-NEXT: call i8* @malloc
+; CHECK-NEXT: call void @llvm.memcpy
+; CHECK-NEXT: call void @llvm.memmove
+; CHECK-NEXT: store
+; CHECK-NEXT: call void @llvm.memcpy
+; CHECK-NEXT: call void @llvm.memmove
+; CHECK-NEXT: call void @llvm.memset
+; CHECK-NEXT: store volatile
+; CHECK-NEXT: ret
+  %a = call i8* @malloc(i32 700)
+  %b = call i8* @malloc(i32 700)
+  %c = call i8* @malloc(i32 700)
+  %d = call i8* @malloc(i32 700)
+  %e = call i8* @malloc(i32 700)
+  %f = call i8* @malloc(i32 700)
+  %g = call i8* @malloc(i32 700)
+  call void @llvm.memcpy.p0i8.p0i8.i32(i8* %ptr, i8* %a, i32 32, i1 false)
+  call void @llvm.memmove.p0i8.p0i8.i32(i8* %ptr, i8* %b, i32 32, i1 false)
+  store i8* %c, i8** %esc
+  call void @llvm.memcpy.p0i8.p0i8.i32(i8* %d, i8* %ptr, i32 32, i1 true)
+  call void @llvm.memmove.p0i8.p0i8.i32(i8* %e, i8* %ptr, i32 32, i1 true)
+  call void @llvm.memset.p0i8.i32(i8* %f, i8 5, i32 32, i1 true)
+  store volatile i8 4, i8* %g
+  ret void
+}
+
+;; When a basic block contains only a call to free and this block is accessed
+;; through a test of the argument of free against null, move the call in the
+;; predecessor block.
+;; Using simplifycfg will remove the empty basic block and the branch operation
+;; Then, performing a dead elimination will remove the comparison.
+;; This is what happens with -O1 and upper.
+; CHECK-LABEL: @test6(
+define void @test6(i8* %foo) minsize {
+; CHECK:  %tobool = icmp eq i8* %foo, null
+;; Call to free moved
+; CHECK-NEXT: tail call void @free(i8* %foo)
+; CHECK-NEXT: br i1 %tobool, label %if.end, label %if.then
+; CHECK: if.then:
+;; Block is now empty and may be simplified by simplifycfg
+; CHECK-NEXT:   br label %if.end
+; CHECK: if.end:
+; CHECK-NEXT:  ret void
+entry:
+  %tobool = icmp eq i8* %foo, null
+  br i1 %tobool, label %if.end, label %if.then
+
+if.then:                                          ; preds = %entry
+  tail call void @free(i8* %foo)
+  br label %if.end
+
+if.end:                                           ; preds = %entry, %if.then
+  ret void
+}
+
+declare i8* @_ZnwmRKSt9nothrow_t(i64, i8*) nobuiltin
+declare void @_ZdlPvRKSt9nothrow_t(i8*, i8*) nobuiltin
+declare i32 @__gxx_personality_v0(...)
+declare void @_ZN1AC2Ev(i8* %this)
+
+; CHECK-LABEL: @test7(
+define void @test7() personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) {
+entry:
+  %nt = alloca i8
+  ; CHECK-NOT: call {{.*}}@_ZnwmRKSt9nothrow_t(
+  %call.i = tail call i8* @_ZnwmRKSt9nothrow_t(i64 1, i8* %nt) builtin nounwind
+  invoke void @_ZN1AC2Ev(i8* undef)
+          to label %.noexc.i unwind label %lpad.i
+
+.noexc.i:                                         ; preds = %entry
+  unreachable
+
+lpad.i:                                           ; preds = %entry
+  %0 = landingpad { i8*, i32 } cleanup
+  ; CHECK-NOT: call {{.*}}@_ZdlPvRKSt9nothrow_t(
+  call void @_ZdlPvRKSt9nothrow_t(i8* %call.i, i8* %nt) builtin nounwind
+  resume { i8*, i32 } %0
+}
+
+declare i8* @_Znwm(i64) nobuiltin
+define i8* @_Znwj(i32 %n) nobuiltin {
+  %z = zext i32 %n to i64
+  %m = call i8* @_Znwm(i64 %z)
+  ret i8* %m
+}
+declare i8* @_Znam(i64) nobuiltin
+declare i8* @_Znaj(i32) nobuiltin
+declare void @_ZdlPv(i8*) nobuiltin
+declare void @_ZdaPv(i8*) nobuiltin
+
+define linkonce void @_ZdlPvm(i8* %p, i64) nobuiltin {
+  call void @_ZdlPv(i8* %p)
+  ret void
+}
+define linkonce void @_ZdlPvj(i8* %p, i32) nobuiltin {
+  call void @_ZdlPv(i8* %p)
+  ret void
+}
+define linkonce void @_ZdaPvm(i8* %p, i64) nobuiltin {
+  call void @_ZdaPv(i8* %p)
+  ret void
+}
+define linkonce void @_ZdaPvj(i8* %p, i32) nobuiltin {
+  call void @_ZdaPv(i8* %p)
+  ret void
+}
+
+
+; new(size_t, align_val_t)
+declare i8* @_ZnwmSt11align_val_t(i64, i64) nobuiltin
+declare i8* @_ZnwjSt11align_val_t(i32, i32) nobuiltin
+; new[](size_t, align_val_t)
+declare i8* @_ZnamSt11align_val_t(i64, i64) nobuiltin
+declare i8* @_ZnajSt11align_val_t(i32, i32) nobuiltin
+; new(size_t, align_val_t, nothrow)
+declare i8* @_ZnwmSt11align_val_tRKSt9nothrow_t(i64, i64, i8*) nobuiltin
+declare i8* @_ZnwjSt11align_val_tRKSt9nothrow_t(i32, i32, i8*) nobuiltin
+; new[](size_t, align_val_t, nothrow)
+declare i8* @_ZnamSt11align_val_tRKSt9nothrow_t(i64, i64, i8*) nobuiltin
+declare i8* @_ZnajSt11align_val_tRKSt9nothrow_t(i32, i32, i8*) nobuiltin
+; delete(void*, align_val_t)
+declare void @_ZdlPvSt11align_val_t(i8*, i64) nobuiltin
+; delete[](void*, align_val_t)
+declare void @_ZdaPvSt11align_val_t(i8*, i64) nobuiltin
+; delete(void*, align_val_t, nothrow)
+declare void @_ZdlPvSt11align_val_tRKSt9nothrow_t(i8*, i64, i8*) nobuiltin
+; delete[](void*, align_val_t, nothrow)
+declare void @_ZdaPvSt11align_val_tRKSt9nothrow_t(i8*, i64, i8*) nobuiltin
+
+
+; CHECK-LABEL: @test8(
+define void @test8() {
+  ; CHECK-NOT: call
+  %nt = alloca i8
+  %nw = call i8* @_Znwm(i64 32) builtin
+  call void @_ZdlPv(i8* %nw) builtin
+  %na = call i8* @_Znam(i64 32) builtin
+  call void @_ZdaPv(i8* %na) builtin
+  %nwm = call i8* @_Znwm(i64 32) builtin
+  call void @_ZdlPvm(i8* %nwm, i64 32) builtin
+  %nwj = call i8* @_Znwj(i32 32) builtin
+  call void @_ZdlPvj(i8* %nwj, i32 32) builtin
+  %nam = call i8* @_Znam(i64 32) builtin
+  call void @_ZdaPvm(i8* %nam, i64 32) builtin
+  %naj = call i8* @_Znaj(i32 32) builtin
+  call void @_ZdaPvj(i8* %naj, i32 32) builtin
+  %nwa = call i8* @_ZnwmSt11align_val_t(i64 32, i64 8) builtin
+  call void @_ZdlPvSt11align_val_t(i8* %nwa, i64 8) builtin
+  %naa = call i8* @_ZnamSt11align_val_t(i64 32, i64 8) builtin
+  call void @_ZdaPvSt11align_val_t(i8* %naa, i64 8) builtin
+  %nwja = call i8* @_ZnwjSt11align_val_t(i32 32, i32 8) builtin
+  call void @_ZdlPvSt11align_val_t(i8* %nwja, i64 8) builtin
+  %naja = call i8* @_ZnajSt11align_val_t(i32 32, i32 8) builtin
+  call void @_ZdaPvSt11align_val_t(i8* %naja, i64 8) builtin
+  %nwat = call i8* @_ZnwmSt11align_val_tRKSt9nothrow_t(i64 32, i64 8, i8* %nt) builtin
+  call void @_ZdlPvSt11align_val_tRKSt9nothrow_t(i8* %nwat, i64 8, i8* %nt) builtin
+  %naat = call i8* @_ZnamSt11align_val_tRKSt9nothrow_t(i64 32, i64 8, i8* %nt) builtin
+  call void @_ZdaPvSt11align_val_tRKSt9nothrow_t(i8* %naat, i64 8, i8* %nt) builtin
+  %nwjat = call i8* @_ZnwjSt11align_val_tRKSt9nothrow_t(i32 32, i32 8, i8* %nt) builtin
+  call void @_ZdlPvSt11align_val_tRKSt9nothrow_t(i8* %nwjat, i64 8, i8* %nt) builtin
+  %najat = call i8* @_ZnajSt11align_val_tRKSt9nothrow_t(i32 32, i32 8, i8* %nt) builtin
+  call void @_ZdaPvSt11align_val_tRKSt9nothrow_t(i8* %najat, i64 8, i8* %nt) builtin
+  ret void
+}
+
+declare noalias i8* @"\01??2 at YAPEAX_K@Z"(i64) nobuiltin
+declare void @"\01??3 at YAXPEAX@Z"(i8*) nobuiltin
+
+; CHECK-LABEL: @test9(
+define void @test9() {
+  ; CHECK-NOT: call
+  %new_long_long = call noalias i8* @"\01??2 at YAPEAX_K@Z"(i64 32) builtin
+  call void @"\01??3 at YAXPEAX@Z"(i8* %new_long_long) builtin
+  ret void
+}
+
+define void @test10()  {
+; CHECK-LABEL: @test10
+; CHECK: call void @_ZdlPv
+  call void @_ZdlPv(i8* null)
+  ret void
+}
+
+define void @test11() {
+; CHECK-LABEL: @test11
+; CHECK: call i8* @_Znwm
+; CHECK: call void @_ZdlPv
+  %call = call i8* @_Znwm(i64 8) builtin
+  call void @_ZdlPv(i8* %call)
+  ret void
+}
+
+;; Check that the optimization that moves a call to free in its predecessor
+;; block (see test6) also happens when noop casts are involved.
+; CHECK-LABEL: @test12(
+define void @test12(i32* %foo) minsize {
+; CHECK:  %tobool = icmp eq i32* %foo, null
+;; Everything before the call to free should have been moved as well.
+; CHECK-NEXT:   %bitcast = bitcast i32* %foo to i8*
+;; Call to free moved
+; CHECK-NEXT: tail call void @free(i8* %bitcast)
+; CHECK-NEXT: br i1 %tobool, label %if.end, label %if.then
+; CHECK: if.then:
+;; Block is now empty and may be simplified by simplifycfg
+; CHECK-NEXT:   br label %if.end
+; CHECK: if.end:
+; CHECK-NEXT:  ret void
+entry:
+  %tobool = icmp eq i32* %foo, null
+  br i1 %tobool, label %if.end, label %if.then
+
+if.then:                                          ; preds = %entry
+  %bitcast = bitcast i32* %foo to i8*
+  tail call void @free(i8* %bitcast)
+  br label %if.end
+
+if.end:                                           ; preds = %entry, %if.then
+  ret void
+}
+

Added: llvm/trunk/test/Transforms/InstCombine/masked-merge-add.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/masked-merge-add.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/masked-merge-add.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/masked-merge-add.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,415 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt < %s -instcombine -S | FileCheck %s
+
+; https://bugs.llvm.org/show_bug.cgi?id=6773
+
+; Patterns:
+;   (x & m) | (y & ~m)
+;   (x & m) ^ (y & ~m)
+;   (x & m) + (y & ~m)
+; Should be transformed into:
+;   (x & m) | (y & ~m)
+; And then into:
+;   ((x ^ y) & m) ^ y
+
+; ============================================================================ ;
+; Most basic positive tests
+; ============================================================================ ;
+
+define i32 @p(i32 %x, i32 %y, i32 %m) {
+; CHECK-LABEL: @p(
+; CHECK-NEXT:    [[AND:%.*]] = and i32 [[X:%.*]], [[M:%.*]]
+; CHECK-NEXT:    [[NEG:%.*]] = xor i32 [[M]], -1
+; CHECK-NEXT:    [[AND1:%.*]] = and i32 [[NEG]], [[Y:%.*]]
+; CHECK-NEXT:    [[RET:%.*]] = or i32 [[AND]], [[AND1]]
+; CHECK-NEXT:    ret i32 [[RET]]
+;
+  %and = and i32 %x, %m
+  %neg = xor i32 %m, -1
+  %and1 = and i32 %neg, %y
+  %ret = add i32 %and, %and1
+  ret i32 %ret
+}
+
+define <2 x i32> @p_splatvec(<2 x i32> %x, <2 x i32> %y, <2 x i32> %m) {
+; CHECK-LABEL: @p_splatvec(
+; CHECK-NEXT:    [[AND:%.*]] = and <2 x i32> [[X:%.*]], [[M:%.*]]
+; CHECK-NEXT:    [[NEG:%.*]] = xor <2 x i32> [[M]], <i32 -1, i32 -1>
+; CHECK-NEXT:    [[AND1:%.*]] = and <2 x i32> [[NEG]], [[Y:%.*]]
+; CHECK-NEXT:    [[RET:%.*]] = or <2 x i32> [[AND]], [[AND1]]
+; CHECK-NEXT:    ret <2 x i32> [[RET]]
+;
+  %and = and <2 x i32> %x, %m
+  %neg = xor <2 x i32> %m, <i32 -1, i32 -1>
+  %and1 = and <2 x i32> %neg, %y
+  %ret = add <2 x i32> %and, %and1
+  ret <2 x i32> %ret
+}
+
+define <3 x i32> @p_vec_undef(<3 x i32> %x, <3 x i32> %y, <3 x i32> %m) {
+; CHECK-LABEL: @p_vec_undef(
+; CHECK-NEXT:    [[AND:%.*]] = and <3 x i32> [[X:%.*]], [[M:%.*]]
+; CHECK-NEXT:    [[NEG:%.*]] = xor <3 x i32> [[M]], <i32 -1, i32 undef, i32 -1>
+; CHECK-NEXT:    [[AND1:%.*]] = and <3 x i32> [[NEG]], [[Y:%.*]]
+; CHECK-NEXT:    [[RET:%.*]] = or <3 x i32> [[AND]], [[AND1]]
+; CHECK-NEXT:    ret <3 x i32> [[RET]]
+;
+  %and = and <3 x i32> %x, %m
+  %neg = xor <3 x i32> %m, <i32 -1, i32 undef, i32 -1>
+  %and1 = and <3 x i32> %neg, %y
+  %ret = add <3 x i32> %and, %and1
+  ret <3 x i32> %ret
+}
+
+; ============================================================================ ;
+; Constant mask.
+; ============================================================================ ;
+
+define i32 @p_constmask(i32 %x, i32 %y) {
+; CHECK-LABEL: @p_constmask(
+; CHECK-NEXT:    [[AND:%.*]] = and i32 [[X:%.*]], 65280
+; CHECK-NEXT:    [[AND1:%.*]] = and i32 [[Y:%.*]], -65281
+; CHECK-NEXT:    [[RET:%.*]] = or i32 [[AND]], [[AND1]]
+; CHECK-NEXT:    ret i32 [[RET]]
+;
+  %and = and i32 %x, 65280
+  %and1 = and i32 %y, -65281
+  %ret = add i32 %and, %and1
+  ret i32 %ret
+}
+
+define <2 x i32> @p_constmask_splatvec(<2 x i32> %x, <2 x i32> %y) {
+; CHECK-LABEL: @p_constmask_splatvec(
+; CHECK-NEXT:    [[AND:%.*]] = and <2 x i32> [[X:%.*]], <i32 65280, i32 65280>
+; CHECK-NEXT:    [[AND1:%.*]] = and <2 x i32> [[Y:%.*]], <i32 -65281, i32 -65281>
+; CHECK-NEXT:    [[RET:%.*]] = or <2 x i32> [[AND]], [[AND1]]
+; CHECK-NEXT:    ret <2 x i32> [[RET]]
+;
+  %and = and <2 x i32> %x, <i32 65280, i32 65280>
+  %and1 = and <2 x i32> %y, <i32 -65281, i32 -65281>
+  %ret = add <2 x i32> %and, %and1
+  ret <2 x i32> %ret
+}
+
+define <2 x i32> @p_constmask_vec(<2 x i32> %x, <2 x i32> %y) {
+; CHECK-LABEL: @p_constmask_vec(
+; CHECK-NEXT:    [[AND:%.*]] = and <2 x i32> [[X:%.*]], <i32 65280, i32 16776960>
+; CHECK-NEXT:    [[AND1:%.*]] = and <2 x i32> [[Y:%.*]], <i32 -65281, i32 -16776961>
+; CHECK-NEXT:    [[RET:%.*]] = add <2 x i32> [[AND]], [[AND1]]
+; CHECK-NEXT:    ret <2 x i32> [[RET]]
+;
+  %and = and <2 x i32> %x, <i32 65280, i32 16776960>
+  %and1 = and <2 x i32> %y, <i32 -65281, i32 -16776961>
+  %ret = add <2 x i32> %and, %and1
+  ret <2 x i32> %ret
+}
+
+define <3 x i32> @p_constmask_vec_undef(<3 x i32> %x, <3 x i32> %y) {
+; CHECK-LABEL: @p_constmask_vec_undef(
+; CHECK-NEXT:    [[AND:%.*]] = and <3 x i32> [[X:%.*]], <i32 65280, i32 undef, i32 65280>
+; CHECK-NEXT:    [[AND1:%.*]] = and <3 x i32> [[Y:%.*]], <i32 -65281, i32 undef, i32 -65281>
+; CHECK-NEXT:    [[RET:%.*]] = add <3 x i32> [[AND]], [[AND1]]
+; CHECK-NEXT:    ret <3 x i32> [[RET]]
+;
+  %and = and <3 x i32> %x, <i32 65280, i32 undef, i32 65280>
+  %and1 = and <3 x i32> %y, <i32 -65281, i32 undef, i32 -65281>
+  %ret = add <3 x i32> %and, %and1
+  ret <3 x i32> %ret
+}
+
+; ============================================================================ ;
+; Constant mask with no common bits set, but common unset bits.
+; ============================================================================ ;
+
+define i32 @p_constmask2(i32 %x, i32 %y) {
+; CHECK-LABEL: @p_constmask2(
+; CHECK-NEXT:    [[AND:%.*]] = and i32 [[X:%.*]], 61440
+; CHECK-NEXT:    [[AND1:%.*]] = and i32 [[Y:%.*]], -65281
+; CHECK-NEXT:    [[RET:%.*]] = or i32 [[AND]], [[AND1]]
+; CHECK-NEXT:    ret i32 [[RET]]
+;
+  %and = and i32 %x, 61440
+  %and1 = and i32 %y, -65281
+  %ret = add i32 %and, %and1
+  ret i32 %ret
+}
+
+define <2 x i32> @p_constmask2_splatvec(<2 x i32> %x, <2 x i32> %y) {
+; CHECK-LABEL: @p_constmask2_splatvec(
+; CHECK-NEXT:    [[AND:%.*]] = and <2 x i32> [[X:%.*]], <i32 61440, i32 61440>
+; CHECK-NEXT:    [[AND1:%.*]] = and <2 x i32> [[Y:%.*]], <i32 -65281, i32 -65281>
+; CHECK-NEXT:    [[RET:%.*]] = or <2 x i32> [[AND]], [[AND1]]
+; CHECK-NEXT:    ret <2 x i32> [[RET]]
+;
+  %and = and <2 x i32> %x, <i32 61440, i32 61440>
+  %and1 = and <2 x i32> %y, <i32 -65281, i32 -65281>
+  %ret = add <2 x i32> %and, %and1
+  ret <2 x i32> %ret
+}
+
+define <2 x i32> @p_constmask2_vec(<2 x i32> %x, <2 x i32> %y) {
+; CHECK-LABEL: @p_constmask2_vec(
+; CHECK-NEXT:    [[AND:%.*]] = and <2 x i32> [[X:%.*]], <i32 61440, i32 16711680>
+; CHECK-NEXT:    [[AND1:%.*]] = and <2 x i32> [[Y:%.*]], <i32 -65281, i32 -16776961>
+; CHECK-NEXT:    [[RET:%.*]] = add <2 x i32> [[AND]], [[AND1]]
+; CHECK-NEXT:    ret <2 x i32> [[RET]]
+;
+  %and = and <2 x i32> %x, <i32 61440, i32 16711680>
+  %and1 = and <2 x i32> %y, <i32 -65281, i32 -16776961>
+  %ret = add <2 x i32> %and, %and1
+  ret <2 x i32> %ret
+}
+
+define <3 x i32> @p_constmask2_vec_undef(<3 x i32> %x, <3 x i32> %y) {
+; CHECK-LABEL: @p_constmask2_vec_undef(
+; CHECK-NEXT:    [[AND:%.*]] = and <3 x i32> [[X:%.*]], <i32 61440, i32 undef, i32 61440>
+; CHECK-NEXT:    [[AND1:%.*]] = and <3 x i32> [[Y:%.*]], <i32 -65281, i32 undef, i32 -65281>
+; CHECK-NEXT:    [[RET:%.*]] = add <3 x i32> [[AND]], [[AND1]]
+; CHECK-NEXT:    ret <3 x i32> [[RET]]
+;
+  %and = and <3 x i32> %x, <i32 61440, i32 undef, i32 61440>
+  %and1 = and <3 x i32> %y, <i32 -65281, i32 undef, i32 -65281>
+  %ret = add <3 x i32> %and, %and1
+  ret <3 x i32> %ret
+}
+
+; ============================================================================ ;
+; Commutativity.
+; ============================================================================ ;
+
+; Used to make sure that the IR complexity sorting does not interfere.
+declare i32 @gen32()
+
+define i32 @p_commutative0(i32 %x, i32 %y, i32 %m) {
+; CHECK-LABEL: @p_commutative0(
+; CHECK-NEXT:    [[AND:%.*]] = and i32 [[M:%.*]], [[X:%.*]]
+; CHECK-NEXT:    [[NEG:%.*]] = xor i32 [[M]], -1
+; CHECK-NEXT:    [[AND1:%.*]] = and i32 [[NEG]], [[Y:%.*]]
+; CHECK-NEXT:    [[RET:%.*]] = or i32 [[AND]], [[AND1]]
+; CHECK-NEXT:    ret i32 [[RET]]
+;
+  %and = and i32 %m, %x ; swapped order
+  %neg = xor i32 %m, -1
+  %and1 = and i32 %neg, %y
+  %ret = add i32 %and, %and1
+  ret i32 %ret
+}
+
+define i32 @p_commutative1(i32 %x, i32 %m) {
+; CHECK-LABEL: @p_commutative1(
+; CHECK-NEXT:    [[Y:%.*]] = call i32 @gen32()
+; CHECK-NEXT:    [[AND:%.*]] = and i32 [[X:%.*]], [[M:%.*]]
+; CHECK-NEXT:    [[NEG:%.*]] = xor i32 [[M]], -1
+; CHECK-NEXT:    [[AND1:%.*]] = and i32 [[Y]], [[NEG]]
+; CHECK-NEXT:    [[RET:%.*]] = or i32 [[AND]], [[AND1]]
+; CHECK-NEXT:    ret i32 [[RET]]
+;
+  %y = call i32 @gen32()
+  %and = and i32 %x, %m
+  %neg = xor i32 %m, -1
+  %and1 = and i32 %y, %neg; swapped order
+  %ret = add i32 %and, %and1
+  ret i32 %ret
+}
+
+define i32 @p_commutative2(i32 %x, i32 %y, i32 %m) {
+; CHECK-LABEL: @p_commutative2(
+; CHECK-NEXT:    [[AND:%.*]] = and i32 [[X:%.*]], [[M:%.*]]
+; CHECK-NEXT:    [[NEG:%.*]] = xor i32 [[M]], -1
+; CHECK-NEXT:    [[AND1:%.*]] = and i32 [[NEG]], [[Y:%.*]]
+; CHECK-NEXT:    [[RET:%.*]] = or i32 [[AND1]], [[AND]]
+; CHECK-NEXT:    ret i32 [[RET]]
+;
+  %and = and i32 %x, %m
+  %neg = xor i32 %m, -1
+  %and1 = and i32 %neg, %y
+  %ret = add i32 %and1, %and ; swapped order
+  ret i32 %ret
+}
+
+define i32 @p_commutative3(i32 %x, i32 %m) {
+; CHECK-LABEL: @p_commutative3(
+; CHECK-NEXT:    [[Y:%.*]] = call i32 @gen32()
+; CHECK-NEXT:    [[AND:%.*]] = and i32 [[M:%.*]], [[X:%.*]]
+; CHECK-NEXT:    [[NEG:%.*]] = xor i32 [[M]], -1
+; CHECK-NEXT:    [[AND1:%.*]] = and i32 [[Y]], [[NEG]]
+; CHECK-NEXT:    [[RET:%.*]] = or i32 [[AND]], [[AND1]]
+; CHECK-NEXT:    ret i32 [[RET]]
+;
+  %y = call i32 @gen32()
+  %and = and i32 %m, %x ; swapped order
+  %neg = xor i32 %m, -1
+  %and1 = and i32 %y, %neg; swapped order
+  %ret = add i32 %and, %and1
+  ret i32 %ret
+}
+
+define i32 @p_commutative4(i32 %x, i32 %y, i32 %m) {
+; CHECK-LABEL: @p_commutative4(
+; CHECK-NEXT:    [[AND:%.*]] = and i32 [[M:%.*]], [[X:%.*]]
+; CHECK-NEXT:    [[NEG:%.*]] = xor i32 [[M]], -1
+; CHECK-NEXT:    [[AND1:%.*]] = and i32 [[NEG]], [[Y:%.*]]
+; CHECK-NEXT:    [[RET:%.*]] = or i32 [[AND1]], [[AND]]
+; CHECK-NEXT:    ret i32 [[RET]]
+;
+  %and = and i32 %m, %x ; swapped order
+  %neg = xor i32 %m, -1
+  %and1 = and i32 %neg, %y
+  %ret = add i32 %and1, %and ; swapped order
+  ret i32 %ret
+}
+
+define i32 @p_commutative5(i32 %x, i32 %m) {
+; CHECK-LABEL: @p_commutative5(
+; CHECK-NEXT:    [[Y:%.*]] = call i32 @gen32()
+; CHECK-NEXT:    [[AND:%.*]] = and i32 [[X:%.*]], [[M:%.*]]
+; CHECK-NEXT:    [[NEG:%.*]] = xor i32 [[M]], -1
+; CHECK-NEXT:    [[AND1:%.*]] = and i32 [[Y]], [[NEG]]
+; CHECK-NEXT:    [[RET:%.*]] = or i32 [[AND1]], [[AND]]
+; CHECK-NEXT:    ret i32 [[RET]]
+;
+  %y = call i32 @gen32()
+  %and = and i32 %x, %m
+  %neg = xor i32 %m, -1
+  %and1 = and i32 %y, %neg; swapped order
+  %ret = add i32 %and1, %and ; swapped order
+  ret i32 %ret
+}
+
+define i32 @p_commutative6(i32 %x, i32 %m) {
+; CHECK-LABEL: @p_commutative6(
+; CHECK-NEXT:    [[Y:%.*]] = call i32 @gen32()
+; CHECK-NEXT:    [[AND:%.*]] = and i32 [[M:%.*]], [[X:%.*]]
+; CHECK-NEXT:    [[NEG:%.*]] = xor i32 [[M]], -1
+; CHECK-NEXT:    [[AND1:%.*]] = and i32 [[Y]], [[NEG]]
+; CHECK-NEXT:    [[RET:%.*]] = or i32 [[AND1]], [[AND]]
+; CHECK-NEXT:    ret i32 [[RET]]
+;
+  %y = call i32 @gen32()
+  %and = and i32 %m, %x ; swapped order
+  %neg = xor i32 %m, -1
+  %and1 = and i32 %y, %neg; swapped order
+  %ret = add i32 %and1, %and ; swapped order
+  ret i32 %ret
+}
+
+define i32 @p_constmask_commutative(i32 %x, i32 %y) {
+; CHECK-LABEL: @p_constmask_commutative(
+; CHECK-NEXT:    [[AND:%.*]] = and i32 [[X:%.*]], 65280
+; CHECK-NEXT:    [[AND1:%.*]] = and i32 [[Y:%.*]], -65281
+; CHECK-NEXT:    [[RET:%.*]] = or i32 [[AND1]], [[AND]]
+; CHECK-NEXT:    ret i32 [[RET]]
+;
+  %and = and i32 %x, 65280
+  %and1 = and i32 %y, -65281
+  %ret = add i32 %and1, %and ; swapped order
+  ret i32 %ret
+}
+
+; ============================================================================ ;
+; Negative tests. Should not be folded.
+; ============================================================================ ;
+
+; One use only.
+
+declare void @use32(i32)
+
+define i32 @n0_oneuse(i32 %x, i32 %y, i32 %m) {
+; CHECK-LABEL: @n0_oneuse(
+; CHECK-NEXT:    [[AND:%.*]] = and i32 [[X:%.*]], [[M:%.*]]
+; CHECK-NEXT:    [[NEG:%.*]] = xor i32 [[M]], -1
+; CHECK-NEXT:    [[AND1:%.*]] = and i32 [[NEG]], [[Y:%.*]]
+; CHECK-NEXT:    [[RET:%.*]] = or i32 [[AND]], [[AND1]]
+; CHECK-NEXT:    call void @use32(i32 [[AND]])
+; CHECK-NEXT:    call void @use32(i32 [[NEG]])
+; CHECK-NEXT:    call void @use32(i32 [[AND1]])
+; CHECK-NEXT:    ret i32 [[RET]]
+;
+  %and = and i32 %x, %m
+  %neg = xor i32 %m, -1
+  %and1 = and i32 %neg, %y
+  %ret = add i32 %and, %and1
+  call void @use32(i32 %and)
+  call void @use32(i32 %neg)
+  call void @use32(i32 %and1)
+  ret i32 %ret
+}
+
+define i32 @n0_constmask_oneuse(i32 %x, i32 %y) {
+; CHECK-LABEL: @n0_constmask_oneuse(
+; CHECK-NEXT:    [[AND:%.*]] = and i32 [[X:%.*]], 65280
+; CHECK-NEXT:    [[AND1:%.*]] = and i32 [[Y:%.*]], -65281
+; CHECK-NEXT:    [[RET:%.*]] = or i32 [[AND]], [[AND1]]
+; CHECK-NEXT:    call void @use32(i32 [[AND]])
+; CHECK-NEXT:    call void @use32(i32 [[AND1]])
+; CHECK-NEXT:    ret i32 [[RET]]
+;
+  %and = and i32 %x, 65280
+  %and1 = and i32 %y, -65281
+  %ret = add i32 %and, %and1
+  call void @use32(i32 %and)
+  call void @use32(i32 %and1)
+  ret i32 %ret
+}
+
+; Bad xor constant
+
+define i32 @n1_badxor(i32 %x, i32 %y, i32 %m) {
+; CHECK-LABEL: @n1_badxor(
+; CHECK-NEXT:    [[AND:%.*]] = and i32 [[X:%.*]], [[M:%.*]]
+; CHECK-NEXT:    [[NEG:%.*]] = xor i32 [[M]], 1
+; CHECK-NEXT:    [[AND1:%.*]] = and i32 [[NEG]], [[Y:%.*]]
+; CHECK-NEXT:    [[RET:%.*]] = add i32 [[AND]], [[AND1]]
+; CHECK-NEXT:    ret i32 [[RET]]
+;
+  %and = and i32 %x, %m
+  %neg = xor i32 %m, 1 ; not -1
+  %and1 = and i32 %neg, %y
+  %ret = add i32 %and, %and1
+  ret i32 %ret
+}
+
+; Different mask is used
+
+define i32 @n2_badmask(i32 %x, i32 %y, i32 %m1, i32 %m2) {
+; CHECK-LABEL: @n2_badmask(
+; CHECK-NEXT:    [[AND:%.*]] = and i32 [[M1:%.*]], [[X:%.*]]
+; CHECK-NEXT:    [[NEG:%.*]] = xor i32 [[M2:%.*]], -1
+; CHECK-NEXT:    [[AND1:%.*]] = and i32 [[NEG]], [[Y:%.*]]
+; CHECK-NEXT:    [[RET:%.*]] = add i32 [[AND]], [[AND1]]
+; CHECK-NEXT:    ret i32 [[RET]]
+;
+  %and = and i32 %m1, %x
+  %neg = xor i32 %m2, -1 ; different mask, not %m1
+  %and1 = and i32 %neg, %y
+  %ret = add i32 %and, %and1
+  ret i32 %ret
+}
+
+; Different const mask is used
+
+define i32 @n3_constmask_badmask(i32 %x, i32 %y) {
+; CHECK-LABEL: @n3_constmask_badmask(
+; CHECK-NEXT:    [[AND:%.*]] = and i32 [[X:%.*]], 65280
+; CHECK-NEXT:    [[AND1:%.*]] = and i32 [[Y:%.*]], -65280
+; CHECK-NEXT:    [[RET:%.*]] = add i32 [[AND]], [[AND1]]
+; CHECK-NEXT:    ret i32 [[RET]]
+;
+  %and = and i32 %x, 65280
+  %and1 = and i32 %y, -65280 ; not -65281, so they have one common bit set
+  %ret = add i32 %and, %and1
+  ret i32 %ret
+}
+
+define i32 @n3_constmask_samemask(i32 %x, i32 %y) {
+; CHECK-LABEL: @n3_constmask_samemask(
+; CHECK-NEXT:    [[AND:%.*]] = and i32 [[X:%.*]], 65280
+; CHECK-NEXT:    [[AND1:%.*]] = and i32 [[Y:%.*]], 65280
+; CHECK-NEXT:    [[RET:%.*]] = add nuw nsw i32 [[AND]], [[AND1]]
+; CHECK-NEXT:    ret i32 [[RET]]
+;
+  %and = and i32 %x, 65280
+  %and1 = and i32 %y, 65280 ; both masks are the same
+  %ret = add i32 %and, %and1
+  ret i32 %ret
+}

Added: llvm/trunk/test/Transforms/InstCombine/masked-merge-and-of-ors.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/masked-merge-and-of-ors.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/masked-merge-and-of-ors.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/masked-merge-and-of-ors.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,509 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt < %s -instcombine -S | FileCheck %s
+
+; https://bugs.llvm.org/show_bug.cgi?id=6773
+
+; Pattern:
+;   (x | ~m) & (y & m)
+; Should be transformed into:
+;   (x & m) | (y & ~m)
+; And then into:
+;   ((x ^ y) & m) ^ y
+
+; ============================================================================ ;
+; Most basic positive tests
+; ============================================================================ ;
+
+define i32 @p(i32 %x, i32 %y, i32 %m) {
+; CHECK-LABEL: @p(
+; CHECK-NEXT:    [[NEG:%.*]] = xor i32 [[M:%.*]], -1
+; CHECK-NEXT:    [[OR:%.*]] = or i32 [[NEG]], [[X:%.*]]
+; CHECK-NEXT:    [[OR1:%.*]] = or i32 [[Y:%.*]], [[M]]
+; CHECK-NEXT:    [[RET:%.*]] = and i32 [[OR]], [[OR1]]
+; CHECK-NEXT:    ret i32 [[RET]]
+;
+  %neg = xor i32 %m, -1
+  %or = or i32 %neg, %x
+  %or1 = or i32 %y, %m
+  %ret = and i32 %or, %or1
+  ret i32 %ret
+}
+
+define <2 x i32> @p_splatvec(<2 x i32> %x, <2 x i32> %y, <2 x i32> %m) {
+; CHECK-LABEL: @p_splatvec(
+; CHECK-NEXT:    [[NEG:%.*]] = xor <2 x i32> [[M:%.*]], <i32 -1, i32 -1>
+; CHECK-NEXT:    [[OR:%.*]] = or <2 x i32> [[NEG]], [[X:%.*]]
+; CHECK-NEXT:    [[OR1:%.*]] = or <2 x i32> [[Y:%.*]], [[M]]
+; CHECK-NEXT:    [[RET:%.*]] = and <2 x i32> [[OR]], [[OR1]]
+; CHECK-NEXT:    ret <2 x i32> [[RET]]
+;
+  %neg = xor <2 x i32> %m, <i32 -1, i32 -1>
+  %or = or <2 x i32> %neg, %x
+  %or1 = or <2 x i32> %y, %m
+  %ret = and <2 x i32> %or, %or1
+  ret <2 x i32> %ret
+}
+
+define <3 x i32> @p_vec_undef(<3 x i32> %x, <3 x i32> %y, <3 x i32> %m) {
+; CHECK-LABEL: @p_vec_undef(
+; CHECK-NEXT:    [[NEG:%.*]] = xor <3 x i32> [[M:%.*]], <i32 -1, i32 undef, i32 -1>
+; CHECK-NEXT:    [[OR:%.*]] = or <3 x i32> [[NEG]], [[X:%.*]]
+; CHECK-NEXT:    [[OR1:%.*]] = or <3 x i32> [[Y:%.*]], [[M]]
+; CHECK-NEXT:    [[RET:%.*]] = and <3 x i32> [[OR]], [[OR1]]
+; CHECK-NEXT:    ret <3 x i32> [[RET]]
+;
+  %neg = xor <3 x i32> %m, <i32 -1, i32 undef, i32 -1>
+  %or = or <3 x i32> %neg, %x
+  %or1 = or <3 x i32> %y, %m
+  %ret = and <3 x i32> %or, %or1
+  ret <3 x i32> %ret
+}
+
+; ============================================================================ ;
+; Constant mask.
+; ============================================================================ ;
+
+define i32 @p_constmask(i32 %x, i32 %y) {
+; CHECK-LABEL: @p_constmask(
+; CHECK-NEXT:    [[OR:%.*]] = or i32 [[X:%.*]], -65281
+; CHECK-NEXT:    [[OR1:%.*]] = or i32 [[Y:%.*]], 65280
+; CHECK-NEXT:    [[RET:%.*]] = and i32 [[OR]], [[OR1]]
+; CHECK-NEXT:    ret i32 [[RET]]
+;
+  %or = or i32 %x, -65281
+  %or1 = or i32 %y, 65280
+  %ret = and i32 %or, %or1
+  ret i32 %ret
+}
+
+define <2 x i32> @p_constmask_splatvec(<2 x i32> %x, <2 x i32> %y) {
+; CHECK-LABEL: @p_constmask_splatvec(
+; CHECK-NEXT:    [[OR:%.*]] = or <2 x i32> [[X:%.*]], <i32 -65281, i32 -65281>
+; CHECK-NEXT:    [[OR1:%.*]] = or <2 x i32> [[Y:%.*]], <i32 65280, i32 65280>
+; CHECK-NEXT:    [[RET:%.*]] = and <2 x i32> [[OR]], [[OR1]]
+; CHECK-NEXT:    ret <2 x i32> [[RET]]
+;
+  %or = or <2 x i32> %x, <i32 -65281, i32 -65281>
+  %or1 = or <2 x i32> %y, <i32 65280, i32 65280>
+  %ret = and <2 x i32> %or, %or1
+  ret <2 x i32> %ret
+}
+
+define <2 x i32> @p_constmask_vec(<2 x i32> %x, <2 x i32> %y) {
+; CHECK-LABEL: @p_constmask_vec(
+; CHECK-NEXT:    [[OR:%.*]] = or <2 x i32> [[X:%.*]], <i32 -65281, i32 -16776961>
+; CHECK-NEXT:    [[OR1:%.*]] = or <2 x i32> [[Y:%.*]], <i32 65280, i32 16776960>
+; CHECK-NEXT:    [[RET:%.*]] = and <2 x i32> [[OR]], [[OR1]]
+; CHECK-NEXT:    ret <2 x i32> [[RET]]
+;
+  %or = or <2 x i32> %x, <i32 -65281, i32 -16776961>
+  %or1 = or <2 x i32> %y, <i32 65280, i32 16776960>
+  %ret = and <2 x i32> %or, %or1
+  ret <2 x i32> %ret
+}
+
+define <3 x i32> @p_constmask_vec_undef(<3 x i32> %x, <3 x i32> %y) {
+; CHECK-LABEL: @p_constmask_vec_undef(
+; CHECK-NEXT:    [[OR:%.*]] = or <3 x i32> [[X:%.*]], <i32 -65281, i32 undef, i32 -65281>
+; CHECK-NEXT:    [[OR1:%.*]] = or <3 x i32> [[Y:%.*]], <i32 65280, i32 undef, i32 65280>
+; CHECK-NEXT:    [[RET:%.*]] = and <3 x i32> [[OR]], [[OR1]]
+; CHECK-NEXT:    ret <3 x i32> [[RET]]
+;
+  %or = or <3 x i32> %x, <i32 -65281, i32 undef, i32 -65281>
+  %or1 = or <3 x i32> %y, <i32 65280, i32 undef, i32 65280>
+  %ret = and <3 x i32> %or, %or1
+  ret <3 x i32> %ret
+}
+
+; ============================================================================ ;
+; Commutativity.
+; ============================================================================ ;
+
+; Used to make sure that the IR complexity sorting does not interfere.
+declare i32 @gen32()
+
+define i32 @p_commutative0(i32 %x, i32 %y, i32 %m) {
+; CHECK-LABEL: @p_commutative0(
+; CHECK-NEXT:    [[NEG:%.*]] = xor i32 [[M:%.*]], -1
+; CHECK-NEXT:    [[OR:%.*]] = or i32 [[NEG]], [[X:%.*]]
+; CHECK-NEXT:    [[OR1:%.*]] = or i32 [[Y:%.*]], [[M]]
+; CHECK-NEXT:    [[RET:%.*]] = and i32 [[OR]], [[OR1]]
+; CHECK-NEXT:    ret i32 [[RET]]
+;
+  %neg = xor i32 %m, -1
+  %or = or i32 %x, %neg ; swapped order
+  %or1 = or i32 %y, %m
+  %ret = and i32 %or, %or1
+  ret i32 %ret
+}
+
+define i32 @p_commutative1(i32 %x, i32 %m) {
+; CHECK-LABEL: @p_commutative1(
+; CHECK-NEXT:    [[Y:%.*]] = call i32 @gen32()
+; CHECK-NEXT:    [[NEG:%.*]] = xor i32 [[M:%.*]], -1
+; CHECK-NEXT:    [[OR:%.*]] = or i32 [[NEG]], [[X:%.*]]
+; CHECK-NEXT:    [[OR1:%.*]] = or i32 [[Y]], [[M]]
+; CHECK-NEXT:    [[RET:%.*]] = and i32 [[OR]], [[OR1]]
+; CHECK-NEXT:    ret i32 [[RET]]
+;
+  %y = call i32 @gen32()
+  %neg = xor i32 %m, -1
+  %or = or i32 %neg, %x
+  %or1 = or i32 %m, %y; swapped order
+  %ret = and i32 %or, %or1
+  ret i32 %ret
+}
+
+define i32 @p_commutative2(i32 %x, i32 %y, i32 %m) {
+; CHECK-LABEL: @p_commutative2(
+; CHECK-NEXT:    [[NEG:%.*]] = xor i32 [[M:%.*]], -1
+; CHECK-NEXT:    [[OR:%.*]] = or i32 [[NEG]], [[X:%.*]]
+; CHECK-NEXT:    [[OR1:%.*]] = or i32 [[Y:%.*]], [[M]]
+; CHECK-NEXT:    [[RET:%.*]] = and i32 [[OR1]], [[OR]]
+; CHECK-NEXT:    ret i32 [[RET]]
+;
+  %neg = xor i32 %m, -1
+  %or = or i32 %neg, %x
+  %or1 = or i32 %y, %m
+  %ret = and i32 %or1, %or ; swapped order
+  ret i32 %ret
+}
+
+define i32 @p_commutative3(i32 %x, i32 %m) {
+; CHECK-LABEL: @p_commutative3(
+; CHECK-NEXT:    [[Y:%.*]] = call i32 @gen32()
+; CHECK-NEXT:    [[NEG:%.*]] = xor i32 [[M:%.*]], -1
+; CHECK-NEXT:    [[OR:%.*]] = or i32 [[NEG]], [[X:%.*]]
+; CHECK-NEXT:    [[OR1:%.*]] = or i32 [[Y]], [[M]]
+; CHECK-NEXT:    [[RET:%.*]] = and i32 [[OR]], [[OR1]]
+; CHECK-NEXT:    ret i32 [[RET]]
+;
+  %y = call i32 @gen32()
+  %neg = xor i32 %m, -1
+  %or = or i32 %x, %neg ; swapped order
+  %or1 = or i32 %m, %y; swapped order
+  %ret = and i32 %or, %or1
+  ret i32 %ret
+}
+
+define i32 @p_commutative4(i32 %x, i32 %y, i32 %m) {
+; CHECK-LABEL: @p_commutative4(
+; CHECK-NEXT:    [[NEG:%.*]] = xor i32 [[M:%.*]], -1
+; CHECK-NEXT:    [[OR:%.*]] = or i32 [[NEG]], [[X:%.*]]
+; CHECK-NEXT:    [[OR1:%.*]] = or i32 [[Y:%.*]], [[M]]
+; CHECK-NEXT:    [[RET:%.*]] = and i32 [[OR1]], [[OR]]
+; CHECK-NEXT:    ret i32 [[RET]]
+;
+  %neg = xor i32 %m, -1
+  %or = or i32 %x, %neg ; swapped order
+  %or1 = or i32 %y, %m
+  %ret = and i32 %or1, %or ; swapped order
+  ret i32 %ret
+}
+
+define i32 @p_commutative5(i32 %x, i32 %m) {
+; CHECK-LABEL: @p_commutative5(
+; CHECK-NEXT:    [[Y:%.*]] = call i32 @gen32()
+; CHECK-NEXT:    [[NEG:%.*]] = xor i32 [[M:%.*]], -1
+; CHECK-NEXT:    [[OR:%.*]] = or i32 [[NEG]], [[X:%.*]]
+; CHECK-NEXT:    [[OR1:%.*]] = or i32 [[Y]], [[M]]
+; CHECK-NEXT:    [[RET:%.*]] = and i32 [[OR1]], [[OR]]
+; CHECK-NEXT:    ret i32 [[RET]]
+;
+  %y = call i32 @gen32()
+  %neg = xor i32 %m, -1
+  %or = or i32 %neg, %x
+  %or1 = or i32 %m, %y; swapped order
+  %ret = and i32 %or1, %or ; swapped order
+  ret i32 %ret
+}
+
+define i32 @p_commutative6(i32 %x, i32 %m) {
+; CHECK-LABEL: @p_commutative6(
+; CHECK-NEXT:    [[Y:%.*]] = call i32 @gen32()
+; CHECK-NEXT:    [[NEG:%.*]] = xor i32 [[M:%.*]], -1
+; CHECK-NEXT:    [[OR:%.*]] = or i32 [[NEG]], [[X:%.*]]
+; CHECK-NEXT:    [[OR1:%.*]] = or i32 [[Y]], [[M]]
+; CHECK-NEXT:    [[RET:%.*]] = and i32 [[OR1]], [[OR]]
+; CHECK-NEXT:    ret i32 [[RET]]
+;
+  %y = call i32 @gen32()
+  %neg = xor i32 %m, -1
+  %or = or i32 %x, %neg ; swapped order
+  %or1 = or i32 %m, %y; swapped order
+  %ret = and i32 %or1, %or ; swapped order
+  ret i32 %ret
+}
+
+define i32 @p_constmask_commutative(i32 %x, i32 %y) {
+; CHECK-LABEL: @p_constmask_commutative(
+; CHECK-NEXT:    [[OR:%.*]] = or i32 [[X:%.*]], -65281
+; CHECK-NEXT:    [[OR1:%.*]] = or i32 [[Y:%.*]], 65280
+; CHECK-NEXT:    [[RET:%.*]] = and i32 [[OR1]], [[OR]]
+; CHECK-NEXT:    ret i32 [[RET]]
+;
+  %or = or i32 %x, -65281
+  %or1 = or i32 %y, 65280
+  %ret = and i32 %or1, %or ; swapped order
+  ret i32 %ret
+}
+
+; ============================================================================ ;
+; Negative tests. Should not be folded.
+; ============================================================================ ;
+
+; One use only.
+
+declare void @use32(i32)
+
+define i32 @n0_oneuse_of_neg_is_ok_0(i32 %x, i32 %y, i32 %m) {
+; CHECK-LABEL: @n0_oneuse_of_neg_is_ok_0(
+; CHECK-NEXT:    [[NEG:%.*]] = xor i32 [[M:%.*]], -1
+; CHECK-NEXT:    [[OR:%.*]] = or i32 [[NEG]], [[X:%.*]]
+; CHECK-NEXT:    [[OR1:%.*]] = or i32 [[Y:%.*]], [[M]]
+; CHECK-NEXT:    [[RET:%.*]] = and i32 [[OR]], [[OR1]]
+; CHECK-NEXT:    call void @use32(i32 [[NEG]])
+; CHECK-NEXT:    ret i32 [[RET]]
+;
+  %neg = xor i32 %m, -1
+  %or = or i32 %neg, %x
+  %or1 = or i32 %y, %m
+  %ret = and i32 %or, %or1
+  call void @use32(i32 %neg)
+  ret i32 %ret
+}
+
+define i32 @n0_oneuse_1(i32 %x, i32 %y, i32 %m) {
+; CHECK-LABEL: @n0_oneuse_1(
+; CHECK-NEXT:    [[NEG:%.*]] = xor i32 [[M:%.*]], -1
+; CHECK-NEXT:    [[OR:%.*]] = or i32 [[NEG]], [[X:%.*]]
+; CHECK-NEXT:    [[OR1:%.*]] = or i32 [[Y:%.*]], [[M]]
+; CHECK-NEXT:    [[RET:%.*]] = and i32 [[OR]], [[OR1]]
+; CHECK-NEXT:    call void @use32(i32 [[OR]])
+; CHECK-NEXT:    ret i32 [[RET]]
+;
+  %neg = xor i32 %m, -1
+  %or = or i32 %neg, %x
+  %or1 = or i32 %y, %m
+  %ret = and i32 %or, %or1
+  call void @use32(i32 %or)
+  ret i32 %ret
+}
+
+define i32 @n0_oneuse_2(i32 %x, i32 %y, i32 %m) {
+; CHECK-LABEL: @n0_oneuse_2(
+; CHECK-NEXT:    [[NEG:%.*]] = xor i32 [[M:%.*]], -1
+; CHECK-NEXT:    [[OR:%.*]] = or i32 [[NEG]], [[X:%.*]]
+; CHECK-NEXT:    [[OR1:%.*]] = or i32 [[Y:%.*]], [[M]]
+; CHECK-NEXT:    [[RET:%.*]] = and i32 [[OR]], [[OR1]]
+; CHECK-NEXT:    call void @use32(i32 [[OR1]])
+; CHECK-NEXT:    ret i32 [[RET]]
+;
+  %neg = xor i32 %m, -1
+  %or = or i32 %neg, %x
+  %or1 = or i32 %y, %m
+  %ret = and i32 %or, %or1
+  call void @use32(i32 %or1)
+  ret i32 %ret
+}
+
+define i32 @n0_oneuse_3(i32 %x, i32 %y, i32 %m) {
+; CHECK-LABEL: @n0_oneuse_3(
+; CHECK-NEXT:    [[NEG:%.*]] = xor i32 [[M:%.*]], -1
+; CHECK-NEXT:    [[OR:%.*]] = or i32 [[NEG]], [[X:%.*]]
+; CHECK-NEXT:    [[OR1:%.*]] = or i32 [[Y:%.*]], [[M]]
+; CHECK-NEXT:    [[RET:%.*]] = and i32 [[OR]], [[OR1]]
+; CHECK-NEXT:    call void @use32(i32 [[NEG]])
+; CHECK-NEXT:    call void @use32(i32 [[OR]])
+; CHECK-NEXT:    ret i32 [[RET]]
+;
+  %neg = xor i32 %m, -1
+  %or = or i32 %neg, %x
+  %or1 = or i32 %y, %m
+  %ret = and i32 %or, %or1
+  call void @use32(i32 %neg)
+  call void @use32(i32 %or)
+  ret i32 %ret
+}
+
+define i32 @n0_oneuse_4(i32 %x, i32 %y, i32 %m) {
+; CHECK-LABEL: @n0_oneuse_4(
+; CHECK-NEXT:    [[NEG:%.*]] = xor i32 [[M:%.*]], -1
+; CHECK-NEXT:    [[OR:%.*]] = or i32 [[NEG]], [[X:%.*]]
+; CHECK-NEXT:    [[OR1:%.*]] = or i32 [[Y:%.*]], [[M]]
+; CHECK-NEXT:    [[RET:%.*]] = and i32 [[OR]], [[OR1]]
+; CHECK-NEXT:    call void @use32(i32 [[NEG]])
+; CHECK-NEXT:    call void @use32(i32 [[OR1]])
+; CHECK-NEXT:    ret i32 [[RET]]
+;
+  %neg = xor i32 %m, -1
+  %or = or i32 %neg, %x
+  %or1 = or i32 %y, %m
+  %ret = and i32 %or, %or1
+  call void @use32(i32 %neg)
+  call void @use32(i32 %or1)
+  ret i32 %ret
+}
+
+define i32 @n0_oneuse_5(i32 %x, i32 %y, i32 %m) {
+; CHECK-LABEL: @n0_oneuse_5(
+; CHECK-NEXT:    [[NEG:%.*]] = xor i32 [[M:%.*]], -1
+; CHECK-NEXT:    [[OR:%.*]] = or i32 [[NEG]], [[X:%.*]]
+; CHECK-NEXT:    [[OR1:%.*]] = or i32 [[Y:%.*]], [[M]]
+; CHECK-NEXT:    [[RET:%.*]] = and i32 [[OR]], [[OR1]]
+; CHECK-NEXT:    call void @use32(i32 [[NEG]])
+; CHECK-NEXT:    call void @use32(i32 [[OR]])
+; CHECK-NEXT:    call void @use32(i32 [[OR1]])
+; CHECK-NEXT:    ret i32 [[RET]]
+;
+  %neg = xor i32 %m, -1
+  %or = or i32 %neg, %x
+  %or1 = or i32 %y, %m
+  %ret = and i32 %or, %or1
+  call void @use32(i32 %neg)
+  call void @use32(i32 %or)
+  call void @use32(i32 %or1)
+  ret i32 %ret
+}
+
+define i32 @n0_oneuse_6(i32 %x, i32 %y, i32 %m) {
+; CHECK-LABEL: @n0_oneuse_6(
+; CHECK-NEXT:    [[NEG:%.*]] = xor i32 [[M:%.*]], -1
+; CHECK-NEXT:    [[OR:%.*]] = or i32 [[NEG]], [[X:%.*]]
+; CHECK-NEXT:    [[OR1:%.*]] = or i32 [[Y:%.*]], [[M]]
+; CHECK-NEXT:    [[RET:%.*]] = and i32 [[OR]], [[OR1]]
+; CHECK-NEXT:    call void @use32(i32 [[OR]])
+; CHECK-NEXT:    call void @use32(i32 [[OR1]])
+; CHECK-NEXT:    ret i32 [[RET]]
+;
+  %neg = xor i32 %m, -1
+  %or = or i32 %neg, %x
+  %or1 = or i32 %y, %m
+  %ret = and i32 %or, %or1
+  call void @use32(i32 %or)
+  call void @use32(i32 %or1)
+  ret i32 %ret
+}
+
+; One-use with constant mask
+
+define i32 @n0_constmask_oneuse_0(i32 %x, i32 %y) {
+; CHECK-LABEL: @n0_constmask_oneuse_0(
+; CHECK-NEXT:    [[OR:%.*]] = or i32 [[X:%.*]], -65281
+; CHECK-NEXT:    [[OR1:%.*]] = or i32 [[Y:%.*]], 65280
+; CHECK-NEXT:    [[RET:%.*]] = and i32 [[OR]], [[OR1]]
+; CHECK-NEXT:    call void @use32(i32 [[OR]])
+; CHECK-NEXT:    ret i32 [[RET]]
+;
+  %or = or i32 %x, -65281
+  %or1 = or i32 %y, 65280
+  %ret = and i32 %or, %or1
+  call void @use32(i32 %or)
+  ret i32 %ret
+}
+
+define i32 @n0_constmask_oneuse_1(i32 %x, i32 %y) {
+; CHECK-LABEL: @n0_constmask_oneuse_1(
+; CHECK-NEXT:    [[OR:%.*]] = or i32 [[X:%.*]], -65281
+; CHECK-NEXT:    [[OR1:%.*]] = or i32 [[Y:%.*]], 65280
+; CHECK-NEXT:    [[RET:%.*]] = and i32 [[OR]], [[OR1]]
+; CHECK-NEXT:    call void @use32(i32 [[OR1]])
+; CHECK-NEXT:    ret i32 [[RET]]
+;
+  %or = or i32 %x, -65281
+  %or1 = or i32 %y, 65280
+  %ret = and i32 %or, %or1
+  call void @use32(i32 %or1)
+  ret i32 %ret
+}
+
+define i32 @n0_constmask_oneuse_2(i32 %x, i32 %y) {
+; CHECK-LABEL: @n0_constmask_oneuse_2(
+; CHECK-NEXT:    [[OR:%.*]] = or i32 [[X:%.*]], -65281
+; CHECK-NEXT:    [[OR1:%.*]] = or i32 [[Y:%.*]], 65280
+; CHECK-NEXT:    [[RET:%.*]] = and i32 [[OR]], [[OR1]]
+; CHECK-NEXT:    call void @use32(i32 [[OR]])
+; CHECK-NEXT:    call void @use32(i32 [[OR1]])
+; CHECK-NEXT:    ret i32 [[RET]]
+;
+  %or = or i32 %x, -65281
+  %or1 = or i32 %y, 65280
+  %ret = and i32 %or, %or1
+  call void @use32(i32 %or)
+  call void @use32(i32 %or1)
+  ret i32 %ret
+}
+
+; Bad xor constant
+
+define i32 @n1_badxor(i32 %x, i32 %y, i32 %m) {
+; CHECK-LABEL: @n1_badxor(
+; CHECK-NEXT:    [[NEG:%.*]] = xor i32 [[M:%.*]], 1
+; CHECK-NEXT:    [[OR:%.*]] = or i32 [[NEG]], [[X:%.*]]
+; CHECK-NEXT:    [[OR1:%.*]] = or i32 [[Y:%.*]], [[M]]
+; CHECK-NEXT:    [[RET:%.*]] = and i32 [[OR]], [[OR1]]
+; CHECK-NEXT:    ret i32 [[RET]]
+;
+  %neg = xor i32 %m, 1 ; not -1
+  %or = or i32 %neg, %x
+  %or1 = or i32 %y, %m
+  %ret = and i32 %or, %or1
+  ret i32 %ret
+}
+
+; Different mask is used
+
+define i32 @n2_badmask(i32 %x, i32 %y, i32 %m1, i32 %m2) {
+; CHECK-LABEL: @n2_badmask(
+; CHECK-NEXT:    [[NEG:%.*]] = xor i32 [[M2:%.*]], -1
+; CHECK-NEXT:    [[OR:%.*]] = or i32 [[NEG]], [[X:%.*]]
+; CHECK-NEXT:    [[OR1:%.*]] = or i32 [[M1:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    [[RET:%.*]] = and i32 [[OR]], [[OR1]]
+; CHECK-NEXT:    ret i32 [[RET]]
+;
+  %neg = xor i32 %m2, -1 ; different mask, not %m1
+  %or = or i32 %neg, %x
+  %or1 = or i32 %m1, %y
+  %ret = and i32 %or, %or1
+  ret i32 %ret
+}
+
+; Different const mask is used
+
+define i32 @n3_constmask_badmask_set(i32 %x, i32 %y) {
+; CHECK-LABEL: @n3_constmask_badmask_set(
+; CHECK-NEXT:    [[OR:%.*]] = or i32 [[X:%.*]], -65281
+; CHECK-NEXT:    [[OR1:%.*]] = or i32 [[Y:%.*]], 65281
+; CHECK-NEXT:    [[RET:%.*]] = and i32 [[OR]], [[OR1]]
+; CHECK-NEXT:    ret i32 [[RET]]
+;
+  %or = or i32 %x, -65281
+  %or1 = or i32 %y, 65281 ; not 65280, so they have one common bit
+  %ret = and i32 %or, %or1
+  ret i32 %ret
+}
+
+define i32 @n3_constmask_badmask_unset(i32 %x, i32 %y) {
+; CHECK-LABEL: @n3_constmask_badmask_unset(
+; CHECK-NEXT:    [[OR:%.*]] = or i32 [[X:%.*]], -65281
+; CHECK-NEXT:    [[OR1:%.*]] = or i32 [[Y:%.*]], 65024
+; CHECK-NEXT:    [[RET:%.*]] = and i32 [[OR]], [[OR1]]
+; CHECK-NEXT:    ret i32 [[RET]]
+;
+  %or = or i32 %x, -65281
+  %or1 = or i32 %y, 65024 ; not 65280, so they have one common unset bit
+  %ret = and i32 %or, %or1
+  ret i32 %ret
+}
+
+define i32 @n3_constmask_samemask(i32 %x, i32 %y) {
+; CHECK-LABEL: @n3_constmask_samemask(
+; CHECK-NEXT:    [[OR2:%.*]] = and i32 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    [[RET:%.*]] = or i32 [[OR2]], -65281
+; CHECK-NEXT:    ret i32 [[RET]]
+;
+  %or = or i32 %x, -65281
+  %or1 = or i32 %y, -65281 ; both masks are the same
+  %ret = and i32 %or, %or1
+  ret i32 %ret
+}

Added: llvm/trunk/test/Transforms/InstCombine/masked-merge-or.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/masked-merge-or.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/masked-merge-or.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/masked-merge-or.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,414 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt < %s -instcombine -S | FileCheck %s
+
+; https://bugs.llvm.org/show_bug.cgi?id=6773
+
+; Patterns:
+;   (x & m) | (y & ~m)
+;   (x & m) ^ (y & ~m)
+;   (x & m) + (y & ~m)
+; Should be transformed into:
+;   (x & m) | (y & ~m)
+; And then into:
+;   ((x ^ y) & m) ^ y
+
+; ============================================================================ ;
+; Most basic positive tests
+; ============================================================================ ;
+
+define i32 @p(i32 %x, i32 %y, i32 %m) {
+; CHECK-LABEL: @p(
+; CHECK-NEXT:    [[AND:%.*]] = and i32 [[X:%.*]], [[M:%.*]]
+; CHECK-NEXT:    [[NEG:%.*]] = xor i32 [[M]], -1
+; CHECK-NEXT:    [[AND1:%.*]] = and i32 [[NEG]], [[Y:%.*]]
+; CHECK-NEXT:    [[RET:%.*]] = or i32 [[AND]], [[AND1]]
+; CHECK-NEXT:    ret i32 [[RET]]
+;
+  %and = and i32 %x, %m
+  %neg = xor i32 %m, -1
+  %and1 = and i32 %neg, %y
+  %ret = or i32 %and, %and1
+  ret i32 %ret
+}
+
+define <2 x i32> @p_splatvec(<2 x i32> %x, <2 x i32> %y, <2 x i32> %m) {
+; CHECK-LABEL: @p_splatvec(
+; CHECK-NEXT:    [[AND:%.*]] = and <2 x i32> [[X:%.*]], [[M:%.*]]
+; CHECK-NEXT:    [[NEG:%.*]] = xor <2 x i32> [[M]], <i32 -1, i32 -1>
+; CHECK-NEXT:    [[AND1:%.*]] = and <2 x i32> [[NEG]], [[Y:%.*]]
+; CHECK-NEXT:    [[RET:%.*]] = or <2 x i32> [[AND]], [[AND1]]
+; CHECK-NEXT:    ret <2 x i32> [[RET]]
+;
+  %and = and <2 x i32> %x, %m
+  %neg = xor <2 x i32> %m, <i32 -1, i32 -1>
+  %and1 = and <2 x i32> %neg, %y
+  %ret = or <2 x i32> %and, %and1
+  ret <2 x i32> %ret
+}
+
+define <3 x i32> @p_vec_undef(<3 x i32> %x, <3 x i32> %y, <3 x i32> %m) {
+; CHECK-LABEL: @p_vec_undef(
+; CHECK-NEXT:    [[AND:%.*]] = and <3 x i32> [[X:%.*]], [[M:%.*]]
+; CHECK-NEXT:    [[NEG:%.*]] = xor <3 x i32> [[M]], <i32 -1, i32 undef, i32 -1>
+; CHECK-NEXT:    [[AND1:%.*]] = and <3 x i32> [[NEG]], [[Y:%.*]]
+; CHECK-NEXT:    [[RET:%.*]] = or <3 x i32> [[AND]], [[AND1]]
+; CHECK-NEXT:    ret <3 x i32> [[RET]]
+;
+  %and = and <3 x i32> %x, %m
+  %neg = xor <3 x i32> %m, <i32 -1, i32 undef, i32 -1>
+  %and1 = and <3 x i32> %neg, %y
+  %ret = or <3 x i32> %and, %and1
+  ret <3 x i32> %ret
+}
+
+; ============================================================================ ;
+; Constant mask.
+; ============================================================================ ;
+
+define i32 @p_constmask(i32 %x, i32 %y) {
+; CHECK-LABEL: @p_constmask(
+; CHECK-NEXT:    [[AND:%.*]] = and i32 [[X:%.*]], 65280
+; CHECK-NEXT:    [[AND1:%.*]] = and i32 [[Y:%.*]], -65281
+; CHECK-NEXT:    [[RET:%.*]] = or i32 [[AND]], [[AND1]]
+; CHECK-NEXT:    ret i32 [[RET]]
+;
+  %and = and i32 %x, 65280
+  %and1 = and i32 %y, -65281
+  %ret = or i32 %and, %and1
+  ret i32 %ret
+}
+
+define <2 x i32> @p_constmask_splatvec(<2 x i32> %x, <2 x i32> %y) {
+; CHECK-LABEL: @p_constmask_splatvec(
+; CHECK-NEXT:    [[AND:%.*]] = and <2 x i32> [[X:%.*]], <i32 65280, i32 65280>
+; CHECK-NEXT:    [[AND1:%.*]] = and <2 x i32> [[Y:%.*]], <i32 -65281, i32 -65281>
+; CHECK-NEXT:    [[RET:%.*]] = or <2 x i32> [[AND]], [[AND1]]
+; CHECK-NEXT:    ret <2 x i32> [[RET]]
+;
+  %and = and <2 x i32> %x, <i32 65280, i32 65280>
+  %and1 = and <2 x i32> %y, <i32 -65281, i32 -65281>
+  %ret = or <2 x i32> %and, %and1
+  ret <2 x i32> %ret
+}
+
+define <2 x i32> @p_constmask_vec(<2 x i32> %x, <2 x i32> %y) {
+; CHECK-LABEL: @p_constmask_vec(
+; CHECK-NEXT:    [[AND:%.*]] = and <2 x i32> [[X:%.*]], <i32 65280, i32 16776960>
+; CHECK-NEXT:    [[AND1:%.*]] = and <2 x i32> [[Y:%.*]], <i32 -65281, i32 -16776961>
+; CHECK-NEXT:    [[RET:%.*]] = or <2 x i32> [[AND]], [[AND1]]
+; CHECK-NEXT:    ret <2 x i32> [[RET]]
+;
+  %and = and <2 x i32> %x, <i32 65280, i32 16776960>
+  %and1 = and <2 x i32> %y, <i32 -65281, i32 -16776961>
+  %ret = or <2 x i32> %and, %and1
+  ret <2 x i32> %ret
+}
+
+define <3 x i32> @p_constmask_vec_undef(<3 x i32> %x, <3 x i32> %y) {
+; CHECK-LABEL: @p_constmask_vec_undef(
+; CHECK-NEXT:    [[AND:%.*]] = and <3 x i32> [[X:%.*]], <i32 65280, i32 undef, i32 65280>
+; CHECK-NEXT:    [[AND1:%.*]] = and <3 x i32> [[Y:%.*]], <i32 -65281, i32 undef, i32 -65281>
+; CHECK-NEXT:    [[RET:%.*]] = or <3 x i32> [[AND]], [[AND1]]
+; CHECK-NEXT:    ret <3 x i32> [[RET]]
+;
+  %and = and <3 x i32> %x, <i32 65280, i32 undef, i32 65280>
+  %and1 = and <3 x i32> %y, <i32 -65281, i32 undef, i32 -65281>
+  %ret = or <3 x i32> %and, %and1
+  ret <3 x i32> %ret
+}
+
+; ============================================================================ ;
+; Constant mask with no common bits set, but common unset bits.
+; ============================================================================ ;
+
+define i32 @p_constmask2(i32 %x, i32 %y) {
+; CHECK-LABEL: @p_constmask2(
+; CHECK-NEXT:    [[AND:%.*]] = and i32 [[X:%.*]], 61440
+; CHECK-NEXT:    [[AND1:%.*]] = and i32 [[Y:%.*]], -65281
+; CHECK-NEXT:    [[RET:%.*]] = or i32 [[AND]], [[AND1]]
+; CHECK-NEXT:    ret i32 [[RET]]
+;
+  %and = and i32 %x, 61440
+  %and1 = and i32 %y, -65281
+  %ret = or i32 %and, %and1
+  ret i32 %ret
+}
+
+define <2 x i32> @p_constmask2_splatvec(<2 x i32> %x, <2 x i32> %y) {
+; CHECK-LABEL: @p_constmask2_splatvec(
+; CHECK-NEXT:    [[AND:%.*]] = and <2 x i32> [[X:%.*]], <i32 61440, i32 61440>
+; CHECK-NEXT:    [[AND1:%.*]] = and <2 x i32> [[Y:%.*]], <i32 -65281, i32 -65281>
+; CHECK-NEXT:    [[RET:%.*]] = or <2 x i32> [[AND]], [[AND1]]
+; CHECK-NEXT:    ret <2 x i32> [[RET]]
+;
+  %and = and <2 x i32> %x, <i32 61440, i32 61440>
+  %and1 = and <2 x i32> %y, <i32 -65281, i32 -65281>
+  %ret = or <2 x i32> %and, %and1
+  ret <2 x i32> %ret
+}
+
+define <2 x i32> @p_constmask2_vec(<2 x i32> %x, <2 x i32> %y) {
+; CHECK-LABEL: @p_constmask2_vec(
+; CHECK-NEXT:    [[AND:%.*]] = and <2 x i32> [[X:%.*]], <i32 61440, i32 16711680>
+; CHECK-NEXT:    [[AND1:%.*]] = and <2 x i32> [[Y:%.*]], <i32 -65281, i32 -16776961>
+; CHECK-NEXT:    [[RET:%.*]] = or <2 x i32> [[AND]], [[AND1]]
+; CHECK-NEXT:    ret <2 x i32> [[RET]]
+;
+  %and = and <2 x i32> %x, <i32 61440, i32 16711680>
+  %and1 = and <2 x i32> %y, <i32 -65281, i32 -16776961>
+  %ret = or <2 x i32> %and, %and1
+  ret <2 x i32> %ret
+}
+
+define <3 x i32> @p_constmask2_vec_undef(<3 x i32> %x, <3 x i32> %y) {
+; CHECK-LABEL: @p_constmask2_vec_undef(
+; CHECK-NEXT:    [[AND:%.*]] = and <3 x i32> [[X:%.*]], <i32 61440, i32 undef, i32 61440>
+; CHECK-NEXT:    [[AND1:%.*]] = and <3 x i32> [[Y:%.*]], <i32 -65281, i32 undef, i32 -65281>
+; CHECK-NEXT:    [[RET:%.*]] = or <3 x i32> [[AND]], [[AND1]]
+; CHECK-NEXT:    ret <3 x i32> [[RET]]
+;
+  %and = and <3 x i32> %x, <i32 61440, i32 undef, i32 61440>
+  %and1 = and <3 x i32> %y, <i32 -65281, i32 undef, i32 -65281>
+  %ret = or <3 x i32> %and, %and1
+  ret <3 x i32> %ret
+}
+
+; ============================================================================ ;
+; Commutativity.
+; ============================================================================ ;
+
+; Used to make sure that the IR complexity sorting does not interfere.
+declare i32 @gen32()
+
+define i32 @p_commutative0(i32 %x, i32 %y, i32 %m) {
+; CHECK-LABEL: @p_commutative0(
+; CHECK-NEXT:    [[AND:%.*]] = and i32 [[M:%.*]], [[X:%.*]]
+; CHECK-NEXT:    [[NEG:%.*]] = xor i32 [[M]], -1
+; CHECK-NEXT:    [[AND1:%.*]] = and i32 [[NEG]], [[Y:%.*]]
+; CHECK-NEXT:    [[RET:%.*]] = or i32 [[AND]], [[AND1]]
+; CHECK-NEXT:    ret i32 [[RET]]
+;
+  %and = and i32 %m, %x ; swapped order
+  %neg = xor i32 %m, -1
+  %and1 = and i32 %neg, %y
+  %ret = or i32 %and, %and1
+  ret i32 %ret
+}
+
+define i32 @p_commutative1(i32 %x, i32 %m) {
+; CHECK-LABEL: @p_commutative1(
+; CHECK-NEXT:    [[Y:%.*]] = call i32 @gen32()
+; CHECK-NEXT:    [[AND:%.*]] = and i32 [[X:%.*]], [[M:%.*]]
+; CHECK-NEXT:    [[NEG:%.*]] = xor i32 [[M]], -1
+; CHECK-NEXT:    [[AND1:%.*]] = and i32 [[Y]], [[NEG]]
+; CHECK-NEXT:    [[RET:%.*]] = or i32 [[AND]], [[AND1]]
+; CHECK-NEXT:    ret i32 [[RET]]
+;
+  %y = call i32 @gen32()
+  %and = and i32 %x, %m
+  %neg = xor i32 %m, -1
+  %and1 = and i32 %y, %neg; swapped order
+  %ret = or i32 %and, %and1
+  ret i32 %ret
+}
+
+define i32 @p_commutative2(i32 %x, i32 %y, i32 %m) {
+; CHECK-LABEL: @p_commutative2(
+; CHECK-NEXT:    [[AND:%.*]] = and i32 [[X:%.*]], [[M:%.*]]
+; CHECK-NEXT:    [[NEG:%.*]] = xor i32 [[M]], -1
+; CHECK-NEXT:    [[AND1:%.*]] = and i32 [[NEG]], [[Y:%.*]]
+; CHECK-NEXT:    [[RET:%.*]] = or i32 [[AND1]], [[AND]]
+; CHECK-NEXT:    ret i32 [[RET]]
+;
+  %and = and i32 %x, %m
+  %neg = xor i32 %m, -1
+  %and1 = and i32 %neg, %y
+  %ret = or i32 %and1, %and ; swapped order
+  ret i32 %ret
+}
+
+define i32 @p_commutative3(i32 %x, i32 %m) {
+; CHECK-LABEL: @p_commutative3(
+; CHECK-NEXT:    [[Y:%.*]] = call i32 @gen32()
+; CHECK-NEXT:    [[AND:%.*]] = and i32 [[M:%.*]], [[X:%.*]]
+; CHECK-NEXT:    [[NEG:%.*]] = xor i32 [[M]], -1
+; CHECK-NEXT:    [[AND1:%.*]] = and i32 [[Y]], [[NEG]]
+; CHECK-NEXT:    [[RET:%.*]] = or i32 [[AND]], [[AND1]]
+; CHECK-NEXT:    ret i32 [[RET]]
+;
+  %y = call i32 @gen32()
+  %and = and i32 %m, %x ; swapped order
+  %neg = xor i32 %m, -1
+  %and1 = and i32 %y, %neg; swapped order
+  %ret = or i32 %and, %and1
+  ret i32 %ret
+}
+
+define i32 @p_commutative4(i32 %x, i32 %y, i32 %m) {
+; CHECK-LABEL: @p_commutative4(
+; CHECK-NEXT:    [[AND:%.*]] = and i32 [[M:%.*]], [[X:%.*]]
+; CHECK-NEXT:    [[NEG:%.*]] = xor i32 [[M]], -1
+; CHECK-NEXT:    [[AND1:%.*]] = and i32 [[NEG]], [[Y:%.*]]
+; CHECK-NEXT:    [[RET:%.*]] = or i32 [[AND1]], [[AND]]
+; CHECK-NEXT:    ret i32 [[RET]]
+;
+  %and = and i32 %m, %x ; swapped order
+  %neg = xor i32 %m, -1
+  %and1 = and i32 %neg, %y
+  %ret = or i32 %and1, %and ; swapped order
+  ret i32 %ret
+}
+
+define i32 @p_commutative5(i32 %x, i32 %m) {
+; CHECK-LABEL: @p_commutative5(
+; CHECK-NEXT:    [[Y:%.*]] = call i32 @gen32()
+; CHECK-NEXT:    [[AND:%.*]] = and i32 [[X:%.*]], [[M:%.*]]
+; CHECK-NEXT:    [[NEG:%.*]] = xor i32 [[M]], -1
+; CHECK-NEXT:    [[AND1:%.*]] = and i32 [[Y]], [[NEG]]
+; CHECK-NEXT:    [[RET:%.*]] = or i32 [[AND1]], [[AND]]
+; CHECK-NEXT:    ret i32 [[RET]]
+;
+  %y = call i32 @gen32()
+  %and = and i32 %x, %m
+  %neg = xor i32 %m, -1
+  %and1 = and i32 %y, %neg; swapped order
+  %ret = or i32 %and1, %and ; swapped order
+  ret i32 %ret
+}
+
+define i32 @p_commutative6(i32 %x, i32 %m) {
+; CHECK-LABEL: @p_commutative6(
+; CHECK-NEXT:    [[Y:%.*]] = call i32 @gen32()
+; CHECK-NEXT:    [[AND:%.*]] = and i32 [[M:%.*]], [[X:%.*]]
+; CHECK-NEXT:    [[NEG:%.*]] = xor i32 [[M]], -1
+; CHECK-NEXT:    [[AND1:%.*]] = and i32 [[Y]], [[NEG]]
+; CHECK-NEXT:    [[RET:%.*]] = or i32 [[AND1]], [[AND]]
+; CHECK-NEXT:    ret i32 [[RET]]
+;
+  %y = call i32 @gen32()
+  %and = and i32 %m, %x ; swapped order
+  %neg = xor i32 %m, -1
+  %and1 = and i32 %y, %neg; swapped order
+  %ret = or i32 %and1, %and ; swapped order
+  ret i32 %ret
+}
+
+define i32 @p_constmask_commutative(i32 %x, i32 %y) {
+; CHECK-LABEL: @p_constmask_commutative(
+; CHECK-NEXT:    [[AND:%.*]] = and i32 [[X:%.*]], 65280
+; CHECK-NEXT:    [[AND1:%.*]] = and i32 [[Y:%.*]], -65281
+; CHECK-NEXT:    [[RET:%.*]] = or i32 [[AND1]], [[AND]]
+; CHECK-NEXT:    ret i32 [[RET]]
+;
+  %and = and i32 %x, 65280
+  %and1 = and i32 %y, -65281
+  %ret = or i32 %and1, %and ; swapped order
+  ret i32 %ret
+}
+
+; ============================================================================ ;
+; Negative tests. Should not be folded.
+; ============================================================================ ;
+
+; One use only.
+
+declare void @use32(i32)
+
+define i32 @n0_oneuse(i32 %x, i32 %y, i32 %m) {
+; CHECK-LABEL: @n0_oneuse(
+; CHECK-NEXT:    [[AND:%.*]] = and i32 [[X:%.*]], [[M:%.*]]
+; CHECK-NEXT:    [[NEG:%.*]] = xor i32 [[M]], -1
+; CHECK-NEXT:    [[AND1:%.*]] = and i32 [[NEG]], [[Y:%.*]]
+; CHECK-NEXT:    [[RET:%.*]] = or i32 [[AND]], [[AND1]]
+; CHECK-NEXT:    call void @use32(i32 [[AND]])
+; CHECK-NEXT:    call void @use32(i32 [[NEG]])
+; CHECK-NEXT:    call void @use32(i32 [[AND1]])
+; CHECK-NEXT:    ret i32 [[RET]]
+;
+  %and = and i32 %x, %m
+  %neg = xor i32 %m, -1
+  %and1 = and i32 %neg, %y
+  %ret = or i32 %and, %and1
+  call void @use32(i32 %and)
+  call void @use32(i32 %neg)
+  call void @use32(i32 %and1)
+  ret i32 %ret
+}
+
+define i32 @n0_constmask_oneuse(i32 %x, i32 %y) {
+; CHECK-LABEL: @n0_constmask_oneuse(
+; CHECK-NEXT:    [[AND:%.*]] = and i32 [[X:%.*]], 65280
+; CHECK-NEXT:    [[AND1:%.*]] = and i32 [[Y:%.*]], -65281
+; CHECK-NEXT:    [[RET:%.*]] = or i32 [[AND]], [[AND1]]
+; CHECK-NEXT:    call void @use32(i32 [[AND]])
+; CHECK-NEXT:    call void @use32(i32 [[AND1]])
+; CHECK-NEXT:    ret i32 [[RET]]
+;
+  %and = and i32 %x, 65280
+  %and1 = and i32 %y, -65281
+  %ret = or i32 %and, %and1
+  call void @use32(i32 %and)
+  call void @use32(i32 %and1)
+  ret i32 %ret
+}
+
+; Bad xor constant
+
+define i32 @n1_badxor(i32 %x, i32 %y, i32 %m) {
+; CHECK-LABEL: @n1_badxor(
+; CHECK-NEXT:    [[AND:%.*]] = and i32 [[X:%.*]], [[M:%.*]]
+; CHECK-NEXT:    [[NEG:%.*]] = xor i32 [[M]], 1
+; CHECK-NEXT:    [[AND1:%.*]] = and i32 [[NEG]], [[Y:%.*]]
+; CHECK-NEXT:    [[RET:%.*]] = or i32 [[AND]], [[AND1]]
+; CHECK-NEXT:    ret i32 [[RET]]
+;
+  %and = and i32 %x, %m
+  %neg = xor i32 %m, 1 ; not -1
+  %and1 = and i32 %neg, %y
+  %ret = or i32 %and, %and1
+  ret i32 %ret
+}
+
+; Different mask is used
+
+define i32 @n2_badmask(i32 %x, i32 %y, i32 %m1, i32 %m2) {
+; CHECK-LABEL: @n2_badmask(
+; CHECK-NEXT:    [[AND:%.*]] = and i32 [[M1:%.*]], [[X:%.*]]
+; CHECK-NEXT:    [[NEG:%.*]] = xor i32 [[M2:%.*]], -1
+; CHECK-NEXT:    [[AND1:%.*]] = and i32 [[NEG]], [[Y:%.*]]
+; CHECK-NEXT:    [[RET:%.*]] = or i32 [[AND]], [[AND1]]
+; CHECK-NEXT:    ret i32 [[RET]]
+;
+  %and = and i32 %m1, %x
+  %neg = xor i32 %m2, -1 ; different mask, not %m1
+  %and1 = and i32 %neg, %y
+  %ret = or i32 %and, %and1
+  ret i32 %ret
+}
+
+; Different const mask is used
+
+define i32 @n3_constmask_badmask(i32 %x, i32 %y) {
+; CHECK-LABEL: @n3_constmask_badmask(
+; CHECK-NEXT:    [[AND:%.*]] = and i32 [[X:%.*]], 65280
+; CHECK-NEXT:    [[AND1:%.*]] = and i32 [[Y:%.*]], -65280
+; CHECK-NEXT:    [[RET:%.*]] = or i32 [[AND]], [[AND1]]
+; CHECK-NEXT:    ret i32 [[RET]]
+;
+  %and = and i32 %x, 65280
+  %and1 = and i32 %y, -65280 ; not -65281, so they have one common bit
+  %ret = or i32 %and, %and1
+  ret i32 %ret
+}
+
+define i32 @n3_constmask_samemask(i32 %x, i32 %y) {
+; CHECK-LABEL: @n3_constmask_samemask(
+; CHECK-NEXT:    [[AND2:%.*]] = or i32 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    [[RET:%.*]] = and i32 [[AND2]], 65280
+; CHECK-NEXT:    ret i32 [[RET]]
+;
+  %and = and i32 %x, 65280
+  %and1 = and i32 %y, 65280 ; both masks are the same
+  %ret = or i32 %and, %and1
+  ret i32 %ret
+}

Added: llvm/trunk/test/Transforms/InstCombine/masked-merge-xor.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/masked-merge-xor.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/masked-merge-xor.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/masked-merge-xor.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,414 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt < %s -instcombine -S | FileCheck %s
+
+; https://bugs.llvm.org/show_bug.cgi?id=6773
+
+; Patterns:
+;   (x & m) | (y & ~m)
+;   (x & m) ^ (y & ~m)
+;   (x & m) + (y & ~m)
+; Should be transformed into:
+;   (x & m) | (y & ~m)
+; And then into:
+;   ((x ^ y) & m) ^ y
+
+; ============================================================================ ;
+; Most basic positive tests
+; ============================================================================ ;
+
+define i32 @p(i32 %x, i32 %y, i32 %m) {
+; CHECK-LABEL: @p(
+; CHECK-NEXT:    [[AND:%.*]] = and i32 [[X:%.*]], [[M:%.*]]
+; CHECK-NEXT:    [[NEG:%.*]] = xor i32 [[M]], -1
+; CHECK-NEXT:    [[AND1:%.*]] = and i32 [[NEG]], [[Y:%.*]]
+; CHECK-NEXT:    [[RET:%.*]] = or i32 [[AND]], [[AND1]]
+; CHECK-NEXT:    ret i32 [[RET]]
+;
+  %and = and i32 %x, %m
+  %neg = xor i32 %m, -1
+  %and1 = and i32 %neg, %y
+  %ret = xor i32 %and, %and1
+  ret i32 %ret
+}
+
+define <2 x i32> @p_splatvec(<2 x i32> %x, <2 x i32> %y, <2 x i32> %m) {
+; CHECK-LABEL: @p_splatvec(
+; CHECK-NEXT:    [[AND:%.*]] = and <2 x i32> [[X:%.*]], [[M:%.*]]
+; CHECK-NEXT:    [[NEG:%.*]] = xor <2 x i32> [[M]], <i32 -1, i32 -1>
+; CHECK-NEXT:    [[AND1:%.*]] = and <2 x i32> [[NEG]], [[Y:%.*]]
+; CHECK-NEXT:    [[RET:%.*]] = or <2 x i32> [[AND]], [[AND1]]
+; CHECK-NEXT:    ret <2 x i32> [[RET]]
+;
+  %and = and <2 x i32> %x, %m
+  %neg = xor <2 x i32> %m, <i32 -1, i32 -1>
+  %and1 = and <2 x i32> %neg, %y
+  %ret = xor <2 x i32> %and, %and1
+  ret <2 x i32> %ret
+}
+
+define <3 x i32> @p_vec_undef(<3 x i32> %x, <3 x i32> %y, <3 x i32> %m) {
+; CHECK-LABEL: @p_vec_undef(
+; CHECK-NEXT:    [[AND:%.*]] = and <3 x i32> [[X:%.*]], [[M:%.*]]
+; CHECK-NEXT:    [[NEG:%.*]] = xor <3 x i32> [[M]], <i32 -1, i32 undef, i32 -1>
+; CHECK-NEXT:    [[AND1:%.*]] = and <3 x i32> [[NEG]], [[Y:%.*]]
+; CHECK-NEXT:    [[RET:%.*]] = or <3 x i32> [[AND]], [[AND1]]
+; CHECK-NEXT:    ret <3 x i32> [[RET]]
+;
+  %and = and <3 x i32> %x, %m
+  %neg = xor <3 x i32> %m, <i32 -1, i32 undef, i32 -1>
+  %and1 = and <3 x i32> %neg, %y
+  %ret = xor <3 x i32> %and, %and1
+  ret <3 x i32> %ret
+}
+
+; ============================================================================ ;
+; Constant mask.
+; ============================================================================ ;
+
+define i32 @p_constmask(i32 %x, i32 %y) {
+; CHECK-LABEL: @p_constmask(
+; CHECK-NEXT:    [[AND:%.*]] = and i32 [[X:%.*]], 65280
+; CHECK-NEXT:    [[AND1:%.*]] = and i32 [[Y:%.*]], -65281
+; CHECK-NEXT:    [[RET1:%.*]] = or i32 [[AND]], [[AND1]]
+; CHECK-NEXT:    ret i32 [[RET1]]
+;
+  %and = and i32 %x, 65280
+  %and1 = and i32 %y, -65281
+  %ret = xor i32 %and, %and1
+  ret i32 %ret
+}
+
+define <2 x i32> @p_constmask_splatvec(<2 x i32> %x, <2 x i32> %y) {
+; CHECK-LABEL: @p_constmask_splatvec(
+; CHECK-NEXT:    [[AND:%.*]] = and <2 x i32> [[X:%.*]], <i32 65280, i32 65280>
+; CHECK-NEXT:    [[AND1:%.*]] = and <2 x i32> [[Y:%.*]], <i32 -65281, i32 -65281>
+; CHECK-NEXT:    [[RET1:%.*]] = or <2 x i32> [[AND]], [[AND1]]
+; CHECK-NEXT:    ret <2 x i32> [[RET1]]
+;
+  %and = and <2 x i32> %x, <i32 65280, i32 65280>
+  %and1 = and <2 x i32> %y, <i32 -65281, i32 -65281>
+  %ret = xor <2 x i32> %and, %and1
+  ret <2 x i32> %ret
+}
+
+define <2 x i32> @p_constmask_vec(<2 x i32> %x, <2 x i32> %y) {
+; CHECK-LABEL: @p_constmask_vec(
+; CHECK-NEXT:    [[AND:%.*]] = and <2 x i32> [[X:%.*]], <i32 65280, i32 16776960>
+; CHECK-NEXT:    [[AND1:%.*]] = and <2 x i32> [[Y:%.*]], <i32 -65281, i32 -16776961>
+; CHECK-NEXT:    [[RET:%.*]] = xor <2 x i32> [[AND]], [[AND1]]
+; CHECK-NEXT:    ret <2 x i32> [[RET]]
+;
+  %and = and <2 x i32> %x, <i32 65280, i32 16776960>
+  %and1 = and <2 x i32> %y, <i32 -65281, i32 -16776961>
+  %ret = xor <2 x i32> %and, %and1
+  ret <2 x i32> %ret
+}
+
+define <3 x i32> @p_constmask_vec_undef(<3 x i32> %x, <3 x i32> %y) {
+; CHECK-LABEL: @p_constmask_vec_undef(
+; CHECK-NEXT:    [[AND:%.*]] = and <3 x i32> [[X:%.*]], <i32 65280, i32 undef, i32 65280>
+; CHECK-NEXT:    [[AND1:%.*]] = and <3 x i32> [[Y:%.*]], <i32 -65281, i32 undef, i32 -65281>
+; CHECK-NEXT:    [[RET:%.*]] = xor <3 x i32> [[AND]], [[AND1]]
+; CHECK-NEXT:    ret <3 x i32> [[RET]]
+;
+  %and = and <3 x i32> %x, <i32 65280, i32 undef, i32 65280>
+  %and1 = and <3 x i32> %y, <i32 -65281, i32 undef, i32 -65281>
+  %ret = xor <3 x i32> %and, %and1
+  ret <3 x i32> %ret
+}
+
+; ============================================================================ ;
+; Constant mask with no common bits set, but common unset bits.
+; ============================================================================ ;
+
+define i32 @p_constmask2(i32 %x, i32 %y) {
+; CHECK-LABEL: @p_constmask2(
+; CHECK-NEXT:    [[AND:%.*]] = and i32 [[X:%.*]], 61440
+; CHECK-NEXT:    [[AND1:%.*]] = and i32 [[Y:%.*]], -65281
+; CHECK-NEXT:    [[RET1:%.*]] = or i32 [[AND]], [[AND1]]
+; CHECK-NEXT:    ret i32 [[RET1]]
+;
+  %and = and i32 %x, 61440
+  %and1 = and i32 %y, -65281
+  %ret = xor i32 %and, %and1
+  ret i32 %ret
+}
+
+define <2 x i32> @p_constmask2_splatvec(<2 x i32> %x, <2 x i32> %y) {
+; CHECK-LABEL: @p_constmask2_splatvec(
+; CHECK-NEXT:    [[AND:%.*]] = and <2 x i32> [[X:%.*]], <i32 61440, i32 61440>
+; CHECK-NEXT:    [[AND1:%.*]] = and <2 x i32> [[Y:%.*]], <i32 -65281, i32 -65281>
+; CHECK-NEXT:    [[RET1:%.*]] = or <2 x i32> [[AND]], [[AND1]]
+; CHECK-NEXT:    ret <2 x i32> [[RET1]]
+;
+  %and = and <2 x i32> %x, <i32 61440, i32 61440>
+  %and1 = and <2 x i32> %y, <i32 -65281, i32 -65281>
+  %ret = xor <2 x i32> %and, %and1
+  ret <2 x i32> %ret
+}
+
+define <2 x i32> @p_constmask2_vec(<2 x i32> %x, <2 x i32> %y) {
+; CHECK-LABEL: @p_constmask2_vec(
+; CHECK-NEXT:    [[AND:%.*]] = and <2 x i32> [[X:%.*]], <i32 61440, i32 16711680>
+; CHECK-NEXT:    [[AND1:%.*]] = and <2 x i32> [[Y:%.*]], <i32 -65281, i32 -16776961>
+; CHECK-NEXT:    [[RET:%.*]] = xor <2 x i32> [[AND]], [[AND1]]
+; CHECK-NEXT:    ret <2 x i32> [[RET]]
+;
+  %and = and <2 x i32> %x, <i32 61440, i32 16711680>
+  %and1 = and <2 x i32> %y, <i32 -65281, i32 -16776961>
+  %ret = xor <2 x i32> %and, %and1
+  ret <2 x i32> %ret
+}
+
+define <3 x i32> @p_constmask2_vec_undef(<3 x i32> %x, <3 x i32> %y) {
+; CHECK-LABEL: @p_constmask2_vec_undef(
+; CHECK-NEXT:    [[AND:%.*]] = and <3 x i32> [[X:%.*]], <i32 61440, i32 undef, i32 61440>
+; CHECK-NEXT:    [[AND1:%.*]] = and <3 x i32> [[Y:%.*]], <i32 -65281, i32 undef, i32 -65281>
+; CHECK-NEXT:    [[RET:%.*]] = xor <3 x i32> [[AND]], [[AND1]]
+; CHECK-NEXT:    ret <3 x i32> [[RET]]
+;
+  %and = and <3 x i32> %x, <i32 61440, i32 undef, i32 61440>
+  %and1 = and <3 x i32> %y, <i32 -65281, i32 undef, i32 -65281>
+  %ret = xor <3 x i32> %and, %and1
+  ret <3 x i32> %ret
+}
+
+; ============================================================================ ;
+; Commutativity.
+; ============================================================================ ;
+
+; Used to make sure that the IR complexity sorting does not interfere.
+declare i32 @gen32()
+
+define i32 @p_commutative0(i32 %x, i32 %y, i32 %m) {
+; CHECK-LABEL: @p_commutative0(
+; CHECK-NEXT:    [[AND:%.*]] = and i32 [[M:%.*]], [[X:%.*]]
+; CHECK-NEXT:    [[NEG:%.*]] = xor i32 [[M]], -1
+; CHECK-NEXT:    [[AND1:%.*]] = and i32 [[NEG]], [[Y:%.*]]
+; CHECK-NEXT:    [[RET:%.*]] = or i32 [[AND]], [[AND1]]
+; CHECK-NEXT:    ret i32 [[RET]]
+;
+  %and = and i32 %m, %x ; swapped order
+  %neg = xor i32 %m, -1
+  %and1 = and i32 %neg, %y
+  %ret = xor i32 %and, %and1
+  ret i32 %ret
+}
+
+define i32 @p_commutative1(i32 %x, i32 %m) {
+; CHECK-LABEL: @p_commutative1(
+; CHECK-NEXT:    [[Y:%.*]] = call i32 @gen32()
+; CHECK-NEXT:    [[AND:%.*]] = and i32 [[X:%.*]], [[M:%.*]]
+; CHECK-NEXT:    [[NEG:%.*]] = xor i32 [[M]], -1
+; CHECK-NEXT:    [[AND1:%.*]] = and i32 [[Y]], [[NEG]]
+; CHECK-NEXT:    [[RET:%.*]] = or i32 [[AND]], [[AND1]]
+; CHECK-NEXT:    ret i32 [[RET]]
+;
+  %y = call i32 @gen32()
+  %and = and i32 %x, %m
+  %neg = xor i32 %m, -1
+  %and1 = and i32 %y, %neg; swapped order
+  %ret = xor i32 %and, %and1
+  ret i32 %ret
+}
+
+define i32 @p_commutative2(i32 %x, i32 %y, i32 %m) {
+; CHECK-LABEL: @p_commutative2(
+; CHECK-NEXT:    [[AND:%.*]] = and i32 [[X:%.*]], [[M:%.*]]
+; CHECK-NEXT:    [[NEG:%.*]] = xor i32 [[M]], -1
+; CHECK-NEXT:    [[AND1:%.*]] = and i32 [[NEG]], [[Y:%.*]]
+; CHECK-NEXT:    [[RET:%.*]] = or i32 [[AND1]], [[AND]]
+; CHECK-NEXT:    ret i32 [[RET]]
+;
+  %and = and i32 %x, %m
+  %neg = xor i32 %m, -1
+  %and1 = and i32 %neg, %y
+  %ret = xor i32 %and1, %and ; swapped order
+  ret i32 %ret
+}
+
+define i32 @p_commutative3(i32 %x, i32 %m) {
+; CHECK-LABEL: @p_commutative3(
+; CHECK-NEXT:    [[Y:%.*]] = call i32 @gen32()
+; CHECK-NEXT:    [[AND:%.*]] = and i32 [[M:%.*]], [[X:%.*]]
+; CHECK-NEXT:    [[NEG:%.*]] = xor i32 [[M]], -1
+; CHECK-NEXT:    [[AND1:%.*]] = and i32 [[Y]], [[NEG]]
+; CHECK-NEXT:    [[RET:%.*]] = or i32 [[AND]], [[AND1]]
+; CHECK-NEXT:    ret i32 [[RET]]
+;
+  %y = call i32 @gen32()
+  %and = and i32 %m, %x ; swapped order
+  %neg = xor i32 %m, -1
+  %and1 = and i32 %y, %neg; swapped order
+  %ret = xor i32 %and, %and1
+  ret i32 %ret
+}
+
+define i32 @p_commutative4(i32 %x, i32 %y, i32 %m) {
+; CHECK-LABEL: @p_commutative4(
+; CHECK-NEXT:    [[AND:%.*]] = and i32 [[M:%.*]], [[X:%.*]]
+; CHECK-NEXT:    [[NEG:%.*]] = xor i32 [[M]], -1
+; CHECK-NEXT:    [[AND1:%.*]] = and i32 [[NEG]], [[Y:%.*]]
+; CHECK-NEXT:    [[RET:%.*]] = or i32 [[AND1]], [[AND]]
+; CHECK-NEXT:    ret i32 [[RET]]
+;
+  %and = and i32 %m, %x ; swapped order
+  %neg = xor i32 %m, -1
+  %and1 = and i32 %neg, %y
+  %ret = xor i32 %and1, %and ; swapped order
+  ret i32 %ret
+}
+
+define i32 @p_commutative5(i32 %x, i32 %m) {
+; CHECK-LABEL: @p_commutative5(
+; CHECK-NEXT:    [[Y:%.*]] = call i32 @gen32()
+; CHECK-NEXT:    [[AND:%.*]] = and i32 [[X:%.*]], [[M:%.*]]
+; CHECK-NEXT:    [[NEG:%.*]] = xor i32 [[M]], -1
+; CHECK-NEXT:    [[AND1:%.*]] = and i32 [[Y]], [[NEG]]
+; CHECK-NEXT:    [[RET:%.*]] = or i32 [[AND1]], [[AND]]
+; CHECK-NEXT:    ret i32 [[RET]]
+;
+  %y = call i32 @gen32()
+  %and = and i32 %x, %m
+  %neg = xor i32 %m, -1
+  %and1 = and i32 %y, %neg; swapped order
+  %ret = xor i32 %and1, %and ; swapped order
+  ret i32 %ret
+}
+
+define i32 @p_commutative6(i32 %x, i32 %m) {
+; CHECK-LABEL: @p_commutative6(
+; CHECK-NEXT:    [[Y:%.*]] = call i32 @gen32()
+; CHECK-NEXT:    [[AND:%.*]] = and i32 [[M:%.*]], [[X:%.*]]
+; CHECK-NEXT:    [[NEG:%.*]] = xor i32 [[M]], -1
+; CHECK-NEXT:    [[AND1:%.*]] = and i32 [[Y]], [[NEG]]
+; CHECK-NEXT:    [[RET:%.*]] = or i32 [[AND1]], [[AND]]
+; CHECK-NEXT:    ret i32 [[RET]]
+;
+  %y = call i32 @gen32()
+  %and = and i32 %m, %x ; swapped order
+  %neg = xor i32 %m, -1
+  %and1 = and i32 %y, %neg; swapped order
+  %ret = xor i32 %and1, %and ; swapped order
+  ret i32 %ret
+}
+
+define i32 @p_constmask_commutative(i32 %x, i32 %y) {
+; CHECK-LABEL: @p_constmask_commutative(
+; CHECK-NEXT:    [[AND:%.*]] = and i32 [[X:%.*]], 65280
+; CHECK-NEXT:    [[AND1:%.*]] = and i32 [[Y:%.*]], -65281
+; CHECK-NEXT:    [[RET1:%.*]] = or i32 [[AND1]], [[AND]]
+; CHECK-NEXT:    ret i32 [[RET1]]
+;
+  %and = and i32 %x, 65280
+  %and1 = and i32 %y, -65281
+  %ret = xor i32 %and1, %and ; swapped order
+  ret i32 %ret
+}
+
+; ============================================================================ ;
+; Negative tests. Should not be folded.
+; ============================================================================ ;
+
+; One use only.
+
+declare void @use32(i32)
+
+define i32 @n0_oneuse(i32 %x, i32 %y, i32 %m) {
+; CHECK-LABEL: @n0_oneuse(
+; CHECK-NEXT:    [[AND:%.*]] = and i32 [[X:%.*]], [[M:%.*]]
+; CHECK-NEXT:    [[NEG:%.*]] = xor i32 [[M]], -1
+; CHECK-NEXT:    [[AND1:%.*]] = and i32 [[NEG]], [[Y:%.*]]
+; CHECK-NEXT:    [[RET:%.*]] = or i32 [[AND]], [[AND1]]
+; CHECK-NEXT:    call void @use32(i32 [[AND]])
+; CHECK-NEXT:    call void @use32(i32 [[NEG]])
+; CHECK-NEXT:    call void @use32(i32 [[AND1]])
+; CHECK-NEXT:    ret i32 [[RET]]
+;
+  %and = and i32 %x, %m
+  %neg = xor i32 %m, -1
+  %and1 = and i32 %neg, %y
+  %ret = xor i32 %and, %and1
+  call void @use32(i32 %and)
+  call void @use32(i32 %neg)
+  call void @use32(i32 %and1)
+  ret i32 %ret
+}
+
+define i32 @n0_constmask_oneuse(i32 %x, i32 %y) {
+; CHECK-LABEL: @n0_constmask_oneuse(
+; CHECK-NEXT:    [[AND:%.*]] = and i32 [[X:%.*]], 65280
+; CHECK-NEXT:    [[AND1:%.*]] = and i32 [[Y:%.*]], -65281
+; CHECK-NEXT:    [[RET1:%.*]] = or i32 [[AND]], [[AND1]]
+; CHECK-NEXT:    call void @use32(i32 [[AND]])
+; CHECK-NEXT:    call void @use32(i32 [[AND1]])
+; CHECK-NEXT:    ret i32 [[RET1]]
+;
+  %and = and i32 %x, 65280
+  %and1 = and i32 %y, -65281
+  %ret = xor i32 %and, %and1
+  call void @use32(i32 %and)
+  call void @use32(i32 %and1)
+  ret i32 %ret
+}
+
+; Bad xor constant
+
+define i32 @n1_badxor(i32 %x, i32 %y, i32 %m) {
+; CHECK-LABEL: @n1_badxor(
+; CHECK-NEXT:    [[AND:%.*]] = and i32 [[X:%.*]], [[M:%.*]]
+; CHECK-NEXT:    [[NEG:%.*]] = xor i32 [[M]], 1
+; CHECK-NEXT:    [[AND1:%.*]] = and i32 [[NEG]], [[Y:%.*]]
+; CHECK-NEXT:    [[RET:%.*]] = xor i32 [[AND]], [[AND1]]
+; CHECK-NEXT:    ret i32 [[RET]]
+;
+  %and = and i32 %x, %m
+  %neg = xor i32 %m, 1 ; not -1
+  %and1 = and i32 %neg, %y
+  %ret = xor i32 %and, %and1
+  ret i32 %ret
+}
+
+; Different mask is used
+
+define i32 @n2_badmask(i32 %x, i32 %y, i32 %m1, i32 %m2) {
+; CHECK-LABEL: @n2_badmask(
+; CHECK-NEXT:    [[AND:%.*]] = and i32 [[M1:%.*]], [[X:%.*]]
+; CHECK-NEXT:    [[NEG:%.*]] = xor i32 [[M2:%.*]], -1
+; CHECK-NEXT:    [[AND1:%.*]] = and i32 [[NEG]], [[Y:%.*]]
+; CHECK-NEXT:    [[RET:%.*]] = xor i32 [[AND]], [[AND1]]
+; CHECK-NEXT:    ret i32 [[RET]]
+;
+  %and = and i32 %m1, %x
+  %neg = xor i32 %m2, -1 ; different mask, not %m1
+  %and1 = and i32 %neg, %y
+  %ret = xor i32 %and, %and1
+  ret i32 %ret
+}
+
+; Different const mask is used
+
+define i32 @n3_constmask_badmask(i32 %x, i32 %y) {
+; CHECK-LABEL: @n3_constmask_badmask(
+; CHECK-NEXT:    [[AND:%.*]] = and i32 [[X:%.*]], 65280
+; CHECK-NEXT:    [[AND1:%.*]] = and i32 [[Y:%.*]], -65280
+; CHECK-NEXT:    [[RET:%.*]] = xor i32 [[AND]], [[AND1]]
+; CHECK-NEXT:    ret i32 [[RET]]
+;
+  %and = and i32 %x, 65280
+  %and1 = and i32 %y, -65280 ; not -65281, so they have one common bit
+  %ret = xor i32 %and, %and1
+  ret i32 %ret
+}
+
+define i32 @n3_constmask_samemask(i32 %x, i32 %y) {
+; CHECK-LABEL: @n3_constmask_samemask(
+; CHECK-NEXT:    [[AND2:%.*]] = xor i32 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    [[RET:%.*]] = and i32 [[AND2]], 65280
+; CHECK-NEXT:    ret i32 [[RET]]
+;
+  %and = and i32 %x, 65280
+  %and1 = and i32 %y, 65280 ; both masks are the same
+  %ret = xor i32 %and, %and1
+  ret i32 %ret
+}

Added: llvm/trunk/test/Transforms/InstCombine/masked_intrinsics.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/masked_intrinsics.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/masked_intrinsics.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/masked_intrinsics.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,261 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt -instcombine -S < %s | FileCheck %s
+
+declare <2 x double> @llvm.masked.load.v2f64.p0v2f64(<2 x double>* %ptrs, i32, <2 x i1> %mask, <2 x double> %src0)
+declare void @llvm.masked.store.v2f64.p0v2f64(<2 x double> %val, <2 x double>* %ptrs, i32, <2 x i1> %mask)
+declare <2 x double> @llvm.masked.gather.v2f64.v2p0f64(<2 x double*> %ptrs, i32, <2 x i1> %mask, <2 x double> %passthru)
+declare <4 x double> @llvm.masked.gather.v4f64.p0v4f64(<4 x double*> %ptrs, i32, <4 x i1> %mask, <4 x double> %passthru)
+declare void @llvm.masked.scatter.v2f64.v2p0f64(<2 x double> %val, <2 x double*> %ptrs, i32, <2 x i1> %mask)
+
+define <2 x double> @load_zeromask(<2 x double>* %ptr, <2 x double> %passthru)  {
+; CHECK-LABEL: @load_zeromask(
+; CHECK-NEXT:    ret <2 x double> [[PASSTHRU:%.*]]
+;
+  %res = call <2 x double> @llvm.masked.load.v2f64.p0v2f64(<2 x double>* %ptr, i32 1, <2 x i1> zeroinitializer, <2 x double> %passthru)
+  ret <2 x double> %res
+}
+
+define <2 x double> @load_onemask(<2 x double>* %ptr, <2 x double> %passthru)  {
+; CHECK-LABEL: @load_onemask(
+; CHECK-NEXT:    [[UNMASKEDLOAD:%.*]] = load <2 x double>, <2 x double>* [[PTR:%.*]], align 2
+; CHECK-NEXT:    ret <2 x double> [[UNMASKEDLOAD]]
+;
+  %res = call <2 x double> @llvm.masked.load.v2f64.p0v2f64(<2 x double>* %ptr, i32 2, <2 x i1> <i1 1, i1 1>, <2 x double> %passthru)
+  ret <2 x double> %res
+}
+
+define <2 x double> @load_undefmask(<2 x double>* %ptr, <2 x double> %passthru)  {
+; CHECK-LABEL: @load_undefmask(
+; CHECK-NEXT:    [[UNMASKEDLOAD:%.*]] = load <2 x double>, <2 x double>* [[PTR:%.*]], align 2
+; CHECK-NEXT:    ret <2 x double> [[UNMASKEDLOAD]]
+;
+  %res = call <2 x double> @llvm.masked.load.v2f64.p0v2f64(<2 x double>* %ptr, i32 2, <2 x i1> <i1 1, i1 undef>, <2 x double> %passthru)
+  ret <2 x double> %res
+}
+
+ at G = external global i8
+
+define <2 x double> @load_cemask(<2 x double>* %ptr, <2 x double> %passthru)  {
+; CHECK-LABEL: @load_cemask(
+; CHECK-NEXT:    [[RES:%.*]] = call <2 x double> @llvm.masked.load.v2f64.p0v2f64(<2 x double>* [[PTR:%.*]], i32 2, <2 x i1> <i1 true, i1 ptrtoint (i8* @G to i1)>, <2 x double> [[PASSTHRU:%.*]])
+; CHECK-NEXT:    ret <2 x double> [[RES]]
+;
+  %res = call <2 x double> @llvm.masked.load.v2f64.p0v2f64(<2 x double>* %ptr, i32 2, <2 x i1> <i1 1, i1 ptrtoint (i8* @G to i1)>, <2 x double> %passthru)
+  ret <2 x double> %res
+}
+
+define <2 x double> @load_lane0(<2 x double>* %ptr, double %pt)  {
+; CHECK-LABEL: @load_lane0(
+; CHECK-NEXT:    [[PTV2:%.*]] = insertelement <2 x double> undef, double [[PT:%.*]], i64 1
+; CHECK-NEXT:    [[RES:%.*]] = call <2 x double> @llvm.masked.load.v2f64.p0v2f64(<2 x double>* [[PTR:%.*]], i32 2, <2 x i1> <i1 true, i1 false>, <2 x double> [[PTV2]])
+; CHECK-NEXT:    ret <2 x double> [[RES]]
+;
+  %ptv1 = insertelement <2 x double> undef, double %pt, i64 0
+  %ptv2 = insertelement <2 x double> %ptv1, double %pt, i64 1
+  %res = call <2 x double> @llvm.masked.load.v2f64.p0v2f64(<2 x double>* %ptr, i32 2, <2 x i1> <i1 true, i1 false>, <2 x double> %ptv2)
+  ret <2 x double> %res
+}
+
+define double @load_all(double* %base, double %pt)  {
+; CHECK-LABEL: @load_all(
+; CHECK-NEXT:    [[PTRS:%.*]] = getelementptr double, double* [[BASE:%.*]], <4 x i64> <i64 0, i64 undef, i64 2, i64 3>
+; CHECK-NEXT:    [[RES:%.*]] = call <4 x double> @llvm.masked.gather.v4f64.v4p0f64(<4 x double*> [[PTRS]], i32 4, <4 x i1> <i1 true, i1 false, i1 true, i1 true>, <4 x double> undef)
+; CHECK-NEXT:    [[ELT:%.*]] = extractelement <4 x double> [[RES]], i64 2
+; CHECK-NEXT:    ret double [[ELT]]
+;
+  %ptrs = getelementptr double, double* %base, <4 x i64> <i64 0, i64 1, i64 2, i64 3>
+  %res = call <4 x double> @llvm.masked.gather.v4f64.p0v4f64(<4 x double*> %ptrs, i32 4, <4 x i1> <i1 true, i1 false, i1 true, i1 true>, <4 x double> undef)
+  %elt = extractelement <4 x double> %res, i64 2
+  ret double %elt
+}
+
+define <2 x double> @load_generic(<2 x double>* %ptr, double %pt,
+; CHECK-LABEL: @load_generic(
+; CHECK-NEXT:    [[PTV1:%.*]] = insertelement <2 x double> undef, double [[PT:%.*]], i64 0
+; CHECK-NEXT:    [[PTV2:%.*]] = shufflevector <2 x double> [[PTV1]], <2 x double> undef, <2 x i32> zeroinitializer
+; CHECK-NEXT:    [[RES:%.*]] = call <2 x double> @llvm.masked.load.v2f64.p0v2f64(<2 x double>* [[PTR:%.*]], i32 4, <2 x i1> [[MASK:%.*]], <2 x double> [[PTV2]])
+; CHECK-NEXT:    ret <2 x double> [[RES]]
+;
+  <2 x i1> %mask)  {
+  %ptv1 = insertelement <2 x double> undef, double %pt, i64 0
+  %ptv2 = insertelement <2 x double> %ptv1, double %pt, i64 1
+  %res = call <2 x double> @llvm.masked.load.v2f64.p0v2f64(<2 x double>* %ptr, i32 4, <2 x i1> %mask, <2 x double> %ptv2)
+  ret <2 x double> %res
+}
+
+define <2 x double> @load_speculative(<2 x double>* dereferenceable(16) %ptr,
+; CHECK-LABEL: @load_speculative(
+; CHECK-NEXT:    [[PTV1:%.*]] = insertelement <2 x double> undef, double [[PT:%.*]], i64 0
+; CHECK-NEXT:    [[PTV2:%.*]] = shufflevector <2 x double> [[PTV1]], <2 x double> undef, <2 x i32> zeroinitializer
+; CHECK-NEXT:    [[RES:%.*]] = call <2 x double> @llvm.masked.load.v2f64.p0v2f64(<2 x double>* nonnull [[PTR:%.*]], i32 4, <2 x i1> [[MASK:%.*]], <2 x double> [[PTV2]])
+; CHECK-NEXT:    ret <2 x double> [[RES]]
+;
+  double %pt, <2 x i1> %mask)  {
+  %ptv1 = insertelement <2 x double> undef, double %pt, i64 0
+  %ptv2 = insertelement <2 x double> %ptv1, double %pt, i64 1
+  %res = call <2 x double> @llvm.masked.load.v2f64.p0v2f64(<2 x double>* %ptr, i32 4, <2 x i1> %mask, <2 x double> %ptv2)
+  ret <2 x double> %res
+}
+
+; Can't speculate since only half of required size is known deref
+define <2 x double> @load_spec_neg_size(<2 x double>* dereferenceable(8) %ptr,
+; CHECK-LABEL: @load_spec_neg_size(
+; CHECK-NEXT:    [[PTV1:%.*]] = insertelement <2 x double> undef, double [[PT:%.*]], i64 0
+; CHECK-NEXT:    [[PTV2:%.*]] = shufflevector <2 x double> [[PTV1]], <2 x double> undef, <2 x i32> zeroinitializer
+; CHECK-NEXT:    [[RES:%.*]] = call <2 x double> @llvm.masked.load.v2f64.p0v2f64(<2 x double>* nonnull [[PTR:%.*]], i32 4, <2 x i1> [[MASK:%.*]], <2 x double> [[PTV2]])
+; CHECK-NEXT:    ret <2 x double> [[RES]]
+;
+  double %pt, <2 x i1> %mask)  {
+  %ptv1 = insertelement <2 x double> undef, double %pt, i64 0
+  %ptv2 = insertelement <2 x double> %ptv1, double %pt, i64 1
+  %res = call <2 x double> @llvm.masked.load.v2f64.p0v2f64(<2 x double>* %ptr, i32 4, <2 x i1> %mask, <2 x double> %ptv2)
+  ret <2 x double> %res
+}
+
+; Can only speculate one lane (but it's the only one active)
+define <2 x double> @load_spec_lan0(<2 x double>* dereferenceable(8) %ptr,
+; CHECK-LABEL: @load_spec_lan0(
+; CHECK-NEXT:    [[PTV1:%.*]] = insertelement <2 x double> undef, double [[PT:%.*]], i64 0
+; CHECK-NEXT:    [[PTV2:%.*]] = shufflevector <2 x double> [[PTV1]], <2 x double> undef, <2 x i32> zeroinitializer
+; CHECK-NEXT:    [[MASK2:%.*]] = insertelement <2 x i1> [[MASK:%.*]], i1 false, i64 1
+; CHECK-NEXT:    [[RES:%.*]] = call <2 x double> @llvm.masked.load.v2f64.p0v2f64(<2 x double>* nonnull [[PTR:%.*]], i32 4, <2 x i1> [[MASK2]], <2 x double> [[PTV2]])
+; CHECK-NEXT:    ret <2 x double> [[RES]]
+;
+  double %pt, <2 x i1> %mask)  {
+  %ptv1 = insertelement <2 x double> undef, double %pt, i64 0
+  %ptv2 = insertelement <2 x double> %ptv1, double %pt, i64 1
+  %mask2 = insertelement <2 x i1> %mask, i1 false, i64 1
+  %res = call <2 x double> @llvm.masked.load.v2f64.p0v2f64(<2 x double>* %ptr, i32 4, <2 x i1> %mask2, <2 x double> %ptv2)
+  ret <2 x double> %res
+}
+
+define void @store_zeromask(<2 x double>* %ptr, <2 x double> %val)  {
+; CHECK-LABEL: @store_zeromask(
+; CHECK-NEXT:    ret void
+;
+  call void @llvm.masked.store.v2f64.p0v2f64(<2 x double> %val, <2 x double>* %ptr, i32 4, <2 x i1> zeroinitializer)
+  ret void
+}
+
+define void @store_onemask(<2 x double>* %ptr, <2 x double> %val)  {
+; CHECK-LABEL: @store_onemask(
+; CHECK-NEXT:    store <2 x double> [[VAL:%.*]], <2 x double>* [[PTR:%.*]], align 4
+; CHECK-NEXT:    ret void
+;
+  call void @llvm.masked.store.v2f64.p0v2f64(<2 x double> %val, <2 x double>* %ptr, i32 4, <2 x i1> <i1 1, i1 1>)
+  ret void
+}
+
+define void @store_demandedelts(<2 x double>* %ptr, double %val)  {
+; CHECK-LABEL: @store_demandedelts(
+; CHECK-NEXT:    [[VALVEC2:%.*]] = insertelement <2 x double> undef, double [[VAL:%.*]], i32 0
+; CHECK-NEXT:    call void @llvm.masked.store.v2f64.p0v2f64(<2 x double> [[VALVEC2]], <2 x double>* [[PTR:%.*]], i32 4, <2 x i1> <i1 true, i1 false>)
+; CHECK-NEXT:    ret void
+;
+  %valvec1 = insertelement <2 x double> undef, double %val, i32 0
+  %valvec2 = insertelement <2 x double> %valvec1, double %val, i32 1
+  call void @llvm.masked.store.v2f64.p0v2f64(<2 x double> %valvec2, <2 x double>* %ptr, i32 4, <2 x i1> <i1 true, i1 false>)
+  ret void
+}
+
+define <2 x double> @gather_generic(<2 x double*> %ptrs, <2 x i1> %mask,
+; CHECK-LABEL: @gather_generic(
+; CHECK-NEXT:    [[RES:%.*]] = call <2 x double> @llvm.masked.gather.v2f64.v2p0f64(<2 x double*> [[PTRS:%.*]], i32 4, <2 x i1> [[MASK:%.*]], <2 x double> [[PASSTHRU:%.*]])
+; CHECK-NEXT:    ret <2 x double> [[RES]]
+;
+  <2 x double> %passthru)  {
+  %res = call <2 x double> @llvm.masked.gather.v2f64.v2p0f64(<2 x double*> %ptrs, i32 4, <2 x i1> %mask, <2 x double> %passthru)
+  ret <2 x double> %res
+}
+
+
+define <2 x double> @gather_zeromask(<2 x double*> %ptrs, <2 x double> %passthru)  {
+; CHECK-LABEL: @gather_zeromask(
+; CHECK-NEXT:    ret <2 x double> [[PASSTHRU:%.*]]
+;
+  %res = call <2 x double> @llvm.masked.gather.v2f64.v2p0f64(<2 x double*> %ptrs, i32 4, <2 x i1> zeroinitializer, <2 x double> %passthru)
+  ret <2 x double> %res
+}
+
+
+define <2 x double> @gather_onemask(<2 x double*> %ptrs, <2 x double> %passthru)  {
+; CHECK-LABEL: @gather_onemask(
+; CHECK-NEXT:    [[RES:%.*]] = call <2 x double> @llvm.masked.gather.v2f64.v2p0f64(<2 x double*> [[PTRS:%.*]], i32 4, <2 x i1> <i1 true, i1 true>, <2 x double> undef)
+; CHECK-NEXT:    ret <2 x double> [[RES]]
+;
+  %res = call <2 x double> @llvm.masked.gather.v2f64.v2p0f64(<2 x double*> %ptrs, i32 4, <2 x i1> <i1 true, i1 true>, <2 x double> %passthru)
+  ret <2 x double> %res
+}
+
+define <2 x double> @gather_lane0(double* %base, double %pt)  {
+; CHECK-LABEL: @gather_lane0(
+; CHECK-NEXT:    [[PTRS:%.*]] = getelementptr double, double* [[BASE:%.*]], <2 x i64> <i64 0, i64 undef>
+; CHECK-NEXT:    [[PT_V2:%.*]] = insertelement <2 x double> undef, double [[PT:%.*]], i64 1
+; CHECK-NEXT:    [[RES:%.*]] = call <2 x double> @llvm.masked.gather.v2f64.v2p0f64(<2 x double*> [[PTRS]], i32 4, <2 x i1> <i1 true, i1 false>, <2 x double> [[PT_V2]])
+; CHECK-NEXT:    ret <2 x double> [[RES]]
+;
+  %ptrs = getelementptr double, double *%base, <2 x i64> <i64 0, i64 1>
+  %pt_v1 = insertelement <2 x double> undef, double %pt, i64 0
+  %pt_v2 = insertelement <2 x double> %pt_v1, double %pt, i64 1
+  %res = call <2 x double> @llvm.masked.gather.v2f64.v2p0f64(<2 x double*> %ptrs, i32 4, <2 x i1> <i1 true, i1 false>, <2 x double> %pt_v2)
+  ret <2 x double> %res
+}
+
+define <2 x double> @gather_lane0_maybe(double* %base, double %pt,
+; CHECK-LABEL: @gather_lane0_maybe(
+; CHECK-NEXT:    [[PTRS:%.*]] = getelementptr double, double* [[BASE:%.*]], <2 x i64> <i64 0, i64 1>
+; CHECK-NEXT:    [[PT_V1:%.*]] = insertelement <2 x double> undef, double [[PT:%.*]], i64 0
+; CHECK-NEXT:    [[PT_V2:%.*]] = shufflevector <2 x double> [[PT_V1]], <2 x double> undef, <2 x i32> zeroinitializer
+; CHECK-NEXT:    [[MASK2:%.*]] = insertelement <2 x i1> [[MASK:%.*]], i1 false, i64 1
+; CHECK-NEXT:    [[RES:%.*]] = call <2 x double> @llvm.masked.gather.v2f64.v2p0f64(<2 x double*> [[PTRS]], i32 4, <2 x i1> [[MASK2]], <2 x double> [[PT_V2]])
+; CHECK-NEXT:    ret <2 x double> [[RES]]
+;
+  <2 x i1> %mask)  {
+  %ptrs = getelementptr double, double *%base, <2 x i64> <i64 0, i64 1>
+  %pt_v1 = insertelement <2 x double> undef, double %pt, i64 0
+  %pt_v2 = insertelement <2 x double> %pt_v1, double %pt, i64 1
+  %mask2 = insertelement <2 x i1> %mask, i1 false, i64 1
+  %res = call <2 x double> @llvm.masked.gather.v2f64.v2p0f64(<2 x double*> %ptrs, i32 4, <2 x i1> %mask2, <2 x double> %pt_v2)
+  ret <2 x double> %res
+}
+
+define <2 x double> @gather_lane0_maybe_spec(double* %base, double %pt,
+; CHECK-LABEL: @gather_lane0_maybe_spec(
+; CHECK-NEXT:    [[PTRS:%.*]] = getelementptr double, double* [[BASE:%.*]], <2 x i64> <i64 0, i64 1>
+; CHECK-NEXT:    [[PT_V1:%.*]] = insertelement <2 x double> undef, double [[PT:%.*]], i64 0
+; CHECK-NEXT:    [[PT_V2:%.*]] = shufflevector <2 x double> [[PT_V1]], <2 x double> undef, <2 x i32> zeroinitializer
+; CHECK-NEXT:    [[MASK2:%.*]] = insertelement <2 x i1> [[MASK:%.*]], i1 false, i64 1
+; CHECK-NEXT:    [[RES:%.*]] = call <2 x double> @llvm.masked.gather.v2f64.v2p0f64(<2 x double*> [[PTRS]], i32 4, <2 x i1> [[MASK2]], <2 x double> [[PT_V2]])
+; CHECK-NEXT:    ret <2 x double> [[RES]]
+;
+  <2 x i1> %mask)  {
+  %ptrs = getelementptr double, double *%base, <2 x i64> <i64 0, i64 1>
+  %pt_v1 = insertelement <2 x double> undef, double %pt, i64 0
+  %pt_v2 = insertelement <2 x double> %pt_v1, double %pt, i64 1
+  %mask2 = insertelement <2 x i1> %mask, i1 false, i64 1
+  %res = call <2 x double> @llvm.masked.gather.v2f64.v2p0f64(<2 x double*> %ptrs, i32 4, <2 x i1> %mask2, <2 x double> %pt_v2)
+  ret <2 x double> %res
+}
+
+
+define void @scatter_zeromask(<2 x double*> %ptrs, <2 x double> %val)  {
+; CHECK-LABEL: @scatter_zeromask(
+; CHECK-NEXT:    ret void
+;
+  call void @llvm.masked.scatter.v2f64.v2p0f64(<2 x double> %val, <2 x double*> %ptrs, i32 6, <2 x i1> zeroinitializer)
+  ret void
+}
+
+define void @scatter_demandedelts(double* %ptr, double %val)  {
+; CHECK-LABEL: @scatter_demandedelts(
+; CHECK-NEXT:    [[PTRS:%.*]] = getelementptr double, double* [[PTR:%.*]], <2 x i64> <i64 0, i64 undef>
+; CHECK-NEXT:    [[VALVEC2:%.*]] = insertelement <2 x double> undef, double [[VAL:%.*]], i32 0
+; CHECK-NEXT:    call void @llvm.masked.scatter.v2f64.v2p0f64(<2 x double> [[VALVEC2]], <2 x double*> [[PTRS]], i32 8, <2 x i1> <i1 true, i1 false>)
+; CHECK-NEXT:    ret void
+;
+  %ptrs = getelementptr double, double* %ptr, <2 x i64> <i64 0, i64 1>
+  %valvec1 = insertelement <2 x double> undef, double %val, i32 0
+  %valvec2 = insertelement <2 x double> %valvec1, double %val, i32 1
+  call void @llvm.masked.scatter.v2f64.v2p0f64(<2 x double> %valvec2, <2 x double*> %ptrs, i32 8, <2 x i1> <i1 true, i1 false>)
+  ret void
+}

Added: llvm/trunk/test/Transforms/InstCombine/max-of-nots.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/max-of-nots.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/max-of-nots.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/max-of-nots.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,360 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt -S -instcombine < %s | FileCheck %s
+
+define <2 x i32> @umin_of_nots(<2 x i32> %x, <2 x i32> %y) {
+; CHECK-LABEL: @umin_of_nots(
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp ult <2 x i32> [[Y:%.*]], [[X:%.*]]
+; CHECK-NEXT:    [[TMP2:%.*]] = select <2 x i1> [[TMP1]], <2 x i32> [[X]], <2 x i32> [[Y]]
+; CHECK-NEXT:    [[MIN:%.*]] = xor <2 x i32> [[TMP2]], <i32 -1, i32 -1>
+; CHECK-NEXT:    ret <2 x i32> [[MIN]]
+;
+  %notx = xor <2 x i32> %x, <i32 -1, i32 -1>
+  %noty = xor <2 x i32> %y, <i32 -1, i32 -1>
+  %cmp = icmp ult <2 x i32> %notx, %noty
+  %min = select <2 x i1> %cmp, <2 x i32> %notx, <2 x i32> %noty
+  ret <2 x i32> %min
+}
+
+define <2 x i32> @smin_of_nots(<2 x i32> %x, <2 x i32> %y) {
+; CHECK-LABEL: @smin_of_nots(
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp slt <2 x i32> [[Y:%.*]], [[X:%.*]]
+; CHECK-NEXT:    [[TMP2:%.*]] = select <2 x i1> [[TMP1]], <2 x i32> [[X]], <2 x i32> [[Y]]
+; CHECK-NEXT:    [[MIN:%.*]] = xor <2 x i32> [[TMP2]], <i32 -1, i32 -1>
+; CHECK-NEXT:    ret <2 x i32> [[MIN]]
+;
+  %notx = xor <2 x i32> %x, <i32 -1, i32 -1>
+  %noty = xor <2 x i32> %y, <i32 -1, i32 -1>
+  %cmp = icmp sle <2 x i32> %notx, %noty
+  %min = select <2 x i1> %cmp, <2 x i32> %notx, <2 x i32> %noty
+  ret <2 x i32> %min
+}
+
+define i32 @compute_min_2(i32 %x, i32 %y) {
+; CHECK-LABEL: @compute_min_2(
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp sgt i32 [[Y:%.*]], [[X:%.*]]
+; CHECK-NEXT:    [[TMP2:%.*]] = select i1 [[TMP1]], i32 [[X]], i32 [[Y]]
+; CHECK-NEXT:    ret i32 [[TMP2]]
+;
+  %not_x = sub i32 -1, %x
+  %not_y = sub i32 -1, %y
+  %cmp = icmp sgt i32 %not_x, %not_y
+  %not_min = select i1 %cmp, i32 %not_x, i32 %not_y
+  %min = sub i32 -1, %not_min
+  ret i32 %min
+}
+
+declare void @extra_use(i8)
+define i8 @umin_not_1_extra_use(i8 %x, i8 %y) {
+; CHECK-LABEL: @umin_not_1_extra_use(
+; CHECK-NEXT:    [[NX:%.*]] = xor i8 [[X:%.*]], -1
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp ult i8 [[X]], [[Y:%.*]]
+; CHECK-NEXT:    [[TMP2:%.*]] = select i1 [[TMP1]], i8 [[Y]], i8 [[X]]
+; CHECK-NEXT:    [[MINXY:%.*]] = xor i8 [[TMP2]], -1
+; CHECK-NEXT:    call void @extra_use(i8 [[NX]])
+; CHECK-NEXT:    ret i8 [[MINXY]]
+;
+  %nx = xor i8 %x, -1
+  %ny = xor i8 %y, -1
+  %cmpxy = icmp ult i8 %nx, %ny
+  %minxy = select i1 %cmpxy, i8 %nx, i8 %ny
+  call void @extra_use(i8 %nx)
+  ret i8 %minxy
+}
+
+define i8 @umin_not_2_extra_use(i8 %x, i8 %y) {
+; CHECK-LABEL: @umin_not_2_extra_use(
+; CHECK-NEXT:    [[NX:%.*]] = xor i8 [[X:%.*]], -1
+; CHECK-NEXT:    [[NY:%.*]] = xor i8 [[Y:%.*]], -1
+; CHECK-NEXT:    [[CMPXY:%.*]] = icmp ult i8 [[NX]], [[NY]]
+; CHECK-NEXT:    [[MINXY:%.*]] = select i1 [[CMPXY]], i8 [[NX]], i8 [[NY]]
+; CHECK-NEXT:    call void @extra_use(i8 [[NX]])
+; CHECK-NEXT:    call void @extra_use(i8 [[NY]])
+; CHECK-NEXT:    ret i8 [[MINXY]]
+;
+  %nx = xor i8 %x, -1
+  %ny = xor i8 %y, -1
+  %cmpxy = icmp ult i8 %nx, %ny
+  %minxy = select i1 %cmpxy, i8 %nx, i8 %ny
+  call void @extra_use(i8 %nx)
+  call void @extra_use(i8 %ny)
+  ret i8 %minxy
+}
+
+; PR35834 - https://bugs.llvm.org/show_bug.cgi?id=35834
+
+define i8 @umin3_not(i8 %x, i8 %y, i8 %z) {
+; CHECK-LABEL: @umin3_not(
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp ult i8 [[Z:%.*]], [[X:%.*]]
+; CHECK-NEXT:    [[TMP2:%.*]] = select i1 [[TMP1]], i8 [[X]], i8 [[Z]]
+; CHECK-NEXT:    [[TMP3:%.*]] = icmp ugt i8 [[TMP2]], [[Y:%.*]]
+; CHECK-NEXT:    [[R_V:%.*]] = select i1 [[TMP3]], i8 [[TMP2]], i8 [[Y]]
+; CHECK-NEXT:    [[R:%.*]] = xor i8 [[R_V]], -1
+; CHECK-NEXT:    ret i8 [[R]]
+;
+  %nx = xor i8 %x, -1
+  %ny = xor i8 %y, -1
+  %nz = xor i8 %z, -1
+  %cmpyx = icmp ult i8 %y, %x
+  %cmpxz = icmp ult i8 %nx, %nz
+  %minxz = select i1 %cmpxz, i8 %nx, i8 %nz
+  %cmpyz = icmp ult i8 %ny, %nz
+  %minyz = select i1 %cmpyz, i8 %ny, i8 %nz
+  %r = select i1 %cmpyx, i8 %minxz, i8 %minyz
+  ret i8 %r
+}
+
+; PR35875 - https://bugs.llvm.org/show_bug.cgi?id=35875
+
+define i8 @umin3_not_more_uses(i8 %x, i8 %y, i8 %z) {
+; CHECK-LABEL: @umin3_not_more_uses(
+; CHECK-NEXT:    [[NX:%.*]] = xor i8 [[X:%.*]], -1
+; CHECK-NEXT:    [[NY:%.*]] = xor i8 [[Y:%.*]], -1
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp ult i8 [[X]], [[Z:%.*]]
+; CHECK-NEXT:    [[TMP2:%.*]] = select i1 [[TMP1]], i8 [[Z]], i8 [[X]]
+; CHECK-NEXT:    [[TMP3:%.*]] = icmp ugt i8 [[TMP2]], [[Y]]
+; CHECK-NEXT:    [[TMP4:%.*]] = select i1 [[TMP3]], i8 [[TMP2]], i8 [[Y]]
+; CHECK-NEXT:    [[R:%.*]] = xor i8 [[TMP4]], -1
+; CHECK-NEXT:    call void @extra_use(i8 [[NX]])
+; CHECK-NEXT:    call void @extra_use(i8 [[NY]])
+; CHECK-NEXT:    ret i8 [[R]]
+;
+  %nx = xor i8 %x, -1
+  %ny = xor i8 %y, -1
+  %nz = xor i8 %z, -1
+  %cmpxz = icmp ult i8 %nx, %nz
+  %minxz = select i1 %cmpxz, i8 %nx, i8 %nz
+  %cmpyz = icmp ult i8 %ny, %nz
+  %minyz = select i1 %cmpyz, i8 %ny, i8 %nz
+  %cmpyx = icmp ult i8 %y, %x
+  %r = select i1 %cmpyx, i8 %minxz, i8 %minyz
+  call void @extra_use(i8 %nx)
+  call void @extra_use(i8 %ny)
+  ret i8 %r
+}
+
+declare void @use8(i8)
+
+define i8 @umin3_not_all_ops_extra_uses(i8 %x, i8 %y, i8 %z) {
+; CHECK-LABEL: @umin3_not_all_ops_extra_uses(
+; CHECK-NEXT:    [[XN:%.*]] = xor i8 [[X:%.*]], -1
+; CHECK-NEXT:    [[YN:%.*]] = xor i8 [[Y:%.*]], -1
+; CHECK-NEXT:    [[ZN:%.*]] = xor i8 [[Z:%.*]], -1
+; CHECK-NEXT:    [[CMPXZ:%.*]] = icmp ult i8 [[XN]], [[ZN]]
+; CHECK-NEXT:    [[MINXZ:%.*]] = select i1 [[CMPXZ]], i8 [[XN]], i8 [[ZN]]
+; CHECK-NEXT:    [[CMPXYZ:%.*]] = icmp ult i8 [[MINXZ]], [[YN]]
+; CHECK-NEXT:    [[MINXYZ:%.*]] = select i1 [[CMPXYZ]], i8 [[MINXZ]], i8 [[YN]]
+; CHECK-NEXT:    call void @use8(i8 [[XN]])
+; CHECK-NEXT:    call void @use8(i8 [[YN]])
+; CHECK-NEXT:    call void @use8(i8 [[ZN]])
+; CHECK-NEXT:    ret i8 [[MINXYZ]]
+;
+  %xn = xor i8 %x, -1
+  %yn = xor i8 %y, -1
+  %zn = xor i8 %z, -1
+  %cmpxz = icmp ult i8 %xn, %zn
+  %minxz = select i1 %cmpxz, i8 %xn, i8 %zn
+  %cmpxyz = icmp ult i8 %minxz, %yn
+  %minxyz = select i1 %cmpxyz, i8 %minxz, i8 %yn
+  call void @use8(i8 %xn)
+  call void @use8(i8 %yn)
+  call void @use8(i8 %zn)
+  ret i8 %minxyz
+}
+
+define i32 @compute_min_3(i32 %x, i32 %y, i32 %z) {
+; CHECK-LABEL: @compute_min_3(
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp sgt i32 [[Y:%.*]], [[X:%.*]]
+; CHECK-NEXT:    [[TMP2:%.*]] = select i1 [[TMP1]], i32 [[X]], i32 [[Y]]
+; CHECK-NEXT:    [[TMP3:%.*]] = icmp slt i32 [[TMP2]], [[Z:%.*]]
+; CHECK-NEXT:    [[TMP4:%.*]] = select i1 [[TMP3]], i32 [[TMP2]], i32 [[Z]]
+; CHECK-NEXT:    ret i32 [[TMP4]]
+;
+  %not_x = sub i32 -1, %x
+  %not_y = sub i32 -1, %y
+  %not_z = sub i32 -1, %z
+  %cmp_1 = icmp sgt i32 %not_x, %not_y
+  %not_min_1 = select i1 %cmp_1, i32 %not_x, i32 %not_y
+  %cmp_2 = icmp sgt i32 %not_min_1, %not_z
+  %not_min_2 = select i1 %cmp_2, i32 %not_min_1, i32 %not_z
+  %min = sub i32 -1, %not_min_2
+  ret i32 %min
+}
+
+; Don't increase the critical path by moving the 'not' op after the 'select'.
+
+define i32 @compute_min_arithmetic(i32 %x, i32 %y) {
+; CHECK-LABEL: @compute_min_arithmetic(
+; CHECK-NEXT:    [[NOT_VALUE:%.*]] = sub i32 3, [[X:%.*]]
+; CHECK-NEXT:    [[NOT_Y:%.*]] = xor i32 [[Y:%.*]], -1
+; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt i32 [[NOT_VALUE]], [[NOT_Y]]
+; CHECK-NEXT:    [[NOT_MIN:%.*]] = select i1 [[CMP]], i32 [[NOT_VALUE]], i32 [[NOT_Y]]
+; CHECK-NEXT:    ret i32 [[NOT_MIN]]
+;
+  %not_value = sub i32 3, %x
+  %not_y = sub i32 -1, %y
+  %cmp = icmp sgt i32 %not_value, %not_y
+  %not_min = select i1 %cmp, i32 %not_value, i32 %not_y
+  ret i32 %not_min
+}
+
+declare void @fake_use(i32)
+
+define i32 @compute_min_pessimization(i32 %x, i32 %y) {
+; CHECK-LABEL: @compute_min_pessimization(
+; CHECK-NEXT:    [[NOT_VALUE:%.*]] = sub i32 3, [[X:%.*]]
+; CHECK-NEXT:    call void @fake_use(i32 [[NOT_VALUE]])
+; CHECK-NEXT:    [[TMP1:%.*]] = add i32 [[X]], -4
+; CHECK-NEXT:    [[TMP2:%.*]] = icmp slt i32 [[TMP1]], [[Y:%.*]]
+; CHECK-NEXT:    [[MIN:%.*]] = select i1 [[TMP2]], i32 [[TMP1]], i32 [[Y]]
+; CHECK-NEXT:    ret i32 [[MIN]]
+;
+  %not_value = sub i32 3, %x
+  call void @fake_use(i32 %not_value)
+  %not_y = sub i32 -1, %y
+  %cmp = icmp sgt i32 %not_value, %not_y
+  %not_min = select i1 %cmp, i32 %not_value, i32 %not_y
+  %min = sub i32 -1, %not_min
+  ret i32 %min
+}
+
+define i32 @max_of_nots(i32 %x, i32 %y) {
+; CHECK-LABEL: @max_of_nots(
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp sgt i32 [[Y:%.*]], 0
+; CHECK-NEXT:    [[TMP2:%.*]] = select i1 [[TMP1]], i32 [[Y]], i32 0
+; CHECK-NEXT:    [[TMP3:%.*]] = icmp slt i32 [[TMP2]], [[X:%.*]]
+; CHECK-NEXT:    [[TMP4:%.*]] = select i1 [[TMP3]], i32 [[TMP2]], i32 [[X]]
+; CHECK-NEXT:    [[TMP5:%.*]] = xor i32 [[TMP4]], -1
+; CHECK-NEXT:    ret i32 [[TMP5]]
+;
+  %c0 = icmp sgt i32 %y, 0
+  %xor_y = xor i32 %y, -1
+  %s0 = select i1 %c0, i32 %xor_y, i32 -1
+  %xor_x = xor i32 %x, -1
+  %c1 = icmp slt i32 %s0, %xor_x
+  %smax96 = select i1 %c1, i32 %xor_x, i32 %s0
+  ret i32 %smax96
+}
+
+ ; negative test case (i.e. can not simplify) : ABS(MIN(NOT x,y))
+define i32 @abs_of_min_of_not(i32 %x, i32 %y) {
+; CHECK-LABEL: @abs_of_min_of_not(
+; CHECK-NEXT:    [[XORD:%.*]] = xor i32 [[X:%.*]], -1
+; CHECK-NEXT:    [[YADD:%.*]] = add i32 [[Y:%.*]], 2
+; CHECK-NEXT:    [[COND_I:%.*]] = icmp slt i32 [[YADD]], [[XORD]]
+; CHECK-NEXT:    [[MIN:%.*]] = select i1 [[COND_I]], i32 [[YADD]], i32 [[XORD]]
+; CHECK-NEXT:    [[CMP2:%.*]] = icmp slt i32 [[MIN]], 0
+; CHECK-NEXT:    [[SUB:%.*]] = sub i32 0, [[MIN]]
+; CHECK-NEXT:    [[ABS:%.*]] = select i1 [[CMP2]], i32 [[SUB]], i32 [[MIN]]
+; CHECK-NEXT:    ret i32 [[ABS]]
+;
+
+  %xord = xor i32 %x, -1
+  %yadd = add i32 %y, 2
+  %cond.i = icmp sge i32 %yadd, %xord
+  %min = select i1 %cond.i, i32 %xord, i32 %yadd
+  %cmp2 = icmp sgt i32 %min, -1
+  %sub = sub i32 0, %min
+  %abs = select i1 %cmp2, i32 %min, i32 %sub
+  ret i32  %abs
+}
+
+define <2 x i32> @max_of_nots_vec(<2 x i32> %x, <2 x i32> %y) {
+; CHECK-LABEL: @max_of_nots_vec(
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp sgt <2 x i32> [[Y:%.*]], zeroinitializer
+; CHECK-NEXT:    [[TMP2:%.*]] = select <2 x i1> [[TMP1]], <2 x i32> [[Y]], <2 x i32> zeroinitializer
+; CHECK-NEXT:    [[TMP3:%.*]] = icmp slt <2 x i32> [[TMP2]], [[X:%.*]]
+; CHECK-NEXT:    [[TMP4:%.*]] = select <2 x i1> [[TMP3]], <2 x i32> [[TMP2]], <2 x i32> [[X]]
+; CHECK-NEXT:    [[TMP5:%.*]] = xor <2 x i32> [[TMP4]], <i32 -1, i32 -1>
+; CHECK-NEXT:    ret <2 x i32> [[TMP5]]
+;
+  %c0 = icmp sgt <2 x i32> %y, zeroinitializer
+  %xor_y = xor <2 x i32> %y, <i32 -1, i32 -1>
+  %s0 = select <2 x i1> %c0, <2 x i32> %xor_y, <2 x i32> <i32 -1, i32 -1>
+  %xor_x = xor <2 x i32> %x, <i32 -1, i32 -1>
+  %c1 = icmp slt <2 x i32> %s0, %xor_x
+  %smax96 = select <2 x i1> %c1, <2 x i32> %xor_x, <2 x i32> %s0
+  ret <2 x i32> %smax96
+}
+
+define <2 x i37> @max_of_nots_weird_type_vec(<2 x i37> %x, <2 x i37> %y) {
+; CHECK-LABEL: @max_of_nots_weird_type_vec(
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp sgt <2 x i37> [[Y:%.*]], zeroinitializer
+; CHECK-NEXT:    [[TMP2:%.*]] = select <2 x i1> [[TMP1]], <2 x i37> [[Y]], <2 x i37> zeroinitializer
+; CHECK-NEXT:    [[TMP3:%.*]] = icmp slt <2 x i37> [[TMP2]], [[X:%.*]]
+; CHECK-NEXT:    [[TMP4:%.*]] = select <2 x i1> [[TMP3]], <2 x i37> [[TMP2]], <2 x i37> [[X]]
+; CHECK-NEXT:    [[TMP5:%.*]] = xor <2 x i37> [[TMP4]], <i37 -1, i37 -1>
+; CHECK-NEXT:    ret <2 x i37> [[TMP5]]
+;
+  %c0 = icmp sgt <2 x i37> %y, zeroinitializer
+  %xor_y = xor <2 x i37> %y, <i37 -1, i37 -1>
+  %s0 = select <2 x i1> %c0, <2 x i37> %xor_y, <2 x i37> <i37 -1, i37 -1>
+  %xor_x = xor <2 x i37> %x, <i37 -1, i37 -1>
+  %c1 = icmp slt <2 x i37> %s0, %xor_x
+  %smax96 = select <2 x i1> %c1, <2 x i37> %xor_x, <2 x i37> %s0
+  ret <2 x i37> %smax96
+}
+
+; max(min(%a, -1), -1) == -1
+define i32 @max_of_min(i32 %a) {
+; CHECK-LABEL: @max_of_min(
+; CHECK-NEXT:    ret i32 -1
+;
+  %not_a = xor i32 %a, -1
+  %c0 = icmp sgt i32 %a, 0
+  %s0 = select i1 %c0, i32 %not_a, i32 -1
+  %c1 = icmp sgt i32 %s0, -1
+  %s1 = select i1 %c1, i32 %s0, i32 -1
+  ret i32 %s1
+}
+
+; max(min(%a, -1), -1) == -1 (swap predicate and select ops)
+define i32 @max_of_min_swap(i32 %a) {
+; CHECK-LABEL: @max_of_min_swap(
+; CHECK-NEXT:    ret i32 -1
+;
+  %not_a = xor i32 %a, -1
+  %c0 = icmp slt i32 %a, 0
+  %s0 = select i1 %c0, i32 -1, i32 %not_a
+  %c1 = icmp sgt i32 %s0, -1
+  %s1 = select i1 %c1, i32 %s0, i32 -1
+  ret i32 %s1
+}
+
+; min(max(%a, -1), -1) == -1
+define i32 @min_of_max(i32 %a) {
+; CHECK-LABEL: @min_of_max(
+; CHECK-NEXT:    ret i32 -1
+;
+  %not_a = xor i32 %a, -1
+  %c0 = icmp slt i32 %a, 0
+  %s0 = select i1 %c0, i32 %not_a, i32 -1
+  %c1 = icmp slt i32 %s0, -1
+  %s1 = select i1 %c1, i32 %s0, i32 -1
+  ret i32 %s1
+}
+
+; min(max(%a, -1), -1) == -1 (swap predicate and select ops)
+define i32 @min_of_max_swap(i32 %a) {
+; CHECK-LABEL: @min_of_max_swap(
+; CHECK-NEXT:    ret i32 -1
+;
+  %not_a = xor i32 %a, -1
+  %c0 = icmp sgt i32 %a, 0
+  %s0 = select i1 %c0, i32 -1, i32 %not_a
+  %c1 = icmp slt i32 %s0, -1
+  %s1 = select i1 %c1, i32 %s0, i32 -1
+  ret i32 %s1
+}
+
+define <2 x i32> @max_of_min_vec(<2 x i32> %a) {
+; CHECK-LABEL: @max_of_min_vec(
+; CHECK-NEXT:    ret <2 x i32> <i32 -1, i32 -1>
+;
+  %not_a = xor <2 x i32> %a, <i32 -1, i32 -1>
+  %c0 = icmp sgt <2 x i32> %a, zeroinitializer
+  %s0 = select <2 x i1> %c0, <2 x i32> %not_a, <2 x i32> <i32 -1, i32 -1>
+  %c1 = icmp sgt <2 x i32> %s0, <i32 -1, i32 -1>
+  %s1 = select <2 x i1> %c1, <2 x i32> %s0, <2 x i32> <i32 -1, i32 -1>
+  ret <2 x i32> %s1
+}
+

Added: llvm/trunk/test/Transforms/InstCombine/max_known_bits.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/max_known_bits.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/max_known_bits.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/max_known_bits.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,95 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt -S -instcombine < %s | FileCheck %s
+
+define i16 @foo(i16 %x)  {
+; CHECK-LABEL: @foo(
+; CHECK-NEXT:    [[T1:%.*]] = and i16 [[X:%.*]], 255
+; CHECK-NEXT:    ret i16 [[T1]]
+;
+  %t1 = and i16 %x, 255
+  %t2 = zext i16 %t1 to i32
+  %t3 = icmp ult i32 %t2, 255
+  %t4 = select i1 %t3, i32 %t2, i32 255
+  %t5 = trunc i32 %t4 to i16
+  %t6 = and i16 %t5, 255
+  ret i16 %t6
+}
+
+; This contains a min/max pair to clamp a value to 12 bits.
+; By analyzing the clamp pattern, we can tell the add doesn't have signed overflow.
+define i16 @min_max_clamp(i16 %x) {
+; CHECK-LABEL: @min_max_clamp(
+; CHECK-NEXT:    [[A:%.*]] = icmp sgt i16 [[X:%.*]], -2048
+; CHECK-NEXT:    [[B:%.*]] = select i1 [[A]], i16 [[X]], i16 -2048
+; CHECK-NEXT:    [[C:%.*]] = icmp slt i16 [[B]], 2047
+; CHECK-NEXT:    [[D:%.*]] = select i1 [[C]], i16 [[B]], i16 2047
+; CHECK-NEXT:    [[E:%.*]] = add nsw i16 [[D]], 1
+; CHECK-NEXT:    ret i16 [[E]]
+;
+  %a = icmp sgt i16 %x, -2048
+  %b = select i1 %a, i16 %x, i16 -2048
+  %c = icmp slt i16 %b, 2047
+  %d = select i1 %c, i16 %b, i16 2047
+  %e = add i16 %d, 1
+  ret i16 %e
+}
+
+; Same as above with min/max reversed.
+define i16 @min_max_clamp_2(i16 %x) {
+; CHECK-LABEL: @min_max_clamp_2(
+; CHECK-NEXT:    [[A:%.*]] = icmp slt i16 [[X:%.*]], 2047
+; CHECK-NEXT:    [[B:%.*]] = select i1 [[A]], i16 [[X]], i16 2047
+; CHECK-NEXT:    [[C:%.*]] = icmp sgt i16 [[B]], -2048
+; CHECK-NEXT:    [[D:%.*]] = select i1 [[C]], i16 [[B]], i16 -2048
+; CHECK-NEXT:    [[E:%.*]] = add nsw i16 [[D]], 1
+; CHECK-NEXT:    ret i16 [[E]]
+;
+  %a = icmp slt i16 %x, 2047
+  %b = select i1 %a, i16 %x, i16 2047
+  %c = icmp sgt i16 %b, -2048
+  %d = select i1 %c, i16 %b, i16 -2048
+  %e = add i16 %d, 1
+  ret i16 %e
+}
+
+; This contains a min/max pair to clamp a value to 12 bits.
+; By analyzing the clamp pattern, we can tell that the second add doesn't
+; overflow the original type and can be moved before the extend.
+define i32 @min_max_clamp_3(i16 %x) {
+; CHECK-LABEL: @min_max_clamp_3(
+; CHECK-NEXT:    [[A:%.*]] = icmp sgt i16 [[X:%.*]], -2048
+; CHECK-NEXT:    [[B:%.*]] = select i1 [[A]], i16 [[X]], i16 -2048
+; CHECK-NEXT:    [[C:%.*]] = icmp slt i16 [[B]], 2047
+; CHECK-NEXT:    [[D:%.*]] = select i1 [[C]], i16 [[B]], i16 2047
+; CHECK-NEXT:    [[G:%.*]] = sext i16 [[D]] to i32
+; CHECK-NEXT:    ret i32 [[G]]
+;
+  %a = icmp sgt i16 %x, -2048
+  %b = select i1 %a, i16 %x, i16 -2048
+  %c = icmp slt i16 %b, 2047
+  %d = select i1 %c, i16 %b, i16 2047
+  %e = add i16 %d, 1
+  %f = sext i16 %e to i32
+  %g = add i32 %f, -1
+  ret i32 %g
+}
+
+; Same as above with min/max order reversed
+define i32 @min_max_clamp_4(i16 %x) {
+; CHECK-LABEL: @min_max_clamp_4(
+; CHECK-NEXT:    [[A:%.*]] = icmp slt i16 [[X:%.*]], 2047
+; CHECK-NEXT:    [[B:%.*]] = select i1 [[A]], i16 [[X]], i16 2047
+; CHECK-NEXT:    [[C:%.*]] = icmp sgt i16 [[B]], -2048
+; CHECK-NEXT:    [[D:%.*]] = select i1 [[C]], i16 [[B]], i16 -2048
+; CHECK-NEXT:    [[G:%.*]] = sext i16 [[D]] to i32
+; CHECK-NEXT:    ret i32 [[G]]
+;
+  %a = icmp slt i16 %x, 2047
+  %b = select i1 %a, i16 %x, i16 2047
+  %c = icmp sgt i16 %b, -2048
+  %d = select i1 %c, i16 %b, i16 -2048
+  %e = add i16 %d, 1
+  %f = sext i16 %e to i32
+  %g = add i32 %f, -1
+  ret i32 %g
+}

Added: llvm/trunk/test/Transforms/InstCombine/maximum.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/maximum.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/maximum.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/maximum.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,292 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt -S -instcombine < %s | FileCheck %s
+
+declare float @llvm.maximum.f32(float, float)
+declare <2 x float> @llvm.maximum.v2f32(<2 x float>, <2 x float>)
+declare <4 x float> @llvm.maximum.v4f32(<4 x float>, <4 x float>)
+
+declare double @llvm.maximum.f64(double, double)
+declare <2 x double> @llvm.maximum.v2f64(<2 x double>, <2 x double>)
+
+define float @constant_fold_maximum_f32() {
+; CHECK-LABEL: @constant_fold_maximum_f32(
+; CHECK-NEXT:    ret float 2.000000e+00
+;
+  %x = call float @llvm.maximum.f32(float 1.0, float 2.0)
+  ret float %x
+}
+
+define float @constant_fold_maximum_f32_inv() {
+; CHECK-LABEL: @constant_fold_maximum_f32_inv(
+; CHECK-NEXT:    ret float 2.000000e+00
+;
+  %x = call float @llvm.maximum.f32(float 2.0, float 1.0)
+  ret float %x
+}
+
+define float @constant_fold_maximum_f32_nan0() {
+; CHECK-LABEL: @constant_fold_maximum_f32_nan0(
+; CHECK-NEXT:    ret float 0x7FF8000000000000
+;
+  %x = call float @llvm.maximum.f32(float 0x7FF8000000000000, float 2.0)
+  ret float %x
+}
+
+define float @constant_fold_maximum_f32_nan1() {
+; CHECK-LABEL: @constant_fold_maximum_f32_nan1(
+; CHECK-NEXT:    ret float 0x7FF8000000000000
+;
+  %x = call float @llvm.maximum.f32(float 2.0, float 0x7FF8000000000000)
+  ret float %x
+}
+
+define float @constant_fold_maximum_f32_nan_nan() {
+; CHECK-LABEL: @constant_fold_maximum_f32_nan_nan(
+; CHECK-NEXT:    ret float 0x7FF8000000000000
+;
+  %x = call float @llvm.maximum.f32(float 0x7FF8000000000000, float 0x7FF8000000000000)
+  ret float %x
+}
+
+define float @constant_fold_maximum_f32_p0_p0() {
+; CHECK-LABEL: @constant_fold_maximum_f32_p0_p0(
+; CHECK-NEXT:    ret float 0.000000e+00
+;
+  %x = call float @llvm.maximum.f32(float 0.0, float 0.0)
+  ret float %x
+}
+
+define float @constant_fold_maximum_f32_p0_n0() {
+; CHECK-LABEL: @constant_fold_maximum_f32_p0_n0(
+; CHECK-NEXT:    ret float 0.000000e+00
+;
+  %x = call float @llvm.maximum.f32(float 0.0, float -0.0)
+  ret float %x
+}
+
+define float @constant_fold_maximum_f32_n0_p0() {
+; CHECK-LABEL: @constant_fold_maximum_f32_n0_p0(
+; CHECK-NEXT:    ret float 0.000000e+00
+;
+  %x = call float @llvm.maximum.f32(float -0.0, float 0.0)
+  ret float %x
+}
+
+define float @constant_fold_maximum_f32_n0_n0() {
+; CHECK-LABEL: @constant_fold_maximum_f32_n0_n0(
+; CHECK-NEXT:    ret float -0.000000e+00
+;
+  %x = call float @llvm.maximum.f32(float -0.0, float -0.0)
+  ret float %x
+}
+
+define <4 x float> @constant_fold_maximum_v4f32() {
+; CHECK-LABEL: @constant_fold_maximum_v4f32(
+; CHECK-NEXT:    ret <4 x float> <float 2.000000e+00, float 8.000000e+00, float 1.000000e+01, float 9.000000e+00>
+;
+  %x = call <4 x float> @llvm.maximum.v4f32(<4 x float> <float 1.0, float 8.0, float 3.0, float 9.0>, <4 x float> <float 2.0, float 2.0, float 10.0, float 5.0>)
+  ret <4 x float> %x
+}
+
+define double @constant_fold_maximum_f64() {
+; CHECK-LABEL: @constant_fold_maximum_f64(
+; CHECK-NEXT:    ret double 2.000000e+00
+;
+  %x = call double @llvm.maximum.f64(double 1.0, double 2.0)
+  ret double %x
+}
+
+define double @constant_fold_maximum_f64_nan0() {
+; CHECK-LABEL: @constant_fold_maximum_f64_nan0(
+; CHECK-NEXT:    ret double 0x7FF8000000000000
+;
+  %x = call double @llvm.maximum.f64(double 0x7FF8000000000000, double 2.0)
+  ret double %x
+}
+
+define double @constant_fold_maximum_f64_nan1() {
+; CHECK-LABEL: @constant_fold_maximum_f64_nan1(
+; CHECK-NEXT:    ret double 0x7FF8000000000000
+;
+  %x = call double @llvm.maximum.f64(double 2.0, double 0x7FF8000000000000)
+  ret double %x
+}
+
+define double @constant_fold_maximum_f64_nan_nan() {
+; CHECK-LABEL: @constant_fold_maximum_f64_nan_nan(
+; CHECK-NEXT:    ret double 0x7FF8000000000000
+;
+  %x = call double @llvm.maximum.f64(double 0x7FF8000000000000, double 0x7FF8000000000000)
+  ret double %x
+}
+
+define float @canonicalize_constant_maximum_f32(float %x) {
+; CHECK-LABEL: @canonicalize_constant_maximum_f32(
+; CHECK-NEXT:    [[Y:%.*]] = call float @llvm.maximum.f32(float [[X:%.*]], float 1.000000e+00)
+; CHECK-NEXT:    ret float [[Y]]
+;
+  %y = call float @llvm.maximum.f32(float 1.0, float %x)
+  ret float %y
+}
+
+define float @maximum_f32_nan_val(float %x) {
+; CHECK-LABEL: @maximum_f32_nan_val(
+; CHECK-NEXT:    ret float 0x7FF8000000000000
+;
+  %y = call float @llvm.maximum.f32(float 0x7FF8000000000000, float %x)
+  ret float %y
+}
+
+define float @maximum_f32_val_nan(float %x) {
+; CHECK-LABEL: @maximum_f32_val_nan(
+; CHECK-NEXT:    ret float 0x7FF8000000000000
+;
+  %y = call float @llvm.maximum.f32(float %x, float 0x7FF8000000000000)
+  ret float %y
+}
+
+define float @maximum_f32_1_maximum_val_p0(float %x) {
+; CHECK-LABEL: @maximum_f32_1_maximum_val_p0(
+; CHECK-NEXT: [[RES:%.*]] = call float @llvm.maximum.f32(float %x, float 1.000000e+00)
+; CHECK-NEXT: ret float [[RES]]
+  %y = call float @llvm.maximum.f32(float %x, float 0.0)
+  %z = call float @llvm.maximum.f32(float %y, float 1.0)
+  ret float %z
+}
+
+define float @maximum_f32_1_maximum_p0_val_fast(float %x) {
+; CHECK-LABEL: @maximum_f32_1_maximum_p0_val_fast(
+; CHECK-NEXT: [[RES:%.*]] = call fast float @llvm.maximum.f32(float %x, float 1.000000e+00)
+; CHECK-NEXT: ret float [[RES]]
+  %y = call float @llvm.maximum.f32(float 0.0, float %x)
+  %z = call fast float @llvm.maximum.f32(float %y, float 1.0)
+  ret float %z
+}
+
+define float @maximum_f32_1_maximum_p0_val_nnan_ninf(float %x) {
+; CHECK-LABEL: @maximum_f32_1_maximum_p0_val_nnan_ninf(
+; CHECK-NEXT: [[RES:%.*]] = call nnan ninf float @llvm.maximum.f32(float %x, float 1.000000e+00)
+; CHECK-NEXT: ret float [[RES]]
+  %y = call float @llvm.maximum.f32(float 0.0, float %x)
+  %z = call nnan ninf float @llvm.maximum.f32(float %y, float 1.0)
+  ret float %z
+}
+
+define float @maximum_f32_p0_maximum_val_n0(float %x) {
+; CHECK-LABEL: @maximum_f32_p0_maximum_val_n0(
+; CHECK-NEXT: [[RES:%.*]] = call float @llvm.maximum.f32(float %x, float 0.000000e+00)
+; CHECK-NEXT: ret float [[RES]]
+  %y = call float @llvm.maximum.f32(float %x, float -0.0)
+  %z = call float @llvm.maximum.f32(float %y, float 0.0)
+  ret float %z
+}
+
+define float @maximum_f32_1_maximum_p0_val(float %x) {
+; CHECK-LABEL: @maximum_f32_1_maximum_p0_val(
+; CHECK-NEXT: [[RES:%.*]] = call float @llvm.maximum.f32(float %x, float 1.000000e+00)
+; CHECK-NEXT: ret float [[RES]]
+  %y = call float @llvm.maximum.f32(float 0.0, float %x)
+  %z = call float @llvm.maximum.f32(float %y, float 1.0)
+  ret float %z
+}
+
+define <2 x float> @maximum_f32_1_maximum_val_p0_val_v2f32(<2 x float> %x) {
+; CHECK-LABEL: @maximum_f32_1_maximum_val_p0_val_v2f32(
+; CHECK-NEXT: [[RES:%.*]] = call <2 x float> @llvm.maximum.v2f32(<2 x float> %x, <2 x float> <float 1.000000e+00, float 1.000000e+00>)
+; CHECK-NEXT: ret <2 x float> [[RES]]
+  %y = call <2 x float> @llvm.maximum.v2f32(<2 x float> %x, <2 x float> zeroinitializer)
+  %z = call <2 x float> @llvm.maximum.v2f32(<2 x float> %y, <2 x float><float 1.0, float 1.0>)
+  ret <2 x float> %z
+}
+
+define float @maximum4(float %x, float %y, float %z, float %w) {
+; CHECK-LABEL: @maximum4(
+; CHECK-NEXT:    [[A:%.*]] = call float @llvm.maximum.f32(float [[X:%.*]], float [[Y:%.*]])
+; CHECK-NEXT:    [[B:%.*]] = call float @llvm.maximum.f32(float [[Z:%.*]], float [[W:%.*]])
+; CHECK-NEXT:    [[C:%.*]] = call float @llvm.maximum.f32(float [[A]], float [[B]])
+; CHECK-NEXT:    ret float [[C]]
+;
+  %a = call float @llvm.maximum.f32(float %x, float %y)
+  %b = call float @llvm.maximum.f32(float %z, float %w)
+  %c = call float @llvm.maximum.f32(float %a, float %b)
+  ret float %c
+}
+
+; PR37404 - https://bugs.llvm.org/show_bug.cgi?id=37404
+
+define <2 x float> @neg_neg(<2 x float> %x, <2 x float> %y) {
+; CHECK-LABEL: @neg_neg(
+; CHECK-NEXT:    [[TMP1:%.*]] = call <2 x float> @llvm.minimum.v2f32(<2 x float> [[X:%.*]], <2 x float> [[Y:%.*]])
+; CHECK-NEXT:    [[R:%.*]] = fsub <2 x float> <float -0.000000e+00, float -0.000000e+00>, [[TMP1]]
+; CHECK-NEXT:    ret <2 x float> [[R]]
+;
+  %negx = fsub <2 x float> <float -0.0, float -0.0>, %x
+  %negy = fsub <2 x float> <float -0.0, float -0.0>, %y
+  %r = call <2 x float> @llvm.maximum.v2f32(<2 x float> %negx, <2 x float> %negy)
+  ret <2 x float> %r
+}
+
+; FMF is not required, but it should be propagated from the intrinsic (not the fnegs).
+
+define float @neg_neg_vec_fmf(float %x, float %y) {
+; CHECK-LABEL: @neg_neg_vec_fmf(
+; CHECK-NEXT:    [[TMP1:%.*]] = call fast float @llvm.minimum.f32(float [[X:%.*]], float [[Y:%.*]])
+; CHECK-NEXT:    [[R:%.*]] = fsub fast float -0.000000e+00, [[TMP1]]
+; CHECK-NEXT:    ret float [[R]]
+;
+  %negx = fsub arcp float -0.0, %x
+  %negy = fsub afn float -0.0, %y
+  %r = call fast float @llvm.maximum.f32(float %negx, float %negy)
+  ret float %r
+}
+
+; 1 extra use of an intermediate value should still allow the fold,
+; but 2 would require more instructions than we started with.
+
+declare void @use(float)
+define float @neg_neg_extra_use_x(float %x, float %y) {
+; CHECK-LABEL: @neg_neg_extra_use_x(
+; CHECK-NEXT:    [[NEGX:%.*]] = fsub float -0.000000e+00, [[X:%.*]]
+; CHECK-NEXT:    [[TMP1:%.*]] = call float @llvm.minimum.f32(float [[X]], float [[Y:%.*]])
+; CHECK-NEXT:    [[R:%.*]] = fsub float -0.000000e+00, [[TMP1]]
+; CHECK-NEXT:    call void @use(float [[NEGX]])
+; CHECK-NEXT:    ret float [[R]]
+;
+  %negx = fsub float -0.0, %x
+  %negy = fsub float -0.0, %y
+  %r = call float @llvm.maximum.f32(float %negx, float %negy)
+  call void @use(float %negx)
+  ret float %r
+}
+
+define float @neg_neg_extra_use_y(float %x, float %y) {
+; CHECK-LABEL: @neg_neg_extra_use_y(
+; CHECK-NEXT:    [[NEGY:%.*]] = fsub float -0.000000e+00, [[Y:%.*]]
+; CHECK-NEXT:    [[TMP1:%.*]] = call float @llvm.minimum.f32(float [[X:%.*]], float [[Y]])
+; CHECK-NEXT:    [[R:%.*]] = fsub float -0.000000e+00, [[TMP1]]
+; CHECK-NEXT:    call void @use(float [[NEGY]])
+; CHECK-NEXT:    ret float [[R]]
+;
+  %negx = fsub float -0.0, %x
+  %negy = fsub float -0.0, %y
+  %r = call float @llvm.maximum.f32(float %negx, float %negy)
+  call void @use(float %negy)
+  ret float %r
+}
+
+define float @neg_neg_extra_use_x_and_y(float %x, float %y) {
+; CHECK-LABEL: @neg_neg_extra_use_x_and_y(
+; CHECK-NEXT:    [[NEGX:%.*]] = fsub float -0.000000e+00, [[X:%.*]]
+; CHECK-NEXT:    [[NEGY:%.*]] = fsub float -0.000000e+00, [[Y:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = call float @llvm.maximum.f32(float [[NEGX]], float [[NEGY]])
+; CHECK-NEXT:    call void @use(float [[NEGX]])
+; CHECK-NEXT:    call void @use(float [[NEGY]])
+; CHECK-NEXT:    ret float [[R]]
+;
+  %negx = fsub float -0.0, %x
+  %negy = fsub float -0.0, %y
+  %r = call float @llvm.maximum.f32(float %negx, float %negy)
+  call void @use(float %negx)
+  call void @use(float %negy)
+  ret float %r
+}

Added: llvm/trunk/test/Transforms/InstCombine/maxnum.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/maxnum.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/maxnum.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/maxnum.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,293 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt -S -instcombine < %s | FileCheck %s
+
+declare float @llvm.maxnum.f32(float, float)
+declare <2 x float> @llvm.maxnum.v2f32(<2 x float>, <2 x float>)
+declare <4 x float> @llvm.maxnum.v4f32(<4 x float>, <4 x float>)
+
+declare double @llvm.maxnum.f64(double, double)
+declare <2 x double> @llvm.maxnum.v2f64(<2 x double>, <2 x double>)
+
+define float @constant_fold_maxnum_f32() {
+; CHECK-LABEL: @constant_fold_maxnum_f32(
+; CHECK-NEXT:    ret float 2.000000e+00
+;
+  %x = call float @llvm.maxnum.f32(float 1.0, float 2.0)
+  ret float %x
+}
+
+define float @constant_fold_maxnum_f32_inv() {
+; CHECK-LABEL: @constant_fold_maxnum_f32_inv(
+; CHECK-NEXT:    ret float 2.000000e+00
+;
+  %x = call float @llvm.maxnum.f32(float 2.0, float 1.0)
+  ret float %x
+}
+
+define float @constant_fold_maxnum_f32_nan0() {
+; CHECK-LABEL: @constant_fold_maxnum_f32_nan0(
+; CHECK-NEXT:    ret float 2.000000e+00
+;
+  %x = call float @llvm.maxnum.f32(float 0x7FF8000000000000, float 2.0)
+  ret float %x
+}
+
+define float @constant_fold_maxnum_f32_nan1() {
+; CHECK-LABEL: @constant_fold_maxnum_f32_nan1(
+; CHECK-NEXT:    ret float 2.000000e+00
+;
+  %x = call float @llvm.maxnum.f32(float 2.0, float 0x7FF8000000000000)
+  ret float %x
+}
+
+define float @constant_fold_maxnum_f32_nan_nan() {
+; CHECK-LABEL: @constant_fold_maxnum_f32_nan_nan(
+; CHECK-NEXT:    ret float 0x7FF8000000000000
+;
+  %x = call float @llvm.maxnum.f32(float 0x7FF8000000000000, float 0x7FF8000000000000)
+  ret float %x
+}
+
+define float @constant_fold_maxnum_f32_p0_p0() {
+; CHECK-LABEL: @constant_fold_maxnum_f32_p0_p0(
+; CHECK-NEXT:    ret float 0.000000e+00
+;
+  %x = call float @llvm.maxnum.f32(float 0.0, float 0.0)
+  ret float %x
+}
+
+define float @constant_fold_maxnum_f32_p0_n0() {
+; CHECK-LABEL: @constant_fold_maxnum_f32_p0_n0(
+; CHECK-NEXT:    ret float 0.000000e+00
+;
+  %x = call float @llvm.maxnum.f32(float 0.0, float -0.0)
+  ret float %x
+}
+
+define float @constant_fold_maxnum_f32_n0_p0() {
+; CHECK-LABEL: @constant_fold_maxnum_f32_n0_p0(
+; CHECK-NEXT:    ret float -0.000000e+00
+;
+  %x = call float @llvm.maxnum.f32(float -0.0, float 0.0)
+  ret float %x
+}
+
+define float @constant_fold_maxnum_f32_n0_n0() {
+; CHECK-LABEL: @constant_fold_maxnum_f32_n0_n0(
+; CHECK-NEXT:    ret float -0.000000e+00
+;
+  %x = call float @llvm.maxnum.f32(float -0.0, float -0.0)
+  ret float %x
+}
+
+define <4 x float> @constant_fold_maxnum_v4f32() {
+; CHECK-LABEL: @constant_fold_maxnum_v4f32(
+; CHECK-NEXT:    ret <4 x float> <float 2.000000e+00, float 8.000000e+00, float 1.000000e+01, float 9.000000e+00>
+;
+  %x = call <4 x float> @llvm.maxnum.v4f32(<4 x float> <float 1.0, float 8.0, float 3.0, float 9.0>, <4 x float> <float 2.0, float 2.0, float 10.0, float 5.0>)
+  ret <4 x float> %x
+}
+
+define double @constant_fold_maxnum_f64() {
+; CHECK-LABEL: @constant_fold_maxnum_f64(
+; CHECK-NEXT:    ret double 2.000000e+00
+;
+  %x = call double @llvm.maxnum.f64(double 1.0, double 2.0)
+  ret double %x
+}
+
+define double @constant_fold_maxnum_f64_nan0() {
+; CHECK-LABEL: @constant_fold_maxnum_f64_nan0(
+; CHECK-NEXT:    ret double 2.000000e+00
+;
+  %x = call double @llvm.maxnum.f64(double 0x7FF8000000000000, double 2.0)
+  ret double %x
+}
+
+define double @constant_fold_maxnum_f64_nan1() {
+; CHECK-LABEL: @constant_fold_maxnum_f64_nan1(
+; CHECK-NEXT:    ret double 2.000000e+00
+;
+  %x = call double @llvm.maxnum.f64(double 2.0, double 0x7FF8000000000000)
+  ret double %x
+}
+
+define double @constant_fold_maxnum_f64_nan_nan() {
+; CHECK-LABEL: @constant_fold_maxnum_f64_nan_nan(
+; CHECK-NEXT:    ret double 0x7FF8000000000000
+;
+  %x = call double @llvm.maxnum.f64(double 0x7FF8000000000000, double 0x7FF8000000000000)
+  ret double %x
+}
+
+define float @canonicalize_constant_maxnum_f32(float %x) {
+; CHECK-LABEL: @canonicalize_constant_maxnum_f32(
+; CHECK-NEXT:    [[Y:%.*]] = call float @llvm.maxnum.f32(float [[X:%.*]], float 1.000000e+00)
+; CHECK-NEXT:    ret float [[Y]]
+;
+  %y = call float @llvm.maxnum.f32(float 1.0, float %x)
+  ret float %y
+}
+
+define float @maxnum_f32_nan_val(float %x) {
+; CHECK-LABEL: @maxnum_f32_nan_val(
+; CHECK-NEXT:    ret float [[X:%.*]]
+;
+  %y = call float @llvm.maxnum.f32(float 0x7FF8000000000000, float %x)
+  ret float %y
+}
+
+define float @maxnum_f32_val_nan(float %x) {
+; CHECK-LABEL: @maxnum_f32_val_nan(
+; CHECK-NEXT:    ret float [[X:%.*]]
+;
+  %y = call float @llvm.maxnum.f32(float %x, float 0x7FF8000000000000)
+  ret float %y
+}
+
+define float @maxnum_f32_1_maxnum_val_p0(float %x) {
+; CHECK-LABEL: @maxnum_f32_1_maxnum_val_p0(
+; CHECK-NEXT: [[RES:%.*]] = call float @llvm.maxnum.f32(float %x, float 1.000000e+00)
+; CHECK-NEXT: ret float [[RES]]
+  %y = call float @llvm.maxnum.f32(float %x, float 0.0)
+  %z = call float @llvm.maxnum.f32(float %y, float 1.0)
+  ret float %z
+}
+
+define float @maxnum_f32_1_maxnum_p0_val_fast(float %x) {
+; CHECK-LABEL: @maxnum_f32_1_maxnum_p0_val_fast(
+; CHECK-NEXT: [[RES:%.*]] = call fast float @llvm.maxnum.f32(float %x, float 1.000000e+00)
+; CHECK-NEXT: ret float [[RES]]
+  %y = call float @llvm.maxnum.f32(float 0.0, float %x)
+  %z = call fast float @llvm.maxnum.f32(float %y, float 1.0)
+  ret float %z
+}
+
+define float @maxnum_f32_1_maxnum_p0_val_nnan_ninf(float %x) {
+; CHECK-LABEL: @maxnum_f32_1_maxnum_p0_val_nnan_ninf(
+; CHECK-NEXT: [[RES:%.*]] = call nnan ninf float @llvm.maxnum.f32(float %x, float 1.000000e+00)
+; CHECK-NEXT: ret float [[RES]]
+  %y = call float @llvm.maxnum.f32(float 0.0, float %x)
+  %z = call nnan ninf float @llvm.maxnum.f32(float %y, float 1.0)
+  ret float %z
+}
+
+define float @maxnum_f32_p0_maxnum_val_n0(float %x) {
+; CHECK-LABEL: @maxnum_f32_p0_maxnum_val_n0(
+; CHECK-NEXT: [[RES:%.*]] = call float @llvm.maxnum.f32(float %x, float 0.000000e+00)
+; CHECK-NEXT: ret float [[RES]]
+  %y = call float @llvm.maxnum.f32(float %x, float -0.0)
+  %z = call float @llvm.maxnum.f32(float %y, float 0.0)
+  ret float %z
+}
+
+define float @maxnum_f32_1_maxnum_p0_val(float %x) {
+; CHECK-LABEL: @maxnum_f32_1_maxnum_p0_val(
+; CHECK-NEXT: [[RES:%.*]] = call float @llvm.maxnum.f32(float %x, float 1.000000e+00)
+; CHECK-NEXT: ret float [[RES]]
+  %y = call float @llvm.maxnum.f32(float 0.0, float %x)
+  %z = call float @llvm.maxnum.f32(float %y, float 1.0)
+  ret float %z
+}
+
+define <2 x float> @maxnum_f32_1_maxnum_val_p0_val_v2f32(<2 x float> %x) {
+; CHECK-LABEL: @maxnum_f32_1_maxnum_val_p0_val_v2f32(
+; CHECK-NEXT: [[RES:%.*]] = call <2 x float> @llvm.maxnum.v2f32(<2 x float> %x, <2 x float> <float 1.000000e+00, float 1.000000e+00>)
+; CHECK-NEXT: ret <2 x float> [[RES]]
+  %y = call <2 x float> @llvm.maxnum.v2f32(<2 x float> %x, <2 x float> zeroinitializer)
+  %z = call <2 x float> @llvm.maxnum.v2f32(<2 x float> %y, <2 x float><float 1.0, float 1.0>)
+  ret <2 x float> %z
+}
+
+define float @maxnum4(float %x, float %y, float %z, float %w) {
+; CHECK-LABEL: @maxnum4(
+; CHECK-NEXT:    [[A:%.*]] = call float @llvm.maxnum.f32(float [[X:%.*]], float [[Y:%.*]])
+; CHECK-NEXT:    [[B:%.*]] = call float @llvm.maxnum.f32(float [[Z:%.*]], float [[W:%.*]])
+; CHECK-NEXT:    [[C:%.*]] = call float @llvm.maxnum.f32(float [[A]], float [[B]])
+; CHECK-NEXT:    ret float [[C]]
+;
+  %a = call float @llvm.maxnum.f32(float %x, float %y)
+  %b = call float @llvm.maxnum.f32(float %z, float %w)
+  %c = call float @llvm.maxnum.f32(float %a, float %b)
+  ret float %c
+}
+
+; PR37404 - https://bugs.llvm.org/show_bug.cgi?id=37404
+
+define <2 x float> @neg_neg(<2 x float> %x, <2 x float> %y) {
+; CHECK-LABEL: @neg_neg(
+; CHECK-NEXT:    [[TMP1:%.*]] = call <2 x float> @llvm.minnum.v2f32(<2 x float> [[X:%.*]], <2 x float> [[Y:%.*]])
+; CHECK-NEXT:    [[R:%.*]] = fsub <2 x float> <float -0.000000e+00, float -0.000000e+00>, [[TMP1]]
+; CHECK-NEXT:    ret <2 x float> [[R]]
+;
+  %negx = fsub <2 x float> <float -0.0, float -0.0>, %x
+  %negy = fsub <2 x float> <float -0.0, float -0.0>, %y
+  %r = call <2 x float> @llvm.maxnum.v2f32(<2 x float> %negx, <2 x float> %negy)
+  ret <2 x float> %r
+}
+
+; FMF is not required, but it should be propagated from the intrinsic (not the fnegs).
+
+define float @neg_neg_vec_fmf(float %x, float %y) {
+; CHECK-LABEL: @neg_neg_vec_fmf(
+; CHECK-NEXT:    [[TMP1:%.*]] = call fast float @llvm.minnum.f32(float [[X:%.*]], float [[Y:%.*]])
+; CHECK-NEXT:    [[R:%.*]] = fsub fast float -0.000000e+00, [[TMP1]]
+; CHECK-NEXT:    ret float [[R]]
+;
+  %negx = fsub arcp float -0.0, %x
+  %negy = fsub afn float -0.0, %y
+  %r = call fast float @llvm.maxnum.f32(float %negx, float %negy)
+  ret float %r
+}
+
+; 1 extra use of an intermediate value should still allow the fold,
+; but 2 would require more instructions than we started with.
+
+declare void @use(float)
+define float @neg_neg_extra_use_x(float %x, float %y) {
+; CHECK-LABEL: @neg_neg_extra_use_x(
+; CHECK-NEXT:    [[NEGX:%.*]] = fsub float -0.000000e+00, [[X:%.*]]
+; CHECK-NEXT:    [[TMP1:%.*]] = call float @llvm.minnum.f32(float [[X]], float [[Y:%.*]])
+; CHECK-NEXT:    [[R:%.*]] = fsub float -0.000000e+00, [[TMP1]]
+; CHECK-NEXT:    call void @use(float [[NEGX]])
+; CHECK-NEXT:    ret float [[R]]
+;
+  %negx = fsub float -0.0, %x
+  %negy = fsub float -0.0, %y
+  %r = call float @llvm.maxnum.f32(float %negx, float %negy)
+  call void @use(float %negx)
+  ret float %r
+}
+
+define float @neg_neg_extra_use_y(float %x, float %y) {
+; CHECK-LABEL: @neg_neg_extra_use_y(
+; CHECK-NEXT:    [[NEGY:%.*]] = fsub float -0.000000e+00, [[Y:%.*]]
+; CHECK-NEXT:    [[TMP1:%.*]] = call float @llvm.minnum.f32(float [[X:%.*]], float [[Y]])
+; CHECK-NEXT:    [[R:%.*]] = fsub float -0.000000e+00, [[TMP1]]
+; CHECK-NEXT:    call void @use(float [[NEGY]])
+; CHECK-NEXT:    ret float [[R]]
+;
+  %negx = fsub float -0.0, %x
+  %negy = fsub float -0.0, %y
+  %r = call float @llvm.maxnum.f32(float %negx, float %negy)
+  call void @use(float %negy)
+  ret float %r
+}
+
+define float @neg_neg_extra_use_x_and_y(float %x, float %y) {
+; CHECK-LABEL: @neg_neg_extra_use_x_and_y(
+; CHECK-NEXT:    [[NEGX:%.*]] = fsub float -0.000000e+00, [[X:%.*]]
+; CHECK-NEXT:    [[NEGY:%.*]] = fsub float -0.000000e+00, [[Y:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = call float @llvm.maxnum.f32(float [[NEGX]], float [[NEGY]])
+; CHECK-NEXT:    call void @use(float [[NEGX]])
+; CHECK-NEXT:    call void @use(float [[NEGY]])
+; CHECK-NEXT:    ret float [[R]]
+;
+  %negx = fsub float -0.0, %x
+  %negy = fsub float -0.0, %y
+  %r = call float @llvm.maxnum.f32(float %negx, float %negy)
+  call void @use(float %negx)
+  call void @use(float %negy)
+  ret float %r
+}
+

Added: llvm/trunk/test/Transforms/InstCombine/mem-gep-zidx.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/mem-gep-zidx.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/mem-gep-zidx.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/mem-gep-zidx.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,60 @@
+; RUN: opt -S -instcombine < %s | FileCheck %s
+target datalayout = "E-m:e-i64:64-n32:64"
+target triple = "powerpc64-unknown-linux-gnu"
+
+ at f.a = private unnamed_addr constant [1 x i32] [i32 12], align 4
+ at f.b = private unnamed_addr constant [1 x i32] [i32 55], align 4
+ at f.c = linkonce unnamed_addr alias [1 x i32], [1 x i32]* @f.b
+
+define signext i32 @test1(i32 signext %x) #0 {
+entry:
+  %idxprom = sext i32 %x to i64
+  %arrayidx = getelementptr inbounds [1 x i32], [1 x i32]* @f.a, i64 0, i64 %idxprom
+  %0 = load i32, i32* %arrayidx, align 4
+  ret i32 %0
+
+; CHECK-LABEL: @test1
+; CHECK: ret i32 12
+}
+
+declare void @foo(i64* %p)
+define void @test2(i32 signext %x, i64 %v) #0 {
+entry:
+  %p = alloca i64
+  %idxprom = sext i32 %x to i64
+  %arrayidx = getelementptr inbounds i64, i64* %p, i64 %idxprom
+  store i64 %v, i64* %arrayidx
+  call void @foo(i64* %p)
+  ret void
+
+; CHECK-LABEL: @test2
+; CHECK: %p = alloca i64
+; CHECK: store i64 %v, i64* %p
+; CHECK: ret void
+}
+
+define signext i32 @test3(i32 signext %x, i1 %y) #0 {
+entry:
+  %idxprom = sext i32 %x to i64
+  %p = select i1 %y, [1 x i32]* @f.a, [1 x i32]* @f.b
+  %arrayidx = getelementptr inbounds [1 x i32], [1 x i32]* %p, i64 0, i64 %idxprom
+  %0 = load i32, i32* %arrayidx, align 4
+  ret i32 %0
+
+; CHECK-LABEL: @test3
+; CHECK: getelementptr inbounds [1 x i32], [1 x i32]* %p, i64 0, i64 0
+}
+
+define signext i32 @test4(i32 signext %x, i1 %y) #0 {
+entry:
+  %idxprom = sext i32 %x to i64
+  %arrayidx = getelementptr inbounds [1 x i32], [1 x i32]* @f.c, i64 0, i64 %idxprom
+  %0 = load i32, i32* %arrayidx, align 4
+  ret i32 %0
+
+; CHECK-LABEL: @test4
+; CHECK: getelementptr inbounds [1 x i32], [1 x i32]* @f.c, i64 0, i64 %idxprom
+}
+
+attributes #0 = { nounwind readnone }
+

Added: llvm/trunk/test/Transforms/InstCombine/mem-par-metadata-memcpy.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/mem-par-metadata-memcpy.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/mem-par-metadata-memcpy.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/mem-par-metadata-memcpy.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,62 @@
+; RUN: opt < %s -instcombine -S | FileCheck %s
+;
+; Make sure the llvm.access.group meta-data is preserved
+; when a memcpy is replaced with a load+store by instcombine
+;
+; #include <string.h>
+; void test(char* out, long size)
+; {
+;     #pragma clang loop vectorize(assume_safety)
+;     for (long i = 0; i < size; i+=2) {
+;         memcpy(&(out[i]), &(out[i+size]), 2);
+;     }
+; }
+
+; CHECK: for.body:
+; CHECK:  %{{.*}} = load i16, i16* %{{.*}}, align 1, !llvm.access.group !1
+; CHECK:  store i16 %{{.*}}, i16* %{{.*}}, align 1, !llvm.access.group !1
+
+
+; ModuleID = '<stdin>'
+source_filename = "memcpy.pragma.cpp"
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+; Function Attrs: nounwind uwtable
+define void @_Z4testPcl(i8* %out, i64 %size) #0 {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %i.0 = phi i64 [ 0, %entry ], [ %add2, %for.inc ]
+  %cmp = icmp slt i64 %i.0, %size
+  br i1 %cmp, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  %arrayidx = getelementptr inbounds i8, i8* %out, i64 %i.0
+  %add = add nsw i64 %i.0, %size
+  %arrayidx1 = getelementptr inbounds i8, i8* %out, i64 %add
+  call void @llvm.memcpy.p0i8.p0i8.i64(i8* %arrayidx, i8* %arrayidx1, i64 2, i1 false), !llvm.access.group !4
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body
+  %add2 = add nsw i64 %i.0, 2
+  br label %for.cond, !llvm.loop !2
+
+for.end:                                          ; preds = %for.cond
+  ret void
+}
+
+; Function Attrs: argmemonly nounwind
+declare void @llvm.memcpy.p0i8.p0i8.i64(i8* nocapture writeonly, i8* nocapture readonly, i64, i1) #1
+
+attributes #0 = { nounwind uwtable "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #1 = { argmemonly nounwind }
+
+!llvm.ident = !{!0}
+
+!0 = !{!"clang version 4.0.0 (cfe/trunk 277751)"}
+!1 = distinct !{!1, !2, !3, !{!"llvm.loop.parallel_accesses", !4}}
+!2 = distinct !{!2, !3}
+!3 = !{!"llvm.loop.vectorize.enable", i1 true}
+!4 = distinct !{} ; access group

Added: llvm/trunk/test/Transforms/InstCombine/memchr.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/memchr.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/memchr.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/memchr.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,204 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; Test that the memchr library call simplifier works correctly.
+; RUN: opt < %s -instcombine -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:128:128-n8:16:32"
+
+ at hello = constant [14 x i8] c"hello world\5Cn\00"
+ at hellonull = constant [14 x i8] c"hello\00world\5Cn\00"
+ at null = constant [1 x i8] zeroinitializer
+ at newlines = constant [3 x i8] c"\0D\0A\00"
+ at single = constant [2 x i8] c"\1F\00"
+ at spaces = constant [4 x i8] c" \0D\0A\00"
+ at negative = constant [3 x i8] c"\FF\FE\00"
+ at chp = global i8* zeroinitializer
+
+declare i8* @memchr(i8*, i32, i32)
+
+define void @test1() {
+; CHECK-LABEL: @test1(
+; CHECK-NEXT:    store i8* getelementptr inbounds ([14 x i8], [14 x i8]* @hello, i32 0, i32 6), i8** @chp, align 4
+; CHECK-NEXT:    ret void
+;
+  %str = getelementptr [14 x i8], [14 x i8]* @hello, i32 0, i32 0
+  %dst = call i8* @memchr(i8* %str, i32 119, i32 14)
+  store i8* %dst, i8** @chp
+  ret void
+}
+
+define void @test2() {
+; CHECK-LABEL: @test2(
+; CHECK-NEXT:    store i8* null, i8** @chp, align 4
+; CHECK-NEXT:    ret void
+;
+  %str = getelementptr [1 x i8], [1 x i8]* @null, i32 0, i32 0
+  %dst = call i8* @memchr(i8* %str, i32 119, i32 1)
+  store i8* %dst, i8** @chp
+  ret void
+}
+
+define void @test3() {
+; CHECK-LABEL: @test3(
+; CHECK-NEXT:    store i8* getelementptr inbounds ([14 x i8], [14 x i8]* @hello, i32 0, i32 13), i8** @chp, align 4
+; CHECK-NEXT:    ret void
+;
+  %src = getelementptr [14 x i8], [14 x i8]* @hello, i32 0, i32 0
+  %dst = call i8* @memchr(i8* %src, i32 0, i32 14)
+  store i8* %dst, i8** @chp
+  ret void
+}
+
+define void @test4(i32 %chr) {
+; CHECK-LABEL: @test4(
+; CHECK-NEXT:    [[DST:%.*]] = call i8* @memchr(i8* getelementptr inbounds ([14 x i8], [14 x i8]* @hello, i32 0, i32 0), i32 [[CHR:%.*]], i32 14)
+; CHECK-NEXT:    store i8* [[DST]], i8** @chp, align 4
+; CHECK-NEXT:    ret void
+;
+  %src = getelementptr [14 x i8], [14 x i8]* @hello, i32 0, i32 0
+  %dst = call i8* @memchr(i8* %src, i32 %chr, i32 14)
+  store i8* %dst, i8** @chp
+  ret void
+}
+
+define void @test5() {
+; CHECK-LABEL: @test5(
+; CHECK-NEXT:    store i8* getelementptr inbounds ([14 x i8], [14 x i8]* @hello, i32 0, i32 13), i8** @chp, align 4
+; CHECK-NEXT:    ret void
+;
+  %src = getelementptr [14 x i8], [14 x i8]* @hello, i32 0, i32 0
+  %dst = call i8* @memchr(i8* %src, i32 65280, i32 14)
+  store i8* %dst, i8** @chp
+  ret void
+}
+
+define void @test6() {
+; CHECK-LABEL: @test6(
+; CHECK-NEXT:    store i8* getelementptr inbounds ([14 x i8], [14 x i8]* @hello, i32 0, i32 6), i8** @chp, align 4
+; CHECK-NEXT:    ret void
+;
+  %src = getelementptr [14 x i8], [14 x i8]* @hello, i32 0, i32 0
+; Overflow, but we still find the right thing.
+  %dst = call i8* @memchr(i8* %src, i32 119, i32 100)
+  store i8* %dst, i8** @chp
+  ret void
+}
+
+define void @test7() {
+; CHECK-LABEL: @test7(
+; CHECK-NEXT:    store i8* null, i8** @chp, align 4
+; CHECK-NEXT:    ret void
+;
+  %src = getelementptr [14 x i8], [14 x i8]* @hello, i32 0, i32 0
+; Overflow
+  %dst = call i8* @memchr(i8* %src, i32 120, i32 100)
+  store i8* %dst, i8** @chp
+  ret void
+}
+
+define void @test8() {
+; CHECK-LABEL: @test8(
+; CHECK-NEXT:    store i8* getelementptr inbounds ([14 x i8], [14 x i8]* @hellonull, i32 0, i32 6), i8** @chp, align 4
+; CHECK-NEXT:    ret void
+;
+  %str = getelementptr [14 x i8], [14 x i8]* @hellonull, i32 0, i32 0
+  %dst = call i8* @memchr(i8* %str, i32 119, i32 14)
+  store i8* %dst, i8** @chp
+  ret void
+}
+
+define void @test9() {
+; CHECK-LABEL: @test9(
+; CHECK-NEXT:    store i8* getelementptr inbounds ([14 x i8], [14 x i8]* @hellonull, i32 0, i32 6), i8** @chp, align 4
+; CHECK-NEXT:    ret void
+;
+  %str = getelementptr [14 x i8], [14 x i8]* @hellonull, i32 0, i32 2
+  %dst = call i8* @memchr(i8* %str, i32 119, i32 12)
+  store i8* %dst, i8** @chp
+  ret void
+}
+
+define void @test10() {
+; CHECK-LABEL: @test10(
+; CHECK-NEXT:    store i8* null, i8** @chp, align 4
+; CHECK-NEXT:    ret void
+;
+  %str = getelementptr [14 x i8], [14 x i8]* @hello, i32 0, i32 0
+  %dst = call i8* @memchr(i8* %str, i32 119, i32 6)
+  store i8* %dst, i8** @chp
+  ret void
+}
+
+; Check transformation memchr("\r\n", C, 2) != nullptr -> (C & 9216) != 0
+define i1 @test11(i32 %C) {
+; CHECK-LABEL: @test11(
+; CHECK-NEXT:    [[TMP1:%.*]] = trunc i32 [[C:%.*]] to i16
+; CHECK-NEXT:    [[TMP2:%.*]] = and i16 [[TMP1]], 255
+; CHECK-NEXT:    [[MEMCHR_BOUNDS:%.*]] = icmp ult i16 [[TMP2]], 16
+; CHECK-NEXT:    [[TMP3:%.*]] = shl i16 1, [[TMP2]]
+; CHECK-NEXT:    [[TMP4:%.*]] = and i16 [[TMP3]], 9216
+; CHECK-NEXT:    [[MEMCHR_BITS:%.*]] = icmp ne i16 [[TMP4]], 0
+; CHECK-NEXT:    [[MEMCHR:%.*]] = and i1 [[MEMCHR_BOUNDS]], [[MEMCHR_BITS]]
+; CHECK-NEXT:    ret i1 [[MEMCHR]]
+;
+  %dst = call i8* @memchr(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @newlines, i64 0, i64 0), i32 %C, i32 2)
+  %cmp = icmp ne i8* %dst, null
+  ret i1 %cmp
+}
+
+; No 64 bits here
+define i1 @test12(i32 %C) {
+; CHECK-LABEL: @test12(
+; CHECK-NEXT:    [[DST:%.*]] = call i8* @memchr(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @spaces, i32 0, i32 0), i32 [[C:%.*]], i32 3)
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ne i8* [[DST]], null
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %dst = call i8* @memchr(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @spaces, i64 0, i64 0), i32 %C, i32 3)
+  %cmp = icmp ne i8* %dst, null
+  ret i1 %cmp
+}
+
+define i1 @test13(i32 %C) {
+; CHECK-LABEL: @test13(
+; CHECK-NEXT:    [[TMP1:%.*]] = and i32 [[C:%.*]], 255
+; CHECK-NEXT:    [[MEMCHR_BOUNDS:%.*]] = icmp ult i32 [[TMP1]], 32
+; CHECK-NEXT:    [[TMP2:%.*]] = shl i32 1, [[TMP1]]
+; CHECK-NEXT:    [[TMP3:%.*]] = and i32 [[TMP2]], -2147483647
+; CHECK-NEXT:    [[MEMCHR_BITS:%.*]] = icmp ne i32 [[TMP3]], 0
+; CHECK-NEXT:    [[MEMCHR:%.*]] = and i1 [[MEMCHR_BOUNDS]], [[MEMCHR_BITS]]
+; CHECK-NEXT:    ret i1 [[MEMCHR]]
+;
+  %dst = call i8* @memchr(i8* getelementptr inbounds ([2 x i8], [2 x i8]* @single, i64 0, i64 0), i32 %C, i32 2)
+  %cmp = icmp ne i8* %dst, null
+  ret i1 %cmp
+}
+
+define i1 @test14(i32 %C) {
+; CHECK-LABEL: @test14(
+; CHECK-NEXT:    [[TMP1:%.*]] = and i32 [[C:%.*]], 255
+; CHECK-NEXT:    [[MEMCHR_BITS:%.*]] = icmp eq i32 [[TMP1]], 31
+; CHECK-NEXT:    ret i1 [[MEMCHR_BITS]]
+;
+  %dst = call i8* @memchr(i8* getelementptr inbounds ([2 x i8], [2 x i8]* @single, i64 0, i64 0), i32 %C, i32 1)
+  %cmp = icmp ne i8* %dst, null
+  ret i1 %cmp
+}
+
+define i1 @test15(i32 %C) {
+; CHECK-LABEL: @test15(
+; CHECK-NEXT:    [[DST:%.*]] = call i8* @memchr(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @negative, i32 0, i32 0), i32 [[C:%.*]], i32 3)
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ne i8* [[DST]], null
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %dst = call i8* @memchr(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @negative, i64 0, i64 0), i32 %C, i32 3)
+  %cmp = icmp ne i8* %dst, null
+  ret i1 %cmp
+}
+
+ at s = internal constant [1 x i8] [i8 0], align 1
+define i8* @pr32124() {
+; CHECK-LABEL: @pr32124(
+; CHECK-NEXT:    ret i8* getelementptr inbounds ([1 x i8], [1 x i8]* @s, i32 0, i32 0)
+;
+  %res = tail call i8* @memchr(i8* getelementptr ([1 x i8], [1 x i8]* @s, i64 0, i64 0), i32 0, i32 1)
+  ret i8* %res
+}

Added: llvm/trunk/test/Transforms/InstCombine/memcmp-1.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/memcmp-1.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/memcmp-1.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/memcmp-1.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,151 @@
+; Test that the memcmp library call simplifier works correctly.
+;
+; RUN: opt < %s -instcombine -S | FileCheck --check-prefix=CHECK --check-prefix=NOBCMP %s
+; RUN: opt < %s -instcombine -mtriple=x86_64-unknown-linux-gnu -S | FileCheck --check-prefix=CHECK --check-prefix=BCMP %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:128:128-n8:16:32:64"
+
+ at foo = constant [4 x i8] c"foo\00"
+ at hel = constant [4 x i8] c"hel\00"
+ at hello_u = constant [8 x i8] c"hello_u\00"
+
+declare i32 @memcmp(i8*, i8*, i32)
+
+; Check memcmp(mem, mem, size) -> 0.
+
+define i32 @test_simplify1(i8* %mem, i32 %size) {
+; CHECK-LABEL: @test_simplify1(
+; CHECK-NEXT:    ret i32 0
+;
+  %ret = call i32 @memcmp(i8* %mem, i8* %mem, i32 %size)
+  ret i32 %ret
+}
+
+; Check memcmp(mem1, mem2, 0) -> 0.
+
+define i32 @test_simplify2(i8* %mem1, i8* %mem2) {
+; CHECK-LABEL: @test_simplify2(
+; CHECK-NEXT:    ret i32 0
+;
+  %ret = call i32 @memcmp(i8* %mem1, i8* %mem2, i32 0)
+  ret i32 %ret
+}
+
+;; Check memcmp(mem1, mem2, 1) -> *(unsigned char*)mem1 - *(unsigned char*)mem2.
+
+define i32 @test_simplify3(i8* %mem1, i8* %mem2) {
+; CHECK-LABEL: @test_simplify3(
+; CHECK-NEXT:    [[LHSC:%.*]] = load i8, i8* %mem1, align 1
+; CHECK-NEXT:    [[LHSV:%.*]] = zext i8 [[LHSC]] to i32
+; CHECK-NEXT:    [[RHSC:%.*]] = load i8, i8* %mem2, align 1
+; CHECK-NEXT:    [[RHSV:%.*]] = zext i8 [[RHSC]] to i32
+; CHECK-NEXT:    [[CHARDIFF:%.*]] = sub nsw i32 [[LHSV]], [[RHSV]]
+; CHECK-NEXT:    ret i32 [[CHARDIFF]]
+;
+  %ret = call i32 @memcmp(i8* %mem1, i8* %mem2, i32 1)
+  ret i32 %ret
+}
+
+; Check memcmp(mem1, mem2, size) -> cnst, where all arguments are constants.
+
+define i32 @test_simplify4() {
+; CHECK-LABEL: @test_simplify4(
+; CHECK-NEXT:    ret i32 0
+;
+  %mem1 = getelementptr [4 x i8], [4 x i8]* @hel, i32 0, i32 0
+  %mem2 = getelementptr [8 x i8], [8 x i8]* @hello_u, i32 0, i32 0
+  %ret = call i32 @memcmp(i8* %mem1, i8* %mem2, i32 3)
+  ret i32 %ret
+}
+
+define i32 @test_simplify5() {
+; CHECK-LABEL: @test_simplify5(
+; CHECK-NEXT:    ret i32 1
+;
+  %mem1 = getelementptr [4 x i8], [4 x i8]* @hel, i32 0, i32 0
+  %mem2 = getelementptr [4 x i8], [4 x i8]* @foo, i32 0, i32 0
+  %ret = call i32 @memcmp(i8* %mem1, i8* %mem2, i32 3)
+  ret i32 %ret
+}
+
+define i32 @test_simplify6() {
+; CHECK-LABEL: @test_simplify6(
+; CHECK-NEXT:    ret i32 -1
+;
+  %mem1 = getelementptr [4 x i8], [4 x i8]* @foo, i32 0, i32 0
+  %mem2 = getelementptr [4 x i8], [4 x i8]* @hel, i32 0, i32 0
+  %ret = call i32 @memcmp(i8* %mem1, i8* %mem2, i32 3)
+  ret i32 %ret
+}
+
+; Check memcmp(mem1, mem2, 8)==0 -> *(int64_t*)mem1 == *(int64_t*)mem2
+
+define i1 @test_simplify7(i64 %x, i64 %y) {
+; CHECK-LABEL: @test_simplify7(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i64 %x, %y
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %x.addr = alloca i64, align 8
+  %y.addr = alloca i64, align 8
+  store i64 %x, i64* %x.addr, align 8
+  store i64 %y, i64* %y.addr, align 8
+  %xptr = bitcast i64* %x.addr to i8*
+  %yptr = bitcast i64* %y.addr to i8*
+  %call = call i32 @memcmp(i8* %xptr, i8* %yptr, i32 8)
+  %cmp = icmp eq i32 %call, 0
+  ret i1 %cmp
+}
+
+; Check memcmp(mem1, mem2, 4)==0 -> *(int32_t*)mem1 == *(int32_t*)mem2
+
+define i1 @test_simplify8(i32 %x, i32 %y) {
+; CHECK-LABEL: @test_simplify8(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 %x, %y
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %x.addr = alloca i32, align 4
+  %y.addr = alloca i32, align 4
+  store i32 %x, i32* %x.addr, align 4
+  store i32 %y, i32* %y.addr, align 4
+  %xptr = bitcast i32* %x.addr to i8*
+  %yptr = bitcast i32* %y.addr to i8*
+  %call = call i32 @memcmp(i8* %xptr, i8* %yptr, i32 4)
+  %cmp = icmp eq i32 %call, 0
+  ret i1 %cmp
+}
+
+; Check memcmp(mem1, mem2, 2)==0 -> *(int16_t*)mem1 == *(int16_t*)mem2
+
+define i1 @test_simplify9(i16 %x, i16 %y) {
+; CHECK-LABEL: @test_simplify9(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i16 %x, %y
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %x.addr = alloca i16, align 2
+  %y.addr = alloca i16, align 2
+  store i16 %x, i16* %x.addr, align 2
+  store i16 %y, i16* %y.addr, align 2
+  %xptr = bitcast i16* %x.addr to i8*
+  %yptr = bitcast i16* %y.addr to i8*
+  %call = call i32 @memcmp(i8* %xptr, i8* %yptr, i32 2)
+  %cmp = icmp eq i32 %call, 0
+  ret i1 %cmp
+}
+
+; Check memcmp(mem1, mem2, size)==0 -> bcmp(mem1, mem2, size)==0
+
+define i1 @test_simplify10(i8* %mem1, i8* %mem2, i32 %size) {
+; NOBCMP-LABEL: @test_simplify10(
+; NOBCMP-NEXT:    [[CALL:%.*]] = call i32 @memcmp(i8* %mem1, i8* %mem2, i32 %size)
+; NOBCMP-NEXT:    [[CMP:%.*]] = icmp eq i32 [[CALL]], 0
+; NOBCMP-NEXT:    ret i1 [[CMP]]
+;
+; BCMP-LABEL: @test_simplify10(
+; BCMP-NEXT:    [[CALL:%.*]] = call i32 @bcmp(i8* %mem1, i8* %mem2, i32 %size)
+; BCMP-NEXT:    [[CMP:%.*]] = icmp eq i32 [[CALL]], 0
+; BCMP-NEXT:    ret i1 [[CMP]]
+;
+  %call = call i32 @memcmp(i8* %mem1, i8* %mem2, i32 %size)
+  %cmp = icmp eq i32 %call, 0
+  ret i1 %cmp
+}

Added: llvm/trunk/test/Transforms/InstCombine/memcmp-2.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/memcmp-2.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/memcmp-2.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/memcmp-2.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,17 @@
+; Test that the memcmp library call simplifier works correctly.
+;
+; RUN: opt < %s -instcombine -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:128:128"
+
+declare i32* @memcmp(i8*, i8*, i32)
+
+; Check that memcmp functions with the wrong prototype aren't simplified.
+
+define i32* @test_no_simplify1(i8* %mem, i32 %size) {
+; CHECK-LABEL: @test_no_simplify1(
+  %ret = call i32* @memcmp(i8* %mem, i8* %mem, i32 %size)
+; CHECK-NEXT: call i32* @memcmp
+  ret i32* %ret
+; CHECK-NEXT: ret i32* %ret
+}

Added: llvm/trunk/test/Transforms/InstCombine/memcmp-constant-fold.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/memcmp-constant-fold.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/memcmp-constant-fold.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/memcmp-constant-fold.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,80 @@
+; RUN: opt < %s -instcombine -S -data-layout=e-n32 | FileCheck %s --check-prefix=ALL --check-prefix=LE
+; RUN: opt < %s -instcombine -S -data-layout=E-n32 | FileCheck %s --check-prefix=ALL --check-prefix=BE
+
+declare i32 @memcmp(i8*, i8*, i64)
+
+; The alignment of this constant does not matter. We constant fold the load.
+
+ at charbuf = private unnamed_addr constant [4 x i8] [i8 0, i8 0, i8 0, i8 1], align 1
+
+define i1 @memcmp_4bytes_unaligned_constant_i8(i8* align 4 %x) {
+; LE-LABEL: @memcmp_4bytes_unaligned_constant_i8(
+; LE-NEXT:    [[TMP1:%.*]] = bitcast i8* %x to i32*
+; LE-NEXT:    [[LHSV:%.*]] = load i32, i32* [[TMP1]], align 4
+; LE-NEXT:    [[TMP2:%.*]] = icmp eq i32 [[LHSV]], 16777216
+; LE-NEXT:    ret i1 [[TMP2]]
+;
+; BE-LABEL: @memcmp_4bytes_unaligned_constant_i8(
+; BE-NEXT:    [[TMP1:%.*]] = bitcast i8* %x to i32*
+; BE-NEXT:    [[LHSV:%.*]] = load i32, i32* [[TMP1]], align 4
+; BE-NEXT:    [[TMP2:%.*]] = icmp eq i32 [[LHSV]], 1
+; BE-NEXT:    ret i1 [[TMP2]]
+;
+  %call = tail call i32 @memcmp(i8* %x, i8* getelementptr inbounds ([4 x i8], [4 x i8]* @charbuf, i64 0, i64 0), i64 4)
+  %cmpeq0 = icmp eq i32 %call, 0
+  ret i1 %cmpeq0
+}
+
+; We still don't care about alignment of the constant. We are not limited to constant folding only i8 arrays.
+; It doesn't matter if the constant operand is the first operand to the memcmp.
+
+ at intbuf_unaligned = private unnamed_addr constant [4 x i16] [i16 1, i16 2, i16 3, i16 4], align 1
+
+define i1 @memcmp_4bytes_unaligned_constant_i16(i8* align 4 %x) {
+; LE-LABEL: @memcmp_4bytes_unaligned_constant_i16(
+; LE-NEXT:    [[TMP1:%.*]] = bitcast i8* %x to i32*
+; LE-NEXT:    [[RHSV:%.*]] = load i32, i32* [[TMP1]], align 4
+; LE-NEXT:    [[TMP2:%.*]] = icmp eq i32 [[RHSV]], 131073
+; LE-NEXT:    ret i1 [[TMP2]]
+;
+; BE-LABEL: @memcmp_4bytes_unaligned_constant_i16(
+; BE-NEXT:    [[TMP1:%.*]] = bitcast i8* %x to i32*
+; BE-NEXT:    [[RHSV:%.*]] = load i32, i32* [[TMP1]], align 4
+; BE-NEXT:    [[TMP2:%.*]] = icmp eq i32 [[RHSV]], 65538
+; BE-NEXT:    ret i1 [[TMP2]]
+;
+  %call = tail call i32 @memcmp(i8* bitcast (i16* getelementptr inbounds ([4 x i16], [4 x i16]* @intbuf_unaligned, i64 0, i64 0) to i8*), i8* %x, i64 4)
+  %cmpeq0 = icmp eq i32 %call, 0
+  ret i1 %cmpeq0
+}
+
+; TODO: Any memcmp where all arguments are constants should be constant folded. Currently, we only handle i8 array constants.
+
+ at intbuf = private unnamed_addr constant [2 x i32] [i32 0, i32 1], align 4
+
+define i1 @memcmp_3bytes_aligned_constant_i32(i8* align 4 %x) {
+; ALL-LABEL: @memcmp_3bytes_aligned_constant_i32(
+; ALL-NEXT:    [[CALL:%.*]] = tail call i32 @memcmp(i8* bitcast (i32* getelementptr inbounds ([2 x i32], [2 x i32]* @intbuf, i64 0, i64 1) to i8*), i8* bitcast ([2 x i32]* @intbuf to i8*), i64 3)
+; ALL-NEXT:    [[CMPEQ0:%.*]] = icmp eq i32 [[CALL]], 0
+; ALL-NEXT:    ret i1 [[CMPEQ0]]
+;
+  %call = tail call i32 @memcmp(i8* bitcast (i32* getelementptr inbounds ([2 x i32], [2 x i32]* @intbuf, i64 0, i64 1) to i8*), i8* bitcast (i32* getelementptr inbounds ([2 x i32], [2 x i32]* @intbuf, i64 0, i64 0) to i8*), i64 3)
+  %cmpeq0 = icmp eq i32 %call, 0
+  ret i1 %cmpeq0
+}
+
+; A sloppy implementation would infinite loop by recreating the unused instructions.
+
+define i1 @memcmp_4bytes_one_unaligned_i8(i8* align 4 %x, i8* align 1 %y) {
+; ALL-LABEL: @memcmp_4bytes_one_unaligned_i8(
+; ALL-NEXT:    [[CALL:%.*]] = tail call i32 @memcmp(i8* %x, i8* %y, i64 4)
+; ALL-NEXT:    [[CMPEQ0:%.*]] = icmp eq i32 [[CALL]], 0
+; ALL-NEXT:    ret i1 [[CMPEQ0]]
+;
+  %bc = bitcast i8* %x to i32*
+  %lhsv = load i32, i32* %bc
+  %call = tail call i32 @memcmp(i8* %x, i8* %y, i64 4)
+  %cmpeq0 = icmp eq i32 %call, 0
+  ret i1 %cmpeq0
+}
+

Added: llvm/trunk/test/Transforms/InstCombine/memcpy-1.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/memcpy-1.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/memcpy-1.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/memcpy-1.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,28 @@
+; Test that the memcpy library call simplifier works correctly.
+;
+; RUN: opt < %s -instcombine -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:128:128"
+
+declare i8* @memcpy(i8*, i8*, i32)
+
+; Check memcpy(mem1, mem2, size) -> llvm.memcpy(mem1, mem2, size, 1).
+
+define i8* @test_simplify1(i8* %mem1, i8* %mem2, i32 %size) {
+; CHECK-LABEL: @test_simplify1(
+; CHECK-NEXT:    call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 1 %mem1, i8* align 1 %mem2, i32 %size, i1 false)
+; CHECK-NEXT:    ret i8* %mem1
+;
+  %ret = call i8* @memcpy(i8* %mem1, i8* %mem2, i32 %size)
+  ret i8* %ret
+}
+
+; Verify that the strictfp attr doesn't block this optimization.
+
+define i8* @test_simplify2(i8* %mem1, i8* %mem2, i32 %size) {
+; CHECK-LABEL: @test_simplify2(
+  %ret = call i8* @memcpy(i8* %mem1, i8* %mem2, i32 %size) strictfp
+; CHECK: call void @llvm.memcpy
+  ret i8* %ret
+; CHECK: ret i8* %mem1
+}

Added: llvm/trunk/test/Transforms/InstCombine/memcpy-2.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/memcpy-2.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/memcpy-2.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/memcpy-2.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,18 @@
+; Test that the memcpy library call simplifier works correctly.
+;
+; RUN: opt < %s -instcombine -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:128:128"
+
+declare i8 @memcpy(i8*, i8*, i32)
+
+; Check that memcpy functions with the wrong prototype (doesn't return a pointer) aren't simplified.
+
+define i8 @test_no_simplify1(i8* %mem1, i8* %mem2, i32 %size) {
+; CHECK-LABEL: @test_no_simplify1(
+; CHECK-NEXT:    [[RET:%.*]] = call i8 @memcpy(i8* %mem1, i8* %mem2, i32 %size)
+; CHECK-NEXT:    ret i8 [[RET]]
+;
+  %ret = call i8 @memcpy(i8* %mem1, i8* %mem2, i32 %size)
+  ret i8 %ret
+}

Added: llvm/trunk/test/Transforms/InstCombine/memcpy-addrspace.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/memcpy-addrspace.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/memcpy-addrspace.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/memcpy-addrspace.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,125 @@
+; RUN: opt < %s -instcombine -S | FileCheck %s
+
+ at test.data = private unnamed_addr addrspace(2) constant [8 x i32] [i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7], align 4
+
+; CHECK-LABEL: test_load
+; CHECK: %[[GEP:.*]] = getelementptr [8 x i32], [8 x i32] addrspace(2)* @test.data, i64 0, i64 %x
+; CHECK: %{{.*}} = load i32, i32 addrspace(2)* %[[GEP]]
+; CHECK-NOT: alloca
+; CHECK-NOT: call void @llvm.memcpy.p0i8.p2i8.i64
+; CHECK-NOT: addrspacecast
+; CHECK-NOT: load i32, i32*
+define void @test_load(i32 addrspace(1)* %out, i64 %x) {
+entry:
+  %data = alloca [8 x i32], align 4
+  %0 = bitcast [8 x i32]* %data to i8*
+  call void @llvm.memcpy.p0i8.p2i8.i64(i8* align 4 %0, i8 addrspace(2)* align 4 bitcast ([8 x i32] addrspace(2)* @test.data to i8 addrspace(2)*), i64 32, i1 false)
+  %arrayidx = getelementptr inbounds [8 x i32], [8 x i32]* %data, i64 0, i64 %x
+  %1 = load i32, i32* %arrayidx, align 4
+  %arrayidx1 = getelementptr inbounds i32, i32 addrspace(1)* %out, i64 %x
+  store i32 %1, i32 addrspace(1)* %arrayidx1, align 4
+  ret void
+}
+
+; CHECK-LABEL: test_load_bitcast_chain
+; CHECK: %[[GEP:.*]] = getelementptr [8 x i32], [8 x i32] addrspace(2)* @test.data, i64 0, i64 %x
+; CHECK: %{{.*}} = load i32, i32 addrspace(2)* %[[GEP]]
+; CHECK-NOT: alloca
+; CHECK-NOT: call void @llvm.memcpy.p0i8.p2i8.i64
+; CHECK-NOT: addrspacecast
+; CHECK-NOT: load i32, i32*
+define void @test_load_bitcast_chain(i32 addrspace(1)* %out, i64 %x) {
+entry:
+  %data = alloca [8 x i32], align 4
+  %0 = bitcast [8 x i32]* %data to i8*
+  call void @llvm.memcpy.p0i8.p2i8.i64(i8* align 4 %0, i8 addrspace(2)* align 4 bitcast ([8 x i32] addrspace(2)* @test.data to i8 addrspace(2)*), i64 32, i1 false)
+  %1 = bitcast i8* %0 to i32*
+  %arrayidx = getelementptr inbounds i32, i32* %1, i64 %x
+  %2 = load i32, i32* %arrayidx, align 4
+  %arrayidx1 = getelementptr inbounds i32, i32 addrspace(1)* %out, i64 %x
+  store i32 %2, i32 addrspace(1)* %arrayidx1, align 4
+  ret void
+}
+
+; CHECK-LABEL: test_call
+; CHECK: alloca
+; CHECK: call void @llvm.memcpy.p0i8.p2i8.i64
+; CHECK-NOT: addrspacecast
+; CHECK: call i32 @foo(i32* nonnull %{{.*}})
+define void @test_call(i32 addrspace(1)* %out, i64 %x) {
+entry:
+  %data = alloca [8 x i32], align 4
+  %0 = bitcast [8 x i32]* %data to i8*
+  call void @llvm.memcpy.p0i8.p2i8.i64(i8* align 4 %0, i8 addrspace(2)* align 4 bitcast ([8 x i32] addrspace(2)* @test.data to i8 addrspace(2)*), i64 32, i1 false)
+  %arrayidx = getelementptr inbounds [8 x i32], [8 x i32]* %data, i64 0, i64 %x
+  %1 = call i32 @foo(i32* %arrayidx)
+  %arrayidx1 = getelementptr inbounds i32, i32 addrspace(1)* %out, i64 %x
+  store i32 %1, i32 addrspace(1)* %arrayidx1, align 4
+  ret void
+}
+
+; CHECK-LABEL: test_call_no_null_opt
+; CHECK: alloca
+; CHECK: call void @llvm.memcpy.p0i8.p2i8.i64
+; CHECK-NOT: addrspacecast
+; CHECK: call i32 @foo(i32* %{{.*}})
+define void @test_call_no_null_opt(i32 addrspace(1)* %out, i64 %x) #0 {
+entry:
+  %data = alloca [8 x i32], align 4
+  %0 = bitcast [8 x i32]* %data to i8*
+  call void @llvm.memcpy.p0i8.p2i8.i64(i8* align 4 %0, i8 addrspace(2)* align 4 bitcast ([8 x i32] addrspace(2)* @test.data to i8 addrspace(2)*), i64 32, i1 false)
+  %arrayidx = getelementptr inbounds [8 x i32], [8 x i32]* %data, i64 0, i64 %x
+  %1 = call i32 @foo(i32* %arrayidx)
+  %arrayidx1 = getelementptr inbounds i32, i32 addrspace(1)* %out, i64 %x
+  store i32 %1, i32 addrspace(1)* %arrayidx1, align 4
+  ret void
+}
+
+; CHECK-LABEL: test_load_and_call
+; CHECK: alloca
+; CHECK: call void @llvm.memcpy.p0i8.p2i8.i64
+; CHECK: load i32, i32* %{{.*}}
+; CHECK: call i32 @foo(i32* nonnull %{{.*}})
+; CHECK-NOT: addrspacecast
+; CHECK-NOT: load i32, i32 addrspace(2)*
+define void @test_load_and_call(i32 addrspace(1)* %out, i64 %x, i64 %y) {
+entry:
+  %data = alloca [8 x i32], align 4
+  %0 = bitcast [8 x i32]* %data to i8*
+  call void @llvm.memcpy.p0i8.p2i8.i64(i8* align 4 %0, i8 addrspace(2)* align 4 bitcast ([8 x i32] addrspace(2)* @test.data to i8 addrspace(2)*), i64 32, i1 false)
+  %arrayidx = getelementptr inbounds [8 x i32], [8 x i32]* %data, i64 0, i64 %x
+  %1 = load i32, i32* %arrayidx, align 4
+  %arrayidx1 = getelementptr inbounds i32, i32 addrspace(1)* %out, i64 %x
+  store i32 %1, i32 addrspace(1)* %arrayidx1, align 4
+  %2 = call i32 @foo(i32* %arrayidx)
+  %arrayidx2 = getelementptr inbounds i32, i32 addrspace(1)* %out, i64 %y
+  store i32 %2, i32 addrspace(1)* %arrayidx2, align 4
+  ret void
+}
+
+; CHECK-LABEL: test_load_and_call_no_null_opt
+; CHECK: alloca
+; CHECK: call void @llvm.memcpy.p0i8.p2i8.i64
+; CHECK: load i32, i32* %{{.*}}
+; CHECK: call i32 @foo(i32* %{{.*}})
+; CHECK-NOT: addrspacecast
+; CHECK-NOT: load i32, i32 addrspace(2)*
+define void @test_load_and_call_no_null_opt(i32 addrspace(1)* %out, i64 %x, i64 %y) #0 {
+entry:
+  %data = alloca [8 x i32], align 4
+  %0 = bitcast [8 x i32]* %data to i8*
+  call void @llvm.memcpy.p0i8.p2i8.i64(i8* align 4 %0, i8 addrspace(2)* align 4 bitcast ([8 x i32] addrspace(2)* @test.data to i8 addrspace(2)*), i64 32, i1 false)
+  %arrayidx = getelementptr inbounds [8 x i32], [8 x i32]* %data, i64 0, i64 %x
+  %1 = load i32, i32* %arrayidx, align 4
+  %arrayidx1 = getelementptr inbounds i32, i32 addrspace(1)* %out, i64 %x
+  store i32 %1, i32 addrspace(1)* %arrayidx1, align 4
+  %2 = call i32 @foo(i32* %arrayidx)
+  %arrayidx2 = getelementptr inbounds i32, i32 addrspace(1)* %out, i64 %y
+  store i32 %2, i32 addrspace(1)* %arrayidx2, align 4
+  ret void
+}
+
+declare void @llvm.memcpy.p0i8.p2i8.i64(i8* nocapture writeonly, i8 addrspace(2)* nocapture readonly, i64, i1)
+declare i32 @foo(i32* %x)
+
+attributes #0 = { "null-pointer-is-valid"="true" }

Added: llvm/trunk/test/Transforms/InstCombine/memcpy-from-global.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/memcpy-from-global.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/memcpy-from-global.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/memcpy-from-global.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,259 @@
+; RUN: opt < %s -instcombine -S | FileCheck %s
+target datalayout = "E-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64"
+ at C.0.1248 = internal constant [128 x float] [ float -1.000000e+00, float -1.000000e+00, float -1.000000e+00, float 0.000000e+00, float -1.000000e+00, float -1.000000e+00, float 0.000000e+00, float -1.000000e+00, float -1.000000e+00, float -1.000000e+00, float 0.000000e+00, float 1.000000e+00, float -1.000000e+00, float -1.000000e+00, float 1.000000e+00, float 0.000000e+00, float -1.000000e+00, float 0.000000e+00, float -1.000000e+00, float -1.000000e+00, float -1.000000e+00, float 0.000000e+00, float -1.000000e+00, float 1.000000e+00, float -1.000000e+00, float 0.000000e+00, float 1.000000e+00, float -1.000000e+00, float -1.000000e+00, float 0.000000e+00, float 1.000000e+00, float 1.000000e+00, float -1.000000e+00, float 1.000000e+00, float -1.000000e+00, float 0.000000e+00, float -1.000000e+00, float 1.000000e+00, float 0.000000e+00, float -1.000000e+00, float -1.000000e+00, float 1.000000e+00, float 0.000000e+00, float 1.000000e+00, float -1.000000e+00, float 1.000000e+00, float 1.000000e+00, float 0.000000e+00, float 0.000000e+00, float -1.000000e+00, float -1.000000e+00, float -1.000000e+00, float 0.000000e+00, float -1.000000e+00, float -1.000000e+00, float 1.000000e+00, float 0.000000e+00, float -1.000000e+00, float 1.000000e+00, float -1.000000e+00, float 0.000000e+00, float -1.000000e+00, float 1.000000e+00, float 1.000000e+00, float 1.000000e+00, float -1.000000e+00, float -1.000000e+00, float 0.000000e+00, float 1.000000e+00, float -1.000000e+00, float 0.000000e+00, float -1.000000e+00, float 1.000000e+00, float -1.000000e+00, float 0.000000e+00, float 1.000000e+00, float 1.000000e+00, float -1.000000e+00, float 1.000000e+00, float 0.000000e+00, float 1.000000e+00, float 0.000000e+00, float -1.000000e+00, float -1.000000e+00, float 1.000000e+00, float 0.000000e+00, float -1.000000e+00, float 1.000000e+00, float 1.000000e+00, float 0.000000e+00, float 1.000000e+00, float -1.000000e+00, float 1.000000e+00, float 0.000000e+00, float 1.000000e+00, float 1.000000e+00, float 1.000000e+00, float 1.000000e+00, float -1.000000e+00, float 0.000000e+00, float 1.000000e+00, float 1.000000e+00, float 0.000000e+00, float -1.000000e+00, float 1.000000e+00, float 1.000000e+00, float 0.000000e+00, float 1.000000e+00, float 1.000000e+00, float 1.000000e+00, float 1.000000e+00, float 0.000000e+00, float 0.000000e+00, float 1.000000e+00, float -1.000000e+00, float -1.000000e+00, float 0.000000e+00, float 1.000000e+00, float -1.000000e+00, float 1.000000e+00, float 0.000000e+00, float 1.000000e+00, float 1.000000e+00, float -1.000000e+00, float 0.000000e+00, float 1.000000e+00, float 1.000000e+00, float 1.000000e+00 ], align 32		; <[128 x float]*> [#uses=1]
+
+define float @test1(i32 %hash, float %x, float %y, float %z, float %w) {
+entry:
+	%lookupTable = alloca [128 x float], align 16		; <[128 x float]*> [#uses=5]
+	%lookupTable1 = bitcast [128 x float]* %lookupTable to i8*		; <i8*> [#uses=1]
+	call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 16 %lookupTable1, i8* align 16 bitcast ([128 x float]* @C.0.1248 to i8*), i64 512, i1 false)
+
+; CHECK-LABEL: @test1(
+; CHECK-NOT: alloca
+; CHECK-NOT: call{{.*}}@llvm.memcpy
+
+	%tmp3 = shl i32 %hash, 2		; <i32> [#uses=1]
+	%tmp5 = and i32 %tmp3, 124		; <i32> [#uses=4]
+	%tmp753 = getelementptr [128 x float], [128 x float]* %lookupTable, i32 0, i32 %tmp5		; <float*> [#uses=1]
+	%tmp9 = load float, float* %tmp753		; <float> [#uses=1]
+	%tmp11 = fmul float %tmp9, %x		; <float> [#uses=1]
+	%tmp13 = fadd float %tmp11, 0.000000e+00		; <float> [#uses=1]
+	%tmp17.sum52 = or i32 %tmp5, 1		; <i32> [#uses=1]
+	%tmp1851 = getelementptr [128 x float], [128 x float]* %lookupTable, i32 0, i32 %tmp17.sum52		; <float*> [#uses=1]
+	%tmp19 = load float, float* %tmp1851		; <float> [#uses=1]
+	%tmp21 = fmul float %tmp19, %y		; <float> [#uses=1]
+	%tmp23 = fadd float %tmp21, %tmp13		; <float> [#uses=1]
+	%tmp27.sum50 = or i32 %tmp5, 2		; <i32> [#uses=1]
+	%tmp2849 = getelementptr [128 x float], [128 x float]* %lookupTable, i32 0, i32 %tmp27.sum50		; <float*> [#uses=1]
+	%tmp29 = load float, float* %tmp2849		; <float> [#uses=1]
+	%tmp31 = fmul float %tmp29, %z		; <float> [#uses=1]
+	%tmp33 = fadd float %tmp31, %tmp23		; <float> [#uses=1]
+	%tmp37.sum48 = or i32 %tmp5, 3		; <i32> [#uses=1]
+	%tmp3847 = getelementptr [128 x float], [128 x float]* %lookupTable, i32 0, i32 %tmp37.sum48		; <float*> [#uses=1]
+	%tmp39 = load float, float* %tmp3847		; <float> [#uses=1]
+	%tmp41 = fmul float %tmp39, %w		; <float> [#uses=1]
+	%tmp43 = fadd float %tmp41, %tmp33		; <float> [#uses=1]
+	ret float %tmp43
+}
+
+declare void @llvm.memcpy.p0i8.p0i8.i64(i8* nocapture, i8* nocapture, i64, i1) nounwind
+declare void @llvm.memcpy.p1i8.p0i8.i64(i8 addrspace(1)* nocapture, i8* nocapture, i64, i1) nounwind
+declare void @llvm.memcpy.p0i8.p1i8.i64(i8* nocapture, i8 addrspace(1)* nocapture, i64, i1) nounwind
+declare void @llvm.memcpy.p1i8.p1i8.i64(i8 addrspace(1)* nocapture, i8 addrspace(1)* nocapture, i64, i1) nounwind
+
+%T = type { i8, [123 x i8] }
+%U = type { i32, i32, i32, i32, i32 }
+
+ at G = constant %T {i8 1, [123 x i8] zeroinitializer }
+ at H = constant [2 x %U] zeroinitializer, align 16
+
+define void @test2() {
+  %A = alloca %T
+  %B = alloca %T
+  %a = bitcast %T* %A to i8*
+  %b = bitcast %T* %B to i8*
+
+; CHECK-LABEL: @test2(
+
+; %A alloca is deleted
+; CHECK-NEXT: alloca [124 x i8]
+; CHECK-NEXT: getelementptr inbounds [124 x i8], [124 x i8]*
+
+; use @G instead of %A
+; CHECK-NEXT: call void @llvm.memcpy.p0i8.p0i8.i64(i8* nonnull align 8 %{{.*}}, i8* align 16 getelementptr inbounds (%T, %T* @G, i64 0, i32 0)
+  call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 4 %a, i8* align 4 bitcast (%T* @G to i8*), i64 124, i1 false)
+  call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 4 %b, i8* align 4 %a, i64 124, i1 false)
+  call void @bar(i8* %b)
+  ret void
+}
+
+define void @test2_no_null_opt() #0 {
+  %A = alloca %T
+  %B = alloca %T
+  %a = bitcast %T* %A to i8*
+  %b = bitcast %T* %B to i8*
+
+; CHECK-LABEL: @test2_no_null_opt(
+
+; %A alloca is deleted
+; CHECK-NEXT: alloca [124 x i8]
+; CHECK-NEXT: getelementptr inbounds [124 x i8], [124 x i8]*
+
+; use @G instead of %A
+; CHECK-NEXT: call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 8 %{{.*}}, i8* align 16 getelementptr inbounds (%T, %T* @G, i64 0, i32 0)
+  call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 4 %a, i8* align 4 bitcast (%T* @G to i8*), i64 124, i1 false)
+  call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 4 %b, i8* align 4 %a, i64 124, i1 false)
+  call void @bar(i8* %b)
+  ret void
+}
+
+define void @test2_addrspacecast() {
+  %A = alloca %T
+  %B = alloca %T
+  %a = addrspacecast %T* %A to i8 addrspace(1)*
+  %b = addrspacecast %T* %B to i8 addrspace(1)*
+
+; CHECK-LABEL: @test2_addrspacecast(
+
+; %A alloca is deleted
+; This doesn't exactly match what test2 does, because folding the type
+; cast into the alloca doesn't work for the addrspacecast yet.
+; CHECK-NEXT: alloca [124 x i8]
+; CHECK-NEXT: getelementptr
+; CHECK-NEXT: addrspacecast
+
+; use @G instead of %A
+; CHECK-NEXT: call void @llvm.memcpy.p1i8.p1i8.i64(i8 addrspace(1)* align 4 %{{.*}},
+  call void @llvm.memcpy.p1i8.p0i8.i64(i8 addrspace(1)* align 4 %a, i8* align 4 bitcast (%T* @G to i8*), i64 124, i1 false)
+  call void @llvm.memcpy.p1i8.p1i8.i64(i8 addrspace(1)* align 4 %b, i8 addrspace(1)* align 4 %a, i64 124, i1 false)
+  call void @bar_as1(i8 addrspace(1)* %b)
+  ret void
+}
+
+declare void @bar(i8*)
+declare void @bar_as1(i8 addrspace(1)*)
+
+
+;; Should be able to eliminate the alloca.
+define void @test3() {
+  %A = alloca %T
+  %a = bitcast %T* %A to i8*
+  call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 4 %a, i8* align 4 bitcast (%T* @G to i8*), i64 124, i1 false)
+  call void @bar(i8* %a) readonly
+; CHECK-LABEL: @test3(
+; CHECK-NEXT: call void @bar(i8* getelementptr inbounds (%T, %T* @G, i64 0, i32 0))
+  ret void
+}
+
+define void @test3_addrspacecast() {
+  %A = alloca %T
+  %a = bitcast %T* %A to i8*
+  call void @llvm.memcpy.p0i8.p1i8.i64(i8* align 4 %a, i8 addrspace(1)* align 4 addrspacecast (%T* @G to i8 addrspace(1)*), i64 124, i1 false)
+  call void @bar(i8* %a) readonly
+; CHECK-LABEL: @test3_addrspacecast(
+; CHECK-NEXT: call void @bar(i8* getelementptr inbounds (%T, %T* @G, i64 0, i32 0))
+  ret void
+}
+
+
+define void @test4() {
+  %A = alloca %T
+  %a = bitcast %T* %A to i8*
+  call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 4 %a, i8* align 4 bitcast (%T* @G to i8*), i64 124, i1 false)
+  call void @baz(i8* byval %a)
+; CHECK-LABEL: @test4(
+; CHECK-NEXT: call void @baz(i8* byval getelementptr inbounds (%T, %T* @G, i64 0, i32 0))
+  ret void
+}
+
+declare void @llvm.lifetime.start.p0i8(i64, i8*)
+define void @test5() {
+  %A = alloca %T
+  %a = bitcast %T* %A to i8*
+  call void @llvm.lifetime.start.p0i8(i64 -1, i8* %a)
+  call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 4 %a, i8* align 4 bitcast (%T* @G to i8*), i64 124, i1 false)
+  call void @baz(i8* byval %a)
+; CHECK-LABEL: @test5(
+; CHECK-NEXT: call void @baz(i8* byval getelementptr inbounds (%T, %T* @G, i64 0, i32 0))
+  ret void
+}
+
+
+declare void @baz(i8* byval)
+
+
+define void @test6() {
+  %A = alloca %U, align 16
+  %a = bitcast %U* %A to i8*
+  call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 16 %a, i8* align 16 bitcast ([2 x %U]* @H to i8*), i64 20, i1 false)
+  call void @bar(i8* %a) readonly
+; CHECK-LABEL: @test6(
+; CHECK-NEXT: call void @bar(i8* bitcast ([2 x %U]* @H to i8*))
+  ret void
+}
+
+define void @test7() {
+  %A = alloca %U, align 16
+  %a = bitcast %U* %A to i8*
+  call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 4 %a, i8* align 4 bitcast (%U* getelementptr ([2 x %U], [2 x %U]* @H, i64 0, i32 0) to i8*), i64 20, i1 false)
+  call void @bar(i8* %a) readonly
+; CHECK-LABEL: @test7(
+; CHECK-NEXT: call void @bar(i8* bitcast ([2 x %U]* @H to i8*))
+  ret void
+}
+
+define void @test8() {
+  %A = alloca %U, align 16
+  %a = bitcast %U* %A to i8*
+  call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 4 %a, i8* align 4 bitcast (%U* getelementptr ([2 x %U], [2 x %U]* @H, i64 0, i32 1) to i8*), i64 20, i1 false)
+  call void @bar(i8* %a) readonly
+; CHECK-LABEL: @test8(
+; CHECK: llvm.memcpy
+; CHECK: bar
+  ret void
+}
+
+
+define void @test8_addrspacecast() {
+  %A = alloca %U, align 16
+  %a = bitcast %U* %A to i8*
+  call void @llvm.memcpy.p0i8.p1i8.i64(i8* align 4 %a, i8 addrspace(1)* align 4 addrspacecast (%U* getelementptr ([2 x %U], [2 x %U]* @H, i64 0, i32 1) to i8 addrspace(1)*), i64 20, i1 false)
+  call void @bar(i8* %a) readonly
+; CHECK-LABEL: @test8_addrspacecast(
+; CHECK: llvm.memcpy
+; CHECK: bar
+  ret void
+}
+
+define void @test9() {
+  %A = alloca %U, align 4
+  %a = bitcast %U* %A to i8*
+  call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 4 %a, i8* align 4 bitcast (%U* getelementptr ([2 x %U], [2 x %U]* @H, i64 0, i32 1) to i8*), i64 20, i1 false)
+  call void @bar(i8* %a) readonly
+; CHECK-LABEL: @test9(
+; CHECK-NEXT: call void @bar(i8* bitcast (%U* getelementptr inbounds ([2 x %U], [2 x %U]* @H, i64 0, i64 1) to i8*))
+  ret void
+}
+
+define void @test9_addrspacecast() {
+  %A = alloca %U, align 4
+  %a = bitcast %U* %A to i8*
+  call void @llvm.memcpy.p0i8.p1i8.i64(i8* align 4 %a, i8 addrspace(1)* align 4 addrspacecast (%U* getelementptr ([2 x %U], [2 x %U]* @H, i64 0, i32 1) to i8 addrspace(1)*), i64 20, i1 false)
+  call void @bar(i8* %a) readonly
+; CHECK-LABEL: @test9_addrspacecast(
+; CHECK-NEXT: call void @bar(i8* bitcast (%U* getelementptr inbounds ([2 x %U], [2 x %U]* @H, i64 0, i64 1) to i8*))
+  ret void
+}
+
+ at bbb = local_unnamed_addr global [1000000 x i8] zeroinitializer, align 16
+ at _ZL3KKK = internal unnamed_addr constant [3 x i8] c"\01\01\02", align 1
+
+; Should not replace alloca with global because of size mismatch.
+define void @test9_small_global() {
+; CHECK-LABEL: @test9_small_global(
+; CHECK-NOT: call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}@bbb,{{.*}}@_ZL3KKK, 
+; CHECK: alloca [1000000 x i8]
+entry:
+  %cc = alloca [1000000 x i8], align 16
+  %cc.0..sroa_idx = getelementptr inbounds [1000000 x i8], [1000000 x i8]* %cc, i64 0, i64 0
+  %arraydecay = getelementptr inbounds [1000000 x i8], [1000000 x i8]* %cc, i32 0, i32 0
+  call void @llvm.memcpy.p0i8.p0i8.i64(i8* %arraydecay, i8* getelementptr inbounds ([3 x i8], [3 x i8]* @_ZL3KKK, i32 0, i32 0), i64 3, i1 false)
+  call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 16 getelementptr inbounds ([1000000 x i8], [1000000 x i8]* @bbb, i32 0, i32 0), i8* align 16 %arraydecay, i64 1000000, i1 false)
+  ret void
+}
+
+; Should replace alloca with global as they have exactly the same size.
+define void @test10_same_global() {
+; CHECK-LABEL: @test10_same_global(
+; CHECK-NOT: alloca
+; CHECK: call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}@bbb,{{.*}}@_ZL3KKK,{{.*}}, i64 3,
+entry:
+  %cc = alloca [3 x i8], align 1
+  %cc.0..sroa_idx = getelementptr inbounds [3 x i8], [3 x i8]* %cc, i64 0, i64 0
+  %arraydecay = getelementptr inbounds [3 x i8], [3 x i8]* %cc, i32 0, i32 0
+  call void @llvm.memcpy.p0i8.p0i8.i64(i8* %arraydecay, i8* getelementptr inbounds ([3 x i8], [3 x i8]* @_ZL3KKK, i32 0, i32 0), i64 3, i1 false)
+  call void @llvm.memcpy.p0i8.p0i8.i64(i8* getelementptr inbounds ([1000000 x i8], [1000000 x i8]* @bbb, i32 0, i32 0), i8* %arraydecay, i64 3, i1 false)
+  ret void
+}
+
+attributes #0 = { "null-pointer-is-valid"="true" }

Added: llvm/trunk/test/Transforms/InstCombine/memcpy-to-load.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/memcpy-to-load.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/memcpy-to-load.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/memcpy-to-load.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,87 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt < %s -instcombine -S                         | FileCheck %s --check-prefix=ALL --check-prefix=NODL
+; RUN: opt < %s -instcombine -S -data-layout=n32        | FileCheck %s --check-prefix=ALL --check-prefix=I32
+; RUN: opt < %s -instcombine -S -data-layout=n32:64     | FileCheck %s --check-prefix=ALL --check-prefix=I64
+; RUN: opt < %s -instcombine -S -data-layout=n32:64:128 | FileCheck %s --check-prefix=ALL --check-prefix=I128
+
+declare void @llvm.memcpy.p0i8.p0i8.i32(i8* nocapture, i8* nocapture, i32, i1) nounwind
+
+; memcpy can be expanded inline with load/store (based on the datalayout?)
+
+define void @copy_1_byte(i8* %d, i8* %s) {
+; ALL-LABEL: @copy_1_byte(
+; ALL-NEXT:    [[TMP1:%.*]] = load i8, i8* [[S:%.*]], align 1
+; ALL-NEXT:    store i8 [[TMP1]], i8* [[D:%.*]], align 1
+; ALL-NEXT:    ret void
+;
+  call void @llvm.memcpy.p0i8.p0i8.i32(i8* %d, i8* %s, i32 1, i1 false)
+  ret void
+}
+
+define void @copy_2_bytes(i8* %d, i8* %s) {
+; ALL-LABEL: @copy_2_bytes(
+; ALL-NEXT:    [[TMP1:%.*]] = bitcast i8* [[S:%.*]] to i16*
+; ALL-NEXT:    [[TMP2:%.*]] = bitcast i8* [[D:%.*]] to i16*
+; ALL-NEXT:    [[TMP3:%.*]] = load i16, i16* [[TMP1]], align 1
+; ALL-NEXT:    store i16 [[TMP3]], i16* [[TMP2]], align 1
+; ALL-NEXT:    ret void
+;
+  call void @llvm.memcpy.p0i8.p0i8.i32(i8* %d, i8* %s, i32 2, i1 false)
+  ret void
+}
+
+; We don't expand small non-power-of-2. Should we? Might be a target-dependent choice.
+
+define void @copy_3_bytes(i8* %d, i8* %s) {
+; ALL-LABEL: @copy_3_bytes(
+; ALL-NEXT:    call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 1 [[D:%.*]], i8* align 1 [[S:%.*]], i32 3, i1 false)
+; ALL-NEXT:    ret void
+;
+  call void @llvm.memcpy.p0i8.p0i8.i32(i8* %d, i8* %s, i32 3, i1 false)
+  ret void
+}
+
+define void @copy_4_bytes(i8* %d, i8* %s) {
+; ALL-LABEL: @copy_4_bytes(
+; ALL-NEXT:    [[TMP1:%.*]] = bitcast i8* [[S:%.*]] to i32*
+; ALL-NEXT:    [[TMP2:%.*]] = bitcast i8* [[D:%.*]] to i32*
+; ALL-NEXT:    [[TMP3:%.*]] = load i32, i32* [[TMP1]], align 1
+; ALL-NEXT:    store i32 [[TMP3]], i32* [[TMP2]], align 1
+; ALL-NEXT:    ret void
+;
+  call void @llvm.memcpy.p0i8.p0i8.i32(i8* %d, i8* %s, i32 4, i1 false)
+  ret void
+}
+
+; We don't expand small non-power-of-2. Should we? Might be a target-dependent choice.
+
+define void @copy_5_bytes(i8* %d, i8* %s) {
+; ALL-LABEL: @copy_5_bytes(
+; ALL-NEXT:    call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 1 [[D:%.*]], i8* align 1 [[S:%.*]], i32 5, i1 false)
+; ALL-NEXT:    ret void
+;
+  call void @llvm.memcpy.p0i8.p0i8.i32(i8* %d, i8* %s, i32 5, i1 false)
+  ret void
+}
+
+define void @copy_8_bytes(i8* %d, i8* %s) {
+; ALL-LABEL: @copy_8_bytes(
+; ALL-NEXT:    [[TMP1:%.*]] = bitcast i8* [[S:%.*]] to i64*
+; ALL-NEXT:    [[TMP2:%.*]] = bitcast i8* [[D:%.*]] to i64*
+; ALL-NEXT:    [[TMP3:%.*]] = load i64, i64* [[TMP1]], align 1
+; ALL-NEXT:    store i64 [[TMP3]], i64* [[TMP2]], align 1
+; ALL-NEXT:    ret void
+;
+  call void @llvm.memcpy.p0i8.p0i8.i32(i8* %d, i8* %s, i32 8, i1 false)
+  ret void
+}
+
+define void @copy_16_bytes(i8* %d, i8* %s) {
+; ALL-LABEL: @copy_16_bytes(
+; ALL-NEXT:    call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 1 [[D:%.*]], i8* align 1 [[S:%.*]], i32 16, i1 false)
+; ALL-NEXT:    ret void
+;
+  call void @llvm.memcpy.p0i8.p0i8.i32(i8* %d, i8* %s, i32 16, i1 false)
+  ret void
+}
+

Added: llvm/trunk/test/Transforms/InstCombine/memcpy.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/memcpy.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/memcpy.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/memcpy.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,49 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt < %s -instcombine -S | FileCheck %s
+
+declare void @llvm.memcpy.p0i8.p0i8.i32(i8* nocapture, i8* nocapture, i32, i1) nounwind
+declare void @llvm.memcpy.p0i8.p0i8.i64(i8* nocapture, i8* nocapture, i64, i1) nounwind
+
+; Same src/dest.
+
+define void @test1(i8* %a) {
+; CHECK-LABEL: @test1(
+; CHECK-NEXT:    ret void
+;
+  tail call void @llvm.memcpy.p0i8.p0i8.i32(i8* %a, i8* %a, i32 100, i1 false)
+  ret void
+}
+
+; PR8267 - same src/dest, but volatile.
+
+define void @test2(i8* %a) {
+; CHECK-LABEL: @test2(
+; CHECK-NEXT:    tail call void @llvm.memcpy.p0i8.p0i8.i32(i8* [[A:%.*]], i8* [[A]], i32 100, i1 true)
+; CHECK-NEXT:    ret void
+;
+  tail call void @llvm.memcpy.p0i8.p0i8.i32(i8* %a, i8* %a, i32 100, i1 true)
+  ret void
+}
+
+; 17179869184 == 0x400000000 - make sure that doesn't get truncated to 32-bit.
+
+define void @test3(i8* %d, i8* %s) {
+; CHECK-LABEL: @test3(
+; CHECK-NEXT:    tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 4 [[D:%.*]], i8* align 4 [[S:%.*]], i64 17179869184, i1 false)
+; CHECK-NEXT:    ret void
+;
+  tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 4 %d, i8* align 4 %s, i64 17179869184, i1 false)
+  ret void
+}
+
+ at UnknownConstant = external constant i128
+
+define void @memcpy_to_constant(i8* %src) {
+; CHECK-LABEL: @memcpy_to_constant(
+; CHECK-NEXT:    call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 4 bitcast (i128* @UnknownConstant to i8*), i8* align 1 [[SRC:%.*]], i32 16, i1 false)
+; CHECK-NEXT:    ret void
+;
+  %dest = bitcast i128* @UnknownConstant to i8*
+  call void @llvm.memcpy.p0i8.p0i8.i32(i8* %dest, i8* %src, i32 16, i1 false)
+  ret void
+}

Added: llvm/trunk/test/Transforms/InstCombine/memcpy_chk-1.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/memcpy_chk-1.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/memcpy_chk-1.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/memcpy_chk-1.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,77 @@
+; Test lib call simplification of __memcpy_chk calls with various values
+; for dstlen and len.
+;
+; RUN: opt < %s -instcombine -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"
+
+%struct.T1 = type { [100 x i32], [100 x i32], [1024 x i8] }
+%struct.T2 = type { [100 x i32], [100 x i32], [1024 x i8] }
+%struct.T3 = type { [100 x i32], [100 x i32], [2048 x i8] }
+
+ at t1 = common global %struct.T1 zeroinitializer
+ at t2 = common global %struct.T2 zeroinitializer
+ at t3 = common global %struct.T3 zeroinitializer
+
+; Check cases where dstlen >= len.
+
+define i8* @test_simplify1() {
+; CHECK-LABEL: @test_simplify1(
+  %dst = bitcast %struct.T1* @t1 to i8*
+  %src = bitcast %struct.T2* @t2 to i8*
+
+; CHECK-NEXT: call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 4 bitcast (%struct.T1* @t1 to i8*), i8* align 4 bitcast (%struct.T2* @t2 to i8*), i64 1824, i1 false)
+; CHECK-NEXT: ret i8* bitcast (%struct.T1* @t1 to i8*)
+  %ret = call i8* @__memcpy_chk(i8* %dst, i8* %src, i64 1824, i64 1824)
+  ret i8* %ret
+}
+
+define i8* @test_simplify2() {
+; CHECK-LABEL: @test_simplify2(
+  %dst = bitcast %struct.T1* @t1 to i8*
+  %src = bitcast %struct.T3* @t3 to i8*
+
+; CHECK-NEXT: call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 4 bitcast (%struct.T1* @t1 to i8*), i8* align 4 bitcast (%struct.T3* @t3 to i8*), i64 1824, i1 false)
+; CHECK-NEXT: ret i8* bitcast (%struct.T1* @t1 to i8*)
+  %ret = call i8* @__memcpy_chk(i8* %dst, i8* %src, i64 1824, i64 2848)
+  ret i8* %ret
+}
+
+; Check cases where dstlen < len.
+
+define i8* @test_no_simplify1() {
+; CHECK-LABEL: @test_no_simplify1(
+  %dst = bitcast %struct.T3* @t3 to i8*
+  %src = bitcast %struct.T1* @t1 to i8*
+
+; CHECK-NEXT: %ret = call i8* @__memcpy_chk(i8* bitcast (%struct.T3* @t3 to i8*), i8* bitcast (%struct.T1* @t1 to i8*), i64 2848, i64 1824)
+; CHECK-NEXT: ret i8* %ret
+  %ret = call i8* @__memcpy_chk(i8* %dst, i8* %src, i64 2848, i64 1824)
+  ret i8* %ret
+}
+
+define i8* @test_no_simplify2() {
+; CHECK-LABEL: @test_no_simplify2(
+  %dst = bitcast %struct.T1* @t1 to i8*
+  %src = bitcast %struct.T2* @t2 to i8*
+
+; CHECK-NEXT: %ret = call i8* @__memcpy_chk(i8* bitcast (%struct.T1* @t1 to i8*), i8* bitcast (%struct.T2* @t2 to i8*), i64 1024, i64 0)
+; CHECK-NEXT: ret i8* %ret
+  %ret = call i8* @__memcpy_chk(i8* %dst, i8* %src, i64 1024, i64 0)
+  ret i8* %ret
+}
+
+define i8* @test_simplify_return_indcall(i8* ()* %alloc) {
+; CHECK-LABEL: @test_simplify_return_indcall(
+  %src = bitcast %struct.T2* @t2 to i8*
+
+; CHECK-NEXT: %dst = call i8* %alloc()
+  %dst = call i8* %alloc()
+
+; CHECK-NEXT: call void @llvm.memcpy.p0i8.p0i8.i64
+  %ret = call i8* @__memcpy_chk(i8* %dst, i8* %src, i64 1824, i64 1824)
+; CHECK-NEXT: ret i8* %dst
+  ret i8* %ret
+}
+
+declare i8* @__memcpy_chk(i8*, i8*, i64, i64)

Added: llvm/trunk/test/Transforms/InstCombine/memcpy_chk-2.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/memcpy_chk-2.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/memcpy_chk-2.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/memcpy_chk-2.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,24 @@
+; Test that lib call simplification doesn't simplify __memcpy_chk calls
+; with the wrong prototype.
+;
+; RUN: opt < %s -instcombine -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"
+
+%struct.T1 = type { [100 x i32], [100 x i32], [1024 x i8] }
+%struct.T2 = type { [100 x i32], [100 x i32], [1024 x i8] }
+
+ at t1 = common global %struct.T1 zeroinitializer
+ at t2 = common global %struct.T2 zeroinitializer
+
+define void @test_no_simplify() {
+; CHECK-LABEL: @test_no_simplify(
+  %dst = bitcast %struct.T1* @t1 to i8*
+  %src = bitcast %struct.T2* @t2 to i8*
+
+; CHECK-NEXT: call i8* @__memcpy_chk
+  call i8* @__memcpy_chk(i8* %dst, i8* %src, i64 1824)
+  ret void
+}
+
+declare i8* @__memcpy_chk(i8*, i8*, i64)

Added: llvm/trunk/test/Transforms/InstCombine/memmove-1.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/memmove-1.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/memmove-1.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/memmove-1.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,17 @@
+; Test that the memmove library call simplifier works correctly.
+;
+; RUN: opt < %s -instcombine -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:128:128"
+
+declare i8* @memmove(i8*, i8*, i32)
+
+; Check memmove(mem1, mem2, size) -> llvm.memmove(mem1, mem2, size, 1).
+
+define i8* @test_simplify1(i8* %mem1, i8* %mem2, i32 %size) {
+; CHECK-LABEL: @test_simplify1(
+  %ret = call i8* @memmove(i8* %mem1, i8* %mem2, i32 %size)
+; CHECK: call void @llvm.memmove
+  ret i8* %ret
+; CHECK: ret i8* %mem1
+}

Added: llvm/trunk/test/Transforms/InstCombine/memmove-2.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/memmove-2.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/memmove-2.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/memmove-2.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,17 @@
+; Test that the memmove library call simplifier works correctly.
+;
+; RUN: opt < %s -instcombine -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:128:128"
+
+declare i8 @memmove(i8*, i8*, i32)
+
+; Check that memmove functions with the wrong prototype aren't simplified.
+
+define i8 @test_no_simplify1(i8* %mem1, i8* %mem2, i32 %size) {
+; CHECK-LABEL: @test_no_simplify1(
+  %ret = call i8 @memmove(i8* %mem1, i8* %mem2, i32 %size)
+; CHECK: call i8 @memmove
+  ret i8 %ret
+; CHECK: ret i8 %ret
+}

Added: llvm/trunk/test/Transforms/InstCombine/memmove.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/memmove.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/memmove.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/memmove.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,71 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; This test makes sure that memmove instructions are properly eliminated.
+;
+; RUN: opt < %s -instcombine -S | FileCheck %s
+
+ at S = internal constant [33 x i8] c"panic: restorelist inconsistency\00"		; <[33 x i8]*> [#uses=1]
+ at h = constant [2 x i8] c"h\00"		; <[2 x i8]*> [#uses=1]
+ at hel = constant [4 x i8] c"hel\00"		; <[4 x i8]*> [#uses=1]
+ at hello_u = constant [8 x i8] c"hello_u\00"		; <[8 x i8]*> [#uses=1]
+
+define void @test1(i8* %A, i8* %B, i32 %N) {
+; CHECK-LABEL: @test1(
+; CHECK-NEXT:    ret void
+;
+  call void @llvm.memmove.p0i8.p0i8.i32(i8* %A, i8* %B, i32 0, i1 false)
+  ret void
+}
+
+define void @test2(i8* %A, i32 %N) {
+  ;; dest can't alias source since we can't write to source!
+; CHECK-LABEL: @test2(
+; CHECK-NEXT:    call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 1 [[A:%.*]], i8* align 16 getelementptr inbounds ([33 x i8], [33 x i8]* @S, i64 0, i64 0), i32 [[N:%.*]], i1 false)
+; CHECK-NEXT:    ret void
+;
+  call void @llvm.memmove.p0i8.p0i8.i32(i8* %A, i8* getelementptr inbounds ([33 x i8], [33 x i8]* @S, i32 0, i32 0), i32 %N, i1 false)
+  ret void
+}
+
+define i32 @test3([1024 x i8]* %target) { ; arg: [1024 x i8]*> [#uses=1]
+; CHECK-LABEL: @test3(
+; CHECK-NEXT:    [[TMP1:%.*]] = bitcast [1024 x i8]* [[TARGET:%.*]] to i16*
+; CHECK-NEXT:    store i16 104, i16* [[TMP1]], align 2
+; CHECK-NEXT:    [[TMP2:%.*]] = bitcast [1024 x i8]* [[TARGET]] to i32*
+; CHECK-NEXT:    store i32 7103848, i32* [[TMP2]], align 4
+; CHECK-NEXT:    [[TMP3:%.*]] = bitcast [1024 x i8]* [[TARGET]] to i64*
+; CHECK-NEXT:    store i64 33037504440198504, i64* [[TMP3]], align 8
+; CHECK-NEXT:    ret i32 0
+;
+  %h_p = getelementptr [2 x i8], [2 x i8]* @h, i32 0, i32 0		; <i8*> [#uses=1]
+  %hel_p = getelementptr [4 x i8], [4 x i8]* @hel, i32 0, i32 0		; <i8*> [#uses=1]
+  %hello_u_p = getelementptr [8 x i8], [8 x i8]* @hello_u, i32 0, i32 0		; <i8*> [#uses=1]
+  %target_p = getelementptr [1024 x i8], [1024 x i8]* %target, i32 0, i32 0		; <i8*> [#uses=3]
+  call void @llvm.memmove.p0i8.p0i8.i32(i8* align 2 %target_p, i8* align 2 %h_p, i32 2, i1 false)
+  call void @llvm.memmove.p0i8.p0i8.i32(i8* align 4 %target_p, i8* align 4 %hel_p, i32 4, i1 false)
+  call void @llvm.memmove.p0i8.p0i8.i32(i8* align 8 %target_p, i8* align 8 %hello_u_p, i32 8, i1 false)
+  ret i32 0
+}
+
+; PR2370
+define void @test4(i8* %a) {
+; CHECK-LABEL: @test4(
+; CHECK-NEXT:    ret void
+;
+  tail call void @llvm.memmove.p0i8.p0i8.i32(i8* %a, i8* %a, i32 100, i1 false)
+  ret void
+}
+
+ at UnknownConstant = external constant i128
+
+define void @memmove_to_constant(i8* %src) {
+; CHECK-LABEL: @memmove_to_constant(
+; CHECK-NEXT:    call void @llvm.memmove.p0i8.p0i8.i32(i8* align 4 bitcast (i128* @UnknownConstant to i8*), i8* align 1 [[SRC:%.*]], i32 16, i1 false)
+; CHECK-NEXT:    ret void
+;
+  %dest = bitcast i128* @UnknownConstant to i8*
+  call void @llvm.memmove.p0i8.p0i8.i32(i8* %dest, i8* %src, i32 16, i1 false)
+  ret void
+}
+
+
+declare void @llvm.memmove.p0i8.p0i8.i32(i8* nocapture, i8* nocapture readonly, i32, i1) argmemonly nounwind

Added: llvm/trunk/test/Transforms/InstCombine/memmove_chk-1.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/memmove_chk-1.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/memmove_chk-1.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/memmove_chk-1.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,64 @@
+; Test lib call simplification of __memmove_chk calls with various values
+; for dstlen and len.
+;
+; RUN: opt < %s -instcombine -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"
+
+%struct.T1 = type { [100 x i32], [100 x i32], [1024 x i8] }
+%struct.T2 = type { [100 x i32], [100 x i32], [1024 x i8] }
+%struct.T3 = type { [100 x i32], [100 x i32], [2048 x i8] }
+
+ at t1 = common global %struct.T1 zeroinitializer
+ at t2 = common global %struct.T2 zeroinitializer
+ at t3 = common global %struct.T3 zeroinitializer
+
+; Check cases where dstlen >= len.
+
+define i8* @test_simplify1() {
+; CHECK-LABEL: @test_simplify1(
+  %dst = bitcast %struct.T1* @t1 to i8*
+  %src = bitcast %struct.T2* @t2 to i8*
+
+; CHECK-NEXT: call void @llvm.memmove.p0i8.p0i8.i64(i8* align 4 bitcast (%struct.T1* @t1 to i8*), i8* align 4 bitcast (%struct.T2* @t2 to i8*), i64 1824, i1 false)
+; CHECK-NEXT: ret i8* bitcast (%struct.T1* @t1 to i8*)
+  %ret = call i8* @__memmove_chk(i8* %dst, i8* %src, i64 1824, i64 1824)
+  ret i8* %ret
+}
+
+define i8* @test_simplify2() {
+; CHECK-LABEL: @test_simplify2(
+  %dst = bitcast %struct.T1* @t1 to i8*
+  %src = bitcast %struct.T3* @t3 to i8*
+
+; CHECK-NEXT: call void @llvm.memmove.p0i8.p0i8.i64(i8* align 4 bitcast (%struct.T1* @t1 to i8*), i8* align 4 bitcast (%struct.T3* @t3 to i8*), i64 1824, i1 false)
+; CHECK-NEXT: ret i8* bitcast (%struct.T1* @t1 to i8*)
+  %ret = call i8* @__memmove_chk(i8* %dst, i8* %src, i64 1824, i64 2848)
+  ret i8* %ret
+}
+
+; Check cases where dstlen < len.
+
+define i8* @test_no_simplify1() {
+; CHECK-LABEL: @test_no_simplify1(
+  %dst = bitcast %struct.T3* @t3 to i8*
+  %src = bitcast %struct.T1* @t1 to i8*
+
+; CHECK-NEXT: %ret = call i8* @__memmove_chk(i8* bitcast (%struct.T3* @t3 to i8*), i8* bitcast (%struct.T1* @t1 to i8*), i64 2848, i64 1824)
+; CHECK-NEXT: ret i8* %ret
+  %ret = call i8* @__memmove_chk(i8* %dst, i8* %src, i64 2848, i64 1824)
+  ret i8* %ret
+}
+
+define i8* @test_no_simplify2() {
+; CHECK-LABEL: @test_no_simplify2(
+  %dst = bitcast %struct.T1* @t1 to i8*
+  %src = bitcast %struct.T2* @t2 to i8*
+
+; CHECK-NEXT: %ret = call i8* @__memmove_chk(i8* bitcast (%struct.T1* @t1 to i8*), i8* bitcast (%struct.T2* @t2 to i8*), i64 1024, i64 0)
+; CHECK-NEXT: ret i8* %ret
+  %ret = call i8* @__memmove_chk(i8* %dst, i8* %src, i64 1024, i64 0)
+  ret i8* %ret
+}
+
+declare i8* @__memmove_chk(i8*, i8*, i64, i64)

Added: llvm/trunk/test/Transforms/InstCombine/memmove_chk-2.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/memmove_chk-2.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/memmove_chk-2.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/memmove_chk-2.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,24 @@
+; Test that lib call simplification doesn't simplify __memmove_chk calls
+; with the wrong prototype.
+;
+; RUN: opt < %s -instcombine -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"
+
+%struct.T1 = type { [100 x i32], [100 x i32], [1024 x i8] }
+%struct.T2 = type { [100 x i32], [100 x i32], [1024 x i8] }
+
+ at t1 = common global %struct.T1 zeroinitializer
+ at t2 = common global %struct.T2 zeroinitializer
+
+define void @test_no_simplify() {
+; CHECK-LABEL: @test_no_simplify(
+  %dst = bitcast %struct.T1* @t1 to i8*
+  %src = bitcast %struct.T2* @t2 to i8*
+
+; CHECK-NEXT: call i8* @__memmove_chk
+  call i8* @__memmove_chk(i8* %dst, i8* %src, i64 1824)
+  ret void
+}
+
+declare i8* @__memmove_chk(i8*, i8*, i64)

Added: llvm/trunk/test/Transforms/InstCombine/memset-1.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/memset-1.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/memset-1.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/memset-1.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,108 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; Test that the memset library call simplifier works correctly.
+;
+; RUN: opt < %s -instcombine -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:128:128"
+
+declare i8* @memset(i8*, i32, i32)
+declare void @llvm.memset.p0i8.i32(i8* nocapture writeonly, i8, i32, i32, i1)
+declare noalias i8* @malloc(i32) #1
+
+; Check memset(mem1, val, size) -> llvm.memset(mem1, val, size, 1).
+
+define i8* @test_simplify1(i8* %mem, i32 %val, i32 %size) {
+; CHECK-LABEL: @test_simplify1(
+; CHECK-NEXT:    [[TMP1:%.*]] = trunc i32 [[VAL:%.*]] to i8
+; CHECK-NEXT:    call void @llvm.memset.p0i8.i32(i8* align 1 [[MEM:%.*]], i8 [[TMP1]], i32 [[SIZE:%.*]], i1 false)
+; CHECK-NEXT:    ret i8* [[MEM]]
+;
+  %ret = call i8* @memset(i8* %mem, i32 %val, i32 %size)
+  ret i8* %ret
+}
+
+define i8* @pr25892_lite(i32 %size) #0 {
+; CHECK-LABEL: @pr25892_lite(
+; CHECK-NEXT:    [[CALLOC:%.*]] = call i8* @calloc(i32 1, i32 [[SIZE:%.*]])
+; CHECK-NEXT:    ret i8* [[CALLOC]]
+;
+  %call1 = call i8* @malloc(i32 %size) #1
+  %call2 = call i8* @memset(i8* %call1, i32 0, i32 %size) #1
+  ret i8* %call2
+}
+
+; FIXME: A memset intrinsic should be handled similarly to a memset() libcall.
+
+define i8* @malloc_and_memset_intrinsic(i32 %n) #0 {
+; CHECK-LABEL: @malloc_and_memset_intrinsic(
+; CHECK-NEXT:    [[CALL:%.*]] = call i8* @malloc(i32 [[N:%.*]])
+; CHECK-NEXT:    call void @llvm.memset.p0i8.i32(i8* align 1 [[CALL]], i8 0, i32 [[N]], i1 false)
+; CHECK-NEXT:    ret i8* [[CALL]]
+;
+  %call = call i8* @malloc(i32 %n)
+  call void @llvm.memset.p0i8.i32(i8* %call, i8 0, i32 %n, i32 1, i1 false)
+  ret i8* %call
+}
+
+; This should not create a calloc and should not crash the compiler.
+
+define i8* @notmalloc_memset(i32 %size, i8*(i32)* %notmalloc) {
+; CHECK-LABEL: @notmalloc_memset(
+; CHECK-NEXT:    [[CALL1:%.*]] = call i8* [[NOTMALLOC:%.*]](i32 [[SIZE:%.*]]) #0
+; CHECK-NEXT:    call void @llvm.memset.p0i8.i32(i8* align 1 [[CALL1]], i8 0, i32 [[SIZE]], i1 false)
+; CHECK-NEXT:    ret i8* [[CALL1]]
+;
+  %call1 = call i8* %notmalloc(i32 %size) #1
+  %call2 = call i8* @memset(i8* %call1, i32 0, i32 %size) #1
+  ret i8* %call2
+}
+
+; FIXME: memset(malloc(x), 0, x) -> calloc(1, x)
+; This doesn't fire currently because the malloc has more than one use.
+
+define float* @pr25892(i32 %size) #0 {
+; CHECK-LABEL: @pr25892(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[CALL:%.*]] = tail call i8* @malloc(i32 [[SIZE:%.*]]) #0
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i8* [[CALL]], null
+; CHECK-NEXT:    br i1 [[CMP]], label [[CLEANUP:%.*]], label [[IF_END:%.*]]
+; CHECK:       if.end:
+; CHECK-NEXT:    [[BC:%.*]] = bitcast i8* [[CALL]] to float*
+; CHECK-NEXT:    call void @llvm.memset.p0i8.i32(i8* nonnull align 1 [[CALL]], i8 0, i32 [[SIZE]], i1 false)
+; CHECK-NEXT:    br label [[CLEANUP]]
+; CHECK:       cleanup:
+; CHECK-NEXT:    [[RETVAL_0:%.*]] = phi float* [ [[BC]], [[IF_END]] ], [ null, [[ENTRY:%.*]] ]
+; CHECK-NEXT:    ret float* [[RETVAL_0]]
+;
+entry:
+  %call = tail call i8* @malloc(i32 %size) #1
+  %cmp = icmp eq i8* %call, null
+  br i1 %cmp, label %cleanup, label %if.end
+if.end:
+  %bc = bitcast i8* %call to float*
+  %call2 = tail call i8* @memset(i8* nonnull %call, i32 0, i32 %size) #1
+  br label %cleanup
+cleanup:
+  %retval.0 = phi float* [ %bc, %if.end ], [ null, %entry ]
+  ret float* %retval.0
+}
+
+; If there's a calloc transform, the store must also be eliminated.
+
+define i8* @buffer_is_modified_then_memset(i32 %size) {
+; CHECK-LABEL: @buffer_is_modified_then_memset(
+; CHECK-NEXT:    [[PTR:%.*]] = tail call i8* @malloc(i32 [[SIZE:%.*]]) #0
+; CHECK-NEXT:    store i8 1, i8* [[PTR]], align 1
+; CHECK-NEXT:    call void @llvm.memset.p0i8.i32(i8* align 1 [[PTR]], i8 0, i32 [[SIZE]], i1 false)
+; CHECK-NEXT:    ret i8* [[PTR]]
+;
+  %ptr = tail call i8* @malloc(i32 %size) #1
+  store i8 1, i8* %ptr           ;; fdata[0] = 1;
+  %memset = tail call i8* @memset(i8* nonnull %ptr, i32 0, i32 %size) #1
+  ret i8* %memset
+}
+
+attributes #0 = { nounwind ssp uwtable }
+attributes #1 = { nounwind }
+attributes #2 = { nounwind readnone }
+

Added: llvm/trunk/test/Transforms/InstCombine/memset-2.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/memset-2.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/memset-2.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/memset-2.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,17 @@
+; Test that the memset library call simplifier works correctly.
+;
+; RUN: opt < %s -instcombine -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:128:128"
+
+declare i8 @memset(i8*, i32, i32)
+
+; Check that memset functions with the wrong prototype aren't simplified.
+
+define i8 @test_no_simplify1(i8* %mem, i32 %val, i32 %size) {
+; CHECK-LABEL: @test_no_simplify1(
+  %ret = call i8 @memset(i8* %mem, i32 %val, i32 %size)
+; CHECK: call i8 @memset
+  ret i8 %ret
+; CHECK: ret i8 %ret
+}

Added: llvm/trunk/test/Transforms/InstCombine/memset.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/memset.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/memset.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/memset.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,37 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt < %s -instcombine -S | FileCheck %s
+
+define i32 @test([1024 x i8]* %target) {
+; CHECK-LABEL: @test(
+; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds [1024 x i8], [1024 x i8]* [[TARGET:%.*]], i64 0, i64 0
+; CHECK-NEXT:    store i8 1, i8* [[TMP1]], align 1
+; CHECK-NEXT:    [[TMP2:%.*]] = bitcast [1024 x i8]* [[TARGET]] to i16*
+; CHECK-NEXT:    store i16 257, i16* [[TMP2]], align 2
+; CHECK-NEXT:    [[TMP3:%.*]] = bitcast [1024 x i8]* [[TARGET]] to i32*
+; CHECK-NEXT:    store i32 16843009, i32* [[TMP3]], align 4
+; CHECK-NEXT:    [[TMP4:%.*]] = bitcast [1024 x i8]* [[TARGET]] to i64*
+; CHECK-NEXT:    store i64 72340172838076673, i64* [[TMP4]], align 8
+; CHECK-NEXT:    ret i32 0
+;
+  %target_p = getelementptr [1024 x i8], [1024 x i8]* %target, i32 0, i32 0
+  call void @llvm.memset.p0i8.i32(i8* %target_p, i8 1, i32 0, i1 false)
+  call void @llvm.memset.p0i8.i32(i8* %target_p, i8 1, i32 1, i1 false)
+  call void @llvm.memset.p0i8.i32(i8* align 2 %target_p, i8 1, i32 2, i1 false)
+  call void @llvm.memset.p0i8.i32(i8* align 4 %target_p, i8 1, i32 4, i1 false)
+  call void @llvm.memset.p0i8.i32(i8* align 8 %target_p, i8 1, i32 8, i1 false)
+  ret i32 0
+}
+
+ at Unknown = external constant i128
+
+define void @memset_to_constant() {
+; CHECK-LABEL: @memset_to_constant(
+; CHECK-NEXT:    call void @llvm.memset.p0i8.i32(i8* align 4 bitcast (i128* @Unknown to i8*), i8 0, i32 16, i1 false)
+; CHECK-NEXT:    ret void
+;
+  %p = bitcast i128* @Unknown to i8*
+  call void @llvm.memset.p0i8.i32(i8* %p, i8 0, i32 16, i1 false)
+  ret void
+}
+
+declare void @llvm.memset.p0i8.i32(i8* nocapture writeonly, i8, i32, i1) argmemonly nounwind

Added: llvm/trunk/test/Transforms/InstCombine/memset2.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/memset2.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/memset2.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/memset2.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,15 @@
+; RUN: opt < %s -instcombine -S | FileCheck %s
+
+; Test to check that instcombine doesn't drop the address space when optimizing
+; memset.
+%struct.Moves = type { [9 x i8], i8, i8, i8, [5 x i8] }
+
+define i32 @test(%struct.Moves addrspace(1)* nocapture %moves) {
+entry:
+; CHECK: bitcast i8 addrspace(1)* %gep to i64 addrspace(1)*
+	%gep = getelementptr inbounds %struct.Moves, %struct.Moves addrspace(1)* %moves, i32 1, i32 0, i32 9
+	call void @llvm.memset.p1i8.i64(i8 addrspace(1)* %gep, i8 0, i64 8, i1 false)
+	ret i32 0
+}
+
+declare void @llvm.memset.p1i8.i64(i8addrspace(1)* nocapture, i8, i64, i1) nounwind

Added: llvm/trunk/test/Transforms/InstCombine/memset_chk-1.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/memset_chk-1.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/memset_chk-1.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/memset_chk-1.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,130 @@
+; Test lib call simplification of __memset_chk calls with various values
+; for dstlen and len.
+;
+; RUN: opt < %s -instcombine -S | FileCheck %s
+; rdar://7719085
+
+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"
+
+%struct.T = type { [100 x i32], [100 x i32], [1024 x i8] }
+ at t = common global %struct.T zeroinitializer
+
+; Check cases where dstlen >= len.
+
+define i8* @test_simplify1() {
+; CHECK-LABEL: @test_simplify1(
+  %dst = bitcast %struct.T* @t to i8*
+
+; CHECK-NEXT: call void @llvm.memset.p0i8.i64(i8* align 4 bitcast (%struct.T* @t to i8*), i8 0, i64 1824, i1 false)
+; CHECK-NEXT: ret i8* bitcast (%struct.T* @t to i8*)
+  %ret = call i8* @__memset_chk(i8* %dst, i32 0, i64 1824, i64 1824)
+  ret i8* %ret
+}
+
+define i8* @test_simplify2() {
+; CHECK-LABEL: @test_simplify2(
+  %dst = bitcast %struct.T* @t to i8*
+
+; CHECK-NEXT: call void @llvm.memset.p0i8.i64(i8* align 4 bitcast (%struct.T* @t to i8*), i8 0, i64 1824, i1 false)
+; CHECK-NEXT: ret i8* bitcast (%struct.T* @t to i8*)
+  %ret = call i8* @__memset_chk(i8* %dst, i32 0, i64 1824, i64 3648)
+  ret i8* %ret
+}
+
+define i8* @test_simplify3() {
+; CHECK-LABEL: @test_simplify3(
+  %dst = bitcast %struct.T* @t to i8*
+
+; CHECK-NEXT: call void @llvm.memset.p0i8.i64(i8* align 4 bitcast (%struct.T* @t to i8*), i8 0, i64 1824, i1 false)
+; CHECK-NEXT: ret i8* bitcast (%struct.T* @t to i8*)
+  %ret = call i8* @__memset_chk(i8* %dst, i32 0, i64 1824, i64 -1)
+  ret i8* %ret
+}
+
+; Check cases where dstlen < len.
+
+define i8* @test_no_simplify1() {
+; CHECK-LABEL: @test_no_simplify1(
+  %dst = bitcast %struct.T* @t to i8*
+
+; CHECK-NEXT: %ret = call i8* @__memset_chk(i8* bitcast (%struct.T* @t to i8*), i32 0, i64 1824, i64 400)
+; CHECK-NEXT: ret i8* %ret
+  %ret = call i8* @__memset_chk(i8* %dst, i32 0, i64 1824, i64 400)
+  ret i8* %ret
+}
+
+define i8* @test_no_simplify2() {
+; CHECK-LABEL: @test_no_simplify2(
+  %dst = bitcast %struct.T* @t to i8*
+
+; CHECK-NEXT: %ret = call i8* @__memset_chk(i8* bitcast (%struct.T* @t to i8*), i32 0, i64 1824, i64 0)
+; CHECK-NEXT: ret i8* %ret
+  %ret = call i8* @__memset_chk(i8* %dst, i32 0, i64 1824, i64 0)
+  ret i8* %ret
+}
+
+; Test that RAUW in SimplifyLibCalls for __memset_chk generates valid IR
+define i32 @test_rauw(i8* %a, i8* %b, i8** %c) {
+; CHECK-LABEL: test_rauw
+entry:
+  %call49 = call i64 @strlen(i8* %a)
+  %add180 = add i64 %call49, 1
+  %yo107 = call i64 @llvm.objectsize.i64.p0i8(i8* %b, i1 false, i1 false, i1 false)
+  %call50 = call i8* @__memmove_chk(i8* %b, i8* %a, i64 %add180, i64 %yo107)
+; CHECK: %strlen = call i64 @strlen(i8* %b)
+; CHECK-NEXT: %strchr2 = getelementptr i8, i8* %b, i64 %strlen
+  %call51i = call i8* @strrchr(i8* %b, i32 0)
+  %d = load i8*, i8** %c, align 8
+  %sub182 = ptrtoint i8* %d to i64
+  %sub183 = ptrtoint i8* %b to i64
+  %sub184 = sub i64 %sub182, %sub183
+  %add52.i.i = add nsw i64 %sub184, 1
+; CHECK: call void @llvm.memset.p0i8.i64(i8* align 1 %strchr2
+  %call185 = call i8* @__memset_chk(i8* %call51i, i32 0, i64 %add52.i.i, i64 -1)
+  ret i32 4
+}
+
+declare i8* @__memmove_chk(i8*, i8*, i64, i64)
+declare i8* @strrchr(i8*, i32)
+declare i64 @strlen(i8* nocapture)
+declare i64 @llvm.objectsize.i64.p0i8(i8*, i1, i1, i1)
+
+declare i8* @__memset_chk(i8*, i32, i64, i64)
+
+; FIXME: memset(malloc(x), 0, x) -> calloc(1, x)
+
+define float* @pr25892(i64 %size) #0 {
+entry:
+  %call = tail call i8* @malloc(i64 %size) #1
+  %cmp = icmp eq i8* %call, null
+  br i1 %cmp, label %cleanup, label %if.end
+if.end:
+  %bc = bitcast i8* %call to float*
+  %call2 = tail call i64 @llvm.objectsize.i64.p0i8(i8* nonnull %call, i1 false, i1 false, i1 false)
+  %call3 = tail call i8* @__memset_chk(i8* nonnull %call, i32 0, i64 %size, i64 %call2) #1
+  br label %cleanup
+cleanup:
+  %retval.0 = phi float* [ %bc, %if.end ], [ null, %entry ]
+  ret float* %retval.0
+
+; CHECK-LABEL: @pr25892(
+; CHECK:       entry:
+; CHECK-NEXT:    %call = tail call i8* @malloc(i64 %size)
+; CHECK-NEXT:    %cmp = icmp eq i8* %call, null
+; CHECK-NEXT:    br i1 %cmp, label %cleanup, label %if.end
+; CHECK:       if.end:
+; CHECK-NEXT:    %bc = bitcast i8* %call to float*
+; CHECK-NEXT:    %call2 = tail call i64 @llvm.objectsize.i64.p0i8(i8* nonnull %call, i1 false, i1 false, i1 false)
+; CHECK-NEXT:    %call3 = tail call i8* @__memset_chk(i8* nonnull %call, i32 0, i64 %size, i64 %call2)
+; CHECK-NEXT:    br label %cleanup
+; CHECK:       cleanup:
+; CHECK-NEXT:    %retval.0 = phi float* [ %bc, %if.end ], [ null, %entry ]
+; CHECK-NEXT:    ret float* %retval.0
+}
+
+declare noalias i8* @malloc(i64) #1
+
+attributes #0 = { nounwind ssp uwtable }
+attributes #1 = { nounwind }
+attributes #2 = { nounwind readnone }
+

Added: llvm/trunk/test/Transforms/InstCombine/memset_chk-2.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/memset_chk-2.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/memset_chk-2.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/memset_chk-2.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,20 @@
+; Test that lib call simplification doesn't simplify __memset_chk calls
+; with the wrong prototype.
+;
+; RUN: opt < %s -instcombine -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"
+
+%struct.T = type { [100 x i32], [100 x i32], [1024 x i8] }
+ at t = common global %struct.T zeroinitializer
+
+define void @test_no_simplify() {
+; CHECK-LABEL: @test_no_simplify(
+  %dst = bitcast %struct.T* @t to i8*
+
+; CHECK-NEXT: call i8* @__memset_chk
+  call i8* @__memset_chk(i8* %dst, i32 0, i64 1824)
+  ret void
+}
+
+declare i8* @__memset_chk(i8*, i32, i64)

Added: llvm/trunk/test/Transforms/InstCombine/merge-icmp.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/merge-icmp.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/merge-icmp.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/merge-icmp.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,29 @@
+; RUN: opt -S -instcombine < %s | FileCheck %s
+
+define i1 @test1(i16* %x) {
+  %load = load i16, i16* %x, align 4
+  %trunc = trunc i16 %load to i8
+  %cmp1 = icmp eq i8 %trunc, 127
+  %and = and i16 %load, -256
+  %cmp2 = icmp eq i16 %and, 17664
+  %or = and i1 %cmp1, %cmp2
+  ret i1 %or
+; CHECK-LABEL: @test1(
+; CHECK-NEXT: load i16
+; CHECK-NEXT: icmp eq i16 %load, 17791
+; CHECK-NEXT: ret i1
+}
+
+define i1 @test2(i16* %x) {
+  %load = load i16, i16* %x, align 4
+  %and = and i16 %load, -256
+  %cmp1 = icmp eq i16 %and, 32512
+  %trunc = trunc i16 %load to i8
+  %cmp2 = icmp eq i8 %trunc, 69
+  %or = and i1 %cmp1, %cmp2
+  ret i1 %or
+; CHECK-LABEL: @test2(
+; CHECK-NEXT: load i16
+; CHECK-NEXT: icmp eq i16 %load, 32581
+; CHECK-NEXT: ret i1
+}

Added: llvm/trunk/test/Transforms/InstCombine/min-positive.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/min-positive.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/min-positive.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/min-positive.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,101 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt -S -instcombine < %s | FileCheck %s
+
+ at g = external global i32
+
+define i1 @smin(i32 %other) {
+; CHECK-LABEL: @smin(
+; CHECK-NEXT:    [[TEST:%.*]] = icmp sgt i32 [[OTHER:%.*]], 0
+; CHECK-NEXT:    ret i1 [[TEST]]
+;
+  %positive = load i32, i32* @g, !range !{i32 1, i32 2048}
+  %cmp = icmp slt i32 %positive, %other
+  %sel = select i1 %cmp, i32 %positive, i32 %other
+  %test = icmp sgt i32 %sel, 0
+  ret i1 %test
+}
+
+; Range metadata doesn't work for vectors, so find another way to trigger isKnownPositive().
+
+define <2 x i1> @smin_vec(<2 x i32> %x, <2 x i32> %other) {
+; CHECK-LABEL: @smin_vec(
+; CHECK-NEXT:    [[TEST:%.*]] = icmp sgt <2 x i32> [[OTHER:%.*]], zeroinitializer
+; CHECK-NEXT:    ret <2 x i1> [[TEST]]
+;
+  %notneg = and <2 x i32> %x, <i32 7, i32 7>
+  %positive = or <2 x i32> %notneg, <i32 1, i32 1>
+  %cmp = icmp slt <2 x i32> %positive, %other
+  %sel = select <2 x i1> %cmp, <2 x i32> %positive, <2 x i32> %other
+  %test = icmp sgt <2 x i32> %sel, zeroinitializer
+  ret <2 x i1> %test
+}
+
+define i1 @smin_commute(i32 %other) {
+; CHECK-LABEL: @smin_commute(
+; CHECK-NEXT:    [[TEST:%.*]] = icmp sgt i32 [[OTHER:%.*]], 0
+; CHECK-NEXT:    ret i1 [[TEST]]
+;
+  %positive = load i32, i32* @g, !range !{i32 1, i32 2048}
+  %cmp = icmp slt i32 %other, %positive
+  %sel = select i1 %cmp, i32 %other, i32 %positive
+  %test = icmp sgt i32 %sel, 0
+  ret i1 %test
+}
+
+define <2 x i1> @smin_commute_vec(<2 x i32> %x, <2 x i32> %other) {
+; CHECK-LABEL: @smin_commute_vec(
+; CHECK-NEXT:    [[TEST:%.*]] = icmp sgt <2 x i32> [[OTHER:%.*]], zeroinitializer
+; CHECK-NEXT:    ret <2 x i1> [[TEST]]
+;
+  %notneg = and <2 x i32> %x, <i32 7, i32 7>
+  %positive = or <2 x i32> %notneg, <i32 1, i32 1>
+  %cmp = icmp slt <2 x i32> %other, %positive
+  %sel = select <2 x i1> %cmp, <2 x i32> %other, <2 x i32> %positive
+  %test = icmp sgt <2 x i32> %sel, zeroinitializer
+  ret <2 x i1> %test
+}
+
+define <2 x i1> @smin_commute_vec_undef_elts(<2 x i32> %x, <2 x i32> %other) {
+; CHECK-LABEL: @smin_commute_vec_undef_elts(
+; CHECK-NEXT:    [[TEST:%.*]] = icmp sgt <2 x i32> [[OTHER:%.*]], <i32 0, i32 undef>
+; CHECK-NEXT:    ret <2 x i1> [[TEST]]
+;
+  %notneg = and <2 x i32> %x, <i32 7, i32 7>
+  %positive = or <2 x i32> %notneg, <i32 1, i32 1>
+  %cmp = icmp slt <2 x i32> %other, %positive
+  %sel = select <2 x i1> %cmp, <2 x i32> %other, <2 x i32> %positive
+  %test = icmp sgt <2 x i32> %sel, <i32 0, i32 undef>
+  ret <2 x i1> %test
+}
+; %positive might be zero
+
+define i1 @maybe_not_positive(i32 %other) {
+; CHECK-LABEL: @maybe_not_positive(
+; CHECK-NEXT:    [[POSITIVE:%.*]] = load i32, i32* @g, align 4, !range !0
+; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i32 [[POSITIVE]], [[OTHER:%.*]]
+; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[CMP]], i32 [[POSITIVE]], i32 [[OTHER]]
+; CHECK-NEXT:    [[TEST:%.*]] = icmp sgt i32 [[SEL]], 0
+; CHECK-NEXT:    ret i1 [[TEST]]
+;
+  %positive = load i32, i32* @g, !range !{i32 0, i32 2048}
+  %cmp = icmp slt i32 %positive, %other
+  %sel = select i1 %cmp, i32 %positive, i32 %other
+  %test = icmp sgt i32 %sel, 0
+  ret i1 %test
+}
+
+define <2 x i1> @maybe_not_positive_vec(<2 x i32> %x, <2 x i32> %other) {
+; CHECK-LABEL: @maybe_not_positive_vec(
+; CHECK-NEXT:    [[NOTNEG:%.*]] = and <2 x i32> [[X:%.*]], <i32 7, i32 7>
+; CHECK-NEXT:    [[CMP:%.*]] = icmp slt <2 x i32> [[NOTNEG]], [[OTHER:%.*]]
+; CHECK-NEXT:    [[SEL:%.*]] = select <2 x i1> [[CMP]], <2 x i32> [[NOTNEG]], <2 x i32> [[OTHER]]
+; CHECK-NEXT:    [[TEST:%.*]] = icmp sgt <2 x i32> [[SEL]], zeroinitializer
+; CHECK-NEXT:    ret <2 x i1> [[TEST]]
+;
+  %notneg = and <2 x i32> %x, <i32 7, i32 7>
+  %cmp = icmp slt <2 x i32> %notneg, %other
+  %sel = select <2 x i1> %cmp, <2 x i32> %notneg, <2 x i32> %other
+  %test = icmp sgt <2 x i32> %sel, zeroinitializer
+  ret <2 x i1> %test
+}
+

Added: llvm/trunk/test/Transforms/InstCombine/minimum.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/minimum.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/minimum.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/minimum.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,317 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt -S -instcombine < %s | FileCheck %s
+
+declare float @llvm.minimum.f32(float, float)
+declare <2 x float> @llvm.minimum.v2f32(<2 x float>, <2 x float>)
+declare <4 x float> @llvm.minimum.v4f32(<4 x float>, <4 x float>)
+
+declare double @llvm.minimum.f64(double, double)
+declare <2 x double> @llvm.minimum.v2f64(<2 x double>, <2 x double>)
+
+declare float @llvm.maximum.f32(float, float)
+
+define float @constant_fold_minimum_f32() {
+; CHECK-LABEL: @constant_fold_minimum_f32(
+; CHECK-NEXT:    ret float 1.000000e+00
+;
+  %x = call float @llvm.minimum.f32(float 1.0, float 2.0)
+  ret float %x
+}
+
+define float @constant_fold_minimum_f32_inv() {
+; CHECK-LABEL: @constant_fold_minimum_f32_inv(
+; CHECK-NEXT:    ret float 1.000000e+00
+;
+  %x = call float @llvm.minimum.f32(float 2.0, float 1.0)
+  ret float %x
+}
+
+define float @constant_fold_minimum_f32_nan0() {
+; CHECK-LABEL: @constant_fold_minimum_f32_nan0(
+; CHECK-NEXT:    ret float 0x7FF8000000000000
+;
+  %x = call float @llvm.minimum.f32(float 0x7FF8000000000000, float 2.0)
+  ret float %x
+}
+
+define float @constant_fold_minimum_f32_nan1() {
+; CHECK-LABEL: @constant_fold_minimum_f32_nan1(
+; CHECK-NEXT:    ret float 0x7FF8000000000000
+;
+  %x = call float @llvm.minimum.f32(float 2.0, float 0x7FF8000000000000)
+  ret float %x
+}
+
+define float @constant_fold_minimum_f32_nan_nan() {
+; CHECK-LABEL: @constant_fold_minimum_f32_nan_nan(
+; CHECK-NEXT:    ret float 0x7FF8000000000000
+;
+  %x = call float @llvm.minimum.f32(float 0x7FF8000000000000, float 0x7FF8000000000000)
+  ret float %x
+}
+
+define float @constant_fold_minimum_f32_p0_p0() {
+; CHECK-LABEL: @constant_fold_minimum_f32_p0_p0(
+; CHECK-NEXT:    ret float 0.000000e+00
+;
+  %x = call float @llvm.minimum.f32(float 0.0, float 0.0)
+  ret float %x
+}
+
+define float @constant_fold_minimum_f32_p0_n0() {
+; CHECK-LABEL: @constant_fold_minimum_f32_p0_n0(
+; CHECK-NEXT:    ret float -0.000000e+00
+;
+  %x = call float @llvm.minimum.f32(float 0.0, float -0.0)
+  ret float %x
+}
+
+define float @constant_fold_minimum_f32_n0_p0() {
+; CHECK-LABEL: @constant_fold_minimum_f32_n0_p0(
+; CHECK-NEXT:    ret float -0.000000e+00
+;
+  %x = call float @llvm.minimum.f32(float -0.0, float 0.0)
+  ret float %x
+}
+
+define float @constant_fold_minimum_f32_n0_n0() {
+; CHECK-LABEL: @constant_fold_minimum_f32_n0_n0(
+; CHECK-NEXT:    ret float -0.000000e+00
+;
+  %x = call float @llvm.minimum.f32(float -0.0, float -0.0)
+  ret float %x
+}
+
+define <4 x float> @constant_fold_minimum_v4f32() {
+; CHECK-LABEL: @constant_fold_minimum_v4f32(
+; CHECK-NEXT:    ret <4 x float> <float 1.000000e+00, float 2.000000e+00, float 3.000000e+00, float 5.000000e+00>
+;
+  %x = call <4 x float> @llvm.minimum.v4f32(<4 x float> <float 1.0, float 8.0, float 3.0, float 9.0>, <4 x float> <float 2.0, float 2.0, float 10.0, float 5.0>)
+  ret <4 x float> %x
+}
+
+define double @constant_fold_minimum_f64() {
+; CHECK-LABEL: @constant_fold_minimum_f64(
+; CHECK-NEXT:    ret double 1.000000e+00
+;
+  %x = call double @llvm.minimum.f64(double 1.0, double 2.0)
+  ret double %x
+}
+
+define double @constant_fold_minimum_f64_nan0() {
+; CHECK-LABEL: @constant_fold_minimum_f64_nan0(
+; CHECK-NEXT:    ret double 0x7FF8000000000000
+;
+  %x = call double @llvm.minimum.f64(double 0x7FF8000000000000, double 2.0)
+  ret double %x
+}
+
+define double @constant_fold_minimum_f64_nan1() {
+; CHECK-LABEL: @constant_fold_minimum_f64_nan1(
+; CHECK-NEXT:    ret double 0x7FF8000000000000
+;
+  %x = call double @llvm.minimum.f64(double 2.0, double 0x7FF8000000000000)
+  ret double %x
+}
+
+define double @constant_fold_minimum_f64_nan_nan() {
+; CHECK-LABEL: @constant_fold_minimum_f64_nan_nan(
+; CHECK-NEXT:    ret double 0x7FF8000000000000
+;
+  %x = call double @llvm.minimum.f64(double 0x7FF8000000000000, double 0x7FF8000000000000)
+  ret double %x
+}
+
+define float @canonicalize_constant_minimum_f32(float %x) {
+; CHECK-LABEL: @canonicalize_constant_minimum_f32(
+; CHECK-NEXT:    [[Y:%.*]] = call float @llvm.minimum.f32(float [[X:%.*]], float 1.000000e+00)
+; CHECK-NEXT:    ret float [[Y]]
+;
+  %y = call float @llvm.minimum.f32(float 1.0, float %x)
+  ret float %y
+}
+
+define float @minimum_f32_nan_val(float %x) {
+; CHECK-LABEL: @minimum_f32_nan_val(
+; CHECK-NEXT:    ret float 0x7FF8000000000000
+;
+  %y = call float @llvm.minimum.f32(float 0x7FF8000000000000, float %x)
+  ret float %y
+}
+
+define float @minimum_f32_val_nan(float %x) {
+; CHECK-LABEL: @minimum_f32_val_nan(
+; CHECK-NEXT:    ret float 0x7FF8000000000000
+;
+  %y = call float @llvm.minimum.f32(float %x, float 0x7FF8000000000000)
+  ret float %y
+}
+
+define float @minimum_f32_1_minimum_val_p0(float %x) {
+; CHECK-LABEL: @minimum_f32_1_minimum_val_p0(
+; CHECK-NEXT: [[RES:%.*]] = call float @llvm.minimum.f32(float %x, float 0.000000e+00)
+; CHECK-NEXT: ret float [[RES]]
+  %y = call float @llvm.minimum.f32(float %x, float 0.0)
+  %z = call float @llvm.minimum.f32(float %y, float 1.0)
+  ret float %z
+}
+
+define float @minimum_f32_1_minimum_p0_val_fast(float %x) {
+; CHECK-LABEL: @minimum_f32_1_minimum_p0_val_fast(
+; CHECK-NEXT: [[RES:%.*]] = call fast float @llvm.minimum.f32(float %x, float 0.000000e+00)
+; CHECK-NEXT: ret float [[RES]]
+  %y = call float @llvm.minimum.f32(float 0.0, float %x)
+  %z = call fast float @llvm.minimum.f32(float %y, float 1.0)
+  ret float %z
+}
+
+define float @minimum_f32_1_minimum_p0_val_nnan_ninf(float %x) {
+; CHECK-LABEL: @minimum_f32_1_minimum_p0_val_nnan_ninf(
+; CHECK-NEXT: [[RES:%.*]] = call nnan ninf float @llvm.minimum.f32(float %x, float 0.000000e+00)
+; CHECK-NEXT: ret float [[RES]]
+  %y = call float @llvm.minimum.f32(float 0.0, float %x)
+  %z = call nnan ninf float @llvm.minimum.f32(float %y, float 1.0)
+  ret float %z
+}
+
+define float @minimum_f32_p0_minimum_val_n0(float %x) {
+; CHECK-LABEL: @minimum_f32_p0_minimum_val_n0(
+; CHECK-NEXT: [[RES:%.*]] = call float @llvm.minimum.f32(float %x, float -0.000000e+00)
+; CHECK-NEXT: ret float [[RES]]
+  %y = call float @llvm.minimum.f32(float %x, float -0.0)
+  %z = call float @llvm.minimum.f32(float %y, float 0.0)
+  ret float %z
+}
+
+define float @minimum_f32_1_minimum_p0_val(float %x) {
+; CHECK-LABEL: @minimum_f32_1_minimum_p0_val(
+; CHECK-NEXT: [[RES:%.*]] = call float @llvm.minimum.f32(float %x, float 0.000000e+00)
+; CHECK-NEXT: ret float [[RES]]
+  %y = call float @llvm.minimum.f32(float 0.0, float %x)
+  %z = call float @llvm.minimum.f32(float %y, float 1.0)
+  ret float %z
+}
+
+define <2 x float> @minimum_f32_1_minimum_val_p0_val_v2f32(<2 x float> %x) {
+; CHECK-LABEL: @minimum_f32_1_minimum_val_p0_val_v2f32(
+; CHECK-NEXT: [[RES:%.*]] = call <2 x float> @llvm.minimum.v2f32(<2 x float> %x, <2 x float> zeroinitializer)
+; CHECK-NEXT: ret <2 x float> [[RES]]
+  %y = call <2 x float> @llvm.minimum.v2f32(<2 x float> %x, <2 x float> zeroinitializer)
+  %z = call <2 x float> @llvm.minimum.v2f32(<2 x float> %y, <2 x float><float 1.0, float 1.0>)
+  ret <2 x float> %z
+}
+
+define float @minimum4(float %x, float %y, float %z, float %w) {
+; CHECK-LABEL: @minimum4(
+; CHECK-NEXT:    [[A:%.*]] = call float @llvm.minimum.f32(float [[X:%.*]], float [[Y:%.*]])
+; CHECK-NEXT:    [[B:%.*]] = call float @llvm.minimum.f32(float [[Z:%.*]], float [[W:%.*]])
+; CHECK-NEXT:    [[C:%.*]] = call float @llvm.minimum.f32(float [[A]], float [[B]])
+; CHECK-NEXT:    ret float [[C]]
+;
+  %a = call float @llvm.minimum.f32(float %x, float %y)
+  %b = call float @llvm.minimum.f32(float %z, float %w)
+  %c = call float @llvm.minimum.f32(float %a, float %b)
+  ret float %c
+}
+
+define float @minimum_x_maximum_x_y(float %x, float %y) {
+; CHECK-LABEL: @minimum_x_maximum_x_y(
+; CHECK-NEXT:    [[A:%.*]] = call float @llvm.maximum.f32(float [[X:%.*]], float [[Y:%.*]])
+; CHECK-NEXT:    [[B:%.*]] = call float @llvm.minimum.f32(float [[X]], float [[A]])
+; CHECK-NEXT:    ret float [[B]]
+;
+  %a = call float @llvm.maximum.f32(float %x, float %y)
+  %b = call float @llvm.minimum.f32(float %x, float %a)
+  ret float %b
+}
+
+define float @maximum_x_minimum_x_y(float %x, float %y) {
+; CHECK-LABEL: @maximum_x_minimum_x_y(
+; CHECK-NEXT:    [[A:%.*]] = call float @llvm.minimum.f32(float [[X:%.*]], float [[Y:%.*]])
+; CHECK-NEXT:    [[B:%.*]] = call float @llvm.maximum.f32(float [[X]], float [[A]])
+; CHECK-NEXT:    ret float [[B]]
+;
+  %a = call float @llvm.minimum.f32(float %x, float %y)
+  %b = call float @llvm.maximum.f32(float %x, float %a)
+  ret float %b
+}
+
+; PR37405 - https://bugs.llvm.org/show_bug.cgi?id=37405
+
+define double @neg_neg(double %x, double %y) {
+; CHECK-LABEL: @neg_neg(
+; CHECK-NEXT:    [[TMP1:%.*]] = call double @llvm.maximum.f64(double [[X:%.*]], double [[Y:%.*]])
+; CHECK-NEXT:    [[R:%.*]] = fsub double -0.000000e+00, [[TMP1]]
+; CHECK-NEXT:    ret double [[R]]
+;
+  %negx = fsub double -0.0, %x
+  %negy = fsub double -0.0, %y
+  %r = call double @llvm.minimum.f64(double %negx, double %negy)
+  ret double %r
+}
+
+; FMF is not required, but it should be propagated from the intrinsic (not the fnegs).
+; Also, make sure this works with vectors.
+
+define <2 x double> @neg_neg_vec_fmf(<2 x double> %x, <2 x double> %y) {
+; CHECK-LABEL: @neg_neg_vec_fmf(
+; CHECK-NEXT:    [[TMP1:%.*]] = call nnan ninf <2 x double> @llvm.maximum.v2f64(<2 x double> [[X:%.*]], <2 x double> [[Y:%.*]])
+; CHECK-NEXT:    [[R:%.*]] = fsub nnan ninf <2 x double> <double -0.000000e+00, double -0.000000e+00>, [[TMP1]]
+; CHECK-NEXT:    ret <2 x double> [[R]]
+;
+  %negx = fsub reassoc <2 x double> <double -0.0, double -0.0>, %x
+  %negy = fsub fast <2 x double> <double -0.0, double -0.0>, %y
+  %r = call nnan ninf <2 x double> @llvm.minimum.v2f64(<2 x double> %negx, <2 x double> %negy)
+  ret <2 x double> %r
+}
+
+; 1 extra use of an intermediate value should still allow the fold,
+; but 2 would require more instructions than we started with.
+
+declare void @use(double)
+define double @neg_neg_extra_use_x(double %x, double %y) {
+; CHECK-LABEL: @neg_neg_extra_use_x(
+; CHECK-NEXT:    [[NEGX:%.*]] = fsub double -0.000000e+00, [[X:%.*]]
+; CHECK-NEXT:    [[TMP1:%.*]] = call double @llvm.maximum.f64(double [[X]], double [[Y:%.*]])
+; CHECK-NEXT:    [[R:%.*]] = fsub double -0.000000e+00, [[TMP1]]
+; CHECK-NEXT:    call void @use(double [[NEGX]])
+; CHECK-NEXT:    ret double [[R]]
+;
+  %negx = fsub double -0.0, %x
+  %negy = fsub double -0.0, %y
+  %r = call double @llvm.minimum.f64(double %negx, double %negy)
+  call void @use(double %negx)
+  ret double %r
+}
+
+define double @neg_neg_extra_use_y(double %x, double %y) {
+; CHECK-LABEL: @neg_neg_extra_use_y(
+; CHECK-NEXT:    [[NEGY:%.*]] = fsub double -0.000000e+00, [[Y:%.*]]
+; CHECK-NEXT:    [[TMP1:%.*]] = call double @llvm.maximum.f64(double [[X:%.*]], double [[Y]])
+; CHECK-NEXT:    [[R:%.*]] = fsub double -0.000000e+00, [[TMP1]]
+; CHECK-NEXT:    call void @use(double [[NEGY]])
+; CHECK-NEXT:    ret double [[R]]
+;
+  %negx = fsub double -0.0, %x
+  %negy = fsub double -0.0, %y
+  %r = call double @llvm.minimum.f64(double %negx, double %negy)
+  call void @use(double %negy)
+  ret double %r
+}
+
+define double @neg_neg_extra_use_x_and_y(double %x, double %y) {
+; CHECK-LABEL: @neg_neg_extra_use_x_and_y(
+; CHECK-NEXT:    [[NEGX:%.*]] = fsub double -0.000000e+00, [[X:%.*]]
+; CHECK-NEXT:    [[NEGY:%.*]] = fsub double -0.000000e+00, [[Y:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = call double @llvm.minimum.f64(double [[NEGX]], double [[NEGY]])
+; CHECK-NEXT:    call void @use(double [[NEGX]])
+; CHECK-NEXT:    call void @use(double [[NEGY]])
+; CHECK-NEXT:    ret double [[R]]
+;
+  %negx = fsub double -0.0, %x
+  %negy = fsub double -0.0, %y
+  %r = call double @llvm.minimum.f64(double %negx, double %negy)
+  call void @use(double %negx)
+  call void @use(double %negy)
+  ret double %r
+}

Added: llvm/trunk/test/Transforms/InstCombine/minmax-demandbits.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/minmax-demandbits.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/minmax-demandbits.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/minmax-demandbits.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,236 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt -S -instcombine < %s | FileCheck %s
+
+
+define i32 @and_umax_less(i32 %A) {
+; CHECK-LABEL: @and_umax_less(
+; CHECK-NEXT:    [[X:%.*]] = and i32 [[A:%.*]], -32
+; CHECK-NEXT:    ret i32 [[X]]
+;
+  %l0 = icmp ugt i32 31, %A
+  %l1 = select i1 %l0, i32 31, i32 %A
+  %x = and i32 %l1, -32
+  ret i32 %x
+}
+
+define i32 @and_umax_muchless(i32 %A) {
+; CHECK-LABEL: @and_umax_muchless(
+; CHECK-NEXT:    [[X:%.*]] = and i32 [[A:%.*]], -32
+; CHECK-NEXT:    ret i32 [[X]]
+;
+  %l0 = icmp ugt i32 12, %A
+  %l1 = select i1 %l0, i32 12, i32 %A
+  %x = and i32 %l1, -32
+  ret i32 %x
+}
+
+define i32 @and_umax_more(i32 %A) {
+; CHECK-LABEL: @and_umax_more(
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp ugt i32 [[A:%.*]], 32
+; CHECK-NEXT:    [[L1:%.*]] = select i1 [[TMP1]], i32 [[A]], i32 32
+; CHECK-NEXT:    [[X:%.*]] = and i32 [[L1]], -32
+; CHECK-NEXT:    ret i32 [[X]]
+;
+  %l0 = icmp ugt i32 32, %A
+  %l1 = select i1 %l0, i32 32, i32 %A
+  %x = and i32 %l1, -32
+  ret i32 %x
+}
+
+define i32 @shr_umax(i32 %A) {
+; CHECK-LABEL: @shr_umax(
+; CHECK-NEXT:    [[X:%.*]] = lshr i32 [[A:%.*]], 4
+; CHECK-NEXT:    ret i32 [[X]]
+;
+  %l0 = icmp ugt i32 15, %A
+  %l1 = select i1 %l0, i32 15, i32 %A
+  %x = lshr i32 %l1, 4
+  ret i32 %x
+}
+
+; Various constants for C2 & umax(A, C1)
+
+define i8 @t_0_1(i8 %A) {
+; CHECK-LABEL: @t_0_1(
+; CHECK-NEXT:    [[X:%.*]] = and i8 [[A:%.*]], 1
+; CHECK-NEXT:    ret i8 [[X]]
+;
+  %l2 = icmp ugt i8 %A, 0
+  %l1 = select i1 %l2, i8 %A, i8 0
+  %x = and i8 %l1, 1
+  ret i8 %x
+}
+
+define i8 @t_0_10(i8 %A) {
+; CHECK-LABEL: @t_0_10(
+; CHECK-NEXT:    [[X:%.*]] = and i8 [[A:%.*]], 10
+; CHECK-NEXT:    ret i8 [[X]]
+;
+  %l2 = icmp ugt i8 %A, 0
+  %l1 = select i1 %l2, i8 %A, i8 0
+  %x = and i8 %l1, 10
+  ret i8 %x
+}
+
+define i8 @t_1_10(i8 %A) {
+; CHECK-LABEL: @t_1_10(
+; CHECK-NEXT:    [[X:%.*]] = and i8 [[A:%.*]], 10
+; CHECK-NEXT:    ret i8 [[X]]
+;
+  %l2 = icmp ugt i8 %A, 1
+  %l1 = select i1 %l2, i8 %A, i8 1
+  %x = and i8 %l1, 10
+  ret i8 %x
+}
+
+define i8 @t_2_4(i8 %A) {
+; CHECK-LABEL: @t_2_4(
+; CHECK-NEXT:    [[X:%.*]] = and i8 [[A:%.*]], 4
+; CHECK-NEXT:    ret i8 [[X]]
+;
+  %l2 = icmp ugt i8 %A, 2
+  %l1 = select i1 %l2, i8 %A, i8 2
+  %x = and i8 %l1, 4
+  ret i8 %x
+}
+
+define i8 @t_2_192(i8 %A) {
+; CHECK-LABEL: @t_2_192(
+; CHECK-NEXT:    [[X:%.*]] = and i8 [[A:%.*]], -64
+; CHECK-NEXT:    ret i8 [[X]]
+;
+  %l2 = icmp ugt i8 %A, 2
+  %l1 = select i1 %l2, i8 %A, i8 2
+  %x = and i8 %l1, -64
+  ret i8 %x
+}
+
+define i8 @t_2_63_or(i8 %A) {
+; CHECK-LABEL: @t_2_63_or(
+; CHECK-NEXT:    [[X:%.*]] = or i8 [[A:%.*]], 63
+; CHECK-NEXT:    ret i8 [[X]]
+;
+  %l2 = icmp ugt i8 %A, 2
+  %l1 = select i1 %l2, i8 %A, i8 2
+  %x = or i8 %l1, 63
+  ret i8 %x
+}
+
+define i8 @f_1_1(i8 %A) {
+; CHECK-LABEL: @f_1_1(
+; CHECK-NEXT:    [[L2:%.*]] = icmp ugt i8 [[A:%.*]], 1
+; CHECK-NEXT:    [[L1:%.*]] = select i1 [[L2]], i8 [[A]], i8 1
+; CHECK-NEXT:    [[X:%.*]] = and i8 [[L1]], 1
+; CHECK-NEXT:    ret i8 [[X]]
+;
+  %l2 = icmp ugt i8 %A, 1
+  %l1 = select i1 %l2, i8 %A, i8 1
+  %x = and i8 %l1, 1
+  ret i8 %x
+}
+
+define i8 @f_32_32(i8 %A) {
+; CHECK-LABEL: @f_32_32(
+; CHECK-NEXT:    [[L2:%.*]] = icmp ugt i8 [[A:%.*]], 32
+; CHECK-NEXT:    [[L1:%.*]] = select i1 [[L2]], i8 [[A]], i8 32
+; CHECK-NEXT:    [[X:%.*]] = and i8 [[L1]], -32
+; CHECK-NEXT:    ret i8 [[X]]
+;
+  %l2 = icmp ugt i8 %A, 32
+  %l1 = select i1 %l2, i8 %A, i8 32
+  %x = and i8 %l1, -32
+  ret i8 %x
+}
+
+define i8 @f_191_192(i8 %A) {
+; CHECK-LABEL: @f_191_192(
+; CHECK-NEXT:    [[L2:%.*]] = icmp ugt i8 [[A:%.*]], -65
+; CHECK-NEXT:    [[L1:%.*]] = select i1 [[L2]], i8 [[A]], i8 -65
+; CHECK-NEXT:    [[X:%.*]] = and i8 [[L1]], -64
+; CHECK-NEXT:    ret i8 [[X]]
+;
+  %l2 = icmp ugt i8 %A, 191
+  %l1 = select i1 %l2, i8 %A, i8 191
+  %x = and i8 %l1, 192
+  ret i8 %x
+}
+
+define i8 @f_10_1(i8 %A) {
+; CHECK-LABEL: @f_10_1(
+; CHECK-NEXT:    [[L2:%.*]] = icmp ugt i8 [[A:%.*]], 10
+; CHECK-NEXT:    [[L1:%.*]] = select i1 [[L2]], i8 [[A]], i8 10
+; CHECK-NEXT:    [[X:%.*]] = and i8 [[L1]], 1
+; CHECK-NEXT:    ret i8 [[X]]
+;
+  %l2 = icmp ugt i8 %A, 10
+  %l1 = select i1 %l2, i8 %A, i8 10
+  %x = and i8 %l1, 1
+  ret i8 %x
+}
+
+define i32 @and_umin(i32 %A) {
+; CHECK-LABEL: @and_umin(
+; CHECK-NEXT:    ret i32 0
+;
+  %l0 = icmp ult i32 15, %A
+  %l1 = select i1 %l0, i32 15, i32 %A
+  %x = and i32 %l1, -32
+  ret i32 %x
+}
+
+define i32 @or_umin(i32 %A) {
+; CHECK-LABEL: @or_umin(
+; CHECK-NEXT:    ret i32 31
+;
+  %l0 = icmp ult i32 15, %A
+  %l1 = select i1 %l0, i32 15, i32 %A
+  %x = or i32 %l1, 31
+  ret i32 %x
+}
+
+define i8 @or_min_31_30(i8 %A) {
+; CHECK-LABEL: @or_min_31_30(
+; CHECK-NEXT:    [[R:%.*]] = or i8 [[A:%.*]], 31
+; CHECK-NEXT:    ret i8 [[R]]
+;
+  %cmp = icmp ult i8 %A, -30
+  %min = select i1 %cmp, i8 %A, i8 -30
+  %r = or i8 %min, 31
+  ret i8 %r
+}
+
+define i8 @and_min_7_7(i8 %A) {
+; CHECK-LABEL: @and_min_7_7(
+; CHECK-NEXT:    [[R:%.*]] = and i8 [[A:%.*]], -8
+; CHECK-NEXT:    ret i8 [[R]]
+;
+  %l2 = icmp ult i8 %A, -7
+  %min = select i1 %l2, i8 %A, i8 -7
+  %r = and i8 %min, -8
+  ret i8 %r
+}
+
+define i8 @and_min_7_8(i8 %A) {
+; CHECK-LABEL: @and_min_7_8(
+; CHECK-NEXT:    [[R:%.*]] = and i8 [[A:%.*]], -8
+; CHECK-NEXT:    ret i8 [[R]]
+;
+  %l2 = icmp ult i8 %A, -8
+  %min = select i1 %l2, i8 %A, i8 -8
+  %r = and i8 %min, -8
+  ret i8 %r
+}
+
+define i8 @and_min_7_9(i8 %A) {
+; CHECK-LABEL: @and_min_7_9(
+; CHECK-NEXT:    [[L2:%.*]] = icmp ult i8 [[A:%.*]], -9
+; CHECK-NEXT:    [[MIN:%.*]] = select i1 [[L2]], i8 [[A]], i8 -9
+; CHECK-NEXT:    [[R:%.*]] = and i8 [[MIN]], -8
+; CHECK-NEXT:    ret i8 [[R]]
+;
+  %l2 = icmp ult i8 %A, -9
+  %min = select i1 %l2, i8 %A, i8 -9
+  %r = and i8 %min, -8
+  ret i8 %r
+}
+

Added: llvm/trunk/test/Transforms/InstCombine/minmax-fold.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/minmax-fold.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/minmax-fold.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/minmax-fold.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,1450 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt -S -instcombine < %s | FileCheck %s
+
+; This is the canonical form for a type-changing min/max.
+define i64 @t1(i32 %a) {
+; CHECK-LABEL: @t1(
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp slt i32 [[A:%.*]], 5
+; CHECK-NEXT:    [[TMP2:%.*]] = select i1 [[TMP1]], i32 [[A]], i32 5
+; CHECK-NEXT:    [[TMP3:%.*]] = sext i32 [[TMP2]] to i64
+; CHECK-NEXT:    ret i64 [[TMP3]]
+;
+  %1 = icmp slt i32 %a, 5
+  %2 = select i1 %1, i32 %a, i32 5
+  %3 = sext i32 %2 to i64
+  ret i64 %3
+}
+
+; Check this is converted into canonical form, as above.
+define i64 @t2(i32 %a) {
+; CHECK-LABEL: @t2(
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp slt i32 [[A:%.*]], 5
+; CHECK-NEXT:    [[NARROW:%.*]] = select i1 [[TMP1]], i32 [[A]], i32 5
+; CHECK-NEXT:    [[TMP2:%.*]] = sext i32 [[NARROW]] to i64
+; CHECK-NEXT:    ret i64 [[TMP2]]
+;
+  %1 = icmp slt i32 %a, 5
+  %2 = sext i32 %a to i64
+  %3 = select i1 %1, i64 %2, i64 5
+  ret i64 %3
+}
+
+; Same as @t2, with flipped operands and zext instead of sext.
+define i64 @t3(i32 %a) {
+; CHECK-LABEL: @t3(
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp ugt i32 [[A:%.*]], 5
+; CHECK-NEXT:    [[NARROW:%.*]] = select i1 [[TMP1]], i32 [[A]], i32 5
+; CHECK-NEXT:    [[TMP2:%.*]] = zext i32 [[NARROW]] to i64
+; CHECK-NEXT:    ret i64 [[TMP2]]
+;
+  %1 = icmp ult i32 %a, 5
+  %2 = zext i32 %a to i64
+  %3 = select i1 %1, i64 5, i64 %2
+  ret i64 %3
+}
+
+; Same again, with trunc.
+define i32 @t4(i64 %a) {
+; CHECK-LABEL: @t4(
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp slt i64 [[A:%.*]], 5
+; CHECK-NEXT:    [[TMP2:%.*]] = select i1 [[TMP1]], i64 [[A]], i64 5
+; CHECK-NEXT:    [[TMP3:%.*]] = trunc i64 [[TMP2]] to i32
+; CHECK-NEXT:    ret i32 [[TMP3]]
+;
+  %1 = icmp slt i64 %a, 5
+  %2 = trunc i64 %a to i32
+  %3 = select i1 %1, i32 %2, i32 5
+  ret i32 %3
+}
+
+; Same as @t3, but with mismatched signedness between icmp and zext.
+define i64 @t5(i32 %a) {
+; CHECK-LABEL: @t5(
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp sgt i32 [[A:%.*]], 5
+; CHECK-NEXT:    [[NARROW:%.*]] = select i1 [[TMP1]], i32 [[A]], i32 5
+; CHECK-NEXT:    [[TMP2:%.*]] = zext i32 [[NARROW]] to i64
+; CHECK-NEXT:    ret i64 [[TMP2]]
+;
+  %1 = icmp slt i32 %a, 5
+  %2 = zext i32 %a to i64
+  %3 = select i1 %1, i64 5, i64 %2
+  ret i64 %3
+}
+
+define float @t6(i32 %a) {
+; CHECK-LABEL: @t6(
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp slt i32 [[A:%.*]], 0
+; CHECK-NEXT:    [[TMP2:%.*]] = select i1 [[TMP1]], i32 [[A]], i32 0
+; CHECK-NEXT:    [[TMP3:%.*]] = sitofp i32 [[TMP2]] to float
+; CHECK-NEXT:    ret float [[TMP3]]
+;
+  %1 = icmp slt i32 %a, 0
+  %2 = select i1 %1, i32 %a, i32 0
+  %3 = sitofp i32 %2 to float
+  ret float %3
+}
+
+define i16 @t7(i32 %a) {
+; CHECK-LABEL: @t7(
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp slt i32 [[A:%.*]], -32768
+; CHECK-NEXT:    [[TMP2:%.*]] = select i1 [[TMP1]], i32 [[A]], i32 -32768
+; CHECK-NEXT:    [[TMP3:%.*]] = trunc i32 [[TMP2]] to i16
+; CHECK-NEXT:    ret i16 [[TMP3]]
+;
+  %1 = icmp slt i32 %a, -32768
+  %2 = trunc i32 %a to i16
+  %3 = select i1 %1, i16 %2, i16 -32768
+  ret i16 %3
+}
+
+; Just check for no infinite loop. InstSimplify liked to
+; "simplify" -32767 by removing all the sign bits,
+; which led to a canonicalization fight between different
+; parts of instcombine.
+define i32 @t8(i64 %a, i32 %b) {
+; CHECK-LABEL: @t8(
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp slt i64 [[A:%.*]], -32767
+; CHECK-NEXT:    [[TMP2:%.*]] = select i1 [[TMP1]], i64 [[A]], i64 -32767
+; CHECK-NEXT:    [[TMP3:%.*]] = trunc i64 [[TMP2]] to i32
+; CHECK-NEXT:    [[TMP4:%.*]] = icmp slt i32 [[B:%.*]], 42
+; CHECK-NEXT:    [[TMP5:%.*]] = select i1 [[TMP4]], i32 42, i32 [[TMP3]]
+; CHECK-NEXT:    [[TMP6:%.*]] = icmp ne i32 [[TMP5]], [[B]]
+; CHECK-NEXT:    [[TMP7:%.*]] = zext i1 [[TMP6]] to i32
+; CHECK-NEXT:    ret i32 [[TMP7]]
+;
+  %1 = icmp slt i64 %a, -32767
+  %2 = select i1 %1, i64 %a, i64 -32767
+  %3 = trunc i64 %2 to i32
+  %4 = icmp slt i32 %b, 42
+  %5 = select i1 %4, i32 42, i32 %3
+  %6 = icmp ne i32 %5, %b
+  %7 = zext i1 %6 to i32
+  ret i32 %7
+}
+
+; Ensure this doesn't get converted to a min/max.
+define i64 @t9(i32 %a) {
+; CHECK-LABEL: @t9(
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp sgt i32 [[A:%.*]], -1
+; CHECK-NEXT:    [[TMP2:%.*]] = sext i32 [[A]] to i64
+; CHECK-NEXT:    [[TMP3:%.*]] = select i1 [[TMP1]], i64 [[TMP2]], i64 4294967295
+; CHECK-NEXT:    ret i64 [[TMP3]]
+;
+  %1 = icmp sgt i32 %a, -1
+  %2 = sext i32 %a to i64
+  %3 = select i1 %1, i64 %2, i64 4294967295
+  ret i64 %3
+}
+
+define float @t10(i32 %x) {
+; CHECK-LABEL: @t10(
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp sgt i32 [[X:%.*]], 255
+; CHECK-NEXT:    [[R1:%.*]] = select i1 [[TMP1]], i32 [[X]], i32 255
+; CHECK-NEXT:    [[TMP2:%.*]] = sitofp i32 [[R1]] to float
+; CHECK-NEXT:    ret float [[TMP2]]
+;
+  %f_x = sitofp i32 %x to float
+  %cmp = icmp sgt i32 %x, 255
+  %r = select i1 %cmp, float %f_x, float 255.0
+  ret float %r
+}
+
+define float @t11(i64 %x) {
+; CHECK-LABEL: @t11(
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp sgt i64 [[X:%.*]], 255
+; CHECK-NEXT:    [[R1:%.*]] = select i1 [[TMP1]], i64 [[X]], i64 255
+; CHECK-NEXT:    [[TMP2:%.*]] = sitofp i64 [[R1]] to float
+; CHECK-NEXT:    ret float [[TMP2]]
+;
+  %f_x = sitofp i64 %x to float
+  %cmp = icmp sgt i64 %x, 255
+  %r = select i1 %cmp, float %f_x, float 255.0
+  ret float %r
+}
+
+; Reuse the first 2 bitcasts as the select operands.
+
+define <4 x i32> @bitcasts_fcmp_1(<2 x i64> %a, <2 x i64> %b) {
+; CHECK-LABEL: @bitcasts_fcmp_1(
+; CHECK-NEXT:    [[T0:%.*]] = bitcast <2 x i64> [[A:%.*]] to <4 x float>
+; CHECK-NEXT:    [[T1:%.*]] = bitcast <2 x i64> [[B:%.*]] to <4 x float>
+; CHECK-NEXT:    [[T2:%.*]] = fcmp olt <4 x float> [[T1]], [[T0]]
+; CHECK-NEXT:    [[TMP1:%.*]] = select <4 x i1> [[T2]], <4 x float> [[T0]], <4 x float> [[T1]]
+; CHECK-NEXT:    [[T5:%.*]] = bitcast <4 x float> [[TMP1]] to <4 x i32>
+; CHECK-NEXT:    ret <4 x i32> [[T5]]
+;
+  %t0 = bitcast <2 x i64> %a to <4 x float>
+  %t1 = bitcast <2 x i64> %b to <4 x float>
+  %t2 = fcmp olt <4 x float> %t1, %t0
+  %t3 = bitcast <2 x i64> %a to <4 x i32>
+  %t4 = bitcast <2 x i64> %b to <4 x i32>
+  %t5 = select <4 x i1> %t2, <4 x i32> %t3, <4 x i32> %t4
+  ret <4 x i32> %t5
+}
+
+; Switch cmp operand order.
+
+define <4 x i32> @bitcasts_fcmp_2(<2 x i64> %a, <2 x i64> %b) {
+; CHECK-LABEL: @bitcasts_fcmp_2(
+; CHECK-NEXT:    [[T0:%.*]] = bitcast <2 x i64> [[A:%.*]] to <4 x float>
+; CHECK-NEXT:    [[T1:%.*]] = bitcast <2 x i64> [[B:%.*]] to <4 x float>
+; CHECK-NEXT:    [[T2:%.*]] = fcmp olt <4 x float> [[T0]], [[T1]]
+; CHECK-NEXT:    [[TMP1:%.*]] = select <4 x i1> [[T2]], <4 x float> [[T0]], <4 x float> [[T1]]
+; CHECK-NEXT:    [[T5:%.*]] = bitcast <4 x float> [[TMP1]] to <4 x i32>
+; CHECK-NEXT:    ret <4 x i32> [[T5]]
+;
+  %t0 = bitcast <2 x i64> %a to <4 x float>
+  %t1 = bitcast <2 x i64> %b to <4 x float>
+  %t2 = fcmp olt <4 x float> %t0, %t1
+  %t3 = bitcast <2 x i64> %a to <4 x i32>
+  %t4 = bitcast <2 x i64> %b to <4 x i32>
+  %t5 = select <4 x i1> %t2, <4 x i32> %t3, <4 x i32> %t4
+  ret <4 x i32> %t5
+}
+
+; Integer cmp should have the same transforms.
+
+define <4 x float> @bitcasts_icmp(<2 x i64> %a, <2 x i64> %b) {
+; CHECK-LABEL: @bitcasts_icmp(
+; CHECK-NEXT:    [[T0:%.*]] = bitcast <2 x i64> [[A:%.*]] to <4 x i32>
+; CHECK-NEXT:    [[T1:%.*]] = bitcast <2 x i64> [[B:%.*]] to <4 x i32>
+; CHECK-NEXT:    [[T2:%.*]] = icmp slt <4 x i32> [[T1]], [[T0]]
+; CHECK-NEXT:    [[TMP1:%.*]] = select <4 x i1> [[T2]], <4 x i32> [[T0]], <4 x i32> [[T1]]
+; CHECK-NEXT:    [[T5:%.*]] = bitcast <4 x i32> [[TMP1]] to <4 x float>
+; CHECK-NEXT:    ret <4 x float> [[T5]]
+;
+  %t0 = bitcast <2 x i64> %a to <4 x i32>
+  %t1 = bitcast <2 x i64> %b to <4 x i32>
+  %t2 = icmp slt <4 x i32> %t1, %t0
+  %t3 = bitcast <2 x i64> %a to <4 x float>
+  %t4 = bitcast <2 x i64> %b to <4 x float>
+  %t5 = select <4 x i1> %t2, <4 x float> %t3, <4 x float> %t4
+  ret <4 x float> %t5
+}
+
+; SMIN(SMIN(X, 11), 92) -> SMIN(X, 11)
+define i32 @test68(i32 %x) {
+; CHECK-LABEL: @test68(
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp slt i32 [[X:%.*]], 11
+; CHECK-NEXT:    [[COND:%.*]] = select i1 [[TMP1]], i32 [[X]], i32 11
+; CHECK-NEXT:    ret i32 [[COND]]
+;
+  %cmp = icmp slt i32 11, %x
+  %cond = select i1 %cmp, i32 11, i32 %x
+  %cmp3 = icmp slt i32 92, %cond
+  %retval = select i1 %cmp3, i32 92, i32 %cond
+  ret i32 %retval
+}
+
+define <2 x i32> @test68vec(<2 x i32> %x) {
+; CHECK-LABEL: @test68vec(
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp slt <2 x i32> [[X:%.*]], <i32 11, i32 11>
+; CHECK-NEXT:    [[COND:%.*]] = select <2 x i1> [[TMP1]], <2 x i32> [[X]], <2 x i32> <i32 11, i32 11>
+; CHECK-NEXT:    ret <2 x i32> [[COND]]
+;
+  %cmp = icmp slt <2 x i32> <i32 11, i32 11>, %x
+  %cond = select <2 x i1> %cmp, <2 x i32> <i32 11, i32 11>, <2 x i32> %x
+  %cmp3 = icmp slt <2 x i32> <i32 92, i32 92>, %cond
+  %retval = select <2 x i1> %cmp3, <2 x i32> <i32 92, i32 92>, <2 x i32> %cond
+  ret <2 x i32> %retval
+}
+
+; MIN(MIN(X, 24), 83) -> MIN(X, 24)
+define i32 @test69(i32 %x) {
+; CHECK-LABEL: @test69(
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp ult i32 [[X:%.*]], 24
+; CHECK-NEXT:    [[COND:%.*]] = select i1 [[TMP1]], i32 [[X]], i32 24
+; CHECK-NEXT:    ret i32 [[COND]]
+;
+  %cmp = icmp ult i32 24, %x
+  %cond = select i1 %cmp, i32 24, i32 %x
+  %cmp3 = icmp ult i32 83, %cond
+  %retval = select i1 %cmp3, i32 83, i32 %cond
+  ret i32 %retval
+}
+
+; SMAX(SMAX(X, 75), 36) -> SMAX(X, 75)
+define i32 @test70(i32 %x) {
+; CHECK-LABEL: @test70(
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp sgt i32 [[X:%.*]], 75
+; CHECK-NEXT:    [[COND:%.*]] = select i1 [[TMP1]], i32 [[X]], i32 75
+; CHECK-NEXT:    ret i32 [[COND]]
+;
+  %cmp = icmp slt i32 %x, 75
+  %cond = select i1 %cmp, i32 75, i32 %x
+  %cmp3 = icmp slt i32 %cond, 36
+  %retval = select i1 %cmp3, i32 36, i32 %cond
+  ret i32 %retval
+}
+
+; MAX(MAX(X, 68), 47) -> MAX(X, 68)
+define i32 @test71(i32 %x) {
+; CHECK-LABEL: @test71(
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp ugt i32 [[X:%.*]], 68
+; CHECK-NEXT:    [[COND:%.*]] = select i1 [[TMP1]], i32 [[X]], i32 68
+; CHECK-NEXT:    ret i32 [[COND]]
+;
+  %cmp = icmp ult i32 %x, 68
+  %cond = select i1 %cmp, i32 68, i32 %x
+  %cmp3 = icmp ult i32 %cond, 47
+  %retval = select i1 %cmp3, i32 47, i32 %cond
+  ret i32 %retval
+}
+
+; SMIN(SMIN(X, 92), 11) -> SMIN(X, 11)
+define i32 @test72(i32 %x) {
+; CHECK-LABEL: @test72(
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp slt i32 [[X:%.*]], 11
+; CHECK-NEXT:    [[RETVAL:%.*]] = select i1 [[TMP1]], i32 [[X]], i32 11
+; CHECK-NEXT:    ret i32 [[RETVAL]]
+;
+  %cmp = icmp sgt i32 %x, 92
+  %cond = select i1 %cmp, i32 92, i32 %x
+  %cmp3 = icmp sgt i32 %cond, 11
+  %retval = select i1 %cmp3, i32 11, i32 %cond
+  ret i32 %retval
+}
+
+define <2 x i32> @test72vec(<2 x i32> %x) {
+; CHECK-LABEL: @test72vec(
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp slt <2 x i32> [[X:%.*]], <i32 11, i32 11>
+; CHECK-NEXT:    [[RETVAL:%.*]] = select <2 x i1> [[TMP1]], <2 x i32> [[X]], <2 x i32> <i32 11, i32 11>
+; CHECK-NEXT:    ret <2 x i32> [[RETVAL]]
+;
+  %cmp = icmp sgt <2 x i32> %x, <i32 92, i32 92>
+  %cond = select <2 x i1> %cmp, <2 x i32> <i32 92, i32 92>, <2 x i32> %x
+  %cmp3 = icmp sgt <2 x i32> %cond, <i32 11, i32 11>
+  %retval = select <2 x i1> %cmp3, <2 x i32> <i32 11, i32 11>, <2 x i32> %cond
+  ret <2 x i32> %retval
+}
+
+; MIN(MIN(X, 83), 24) -> MIN(X, 24)
+define i32 @test73(i32 %x) {
+; CHECK-LABEL: @test73(
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp ult i32 [[X:%.*]], 24
+; CHECK-NEXT:    [[RETVAL:%.*]] = select i1 [[TMP1]], i32 [[X]], i32 24
+; CHECK-NEXT:    ret i32 [[RETVAL]]
+;
+  %cmp = icmp ugt i32 %x, 83
+  %cond = select i1 %cmp, i32 83, i32 %x
+  %cmp3 = icmp ugt i32 %cond, 24
+  %retval = select i1 %cmp3, i32 24, i32 %cond
+  ret i32 %retval
+}
+
+; SMAX(SMAX(X, 36), 75) -> SMAX(X, 75)
+define i32 @test74(i32 %x) {
+; CHECK-LABEL: @test74(
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp sgt i32 [[X:%.*]], 75
+; CHECK-NEXT:    [[RETVAL:%.*]] = select i1 [[TMP1]], i32 [[X]], i32 75
+; CHECK-NEXT:    ret i32 [[RETVAL]]
+;
+  %cmp = icmp slt i32 %x, 36
+  %cond = select i1 %cmp, i32 36, i32 %x
+  %cmp3 = icmp slt i32 %cond, 75
+  %retval = select i1 %cmp3, i32 75, i32 %cond
+  ret i32 %retval
+}
+
+; MAX(MAX(X, 47), 68) -> MAX(X, 68)
+define i32 @test75(i32 %x) {
+; CHECK-LABEL: @test75(
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp ugt i32 [[X:%.*]], 68
+; CHECK-NEXT:    [[RETVAL:%.*]] = select i1 [[TMP1]], i32 [[X]], i32 68
+; CHECK-NEXT:    ret i32 [[RETVAL]]
+;
+  %cmp = icmp ult i32 %x, 47
+  %cond = select i1 %cmp, i32 47, i32 %x
+  %cmp3 = icmp ult i32 %cond, 68
+  %retval = select i1 %cmp3, i32 68, i32 %cond
+  ret i32 %retval
+}
+
+; The next 10 tests are value clamping with constants:
+; https://llvm.org/bugs/show_bug.cgi?id=31693
+
+; (X <s C1) ? C1 : SMIN(X, C2) ==> SMAX(SMIN(X, C2), C1)
+
+define i32 @clamp_signed1(i32 %x) {
+; CHECK-LABEL: @clamp_signed1(
+; CHECK-NEXT:    [[CMP2:%.*]] = icmp slt i32 [[X:%.*]], 255
+; CHECK-NEXT:    [[MIN:%.*]] = select i1 [[CMP2]], i32 [[X]], i32 255
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp sgt i32 [[MIN]], 15
+; CHECK-NEXT:    [[R:%.*]] = select i1 [[TMP1]], i32 [[MIN]], i32 15
+; CHECK-NEXT:    ret i32 [[R]]
+;
+  %cmp2 = icmp slt i32 %x, 255
+  %min = select i1 %cmp2, i32 %x, i32 255
+  %cmp1 = icmp slt i32 %x, 15
+  %r = select i1 %cmp1, i32 15, i32 %min
+  ret i32 %r
+}
+
+; (X >s C1) ? C1 : SMAX(X, C2) ==> SMIN(SMAX(X, C2), C1)
+
+define i32 @clamp_signed2(i32 %x) {
+; CHECK-LABEL: @clamp_signed2(
+; CHECK-NEXT:    [[CMP2:%.*]] = icmp sgt i32 [[X:%.*]], 15
+; CHECK-NEXT:    [[MAX:%.*]] = select i1 [[CMP2]], i32 [[X]], i32 15
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp slt i32 [[MAX]], 255
+; CHECK-NEXT:    [[R:%.*]] = select i1 [[TMP1]], i32 [[MAX]], i32 255
+; CHECK-NEXT:    ret i32 [[R]]
+;
+  %cmp2 = icmp sgt i32 %x, 15
+  %max = select i1 %cmp2, i32 %x, i32 15
+  %cmp1 = icmp sgt i32 %x, 255
+  %r = select i1 %cmp1, i32 255, i32 %max
+  ret i32 %r
+}
+
+; (X >s C1) ? SMIN(X, C2) : C1 ==> SMAX(SMIN(X, C2), C1)
+
+define i32 @clamp_signed3(i32 %x) {
+; CHECK-LABEL: @clamp_signed3(
+; CHECK-NEXT:    [[CMP2:%.*]] = icmp slt i32 [[X:%.*]], 255
+; CHECK-NEXT:    [[MIN:%.*]] = select i1 [[CMP2]], i32 [[X]], i32 255
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp sgt i32 [[MIN]], 15
+; CHECK-NEXT:    [[R:%.*]] = select i1 [[TMP1]], i32 [[MIN]], i32 15
+; CHECK-NEXT:    ret i32 [[R]]
+;
+  %cmp2 = icmp slt i32 %x, 255
+  %min = select i1 %cmp2, i32 %x, i32 255
+  %cmp1 = icmp sgt i32 %x, 15
+  %r = select i1 %cmp1, i32 %min, i32 15
+  ret i32 %r
+}
+
+; (X <s C1) ? SMAX(X, C2) : C1 ==> SMIN(SMAX(X, C1), C2)
+
+define i32 @clamp_signed4(i32 %x) {
+; CHECK-LABEL: @clamp_signed4(
+; CHECK-NEXT:    [[CMP2:%.*]] = icmp sgt i32 [[X:%.*]], 15
+; CHECK-NEXT:    [[MAX:%.*]] = select i1 [[CMP2]], i32 [[X]], i32 15
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp slt i32 [[MAX]], 255
+; CHECK-NEXT:    [[R:%.*]] = select i1 [[TMP1]], i32 [[MAX]], i32 255
+; CHECK-NEXT:    ret i32 [[R]]
+;
+  %cmp2 = icmp sgt i32 %x, 15
+  %max = select i1 %cmp2, i32 %x, i32 15
+  %cmp1 = icmp slt i32 %x, 255
+  %r = select i1 %cmp1, i32 %max, i32 255
+  ret i32 %r
+}
+
+; (X <u C1) ? C1 : UMIN(X, C2) ==> UMAX(UMIN(X, C2), C1)
+
+define i32 @clamp_unsigned1(i32 %x) {
+; CHECK-LABEL: @clamp_unsigned1(
+; CHECK-NEXT:    [[CMP2:%.*]] = icmp ult i32 [[X:%.*]], 255
+; CHECK-NEXT:    [[MIN:%.*]] = select i1 [[CMP2]], i32 [[X]], i32 255
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp ugt i32 [[MIN]], 15
+; CHECK-NEXT:    [[R:%.*]] = select i1 [[TMP1]], i32 [[MIN]], i32 15
+; CHECK-NEXT:    ret i32 [[R]]
+;
+  %cmp2 = icmp ult i32 %x, 255
+  %min = select i1 %cmp2, i32 %x, i32 255
+  %cmp1 = icmp ult i32 %x, 15
+  %r = select i1 %cmp1, i32 15, i32 %min
+  ret i32 %r
+}
+
+; (X >u C1) ? C1 : UMAX(X, C2) ==> UMIN(UMAX(X, C2), C1)
+
+define i32 @clamp_unsigned2(i32 %x) {
+; CHECK-LABEL: @clamp_unsigned2(
+; CHECK-NEXT:    [[CMP2:%.*]] = icmp ugt i32 [[X:%.*]], 15
+; CHECK-NEXT:    [[MAX:%.*]] = select i1 [[CMP2]], i32 [[X]], i32 15
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp ult i32 [[MAX]], 255
+; CHECK-NEXT:    [[R:%.*]] = select i1 [[TMP1]], i32 [[MAX]], i32 255
+; CHECK-NEXT:    ret i32 [[R]]
+;
+  %cmp2 = icmp ugt i32 %x, 15
+  %max = select i1 %cmp2, i32 %x, i32 15
+  %cmp1 = icmp ugt i32 %x, 255
+  %r = select i1 %cmp1, i32 255, i32 %max
+  ret i32 %r
+}
+
+; (X >u C1) ? UMIN(X, C2) : C1 ==> UMAX(UMIN(X, C2), C1)
+
+define i32 @clamp_unsigned3(i32 %x) {
+; CHECK-LABEL: @clamp_unsigned3(
+; CHECK-NEXT:    [[CMP2:%.*]] = icmp ult i32 [[X:%.*]], 255
+; CHECK-NEXT:    [[MIN:%.*]] = select i1 [[CMP2]], i32 [[X]], i32 255
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp ugt i32 [[MIN]], 15
+; CHECK-NEXT:    [[R:%.*]] = select i1 [[TMP1]], i32 [[MIN]], i32 15
+; CHECK-NEXT:    ret i32 [[R]]
+;
+  %cmp2 = icmp ult i32 %x, 255
+  %min = select i1 %cmp2, i32 %x, i32 255
+  %cmp1 = icmp ugt i32 %x, 15
+  %r = select i1 %cmp1, i32 %min, i32 15
+  ret i32 %r
+}
+
+; (X <u C1) ? UMAX(X, C2) : C1 ==> UMIN(UMAX(X, C2), C1)
+
+define i32 @clamp_unsigned4(i32 %x) {
+; CHECK-LABEL: @clamp_unsigned4(
+; CHECK-NEXT:    [[CMP2:%.*]] = icmp ugt i32 [[X:%.*]], 15
+; CHECK-NEXT:    [[MAX:%.*]] = select i1 [[CMP2]], i32 [[X]], i32 15
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp ult i32 [[MAX]], 255
+; CHECK-NEXT:    [[R:%.*]] = select i1 [[TMP1]], i32 [[MAX]], i32 255
+; CHECK-NEXT:    ret i32 [[R]]
+;
+  %cmp2 = icmp ugt i32 %x, 15
+  %max = select i1 %cmp2, i32 %x, i32 15
+  %cmp1 = icmp ult i32 %x, 255
+  %r = select i1 %cmp1, i32 %max, i32 255
+  ret i32 %r
+}
+
+; Check that clamp is recognized and there is no infinite
+; loop because of reverse cmp transformation:
+; (icmp sgt smin(PositiveA, B) 0) -> (icmp sgt B 0)
+define i32 @clamp_check_for_no_infinite_loop1(i32 %i) {
+; CHECK-LABEL: @clamp_check_for_no_infinite_loop1(
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp slt i32 [[I:%.*]], 255
+; CHECK-NEXT:    [[SEL1:%.*]] = select i1 [[CMP1]], i32 [[I]], i32 255
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp sgt i32 [[SEL1]], 0
+; CHECK-NEXT:    [[RES:%.*]] = select i1 [[TMP1]], i32 [[SEL1]], i32 0
+; CHECK-NEXT:    ret i32 [[RES]]
+;
+  %cmp1 = icmp slt i32 %i, 255
+  %sel1 = select i1 %cmp1, i32 %i, i32 255
+  %cmp2 = icmp slt i32 %i, 0
+  %res = select i1 %cmp2, i32 0, i32 %sel1
+  ret i32 %res
+}
+; Check that there is no infinite loop in case of:
+; (icmp slt smax(NegativeA, B) 0) -> (icmp slt B 0)
+define i32 @clamp_check_for_no_infinite_loop2(i32 %i) {
+; CHECK-LABEL: @clamp_check_for_no_infinite_loop2(
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp sgt i32 [[I:%.*]], -255
+; CHECK-NEXT:    [[SEL1:%.*]] = select i1 [[CMP1]], i32 [[I]], i32 -255
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp slt i32 [[SEL1]], 0
+; CHECK-NEXT:    [[RES:%.*]] = select i1 [[TMP1]], i32 [[SEL1]], i32 0
+; CHECK-NEXT:    ret i32 [[RES]]
+;
+  %cmp1 = icmp sgt i32 %i, -255
+  %sel1 = select i1 %cmp1, i32 %i, i32 -255
+  %cmp2 = icmp slt i32 %i, 0
+  %res = select i1 %cmp2, i32 %sel1, i32 0
+  ret i32 %res
+}
+
+; Check that there is no infinite loop because of reverse cmp transformation:
+; (icmp slt smax(PositiveA, B) 2) -> (icmp eq B 1)
+define i32 @clamp_check_for_no_infinite_loop3(i32 %i) {
+; CHECK-LABEL: @clamp_check_for_no_infinite_loop3(
+; CHECK-NEXT:    [[I2:%.*]] = icmp sgt i32 [[I:%.*]], 1
+; CHECK-NEXT:    [[I3:%.*]] = select i1 [[I2]], i32 [[I]], i32 1
+; CHECK-NEXT:    br i1 true, label [[TRUELABEL:%.*]], label [[FALSELABEL:%.*]]
+; CHECK:       truelabel:
+; CHECK-NEXT:    [[I5:%.*]] = icmp slt i32 [[I3]], 2
+; CHECK-NEXT:    [[I6:%.*]] = select i1 [[I5]], i32 [[I3]], i32 2
+; CHECK-NEXT:    [[I7:%.*]] = shl nuw nsw i32 [[I6]], 2
+; CHECK-NEXT:    ret i32 [[I7]]
+; CHECK:       falselabel:
+; CHECK-NEXT:    ret i32 0
+;
+
+  %i2 = icmp sgt i32 %i, 1
+  %i3 = select i1 %i2, i32 %i, i32 1
+  %i4 = icmp sgt i32 %i3, 0
+  br i1 %i4, label %truelabel, label %falselabel
+
+truelabel: ; %i<=1, %i3>0
+  %i5 = icmp slt i32 %i3, 2
+  %i6 = select i1 %i5, i32 %i3, i32 2
+  %i7 = shl nuw nsw i32 %i6, 2
+  ret i32 %i7
+
+falselabel:
+  ret i32 0
+}
+
+; The next 3 min tests should canonicalize to the same form...and not infinite loop.
+
+define double @PR31751_umin1(i32 %x) {
+; CHECK-LABEL: @PR31751_umin1(
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp ult i32 [[X:%.*]], 2147483647
+; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[TMP1]], i32 [[X]], i32 2147483647
+; CHECK-NEXT:    [[CONV:%.*]] = sitofp i32 [[SEL]] to double
+; CHECK-NEXT:    ret double [[CONV]]
+;
+  %cmp = icmp slt i32 %x, 0
+  %sel = select i1 %cmp, i32 2147483647, i32 %x
+  %conv = sitofp i32 %sel to double
+  ret double %conv
+}
+
+define double @PR31751_umin2(i32 %x) {
+; CHECK-LABEL: @PR31751_umin2(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i32 [[X:%.*]], 2147483647
+; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[CMP]], i32 [[X]], i32 2147483647
+; CHECK-NEXT:    [[CONV:%.*]] = sitofp i32 [[SEL]] to double
+; CHECK-NEXT:    ret double [[CONV]]
+;
+  %cmp = icmp ult i32 %x, 2147483647
+  %sel = select i1 %cmp, i32 %x, i32 2147483647
+  %conv = sitofp i32 %sel to double
+  ret double %conv
+}
+
+define double @PR31751_umin3(i32 %x) {
+; CHECK-LABEL: @PR31751_umin3(
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp ult i32 [[X:%.*]], 2147483647
+; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[TMP1]], i32 [[X]], i32 2147483647
+; CHECK-NEXT:    [[CONV:%.*]] = sitofp i32 [[SEL]] to double
+; CHECK-NEXT:    ret double [[CONV]]
+;
+  %cmp = icmp ugt i32 %x, 2147483647
+  %sel = select i1 %cmp, i32 2147483647, i32 %x
+  %conv = sitofp i32 %sel to double
+  ret double %conv
+}
+
+; The next 3 max tests should canonicalize to the same form...and not infinite loop.
+
+define double @PR31751_umax1(i32 %x) {
+; CHECK-LABEL: @PR31751_umax1(
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp ugt i32 [[X:%.*]], -2147483648
+; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[TMP1]], i32 [[X]], i32 -2147483648
+; CHECK-NEXT:    [[CONV:%.*]] = sitofp i32 [[SEL]] to double
+; CHECK-NEXT:    ret double [[CONV]]
+;
+  %cmp = icmp sgt i32 %x, -1
+  %sel = select i1 %cmp, i32 2147483648, i32 %x
+  %conv = sitofp i32 %sel to double
+  ret double %conv
+}
+
+define double @PR31751_umax2(i32 %x) {
+; CHECK-LABEL: @PR31751_umax2(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ugt i32 [[X:%.*]], -2147483648
+; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[CMP]], i32 [[X]], i32 -2147483648
+; CHECK-NEXT:    [[CONV:%.*]] = sitofp i32 [[SEL]] to double
+; CHECK-NEXT:    ret double [[CONV]]
+;
+  %cmp = icmp ugt i32 %x, 2147483648
+  %sel = select i1 %cmp, i32 %x, i32 2147483648
+  %conv = sitofp i32 %sel to double
+  ret double %conv
+}
+
+define double @PR31751_umax3(i32 %x) {
+; CHECK-LABEL: @PR31751_umax3(
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp ugt i32 [[X:%.*]], -2147483648
+; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[TMP1]], i32 [[X]], i32 -2147483648
+; CHECK-NEXT:    [[CONV:%.*]] = sitofp i32 [[SEL]] to double
+; CHECK-NEXT:    ret double [[CONV]]
+;
+  %cmp = icmp ult i32 %x, 2147483648
+  %sel = select i1 %cmp, i32 2147483648, i32 %x
+  %conv = sitofp i32 %sel to double
+  ret double %conv
+}
+
+; The icmp/select form a canonical smax, so don't hide that by folding the final bitcast into the select.
+
+define float @bitcast_scalar_smax(float %x, float %y) {
+; CHECK-LABEL: @bitcast_scalar_smax(
+; CHECK-NEXT:    [[BCX:%.*]] = bitcast float [[X:%.*]] to i32
+; CHECK-NEXT:    [[BCY:%.*]] = bitcast float [[Y:%.*]] to i32
+; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt i32 [[BCX]], [[BCY]]
+; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[CMP]], i32 [[BCX]], i32 [[BCY]]
+; CHECK-NEXT:    [[BCS:%.*]] = bitcast i32 [[SEL]] to float
+; CHECK-NEXT:    ret float [[BCS]]
+;
+  %bcx = bitcast float %x to i32
+  %bcy = bitcast float %y to i32
+  %cmp = icmp sgt i32 %bcx, %bcy
+  %sel = select i1 %cmp, i32 %bcx, i32 %bcy
+  %bcs = bitcast i32 %sel to float
+  ret float %bcs
+}
+
+; FIXME: Create a canonical umax by bitcasting the select.
+
+define float @bitcast_scalar_umax(float %x, float %y) {
+; CHECK-LABEL: @bitcast_scalar_umax(
+; CHECK-NEXT:    [[BCX:%.*]] = bitcast float [[X:%.*]] to i32
+; CHECK-NEXT:    [[BCY:%.*]] = bitcast float [[Y:%.*]] to i32
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ugt i32 [[BCX]], [[BCY]]
+; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[CMP]], float [[X]], float [[Y]]
+; CHECK-NEXT:    ret float [[SEL]]
+;
+  %bcx = bitcast float %x to i32
+  %bcy = bitcast float %y to i32
+  %cmp = icmp ugt i32 %bcx, %bcy
+  %sel = select i1 %cmp, float %x, float %y
+  ret float %sel
+}
+
+; PR32306 - https://bugs.llvm.org/show_bug.cgi?id=32306
+; The icmp/select form a canonical smin, so don't hide that by folding the final bitcast into the select.
+
+define <8 x float> @bitcast_vector_smin(<8 x float> %x, <8 x float> %y) {
+; CHECK-LABEL: @bitcast_vector_smin(
+; CHECK-NEXT:    [[BCX:%.*]] = bitcast <8 x float> [[X:%.*]] to <8 x i32>
+; CHECK-NEXT:    [[BCY:%.*]] = bitcast <8 x float> [[Y:%.*]] to <8 x i32>
+; CHECK-NEXT:    [[CMP:%.*]] = icmp slt <8 x i32> [[BCX]], [[BCY]]
+; CHECK-NEXT:    [[SEL:%.*]] = select <8 x i1> [[CMP]], <8 x i32> [[BCX]], <8 x i32> [[BCY]]
+; CHECK-NEXT:    [[BCS:%.*]] = bitcast <8 x i32> [[SEL]] to <8 x float>
+; CHECK-NEXT:    ret <8 x float> [[BCS]]
+;
+  %bcx = bitcast <8 x float> %x to <8 x i32>
+  %bcy = bitcast <8 x float> %y to <8 x i32>
+  %cmp = icmp slt <8 x i32> %bcx, %bcy
+  %sel = select <8 x i1> %cmp, <8 x i32> %bcx, <8 x i32> %bcy
+  %bcs = bitcast <8 x i32> %sel to <8 x float>
+  ret <8 x float> %bcs
+}
+
+; FIXME: Create a canonical umin by bitcasting the select.
+
+define <8 x float> @bitcast_vector_umin(<8 x float> %x, <8 x float> %y) {
+; CHECK-LABEL: @bitcast_vector_umin(
+; CHECK-NEXT:    [[BCX:%.*]] = bitcast <8 x float> [[X:%.*]] to <8 x i32>
+; CHECK-NEXT:    [[BCY:%.*]] = bitcast <8 x float> [[Y:%.*]] to <8 x i32>
+; CHECK-NEXT:    [[CMP:%.*]] = icmp slt <8 x i32> [[BCX]], [[BCY]]
+; CHECK-NEXT:    [[SEL:%.*]] = select <8 x i1> [[CMP]], <8 x float> [[X]], <8 x float> [[Y]]
+; CHECK-NEXT:    ret <8 x float> [[SEL]]
+;
+  %bcx = bitcast <8 x float> %x to <8 x i32>
+  %bcy = bitcast <8 x float> %y to <8 x i32>
+  %cmp = icmp slt <8 x i32> %bcx, %bcy
+  %sel = select <8 x i1> %cmp, <8 x float> %x, <8 x float> %y
+  ret <8 x float> %sel
+}
+
+; Check that we look through cast and recognize min idiom.
+
+define zeroext i8 @look_through_cast1(i32 %x) {
+; CHECK-LABEL: @look_through_cast1(
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp slt i32 [[X:%.*]], 511
+; CHECK-NEXT:    [[RES1:%.*]] = select i1 [[TMP1]], i32 [[X]], i32 511
+; CHECK-NEXT:    [[TMP2:%.*]] = trunc i32 [[RES1]] to i8
+; CHECK-NEXT:    ret i8 [[TMP2]]
+;
+  %cmp1 = icmp slt i32 %x, 511
+  %x_trunc = trunc i32 %x to i8
+  %res = select i1 %cmp1, i8 %x_trunc, i8 255
+  ret i8 %res
+}
+
+; Check that we look through cast but min is not recognized.
+
+define zeroext i8 @look_through_cast2(i32 %x) {
+; CHECK-LABEL: @look_through_cast2(
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp slt i32 [[X:%.*]], 510
+; CHECK-NEXT:    [[X_TRUNC:%.*]] = trunc i32 [[X]] to i8
+; CHECK-NEXT:    [[RES:%.*]] = select i1 [[CMP1]], i8 [[X_TRUNC]], i8 -1
+; CHECK-NEXT:    ret i8 [[RES]]
+;
+  %cmp1 = icmp slt i32 %x, 510
+  %x_trunc = trunc i32 %x to i8
+  %res = select i1 %cmp1, i8 %x_trunc, i8 255
+  ret i8 %res
+}
+
+define <2 x i8> @min_through_cast_vec1(<2 x i32> %x) {
+; CHECK-LABEL: @min_through_cast_vec1(
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp slt <2 x i32> [[X:%.*]], <i32 510, i32 511>
+; CHECK-NEXT:    [[RES1:%.*]] = select <2 x i1> [[TMP1]], <2 x i32> [[X]], <2 x i32> <i32 510, i32 511>
+; CHECK-NEXT:    [[TMP2:%.*]] = trunc <2 x i32> [[RES1]] to <2 x i8>
+; CHECK-NEXT:    ret <2 x i8> [[TMP2]]
+;
+  %cmp = icmp slt <2 x i32> %x, <i32 510, i32 511>
+  %x_trunc = trunc <2 x i32> %x to <2 x i8>
+  %res = select <2 x i1> %cmp, <2 x i8> %x_trunc, <2 x i8> <i8 254, i8 255>
+  ret <2 x i8> %res
+}
+
+define <2 x i8> @min_through_cast_vec2(<2 x i32> %x) {
+; CHECK-LABEL: @min_through_cast_vec2(
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp slt <2 x i32> [[X:%.*]], <i32 511, i32 511>
+; CHECK-NEXT:    [[RES1:%.*]] = select <2 x i1> [[TMP1]], <2 x i32> [[X]], <2 x i32> <i32 511, i32 511>
+; CHECK-NEXT:    [[TMP2:%.*]] = trunc <2 x i32> [[RES1]] to <2 x i8>
+; CHECK-NEXT:    ret <2 x i8> [[TMP2]]
+;
+  %cmp = icmp slt <2 x i32> %x, <i32 511, i32 511>
+  %x_trunc = trunc <2 x i32> %x to <2 x i8>
+  %res = select <2 x i1> %cmp, <2 x i8> %x_trunc, <2 x i8> <i8 255, i8 255>
+  ret <2 x i8> %res
+}
+
+; Remove a min/max op in a sequence with a common operand.
+; PR35717: https://bugs.llvm.org/show_bug.cgi?id=35717
+
+; min(min(a, b), min(b, c)) --> min(min(a, b), c)
+
+define i32 @common_factor_smin(i32 %a, i32 %b, i32 %c) {
+; CHECK-LABEL: @common_factor_smin(
+; CHECK-NEXT:    [[CMP_AB:%.*]] = icmp slt i32 [[A:%.*]], [[B:%.*]]
+; CHECK-NEXT:    [[MIN_AB:%.*]] = select i1 [[CMP_AB]], i32 [[A]], i32 [[B]]
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp slt i32 [[MIN_AB]], [[C:%.*]]
+; CHECK-NEXT:    [[MIN_ABC:%.*]] = select i1 [[TMP1]], i32 [[MIN_AB]], i32 [[C]]
+; CHECK-NEXT:    ret i32 [[MIN_ABC]]
+;
+  %cmp_ab = icmp slt i32 %a, %b
+  %min_ab = select i1 %cmp_ab, i32 %a, i32 %b
+  %cmp_bc = icmp slt i32 %b, %c
+  %min_bc = select i1 %cmp_bc, i32 %b, i32 %c
+  %cmp_ab_bc = icmp slt i32 %min_ab, %min_bc
+  %min_abc = select i1 %cmp_ab_bc, i32 %min_ab, i32 %min_bc
+  ret i32 %min_abc
+}
+
+; max(max(a, b), max(c, b)) --> max(max(a, b), c)
+
+define <2 x i32> @common_factor_smax(<2 x i32> %a, <2 x i32> %b, <2 x i32> %c) {
+; CHECK-LABEL: @common_factor_smax(
+; CHECK-NEXT:    [[CMP_AB:%.*]] = icmp sgt <2 x i32> [[A:%.*]], [[B:%.*]]
+; CHECK-NEXT:    [[MAX_AB:%.*]] = select <2 x i1> [[CMP_AB]], <2 x i32> [[A]], <2 x i32> [[B]]
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp sgt <2 x i32> [[MAX_AB]], [[C:%.*]]
+; CHECK-NEXT:    [[MAX_ABC:%.*]] = select <2 x i1> [[TMP1]], <2 x i32> [[MAX_AB]], <2 x i32> [[C]]
+; CHECK-NEXT:    ret <2 x i32> [[MAX_ABC]]
+;
+  %cmp_ab = icmp sgt <2 x i32> %a, %b
+  %max_ab = select <2 x i1> %cmp_ab, <2 x i32> %a, <2 x i32> %b
+  %cmp_cb = icmp sgt <2 x i32> %c, %b
+  %max_cb = select <2 x i1> %cmp_cb, <2 x i32> %c, <2 x i32> %b
+  %cmp_ab_cb = icmp sgt <2 x i32> %max_ab, %max_cb
+  %max_abc = select <2 x i1> %cmp_ab_cb, <2 x i32> %max_ab, <2 x i32> %max_cb
+  ret <2 x i32> %max_abc
+}
+
+; min(min(b, c), min(a, b)) --> min(min(b, c), a)
+
+define <2 x i32> @common_factor_umin(<2 x i32> %a, <2 x i32> %b, <2 x i32> %c) {
+; CHECK-LABEL: @common_factor_umin(
+; CHECK-NEXT:    [[CMP_BC:%.*]] = icmp ult <2 x i32> [[B:%.*]], [[C:%.*]]
+; CHECK-NEXT:    [[MIN_BC:%.*]] = select <2 x i1> [[CMP_BC]], <2 x i32> [[B]], <2 x i32> [[C]]
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp ult <2 x i32> [[MIN_BC]], [[A:%.*]]
+; CHECK-NEXT:    [[MIN_ABC:%.*]] = select <2 x i1> [[TMP1]], <2 x i32> [[MIN_BC]], <2 x i32> [[A]]
+; CHECK-NEXT:    ret <2 x i32> [[MIN_ABC]]
+;
+  %cmp_bc = icmp ult <2 x i32> %b, %c
+  %min_bc = select <2 x i1> %cmp_bc, <2 x i32> %b, <2 x i32> %c
+  %cmp_ab = icmp ult <2 x i32> %a, %b
+  %min_ab = select <2 x i1> %cmp_ab, <2 x i32> %a, <2 x i32> %b
+  %cmp_bc_ab = icmp ult <2 x i32> %min_bc, %min_ab
+  %min_abc = select <2 x i1> %cmp_bc_ab, <2 x i32> %min_bc, <2 x i32> %min_ab
+  ret <2 x i32> %min_abc
+}
+
+; max(max(b, c), max(b, a)) --> max(max(b, c), a)
+
+define i32 @common_factor_umax(i32 %a, i32 %b, i32 %c) {
+; CHECK-LABEL: @common_factor_umax(
+; CHECK-NEXT:    [[CMP_BC:%.*]] = icmp ugt i32 [[B:%.*]], [[C:%.*]]
+; CHECK-NEXT:    [[MAX_BC:%.*]] = select i1 [[CMP_BC]], i32 [[B]], i32 [[C]]
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp ugt i32 [[MAX_BC]], [[A:%.*]]
+; CHECK-NEXT:    [[MAX_ABC:%.*]] = select i1 [[TMP1]], i32 [[MAX_BC]], i32 [[A]]
+; CHECK-NEXT:    ret i32 [[MAX_ABC]]
+;
+  %cmp_bc = icmp ugt i32 %b, %c
+  %max_bc = select i1 %cmp_bc, i32 %b, i32 %c
+  %cmp_ba = icmp ugt i32 %b, %a
+  %max_ba = select i1 %cmp_ba, i32 %b, i32 %a
+  %cmp_bc_ba = icmp ugt i32 %max_bc, %max_ba
+  %max_abc = select i1 %cmp_bc_ba, i32 %max_bc, i32 %max_ba
+  ret i32 %max_abc
+}
+
+declare void @extra_use(i32)
+
+define i32 @common_factor_umax_extra_use_lhs(i32 %a, i32 %b, i32 %c) {
+; CHECK-LABEL: @common_factor_umax_extra_use_lhs(
+; CHECK-NEXT:    [[CMP_BC:%.*]] = icmp ugt i32 [[B:%.*]], [[C:%.*]]
+; CHECK-NEXT:    [[MAX_BC:%.*]] = select i1 [[CMP_BC]], i32 [[B]], i32 [[C]]
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp ugt i32 [[MAX_BC]], [[A:%.*]]
+; CHECK-NEXT:    [[MAX_ABC:%.*]] = select i1 [[TMP1]], i32 [[MAX_BC]], i32 [[A]]
+; CHECK-NEXT:    call void @extra_use(i32 [[MAX_BC]])
+; CHECK-NEXT:    ret i32 [[MAX_ABC]]
+;
+  %cmp_bc = icmp ugt i32 %b, %c
+  %max_bc = select i1 %cmp_bc, i32 %b, i32 %c
+  %cmp_ba = icmp ugt i32 %b, %a
+  %max_ba = select i1 %cmp_ba, i32 %b, i32 %a
+  %cmp_bc_ba = icmp ugt i32 %max_bc, %max_ba
+  %max_abc = select i1 %cmp_bc_ba, i32 %max_bc, i32 %max_ba
+  call void @extra_use(i32 %max_bc)
+  ret i32 %max_abc
+}
+
+define i32 @common_factor_umax_extra_use_rhs(i32 %a, i32 %b, i32 %c) {
+; CHECK-LABEL: @common_factor_umax_extra_use_rhs(
+; CHECK-NEXT:    [[CMP_BA:%.*]] = icmp ugt i32 [[B:%.*]], [[A:%.*]]
+; CHECK-NEXT:    [[MAX_BA:%.*]] = select i1 [[CMP_BA]], i32 [[B]], i32 [[A]]
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp ugt i32 [[MAX_BA]], [[C:%.*]]
+; CHECK-NEXT:    [[MAX_ABC:%.*]] = select i1 [[TMP1]], i32 [[MAX_BA]], i32 [[C]]
+; CHECK-NEXT:    call void @extra_use(i32 [[MAX_BA]])
+; CHECK-NEXT:    ret i32 [[MAX_ABC]]
+;
+  %cmp_bc = icmp ugt i32 %b, %c
+  %max_bc = select i1 %cmp_bc, i32 %b, i32 %c
+  %cmp_ba = icmp ugt i32 %b, %a
+  %max_ba = select i1 %cmp_ba, i32 %b, i32 %a
+  %cmp_bc_ba = icmp ugt i32 %max_bc, %max_ba
+  %max_abc = select i1 %cmp_bc_ba, i32 %max_bc, i32 %max_ba
+  call void @extra_use(i32 %max_ba)
+  ret i32 %max_abc
+}
+
+define i32 @common_factor_umax_extra_use_both(i32 %a, i32 %b, i32 %c) {
+; CHECK-LABEL: @common_factor_umax_extra_use_both(
+; CHECK-NEXT:    [[CMP_BC:%.*]] = icmp ugt i32 [[B:%.*]], [[C:%.*]]
+; CHECK-NEXT:    [[MAX_BC:%.*]] = select i1 [[CMP_BC]], i32 [[B]], i32 [[C]]
+; CHECK-NEXT:    [[CMP_BA:%.*]] = icmp ugt i32 [[B]], [[A:%.*]]
+; CHECK-NEXT:    [[MAX_BA:%.*]] = select i1 [[CMP_BA]], i32 [[B]], i32 [[A]]
+; CHECK-NEXT:    [[CMP_BC_BA:%.*]] = icmp ugt i32 [[MAX_BC]], [[MAX_BA]]
+; CHECK-NEXT:    [[MAX_ABC:%.*]] = select i1 [[CMP_BC_BA]], i32 [[MAX_BC]], i32 [[MAX_BA]]
+; CHECK-NEXT:    call void @extra_use(i32 [[MAX_BC]])
+; CHECK-NEXT:    call void @extra_use(i32 [[MAX_BA]])
+; CHECK-NEXT:    ret i32 [[MAX_ABC]]
+;
+  %cmp_bc = icmp ugt i32 %b, %c
+  %max_bc = select i1 %cmp_bc, i32 %b, i32 %c
+  %cmp_ba = icmp ugt i32 %b, %a
+  %max_ba = select i1 %cmp_ba, i32 %b, i32 %a
+  %cmp_bc_ba = icmp ugt i32 %max_bc, %max_ba
+  %max_abc = select i1 %cmp_bc_ba, i32 %max_bc, i32 %max_ba
+  call void @extra_use(i32 %max_bc)
+  call void @extra_use(i32 %max_ba)
+  ret i32 %max_abc
+}
+
+; This would assert. Don't assume that earlier min/max types match a possible later min/max.
+
+define float @not_min_of_min(i8 %i, float %x) {
+; CHECK-LABEL: @not_min_of_min(
+; CHECK-NEXT:    [[CMP1_INV:%.*]] = fcmp fast oge float [[X:%.*]], 1.000000e+00
+; CHECK-NEXT:    [[MIN1:%.*]] = select i1 [[CMP1_INV]], float 1.000000e+00, float [[X]]
+; CHECK-NEXT:    [[CMP2_INV:%.*]] = fcmp fast oge float [[X]], 2.000000e+00
+; CHECK-NEXT:    [[MIN2:%.*]] = select i1 [[CMP2_INV]], float 2.000000e+00, float [[X]]
+; CHECK-NEXT:    [[CMP3:%.*]] = icmp ult i8 [[I:%.*]], 16
+; CHECK-NEXT:    [[R:%.*]] = select i1 [[CMP3]], float [[MIN1]], float [[MIN2]]
+; CHECK-NEXT:    ret float [[R]]
+;
+  %cmp1 = fcmp fast ult float %x, 1.0
+  %min1 = select i1 %cmp1, float %x, float 1.0
+  %cmp2 = fcmp fast ult float %x, 2.0
+  %min2 = select i1 %cmp2, float %x, float 2.0
+  %cmp3 = icmp ult i8 %i, 16
+  %r = select i1 %cmp3, float %min1, float %min2
+  ret float %r
+}
+
+define i32 @add_umin(i32 %x) {
+; CHECK-LABEL: @add_umin(
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp ult i32 [[X:%.*]], 27
+; CHECK-NEXT:    [[TMP2:%.*]] = select i1 [[TMP1]], i32 [[X]], i32 27
+; CHECK-NEXT:    [[R:%.*]] = add nuw nsw i32 [[TMP2]], 15
+; CHECK-NEXT:    ret i32 [[R]]
+;
+  %a = add nuw i32 %x, 15
+  %c = icmp ult i32 %a, 42
+  %r = select i1 %c, i32 %a, i32 42
+  ret i32 %r
+}
+
+define i32 @add_umin_constant_limit(i32 %x) {
+; CHECK-LABEL: @add_umin_constant_limit(
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp eq i32 [[X:%.*]], 0
+; CHECK-NEXT:    [[R:%.*]] = select i1 [[TMP1]], i32 41, i32 42
+; CHECK-NEXT:    ret i32 [[R]]
+;
+  %a = add nuw i32 %x, 41
+  %c = icmp ult i32 %a, 42
+  %r = select i1 %c, i32 %a, i32 42
+  ret i32 %r
+}
+
+; Negative test
+; TODO: assert that instsimplify always gets this?
+
+define i32 @add_umin_simplify(i32 %x) {
+; CHECK-LABEL: @add_umin_simplify(
+; CHECK-NEXT:    ret i32 42
+;
+  %a = add nuw i32 %x, 42
+  %c = icmp ult i32 %a, 42
+  %r = select i1 %c, i32 %a, i32 42
+  ret i32 %r
+}
+
+; Negative test
+; TODO: assert that instsimplify always gets this?
+
+define i32 @add_umin_simplify2(i32 %x) {
+; CHECK-LABEL: @add_umin_simplify2(
+; CHECK-NEXT:    ret i32 42
+;
+  %a = add nuw i32 %x, 43
+  %c = icmp ult i32 %a, 42
+  %r = select i1 %c, i32 %a, i32 42
+  ret i32 %r
+}
+
+; Negative test
+
+define i32 @add_umin_wrong_pred(i32 %x) {
+; CHECK-LABEL: @add_umin_wrong_pred(
+; CHECK-NEXT:    [[A:%.*]] = add nuw i32 [[X:%.*]], 15
+; CHECK-NEXT:    [[C:%.*]] = icmp slt i32 [[A]], 42
+; CHECK-NEXT:    [[R:%.*]] = select i1 [[C]], i32 [[A]], i32 42
+; CHECK-NEXT:    ret i32 [[R]]
+;
+  %a = add nuw i32 %x, 15
+  %c = icmp slt i32 %a, 42
+  %r = select i1 %c, i32 %a, i32 42
+  ret i32 %r
+}
+
+; Negative test
+
+define i32 @add_umin_wrong_wrap(i32 %x) {
+; CHECK-LABEL: @add_umin_wrong_wrap(
+; CHECK-NEXT:    [[A:%.*]] = add nsw i32 [[X:%.*]], 15
+; CHECK-NEXT:    [[C:%.*]] = icmp ult i32 [[A]], 42
+; CHECK-NEXT:    [[R:%.*]] = select i1 [[C]], i32 [[A]], i32 42
+; CHECK-NEXT:    ret i32 [[R]]
+;
+  %a = add nsw i32 %x, 15
+  %c = icmp ult i32 %a, 42
+  %r = select i1 %c, i32 %a, i32 42
+  ret i32 %r
+}
+
+; Negative test
+
+define i32 @add_umin_extra_use(i32 %x, i32* %p) {
+; CHECK-LABEL: @add_umin_extra_use(
+; CHECK-NEXT:    [[A:%.*]] = add nuw i32 [[X:%.*]], 15
+; CHECK-NEXT:    store i32 [[A]], i32* [[P:%.*]], align 4
+; CHECK-NEXT:    [[C:%.*]] = icmp ult i32 [[A]], 42
+; CHECK-NEXT:    [[R:%.*]] = select i1 [[C]], i32 [[A]], i32 42
+; CHECK-NEXT:    ret i32 [[R]]
+;
+  %a = add nuw i32 %x, 15
+  store i32 %a, i32* %p
+  %c = icmp ult i32 %a, 42
+  %r = select i1 %c, i32 %a, i32 42
+  ret i32 %r
+}
+
+define <2 x i16> @add_umin_vec(<2 x i16> %x) {
+; CHECK-LABEL: @add_umin_vec(
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp ult <2 x i16> [[X:%.*]], <i16 225, i16 225>
+; CHECK-NEXT:    [[TMP2:%.*]] = select <2 x i1> [[TMP1]], <2 x i16> [[X]], <2 x i16> <i16 225, i16 225>
+; CHECK-NEXT:    [[R:%.*]] = add nuw nsw <2 x i16> [[TMP2]], <i16 15, i16 15>
+; CHECK-NEXT:    ret <2 x i16> [[R]]
+;
+  %a = add nuw <2 x i16> %x, <i16 15, i16 15>
+  %c = icmp ult <2 x i16> %a, <i16 240, i16 240>
+  %r = select <2 x i1> %c, <2 x i16> %a, <2 x i16> <i16 240, i16 240>
+  ret <2 x i16> %r
+}
+
+define i37 @add_umax(i37 %x) {
+; CHECK-LABEL: @add_umax(
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp ugt i37 [[X:%.*]], 37
+; CHECK-NEXT:    [[TMP2:%.*]] = select i1 [[TMP1]], i37 [[X]], i37 37
+; CHECK-NEXT:    [[R:%.*]] = add nuw i37 [[TMP2]], 5
+; CHECK-NEXT:    ret i37 [[R]]
+;
+  %a = add nuw i37 %x, 5
+  %c = icmp ugt i37 %a, 42
+  %r = select i1 %c, i37 %a, i37 42
+  ret i37 %r
+}
+
+define i37 @add_umax_constant_limit(i37 %x) {
+; CHECK-LABEL: @add_umax_constant_limit(
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp ugt i37 [[X:%.*]], 1
+; CHECK-NEXT:    [[TMP2:%.*]] = select i1 [[TMP1]], i37 [[X]], i37 1
+; CHECK-NEXT:    [[R:%.*]] = add nuw i37 [[TMP2]], 81
+; CHECK-NEXT:    ret i37 [[R]]
+;
+  %a = add nuw i37 %x, 81
+  %c = icmp ugt i37 %a, 82
+  %r = select i1 %c, i37 %a, i37 82
+  ret i37 %r
+}
+
+; Negative test
+; TODO: assert that instsimplify always gets this?
+
+define i37 @add_umax_simplify(i37 %x) {
+; CHECK-LABEL: @add_umax_simplify(
+; CHECK-NEXT:    [[R:%.*]] = add nuw i37 [[X:%.*]], 42
+; CHECK-NEXT:    ret i37 [[R]]
+;
+  %a = add nuw i37 %x, 42
+  %c = icmp ugt i37 %a, 42
+  %r = select i1 %c, i37 %a, i37 42
+  ret i37 %r
+}
+
+; Negative test
+; TODO: assert that instsimplify always gets this?
+
+define i32 @add_umax_simplify2(i32 %x) {
+; CHECK-LABEL: @add_umax_simplify2(
+; CHECK-NEXT:    [[A:%.*]] = add nuw i32 [[X:%.*]], 57
+; CHECK-NEXT:    ret i32 [[A]]
+;
+  %a = add nuw i32 %x, 57
+  %c = icmp ugt i32 %a, 56
+  %r = select i1 %c, i32 %a, i32 56
+  ret i32 %r
+}
+
+; Negative test
+
+define i32 @add_umax_wrong_pred(i32 %x) {
+; CHECK-LABEL: @add_umax_wrong_pred(
+; CHECK-NEXT:    [[A:%.*]] = add nuw i32 [[X:%.*]], 15
+; CHECK-NEXT:    [[C:%.*]] = icmp sgt i32 [[A]], 42
+; CHECK-NEXT:    [[R:%.*]] = select i1 [[C]], i32 [[A]], i32 42
+; CHECK-NEXT:    ret i32 [[R]]
+;
+  %a = add nuw i32 %x, 15
+  %c = icmp sgt i32 %a, 42
+  %r = select i1 %c, i32 %a, i32 42
+  ret i32 %r
+}
+
+; Negative test
+
+define i32 @add_umax_wrong_wrap(i32 %x) {
+; CHECK-LABEL: @add_umax_wrong_wrap(
+; CHECK-NEXT:    [[A:%.*]] = add nsw i32 [[X:%.*]], 15
+; CHECK-NEXT:    [[C:%.*]] = icmp ugt i32 [[A]], 42
+; CHECK-NEXT:    [[R:%.*]] = select i1 [[C]], i32 [[A]], i32 42
+; CHECK-NEXT:    ret i32 [[R]]
+;
+  %a = add nsw i32 %x, 15
+  %c = icmp ugt i32 %a, 42
+  %r = select i1 %c, i32 %a, i32 42
+  ret i32 %r
+}
+
+; Negative test
+
+define i32 @add_umax_extra_use(i32 %x, i32* %p) {
+; CHECK-LABEL: @add_umax_extra_use(
+; CHECK-NEXT:    [[A:%.*]] = add nuw i32 [[X:%.*]], 15
+; CHECK-NEXT:    store i32 [[A]], i32* [[P:%.*]], align 4
+; CHECK-NEXT:    [[C:%.*]] = icmp ugt i32 [[A]], 42
+; CHECK-NEXT:    [[R:%.*]] = select i1 [[C]], i32 [[A]], i32 42
+; CHECK-NEXT:    ret i32 [[R]]
+;
+  %a = add nuw i32 %x, 15
+  store i32 %a, i32* %p
+  %c = icmp ugt i32 %a, 42
+  %r = select i1 %c, i32 %a, i32 42
+  ret i32 %r
+}
+
+define <2 x i33> @add_umax_vec(<2 x i33> %x) {
+; CHECK-LABEL: @add_umax_vec(
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp ugt <2 x i33> [[X:%.*]], <i33 235, i33 235>
+; CHECK-NEXT:    [[TMP2:%.*]] = select <2 x i1> [[TMP1]], <2 x i33> [[X]], <2 x i33> <i33 235, i33 235>
+; CHECK-NEXT:    [[R:%.*]] = add nuw <2 x i33> [[TMP2]], <i33 5, i33 5>
+; CHECK-NEXT:    ret <2 x i33> [[R]]
+;
+  %a = add nuw <2 x i33> %x, <i33 5, i33 5>
+  %c = icmp ugt <2 x i33> %a, <i33 240, i33 240>
+  %r = select <2 x i1> %c, <2 x i33> %a, <2 x i33> <i33 240, i33 240>
+  ret <2 x i33> %r
+}
+
+define i8 @PR14613_umin(i8 %x) {
+; CHECK-LABEL: @PR14613_umin(
+; CHECK-NEXT:    [[U7:%.*]] = call i8 @llvm.uadd.sat.i8(i8 [[X:%.*]], i8 15)
+; CHECK-NEXT:    ret i8 [[U7]]
+;
+  %u4 = zext i8 %x to i32
+  %u5 = add nuw nsw i32 %u4, 15
+  %u6 = icmp ult i32 %u5, 255
+  %u7 = select i1 %u6, i32 %u5, i32 255
+  %r = trunc i32 %u7 to i8
+  ret i8 %r
+}
+
+define i8 @PR14613_umax(i8 %x) {
+; CHECK-LABEL: @PR14613_umax(
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp ugt i8 [[X:%.*]], -16
+; CHECK-NEXT:    [[TMP2:%.*]] = select i1 [[TMP1]], i8 [[X]], i8 -16
+; CHECK-NEXT:    [[U7:%.*]] = add nsw i8 [[TMP2]], 15
+; CHECK-NEXT:    ret i8 [[U7]]
+;
+  %u4 = zext i8 %x to i32
+  %u5 = add nuw nsw i32 %u4, 15
+  %u6 = icmp ugt i32 %u5, 255
+  %u7 = select i1 %u6, i32 %u5, i32 255
+  %r = trunc i32 %u7 to i8
+  ret i8 %r
+}
+
+define i32 @add_smin(i32 %x) {
+; CHECK-LABEL: @add_smin(
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp slt i32 [[X:%.*]], 27
+; CHECK-NEXT:    [[TMP2:%.*]] = select i1 [[TMP1]], i32 [[X]], i32 27
+; CHECK-NEXT:    [[R:%.*]] = add nsw i32 [[TMP2]], 15
+; CHECK-NEXT:    ret i32 [[R]]
+;
+  %a = add nsw i32 %x, 15
+  %c = icmp slt i32 %a, 42
+  %r = select i1 %c, i32 %a, i32 42
+  ret i32 %r
+}
+
+define i32 @add_smin_constant_limit(i32 %x) {
+; CHECK-LABEL: @add_smin_constant_limit(
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp slt i32 [[X:%.*]], 2147483646
+; CHECK-NEXT:    [[TMP2:%.*]] = select i1 [[TMP1]], i32 [[X]], i32 2147483646
+; CHECK-NEXT:    [[R:%.*]] = add nsw i32 [[TMP2]], -3
+; CHECK-NEXT:    ret i32 [[R]]
+;
+  %a = add nsw i32 %x, -3
+  %c = icmp slt i32 %a, 2147483643
+  %r = select i1 %c, i32 %a, i32 2147483643
+  ret i32 %r
+}
+
+; Negative test
+; TODO: assert that instsimplify always gets this?
+
+define i32 @add_smin_simplify(i32 %x) {
+; CHECK-LABEL: @add_smin_simplify(
+; CHECK-NEXT:    [[R:%.*]] = add nsw i32 [[X:%.*]], -3
+; CHECK-NEXT:    ret i32 [[R]]
+;
+  %a = add nsw i32 %x, -3
+  %c = icmp slt i32 %a, 2147483644
+  %r = select i1 %c, i32 %a, i32 2147483644
+  ret i32 %r
+}
+
+; Negative test
+; TODO: assert that instsimplify always gets this?
+
+define i32 @add_smin_simplify2(i32 %x) {
+; CHECK-LABEL: @add_smin_simplify2(
+; CHECK-NEXT:    [[A:%.*]] = add nsw i32 [[X:%.*]], -3
+; CHECK-NEXT:    ret i32 [[A]]
+;
+  %a = add nsw i32 %x, -3
+  %c = icmp slt i32 %a, 2147483645
+  %r = select i1 %c, i32 %a, i32 2147483645
+  ret i32 %r
+}
+
+; Negative test
+
+define i32 @add_smin_wrong_pred(i32 %x) {
+; CHECK-LABEL: @add_smin_wrong_pred(
+; CHECK-NEXT:    [[A:%.*]] = add nsw i32 [[X:%.*]], 15
+; CHECK-NEXT:    [[C:%.*]] = icmp ult i32 [[A]], 42
+; CHECK-NEXT:    [[R:%.*]] = select i1 [[C]], i32 [[A]], i32 42
+; CHECK-NEXT:    ret i32 [[R]]
+;
+  %a = add nsw i32 %x, 15
+  %c = icmp ult i32 %a, 42
+  %r = select i1 %c, i32 %a, i32 42
+  ret i32 %r
+}
+
+; Negative test
+
+define i32 @add_smin_wrong_wrap(i32 %x) {
+; CHECK-LABEL: @add_smin_wrong_wrap(
+; CHECK-NEXT:    [[A:%.*]] = add nuw i32 [[X:%.*]], 15
+; CHECK-NEXT:    [[C:%.*]] = icmp slt i32 [[A]], 42
+; CHECK-NEXT:    [[R:%.*]] = select i1 [[C]], i32 [[A]], i32 42
+; CHECK-NEXT:    ret i32 [[R]]
+;
+  %a = add nuw i32 %x, 15
+  %c = icmp slt i32 %a, 42
+  %r = select i1 %c, i32 %a, i32 42
+  ret i32 %r
+}
+
+; Negative test
+
+define i32 @add_smin_extra_use(i32 %x, i32* %p) {
+; CHECK-LABEL: @add_smin_extra_use(
+; CHECK-NEXT:    [[A:%.*]] = add nsw i32 [[X:%.*]], 15
+; CHECK-NEXT:    store i32 [[A]], i32* [[P:%.*]], align 4
+; CHECK-NEXT:    [[C:%.*]] = icmp slt i32 [[A]], 42
+; CHECK-NEXT:    [[R:%.*]] = select i1 [[C]], i32 [[A]], i32 42
+; CHECK-NEXT:    ret i32 [[R]]
+;
+  %a = add nsw i32 %x, 15
+  store i32 %a, i32* %p
+  %c = icmp slt i32 %a, 42
+  %r = select i1 %c, i32 %a, i32 42
+  ret i32 %r
+}
+
+define <2 x i16> @add_smin_vec(<2 x i16> %x) {
+; CHECK-LABEL: @add_smin_vec(
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp slt <2 x i16> [[X:%.*]], <i16 225, i16 225>
+; CHECK-NEXT:    [[TMP2:%.*]] = select <2 x i1> [[TMP1]], <2 x i16> [[X]], <2 x i16> <i16 225, i16 225>
+; CHECK-NEXT:    [[R:%.*]] = add nsw <2 x i16> [[TMP2]], <i16 15, i16 15>
+; CHECK-NEXT:    ret <2 x i16> [[R]]
+;
+  %a = add nsw <2 x i16> %x, <i16 15, i16 15>
+  %c = icmp slt <2 x i16> %a, <i16 240, i16 240>
+  %r = select <2 x i1> %c, <2 x i16> %a, <2 x i16> <i16 240, i16 240>
+  ret <2 x i16> %r
+}
+
+define i37 @add_smax(i37 %x) {
+; CHECK-LABEL: @add_smax(
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp sgt i37 [[X:%.*]], 37
+; CHECK-NEXT:    [[TMP2:%.*]] = select i1 [[TMP1]], i37 [[X]], i37 37
+; CHECK-NEXT:    [[R:%.*]] = add nuw nsw i37 [[TMP2]], 5
+; CHECK-NEXT:    ret i37 [[R]]
+;
+  %a = add nsw i37 %x, 5
+  %c = icmp sgt i37 %a, 42
+  %r = select i1 %c, i37 %a, i37 42
+  ret i37 %r
+}
+
+define i8 @add_smax_constant_limit(i8 %x) {
+; CHECK-LABEL: @add_smax_constant_limit(
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp sgt i8 [[X:%.*]], -127
+; CHECK-NEXT:    [[TMP2:%.*]] = select i1 [[TMP1]], i8 [[X]], i8 -127
+; CHECK-NEXT:    [[R:%.*]] = add nsw i8 [[TMP2]], 125
+; CHECK-NEXT:    ret i8 [[R]]
+;
+  %a = add nsw i8 %x, 125
+  %c = icmp sgt i8 %a, -2
+  %r = select i1 %c, i8 %a, i8 -2
+  ret i8 %r
+}
+
+; Negative test
+; TODO: assert that instsimplify always gets this?
+
+define i8 @add_smax_simplify(i8 %x) {
+; CHECK-LABEL: @add_smax_simplify(
+; CHECK-NEXT:    [[R:%.*]] = add nsw i8 [[X:%.*]], 126
+; CHECK-NEXT:    ret i8 [[R]]
+;
+  %a = add nsw i8 %x, 126
+  %c = icmp sgt i8 %a, -2
+  %r = select i1 %c, i8 %a, i8 -2
+  ret i8 %r
+}
+
+; Negative test
+; TODO: assert that instsimplify always gets this?
+
+define i8 @add_smax_simplify2(i8 %x) {
+; CHECK-LABEL: @add_smax_simplify2(
+; CHECK-NEXT:    [[A:%.*]] = add nsw i8 [[X:%.*]], 127
+; CHECK-NEXT:    ret i8 [[A]]
+;
+  %a = add nsw i8 %x, 127
+  %c = icmp sgt i8 %a, -2
+  %r = select i1 %c, i8 %a, i8 -2
+  ret i8 %r
+}
+
+; Negative test
+
+define i32 @add_smax_wrong_pred(i32 %x) {
+; CHECK-LABEL: @add_smax_wrong_pred(
+; CHECK-NEXT:    [[A:%.*]] = add nsw i32 [[X:%.*]], 15
+; CHECK-NEXT:    [[C:%.*]] = icmp ugt i32 [[A]], 42
+; CHECK-NEXT:    [[R:%.*]] = select i1 [[C]], i32 [[A]], i32 42
+; CHECK-NEXT:    ret i32 [[R]]
+;
+  %a = add nsw i32 %x, 15
+  %c = icmp ugt i32 %a, 42
+  %r = select i1 %c, i32 %a, i32 42
+  ret i32 %r
+}
+
+; Negative test
+
+define i32 @add_smax_wrong_wrap(i32 %x) {
+; CHECK-LABEL: @add_smax_wrong_wrap(
+; CHECK-NEXT:    [[A:%.*]] = add nuw i32 [[X:%.*]], 15
+; CHECK-NEXT:    [[C:%.*]] = icmp sgt i32 [[A]], 42
+; CHECK-NEXT:    [[R:%.*]] = select i1 [[C]], i32 [[A]], i32 42
+; CHECK-NEXT:    ret i32 [[R]]
+;
+  %a = add nuw i32 %x, 15
+  %c = icmp sgt i32 %a, 42
+  %r = select i1 %c, i32 %a, i32 42
+  ret i32 %r
+}
+
+; Negative test
+
+define i32 @add_smax_extra_use(i32 %x, i32* %p) {
+; CHECK-LABEL: @add_smax_extra_use(
+; CHECK-NEXT:    [[A:%.*]] = add nsw i32 [[X:%.*]], 15
+; CHECK-NEXT:    store i32 [[A]], i32* [[P:%.*]], align 4
+; CHECK-NEXT:    [[C:%.*]] = icmp sgt i32 [[A]], 42
+; CHECK-NEXT:    [[R:%.*]] = select i1 [[C]], i32 [[A]], i32 42
+; CHECK-NEXT:    ret i32 [[R]]
+;
+  %a = add nsw i32 %x, 15
+  store i32 %a, i32* %p
+  %c = icmp sgt i32 %a, 42
+  %r = select i1 %c, i32 %a, i32 42
+  ret i32 %r
+}
+
+define <2 x i33> @add_smax_vec(<2 x i33> %x) {
+; CHECK-LABEL: @add_smax_vec(
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp sgt <2 x i33> [[X:%.*]], <i33 235, i33 235>
+; CHECK-NEXT:    [[TMP2:%.*]] = select <2 x i1> [[TMP1]], <2 x i33> [[X]], <2 x i33> <i33 235, i33 235>
+; CHECK-NEXT:    [[R:%.*]] = add nuw nsw <2 x i33> [[TMP2]], <i33 5, i33 5>
+; CHECK-NEXT:    ret <2 x i33> [[R]]
+;
+  %a = add nsw <2 x i33> %x, <i33 5, i33 5>
+  %c = icmp sgt <2 x i33> %a, <i33 240, i33 240>
+  %r = select <2 x i1> %c, <2 x i33> %a, <2 x i33> <i33 240, i33 240>
+  ret <2 x i33> %r
+}
+
+define i8 @PR14613_smin(i8 %x) {
+; CHECK-LABEL: @PR14613_smin(
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp slt i8 [[X:%.*]], 40
+; CHECK-NEXT:    [[TMP2:%.*]] = select i1 [[TMP1]], i8 [[X]], i8 40
+; CHECK-NEXT:    [[U7:%.*]] = add nsw i8 [[TMP2]], 15
+; CHECK-NEXT:    ret i8 [[U7]]
+;
+  %u4 = sext i8 %x to i32
+  %u5 = add nuw nsw i32 %u4, 15
+  %u6 = icmp slt i32 %u5, 55
+  %u7 = select i1 %u6, i32 %u5, i32 55
+  %r = trunc i32 %u7 to i8
+  ret i8 %r
+}
+
+define i8 @PR14613_smax(i8 %x) {
+; CHECK-LABEL: @PR14613_smax(
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp sgt i8 [[X:%.*]], 40
+; CHECK-NEXT:    [[TMP2:%.*]] = select i1 [[TMP1]], i8 [[X]], i8 40
+; CHECK-NEXT:    [[U7:%.*]] = add nuw i8 [[TMP2]], 15
+; CHECK-NEXT:    ret i8 [[U7]]
+;
+  %u4 = sext i8 %x to i32
+  %u5 = add nuw nsw i32 %u4, 15
+  %u6 = icmp sgt i32 %u5, 55
+  %u7 = select i1 %u6, i32 %u5, i32 55
+  %r = trunc i32 %u7 to i8
+  ret i8 %r
+}

Added: llvm/trunk/test/Transforms/InstCombine/minmax-fp.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/minmax-fp.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/minmax-fp.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/minmax-fp.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,257 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt -S -instcombine < %s | FileCheck %s
+
+; This is the canonical form for a type-changing min/max.
+define double @t1(float %a) {
+; CHECK-LABEL: @t1(
+; CHECK-NEXT:    [[DOTINV:%.*]] = fcmp oge float [[A:%.*]], 5.000000e+00
+; CHECK-NEXT:    [[TMP1:%.*]] = select i1 [[DOTINV]], float 5.000000e+00, float [[A]]
+; CHECK-NEXT:    [[TMP2:%.*]] = fpext float [[TMP1]] to double
+; CHECK-NEXT:    ret double [[TMP2]]
+;
+  %1 = fcmp ult float %a, 5.0
+  %2 = select i1 %1, float %a, float 5.0
+  %3 = fpext float %2 to double
+  ret double %3
+}
+
+; Check this is converted into canonical form, as above.
+define double @t2(float %a) {
+; CHECK-LABEL: @t2(
+; CHECK-NEXT:    [[DOTINV:%.*]] = fcmp oge float [[A:%.*]], 5.000000e+00
+; CHECK-NEXT:    [[TMP1:%.*]] = select i1 [[DOTINV]], float 5.000000e+00, float [[A]]
+; CHECK-NEXT:    [[TMP2:%.*]] = fpext float [[TMP1]] to double
+; CHECK-NEXT:    ret double [[TMP2]]
+;
+  %1 = fcmp ult float %a, 5.0
+  %2 = fpext float %a to double
+  %3 = select i1 %1, double %2, double 5.0
+  ret double %3
+}
+
+; Same again, with trunc.
+define float @t4(double %a) {
+; CHECK-LABEL: @t4(
+; CHECK-NEXT:    [[DOTINV:%.*]] = fcmp oge double [[A:%.*]], 5.000000e+00
+; CHECK-NEXT:    [[TMP1:%.*]] = select i1 [[DOTINV]], double 5.000000e+00, double [[A]]
+; CHECK-NEXT:    [[TMP2:%.*]] = fptrunc double [[TMP1]] to float
+; CHECK-NEXT:    ret float [[TMP2]]
+;
+  %1 = fcmp ult double %a, 5.0
+  %2 = fptrunc double %a to float
+  %3 = select i1 %1, float %2, float 5.0
+  ret float %3
+}
+
+; different values, should not be converted.
+define double @t5(float %a) {
+; CHECK-LABEL: @t5(
+; CHECK-NEXT:    [[TMP1:%.*]] = fcmp ult float [[A:%.*]], 5.000000e+00
+; CHECK-NEXT:    [[TMP2:%.*]] = fpext float [[A]] to double
+; CHECK-NEXT:    [[TMP3:%.*]] = select i1 [[TMP1]], double [[TMP2]], double 5.001000e+00
+; CHECK-NEXT:    ret double [[TMP3]]
+;
+  %1 = fcmp ult float %a, 5.0
+  %2 = fpext float %a to double
+  %3 = select i1 %1, double %2, double 5.001
+  ret double %3
+}
+
+; From IEEE754: "Comparisons shall ignore the sign of zero (so +0 = -0)."
+; So the compare constant may be treated as +0.0, and we sink the fpext.
+
+define double @t6(float %a) {
+; CHECK-LABEL: @t6(
+; CHECK-NEXT:    [[DOTINV:%.*]] = fcmp oge float [[A:%.*]], 0.000000e+00
+; CHECK-NEXT:    [[TMP1:%.*]] = select i1 [[DOTINV]], float 0.000000e+00, float [[A]]
+; CHECK-NEXT:    [[TMP2:%.*]] = fpext float [[TMP1]] to double
+; CHECK-NEXT:    ret double [[TMP2]]
+;
+  %1 = fcmp ult float %a, -0.0
+  %2 = fpext float %a to double
+  %3 = select i1 %1, double %2, double 0.0
+  ret double %3
+}
+
+; From IEEE754: "Comparisons shall ignore the sign of zero (so +0 = -0)."
+; So the compare constant may be treated as -0.0, and we sink the fpext.
+
+define double @t7(float %a) {
+; CHECK-LABEL: @t7(
+; CHECK-NEXT:    [[DOTINV:%.*]] = fcmp oge float [[A:%.*]], 0.000000e+00
+; CHECK-NEXT:    [[TMP1:%.*]] = select i1 [[DOTINV]], float -0.000000e+00, float [[A]]
+; CHECK-NEXT:    [[TMP2:%.*]] = fpext float [[TMP1]] to double
+; CHECK-NEXT:    ret double [[TMP2]]
+;
+  %1 = fcmp ult float %a, 0.0
+  %2 = fpext float %a to double
+  %3 = select i1 %1, double %2, double -0.0
+  ret double %3
+}
+
+; min(min(x, 0.0), 0.0) --> min(x, 0.0)
+
+define float @fmin_fmin_zero_mismatch(float %x) {
+; CHECK-LABEL: @fmin_fmin_zero_mismatch(
+; CHECK-NEXT:    [[TMP1:%.*]] = fcmp olt float [[X:%.*]], 0.000000e+00
+; CHECK-NEXT:    [[MIN2:%.*]] = select i1 [[TMP1]], float [[X]], float 0.000000e+00
+; CHECK-NEXT:    ret float [[MIN2]]
+;
+  %cmp1 = fcmp olt float %x, -0.0
+  %min1 = select i1 %cmp1, float %x, float 0.0
+  %cmp2 = fcmp olt float %min1, 0.0
+  %min2 = select i1 %cmp2, float %min1, float 0.0
+  ret float %min2
+}
+
+; max(max(x, -0.0), -0.0) --> max(x, -0.0)
+
+define float @fmax_fmax_zero_mismatch(float %x) {
+; CHECK-LABEL: @fmax_fmax_zero_mismatch(
+; CHECK-NEXT:    [[TMP1:%.*]] = fcmp ogt float [[X:%.*]], -0.000000e+00
+; CHECK-NEXT:    [[MAX11:%.*]] = select i1 [[TMP1]], float [[X]], float -0.000000e+00
+; CHECK-NEXT:    ret float [[MAX11]]
+;
+  %cmp1 = fcmp ogt float %x, 0.0
+  %max1 = select i1 %cmp1, float %x, float -0.0
+  %cmp2 = fcmp ogt float 0.0, %max1
+  %max2 = select i1 %cmp2, float -0.0, float %max1
+  ret float %max2
+}
+
+define i64 @t8(float %a) {
+; CHECK-LABEL: @t8(
+; CHECK-NEXT:    [[DOTINV:%.*]] = fcmp oge float [[A:%.*]], 5.000000e+00
+; CHECK-NEXT:    [[TMP1:%.*]] = select i1 [[DOTINV]], float 5.000000e+00, float [[A]]
+; CHECK-NEXT:    [[TMP2:%.*]] = fptoui float [[TMP1]] to i64
+; CHECK-NEXT:    ret i64 [[TMP2]]
+;
+  %1 = fcmp ult float %a, 5.0
+  %2 = fptoui float %a to i64
+  %3 = select i1 %1, i64 %2, i64 5
+  ret i64 %3
+}
+
+define i8 @t9(float %a) {
+; CHECK-LABEL: @t9(
+; CHECK-NEXT:    [[DOTINV:%.*]] = fcmp oge float [[A:%.*]], 0.000000e+00
+; CHECK-NEXT:    [[TMP1:%.*]] = select i1 [[DOTINV]], float 0.000000e+00, float [[A]]
+; CHECK-NEXT:    [[TMP2:%.*]] = fptosi float [[TMP1]] to i8
+; CHECK-NEXT:    ret i8 [[TMP2]]
+;
+  %1 = fcmp ult float %a, 0.0
+  %2 = fptosi float %a to i8
+  %3 = select i1 %1, i8 %2, i8 0
+  ret i8 %3
+}
+
+  ; Either operand could be NaN, but fast modifier applied.
+define i8 @t11(float %a, float %b) {
+; CHECK-LABEL: @t11(
+; CHECK-NEXT:    [[DOTINV:%.*]] = fcmp fast oge float [[B:%.*]], [[A:%.*]]
+; CHECK-NEXT:    [[DOTV:%.*]] = select i1 [[DOTINV]], float [[A]], float [[B]]
+; CHECK-NEXT:    [[TMP1:%.*]] = fptosi float [[DOTV]] to i8
+; CHECK-NEXT:    ret i8 [[TMP1]]
+;
+  %1 = fcmp fast ult float %b, %a
+  %2 = fptosi float %a to i8
+  %3 = fptosi float %b to i8
+  %4 = select i1 %1, i8 %3, i8 %2
+  ret i8 %4
+}
+
+; Either operand could be NaN, but nnan modifier applied.
+define i8 @t12(float %a, float %b) {
+; CHECK-LABEL: @t12(
+; CHECK-NEXT:    [[DOTINV:%.*]] = fcmp nnan oge float [[B:%.*]], [[A:%.*]]
+; CHECK-NEXT:    [[DOTV:%.*]] = select i1 [[DOTINV]], float [[A]], float [[B]]
+; CHECK-NEXT:    [[TMP1:%.*]] = fptosi float [[DOTV]] to i8
+; CHECK-NEXT:    ret i8 [[TMP1]]
+;
+  %1 = fcmp nnan ult float %b, %a
+  %2 = fptosi float %a to i8
+  %3 = fptosi float %b to i8
+  %4 = select i1 %1, i8 %3, i8 %2
+  ret i8 %4
+}
+
+; Float and int values do not match.
+define i8 @t13(float %a) {
+; CHECK-LABEL: @t13(
+; CHECK-NEXT:    [[TMP1:%.*]] = fcmp ult float [[A:%.*]], 1.500000e+00
+; CHECK-NEXT:    [[TMP2:%.*]] = fptosi float [[A]] to i8
+; CHECK-NEXT:    [[TMP3:%.*]] = select i1 [[TMP1]], i8 [[TMP2]], i8 1
+; CHECK-NEXT:    ret i8 [[TMP3]]
+;
+  %1 = fcmp ult float %a, 1.5
+  %2 = fptosi float %a to i8
+  %3 = select i1 %1, i8 %2, i8 1
+  ret i8 %3
+}
+
+; %a could be -0.0, but it doesn't matter because the conversion to int is the same for 0.0 or -0.0.
+define i8 @t14(float %a) {
+; CHECK-LABEL: @t14(
+; CHECK-NEXT:    [[DOTINV:%.*]] = fcmp oge float [[A:%.*]], 0.000000e+00
+; CHECK-NEXT:    [[TMP1:%.*]] = select i1 [[DOTINV]], float 0.000000e+00, float [[A]]
+; CHECK-NEXT:    [[TMP2:%.*]] = fptosi float [[TMP1]] to i8
+; CHECK-NEXT:    ret i8 [[TMP2]]
+;
+  %1 = fcmp ule float %a, 0.0
+  %2 = fptosi float %a to i8
+  %3 = select i1 %1, i8 %2, i8 0
+  ret i8 %3
+}
+
+define i8 @t14_commute(float %a) {
+; CHECK-LABEL: @t14_commute(
+; CHECK-NEXT:    [[TMP1:%.*]] = fcmp ogt float [[A:%.*]], 0.000000e+00
+; CHECK-NEXT:    [[TMP2:%.*]] = select i1 [[TMP1]], float [[A]], float 0.000000e+00
+; CHECK-NEXT:    [[TMP3:%.*]] = fptosi float [[TMP2]] to i8
+; CHECK-NEXT:    ret i8 [[TMP3]]
+;
+  %1 = fcmp ule float %a, 0.0
+  %2 = fptosi float %a to i8
+  %3 = select i1 %1, i8 0, i8 %2
+  ret i8 %3
+}
+
+define i8 @t15(float %a) {
+; CHECK-LABEL: @t15(
+; CHECK-NEXT:    [[DOTINV:%.*]] = fcmp nsz oge float [[A:%.*]], 0.000000e+00
+; CHECK-NEXT:    [[TMP1:%.*]] = select i1 [[DOTINV]], float 0.000000e+00, float [[A]]
+; CHECK-NEXT:    [[TMP2:%.*]] = fptosi float [[TMP1]] to i8
+; CHECK-NEXT:    ret i8 [[TMP2]]
+;
+  %1 = fcmp nsz ule float %a, 0.0
+  %2 = fptosi float %a to i8
+  %3 = select i1 %1, i8 %2, i8 0
+  ret i8 %3
+}
+
+define double @t16(i32 %x) {
+; CHECK-LABEL: @t16(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt i32 [[X:%.*]], 0
+; CHECK-NEXT:    [[CST:%.*]] = sitofp i32 [[X]] to double
+; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[CMP]], double [[CST]], double 5.000000e-01
+; CHECK-NEXT:    ret double [[SEL]]
+;
+  %cmp = icmp sgt i32 %x, 0
+  %cst = sitofp i32 %x to double
+  %sel = select i1 %cmp, double %cst, double 5.000000e-01
+  ret double %sel
+}
+
+define double @t17(i32 %x) {
+; CHECK-LABEL: @t17(
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp sgt i32 [[X:%.*]], 2
+; CHECK-NEXT:    [[SEL1:%.*]] = select i1 [[TMP1]], i32 [[X]], i32 2
+; CHECK-NEXT:    [[TMP2:%.*]] = sitofp i32 [[SEL1]] to double
+; CHECK-NEXT:    ret double [[TMP2]]
+;
+  %cmp = icmp sgt i32 %x, 2
+  %cst = sitofp i32 %x to double
+  %sel = select i1 %cmp, double %cst, double 2.0
+  ret double %sel
+}
+

Added: llvm/trunk/test/Transforms/InstCombine/minnum.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/minnum.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/minnum.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/minnum.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,318 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt -S -instcombine < %s | FileCheck %s
+
+declare float @llvm.minnum.f32(float, float)
+declare <2 x float> @llvm.minnum.v2f32(<2 x float>, <2 x float>)
+declare <4 x float> @llvm.minnum.v4f32(<4 x float>, <4 x float>)
+
+declare double @llvm.minnum.f64(double, double)
+declare <2 x double> @llvm.minnum.v2f64(<2 x double>, <2 x double>)
+
+declare float @llvm.maxnum.f32(float, float)
+
+define float @constant_fold_minnum_f32() {
+; CHECK-LABEL: @constant_fold_minnum_f32(
+; CHECK-NEXT:    ret float 1.000000e+00
+;
+  %x = call float @llvm.minnum.f32(float 1.0, float 2.0)
+  ret float %x
+}
+
+define float @constant_fold_minnum_f32_inv() {
+; CHECK-LABEL: @constant_fold_minnum_f32_inv(
+; CHECK-NEXT:    ret float 1.000000e+00
+;
+  %x = call float @llvm.minnum.f32(float 2.0, float 1.0)
+  ret float %x
+}
+
+define float @constant_fold_minnum_f32_nan0() {
+; CHECK-LABEL: @constant_fold_minnum_f32_nan0(
+; CHECK-NEXT:    ret float 2.000000e+00
+;
+  %x = call float @llvm.minnum.f32(float 0x7FF8000000000000, float 2.0)
+  ret float %x
+}
+
+define float @constant_fold_minnum_f32_nan1() {
+; CHECK-LABEL: @constant_fold_minnum_f32_nan1(
+; CHECK-NEXT:    ret float 2.000000e+00
+;
+  %x = call float @llvm.minnum.f32(float 2.0, float 0x7FF8000000000000)
+  ret float %x
+}
+
+define float @constant_fold_minnum_f32_nan_nan() {
+; CHECK-LABEL: @constant_fold_minnum_f32_nan_nan(
+; CHECK-NEXT:    ret float 0x7FF8000000000000
+;
+  %x = call float @llvm.minnum.f32(float 0x7FF8000000000000, float 0x7FF8000000000000)
+  ret float %x
+}
+
+define float @constant_fold_minnum_f32_p0_p0() {
+; CHECK-LABEL: @constant_fold_minnum_f32_p0_p0(
+; CHECK-NEXT:    ret float 0.000000e+00
+;
+  %x = call float @llvm.minnum.f32(float 0.0, float 0.0)
+  ret float %x
+}
+
+define float @constant_fold_minnum_f32_p0_n0() {
+; CHECK-LABEL: @constant_fold_minnum_f32_p0_n0(
+; CHECK-NEXT:    ret float 0.000000e+00
+;
+  %x = call float @llvm.minnum.f32(float 0.0, float -0.0)
+  ret float %x
+}
+
+define float @constant_fold_minnum_f32_n0_p0() {
+; CHECK-LABEL: @constant_fold_minnum_f32_n0_p0(
+; CHECK-NEXT:    ret float -0.000000e+00
+;
+  %x = call float @llvm.minnum.f32(float -0.0, float 0.0)
+  ret float %x
+}
+
+define float @constant_fold_minnum_f32_n0_n0() {
+; CHECK-LABEL: @constant_fold_minnum_f32_n0_n0(
+; CHECK-NEXT:    ret float -0.000000e+00
+;
+  %x = call float @llvm.minnum.f32(float -0.0, float -0.0)
+  ret float %x
+}
+
+define <4 x float> @constant_fold_minnum_v4f32() {
+; CHECK-LABEL: @constant_fold_minnum_v4f32(
+; CHECK-NEXT:    ret <4 x float> <float 1.000000e+00, float 2.000000e+00, float 3.000000e+00, float 5.000000e+00>
+;
+  %x = call <4 x float> @llvm.minnum.v4f32(<4 x float> <float 1.0, float 8.0, float 3.0, float 9.0>, <4 x float> <float 2.0, float 2.0, float 10.0, float 5.0>)
+  ret <4 x float> %x
+}
+
+define double @constant_fold_minnum_f64() {
+; CHECK-LABEL: @constant_fold_minnum_f64(
+; CHECK-NEXT:    ret double 1.000000e+00
+;
+  %x = call double @llvm.minnum.f64(double 1.0, double 2.0)
+  ret double %x
+}
+
+define double @constant_fold_minnum_f64_nan0() {
+; CHECK-LABEL: @constant_fold_minnum_f64_nan0(
+; CHECK-NEXT:    ret double 2.000000e+00
+;
+  %x = call double @llvm.minnum.f64(double 0x7FF8000000000000, double 2.0)
+  ret double %x
+}
+
+define double @constant_fold_minnum_f64_nan1() {
+; CHECK-LABEL: @constant_fold_minnum_f64_nan1(
+; CHECK-NEXT:    ret double 2.000000e+00
+;
+  %x = call double @llvm.minnum.f64(double 2.0, double 0x7FF8000000000000)
+  ret double %x
+}
+
+define double @constant_fold_minnum_f64_nan_nan() {
+; CHECK-LABEL: @constant_fold_minnum_f64_nan_nan(
+; CHECK-NEXT:    ret double 0x7FF8000000000000
+;
+  %x = call double @llvm.minnum.f64(double 0x7FF8000000000000, double 0x7FF8000000000000)
+  ret double %x
+}
+
+define float @canonicalize_constant_minnum_f32(float %x) {
+; CHECK-LABEL: @canonicalize_constant_minnum_f32(
+; CHECK-NEXT:    [[Y:%.*]] = call float @llvm.minnum.f32(float [[X:%.*]], float 1.000000e+00)
+; CHECK-NEXT:    ret float [[Y]]
+;
+  %y = call float @llvm.minnum.f32(float 1.0, float %x)
+  ret float %y
+}
+
+define float @minnum_f32_nan_val(float %x) {
+; CHECK-LABEL: @minnum_f32_nan_val(
+; CHECK-NEXT:    ret float [[X:%.*]]
+;
+  %y = call float @llvm.minnum.f32(float 0x7FF8000000000000, float %x)
+  ret float %y
+}
+
+define float @minnum_f32_val_nan(float %x) {
+; CHECK-LABEL: @minnum_f32_val_nan(
+; CHECK-NEXT:    ret float [[X:%.*]]
+;
+  %y = call float @llvm.minnum.f32(float %x, float 0x7FF8000000000000)
+  ret float %y
+}
+
+define float @minnum_f32_1_minnum_val_p0(float %x) {
+; CHECK-LABEL: @minnum_f32_1_minnum_val_p0(
+; CHECK-NEXT: [[RES:%.*]] = call float @llvm.minnum.f32(float %x, float 0.000000e+00)
+; CHECK-NEXT: ret float [[RES]]
+  %y = call float @llvm.minnum.f32(float %x, float 0.0)
+  %z = call float @llvm.minnum.f32(float %y, float 1.0)
+  ret float %z
+}
+
+define float @minnum_f32_1_minnum_p0_val_fast(float %x) {
+; CHECK-LABEL: @minnum_f32_1_minnum_p0_val_fast(
+; CHECK-NEXT: [[RES:%.*]] = call fast float @llvm.minnum.f32(float %x, float 0.000000e+00)
+; CHECK-NEXT: ret float [[RES]]
+  %y = call float @llvm.minnum.f32(float 0.0, float %x)
+  %z = call fast float @llvm.minnum.f32(float %y, float 1.0)
+  ret float %z
+}
+
+define float @minnum_f32_1_minnum_p0_val_nnan_ninf(float %x) {
+; CHECK-LABEL: @minnum_f32_1_minnum_p0_val_nnan_ninf(
+; CHECK-NEXT: [[RES:%.*]] = call nnan ninf float @llvm.minnum.f32(float %x, float 0.000000e+00)
+; CHECK-NEXT: ret float [[RES]]
+  %y = call float @llvm.minnum.f32(float 0.0, float %x)
+  %z = call nnan ninf float @llvm.minnum.f32(float %y, float 1.0)
+  ret float %z
+}
+
+define float @minnum_f32_p0_minnum_val_n0(float %x) {
+; CHECK-LABEL: @minnum_f32_p0_minnum_val_n0(
+; CHECK-NEXT: [[RES:%.*]] = call float @llvm.minnum.f32(float %x, float 0.000000e+00)
+; CHECK-NEXT: ret float [[RES]]
+  %y = call float @llvm.minnum.f32(float %x, float -0.0)
+  %z = call float @llvm.minnum.f32(float %y, float 0.0)
+  ret float %z
+}
+
+define float @minnum_f32_1_minnum_p0_val(float %x) {
+; CHECK-LABEL: @minnum_f32_1_minnum_p0_val(
+; CHECK-NEXT: [[RES:%.*]] = call float @llvm.minnum.f32(float %x, float 0.000000e+00)
+; CHECK-NEXT: ret float [[RES]]
+  %y = call float @llvm.minnum.f32(float 0.0, float %x)
+  %z = call float @llvm.minnum.f32(float %y, float 1.0)
+  ret float %z
+}
+
+define <2 x float> @minnum_f32_1_minnum_val_p0_val_v2f32(<2 x float> %x) {
+; CHECK-LABEL: @minnum_f32_1_minnum_val_p0_val_v2f32(
+; CHECK-NEXT: [[RES:%.*]] = call <2 x float> @llvm.minnum.v2f32(<2 x float> %x, <2 x float> zeroinitializer)
+; CHECK-NEXT: ret <2 x float> [[RES]]
+  %y = call <2 x float> @llvm.minnum.v2f32(<2 x float> %x, <2 x float> zeroinitializer)
+  %z = call <2 x float> @llvm.minnum.v2f32(<2 x float> %y, <2 x float><float 1.0, float 1.0>)
+  ret <2 x float> %z
+}
+
+define float @minnum4(float %x, float %y, float %z, float %w) {
+; CHECK-LABEL: @minnum4(
+; CHECK-NEXT:    [[A:%.*]] = call float @llvm.minnum.f32(float [[X:%.*]], float [[Y:%.*]])
+; CHECK-NEXT:    [[B:%.*]] = call float @llvm.minnum.f32(float [[Z:%.*]], float [[W:%.*]])
+; CHECK-NEXT:    [[C:%.*]] = call float @llvm.minnum.f32(float [[A]], float [[B]])
+; CHECK-NEXT:    ret float [[C]]
+;
+  %a = call float @llvm.minnum.f32(float %x, float %y)
+  %b = call float @llvm.minnum.f32(float %z, float %w)
+  %c = call float @llvm.minnum.f32(float %a, float %b)
+  ret float %c
+}
+
+define float @minnum_x_maxnum_x_y(float %x, float %y) {
+; CHECK-LABEL: @minnum_x_maxnum_x_y(
+; CHECK-NEXT:    [[A:%.*]] = call float @llvm.maxnum.f32(float [[X:%.*]], float [[Y:%.*]])
+; CHECK-NEXT:    [[B:%.*]] = call float @llvm.minnum.f32(float [[X]], float [[A]])
+; CHECK-NEXT:    ret float [[B]]
+;
+  %a = call float @llvm.maxnum.f32(float %x, float %y)
+  %b = call float @llvm.minnum.f32(float %x, float %a)
+  ret float %b
+}
+
+define float @maxnum_x_minnum_x_y(float %x, float %y) {
+; CHECK-LABEL: @maxnum_x_minnum_x_y(
+; CHECK-NEXT:    [[A:%.*]] = call float @llvm.minnum.f32(float [[X:%.*]], float [[Y:%.*]])
+; CHECK-NEXT:    [[B:%.*]] = call float @llvm.maxnum.f32(float [[X]], float [[A]])
+; CHECK-NEXT:    ret float [[B]]
+;
+  %a = call float @llvm.minnum.f32(float %x, float %y)
+  %b = call float @llvm.maxnum.f32(float %x, float %a)
+  ret float %b
+}
+
+; PR37405 - https://bugs.llvm.org/show_bug.cgi?id=37405
+
+define double @neg_neg(double %x, double %y) {
+; CHECK-LABEL: @neg_neg(
+; CHECK-NEXT:    [[TMP1:%.*]] = call double @llvm.maxnum.f64(double [[X:%.*]], double [[Y:%.*]])
+; CHECK-NEXT:    [[R:%.*]] = fsub double -0.000000e+00, [[TMP1]]
+; CHECK-NEXT:    ret double [[R]]
+;
+  %negx = fsub double -0.0, %x
+  %negy = fsub double -0.0, %y
+  %r = call double @llvm.minnum.f64(double %negx, double %negy)
+  ret double %r
+}
+
+; FMF is not required, but it should be propagated from the intrinsic (not the fnegs).
+; Also, make sure this works with vectors.
+
+define <2 x double> @neg_neg_vec_fmf(<2 x double> %x, <2 x double> %y) {
+; CHECK-LABEL: @neg_neg_vec_fmf(
+; CHECK-NEXT:    [[TMP1:%.*]] = call nnan ninf <2 x double> @llvm.maxnum.v2f64(<2 x double> [[X:%.*]], <2 x double> [[Y:%.*]])
+; CHECK-NEXT:    [[R:%.*]] = fsub nnan ninf <2 x double> <double -0.000000e+00, double -0.000000e+00>, [[TMP1]]
+; CHECK-NEXT:    ret <2 x double> [[R]]
+;
+  %negx = fsub reassoc <2 x double> <double -0.0, double -0.0>, %x
+  %negy = fsub fast <2 x double> <double -0.0, double -0.0>, %y
+  %r = call nnan ninf <2 x double> @llvm.minnum.v2f64(<2 x double> %negx, <2 x double> %negy)
+  ret <2 x double> %r
+}
+
+; 1 extra use of an intermediate value should still allow the fold,
+; but 2 would require more instructions than we started with.
+
+declare void @use(double)
+define double @neg_neg_extra_use_x(double %x, double %y) {
+; CHECK-LABEL: @neg_neg_extra_use_x(
+; CHECK-NEXT:    [[NEGX:%.*]] = fsub double -0.000000e+00, [[X:%.*]]
+; CHECK-NEXT:    [[TMP1:%.*]] = call double @llvm.maxnum.f64(double [[X]], double [[Y:%.*]])
+; CHECK-NEXT:    [[R:%.*]] = fsub double -0.000000e+00, [[TMP1]]
+; CHECK-NEXT:    call void @use(double [[NEGX]])
+; CHECK-NEXT:    ret double [[R]]
+;
+  %negx = fsub double -0.0, %x
+  %negy = fsub double -0.0, %y
+  %r = call double @llvm.minnum.f64(double %negx, double %negy)
+  call void @use(double %negx)
+  ret double %r
+}
+
+define double @neg_neg_extra_use_y(double %x, double %y) {
+; CHECK-LABEL: @neg_neg_extra_use_y(
+; CHECK-NEXT:    [[NEGY:%.*]] = fsub double -0.000000e+00, [[Y:%.*]]
+; CHECK-NEXT:    [[TMP1:%.*]] = call double @llvm.maxnum.f64(double [[X:%.*]], double [[Y]])
+; CHECK-NEXT:    [[R:%.*]] = fsub double -0.000000e+00, [[TMP1]]
+; CHECK-NEXT:    call void @use(double [[NEGY]])
+; CHECK-NEXT:    ret double [[R]]
+;
+  %negx = fsub double -0.0, %x
+  %negy = fsub double -0.0, %y
+  %r = call double @llvm.minnum.f64(double %negx, double %negy)
+  call void @use(double %negy)
+  ret double %r
+}
+
+define double @neg_neg_extra_use_x_and_y(double %x, double %y) {
+; CHECK-LABEL: @neg_neg_extra_use_x_and_y(
+; CHECK-NEXT:    [[NEGX:%.*]] = fsub double -0.000000e+00, [[X:%.*]]
+; CHECK-NEXT:    [[NEGY:%.*]] = fsub double -0.000000e+00, [[Y:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = call double @llvm.minnum.f64(double [[NEGX]], double [[NEGY]])
+; CHECK-NEXT:    call void @use(double [[NEGX]])
+; CHECK-NEXT:    call void @use(double [[NEGY]])
+; CHECK-NEXT:    ret double [[R]]
+;
+  %negx = fsub double -0.0, %x
+  %negy = fsub double -0.0, %y
+  %r = call double @llvm.minnum.f64(double %negx, double %negy)
+  call void @use(double %negx)
+  call void @use(double %negy)
+  ret double %r
+}
+

Added: llvm/trunk/test/Transforms/InstCombine/misc-2002.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/misc-2002.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/misc-2002.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/misc-2002.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,50 @@
+; NOTE: Assertions have been autogenerated by update_test_checks.py
+; RUN: opt < %s -instcombine -S | FileCheck %s
+
+define void @hang_2002-03-11(i32 %X) {
+; CHECK-LABEL: @hang_2002-03-11(
+; CHECK-NEXT:    ret void
+;
+  %reg117 = add i32 %X, 0
+  ret void
+}
+
+; Instcombine was missing a test that caused it to make illegal transformations
+; sometimes. In this case, it transformed the sub into an add:
+
+define i32 @sub_failure_2002-05-14(i32 %i, i32 %j) {
+; CHECK-LABEL: @sub_failure_2002-05-14(
+; CHECK-NEXT:    [[A:%.*]] = mul i32 %i, %j
+; CHECK-NEXT:    [[B:%.*]] = sub i32 2, [[A]]
+; CHECK-NEXT:    ret i32 [[B]]
+;
+  %A = mul i32 %i, %j
+  %B = sub i32 2, %A
+  ret i32 %B
+}
+
+; This testcase was incorrectly getting completely eliminated. There should be
+; SOME instruction named %c here, even if it's a bitwise and.
+
+define i64 @cast_test_2002-08-02(i64 %A) {
+; CHECK-LABEL: @cast_test_2002-08-02(
+; CHECK-NEXT:    [[C2:%.*]] = and i64 %A, 255
+; CHECK-NEXT:    ret i64 [[C2]]
+;
+  %c1 = trunc i64 %A to i8
+  %c2 = zext i8 %c1 to i64
+  ret i64 %c2
+}
+
+define i32 @missed_const_prop_2002-12-05(i32 %A) {
+; CHECK-LABEL: @missed_const_prop_2002-12-05(
+; CHECK-NEXT:    ret i32 0
+;
+  %A.neg = sub i32 0, %A
+  %.neg = sub i32 0, 1
+  %X = add i32 %.neg, 1
+  %Y.neg.ra = add i32 %A, %X
+  %r = add i32 %A.neg, %Y.neg.ra
+  ret i32 %r
+}
+

Added: llvm/trunk/test/Transforms/InstCombine/mul-masked-bits.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/mul-masked-bits.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/mul-masked-bits.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/mul-masked-bits.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,19 @@
+; NOTE: Assertions have been autogenerated by update_test_checks.py
+; RUN: opt < %s -instcombine -S | FileCheck %s
+
+define i32 @foo(i32 %x, i32 %y) {
+; CHECK-LABEL: @foo(
+; CHECK-NEXT:    [[A:%.*]] = and i32 %x, 7
+; CHECK-NEXT:    [[B:%.*]] = and i32 %y, 7
+; CHECK-NEXT:    [[C:%.*]] = mul nuw nsw i32 [[A]], [[B]]
+; CHECK-NEXT:    [[D:%.*]] = shl nuw i32 [[C]], 26
+; CHECK-NEXT:    [[E:%.*]] = ashr exact i32 [[D]], 26
+; CHECK-NEXT:    ret i32 [[E]]
+;
+  %a = and i32 %x, 7
+  %b = and i32 %y, 7
+  %c = mul i32 %a, %b
+  %d = shl i32 %c, 26
+  %e = ashr i32 %d, 26
+  ret i32 %e
+}

Added: llvm/trunk/test/Transforms/InstCombine/mul.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/mul.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/mul.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/mul.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,519 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt < %s -instcombine -S | FileCheck %s
+
+define i32 @pow2_multiplier(i32 %A) {
+; CHECK-LABEL: @pow2_multiplier(
+; CHECK-NEXT:    [[B:%.*]] = shl i32 [[A:%.*]], 1
+; CHECK-NEXT:    ret i32 [[B]]
+;
+  %B = mul i32 %A, 2
+  ret i32 %B
+}
+
+define <2 x i32> @pow2_multiplier_vec(<2 x i32> %A) {
+; CHECK-LABEL: @pow2_multiplier_vec(
+; CHECK-NEXT:    [[B:%.*]] = shl <2 x i32> [[A:%.*]], <i32 3, i32 3>
+; CHECK-NEXT:    ret <2 x i32> [[B]]
+;
+  %B = mul <2 x i32> %A, <i32 8, i32 8>
+  ret <2 x i32> %B
+}
+
+define i8 @combine_shl(i8 %A) {
+; CHECK-LABEL: @combine_shl(
+; CHECK-NEXT:    [[C:%.*]] = shl i8 [[A:%.*]], 6
+; CHECK-NEXT:    ret i8 [[C]]
+;
+  %B = mul i8 %A, 8
+  %C = mul i8 %B, 8
+  ret i8 %C
+}
+
+define i32 @neg(i32 %i) {
+; CHECK-LABEL: @neg(
+; CHECK-NEXT:    [[TMP:%.*]] = sub i32 0, [[I:%.*]]
+; CHECK-NEXT:    ret i32 [[TMP]]
+;
+  %tmp = mul i32 %i, -1
+  ret i32 %tmp
+}
+
+; Use the sign-bit as a mask:
+; (zext (A < 0)) * B --> (A >> 31) & B
+
+define i32 @test10(i32 %a, i32 %b) {
+; CHECK-LABEL: @test10(
+; CHECK-NEXT:    [[TMP1:%.*]] = ashr i32 [[A:%.*]], 31
+; CHECK-NEXT:    [[E:%.*]] = and i32 [[TMP1]], [[B:%.*]]
+; CHECK-NEXT:    ret i32 [[E]]
+;
+  %c = icmp slt i32 %a, 0
+  %d = zext i1 %c to i32
+  %e = mul i32 %d, %b
+  ret i32 %e
+}
+
+define i32 @test11(i32 %a, i32 %b) {
+; CHECK-LABEL: @test11(
+; CHECK-NEXT:    [[TMP1:%.*]] = ashr i32 [[A:%.*]], 31
+; CHECK-NEXT:    [[E:%.*]] = and i32 [[TMP1]], [[B:%.*]]
+; CHECK-NEXT:    ret i32 [[E]]
+;
+  %c = icmp sle i32 %a, -1
+  %d = zext i1 %c to i32
+  %e = mul i32 %d, %b
+  ret i32 %e
+}
+
+declare void @use32(i32)
+
+define i32 @test12(i32 %a, i32 %b) {
+; CHECK-LABEL: @test12(
+; CHECK-NEXT:    [[A_LOBIT:%.*]] = lshr i32 [[A:%.*]], 31
+; CHECK-NEXT:    [[TMP1:%.*]] = ashr i32 [[A]], 31
+; CHECK-NEXT:    [[E:%.*]] = and i32 [[TMP1]], [[B:%.*]]
+; CHECK-NEXT:    call void @use32(i32 [[A_LOBIT]])
+; CHECK-NEXT:    ret i32 [[E]]
+;
+  %c = icmp ugt i32 %a, 2147483647
+  %d = zext i1 %c to i32
+  %e = mul i32 %d, %b
+  call void @use32(i32 %d)
+  ret i32 %e
+}
+
+; rdar://7293527
+define i32 @test15(i32 %A, i32 %B) {
+; CHECK-LABEL: @test15(
+; CHECK-NEXT:    [[M:%.*]] = shl i32 [[A:%.*]], [[B:%.*]]
+; CHECK-NEXT:    ret i32 [[M]]
+;
+  %shl = shl i32 1, %B
+  %m = mul i32 %shl, %A
+  ret i32 %m
+}
+
+; X * Y (when Y is a boolean) --> Y ? X : 0
+
+define i32 @mul_bool(i32 %x, i1 %y) {
+; CHECK-LABEL: @mul_bool(
+; CHECK-NEXT:    [[M:%.*]] = select i1 [[Y:%.*]], i32 [[X:%.*]], i32 0
+; CHECK-NEXT:    ret i32 [[M]]
+;
+  %z = zext i1 %y to i32
+  %m = mul i32 %x, %z
+  ret i32 %m
+}
+
+; Commute and test vector type.
+
+define <2 x i32> @mul_bool_vec(<2 x i32> %x, <2 x i1> %y) {
+; CHECK-LABEL: @mul_bool_vec(
+; CHECK-NEXT:    [[M:%.*]] = select <2 x i1> [[Y:%.*]], <2 x i32> [[X:%.*]], <2 x i32> zeroinitializer
+; CHECK-NEXT:    ret <2 x i32> [[M]]
+;
+  %z = zext <2 x i1> %y to <2 x i32>
+  %m = mul <2 x i32> %x, %z
+  ret <2 x i32> %m
+}
+
+define <2 x i32> @mul_bool_vec_commute(<2 x i32> %x, <2 x i1> %y) {
+; CHECK-LABEL: @mul_bool_vec_commute(
+; CHECK-NEXT:    [[M:%.*]] = select <2 x i1> [[Y:%.*]], <2 x i32> [[X:%.*]], <2 x i32> zeroinitializer
+; CHECK-NEXT:    ret <2 x i32> [[M]]
+;
+  %z = zext <2 x i1> %y to <2 x i32>
+  %m = mul <2 x i32> %z, %x
+  ret <2 x i32> %m
+}
+
+; (A >>u 31) * B --> (A >>s 31) & B
+
+define i32 @signbit_mul(i32 %a, i32 %b) {
+; CHECK-LABEL: @signbit_mul(
+; CHECK-NEXT:    [[TMP1:%.*]] = ashr i32 [[A:%.*]], 31
+; CHECK-NEXT:    [[E:%.*]] = and i32 [[TMP1]], [[B:%.*]]
+; CHECK-NEXT:    ret i32 [[E]]
+;
+  %d = lshr i32 %a, 31
+  %e = mul i32 %d, %b
+  ret i32 %e
+}
+
+define i32 @signbit_mul_commute_extra_use(i32 %a, i32 %b) {
+; CHECK-LABEL: @signbit_mul_commute_extra_use(
+; CHECK-NEXT:    [[D:%.*]] = lshr i32 [[A:%.*]], 31
+; CHECK-NEXT:    [[TMP1:%.*]] = ashr i32 [[A]], 31
+; CHECK-NEXT:    [[E:%.*]] = and i32 [[TMP1]], [[B:%.*]]
+; CHECK-NEXT:    call void @use32(i32 [[D]])
+; CHECK-NEXT:    ret i32 [[E]]
+;
+  %d = lshr i32 %a, 31
+  %e = mul i32 %b, %d
+  call void @use32(i32 %d)
+  ret i32 %e
+}
+
+; (A >>u 31)) * B --> (A >>s 31) & B
+
+define <2 x i32> @signbit_mul_vec(<2 x i32> %a, <2 x i32> %b) {
+; CHECK-LABEL: @signbit_mul_vec(
+; CHECK-NEXT:    [[TMP1:%.*]] = ashr <2 x i32> [[A:%.*]], <i32 31, i32 31>
+; CHECK-NEXT:    [[E:%.*]] = and <2 x i32> [[TMP1]], [[B:%.*]]
+; CHECK-NEXT:    ret <2 x i32> [[E]]
+;
+  %d = lshr <2 x i32> %a, <i32 31, i32 31>
+  %e = mul <2 x i32> %d, %b
+  ret <2 x i32> %e
+}
+
+define <2 x i32> @signbit_mul_vec_commute(<2 x i32> %a, <2 x i32> %b) {
+; CHECK-LABEL: @signbit_mul_vec_commute(
+; CHECK-NEXT:    [[TMP1:%.*]] = ashr <2 x i32> [[A:%.*]], <i32 31, i32 31>
+; CHECK-NEXT:    [[E:%.*]] = and <2 x i32> [[TMP1]], [[B:%.*]]
+; CHECK-NEXT:    ret <2 x i32> [[E]]
+;
+  %d = lshr <2 x i32> %a, <i32 31, i32 31>
+  %e = mul <2 x i32> %b, %d
+  ret <2 x i32> %e
+}
+
+define i32 @test18(i32 %A, i32 %B) {
+; CHECK-LABEL: @test18(
+; CHECK-NEXT:    ret i32 0
+;
+  %C = and i32 %A, 1
+  %D = and i32 %B, 1
+  %E = mul i32 %C, %D
+  %F = and i32 %E, 16
+  ret i32 %F
+}
+
+declare {i32, i1} @llvm.smul.with.overflow.i32(i32, i32)
+declare void @use(i1)
+
+define i32 @test19(i32 %A, i32 %B) {
+; CHECK-LABEL: @test19(
+; CHECK-NEXT:    call void @use(i1 false)
+; CHECK-NEXT:    ret i32 0
+;
+  %C = and i32 %A, 1
+  %D = and i32 %B, 1
+
+; It would be nice if we also started proving that this doesn't overflow.
+  %E = call {i32, i1} @llvm.smul.with.overflow.i32(i32 %C, i32 %D)
+  %F = extractvalue {i32, i1} %E, 0
+  %G = extractvalue {i32, i1} %E, 1
+  call void @use(i1 %G)
+  %H = and i32 %F, 16
+  ret i32 %H
+}
+
+define <2 x i64> @test20(<2 x i64> %A) {
+; CHECK-LABEL: @test20(
+; CHECK-NEXT:    [[TMP1:%.*]] = mul <2 x i64> [[A:%.*]], <i64 3, i64 2>
+; CHECK-NEXT:    [[C:%.*]] = add <2 x i64> [[TMP1]], <i64 36, i64 28>
+; CHECK-NEXT:    ret <2 x i64> [[C]]
+;
+  %B = add <2 x i64> %A, <i64 12, i64 14>
+  %C = mul <2 x i64> %B, <i64 3, i64 2>
+  ret <2 x i64> %C
+}
+
+define <2 x i1> @test21(<2 x i1> %A, <2 x i1> %B) {
+; CHECK-LABEL: @test21(
+; CHECK-NEXT:    [[C:%.*]] = and <2 x i1> [[A:%.*]], [[B:%.*]]
+; CHECK-NEXT:    ret <2 x i1> [[C]]
+;
+  %C = mul <2 x i1> %A, %B
+  ret <2 x i1> %C
+}
+
+define i32 @test22(i32 %A) {
+; CHECK-LABEL: @test22(
+; CHECK-NEXT:    [[B:%.*]] = sub nsw i32 0, [[A:%.*]]
+; CHECK-NEXT:    ret i32 [[B]]
+;
+  %B = mul nsw i32 %A, -1
+  ret i32 %B
+}
+
+define i32 @test23(i32 %A) {
+; CHECK-LABEL: @test23(
+; CHECK-NEXT:    [[C:%.*]] = mul nuw i32 [[A:%.*]], 6
+; CHECK-NEXT:    ret i32 [[C]]
+;
+  %B = shl nuw i32 %A, 1
+  %C = mul nuw i32 %B, 3
+  ret i32 %C
+}
+
+define i32 @test24(i32 %A) {
+; CHECK-LABEL: @test24(
+; CHECK-NEXT:    [[C:%.*]] = mul nsw i32 [[A:%.*]], 6
+; CHECK-NEXT:    ret i32 [[C]]
+;
+  %B = shl nsw i32 %A, 1
+  %C = mul nsw i32 %B, 3
+  ret i32 %C
+}
+
+define i32 @neg_neg_mul(i32 %A, i32 %B) {
+; CHECK-LABEL: @neg_neg_mul(
+; CHECK-NEXT:    [[E:%.*]] = mul i32 [[A:%.*]], [[B:%.*]]
+; CHECK-NEXT:    ret i32 [[E]]
+;
+  %C = sub i32 0, %A
+  %D = sub i32 0, %B
+  %E = mul i32 %C, %D
+  ret i32 %E
+}
+
+define i32 @neg_neg_mul_nsw(i32 %A, i32 %B) {
+; CHECK-LABEL: @neg_neg_mul_nsw(
+; CHECK-NEXT:    [[E:%.*]] = mul nsw i32 [[A:%.*]], [[B:%.*]]
+; CHECK-NEXT:    ret i32 [[E]]
+;
+  %C = sub nsw i32 0, %A
+  %D = sub nsw i32 0, %B
+  %E = mul nsw i32 %C, %D
+  ret i32 %E
+}
+
+define i124 @neg_neg_mul_apint(i124 %A, i124 %B) {
+; CHECK-LABEL: @neg_neg_mul_apint(
+; CHECK-NEXT:    [[E:%.*]] = mul i124 [[A:%.*]], [[B:%.*]]
+; CHECK-NEXT:    ret i124 [[E]]
+;
+  %C = sub i124 0, %A
+  %D = sub i124 0, %B
+  %E = mul i124 %C, %D
+  ret i124 %E
+}
+
+define i32 @neg_mul_constant(i32 %A) {
+; CHECK-LABEL: @neg_mul_constant(
+; CHECK-NEXT:    [[E:%.*]] = mul i32 [[A:%.*]], -7
+; CHECK-NEXT:    ret i32 [[E]]
+;
+  %C = sub i32 0, %A
+  %E = mul i32 %C, 7
+  ret i32 %E
+}
+
+define i55 @neg_mul_constant_apint(i55 %A) {
+; CHECK-LABEL: @neg_mul_constant_apint(
+; CHECK-NEXT:    [[E:%.*]] = mul i55 [[A:%.*]], -7
+; CHECK-NEXT:    ret i55 [[E]]
+;
+  %C = sub i55 0, %A
+  %E = mul i55 %C, 7
+  ret i55 %E
+}
+
+define <3 x i8> @neg_mul_constant_vec(<3 x i8> %a) {
+; CHECK-LABEL: @neg_mul_constant_vec(
+; CHECK-NEXT:    [[B:%.*]] = mul <3 x i8> [[A:%.*]], <i8 -5, i8 -5, i8 -5>
+; CHECK-NEXT:    ret <3 x i8> [[B]]
+;
+  %A = sub <3 x i8> zeroinitializer, %a
+  %B = mul <3 x i8> %A, <i8 5, i8 5, i8 5>
+  ret <3 x i8> %B
+}
+
+define <3 x i4> @neg_mul_constant_vec_weird(<3 x i4> %a) {
+; CHECK-LABEL: @neg_mul_constant_vec_weird(
+; CHECK-NEXT:    [[B:%.*]] = mul <3 x i4> [[A:%.*]], <i4 -5, i4 -5, i4 -5>
+; CHECK-NEXT:    ret <3 x i4> [[B]]
+;
+  %A = sub <3 x i4> zeroinitializer, %a
+  %B = mul <3 x i4> %A, <i4 5, i4 5, i4 5>
+  ret <3 x i4> %B
+}
+
+define i32 @test26(i32 %A, i32 %B) {
+; CHECK-LABEL: @test26(
+; CHECK-NEXT:    [[D:%.*]] = shl nsw i32 [[A:%.*]], [[B:%.*]]
+; CHECK-NEXT:    ret i32 [[D]]
+;
+  %C = shl nsw i32 1, %B
+  %D = mul nsw i32 %A, %C
+  ret i32 %D
+}
+
+define i32 @test27(i32 %A, i32 %B) {
+; CHECK-LABEL: @test27(
+; CHECK-NEXT:    [[D:%.*]] = shl nuw i32 [[A:%.*]], [[B:%.*]]
+; CHECK-NEXT:    ret i32 [[D]]
+;
+  %C = shl i32 1, %B
+  %D = mul nuw i32 %A, %C
+  ret i32 %D
+}
+
+define i32 @test28(i32 %A) {
+; CHECK-LABEL: @test28(
+; CHECK-NEXT:    [[B:%.*]] = shl i32 1, [[A:%.*]]
+; CHECK-NEXT:    [[C:%.*]] = shl i32 [[B]], [[A]]
+; CHECK-NEXT:    ret i32 [[C]]
+;
+  %B = shl i32 1, %A
+  %C = mul nsw i32 %B, %B
+  ret i32 %C
+}
+
+define i64 @test29(i31 %A, i31 %B) {
+; CHECK-LABEL: @test29(
+; CHECK-NEXT:    [[C:%.*]] = sext i31 [[A:%.*]] to i64
+; CHECK-NEXT:    [[D:%.*]] = sext i31 [[B:%.*]] to i64
+; CHECK-NEXT:    [[E:%.*]] = mul nsw i64 [[C]], [[D]]
+; CHECK-NEXT:    ret i64 [[E]]
+;
+  %C = sext i31 %A to i64
+  %D = sext i31 %B to i64
+  %E = mul i64 %C, %D
+  ret i64 %E
+}
+
+define i64 @test30(i32 %A, i32 %B) {
+; CHECK-LABEL: @test30(
+; CHECK-NEXT:    [[C:%.*]] = zext i32 [[A:%.*]] to i64
+; CHECK-NEXT:    [[D:%.*]] = zext i32 [[B:%.*]] to i64
+; CHECK-NEXT:    [[E:%.*]] = mul nuw i64 [[C]], [[D]]
+; CHECK-NEXT:    ret i64 [[E]]
+;
+  %C = zext i32 %A to i64
+  %D = zext i32 %B to i64
+  %E = mul i64 %C, %D
+  ret i64 %E
+}
+
+ at PR22087 = external global i32
+define i32 @test31(i32 %V) {
+; CHECK-LABEL: @test31(
+; CHECK-NEXT:    [[MUL:%.*]] = shl i32 [[V:%.*]], zext (i1 icmp ne (i32* inttoptr (i64 1 to i32*), i32* @PR22087) to i32)
+; CHECK-NEXT:    ret i32 [[MUL]]
+;
+  %mul = mul i32 %V, shl (i32 1, i32 zext (i1 icmp ne (i32* inttoptr (i64 1 to i32*), i32* @PR22087) to i32))
+  ret i32 %mul
+}
+
+define i32 @test32(i32 %X) {
+; CHECK-LABEL: @test32(
+; CHECK-NEXT:    [[MUL:%.*]] = shl i32 [[X:%.*]], 31
+; CHECK-NEXT:    ret i32 [[MUL]]
+;
+  %mul = mul nsw i32 %X, -2147483648
+  ret i32 %mul
+}
+
+define <2 x i32> @test32vec(<2 x i32> %X) {
+; CHECK-LABEL: @test32vec(
+; CHECK-NEXT:    [[MUL:%.*]] = shl <2 x i32> [[X:%.*]], <i32 31, i32 31>
+; CHECK-NEXT:    ret <2 x i32> [[MUL]]
+;
+  %mul = mul nsw <2 x i32> %X, <i32 -2147483648, i32 -2147483648>
+  ret <2 x i32> %mul
+}
+
+define i32 @test33(i32 %X) {
+; CHECK-LABEL: @test33(
+; CHECK-NEXT:    [[MUL:%.*]] = shl nsw i32 [[X:%.*]], 30
+; CHECK-NEXT:    ret i32 [[MUL]]
+;
+  %mul = mul nsw i32 %X, 1073741824
+  ret i32 %mul
+}
+
+define <2 x i32> @test33vec(<2 x i32> %X) {
+; CHECK-LABEL: @test33vec(
+; CHECK-NEXT:    [[MUL:%.*]] = shl nsw <2 x i32> [[X:%.*]], <i32 30, i32 30>
+; CHECK-NEXT:    ret <2 x i32> [[MUL]]
+;
+  %mul = mul nsw <2 x i32> %X, <i32 1073741824, i32 1073741824>
+  ret <2 x i32> %mul
+}
+
+define i128 @test34(i128 %X) {
+; CHECK-LABEL: @test34(
+; CHECK-NEXT:    [[MUL:%.*]] = shl nsw i128 [[X:%.*]], 1
+; CHECK-NEXT:    ret i128 [[MUL]]
+;
+  %mul = mul nsw i128 %X, 2
+  ret i128 %mul
+}
+
+define i32 @test_mul_canonicalize_op0(i32 %x, i32 %y) {
+; CHECK-LABEL: @test_mul_canonicalize_op0(
+; CHECK-NEXT:    [[TMP1:%.*]] = mul i32 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    [[MUL:%.*]] = sub i32 0, [[TMP1]]
+; CHECK-NEXT:    ret i32 [[MUL]]
+;
+  %neg = sub i32 0, %x
+  %mul = mul i32 %neg, %y
+  ret i32 %mul
+}
+
+define i32 @test_mul_canonicalize_op1(i32 %x, i32 %z) {
+; CHECK-LABEL: @test_mul_canonicalize_op1(
+; CHECK-NEXT:    [[Y:%.*]] = mul i32 [[Z:%.*]], 3
+; CHECK-NEXT:    [[TMP1:%.*]] = mul i32 [[Y]], [[X:%.*]]
+; CHECK-NEXT:    [[MUL:%.*]] = sub i32 0, [[TMP1]]
+; CHECK-NEXT:    ret i32 [[MUL]]
+;
+  %y = mul i32 %z, 3
+  %neg = sub i32 0, %x
+  %mul = mul i32 %y, %neg
+  ret i32 %mul
+}
+
+define i32 @test_mul_canonicalize_nsw(i32 %x, i32 %y) {
+; CHECK-LABEL: @test_mul_canonicalize_nsw(
+; CHECK-NEXT:    [[TMP1:%.*]] = mul i32 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    [[MUL:%.*]] = sub i32 0, [[TMP1]]
+; CHECK-NEXT:    ret i32 [[MUL]]
+;
+  %neg = sub nsw i32 0, %x
+  %mul = mul nsw i32 %neg, %y
+  ret i32 %mul
+}
+
+define <2 x i32> @test_mul_canonicalize_vec(<2 x i32> %x, <2 x i32> %y) {
+; CHECK-LABEL: @test_mul_canonicalize_vec(
+; CHECK-NEXT:    [[TMP1:%.*]] = mul <2 x i32> [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    [[MUL:%.*]] = sub <2 x i32> zeroinitializer, [[TMP1]]
+; CHECK-NEXT:    ret <2 x i32> [[MUL]]
+;
+  %neg = sub <2 x i32> <i32 0, i32 0>, %x
+  %mul = mul <2 x i32> %neg, %y
+  ret <2 x i32> %mul
+}
+
+define i32 @test_mul_canonicalize_multiple_uses(i32 %x, i32 %y) {
+; CHECK-LABEL: @test_mul_canonicalize_multiple_uses(
+; CHECK-NEXT:    [[NEG:%.*]] = sub i32 0, [[X:%.*]]
+; CHECK-NEXT:    [[MUL:%.*]] = mul i32 [[NEG]], [[Y:%.*]]
+; CHECK-NEXT:    [[MUL2:%.*]] = mul i32 [[MUL]], [[NEG]]
+; CHECK-NEXT:    ret i32 [[MUL2]]
+;
+  %neg = sub i32 0, %x
+  %mul = mul i32 %neg, %y
+  %mul2 = mul i32 %mul, %neg
+  ret i32 %mul2
+}
+
+ at X = global i32 5
+
+define i64 @test_mul_canonicalize_neg_is_not_undone(i64 %L1) {
+; Check we do not undo the canonicalization of 0 - (X * Y), if Y is a constant
+; expr.
+; CHECK-LABEL: @test_mul_canonicalize_neg_is_not_undone(
+; CHECK-NEXT:    [[TMP1:%.*]] = mul i64 [[L1:%.*]], ptrtoint (i32* @X to i64)
+; CHECK-NEXT:    [[B4:%.*]] = sub i64 0, [[TMP1]]
+; CHECK-NEXT:    ret i64 [[B4]]
+;
+  %v1 = ptrtoint i32* @X to i64
+  %B8 = sub i64 0, %v1
+  %B4 = mul i64 %B8, %L1
+  ret i64 %B4
+}

Added: llvm/trunk/test/Transforms/InstCombine/multi-size-address-space-pointer.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/multi-size-address-space-pointer.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/multi-size-address-space-pointer.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/multi-size-address-space-pointer.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,112 @@
+; RUN: opt -S -instcombine %s -o - | FileCheck %s
+target datalayout = "e-p:32:32:32-p1:64:64:64-p2:8:8:8-p3:16:16:16-p4:16:16:16-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:32"
+
+
+define i32 @test_as0(i32 addrspace(0)* %a) {
+; CHECK-LABEL: @test_as0(
+; CHECK: %arrayidx = getelementptr i32, i32* %a, i32 1
+  %arrayidx = getelementptr i32, i32 addrspace(0)* %a, i64 1
+  %y = load i32, i32 addrspace(0)* %arrayidx, align 4
+  ret i32 %y
+}
+
+define i32 @test_as1(i32 addrspace(1)* %a) {
+; CHECK-LABEL: @test_as1(
+; CHECK: %arrayidx = getelementptr i32, i32 addrspace(1)* %a, i64 1
+  %arrayidx = getelementptr i32, i32 addrspace(1)* %a, i32 1
+  %y = load i32, i32 addrspace(1)* %arrayidx, align 4
+  ret i32 %y
+}
+
+define i32 @test_as2(i32 addrspace(2)* %a) {
+; CHECK-LABEL: @test_as2(
+; CHECK: %arrayidx = getelementptr i32, i32 addrspace(2)* %a, i8 1
+  %arrayidx = getelementptr i32, i32 addrspace(2)* %a, i32 1
+  %y = load i32, i32 addrspace(2)* %arrayidx, align 4
+  ret i32 %y
+}
+
+define i32 @test_as3(i32 addrspace(3)* %a) {
+; CHECK-LABEL: @test_as3(
+; CHECK: %arrayidx = getelementptr i32, i32 addrspace(3)* %a, i16 1
+  %arrayidx = getelementptr i32, i32 addrspace(3)* %a, i32 1
+  %y = load i32, i32 addrspace(3)* %arrayidx, align 4
+  ret i32 %y
+}
+
+define i32 @test_combine_ptrtoint(i32 addrspace(2)* %a) {
+; CHECK-LABEL: @test_combine_ptrtoint(
+; CHECK-NEXT: %y = load i32, i32 addrspace(2)* %a
+; CHECK-NEXT: ret i32 %y
+  %cast = ptrtoint i32 addrspace(2)* %a to i8
+  %castback = inttoptr i8 %cast to i32 addrspace(2)*
+  %y = load i32, i32 addrspace(2)* %castback, align 4
+  ret i32 %y
+}
+
+define i8 @test_combine_inttoptr(i8 %a) {
+; CHECK-LABEL: @test_combine_inttoptr(
+; CHECK-NEXT: ret i8 %a
+  %cast = inttoptr i8 %a to i32 addrspace(2)*
+  %castback = ptrtoint i32 addrspace(2)* %cast to i8
+  ret i8 %castback
+}
+
+define i32 @test_combine_vector_ptrtoint(<2 x i32 addrspace(2)*> %a) {
+; CHECK-LABEL: @test_combine_vector_ptrtoint(
+; CHECK-NEXT: %p = extractelement <2 x i32 addrspace(2)*> %a, i32 0
+; CHECK-NEXT: %y = load i32, i32 addrspace(2)* %p, align 4
+; CHECK-NEXT: ret i32 %y
+  %cast = ptrtoint <2 x i32 addrspace(2)*> %a to <2 x i8>
+  %castback = inttoptr <2 x i8> %cast to <2 x i32 addrspace(2)*>
+  %p = extractelement <2 x i32 addrspace(2)*> %castback, i32 0
+  %y = load i32, i32 addrspace(2)* %p, align 4
+  ret i32 %y
+}
+
+define <2 x i8> @test_combine_vector_inttoptr(<2 x i8> %a) {
+; CHECK-LABEL: @test_combine_vector_inttoptr(
+; CHECK-NEXT: ret <2 x i8> %a
+  %cast = inttoptr <2 x i8> %a to <2 x i32 addrspace(2)*>
+  %castback = ptrtoint <2 x i32 addrspace(2)*> %cast to <2 x i8>
+  ret <2 x i8> %castback
+}
+
+; Check that the GEP index is changed to the address space integer type (i64 -> i8)
+define i32 addrspace(2)* @shrink_gep_constant_index_64_as2(i32 addrspace(2)* %p) {
+; CHECK-LABEL: @shrink_gep_constant_index_64_as2(
+; CHECK-NEXT: getelementptr i32, i32 addrspace(2)* %p, i8 1
+  %ret = getelementptr i32, i32 addrspace(2)* %p, i64 1
+  ret i32 addrspace(2)* %ret
+}
+
+define i32 addrspace(2)* @shrink_gep_constant_index_32_as2(i32 addrspace(2)* %p) {
+; CHECK-LABEL: @shrink_gep_constant_index_32_as2(
+; CHECK-NEXT: getelementptr i32, i32 addrspace(2)* %p, i8 1
+  %ret = getelementptr i32, i32 addrspace(2)* %p, i32 1
+  ret i32 addrspace(2)* %ret
+}
+
+define i32 addrspace(3)* @shrink_gep_constant_index_64_as3(i32 addrspace(3)* %p) {
+; CHECK-LABEL: @shrink_gep_constant_index_64_as3(
+; CHECK-NEXT: getelementptr i32, i32 addrspace(3)* %p, i16 1
+  %ret = getelementptr i32, i32 addrspace(3)* %p, i64 1
+  ret i32 addrspace(3)* %ret
+}
+
+define i32 addrspace(2)* @shrink_gep_variable_index_64_as2(i32 addrspace(2)* %p, i64 %idx) {
+; CHECK-LABEL: @shrink_gep_variable_index_64_as2(
+; CHECK-NEXT: %1 = trunc i64 %idx to i8
+; CHECK-NEXT: getelementptr i32, i32 addrspace(2)* %p, i8 %1
+  %ret = getelementptr i32, i32 addrspace(2)* %p, i64 %idx
+  ret i32 addrspace(2)* %ret
+}
+
+define i32 addrspace(1)* @grow_gep_variable_index_8_as1(i32 addrspace(1)* %p, i8 %idx) {
+; CHECK-LABEL: @grow_gep_variable_index_8_as1(
+; CHECK-NEXT: %1 = sext i8 %idx to i64
+; CHECK-NEXT: getelementptr i32, i32 addrspace(1)* %p, i64 %1
+  %ret = getelementptr i32, i32 addrspace(1)* %p, i8 %idx
+  ret i32 addrspace(1)* %ret
+}
+

Added: llvm/trunk/test/Transforms/InstCombine/multi-use-or.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/multi-use-or.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/multi-use-or.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/multi-use-or.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,24 @@
+; RUN: opt < %s -instcombine -S | grep "fadd double .sx, .sy"
+; The 'or' has multiple uses, make sure that this doesn't prevent instcombine
+; from propagating the extends to the truncs.
+
+define double @ScaleObjectAdd(double %sx, double %sy, double %sz) nounwind {
+entry:
+        %sx34 = bitcast double %sx to i64               ; <i64> [#uses=1]
+        %sx3435 = zext i64 %sx34 to i192                ; <i192> [#uses=1]
+        %sy22 = bitcast double %sy to i64               ; <i64> [#uses=1]
+        %sy2223 = zext i64 %sy22 to i192                ; <i192> [#uses=1]
+        %sy222324 = shl i192 %sy2223, 128               ; <i192> [#uses=1]
+        %sy222324.ins = or i192 %sx3435, %sy222324              ; <i192> [#uses=1]
+        
+        
+        %a = trunc i192 %sy222324.ins to i64            ; <i64> [#uses=1]
+        %b = bitcast i64 %a to double           ; <double> [#uses=1]
+        %c = lshr i192 %sy222324.ins, 128               ; <i192> [#uses=1]
+        %d = trunc i192 %c to i64               ; <i64> [#uses=1]
+        %e = bitcast i64 %d to double           ; <double> [#uses=1]
+        %f = fadd double %b, %e
+
+;        ret double %e
+        ret double %f
+}

Added: llvm/trunk/test/Transforms/InstCombine/multiple-uses-load-bitcast-select.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/multiple-uses-load-bitcast-select.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/multiple-uses-load-bitcast-select.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/multiple-uses-load-bitcast-select.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,30 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt < %s -instcombine -S -data-layout="E-m:e-i1:8:16-i8:8:16-i64:64-f128:64-v128:64-a:8:16-n32:64" | FileCheck %s
+
+define void @PR35618(i64* %st1, double* %st2) {
+; CHECK-LABEL: @PR35618(
+; CHECK-NEXT:    [[Y1:%.*]] = alloca double, align 8
+; CHECK-NEXT:    [[Z1:%.*]] = alloca double, align 8
+; CHECK-NEXT:    [[LD1:%.*]] = load double, double* [[Y1]], align 8
+; CHECK-NEXT:    [[LD2:%.*]] = load double, double* [[Z1]], align 8
+; CHECK-NEXT:    [[TMP10:%.*]] = fcmp olt double [[LD1]], [[LD2]]
+; CHECK-NEXT:    [[TMP121:%.*]] = select i1 [[TMP10]], double [[LD1]], double [[LD2]]
+; CHECK-NEXT:    [[TMP1:%.*]] = bitcast i64* [[ST1:%.*]] to double*
+; CHECK-NEXT:    store double [[TMP121]], double* [[TMP1]], align 8
+; CHECK-NEXT:    store double [[TMP121]], double* [[ST2:%.*]], align 8
+; CHECK-NEXT:    ret void
+;
+  %y1 = alloca double
+  %z1 = alloca double
+  %ld1 = load double, double* %y1
+  %ld2 = load double, double* %z1
+  %tmp10 = fcmp olt double %ld1, %ld2
+  %sel = select i1 %tmp10, double* %y1, double* %z1
+  %tmp11 = bitcast double* %sel to i64*
+  %tmp12 = load i64, i64* %tmp11
+  store i64 %tmp12, i64* %st1
+  %bc = bitcast double* %st2 to i64*
+  store i64 %tmp12, i64* %bc
+  ret void
+}
+

Added: llvm/trunk/test/Transforms/InstCombine/musttail-thunk.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/musttail-thunk.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/musttail-thunk.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/musttail-thunk.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,33 @@
+; RUN: opt -instcombine -S < %s | FileCheck %s
+; RUN: opt -debugify-each -instcombine -S < %s | FileCheck %s
+
+; These are both direct calls, but make sure instcombine leaves the casts
+; alone.
+
+define i32 @call_thunk(i32 %x, i32 %y) {
+  %r = call i32 bitcast (void (i32, ...)* @inc_first_arg_thunk to i32 (i32, i32)*)(i32 %x, i32 %y)
+  ret i32 %r
+}
+
+; CHECK-LABEL: define i32 @call_thunk(i32 %x, i32 %y)
+; CHECK:   %r = call i32 bitcast (void (i32, ...)* @inc_first_arg_thunk to i32 (i32, i32)*)(i32 %x, i32 %y)
+; CHECK:   ret i32 %r
+
+define internal void @inc_first_arg_thunk(i32 %arg1, ...) #0 {
+entry:
+  %inc = add i32 %arg1, 1
+  musttail call void (i32, ...) bitcast (i32 (i32, i32)* @plus to void (i32, ...)*)(i32 %inc, ...)
+  ret void
+}
+
+; CHECK-LABEL: define internal void @inc_first_arg_thunk(i32 %arg1, ...) #0
+; CHECK:   %inc = add i32 %arg1, 1
+; CHECK:   musttail call void (i32, ...) bitcast (i32 (i32, i32)* @plus to void (i32, ...)*)(i32 %inc, ...)
+; CHECK:   ret void
+
+define internal i32 @plus(i32 %x, i32 %y) {
+  %r = add i32 %x, %y
+  ret i32 %r
+}
+
+attributes #0 = { "thunk" }

Added: llvm/trunk/test/Transforms/InstCombine/narrow-math.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/narrow-math.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/narrow-math.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/narrow-math.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,630 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt < %s -instcombine -S | FileCheck %s
+
+declare i32 @callee()
+
+declare void @use(i64)
+
+define i64 @sext_sext_add(i32 %A) {
+; CHECK-LABEL: @sext_sext_add(
+; CHECK-NEXT:    [[B:%.*]] = ashr i32 [[A:%.*]], 7
+; CHECK-NEXT:    [[C:%.*]] = ashr i32 [[A]], 9
+; CHECK-NEXT:    [[NARROW:%.*]] = add nsw i32 [[B]], [[C]]
+; CHECK-NEXT:    [[F:%.*]] = sext i32 [[NARROW]] to i64
+; CHECK-NEXT:    ret i64 [[F]]
+;
+  %B = ashr i32 %A, 7
+  %C = ashr i32 %A, 9
+  %D = sext i32 %B to i64
+  %E = sext i32 %C to i64
+  %F = add i64 %D, %E
+  ret i64 %F
+}
+
+; Negative test
+
+define i64 @sext_zext_add_mismatched_exts(i32 %A) {
+; CHECK-LABEL: @sext_zext_add_mismatched_exts(
+; CHECK-NEXT:    [[B:%.*]] = ashr i32 [[A:%.*]], 7
+; CHECK-NEXT:    [[C:%.*]] = lshr i32 [[A]], 9
+; CHECK-NEXT:    [[D:%.*]] = sext i32 [[B]] to i64
+; CHECK-NEXT:    [[E:%.*]] = zext i32 [[C]] to i64
+; CHECK-NEXT:    [[F:%.*]] = add nsw i64 [[D]], [[E]]
+; CHECK-NEXT:    ret i64 [[F]]
+;
+  %B = ashr i32 %A, 7
+  %C = lshr i32 %A, 9
+  %D = sext i32 %B to i64
+  %E = zext i32 %C to i64
+  %F = add i64 %D, %E
+  ret i64 %F
+}
+
+; Negative test
+
+define i64 @sext_sext_add_mismatched_types(i16 %A, i32 %x) {
+; CHECK-LABEL: @sext_sext_add_mismatched_types(
+; CHECK-NEXT:    [[B:%.*]] = ashr i16 [[A:%.*]], 7
+; CHECK-NEXT:    [[C:%.*]] = ashr i32 [[X:%.*]], 9
+; CHECK-NEXT:    [[D:%.*]] = sext i16 [[B]] to i64
+; CHECK-NEXT:    [[E:%.*]] = sext i32 [[C]] to i64
+; CHECK-NEXT:    [[F:%.*]] = add nsw i64 [[D]], [[E]]
+; CHECK-NEXT:    ret i64 [[F]]
+;
+  %B = ashr i16 %A, 7
+  %C = ashr i32 %x, 9
+  %D = sext i16 %B to i64
+  %E = sext i32 %C to i64
+  %F = add i64 %D, %E
+  ret i64 %F
+}
+
+define i64 @sext_sext_add_extra_use1(i32 %A) {
+; CHECK-LABEL: @sext_sext_add_extra_use1(
+; CHECK-NEXT:    [[B:%.*]] = ashr i32 [[A:%.*]], 7
+; CHECK-NEXT:    [[C:%.*]] = ashr i32 [[A]], 9
+; CHECK-NEXT:    [[D:%.*]] = sext i32 [[B]] to i64
+; CHECK-NEXT:    call void @use(i64 [[D]])
+; CHECK-NEXT:    [[NARROW:%.*]] = add nsw i32 [[B]], [[C]]
+; CHECK-NEXT:    [[F:%.*]] = sext i32 [[NARROW]] to i64
+; CHECK-NEXT:    ret i64 [[F]]
+;
+  %B = ashr i32 %A, 7
+  %C = ashr i32 %A, 9
+  %D = sext i32 %B to i64
+  call void @use(i64 %D)
+  %E = sext i32 %C to i64
+  %F = add i64 %D, %E
+  ret i64 %F
+}
+
+define i64 @sext_sext_add_extra_use2(i32 %A) {
+; CHECK-LABEL: @sext_sext_add_extra_use2(
+; CHECK-NEXT:    [[B:%.*]] = ashr i32 [[A:%.*]], 7
+; CHECK-NEXT:    [[C:%.*]] = ashr i32 [[A]], 9
+; CHECK-NEXT:    [[E:%.*]] = sext i32 [[C]] to i64
+; CHECK-NEXT:    call void @use(i64 [[E]])
+; CHECK-NEXT:    [[NARROW:%.*]] = add nsw i32 [[B]], [[C]]
+; CHECK-NEXT:    [[F:%.*]] = sext i32 [[NARROW]] to i64
+; CHECK-NEXT:    ret i64 [[F]]
+;
+  %B = ashr i32 %A, 7
+  %C = ashr i32 %A, 9
+  %D = sext i32 %B to i64
+  %E = sext i32 %C to i64
+  call void @use(i64 %E)
+  %F = add i64 %D, %E
+  ret i64 %F
+}
+
+; Negative test - if both extends have extra uses, we need an extra instruction.
+
+define i64 @sext_sext_add_extra_use3(i32 %A) {
+; CHECK-LABEL: @sext_sext_add_extra_use3(
+; CHECK-NEXT:    [[B:%.*]] = ashr i32 [[A:%.*]], 7
+; CHECK-NEXT:    [[C:%.*]] = ashr i32 [[A]], 9
+; CHECK-NEXT:    [[D:%.*]] = sext i32 [[B]] to i64
+; CHECK-NEXT:    call void @use(i64 [[D]])
+; CHECK-NEXT:    [[E:%.*]] = sext i32 [[C]] to i64
+; CHECK-NEXT:    call void @use(i64 [[E]])
+; CHECK-NEXT:    [[F:%.*]] = add nsw i64 [[D]], [[E]]
+; CHECK-NEXT:    ret i64 [[F]]
+;
+  %B = ashr i32 %A, 7
+  %C = ashr i32 %A, 9
+  %D = sext i32 %B to i64
+  call void @use(i64 %D)
+  %E = sext i32 %C to i64
+  call void @use(i64 %E)
+  %F = add i64 %D, %E
+  ret i64 %F
+}
+
+define i64 @test1(i32 %V) {
+; CHECK-LABEL: @test1(
+; CHECK-NEXT:    [[CALL1:%.*]] = call i32 @callee(), !range !0
+; CHECK-NEXT:    [[CALL2:%.*]] = call i32 @callee(), !range !0
+; CHECK-NEXT:    [[NARROW:%.*]] = add nuw nsw i32 [[CALL1]], [[CALL2]]
+; CHECK-NEXT:    [[ADD:%.*]] = zext i32 [[NARROW]] to i64
+; CHECK-NEXT:    ret i64 [[ADD]]
+;
+  %call1 = call i32 @callee(), !range !0
+  %call2 = call i32 @callee(), !range !0
+  %zext1 = sext i32 %call1 to i64
+  %zext2 = sext i32 %call2 to i64
+  %add = add i64 %zext1, %zext2
+  ret i64 %add
+}
+
+define i64 @test2(i32 %V) {
+; CHECK-LABEL: @test2(
+; CHECK-NEXT:    [[CALL1:%.*]] = call i32 @callee(), !range !0
+; CHECK-NEXT:    [[CALL2:%.*]] = call i32 @callee(), !range !0
+; CHECK-NEXT:    [[ADD:%.*]] = add nuw nsw i32 [[CALL1]], [[CALL2]]
+; CHECK-NEXT:    [[TMP1:%.*]] = zext i32 [[ADD]] to i64
+; CHECK-NEXT:    ret i64 [[TMP1]]
+;
+  %call1 = call i32 @callee(), !range !0
+  %call2 = call i32 @callee(), !range !0
+  %add = add i32 %call1, %call2
+  %zext = sext i32 %add to i64
+  ret i64 %zext
+}
+
+define i64 @test3(i32 %V) {
+; CHECK-LABEL: @test3(
+; CHECK-NEXT:    [[CALL1:%.*]] = call i32 @callee(), !range !0
+; CHECK-NEXT:    [[CALL2:%.*]] = call i32 @callee(), !range !0
+; CHECK-NEXT:    [[NARROW:%.*]] = mul nuw nsw i32 [[CALL1]], [[CALL2]]
+; CHECK-NEXT:    [[ADD:%.*]] = zext i32 [[NARROW]] to i64
+; CHECK-NEXT:    ret i64 [[ADD]]
+;
+  %call1 = call i32 @callee(), !range !0
+  %call2 = call i32 @callee(), !range !0
+  %zext1 = sext i32 %call1 to i64
+  %zext2 = sext i32 %call2 to i64
+  %add = mul i64 %zext1, %zext2
+  ret i64 %add
+}
+
+define i64 @test4(i32 %V) {
+; CHECK-LABEL: @test4(
+; CHECK-NEXT:    [[CALL1:%.*]] = call i32 @callee(), !range !0
+; CHECK-NEXT:    [[CALL2:%.*]] = call i32 @callee(), !range !0
+; CHECK-NEXT:    [[ADD:%.*]] = mul nuw nsw i32 [[CALL1]], [[CALL2]]
+; CHECK-NEXT:    [[TMP1:%.*]] = zext i32 [[ADD]] to i64
+; CHECK-NEXT:    ret i64 [[TMP1]]
+;
+  %call1 = call i32 @callee(), !range !0
+  %call2 = call i32 @callee(), !range !0
+  %add = mul i32 %call1, %call2
+  %zext = sext i32 %add to i64
+  ret i64 %zext
+}
+
+define i64 @test5(i32 %V) {
+; CHECK-LABEL: @test5(
+; CHECK-NEXT:    [[ASHR:%.*]] = ashr i32 [[V:%.*]], 1
+; CHECK-NEXT:    [[NARROW:%.*]] = add nsw i32 [[ASHR]], 1073741823
+; CHECK-NEXT:    [[ADD:%.*]] = sext i32 [[NARROW]] to i64
+; CHECK-NEXT:    ret i64 [[ADD]]
+;
+  %ashr = ashr i32 %V, 1
+  %sext = sext i32 %ashr to i64
+  %add = add i64 %sext, 1073741823
+  ret i64 %add
+}
+
+; Negative test - extra use means we'd have more instructions than we started with.
+
+define i64 @sext_add_constant_extra_use(i32 %V) {
+; CHECK-LABEL: @sext_add_constant_extra_use(
+; CHECK-NEXT:    [[ASHR:%.*]] = ashr i32 [[V:%.*]], 1
+; CHECK-NEXT:    [[SEXT:%.*]] = sext i32 [[ASHR]] to i64
+; CHECK-NEXT:    call void @use(i64 [[SEXT]])
+; CHECK-NEXT:    [[ADD:%.*]] = add nsw i64 [[SEXT]], 1073741823
+; CHECK-NEXT:    ret i64 [[ADD]]
+;
+  %ashr = ashr i32 %V, 1
+  %sext = sext i32 %ashr to i64
+  call void @use(i64 %sext)
+  %add = add i64 %sext, 1073741823
+  ret i64 %add
+}
+
+define <2 x i64> @test5_splat(<2 x i32> %V) {
+; CHECK-LABEL: @test5_splat(
+; CHECK-NEXT:    [[ASHR:%.*]] = ashr <2 x i32> [[V:%.*]], <i32 1, i32 1>
+; CHECK-NEXT:    [[NARROW:%.*]] = add nsw <2 x i32> [[ASHR]], <i32 1073741823, i32 1073741823>
+; CHECK-NEXT:    [[ADD:%.*]] = sext <2 x i32> [[NARROW]] to <2 x i64>
+; CHECK-NEXT:    ret <2 x i64> [[ADD]]
+;
+  %ashr = ashr <2 x i32> %V, <i32 1, i32 1>
+  %sext = sext <2 x i32> %ashr to <2 x i64>
+  %add = add <2 x i64> %sext, <i64 1073741823, i64 1073741823>
+  ret <2 x i64> %add
+}
+
+define <2 x i64> @test5_vec(<2 x i32> %V) {
+; CHECK-LABEL: @test5_vec(
+; CHECK-NEXT:    [[ASHR:%.*]] = ashr <2 x i32> [[V:%.*]], <i32 1, i32 1>
+; CHECK-NEXT:    [[NARROW:%.*]] = add nsw <2 x i32> [[ASHR]], <i32 1, i32 2>
+; CHECK-NEXT:    [[ADD:%.*]] = sext <2 x i32> [[NARROW]] to <2 x i64>
+; CHECK-NEXT:    ret <2 x i64> [[ADD]]
+;
+  %ashr = ashr <2 x i32> %V, <i32 1, i32 1>
+  %sext = sext <2 x i32> %ashr to <2 x i64>
+  %add = add <2 x i64> %sext, <i64 1, i64 2>
+  ret <2 x i64> %add
+}
+
+define i64 @test6(i32 %V) {
+; CHECK-LABEL: @test6(
+; CHECK-NEXT:    [[ASHR:%.*]] = ashr i32 [[V:%.*]], 1
+; CHECK-NEXT:    [[NARROW:%.*]] = add nsw i32 [[ASHR]], -1073741824
+; CHECK-NEXT:    [[ADD:%.*]] = sext i32 [[NARROW]] to i64
+; CHECK-NEXT:    ret i64 [[ADD]]
+;
+  %ashr = ashr i32 %V, 1
+  %sext = sext i32 %ashr to i64
+  %add = add i64 %sext, -1073741824
+  ret i64 %add
+}
+
+define <2 x i64> @test6_splat(<2 x i32> %V) {
+; CHECK-LABEL: @test6_splat(
+; CHECK-NEXT:    [[ASHR:%.*]] = ashr <2 x i32> [[V:%.*]], <i32 1, i32 1>
+; CHECK-NEXT:    [[NARROW:%.*]] = add nsw <2 x i32> [[ASHR]], <i32 -1073741824, i32 -1073741824>
+; CHECK-NEXT:    [[ADD:%.*]] = sext <2 x i32> [[NARROW]] to <2 x i64>
+; CHECK-NEXT:    ret <2 x i64> [[ADD]]
+;
+  %ashr = ashr <2 x i32> %V, <i32 1, i32 1>
+  %sext = sext <2 x i32> %ashr to <2 x i64>
+  %add = add <2 x i64> %sext, <i64 -1073741824, i64 -1073741824>
+  ret <2 x i64> %add
+}
+
+define <2 x i64> @test6_vec(<2 x i32> %V) {
+; CHECK-LABEL: @test6_vec(
+; CHECK-NEXT:    [[ASHR:%.*]] = ashr <2 x i32> [[V:%.*]], <i32 1, i32 1>
+; CHECK-NEXT:    [[NARROW:%.*]] = add nsw <2 x i32> [[ASHR]], <i32 -1, i32 -2>
+; CHECK-NEXT:    [[ADD:%.*]] = sext <2 x i32> [[NARROW]] to <2 x i64>
+; CHECK-NEXT:    ret <2 x i64> [[ADD]]
+;
+  %ashr = ashr <2 x i32> %V, <i32 1, i32 1>
+  %sext = sext <2 x i32> %ashr to <2 x i64>
+  %add = add <2 x i64> %sext, <i64 -1, i64 -2>
+  ret <2 x i64> %add
+}
+
+define <2 x i64> @test6_vec2(<2 x i32> %V) {
+; CHECK-LABEL: @test6_vec2(
+; CHECK-NEXT:    [[ASHR:%.*]] = ashr <2 x i32> [[V:%.*]], <i32 1, i32 1>
+; CHECK-NEXT:    [[NARROW:%.*]] = add nsw <2 x i32> [[ASHR]], <i32 -1, i32 1>
+; CHECK-NEXT:    [[ADD:%.*]] = sext <2 x i32> [[NARROW]] to <2 x i64>
+; CHECK-NEXT:    ret <2 x i64> [[ADD]]
+;
+  %ashr = ashr <2 x i32> %V, <i32 1, i32 1>
+  %sext = sext <2 x i32> %ashr to <2 x i64>
+  %add = add <2 x i64> %sext, <i64 -1, i64 1>
+  ret <2 x i64> %add
+}
+
+define i64 @test7(i32 %V) {
+; CHECK-LABEL: @test7(
+; CHECK-NEXT:    [[LSHR:%.*]] = lshr i32 [[V:%.*]], 1
+; CHECK-NEXT:    [[NARROW:%.*]] = add nuw i32 [[LSHR]], 2147483647
+; CHECK-NEXT:    [[ADD:%.*]] = zext i32 [[NARROW]] to i64
+; CHECK-NEXT:    ret i64 [[ADD]]
+;
+  %lshr = lshr i32 %V, 1
+  %zext = zext i32 %lshr to i64
+  %add = add i64 %zext, 2147483647
+  ret i64 %add
+}
+
+define <2 x i64> @test7_splat(<2 x i32> %V) {
+; CHECK-LABEL: @test7_splat(
+; CHECK-NEXT:    [[LSHR:%.*]] = lshr <2 x i32> [[V:%.*]], <i32 1, i32 1>
+; CHECK-NEXT:    [[NARROW:%.*]] = add nuw <2 x i32> [[LSHR]], <i32 2147483647, i32 2147483647>
+; CHECK-NEXT:    [[ADD:%.*]] = zext <2 x i32> [[NARROW]] to <2 x i64>
+; CHECK-NEXT:    ret <2 x i64> [[ADD]]
+;
+  %lshr = lshr <2 x i32> %V, <i32 1, i32 1>
+  %zext = zext <2 x i32> %lshr to <2 x i64>
+  %add = add <2 x i64> %zext, <i64 2147483647, i64 2147483647>
+  ret <2 x i64> %add
+}
+
+define <2 x i64> @test7_vec(<2 x i32> %V) {
+; CHECK-LABEL: @test7_vec(
+; CHECK-NEXT:    [[LSHR:%.*]] = lshr <2 x i32> [[V:%.*]], <i32 1, i32 1>
+; CHECK-NEXT:    [[NARROW:%.*]] = add nuw <2 x i32> [[LSHR]], <i32 1, i32 2>
+; CHECK-NEXT:    [[ADD:%.*]] = zext <2 x i32> [[NARROW]] to <2 x i64>
+; CHECK-NEXT:    ret <2 x i64> [[ADD]]
+;
+  %lshr = lshr <2 x i32> %V, <i32 1, i32 1>
+  %zext = zext <2 x i32> %lshr to <2 x i64>
+  %add = add <2 x i64> %zext, <i64 1, i64 2>
+  ret <2 x i64> %add
+}
+
+define i64 @test8(i32 %V) {
+; CHECK-LABEL: @test8(
+; CHECK-NEXT:    [[ASHR:%.*]] = ashr i32 [[V:%.*]], 16
+; CHECK-NEXT:    [[NARROW:%.*]] = mul nsw i32 [[ASHR]], 32767
+; CHECK-NEXT:    [[MUL:%.*]] = sext i32 [[NARROW]] to i64
+; CHECK-NEXT:    ret i64 [[MUL]]
+;
+  %ashr = ashr i32 %V, 16
+  %sext = sext i32 %ashr to i64
+  %mul = mul i64 %sext, 32767
+  ret i64 %mul
+}
+
+define <2 x i64> @test8_splat(<2 x i32> %V) {
+; CHECK-LABEL: @test8_splat(
+; CHECK-NEXT:    [[ASHR:%.*]] = ashr <2 x i32> [[V:%.*]], <i32 16, i32 16>
+; CHECK-NEXT:    [[NARROW:%.*]] = mul nsw <2 x i32> [[ASHR]], <i32 32767, i32 32767>
+; CHECK-NEXT:    [[MUL:%.*]] = sext <2 x i32> [[NARROW]] to <2 x i64>
+; CHECK-NEXT:    ret <2 x i64> [[MUL]]
+;
+  %ashr = ashr <2 x i32> %V, <i32 16, i32 16>
+  %sext = sext <2 x i32> %ashr to <2 x i64>
+  %mul = mul <2 x i64> %sext, <i64 32767, i64 32767>
+  ret <2 x i64> %mul
+}
+
+define <2 x i64> @test8_vec(<2 x i32> %V) {
+; CHECK-LABEL: @test8_vec(
+; CHECK-NEXT:    [[ASHR:%.*]] = ashr <2 x i32> [[V:%.*]], <i32 16, i32 16>
+; CHECK-NEXT:    [[NARROW:%.*]] = mul nsw <2 x i32> [[ASHR]], <i32 32767, i32 16384>
+; CHECK-NEXT:    [[MUL:%.*]] = sext <2 x i32> [[NARROW]] to <2 x i64>
+; CHECK-NEXT:    ret <2 x i64> [[MUL]]
+;
+  %ashr = ashr <2 x i32> %V, <i32 16, i32 16>
+  %sext = sext <2 x i32> %ashr to <2 x i64>
+  %mul = mul <2 x i64> %sext, <i64 32767, i64 16384>
+  ret <2 x i64> %mul
+}
+
+define <2 x i64> @test8_vec2(<2 x i32> %V) {
+; CHECK-LABEL: @test8_vec2(
+; CHECK-NEXT:    [[ASHR:%.*]] = ashr <2 x i32> [[V:%.*]], <i32 16, i32 16>
+; CHECK-NEXT:    [[NARROW:%.*]] = mul nsw <2 x i32> [[ASHR]], <i32 32767, i32 -32767>
+; CHECK-NEXT:    [[MUL:%.*]] = sext <2 x i32> [[NARROW]] to <2 x i64>
+; CHECK-NEXT:    ret <2 x i64> [[MUL]]
+;
+  %ashr = ashr <2 x i32> %V, <i32 16, i32 16>
+  %sext = sext <2 x i32> %ashr to <2 x i64>
+  %mul = mul <2 x i64> %sext, <i64 32767, i64 -32767>
+  ret <2 x i64> %mul
+}
+
+define i64 @test9(i32 %V) {
+; CHECK-LABEL: @test9(
+; CHECK-NEXT:    [[ASHR:%.*]] = ashr i32 [[V:%.*]], 16
+; CHECK-NEXT:    [[NARROW:%.*]] = mul nsw i32 [[ASHR]], -32767
+; CHECK-NEXT:    [[MUL:%.*]] = sext i32 [[NARROW]] to i64
+; CHECK-NEXT:    ret i64 [[MUL]]
+;
+  %ashr = ashr i32 %V, 16
+  %sext = sext i32 %ashr to i64
+  %mul = mul i64 %sext, -32767
+  ret i64 %mul
+}
+
+define <2 x i64> @test9_splat(<2 x i32> %V) {
+; CHECK-LABEL: @test9_splat(
+; CHECK-NEXT:    [[ASHR:%.*]] = ashr <2 x i32> [[V:%.*]], <i32 16, i32 16>
+; CHECK-NEXT:    [[NARROW:%.*]] = mul nsw <2 x i32> [[ASHR]], <i32 -32767, i32 -32767>
+; CHECK-NEXT:    [[MUL:%.*]] = sext <2 x i32> [[NARROW]] to <2 x i64>
+; CHECK-NEXT:    ret <2 x i64> [[MUL]]
+;
+  %ashr = ashr <2 x i32> %V, <i32 16, i32 16>
+  %sext = sext <2 x i32> %ashr to <2 x i64>
+  %mul = mul <2 x i64> %sext, <i64 -32767, i64 -32767>
+  ret <2 x i64> %mul
+}
+
+define <2 x i64> @test9_vec(<2 x i32> %V) {
+; CHECK-LABEL: @test9_vec(
+; CHECK-NEXT:    [[ASHR:%.*]] = ashr <2 x i32> [[V:%.*]], <i32 16, i32 16>
+; CHECK-NEXT:    [[NARROW:%.*]] = mul nsw <2 x i32> [[ASHR]], <i32 -32767, i32 -10>
+; CHECK-NEXT:    [[MUL:%.*]] = sext <2 x i32> [[NARROW]] to <2 x i64>
+; CHECK-NEXT:    ret <2 x i64> [[MUL]]
+;
+  %ashr = ashr <2 x i32> %V, <i32 16, i32 16>
+  %sext = sext <2 x i32> %ashr to <2 x i64>
+  %mul = mul <2 x i64> %sext, <i64 -32767, i64 -10>
+  ret <2 x i64> %mul
+}
+
+define i64 @test10(i32 %V) {
+; CHECK-LABEL: @test10(
+; CHECK-NEXT:    [[LSHR:%.*]] = lshr i32 [[V:%.*]], 16
+; CHECK-NEXT:    [[NARROW:%.*]] = mul nuw i32 [[LSHR]], 65535
+; CHECK-NEXT:    [[MUL:%.*]] = zext i32 [[NARROW]] to i64
+; CHECK-NEXT:    ret i64 [[MUL]]
+;
+  %lshr = lshr i32 %V, 16
+  %zext = zext i32 %lshr to i64
+  %mul = mul i64 %zext, 65535
+  ret i64 %mul
+}
+
+define <2 x i64> @test10_splat(<2 x i32> %V) {
+; CHECK-LABEL: @test10_splat(
+; CHECK-NEXT:    [[LSHR:%.*]] = lshr <2 x i32> [[V:%.*]], <i32 16, i32 16>
+; CHECK-NEXT:    [[NARROW:%.*]] = mul nuw <2 x i32> [[LSHR]], <i32 65535, i32 65535>
+; CHECK-NEXT:    [[MUL:%.*]] = zext <2 x i32> [[NARROW]] to <2 x i64>
+; CHECK-NEXT:    ret <2 x i64> [[MUL]]
+;
+  %lshr = lshr <2 x i32> %V, <i32 16, i32 16>
+  %zext = zext <2 x i32> %lshr to <2 x i64>
+  %mul = mul <2 x i64> %zext, <i64 65535, i64 65535>
+  ret <2 x i64> %mul
+}
+
+define <2 x i64> @test10_vec(<2 x i32> %V) {
+; CHECK-LABEL: @test10_vec(
+; CHECK-NEXT:    [[LSHR:%.*]] = lshr <2 x i32> [[V:%.*]], <i32 16, i32 16>
+; CHECK-NEXT:    [[NARROW:%.*]] = mul nuw <2 x i32> [[LSHR]], <i32 65535, i32 2>
+; CHECK-NEXT:    [[MUL:%.*]] = zext <2 x i32> [[NARROW]] to <2 x i64>
+; CHECK-NEXT:    ret <2 x i64> [[MUL]]
+;
+  %lshr = lshr <2 x i32> %V, <i32 16, i32 16>
+  %zext = zext <2 x i32> %lshr to <2 x i64>
+  %mul = mul <2 x i64> %zext, <i64 65535, i64 2>
+  ret <2 x i64> %mul
+}
+
+define i64 @test11(i32 %V) {
+; CHECK-LABEL: @test11(
+; CHECK-NEXT:    [[CALL1:%.*]] = call i32 @callee(), !range !1
+; CHECK-NEXT:    [[CALL2:%.*]] = call i32 @callee(), !range !1
+; CHECK-NEXT:    [[NARROW:%.*]] = add nsw i32 [[CALL1]], [[CALL2]]
+; CHECK-NEXT:    [[ADD:%.*]] = sext i32 [[NARROW]] to i64
+; CHECK-NEXT:    ret i64 [[ADD]]
+;
+  %call1 = call i32 @callee(), !range !1
+  %call2 = call i32 @callee(), !range !1
+  %sext1 = sext i32 %call1 to i64
+  %sext2 = sext i32 %call2 to i64
+  %add = add i64 %sext1, %sext2
+  ret i64 %add
+}
+
+define i64 @test12(i32 %V) {
+; CHECK-LABEL: @test12(
+; CHECK-NEXT:    [[CALL1:%.*]] = call i32 @callee(), !range !1
+; CHECK-NEXT:    [[CALL2:%.*]] = call i32 @callee(), !range !1
+; CHECK-NEXT:    [[NARROW:%.*]] = mul nsw i32 [[CALL1]], [[CALL2]]
+; CHECK-NEXT:    [[TMP1:%.*]] = zext i32 [[NARROW]] to i64
+; CHECK-NEXT:    ret i64 [[TMP1]]
+;
+  %call1 = call i32 @callee(), !range !1
+  %call2 = call i32 @callee(), !range !1
+  %sext1 = sext i32 %call1 to i64
+  %sext2 = sext i32 %call2 to i64
+  %add = mul i64 %sext1, %sext2
+  ret i64 %add
+}
+
+define i64 @test13(i32 %V) {
+; CHECK-LABEL: @test13(
+; CHECK-NEXT:    [[CALL1:%.*]] = call i32 @callee(), !range !2
+; CHECK-NEXT:    [[CALL2:%.*]] = call i32 @callee(), !range !3
+; CHECK-NEXT:    [[SUBCONV:%.*]] = sub nsw i32 [[CALL1]], [[CALL2]]
+; CHECK-NEXT:    [[SUB:%.*]] = sext i32 [[SUBCONV]] to i64
+; CHECK-NEXT:    ret i64 [[SUB]]
+;
+  %call1 = call i32 @callee(), !range !2
+  %call2 = call i32 @callee(), !range !3
+  %sext1 = sext i32 %call1 to i64
+  %sext2 = sext i32 %call2 to i64
+  %sub = sub i64 %sext1, %sext2
+  ret i64 %sub
+}
+
+define i64 @test14(i32 %V) {
+; CHECK-LABEL: @test14(
+; CHECK-NEXT:    [[CALL1:%.*]] = call i32 @callee(), !range !2
+; CHECK-NEXT:    [[CALL2:%.*]] = call i32 @callee(), !range !0
+; CHECK-NEXT:    [[SUBCONV:%.*]] = sub nuw nsw i32 [[CALL1]], [[CALL2]]
+; CHECK-NEXT:    [[SUB:%.*]] = zext i32 [[SUBCONV]] to i64
+; CHECK-NEXT:    ret i64 [[SUB]]
+;
+  %call1 = call i32 @callee(), !range !2
+  %call2 = call i32 @callee(), !range !0
+  %zext1 = zext i32 %call1 to i64
+  %zext2 = zext i32 %call2 to i64
+  %sub = sub i64 %zext1, %zext2
+  ret i64 %sub
+}
+
+define i64 @test15(i32 %V) {
+; CHECK-LABEL: @test15(
+; CHECK-NEXT:    [[ASHR:%.*]] = ashr i32 [[V:%.*]], 1
+; CHECK-NEXT:    [[SUBCONV:%.*]] = sub nsw i32 8, [[ASHR]]
+; CHECK-NEXT:    [[SUB:%.*]] = sext i32 [[SUBCONV]] to i64
+; CHECK-NEXT:    ret i64 [[SUB]]
+;
+  %ashr = ashr i32 %V, 1
+  %sext = sext i32 %ashr to i64
+  %sub = sub i64 8, %sext
+  ret i64 %sub
+}
+
+define <2 x i64> @test15vec(<2 x i32> %V) {
+; CHECK-LABEL: @test15vec(
+; CHECK-NEXT:    [[ASHR:%.*]] = ashr <2 x i32> [[V:%.*]], <i32 1, i32 1>
+; CHECK-NEXT:    [[SUBCONV:%.*]] = sub nsw <2 x i32> <i32 8, i32 8>, [[ASHR]]
+; CHECK-NEXT:    [[SUB:%.*]] = sext <2 x i32> [[SUBCONV]] to <2 x i64>
+; CHECK-NEXT:    ret <2 x i64> [[SUB]]
+;
+  %ashr = ashr <2 x i32> %V, <i32 1, i32 1>
+  %sext = sext <2 x i32> %ashr to <2 x i64>
+  %sub = sub <2 x i64> <i64 8, i64 8>, %sext
+  ret <2 x i64> %sub
+}
+
+define i64 @test16(i32 %V) {
+; CHECK-LABEL: @test16(
+; CHECK-NEXT:    [[LSHR:%.*]] = lshr i32 [[V:%.*]], 1
+; CHECK-NEXT:    [[SUBCONV:%.*]] = sub nuw i32 -2, [[LSHR]]
+; CHECK-NEXT:    [[SUB:%.*]] = zext i32 [[SUBCONV]] to i64
+; CHECK-NEXT:    ret i64 [[SUB]]
+;
+  %lshr = lshr i32 %V, 1
+  %zext = zext i32 %lshr to i64
+  %sub = sub i64 4294967294, %zext
+  ret i64 %sub
+}
+
+define <2 x i64> @test16vec(<2 x i32> %V) {
+; CHECK-LABEL: @test16vec(
+; CHECK-NEXT:    [[LSHR:%.*]] = lshr <2 x i32> [[V:%.*]], <i32 1, i32 1>
+; CHECK-NEXT:    [[SUBCONV:%.*]] = sub nuw <2 x i32> <i32 -2, i32 -2>, [[LSHR]]
+; CHECK-NEXT:    [[SUB:%.*]] = zext <2 x i32> [[SUBCONV]] to <2 x i64>
+; CHECK-NEXT:    ret <2 x i64> [[SUB]]
+;
+  %lshr = lshr <2 x i32> %V, <i32 1, i32 1>
+  %zext = zext <2 x i32> %lshr to <2 x i64>
+  %sub = sub <2 x i64> <i64 4294967294, i64 4294967294>, %zext
+  ret <2 x i64> %sub
+}
+
+; Negative test. Both have the same range so we can't guarantee the subtract
+; won't wrap.
+define i64 @test17(i32 %V) {
+; CHECK-LABEL: @test17(
+; CHECK-NEXT:    [[CALL1:%.*]] = call i32 @callee(), !range !0
+; CHECK-NEXT:    [[CALL2:%.*]] = call i32 @callee(), !range !0
+; CHECK-NEXT:    [[SEXT1:%.*]] = zext i32 [[CALL1]] to i64
+; CHECK-NEXT:    [[SEXT2:%.*]] = zext i32 [[CALL2]] to i64
+; CHECK-NEXT:    [[SUB:%.*]] = sub nsw i64 [[SEXT1]], [[SEXT2]]
+; CHECK-NEXT:    ret i64 [[SUB]]
+;
+  %call1 = call i32 @callee(), !range !0
+  %call2 = call i32 @callee(), !range !0
+  %sext1 = zext i32 %call1 to i64
+  %sext2 = zext i32 %call2 to i64
+  %sub = sub i64 %sext1, %sext2
+  ret i64 %sub
+}
+
+; Negative test. LHS is large positive 32-bit number. Range of callee can
+; cause overflow.
+define i64 @test18(i32 %V) {
+; CHECK-LABEL: @test18(
+; CHECK-NEXT:    [[CALL1:%.*]] = call i32 @callee(), !range !1
+; CHECK-NEXT:    [[SEXT1:%.*]] = sext i32 [[CALL1]] to i64
+; CHECK-NEXT:    [[SUB:%.*]] = sub nsw i64 2147481648, [[SEXT1]]
+; CHECK-NEXT:    ret i64 [[SUB]]
+;
+  %call1 = call i32 @callee(), !range !1
+  %sext1 = sext i32 %call1 to i64
+  %sub = sub i64 2147481648, %sext1
+  ret i64 %sub
+}
+
+; Negative test. LHS is large negative 32-bit number. Range of callee can
+; cause overflow.
+define i64 @test19(i32 %V) {
+; CHECK-LABEL: @test19(
+; CHECK-NEXT:    [[CALL1:%.*]] = call i32 @callee(), !range !0
+; CHECK-NEXT:    [[TMP1:%.*]] = zext i32 [[CALL1]] to i64
+; CHECK-NEXT:    [[SUB:%.*]] = sub nuw nsw i64 -2147481648, [[TMP1]]
+; CHECK-NEXT:    ret i64 [[SUB]]
+;
+  %call1 = call i32 @callee(), !range !0
+  %sext1 = sext i32 %call1 to i64
+  %sub = sub i64 -2147481648, %sext1
+  ret i64 %sub
+}
+
+!0 = !{ i32 0, i32 2000 }
+!1 = !{ i32 -2000, i32 0 }
+!2 = !{ i32 -512, i32 -255 }
+!3 = !{ i32 -128, i32 0 }

Added: llvm/trunk/test/Transforms/InstCombine/narrow-switch.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/narrow-switch.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/narrow-switch.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/narrow-switch.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,262 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; Vary legal integer types in data layout.
+; RUN: opt < %s -instcombine -S -data-layout=n32    | FileCheck %s --check-prefix=ALL --check-prefix=CHECK32
+; RUN: opt < %s -instcombine -S -data-layout=n32:64 | FileCheck %s --check-prefix=ALL --check-prefix=CHECK64
+
+define i32 @positive1(i64 %a) {
+; ALL-LABEL: @positive1(
+; ALL:         switch i32
+; ALL-NEXT:    i32 10, label %return
+; ALL-NEXT:    i32 100, label %sw.bb1
+; ALL-NEXT:    i32 1001, label %sw.bb2
+; ALL-NEXT:    ]
+;
+entry:
+  %and = and i64 %a, 4294967295
+  switch i64 %and, label %sw.default [
+  i64 10, label %return
+  i64 100, label %sw.bb1
+  i64 1001, label %sw.bb2
+  ]
+
+sw.bb1:
+  br label %return
+
+sw.bb2:
+  br label %return
+
+sw.default:
+  br label %return
+
+return:
+  %retval.0 = phi i32 [ 24, %sw.default ], [ 123, %sw.bb2 ], [ 213, %sw.bb1 ], [ 231, %entry ]
+  ret i32 %retval.0
+}
+
+define i32 @negative1(i64 %a) {
+; ALL-LABEL: @negative1(
+; ALL:         switch i32
+; ALL-NEXT:    i32 -10, label %return
+; ALL-NEXT:    i32 -100, label %sw.bb1
+; ALL-NEXT:    i32 -1001, label %sw.bb2
+; ALL-NEXT:    ]
+;
+entry:
+  %or = or i64 %a, -4294967296
+  switch i64 %or, label %sw.default [
+  i64 -10, label %return
+  i64 -100, label %sw.bb1
+  i64 -1001, label %sw.bb2
+  ]
+
+sw.bb1:
+  br label %return
+
+sw.bb2:
+  br label %return
+
+sw.default:
+  br label %return
+
+return:
+  %retval.0 = phi i32 [ 24, %sw.default ], [ 123, %sw.bb2 ], [ 213, %sw.bb1 ], [ 231, %entry ]
+  ret i32 %retval.0
+}
+
+; Make sure truncating a constant int larger than 64-bit doesn't trigger an
+; assertion.
+
+define i32 @trunc72to68(i72 %a) {
+; ALL-LABEL: @trunc72to68(
+; ALL:         switch i68
+; ALL-NEXT:    i68 10, label %return
+; ALL-NEXT:    i68 100, label %sw.bb1
+; ALL-NEXT:    i68 1001, label %sw.bb2
+; ALL-NEXT:    ]
+;
+entry:
+  %and = and i72 %a, 295147905179352825855
+  switch i72 %and, label %sw.default [
+  i72 10, label %return
+  i72 100, label %sw.bb1
+  i72 1001, label %sw.bb2
+  ]
+
+sw.bb1:
+  br label %return
+
+sw.bb2:
+  br label %return
+
+sw.default:
+  br label %return
+
+return:
+  %retval.0 = phi i32 [ 24, %sw.default ], [ 123, %sw.bb2 ], [ 213, %sw.bb1 ], [ 231, %entry ]
+  ret i32 %retval.0
+}
+
+; Make sure to avoid assertion crashes and use the type before
+; truncation to generate the sub constant expressions that leads
+; to the recomputed condition.
+; We allow to truncate from i64 to i59 if in 32-bit mode,
+; because both are illegal.
+
+define void @trunc64to59(i64 %a) {
+; ALL-LABEL: @trunc64to59(
+; ALL-CHECK32:         switch i59
+; ALL-CHECK32-NEXT:    i59 0, label %sw.bb1
+; ALL-CHECK32-NEXT:    i59 18717182647723699, label %sw.bb2
+; ALL-CHECK32-NEXT:    ]
+; ALL-CHECK64:         switch i64
+; ALL-CHECK64-NEXT:    i64 0, label %sw.bb1
+; ALL-CHECK64-NEXT:    i64 18717182647723699, label %sw.bb2
+; ALL-CHECK64-NEXT:    ]
+;
+entry:
+  %tmp0 = and i64 %a, 15
+  %tmp1 = mul i64 %tmp0, -6425668444178048401
+  %tmp2 = add i64 %tmp1, 5170979678563097242
+  %tmp3 = mul i64 %tmp2, 1627972535142754813
+  switch i64 %tmp3, label %sw.default [
+  i64 847514119312061490, label %sw.bb1
+  i64 866231301959785189, label %sw.bb2
+  ]
+
+sw.bb1:
+  br label %sw.default
+
+sw.bb2:
+  br label %sw.default
+
+sw.default:
+  ret void
+}
+
+; https://llvm.org/bugs/show_bug.cgi?id=31260
+
+define i8 @PR31260(i8 %x) {
+; ALL-LABEL: @PR31260(
+; ALL-NEXT:  entry:
+; ALL-NEXT:    [[TMP0:%.*]] = trunc i8 %x to i2
+; ALL-NEXT:    [[TRUNC:%.*]] = and i2 [[TMP0]], -2
+; ALL-NEXT:    switch i2 [[TRUNC]], label %exit [
+; ALL-NEXT:    i2 0, label %case126
+; ALL-NEXT:    i2 -2, label %case124
+; ALL-NEXT:    ]
+; ALL:       exit:
+; ALL-NEXT:    ret i8 1
+; ALL:       case126:
+; ALL-NEXT:    ret i8 3
+; ALL:       case124:
+; ALL-NEXT:    ret i8 5
+;
+entry:
+  %t4 = and i8 %x, 2
+  %t5 = add nsw i8 %t4, -126
+  switch i8 %t5, label %exit [
+  i8 -126, label %case126
+  i8 -124, label %case124
+  ]
+
+exit:
+  ret i8 1
+case126:
+  ret i8 3
+case124:
+  ret i8 5
+}
+
+; Make sure the arithmetic evaluation of the switch
+; condition is evaluated on the original type
+define i32 @trunc32to16(i32 %a0) #0 {
+; ALL-LABEL: @trunc32to16(
+; ALL:         switch i16
+; ALL-NEXT:    i16 63, label %sw.bb
+; ALL-NEXT:    i16 1, label %sw.bb1
+; ALL-NEXT:    i16 100, label %sw.bb2
+; ALL-NEXT:    ]
+;
+entry:
+  %retval = alloca i32, align 4
+  %xor = xor i32 %a0, 1034460917
+  %shr = lshr i32 %xor, 16
+  %add = add i32 %shr, -917677090
+  switch i32 %add, label %sw.epilog [
+    i32 -917677027, label %sw.bb
+    i32 -917677089, label %sw.bb1
+    i32 -917676990, label %sw.bb2
+  ]
+
+sw.bb:                                            ; preds = %entry
+  store i32 90, i32* %retval, align 4
+  br label %return
+
+sw.bb1:                                           ; preds = %entry
+  store i32 91, i32* %retval, align 4
+  br label %return
+
+sw.bb2:                                           ; preds = %entry
+  store i32 92, i32* %retval, align 4
+  br label %return
+
+sw.epilog:                                        ; preds = %entry
+  store i32 113, i32* %retval, align 4
+  br label %return
+
+return:                                           ; preds = %sw.epilog, %sw.bb2,
+  %rval = load i32, i32* %retval, align 4
+  ret i32 %rval
+}
+
+; https://llvm.org/bugs/show_bug.cgi?id=29009
+
+ at a = global i32 0, align 4
+ at njob = global i32 0, align 4
+
+declare i32 @goo()
+
+; Make sure we do not shrink to illegal types (i3 in this case)
+; if original type is legal (i32 in this case)
+
+define void @PR29009() {
+; ALL-LABEL: @PR29009(
+; ALL:         switch i32
+; ALL-NEXT:    i32 0, label
+; ALL-NEXT:    i32 3, label
+; ALL-NEXT:    ]
+;
+  br label %1
+
+; <label>:1:                                      ; preds = %10, %0
+  %2 = load volatile i32, i32* @njob, align 4
+  %3 = icmp ne i32 %2, 0
+  br i1 %3, label %4, label %11
+
+; <label>:4:                                      ; preds = %1
+  %5 = call i32 @goo()
+  %6 = and i32 %5, 7
+  switch i32 %6, label %7 [
+    i32 0, label %8
+    i32 3, label %9
+  ]
+
+; <label>:7:                                      ; preds = %4
+  store i32 6, i32* @a, align 4
+  br label %10
+
+; <label>:8:                                      ; preds = %4
+  store i32 1, i32* @a, align 4
+  br label %10
+
+; <label>:9:                                      ; preds = %4
+  store i32 2, i32* @a, align 4
+  br label %10
+
+; <label>:10:                                     ; preds = %13, %12, %11, %10, %9, %8, %7
+  br label %1
+
+; <label>:11:                                     ; preds = %1
+  ret void
+}
+

Added: llvm/trunk/test/Transforms/InstCombine/narrow.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/narrow.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/narrow.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/narrow.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,239 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt < %s -instcombine -S | FileCheck %s
+
+target datalayout = "n8:16:32:64"
+
+; Eliminating the casts in this testcase (by narrowing the AND operation)
+; allows instcombine to realize the function always returns false.
+
+define i1 @test1(i32 %A, i32 %B) {
+; CHECK-LABEL: @test1(
+; CHECK-NEXT:    ret i1 false
+;
+  %C1 = icmp slt i32 %A, %B
+  %ELIM1 = zext i1 %C1 to i32
+  %C2 = icmp sgt i32 %A, %B
+  %ELIM2 = zext i1 %C2 to i32
+  %C3 = and i32 %ELIM1, %ELIM2
+  %ELIM3 = trunc i32 %C3 to i1
+  ret i1 %ELIM3
+}
+
+; The next 6 (3 logic ops * (scalar+vector)) tests show potential cases for narrowing a bitwise logic op.
+
+define i32 @shrink_xor(i64 %a) {
+; CHECK-LABEL: @shrink_xor(
+; CHECK-NEXT:    [[TMP1:%.*]] = trunc i64 [[A:%.*]] to i32
+; CHECK-NEXT:    [[TRUNC:%.*]] = xor i32 [[TMP1]], 1
+; CHECK-NEXT:    ret i32 [[TRUNC]]
+;
+  %xor = xor i64 %a, 1
+  %trunc = trunc i64 %xor to i32
+  ret i32 %trunc
+}
+
+; Vectors (with splat constants) should get the same transform.
+
+define <2 x i32> @shrink_xor_vec(<2 x i64> %a) {
+; CHECK-LABEL: @shrink_xor_vec(
+; CHECK-NEXT:    [[TMP1:%.*]] = trunc <2 x i64> [[A:%.*]] to <2 x i32>
+; CHECK-NEXT:    [[TRUNC:%.*]] = xor <2 x i32> [[TMP1]], <i32 2, i32 2>
+; CHECK-NEXT:    ret <2 x i32> [[TRUNC]]
+;
+  %xor = xor <2 x i64> %a, <i64 2, i64 2>
+  %trunc = trunc <2 x i64> %xor to <2 x i32>
+  ret <2 x i32> %trunc
+}
+
+; Source and dest types are not in the datalayout.
+
+define i3 @shrink_or(i6 %a) {
+; CHECK-LABEL: @shrink_or(
+; CHECK-NEXT:    [[TMP1:%.*]] = trunc i6 [[A:%.*]] to i3
+; CHECK-NEXT:    [[TRUNC:%.*]] = or i3 [[TMP1]], 1
+; CHECK-NEXT:    ret i3 [[TRUNC]]
+;
+  %or = or i6 %a, 33
+  %trunc = trunc i6 %or to i3
+  ret i3 %trunc
+}
+
+; Vectors (with non-splat constants) should get the same transform.
+
+define <2 x i8> @shrink_or_vec(<2 x i16> %a) {
+; CHECK-LABEL: @shrink_or_vec(
+; CHECK-NEXT:    [[TMP1:%.*]] = trunc <2 x i16> [[A:%.*]] to <2 x i8>
+; CHECK-NEXT:    [[TRUNC:%.*]] = or <2 x i8> [[TMP1]], <i8 -1, i8 0>
+; CHECK-NEXT:    ret <2 x i8> [[TRUNC]]
+;
+  %or = or <2 x i16> %a, <i16 -1, i16 256>
+  %trunc = trunc <2 x i16> %or to <2 x i8>
+  ret <2 x i8> %trunc
+}
+
+; We discriminate against weird types.
+
+define i31 @shrink_and(i64 %a) {
+; CHECK-LABEL: @shrink_and(
+; CHECK-NEXT:    [[AND:%.*]] = and i64 [[A:%.*]], 42
+; CHECK-NEXT:    [[TRUNC:%.*]] = trunc i64 [[AND]] to i31
+; CHECK-NEXT:    ret i31 [[TRUNC]]
+;
+  %and = and i64 %a, 42
+  %trunc = trunc i64 %and to i31
+  ret i31 %trunc
+}
+
+; Chop the top of the constant(s) if needed.
+
+define <2 x i32> @shrink_and_vec(<2 x i33> %a) {
+; CHECK-LABEL: @shrink_and_vec(
+; CHECK-NEXT:    [[TMP1:%.*]] = trunc <2 x i33> [[A:%.*]] to <2 x i32>
+; CHECK-NEXT:    [[TRUNC:%.*]] = and <2 x i32> [[TMP1]], <i32 0, i32 6>
+; CHECK-NEXT:    ret <2 x i32> [[TRUNC]]
+;
+  %and = and <2 x i33> %a, <i33 4294967296, i33 6>
+  %trunc = trunc <2 x i33> %and to <2 x i32>
+  ret <2 x i32> %trunc
+}
+
+; FIXME:
+; This is based on an 'any_of' loop construct.
+; By narrowing the phi and logic op, we simplify away the zext and the final icmp.
+
+define i1 @searchArray1(i32 %needle, i32* %haystack) {
+; CHECK-LABEL: @searchArray1(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    br label [[LOOP:%.*]]
+; CHECK:       loop:
+; CHECK-NEXT:    [[INDVAR:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[INDVAR_NEXT:%.*]], [[LOOP]] ]
+; CHECK-NEXT:    [[FOUND:%.*]] = phi i8 [ 0, [[ENTRY]] ], [ [[OR:%.*]], [[LOOP]] ]
+; CHECK-NEXT:    [[TMP0:%.*]] = sext i32 [[INDVAR]] to i64
+; CHECK-NEXT:    [[IDX:%.*]] = getelementptr i32, i32* [[HAYSTACK:%.*]], i64 [[TMP0]]
+; CHECK-NEXT:    [[LD:%.*]] = load i32, i32* [[IDX]], align 4
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp eq i32 [[LD]], [[NEEDLE:%.*]]
+; CHECK-NEXT:    [[ZEXT:%.*]] = zext i1 [[CMP1]] to i8
+; CHECK-NEXT:    [[OR]] = or i8 [[FOUND]], [[ZEXT]]
+; CHECK-NEXT:    [[INDVAR_NEXT]] = add i32 [[INDVAR]], 1
+; CHECK-NEXT:    [[EXITCOND:%.*]] = icmp eq i32 [[INDVAR_NEXT]], 1000
+; CHECK-NEXT:    br i1 [[EXITCOND]], label [[EXIT:%.*]], label [[LOOP]]
+; CHECK:       exit:
+; CHECK-NEXT:    [[TOBOOL:%.*]] = icmp ne i8 [[OR]], 0
+; CHECK-NEXT:    ret i1 [[TOBOOL]]
+;
+entry:
+  br label %loop
+
+loop:
+  %indvar = phi i32 [ 0, %entry ], [ %indvar.next, %loop ]
+  %found = phi i8 [ 0, %entry ], [ %or, %loop ]
+  %idx = getelementptr i32, i32* %haystack, i32 %indvar
+  %ld = load i32, i32* %idx
+  %cmp1 = icmp eq i32 %ld, %needle
+  %zext = zext i1 %cmp1 to i8
+  %or = or i8 %found, %zext
+  %indvar.next = add i32 %indvar, 1
+  %exitcond = icmp eq i32 %indvar.next, 1000
+  br i1 %exitcond, label %exit, label %loop
+
+exit:
+  %tobool = icmp ne i8 %or, 0
+  ret i1 %tobool
+}
+
+; FIXME:
+; This is based on an 'all_of' loop construct.
+; By narrowing the phi and logic op, we simplify away the zext and the final icmp.
+
+define i1 @searchArray2(i32 %hay, i32* %haystack) {
+; CHECK-LABEL: @searchArray2(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    br label [[LOOP:%.*]]
+; CHECK:       loop:
+; CHECK-NEXT:    [[INDVAR:%.*]] = phi i64 [ 0, [[ENTRY:%.*]] ], [ [[INDVAR_NEXT:%.*]], [[LOOP]] ]
+; CHECK-NEXT:    [[FOUND:%.*]] = phi i8 [ 1, [[ENTRY]] ], [ [[AND:%.*]], [[LOOP]] ]
+; CHECK-NEXT:    [[IDX:%.*]] = getelementptr i32, i32* [[HAYSTACK:%.*]], i64 [[INDVAR]]
+; CHECK-NEXT:    [[LD:%.*]] = load i32, i32* [[IDX]], align 4
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp eq i32 [[LD]], [[HAY:%.*]]
+; CHECK-NEXT:    [[ZEXT:%.*]] = zext i1 [[CMP1]] to i8
+; CHECK-NEXT:    [[AND]] = and i8 [[FOUND]], [[ZEXT]]
+; CHECK-NEXT:    [[INDVAR_NEXT]] = add i64 [[INDVAR]], 1
+; CHECK-NEXT:    [[EXITCOND:%.*]] = icmp eq i64 [[INDVAR_NEXT]], 1000
+; CHECK-NEXT:    br i1 [[EXITCOND]], label [[EXIT:%.*]], label [[LOOP]]
+; CHECK:       exit:
+; CHECK-NEXT:    [[TOBOOL:%.*]] = icmp ne i8 [[AND]], 0
+; CHECK-NEXT:    ret i1 [[TOBOOL]]
+;
+entry:
+  br label %loop
+
+loop:
+  %indvar = phi i64 [ 0, %entry ], [ %indvar.next, %loop ]
+  %found = phi i8 [ 1, %entry ], [ %and, %loop ]
+  %idx = getelementptr i32, i32* %haystack, i64 %indvar
+  %ld = load i32, i32* %idx
+  %cmp1 = icmp eq i32 %ld, %hay
+  %zext = zext i1 %cmp1 to i8
+  %and = and i8 %found, %zext
+  %indvar.next = add i64 %indvar, 1
+  %exitcond = icmp eq i64 %indvar.next, 1000
+  br i1 %exitcond, label %exit, label %loop
+
+exit:
+  %tobool = icmp ne i8 %and, 0
+  ret i1 %tobool
+}
+
+; FIXME:
+; Narrowing should work with an 'xor' and is not limited to bool types.
+
+define i32 @shrinkLogicAndPhi1(i8 %x, i1 %cond) {
+; CHECK-LABEL: @shrinkLogicAndPhi1(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    br i1 [[COND:%.*]], label [[IF:%.*]], label [[ENDIF:%.*]]
+; CHECK:       if:
+; CHECK-NEXT:    br label [[ENDIF]]
+; CHECK:       endif:
+; CHECK-NEXT:    [[PHI:%.*]] = phi i32 [ 21, [[ENTRY:%.*]] ], [ 33, [[IF]] ]
+; CHECK-NEXT:    [[ZEXT:%.*]] = zext i8 [[X:%.*]] to i32
+; CHECK-NEXT:    [[LOGIC:%.*]] = xor i32 [[PHI]], [[ZEXT]]
+; CHECK-NEXT:    ret i32 [[LOGIC]]
+;
+entry:
+  br i1 %cond, label %if, label %endif
+if:
+  br label %endif
+endif:
+  %phi = phi i32 [ 21, %entry], [ 33, %if ]
+  %zext = zext i8 %x to i32
+  %logic = xor i32 %phi, %zext
+  ret i32 %logic
+}
+
+; FIXME:
+; Narrowing should work with an 'xor' and is not limited to bool types.
+; Test that commuting the xor operands does not inhibit optimization.
+
+define i32 @shrinkLogicAndPhi2(i8 %x, i1 %cond) {
+; CHECK-LABEL: @shrinkLogicAndPhi2(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    br i1 [[COND:%.*]], label [[IF:%.*]], label [[ENDIF:%.*]]
+; CHECK:       if:
+; CHECK-NEXT:    br label [[ENDIF]]
+; CHECK:       endif:
+; CHECK-NEXT:    [[PHI:%.*]] = phi i32 [ 21, [[ENTRY:%.*]] ], [ 33, [[IF]] ]
+; CHECK-NEXT:    [[ZEXT:%.*]] = zext i8 [[X:%.*]] to i32
+; CHECK-NEXT:    [[LOGIC:%.*]] = xor i32 [[PHI]], [[ZEXT]]
+; CHECK-NEXT:    ret i32 [[LOGIC]]
+;
+entry:
+  br i1 %cond, label %if, label %endif
+if:
+  br label %endif
+endif:
+  %phi = phi i32 [ 21, %entry], [ 33, %if ]
+  %zext = zext i8 %x to i32
+  %logic = xor i32 %zext, %phi
+  ret i32 %logic
+}
+

Added: llvm/trunk/test/Transforms/InstCombine/no-negzero.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/no-negzero.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/no-negzero.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/no-negzero.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,33 @@
+; RUN: opt < %s -instcombine -S | FileCheck %s
+; ModuleID = '3555a.c'
+; sqrt(fabs) cannot be negative zero, so we should eliminate the fadd.
+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:128:128"
+target triple = "i386-apple-darwin9.8"
+
+; CHECK-LABEL: @mysqrt(
+; CHECK-NOT: fadd
+; CHECK: ret
+define double @mysqrt(double %x) nounwind {
+entry:
+  %x_addr = alloca double                         ; <double*> [#uses=2]
+  %retval = alloca double, align 8                ; <double*> [#uses=2]
+  %0 = alloca double, align 8                     ; <double*> [#uses=2]
+  %"alloca point" = bitcast i32 0 to i32          ; <i32> [#uses=0]
+  store double %x, double* %x_addr
+  %1 = load double, double* %x_addr, align 8              ; <double> [#uses=1]
+  %2 = call double @fabs(double %1) nounwind readnone ; <double> [#uses=1]
+  %3 = call double @sqrt(double %2) nounwind readonly ; <double> [#uses=1]
+  %4 = fadd double %3, 0.000000e+00               ; <double> [#uses=1]
+  store double %4, double* %0, align 8
+  %5 = load double, double* %0, align 8                   ; <double> [#uses=1]
+  store double %5, double* %retval, align 8
+  br label %return
+
+return:                                           ; preds = %entry
+  %retval1 = load double, double* %retval                 ; <double> [#uses=1]
+  ret double %retval1
+}
+
+declare double @fabs(double)
+
+declare double @sqrt(double) nounwind readonly

Added: llvm/trunk/test/Transforms/InstCombine/no_cgscc_assert.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/no_cgscc_assert.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/no_cgscc_assert.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/no_cgscc_assert.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,18 @@
+; RUN: opt < %s -inline -instcombine -S | FileCheck %s
+
+; PR21403: http://llvm.org/bugs/show_bug.cgi?id=21403
+; When the call to sqrtf is replaced by an intrinsic call to fabs,
+; it should not cause a problem in CGSCC. 
+
+define float @bar(float %f) #0 {
+  %mul = fmul fast float %f, %f
+  %call1 = call fast float @sqrtf(float %mul)
+  ret float %call1
+
+; CHECK-LABEL: @bar(
+; CHECK-NEXT: call fast float @llvm.fabs.f32
+; CHECK-NEXT: ret float
+}
+
+declare float @sqrtf(float)
+

Added: llvm/trunk/test/Transforms/InstCombine/no_sink_instruction.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/no_sink_instruction.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/no_sink_instruction.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/no_sink_instruction.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,19 @@
+; RUN: opt -instcombine -instcombine-code-sinking=0 -S < %s | FileCheck %s
+
+define i32 @test(i1 %C, i32 %A, i32 %B) {
+; CHECK-LABEL: @test(
+; CHECK: sdiv i32
+; CHECK-NEXT: add i32
+entry:
+        %tmp.2 = sdiv i32 %A, %B                ; <i32> [#uses=1]
+        %tmp.9 = add i32 %B, %A         ; <i32> [#uses=1]
+        br i1 %C, label %then, label %endif
+
+then:           ; preds = %entry
+; CHECK: ret i32
+        ret i32 %tmp.9
+
+endif:          ; preds = %entry
+; CHECK: ret i32
+        ret i32 %tmp.2
+}

Added: llvm/trunk/test/Transforms/InstCombine/non-integral-pointers.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/non-integral-pointers.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/non-integral-pointers.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/non-integral-pointers.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,92 @@
+; RUN: opt -instcombine -S < %s | FileCheck %s
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128-ni:4"
+target triple = "x86_64-unknown-linux-gnu"
+
+define i8 addrspace(4)* @f_0() {
+; CHECK-LABEL: @f_0(
+; CHECK: ret i8 addrspace(4)* getelementptr (i8, i8 addrspace(4)* null, i64 50)
+  %result = getelementptr i8, i8 addrspace(4)* null, i64 50
+  ret i8 addrspace(4)* %result
+}
+
+define i8 addrspace(3)* @f_1() {
+; inttoptr is fine here since addrspace(3) is integral.
+
+; CHECK-LABEL: @f_1(
+; CHECK: ret i8 addrspace(3)* inttoptr (i64 50 to i8 addrspace(3)*)
+  %result = getelementptr i8, i8 addrspace(3)* null, i64 50
+  ret i8 addrspace(3)* %result
+}
+
+define void @f_2(i8 addrspace(4)** %ptr0, i8 addrspace(4)** %ptr1) {
+; It is not okay to convert the load/store pair to load and store
+; integers, since pointers in address space 4 are non-integral.
+
+; CHECK-LABEL: @f_2(
+entry:
+; CHECK:  %val = load i8 addrspace(4)*, i8 addrspace(4)** %ptr0, align 8
+; CHECK:  store i8 addrspace(4)* %val, i8 addrspace(4)** %ptr1, align 8
+; CHECK-NOT: load i64
+; CHECK-NOT: store i64
+  %val = load i8 addrspace(4)*, i8 addrspace(4)** %ptr0
+  store i8 addrspace(4)* %val, i8 addrspace(4)** %ptr1
+  ret void
+}
+
+define void @f_3(i8 addrspace(3)** %ptr0, i8 addrspace(3)** %ptr1) {
+; It *is* okay to convert the load/store pair to load and store
+; integers, since pointers in address space 3 are integral.
+
+; CHECK-LABEL: @f_3(
+entry:
+; CHECK: load i64
+; CHECK:  store i64
+  %val = load i8 addrspace(3)*, i8 addrspace(3)** %ptr0
+  store i8 addrspace(3)* %val, i8 addrspace(3)** %ptr1
+  ret void
+}
+
+define i64 @g(i8 addrspace(4)** %gp) {
+  ; CHECK-LABEL: @g(
+  ; CHECK: load
+  %.pre = load i8 addrspace(4)*, i8 addrspace(4)** %gp, align 8
+  %v74 = call i8 addrspace(4)* @alloc()
+  %v75 = addrspacecast i8 addrspace(4)* %v74 to i8*
+  %v76 = bitcast i8* %v75 to i8 addrspace(4)**
+  %v77 = getelementptr i8 addrspace(4)*, i8 addrspace(4)** %v76, i64 -1
+  ; CHECK: store
+  store i8 addrspace(4)* %.pre, i8 addrspace(4)** %v77, align 8
+  %v80 = bitcast i8 addrspace(4)** %v77 to i64*
+  ; CHECK: load
+  ; CHECK-NOT: ptrtoint
+  %v81 = load i64, i64* %v80, align 8
+  ret i64 %v81
+}
+
+define i64 @g2(i8* addrspace(4)* %gp) {
+  ; CHECK-LABEL: @g2(
+  ; CHECK: load
+  %.pre = load i8*, i8* addrspace(4)* %gp, align 8
+  %v74 = call i8 addrspace(4)* @alloc()
+  %v76 = bitcast i8 addrspace(4)* %v74 to i8* addrspace(4)*
+  %v77 = getelementptr i8*, i8* addrspace(4)* %v76, i64 -1
+  ; CHECK: store
+  store i8* %.pre, i8* addrspace(4)* %v77, align 8
+  %v80 = bitcast i8* addrspace(4)* %v77 to i64 addrspace(4)*
+  ; CHECK-NOT: store
+  %v81 = load i64, i64 addrspace(4)* %v80, align 8
+  ret i64 %v81
+}
+
+declare i8 addrspace(4)* @alloc()
+
+define i64 @f_4(i8 addrspace(4)* %v0) {
+  ; CHECK-LABEL: @f_4(
+  ; CHECK-NOT: ptrtoint
+  %v5 = bitcast i64 (i64)* @f_5 to i64 (i8 addrspace(4)*)*
+  %v6 = call i64 %v5(i8 addrspace(4)* %v0)
+  ret i64 %v6
+}
+
+declare i64 @f_5(i64)

Added: llvm/trunk/test/Transforms/InstCombine/nonnull-attribute.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/nonnull-attribute.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/nonnull-attribute.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/nonnull-attribute.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,19 @@
+; RUN: opt < %s -instcombine -S | FileCheck %s
+
+; This test makes sure that we do not assume globals in address spaces other
+; than 0 are able to be null.
+
+ at as0 = external global i32
+ at as1 = external addrspace(1) global i32
+
+declare void @addrspace0(i32*)
+declare void @addrspace1(i32 addrspace(1)*)
+
+; CHECK: call void @addrspace0(i32* nonnull @as0)
+; CHECK: call void @addrspace1(i32 addrspace(1)* @as1)
+
+define void @test() {
+  call void @addrspace0(i32* @as0)
+  call void @addrspace1(i32 addrspace(1)* @as1)
+  ret void
+}

Added: llvm/trunk/test/Transforms/InstCombine/not.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/not.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/not.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/not.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,253 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt < %s -instcombine -S | FileCheck %s
+
+define i32 @test1(i32 %A) {
+; CHECK-LABEL: @test1(
+; CHECK-NEXT:    ret i32 [[A:%.*]]
+;
+  %B = xor i32 %A, -1
+  %C = xor i32 %B, -1
+  ret i32 %C
+}
+
+define i1 @invert_icmp(i32 %A, i32 %B) {
+; CHECK-LABEL: @invert_icmp(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt i32 [[A:%.*]], [[B:%.*]]
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %cmp = icmp sle i32 %A, %B
+  %not = xor i1 %cmp, true
+  ret i1 %not
+}
+
+; PR1570
+
+define i1 @invert_fcmp(float %X, float %Y) {
+; CHECK-LABEL: @invert_fcmp(
+; CHECK-NEXT:    [[CMP:%.*]] = fcmp uge float [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %cmp = fcmp olt float %X, %Y
+  %not = xor i1 %cmp, true
+  ret i1 %not
+}
+
+; PR2298
+
+define i1 @not_not_cmp(i32 %a, i32 %b) {
+; CHECK-LABEL: @not_not_cmp(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i32 [[B:%.*]], [[A:%.*]]
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %nota = xor i32 %a, -1
+  %notb = xor i32 %b, -1
+  %cmp = icmp slt i32 %nota, %notb
+  ret i1 %cmp
+}
+
+define <2 x i1> @not_not_cmp_vector(<2 x i32> %a, <2 x i32> %b) {
+; CHECK-LABEL: @not_not_cmp_vector(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ugt <2 x i32> [[B:%.*]], [[A:%.*]]
+; CHECK-NEXT:    ret <2 x i1> [[CMP]]
+;
+  %nota = xor <2 x i32> %a, <i32 -1, i32 -1>
+  %notb = xor <2 x i32> %b, <i32 -1, i32 -1>
+  %cmp = icmp ugt <2 x i32> %nota, %notb
+  ret <2 x i1> %cmp
+}
+
+define i1 @not_cmp_constant(i32 %a) {
+; CHECK-LABEL: @not_cmp_constant(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i32 [[A:%.*]], -43
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %nota = xor i32 %a, -1
+  %cmp = icmp ugt i32 %nota, 42
+  ret i1 %cmp
+}
+
+define <2 x i1> @not_cmp_constant_vector(<2 x i32> %a) {
+; CHECK-LABEL: @not_cmp_constant_vector(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt <2 x i32> [[A:%.*]], <i32 -43, i32 -43>
+; CHECK-NEXT:    ret <2 x i1> [[CMP]]
+;
+  %nota = xor <2 x i32> %a, <i32 -1, i32 -1>
+  %cmp = icmp slt <2 x i32> %nota, <i32 42, i32 42>
+  ret <2 x i1> %cmp
+}
+
+define <2 x i1> @test7(<2 x i32> %A, <2 x i32> %B) {
+; CHECK-LABEL: @test7(
+; CHECK-NEXT:    [[COND:%.*]] = icmp sgt <2 x i32> [[A:%.*]], [[B:%.*]]
+; CHECK-NEXT:    ret <2 x i1> [[COND]]
+;
+  %cond = icmp sle <2 x i32> %A, %B
+  %Ret = xor <2 x i1> %cond, <i1 true, i1 true>
+  ret <2 x i1> %Ret
+}
+
+define i32 @not_ashr_not(i32 %A, i32 %B) {
+; CHECK-LABEL: @not_ashr_not(
+; CHECK-NEXT:    [[NOT2:%.*]] = ashr i32 [[A:%.*]], [[B:%.*]]
+; CHECK-NEXT:    ret i32 [[NOT2]]
+;
+  %not1 = xor i32 %A, -1
+  %ashr = ashr i32 %not1, %B
+  %not2 = xor i32 %ashr, -1
+  ret i32 %not2
+}
+
+define i8 @not_ashr_const(i8 %x) {
+; CHECK-LABEL: @not_ashr_const(
+; CHECK-NEXT:    [[NOT:%.*]] = lshr i8 41, [[X:%.*]]
+; CHECK-NEXT:    ret i8 [[NOT]]
+;
+  %shr = ashr i8 -42, %x
+  %not = xor i8 %shr, -1
+  ret i8 %not
+}
+
+define <2 x i8> @not_ashr_const_splat(<2 x i8> %x) {
+; CHECK-LABEL: @not_ashr_const_splat(
+; CHECK-NEXT:    [[NOT:%.*]] = lshr <2 x i8> <i8 41, i8 41>, [[X:%.*]]
+; CHECK-NEXT:    ret <2 x i8> [[NOT]]
+;
+  %shr = ashr <2 x i8> <i8 -42, i8 -42>, %x
+  %not = xor <2 x i8> %shr, <i8 -1, i8 -1>
+  ret <2 x i8> %not
+}
+
+; We can't get rid of the 'not' on a logical shift of a negative constant.
+
+define i8 @not_lshr_const_negative(i8 %x) {
+; CHECK-LABEL: @not_lshr_const_negative(
+; CHECK-NEXT:    [[SHR:%.*]] = lshr i8 -42, [[X:%.*]]
+; CHECK-NEXT:    [[NOT:%.*]] = xor i8 [[SHR]], -1
+; CHECK-NEXT:    ret i8 [[NOT]]
+;
+  %shr = lshr i8 -42, %x
+  %not = xor i8 %shr, -1
+  ret i8 %not
+}
+
+define i8 @not_lshr_const(i8 %x) {
+; CHECK-LABEL: @not_lshr_const(
+; CHECK-NEXT:    [[NOT:%.*]] = ashr i8 -43, [[X:%.*]]
+; CHECK-NEXT:    ret i8 [[NOT]]
+;
+  %shr = lshr i8 42, %x
+  %not = xor i8 %shr, -1
+  ret i8 %not
+}
+
+define <2 x i8> @not_lshr_const_splat(<2 x i8> %x) {
+; CHECK-LABEL: @not_lshr_const_splat(
+; CHECK-NEXT:    [[NOT:%.*]] = ashr <2 x i8> <i8 -43, i8 -43>, [[X:%.*]]
+; CHECK-NEXT:    ret <2 x i8> [[NOT]]
+;
+  %shr = lshr <2 x i8> <i8 42, i8 42>, %x
+  %not = xor <2 x i8> %shr, <i8 -1, i8 -1>
+  ret <2 x i8> %not
+}
+
+define i32 @not_sub(i32 %y) {
+; CHECK-LABEL: @not_sub(
+; CHECK-NEXT:    [[R:%.*]] = add i32 [[Y:%.*]], -124
+; CHECK-NEXT:    ret i32 [[R]]
+;
+  %s = sub i32 123, %y
+  %r = xor i32 %s, -1
+  ret i32 %r
+}
+
+define i32 @not_sub_extra_use(i32 %y, i32* %p) {
+; CHECK-LABEL: @not_sub_extra_use(
+; CHECK-NEXT:    [[S:%.*]] = sub i32 123, [[Y:%.*]]
+; CHECK-NEXT:    store i32 [[S]], i32* [[P:%.*]], align 4
+; CHECK-NEXT:    [[R:%.*]] = add i32 [[Y]], -124
+; CHECK-NEXT:    ret i32 [[R]]
+;
+  %s = sub i32 123, %y
+  store i32 %s, i32* %p
+  %r = xor i32 %s, -1
+  ret i32 %r
+}
+
+define <2 x i32> @not_sub_splat(<2 x i32> %y) {
+; CHECK-LABEL: @not_sub_splat(
+; CHECK-NEXT:    [[R:%.*]] = add <2 x i32> [[Y:%.*]], <i32 -124, i32 -124>
+; CHECK-NEXT:    ret <2 x i32> [[R]]
+;
+  %s = sub <2 x i32> <i32 123, i32 123>, %y
+  %r = xor <2 x i32> %s, <i32 -1, i32 -1>
+  ret <2 x i32> %r
+}
+
+define <2 x i32> @not_sub_extra_use_splat(<2 x i32> %y, <2 x i32>* %p) {
+; CHECK-LABEL: @not_sub_extra_use_splat(
+; CHECK-NEXT:    [[S:%.*]] = sub <2 x i32> <i32 123, i32 123>, [[Y:%.*]]
+; CHECK-NEXT:    store <2 x i32> [[S]], <2 x i32>* [[P:%.*]], align 8
+; CHECK-NEXT:    [[R:%.*]] = add <2 x i32> [[Y]], <i32 -124, i32 -124>
+; CHECK-NEXT:    ret <2 x i32> [[R]]
+;
+  %s = sub <2 x i32> <i32 123, i32 123>, %y
+  store <2 x i32> %s, <2 x i32>* %p
+  %r = xor <2 x i32> %s, <i32 -1, i32 -1>
+  ret <2 x i32> %r
+}
+
+define <2 x i32> @not_sub_vec(<2 x i32> %y) {
+; CHECK-LABEL: @not_sub_vec(
+; CHECK-NEXT:    [[R:%.*]] = add <2 x i32> [[Y:%.*]], <i32 -43, i32 -124>
+; CHECK-NEXT:    ret <2 x i32> [[R]]
+;
+  %s = sub <2 x i32> <i32 42, i32 123>, %y
+  %r = xor <2 x i32> %s, <i32 -1, i32 -1>
+  ret <2 x i32> %r
+}
+
+define <2 x i32> @not_sub_extra_use_vec(<2 x i32> %y, <2 x i32>* %p) {
+; CHECK-LABEL: @not_sub_extra_use_vec(
+; CHECK-NEXT:    [[S:%.*]] = sub <2 x i32> <i32 123, i32 42>, [[Y:%.*]]
+; CHECK-NEXT:    store <2 x i32> [[S]], <2 x i32>* [[P:%.*]], align 8
+; CHECK-NEXT:    [[R:%.*]] = add <2 x i32> [[Y]], <i32 -124, i32 -43>
+; CHECK-NEXT:    ret <2 x i32> [[R]]
+;
+  %s = sub <2 x i32> <i32 123, i32 42>, %y
+  store <2 x i32> %s, <2 x i32>* %p
+  %r = xor <2 x i32> %s, <i32 -1, i32 -1>
+  ret <2 x i32> %r
+}
+
+; ~(X + C) --> -X - C - 1 --> -(C + 1) - X
+
+define i32 @not_add(i32 %x) {
+; CHECK-LABEL: @not_add(
+; CHECK-NEXT:    [[R:%.*]] = sub i32 -124, [[X:%.*]]
+; CHECK-NEXT:    ret i32 [[R]]
+;
+  %a = add i32 %x, 123
+  %r = xor i32 %a, -1
+  ret i32 %r
+}
+
+define <2 x i32> @not_add_splat(<2 x i32> %x) {
+; CHECK-LABEL: @not_add_splat(
+; CHECK-NEXT:    [[R:%.*]] = sub <2 x i32> <i32 -124, i32 -124>, [[X:%.*]]
+; CHECK-NEXT:    ret <2 x i32> [[R]]
+;
+  %a = add <2 x i32> %x, <i32 123, i32 123>
+  %r = xor <2 x i32> %a, <i32 -1, i32 -1>
+  ret <2 x i32> %r
+}
+
+define <2 x i32> @not_add_vec(<2 x i32> %x) {
+; CHECK-LABEL: @not_add_vec(
+; CHECK-NEXT:    [[R:%.*]] = sub <2 x i32> <i32 -43, i32 -124>, [[X:%.*]]
+; CHECK-NEXT:    ret <2 x i32> [[R]]
+;
+  %a = add <2 x i32> %x, <i32 42, i32 123>
+  %r = xor <2 x i32> %a, <i32 -1, i32 -1>
+  ret <2 x i32> %r
+}
+

Added: llvm/trunk/test/Transforms/InstCombine/nothrow.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/nothrow.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/nothrow.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/nothrow.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,8 @@
+; RUN: opt < %s -instcombine -S | not grep call
+; rdar://6880732
+declare double @t1(i32) readonly
+
+define void @t2() nounwind {
+  call double @t1(i32 42)  ;; dead call even though callee is not nothrow.
+  ret void
+}

Added: llvm/trunk/test/Transforms/InstCombine/nsw.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/nsw.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/nsw.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/nsw.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,132 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt < %s -instcombine -S | FileCheck %s
+
+define i32 @sub1(i32 %x) {
+; CHECK-LABEL: @sub1(
+; CHECK-NEXT:    [[Y:%.*]] = sub i32 0, [[X:%.*]]
+; CHECK-NEXT:    [[Z:%.*]] = sdiv i32 [[Y]], 337
+; CHECK-NEXT:    ret i32 [[Z]]
+;
+  %y = sub i32 0, %x
+  %z = sdiv i32 %y, 337
+  ret i32 %z
+}
+
+define i32 @sub2(i32 %x) {
+; CHECK-LABEL: @sub2(
+; CHECK-NEXT:    [[Z:%.*]] = sdiv i32 [[X:%.*]], -337
+; CHECK-NEXT:    ret i32 [[Z]]
+;
+  %y = sub nsw i32 0, %x
+  %z = sdiv i32 %y, 337
+  ret i32 %z
+}
+
+define i1 @shl_icmp(i64 %X) {
+; CHECK-LABEL: @shl_icmp(
+; CHECK-NEXT:    [[B:%.*]] = icmp eq i64 [[X:%.*]], 0
+; CHECK-NEXT:    ret i1 [[B]]
+;
+  %A = shl nuw i64 %X, 2   ; X/4
+  %B = icmp eq i64 %A, 0
+  ret i1 %B
+}
+
+define i64 @shl1(i64 %X, i64* %P) {
+; CHECK-LABEL: @shl1(
+; CHECK-NEXT:    [[A:%.*]] = and i64 [[X:%.*]], 312
+; CHECK-NEXT:    store i64 [[A]], i64* [[P:%.*]], align 4
+; CHECK-NEXT:    [[B:%.*]] = shl nuw nsw i64 [[A]], 8
+; CHECK-NEXT:    ret i64 [[B]]
+;
+  %A = and i64 %X, 312
+  store i64 %A, i64* %P  ; multiple uses of A.
+  %B = shl i64 %A, 8
+  ret i64 %B
+}
+
+define i32 @preserve1(i32 %x) {
+; CHECK-LABEL: @preserve1(
+; CHECK-NEXT:    [[ADD3:%.*]] = add nsw i32 [[X:%.*]], 5
+; CHECK-NEXT:    ret i32 [[ADD3]]
+;
+  %add = add nsw i32 %x, 2
+  %add3 = add nsw i32 %add, 3
+  ret i32 %add3
+}
+
+define i8 @nopreserve1(i8 %x) {
+; CHECK-LABEL: @nopreserve1(
+; CHECK-NEXT:    [[ADD3:%.*]] = add i8 [[X:%.*]], -126
+; CHECK-NEXT:    ret i8 [[ADD3]]
+;
+  %add = add nsw i8 %x, 127
+  %add3 = add nsw i8 %add, 3
+  ret i8 %add3
+}
+
+define i8 @nopreserve2(i8 %x) {
+; CHECK-LABEL: @nopreserve2(
+; CHECK-NEXT:    [[ADD3:%.*]] = add i8 [[X:%.*]], 3
+; CHECK-NEXT:    ret i8 [[ADD3]]
+;
+  %add = add i8 %x, 1
+  %add3 = add nsw i8 %add, 2
+  ret i8 %add3
+}
+
+define i8 @nopreserve3(i8 %A, i8 %B) {
+; CHECK-LABEL: @nopreserve3(
+; CHECK-NEXT:    [[Y:%.*]] = add i8 [[A:%.*]], [[B:%.*]]
+; CHECK-NEXT:    [[ADD:%.*]] = add i8 [[Y]], 20
+; CHECK-NEXT:    ret i8 [[ADD]]
+;
+  %x = add i8 %A, 10
+  %y = add i8 %B, 10
+  %add = add nsw i8 %x, %y
+  ret i8 %add
+}
+
+define i8 @nopreserve4(i8 %A, i8 %B) {
+; CHECK-LABEL: @nopreserve4(
+; CHECK-NEXT:    [[Y:%.*]] = add i8 [[A:%.*]], [[B:%.*]]
+; CHECK-NEXT:    [[ADD:%.*]] = add i8 [[Y]], 20
+; CHECK-NEXT:    ret i8 [[ADD]]
+;
+  %x = add nsw i8 %A, 10
+  %y = add nsw i8 %B, 10
+  %add = add nsw i8 %x, %y
+  ret i8 %add
+}
+
+; TODO: computeKnownBits() should look through a shufflevector.
+
+define <3 x i32> @shl_nuw_nsw_shuffle_splat_vec(<2 x i8> %x) {
+; CHECK-LABEL: @shl_nuw_nsw_shuffle_splat_vec(
+; CHECK-NEXT:    [[T2:%.*]] = zext <2 x i8> [[X:%.*]] to <2 x i32>
+; CHECK-NEXT:    [[SHUF:%.*]] = shufflevector <2 x i32> [[T2]], <2 x i32> undef, <3 x i32> <i32 1, i32 0, i32 1>
+; CHECK-NEXT:    [[T3:%.*]] = shl nsw <3 x i32> [[SHUF]], <i32 17, i32 17, i32 17>
+; CHECK-NEXT:    ret <3 x i32> [[T3]]
+;
+  %t2 = zext <2 x i8> %x to <2 x i32>
+  %shuf = shufflevector <2 x i32> %t2, <2 x i32> undef, <3 x i32> <i32 1, i32 0, i32 1>
+  %t3 = shl <3 x i32> %shuf, <i32 17, i32 17, i32 17>
+  ret <3 x i32> %t3
+}
+
+; Negative test - if the shuffle mask contains an undef, we bail out to
+; avoid propagating information that may not be used consistently by callers.
+
+define <3 x i32> @shl_nuw_nsw_shuffle_undef_elt_splat_vec(<2 x i8> %x) {
+; CHECK-LABEL: @shl_nuw_nsw_shuffle_undef_elt_splat_vec(
+; CHECK-NEXT:    [[T2:%.*]] = zext <2 x i8> [[X:%.*]] to <2 x i32>
+; CHECK-NEXT:    [[SHUF:%.*]] = shufflevector <2 x i32> [[T2]], <2 x i32> undef, <3 x i32> <i32 1, i32 undef, i32 0>
+; CHECK-NEXT:    [[T3:%.*]] = shl <3 x i32> [[SHUF]], <i32 17, i32 17, i32 17>
+; CHECK-NEXT:    ret <3 x i32> [[T3]]
+;
+  %t2 = zext <2 x i8> %x to <2 x i32>
+  %shuf = shufflevector <2 x i32> %t2, <2 x i32> undef, <3 x i32> <i32 1, i32 undef, i32 0>
+  %t3 = shl <3 x i32> %shuf, <i32 17, i32 17, i32 17>
+  ret <3 x i32> %t3
+}
+

Added: llvm/trunk/test/Transforms/InstCombine/obfuscated_splat.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/obfuscated_splat.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/obfuscated_splat.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/obfuscated_splat.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,11 @@
+; RUN: opt -instcombine -S < %s | FileCheck %s
+
+define void @test(<4 x float> *%in_ptr, <4 x float> *%out_ptr) {
+  %A = load <4 x float>, <4 x float>* %in_ptr, align 16
+  %B = shufflevector <4 x float> %A, <4 x float> undef, <4 x i32> <i32 0, i32 0, i32 undef, i32 undef>
+  %C = shufflevector <4 x float> %B, <4 x float> %A, <4 x i32> <i32 0, i32 1, i32 4, i32 undef>
+  %D = shufflevector <4 x float> %C, <4 x float> %A, <4 x i32> <i32 0, i32 1, i32 2, i32 4>
+; CHECK:  %D = shufflevector <4 x float> %A, <4 x float> undef, <4 x i32> zeroinitializer
+  store <4 x float> %D, <4 x float> *%out_ptr
+  ret void
+}

Added: llvm/trunk/test/Transforms/InstCombine/objsize-64.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/objsize-64.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/objsize-64.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/objsize-64.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,39 @@
+; RUN: opt < %s -instcombine -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"
+
+declare noalias i8* @malloc(i32) nounwind
+declare noalias i8* @_Znwm(i64)  ; new(unsigned long)
+declare i32 @__gxx_personality_v0(...)
+declare void @__cxa_call_unexpected(i8*)
+declare i64 @llvm.objectsize.i64(i8*, i1) nounwind readonly
+
+; CHECK-LABEL: @f1(
+define i64 @f1(i8 **%esc) {
+  %call = call i8* @malloc(i32 4)
+  store i8* %call, i8** %esc
+  %size = call i64 @llvm.objectsize.i64(i8* %call, i1 false)
+; CHECK: ret i64 4
+  ret i64 %size
+}
+
+
+; CHECK-LABEL: @f2(
+define i64 @f2(i8** %esc) nounwind uwtable ssp personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) {
+entry:
+; CHECK: invoke noalias i8* @_Znwm(i64 13)
+  %call = invoke noalias i8* @_Znwm(i64 13)
+          to label %invoke.cont unwind label %lpad
+
+invoke.cont:
+; CHECK: ret i64 13
+  store i8* %call, i8** %esc
+  %0 = tail call i64 @llvm.objectsize.i64(i8* %call, i1 false)
+  ret i64 %0
+
+lpad:
+  %1 = landingpad { i8*, i32 }
+          filter [0 x i8*] zeroinitializer
+  %2 = extractvalue { i8*, i32 } %1, 0
+  tail call void @__cxa_call_unexpected(i8* %2) noreturn nounwind
+  unreachable
+}

Added: llvm/trunk/test/Transforms/InstCombine/objsize-address-space.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/objsize-address-space.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/objsize-address-space.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/objsize-address-space.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,80 @@
+; RUN: opt -S -instcombine -o - %s | FileCheck %s
+target datalayout = "e-p:32:32:32-p1:64:64:64-p2:8:8:8-p3:16:16:16-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:32"
+
+declare i32 @llvm.objectsize.i32.p0i8(i8*, i1) nounwind readonly
+declare i32 @llvm.objectsize.i32.p1i8(i8 addrspace(1)*, i1) nounwind readonly
+declare i32 @llvm.objectsize.i32.p2i8(i8 addrspace(2)*, i1) nounwind readonly
+declare i32 @llvm.objectsize.i32.p3i8(i8 addrspace(3)*, i1) nounwind readonly
+declare i16 @llvm.objectsize.i16.p3i8(i8 addrspace(3)*, i1) nounwind readonly
+
+ at array_as2 = private addrspace(2) global [60 x i8] zeroinitializer, align 4
+
+ at array_as1_pointers = private global [10 x i32 addrspace(1)*] zeroinitializer, align 4
+ at array_as2_pointers = private global [24 x i32 addrspace(2)*] zeroinitializer, align 4
+ at array_as3_pointers = private global [42 x i32 addrspace(3)*] zeroinitializer, align 4
+
+ at array_as2_as1_pointer_pointers = private global [16 x i32 addrspace(2)* addrspace(1)*] zeroinitializer, align 4
+
+
+ at a_as3 = private addrspace(3) global [60 x i8] zeroinitializer, align 1
+
+define i32 @foo_as3() nounwind {
+; CHECK-LABEL: @foo_as3(
+; CHECK-NEXT: ret i32 60
+  %1 = call i32 @llvm.objectsize.i32.p3i8(i8 addrspace(3)* getelementptr inbounds ([60 x i8], [60 x i8] addrspace(3)* @a_as3, i32 0, i32 0), i1 false)
+  ret i32 %1
+}
+
+define i16 @foo_as3_i16() nounwind {
+; CHECK-LABEL: @foo_as3_i16(
+; CHECK-NEXT: ret i16 60
+  %1 = call i16 @llvm.objectsize.i16.p3i8(i8 addrspace(3)* getelementptr inbounds ([60 x i8], [60 x i8] addrspace(3)* @a_as3, i32 0, i32 0), i1 false)
+  ret i16 %1
+}
+
+ at a_alias = weak alias [60 x i8], [60 x i8] addrspace(3)* @a_as3
+define i32 @foo_alias() nounwind {
+  %1 = call i32 @llvm.objectsize.i32.p3i8(i8 addrspace(3)* getelementptr inbounds ([60 x i8], [60 x i8] addrspace(3)* @a_alias, i32 0, i32 0), i1 false)
+  ret i32 %1
+}
+
+define i32 @array_as2_size() {
+; CHECK-LABEL: @array_as2_size(
+; CHECK-NEXT: ret i32 60
+  %bc = bitcast [60 x i8] addrspace(2)* @array_as2 to i8 addrspace(2)*
+  %1 = call i32 @llvm.objectsize.i32.p2i8(i8 addrspace(2)* %bc, i1 false)
+  ret i32 %1
+}
+
+define i32 @pointer_array_as1() {
+; CHECK-LABEL: @pointer_array_as1(
+; CHECK-NEXT: ret i32 80
+  %bc = addrspacecast [10 x i32 addrspace(1)*]* @array_as1_pointers to i8 addrspace(1)*
+  %1 = call i32 @llvm.objectsize.i32.p1i8(i8 addrspace(1)* %bc, i1 false)
+  ret i32 %1
+}
+
+define i32 @pointer_array_as2() {
+; CHECK-LABEL: @pointer_array_as2(
+; CHECK-NEXT: ret i32 24
+  %bc = bitcast [24 x i32 addrspace(2)*]* @array_as2_pointers to i8*
+  %1 = call i32 @llvm.objectsize.i32.p0i8(i8* %bc, i1 false)
+  ret i32 %1
+}
+
+define i32 @pointer_array_as3() {
+; CHECK-LABEL: @pointer_array_as3(
+; CHECK-NEXT: ret i32 84
+  %bc = bitcast [42 x i32 addrspace(3)*]* @array_as3_pointers to i8*
+  %1 = call i32 @llvm.objectsize.i32.p0i8(i8* %bc, i1 false)
+  ret i32 %1
+}
+
+define i32 @pointer_pointer_array_as2_as1() {
+; CHECK-LABEL: @pointer_pointer_array_as2_as1(
+; CHECK-NEXT: ret i32 128
+  %bc = bitcast [16 x i32 addrspace(2)* addrspace(1)*]* @array_as2_as1_pointer_pointers to i8*
+  %1 = call i32 @llvm.objectsize.i32.p0i8(i8* %bc, i1 false)
+  ret i32 %1
+}
+

Added: llvm/trunk/test/Transforms/InstCombine/objsize-noverify.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/objsize-noverify.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/objsize-noverify.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/objsize-noverify.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,43 @@
+; Test objectsize bounds checking that won't verify until after -instcombine.
+; RUN: opt < %s -disable-verify -instcombine -S | opt -S | FileCheck %s
+; We need target data to get the sizes of the arrays and structures.
+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:128:128"
+
+declare i32 @llvm.objectsize.i32.p0i8(i8*, i1) nounwind readonly
+
+; CHECK-LABEL: @PR13390(
+define i32 @PR13390(i1 %bool, i8* %a) {
+entry:
+  %cond = or i1 %bool, true
+  br i1 %cond, label %return, label %xpto
+
+xpto:
+  %select = select i1 %bool, i8* %select, i8* %a
+  %select2 = select i1 %bool, i8* %a, i8* %select2
+  %0 = tail call i32 @llvm.objectsize.i32.p0i8(i8* %select, i1 true)
+  %1 = tail call i32 @llvm.objectsize.i32.p0i8(i8* %select2, i1 true)
+  %2 = add i32 %0, %1
+; CHECK: ret i32 undef
+  ret i32 %2
+
+return:
+  ret i32 42
+}
+
+; CHECK-LABEL: @PR13621(
+define i32 @PR13621(i1 %bool) nounwind {
+entry:
+  %cond = or i1 %bool, true
+  br i1 %cond, label %return, label %xpto
+
+; technically reachable, but this malformed IR may appear as a result of constant propagation
+xpto:
+  %gep2 = getelementptr i8, i8* %gep, i32 1
+  %gep = getelementptr i8, i8* %gep2, i32 1
+  %o = call i32 @llvm.objectsize.i32.p0i8(i8* %gep, i1 true)
+; CHECK: ret i32 undef
+  ret i32 %o
+
+return:
+  ret i32 7
+}

Added: llvm/trunk/test/Transforms/InstCombine/objsize.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/objsize.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/objsize.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/objsize.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,303 @@
+; Test a pile of objectsize bounds checking.
+; RUN: opt < %s -instcombine -S | FileCheck %s
+; We need target data to get the sizes of the arrays and structures.
+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:128:128"
+
+ at a = private global [60 x i8] zeroinitializer, align 1 ; <[60 x i8]*>
+ at .str = private constant [8 x i8] c"abcdefg\00"   ; <[8 x i8]*>
+define i32 @foo() nounwind {
+; CHECK-LABEL: @foo(
+; CHECK-NEXT: ret i32 60
+  %1 = call i32 @llvm.objectsize.i32.p0i8(i8* getelementptr inbounds ([60 x i8], [60 x i8]* @a, i32 0, i32 0), i1 false, i1 false, i1 false)
+  ret i32 %1
+}
+
+define i8* @bar() nounwind {
+; CHECK-LABEL: @bar(
+entry:
+  %retval = alloca i8*
+  %0 = call i32 @llvm.objectsize.i32.p0i8(i8* getelementptr inbounds ([60 x i8], [60 x i8]* @a, i32 0, i32 0), i1 false, i1 false, i1 false)
+  %cmp = icmp ne i32 %0, -1
+; CHECK: br i1 true
+  br i1 %cmp, label %cond.true, label %cond.false
+
+cond.true:
+  %1 = load i8*, i8** %retval
+  ret i8* %1
+
+cond.false:
+  %2 = load i8*, i8** %retval
+  ret i8* %2
+}
+
+define i32 @f() nounwind {
+; CHECK-LABEL: @f(
+; CHECK-NEXT: ret i32 0
+  %1 = call i32 @llvm.objectsize.i32.p0i8(i8* getelementptr ([60 x i8], [60 x i8]* @a, i32 1, i32 0), i1 false, i1 false, i1 false)
+  ret i32 %1
+}
+
+ at window = external global [0 x i8]
+
+define i1 @baz() nounwind {
+; CHECK-LABEL: @baz(
+; CHECK-NEXT: objectsize
+  %1 = tail call i32 @llvm.objectsize.i32.p0i8(i8* getelementptr inbounds ([0 x i8], [0 x i8]* @window, i32 0, i32 0), i1 false, i1 false, i1 false)
+  %2 = icmp eq i32 %1, -1
+  ret i1 %2
+}
+
+define void @test1(i8* %q, i32 %x) nounwind noinline {
+; CHECK-LABEL: @test1(
+; CHECK: objectsize.i32.p0i8
+entry:
+  %0 = call i32 @llvm.objectsize.i32.p0i8(i8* getelementptr inbounds ([0 x i8], [0 x i8]* @window, i32 0, i32 10), i1 false, i1 false, i1 false) ; <i64> [#uses=1]
+  %1 = icmp eq i32 %0, -1                         ; <i1> [#uses=1]
+  br i1 %1, label %"47", label %"46"
+
+"46":                                             ; preds = %entry
+  unreachable
+
+"47":                                             ; preds = %entry
+  unreachable
+}
+
+ at .str5 = private constant [9 x i32] [i32 97, i32 98, i32 99, i32 100, i32 0, i32
+ 101, i32 102, i32 103, i32 0], align 4
+define i32 @test2() nounwind {
+; CHECK-LABEL: @test2(
+; CHECK-NEXT: ret i32 34
+  %1 = call i32 @llvm.objectsize.i32.p0i8(i8* getelementptr (i8, i8* bitcast ([9 x i32]* @.str5 to i8*), i32 2), i1 false, i1 false, i1 false)
+  ret i32 %1
+}
+
+; rdar://7674946
+ at array = internal global [480 x float] zeroinitializer ; <[480 x float]*> [#uses=1]
+
+declare i8* @__memcpy_chk(i8*, i8*, i32, i32) nounwind
+
+declare i32 @llvm.objectsize.i32.p0i8(i8*, i1, i1, i1) nounwind readonly
+
+declare i32 @llvm.objectsize.i32.p1i8(i8 addrspace(1)*, i1, i1, i1) nounwind readonly
+
+declare i8* @__inline_memcpy_chk(i8*, i8*, i32) nounwind inlinehint
+
+define void @test3() nounwind {
+; CHECK-LABEL: @test3(
+entry:
+  br i1 undef, label %bb11, label %bb12
+
+bb11:
+  %0 = getelementptr inbounds float, float* getelementptr inbounds ([480 x float], [480 x float]* @array, i32 0, i32 128), i32 -127 ; <float*> [#uses=1]
+  %1 = bitcast float* %0 to i8*                   ; <i8*> [#uses=1]
+  %2 = call i32 @llvm.objectsize.i32.p0i8(i8* %1, i1 false, i1 false, i1 false) ; <i32> [#uses=1]
+  %3 = call i8* @__memcpy_chk(i8* undef, i8* undef, i32 512, i32 %2) nounwind ; <i8*> [#uses=0]
+; CHECK: unreachable
+  unreachable
+
+bb12:
+  %4 = getelementptr inbounds float, float* getelementptr inbounds ([480 x float], [480 x float]* @array, i32 0, i32 128), i32 -127 ; <float*> [#uses=1]
+  %5 = bitcast float* %4 to i8*                   ; <i8*> [#uses=1]
+  %6 = call i8* @__inline_memcpy_chk(i8* %5, i8* undef, i32 512) nounwind inlinehint ; <i8*> [#uses=0]
+; CHECK: @__inline_memcpy_chk
+  unreachable
+}
+
+; rdar://7718857
+
+%struct.data = type { [100 x i32], [100 x i32], [1024 x i8] }
+
+define i32 @test4(i8** %esc) nounwind ssp {
+; CHECK-LABEL: @test4(
+entry:
+  %0 = alloca %struct.data, align 8
+  %1 = bitcast %struct.data* %0 to i8*
+  %2 = call i32 @llvm.objectsize.i32.p0i8(i8* %1, i1 false, i1 false, i1 false) nounwind
+; CHECK-NOT: @llvm.objectsize
+; CHECK: @llvm.memset.p0i8.i32(i8* nonnull align 8 %1, i8 0, i32 1824, i1 false)
+  %3 = call i8* @__memset_chk(i8* %1, i32 0, i32 1824, i32 %2) nounwind
+  store i8* %1, i8** %esc
+  ret i32 0
+}
+
+; rdar://7782496
+ at s = external global i8*
+
+define i8* @test5(i32 %n) nounwind ssp {
+; CHECK-LABEL: @test5(
+entry:
+  %0 = tail call noalias i8* @malloc(i32 20) nounwind
+  %1 = tail call i32 @llvm.objectsize.i32.p0i8(i8* %0, i1 false, i1 false, i1 false)
+  %2 = load i8*, i8** @s, align 8
+; CHECK-NOT: @llvm.objectsize
+; CHECK: @llvm.memcpy.p0i8.p0i8.i32(i8* align 1 %0, i8* align 1 %1, i32 10, i1 false)
+  %3 = tail call i8* @__memcpy_chk(i8* %0, i8* %2, i32 10, i32 %1) nounwind
+  ret i8* %0
+}
+
+define void @test6(i32 %n) nounwind ssp {
+; CHECK-LABEL: @test6(
+entry:
+  %0 = tail call noalias i8* @malloc(i32 20) nounwind
+  %1 = tail call i32 @llvm.objectsize.i32.p0i8(i8* %0, i1 false, i1 false, i1 false)
+  %2 = load i8*, i8** @s, align 8
+; CHECK-NOT: @llvm.objectsize
+; CHECK: @__memcpy_chk(i8* %0, i8* %1, i32 30, i32 20)
+  %3 = tail call i8* @__memcpy_chk(i8* %0, i8* %2, i32 30, i32 %1) nounwind
+  ret void
+}
+
+declare i8* @__memset_chk(i8*, i32, i32, i32) nounwind
+
+declare noalias i8* @malloc(i32) nounwind
+
+define i32 @test7(i8** %esc) {
+; CHECK-LABEL: @test7(
+  %alloc = call noalias i8* @malloc(i32 48) nounwind
+  store i8* %alloc, i8** %esc
+  %gep = getelementptr inbounds i8, i8* %alloc, i32 16
+  %objsize = call i32 @llvm.objectsize.i32.p0i8(i8* %gep, i1 false, i1 false, i1 false) nounwind readonly
+; CHECK: ret i32 32
+  ret i32 %objsize
+}
+
+declare noalias i8* @calloc(i32, i32) nounwind
+
+define i32 @test8(i8** %esc) {
+; CHECK-LABEL: @test8(
+  %alloc = call noalias i8* @calloc(i32 5, i32 7) nounwind
+  store i8* %alloc, i8** %esc
+  %gep = getelementptr inbounds i8, i8* %alloc, i32 5
+  %objsize = call i32 @llvm.objectsize.i32.p0i8(i8* %gep, i1 false, i1 false, i1 false) nounwind readonly
+; CHECK: ret i32 30
+  ret i32 %objsize
+}
+
+declare noalias i8* @strdup(i8* nocapture) nounwind
+declare noalias i8* @strndup(i8* nocapture, i32) nounwind
+
+; CHECK-LABEL: @test9(
+define i32 @test9(i8** %esc) {
+  %call = tail call i8* @strdup(i8* getelementptr inbounds ([8 x i8], [8 x i8]* @.str, i64 0, i64 0)) nounwind
+  store i8* %call, i8** %esc, align 8
+  %1 = tail call i32 @llvm.objectsize.i32.p0i8(i8* %call, i1 true, i1 false, i1 false)
+; CHECK: ret i32 8
+  ret i32 %1
+}
+
+; CHECK-LABEL: @test10(
+define i32 @test10(i8** %esc) {
+  %call = tail call i8* @strndup(i8* getelementptr inbounds ([8 x i8], [8 x i8]* @.str, i64 0, i64 0), i32 3) nounwind
+  store i8* %call, i8** %esc, align 8
+  %1 = tail call i32 @llvm.objectsize.i32.p0i8(i8* %call, i1 true, i1 false, i1 false)
+; CHECK: ret i32 4
+  ret i32 %1
+}
+
+; CHECK-LABEL: @test11(
+define i32 @test11(i8** %esc) {
+  %call = tail call i8* @strndup(i8* getelementptr inbounds ([8 x i8], [8 x i8]* @.str, i64 0, i64 0), i32 7) nounwind
+  store i8* %call, i8** %esc, align 8
+  %1 = tail call i32 @llvm.objectsize.i32.p0i8(i8* %call, i1 true, i1 false, i1 false)
+; CHECK: ret i32 8
+  ret i32 %1
+}
+
+; CHECK-LABEL: @test12(
+define i32 @test12(i8** %esc) {
+  %call = tail call i8* @strndup(i8* getelementptr inbounds ([8 x i8], [8 x i8]* @.str, i64 0, i64 0), i32 8) nounwind
+  store i8* %call, i8** %esc, align 8
+  %1 = tail call i32 @llvm.objectsize.i32.p0i8(i8* %call, i1 true, i1 false, i1 false)
+; CHECK: ret i32 8
+  ret i32 %1
+}
+
+; CHECK-LABEL: @test13(
+define i32 @test13(i8** %esc) {
+  %call = tail call i8* @strndup(i8* getelementptr inbounds ([8 x i8], [8 x i8]* @.str, i64 0, i64 0), i32 57) nounwind
+  store i8* %call, i8** %esc, align 8
+  %1 = tail call i32 @llvm.objectsize.i32.p0i8(i8* %call, i1 true, i1 false, i1 false)
+; CHECK: ret i32 8
+  ret i32 %1
+}
+
+ at globalalias = internal alias [60 x i8], [60 x i8]* @a
+
+; CHECK-LABEL: @test18(
+; CHECK-NEXT: ret i32 60
+define i32 @test18() {
+  %bc = bitcast [60 x i8]* @globalalias to i8*
+  %1 = call i32 @llvm.objectsize.i32.p0i8(i8* %bc, i1 false, i1 false, i1 false)
+  ret i32 %1
+}
+
+ at globalalias2 = weak alias [60 x i8], [60 x i8]* @a
+
+; CHECK-LABEL: @test19(
+; CHECK: llvm.objectsize
+define i32 @test19() {
+  %bc = bitcast [60 x i8]* @globalalias2 to i8*
+  %1 = call i32 @llvm.objectsize.i32.p0i8(i8* %bc, i1 false, i1 false, i1 false)
+  ret i32 %1
+}
+
+; CHECK-LABEL: @test20(
+; CHECK: ret i32 0
+define i32 @test20() {
+  %1 = call i32 @llvm.objectsize.i32.p0i8(i8* null, i1 false, i1 false, i1 false)
+  ret i32 %1
+}
+
+; CHECK-LABEL: @test21(
+; CHECK: ret i32 0
+define i32 @test21() {
+  %1 = call i32 @llvm.objectsize.i32.p0i8(i8* null, i1 true, i1 false, i1 false)
+  ret i32 %1
+}
+
+; CHECK-LABEL: @test22(
+; CHECK: llvm.objectsize
+define i32 @test22() {
+  %1 = call i32 @llvm.objectsize.i32.p0i8(i8* null, i1 false, i1 true, i1 false)
+  ret i32 %1
+}
+
+; CHECK-LABEL: @test23(
+; CHECK: llvm.objectsize
+define i32 @test23() {
+  %1 = call i32 @llvm.objectsize.i32.p0i8(i8* null, i1 true, i1 true, i1 false)
+  ret i32 %1
+}
+
+; 1 is an arbitrary non-zero address space.
+; CHECK-LABEL: @test24(
+; CHECK: llvm.objectsize
+define i32 @test24() {
+  %1 = call i32 @llvm.objectsize.i32.p1i8(i8 addrspace(1)* null, i1 false,
+                                          i1 false, i1 false)
+  ret i32 %1
+}
+
+; CHECK-LABEL: @test25(
+; CHECK: llvm.objectsize
+define i32 @test25() {
+  %1 = call i32 @llvm.objectsize.i32.p1i8(i8 addrspace(1)* null, i1 true,
+                                          i1 false, i1 false)
+  ret i32 %1
+}
+
+; CHECK-LABEL: @test26(
+; CHECK: llvm.objectsize
+define i32 @test26() {
+  %1 = call i32 @llvm.objectsize.i32.p1i8(i8 addrspace(1)* null, i1 false,
+                                          i1 true, i1 false)
+  ret i32 %1
+}
+
+; CHECK-LABEL: @test27(
+; CHECK: llvm.objectsize
+define i32 @test27() {
+  %1 = call i32 @llvm.objectsize.i32.p1i8(i8 addrspace(1)* null, i1 true,
+                                          i1 true, i1 false)
+  ret i32 %1
+}

Added: llvm/trunk/test/Transforms/InstCombine/odr-linkage.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/odr-linkage.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/odr-linkage.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/odr-linkage.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,19 @@
+; RUN: opt < %s -instcombine -S | grep "ret i32 10"
+
+ at g1 = available_externally constant i32 1
+ at g2 = linkonce_odr constant i32 2
+ at g3 = weak_odr constant i32 3
+ at g4 = internal constant i32 4
+
+define i32 @test() {
+  %A = load i32, i32* @g1
+  %B = load i32, i32* @g2
+  %C = load i32, i32* @g3
+  %D = load i32, i32* @g4
+  
+  %a = add i32 %A, %B
+  %b = add i32 %a, %C
+  %c = add i32 %b, %D
+  ret i32 %c
+}
+   

Added: llvm/trunk/test/Transforms/InstCombine/onehot_merge.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/onehot_merge.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/onehot_merge.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/onehot_merge.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,111 @@
+; RUN: opt < %s -instcombine -S | FileCheck %s
+
+;CHECK: @and_consts
+;CHECK: and i32 %k, 12
+;CHECK: icmp ne i32 %0, 12
+;CHECK: ret
+define i1 @and_consts(i32 %k, i32 %c1, i32 %c2) {
+bb:
+  %tmp1 = and i32 4, %k
+  %tmp2 = icmp eq i32 %tmp1, 0
+  %tmp5 = and i32 8, %k
+  %tmp6 = icmp eq i32 %tmp5, 0
+  %or = or i1 %tmp2, %tmp6
+  ret i1 %or
+}
+
+;CHECK: @foo1_and
+;CHECK:  shl i32 1, %c1
+;CHECK-NEXT:  lshr i32 -2147483648, %c2
+;CHECK-NEXT:  or i32
+;CHECK-NEXT:  and i32
+;CHECK-NEXT:  icmp ne i32 %1, %0
+;CHECK: ret
+define i1 @foo1_and(i32 %k, i32 %c1, i32 %c2) {
+bb:
+  %tmp = shl i32 1, %c1
+  %tmp4 = lshr i32 -2147483648, %c2
+  %tmp1 = and i32 %tmp, %k
+  %tmp2 = icmp eq i32 %tmp1, 0
+  %tmp5 = and i32 %tmp4, %k
+  %tmp6 = icmp eq i32 %tmp5, 0
+  %or = or i1 %tmp2, %tmp6
+  ret i1 %or
+}
+
+; Same as above but with operands commuted one of the ands, but not the other.
+define i1 @foo1_and_commuted(i32 %k, i32 %c1, i32 %c2) {
+; CHECK-LABEL: @foo1_and_commuted(
+; CHECK-NEXT:    [[K2:%.*]] = mul i32 [[K:%.*]], [[K]]
+; CHECK-NEXT:    [[TMP:%.*]] = shl i32 1, [[C1:%.*]]
+; CHECK-NEXT:    [[TMP4:%.*]] = lshr i32 -2147483648, [[C2:%.*]]
+; CHECK-NEXT:    [[TMP0:%.*]] = or i32 [[TMP]], [[TMP4]]
+; CHECK-NEXT:    [[TMP1:%.*]] = and i32 [[K2]], [[TMP0]]
+; CHECK-NEXT:    [[TMP2:%.*]] = icmp ne i32 [[TMP1]], [[TMP0]]
+; CHECK-NEXT:    ret i1 [[TMP2]]
+;
+  %k2 = mul i32 %k, %k ; to trick the complexity sorting
+  %tmp = shl i32 1, %c1
+  %tmp4 = lshr i32 -2147483648, %c2
+  %tmp1 = and i32 %k2, %tmp
+  %tmp2 = icmp eq i32 %tmp1, 0
+  %tmp5 = and i32 %tmp4, %k2
+  %tmp6 = icmp eq i32 %tmp5, 0
+  %or = or i1 %tmp2, %tmp6
+  ret i1 %or
+}
+
+define i1 @or_consts(i32 %k, i32 %c1, i32 %c2) {
+; CHECK-LABEL: @or_consts(
+; CHECK-NEXT:    [[TMP1:%.*]] = and i32 [[K:%.*]], 12
+; CHECK-NEXT:    [[TMP2:%.*]] = icmp eq i32 [[TMP1]], 12
+; CHECK-NEXT:    ret i1 [[TMP2]]
+;
+  %tmp1 = and i32 4, %k
+  %tmp2 = icmp ne i32 %tmp1, 0
+  %tmp5 = and i32 8, %k
+  %tmp6 = icmp ne i32 %tmp5, 0
+  %or = and i1 %tmp2, %tmp6
+  ret i1 %or
+}
+
+define i1 @foo1_or(i32 %k, i32 %c1, i32 %c2) {
+; CHECK-LABEL: @foo1_or(
+; CHECK-NEXT:    [[TMP:%.*]] = shl i32 1, [[C1:%.*]]
+; CHECK-NEXT:    [[TMP4:%.*]] = lshr i32 -2147483648, [[C2:%.*]]
+; CHECK-NEXT:    [[TMP1:%.*]] = or i32 [[TMP]], [[TMP4]]
+; CHECK-NEXT:    [[TMP2:%.*]] = and i32 [[TMP1]], [[K:%.*]]
+; CHECK-NEXT:    [[TMP3:%.*]] = icmp eq i32 [[TMP2]], [[TMP1]]
+; CHECK-NEXT:    ret i1 [[TMP3]]
+;
+  %tmp = shl i32 1, %c1
+  %tmp4 = lshr i32 -2147483648, %c2
+  %tmp1 = and i32 %tmp, %k
+  %tmp2 = icmp ne i32 %tmp1, 0
+  %tmp5 = and i32 %tmp4, %k
+  %tmp6 = icmp ne i32 %tmp5, 0
+  %or = and i1 %tmp2, %tmp6
+  ret i1 %or
+}
+
+; Same as above but with operands commuted one of the ors, but not the other.
+define i1 @foo1_or_commuted(i32 %k, i32 %c1, i32 %c2) {
+; CHECK-LABEL: @foo1_or_commuted(
+; CHECK-NEXT:    [[K2:%.*]] = mul i32 [[K:%.*]], [[K]]
+; CHECK-NEXT:    [[TMP:%.*]] = shl i32 1, [[C1:%.*]]
+; CHECK-NEXT:    [[TMP4:%.*]] = lshr i32 -2147483648, [[C2:%.*]]
+; CHECK-NEXT:    [[TMP1:%.*]] = or i32 [[TMP]], [[TMP4]]
+; CHECK-NEXT:    [[TMP2:%.*]] = and i32 [[K2]], [[TMP1]]
+; CHECK-NEXT:    [[TMP3:%.*]] = icmp eq i32 [[TMP2]], [[TMP1]]
+; CHECK-NEXT:    ret i1 [[TMP3]]
+;
+  %k2 = mul i32 %k, %k ; to trick the complexity sorting
+  %tmp = shl i32 1, %c1
+  %tmp4 = lshr i32 -2147483648, %c2
+  %tmp1 = and i32 %k2, %tmp
+  %tmp2 = icmp ne i32 %tmp1, 0
+  %tmp5 = and i32 %tmp4, %k2
+  %tmp6 = icmp ne i32 %tmp5, 0
+  %or = and i1 %tmp2, %tmp6
+  ret i1 %or
+}

Added: llvm/trunk/test/Transforms/InstCombine/opaque.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/opaque.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/opaque.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/opaque.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,31 @@
+; RUN: opt < %s -instcombine -disable-output
+; Checks that bitcasts are not converted into GEP when
+; when the size of an aggregate cannot be determined.
+%swift.opaque = type opaque
+%SQ = type <{ [8 x i8] }>
+%Si = type <{ i64 }>
+
+%V = type <{ <{ %Vs4Int8, %Vs4Int8, %Vs4Int8, %Vs4Int8, %Vs4Int8, %Vs4Int8, %Vs4Int8, %Vs4Int8 }>, %Si, %SQ, %SQ, %Si, %swift.opaque }>
+%Vs4Int8 = type <{ i8 }>
+%swift.type = type { i64 }
+
+declare void @llvm.memcpy.p0i8.p0i8.i64(i8* nocapture, i8* nocapture readonly, i64, i1) #8
+
+ at _swift_slowAlloc = external global i8* (i64, i64)*
+
+declare i8* @rt_swift_slowAlloc(i64, i64)
+
+define  %swift.opaque* @_TwTkV([24 x i8]* %dest, %swift.opaque* %src,
+%swift.type* %bios_boot_params) #0 {
+entry:
+  %0 = bitcast %swift.opaque* %src to %V*
+  %1 = call noalias i8* @rt_swift_slowAlloc(i64 40, i64 0) #11
+  %2 = bitcast [24 x i8]* %dest to i8**
+  store i8* %1, i8** %2, align 8
+  %3 = bitcast i8* %1 to %V*
+  %4 = bitcast %V* %3 to i8*
+  %5 = bitcast %V* %0 to i8*
+  call void @llvm.memcpy.p0i8.p0i8.i64(i8* %4, i8* %5, i64 40, i1 false)
+  %6 = bitcast %V* %3 to %swift.opaque*
+  ret %swift.opaque* %6
+}

Added: llvm/trunk/test/Transforms/InstCombine/operand-complexity.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/operand-complexity.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/operand-complexity.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/operand-complexity.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,136 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt < %s -instcombine -S | FileCheck %s
+
+; 'Negate' is considered less complex than a normal binop, so the xor should have the binop as the first operand.
+
+define i8 @neg(i8 %x) {
+; CHECK-LABEL: @neg(
+; CHECK-NEXT:    [[BO:%.*]] = udiv i8 [[X:%.*]], 42
+; CHECK-NEXT:    [[NEGX:%.*]] = sub i8 0, [[X]]
+; CHECK-NEXT:    [[R:%.*]] = xor i8 [[BO]], [[NEGX]]
+; CHECK-NEXT:    ret i8 [[R]]
+;
+  %bo = udiv i8 %x, 42
+  %negx = sub i8 0, %x
+  %r = xor i8 %negx, %bo
+  ret i8 %r
+}
+
+define <2 x i8> @neg_vec(<2 x i8> %x) {
+; CHECK-LABEL: @neg_vec(
+; CHECK-NEXT:    [[BO:%.*]] = udiv <2 x i8> [[X:%.*]], <i8 42, i8 -42>
+; CHECK-NEXT:    [[NEGX:%.*]] = sub <2 x i8> zeroinitializer, [[X]]
+; CHECK-NEXT:    [[R:%.*]] = xor <2 x i8> [[BO]], [[NEGX]]
+; CHECK-NEXT:    ret <2 x i8> [[R]]
+;
+  %bo = udiv <2 x i8> %x, <i8 42, i8 -42>
+  %negx = sub <2 x i8> <i8 0, i8 0>, %x
+  %r = xor <2 x i8> %negx, %bo
+  ret <2 x i8> %r
+}
+
+define <2 x i8> @neg_vec_undef(<2 x i8> %x) {
+; CHECK-LABEL: @neg_vec_undef(
+; CHECK-NEXT:    [[BO:%.*]] = udiv <2 x i8> [[X:%.*]], <i8 42, i8 -42>
+; CHECK-NEXT:    [[NEGX:%.*]] = sub <2 x i8> <i8 0, i8 undef>, [[X]]
+; CHECK-NEXT:    [[R:%.*]] = xor <2 x i8> [[BO]], [[NEGX]]
+; CHECK-NEXT:    ret <2 x i8> [[R]]
+;
+  %bo = udiv <2 x i8> %x, <i8 42, i8 -42>
+  %negx = sub <2 x i8> <i8 0, i8 undef>, %x
+  %r = xor <2 x i8> %negx, %bo
+  ret <2 x i8> %r
+}
+
+; 'Not' is considered less complex than a normal binop, so the mul should have the binop as the first operand.
+
+define i8 @not(i8 %x) {
+; CHECK-LABEL: @not(
+; CHECK-NEXT:    [[BO:%.*]] = udiv i8 [[X:%.*]], 42
+; CHECK-NEXT:    [[NOTX:%.*]] = xor i8 [[X]], -1
+; CHECK-NEXT:    [[R:%.*]] = mul i8 [[BO]], [[NOTX]]
+; CHECK-NEXT:    ret i8 [[R]]
+;
+  %bo = udiv i8 %x, 42
+  %notx = xor i8 -1, %x
+  %r = mul i8 %notx, %bo
+  ret i8 %r
+}
+
+define <2 x i8> @not_vec(<2 x i8> %x) {
+; CHECK-LABEL: @not_vec(
+; CHECK-NEXT:    [[BO:%.*]] = udiv <2 x i8> [[X:%.*]], <i8 42, i8 -42>
+; CHECK-NEXT:    [[NOTX:%.*]] = xor <2 x i8> [[X]], <i8 -1, i8 -1>
+; CHECK-NEXT:    [[R:%.*]] = mul <2 x i8> [[BO]], [[NOTX]]
+; CHECK-NEXT:    ret <2 x i8> [[R]]
+;
+  %bo = udiv <2 x i8> %x, <i8 42, i8 -42>
+  %notx = xor <2 x i8> <i8 -1, i8 -1>, %x
+  %r = mul <2 x i8> %notx, %bo
+  ret <2 x i8> %r
+}
+
+define <2 x i8> @not_vec_undef(<2 x i8> %x) {
+; CHECK-LABEL: @not_vec_undef(
+; CHECK-NEXT:    [[BO:%.*]] = udiv <2 x i8> [[X:%.*]], <i8 42, i8 -42>
+; CHECK-NEXT:    [[NOTX:%.*]] = xor <2 x i8> [[X]], <i8 -1, i8 undef>
+; CHECK-NEXT:    [[R:%.*]] = mul <2 x i8> [[BO]], [[NOTX]]
+; CHECK-NEXT:    ret <2 x i8> [[R]]
+;
+  %bo = udiv <2 x i8> %x, <i8 42, i8 -42>
+  %notx = xor <2 x i8> <i8 -1, i8 undef>, %x
+  %r = mul <2 x i8> %notx, %bo
+  ret <2 x i8> %r
+}
+
+; 'Fneg' is considered less complex than a normal binop, so the fmul should have the binop as the first operand.
+; Extra uses are required to ensure that the fneg is not canonicalized after the fmul.
+
+declare void @use(float)
+declare void @use_vec(<2 x float>)
+
+define float @fneg(float %x) {
+; CHECK-LABEL: @fneg(
+; CHECK-NEXT:    [[BO:%.*]] = fdiv float [[X:%.*]], 4.200000e+01
+; CHECK-NEXT:    [[FNEGX:%.*]] = fsub float -0.000000e+00, [[X]]
+; CHECK-NEXT:    [[R:%.*]] = fmul float [[BO]], [[FNEGX]]
+; CHECK-NEXT:    call void @use(float [[FNEGX]])
+; CHECK-NEXT:    ret float [[R]]
+;
+  %bo = fdiv float %x, 42.0
+  %fnegx = fsub float -0.0, %x
+  %r = fmul float %fnegx, %bo
+  call void @use(float %fnegx)
+  ret float %r
+}
+
+define <2 x float> @fneg_vec(<2 x float> %x) {
+; CHECK-LABEL: @fneg_vec(
+; CHECK-NEXT:    [[BO:%.*]] = fdiv <2 x float> [[X:%.*]], <float 4.200000e+01, float -4.200000e+01>
+; CHECK-NEXT:    [[FNEGX:%.*]] = fsub <2 x float> <float -0.000000e+00, float -0.000000e+00>, [[X]]
+; CHECK-NEXT:    [[R:%.*]] = fmul <2 x float> [[BO]], [[FNEGX]]
+; CHECK-NEXT:    call void @use_vec(<2 x float> [[FNEGX]])
+; CHECK-NEXT:    ret <2 x float> [[R]]
+;
+  %bo = fdiv <2 x float> %x, <float 42.0, float -42.0>
+  %fnegx = fsub <2 x float> <float -0.0, float -0.0>, %x
+  %r = fmul <2 x float> %fnegx, %bo
+  call void @use_vec(<2 x float> %fnegx)
+  ret <2 x float> %r
+}
+
+define <2 x float> @fneg_vec_undef(<2 x float> %x) {
+; CHECK-LABEL: @fneg_vec_undef(
+; CHECK-NEXT:    [[BO:%.*]] = fdiv <2 x float> [[X:%.*]], <float 4.200000e+01, float -4.200000e+01>
+; CHECK-NEXT:    [[FNEGX:%.*]] = fsub <2 x float> <float -0.000000e+00, float undef>, [[X]]
+; CHECK-NEXT:    [[R:%.*]] = fmul <2 x float> [[BO]], [[FNEGX]]
+; CHECK-NEXT:    call void @use_vec(<2 x float> [[FNEGX]])
+; CHECK-NEXT:    ret <2 x float> [[R]]
+;
+  %bo = fdiv <2 x float> %x, <float 42.0, float -42.0>
+  %fnegx = fsub <2 x float> <float -0.0, float undef>, %x
+  %r = fmul <2 x float> %fnegx, %bo
+  call void @use_vec(<2 x float> %fnegx)
+  ret <2 x float> %r
+}
+




More information about the llvm-commits mailing list