[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/canonicalize-shl-lshr-to-masking.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/canonicalize-shl-lshr-to-masking.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/canonicalize-shl-lshr-to-masking.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/canonicalize-shl-lshr-to-masking.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,398 @@
+; 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=37603
+
+; Pattern:
+;   x << y >> y
+; Should be transformed into:
+;   x & (-1 >> y)
+
+; ============================================================================ ;
+; Basic positive tests
+; ============================================================================ ;
+
+define i32 @positive_samevar(i32 %x, i32 %y) {
+; CHECK-LABEL: @positive_samevar(
+; CHECK-NEXT:    [[TMP1:%.*]] = lshr i32 -1, [[Y:%.*]]
+; CHECK-NEXT:    [[RET:%.*]] = and i32 [[TMP1]], [[X:%.*]]
+; CHECK-NEXT:    ret i32 [[RET]]
+;
+  %tmp0 = shl i32 %x, %y
+  %ret = lshr i32 %tmp0, %y
+  ret i32 %ret
+}
+
+define i32 @positive_sameconst(i32 %x) {
+; CHECK-LABEL: @positive_sameconst(
+; CHECK-NEXT:    [[TMP0:%.*]] = and i32 [[X:%.*]], 134217727
+; CHECK-NEXT:    ret i32 [[TMP0]]
+;
+  %tmp0 = shl i32 %x, 5
+  %ret = lshr i32 %tmp0, 5
+  ret i32 %ret
+}
+
+define i32 @positive_biggerShl(i32 %x) {
+; CHECK-LABEL: @positive_biggerShl(
+; CHECK-NEXT:    [[TMP1:%.*]] = shl i32 [[X:%.*]], 5
+; CHECK-NEXT:    [[RET:%.*]] = and i32 [[TMP1]], 134217696
+; CHECK-NEXT:    ret i32 [[RET]]
+;
+  %tmp0 = shl i32 %x, 10
+  %ret = lshr i32 %tmp0, 5
+  ret i32 %ret
+}
+
+define i32 @positive_biggerLshr(i32 %x) {
+; CHECK-LABEL: @positive_biggerLshr(
+; CHECK-NEXT:    [[TMP1:%.*]] = lshr i32 [[X:%.*]], 5
+; CHECK-NEXT:    [[RET:%.*]] = and i32 [[TMP1]], 4194303
+; CHECK-NEXT:    ret i32 [[RET]]
+;
+  %tmp0 = shl i32 %x, 5
+  %ret = lshr i32 %tmp0, 10
+  ret i32 %ret
+}
+
+define i32 @positive_biggerLshr_lshrexact(i32 %x) {
+; CHECK-LABEL: @positive_biggerLshr_lshrexact(
+; CHECK-NEXT:    [[TMP1:%.*]] = lshr exact i32 [[X:%.*]], 5
+; CHECK-NEXT:    [[RET:%.*]] = and i32 [[TMP1]], 4194303
+; CHECK-NEXT:    ret i32 [[RET]]
+;
+  %tmp0 = shl i32 %x, 5
+  %ret = lshr exact i32 %tmp0, 10
+  ret i32 %ret
+}
+
+; ============================================================================ ;
+; NUW on the first shift
+; ============================================================================ ;
+
+define i32 @positive_samevar_shlnuw(i32 %x, i32 %y) {
+; CHECK-LABEL: @positive_samevar_shlnuw(
+; CHECK-NEXT:    ret i32 [[X:%.*]]
+;
+  %tmp0 = shl nuw i32 %x, %y
+  %ret = lshr i32 %tmp0, %y ; this one is obviously 'exact'.
+  ret i32 %ret
+}
+
+define i32 @positive_sameconst_shlnuw(i32 %x) {
+; CHECK-LABEL: @positive_sameconst_shlnuw(
+; CHECK-NEXT:    ret i32 [[X:%.*]]
+;
+  %tmp0 = shl nuw i32 %x, 5
+  %ret = lshr i32 %tmp0, 5 ; this one is obviously 'exact'.
+  ret i32 %ret
+}
+
+define i32 @positive_biggerShl_shlnuw(i32 %x) {
+; CHECK-LABEL: @positive_biggerShl_shlnuw(
+; CHECK-NEXT:    [[RET:%.*]] = shl nuw i32 [[X:%.*]], 5
+; CHECK-NEXT:    ret i32 [[RET]]
+;
+  %tmp0 = shl nuw i32 %x, 10
+  %ret = lshr i32 %tmp0, 5 ; this one is obviously 'exact'.
+  ret i32 %ret
+}
+
+define i32 @positive_biggerLshr_shlnuw(i32 %x) {
+; CHECK-LABEL: @positive_biggerLshr_shlnuw(
+; CHECK-NEXT:    [[RET:%.*]] = lshr i32 [[X:%.*]], 5
+; CHECK-NEXT:    ret i32 [[RET]]
+;
+  %tmp0 = shl nuw i32 %x, 5
+  %ret = lshr i32 %tmp0, 10
+  ret i32 %ret
+}
+
+define i32 @positive_biggerLshr_shlnuw_lshrexact(i32 %x) {
+; CHECK-LABEL: @positive_biggerLshr_shlnuw_lshrexact(
+; CHECK-NEXT:    [[RET:%.*]] = lshr exact i32 [[X:%.*]], 5
+; CHECK-NEXT:    ret i32 [[RET]]
+;
+  %tmp0 = shl nuw i32 %x, 5
+  %ret = lshr exact i32 %tmp0, 10
+  ret i32 %ret
+}
+
+; ============================================================================ ;
+; Vector
+; ============================================================================ ;
+
+define <2 x i32> @positive_samevar_vec(<2 x i32> %x, <2 x i32> %y) {
+; CHECK-LABEL: @positive_samevar_vec(
+; CHECK-NEXT:    [[TMP1:%.*]] = lshr <2 x i32> <i32 -1, i32 -1>, [[Y:%.*]]
+; CHECK-NEXT:    [[RET:%.*]] = and <2 x i32> [[TMP1]], [[X:%.*]]
+; CHECK-NEXT:    ret <2 x i32> [[RET]]
+;
+  %tmp0 = shl <2 x i32> %x, %y
+  %ret = lshr <2 x i32> %tmp0, %y
+  ret <2 x i32> %ret
+}
+
+; ============================================================================ ;
+; Constant Vectors
+; ============================================================================ ;
+
+define <2 x i32> @positive_sameconst_vec(<2 x i32> %x) {
+; CHECK-LABEL: @positive_sameconst_vec(
+; CHECK-NEXT:    [[TMP0:%.*]] = and <2 x i32> [[X:%.*]], <i32 134217727, i32 134217727>
+; CHECK-NEXT:    ret <2 x i32> [[TMP0]]
+;
+  %tmp0 = shl <2 x i32> %x, <i32 5, i32 5>
+  %ret = lshr <2 x i32> %tmp0, <i32 5, i32 5>
+  ret <2 x i32> %ret
+}
+
+define <3 x i32> @positive_sameconst_vec_undef0(<3 x i32> %x) {
+; CHECK-LABEL: @positive_sameconst_vec_undef0(
+; CHECK-NEXT:    [[TMP0:%.*]] = shl <3 x i32> [[X:%.*]], <i32 5, i32 undef, i32 5>
+; CHECK-NEXT:    [[RET:%.*]] = lshr <3 x i32> [[TMP0]], <i32 5, i32 5, i32 5>
+; CHECK-NEXT:    ret <3 x i32> [[RET]]
+;
+  %tmp0 = shl <3 x i32> %x, <i32 5, i32 undef, i32 5>
+  %ret = lshr <3 x i32> %tmp0, <i32 5, i32 5, i32 5>
+  ret <3 x i32> %ret
+}
+
+define <3 x i32> @positive_sameconst_vec_undef1(<3 x i32> %x) {
+; CHECK-LABEL: @positive_sameconst_vec_undef1(
+; CHECK-NEXT:    [[TMP0:%.*]] = shl <3 x i32> [[X:%.*]], <i32 5, i32 5, i32 5>
+; CHECK-NEXT:    [[RET:%.*]] = lshr <3 x i32> [[TMP0]], <i32 5, i32 undef, i32 5>
+; CHECK-NEXT:    ret <3 x i32> [[RET]]
+;
+  %tmp0 = shl <3 x i32> %x, <i32 5, i32 5, i32 5>
+  %ret = lshr <3 x i32> %tmp0, <i32 5, i32 undef, i32 5>
+  ret <3 x i32> %ret
+}
+
+define <3 x i32> @positive_sameconst_vec_undef2(<3 x i32> %x) {
+; CHECK-LABEL: @positive_sameconst_vec_undef2(
+; CHECK-NEXT:    [[RET:%.*]] = and <3 x i32> [[X:%.*]], <i32 134217727, i32 undef, i32 134217727>
+; CHECK-NEXT:    ret <3 x i32> [[RET]]
+;
+  %tmp0 = shl <3 x i32> %x, <i32 5, i32 undef, i32 5>
+  %ret = lshr <3 x i32> %tmp0, <i32 5, i32 undef, i32 5>
+  ret <3 x i32> %ret
+}
+
+define <2 x i32> @positive_biggerShl_vec(<2 x i32> %x) {
+; CHECK-LABEL: @positive_biggerShl_vec(
+; CHECK-NEXT:    [[TMP1:%.*]] = shl <2 x i32> [[X:%.*]], <i32 5, i32 5>
+; CHECK-NEXT:    [[RET:%.*]] = and <2 x i32> [[TMP1]], <i32 134217696, i32 134217696>
+; CHECK-NEXT:    ret <2 x i32> [[RET]]
+;
+  %tmp0 = shl <2 x i32> %x, <i32 10, i32 10>
+  %ret = lshr <2 x i32> %tmp0, <i32 5, i32 5>
+  ret <2 x i32> %ret
+}
+
+define <3 x i32> @positive_biggerShl_vec_undef0(<3 x i32> %x) {
+; CHECK-LABEL: @positive_biggerShl_vec_undef0(
+; CHECK-NEXT:    [[TMP0:%.*]] = shl <3 x i32> [[X:%.*]], <i32 10, i32 undef, i32 10>
+; CHECK-NEXT:    [[RET:%.*]] = lshr <3 x i32> [[TMP0]], <i32 5, i32 5, i32 5>
+; CHECK-NEXT:    ret <3 x i32> [[RET]]
+;
+  %tmp0 = shl <3 x i32> %x, <i32 10, i32 undef, i32 10>
+  %ret = lshr <3 x i32> %tmp0, <i32 5, i32 5, i32 5>
+  ret <3 x i32> %ret
+}
+
+define <3 x i32> @positive_biggerShl_vec_undef1(<3 x i32> %x) {
+; CHECK-LABEL: @positive_biggerShl_vec_undef1(
+; CHECK-NEXT:    [[TMP0:%.*]] = shl <3 x i32> [[X:%.*]], <i32 10, i32 10, i32 10>
+; CHECK-NEXT:    [[RET:%.*]] = lshr <3 x i32> [[TMP0]], <i32 5, i32 undef, i32 5>
+; CHECK-NEXT:    ret <3 x i32> [[RET]]
+;
+  %tmp0 = shl <3 x i32> %x, <i32 10, i32 10, i32 10>
+  %ret = lshr <3 x i32> %tmp0, <i32 5, i32 undef, i32 5>
+  ret <3 x i32> %ret
+}
+
+define <3 x i32> @positive_biggerShl_vec_undef2(<3 x i32> %x) {
+; CHECK-LABEL: @positive_biggerShl_vec_undef2(
+; CHECK-NEXT:    [[TMP0:%.*]] = shl <3 x i32> [[X:%.*]], <i32 10, i32 undef, i32 10>
+; CHECK-NEXT:    [[RET:%.*]] = lshr <3 x i32> [[TMP0]], <i32 5, i32 undef, i32 5>
+; CHECK-NEXT:    ret <3 x i32> [[RET]]
+;
+  %tmp0 = shl <3 x i32> %x, <i32 10, i32 undef, i32 10>
+  %ret = lshr <3 x i32> %tmp0, <i32 5, i32 undef, i32 5>
+  ret <3 x i32> %ret
+}
+
+define <2 x i32> @positive_biggerLshr_vec(<2 x i32> %x) {
+; CHECK-LABEL: @positive_biggerLshr_vec(
+; CHECK-NEXT:    [[TMP1:%.*]] = lshr <2 x i32> [[X:%.*]], <i32 5, i32 5>
+; CHECK-NEXT:    [[RET:%.*]] = and <2 x i32> [[TMP1]], <i32 4194303, i32 4194303>
+; CHECK-NEXT:    ret <2 x i32> [[RET]]
+;
+  %tmp0 = shl <2 x i32> %x, <i32 5, i32 5>
+  %ret = lshr <2 x i32> %tmp0, <i32 10, i32 10>
+  ret <2 x i32> %ret
+}
+
+define <3 x i32> @positive_biggerLshr_vec_undef0(<3 x i32> %x) {
+; CHECK-LABEL: @positive_biggerLshr_vec_undef0(
+; CHECK-NEXT:    [[TMP0:%.*]] = shl <3 x i32> [[X:%.*]], <i32 5, i32 undef, i32 5>
+; CHECK-NEXT:    [[RET:%.*]] = lshr <3 x i32> [[TMP0]], <i32 10, i32 10, i32 10>
+; CHECK-NEXT:    ret <3 x i32> [[RET]]
+;
+  %tmp0 = shl <3 x i32> %x, <i32 5, i32 undef, i32 5>
+  %ret = lshr <3 x i32> %tmp0, <i32 10, i32 10, i32 10>
+  ret <3 x i32> %ret
+}
+
+define <3 x i32> @positive_biggerLshr_vec_undef1(<3 x i32> %x) {
+; CHECK-LABEL: @positive_biggerLshr_vec_undef1(
+; CHECK-NEXT:    [[TMP0:%.*]] = shl <3 x i32> [[X:%.*]], <i32 5, i32 5, i32 5>
+; CHECK-NEXT:    [[RET:%.*]] = lshr <3 x i32> [[TMP0]], <i32 10, i32 undef, i32 10>
+; CHECK-NEXT:    ret <3 x i32> [[RET]]
+;
+  %tmp0 = shl <3 x i32> %x, <i32 5, i32 5, i32 5>
+  %ret = lshr <3 x i32> %tmp0, <i32 10, i32 undef, i32 10>
+  ret <3 x i32> %ret
+}
+
+define <3 x i32> @positive_biggerLshr_vec_undef2(<3 x i32> %x) {
+; CHECK-LABEL: @positive_biggerLshr_vec_undef2(
+; CHECK-NEXT:    [[TMP0:%.*]] = shl <3 x i32> [[X:%.*]], <i32 5, i32 undef, i32 5>
+; CHECK-NEXT:    [[RET:%.*]] = lshr <3 x i32> [[TMP0]], <i32 10, i32 undef, i32 10>
+; CHECK-NEXT:    ret <3 x i32> [[RET]]
+;
+  %tmp0 = shl <3 x i32> %x, <i32 5, i32 undef, i32 5>
+  %ret = lshr <3 x i32> %tmp0, <i32 10, i32 undef, i32 10>
+  ret <3 x i32> %ret
+}
+
+; ============================================================================ ;
+; Positive multi-use tests with constant
+; ============================================================================ ;
+
+define i32 @positive_sameconst_multiuse(i32 %x) {
+; CHECK-LABEL: @positive_sameconst_multiuse(
+; CHECK-NEXT:    [[TMP0:%.*]] = shl i32 [[X:%.*]], 5
+; CHECK-NEXT:    call void @use32(i32 [[TMP0]])
+; CHECK-NEXT:    [[RET:%.*]] = and i32 [[X]], 134217727
+; CHECK-NEXT:    ret i32 [[RET]]
+;
+  %tmp0 = shl i32 %x, 5
+  call void @use32(i32 %tmp0)
+  %ret = lshr i32 %tmp0, 5
+  ret i32 %ret
+}
+
+define i32 @positive_biggerShl_shlnuw_multiuse(i32 %x) {
+; CHECK-LABEL: @positive_biggerShl_shlnuw_multiuse(
+; CHECK-NEXT:    [[TMP0:%.*]] = shl nuw i32 [[X:%.*]], 10
+; CHECK-NEXT:    call void @use32(i32 [[TMP0]])
+; CHECK-NEXT:    [[RET:%.*]] = shl nuw i32 [[X]], 5
+; CHECK-NEXT:    ret i32 [[RET]]
+;
+  %tmp0 = shl nuw i32 %x, 10
+  call void @use32(i32 %tmp0)
+  %ret = lshr i32 %tmp0, 5
+  ret i32 %ret
+}
+
+define i32 @positive_biggerLshr_shlnuw_multiuse(i32 %x) {
+; CHECK-LABEL: @positive_biggerLshr_shlnuw_multiuse(
+; CHECK-NEXT:    [[TMP0:%.*]] = shl nuw i32 [[X:%.*]], 5
+; CHECK-NEXT:    call void @use32(i32 [[TMP0]])
+; CHECK-NEXT:    [[RET:%.*]] = lshr i32 [[X]], 5
+; CHECK-NEXT:    ret i32 [[RET]]
+;
+  %tmp0 = shl nuw i32 %x, 5
+  call void @use32(i32 %tmp0)
+  %ret = lshr i32 %tmp0, 10
+  ret i32 %ret
+}
+
+; NOTE: creates one extra instruction, but this seems intentional.
+define i32 @positive_biggerShl_multiuse_extrainstr(i32 %x) {
+; CHECK-LABEL: @positive_biggerShl_multiuse_extrainstr(
+; CHECK-NEXT:    [[TMP0:%.*]] = shl i32 [[X:%.*]], 10
+; CHECK-NEXT:    call void @use32(i32 [[TMP0]])
+; CHECK-NEXT:    [[TMP1:%.*]] = shl i32 [[X]], 5
+; CHECK-NEXT:    [[RET:%.*]] = and i32 [[TMP1]], 134217696
+; CHECK-NEXT:    ret i32 [[RET]]
+;
+  %tmp0 = shl i32 %x, 10
+  call void @use32(i32 %tmp0)
+  %ret = lshr i32 %tmp0, 5
+  ret i32 %ret
+}
+
+; NOTE: creates one extra instruction, but this seems intentional.
+define i32 @positive_biggerLshr_multiuse_extrainstr(i32 %x) {
+; CHECK-LABEL: @positive_biggerLshr_multiuse_extrainstr(
+; CHECK-NEXT:    [[TMP0:%.*]] = shl i32 [[X:%.*]], 5
+; CHECK-NEXT:    call void @use32(i32 [[TMP0]])
+; CHECK-NEXT:    [[TMP1:%.*]] = lshr i32 [[X]], 5
+; CHECK-NEXT:    [[RET:%.*]] = and i32 [[TMP1]], 4194303
+; CHECK-NEXT:    ret i32 [[RET]]
+;
+  %tmp0 = shl i32 %x, 5
+  call void @use32(i32 %tmp0)
+  %ret = lshr i32 %tmp0, 10
+  ret i32 %ret
+}
+
+; ============================================================================ ;
+; Constant Non-Splat Vectors
+; ============================================================================ ;
+
+define <2 x i32> @positive_biggerShl_vec_nonsplat(<2 x i32> %x) {
+; CHECK-LABEL: @positive_biggerShl_vec_nonsplat(
+; CHECK-NEXT:    [[TMP0:%.*]] = shl <2 x i32> [[X:%.*]], <i32 5, i32 5>
+; CHECK-NEXT:    [[RET:%.*]] = lshr <2 x i32> [[TMP0]], <i32 5, i32 10>
+; CHECK-NEXT:    ret <2 x i32> [[RET]]
+;
+  %tmp0 = shl <2 x i32> %x, <i32 5, i32 5>
+  %ret = lshr <2 x i32> %tmp0, <i32 5, i32 10>
+  ret <2 x i32> %ret
+}
+
+define <2 x i32> @positive_biggerLshl_vec_nonsplat(<2 x i32> %x) {
+; CHECK-LABEL: @positive_biggerLshl_vec_nonsplat(
+; CHECK-NEXT:    [[TMP0:%.*]] = shl <2 x i32> [[X:%.*]], <i32 5, i32 10>
+; CHECK-NEXT:    [[RET:%.*]] = lshr <2 x i32> [[TMP0]], <i32 5, i32 5>
+; CHECK-NEXT:    ret <2 x i32> [[RET]]
+;
+  %tmp0 = shl <2 x i32> %x, <i32 5, i32 10>
+  %ret = lshr <2 x i32> %tmp0, <i32 5, i32 5>
+  ret <2 x i32> %ret
+}
+
+; ============================================================================ ;
+; Negative tests. Should not be folded.
+; ============================================================================ ;
+
+define i32 @negative_twovars(i32 %x, i32 %y, i32 %z) {
+; CHECK-LABEL: @negative_twovars(
+; CHECK-NEXT:    [[TMP0:%.*]] = shl i32 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    [[RET:%.*]] = lshr i32 [[TMP0]], [[Z:%.*]]
+; CHECK-NEXT:    ret i32 [[RET]]
+;
+  %tmp0 = shl i32 %x, %y
+  %ret = lshr i32 %tmp0, %z ; $z, not %y
+  ret i32 %ret
+}
+
+declare void @use32(i32)
+
+; One use only.
+define i32 @negative_oneuse(i32 %x, i32 %y) {
+; CHECK-LABEL: @negative_oneuse(
+; CHECK-NEXT:    [[TMP0:%.*]] = shl i32 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    call void @use32(i32 [[TMP0]])
+; CHECK-NEXT:    [[RET:%.*]] = lshr i32 [[TMP0]], [[Y]]
+; CHECK-NEXT:    ret i32 [[RET]]
+;
+  %tmp0 = shl i32 %x, %y
+  call void @use32(i32 %tmp0)
+  %ret = lshr i32 %tmp0, %y
+  ret i32 %ret
+}

Added: llvm/trunk/test/Transforms/InstCombine/canonicalize-signed-truncation-check.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/canonicalize-signed-truncation-check.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/canonicalize-signed-truncation-check.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/canonicalize-signed-truncation-check.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,234 @@
+; 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=38149
+
+; Pattern:
+;   ((%x << MaskedBits) a>> MaskedBits) != %x
+; Should be transformed into:
+;   (add %x, (1 << (KeptBits-1))) u>= (1 << KeptBits)
+; Where  KeptBits = bitwidth(%x) - MaskedBits
+
+; ============================================================================ ;
+; Basic positive tests
+; ============================================================================ ;
+
+define i1 @p0(i8 %x) {
+; CHECK-LABEL: @p0(
+; CHECK-NEXT:    [[TMP1:%.*]] = add i8 [[X:%.*]], 4
+; CHECK-NEXT:    [[TMP2:%.*]] = icmp ugt i8 [[TMP1]], 7
+; CHECK-NEXT:    ret i1 [[TMP2]]
+;
+  %tmp0 = shl i8 %x, 5
+  %tmp1 = ashr exact i8 %tmp0, 5
+  %tmp2 = icmp ne i8 %tmp1, %x
+  ret i1 %tmp2
+}
+
+; Big unusual bit width, https://bugs.llvm.org/show_bug.cgi?id=38204
+define i1 @pb(i65 %x) {
+; CHECK-LABEL: @pb(
+; CHECK-NEXT:    [[TMP1:%.*]] = add i65 [[X:%.*]], 9223372036854775808
+; CHECK-NEXT:    [[TMP2:%.*]] = icmp slt i65 [[TMP1]], 0
+; CHECK-NEXT:    ret i1 [[TMP2]]
+;
+  %tmp0 = shl i65 %x, 1
+  %tmp1 = ashr exact i65 %tmp0, 1
+  %tmp2 = icmp ne i65 %x, %tmp1
+  ret i1 %tmp2
+}
+
+; ============================================================================ ;
+; Vector tests
+; ============================================================================ ;
+
+define <2 x i1> @p1_vec_splat(<2 x i8> %x) {
+; CHECK-LABEL: @p1_vec_splat(
+; CHECK-NEXT:    [[TMP1:%.*]] = add <2 x i8> [[X:%.*]], <i8 4, i8 4>
+; CHECK-NEXT:    [[TMP2:%.*]] = icmp ugt <2 x i8> [[TMP1]], <i8 7, i8 7>
+; CHECK-NEXT:    ret <2 x i1> [[TMP2]]
+;
+  %tmp0 = shl <2 x i8> %x, <i8 5, i8 5>
+  %tmp1 = ashr exact <2 x i8> %tmp0, <i8 5, i8 5>
+  %tmp2 = icmp ne <2 x i8> %tmp1, %x
+  ret <2 x i1> %tmp2
+}
+
+define <2 x i1> @p2_vec_nonsplat(<2 x i8> %x) {
+; CHECK-LABEL: @p2_vec_nonsplat(
+; CHECK-NEXT:    [[TMP0:%.*]] = shl <2 x i8> [[X:%.*]], <i8 5, i8 6>
+; CHECK-NEXT:    [[TMP1:%.*]] = ashr exact <2 x i8> [[TMP0]], <i8 5, i8 6>
+; CHECK-NEXT:    [[TMP2:%.*]] = icmp ne <2 x i8> [[TMP1]], [[X]]
+; CHECK-NEXT:    ret <2 x i1> [[TMP2]]
+;
+  %tmp0 = shl <2 x i8> %x, <i8 5, i8 6>
+  %tmp1 = ashr exact <2 x i8> %tmp0, <i8 5, i8 6>
+  %tmp2 = icmp ne <2 x i8> %tmp1, %x
+  ret <2 x i1> %tmp2
+}
+
+define <3 x i1> @p3_vec_undef0(<3 x i8> %x) {
+; CHECK-LABEL: @p3_vec_undef0(
+; CHECK-NEXT:    [[TMP0:%.*]] = shl <3 x i8> [[X:%.*]], <i8 5, i8 undef, i8 5>
+; CHECK-NEXT:    [[TMP1:%.*]] = ashr exact <3 x i8> [[TMP0]], <i8 5, i8 5, i8 5>
+; CHECK-NEXT:    [[TMP2:%.*]] = icmp ne <3 x i8> [[TMP1]], [[X]]
+; CHECK-NEXT:    ret <3 x i1> [[TMP2]]
+;
+  %tmp0 = shl <3 x i8> %x, <i8 5, i8 undef, i8 5>
+  %tmp1 = ashr exact <3 x i8> %tmp0, <i8 5, i8 5, i8 5>
+  %tmp2 = icmp ne <3 x i8> %tmp1, %x
+  ret <3 x i1> %tmp2
+}
+
+define <3 x i1> @p4_vec_undef1(<3 x i8> %x) {
+; CHECK-LABEL: @p4_vec_undef1(
+; CHECK-NEXT:    [[TMP0:%.*]] = shl <3 x i8> [[X:%.*]], <i8 5, i8 5, i8 5>
+; CHECK-NEXT:    [[TMP1:%.*]] = ashr exact <3 x i8> [[TMP0]], <i8 5, i8 undef, i8 5>
+; CHECK-NEXT:    [[TMP2:%.*]] = icmp ne <3 x i8> [[TMP1]], [[X]]
+; CHECK-NEXT:    ret <3 x i1> [[TMP2]]
+;
+  %tmp0 = shl <3 x i8> %x, <i8 5, i8 5, i8 5>
+  %tmp1 = ashr exact <3 x i8> %tmp0, <i8 5, i8 undef, i8 5>
+  %tmp2 = icmp ne <3 x i8> %tmp1, %x
+  ret <3 x i1> %tmp2
+}
+
+define <3 x i1> @p5_vec_undef2(<3 x i8> %x) {
+; CHECK-LABEL: @p5_vec_undef2(
+; CHECK-NEXT:    [[TMP0:%.*]] = shl <3 x i8> [[X:%.*]], <i8 5, i8 undef, i8 5>
+; CHECK-NEXT:    [[TMP1:%.*]] = ashr exact <3 x i8> [[TMP0]], <i8 5, i8 undef, i8 5>
+; CHECK-NEXT:    [[TMP2:%.*]] = icmp ne <3 x i8> [[TMP1]], [[X]]
+; CHECK-NEXT:    ret <3 x i1> [[TMP2]]
+;
+  %tmp0 = shl <3 x i8> %x, <i8 5, i8 undef, i8 5>
+  %tmp1 = ashr exact <3 x i8> %tmp0, <i8 5, i8 undef, i8 5>
+  %tmp2 = icmp ne <3 x i8> %tmp1, %x
+  ret <3 x i1> %tmp2
+}
+
+; ============================================================================ ;
+; Commutativity tests.
+; ============================================================================ ;
+
+declare i8 @gen8()
+
+define i1 @c0() {
+; CHECK-LABEL: @c0(
+; CHECK-NEXT:    [[X:%.*]] = call i8 @gen8()
+; CHECK-NEXT:    [[TMP1:%.*]] = add i8 [[X]], 4
+; CHECK-NEXT:    [[TMP2:%.*]] = icmp ugt i8 [[TMP1]], 7
+; CHECK-NEXT:    ret i1 [[TMP2]]
+;
+  %x = call i8 @gen8()
+  %tmp0 = shl i8 %x, 5
+  %tmp1 = ashr exact i8 %tmp0, 5
+  %tmp2 = icmp ne i8 %x, %tmp1 ; swapped order
+  ret i1 %tmp2
+}
+
+; ============================================================================ ;
+; One-use tests.
+; ============================================================================ ;
+
+declare void @use8(i8)
+
+define i1 @n_oneuse0(i8 %x) {
+; CHECK-LABEL: @n_oneuse0(
+; CHECK-NEXT:    [[TMP0:%.*]] = shl i8 [[X:%.*]], 5
+; CHECK-NEXT:    call void @use8(i8 [[TMP0]])
+; CHECK-NEXT:    [[TMP1:%.*]] = add i8 [[X]], 4
+; CHECK-NEXT:    [[TMP2:%.*]] = icmp ugt i8 [[TMP1]], 7
+; CHECK-NEXT:    ret i1 [[TMP2]]
+;
+  %tmp0 = shl i8 %x, 5
+  call void @use8(i8 %tmp0)
+  %tmp1 = ashr exact i8 %tmp0, 5
+  %tmp2 = icmp ne i8 %tmp1, %x
+  ret i1 %tmp2
+}
+
+define i1 @n_oneuse1(i8 %x) {
+; CHECK-LABEL: @n_oneuse1(
+; CHECK-NEXT:    [[TMP0:%.*]] = shl i8 [[X:%.*]], 5
+; CHECK-NEXT:    [[TMP1:%.*]] = ashr exact i8 [[TMP0]], 5
+; CHECK-NEXT:    call void @use8(i8 [[TMP1]])
+; CHECK-NEXT:    [[TMP2:%.*]] = icmp ne i8 [[TMP1]], [[X]]
+; CHECK-NEXT:    ret i1 [[TMP2]]
+;
+  %tmp0 = shl i8 %x, 5
+  %tmp1 = ashr exact i8 %tmp0, 5
+  call void @use8(i8 %tmp1)
+  %tmp2 = icmp ne i8 %tmp1, %x
+  ret i1 %tmp2
+}
+
+define i1 @n_oneuse2(i8 %x) {
+; CHECK-LABEL: @n_oneuse2(
+; CHECK-NEXT:    [[TMP0:%.*]] = shl i8 [[X:%.*]], 5
+; CHECK-NEXT:    call void @use8(i8 [[TMP0]])
+; CHECK-NEXT:    [[TMP1:%.*]] = ashr exact i8 [[TMP0]], 5
+; CHECK-NEXT:    call void @use8(i8 [[TMP1]])
+; CHECK-NEXT:    [[TMP2:%.*]] = icmp ne i8 [[TMP1]], [[X]]
+; CHECK-NEXT:    ret i1 [[TMP2]]
+;
+  %tmp0 = shl i8 %x, 5
+  call void @use8(i8 %tmp0)
+  %tmp1 = ashr exact i8 %tmp0, 5
+  call void @use8(i8 %tmp1)
+  %tmp2 = icmp ne i8 %tmp1, %x
+  ret i1 %tmp2
+}
+
+; ============================================================================ ;
+; Negative tests
+; ============================================================================ ;
+
+define i1 @n0(i8 %x) {
+; CHECK-LABEL: @n0(
+; CHECK-NEXT:    [[TMP0:%.*]] = shl i8 [[X:%.*]], 5
+; CHECK-NEXT:    [[TMP1:%.*]] = ashr exact i8 [[TMP0]], 3
+; CHECK-NEXT:    [[TMP2:%.*]] = icmp ne i8 [[TMP1]], [[X]]
+; CHECK-NEXT:    ret i1 [[TMP2]]
+;
+  %tmp0 = shl i8 %x, 5
+  %tmp1 = ashr exact i8 %tmp0, 3 ; not 5
+  %tmp2 = icmp ne i8 %tmp1, %x
+  ret i1 %tmp2
+}
+
+define i1 @n1(i8 %x) {
+; CHECK-LABEL: @n1(
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp ugt i8 [[X:%.*]], 7
+; CHECK-NEXT:    ret i1 [[TMP1]]
+;
+  %tmp0 = shl i8 %x, 5
+  %tmp1 = lshr exact i8 %tmp0, 5 ; not ashr
+  %tmp2 = icmp ne i8 %tmp1, %x
+  ret i1 %tmp2
+}
+
+define i1 @n2(i8 %x, i8 %y) {
+; CHECK-LABEL: @n2(
+; CHECK-NEXT:    [[TMP0:%.*]] = shl i8 [[X:%.*]], 5
+; CHECK-NEXT:    [[TMP1:%.*]] = ashr exact i8 [[TMP0]], 5
+; CHECK-NEXT:    [[TMP2:%.*]] = icmp ne i8 [[TMP1]], [[Y:%.*]]
+; CHECK-NEXT:    ret i1 [[TMP2]]
+;
+  %tmp0 = shl i8 %x, 5
+  %tmp1 = ashr exact i8 %tmp0, 5
+  %tmp2 = icmp ne i8 %tmp1, %y ; not %x
+  ret i1 %tmp2
+}
+
+define <2 x i1> @n3_vec_nonsplat(<2 x i8> %x) {
+; CHECK-LABEL: @n3_vec_nonsplat(
+; CHECK-NEXT:    [[TMP0:%.*]] = shl <2 x i8> [[X:%.*]], <i8 5, i8 5>
+; CHECK-NEXT:    [[TMP1:%.*]] = ashr exact <2 x i8> [[TMP0]], <i8 5, i8 3>
+; CHECK-NEXT:    [[TMP2:%.*]] = icmp ne <2 x i8> [[TMP1]], [[X]]
+; CHECK-NEXT:    ret <2 x i1> [[TMP2]]
+;
+  %tmp0 = shl <2 x i8> %x, <i8 5, i8 5>
+  %tmp1 = ashr exact <2 x i8> %tmp0, <i8 5, i8 3> ; 3 instead of 5
+  %tmp2 = icmp ne <2 x i8> %tmp1, %x
+  ret <2 x i1> %tmp2
+}

Added: llvm/trunk/test/Transforms/InstCombine/canonicalize_branch.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/canonicalize_branch.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/canonicalize_branch.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/canonicalize_branch.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,500 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt < %s -instcombine -S | FileCheck %s
+
+; Test an already canonical branch to make sure we don't flip those.
+define i32 @eq(i32 %X, i32 %Y) {
+; CHECK-LABEL: @eq(
+; CHECK-NEXT:    [[C:%.*]] = icmp eq i32 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    br i1 [[C]], label [[T:%.*]], label [[F:%.*]], !prof !0
+; CHECK:       T:
+; CHECK-NEXT:    ret i32 12
+; CHECK:       F:
+; CHECK-NEXT:    ret i32 123
+;
+  %C = icmp eq i32 %X, %Y
+  br i1 %C, label %T, label %F, !prof !0
+T:
+  ret i32 12
+F:
+  ret i32 123
+}
+
+define i32 @ne(i32 %X, i32 %Y) {
+; CHECK-LABEL: @ne(
+; CHECK-NEXT:    [[C:%.*]] = icmp eq i32 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    br i1 [[C]], label [[F:%.*]], label [[T:%.*]], !prof !1
+; CHECK:       T:
+; CHECK-NEXT:    ret i32 12
+; CHECK:       F:
+; CHECK-NEXT:    ret i32 123
+;
+  %C = icmp ne i32 %X, %Y
+  br i1 %C, label %T, label %F, !prof !1
+T:
+  ret i32 12
+F:
+  ret i32 123
+}
+
+define i32 @ugt(i32 %X, i32 %Y) {
+; CHECK-LABEL: @ugt(
+; CHECK-NEXT:    [[C:%.*]] = icmp ugt i32 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    br i1 [[C]], label [[T:%.*]], label [[F:%.*]], !prof !2
+; CHECK:       T:
+; CHECK-NEXT:    ret i32 12
+; CHECK:       F:
+; CHECK-NEXT:    ret i32 123
+;
+  %C = icmp ugt i32 %X, %Y
+  br i1 %C, label %T, label %F, !prof !2
+T:
+  ret i32 12
+F:
+  ret i32 123
+}
+
+define i32 @uge(i32 %X, i32 %Y) {
+; CHECK-LABEL: @uge(
+; CHECK-NEXT:    [[C:%.*]] = icmp ult i32 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    br i1 [[C]], label [[F:%.*]], label [[T:%.*]], !prof !3
+; CHECK:       T:
+; CHECK-NEXT:    ret i32 12
+; CHECK:       F:
+; CHECK-NEXT:    ret i32 123
+;
+  %C = icmp uge i32 %X, %Y
+  br i1 %C, label %T, label %F, !prof !3
+T:
+  ret i32 12
+F:
+  ret i32 123
+}
+
+define i32 @ult(i32 %X, i32 %Y) {
+; CHECK-LABEL: @ult(
+; CHECK-NEXT:    [[C:%.*]] = icmp ult i32 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    br i1 [[C]], label [[T:%.*]], label [[F:%.*]], !prof !4
+; CHECK:       T:
+; CHECK-NEXT:    ret i32 12
+; CHECK:       F:
+; CHECK-NEXT:    ret i32 123
+;
+  %C = icmp ult i32 %X, %Y
+  br i1 %C, label %T, label %F, !prof !4
+T:
+  ret i32 12
+F:
+  ret i32 123
+}
+
+define i32 @ule(i32 %X, i32 %Y) {
+; CHECK-LABEL: @ule(
+; CHECK-NEXT:    [[C:%.*]] = icmp ugt i32 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    br i1 [[C]], label [[F:%.*]], label [[T:%.*]], !prof !5
+; CHECK:       T:
+; CHECK-NEXT:    ret i32 12
+; CHECK:       F:
+; CHECK-NEXT:    ret i32 123
+;
+  %C = icmp ule i32 %X, %Y
+  br i1 %C, label %T, label %F, !prof !5
+T:
+  ret i32 12
+F:
+  ret i32 123
+}
+
+define i32 @sgt(i32 %X, i32 %Y) {
+; CHECK-LABEL: @sgt(
+; CHECK-NEXT:    [[C:%.*]] = icmp sgt i32 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    br i1 [[C]], label [[T:%.*]], label [[F:%.*]], !prof !6
+; CHECK:       T:
+; CHECK-NEXT:    ret i32 12
+; CHECK:       F:
+; CHECK-NEXT:    ret i32 123
+;
+  %C = icmp sgt i32 %X, %Y
+  br i1 %C, label %T, label %F, !prof !6
+T:
+  ret i32 12
+F:
+  ret i32 123
+}
+
+define i32 @sge(i32 %X, i32 %Y) {
+; CHECK-LABEL: @sge(
+; CHECK-NEXT:    [[C:%.*]] = icmp slt i32 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    br i1 [[C]], label [[F:%.*]], label [[T:%.*]], !prof !7
+; CHECK:       T:
+; CHECK-NEXT:    ret i32 12
+; CHECK:       F:
+; CHECK-NEXT:    ret i32 123
+;
+  %C = icmp sge i32 %X, %Y
+  br i1 %C, label %T, label %F, !prof !7
+T:
+  ret i32 12
+F:
+  ret i32 123
+}
+
+define i32 @slt(i32 %X, i32 %Y) {
+; CHECK-LABEL: @slt(
+; CHECK-NEXT:    [[C:%.*]] = icmp slt i32 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    br i1 [[C]], label [[T:%.*]], label [[F:%.*]], !prof !8
+; CHECK:       T:
+; CHECK-NEXT:    ret i32 12
+; CHECK:       F:
+; CHECK-NEXT:    ret i32 123
+;
+  %C = icmp slt i32 %X, %Y
+  br i1 %C, label %T, label %F, !prof !8
+T:
+  ret i32 12
+F:
+  ret i32 123
+}
+
+define i32 @sle(i32 %X, i32 %Y) {
+; CHECK-LABEL: @sle(
+; CHECK-NEXT:    [[C:%.*]] = icmp sgt i32 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    br i1 [[C]], label [[F:%.*]], label [[T:%.*]], !prof !9
+; CHECK:       T:
+; CHECK-NEXT:    ret i32 12
+; CHECK:       F:
+; CHECK-NEXT:    ret i32 123
+;
+  %C = icmp sle i32 %X, %Y
+  br i1 %C, label %T, label %F, !prof !9
+T:
+  ret i32 12
+F:
+  ret i32 123
+}
+
+define i32 @f_false(float %X, float %Y) {
+; CHECK-LABEL: @f_false(
+; CHECK-NEXT:    br i1 false, label [[T:%.*]], label [[F:%.*]], !prof !10
+; CHECK:       T:
+; CHECK-NEXT:    ret i32 12
+; CHECK:       F:
+; CHECK-NEXT:    ret i32 123
+;
+  %C = fcmp false float %X, %Y
+  br i1 %C, label %T, label %F, !prof !10
+T:
+  ret i32 12
+F:
+  ret i32 123
+}
+
+define i32 @f_oeq(float %X, float %Y) {
+; CHECK-LABEL: @f_oeq(
+; CHECK-NEXT:    [[C:%.*]] = fcmp oeq float [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    br i1 [[C]], label [[T:%.*]], label [[F:%.*]], !prof !11
+; CHECK:       T:
+; CHECK-NEXT:    ret i32 12
+; CHECK:       F:
+; CHECK-NEXT:    ret i32 123
+;
+  %C = fcmp oeq float %X, %Y
+  br i1 %C, label %T, label %F, !prof !11
+T:
+  ret i32 12
+F:
+  ret i32 123
+}
+
+define i32 @f_ogt(float %X, float %Y) {
+; CHECK-LABEL: @f_ogt(
+; CHECK-NEXT:    [[C:%.*]] = fcmp ogt float [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    br i1 [[C]], label [[T:%.*]], label [[F:%.*]], !prof !12
+; CHECK:       T:
+; CHECK-NEXT:    ret i32 12
+; CHECK:       F:
+; CHECK-NEXT:    ret i32 123
+;
+  %C = fcmp ogt float %X, %Y
+  br i1 %C, label %T, label %F, !prof !12
+T:
+  ret i32 12
+F:
+  ret i32 123
+}
+
+define i32 @f_oge(float %X, float %Y) {
+; CHECK-LABEL: @f_oge(
+; CHECK-NEXT:    [[C:%.*]] = fcmp ult float [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    br i1 [[C]], label [[F:%.*]], label [[T:%.*]], !prof !13
+; CHECK:       T:
+; CHECK-NEXT:    ret i32 12
+; CHECK:       F:
+; CHECK-NEXT:    ret i32 123
+;
+  %C = fcmp oge float %X, %Y
+  br i1 %C, label %T, label %F, !prof !13
+T:
+  ret i32 12
+F:
+  ret i32 123
+}
+
+define i32 @f_olt(float %X, float %Y) {
+; CHECK-LABEL: @f_olt(
+; CHECK-NEXT:    [[C:%.*]] = fcmp olt float [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    br i1 [[C]], label [[T:%.*]], label [[F:%.*]], !prof !14
+; CHECK:       T:
+; CHECK-NEXT:    ret i32 12
+; CHECK:       F:
+; CHECK-NEXT:    ret i32 123
+;
+  %C = fcmp olt float %X, %Y
+  br i1 %C, label %T, label %F, !prof !14
+T:
+  ret i32 12
+F:
+  ret i32 123
+}
+
+define i32 @f_ole(float %X, float %Y) {
+; CHECK-LABEL: @f_ole(
+; CHECK-NEXT:    [[C:%.*]] = fcmp ugt float [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    br i1 [[C]], label [[F:%.*]], label [[T:%.*]], !prof !15
+; CHECK:       T:
+; CHECK-NEXT:    ret i32 12
+; CHECK:       F:
+; CHECK-NEXT:    ret i32 123
+;
+  %C = fcmp ole float %X, %Y
+  br i1 %C, label %T, label %F, !prof !15
+T:
+  ret i32 12
+F:
+  ret i32 123
+}
+
+define i32 @f_one(float %X, float %Y) {
+; CHECK-LABEL: @f_one(
+; CHECK-NEXT:    [[C:%.*]] = fcmp ueq float [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    br i1 [[C]], label [[F:%.*]], label [[T:%.*]], !prof !16
+; CHECK:       T:
+; CHECK-NEXT:    ret i32 12
+; CHECK:       F:
+; CHECK-NEXT:    ret i32 123
+;
+  %C = fcmp one float %X, %Y
+  br i1 %C, label %T, label %F, !prof !16
+T:
+  ret i32 12
+F:
+  ret i32 123
+}
+
+define i32 @f_ord(float %X, float %Y) {
+; CHECK-LABEL: @f_ord(
+; CHECK-NEXT:    [[C:%.*]] = fcmp ord float [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    br i1 [[C]], label [[T:%.*]], label [[F:%.*]], !prof !17
+; CHECK:       T:
+; CHECK-NEXT:    ret i32 12
+; CHECK:       F:
+; CHECK-NEXT:    ret i32 123
+;
+  %C = fcmp ord float %X, %Y
+  br i1 %C, label %T, label %F, !prof !17
+T:
+  ret i32 12
+F:
+  ret i32 123
+}
+
+define i32 @f_uno(float %X, float %Y) {
+; CHECK-LABEL: @f_uno(
+; CHECK-NEXT:    [[C:%.*]] = fcmp uno float [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    br i1 [[C]], label [[T:%.*]], label [[F:%.*]], !prof !18
+; CHECK:       T:
+; CHECK-NEXT:    ret i32 12
+; CHECK:       F:
+; CHECK-NEXT:    ret i32 123
+;
+  %C = fcmp uno float %X, %Y
+  br i1 %C, label %T, label %F, !prof !18
+T:
+  ret i32 12
+F:
+  ret i32 123
+}
+
+define i32 @f_ueq(float %X, float %Y) {
+; CHECK-LABEL: @f_ueq(
+; CHECK-NEXT:    [[C:%.*]] = fcmp ueq float [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    br i1 [[C]], label [[T:%.*]], label [[F:%.*]], !prof !19
+; CHECK:       T:
+; CHECK-NEXT:    ret i32 12
+; CHECK:       F:
+; CHECK-NEXT:    ret i32 123
+;
+  %C = fcmp ueq float %X, %Y
+  br i1 %C, label %T, label %F, !prof !19
+T:
+  ret i32 12
+F:
+  ret i32 123
+}
+
+define i32 @f_ugt(float %X, float %Y) {
+; CHECK-LABEL: @f_ugt(
+; CHECK-NEXT:    [[C:%.*]] = fcmp ugt float [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    br i1 [[C]], label [[T:%.*]], label [[F:%.*]], !prof !20
+; CHECK:       T:
+; CHECK-NEXT:    ret i32 12
+; CHECK:       F:
+; CHECK-NEXT:    ret i32 123
+;
+  %C = fcmp ugt float %X, %Y
+  br i1 %C, label %T, label %F, !prof !20
+T:
+  ret i32 12
+F:
+  ret i32 123
+}
+
+define i32 @f_uge(float %X, float %Y) {
+; CHECK-LABEL: @f_uge(
+; CHECK-NEXT:    [[C:%.*]] = fcmp uge float [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    br i1 [[C]], label [[T:%.*]], label [[F:%.*]], !prof !21
+; CHECK:       T:
+; CHECK-NEXT:    ret i32 12
+; CHECK:       F:
+; CHECK-NEXT:    ret i32 123
+;
+  %C = fcmp uge float %X, %Y
+  br i1 %C, label %T, label %F, !prof !21
+T:
+  ret i32 12
+F:
+  ret i32 123
+}
+
+define i32 @f_ult(float %X, float %Y) {
+; CHECK-LABEL: @f_ult(
+; CHECK-NEXT:    [[C:%.*]] = fcmp ult float [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    br i1 [[C]], label [[T:%.*]], label [[F:%.*]], !prof !22
+; CHECK:       T:
+; CHECK-NEXT:    ret i32 12
+; CHECK:       F:
+; CHECK-NEXT:    ret i32 123
+;
+  %C = fcmp ult float %X, %Y
+  br i1 %C, label %T, label %F, !prof !22
+T:
+  ret i32 12
+F:
+  ret i32 123
+}
+
+define i32 @f_ule(float %X, float %Y) {
+; CHECK-LABEL: @f_ule(
+; CHECK-NEXT:    [[C:%.*]] = fcmp ule float [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    br i1 [[C]], label [[T:%.*]], label [[F:%.*]], !prof !23
+; CHECK:       T:
+; CHECK-NEXT:    ret i32 12
+; CHECK:       F:
+; CHECK-NEXT:    ret i32 123
+;
+  %C = fcmp ule float %X, %Y
+  br i1 %C, label %T, label %F, !prof !23
+T:
+  ret i32 12
+F:
+  ret i32 123
+}
+
+define i32 @f_une(float %X, float %Y) {
+; CHECK-LABEL: @f_une(
+; CHECK-NEXT:    [[C:%.*]] = fcmp une float [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    br i1 [[C]], label [[T:%.*]], label [[F:%.*]], !prof !24
+; CHECK:       T:
+; CHECK-NEXT:    ret i32 12
+; CHECK:       F:
+; CHECK-NEXT:    ret i32 123
+;
+  %C = fcmp une float %X, %Y
+  br i1 %C, label %T, label %F, !prof !24
+T:
+  ret i32 12
+F:
+  ret i32 123
+}
+
+define i32 @f_true(float %X, float %Y) {
+; CHECK-LABEL: @f_true(
+; CHECK-NEXT:    br i1 true, label [[T:%.*]], label [[F:%.*]], !prof !25
+; CHECK:       T:
+; CHECK-NEXT:    ret i32 12
+; CHECK:       F:
+; CHECK-NEXT:    ret i32 123
+;
+  %C = fcmp true float %X, %Y
+  br i1 %C, label %T, label %F, !prof !25
+T:
+  ret i32 12
+F:
+  ret i32 123
+}
+
+
+!0  = !{!"branch_weights", i32 0,  i32 99}
+!1  = !{!"branch_weights", i32 1,  i32 99}
+!2  = !{!"branch_weights", i32 2,  i32 99}
+!3  = !{!"branch_weights", i32 3,  i32 99}
+!4  = !{!"branch_weights", i32 4,  i32 99}
+!5  = !{!"branch_weights", i32 5,  i32 99}
+!6  = !{!"branch_weights", i32 6,  i32 99}
+!7  = !{!"branch_weights", i32 7,  i32 99}
+!8  = !{!"branch_weights", i32 8,  i32 99}
+!9  = !{!"branch_weights", i32 9,  i32 99}
+!10 = !{!"branch_weights", i32 10, i32 99}
+!11 = !{!"branch_weights", i32 11, i32 99}
+!12 = !{!"branch_weights", i32 12, i32 99}
+!13 = !{!"branch_weights", i32 13, i32 99}
+!14 = !{!"branch_weights", i32 14, i32 99}
+!15 = !{!"branch_weights", i32 15, i32 99}
+!16 = !{!"branch_weights", i32 16, i32 99}
+!17 = !{!"branch_weights", i32 17, i32 99}
+!18 = !{!"branch_weights", i32 18, i32 99}
+!19 = !{!"branch_weights", i32 19, i32 99}
+!20 = !{!"branch_weights", i32 20, i32 99}
+!21 = !{!"branch_weights", i32 21, i32 99}
+!22 = !{!"branch_weights", i32 22, i32 99}
+!23 = !{!"branch_weights", i32 23, i32 99}
+!24 = !{!"branch_weights", i32 24, i32 99}
+!25 = !{!"branch_weights", i32 25, i32 99}
+
+; Ensure that the branch metadata is reversed to match the reversals above.
+; CHECK: !0 = {{.*}} i32 0, i32 99}
+; CHECK: !1 = {{.*}} i32 99, i32 1}
+; CHECK: !2 = {{.*}} i32 2, i32 99}
+; CHECK: !3 = {{.*}} i32 99, i32 3}
+; CHECK: !4 = {{.*}} i32 4, i32 99}
+; CHECK: !5 = {{.*}} i32 99, i32 5}
+; CHECK: !6 = {{.*}} i32 6, i32 99}
+; CHECK: !7 = {{.*}} i32 99, i32 7}
+; CHECK: !8 = {{.*}} i32 8, i32 99}
+; CHECK: !9 = {{.*}} i32 99, i32 9}
+; CHECK: !10 = {{.*}} i32 10, i32 99}
+; CHECK: !11 = {{.*}} i32 11, i32 99}
+; CHECK: !12 = {{.*}} i32 12, i32 99}
+; CHECK: !13 = {{.*}} i32 99, i32 13}
+; CHECK: !14 = {{.*}} i32 14, i32 99}
+; CHECK: !15 = {{.*}} i32 99, i32 15}
+; CHECK: !16 = {{.*}} i32 99, i32 16}
+; CHECK: !17 = {{.*}} i32 17, i32 99}
+; CHECK: !18 = {{.*}} i32 18, i32 99}
+; CHECK: !19 = {{.*}} i32 19, i32 99}
+; CHECK: !20 = {{.*}} i32 20, i32 99}
+; CHECK: !21 = {{.*}} i32 21, i32 99}
+; CHECK: !22 = {{.*}} i32 22, i32 99}
+; CHECK: !23 = {{.*}} i32 23, i32 99}
+; CHECK: !24 = {{.*}} i32 24, i32 99}
+; CHECK: !25 = {{.*}} i32 25, i32 99}
+

Added: llvm/trunk/test/Transforms/InstCombine/cast-call-combine-prof.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/cast-call-combine-prof.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/cast-call-combine-prof.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/cast-call-combine-prof.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,53 @@
+; RUN: opt -S -instcombine < %s | FileCheck -enable-var-scope %s
+
+; Check that instcombine preserves !prof metadata when removing function
+; prototype casts.
+
+declare i32 @__gxx_personality_v0(...)
+declare void @__cxa_call_unexpected(i8*)
+declare void @foo(i16* %a)
+
+; CHECK-LABEL: @test_call()
+; CHECK: call void @foo(i16* null), !prof ![[$PROF:[0-9]+]]
+define void @test_call() {
+  call void bitcast (void (i16*)* @foo to void (i8*)*) (i8* null), !prof !0
+  ret void
+}
+
+; CHECK-LABEL: @test_invoke()
+; CHECK: invoke void @foo(i16* null)
+; CHECK-NEXT: to label %done unwind label %lpad, !prof ![[$PROF]]
+define void @test_invoke() personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) {
+  invoke void bitcast (void (i16*)* @foo to void (i8*)*) (i8* null)
+          to label %done unwind label %lpad, !prof !0
+
+done:
+  ret void
+
+lpad:
+  %lp = landingpad { i8*, i32 }
+          filter [0 x i8*] zeroinitializer
+  %ehptr = extractvalue { i8*, i32 } %lp, 0
+  tail call void @__cxa_call_unexpected(i8* %ehptr) noreturn nounwind
+  unreachable
+}
+
+; CHECK: ![[$PROF]] = !{!"branch_weights", i32 2000}
+!0 = !{!"VP", i32 0, i64 2000, i64 -3913987384944532146, i64 2000}
+
+!llvm.module.flags = !{!1}
+
+!1 = !{i32 1, !"ProfileSummary", !2}
+!2 = !{!3, !4, !5, !6, !7, !8, !9, !10}
+!3 = !{!"ProfileFormat", !"InstrProf"}
+!4 = !{!"TotalCount", i64 10000}
+!5 = !{!"MaxCount", i64 1000}
+!6 = !{!"MaxInternalCount", i64 1}
+!7 = !{!"MaxFunctionCount", i64 1000}
+!8 = !{!"NumCounts", i64 3}
+!9 = !{!"NumFunctions", i64 3}
+!10 = !{!"DetailedSummary", !11}
+!11 = !{!12, !13, !14}
+!12 = !{i32 10000, i64 1000, i32 1}
+!13 = !{i32 999000, i64 1000, i32 1}
+!14 = !{i32 999999, i64 1, i32 2}

Added: llvm/trunk/test/Transforms/InstCombine/cast-call-combine.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/cast-call-combine.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/cast-call-combine.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/cast-call-combine.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,23 @@
+; RUN: opt < %s -always-inline -instcombine -S | FileCheck %s
+
+define internal void @foo(i16*) alwaysinline {
+  ret void
+}
+
+define void @bar() noinline noreturn {
+  unreachable
+}
+
+define void @test() {
+  br i1 false, label %then, label %else
+
+then:
+  call void @bar()
+  unreachable
+
+else:
+  ; CHECK-NOT: call
+  call void bitcast (void (i16*)* @foo to void (i8*)*) (i8* null)
+  ret void
+}
+

Added: llvm/trunk/test/Transforms/InstCombine/cast-callee-deopt-bundles.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/cast-callee-deopt-bundles.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/cast-callee-deopt-bundles.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/cast-callee-deopt-bundles.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,11 @@
+; RUN: opt -instcombine -S < %s | FileCheck %s
+
+declare void @foo(i32)
+
+define void @g() {
+; CHECK-LABEL: @g(
+ entry:
+; CHECK: call void @foo(i32 0) [ "deopt"() ]
+  call void bitcast (void (i32)* @foo to void ()*) ()  [ "deopt"() ]
+  ret void
+}

Added: llvm/trunk/test/Transforms/InstCombine/cast-int-fcmp-eq-0.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/cast-int-fcmp-eq-0.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/cast-int-fcmp-eq-0.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/cast-int-fcmp-eq-0.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,511 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt -S -instcombine < %s | FileCheck %s
+
+define i1 @i32_cast_cmp_oeq_int_0_uitofp(i32 %i) {
+; CHECK-LABEL: @i32_cast_cmp_oeq_int_0_uitofp(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[I:%.*]], 0
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %f = uitofp i32 %i to float
+  %cmp = fcmp oeq float %f, 0.0
+  ret i1 %cmp
+}
+
+define i1 @i32_cast_cmp_oeq_int_n0_uitofp(i32 %i) {
+; CHECK-LABEL: @i32_cast_cmp_oeq_int_n0_uitofp(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[I:%.*]], 0
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %f = uitofp i32 %i to float
+  %cmp = fcmp oeq float %f, -0.0
+  ret i1 %cmp
+}
+
+define i1 @i32_cast_cmp_oeq_int_0_sitofp(i32 %i) {
+; CHECK-LABEL: @i32_cast_cmp_oeq_int_0_sitofp(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[I:%.*]], 0
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %f = sitofp i32 %i to float
+  %cmp = fcmp oeq float %f, 0.0
+  ret i1 %cmp
+}
+
+define i1 @i32_cast_cmp_oeq_int_n0_sitofp(i32 %i) {
+; CHECK-LABEL: @i32_cast_cmp_oeq_int_n0_sitofp(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[I:%.*]], 0
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %f = sitofp i32 %i to float
+  %cmp = fcmp oeq float %f, -0.0
+  ret i1 %cmp
+}
+
+define i1 @i32_cast_cmp_one_int_0_uitofp(i32 %i) {
+; CHECK-LABEL: @i32_cast_cmp_one_int_0_uitofp(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ne i32 [[I:%.*]], 0
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %f = uitofp i32 %i to float
+  %cmp = fcmp one float %f, 0.0
+  ret i1 %cmp
+}
+
+define i1 @i32_cast_cmp_one_int_n0_uitofp(i32 %i) {
+; CHECK-LABEL: @i32_cast_cmp_one_int_n0_uitofp(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ne i32 [[I:%.*]], 0
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %f = uitofp i32 %i to float
+  %cmp = fcmp one float %f, -0.0
+  ret i1 %cmp
+}
+
+define i1 @i32_cast_cmp_one_int_0_sitofp(i32 %i) {
+; CHECK-LABEL: @i32_cast_cmp_one_int_0_sitofp(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ne i32 [[I:%.*]], 0
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %f = sitofp i32 %i to float
+  %cmp = fcmp one float %f, 0.0
+  ret i1 %cmp
+}
+
+define i1 @i32_cast_cmp_one_int_n0_sitofp(i32 %i) {
+; CHECK-LABEL: @i32_cast_cmp_one_int_n0_sitofp(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ne i32 [[I:%.*]], 0
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %f = sitofp i32 %i to float
+  %cmp = fcmp one float %f, -0.0
+  ret i1 %cmp
+}
+
+define i1 @i32_cast_cmp_ueq_int_0_uitofp(i32 %i) {
+; CHECK-LABEL: @i32_cast_cmp_ueq_int_0_uitofp(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[I:%.*]], 0
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %f = uitofp i32 %i to float
+  %cmp = fcmp ueq float %f, 0.0
+  ret i1 %cmp
+}
+
+define i1 @i32_cast_cmp_ueq_int_n0_uitofp(i32 %i) {
+; CHECK-LABEL: @i32_cast_cmp_ueq_int_n0_uitofp(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[I:%.*]], 0
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %f = uitofp i32 %i to float
+  %cmp = fcmp ueq float %f, -0.0
+  ret i1 %cmp
+}
+
+define i1 @i32_cast_cmp_ueq_int_0_sitofp(i32 %i) {
+; CHECK-LABEL: @i32_cast_cmp_ueq_int_0_sitofp(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[I:%.*]], 0
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %f = sitofp i32 %i to float
+  %cmp = fcmp ueq float %f, 0.0
+  ret i1 %cmp
+}
+
+define i1 @i32_cast_cmp_ueq_int_n0_sitofp(i32 %i) {
+; CHECK-LABEL: @i32_cast_cmp_ueq_int_n0_sitofp(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[I:%.*]], 0
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %f = sitofp i32 %i to float
+  %cmp = fcmp ueq float %f, -0.0
+  ret i1 %cmp
+}
+
+define i1 @i32_cast_cmp_une_int_0_uitofp(i32 %i) {
+; CHECK-LABEL: @i32_cast_cmp_une_int_0_uitofp(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ne i32 [[I:%.*]], 0
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %f = uitofp i32 %i to float
+  %cmp = fcmp une float %f, 0.0
+  ret i1 %cmp
+}
+
+define i1 @i32_cast_cmp_une_int_n0_uitofp(i32 %i) {
+; CHECK-LABEL: @i32_cast_cmp_une_int_n0_uitofp(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ne i32 [[I:%.*]], 0
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %f = uitofp i32 %i to float
+  %cmp = fcmp une float %f, -0.0
+  ret i1 %cmp
+}
+
+define i1 @i32_cast_cmp_une_int_0_sitofp(i32 %i) {
+; CHECK-LABEL: @i32_cast_cmp_une_int_0_sitofp(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ne i32 [[I:%.*]], 0
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %f = sitofp i32 %i to float
+  %cmp = fcmp une float %f, 0.0
+  ret i1 %cmp
+}
+
+define i1 @i32_cast_cmp_une_int_n0_sitofp(i32 %i) {
+; CHECK-LABEL: @i32_cast_cmp_une_int_n0_sitofp(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ne i32 [[I:%.*]], 0
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %f = sitofp i32 %i to float
+  %cmp = fcmp une float %f, -0.0
+  ret i1 %cmp
+}
+
+define i1 @i32_cast_cmp_ogt_int_0_uitofp(i32 %i) {
+; CHECK-LABEL: @i32_cast_cmp_ogt_int_0_uitofp(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ne i32 [[I:%.*]], 0
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %f = uitofp i32 %i to float
+  %cmp = fcmp ogt float %f, 0.0
+  ret i1 %cmp
+}
+
+define i1 @i32_cast_cmp_ogt_int_n0_uitofp(i32 %i) {
+; CHECK-LABEL: @i32_cast_cmp_ogt_int_n0_uitofp(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ne i32 [[I:%.*]], 0
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %f = uitofp i32 %i to float
+  %cmp = fcmp ogt float %f, -0.0
+  ret i1 %cmp
+}
+
+define i1 @i32_cast_cmp_ogt_int_0_sitofp(i32 %i) {
+; CHECK-LABEL: @i32_cast_cmp_ogt_int_0_sitofp(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt i32 [[I:%.*]], 0
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %f = sitofp i32 %i to float
+  %cmp = fcmp ogt float %f, 0.0
+  ret i1 %cmp
+}
+
+define i1 @i32_cast_cmp_ogt_int_n0_sitofp(i32 %i) {
+; CHECK-LABEL: @i32_cast_cmp_ogt_int_n0_sitofp(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt i32 [[I:%.*]], 0
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %f = sitofp i32 %i to float
+  %cmp = fcmp ogt float %f, -0.0
+  ret i1 %cmp
+}
+
+define i1 @i32_cast_cmp_ole_int_0_uitofp(i32 %i) {
+; CHECK-LABEL: @i32_cast_cmp_ole_int_0_uitofp(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[I:%.*]], 0
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %f = uitofp i32 %i to float
+  %cmp = fcmp ole float %f, 0.0
+  ret i1 %cmp
+}
+
+define i1 @i32_cast_cmp_ole_int_0_sitofp(i32 %i) {
+; CHECK-LABEL: @i32_cast_cmp_ole_int_0_sitofp(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i32 [[I:%.*]], 1
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %f = sitofp i32 %i to float
+  %cmp = fcmp ole float %f, 0.0
+  ret i1 %cmp
+}
+
+define i1 @i32_cast_cmp_olt_int_0_sitofp(i32 %i) {
+; CHECK-LABEL: @i32_cast_cmp_olt_int_0_sitofp(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i32 [[I:%.*]], 0
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %f = sitofp i32 %i to float
+  %cmp = fcmp olt float %f, 0.0
+  ret i1 %cmp
+}
+
+define i1 @i64_cast_cmp_oeq_int_0_uitofp(i64 %i) {
+; CHECK-LABEL: @i64_cast_cmp_oeq_int_0_uitofp(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i64 [[I:%.*]], 0
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %f = uitofp i64 %i to float
+  %cmp = fcmp oeq float %f, 0.0
+  ret i1 %cmp
+}
+
+define i1 @i64_cast_cmp_oeq_int_0_sitofp(i64 %i) {
+; CHECK-LABEL: @i64_cast_cmp_oeq_int_0_sitofp(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i64 [[I:%.*]], 0
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %f = sitofp i64 %i to float
+  %cmp = fcmp oeq float %f, 0.0
+  ret i1 %cmp
+}
+
+define i1 @i64_cast_cmp_oeq_int_0_uitofp_half(i64 %i) {
+; CHECK-LABEL: @i64_cast_cmp_oeq_int_0_uitofp_half(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i64 [[I:%.*]], 0
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %f = uitofp i64 %i to half
+  %cmp = fcmp oeq half %f, 0.0
+  ret i1 %cmp
+}
+
+define i1 @i64_cast_cmp_oeq_int_0_sitofp_half(i64 %i) {
+; CHECK-LABEL: @i64_cast_cmp_oeq_int_0_sitofp_half(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i64 [[I:%.*]], 0
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %f = sitofp i64 %i to half
+  %cmp = fcmp oeq half %f, 0.0
+  ret i1 %cmp
+}
+
+define i1 @i32_cast_cmp_oeq_int_0_uitofp_ppcf128(i32 %i) {
+; CHECK-LABEL: @i32_cast_cmp_oeq_int_0_uitofp_ppcf128(
+; CHECK-NEXT:    [[F:%.*]] = uitofp i32 [[I:%.*]] to ppc_fp128
+; CHECK-NEXT:    [[CMP:%.*]] = fcmp oeq ppc_fp128 [[F]], 0xM00000000000000000000000000000000
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %f = uitofp i32 %i to ppc_fp128
+  %cmp = fcmp oeq ppc_fp128 %f, 0xM00000000000000000000000000000000
+  ret i1 %cmp
+}
+
+; Since 0xFFFFFF fits in a float, and one less and
+; one more than it also fits without rounding, the
+; test can be optimized to an integer compare.
+
+define i1 @i32_cast_cmp_oeq_int_i24max_uitofp(i32 %i) {
+; CHECK-LABEL: @i32_cast_cmp_oeq_int_i24max_uitofp(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[I:%.*]], 16777215
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %f = uitofp i32 %i to float
+  %cmp = fcmp oeq float %f, 0x416FFFFFE0000000
+  ret i1 %cmp
+}
+
+define i1 @i32_cast_cmp_oeq_int_i24max_sitofp(i32 %i) {
+; CHECK-LABEL: @i32_cast_cmp_oeq_int_i24max_sitofp(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[I:%.*]], 16777215
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %f = sitofp i32 %i to float
+  %cmp = fcmp oeq float %f, 0x416FFFFFE0000000
+  ret i1 %cmp
+}
+
+; Though 0x1000000 fits in a float, one more than it
+; would round to it too, hence a single integer comparison
+; does not suffice.
+
+
+define i1 @i32_cast_cmp_oeq_int_i24maxp1_uitofp(i32 %i) {
+; CHECK-LABEL: @i32_cast_cmp_oeq_int_i24maxp1_uitofp(
+; CHECK-NEXT:    [[F:%.*]] = uitofp i32 [[I:%.*]] to float
+; CHECK-NEXT:    [[CMP:%.*]] = fcmp oeq float [[F]], 0x4170000000000000
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %f = uitofp i32 %i to float
+  %cmp = fcmp oeq float %f, 0x4170000000000000
+  ret i1 %cmp
+}
+
+
+define i1 @i32_cast_cmp_oeq_int_i24maxp1_sitofp(i32 %i) {
+; CHECK-LABEL: @i32_cast_cmp_oeq_int_i24maxp1_sitofp(
+; CHECK-NEXT:    [[F:%.*]] = sitofp i32 [[I:%.*]] to float
+; CHECK-NEXT:    [[CMP:%.*]] = fcmp oeq float [[F]], 0x4170000000000000
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %f = sitofp i32 %i to float
+  %cmp = fcmp oeq float %f, 0x4170000000000000
+  ret i1 %cmp
+}
+
+define i1 @i32_cast_cmp_oeq_int_i32umax_uitofp(i32 %i) {
+; CHECK-LABEL: @i32_cast_cmp_oeq_int_i32umax_uitofp(
+; CHECK-NEXT:    [[F:%.*]] = uitofp i32 [[I:%.*]] to float
+; CHECK-NEXT:    [[CMP:%.*]] = fcmp oeq float [[F]], 0x41F0000000000000
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %f = uitofp i32 %i to float
+  %cmp = fcmp oeq float %f, 0x41F0000000000000
+  ret i1 %cmp
+}
+
+; 32-bit unsigned integer cannot possibly round up to 1<<33
+define i1 @i32_cast_cmp_oeq_int_big_uitofp(i32 %i) {
+; CHECK-LABEL: @i32_cast_cmp_oeq_int_big_uitofp(
+; CHECK-NEXT:    ret i1 false
+;
+  %f = uitofp i32 %i to float
+  %cmp = fcmp oeq float %f, 0x4200000000000000
+  ret i1 %cmp
+}
+
+; 32-bit signed integer cannot possibly round up to 1<<32
+define i1 @i32_cast_cmp_oeq_int_i32umax_sitofp(i32 %i) {
+; CHECK-LABEL: @i32_cast_cmp_oeq_int_i32umax_sitofp(
+; CHECK-NEXT:    ret i1 false
+;
+  %f = sitofp i32 %i to float
+  %cmp = fcmp oeq float %f, 0x41F0000000000000
+  ret i1 %cmp
+}
+
+define i1 @i32_cast_cmp_oeq_int_i32imin_sitofp(i32 %i) {
+; CHECK-LABEL: @i32_cast_cmp_oeq_int_i32imin_sitofp(
+; CHECK-NEXT:    [[F:%.*]] = sitofp i32 [[I:%.*]] to float
+; CHECK-NEXT:    [[CMP:%.*]] = fcmp oeq float [[F]], 0xC1E0000000000000
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %f = sitofp i32 %i to float
+  %cmp = fcmp oeq float %f, 0xC1E0000000000000
+  ret i1 %cmp
+}
+
+define i1 @i32_cast_cmp_oeq_int_i32imax_uitofp(i32 %i) {
+; CHECK-LABEL: @i32_cast_cmp_oeq_int_i32imax_uitofp(
+; CHECK-NEXT:    [[F:%.*]] = uitofp i32 [[I:%.*]] to float
+; CHECK-NEXT:    [[CMP:%.*]] = fcmp oeq float [[F]], 0x41E0000000000000
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %f = uitofp i32 %i to float
+  %cmp = fcmp oeq float %f, 0x41E0000000000000
+  ret i1 %cmp
+}
+
+define i1 @i32_cast_cmp_oeq_int_i32imax_sitofp(i32 %i) {
+; CHECK-LABEL: @i32_cast_cmp_oeq_int_i32imax_sitofp(
+; CHECK-NEXT:    [[F:%.*]] = sitofp i32 [[I:%.*]] to float
+; CHECK-NEXT:    [[CMP:%.*]] = fcmp oeq float [[F]], 0x41E0000000000000
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %f = sitofp i32 %i to float
+  %cmp = fcmp oeq float %f, 0x41E0000000000000
+  ret i1 %cmp
+}
+
+; 32-bit signed integer cannot possibly round to -1<<32
+define i1 @i32_cast_cmp_oeq_int_negi32umax_sitofp(i32 %i) {
+; CHECK-LABEL: @i32_cast_cmp_oeq_int_negi32umax_sitofp(
+; CHECK-NEXT:    ret i1 false
+;
+  %f = sitofp i32 %i to float
+  %cmp = fcmp oeq float %f, 0xC1F0000000000000
+  ret i1 %cmp
+}
+
+define i1 @i32_cast_cmp_oeq_half_uitofp(i32 %i) {
+; CHECK-LABEL: @i32_cast_cmp_oeq_half_uitofp(
+; CHECK-NEXT:    ret i1 false
+;
+  %f = uitofp i32 %i to float
+  %cmp = fcmp oeq float %f, 0.5
+  ret i1 %cmp
+}
+
+define i1 @i32_cast_cmp_oeq_half_sitofp(i32 %i) {
+; CHECK-LABEL: @i32_cast_cmp_oeq_half_sitofp(
+; CHECK-NEXT:    ret i1 false
+;
+  %f = sitofp i32 %i to float
+  %cmp = fcmp oeq float %f, 0.5
+  ret i1 %cmp
+}
+
+define i1 @i32_cast_cmp_one_half_uitofp(i32 %i) {
+; CHECK-LABEL: @i32_cast_cmp_one_half_uitofp(
+; CHECK-NEXT:    ret i1 true
+;
+  %f = uitofp i32 %i to float
+  %cmp = fcmp one float %f, 0.5
+  ret i1 %cmp
+}
+
+define i1 @i32_cast_cmp_one_half_sitofp(i32 %i) {
+; CHECK-LABEL: @i32_cast_cmp_one_half_sitofp(
+; CHECK-NEXT:    ret i1 true
+;
+  %f = sitofp i32 %i to float
+  %cmp = fcmp one float %f, 0.5
+  ret i1 %cmp
+}
+
+define i1 @i32_cast_cmp_ueq_half_uitofp(i32 %i) {
+; CHECK-LABEL: @i32_cast_cmp_ueq_half_uitofp(
+; CHECK-NEXT:    ret i1 false
+;
+  %f = uitofp i32 %i to float
+  %cmp = fcmp ueq float %f, 0.5
+  ret i1 %cmp
+}
+
+define i1 @i32_cast_cmp_ueq_half_sitofp(i32 %i) {
+; CHECK-LABEL: @i32_cast_cmp_ueq_half_sitofp(
+; CHECK-NEXT:    ret i1 false
+;
+  %f = sitofp i32 %i to float
+  %cmp = fcmp ueq float %f, 0.5
+  ret i1 %cmp
+}
+
+define i1 @i32_cast_cmp_une_half_uitofp(i32 %i) {
+; CHECK-LABEL: @i32_cast_cmp_une_half_uitofp(
+; CHECK-NEXT:    ret i1 true
+;
+  %f = uitofp i32 %i to float
+  %cmp = fcmp une float %f, 0.5
+  ret i1 %cmp
+}
+
+define i1 @i32_cast_cmp_une_half_sitofp(i32 %i) {
+; CHECK-LABEL: @i32_cast_cmp_une_half_sitofp(
+; CHECK-NEXT:    ret i1 true
+;
+  %f = sitofp i32 %i to float
+  %cmp = fcmp une float %f, 0.5
+  ret i1 %cmp
+}
+
+define i1 @i32_cast_cmp_oeq_int_inf_uitofp(i32 %i) {
+; CHECK-LABEL: @i32_cast_cmp_oeq_int_inf_uitofp(
+; CHECK-NEXT:    ret i1 false
+;
+  %f = uitofp i32 %i to float
+  %cmp = fcmp oeq float %f, 0x7FF0000000000000
+  ret i1 %cmp
+}
+
+define i1 @i32_cast_cmp_oeq_int_inf_sitofp(i32 %i) {
+; CHECK-LABEL: @i32_cast_cmp_oeq_int_inf_sitofp(
+; CHECK-NEXT:    ret i1 false
+;
+  %f = sitofp i32 %i to float
+  %cmp = fcmp oeq float %f, 0x7FF0000000000000
+  ret i1 %cmp
+}
+
+; An i128 could round to an IEEE single-precision infinity.
+define i1 @i128_cast_cmp_oeq_int_inf_uitofp(i128 %i) {
+; CHECK-LABEL: @i128_cast_cmp_oeq_int_inf_uitofp(
+; CHECK-NEXT:    [[F:%.*]] = uitofp i128 [[I:%.*]] to float
+; CHECK-NEXT:    [[CMP:%.*]] = fcmp oeq float [[F]], 0x7FF0000000000000
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %f = uitofp i128 %i to float
+  %cmp = fcmp oeq float %f, 0x7FF0000000000000
+  ret i1 %cmp
+}

Added: llvm/trunk/test/Transforms/InstCombine/cast-int-icmp-eq-0.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/cast-int-icmp-eq-0.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/cast-int-icmp-eq-0.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/cast-int-icmp-eq-0.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,709 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt < %s -instcombine -S | FileCheck %s
+
+; This is https://bugs.llvm.org/show_bug.cgi?id=36682
+
+; In *all* of these, sitofp and bitcast should be instcombine'd out.
+; "sle 0" is canonicalized to "slt 1",  so we don't test "sle 0" case.
+; "sge 0" is canonicalized to "sgt -1", so we don't test "sge 0" case.
+; "sge 1" is canonicalized to "sgt 0",  so we don't test "sge 1" case.
+; "sle -1" is canonicalized to "slt 0", so we don't test "sle -1" case.
+
+define i1 @i32_cast_cmp_eq_int_0_sitofp_float(i32 %i) {
+; CHECK-LABEL: @i32_cast_cmp_eq_int_0_sitofp_float(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[I:%.*]], 0
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %f = sitofp i32 %i to float
+  %b = bitcast float %f to i32
+  %cmp = icmp eq i32 %b, 0
+  ret i1 %cmp
+}
+
+define i1 @i32_cast_cmp_ne_int_0_sitofp_float(i32 %i) {
+; CHECK-LABEL: @i32_cast_cmp_ne_int_0_sitofp_float(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ne i32 [[I:%.*]], 0
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %f = sitofp i32 %i to float
+  %b = bitcast float %f to i32
+  %cmp = icmp ne i32 %b, 0
+  ret i1 %cmp
+}
+
+define i1 @i32_cast_cmp_slt_int_0_sitofp_float(i32 %i) {
+; CHECK-LABEL: @i32_cast_cmp_slt_int_0_sitofp_float(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i32 [[I:%.*]], 0
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %f = sitofp i32 %i to float
+  %b = bitcast float %f to i32
+  %cmp = icmp slt i32 %b, 0
+  ret i1 %cmp
+}
+
+define i1 @i32_cast_cmp_sgt_int_0_sitofp_float(i32 %i) {
+; CHECK-LABEL: @i32_cast_cmp_sgt_int_0_sitofp_float(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt i32 [[I:%.*]], 0
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %f = sitofp i32 %i to float
+  %b = bitcast float %f to i32
+  %cmp = icmp sgt i32 %b, 0
+  ret i1 %cmp
+}
+
+define i1 @i32_cast_cmp_slt_int_1_sitofp_float(i32 %i) {
+; CHECK-LABEL: @i32_cast_cmp_slt_int_1_sitofp_float(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i32 [[I:%.*]], 1
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %f = sitofp i32 %i to float
+  %b = bitcast float %f to i32
+  %cmp = icmp slt i32 %b, 1
+  ret i1 %cmp
+}
+
+define i1 @i32_cast_cmp_sgt_int_m1_sitofp_float(i32 %i) {
+; CHECK-LABEL: @i32_cast_cmp_sgt_int_m1_sitofp_float(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt i32 [[I:%.*]], -1
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %f = sitofp i32 %i to float
+  %b = bitcast float %f to i32
+  %cmp = icmp sgt i32 %b, -1
+  ret i1 %cmp
+}
+
+define i1 @i32_cast_cmp_eq_int_0_sitofp_double(i32 %i) {
+; CHECK-LABEL: @i32_cast_cmp_eq_int_0_sitofp_double(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[I:%.*]], 0
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %f = sitofp i32 %i to double
+  %b = bitcast double %f to i64
+  %cmp = icmp eq i64 %b, 0
+  ret i1 %cmp
+}
+
+define i1 @i32_cast_cmp_ne_int_0_sitofp_double(i32 %i) {
+; CHECK-LABEL: @i32_cast_cmp_ne_int_0_sitofp_double(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ne i32 [[I:%.*]], 0
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %f = sitofp i32 %i to double
+  %b = bitcast double %f to i64
+  %cmp = icmp ne i64 %b, 0
+  ret i1 %cmp
+}
+
+define i1 @i32_cast_cmp_slt_int_0_sitofp_double(i32 %i) {
+; CHECK-LABEL: @i32_cast_cmp_slt_int_0_sitofp_double(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i32 [[I:%.*]], 0
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %f = sitofp i32 %i to double
+  %b = bitcast double %f to i64
+  %cmp = icmp slt i64 %b, 0
+  ret i1 %cmp
+}
+
+define i1 @i32_cast_cmp_sgt_int_0_sitofp_double(i32 %i) {
+; CHECK-LABEL: @i32_cast_cmp_sgt_int_0_sitofp_double(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt i32 [[I:%.*]], 0
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %f = sitofp i32 %i to double
+  %b = bitcast double %f to i64
+  %cmp = icmp sgt i64 %b, 0
+  ret i1 %cmp
+}
+
+define i1 @i32_cast_cmp_slt_int_1_sitofp_double(i32 %i) {
+; CHECK-LABEL: @i32_cast_cmp_slt_int_1_sitofp_double(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i32 [[I:%.*]], 1
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %f = sitofp i32 %i to double
+  %b = bitcast double %f to i64
+  %cmp = icmp slt i64 %b, 1
+  ret i1 %cmp
+}
+
+define i1 @i32_cast_cmp_sgt_int_m1_sitofp_double(i32 %i) {
+; CHECK-LABEL: @i32_cast_cmp_sgt_int_m1_sitofp_double(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt i32 [[I:%.*]], -1
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %f = sitofp i32 %i to double
+  %b = bitcast double %f to i64
+  %cmp = icmp sgt i64 %b, -1
+  ret i1 %cmp
+}
+
+define i1 @i32_cast_cmp_eq_int_0_sitofp_half(i32 %i) {
+; CHECK-LABEL: @i32_cast_cmp_eq_int_0_sitofp_half(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[I:%.*]], 0
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %f = sitofp i32 %i to half
+  %b = bitcast half %f to i16
+  %cmp = icmp eq i16 %b, 0
+  ret i1 %cmp
+}
+
+define i1 @i32_cast_cmp_ne_int_0_sitofp_half(i32 %i) {
+; CHECK-LABEL: @i32_cast_cmp_ne_int_0_sitofp_half(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ne i32 [[I:%.*]], 0
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %f = sitofp i32 %i to half
+  %b = bitcast half %f to i16
+  %cmp = icmp ne i16 %b, 0
+  ret i1 %cmp
+}
+
+define i1 @i32_cast_cmp_slt_int_0_sitofp_half(i32 %i) {
+; CHECK-LABEL: @i32_cast_cmp_slt_int_0_sitofp_half(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i32 [[I:%.*]], 0
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %f = sitofp i32 %i to half
+  %b = bitcast half %f to i16
+  %cmp = icmp slt i16 %b, 0
+  ret i1 %cmp
+}
+
+define i1 @i32_cast_cmp_sgt_int_0_sitofp_half(i32 %i) {
+; CHECK-LABEL: @i32_cast_cmp_sgt_int_0_sitofp_half(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt i32 [[I:%.*]], 0
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %f = sitofp i32 %i to half
+  %b = bitcast half %f to i16
+  %cmp = icmp sgt i16 %b, 0
+  ret i1 %cmp
+}
+
+define i1 @i32_cast_cmp_slt_int_1_sitofp_half(i32 %i) {
+; CHECK-LABEL: @i32_cast_cmp_slt_int_1_sitofp_half(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i32 [[I:%.*]], 1
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %f = sitofp i32 %i to half
+  %b = bitcast half %f to i16
+  %cmp = icmp slt i16 %b, 1
+  ret i1 %cmp
+}
+
+define i1 @i32_cast_cmp_sgt_int_m1_sitofp_half(i32 %i) {
+; CHECK-LABEL: @i32_cast_cmp_sgt_int_m1_sitofp_half(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt i32 [[I:%.*]], -1
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %f = sitofp i32 %i to half
+  %b = bitcast half %f to i16
+  %cmp = icmp sgt i16 %b, -1
+  ret i1 %cmp
+}
+
+define i1 @i64_cast_cmp_eq_int_0_sitofp_float(i64 %i) {
+; CHECK-LABEL: @i64_cast_cmp_eq_int_0_sitofp_float(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i64 [[I:%.*]], 0
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %f = sitofp i64 %i to float
+  %b = bitcast float %f to i32
+  %cmp = icmp eq i32 %b, 0
+  ret i1 %cmp
+}
+
+define i1 @i64_cast_cmp_ne_int_0_sitofp_float(i64 %i) {
+; CHECK-LABEL: @i64_cast_cmp_ne_int_0_sitofp_float(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ne i64 [[I:%.*]], 0
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %f = sitofp i64 %i to float
+  %b = bitcast float %f to i32
+  %cmp = icmp ne i32 %b, 0
+  ret i1 %cmp
+}
+
+define i1 @i64_cast_cmp_slt_int_0_sitofp_float(i64 %i) {
+; CHECK-LABEL: @i64_cast_cmp_slt_int_0_sitofp_float(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i64 [[I:%.*]], 0
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %f = sitofp i64 %i to float
+  %b = bitcast float %f to i32
+  %cmp = icmp slt i32 %b, 0
+  ret i1 %cmp
+}
+
+define i1 @i64_cast_cmp_sgt_int_0_sitofp_float(i64 %i) {
+; CHECK-LABEL: @i64_cast_cmp_sgt_int_0_sitofp_float(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt i64 [[I:%.*]], 0
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %f = sitofp i64 %i to float
+  %b = bitcast float %f to i32
+  %cmp = icmp sgt i32 %b, 0
+  ret i1 %cmp
+}
+
+define i1 @i64_cast_cmp_slt_int_1_sitofp_float(i64 %i) {
+; CHECK-LABEL: @i64_cast_cmp_slt_int_1_sitofp_float(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i64 [[I:%.*]], 1
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %f = sitofp i64 %i to float
+  %b = bitcast float %f to i32
+  %cmp = icmp slt i32 %b, 1
+  ret i1 %cmp
+}
+
+define i1 @i64_cast_cmp_sgt_int_m1_sitofp_float(i64 %i) {
+; CHECK-LABEL: @i64_cast_cmp_sgt_int_m1_sitofp_float(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt i64 [[I:%.*]], -1
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %f = sitofp i64 %i to float
+  %b = bitcast float %f to i32
+  %cmp = icmp sgt i32 %b, -1
+  ret i1 %cmp
+}
+
+define i1 @i64_cast_cmp_eq_int_0_sitofp_double(i64 %i) {
+; CHECK-LABEL: @i64_cast_cmp_eq_int_0_sitofp_double(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i64 [[I:%.*]], 0
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %f = sitofp i64 %i to double
+  %b = bitcast double %f to i64
+  %cmp = icmp eq i64 %b, 0
+  ret i1 %cmp
+}
+
+define i1 @i64_cast_cmp_ne_int_0_sitofp_double(i64 %i) {
+; CHECK-LABEL: @i64_cast_cmp_ne_int_0_sitofp_double(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ne i64 [[I:%.*]], 0
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %f = sitofp i64 %i to double
+  %b = bitcast double %f to i64
+  %cmp = icmp ne i64 %b, 0
+  ret i1 %cmp
+}
+
+define i1 @i64_cast_cmp_slt_int_0_sitofp_double(i64 %i) {
+; CHECK-LABEL: @i64_cast_cmp_slt_int_0_sitofp_double(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i64 [[I:%.*]], 0
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %f = sitofp i64 %i to double
+  %b = bitcast double %f to i64
+  %cmp = icmp slt i64 %b, 0
+  ret i1 %cmp
+}
+
+define i1 @i64_cast_cmp_sgt_int_0_sitofp_double(i64 %i) {
+; CHECK-LABEL: @i64_cast_cmp_sgt_int_0_sitofp_double(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt i64 [[I:%.*]], 0
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %f = sitofp i64 %i to double
+  %b = bitcast double %f to i64
+  %cmp = icmp sgt i64 %b, 0
+  ret i1 %cmp
+}
+
+define i1 @i64_cast_cmp_slt_int_1_sitofp_double(i64 %i) {
+; CHECK-LABEL: @i64_cast_cmp_slt_int_1_sitofp_double(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i64 [[I:%.*]], 1
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %f = sitofp i64 %i to double
+  %b = bitcast double %f to i64
+  %cmp = icmp slt i64 %b, 1
+  ret i1 %cmp
+}
+
+define i1 @i64_cast_cmp_sgt_int_m1_sitofp_double(i64 %i) {
+; CHECK-LABEL: @i64_cast_cmp_sgt_int_m1_sitofp_double(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt i64 [[I:%.*]], -1
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %f = sitofp i64 %i to double
+  %b = bitcast double %f to i64
+  %cmp = icmp sgt i64 %b, -1
+  ret i1 %cmp
+}
+
+define i1 @i64_cast_cmp_eq_int_0_sitofp_half(i64 %i) {
+; CHECK-LABEL: @i64_cast_cmp_eq_int_0_sitofp_half(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i64 [[I:%.*]], 0
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %f = sitofp i64 %i to half
+  %b = bitcast half %f to i16
+  %cmp = icmp eq i16 %b, 0
+  ret i1 %cmp
+}
+
+define i1 @i64_cast_cmp_ne_int_0_sitofp_half(i64 %i) {
+; CHECK-LABEL: @i64_cast_cmp_ne_int_0_sitofp_half(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ne i64 [[I:%.*]], 0
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %f = sitofp i64 %i to half
+  %b = bitcast half %f to i16
+  %cmp = icmp ne i16 %b, 0
+  ret i1 %cmp
+}
+
+define i1 @i64_cast_cmp_slt_int_0_sitofp_half(i64 %i) {
+; CHECK-LABEL: @i64_cast_cmp_slt_int_0_sitofp_half(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i64 [[I:%.*]], 0
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %f = sitofp i64 %i to half
+  %b = bitcast half %f to i16
+  %cmp = icmp slt i16 %b, 0
+  ret i1 %cmp
+}
+
+define i1 @i64_cast_cmp_sgt_int_0_sitofp_half(i64 %i) {
+; CHECK-LABEL: @i64_cast_cmp_sgt_int_0_sitofp_half(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt i64 [[I:%.*]], 0
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %f = sitofp i64 %i to half
+  %b = bitcast half %f to i16
+  %cmp = icmp sgt i16 %b, 0
+  ret i1 %cmp
+}
+
+define i1 @i64_cast_cmp_slt_int_1_sitofp_half(i64 %i) {
+; CHECK-LABEL: @i64_cast_cmp_slt_int_1_sitofp_half(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i64 [[I:%.*]], 1
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %f = sitofp i64 %i to half
+  %b = bitcast half %f to i16
+  %cmp = icmp slt i16 %b, 1
+  ret i1 %cmp
+}
+
+define i1 @i64_cast_cmp_sgt_int_m1_sitofp_half(i64 %i) {
+; CHECK-LABEL: @i64_cast_cmp_sgt_int_m1_sitofp_half(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt i64 [[I:%.*]], -1
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %f = sitofp i64 %i to half
+  %b = bitcast half %f to i16
+  %cmp = icmp sgt i16 %b, -1
+  ret i1 %cmp
+}
+
+define i1 @i16_cast_cmp_eq_int_0_sitofp_float(i16 %i) {
+; CHECK-LABEL: @i16_cast_cmp_eq_int_0_sitofp_float(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i16 [[I:%.*]], 0
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %f = sitofp i16 %i to float
+  %b = bitcast float %f to i32
+  %cmp = icmp eq i32 %b, 0
+  ret i1 %cmp
+}
+
+define i1 @i16_cast_cmp_ne_int_0_sitofp_float(i16 %i) {
+; CHECK-LABEL: @i16_cast_cmp_ne_int_0_sitofp_float(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ne i16 [[I:%.*]], 0
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %f = sitofp i16 %i to float
+  %b = bitcast float %f to i32
+  %cmp = icmp ne i32 %b, 0
+  ret i1 %cmp
+}
+
+define i1 @i16_cast_cmp_slt_int_0_sitofp_float(i16 %i) {
+; CHECK-LABEL: @i16_cast_cmp_slt_int_0_sitofp_float(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i16 [[I:%.*]], 0
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %f = sitofp i16 %i to float
+  %b = bitcast float %f to i32
+  %cmp = icmp slt i32 %b, 0
+  ret i1 %cmp
+}
+
+define i1 @i16_cast_cmp_sgt_int_0_sitofp_float(i16 %i) {
+; CHECK-LABEL: @i16_cast_cmp_sgt_int_0_sitofp_float(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt i16 [[I:%.*]], 0
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %f = sitofp i16 %i to float
+  %b = bitcast float %f to i32
+  %cmp = icmp sgt i32 %b, 0
+  ret i1 %cmp
+}
+
+define i1 @i16_cast_cmp_slt_int_1_sitofp_float(i16 %i) {
+; CHECK-LABEL: @i16_cast_cmp_slt_int_1_sitofp_float(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i16 [[I:%.*]], 1
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %f = sitofp i16 %i to float
+  %b = bitcast float %f to i32
+  %cmp = icmp slt i32 %b, 1
+  ret i1 %cmp
+}
+
+define i1 @i16_cast_cmp_sgt_int_m1_sitofp_float(i16 %i) {
+; CHECK-LABEL: @i16_cast_cmp_sgt_int_m1_sitofp_float(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt i16 [[I:%.*]], -1
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %f = sitofp i16 %i to float
+  %b = bitcast float %f to i32
+  %cmp = icmp sgt i32 %b, -1
+  ret i1 %cmp
+}
+
+define i1 @i16_cast_cmp_eq_int_0_sitofp_double(i16 %i) {
+; CHECK-LABEL: @i16_cast_cmp_eq_int_0_sitofp_double(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i16 [[I:%.*]], 0
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %f = sitofp i16 %i to double
+  %b = bitcast double %f to i64
+  %cmp = icmp eq i64 %b, 0
+  ret i1 %cmp
+}
+
+define i1 @i16_cast_cmp_ne_int_0_sitofp_double(i16 %i) {
+; CHECK-LABEL: @i16_cast_cmp_ne_int_0_sitofp_double(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ne i16 [[I:%.*]], 0
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %f = sitofp i16 %i to double
+  %b = bitcast double %f to i64
+  %cmp = icmp ne i64 %b, 0
+  ret i1 %cmp
+}
+
+define i1 @i16_cast_cmp_slt_int_0_sitofp_double(i16 %i) {
+; CHECK-LABEL: @i16_cast_cmp_slt_int_0_sitofp_double(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i16 [[I:%.*]], 0
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %f = sitofp i16 %i to double
+  %b = bitcast double %f to i64
+  %cmp = icmp slt i64 %b, 0
+  ret i1 %cmp
+}
+
+define i1 @i16_cast_cmp_sgt_int_0_sitofp_double(i16 %i) {
+; CHECK-LABEL: @i16_cast_cmp_sgt_int_0_sitofp_double(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt i16 [[I:%.*]], 0
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %f = sitofp i16 %i to double
+  %b = bitcast double %f to i64
+  %cmp = icmp sgt i64 %b, 0
+  ret i1 %cmp
+}
+
+define i1 @i16_cast_cmp_slt_int_1_sitofp_double(i16 %i) {
+; CHECK-LABEL: @i16_cast_cmp_slt_int_1_sitofp_double(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i16 [[I:%.*]], 1
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %f = sitofp i16 %i to double
+  %b = bitcast double %f to i64
+  %cmp = icmp slt i64 %b, 1
+  ret i1 %cmp
+}
+
+define i1 @i16_cast_cmp_sgt_int_m1_sitofp_double(i16 %i) {
+; CHECK-LABEL: @i16_cast_cmp_sgt_int_m1_sitofp_double(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt i16 [[I:%.*]], -1
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %f = sitofp i16 %i to double
+  %b = bitcast double %f to i64
+  %cmp = icmp sgt i64 %b, -1
+  ret i1 %cmp
+}
+
+define i1 @i16_cast_cmp_eq_int_0_sitofp_half(i16 %i) {
+; CHECK-LABEL: @i16_cast_cmp_eq_int_0_sitofp_half(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i16 [[I:%.*]], 0
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %f = sitofp i16 %i to half
+  %b = bitcast half %f to i16
+  %cmp = icmp eq i16 %b, 0
+  ret i1 %cmp
+}
+
+define i1 @i16_cast_cmp_ne_int_0_sitofp_half(i16 %i) {
+; CHECK-LABEL: @i16_cast_cmp_ne_int_0_sitofp_half(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ne i16 [[I:%.*]], 0
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %f = sitofp i16 %i to half
+  %b = bitcast half %f to i16
+  %cmp = icmp ne i16 %b, 0
+  ret i1 %cmp
+}
+
+define i1 @i16_cast_cmp_slt_int_0_sitofp_half(i16 %i) {
+; CHECK-LABEL: @i16_cast_cmp_slt_int_0_sitofp_half(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i16 [[I:%.*]], 0
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %f = sitofp i16 %i to half
+  %b = bitcast half %f to i16
+  %cmp = icmp slt i16 %b, 0
+  ret i1 %cmp
+}
+
+define i1 @i16_cast_cmp_sgt_int_0_sitofp_half(i16 %i) {
+; CHECK-LABEL: @i16_cast_cmp_sgt_int_0_sitofp_half(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt i16 [[I:%.*]], 0
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %f = sitofp i16 %i to half
+  %b = bitcast half %f to i16
+  %cmp = icmp sgt i16 %b, 0
+  ret i1 %cmp
+}
+
+define i1 @i16_cast_cmp_slt_int_1_sitofp_half(i16 %i) {
+; CHECK-LABEL: @i16_cast_cmp_slt_int_1_sitofp_half(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i16 [[I:%.*]], 1
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %f = sitofp i16 %i to half
+  %b = bitcast half %f to i16
+  %cmp = icmp slt i16 %b, 1
+  ret i1 %cmp
+}
+
+define i1 @i16_cast_cmp_sgt_int_m1_sitofp_half(i16 %i) {
+; CHECK-LABEL: @i16_cast_cmp_sgt_int_m1_sitofp_half(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt i16 [[I:%.*]], -1
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %f = sitofp i16 %i to half
+  %b = bitcast half %f to i16
+  %cmp = icmp sgt i16 %b, -1
+  ret i1 %cmp
+}
+
+; Verify that vector types and vector constants including undef elements are transformed too.
+
+define <3 x i1> @i32_cast_cmp_ne_int_0_sitofp_double_vec(<3 x i32> %i) {
+; CHECK-LABEL: @i32_cast_cmp_ne_int_0_sitofp_double_vec(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ne <3 x i32> [[I:%.*]], zeroinitializer
+; CHECK-NEXT:    ret <3 x i1> [[CMP]]
+;
+  %f = sitofp <3 x i32> %i to  <3 x double>
+  %b = bitcast <3 x double> %f to <3 x i64>
+  %cmp = icmp ne <3 x i64> %b, <i64 0, i64 0, i64 0>
+  ret <3 x i1> %cmp
+}
+
+; TODO: Can we propagate the constant vector with undef element?
+
+define <3 x i1> @i32_cast_cmp_eq_int_0_sitofp_float_vec_undef(<3 x i32> %i) {
+; CHECK-LABEL: @i32_cast_cmp_eq_int_0_sitofp_float_vec_undef(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq <3 x i32> [[I:%.*]], zeroinitializer
+; CHECK-NEXT:    ret <3 x i1> [[CMP]]
+;
+  %f = sitofp <3 x i32> %i to  <3 x float>
+  %b = bitcast <3 x float> %f to <3 x i32>
+  %cmp = icmp eq <3 x i32> %b, <i32 0, i32 undef, i32 0>
+  ret <3 x i1> %cmp
+}
+
+define <3 x i1> @i64_cast_cmp_slt_int_1_sitofp_half_vec_undef(<3 x i64> %i) {
+; CHECK-LABEL: @i64_cast_cmp_slt_int_1_sitofp_half_vec_undef(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp slt <3 x i64> [[I:%.*]], <i64 1, i64 1, i64 1>
+; CHECK-NEXT:    ret <3 x i1> [[CMP]]
+;
+  %f = sitofp <3 x i64> %i to  <3 x half>
+  %b = bitcast <3 x half> %f to <3 x i16>
+  %cmp = icmp slt <3 x i16> %b, <i16 1, i16 undef, i16 1>
+  ret <3 x i1> %cmp
+}
+
+define <3 x i1> @i16_cast_cmp_sgt_int_m1_sitofp_float_vec_undef(<3 x i16> %i) {
+; CHECK-LABEL: @i16_cast_cmp_sgt_int_m1_sitofp_float_vec_undef(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt <3 x i16> [[I:%.*]], <i16 -1, i16 -1, i16 -1>
+; CHECK-NEXT:    ret <3 x i1> [[CMP]]
+;
+  %f = sitofp <3 x i16> %i to  <3 x float>
+  %b = bitcast <3 x float> %f to <3 x i32>
+  %cmp = icmp sgt <3 x i32> %b, <i32 -1, i32 undef, i32 -1>
+  ret <3 x i1> %cmp
+}
+
+; Verify that the various forms of this transform are not applied when the
+; bitcast changes the number of vector elements:
+;   icmp (bitcast ([su]itofp X)), Y -> icmp X, Y
+
+define <6 x i1> @i16_cast_cmp_sgt_int_m1_bitcast_vector_num_elements_sitofp(<3 x i16> %i) {
+; CHECK-LABEL: @i16_cast_cmp_sgt_int_m1_bitcast_vector_num_elements_sitofp(
+; CHECK-NEXT:    [[F:%.*]] = sitofp <3 x i16> [[I:%.*]] to <3 x float>
+; CHECK-NEXT:    [[B:%.*]] = bitcast <3 x float> [[F]] to <6 x i16>
+; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt <6 x i16> [[B]], <i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1>
+; CHECK-NEXT:    ret <6 x i1> [[CMP]]
+;
+  %f = sitofp <3 x i16> %i to  <3 x float>
+  %b = bitcast <3 x float> %f to <6 x i16>
+  %cmp = icmp sgt <6 x i16> %b, <i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1>
+  ret <6 x i1> %cmp
+}
+
+define i1 @i16_cast_cmp_sgt_int_m1_bitcast_vector_to_scalar_sitofp(<3 x i16> %i) {
+; CHECK-LABEL: @i16_cast_cmp_sgt_int_m1_bitcast_vector_to_scalar_sitofp(
+; CHECK-NEXT:    [[F:%.*]] = sitofp <3 x i16> [[I:%.*]] to <3 x float>
+; CHECK-NEXT:    [[B:%.*]] = bitcast <3 x float> [[F]] to i96
+; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt i96 [[B]], -1
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %f = sitofp <3 x i16> %i to  <3 x float>
+  %b = bitcast <3 x float> %f to i96
+  %cmp = icmp sgt i96 %b, -1
+  ret i1 %cmp
+}
+
+
+define <6 x i1> @i16_cast_cmp_eq_int_0_bitcast_vector_num_elements_uitofp(<3 x i16> %i) {
+; CHECK-LABEL: @i16_cast_cmp_eq_int_0_bitcast_vector_num_elements_uitofp(
+; CHECK-NEXT:    [[F:%.*]] = uitofp <3 x i16> [[I:%.*]] to <3 x float>
+; CHECK-NEXT:    [[B:%.*]] = bitcast <3 x float> [[F]] to <6 x i16>
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq <6 x i16> [[B]], zeroinitializer
+; CHECK-NEXT:    ret <6 x i1> [[CMP]]
+;
+  %f = uitofp <3 x i16> %i to <3 x float>
+  %b = bitcast <3 x float> %f to <6 x i16>
+  %cmp = icmp eq <6 x i16> %b, <i16 0, i16 0, i16 0, i16 0, i16 0, i16 0>
+  ret <6 x i1> %cmp
+}
+
+define i1 @i16_cast_cmp_eq_int_0_bitcast_vector_to_scalar_uitofp(<3 x i16> %i) {
+; CHECK-LABEL: @i16_cast_cmp_eq_int_0_bitcast_vector_to_scalar_uitofp(
+; CHECK-NEXT:    [[F:%.*]] = uitofp <3 x i16> [[I:%.*]] to <3 x float>
+; CHECK-NEXT:    [[B:%.*]] = bitcast <3 x float> [[F]] to i96
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i96 [[B]], 0
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %f = uitofp <3 x i16> %i to <3 x float>
+  %b = bitcast <3 x float> %f to i96
+  %cmp = icmp eq i96 %b, 0
+  ret i1 %cmp
+}

Added: llvm/trunk/test/Transforms/InstCombine/cast-mul-select.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/cast-mul-select.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/cast-mul-select.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/cast-mul-select.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,181 @@
+; RUN: opt < %s -instcombine -S | FileCheck %s
+; RUN: opt -debugify -instcombine -S < %s | FileCheck %s -check-prefix DBGINFO
+
+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"
+
+define i32 @mul(i32 %x, i32 %y) {
+; CHECK-LABEL: @mul(
+; CHECK-NEXT:    [[C:%.*]] = mul i32 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    [[D:%.*]] = and i32 [[C]], 255
+; CHECK-NEXT:    ret i32 [[D]]
+
+; Test that when zext is evaluated in different type
+; we preserve the debug information in the resulting
+; instruction.
+; DBGINFO-LABEL: @mul(
+; DBGINFO-NEXT:    [[C:%.*]] = mul i32 {{.*}}
+; DBGINFO-NEXT:    [[D:%.*]] = and i32 {{.*}}
+; DBGINFO-NEXT:    call void @llvm.dbg.value(metadata i32 [[C]]
+; DBGINFO-NEXT:    call void @llvm.dbg.value(metadata i32 [[D]]
+
+  %A = trunc i32 %x to i8
+  %B = trunc i32 %y to i8
+  %C = mul i8 %A, %B
+  %D = zext i8 %C to i32
+  ret i32 %D
+}
+
+define i32 @select1(i1 %cond, i32 %x, i32 %y, i32 %z) {
+; CHECK-LABEL: @select1(
+; CHECK-NEXT:    [[D:%.*]] = add i32 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    [[E:%.*]] = select i1 [[COND:%.*]], i32 [[Z:%.*]], i32 [[D]]
+; CHECK-NEXT:    [[F:%.*]] = and i32 [[E]], 255
+; CHECK-NEXT:    ret i32 [[F]]
+;
+  %A = trunc i32 %x to i8
+  %B = trunc i32 %y to i8
+  %C = trunc i32 %z to i8
+  %D = add i8 %A, %B
+  %E = select i1 %cond, i8 %C, i8 %D
+  %F = zext i8 %E to i32
+  ret i32 %F
+}
+
+define i8 @select2(i1 %cond, i8 %x, i8 %y, i8 %z) {
+; CHECK-LABEL: @select2(
+; CHECK-NEXT:    [[D:%.*]] = add i8 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    [[E:%.*]] = select i1 [[COND:%.*]], i8 [[Z:%.*]], i8 [[D]]
+; CHECK-NEXT:    ret i8 [[E]]
+;
+  %A = zext i8 %x to i32
+  %B = zext i8 %y to i32
+  %C = zext i8 %z to i32
+  %D = add i32 %A, %B
+  %E = select i1 %cond, i32 %C, i32 %D
+  %F = trunc i32 %E to i8
+  ret i8 %F
+}
+
+; The next 3 tests could be handled in instcombine, but evaluating values
+; with multiple uses may be very slow. Let some other pass deal with it.
+
+define i32 @eval_trunc_multi_use_in_one_inst(i32 %x) {
+; CHECK-LABEL: @eval_trunc_multi_use_in_one_inst(
+; CHECK-NEXT:    [[Z:%.*]] = zext i32 [[X:%.*]] to i64
+; CHECK-NEXT:    [[A:%.*]] = add nuw nsw i64 [[Z]], 15
+; CHECK-NEXT:    [[M:%.*]] = mul i64 [[A]], [[A]]
+; CHECK-NEXT:    [[T:%.*]] = trunc i64 [[M]] to i32
+; CHECK-NEXT:    ret i32 [[T]]
+;
+  %z = zext i32 %x to i64
+  %a = add nsw nuw i64 %z, 15
+  %m = mul i64 %a, %a
+  %t = trunc i64 %m to i32
+  ret i32 %t
+}
+
+define i32 @eval_zext_multi_use_in_one_inst(i32 %x) {
+; CHECK-LABEL: @eval_zext_multi_use_in_one_inst(
+; CHECK-NEXT:    [[T:%.*]] = trunc i32 [[X:%.*]] to i16
+; CHECK-NEXT:    [[A:%.*]] = and i16 [[T]], 5
+; CHECK-NEXT:    [[M:%.*]] = mul nuw nsw i16 [[A]], [[A]]
+; CHECK-NEXT:    [[R:%.*]] = zext i16 [[M]] to i32
+; CHECK-NEXT:    ret i32 [[R]]
+;
+  %t = trunc i32 %x to i16
+  %a = and i16 %t, 5
+  %m = mul nuw nsw i16 %a, %a
+  %r = zext i16 %m to i32
+  ret i32 %r
+}
+
+define i32 @eval_sext_multi_use_in_one_inst(i32 %x) {
+; CHECK-LABEL: @eval_sext_multi_use_in_one_inst(
+; CHECK-NEXT:    [[T:%.*]] = trunc i32 [[X:%.*]] to i16
+; CHECK-NEXT:    [[A:%.*]] = and i16 [[T]], 14
+; CHECK-NEXT:    [[M:%.*]] = mul nuw nsw i16 [[A]], [[A]]
+; CHECK-NEXT:    [[O:%.*]] = or i16 [[M]], -32768
+; CHECK-NEXT:    [[R:%.*]] = sext i16 [[O]] to i32
+; CHECK-NEXT:    ret i32 [[R]]
+;
+  %t = trunc i32 %x to i16
+  %a = and i16 %t, 14
+  %m = mul nuw nsw i16 %a, %a
+  %o = or i16 %m, 32768
+  %r = sext i16 %o to i32
+  ret i32 %r
+}
+
+; If we have a transform to shrink the above 3 cases, make sure it's not
+; also trying to look through multiple uses in this test and crashing.
+
+define void @PR36225(i32 %a, i32 %b) {
+; CHECK-LABEL: @PR36225(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    br label [[WHILE_BODY:%.*]]
+; CHECK:       while.body:
+; CHECK-NEXT:    br i1 undef, label [[FOR_BODY3_US:%.*]], label [[FOR_BODY3:%.*]]
+; CHECK:       for.body3.us:
+; CHECK-NEXT:    [[TOBOOL:%.*]] = icmp eq i32 [[B:%.*]], 0
+; CHECK-NEXT:    [[SPEC_SELECT:%.*]] = select i1 [[TOBOOL]], i8 0, i8 4
+; CHECK-NEXT:    switch i3 undef, label [[EXIT:%.*]] [
+; CHECK-NEXT:    i3 0, label [[FOR_END:%.*]]
+; CHECK-NEXT:    i3 -1, label [[FOR_END]]
+; CHECK-NEXT:    ]
+; CHECK:       for.body3:
+; CHECK-NEXT:    switch i3 undef, label [[EXIT]] [
+; CHECK-NEXT:    i3 0, label [[FOR_END]]
+; CHECK-NEXT:    i3 -1, label [[FOR_END]]
+; CHECK-NEXT:    ]
+; CHECK:       for.end:
+; CHECK-NEXT:    [[H:%.*]] = phi i8 [ [[SPEC_SELECT]], [[FOR_BODY3_US]] ], [ [[SPEC_SELECT]], [[FOR_BODY3_US]] ], [ 0, [[FOR_BODY3]] ], [ 0, [[FOR_BODY3]] ]
+; CHECK-NEXT:    [[TMP0:%.*]] = zext i8 [[H]] to i32
+; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i32 [[TMP0]], [[A:%.*]]
+; CHECK-NEXT:    br i1 [[CMP]], label [[EXIT]], label [[EXIT2:%.*]]
+; CHECK:       exit2:
+; CHECK-NEXT:    unreachable
+; CHECK:       exit:
+; CHECK-NEXT:    unreachable
+;
+entry:
+  br label %while.body
+
+while.body:
+  %tobool = icmp eq i32 %b, 0
+  br i1 undef, label %for.body3.us, label %for.body3
+
+for.body3.us:
+  %spec.select = select i1 %tobool, i8 0, i8 4
+  switch i3 undef, label %exit [
+  i3 0, label %for.end
+  i3 -1, label %for.end
+  ]
+
+for.body3:
+  switch i3 undef, label %exit [
+  i3 0, label %for.end
+  i3 -1, label %for.end
+  ]
+
+for.end:
+  %h = phi i8 [ %spec.select, %for.body3.us ], [ %spec.select, %for.body3.us ], [ 0, %for.body3 ], [ 0, %for.body3 ]
+  %conv = sext i8 %h to i32
+  %cmp = icmp sgt i32 %a, %conv
+  br i1 %cmp, label %exit, label %exit2
+
+exit2:
+  unreachable
+
+exit:
+  unreachable
+}
+
+; Check that we don't drop debug info when a zext is removed.
+define i1 @foo(i1 zeroext %b) {
+; DBGINFO-LABEL: @foo(
+; DBGINFO-NEXT:  call void @llvm.dbg.value(metadata i1 %b
+; DBGINFO-NEXT:  ret i1 %b
+
+  %frombool = zext i1 %b to i8 
+  ret i1 %b
+}

Added: llvm/trunk/test/Transforms/InstCombine/cast-select.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/cast-select.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/cast-select.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/cast-select.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,133 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt < %s -instcombine -S | FileCheck %s
+
+define i64 @zext(i32 %x, i32 %y, i32 %z) {
+; CHECK-LABEL: @zext(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[CMP]], i32 0, i32 [[Z:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = zext i32 [[SEL]] to i64
+; CHECK-NEXT:    ret i64 [[R]]
+;
+  %cmp = icmp eq i32 %x, %y
+  %sel = select i1 %cmp, i32 0, i32 %z
+  %r = zext i32 %sel to i64
+  ret i64 %r
+}
+
+define <2 x i32> @zext_vec(<2 x i8> %x, <2 x i8> %y, <2 x i8> %z) {
+; CHECK-LABEL: @zext_vec(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ugt <2 x i8> [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    [[SEL:%.*]] = select <2 x i1> [[CMP]], <2 x i8> [[Z:%.*]], <2 x i8> <i8 42, i8 7>
+; CHECK-NEXT:    [[R:%.*]] = zext <2 x i8> [[SEL]] to <2 x i32>
+; CHECK-NEXT:    ret <2 x i32> [[R]]
+;
+  %cmp = icmp ugt <2 x i8> %x, %y
+  %sel = select <2 x i1> %cmp, <2 x i8> %z, <2 x i8> <i8 42, i8 7>
+  %r = zext <2 x i8> %sel to <2 x i32>
+  ret <2 x i32> %r
+}
+
+define i64 @sext(i8 %x, i8 %y, i8 %z) {
+; CHECK-LABEL: @sext(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i8 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[CMP]], i8 42, i8 [[Z:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = sext i8 [[SEL]] to i64
+; CHECK-NEXT:    ret i64 [[R]]
+;
+  %cmp = icmp ult i8 %x, %y
+  %sel = select i1 %cmp, i8 42, i8 %z
+  %r = sext i8 %sel to i64
+  ret i64 %r
+}
+
+define <2 x i32> @sext_vec(<2 x i8> %x, <2 x i8> %y, <2 x i8> %z) {
+; CHECK-LABEL: @sext_vec(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ugt <2 x i8> [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    [[SEL:%.*]] = select <2 x i1> [[CMP]], <2 x i8> [[Z:%.*]], <2 x i8> <i8 42, i8 7>
+; CHECK-NEXT:    [[R:%.*]] = sext <2 x i8> [[SEL]] to <2 x i32>
+; CHECK-NEXT:    ret <2 x i32> [[R]]
+;
+  %cmp = icmp ugt <2 x i8> %x, %y
+  %sel = select <2 x i1> %cmp, <2 x i8> %z, <2 x i8> <i8 42, i8 7>
+  %r = sext <2 x i8> %sel to <2 x i32>
+  ret <2 x i32> %r
+}
+
+define i16 @trunc(i32 %x, i32 %y, i32 %z) {
+; CHECK-LABEL: @trunc(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i32 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[CMP]], i32 42, i32 [[Z:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = trunc i32 [[SEL]] to i16
+; CHECK-NEXT:    ret i16 [[R]]
+;
+  %cmp = icmp ult i32 %x, %y
+  %sel = select i1 %cmp, i32 42, i32 %z
+  %r = trunc i32 %sel to i16
+  ret i16 %r
+}
+
+define <2 x i32> @trunc_vec(<2 x i64> %x, <2 x i64> %y, <2 x i64> %z) {
+; CHECK-LABEL: @trunc_vec(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ugt <2 x i64> [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    [[SEL:%.*]] = select <2 x i1> [[CMP]], <2 x i64> [[Z:%.*]], <2 x i64> <i64 42, i64 7>
+; CHECK-NEXT:    [[R:%.*]] = trunc <2 x i64> [[SEL]] to <2 x i32>
+; CHECK-NEXT:    ret <2 x i32> [[R]]
+;
+  %cmp = icmp ugt <2 x i64> %x, %y
+  %sel = select <2 x i1> %cmp, <2 x i64> %z, <2 x i64> <i64 42, i64 7>
+  %r = trunc <2 x i64> %sel to <2 x i32>
+  ret <2 x i32> %r
+}
+
+define double @fpext(float %x, float %y, float %z) {
+; CHECK-LABEL: @fpext(
+; CHECK-NEXT:    [[CMP:%.*]] = fcmp oeq float [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[CMP]], float 1.700000e+01, float [[Z:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = fpext float [[SEL]] to double
+; CHECK-NEXT:    ret double [[R]]
+;
+  %cmp = fcmp oeq float %x, %y
+  %sel = select i1 %cmp, float 17.0, float %z
+  %r = fpext float %sel to double
+  ret double %r
+}
+
+define <2 x double> @fpext_vec(<2 x float> %x, <2 x float> %y, <2 x float> %z) {
+; CHECK-LABEL: @fpext_vec(
+; CHECK-NEXT:    [[CMP:%.*]] = fcmp ugt <2 x float> [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    [[SEL:%.*]] = select <2 x i1> [[CMP]], <2 x float> [[Z:%.*]], <2 x float> <float 4.200000e+01, float -2.000000e+00>
+; CHECK-NEXT:    [[R:%.*]] = fpext <2 x float> [[SEL]] to <2 x double>
+; CHECK-NEXT:    ret <2 x double> [[R]]
+;
+  %cmp = fcmp ugt <2 x float> %x, %y
+  %sel = select <2 x i1> %cmp, <2 x float> %z, <2 x float> <float 42.0, float -2.0>
+  %r = fpext <2 x float> %sel to <2 x double>
+  ret <2 x double> %r
+}
+
+define float @fptrunc(double %x, double %y, double %z) {
+; CHECK-LABEL: @fptrunc(
+; CHECK-NEXT:    [[CMP:%.*]] = fcmp ult double [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[CMP]], double 4.200000e+01, double [[Z:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = fptrunc double [[SEL]] to float
+; CHECK-NEXT:    ret float [[R]]
+;
+  %cmp = fcmp ult double %x, %y
+  %sel = select i1 %cmp, double 42.0, double %z
+  %r = fptrunc double %sel to float
+  ret float %r
+}
+
+define <2 x float> @fptrunc_vec(<2 x double> %x, <2 x double> %y, <2 x double> %z) {
+; CHECK-LABEL: @fptrunc_vec(
+; CHECK-NEXT:    [[CMP:%.*]] = fcmp oge <2 x double> [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    [[SEL:%.*]] = select <2 x i1> [[CMP]], <2 x double> [[Z:%.*]], <2 x double> <double -4.200000e+01, double 1.200000e+01>
+; CHECK-NEXT:    [[R:%.*]] = fptrunc <2 x double> [[SEL]] to <2 x float>
+; CHECK-NEXT:    ret <2 x float> [[R]]
+;
+  %cmp = fcmp oge <2 x double> %x, %y
+  %sel = select <2 x i1> %cmp, <2 x double> %z, <2 x double> <double -42.0, double 12.0>
+  %r = fptrunc <2 x double> %sel to <2 x float>
+  ret <2 x float> %r
+}
+

Added: llvm/trunk/test/Transforms/InstCombine/cast-set-preserve-signed-dbg-val.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/cast-set-preserve-signed-dbg-val.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/cast-set-preserve-signed-dbg-val.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/cast-set-preserve-signed-dbg-val.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,50 @@
+; RUN: opt -instcombine -S < %s | FileCheck %s
+
+; CHECK-LABEL: define {{.*}} @test5
+define i16 @test5(i16 %A) !dbg !34 {
+  ; CHECK: [[and:%.*]] = and i16 %A, 15
+
+  %B = sext i16 %A to i32, !dbg !40
+  call void @llvm.dbg.value(metadata i32 %B, metadata !36, metadata !DIExpression()), !dbg !40
+
+  %C = and i32 %B, 15, !dbg !41
+  call void @llvm.dbg.value(metadata i32 %C, metadata !37, metadata !DIExpression()), !dbg !41
+
+  ; Preserve the dbg.value for the DCE'd 32-bit 'and'.
+  ;
+  ; The high 16 bits of the original 'and' require sign-extending the new 16-bit and:
+  ; CHECK-NEXT: call void @llvm.dbg.value(metadata i16 [[and]], metadata [[C:![0-9]+]],
+  ; CHECK-SAME:    metadata !DIExpression(DW_OP_LLVM_convert, 16, DW_ATE_signed, DW_OP_LLVM_convert, 32, DW_ATE_signed, DW_OP_stack_value)
+
+  %D = trunc i32 %C to i16, !dbg !42
+  call void @llvm.dbg.value(metadata i16 %D, metadata !38, metadata !DIExpression()), !dbg !42
+
+  ; The dbg.value for a truncate should simply point to the result of the 16-bit 'and'.
+  ; CHECK-NEXT: call void @llvm.dbg.value(metadata i16 [[and]], metadata [[D:![0-9]+]], metadata !DIExpression())
+
+  ret i16 %D, !dbg !43
+  ; CHECK-NEXT: ret i16 [[and]]
+}
+
+declare void @llvm.dbg.value(metadata, metadata, metadata)
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!5}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C, file: !1, producer: "debugify", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2)
+!1 = !DIFile(filename: "void", directory: "/")
+!2 = !{}
+!5 = !{i32 2, !"Debug Info Version", i32 3}
+!7 = !DISubroutineType(types: !2)
+!10 = !DIBasicType(name: "ty32", size: 32, encoding: DW_ATE_signed)
+!12 = !DIBasicType(name: "ty8", size: 8, encoding: DW_ATE_signed)
+!34 = distinct !DISubprogram(name: "test5", linkageName: "test5", scope: null, file: !1, line: 12, type: !7, isLocal: false, isDefinition: true, scopeLine: 12, isOptimized: true, unit: !0, retainedNodes: !35)
+!35 = !{!36, !37, !38}
+!36 = !DILocalVariable(name: "B", scope: !34, file: !1, line: 12, type: !10)
+!37 = !DILocalVariable(name: "C", scope: !34, file: !1, line: 13, type: !10)
+!38 = !DILocalVariable(name: "D", scope: !34, file: !1, line: 14, type: !39)
+!39 = !DIBasicType(name: "ty16", size: 16, encoding: DW_ATE_signed)
+!40 = !DILocation(line: 12, column: 1, scope: !34)
+!41 = !DILocation(line: 13, column: 1, scope: !34)
+!42 = !DILocation(line: 14, column: 1, scope: !34)
+!43 = !DILocation(line: 15, column: 1, scope: !34)

Added: llvm/trunk/test/Transforms/InstCombine/cast-set.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/cast-set.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/cast-set.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/cast-set.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,77 @@
+; 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-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"
+
+define i1 @test1(i32 %X) {
+; CHECK-LABEL: @test1(
+; CHECK-NEXT:    [[C:%.*]] = icmp ne i32 %X, 12
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %A = bitcast i32 %X to i32
+  ; Convert to setne int %X, 12
+  %c = icmp ne i32 %A, 12
+  ret i1 %c
+}
+
+define i1 @test2(i32 %X, i32 %Y) {
+; CHECK-LABEL: @test2(
+; CHECK-NEXT:    [[C:%.*]] = icmp ne i32 %X, %Y
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %A = bitcast i32 %X to i32
+  %B = bitcast i32 %Y to i32
+  ; Convert to setne int %X, %Y
+  %c = icmp ne i32 %A, %B
+  ret i1 %c
+}
+
+define i32 @test4(i32 %A) {
+; CHECK-LABEL: @test4(
+; CHECK-NEXT:    [[C:%.*]] = shl i32 %A, 2
+; CHECK-NEXT:    ret i32 [[C]]
+;
+  %B = bitcast i32 %A to i32
+  %C = shl i32 %B, 2
+  %D = bitcast i32 %C to i32
+  ret i32 %D
+}
+
+define i16 @test5(i16 %A) {
+; CHECK-LABEL: @test5(
+; CHECK-NEXT:    [[C:%.*]] = and i16 %A, 15
+; CHECK-NEXT:    ret i16 [[C]]
+;
+  %B = sext i16 %A to i32
+  %C = and i32 %B, 15
+  %D = trunc i32 %C to i16
+  ret i16 %D
+}
+
+define i1 @test6(i1 %A) {
+; CHECK-LABEL: @test6(
+; CHECK-NEXT:    ret i1 %A
+;
+  %B = zext i1 %A to i32
+  %C = icmp ne i32 %B, 0
+  ret i1 %C
+}
+
+define i1 @test6a(i1 %A) {
+; CHECK-LABEL: @test6a(
+; CHECK-NEXT:    ret i1 true
+;
+  %B = zext i1 %A to i32
+  %C = icmp ne i32 %B, -1
+  ret i1 %C
+}
+
+define i1 @test7(i8* %A) {
+; CHECK-LABEL: @test7(
+; CHECK-NEXT:    [[C:%.*]] = icmp eq i8* %A, null
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %B = bitcast i8* %A to i32*
+  %C = icmp eq i32* %B, null
+  ret i1 %C
+}

Added: llvm/trunk/test/Transforms/InstCombine/cast-unsigned-icmp-eqcmp-0.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/cast-unsigned-icmp-eqcmp-0.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/cast-unsigned-icmp-eqcmp-0.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/cast-unsigned-icmp-eqcmp-0.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,204 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt < %s -instcombine -S | FileCheck %s
+
+; This is related to https://bugs.llvm.org/show_bug.cgi?id=36682
+
+; In *all* of these, uitofp and bitcast should be instcombine'd out.
+
+define i1 @i32_cast_cmp_eq_int_0_uitofp_float(i32 %i) {
+; CHECK-LABEL: @i32_cast_cmp_eq_int_0_uitofp_float(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[I:%.*]], 0
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %f = uitofp i32 %i to float
+  %b = bitcast float %f to i32
+  %cmp = icmp eq i32 %b, 0
+  ret i1 %cmp
+}
+
+define <2 x i1> @i32_cast_cmp_eq_int_0_uitofp_float_vec(<2 x i32> %i) {
+; CHECK-LABEL: @i32_cast_cmp_eq_int_0_uitofp_float_vec(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq <2 x i32> [[I:%.*]], zeroinitializer
+; CHECK-NEXT:    ret <2 x i1> [[CMP]]
+;
+  %f = uitofp <2 x i32> %i to  <2 x float>
+  %b = bitcast <2 x float> %f to <2 x i32>
+  %cmp = icmp eq <2 x i32> %b, <i32 0, i32 0>
+  ret <2 x i1> %cmp
+}
+
+define <3 x i1> @i32_cast_cmp_eq_int_0_uitofp_float_vec_undef(<3 x i32> %i) {
+; CHECK-LABEL: @i32_cast_cmp_eq_int_0_uitofp_float_vec_undef(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq <3 x i32> [[I:%.*]], zeroinitializer
+; CHECK-NEXT:    ret <3 x i1> [[CMP]]
+;
+  %f = uitofp <3 x i32> %i to <3 x float>
+  %b = bitcast <3 x float> %f to <3 x i32>
+  %cmp = icmp eq <3 x i32> %b, <i32 0, i32 undef, i32 0>
+  ret <3 x i1> %cmp
+}
+
+define i1 @i32_cast_cmp_ne_int_0_uitofp_float(i32 %i) {
+; CHECK-LABEL: @i32_cast_cmp_ne_int_0_uitofp_float(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ne i32 [[I:%.*]], 0
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %f = uitofp i32 %i to float
+  %b = bitcast float %f to i32
+  %cmp = icmp ne i32 %b, 0
+  ret i1 %cmp
+}
+
+define <2 x i1> @i32_cast_cmp_ne_int_0_uitofp_float_vec(<2 x i32> %i) {
+; CHECK-LABEL: @i32_cast_cmp_ne_int_0_uitofp_float_vec(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ne <2 x i32> [[I:%.*]], zeroinitializer
+; CHECK-NEXT:    ret <2 x i1> [[CMP]]
+;
+  %f = uitofp <2 x i32> %i to  <2 x float>
+  %b = bitcast <2 x float> %f to <2 x i32>
+  %cmp = icmp ne <2 x i32> %b, <i32 0, i32 0>
+  ret <2 x i1> %cmp
+}
+
+define <3 x i1> @i32_cast_cmp_ne_int_0_uitofp_float_vec_undef(<3 x i32> %i) {
+; CHECK-LABEL: @i32_cast_cmp_ne_int_0_uitofp_float_vec_undef(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ne <3 x i32> [[I:%.*]], zeroinitializer
+; CHECK-NEXT:    ret <3 x i1> [[CMP]]
+;
+  %f = uitofp <3 x i32> %i to <3 x float>
+  %b = bitcast <3 x float> %f to <3 x i32>
+  %cmp = icmp ne <3 x i32> %b, <i32 0, i32 undef, i32 0>
+  ret <3 x i1> %cmp
+}
+
+define i1 @i32_cast_cmp_eq_int_0_uitofp_double(i32 %i) {
+; CHECK-LABEL: @i32_cast_cmp_eq_int_0_uitofp_double(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[I:%.*]], 0
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %f = uitofp i32 %i to double
+  %b = bitcast double %f to i64
+  %cmp = icmp eq i64 %b, 0
+  ret i1 %cmp
+}
+
+define <2 x i1> @i32_cast_cmp_eq_int_0_uitofp_double_vec(<2 x i32> %i) {
+; CHECK-LABEL: @i32_cast_cmp_eq_int_0_uitofp_double_vec(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq <2 x i32> [[I:%.*]], zeroinitializer
+; CHECK-NEXT:    ret <2 x i1> [[CMP]]
+;
+  %f = uitofp <2 x i32> %i to  <2 x double>
+  %b = bitcast <2 x double> %f to <2 x i64>
+  %cmp = icmp eq <2 x i64> %b, <i64 0, i64 0>
+  ret <2 x i1> %cmp
+}
+
+define <3 x i1> @i32_cast_cmp_eq_int_0_uitofp_double_vec_undef(<3 x i32> %i) {
+; CHECK-LABEL: @i32_cast_cmp_eq_int_0_uitofp_double_vec_undef(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq <3 x i32> [[I:%.*]], zeroinitializer
+; CHECK-NEXT:    ret <3 x i1> [[CMP]]
+;
+  %f = uitofp <3 x i32> %i to <3 x double>
+  %b = bitcast <3 x double> %f to <3 x i64>
+  %cmp = icmp eq <3 x i64> %b, <i64 0, i64 undef, i64 0>
+  ret <3 x i1> %cmp
+}
+
+define i1 @i32_cast_cmp_ne_int_0_uitofp_double(i32 %i) {
+; CHECK-LABEL: @i32_cast_cmp_ne_int_0_uitofp_double(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ne i32 [[I:%.*]], 0
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %f = uitofp i32 %i to double
+  %b = bitcast double %f to i64
+  %cmp = icmp ne i64 %b, 0
+  ret i1 %cmp
+}
+
+define <2 x i1> @i32_cast_cmp_ne_int_0_uitofp_double_vec(<2 x i32> %i) {
+; CHECK-LABEL: @i32_cast_cmp_ne_int_0_uitofp_double_vec(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ne <2 x i32> [[I:%.*]], zeroinitializer
+; CHECK-NEXT:    ret <2 x i1> [[CMP]]
+;
+  %f = uitofp <2 x i32> %i to  <2 x double>
+  %b = bitcast <2 x double> %f to <2 x i64>
+  %cmp = icmp ne <2 x i64> %b, <i64 0, i64 0>
+  ret <2 x i1> %cmp
+}
+
+define <3 x i1> @i32_cast_cmp_ne_int_0_uitofp_double_vec_undef(<3 x i32> %i) {
+; CHECK-LABEL: @i32_cast_cmp_ne_int_0_uitofp_double_vec_undef(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ne <3 x i32> [[I:%.*]], zeroinitializer
+; CHECK-NEXT:    ret <3 x i1> [[CMP]]
+;
+  %f = uitofp <3 x i32> %i to <3 x double>
+  %b = bitcast <3 x double> %f to <3 x i64>
+  %cmp = icmp ne <3 x i64> %b, <i64 0, i64 undef, i64 0>
+  ret <3 x i1> %cmp
+}
+
+define i1 @i32_cast_cmp_eq_int_0_uitofp_half(i32 %i) {
+; CHECK-LABEL: @i32_cast_cmp_eq_int_0_uitofp_half(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[I:%.*]], 0
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %f = uitofp i32 %i to half
+  %b = bitcast half %f to i16
+  %cmp = icmp eq i16 %b, 0
+  ret i1 %cmp
+}
+
+define <2 x i1> @i32_cast_cmp_eq_int_0_uitofp_half_vec(<2 x i32> %i) {
+; CHECK-LABEL: @i32_cast_cmp_eq_int_0_uitofp_half_vec(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq <2 x i32> [[I:%.*]], zeroinitializer
+; CHECK-NEXT:    ret <2 x i1> [[CMP]]
+;
+  %f = uitofp <2 x i32> %i to  <2 x half>
+  %b = bitcast <2 x half> %f to <2 x i16>
+  %cmp = icmp eq <2 x i16> %b, <i16 0, i16 0>
+  ret <2 x i1> %cmp
+}
+
+define <3 x i1> @i32_cast_cmp_eq_int_0_uitofp_half_vec_undef(<3 x i32> %i) {
+; CHECK-LABEL: @i32_cast_cmp_eq_int_0_uitofp_half_vec_undef(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq <3 x i32> [[I:%.*]], zeroinitializer
+; CHECK-NEXT:    ret <3 x i1> [[CMP]]
+;
+  %f = uitofp <3 x i32> %i to <3 x half>
+  %b = bitcast <3 x half> %f to <3 x i16>
+  %cmp = icmp eq <3 x i16> %b, <i16 0, i16 undef, i16 0>
+  ret <3 x i1> %cmp
+}
+
+define i1 @i32_cast_cmp_ne_int_0_uitofp_half(i32 %i) {
+; CHECK-LABEL: @i32_cast_cmp_ne_int_0_uitofp_half(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ne i32 [[I:%.*]], 0
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %f = uitofp i32 %i to half
+  %b = bitcast half %f to i16
+  %cmp = icmp ne i16 %b, 0
+  ret i1 %cmp
+}
+
+define <2 x i1> @i32_cast_cmp_ne_int_0_uitofp_half_vec(<2 x i32> %i) {
+; CHECK-LABEL: @i32_cast_cmp_ne_int_0_uitofp_half_vec(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ne <2 x i32> [[I:%.*]], zeroinitializer
+; CHECK-NEXT:    ret <2 x i1> [[CMP]]
+;
+  %f = uitofp <2 x i32> %i to  <2 x half>
+  %b = bitcast <2 x half> %f to <2 x i16>
+  %cmp = icmp ne <2 x i16> %b, <i16 0, i16 0>
+  ret <2 x i1> %cmp
+}
+
+define <3 x i1> @i32_cast_cmp_ne_int_0_uitofp_half_vec_undef(<3 x i32> %i) {
+; CHECK-LABEL: @i32_cast_cmp_ne_int_0_uitofp_half_vec_undef(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ne <3 x i32> [[I:%.*]], zeroinitializer
+; CHECK-NEXT:    ret <3 x i1> [[CMP]]
+;
+  %f = uitofp <3 x i32> %i to <3 x half>
+  %b = bitcast <3 x half> %f to <3 x i16>
+  %cmp = icmp ne <3 x i16> %b, <i16 0, i16 undef, i16 0>
+  ret <3 x i1> %cmp
+}

Added: llvm/trunk/test/Transforms/InstCombine/cast.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/cast.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/cast.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/cast.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,1561 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; Tests to make sure elimination of casts is working correctly
+; RUN: opt < %s -instcombine -S | FileCheck %s
+target datalayout = "E-p:64:64:64-p1:32:32:32-p2:64:64:64-p3:64:64:64-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-n8:16:32:64"
+
+ at inbuf = external global [32832 x i8]
+
+define i32 @test1(i32 %A) {
+; CHECK-LABEL: @test1(
+; CHECK-NEXT:    ret i32 [[A:%.*]]
+;
+  %c1 = bitcast i32 %A to i32
+  %c2 = bitcast i32 %c1 to i32
+  ret i32 %c2
+}
+
+define i64 @test2(i8 %A) {
+; CHECK-LABEL: @test2(
+; CHECK-NEXT:    [[RET:%.*]] = zext i8 [[A:%.*]] to i64
+; CHECK-NEXT:    ret i64 [[RET]]
+;
+  %c1 = zext i8 %A to i16
+  %c2 = zext i16 %c1 to i32
+  %Ret = zext i32 %c2 to i64
+  ret i64 %Ret
+}
+
+define i64 @test3(i64 %A) {
+; CHECK-LABEL: @test3(
+; 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 @test4(i32 %A, i32 %B) {
+; CHECK-LABEL: @test4(
+; CHECK-NEXT:    [[COND:%.*]] = icmp slt i32 [[A:%.*]], [[B:%.*]]
+; CHECK-NEXT:    [[RESULT:%.*]] = zext i1 [[COND]] to i32
+; CHECK-NEXT:    ret i32 [[RESULT]]
+;
+  %COND = icmp slt i32 %A, %B
+  %c = zext i1 %COND to i8
+  %result = zext i8 %c to i32
+  ret i32 %result
+}
+
+define i32 @test5(i1 %B) {
+; CHECK-LABEL: @test5(
+; CHECK-NEXT:    [[RESULT:%.*]] = zext i1 [[B:%.*]] to i32
+; CHECK-NEXT:    ret i32 [[RESULT]]
+;
+  %c = zext i1 %B to i8
+  %result = zext i8 %c to i32
+  ret i32 %result
+}
+
+define i32 @test6(i64 %A) {
+; CHECK-LABEL: @test6(
+; CHECK-NEXT:    [[C1:%.*]] = trunc i64 [[A:%.*]] to i32
+; CHECK-NEXT:    ret i32 [[C1]]
+;
+  %c1 = trunc i64 %A to i32
+  %res = bitcast i32 %c1 to i32
+  ret i32 %res
+}
+
+define i64 @test7(i1 %A) {
+; CHECK-LABEL: @test7(
+; CHECK-NEXT:    [[RES:%.*]] = zext i1 [[A:%.*]] to i64
+; CHECK-NEXT:    ret i64 [[RES]]
+;
+  %c1 = zext i1 %A to i32
+  %res = sext i32 %c1 to i64
+  ret i64 %res
+}
+
+define i64 @test8(i8 %A) {
+; CHECK-LABEL: @test8(
+; CHECK-NEXT:    [[C1:%.*]] = sext i8 [[A:%.*]] to i64
+; CHECK-NEXT:    ret i64 [[C1]]
+;
+  %c1 = sext i8 %A to i64
+  %res = bitcast i64 %c1 to i64
+  ret i64 %res
+}
+
+define i16 @test9(i16 %A) {
+; CHECK-LABEL: @test9(
+; CHECK-NEXT:    ret i16 [[A:%.*]]
+;
+  %c1 = sext i16 %A to i32
+  %c2 = trunc i32 %c1 to i16
+  ret i16 %c2
+}
+
+define i16 @test10(i16 %A) {
+; CHECK-LABEL: @test10(
+; CHECK-NEXT:    ret i16 [[A:%.*]]
+;
+  %c1 = sext i16 %A to i32
+  %c2 = trunc i32 %c1 to i16
+  ret i16 %c2
+}
+
+declare void @varargs(i32, ...)
+
+define void @test11(i32* %P) {
+; CHECK-LABEL: @test11(
+; CHECK-NEXT:    call void (i32, ...) @varargs(i32 5, i32* [[P:%.*]])
+; CHECK-NEXT:    ret void
+;
+  %c = bitcast i32* %P to i16*
+  call void (i32, ...) @varargs( i32 5, i16* %c )
+  ret void
+}
+
+declare i32 @__gxx_personality_v0(...)
+define void @test_invoke_vararg_cast(i32* %a, i32* %b) personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) {
+; CHECK-LABEL: @test_invoke_vararg_cast(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    invoke void (i32, ...) @varargs(i32 1, i32* [[B:%.*]], i32* [[A:%.*]])
+; CHECK-NEXT:    to label [[INVOKE_CONT:%.*]] unwind label [[LPAD:%.*]]
+; CHECK:       invoke.cont:
+; CHECK-NEXT:    ret void
+; CHECK:       lpad:
+; CHECK-NEXT:    [[TMP0:%.*]] = landingpad { i8*, i32 }
+; CHECK-NEXT:    cleanup
+; CHECK-NEXT:    ret void
+;
+entry:
+  %0 = bitcast i32* %b to i8*
+  %1 = bitcast i32* %a to i64*
+  invoke void (i32, ...) @varargs(i32 1, i8* %0, i64* %1)
+  to label %invoke.cont unwind label %lpad
+
+invoke.cont:
+  ret void
+
+lpad:
+  %2 = landingpad { i8*, i32 }
+  cleanup
+  ret void
+}
+
+define i8* @test13(i64 %A) {
+; CHECK-LABEL: @test13(
+; CHECK-NEXT:    [[C:%.*]] = getelementptr [32832 x i8], [32832 x i8]* @inbuf, i64 0, i64 [[A:%.*]]
+; CHECK-NEXT:    ret i8* [[C]]
+;
+  %c = getelementptr [0 x i8], [0 x i8]* bitcast ([32832 x i8]* @inbuf to [0 x i8]*), i64 0, i64 %A
+  ret i8* %c
+}
+
+define i1 @test14(i8 %A) {
+; CHECK-LABEL: @test14(
+; CHECK-NEXT:    [[X:%.*]] = icmp sgt i8 [[A:%.*]], -1
+; CHECK-NEXT:    ret i1 [[X]]
+;
+  %c = bitcast i8 %A to i8
+  %X = icmp ult i8 %c, -128
+  ret i1 %X
+}
+
+
+; This just won't occur when there's no difference between ubyte and sbyte
+;bool %test15(ubyte %A) {
+;        %c = cast ubyte %A to sbyte
+;        %X = setlt sbyte %c, 0   ; setgt %A, 127
+;        ret bool %X
+;}
+
+define i1 @test16(i32* %P) {
+; CHECK-LABEL: @test16(
+; CHECK-NEXT:    [[C:%.*]] = icmp ne i32* [[P:%.*]], null
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %c = icmp ne i32* %P, null
+  ret i1 %c
+}
+
+define i16 @test17(i1 %x) {
+; CHECK-LABEL: @test17(
+; CHECK-NEXT:    [[T86:%.*]] = zext i1 [[X:%.*]] to i16
+; CHECK-NEXT:    ret i16 [[T86]]
+;
+  %c = zext i1 %x to i32
+  %t86 = trunc i32 %c to i16
+  ret i16 %t86
+}
+
+define i16 @test18(i8 %x) {
+; CHECK-LABEL: @test18(
+; CHECK-NEXT:    [[T86:%.*]] = sext i8 [[X:%.*]] to i16
+; CHECK-NEXT:    ret i16 [[T86]]
+;
+  %c = sext i8 %x to i32
+  %t86 = trunc i32 %c to i16
+  ret i16 %t86
+}
+
+define i1 @test19(i32 %X) {
+; CHECK-LABEL: @test19(
+; CHECK-NEXT:    [[Z:%.*]] = icmp slt i32 [[X:%.*]], 12345
+; CHECK-NEXT:    ret i1 [[Z]]
+;
+  %c = sext i32 %X to i64
+  %Z = icmp slt i64 %c, 12345
+  ret i1 %Z
+}
+
+define <2 x i1> @test19vec(<2 x i32> %X) {
+; CHECK-LABEL: @test19vec(
+; CHECK-NEXT:    [[Z:%.*]] = icmp slt <2 x i32> [[X:%.*]], <i32 12345, i32 2147483647>
+; CHECK-NEXT:    ret <2 x i1> [[Z]]
+;
+  %c = sext <2 x i32> %X to <2 x i64>
+  %Z = icmp slt <2 x i64> %c, <i64 12345, i64 2147483647>
+  ret <2 x i1> %Z
+}
+
+define <3 x i1> @test19vec2(<3 x i1> %X) {
+; CHECK-LABEL: @test19vec2(
+; CHECK-NEXT:    [[CMPEQ:%.*]] = xor <3 x i1> [[X:%.*]], <i1 true, i1 true, i1 true>
+; CHECK-NEXT:    ret <3 x i1> [[CMPEQ]]
+;
+  %sext = sext <3 x i1> %X to <3 x i32>
+  %cmpeq = icmp eq <3 x i32> %sext, zeroinitializer
+  ret <3 x i1> %cmpeq
+}
+
+define i1 @test20(i1 %B) {
+; CHECK-LABEL: @test20(
+; CHECK-NEXT:    ret i1 false
+;
+  %c = zext i1 %B to i32
+  %D = icmp slt i32 %c, -1
+  ret i1 %D
+}
+
+define i32 @test21(i32 %X) {
+; CHECK-LABEL: @test21(
+; CHECK-NEXT:    [[TMP1:%.*]] = and i32 [[X:%.*]], 255
+; CHECK-NEXT:    ret i32 [[TMP1]]
+;
+  %c1 = trunc i32 %X to i8
+  %c2 = sext i8 %c1 to i32
+  %RV = and i32 %c2, 255
+  ret i32 %RV
+}
+
+define i32 @test22(i32 %X) {
+; CHECK-LABEL: @test22(
+; CHECK-NEXT:    [[SEXT:%.*]] = shl i32 [[X:%.*]], 24
+; CHECK-NEXT:    ret i32 [[SEXT]]
+;
+  %c1 = trunc i32 %X to i8
+  %c2 = sext i8 %c1 to i32
+  %RV = shl i32 %c2, 24
+  ret i32 %RV
+}
+
+define i32 @test23(i32 %X) {
+; CHECK-LABEL: @test23(
+; CHECK-NEXT:    [[C2:%.*]] = and i32 [[X:%.*]], 65535
+; CHECK-NEXT:    ret i32 [[C2]]
+;
+  %c1 = trunc i32 %X to i16
+  %c2 = zext i16 %c1 to i32
+  ret i32 %c2
+}
+
+define i1 @test24(i1 %C) {
+; CHECK-LABEL: @test24(
+; CHECK-NEXT:    ret i1 true
+;
+  %X = select i1 %C, i32 14, i32 1234
+  %c = icmp ne i32 %X, 0
+  ret i1 %c
+}
+
+define i32 @test26(float %F) {
+; CHECK-LABEL: @test26(
+; CHECK-NEXT:    [[D:%.*]] = fptosi float [[F:%.*]] to i32
+; CHECK-NEXT:    ret i32 [[D]]
+;
+  %c = fpext float %F to double
+  %D = fptosi double %c to i32
+  ret i32 %D
+}
+
+define [4 x float]* @test27([9 x [4 x float]]* %A) {
+; CHECK-LABEL: @test27(
+; CHECK-NEXT:    [[C:%.*]] = getelementptr inbounds [9 x [4 x float]], [9 x [4 x float]]* [[A:%.*]], i64 0, i64 0
+; CHECK-NEXT:    ret [4 x float]* [[C]]
+;
+  %c = bitcast [9 x [4 x float]]* %A to [4 x float]*
+  ret [4 x float]* %c
+}
+
+define float* @test28([4 x float]* %A) {
+; CHECK-LABEL: @test28(
+; CHECK-NEXT:    [[C:%.*]] = getelementptr inbounds [4 x float], [4 x float]* [[A:%.*]], i64 0, i64 0
+; CHECK-NEXT:    ret float* [[C]]
+;
+  %c = bitcast [4 x float]* %A to float*
+  ret float* %c
+}
+
+define i32 @test29(i32 %c1, i32 %c2) {
+; CHECK-LABEL: @test29(
+; CHECK-NEXT:    [[T21:%.*]] = or i32 [[C2:%.*]], [[C1:%.*]]
+; CHECK-NEXT:    [[T10:%.*]] = and i32 [[T21]], 255
+; CHECK-NEXT:    ret i32 [[T10]]
+;
+  %t1 = trunc i32 %c1 to i8
+  %tmask = trunc i32 %c2 to i8
+  %t2 = or i8 %tmask, %t1
+  %t10 = zext i8 %t2 to i32
+  ret i32 %t10
+}
+
+define i32 @test30(i32 %c1) {
+; CHECK-LABEL: @test30(
+; CHECK-NEXT:    [[C3:%.*]] = and i32 [[C1:%.*]], 255
+; CHECK-NEXT:    [[C4:%.*]] = xor i32 [[C3]], 1
+; CHECK-NEXT:    ret i32 [[C4]]
+;
+  %c2 = trunc i32 %c1 to i8
+  %c3 = xor i8 %c2, 1
+  %c4 = zext i8 %c3 to i32
+  ret i32 %c4
+}
+
+define i1 @test31(i64 %A) {
+; CHECK-LABEL: @test31(
+; CHECK-NEXT:    [[C1:%.*]] = and i64 [[A:%.*]], 42
+; CHECK-NEXT:    [[D:%.*]] = icmp eq i64 [[C1]], 10
+; CHECK-NEXT:    ret i1 [[D]]
+;
+  %B = trunc i64 %A to i32
+  %C = and i32 %B, 42
+  %D = icmp eq i32 %C, 10
+  ret i1 %D
+}
+
+; FIXME: Vectors should fold too...or not?
+; Does this depend on the whether the source/dest types of the trunc are legal in the data layout?
+define <2 x i1> @test31vec(<2 x i64> %A) {
+; CHECK-LABEL: @test31vec(
+; CHECK-NEXT:    [[B:%.*]] = trunc <2 x i64> [[A:%.*]] to <2 x i32>
+; CHECK-NEXT:    [[C:%.*]] = and <2 x i32> [[B]], <i32 42, i32 42>
+; CHECK-NEXT:    [[D:%.*]] = icmp eq <2 x i32> [[C]], <i32 10, i32 10>
+; CHECK-NEXT:    ret <2 x i1> [[D]]
+;
+  %B = trunc <2 x i64> %A to <2 x i32>
+  %C = and <2 x i32> %B, <i32 42, i32 42>
+  %D = icmp eq <2 x i32> %C, <i32 10, i32 10>
+  ret <2 x i1> %D
+}
+
+; Verify that the 'and' was narrowed, the zext was eliminated, and the compare was narrowed
+; even for vectors. Earlier folds should ensure that the icmp(and(zext)) pattern never occurs.
+
+define <2 x i1> @test32vec(<2 x i8> %A) {
+; CHECK-LABEL: @test32vec(
+; CHECK-NEXT:    [[TMP1:%.*]] = and <2 x i8> [[A:%.*]], <i8 42, i8 42>
+; CHECK-NEXT:    [[D:%.*]] = icmp eq <2 x i8> [[TMP1]], <i8 10, i8 10>
+; CHECK-NEXT:    ret <2 x i1> [[D]]
+;
+  %B = zext <2 x i8> %A to <2 x i16>
+  %C = and <2 x i16> %B, <i16 42, i16 42>
+  %D = icmp eq <2 x i16> %C, <i16 10, i16 10>
+  ret <2 x i1> %D
+}
+
+define i32 @test33(i32 %c1) {
+; CHECK-LABEL: @test33(
+; CHECK-NEXT:    ret i32 [[C1:%.*]]
+;
+  %x = bitcast i32 %c1 to float
+  %y = bitcast float %x to i32
+  ret i32 %y
+}
+
+define i16 @test34(i16 %a) {
+; CHECK-LABEL: @test34(
+; CHECK-NEXT:    [[TMP1:%.*]] = lshr i16 [[A:%.*]], 8
+; CHECK-NEXT:    ret i16 [[TMP1]]
+;
+  %c1 = zext i16 %a to i32
+  %t21 = lshr i32 %c1, 8
+  %c2 = trunc i32 %t21 to i16
+  ret i16 %c2
+}
+
+define i16 @test35(i16 %a) {
+; CHECK-LABEL: @test35(
+; CHECK-NEXT:    [[T2:%.*]] = lshr i16 [[A:%.*]], 8
+; CHECK-NEXT:    ret i16 [[T2]]
+;
+  %c1 = bitcast i16 %a to i16
+  %t2 = lshr i16 %c1, 8
+  %c2 = bitcast i16 %t2 to i16
+  ret i16 %c2
+}
+
+; rdar://6480391
+define i1 @test36(i32 %a) {
+; CHECK-LABEL: @test36(
+; CHECK-NEXT:    [[D:%.*]] = icmp sgt i32 [[A:%.*]], -1
+; CHECK-NEXT:    ret i1 [[D]]
+;
+  %b = lshr i32 %a, 31
+  %c = trunc i32 %b to i8
+  %d = icmp eq i8 %c, 0
+  ret i1 %d
+}
+
+define <2 x i1> @test36vec(<2 x i32> %a) {
+; CHECK-LABEL: @test36vec(
+; CHECK-NEXT:    [[D:%.*]] = icmp sgt <2 x i32> [[A:%.*]], <i32 -1, i32 -1>
+; CHECK-NEXT:    ret <2 x i1> [[D]]
+;
+  %b = lshr <2 x i32> %a, <i32 31, i32 31>
+  %c = trunc <2 x i32> %b to <2 x i8>
+  %d = icmp eq <2 x i8> %c, zeroinitializer
+  ret <2 x i1> %d
+}
+
+define i1 @test37(i32 %a) {
+; CHECK-LABEL: @test37(
+; CHECK-NEXT:    ret i1 false
+;
+  %b = lshr i32 %a, 31
+  %c = or i32 %b, 512
+  %d = trunc i32 %c to i8
+  %e = icmp eq i8 %d, 11
+  ret i1 %e
+}
+
+define i64 @test38(i32 %a) {
+; CHECK-LABEL: @test38(
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp ne i32 [[A:%.*]], -2
+; CHECK-NEXT:    [[TMP2:%.*]] = zext i1 [[TMP1]] to i64
+; CHECK-NEXT:    ret i64 [[TMP2]]
+;
+  %1 = icmp eq i32 %a, -2
+  %2 = zext i1 %1 to i8
+  %3 = xor i8 %2, 1
+  %4 = zext i8 %3 to i64
+  ret i64 %4
+}
+
+define i16 @test39(i16 %a) {
+; CHECK-LABEL: @test39(
+; CHECK-NEXT:    [[REV:%.*]] = call i16 @llvm.bswap.i16(i16 [[A:%.*]])
+; CHECK-NEXT:    ret i16 [[REV]]
+;
+  %t = zext i16 %a to i32
+  %t21 = lshr i32 %t, 8
+  %t5 = shl i32 %t, 8
+  %t32 = or i32 %t21, %t5
+  %r = trunc i32 %t32 to i16
+  ret i16 %r
+}
+
+define i16 @test40(i16 %a) {
+; CHECK-LABEL: @test40(
+; CHECK-NEXT:    [[T21:%.*]] = lshr i16 [[A:%.*]], 9
+; CHECK-NEXT:    [[T5:%.*]] = shl i16 [[A]], 8
+; CHECK-NEXT:    [[T32:%.*]] = or i16 [[T21]], [[T5]]
+; CHECK-NEXT:    ret i16 [[T32]]
+;
+  %t = zext i16 %a to i32
+  %t21 = lshr i32 %t, 9
+  %t5 = shl i32 %t, 8
+  %t32 = or i32 %t21, %t5
+  %r = trunc i32 %t32 to i16
+  ret i16 %r
+}
+
+define <2 x i16> @test40vec(<2 x i16> %a) {
+; CHECK-LABEL: @test40vec(
+; CHECK-NEXT:    [[T21:%.*]] = lshr <2 x i16> [[A:%.*]], <i16 9, i16 9>
+; CHECK-NEXT:    [[T5:%.*]] = shl <2 x i16> [[A]], <i16 8, i16 8>
+; CHECK-NEXT:    [[T32:%.*]] = or <2 x i16> [[T21]], [[T5]]
+; CHECK-NEXT:    ret <2 x i16> [[T32]]
+;
+  %t = zext <2 x i16> %a to <2 x i32>
+  %t21 = lshr <2 x i32> %t, <i32 9, i32 9>
+  %t5 = shl <2 x i32> %t, <i32 8, i32 8>
+  %t32 = or <2 x i32> %t21, %t5
+  %r = trunc <2 x i32> %t32 to <2 x i16>
+  ret <2 x i16> %r
+}
+
+; PR1263
+define i32* @test41(i32* %t1) {
+; CHECK-LABEL: @test41(
+; CHECK-NEXT:    ret i32* [[T1:%.*]]
+;
+  %t64 = bitcast i32* %t1 to { i32 }*
+  %t65 = getelementptr { i32 }, { i32 }* %t64, i32 0, i32 0
+  ret i32* %t65
+}
+
+define i32 addrspace(1)* @test41_addrspacecast_smaller(i32* %t1) {
+; CHECK-LABEL: @test41_addrspacecast_smaller(
+; CHECK-NEXT:    [[T65:%.*]] = addrspacecast i32* [[T1:%.*]] to i32 addrspace(1)*
+; CHECK-NEXT:    ret i32 addrspace(1)* [[T65]]
+;
+  %t64 = addrspacecast i32* %t1 to { i32 } addrspace(1)*
+  %t65 = getelementptr { i32 }, { i32 } addrspace(1)* %t64, i32 0, i32 0
+  ret i32 addrspace(1)* %t65
+}
+
+define i32* @test41_addrspacecast_larger(i32 addrspace(1)* %t1) {
+; CHECK-LABEL: @test41_addrspacecast_larger(
+; CHECK-NEXT:    [[T65:%.*]] = addrspacecast i32 addrspace(1)* [[T1:%.*]] to i32*
+; CHECK-NEXT:    ret i32* [[T65]]
+;
+  %t64 = addrspacecast i32 addrspace(1)* %t1 to { i32 }*
+  %t65 = getelementptr { i32 }, { i32 }* %t64, i32 0, i32 0
+  ret i32* %t65
+}
+
+define i32 @test42(i32 %X) {
+; CHECK-LABEL: @test42(
+; CHECK-NEXT:    [[Z:%.*]] = and i32 [[X:%.*]], 255
+; CHECK-NEXT:    ret i32 [[Z]]
+;
+  %Y = trunc i32 %X to i8
+  %Z = zext i8 %Y to i32
+  ret i32 %Z
+}
+
+; rdar://6598839
+define zeroext i64 @test43(i8 zeroext %on_off) {
+; CHECK-LABEL: @test43(
+; CHECK-NEXT:    [[A:%.*]] = zext i8 [[ON_OFF:%.*]] to i64
+; CHECK-NEXT:    [[B:%.*]] = add nsw i64 [[A]], -1
+; CHECK-NEXT:    ret i64 [[B]]
+;
+  %A = zext i8 %on_off to i32
+  %B = add i32 %A, -1
+  %C = sext i32 %B to i64
+  ret i64 %C  ;; Should be (add (zext i8 -> i64), -1)
+}
+
+define i64 @test44(i8 %T) {
+; CHECK-LABEL: @test44(
+; CHECK-NEXT:    [[A:%.*]] = zext i8 [[T:%.*]] to i64
+; CHECK-NEXT:    [[B:%.*]] = or i64 [[A]], 1234
+; CHECK-NEXT:    ret i64 [[B]]
+;
+  %A = zext i8 %T to i16
+  %B = or i16 %A, 1234
+  %C = zext i16 %B to i64
+  ret i64 %C
+}
+
+define i64 @test45(i8 %A, i64 %Q) {
+; CHECK-LABEL: @test45(
+; CHECK-NEXT:    [[B:%.*]] = sext i8 [[A:%.*]] to i64
+; CHECK-NEXT:    [[C:%.*]] = or i64 [[B]], [[Q:%.*]]
+; CHECK-NEXT:    [[E:%.*]] = and i64 [[C]], 4294967295
+; CHECK-NEXT:    ret i64 [[E]]
+;
+  %D = trunc i64 %Q to i32  ;; should be removed
+  %B = sext i8 %A to i32
+  %C = or i32 %B, %D
+  %E = zext i32 %C to i64
+  ret i64 %E
+}
+
+
+define i64 @test46(i64 %A) {
+; CHECK-LABEL: @test46(
+; CHECK-NEXT:    [[C:%.*]] = shl i64 [[A:%.*]], 8
+; CHECK-NEXT:    [[D:%.*]] = and i64 [[C]], 10752
+; CHECK-NEXT:    ret i64 [[D]]
+;
+  %B = trunc i64 %A to i32
+  %C = and i32 %B, 42
+  %D = shl i32 %C, 8
+  %E = zext i32 %D to i64
+  ret i64 %E
+}
+
+define <2 x i64> @test46vec(<2 x i64> %A) {
+; CHECK-LABEL: @test46vec(
+; CHECK-NEXT:    [[B:%.*]] = trunc <2 x i64> [[A:%.*]] to <2 x i32>
+; CHECK-NEXT:    [[C:%.*]] = shl <2 x i32> [[B]], <i32 8, i32 8>
+; CHECK-NEXT:    [[D:%.*]] = and <2 x i32> [[C]], <i32 10752, i32 10752>
+; CHECK-NEXT:    [[E:%.*]] = zext <2 x i32> [[D]] to <2 x i64>
+; CHECK-NEXT:    ret <2 x i64> [[E]]
+;
+  %B = trunc <2 x i64> %A to <2 x i32>
+  %C = and <2 x i32> %B, <i32 42, i32 42>
+  %D = shl <2 x i32> %C, <i32 8, i32 8>
+  %E = zext <2 x i32> %D to <2 x i64>
+  ret <2 x i64> %E
+}
+
+define i64 @test47(i8 %A) {
+; CHECK-LABEL: @test47(
+; CHECK-NEXT:    [[TMP1:%.*]] = or i8 [[A:%.*]], 42
+; CHECK-NEXT:    [[C:%.*]] = sext i8 [[TMP1]] to i64
+; CHECK-NEXT:    [[E:%.*]] = and i64 [[C]], 4294967295
+; CHECK-NEXT:    ret i64 [[E]]
+;
+  %B = sext i8 %A to i32
+  %C = or i32 %B, 42
+  %E = zext i32 %C to i64
+  ret i64 %E
+}
+
+define i64 @test48(i8 %A1, i8 %a2) {
+; CHECK-LABEL: @test48(
+; CHECK-NEXT:    [[Z2:%.*]] = zext i8 [[A1:%.*]] to i32
+; CHECK-NEXT:    [[C:%.*]] = shl nuw nsw i32 [[Z2]], 8
+; CHECK-NEXT:    [[D:%.*]] = or i32 [[C]], [[Z2]]
+; CHECK-NEXT:    [[E:%.*]] = zext i32 [[D]] to i64
+; CHECK-NEXT:    ret i64 [[E]]
+;
+  %Z1 = zext i8 %a2 to i32
+  %Z2 = zext i8 %A1 to i32
+  %C = shl i32 %Z2, 8
+  %D = or i32 %C, %Z2
+  %E = zext i32 %D to i64
+  ret i64 %E
+}
+
+define i64 @test49(i64 %A) {
+; CHECK-LABEL: @test49(
+; CHECK-NEXT:    [[C:%.*]] = shl i64 [[A:%.*]], 32
+; CHECK-NEXT:    [[SEXT:%.*]] = ashr exact i64 [[C]], 32
+; CHECK-NEXT:    [[D:%.*]] = or i64 [[SEXT]], 1
+; CHECK-NEXT:    ret i64 [[D]]
+;
+  %B = trunc i64 %A to i32
+  %C = or i32 %B, 1
+  %D = sext i32 %C to i64
+  ret i64 %D
+}
+
+define i64 @test50(i64 %x) {
+; CHECK-LABEL: @test50(
+; CHECK-NEXT:    [[A:%.*]] = lshr i64 [[X:%.*]], 2
+; CHECK-NEXT:    [[D:%.*]] = shl i64 [[A]], 32
+; CHECK-NEXT:    [[SEXT:%.*]] = add i64 [[D]], -4294967296
+; CHECK-NEXT:    [[E:%.*]] = ashr exact i64 [[SEXT]], 32
+; CHECK-NEXT:    ret i64 [[E]]
+;
+  %a = lshr i64 %x, 2
+  %B = trunc i64 %a to i32
+  %D = add i32 %B, -1
+  %E = sext i32 %D to i64
+  ret i64 %E
+; lshr+shl will be handled by DAGCombine.
+}
+
+define i64 @test51(i64 %A, i1 %cond) {
+; CHECK-LABEL: @test51(
+; CHECK-NEXT:    [[C:%.*]] = and i64 [[A:%.*]], 4294967294
+; CHECK-NEXT:    [[D:%.*]] = or i64 [[A]], 1
+; CHECK-NEXT:    [[E:%.*]] = select i1 [[COND:%.*]], i64 [[C]], i64 [[D]]
+; CHECK-NEXT:    [[SEXT:%.*]] = shl i64 [[E]], 32
+; CHECK-NEXT:    [[F:%.*]] = ashr exact i64 [[SEXT]], 32
+; CHECK-NEXT:    ret i64 [[F]]
+;
+  %B = trunc i64 %A to i32
+  %C = and i32 %B, -2
+  %D = or i32 %B, 1
+  %E = select i1 %cond, i32 %C, i32 %D
+  %F = sext i32 %E to i64
+  ret i64 %F
+}
+
+define i32 @test52(i64 %A) {
+; CHECK-LABEL: @test52(
+; CHECK-NEXT:    [[B:%.*]] = trunc i64 [[A:%.*]] to i32
+; CHECK-NEXT:    [[C:%.*]] = and i32 [[B]], 7224
+; CHECK-NEXT:    [[D:%.*]] = or i32 [[C]], 32962
+; CHECK-NEXT:    ret i32 [[D]]
+;
+  %B = trunc i64 %A to i16
+  %C = or i16 %B, -32574
+  %D = and i16 %C, -25350
+  %E = zext i16 %D to i32
+  ret i32 %E
+}
+
+define i64 @test53(i32 %A) {
+; CHECK-LABEL: @test53(
+; CHECK-NEXT:    [[TMP1:%.*]] = and i32 [[A:%.*]], 7224
+; CHECK-NEXT:    [[TMP2:%.*]] = or i32 [[TMP1]], 32962
+; CHECK-NEXT:    [[D:%.*]] = zext i32 [[TMP2]] to i64
+; CHECK-NEXT:    ret i64 [[D]]
+;
+  %B = trunc i32 %A to i16
+  %C = or i16 %B, -32574
+  %D = and i16 %C, -25350
+  %E = zext i16 %D to i64
+  ret i64 %E
+}
+
+define i32 @test54(i64 %A) {
+; CHECK-LABEL: @test54(
+; CHECK-NEXT:    [[B:%.*]] = trunc i64 [[A:%.*]] to i32
+; CHECK-NEXT:    [[C:%.*]] = and i32 [[B]], 7224
+; CHECK-NEXT:    [[D:%.*]] = or i32 [[C]], -32574
+; CHECK-NEXT:    ret i32 [[D]]
+;
+  %B = trunc i64 %A to i16
+  %C = or i16 %B, -32574
+  %D = and i16 %C, -25350
+  %E = sext i16 %D to i32
+  ret i32 %E
+}
+
+define i64 @test55(i32 %A) {
+; CHECK-LABEL: @test55(
+; CHECK-NEXT:    [[TMP1:%.*]] = and i32 [[A:%.*]], 7224
+; CHECK-NEXT:    [[C:%.*]] = zext i32 [[TMP1]] to i64
+; CHECK-NEXT:    [[D:%.*]] = or i64 [[C]], -32574
+; CHECK-NEXT:    ret i64 [[D]]
+;
+  %B = trunc i32 %A to i16
+  %C = or i16 %B, -32574
+  %D = and i16 %C, -25350
+  %E = sext i16 %D to i64
+  ret i64 %E
+}
+
+define i64 @test56(i16 %A) {
+; CHECK-LABEL: @test56(
+; CHECK-NEXT:    [[P353:%.*]] = sext i16 [[A:%.*]] to i64
+; CHECK-NEXT:    [[P354:%.*]] = lshr i64 [[P353]], 5
+; CHECK-NEXT:    [[P355:%.*]] = and i64 [[P354]], 134217727
+; CHECK-NEXT:    ret i64 [[P355]]
+;
+  %p353 = sext i16 %A to i32
+  %p354 = lshr i32 %p353, 5
+  %p355 = zext i32 %p354 to i64
+  ret i64 %p355
+}
+
+define <2 x i64> @test56vec(<2 x i16> %A) {
+; CHECK-LABEL: @test56vec(
+; CHECK-NEXT:    [[P353:%.*]] = sext <2 x i16> [[A:%.*]] to <2 x i32>
+; CHECK-NEXT:    [[P354:%.*]] = lshr <2 x i32> [[P353]], <i32 5, i32 5>
+; CHECK-NEXT:    [[P355:%.*]] = zext <2 x i32> [[P354]] to <2 x i64>
+; CHECK-NEXT:    ret <2 x i64> [[P355]]
+;
+  %p353 = sext <2 x i16> %A to <2 x i32>
+  %p354 = lshr <2 x i32> %p353, <i32 5, i32 5>
+  %p355 = zext <2 x i32> %p354 to <2 x i64>
+  ret <2 x i64> %p355
+}
+
+define i64 @test57(i64 %A) {
+; CHECK-LABEL: @test57(
+; CHECK-NEXT:    [[C:%.*]] = lshr i64 [[A:%.*]], 8
+; CHECK-NEXT:    [[E:%.*]] = and i64 [[C]], 16777215
+; CHECK-NEXT:    ret i64 [[E]]
+;
+  %B = trunc i64 %A to i32
+  %C = lshr i32 %B, 8
+  %E = zext i32 %C to i64
+  ret i64 %E
+}
+
+define <2 x i64> @test57vec(<2 x i64> %A) {
+; CHECK-LABEL: @test57vec(
+; CHECK-NEXT:    [[B:%.*]] = trunc <2 x i64> [[A:%.*]] to <2 x i32>
+; CHECK-NEXT:    [[C:%.*]] = lshr <2 x i32> [[B]], <i32 8, i32 8>
+; CHECK-NEXT:    [[E:%.*]] = zext <2 x i32> [[C]] to <2 x i64>
+; CHECK-NEXT:    ret <2 x i64> [[E]]
+;
+  %B = trunc <2 x i64> %A to <2 x i32>
+  %C = lshr <2 x i32> %B, <i32 8, i32 8>
+  %E = zext <2 x i32> %C to <2 x i64>
+  ret <2 x i64> %E
+}
+
+define i64 @test58(i64 %A) {
+; CHECK-LABEL: @test58(
+; CHECK-NEXT:    [[C:%.*]] = lshr i64 [[A:%.*]], 8
+; CHECK-NEXT:    [[D:%.*]] = and i64 [[C]], 16777087
+; CHECK-NEXT:    [[E:%.*]] = or i64 [[D]], 128
+; CHECK-NEXT:    ret i64 [[E]]
+;
+  %B = trunc i64 %A to i32
+  %C = lshr i32 %B, 8
+  %D = or i32 %C, 128
+  %E = zext i32 %D to i64
+  ret i64 %E
+
+}
+
+define i64 @test59(i8 %A, i8 %B) {
+; CHECK-LABEL: @test59(
+; CHECK-NEXT:    [[C:%.*]] = zext i8 [[A:%.*]] to i64
+; CHECK-NEXT:    [[D:%.*]] = shl nuw nsw i64 [[C]], 4
+; CHECK-NEXT:    [[E:%.*]] = and i64 [[D]], 48
+; CHECK-NEXT:    [[TMP1:%.*]] = lshr i8 [[B:%.*]], 4
+; CHECK-NEXT:    [[G:%.*]] = zext i8 [[TMP1]] to i64
+; CHECK-NEXT:    [[H:%.*]] = or i64 [[E]], [[G]]
+; CHECK-NEXT:    ret i64 [[H]]
+;
+  %C = zext i8 %A to i32
+  %D = shl i32 %C, 4
+  %E = and i32 %D, 48
+  %F = zext i8 %B to i32
+  %G = lshr i32 %F, 4
+  %H = or i32 %G, %E
+  %I = zext i32 %H to i64
+  ret i64 %I
+}
+
+define <3 x i32> @test60(<4 x i32> %call4) {
+; CHECK-LABEL: @test60(
+; CHECK-NEXT:    [[P10:%.*]] = shufflevector <4 x i32> [[CALL4:%.*]], <4 x i32> undef, <3 x i32> <i32 0, i32 1, i32 2>
+; CHECK-NEXT:    ret <3 x i32> [[P10]]
+;
+  %p11 = bitcast <4 x i32> %call4 to i128
+  %p9 = trunc i128 %p11 to i96
+  %p10 = bitcast i96 %p9 to <3 x i32>
+  ret <3 x i32> %p10
+
+}
+
+define <4 x i32> @test61(<3 x i32> %call4) {
+; CHECK-LABEL: @test61(
+; CHECK-NEXT:    [[P10:%.*]] = shufflevector <3 x i32> [[CALL4:%.*]], <3 x i32> <i32 0, i32 undef, i32 undef>, <4 x i32> <i32 0, i32 1, i32 2, i32 3>
+; CHECK-NEXT:    ret <4 x i32> [[P10]]
+;
+  %p11 = bitcast <3 x i32> %call4 to i96
+  %p9 = zext i96 %p11 to i128
+  %p10 = bitcast i128 %p9 to <4 x i32>
+  ret <4 x i32> %p10
+}
+
+define <4 x i32> @test62(<3 x float> %call4) {
+; CHECK-LABEL: @test62(
+; CHECK-NEXT:    [[TMP1:%.*]] = bitcast <3 x float> [[CALL4:%.*]] to <3 x i32>
+; CHECK-NEXT:    [[P10:%.*]] = shufflevector <3 x i32> [[TMP1]], <3 x i32> <i32 0, i32 undef, i32 undef>, <4 x i32> <i32 0, i32 1, i32 2, i32 3>
+; CHECK-NEXT:    ret <4 x i32> [[P10]]
+;
+  %p11 = bitcast <3 x float> %call4 to i96
+  %p9 = zext i96 %p11 to i128
+  %p10 = bitcast i128 %p9 to <4 x i32>
+  ret <4 x i32> %p10
+}
+
+; PR7311 - Don't create invalid IR on scalar->vector cast.
+define <2 x float> @test63(i64 %t8) {
+; CHECK-LABEL: @test63(
+; CHECK-NEXT:    [[A:%.*]] = bitcast i64 [[T8:%.*]] to <2 x i32>
+; CHECK-NEXT:    [[VCVT_I:%.*]] = uitofp <2 x i32> [[A]] to <2 x float>
+; CHECK-NEXT:    ret <2 x float> [[VCVT_I]]
+;
+  %a = bitcast i64 %t8 to <2 x i32>
+  %vcvt.i = uitofp <2 x i32> %a to <2 x float>
+  ret <2 x float> %vcvt.i
+}
+
+define <4 x float> @test64(<4 x float> %c) {
+; CHECK-LABEL: @test64(
+; CHECK-NEXT:    ret <4 x float> [[C:%.*]]
+;
+  %t0 = bitcast <4 x float> %c to <4 x i32>
+  %t1 = bitcast <4 x i32> %t0 to <4 x float>
+  ret <4 x float> %t1
+}
+
+define <4 x float> @test65(<4 x float> %c) {
+; CHECK-LABEL: @test65(
+; CHECK-NEXT:    ret <4 x float> [[C:%.*]]
+;
+  %t0 = bitcast <4 x float> %c to <2 x double>
+  %t1 = bitcast <2 x double> %t0 to <4 x float>
+  ret <4 x float> %t1
+}
+
+define <2 x float> @test66(<2 x float> %c) {
+; CHECK-LABEL: @test66(
+; CHECK-NEXT:    ret <2 x float> [[C:%.*]]
+;
+  %t0 = bitcast <2 x float> %c to double
+  %t1 = bitcast double %t0 to <2 x float>
+  ret <2 x float> %t1
+}
+
+define float @test2c() {
+; CHECK-LABEL: @test2c(
+; CHECK-NEXT:    ret float -1.000000e+00
+;
+  ret float extractelement (<2 x float> bitcast (double bitcast (<2 x float> <float -1.000000e+00, float -1.000000e+00> to double) to <2 x float>), i32 0)
+}
+
+define i64 @test_mmx(<2 x i32> %x) {
+; CHECK-LABEL: @test_mmx(
+; CHECK-NEXT:    [[C:%.*]] = bitcast <2 x i32> [[X:%.*]] to i64
+; CHECK-NEXT:    ret i64 [[C]]
+;
+  %A = bitcast <2 x i32> %x to x86_mmx
+  %B = bitcast x86_mmx %A to <2 x i32>
+  %C = bitcast <2 x i32> %B to i64
+  ret i64 %C
+}
+
+define i64 @test_mmx_const(<2 x i32> %c) {
+; CHECK-LABEL: @test_mmx_const(
+; CHECK-NEXT:    ret i64 0
+;
+  %A = bitcast <2 x i32> zeroinitializer to x86_mmx
+  %B = bitcast x86_mmx %A to <2 x i32>
+  %C = bitcast <2 x i32> %B to i64
+  ret i64 %C
+}
+
+; PR12514
+define i1 @test67(i1 %a, i32 %b) {
+; CHECK-LABEL: @test67(
+; CHECK-NEXT:    ret i1 false
+;
+  %t2 = zext i1 %a to i32
+  %conv6 = xor i32 %t2, 1
+  %and = and i32 %b, %conv6
+  %sext = shl nuw nsw i32 %and, 24
+  %neg.i = xor i32 %sext, -16777216
+  %conv.i.i = ashr exact i32 %neg.i, 24
+  %trunc = trunc i32 %conv.i.i to i8
+  %tobool.i = icmp eq i8 %trunc, 0
+  ret i1 %tobool.i
+}
+
+%s = type { i32, i32, i16 }
+
+define %s @test68(%s *%p, i64 %i) {
+; CHECK-LABEL: @test68(
+; CHECK-NEXT:    [[PP1:%.*]] = getelementptr [[S:%.*]], %s* [[P:%.*]], i64 [[I:%.*]]
+; CHECK-NEXT:    [[L:%.*]] = load [[S]], %s* [[PP1]], align 4
+; CHECK-NEXT:    ret [[S]] %l
+;
+  %o = mul i64 %i, 12
+  %q = bitcast %s* %p to i8*
+  %pp = getelementptr inbounds i8, i8* %q, i64 %o
+  %r = bitcast i8* %pp to %s*
+  %l = load %s, %s* %r
+  ret %s %l
+}
+
+; addrspacecasts should be eliminated.
+define %s @test68_addrspacecast(%s* %p, i64 %i) {
+; CHECK-LABEL: @test68_addrspacecast(
+; CHECK-NEXT:    [[PP1:%.*]] = getelementptr [[S:%.*]], %s* [[P:%.*]], i64 [[I:%.*]]
+; CHECK-NEXT:    [[L:%.*]] = load [[S]], %s* [[PP1]], align 4
+; CHECK-NEXT:    ret [[S]] %l
+;
+  %o = mul i64 %i, 12
+  %q = addrspacecast %s* %p to i8 addrspace(2)*
+  %pp = getelementptr inbounds i8, i8 addrspace(2)* %q, i64 %o
+  %r = addrspacecast i8 addrspace(2)* %pp to %s*
+  %l = load %s, %s* %r
+  ret %s %l
+}
+
+define %s @test68_addrspacecast_2(%s* %p, i64 %i) {
+; CHECK-LABEL: @test68_addrspacecast_2(
+; CHECK-NEXT:    [[PP1:%.*]] = getelementptr [[S:%.*]], %s* [[P:%.*]], i64 [[I:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = addrspacecast %s* [[PP1]] to [[S]] addrspace(1)*
+; CHECK-NEXT:    [[L:%.*]] = load [[S]], [[S]] addrspace(1)* [[R]], align 4
+; CHECK-NEXT:    ret [[S]] %l
+;
+  %o = mul i64 %i, 12
+  %q = addrspacecast %s* %p to i8 addrspace(2)*
+  %pp = getelementptr inbounds i8, i8 addrspace(2)* %q, i64 %o
+  %r = addrspacecast i8 addrspace(2)* %pp to %s addrspace(1)*
+  %l = load %s, %s addrspace(1)* %r
+  ret %s %l
+}
+
+define %s @test68_as1(%s addrspace(1)* %p, i32 %i) {
+; CHECK-LABEL: @test68_as1(
+; CHECK-NEXT:    [[PP1:%.*]] = getelementptr [[S:%.*]], [[S]] addrspace(1)* [[P:%.*]], i32 [[I:%.*]]
+; CHECK-NEXT:    [[L:%.*]] = load [[S]], [[S]] addrspace(1)* [[PP1]], align 4
+; CHECK-NEXT:    ret [[S]] %l
+;
+  %o = mul i32 %i, 12
+  %q = bitcast %s addrspace(1)* %p to i8 addrspace(1)*
+  %pp = getelementptr inbounds i8, i8 addrspace(1)* %q, i32 %o
+  %r = bitcast i8 addrspace(1)* %pp to %s addrspace(1)*
+  %l = load %s, %s addrspace(1)* %r
+  ret %s %l
+}
+
+define double @test69(double *%p, i64 %i) {
+; CHECK-LABEL: @test69(
+; CHECK-NEXT:    [[PP1:%.*]] = getelementptr inbounds double, double* [[P:%.*]], i64 [[I:%.*]]
+; CHECK-NEXT:    [[L:%.*]] = load double, double* [[PP1]], align 8
+; CHECK-NEXT:    ret double [[L]]
+;
+  %o = shl nsw i64 %i, 3
+  %q = bitcast double* %p to i8*
+  %pp = getelementptr inbounds i8, i8* %q, i64 %o
+  %r = bitcast i8* %pp to double*
+  %l = load double, double* %r
+  ret double %l
+}
+
+define %s @test70(%s *%p, i64 %i) {
+; CHECK-LABEL: @test70(
+; CHECK-NEXT:    [[O:%.*]] = mul nsw i64 [[I:%.*]], 3
+; CHECK-NEXT:    [[PP1:%.*]] = getelementptr inbounds [[S:%.*]], %s* [[P:%.*]], i64 [[O]]
+; CHECK-NEXT:    [[L:%.*]] = load [[S]], %s* [[PP1]], align 4
+; CHECK-NEXT:    ret [[S]] %l
+;
+  %o = mul nsw i64 %i, 36
+  %q = bitcast %s* %p to i8*
+  %pp = getelementptr inbounds i8, i8* %q, i64 %o
+  %r = bitcast i8* %pp to %s*
+  %l = load %s, %s* %r
+  ret %s %l
+}
+
+define double @test71(double *%p, i64 %i) {
+; CHECK-LABEL: @test71(
+; CHECK-NEXT:    [[O:%.*]] = shl i64 [[I:%.*]], 2
+; CHECK-NEXT:    [[PP1:%.*]] = getelementptr double, double* [[P:%.*]], i64 [[O]]
+; CHECK-NEXT:    [[L:%.*]] = load double, double* [[PP1]], align 8
+; CHECK-NEXT:    ret double [[L]]
+;
+  %o = shl i64 %i, 5
+  %q = bitcast double* %p to i8*
+  %pp = getelementptr i8, i8* %q, i64 %o
+  %r = bitcast i8* %pp to double*
+  %l = load double, double* %r
+  ret double %l
+}
+
+define double @test72(double *%p, i32 %i) {
+; CHECK-LABEL: @test72(
+; CHECK-NEXT:    [[O:%.*]] = sext i32 [[I:%.*]] to i64
+; CHECK-NEXT:    [[PP1:%.*]] = getelementptr inbounds double, double* [[P:%.*]], i64 [[O]]
+; CHECK-NEXT:    [[L:%.*]] = load double, double* [[PP1]], align 8
+; CHECK-NEXT:    ret double [[L]]
+;
+  %so = shl nsw i32 %i, 3
+  %o = sext i32 %so to i64
+  %q = bitcast double* %p to i8*
+  %pp = getelementptr inbounds i8, i8* %q, i64 %o
+  %r = bitcast i8* %pp to double*
+  %l = load double, double* %r
+  ret double %l
+}
+
+define double @test73(double *%p, i128 %i) {
+; CHECK-LABEL: @test73(
+; CHECK-NEXT:    [[I_TR:%.*]] = trunc i128 [[I:%.*]] to i64
+; CHECK-NEXT:    [[PP1:%.*]] = getelementptr double, double* [[P:%.*]], i64 [[I_TR]]
+; CHECK-NEXT:    [[L:%.*]] = load double, double* [[PP1]], align 8
+; CHECK-NEXT:    ret double [[L]]
+;
+  %lo = shl nsw i128 %i, 3
+  %o = trunc i128 %lo to i64
+  %q = bitcast double* %p to i8*
+  %pp = getelementptr inbounds i8, i8* %q, i64 %o
+  %r = bitcast i8* %pp to double*
+  %l = load double, double* %r
+  ret double %l
+}
+
+define double @test74(double *%p, i64 %i) {
+; CHECK-LABEL: @test74(
+; CHECK-NEXT:    [[PP1:%.*]] = getelementptr inbounds double, double* [[P:%.*]], i64 [[I:%.*]]
+; CHECK-NEXT:    [[L:%.*]] = load double, double* [[PP1]], align 8
+; CHECK-NEXT:    ret double [[L]]
+;
+  %q = bitcast double* %p to i64*
+  %pp = getelementptr inbounds i64, i64* %q, i64 %i
+  %r = bitcast i64* %pp to double*
+  %l = load double, double* %r
+  ret double %l
+}
+
+define i32* @test75(i32* %p, i32 %x) {
+; CHECK-LABEL: @test75(
+; CHECK-NEXT:    [[Y:%.*]] = shl i32 [[X:%.*]], 3
+; CHECK-NEXT:    [[Z:%.*]] = sext i32 [[Y]] to i64
+; CHECK-NEXT:    [[Q:%.*]] = bitcast i32* [[P:%.*]] to i8*
+; CHECK-NEXT:    [[R:%.*]] = getelementptr i8, i8* [[Q]], i64 [[Z]]
+; CHECK-NEXT:    [[S:%.*]] = bitcast i8* [[R]] to i32*
+; CHECK-NEXT:    ret i32* [[S]]
+;
+  %y = shl i32 %x, 3
+  %z = sext i32 %y to i64
+  %q = bitcast i32* %p to i8*
+  %r = getelementptr i8, i8* %q, i64 %z
+  %s = bitcast i8* %r to i32*
+  ret i32* %s
+}
+
+define %s @test76(%s *%p, i64 %i, i64 %j) {
+; CHECK-LABEL: @test76(
+; CHECK-NEXT:    [[O2:%.*]] = mul i64 [[I:%.*]], [[J:%.*]]
+; CHECK-NEXT:    [[PP1:%.*]] = getelementptr [[S:%.*]], %s* [[P:%.*]], i64 [[O2]]
+; CHECK-NEXT:    [[L:%.*]] = load [[S]], %s* [[PP1]], align 4
+; CHECK-NEXT:    ret [[S]] %l
+;
+  %o = mul i64 %i, 12
+  %o2 = mul nsw i64 %o, %j
+  %q = bitcast %s* %p to i8*
+  %pp = getelementptr inbounds i8, i8* %q, i64 %o2
+  %r = bitcast i8* %pp to %s*
+  %l = load %s, %s* %r
+  ret %s %l
+}
+
+define %s @test77(%s *%p, i64 %i, i64 %j) {
+; CHECK-LABEL: @test77(
+; CHECK-NEXT:    [[O:%.*]] = mul nsw i64 [[I:%.*]], 3
+; CHECK-NEXT:    [[O2:%.*]] = mul nsw i64 [[O]], [[J:%.*]]
+; CHECK-NEXT:    [[PP1:%.*]] = getelementptr inbounds [[S:%.*]], %s* [[P:%.*]], i64 [[O2]]
+; CHECK-NEXT:    [[L:%.*]] = load [[S]], %s* [[PP1]], align 4
+; CHECK-NEXT:    ret [[S]] %l
+;
+  %o = mul nsw i64 %i, 36
+  %o2 = mul nsw i64 %o, %j
+  %q = bitcast %s* %p to i8*
+  %pp = getelementptr inbounds i8, i8* %q, i64 %o2
+  %r = bitcast i8* %pp to %s*
+  %l = load %s, %s* %r
+  ret %s %l
+}
+
+define %s @test78(%s *%p, i64 %i, i64 %j, i32 %k, i32 %l, i128 %m, i128 %n) {
+; CHECK-LABEL: @test78(
+; CHECK-NEXT:    [[A:%.*]] = mul nsw i32 [[K:%.*]], 3
+; CHECK-NEXT:    [[B:%.*]] = mul nsw i32 [[A]], [[L:%.*]]
+; CHECK-NEXT:    [[C:%.*]] = sext i32 [[B]] to i128
+; CHECK-NEXT:    [[D:%.*]] = mul nsw i128 [[C]], [[M:%.*]]
+; CHECK-NEXT:    [[E:%.*]] = mul i128 [[D]], [[N:%.*]]
+; CHECK-NEXT:    [[F:%.*]] = trunc i128 [[E]] to i64
+; CHECK-NEXT:    [[G:%.*]] = mul i64 [[F]], [[I:%.*]]
+; CHECK-NEXT:    [[H:%.*]] = mul i64 [[G]], [[J:%.*]]
+; CHECK-NEXT:    [[PP1:%.*]] = getelementptr [[S:%.*]], %s* [[P:%.*]], i64 [[H]]
+; CHECK-NEXT:    [[LOAD:%.*]] = load [[S]], %s* [[PP1]], align 4
+; CHECK-NEXT:    ret [[S]] %load
+;
+  %a = mul nsw i32 %k, 36
+  %b = mul nsw i32 %a, %l
+  %c = sext i32 %b to i128
+  %d = mul nsw i128 %c, %m
+  %e = mul i128 %d, %n
+  %f = trunc i128 %e to i64
+  %g = mul nsw i64 %f, %i
+  %h = mul nsw i64 %g, %j
+  %q = bitcast %s* %p to i8*
+  %pp = getelementptr inbounds i8, i8* %q, i64 %h
+  %r = bitcast i8* %pp to %s*
+  %load = load %s, %s* %r
+  ret %s %load
+}
+
+define %s @test79(%s *%p, i64 %i, i32 %j) {
+; CHECK-LABEL: @test79(
+; CHECK-NEXT:    [[TMP1:%.*]] = trunc i64 [[I:%.*]] to i32
+; CHECK-NEXT:    [[B:%.*]] = mul i32 [[TMP1]], 36
+; CHECK-NEXT:    [[C:%.*]] = mul i32 [[B]], [[J:%.*]]
+; CHECK-NEXT:    [[Q:%.*]] = bitcast %s* [[P:%.*]] to i8*
+; CHECK-NEXT:    [[TMP2:%.*]] = sext i32 [[C]] to i64
+; CHECK-NEXT:    [[PP:%.*]] = getelementptr inbounds i8, i8* [[Q]], i64 [[TMP2]]
+; CHECK-NEXT:    [[R:%.*]] = bitcast i8* [[PP]] to %s*
+; CHECK-NEXT:    [[L:%.*]] = load [[S:%.*]], %s* [[R]], align 4
+; CHECK-NEXT:    ret [[S]] %l
+;
+  %a = mul nsw i64 %i, 36
+  %b = trunc i64 %a to i32
+  %c = mul i32 %b, %j
+  %q = bitcast %s* %p to i8*
+  %pp = getelementptr inbounds i8, i8* %q, i32 %c
+  %r = bitcast i8* %pp to %s*
+  %l = load %s, %s* %r
+  ret %s %l
+}
+
+define double @test80([100 x double]* %p, i32 %i) {
+; CHECK-LABEL: @test80(
+; CHECK-NEXT:    [[TMP1:%.*]] = sext i32 [[I:%.*]] to i64
+; CHECK-NEXT:    [[PP1:%.*]] = getelementptr [100 x double], [100 x double]* [[P:%.*]], i64 0, i64 [[TMP1]]
+; CHECK-NEXT:    [[L:%.*]] = load double, double* [[PP1]], align 8
+; CHECK-NEXT:    ret double [[L]]
+;
+  %t = shl nsw i32 %i, 3
+  %q = bitcast [100 x double]* %p to i8*
+  %pp = getelementptr i8, i8* %q, i32 %t
+  %r = bitcast i8* %pp to double*
+  %l = load double, double* %r
+  ret double %l
+}
+
+define double @test80_addrspacecast([100 x double] addrspace(1)* %p, i32 %i) {
+; CHECK-LABEL: @test80_addrspacecast(
+; CHECK-NEXT:    [[PP1:%.*]] = getelementptr [100 x double], [100 x double] addrspace(1)* [[P:%.*]], i32 0, i32 [[I:%.*]]
+; CHECK-NEXT:    [[L:%.*]] = load double, double addrspace(1)* [[PP1]], align 8
+; CHECK-NEXT:    ret double [[L]]
+;
+  %t = shl nsw i32 %i, 3
+  %q = addrspacecast [100 x double] addrspace(1)* %p to i8 addrspace(2)*
+  %pp = getelementptr i8, i8 addrspace(2)* %q, i32 %t
+  %r = addrspacecast i8 addrspace(2)* %pp to double addrspace(1)*
+  %l = load double, double addrspace(1)* %r
+  ret double %l
+}
+
+define double @test80_addrspacecast_2([100 x double] addrspace(1)* %p, i32 %i) {
+; CHECK-LABEL: @test80_addrspacecast_2(
+; CHECK-NEXT:    [[PP1:%.*]] = getelementptr [100 x double], [100 x double] addrspace(1)* [[P:%.*]], i32 0, i32 [[I:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = addrspacecast double addrspace(1)* [[PP1]] to double addrspace(3)*
+; CHECK-NEXT:    [[L:%.*]] = load double, double addrspace(3)* [[R]], align 8
+; CHECK-NEXT:    ret double [[L]]
+;
+  %t = shl nsw i32 %i, 3
+  %q = addrspacecast [100 x double] addrspace(1)* %p to i8 addrspace(2)*
+  %pp = getelementptr i8, i8 addrspace(2)* %q, i32 %t
+  %r = addrspacecast i8 addrspace(2)* %pp to double addrspace(3)*
+  %l = load double, double addrspace(3)* %r
+  ret double %l
+}
+
+define double @test80_as1([100 x double] addrspace(1)* %p, i16 %i) {
+; CHECK-LABEL: @test80_as1(
+; CHECK-NEXT:    [[TMP1:%.*]] = sext i16 [[I:%.*]] to i32
+; CHECK-NEXT:    [[PP1:%.*]] = getelementptr [100 x double], [100 x double] addrspace(1)* [[P:%.*]], i32 0, i32 [[TMP1]]
+; CHECK-NEXT:    [[L:%.*]] = load double, double addrspace(1)* [[PP1]], align 8
+; CHECK-NEXT:    ret double [[L]]
+;
+  %t = shl nsw i16 %i, 3
+  %q = bitcast [100 x double] addrspace(1)* %p to i8 addrspace(1)*
+  %pp = getelementptr i8, i8 addrspace(1)* %q, i16 %t
+  %r = bitcast i8 addrspace(1)* %pp to double addrspace(1)*
+  %l = load double, double addrspace(1)* %r
+  ret double %l
+}
+
+define double @test81(double *%p, float %f) {
+; CHECK-LABEL: @test81(
+; CHECK-NEXT:    [[I:%.*]] = fptosi float [[F:%.*]] to i64
+; CHECK-NEXT:    [[Q:%.*]] = bitcast double* [[P:%.*]] to i8*
+; CHECK-NEXT:    [[PP:%.*]] = getelementptr i8, i8* [[Q]], i64 [[I]]
+; CHECK-NEXT:    [[R:%.*]] = bitcast i8* [[PP]] to double*
+; CHECK-NEXT:    [[L:%.*]] = load double, double* [[R]], align 8
+; CHECK-NEXT:    ret double [[L]]
+;
+  %i = fptosi float %f to i64
+  %q = bitcast double* %p to i8*
+  %pp = getelementptr i8, i8* %q, i64 %i
+  %r = bitcast i8* %pp to double*
+  %l = load double, double* %r
+  ret double %l
+}
+
+define i64 @test82(i64 %A) {
+; CHECK-LABEL: @test82(
+; CHECK-NEXT:    [[TMP1:%.*]] = shl i64 [[A:%.*]], 1
+; CHECK-NEXT:    [[E:%.*]] = and i64 [[TMP1]], 4294966784
+; CHECK-NEXT:    ret i64 [[E]]
+;
+  %B = trunc i64 %A to i32
+  %C = lshr i32 %B, 8
+  %D = shl i32 %C, 9
+  %E = zext i32 %D to i64
+  ret i64 %E
+}
+
+; PR15959
+define i64 @test83(i16 %a, i64 %k) {
+; CHECK-LABEL: @test83(
+; CHECK-NEXT:    [[CONV:%.*]] = sext i16 [[A:%.*]] to i32
+; CHECK-NEXT:    [[TMP1:%.*]] = trunc i64 [[K:%.*]] to i32
+; CHECK-NEXT:    [[SH_PROM:%.*]] = add i32 [[TMP1]], -1
+; CHECK-NEXT:    [[SHL:%.*]] = shl i32 [[CONV]], [[SH_PROM]]
+; CHECK-NEXT:    [[SH_PROM1:%.*]] = zext i32 [[SHL]] to i64
+; CHECK-NEXT:    ret i64 [[SH_PROM1]]
+;
+  %conv = sext i16 %a to i32
+  %sub = add nsw i64 %k, -1
+  %sh_prom = trunc i64 %sub to i32
+  %shl = shl i32 %conv, %sh_prom
+  %sh_prom1 = zext i32 %shl to i64
+  ret i64 %sh_prom1
+}
+
+define i8 @test84(i32 %a) {
+; CHECK-LABEL: @test84(
+; CHECK-NEXT:    [[ADD:%.*]] = add i32 [[A:%.*]], 2130706432
+; CHECK-NEXT:    [[SHR:%.*]] = lshr exact i32 [[ADD]], 23
+; CHECK-NEXT:    [[TRUNC:%.*]] = trunc i32 [[SHR]] to i8
+; CHECK-NEXT:    ret i8 [[TRUNC]]
+;
+  %add = add nsw i32 %a, -16777216
+  %shr = lshr exact i32 %add, 23
+  %trunc = trunc i32 %shr to i8
+  ret i8 %trunc
+}
+
+define i8 @test85(i32 %a) {
+; CHECK-LABEL: @test85(
+; CHECK-NEXT:    [[ADD:%.*]] = add i32 [[A:%.*]], 2130706432
+; CHECK-NEXT:    [[SHR:%.*]] = lshr exact i32 [[ADD]], 23
+; CHECK-NEXT:    [[TRUNC:%.*]] = trunc i32 [[SHR]] to i8
+; CHECK-NEXT:    ret i8 [[TRUNC]]
+;
+  %add = add nuw i32 %a, -16777216
+  %shr = lshr exact i32 %add, 23
+  %trunc = trunc i32 %shr to i8
+  ret i8 %trunc
+}
+
+define i16 @test86(i16 %v) {
+; CHECK-LABEL: @test86(
+; CHECK-NEXT:    [[TMP1:%.*]] = ashr i16 [[V:%.*]], 4
+; CHECK-NEXT:    ret i16 [[TMP1]]
+;
+  %a = sext i16 %v to i32
+  %s = ashr i32 %a, 4
+  %t = trunc i32 %s to i16
+  ret i16 %t
+}
+
+define i16 @test87(i16 %v) {
+; CHECK-LABEL: @test87(
+; CHECK-NEXT:    [[TMP1:%.*]] = ashr i16 [[V:%.*]], 12
+; CHECK-NEXT:    ret i16 [[TMP1]]
+;
+  %c = sext i16 %v to i32
+  %m = mul nsw i32 %c, 16
+  %a = ashr i32 %m, 16
+  %t = trunc i32 %a to i16
+  ret i16 %t
+}
+
+define i16 @test88(i16 %v) {
+; CHECK-LABEL: @test88(
+; CHECK-NEXT:    [[TMP1:%.*]] = ashr i16 [[V:%.*]], 15
+; CHECK-NEXT:    ret i16 [[TMP1]]
+;
+  %a = sext i16 %v to i32
+  %s = ashr i32 %a, 18
+  %t = trunc i32 %s to i16
+  ret i16 %t
+}
+
+define i32 @PR21388(i32* %v) {
+; CHECK-LABEL: @PR21388(
+; CHECK-NEXT:    [[ICMP:%.*]] = icmp slt i32* [[V:%.*]], null
+; CHECK-NEXT:    [[SEXT:%.*]] = sext i1 [[ICMP]] to i32
+; CHECK-NEXT:    ret i32 [[SEXT]]
+;
+  %icmp = icmp slt i32* %v, null
+  %sext = sext i1 %icmp to i32
+  ret i32 %sext
+}
+
+define float @sitofp_zext(i16 %a) {
+; CHECK-LABEL: @sitofp_zext(
+; CHECK-NEXT:    [[SITOFP:%.*]] = uitofp i16 [[A:%.*]] to float
+; CHECK-NEXT:    ret float [[SITOFP]]
+;
+  %zext = zext i16 %a to i32
+  %sitofp = sitofp i32 %zext to float
+  ret float %sitofp
+}
+
+define i1 @PR23309(i32 %A, i32 %B) {
+; CHECK-LABEL: @PR23309(
+; CHECK-NEXT:    [[SUB:%.*]] = sub i32 [[A:%.*]], [[B:%.*]]
+; CHECK-NEXT:    [[TMP1:%.*]] = and i32 [[SUB]], 1
+; CHECK-NEXT:    [[TRUNC:%.*]] = icmp ne i32 [[TMP1]], 0
+; CHECK-NEXT:    ret i1 [[TRUNC]]
+;
+  %add = add i32 %A, -4
+  %sub = sub nsw i32 %add, %B
+  %trunc = trunc i32 %sub to i1
+  ret i1 %trunc
+}
+
+define i1 @PR23309v2(i32 %A, i32 %B) {
+; CHECK-LABEL: @PR23309v2(
+; CHECK-NEXT:    [[SUB:%.*]] = add i32 [[A:%.*]], [[B:%.*]]
+; CHECK-NEXT:    [[TMP1:%.*]] = and i32 [[SUB]], 1
+; CHECK-NEXT:    [[TRUNC:%.*]] = icmp ne i32 [[TMP1]], 0
+; CHECK-NEXT:    ret i1 [[TRUNC]]
+;
+  %add = add i32 %A, -4
+  %sub = add nuw i32 %add, %B
+  %trunc = trunc i32 %sub to i1
+  ret i1 %trunc
+}
+
+define i16 @PR24763(i8 %V) {
+; CHECK-LABEL: @PR24763(
+; CHECK-NEXT:    [[L:%.*]] = ashr i8 [[V:%.*]], 1
+; CHECK-NEXT:    [[T:%.*]] = sext i8 [[L]] to i16
+; CHECK-NEXT:    ret i16 [[T]]
+;
+  %conv = sext i8 %V to i32
+  %l = lshr i32 %conv, 1
+  %t = trunc i32 %l to i16
+  ret i16 %t
+}
+
+define i64 @PR28745() {
+; CHECK-LABEL: @PR28745(
+; CHECK-NEXT:    ret i64 1
+;
+  %b = zext i32 extractvalue ({ i32 } select (i1 icmp eq (i16 extractelement (<2 x i16> bitcast (<1 x i32> <i32 1> to <2 x i16>), i32 0), i16 0), { i32 } { i32 1 }, { i32 } zeroinitializer), 0) to i64
+  ret i64 %b
+}
+
+define i32 @test89() {
+; CHECK-LABEL: @test89(
+; CHECK-NEXT:    ret i32 393216
+;
+  ret i32 bitcast (<2 x i16> <i16 6, i16 undef> to i32)
+}
+
+define <2 x i32> @test90() {
+; CHECK-LABEL: @test90(
+; CHECK-NEXT:    ret <2 x i32> <i32 0, i32 15360>
+;
+  %t6 = bitcast <4 x half> <half undef, half undef, half undef, half 0xH3C00> to <2 x i32>
+  ret <2 x i32> %t6
+}
+
+; Do not optimize to ashr i64 (shift by 48 > 96 - 64)
+define i64 @test91(i64 %A) {
+; CHECK-LABEL: @test91(
+; CHECK-NEXT:    [[B:%.*]] = sext i64 [[A:%.*]] to i96
+; CHECK-NEXT:    [[C:%.*]] = lshr i96 [[B]], 48
+; CHECK-NEXT:    [[D:%.*]] = trunc i96 [[C]] to i64
+; CHECK-NEXT:    ret i64 [[D]]
+;
+  %B = sext i64 %A to i96
+  %C = lshr i96 %B, 48
+  %D = trunc i96 %C to i64
+  ret i64 %D
+}
+
+; Do optimize to ashr i64 (shift by 32 <= 96 - 64)
+define i64 @test92(i64 %A) {
+; CHECK-LABEL: @test92(
+; CHECK-NEXT:    [[TMP1:%.*]] = ashr i64 [[A:%.*]], 32
+; CHECK-NEXT:    ret i64 [[TMP1]]
+;
+  %B = sext i64 %A to i96
+  %C = lshr i96 %B, 32
+  %D = trunc i96 %C to i64
+  ret i64 %D
+}
+
+; When optimizing to ashr i32, don't shift by more than 31.
+define i32 @test93(i32 %A) {
+; CHECK-LABEL: @test93(
+; CHECK-NEXT:    [[TMP1:%.*]] = ashr i32 [[A:%.*]], 31
+; CHECK-NEXT:    ret i32 [[TMP1]]
+;
+  %B = sext i32 %A to i96
+  %C = lshr i96 %B, 64
+  %D = trunc i96 %C to i32
+  ret i32 %D
+}
+
+; The following four tests sext + lshr + trunc patterns.
+; PR33078
+
+define i8 @pr33078_1(i8 %A) {
+; CHECK-LABEL: @pr33078_1(
+; CHECK-NEXT:    [[TMP1:%.*]] = ashr i8 [[A:%.*]], 7
+; CHECK-NEXT:    ret i8 [[TMP1]]
+;
+  %B = sext i8 %A to i16
+  %C = lshr i16 %B, 8
+  %D = trunc i16 %C to i8
+  ret i8 %D
+}
+
+define i12 @pr33078_2(i8 %A) {
+; CHECK-LABEL: @pr33078_2(
+; CHECK-NEXT:    [[C:%.*]] = ashr i8 [[A:%.*]], 4
+; CHECK-NEXT:    [[D:%.*]] = sext i8 [[C]] to i12
+; CHECK-NEXT:    ret i12 [[D]]
+;
+  %B = sext i8 %A to i16
+  %C = lshr i16 %B, 4
+  %D = trunc i16 %C to i12
+  ret i12 %D
+}
+
+define i4 @pr33078_3(i8 %A) {
+; CHECK-LABEL: @pr33078_3(
+; CHECK-NEXT:    [[B:%.*]] = sext i8 [[A:%.*]] to i16
+; CHECK-NEXT:    [[C:%.*]] = lshr i16 [[B]], 12
+; CHECK-NEXT:    [[D:%.*]] = trunc i16 [[C]] to i4
+; CHECK-NEXT:    ret i4 [[D]]
+;
+  %B = sext i8 %A to i16
+  %C = lshr i16 %B, 12
+  %D = trunc i16 %C to i4
+  ret i4 %D
+}
+
+define i8 @pr33078_4(i3 %x) {
+; Don't turn this in an `ashr`. This was getting miscompiled
+; CHECK-LABEL: @pr33078_4(
+; CHECK-NEXT:    [[B:%.*]] = sext i3 [[X:%.*]] to i16
+; CHECK-NEXT:    [[C:%.*]] = lshr i16 [[B]], 13
+; CHECK-NEXT:    [[D:%.*]] = trunc i16 [[C]] to i8
+; CHECK-NEXT:    ret i8 [[D]]
+;
+  %B = sext i3 %x to i16
+  %C = lshr i16 %B, 13
+  %D = trunc i16 %C to i8
+  ret i8 %D
+}
+
+; (sext (xor (cmp), -1)) -> (sext (!cmp))
+define i64 @test94(i32 %a) {
+; CHECK-LABEL: @test94(
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp ne i32 [[A:%.*]], -2
+; CHECK-NEXT:    [[TMP2:%.*]] = sext i1 [[TMP1]] to i64
+; CHECK-NEXT:    ret i64 [[TMP2]]
+;
+  %1 = icmp eq i32 %a, -2
+  %2 = sext i1 %1 to i8
+  %3 = xor i8 %2, -1
+  %4 = sext i8 %3 to i64
+  ret i64 %4
+}
+
+; We should be able to remove the zext and trunc here.
+define i32 @test95(i32 %x) {
+; CHECK-LABEL: @test95(
+; CHECK-NEXT:    [[TMP1:%.*]] = lshr i32 [[X:%.*]], 6
+; CHECK-NEXT:    [[TMP2:%.*]] = and i32 [[TMP1]], 2
+; CHECK-NEXT:    [[TMP3:%.*]] = or i32 [[TMP2]], 40
+; CHECK-NEXT:    ret i32 [[TMP3]]
+;
+  %1 = trunc i32 %x to i8
+  %2 = lshr i8 %1, 6
+  %3 = and i8 %2, 2
+  %4 = or i8 %3, 40
+  %5 = zext i8 %4 to i32
+  ret i32 %5
+}

Added: llvm/trunk/test/Transforms/InstCombine/cast_phi.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/cast_phi.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/cast_phi.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/cast_phi.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,135 @@
+; RUN: opt < %s -instcombine -S | FileCheck %s
+; RUN: opt < %s -passes=instcombine -S | FileCheck %s
+
+define void @MainKernel(i32 %iNumSteps, i32 %tid, i32 %base) {
+; CHECK-NOT: bitcast
+
+  %callA = alloca [258 x float], align 4
+  %callB = alloca [258 x float], align 4
+  %conv.i = uitofp i32 %iNumSteps to float
+  %1 = bitcast float %conv.i to i32
+  %conv.i12 = zext i32 %tid to i64
+  %arrayidx3 = getelementptr inbounds [258 x float], [258 x float]* %callA, i64 0, i64 %conv.i12
+  %2 = bitcast float* %arrayidx3 to i32*
+  store i32 %1, i32* %2, align 4
+  %arrayidx6 = getelementptr inbounds [258 x float], [258 x float]* %callB, i64 0, i64 %conv.i12
+  %3 = bitcast float* %arrayidx6 to i32*
+  store i32 %1, i32* %3, align 4
+  %cmp7 = icmp eq i32 %tid, 0
+  br i1 %cmp7, label %.bb1, label %.bb2
+
+.bb1:
+  %arrayidx10 = getelementptr inbounds [258 x float], [258 x float]* %callA, i64 0, i64 256
+  store float %conv.i, float* %arrayidx10, align 4
+  %arrayidx11 = getelementptr inbounds [258 x float], [258 x float]* %callB, i64 0, i64 256
+  store float 0.000000e+00, float* %arrayidx11, align 4
+  br label %.bb2
+
+.bb2:
+  %cmp135 = icmp sgt i32 %iNumSteps, 0
+  br i1 %cmp135, label %.bb3, label %.bb8
+
+; CHECK-LABEL: .bb3
+; CHECK: phi float
+; CHECK: phi float
+; CHECK: phi i32 {{.*}} [ %iNumSteps
+; CHECK-NOT: rA.sroa.[0-9].[0-9] = phi i32
+; CHECK-NOT: phi float
+; CHECK-NOT: phi i32
+; CHECK-LABEL: .bb4
+
+.bb3:
+  %rA.sroa.8.0 = phi i32 [ %rA.sroa.8.2, %.bb12 ], [ %1, %.bb2 ]
+  %rA.sroa.0.0 = phi i32 [ %rA.sroa.0.2, %.bb12 ], [ %1, %.bb2 ]
+  %i12.06 = phi i32 [ %sub, %.bb12 ], [ %iNumSteps, %.bb2 ]
+  %4 = icmp ugt i32 %i12.06, %base
+  %add = add i32 %i12.06, 1
+  %conv.i9 = sext i32 %add to i64
+  %arrayidx20 = getelementptr inbounds [258 x float], [258 x float]* %callA, i64 0, i64 %conv.i9
+  %5 = bitcast float* %arrayidx20 to i32*
+  %arrayidx24 = getelementptr inbounds [258 x float], [258 x float]* %callB, i64 0, i64 %conv.i9
+  %6 = bitcast float* %arrayidx24 to i32*
+  %cmp40 = icmp ult i32 %i12.06, %base
+  br i1 %4, label %.bb4, label %.bb5
+
+.bb4:
+  %7 = load i32, i32* %5, align 4
+  %8 = load i32, i32* %6, align 4
+  %9 = bitcast i32 %8 to float
+  %10 = bitcast i32 %7 to float
+  %add33 = fadd float %9, %10
+  %11 = bitcast i32 %rA.sroa.8.0 to float
+  %add33.1 = fadd float %add33, %11
+  %12 = bitcast float %add33.1 to i32
+  %13 = bitcast i32 %rA.sroa.0.0 to float
+  %add33.2 = fadd float %add33.1, %13
+  %14 = bitcast float %add33.2 to i32
+  br label %.bb5
+
+; CHECK-LABEL: .bb5
+; CHECK: phi float
+; CHECK: phi float
+; CHECK-NOT: rA.sroa.[0-9].[0-9] = phi i32
+; CHECK-NOT: phi float
+; CHECK-NOT: phi i32
+; CHECK-LABEL: .bb6
+
+.bb5:
+  %rA.sroa.8.1 = phi i32 [ %12, %.bb4 ], [ %rA.sroa.8.0, %.bb3 ]
+  %rA.sroa.0.1 = phi i32 [ %14, %.bb4 ], [ %rA.sroa.0.0, %.bb3 ]
+  br i1 %cmp40, label %.bb6, label %.bb7
+
+.bb6:
+  store i32 %rA.sroa.0.1, i32* %2, align 4
+  store i32 %rA.sroa.8.1, i32* %3, align 4
+  br label %.bb7
+
+.bb7:
+  br i1 %4, label %.bb9, label %.bb10
+
+.bb8:
+  ret void
+
+.bb9:
+  %15 = load i32, i32* %5, align 4
+  %16 = load i32, i32* %6, align 4
+  %17 = bitcast i32 %16 to float
+  %18 = bitcast i32 %15 to float
+  %add33.112 = fadd float %17, %18
+  %19 = bitcast i32 %rA.sroa.8.1 to float
+  %add33.1.1 = fadd float %add33.112, %19
+  %20 = bitcast float %add33.1.1 to i32
+  %21 = bitcast i32 %rA.sroa.0.1 to float
+  %add33.2.1 = fadd float %add33.1.1, %21
+  %22 = bitcast float %add33.2.1 to i32
+  br label %.bb10
+
+; CHECK-LABEL: .bb10
+; CHECK: phi float
+; CHECK: phi float
+; CHECK-NOT: rA.sroa.[0-9].[0-9] = phi i32
+; CHECK-NOT: phi float
+; CHECK-NOT: phi i32
+; CHECK-LABEL: .bb11
+
+.bb10:
+  %rA.sroa.8.2 = phi i32 [ %20, %.bb9 ], [ %rA.sroa.8.1, %.bb7 ]
+  %rA.sroa.0.2 = phi i32 [ %22, %.bb9 ], [ %rA.sroa.0.1, %.bb7 ]
+  br i1 %cmp40, label %.bb11, label %.bb12
+
+; CHECK-LABEL: .bb11
+; CHECK: store float
+; CHECK: store float
+; CHECK-NOT: store i32 %rA.sroa.[0-9].[0-9]
+; CHECK-LABEL: .bb12
+
+.bb11:
+  store i32 %rA.sroa.0.2, i32* %2, align 4
+  store i32 %rA.sroa.8.2, i32* %3, align 4
+  br label %.bb12
+
+.bb12:
+  %sub = add i32 %i12.06, -4
+  %cmp13 = icmp sgt i32 %sub, 0
+  br i1 %cmp13, label %.bb3, label %.bb8
+}

Added: llvm/trunk/test/Transforms/InstCombine/cast_ptr.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/cast_ptr.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/cast_ptr.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/cast_ptr.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,129 @@
+; Tests to make sure elimination of casts is working correctly
+; RUN: opt < %s -instcombine -S | FileCheck %s
+
+target datalayout = "p:32:32-p1:32:32-p2:16:16"
+
+ at global = global i8 0
+
+; This shouldn't convert to getelementptr because the relationship
+; between the arithmetic and the layout of allocated memory is
+; entirely unknown.
+; CHECK-LABEL: @test1(
+; CHECK: ptrtoint
+; CHECK: add
+; CHECK: inttoptr
+define i8* @test1(i8* %t) {
+        %tmpc = ptrtoint i8* %t to i32          ; <i32> [#uses=1]
+        %tmpa = add i32 %tmpc, 32               ; <i32> [#uses=1]
+        %tv = inttoptr i32 %tmpa to i8*         ; <i8*> [#uses=1]
+        ret i8* %tv
+}
+
+; These casts should be folded away.
+; CHECK-LABEL: @test2(
+; CHECK: icmp eq i8* %a, %b
+define i1 @test2(i8* %a, i8* %b) {
+        %tmpa = ptrtoint i8* %a to i32          ; <i32> [#uses=1]
+        %tmpb = ptrtoint i8* %b to i32          ; <i32> [#uses=1]
+        %r = icmp eq i32 %tmpa, %tmpb           ; <i1> [#uses=1]
+        ret i1 %r
+}
+
+; These casts should be folded away.
+; CHECK-LABEL: @test2_as2_same_int(
+; CHECK: icmp eq i8 addrspace(2)* %a, %b
+define i1 @test2_as2_same_int(i8 addrspace(2)* %a, i8 addrspace(2)* %b) {
+  %tmpa = ptrtoint i8 addrspace(2)* %a to i16
+  %tmpb = ptrtoint i8 addrspace(2)* %b to i16
+  %r = icmp eq i16 %tmpa, %tmpb
+  ret i1 %r
+}
+
+; These casts should be folded away.
+; CHECK-LABEL: @test2_as2_larger(
+; CHECK: icmp eq i8 addrspace(2)* %a, %b
+define i1 @test2_as2_larger(i8 addrspace(2)* %a, i8 addrspace(2)* %b) {
+  %tmpa = ptrtoint i8 addrspace(2)* %a to i32
+  %tmpb = ptrtoint i8 addrspace(2)* %b to i32
+  %r = icmp eq i32 %tmpa, %tmpb
+  ret i1 %r
+}
+
+; These casts should not be folded away.
+; CHECK-LABEL: @test2_diff_as
+; CHECK: icmp sge i32 %i0, %i1
+define i1 @test2_diff_as(i8* %p, i8 addrspace(1)* %q) {
+  %i0 = ptrtoint i8* %p to i32
+  %i1 = ptrtoint i8 addrspace(1)* %q to i32
+  %r0 = icmp sge i32 %i0, %i1
+  ret i1 %r0
+}
+
+; These casts should not be folded away.
+; CHECK-LABEL: @test2_diff_as_global
+; CHECK: icmp sge i32 %i1
+define i1 @test2_diff_as_global(i8 addrspace(1)* %q) {
+  %i0 = ptrtoint i8* @global to i32
+  %i1 = ptrtoint i8 addrspace(1)* %q to i32
+  %r0 = icmp sge i32 %i1, %i0
+  ret i1 %r0
+}
+
+; These casts should also be folded away.
+; CHECK-LABEL: @test3(
+; CHECK: icmp eq i8* %a, @global
+define i1 @test3(i8* %a) {
+        %tmpa = ptrtoint i8* %a to i32
+        %r = icmp eq i32 %tmpa, ptrtoint (i8* @global to i32)
+        ret i1 %r
+}
+
+define i1 @test4(i32 %A) {
+  %B = inttoptr i32 %A to i8*
+  %C = icmp eq i8* %B, null
+  ret i1 %C
+; CHECK-LABEL: @test4(
+; CHECK-NEXT: %C = icmp eq i32 %A, 0
+; CHECK-NEXT: ret i1 %C
+}
+
+define i1 @test4_as2(i16 %A) {
+; CHECK-LABEL: @test4_as2(
+; CHECK-NEXT: %C = icmp eq i16 %A, 0
+; CHECK-NEXT: ret i1 %C
+  %B = inttoptr i16 %A to i8 addrspace(2)*
+  %C = icmp eq i8 addrspace(2)* %B, null
+  ret i1 %C
+}
+
+
+; Pulling the cast out of the load allows us to eliminate the load, and then
+; the whole array.
+
+        %op = type { float }
+        %unop = type { i32 }
+ at Array = internal constant [1 x %op* (%op*)*] [ %op* (%op*)* @foo ]             ; <[1 x %op* (%op*)*]*> [#uses=1]
+
+declare %op* @foo(%op* %X)
+
+define %unop* @test5(%op* %O) {
+        %tmp = load %unop* (%op*)*, %unop* (%op*)** bitcast ([1 x %op* (%op*)*]* @Array to %unop* (%op*)**); <%unop* (%op*)*> [#uses=1]
+        %tmp.2 = call %unop* %tmp( %op* %O )            ; <%unop*> [#uses=1]
+        ret %unop* %tmp.2
+; CHECK-LABEL: @test5(
+; CHECK: call %op* @foo(%op* %O)
+}
+
+
+
+; InstCombine can not 'load (cast P)' -> cast (load P)' if the cast changes
+; the address space.
+
+define i8 @test6(i8 addrspace(1)* %source) {
+entry:
+  %arrayidx223 = addrspacecast i8 addrspace(1)* %source to i8*
+  %tmp4 = load i8, i8* %arrayidx223
+  ret i8 %tmp4
+; CHECK-LABEL: @test6(
+; CHECK: load i8, i8* %arrayidx223
+}

Added: llvm/trunk/test/Transforms/InstCombine/ceil.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/ceil.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/ceil.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/ceil.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,56 @@
+; RUN: opt -S -instcombine < %s | FileCheck %s
+
+declare float @llvm.ceil.f32(float) #0
+declare double @llvm.ceil.f64(double) #0
+declare <4 x float> @llvm.ceil.v4f32(<4 x float>) #0
+
+; CHECK-LABEL: @constant_fold_ceil_f32_01
+; CHECK-NEXT: ret float 1.000000e+00
+define float @constant_fold_ceil_f32_01() #0 {
+  %x = call float @llvm.ceil.f32(float 1.00) #0
+  ret float %x
+}
+
+; CHECK-LABEL: @constant_fold_ceil_f32_02
+; CHECK-NEXT: ret float 2.000000e+00
+define float @constant_fold_ceil_f32_02() #0 {
+  %x = call float @llvm.ceil.f32(float 1.25) #0
+  ret float %x
+}
+
+; CHECK-LABEL: @constant_fold_ceil_f32_03
+; CHECK-NEXT: ret float -1.000000e+00
+define float @constant_fold_ceil_f32_03() #0 {
+  %x = call float @llvm.ceil.f32(float -1.25) #0
+  ret float %x
+}
+
+; CHECK-LABEL: @constant_fold_ceil_v4f32_01
+; CHECK-NEXT: ret <4 x float> <float 1.000000e+00, float 2.000000e+00, float -1.000000e+00, float -1.000000e+00>
+define <4 x float> @constant_fold_ceil_v4f32_01() #0 {
+  %x = call <4 x float> @llvm.ceil.v4f32(<4 x float> <float 1.00, float 1.25, float -1.25, float -1.00>)
+  ret <4 x float> %x
+}
+
+; CHECK-LABEL: @constant_fold_ceil_f64_01
+; CHECK-NEXT: ret double 1.000000e+00
+define double @constant_fold_ceil_f64_01() #0 {
+  %x = call double @llvm.ceil.f64(double 1.0) #0
+  ret double %x
+}
+
+; CHECK-LABEL: @constant_fold_ceil_f64_02
+; CHECK-NEXT: ret double 2.000000e+00
+define double @constant_fold_ceil_f64_02() #0 {
+  %x = call double @llvm.ceil.f64(double 1.3) #0
+  ret double %x
+}
+
+; CHECK-LABEL: @constant_fold_ceil_f64_03
+; CHECK-NEXT: ret double -1.000000e+00
+define double @constant_fold_ceil_f64_03() #0 {
+  %x = call double @llvm.ceil.f64(double -1.75) #0
+  ret double %x
+}
+
+attributes #0 = { nounwind readnone }

Added: llvm/trunk/test/Transforms/InstCombine/clamp-to-minmax.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/clamp-to-minmax.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/clamp-to-minmax.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/clamp-to-minmax.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,607 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt < %s -instcombine -S | FileCheck %s
+
+; (X < C1) ? C1 : MIN(X, C2)
+define float @clamp_float_fast_ordered_strict_maxmin(float %x) {
+;
+; CHECK-LABEL: @clamp_float_fast_ordered_strict_maxmin(
+; CHECK-NEXT:    [[CMP2:%.*]] = fcmp fast olt float [[X:%.*]], 2.550000e+02
+; CHECK-NEXT:    [[MIN:%.*]] = select i1 [[CMP2]], float [[X]], float 2.550000e+02
+; CHECK-NEXT:    [[DOTINV:%.*]] = fcmp fast oge float [[MIN]], 1.000000e+00
+; CHECK-NEXT:    [[R1:%.*]] = select i1 [[DOTINV]], float [[MIN]], float 1.000000e+00
+; CHECK-NEXT:    ret float [[R1]]
+;
+  %cmp2 = fcmp fast olt float %x, 255.0
+  %min = select i1 %cmp2, float %x, float 255.0
+  %cmp1 = fcmp fast olt float %x, 1.0
+  %r = select i1 %cmp1, float 1.0, float %min
+  ret float %r
+}
+
+; (X <= C1) ? C1 : MIN(X, C2)
+define float @clamp_float_fast_ordered_nonstrict_maxmin(float %x) {
+;
+; CHECK-LABEL: @clamp_float_fast_ordered_nonstrict_maxmin(
+; CHECK-NEXT:    [[CMP2:%.*]] = fcmp fast olt float [[X:%.*]], 2.550000e+02
+; CHECK-NEXT:    [[MIN:%.*]] = select i1 [[CMP2]], float [[X]], float 2.550000e+02
+; CHECK-NEXT:    [[DOTINV:%.*]] = fcmp fast oge float [[MIN]], 1.000000e+00
+; CHECK-NEXT:    [[R1:%.*]] = select i1 [[DOTINV]], float [[MIN]], float 1.000000e+00
+; CHECK-NEXT:    ret float [[R1]]
+;
+  %cmp2 = fcmp fast olt float %x, 255.0
+  %min = select i1 %cmp2, float %x, float 255.0
+  %cmp1 = fcmp fast ole float %x, 1.0
+  %r = select i1 %cmp1, float 1.0, float %min
+  ret float %r
+}
+
+; (X > C1) ? C1 : MAX(X, C2)
+define float @clamp_float_fast_ordered_strict_minmax(float %x) {
+;
+; CHECK-LABEL: @clamp_float_fast_ordered_strict_minmax(
+; CHECK-NEXT:    [[CMP2:%.*]] = fcmp fast ogt float [[X:%.*]], 1.000000e+00
+; CHECK-NEXT:    [[MAX:%.*]] = select i1 [[CMP2]], float [[X]], float 1.000000e+00
+; CHECK-NEXT:    [[DOTINV:%.*]] = fcmp fast ole float [[MAX]], 2.550000e+02
+; CHECK-NEXT:    [[R1:%.*]] = select i1 [[DOTINV]], float [[MAX]], float 2.550000e+02
+; CHECK-NEXT:    ret float [[R1]]
+;
+  %cmp2 = fcmp fast ogt float %x, 1.0
+  %max = select i1 %cmp2, float %x, float 1.0
+  %cmp1 = fcmp fast ogt float %x, 255.0
+  %r = select i1 %cmp1, float 255.0, float %max
+  ret float %r
+}
+
+; (X >= C1) ? C1 : MAX(X, C2)
+define float @clamp_float_fast_ordered_nonstrict_minmax(float %x) {
+;
+; CHECK-LABEL: @clamp_float_fast_ordered_nonstrict_minmax(
+; CHECK-NEXT:    [[CMP2:%.*]] = fcmp fast ogt float [[X:%.*]], 1.000000e+00
+; CHECK-NEXT:    [[MAX:%.*]] = select i1 [[CMP2]], float [[X]], float 1.000000e+00
+; CHECK-NEXT:    [[DOTINV:%.*]] = fcmp fast ole float [[MAX]], 2.550000e+02
+; CHECK-NEXT:    [[R1:%.*]] = select i1 [[DOTINV]], float [[MAX]], float 2.550000e+02
+; CHECK-NEXT:    ret float [[R1]]
+;
+  %cmp2 = fcmp fast ogt float %x, 1.0
+  %max = select i1 %cmp2, float %x, float 1.0
+  %cmp1 = fcmp fast oge float %x, 255.0
+  %r = select i1 %cmp1, float 255.0, float %max
+  ret float %r
+}
+
+
+; The same for unordered
+
+; (X < C1) ? C1 : MIN(X, C2)
+define float @clamp_float_fast_unordered_strict_maxmin(float %x) {
+;
+; CHECK-LABEL: @clamp_float_fast_unordered_strict_maxmin(
+; CHECK-NEXT:    [[CMP2_INV:%.*]] = fcmp fast oge float [[X:%.*]], 2.550000e+02
+; CHECK-NEXT:    [[MIN:%.*]] = select i1 [[CMP2_INV]], float 2.550000e+02, float [[X]]
+; CHECK-NEXT:    [[DOTINV:%.*]] = fcmp fast oge float [[MIN]], 1.000000e+00
+; CHECK-NEXT:    [[R1:%.*]] = select i1 [[DOTINV]], float [[MIN]], float 1.000000e+00
+; CHECK-NEXT:    ret float [[R1]]
+;
+  %cmp2 = fcmp fast ult float %x, 255.0
+  %min = select i1 %cmp2, float %x, float 255.0
+  %cmp1 = fcmp fast ult float %x, 1.0
+  %r = select i1 %cmp1, float 1.0, float %min
+  ret float %r
+}
+
+; (X <= C1) ? C1 : MIN(X, C2)
+define float @clamp_float_fast_unordered_nonstrict_maxmin(float %x) {
+;
+; CHECK-LABEL: @clamp_float_fast_unordered_nonstrict_maxmin(
+; CHECK-NEXT:    [[CMP2_INV:%.*]] = fcmp fast oge float [[X:%.*]], 2.550000e+02
+; CHECK-NEXT:    [[MIN:%.*]] = select i1 [[CMP2_INV]], float 2.550000e+02, float [[X]]
+; CHECK-NEXT:    [[DOTINV:%.*]] = fcmp fast oge float [[MIN]], 1.000000e+00
+; CHECK-NEXT:    [[R1:%.*]] = select i1 [[DOTINV]], float [[MIN]], float 1.000000e+00
+; CHECK-NEXT:    ret float [[R1]]
+;
+  %cmp2 = fcmp fast ult float %x, 255.0
+  %min = select i1 %cmp2, float %x, float 255.0
+  %cmp1 = fcmp fast ule float %x, 1.0
+  %r = select i1 %cmp1, float 1.0, float %min
+  ret float %r
+}
+
+; (X > C1) ? C1 : MAX(X, C2)
+define float @clamp_float_fast_unordered_strict_minmax(float %x) {
+;
+; CHECK-LABEL: @clamp_float_fast_unordered_strict_minmax(
+; CHECK-NEXT:    [[CMP2_INV:%.*]] = fcmp fast ole float [[X:%.*]], 1.000000e+00
+; CHECK-NEXT:    [[MAX:%.*]] = select i1 [[CMP2_INV]], float 1.000000e+00, float [[X]]
+; CHECK-NEXT:    [[DOTINV:%.*]] = fcmp fast ole float [[MAX]], 2.550000e+02
+; CHECK-NEXT:    [[R1:%.*]] = select i1 [[DOTINV]], float [[MAX]], float 2.550000e+02
+; CHECK-NEXT:    ret float [[R1]]
+;
+  %cmp2 = fcmp fast ugt float %x, 1.0
+  %max = select i1 %cmp2, float %x, float 1.0
+  %cmp1 = fcmp fast ugt float %x, 255.0
+  %r = select i1 %cmp1, float 255.0, float %max
+  ret float %r
+}
+
+; (X >= C1) ? C1 : MAX(X, C2)
+define float @clamp_float_fast_unordered_nonstrict_minmax(float %x) {
+;
+; CHECK-LABEL: @clamp_float_fast_unordered_nonstrict_minmax(
+; CHECK-NEXT:    [[CMP2_INV:%.*]] = fcmp fast ole float [[X:%.*]], 1.000000e+00
+; CHECK-NEXT:    [[MAX:%.*]] = select i1 [[CMP2_INV]], float 1.000000e+00, float [[X]]
+; CHECK-NEXT:    [[DOTINV:%.*]] = fcmp fast ole float [[MAX]], 2.550000e+02
+; CHECK-NEXT:    [[R1:%.*]] = select i1 [[DOTINV]], float [[MAX]], float 2.550000e+02
+; CHECK-NEXT:    ret float [[R1]]
+;
+  %cmp2 = fcmp fast ugt float %x, 1.0
+  %max = select i1 %cmp2, float %x, float 1.0
+  %cmp1 = fcmp fast uge float %x, 255.0
+  %r = select i1 %cmp1, float 255.0, float %max
+  ret float %r
+}
+
+; Some more checks with fast
+
+; (X > 1.0) ? min(x, 255.0) : 1.0
+; That did not match because select was in inverse order.
+define float @clamp_test_1(float %x) {
+; CHECK-LABEL: @clamp_test_1(
+; CHECK-NEXT:    [[INNER_CMP_INV:%.*]] = fcmp fast oge float [[X:%.*]], 2.550000e+02
+; CHECK-NEXT:    [[INNER_SEL:%.*]] = select i1 [[INNER_CMP_INV]], float 2.550000e+02, float [[X]]
+; CHECK-NEXT:    [[DOTINV:%.*]] = fcmp fast oge float [[INNER_SEL]], 1.000000e+00
+; CHECK-NEXT:    [[R1:%.*]] = select i1 [[DOTINV]], float [[INNER_SEL]], float 1.000000e+00
+; CHECK-NEXT:    ret float [[R1]]
+;
+  %inner_cmp = fcmp fast ult float %x, 255.0
+  %inner_sel = select i1 %inner_cmp, float %x, float 255.0
+  %outer_cmp = fcmp fast ugt float %x, 1.0
+  %r = select i1 %outer_cmp, float %inner_sel, float 1.0
+  ret float %r
+}
+
+; And something negative
+
+; Like @clamp_test_1 but HighConst < LowConst
+define float @clamp_negative_wrong_const(float %x) {
+; CHECK-LABEL: @clamp_negative_wrong_const(
+; CHECK-NEXT:    [[INNER_CMP_INV:%.*]] = fcmp fast oge float [[X:%.*]], 2.550000e+02
+; CHECK-NEXT:    [[INNER_SEL:%.*]] = select i1 [[INNER_CMP_INV]], float 2.550000e+02, float [[X]]
+; CHECK-NEXT:    [[OUTER_CMP:%.*]] = fcmp fast ugt float [[X]], 5.120000e+02
+; CHECK-NEXT:    [[R:%.*]] = select i1 [[OUTER_CMP]], float [[INNER_SEL]], float 5.120000e+02
+; CHECK-NEXT:    ret float [[R]]
+;
+  %inner_cmp = fcmp fast ult float %x, 255.0
+  %inner_sel = select i1 %inner_cmp, float %x, float 255.0
+  %outer_cmp = fcmp fast ugt float %x, 512.0
+  %r = select i1 %outer_cmp, float %inner_sel, float 512.0
+  ret float %r
+}
+
+; Like @clamp_test_1 but both are min
+define float @clamp_negative_same_op(float %x) {
+; CHECK-LABEL: @clamp_negative_same_op(
+; CHECK-NEXT:    [[INNER_CMP_INV:%.*]] = fcmp fast oge float [[X:%.*]], 2.550000e+02
+; CHECK-NEXT:    [[INNER_SEL:%.*]] = select i1 [[INNER_CMP_INV]], float 2.550000e+02, float [[X]]
+; CHECK-NEXT:    [[OUTER_CMP:%.*]] = fcmp fast ult float [[X]], 1.000000e+00
+; CHECK-NEXT:    [[R:%.*]] = select i1 [[OUTER_CMP]], float [[INNER_SEL]], float 1.000000e+00
+; CHECK-NEXT:    ret float [[R]]
+;
+  %inner_cmp = fcmp fast ult float %x, 255.0
+  %inner_sel = select i1 %inner_cmp, float %x, float 255.0
+  %outer_cmp = fcmp fast ult float %x, 1.0
+  %r = select i1 %outer_cmp, float %inner_sel, float 1.0
+  ret float %r
+}
+
+
+; And now without fast.
+
+; First, check that we don't do bad things in the presence of signed zeros
+define float @clamp_float_with_zero1(float %x) {
+; CHECK-LABEL: @clamp_float_with_zero1(
+; CHECK-NEXT:    [[CMP2:%.*]] = fcmp fast olt float [[X:%.*]], 2.550000e+02
+; CHECK-NEXT:    [[MIN:%.*]] = select i1 [[CMP2]], float [[X]], float 2.550000e+02
+; CHECK-NEXT:    [[CMP1:%.*]] = fcmp ole float [[X]], 0.000000e+00
+; CHECK-NEXT:    [[R:%.*]] = select i1 [[CMP1]], float 0.000000e+00, float [[MIN]]
+; CHECK-NEXT:    ret float [[R]]
+;
+  %cmp2 = fcmp fast olt float %x, 255.0
+  %min = select i1 %cmp2, float %x, float 255.0
+  %cmp1 = fcmp ole float %x, 0.0
+  %r = select i1 %cmp1, float 0.0, float %min
+  ret float %r
+}
+
+define float @clamp_float_with_zero2(float %x) {
+; CHECK-LABEL: @clamp_float_with_zero2(
+; CHECK-NEXT:    [[CMP2:%.*]] = fcmp fast olt float [[X:%.*]], 2.550000e+02
+; CHECK-NEXT:    [[MIN:%.*]] = select i1 [[CMP2]], float [[X]], float 2.550000e+02
+; CHECK-NEXT:    [[CMP1:%.*]] = fcmp olt float [[X]], 0.000000e+00
+; CHECK-NEXT:    [[R:%.*]] = select i1 [[CMP1]], float 0.000000e+00, float [[MIN]]
+; CHECK-NEXT:    ret float [[R]]
+;
+  %cmp2 = fcmp fast olt float %x, 255.0
+  %min = select i1 %cmp2, float %x, float 255.0
+  %cmp1 = fcmp olt float %x, 0.0
+  %r = select i1 %cmp1, float 0.0, float %min
+  ret float %r
+}
+
+; Also, here we care more about the ordering of the inner min/max, so
+; two times more cases.
+; TODO: that is not implemented yet, so these checks are for the
+;       future. This means that checks below can just check that
+;       "fcmp.*%x" happens twice for each label.
+
+; (X < C1) ? C1 : MIN(X, C2)
+define float @clamp_float_ordered_strict_maxmin1(float %x) {
+;
+; CHECK-LABEL: @clamp_float_ordered_strict_maxmin1(
+; CHECK-NEXT:    [[CMP2:%.*]] = fcmp olt float [[X:%.*]], 2.550000e+02
+; CHECK-NEXT:    [[MIN:%.*]] = select i1 [[CMP2]], float [[X]], float 2.550000e+02
+; CHECK-NEXT:    [[CMP1:%.*]] = fcmp olt float [[X]], 1.000000e+00
+; CHECK-NEXT:    [[R:%.*]] = select i1 [[CMP1]], float 1.000000e+00, float [[MIN]]
+; CHECK-NEXT:    ret float [[R]]
+;
+  %cmp2 = fcmp olt float %x, 255.0                   ; X is NaN => false
+  %min = select i1 %cmp2, float %x, float 255.0      ;             255.0
+  %cmp1 = fcmp olt float %x, 1.0                     ;             false
+  %r = select i1 %cmp1, float 1.0, float %min        ;             min (255.0)
+  ret float %r
+}
+
+define float @clamp_float_ordered_strict_maxmin2(float %x) {
+;
+; CHECK-LABEL: @clamp_float_ordered_strict_maxmin2(
+; CHECK-NEXT:    [[CMP2_INV:%.*]] = fcmp oge float [[X:%.*]], 2.550000e+02
+; CHECK-NEXT:    [[MIN:%.*]] = select i1 [[CMP2_INV]], float 2.550000e+02, float [[X]]
+; CHECK-NEXT:    [[CMP1:%.*]] = fcmp olt float [[X]], 1.000000e+00
+; CHECK-NEXT:    [[R:%.*]] = select i1 [[CMP1]], float 1.000000e+00, float [[MIN]]
+; CHECK-NEXT:    ret float [[R]]
+;
+  %cmp2 = fcmp ult float %x, 255.0                  ; X is NaN => true
+  %min = select i1 %cmp2, float %x, float 255.0     ;             NaN
+  %cmp1 = fcmp olt float %x, 1.0                    ;             false
+  %r = select i1 %cmp1, float 1.0, float %min       ;             min (NaN)
+  ret float %r
+}
+
+; (X <= C1) ? C1 : MIN(X, C2)
+define float @clamp_float_ordered_nonstrict_maxmin1(float %x) {
+;
+; CHECK-LABEL: @clamp_float_ordered_nonstrict_maxmin1(
+; CHECK-NEXT:    [[CMP2:%.*]] = fcmp olt float [[X:%.*]], 2.550000e+02
+; CHECK-NEXT:    [[MIN:%.*]] = select i1 [[CMP2]], float [[X]], float 2.550000e+02
+; CHECK-NEXT:    [[CMP1:%.*]] = fcmp ole float [[X]], 1.000000e+00
+; CHECK-NEXT:    [[R:%.*]] = select i1 [[CMP1]], float 1.000000e+00, float [[MIN]]
+; CHECK-NEXT:    ret float [[R]]
+;
+  %cmp2 = fcmp olt float %x, 255.0                  ; X is NaN => false
+  %min = select i1 %cmp2, float %x, float 255.0     ;             255.0
+  %cmp1 = fcmp ole float %x, 1.0                    ;             false
+  %r = select i1 %cmp1, float 1.0, float %min       ;             min (255.0)
+  ret float %r
+}
+
+define float @clamp_float_ordered_nonstrict_maxmin2(float %x) {
+;
+; CHECK-LABEL: @clamp_float_ordered_nonstrict_maxmin2(
+; CHECK-NEXT:    [[CMP2_INV:%.*]] = fcmp oge float [[X:%.*]], 2.550000e+02
+; CHECK-NEXT:    [[MIN:%.*]] = select i1 [[CMP2_INV]], float 2.550000e+02, float [[X]]
+; CHECK-NEXT:    [[CMP1:%.*]] = fcmp ole float [[X]], 1.000000e+00
+; CHECK-NEXT:    [[R:%.*]] = select i1 [[CMP1]], float 1.000000e+00, float [[MIN]]
+; CHECK-NEXT:    ret float [[R]]
+;
+  %cmp2 = fcmp ult float %x, 255.0                  ; x is NaN => true
+  %min = select i1 %cmp2, float %x, float 255.0     ;             NaN
+  %cmp1 = fcmp ole float %x, 1.0                    ;             false
+  %r = select i1 %cmp1, float 1.0, float %min       ;             min (NaN)
+  ret float %r
+}
+
+; (X > C1) ? C1 : MAX(X, C2)
+define float @clamp_float_ordered_strict_minmax1(float %x) {
+;
+; CHECK-LABEL: @clamp_float_ordered_strict_minmax1(
+; CHECK-NEXT:    [[CMP2:%.*]] = fcmp ogt float [[X:%.*]], 1.000000e+00
+; CHECK-NEXT:    [[MAX:%.*]] = select i1 [[CMP2]], float [[X]], float 1.000000e+00
+; CHECK-NEXT:    [[CMP1:%.*]] = fcmp ogt float [[X]], 2.550000e+02
+; CHECK-NEXT:    [[R:%.*]] = select i1 [[CMP1]], float 2.550000e+02, float [[MAX]]
+; CHECK-NEXT:    ret float [[R]]
+;
+  %cmp2 = fcmp ogt float %x, 1.0                    ; x is NaN => false
+  %max = select i1 %cmp2, float %x, float 1.0       ;             1.0
+  %cmp1 = fcmp ogt float %x, 255.0                  ;             false
+  %r = select i1 %cmp1, float 255.0, float %max     ;             max (1.0)
+  ret float %r
+}
+
+define float @clamp_float_ordered_strict_minmax2(float %x) {
+;
+; CHECK-LABEL: @clamp_float_ordered_strict_minmax2(
+; CHECK-NEXT:    [[CMP2_INV:%.*]] = fcmp ole float [[X:%.*]], 1.000000e+00
+; CHECK-NEXT:    [[MAX:%.*]] = select i1 [[CMP2_INV]], float 1.000000e+00, float [[X]]
+; CHECK-NEXT:    [[CMP1:%.*]] = fcmp ogt float [[X]], 2.550000e+02
+; CHECK-NEXT:    [[R:%.*]] = select i1 [[CMP1]], float 2.550000e+02, float [[MAX]]
+; CHECK-NEXT:    ret float [[R]]
+;
+  %cmp2 = fcmp ugt float %x, 1.0                    ; x is NaN => true
+  %max = select i1 %cmp2, float %x, float 1.0       ;             NaN
+  %cmp1 = fcmp ogt float %x, 255.0                  ;             false
+  %r = select i1 %cmp1, float 255.0, float %max     ;             max (NaN)
+  ret float %r
+}
+
+; (X >= C1) ? C1 : MAX(X, C2)
+define float @clamp_float_ordered_nonstrict_minmax1(float %x) {
+;
+; CHECK-LABEL: @clamp_float_ordered_nonstrict_minmax1(
+; CHECK-NEXT:    [[CMP2:%.*]] = fcmp ogt float [[X:%.*]], 1.000000e+00
+; CHECK-NEXT:    [[MAX:%.*]] = select i1 [[CMP2]], float [[X]], float 1.000000e+00
+; CHECK-NEXT:    [[CMP1:%.*]] = fcmp oge float [[X]], 2.550000e+02
+; CHECK-NEXT:    [[R:%.*]] = select i1 [[CMP1]], float 2.550000e+02, float [[MAX]]
+; CHECK-NEXT:    ret float [[R]]
+;
+  %cmp2 = fcmp ogt float %x, 1.0                    ; x is NaN => false
+  %max = select i1 %cmp2, float %x, float 1.0       ;             1.0
+  %cmp1 = fcmp oge float %x, 255.0                  ;             false
+  %r = select i1 %cmp1, float 255.0, float %max     ;             max (1.0)
+  ret float %r
+}
+
+define float @clamp_float_ordered_nonstrict_minmax2(float %x) {
+;
+; CHECK-LABEL: @clamp_float_ordered_nonstrict_minmax2(
+; CHECK-NEXT:    [[CMP2_INV:%.*]] = fcmp ole float [[X:%.*]], 1.000000e+00
+; CHECK-NEXT:    [[MAX:%.*]] = select i1 [[CMP2_INV]], float 1.000000e+00, float [[X]]
+; CHECK-NEXT:    [[CMP1:%.*]] = fcmp oge float [[X]], 2.550000e+02
+; CHECK-NEXT:    [[R:%.*]] = select i1 [[CMP1]], float 2.550000e+02, float [[MAX]]
+; CHECK-NEXT:    ret float [[R]]
+;
+  %cmp2 = fcmp ugt float %x, 1.0                    ; x is NaN => true
+  %max = select i1 %cmp2, float %x, float 1.0       ;             NaN
+  %cmp1 = fcmp oge float %x, 255.0                  ;             false
+  %r = select i1 %cmp1, float 255.0, float %max     ;             max (NaN)
+  ret float %r
+}
+
+
+; The same for unordered
+
+; (X < C1) ? C1 : MIN(X, C2)
+define float @clamp_float_unordered_strict_maxmin1(float %x) {
+;
+; CHECK-LABEL: @clamp_float_unordered_strict_maxmin1(
+; CHECK-NEXT:    [[CMP2:%.*]] = fcmp olt float [[X:%.*]], 2.550000e+02
+; CHECK-NEXT:    [[MIN:%.*]] = select i1 [[CMP2]], float [[X]], float 2.550000e+02
+; CHECK-NEXT:    [[CMP1:%.*]] = fcmp ult float [[X]], 1.000000e+00
+; CHECK-NEXT:    [[R:%.*]] = select i1 [[CMP1]], float 1.000000e+00, float [[MIN]]
+; CHECK-NEXT:    ret float [[R]]
+;
+  %cmp2 = fcmp olt float %x, 255.0                  ; x is NaN => false
+  %min = select i1 %cmp2, float %x, float 255.0     ;             255.0
+  %cmp1 = fcmp ult float %x, 1.0                    ;             true
+  %r = select i1 %cmp1, float 1.0, float %min       ;             1.0
+  ret float %r
+}
+
+define float @clamp_float_unordered_strict_maxmin2(float %x) {
+;
+; CHECK-LABEL: @clamp_float_unordered_strict_maxmin2(
+; CHECK-NEXT:    [[CMP2_INV:%.*]] = fcmp oge float [[X:%.*]], 2.550000e+02
+; CHECK-NEXT:    [[MIN:%.*]] = select i1 [[CMP2_INV]], float 2.550000e+02, float [[X]]
+; CHECK-NEXT:    [[CMP1:%.*]] = fcmp ult float [[X]], 1.000000e+00
+; CHECK-NEXT:    [[R:%.*]] = select i1 [[CMP1]], float 1.000000e+00, float [[MIN]]
+; CHECK-NEXT:    ret float [[R]]
+;
+  %cmp2 = fcmp ult float %x, 255.0                  ; x is NaN => true
+  %min = select i1 %cmp2, float %x, float 255.0     ;             NaN
+  %cmp1 = fcmp ult float %x, 1.0                    ;             true
+  %r = select i1 %cmp1, float 1.0, float %min       ;             1.0
+  ret float %r
+}
+
+; (X <= C1) ? C1 : MIN(X, C2)
+define float @clamp_float_unordered_nonstrict_maxmin1(float %x) {
+;
+; CHECK-LABEL: @clamp_float_unordered_nonstrict_maxmin1(
+; CHECK-NEXT:    [[CMP2:%.*]] = fcmp olt float [[X:%.*]], 2.550000e+02
+; CHECK-NEXT:    [[MIN:%.*]] = select i1 [[CMP2]], float [[X]], float 2.550000e+02
+; CHECK-NEXT:    [[CMP1:%.*]] = fcmp ule float [[X]], 1.000000e+00
+; CHECK-NEXT:    [[R:%.*]] = select i1 [[CMP1]], float 1.000000e+00, float [[MIN]]
+; CHECK-NEXT:    ret float [[R]]
+;
+  %cmp2 = fcmp olt float %x, 255.0                  ; x is NaN => false
+  %min = select i1 %cmp2, float %x, float 255.0     ;             255.0
+  %cmp1 = fcmp ule float %x, 1.0                    ;             true
+  %r = select i1 %cmp1, float 1.0, float %min       ;             1.0
+  ret float %r
+}
+
+define float @clamp_float_unordered_nonstrict_maxmin2(float %x) {
+;
+; CHECK-LABEL: @clamp_float_unordered_nonstrict_maxmin2(
+; CHECK-NEXT:    [[CMP2_INV:%.*]] = fcmp oge float [[X:%.*]], 2.550000e+02
+; CHECK-NEXT:    [[MIN:%.*]] = select i1 [[CMP2_INV]], float 2.550000e+02, float [[X]]
+; CHECK-NEXT:    [[CMP1:%.*]] = fcmp ule float [[X]], 1.000000e+00
+; CHECK-NEXT:    [[R:%.*]] = select i1 [[CMP1]], float 1.000000e+00, float [[MIN]]
+; CHECK-NEXT:    ret float [[R]]
+;
+  %cmp2 = fcmp ult float %x, 255.0                  ; x is NaN => true
+  %min = select i1 %cmp2, float %x, float 255.0     ;             NaN
+  %cmp1 = fcmp ule float %x, 1.0                    ;             true
+  %r = select i1 %cmp1, float 1.0, float %min       ;             1.0
+  ret float %r
+}
+
+; (X > C1) ? C1 : MAX(X, C2)
+define float @clamp_float_unordered_strict_minmax1(float %x) {
+;
+; CHECK-LABEL: @clamp_float_unordered_strict_minmax1(
+; CHECK-NEXT:    [[CMP2:%.*]] = fcmp ogt float [[X:%.*]], 1.000000e+00
+; CHECK-NEXT:    [[MAX:%.*]] = select i1 [[CMP2]], float [[X]], float 1.000000e+00
+; CHECK-NEXT:    [[CMP1:%.*]] = fcmp ugt float [[X]], 2.550000e+02
+; CHECK-NEXT:    [[R:%.*]] = select i1 [[CMP1]], float 2.550000e+02, float [[MAX]]
+; CHECK-NEXT:    ret float [[R]]
+;
+  %cmp2 = fcmp ogt float %x, 1.0                    ; x is NaN => false
+  %max = select i1 %cmp2, float %x, float 1.0       ;             1.0
+  %cmp1 = fcmp ugt float %x, 255.0                  ;             true
+  %r = select i1 %cmp1, float 255.0, float %max     ;             255.0
+  ret float %r
+}
+
+define float @clamp_float_unordered_strict_minmax2(float %x) {
+;
+; CHECK-LABEL: @clamp_float_unordered_strict_minmax2(
+; CHECK-NEXT:    [[CMP2_INV:%.*]] = fcmp ole float [[X:%.*]], 1.000000e+00
+; CHECK-NEXT:    [[MAX:%.*]] = select i1 [[CMP2_INV]], float 1.000000e+00, float [[X]]
+; CHECK-NEXT:    [[CMP1:%.*]] = fcmp ugt float [[X]], 2.550000e+02
+; CHECK-NEXT:    [[R:%.*]] = select i1 [[CMP1]], float 2.550000e+02, float [[MAX]]
+; CHECK-NEXT:    ret float [[R]]
+;
+  %cmp2 = fcmp ugt float %x, 1.0                    ; x is NaN => true
+  %max = select i1 %cmp2, float %x, float 1.0       ;             NaN
+  %cmp1 = fcmp ugt float %x, 255.0                  ;             true
+  %r = select i1 %cmp1, float 255.0, float %max     ;             255.0
+  ret float %r
+}
+
+; (X >= C1) ? C1 : MAX(X, C2)
+define float @clamp_float_unordered_nonstrict_minmax1(float %x) {
+;
+; CHECK-LABEL: @clamp_float_unordered_nonstrict_minmax1(
+; CHECK-NEXT:    [[CMP2:%.*]] = fcmp ogt float [[X:%.*]], 1.000000e+00
+; CHECK-NEXT:    [[MAX:%.*]] = select i1 [[CMP2]], float [[X]], float 1.000000e+00
+; CHECK-NEXT:    [[CMP1:%.*]] = fcmp uge float [[X]], 2.550000e+02
+; CHECK-NEXT:    [[R:%.*]] = select i1 [[CMP1]], float 2.550000e+02, float [[MAX]]
+; CHECK-NEXT:    ret float [[R]]
+;
+  %cmp2 = fcmp ogt float %x, 1.0                    ; x is NaN => false
+  %max = select i1 %cmp2, float %x, float 1.0       ;             1.0
+  %cmp1 = fcmp uge float %x, 255.0                  ;             true
+  %r = select i1 %cmp1, float 255.0, float %max     ;             255.0
+  ret float %r
+}
+
+define float @clamp_float_unordered_nonstrict_minmax2(float %x) {
+;
+; CHECK-LABEL: @clamp_float_unordered_nonstrict_minmax2(
+; CHECK-NEXT:    [[CMP2_INV:%.*]] = fcmp ole float [[X:%.*]], 1.000000e+00
+; CHECK-NEXT:    [[MAX:%.*]] = select i1 [[CMP2_INV]], float 1.000000e+00, float [[X]]
+; CHECK-NEXT:    [[CMP1:%.*]] = fcmp uge float [[X]], 2.550000e+02
+; CHECK-NEXT:    [[R:%.*]] = select i1 [[CMP1]], float 2.550000e+02, float [[MAX]]
+; CHECK-NEXT:    ret float [[R]]
+;
+  %cmp2 = fcmp ugt float %x, 1.0                    ; x is NaN => true
+  %max = select i1 %cmp2, float %x, float 1.0       ;             NaN
+  %cmp1 = fcmp uge float %x, 255.0                  ;             true
+  %r = select i1 %cmp1, float 255.0, float %max     ;             255.0
+  ret float %r
+}
+
+;; Check casts behavior
+define float @ui32_clamp_and_cast_to_float(i32 %x) {
+; CHECK-LABEL: @ui32_clamp_and_cast_to_float(
+; CHECK-NEXT:    [[LO_CMP:%.*]] = icmp eq i32 [[X:%.*]], 0
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp ult i32 [[X]], 255
+; CHECK-NEXT:    [[MIN1:%.*]] = select i1 [[TMP1]], i32 [[X]], i32 255
+; CHECK-NEXT:    [[TMP2:%.*]] = uitofp i32 [[MIN1]] to float
+; CHECK-NEXT:    [[R:%.*]] = select i1 [[LO_CMP]], float 1.000000e+00, float [[TMP2]]
+; CHECK-NEXT:    ret float [[R]]
+;
+  %f_x = uitofp i32 %x to float
+  %up_cmp = icmp ugt i32 %x, 255
+  %lo_cmp = icmp ult i32 %x, 1
+  %min = select i1 %up_cmp, float 255.0, float %f_x
+  %r = select i1 %lo_cmp, float 1.0, float %min
+  ret float %r
+}
+
+define float @ui64_clamp_and_cast_to_float(i64 %x) {
+; CHECK-LABEL: @ui64_clamp_and_cast_to_float(
+; CHECK-NEXT:    [[LO_CMP:%.*]] = icmp eq i64 [[X:%.*]], 0
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp ult i64 [[X]], 255
+; CHECK-NEXT:    [[MIN1:%.*]] = select i1 [[TMP1]], i64 [[X]], i64 255
+; CHECK-NEXT:    [[TMP2:%.*]] = uitofp i64 [[MIN1]] to float
+; CHECK-NEXT:    [[R:%.*]] = select i1 [[LO_CMP]], float 1.000000e+00, float [[TMP2]]
+; CHECK-NEXT:    ret float [[R]]
+;
+  %f_x = uitofp i64 %x to float
+  %up_cmp = icmp ugt i64 %x, 255
+  %lo_cmp = icmp ult i64 %x, 1
+  %min = select i1 %up_cmp, float 255.0, float %f_x
+  %r = select i1 %lo_cmp, float 1.0, float %min
+  ret float %r
+}
+
+define float @mixed_clamp_to_float_1(i32 %x) {
+; CHECK-LABEL: @mixed_clamp_to_float_1(
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp slt i32 [[X:%.*]], 255
+; CHECK-NEXT:    [[SI_MIN:%.*]] = select i1 [[TMP1]], i32 [[X]], i32 255
+; CHECK-NEXT:    [[TMP2:%.*]] = icmp sgt i32 [[SI_MIN]], 1
+; CHECK-NEXT:    [[R1:%.*]] = select i1 [[TMP2]], i32 [[SI_MIN]], i32 1
+; CHECK-NEXT:    [[TMP3:%.*]] = sitofp i32 [[R1]] to float
+; CHECK-NEXT:    ret float [[TMP3]]
+;
+  %si_min_cmp = icmp sgt i32 %x, 255
+  %si_min = select i1 %si_min_cmp, i32 255, i32 %x
+  %f_min = sitofp i32 %si_min to float
+  %f_x = sitofp i32 %x to float
+  %lo_cmp = fcmp ult float %f_x, 1.0
+  %r = select i1 %lo_cmp, float 1.0, float %f_min
+  ret float %r
+}
+
+define i32 @mixed_clamp_to_i32_1(float %x) {
+; CHECK-LABEL: @mixed_clamp_to_i32_1(
+; CHECK-NEXT:    [[FLOAT_MIN_CMP:%.*]] = fcmp ogt float [[X:%.*]], 2.550000e+02
+; CHECK-NEXT:    [[FLOAT_MIN:%.*]] = select i1 [[FLOAT_MIN_CMP]], float 2.550000e+02, float [[X]]
+; CHECK-NEXT:    [[I32_MIN:%.*]] = fptosi float [[FLOAT_MIN]] to i32
+; CHECK-NEXT:    [[I32_X:%.*]] = fptosi float [[X]] to i32
+; CHECK-NEXT:    [[LO_CMP:%.*]] = icmp eq i32 [[I32_X]], 0
+; CHECK-NEXT:    [[R:%.*]] = select i1 [[LO_CMP]], i32 1, i32 [[I32_MIN]]
+; CHECK-NEXT:    ret i32 [[R]]
+;
+  %float_min_cmp = fcmp ogt float %x, 255.0
+  %float_min = select i1 %float_min_cmp, float 255.0, float %x
+  %i32_min = fptosi float %float_min to i32
+  %i32_x = fptosi float %x to i32
+  %lo_cmp = icmp ult i32 %i32_x, 1
+  %r = select i1 %lo_cmp, i32 1, i32 %i32_min
+  ret i32 %r
+}
+
+define float @mixed_clamp_to_float_2(i32 %x) {
+; CHECK-LABEL: @mixed_clamp_to_float_2(
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp slt i32 [[X:%.*]], 255
+; CHECK-NEXT:    [[SI_MIN:%.*]] = select i1 [[TMP1]], i32 [[X]], i32 255
+; CHECK-NEXT:    [[TMP2:%.*]] = icmp sgt i32 [[SI_MIN]], 1
+; CHECK-NEXT:    [[R1:%.*]] = select i1 [[TMP2]], i32 [[SI_MIN]], i32 1
+; CHECK-NEXT:    [[TMP3:%.*]] = sitofp i32 [[R1]] to float
+; CHECK-NEXT:    ret float [[TMP3]]
+;
+  %si_min_cmp = icmp sgt i32 %x, 255
+  %si_min = select i1 %si_min_cmp, i32 255, i32 %x
+  %f_min = sitofp i32 %si_min to float
+  %lo_cmp = icmp slt i32 %x, 1
+  %r = select i1 %lo_cmp, float 1.0, float %f_min
+  ret float %r
+}
+
+define i32 @mixed_clamp_to_i32_2(float %x) {
+; CHECK-LABEL: @mixed_clamp_to_i32_2(
+; CHECK-NEXT:    [[FLOAT_MIN_CMP:%.*]] = fcmp ogt float [[X:%.*]], 2.550000e+02
+; CHECK-NEXT:    [[FLOAT_MIN:%.*]] = select i1 [[FLOAT_MIN_CMP]], float 2.550000e+02, float [[X]]
+; CHECK-NEXT:    [[I32_MIN:%.*]] = fptosi float [[FLOAT_MIN]] to i32
+; CHECK-NEXT:    [[LO_CMP:%.*]] = fcmp olt float [[X]], 1.000000e+00
+; CHECK-NEXT:    [[R:%.*]] = select i1 [[LO_CMP]], i32 1, i32 [[I32_MIN]]
+; CHECK-NEXT:    ret i32 [[R]]
+;
+  %float_min_cmp = fcmp ogt float %x, 255.0
+  %float_min = select i1 %float_min_cmp, float 255.0, float %x
+  %i32_min = fptosi float %float_min to i32
+  %lo_cmp = fcmp olt float %x, 1.0
+  %r = select i1 %lo_cmp, i32 1, i32 %i32_min
+  ret i32 %r
+}

Added: llvm/trunk/test/Transforms/InstCombine/cmp-intrinsic.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/cmp-intrinsic.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/cmp-intrinsic.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/cmp-intrinsic.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,493 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt < %s -instcombine -S | FileCheck %s
+
+declare i16 @llvm.bswap.i16(i16)
+declare i32 @llvm.bswap.i32(i32)
+declare <2 x i64> @llvm.bswap.v2i64(<2 x i64>)
+declare i33 @llvm.cttz.i33(i33, i1)
+declare i32 @llvm.ctlz.i32(i32, i1)
+declare i8 @llvm.ctpop.i8(i8)
+declare i11 @llvm.ctpop.i11(i11)
+declare <2 x i32> @llvm.cttz.v2i32(<2 x i32>, i1)
+declare <2 x i32> @llvm.ctlz.v2i32(<2 x i32>, i1)
+declare <2 x i32> @llvm.ctpop.v2i32(<2 x i32>)
+
+define i1 @bswap_eq_i16(i16 %x) {
+; CHECK-LABEL: @bswap_eq_i16(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i16 [[X:%.*]], 256
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %bs = call i16 @llvm.bswap.i16(i16 %x)
+  %cmp = icmp eq i16 %bs, 1
+  ret i1 %cmp
+}
+
+define i1 @bswap_ne_i32(i32 %x) {
+; CHECK-LABEL: @bswap_ne_i32(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ne i32 [[X:%.*]], 33554432
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %bs = tail call i32 @llvm.bswap.i32(i32 %x)
+  %cmp = icmp ne i32 %bs, 2
+  ret i1 %cmp
+}
+
+define <2 x i1> @bswap_eq_v2i64(<2 x i64> %x) {
+; CHECK-LABEL: @bswap_eq_v2i64(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq <2 x i64> [[X:%.*]], <i64 216172782113783808, i64 216172782113783808>
+; CHECK-NEXT:    ret <2 x i1> [[CMP]]
+;
+  %bs = tail call <2 x i64> @llvm.bswap.v2i64(<2 x i64> %x)
+  %cmp = icmp eq <2 x i64> %bs, <i64 3, i64 3>
+  ret <2 x i1> %cmp
+}
+
+define i1 @ctlz_eq_bitwidth_i32(i32 %x) {
+; CHECK-LABEL: @ctlz_eq_bitwidth_i32(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[X:%.*]], 0
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %lz = tail call i32 @llvm.ctlz.i32(i32 %x, i1 false)
+  %cmp = icmp eq i32 %lz, 32
+  ret i1 %cmp
+}
+
+define i1 @ctlz_eq_zero_i32(i32 %x) {
+; CHECK-LABEL: @ctlz_eq_zero_i32(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i32 [[X:%.*]], 0
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %lz = tail call i32 @llvm.ctlz.i32(i32 %x, i1 false)
+  %cmp = icmp eq i32 %lz, 0
+  ret i1 %cmp
+}
+
+define <2 x i1> @ctlz_ne_zero_v2i32(<2 x i32> %a) {
+; CHECK-LABEL: @ctlz_ne_zero_v2i32(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt <2 x i32> [[A:%.*]], <i32 -1, i32 -1>
+; CHECK-NEXT:    ret <2 x i1> [[CMP]]
+;
+  %x = tail call <2 x i32> @llvm.ctlz.v2i32(<2 x i32> %a, i1 false)
+  %cmp = icmp ne <2 x i32> %x, zeroinitializer
+  ret <2 x i1> %cmp
+}
+
+define i1 @ctlz_eq_bw_minus_1_i32(i32 %x) {
+; CHECK-LABEL: @ctlz_eq_bw_minus_1_i32(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[X:%.*]], 1
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %lz = tail call i32 @llvm.ctlz.i32(i32 %x, i1 false)
+  %cmp = icmp eq i32 %lz, 31
+  ret i1 %cmp
+}
+
+define <2 x i1> @ctlz_ne_bw_minus_1_v2i32(<2 x i32> %a) {
+; CHECK-LABEL: @ctlz_ne_bw_minus_1_v2i32(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ne <2 x i32> [[A:%.*]], <i32 1, i32 1>
+; CHECK-NEXT:    ret <2 x i1> [[CMP]]
+;
+  %x = tail call <2 x i32> @llvm.ctlz.v2i32(<2 x i32> %a, i1 false)
+  %cmp = icmp ne <2 x i32> %x, <i32 31, i32 31>
+  ret <2 x i1> %cmp
+}
+
+define i1 @ctlz_eq_other_i32(i32 %x) {
+; CHECK-LABEL: @ctlz_eq_other_i32(
+; CHECK-NEXT:    [[TMP1:%.*]] = and i32 [[X:%.*]], -128
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[TMP1]], 128
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %lz = tail call i32 @llvm.ctlz.i32(i32 %x, i1 false)
+  %cmp = icmp eq i32 %lz, 24
+  ret i1 %cmp
+}
+
+define <2 x i1> @ctlz_ne_other_v2i32(<2 x i32> %a) {
+; CHECK-LABEL: @ctlz_ne_other_v2i32(
+; CHECK-NEXT:    [[TMP1:%.*]] = and <2 x i32> [[A:%.*]], <i32 -128, i32 -128>
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ne <2 x i32> [[TMP1]], <i32 128, i32 128>
+; CHECK-NEXT:    ret <2 x i1> [[CMP]]
+;
+  %x = tail call <2 x i32> @llvm.ctlz.v2i32(<2 x i32> %a, i1 false)
+  %cmp = icmp ne <2 x i32> %x, <i32 24, i32 24>
+  ret <2 x i1> %cmp
+}
+
+define i1 @ctlz_eq_other_i32_multiuse(i32 %x, i32* %p) {
+; CHECK-LABEL: @ctlz_eq_other_i32_multiuse(
+; CHECK-NEXT:    [[LZ:%.*]] = tail call i32 @llvm.ctlz.i32(i32 [[X:%.*]], i1 false), !range !0
+; CHECK-NEXT:    store i32 [[LZ]], i32* [[P:%.*]], align 4
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[LZ]], 24
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %lz = tail call i32 @llvm.ctlz.i32(i32 %x, i1 false)
+  store i32 %lz, i32* %p
+  %cmp = icmp eq i32 %lz, 24
+  ret i1 %cmp
+}
+
+define <2 x i1> @ctlz_ne_bitwidth_v2i32(<2 x i32> %a) {
+; CHECK-LABEL: @ctlz_ne_bitwidth_v2i32(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ne <2 x i32> [[A:%.*]], zeroinitializer
+; CHECK-NEXT:    ret <2 x i1> [[CMP]]
+;
+  %x = tail call <2 x i32> @llvm.ctlz.v2i32(<2 x i32> %a, i1 false)
+  %cmp = icmp ne <2 x i32> %x, <i32 32, i32 32>
+  ret <2 x i1> %cmp
+}
+
+define i1 @ctlz_ugt_zero_i32(i32 %x) {
+; CHECK-LABEL: @ctlz_ugt_zero_i32(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt i32 [[X:%.*]], -1
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %lz = tail call i32 @llvm.ctlz.i32(i32 %x, i1 false)
+  %cmp = icmp ugt i32 %lz, 0
+  ret i1 %cmp
+}
+
+define i1 @ctlz_ugt_one_i32(i32 %x) {
+; CHECK-LABEL: @ctlz_ugt_one_i32(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i32 [[X:%.*]], 1073741824
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %lz = tail call i32 @llvm.ctlz.i32(i32 %x, i1 false)
+  %cmp = icmp ugt i32 %lz, 1
+  ret i1 %cmp
+}
+
+define i1 @ctlz_ugt_other_i32(i32 %x) {
+; CHECK-LABEL: @ctlz_ugt_other_i32(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i32 [[X:%.*]], 32768
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %lz = tail call i32 @llvm.ctlz.i32(i32 %x, i1 false)
+  %cmp = icmp ugt i32 %lz, 16
+  ret i1 %cmp
+}
+
+define i1 @ctlz_ugt_other_multiuse_i32(i32 %x, i32* %p) {
+; CHECK-LABEL: @ctlz_ugt_other_multiuse_i32(
+; CHECK-NEXT:    [[LZ:%.*]] = tail call i32 @llvm.ctlz.i32(i32 [[X:%.*]], i1 false), !range !0
+; CHECK-NEXT:    store i32 [[LZ]], i32* [[P:%.*]], align 4
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i32 [[X]], 32768
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %lz = tail call i32 @llvm.ctlz.i32(i32 %x, i1 false)
+  store i32 %lz, i32* %p
+  %cmp = icmp ugt i32 %lz, 16
+  ret i1 %cmp
+}
+
+define i1 @ctlz_ugt_bw_minus_one_i32(i32 %x) {
+; CHECK-LABEL: @ctlz_ugt_bw_minus_one_i32(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[X:%.*]], 0
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %lz = tail call i32 @llvm.ctlz.i32(i32 %x, i1 false)
+  %cmp = icmp ugt i32 %lz, 31
+  ret i1 %cmp
+}
+
+define <2 x i1> @ctlz_ult_one_v2i32(<2 x i32> %x) {
+; CHECK-LABEL: @ctlz_ult_one_v2i32(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp slt <2 x i32> [[X:%.*]], zeroinitializer
+; CHECK-NEXT:    ret <2 x i1> [[CMP]]
+;
+  %lz = tail call <2 x i32> @llvm.ctlz.v2i32(<2 x i32> %x, i1 false)
+  %cmp = icmp ult <2 x i32> %lz, <i32 1, i32 1>
+  ret <2 x i1> %cmp
+}
+
+define <2 x i1> @ctlz_ult_other_v2i32(<2 x i32> %x) {
+; CHECK-LABEL: @ctlz_ult_other_v2i32(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ugt <2 x i32> [[X:%.*]], <i32 65535, i32 65535>
+; CHECK-NEXT:    ret <2 x i1> [[CMP]]
+;
+  %lz = tail call <2 x i32> @llvm.ctlz.v2i32(<2 x i32> %x, i1 false)
+  %cmp = icmp ult <2 x i32> %lz, <i32 16, i32 16>
+  ret <2 x i1> %cmp
+}
+
+define <2 x i1> @ctlz_ult_other_multiuse_v2i32(<2 x i32> %x, <2 x i32>* %p) {
+; CHECK-LABEL: @ctlz_ult_other_multiuse_v2i32(
+; CHECK-NEXT:    [[LZ:%.*]] = tail call <2 x i32> @llvm.ctlz.v2i32(<2 x i32> [[X:%.*]], i1 false)
+; CHECK-NEXT:    store <2 x i32> [[LZ]], <2 x i32>* [[P:%.*]], align 8
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ugt <2 x i32> [[X]], <i32 65535, i32 65535>
+; CHECK-NEXT:    ret <2 x i1> [[CMP]]
+;
+  %lz = tail call <2 x i32> @llvm.ctlz.v2i32(<2 x i32> %x, i1 false)
+  store <2 x i32> %lz, <2 x i32>* %p
+  %cmp = icmp ult <2 x i32> %lz, <i32 16, i32 16>
+  ret <2 x i1> %cmp
+}
+
+define <2 x i1> @ctlz_ult_bw_minus_one_v2i32(<2 x i32> %x) {
+; CHECK-LABEL: @ctlz_ult_bw_minus_one_v2i32(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ugt <2 x i32> [[X:%.*]], <i32 1, i32 1>
+; CHECK-NEXT:    ret <2 x i1> [[CMP]]
+;
+  %lz = tail call <2 x i32> @llvm.ctlz.v2i32(<2 x i32> %x, i1 false)
+  %cmp = icmp ult <2 x i32> %lz, <i32 31, i32 31>
+  ret <2 x i1> %cmp
+}
+
+define <2 x i1> @ctlz_ult_bitwidth_v2i32(<2 x i32> %x) {
+; CHECK-LABEL: @ctlz_ult_bitwidth_v2i32(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ne <2 x i32> [[X:%.*]], zeroinitializer
+; CHECK-NEXT:    ret <2 x i1> [[CMP]]
+;
+  %lz = tail call <2 x i32> @llvm.ctlz.v2i32(<2 x i32> %x, i1 false)
+  %cmp = icmp ult <2 x i32> %lz, <i32 32, i32 32>
+  ret <2 x i1> %cmp
+}
+
+define i1 @cttz_ne_bitwidth_i33(i33 %x) {
+; CHECK-LABEL: @cttz_ne_bitwidth_i33(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ne i33 [[X:%.*]], 0
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %tz = tail call i33 @llvm.cttz.i33(i33 %x, i1 false)
+  %cmp = icmp ne i33 %tz, 33
+  ret i1 %cmp
+}
+
+define <2 x i1> @cttz_eq_bitwidth_v2i32(<2 x i32> %a) {
+; CHECK-LABEL: @cttz_eq_bitwidth_v2i32(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq <2 x i32> [[A:%.*]], zeroinitializer
+; CHECK-NEXT:    ret <2 x i1> [[CMP]]
+;
+  %x = tail call <2 x i32> @llvm.cttz.v2i32(<2 x i32> %a, i1 false)
+  %cmp = icmp eq <2 x i32> %x, <i32 32, i32 32>
+  ret <2 x i1> %cmp
+}
+
+define i1 @cttz_eq_zero_i33(i33 %x) {
+; CHECK-LABEL: @cttz_eq_zero_i33(
+; CHECK-NEXT:    [[TMP1:%.*]] = and i33 [[X:%.*]], 1
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ne i33 [[TMP1]], 0
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %tz = tail call i33 @llvm.cttz.i33(i33 %x, i1 false)
+  %cmp = icmp eq i33 %tz, 0
+  ret i1 %cmp
+}
+
+define <2 x i1> @cttz_ne_zero_v2i32(<2 x i32> %a) {
+; CHECK-LABEL: @cttz_ne_zero_v2i32(
+; CHECK-NEXT:    [[TMP1:%.*]] = and <2 x i32> [[A:%.*]], <i32 1, i32 1>
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq <2 x i32> [[TMP1]], zeroinitializer
+; CHECK-NEXT:    ret <2 x i1> [[CMP]]
+;
+  %x = tail call <2 x i32> @llvm.cttz.v2i32(<2 x i32> %a, i1 false)
+  %cmp = icmp ne <2 x i32> %x, zeroinitializer
+  ret <2 x i1> %cmp
+}
+
+define i1 @cttz_eq_bw_minus_1_i33(i33 %x) {
+; CHECK-LABEL: @cttz_eq_bw_minus_1_i33(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i33 [[X:%.*]], -4294967296
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %tz = tail call i33 @llvm.cttz.i33(i33 %x, i1 false)
+  %cmp = icmp eq i33 %tz, 32
+  ret i1 %cmp
+}
+
+define <2 x i1> @cttz_ne_bw_minus_1_v2i32(<2 x i32> %a) {
+; CHECK-LABEL: @cttz_ne_bw_minus_1_v2i32(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ne <2 x i32> [[A:%.*]], <i32 -2147483648, i32 -2147483648>
+; CHECK-NEXT:    ret <2 x i1> [[CMP]]
+;
+  %x = tail call <2 x i32> @llvm.cttz.v2i32(<2 x i32> %a, i1 false)
+  %cmp = icmp ne <2 x i32> %x, <i32 31, i32 31>
+  ret <2 x i1> %cmp
+}
+
+define i1 @cttz_eq_other_i33(i33 %x) {
+; CHECK-LABEL: @cttz_eq_other_i33(
+; CHECK-NEXT:    [[TMP1:%.*]] = and i33 [[X:%.*]], 31
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i33 [[TMP1]], 16
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %tz = tail call i33 @llvm.cttz.i33(i33 %x, i1 false)
+  %cmp = icmp eq i33 %tz, 4
+  ret i1 %cmp
+}
+
+define <2 x i1> @cttz_ne_other_v2i32(<2 x i32> %a) {
+; CHECK-LABEL: @cttz_ne_other_v2i32(
+; CHECK-NEXT:    [[TMP1:%.*]] = and <2 x i32> [[A:%.*]], <i32 31, i32 31>
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ne <2 x i32> [[TMP1]], <i32 16, i32 16>
+; CHECK-NEXT:    ret <2 x i1> [[CMP]]
+;
+  %x = tail call <2 x i32> @llvm.cttz.v2i32(<2 x i32> %a, i1 false)
+  %cmp = icmp ne <2 x i32> %x, <i32 4, i32 4>
+  ret <2 x i1> %cmp
+}
+
+define i1 @cttz_eq_other_i33_multiuse(i33 %x, i33* %p) {
+; CHECK-LABEL: @cttz_eq_other_i33_multiuse(
+; CHECK-NEXT:    [[TZ:%.*]] = tail call i33 @llvm.cttz.i33(i33 [[X:%.*]], i1 false), !range !1
+; CHECK-NEXT:    store i33 [[TZ]], i33* [[P:%.*]], align 4
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i33 [[TZ]], 4
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %tz = tail call i33 @llvm.cttz.i33(i33 %x, i1 false)
+  store i33 %tz, i33* %p
+  %cmp = icmp eq i33 %tz, 4
+  ret i1 %cmp
+}
+
+define i1 @cttz_ugt_zero_i33(i33 %x) {
+; CHECK-LABEL: @cttz_ugt_zero_i33(
+; CHECK-NEXT:    [[TMP1:%.*]] = and i33 [[X:%.*]], 1
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i33 [[TMP1]], 0
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %tz = tail call i33 @llvm.cttz.i33(i33 %x, i1 false)
+  %cmp = icmp ugt i33 %tz, 0
+  ret i1 %cmp
+}
+
+define i1 @cttz_ugt_one_i33(i33 %x) {
+; CHECK-LABEL: @cttz_ugt_one_i33(
+; CHECK-NEXT:    [[TMP1:%.*]] = and i33 [[X:%.*]], 3
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i33 [[TMP1]], 0
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %tz = tail call i33 @llvm.cttz.i33(i33 %x, i1 false)
+  %cmp = icmp ugt i33 %tz, 1
+  ret i1 %cmp
+}
+
+define i1 @cttz_ugt_other_i33(i33 %x) {
+; CHECK-LABEL: @cttz_ugt_other_i33(
+; CHECK-NEXT:    [[TMP1:%.*]] = and i33 [[X:%.*]], 131071
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i33 [[TMP1]], 0
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %tz = tail call i33 @llvm.cttz.i33(i33 %x, i1 false)
+  %cmp = icmp ugt i33 %tz, 16
+  ret i1 %cmp
+}
+
+define i1 @cttz_ugt_other_multiuse_i33(i33 %x, i33* %p) {
+; CHECK-LABEL: @cttz_ugt_other_multiuse_i33(
+; CHECK-NEXT:    [[TZ:%.*]] = tail call i33 @llvm.cttz.i33(i33 [[X:%.*]], i1 false), !range !1
+; CHECK-NEXT:    store i33 [[TZ]], i33* [[P:%.*]], align 4
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ugt i33 [[TZ]], 16
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %tz = tail call i33 @llvm.cttz.i33(i33 %x, i1 false)
+  store i33 %tz, i33* %p
+  %cmp = icmp ugt i33 %tz, 16
+  ret i1 %cmp
+}
+
+define i1 @cttz_ugt_bw_minus_one_i33(i33 %x) {
+; CHECK-LABEL: @cttz_ugt_bw_minus_one_i33(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i33 [[X:%.*]], 0
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %tz = tail call i33 @llvm.cttz.i33(i33 %x, i1 false)
+  %cmp = icmp ugt i33 %tz, 32
+  ret i1 %cmp
+}
+
+define <2 x i1> @cttz_ult_one_v2i32(<2 x i32> %x) {
+; CHECK-LABEL: @cttz_ult_one_v2i32(
+; CHECK-NEXT:    [[CMP:%.*]] = trunc <2 x i32> [[X:%.*]] to <2 x i1>
+; CHECK-NEXT:    ret <2 x i1> [[CMP]]
+;
+  %tz = tail call <2 x i32> @llvm.cttz.v2i32(<2 x i32> %x, i1 false)
+  %cmp = icmp ult <2 x i32> %tz, <i32 1, i32 1>
+  ret <2 x i1> %cmp
+}
+
+define <2 x i1> @cttz_ult_other_v2i32(<2 x i32> %x) {
+; CHECK-LABEL: @cttz_ult_other_v2i32(
+; CHECK-NEXT:    [[TMP1:%.*]] = and <2 x i32> [[X:%.*]], <i32 65535, i32 65535>
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ne <2 x i32> [[TMP1]], zeroinitializer
+; CHECK-NEXT:    ret <2 x i1> [[CMP]]
+;
+  %tz = tail call <2 x i32> @llvm.cttz.v2i32(<2 x i32> %x, i1 false)
+  %cmp = icmp ult <2 x i32> %tz, <i32 16, i32 16>
+  ret <2 x i1> %cmp
+}
+
+define <2 x i1> @cttz_ult_other_multiuse_v2i32(<2 x i32> %x, <2 x i32>* %p) {
+; CHECK-LABEL: @cttz_ult_other_multiuse_v2i32(
+; CHECK-NEXT:    [[TZ:%.*]] = tail call <2 x i32> @llvm.cttz.v2i32(<2 x i32> [[X:%.*]], i1 false)
+; CHECK-NEXT:    store <2 x i32> [[TZ]], <2 x i32>* [[P:%.*]], align 8
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ult <2 x i32> [[TZ]], <i32 16, i32 16>
+; CHECK-NEXT:    ret <2 x i1> [[CMP]]
+;
+  %tz = tail call <2 x i32> @llvm.cttz.v2i32(<2 x i32> %x, i1 false)
+  store <2 x i32> %tz, <2 x i32>* %p
+  %cmp = icmp ult <2 x i32> %tz, <i32 16, i32 16>
+  ret <2 x i1> %cmp
+}
+
+define <2 x i1> @cttz_ult_bw_minus_one_v2i32(<2 x i32> %x) {
+; CHECK-LABEL: @cttz_ult_bw_minus_one_v2i32(
+; CHECK-NEXT:    [[TMP1:%.*]] = and <2 x i32> [[X:%.*]], <i32 2147483647, i32 2147483647>
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ne <2 x i32> [[TMP1]], zeroinitializer
+; CHECK-NEXT:    ret <2 x i1> [[CMP]]
+;
+  %tz = tail call <2 x i32> @llvm.cttz.v2i32(<2 x i32> %x, i1 false)
+  %cmp = icmp ult <2 x i32> %tz, <i32 31, i32 31>
+  ret <2 x i1> %cmp
+}
+
+define <2 x i1> @cttz_ult_bitwidth_v2i32(<2 x i32> %x) {
+; CHECK-LABEL: @cttz_ult_bitwidth_v2i32(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ne <2 x i32> [[X:%.*]], zeroinitializer
+; CHECK-NEXT:    ret <2 x i1> [[CMP]]
+;
+  %tz = tail call <2 x i32> @llvm.cttz.v2i32(<2 x i32> %x, i1 false)
+  %cmp = icmp ult <2 x i32> %tz, <i32 32, i32 32>
+  ret <2 x i1> %cmp
+}
+
+define i1 @ctpop_eq_zero_i11(i11 %x) {
+; CHECK-LABEL: @ctpop_eq_zero_i11(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i11 [[X:%.*]], 0
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %pop = tail call i11 @llvm.ctpop.i11(i11 %x)
+  %cmp = icmp eq i11 %pop, 0
+  ret i1 %cmp
+}
+
+define <2 x i1> @ctpop_ne_zero_v2i32(<2 x i32> %x) {
+; CHECK-LABEL: @ctpop_ne_zero_v2i32(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ne <2 x i32> [[X:%.*]], zeroinitializer
+; CHECK-NEXT:    ret <2 x i1> [[CMP]]
+;
+  %pop = tail call <2 x i32> @llvm.ctpop.v2i32(<2 x i32> %x)
+  %cmp = icmp ne <2 x i32> %pop, zeroinitializer
+  ret <2 x i1> %cmp
+}
+
+define i1 @ctpop_eq_bitwidth_i8(i8 %x) {
+; CHECK-LABEL: @ctpop_eq_bitwidth_i8(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i8 [[X:%.*]], -1
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %pop = tail call i8 @llvm.ctpop.i8(i8 %x)
+  %cmp = icmp eq i8 %pop, 8
+  ret i1 %cmp
+}
+
+define <2 x i1> @ctpop_ne_bitwidth_v2i32(<2 x i32> %x) {
+; CHECK-LABEL: @ctpop_ne_bitwidth_v2i32(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ne <2 x i32> [[X:%.*]], <i32 -1, i32 -1>
+; CHECK-NEXT:    ret <2 x i1> [[CMP]]
+;
+  %pop = tail call <2 x i32> @llvm.ctpop.v2i32(<2 x i32> %x)
+  %cmp = icmp ne <2 x i32> %pop, <i32 32, i32 32>
+  ret <2 x i1> %cmp
+}
+

Added: llvm/trunk/test/Transforms/InstCombine/compare-3way.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/compare-3way.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/compare-3way.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/compare-3way.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,395 @@
+; RUN: opt -S -instcombine < %s | FileCheck %s
+
+declare void @use(i32)
+
+; These 18 exercise all combinations of signed comparison
+; for each of the three values produced by your typical 
+; 3way compare function (-1, 0, 1)
+
+define void @test_low_sgt(i64 %a, i64 %b) {
+; CHECK-LABEL: @test_low_sgt
+; CHECK: [[TMP1:%.*]] = icmp slt i64 %a, %b
+; CHECK: br i1 [[TMP1]], label %normal, label %unreached
+  %eq = icmp eq i64 %a, %b
+  %slt = icmp slt i64 %a, %b
+  %. = select i1 %slt, i32 -1, i32 1
+  %result = select i1 %eq, i32 0, i32 %.
+  %cmp = icmp sgt i32 %result, -1
+  br i1 %cmp, label %unreached, label %normal
+normal:
+  ret void
+unreached:
+  call void @use(i32 %result)
+  ret void
+}
+
+define void @test_low_slt(i64 %a, i64 %b) {
+; CHECK-LABEL: @test_low_slt
+; CHECK: br i1 false, label %unreached, label %normal
+  %eq = icmp eq i64 %a, %b
+  %slt = icmp slt i64 %a, %b
+  %. = select i1 %slt, i32 -1, i32 1
+  %result = select i1 %eq, i32 0, i32 %.
+  %cmp = icmp slt i32 %result, -1
+  br i1 %cmp, label %unreached, label %normal
+normal:
+  ret void
+unreached:
+  call void @use(i32 %result)
+  ret void
+}
+
+define void @test_low_sge(i64 %a, i64 %b) {
+; CHECK-LABEL: @test_low_sge
+; CHECK: br i1 true, label %unreached, label %normal
+  %eq = icmp eq i64 %a, %b
+  %slt = icmp slt i64 %a, %b
+  %. = select i1 %slt, i32 -1, i32 1
+  %result = select i1 %eq, i32 0, i32 %.
+  %cmp = icmp sge i32 %result, -1
+  br i1 %cmp, label %unreached, label %normal
+normal:
+  ret void
+unreached:
+  call void @use(i32 %result)
+  ret void
+}
+
+define void @test_low_sle(i64 %a, i64 %b) {
+; CHECK-LABEL: @test_low_sle
+; CHECK: [[TMP1:%.*]] = icmp slt i64 %a, %b
+; CHECK: br i1 [[TMP1]], label %unreached, label %normal
+  %eq = icmp eq i64 %a, %b
+  %slt = icmp slt i64 %a, %b
+  %. = select i1 %slt, i32 -1, i32 1
+  %result = select i1 %eq, i32 0, i32 %.
+  %cmp = icmp sle i32 %result, -1
+  br i1 %cmp, label %unreached, label %normal
+normal:
+  ret void
+unreached:
+  call void @use(i32 %result)
+  ret void
+}
+
+define void @test_low_ne(i64 %a, i64 %b) {
+; CHECK-LABEL: @test_low_ne
+; CHECK: [[TMP1:%.*]] = icmp slt i64 %a, %b
+; CHECK: br i1 [[TMP1]], label %normal, label %unreached
+  %eq = icmp eq i64 %a, %b
+  %slt = icmp slt i64 %a, %b
+  %. = select i1 %slt, i32 -1, i32 1
+  %result = select i1 %eq, i32 0, i32 %.
+  %cmp = icmp ne i32 %result, -1
+  br i1 %cmp, label %unreached, label %normal
+normal:
+  ret void
+unreached:
+  call void @use(i32 %result)
+  ret void
+}
+
+define void @test_low_eq(i64 %a, i64 %b) {
+; CHECK-LABEL: @test_low_eq
+; CHECK: [[TMP1:%.*]] = icmp slt i64 %a, %b
+; CHECK: br i1 [[TMP1]], label %unreached, label %normal
+  %eq = icmp eq i64 %a, %b
+  %slt = icmp slt i64 %a, %b
+  %. = select i1 %slt, i32 -1, i32 1
+  %result = select i1 %eq, i32 0, i32 %.
+  %cmp = icmp eq i32 %result, -1
+  br i1 %cmp, label %unreached, label %normal
+normal:
+  ret void
+unreached:
+  call void @use(i32 %result)
+  ret void
+}
+
+define void @test_mid_sgt(i64 %a, i64 %b) {
+; CHECK-LABEL: @test_mid_sgt
+; CHECK: [[TMP1:%.*]] = icmp sgt i64 %a, %b
+; CHECK: br i1 [[TMP1]], label %unreached, label %normal
+  %eq = icmp eq i64 %a, %b
+  %slt = icmp slt i64 %a, %b
+  %. = select i1 %slt, i32 -1, i32 1
+  %result = select i1 %eq, i32 0, i32 %.
+  %cmp = icmp sgt i32 %result, 0
+  br i1 %cmp, label %unreached, label %normal
+normal:
+  ret void
+unreached:
+  call void @use(i32 %result)
+  ret void
+}
+
+define void @test_mid_slt(i64 %a, i64 %b) {
+; CHECK-LABEL: @test_mid_slt
+; CHECK: [[TMP1:%.*]] = icmp slt i64 %a, %b
+; CHECK: br i1 [[TMP1]], label %unreached, label %normal
+  %eq = icmp eq i64 %a, %b
+  %slt = icmp slt i64 %a, %b
+  %. = select i1 %slt, i32 -1, i32 1
+  %result = select i1 %eq, i32 0, i32 %.
+  %cmp = icmp slt i32 %result, 0
+  br i1 %cmp, label %unreached, label %normal
+normal:
+  ret void
+unreached:
+  call void @use(i32 %result)
+  ret void
+}
+
+define void @test_mid_sge(i64 %a, i64 %b) {
+; CHECK-LABEL: @test_mid_sge
+; CHECK: [[TMP1:%.*]] = icmp slt i64 %a, %b
+; CHECK: br i1 [[TMP1]], label %normal, label %unreached
+  %eq = icmp eq i64 %a, %b
+  %slt = icmp slt i64 %a, %b
+  %. = select i1 %slt, i32 -1, i32 1
+  %result = select i1 %eq, i32 0, i32 %.
+  %cmp = icmp sge i32 %result, 0
+  br i1 %cmp, label %unreached, label %normal
+normal:
+  ret void
+unreached:
+  call void @use(i32 %result)
+  ret void
+}
+
+define void @test_mid_sle(i64 %a, i64 %b) {
+; CHECK-LABEL: @test_mid_sle
+; CHECK: [[TMP1:%.*]] = icmp sgt i64 %a, %b
+; CHECK: br i1 [[TMP1]], label %normal, label %unreached
+  %eq = icmp eq i64 %a, %b
+  %slt = icmp slt i64 %a, %b
+  %. = select i1 %slt, i32 -1, i32 1
+  %result = select i1 %eq, i32 0, i32 %.
+  %cmp = icmp sle i32 %result, 0
+  br i1 %cmp, label %unreached, label %normal
+normal:
+  ret void
+unreached:
+  call void @use(i32 %result)
+  ret void
+}
+
+define void @test_mid_ne(i64 %a, i64 %b) {
+; CHECK-LABEL: @test_mid_ne
+; CHECK: [[TMP1:%.*]] = icmp eq i64 %a, %b
+; CHECK: br i1 [[TMP1]], label %normal, label %unreached
+  %eq = icmp eq i64 %a, %b
+  %slt = icmp slt i64 %a, %b
+  %. = select i1 %slt, i32 -1, i32 1
+  %result = select i1 %eq, i32 0, i32 %.
+  %cmp = icmp ne i32 %result, 0
+  br i1 %cmp, label %unreached, label %normal
+normal:
+  ret void
+unreached:
+  call void @use(i32 %result)
+  ret void
+}
+
+define void @test_mid_eq(i64 %a, i64 %b) {
+; CHECK-LABEL: @test_mid_eq
+; CHECK: icmp eq i64 %a, %b
+; CHECK: br i1 %eq, label %unreached, label %normal
+  %eq = icmp eq i64 %a, %b
+  %slt = icmp slt i64 %a, %b
+  %. = select i1 %slt, i32 -1, i32 1
+  %result = select i1 %eq, i32 0, i32 %.
+  %cmp = icmp eq i32 %result, 0
+  br i1 %cmp, label %unreached, label %normal
+normal:
+  ret void
+unreached:
+  call void @use(i32 %result)
+  ret void
+}
+
+define void @test_high_sgt(i64 %a, i64 %b) {
+; CHECK-LABEL: @test_high_sgt
+; CHECK: br i1 false, label %unreached, label %normal
+  %eq = icmp eq i64 %a, %b
+  %slt = icmp slt i64 %a, %b
+  %. = select i1 %slt, i32 -1, i32 1
+  %result = select i1 %eq, i32 0, i32 %.
+  %cmp = icmp sgt i32 %result, 1
+  br i1 %cmp, label %unreached, label %normal
+normal:
+  ret void
+unreached:
+  call void @use(i32 %result)
+  ret void
+}
+
+define void @test_high_slt(i64 %a, i64 %b) {
+; CHECK-LABEL: @test_high_slt
+; CHECK: [[TMP1:%.*]] = icmp sgt i64 %a, %b
+; CHECK: br i1 [[TMP1]], label %normal, label %unreached
+  %eq = icmp eq i64 %a, %b
+  %slt = icmp slt i64 %a, %b
+  %. = select i1 %slt, i32 -1, i32 1
+  %result = select i1 %eq, i32 0, i32 %.
+  %cmp = icmp slt i32 %result, 1
+  br i1 %cmp, label %unreached, label %normal
+normal:
+  ret void
+unreached:
+  call void @use(i32 %result)
+  ret void
+}
+
+define void @test_high_sge(i64 %a, i64 %b) {
+; CHECK-LABEL: @test_high_sge
+; CHECK: [[TMP1:%.*]] = icmp sgt i64 %a, %b
+; CHECK: br i1 [[TMP1]], label %unreached, label %normal
+  %eq = icmp eq i64 %a, %b
+  %slt = icmp slt i64 %a, %b
+  %. = select i1 %slt, i32 -1, i32 1
+  %result = select i1 %eq, i32 0, i32 %.
+  %cmp = icmp sge i32 %result, 1
+  br i1 %cmp, label %unreached, label %normal
+normal:
+  ret void
+unreached:
+  call void @use(i32 %result)
+  ret void
+}
+
+define void @test_high_sle(i64 %a, i64 %b) {
+; CHECK-LABEL: @test_high_sle
+; CHECK: br i1 true, label %unreached, label %normal
+  %eq = icmp eq i64 %a, %b
+  %slt = icmp slt i64 %a, %b
+  %. = select i1 %slt, i32 -1, i32 1
+  %result = select i1 %eq, i32 0, i32 %.
+  %cmp = icmp sle i32 %result, 1
+  br i1 %cmp, label %unreached, label %normal
+normal:
+  ret void
+unreached:
+  call void @use(i32 %result)
+  ret void
+}
+
+define void @test_high_ne(i64 %a, i64 %b) {
+; CHECK-LABEL: @test_high_ne
+; CHECK: [[TMP1:%.*]] = icmp sgt i64 %a, %b
+; CHECK: br i1 [[TMP1]], label %normal, label %unreached
+  %eq = icmp eq i64 %a, %b
+  %slt = icmp slt i64 %a, %b
+  %. = select i1 %slt, i32 -1, i32 1
+  %result = select i1 %eq, i32 0, i32 %.
+  %cmp = icmp ne i32 %result, 1
+  br i1 %cmp, label %unreached, label %normal
+normal:
+  ret void
+unreached:
+  call void @use(i32 %result)
+  ret void
+}
+
+define void @test_high_eq(i64 %a, i64 %b) {
+; CHECK-LABEL: @test_high_eq
+; CHECK: [[TMP1:%.*]] = icmp sgt i64 %a, %b
+; CHECK: br i1 [[TMP1]], label %unreached, label %normal
+  %eq = icmp eq i64 %a, %b
+  %slt = icmp slt i64 %a, %b
+  %. = select i1 %slt, i32 -1, i32 1
+  %result = select i1 %eq, i32 0, i32 %.
+  %cmp = icmp eq i32 %result, 1
+  br i1 %cmp, label %unreached, label %normal
+normal:
+  ret void
+unreached:
+  call void @use(i32 %result)
+  ret void
+}
+
+; These five make sure we didn't accidentally hard code one of the
+; produced values
+
+define void @non_standard_low(i64 %a, i64 %b) {
+; CHECK-LABEL: @non_standard_low
+; CHECK: [[TMP1:%.*]] = icmp slt i64 %a, %b
+; CHECK: br i1 [[TMP1]], label %unreached, label %normal
+  %eq = icmp eq i64 %a, %b
+  %slt = icmp slt i64 %a, %b
+  %. = select i1 %slt, i32 -3, i32 -1
+  %result = select i1 %eq, i32 -2, i32 %.
+  %cmp = icmp eq i32 %result, -3
+  br i1 %cmp, label %unreached, label %normal
+normal:
+  ret void
+unreached:
+  call void @use(i32 %result)
+  ret void
+}
+
+define void @non_standard_mid(i64 %a, i64 %b) {
+; CHECK-LABEL: @non_standard_mid
+; CHECK: icmp eq i64 %a, %b
+; CHECK: br i1 %eq, label %unreached, label %normal
+  %eq = icmp eq i64 %a, %b
+  %slt = icmp slt i64 %a, %b
+  %. = select i1 %slt, i32 -3, i32 -1
+  %result = select i1 %eq, i32 -2, i32 %.
+  %cmp = icmp eq i32 %result, -2
+  br i1 %cmp, label %unreached, label %normal
+normal:
+  ret void
+unreached:
+  call void @use(i32 %result)
+  ret void
+}
+
+define void @non_standard_high(i64 %a, i64 %b) {
+; CHECK-LABEL: @non_standard_high
+; CHECK: [[TMP1:%.*]] = icmp sgt i64 %a, %b
+; CHECK: br i1 [[TMP1]], label %unreached, label %normal
+  %eq = icmp eq i64 %a, %b
+  %slt = icmp slt i64 %a, %b
+  %. = select i1 %slt, i32 -3, i32 -1
+  %result = select i1 %eq, i32 -2, i32 %.
+  %cmp = icmp eq i32 %result, -1
+  br i1 %cmp, label %unreached, label %normal
+normal:
+  ret void
+unreached:
+  call void @use(i32 %result)
+  ret void
+}
+
+define void @non_standard_bound1(i64 %a, i64 %b) {
+; CHECK-LABEL: @non_standard_bound1
+; CHECK: br i1 false, label %unreached, label %normal
+  %eq = icmp eq i64 %a, %b
+  %slt = icmp slt i64 %a, %b
+  %. = select i1 %slt, i32 -3, i32 -1
+  %result = select i1 %eq, i32 -2, i32 %.
+  %cmp = icmp eq i32 %result, -20
+  br i1 %cmp, label %unreached, label %normal
+normal:
+  ret void
+unreached:
+  call void @use(i32 %result)
+  ret void
+}
+
+define void @non_standard_bound2(i64 %a, i64 %b) {
+; CHECK-LABEL: @non_standard_bound2
+; CHECK: br i1 false, label %unreached, label %normal
+  %eq = icmp eq i64 %a, %b
+  %slt = icmp slt i64 %a, %b
+  %. = select i1 %slt, i32 -3, i32 -1
+  %result = select i1 %eq, i32 -2, i32 %.
+  %cmp = icmp eq i32 %result, 0
+  br i1 %cmp, label %unreached, label %normal
+normal:
+  ret void
+unreached:
+  call void @use(i32 %result)
+  ret void
+}

Added: llvm/trunk/test/Transforms/InstCombine/compare-alloca.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/compare-alloca.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/compare-alloca.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/compare-alloca.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,97 @@
+; RUN: opt -instcombine -S %s | FileCheck %s
+target datalayout = "p:32:32"
+
+
+define i1 @alloca_argument_compare(i64* %arg) {
+  %alloc = alloca i64
+  %cmp = icmp eq i64* %arg, %alloc
+  ret i1 %cmp
+  ; CHECK-LABEL: alloca_argument_compare
+  ; CHECK: ret i1 false
+}
+
+define i1 @alloca_argument_compare_swapped(i64* %arg) {
+  %alloc = alloca i64
+  %cmp = icmp eq i64* %alloc, %arg
+  ret i1 %cmp
+  ; CHECK-LABEL: alloca_argument_compare_swapped
+  ; CHECK: ret i1 false
+}
+
+define i1 @alloca_argument_compare_ne(i64* %arg) {
+  %alloc = alloca i64
+  %cmp = icmp ne i64* %arg, %alloc
+  ret i1 %cmp
+  ; CHECK-LABEL: alloca_argument_compare_ne
+  ; CHECK: ret i1 true
+}
+
+define i1 @alloca_argument_compare_derived_ptrs(i64* %arg, i64 %x) {
+  %alloc = alloca i64, i64 8
+  %p = getelementptr i64, i64* %arg, i64 %x
+  %q = getelementptr i64, i64* %alloc, i64 3
+  %cmp = icmp eq i64* %p, %q
+  ret i1 %cmp
+  ; CHECK-LABEL: alloca_argument_compare_derived_ptrs
+  ; CHECK: ret i1 false
+}
+
+declare void @escape(i64*)
+define i1 @alloca_argument_compare_escaped_alloca(i64* %arg) {
+  %alloc = alloca i64
+  call void @escape(i64* %alloc)
+  %cmp = icmp eq i64* %alloc, %arg
+  ret i1 %cmp
+  ; CHECK-LABEL: alloca_argument_compare_escaped_alloca
+  ; CHECK: %cmp = icmp eq i64* %alloc, %arg
+  ; CHECK: ret i1 %cmp
+}
+
+declare void @check_compares(i1, i1)
+define void @alloca_argument_compare_two_compares(i64* %p) {
+  %q = alloca i64, i64 8
+  %r = getelementptr i64, i64* %p, i64 1
+  %s = getelementptr i64, i64* %q, i64 2
+  %cmp1 = icmp eq i64* %p, %q
+  %cmp2 = icmp eq i64* %r, %s
+  call void @check_compares(i1 %cmp1, i1 %cmp2)
+  ret void
+  ; We will only fold if there is a single cmp.
+  ; CHECK-LABEL: alloca_argument_compare_two_compares
+  ; CHECK: call void @check_compares(i1 %cmp1, i1 %cmp2)
+}
+
+define i1 @alloca_argument_compare_escaped_through_store(i64* %arg, i64** %ptr) {
+  %alloc = alloca i64
+  %cmp = icmp eq i64* %alloc, %arg
+  %p = getelementptr i64, i64* %alloc, i64 1
+  store i64* %p, i64** %ptr
+  ret i1 %cmp
+  ; CHECK-LABEL: alloca_argument_compare_escaped_through_store
+  ; CHECK: %cmp = icmp eq i64* %alloc, %arg
+  ; CHECK: ret i1 %cmp
+}
+
+declare void @llvm.lifetime.start.p0i8(i64, i8* nocapture)
+declare void @llvm.lifetime.end.p0i8(i64, i8* nocapture)
+define i1 @alloca_argument_compare_benign_instrs(i8* %arg) {
+  %alloc = alloca i8
+  call void @llvm.lifetime.start.p0i8(i64 1, i8* %alloc)
+  %cmp = icmp eq i8* %arg, %alloc
+  %x = load i8, i8* %arg
+  store i8 %x, i8* %alloc
+  call void @llvm.lifetime.end.p0i8(i64 1, i8* %alloc)
+  ret i1 %cmp
+  ; CHECK-LABEL: alloca_argument_compare_benign_instrs
+  ; CHECK: ret i1 false
+}
+
+declare i64* @allocator()
+define i1 @alloca_call_compare() {
+  %p = alloca i64
+  %q = call i64* @allocator()
+  %cmp = icmp eq i64* %p, %q
+  ret i1 %cmp
+  ; CHECK-LABEL: alloca_call_compare
+  ; CHECK: ret i1 false
+}

Added: llvm/trunk/test/Transforms/InstCombine/compare-signs.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/compare-signs.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/compare-signs.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/compare-signs.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,150 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt -instcombine -S < %s | FileCheck %s
+
+; PR5438
+
+define i32 @test1(i32 %a, i32 %b) nounwind readnone {
+; CHECK-LABEL: @test1(
+; CHECK-NEXT:    [[TMP1:%.*]] = xor i32 [[B:%.*]], [[A:%.*]]
+; CHECK-NEXT:    [[DOTLOBIT:%.*]] = lshr i32 [[TMP1]], 31
+; CHECK-NEXT:    [[DOTLOBIT_NOT:%.*]] = xor i32 [[DOTLOBIT]], 1
+; CHECK-NEXT:    ret i32 [[DOTLOBIT_NOT]]
+;
+  %t0 = icmp sgt i32 %a, -1
+  %t1 = icmp slt i32 %b, 0
+  %t2 = xor i1 %t1, %t0
+  %t3 = zext i1 %t2 to i32
+  ret i32 %t3
+}
+
+; TODO: This optimizes partially but not all the way.
+define i32 @test2(i32 %a, i32 %b) nounwind readnone {
+; CHECK-LABEL: @test2(
+; CHECK-NEXT:    [[TMP1:%.*]] = xor i32 [[A:%.*]], [[B:%.*]]
+; CHECK-NEXT:    [[TMP2:%.*]] = lshr i32 [[TMP1]], 3
+; CHECK-NEXT:    [[DOTLOBIT:%.*]] = and i32 [[TMP2]], 1
+; CHECK-NEXT:    [[TMP3:%.*]] = xor i32 [[DOTLOBIT]], 1
+; CHECK-NEXT:    ret i32 [[TMP3]]
+;
+  %t0 = and i32 %a, 8
+  %t1 = and i32 %b, 8
+  %t2 = icmp eq i32 %t0, %t1
+  %t3 = zext i1 %t2 to i32
+  ret i32 %t3
+}
+
+define i32 @test3(i32 %a, i32 %b) nounwind readnone {
+; CHECK-LABEL: @test3(
+; CHECK-NEXT:    [[T2_UNSHIFTED:%.*]] = xor i32 [[A:%.*]], [[B:%.*]]
+; CHECK-NEXT:    [[T2_UNSHIFTED_LOBIT:%.*]] = lshr i32 [[T2_UNSHIFTED]], 31
+; CHECK-NEXT:    [[T2_UNSHIFTED_LOBIT_NOT:%.*]] = xor i32 [[T2_UNSHIFTED_LOBIT]], 1
+; CHECK-NEXT:    ret i32 [[T2_UNSHIFTED_LOBIT_NOT]]
+;
+  %t0 = lshr i32 %a, 31
+  %t1 = lshr i32 %b, 31
+  %t2 = icmp eq i32 %t0, %t1
+  %t3 = zext i1 %t2 to i32
+  ret i32 %t3
+}
+
+; TODO this should optimize but doesn't due to missing vector support in InstCombiner::foldICmpEquality.
+define <2 x i32> @test3vec(<2 x i32> %a, <2 x i32> %b) nounwind readnone {
+; CHECK-LABEL: @test3vec(
+; CHECK-NEXT:    [[T0:%.*]] = lshr <2 x i32> [[A:%.*]], <i32 31, i32 31>
+; CHECK-NEXT:    [[T1:%.*]] = lshr <2 x i32> [[B:%.*]], <i32 31, i32 31>
+; CHECK-NEXT:    [[T2:%.*]] = icmp eq <2 x i32> [[T0]], [[T1]]
+; CHECK-NEXT:    [[T3:%.*]] = zext <2 x i1> [[T2]] to <2 x i32>
+; CHECK-NEXT:    ret <2 x i32> [[T3]]
+;
+  %t0 = lshr <2 x i32> %a, <i32 31, i32 31>
+  %t1 = lshr <2 x i32> %b, <i32 31, i32 31>
+  %t2 = icmp eq <2 x i32> %t0, %t1
+  %t3 = zext <2 x i1> %t2 to <2 x i32>
+  ret <2 x i32> %t3
+}
+
+; Variation on @test3: checking the 2nd bit in a situation where the 5th bit
+; is one, not zero.
+define i32 @test3i(i32 %a, i32 %b) nounwind readnone {
+; CHECK-LABEL: @test3i(
+; CHECK-NEXT:    [[T01:%.*]] = xor i32 [[A:%.*]], [[B:%.*]]
+; CHECK-NEXT:    [[TMP1:%.*]] = lshr i32 [[T01]], 31
+; CHECK-NEXT:    [[T4:%.*]] = xor i32 [[TMP1]], 1
+; CHECK-NEXT:    ret i32 [[T4]]
+;
+  %t0 = lshr i32 %a, 29
+  %t1 = lshr i32 %b, 29
+  %t2 = or i32 %t0, 35
+  %t3 = or i32 %t1, 35
+  %t4 = icmp eq i32 %t2, %t3
+  %t5 = zext i1 %t4 to i32
+  ret i32 %t5
+}
+
+define i1 @test4a(i32 %a) {
+; CHECK-LABEL: @test4a(
+; CHECK-NEXT:    [[C:%.*]] = icmp slt i32 [[A:%.*]], 1
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %l = ashr i32 %a, 31
+  %na = sub i32 0, %a
+  %r = lshr i32 %na, 31
+  %signum = or i32 %l, %r
+  %c = icmp slt i32 %signum, 1
+  ret i1 %c
+}
+
+define <2 x i1> @test4a_vec(<2 x i32> %a) {
+; CHECK-LABEL: @test4a_vec(
+; CHECK-NEXT:    [[C:%.*]] = icmp slt <2 x i32> [[A:%.*]], <i32 1, i32 1>
+; CHECK-NEXT:    ret <2 x i1> [[C]]
+;
+  %l = ashr <2 x i32> %a, <i32 31, i32 31>
+  %na = sub <2 x i32> zeroinitializer, %a
+  %r = lshr <2 x i32> %na, <i32 31, i32 31>
+  %signum = or <2 x i32> %l, %r
+  %c = icmp slt <2 x i32> %signum, <i32 1, i32 1>
+  ret <2 x i1> %c
+}
+
+define i1 @test4b(i64 %a) {
+; CHECK-LABEL: @test4b(
+; CHECK-NEXT:    [[C:%.*]] = icmp slt i64 [[A:%.*]], 1
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %l = ashr i64 %a, 63
+  %na = sub i64 0, %a
+  %r = lshr i64 %na, 63
+  %signum = or i64 %l, %r
+  %c = icmp slt i64 %signum, 1
+  ret i1 %c
+}
+
+define i1 @test4c(i64 %a) {
+; CHECK-LABEL: @test4c(
+; CHECK-NEXT:    [[C:%.*]] = icmp slt i64 [[A:%.*]], 1
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %l = ashr i64 %a, 63
+  %na = sub i64 0, %a
+  %r = lshr i64 %na, 63
+  %signum = or i64 %l, %r
+  %signum.trunc = trunc i64 %signum to i32
+  %c = icmp slt i32 %signum.trunc, 1
+  ret i1 %c
+}
+
+define <2 x i1> @test4c_vec(<2 x i64> %a) {
+; CHECK-LABEL: @test4c_vec(
+; CHECK-NEXT:    [[C:%.*]] = icmp slt <2 x i64> [[A:%.*]], <i64 1, i64 1>
+; CHECK-NEXT:    ret <2 x i1> [[C]]
+;
+  %l = ashr <2 x i64> %a, <i64 63, i64 63>
+  %na = sub <2 x i64> zeroinitializer, %a
+  %r = lshr <2 x i64> %na, <i64 63, i64 63>
+  %signum = or <2 x i64> %l, %r
+  %signum.trunc = trunc <2 x i64> %signum to <2 x i32>
+  %c = icmp slt <2 x i32> %signum.trunc, <i32 1, i32 1>
+  ret <2 x i1> %c
+}
+

Added: llvm/trunk/test/Transforms/InstCombine/compare-udiv.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/compare-udiv.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/compare-udiv.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/compare-udiv.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 -instcombine -S < %s | FileCheck %s
+
+define i1 @test1(i32 %n, i32 %d) {
+; CHECK-LABEL: @test1(
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp ugt i32 %d, %n
+; CHECK-NEXT:    ret i1 [[CMP1]]
+;
+  %div = udiv i32 %n, %d
+  %cmp1 = icmp eq i32 %div, 0
+  ret i1 %cmp1
+}
+
+define <2 x i1> @test1vec(<2 x i32> %n, <2 x i32> %d) {
+; CHECK-LABEL: @test1vec(
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp ugt <2 x i32> %d, %n
+; CHECK-NEXT:    ret <2 x i1> [[CMP1]]
+;
+  %div = udiv <2 x i32> %n, %d
+  %cmp1 = icmp eq <2 x i32> %div, zeroinitializer
+  ret <2 x i1> %cmp1
+}
+
+define i1 @test2(i32 %d) {
+; CHECK-LABEL: @test2(
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp ugt i32 %d, 64
+; CHECK-NEXT:    ret i1 [[CMP1]]
+;
+  %div = udiv i32 64, %d
+  %cmp1 = icmp eq i32 %div, 0
+  ret i1 %cmp1
+}
+
+define <2 x i1> @test2vec(<2 x i32> %d) {
+; CHECK-LABEL: @test2vec(
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp ugt <2 x i32> %d, <i32 64, i32 63>
+; CHECK-NEXT:    ret <2 x i1> [[CMP1]]
+;
+  %div = udiv <2 x i32> <i32 64, i32 63>, %d
+  %cmp1 = icmp eq <2 x i32> %div, zeroinitializer
+  ret <2 x i1> %cmp1
+}
+
+define i1 @test3(i32 %n, i32 %d) {
+; CHECK-LABEL: @test3(
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp ule i32 %d, %n
+; CHECK-NEXT:    ret i1 [[CMP1]]
+;
+  %div = udiv i32 %n, %d
+  %cmp1 = icmp ne i32 %div, 0
+  ret i1 %cmp1
+}
+
+define <2 x i1> @test3vec(<2 x i32> %n, <2 x i32> %d) {
+; CHECK-LABEL: @test3vec(
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp ule <2 x i32> %d, %n
+; CHECK-NEXT:    ret <2 x i1> [[CMP1]]
+;
+  %div = udiv <2 x i32> %n, %d
+  %cmp1 = icmp ne <2 x i32> %div, zeroinitializer
+  ret <2 x i1> %cmp1
+}
+
+define i1 @test4(i32 %d) {
+; CHECK-LABEL: @test4(
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp ult i32 %d, 65
+; CHECK-NEXT:    ret i1 [[CMP1]]
+;
+  %div = udiv i32 64, %d
+  %cmp1 = icmp ne i32 %div, 0
+  ret i1 %cmp1
+}
+
+define <2 x i1> @test4vec(<2 x i32> %d) {
+; CHECK-LABEL: @test4vec(
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp ult <2 x i32> %d, <i32 65, i32 66>
+; CHECK-NEXT:    ret <2 x i1> [[CMP1]]
+;
+  %div = udiv <2 x i32> <i32 64, i32 65>, %d
+  %cmp1 = icmp ne <2 x i32> %div, zeroinitializer
+  ret <2 x i1> %cmp1
+}
+
+define i1 @test5(i32 %d) {
+; CHECK-LABEL: @test5(
+; CHECK-NEXT:    ret i1 true
+;
+  %div = udiv i32 -1, %d
+  %cmp1 = icmp ne i32 %div, 0
+  ret i1 %cmp1
+}
+
+define <2 x i1> @test5vec(<2 x i32> %d) {
+; CHECK-LABEL: @test5vec(
+; CHECK-NEXT:    ret <2 x i1> <i1 true, i1 true>
+;
+  %div = udiv <2 x i32> <i32 -1, i32 -1>, %d
+  %cmp1 = icmp ne <2 x i32> %div, zeroinitializer
+  ret <2 x i1> %cmp1
+}
+
+define i1 @test6(i32 %d) {
+; CHECK-LABEL: @test6(
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp ult i32 %d, 6
+; CHECK-NEXT:    ret i1 [[CMP1]]
+;
+  %div = udiv i32 5, %d
+  %cmp1 = icmp ugt i32 %div, 0
+  ret i1 %cmp1
+}
+
+define <2 x i1> @test6vec(<2 x i32> %d) {
+; CHECK-LABEL: @test6vec(
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp ult <2 x i32> %d, <i32 6, i32 6>
+; CHECK-NEXT:    ret <2 x i1> [[CMP1]]
+;
+  %div = udiv <2 x i32> <i32 5, i32 5>, %d
+  %cmp1 = icmp ugt <2 x i32> %div, zeroinitializer
+  ret <2 x i1> %cmp1
+}
+
+; (icmp ugt (udiv C1, X), C1) -> false.
+define i1 @test7(i32 %d) {
+; CHECK-LABEL: @test7(
+; CHECK-NEXT:    ret i1 false
+;
+  %div = udiv i32 8, %d
+  %cmp1 = icmp ugt i32 %div, 8
+  ret i1 %cmp1
+}
+
+define <2 x i1> @test7vec(<2 x i32> %d) {
+; CHECK-LABEL: @test7vec(
+; CHECK-NEXT:    ret <2 x i1> zeroinitializer
+;
+  %div = udiv <2 x i32> <i32 8, i32 8>, %d
+  %cmp1 = icmp ugt <2 x i32> %div, <i32 8, i32 8>
+  ret <2 x i1> %cmp1
+}
+
+define i1 @test8(i32 %d) {
+; CHECK-LABEL: @test8(
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp ult i32 %d, 2
+; CHECK-NEXT:    ret i1 [[CMP1]]
+;
+  %div = udiv i32 4, %d
+  %cmp1 = icmp ugt i32 %div, 3
+  ret i1 %cmp1
+}
+
+define <2 x i1> @test8vec(<2 x i32> %d) {
+; CHECK-LABEL: @test8vec(
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp ult <2 x i32> %d, <i32 2, i32 2>
+; CHECK-NEXT:    ret <2 x i1> [[CMP1]]
+;
+  %div = udiv <2 x i32> <i32 4, i32 4>, %d
+  %cmp1 = icmp ugt <2 x i32> %div, <i32 3, i32 3>
+  ret <2 x i1> %cmp1
+}
+
+define i1 @test9(i32 %d) {
+; CHECK-LABEL: @test9(
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp ult i32 %d, 2
+; CHECK-NEXT:    ret i1 [[CMP1]]
+;
+  %div = udiv i32 4, %d
+  %cmp1 = icmp ugt i32 %div, 2
+  ret i1 %cmp1
+}
+
+define <2 x i1> @test9vec(<2 x i32> %d) {
+; CHECK-LABEL: @test9vec(
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp ult <2 x i32> %d, <i32 2, i32 2>
+; CHECK-NEXT:    ret <2 x i1> [[CMP1]]
+;
+  %div = udiv <2 x i32> <i32 4, i32 4>, %d
+  %cmp1 = icmp ugt <2 x i32> %div, <i32 2, i32 2>
+  ret <2 x i1> %cmp1
+}
+
+define i1 @test10(i32 %d) {
+; CHECK-LABEL: @test10(
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp ult i32 %d, 3
+; CHECK-NEXT:    ret i1 [[CMP1]]
+;
+  %div = udiv i32 4, %d
+  %cmp1 = icmp ugt i32 %div, 1
+  ret i1 %cmp1
+}
+
+define <2 x i1> @test10vec(<2 x i32> %d) {
+; CHECK-LABEL: @test10vec(
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp ult <2 x i32> %d, <i32 3, i32 3>
+; CHECK-NEXT:    ret <2 x i1> [[CMP1]]
+;
+  %div = udiv <2 x i32> <i32 4, i32 4>, %d
+  %cmp1 = icmp ugt <2 x i32> %div, <i32 1, i32 1>
+  ret <2 x i1> %cmp1
+}
+
+define i1 @test11(i32 %d) {
+; CHECK-LABEL: @test11(
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp ugt i32 %d, 4
+; CHECK-NEXT:    ret i1 [[CMP1]]
+;
+  %div = udiv i32 4, %d
+  %cmp1 = icmp ult i32 %div, 1
+  ret i1 %cmp1
+}
+
+define <2 x i1> @test11vec(<2 x i32> %d) {
+; CHECK-LABEL: @test11vec(
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp ugt <2 x i32> %d, <i32 4, i32 4>
+; CHECK-NEXT:    ret <2 x i1> [[CMP1]]
+;
+  %div = udiv <2 x i32> <i32 4, i32 4>, %d
+  %cmp1 = icmp ult <2 x i32> %div, <i32 1, i32 1>
+  ret <2 x i1> %cmp1
+}
+
+define i1 @test12(i32 %d) {
+; CHECK-LABEL: @test12(
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp ugt i32 %d, 2
+; CHECK-NEXT:    ret i1 [[CMP1]]
+;
+  %div = udiv i32 4, %d
+  %cmp1 = icmp ult i32 %div, 2
+  ret i1 %cmp1
+}
+
+define <2 x i1> @test12vec(<2 x i32> %d) {
+; CHECK-LABEL: @test12vec(
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp ugt <2 x i32> %d, <i32 2, i32 2>
+; CHECK-NEXT:    ret <2 x i1> [[CMP1]]
+;
+  %div = udiv <2 x i32> <i32 4, i32 4>, %d
+  %cmp1 = icmp ult <2 x i32> %div, <i32 2, i32 2>
+  ret <2 x i1> %cmp1
+}
+
+define i1 @test13(i32 %d) {
+; CHECK-LABEL: @test13(
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp ugt i32 %d, 1
+; CHECK-NEXT:    ret i1 [[CMP1]]
+;
+  %div = udiv i32 4, %d
+  %cmp1 = icmp ult i32 %div, 3
+  ret i1 %cmp1
+}
+
+define <2 x i1> @test13vec(<2 x i32> %d) {
+; CHECK-LABEL: @test13vec(
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp ugt <2 x i32> %d, <i32 1, i32 1>
+; CHECK-NEXT:    ret <2 x i1> [[CMP1]]
+;
+  %div = udiv <2 x i32> <i32 4, i32 4>, %d
+  %cmp1 = icmp ult <2 x i32> %div, <i32 3, i32 3>
+  ret <2 x i1> %cmp1
+}
+
+define i1 @test14(i32 %d) {
+; CHECK-LABEL: @test14(
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp ugt i32 %d, 1
+; CHECK-NEXT:    ret i1 [[CMP1]]
+;
+  %div = udiv i32 4, %d
+  %cmp1 = icmp ult i32 %div, 4
+  ret i1 %cmp1
+}
+
+define <2 x i1> @test14vec(<2 x i32> %d) {
+; CHECK-LABEL: @test14vec(
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp ugt <2 x i32> %d, <i32 1, i32 1>
+; CHECK-NEXT:    ret <2 x i1> [[CMP1]]
+;
+  %div = udiv <2 x i32> <i32 4, i32 4>, %d
+  %cmp1 = icmp ult <2 x i32> %div, <i32 4, i32 4>
+  ret <2 x i1> %cmp1
+}
+
+; icmp ugt X, UINT_MAX -> false.
+define i1 @test15(i32 %d) {
+; CHECK-LABEL: @test15(
+; CHECK-NEXT:    ret i1 false
+;
+  %div = udiv i32 4, %d
+  %cmp1 = icmp ugt i32 %div, -1
+  ret i1 %cmp1
+}
+
+define <2 x i1> @test15vec(<2 x i32> %d) {
+; CHECK-LABEL: @test15vec(
+; CHECK-NEXT:    ret <2 x i1> zeroinitializer
+;
+  %div = udiv <2 x i32> <i32 4, i32 4>, %d
+  %cmp1 = icmp ugt <2 x i32> %div, <i32 -1, i32 -1>
+  ret <2 x i1> %cmp1
+}
+
+; icmp ult X, UINT_MAX -> true.
+define i1 @test16(i32 %d) {
+; CHECK-LABEL: @test16(
+; CHECK-NEXT:    ret i1 true
+;
+  %div = udiv i32 4, %d
+  %cmp1 = icmp ult i32 %div, -1
+  ret i1 %cmp1
+}
+
+define <2 x i1> @test16vec(<2 x i32> %d) {
+; CHECK-LABEL: @test16vec(
+; CHECK-NEXT:    ret <2 x i1> <i1 true, i1 true>
+;
+  %div = udiv <2 x i32> <i32 4, i32 4>, %d
+  %cmp1 = icmp ult <2 x i32> %div, <i32 -1, i32 -1>
+  ret <2 x i1> %cmp1
+}
+

Added: llvm/trunk/test/Transforms/InstCombine/compare-unescaped.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/compare-unescaped.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/compare-unescaped.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/compare-unescaped.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,164 @@
+; RUN: opt -instcombine -S < %s | FileCheck %s
+
+ at gp = global i32* null, align 8
+
+declare i8* @malloc(i64) #1
+
+define i1 @compare_global_trivialeq() {
+  %m = call i8* @malloc(i64 4)
+  %bc = bitcast i8* %m to i32*
+  %lgp = load i32*, i32** @gp, align 8
+  %cmp = icmp eq i32* %bc, %lgp
+  ret i1 %cmp
+; CHECK-LABEL: compare_global_trivialeq
+; CHECK: ret i1 false
+}
+
+define i1 @compare_global_trivialne() {
+  %m = call i8* @malloc(i64 4)
+  %bc = bitcast i8* %m to i32*
+  %lgp = load i32*, i32** @gp, align 8
+  %cmp = icmp ne i32* %bc, %lgp
+  ret i1 %cmp
+; CHECK-LABEL: compare_global_trivialne
+; CHECK: ret i1 true
+}
+
+
+; Although the %m is marked nocapture in the deopt operand in call to function f,
+; we cannot remove the alloc site: call to malloc
+; The comparison should fold to false irrespective of whether the call to malloc can be elided or not
+declare void @f()
+define i1 @compare_and_call_with_deopt() {
+; CHECK-LABEL: compare_and_call_with_deopt
+  %m = call i8* @malloc(i64 24)
+  %bc = bitcast i8* %m to i32*
+  %lgp = load i32*, i32** @gp, align 8, !nonnull !0
+  %cmp = icmp eq i32* %lgp, %bc
+  tail call void @f() [ "deopt"(i8* %m) ]
+  ret i1 %cmp
+; CHECK: ret i1 false
+}
+
+; Same functon as above with deopt operand in function f, but comparison is NE
+define i1 @compare_ne_and_call_with_deopt() {
+; CHECK-LABEL: compare_ne_and_call_with_deopt
+  %m = call i8* @malloc(i64 24)
+  %bc = bitcast i8* %m to i32*
+  %lgp = load i32*, i32** @gp, align 8, !nonnull !0
+  %cmp = icmp ne i32* %lgp, %bc
+  tail call void @f() [ "deopt"(i8* %m) ]
+  ret i1 %cmp
+; CHECK: ret i1 true
+}
+
+; Same function as above, but global not marked nonnull, and we cannot fold the comparison
+define i1 @compare_ne_global_maybe_null() {
+; CHECK-LABEL: compare_ne_global_maybe_null
+  %m = call i8* @malloc(i64 24)
+  %bc = bitcast i8* %m to i32*
+  %lgp = load i32*, i32** @gp
+  %cmp = icmp ne i32* %lgp, %bc
+  tail call void @f() [ "deopt"(i8* %m) ]
+  ret i1 %cmp
+; CHECK: ret i1 %cmp
+}
+
+; FIXME: The comparison should fold to false since %m escapes (call to function escape)
+; after the comparison.
+declare void @escape(i8*)
+define i1 @compare_and_call_after() {
+; CHECK-LABEL: compare_and_call_after
+  %m = call i8* @malloc(i64 24)
+  %bc = bitcast i8* %m to i32*
+  %lgp = load i32*, i32** @gp, align 8, !nonnull !0
+  %cmp = icmp eq i32* %bc, %lgp
+  br i1 %cmp, label %escape_call, label %just_return
+
+escape_call:
+ call void @escape(i8* %m)
+ ret i1 true
+
+just_return:
+ ret i1 %cmp
+}
+
+define i1 @compare_distinct_mallocs() {
+  %m = call i8* @malloc(i64 4)
+  %n = call i8* @malloc(i64 4)
+  %cmp = icmp eq i8* %m, %n
+  ret i1 %cmp
+  ; CHECK-LABEL: compare_distinct_mallocs
+  ; CHECK: ret i1 false
+}
+
+; the compare is folded to true since the folding compare looks through bitcasts. 
+; call to malloc and the bitcast instructions are elided after that since there are no uses of the malloc 
+define i1 @compare_samepointer_under_bitcast() {
+  %m = call i8* @malloc(i64 4)
+  %bc = bitcast i8* %m to i32*
+  %bcback = bitcast i32* %bc to i8*
+  %cmp = icmp eq i8* %m, %bcback
+  ret i1 %cmp
+; CHECK-LABEL: compare_samepointer_under_bitcast
+; CHECK: ret i1 true 
+}
+
+; the compare is folded to true since the folding compare looks through bitcasts. 
+; The malloc call for %m cannot be elided since it is used in the call to function f.
+define i1 @compare_samepointer_escaped() {
+  %m = call i8* @malloc(i64 4)
+  %bc = bitcast i8* %m to i32*
+  %bcback = bitcast i32* %bc to i8*
+  %cmp = icmp eq i8* %m, %bcback
+  call void @f() [ "deopt"(i8* %m) ]
+  ret i1 %cmp
+; CHECK-LABEL: compare_samepointer_escaped
+; CHECK-NEXT: %m = call i8* @malloc(i64 4)
+; CHECK-NEXT: call void @f() [ "deopt"(i8* %m) ]
+; CHECK: ret i1 true 
+}
+
+; Technically, we can fold the %cmp2 comparison, even though %m escapes through
+; the ret statement since `ret` terminates the function and we cannot reach from
+; the ret to cmp. 
+; FIXME: Folding this %cmp2 when %m escapes through ret could be an issue with
+; cross-threading data dependencies since we do not make the distinction between
+; atomic and non-atomic loads in capture tracking.
+define i8* @compare_ret_escape(i8* %c) {
+  %m = call i8* @malloc(i64 4)
+  %n = call i8* @malloc(i64 4)
+  %cmp = icmp eq i8* %n, %c
+  br i1 %cmp, label %retst, label %chk
+
+retst:
+  ret i8* %m
+
+chk:
+  %bc = bitcast i8* %m to i32*
+  %lgp = load i32*, i32** @gp, align 8, !nonnull !0
+  %cmp2 = icmp eq i32* %bc, %lgp
+  br i1 %cmp2, label %retst,  label %chk2
+
+chk2:
+  ret i8* %n
+; CHECK-LABEL: compare_ret_escape
+; CHECK: %cmp = icmp eq i8* %n, %c
+; CHECK: %cmp2 = icmp eq i32* %lgp, %bc
+}
+
+; The malloc call for %m cannot be elided since it is used in the call to function f.
+; However, the cmp can be folded to true as %n doesnt escape and %m, %n are distinct allocations
+define i1 @compare_distinct_pointer_escape() {
+  %m = call i8* @malloc(i64 4)
+  %n = call i8* @malloc(i64 4)
+  tail call void @f() [ "deopt"(i8* %m) ]
+  %cmp = icmp ne i8* %m, %n
+  ret i1 %cmp
+; CHECK-LABEL: compare_distinct_pointer_escape
+; CHECK-NEXT: %m = call i8* @malloc(i64 4)
+; CHECK-NEXT: tail call void @f() [ "deopt"(i8* %m) ]
+; CHECK-NEXT: ret i1 true
+}
+
+!0 = !{}

Added: llvm/trunk/test/Transforms/InstCombine/consecutive-fences.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/consecutive-fences.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/consecutive-fences.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/consecutive-fences.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,73 @@
+; RUN: opt -instcombine -S %s | FileCheck %s
+
+; Make sure we collapse the fences in this case
+
+; CHECK-LABEL: define void @tinkywinky
+; CHECK-NEXT:   fence seq_cst
+; CHECK-NEXT:   fence syncscope("singlethread") acquire
+; CHECK-NEXT:   ret void
+; CHECK-NEXT: }
+
+define void @tinkywinky() {
+  fence seq_cst
+  fence seq_cst
+  fence seq_cst
+  fence syncscope("singlethread") acquire
+  fence syncscope("singlethread") acquire
+  fence syncscope("singlethread") acquire
+  ret void
+}
+
+; CHECK-LABEL: define void @dipsy
+; CHECK-NEXT:   fence seq_cst
+; CHECK-NEXT:   fence syncscope("singlethread") seq_cst
+; CHECK-NEXT:   ret void
+; CHECK-NEXT: }
+
+define void @dipsy() {
+  fence seq_cst
+  fence syncscope("singlethread") seq_cst
+  ret void
+}
+
+; CHECK-LABEL: define void @patatino
+; CHECK-NEXT:   fence acquire
+; CHECK-NEXT:   fence seq_cst
+; CHECK-NEXT:   fence acquire
+; CHECK-NEXT:   fence seq_cst
+; CHECK-NEXT:   ret void
+; CHECK-NEXT: }
+
+define void @patatino() {
+  fence acquire
+  fence seq_cst
+  fence acquire
+  fence seq_cst
+  ret void
+}
+
+; CHECK-LABEL: define void @debug
+; CHECK-NOT: fence
+; CHECK: call void @llvm.dbg.value
+; CHECK: fence seq_cst
+define void @debug() {
+  fence seq_cst
+  tail call void @llvm.dbg.value(metadata i32 5, metadata !1, metadata !DIExpression()), !dbg !9
+  fence seq_cst
+  ret void
+}
+
+declare void @llvm.dbg.value(metadata, metadata, metadata)
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!5, !6, !7, !8}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C, file: !3, producer: "Me", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: null, retainedTypes: null, imports: null)
+!1 = !DILocalVariable(name: "", arg: 1, scope: !2, file: null, line: 1, type: null)
+!2 = distinct !DISubprogram(name: "debug", linkageName: "debug", scope: null, file: null, line: 0, type: null, isLocal: false, isDefinition: true, scopeLine: 1, flags: DIFlagPrototyped, isOptimized: true, unit: !0)
+!3 = !DIFile(filename: "consecutive-fences.ll", directory: "")
+!5 = !{i32 2, !"Dwarf Version", i32 4}
+!6 = !{i32 2, !"Debug Info Version", i32 3}
+!7 = !{i32 1, !"wchar_size", i32 4}
+!8 = !{i32 7, !"PIC Level", i32 2}
+!9 = !DILocation(line: 0, column: 0, scope: !2)

Added: llvm/trunk/test/Transforms/InstCombine/constant-expr-datalayout.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/constant-expr-datalayout.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/constant-expr-datalayout.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/constant-expr-datalayout.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,12 @@
+; RUN: opt -instcombine %s -S -o - | FileCheck %s
+
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+%test1.struct = type { i32, i32 }
+ at test1.aligned_glbl = global %test1.struct zeroinitializer, align 4
+define void @test1(i64 *%ptr) {
+  store i64 and (i64 ptrtoint (i32* getelementptr (%test1.struct, %test1.struct* @test1.aligned_glbl, i32 0, i32 1) to i64), i64 3), i64* %ptr
+; CHECK: store i64 0, i64* %ptr
+  ret void
+}

Added: llvm/trunk/test/Transforms/InstCombine/constant-fold-address-space-pointer.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/constant-fold-address-space-pointer.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/constant-fold-address-space-pointer.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/constant-fold-address-space-pointer.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,241 @@
+; 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"
+
+ at g = addrspace(3) global i32 89
+
+ at const_zero_i8_as1 = addrspace(1) constant i8 0
+ at const_zero_i32_as1 = addrspace(1) constant i32 0
+
+ at const_zero_i8_as2 = addrspace(2) constant i8 0
+ at const_zero_i32_as2 = addrspace(2) constant i32 0
+
+ at const_zero_i8_as3 = addrspace(3) constant i8 0
+ at const_zero_i32_as3 = addrspace(3) constant i32 0
+
+; Test constant folding of inttoptr (ptrtoint constantexpr)
+; The intermediate integer size is the same as the pointer size
+define i32 addrspace(3)* @test_constant_fold_inttoptr_as_pointer_same_size() {
+; CHECK-LABEL: @test_constant_fold_inttoptr_as_pointer_same_size(
+; CHECK-NEXT: ret i32 addrspace(3)* @const_zero_i32_as3
+  %x = ptrtoint i32 addrspace(3)* @const_zero_i32_as3 to i32
+  %y = inttoptr i32 %x to i32 addrspace(3)*
+  ret i32 addrspace(3)* %y
+}
+
+; The intermediate integer size is larger than the pointer size
+define i32 addrspace(2)* @test_constant_fold_inttoptr_as_pointer_smaller() {
+; CHECK-LABEL: @test_constant_fold_inttoptr_as_pointer_smaller(
+; CHECK-NEXT: ret i32 addrspace(2)* @const_zero_i32_as2
+  %x = ptrtoint i32 addrspace(2)* @const_zero_i32_as2 to i16
+  %y = inttoptr i16 %x to i32 addrspace(2)*
+  ret i32 addrspace(2)* %y
+}
+
+; Different address spaces that are the same size, but they are
+; different so nothing should happen
+define i32 addrspace(4)* @test_constant_fold_inttoptr_as_pointer_smaller_different_as() {
+; CHECK-LABEL: @test_constant_fold_inttoptr_as_pointer_smaller_different_as(
+; CHECK-NEXT: ret i32 addrspace(4)* inttoptr (i16 ptrtoint (i32 addrspace(3)* @const_zero_i32_as3 to i16) to i32 addrspace(4)*)
+  %x = ptrtoint i32 addrspace(3)* @const_zero_i32_as3 to i16
+  %y = inttoptr i16 %x to i32 addrspace(4)*
+  ret i32 addrspace(4)* %y
+}
+
+; Make sure we don't introduce a bitcast between different sized
+; address spaces when folding this
+define i32 addrspace(2)* @test_constant_fold_inttoptr_as_pointer_smaller_different_size_as() {
+; CHECK-LABEL: @test_constant_fold_inttoptr_as_pointer_smaller_different_size_as(
+; CHECK-NEXT: ret i32 addrspace(2)* inttoptr (i32 ptrtoint (i32 addrspace(3)* @const_zero_i32_as3 to i32) to i32 addrspace(2)*)
+  %x = ptrtoint i32 addrspace(3)* @const_zero_i32_as3 to i32
+  %y = inttoptr i32 %x to i32 addrspace(2)*
+  ret i32 addrspace(2)* %y
+}
+
+; The intermediate integer size is too small, nothing should happen
+define i32 addrspace(3)* @test_constant_fold_inttoptr_as_pointer_larger() {
+; CHECK-LABEL: @test_constant_fold_inttoptr_as_pointer_larger(
+; CHECK-NEXT: ret i32 addrspace(3)* inttoptr (i8 ptrtoint (i32 addrspace(3)* @const_zero_i32_as3 to i8) to i32 addrspace(3)*)
+  %x = ptrtoint i32 addrspace(3)* @const_zero_i32_as3 to i8
+  %y = inttoptr i8 %x to i32 addrspace(3)*
+  ret i32 addrspace(3)* %y
+}
+
+define i8 @const_fold_ptrtoint() {
+; CHECK-LABEL: @const_fold_ptrtoint(
+; CHECK-NEXT: ret i8 4
+  ret i8 ptrtoint (i32 addrspace(2)* inttoptr (i4 4 to i32 addrspace(2)*) to i8)
+}
+
+; Test that mask happens when the destination pointer is smaller than
+; the original
+define i8 @const_fold_ptrtoint_mask() {
+; CHECK-LABEL: @const_fold_ptrtoint_mask(
+; CHECK-NEXT: ret i8 1
+  ret i8 ptrtoint (i32 addrspace(3)* inttoptr (i32 257 to i32 addrspace(3)*) to i8)
+}
+
+; Address space 0 is too small for the correct mask, should mask with
+; 64-bits instead of 32
+define i64 @const_fold_ptrtoint_mask_small_as0() {
+; CHECK-LABEL: @const_fold_ptrtoint_mask_small_as0(
+; CHECK: ret i64 -1
+  ret i64 ptrtoint (i32 addrspace(1)* inttoptr (i128 -1 to i32 addrspace(1)*) to i64)
+}
+
+define i32 addrspace(3)* @const_inttoptr() {
+; CHECK-LABEL: @const_inttoptr(
+; CHECK-NEXT: ret i32 addrspace(3)* inttoptr (i16 4 to i32 addrspace(3)*)
+  %p = inttoptr i16 4 to i32 addrspace(3)*
+  ret i32 addrspace(3)* %p
+}
+
+define i16 @const_ptrtoint() {
+; CHECK-LABEL: @const_ptrtoint(
+; CHECK-NEXT: ret i16 ptrtoint (i32 addrspace(3)* @g to i16)
+  %i = ptrtoint i32 addrspace(3)* @g to i16
+  ret i16 %i
+}
+
+define i16 @const_inttoptr_ptrtoint() {
+; CHECK-LABEL: @const_inttoptr_ptrtoint(
+; CHECK-NEXT: ret i16 9
+  ret i16 ptrtoint (i32 addrspace(3)* inttoptr (i16 9 to i32 addrspace(3)*) to i16)
+}
+
+define i1 @constant_fold_cmp_constantexpr_inttoptr() {
+; CHECK-LABEL: @constant_fold_cmp_constantexpr_inttoptr(
+; CHECK-NEXT: ret i1 true
+  %x = icmp eq i32 addrspace(3)* inttoptr (i16 0 to i32 addrspace(3)*), null
+  ret i1 %x
+}
+
+define i1 @constant_fold_inttoptr_null(i16 %i) {
+; CHECK-LABEL: @constant_fold_inttoptr_null(
+; CHECK-NEXT: ret i1 false
+  %x = icmp eq i32 addrspace(3)* inttoptr (i16 99 to i32 addrspace(3)*), inttoptr (i16 0 to i32 addrspace(3)*)
+  ret i1 %x
+}
+
+define i1 @constant_fold_ptrtoint_null() {
+; CHECK-LABEL: @constant_fold_ptrtoint_null(
+; CHECK-NEXT: ret i1 icmp eq (i32 addrspace(3)* @g, i32 addrspace(3)* null)
+  %x = icmp eq i16 ptrtoint (i32 addrspace(3)* @g to i16), ptrtoint (i32 addrspace(3)* null to i16)
+  ret i1 %x
+}
+
+define i1 @constant_fold_ptrtoint_null_2() {
+; CHECK-LABEL: @constant_fold_ptrtoint_null_2(
+; CHECK-NEXT: ret i1 icmp eq (i32 addrspace(3)* @g, i32 addrspace(3)* null)
+  %x = icmp eq i16 ptrtoint (i32 addrspace(3)* null to i16), ptrtoint (i32 addrspace(3)* @g to i16)
+  ret i1 %x
+}
+
+define i1 @constant_fold_ptrtoint() {
+; CHECK-LABEL: @constant_fold_ptrtoint(
+; CHECK-NEXT: ret i1 true
+  %x = icmp eq i16 ptrtoint (i32 addrspace(3)* @g to i16), ptrtoint (i32 addrspace(3)* @g to i16)
+  ret i1 %x
+}
+
+define i1 @constant_fold_inttoptr() {
+; CHECK-LABEL: @constant_fold_inttoptr(
+; CHECK-NEXT: ret i1 false
+  %x = icmp eq i32 addrspace(3)* inttoptr (i16 99 to i32 addrspace(3)*), inttoptr (i16 27 to i32 addrspace(3)*)
+  ret i1 %x
+}
+
+ at g_float_as3 = addrspace(3) global float zeroinitializer
+ at g_v4f_as3 = addrspace(3) global <4 x float> zeroinitializer
+
+define float @constant_fold_bitcast_ftoi_load() {
+; CHECK-LABEL: @constant_fold_bitcast_ftoi_load(
+; CHECK: load float, float addrspace(3)* bitcast (i32 addrspace(3)* @g to float addrspace(3)*), align 4
+  %a = load float, float addrspace(3)* bitcast (i32 addrspace(3)* @g to float addrspace(3)*), align 4
+  ret float %a
+}
+
+define i32 @constant_fold_bitcast_itof_load() {
+; CHECK-LABEL: @constant_fold_bitcast_itof_load(
+; CHECK: load i32, i32 addrspace(3)* bitcast (float addrspace(3)* @g_float_as3 to i32 addrspace(3)*), align 4
+  %a = load i32, i32 addrspace(3)* bitcast (float addrspace(3)* @g_float_as3 to i32 addrspace(3)*), align 4
+  ret i32 %a
+}
+
+define <4 x float> @constant_fold_bitcast_vector_as() {
+; CHECK-LABEL: @constant_fold_bitcast_vector_as(
+; CHECK: load <4 x float>, <4 x float> addrspace(3)* @g_v4f_as3, align 16
+  %a = load <4 x float>, <4 x float> addrspace(3)* bitcast (<4 x i32> addrspace(3)* bitcast (<4 x float> addrspace(3)* @g_v4f_as3 to <4 x i32> addrspace(3)*) to <4 x float> addrspace(3)*), align 4
+  ret <4 x float> %a
+}
+
+ at i32_array_as3 = addrspace(3) global [10 x i32] zeroinitializer
+
+define i32 @test_cast_gep_small_indices_as() {
+; CHECK-LABEL: @test_cast_gep_small_indices_as(
+; CHECK: load i32, i32 addrspace(3)* getelementptr inbounds ([10 x i32], [10 x i32] addrspace(3)* @i32_array_as3, i16 0, i16 0), align 16
+   %p = getelementptr [10 x i32], [10 x i32] addrspace(3)* @i32_array_as3, i7 0, i7 0
+   %x = load i32, i32 addrspace(3)* %p, align 4
+   ret i32 %x
+}
+
+%struct.foo = type { float, float, [4 x i32], i32 addrspace(3)* }
+
+ at constant_fold_global_ptr = addrspace(3) global %struct.foo {
+  float 0.0,
+  float 0.0,
+  [4 x i32] zeroinitializer,
+  i32 addrspace(3)* getelementptr ([10 x i32], [10 x i32] addrspace(3)* @i32_array_as3, i64 0, i64 0)
+}
+
+define i32 @test_cast_gep_large_indices_as() {
+; CHECK-LABEL: @test_cast_gep_large_indices_as(
+; CHECK: load i32, i32 addrspace(3)* getelementptr inbounds ([10 x i32], [10 x i32] addrspace(3)* @i32_array_as3, i16 0, i16 0), align 16
+   %p = getelementptr [10 x i32], [10 x i32] addrspace(3)* @i32_array_as3, i64 0, i64 0
+   %x = load i32, i32 addrspace(3)* %p, align 4
+   ret i32 %x
+}
+
+define i32 @test_constant_cast_gep_struct_indices_as() {
+; CHECK-LABEL: @test_constant_cast_gep_struct_indices_as(
+; CHECK: load i32, i32 addrspace(3)* getelementptr inbounds (%struct.foo, %struct.foo addrspace(3)* @constant_fold_global_ptr, i16 0, i32 2, i16 2), align 8
+  %x = getelementptr %struct.foo, %struct.foo addrspace(3)* @constant_fold_global_ptr, i18 0, i32 2, i12 2
+  %y = load i32, i32 addrspace(3)* %x, align 4
+  ret i32 %y
+}
+
+ at constant_data_as3 = addrspace(3) constant [5 x i32] [i32 1, i32 2, i32 3, i32 4, i32 5]
+
+define i32 @test_read_data_from_global_as3() {
+; CHECK-LABEL: @test_read_data_from_global_as3(
+; CHECK-NEXT: ret i32 2
+  %x = getelementptr [5 x i32], [5 x i32] addrspace(3)* @constant_data_as3, i32 0, i32 1
+  %y = load i32, i32 addrspace(3)* %x, align 4
+  ret i32 %y
+}
+
+ at a = addrspace(1) constant i32 9
+ at b = addrspace(1) constant i32 23
+ at c = addrspace(1) constant i32 34
+ at d = addrspace(1) constant i32 99
+
+ at ptr_array = addrspace(2) constant [4 x i32 addrspace(1)*] [ i32 addrspace(1)* @a, i32 addrspace(1)* @b, i32 addrspace(1)* @c, i32 addrspace(1)* @d]
+ at indirect = addrspace(0) constant i32 addrspace(1)* addrspace(2)* getelementptr inbounds ([4 x i32 addrspace(1)*], [4 x i32 addrspace(1)*] addrspace(2)* @ptr_array, i1 0, i32 2)
+
+define i32 @constant_through_array_as_ptrs() {
+; CHECK-LABEL: @constant_through_array_as_ptrs(
+; CHECK-NEXT: ret i32 34
+  %p = load i32 addrspace(1)* addrspace(2)*, i32 addrspace(1)* addrspace(2)* addrspace(0)* @indirect, align 4
+  %a = load i32 addrspace(1)*, i32 addrspace(1)* addrspace(2)* %p, align 4
+  %b = load i32, i32 addrspace(1)* %a, align 4
+  ret i32 %b
+}
+
+ at shared_mem = external addrspace(3) global [0 x i8]
+
+define float @canonicalize_addrspacecast(i32 %i) {
+; CHECK-LABEL: @canonicalize_addrspacecast
+; CHECK-NEXT: getelementptr inbounds float, float* addrspacecast (float addrspace(3)* bitcast ([0 x i8] addrspace(3)* @shared_mem to float addrspace(3)*) to float*), i32 %i
+  %p = getelementptr inbounds float, float* addrspacecast ([0 x i8] addrspace(3)* @shared_mem to float*), i32 %i
+  %v = load float, float* %p
+  ret float %v
+}

Added: llvm/trunk/test/Transforms/InstCombine/constant-fold-alias.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/constant-fold-alias.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/constant-fold-alias.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/constant-fold-alias.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,40 @@
+; RUN: opt -S < %s -instcombine | FileCheck %s
+
+target datalayout = "e-p1:16:16-p2:32:32-p3:64:64"
+
+ at G1 = global i32 42, align 1
+ at G2 = global i32 42
+ at G3 = global [4 x i8] zeroinitializer, align 1
+
+ at A1 = alias i32, bitcast (i8* getelementptr inbounds ([4 x i8], [4 x i8]* @G3, i32 0, i32 2) to i32*)
+ at A2 = alias i32, inttoptr (i64 and (i64 ptrtoint (i8* getelementptr inbounds ([4 x i8], [4 x i8]* @G3, i32 0, i32 3) to i64), i64 -4) to i32*)
+
+define i64 @f1() {
+; This cannot be constant folded because G1 is underaligned.
+; CHECK-LABEL: @f1(
+; CHECK: ret i64 and
+  ret i64 and (i64 ptrtoint (i32* @G1 to i64), i64 1)
+}
+
+define i64 @f2() {
+; The preferred alignment for G2 allows this one to foled to zero.
+; CHECK-LABEL: @f2(
+; CHECK: ret i64 0
+  ret i64 and (i64 ptrtoint (i32* @G2 to i64), i64 1)
+}
+
+define i64 @g1() {
+; This cannot be constant folded because A1 aliases G3 which is underalaigned.
+; CHECK-LABEL: @g1(
+; CHECK: ret i64 and
+  ret i64 and (i64 ptrtoint (i32* @A1 to i64), i64 1)
+}
+
+define i64 @g2() {
+; While A2 also aliases G3 which is underaligned, the math of A2 forces a
+; certain alignment allowing this to fold to zero.
+; CHECK-LABEL: @g2(
+; CHECK: ret i64 0
+  ret i64 and (i64 ptrtoint (i32* @A2 to i64), i64 1)
+}
+

Added: llvm/trunk/test/Transforms/InstCombine/constant-fold-compare.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/constant-fold-compare.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/constant-fold-compare.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/constant-fold-compare.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,8 @@
+; 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:32:32-n8:16:32"
+
+define i32 @a() nounwind readnone {
+entry:
+  ret i32 zext (i1 icmp eq (i32 0, i32 ptrtoint (i32 ()* @a to i32)) to i32)
+}
+; CHECK: ret i32 0

Added: llvm/trunk/test/Transforms/InstCombine/constant-fold-gep.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/constant-fold-gep.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/constant-fold-gep.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/constant-fold-gep.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,92 @@
+; RUN: opt < %s -instcombine -S | FileCheck %s
+target datalayout = "E-p:64:64:64-p1:16:16:16-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"
+
+; Constant folding should fix notionally out-of-bounds indices
+; and add inbounds keywords.
+
+%struct.X = type { [3 x i32], [3 x i32] }
+
+ at Y = internal global [3 x %struct.X] zeroinitializer
+
+define void @frob() {
+; CHECK: store i32 1, i32* getelementptr inbounds ([3 x %struct.X], [3 x %struct.X]* @Y, i64 0, i64 0, i32 0, i64 0), align 16
+  store i32 1, i32* getelementptr ([3 x %struct.X], [3 x %struct.X]* @Y, i64 0, i64 0, i32 0, i64 0), align 4
+; CHECK: store i32 1, i32* getelementptr inbounds ([3 x %struct.X], [3 x %struct.X]* @Y, i64 0, i64 0, i32 0, i64 1), align 4
+  store i32 1, i32* getelementptr ([3 x %struct.X], [3 x %struct.X]* @Y, i64 0, i64 0, i32 0, i64 1), align 4
+; CHECK: store i32 1, i32* getelementptr inbounds ([3 x %struct.X], [3 x %struct.X]* @Y, i64 0, i64 0, i32 0, i64 2), align 8
+  store i32 1, i32* getelementptr ([3 x %struct.X], [3 x %struct.X]* @Y, i64 0, i64 0, i32 0, i64 2), align 4
+; CHECK: store i32 1, i32* getelementptr inbounds ([3 x %struct.X], [3 x %struct.X]* @Y, i64 0, i64 0, i32 1, i64 0), align 4
+  store i32 1, i32* getelementptr ([3 x %struct.X], [3 x %struct.X]* @Y, i64 0, i64 0, i32 0, i64 3), align 4
+; CHECK: store i32 1, i32* getelementptr inbounds ([3 x %struct.X], [3 x %struct.X]* @Y, i64 0, i64 0, i32 1, i64 1), align 4
+  store i32 1, i32* getelementptr ([3 x %struct.X], [3 x %struct.X]* @Y, i64 0, i64 0, i32 0, i64 4), align 4
+; CHECK: store i32 1, i32* getelementptr inbounds ([3 x %struct.X], [3 x %struct.X]* @Y, i64 0, i64 0, i32 1, i64 2), align 4
+  store i32 1, i32* getelementptr ([3 x %struct.X], [3 x %struct.X]* @Y, i64 0, i64 0, i32 0, i64 5), align 4
+; CHECK: store i32 1, i32* getelementptr inbounds ([3 x %struct.X], [3 x %struct.X]* @Y, i64 0, i64 1, i32 0, i64 0), align 8
+  store i32 1, i32* getelementptr ([3 x %struct.X], [3 x %struct.X]* @Y, i64 0, i64 0, i32 0, i64 6), align 4
+; CHECK: store i32 1, i32* getelementptr inbounds ([3 x %struct.X], [3 x %struct.X]* @Y, i64 0, i64 1, i32 0, i64 1), align 4
+  store i32 1, i32* getelementptr ([3 x %struct.X], [3 x %struct.X]* @Y, i64 0, i64 0, i32 0, i64 7), align 4
+; CHECK: store i32 1, i32* getelementptr inbounds ([3 x %struct.X], [3 x %struct.X]* @Y, i64 0, i64 1, i32 0, i64 2), align 8
+  store i32 1, i32* getelementptr ([3 x %struct.X], [3 x %struct.X]* @Y, i64 0, i64 0, i32 0, i64 8), align 4
+; CHECK: store i32 1, i32* getelementptr inbounds ([3 x %struct.X], [3 x %struct.X]* @Y, i64 0, i64 1, i32 1, i64 0), align 4
+  store i32 1, i32* getelementptr ([3 x %struct.X], [3 x %struct.X]* @Y, i64 0, i64 0, i32 0, i64 9), align 4
+; CHECK: store i32 1, i32* getelementptr inbounds ([3 x %struct.X], [3 x %struct.X]* @Y, i64 0, i64 1, i32 1, i64 1), align 4
+  store i32 1, i32* getelementptr ([3 x %struct.X], [3 x %struct.X]* @Y, i64 0, i64 0, i32 0, i64 10), align 4
+; CHECK: store i32 1, i32* getelementptr inbounds ([3 x %struct.X], [3 x %struct.X]* @Y, i64 0, i64 1, i32 1, i64 2), align 4
+  store i32 1, i32* getelementptr ([3 x %struct.X], [3 x %struct.X]* @Y, i64 0, i64 0, i32 0, i64 11), align 4
+; CHECK: store i32 1, i32* getelementptr inbounds ([3 x %struct.X], [3 x %struct.X]* @Y, i64 0, i64 2, i32 0, i64 0), align 16
+  store i32 1, i32* getelementptr ([3 x %struct.X], [3 x %struct.X]* @Y, i64 0, i64 0, i32 0, i64 12), align 4
+; CHECK: store i32 1, i32* getelementptr inbounds ([3 x %struct.X], [3 x %struct.X]* @Y, i64 0, i64 2, i32 0, i64 1), align 4
+  store i32 1, i32* getelementptr ([3 x %struct.X], [3 x %struct.X]* @Y, i64 0, i64 0, i32 0, i64 13), align 4
+; CHECK: store i32 1, i32* getelementptr inbounds ([3 x %struct.X], [3 x %struct.X]* @Y, i64 0, i64 2, i32 0, i64 2), align 8
+  store i32 1, i32* getelementptr ([3 x %struct.X], [3 x %struct.X]* @Y, i64 0, i64 0, i32 0, i64 14), align 8
+; CHECK: store i32 1, i32* getelementptr inbounds ([3 x %struct.X], [3 x %struct.X]* @Y, i64 0, i64 2, i32 1, i64 0), align 8
+  store i32 1, i32* getelementptr ([3 x %struct.X], [3 x %struct.X]* @Y, i64 0, i64 0, i32 0, i64 15), align 8
+; CHECK: store i32 1, i32* getelementptr inbounds ([3 x %struct.X], [3 x %struct.X]* @Y, i64 0, i64 2, i32 1, i64 1), align 8
+  store i32 1, i32* getelementptr ([3 x %struct.X], [3 x %struct.X]* @Y, i64 0, i64 0, i32 0, i64 16), align 8
+; CHECK: store i32 1, i32* getelementptr inbounds ([3 x %struct.X], [3 x %struct.X]* @Y, i64 0, i64 2, i32 1, i64 2), align 8
+  store i32 1, i32* getelementptr ([3 x %struct.X], [3 x %struct.X]* @Y, i64 0, i64 0, i32 0, i64 17), align 8
+; CHECK: store i32 1, i32* getelementptr inbounds ([3 x %struct.X], [3 x %struct.X]* @Y, i64 1, i64 0, i32 0, i64 0), align 8
+  store i32 1, i32* getelementptr ([3 x %struct.X], [3 x %struct.X]* @Y, i64 0, i64 0, i32 0, i64 18), align 8
+; CHECK: store i32 1, i32* getelementptr ([3 x %struct.X], [3 x %struct.X]* @Y, i64 2, i64 0, i32 0, i64 0), align 16
+  store i32 1, i32* getelementptr ([3 x %struct.X], [3 x %struct.X]* @Y, i64 0, i64 0, i32 0, i64 36), align 8
+; CHECK: store i32 1, i32* getelementptr ([3 x %struct.X], [3 x %struct.X]* @Y, i64 1, i64 0, i32 0, i64 1), align 8
+  store i32 1, i32* getelementptr ([3 x %struct.X], [3 x %struct.X]* @Y, i64 0, i64 0, i32 0, i64 19), align 8
+  ret void
+}
+
+
+; PR8883 - Constant fold exotic gep subtract
+; CHECK-LABEL: @test2(
+ at X = global [1000 x i8] zeroinitializer, align 16
+
+define i64 @test2() {
+entry:
+  %A = bitcast i8* getelementptr inbounds ([1000 x i8], [1000 x i8]* @X, i64 1, i64 0) to i8*
+  %B = bitcast i8* getelementptr inbounds ([1000 x i8], [1000 x i8]* @X, i64 0, i64 0) to i8*
+
+  %B2 = ptrtoint i8* %B to i64
+  %C = sub i64 0, %B2
+  %D = getelementptr i8, i8* %A, i64 %C
+  %E = ptrtoint i8* %D to i64
+
+  ret i64 %E
+  ; CHECK: ret i64 1000
+}
+
+ at X_as1 = addrspace(1) global [1000 x i8] zeroinitializer, align 16
+
+define i16 @test2_as1() {
+; CHECK-LABEL: @test2_as1(
+  ; CHECK: ret i16 1000
+
+entry:
+  %A = bitcast i8 addrspace(1)* getelementptr inbounds ([1000 x i8], [1000 x i8] addrspace(1)* @X_as1, i64 1, i64 0) to i8 addrspace(1)*
+  %B = bitcast i8 addrspace(1)* getelementptr inbounds ([1000 x i8], [1000 x i8] addrspace(1)* @X_as1, i64 0, i64 0) to i8 addrspace(1)*
+
+  %B2 = ptrtoint i8 addrspace(1)* %B to i16
+  %C = sub i16 0, %B2
+  %D = getelementptr i8, i8 addrspace(1)* %A, i16 %C
+  %E = ptrtoint i8 addrspace(1)* %D to i16
+
+  ret i16 %E
+}

Added: llvm/trunk/test/Transforms/InstCombine/constant-fold-iteration.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/constant-fold-iteration.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/constant-fold-iteration.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/constant-fold-iteration.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,10 @@
+; RUN: opt < %s -instcombine -S -debug 2>&1 | FileCheck %s
+; REQUIRES: asserts
+target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:32:32-n8:16:32"
+
+define i32 @a() nounwind readnone {
+entry:
+  ret i32 zext (i1 icmp eq (i32 0, i32 ptrtoint (i32 ()* @a to i32)) to i32)
+}
+; CHECK: INSTCOMBINE ITERATION #1
+; CHECK-NOT: INSTCOMBINE ITERATION #2

Added: llvm/trunk/test/Transforms/InstCombine/constant-fold-libfunc.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/constant-fold-libfunc.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/constant-fold-libfunc.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/constant-fold-libfunc.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,31 @@
+; RUN: opt < %s -instcombine -S | FileCheck %s
+
+declare double @acos(double)
+
+; Check that functions without any function attributes are simplified.
+
+define double @test_simplify_acos() {
+; CHECK-LABEL: @test_simplify_acos
+  %pi = call double @acos(double -1.000000e+00)
+; CHECK-NOT: call double @acos
+; CHECK: ret double 0x400921FB54442D18
+  ret double %pi
+}
+
+; Check that we don't constant fold builtin functions.
+
+define double @test_acos_nobuiltin() {
+; CHECK-LABEL: @test_acos_nobuiltin
+  %pi = call double @acos(double -1.000000e+00) nobuiltin 
+; CHECK: call double @acos(double -1.000000e+00)
+  ret double %pi
+}
+
+; Check that we don't constant fold strictfp results that require rounding.
+
+define double @test_acos_strictfp() {
+; CHECK-LABEL: @test_acos_strictfp
+  %pi = call double @acos(double -1.000000e+00) strictfp 
+; CHECK: call double @acos(double -1.000000e+00)
+  ret double %pi
+}

Added: llvm/trunk/test/Transforms/InstCombine/constant-fold-math.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/constant-fold-math.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/constant-fold-math.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/constant-fold-math.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,66 @@
+; RUN: opt -S -instcombine < %s | FileCheck %s
+
+declare float @llvm.fma.f32(float, float, float) #0
+declare float @llvm.fmuladd.f32(float, float, float) #0
+declare <4 x float> @llvm.fma.v4f32(<4 x float>, <4 x float>, <4 x float>) #0
+
+declare double @llvm.fma.f64(double, double, double) #0
+declare double @llvm.fmuladd.f64(double, double, double) #0
+
+declare double @llvm.sqrt.f64(double) #0
+
+
+; CHECK-LABEL: @constant_fold_fma_f32
+; CHECK-NEXT: ret float 6.000000e+00
+define float @constant_fold_fma_f32() #0 {
+  %x = call float @llvm.fma.f32(float 1.0, float 2.0, float 4.0) #0
+  ret float %x
+}
+
+; CHECK-LABEL: @constant_fold_fma_v4f32
+; CHECK-NEXT: ret <4 x float> <float 1.200000e+01, float 1.400000e+01, float 1.600000e+01, float 1.800000e+01>
+define <4 x float> @constant_fold_fma_v4f32() #0 {
+  %x = call <4 x float> @llvm.fma.v4f32(<4 x float> <float 1.0, float 2.0, float 3.0, float 4.0>, <4 x float> <float 2.0, float 2.0, float 2.0, float 2.0>, <4 x float> <float 10.0, float 10.0, float 10.0, float 10.0>)
+  ret <4 x float> %x
+}
+
+; CHECK-LABEL: @constant_fold_fmuladd_f32
+; CHECK-NEXT: ret float 6.000000e+00
+define float @constant_fold_fmuladd_f32() #0 {
+  %x = call float @llvm.fmuladd.f32(float 1.0, float 2.0, float 4.0) #0
+  ret float %x
+}
+
+; CHECK-LABEL: @constant_fold_fma_f64
+; CHECK-NEXT: ret double 6.000000e+00
+define double @constant_fold_fma_f64() #0 {
+  %x = call double @llvm.fma.f64(double 1.0, double 2.0, double 4.0) #0
+  ret double %x
+}
+
+; CHECK-LABEL: @constant_fold_fmuladd_f64
+; CHECK-NEXT: ret double 6.000000e+00
+define double @constant_fold_fmuladd_f64() #0 {
+  %x = call double @llvm.fmuladd.f64(double 1.0, double 2.0, double 4.0) #0
+  ret double %x
+}
+
+; PR32177
+
+; CHECK-LABEL: @constant_fold_frem_f32
+; CHECK-NEXT: ret float 0x41A61B2000000000
+define float @constant_fold_frem_f32() #0 {
+  %x = frem float 0x43cbfcd960000000, 0xc1e2b34a00000000
+  ret float %x
+}
+
+; PR3316
+
+; CHECK-LABEL: @constant_fold_frem_f64
+; CHECK-NEXT: ret double 0.000000e+00
+define double @constant_fold_frem_f64() {
+  %x = frem double 0x43E0000000000000, 1.000000e+00
+  ret double %x
+}
+
+attributes #0 = { nounwind readnone }

Added: llvm/trunk/test/Transforms/InstCombine/constant-fold-shifts.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/constant-fold-shifts.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/constant-fold-shifts.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/constant-fold-shifts.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,36 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt -S -instcombine < %s | FileCheck %s
+
+ at A = external constant i32
+
+; OSS-Fuzz #14169
+; https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=14169
+define void @ossfuzz_14169_test1(i32* %a0) {
+; CHECK-LABEL: @ossfuzz_14169_test1(
+; CHECK-NEXT:  bb:
+; CHECK-NEXT:    ret void
+;
+bb:
+  %B = ptrtoint i32* @A to i64
+  %C = icmp sge i64 %B, 0
+  %X = select i1 %C, i712 0, i712 1
+  %B9 = lshr i712 %X, 146783911423364576743092537299333564210980159306769991919205685720763064069663027716481187399048043939495936
+  %G5 = getelementptr i64, i64* undef, i712 %B9
+  store i64* %G5, i64** undef
+  ret void
+}
+
+define void @ossfuzz_14169_test2(i32* %a0) {
+; CHECK-LABEL: @ossfuzz_14169_test2(
+; CHECK-NEXT:  bb:
+; CHECK-NEXT:    ret void
+;
+bb:
+  %B = ptrtoint i32* @A to i64
+  %C = icmp sge i64 %B, 0
+  %X = select i1 %C, i712 0, i712 1
+  %B9 = shl i712 %X, 146783911423364576743092537299333564210980159306769991919205685720763064069663027716481187399048043939495936
+  %G5 = getelementptr i64, i64* undef, i712 %B9
+  store i64* %G5, i64** undef
+  ret void
+}

Added: llvm/trunk/test/Transforms/InstCombine/convergent.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/convergent.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/convergent.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/convergent.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,44 @@
+; RUN: opt -instcombine -S < %s | FileCheck -enable-var-scope %s
+
+declare i32 @k() convergent
+declare i32 @f()
+
+declare i64 @llvm.read_register.i64(metadata) nounwind
+
+define i32 @extern() {
+  ; Convergent attr shouldn't be removed here; k is convergent.
+  ; CHECK: call i32 @k() [[$CONVERGENT_ATTR:#[0-9]+]]
+  %a = call i32 @k() convergent
+  ret i32 %a
+}
+
+define i32 @extern_no_attr() {
+  ; Convergent attr shouldn't be added here, even though k is convergent.
+  ; CHECK: call i32 @k(){{$}}
+  %a = call i32 @k()
+  ret i32 %a
+}
+
+define i32 @no_extern() {
+  ; Convergent should be removed here, as the target is convergent.
+  ; CHECK: call i32 @f(){{$}}
+  %a = call i32 @f() convergent
+  ret i32 %a
+}
+
+define i32 @indirect_call(i32 ()* %f) {
+  ; CHECK: call i32 %f() [[$CONVERGENT_ATTR]]
+  %a = call i32 %f() convergent
+  ret i32 %a
+}
+
+; do not remove from convergent intrinsic call sites
+; CHECK-LABEL: @convergent_intrinsic_call(
+; CHECK: call i64 @llvm.read_register.i64(metadata !0) [[$CONVERGENT_ATTR]]
+define i64 @convergent_intrinsic_call() {
+  %val = call i64 @llvm.read_register.i64(metadata !0) convergent
+  ret i64 %val
+}
+
+; CHECK: [[$CONVERGENT_ATTR]] = { convergent }
+!0 = !{!"foo"}

Added: llvm/trunk/test/Transforms/InstCombine/copysign.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/copysign.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/copysign.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/copysign.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,49 @@
+; RUN: opt -S -instcombine < %s | FileCheck %s
+
+declare float @llvm.copysign.f32(float, float) #0
+declare double @llvm.copysign.f64(double, double) #0
+
+; CHECK-LABEL: @constant_fold_copysign_f32_01
+; CHECK-NEXT: ret float -1.000000e+00
+define float @constant_fold_copysign_f32_01() #0 {
+  %x = call float @llvm.copysign.f32(float 1.0, float -2.0) #0
+  ret float %x
+}
+
+; CHECK-LABEL: @constant_fold_copysign_f32_02
+; CHECK-NEXT: ret float 2.000000e+00
+define float @constant_fold_copysign_f32_02() #0 {
+  %x = call float @llvm.copysign.f32(float -2.0, float 1.0) #0
+  ret float %x
+}
+
+; CHECK-LABEL: @constant_fold_copysign_f32_03
+; CHECK-NEXT: ret float -2.000000e+00
+define float @constant_fold_copysign_f32_03() #0 {
+  %x = call float @llvm.copysign.f32(float -2.0, float -1.0) #0
+  ret float %x
+}
+
+; CHECK-LABEL: @constant_fold_copysign_f64_01
+; CHECK-NEXT: ret double -1.000000e+00
+define double @constant_fold_copysign_f64_01() #0 {
+  %x = call double @llvm.copysign.f64(double 1.0, double -2.0) #0
+  ret double %x
+}
+
+; CHECK-LABEL: @constant_fold_copysign_f64_02
+; CHECK-NEXT: ret double 1.000000e+00
+define double @constant_fold_copysign_f64_02() #0 {
+  %x = call double @llvm.copysign.f64(double -1.0, double 2.0) #0
+  ret double %x
+}
+
+; CHECK-LABEL: @constant_fold_copysign_f64_03
+; CHECK-NEXT: ret double -1.000000e+00
+define double @constant_fold_copysign_f64_03() #0 {
+  %x = call double @llvm.copysign.f64(double -1.0, double -2.0) #0
+  ret double %x
+}
+
+
+attributes #0 = { nounwind readnone }

Added: llvm/trunk/test/Transforms/InstCombine/cos-1.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/cos-1.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/cos-1.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/cos-1.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,175 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt < %s -instcombine -S                             | FileCheck %s --check-prefixes=ANY,NO-FLOAT-SHRINK
+; RUN: opt < %s -instcombine -enable-double-float-shrink -S | FileCheck %s --check-prefixes=ANY,DO-FLOAT-SHRINK
+
+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 double @cos(double)
+declare double @llvm.cos.f64(double)
+declare float @cosf(float)
+declare float @llvm.cos.f32(float)
+
+declare double @sin(double)
+declare double @llvm.sin.f64(double)
+declare float @sinf(float)
+declare float @llvm.sin.f32(float)
+
+declare double @tan(double)
+declare fp128 @tanl(fp128)
+
+; cos(-x) -> cos(x);
+
+define double @cos_negated_arg(double %x) {
+; ANY-LABEL: @cos_negated_arg(
+; ANY-NEXT:    [[COS:%.*]] = call double @cos(double [[X:%.*]])
+; ANY-NEXT:    ret double [[COS]]
+;
+  %neg = fsub double -0.0, %x
+  %r = call double @cos(double %neg)
+  ret double %r
+}
+
+define float @cosf_negated_arg(float %x) {
+; ANY-LABEL: @cosf_negated_arg(
+; ANY-NEXT:    [[COS:%.*]] = call float @cosf(float [[X:%.*]])
+; ANY-NEXT:    ret float [[COS]]
+;
+  %neg = fsub float -0.0, %x
+  %r = call float @cosf(float %neg)
+  ret float %r
+}
+
+define float @cosf_negated_arg_FMF(float %x) {
+; ANY-LABEL: @cosf_negated_arg_FMF(
+; ANY-NEXT:    [[COS:%.*]] = call reassoc nnan float @cosf(float [[X:%.*]])
+; ANY-NEXT:    ret float [[COS]]
+;
+  %neg = fsub float -0.0, %x
+  %r = call nnan reassoc float @cosf(float %neg)
+  ret float %r
+}
+
+; sin(-x) -> -sin(x);
+
+define double @sin_negated_arg(double %x) {
+; ANY-LABEL: @sin_negated_arg(
+; ANY-NEXT:    [[TMP1:%.*]] = call double @sin(double [[X:%.*]])
+; ANY-NEXT:    [[TMP2:%.*]] = fsub double -0.000000e+00, [[TMP1]]
+; ANY-NEXT:    ret double [[TMP2]]
+;
+  %neg = fsub double -0.0, %x
+  %r = call double @sin(double %neg)
+  ret double %r
+}
+
+define float @sinf_negated_arg(float %x) {
+; ANY-LABEL: @sinf_negated_arg(
+; ANY-NEXT:    [[TMP1:%.*]] = call float @sinf(float [[X:%.*]])
+; ANY-NEXT:    [[TMP2:%.*]] = fsub float -0.000000e+00, [[TMP1]]
+; ANY-NEXT:    ret float [[TMP2]]
+;
+  %neg = fsub float -0.0, %x
+  %r = call float @sinf(float %neg)
+  ret float %r
+}
+
+define float @sinf_negated_arg_FMF(float %x) {
+; ANY-LABEL: @sinf_negated_arg_FMF(
+; ANY-NEXT:    [[TMP1:%.*]] = call nnan afn float @sinf(float [[X:%.*]])
+; ANY-NEXT:    [[TMP2:%.*]] = fsub nnan afn float -0.000000e+00, [[TMP1]]
+; ANY-NEXT:    ret float [[TMP2]]
+;
+  %neg = fsub ninf float -0.0, %x
+  %r = call afn nnan float @sinf(float %neg)
+  ret float %r
+}
+
+declare void @use(double)
+
+define double @sin_negated_arg_extra_use(double %x) {
+; ANY-LABEL: @sin_negated_arg_extra_use(
+; ANY-NEXT:    [[NEG:%.*]] = fsub double -0.000000e+00, [[X:%.*]]
+; ANY-NEXT:    [[R:%.*]] = call double @sin(double [[NEG]])
+; ANY-NEXT:    call void @use(double [[NEG]])
+; ANY-NEXT:    ret double [[R]]
+;
+  %neg = fsub double -0.0, %x
+  %r = call double @sin(double %neg)
+  call void @use(double %neg)
+  ret double %r
+}
+
+; -sin(-x) --> sin(x)
+; PR38458: https://bugs.llvm.org/show_bug.cgi?id=38458
+
+define double @neg_sin_negated_arg(double %x) {
+; ANY-LABEL: @neg_sin_negated_arg(
+; ANY-NEXT:    [[TMP1:%.*]] = call double @sin(double [[X:%.*]])
+; ANY-NEXT:    ret double [[TMP1]]
+;
+  %neg = fsub double -0.0, %x
+  %r = call double @sin(double %neg)
+  %rn = fsub double -0.0, %r
+  ret double %rn
+}
+
+; tan(-x) -> -tan(x);
+
+define double @tan_negated_arg(double %x) {
+; ANY-LABEL: @tan_negated_arg(
+; ANY-NEXT:    [[TMP1:%.*]] = call double @tan(double [[X:%.*]])
+; ANY-NEXT:    [[TMP2:%.*]] = fsub double -0.000000e+00, [[TMP1]]
+; ANY-NEXT:    ret double [[TMP2]]
+;
+  %neg = fsub double -0.0, %x
+  %r = call double @tan(double %neg)
+  ret double %r
+}
+
+; tanl(-x) -> -tanl(x);
+
+define fp128 @tanl_negated_arg(fp128 %x) {
+; ANY-LABEL: @tanl_negated_arg(
+; ANY-NEXT:    [[TMP1:%.*]] = call fp128 @tanl(fp128 [[X:%.*]])
+; ANY-NEXT:    [[TMP2:%.*]] = fsub fp128 0xL00000000000000008000000000000000, [[TMP1]]
+; ANY-NEXT:    ret fp128 [[TMP2]]
+;
+  %neg = fsub fp128 0xL00000000000000008000000000000000, %x
+  %r = call fp128 @tanl(fp128 %neg)
+  ret fp128 %r
+}
+
+define float @negated_and_shrinkable_libcall(float %f) {
+; NO-FLOAT-SHRINK-LABEL: @negated_and_shrinkable_libcall(
+; NO-FLOAT-SHRINK-NEXT:    [[CONV1:%.*]] = fpext float [[F:%.*]] to double
+; NO-FLOAT-SHRINK-NEXT:    [[COS1:%.*]] = call double @cos(double [[CONV1]])
+; NO-FLOAT-SHRINK-NEXT:    [[CONV2:%.*]] = fptrunc double [[COS1]] to float
+; NO-FLOAT-SHRINK-NEXT:    ret float [[CONV2]]
+;
+; DO-FLOAT-SHRINK-LABEL: @negated_and_shrinkable_libcall(
+; DO-FLOAT-SHRINK-NEXT:    [[COSF:%.*]] = call float @cosf(float [[F:%.*]])
+; DO-FLOAT-SHRINK-NEXT:    ret float [[COSF]]
+;
+  %conv1 = fpext float %f to double
+  %neg = fsub double -0.0, %conv1
+  %cos = call double @cos(double %neg)
+  %conv2 = fptrunc double %cos to float
+  ret float %conv2
+}
+
+; TODO: It was ok to shrink the libcall, so the intrinsic should shrink too?
+
+define float @negated_and_shrinkable_intrinsic(float %f) {
+; ANY-LABEL: @negated_and_shrinkable_intrinsic(
+; ANY-NEXT:    [[CONV1:%.*]] = fpext float [[F:%.*]] to double
+; ANY-NEXT:    [[COS:%.*]] = call double @llvm.cos.f64(double [[CONV1]])
+; ANY-NEXT:    [[CONV2:%.*]] = fptrunc double [[COS]] to float
+; ANY-NEXT:    ret float [[CONV2]]
+;
+  %conv1 = fpext float %f to double
+  %neg = fsub double -0.0, %conv1
+  %cos = call double @llvm.cos.f64(double %neg)
+  %conv2 = fptrunc double %cos to float
+  ret float %conv2
+}
+

Added: llvm/trunk/test/Transforms/InstCombine/cos-2.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/cos-2.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/cos-2.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/cos-2.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,27 @@
+; 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 float @cos(double)
+declare signext i8 @sqrt(...)
+
+; Check that functions with the wrong prototype aren't simplified.
+
+define float @test_no_simplify1(double %d) {
+; CHECK-LABEL: @test_no_simplify1(
+  %neg = fsub double -0.000000e+00, %d
+  %cos = call float @cos(double %neg)
+; CHECK: call float @cos(double %neg)
+  ret float %cos
+}
+
+
+define i8 @bogus_sqrt() {
+  %fake_sqrt = call signext i8 (...) @sqrt()
+  ret i8 %fake_sqrt
+
+; CHECK-LABEL: bogus_sqrt(
+; CHECK-NEXT:  %fake_sqrt = call signext i8 (...) @sqrt()
+; CHECK-NEXT:  ret i8 %fake_sqrt
+}
+

Added: llvm/trunk/test/Transforms/InstCombine/cos-sin-intrinsic.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/cos-sin-intrinsic.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/cos-sin-intrinsic.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/cos-sin-intrinsic.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,122 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt < %s -instcombine -S | FileCheck %s
+
+declare double    @llvm.cos.f64(double %Val)
+declare float     @llvm.cos.f32(float %Val)
+declare <2 x float> @llvm.cos.v2f32(<2 x float> %Val)
+
+declare float @llvm.fabs.f32(float %Val)
+declare <2 x float> @llvm.fabs.v2f32(<2 x float> %Val)
+
+define double @undef_arg() {
+; CHECK-LABEL: @undef_arg(
+; CHECK-NEXT:    ret double 0.000000e+00
+;
+  %r = call double @llvm.cos.f64(double undef)
+  ret double %r
+}
+
+define float @undef_arg2(float %d) {
+; CHECK-LABEL: @undef_arg2(
+; CHECK-NEXT:    [[COSVAL:%.*]] = call float @llvm.cos.f32(float [[D:%.*]])
+; CHECK-NEXT:    [[FSUM:%.*]] = fadd float [[COSVAL]], 0.000000e+00
+; CHECK-NEXT:    ret float [[FSUM]]
+;
+  %cosval   = call float @llvm.cos.f32(float %d)
+  %cosval2  = call float @llvm.cos.f32(float undef)
+  %fsum   = fadd float %cosval2, %cosval
+  ret float %fsum
+}
+
+define float @fneg_f32(float %x) {
+; CHECK-LABEL: @fneg_f32(
+; CHECK-NEXT:    [[COS:%.*]] = call float @llvm.cos.f32(float [[X:%.*]])
+; CHECK-NEXT:    ret float [[COS]]
+;
+  %x.fneg = fsub float -0.0, %x
+  %cos = call float @llvm.cos.f32(float %x.fneg)
+  ret float %cos
+}
+
+define <2 x float> @fneg_v2f32(<2 x float> %x) {
+; CHECK-LABEL: @fneg_v2f32(
+; CHECK-NEXT:    [[COS:%.*]] = call <2 x float> @llvm.cos.v2f32(<2 x float> [[X:%.*]])
+; CHECK-NEXT:    ret <2 x float> [[COS]]
+;
+  %x.fneg = fsub <2 x float> <float -0.0, float -0.0>, %x
+  %cos = call <2 x float> @llvm.cos.v2f32(<2 x float> %x.fneg)
+  ret <2 x float> %cos
+}
+
+; FMF are not required, but they should propagate.
+
+define <2 x float> @fneg_cos_fmf(<2 x float> %x){
+; CHECK-LABEL: @fneg_cos_fmf(
+; CHECK-NEXT:    [[R:%.*]] = call nnan afn <2 x float> @llvm.cos.v2f32(<2 x float> [[X:%.*]])
+; CHECK-NEXT:    ret <2 x float> [[R]]
+;
+  %negx = fsub fast <2 x float> <float -0.0, float -0.0>, %x
+  %r = call nnan afn <2 x float> @llvm.cos.v2f32(<2 x float> %negx)
+  ret <2 x float> %r
+}
+
+define float @fabs_f32(float %x) {
+; CHECK-LABEL: @fabs_f32(
+; CHECK-NEXT:    [[COS:%.*]] = call float @llvm.cos.f32(float [[X:%.*]])
+; CHECK-NEXT:    ret float [[COS]]
+;
+  %x.fabs = call float @llvm.fabs.f32(float %x)
+  %cos = call float @llvm.cos.f32(float %x.fabs)
+  ret float %cos
+}
+
+define float @fabs_fneg_f32(float %x) {
+; CHECK-LABEL: @fabs_fneg_f32(
+; CHECK-NEXT:    [[COS:%.*]] = call float @llvm.cos.f32(float [[X:%.*]])
+; CHECK-NEXT:    ret float [[COS]]
+;
+  %x.fabs = call float @llvm.fabs.f32(float %x)
+  %x.fabs.fneg = fsub float -0.0, %x.fabs
+  %cos = call float @llvm.cos.f32(float %x.fabs.fneg)
+  ret float %cos
+}
+
+define <2 x float> @fabs_fneg_v2f32(<2 x float> %x) {
+; CHECK-LABEL: @fabs_fneg_v2f32(
+; CHECK-NEXT:    [[COS:%.*]] = call <2 x float> @llvm.cos.v2f32(<2 x float> [[X:%.*]])
+; CHECK-NEXT:    ret <2 x float> [[COS]]
+;
+  %x.fabs = call <2 x float> @llvm.fabs.v2f32(<2 x float> %x)
+  %x.fabs.fneg = fsub <2 x float> <float -0.0, float -0.0>, %x.fabs
+  %cos = call <2 x float> @llvm.cos.v2f32(<2 x float> %x.fabs.fneg)
+  ret <2 x float> %cos
+}
+
+; Negate is canonicalized after sin.
+
+declare <2 x float> @llvm.sin.v2f32(<2 x float>)
+
+define <2 x float> @fneg_sin(<2 x float> %x){
+; CHECK-LABEL: @fneg_sin(
+; CHECK-NEXT:    [[TMP1:%.*]] = call <2 x float> @llvm.sin.v2f32(<2 x float> [[X:%.*]])
+; 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
+  %r = call <2 x float> @llvm.sin.v2f32(<2 x float> %negx)
+  ret <2 x float> %r
+}
+
+; FMF are not required, but they should propagate.
+
+define <2 x float> @fneg_sin_fmf(<2 x float> %x){
+; CHECK-LABEL: @fneg_sin_fmf(
+; CHECK-NEXT:    [[TMP1:%.*]] = call nnan arcp afn <2 x float> @llvm.sin.v2f32(<2 x float> [[X:%.*]])
+; CHECK-NEXT:    [[R:%.*]] = fsub nnan arcp afn <2 x float> <float -0.000000e+00, float -0.000000e+00>, [[TMP1]]
+; CHECK-NEXT:    ret <2 x float> [[R]]
+;
+  %negx = fsub fast <2 x float> <float -0.0, float -0.0>, %x
+  %r = call nnan arcp afn <2 x float> @llvm.sin.v2f32(<2 x float> %negx)
+  ret <2 x float> %r
+}
+

Added: llvm/trunk/test/Transforms/InstCombine/crash.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/crash.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/crash.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/crash.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,398 @@
+; RUN: opt < %s -instcombine -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"
+target triple = "i386-apple-darwin10.0"
+
+define i32 @test0(i8 %tmp2) ssp {
+entry:
+  %tmp3 = zext i8 %tmp2 to i32
+  %tmp8 = lshr i32 %tmp3, 6 
+  %tmp9 = lshr i32 %tmp3, 7 
+  %tmp10 = xor i32 %tmp9, 67108858
+  %tmp11 = xor i32 %tmp10, %tmp8 
+  %tmp12 = xor i32 %tmp11, 0     
+  ret i32 %tmp12
+}
+
+; PR4905
+define <2 x i64> @test1(<2 x i64> %x, <2 x i64> %y) nounwind {
+entry:
+  %conv.i94 = bitcast <2 x i64> %y to <4 x i32>   ; <<4 x i32>> [#uses=1]
+  %sub.i97 = sub <4 x i32> %conv.i94, undef       ; <<4 x i32>> [#uses=1]
+  %conv3.i98 = bitcast <4 x i32> %sub.i97 to <2 x i64> ; <<2 x i64>> [#uses=2]
+  %conv2.i86 = bitcast <2 x i64> %conv3.i98 to <4 x i32> ; <<4 x i32>> [#uses=1]
+  %cmp.i87 = icmp sgt <4 x i32> undef, %conv2.i86 ; <<4 x i1>> [#uses=1]
+  %sext.i88 = sext <4 x i1> %cmp.i87 to <4 x i32> ; <<4 x i32>> [#uses=1]
+  %conv3.i89 = bitcast <4 x i32> %sext.i88 to <2 x i64> ; <<2 x i64>> [#uses=1]
+  %and.i = and <2 x i64> %conv3.i89, %conv3.i98   ; <<2 x i64>> [#uses=1]
+  %or.i = or <2 x i64> zeroinitializer, %and.i    ; <<2 x i64>> [#uses=1]
+  %conv2.i43 = bitcast <2 x i64> %or.i to <4 x i32> ; <<4 x i32>> [#uses=1]
+  %sub.i = sub <4 x i32> zeroinitializer, %conv2.i43 ; <<4 x i32>> [#uses=1]
+  %conv3.i44 = bitcast <4 x i32> %sub.i to <2 x i64> ; <<2 x i64>> [#uses=1]
+  ret <2 x i64> %conv3.i44
+}
+
+
+; PR4908
+define void @test2(<1 x i16>* nocapture %b, i32* nocapture %c) nounwind ssp {
+entry:
+  %arrayidx = getelementptr inbounds <1 x i16>, <1 x i16>* %b, i64 undef ; <<1 x i16>*>
+  %tmp2 = load <1 x i16>, <1 x i16>* %arrayidx               ; <<1 x i16>> [#uses=1]
+  %tmp6 = bitcast <1 x i16> %tmp2 to i16          ; <i16> [#uses=1]
+  %tmp7 = zext i16 %tmp6 to i32                   ; <i32> [#uses=1]
+  %ins = or i32 0, %tmp7                          ; <i32> [#uses=1]
+  %arrayidx20 = getelementptr inbounds i32, i32* %c, i64 undef ; <i32*> [#uses=1]
+  store i32 %ins, i32* %arrayidx20
+  ret void
+}
+
+; PR5262
+ at tmp2 = global i64 0                              ; <i64*> [#uses=1]
+
+declare void @use(i64) nounwind
+
+define void @foo(i1) nounwind align 2 {
+; <label>:1
+  br i1 %0, label %2, label %3
+
+; <label>:2                                       ; preds = %1
+  br label %3
+
+; <label>:3                                       ; preds = %2, %1
+  %4 = phi i8 [ 1, %2 ], [ 0, %1 ]                ; <i8> [#uses=1]
+  %5 = icmp eq i8 %4, 0                           ; <i1> [#uses=1]
+  %6 = load i64, i64* @tmp2, align 8                   ; <i64> [#uses=1]
+  %7 = select i1 %5, i64 0, i64 %6                ; <i64> [#uses=1]
+  br label %8
+
+; <label>:8                                       ; preds = %3
+  call void @use(i64 %7)
+  ret void
+}
+
+%t0 = type { i32, i32 }
+%t1 = type { i32, i32, i32, i32, i32* }
+
+declare %t0* @bar2(i64)
+
+define void @bar3(i1, i1) nounwind align 2 {
+; <label>:2
+  br i1 %1, label %10, label %3
+
+; <label>:3                                       ; preds = %2
+  %4 = getelementptr inbounds %t0, %t0* null, i64 0, i32 1 ; <i32*> [#uses=0]
+  %5 = getelementptr inbounds %t1, %t1* null, i64 0, i32 4 ; <i32**> [#uses=1]
+  %6 = load i32*, i32** %5, align 8                     ; <i32*> [#uses=1]
+  %7 = icmp ne i32* %6, null                      ; <i1> [#uses=1]
+  %8 = zext i1 %7 to i32                          ; <i32> [#uses=1]
+  %9 = add i32 %8, 0                              ; <i32> [#uses=1]
+  br label %10
+
+; <label>:10                                      ; preds = %3, %2
+  %11 = phi i32 [ %9, %3 ], [ 0, %2 ]             ; <i32> [#uses=1]
+  br i1 %1, label %12, label %13
+
+; <label>:12                                      ; preds = %10
+  br label %13
+
+; <label>:13                                      ; preds = %12, %10
+  %14 = zext i32 %11 to i64                       ; <i64> [#uses=1]
+  %15 = tail call %t0* @bar2(i64 %14) nounwind      ; <%0*> [#uses=0]
+  ret void
+}
+
+
+
+
+; PR5262
+; Make sure the PHI node gets put in a place where all of its operands dominate
+; it.
+define i64 @test4(i1 %c, i64* %P) nounwind align 2 {
+BB0:
+  br i1 %c, label %BB1, label %BB2
+
+BB1:
+  br label %BB2
+
+BB2:
+  %v5_ = phi i1 [ true, %BB0], [false, %BB1]
+  %v6 = load i64, i64* %P
+  br label %l8
+
+l8:
+  br label %l10
+  
+l10:
+  %v11 = select i1 %v5_, i64 0, i64 %v6
+  ret i64 %v11
+}
+
+; PR5471
+define i32 @test5a() {
+       ret i32 0
+}
+
+define void @test5() personality i32 (...)* @__gxx_personality_v0 {
+  store i1 true, i1* undef
+  %r = invoke i32 @test5a() to label %exit unwind label %unwind
+unwind:
+  %exn = landingpad {i8*, i32}
+          cleanup
+  br label %exit
+exit:
+  ret void
+}
+
+
+; PR5673
+
+ at test6g = external global i32*  
+
+define arm_aapcs_vfpcc i32 @test6(i32 %argc, i8** %argv) nounwind {
+entry:
+  store i32* getelementptr (i32, i32* bitcast (i32 (i32, i8**)* @test6 to i32*), i32 -2048), i32** @test6g, align 4
+  unreachable
+}
+
+
+; PR5827
+
+%class.RuleBasedBreakIterator = type { i64 ()* }
+%class.UStack = type { i8** }
+
+define i32 @_ZN22RuleBasedBreakIterator15checkDictionaryEi(%class.RuleBasedBreakIterator* %this, i32 %x) align 2 personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) {
+entry:
+  %breaks = alloca %class.UStack, align 4         ; <%class.UStack*> [#uses=3]
+  call void @_ZN6UStackC1Ei(%class.UStack* %breaks, i32 0)
+  %tobool = icmp ne i32 %x, 0                     ; <i1> [#uses=1]
+  br i1 %tobool, label %cond.end, label %cond.false
+
+terminate.handler:                                ; preds = %ehcleanup
+  %exc = landingpad { i8*, i32 }
+           cleanup
+  call void @_ZSt9terminatev() noreturn nounwind
+  unreachable
+
+ehcleanup:                                        ; preds = %cond.false
+  %exc1 = landingpad { i8*, i32 }
+           catch i8* null
+  invoke void @_ZN6UStackD1Ev(%class.UStack* %breaks)
+          to label %cont unwind label %terminate.handler
+
+cont:                                             ; preds = %ehcleanup
+  resume { i8*, i32 } %exc1
+
+cond.false:                                       ; preds = %entry
+  %tmp4 = getelementptr inbounds %class.RuleBasedBreakIterator, %class.RuleBasedBreakIterator* %this, i32 0, i32 0 ; <i64 ()**> [#uses=1]
+  %tmp5 = load i64 ()*, i64 ()** %tmp4                     ; <i64 ()*> [#uses=1]
+  %call = invoke i64 %tmp5()
+          to label %cond.end unwind label %ehcleanup ; <i64> [#uses=1]
+
+cond.end:                                         ; preds = %cond.false, %entry
+  %cond = phi i64 [ 0, %entry ], [ %call, %cond.false ] ; <i64> [#uses=1]
+  %conv = trunc i64 %cond to i32                  ; <i32> [#uses=1]
+  call void @_ZN6UStackD1Ev(%class.UStack* %breaks)
+  ret i32 %conv
+}
+
+declare void @_ZN6UStackC1Ei(%class.UStack*, i32)
+
+declare void @_ZN6UStackD1Ev(%class.UStack*)
+
+declare i32 @__gxx_personality_v0(...)
+
+declare void @_ZSt9terminatev()
+
+declare void @_Unwind_Resume_or_Rethrow(i8*)
+
+
+
+; rdar://7590304
+define i8* @test10(i8* %self, i8* %tmp3) personality i32 (...)* @__gxx_personality_v0 {
+entry:
+  store i1 true, i1* undef
+  store i1 true, i1* undef
+  invoke void @test10a()
+          to label %invoke.cont unwind label %try.handler ; <i8*> [#uses=0]
+
+invoke.cont:                                      ; preds = %entry
+  unreachable
+
+try.handler:                                      ; preds = %entry
+  %exn = landingpad {i8*, i32}
+           catch i8* null
+  ret i8* %self
+}
+
+define void @test10a() {
+  ret void
+}
+
+
+; PR6193
+define i32 @test11(i32 %aMaskWidth, i8 %aStride) nounwind {
+entry:
+  %conv41 = sext i8 %aStride to i32
+  %neg = xor i32 %conv41, -1
+  %and42 = and i32 %aMaskWidth, %neg
+  %and47 = and i32 130, %conv41
+  %or = or i32 %and42, %and47
+  ret i32 %or
+}
+
+; PR6503
+define void @test12(i32* %A) nounwind {
+entry:
+  %tmp1 = load i32, i32* %A
+  %cmp = icmp ugt i32 1, %tmp1                    ; <i1> [#uses=1]
+  %conv = zext i1 %cmp to i32                     ; <i32> [#uses=1]
+  %tmp2 = load i32, i32* %A
+  %cmp3 = icmp ne i32 %tmp2, 0                    ; <i1> [#uses=1]
+  %conv4 = zext i1 %cmp3 to i32                   ; <i32> [#uses=1]
+  %or = or i32 %conv, %conv4                      ; <i32> [#uses=1]
+  %cmp5 = icmp ugt i32 undef, %or                 ; <i1> [#uses=1]
+  %conv6 = zext i1 %cmp5 to i32                   ; <i32> [#uses=0]
+  ret void
+}
+
+%s1 = type { %s2, %s2, [6 x %s2], i32, i32, i32, [1 x i32], [0 x i8] }
+%s2 = type { i64 }
+define void @test13() nounwind ssp {
+entry:
+  %0 = getelementptr inbounds %s1, %s1* null, i64 0, i32 2, i64 0, i32 0
+  %1 = bitcast i64* %0 to i32*
+  %2 = getelementptr inbounds %s1, %s1* null, i64 0, i32 2, i64 1, i32 0
+  %.pre = load i32, i32* %1, align 8
+  %3 = lshr i32 %.pre, 19
+  %brmerge = or i1 undef, undef
+  %4 = and i32 %3, 3
+  %5 = add nsw i32 %4, 1
+  %6 = shl i32 %5, 19
+  %7 = add i32 %6, 1572864
+  %8 = and i32 %7, 1572864
+  %9 = load i64, i64* %2, align 8
+  %trunc156 = trunc i64 %9 to i32
+  %10 = and i32 %trunc156, -1537
+  %11 = and i32 %10, -6145
+  %12 = or i32 %11, 2048
+  %13 = and i32 %12, -24577
+  %14 = or i32 %13, 16384
+  %15 = or i32 %14, 98304
+  store i32 %15, i32* undef, align 8
+  %16 = and i32 %15, -1572865
+  %17 = or i32 %16, %8
+  store i32 %17, i32* undef, align 8
+  %18 = and i32 %17, -449
+  %19 = or i32 %18, 64
+  store i32 %19, i32* undef, align 8
+  unreachable
+}
+
+
+; PR8807
+declare i32 @test14f(i8* (i8*)*) nounwind
+
+define void @test14() nounwind readnone {
+entry:
+  %tmp = bitcast i32 (i8* (i8*)*)* @test14f to i32 (i32*)*
+  %call10 = call i32 %tmp(i32* byval undef)
+  ret void
+}
+
+
+; PR8896
+ at g_54 = external global [7 x i16]
+
+define void @test15(i32* %p_92) nounwind {
+entry:
+%0 = load i32, i32* %p_92, align 4
+%1 = icmp ne i32 %0, 0
+%2 = zext i1 %1 to i32
+%3 = call i32 @func_14() nounwind
+%4 = trunc i32 %3 to i16
+%5 = sext i16 %4 to i32
+%6 = trunc i32 %5 to i16
+br i1 undef, label %"3", label %"5"
+
+"3":                                              ; preds = %entry
+%7 = sext i16 %6 to i32
+%8 = ashr i32 %7, -1649554541
+%9 = trunc i32 %8 to i16
+br label %"5"
+
+"5":                                              ; preds = %"3", %entry
+%10 = phi i16 [ %9, %"3" ], [ %6, %entry ]
+%11 = sext i16 %10 to i32
+%12 = xor i32 %2, %11
+%13 = sext i32 %12 to i64
+%14 = icmp ne i64 %13, 0
+br i1 %14, label %return, label %"7"
+
+"7":                                              ; preds = %"5"
+ret void
+
+return:                                           ; preds = %"5"
+ret void
+}
+
+declare i32 @func_14()
+
+
+define double @test16(i32 %a) nounwind {
+  %cmp = icmp slt i32 %a, 2
+  %select = select i1 %cmp, double 2.000000e+00, double 3.141592e+00
+  ret double %select
+}
+
+
+; PR8983
+%struct.basic_ios = type { i8 }
+
+define %struct.basic_ios *@test17() ssp {
+entry:
+  %add.ptr.i = getelementptr i8, i8* null, i64 undef
+  %0 = bitcast i8* %add.ptr.i to %struct.basic_ios*
+  ret %struct.basic_ios* %0
+}
+
+; PR9013
+define void @test18() nounwind ssp {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %l_197.0 = phi i32 [ 0, %entry ], [ %sub.i, %for.inc ]
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.cond
+  %conv = and i32 %l_197.0, 255
+  %sub.i = add nsw i32 %conv, -1
+  br label %for.cond
+
+return:                                           ; No predecessors!
+  ret void
+}
+
+; PR11275
+declare void @test18b() noreturn
+declare void @test18foo(double**)
+declare void @test18a() noreturn
+define fastcc void @test18x(i8* %t0, i1 %b) uwtable align 2 personality i32 (...)* @__gxx_personality_v0 {
+entry:
+  br i1 %b, label %e1, label %e2
+e1:
+  %t2 = bitcast i8* %t0 to double**
+  invoke void @test18b() noreturn
+          to label %u unwind label %lpad
+e2:
+  %t4 = bitcast i8* %t0 to double**
+  invoke void @test18a() noreturn
+          to label %u unwind label %lpad
+lpad:
+  %t5 = phi double** [ %t2, %e1 ], [ %t4, %e2 ]
+  %lpad.nonloopexit262 = landingpad { i8*, i32 }
+          cleanup
+  call void @test18foo(double** %t5)
+  unreachable
+u:
+  unreachable
+}

Added: llvm/trunk/test/Transforms/InstCombine/ctlz-cttz-bitreverse.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/ctlz-cttz-bitreverse.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/ctlz-cttz-bitreverse.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/ctlz-cttz-bitreverse.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,69 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt -instcombine -S < %s | FileCheck %s
+
+define i32 @ctlz_true_bitreverse(i32 %x) {
+; CHECK-LABEL: @ctlz_true_bitreverse(
+; CHECK-NEXT:    [[TMP1:%.*]] = call i32 @llvm.cttz.i32(i32 [[X:%.*]], i1 true), !range !0
+; CHECK-NEXT:    ret i32 [[TMP1]]
+;
+  %a = tail call i32 @llvm.bitreverse.i32(i32 %x)
+  %b = tail call i32 @llvm.ctlz.i32(i32 %a, i1 true)
+  ret i32 %b
+}
+
+define <2 x i64> @ctlz_true_bitreverse_vec(<2 x i64> %x) {
+; CHECK-LABEL: @ctlz_true_bitreverse_vec(
+; CHECK-NEXT:    [[TMP1:%.*]] = call <2 x i64> @llvm.cttz.v2i64(<2 x i64> [[X:%.*]], i1 true)
+; CHECK-NEXT:    ret <2 x i64> [[TMP1]]
+;
+  %a = tail call <2 x i64> @llvm.bitreverse.v2i64(<2 x i64> %x)
+  %b = tail call <2 x i64> @llvm.ctlz.v2i64(<2 x i64> %a, i1 true)
+  ret <2 x i64> %b
+}
+
+define i32 @ctlz_false_bitreverse(i32 %x) {
+; CHECK-LABEL: @ctlz_false_bitreverse(
+; CHECK-NEXT:    [[TMP1:%.*]] = call i32 @llvm.cttz.i32(i32 [[X:%.*]], i1 false), !range !0
+; CHECK-NEXT:    ret i32 [[TMP1]]
+;
+  %a = tail call i32 @llvm.bitreverse.i32(i32 %x)
+  %b = tail call i32 @llvm.ctlz.i32(i32 %a, i1 false)
+  ret i32 %b
+}
+
+define i32 @cttz_true_bitreverse(i32 %x) {
+; CHECK-LABEL: @cttz_true_bitreverse(
+; CHECK-NEXT:    [[TMP1:%.*]] = call i32 @llvm.ctlz.i32(i32 [[X:%.*]], i1 true), !range !0
+; CHECK-NEXT:    ret i32 [[TMP1]]
+;
+  %a = tail call i32 @llvm.bitreverse.i32(i32 %x)
+  %b = tail call i32 @llvm.cttz.i32(i32 %a, i1 true)
+  ret i32 %b
+}
+
+define <2 x i64> @cttz_true_bitreverse_vec(<2 x i64> %x) {
+; CHECK-LABEL: @cttz_true_bitreverse_vec(
+; CHECK-NEXT:    [[TMP1:%.*]] = call <2 x i64> @llvm.ctlz.v2i64(<2 x i64> [[X:%.*]], i1 true)
+; CHECK-NEXT:    ret <2 x i64> [[TMP1]]
+;
+  %a = tail call <2 x i64> @llvm.bitreverse.v2i64(<2 x i64> %x)
+  %b = tail call <2 x i64> @llvm.cttz.v2i64(<2 x i64> %a, i1 true)
+  ret <2 x i64> %b
+}
+
+define i32 @cttz_false_bitreverse(i32 %x) {
+; CHECK-LABEL: @cttz_false_bitreverse(
+; CHECK-NEXT:    [[TMP1:%.*]] = call i32 @llvm.ctlz.i32(i32 [[X:%.*]], i1 false), !range !0
+; CHECK-NEXT:    ret i32 [[TMP1]]
+;
+  %a = tail call i32 @llvm.bitreverse.i32(i32 %x)
+  %b = tail call i32 @llvm.cttz.i32(i32 %a, i1 false)
+  ret i32 %b
+}
+
+declare i32 @llvm.bitreverse.i32(i32)
+declare <2 x i64> @llvm.bitreverse.v2i64(<2 x i64>)
+declare i32 @llvm.ctlz.i32(i32, i1)
+declare i32 @llvm.cttz.i32(i32, i1)
+declare <2 x i64> @llvm.ctlz.v2i64(<2 x i64>, i1)
+declare <2 x i64> @llvm.cttz.v2i64(<2 x i64>, i1)

Added: llvm/trunk/test/Transforms/InstCombine/ctpop-bswap-bitreverse.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/ctpop-bswap-bitreverse.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/ctpop-bswap-bitreverse.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/ctpop-bswap-bitreverse.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 -instcombine -S < %s | FileCheck %s
+
+define i32 @ctpop_bitreverse(i32 %x) {
+; CHECK-LABEL: @ctpop_bitreverse(
+; CHECK-NEXT:    [[B:%.*]] = tail call i32 @llvm.ctpop.i32(i32 [[X:%.*]]), !range !0
+; CHECK-NEXT:    ret i32 [[B]]
+;
+  %a = tail call i32 @llvm.bitreverse.i32(i32 %x)
+  %b = tail call i32 @llvm.ctpop.i32(i32 %a)
+  ret i32 %b
+}
+
+define <2 x i64> @ctpop_bitreverse_vec(<2 x i64> %x) {
+; CHECK-LABEL: @ctpop_bitreverse_vec(
+; CHECK-NEXT:    [[B:%.*]] = tail call <2 x i64> @llvm.ctpop.v2i64(<2 x i64> [[X:%.*]])
+; CHECK-NEXT:    ret <2 x i64> [[B]]
+;
+  %a = tail call <2 x i64> @llvm.bitreverse.v2i64(<2 x i64> %x)
+  %b = tail call <2 x i64> @llvm.ctpop.v2i64(<2 x i64> %a)
+  ret <2 x i64> %b
+}
+
+define i32 @ctpop_bswap(i32 %x) {
+; CHECK-LABEL: @ctpop_bswap(
+; CHECK-NEXT:    [[B:%.*]] = tail call i32 @llvm.ctpop.i32(i32 [[X:%.*]]), !range !0
+; CHECK-NEXT:    ret i32 [[B]]
+;
+  %a = tail call i32 @llvm.bswap.i32(i32 %x)
+  %b = tail call i32 @llvm.ctpop.i32(i32 %a)
+  ret i32 %b
+}
+
+define <2 x i64> @ctpop_bswap_vec(<2 x i64> %x) {
+; CHECK-LABEL: @ctpop_bswap_vec(
+; CHECK-NEXT:    [[B:%.*]] = tail call <2 x i64> @llvm.ctpop.v2i64(<2 x i64> [[X:%.*]])
+; CHECK-NEXT:    ret <2 x i64> [[B]]
+;
+  %a = tail call <2 x i64> @llvm.bswap.v2i64(<2 x i64> %x)
+  %b = tail call <2 x i64> @llvm.ctpop.v2i64(<2 x i64> %a)
+  ret <2 x i64> %b
+}
+
+declare i32 @llvm.bitreverse.i32(i32)
+declare <2 x i64> @llvm.bitreverse.v2i64(<2 x i64>)
+declare i32 @llvm.bswap.i32(i32)
+declare <2 x i64> @llvm.bswap.v2i64(<2 x i64>)
+declare i32 @llvm.ctpop.i32(i32)
+declare <2 x i64> @llvm.ctpop.v2i64(<2 x i64>)

Added: llvm/trunk/test/Transforms/InstCombine/ctpop.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/ctpop.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/ctpop.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/ctpop.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,97 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt < %s -S -instcombine | FileCheck %s
+
+declare i32 @llvm.ctpop.i32(i32)
+declare i8 @llvm.ctpop.i8(i8)
+declare i1 @llvm.ctpop.i1(i1)
+declare <2 x i32> @llvm.ctpop.v2i32(<2 x i32>)
+declare void @llvm.assume(i1)
+
+define i1 @test1(i32 %arg) {
+; CHECK-LABEL: @test1(
+; CHECK-NEXT:    ret i1 false
+;
+  %and = and i32 %arg, 15
+  %cnt = call i32 @llvm.ctpop.i32(i32 %and)
+  %res = icmp eq i32 %cnt, 9
+  ret i1 %res
+}
+
+define i1 @test2(i32 %arg) {
+; CHECK-LABEL: @test2(
+; CHECK-NEXT:    ret i1 false
+;
+  %and = and i32 %arg, 1
+  %cnt = call i32 @llvm.ctpop.i32(i32 %and)
+  %res = icmp eq i32 %cnt, 2
+  ret i1 %res
+}
+
+define i1 @test3(i32 %arg) {
+; CHECK-LABEL: @test3(
+; CHECK-NEXT:    [[ASSUME:%.*]] = icmp eq i32 [[ARG:%.*]], 0
+; CHECK-NEXT:    call void @llvm.assume(i1 [[ASSUME]])
+; CHECK-NEXT:    ret i1 false
+;
+  ;; Use an assume to make all the bits known without triggering constant
+  ;; folding.  This is trying to hit a corner case where we have to avoid
+  ;; taking the log of 0.
+  %assume = icmp eq i32 %arg, 0
+  call void @llvm.assume(i1 %assume)
+  %cnt = call i32 @llvm.ctpop.i32(i32 %arg)
+  %res = icmp eq i32 %cnt, 2
+  ret i1 %res
+}
+
+; Negative test for when we know nothing
+define i1 @test4(i8 %arg) {
+; CHECK-LABEL: @test4(
+; CHECK-NEXT:    [[CNT:%.*]] = call i8 @llvm.ctpop.i8(i8 [[ARG:%.*]]), !range ![[$RANGE:[0-9]+]]
+; CHECK-NEXT:    [[RES:%.*]] = icmp eq i8 [[CNT]], 2
+; CHECK-NEXT:    ret i1 [[RES]]
+;
+  %cnt = call i8 @llvm.ctpop.i8(i8 %arg)
+  %res = icmp eq i8 %cnt, 2
+  ret i1 %res
+}
+
+; Test when the number of possible known bits isn't one less than a power of 2
+; and the compare value is greater but less than the next power of 2.
+define i1 @test5(i32 %arg) {
+; CHECK-LABEL: @test5(
+; CHECK-NEXT:    ret i1 false
+;
+  %and = and i32 %arg, 3
+  %cnt = call i32 @llvm.ctpop.i32(i32 %and)
+  %res = icmp eq i32 %cnt, 3
+  ret i1 %res
+}
+
+; Test when the number of possible known bits isn't one less than a power of 2
+; and the compare value is greater but less than the next power of 2.
+; TODO: The icmp is unnecessary given the known bits of the input, but range
+; metadata doesn't support vectors
+define <2 x i1> @test5vec(<2 x i32> %arg) {
+; CHECK-LABEL: @test5vec(
+; CHECK-NEXT:    [[AND:%.*]] = and <2 x i32> [[ARG:%.*]], <i32 3, i32 3>
+; CHECK-NEXT:    [[CNT:%.*]] = call <2 x i32> @llvm.ctpop.v2i32(<2 x i32> [[AND]])
+; CHECK-NEXT:    [[RES:%.*]] = icmp eq <2 x i32> [[CNT]], <i32 3, i32 3>
+; CHECK-NEXT:    ret <2 x i1> [[RES]]
+;
+  %and = and <2 x i32> %arg, <i32 3, i32 3>
+  %cnt = call <2 x i32> @llvm.ctpop.v2i32(<2 x i32> %and)
+  %res = icmp eq <2 x i32> %cnt, <i32 3, i32 3>
+  ret <2 x i1> %res
+}
+
+; Make sure we don't add range metadata to i1 ctpop.
+define i1 @test6(i1 %arg) {
+; CHECK-LABEL: @test6(
+; CHECK-NEXT:    [[CNT:%.*]] = call i1 @llvm.ctpop.i1(i1 [[ARG:%.*]])
+; CHECK-NEXT:    ret i1 [[CNT]]
+;
+  %cnt = call i1 @llvm.ctpop.i1(i1 %arg)
+  ret i1 %cnt
+}
+
+; CHECK: ![[$RANGE]] = !{i8 0, i8 9}

Added: llvm/trunk/test/Transforms/InstCombine/dce-iterate.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/dce-iterate.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/dce-iterate.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/dce-iterate.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,24 @@
+; RUN: opt < %s -instcombine -S | grep "ret double .sy"
+
+define internal double @ScaleObjectAdd(double %sx, double %sy, double %sz) nounwind {
+entry:
+        %sx34 = bitcast double %sx to i64               ; <i64> [#uses=1]
+        %sx3435 = zext i64 %sx34 to i960                ; <i960> [#uses=1]
+        %sy22 = bitcast double %sy to i64               ; <i64> [#uses=1]
+        %sy2223 = zext i64 %sy22 to i960                ; <i960> [#uses=1]
+        %sy222324 = shl i960 %sy2223, 320               ; <i960> [#uses=1]
+        %sy222324.ins = or i960 %sx3435, %sy222324              ; <i960> [#uses=1]
+        %sz10 = bitcast double %sz to i64               ; <i64> [#uses=1]
+        %sz1011 = zext i64 %sz10 to i960                ; <i960> [#uses=1]
+        %sz101112 = shl i960 %sz1011, 640               ; <i960> [#uses=1]
+        %sz101112.ins = or i960 %sy222324.ins, %sz101112 
+        
+        %a = trunc i960 %sz101112.ins to i64            ; <i64> [#uses=1]
+        %b = bitcast i64 %a to double           ; <double> [#uses=1]
+        %c = lshr i960 %sz101112.ins, 320               ; <i960> [#uses=1]
+        %d = trunc i960 %c to i64               ; <i64> [#uses=1]
+        %e = bitcast i64 %d to double           ; <double> [#uses=1]
+        %f = fadd double %b, %e
+
+        ret double %e
+}

Added: llvm/trunk/test/Transforms/InstCombine/deadcode.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/deadcode.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/deadcode.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/deadcode.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,33 @@
+; RUN: opt < %s -instcombine -S | grep "ret i32 %A"
+; RUN: opt < %s -die -S | not grep call.*llvm
+
+define i32 @test(i32 %A) {
+	%X = or i1 false, false		
+	br i1 %X, label %T, label %C
+
+T:		; preds = %0
+	%B = add i32 %A, 1	
+	br label %C
+
+C:		; preds = %T, %0
+	%C.upgrd.1 = phi i32 [ %B, %T ], [ %A, %0 ]
+	ret i32 %C.upgrd.1
+}
+
+define i32* @test2(i32 %width) {
+	%tmp = call i8* @llvm.stacksave( )
+        %tmp14 = alloca i32, i32 %width
+	ret i32* %tmp14
+} 
+
+declare i8* @llvm.stacksave()
+
+declare void @llvm.lifetime.start.p0i8(i64, i8*)
+declare void @llvm.lifetime.end.p0i8(i64, i8*)
+
+define void @test3() {
+  call void @llvm.lifetime.start.p0i8(i64 -1, i8* undef)
+  call void @llvm.lifetime.end.p0i8(i64 -1, i8* undef)
+  ret void
+}
+

Added: llvm/trunk/test/Transforms/InstCombine/debug-line.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/debug-line.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/debug-line.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/debug-line.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,26 @@
+; RUN: opt -instcombine -S < %s | FileCheck %s
+
+
+ at .str = private constant [3 x i8] c"%c\00"
+
+define void @foo() nounwind ssp !dbg !0 {
+;CHECK: call i32 @putchar{{.+}} !dbg
+  %1 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @.str, i32 0, i32 0), i32 97), !dbg !5
+  ret void, !dbg !7
+}
+
+declare i32 @printf(i8*, ...)
+
+!llvm.dbg.cu = !{!2}
+!llvm.module.flags = !{!10}
+
+!0 = distinct !DISubprogram(name: "foo", line: 4, isLocal: false, isDefinition: true, virtualIndex: 6, isOptimized: false, unit: !2, file: !8, scope: !1, type: !3)
+!1 = !DIFile(filename: "m.c", directory: "/private/tmp")
+!2 = distinct !DICompileUnit(language: DW_LANG_C99, producer: "clang", isOptimized: true, emissionKind: FullDebug, file: !8, enums: !{}, retainedTypes: !{})
+!3 = !DISubroutineType(types: !4)
+!4 = !{null}
+!5 = !DILocation(line: 5, column: 2, scope: !6)
+!6 = distinct !DILexicalBlock(line: 4, column: 12, file: !8, scope: !0)
+!7 = !DILocation(line: 6, column: 1, scope: !6)
+!8 = !DIFile(filename: "m.c", directory: "/private/tmp")
+!10 = !{i32 1, !"Debug Info Version", i32 3}

Added: llvm/trunk/test/Transforms/InstCombine/debuginfo-dce.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/debuginfo-dce.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/debuginfo-dce.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/debuginfo-dce.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,141 @@
+; RUN: opt -instcombine %s -S -o - | FileCheck %s
+; Verify that the eliminated instructions (bitcast, gep, load) are salvaged into
+; a DIExpression.
+;
+; Originally created from the following C source and then heavily isolated/reduced.
+;
+; struct entry {
+;   struct entry *next;
+; };
+; void scan(struct entry *queue, struct entry *end)
+; {
+;   struct entry *entry;
+;   for (entry = (struct entry *)((char *)(queue->next) - 8);
+;        &entry->next == end;
+;        entry = (struct entry *)((char *)(entry->next) - 8)) {
+;   }
+; }
+
+; ModuleID = '<stdin>'
+source_filename = "test.c"
+target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-apple-macosx10.12.0"
+
+%struct.entry = type { %struct.entry* }
+
+; This salvage can't currently occur safely (PR40628), however if/when that's
+; ever fixed, then this is definitely a piece of test coverage that should
+; be maintained.
+define void @salvage_load(%struct.entry** %queue) local_unnamed_addr #0 !dbg !14 {
+entry:
+  %im_not_dead = alloca %struct.entry*
+  %0 = load %struct.entry*, %struct.entry** %queue, align 8, !dbg !19
+  %1 = load %struct.entry*, %struct.entry** %queue, align 8, !dbg !19
+  call void @llvm.dbg.value(metadata %struct.entry* %1, metadata !18, metadata !20), !dbg !19
+; CHECK: define void @salvage_load
+; CHECK-NEXT: entry:
+; CHECK-NOT: dbg.value
+  store %struct.entry* %1, %struct.entry** %im_not_dead, align 8
+  ret void, !dbg !21
+}
+
+define void @salvage_bitcast(%struct.entry* %queue) local_unnamed_addr #0 !dbg !22 {
+entry:
+  %im_not_dead = alloca i8*
+  %0 = bitcast %struct.entry* %queue to i8*, !dbg !23
+  %1 = bitcast %struct.entry* %queue to i8*, !dbg !23
+  call void @llvm.dbg.value(metadata i8* %1, metadata !24, metadata !20), !dbg !23
+; CHECK: define void @salvage_bitcast
+; CHECK-NEXT: entry:
+; CHECK-NEXT: call void @llvm.dbg.value(metadata %struct.entry* %queue,
+; CHECK-SAME:                           metadata !DIExpression(DW_OP_plus_uconst, 0))
+  store i8* %1, i8** %im_not_dead, align 8
+  ret void, !dbg !23
+}
+
+define void @salvage_gep0(%struct.entry* %queue, %struct.entry* %end) local_unnamed_addr #0 !dbg !25 {
+entry:
+  %im_not_dead = alloca %struct.entry**
+  %0 = getelementptr inbounds %struct.entry, %struct.entry* %queue, i32 -1, i32 0, !dbg !26
+  %1 = getelementptr inbounds %struct.entry, %struct.entry* %queue, i32 -1, i32 0, !dbg !26
+  call void @llvm.dbg.value(metadata %struct.entry** %1, metadata !27, metadata !20), !dbg !26
+; CHECK: define void @salvage_gep0
+; CHECK-NEXT: entry:
+; CHECK-NEXT: call void @llvm.dbg.value(metadata %struct.entry* %queue,
+; CHECK-SAME:                           metadata !DIExpression(DW_OP_constu, 8, DW_OP_minus, DW_OP_plus_uconst, 0, DW_OP_stack_value))
+  store %struct.entry** %1, %struct.entry*** %im_not_dead, align 8
+  ret void, !dbg !26
+}
+
+define void @salvage_gep1(%struct.entry* %queue, %struct.entry* %end) local_unnamed_addr #0 !dbg !28 {
+entry:
+  %im_not_dead = alloca %struct.entry**
+  %0 = getelementptr inbounds %struct.entry, %struct.entry* %queue, i32 -1, i32 0, !dbg !29
+  %1 = getelementptr inbounds %struct.entry, %struct.entry* %queue, i32 -1, i32 0, !dbg !29
+  call void @llvm.dbg.value(metadata %struct.entry** %1, metadata !30, metadata !DIExpression(DW_OP_LLVM_fragment, 0, 32)), !dbg !29
+; CHECK: define void @salvage_gep1
+; CHECK-NEXT: entry:
+; CHECK-NEXT: call void @llvm.dbg.value(metadata %struct.entry* %queue,
+; CHECK-SAME:     metadata !DIExpression(DW_OP_constu, 8, DW_OP_minus, DW_OP_stack_value, DW_OP_LLVM_fragment, 0, 32))
+  store %struct.entry** %1, %struct.entry*** %im_not_dead, align 8
+  ret void, !dbg !29
+}
+
+define void @salvage_gep2(%struct.entry* %queue, %struct.entry* %end) local_unnamed_addr #0 !dbg !31 {
+entry:
+  %im_not_dead = alloca %struct.entry**
+  %0 = getelementptr inbounds %struct.entry, %struct.entry* %queue, i32 -1, i32 0, !dbg !32
+  %1 = getelementptr inbounds %struct.entry, %struct.entry* %queue, i32 -1, i32 0, !dbg !32
+  call void @llvm.dbg.value(metadata %struct.entry** %1, metadata !33, metadata !DIExpression(DW_OP_stack_value)), !dbg !32
+; CHECK: define void @salvage_gep2
+; CHECK-NEXT: entry:
+; CHECK-NEXT: call void @llvm.dbg.value(metadata %struct.entry* %queue,
+; CHECK-SAME:     metadata !DIExpression(DW_OP_constu, 8, DW_OP_minus, DW_OP_stack_value))
+  store %struct.entry** %1, %struct.entry*** %im_not_dead, align 8
+  ret void, !dbg !32
+}
+
+; Function Attrs: nounwind readnone
+declare void @llvm.dbg.value(metadata, metadata, metadata) #1
+
+attributes #0 = { nounwind ssp uwtable }
+attributes #1 = { nounwind readnone }
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!10, !11, !12}
+!llvm.ident = !{!13}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 5.0.0 (trunk 297628) (llvm/trunk 297643)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, retainedTypes: !3)
+!1 = !DIFile(filename: "test.c", directory: "/")
+!2 = !{}
+!3 = !{!4, !8}
+!4 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !5, size: 64)
+!5 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "entry", file: !1, line: 1, size: 64, elements: !6)
+!6 = !{!7}
+!7 = !DIDerivedType(tag: DW_TAG_member, name: "next", scope: !5, file: !1, line: 2, baseType: !4, size: 64)
+!8 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !9, size: 64)
+!9 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char)
+!10 = !{i32 2, !"Dwarf Version", i32 4}
+!11 = !{i32 2, !"Debug Info Version", i32 3}
+!12 = !{i32 1, !"PIC Level", i32 2}
+!13 = !{!"clang version 5.0.0 (trunk 297628) (llvm/trunk 297643)"}
+!14 = distinct !DISubprogram(name: "scan", scope: !1, file: !1, line: 4, type: !15, isLocal: false, isDefinition: true, scopeLine: 5, flags: DIFlagPrototyped, isOptimized: true, unit: !0, retainedNodes: !17)
+!15 = !DISubroutineType(types: !16)
+!16 = !{null, !4, !4}
+!17 = !{!18}
+!18 = !DILocalVariable(name: "entry", scope: !14, file: !1, line: 6, type: !4)
+!19 = !DILocation(line: 6, column: 17, scope: !14)
+!20 = !DIExpression(DW_OP_plus_uconst, 0)
+!21 = !DILocation(line: 11, column: 1, scope: !14)
+!22 = distinct !DISubprogram(name: "scan", scope: !1, file: !1, line: 4, type: !15, isLocal: false, isDefinition: true, scopeLine: 5, flags: DIFlagPrototyped, isOptimized: true, unit: !0, retainedNodes: !17)
+!23 = !DILocation(line: 6, column: 17, scope: !22)
+!24 = !DILocalVariable(name: "entry", scope: !22, file: !1, line: 6, type: !4)
+!25 = distinct !DISubprogram(name: "scan", scope: !1, file: !1, line: 4, type: !15, isLocal: false, isDefinition: true, scopeLine: 5, flags: DIFlagPrototyped, isOptimized: true, unit: !0, retainedNodes: !17)
+!26 = !DILocation(line: 6, column: 17, scope: !25)
+!27 = !DILocalVariable(name: "entry", scope: !25, file: !1, line: 6, type: !4)
+!28 = distinct !DISubprogram(name: "scan", scope: !1, file: !1, line: 4, type: !15, isLocal: false, isDefinition: true, scopeLine: 5, flags: DIFlagPrototyped, isOptimized: true, unit: !0, retainedNodes: !17)
+!29 = !DILocation(line: 6, column: 17, scope: !28)
+!30 = !DILocalVariable(name: "entry", scope: !28, file: !1, line: 6, type: !4)
+!31 = distinct !DISubprogram(name: "scan", scope: !1, file: !1, line: 4, type: !15, isLocal: false, isDefinition: true, scopeLine: 5, flags: DIFlagPrototyped, isOptimized: true, unit: !0, retainedNodes: !17)
+!32 = !DILocation(line: 6, column: 17, scope: !31)
+!33 = !DILocalVariable(name: "entry", scope: !31, file: !1, line: 6, type: !4)

Added: llvm/trunk/test/Transforms/InstCombine/debuginfo-dce2.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/debuginfo-dce2.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/debuginfo-dce2.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/debuginfo-dce2.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,70 @@
+; RUN: opt -instcombine -S %s -o - | FileCheck %s
+
+; In this example, the cast from i8* to i32* becomes trivially dead. We should
+; salvage its debug info.
+
+; C source:
+; void use_as_void(void *);
+; void f(void *p) {
+;   int *q = (int *)p;
+;   use_as_void(q);
+; }
+
+; ModuleID = '<stdin>'
+source_filename = "t.c"
+target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-pc-windows-msvc19.11.25508"
+
+; Function Attrs: nounwind uwtable
+define void @f(i8* %p) !dbg !11 {
+entry:
+  call void @llvm.dbg.value(metadata i8* %p, metadata !16, metadata !DIExpression()), !dbg !18
+  %0 = bitcast i8* %p to i32*, !dbg !19
+  call void @llvm.dbg.value(metadata i32* %0, metadata !17, metadata !DIExpression()), !dbg !20
+  %1 = bitcast i32* %0 to i8*, !dbg !21
+  call void @use_as_void(i8* %1), !dbg !22
+  ret void, !dbg !23
+}
+
+; CHECK-LABEL: define void @f(i8* %p)
+; CHECK: call void @llvm.dbg.value(metadata i8* %p, metadata ![[P_VAR:[0-9]+]], metadata !DIExpression())
+; CHECK-NOT: bitcast
+; CHECK: call void @llvm.dbg.value(metadata i8* %p, metadata ![[Q_VAR:[0-9]+]], metadata !DIExpression())
+; CHECK-NOT: bitcast
+; CHECK ret void
+
+; CHECK: ![[P_VAR]] = !DILocalVariable(name: "p", {{.*}})
+; CHECK: ![[Q_VAR]] = !DILocalVariable(name: "q", {{.*}})
+
+declare void @use_as_void(i8*)
+
+declare void @llvm.dbg.value(metadata, metadata, metadata)
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!6, !7, !8, !9}
+!llvm.ident = !{!10}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 6.0.0 ", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, retainedTypes: !3)
+!1 = !DIFile(filename: "t.c", directory: "C:\5Csrc\5Cllvm-project\5Cbuild", checksumkind: CSK_MD5, checksum: "56c40617ada23a8cccbd9a16bcec57af")
+!2 = !{}
+!3 = !{!4}
+!4 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !5, size: 64)
+!5 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!6 = !{i32 2, !"CodeView", i32 1}
+!7 = !{i32 2, !"Debug Info Version", i32 3}
+!8 = !{i32 1, !"wchar_size", i32 2}
+!9 = !{i32 7, !"PIC Level", i32 2}
+!10 = !{!"clang version 6.0.0 "}
+!11 = distinct !DISubprogram(name: "f", scope: !1, file: !1, line: 2, type: !12, isLocal: false, isDefinition: true, scopeLine: 2, flags: DIFlagPrototyped, isOptimized: true, unit: !0, retainedNodes: !15)
+!12 = !DISubroutineType(types: !13)
+!13 = !{null, !14}
+!14 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: null, size: 64)
+!15 = !{!16, !17}
+!16 = !DILocalVariable(name: "p", arg: 1, scope: !11, file: !1, line: 2, type: !14)
+!17 = !DILocalVariable(name: "q", scope: !11, file: !1, line: 3, type: !4)
+!18 = !DILocation(line: 2, column: 14, scope: !11)
+!19 = !DILocation(line: 3, column: 12, scope: !11)
+!20 = !DILocation(line: 3, column: 8, scope: !11)
+!21 = !DILocation(line: 4, column: 15, scope: !11)
+!22 = !DILocation(line: 4, column: 3, scope: !11)
+!23 = !DILocation(line: 5, column: 1, scope: !11)

Added: llvm/trunk/test/Transforms/InstCombine/debuginfo-sink.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/debuginfo-sink.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/debuginfo-sink.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/debuginfo-sink.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,78 @@
+; RUN: opt  %s -instcombine -S | FileCheck %s
+
+; Test sinking of dbg.values when instcombine sinks associated instructions.
+
+declare void @llvm.dbg.value(metadata, metadata, metadata)
+
+; This GEP is sunk, but can be folded into a DIExpression. Check that it
+; gets folded. The dbg.value should be duplicated in the block its sunk
+; into, to maximise liveness.
+;
+; CHECK-LABEL: define i32 @foo(i32*
+; CHECK:       call void @llvm.dbg.value(metadata i32* %a, metadata !{{[0-9]+}},
+; CHECK-SAME:  metadata !DIExpression(DW_OP_plus_uconst, 4, DW_OP_stack_value))
+; CHECK-NEXT:  br label %sink1
+
+define i32 @foo(i32 *%a) !dbg !7 {
+entry:
+  %gep = getelementptr i32, i32 *%a, i32 1
+  call void @llvm.dbg.value(metadata i32 *%gep, metadata !16, metadata !12), !dbg !15
+  br label %sink1
+
+sink1:
+; CHECK-LABEL: sink1:
+; CHECK:       call void @llvm.dbg.value(metadata i32* %gep,
+; CHECK-SAME:                    metadata !{{[0-9]+}}, metadata !DIExpression())
+; CHECK-NEXT:  load
+  %0 = load i32, i32* %gep, align 4, !dbg !15
+  ret i32 %0, !dbg !15
+}
+
+; In this example the GEP cannot (yet) be salvaged. Check that not only is the
+; dbg.value sunk, but an undef dbg.value is left to terminate any earlier
+; value range.
+
+; CHECK-LABEL: define i32 @bar(
+; CHECK:       call void @llvm.dbg.value(metadata i32* undef,
+; CHECK-NEXT:  br label %sink2
+
+define i32 @bar(i32 *%a, i32 %b) !dbg !70 {
+entry:
+  %gep = getelementptr i32, i32 *%a, i32 %b
+  call void @llvm.dbg.value(metadata i32* %gep, metadata !73, metadata !12), !dbg !74
+  br label %sink2
+
+sink2:
+; CHECK-LABEL: sink2:
+; CHECK:       call void @llvm.dbg.value(metadata i32* %gep,
+; CHECK-SAME:                    metadata !{{[0-9]+}}, metadata !DIExpression())
+; CHECK-NEXT:  load
+; CHECK-NEXT:  ret
+  %0 = load i32, i32* %gep
+  ret i32 %0
+}
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!3, !4, !5}
+!llvm.ident = !{!6}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug)
+!1 = !DIFile(filename: "a.c", directory: ".")
+!2 = !{}
+!3 = !{i32 2, !"Dwarf Version", i32 4}
+!4 = !{i32 2, !"Debug Info Version", i32 3}
+!5 = !{i32 1, !"PIC Level", i32 2}
+!6 = !{!"clang"}
+!7 = distinct !DISubprogram(name: "foo", scope: !1, file: !1, line: 2, type: !8, isLocal: false, isDefinition: true, scopeLine: 3, flags: DIFlagPrototyped, isOptimized: false, unit: !0, retainedNodes: !2)
+!8 = !DISubroutineType(types: !9)
+!9 = !{!10, !10}
+!10 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!11 = !DILocalVariable(name: "j", scope: !7, file: !1, line: 2, type: !10)
+!12 = !DIExpression()
+!15 = !DILocation(line: 5, column: 3, scope: !7)
+!16 = !DILocalVariable(name: "h", scope: !7, file: !1, line: 4, type: !10)
+!70 = distinct !DISubprogram(name: "bar", scope: !1, file: !1, line: 2, type: !71, isLocal: false, isDefinition: true, scopeLine: 3, flags: DIFlagPrototyped, isOptimized: false, unit: !0, retainedNodes: !2)
+!71 = !DISubroutineType(types: !72)
+!72 = !{!10, !10, !10}
+!73 = !DILocalVariable(name: "k", scope: !70, file: !1, line: 2, type: !10)
+!74 = !DILocation(line: 5, column: 3, scope: !70)

Added: llvm/trunk/test/Transforms/InstCombine/debuginfo-skip.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/debuginfo-skip.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/debuginfo-skip.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/debuginfo-skip.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,45 @@
+; RUN: opt -instcombine-lower-dbg-declare=0 < %s -instcombine -S | FileCheck %s
+; RUN: opt -instcombine-lower-dbg-declare=1 < %s -instcombine -S | FileCheck %s
+
+define i32 @foo(i32 %j) #0 !dbg !7 {
+entry:
+  %j.addr = alloca i32, align 4
+  store i32 %j, i32* %j.addr, align 4
+  call void @llvm.dbg.declare(metadata i32* %j.addr, metadata !11, metadata !12), !dbg !13
+  call void @llvm.dbg.value(metadata i32 10, metadata !16, metadata !12), !dbg !15
+  %0 = load i32, i32* %j.addr, align 4, !dbg !14
+  ret i32 %0, !dbg !15
+}
+
+; Instcombine can remove the alloca and forward the load to store, but it
+; should convert the declare to dbg value.
+; CHECK-LABEL: define i32 @foo(i32 %j)
+; CHECK-NOT: alloca
+; CHECK: call void @llvm.dbg.value(metadata i32 %j, {{.*}})
+; CHECK: call void @llvm.dbg.value(metadata i32 10, {{.*}})
+; CHECK: ret i32 %j
+
+declare void @llvm.dbg.declare(metadata, metadata, metadata) #1
+declare void @llvm.dbg.value(metadata, metadata, metadata) #1
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!3, !4, !5}
+!llvm.ident = !{!6}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang 5.0.0", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug)
+!1 = !DIFile(filename: "a.c", directory: "/tmp")
+!2 = !{}
+!3 = !{i32 2, !"Dwarf Version", i32 4}
+!4 = !{i32 2, !"Debug Info Version", i32 3}
+!5 = !{i32 1, !"PIC Level", i32 2}
+!6 = !{!"clang version 5.0.0 (trunk 302918) (llvm/trunk 302925)"}
+!7 = distinct !DISubprogram(name: "foo", scope: !1, file: !1, line: 2, type: !8, isLocal: false, isDefinition: true, scopeLine: 3, flags: DIFlagPrototyped, isOptimized: false, unit: !0, retainedNodes: !2)
+!8 = !DISubroutineType(types: !9)
+!9 = !{!10, !10}
+!10 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!11 = !DILocalVariable(name: "j", arg: 1, scope: !7, file: !1, line: 2, type: !10)
+!12 = !DIExpression()
+!13 = !DILocation(line: 2, column: 13, scope: !7)
+!14 = !DILocation(line: 5, column: 10, scope: !7)
+!15 = !DILocation(line: 5, column: 3, scope: !7)
+!16 = !DILocalVariable(name: "h", scope: !7, file: !1, line: 4, type: !10)

Added: llvm/trunk/test/Transforms/InstCombine/debuginfo-variables.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/debuginfo-variables.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/debuginfo-variables.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/debuginfo-variables.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,122 @@
+; RUN: opt < %s -debugify -instcombine -S | FileCheck %s
+
+declare void @escape32(i32)
+
+define i64 @test_sext_zext(i16 %A) {
+; CHECK-LABEL: @test_sext_zext(
+; CHECK-NEXT:  [[C2:%.*]] = zext i16 %A to i64
+; CHECK-NEXT:  call void @llvm.dbg.value(metadata i64 [[C2]], {{.*}}, metadata !DIExpression())
+; CHECK-NEXT:  call void @llvm.dbg.value(metadata i64 [[C2]], {{.*}}, metadata !DIExpression())
+  %c1 = zext i16 %A to i32
+  %c2 = sext i32 %c1 to i64
+  ret i64 %c2
+}
+
+define i64 @test_used_sext_zext(i16 %A) {
+; CHECK-LABEL: @test_used_sext_zext(
+; CHECK-NEXT:  [[C1:%.*]] = zext i16 %A to i32
+; CHECK-NEXT:  call void @llvm.dbg.value(metadata i32 [[C1]], {{.*}}, metadata !DIExpression())
+; CHECK-NEXT:  [[C2:%.*]] = zext i16 %A to i64
+; CHECK-NEXT:  call void @llvm.dbg.value(metadata i64 [[C2]], {{.*}}, metadata !DIExpression())
+; CHECK-NEXT:  call void @escape32(i32 %c1)
+; CHECK-NEXT:  ret i64 %c2
+  %c1 = zext i16 %A to i32
+  %c2 = sext i32 %c1 to i64
+  call void @escape32(i32 %c1)
+  ret i64 %c2
+}
+
+define i32 @test_cast_select(i1 %cond) {
+; CHECK-LABEL: @test_cast_select(
+; CHECK-NEXT:  [[sel:%.*]] = select i1 %cond, i32 3, i32 5
+; CHECK-NEXT:  call void @llvm.dbg.value(metadata i32 [[sel]], {{.*}}, metadata !DIExpression())
+; CHECK-NEXT:  call void @llvm.dbg.value(metadata i32 [[sel]], {{.*}}, metadata !DIExpression())
+; CHECK-NEXT:  ret i32 [[sel]]
+  %sel = select i1 %cond, i16 3, i16 5
+  %cast = zext i16 %sel to i32
+  ret i32 %cast
+}
+
+define void @test_or(i64 %A) {
+; CHECK-LABEL: @test_or(
+; CHECK-NEXT:  call void @llvm.dbg.value(metadata i64 %A, {{.*}}, metadata !DIExpression(DW_OP_constu, 256, DW_OP_or, DW_OP_stack_value))
+  %1 = or i64 %A, 256
+  ret void
+}
+
+define void @test_xor(i32 %A) {
+; CHECK-LABEL: @test_xor(
+; CHECK-NEXT:  call void @llvm.dbg.value(metadata i32 %A, {{.*}}, metadata !DIExpression(DW_OP_constu, 1, DW_OP_xor, DW_OP_stack_value))
+  %1 = xor i32 %A, 1
+  ret void
+}
+
+define void @test_sub_neg(i64 %A) {
+; CHECK-LABEL: @test_sub_neg(
+; CHECK-NEXT:  call void @llvm.dbg.value(metadata i64 %A, {{.*}}, metadata !DIExpression(DW_OP_plus_uconst, 1, DW_OP_stack_value))
+  %1 = sub i64 %A, -1
+  ret void
+}
+
+define void @test_sub_pos(i64 %A) {
+; CHECK-LABEL: @test_sub_pos(
+; CHECK-NEXT:  call void @llvm.dbg.value(metadata i64 %A, {{.*}}, metadata !DIExpression(DW_OP_constu, 1, DW_OP_minus, DW_OP_stack_value))
+  %1 = sub i64 %A, 1
+  ret void
+}
+
+define void @test_shl(i64 %A) {
+; CHECK-LABEL: @test_shl(
+; CHECK-NEXT:  call void @llvm.dbg.value(metadata i64 %A, {{.*}}, metadata !DIExpression(DW_OP_constu, 7, DW_OP_shl, DW_OP_stack_value))
+  %1 = shl i64 %A, 7
+  ret void
+}
+
+define void @test_lshr(i64 %A) {
+; CHECK-LABEL: @test_lshr(
+; CHECK-NEXT:  call void @llvm.dbg.value(metadata i64 %A, {{.*}}, metadata !DIExpression(DW_OP_constu, 7, DW_OP_shr, DW_OP_stack_value))
+  %1 = lshr i64 %A, 7
+  ret void
+}
+
+define void @test_ashr(i64 %A) {
+; CHECK-LABEL: @test_ashr(
+; CHECK-NEXT:  call void @llvm.dbg.value(metadata i64 %A, {{.*}}, metadata !DIExpression(DW_OP_constu, 7, DW_OP_shra, DW_OP_stack_value))
+  %1 = ashr i64 %A, 7
+  ret void
+}
+
+define void @test_mul(i64 %A) {
+; CHECK-LABEL: @test_mul(
+; CHECK-NEXT:  call void @llvm.dbg.value(metadata i64 %A, {{.*}}, metadata !DIExpression(DW_OP_constu, 7, DW_OP_mul, DW_OP_stack_value))
+  %1 = mul i64 %A, 7
+  ret void
+}
+
+define void @test_sdiv(i64 %A) {
+; CHECK-LABEL: @test_sdiv(
+; CHECK-NEXT:  call void @llvm.dbg.value(metadata i64 %A, {{.*}}, metadata !DIExpression(DW_OP_constu, 7, DW_OP_div, DW_OP_stack_value))
+  %1 = sdiv i64 %A, 7
+  ret void
+}
+
+define void @test_srem(i64 %A) {
+; CHECK-LABEL: @test_srem(
+; CHECK-NEXT:  call void @llvm.dbg.value(metadata i64 %A, {{.*}}, metadata !DIExpression(DW_OP_constu, 7, DW_OP_mod, DW_OP_stack_value))
+  %1 = srem i64 %A, 7
+  ret void
+}
+
+define void @test_ptrtoint(i64* %P) {
+; CHECK-LABEL: @test_ptrtoint
+; CHECK-NEXT:  call void @llvm.dbg.value(metadata i64* %P, {{.*}}, metadata !DIExpression())
+  %1 = ptrtoint i64* %P to i64
+  ret void
+}
+
+define void @test_and(i64 %A) {
+; CHECK-LABEL: @test_and(
+; CHECK-NEXT:  call void @llvm.dbg.value(metadata i64 %A, {{.*}}, metadata !DIExpression(DW_OP_constu, 256, DW_OP_and, DW_OP_stack_value))
+  %1 = and i64 %A, 256
+  ret void
+}

Added: llvm/trunk/test/Transforms/InstCombine/debuginfo.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/debuginfo.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/debuginfo.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/debuginfo.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,119 @@
+; RUN: opt < %s -instcombine -instcombine-lower-dbg-declare=0 -S \
+; RUN:      | FileCheck %s --check-prefix=CHECK --check-prefix=NOLOWER
+; RUN: opt < %s -instcombine -instcombine-lower-dbg-declare=1 -S | FileCheck %s
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64--linux"
+
+%struct.TwoRegs = type { i64, i64 }
+
+declare void @llvm.dbg.declare(metadata, metadata, metadata) nounwind readnone
+
+declare i64 @llvm.objectsize.i64.p0i8(i8*, i1) nounwind readnone
+
+declare i8* @passthru_callee(i8*, i32, i64, i64)
+
+define i8* @passthru(i8* %a, i32 %b, i64 %c) !dbg !1 {
+entry:
+  %a.addr = alloca i8*, align 8
+  %b.addr = alloca i32, align 4
+  %c.addr = alloca i64, align 8
+  store i8* %a, i8** %a.addr, align 8
+  call void @llvm.dbg.declare(metadata i8** %a.addr, metadata !0, metadata !DIExpression()), !dbg !16
+  store i32 %b, i32* %b.addr, align 4
+  call void @llvm.dbg.declare(metadata i32* %b.addr, metadata !7, metadata !DIExpression()), !dbg !18
+  store i64 %c, i64* %c.addr, align 8
+  call void @llvm.dbg.declare(metadata i64* %c.addr, metadata !9, metadata !DIExpression()), !dbg !20
+  %tmp = load i8*, i8** %a.addr, align 8, !dbg !21
+  %tmp1 = load i32, i32* %b.addr, align 4, !dbg !21
+  %tmp2 = load i64, i64* %c.addr, align 8, !dbg !21
+  %tmp3 = load i8*, i8** %a.addr, align 8, !dbg !21
+  %0 = call i64 @llvm.objectsize.i64.p0i8(i8* %tmp3, i1 false), !dbg !21
+  %call = call i8* @passthru_callee(i8* %tmp, i32 %tmp1, i64 %tmp2, i64 %0), !dbg !21
+  ret i8* %call, !dbg !21
+}
+
+; CHECK-LABEL: define i8* @passthru(i8* %a, i32 %b, i64 %c)
+; CHECK-NOT: alloca
+; CHECK-NOT: store
+; CHECK-NOT: call void @llvm.dbg.declare
+; CHECK: call void @llvm.dbg.value(metadata i8* %a, {{.*}})
+; CHECK-NOT: store
+; CHECK: call void @llvm.dbg.value(metadata i32 %b, {{.*}})
+; CHECK-NOT: store
+; CHECK: call void @llvm.dbg.value(metadata i64 %c, {{.*}})
+; CHECK-NOT: store
+; CHECK: call i8* @passthru_callee(i8* %a, i32 %b, i64 %c, i64 %{{.*}})
+
+declare void @tworegs_callee(i64, i64)
+
+; Lowering dbg.declare in instcombine doesn't handle this case very well.
+
+define void @tworegs(i64 %o.coerce0, i64 %o.coerce1) !dbg !31 {
+entry:
+  %o = alloca %struct.TwoRegs, align 8
+  %0 = bitcast %struct.TwoRegs* %o to { i64, i64 }*
+  %1 = getelementptr inbounds { i64, i64 }, { i64, i64 }* %0, i32 0, i32 0
+  store i64 %o.coerce0, i64* %1, align 8
+  %2 = getelementptr inbounds { i64, i64 }, { i64, i64 }* %0, i32 0, i32 1
+  store i64 %o.coerce1, i64* %2, align 8
+  call void @llvm.dbg.declare(metadata %struct.TwoRegs* %o, metadata !35, metadata !DIExpression()), !dbg !32
+  %3 = bitcast %struct.TwoRegs* %o to { i64, i64 }*, !dbg !33
+  %4 = getelementptr inbounds { i64, i64 }, { i64, i64 }* %3, i32 0, i32 0, !dbg !33
+  %5 = load i64, i64* %4, align 8, !dbg !33
+  %6 = getelementptr inbounds { i64, i64 }, { i64, i64 }* %3, i32 0, i32 1, !dbg !33
+  %7 = load i64, i64* %6, align 8, !dbg !33
+  call void @tworegs_callee(i64 %5, i64 %7), !dbg !33
+  ret void, !dbg !33
+}
+
+; NOLOWER-LABEL: define void @tworegs(i64 %o.coerce0, i64 %o.coerce1)
+; NOLOWER-NOT: alloca
+; NOLOWER-NOT: store
+; NOLOWER-NOT: call void @llvm.dbg.declare
+; Here we want to find:  call void @llvm.dbg.value(metadata i64 %o.coerce0, metadata [[VARIABLE_O]], metadata !DIExpression(DW_OP_LLVM_fragment, 0, 64))
+; NOLOWER: call void @llvm.dbg.value(metadata i64 undef, {{.*}})
+; NOLOWER-NOT: store
+; Here we want to find:  call void @llvm.dbg.value(metadata i64 %o.coerce1, metadata [[VARIABLE_O]], metadata !DIExpression(DW_OP_LLVM_fragment, 64, 64))
+; NOLOWER: call void @llvm.dbg.value(metadata i64 undef, {{.*}})
+; NOLOWER-NOT: store
+; NOLOWER: call void @tworegs_callee(i64 %o.coerce0, i64 %o.coerce1)
+
+
+!llvm.dbg.cu = !{!3}
+!llvm.module.flags = !{!30}
+
+!0 = !DILocalVariable(name: "a", line: 78, arg: 1, scope: !1, file: !2, type: !6)
+!1 = distinct !DISubprogram(name: "passthru", line: 79, isLocal: true, isDefinition: true, virtualIndex: 6, flags: DIFlagPrototyped, isOptimized: true, unit: !3, scopeLine: 79, file: !27, scope: !2, type: !4, retainedNodes: !25)
+!2 = !DIFile(filename: "string.h", directory: "Game")
+!3 = distinct !DICompileUnit(language: DW_LANG_C99, producer: "clang version 3.0 (trunk 127710)", isOptimized: true, emissionKind: FullDebug, file: !28, enums: !29, retainedTypes: !29)
+!4 = !DISubroutineType(types: !5)
+!5 = !{!6}
+!6 = !DIDerivedType(tag: DW_TAG_pointer_type, size: 64, align: 64, scope: !3, baseType: null)
+!7 = !DILocalVariable(name: "b", line: 78, arg: 2, scope: !1, file: !2, type: !8)
+!8 = !DIBasicType(tag: DW_TAG_base_type, name: "int", size: 32, align: 32, encoding: DW_ATE_signed)
+!9 = !DILocalVariable(name: "c", line: 78, arg: 3, scope: !1, file: !2, type: !12)
+!12 = !DIBasicType(tag: DW_TAG_base_type, name: "long unsigned int", size: 64, align: 64, encoding: DW_ATE_unsigned)
+!16 = !DILocation(line: 78, column: 28, scope: !1)
+!18 = !DILocation(line: 78, column: 40, scope: !1)
+!20 = !DILocation(line: 78, column: 54, scope: !1)
+!21 = !DILocation(line: 80, column: 3, scope: !22)
+!22 = distinct !DILexicalBlock(line: 80, column: 3, file: !27, scope: !23)
+!23 = distinct !DILexicalBlock(line: 79, column: 1, file: !27, scope: !1)
+!25 = !{!0, !7, !9}
+!27 = !DIFile(filename: "string.h", directory: "Game")
+!28 = !DIFile(filename: "bits.c", directory: "Game")
+!29 = !{}
+!30 = !{i32 1, !"Debug Info Version", i32 3}
+
+!31 = distinct !DISubprogram(name: "tworegs", scope: !28, file: !28, line: 4, type: !4, isLocal: false, isDefinition: true, scopeLine: 4, flags: DIFlagPrototyped, isOptimized: true, unit: !3, retainedNodes: !34)
+!32 = !DILocation(line: 4, column: 23, scope: !31)
+!33 = !DILocation(line: 5, column: 3, scope: !31)
+!34 = !{!35}
+!35 = !DILocalVariable(name: "o", arg: 1, scope: !31, file: !28, line: 4, type: !36)
+!36 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "TwoRegs", file: !28, line: 1, size: 128, elements: !37)
+!37 = !{!38, !39}
+!38 = !DIDerivedType(tag: DW_TAG_member, name: "x", scope: !36, file: !28, line: 1, baseType: !12, size: 64)
+!39 = !DIDerivedType(tag: DW_TAG_member, name: "y", scope: !36, file: !28, line: 1, baseType: !12, size: 64)
+!40 = !DISubroutineType(types: !41)
+!41 = !{!36}

Added: llvm/trunk/test/Transforms/InstCombine/debuginfo_add.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/debuginfo_add.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/debuginfo_add.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/debuginfo_add.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,114 @@
+; RUN: opt -instcombine %s -o - -S | FileCheck %s
+; typedef struct v *v_t;
+; struct v {
+;   unsigned long long p;
+; };
+;  
+; void f(v_t object, unsigned long long *start) {
+;   unsigned head_size;
+;   unsigned long long orig_start;
+;   unsigned long long offset;
+;   orig_start = *start;
+;   for (offset = orig_start - (unsigned long long)(1 << 12); head_size;
+;        offset -= (unsigned long long)(1 << 12), head_size -= (1 << 12))
+;     use(offset, (object));
+; }
+source_filename = "test.i"
+target datalayout = "e-m:o-p:32:32-f64:32:64-v64:32:64-v128:32:128-a:0:32-n32-S32"
+target triple = "thumbv7s-apple-ios5.0.0"
+
+%struct.vm_object = type { i64 }
+
+; Function Attrs: nounwind ssp
+define void @f(%struct.vm_object* %object, i64* nocapture readonly %start) local_unnamed_addr #0 !dbg !11 {
+entry:
+  tail call void @llvm.dbg.value(metadata %struct.vm_object* %object, metadata !21, metadata !DIExpression()), !dbg !27
+  tail call void @llvm.dbg.value(metadata i64* %start, metadata !22, metadata !DIExpression()), !dbg !28
+  %0 = load i64, i64* %start, align 4, !dbg !29
+  tail call void @llvm.dbg.value(metadata i64 %0, metadata !25, metadata !DIExpression()), !dbg !30
+  %offset.08 = add i64 %0, -4096
+  tail call void @llvm.dbg.value(metadata i64 %offset.08, metadata !26, metadata !DIExpression()), !dbg !31
+  tail call void @llvm.dbg.value(metadata i32 undef, metadata !23, metadata !DIExpression()), !dbg !32
+  br i1 undef, label %for.end, label %for.body.lr.ph, !dbg !32
+
+for.body.lr.ph:                                   ; preds = %entry
+  ; The 'load' and the 'add' are sunken to this basic block. So let's verify that the related dbg.values are sunken as well.
+  ; The add is later eliminated, so we verify that the dbg.value is salvaged by using DW_OP_minus.
+  ; CHECK-LABEL: for.body.lr.ph:
+  ; CHECK-NEXT: %0 = load
+  ; CHECK-NEXT: call void @llvm.dbg.value(metadata i64 %0, metadata !25, metadata !DIExpression()), !dbg !
+  ; CHECK-NEXT: call void @llvm.dbg.value(metadata i64 %0, metadata !26, metadata !DIExpression(DW_OP_constu, 4096, DW_OP_minus, DW_OP_stack_value)), !dbg !
+  br label %for.body, !dbg !32
+
+for.body:                                         ; preds = %for.body.lr.ph, %for.body
+  ; CHECK-LABEL: for.body:
+  %offset.010 = phi i64 [ %offset.08, %for.body.lr.ph ], [ %offset.0, %for.body ]
+  %head_size.09 = phi i32 [ undef, %for.body.lr.ph ], [ %sub2, %for.body ]
+  tail call void @llvm.dbg.value(metadata i32 %head_size.09, metadata !23, metadata !DIExpression()), !dbg !31
+  %call = tail call i32 bitcast (i32 (...)* @use to i32 (i64, %struct.vm_object*)*)(i64 %offset.010, %struct.vm_object* %object) #3, !dbg !34
+  %sub2 = add i32 %head_size.09, -4096, !dbg !37
+  %offset.0 = add i64 %offset.010, -4096
+  tail call void @llvm.dbg.value(metadata i64 %offset.0, metadata !26, metadata !DIExpression()), !dbg !30
+  ; CHECK: call void @llvm.dbg.value(metadata i64 %offset.010, metadata !26, metadata !DIExpression(DW_OP_constu, 4096, DW_OP_minus, DW_OP_stack_value)), !dbg !
+  tail call void @llvm.dbg.value(metadata i32 %sub2, metadata !23, metadata !DIExpression()), !dbg !31
+  %tobool = icmp eq i32 %sub2, 0, !dbg !32
+  br i1 %tobool, label %for.end, label %for.body, !dbg !32, !llvm.loop !38
+
+for.end:                                          ; preds = %for.body, %entry
+  ret void, !dbg !40
+}
+
+declare i32 @use(...) local_unnamed_addr
+
+; Function Attrs: nounwind readnone speculatable
+declare void @llvm.dbg.value(metadata, metadata, metadata) #2
+
+attributes #0 = { nounwind ssp }
+attributes #2 = { nounwind readnone speculatable }
+attributes #3 = { nobuiltin }
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!5, !6, !7, !8, !9}
+!llvm.ident = !{!10}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 6.0.0 (trunk 317434) (llvm/trunk 317437)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, retainedTypes: !3)
+!1 = !DIFile(filename: "test.i", directory: "/Data/radar/31209283")
+!2 = !{}
+!3 = !{!4}
+!4 = !DIBasicType(name: "long long unsigned int", size: 64, encoding: DW_ATE_unsigned)
+!5 = !{i32 2, !"Dwarf Version", i32 2}
+!6 = !{i32 2, !"Debug Info Version", i32 3}
+!7 = !{i32 1, !"wchar_size", i32 4}
+!8 = !{i32 1, !"min_enum_size", i32 4}
+!9 = !{i32 7, !"PIC Level", i32 2}
+!10 = !{!"clang version 6.0.0 (trunk 317434) (llvm/trunk 317437)"}
+!11 = distinct !DISubprogram(name: "f", scope: !1, file: !1, line: 6, type: !12, isLocal: false, isDefinition: true, scopeLine: 6, flags: DIFlagPrototyped, isOptimized: true, unit: !0, retainedNodes: !20)
+!12 = !DISubroutineType(types: !13)
+!13 = !{null, !14, !19}
+!14 = !DIDerivedType(tag: DW_TAG_typedef, name: "v_t", file: !1, line: 1, baseType: !15)
+!15 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !16, size: 32)
+!16 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "v", file: !1, line: 2, size: 64, elements: !17)
+!17 = !{!18}
+!18 = !DIDerivedType(tag: DW_TAG_member, name: "p", scope: !16, file: !1, line: 3, baseType: !4, size: 64)
+!19 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !4, size: 32)
+!20 = !{!21, !22, !23, !25, !26}
+!21 = !DILocalVariable(name: "object", arg: 1, scope: !11, file: !1, line: 6, type: !14)
+!22 = !DILocalVariable(name: "start", arg: 2, scope: !11, file: !1, line: 6, type: !19)
+!23 = !DILocalVariable(name: "head_size", scope: !11, file: !1, line: 7, type: !24)
+!24 = !DIBasicType(name: "unsigned int", size: 32, encoding: DW_ATE_unsigned)
+!25 = !DILocalVariable(name: "orig_start", scope: !11, file: !1, line: 8, type: !4)
+!26 = !DILocalVariable(name: "offset", scope: !11, file: !1, line: 9, type: !4)
+!27 = !DILocation(line: 6, column: 20, scope: !11)
+!28 = !DILocation(line: 6, column: 48, scope: !11)
+!29 = !DILocation(line: 8, column: 22, scope: !11)
+!30 = !DILocation(line: 7, column: 12, scope: !11)
+!31 = !DILocation(line: 10, column: 16, scope: !11)
+!32 = !DILocation(line: 11, column: 5, scope: !33)
+!33 = distinct !DILexicalBlock(scope: !11, file: !1, line: 11, column: 5)
+!34 = !DILocation(line: 13, column: 7, scope: !35)
+!35 = distinct !DILexicalBlock(scope: !36, file: !1, line: 12, column: 75)
+!36 = distinct !DILexicalBlock(scope: !33, file: !1, line: 11, column: 5)
+!37 = !DILocation(line: 12, column: 61, scope: !36)
+!38 = distinct !{!38, !32, !39}
+!39 = !DILocation(line: 14, column: 3, scope: !33)
+!40 = !DILocation(line: 15, column: 1, scope: !11)

Added: llvm/trunk/test/Transforms/InstCombine/default-alignment.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/default-alignment.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/default-alignment.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/default-alignment.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,10 @@
+; RUN: opt -verify -instcombine < %s
+%Foo = type <{ i8, x86_fp80 }>
+
+define i8 @t(%Foo* %arg) {
+entry:
+  %0 = getelementptr %Foo, %Foo* %arg, i32 0, i32 0
+  %1 = load i8, i8* %0, align 1
+  ret i8 %1
+}
+

Added: llvm/trunk/test/Transforms/InstCombine/demand_shrink_nsw.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/demand_shrink_nsw.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/demand_shrink_nsw.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/demand_shrink_nsw.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,33 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt -instcombine -o - -S %s | FileCheck %s
+
+; The constant at %v35 should be shrunk, but this must lead to the nsw flag of
+; %v43 getting removed.
+
+define i32 @foo(i32 %arg) {
+; CHECK-LABEL: @foo(
+; CHECK-NEXT:    [[V33:%.*]] = and i32 [[ARG:%.*]], 223
+; CHECK-NEXT:    [[V34:%.*]] = xor i32 [[V33]], 29
+; CHECK-NEXT:    [[V35:%.*]] = add nuw nsw i32 [[V34]], 1362915575
+; CHECK-NEXT:    [[V40:%.*]] = shl nuw nsw i32 [[V34]], 1
+; CHECK-NEXT:    [[V41:%.*]] = and i32 [[V40]], 290
+; CHECK-NEXT:    [[V42:%.*]] = sub nuw nsw i32 [[V35]], [[V41]]
+; CHECK-NEXT:    [[V43:%.*]] = add nuw i32 [[V42]], 1533579450
+; CHECK-NEXT:    [[V45:%.*]] = xor i32 [[V43]], 749011377
+; CHECK-NEXT:    ret i32 [[V45]]
+;
+  %v33 = and i32 %arg, 223
+  %v34 = xor i32 %v33, 29
+  %v35 = add nuw i32 %v34, 3510399223
+  %v37 = or i32 %v34, 1874836915
+  %v38 = and i32 %v34, 221
+  %v39 = xor i32 %v38, 1874836915
+  %v40 = xor i32 %v37, %v39
+  %v41 = shl nsw nuw i32 %v40, 1
+  %v42 = sub i32 %v35, %v41
+  %v43 = add nsw i32 %v42, 1533579450
+  %v44 = or i32 %v43, -2147483648
+  %v45 = xor i32 %v44, 749011377
+  ret i32 %v45
+}
+

Added: llvm/trunk/test/Transforms/InstCombine/demorgan-sink-not-into-xor.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/demorgan-sink-not-into-xor.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/demorgan-sink-not-into-xor.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/demorgan-sink-not-into-xor.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,138 @@
+; 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=38446
+
+; Pattern:
+;   ~(x ^ y)
+; Should be transformed into:
+;   (~x) ^ y
+; or into
+;   x ^ (~y)
+
+; While -reassociate does handle this simple pattern, it does not handle
+; the more complicated motivating pattern.
+
+; ============================================================================ ;
+; Basic positive tests
+; ============================================================================ ;
+
+; If the operand is easily-invertible, fold into it.
+declare i1 @gen1()
+
+define i1 @positive_easyinvert(i16 %x, i8 %y) {
+; CHECK-LABEL: @positive_easyinvert(
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp slt i16 [[X:%.*]], 0
+; CHECK-NEXT:    [[TMP2:%.*]] = icmp sgt i8 [[Y:%.*]], -1
+; CHECK-NEXT:    [[TMP4:%.*]] = xor i1 [[TMP1]], [[TMP2]]
+; CHECK-NEXT:    ret i1 [[TMP4]]
+;
+  %tmp1 = icmp slt i16 %x, 0
+  %tmp2 = icmp slt i8 %y, 0
+  %tmp3 = xor i1 %tmp2, %tmp1
+  %tmp4 = xor i1 %tmp3, true
+  ret i1 %tmp4
+}
+
+define i1 @positive_easyinvert0(i8 %y) {
+; CHECK-LABEL: @positive_easyinvert0(
+; CHECK-NEXT:    [[TMP1:%.*]] = call i1 @gen1()
+; CHECK-NEXT:    [[TMP2:%.*]] = icmp sgt i8 [[Y:%.*]], -1
+; CHECK-NEXT:    [[TMP4:%.*]] = xor i1 [[TMP1]], [[TMP2]]
+; CHECK-NEXT:    ret i1 [[TMP4]]
+;
+  %tmp1 = call i1 @gen1()
+  %tmp2 = icmp slt i8 %y, 0
+  %tmp3 = xor i1 %tmp2, %tmp1
+  %tmp4 = xor i1 %tmp3, true
+  ret i1 %tmp4
+}
+
+define i1 @positive_easyinvert1(i8 %y) {
+; CHECK-LABEL: @positive_easyinvert1(
+; CHECK-NEXT:    [[TMP1:%.*]] = call i1 @gen1()
+; CHECK-NEXT:    [[TMP2:%.*]] = icmp sgt i8 [[Y:%.*]], -1
+; CHECK-NEXT:    [[TMP4:%.*]] = xor i1 [[TMP1]], [[TMP2]]
+; CHECK-NEXT:    ret i1 [[TMP4]]
+;
+  %tmp1 = call i1 @gen1()
+  %tmp2 = icmp slt i8 %y, 0
+  %tmp3 = xor i1 %tmp1, %tmp2
+  %tmp4 = xor i1 %tmp3, true
+  ret i1 %tmp4
+}
+
+; ============================================================================ ;
+; One-use tests with easily-invertible operand.
+; ============================================================================ ;
+
+declare void @use1(i1)
+
+define i1 @oneuse_easyinvert_0(i8 %y) {
+; CHECK-LABEL: @oneuse_easyinvert_0(
+; CHECK-NEXT:    [[TMP1:%.*]] = call i1 @gen1()
+; CHECK-NEXT:    [[TMP2:%.*]] = icmp slt i8 [[Y:%.*]], 0
+; CHECK-NEXT:    call void @use1(i1 [[TMP2]])
+; CHECK-NEXT:    [[TMP3:%.*]] = xor i1 [[TMP1]], [[TMP2]]
+; CHECK-NEXT:    [[TMP4:%.*]] = xor i1 [[TMP3]], true
+; CHECK-NEXT:    ret i1 [[TMP4]]
+;
+  %tmp1 = call i1 @gen1()
+  %tmp2 = icmp slt i8 %y, 0
+  call void @use1(i1 %tmp2)
+  %tmp3 = xor i1 %tmp1, %tmp2
+  %tmp4 = xor i1 %tmp3, true
+  ret i1 %tmp4
+}
+
+define i1 @oneuse_easyinvert_1(i8 %y) {
+; CHECK-LABEL: @oneuse_easyinvert_1(
+; CHECK-NEXT:    [[TMP1:%.*]] = call i1 @gen1()
+; CHECK-NEXT:    [[TMP2:%.*]] = icmp slt i8 [[Y:%.*]], 0
+; CHECK-NEXT:    [[TMP3:%.*]] = xor i1 [[TMP1]], [[TMP2]]
+; CHECK-NEXT:    call void @use1(i1 [[TMP3]])
+; CHECK-NEXT:    [[TMP4:%.*]] = xor i1 [[TMP3]], true
+; CHECK-NEXT:    ret i1 [[TMP4]]
+;
+  %tmp1 = call i1 @gen1()
+  %tmp2 = icmp slt i8 %y, 0
+  %tmp3 = xor i1 %tmp1, %tmp2
+  call void @use1(i1 %tmp3)
+  %tmp4 = xor i1 %tmp3, true
+  ret i1 %tmp4
+}
+
+define i1 @oneuse_easyinvert_2(i8 %y) {
+; CHECK-LABEL: @oneuse_easyinvert_2(
+; CHECK-NEXT:    [[TMP1:%.*]] = call i1 @gen1()
+; CHECK-NEXT:    [[TMP2:%.*]] = icmp slt i8 [[Y:%.*]], 0
+; CHECK-NEXT:    call void @use1(i1 [[TMP2]])
+; CHECK-NEXT:    [[TMP3:%.*]] = xor i1 [[TMP1]], [[TMP2]]
+; CHECK-NEXT:    call void @use1(i1 [[TMP3]])
+; CHECK-NEXT:    [[TMP4:%.*]] = xor i1 [[TMP3]], true
+; CHECK-NEXT:    ret i1 [[TMP4]]
+;
+  %tmp1 = call i1 @gen1()
+  %tmp2 = icmp slt i8 %y, 0
+  call void @use1(i1 %tmp2)
+  %tmp3 = xor i1 %tmp1, %tmp2
+  call void @use1(i1 %tmp3)
+  %tmp4 = xor i1 %tmp3, true
+  ret i1 %tmp4
+}
+
+; ============================================================================ ;
+; Negative tests
+; ============================================================================ ;
+
+; Not easily invertible.
+define i32 @negative(i32 %x, i32 %y) {
+; CHECK-LABEL: @negative(
+; CHECK-NEXT:    [[TMP1:%.*]] = xor i32 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    [[TMP2:%.*]] = xor i32 [[TMP1]], -1
+; CHECK-NEXT:    ret i32 [[TMP2]]
+;
+  %tmp1 = xor i32 %x, %y
+  %tmp2 = xor i32 %tmp1, -1
+  ret i32 %tmp2
+}

Added: llvm/trunk/test/Transforms/InstCombine/demorgan.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/demorgan.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/demorgan.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/demorgan.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,501 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt < %s -instcombine -S | FileCheck %s
+
+; (~A | ~B) == ~(A & B)
+
+define i43 @demorgan_or_apint1(i43 %A, i43 %B) {
+; CHECK-LABEL: @demorgan_or_apint1(
+; CHECK-NEXT:    [[C_DEMORGAN:%.*]] = and i43 %A, %B
+; CHECK-NEXT:    [[C:%.*]] = xor i43 [[C_DEMORGAN]], -1
+; CHECK-NEXT:    ret i43 [[C]]
+;
+  %NotA = xor i43 %A, -1
+  %NotB = xor i43 %B, -1
+  %C = or i43 %NotA, %NotB
+  ret i43 %C
+}
+
+; (~A | ~B) == ~(A & B)
+
+define i129 @demorgan_or_apint2(i129 %A, i129 %B) {
+; CHECK-LABEL: @demorgan_or_apint2(
+; CHECK-NEXT:    [[C_DEMORGAN:%.*]] = and i129 %A, %B
+; CHECK-NEXT:    [[C:%.*]] = xor i129 [[C_DEMORGAN]], -1
+; CHECK-NEXT:    ret i129 [[C]]
+;
+  %NotA = xor i129 %A, -1
+  %NotB = xor i129 %B, -1
+  %C = or i129 %NotA, %NotB
+  ret i129 %C
+}
+
+; (~A & ~B) == ~(A | B)
+
+define i477 @demorgan_and_apint1(i477 %A, i477 %B) {
+; CHECK-LABEL: @demorgan_and_apint1(
+; CHECK-NEXT:    [[C_DEMORGAN:%.*]] = or i477 %A, %B
+; CHECK-NEXT:    [[C:%.*]] = xor i477 [[C_DEMORGAN]], -1
+; CHECK-NEXT:    ret i477 [[C]]
+;
+  %NotA = xor i477 %A, -1
+  %NotB = xor i477 %B, -1
+  %C = and i477 %NotA, %NotB
+  ret i477 %C
+}
+
+; (~A & ~B) == ~(A | B)
+
+define i129 @demorgan_and_apint2(i129 %A, i129 %B) {
+; CHECK-LABEL: @demorgan_and_apint2(
+; CHECK-NEXT:    [[C_DEMORGAN:%.*]] = or i129 %A, %B
+; CHECK-NEXT:    [[C:%.*]] = xor i129 [[C_DEMORGAN]], -1
+; CHECK-NEXT:    ret i129 [[C]]
+;
+  %NotA = xor i129 %A, -1
+  %NotB = xor i129 %B, -1
+  %C = and i129 %NotA, %NotB
+  ret i129 %C
+}
+
+; (~A & ~B) == ~(A | B)
+
+define i65 @demorgan_and_apint3(i65 %A, i65 %B) {
+; CHECK-LABEL: @demorgan_and_apint3(
+; CHECK-NEXT:    [[C_DEMORGAN:%.*]] = or i65 %A, %B
+; CHECK-NEXT:    [[C:%.*]] = xor i65 [[C_DEMORGAN]], -1
+; CHECK-NEXT:    ret i65 [[C]]
+;
+  %NotA = xor i65 %A, -1
+  %NotB = xor i65 -1, %B
+  %C = and i65 %NotA, %NotB
+  ret i65 %C
+}
+
+; (~A & ~B) == ~(A | B)
+
+define i66 @demorgan_and_apint4(i66 %A, i66 %B) {
+; CHECK-LABEL: @demorgan_and_apint4(
+; CHECK-NEXT:    [[C_DEMORGAN:%.*]] = or i66 %A, %B
+; CHECK-NEXT:    [[C:%.*]] = xor i66 [[C_DEMORGAN]], -1
+; CHECK-NEXT:    ret i66 [[C]]
+;
+  %NotA = xor i66 %A, -1
+  %NotB = xor i66 %B, -1
+  %C = and i66 %NotA, %NotB
+  ret i66 %C
+}
+
+; (~A & ~B) == ~(A | B)
+
+define i47 @demorgan_and_apint5(i47 %A, i47 %B) {
+; CHECK-LABEL: @demorgan_and_apint5(
+; CHECK-NEXT:    [[C_DEMORGAN:%.*]] = or i47 %A, %B
+; CHECK-NEXT:    [[C:%.*]] = xor i47 [[C_DEMORGAN]], -1
+; CHECK-NEXT:    ret i47 [[C]]
+;
+  %NotA = xor i47 %A, -1
+  %NotB = xor i47 %B, -1
+  %C = and i47 %NotA, %NotB
+  ret i47 %C
+}
+
+; This is confirming that 2 transforms work together:
+; ~(~A & ~B) --> A | B
+
+define i32 @test3(i32 %A, i32 %B) {
+; CHECK-LABEL: @test3(
+; CHECK-NEXT:    [[C_DEMORGAN:%.*]] = or i32 %A, %B
+; CHECK-NEXT:    ret i32 [[C_DEMORGAN]]
+;
+  %nota = xor i32 %A, -1
+  %notb = xor i32 %B, -1
+  %c = and i32 %nota, %notb
+  %notc = xor i32 %c, -1
+  ret i32 %notc
+}
+
+; Invert a constant if needed:
+; ~(~A & 5) --> A | ~5
+
+define i32 @test4(i32 %A) {
+; CHECK-LABEL: @test4(
+; CHECK-NEXT:    [[NOTC1:%.*]] = or i32 %A, -6
+; CHECK-NEXT:    ret i32 [[NOTC1]]
+;
+  %nota = xor i32 %A, -1
+  %c = and i32 %nota, 5
+  %notc = xor i32 %c, -1
+  ret i32 %notc
+}
+
+; Test the mirror of DeMorgan's law with an extra 'not'.
+; ~(~A | ~B) --> A & B
+
+define i32 @test5(i32 %A, i32 %B) {
+; CHECK-LABEL: @test5(
+; CHECK-NEXT:    [[C_DEMORGAN:%.*]] = and i32 %A, %B
+; CHECK-NEXT:    ret i32 [[C_DEMORGAN]]
+;
+  %nota = xor i32 %A, -1
+  %notb = xor i32 %B, -1
+  %c = or i32 %nota, %notb
+  %notc = xor i32 %c, -1
+  ret i32 %notc
+}
+
+; Repeat with weird types for extra coverage.
+; ~(~A & ~B) --> A | B
+
+define i47 @test3_apint(i47 %A, i47 %B) {
+; CHECK-LABEL: @test3_apint(
+; CHECK-NEXT:    [[C_DEMORGAN:%.*]] = or i47 %A, %B
+; CHECK-NEXT:    ret i47 [[C_DEMORGAN]]
+;
+  %nota = xor i47 %A, -1
+  %notb = xor i47 %B, -1
+  %c = and i47 %nota, %notb
+  %notc = xor i47 %c, -1
+  ret i47 %notc
+}
+
+; ~(~A & 5) --> A | ~5
+
+define i61 @test4_apint(i61 %A) {
+; CHECK-LABEL: @test4_apint(
+; CHECK-NEXT:    [[NOTA:%.*]] = and i61 %A, 5
+; CHECK-NEXT:    [[C:%.*]] = xor i61 [[NOTA]], 5
+; CHECK-NEXT:    ret i61 [[C]]
+;
+  %nota = xor i61 %A, -1
+  %c = and i61 %nota, 5    ; 5 = ~c2
+  %notc = xor i61 %c, -1
+  ret i61 %c
+}
+
+; ~(~A | ~B) --> A & B
+
+define i71 @test5_apint(i71 %A, i71 %B) {
+; CHECK-LABEL: @test5_apint(
+; CHECK-NEXT:    [[C_DEMORGAN:%.*]] = and i71 %A, %B
+; CHECK-NEXT:    ret i71 [[C_DEMORGAN]]
+;
+  %nota = xor i71 %A, -1
+  %notb = xor i71 %B, -1
+  %c = or i71 %nota, %notb
+  %notc = xor i71 %c, -1
+  ret i71 %notc
+}
+
+; ~(~A & B) --> (A | ~B)
+
+define i8 @demorgan_nand(i8 %A, i8 %B) {
+; CHECK-LABEL: @demorgan_nand(
+; CHECK-NEXT:    [[B_NOT:%.*]] = xor i8 %B, -1
+; CHECK-NEXT:    [[NOTC:%.*]] = or i8 [[B_NOT]], %A
+; CHECK-NEXT:    ret i8 [[NOTC]]
+;
+  %notx = xor i8 %A, -1
+  %c = and i8 %notx, %B
+  %notc = xor i8 %c, -1
+  ret i8 %notc
+}
+
+; ~(~A & B) --> (A | ~B)
+
+define i7 @demorgan_nand_apint1(i7 %A, i7 %B) {
+; CHECK-LABEL: @demorgan_nand_apint1(
+; CHECK-NEXT:    [[B_NOT:%.*]] = xor i7 %B, -1
+; CHECK-NEXT:    [[NOTC:%.*]] = or i7 [[B_NOT]], %A
+; CHECK-NEXT:    ret i7 [[NOTC]]
+;
+  %nota = xor i7 %A, -1
+  %c = and i7 %nota, %B
+  %notc = xor i7 %c, -1
+  ret i7 %notc
+}
+
+; ~(~A & B) --> (A | ~B)
+
+define i117 @demorgan_nand_apint2(i117 %A, i117 %B) {
+; CHECK-LABEL: @demorgan_nand_apint2(
+; CHECK-NEXT:    [[B_NOT:%.*]] = xor i117 %B, -1
+; CHECK-NEXT:    [[NOTC:%.*]] = or i117 [[B_NOT]], %A
+; CHECK-NEXT:    ret i117 [[NOTC]]
+;
+  %nota = xor i117 %A, -1
+  %c = and i117 %nota, %B
+  %notc = xor i117 %c, -1
+  ret i117 %notc
+}
+
+; ~(~A | B) --> (A & ~B)
+
+define i8 @demorgan_nor(i8 %A, i8 %B) {
+; CHECK-LABEL: @demorgan_nor(
+; CHECK-NEXT:    [[B_NOT:%.*]] = xor i8 %B, -1
+; CHECK-NEXT:    [[NOTC:%.*]] = and i8 [[B_NOT]], %A
+; CHECK-NEXT:    ret i8 [[NOTC]]
+;
+  %notx = xor i8 %A, -1
+  %c = or i8 %notx, %B
+  %notc = xor i8 %c, -1
+  ret i8 %notc
+}
+
+; ~(~A | B) --> (A & ~B) - what if we use one of the intermediate results?
+
+define i8 @demorgan_nor_use2a(i8 %A, i8 %B) {
+; CHECK-LABEL: @demorgan_nor_use2a(
+; CHECK-NEXT:    [[NOTA:%.*]] = xor i8 %A, -1
+; CHECK-NEXT:    [[USE2A:%.*]] = mul i8 [[NOTA]], 23
+; CHECK-NEXT:    [[B_NOT:%.*]] = xor i8 %B, -1
+; CHECK-NEXT:    [[NOTC:%.*]] = and i8 [[B_NOT]], %A
+; CHECK-NEXT:    [[R:%.*]] = sdiv i8 [[NOTC]], [[USE2A]]
+; CHECK-NEXT:    ret i8 [[R]]
+;
+  %nota = xor i8 %A, -1
+  %use2a = mul i8 %nota, 23
+  %c = or i8 %nota, %B
+  %notc = xor i8 %c, -1
+  %r = sdiv i8 %notc, %use2a
+  ret i8 %r
+}
+
+; ~(~A | B) --> (A & ~B) - what if we use one of the intermediate results?
+
+define i8 @demorgan_nor_use2b(i8 %A, i8 %B) {
+; CHECK-LABEL: @demorgan_nor_use2b(
+; CHECK-NEXT:    [[USE2B:%.*]] = mul i8 %B, 23
+; CHECK-NEXT:    [[B_NOT:%.*]] = xor i8 %B, -1
+; CHECK-NEXT:    [[NOTC:%.*]] = and i8 [[B_NOT]], %A
+; CHECK-NEXT:    [[R:%.*]] = sdiv i8 [[NOTC]], [[USE2B]]
+; CHECK-NEXT:    ret i8 [[R]]
+;
+  %use2b = mul i8 %B, 23
+  %nota = xor i8 %A, -1
+  %c = or i8 %nota, %B
+  %notc = xor i8 %c, -1
+  %r = sdiv i8 %notc, %use2b
+  ret i8 %r
+}
+
+; ~(~A | B) --> (A & ~B) - what if we use one of the intermediate results?
+
+define i8 @demorgan_nor_use2c(i8 %A, i8 %B) {
+; CHECK-LABEL: @demorgan_nor_use2c(
+; CHECK-NEXT:    [[NOTA:%.*]] = xor i8 %A, -1
+; CHECK-NEXT:    [[C:%.*]] = or i8 [[NOTA]], %B
+; CHECK-NEXT:    [[USE2C:%.*]] = mul i8 [[C]], 23
+; CHECK-NEXT:    [[NOTC:%.*]] = xor i8 [[C]], -1
+; CHECK-NEXT:    [[R:%.*]] = sdiv i8 [[NOTC]], [[USE2C]]
+; CHECK-NEXT:    ret i8 [[R]]
+;
+  %nota = xor i8 %A, -1
+  %c = or i8 %nota, %B
+  %use2c = mul i8 %c, 23
+  %notc = xor i8 %c, -1
+  %r = sdiv i8 %notc, %use2c
+  ret i8 %r
+}
+
+; ~(~A | B) --> (A & ~B) - what if we use two of the intermediate results?
+
+define i8 @demorgan_nor_use2ab(i8 %A, i8 %B) {
+; CHECK-LABEL: @demorgan_nor_use2ab(
+; CHECK-NEXT:    [[USE2B:%.*]] = mul i8 %B, 23
+; CHECK-NEXT:    [[NOTA:%.*]] = xor i8 %A, -1
+; CHECK-NEXT:    [[USE2A:%.*]] = mul i8 [[NOTA]], 17
+; CHECK-NEXT:    [[B_NOT:%.*]] = xor i8 %B, -1
+; CHECK-NEXT:    [[NOTC:%.*]] = and i8 [[B_NOT]], %A
+; CHECK-NEXT:    [[R1:%.*]] = sdiv i8 [[NOTC]], [[USE2B]]
+; CHECK-NEXT:    [[R2:%.*]] = sdiv i8 [[R1]], [[USE2A]]
+; CHECK-NEXT:    ret i8 [[R2]]
+;
+  %use2b = mul i8 %B, 23
+  %nota = xor i8 %A, -1
+  %use2a = mul i8 %nota, 17
+  %c = or i8 %nota, %B
+  %notc = xor i8 %c, -1
+  %r1 = sdiv i8 %notc, %use2b
+  %r2 = sdiv i8 %r1, %use2a
+  ret i8 %r2
+}
+
+; ~(~A | B) --> (A & ~B) - what if we use two of the intermediate results?
+
+define i8 @demorgan_nor_use2ac(i8 %A, i8 %B) {
+; CHECK-LABEL: @demorgan_nor_use2ac(
+; CHECK-NEXT:    [[NOTA:%.*]] = xor i8 %A, -1
+; CHECK-NEXT:    [[USE2A:%.*]] = mul i8 [[NOTA]], 17
+; CHECK-NEXT:    [[C:%.*]] = or i8 [[NOTA]], %B
+; CHECK-NEXT:    [[USE2C:%.*]] = mul i8 [[C]], 23
+; CHECK-NEXT:    [[NOTC:%.*]] = xor i8 [[C]], -1
+; CHECK-NEXT:    [[R1:%.*]] = sdiv i8 [[NOTC]], [[USE2C]]
+; CHECK-NEXT:    [[R2:%.*]] = sdiv i8 [[R1]], [[USE2A]]
+; CHECK-NEXT:    ret i8 [[R2]]
+;
+  %nota = xor i8 %A, -1
+  %use2a = mul i8 %nota, 17
+  %c = or i8 %nota, %B
+  %use2c = mul i8 %c, 23
+  %notc = xor i8 %c, -1
+  %r1 = sdiv i8 %notc, %use2c
+  %r2 = sdiv i8 %r1, %use2a
+  ret i8 %r2
+}
+
+; ~(~A | B) --> (A & ~B) - what if we use two of the intermediate results?
+
+define i8 @demorgan_nor_use2bc(i8 %A, i8 %B) {
+; CHECK-LABEL: @demorgan_nor_use2bc(
+; CHECK-NEXT:    [[USE2B:%.*]] = mul i8 %B, 23
+; CHECK-NEXT:    [[NOTA:%.*]] = xor i8 %A, -1
+; CHECK-NEXT:    [[C:%.*]] = or i8 [[NOTA]], %B
+; CHECK-NEXT:    [[USE2C:%.*]] = mul i8 [[C]], 23
+; CHECK-NEXT:    [[NOTC:%.*]] = xor i8 [[C]], -1
+; CHECK-NEXT:    [[R1:%.*]] = sdiv i8 [[NOTC]], [[USE2C]]
+; CHECK-NEXT:    [[R2:%.*]] = sdiv i8 [[R1]], [[USE2B]]
+; CHECK-NEXT:    ret i8 [[R2]]
+;
+  %use2b = mul i8 %B, 23
+  %nota = xor i8 %A, -1
+  %c = or i8 %nota, %B
+  %use2c = mul i8 %c, 23
+  %notc = xor i8 %c, -1
+  %r1 = sdiv i8 %notc, %use2c
+  %r2 = sdiv i8 %r1, %use2b
+  ret i8 %r2
+}
+
+; Do not apply DeMorgan's Law to constants. We prefer 'not' ops.
+
+define i32 @demorganize_constant1(i32 %a) {
+; CHECK-LABEL: @demorganize_constant1(
+; CHECK-NEXT:    [[AND:%.*]] = and i32 %a, 15
+; CHECK-NEXT:    [[AND1:%.*]] = xor i32 [[AND]], -1
+; CHECK-NEXT:    ret i32 [[AND1]]
+;
+  %and = and i32 %a, 15
+  %and1 = xor i32 %and, -1
+  ret i32 %and1
+}
+
+; Do not apply DeMorgan's Law to constants. We prefer 'not' ops.
+
+define i32 @demorganize_constant2(i32 %a) {
+; CHECK-LABEL: @demorganize_constant2(
+; CHECK-NEXT:    [[AND:%.*]] = or i32 %a, 15
+; CHECK-NEXT:    [[AND1:%.*]] = xor i32 [[AND]], -1
+; CHECK-NEXT:    ret i32 [[AND1]]
+;
+  %and = or i32 %a, 15
+  %and1 = xor i32 %and, -1
+  ret i32 %and1
+}
+
+; PR22723: Recognize DeMorgan's Laws when obfuscated by zexts.
+
+define i32 @demorgan_or_zext(i1 %X, i1 %Y) {
+; CHECK-LABEL: @demorgan_or_zext(
+; CHECK-NEXT:    [[OR1_DEMORGAN:%.*]] = and i1 %X, %Y
+; CHECK-NEXT:    [[OR1:%.*]] = xor i1 [[OR1_DEMORGAN]], true
+; CHECK-NEXT:    [[OR:%.*]] = zext i1 [[OR1]] to i32
+; CHECK-NEXT:    ret i32 [[OR]]
+;
+  %zextX = zext i1 %X to i32
+  %zextY = zext i1 %Y to i32
+  %notX  = xor i32 %zextX, 1
+  %notY  = xor i32 %zextY, 1
+  %or    = or i32 %notX, %notY
+  ret i32 %or
+}
+
+define i32 @demorgan_and_zext(i1 %X, i1 %Y) {
+; CHECK-LABEL: @demorgan_and_zext(
+; CHECK-NEXT:    [[AND1_DEMORGAN:%.*]] = or i1 %X, %Y
+; CHECK-NEXT:    [[AND1:%.*]] = xor i1 [[AND1_DEMORGAN]], true
+; CHECK-NEXT:    [[AND:%.*]] = zext i1 [[AND1]] to i32
+; CHECK-NEXT:    ret i32 [[AND]]
+;
+  %zextX = zext i1 %X to i32
+  %zextY = zext i1 %Y to i32
+  %notX  = xor i32 %zextX, 1
+  %notY  = xor i32 %zextY, 1
+  %and   = and i32 %notX, %notY
+  ret i32 %and
+}
+
+define <2 x i32> @demorgan_or_zext_vec(<2 x i1> %X, <2 x i1> %Y) {
+; CHECK-LABEL: @demorgan_or_zext_vec(
+; CHECK-NEXT:    [[OR1_DEMORGAN:%.*]] = and <2 x i1> %X, %Y
+; CHECK-NEXT:    [[OR1:%.*]] = xor <2 x i1> [[OR1_DEMORGAN]], <i1 true, i1 true>
+; CHECK-NEXT:    [[OR:%.*]] = zext <2 x i1> [[OR1]] to <2 x i32>
+; CHECK-NEXT:    ret <2 x i32> [[OR]]
+;
+  %zextX = zext <2 x i1> %X to <2 x i32>
+  %zextY = zext <2 x i1> %Y to <2 x i32>
+  %notX  = xor <2 x i32> %zextX, <i32 1, i32 1>
+  %notY  = xor <2 x i32> %zextY, <i32 1, i32 1>
+  %or    = or <2 x i32> %notX, %notY
+  ret <2 x i32> %or
+}
+
+define <2 x i32> @demorgan_and_zext_vec(<2 x i1> %X, <2 x i1> %Y) {
+; CHECK-LABEL: @demorgan_and_zext_vec(
+; CHECK-NEXT:    [[AND1_DEMORGAN:%.*]] = or <2 x i1> %X, %Y
+; CHECK-NEXT:    [[AND1:%.*]] = xor <2 x i1> [[AND1_DEMORGAN]], <i1 true, i1 true>
+; CHECK-NEXT:    [[AND:%.*]] = zext <2 x i1> [[AND1]] to <2 x i32>
+; CHECK-NEXT:    ret <2 x i32> [[AND]]
+;
+  %zextX = zext <2 x i1> %X to <2 x i32>
+  %zextY = zext <2 x i1> %Y to <2 x i32>
+  %notX  = xor <2 x i32> %zextX, <i32 1, i32 1>
+  %notY  = xor <2 x i32> %zextY, <i32 1, i32 1>
+  %and   = and <2 x i32> %notX, %notY
+  ret <2 x i32> %and
+}
+
+define i32 @PR28476(i32 %x, i32 %y) {
+; CHECK-LABEL: @PR28476(
+; CHECK-NEXT:    [[CMP0:%.*]] = icmp eq i32 %x, 0
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp eq i32 %y, 0
+; CHECK-NEXT:    [[TMP1:%.*]] = or i1 [[CMP1]], [[CMP0]]
+; CHECK-NEXT:    [[COND:%.*]] = zext i1 [[TMP1]] to i32
+; CHECK-NEXT:    ret i32 [[COND]]
+;
+  %cmp0 = icmp ne i32 %x, 0
+  %cmp1 = icmp ne i32 %y, 0
+  %and = and i1 %cmp0, %cmp1
+  %zext = zext i1 %and to i32
+  %cond = xor i32 %zext, 1
+  ret i32 %cond
+}
+
+; ~(~(a | b) | (a & b)) --> (a | b) & ~(a & b) -> a ^ b
+
+define i32 @demorgan_plus_and_to_xor(i32 %a, i32 %b) {
+; CHECK-LABEL: @demorgan_plus_and_to_xor(
+; CHECK-NEXT:    [[NOT:%.*]] = xor i32 %b, %a
+; CHECK-NEXT:    ret i32 [[NOT]]
+;
+  %or = or i32 %b, %a
+  %notor = xor i32 %or, -1
+  %and = and i32 %b, %a
+  %or2 = or i32 %and, %notor
+  %not = xor i32 %or2, -1
+  ret i32 %not
+}
+
+define <4 x i32> @demorgan_plus_and_to_xor_vec(<4 x i32> %a, <4 x i32> %b) {
+; CHECK-LABEL: @demorgan_plus_and_to_xor_vec(
+; CHECK-NEXT:    [[NOT:%.*]] = xor <4 x i32> %a, %b
+; CHECK-NEXT:    ret <4 x i32> [[NOT]]
+;
+  %or = or <4 x i32> %a, %b
+  %notor = xor <4 x i32> %or, < i32 -1, i32 -1, i32 -1, i32 -1 >
+  %and = and <4 x i32> %a, %b
+  %or2 = or <4 x i32> %and, %notor
+  %not = xor <4 x i32> %or2, < i32 -1, i32 -1, i32 -1, i32 -1 >
+  ret <4 x i32> %not
+}
+

Added: llvm/trunk/test/Transforms/InstCombine/disable-simplify-libcalls.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/disable-simplify-libcalls.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/disable-simplify-libcalls.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/disable-simplify-libcalls.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,335 @@
+; Test that -disable-simplify-libcalls is wired up correctly.
+;
+; RUN: opt < %s -instcombine -disable-simplify-libcalls -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"
+
+ at .str  = constant [1 x i8] zeroinitializer, align 1
+ at .str1 = constant [13 x i8] c"hello, world\00", align 1
+ at .str2 = constant [4 x i8] c"foo\00", align 1
+ at .str3 = constant [4 x i8] c"bar\00", align 1
+ at .str4 = constant [6 x i8] c"123.4\00", align 1
+ at .str5 = constant [5 x i8] c"1234\00", align 1
+ at empty = constant [1 x i8] c"\00", align 1
+
+declare double @ceil(double)
+declare double @copysign(double, double)
+declare double @cos(double)
+declare double @fabs(double)
+declare double @floor(double)
+declare i8* @strcat(i8*, i8*)
+declare i8* @strncat(i8*, i8*, i32)
+declare i8* @strchr(i8*, i32)
+declare i8* @strrchr(i8*, i32)
+declare i32 @strcmp(i8*, i8*)
+declare i32 @strncmp(i8*, i8*, i64)
+declare i8* @strcpy(i8*, i8*)
+declare i8* @stpcpy(i8*, i8*)
+declare i8* @strncpy(i8*, i8*, i64)
+declare i64 @strlen(i8*)
+declare i8* @strpbrk(i8*, i8*)
+declare i64 @strspn(i8*, i8*)
+declare double @strtod(i8*, i8**)
+declare float @strtof(i8*, i8**)
+declare x86_fp80 @strtold(i8*, i8**)
+declare i64 @strtol(i8*, i8**, i32)
+declare i64 @strtoll(i8*, i8**, i32)
+declare i64 @strtoul(i8*, i8**, i32)
+declare i64 @strtoull(i8*, i8**, i32)
+declare i64 @strcspn(i8*, i8*)
+declare i32 @abs(i32)
+declare i32 @ffs(i32)
+declare i32 @ffsl(i64)
+declare i32 @ffsll(i64)
+declare i32 @fprintf(i8*, i8*)
+declare i32 @isascii(i32)
+declare i32 @isdigit(i32)
+declare i32 @toascii(i32)
+declare i64 @labs(i64)
+declare i64 @llabs(i64)
+declare i32 @printf(i8*)
+declare i32 @sprintf(i8*, i8*)
+
+define double @t1(double %x) {
+; CHECK-LABEL: @t1(
+  %ret = call double @ceil(double %x)
+  ret double %ret
+; CHECK: call double @ceil
+}
+
+define double @t2(double %x, double %y) {
+; CHECK-LABEL: @t2(
+  %ret = call double @copysign(double %x, double %y)
+  ret double %ret
+; CHECK: call double @copysign
+}
+
+define double @t3(double %x) {
+; CHECK-LABEL: @t3(
+  %call = call double @cos(double %x)
+  ret double %call
+; CHECK: call double @cos
+}
+
+define double @t4(double %x) {
+; CHECK-LABEL: @t4(
+  %ret = call double @fabs(double %x)
+  ret double %ret
+; CHECK: call double @fabs
+}
+
+define double @t5(double %x) {
+; CHECK-LABEL: @t5(
+  %ret = call double @floor(double %x)
+  ret double %ret
+; CHECK: call double @floor
+}
+
+define i8* @t6(i8* %x) {
+; CHECK-LABEL: @t6(
+  %empty = getelementptr [1 x i8], [1 x i8]* @empty, i32 0, i32 0
+  %ret = call i8* @strcat(i8* %x, i8* %empty)
+  ret i8* %ret
+; CHECK: call i8* @strcat
+}
+
+define i8* @t7(i8* %x) {
+; CHECK-LABEL: @t7(
+  %empty = getelementptr [1 x i8], [1 x i8]* @empty, i32 0, i32 0
+  %ret = call i8* @strncat(i8* %x, i8* %empty, i32 1)
+  ret i8* %ret
+; CHECK: call i8* @strncat
+}
+
+define i8* @t8() {
+; CHECK-LABEL: @t8(
+  %x = getelementptr inbounds [13 x i8], [13 x i8]* @.str1, i32 0, i32 0
+  %ret = call i8* @strchr(i8* %x, i32 119)
+  ret i8* %ret
+; CHECK: call i8* @strchr
+}
+
+define i8* @t9() {
+; CHECK-LABEL: @t9(
+  %x = getelementptr inbounds [13 x i8], [13 x i8]* @.str1, i32 0, i32 0
+  %ret = call i8* @strrchr(i8* %x, i32 119)
+  ret i8* %ret
+; CHECK: call i8* @strrchr
+}
+
+define i32 @t10() {
+; CHECK-LABEL: @t10(
+  %x = getelementptr inbounds [4 x i8], [4 x i8]* @.str2, i32 0, i32 0
+  %y = getelementptr inbounds [4 x i8], [4 x i8]* @.str3, i32 0, i32 0
+  %ret = call i32 @strcmp(i8* %x, i8* %y)
+  ret i32 %ret
+; CHECK: call i32 @strcmp
+}
+
+define i32 @t11() {
+; CHECK-LABEL: @t11(
+  %x = getelementptr inbounds [4 x i8], [4 x i8]* @.str2, i32 0, i32 0
+  %y = getelementptr inbounds [4 x i8], [4 x i8]* @.str3, i32 0, i32 0
+  %ret = call i32 @strncmp(i8* %x, i8* %y, i64 3)
+  ret i32 %ret
+; CHECK: call i32 @strncmp
+}
+
+define i8* @t12(i8* %x) {
+; CHECK-LABEL: @t12(
+  %y = getelementptr inbounds [4 x i8], [4 x i8]* @.str2, i32 0, i32 0
+  %ret = call i8* @strcpy(i8* %x, i8* %y)
+  ret i8* %ret
+; CHECK: call i8* @strcpy
+}
+
+define i8* @t13(i8* %x) {
+; CHECK-LABEL: @t13(
+  %y = getelementptr inbounds [4 x i8], [4 x i8]* @.str2, i32 0, i32 0
+  %ret = call i8* @stpcpy(i8* %x, i8* %y)
+  ret i8* %ret
+; CHECK: call i8* @stpcpy
+}
+
+define i8* @t14(i8* %x) {
+; CHECK-LABEL: @t14(
+  %y = getelementptr inbounds [4 x i8], [4 x i8]* @.str2, i32 0, i32 0
+  %ret = call i8* @strncpy(i8* %x, i8* %y, i64 3)
+  ret i8* %ret
+; CHECK: call i8* @strncpy
+}
+
+define i64 @t15() {
+; CHECK-LABEL: @t15(
+  %x = getelementptr inbounds [4 x i8], [4 x i8]* @.str2, i32 0, i32 0
+  %ret = call i64 @strlen(i8* %x)
+  ret i64 %ret
+; CHECK: call i64 @strlen
+}
+
+define i8* @t16(i8* %x) {
+; CHECK-LABEL: @t16(
+  %y = getelementptr inbounds [1 x i8], [1 x i8]* @.str, i32 0, i32 0
+  %ret = call i8* @strpbrk(i8* %x, i8* %y)
+  ret i8* %ret
+; CHECK: call i8* @strpbrk
+}
+
+define i64 @t17(i8* %x) {
+; CHECK-LABEL: @t17(
+  %y = getelementptr inbounds [1 x i8], [1 x i8]* @.str, i32 0, i32 0
+  %ret = call i64 @strspn(i8* %x, i8* %y)
+  ret i64 %ret
+; CHECK: call i64 @strspn
+}
+
+define double @t18(i8** %y) {
+; CHECK-LABEL: @t18(
+  %x = getelementptr inbounds [6 x i8], [6 x i8]* @.str4, i64 0, i64 0
+  %ret = call double @strtod(i8* %x, i8** %y)
+  ret double %ret
+; CHECK: call double @strtod
+}
+
+define float @t19(i8** %y) {
+; CHECK-LABEL: @t19(
+  %x = getelementptr inbounds [6 x i8], [6 x i8]* @.str4, i64 0, i64 0
+  %ret = call float @strtof(i8* %x, i8** %y)
+  ret float %ret
+; CHECK: call float @strtof
+}
+
+define x86_fp80 @t20(i8** %y) {
+; CHECK-LABEL: @t20(
+  %x = getelementptr inbounds [6 x i8], [6 x i8]* @.str4, i64 0, i64 0
+  %ret = call x86_fp80 @strtold(i8* %x, i8** %y)
+  ret x86_fp80 %ret
+; CHECK: call x86_fp80 @strtold
+}
+
+define i64 @t21(i8** %y) {
+; CHECK-LABEL: @t21(
+  %x = getelementptr inbounds [5 x i8], [5 x i8]* @.str5, i64 0, i64 0
+  %ret = call i64 @strtol(i8* %x, i8** %y, i32 10)
+  ret i64 %ret
+; CHECK: call i64 @strtol
+}
+
+define i64 @t22(i8** %y) {
+; CHECK-LABEL: @t22(
+  %x = getelementptr inbounds [5 x i8], [5 x i8]* @.str5, i64 0, i64 0
+  %ret = call i64 @strtoll(i8* %x, i8** %y, i32 10)
+  ret i64 %ret
+; CHECK: call i64 @strtoll
+}
+
+define i64 @t23(i8** %y) {
+; CHECK-LABEL: @t23(
+  %x = getelementptr inbounds [5 x i8], [5 x i8]* @.str5, i64 0, i64 0
+  %ret = call i64 @strtoul(i8* %x, i8** %y, i32 10)
+  ret i64 %ret
+; CHECK: call i64 @strtoul
+}
+
+define i64 @t24(i8** %y) {
+; CHECK-LABEL: @t24(
+  %x = getelementptr inbounds [5 x i8], [5 x i8]* @.str5, i64 0, i64 0
+  %ret = call i64 @strtoull(i8* %x, i8** %y, i32 10)
+  ret i64 %ret
+; CHECK: call i64 @strtoull
+}
+
+define i64 @t25(i8* %y) {
+; CHECK-LABEL: @t25(
+  %x = getelementptr [1 x i8], [1 x i8]* @empty, i32 0, i32 0
+  %ret = call i64 @strcspn(i8* %x, i8* %y)
+  ret i64 %ret
+; CHECK: call i64 @strcspn
+}
+
+define i32 @t26(i32 %y) {
+; CHECK-LABEL: @t26(
+  %ret = call i32 @abs(i32 %y)
+  ret i32 %ret
+; CHECK: call i32 @abs
+}
+
+define i32 @t27(i32 %y) {
+; CHECK-LABEL: @t27(
+  %ret = call i32 @ffs(i32 %y)
+  ret i32 %ret
+; CHECK: call i32 @ffs
+}
+
+define i32 @t28(i64 %y) {
+; CHECK-LABEL: @t28(
+  %ret = call i32 @ffsl(i64 %y)
+  ret i32 %ret
+; CHECK: call i32 @ffsl
+}
+
+define i32 @t29(i64 %y) {
+; CHECK-LABEL: @t29(
+  %ret = call i32 @ffsll(i64 %y)
+  ret i32 %ret
+; CHECK: call i32 @ffsll
+}
+
+define void @t30() {
+; CHECK-LABEL: @t30(
+  %x = getelementptr inbounds [13 x i8], [13 x i8]* @.str1, i32 0, i32 0
+  call i32 @fprintf(i8* null, i8* %x)
+  ret void
+; CHECK: call i32 @fprintf
+}
+
+define i32 @t31(i32 %y) {
+; CHECK-LABEL: @t31(
+  %ret = call i32 @isascii(i32 %y)
+  ret i32 %ret
+; CHECK: call i32 @isascii
+}
+
+define i32 @t32(i32 %y) {
+; CHECK-LABEL: @t32(
+  %ret = call i32 @isdigit(i32 %y)
+  ret i32 %ret
+; CHECK: call i32 @isdigit
+}
+
+define i32 @t33(i32 %y) {
+; CHECK-LABEL: @t33(
+  %ret = call i32 @toascii(i32 %y)
+  ret i32 %ret
+; CHECK: call i32 @toascii
+}
+
+define i64 @t34(i64 %y) {
+; CHECK-LABEL: @t34(
+  %ret = call i64 @labs(i64 %y)
+  ret i64 %ret
+; CHECK: call i64 @labs
+}
+
+define i64 @t35(i64 %y) {
+; CHECK-LABEL: @t35(
+  %ret = call i64 @llabs(i64 %y)
+  ret i64 %ret
+; CHECK: call i64 @llabs
+}
+
+define void @t36() {
+; CHECK-LABEL: @t36(
+  %x = getelementptr inbounds [1 x i8], [1 x i8]* @empty, i32 0, i32 0
+  call i32 @printf(i8* %x)
+  ret void
+; CHECK: call i32 @printf
+}
+
+define void @t37(i8* %x) {
+; CHECK-LABEL: @t37(
+  %y = getelementptr inbounds [13 x i8], [13 x i8]* @.str1, i32 0, i32 0
+  call i32 @sprintf(i8* %x, i8* %y)
+  ret void
+; CHECK: call i32 @sprintf
+}

Added: llvm/trunk/test/Transforms/InstCombine/distribute.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/distribute.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/distribute.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/distribute.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,68 @@
+; RUN: opt < %s -instcombine -S | FileCheck %s
+
+define i32 @factorize(i32 %x, i32 %y) {
+; CHECK-LABEL: @factorize(
+; (X | 1) & (X | 2) -> X | (1 & 2) -> X
+  %l = or i32 %x, 1
+  %r = or i32 %x, 2
+  %z = and i32 %l, %r
+  ret i32 %z
+; CHECK: ret i32 %x
+}
+
+define i32 @factorize2(i32 %x) {
+; CHECK-LABEL: @factorize2(
+; 3*X - 2*X -> X
+  %l = mul i32 3, %x
+  %r = mul i32 2, %x
+  %z = sub i32 %l, %r
+  ret i32 %z
+; CHECK: ret i32 %x
+}
+
+define i32 @factorize3(i32 %x, i32 %a, i32 %b) {
+; CHECK-LABEL: @factorize3(
+; (X | (A|B)) & (X | B) -> X | ((A|B) & B) -> X | B
+  %aORb = or i32 %a, %b
+  %l = or i32 %x, %aORb
+  %r = or i32 %x, %b
+  %z = and i32 %l, %r
+  ret i32 %z
+; CHECK: %z = or i32 %b, %x
+; CHECK: ret i32 %z
+}
+
+define i32 @factorize4(i32 %x, i32 %y) {
+; CHECK-LABEL: @factorize4(
+; ((Y << 1) * X) - (X * Y) -> (X * (Y * 2 - Y)) -> (X * Y)
+  %sh = shl i32 %y, 1
+  %ml = mul i32 %sh, %x
+  %mr = mul i32 %x, %y
+  %s = sub i32 %ml, %mr
+  ret i32 %s
+; CHECK: %s = mul i32 %y, %x
+; CHECK: ret i32 %s
+}
+
+define i32 @factorize5(i32 %x, i32 %y) {
+; CHECK-LABEL: @factorize5(
+; ((Y * 2) * X) - (X * Y) -> (X * Y)
+  %sh = mul i32 %y, 2
+  %ml = mul i32 %sh, %x
+  %mr = mul i32 %x, %y
+  %s = sub i32 %ml, %mr
+  ret i32 %s
+; CHECK: %s = mul i32 %y, %x
+; CHECK: ret i32 %s
+}
+
+define i32 @expand(i32 %x) {
+; CHECK-LABEL: @expand(
+; ((X & 1) | 2) & 1 -> ((X & 1) & 1) | (2 & 1) -> (X & 1) | 0 -> X & 1
+  %a = and i32 %x, 1
+  %b = or i32 %a, 2
+  %c = and i32 %b, 1
+  ret i32 %c
+; CHECK: %a = and i32 %x, 1
+; CHECK: ret i32 %a
+}

Added: llvm/trunk/test/Transforms/InstCombine/div-shift-crash.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/div-shift-crash.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/div-shift-crash.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/div-shift-crash.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,101 @@
+; RUN: opt -instcombine < %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-f128:128:128-v128:128:128-n32:64"
+target triple = "powerpc64-unknown-linux-gnu"
+
+%struct.S0.0.1.2.3.4.13.22.31.44.48.53.54.55.56.58.59.60.66.68.70.74.77.106.107.108.109.110.113.117.118.128.129 = type <{ i64 }>
+
+; Function Attrs: nounwind
+define void @main() #0 {
+entry:
+  %l_819.i.i = alloca %struct.S0.0.1.2.3.4.13.22.31.44.48.53.54.55.56.58.59.60.66.68.70.74.77.106.107.108.109.110.113.117.118.128.129, align 8
+  br i1 undef, label %land.lhs.true, label %for.cond.i
+
+land.lhs.true:                                    ; preds = %entry
+  br label %for.cond.i
+
+for.cond.i:                                       ; preds = %land.lhs.true, %entry
+  %0 = getelementptr inbounds %struct.S0.0.1.2.3.4.13.22.31.44.48.53.54.55.56.58.59.60.66.68.70.74.77.106.107.108.109.110.113.117.118.128.129, %struct.S0.0.1.2.3.4.13.22.31.44.48.53.54.55.56.58.59.60.66.68.70.74.77.106.107.108.109.110.113.117.118.128.129* %l_819.i.i, i64 0, i32 0
+  br label %for.cond.i6.i.i
+
+for.cond.i6.i.i:                                  ; preds = %for.body.i8.i.i, %for.cond.i
+  br i1 undef, label %for.body.i8.i.i, label %lbl_707.i.i.i
+
+for.body.i8.i.i:                                  ; preds = %for.cond.i6.i.i
+  br label %for.cond.i6.i.i
+
+lbl_707.i.i.i:                                    ; preds = %for.cond.i6.i.i
+  br i1 undef, label %lor.rhs.i.i.i, label %lor.end.i.i.i
+
+lor.rhs.i.i.i:                                    ; preds = %lbl_707.i.i.i
+  br label %lor.end.i.i.i
+
+lor.end.i.i.i:                                    ; preds = %lor.rhs.i.i.i, %lbl_707.i.i.i
+  br label %for.cond1.i.i.i.i
+
+for.cond1.i.i.i.i:                                ; preds = %for.body4.i.i.i.i, %lor.end.i.i.i
+  br i1 undef, label %for.body4.i.i.i.i, label %func_39.exit.i.i
+
+for.body4.i.i.i.i:                                ; preds = %for.cond1.i.i.i.i
+  br label %for.cond1.i.i.i.i
+
+func_39.exit.i.i:                                 ; preds = %for.cond1.i.i.i.i
+  %l_8191.sroa.0.0.copyload.i.i = load i64, i64* %0, align 1
+  br label %for.cond1.i.i.i
+
+for.cond1.i.i.i:                                  ; preds = %safe_div_func_uint32_t_u_u.exit.i.i.i, %func_39.exit.i.i
+  br i1 undef, label %for.cond7.i.i.i, label %func_11.exit.i
+
+for.cond7.i.i.i:                                  ; preds = %for.end30.i.i.i, %for.cond1.i.i.i
+  %storemerge.i.i.i = phi i32 [ %sub.i.i.i, %for.end30.i.i.i ], [ 4, %for.cond1.i.i.i ]
+  br i1 undef, label %for.cond22.i.i.i, label %for.end32.i.i.i
+
+for.cond22.i.i.i:                                 ; preds = %for.body25.i.i.i, %for.cond7.i.i.i
+  br i1 undef, label %for.body25.i.i.i, label %for.end30.i.i.i
+
+for.body25.i.i.i:                                 ; preds = %for.cond22.i.i.i
+  br label %for.cond22.i.i.i
+
+for.end30.i.i.i:                                  ; preds = %for.cond22.i.i.i
+  %sub.i.i.i = add nsw i32 0, -1
+  br label %for.cond7.i.i.i
+
+for.end32.i.i.i:                                  ; preds = %for.cond7.i.i.i
+  %conv33.i.i.i = trunc i64 %l_8191.sroa.0.0.copyload.i.i to i32
+  %xor.i.i.i.i = xor i32 %storemerge.i.i.i, -701565022
+  %sub.i.i.i.i = sub nsw i32 0, %storemerge.i.i.i
+  %xor3.i.i.i.i = xor i32 %sub.i.i.i.i, %storemerge.i.i.i
+  %and4.i.i.i.i = and i32 %xor.i.i.i.i, %xor3.i.i.i.i
+  %cmp.i.i.i.i = icmp slt i32 %and4.i.i.i.i, 0
+  %sub5.i.i.i.i = sub nsw i32 -701565022, %storemerge.i.i.i
+  %.sub5.i.i.i.i = select i1 %cmp.i.i.i.i, i32 -701565022, i32 %sub5.i.i.i.i
+  br i1 undef, label %safe_div_func_uint32_t_u_u.exit.i.i.i, label %cond.false.i.i.i.i
+
+cond.false.i.i.i.i:                               ; preds = %for.end32.i.i.i
+  %div.i.i.i.i = udiv i32 %conv33.i.i.i, %.sub5.i.i.i.i
+  br label %safe_div_func_uint32_t_u_u.exit.i.i.i
+
+safe_div_func_uint32_t_u_u.exit.i.i.i:            ; preds = %cond.false.i.i.i.i, %for.end32.i.i.i
+  %cond.i.i.i.i = phi i32 [ %div.i.i.i.i, %cond.false.i.i.i.i ], [ %conv33.i.i.i, %for.end32.i.i.i ]
+  %cmp35.i.i.i = icmp ne i32 %cond.i.i.i.i, -7
+  br label %for.cond1.i.i.i
+
+func_11.exit.i:                                   ; preds = %for.cond1.i.i.i
+  br i1 undef, label %for.body, label %for.end
+
+for.body:                                         ; preds = %func_11.exit.i
+  unreachable
+
+for.end:                                          ; preds = %func_11.exit.i
+  br label %for.cond15
+
+for.cond15:                                       ; preds = %for.cond19, %for.end
+  br i1 undef, label %for.cond19, label %for.end45
+
+for.cond19:                                       ; preds = %for.cond15
+  br label %for.cond15
+
+for.end45:                                        ; preds = %for.cond15
+  unreachable
+}
+
+attributes #0 = { nounwind "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf"="true" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "unsafe-fp-math"="false" "use-soft-float"="false" }

Added: llvm/trunk/test/Transforms/InstCombine/div-shift.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/div-shift.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/div-shift.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/div-shift.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,204 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt < %s -instcombine -S | FileCheck %s
+
+define i32 @t1(i16 zeroext %x, i32 %y) {
+; CHECK-LABEL: @t1(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[CONV:%.*]] = zext i16 [[X:%.*]] to i32
+; CHECK-NEXT:    [[TMP0:%.*]] = add i32 [[Y:%.*]], 1
+; CHECK-NEXT:    [[D:%.*]] = lshr i32 [[CONV]], [[TMP0]]
+; CHECK-NEXT:    ret i32 [[D]]
+;
+entry:
+  %conv = zext i16 %x to i32
+  %s = shl i32 2, %y
+  %d = sdiv i32 %conv, %s
+  ret i32 %d
+}
+
+define <2 x i32> @t1vec(<2 x i16> %x, <2 x i32> %y) {
+; CHECK-LABEL: @t1vec(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[CONV:%.*]] = zext <2 x i16> [[X:%.*]] to <2 x i32>
+; CHECK-NEXT:    [[TMP0:%.*]] = add <2 x i32> [[Y:%.*]], <i32 1, i32 1>
+; CHECK-NEXT:    [[D:%.*]] = lshr <2 x i32> [[CONV]], [[TMP0]]
+; CHECK-NEXT:    ret <2 x i32> [[D]]
+;
+entry:
+  %conv = zext <2 x i16> %x to <2 x i32>
+  %s = shl <2 x i32> <i32 2, i32 2>, %y
+  %d = sdiv <2 x i32> %conv, %s
+  ret <2 x i32> %d
+}
+
+; rdar://11721329
+define i64 @t2(i64 %x, i32 %y) {
+; CHECK-LABEL: @t2(
+; CHECK-NEXT:    [[TMP1:%.*]] = zext i32 [[Y:%.*]] to i64
+; CHECK-NEXT:    [[TMP2:%.*]] = lshr i64 [[X:%.*]], [[TMP1]]
+; CHECK-NEXT:    ret i64 [[TMP2]]
+;
+  %1 = shl i32 1, %y
+  %2 = zext i32 %1 to i64
+  %3 = udiv i64 %x, %2
+  ret i64 %3
+}
+
+; PR13250
+define i64 @t3(i64 %x, i32 %y) {
+; CHECK-LABEL: @t3(
+; CHECK-NEXT:    [[TMP1:%.*]] = add i32 [[Y:%.*]], 2
+; CHECK-NEXT:    [[TMP2:%.*]] = zext i32 [[TMP1]] to i64
+; CHECK-NEXT:    [[TMP3:%.*]] = lshr i64 [[X:%.*]], [[TMP2]]
+; CHECK-NEXT:    ret i64 [[TMP3]]
+;
+  %1 = shl i32 4, %y
+  %2 = zext i32 %1 to i64
+  %3 = udiv i64 %x, %2
+  ret i64 %3
+}
+
+define i32 @t4(i32 %x, i32 %y) {
+; CHECK-LABEL: @t4(
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp ugt i32 [[Y:%.*]], 5
+; CHECK-NEXT:    [[DOTV:%.*]] = select i1 [[TMP1]], i32 [[Y]], i32 5
+; CHECK-NEXT:    [[TMP2:%.*]] = lshr i32 [[X:%.*]], [[DOTV]]
+; CHECK-NEXT:    ret i32 [[TMP2]]
+;
+  %1 = shl i32 1, %y
+  %2 = icmp ult i32 %1, 32
+  %3 = select i1 %2, i32 32, i32 %1
+  %4 = udiv i32 %x, %3
+  ret i32 %4
+}
+
+define i32 @t5(i1 %x, i1 %y, i32 %V) {
+; CHECK-LABEL: @t5(
+; CHECK-NEXT:    [[DOTV:%.*]] = select i1 [[X:%.*]], i32 5, i32 6
+; CHECK-NEXT:    [[TMP1:%.*]] = lshr i32 [[V:%.*]], [[DOTV]]
+; CHECK-NEXT:    [[TMP2:%.*]] = select i1 [[Y:%.*]], i32 [[TMP1]], i32 0
+; CHECK-NEXT:    ret i32 [[TMP2]]
+;
+  %1 = shl i32 1, %V
+  %2 = select i1 %x, i32 32, i32 64
+  %3 = select i1 %y, i32 %2, i32 %1
+  %4 = udiv i32 %V, %3
+  ret i32 %4
+}
+
+define i32 @t6(i32 %x, i32 %z) {
+; CHECK-LABEL: @t6(
+; CHECK-NEXT:    [[X_IS_ZERO:%.*]] = icmp eq i32 [[X:%.*]], 0
+; CHECK-NEXT:    [[DIVISOR:%.*]] = select i1 [[X_IS_ZERO]], i32 1, i32 [[X]]
+; CHECK-NEXT:    [[Y:%.*]] = udiv i32 [[Z:%.*]], [[DIVISOR]]
+; CHECK-NEXT:    ret i32 [[Y]]
+;
+  %x_is_zero = icmp eq i32 %x, 0
+  %divisor = select i1 %x_is_zero, i32 1, i32 %x
+  %y = udiv i32 %z, %divisor
+  ret i32 %y
+}
+
+; (X << C1) / X -> 1 << C1 optimizations
+
+define i32 @t7(i32 %x) {
+; CHECK-LABEL: @t7(
+; CHECK-NEXT:    ret i32 4
+;
+  %shl = shl nsw i32 %x, 2
+  %r = sdiv i32 %shl, %x
+  ret i32 %r
+}
+
+; make sure the previous opt doesn't take place for wrapped shifts
+
+define i32 @t8(i32 %x) {
+; CHECK-LABEL: @t8(
+; CHECK-NEXT:    [[SHL:%.*]] = shl i32 [[X:%.*]], 2
+; CHECK-NEXT:    [[R:%.*]] = sdiv i32 [[SHL]], [[X]]
+; CHECK-NEXT:    ret i32 [[R]]
+;
+  %shl = shl i32 %x, 2
+  %r = sdiv i32 %shl, %x
+  ret i32 %r
+}
+
+define <2 x i32> @t9(<2 x i32> %x) {
+; CHECK-LABEL: @t9(
+; CHECK-NEXT:    ret <2 x i32> <i32 4, i32 8>
+;
+  %shl = shl nsw <2 x i32> %x, <i32 2, i32 3>
+  %r = sdiv <2 x i32> %shl, %x
+  ret <2 x i32> %r
+}
+
+define i32 @t10(i32 %x, i32 %y) {
+; CHECK-LABEL: @t10(
+; CHECK-NEXT:    [[R:%.*]] = shl nsw i32 1, [[Y:%.*]]
+; CHECK-NEXT:    ret i32 [[R]]
+;
+  %shl = shl nsw i32 %x, %y
+  %r = sdiv i32 %shl, %x
+  ret i32 %r
+}
+
+define <2 x i32> @t11(<2 x i32> %x, <2 x i32> %y) {
+; CHECK-LABEL: @t11(
+; CHECK-NEXT:    [[R:%.*]] = shl nsw <2 x i32> <i32 1, i32 1>, [[Y:%.*]]
+; CHECK-NEXT:    ret <2 x i32> [[R]]
+;
+  %shl = shl nsw <2 x i32> %x, %y
+  %r = sdiv <2 x i32> %shl, %x
+  ret <2 x i32> %r
+}
+
+define i32 @t12(i32 %x) {
+; CHECK-LABEL: @t12(
+; CHECK-NEXT:    ret i32 4
+;
+  %shl = shl nuw i32 %x, 2
+  %r = udiv i32 %shl, %x
+  ret i32 %r
+}
+
+; make sure the previous opt doesn't take place for wrapped shifts
+
+define i32 @t13(i32 %x) {
+; CHECK-LABEL: @t13(
+; CHECK-NEXT:    [[SHL:%.*]] = shl i32 [[X:%.*]], 2
+; CHECK-NEXT:    [[R:%.*]] = udiv i32 [[SHL]], [[X]]
+; CHECK-NEXT:    ret i32 [[R]]
+;
+  %shl = shl i32 %x, 2
+  %r = udiv i32 %shl, %x
+  ret i32 %r
+}
+
+define <2 x i32> @t14(<2 x i32> %x) {
+; CHECK-LABEL: @t14(
+; CHECK-NEXT:    ret <2 x i32> <i32 4, i32 8>
+;
+  %shl = shl nuw <2 x i32> %x, <i32 2, i32 3>
+  %r = udiv <2 x i32> %shl, %x
+  ret <2 x i32> %r
+}
+
+define i32 @t15(i32 %x, i32 %y) {
+; CHECK-LABEL: @t15(
+; CHECK-NEXT:    [[R:%.*]] = shl nuw i32 1, [[Y:%.*]]
+; CHECK-NEXT:    ret i32 [[R]]
+;
+  %shl = shl nuw i32 %x, %y
+  %r = udiv i32 %shl, %x
+  ret i32 %r
+}
+
+define <2 x i32> @t16(<2 x i32> %x, <2 x i32> %y) {
+; CHECK-LABEL: @t16(
+; CHECK-NEXT:    [[R:%.*]] = shl nuw <2 x i32> <i32 1, i32 1>, [[Y:%.*]]
+; CHECK-NEXT:    ret <2 x i32> [[R]]
+;
+  %shl = shl nuw <2 x i32> %x, %y
+  %r = udiv <2 x i32> %shl, %x
+  ret <2 x i32> %r
+}

Added: llvm/trunk/test/Transforms/InstCombine/div.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/div.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/div.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/div.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,1049 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; This test makes sure that div instructions are properly eliminated.
+
+; RUN: opt < %s -instcombine -S | FileCheck %s
+
+define i32 @test1(i32 %A) {
+; CHECK-LABEL: @test1(
+; CHECK-NEXT:    ret i32 [[A:%.*]]
+;
+  %B = sdiv i32 %A, 1
+  ret i32 %B
+}
+
+define i32 @test2(i32 %A) {
+; CHECK-LABEL: @test2(
+; CHECK-NEXT:    [[B:%.*]] = lshr i32 [[A:%.*]], 3
+; CHECK-NEXT:    ret i32 [[B]]
+;
+  %B = udiv i32 %A, 8
+  ret i32 %B
+}
+
+define i32 @sdiv_by_minus1(i32 %A) {
+; CHECK-LABEL: @sdiv_by_minus1(
+; CHECK-NEXT:    [[B:%.*]] = sub i32 0, [[A:%.*]]
+; CHECK-NEXT:    ret i32 [[B]]
+;
+  %B = sdiv i32 %A, -1
+  ret i32 %B
+}
+
+define <2 x i64> @sdiv_by_minus1_vec(<2 x i64> %x) {
+; CHECK-LABEL: @sdiv_by_minus1_vec(
+; CHECK-NEXT:    [[DIV:%.*]] = sub <2 x i64> zeroinitializer, [[X:%.*]]
+; CHECK-NEXT:    ret <2 x i64> [[DIV]]
+;
+  %div = sdiv <2 x i64> %x, <i64 -1, i64 -1>
+  ret <2 x i64> %div
+}
+
+define <2 x i64> @sdiv_by_minus1_vec_undef_elt(<2 x i64> %x) {
+; CHECK-LABEL: @sdiv_by_minus1_vec_undef_elt(
+; CHECK-NEXT:    ret <2 x i64> undef
+;
+  %div = sdiv <2 x i64> %x, <i64 -1, i64 undef>
+  ret <2 x i64> %div
+}
+
+define i32 @sdiv_by_sext_minus1(i1 %x, i32 %y) {
+; CHECK-LABEL: @sdiv_by_sext_minus1(
+; CHECK-NEXT:    [[DIV:%.*]] = sub i32 0, [[Y:%.*]]
+; CHECK-NEXT:    ret i32 [[DIV]]
+;
+  %sext = sext i1 %x to i32
+  %div = sdiv i32 %y, %sext
+  ret i32 %div
+}
+
+define <2 x i32> @sdiv_by_sext_minus1_vec(<2 x i1> %x, <2 x i32> %y) {
+; CHECK-LABEL: @sdiv_by_sext_minus1_vec(
+; CHECK-NEXT:    [[DIV:%.*]] = sub <2 x i32> zeroinitializer, [[Y:%.*]]
+; CHECK-NEXT:    ret <2 x i32> [[DIV]]
+;
+  %sext = sext <2 x i1> %x to <2 x i32>
+  %div = sdiv <2 x i32> %y, %sext
+  ret <2 x i32> %div
+}
+
+define i8 @udiv_by_negative(i8 %x) {
+; CHECK-LABEL: @udiv_by_negative(
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp ugt i8 [[X:%.*]], -7
+; CHECK-NEXT:    [[A:%.*]] = zext i1 [[TMP1]] to i8
+; CHECK-NEXT:    ret i8 [[A]]
+;
+  %A = udiv i8 %x, 250
+  ret i8 %A
+}
+
+define i32 @udiv_by_minus1(i32 %A) {
+; CHECK-LABEL: @udiv_by_minus1(
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp eq i32 [[A:%.*]], -1
+; CHECK-NEXT:    [[B:%.*]] = zext i1 [[TMP1]] to i32
+; CHECK-NEXT:    ret i32 [[B]]
+;
+  %B = udiv i32 %A, -1
+  ret i32 %B
+}
+
+define <2 x i64> @udiv_by_minus1_vec(<2 x i64> %x) {
+; CHECK-LABEL: @udiv_by_minus1_vec(
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp eq <2 x i64> [[X:%.*]], <i64 -1, i64 -1>
+; CHECK-NEXT:    [[DIV:%.*]] = zext <2 x i1> [[TMP1]] to <2 x i64>
+; CHECK-NEXT:    ret <2 x i64> [[DIV]]
+;
+  %div = udiv <2 x i64> %x, <i64 -1, i64 -1>
+  ret <2 x i64> %div
+}
+
+define i32 @udiv_by_sext_all_ones(i1 %x, i32 %y) {
+; CHECK-LABEL: @udiv_by_sext_all_ones(
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp eq i32 [[Y:%.*]], -1
+; CHECK-NEXT:    [[DIV:%.*]] = zext i1 [[TMP1]] to i32
+; CHECK-NEXT:    ret i32 [[DIV]]
+;
+  %sext = sext i1 %x to i32
+  %div = udiv i32 %y, %sext
+  ret i32 %div
+}
+
+define <2 x i32> @udiv_by_sext_all_ones_vec(<2 x i1> %x, <2 x i32> %y) {
+; CHECK-LABEL: @udiv_by_sext_all_ones_vec(
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp eq <2 x i32> [[Y:%.*]], <i32 -1, i32 -1>
+; CHECK-NEXT:    [[DIV:%.*]] = zext <2 x i1> [[TMP1]] to <2 x i32>
+; CHECK-NEXT:    ret <2 x i32> [[DIV]]
+;
+  %sext = sext <2 x i1> %x to <2 x i32>
+  %div = udiv <2 x i32> %y, %sext
+  ret <2 x i32> %div
+}
+
+define i32 @test5(i32 %A) {
+; CHECK-LABEL: @test5(
+; CHECK-NEXT:    ret i32 0
+;
+  %B = udiv i32 %A, -16
+  %C = udiv i32 %B, -4
+  ret i32 %C
+}
+
+define i1 @test6(i32 %A) {
+; CHECK-LABEL: @test6(
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp ult i32 [[A:%.*]], 123
+; CHECK-NEXT:    ret i1 [[TMP1]]
+;
+  %B = udiv i32 %A, 123
+  ; A < 123
+  %C = icmp eq i32 %B, 0
+  ret i1 %C
+}
+
+define i1 @test7(i32 %A) {
+; CHECK-LABEL: @test7(
+; CHECK-NEXT:    [[A_OFF:%.*]] = add i32 [[A:%.*]], -20
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp ult i32 [[A_OFF]], 10
+; CHECK-NEXT:    ret i1 [[TMP1]]
+;
+  %B = udiv i32 %A, 10
+  ; A >= 20 && A < 30
+  %C = icmp eq i32 %B, 2
+  ret i1 %C
+}
+
+define <2 x i1> @test7vec(<2 x i32> %A) {
+; CHECK-LABEL: @test7vec(
+; CHECK-NEXT:    [[A_OFF:%.*]] = add <2 x i32> [[A:%.*]], <i32 -20, i32 -20>
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp ult <2 x i32> [[A_OFF]], <i32 10, i32 10>
+; CHECK-NEXT:    ret <2 x i1> [[TMP1]]
+;
+  %B = udiv <2 x i32> %A, <i32 10, i32 10>
+  %C = icmp eq <2 x i32> %B, <i32 2, i32 2>
+  ret <2 x i1> %C
+}
+
+define i1 @test8(i8 %A) {
+; CHECK-LABEL: @test8(
+; CHECK-NEXT:    [[C:%.*]] = icmp ugt i8 [[A:%.*]], -11
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %B = udiv i8 %A, 123
+  ; A >= 246
+  %C = icmp eq i8 %B, 2
+  ret i1 %C
+}
+
+define <2 x i1> @test8vec(<2 x i8> %A) {
+; CHECK-LABEL: @test8vec(
+; CHECK-NEXT:    [[C:%.*]] = icmp ugt <2 x i8> [[A:%.*]], <i8 -11, i8 -11>
+; CHECK-NEXT:    ret <2 x i1> [[C]]
+;
+  %B = udiv <2 x i8> %A, <i8 123, i8 123>
+  %C = icmp eq <2 x i8> %B, <i8 2, i8 2>
+  ret <2 x i1> %C
+}
+
+define i1 @test9(i8 %A) {
+; CHECK-LABEL: @test9(
+; CHECK-NEXT:    [[C:%.*]] = icmp ult i8 [[A:%.*]], -10
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %B = udiv i8 %A, 123
+  ; A < 246
+  %C = icmp ne i8 %B, 2
+  ret i1 %C
+}
+
+define <2 x i1> @test9vec(<2 x i8> %A) {
+; CHECK-LABEL: @test9vec(
+; CHECK-NEXT:    [[C:%.*]] = icmp ult <2 x i8> [[A:%.*]], <i8 -10, i8 -10>
+; CHECK-NEXT:    ret <2 x i1> [[C]]
+;
+  %B = udiv <2 x i8> %A, <i8 123, i8 123>
+  %C = icmp ne <2 x i8> %B, <i8 2, i8 2>
+  ret <2 x i1> %C
+}
+
+define i32 @test10(i32 %X, i1 %C) {
+; CHECK-LABEL: @test10(
+; CHECK-NEXT:    [[R_V:%.*]] = select i1 [[C:%.*]], i32 6, i32 3
+; CHECK-NEXT:    [[R:%.*]] = lshr i32 [[X:%.*]], [[R_V]]
+; CHECK-NEXT:    ret i32 [[R]]
+;
+  %V = select i1 %C, i32 64, i32 8
+  %R = udiv i32 %X, %V
+  ret i32 %R
+}
+
+define i32 @test11(i32 %X, i1 %C) {
+; CHECK-LABEL: @test11(
+; CHECK-NEXT:    [[B_V:%.*]] = select i1 [[C:%.*]], i32 10, i32 5
+; CHECK-NEXT:    [[B:%.*]] = lshr i32 [[X:%.*]], [[B_V]]
+; CHECK-NEXT:    ret i32 [[B]]
+;
+  %A = select i1 %C, i32 1024, i32 32
+  %B = udiv i32 %X, %A
+  ret i32 %B
+}
+
+; PR2328
+define i32 @test12(i32 %x) {
+; CHECK-LABEL: @test12(
+; CHECK-NEXT:    ret i32 1
+;
+  %tmp3 = udiv i32 %x, %x		; 1
+  ret i32 %tmp3
+}
+
+define i32 @test13(i32 %x) {
+; CHECK-LABEL: @test13(
+; CHECK-NEXT:    ret i32 1
+;
+  %tmp3 = sdiv i32 %x, %x		; 1
+  ret i32 %tmp3
+}
+
+define i32 @test14(i8 %x) {
+; CHECK-LABEL: @test14(
+; CHECK-NEXT:    ret i32 0
+;
+  %zext = zext i8 %x to i32
+  %div = udiv i32 %zext, 257	; 0
+  ret i32 %div
+}
+
+; PR9814
+define i32 @test15(i32 %a, i32 %b) {
+; CHECK-LABEL: @test15(
+; CHECK-NEXT:    [[TMP1:%.*]] = add i32 [[B:%.*]], -2
+; CHECK-NEXT:    [[DIV2:%.*]] = lshr i32 [[A:%.*]], [[TMP1]]
+; CHECK-NEXT:    ret i32 [[DIV2]]
+;
+  %shl = shl i32 1, %b
+  %div = lshr i32 %shl, 2
+  %div2 = udiv i32 %a, %div
+  ret i32 %div2
+}
+
+define <2 x i64> @test16(<2 x i64> %x) {
+; CHECK-LABEL: @test16(
+; CHECK-NEXT:    [[DIV:%.*]] = udiv <2 x i64> [[X:%.*]], <i64 192, i64 192>
+; CHECK-NEXT:    ret <2 x i64> [[DIV]]
+;
+  %shr = lshr <2 x i64> %x, <i64 5, i64 5>
+  %div = udiv <2 x i64> %shr, <i64 6, i64 6>
+  ret <2 x i64> %div
+}
+
+define i32 @test19(i32 %x) {
+; CHECK-LABEL: @test19(
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp eq i32 [[X:%.*]], 1
+; CHECK-NEXT:    [[A:%.*]] = zext i1 [[TMP1]] to i32
+; CHECK-NEXT:    ret i32 [[A]]
+;
+  %A = udiv i32 1, %x
+  ret i32 %A
+}
+
+define <2 x i32> @test19vec(<2 x i32> %x) {
+; CHECK-LABEL: @test19vec(
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp eq <2 x i32> [[X:%.*]], <i32 1, i32 1>
+; CHECK-NEXT:    [[A:%.*]] = zext <2 x i1> [[TMP1]] to <2 x i32>
+; CHECK-NEXT:    ret <2 x i32> [[A]]
+;
+  %A = udiv <2 x i32> <i32 1, i32 1>, %x
+  ret <2 x i32> %A
+}
+
+define i32 @test20(i32 %x) {
+; CHECK-LABEL: @test20(
+; CHECK-NEXT:    [[TMP1:%.*]] = add i32 [[X:%.*]], 1
+; CHECK-NEXT:    [[TMP2:%.*]] = icmp ult i32 [[TMP1]], 3
+; CHECK-NEXT:    [[A:%.*]] = select i1 [[TMP2]], i32 [[X]], i32 0
+; CHECK-NEXT:    ret i32 [[A]]
+;
+  %A = sdiv i32 1, %x
+  ret i32 %A
+}
+
+define <2 x i32> @test20vec(<2 x i32> %x) {
+; CHECK-LABEL: @test20vec(
+; CHECK-NEXT:    [[TMP1:%.*]] = add <2 x i32> [[X:%.*]], <i32 1, i32 1>
+; CHECK-NEXT:    [[TMP2:%.*]] = icmp ult <2 x i32> [[TMP1]], <i32 3, i32 3>
+; CHECK-NEXT:    [[A:%.*]] = select <2 x i1> [[TMP2]], <2 x i32> [[X]], <2 x i32> zeroinitializer
+; CHECK-NEXT:    ret <2 x i32> [[A]]
+;
+  %A = sdiv <2 x i32> <i32 1, i32 1>, %x
+  ret <2 x i32> %A
+}
+
+define i32 @test21(i32 %a) {
+; CHECK-LABEL: @test21(
+; CHECK-NEXT:    [[DIV:%.*]] = sdiv i32 [[A:%.*]], 3
+; CHECK-NEXT:    ret i32 [[DIV]]
+;
+  %shl = shl nsw i32 %a, 2
+  %div = sdiv i32 %shl, 12
+  ret i32 %div
+}
+
+define i32 @test22(i32 %a) {
+; CHECK-LABEL: @test22(
+; CHECK-NEXT:    [[DIV:%.*]] = sdiv i32 [[A:%.*]], 4
+; CHECK-NEXT:    ret i32 [[DIV]]
+;
+  %mul = mul nsw i32 %a, 3
+  %div = sdiv i32 %mul, 12
+  ret i32 %div
+}
+
+define i32 @test23(i32 %a) {
+; CHECK-LABEL: @test23(
+; CHECK-NEXT:    [[DIV:%.*]] = udiv i32 [[A:%.*]], 3
+; CHECK-NEXT:    ret i32 [[DIV]]
+;
+  %shl = shl nuw i32 %a, 2
+  %div = udiv i32 %shl, 12
+  ret i32 %div
+}
+
+define i32 @test24(i32 %a) {
+; CHECK-LABEL: @test24(
+; CHECK-NEXT:    [[DIV:%.*]] = lshr i32 [[A:%.*]], 2
+; CHECK-NEXT:    ret i32 [[DIV]]
+;
+  %mul = mul nuw i32 %a, 3
+  %div = udiv i32 %mul, 12
+  ret i32 %div
+}
+
+define i32 @test25(i32 %a) {
+; CHECK-LABEL: @test25(
+; CHECK-NEXT:    [[DIV:%.*]] = shl nsw i32 [[A:%.*]], 1
+; CHECK-NEXT:    ret i32 [[DIV]]
+;
+  %shl = shl nsw i32 %a, 2
+  %div = sdiv i32 %shl, 2
+  ret i32 %div
+}
+
+define i32 @test26(i32 %a) {
+; CHECK-LABEL: @test26(
+; CHECK-NEXT:    [[DIV:%.*]] = shl nsw i32 [[A:%.*]], 2
+; CHECK-NEXT:    ret i32 [[DIV]]
+;
+  %mul = mul nsw i32 %a, 12
+  %div = sdiv i32 %mul, 3
+  ret i32 %div
+}
+
+define i32 @test27(i32 %a) {
+; CHECK-LABEL: @test27(
+; CHECK-NEXT:    [[DIV:%.*]] = shl nuw i32 [[A:%.*]], 1
+; CHECK-NEXT:    ret i32 [[DIV]]
+;
+  %shl = shl nuw i32 %a, 2
+  %div = udiv i32 %shl, 2
+  ret i32 %div
+}
+
+define i32 @test28(i32 %a) {
+; CHECK-LABEL: @test28(
+; CHECK-NEXT:    [[DIV:%.*]] = mul nuw i32 [[A:%.*]], 12
+; CHECK-NEXT:    ret i32 [[DIV]]
+;
+  %mul = mul nuw i32 %a, 36
+  %div = udiv i32 %mul, 3
+  ret i32 %div
+}
+
+define i32 @test29(i32 %a) {
+; CHECK-LABEL: @test29(
+; CHECK-NEXT:    [[MUL_LOBIT:%.*]] = and i32 [[A:%.*]], 1
+; CHECK-NEXT:    ret i32 [[MUL_LOBIT]]
+;
+  %mul = shl nsw i32 %a, 31
+  %div = sdiv i32 %mul, -2147483648
+  ret i32 %div
+}
+
+define i32 @test30(i32 %a) {
+; CHECK-LABEL: @test30(
+; CHECK-NEXT:    ret i32 [[A:%.*]]
+;
+  %mul = shl nuw i32 %a, 31
+  %div = udiv i32 %mul, -2147483648
+  ret i32 %div
+}
+
+define <2 x i32> @test31(<2 x i32> %x) {
+; CHECK-LABEL: @test31(
+; CHECK-NEXT:    ret <2 x i32> zeroinitializer
+;
+  %shr = lshr <2 x i32> %x, <i32 31, i32 31>
+  %div = udiv <2 x i32> %shr, <i32 2147483647, i32 2147483647>
+  ret <2 x i32> %div
+}
+
+define i32 @test32(i32 %a, i32 %b) {
+; CHECK-LABEL: @test32(
+; CHECK-NEXT:    [[SHL:%.*]] = shl i32 2, [[B:%.*]]
+; CHECK-NEXT:    [[DIV:%.*]] = lshr i32 [[SHL]], 2
+; CHECK-NEXT:    [[DIV2:%.*]] = udiv i32 [[A:%.*]], [[DIV]]
+; CHECK-NEXT:    ret i32 [[DIV2]]
+;
+  %shl = shl i32 2, %b
+  %div = lshr i32 %shl, 2
+  %div2 = udiv i32 %a, %div
+  ret i32 %div2
+}
+
+define <2 x i64> @test33(<2 x i64> %x) {
+; CHECK-LABEL: @test33(
+; CHECK-NEXT:    [[DIV:%.*]] = udiv exact <2 x i64> [[X:%.*]], <i64 192, i64 192>
+; CHECK-NEXT:    ret <2 x i64> [[DIV]]
+;
+  %shr = lshr exact <2 x i64> %x, <i64 5, i64 5>
+  %div = udiv exact <2 x i64> %shr, <i64 6, i64 6>
+  ret <2 x i64> %div
+}
+
+; -X / C --> X / -C (if negation does not overflow)
+
+define i8 @sdiv_negated_dividend_constant_divisor(i8 %x) {
+; CHECK-LABEL: @sdiv_negated_dividend_constant_divisor(
+; CHECK-NEXT:    [[D:%.*]] = sdiv i8 [[X:%.*]], 42
+; CHECK-NEXT:    ret i8 [[D]]
+;
+  %neg = sub nsw i8 0, %x
+  %d = sdiv i8 %neg, -42
+  ret i8 %d
+}
+
+define <2 x i8> @sdiv_negated_dividend_constant_divisor_vec_splat(<2 x i8> %x) {
+; CHECK-LABEL: @sdiv_negated_dividend_constant_divisor_vec_splat(
+; CHECK-NEXT:    [[D:%.*]] = sdiv <2 x i8> [[X:%.*]], <i8 42, i8 42>
+; CHECK-NEXT:    ret <2 x i8> [[D]]
+;
+  %neg = sub nsw <2 x i8> zeroinitializer, %x
+  %d = sdiv <2 x i8> %neg, <i8 -42, i8 -42>
+  ret <2 x i8> %d
+}
+
+define i8 @sdiv_exact_negated_dividend_constant_divisor(i8 %x) {
+; CHECK-LABEL: @sdiv_exact_negated_dividend_constant_divisor(
+; CHECK-NEXT:    [[D:%.*]] = sdiv exact i8 [[X:%.*]], 42
+; CHECK-NEXT:    ret i8 [[D]]
+;
+  %neg = sub nsw i8 0, %x
+  %d = sdiv exact i8 %neg, -42
+  ret i8 %d
+}
+
+define <2 x i8> @sdiv_exact_negated_dividend_constant_divisor_vec_splat(<2 x i8> %x) {
+; CHECK-LABEL: @sdiv_exact_negated_dividend_constant_divisor_vec_splat(
+; CHECK-NEXT:    [[D:%.*]] = sdiv exact <2 x i8> [[X:%.*]], <i8 42, i8 42>
+; CHECK-NEXT:    ret <2 x i8> [[D]]
+;
+  %neg = sub nsw <2 x i8> zeroinitializer, %x
+  %d = sdiv exact <2 x i8> %neg, <i8 -42, i8 -42>
+  ret <2 x i8> %d
+}
+
+define i8 @sdiv_negated_dividend_constant_divisor_smin(i8 %x) {
+; CHECK-LABEL: @sdiv_negated_dividend_constant_divisor_smin(
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp eq i8 [[X:%.*]], -128
+; CHECK-NEXT:    [[D:%.*]] = zext i1 [[TMP1]] to i8
+; CHECK-NEXT:    ret i8 [[D]]
+;
+  %neg = sub nsw i8 0, %x
+  %d = sdiv i8 %neg, -128
+  ret i8 %d
+}
+
+define <2 x i8> @sdiv_negated_dividend_constant_divisor_vec_splat_smin(<2 x i8> %x) {
+; CHECK-LABEL: @sdiv_negated_dividend_constant_divisor_vec_splat_smin(
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp eq <2 x i8> [[X:%.*]], <i8 -128, i8 -128>
+; CHECK-NEXT:    [[D:%.*]] = zext <2 x i1> [[TMP1]] to <2 x i8>
+; CHECK-NEXT:    ret <2 x i8> [[D]]
+;
+  %neg = sub nsw <2 x i8> zeroinitializer, %x
+  %d = sdiv <2 x i8> %neg, <i8 -128, i8 -128>
+  ret <2 x i8> %d
+}
+
+define <2 x i8> @sdiv_negated_dividend_constant_divisor_vec_undef(<2 x i8> %x) {
+; CHECK-LABEL: @sdiv_negated_dividend_constant_divisor_vec_undef(
+; CHECK-NEXT:    ret <2 x i8> undef
+;
+  %neg = sub nsw <2 x i8> zeroinitializer, %x
+  %d = sdiv <2 x i8> %neg, <i8 -128, i8 undef>
+  ret <2 x i8> %d
+}
+
+define <2 x i64> @sdiv_negated_dividend_constant_divisor_vec(<2 x i64> %x) {
+; CHECK-LABEL: @sdiv_negated_dividend_constant_divisor_vec(
+; CHECK-NEXT:    [[DIV1:%.*]] = sdiv <2 x i64> [[X:%.*]], <i64 3, i64 4>
+; CHECK-NEXT:    [[DIV:%.*]] = sub nsw <2 x i64> zeroinitializer, [[DIV1]]
+; CHECK-NEXT:    ret <2 x i64> [[DIV]]
+;
+  %neg = sub nsw <2 x i64> zeroinitializer, %x
+  %div = sdiv <2 x i64> %neg, <i64 3, i64 4>
+  ret <2 x i64> %div
+}
+
+define <2 x i64> @sdiv_exact_negated_dividend_constant_divisor_vec(<2 x i64> %x) {
+; CHECK-LABEL: @sdiv_exact_negated_dividend_constant_divisor_vec(
+; CHECK-NEXT:    [[DIV1:%.*]] = sdiv exact <2 x i64> [[X:%.*]], <i64 3, i64 4>
+; CHECK-NEXT:    [[DIV:%.*]] = sub nsw <2 x i64> zeroinitializer, [[DIV1]]
+; CHECK-NEXT:    ret <2 x i64> [[DIV]]
+;
+  %neg = sub nsw <2 x i64> zeroinitializer, %x
+  %div = sdiv exact <2 x i64> %neg, <i64 3, i64 4>
+  ret <2 x i64> %div
+}
+
+; Can't negate signed min vector element.
+
+define <2 x i8> @sdiv_exact_negated_dividend_constant_divisor_vec_overflow(<2 x i8> %x) {
+; CHECK-LABEL: @sdiv_exact_negated_dividend_constant_divisor_vec_overflow(
+; CHECK-NEXT:    [[DIV1:%.*]] = sdiv exact <2 x i8> [[X:%.*]], <i8 -128, i8 42>
+; CHECK-NEXT:    [[DIV:%.*]] = sub nsw <2 x i8> zeroinitializer, [[DIV1]]
+; CHECK-NEXT:    ret <2 x i8> [[DIV]]
+;
+  %neg = sub nsw <2 x i8> zeroinitializer, %x
+  %div = sdiv exact <2 x i8> %neg, <i8 -128, i8 42>
+  ret <2 x i8> %div
+}
+
+define i32 @test35(i32 %A) {
+; CHECK-LABEL: @test35(
+; CHECK-NEXT:    [[AND:%.*]] = and i32 [[A:%.*]], 2147483647
+; CHECK-NEXT:    [[MUL:%.*]] = udiv exact i32 [[AND]], 2147483647
+; CHECK-NEXT:    ret i32 [[MUL]]
+;
+  %and = and i32 %A, 2147483647
+  %mul = sdiv exact i32 %and, 2147483647
+  ret i32 %mul
+}
+
+define <2 x i32> @test35vec(<2 x i32> %A) {
+; CHECK-LABEL: @test35vec(
+; CHECK-NEXT:    [[AND:%.*]] = and <2 x i32> [[A:%.*]], <i32 2147483647, i32 2147483647>
+; CHECK-NEXT:    [[MUL:%.*]] = udiv exact <2 x i32> [[AND]], <i32 2147483647, i32 2147483647>
+; CHECK-NEXT:    ret <2 x i32> [[MUL]]
+;
+  %and = and <2 x i32> %A, <i32 2147483647, i32 2147483647>
+  %mul = sdiv exact <2 x i32> %and, <i32 2147483647, i32 2147483647>
+  ret <2 x i32> %mul
+}
+
+define i32 @test36(i32 %A) {
+; CHECK-LABEL: @test36(
+; CHECK-NEXT:    [[AND:%.*]] = and i32 [[A:%.*]], 2147483647
+; CHECK-NEXT:    [[MUL:%.*]] = lshr exact i32 [[AND]], [[A]]
+; CHECK-NEXT:    ret i32 [[MUL]]
+;
+  %and = and i32 %A, 2147483647
+  %shl = shl nsw i32 1, %A
+  %mul = sdiv exact i32 %and, %shl
+  ret i32 %mul
+}
+
+define <2 x i32> @test36vec(<2 x i32> %A) {
+; CHECK-LABEL: @test36vec(
+; CHECK-NEXT:    [[AND:%.*]] = and <2 x i32> [[A:%.*]], <i32 2147483647, i32 2147483647>
+; CHECK-NEXT:    [[MUL:%.*]] = lshr exact <2 x i32> [[AND]], [[A]]
+; CHECK-NEXT:    ret <2 x i32> [[MUL]]
+;
+  %and = and <2 x i32> %A, <i32 2147483647, i32 2147483647>
+  %shl = shl nsw <2 x i32> <i32 1, i32 1>, %A
+  %mul = sdiv exact <2 x i32> %and, %shl
+  ret <2 x i32> %mul
+}
+
+define i32 @test37(i32* %b) {
+; CHECK-LABEL: @test37(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    store i32 0, i32* [[B:%.*]], align 4
+; CHECK-NEXT:    br i1 undef, label [[LOR_RHS:%.*]], label [[LOR_END:%.*]]
+; CHECK:       lor.rhs:
+; CHECK-NEXT:    br label [[LOR_END]]
+; CHECK:       lor.end:
+; CHECK-NEXT:    ret i32 0
+;
+entry:
+  store i32 0, i32* %b, align 4
+  %0 = load i32, i32* %b, align 4
+  br i1 undef, label %lor.rhs, label %lor.end
+
+lor.rhs:                                          ; preds = %entry
+  %mul = mul nsw i32 undef, %0
+  br label %lor.end
+
+lor.end:                                          ; preds = %lor.rhs, %entry
+  %t.0 = phi i32 [ %0, %entry ], [ %mul, %lor.rhs ]
+  %div = sdiv i32 %t.0, 2
+  ret i32 %div
+}
+
+; We can perform the division in the smaller type.
+
+define i32 @shrink(i8 %x) {
+; CHECK-LABEL: @shrink(
+; CHECK-NEXT:    [[TMP1:%.*]] = sdiv i8 [[X:%.*]], 127
+; CHECK-NEXT:    [[DIV:%.*]] = sext i8 [[TMP1]] to i32
+; CHECK-NEXT:    ret i32 [[DIV]]
+;
+  %conv = sext i8 %x to i32
+  %div = sdiv i32 %conv, 127
+  ret i32 %div
+}
+
+; Division in the smaller type can lead to more optimizations.
+
+define i32 @zap(i8 %x) {
+; CHECK-LABEL: @zap(
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp eq i8 [[X:%.*]], -128
+; CHECK-NEXT:    [[DIV:%.*]] = zext i1 [[TMP1]] to i32
+; CHECK-NEXT:    ret i32 [[DIV]]
+;
+  %conv = sext i8 %x to i32
+  %div = sdiv i32 %conv, -128
+  ret i32 %div
+}
+
+; Splat constant divisors should get the same folds.
+
+define <3 x i32> @shrink_vec(<3 x i8> %x) {
+; CHECK-LABEL: @shrink_vec(
+; CHECK-NEXT:    [[TMP1:%.*]] = sdiv <3 x i8> [[X:%.*]], <i8 127, i8 127, i8 127>
+; CHECK-NEXT:    [[DIV:%.*]] = sext <3 x i8> [[TMP1]] to <3 x i32>
+; CHECK-NEXT:    ret <3 x i32> [[DIV]]
+;
+  %conv = sext <3 x i8> %x to <3 x i32>
+  %div = sdiv <3 x i32> %conv, <i32 127, i32 127, i32 127>
+  ret <3 x i32> %div
+}
+
+define <2 x i32> @zap_vec(<2 x i8> %x) {
+; CHECK-LABEL: @zap_vec(
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp eq <2 x i8> [[X:%.*]], <i8 -128, i8 -128>
+; CHECK-NEXT:    [[DIV:%.*]] = zext <2 x i1> [[TMP1]] to <2 x i32>
+; CHECK-NEXT:    ret <2 x i32> [[DIV]]
+;
+  %conv = sext <2 x i8> %x to <2 x i32>
+  %div = sdiv <2 x i32> %conv, <i32 -128, i32 -128>
+  ret <2 x i32> %div
+}
+
+; But we can't do this if the signed constant won't fit in the original type.
+
+define i32 @shrink_no(i8 %x) {
+; CHECK-LABEL: @shrink_no(
+; CHECK-NEXT:    [[CONV:%.*]] = sext i8 [[X:%.*]] to i32
+; CHECK-NEXT:    [[DIV:%.*]] = sdiv i32 [[CONV]], 128
+; CHECK-NEXT:    ret i32 [[DIV]]
+;
+  %conv = sext i8 %x to i32
+  %div = sdiv i32 %conv, 128
+  ret i32 %div
+}
+
+; When the divisor is known larger than the quotient,
+; InstSimplify should kill it before InstCombine sees it.
+
+define i32 @shrink_no2(i8 %x) {
+; CHECK-LABEL: @shrink_no2(
+; CHECK-NEXT:    ret i32 0
+;
+  %conv = sext i8 %x to i32
+  %div = sdiv i32 %conv, -129
+  ret i32 %div
+}
+
+define i32 @shrink_no3(i16 %x) {
+; CHECK-LABEL: @shrink_no3(
+; CHECK-NEXT:    ret i32 0
+;
+  %conv = sext i16 %x to i32
+  %div = sdiv i32 %conv, 65535
+  ret i32 %div
+}
+
+; This previously crashed when trying to simplify the zext/icmp this becomes.
+define <2 x i8> @PR34841(<2 x i8> %x) {
+; CHECK-LABEL: @PR34841(
+; CHECK-NEXT:    ret <2 x i8> zeroinitializer
+;
+  %neg = and <2 x i8> %x, <i8 2, i8 2>
+  %div = udiv <2 x i8> <i8 1, i8 1>, %neg
+  ret <2 x i8> %div
+}
+
+; X / (X * Y) -> 1 / Y if the multiplication does not overflow
+
+define i8 @div_factor_signed(i8 %x, i8 %y) {
+; CHECK-LABEL: @div_factor_signed(
+; CHECK-NEXT:    [[TMP1:%.*]] = add i8 [[Y:%.*]], 1
+; CHECK-NEXT:    [[TMP2:%.*]] = icmp ult i8 [[TMP1]], 3
+; CHECK-NEXT:    [[R:%.*]] = select i1 [[TMP2]], i8 [[Y]], i8 0
+; CHECK-NEXT:    ret i8 [[R]]
+;
+  %a = mul nsw i8 %x, %y
+  %r = sdiv i8 %x, %a
+  ret i8 %r
+}
+
+; X / (Y * X) -> 1 / Y if the multiplication does not overflow
+
+define <2 x i8> @div_factor_signed_vec(<2 x i8> %x, <2 x i8> %y) {
+; CHECK-LABEL: @div_factor_signed_vec(
+; CHECK-NEXT:    [[TMP1:%.*]] = add <2 x i8> [[Y:%.*]], <i8 1, i8 1>
+; CHECK-NEXT:    [[TMP2:%.*]] = icmp ult <2 x i8> [[TMP1]], <i8 3, i8 3>
+; CHECK-NEXT:    [[R:%.*]] = select <2 x i1> [[TMP2]], <2 x i8> [[Y]], <2 x i8> zeroinitializer
+; CHECK-NEXT:    ret <2 x i8> [[R]]
+;
+  %a = mul nsw <2 x i8> %y, %x
+  %r = sdiv <2 x i8> %x, %a
+  ret <2 x i8> %r
+}
+
+; X / (Y * X) -> 1 / Y if the multiplication does not overflow
+
+define i8 @div_factor_unsigned(i8 %x, i8 %y) {
+; CHECK-LABEL: @div_factor_unsigned(
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp eq i8 [[Y:%.*]], 1
+; CHECK-NEXT:    [[R:%.*]] = zext i1 [[TMP1]] to i8
+; CHECK-NEXT:    ret i8 [[R]]
+;
+  %a = mul nuw i8 %y, %x
+  %r = udiv i8 %x, %a
+  ret i8 %r
+}
+
+; X / (X * Y) -> 1 / Y if the multiplication does not overflow
+
+define <2 x i8> @div_factor_unsigned_vec(<2 x i8> %x, <2 x i8> %y) {
+; CHECK-LABEL: @div_factor_unsigned_vec(
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp eq <2 x i8> [[Y:%.*]], <i8 1, i8 1>
+; CHECK-NEXT:    [[R:%.*]] = zext <2 x i1> [[TMP1]] to <2 x i8>
+; CHECK-NEXT:    ret <2 x i8> [[R]]
+;
+  %a = mul nuw <2 x i8> %x, %y
+  %r = udiv <2 x i8> %x, %a
+  ret <2 x i8> %r
+}
+
+define i8 @udiv_common_factor(i8 %x, i8 %y, i8 %z) {
+; CHECK-LABEL: @udiv_common_factor(
+; CHECK-NEXT:    [[C:%.*]] = udiv i8 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    ret i8 [[C]]
+;
+  %a = mul nuw i8 %z, %x
+  %b = mul nuw i8 %z, %y
+  %c = udiv i8 %a, %b
+  ret i8 %c
+}
+
+define <2 x i8> @udiv_common_factor_commute1_vec(<2 x i8> %x, <2 x i8> %y, <2 x i8> %z) {
+; CHECK-LABEL: @udiv_common_factor_commute1_vec(
+; CHECK-NEXT:    [[C:%.*]] = udiv <2 x i8> [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    ret <2 x i8> [[C]]
+;
+  %a = mul nuw <2 x i8> %x, %z
+  %b = mul nuw <2 x i8> %z, %y
+  %c = udiv <2 x i8> %a, %b
+  ret <2 x i8> %c
+}
+
+define i8 @udiv_common_factor_commute2(i8 %x, i8 %y, i8 %z) {
+; CHECK-LABEL: @udiv_common_factor_commute2(
+; CHECK-NEXT:    [[C:%.*]] = udiv i8 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    ret i8 [[C]]
+;
+  %a = mul nuw i8 %x, %z
+  %b = mul nuw i8 %y, %z
+  %c = udiv i8 %a, %b
+  ret i8 %c
+}
+
+define i8 @udiv_common_factor_commute3(i8 %x, i8 %y, i8 %z) {
+; CHECK-LABEL: @udiv_common_factor_commute3(
+; CHECK-NEXT:    [[C:%.*]] = udiv i8 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    ret i8 [[C]]
+;
+  %a = mul nuw i8 %z, %x
+  %b = mul nuw i8 %y, %z
+  %c = udiv i8 %a, %b
+  ret i8 %c
+}
+
+; Negative test: both mul must be 'nuw'.
+
+define i8 @udiv_common_factor_not_nuw(i8 %x, i8 %y, i8 %z) {
+; CHECK-LABEL: @udiv_common_factor_not_nuw(
+; CHECK-NEXT:    [[A:%.*]] = mul i8 [[Z:%.*]], [[X:%.*]]
+; CHECK-NEXT:    [[B:%.*]] = mul nuw i8 [[Z]], [[Y:%.*]]
+; CHECK-NEXT:    [[C:%.*]] = udiv i8 [[A]], [[B]]
+; CHECK-NEXT:    ret i8 [[C]]
+;
+  %a = mul i8 %z, %x
+  %b = mul nuw i8 %z, %y
+  %c = udiv i8 %a, %b
+  ret i8 %c
+}
+
+; Negative test: both mul must be 'nuw'.
+
+define <2 x i8> @udiv_common_factor_not_nuw_vec(<2 x i8> %x, <2 x i8> %y, <2 x i8> %z) {
+; CHECK-LABEL: @udiv_common_factor_not_nuw_vec(
+; CHECK-NEXT:    [[A:%.*]] = mul nuw <2 x i8> [[Z:%.*]], [[X:%.*]]
+; CHECK-NEXT:    [[B:%.*]] = mul <2 x i8> [[Z]], [[Y:%.*]]
+; CHECK-NEXT:    [[C:%.*]] = udiv <2 x i8> [[A]], [[B]]
+; CHECK-NEXT:    ret <2 x i8> [[C]]
+;
+  %a = mul nuw <2 x i8> %z, %x
+  %b = mul <2 x i8> %z, %y
+  %c = udiv <2 x i8> %a, %b
+  ret <2 x i8> %c
+}
+
+define i32 @test_exact_nsw_exact(i32 %x) {
+; CHECK-LABEL: @test_exact_nsw_exact(
+; CHECK-NEXT:    [[NEG:%.*]] = sdiv exact i32 [[X:%.*]], -3
+; CHECK-NEXT:    ret i32 [[NEG]]
+;
+  %div = sdiv exact i32 %x, 3
+  %neg = sub nsw i32 0, %div
+  ret i32 %neg
+}
+
+define <2 x i64> @test_exact_vec(<2 x i64> %x) {
+; CHECK-LABEL: @test_exact_vec(
+; CHECK-NEXT:    [[DIV:%.*]] = sdiv exact <2 x i64> [[X:%.*]], <i64 3, i64 4>
+; CHECK-NEXT:    [[NEG:%.*]] = sub nsw <2 x i64> zeroinitializer, [[DIV]]
+; CHECK-NEXT:    ret <2 x i64> [[NEG]]
+;
+  %div = sdiv exact <2 x i64> %x, <i64 3, i64 4>
+  %neg = sub nsw <2 x i64> zeroinitializer, %div
+  ret <2 x i64> %neg
+}
+
+; Constant is safe to negate.
+
+define <2 x i8> @negate_sdiv_vec_splat(<2 x i8> %x) {
+; CHECK-LABEL: @negate_sdiv_vec_splat(
+; CHECK-NEXT:    [[NEG:%.*]] = sdiv <2 x i8> [[X:%.*]], <i8 -42, i8 -42>
+; CHECK-NEXT:    ret <2 x i8> [[NEG]]
+;
+  %div = sdiv <2 x i8> %x, <i8 42, i8 42>
+  %neg = sub <2 x i8> zeroinitializer, %div
+  ret <2 x i8> %neg
+}
+
+; Dividing by undef is UB.
+
+define <2 x i8> @negate_sdiv_vec_undef_elt(<2 x i8> %x) {
+; CHECK-LABEL: @negate_sdiv_vec_undef_elt(
+; CHECK-NEXT:    ret <2 x i8> undef
+;
+  %div = sdiv <2 x i8> %x, <i8 undef, i8 42>
+  %neg = sub <2 x i8> zeroinitializer, %div
+  ret <2 x i8> %neg
+}
+
+; Division by -1 may be UB (if numerator is the signed min val), but div-by-1 can be simplified.
+
+define <2 x i8> @negate_sdiv_vec_splat_one(<2 x i8> %x) {
+; CHECK-LABEL: @negate_sdiv_vec_splat_one(
+; CHECK-NEXT:    [[NEG:%.*]] = sub <2 x i8> zeroinitializer, [[X:%.*]]
+; CHECK-NEXT:    ret <2 x i8> [[NEG]]
+;
+  %div = sdiv <2 x i8> %x, <i8 1, i8 1>
+  %neg = sub <2 x i8> zeroinitializer, %div
+  ret <2 x i8> %neg
+}
+
+; Can't negate signed-min constant, but can convert to a compare..
+
+define <2 x i8> @negate_sdiv_vec_splat_signed_min(<2 x i8> %x) {
+; CHECK-LABEL: @negate_sdiv_vec_splat_signed_min(
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp eq <2 x i8> [[X:%.*]], <i8 -128, i8 -128>
+; CHECK-NEXT:    [[NEG:%.*]] = sext <2 x i1> [[TMP1]] to <2 x i8>
+; CHECK-NEXT:    ret <2 x i8> [[NEG]]
+;
+  %div = sdiv <2 x i8> %x, <i8 -128, i8 -128>
+  %neg = sub <2 x i8> zeroinitializer, %div
+  ret <2 x i8> %neg
+}
+
+; Division by -1 may be UB for any element of a vector.
+
+define <2 x i8> @negate_sdiv_vec_one_element(<2 x i8> %x) {
+; CHECK-LABEL: @negate_sdiv_vec_one_element(
+; CHECK-NEXT:    [[DIV:%.*]] = sdiv <2 x i8> [[X:%.*]], <i8 -1, i8 1>
+; CHECK-NEXT:    [[NEG:%.*]] = sub <2 x i8> zeroinitializer, [[DIV]]
+; CHECK-NEXT:    ret <2 x i8> [[NEG]]
+;
+  %div = sdiv <2 x i8> %x, <i8 -1, i8 1>
+  %neg = sub <2 x i8> zeroinitializer, %div
+  ret <2 x i8> %neg
+}
+
+; Can't negate signed-min constant for any element of a vector.
+
+define <2 x i8> @negate_sdiv_vec_signed_min_elt(<2 x i8> %x) {
+; CHECK-LABEL: @negate_sdiv_vec_signed_min_elt(
+; CHECK-NEXT:    [[DIV:%.*]] = sdiv <2 x i8> [[X:%.*]], <i8 -1, i8 -128>
+; CHECK-NEXT:    [[NEG:%.*]] = sub <2 x i8> zeroinitializer, [[DIV]]
+; CHECK-NEXT:    ret <2 x i8> [[NEG]]
+;
+  %div = sdiv <2 x i8> %x, <i8 -1, i8 -128>
+  %neg = sub <2 x i8> zeroinitializer, %div
+  ret <2 x i8> %neg
+}
+
+; Division by -1 may be UB and can't negate signed-min.
+
+define <2 x i8> @negate_sdiv_vec_signed_min_and_one_elt(<2 x i8> %x) {
+; CHECK-LABEL: @negate_sdiv_vec_signed_min_and_one_elt(
+; CHECK-NEXT:    [[DIV:%.*]] = sdiv <2 x i8> [[X:%.*]], <i8 1, i8 -128>
+; CHECK-NEXT:    [[NEG:%.*]] = sub <2 x i8> zeroinitializer, [[DIV]]
+; CHECK-NEXT:    ret <2 x i8> [[NEG]]
+;
+  %div = sdiv <2 x i8> %x, <i8 1, i8 -128>
+  %neg = sub <2 x i8> zeroinitializer, %div
+  ret <2 x i8> %neg
+}
+
+define i32 @test_exact_nonsw_exact(i32 %x) {
+; CHECK-LABEL: @test_exact_nonsw_exact(
+; CHECK-NEXT:    [[NEG:%.*]] = sdiv exact i32 [[X:%.*]], -3
+; CHECK-NEXT:    ret i32 [[NEG]]
+;
+  %div = sdiv exact i32 %x, 3
+  %neg = sub i32 0, %div
+  ret i32 %neg
+}
+
+define i32 @test_exact_nsw_noexact(i32 %x) {
+; CHECK-LABEL: @test_exact_nsw_noexact(
+; CHECK-NEXT:    [[NEG:%.*]] = sdiv i32 [[X:%.*]], -3
+; CHECK-NEXT:    ret i32 [[NEG]]
+;
+  %div = sdiv i32 %x, 3
+  %neg = sub nsw i32 0, %div
+  ret i32 %neg
+}
+
+define i32 @test_exact_nonsw_noexact(i32 %x) {
+; CHECK-LABEL: @test_exact_nonsw_noexact(
+; CHECK-NEXT:    [[NEG:%.*]] = sdiv i32 [[X:%.*]], -3
+; CHECK-NEXT:    ret i32 [[NEG]]
+;
+  %div = sdiv i32 %x, 3
+  %neg = sub i32 0, %div
+  ret i32 %neg
+}
+
+define i32 @test_exact_div_nonconst(i32 %x, i32 %y) {
+; CHECK-LABEL: @test_exact_div_nonconst(
+; CHECK-NEXT:    [[DIV:%.*]] = sdiv exact i32 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    [[NEG:%.*]] = sub nsw i32 0, [[DIV]]
+; CHECK-NEXT:    ret i32 [[NEG]]
+;
+  %div = sdiv exact i32 %x, %y
+  %neg = sub nsw i32 0, %div
+  ret i32 %neg
+}
+
+define i32 @test_exact_div_one(i32 %x) {
+; CHECK-LABEL: @test_exact_div_one(
+; CHECK-NEXT:    [[NEG:%.*]] = sub nsw i32 0, [[X:%.*]]
+; CHECK-NEXT:    ret i32 [[NEG]]
+;
+  %div = sdiv exact i32 %x, 1
+  %neg = sub nsw i32 0, %div
+  ret i32 %neg
+}
+
+define i8 @test_exact_div_minSigned(i8 %x) {
+; CHECK-LABEL: @test_exact_div_minSigned(
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp eq i8 [[X:%.*]], -128
+; CHECK-NEXT:    [[NEG:%.*]] = sext i1 [[TMP1]] to i8
+; CHECK-NEXT:    ret i8 [[NEG]]
+;
+  %div = sdiv exact i8 %x, -128
+  %neg = sub nsw i8 0, %div
+  ret i8 %neg
+}
+
+; X / INT_MIN --> X == INT_MIN
+
+define i8 @sdiv_by_int_min(i8 %x) {
+; CHECK-LABEL: @sdiv_by_int_min(
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp eq i8 [[X:%.*]], -128
+; CHECK-NEXT:    [[D:%.*]] = zext i1 [[TMP1]] to i8
+; CHECK-NEXT:    ret i8 [[D]]
+;
+  %d = sdiv i8 %x, -128
+  ret i8 %d
+}
+
+define <2 x i8> @sdiv_by_int_min_vec_splat(<2 x i8> %x) {
+; CHECK-LABEL: @sdiv_by_int_min_vec_splat(
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp eq <2 x i8> [[X:%.*]], <i8 -128, i8 -128>
+; CHECK-NEXT:    [[D:%.*]] = zext <2 x i1> [[TMP1]] to <2 x i8>
+; CHECK-NEXT:    ret <2 x i8> [[D]]
+;
+  %d = sdiv <2 x i8> %x, <i8 -128, i8 -128>
+  ret <2 x i8> %d
+}
+
+define <2 x i8> @sdiv_by_int_min_vec_splat_undef(<2 x i8> %x) {
+; CHECK-LABEL: @sdiv_by_int_min_vec_splat_undef(
+; CHECK-NEXT:    ret <2 x i8> undef
+;
+  %d = sdiv <2 x i8> %x, <i8 -128, i8 undef>
+  ret <2 x i8> %d
+}

Added: llvm/trunk/test/Transforms/InstCombine/double-float-shrink-1.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/double-float-shrink-1.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/double-float-shrink-1.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/double-float-shrink-1.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,574 @@
+; RUN: opt < %s -instcombine -S -mtriple x86_64-unknown-linux-gnu | FileCheck %s --check-prefixes=CHECK,LINUX,ISC99
+; RUN: opt < %s -instcombine -S -mtriple x86_64-pc-win32          | FileCheck %s --check-prefixes=CHECK,ISC99
+; RUN: opt < %s -instcombine -S -mtriple x86_64-pc-windows-msvc16 | FileCheck %s --check-prefixes=CHECK,MS64,ISC89
+; RUN: opt < %s -instcombine -S -mtriple i386-pc-windows-msvc     | FileCheck %s --check-prefixes=CHECK,ISC99
+; RUN: opt < %s -instcombine -S -mtriple i686-pc-windows-msvc17   | FileCheck %s --check-prefixes=CHECK,MS32,ISC89
+
+; Check for and against shrinkage when using the
+; unsafe-fp-math function attribute on a math lib
+; function. This optimization may be overridden by
+; the -enable-double-float-shrink option.
+; PR17850: http://llvm.org/bugs/show_bug.cgi?id=17850
+
+define float @acos_test1(float %f)   {
+; CHECK-LABEL: @acos_test1(
+; LINUX-NEXT:    [[ACOSF:%.*]] = call fast float @acosf(float [[F:%.*]])
+; LINUX-NEXT:    ret float [[ACOSF]]
+; MS32:          [[ACOSF:%.*]] = call fast double @acos(double [[F:%.*]])
+; MS64-NEXT:     [[ACOSF:%.*]] = call fast float @acosf(float [[F:%.*]])
+;
+  %conv = fpext float %f to double
+  %call = call fast double @acos(double %conv)
+  %conv1 = fptrunc double %call to float
+  ret float %conv1
+}
+
+define double @acos_test2(float %f)   {
+; CHECK-LABEL: @acos_test2(
+; CHECK-NEXT:    [[CONV:%.*]] = fpext float [[F:%.*]] to double
+; CHECK-NEXT:    [[CALL:%.*]] = call fast double @acos(double [[CONV]])
+; CHECK-NEXT:    ret double [[CALL]]
+;
+  %conv = fpext float %f to double
+  %call = call fast double @acos(double %conv)
+  ret double %call
+}
+
+define float @acosh_test1(float %f)   {
+; CHECK-LABEL: @acosh_test1(
+; ISC99-NEXT:    [[ACOSHF:%.*]] = call fast float @acoshf(float [[F:%.*]])
+; ISC99-NEXT:    ret float [[ACOSHF]]
+; ISC89:         [[ACOSHF:%.*]] = call fast double @acosh(double [[F:%.*]])
+;
+  %conv = fpext float %f to double
+  %call = call fast double @acosh(double %conv)
+  %conv1 = fptrunc double %call to float
+  ret float %conv1
+}
+
+define double @acosh_test2(float %f)   {
+; CHECK-LABEL: @acosh_test2(
+; CHECK-NEXT:    [[CONV:%.*]] = fpext float [[F:%.*]] to double
+; CHECK-NEXT:    [[CALL:%.*]] = call fast double @acosh(double [[CONV]])
+; CHECK-NEXT:    ret double [[CALL]]
+;
+  %conv = fpext float %f to double
+  %call = call fast double @acosh(double %conv)
+  ret double %call
+}
+
+define float @asin_test1(float %f)   {
+; CHECK-LABEL: @asin_test1(
+; LINUX-NEXT:    [[ASINF:%.*]] = call fast float @asinf(float [[F:%.*]])
+; LINUX-NEXT:    ret float [[ASINF]]
+; MS32:          [[ASINF:%.*]] = call fast double @asin(double [[F:%.*]])
+; MS64-NEXT:     [[ASINF:%.*]] = call fast float @asinf(float [[F:%.*]])
+;
+  %conv = fpext float %f to double
+  %call = call fast double @asin(double %conv)
+  %conv1 = fptrunc double %call to float
+  ret float %conv1
+}
+
+define double @asin_test2(float %f)   {
+; CHECK-LABEL: @asin_test2(
+; CHECK-NEXT:    [[CONV:%.*]] = fpext float [[F:%.*]] to double
+; CHECK-NEXT:    [[CALL:%.*]] = call fast double @asin(double [[CONV]])
+; CHECK-NEXT:    ret double [[CALL]]
+;
+  %conv = fpext float %f to double
+  %call = call fast double @asin(double %conv)
+  ret double %call
+}
+
+define float @asinh_test1(float %f)   {
+; CHECK-LABEL: @asinh_test1(
+; ISC99-NEXT:   [[ASINHF:%.*]] = call fast float @asinhf(float [[F:%.*]])
+; ISC99-NEXT:   ret float [[ASINHF]]
+; ISC89:        [[ASINHF:%.*]] = call fast double @asinh(double [[F:%.*]])
+;
+  %conv = fpext float %f to double
+  %call = call fast double @asinh(double %conv)
+  %conv1 = fptrunc double %call to float
+  ret float %conv1
+}
+
+define double @asinh_test2(float %f)   {
+; CHECK-LABEL: @asinh_test2(
+; CHECK-NEXT:    [[CONV:%.*]] = fpext float [[F:%.*]] to double
+; CHECK-NEXT:    [[CALL:%.*]] = call fast double @asinh(double [[CONV]])
+; CHECK-NEXT:    ret double [[CALL]]
+;
+  %conv = fpext float %f to double
+  %call = call fast double @asinh(double %conv)
+  ret double %call
+}
+
+define float @atan_test1(float %f)   {
+; CHECK-LABEL: @atan_test1(
+; LINUX-NEXT:    [[ATANF:%.*]] = call fast float @atanf(float [[F:%.*]])
+; LINUX-NEXT:    ret float [[ATANF]]
+; MS32:          [[ATANF:%.*]] = call fast double @atan(double [[F:%.*]])
+; MS64-NEXT:     [[ATANF:%.*]] = call fast float @atanf(float [[F:%.*]])
+;
+  %conv = fpext float %f to double
+  %call = call fast double @atan(double %conv)
+  %conv1 = fptrunc double %call to float
+  ret float %conv1
+}
+
+define double @atan_test2(float %f)   {
+; CHECK-LABEL: @atan_test2(
+; CHECK-NEXT:    [[CONV:%.*]] = fpext float [[F:%.*]] to double
+; CHECK-NEXT:    [[CALL:%.*]] = call fast double @atan(double [[CONV]])
+; CHECK-NEXT:    ret double [[CALL]]
+;
+  %conv = fpext float %f to double
+  %call = call fast double @atan(double %conv)
+  ret double %call
+}
+
+define float @atanh_test1(float %f)   {
+; CHECK-LABEL: @atanh_test1(
+; ISC99-NEXT:    [[ATANHF:%.*]] = call fast float @atanhf(float [[F:%.*]])
+; ISC99-NEXT:    ret float [[ATANHF]]
+; ISC89:         [[ATANHF:%.*]] = call fast double @atanh(double [[F:%.*]])
+;
+  %conv = fpext float %f to double
+  %call = call fast double @atanh(double %conv)
+  %conv1 = fptrunc double %call to float
+  ret float %conv1
+}
+
+define double @atanh_test2(float %f)   {
+; CHECK-LABEL: @atanh_test2(
+; CHECK-NEXT:    [[CONV:%.*]] = fpext float [[F:%.*]] to double
+; CHECK-NEXT:    [[CALL:%.*]] = call fast double @atanh(double [[CONV]])
+; CHECK-NEXT:    ret double [[CALL]]
+;
+  %conv = fpext float %f to double
+  %call = call fast double @atanh(double %conv)
+  ret double %call
+}
+
+define float @cbrt_test1(float %f)   {
+; CHECK-LABEL: @cbrt_test1(
+; ISC99-NEXT:    [[CBRTF:%.*]] = call fast float @cbrtf(float [[F:%.*]])
+; ISC99-NEXT:    ret float [[CBRTF]]
+; ISC89:         [[CBRTF:%.*]] = call fast double @cbrt(double [[F:%.*]])
+;
+  %conv = fpext float %f to double
+  %call = call fast double @cbrt(double %conv)
+  %conv1 = fptrunc double %call to float
+  ret float %conv1
+}
+
+define double @cbrt_test2(float %f)   {
+; CHECK-LABEL: @cbrt_test2(
+; CHECK-NEXT:    [[CONV:%.*]] = fpext float [[F:%.*]] to double
+; CHECK-NEXT:    [[CALL:%.*]] = call fast double @cbrt(double [[CONV]])
+; CHECK-NEXT:    ret double [[CALL]]
+;
+  %conv = fpext float %f to double
+  %call = call fast  double @cbrt(double %conv)
+  ret double %call
+}
+
+define float @exp_test1(float %f)   {
+; CHECK-LABEL: @exp_test1(
+; LINUX-NEXT:    [[EXPF:%.*]] = call fast float @expf(float [[F:%.*]])
+; LINUX-NEXT:    ret float [[EXPF]]
+; MS32:          [[EXPF:%.*]] = call fast double @exp(double [[F:%.*]])
+; MS64-NEXT:     [[EXPF:%.*]] = call fast float @expf(float [[F:%.*]])
+;
+  %conv = fpext float %f to double
+  %call = call fast double @exp(double %conv)
+  %conv1 = fptrunc double %call to float
+  ret float %conv1
+}
+
+define double @exp_test2(float %f)   {
+; CHECK-LABEL: @exp_test2(
+; CHECK-NEXT:    [[CONV:%.*]] = fpext float [[F:%.*]] to double
+; CHECK-NEXT:    [[CALL:%.*]] = call fast double @exp(double [[CONV]])
+; CHECK-NEXT:    ret double [[CALL]]
+;
+  %conv = fpext float %f to double
+  %call = call fast double @exp(double %conv)
+  ret double %call
+}
+
+define float @expm1_test1(float %f)   {
+; CHECK-LABEL: @expm1_test1(
+; ISC99-NEXT:    [[EXPM1F:%.*]] = call fast float @expm1f(float [[F:%.*]])
+; ISC99-NEXT:    ret float [[EXPM1F]]
+; ISC89:         [[EXPM1F:%.*]] = call fast double @expm1(double [[F:%.*]])
+;
+  %conv = fpext float %f to double
+  %call = call fast double @expm1(double %conv)
+  %conv1 = fptrunc double %call to float
+  ret float %conv1
+}
+
+define double @expm1_test2(float %f)   {
+; CHECK-LABEL: @expm1_test2(
+; CHECK-NEXT:    [[CONV:%.*]] = fpext float [[F:%.*]] to double
+; CHECK-NEXT:    [[CALL:%.*]] = call fast double @expm1(double [[CONV]])
+; CHECK-NEXT:    ret double [[CALL]]
+;
+  %conv = fpext float %f to double
+  %call = call fast double @expm1(double %conv)
+  ret double %call
+}
+
+; exp10f() doesn't exist for this triple, so it doesn't shrink.
+
+define float @exp10_test1(float %f)   {
+; CHECK-LABEL: @exp10_test1(
+; CHECK-NEXT:    [[CONV:%.*]] = fpext float [[F:%.*]] to double
+; CHECK-NEXT:    [[CALL:%.*]] = call fast double @exp10(double [[CONV]])
+; CHECK-NEXT:    [[CONV1:%.*]] = fptrunc double [[CALL]] to float
+; CHECK-NEXT:    ret float [[CONV1]]
+;
+  %conv = fpext float %f to double
+  %call = call fast double @exp10(double %conv)
+  %conv1 = fptrunc double %call to float
+  ret float %conv1
+}
+
+define double @exp10_test2(float %f)   {
+; CHECK-LABEL: @exp10_test2(
+; CHECK-NEXT:    [[CONV:%.*]] = fpext float [[F:%.*]] to double
+; CHECK-NEXT:    [[CALL:%.*]] = call fast double @exp10(double [[CONV]])
+; CHECK-NEXT:    ret double [[CALL]]
+;
+  %conv = fpext float %f to double
+  %call = call fast double @exp10(double %conv)
+  ret double %call
+}
+
+define float @log_test1(float %f)   {
+; CHECK-LABEL: @log_test1(
+; LINUX-NEXT:    [[LOGF:%.*]] = call fast float @logf(float [[F:%.*]])
+; LINUX-NEXT:    ret float [[LOGF]]
+; MS32:          [[LOGF:%.*]] = call fast double @log(double [[F:%.*]])
+; MS64-NEXT:     [[LOGF:%.*]] = call fast float @logf(float [[F:%.*]])
+;
+  %conv = fpext float %f to double
+  %call = call fast double @log(double %conv)
+  %conv1 = fptrunc double %call to float
+  ret float %conv1
+}
+
+define double @log_test2(float %f)   {
+; CHECK-LABEL: @log_test2(
+; CHECK-NEXT:    [[CONV:%.*]] = fpext float [[F:%.*]] to double
+; CHECK-NEXT:    [[CALL:%.*]] = call fast double @log(double [[CONV]])
+; CHECK-NEXT:    ret double [[CALL]]
+;
+  %conv = fpext float %f to double
+  %call = call fast double @log(double %conv)
+  ret double %call
+}
+
+define float @log10_test1(float %f)   {
+; CHECK-LABEL: @log10_test1(
+; LINUX-NEXT:    [[LOG10F:%.*]] = call fast float @log10f(float [[F:%.*]])
+; LINUX-NEXT:    ret float [[LOG10F]]
+; MS32:          [[LOG10F:%.*]] = call fast double @log10(double [[F:%.*]])
+; MS64-NEXT:     [[LOG10F:%.*]] = call fast float @log10f(float [[F:%.*]])
+;
+  %conv = fpext float %f to double
+  %call = call fast double @log10(double %conv)
+  %conv1 = fptrunc double %call to float
+  ret float %conv1
+}
+
+define double @log10_test2(float %f) {
+; CHECK-LABEL: @log10_test2(
+; CHECK-NEXT:    [[CONV:%.*]] = fpext float [[F:%.*]] to double
+; CHECK-NEXT:    [[CALL:%.*]] = call fast double @log10(double [[CONV]])
+; CHECK-NEXT:    ret double [[CALL]]
+;
+  %conv = fpext float %f to double
+  %call = call fast double @log10(double %conv)
+  ret double %call
+}
+
+define float @log1p_test1(float %f)   {
+; CHECK-LABEL: @log1p_test1(
+; ISC99-NEXT:    [[LOG1PF:%.*]] = call fast float @log1pf(float [[F:%.*]])
+; ISC99-NEXT:    ret float [[LOG1PF]]
+; ISC89:         [[LOG1PF:%.*]] = call fast double @log1p(double [[F:%.*]])
+;
+  %conv = fpext float %f to double
+  %call = call fast double @log1p(double %conv)
+  %conv1 = fptrunc double %call to float
+  ret float %conv1
+}
+
+define double @log1p_test2(float %f)   {
+; CHECK-LABEL: @log1p_test2(
+; CHECK-NEXT:    [[CONV:%.*]] = fpext float [[F:%.*]] to double
+; CHECK-NEXT:    [[CALL:%.*]] = call fast double @log1p(double [[CONV]])
+; CHECK-NEXT:    ret double [[CALL]]
+;
+  %conv = fpext float %f to double
+  %call = call fast double @log1p(double %conv)
+  ret double %call
+}
+
+define float @log2_test1(float %f)   {
+; CHECK-LABEL: @log2_test1(
+; ISC99-NEXT:    [[LOG2F:%.*]] = call fast float @log2f(float [[F:%.*]])
+; ISC99-NEXT:    ret float [[LOG2F]]
+; ISC89:         [[LOG2F:%.*]] = call fast double @log2(double [[F:%.*]])
+;
+  %conv = fpext float %f to double
+  %call = call fast double @log2(double %conv)
+  %conv1 = fptrunc double %call to float
+  ret float %conv1
+}
+
+define double @log2_test2(float %f)   {
+; CHECK-LABEL: @log2_test2(
+; CHECK-NEXT:    [[CONV:%.*]] = fpext float [[F:%.*]] to double
+; CHECK-NEXT:    [[CALL:%.*]] = call fast double @log2(double [[CONV]])
+; CHECK-NEXT:    ret double [[CALL]]
+;
+  %conv = fpext float %f to double
+  %call = call fast double @log2(double %conv)
+  ret double %call
+}
+
+define float @logb_test1(float %f)   {
+; CHECK-LABEL: @logb_test1(
+; LINUX-NEXT:    [[LOGBF:%.*]] = call fast float @logbf(float [[F:%.*]])
+; LINUX-NEXT:    ret float [[LOGBF]]
+; MS32:          [[POWF:%.*]] = call fast double @logb(double [[F:%.*]])
+; MS64-NEXT:     [[LOGBF:%.*]] = call fast float @logbf(float [[F:%.*]])
+;
+  %conv = fpext float %f to double
+  %call = call fast double @logb(double %conv)
+  %conv1 = fptrunc double %call to float
+  ret float %conv1
+}
+
+define double @logb_test2(float %f)   {
+; CHECK-LABEL: @logb_test2(
+; CHECK-NEXT:    [[CONV:%.*]] = fpext float [[F:%.*]] to double
+; CHECK-NEXT:    [[CALL:%.*]] = call fast double @logb(double [[CONV]])
+; CHECK-NEXT:    ret double [[CALL]]
+;
+  %conv = fpext float %f to double
+  %call = call fast double @logb(double %conv)
+  ret double %call
+}
+
+define float @pow_test1(float %f, float %g)   {
+; CHECK-LABEL: @pow_test1(
+; LINUX-NEXT:    [[POWF:%.*]] = call fast float @powf(float %f, float %g)
+; LINUX-NEXT:    ret float [[POWF]]
+; MS32:          [[POWF:%.*]] = call fast double @pow(double %df, double %dg)
+; MS64-NEXT:     [[POWF:%.*]] = call fast float @powf(float %f, float %g)
+;
+  %df = fpext float %f to double
+  %dg = fpext float %g to double
+  %call = call fast double @pow(double %df, double %dg)
+  %fr = fptrunc double %call to float
+  ret float %fr
+}
+
+define double @pow_test2(float %f, float %g) {
+; CHECK-LABEL: @pow_test2(
+; CHECK:         [[POW:%.*]] = call fast double @pow(double %df, double %dg)
+; CHECK-NEXT:    ret double [[POW]]
+;
+  %df = fpext float %f to double
+  %dg = fpext float %g to double
+  %call = call fast double @pow(double %df, double %dg)
+  ret double %call
+}
+
+define float @sin_test1(float %f)   {
+; CHECK-LABEL: @sin_test1(
+; LINUX-NEXT:    [[SINF:%.*]] = call fast float @sinf(float [[F:%.*]])
+; LINUX-NEXT:    ret float [[SINF]]
+; MS32:          [[SINF:%.*]] = call fast double @sin(double [[F:%.*]])
+; MS64-NEXT:     [[SINF:%.*]] = call fast float @sinf(float [[F:%.*]])
+;
+  %conv = fpext float %f to double
+  %call = call fast double @sin(double %conv)
+  %conv1 = fptrunc double %call to float
+  ret float %conv1
+}
+
+define double @sin_test2(float %f) {
+; CHECK-LABEL: @sin_test2(
+; CHECK-NEXT:    [[CONV:%.*]] = fpext float [[F:%.*]] to double
+; CHECK-NEXT:    [[CALL:%.*]] = call fast double @sin(double [[CONV]])
+; CHECK-NEXT:    ret double [[CALL]]
+;
+  %conv = fpext float %f to double
+  %call = call fast double @sin(double %conv)
+  ret double %call
+}
+
+define float @sqrt_test1(float %f) {
+; CHECK-LABEL: @sqrt_test1(
+; LINUX-NEXT:    [[SQRTF:%.*]] = call float @sqrtf(float [[F:%.*]])
+; LINUX-NEXT:    ret float [[SQRTF]]
+; MS32:          [[SQRTF:%.*]] = call double @sqrt(double [[F:%.*]])
+; MS64-NEXT:     [[SQRTF:%.*]] = call float @sqrtf(float [[F:%.*]])
+;
+  %conv = fpext float %f to double
+  %call = call double @sqrt(double %conv)
+  %conv1 = fptrunc double %call to float
+  ret float %conv1
+}
+
+define double @sqrt_test2(float %f) {
+; CHECK-LABEL: @sqrt_test2(
+; CHECK-NEXT:    [[CONV:%.*]] = fpext float [[F:%.*]] to double
+; CHECK-NEXT:    [[CALL:%.*]] = call double @sqrt(double [[CONV]])
+; CHECK-NEXT:    ret double [[CALL]]
+;
+  %conv = fpext float %f to double
+  %call = call double @sqrt(double %conv)
+  ret double %call
+}
+
+define float @sqrt_int_test1(float %f) {
+; CHECK-LABEL: @sqrt_int_test1(
+; LINUX-NEXT:    [[TMP1:%.*]] = call float @llvm.sqrt.f32(float [[F:%.*]])
+; LINUX-NEXT:    ret float [[TMP1]]
+; MS32:          [[TMP1:%.*]] = call double @llvm.sqrt.f64(double [[F:%.*]])
+; MS64-NEXT:     [[TMP1:%.*]] = call float @llvm.sqrt.f32(float [[F:%.*]])
+;
+  %conv = fpext float %f to double
+  %call = call double @llvm.sqrt.f64(double %conv)
+  %conv1 = fptrunc double %call to float
+  ret float %conv1
+}
+
+define double @sqrt_int_test2(float %f) {
+; CHECK-LABEL: @sqrt_int_test2(
+; CHECK-NEXT:    [[CONV:%.*]] = fpext float [[F:%.*]] to double
+; CHECK-NEXT:    [[CALL:%.*]] = call double @llvm.sqrt.f64(double [[CONV]])
+; CHECK-NEXT:    ret double [[CALL]]
+;
+  %conv = fpext float %f to double
+  %call = call double @llvm.sqrt.f64(double %conv)
+  ret double %call
+}
+
+define float @tan_test1(float %f) {
+; CHECK-LABEL: @tan_test1(
+; LINUX-NEXT:    [[TANF:%.*]] = call fast float @tanf(float [[F:%.*]])
+; LINUX-NEXT:    ret float [[TANF]]
+; MS32:          [[TANF:%.*]] = call fast double @tan(double [[F:%.*]])
+; MS64-NEXT:     [[TANF:%.*]] = call fast float @tanf(float [[F:%.*]])
+;
+  %conv = fpext float %f to double
+  %call = call fast double @tan(double %conv)
+  %conv1 = fptrunc double %call to float
+  ret float %conv1
+}
+
+define double @tan_test2(float %f) {
+; CHECK-LABEL: @tan_test2(
+; CHECK-NEXT:    [[CONV:%.*]] = fpext float [[F:%.*]] to double
+; CHECK-NEXT:    [[CALL:%.*]] = call fast double @tan(double [[CONV]])
+; CHECK-NEXT:    ret double [[CALL]]
+;
+  %conv = fpext float %f to double
+  %call = call fast double @tan(double %conv)
+  ret double %call
+}
+define float @tanh_test1(float %f) {
+; CHECK-LABEL: @tanh_test1(
+; LINUX-NEXT:    [[TANHF:%.*]] = call fast float @tanhf(float [[F:%.*]])
+; LINUX-NEXT:    ret float [[TANHF]]
+; MS32:          [[TANHF:%.*]] = call fast double @tanh(double [[F:%.*]])
+; MS64-NEXT:     [[TANHF:%.*]] = call fast float @tanhf(float [[F:%.*]])
+;
+  %conv = fpext float %f to double
+  %call = call fast double @tanh(double %conv)
+  %conv1 = fptrunc double %call to float
+  ret float %conv1
+}
+
+define double @tanh_test2(float %f) {
+; CHECK-LABEL: @tanh_test2(
+; CHECK-NEXT:    [[CONV:%.*]] = fpext float [[F:%.*]] to double
+; CHECK-NEXT:    [[CALL:%.*]] = call fast double @tanh(double [[CONV]])
+; CHECK-NEXT:    ret double [[CALL]]
+;
+  %conv = fpext float %f to double
+  %call = call fast double @tanh(double %conv)
+  ret double %call
+}
+
+; 'arcp' on an fmax() is meaningless. This test just proves that
+; flags are propagated for shrunken *binary* double FP calls.
+define float @max1(float %a, float %b) {
+; CHECK-LABEL: @max1(
+; ISC99-NEXT:    [[FMAXF:%.*]] = call arcp float @fmaxf(float [[A:%.*]], float [[B:%.*]])
+; ISC99-NEXT:    ret float [[FMAXF]]
+; ISC89:         [[FMAXF:%.*]] = call arcp double @fmax(double [[A:%.*]], double [[B:%.*]])
+;
+  %c = fpext float %a to double
+  %d = fpext float %b to double
+  %e = call arcp double @fmax(double %c, double %d)
+  %f = fptrunc double %e to float
+  ret float %f
+}
+
+; A function can have a name that matches a common libcall,
+; but with the wrong type(s). Let it be.
+
+define float @fake_fmin(float %a, float %b) {
+; CHECK-LABEL: @fake_fmin(
+; CHECK-NEXT:    [[C:%.*]] = fpext float [[A:%.*]] to fp128
+; CHECK-NEXT:    [[D:%.*]] = fpext float [[B:%.*]] to fp128
+; CHECK-NEXT:    [[E:%.*]] = call fp128 @fmin(fp128 [[C]], fp128 [[D]])
+; CHECK-NEXT:    [[F:%.*]] = fptrunc fp128 [[E]] to float
+; CHECK-NEXT:    ret float [[F]]
+;
+  %c = fpext float %a to fp128
+  %d = fpext float %b to fp128
+  %e = call fp128 @fmin(fp128 %c, fp128 %d)
+  %f = fptrunc fp128 %e to float
+  ret float %f
+}
+
+declare fp128 @fmin(fp128, fp128) ; This is not the 'fmin' you're looking for.
+
+declare double @fmax(double, double)
+
+declare double @tanh(double)
+declare double @tan(double)
+
+; sqrt is a special case: the shrinking optimization
+; is valid even without unsafe-fp-math.
+declare double @sqrt(double)
+declare double @llvm.sqrt.f64(double)
+
+declare double @sin(double)
+declare double @pow(double, double)
+declare double @log2(double)
+declare double @log1p(double)
+declare double @log10(double)
+declare double @log(double)
+declare double @logb(double)
+declare double @exp10(double)
+declare double @expm1(double)
+declare double @exp(double)
+declare double @cbrt(double)
+declare double @atanh(double)
+declare double @atan(double)
+declare double @acos(double)
+declare double @acosh(double)
+declare double @asin(double)
+declare double @asinh(double)
+

Added: llvm/trunk/test/Transforms/InstCombine/double-float-shrink-2.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/double-float-shrink-2.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/double-float-shrink-2.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/double-float-shrink-2.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,654 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt < %s -instcombine -S -mtriple "i386-pc-linux"     | FileCheck %s
+; RUN: opt < %s -instcombine -S -mtriple "i386-pc-win32"     | FileCheck %s
+; RUN: opt < %s -instcombine -S -mtriple "x86_64-pc-win32"   | FileCheck %s
+; RUN: opt < %s -instcombine -S -mtriple "i386-pc-mingw32"   | FileCheck %s
+; RUN: opt < %s -instcombine -S -mtriple "x86_64-pc-mingw32" | FileCheck %s
+; RUN: opt < %s -instcombine -S -mtriple "sparc-sun-solaris" | FileCheck %s
+; RUN: opt < %s -instcombine -S -mtriple "x86_64-pc-win32" -enable-debugify 2>&1 | FileCheck --check-prefix=DBG-VALID %s
+
+declare double @floor(double)
+declare double @ceil(double)
+declare double @round(double)
+declare double @nearbyint(double)
+declare double @trunc(double)
+declare double @fabs(double)
+
+declare double @llvm.ceil.f64(double)
+declare <2 x double> @llvm.ceil.v2f64(<2 x double>)
+
+declare double @llvm.fabs.f64(double)
+declare <2 x double> @llvm.fabs.v2f64(<2 x double>)
+
+declare double @llvm.floor.f64(double)
+declare <2 x double> @llvm.floor.v2f64(<2 x double>)
+
+declare double @llvm.nearbyint.f64(double)
+declare <2 x double> @llvm.nearbyint.v2f64(<2 x double>)
+
+declare float @llvm.rint.f32(float)
+declare <2 x float> @llvm.rint.v2f32(<2 x float>)
+
+declare double @llvm.round.f64(double)
+declare <2 x double> @llvm.round.v2f64(<2 x double>)
+
+declare double @llvm.trunc.f64(double)
+declare <2 x double> @llvm.trunc.v2f64(<2 x double>)
+
+define float @test_shrink_libcall_floor(float %C) {
+; CHECK-LABEL: @test_shrink_libcall_floor(
+; CHECK-NEXT:    [[F:%.*]] = call float @llvm.floor.f32(float [[C:%.*]])
+; CHECK-NEXT:    ret float [[F]]
+;
+  %D = fpext float %C to double
+  ; --> floorf
+  %E = call double @floor(double %D)
+  %F = fptrunc double %E to float
+  ret float %F
+}
+
+define float @test_shrink_libcall_ceil(float %C) {
+; CHECK-LABEL: @test_shrink_libcall_ceil(
+; CHECK-NEXT:    [[F:%.*]] = call float @llvm.ceil.f32(float [[C:%.*]])
+; CHECK-NEXT:    ret float [[F]]
+;
+  %D = fpext float %C to double
+  ; --> ceilf
+  %E = call double @ceil(double %D)
+  %F = fptrunc double %E to float
+  ret float %F
+}
+
+define float @test_shrink_libcall_round(float %C) {
+; CHECK-LABEL: @test_shrink_libcall_round(
+; CHECK-NEXT:    [[F:%.*]] = call float @llvm.round.f32(float [[C:%.*]])
+; CHECK-NEXT:    ret float [[F]]
+;
+  %D = fpext float %C to double
+  ; --> roundf
+  %E = call double @round(double %D)
+  %F = fptrunc double %E to float
+  ret float %F
+}
+
+define float @test_shrink_libcall_nearbyint(float %C) {
+; CHECK-LABEL: @test_shrink_libcall_nearbyint(
+; CHECK-NEXT:    [[F:%.*]] = call float @llvm.nearbyint.f32(float [[C:%.*]])
+; CHECK-NEXT:    ret float [[F]]
+;
+  %D = fpext float %C to double
+  ; --> nearbyintf
+  %E = call double @nearbyint(double %D)
+  %F = fptrunc double %E to float
+  ret float %F
+}
+
+define float @test_shrink_libcall_trunc(float %C) {
+; CHECK-LABEL: @test_shrink_libcall_trunc(
+; CHECK-NEXT:    [[F:%.*]] = call float @llvm.trunc.f32(float [[C:%.*]])
+; CHECK-NEXT:    ret float [[F]]
+;
+  %D = fpext float %C to double
+  ; --> truncf
+  %E = call double @trunc(double %D)
+  %F = fptrunc double %E to float
+  ret float %F
+}
+
+; This is replaced with the intrinsic, which does the right thing on
+; CHECK platforms.
+define float @test_shrink_libcall_fabs(float %C) {
+; CHECK-LABEL: @test_shrink_libcall_fabs(
+; CHECK-NEXT:    [[F:%.*]] = call float @llvm.fabs.f32(float [[C:%.*]])
+; CHECK-NEXT:    ret float [[F]]
+;
+  %D = fpext float %C to double
+  %E = call double @fabs(double %D)
+  %F = fptrunc double %E to float
+  ret float %F
+}
+
+; Make sure fast math flags are preserved
+define float @test_shrink_libcall_fabs_fast(float %C) {
+; CHECK-LABEL: @test_shrink_libcall_fabs_fast(
+; CHECK-NEXT:    [[F:%.*]] = call fast float @llvm.fabs.f32(float [[C:%.*]])
+; CHECK-NEXT:    ret float [[F]]
+;
+  %D = fpext float %C to double
+  %E = call fast double @fabs(double %D)
+  %F = fptrunc double %E to float
+  ret float %F
+}
+
+define float @test_shrink_intrin_ceil(float %C) {
+; CHECK-LABEL: @test_shrink_intrin_ceil(
+; CHECK-NEXT:    [[TMP1:%.*]] = call float @llvm.ceil.f32(float [[C:%.*]])
+; CHECK-NEXT:    ret float [[TMP1]]
+;
+  %D = fpext float %C to double
+  %E = call double @llvm.ceil.f64(double %D)
+  %F = fptrunc double %E to float
+  ret float %F
+}
+
+define float @test_shrink_intrin_fabs(float %C) {
+; CHECK-LABEL: @test_shrink_intrin_fabs(
+; CHECK-NEXT:    [[TMP1:%.*]] = call float @llvm.fabs.f32(float [[C:%.*]])
+; CHECK-NEXT:    ret float [[TMP1]]
+;
+  %D = fpext float %C to double
+  %E = call double @llvm.fabs.f64(double %D)
+  %F = fptrunc double %E to float
+  ret float %F
+}
+
+define float @test_shrink_intrin_floor(float %C) {
+; CHECK-LABEL: @test_shrink_intrin_floor(
+; CHECK-NEXT:    [[TMP1:%.*]] = call float @llvm.floor.f32(float [[C:%.*]])
+; CHECK-NEXT:    ret float [[TMP1]]
+;
+  %D = fpext float %C to double
+  %E = call double @llvm.floor.f64(double %D)
+  %F = fptrunc double %E to float
+  ret float %F
+}
+
+define float @test_shrink_intrin_nearbyint(float %C) {
+; CHECK-LABEL: @test_shrink_intrin_nearbyint(
+; CHECK-NEXT:    [[TMP1:%.*]] = call float @llvm.nearbyint.f32(float [[C:%.*]])
+; CHECK-NEXT:    ret float [[TMP1]]
+;
+  %D = fpext float %C to double
+  %E = call double @llvm.nearbyint.f64(double %D)
+  %F = fptrunc double %E to float
+  ret float %F
+}
+
+define half @test_shrink_intrin_rint(half %C) {
+; CHECK-LABEL: @test_shrink_intrin_rint(
+; CHECK-NEXT:    [[TMP1:%.*]] = call half @llvm.rint.f16(half [[C:%.*]])
+; CHECK-NEXT:    ret half [[TMP1]]
+;
+  %D = fpext half %C to float
+  %E = call float @llvm.rint.f32(float %D)
+  %F = fptrunc float %E to half
+  ret half %F
+}
+
+define float @test_shrink_intrin_round(float %C) {
+; CHECK-LABEL: @test_shrink_intrin_round(
+; CHECK-NEXT:    [[TMP1:%.*]] = call float @llvm.round.f32(float [[C:%.*]])
+; CHECK-NEXT:    ret float [[TMP1]]
+;
+  %D = fpext float %C to double
+  %E = call double @llvm.round.f64(double %D)
+  %F = fptrunc double %E to float
+  ret float %F
+}
+
+define float @test_shrink_intrin_trunc(float %C) {
+; CHECK-LABEL: @test_shrink_intrin_trunc(
+; CHECK-NEXT:    [[TMP1:%.*]] = call float @llvm.trunc.f32(float [[C:%.*]])
+; CHECK-NEXT:    ret float [[TMP1]]
+;
+  %D = fpext float %C to double
+  %E = call double @llvm.trunc.f64(double %D)
+  %F = fptrunc double %E to float
+  ret float %F
+}
+
+declare void @use_v2f64(<2 x double>)
+declare void @use_v2f32(<2 x float>)
+
+define <2 x float> @test_shrink_intrin_ceil_multi_use(<2 x float> %C) {
+; CHECK-LABEL: @test_shrink_intrin_ceil_multi_use(
+; CHECK-NEXT:    [[D:%.*]] = fpext <2 x float> [[C:%.*]] to <2 x double>
+; CHECK-NEXT:    [[E:%.*]] = call <2 x double> @llvm.ceil.v2f64(<2 x double> [[D]])
+; CHECK-NEXT:    [[F:%.*]] = fptrunc <2 x double> [[E]] to <2 x float>
+; CHECK-NEXT:    call void @use_v2f64(<2 x double> [[D]])
+; CHECK-NEXT:    ret <2 x float> [[F]]
+;
+  %D = fpext <2 x float> %C to <2 x double>
+  %E = call <2 x double> @llvm.ceil.v2f64(<2 x double> %D)
+  %F = fptrunc <2 x double> %E to <2 x float>
+  call void @use_v2f64(<2 x double> %D)
+  ret <2 x float> %F
+}
+
+define <2 x float> @test_shrink_intrin_fabs_multi_use(<2 x float> %C) {
+; CHECK-LABEL: @test_shrink_intrin_fabs_multi_use(
+; CHECK-NEXT:    [[TMP1:%.*]] = call <2 x float> @llvm.fabs.v2f32(<2 x float> [[C:%.*]])
+; CHECK-NEXT:    [[E:%.*]] = fpext <2 x float> [[TMP1]] to <2 x double>
+; CHECK-NEXT:    call void @use_v2f64(<2 x double> [[E]])
+; CHECK-NEXT:    ret <2 x float> [[TMP1]]
+;
+  %D = fpext <2 x float> %C to <2 x double>
+  %E = call <2 x double> @llvm.fabs.v2f64(<2 x double> %D)
+  %F = fptrunc <2 x double> %E to <2 x float>
+  call void @use_v2f64(<2 x double> %E)
+  ret <2 x float> %F
+}
+
+define <2 x float> @test_shrink_intrin_floor_multi_use(<2 x float> %C) {
+; CHECK-LABEL: @test_shrink_intrin_floor_multi_use(
+; CHECK-NEXT:    [[D:%.*]] = fpext <2 x float> [[C:%.*]] to <2 x double>
+; CHECK-NEXT:    [[E:%.*]] = call <2 x double> @llvm.floor.v2f64(<2 x double> [[D]])
+; CHECK-NEXT:    [[F:%.*]] = fptrunc <2 x double> [[E]] to <2 x float>
+; CHECK-NEXT:    call void @use_v2f64(<2 x double> [[D]])
+; CHECK-NEXT:    call void @use_v2f64(<2 x double> [[E]])
+; CHECK-NEXT:    ret <2 x float> [[F]]
+;
+  %D = fpext <2 x float> %C to <2 x double>
+  %E = call <2 x double> @llvm.floor.v2f64(<2 x double> %D)
+  %F = fptrunc <2 x double> %E to <2 x float>
+  call void @use_v2f64(<2 x double> %D)
+  call void @use_v2f64(<2 x double> %E)
+  ret <2 x float> %F
+}
+
+define <2 x float> @test_shrink_intrin_nearbyint_multi_use(<2 x float> %C) {
+; CHECK-LABEL: @test_shrink_intrin_nearbyint_multi_use(
+; CHECK-NEXT:    [[D:%.*]] = fpext <2 x float> [[C:%.*]] to <2 x double>
+; CHECK-NEXT:    [[E:%.*]] = call <2 x double> @llvm.nearbyint.v2f64(<2 x double> [[D]])
+; CHECK-NEXT:    [[F:%.*]] = fptrunc <2 x double> [[E]] to <2 x float>
+; CHECK-NEXT:    call void @use_v2f64(<2 x double> [[D]])
+; CHECK-NEXT:    ret <2 x float> [[F]]
+;
+  %D = fpext <2 x float> %C to <2 x double>
+  %E = call <2 x double> @llvm.nearbyint.v2f64(<2 x double> %D)
+  %F = fptrunc <2 x double> %E to <2 x float>
+  call void @use_v2f64(<2 x double> %D)
+  ret <2 x float> %F
+}
+
+define <2 x half> @test_shrink_intrin_rint_multi_use(<2 x half> %C) {
+; CHECK-LABEL: @test_shrink_intrin_rint_multi_use(
+; CHECK-NEXT:    [[TMP1:%.*]] = call <2 x half> @llvm.rint.v2f16(<2 x half> [[C:%.*]])
+; CHECK-NEXT:    [[E:%.*]] = fpext <2 x half> [[TMP1]] to <2 x float>
+; CHECK-NEXT:    call void @use_v2f32(<2 x float> [[E]])
+; CHECK-NEXT:    ret <2 x half> [[TMP1]]
+;
+  %D = fpext <2 x half> %C to <2 x float>
+  %E = call <2 x float> @llvm.rint.v2f32(<2 x float> %D)
+  %F = fptrunc <2 x float> %E to <2 x half>
+  call void @use_v2f32(<2 x float> %E)
+  ret <2 x half> %F
+}
+
+define <2 x float> @test_shrink_intrin_round_multi_use(<2 x float> %C) {
+; CHECK-LABEL: @test_shrink_intrin_round_multi_use(
+; CHECK-NEXT:    [[D:%.*]] = fpext <2 x float> [[C:%.*]] to <2 x double>
+; CHECK-NEXT:    [[E:%.*]] = call <2 x double> @llvm.round.v2f64(<2 x double> [[D]])
+; CHECK-NEXT:    [[F:%.*]] = fptrunc <2 x double> [[E]] to <2 x float>
+; CHECK-NEXT:    call void @use_v2f64(<2 x double> [[D]])
+; CHECK-NEXT:    call void @use_v2f64(<2 x double> [[E]])
+; CHECK-NEXT:    ret <2 x float> [[F]]
+;
+  %D = fpext <2 x float> %C to <2 x double>
+  %E = call <2 x double> @llvm.round.v2f64(<2 x double> %D)
+  %F = fptrunc <2 x double> %E to <2 x float>
+  call void @use_v2f64(<2 x double> %D)
+  call void @use_v2f64(<2 x double> %E)
+  ret <2 x float> %F
+}
+
+define <2 x float> @test_shrink_intrin_trunc_multi_use(<2 x float> %C) {
+; CHECK-LABEL: @test_shrink_intrin_trunc_multi_use(
+; CHECK-NEXT:    [[D:%.*]] = fpext <2 x float> [[C:%.*]] to <2 x double>
+; CHECK-NEXT:    [[E:%.*]] = call <2 x double> @llvm.trunc.v2f64(<2 x double> [[D]])
+; CHECK-NEXT:    [[F:%.*]] = fptrunc <2 x double> [[E]] to <2 x float>
+; CHECK-NEXT:    call void @use_v2f64(<2 x double> [[D]])
+; CHECK-NEXT:    ret <2 x float> [[F]]
+;
+  %D = fpext <2 x float> %C to <2 x double>
+  %E = call <2 x double> @llvm.trunc.v2f64(<2 x double> %D)
+  %F = fptrunc <2 x double> %E to <2 x float>
+  call void @use_v2f64(<2 x double> %D)
+  ret <2 x float> %F
+}
+
+; Make sure fast math flags are preserved
+define float @test_shrink_intrin_fabs_fast(float %C) {
+; CHECK-LABEL: @test_shrink_intrin_fabs_fast(
+; CHECK-NEXT:    [[TMP1:%.*]] = call fast float @llvm.fabs.f32(float [[C:%.*]])
+; CHECK-NEXT:    ret float [[TMP1]]
+;
+  %D = fpext float %C to double
+  %E = call fast double @llvm.fabs.f64(double %D)
+  %F = fptrunc double %E to float
+  ret float %F
+}
+
+define float @test_no_shrink_intrin_floor(double %D) {
+; CHECK-LABEL: @test_no_shrink_intrin_floor(
+; CHECK-NEXT:    [[E:%.*]] = call double @llvm.floor.f64(double [[D:%.*]])
+; CHECK-NEXT:    [[F:%.*]] = fptrunc double [[E]] to float
+; CHECK-NEXT:    ret float [[F]]
+;
+  %E = call double @llvm.floor.f64(double %D)
+  %F = fptrunc double %E to float
+  ret float %F
+}
+
+define float @test_no_shrink_intrin_ceil(double %D) {
+; CHECK-LABEL: @test_no_shrink_intrin_ceil(
+; CHECK-NEXT:    [[E:%.*]] = call double @llvm.ceil.f64(double [[D:%.*]])
+; CHECK-NEXT:    [[F:%.*]] = fptrunc double [[E]] to float
+; CHECK-NEXT:    ret float [[F]]
+;
+  %E = call double @llvm.ceil.f64(double %D)
+  %F = fptrunc double %E to float
+  ret float %F
+}
+
+define float @test_no_shrink_intrin_round(double %D) {
+; CHECK-LABEL: @test_no_shrink_intrin_round(
+; CHECK-NEXT:    [[E:%.*]] = call double @llvm.round.f64(double [[D:%.*]])
+; CHECK-NEXT:    [[F:%.*]] = fptrunc double [[E]] to float
+; CHECK-NEXT:    ret float [[F]]
+;
+  %E = call double @llvm.round.f64(double %D)
+  %F = fptrunc double %E to float
+  ret float %F
+}
+
+define float @test_no_shrink_intrin_nearbyint(double %D) {
+; CHECK-LABEL: @test_no_shrink_intrin_nearbyint(
+; CHECK-NEXT:    [[E:%.*]] = call double @llvm.nearbyint.f64(double [[D:%.*]])
+; CHECK-NEXT:    [[F:%.*]] = fptrunc double [[E]] to float
+; CHECK-NEXT:    ret float [[F]]
+;
+  %E = call double @llvm.nearbyint.f64(double %D)
+  %F = fptrunc double %E to float
+  ret float %F
+}
+
+define float @test_no_shrink_intrin_trunc(double %D) {
+; CHECK-LABEL: @test_no_shrink_intrin_trunc(
+; CHECK-NEXT:    [[E:%.*]] = call double @llvm.trunc.f64(double [[D:%.*]])
+; CHECK-NEXT:    [[F:%.*]] = fptrunc double [[E]] to float
+; CHECK-NEXT:    ret float [[F]]
+;
+  %E = call double @llvm.trunc.f64(double %D)
+  %F = fptrunc double %E to float
+  ret float %F
+}
+
+define float @test_shrink_intrin_fabs_double_src(double %D) {
+; CHECK-LABEL: @test_shrink_intrin_fabs_double_src(
+; CHECK-NEXT:    [[TMP1:%.*]] = fptrunc double [[D:%.*]] to float
+; CHECK-NEXT:    [[F:%.*]] = call float @llvm.fabs.f32(float [[TMP1]])
+; CHECK-NEXT:    ret float [[F]]
+;
+  %E = call double @llvm.fabs.f64(double %D)
+  %F = fptrunc double %E to float
+  ret float %F
+}
+
+; Make sure fast math flags are preserved
+define float @test_shrink_intrin_fabs_fast_double_src(double %D) {
+; CHECK-LABEL: @test_shrink_intrin_fabs_fast_double_src(
+; CHECK-NEXT:    [[TMP1:%.*]] = fptrunc double [[D:%.*]] to float
+; CHECK-NEXT:    [[F:%.*]] = call fast float @llvm.fabs.f32(float [[TMP1]])
+; CHECK-NEXT:    ret float [[F]]
+;
+  %E = call fast double @llvm.fabs.f64(double %D)
+  %F = fptrunc double %E to float
+  ret float %F
+}
+
+define float @test_shrink_float_convertible_constant_intrin_floor() {
+; CHECK-LABEL: @test_shrink_float_convertible_constant_intrin_floor(
+; CHECK-NEXT:    ret float 2.000000e+00
+;
+  %E = call double @llvm.floor.f64(double 2.1)
+  %F = fptrunc double %E to float
+  ret float %F
+}
+
+define float @test_shrink_float_convertible_constant_intrin_ceil() {
+; CHECK-LABEL: @test_shrink_float_convertible_constant_intrin_ceil(
+; CHECK-NEXT:    ret float 3.000000e+00
+;
+  %E = call double @llvm.ceil.f64(double 2.1)
+  %F = fptrunc double %E to float
+  ret float %F
+}
+
+define float @test_shrink_float_convertible_constant_intrin_round() {
+; CHECK-LABEL: @test_shrink_float_convertible_constant_intrin_round(
+; CHECK-NEXT:    ret float 2.000000e+00
+;
+  %E = call double @llvm.round.f64(double 2.1)
+  %F = fptrunc double %E to float
+  ret float %F
+}
+
+define float @test_shrink_float_convertible_constant_intrin_nearbyint() {
+; CHECK-LABEL: @test_shrink_float_convertible_constant_intrin_nearbyint(
+; CHECK-NEXT:    ret float 2.000000e+00
+;
+  %E = call double @llvm.nearbyint.f64(double 2.1)
+  %F = fptrunc double %E to float
+  ret float %F
+}
+
+define float @test_shrink_float_convertible_constant_intrin_trunc() {
+; CHECK-LABEL: @test_shrink_float_convertible_constant_intrin_trunc(
+; CHECK-NEXT:    ret float 2.000000e+00
+;
+  %E = call double @llvm.trunc.f64(double 2.1)
+  %F = fptrunc double %E to float
+  ret float %F
+}
+
+define float @test_shrink_float_convertible_constant_intrin_fabs() {
+; CHECK-LABEL: @test_shrink_float_convertible_constant_intrin_fabs(
+; CHECK-NEXT:    ret float 0x4000CCCCC0000000
+;
+  %E = call double @llvm.fabs.f64(double 2.1)
+  %F = fptrunc double %E to float
+  ret float %F
+}
+
+; Make sure fast math flags are preserved
+define float @test_shrink_float_convertible_constant_intrin_fabs_fast() {
+; CHECK-LABEL: @test_shrink_float_convertible_constant_intrin_fabs_fast(
+; CHECK-NEXT:    ret float 0x4000CCCCC0000000
+;
+  %E = call fast double @llvm.fabs.f64(double 2.1)
+  %F = fptrunc double %E to float
+  ret float %F
+}
+
+define half @test_no_shrink_mismatched_type_intrin_floor(double %D) {
+; CHECK-LABEL: @test_no_shrink_mismatched_type_intrin_floor(
+; CHECK-NEXT:    [[E:%.*]] = call double @llvm.floor.f64(double [[D:%.*]])
+; CHECK-NEXT:    [[F:%.*]] = fptrunc double [[E]] to half
+; CHECK-NEXT:    ret half [[F]]
+;
+  %E = call double @llvm.floor.f64(double %D)
+  %F = fptrunc double %E to half
+  ret half %F
+}
+
+define half @test_no_shrink_mismatched_type_intrin_ceil(double %D) {
+; CHECK-LABEL: @test_no_shrink_mismatched_type_intrin_ceil(
+; CHECK-NEXT:    [[E:%.*]] = call double @llvm.ceil.f64(double [[D:%.*]])
+; CHECK-NEXT:    [[F:%.*]] = fptrunc double [[E]] to half
+; CHECK-NEXT:    ret half [[F]]
+;
+  %E = call double @llvm.ceil.f64(double %D)
+  %F = fptrunc double %E to half
+  ret half %F
+}
+
+define half @test_no_shrink_mismatched_type_intrin_round(double %D) {
+; CHECK-LABEL: @test_no_shrink_mismatched_type_intrin_round(
+; CHECK-NEXT:    [[E:%.*]] = call double @llvm.round.f64(double [[D:%.*]])
+; CHECK-NEXT:    [[F:%.*]] = fptrunc double [[E]] to half
+; CHECK-NEXT:    ret half [[F]]
+;
+  %E = call double @llvm.round.f64(double %D)
+  %F = fptrunc double %E to half
+  ret half %F
+}
+
+define half @test_no_shrink_mismatched_type_intrin_nearbyint(double %D) {
+; CHECK-LABEL: @test_no_shrink_mismatched_type_intrin_nearbyint(
+; CHECK-NEXT:    [[E:%.*]] = call double @llvm.nearbyint.f64(double [[D:%.*]])
+; CHECK-NEXT:    [[F:%.*]] = fptrunc double [[E]] to half
+; CHECK-NEXT:    ret half [[F]]
+;
+  %E = call double @llvm.nearbyint.f64(double %D)
+  %F = fptrunc double %E to half
+  ret half %F
+}
+
+define half @test_no_shrink_mismatched_type_intrin_trunc(double %D) {
+; CHECK-LABEL: @test_no_shrink_mismatched_type_intrin_trunc(
+; CHECK-NEXT:    [[E:%.*]] = call double @llvm.trunc.f64(double [[D:%.*]])
+; CHECK-NEXT:    [[F:%.*]] = fptrunc double [[E]] to half
+; CHECK-NEXT:    ret half [[F]]
+;
+  %E = call double @llvm.trunc.f64(double %D)
+  %F = fptrunc double %E to half
+  ret half %F
+}
+
+define half @test_shrink_mismatched_type_intrin_fabs_double_src(double %D) {
+; CHECK-LABEL: @test_shrink_mismatched_type_intrin_fabs_double_src(
+; CHECK-NEXT:    [[TMP1:%.*]] = fptrunc double [[D:%.*]] to half
+; CHECK-NEXT:    [[F:%.*]] = call half @llvm.fabs.f16(half [[TMP1]])
+; CHECK-NEXT:    ret half [[F]]
+;
+  %E = call double @llvm.fabs.f64(double %D)
+  %F = fptrunc double %E to half
+  ret half %F
+}
+
+; Make sure fast math flags are preserved
+define half @test_mismatched_type_intrin_fabs_fast_double_src(double %D) {
+; CHECK-LABEL: @test_mismatched_type_intrin_fabs_fast_double_src(
+; CHECK-NEXT:    [[TMP1:%.*]] = fptrunc double [[D:%.*]] to half
+; CHECK-NEXT:    [[F:%.*]] = call fast half @llvm.fabs.f16(half [[TMP1]])
+; CHECK-NEXT:    ret half [[F]]
+;
+  %E = call fast double @llvm.fabs.f64(double %D)
+  %F = fptrunc double %E to half
+  ret half %F
+}
+
+define <2 x double> @test_shrink_intrin_floor_fp16_vec(<2 x half> %C) {
+; CHECK-LABEL: @test_shrink_intrin_floor_fp16_vec(
+; CHECK-NEXT:    [[TMP1:%.*]] = call arcp <2 x half> @llvm.floor.v2f16(<2 x half> [[C:%.*]])
+; CHECK-NEXT:    [[E:%.*]] = fpext <2 x half> [[TMP1]] to <2 x double>
+; CHECK-NEXT:    ret <2 x double> [[E]]
+;
+  %D = fpext <2 x half> %C to <2 x double>
+  %E = call arcp <2 x double> @llvm.floor.v2f64(<2 x double> %D)
+  ret <2 x double> %E
+}
+
+define float @test_shrink_intrin_ceil_fp16_src(half %C) {
+; CHECK-LABEL: @test_shrink_intrin_ceil_fp16_src(
+; CHECK-NEXT:    [[TMP1:%.*]] = call half @llvm.ceil.f16(half [[C:%.*]])
+; CHECK-NEXT:    [[F:%.*]] = fpext half [[TMP1]] to float
+; CHECK-NEXT:    ret float [[F]]
+;
+  %D = fpext half %C to double
+  %E = call double @llvm.ceil.f64(double %D)
+  %F = fptrunc double %E to float
+  ret float %F
+}
+
+define <2 x double> @test_shrink_intrin_round_fp16_vec(<2 x half> %C) {
+; CHECK-LABEL: @test_shrink_intrin_round_fp16_vec(
+; CHECK-NEXT:    [[TMP1:%.*]] = call <2 x half> @llvm.round.v2f16(<2 x half> [[C:%.*]])
+; CHECK-NEXT:    [[E:%.*]] = fpext <2 x half> [[TMP1]] to <2 x double>
+; CHECK-NEXT:    ret <2 x double> [[E]]
+;
+  %D = fpext <2 x  half> %C to <2 x double>
+  %E = call <2 x double> @llvm.round.v2f64(<2 x double> %D)
+  ret <2 x double> %E
+}
+
+define float @test_shrink_intrin_nearbyint_fp16_src(half %C) {
+; CHECK-LABEL: @test_shrink_intrin_nearbyint_fp16_src(
+; CHECK-NEXT:    [[TMP1:%.*]] = call half @llvm.nearbyint.f16(half [[C:%.*]])
+; CHECK-NEXT:    [[F:%.*]] = fpext half [[TMP1]] to float
+; CHECK-NEXT:    ret float [[F]]
+;
+  %D = fpext half %C to double
+  %E = call double @llvm.nearbyint.f64(double %D)
+  %F = fptrunc double %E to float
+  ret float %F
+}
+
+define <2 x double> @test_shrink_intrin_trunc_fp16_src(<2 x half> %C) {
+; CHECK-LABEL: @test_shrink_intrin_trunc_fp16_src(
+; CHECK-NEXT:    [[TMP1:%.*]] = call <2 x half> @llvm.trunc.v2f16(<2 x half> [[C:%.*]])
+; CHECK-NEXT:    [[E:%.*]] = fpext <2 x half> [[TMP1]] to <2 x double>
+; CHECK-NEXT:    ret <2 x double> [[E]]
+;
+  %D = fpext <2 x half> %C to <2 x double>
+  %E = call <2 x double> @llvm.trunc.v2f64(<2 x double> %D)
+  ret <2 x double> %E
+}
+
+define float @test_shrink_intrin_fabs_fp16_src(half %C) {
+; CHECK-LABEL: @test_shrink_intrin_fabs_fp16_src(
+; CHECK-NEXT:    [[TMP1:%.*]] = call half @llvm.fabs.f16(half [[C:%.*]])
+; CHECK-NEXT:    [[F:%.*]] = fpext half [[TMP1]] to float
+; CHECK-NEXT:    ret float [[F]]
+;
+  %D = fpext half %C to double
+  %E = call double @llvm.fabs.f64(double %D)
+  %F = fptrunc double %E to float
+  ret float %F
+}
+
+; Make sure fast math flags are preserved
+define float @test_shrink_intrin_fabs_fast_fp16_src(half %C) {
+; CHECK-LABEL: @test_shrink_intrin_fabs_fast_fp16_src(
+; CHECK-NEXT:    [[TMP1:%.*]] = call fast half @llvm.fabs.f16(half [[C:%.*]])
+; CHECK-NEXT:    [[F:%.*]] = fpext half [[TMP1]] to float
+; CHECK-NEXT:    ret float [[F]]
+;
+  %D = fpext half %C to double
+  %E = call fast double @llvm.fabs.f64(double %D)
+  %F = fptrunc double %E to float
+  ret float %F
+}
+
+define float @test_no_shrink_intrin_floor_multi_use_fpext(half %C) {
+; CHECK-LABEL: @test_no_shrink_intrin_floor_multi_use_fpext(
+; CHECK-NEXT:    [[D:%.*]] = fpext half [[C:%.*]] to double
+; CHECK-NEXT:    store volatile double [[D]], double* undef, align 8
+; CHECK-NEXT:    [[E:%.*]] = call double @llvm.floor.f64(double [[D]])
+; CHECK-NEXT:    [[F:%.*]] = fptrunc double [[E]] to float
+; CHECK-NEXT:    ret float [[F]]
+;
+  %D = fpext half %C to double
+  store volatile double %D, double* undef
+  %E = call double @llvm.floor.f64(double %D)
+  %F = fptrunc double %E to float
+  ret float %F
+}
+
+define float @test_no_shrink_intrin_fabs_multi_use_fpext(half %C) {
+; CHECK-LABEL: @test_no_shrink_intrin_fabs_multi_use_fpext(
+; CHECK-NEXT:    [[D:%.*]] = fpext half [[C:%.*]] to double
+; CHECK-NEXT:    store volatile double [[D]], double* undef, align 8
+; CHECK-NEXT:    [[E:%.*]] = call double @llvm.fabs.f64(double [[D]])
+; CHECK-NEXT:    [[F:%.*]] = fptrunc double [[E]] to float
+; CHECK-NEXT:    ret float [[F]]
+;
+  %D = fpext half %C to double
+  store volatile double %D, double* undef
+  %E = call double @llvm.fabs.f64(double %D)
+  %F = fptrunc double %E to float
+  ret float %F
+}
+
+; DBG-VALID: CheckModuleDebugify: PASS

Added: llvm/trunk/test/Transforms/InstCombine/early_constfold_changes_IR.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/early_constfold_changes_IR.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/early_constfold_changes_IR.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/early_constfold_changes_IR.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,20 @@
+; This run line verifies that we get the expected constant fold.
+; RUN: opt < %s -instcombine -S | FileCheck %s
+
+; This run line verifies that InstructionCombiningPass::runOnFunction reports
+; this as a modification of the IR.
+; RUN: opt < %s -instcombine -disable-output -debug-pass=Details 2>&1 | FileCheck %s --check-prefix=DETAILS
+
+define i32 @foo(i32 %arg) #0 {
+; CHECK-LABEL: @foo(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[AND:%.*]] = and i32 [[ARG:%.*]], 7
+; CHECK-NEXT:    ret i32 [[AND]]
+;
+entry:
+  %or = or i32 0, 7
+  %and = and i32 %arg, %or
+  ret i32 %and
+}
+
+; DETAILS:  Made Modification 'Combine redundant instructions' on Function 'foo'

Added: llvm/trunk/test/Transforms/InstCombine/early_dce_clobbers_callgraph.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/early_dce_clobbers_callgraph.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/early_dce_clobbers_callgraph.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/early_dce_clobbers_callgraph.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,31 @@
+; RUN: opt < %s -inline -instcombine -S | FileCheck %s
+
+; This test case exposed a bug in instcombine where the early
+; DCE of a call wasn't recognized as changing the IR.
+; So when runOnFunction propagated the "made changes" upwards
+; to the CallGraphSCCPass it signalled that no changes had been
+; made, so CallGraphSCCPass assumed that the old CallGraph,
+; as known by that pass manager, still was up-to-date.
+;
+; This was detected as an assert when trying to remove the
+; no longer used function 'bar' (due to incorrect reference
+; count in the CallGraph).
+
+attributes #0 = { noinline norecurse nounwind readnone }
+
+define void @foo() #0 {
+; CHECK-LABEL: @foo(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    ret void
+;
+entry:
+  %call = call i32 @bar()
+  ret void
+}
+
+define internal i32 @bar() #0 {
+; CHECK-NOT: bar
+entry:
+  ret i32 42
+}
+

Added: llvm/trunk/test/Transforms/InstCombine/element-atomic-memintrins.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/element-atomic-memintrins.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/element-atomic-memintrins.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/element-atomic-memintrins.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,418 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt -instcombine -S < %s | FileCheck %s
+
+;; ---- memset -----
+
+; Ensure 0-length memset is removed
+define void @test_memset_zero_length(i8* %dest) {
+; CHECK-LABEL: @test_memset_zero_length(
+; CHECK-NEXT:    ret void
+;
+  call void @llvm.memset.element.unordered.atomic.p0i8.i32(i8* align 1 %dest, i8 1, i32 0, i32 1)
+  ret void
+}
+
+define void @test_memset_to_store(i8* %dest) {
+; CHECK-LABEL: @test_memset_to_store(
+; CHECK-NEXT:    store atomic i8 1, i8* [[DEST:%.*]] unordered, align 1
+; CHECK-NEXT:    call void @llvm.memset.element.unordered.atomic.p0i8.i32(i8* align 1 [[DEST]], i8 1, i32 2, i32 1)
+; CHECK-NEXT:    call void @llvm.memset.element.unordered.atomic.p0i8.i32(i8* align 1 [[DEST]], i8 1, i32 4, i32 1)
+; CHECK-NEXT:    call void @llvm.memset.element.unordered.atomic.p0i8.i32(i8* align 1 [[DEST]], i8 1, i32 8, i32 1)
+; CHECK-NEXT:    call void @llvm.memset.element.unordered.atomic.p0i8.i32(i8* align 1 [[DEST]], i8 1, i32 16, i32 1)
+; CHECK-NEXT:    ret void
+;
+  call void @llvm.memset.element.unordered.atomic.p0i8.i32(i8* align 1 %dest, i8 1, i32 1, i32 1)
+  call void @llvm.memset.element.unordered.atomic.p0i8.i32(i8* align 1 %dest, i8 1, i32 2, i32 1)
+  call void @llvm.memset.element.unordered.atomic.p0i8.i32(i8* align 1 %dest, i8 1, i32 4, i32 1)
+  call void @llvm.memset.element.unordered.atomic.p0i8.i32(i8* align 1 %dest, i8 1, i32 8, i32 1)
+  call void @llvm.memset.element.unordered.atomic.p0i8.i32(i8* align 1 %dest, i8 1, i32 16, i32 1)
+  ret void
+}
+
+define void @test_memset_to_store_2(i8* %dest) {
+; CHECK-LABEL: @test_memset_to_store_2(
+; CHECK-NEXT:    store atomic i8 1, i8* [[DEST:%.*]] unordered, align 2
+; CHECK-NEXT:    [[TMP1:%.*]] = bitcast i8* [[DEST]] to i16*
+; CHECK-NEXT:    store atomic i16 257, i16* [[TMP1]] unordered, align 2
+; CHECK-NEXT:    call void @llvm.memset.element.unordered.atomic.p0i8.i32(i8* align 2 [[DEST]], i8 1, i32 4, i32 2)
+; CHECK-NEXT:    call void @llvm.memset.element.unordered.atomic.p0i8.i32(i8* align 2 [[DEST]], i8 1, i32 8, i32 2)
+; CHECK-NEXT:    call void @llvm.memset.element.unordered.atomic.p0i8.i32(i8* align 2 [[DEST]], i8 1, i32 16, i32 2)
+; CHECK-NEXT:    ret void
+;
+  call void @llvm.memset.element.unordered.atomic.p0i8.i32(i8* align 2 %dest, i8 1, i32 1, i32 1)
+  call void @llvm.memset.element.unordered.atomic.p0i8.i32(i8* align 2 %dest, i8 1, i32 2, i32 2)
+  call void @llvm.memset.element.unordered.atomic.p0i8.i32(i8* align 2 %dest, i8 1, i32 4, i32 2)
+  call void @llvm.memset.element.unordered.atomic.p0i8.i32(i8* align 2 %dest, i8 1, i32 8, i32 2)
+  call void @llvm.memset.element.unordered.atomic.p0i8.i32(i8* align 2 %dest, i8 1, i32 16, i32 2)
+  ret void
+}
+
+define void @test_memset_to_store_4(i8* %dest) {
+; CHECK-LABEL: @test_memset_to_store_4(
+; CHECK-NEXT:    store atomic i8 1, i8* [[DEST:%.*]] unordered, align 4
+; CHECK-NEXT:    [[TMP1:%.*]] = bitcast i8* [[DEST]] to i16*
+; CHECK-NEXT:    store atomic i16 257, i16* [[TMP1]] unordered, align 4
+; CHECK-NEXT:    [[TMP2:%.*]] = bitcast i8* [[DEST]] to i32*
+; CHECK-NEXT:    store atomic i32 16843009, i32* [[TMP2]] unordered, align 4
+; CHECK-NEXT:    call void @llvm.memset.element.unordered.atomic.p0i8.i32(i8* align 4 [[DEST]], i8 1, i32 8, i32 4)
+; CHECK-NEXT:    call void @llvm.memset.element.unordered.atomic.p0i8.i32(i8* align 4 [[DEST]], i8 1, i32 16, i32 4)
+; CHECK-NEXT:    ret void
+;
+  call void @llvm.memset.element.unordered.atomic.p0i8.i32(i8* align 4 %dest, i8 1, i32 1, i32 1)
+  call void @llvm.memset.element.unordered.atomic.p0i8.i32(i8* align 4 %dest, i8 1, i32 2, i32 2)
+  call void @llvm.memset.element.unordered.atomic.p0i8.i32(i8* align 4 %dest, i8 1, i32 4, i32 4)
+  call void @llvm.memset.element.unordered.atomic.p0i8.i32(i8* align 4 %dest, i8 1, i32 8, i32 4)
+  call void @llvm.memset.element.unordered.atomic.p0i8.i32(i8* align 4 %dest, i8 1, i32 16, i32 4)
+  ret void
+}
+
+define void @test_memset_to_store_8(i8* %dest) {
+; CHECK-LABEL: @test_memset_to_store_8(
+; CHECK-NEXT:    store atomic i8 1, i8* [[DEST:%.*]] unordered, align 8
+; CHECK-NEXT:    [[TMP1:%.*]] = bitcast i8* [[DEST]] to i16*
+; CHECK-NEXT:    store atomic i16 257, i16* [[TMP1]] unordered, align 8
+; CHECK-NEXT:    [[TMP2:%.*]] = bitcast i8* [[DEST]] to i32*
+; CHECK-NEXT:    store atomic i32 16843009, i32* [[TMP2]] unordered, align 8
+; CHECK-NEXT:    [[TMP3:%.*]] = bitcast i8* [[DEST]] to i64*
+; CHECK-NEXT:    store atomic i64 72340172838076673, i64* [[TMP3]] unordered, align 8
+; CHECK-NEXT:    call void @llvm.memset.element.unordered.atomic.p0i8.i32(i8* align 8 [[DEST]], i8 1, i32 16, i32 8)
+; CHECK-NEXT:    ret void
+;
+  call void @llvm.memset.element.unordered.atomic.p0i8.i32(i8* align 8 %dest, i8 1, i32 1, i32 1)
+  call void @llvm.memset.element.unordered.atomic.p0i8.i32(i8* align 8 %dest, i8 1, i32 2, i32 2)
+  call void @llvm.memset.element.unordered.atomic.p0i8.i32(i8* align 8 %dest, i8 1, i32 4, i32 4)
+  call void @llvm.memset.element.unordered.atomic.p0i8.i32(i8* align 8 %dest, i8 1, i32 8, i32 8)
+  call void @llvm.memset.element.unordered.atomic.p0i8.i32(i8* align 8 %dest, i8 1, i32 16, i32 8)
+  ret void
+}
+
+define void @test_memset_to_store_16(i8* %dest) {
+; CHECK-LABEL: @test_memset_to_store_16(
+; CHECK-NEXT:    store atomic i8 1, i8* [[DEST:%.*]] unordered, align 16
+; CHECK-NEXT:    [[TMP1:%.*]] = bitcast i8* [[DEST]] to i16*
+; CHECK-NEXT:    store atomic i16 257, i16* [[TMP1]] unordered, align 16
+; CHECK-NEXT:    [[TMP2:%.*]] = bitcast i8* [[DEST]] to i32*
+; CHECK-NEXT:    store atomic i32 16843009, i32* [[TMP2]] unordered, align 16
+; CHECK-NEXT:    [[TMP3:%.*]] = bitcast i8* [[DEST]] to i64*
+; CHECK-NEXT:    store atomic i64 72340172838076673, i64* [[TMP3]] unordered, align 16
+; CHECK-NEXT:    call void @llvm.memset.element.unordered.atomic.p0i8.i32(i8* align 16 [[DEST]], i8 1, i32 16, i32 16)
+; CHECK-NEXT:    ret void
+;
+  call void @llvm.memset.element.unordered.atomic.p0i8.i32(i8* align 16 %dest, i8 1, i32 1, i32 1)
+  call void @llvm.memset.element.unordered.atomic.p0i8.i32(i8* align 16 %dest, i8 1, i32 2, i32 2)
+  call void @llvm.memset.element.unordered.atomic.p0i8.i32(i8* align 16 %dest, i8 1, i32 4, i32 4)
+  call void @llvm.memset.element.unordered.atomic.p0i8.i32(i8* align 16 %dest, i8 1, i32 8, i32 8)
+  call void @llvm.memset.element.unordered.atomic.p0i8.i32(i8* align 16 %dest, i8 1, i32 16, i32 16)
+  ret void
+}
+
+declare void @llvm.memset.element.unordered.atomic.p0i8.i32(i8* nocapture writeonly, i8, i32, i32) nounwind argmemonly
+
+
+;; =========================================
+;; ----- memmove ------
+
+
+ at gconst = constant [32 x i8] c"0123456789012345678901234567890\00"
+; Check that a memmove from a global constant is converted into a memcpy
+define void @test_memmove_to_memcpy(i8* %dest) {
+; CHECK-LABEL: @test_memmove_to_memcpy(
+; CHECK-NEXT:    call void @llvm.memcpy.element.unordered.atomic.p0i8.p0i8.i32(i8* align 1 [[DEST:%.*]], i8* align 16 getelementptr inbounds ([32 x i8], [32 x i8]* @gconst, i64 0, i64 0), i32 32, i32 1)
+; CHECK-NEXT:    ret void
+;
+  call void @llvm.memmove.element.unordered.atomic.p0i8.p0i8.i32(i8* align 1 %dest, i8* align 1 getelementptr inbounds ([32 x i8], [32 x i8]* @gconst, i64 0, i64 0), i32 32, i32 1)
+  ret void
+}
+
+define void @test_memmove_zero_length(i8* %dest, i8* %src) {
+; CHECK-LABEL: @test_memmove_zero_length(
+; CHECK-NEXT:    ret void
+;
+  call void @llvm.memmove.element.unordered.atomic.p0i8.p0i8.i32(i8* align 1 %dest, i8* align 1 %src, i32 0, i32 1)
+  call void @llvm.memmove.element.unordered.atomic.p0i8.p0i8.i32(i8* align 2 %dest, i8* align 2 %src, i32 0, i32 2)
+  call void @llvm.memmove.element.unordered.atomic.p0i8.p0i8.i32(i8* align 4 %dest, i8* align 4 %src, i32 0, i32 4)
+  call void @llvm.memmove.element.unordered.atomic.p0i8.p0i8.i32(i8* align 8 %dest, i8* align 8 %src, i32 0, i32 8)
+  call void @llvm.memmove.element.unordered.atomic.p0i8.p0i8.i32(i8* align 16 %dest, i8* align 16 %src, i32 0, i32 16)
+  ret void
+}
+
+; memmove with src==dest is removed
+define void @test_memmove_removed(i8* %srcdest, i32 %sz) {
+; CHECK-LABEL: @test_memmove_removed(
+; CHECK-NEXT:    ret void
+;
+  call void @llvm.memmove.element.unordered.atomic.p0i8.p0i8.i32(i8* align 1 %srcdest, i8* align 1 %srcdest, i32 %sz, i32 1)
+  call void @llvm.memmove.element.unordered.atomic.p0i8.p0i8.i32(i8* align 2 %srcdest, i8* align 2 %srcdest, i32 %sz, i32 2)
+  call void @llvm.memmove.element.unordered.atomic.p0i8.p0i8.i32(i8* align 4 %srcdest, i8* align 4 %srcdest, i32 %sz, i32 4)
+  call void @llvm.memmove.element.unordered.atomic.p0i8.p0i8.i32(i8* align 8 %srcdest, i8* align 8 %srcdest, i32 %sz, i32 8)
+  call void @llvm.memmove.element.unordered.atomic.p0i8.p0i8.i32(i8* align 16 %srcdest, i8* align 16 %srcdest, i32 %sz, i32 16)
+  ret void
+}
+
+; memmove with a small constant length is converted to a load/store pair
+define void @test_memmove_loadstore(i8* %dest, i8* %src) {
+; CHECK-LABEL: @test_memmove_loadstore(
+; CHECK-NEXT:    [[TMP1:%.*]] = load atomic i8, i8* [[SRC:%.*]] unordered, align 1
+; CHECK-NEXT:    store atomic i8 [[TMP1]], i8* [[DEST:%.*]] unordered, align 1
+; CHECK-NEXT:    call void @llvm.memmove.element.unordered.atomic.p0i8.p0i8.i32(i8* align 1 [[DEST]], i8* align 1 [[SRC]], i32 2, i32 1)
+; CHECK-NEXT:    call void @llvm.memmove.element.unordered.atomic.p0i8.p0i8.i32(i8* align 1 [[DEST]], i8* align 1 [[SRC]], i32 4, i32 1)
+; CHECK-NEXT:    call void @llvm.memmove.element.unordered.atomic.p0i8.p0i8.i32(i8* align 1 [[DEST]], i8* align 1 [[SRC]], i32 8, i32 1)
+; CHECK-NEXT:    call void @llvm.memmove.element.unordered.atomic.p0i8.p0i8.i32(i8* align 1 [[DEST]], i8* align 1 [[SRC]], i32 16, i32 1)
+; CHECK-NEXT:    ret void
+;
+  call void @llvm.memmove.element.unordered.atomic.p0i8.p0i8.i32(i8* align 1 %dest, i8* align 1 %src, i32 1, i32 1)
+  call void @llvm.memmove.element.unordered.atomic.p0i8.p0i8.i32(i8* align 1 %dest, i8* align 1 %src, i32 2, i32 1)
+  call void @llvm.memmove.element.unordered.atomic.p0i8.p0i8.i32(i8* align 1 %dest, i8* align 1 %src, i32 4, i32 1)
+  call void @llvm.memmove.element.unordered.atomic.p0i8.p0i8.i32(i8* align 1 %dest, i8* align 1 %src, i32 8, i32 1)
+  call void @llvm.memmove.element.unordered.atomic.p0i8.p0i8.i32(i8* align 1 %dest, i8* align 1 %src, i32 16, i32 1)
+  ret void
+}
+
+define void @test_memmove_loadstore_2(i8* %dest, i8* %src) {
+; CHECK-LABEL: @test_memmove_loadstore_2(
+; CHECK-NEXT:    [[TMP1:%.*]] = load atomic i8, i8* [[SRC:%.*]] unordered, align 2
+; CHECK-NEXT:    store atomic i8 [[TMP1]], i8* [[DEST:%.*]] unordered, align 2
+; CHECK-NEXT:    [[TMP2:%.*]] = bitcast i8* [[SRC]] to i16*
+; CHECK-NEXT:    [[TMP3:%.*]] = bitcast i8* [[DEST]] to i16*
+; CHECK-NEXT:    [[TMP4:%.*]] = load atomic i16, i16* [[TMP2]] unordered, align 2
+; CHECK-NEXT:    store atomic i16 [[TMP4]], i16* [[TMP3]] unordered, align 2
+; CHECK-NEXT:    call void @llvm.memmove.element.unordered.atomic.p0i8.p0i8.i32(i8* align 2 [[DEST]], i8* align 2 [[SRC]], i32 4, i32 2)
+; CHECK-NEXT:    call void @llvm.memmove.element.unordered.atomic.p0i8.p0i8.i32(i8* align 2 [[DEST]], i8* align 2 [[SRC]], i32 8, i32 2)
+; CHECK-NEXT:    call void @llvm.memmove.element.unordered.atomic.p0i8.p0i8.i32(i8* align 2 [[DEST]], i8* align 2 [[SRC]], i32 16, i32 2)
+; CHECK-NEXT:    ret void
+;
+  call void @llvm.memmove.element.unordered.atomic.p0i8.p0i8.i32(i8* align 2 %dest, i8* align 2 %src, i32 1, i32 1)
+  call void @llvm.memmove.element.unordered.atomic.p0i8.p0i8.i32(i8* align 2 %dest, i8* align 2 %src, i32 2, i32 2)
+  call void @llvm.memmove.element.unordered.atomic.p0i8.p0i8.i32(i8* align 2 %dest, i8* align 2 %src, i32 4, i32 2)
+  call void @llvm.memmove.element.unordered.atomic.p0i8.p0i8.i32(i8* align 2 %dest, i8* align 2 %src, i32 8, i32 2)
+  call void @llvm.memmove.element.unordered.atomic.p0i8.p0i8.i32(i8* align 2 %dest, i8* align 2 %src, i32 16, i32 2)
+  ret void
+}
+
+define void @test_memmove_loadstore_4(i8* %dest, i8* %src) {
+; CHECK-LABEL: @test_memmove_loadstore_4(
+; CHECK-NEXT:    [[TMP1:%.*]] = load atomic i8, i8* [[SRC:%.*]] unordered, align 4
+; CHECK-NEXT:    store atomic i8 [[TMP1]], i8* [[DEST:%.*]] unordered, align 4
+; CHECK-NEXT:    [[TMP2:%.*]] = bitcast i8* [[SRC]] to i16*
+; CHECK-NEXT:    [[TMP3:%.*]] = bitcast i8* [[DEST]] to i16*
+; CHECK-NEXT:    [[TMP4:%.*]] = load atomic i16, i16* [[TMP2]] unordered, align 4
+; CHECK-NEXT:    store atomic i16 [[TMP4]], i16* [[TMP3]] unordered, align 4
+; CHECK-NEXT:    [[TMP5:%.*]] = bitcast i8* [[SRC]] to i32*
+; CHECK-NEXT:    [[TMP6:%.*]] = bitcast i8* [[DEST]] to i32*
+; CHECK-NEXT:    [[TMP7:%.*]] = load atomic i32, i32* [[TMP5]] unordered, align 4
+; CHECK-NEXT:    store atomic i32 [[TMP7]], i32* [[TMP6]] unordered, align 4
+; CHECK-NEXT:    call void @llvm.memmove.element.unordered.atomic.p0i8.p0i8.i32(i8* align 4 [[DEST]], i8* align 4 [[SRC]], i32 8, i32 4)
+; CHECK-NEXT:    call void @llvm.memmove.element.unordered.atomic.p0i8.p0i8.i32(i8* align 4 [[DEST]], i8* align 4 [[SRC]], i32 16, i32 4)
+; CHECK-NEXT:    ret void
+;
+  call void @llvm.memmove.element.unordered.atomic.p0i8.p0i8.i32(i8* align 4 %dest, i8* align 4 %src, i32 1, i32 1)
+  call void @llvm.memmove.element.unordered.atomic.p0i8.p0i8.i32(i8* align 4 %dest, i8* align 4 %src, i32 2, i32 2)
+  call void @llvm.memmove.element.unordered.atomic.p0i8.p0i8.i32(i8* align 4 %dest, i8* align 4 %src, i32 4, i32 4)
+  call void @llvm.memmove.element.unordered.atomic.p0i8.p0i8.i32(i8* align 4 %dest, i8* align 4 %src, i32 8, i32 4)
+  call void @llvm.memmove.element.unordered.atomic.p0i8.p0i8.i32(i8* align 4 %dest, i8* align 4 %src, i32 16, i32 4)
+  ret void
+}
+
+define void @test_memmove_loadstore_8(i8* %dest, i8* %src) {
+; CHECK-LABEL: @test_memmove_loadstore_8(
+; CHECK-NEXT:    [[TMP1:%.*]] = load atomic i8, i8* [[SRC:%.*]] unordered, align 8
+; CHECK-NEXT:    store atomic i8 [[TMP1]], i8* [[DEST:%.*]] unordered, align 8
+; CHECK-NEXT:    [[TMP2:%.*]] = bitcast i8* [[SRC]] to i16*
+; CHECK-NEXT:    [[TMP3:%.*]] = bitcast i8* [[DEST]] to i16*
+; CHECK-NEXT:    [[TMP4:%.*]] = load atomic i16, i16* [[TMP2]] unordered, align 8
+; CHECK-NEXT:    store atomic i16 [[TMP4]], i16* [[TMP3]] unordered, align 8
+; CHECK-NEXT:    [[TMP5:%.*]] = bitcast i8* [[SRC]] to i32*
+; CHECK-NEXT:    [[TMP6:%.*]] = bitcast i8* [[DEST]] to i32*
+; CHECK-NEXT:    [[TMP7:%.*]] = load atomic i32, i32* [[TMP5]] unordered, align 8
+; CHECK-NEXT:    store atomic i32 [[TMP7]], i32* [[TMP6]] unordered, align 8
+; CHECK-NEXT:    [[TMP8:%.*]] = bitcast i8* [[SRC]] to i64*
+; CHECK-NEXT:    [[TMP9:%.*]] = bitcast i8* [[DEST]] to i64*
+; CHECK-NEXT:    [[TMP10:%.*]] = load atomic i64, i64* [[TMP8]] unordered, align 8
+; CHECK-NEXT:    store atomic i64 [[TMP10]], i64* [[TMP9]] unordered, align 8
+; CHECK-NEXT:    call void @llvm.memmove.element.unordered.atomic.p0i8.p0i8.i32(i8* align 8 [[DEST]], i8* align 8 [[SRC]], i32 16, i32 8)
+; CHECK-NEXT:    ret void
+;
+  call void @llvm.memmove.element.unordered.atomic.p0i8.p0i8.i32(i8* align 8 %dest, i8* align 8 %src, i32 1, i32 1)
+  call void @llvm.memmove.element.unordered.atomic.p0i8.p0i8.i32(i8* align 8 %dest, i8* align 8 %src, i32 2, i32 2)
+  call void @llvm.memmove.element.unordered.atomic.p0i8.p0i8.i32(i8* align 8 %dest, i8* align 8 %src, i32 4, i32 4)
+  call void @llvm.memmove.element.unordered.atomic.p0i8.p0i8.i32(i8* align 8 %dest, i8* align 8 %src, i32 8, i32 8)
+  call void @llvm.memmove.element.unordered.atomic.p0i8.p0i8.i32(i8* align 8 %dest, i8* align 8 %src, i32 16, i32 8)
+  ret void
+}
+
+define void @test_memmove_loadstore_16(i8* %dest, i8* %src) {
+; CHECK-LABEL: @test_memmove_loadstore_16(
+; CHECK-NEXT:    [[TMP1:%.*]] = load atomic i8, i8* [[SRC:%.*]] unordered, align 16
+; CHECK-NEXT:    store atomic i8 [[TMP1]], i8* [[DEST:%.*]] unordered, align 16
+; CHECK-NEXT:    [[TMP2:%.*]] = bitcast i8* [[SRC]] to i16*
+; CHECK-NEXT:    [[TMP3:%.*]] = bitcast i8* [[DEST]] to i16*
+; CHECK-NEXT:    [[TMP4:%.*]] = load atomic i16, i16* [[TMP2]] unordered, align 16
+; CHECK-NEXT:    store atomic i16 [[TMP4]], i16* [[TMP3]] unordered, align 16
+; CHECK-NEXT:    [[TMP5:%.*]] = bitcast i8* [[SRC]] to i32*
+; CHECK-NEXT:    [[TMP6:%.*]] = bitcast i8* [[DEST]] to i32*
+; CHECK-NEXT:    [[TMP7:%.*]] = load atomic i32, i32* [[TMP5]] unordered, align 16
+; CHECK-NEXT:    store atomic i32 [[TMP7]], i32* [[TMP6]] unordered, align 16
+; CHECK-NEXT:    [[TMP8:%.*]] = bitcast i8* [[SRC]] to i64*
+; CHECK-NEXT:    [[TMP9:%.*]] = bitcast i8* [[DEST]] to i64*
+; CHECK-NEXT:    [[TMP10:%.*]] = load atomic i64, i64* [[TMP8]] unordered, align 16
+; CHECK-NEXT:    store atomic i64 [[TMP10]], i64* [[TMP9]] unordered, align 16
+; CHECK-NEXT:    call void @llvm.memmove.element.unordered.atomic.p0i8.p0i8.i32(i8* align 16 [[DEST:%.*]], i8* align 16 [[SRC:%.*]], i32 16, i32 16)
+; CHECK-NEXT:    ret void
+;
+  call void @llvm.memmove.element.unordered.atomic.p0i8.p0i8.i32(i8* align 16 %dest, i8* align 16 %src, i32 1, i32 1)
+  call void @llvm.memmove.element.unordered.atomic.p0i8.p0i8.i32(i8* align 16 %dest, i8* align 16 %src, i32 2, i32 2)
+  call void @llvm.memmove.element.unordered.atomic.p0i8.p0i8.i32(i8* align 16 %dest, i8* align 16 %src, i32 4, i32 4)
+  call void @llvm.memmove.element.unordered.atomic.p0i8.p0i8.i32(i8* align 16 %dest, i8* align 16 %src, i32 8, i32 8)
+  call void @llvm.memmove.element.unordered.atomic.p0i8.p0i8.i32(i8* align 16 %dest, i8* align 16 %src, i32 16, i32 16)
+  ret void
+}
+
+declare void @llvm.memmove.element.unordered.atomic.p0i8.p0i8.i32(i8* nocapture writeonly, i8* nocapture readonly, i32, i32) nounwind argmemonly
+
+;; =========================================
+;; ----- memcpy ------
+
+define void @test_memcpy_zero_length(i8* %dest, i8* %src) {
+; CHECK-LABEL: @test_memcpy_zero_length(
+; CHECK-NEXT:    ret void
+;
+  call void @llvm.memcpy.element.unordered.atomic.p0i8.p0i8.i32(i8* align 1 %dest, i8* align 1 %src, i32 0, i32 1)
+  call void @llvm.memcpy.element.unordered.atomic.p0i8.p0i8.i32(i8* align 2 %dest, i8* align 2 %src, i32 0, i32 2)
+  call void @llvm.memcpy.element.unordered.atomic.p0i8.p0i8.i32(i8* align 4 %dest, i8* align 4 %src, i32 0, i32 4)
+  call void @llvm.memcpy.element.unordered.atomic.p0i8.p0i8.i32(i8* align 8 %dest, i8* align 8 %src, i32 0, i32 8)
+  call void @llvm.memcpy.element.unordered.atomic.p0i8.p0i8.i32(i8* align 16 %dest, i8* align 16 %src, i32 0, i32 16)
+  ret void
+}
+
+; memcpy with src==dest is removed
+define void @test_memcpy_removed(i8* %srcdest, i32 %sz) {
+; CHECK-LABEL: @test_memcpy_removed(
+; CHECK-NEXT:    ret void
+;
+  call void @llvm.memcpy.element.unordered.atomic.p0i8.p0i8.i32(i8* align 1 %srcdest, i8* align 1 %srcdest, i32 %sz, i32 1)
+  call void @llvm.memcpy.element.unordered.atomic.p0i8.p0i8.i32(i8* align 2 %srcdest, i8* align 2 %srcdest, i32 %sz, i32 2)
+  call void @llvm.memcpy.element.unordered.atomic.p0i8.p0i8.i32(i8* align 4 %srcdest, i8* align 4 %srcdest, i32 %sz, i32 4)
+  call void @llvm.memcpy.element.unordered.atomic.p0i8.p0i8.i32(i8* align 8 %srcdest, i8* align 8 %srcdest, i32 %sz, i32 8)
+  call void @llvm.memcpy.element.unordered.atomic.p0i8.p0i8.i32(i8* align 16 %srcdest, i8* align 16 %srcdest, i32 %sz, i32 16)
+  ret void
+}
+
+; memcpy with a small constant length is converted to a load/store pair
+define void @test_memcpy_loadstore(i8* %dest, i8* %src) {
+; CHECK-LABEL: @test_memcpy_loadstore(
+; CHECK-NEXT:    [[TMP1:%.*]] = load atomic i8, i8* [[SRC:%.*]] unordered, align 1
+; CHECK-NEXT:    store atomic i8 [[TMP1]], i8* [[DEST:%.*]] unordered, align 1
+; CHECK-NEXT:    call void @llvm.memcpy.element.unordered.atomic.p0i8.p0i8.i32(i8* align 1 [[DEST]], i8* align 1 [[SRC]], i32 2, i32 1)
+; CHECK-NEXT:    call void @llvm.memcpy.element.unordered.atomic.p0i8.p0i8.i32(i8* align 1 [[DEST]], i8* align 1 [[SRC]], i32 4, i32 1)
+; CHECK-NEXT:    call void @llvm.memcpy.element.unordered.atomic.p0i8.p0i8.i32(i8* align 1 [[DEST]], i8* align 1 [[SRC]], i32 8, i32 1)
+; CHECK-NEXT:    call void @llvm.memcpy.element.unordered.atomic.p0i8.p0i8.i32(i8* align 1 [[DEST]], i8* align 1 [[SRC]], i32 16, i32 1)
+; CHECK-NEXT:    ret void
+;
+  call void @llvm.memcpy.element.unordered.atomic.p0i8.p0i8.i32(i8* align 1 %dest, i8* align 1 %src, i32 1, i32 1)
+  call void @llvm.memcpy.element.unordered.atomic.p0i8.p0i8.i32(i8* align 1 %dest, i8* align 1 %src, i32 2, i32 1)
+  call void @llvm.memcpy.element.unordered.atomic.p0i8.p0i8.i32(i8* align 1 %dest, i8* align 1 %src, i32 4, i32 1)
+  call void @llvm.memcpy.element.unordered.atomic.p0i8.p0i8.i32(i8* align 1 %dest, i8* align 1 %src, i32 8, i32 1)
+  call void @llvm.memcpy.element.unordered.atomic.p0i8.p0i8.i32(i8* align 1 %dest, i8* align 1 %src, i32 16, i32 1)
+  ret void
+}
+
+define void @test_memcpy_loadstore_2(i8* %dest, i8* %src) {
+; CHECK-LABEL: @test_memcpy_loadstore_2(
+; CHECK-NEXT:    [[TMP1:%.*]] = load atomic i8, i8* [[SRC:%.*]] unordered, align 2
+; CHECK-NEXT:    store atomic i8 [[TMP1]], i8* [[DEST:%.*]] unordered, align 2
+; CHECK-NEXT:    [[TMP2:%.*]] = bitcast i8* [[SRC]] to i16*
+; CHECK-NEXT:    [[TMP3:%.*]] = bitcast i8* [[DEST]] to i16*
+; CHECK-NEXT:    [[TMP4:%.*]] = load atomic i16, i16* [[TMP2]] unordered, align 2
+; CHECK-NEXT:    store atomic i16 [[TMP4]], i16* [[TMP3]] unordered, align 2
+; CHECK-NEXT:    call void @llvm.memcpy.element.unordered.atomic.p0i8.p0i8.i32(i8* align 2 [[DEST]], i8* align 2 [[SRC]], i32 4, i32 2)
+; CHECK-NEXT:    call void @llvm.memcpy.element.unordered.atomic.p0i8.p0i8.i32(i8* align 2 [[DEST]], i8* align 2 [[SRC]], i32 8, i32 2)
+; CHECK-NEXT:    call void @llvm.memcpy.element.unordered.atomic.p0i8.p0i8.i32(i8* align 2 [[DEST]], i8* align 2 [[SRC]], i32 16, i32 2)
+; CHECK-NEXT:    ret void
+;
+  call void @llvm.memcpy.element.unordered.atomic.p0i8.p0i8.i32(i8* align 2 %dest, i8* align 2 %src, i32 1, i32 1)
+  call void @llvm.memcpy.element.unordered.atomic.p0i8.p0i8.i32(i8* align 2 %dest, i8* align 2 %src, i32 2, i32 2)
+  call void @llvm.memcpy.element.unordered.atomic.p0i8.p0i8.i32(i8* align 2 %dest, i8* align 2 %src, i32 4, i32 2)
+  call void @llvm.memcpy.element.unordered.atomic.p0i8.p0i8.i32(i8* align 2 %dest, i8* align 2 %src, i32 8, i32 2)
+  call void @llvm.memcpy.element.unordered.atomic.p0i8.p0i8.i32(i8* align 2 %dest, i8* align 2 %src, i32 16, i32 2)
+  ret void
+}
+
+define void @test_memcpy_loadstore_4(i8* %dest, i8* %src) {
+; CHECK-LABEL: @test_memcpy_loadstore_4(
+; CHECK-NEXT:    [[TMP1:%.*]] = load atomic i8, i8* [[SRC:%.*]] unordered, align 4
+; CHECK-NEXT:    store atomic i8 [[TMP1]], i8* [[DEST:%.*]] unordered, align 4
+; CHECK-NEXT:    [[TMP2:%.*]] = bitcast i8* [[SRC]] to i16*
+; CHECK-NEXT:    [[TMP3:%.*]] = bitcast i8* [[DEST]] to i16*
+; CHECK-NEXT:    [[TMP4:%.*]] = load atomic i16, i16* [[TMP2]] unordered, align 4
+; CHECK-NEXT:    store atomic i16 [[TMP4]], i16* [[TMP3]] unordered, align 4
+; CHECK-NEXT:    [[TMP5:%.*]] = bitcast i8* [[SRC]] to i32*
+; CHECK-NEXT:    [[TMP6:%.*]] = bitcast i8* [[DEST]] to i32*
+; CHECK-NEXT:    [[TMP7:%.*]] = load atomic i32, i32* [[TMP5]] unordered, align 4
+; CHECK-NEXT:    store atomic i32 [[TMP7]], i32* [[TMP6]] unordered, align 4
+; CHECK-NEXT:    call void @llvm.memcpy.element.unordered.atomic.p0i8.p0i8.i32(i8* align 4 [[DEST]], i8* align 4 [[SRC]], i32 8, i32 4)
+; CHECK-NEXT:    call void @llvm.memcpy.element.unordered.atomic.p0i8.p0i8.i32(i8* align 4 [[DEST]], i8* align 4 [[SRC]], i32 16, i32 4)
+; CHECK-NEXT:    ret void
+;
+  call void @llvm.memcpy.element.unordered.atomic.p0i8.p0i8.i32(i8* align 4 %dest, i8* align 4 %src, i32 1, i32 1)
+  call void @llvm.memcpy.element.unordered.atomic.p0i8.p0i8.i32(i8* align 4 %dest, i8* align 4 %src, i32 2, i32 2)
+  call void @llvm.memcpy.element.unordered.atomic.p0i8.p0i8.i32(i8* align 4 %dest, i8* align 4 %src, i32 4, i32 4)
+  call void @llvm.memcpy.element.unordered.atomic.p0i8.p0i8.i32(i8* align 4 %dest, i8* align 4 %src, i32 8, i32 4)
+  call void @llvm.memcpy.element.unordered.atomic.p0i8.p0i8.i32(i8* align 4 %dest, i8* align 4 %src, i32 16, i32 4)
+  ret void
+}
+
+define void @test_memcpy_loadstore_8(i8* %dest, i8* %src) {
+; CHECK-LABEL: @test_memcpy_loadstore_8(
+; CHECK-NEXT:    [[TMP1:%.*]] = load atomic i8, i8* [[SRC:%.*]] unordered, align 8
+; CHECK-NEXT:    store atomic i8 [[TMP1]], i8* [[DEST:%.*]] unordered, align 8
+; CHECK-NEXT:    [[TMP2:%.*]] = bitcast i8* [[SRC]] to i16*
+; CHECK-NEXT:    [[TMP3:%.*]] = bitcast i8* [[DEST]] to i16*
+; CHECK-NEXT:    [[TMP4:%.*]] = load atomic i16, i16* [[TMP2]] unordered, align 8
+; CHECK-NEXT:    store atomic i16 [[TMP4]], i16* [[TMP3]] unordered, align 8
+; CHECK-NEXT:    [[TMP5:%.*]] = bitcast i8* [[SRC]] to i32*
+; CHECK-NEXT:    [[TMP6:%.*]] = bitcast i8* [[DEST]] to i32*
+; CHECK-NEXT:    [[TMP7:%.*]] = load atomic i32, i32* [[TMP5]] unordered, align 8
+; CHECK-NEXT:    store atomic i32 [[TMP7]], i32* [[TMP6]] unordered, align 8
+; CHECK-NEXT:    [[TMP8:%.*]] = bitcast i8* [[SRC]] to i64*
+; CHECK-NEXT:    [[TMP9:%.*]] = bitcast i8* [[DEST]] to i64*
+; CHECK-NEXT:    [[TMP10:%.*]] = load atomic i64, i64* [[TMP8]] unordered, align 8
+; CHECK-NEXT:    store atomic i64 [[TMP10]], i64* [[TMP9]] unordered, align 8
+; CHECK-NEXT:    call void @llvm.memcpy.element.unordered.atomic.p0i8.p0i8.i32(i8* align 8 [[DEST]], i8* align 8 [[SRC]], i32 16, i32 8)
+; CHECK-NEXT:    ret void
+;
+  call void @llvm.memcpy.element.unordered.atomic.p0i8.p0i8.i32(i8* align 8 %dest, i8* align 8 %src, i32 1, i32 1)
+  call void @llvm.memcpy.element.unordered.atomic.p0i8.p0i8.i32(i8* align 8 %dest, i8* align 8 %src, i32 2, i32 2)
+  call void @llvm.memcpy.element.unordered.atomic.p0i8.p0i8.i32(i8* align 8 %dest, i8* align 8 %src, i32 4, i32 4)
+  call void @llvm.memcpy.element.unordered.atomic.p0i8.p0i8.i32(i8* align 8 %dest, i8* align 8 %src, i32 8, i32 8)
+  call void @llvm.memcpy.element.unordered.atomic.p0i8.p0i8.i32(i8* align 8 %dest, i8* align 8 %src, i32 16, i32 8)
+  ret void
+}
+
+define void @test_memcpy_loadstore_16(i8* %dest, i8* %src) {
+; CHECK-LABEL: @test_memcpy_loadstore_16(
+; CHECK-NEXT:    [[TMP1:%.*]] = load atomic i8, i8* [[SRC:%.*]] unordered, align 16
+; CHECK-NEXT:    store atomic i8 [[TMP1]], i8* [[DEST:%.*]] unordered, align 16
+; CHECK-NEXT:    [[TMP2:%.*]] = bitcast i8* [[SRC]] to i16*
+; CHECK-NEXT:    [[TMP3:%.*]] = bitcast i8* [[DEST]] to i16*
+; CHECK-NEXT:    [[TMP4:%.*]] = load atomic i16, i16* [[TMP2]] unordered, align 16
+; CHECK-NEXT:    store atomic i16 [[TMP4]], i16* [[TMP3]] unordered, align 16
+; CHECK-NEXT:    [[TMP5:%.*]] = bitcast i8* [[SRC]] to i32*
+; CHECK-NEXT:    [[TMP6:%.*]] = bitcast i8* [[DEST]] to i32*
+; CHECK-NEXT:    [[TMP7:%.*]] = load atomic i32, i32* [[TMP5]] unordered, align 16
+; CHECK-NEXT:    store atomic i32 [[TMP7]], i32* [[TMP6]] unordered, align 16
+; CHECK-NEXT:    [[TMP8:%.*]] = bitcast i8* [[SRC]] to i64*
+; CHECK-NEXT:    [[TMP9:%.*]] = bitcast i8* [[DEST]] to i64*
+; CHECK-NEXT:    [[TMP10:%.*]] = load atomic i64, i64* [[TMP8]] unordered, align 16
+; CHECK-NEXT:    store atomic i64 [[TMP10]], i64* [[TMP9]] unordered, align 16
+; CHECK-NEXT:    call void @llvm.memcpy.element.unordered.atomic.p0i8.p0i8.i32(i8* align 16 [[DEST:%.*]], i8* align 16 [[SRC:%.*]], i32 16, i32 16)
+; CHECK-NEXT:    ret void
+;
+  call void @llvm.memcpy.element.unordered.atomic.p0i8.p0i8.i32(i8* align 16 %dest, i8* align 16 %src, i32 1, i32 1)
+  call void @llvm.memcpy.element.unordered.atomic.p0i8.p0i8.i32(i8* align 16 %dest, i8* align 16 %src, i32 2, i32 2)
+  call void @llvm.memcpy.element.unordered.atomic.p0i8.p0i8.i32(i8* align 16 %dest, i8* align 16 %src, i32 4, i32 4)
+  call void @llvm.memcpy.element.unordered.atomic.p0i8.p0i8.i32(i8* align 16 %dest, i8* align 16 %src, i32 8, i32 8)
+  call void @llvm.memcpy.element.unordered.atomic.p0i8.p0i8.i32(i8* align 16 %dest, i8* align 16 %src, i32 16, i32 16)
+  ret void
+}
+
+declare void @llvm.memcpy.element.unordered.atomic.p0i8.p0i8.i32(i8* nocapture writeonly, i8* nocapture readonly, i32, i32) nounwind argmemonly

Added: llvm/trunk/test/Transforms/InstCombine/enforce-known-alignment.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/enforce-known-alignment.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/enforce-known-alignment.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/enforce-known-alignment.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,38 @@
+; RUN: opt  -instcombine -S %s | FileCheck %s
+
+target datalayout = "e-p:32:32:32-p1:16:16:16-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.6"
+
+define void @foo(i32) {
+; CHECK-LABEL: @foo(
+; CHECK: alloca
+; CHECK: align 16
+	%2 = alloca [3 x <{ { { [2 x { { i32 } }], [2 x i8], { i16 }, [2 x i8], i8, i8 } } }>], align 16		; <[3 x <{ { { [2 x { { i32 } }], [2 x i8], { i16 }, [2 x i8], i8, i8 } } }>]*> [#uses=1]
+	%3 = getelementptr [3 x <{ { { [2 x { { i32 } }], [2 x i8], { i16 }, [2 x i8], i8, i8 } } }>], [3 x <{ { { [2 x { { i32 } }], [2 x i8], { i16 }, [2 x i8], i8, i8 } } }>]* %2, i32 0, i32 0		; <<{ { { [2 x { { i32 } }], [2 x i8], { i16 }, [2 x i8], i8, i8 } } }>*> [#uses=1]
+	%4 = getelementptr <{ { { [2 x { { i32 } }], [2 x i8], { i16 }, [2 x i8], i8, i8 } } }>, <{ { { [2 x { { i32 } }], [2 x i8], { i16 }, [2 x i8], i8, i8 } } }>* %3, i32 0, i32 0		; <{ { [2 x { { i32 } }], [2 x i8], { i16 }, [2 x i8], i8, i8 } }*> [#uses=1]
+	%5 = getelementptr { { [2 x { { i32 } }], [2 x i8], { i16 }, [2 x i8], i8, i8 } }, { { [2 x { { i32 } }], [2 x i8], { i16 }, [2 x i8], i8, i8 } }* %4, i32 0, i32 0		; <{ [2 x { { i32 } }], [2 x i8], { i16 }, [2 x i8], i8, i8 }*> [#uses=1]
+	%6 = bitcast { [2 x { { i32 } }], [2 x i8], { i16 }, [2 x i8], i8, i8 }* %5 to { [8 x i16] }*		; <{ [8 x i16] }*> [#uses=1]
+	%7 = getelementptr { [8 x i16] }, { [8 x i16] }* %6, i32 0, i32 0		; <[8 x i16]*> [#uses=1]
+	%8 = getelementptr [8 x i16], [8 x i16]* %7, i32 0, i32 0		; <i16*> [#uses=1]
+	store i16 0, i16* %8, align 16
+    call void @bar(i16* %8)
+	ret void
+}
+
+declare void @bar(i16*)
+
+define void @foo_as1(i32 %a, [3 x <{ { { [2 x { { i32 } }], [2 x i8], { i16 }, [2 x i8], i8, i8 } } }>] addrspace(1)* %b) {
+; CHECK-LABEL: @foo_as1(
+; CHECK: align 16
+  %1 = getelementptr [3 x <{ { { [2 x { { i32 } }], [2 x i8], { i16 }, [2 x i8], i8, i8 } } }>], [3 x <{ { { [2 x { { i32 } }], [2 x i8], { i16 }, [2 x i8], i8, i8 } } }>] addrspace(1)* %b, i32 0, i32 0        ; <<{ { { [2 x { { i32 } }], [2 x i8], { i16 }, [2 x i8], i8, i8 } } }>*> [#uses=1]
+  %2 = getelementptr <{ { { [2 x { { i32 } }], [2 x i8], { i16 }, [2 x i8], i8, i8 } } }>, <{ { { [2 x { { i32 } }], [2 x i8], { i16 }, [2 x i8], i8, i8 } } }> addrspace(1)* %1, i32 0, i32 0      ; <{ { [2 x { { i32 } }], [2 x i8], { i16 }, [2 x i8], i8, i8 } }*> [#uses=1]
+  %3 = getelementptr { { [2 x { { i32 } }], [2 x i8], { i16 }, [2 x i8], i8, i8 } }, { { [2 x { { i32 } }], [2 x i8], { i16 }, [2 x i8], i8, i8 } } addrspace(1)* %2, i32 0, i32 0        ; <{ [2 x { { i32 } }], [2 x i8], { i16 }, [2 x i8], i8, i8 }*> [#uses=1]
+  %4 = bitcast { [2 x { { i32 } }], [2 x i8], { i16 }, [2 x i8], i8, i8 } addrspace(1)* %3 to { [8 x i16] } addrspace(1)*     ; <{ [8 x i16] }*> [#uses=1]
+  %5 = getelementptr { [8 x i16] }, { [8 x i16] } addrspace(1)* %4, i32 0, i32 0     ; <[8 x i16]*> [#uses=1]
+  %6 = getelementptr [8 x i16], [8 x i16] addrspace(1)* %5, i32 0, i32 0     ; <i16*> [#uses=1]
+  store i16 0, i16 addrspace(1)* %6, align 16
+  call void @bar_as1(i16 addrspace(1)* %6)
+  ret void
+}
+
+declare void @bar_as1(i16 addrspace(1)*)

Added: llvm/trunk/test/Transforms/InstCombine/err-rep-cold.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/err-rep-cold.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/err-rep-cold.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/err-rep-cold.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,77 @@
+; Test the static branch probability heuristics for error-reporting functions.
+; RUN: opt < %s -instcombine -S | FileCheck -enable-var-scope %s
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+%struct._IO_FILE = type { i32, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i8*, %struct._IO_marker*, %struct._IO_FILE*, i32, i32, i64, i16, i8, [1 x i8], i8*, i64, i8*, i8*, i8*, i8*, i64, i32, [20 x i8] }
+%struct._IO_marker = type { %struct._IO_marker*, %struct._IO_FILE*, i32 }
+
+ at stdout = external global %struct._IO_FILE*
+ at stderr = external global %struct._IO_FILE*
+ at .str = private unnamed_addr constant [13 x i8] c"an error: %d\00", align 1
+ at .str1 = private unnamed_addr constant [9 x i8] c"an error\00", align 1
+
+define i32 @test1(i32 %a) #0 {
+; CHECK-LABEL: @test1
+entry:
+  %cmp = icmp sgt i32 %a, 8
+  br i1 %cmp, label %if.then, label %return
+
+if.then:                                          ; preds = %entry
+  %0 = load %struct._IO_FILE*, %struct._IO_FILE** @stderr, align 8
+  %call = tail call i32 (%struct._IO_FILE*, i8*, ...) @fprintf(%struct._IO_FILE* %0, i8* getelementptr inbounds ([13 x i8], [13 x i8]* @.str, i64 0, i64 0), i32 %a) #1
+  br label %return
+
+; CHECK: %call = tail call i32 (%struct._IO_FILE*, i8*, ...) @fprintf(%struct._IO_FILE* %0, i8* getelementptr inbounds ([13 x i8], [13 x i8]* @.str, i64 0, i64 0), i32 %a) #[[$AT1:[0-9]+]]
+
+return:                                           ; preds = %entry, %if.then
+  %retval.0 = phi i32 [ 1, %if.then ], [ 0, %entry ]
+  ret i32 %retval.0
+}
+
+declare i32 @fprintf(%struct._IO_FILE* nocapture, i8* nocapture readonly, ...) #1
+
+define i32 @test2(i32 %a) #0 {
+; CHECK-LABEL: @test2
+entry:
+  %cmp = icmp sgt i32 %a, 8
+  br i1 %cmp, label %if.then, label %return
+
+if.then:                                          ; preds = %entry
+  %0 = load %struct._IO_FILE*, %struct._IO_FILE** @stderr, align 8
+  %1 = tail call i64 @fwrite(i8* getelementptr inbounds ([9 x i8], [9 x i8]* @.str1, i64 0, i64 0), i64 8, i64 1, %struct._IO_FILE* %0)
+  br label %return
+
+; CHECK: tail call i64 @fwrite(i8* getelementptr inbounds ([9 x i8], [9 x i8]* @.str1, i64 0, i64 0), i64 8, i64 1, %struct._IO_FILE* %0) #[[$AT2:[0-9]+]]
+
+return:                                           ; preds = %entry, %if.then
+  %retval.0 = phi i32 [ 1, %if.then ], [ 0, %entry ]
+  ret i32 %retval.0
+}
+
+declare i64 @fwrite(i8* nocapture, i64, i64, %struct._IO_FILE* nocapture) #1
+
+define i32 @test3(i32 %a) #0 {
+; CHECK-LABEL: @test3
+entry:
+  %cmp = icmp sgt i32 %a, 8
+  br i1 %cmp, label %if.then, label %return
+
+if.then:                                          ; preds = %entry
+  %0 = load %struct._IO_FILE*, %struct._IO_FILE** @stdout, align 8
+  %1 = tail call i64 @fwrite(i8* getelementptr inbounds ([9 x i8], [9 x i8]* @.str1, i64 0, i64 0), i64 8, i64 1, %struct._IO_FILE* %0)
+  br label %return
+
+; CHECK-NOT: tail call i64 @fwrite(i8* getelementptr inbounds ([9 x i8], [9 x i8]* @.str1, i64 0, i64 0), i64 8, i64 1, %struct._IO_FILE* %0) #[[$AT2]]
+
+return:                                           ; preds = %entry, %if.then
+  %retval.0 = phi i32 [ 1, %if.then ], [ 0, %entry ]
+  ret i32 %retval.0
+}
+
+attributes #0 = { nounwind uwtable }
+attributes #1 = { nounwind }
+
+; CHECK: attributes #[[$AT1]] = { cold nounwind }
+; CHECK: attributes #[[$AT2]] = { cold }
+

Added: llvm/trunk/test/Transforms/InstCombine/exact.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/exact.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/exact.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/exact.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,336 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt < %s -instcombine -S | FileCheck %s
+
+define i32 @sdiv1(i32 %x) {
+; CHECK-LABEL: @sdiv1(
+; CHECK-NEXT:    [[Y:%.*]] = sdiv i32 %x, 8
+; CHECK-NEXT:    ret i32 [[Y]]
+;
+  %y = sdiv i32 %x, 8
+  ret i32 %y
+}
+
+define i32 @sdiv2(i32 %x) {
+; CHECK-LABEL: @sdiv2(
+; CHECK-NEXT:    [[Y:%.*]] = ashr exact i32 %x, 3
+; CHECK-NEXT:    ret i32 [[Y]]
+;
+  %y = sdiv exact i32 %x, 8
+  ret i32 %y
+}
+
+define <2 x i32> @sdiv2_vec(<2 x i32> %x) {
+; CHECK-LABEL: @sdiv2_vec(
+; CHECK-NEXT:    [[Y:%.*]] = ashr exact <2 x i32> %x, <i32 7, i32 7>
+; CHECK-NEXT:    ret <2 x i32> [[Y]]
+;
+  %y = sdiv exact <2 x i32> %x, <i32 128, i32 128>
+  ret <2 x i32> %y
+}
+
+define i32 @sdiv3(i32 %x) {
+; CHECK-LABEL: @sdiv3(
+; CHECK-NEXT:    [[Y:%.*]] = srem i32 %x, 3
+; CHECK-NEXT:    [[Z:%.*]] = sub i32 %x, [[Y]]
+; CHECK-NEXT:    ret i32 [[Z]]
+;
+  %y = sdiv i32 %x, 3
+  %z = mul i32 %y, 3
+  ret i32 %z
+}
+
+define i32 @sdiv4(i32 %x) {
+; CHECK-LABEL: @sdiv4(
+; CHECK-NEXT:    ret i32 %x
+;
+  %y = sdiv exact i32 %x, 3
+  %z = mul i32 %y, 3
+  ret i32 %z
+}
+
+define i32 @sdiv5(i32 %x) {
+; CHECK-LABEL: @sdiv5(
+; CHECK-NEXT:    [[Y:%.*]] = srem i32 %x, 3
+; CHECK-NEXT:    [[Z:%.*]] = sub i32 [[Y]], %x
+; CHECK-NEXT:    ret i32 [[Z]]
+;
+  %y = sdiv i32 %x, 3
+  %z = mul i32 %y, -3
+  ret i32 %z
+}
+
+define i32 @sdiv6(i32 %x) {
+; CHECK-LABEL: @sdiv6(
+; CHECK-NEXT:    [[Z:%.*]] = sub i32 0, %x
+; CHECK-NEXT:    ret i32 [[Z]]
+;
+  %y = sdiv exact i32 %x, 3
+  %z = mul i32 %y, -3
+  ret i32 %z
+}
+
+define i32 @udiv1(i32 %x, i32 %w) {
+; CHECK-LABEL: @udiv1(
+; CHECK-NEXT:    ret i32 %x
+;
+  %y = udiv exact i32 %x, %w
+  %z = mul i32 %y, %w
+  ret i32 %z
+}
+
+define i32 @udiv2(i32 %x, i32 %w) {
+; CHECK-LABEL: @udiv2(
+; CHECK-NEXT:    [[Z:%.*]] = lshr exact i32 %x, %w
+; CHECK-NEXT:    ret i32 [[Z]]
+;
+  %y = shl i32 1, %w
+  %z = udiv exact i32 %x, %y
+  ret i32 %z
+}
+
+define i64 @ashr1(i64 %X) {
+; CHECK-LABEL: @ashr1(
+; CHECK-NEXT:    [[A:%.*]] = shl i64 %X, 8
+; CHECK-NEXT:    [[B:%.*]] = ashr exact i64 [[A]], 2
+; CHECK-NEXT:    ret i64 [[B]]
+;
+  %A = shl i64 %X, 8
+  %B = ashr i64 %A, 2
+  ret i64 %B
+}
+
+; The vector ashr should be exact (like it is in the preceding test).
+
+define <2 x i64> @ashr1_vec(<2 x i64> %X) {
+; CHECK-LABEL: @ashr1_vec(
+; CHECK-NEXT:    [[A:%.*]] = shl <2 x i64> %X, <i64 8, i64 8>
+; CHECK-NEXT:    [[B:%.*]] = ashr exact <2 x i64> [[A]], <i64 2, i64 2>
+; CHECK-NEXT:    ret <2 x i64> [[B]]
+;
+  %A = shl <2 x i64> %X, <i64 8, i64 8>
+  %B = ashr <2 x i64> %A, <i64 2, i64 2>
+  ret <2 x i64> %B
+}
+
+; PR9120
+define i1 @ashr_icmp1(i64 %X) {
+; CHECK-LABEL: @ashr_icmp1(
+; CHECK-NEXT:    [[B:%.*]] = icmp eq i64 %X, 0
+; CHECK-NEXT:    ret i1 [[B]]
+;
+  %A = ashr exact i64 %X, 2   ; X/4
+  %B = icmp eq i64 %A, 0
+  ret i1 %B
+}
+
+define i1 @ashr_icmp2(i64 %X) {
+; CHECK-LABEL: @ashr_icmp2(
+; CHECK-NEXT:    [[Z:%.*]] = icmp slt i64 %X, 16
+; CHECK-NEXT:    ret i1 [[Z]]
+;
+  %Y = ashr exact i64 %X, 2  ; x / 4
+  %Z = icmp slt i64 %Y, 4    ; x < 16
+  ret i1 %Z
+}
+
+define <2 x i1> @ashr_icmp2_vec(<2 x i64> %X) {
+; CHECK-LABEL: @ashr_icmp2_vec(
+; CHECK-NEXT:    [[Z:%.*]] = icmp slt <2 x i64> %X, <i64 16, i64 16>
+; CHECK-NEXT:    ret <2 x i1> [[Z]]
+;
+  %Y = ashr exact <2 x i64> %X, <i64 2, i64 2>
+  %Z = icmp slt <2 x i64> %Y, <i64 4, i64 4>
+  ret <2 x i1> %Z
+}
+
+; PR9998
+; Make sure we don't transform the ashr here into an sdiv
+define i1 @pr9998(i32 %V) {
+; CHECK-LABEL: @pr9998(
+; CHECK-NEXT:    [[W_MASK:%.*]] = and i32 %V, 1
+; CHECK-NEXT:    [[Z:%.*]] = icmp ne i32 [[W_MASK]], 0
+; CHECK-NEXT:    ret i1 [[Z]]
+;
+  %W = shl i32 %V, 31
+  %X = ashr exact i32 %W, 31
+  %Y = sext i32 %X to i64
+  %Z = icmp ugt i64 %Y, 7297771788697658747
+  ret i1 %Z
+}
+
+; FIXME: Vectors should fold the same way.
+define <2 x i1> @pr9998vec(<2 x i32> %V) {
+; CHECK-LABEL: @pr9998vec(
+; CHECK-NEXT:    [[W:%.*]] = shl <2 x i32> %V, <i32 31, i32 31>
+; CHECK-NEXT:    [[X:%.*]] = ashr exact <2 x i32> [[W]], <i32 31, i32 31>
+; CHECK-NEXT:    [[Y:%.*]] = sext <2 x i32> [[X]] to <2 x i64>
+; CHECK-NEXT:    [[Z:%.*]] = icmp ugt <2 x i64> [[Y]], <i64 7297771788697658747, i64 7297771788697658747>
+; CHECK-NEXT:    ret <2 x i1> [[Z]]
+;
+  %W = shl <2 x i32> %V, <i32 31, i32 31>
+  %X = ashr exact <2 x i32> %W, <i32 31, i32 31>
+  %Y = sext <2 x i32> %X to <2 x i64>
+  %Z = icmp ugt <2 x i64> %Y, <i64 7297771788697658747, i64 7297771788697658747>
+  ret <2 x i1> %Z
+}
+
+define i1 @udiv_icmp1(i64 %X) {
+; CHECK-LABEL: @udiv_icmp1(
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp ne i64 %X, 0
+; CHECK-NEXT:    ret i1 [[TMP1]]
+;
+  %A = udiv exact i64 %X, 5   ; X/5
+  %B = icmp ne i64 %A, 0
+  ret i1 %B
+}
+
+define <2 x i1> @udiv_icmp1_vec(<2 x i64> %X) {
+; CHECK-LABEL: @udiv_icmp1_vec(
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp ne <2 x i64> %X, zeroinitializer
+; CHECK-NEXT:    ret <2 x i1> [[TMP1]]
+;
+  %A = udiv exact <2 x i64> %X, <i64 5, i64 5>
+  %B = icmp ne <2 x i64> %A, zeroinitializer
+  ret <2 x i1> %B
+}
+
+define i1 @udiv_icmp2(i64 %X) {
+; CHECK-LABEL: @udiv_icmp2(
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp eq i64 %X, 0
+; CHECK-NEXT:    ret i1 [[TMP1]]
+;
+  %A = udiv exact i64 %X, 5   ; X/5 == 0 --> x == 0
+  %B = icmp eq i64 %A, 0
+  ret i1 %B
+}
+
+define <2 x i1> @udiv_icmp2_vec(<2 x i64> %X) {
+; CHECK-LABEL: @udiv_icmp2_vec(
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp eq <2 x i64> %X, zeroinitializer
+; CHECK-NEXT:    ret <2 x i1> [[TMP1]]
+;
+  %A = udiv exact <2 x i64> %X, <i64 5, i64 5>
+  %B = icmp eq <2 x i64> %A, zeroinitializer
+  ret <2 x i1> %B
+}
+
+define i1 @sdiv_icmp1(i64 %X) {
+; CHECK-LABEL: @sdiv_icmp1(
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp eq i64 %X, 0
+; CHECK-NEXT:    ret i1 [[TMP1]]
+;
+  %A = sdiv exact i64 %X, 5   ; X/5 == 0 --> x == 0
+  %B = icmp eq i64 %A, 0
+  ret i1 %B
+}
+
+define <2 x i1> @sdiv_icmp1_vec(<2 x i64> %X) {
+; CHECK-LABEL: @sdiv_icmp1_vec(
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp eq <2 x i64> %X, zeroinitializer
+; CHECK-NEXT:    ret <2 x i1> [[TMP1]]
+;
+  %A = sdiv exact <2 x i64> %X, <i64 5, i64 5>
+  %B = icmp eq <2 x i64> %A, zeroinitializer
+  ret <2 x i1> %B
+}
+
+define i1 @sdiv_icmp2(i64 %X) {
+; CHECK-LABEL: @sdiv_icmp2(
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp eq i64 %X, 5
+; CHECK-NEXT:    ret i1 [[TMP1]]
+;
+  %A = sdiv exact i64 %X, 5   ; X/5 == 1 --> x == 5
+  %B = icmp eq i64 %A, 1
+  ret i1 %B
+}
+
+define <2 x i1> @sdiv_icmp2_vec(<2 x i64> %X) {
+; CHECK-LABEL: @sdiv_icmp2_vec(
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp eq <2 x i64> %X, <i64 5, i64 5>
+; CHECK-NEXT:    ret <2 x i1> [[TMP1]]
+;
+  %A = sdiv exact <2 x i64> %X, <i64 5, i64 5>
+  %B = icmp eq <2 x i64> %A, <i64 1, i64 1>
+  ret <2 x i1> %B
+}
+
+define i1 @sdiv_icmp3(i64 %X) {
+; CHECK-LABEL: @sdiv_icmp3(
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp eq i64 %X, -5
+; CHECK-NEXT:    ret i1 [[TMP1]]
+;
+  %A = sdiv exact i64 %X, 5   ; X/5 == -1 --> x == -5
+  %B = icmp eq i64 %A, -1
+  ret i1 %B
+}
+
+define <2 x i1> @sdiv_icmp3_vec(<2 x i64> %X) {
+; CHECK-LABEL: @sdiv_icmp3_vec(
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp eq <2 x i64> %X, <i64 -5, i64 -5>
+; CHECK-NEXT:    ret <2 x i1> [[TMP1]]
+;
+  %A = sdiv exact <2 x i64> %X, <i64 5, i64 5>
+  %B = icmp eq <2 x i64> %A, <i64 -1, i64 -1>
+  ret <2 x i1> %B
+}
+
+define i1 @sdiv_icmp4(i64 %X) {
+; CHECK-LABEL: @sdiv_icmp4(
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp eq i64 %X, 0
+; CHECK-NEXT:    ret i1 [[TMP1]]
+;
+  %A = sdiv exact i64 %X, -5   ; X/-5 == 0 --> x == 0
+  %B = icmp eq i64 %A, 0
+  ret i1 %B
+}
+
+define <2 x i1> @sdiv_icmp4_vec(<2 x i64> %X) {
+; CHECK-LABEL: @sdiv_icmp4_vec(
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp eq <2 x i64> %X, zeroinitializer
+; CHECK-NEXT:    ret <2 x i1> [[TMP1]]
+;
+  %A = sdiv exact <2 x i64> %X, <i64 -5, i64 -5>
+  %B = icmp eq <2 x i64> %A, zeroinitializer
+  ret <2 x i1> %B
+}
+
+define i1 @sdiv_icmp5(i64 %X) {
+; CHECK-LABEL: @sdiv_icmp5(
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp eq i64 %X, -5
+; CHECK-NEXT:    ret i1 [[TMP1]]
+;
+  %A = sdiv exact i64 %X, -5   ; X/-5 == 1 --> x == -5
+  %B = icmp eq i64 %A, 1
+  ret i1 %B
+}
+
+define <2 x i1> @sdiv_icmp5_vec(<2 x i64> %X) {
+; CHECK-LABEL: @sdiv_icmp5_vec(
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp eq <2 x i64> %X, <i64 -5, i64 -5>
+; CHECK-NEXT:    ret <2 x i1> [[TMP1]]
+;
+  %A = sdiv exact <2 x i64> %X, <i64 -5, i64 -5>
+  %B = icmp eq <2 x i64> %A, <i64 1, i64 1>
+  ret <2 x i1> %B
+}
+
+define i1 @sdiv_icmp6(i64 %X) {
+; CHECK-LABEL: @sdiv_icmp6(
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp eq i64 %X, 5
+; CHECK-NEXT:    ret i1 [[TMP1]]
+;
+  %A = sdiv exact i64 %X, -5   ; X/-5 == -1 --> x == 5
+  %B = icmp eq i64 %A, -1
+  ret i1 %B
+}
+
+define <2 x i1> @sdiv_icmp6_vec(<2 x i64> %X) {
+; CHECK-LABEL: @sdiv_icmp6_vec(
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp eq <2 x i64> %X, <i64 5, i64 5>
+; CHECK-NEXT:    ret <2 x i1> [[TMP1]]
+;
+  %A = sdiv exact <2 x i64> %X, <i64 -5, i64 -5>
+  %B = icmp eq <2 x i64> %A, <i64 -1, i64 -1>
+  ret <2 x i1> %B
+}
+

Added: llvm/trunk/test/Transforms/InstCombine/exp2-1.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/exp2-1.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/exp2-1.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/exp2-1.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,99 @@
+; Test that the exp2 library call simplifier works correctly.
+;
+; RUN: opt < %s -instcombine -S | FileCheck %s -check-prefix=CHECK -check-prefix=INTRINSIC -check-prefix=LDEXP -check-prefix=LDEXPF
+; RUN: opt < %s -instcombine -S -mtriple=i386-pc-win32 | FileCheck %s -check-prefix=INTRINSIC -check-prefix=LDEXP -check-prefix=NOLDEXPF
+; RUN: opt < %s -instcombine -S -mtriple=amdgcn-unknown-unknown | FileCheck %s -check-prefix=INTRINSIC -check-prefix=NOLDEXP -check-prefix=NOLDEXPF
+
+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 double @exp2(double)
+declare float @exp2f(float)
+
+; Check exp2(sitofp(x)) -> ldexp(1.0, sext(x)).
+
+define double @test_simplify1(i32 %x) {
+; CHECK-LABEL: @test_simplify1(
+  %conv = sitofp i32 %x to double
+  %ret = call double @exp2(double %conv)
+; CHECK: call double @ldexp
+  ret double %ret
+}
+
+define double @test_simplify2(i16 signext %x) {
+; CHECK-LABEL: @test_simplify2(
+  %conv = sitofp i16 %x to double
+  %ret = call double @exp2(double %conv)
+; CHECK: call double @ldexp
+  ret double %ret
+}
+
+define double @test_simplify3(i8 signext %x) {
+; CHECK-LABEL: @test_simplify3(
+  %conv = sitofp i8 %x to double
+  %ret = call double @exp2(double %conv)
+; CHECK: call double @ldexp
+  ret double %ret
+}
+
+define float @test_simplify4(i32 %x) {
+; CHECK-LABEL: @test_simplify4(
+  %conv = sitofp i32 %x to float
+  %ret = call float @exp2f(float %conv)
+; CHECK: call float @ldexpf
+  ret float %ret
+}
+
+; Check exp2(uitofp(x)) -> ldexp(1.0, zext(x)).
+
+define double @test_no_simplify1(i32 %x) {
+; CHECK-LABEL: @test_no_simplify1(
+  %conv = uitofp i32 %x to double
+  %ret = call double @exp2(double %conv)
+; CHECK: call double @exp2
+  ret double %ret
+}
+
+define double @test_simplify6(i16 zeroext %x) {
+; CHECK-LABEL: @test_simplify6(
+  %conv = uitofp i16 %x to double
+  %ret = call double @exp2(double %conv)
+; CHECK: call double @ldexp
+  ret double %ret
+}
+
+define double @test_simplify7(i8 zeroext %x) {
+; CHECK-LABEL: @test_simplify7(
+  %conv = uitofp i8 %x to double
+  %ret = call double @exp2(double %conv)
+; CHECK: call double @ldexp
+  ret double %ret
+}
+
+define float @test_simplify8(i8 zeroext %x) {
+; CHECK-LABEL: @test_simplify8(
+  %conv = uitofp i8 %x to float
+  %ret = call float @exp2f(float %conv)
+; CHECK: call float @ldexpf
+  ret float %ret
+}
+
+declare double @llvm.exp2.f64(double)
+declare float @llvm.exp2.f32(float)
+
+define double @test_simplify9(i8 zeroext %x) {
+; INTRINSIC-LABEL: @test_simplify9(
+  %conv = uitofp i8 %x to double
+  %ret = call double @llvm.exp2.f64(double %conv)
+; LDEXP: call double @ldexp
+; NOLDEXP-NOT: call double @ldexp
+  ret double %ret
+}
+
+define float @test_simplify10(i8 zeroext %x) {
+; INTRINSIC-LABEL: @test_simplify10(
+  %conv = uitofp i8 %x to float
+  %ret = call float @llvm.exp2.f32(float %conv)
+; LDEXPF: call float @ldexpf
+; NOLDEXPF-NOT: call float @ldexpf
+  ret float %ret
+}

Added: llvm/trunk/test/Transforms/InstCombine/exp2-2.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/exp2-2.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/exp2-2.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/exp2-2.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,17 @@
+; Test that the exp2 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 float @exp2(double)
+
+; Check that exp2 functions with the wrong prototype aren't simplified.
+
+define float @test_no_simplify1(i32 %x) {
+; CHECK-LABEL: @test_no_simplify1(
+  %conv = sitofp i32 %x to double
+  %ret = call float @exp2(double %conv)
+; CHECK: call float @exp2(double %conv)
+  ret float %ret
+}

Added: llvm/trunk/test/Transforms/InstCombine/extractelement.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/extractelement.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/extractelement.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/extractelement.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,312 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt < %s -instcombine -S -data-layout="e" | FileCheck %s --check-prefixes=ANY,LE
+; RUN: opt < %s -instcombine -S -data-layout="E" | FileCheck %s --check-prefixes=ANY,BE
+
+define i32 @extractelement_out_of_range(<2 x i32> %x) {
+; ANY-LABEL: @extractelement_out_of_range(
+; ANY-NEXT:    ret i32 undef
+;
+  %E1 = extractelement <2 x i32> %x, i8 16
+  ret i32 %E1
+}
+
+define i32 @extractelement_type_out_of_range(<2 x i32> %x) {
+; ANY-LABEL: @extractelement_type_out_of_range(
+; ANY-NEXT:    [[E1:%.*]] = extractelement <2 x i32> [[X:%.*]], i128 0
+; ANY-NEXT:    ret i32 [[E1]]
+;
+  %E1 = extractelement <2 x i32> %x, i128 0
+  ret i32 %E1
+}
+
+define i32 @bitcasted_inselt_equal_num_elts(float %f) {
+; ANY-LABEL: @bitcasted_inselt_equal_num_elts(
+; ANY-NEXT:    [[R:%.*]] = bitcast float [[F:%.*]] to i32
+; ANY-NEXT:    ret i32 [[R]]
+;
+  %vf = insertelement <4 x float> undef, float %f, i32 0
+  %vi = bitcast <4 x float> %vf to <4 x i32>
+  %r = extractelement <4 x i32> %vi, i32 0
+  ret i32 %r
+}
+
+define i64 @test2(i64 %in) {
+; ANY-LABEL: @test2(
+; ANY-NEXT:    ret i64 [[IN:%.*]]
+;
+  %vec = insertelement <8 x i64> undef, i64 %in, i32 0
+  %splat = shufflevector <8 x i64> %vec, <8 x i64> undef, <8 x i32> zeroinitializer
+  %add = add <8 x i64> %splat, <i64 0, i64 1, i64 2, i64 3, i64 4, i64 5, i64 6, i64 7>
+  %r = extractelement <8 x i64> %add, i32 0
+  ret i64 %r
+}
+
+define i32 @bitcasted_inselt_wide_source_zero_elt(i64 %x) {
+; LE-LABEL: @bitcasted_inselt_wide_source_zero_elt(
+; LE-NEXT:    [[R:%.*]] = trunc i64 [[X:%.*]] to i32
+; LE-NEXT:    ret i32 [[R]]
+;
+; BE-LABEL: @bitcasted_inselt_wide_source_zero_elt(
+; BE-NEXT:    [[TMP1:%.*]] = lshr i64 [[X:%.*]], 32
+; BE-NEXT:    [[R:%.*]] = trunc i64 [[TMP1]] to i32
+; BE-NEXT:    ret i32 [[R]]
+;
+  %i = insertelement <2 x i64> zeroinitializer, i64 %x, i32 0
+  %b = bitcast <2 x i64> %i to <4 x i32>
+  %r = extractelement <4 x i32> %b, i32 0
+  ret i32 %r
+}
+
+define i16 @bitcasted_inselt_wide_source_modulo_elt(i64 %x) {
+; LE-LABEL: @bitcasted_inselt_wide_source_modulo_elt(
+; LE-NEXT:    [[R:%.*]] = trunc i64 [[X:%.*]] to i16
+; LE-NEXT:    ret i16 [[R]]
+;
+; BE-LABEL: @bitcasted_inselt_wide_source_modulo_elt(
+; BE-NEXT:    [[TMP1:%.*]] = lshr i64 [[X:%.*]], 48
+; BE-NEXT:    [[R:%.*]] = trunc i64 [[TMP1]] to i16
+; BE-NEXT:    ret i16 [[R]]
+;
+  %i = insertelement <2 x i64> undef, i64 %x, i32 1
+  %b = bitcast <2 x i64> %i to <8 x i16>
+  %r = extractelement <8 x i16> %b, i32 4
+  ret i16 %r
+}
+
+define i32 @bitcasted_inselt_wide_source_not_modulo_elt(i64 %x) {
+; LE-LABEL: @bitcasted_inselt_wide_source_not_modulo_elt(
+; LE-NEXT:    [[TMP1:%.*]] = lshr i64 [[X:%.*]], 32
+; LE-NEXT:    [[R:%.*]] = trunc i64 [[TMP1]] to i32
+; LE-NEXT:    ret i32 [[R]]
+;
+; BE-LABEL: @bitcasted_inselt_wide_source_not_modulo_elt(
+; BE-NEXT:    [[R:%.*]] = trunc i64 [[X:%.*]] to i32
+; BE-NEXT:    ret i32 [[R]]
+;
+  %i = insertelement <2 x i64> undef, i64 %x, i32 0
+  %b = bitcast <2 x i64> %i to <4 x i32>
+  %r = extractelement <4 x i32> %b, i32 1
+  ret i32 %r
+}
+
+define i8 @bitcasted_inselt_wide_source_not_modulo_elt_not_half(i32 %x) {
+; LE-LABEL: @bitcasted_inselt_wide_source_not_modulo_elt_not_half(
+; LE-NEXT:    [[TMP1:%.*]] = lshr i32 [[X:%.*]], 16
+; LE-NEXT:    [[R:%.*]] = trunc i32 [[TMP1]] to i8
+; LE-NEXT:    ret i8 [[R]]
+;
+; BE-LABEL: @bitcasted_inselt_wide_source_not_modulo_elt_not_half(
+; BE-NEXT:    [[TMP1:%.*]] = lshr i32 [[X:%.*]], 8
+; BE-NEXT:    [[R:%.*]] = trunc i32 [[TMP1]] to i8
+; BE-NEXT:    ret i8 [[R]]
+;
+  %i = insertelement <2 x i32> undef, i32 %x, i32 0
+  %b = bitcast <2 x i32> %i to <8 x i8>
+  %r = extractelement <8 x i8> %b, i32 2
+  ret i8 %r
+}
+
+define i3 @bitcasted_inselt_wide_source_not_modulo_elt_not_half_weird_types(i15 %x) {
+; LE-LABEL: @bitcasted_inselt_wide_source_not_modulo_elt_not_half_weird_types(
+; LE-NEXT:    [[TMP1:%.*]] = lshr i15 [[X:%.*]], 3
+; LE-NEXT:    [[R:%.*]] = trunc i15 [[TMP1]] to i3
+; LE-NEXT:    ret i3 [[R]]
+;
+; BE-LABEL: @bitcasted_inselt_wide_source_not_modulo_elt_not_half_weird_types(
+; BE-NEXT:    [[TMP1:%.*]] = lshr i15 [[X:%.*]], 9
+; BE-NEXT:    [[R:%.*]] = trunc i15 [[TMP1]] to i3
+; BE-NEXT:    ret i3 [[R]]
+;
+  %i = insertelement <3 x i15> undef, i15 %x, i32 0
+  %b = bitcast <3 x i15> %i to <15 x i3>
+  %r = extractelement <15 x i3> %b, i32 1
+  ret i3 %r
+}
+
+; Negative test for the above fold, but we can remove the insert here.
+
+define i8 @bitcasted_inselt_wide_source_wrong_insert(<2 x i32> %v, i32 %x) {
+; ANY-LABEL: @bitcasted_inselt_wide_source_wrong_insert(
+; ANY-NEXT:    [[B:%.*]] = bitcast <2 x i32> [[V:%.*]] to <8 x i8>
+; ANY-NEXT:    [[R:%.*]] = extractelement <8 x i8> [[B]], i32 2
+; ANY-NEXT:    ret i8 [[R]]
+;
+  %i = insertelement <2 x i32> %v, i32 %x, i32 1
+  %b = bitcast <2 x i32> %i to <8 x i8>
+  %r = extractelement <8 x i8> %b, i32 2
+  ret i8 %r
+}
+
+; Partial negative test for the above fold, extra uses are not allowed if shift is needed.
+
+declare void @use(<8 x i8>)
+
+define i8 @bitcasted_inselt_wide_source_uses(i32 %x) {
+; LE-LABEL: @bitcasted_inselt_wide_source_uses(
+; LE-NEXT:    [[I:%.*]] = insertelement <2 x i32> undef, i32 [[X:%.*]], i32 0
+; LE-NEXT:    [[B:%.*]] = bitcast <2 x i32> [[I]] to <8 x i8>
+; LE-NEXT:    call void @use(<8 x i8> [[B]])
+; LE-NEXT:    [[R:%.*]] = extractelement <8 x i8> [[B]], i32 3
+; LE-NEXT:    ret i8 [[R]]
+;
+; BE-LABEL: @bitcasted_inselt_wide_source_uses(
+; BE-NEXT:    [[I:%.*]] = insertelement <2 x i32> undef, i32 [[X:%.*]], i32 0
+; BE-NEXT:    [[B:%.*]] = bitcast <2 x i32> [[I]] to <8 x i8>
+; BE-NEXT:    call void @use(<8 x i8> [[B]])
+; BE-NEXT:    [[R:%.*]] = trunc i32 [[X]] to i8
+; BE-NEXT:    ret i8 [[R]]
+;
+  %i = insertelement <2 x i32> undef, i32 %x, i32 0
+  %b = bitcast <2 x i32> %i to <8 x i8>
+  call void @use(<8 x i8> %b)
+  %r = extractelement <8 x i8> %b, i32 3
+  ret i8 %r
+}
+
+define float @bitcasted_inselt_to_FP(i64 %x) {
+; LE-LABEL: @bitcasted_inselt_to_FP(
+; LE-NEXT:    [[TMP1:%.*]] = lshr i64 [[X:%.*]], 32
+; LE-NEXT:    [[TMP2:%.*]] = trunc i64 [[TMP1]] to i32
+; LE-NEXT:    [[R:%.*]] = bitcast i32 [[TMP2]] to float
+; LE-NEXT:    ret float [[R]]
+;
+; BE-LABEL: @bitcasted_inselt_to_FP(
+; BE-NEXT:    [[TMP1:%.*]] = trunc i64 [[X:%.*]] to i32
+; BE-NEXT:    [[R:%.*]] = bitcast i32 [[TMP1]] to float
+; BE-NEXT:    ret float [[R]]
+;
+  %i = insertelement <2 x i64> undef, i64 %x, i32 0
+  %b = bitcast <2 x i64> %i to <4 x float>
+  %r = extractelement <4 x float> %b, i32 1
+  ret float %r
+}
+
+declare void @use_v2i128(<2 x i128>)
+declare void @use_v8f32(<8 x float>)
+
+define float @bitcasted_inselt_to_FP_uses(i128 %x) {
+; ANY-LABEL: @bitcasted_inselt_to_FP_uses(
+; ANY-NEXT:    [[I:%.*]] = insertelement <2 x i128> undef, i128 [[X:%.*]], i32 0
+; ANY-NEXT:    call void @use_v2i128(<2 x i128> [[I]])
+; ANY-NEXT:    [[B:%.*]] = bitcast <2 x i128> [[I]] to <8 x float>
+; ANY-NEXT:    [[R:%.*]] = extractelement <8 x float> [[B]], i32 1
+; ANY-NEXT:    ret float [[R]]
+;
+  %i = insertelement <2 x i128> undef, i128 %x, i32 0
+  call void @use_v2i128(<2 x i128> %i)
+  %b = bitcast <2 x i128> %i to <8 x float>
+  %r = extractelement <8 x float> %b, i32 1
+  ret float %r
+}
+
+define float @bitcasted_inselt_to_FP_uses2(i128 %x) {
+; ANY-LABEL: @bitcasted_inselt_to_FP_uses2(
+; ANY-NEXT:    [[I:%.*]] = insertelement <2 x i128> undef, i128 [[X:%.*]], i32 0
+; ANY-NEXT:    [[B:%.*]] = bitcast <2 x i128> [[I]] to <8 x float>
+; ANY-NEXT:    call void @use_v8f32(<8 x float> [[B]])
+; ANY-NEXT:    [[R:%.*]] = extractelement <8 x float> [[B]], i32 1
+; ANY-NEXT:    ret float [[R]]
+;
+  %i = insertelement <2 x i128> undef, i128 %x, i32 0
+  %b = bitcast <2 x i128> %i to <8 x float>
+  call void @use_v8f32(<8 x float> %b)
+  %r = extractelement <8 x float> %b, i32 1
+  ret float %r
+}
+
+define i32 @bitcasted_inselt_from_FP(double %x) {
+; LE-LABEL: @bitcasted_inselt_from_FP(
+; LE-NEXT:    [[TMP1:%.*]] = bitcast double [[X:%.*]] to i64
+; LE-NEXT:    [[TMP2:%.*]] = lshr i64 [[TMP1]], 32
+; LE-NEXT:    [[R:%.*]] = trunc i64 [[TMP2]] to i32
+; LE-NEXT:    ret i32 [[R]]
+;
+; BE-LABEL: @bitcasted_inselt_from_FP(
+; BE-NEXT:    [[TMP1:%.*]] = bitcast double [[X:%.*]] to i64
+; BE-NEXT:    [[R:%.*]] = trunc i64 [[TMP1]] to i32
+; BE-NEXT:    ret i32 [[R]]
+;
+  %i = insertelement <2 x double> undef, double %x, i32 0
+  %b = bitcast <2 x double> %i to <4 x i32>
+  %r = extractelement <4 x i32> %b, i32 1
+  ret i32 %r
+}
+
+declare void @use_v2f64(<2 x double>)
+declare void @use_v8i16(<8 x i16>)
+
+define i16 @bitcasted_inselt_from_FP_uses(double %x) {
+; ANY-LABEL: @bitcasted_inselt_from_FP_uses(
+; ANY-NEXT:    [[I:%.*]] = insertelement <2 x double> undef, double [[X:%.*]], i32 0
+; ANY-NEXT:    call void @use_v2f64(<2 x double> [[I]])
+; ANY-NEXT:    [[B:%.*]] = bitcast <2 x double> [[I]] to <8 x i16>
+; ANY-NEXT:    [[R:%.*]] = extractelement <8 x i16> [[B]], i32 1
+; ANY-NEXT:    ret i16 [[R]]
+;
+  %i = insertelement <2 x double> undef, double %x, i32 0
+  call void @use_v2f64(<2 x double> %i)
+  %b = bitcast <2 x double> %i to <8 x i16>
+  %r = extractelement <8 x i16> %b, i32 1
+  ret i16 %r
+}
+
+define i16 @bitcasted_inselt_from_FP_uses2(double %x) {
+; ANY-LABEL: @bitcasted_inselt_from_FP_uses2(
+; ANY-NEXT:    [[I:%.*]] = insertelement <2 x double> undef, double [[X:%.*]], i32 0
+; ANY-NEXT:    [[B:%.*]] = bitcast <2 x double> [[I]] to <8 x i16>
+; ANY-NEXT:    call void @use_v8i16(<8 x i16> [[B]])
+; ANY-NEXT:    [[R:%.*]] = extractelement <8 x i16> [[B]], i32 1
+; ANY-NEXT:    ret i16 [[R]]
+;
+  %i = insertelement <2 x double> undef, double %x, i32 0
+  %b = bitcast <2 x double> %i to <8 x i16>
+  call void @use_v8i16(<8 x i16> %b)
+  %r = extractelement <8 x i16> %b, i32 1
+  ret i16 %r
+}
+
+define float @bitcasted_inselt_to_and_from_FP(double %x) {
+; ANY-LABEL: @bitcasted_inselt_to_and_from_FP(
+; ANY-NEXT:    [[I:%.*]] = insertelement <2 x double> undef, double [[X:%.*]], i32 0
+; ANY-NEXT:    [[B:%.*]] = bitcast <2 x double> [[I]] to <4 x float>
+; ANY-NEXT:    [[R:%.*]] = extractelement <4 x float> [[B]], i32 1
+; ANY-NEXT:    ret float [[R]]
+;
+  %i = insertelement <2 x double> undef, double %x, i32 0
+  %b = bitcast <2 x double> %i to <4 x float>
+  %r = extractelement <4 x float> %b, i32 1
+  ret float %r
+}
+
+define float @bitcasted_inselt_to_and_from_FP_uses(double %x) {
+; ANY-LABEL: @bitcasted_inselt_to_and_from_FP_uses(
+; ANY-NEXT:    [[I:%.*]] = insertelement <2 x double> undef, double [[X:%.*]], i32 0
+; ANY-NEXT:    call void @use_v2f64(<2 x double> [[I]])
+; ANY-NEXT:    [[B:%.*]] = bitcast <2 x double> [[I]] to <4 x float>
+; ANY-NEXT:    [[R:%.*]] = extractelement <4 x float> [[B]], i32 1
+; ANY-NEXT:    ret float [[R]]
+;
+  %i = insertelement <2 x double> undef, double %x, i32 0
+  call void @use_v2f64(<2 x double> %i)
+  %b = bitcast <2 x double> %i to <4 x float>
+  %r = extractelement <4 x float> %b, i32 1
+  ret float %r
+}
+
+declare void @use_v4f32(<4 x float>)
+
+define float @bitcasted_inselt_to_and_from_FP_uses2(double %x) {
+; ANY-LABEL: @bitcasted_inselt_to_and_from_FP_uses2(
+; ANY-NEXT:    [[I:%.*]] = insertelement <2 x double> undef, double [[X:%.*]], i32 0
+; ANY-NEXT:    [[B:%.*]] = bitcast <2 x double> [[I]] to <4 x float>
+; ANY-NEXT:    call void @use_v4f32(<4 x float> [[B]])
+; ANY-NEXT:    [[R:%.*]] = extractelement <4 x float> [[B]], i32 1
+; ANY-NEXT:    ret float [[R]]
+;
+  %i = insertelement <2 x double> undef, double %x, i32 0
+  %b = bitcast <2 x double> %i to <4 x float>
+  call void @use_v4f32(<4 x float> %b)
+  %r = extractelement <4 x float> %b, i32 1
+  ret float %r
+}
+

Added: llvm/trunk/test/Transforms/InstCombine/extractinsert-tbaa.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/extractinsert-tbaa.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/extractinsert-tbaa.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/extractinsert-tbaa.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,45 @@
+; RUN: opt -S -instcombine %s -o - | FileCheck %s
+
+%Complex = type { double, double }
+
+; Check that instcombine preserves TBAA when narrowing loads
+define double @teststructextract(%Complex *%val) {
+; CHECK: load double, {{.*}}, !tbaa
+; CHECK-NOT: load %Complex
+    %loaded = load %Complex, %Complex *%val, !tbaa !1
+    %real = extractvalue %Complex %loaded, 0
+    ret double %real
+}
+
+define double @testarrayextract([2 x double] *%val) {
+; CHECK: load double, {{.*}}, !tbaa
+; CHECK-NOT: load [2 x double]
+    %loaded = load [2 x double], [2 x double] *%val, !tbaa !1
+    %real = extractvalue [2 x double] %loaded, 0
+    ret double %real
+}
+
+; Check that inscombine preserves TBAA when breaking up stores
+define void @teststructinsert(%Complex *%loc, double %a, double %b) {
+; CHECK: store double %a, {{.*}}, !tbaa
+; CHECK: store double %b, {{.*}}, !tbaa
+; CHECK-NOT: store %Complex
+    %inserted  = insertvalue %Complex undef,      double %a, 0
+    %inserted2 = insertvalue %Complex %inserted,  double %b, 1
+    store %Complex %inserted2, %Complex *%loc, !tbaa !1
+    ret void
+}
+
+define void @testarrayinsert([2 x double] *%loc, double %a, double %b) {
+; CHECK: store double %a, {{.*}}, !tbaa
+; CHECK: store double %b, {{.*}}, !tbaa
+; CHECK-NOT: store [2 x double]
+    %inserted  = insertvalue [2 x double] undef,      double %a, 0
+    %inserted2 = insertvalue [2 x double] %inserted,  double %b, 1
+    store [2 x double] %inserted2, [2 x double] *%loc, !tbaa !1
+    ret void
+}
+
+!0 = !{!"tbaa_root"}
+!1 = !{!2, !2, i64 0}
+!2 = !{!"Complex", !0, i64 0}

Added: llvm/trunk/test/Transforms/InstCombine/extractvalue.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/extractvalue.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/extractvalue.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/extractvalue.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,107 @@
+; RUN: opt < %s -instcombine -S | FileCheck %s
+
+declare void @bar({i32, i32} %a)
+declare i32 @baz(i32 %a)
+
+; CHECK-LABEL: define i32 @foo(
+; CHECK-NOT: extractvalue
+define i32 @foo(i32 %a, i32 %b) {
+; Instcombine should fold various combinations of insertvalue and extractvalue
+; together
+        ; Build a simple struct and pull values out again
+        %s1.1 = insertvalue {i32, i32} undef, i32 %a, 0
+        %s1 = insertvalue {i32, i32} %s1.1, i32 %b, 1
+        %v1 = extractvalue {i32, i32} %s1, 0
+        %v2 = extractvalue {i32, i32} %s1, 1
+
+        ; Build a nested struct and pull a sub struct out of it
+        ; This requires instcombine to insert a few insertvalue instructions
+        %ns1.1 = insertvalue {i32, {i32, i32}} undef, i32 %v1, 0
+        %ns1.2 = insertvalue {i32, {i32, i32}} %ns1.1, i32 %v1, 1, 0
+        %ns1   = insertvalue {i32, {i32, i32}} %ns1.2, i32 %v2, 1, 1
+        %s2    = extractvalue {i32, {i32, i32}} %ns1, 1
+        %v3    = extractvalue {i32, {i32, i32}} %ns1, 1, 1
+        call void @bar({i32, i32} %s2)
+
+        ; Use nested extractvalues to get to a value
+        %s3    = extractvalue {i32, {i32, i32}} %ns1, 1
+        %v4    = extractvalue {i32, i32} %s3, 1
+        call void @bar({i32, i32} %s3)
+
+        ; Use nested insertvalues to build a nested struct
+        %s4.1 = insertvalue {i32, i32} undef, i32 %v3, 0
+        %s4   = insertvalue {i32, i32} %s4.1, i32 %v4, 1
+        %ns2  = insertvalue {i32, {i32, i32}} undef, {i32, i32} %s4, 1
+
+        ; And now extract a single value from there
+        %v5   = extractvalue {i32, {i32, i32}} %ns2, 1, 1
+
+        ret i32 %v5
+}
+
+; CHECK-LABEL: define i32 @extract2gep(
+; CHECK-NEXT: [[GEP:%[a-z0-9]+]] = getelementptr inbounds {{.*}}, {{.*}}* %pair, i64 0, i32 1
+; CHECK-NEXT: [[LOAD:%[A-Za-z0-9]+]] = load i32, i32* [[GEP]]
+; CHECK-NEXT: store
+; CHECK-NEXT: br label %loop
+; CHECK-NOT: extractvalue
+; CHECK: call {{.*}}(i32 [[LOAD]])
+; CHECK-NOT: extractvalue
+; CHECK: ret i32 [[LOAD]]
+define i32 @extract2gep({i16, i32}* %pair, i32* %P) {
+        ; The load + extractvalue should be converted
+        ; to an inbounds gep + smaller load.
+        ; The new load should be in the same spot as the old load.
+        %L = load {i16, i32}, {i16, i32}* %pair
+        store i32 0, i32* %P
+        br label %loop
+
+loop:
+        %E = extractvalue {i16, i32} %L, 1
+        %C = call i32 @baz(i32 %E)
+        store i32 %C, i32* %P
+        %cond = icmp eq i32 %C, 0
+        br i1 %cond, label %end, label %loop
+
+end:
+        ret i32 %E
+}
+
+; CHECK-LABEL: define i16 @doubleextract2gep(
+; CHECK-NEXT: [[GEP:%[a-z0-9]+]] = getelementptr inbounds {{.*}}, {{.*}}* %arg, i64 0, i32 1, i32 1
+; CHECK-NEXT: [[LOAD:%[A-Za-z0-9]+]] = load i16, i16* [[GEP]]
+; CHECK-NEXT: ret i16 [[LOAD]]
+define i16 @doubleextract2gep({i16, {i32, i16}}* %arg) {
+        ; The load + extractvalues should be converted
+        ; to a 3-index inbounds gep + smaller load.
+        %L = load {i16, {i32, i16}}, {i16, {i32, i16}}* %arg
+        %E1 = extractvalue {i16, {i32, i16}} %L, 1
+        %E2 = extractvalue {i32, i16} %E1, 1
+        ret i16 %E2
+}
+
+; CHECK: define i32 @nogep-multiuse
+; CHECK-NEXT: load {{.*}} %pair
+; CHECK-NEXT: extractvalue
+; CHECK-NEXT: extractvalue
+; CHECK-NEXT: add
+; CHECK-NEXT: ret
+define i32 @nogep-multiuse({i32, i32}* %pair) {
+        ; The load should be left unchanged since both parts are needed.
+        %L = load volatile {i32, i32}, {i32, i32}* %pair
+        %LHS = extractvalue {i32, i32} %L, 0
+        %RHS = extractvalue {i32, i32} %L, 1
+        %R = add i32 %LHS, %RHS
+        ret i32 %R
+}
+
+; CHECK: define i32 @nogep-volatile
+; CHECK-NEXT: load volatile {{.*}} %pair
+; CHECK-NEXT: extractvalue
+; CHECK-NEXT: ret
+define i32 @nogep-volatile({i32, i32}* %pair) {
+        ; The load volatile should be left unchanged.
+        %L = load volatile {i32, i32}, {i32, i32}* %pair
+        %E = extractvalue {i32, i32} %L, 1
+        ret i32 %E
+}

Added: llvm/trunk/test/Transforms/InstCombine/fabs-libcall.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/fabs-libcall.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/fabs-libcall.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/fabs-libcall.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,22 @@
+; RUN: opt -S -mtriple=i686-apple-macosx -instcombine %s | FileCheck %s
+
+declare x86_fp80 @fabsl(x86_fp80)
+
+define x86_fp80 @replace_fabs_call_f80(x86_fp80 %x) {
+; CHECK-LABEL: @replace_fabs_call_f80(
+; CHECK-NEXT:    [[TMP1:%.*]] = call x86_fp80 @llvm.fabs.f80(x86_fp80 %x)
+; CHECK-NEXT:    ret x86_fp80 [[TMP1]]
+;
+  %fabsl = tail call x86_fp80 @fabsl(x86_fp80 %x)
+  ret x86_fp80 %fabsl
+}
+
+define x86_fp80 @fmf_replace_fabs_call_f80(x86_fp80 %x) {
+; CHECK-LABEL: @fmf_replace_fabs_call_f80(
+; CHECK-NEXT:    [[TMP1:%.*]] = call nnan x86_fp80 @llvm.fabs.f80(x86_fp80 %x)
+; CHECK-NEXT:    ret x86_fp80 [[TMP1]]
+;
+  %fabsl = tail call nnan x86_fp80 @fabsl(x86_fp80 %x)
+  ret x86_fp80 %fabsl
+}
+

Added: llvm/trunk/test/Transforms/InstCombine/fabs.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/fabs.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/fabs.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/fabs.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,420 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt -mtriple=x86_64-unknown-linux-gnu < %s -instcombine -S | FileCheck %s
+
+; Make sure libcalls are replaced with intrinsic calls.
+
+declare float @llvm.fabs.f32(float)
+declare double @llvm.fabs.f64(double)
+declare fp128 @llvm.fabs.f128(fp128)
+
+declare float @fabsf(float)
+declare double @fabs(double)
+declare fp128 @fabsl(fp128)
+declare float @llvm.fma.f32(float, float, float)
+declare float @llvm.fmuladd.f32(float, float, float)
+
+define float @replace_fabs_call_f32(float %x) {
+; CHECK-LABEL: @replace_fabs_call_f32(
+; CHECK-NEXT:    [[FABSF:%.*]] = call float @llvm.fabs.f32(float [[X:%.*]])
+; CHECK-NEXT:    ret float [[FABSF]]
+;
+  %fabsf = tail call float @fabsf(float %x)
+  ret float %fabsf
+}
+
+define double @replace_fabs_call_f64(double %x) {
+; CHECK-LABEL: @replace_fabs_call_f64(
+; CHECK-NEXT:    [[FABS:%.*]] = call double @llvm.fabs.f64(double [[X:%.*]])
+; CHECK-NEXT:    ret double [[FABS]]
+;
+  %fabs = tail call double @fabs(double %x)
+  ret double %fabs
+}
+
+define fp128 @replace_fabs_call_f128(fp128 %x) {
+; CHECK-LABEL: @replace_fabs_call_f128(
+; CHECK-NEXT:    [[FABSL:%.*]] = call fp128 @llvm.fabs.f128(fp128 [[X:%.*]])
+; CHECK-NEXT:    ret fp128 [[FABSL]]
+;
+  %fabsl = tail call fp128 @fabsl(fp128 %x)
+  ret fp128 %fabsl
+}
+
+; Make sure fast math flags are preserved when replacing the libcall.
+define float @fmf_replace_fabs_call_f32(float %x) {
+; CHECK-LABEL: @fmf_replace_fabs_call_f32(
+; CHECK-NEXT:    [[FABSF:%.*]] = call nnan float @llvm.fabs.f32(float [[X:%.*]])
+; CHECK-NEXT:    ret float [[FABSF]]
+;
+  %fabsf = tail call nnan float @fabsf(float %x)
+  ret float %fabsf
+}
+
+; Make sure all intrinsic calls are eliminated when the input is known
+; positive.
+
+; The fabs cannot be eliminated because %x may be a NaN
+
+define float @square_fabs_intrinsic_f32(float %x) {
+; CHECK-LABEL: @square_fabs_intrinsic_f32(
+; CHECK-NEXT:    [[MUL:%.*]] = fmul float [[X:%.*]], [[X]]
+; CHECK-NEXT:    [[FABSF:%.*]] = tail call float @llvm.fabs.f32(float [[MUL]])
+; CHECK-NEXT:    ret float [[FABSF]]
+;
+  %mul = fmul float %x, %x
+  %fabsf = tail call float @llvm.fabs.f32(float %mul)
+  ret float %fabsf
+}
+
+define double @square_fabs_intrinsic_f64(double %x) {
+; CHECK-LABEL: @square_fabs_intrinsic_f64(
+; CHECK-NEXT:    [[MUL:%.*]] = fmul double [[X:%.*]], [[X]]
+; CHECK-NEXT:    [[FABS:%.*]] = tail call double @llvm.fabs.f64(double [[MUL]])
+; CHECK-NEXT:    ret double [[FABS]]
+;
+  %mul = fmul double %x, %x
+  %fabs = tail call double @llvm.fabs.f64(double %mul)
+  ret double %fabs
+}
+
+define fp128 @square_fabs_intrinsic_f128(fp128 %x) {
+; CHECK-LABEL: @square_fabs_intrinsic_f128(
+; CHECK-NEXT:    [[MUL:%.*]] = fmul fp128 [[X:%.*]], [[X]]
+; CHECK-NEXT:    [[FABSL:%.*]] = tail call fp128 @llvm.fabs.f128(fp128 [[MUL]])
+; CHECK-NEXT:    ret fp128 [[FABSL]]
+;
+  %mul = fmul fp128 %x, %x
+  %fabsl = tail call fp128 @llvm.fabs.f128(fp128 %mul)
+  ret fp128 %fabsl
+}
+
+define float @square_nnan_fabs_intrinsic_f32(float %x) {
+; CHECK-LABEL: @square_nnan_fabs_intrinsic_f32(
+; CHECK-NEXT:    [[MUL:%.*]] = fmul nnan float [[X:%.*]], [[X]]
+; CHECK-NEXT:    ret float [[MUL]]
+;
+  %mul = fmul nnan float %x, %x
+  %fabsf = call float @llvm.fabs.f32(float %mul)
+  ret float %fabsf
+}
+
+; Shrinking a library call to a smaller type should not be inhibited by nor inhibit the square optimization.
+
+define float @square_fabs_shrink_call1(float %x) {
+; CHECK-LABEL: @square_fabs_shrink_call1(
+; CHECK-NEXT:    [[TMP1:%.*]] = fmul float [[X:%.*]], [[X]]
+; CHECK-NEXT:    [[TRUNC:%.*]] = call float @llvm.fabs.f32(float [[TMP1]])
+; CHECK-NEXT:    ret float [[TRUNC]]
+;
+  %ext = fpext float %x to double
+  %sq = fmul double %ext, %ext
+  %fabs = call double @fabs(double %sq)
+  %trunc = fptrunc double %fabs to float
+  ret float %trunc
+}
+
+define float @square_fabs_shrink_call2(float %x) {
+; CHECK-LABEL: @square_fabs_shrink_call2(
+; CHECK-NEXT:    [[SQ:%.*]] = fmul float [[X:%.*]], [[X]]
+; CHECK-NEXT:    [[TRUNC:%.*]] = call float @llvm.fabs.f32(float [[SQ]])
+; CHECK-NEXT:    ret float [[TRUNC]]
+;
+  %sq = fmul float %x, %x
+  %ext = fpext float %sq to double
+  %fabs = call double @fabs(double %ext)
+  %trunc = fptrunc double %fabs to float
+  ret float %trunc
+}
+
+define float @fabs_select_constant_negative_positive(i32 %c) {
+; CHECK-LABEL: @fabs_select_constant_negative_positive(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[C:%.*]], 0
+; CHECK-NEXT:    [[FABS:%.*]] = select i1 [[CMP]], float 1.000000e+00, float 2.000000e+00
+; CHECK-NEXT:    ret float [[FABS]]
+;
+  %cmp = icmp eq i32 %c, 0
+  %select = select i1 %cmp, float -1.0, float 2.0
+  %fabs = call float @llvm.fabs.f32(float %select)
+  ret float %fabs
+}
+
+define float @fabs_select_constant_positive_negative(i32 %c) {
+; CHECK-LABEL: @fabs_select_constant_positive_negative(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[C:%.*]], 0
+; CHECK-NEXT:    [[FABS:%.*]] = select i1 [[CMP]], float 1.000000e+00, float 2.000000e+00
+; CHECK-NEXT:    ret float [[FABS]]
+;
+  %cmp = icmp eq i32 %c, 0
+  %select = select i1 %cmp, float 1.0, float -2.0
+  %fabs = call float @llvm.fabs.f32(float %select)
+  ret float %fabs
+}
+
+define float @fabs_select_constant_negative_negative(i32 %c) {
+; CHECK-LABEL: @fabs_select_constant_negative_negative(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[C:%.*]], 0
+; CHECK-NEXT:    [[FABS:%.*]] = select i1 [[CMP]], float 1.000000e+00, float 2.000000e+00
+; CHECK-NEXT:    ret float [[FABS]]
+;
+  %cmp = icmp eq i32 %c, 0
+  %select = select i1 %cmp, float -1.0, float -2.0
+  %fabs = call float @llvm.fabs.f32(float %select)
+  ret float %fabs
+}
+
+define float @fabs_select_constant_neg0(i32 %c) {
+; CHECK-LABEL: @fabs_select_constant_neg0(
+; CHECK-NEXT:    ret float 0.000000e+00
+;
+  %cmp = icmp eq i32 %c, 0
+  %select = select i1 %cmp, float -0.0, float 0.0
+  %fabs = call float @llvm.fabs.f32(float %select)
+  ret float %fabs
+}
+
+define float @fabs_select_var_constant_negative(i32 %c, float %x) {
+; CHECK-LABEL: @fabs_select_var_constant_negative(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[C:%.*]], 0
+; CHECK-NEXT:    [[SELECT:%.*]] = select i1 [[CMP]], float [[X:%.*]], float -1.000000e+00
+; CHECK-NEXT:    [[FABS:%.*]] = call float @llvm.fabs.f32(float [[SELECT]])
+; CHECK-NEXT:    ret float [[FABS]]
+;
+  %cmp = icmp eq i32 %c, 0
+  %select = select i1 %cmp, float %x, float -1.0
+  %fabs = call float @llvm.fabs.f32(float %select)
+  ret float %fabs
+}
+
+; The fabs cannot be eliminated because %x may be a NaN
+
+define float @square_fma_fabs_intrinsic_f32(float %x) {
+; CHECK-LABEL: @square_fma_fabs_intrinsic_f32(
+; CHECK-NEXT:    [[FMA:%.*]] = call float @llvm.fma.f32(float [[X:%.*]], float [[X]], float 1.000000e+00)
+; CHECK-NEXT:    [[FABSF:%.*]] = call float @llvm.fabs.f32(float [[FMA]])
+; CHECK-NEXT:    ret float [[FABSF]]
+;
+  %fma = call float @llvm.fma.f32(float %x, float %x, float 1.0)
+  %fabsf = call float @llvm.fabs.f32(float %fma)
+  ret float %fabsf
+}
+
+; The fabs cannot be eliminated because %x may be a NaN
+
+define float @square_nnan_fma_fabs_intrinsic_f32(float %x) {
+; CHECK-LABEL: @square_nnan_fma_fabs_intrinsic_f32(
+; CHECK-NEXT:    [[FMA:%.*]] = call nnan float @llvm.fma.f32(float [[X:%.*]], float [[X]], float 1.000000e+00)
+; CHECK-NEXT:    ret float [[FMA]]
+;
+  %fma = call nnan float @llvm.fma.f32(float %x, float %x, float 1.0)
+  %fabsf = call float @llvm.fabs.f32(float %fma)
+  ret float %fabsf
+}
+
+define float @square_fmuladd_fabs_intrinsic_f32(float %x) {
+; CHECK-LABEL: @square_fmuladd_fabs_intrinsic_f32(
+; CHECK-NEXT:    [[FMULADD:%.*]] = call float @llvm.fmuladd.f32(float [[X:%.*]], float [[X]], float 1.000000e+00)
+; CHECK-NEXT:    [[FABSF:%.*]] = call float @llvm.fabs.f32(float [[FMULADD]])
+; CHECK-NEXT:    ret float [[FABSF]]
+;
+  %fmuladd = call float @llvm.fmuladd.f32(float %x, float %x, float 1.0)
+  %fabsf = call float @llvm.fabs.f32(float %fmuladd)
+  ret float %fabsf
+}
+
+define float @square_nnan_fmuladd_fabs_intrinsic_f32(float %x) {
+; CHECK-LABEL: @square_nnan_fmuladd_fabs_intrinsic_f32(
+; CHECK-NEXT:    [[FMULADD:%.*]] = call nnan float @llvm.fmuladd.f32(float [[X:%.*]], float [[X]], float 1.000000e+00)
+; CHECK-NEXT:    ret float [[FMULADD]]
+;
+  %fmuladd = call nnan float @llvm.fmuladd.f32(float %x, float %x, float 1.0)
+  %fabsf = call float @llvm.fabs.f32(float %fmuladd)
+  ret float %fabsf
+}
+
+; Don't introduce a second fpext
+
+define double @multi_use_fabs_fpext(float %x) {
+; CHECK-LABEL: @multi_use_fabs_fpext(
+; CHECK-NEXT:    [[FPEXT:%.*]] = fpext float [[X:%.*]] to double
+; CHECK-NEXT:    [[FABS:%.*]] = call double @llvm.fabs.f64(double [[FPEXT]])
+; CHECK-NEXT:    store volatile double [[FPEXT]], double* undef, align 8
+; CHECK-NEXT:    ret double [[FABS]]
+;
+  %fpext = fpext float %x to double
+  %fabs = call double @llvm.fabs.f64(double %fpext)
+  store volatile double %fpext, double* undef
+  ret double %fabs
+}
+
+; Negative test for the fabs folds below: we require nnan, so
+; we won't always clear the sign bit of a NaN value.
+
+define double @select_fcmp_ole_zero(double %x) {
+; CHECK-LABEL: @select_fcmp_ole_zero(
+; CHECK-NEXT:    [[LEZERO:%.*]] = fcmp ole double [[X:%.*]], 0.000000e+00
+; CHECK-NEXT:    [[NEGX:%.*]] = fsub double 0.000000e+00, [[X]]
+; CHECK-NEXT:    [[FABS:%.*]] = select i1 [[LEZERO]], double [[NEGX]], double [[X]]
+; CHECK-NEXT:    ret double [[FABS]]
+;
+  %lezero = fcmp ole double %x, 0.0
+  %negx = fsub double 0.0, %x
+  %fabs = select i1 %lezero, double %negx, double %x
+  ret double %fabs
+}
+
+; X <= 0.0 ? (0.0 - X) : X --> fabs(X)
+
+define double @select_fcmp_nnan_ole_zero(double %x) {
+; CHECK-LABEL: @select_fcmp_nnan_ole_zero(
+; CHECK-NEXT:    [[TMP1:%.*]] = call nnan double @llvm.fabs.f64(double [[X:%.*]])
+; CHECK-NEXT:    ret double [[TMP1]]
+;
+  %lezero = fcmp nnan ole double %x, 0.0
+  %negx = fsub double 0.0, %x
+  %fabs = select i1 %lezero, double %negx, double %x
+  ret double %fabs
+}
+
+; X <= -0.0 ? (0.0 - X) : X --> fabs(X)
+
+define <2 x float> @select_fcmp_nnan_ole_negzero(<2 x float> %x) {
+; CHECK-LABEL: @select_fcmp_nnan_ole_negzero(
+; CHECK-NEXT:    [[TMP1:%.*]] = call nnan <2 x float> @llvm.fabs.v2f32(<2 x float> [[X:%.*]])
+; CHECK-NEXT:    ret <2 x float> [[TMP1]]
+;
+  %lezero = fcmp nnan ole <2 x float> %x, <float -0.0, float -0.0>
+  %negx = fsub <2 x float> <float 0.0, float undef>, %x
+  %fabs = select <2 x i1> %lezero, <2 x float> %negx, <2 x float> %x
+  ret <2 x float> %fabs
+}
+
+; X > 0.0 ? X : (0.0 - X) --> fabs(X)
+
+define fp128 @select_fcmp_nnan_ogt_zero(fp128 %x) {
+; CHECK-LABEL: @select_fcmp_nnan_ogt_zero(
+; CHECK-NEXT:    [[TMP1:%.*]] = call nnan fp128 @llvm.fabs.f128(fp128 [[X:%.*]])
+; CHECK-NEXT:    ret fp128 [[TMP1]]
+;
+  %gtzero = fcmp nnan ogt fp128 %x, zeroinitializer
+  %negx = fsub fp128 zeroinitializer, %x
+  %fabs = select i1 %gtzero, fp128 %x, fp128 %negx
+  ret fp128 %fabs
+}
+
+; X > -0.0 ? X : (0.0 - X) --> fabs(X)
+
+define half @select_fcmp_nnan_ogt_negzero(half %x) {
+; CHECK-LABEL: @select_fcmp_nnan_ogt_negzero(
+; CHECK-NEXT:    [[TMP1:%.*]] = call nnan half @llvm.fabs.f16(half [[X:%.*]])
+; CHECK-NEXT:    ret half [[TMP1]]
+;
+  %gtzero = fcmp nnan ogt half %x, -0.0
+  %negx = fsub half 0.0, %x
+  %fabs = select i1 %gtzero, half %x, half %negx
+  ret half %fabs
+}
+
+; X < 0.0 ? -X : X --> fabs(X)
+
+define double @select_fcmp_nnan_nsz_olt_zero(double %x) {
+; CHECK-LABEL: @select_fcmp_nnan_nsz_olt_zero(
+; CHECK-NEXT:    [[TMP1:%.*]] = call nnan nsz double @llvm.fabs.f64(double [[X:%.*]])
+; CHECK-NEXT:    ret double [[TMP1]]
+;
+  %ltzero = fcmp nnan nsz olt double %x, 0.0
+  %negx = fsub double -0.0, %x
+  %fabs = select i1 %ltzero, double %negx, double %x
+  ret double %fabs
+}
+
+; X < -0.0 ? -X : X --> fabs(X)
+
+define float @select_fcmp_nnan_nsz_olt_negzero(float %x) {
+; CHECK-LABEL: @select_fcmp_nnan_nsz_olt_negzero(
+; CHECK-NEXT:    [[TMP1:%.*]] = call nnan ninf nsz float @llvm.fabs.f32(float [[X:%.*]])
+; CHECK-NEXT:    ret float [[TMP1]]
+;
+  %ltzero = fcmp nnan nsz ninf olt float %x, -0.0
+  %negx = fsub float -0.0, %x
+  %fabs = select i1 %ltzero, float %negx, float %x
+  ret float %fabs
+}
+
+; X <= 0.0 ? -X : X --> fabs(X)
+
+define double @select_fcmp_nnan_nsz_ole_zero(double %x) {
+; CHECK-LABEL: @select_fcmp_nnan_nsz_ole_zero(
+; CHECK-NEXT:    [[TMP1:%.*]] = call fast double @llvm.fabs.f64(double [[X:%.*]])
+; CHECK-NEXT:    ret double [[TMP1]]
+;
+  %lezero = fcmp fast ole double %x, 0.0
+  %negx = fsub double -0.0, %x
+  %fabs = select i1 %lezero, double %negx, double %x
+  ret double %fabs
+}
+
+; X <= -0.0 ? -X : X --> fabs(X)
+
+define float @select_fcmp_nnan_nsz_ole_negzero(float %x) {
+; CHECK-LABEL: @select_fcmp_nnan_nsz_ole_negzero(
+; CHECK-NEXT:    [[TMP1:%.*]] = call nnan nsz float @llvm.fabs.f32(float [[X:%.*]])
+; CHECK-NEXT:    ret float [[TMP1]]
+;
+  %lezero = fcmp nnan nsz ole float %x, -0.0
+  %negx = fsub float -0.0, %x
+  %fabs = select i1 %lezero, float %negx, float %x
+  ret float %fabs
+}
+
+; X > 0.0 ? X : (0.0 - X) --> fabs(X)
+
+define <2 x float> @select_fcmp_nnan_nsz_ogt_zero(<2 x float> %x) {
+; CHECK-LABEL: @select_fcmp_nnan_nsz_ogt_zero(
+; CHECK-NEXT:    [[TMP1:%.*]] = call nnan nsz arcp <2 x float> @llvm.fabs.v2f32(<2 x float> [[X:%.*]])
+; CHECK-NEXT:    ret <2 x float> [[TMP1]]
+;
+  %gtzero = fcmp nnan nsz arcp ogt <2 x float> %x, zeroinitializer
+  %negx = fsub <2 x float> <float -0.0, float -0.0>, %x
+  %fabs = select <2 x i1> %gtzero, <2 x float> %x, <2 x float> %negx
+  ret <2 x float> %fabs
+}
+
+; X > -0.0 ? X : (0.0 - X) --> fabs(X)
+
+define half @select_fcmp_nnan_nsz_ogt_negzero(half %x) {
+; CHECK-LABEL: @select_fcmp_nnan_nsz_ogt_negzero(
+; CHECK-NEXT:    [[TMP1:%.*]] = call fast half @llvm.fabs.f16(half [[X:%.*]])
+; CHECK-NEXT:    ret half [[TMP1]]
+;
+  %gtzero = fcmp fast ogt half %x, -0.0
+  %negx = fsub half 0.0, %x
+  %fabs = select i1 %gtzero, half %x, half %negx
+  ret half %fabs
+}
+
+; X > 0.0 ? X : (0.0 - X) --> fabs(X)
+
+define <2 x double> @select_fcmp_nnan_nsz_oge_zero(<2 x double> %x) {
+; CHECK-LABEL: @select_fcmp_nnan_nsz_oge_zero(
+; CHECK-NEXT:    [[TMP1:%.*]] = call reassoc nnan nsz <2 x double> @llvm.fabs.v2f64(<2 x double> [[X:%.*]])
+; CHECK-NEXT:    ret <2 x double> [[TMP1]]
+;
+  %gezero = fcmp nnan nsz reassoc oge <2 x double> %x, zeroinitializer
+  %negx = fsub <2 x double> <double -0.0, double -0.0>, %x
+  %fabs = select <2 x i1> %gezero, <2 x double> %x, <2 x double> %negx
+  ret <2 x double> %fabs
+}
+
+; X > -0.0 ? X : (0.0 - X) --> fabs(X)
+
+define half @select_fcmp_nnan_nsz_oge_negzero(half %x) {
+; CHECK-LABEL: @select_fcmp_nnan_nsz_oge_negzero(
+; CHECK-NEXT:    [[TMP1:%.*]] = call nnan nsz half @llvm.fabs.f16(half [[X:%.*]])
+; CHECK-NEXT:    ret half [[TMP1]]
+;
+  %gezero = fcmp nnan nsz oge half %x, -0.0
+  %negx = fsub half -0.0, %x
+  %fabs = select i1 %gezero, half %x, half %negx
+  ret half %fabs
+}
+

Added: llvm/trunk/test/Transforms/InstCombine/fadd-fsub-factor.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/fadd-fsub-factor.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/fadd-fsub-factor.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/fadd-fsub-factor.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,473 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt < %s -instcombine -S | FileCheck %s
+
+; =========================================================================
+;
+;   Test FP factorization with patterns:
+;   X * Z + Y * Z --> (X + Y) * Z (including all 4 commuted variants)
+;   X * Z - Y * Z --> (X - Y) * Z (including all 4 commuted variants)
+;   X / Z + Y / Z --> (X + Y) / Z
+;   X / Z - Y / Z --> (X - Y) / Z
+;
+; =========================================================================
+
+; Minimum FMF - the final result requires/propagates FMF.
+
+define float @fmul_fadd(float %x, float %y, float %z) {
+; CHECK-LABEL: @fmul_fadd(
+; CHECK-NEXT:    [[TMP1:%.*]] = fadd reassoc nsz float [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = fmul reassoc nsz float [[TMP1]], [[Z:%.*]]
+; CHECK-NEXT:    ret float [[R]]
+;
+  %t1 = fmul float %x, %z
+  %t2 = fmul float %y, %z
+  %r = fadd reassoc nsz float %t1, %t2
+  ret float %r
+}
+
+; Verify vector types and commuted operands.
+
+define <2 x float> @fmul_fadd_commute1_vec(<2 x float> %x, <2 x float> %y, <2 x float> %z) {
+; CHECK-LABEL: @fmul_fadd_commute1_vec(
+; CHECK-NEXT:    [[TMP1:%.*]] = fadd reassoc nsz <2 x float> [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = fmul reassoc nsz <2 x float> [[TMP1]], [[Z:%.*]]
+; CHECK-NEXT:    ret <2 x float> [[R]]
+;
+  %t1 = fmul <2 x float> %z, %x
+  %t2 = fmul <2 x float> %z, %y
+  %r = fadd reassoc nsz <2 x float> %t1, %t2
+  ret <2 x float> %r
+}
+
+; Verify vector types, commuted operands, FMF propagation.
+
+define <2 x float> @fmul_fadd_commute2_vec(<2 x float> %x, <2 x float> %y, <2 x float> %z) {
+; CHECK-LABEL: @fmul_fadd_commute2_vec(
+; CHECK-NEXT:    [[TMP1:%.*]] = fadd reassoc ninf nsz <2 x float> [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = fmul reassoc ninf nsz <2 x float> [[TMP1]], [[Z:%.*]]
+; CHECK-NEXT:    ret <2 x float> [[R]]
+;
+  %t1 = fmul fast <2 x float> %x, %z
+  %t2 = fmul nnan <2 x float> %z, %y
+  %r = fadd reassoc nsz ninf <2 x float> %t1, %t2
+  ret <2 x float> %r
+}
+
+; Verify different scalar type, commuted operands, FMF propagation.
+
+define double @fmul_fadd_commute3(double %x, double %y, double %z) {
+; CHECK-LABEL: @fmul_fadd_commute3(
+; CHECK-NEXT:    [[TMP1:%.*]] = fadd reassoc nnan nsz double [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = fmul reassoc nnan nsz double [[TMP1]], [[Z:%.*]]
+; CHECK-NEXT:    ret double [[R]]
+;
+  %t1 = fmul double %z, %x
+  %t2 = fmul fast double %y, %z
+  %r = fadd reassoc nsz nnan double %t1, %t2
+  ret double %r
+}
+
+; Negative test - verify the fold is not done with only 'reassoc' ('nsz' is required).
+
+define float @fmul_fadd_not_enough_FMF(float %x, float %y, float %z) {
+; CHECK-LABEL: @fmul_fadd_not_enough_FMF(
+; CHECK-NEXT:    [[T1:%.*]] = fmul fast float [[X:%.*]], [[Z:%.*]]
+; CHECK-NEXT:    [[T2:%.*]] = fmul fast float [[Y:%.*]], [[Z]]
+; CHECK-NEXT:    [[R:%.*]] = fadd reassoc float [[T1]], [[T2]]
+; CHECK-NEXT:    ret float [[R]]
+;
+  %t1 = fmul fast float %x, %z
+  %t2 = fmul fast float %y, %z
+  %r = fadd reassoc float %t1, %t2
+  ret float %r
+}
+
+declare void @use(float)
+
+; Negative test - extra uses should disable the fold.
+
+define float @fmul_fadd_uses1(float %x, float %y, float %z) {
+; CHECK-LABEL: @fmul_fadd_uses1(
+; CHECK-NEXT:    [[T1:%.*]] = fmul float [[Z:%.*]], [[X:%.*]]
+; CHECK-NEXT:    [[T2:%.*]] = fmul float [[Y:%.*]], [[Z]]
+; CHECK-NEXT:    [[R:%.*]] = fadd reassoc nsz float [[T1]], [[T2]]
+; CHECK-NEXT:    call void @use(float [[T1]])
+; CHECK-NEXT:    ret float [[R]]
+;
+  %t1 = fmul float %z, %x
+  %t2 = fmul float %y, %z
+  %r = fadd reassoc nsz float %t1, %t2
+  call void @use(float %t1)
+  ret float %r
+}
+
+; Negative test - extra uses should disable the fold.
+
+define float @fmul_fadd_uses2(float %x, float %y, float %z) {
+; CHECK-LABEL: @fmul_fadd_uses2(
+; CHECK-NEXT:    [[T1:%.*]] = fmul float [[Z:%.*]], [[X:%.*]]
+; CHECK-NEXT:    [[T2:%.*]] = fmul float [[Z]], [[Y:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = fadd reassoc nsz float [[T1]], [[T2]]
+; CHECK-NEXT:    call void @use(float [[T2]])
+; CHECK-NEXT:    ret float [[R]]
+;
+  %t1 = fmul float %z, %x
+  %t2 = fmul float %z, %y
+  %r = fadd reassoc nsz float %t1, %t2
+  call void @use(float %t2)
+  ret float %r
+}
+
+; Negative test - extra uses should disable the fold.
+
+define float @fmul_fadd_uses3(float %x, float %y, float %z) {
+; CHECK-LABEL: @fmul_fadd_uses3(
+; CHECK-NEXT:    [[T1:%.*]] = fmul float [[X:%.*]], [[Z:%.*]]
+; CHECK-NEXT:    [[T2:%.*]] = fmul float [[Z]], [[Y:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = fadd reassoc nsz float [[T1]], [[T2]]
+; CHECK-NEXT:    call void @use(float [[T1]])
+; CHECK-NEXT:    call void @use(float [[T2]])
+; CHECK-NEXT:    ret float [[R]]
+;
+  %t1 = fmul float %x, %z
+  %t2 = fmul float %z, %y
+  %r = fadd reassoc nsz float %t1, %t2
+  call void @use(float %t1)
+  call void @use(float %t2)
+  ret float %r
+}
+
+; Minimum FMF - the final result requires/propagates FMF.
+
+define half @fmul_fsub(half %x, half %y, half %z) {
+; CHECK-LABEL: @fmul_fsub(
+; CHECK-NEXT:    [[TMP1:%.*]] = fsub reassoc nsz half [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = fmul reassoc nsz half [[TMP1]], [[Z:%.*]]
+; CHECK-NEXT:    ret half [[R]]
+;
+  %t1 = fmul half %x, %z
+  %t2 = fmul half %y, %z
+  %r = fsub reassoc nsz half %t1, %t2
+  ret half %r
+}
+
+; Verify vector types and commuted operands.
+
+define <2 x float> @fmul_fsub_commute1_vec(<2 x float> %x, <2 x float> %y, <2 x float> %z) {
+; CHECK-LABEL: @fmul_fsub_commute1_vec(
+; CHECK-NEXT:    [[TMP1:%.*]] = fsub reassoc nsz <2 x float> [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = fmul reassoc nsz <2 x float> [[TMP1]], [[Z:%.*]]
+; CHECK-NEXT:    ret <2 x float> [[R]]
+;
+  %t1 = fmul <2 x float> %z, %x
+  %t2 = fmul <2 x float> %y, %z
+  %r = fsub reassoc nsz <2 x float> %t1, %t2
+  ret <2 x float> %r
+}
+
+; Verify vector types, commuted operands, FMF propagation.
+
+define <2 x float> @fmul_fsub_commute2_vec(<2 x float> %x, <2 x float> %y, <2 x float> %z) {
+; CHECK-LABEL: @fmul_fsub_commute2_vec(
+; CHECK-NEXT:    [[TMP1:%.*]] = fsub reassoc ninf nsz <2 x float> [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = fmul reassoc ninf nsz <2 x float> [[TMP1]], [[Z:%.*]]
+; CHECK-NEXT:    ret <2 x float> [[R]]
+;
+  %t1 = fmul fast <2 x float> %x, %z
+  %t2 = fmul nnan <2 x float> %z, %y
+  %r = fsub reassoc nsz ninf <2 x float> %t1, %t2
+  ret <2 x float> %r
+}
+
+; Verify different scalar type, commuted operands, FMF propagation.
+
+define double @fmul_fsub_commute3(double %x, double %y, double %z) {
+; CHECK-LABEL: @fmul_fsub_commute3(
+; CHECK-NEXT:    [[TMP1:%.*]] = fsub reassoc nnan nsz double [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = fmul reassoc nnan nsz double [[TMP1]], [[Z:%.*]]
+; CHECK-NEXT:    ret double [[R]]
+;
+  %t1 = fmul double %z, %x
+  %t2 = fmul fast double %z, %y
+  %r = fsub reassoc nsz nnan double %t1, %t2
+  ret double %r
+}
+
+; Negative test - verify the fold is not done with only 'nsz' ('reassoc' is required).
+
+define float @fmul_fsub_not_enough_FMF(float %x, float %y, float %z) {
+; CHECK-LABEL: @fmul_fsub_not_enough_FMF(
+; CHECK-NEXT:    [[T1:%.*]] = fmul fast float [[Z:%.*]], [[X:%.*]]
+; CHECK-NEXT:    [[T2:%.*]] = fmul fast float [[Y:%.*]], [[Z]]
+; CHECK-NEXT:    [[R:%.*]] = fsub nsz float [[T1]], [[T2]]
+; CHECK-NEXT:    ret float [[R]]
+;
+  %t1 = fmul fast float %z, %x
+  %t2 = fmul fast float %y, %z
+  %r = fsub nsz float %t1, %t2
+  ret float %r
+}
+
+; Negative test - extra uses should disable the fold.
+
+define float @fmul_fsub_uses1(float %x, float %y, float %z) {
+; CHECK-LABEL: @fmul_fsub_uses1(
+; CHECK-NEXT:    [[T1:%.*]] = fmul float [[X:%.*]], [[Z:%.*]]
+; CHECK-NEXT:    [[T2:%.*]] = fmul float [[Y:%.*]], [[Z]]
+; CHECK-NEXT:    [[R:%.*]] = fsub reassoc nsz float [[T1]], [[T2]]
+; CHECK-NEXT:    call void @use(float [[T1]])
+; CHECK-NEXT:    ret float [[R]]
+;
+  %t1 = fmul float %x, %z
+  %t2 = fmul float %y, %z
+  %r = fsub reassoc nsz float %t1, %t2
+  call void @use(float %t1)
+  ret float %r
+}
+
+; Negative test - extra uses should disable the fold.
+
+define float @fmul_fsub_uses2(float %x, float %y, float %z) {
+; CHECK-LABEL: @fmul_fsub_uses2(
+; CHECK-NEXT:    [[T1:%.*]] = fmul float [[Z:%.*]], [[X:%.*]]
+; CHECK-NEXT:    [[T2:%.*]] = fmul float [[Z]], [[Y:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = fsub reassoc nsz float [[T1]], [[T2]]
+; CHECK-NEXT:    call void @use(float [[T2]])
+; CHECK-NEXT:    ret float [[R]]
+;
+  %t1 = fmul float %z, %x
+  %t2 = fmul float %z, %y
+  %r = fsub reassoc nsz float %t1, %t2
+  call void @use(float %t2)
+  ret float %r
+}
+
+; Negative test - extra uses should disable the fold.
+
+define float @fmul_fsub_uses3(float %x, float %y, float %z) {
+; CHECK-LABEL: @fmul_fsub_uses3(
+; CHECK-NEXT:    [[T1:%.*]] = fmul float [[X:%.*]], [[Z:%.*]]
+; CHECK-NEXT:    [[T2:%.*]] = fmul float [[Y:%.*]], [[Z]]
+; CHECK-NEXT:    [[R:%.*]] = fsub reassoc nsz float [[T1]], [[T2]]
+; CHECK-NEXT:    call void @use(float [[T1]])
+; CHECK-NEXT:    call void @use(float [[T2]])
+; CHECK-NEXT:    ret float [[R]]
+;
+  %t1 = fmul float %x, %z
+  %t2 = fmul float %y, %z
+  %r = fsub reassoc nsz float %t1, %t2
+  call void @use(float %t1)
+  call void @use(float %t2)
+  ret float %r
+}
+
+; Common divisor
+
+define double @fdiv_fadd(double %x, double %y, double %z) {
+; CHECK-LABEL: @fdiv_fadd(
+; CHECK-NEXT:    [[TMP1:%.*]] = fadd reassoc nsz double [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = fdiv reassoc nsz double [[TMP1]], [[Z:%.*]]
+; CHECK-NEXT:    ret double [[R]]
+;
+  %t1 = fdiv double %x, %z
+  %t2 = fdiv double %y, %z
+  %r = fadd reassoc nsz double %t1, %t2
+  ret double %r
+}
+
+define float @fdiv_fsub(float %x, float %y, float %z) {
+; CHECK-LABEL: @fdiv_fsub(
+; CHECK-NEXT:    [[TMP1:%.*]] = fsub reassoc nsz float [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = fdiv reassoc nsz float [[TMP1]], [[Z:%.*]]
+; CHECK-NEXT:    ret float [[R]]
+;
+  %t1 = fdiv fast float %x, %z
+  %t2 = fdiv nnan float %y, %z
+  %r = fsub reassoc nsz float %t1, %t2
+  ret float %r
+}
+
+; Verify vector types.
+
+define <2 x double> @fdiv_fadd_vec(<2 x double> %x, <2 x double> %y, <2 x double> %z) {
+; CHECK-LABEL: @fdiv_fadd_vec(
+; CHECK-NEXT:    [[TMP1:%.*]] = fadd reassoc nsz <2 x double> [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = fdiv reassoc nsz <2 x double> [[TMP1]], [[Z:%.*]]
+; CHECK-NEXT:    ret <2 x double> [[R]]
+;
+  %t1 = fdiv fast <2 x double> %x, %z
+  %t2 = fdiv <2 x double> %y, %z
+  %r = fadd reassoc nsz <2 x double> %t1, %t2
+  ret <2 x double> %r
+}
+
+; Verify vector types.
+
+define <2 x float> @fdiv_fsub_vec(<2 x float> %x, <2 x float> %y, <2 x float> %z) {
+; CHECK-LABEL: @fdiv_fsub_vec(
+; CHECK-NEXT:    [[TMP1:%.*]] = fsub reassoc nsz <2 x float> [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = fdiv reassoc nsz <2 x float> [[TMP1]], [[Z:%.*]]
+; CHECK-NEXT:    ret <2 x float> [[R]]
+;
+  %t1 = fdiv <2 x float> %x, %z
+  %t2 = fdiv nnan <2 x float> %y, %z
+  %r = fsub reassoc nsz <2 x float> %t1, %t2
+  ret <2 x float> %r
+}
+
+; Negative test - common operand is not divisor.
+
+define float @fdiv_fadd_commute1(float %x, float %y, float %z) {
+; CHECK-LABEL: @fdiv_fadd_commute1(
+; CHECK-NEXT:    [[T1:%.*]] = fdiv fast float [[Z:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    [[T2:%.*]] = fdiv fast float [[Z]], [[X:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = fadd fast float [[T1]], [[T2]]
+; CHECK-NEXT:    ret float [[R]]
+;
+  %t1 = fdiv fast float %z, %y
+  %t2 = fdiv fast float %z, %x
+  %r = fadd fast float %t1, %t2
+  ret float %r
+}
+
+; Negative test - common operand is not divisor.
+
+define float @fdiv_fsub_commute2(float %x, float %y, float %z) {
+; CHECK-LABEL: @fdiv_fsub_commute2(
+; CHECK-NEXT:    [[T1:%.*]] = fdiv fast float [[Z:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    [[T2:%.*]] = fdiv fast float [[X:%.*]], [[Z]]
+; CHECK-NEXT:    [[R:%.*]] = fsub fast float [[T1]], [[T2]]
+; CHECK-NEXT:    ret float [[R]]
+;
+  %t1 = fdiv fast float %z, %y
+  %t2 = fdiv fast float %x, %z
+  %r = fsub fast float %t1, %t2
+  ret float %r
+}
+
+; Negative test - verify the fold is not done with only 'nsz' ('reassoc' is required).
+
+define float @fdiv_fadd_not_enough_FMF(float %x, float %y, float %z) {
+; CHECK-LABEL: @fdiv_fadd_not_enough_FMF(
+; CHECK-NEXT:    [[T1:%.*]] = fdiv fast float [[Y:%.*]], [[X:%.*]]
+; CHECK-NEXT:    [[T2:%.*]] = fdiv fast float [[Z:%.*]], [[X]]
+; CHECK-NEXT:    [[T3:%.*]] = fadd nsz float [[T1]], [[T2]]
+; CHECK-NEXT:    ret float [[T3]]
+;
+  %t1 = fdiv fast float %y, %x
+  %t2 = fdiv fast float %z, %x
+  %t3 = fadd nsz float %t1, %t2
+  ret float %t3
+}
+
+; Negative test - verify the fold is not done with only 'reassoc' ('nsz' is required).
+
+define float @fdiv_fsub_not_enough_FMF(float %x, float %y, float %z) {
+; CHECK-LABEL: @fdiv_fsub_not_enough_FMF(
+; CHECK-NEXT:    [[T1:%.*]] = fdiv fast float [[Y:%.*]], [[X:%.*]]
+; CHECK-NEXT:    [[T2:%.*]] = fdiv fast float [[Z:%.*]], [[X]]
+; CHECK-NEXT:    [[T3:%.*]] = fsub reassoc float [[T1]], [[T2]]
+; CHECK-NEXT:    ret float [[T3]]
+;
+  %t1 = fdiv fast float %y, %x
+  %t2 = fdiv fast float %z, %x
+  %t3 = fsub reassoc float %t1, %t2
+  ret float %t3
+}
+
+; Negative test - extra uses should disable the fold.
+
+define float @fdiv_fadd_uses1(float %x, float %y, float %z) {
+; CHECK-LABEL: @fdiv_fadd_uses1(
+; CHECK-NEXT:    [[T1:%.*]] = fdiv fast float [[X:%.*]], [[Z:%.*]]
+; CHECK-NEXT:    [[T2:%.*]] = fdiv fast float [[Y:%.*]], [[Z]]
+; CHECK-NEXT:    [[R:%.*]] = fadd fast float [[T1]], [[T2]]
+; CHECK-NEXT:    call void @use(float [[T1]])
+; CHECK-NEXT:    ret float [[R]]
+;
+  %t1 = fdiv fast float %x, %z
+  %t2 = fdiv fast float %y, %z
+  %r = fadd fast float %t1, %t2
+  call void @use(float %t1)
+  ret float %r
+}
+
+; Negative test - extra uses should disable the fold.
+
+define float @fdiv_fsub_uses2(float %x, float %y, float %z) {
+; CHECK-LABEL: @fdiv_fsub_uses2(
+; CHECK-NEXT:    [[T1:%.*]] = fdiv fast float [[X:%.*]], [[Z:%.*]]
+; CHECK-NEXT:    [[T2:%.*]] = fdiv fast float [[Y:%.*]], [[Z]]
+; CHECK-NEXT:    [[R:%.*]] = fsub fast float [[T1]], [[T2]]
+; CHECK-NEXT:    call void @use(float [[T2]])
+; CHECK-NEXT:    ret float [[R]]
+;
+  %t1 = fdiv fast float %x, %z
+  %t2 = fdiv fast float %y, %z
+  %r = fsub fast float %t1, %t2
+  call void @use(float %t2)
+  ret float %r
+}
+
+; Negative test - extra uses should disable the fold.
+
+define float @fdiv_fsub_uses3(float %x, float %y, float %z) {
+; CHECK-LABEL: @fdiv_fsub_uses3(
+; CHECK-NEXT:    [[T1:%.*]] = fdiv fast float [[X:%.*]], [[Z:%.*]]
+; CHECK-NEXT:    [[T2:%.*]] = fdiv fast float [[Y:%.*]], [[Z]]
+; CHECK-NEXT:    [[R:%.*]] = fsub fast float [[T1]], [[T2]]
+; CHECK-NEXT:    call void @use(float [[T1]])
+; CHECK-NEXT:    call void @use(float [[T2]])
+; CHECK-NEXT:    ret float [[R]]
+;
+  %t1 = fdiv fast float %x, %z
+  %t2 = fdiv fast float %y, %z
+  %r = fsub fast float %t1, %t2
+  call void @use(float %t1)
+  call void @use(float %t2)
+  ret float %r
+}
+
+; Constants are fine to combine if they are not denorms.
+
+define float @fdiv_fadd_not_denorm(float %x) {
+; CHECK-LABEL: @fdiv_fadd_not_denorm(
+; CHECK-NEXT:    [[R:%.*]] = fdiv fast float 0x3818000000000000, [[X:%.*]]
+; CHECK-NEXT:    ret float [[R]]
+;
+  %t1 = fdiv fast float 0x3810000000000000, %x
+  %t2 = fdiv fast float 0x3800000000000000, %x
+  %r = fadd fast float %t1, %t2
+  ret float %r
+}
+
+; Negative test - disabled if x+y is denormal.
+
+define float @fdiv_fadd_denorm(float %x) {
+; CHECK-LABEL: @fdiv_fadd_denorm(
+; CHECK-NEXT:    [[T1:%.*]] = fdiv fast float 0xB810000000000000, [[X:%.*]]
+; CHECK-NEXT:    [[T2:%.*]] = fdiv fast float 0x3800000000000000, [[X]]
+; CHECK-NEXT:    [[R:%.*]] = fadd fast float [[T1]], [[T2]]
+; CHECK-NEXT:    ret float [[R]]
+;
+  %t1 = fdiv fast float 0xB810000000000000, %x
+  %t2 = fdiv fast float 0x3800000000000000, %x
+  %r = fadd fast float %t1, %t2
+  ret float %r
+}
+
+; Negative test - disabled if x-y is denormal.
+
+define float @fdiv_fsub_denorm(float %x) {
+; CHECK-LABEL: @fdiv_fsub_denorm(
+; CHECK-NEXT:    [[T1:%.*]] = fdiv fast float 0x3810000000000000, [[X:%.*]]
+; CHECK-NEXT:    [[T2:%.*]] = fdiv fast float 0x3800000000000000, [[X]]
+; CHECK-NEXT:    [[R:%.*]] = fsub fast float [[T1]], [[T2]]
+; CHECK-NEXT:    ret float [[R]]
+;
+  %t1 = fdiv fast float 0x3810000000000000, %x
+  %t2 = fdiv fast float 0x3800000000000000, %x
+  %r = fsub fast float %t1, %t2
+  ret float %r
+}
+

Added: llvm/trunk/test/Transforms/InstCombine/fadd.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/fadd.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/fadd.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/fadd.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,27 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt < %s -instcombine -S | FileCheck %s
+
+; -x + y => y - x
+
+define float @fneg_op0(float %x, float %y) {
+; CHECK-LABEL: @fneg_op0(
+; CHECK-NEXT:    [[ADD:%.*]] = fsub float [[Y:%.*]], [[X:%.*]]
+; CHECK-NEXT:    ret float [[ADD]]
+;
+  %neg = fsub float -0.0, %x
+  %add = fadd float %neg, %y
+  ret float %add
+}
+
+; x + -y => x - y
+
+define float @fneg_op1(float %x, float %y) {
+; CHECK-LABEL: @fneg_op1(
+; CHECK-NEXT:    [[ADD:%.*]] = fsub float [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    ret float [[ADD]]
+;
+  %neg = fsub float -0.0, %y
+  %add = fadd float %x, %neg
+  ret float %add
+}
+

Added: llvm/trunk/test/Transforms/InstCombine/fast-math.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/fast-math.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/fast-math.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/fast-math.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,931 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt < %s -instcombine -S | FileCheck %s
+
+; testing-case "float fold(float a) { return 1.2f * a * 2.3f; }"
+; 1.2f and 2.3f is supposed to be fold.
+define float @fold(float %a) {
+; CHECK-LABEL: @fold(
+; CHECK-NEXT:    [[MUL1:%.*]] = fmul fast float [[A:%.*]], 0x4006147AE0000000
+; CHECK-NEXT:    ret float [[MUL1]]
+;
+  %mul = fmul fast float %a, 0x3FF3333340000000
+  %mul1 = fmul fast float %mul, 0x4002666660000000
+  ret float %mul1
+}
+
+; Same testing-case as the one used in fold() except that the operators have
+; fixed FP mode.
+define float @notfold(float %a) {
+; CHECK-LABEL: @notfold(
+; CHECK-NEXT:    [[MUL:%.*]] = fmul fast float [[A:%.*]], 0x3FF3333340000000
+; CHECK-NEXT:    [[MUL1:%.*]] = fmul float [[MUL]], 0x4002666660000000
+; CHECK-NEXT:    ret float [[MUL1]]
+;
+  %mul = fmul fast float %a, 0x3FF3333340000000
+  %mul1 = fmul float %mul, 0x4002666660000000
+  ret float %mul1
+}
+
+define float @fold2(float %a) {
+; CHECK-LABEL: @fold2(
+; CHECK-NEXT:    [[MUL1:%.*]] = fmul fast float [[A:%.*]], 0x4006147AE0000000
+; CHECK-NEXT:    ret float [[MUL1]]
+;
+  %mul = fmul float %a, 0x3FF3333340000000
+  %mul1 = fmul fast float %mul, 0x4002666660000000
+  ret float %mul1
+}
+
+; C * f1 + f1 = (C+1) * f1
+; TODO: The particular case where C is 2 (so the folded result is 3.0*f1) is
+; always safe, and so doesn't need any FMF.
+; That is, (x + x + x) and (3*x) each have only a single rounding.
+define double @fold3(double %f1) {
+; CHECK-LABEL: @fold3(
+; CHECK-NEXT:    [[TMP1:%.*]] = fmul fast double [[F1:%.*]], 6.000000e+00
+; CHECK-NEXT:    ret double [[TMP1]]
+;
+  %t1 = fmul fast double 5.000000e+00, %f1
+  %t2 = fadd fast double %f1, %t1
+  ret double %t2
+}
+
+; Check again with 'reassoc' and 'nsz' ('nsz' not technically required).
+define double @fold3_reassoc_nsz(double %f1) {
+; CHECK-LABEL: @fold3_reassoc_nsz(
+; CHECK-NEXT:    [[TMP1:%.*]] = fmul reassoc nsz double [[F1:%.*]], 6.000000e+00
+; CHECK-NEXT:    ret double [[TMP1]]
+;
+  %t1 = fmul reassoc nsz double 5.000000e+00, %f1
+  %t2 = fadd reassoc nsz double %f1, %t1
+  ret double %t2
+}
+
+; TODO: This doesn't require 'nsz'.  It should fold to f1 * 6.0.
+define double @fold3_reassoc(double %f1) {
+; CHECK-LABEL: @fold3_reassoc(
+; CHECK-NEXT:    [[T1:%.*]] = fmul reassoc double [[F1:%.*]], 5.000000e+00
+; CHECK-NEXT:    [[T2:%.*]] = fadd reassoc double [[T1]], [[F1]]
+; CHECK-NEXT:    ret double [[T2]]
+;
+  %t1 = fmul reassoc double 5.000000e+00, %f1
+  %t2 = fadd reassoc double %f1, %t1
+  ret double %t2
+}
+
+; (C1 - X) + (C2 - Y) => (C1+C2) - (X + Y)
+define float @fold4(float %f1, float %f2) {
+; CHECK-LABEL: @fold4(
+; CHECK-NEXT:    [[TMP1:%.*]] = fadd fast float [[F1:%.*]], [[F2:%.*]]
+; CHECK-NEXT:    [[TMP2:%.*]] = fsub fast float 9.000000e+00, [[TMP1]]
+; CHECK-NEXT:    ret float [[TMP2]]
+;
+  %sub = fsub float 4.000000e+00, %f1
+  %sub1 = fsub float 5.000000e+00, %f2
+  %add = fadd fast float %sub, %sub1
+  ret float %add
+}
+
+; Check again with 'reassoc' and 'nsz' ('nsz' not technically required).
+define float @fold4_reassoc_nsz(float %f1, float %f2) {
+; CHECK-LABEL: @fold4_reassoc_nsz(
+; CHECK-NEXT:    [[TMP1:%.*]] = fadd reassoc nsz float [[F1:%.*]], [[F2:%.*]]
+; CHECK-NEXT:    [[TMP2:%.*]] = fsub reassoc nsz float 9.000000e+00, [[TMP1]]
+; CHECK-NEXT:    ret float [[TMP2]]
+;
+  %sub = fsub float 4.000000e+00, %f1
+  %sub1 = fsub float 5.000000e+00, %f2
+  %add = fadd reassoc nsz float %sub, %sub1
+  ret float %add
+}
+
+; TODO: This doesn't require 'nsz'.  It should fold to (9.0 - (f1 + f2)).
+define float @fold4_reassoc(float %f1, float %f2) {
+; CHECK-LABEL: @fold4_reassoc(
+; CHECK-NEXT:    [[SUB:%.*]] = fsub float 4.000000e+00, [[F1:%.*]]
+; CHECK-NEXT:    [[SUB1:%.*]] = fsub float 5.000000e+00, [[F2:%.*]]
+; CHECK-NEXT:    [[ADD:%.*]] = fadd reassoc float [[SUB]], [[SUB1]]
+; CHECK-NEXT:    ret float [[ADD]]
+;
+  %sub = fsub float 4.000000e+00, %f1
+  %sub1 = fsub float 5.000000e+00, %f2
+  %add = fadd reassoc float %sub, %sub1
+  ret float %add
+}
+
+; (X + C1) + C2 => X + (C1 + C2)
+define float @fold5(float %f1) {
+; CHECK-LABEL: @fold5(
+; CHECK-NEXT:    [[ADD1:%.*]] = fadd fast float [[F1:%.*]], 9.000000e+00
+; CHECK-NEXT:    ret float [[ADD1]]
+;
+  %add = fadd float %f1, 4.000000e+00
+  %add1 = fadd fast float %add, 5.000000e+00
+  ret float %add1
+}
+
+; Check again with 'reassoc' and 'nsz' ('nsz' not technically required).
+define float @fold5_reassoc_nsz(float %f1) {
+; CHECK-LABEL: @fold5_reassoc_nsz(
+; CHECK-NEXT:    [[ADD1:%.*]] = fadd reassoc nsz float [[F1:%.*]], 9.000000e+00
+; CHECK-NEXT:    ret float [[ADD1]]
+;
+  %add = fadd float %f1, 4.000000e+00
+  %add1 = fadd reassoc nsz float %add, 5.000000e+00
+  ret float %add1
+}
+
+; TODO: This doesn't require 'nsz'.  It should fold to f1 + 9.0
+define float @fold5_reassoc(float %f1) {
+; CHECK-LABEL: @fold5_reassoc(
+; CHECK-NEXT:    [[ADD:%.*]] = fadd float [[F1:%.*]], 4.000000e+00
+; CHECK-NEXT:    [[ADD1:%.*]] = fadd reassoc float [[ADD]], 5.000000e+00
+; CHECK-NEXT:    ret float [[ADD1]]
+;
+  %add = fadd float %f1, 4.000000e+00
+  %add1 = fadd reassoc float %add, 5.000000e+00
+  ret float %add1
+}
+
+; (X + X) + X + X => 4.0 * X
+define float @fold6(float %f1) {
+; CHECK-LABEL: @fold6(
+; CHECK-NEXT:    [[TMP1:%.*]] = fmul fast float [[F1:%.*]], 4.000000e+00
+; CHECK-NEXT:    ret float [[TMP1]]
+;
+  %t1 = fadd fast float %f1, %f1
+  %t2 = fadd fast float %f1, %t1
+  %t3 = fadd fast float %t2, %f1
+  ret float %t3
+}
+
+; Check again with 'reassoc' and 'nsz' ('nsz' not technically required).
+define float @fold6_reassoc_nsz(float %f1) {
+; CHECK-LABEL: @fold6_reassoc_nsz(
+; CHECK-NEXT:    [[TMP1:%.*]] = fmul reassoc nsz float [[F1:%.*]], 4.000000e+00
+; CHECK-NEXT:    ret float [[TMP1]]
+;
+  %t1 = fadd reassoc nsz float %f1, %f1
+  %t2 = fadd reassoc nsz float %f1, %t1
+  %t3 = fadd reassoc nsz float %t2, %f1
+  ret float %t3
+}
+
+; TODO: This doesn't require 'nsz'.  It should fold to f1 * 4.0.
+define float @fold6_reassoc(float %f1) {
+; CHECK-LABEL: @fold6_reassoc(
+; CHECK-NEXT:    [[T1:%.*]] = fadd reassoc float [[F1:%.*]], [[F1]]
+; CHECK-NEXT:    [[T2:%.*]] = fadd reassoc float [[T1]], [[F1]]
+; CHECK-NEXT:    [[T3:%.*]] = fadd reassoc float [[T2]], [[F1]]
+; CHECK-NEXT:    ret float [[T3]]
+;
+  %t1 = fadd reassoc float %f1, %f1
+  %t2 = fadd reassoc float %f1, %t1
+  %t3 = fadd reassoc float %t2, %f1
+  ret float %t3
+}
+
+; C1 * X + (X + X) = (C1 + 2) * X
+define float @fold7(float %f1) {
+; CHECK-LABEL: @fold7(
+; CHECK-NEXT:    [[TMP1:%.*]] = fmul fast float [[F1:%.*]], 7.000000e+00
+; CHECK-NEXT:    ret float [[TMP1]]
+;
+  %t1 = fmul fast float %f1, 5.000000e+00
+  %t2 = fadd fast float %f1, %f1
+  %t3 = fadd fast float %t1, %t2
+  ret float %t3
+}
+
+; Check again with 'reassoc' and 'nsz' ('nsz' not technically required).
+define float @fold7_reassoc_nsz(float %f1) {
+; CHECK-LABEL: @fold7_reassoc_nsz(
+; CHECK-NEXT:    [[TMP1:%.*]] = fmul reassoc nsz float [[F1:%.*]], 7.000000e+00
+; CHECK-NEXT:    ret float [[TMP1]]
+;
+  %t1 = fmul reassoc nsz float %f1, 5.000000e+00
+  %t2 = fadd reassoc nsz float %f1, %f1
+  %t3 = fadd reassoc nsz float %t1, %t2
+  ret float %t3
+}
+
+; TODO: This doesn't require 'nsz'.  It should fold to f1 * 7.0.
+define float @fold7_reassoc(float %f1) {
+; CHECK-LABEL: @fold7_reassoc(
+; CHECK-NEXT:    [[T1:%.*]] = fmul reassoc float [[F1:%.*]], 5.000000e+00
+; CHECK-NEXT:    [[T2:%.*]] = fadd reassoc float [[F1]], [[F1]]
+; CHECK-NEXT:    [[T3:%.*]] = fadd reassoc float [[T1]], [[T2]]
+; CHECK-NEXT:    ret float [[T3]]
+;
+  %t1 = fmul reassoc float %f1, 5.000000e+00
+  %t2 = fadd reassoc float %f1, %f1
+  %t3 = fadd reassoc float %t1, %t2
+  ret float %t3
+}
+
+; (X + X) + (X + X) + X => 5.0 * X
+define float @fold8(float %f1) {
+; CHECK-LABEL: @fold8(
+; CHECK-NEXT:    [[TMP1:%.*]] = fmul fast float [[F1:%.*]], 5.000000e+00
+; CHECK-NEXT:    ret float [[TMP1]]
+;
+  %t1 = fadd fast float %f1, %f1
+  %t2 = fadd fast float %f1, %f1
+  %t3 = fadd fast float %t1, %t2
+  %t4 = fadd fast float %t3, %f1
+  ret float %t4
+}
+
+; Check again with 'reassoc' and 'nsz' ('nsz' not technically required).
+define float @fold8_reassoc_nsz(float %f1) {
+; CHECK-LABEL: @fold8_reassoc_nsz(
+; CHECK-NEXT:    [[TMP1:%.*]] = fmul reassoc nsz float [[F1:%.*]], 5.000000e+00
+; CHECK-NEXT:    ret float [[TMP1]]
+;
+  %t1 = fadd reassoc nsz float %f1, %f1
+  %t2 = fadd reassoc nsz float %f1, %f1
+  %t3 = fadd reassoc nsz float %t1, %t2
+  %t4 = fadd reassoc nsz float %t3, %f1
+  ret float %t4
+}
+
+; TODO: This doesn't require 'nsz'.  It should fold to f1 * 5.0.
+define float @fold8_reassoc(float %f1) {
+; CHECK-LABEL: @fold8_reassoc(
+; CHECK-NEXT:    [[T1:%.*]] = fadd reassoc float [[F1:%.*]], [[F1]]
+; CHECK-NEXT:    [[T2:%.*]] = fadd reassoc float [[F1]], [[F1]]
+; CHECK-NEXT:    [[T3:%.*]] = fadd reassoc float [[T1]], [[T2]]
+; CHECK-NEXT:    [[T4:%.*]] = fadd reassoc float [[T3]], [[F1]]
+; CHECK-NEXT:    ret float [[T4]]
+;
+  %t1 = fadd reassoc float %f1, %f1
+  %t2 = fadd reassoc float %f1, %f1
+  %t3 = fadd reassoc float %t1, %t2
+  %t4 = fadd reassoc float %t3, %f1
+  ret float %t4
+}
+
+; Y - (X + Y) --> -X
+
+define float @fsub_fadd_common_op_fneg(float %x, float %y) {
+; CHECK-LABEL: @fsub_fadd_common_op_fneg(
+; CHECK-NEXT:    [[R:%.*]] = fsub fast float -0.000000e+00, [[X:%.*]]
+; CHECK-NEXT:    ret float [[R]]
+;
+  %a = fadd float %x, %y
+  %r = fsub fast float %y, %a
+  ret float %r
+}
+
+; Y - (X + Y) --> -X
+; Check again with 'reassoc' and 'nsz'.
+; nsz is required because: 0.0 - (0.0 + 0.0) -> 0.0, not -0.0
+
+define float @fsub_fadd_common_op_fneg_reassoc_nsz(float %x, float %y) {
+; CHECK-LABEL: @fsub_fadd_common_op_fneg_reassoc_nsz(
+; CHECK-NEXT:    [[R:%.*]] = fsub reassoc nsz float -0.000000e+00, [[X:%.*]]
+; CHECK-NEXT:    ret float [[R]]
+;
+  %a = fadd float %x, %y
+  %r = fsub reassoc nsz float %y, %a
+  ret float %r
+}
+
+; Y - (X + Y) --> -X
+
+define <2 x float> @fsub_fadd_common_op_fneg_vec(<2 x float> %x, <2 x float> %y) {
+; CHECK-LABEL: @fsub_fadd_common_op_fneg_vec(
+; CHECK-NEXT:    [[R:%.*]] = fsub reassoc nsz <2 x float> <float -0.000000e+00, float -0.000000e+00>, [[X:%.*]]
+; CHECK-NEXT:    ret <2 x float> [[R]]
+;
+  %a = fadd <2 x float> %x, %y
+  %r = fsub nsz reassoc <2 x float> %y, %a
+  ret <2 x float> %r
+}
+
+; Y - (Y + X) --> -X
+; Commute operands of the 'add'.
+
+define float @fsub_fadd_common_op_fneg_commute(float %x, float %y) {
+; CHECK-LABEL: @fsub_fadd_common_op_fneg_commute(
+; CHECK-NEXT:    [[R:%.*]] = fsub reassoc nsz float -0.000000e+00, [[X:%.*]]
+; CHECK-NEXT:    ret float [[R]]
+;
+  %a = fadd float %y, %x
+  %r = fsub reassoc nsz float %y, %a
+  ret float %r
+}
+
+; Y - (Y + X) --> -X
+
+define <2 x float> @fsub_fadd_common_op_fneg_commute_vec(<2 x float> %x, <2 x float> %y) {
+; CHECK-LABEL: @fsub_fadd_common_op_fneg_commute_vec(
+; CHECK-NEXT:    [[R:%.*]] = fsub reassoc nsz <2 x float> <float -0.000000e+00, float -0.000000e+00>, [[X:%.*]]
+; CHECK-NEXT:    ret <2 x float> [[R]]
+;
+  %a = fadd <2 x float> %y, %x
+  %r = fsub reassoc nsz <2 x float> %y, %a
+  ret <2 x float> %r
+}
+
+; (Y - X) - Y --> -X
+; nsz is required because: (0.0 - 0.0) - 0.0 -> 0.0, not -0.0
+
+define float @fsub_fsub_common_op_fneg(float %x, float %y) {
+; CHECK-LABEL: @fsub_fsub_common_op_fneg(
+; CHECK-NEXT:    [[R:%.*]] = fsub reassoc nsz float -0.000000e+00, [[X:%.*]]
+; CHECK-NEXT:    ret float [[R]]
+;
+  %s = fsub float %y, %x
+  %r = fsub reassoc nsz float %s, %y
+  ret float %r
+}
+
+; (Y - X) - Y --> -X
+
+define <2 x float> @fsub_fsub_common_op_fneg_vec(<2 x float> %x, <2 x float> %y) {
+; CHECK-LABEL: @fsub_fsub_common_op_fneg_vec(
+; CHECK-NEXT:    [[R:%.*]] = fsub reassoc nsz <2 x float> <float -0.000000e+00, float -0.000000e+00>, [[X:%.*]]
+; CHECK-NEXT:    ret <2 x float> [[R]]
+;
+  %s = fsub <2 x float> %y, %x
+  %r = fsub reassoc nsz <2 x float> %s, %y
+  ret <2 x float> %r
+}
+
+; TODO: This doesn't require 'nsz'.  It should fold to 0 - f2
+define float @fold9_reassoc(float %f1, float %f2) {
+; CHECK-LABEL: @fold9_reassoc(
+; CHECK-NEXT:    [[T1:%.*]] = fadd float [[F1:%.*]], [[F2:%.*]]
+; CHECK-NEXT:    [[T3:%.*]] = fsub reassoc float [[F1]], [[T1]]
+; CHECK-NEXT:    ret float [[T3]]
+;
+  %t1 = fadd float %f1, %f2
+  %t3 = fsub reassoc float %f1, %t1
+  ret float %t3
+}
+
+; Let C3 = C1 + C2. (f1 + C1) + (f2 + C2) => (f1 + f2) + C3 instead of
+; "(f1 + C3) + f2" or "(f2 + C3) + f1". Placing constant-addend at the
+; top of resulting simplified expression tree may potentially reveal some
+; optimization opportunities in the super-expression trees.
+;
+define float @fold10(float %f1, float %f2) {
+; CHECK-LABEL: @fold10(
+; CHECK-NEXT:    [[T2:%.*]] = fadd fast float [[F1:%.*]], [[F2:%.*]]
+; CHECK-NEXT:    [[T3:%.*]] = fadd fast float [[T2]], -1.000000e+00
+; CHECK-NEXT:    ret float [[T3]]
+;
+  %t1 = fadd fast float 2.000000e+00, %f1
+  %t2 = fsub fast float %f2, 3.000000e+00
+  %t3 = fadd fast float %t1, %t2
+  ret float %t3
+}
+
+; Check again with 'reassoc' and 'nsz'.
+; TODO: We may be able to remove the 'nsz' requirement.
+define float @fold10_reassoc_nsz(float %f1, float %f2) {
+; CHECK-LABEL: @fold10_reassoc_nsz(
+; CHECK-NEXT:    [[T2:%.*]] = fadd reassoc nsz float [[F1:%.*]], [[F2:%.*]]
+; CHECK-NEXT:    [[T3:%.*]] = fadd reassoc nsz float [[T2]], -1.000000e+00
+; CHECK-NEXT:    ret float [[T3]]
+;
+  %t1 = fadd reassoc nsz float 2.000000e+00, %f1
+  %t2 = fsub reassoc nsz float %f2, 3.000000e+00
+  %t3 = fadd reassoc nsz float %t1, %t2
+  ret float %t3
+}
+
+; Observe that the fold is not done with only reassoc (the instructions are
+; canonicalized, but not folded).
+; TODO: As noted above, 'nsz' may not be required for this to be fully folded.
+define float @fold10_reassoc(float %f1, float %f2) {
+; CHECK-LABEL: @fold10_reassoc(
+; CHECK-NEXT:    [[T1:%.*]] = fadd reassoc float [[F1:%.*]], 2.000000e+00
+; CHECK-NEXT:    [[T2:%.*]] = fadd reassoc float [[F2:%.*]], -3.000000e+00
+; CHECK-NEXT:    [[T3:%.*]] = fadd reassoc float [[T1]], [[T2]]
+; CHECK-NEXT:    ret float [[T3]]
+;
+  %t1 = fadd reassoc float 2.000000e+00, %f1
+  %t2 = fsub reassoc float %f2, 3.000000e+00
+  %t3 = fadd reassoc float %t1, %t2
+  ret float %t3
+}
+
+; This used to crash/miscompile.
+
+define float @fail1(float %f1, float %f2) {
+; CHECK-LABEL: @fail1(
+; CHECK-NEXT:    [[TMP1:%.*]] = fmul fast float [[F1:%.*]], 3.000000e+00
+; CHECK-NEXT:    [[TMP2:%.*]] = fadd fast float [[TMP1]], -3.000000e+00
+; CHECK-NEXT:    ret float [[TMP2]]
+;
+  %conv3 = fadd fast float %f1, -1.000000e+00
+  %add = fadd fast float %conv3, %conv3
+  %add2 = fadd fast float %add, %conv3
+  ret float %add2
+}
+
+define double @fail2(double %f1, double %f2) {
+; CHECK-LABEL: @fail2(
+; CHECK-NEXT:    [[TMP1:%.*]] = fadd fast double [[F2:%.*]], [[F2]]
+; CHECK-NEXT:    [[TMP2:%.*]] = fsub fast double -0.000000e+00, [[TMP1]]
+; CHECK-NEXT:    ret double [[TMP2]]
+;
+  %t1 = fsub fast double %f1, %f2
+  %t2 = fadd fast double %f1, %f2
+  %t3 = fsub fast double %t1, %t2
+  ret double %t3
+}
+
+; (X * C) - X --> X * (C - 1.0)
+
+define float @fsub_op0_fmul_const(float %x) {
+; CHECK-LABEL: @fsub_op0_fmul_const(
+; CHECK-NEXT:    [[SUB:%.*]] = fmul reassoc nsz float [[X:%.*]], 6.000000e+00
+; CHECK-NEXT:    ret float [[SUB]]
+;
+  %mul = fmul float %x, 7.0
+  %sub = fsub reassoc nsz float %mul, %x
+  ret float %sub
+}
+
+; (X * C) - X --> X * (C - 1.0)
+
+define <2 x float> @fsub_op0_fmul_const_vec(<2 x float> %x) {
+; CHECK-LABEL: @fsub_op0_fmul_const_vec(
+; CHECK-NEXT:    [[SUB:%.*]] = fmul reassoc nsz <2 x float> [[X:%.*]], <float 6.000000e+00, float -4.300000e+01>
+; CHECK-NEXT:    ret <2 x float> [[SUB]]
+;
+  %mul = fmul <2 x float> %x, <float 7.0, float -42.0>
+  %sub = fsub reassoc nsz <2 x float> %mul, %x
+  ret <2 x float> %sub
+}
+
+; X - (X * C) --> X * (1.0 - C)
+
+define float @fsub_op1_fmul_const(float %x) {
+; CHECK-LABEL: @fsub_op1_fmul_const(
+; CHECK-NEXT:    [[SUB:%.*]] = fmul reassoc nsz float [[X:%.*]], -6.000000e+00
+; CHECK-NEXT:    ret float [[SUB]]
+;
+  %mul = fmul float %x, 7.0
+  %sub = fsub reassoc nsz float %x, %mul
+  ret float %sub
+}
+
+; X - (X * C) --> X * (1.0 - C)
+
+define <2 x float> @fsub_op1_fmul_const_vec(<2 x float> %x) {
+; CHECK-LABEL: @fsub_op1_fmul_const_vec(
+; CHECK-NEXT:    [[SUB:%.*]] = fmul reassoc nsz <2 x float> [[X:%.*]], <float -6.000000e+00, float 1.000000e+00>
+; CHECK-NEXT:    ret <2 x float> [[SUB]]
+;
+  %mul = fmul <2 x float> %x, <float 7.0, float 0.0>
+  %sub = fsub reassoc nsz <2 x float> %x, %mul
+  ret <2 x float> %sub
+}
+
+; Verify the fold is not done with only 'reassoc' ('nsz' is required).
+
+define float @fsub_op0_fmul_const_wrong_FMF(float %x) {
+; CHECK-LABEL: @fsub_op0_fmul_const_wrong_FMF(
+; CHECK-NEXT:    [[MUL:%.*]] = fmul reassoc float [[X:%.*]], 7.000000e+00
+; CHECK-NEXT:    [[SUB:%.*]] = fsub reassoc float [[MUL]], [[X]]
+; CHECK-NEXT:    ret float [[SUB]]
+;
+  %mul = fmul reassoc float %x, 7.0
+  %sub = fsub reassoc float %mul, %x
+  ret float %sub
+}
+
+; (select X+Y, X-Y) => X + (select Y, -Y)
+; This is always safe.  No FMF required.
+define float @fold16(float %x, float %y) {
+; CHECK-LABEL: @fold16(
+; CHECK-NEXT:    [[CMP:%.*]] = fcmp ogt float [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    [[TMP1:%.*]] = fsub float -0.000000e+00, [[Y]]
+; CHECK-NEXT:    [[R_P:%.*]] = select i1 [[CMP]], float [[Y]], float [[TMP1]]
+; CHECK-NEXT:    [[R:%.*]] = fadd float [[R_P]], [[X]]
+; CHECK-NEXT:    ret float [[R]]
+;
+  %cmp = fcmp ogt float %x, %y
+  %plus = fadd float %x, %y
+  %minus = fsub float %x, %y
+  %r = select i1 %cmp, float %plus, float %minus
+  ret float %r
+}
+
+; =========================================================================
+;
+;   Testing-cases about negation
+;
+; =========================================================================
+define float @fneg1(float %f1, float %f2) {
+; CHECK-LABEL: @fneg1(
+; CHECK-NEXT:    [[MUL:%.*]] = fmul float [[F1:%.*]], [[F2:%.*]]
+; CHECK-NEXT:    ret float [[MUL]]
+;
+  %sub = fsub float -0.000000e+00, %f1
+  %sub1 = fsub nsz float 0.000000e+00, %f2
+  %mul = fmul float %sub, %sub1
+  ret float %mul
+}
+
+define float @fneg2(float %x) {
+; CHECK-LABEL: @fneg2(
+; CHECK-NEXT:    [[SUB:%.*]] = fsub nsz float -0.000000e+00, [[X:%.*]]
+; CHECK-NEXT:    ret float [[SUB]]
+;
+  %sub = fsub nsz float 0.0, %x
+  ret float %sub
+}
+
+define <2 x float> @fneg2_vec_undef(<2 x float> %x) {
+; CHECK-LABEL: @fneg2_vec_undef(
+; CHECK-NEXT:    [[SUB:%.*]] = fsub nsz <2 x float> <float -0.000000e+00, float -0.000000e+00>, [[X:%.*]]
+; CHECK-NEXT:    ret <2 x float> [[SUB]]
+;
+  %sub = fsub nsz <2 x float> <float undef, float 0.0>, %x
+  ret <2 x float> %sub
+}
+
+; =========================================================================
+;
+;   Testing-cases about div
+;
+; =========================================================================
+
+; X/C1 / C2 => X * (1/(C2*C1))
+define float @fdiv1(float %x) {
+; CHECK-LABEL: @fdiv1(
+; CHECK-NEXT:    [[DIV1:%.*]] = fmul fast float [[X:%.*]], 0x3FD7303B60000000
+; CHECK-NEXT:    ret float [[DIV1]]
+;
+  %div = fdiv float %x, 0x3FF3333340000000
+  %div1 = fdiv fast float %div, 0x4002666660000000
+  ret float %div1
+; 0x3FF3333340000000 = 1.2f
+; 0x4002666660000000 = 2.3f
+; 0x3FD7303B60000000 = 0.36231884057971014492
+}
+
+; X*C1 / C2 => X * (C1/C2)
+define float @fdiv2(float %x) {
+; CHECK-LABEL: @fdiv2(
+; CHECK-NEXT:    [[DIV1:%.*]] = fmul fast float [[X:%.*]], 0x3FE0B21660000000
+; CHECK-NEXT:    ret float [[DIV1]]
+;
+  %mul = fmul float %x, 0x3FF3333340000000
+  %div1 = fdiv fast float %mul, 0x4002666660000000
+  ret float %div1
+
+; 0x3FF3333340000000 = 1.2f
+; 0x4002666660000000 = 2.3f
+; 0x3FE0B21660000000 = 0.52173918485641479492
+}
+
+define <2 x float> @fdiv2_vec(<2 x float> %x) {
+; CHECK-LABEL: @fdiv2_vec(
+; CHECK-NEXT:    [[DIV1:%.*]] = fmul fast <2 x float> [[X:%.*]], <float 3.000000e+00, float 3.000000e+00>
+; CHECK-NEXT:    ret <2 x float> [[DIV1]]
+;
+  %mul = fmul <2 x float> %x, <float 6.0, float 9.0>
+  %div1 = fdiv fast <2 x float> %mul, <float 2.0, float 3.0>
+  ret <2 x float> %div1
+}
+
+; "X/C1 / C2 => X * (1/(C2*C1))" is disabled (for now) is C2/C1 is a denormal
+;
+define float @fdiv3(float %x) {
+; CHECK-LABEL: @fdiv3(
+; CHECK-NEXT:    [[TMP1:%.*]] = fmul fast float [[X:%.*]], 0x3FDBD37A80000000
+; CHECK-NEXT:    [[DIV1:%.*]] = fdiv fast float [[TMP1]], 0x47EFFFFFE0000000
+; CHECK-NEXT:    ret float [[DIV1]]
+;
+  %div = fdiv float %x, 0x47EFFFFFE0000000
+  %div1 = fdiv fast float %div, 0x4002666660000000
+  ret float %div1
+}
+
+; "X*C1 / C2 => X * (C1/C2)" is disabled if C1/C2 is a denormal
+define float @fdiv4(float %x) {
+; CHECK-LABEL: @fdiv4(
+; CHECK-NEXT:    [[MUL:%.*]] = fmul float [[X:%.*]], 0x47EFFFFFE0000000
+; CHECK-NEXT:    [[DIV:%.*]] = fdiv float [[MUL]], 0x3FC99999A0000000
+; CHECK-NEXT:    ret float [[DIV]]
+;
+  %mul = fmul float %x, 0x47EFFFFFE0000000
+  %div = fdiv float %mul, 0x3FC99999A0000000
+  ret float %div
+}
+
+; =========================================================================
+;
+;   Test-cases for square root
+;
+; =========================================================================
+
+; A squared factor fed into a square root intrinsic should be hoisted out
+; as a fabs() value.
+
+declare double @llvm.sqrt.f64(double)
+
+define double @sqrt_intrinsic_arg_squared(double %x) {
+; CHECK-LABEL: @sqrt_intrinsic_arg_squared(
+; CHECK-NEXT:    [[FABS:%.*]] = call fast double @llvm.fabs.f64(double [[X:%.*]])
+; CHECK-NEXT:    ret double [[FABS]]
+;
+  %mul = fmul fast double %x, %x
+  %sqrt = call fast double @llvm.sqrt.f64(double %mul)
+  ret double %sqrt
+}
+
+; Check all 6 combinations of a 3-way multiplication tree where
+; one factor is repeated.
+
+define double @sqrt_intrinsic_three_args1(double %x, double %y) {
+; CHECK-LABEL: @sqrt_intrinsic_three_args1(
+; CHECK-NEXT:    [[FABS:%.*]] = call fast double @llvm.fabs.f64(double [[X:%.*]])
+; CHECK-NEXT:    [[SQRT1:%.*]] = call fast double @llvm.sqrt.f64(double [[Y:%.*]])
+; CHECK-NEXT:    [[TMP1:%.*]] = fmul fast double [[FABS]], [[SQRT1]]
+; CHECK-NEXT:    ret double [[TMP1]]
+;
+  %mul = fmul fast double %y, %x
+  %mul2 = fmul fast double %mul, %x
+  %sqrt = call fast double @llvm.sqrt.f64(double %mul2)
+  ret double %sqrt
+}
+
+define double @sqrt_intrinsic_three_args2(double %x, double %y) {
+; CHECK-LABEL: @sqrt_intrinsic_three_args2(
+; CHECK-NEXT:    [[FABS:%.*]] = call fast double @llvm.fabs.f64(double [[X:%.*]])
+; CHECK-NEXT:    [[SQRT1:%.*]] = call fast double @llvm.sqrt.f64(double [[Y:%.*]])
+; CHECK-NEXT:    [[TMP1:%.*]] = fmul fast double [[FABS]], [[SQRT1]]
+; CHECK-NEXT:    ret double [[TMP1]]
+;
+  %mul = fmul fast double %x, %y
+  %mul2 = fmul fast double %mul, %x
+  %sqrt = call fast double @llvm.sqrt.f64(double %mul2)
+  ret double %sqrt
+}
+
+define double @sqrt_intrinsic_three_args3(double %x, double %y) {
+; CHECK-LABEL: @sqrt_intrinsic_three_args3(
+; CHECK-NEXT:    [[FABS:%.*]] = call fast double @llvm.fabs.f64(double [[X:%.*]])
+; CHECK-NEXT:    [[SQRT1:%.*]] = call fast double @llvm.sqrt.f64(double [[Y:%.*]])
+; CHECK-NEXT:    [[TMP1:%.*]] = fmul fast double [[FABS]], [[SQRT1]]
+; CHECK-NEXT:    ret double [[TMP1]]
+;
+  %mul = fmul fast double %x, %x
+  %mul2 = fmul fast double %mul, %y
+  %sqrt = call fast double @llvm.sqrt.f64(double %mul2)
+  ret double %sqrt
+}
+
+define double @sqrt_intrinsic_three_args4(double %x, double %y) {
+; CHECK-LABEL: @sqrt_intrinsic_three_args4(
+; CHECK-NEXT:    [[FABS:%.*]] = call fast double @llvm.fabs.f64(double [[X:%.*]])
+; CHECK-NEXT:    [[SQRT1:%.*]] = call fast double @llvm.sqrt.f64(double [[Y:%.*]])
+; CHECK-NEXT:    [[TMP1:%.*]] = fmul fast double [[FABS]], [[SQRT1]]
+; CHECK-NEXT:    ret double [[TMP1]]
+;
+  %mul = fmul fast double %y, %x
+  %mul2 = fmul fast double %x, %mul
+  %sqrt = call fast double @llvm.sqrt.f64(double %mul2)
+  ret double %sqrt
+}
+
+define double @sqrt_intrinsic_three_args5(double %x, double %y) {
+; CHECK-LABEL: @sqrt_intrinsic_three_args5(
+; CHECK-NEXT:    [[FABS:%.*]] = call fast double @llvm.fabs.f64(double [[X:%.*]])
+; CHECK-NEXT:    [[SQRT1:%.*]] = call fast double @llvm.sqrt.f64(double [[Y:%.*]])
+; CHECK-NEXT:    [[TMP1:%.*]] = fmul fast double [[FABS]], [[SQRT1]]
+; CHECK-NEXT:    ret double [[TMP1]]
+;
+  %mul = fmul fast double %x, %y
+  %mul2 = fmul fast double %x, %mul
+  %sqrt = call fast double @llvm.sqrt.f64(double %mul2)
+  ret double %sqrt
+}
+
+define double @sqrt_intrinsic_three_args6(double %x, double %y) {
+; CHECK-LABEL: @sqrt_intrinsic_three_args6(
+; CHECK-NEXT:    [[FABS:%.*]] = call fast double @llvm.fabs.f64(double [[X:%.*]])
+; CHECK-NEXT:    [[SQRT1:%.*]] = call fast double @llvm.sqrt.f64(double [[Y:%.*]])
+; CHECK-NEXT:    [[TMP1:%.*]] = fmul fast double [[FABS]], [[SQRT1]]
+; CHECK-NEXT:    ret double [[TMP1]]
+;
+  %mul = fmul fast double %x, %x
+  %mul2 = fmul fast double %y, %mul
+  %sqrt = call fast double @llvm.sqrt.f64(double %mul2)
+  ret double %sqrt
+}
+
+; If any operation is not 'fast', we can't simplify.
+
+define double @sqrt_intrinsic_not_so_fast(double %x, double %y) {
+; CHECK-LABEL: @sqrt_intrinsic_not_so_fast(
+; CHECK-NEXT:    [[MUL:%.*]] = fmul double [[X:%.*]], [[X]]
+; CHECK-NEXT:    [[MUL2:%.*]] = fmul fast double [[MUL]], [[Y:%.*]]
+; CHECK-NEXT:    [[SQRT:%.*]] = call fast double @llvm.sqrt.f64(double [[MUL2]])
+; CHECK-NEXT:    ret double [[SQRT]]
+;
+  %mul = fmul double %x, %x
+  %mul2 = fmul fast double %mul, %y
+  %sqrt = call fast double @llvm.sqrt.f64(double %mul2)
+  ret double %sqrt
+}
+
+define double @sqrt_intrinsic_arg_4th(double %x) {
+; CHECK-LABEL: @sqrt_intrinsic_arg_4th(
+; CHECK-NEXT:    [[MUL:%.*]] = fmul fast double [[X:%.*]], [[X]]
+; CHECK-NEXT:    ret double [[MUL]]
+;
+  %mul = fmul fast double %x, %x
+  %mul2 = fmul fast double %mul, %mul
+  %sqrt = call fast double @llvm.sqrt.f64(double %mul2)
+  ret double %sqrt
+}
+
+define double @sqrt_intrinsic_arg_5th(double %x) {
+; CHECK-LABEL: @sqrt_intrinsic_arg_5th(
+; CHECK-NEXT:    [[MUL:%.*]] = fmul fast double [[X:%.*]], [[X]]
+; CHECK-NEXT:    [[SQRT1:%.*]] = call fast double @llvm.sqrt.f64(double [[X]])
+; CHECK-NEXT:    [[TMP1:%.*]] = fmul fast double [[MUL]], [[SQRT1]]
+; CHECK-NEXT:    ret double [[TMP1]]
+;
+  %mul = fmul fast double %x, %x
+  %mul2 = fmul fast double %mul, %x
+  %mul3 = fmul fast double %mul2, %mul
+  %sqrt = call fast double @llvm.sqrt.f64(double %mul3)
+  ret double %sqrt
+}
+
+; Check that square root calls have the same behavior.
+
+declare float @sqrtf(float)
+declare double @sqrt(double)
+declare fp128 @sqrtl(fp128)
+
+define float @sqrt_call_squared_f32(float %x) {
+; CHECK-LABEL: @sqrt_call_squared_f32(
+; CHECK-NEXT:    [[FABS:%.*]] = call fast float @llvm.fabs.f32(float [[X:%.*]])
+; CHECK-NEXT:    ret float [[FABS]]
+;
+  %mul = fmul fast float %x, %x
+  %sqrt = call fast float @sqrtf(float %mul)
+  ret float %sqrt
+}
+
+define double @sqrt_call_squared_f64(double %x) {
+; CHECK-LABEL: @sqrt_call_squared_f64(
+; CHECK-NEXT:    [[FABS:%.*]] = call fast double @llvm.fabs.f64(double [[X:%.*]])
+; CHECK-NEXT:    ret double [[FABS]]
+;
+  %mul = fmul fast double %x, %x
+  %sqrt = call fast double @sqrt(double %mul)
+  ret double %sqrt
+}
+
+define fp128 @sqrt_call_squared_f128(fp128 %x) {
+; CHECK-LABEL: @sqrt_call_squared_f128(
+; CHECK-NEXT:    [[FABS:%.*]] = call fast fp128 @llvm.fabs.f128(fp128 [[X:%.*]])
+; CHECK-NEXT:    ret fp128 [[FABS]]
+;
+  %mul = fmul fast fp128 %x, %x
+  %sqrt = call fast fp128 @sqrtl(fp128 %mul)
+  ret fp128 %sqrt
+}
+
+; =========================================================================
+;
+;   Test-cases for fmin / fmax
+;
+; =========================================================================
+
+declare double @fmax(double, double)
+declare double @fmin(double, double)
+declare float @fmaxf(float, float)
+declare float @fminf(float, float)
+declare fp128 @fmaxl(fp128, fp128)
+declare fp128 @fminl(fp128, fp128)
+
+; No NaNs is the minimum requirement to replace these calls.
+; This should always be set when unsafe-fp-math is true, but
+; alternate the attributes for additional test coverage.
+; 'nsz' is implied by the definition of fmax or fmin itself.
+
+; Shrink and remove the call.
+define float @max1(float %a, float %b) {
+; CHECK-LABEL: @max1(
+; CHECK-NEXT:    [[TMP1:%.*]] = fcmp fast ogt float [[A:%.*]], [[B:%.*]]
+; CHECK-NEXT:    [[TMP2:%.*]] = select i1 [[TMP1]], float [[A]], float [[B]]
+; CHECK-NEXT:    ret float [[TMP2]]
+;
+  %c = fpext float %a to double
+  %d = fpext float %b to double
+  %e = call fast double @fmax(double %c, double %d)
+  %f = fptrunc double %e to float
+  ret float %f
+}
+
+define float @max2(float %a, float %b) {
+; CHECK-LABEL: @max2(
+; CHECK-NEXT:    [[TMP1:%.*]] = fcmp nnan nsz ogt float [[A:%.*]], [[B:%.*]]
+; CHECK-NEXT:    [[TMP2:%.*]] = select i1 [[TMP1]], float [[A]], float [[B]]
+; CHECK-NEXT:    ret float [[TMP2]]
+;
+  %c = call nnan float @fmaxf(float %a, float %b)
+  ret float %c
+}
+
+
+define double @max3(double %a, double %b) {
+; CHECK-LABEL: @max3(
+; CHECK-NEXT:    [[TMP1:%.*]] = fcmp fast ogt double [[A:%.*]], [[B:%.*]]
+; CHECK-NEXT:    [[TMP2:%.*]] = select i1 [[TMP1]], double [[A]], double [[B]]
+; CHECK-NEXT:    ret double [[TMP2]]
+;
+  %c = call fast double @fmax(double %a, double %b)
+  ret double %c
+}
+
+define fp128 @max4(fp128 %a, fp128 %b) {
+; CHECK-LABEL: @max4(
+; CHECK-NEXT:    [[TMP1:%.*]] = fcmp nnan nsz ogt fp128 [[A:%.*]], [[B:%.*]]
+; CHECK-NEXT:    [[TMP2:%.*]] = select i1 [[TMP1]], fp128 [[A]], fp128 [[B]]
+; CHECK-NEXT:    ret fp128 [[TMP2]]
+;
+  %c = call nnan fp128 @fmaxl(fp128 %a, fp128 %b)
+  ret fp128 %c
+}
+
+; Shrink and remove the call.
+define float @min1(float %a, float %b) {
+; CHECK-LABEL: @min1(
+; CHECK-NEXT:    [[TMP1:%.*]] = fcmp nnan nsz olt float [[A:%.*]], [[B:%.*]]
+; CHECK-NEXT:    [[TMP2:%.*]] = select i1 [[TMP1]], float [[A]], float [[B]]
+; CHECK-NEXT:    ret float [[TMP2]]
+;
+  %c = fpext float %a to double
+  %d = fpext float %b to double
+  %e = call nnan double @fmin(double %c, double %d)
+  %f = fptrunc double %e to float
+  ret float %f
+}
+
+define float @min2(float %a, float %b) {
+; CHECK-LABEL: @min2(
+; CHECK-NEXT:    [[TMP1:%.*]] = fcmp fast olt float [[A:%.*]], [[B:%.*]]
+; CHECK-NEXT:    [[TMP2:%.*]] = select i1 [[TMP1]], float [[A]], float [[B]]
+; CHECK-NEXT:    ret float [[TMP2]]
+;
+  %c = call fast float @fminf(float %a, float %b)
+  ret float %c
+}
+
+define double @min3(double %a, double %b) {
+; CHECK-LABEL: @min3(
+; CHECK-NEXT:    [[TMP1:%.*]] = fcmp nnan nsz olt double [[A:%.*]], [[B:%.*]]
+; CHECK-NEXT:    [[TMP2:%.*]] = select i1 [[TMP1]], double [[A]], double [[B]]
+; CHECK-NEXT:    ret double [[TMP2]]
+;
+  %c = call nnan double @fmin(double %a, double %b)
+  ret double %c
+}
+
+define fp128 @min4(fp128 %a, fp128 %b) {
+; CHECK-LABEL: @min4(
+; CHECK-NEXT:    [[TMP1:%.*]] = fcmp fast olt fp128 [[A:%.*]], [[B:%.*]]
+; CHECK-NEXT:    [[TMP2:%.*]] = select i1 [[TMP1]], fp128 [[A]], fp128 [[B]]
+; CHECK-NEXT:    ret fp128 [[TMP2]]
+;
+  %c = call fast fp128 @fminl(fp128 %a, fp128 %b)
+  ret fp128 %c
+}
+
+; ((which ? 2.0 : a) + 1.0) => (which ? 3.0 : (a + 1.0))
+; This is always safe.  No FMF required.
+define float @test55(i1 %which, float %a) {
+; CHECK-LABEL: @test55(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    br i1 [[WHICH:%.*]], label [[FINAL:%.*]], label [[DELAY:%.*]]
+; CHECK:       delay:
+; CHECK-NEXT:    [[PHITMP:%.*]] = fadd float [[A:%.*]], 1.000000e+00
+; CHECK-NEXT:    br label [[FINAL]]
+; CHECK:       final:
+; CHECK-NEXT:    [[A:%.*]] = phi float [ 3.000000e+00, [[ENTRY:%.*]] ], [ [[PHITMP]], [[DELAY]] ]
+; CHECK-NEXT:    ret float [[A]]
+;
+entry:
+  br i1 %which, label %final, label %delay
+
+delay:
+  br label %final
+
+final:
+  %A = phi float [ 2.0, %entry ], [ %a, %delay ]
+  %value = fadd float %A, 1.0
+  ret float %value
+}

Added: llvm/trunk/test/Transforms/InstCombine/fcmp-select.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/fcmp-select.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/fcmp-select.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/fcmp-select.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,116 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt < %s -instcombine -S | FileCheck %s
+
+declare void @use(i1)
+
+; X == 42.0 ? X : 42.0 --> 42.0
+
+define double @oeq(double %x) {
+; CHECK-LABEL: @oeq(
+; CHECK-NEXT:    [[CMP:%.*]] = fcmp oeq double [[X:%.*]], 4.200000e+01
+; CHECK-NEXT:    call void @use(i1 [[CMP]])
+; CHECK-NEXT:    ret double 4.200000e+01
+;
+  %cmp = fcmp oeq double %x, 42.0
+  call void @use(i1 %cmp)      ; extra use to thwart predicate canonicalization
+  %cond = select i1 %cmp, double %x, double 42.0
+  ret double %cond
+}
+
+; X == 42.0 ? 42.0 : X --> X
+
+define float @oeq_swapped(float %x) {
+; CHECK-LABEL: @oeq_swapped(
+; CHECK-NEXT:    [[CMP:%.*]] = fcmp oeq float [[X:%.*]], 4.200000e+01
+; CHECK-NEXT:    call void @use(i1 [[CMP]])
+; CHECK-NEXT:    ret float [[X]]
+;
+  %cmp = fcmp oeq float %x, 42.0
+  call void @use(i1 %cmp)      ; extra use to thwart predicate canonicalization
+  %cond = select i1 %cmp, float 42.0, float %x
+  ret float %cond
+}
+
+; x != y ? x : y -> x if it's the right kind of != and at least
+; one of x and y is not negative zero.
+
+; X != 42.0 ? X : 42.0 --> X
+
+define double @une(double %x) {
+; CHECK-LABEL: @une(
+; CHECK-NEXT:    [[CMP:%.*]] = fcmp une double [[X:%.*]], 4.200000e+01
+; CHECK-NEXT:    call void @use(i1 [[CMP]])
+; CHECK-NEXT:    ret double [[X]]
+;
+  %cmp = fcmp une double %x, 42.0
+  call void @use(i1 %cmp)      ; extra use to thwart predicate canonicalization
+  %cond = select i1 %cmp, double %x, double 42.0
+  ret double %cond
+}
+
+; X != 42.0 ? 42.0 : X --> 42.0
+
+define double @une_swapped(double %x) {
+; CHECK-LABEL: @une_swapped(
+; CHECK-NEXT:    [[CMP:%.*]] = fcmp une double [[X:%.*]], 4.200000e+01
+; CHECK-NEXT:    call void @use(i1 [[CMP]])
+; CHECK-NEXT:    ret double 4.200000e+01
+;
+  %cmp = fcmp une double %x, 42.0
+  call void @use(i1 %cmp)      ; extra use to thwart predicate canonicalization
+  %cond = select i1 %cmp, double 42.0, double %x
+  ret double %cond
+}
+
+define double @une_could_be_negzero(double %x, double %y) {
+; CHECK-LABEL: @une_could_be_negzero(
+; CHECK-NEXT:    [[CMP:%.*]] = fcmp une double [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    call void @use(i1 [[CMP]])
+; CHECK-NEXT:    [[COND:%.*]] = select i1 [[CMP]], double [[X]], double [[Y]]
+; CHECK-NEXT:    ret double [[COND]]
+;
+  %cmp = fcmp une double %x, %y
+  call void @use(i1 %cmp)      ; extra use to thwart predicate canonicalization
+  %cond = select i1 %cmp, double %x, double %y
+  ret double %cond
+}
+
+define double @une_swapped_could_be_negzero(double %x, double %y) {
+; CHECK-LABEL: @une_swapped_could_be_negzero(
+; CHECK-NEXT:    [[CMP:%.*]] = fcmp une double [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    call void @use(i1 [[CMP]])
+; CHECK-NEXT:    [[COND:%.*]] = select i1 [[CMP]], double [[Y]], double [[X]]
+; CHECK-NEXT:    ret double [[COND]]
+;
+  %cmp = fcmp une double %x, %y
+  call void @use(i1 %cmp)      ; extra use to thwart predicate canonicalization
+  %cond = select i1 %cmp, double %y, double %x
+  ret double %cond
+}
+
+define double @one(double %x) {
+; CHECK-LABEL: @one(
+; CHECK-NEXT:    [[CMP:%.*]] = fcmp one double [[X:%.*]], -1.000000e+00
+; CHECK-NEXT:    call void @use(i1 [[CMP]])
+; CHECK-NEXT:    [[COND:%.*]] = select i1 [[CMP]], double [[X]], double -1.000000e+00
+; CHECK-NEXT:    ret double [[COND]]
+;
+  %cmp = fcmp one double %x, -1.0
+  call void @use(i1 %cmp)      ; extra use to thwart predicate canonicalization
+  %cond = select i1 %cmp, double %x, double -1.0
+  ret double %cond
+}
+
+define double @one_swapped(double %x) {
+; CHECK-LABEL: @one_swapped(
+; CHECK-NEXT:    [[CMP:%.*]] = fcmp one double [[X:%.*]], -1.000000e+00
+; CHECK-NEXT:    call void @use(i1 [[CMP]])
+; CHECK-NEXT:    [[COND:%.*]] = select i1 [[CMP]], double -1.000000e+00, double [[X]]
+; CHECK-NEXT:    ret double [[COND]]
+;
+  %cmp = fcmp one double %x, -1.0
+  call void @use(i1 %cmp)      ; extra use to thwart predicate canonicalization
+  %cond = select i1 %cmp, double -1.0, double %x
+  ret double %cond
+}
+

Added: llvm/trunk/test/Transforms/InstCombine/fcmp-special.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/fcmp-special.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/fcmp-special.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/fcmp-special.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,244 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt < %s -instcombine -S | FileCheck %s
+
+define i1 @oeq_self(double %arg) {
+; CHECK-LABEL: @oeq_self(
+; CHECK-NEXT:    [[TMP:%.*]] = fcmp ord double [[ARG:%.*]], 0.000000e+00
+; CHECK-NEXT:    ret i1 [[TMP]]
+;
+  %tmp = fcmp oeq double %arg, %arg
+  ret i1 %tmp
+}
+
+; PR1111 - https://bugs.llvm.org/show_bug.cgi?id=1111
+
+define i1 @une_self(double %x) {
+; CHECK-LABEL: @une_self(
+; CHECK-NEXT:    [[TMP:%.*]] = fcmp uno double [[X:%.*]], 0.000000e+00
+; CHECK-NEXT:    ret i1 [[TMP]]
+;
+  %tmp = fcmp une double %x, %x
+  ret i1 %tmp
+}
+
+; When just checking for a NaN (ORD/UNO), canonicalize constants.
+; Float/double are alternated for additional coverage.
+
+define i1 @ord_zero(float %x) {
+; CHECK-LABEL: @ord_zero(
+; CHECK-NEXT:    [[F:%.*]] = fcmp ord float [[X:%.*]], 0.000000e+00
+; CHECK-NEXT:    ret i1 [[F]]
+;
+  %f = fcmp ord float %x, 0.0
+  ret i1 %f
+}
+
+define i1 @ord_nonzero(double %x) {
+; CHECK-LABEL: @ord_nonzero(
+; CHECK-NEXT:    [[F:%.*]] = fcmp ord double [[X:%.*]], 0.000000e+00
+; CHECK-NEXT:    ret i1 [[F]]
+;
+  %f = fcmp ord double %x, 3.0
+  ret i1 %f
+}
+
+define i1 @ord_self(float %x) {
+; CHECK-LABEL: @ord_self(
+; CHECK-NEXT:    [[F:%.*]] = fcmp ord float [[X:%.*]], 0.000000e+00
+; CHECK-NEXT:    ret i1 [[F]]
+;
+  %f = fcmp ord float %x, %x
+  ret i1 %f
+}
+
+define i1 @uno_zero(double %x) {
+; CHECK-LABEL: @uno_zero(
+; CHECK-NEXT:    [[F:%.*]] = fcmp uno double [[X:%.*]], 0.000000e+00
+; CHECK-NEXT:    ret i1 [[F]]
+;
+  %f = fcmp uno double %x, 0.0
+  ret i1 %f
+}
+
+define i1 @uno_nonzero(float %x) {
+; CHECK-LABEL: @uno_nonzero(
+; CHECK-NEXT:    [[F:%.*]] = fcmp uno float [[X:%.*]], 0.000000e+00
+; CHECK-NEXT:    ret i1 [[F]]
+;
+  %f = fcmp uno float %x, 3.0
+  ret i1 %f
+}
+
+define i1 @uno_self(double %x) {
+; CHECK-LABEL: @uno_self(
+; CHECK-NEXT:    [[F:%.*]] = fcmp uno double [[X:%.*]], 0.000000e+00
+; CHECK-NEXT:    ret i1 [[F]]
+;
+  %f = fcmp uno double %x, %x
+  ret i1 %f
+}
+
+define <2 x i1> @ord_zero_vec(<2 x double> %x) {
+; CHECK-LABEL: @ord_zero_vec(
+; CHECK-NEXT:    [[F:%.*]] = fcmp ord <2 x double> [[X:%.*]], zeroinitializer
+; CHECK-NEXT:    ret <2 x i1> [[F]]
+;
+  %f = fcmp ord <2 x double> %x, zeroinitializer
+  ret <2 x i1> %f
+}
+
+define <2 x i1> @ord_nonzero_vec(<2 x float> %x) {
+; CHECK-LABEL: @ord_nonzero_vec(
+; CHECK-NEXT:    [[F:%.*]] = fcmp ord <2 x float> [[X:%.*]], zeroinitializer
+; CHECK-NEXT:    ret <2 x i1> [[F]]
+;
+  %f = fcmp ord <2 x float> %x, <float 3.0, float 5.0>
+  ret <2 x i1> %f
+}
+
+define <2 x i1> @ord_self_vec(<2 x double> %x) {
+; CHECK-LABEL: @ord_self_vec(
+; CHECK-NEXT:    [[F:%.*]] = fcmp ord <2 x double> [[X:%.*]], zeroinitializer
+; CHECK-NEXT:    ret <2 x i1> [[F]]
+;
+  %f = fcmp ord <2 x double> %x, %x
+  ret <2 x i1> %f
+}
+
+define <2 x i1> @uno_zero_vec(<2 x float> %x) {
+; CHECK-LABEL: @uno_zero_vec(
+; CHECK-NEXT:    [[F:%.*]] = fcmp uno <2 x float> [[X:%.*]], zeroinitializer
+; CHECK-NEXT:    ret <2 x i1> [[F]]
+;
+  %f = fcmp uno <2 x float> %x, zeroinitializer
+  ret <2 x i1> %f
+}
+
+define <2 x i1> @uno_nonzero_vec(<2 x double> %x) {
+; CHECK-LABEL: @uno_nonzero_vec(
+; CHECK-NEXT:    [[F:%.*]] = fcmp uno <2 x double> [[X:%.*]], zeroinitializer
+; CHECK-NEXT:    ret <2 x i1> [[F]]
+;
+  %f = fcmp uno <2 x double> %x, <double 3.0, double 5.0>
+  ret <2 x i1> %f
+}
+
+define <2 x i1> @uno_self_vec(<2 x float> %x) {
+; CHECK-LABEL: @uno_self_vec(
+; CHECK-NEXT:    [[F:%.*]] = fcmp uno <2 x float> [[X:%.*]], zeroinitializer
+; CHECK-NEXT:    ret <2 x i1> [[F]]
+;
+  %f = fcmp uno <2 x float> %x, %x
+  ret <2 x i1> %f
+}
+
+; If a scalar constant is NaN in any of the above tests, it would have been eliminated by InstSimplify.
+; If a vector has a NaN element, we don't do anything with it.
+
+define <2 x i1> @uno_vec_with_nan(<2 x double> %x) {
+; CHECK-LABEL: @uno_vec_with_nan(
+; CHECK-NEXT:    [[F:%.*]] = fcmp uno <2 x double> [[X:%.*]], <double 3.000000e+00, double 0x7FF00000FFFFFFFF>
+; CHECK-NEXT:    ret <2 x i1> [[F]]
+;
+  %f = fcmp uno <2 x double> %x, <double 3.0, double 0x7FF00000FFFFFFFF>
+  ret <2 x i1> %f
+}
+
+define <2 x i1> @uno_vec_with_undef(<2 x double> %x) {
+; CHECK-LABEL: @uno_vec_with_undef(
+; CHECK-NEXT:    [[F:%.*]] = fcmp uno <2 x double> [[X:%.*]], zeroinitializer
+; CHECK-NEXT:    ret <2 x i1> [[F]]
+;
+  %f = fcmp uno <2 x double> %x, <double 3.0, double undef>
+  ret <2 x i1> %f
+}
+
+define <2 x i1> @ord_vec_with_undef(<2 x double> %x) {
+; CHECK-LABEL: @ord_vec_with_undef(
+; CHECK-NEXT:    [[F:%.*]] = fcmp ord <2 x double> [[X:%.*]], <double 0.000000e+00, double undef>
+; CHECK-NEXT:    ret <2 x i1> [[F]]
+;
+  %f = fcmp ord <2 x double> %x, <double 0.0, double undef>
+  ret <2 x i1> %f
+}
+
+; TODO: This could be handled in InstSimplify.
+
+define i1 @nnan_ops_to_fcmp_ord(float %x, float %y) {
+; CHECK-LABEL: @nnan_ops_to_fcmp_ord(
+; CHECK-NEXT:    ret i1 true
+;
+  %mul = fmul nnan float %x, %y
+  %div = fdiv nnan float %x, %y
+  %cmp = fcmp ord float %mul, %div
+  ret i1 %cmp
+}
+
+; TODO: This could be handled in InstSimplify.
+
+define i1 @nnan_ops_to_fcmp_uno(float %x, float %y) {
+; CHECK-LABEL: @nnan_ops_to_fcmp_uno(
+; CHECK-NEXT:    ret i1 false
+;
+  %mul = fmul nnan float %x, %y
+  %div = fdiv nnan float %x, %y
+  %cmp = fcmp uno float %mul, %div
+  ret i1 %cmp
+}
+
+; TODO: For any predicate/type/FMF, comparison to -0.0 is the same as comparison to +0.0.
+
+define i1 @negative_zero_oeq(float %x) {
+; CHECK-LABEL: @negative_zero_oeq(
+; CHECK-NEXT:    [[R:%.*]] = fcmp oeq float [[X:%.*]], 0.000000e+00
+; CHECK-NEXT:    ret i1 [[R]]
+;
+  %r = fcmp oeq float %x, -0.0
+  ret i1 %r
+}
+
+define i1 @negative_zero_oge(double %x) {
+; CHECK-LABEL: @negative_zero_oge(
+; CHECK-NEXT:    [[R:%.*]] = fcmp nnan oge double [[X:%.*]], 0.000000e+00
+; CHECK-NEXT:    ret i1 [[R]]
+;
+  %r = fcmp nnan oge double %x, -0.0
+  ret i1 %r
+}
+
+define i1 @negative_zero_uge(half %x) {
+; CHECK-LABEL: @negative_zero_uge(
+; CHECK-NEXT:    [[R:%.*]] = fcmp fast uge half [[X:%.*]], 0xH0000
+; CHECK-NEXT:    ret i1 [[R]]
+;
+  %r = fcmp fast uge half %x, -0.0
+  ret i1 %r
+}
+
+define <2 x i1> @negative_zero_olt_vec(<2 x float> %x) {
+; CHECK-LABEL: @negative_zero_olt_vec(
+; CHECK-NEXT:    [[R:%.*]] = fcmp reassoc ninf olt <2 x float> [[X:%.*]], zeroinitializer
+; CHECK-NEXT:    ret <2 x i1> [[R]]
+;
+  %r = fcmp reassoc ninf olt <2 x float> %x, <float -0.0, float -0.0>
+  ret <2 x i1> %r
+}
+
+define <2 x i1> @negative_zero_une_vec_undef(<2 x double> %x) {
+; CHECK-LABEL: @negative_zero_une_vec_undef(
+; CHECK-NEXT:    [[R:%.*]] = fcmp nnan une <2 x double> [[X:%.*]], zeroinitializer
+; CHECK-NEXT:    ret <2 x i1> [[R]]
+;
+  %r = fcmp nnan une <2 x double> %x, <double -0.0, double undef>
+  ret <2 x i1> %r
+}
+
+define <2 x i1> @negative_zero_ule_vec_mixed(<2 x float> %x) {
+; CHECK-LABEL: @negative_zero_ule_vec_mixed(
+; CHECK-NEXT:    [[R:%.*]] = fcmp ule <2 x float> [[X:%.*]], zeroinitializer
+; CHECK-NEXT:    ret <2 x i1> [[R]]
+;
+  %r = fcmp ule <2 x float> %x, <float 0.0, float -0.0>
+  ret <2 x i1> %r
+}
+

Added: llvm/trunk/test/Transforms/InstCombine/fcmp.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/fcmp.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/fcmp.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/fcmp.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,463 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt -S -instcombine < %s | FileCheck %s
+
+declare half @llvm.fabs.f16(half)
+declare double @llvm.fabs.f64(double)
+declare <2 x float> @llvm.fabs.v2f32(<2 x float>)
+
+define i1 @fpext_fpext(float %x, float %y) {
+; CHECK-LABEL: @fpext_fpext(
+; CHECK-NEXT:    [[CMP:%.*]] = fcmp nnan ogt float [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %ext1 = fpext float %x to double
+  %ext2 = fpext float %y to double
+  %cmp = fcmp nnan ogt double %ext1, %ext2
+  ret i1 %cmp
+}
+
+define i1 @fpext_constant(float %a) {
+; CHECK-LABEL: @fpext_constant(
+; CHECK-NEXT:    [[CMP:%.*]] = fcmp ninf ogt float [[A:%.*]], 1.000000e+00
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %ext = fpext float %a to double
+  %cmp = fcmp ninf ogt double %ext, 1.000000e+00
+  ret i1 %cmp
+}
+
+define <2 x i1> @fpext_constant_vec_splat(<2 x half> %a) {
+; CHECK-LABEL: @fpext_constant_vec_splat(
+; CHECK-NEXT:    [[CMP:%.*]] = fcmp nnan ole <2 x half> [[A:%.*]], <half 0xH5140, half 0xH5140>
+; CHECK-NEXT:    ret <2 x i1> [[CMP]]
+;
+  %ext = fpext <2 x half> %a to <2 x double>
+  %cmp = fcmp nnan ole <2 x double> %ext, <double 42.0, double 42.0>
+  ret <2 x i1> %cmp
+}
+
+define i1 @fpext_constant_lossy(float %a) {
+; CHECK-LABEL: @fpext_constant_lossy(
+; CHECK-NEXT:    [[EXT:%.*]] = fpext float [[A:%.*]] to double
+; CHECK-NEXT:    [[CMP:%.*]] = fcmp ogt double [[EXT]], 0x3FF0000000000001
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %ext = fpext float %a to double
+  %cmp = fcmp ogt double %ext, 0x3FF0000000000001 ; more precision than float.
+  ret i1 %cmp
+}
+
+define i1 @fpext_constant_denorm(float %a) {
+; CHECK-LABEL: @fpext_constant_denorm(
+; CHECK-NEXT:    [[EXT:%.*]] = fpext float [[A:%.*]] to double
+; CHECK-NEXT:    [[CMP:%.*]] = fcmp ogt double [[EXT]], 0x36A0000000000000
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %ext = fpext float %a to double
+  %cmp = fcmp ogt double %ext, 0x36A0000000000000 ; denormal in float.
+  ret i1 %cmp
+}
+
+define i1 @fneg_constant_swap_pred(float %x) {
+; CHECK-LABEL: @fneg_constant_swap_pred(
+; CHECK-NEXT:    [[CMP:%.*]] = fcmp olt float [[X:%.*]], -1.000000e+00
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %neg = fsub float -0.0, %x
+  %cmp = fcmp ogt float %neg, 1.0
+  ret i1 %cmp
+}
+
+define <2 x i1> @fneg_constant_swap_pred_vec(<2 x float> %x) {
+; CHECK-LABEL: @fneg_constant_swap_pred_vec(
+; CHECK-NEXT:    [[CMP:%.*]] = fcmp olt <2 x float> [[X:%.*]], <float -1.000000e+00, float -2.000000e+00>
+; CHECK-NEXT:    ret <2 x i1> [[CMP]]
+;
+  %neg = fsub <2 x float> <float -0.0, float -0.0>, %x
+  %cmp = fcmp ogt <2 x float> %neg, <float 1.0, float 2.0>
+  ret <2 x i1> %cmp
+}
+
+define <2 x i1> @fneg_constant_swap_pred_vec_undef(<2 x float> %x) {
+; CHECK-LABEL: @fneg_constant_swap_pred_vec_undef(
+; CHECK-NEXT:    [[CMP:%.*]] = fcmp olt <2 x float> [[X:%.*]], <float -1.000000e+00, float -2.000000e+00>
+; CHECK-NEXT:    ret <2 x i1> [[CMP]]
+;
+  %neg = fsub <2 x float> <float undef, float -0.0>, %x
+  %cmp = fcmp ogt <2 x float> %neg, <float 1.0, float 2.0>
+  ret <2 x i1> %cmp
+}
+
+; The new fcmp should have the same FMF as the original.
+
+define i1 @fneg_fmf(float %x) {
+; CHECK-LABEL: @fneg_fmf(
+; CHECK-NEXT:    [[R:%.*]] = fcmp fast oeq float [[X:%.*]], -4.200000e+01
+; CHECK-NEXT:    ret i1 [[R]]
+;
+  %n = fsub fast float -0.0, %x
+  %r = fcmp fast oeq float %n, 42.0
+  ret i1 %r
+}
+
+; The new fcmp should have the same FMF as the original, vector edition.
+
+define <2 x i1> @fcmp_fneg_fmf_vec(<2 x float> %x) {
+; CHECK-LABEL: @fcmp_fneg_fmf_vec(
+; CHECK-NEXT:    [[R:%.*]] = fcmp reassoc nnan ule <2 x float> [[X:%.*]], <float -4.200000e+01, float 1.900000e+01>
+; CHECK-NEXT:    ret <2 x i1> [[R]]
+;
+  %n = fsub nsz <2 x float> zeroinitializer, %x
+  %r = fcmp nnan reassoc uge <2 x float> %n, <float 42.0, float -19.0>
+  ret <2 x i1> %r
+}
+
+define i1 @fneg_fneg_swap_pred(float %x, float %y) {
+; CHECK-LABEL: @fneg_fneg_swap_pred(
+; CHECK-NEXT:    [[CMP:%.*]] = fcmp nnan ogt float [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %neg1 = fsub float -0.0, %x
+  %neg2 = fsub float -0.0, %y
+  %cmp = fcmp nnan olt float %neg1, %neg2
+  ret i1 %cmp
+}
+
+define <2 x i1> @fneg_fneg_swap_pred_vec(<2 x float> %x, <2 x float> %y) {
+; CHECK-LABEL: @fneg_fneg_swap_pred_vec(
+; CHECK-NEXT:    [[CMP:%.*]] = fcmp ninf ogt <2 x float> [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    ret <2 x i1> [[CMP]]
+;
+  %neg1 = fsub <2 x float> <float -0.0, float -0.0>, %x
+  %neg2 = fsub <2 x float> <float -0.0, float -0.0>, %y
+  %cmp = fcmp ninf olt <2 x float> %neg1, %neg2
+  ret <2 x i1> %cmp
+}
+
+define <2 x i1> @fneg_fneg_swap_pred_vec_undef(<2 x float> %x, <2 x float> %y) {
+; CHECK-LABEL: @fneg_fneg_swap_pred_vec_undef(
+; CHECK-NEXT:    [[CMP:%.*]] = fcmp ogt <2 x float> [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    ret <2 x i1> [[CMP]]
+;
+  %neg1 = fsub <2 x float> <float -0.0, float undef>, %x
+  %neg2 = fsub <2 x float> <float undef, float -0.0>, %y
+  %cmp = fcmp olt <2 x float> %neg1, %neg2
+  ret <2 x i1> %cmp
+}
+
+define i1 @test7(float %x) {
+; CHECK-LABEL: @test7(
+; CHECK-NEXT:    [[CMP:%.*]] = fcmp ogt float [[X:%.*]], 0.000000e+00
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %ext = fpext float %x to ppc_fp128
+  %cmp = fcmp ogt ppc_fp128 %ext, 0xM00000000000000000000000000000000
+  ret i1 %cmp
+}
+
+define float @test8(float %x) {
+; CHECK-LABEL: @test8(
+; CHECK-NEXT:    [[CMP:%.*]] = fcmp olt float [[X:%.*]], 0.000000e+00
+; CHECK-NEXT:    [[CONV2:%.*]] = uitofp i1 [[CMP]] to float
+; CHECK-NEXT:    ret float [[CONV2]]
+;
+  %conv = fpext float %x to double
+  %cmp = fcmp olt double %conv, 0.000000e+00
+  %conv1 = zext i1 %cmp to i32
+  %conv2 = sitofp i32 %conv1 to float
+  ret float %conv2
+; Float comparison to zero shouldn't cast to double.
+}
+
+define i1 @fabs_uge(double %a) {
+; CHECK-LABEL: @fabs_uge(
+; CHECK-NEXT:    ret i1 true
+;
+  %call = call double @llvm.fabs.f64(double %a)
+  %cmp = fcmp uge double %call, 0.0
+  ret i1 %cmp
+}
+
+define i1 @fabs_olt(half %a) {
+; CHECK-LABEL: @fabs_olt(
+; CHECK-NEXT:    ret i1 false
+;
+  %call = call half @llvm.fabs.f16(half %a)
+  %cmp = fcmp olt half %call, 0.0
+  ret i1 %cmp
+}
+
+define <2 x i1> @fabs_ole(<2 x float> %a) {
+; CHECK-LABEL: @fabs_ole(
+; CHECK-NEXT:    [[CMP:%.*]] = fcmp ninf oeq <2 x float> [[A:%.*]], zeroinitializer
+; CHECK-NEXT:    ret <2 x i1> [[CMP]]
+;
+  %call = call <2 x float> @llvm.fabs.v2f32(<2 x float> %a)
+  %cmp = fcmp ninf ole <2 x float> %call, zeroinitializer
+  ret <2 x i1> %cmp
+}
+
+define <2 x i1> @fabs_ule(<2 x float> %a) {
+; CHECK-LABEL: @fabs_ule(
+; CHECK-NEXT:    [[CMP:%.*]] = fcmp ninf arcp ueq <2 x float> [[A:%.*]], zeroinitializer
+; CHECK-NEXT:    ret <2 x i1> [[CMP]]
+;
+  %call = call <2 x float> @llvm.fabs.v2f32(<2 x float> %a)
+  %cmp = fcmp ninf arcp ule <2 x float> %call, zeroinitializer
+  ret <2 x i1> %cmp
+}
+
+define i1 @fabs_ogt(double %a) {
+; CHECK-LABEL: @fabs_ogt(
+; CHECK-NEXT:    [[CMP:%.*]] = fcmp reassoc one double [[A:%.*]], 0.000000e+00
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %call = call double @llvm.fabs.f64(double %a)
+  %cmp = fcmp reassoc ogt double %call, 0.0
+  ret i1 %cmp
+}
+
+define i1 @fabs_ugt(double %a) {
+; CHECK-LABEL: @fabs_ugt(
+; CHECK-NEXT:    [[CMP:%.*]] = fcmp reassoc ninf une double [[A:%.*]], 0.000000e+00
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %call = call double @llvm.fabs.f64(double %a)
+  %cmp = fcmp ninf reassoc ugt double %call, 0.0
+  ret i1 %cmp
+}
+
+define i1 @fabs_oge(double %a) {
+; CHECK-LABEL: @fabs_oge(
+; CHECK-NEXT:    [[CMP:%.*]] = fcmp afn ord double [[A:%.*]], 0.000000e+00
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %call = call double @llvm.fabs.f64(double %a)
+  %cmp = fcmp afn oge double %call, 0.0
+  ret i1 %cmp
+}
+
+define i1 @fabs_ult(double %a) {
+; CHECK-LABEL: @fabs_ult(
+; CHECK-NEXT:    [[CMP:%.*]] = fcmp reassoc arcp uno double [[A:%.*]], 0.000000e+00
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %call = call double @llvm.fabs.f64(double %a)
+  %cmp = fcmp reassoc arcp ult double %call, 0.0
+  ret i1 %cmp
+}
+
+define <2 x i1> @fabs_ult_nnan(<2 x float> %a) {
+; CHECK-LABEL: @fabs_ult_nnan(
+; CHECK-NEXT:    ret <2 x i1> zeroinitializer
+;
+  %call = call <2 x float> @llvm.fabs.v2f32(<2 x float> %a)
+  %cmp = fcmp nnan reassoc arcp ult <2 x float> %call, zeroinitializer
+  ret <2 x i1> %cmp
+}
+
+define i1 @fabs_une(half %a) {
+; CHECK-LABEL: @fabs_une(
+; CHECK-NEXT:    [[CMP:%.*]] = fcmp ninf une half [[A:%.*]], 0xH0000
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %call = call half @llvm.fabs.f16(half %a)
+  %cmp = fcmp ninf une half %call, 0.0
+  ret i1 %cmp
+}
+
+define i1 @fabs_oeq(double %a) {
+; CHECK-LABEL: @fabs_oeq(
+; CHECK-NEXT:    [[CMP:%.*]] = fcmp reassoc ninf oeq double [[A:%.*]], 0.000000e+00
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %call = call double @llvm.fabs.f64(double %a)
+  %cmp = fcmp ninf reassoc oeq double %call, 0.0
+  ret i1 %cmp
+}
+
+define i1 @fabs_one(double %a) {
+; CHECK-LABEL: @fabs_one(
+; CHECK-NEXT:    [[CMP:%.*]] = fcmp fast one double [[A:%.*]], 0.000000e+00
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %call = call double @llvm.fabs.f64(double %a)
+  %cmp = fcmp fast one double %call, 0.0
+  ret i1 %cmp
+}
+
+define <2 x i1> @fabs_ueq(<2 x float> %a) {
+; CHECK-LABEL: @fabs_ueq(
+; CHECK-NEXT:    [[CMP:%.*]] = fcmp arcp ueq <2 x float> [[A:%.*]], zeroinitializer
+; CHECK-NEXT:    ret <2 x i1> [[CMP]]
+;
+  %call = call <2 x float> @llvm.fabs.v2f32(<2 x float> %a)
+  %cmp = fcmp arcp ueq <2 x float> %call, zeroinitializer
+  ret <2 x i1> %cmp
+}
+
+define <2 x i1> @fabs_ord(<2 x float> %a) {
+; CHECK-LABEL: @fabs_ord(
+; CHECK-NEXT:    [[CMP:%.*]] = fcmp arcp ord <2 x float> [[A:%.*]], zeroinitializer
+; CHECK-NEXT:    ret <2 x i1> [[CMP]]
+;
+  %call = call <2 x float> @llvm.fabs.v2f32(<2 x float> %a)
+  %cmp = fcmp arcp ord <2 x float> %call, zeroinitializer
+  ret <2 x i1> %cmp
+}
+
+define <2 x i1> @fabs_uno(<2 x float> %a) {
+; CHECK-LABEL: @fabs_uno(
+; CHECK-NEXT:    [[CMP:%.*]] = fcmp arcp uno <2 x float> [[A:%.*]], zeroinitializer
+; CHECK-NEXT:    ret <2 x i1> [[CMP]]
+;
+  %call = call <2 x float> @llvm.fabs.v2f32(<2 x float> %a)
+  %cmp = fcmp arcp uno <2 x float> %call, zeroinitializer
+  ret <2 x i1> %cmp
+}
+
+; Don't crash.
+define i32 @test17(double %a, double (double)* %p) {
+; CHECK-LABEL: @test17(
+; CHECK-NEXT:    [[CALL:%.*]] = tail call double [[P:%.*]](double [[A:%.*]])
+; CHECK-NEXT:    [[CMP:%.*]] = fcmp ueq double [[CALL]], 0.000000e+00
+; CHECK-NEXT:    [[CONV:%.*]] = zext i1 [[CMP]] to i32
+; CHECK-NEXT:    ret i32 [[CONV]]
+;
+  %call = tail call double %p(double %a)
+  %cmp = fcmp ueq double %call, 0.000000e+00
+  %conv = zext i1 %cmp to i32
+  ret i32 %conv
+}
+
+; Can fold fcmp with undef on one side by choosing NaN for the undef
+define i32 @test18_undef_unordered(float %a) {
+; CHECK-LABEL: @test18_undef_unordered(
+; CHECK-NEXT:    ret i32 1
+;
+  %cmp = fcmp ueq float %a, undef
+  %conv = zext i1 %cmp to i32
+  ret i32 %conv
+}
+; Can fold fcmp with undef on one side by choosing NaN for the undef
+define i32 @test18_undef_ordered(float %a) {
+; CHECK-LABEL: @test18_undef_ordered(
+; CHECK-NEXT:    ret i32 0
+;
+  %cmp = fcmp oeq float %a, undef
+  %conv = zext i1 %cmp to i32
+  ret i32 %conv
+}
+
+; Can fold fcmp with undef on both side
+;   fcmp u_pred undef, undef -> true
+;   fcmp o_pred undef, undef -> false
+; because whatever you choose for the first undef
+; you can choose NaN for the other undef
+define i1 @test19_undef_unordered() {
+; CHECK-LABEL: @test19_undef_unordered(
+; CHECK-NEXT:    ret i1 true
+;
+  %cmp = fcmp ueq float undef, undef
+  ret i1 %cmp
+}
+
+define i1 @test19_undef_ordered() {
+; CHECK-LABEL: @test19_undef_ordered(
+; CHECK-NEXT:    ret i1 false
+;
+  %cmp = fcmp oeq float undef, undef
+  ret i1 %cmp
+}
+
+; Can fold 1.0 / X < 0.0 --> X < 0 with ninf
+define i1 @test20_recipX_olt_0(float %X) {
+; CHECK-LABEL: @test20_recipX_olt_0(
+; CHECK-NEXT:    [[CMP:%.*]] = fcmp ninf olt float [[X:%.*]], 0.000000e+00
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %div = fdiv ninf float 1.0, %X
+  %cmp = fcmp ninf olt float %div, 0.0
+  ret i1 %cmp
+}
+
+; Can fold -2.0 / X <= 0.0 --> X >= 0 with ninf
+define i1 @test21_recipX_ole_0(float %X) {
+; CHECK-LABEL: @test21_recipX_ole_0(
+; CHECK-NEXT:    [[CMP:%.*]] = fcmp ninf oge float [[X:%.*]], 0.000000e+00
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %div = fdiv ninf float -2.0, %X
+  %cmp = fcmp ninf ole float %div, 0.0
+  ret i1 %cmp
+}
+
+; Can fold 2.0 / X > 0.0 --> X > 0 with ninf
+define i1 @test22_recipX_ogt_0(float %X) {
+; CHECK-LABEL: @test22_recipX_ogt_0(
+; CHECK-NEXT:    [[CMP:%.*]] = fcmp ninf ogt float [[X:%.*]], 0.000000e+00
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %div = fdiv ninf float 2.0, %X
+  %cmp = fcmp ninf ogt float %div, 0.0
+  ret i1 %cmp
+}
+
+; Can fold -1.0 / X >= 0.0 --> X <= 0 with ninf
+define i1 @test23_recipX_oge_0(float %X) {
+; CHECK-LABEL: @test23_recipX_oge_0(
+; CHECK-NEXT:    [[CMP:%.*]] = fcmp ninf ole float [[X:%.*]], 0.000000e+00
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %div = fdiv ninf float -1.0, %X
+  %cmp = fcmp ninf oge float %div, 0.0
+  ret i1 %cmp
+}
+
+; Do not fold 1.0 / X > 0.0 when ninf is missing
+define i1 @test24_recipX_noninf_cmp(float %X) {
+; CHECK-LABEL: @test24_recipX_noninf_cmp(
+; CHECK-NEXT:    [[DIV:%.*]] = fdiv ninf float 2.000000e+00, [[X:%.*]]
+; CHECK-NEXT:    [[CMP:%.*]] = fcmp ogt float [[DIV]], 0.000000e+00
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %div = fdiv ninf float 2.0, %X
+  %cmp = fcmp ogt float %div, 0.0
+  ret i1 %cmp
+}
+
+; Do not fold 1.0 / X > 0.0 when ninf is missing
+define i1 @test25_recipX_noninf_div(float %X) {
+; CHECK-LABEL: @test25_recipX_noninf_div(
+; CHECK-NEXT:    [[DIV:%.*]] = fdiv float 2.000000e+00, [[X:%.*]]
+; CHECK-NEXT:    [[CMP:%.*]] = fcmp ninf ogt float [[DIV]], 0.000000e+00
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %div = fdiv float 2.0, %X
+  %cmp = fcmp ninf ogt float %div, 0.0
+  ret i1 %cmp
+}
+
+; Do not fold 1.0 / X > 0.0 with unordered predicates
+define i1 @test26_recipX_unorderd(float %X) {
+; CHECK-LABEL: @test26_recipX_unorderd(
+; CHECK-NEXT:    [[DIV:%.*]] = fdiv ninf float 2.000000e+00, [[X:%.*]]
+; CHECK-NEXT:    [[CMP:%.*]] = fcmp ninf ugt float [[DIV]], 0.000000e+00
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %div = fdiv ninf float 2.0, %X
+  %cmp = fcmp ninf ugt float %div, 0.0
+  ret i1 %cmp
+}
+
+; Fold <-1.0, -1.0> / X > <-0.0, -0.0>
+define <2 x i1> @test27_recipX_gt_vecsplat(<2 x float> %X) {
+; CHECK-LABEL: @test27_recipX_gt_vecsplat(
+; CHECK-NEXT:    [[CMP:%.*]] = fcmp ninf olt <2 x float> [[X:%.*]], zeroinitializer
+; CHECK-NEXT:    ret <2 x i1> [[CMP]]
+;
+  %div = fdiv ninf <2 x float> <float -1.0, float -1.0>, %X
+  %cmp = fcmp ninf ogt <2 x float> %div, <float -0.0, float -0.0>
+  ret <2 x i1> %cmp
+}
+

Added: llvm/trunk/test/Transforms/InstCombine/fdiv-cos-sin.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/fdiv-cos-sin.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/fdiv-cos-sin.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/fdiv-cos-sin.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,131 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt -S -instcombine < %s | FileCheck %s
+
+define double @fdiv_cos_sin(double %a) {
+; CHECK-LABEL: @fdiv_cos_sin(
+; CHECK-NEXT:    [[TMP1:%.*]] = call double @llvm.cos.f64(double [[A:%.*]])
+; CHECK-NEXT:    [[TMP2:%.*]] = call double @llvm.sin.f64(double [[A]])
+; CHECK-NEXT:    [[DIV:%.*]] = fdiv double [[TMP1]], [[TMP2]]
+; CHECK-NEXT:    ret double [[DIV]]
+;
+  %1 = call double @llvm.cos.f64(double %a)
+  %2 = call double @llvm.sin.f64(double %a)
+  %div = fdiv double %1, %2
+  ret double %div
+}
+
+define double @fdiv_strict_cos_strict_sin_reassoc(double %a) {
+; CHECK-LABEL: @fdiv_strict_cos_strict_sin_reassoc(
+; CHECK-NEXT:    [[TMP1:%.*]] = call double @llvm.cos.f64(double [[A:%.*]])
+; CHECK-NEXT:    [[TMP2:%.*]] = call reassoc double @llvm.sin.f64(double [[A]])
+; CHECK-NEXT:    [[DIV:%.*]] = fdiv double [[TMP1]], [[TMP2]]
+; CHECK-NEXT:    ret double [[DIV]]
+;
+  %1 = call double @llvm.cos.f64(double %a)
+  %2 = call reassoc double @llvm.sin.f64(double %a)
+  %div = fdiv double %1, %2
+  ret double %div
+}
+
+define double @fdiv_reassoc_cos_strict_sin_strict(double %a, i32* dereferenceable(2) %dummy) {
+; CHECK-LABEL: @fdiv_reassoc_cos_strict_sin_strict(
+; CHECK-NEXT:    [[TAN:%.*]] = call reassoc double @tan(double [[A:%.*]]) #1
+; CHECK-NEXT:    [[TMP1:%.*]] = fdiv reassoc double 1.000000e+00, [[TAN]]
+; CHECK-NEXT:    ret double [[TMP1]]
+;
+  %1 = call double @llvm.cos.f64(double %a)
+  %2 = call double @llvm.sin.f64(double %a)
+  %div = fdiv reassoc double %1, %2
+  ret double %div
+}
+
+define double @fdiv_reassoc_cos_reassoc_sin_strict(double %a) {
+; CHECK-LABEL: @fdiv_reassoc_cos_reassoc_sin_strict(
+; CHECK-NEXT:    [[TAN:%.*]] = call reassoc double @tan(double [[A:%.*]]) #1
+; CHECK-NEXT:    [[TMP1:%.*]] = fdiv reassoc double 1.000000e+00, [[TAN]]
+; CHECK-NEXT:    ret double [[TMP1]]
+;
+  %1 = call reassoc double @llvm.cos.f64(double %a)
+  %2 = call double @llvm.sin.f64(double %a)
+  %div = fdiv reassoc double %1, %2
+  ret double %div
+}
+
+define double @fdiv_cos_sin_reassoc_multiple_uses(double %a) {
+; CHECK-LABEL: @fdiv_cos_sin_reassoc_multiple_uses(
+; CHECK-NEXT:    [[TMP1:%.*]] = call reassoc double @llvm.cos.f64(double [[A:%.*]])
+; CHECK-NEXT:    [[TMP2:%.*]] = call reassoc double @llvm.sin.f64(double [[A]])
+; CHECK-NEXT:    [[DIV:%.*]] = fdiv reassoc double [[TMP1]], [[TMP2]]
+; CHECK-NEXT:    call void @use(double [[TMP2]])
+; CHECK-NEXT:    ret double [[DIV]]
+;
+  %1 = call reassoc double @llvm.cos.f64(double %a)
+  %2 = call reassoc double @llvm.sin.f64(double %a)
+  %div = fdiv reassoc double %1, %2
+  call void @use(double %2)
+  ret double %div
+}
+
+define double @fdiv_cos_sin_reassoc(double %a) {
+; CHECK-LABEL: @fdiv_cos_sin_reassoc(
+; CHECK-NEXT:    [[TAN:%.*]] = call reassoc double @tan(double [[A:%.*]]) #1
+; CHECK-NEXT:    [[TMP1:%.*]] = fdiv reassoc double 1.000000e+00, [[TAN]]
+; CHECK-NEXT:    ret double [[TMP1]]
+;
+  %1 = call reassoc double @llvm.cos.f64(double %a)
+  %2 = call reassoc double @llvm.sin.f64(double %a)
+  %div = fdiv reassoc double %1, %2
+  ret double %div
+}
+
+define half @fdiv_cosf16_sinf16_reassoc(half %a) {
+; CHECK-LABEL: @fdiv_cosf16_sinf16_reassoc(
+; CHECK-NEXT:    [[TMP1:%.*]] = call reassoc half @llvm.cos.f16(half [[A:%.*]])
+; CHECK-NEXT:    [[TMP2:%.*]] = call reassoc half @llvm.sin.f16(half [[A]])
+; CHECK-NEXT:    [[DIV:%.*]] = fdiv reassoc half [[TMP1]], [[TMP2]]
+; CHECK-NEXT:    ret half [[DIV]]
+;
+  %1 = call reassoc half @llvm.cos.f16(half %a)
+  %2 = call reassoc half @llvm.sin.f16(half %a)
+  %div = fdiv reassoc half %1, %2
+  ret half %div
+}
+
+define float @fdiv_cosf_sinf_reassoc(float %a) {
+; CHECK-LABEL: @fdiv_cosf_sinf_reassoc(
+; CHECK-NEXT:    [[TANF:%.*]] = call reassoc float @tanf(float [[A:%.*]]) #1
+; CHECK-NEXT:    [[TMP1:%.*]] = fdiv reassoc float 1.000000e+00, [[TANF]]
+; CHECK-NEXT:    ret float [[TMP1]]
+;
+  %1 = call reassoc float @llvm.cos.f32(float %a)
+  %2 = call reassoc float @llvm.sin.f32(float %a)
+  %div = fdiv reassoc float %1, %2
+  ret float %div
+}
+
+define fp128 @fdiv_cosfp128_sinfp128_reassoc(fp128 %a) {
+; CHECK-LABEL: @fdiv_cosfp128_sinfp128_reassoc(
+; CHECK-NEXT:    [[TANL:%.*]] = call reassoc fp128 @tanl(fp128 [[A:%.*]]) #1
+; CHECK-NEXT:    [[TMP1:%.*]] = fdiv reassoc fp128 0xL00000000000000003FFF000000000000, [[TANL]]
+; CHECK-NEXT:    ret fp128 [[TMP1]]
+;
+  %1 = call reassoc fp128 @llvm.cos.fp128(fp128 %a)
+  %2 = call reassoc fp128 @llvm.sin.fp128(fp128 %a)
+  %div = fdiv reassoc fp128 %1, %2
+  ret fp128 %div
+}
+
+declare half @llvm.cos.f16(half) #1
+declare float @llvm.cos.f32(float) #1
+declare double @llvm.cos.f64(double) #1
+declare fp128 @llvm.cos.fp128(fp128) #1
+
+declare half @llvm.sin.f16(half) #1
+declare float @llvm.sin.f32(float) #1
+declare double @llvm.sin.f64(double) #1
+declare fp128 @llvm.sin.fp128(fp128) #1
+
+declare void @use(double)
+
+attributes #0 = { nounwind readnone speculatable }
+attributes #1 = { nounwind readnone }

Added: llvm/trunk/test/Transforms/InstCombine/fdiv-sin-cos.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/fdiv-sin-cos.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/fdiv-sin-cos.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/fdiv-sin-cos.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,111 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt -S -instcombine < %s | FileCheck %s
+
+define double @fdiv_sin_cos(double %a) {
+; CHECK-LABEL: @fdiv_sin_cos(
+; CHECK-NEXT:    [[TMP1:%.*]] = call double @llvm.sin.f64(double [[A:%.*]])
+; CHECK-NEXT:    [[TMP2:%.*]] = call double @llvm.cos.f64(double [[A]])
+; CHECK-NEXT:    [[DIV:%.*]] = fdiv double [[TMP1]], [[TMP2]]
+; CHECK-NEXT:    ret double [[DIV]]
+;
+  %1 = call double @llvm.sin.f64(double %a)
+  %2 = call double @llvm.cos.f64(double %a)
+  %div = fdiv double %1, %2
+  ret double %div
+}
+
+define double @fdiv_strict_sin_strict_cos_reassoc(double %a) {
+; CHECK-LABEL: @fdiv_strict_sin_strict_cos_reassoc(
+; CHECK-NEXT:    [[TMP1:%.*]] = call double @llvm.sin.f64(double [[A:%.*]])
+; CHECK-NEXT:    [[TMP2:%.*]] = call reassoc double @llvm.cos.f64(double [[A]])
+; CHECK-NEXT:    [[DIV:%.*]] = fdiv double [[TMP1]], [[TMP2]]
+; CHECK-NEXT:    ret double [[DIV]]
+;
+  %1 = call double @llvm.sin.f64(double %a)
+  %2 = call reassoc double @llvm.cos.f64(double %a)
+  %div = fdiv double %1, %2
+  ret double %div
+}
+
+define double @fdiv_reassoc_sin_strict_cos_strict(double %a, i32* dereferenceable(2) %dummy) {
+; CHECK-LABEL: @fdiv_reassoc_sin_strict_cos_strict(
+; CHECK-NEXT:    [[TAN:%.*]] = call reassoc double @tan(double [[A:%.*]]) #1
+; CHECK-NEXT:    ret double [[TAN]]
+;
+  %1 = call double @llvm.sin.f64(double %a)
+  %2 = call double @llvm.cos.f64(double %a)
+  %div = fdiv reassoc double %1, %2
+  ret double %div
+}
+
+define double @fdiv_reassoc_sin_reassoc_cos_strict(double %a) {
+; CHECK-LABEL: @fdiv_reassoc_sin_reassoc_cos_strict(
+; CHECK-NEXT:    [[TAN:%.*]] = call reassoc double @tan(double [[A:%.*]]) #1
+; CHECK-NEXT:    ret double [[TAN]]
+;
+  %1 = call reassoc double @llvm.sin.f64(double %a)
+  %2 = call double @llvm.cos.f64(double %a)
+  %div = fdiv reassoc double %1, %2
+  ret double %div
+}
+
+define double @fdiv_sin_cos_reassoc_multiple_uses(double %a) {
+; CHECK-LABEL: @fdiv_sin_cos_reassoc_multiple_uses(
+; CHECK-NEXT:    [[TMP1:%.*]] = call reassoc double @llvm.sin.f64(double [[A:%.*]])
+; CHECK-NEXT:    [[TMP2:%.*]] = call reassoc double @llvm.cos.f64(double [[A]])
+; CHECK-NEXT:    [[DIV:%.*]] = fdiv reassoc double [[TMP1]], [[TMP2]]
+; CHECK-NEXT:    call void @use(double [[TMP2]])
+; CHECK-NEXT:    ret double [[DIV]]
+;
+  %1 = call reassoc double @llvm.sin.f64(double %a)
+  %2 = call reassoc double @llvm.cos.f64(double %a)
+  %div = fdiv reassoc double %1, %2
+  call void @use(double %2)
+  ret double %div
+}
+
+define double @fdiv_sin_cos_reassoc(double %a) {
+; CHECK-LABEL: @fdiv_sin_cos_reassoc(
+; CHECK-NEXT:    [[TAN:%.*]] = call reassoc double @tan(double [[A:%.*]]) #1
+; CHECK-NEXT:    ret double [[TAN]]
+;
+  %1 = call reassoc double @llvm.sin.f64(double %a)
+  %2 = call reassoc double @llvm.cos.f64(double %a)
+  %div = fdiv reassoc double %1, %2
+  ret double %div
+}
+
+define float @fdiv_sinf_cosf_reassoc(float %a) {
+; CHECK-LABEL: @fdiv_sinf_cosf_reassoc(
+; CHECK-NEXT:    [[TANF:%.*]] = call reassoc float @tanf(float [[A:%.*]]) #1
+; CHECK-NEXT:    ret float [[TANF]]
+;
+  %1 = call reassoc float @llvm.sin.f32(float %a)
+  %2 = call reassoc float @llvm.cos.f32(float %a)
+  %div = fdiv reassoc float %1, %2
+  ret float %div
+}
+
+define fp128 @fdiv_sinfp128_cosfp128_reassoc(fp128 %a) {
+; CHECK-LABEL: @fdiv_sinfp128_cosfp128_reassoc(
+; CHECK-NEXT:    [[TANL:%.*]] = call reassoc fp128 @tanl(fp128 [[A:%.*]]) #1
+; CHECK-NEXT:    ret fp128 [[TANL]]
+;
+  %1 = call reassoc fp128 @llvm.sin.fp128(fp128 %a)
+  %2 = call reassoc fp128 @llvm.cos.fp128(fp128 %a)
+  %div = fdiv reassoc fp128 %1, %2
+  ret fp128 %div
+}
+
+declare double @llvm.sin.f64(double) #1
+declare float @llvm.sin.f32(float) #1
+declare fp128 @llvm.sin.fp128(fp128) #1
+
+declare double @llvm.cos.f64(double) #1
+declare float @llvm.cos.f32(float) #1
+declare fp128 @llvm.cos.fp128(fp128) #1
+
+declare void @use(double)
+
+attributes #0 = { nounwind readnone speculatable }
+attributes #1 = { nounwind readnone }

Added: llvm/trunk/test/Transforms/InstCombine/fdiv.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/fdiv.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/fdiv.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/fdiv.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,383 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt -S -instcombine < %s | FileCheck %s
+
+define float @exact_inverse(float %x) {
+; CHECK-LABEL: @exact_inverse(
+; CHECK-NEXT:    [[DIV:%.*]] = fmul float [[X:%.*]], 1.250000e-01
+; CHECK-NEXT:    ret float [[DIV]]
+;
+  %div = fdiv float %x, 8.0
+  ret float %div
+}
+
+; Min normal float = 1.17549435E-38
+
+define float @exact_inverse2(float %x) {
+; CHECK-LABEL: @exact_inverse2(
+; CHECK-NEXT:    [[DIV:%.*]] = fmul float [[X:%.*]], 0x47D0000000000000
+; CHECK-NEXT:    ret float [[DIV]]
+;
+  %div = fdiv float %x, 0x3810000000000000
+  ret float %div
+}
+
+; Max exponent = 1.70141183E+38; don't transform to multiply with denormal.
+
+define float @exact_inverse_but_denorm(float %x) {
+; CHECK-LABEL: @exact_inverse_but_denorm(
+; CHECK-NEXT:    [[DIV:%.*]] = fdiv float [[X:%.*]], 0x47E0000000000000
+; CHECK-NEXT:    ret float [[DIV]]
+;
+  %div = fdiv float %x, 0x47E0000000000000
+  ret float %div
+}
+
+; Denormal = float 1.40129846E-45; inverse can't be represented.
+
+define float @not_exact_inverse2(float %x) {
+; CHECK-LABEL: @not_exact_inverse2(
+; CHECK-NEXT:    [[DIV:%.*]] = fdiv float [[X:%.*]], 0x36A0000000000000
+; CHECK-NEXT:    ret float [[DIV]]
+;
+  %div = fdiv float %x, 0x36A0000000000000
+  ret float %div
+}
+
+; Fast math allows us to replace this fdiv.
+
+define float @not_exact_but_allow_recip(float %x) {
+; CHECK-LABEL: @not_exact_but_allow_recip(
+; CHECK-NEXT:    [[DIV:%.*]] = fmul arcp float [[X:%.*]], 0x3FD5555560000000
+; CHECK-NEXT:    ret float [[DIV]]
+;
+  %div = fdiv arcp float %x, 3.0
+  ret float %div
+}
+
+; Fast math allows us to replace this fdiv, but we don't to avoid a denormal.
+; TODO: What if the function attributes tell us that denormals are flushed?
+
+define float @not_exact_but_allow_recip_but_denorm(float %x) {
+; CHECK-LABEL: @not_exact_but_allow_recip_but_denorm(
+; CHECK-NEXT:    [[DIV:%.*]] = fdiv arcp float [[X:%.*]], 0x47E0000100000000
+; CHECK-NEXT:    ret float [[DIV]]
+;
+  %div = fdiv arcp float %x, 0x47E0000100000000
+  ret float %div
+}
+
+define <2 x float> @exact_inverse_splat(<2 x float> %x) {
+; CHECK-LABEL: @exact_inverse_splat(
+; CHECK-NEXT:    [[DIV:%.*]] = fmul <2 x float> [[X:%.*]], <float 2.500000e-01, float 2.500000e-01>
+; CHECK-NEXT:    ret <2 x float> [[DIV]]
+;
+  %div = fdiv <2 x float> %x, <float 4.0, float 4.0>
+  ret <2 x float> %div
+}
+
+; Fast math allows us to replace this fdiv.
+
+define <2 x float> @not_exact_but_allow_recip_splat(<2 x float> %x) {
+; CHECK-LABEL: @not_exact_but_allow_recip_splat(
+; CHECK-NEXT:    [[DIV:%.*]] = fmul arcp <2 x float> [[X:%.*]], <float 0x3FD5555560000000, float 0x3FD5555560000000>
+; CHECK-NEXT:    ret <2 x float> [[DIV]]
+;
+  %div = fdiv arcp <2 x float> %x, <float 3.0, float 3.0>
+  ret <2 x float> %div
+}
+
+define <2 x float> @exact_inverse_vec(<2 x float> %x) {
+; CHECK-LABEL: @exact_inverse_vec(
+; CHECK-NEXT:    [[DIV:%.*]] = fmul <2 x float> [[X:%.*]], <float 2.500000e-01, float 1.250000e-01>
+; CHECK-NEXT:    ret <2 x float> [[DIV]]
+;
+  %div = fdiv <2 x float> %x, <float 4.0, float 8.0>
+  ret <2 x float> %div
+}
+
+define <2 x float> @not_exact_inverse_splat(<2 x float> %x) {
+; CHECK-LABEL: @not_exact_inverse_splat(
+; CHECK-NEXT:    [[DIV:%.*]] = fdiv <2 x float> [[X:%.*]], <float 3.000000e+00, float 3.000000e+00>
+; CHECK-NEXT:    ret <2 x float> [[DIV]]
+;
+  %div = fdiv <2 x float> %x, <float 3.0, float 3.0>
+  ret <2 x float> %div
+}
+
+define <2 x float> @not_exact_inverse_vec(<2 x float> %x) {
+; CHECK-LABEL: @not_exact_inverse_vec(
+; CHECK-NEXT:    [[DIV:%.*]] = fdiv <2 x float> [[X:%.*]], <float 4.000000e+00, float 3.000000e+00>
+; CHECK-NEXT:    ret <2 x float> [[DIV]]
+;
+  %div = fdiv <2 x float> %x, <float 4.0, float 3.0>
+  ret <2 x float> %div
+}
+
+define <2 x float> @not_exact_inverse_vec_arcp(<2 x float> %x) {
+; CHECK-LABEL: @not_exact_inverse_vec_arcp(
+; CHECK-NEXT:    [[DIV:%.*]] = fmul arcp <2 x float> [[X:%.*]], <float 2.500000e-01, float 0x3FD5555560000000>
+; CHECK-NEXT:    ret <2 x float> [[DIV]]
+;
+  %div = fdiv arcp <2 x float> %x, <float 4.0, float 3.0>
+  ret <2 x float> %div
+}
+
+define <2 x float> @not_exact_inverse_vec_arcp_with_undef_elt(<2 x float> %x) {
+; CHECK-LABEL: @not_exact_inverse_vec_arcp_with_undef_elt(
+; CHECK-NEXT:    [[DIV:%.*]] = fdiv arcp <2 x float> [[X:%.*]], <float undef, float 3.000000e+00>
+; CHECK-NEXT:    ret <2 x float> [[DIV]]
+;
+  %div = fdiv arcp <2 x float> %x, <float undef, float 3.0>
+  ret <2 x float> %div
+}
+
+; (X / Y) / Z --> X / (Y * Z)
+
+define float @div_with_div_numerator(float %x, float %y, float %z) {
+; CHECK-LABEL: @div_with_div_numerator(
+; CHECK-NEXT:    [[TMP1:%.*]] = fmul reassoc arcp float [[Y:%.*]], [[Z:%.*]]
+; CHECK-NEXT:    [[DIV2:%.*]] = fdiv reassoc arcp float [[X:%.*]], [[TMP1]]
+; CHECK-NEXT:    ret float [[DIV2]]
+;
+  %div1 = fdiv ninf float %x, %y
+  %div2 = fdiv arcp reassoc float %div1, %z
+  ret float %div2
+}
+
+; Z / (X / Y) --> (Z * Y) / X
+
+define <2 x float> @div_with_div_denominator(<2 x float> %x, <2 x float> %y, <2 x float> %z) {
+; CHECK-LABEL: @div_with_div_denominator(
+; CHECK-NEXT:    [[TMP1:%.*]] = fmul reassoc arcp <2 x float> [[Y:%.*]], [[Z:%.*]]
+; CHECK-NEXT:    [[DIV2:%.*]] = fdiv reassoc arcp <2 x float> [[TMP1]], [[X:%.*]]
+; CHECK-NEXT:    ret <2 x float> [[DIV2]]
+;
+  %div1 = fdiv nnan <2 x float> %x, %y
+  %div2 = fdiv arcp reassoc <2 x float> %z, %div1
+  ret <2 x float> %div2
+}
+
+; Don't create an extra multiply if we can't eliminate the first div.
+
+declare void @use_f32(float)
+
+define float @div_with_div_numerator_extra_use(float %x, float %y, float %z) {
+; CHECK-LABEL: @div_with_div_numerator_extra_use(
+; CHECK-NEXT:    [[DIV1:%.*]] = fdiv float [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    [[DIV2:%.*]] = fdiv fast float [[DIV1]], [[Z:%.*]]
+; CHECK-NEXT:    call void @use_f32(float [[DIV1]])
+; CHECK-NEXT:    ret float [[DIV2]]
+;
+  %div1 = fdiv float %x, %y
+  %div2 = fdiv fast float %div1, %z
+  call void @use_f32(float %div1)
+  ret float %div2
+}
+
+define float @div_with_div_denominator_extra_use(float %x, float %y, float %z) {
+; CHECK-LABEL: @div_with_div_denominator_extra_use(
+; CHECK-NEXT:    [[DIV1:%.*]] = fdiv float [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    [[DIV2:%.*]] = fdiv fast float [[Z:%.*]], [[DIV1]]
+; CHECK-NEXT:    call void @use_f32(float [[DIV1]])
+; CHECK-NEXT:    ret float [[DIV2]]
+;
+  %div1 = fdiv float %x, %y
+  %div2 = fdiv fast float %z, %div1
+  call void @use_f32(float %div1)
+  ret float %div2
+}
+
+define float @fneg_fneg(float %x, float %y) {
+; CHECK-LABEL: @fneg_fneg(
+; CHECK-NEXT:    [[DIV:%.*]] = fdiv float [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    ret float [[DIV]]
+;
+  %x.fneg = fsub float -0.0, %x
+  %y.fneg = fsub float -0.0, %y
+  %div = fdiv float %x.fneg, %y.fneg
+  ret float %div
+}
+
+; The test above shows that no FMF are needed, but show that we are not dropping FMF.
+
+define float @fneg_fneg_fast(float %x, float %y) {
+; CHECK-LABEL: @fneg_fneg_fast(
+; CHECK-NEXT:    [[DIV:%.*]] = fdiv fast float [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    ret float [[DIV]]
+;
+  %x.fneg = fsub float -0.0, %x
+  %y.fneg = fsub float -0.0, %y
+  %div = fdiv fast float %x.fneg, %y.fneg
+  ret float %div
+}
+
+define <2 x float> @fneg_fneg_vec(<2 x float> %x, <2 x float> %y) {
+; CHECK-LABEL: @fneg_fneg_vec(
+; CHECK-NEXT:    [[DIV:%.*]] = fdiv <2 x float> [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    ret <2 x float> [[DIV]]
+;
+  %xneg = fsub <2 x float> <float -0.0, float -0.0>, %x
+  %yneg = fsub <2 x float> <float -0.0, float -0.0>, %y
+  %div = fdiv <2 x float> %xneg, %yneg
+  ret <2 x float> %div
+}
+
+define <2 x float> @fneg_fneg_vec_undef_elts(<2 x float> %x, <2 x float> %y) {
+; CHECK-LABEL: @fneg_fneg_vec_undef_elts(
+; CHECK-NEXT:    [[DIV:%.*]] = fdiv <2 x float> [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    ret <2 x float> [[DIV]]
+;
+  %xneg = fsub <2 x float> <float undef, float -0.0>, %x
+  %yneg = fsub <2 x float> <float -0.0, float undef>, %y
+  %div = fdiv <2 x float> %xneg, %yneg
+  ret <2 x float> %div
+}
+
+define float @fneg_dividend_constant_divisor(float %x) {
+; CHECK-LABEL: @fneg_dividend_constant_divisor(
+; CHECK-NEXT:    [[DIV:%.*]] = fdiv nsz float [[X:%.*]], -3.000000e+00
+; CHECK-NEXT:    ret float [[DIV]]
+;
+  %neg = fsub float -0.0, %x
+  %div = fdiv nsz float %neg, 3.0
+  ret  float %div
+}
+
+define float @fneg_divisor_constant_dividend(float %x) {
+; CHECK-LABEL: @fneg_divisor_constant_dividend(
+; CHECK-NEXT:    [[DIV:%.*]] = fdiv nnan float 3.000000e+00, [[X:%.*]]
+; CHECK-NEXT:    ret float [[DIV]]
+;
+  %neg = fsub float -0.0, %x
+  %div = fdiv nnan float -3.0, %neg
+  ret float %div
+}
+
+define <2 x float> @fneg_dividend_constant_divisor_vec(<2 x float> %x) {
+; CHECK-LABEL: @fneg_dividend_constant_divisor_vec(
+; CHECK-NEXT:    [[DIV:%.*]] = fdiv ninf <2 x float> [[X:%.*]], <float -3.000000e+00, float 8.000000e+00>
+; CHECK-NEXT:    ret <2 x float> [[DIV]]
+;
+  %neg = fsub <2 x float> <float -0.0, float -0.0>, %x
+  %div = fdiv ninf <2 x float> %neg, <float 3.0, float -8.0>
+  ret <2 x float> %div
+}
+
+define <2 x float> @fneg_dividend_constant_divisor_vec_undef_elt(<2 x float> %x) {
+; CHECK-LABEL: @fneg_dividend_constant_divisor_vec_undef_elt(
+; CHECK-NEXT:    [[DIV:%.*]] = fdiv ninf <2 x float> [[X:%.*]], <float -3.000000e+00, float 8.000000e+00>
+; CHECK-NEXT:    ret <2 x float> [[DIV]]
+;
+  %neg = fsub <2 x float> <float undef, float -0.0>, %x
+  %div = fdiv ninf <2 x float> %neg, <float 3.0, float -8.0>
+  ret <2 x float> %div
+}
+
+define <2 x float> @fneg_divisor_constant_dividend_vec(<2 x float> %x) {
+; CHECK-LABEL: @fneg_divisor_constant_dividend_vec(
+; CHECK-NEXT:    [[DIV:%.*]] = fdiv afn <2 x float> <float 3.000000e+00, float -5.000000e+00>, [[X:%.*]]
+; CHECK-NEXT:    ret <2 x float> [[DIV]]
+;
+  %neg = fsub <2 x float> <float -0.0, float -0.0>, %x
+  %div = fdiv afn <2 x float> <float -3.0, float 5.0>, %neg
+  ret <2 x float> %div
+}
+
+; X / (X * Y) --> 1.0 / Y
+
+define float @div_factor(float %x, float %y) {
+; CHECK-LABEL: @div_factor(
+; CHECK-NEXT:    [[D:%.*]] = fdiv reassoc nnan float 1.000000e+00, [[Y:%.*]]
+; CHECK-NEXT:    ret float [[D]]
+;
+  %m = fmul float %x, %y
+  %d = fdiv nnan reassoc float %x, %m
+  ret float %d;
+}
+
+; We can't do the transform without 'nnan' because if x is NAN and y is a number, this should return NAN.
+
+define float @div_factor_too_strict(float %x, float %y) {
+; CHECK-LABEL: @div_factor_too_strict(
+; CHECK-NEXT:    [[M:%.*]] = fmul float [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    [[D:%.*]] = fdiv reassoc float [[X]], [[M]]
+; CHECK-NEXT:    ret float [[D]]
+;
+  %m = fmul float %x, %y
+  %d = fdiv reassoc float %x, %m
+  ret float %d
+}
+
+; Commute, verify vector types, and show that we are not dropping extra FMF.
+; X / (Y * X) --> 1.0 / Y
+
+define <2 x float> @div_factor_commute(<2 x float> %x, <2 x float> %y) {
+; CHECK-LABEL: @div_factor_commute(
+; CHECK-NEXT:    [[D:%.*]] = fdiv reassoc nnan ninf nsz <2 x float> <float 1.000000e+00, float 1.000000e+00>, [[Y:%.*]]
+; CHECK-NEXT:    ret <2 x float> [[D]]
+;
+  %m = fmul <2 x float> %y, %x
+  %d = fdiv nnan ninf nsz reassoc <2 x float> %x, %m
+  ret <2 x float> %d
+}
+
+; C1/(X*C2) => (C1/C2) / X
+
+define <2 x float> @div_constant_dividend1(<2 x float> %x) {
+; CHECK-LABEL: @div_constant_dividend1(
+; CHECK-NEXT:    [[T2:%.*]] = fdiv reassoc arcp <2 x float> <float 5.000000e+00, float 1.000000e+00>, [[X:%.*]]
+; CHECK-NEXT:    ret <2 x float> [[T2]]
+;
+  %t1 = fmul <2 x float> %x, <float 3.0e0, float 7.0e0>
+  %t2 = fdiv arcp reassoc <2 x float> <float 15.0e0, float 7.0e0>, %t1
+  ret <2 x float> %t2
+}
+
+define <2 x float> @div_constant_dividend1_arcp_only(<2 x float> %x) {
+; CHECK-LABEL: @div_constant_dividend1_arcp_only(
+; CHECK-NEXT:    [[T1:%.*]] = fmul <2 x float> [[X:%.*]], <float 3.000000e+00, float 7.000000e+00>
+; CHECK-NEXT:    [[T2:%.*]] = fdiv arcp <2 x float> <float 1.500000e+01, float 7.000000e+00>, [[T1]]
+; CHECK-NEXT:    ret <2 x float> [[T2]]
+;
+  %t1 = fmul <2 x float> %x, <float 3.0e0, float 7.0e0>
+  %t2 = fdiv arcp <2 x float> <float 15.0e0, float 7.0e0>, %t1
+  ret <2 x float> %t2
+}
+
+; C1/(X/C2) => (C1*C2) / X
+
+define <2 x float> @div_constant_dividend2(<2 x float> %x) {
+; CHECK-LABEL: @div_constant_dividend2(
+; CHECK-NEXT:    [[T2:%.*]] = fdiv reassoc arcp <2 x float> <float 4.500000e+01, float 4.900000e+01>, [[X:%.*]]
+; CHECK-NEXT:    ret <2 x float> [[T2]]
+;
+  %t1 = fdiv <2 x float> %x, <float 3.0e0, float -7.0e0>
+  %t2 = fdiv arcp reassoc <2 x float> <float 15.0e0, float -7.0e0>, %t1
+  ret <2 x float> %t2
+}
+
+define <2 x float> @div_constant_dividend2_reassoc_only(<2 x float> %x) {
+; CHECK-LABEL: @div_constant_dividend2_reassoc_only(
+; CHECK-NEXT:    [[T1:%.*]] = fdiv <2 x float> [[X:%.*]], <float 3.000000e+00, float -7.000000e+00>
+; CHECK-NEXT:    [[T2:%.*]] = fdiv reassoc <2 x float> <float 1.500000e+01, float -7.000000e+00>, [[T1]]
+; CHECK-NEXT:    ret <2 x float> [[T2]]
+;
+  %t1 = fdiv <2 x float> %x, <float 3.0e0, float -7.0e0>
+  %t2 = fdiv reassoc <2 x float> <float 15.0e0, float -7.0e0>, %t1
+  ret <2 x float> %t2
+}
+
+; C1/(C2/X) => (C1/C2) * X
+; This tests the combination of 2 folds: (C1 * X) / C2 --> (C1 / C2) * X
+
+define <2 x float> @div_constant_dividend3(<2 x float> %x) {
+; CHECK-LABEL: @div_constant_dividend3(
+; CHECK-NEXT:    [[TMP1:%.*]] = fmul reassoc arcp <2 x float> [[X:%.*]], <float 1.500000e+01, float -7.000000e+00>
+; CHECK-NEXT:    [[T2:%.*]] = fmul reassoc arcp <2 x float> [[TMP1]], <float 0x3FD5555560000000, float 0x3FC24924A0000000>
+; CHECK-NEXT:    ret <2 x float> [[T2]]
+;
+  %t1 = fdiv <2 x float> <float 3.0e0, float 7.0e0>, %x
+  %t2 = fdiv arcp reassoc <2 x float> <float 15.0e0, float -7.0e0>, %t1
+  ret <2 x float> %t2
+}
+

Added: llvm/trunk/test/Transforms/InstCombine/ffs-1.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/ffs-1.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/ffs-1.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/ffs-1.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,193 @@
+; Test that the ffs* library call simplifier works correctly.
+;
+; RUN: opt < %s -instcombine -S                                    | FileCheck %s --check-prefix=ALL --check-prefix=GENERIC
+; RUN: opt < %s -instcombine -mtriple i386-pc-linux -S             | FileCheck %s --check-prefix=ALL --check-prefix=TARGET
+; RUN: opt < %s -instcombine -mtriple=arm64-apple-ios9.0 -S        | FileCheck %s --check-prefix=ALL --check-prefix=TARGET
+; RUN: opt < %s -instcombine -mtriple=arm64-apple-tvos9.0 -S       | FileCheck %s --check-prefix=ALL --check-prefix=TARGET
+; RUN: opt < %s -instcombine -mtriple=thumbv7k-apple-watchos2.0 -S | FileCheck %s --check-prefix=ALL --check-prefix=TARGET
+; RUN: opt < %s -instcombine -mtriple=x86_64-apple-macosx10.11 -S  | FileCheck %s --check-prefix=ALL --check-prefix=TARGET
+; RUN: opt < %s -instcombine -mtriple=x86_64-freebsd-gnu -S        | FileCheck %s --check-prefix=ALL --check-prefix=TARGET
+
+declare i32 @ffs(i32)
+declare i32 @ffsl(i32)
+declare i32 @ffsll(i64)
+
+; Check ffs(0) -> 0.
+
+define i32 @test_simplify1() {
+; ALL-LABEL: @test_simplify1(
+; ALL-NEXT:    ret i32 0
+;
+  %ret = call i32 @ffs(i32 0)
+  ret i32 %ret
+}
+
+define i32 @test_simplify2() {
+; GENERIC-LABEL: @test_simplify2(
+; GENERIC-NEXT:    [[RET:%.*]] = call i32 @ffsl(i32 0)
+; GENERIC-NEXT:    ret i32 [[RET]]
+;
+; TARGET-LABEL: @test_simplify2(
+; TARGET-NEXT:    ret i32 0
+;
+  %ret = call i32 @ffsl(i32 0)
+  ret i32 %ret
+}
+
+define i32 @test_simplify3() {
+; GENERIC-LABEL: @test_simplify3(
+; GENERIC-NEXT:    [[RET:%.*]] = call i32 @ffsll(i64 0)
+; GENERIC-NEXT:    ret i32 [[RET]]
+;
+; TARGET-LABEL: @test_simplify3(
+; TARGET-NEXT:    ret i32 0
+;
+  %ret = call i32 @ffsll(i64 0)
+  ret i32 %ret
+}
+
+; Check ffs(c) -> cttz(c) + 1, where 'c' is a constant.
+
+define i32 @test_simplify4() {
+; ALL-LABEL: @test_simplify4(
+; ALL-NEXT:    ret i32 1
+;
+  %ret = call i32 @ffs(i32 1)
+  ret i32 %ret
+}
+
+define i32 @test_simplify5() {
+; ALL-LABEL: @test_simplify5(
+; ALL-NEXT:    ret i32 12
+;
+  %ret = call i32 @ffs(i32 2048)
+  ret i32 %ret
+}
+
+define i32 @test_simplify6() {
+; ALL-LABEL: @test_simplify6(
+; ALL-NEXT:    ret i32 17
+;
+  %ret = call i32 @ffs(i32 65536)
+  ret i32 %ret
+}
+
+define i32 @test_simplify7() {
+; GENERIC-LABEL: @test_simplify7(
+; GENERIC-NEXT:    [[RET:%.*]] = call i32 @ffsl(i32 65536)
+; GENERIC-NEXT:    ret i32 [[RET]]
+;
+; TARGET-LABEL: @test_simplify7(
+; TARGET-NEXT:    ret i32 17
+;
+  %ret = call i32 @ffsl(i32 65536)
+  ret i32 %ret
+}
+
+define i32 @test_simplify8() {
+; GENERIC-LABEL: @test_simplify8(
+; GENERIC-NEXT:    [[RET:%.*]] = call i32 @ffsll(i64 1024)
+; GENERIC-NEXT:    ret i32 [[RET]]
+;
+; TARGET-LABEL: @test_simplify8(
+; TARGET-NEXT:    ret i32 11
+;
+  %ret = call i32 @ffsll(i64 1024)
+  ret i32 %ret
+}
+
+define i32 @test_simplify9() {
+; GENERIC-LABEL: @test_simplify9(
+; GENERIC-NEXT:    [[RET:%.*]] = call i32 @ffsll(i64 65536)
+; GENERIC-NEXT:    ret i32 [[RET]]
+;
+; TARGET-LABEL: @test_simplify9(
+; TARGET-NEXT:    ret i32 17
+;
+  %ret = call i32 @ffsll(i64 65536)
+  ret i32 %ret
+}
+
+define i32 @test_simplify10() {
+; GENERIC-LABEL: @test_simplify10(
+; GENERIC-NEXT:    [[RET:%.*]] = call i32 @ffsll(i64 17179869184)
+; GENERIC-NEXT:    ret i32 [[RET]]
+;
+; TARGET-LABEL: @test_simplify10(
+; TARGET-NEXT:    ret i32 35
+;
+  %ret = call i32 @ffsll(i64 17179869184)
+  ret i32 %ret
+}
+
+define i32 @test_simplify11() {
+; GENERIC-LABEL: @test_simplify11(
+; GENERIC-NEXT:    [[RET:%.*]] = call i32 @ffsll(i64 281474976710656)
+; GENERIC-NEXT:    ret i32 [[RET]]
+;
+; TARGET-LABEL: @test_simplify11(
+; TARGET-NEXT:    ret i32 49
+;
+  %ret = call i32 @ffsll(i64 281474976710656)
+  ret i32 %ret
+}
+
+define i32 @test_simplify12() {
+; GENERIC-LABEL: @test_simplify12(
+; GENERIC-NEXT:    [[RET:%.*]] = call i32 @ffsll(i64 1152921504606846976)
+; GENERIC-NEXT:    ret i32 [[RET]]
+;
+; TARGET-LABEL: @test_simplify12(
+; TARGET-NEXT:    ret i32 61
+;
+  %ret = call i32 @ffsll(i64 1152921504606846976)
+  ret i32 %ret
+}
+
+; Check ffs(x) -> x != 0 ? (i32)llvm.cttz(x) + 1 : 0.
+
+define i32 @test_simplify13(i32 %x) {
+; ALL-LABEL: @test_simplify13(
+; ALL-NEXT:    [[CTTZ:%.*]] = call i32 @llvm.cttz.i32(i32 %x, i1 true), !range !0
+; ALL-NEXT:    [[TMP1:%.*]] = add nuw nsw i32 [[CTTZ]], 1
+; ALL-NEXT:    [[TMP2:%.*]] = icmp eq i32 %x, 0
+; ALL-NEXT:    [[TMP3:%.*]] = select i1 [[TMP2]], i32 0, i32 [[TMP1]]
+; ALL-NEXT:    ret i32 [[TMP3]]
+;
+  %ret = call i32 @ffs(i32 %x)
+  ret i32 %ret
+}
+
+define i32 @test_simplify14(i32 %x) {
+; GENERIC-LABEL: @test_simplify14(
+; GENERIC-NEXT:    [[RET:%.*]] = call i32 @ffsl(i32 %x)
+; GENERIC-NEXT:    ret i32 [[RET]]
+;
+; TARGET-LABEL: @test_simplify14(
+; TARGET-NEXT:    [[CTTZ:%.*]] = call i32 @llvm.cttz.i32(i32 %x, i1 true), !range !0
+; TARGET-NEXT:    [[TMP1:%.*]] = add nuw nsw i32 [[CTTZ]], 1
+; TARGET-NEXT:    [[TMP2:%.*]] = icmp eq i32 %x, 0
+; TARGET-NEXT:    [[TMP3:%.*]] = select i1 [[TMP2]], i32 0, i32 [[TMP1]]
+; TARGET-NEXT:    ret i32 [[TMP3]]
+;
+  %ret = call i32 @ffsl(i32 %x)
+  ret i32 %ret
+}
+
+define i32 @test_simplify15(i64 %x) {
+; GENERIC-LABEL: @test_simplify15(
+; GENERIC-NEXT:    [[RET:%.*]] = call i32 @ffsll(i64 %x)
+; GENERIC-NEXT:    ret i32 [[RET]]
+;
+; TARGET-LABEL: @test_simplify15(
+; TARGET-NEXT:    [[CTTZ:%.*]] = call i64 @llvm.cttz.i64(i64 %x, i1 true), !range !1
+; TARGET-NEXT:    [[TMP1:%.*]] = trunc i64 [[CTTZ]] to i32
+; TARGET-NEXT:    [[TMP2:%.*]] = add nuw nsw i32 [[TMP1]], 1
+; TARGET-NEXT:    [[TMP3:%.*]] = icmp eq i64 %x, 0
+; TARGET-NEXT:    [[TMP4:%.*]] = select i1 [[TMP3]], i32 0, i32 [[TMP2]]
+; TARGET-NEXT:    ret i32 [[TMP4]]
+;
+  %ret = call i32 @ffsll(i64 %x)
+  ret i32 %ret
+}
+

Added: llvm/trunk/test/Transforms/InstCombine/float-shrink-compare.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/float-shrink-compare.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/float-shrink-compare.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/float-shrink-compare.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,473 @@
+; 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"
+target triple = "x86_64-apple-macosx10.8.0"
+
+define i1 @test1(float %x, float %y) {
+; CHECK-LABEL: @test1(
+; CHECK-NEXT:    [[CEIL:%.*]] = call float @llvm.ceil.f32(float %x)
+; CHECK-NEXT:    [[CMP:%.*]] = fcmp oeq float [[CEIL]], %y
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %x.ext = fpext float %x to double
+  %ceil = call double @ceil(double %x.ext) nounwind readnone
+  %ext.y = fpext float %y to double
+  %cmp = fcmp oeq double %ceil, %ext.y
+  ret i1 %cmp
+}
+
+define i1 @test1_intrin(float %x, float %y) {
+; CHECK-LABEL: @test1_intrin(
+; CHECK-NEXT:    [[CEIL:%.*]] = call float @llvm.ceil.f32(float %x)
+; CHECK-NEXT:    [[CMP:%.*]] = fcmp oeq float [[CEIL]], %y
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %x.ext = fpext float %x to double
+  %ceil = call double @llvm.ceil.f64(double %x.ext) nounwind readnone
+  %ext.y = fpext float %y to double
+  %cmp = fcmp oeq double %ceil, %ext.y
+  ret i1 %cmp
+}
+
+define i1 @test2(float %x, float %y) {
+; CHECK-LABEL: @test2(
+; CHECK-NEXT:    [[FABS:%.*]] = call float @llvm.fabs.f32(float %x)
+; CHECK-NEXT:    [[CMP:%.*]] = fcmp oeq float [[FABS]], %y
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %x.ext = fpext float %x to double
+  %fabs = call double @fabs(double %x.ext) nounwind readnone
+  %y.ext = fpext float %y to double
+  %cmp = fcmp oeq double %fabs, %y.ext
+  ret i1 %cmp
+}
+
+define i1 @test2_intrin(float %x, float %y) {
+; CHECK-LABEL: @test2_intrin(
+; CHECK-NEXT:    [[FABS:%.*]] = call float @llvm.fabs.f32(float %x)
+; CHECK-NEXT:    [[CMP:%.*]] = fcmp oeq float [[FABS]], %y
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %x.ext = fpext float %x to double
+  %fabs = call double @llvm.fabs.f64(double %x.ext) nounwind readnone
+  %y.ext = fpext float %y to double
+  %cmp = fcmp oeq double %fabs, %y.ext
+  ret i1 %cmp
+}
+
+define i1 @fmf_test2(float %x, float %y) {
+; CHECK-LABEL: @fmf_test2(
+; CHECK-NEXT:    [[TMP1:%.*]] = call nnan float @llvm.fabs.f32(float %x)
+; CHECK-NEXT:    [[TMP2:%.*]] = fcmp oeq float [[TMP1]], %y
+; CHECK-NEXT:    ret i1 [[TMP2]]
+;
+  %1 = fpext float %x to double
+  %2 = call nnan double @fabs(double %1) nounwind readnone
+  %3 = fpext float %y to double
+  %4 = fcmp oeq double %2, %3
+  ret i1 %4
+}
+
+define i1 @test3(float %x, float %y) {
+; CHECK-LABEL: @test3(
+; CHECK-NEXT:    [[FLOOR:%.*]] = call float @llvm.floor.f32(float %x)
+; CHECK-NEXT:    [[CMP:%.*]] = fcmp oeq float [[FLOOR]], %y
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %x.ext = fpext float %x to double
+  %floor = call double @floor(double %x.ext) nounwind readnone
+  %y.ext = fpext float %y to double
+  %cmp = fcmp oeq double %floor, %y.ext
+  ret i1 %cmp
+}
+
+
+define i1 @test3_intrin(float %x, float %y) {
+; CHECK-LABEL: @test3_intrin(
+; CHECK-NEXT:    [[FLOOR:%.*]] = call float @llvm.floor.f32(float %x)
+; CHECK-NEXT:    [[CMP:%.*]] = fcmp oeq float [[FLOOR]], %y
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %x.ext = fpext float %x to double
+  %floor = call double @llvm.floor.f64(double %x.ext) nounwind readnone
+  %y.ext = fpext float %y to double
+  %cmp = fcmp oeq double %floor, %y.ext
+  ret i1 %cmp
+}
+
+define i1 @test4(float %x, float %y) {
+; CHECK-LABEL: @test4(
+; CHECK-NEXT:    [[NEARBYINT:%.*]] = call float @llvm.nearbyint.f32(float %x)
+; CHECK-NEXT:    [[CMP:%.*]] = fcmp oeq float [[NEARBYINT]], %y
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %x.ext = fpext float %x to double
+  %nearbyint = call double @nearbyint(double %x.ext) nounwind
+  %y.ext = fpext float %y to double
+  %cmp = fcmp oeq double %nearbyint, %y.ext
+  ret i1 %cmp
+}
+
+define i1 @shrink_nearbyint_intrin(float %x, float %y) {
+; CHECK-LABEL: @shrink_nearbyint_intrin(
+; CHECK-NEXT:    [[NEARBYINT:%.*]] = call float @llvm.nearbyint.f32(float %x)
+; CHECK-NEXT:    [[CMP:%.*]] = fcmp oeq float [[NEARBYINT]], %y
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %x.ext = fpext float %x to double
+  %nearbyint = call double @llvm.nearbyint.f64(double %x.ext) nounwind
+  %y.ext = fpext float %y to double
+  %cmp = fcmp oeq double %nearbyint, %y.ext
+  ret i1 %cmp
+}
+
+define i1 @test5(float %x, float %y) {
+; CHECK-LABEL: @test5(
+; CHECK-NEXT:    [[RINT:%.*]] = call float @llvm.rint.f32(float %x)
+; CHECK-NEXT:    [[CMP:%.*]] = fcmp oeq float [[RINT]], %y
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %x.ext = fpext float %x to double
+  %rint = call double @rint(double %x.ext) nounwind
+  %y.ext = fpext float %y to double
+  %cmp = fcmp oeq double %rint, %y.ext
+  ret i1 %cmp
+}
+
+define i1 @test6(float %x, float %y) {
+; CHECK-LABEL: @test6(
+; CHECK-NEXT:    [[ROUND:%.*]] = call float @llvm.round.f32(float %x)
+; CHECK-NEXT:    [[CMP:%.*]] = fcmp oeq float [[ROUND]], %y
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %x.ext = fpext float %x to double
+  %round = call double @round(double %x.ext) nounwind readnone
+  %y.ext = fpext float %y to double
+  %cmp = fcmp oeq double %round, %y.ext
+  ret i1 %cmp
+}
+
+define i1 @test6_intrin(float %x, float %y) {
+; CHECK-LABEL: @test6_intrin(
+; CHECK-NEXT:    [[ROUND:%.*]] = call float @llvm.round.f32(float %x)
+; CHECK-NEXT:    [[CMP:%.*]] = fcmp oeq float [[ROUND]], %y
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %x.ext = fpext float %x to double
+  %round = call double @llvm.round.f64(double %x.ext) nounwind readnone
+  %y.ext = fpext float %y to double
+  %cmp = fcmp oeq double %round, %y.ext
+  ret i1 %cmp
+}
+
+define i1 @test7(float %x, float %y) {
+; CHECK-LABEL: @test7(
+; CHECK-NEXT:    [[TRUNC:%.*]] = call float @llvm.trunc.f32(float %x)
+; CHECK-NEXT:    [[CMP:%.*]] = fcmp oeq float [[TRUNC]], %y
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %x.ext = fpext float %x to double
+  %trunc = call double @trunc(double %x.ext) nounwind
+  %y.ext = fpext float %y to double
+  %cmp = fcmp oeq double %trunc, %y.ext
+  ret i1 %cmp
+}
+
+define i1 @test7_intrin(float %x, float %y) {
+; CHECK-LABEL: @test7_intrin(
+; CHECK-NEXT:    [[TRUNC:%.*]] = call float @llvm.trunc.f32(float %x)
+; CHECK-NEXT:    [[CMP:%.*]] = fcmp oeq float [[TRUNC]], %y
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %x.ext = fpext float %x to double
+  %trunc = call double @llvm.trunc.f64(double %x.ext) nounwind
+  %y.ext = fpext float %y to double
+  %cmp = fcmp oeq double %trunc, %y.ext
+  ret i1 %cmp
+}
+
+define i1 @test8(float %x, float %y) {
+; CHECK-LABEL: @test8(
+; CHECK-NEXT:    [[CEIL:%.*]] = call float @llvm.ceil.f32(float %x)
+; CHECK-NEXT:    [[CMP:%.*]] = fcmp oeq float [[CEIL]], %y
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %x.ext = fpext float %x to double
+  %y.ext = fpext float %y to double
+  %ceil = call double @ceil(double %x.ext) nounwind readnone
+  %cmp = fcmp oeq double %y.ext, %ceil
+  ret i1 %cmp
+}
+
+define i1 @test8_intrin(float %x, float %y) {
+; CHECK-LABEL: @test8_intrin(
+; CHECK-NEXT:    [[CEIL:%.*]] = call float @llvm.ceil.f32(float %x)
+; CHECK-NEXT:    [[CMP:%.*]] = fcmp oeq float [[CEIL]], %y
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %x.ext = fpext float %x to double
+  %y.ext = fpext float %y to double
+  %ceil = call double @llvm.ceil.f64(double %x.ext) nounwind readnone
+  %cmp = fcmp oeq double %y.ext, %ceil
+  ret i1 %cmp
+}
+
+define i1 @test9(float %x, float %y) {
+; CHECK-LABEL: @test9(
+; CHECK-NEXT:    [[FABS:%.*]] = call float @llvm.fabs.f32(float %x)
+; CHECK-NEXT:    [[CMP:%.*]] = fcmp oeq float [[FABS]], %y
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %x.ext = fpext float %x to double
+  %y.ext = fpext float %y to double
+  %fabs = call double @fabs(double %x.ext) nounwind readnone
+  %cmp = fcmp oeq double %y.ext, %fabs
+  ret i1 %cmp
+}
+
+define i1 @test9_intrin(float %x, float %y) {
+; CHECK-LABEL: @test9_intrin(
+; CHECK-NEXT:    [[FABS:%.*]] = call float @llvm.fabs.f32(float %x)
+; CHECK-NEXT:    [[CMP:%.*]] = fcmp oeq float [[FABS]], %y
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %x.ext = fpext float %x to double
+  %y.ext = fpext float %y to double
+  %fabs = call double @llvm.fabs.f64(double %x.ext) nounwind readnone
+  %cmp = fcmp oeq double %y.ext, %fabs
+  ret i1 %cmp
+}
+
+define i1 @test10(float %x, float %y) {
+; CHECK-LABEL: @test10(
+; CHECK-NEXT:    [[FLOOR:%.*]] = call float @llvm.floor.f32(float %x)
+; CHECK-NEXT:    [[CMP:%.*]] = fcmp oeq float [[FLOOR]], %y
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %x.ext = fpext float %x to double
+  %y.ext = fpext float %y to double
+  %floor = call double @floor(double %x.ext) nounwind readnone
+  %cmp = fcmp oeq double %floor, %y.ext
+  ret i1 %cmp
+}
+
+define i1 @test10_intrin(float %x, float %y) {
+; CHECK-LABEL: @test10_intrin(
+; CHECK-NEXT:    [[FLOOR:%.*]] = call float @llvm.floor.f32(float %x)
+; CHECK-NEXT:    [[CMP:%.*]] = fcmp oeq float [[FLOOR]], %y
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %x.ext = fpext float %x to double
+  %y.ext = fpext float %y to double
+  %floor = call double @llvm.floor.f64(double %x.ext) nounwind readnone
+  %cmp = fcmp oeq double %floor, %y.ext
+  ret i1 %cmp
+}
+
+define i1 @test11(float %x, float %y) {
+; CHECK-LABEL: @test11(
+; CHECK-NEXT:    [[NEARBYINT:%.*]] = call float @llvm.nearbyint.f32(float %x)
+; CHECK-NEXT:    [[CMP:%.*]] = fcmp oeq float [[NEARBYINT]], %y
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %x.ext = fpext float %x to double
+  %y.ext = fpext float %y to double
+  %nearbyint = call double @nearbyint(double %x.ext) nounwind
+  %cmp = fcmp oeq double %nearbyint, %y.ext
+  ret i1 %cmp
+}
+
+define i1 @test11_intrin(float %x, float %y) {
+; CHECK-LABEL: @test11_intrin(
+; CHECK-NEXT:    [[NEARBYINT:%.*]] = call float @llvm.nearbyint.f32(float %x)
+; CHECK-NEXT:    [[CMP:%.*]] = fcmp oeq float [[NEARBYINT]], %y
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %x.ext = fpext float %x to double
+  %y.ext = fpext float %y to double
+  %nearbyint = call double @llvm.nearbyint.f64(double %x.ext) nounwind
+  %cmp = fcmp oeq double %nearbyint, %y.ext
+  ret i1 %cmp
+}
+
+define i1 @test12(float %x, float %y) {
+; CHECK-LABEL: @test12(
+; CHECK-NEXT:    [[RINT:%.*]] = call float @llvm.rint.f32(float %x)
+; CHECK-NEXT:    [[CMP:%.*]] = fcmp oeq float [[RINT]], %y
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %x.ext = fpext float %x to double
+  %y.ext = fpext float %y to double
+  %rint = call double @rint(double %x.ext) nounwind
+  %cmp = fcmp oeq double %y.ext, %rint
+  ret i1 %cmp
+}
+
+define i1 @test13(float %x, float %y) {
+; CHECK-LABEL: @test13(
+; CHECK-NEXT:    [[ROUND:%.*]] = call float @llvm.round.f32(float %x)
+; CHECK-NEXT:    [[CMP:%.*]] = fcmp oeq float [[ROUND]], %y
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %x.ext = fpext float %x to double
+  %y.ext = fpext float %y to double
+  %round = call double @round(double %x.ext) nounwind readnone
+  %cmp = fcmp oeq double %y.ext, %round
+  ret i1 %cmp
+}
+
+define i1 @test13_intrin(float %x, float %y) {
+; CHECK-LABEL: @test13_intrin(
+; CHECK-NEXT:    [[ROUND:%.*]] = call float @llvm.round.f32(float %x)
+; CHECK-NEXT:    [[CMP:%.*]] = fcmp oeq float [[ROUND]], %y
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %x.ext = fpext float %x to double
+  %y.ext = fpext float %y to double
+  %round = call double @llvm.round.f64(double %x.ext) nounwind readnone
+  %cmp = fcmp oeq double %y.ext, %round
+  ret i1 %cmp
+}
+
+define i1 @test14(float %x, float %y) {
+; CHECK-LABEL: @test14(
+; CHECK-NEXT:    [[TRUNC:%.*]] = call float @llvm.trunc.f32(float %x)
+; CHECK-NEXT:    [[CMP:%.*]] = fcmp oeq float [[TRUNC]], %y
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %x.ext = fpext float %x to double
+  %y.ext = fpext float %y to double
+  %trunc = call double @trunc(double %x.ext) nounwind
+  %cmp = fcmp oeq double %y.ext, %trunc
+  ret i1 %cmp
+}
+
+define i1 @test14_intrin(float %x, float %y) {
+; CHECK-LABEL: @test14_intrin(
+; CHECK-NEXT:    [[TRUNC:%.*]] = call float @llvm.trunc.f32(float %x)
+; CHECK-NEXT:    [[CMP:%.*]] = fcmp oeq float [[TRUNC]], %y
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %x.ext = fpext float %x to double
+  %y.ext = fpext float %y to double
+  %trunc = call double @llvm.trunc.f64(double %x.ext) nounwind
+  %cmp = fcmp oeq double %y.ext, %trunc
+  ret i1 %cmp
+}
+
+define i1 @test15(float %x, float %y, float %z) {
+; CHECK-LABEL: @test15(
+; CHECK-NEXT:    [[FMINF:%.*]] = call float @fminf(float %x, float %y) #0
+; CHECK-NEXT:    [[TMP1:%.*]] = fcmp oeq float [[FMINF]], %z
+; CHECK-NEXT:    ret i1 [[TMP1]]
+;
+  %1 = fpext float %x to double
+  %2 = fpext float %y to double
+  %3 = call double @fmin(double %1, double %2) nounwind
+  %4 = fpext float %z to double
+  %5 = fcmp oeq double %3, %4
+  ret i1 %5
+}
+
+define i1 @test16(float %x, float %y, float %z) {
+; CHECK-LABEL: @test16(
+; CHECK-NEXT:    [[FMINF:%.*]] = call float @fminf(float %x, float %y) #0
+; CHECK-NEXT:    [[TMP1:%.*]] = fcmp oeq float [[FMINF]], %z
+; CHECK-NEXT:    ret i1 [[TMP1]]
+;
+  %1 = fpext float %z to double
+  %2 = fpext float %x to double
+  %3 = fpext float %y to double
+  %4 = call double @fmin(double %2, double %3) nounwind
+  %5 = fcmp oeq double %1, %4
+  ret i1 %5
+}
+
+define i1 @test17(float %x, float %y, float %z) {
+; CHECK-LABEL: @test17(
+; CHECK-NEXT:    [[FMAXF:%.*]] = call float @fmaxf(float %x, float %y) #0
+; CHECK-NEXT:    [[TMP1:%.*]] = fcmp oeq float [[FMAXF]], %z
+; CHECK-NEXT:    ret i1 [[TMP1]]
+;
+  %1 = fpext float %x to double
+  %2 = fpext float %y to double
+  %3 = call double @fmax(double %1, double %2) nounwind
+  %4 = fpext float %z to double
+  %5 = fcmp oeq double %3, %4
+  ret i1 %5
+}
+
+define i1 @test18(float %x, float %y, float %z) {
+; CHECK-LABEL: @test18(
+; CHECK-NEXT:    [[FMAXF:%.*]] = call float @fmaxf(float %x, float %y) #0
+; CHECK-NEXT:    [[TMP1:%.*]] = fcmp oeq float [[FMAXF]], %z
+; CHECK-NEXT:    ret i1 [[TMP1]]
+;
+  %1 = fpext float %z to double
+  %2 = fpext float %x to double
+  %3 = fpext float %y to double
+  %4 = call double @fmax(double %2, double %3) nounwind
+  %5 = fcmp oeq double %1, %4
+  ret i1 %5
+}
+
+define i1 @test19(float %x, float %y, float %z) {
+; CHECK-LABEL: @test19(
+; CHECK-NEXT:    [[COPYSIGNF:%.*]] = call float @copysignf(float %x, float %y) #0
+; CHECK-NEXT:    [[TMP1:%.*]] = fcmp oeq float [[COPYSIGNF]], %z
+; CHECK-NEXT:    ret i1 [[TMP1]]
+;
+  %1 = fpext float %x to double
+  %2 = fpext float %y to double
+  %3 = call double @copysign(double %1, double %2) nounwind
+  %4 = fpext float %z to double
+  %5 = fcmp oeq double %3, %4
+  ret i1 %5
+}
+
+define i1 @test20(float %x, float %y) {
+; CHECK-LABEL: @test20(
+; CHECK-NEXT:    [[FMINF:%.*]] = call float @fminf(float 1.000000e+00, float %x) #0
+; CHECK-NEXT:    [[TMP1:%.*]] = fcmp oeq float [[FMINF]], %y
+; CHECK-NEXT:    ret i1 [[TMP1]]
+;
+  %1 = fpext float %y to double
+  %2 = fpext float %x to double
+  %3 = call double @fmin(double 1.000000e+00, double %2) nounwind
+  %4 = fcmp oeq double %1, %3
+  ret i1 %4
+}
+
+; should not be changed to fminf as the constant would lose precision
+
+define i1 @test21(float %x, float %y) {
+; CHECK-LABEL: @test21(
+; CHECK-NEXT:    [[TMP1:%.*]] = fpext float %y to double
+; CHECK-NEXT:    [[TMP2:%.*]] = fpext float %x to double
+; CHECK-NEXT:    [[TMP3:%.*]] = call double @fmin(double 1.300000e+00, double [[TMP2]]) #2
+; CHECK-NEXT:    [[TMP4:%.*]] = fcmp oeq double [[TMP3]], [[TMP1]]
+; CHECK-NEXT:    ret i1 [[TMP4]]
+;
+  %1 = fpext float %y to double
+  %2 = fpext float %x to double
+  %3 = call double @fmin(double 1.300000e+00, double %2) nounwind
+  %4 = fcmp oeq double %1, %3
+  ret i1 %4
+}
+
+declare double @fabs(double) nounwind readnone
+declare double @ceil(double) nounwind readnone
+declare double @copysign(double, double) nounwind readnone
+declare double @floor(double) nounwind readnone
+declare double @nearbyint(double) nounwind readnone
+declare double @rint(double) nounwind readnone
+declare double @round(double) nounwind readnone
+declare double @trunc(double) nounwind readnone
+declare double @fmin(double, double) nounwind readnone
+declare double @fmax(double, double) nounwind readnone
+
+declare double @llvm.fabs.f64(double) nounwind readnone
+declare double @llvm.ceil.f64(double) nounwind readnone
+declare double @llvm.floor.f64(double) nounwind readnone
+declare double @llvm.nearbyint.f64(double) nounwind readnone
+declare double @llvm.round.f64(double) nounwind readnone
+declare double @llvm.trunc.f64(double) nounwind readnone

Added: llvm/trunk/test/Transforms/InstCombine/fls.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/fls.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/fls.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/fls.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,54 @@
+; RUN: opt < %s -instcombine -S | FileCheck %s
+
+target triple = "x86_64-unknown-freebsd11.0"
+
+define i32 @myfls() {
+; CHECK-LABEL: @myfls(
+; CHECK-NEXT:    ret i32 6
+;
+  %call = call i32 @fls(i32 42)
+  ret i32 %call
+}
+
+define i32 @myflsl() {
+; CHECK-LABEL: @myflsl(
+; CHECK-NEXT:    ret i32 6
+;
+  %patatino = call i32 @flsl(i64 42)
+  ret i32 %patatino
+}
+
+define i32 @myflsll() {
+; CHECK-LABEL: @myflsll(
+; CHECK-NEXT:    ret i32 6
+;
+  %whatever = call i32 @flsll(i64 42)
+  ret i32 %whatever
+}
+
+; Lower to llvm.ctlz() if the argument is not a constant
+
+define i32 @flsnotconst(i64 %z) {
+; CHECK-LABEL: @flsnotconst(
+; CHECK-NEXT:    [[CTLZ:%.*]] = call i64 @llvm.ctlz.i64(i64 %z, i1 false), !range !0
+; CHECK-NEXT:    [[TMP1:%.*]] = trunc i64 [[CTLZ]] to i32
+; CHECK-NEXT:    [[TMP2:%.*]] = sub nsw i32 64, [[TMP1]]
+; CHECK-NEXT:    ret i32 [[TMP2]]
+;
+  %goo = call i32 @flsl(i64 %z)
+  ret i32 %goo
+}
+
+; Make sure we lower fls(0) to 0 and not to `undef`.
+
+define i32 @flszero() {
+; CHECK-LABEL: @flszero(
+; CHECK-NEXT:    ret i32 0
+;
+  %zero = call i32 @fls(i32 0)
+  ret i32 %zero
+}
+
+declare i32 @fls(i32)
+declare i32 @flsl(i64)
+declare i32 @flsll(i64)

Added: llvm/trunk/test/Transforms/InstCombine/fma.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/fma.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/fma.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/fma.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,277 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt -S -instcombine < %s | FileCheck %s
+
+declare float @llvm.fma.f32(float, float, float) #1
+declare <2 x float> @llvm.fma.v2f32(<2 x float>, <2 x float>, <2 x float>) #1
+declare float @llvm.fmuladd.f32(float, float, float) #1
+declare float @llvm.fabs.f32(float) #1
+
+ at external = external global i32
+
+define float @fma_fneg_x_fneg_y(float %x, float %y, float %z) {
+; CHECK-LABEL: @fma_fneg_x_fneg_y(
+; CHECK-NEXT:    [[FMA:%.*]] = call float @llvm.fma.f32(float [[X:%.*]], float [[Y:%.*]], float [[Z:%.*]])
+; CHECK-NEXT:    ret float [[FMA]]
+;
+  %x.fneg = fsub float -0.0, %x
+  %y.fneg = fsub float -0.0, %y
+  %fma = call float @llvm.fma.f32(float %x.fneg, float %y.fneg, float %z)
+  ret float %fma
+}
+
+define <2 x float> @fma_fneg_x_fneg_y_vec(<2 x float> %x, <2 x float> %y, <2 x float> %z) {
+; CHECK-LABEL: @fma_fneg_x_fneg_y_vec(
+; CHECK-NEXT:    [[FMA:%.*]] = call <2 x float> @llvm.fma.v2f32(<2 x float> [[X:%.*]], <2 x float> [[Y:%.*]], <2 x float> [[Z:%.*]])
+; CHECK-NEXT:    ret <2 x float> [[FMA]]
+;
+  %xn = fsub <2 x float> <float -0.0, float -0.0>, %x
+  %yn = fsub <2 x float> <float -0.0, float -0.0>, %y
+  %fma = call <2 x float> @llvm.fma.v2f32(<2 x float> %xn, <2 x float> %yn, <2 x float> %z)
+  ret <2 x float> %fma
+}
+
+define <2 x float> @fma_fneg_x_fneg_y_vec_undef(<2 x float> %x, <2 x float> %y, <2 x float> %z) {
+; CHECK-LABEL: @fma_fneg_x_fneg_y_vec_undef(
+; CHECK-NEXT:    [[FMA:%.*]] = call <2 x float> @llvm.fma.v2f32(<2 x float> [[X:%.*]], <2 x float> [[Y:%.*]], <2 x float> [[Z:%.*]])
+; CHECK-NEXT:    ret <2 x float> [[FMA]]
+;
+  %xn = fsub <2 x float> <float -0.0, float undef>, %x
+  %yn = fsub <2 x float> <float undef, float -0.0>, %y
+  %fma = call <2 x float> @llvm.fma.v2f32(<2 x float> %xn, <2 x float> %yn, <2 x float> %z)
+  ret <2 x float> %fma
+}
+
+define float @fma_fneg_x_fneg_y_fast(float %x, float %y, float %z) {
+; CHECK-LABEL: @fma_fneg_x_fneg_y_fast(
+; CHECK-NEXT:    [[FMA:%.*]] = call fast float @llvm.fma.f32(float [[X:%.*]], float [[Y:%.*]], float [[Z:%.*]])
+; CHECK-NEXT:    ret float [[FMA]]
+;
+  %x.fneg = fsub float -0.0, %x
+  %y.fneg = fsub float -0.0, %y
+  %fma = call fast float @llvm.fma.f32(float %x.fneg, float %y.fneg, float %z)
+  ret float %fma
+}
+
+define float @fma_fneg_const_fneg_y(float %y, float %z) {
+; CHECK-LABEL: @fma_fneg_const_fneg_y(
+; CHECK-NEXT:    [[FMA:%.*]] = call float @llvm.fma.f32(float [[Y:%.*]], float bitcast (i32 ptrtoint (i32* @external to i32) to float), float [[Z:%.*]])
+; CHECK-NEXT:    ret float [[FMA]]
+;
+  %y.fneg = fsub float -0.0, %y
+  %fma = call float @llvm.fma.f32(float fsub (float -0.0, float bitcast (i32 ptrtoint (i32* @external to i32) to float)), float %y.fneg, float %z)
+  ret float %fma
+}
+
+define float @fma_fneg_x_fneg_const(float %x, float %z) {
+; CHECK-LABEL: @fma_fneg_x_fneg_const(
+; CHECK-NEXT:    [[FMA:%.*]] = call float @llvm.fma.f32(float [[X:%.*]], float bitcast (i32 ptrtoint (i32* @external to i32) to float), float [[Z:%.*]])
+; CHECK-NEXT:    ret float [[FMA]]
+;
+  %x.fneg = fsub float -0.0, %x
+  %fma = call float @llvm.fma.f32(float %x.fneg, float fsub (float -0.0, float bitcast (i32 ptrtoint (i32* @external to i32) to float)), float %z)
+  ret float %fma
+}
+
+define float @fma_fabs_x_fabs_y(float %x, float %y, float %z) {
+; CHECK-LABEL: @fma_fabs_x_fabs_y(
+; CHECK-NEXT:    [[X_FABS:%.*]] = call float @llvm.fabs.f32(float [[X:%.*]])
+; CHECK-NEXT:    [[Y_FABS:%.*]] = call float @llvm.fabs.f32(float [[Y:%.*]])
+; CHECK-NEXT:    [[FMA:%.*]] = call float @llvm.fma.f32(float [[X_FABS]], float [[Y_FABS]], float [[Z:%.*]])
+; CHECK-NEXT:    ret float [[FMA]]
+;
+  %x.fabs = call float @llvm.fabs.f32(float %x)
+  %y.fabs = call float @llvm.fabs.f32(float %y)
+  %fma = call float @llvm.fma.f32(float %x.fabs, float %y.fabs, float %z)
+  ret float %fma
+}
+
+define float @fma_fabs_x_fabs_x(float %x, float %z) {
+; CHECK-LABEL: @fma_fabs_x_fabs_x(
+; CHECK-NEXT:    [[FMA:%.*]] = call float @llvm.fma.f32(float [[X:%.*]], float [[X]], float [[Z:%.*]])
+; CHECK-NEXT:    ret float [[FMA]]
+;
+  %x.fabs = call float @llvm.fabs.f32(float %x)
+  %fma = call float @llvm.fma.f32(float %x.fabs, float %x.fabs, float %z)
+  ret float %fma
+}
+
+define float @fma_fabs_x_fabs_x_fast(float %x, float %z) {
+; CHECK-LABEL: @fma_fabs_x_fabs_x_fast(
+; CHECK-NEXT:    [[FMA:%.*]] = call fast float @llvm.fma.f32(float [[X:%.*]], float [[X]], float [[Z:%.*]])
+; CHECK-NEXT:    ret float [[FMA]]
+;
+  %x.fabs = call float @llvm.fabs.f32(float %x)
+  %fma = call fast float @llvm.fma.f32(float %x.fabs, float %x.fabs, float %z)
+  ret float %fma
+}
+
+define float @fmuladd_fneg_x_fneg_y(float %x, float %y, float %z) {
+; CHECK-LABEL: @fmuladd_fneg_x_fneg_y(
+; CHECK-NEXT:    [[FMULADD:%.*]] = call float @llvm.fmuladd.f32(float [[X:%.*]], float [[Y:%.*]], float [[Z:%.*]])
+; CHECK-NEXT:    ret float [[FMULADD]]
+;
+  %x.fneg = fsub float -0.0, %x
+  %y.fneg = fsub float -0.0, %y
+  %fmuladd = call float @llvm.fmuladd.f32(float %x.fneg, float %y.fneg, float %z)
+  ret float %fmuladd
+}
+
+define float @fmuladd_fneg_x_fneg_y_fast(float %x, float %y, float %z) {
+; CHECK-LABEL: @fmuladd_fneg_x_fneg_y_fast(
+; CHECK-NEXT:    [[TMP1:%.*]] = fmul fast float [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    [[FMULADD:%.*]] = fadd fast float [[TMP1]], [[Z:%.*]]
+; CHECK-NEXT:    ret float [[FMULADD]]
+;
+  %x.fneg = fsub float -0.0, %x
+  %y.fneg = fsub float -0.0, %y
+  %fmuladd = call fast float @llvm.fmuladd.f32(float %x.fneg, float %y.fneg, float %z)
+  ret float %fmuladd
+}
+
+define float @fmuladd_fneg_const_fneg_y(float %y, float %z) {
+; CHECK-LABEL: @fmuladd_fneg_const_fneg_y(
+; CHECK-NEXT:    [[FMULADD:%.*]] = call float @llvm.fmuladd.f32(float [[Y:%.*]], float bitcast (i32 ptrtoint (i32* @external to i32) to float), float [[Z:%.*]])
+; CHECK-NEXT:    ret float [[FMULADD]]
+;
+  %y.fneg = fsub float -0.0, %y
+  %fmuladd = call float @llvm.fmuladd.f32(float fsub (float -0.0, float bitcast (i32 ptrtoint (i32* @external to i32) to float)), float %y.fneg, float %z)
+  ret float %fmuladd
+}
+
+define float @fmuladd_fneg_x_fneg_const(float %x, float %z) {
+; CHECK-LABEL: @fmuladd_fneg_x_fneg_const(
+; CHECK-NEXT:    [[FMULADD:%.*]] = call float @llvm.fmuladd.f32(float [[X:%.*]], float bitcast (i32 ptrtoint (i32* @external to i32) to float), float [[Z:%.*]])
+; CHECK-NEXT:    ret float [[FMULADD]]
+;
+  %x.fneg = fsub float -0.0, %x
+  %fmuladd = call float @llvm.fmuladd.f32(float %x.fneg, float fsub (float -0.0, float bitcast (i32 ptrtoint (i32* @external to i32) to float)), float %z)
+  ret float %fmuladd
+}
+
+define float @fmuladd_fabs_x_fabs_y(float %x, float %y, float %z) {
+; CHECK-LABEL: @fmuladd_fabs_x_fabs_y(
+; CHECK-NEXT:    [[X_FABS:%.*]] = call float @llvm.fabs.f32(float [[X:%.*]])
+; CHECK-NEXT:    [[Y_FABS:%.*]] = call float @llvm.fabs.f32(float [[Y:%.*]])
+; CHECK-NEXT:    [[FMULADD:%.*]] = call float @llvm.fmuladd.f32(float [[X_FABS]], float [[Y_FABS]], float [[Z:%.*]])
+; CHECK-NEXT:    ret float [[FMULADD]]
+;
+  %x.fabs = call float @llvm.fabs.f32(float %x)
+  %y.fabs = call float @llvm.fabs.f32(float %y)
+  %fmuladd = call float @llvm.fmuladd.f32(float %x.fabs, float %y.fabs, float %z)
+  ret float %fmuladd
+}
+
+define float @fmuladd_fabs_x_fabs_x(float %x, float %z) {
+; CHECK-LABEL: @fmuladd_fabs_x_fabs_x(
+; CHECK-NEXT:    [[FMULADD:%.*]] = call float @llvm.fmuladd.f32(float [[X:%.*]], float [[X]], float [[Z:%.*]])
+; CHECK-NEXT:    ret float [[FMULADD]]
+;
+  %x.fabs = call float @llvm.fabs.f32(float %x)
+  %fmuladd = call float @llvm.fmuladd.f32(float %x.fabs, float %x.fabs, float %z)
+  ret float %fmuladd
+}
+
+define float @fmuladd_fabs_x_fabs_x_fast(float %x, float %z) {
+; CHECK-LABEL: @fmuladd_fabs_x_fabs_x_fast(
+; CHECK-NEXT:    [[TMP1:%.*]] = fmul fast float [[X:%.*]], [[X]]
+; CHECK-NEXT:    [[FMULADD:%.*]] = fadd fast float [[TMP1]], [[Z:%.*]]
+; CHECK-NEXT:    ret float [[FMULADD]]
+;
+  %x.fabs = call float @llvm.fabs.f32(float %x)
+  %fmuladd = call fast float @llvm.fmuladd.f32(float %x.fabs, float %x.fabs, float %z)
+  ret float %fmuladd
+}
+
+define float @fma_k_y_z(float %y, float %z) {
+; CHECK-LABEL: @fma_k_y_z(
+; CHECK-NEXT:    [[FMA:%.*]] = call float @llvm.fma.f32(float [[Y:%.*]], float 4.000000e+00, float [[Z:%.*]])
+; CHECK-NEXT:    ret float [[FMA]]
+;
+  %fma = call float @llvm.fma.f32(float 4.0, float %y, float %z)
+  ret float %fma
+}
+
+define float @fma_k_y_z_fast(float %y, float %z) {
+; CHECK-LABEL: @fma_k_y_z_fast(
+; CHECK-NEXT:    [[FMA:%.*]] = call fast float @llvm.fma.f32(float [[Y:%.*]], float 4.000000e+00, float [[Z:%.*]])
+; CHECK-NEXT:    ret float [[FMA]]
+;
+  %fma = call fast float @llvm.fma.f32(float 4.0, float %y, float %z)
+  ret float %fma
+}
+
+define float @fmuladd_k_y_z_fast(float %y, float %z) {
+; CHECK-LABEL: @fmuladd_k_y_z_fast(
+; CHECK-NEXT:    [[TMP1:%.*]] = fmul fast float [[Y:%.*]], 4.000000e+00
+; CHECK-NEXT:    [[FMULADD:%.*]] = fadd fast float [[TMP1]], [[Z:%.*]]
+; CHECK-NEXT:    ret float [[FMULADD]]
+;
+  %fmuladd = call fast float @llvm.fmuladd.f32(float 4.0, float %y, float %z)
+  ret float %fmuladd
+}
+
+define float @fma_1_y_z(float %y, float %z) {
+; CHECK-LABEL: @fma_1_y_z(
+; CHECK-NEXT:    [[FMA:%.*]] = fadd float [[Y:%.*]], [[Z:%.*]]
+; CHECK-NEXT:    ret float [[FMA]]
+;
+  %fma = call float @llvm.fma.f32(float 1.0, float %y, float %z)
+  ret float %fma
+}
+
+define float @fma_x_1_z(float %x, float %z) {
+; CHECK-LABEL: @fma_x_1_z(
+; CHECK-NEXT:    [[FMA:%.*]] = fadd float [[X:%.*]], [[Z:%.*]]
+; CHECK-NEXT:    ret float [[FMA]]
+;
+  %fma = call float @llvm.fma.f32(float %x, float 1.0, float %z)
+  ret float %fma
+}
+
+define <2 x float> @fma_x_1_z_v2f32(<2 x float> %x, <2 x float> %z) {
+; CHECK-LABEL: @fma_x_1_z_v2f32(
+; CHECK-NEXT:    [[FMA:%.*]] = fadd <2 x float> [[X:%.*]], [[Z:%.*]]
+; CHECK-NEXT:    ret <2 x float> [[FMA]]
+;
+  %fma = call <2 x float> @llvm.fma.v2f32(<2 x float> %x, <2 x float> <float 1.0, float 1.0>, <2 x float> %z)
+  ret <2 x float> %fma
+}
+
+define <2 x float> @fma_x_1_2_z_v2f32(<2 x float> %x, <2 x float> %z) {
+; CHECK-LABEL: @fma_x_1_2_z_v2f32(
+; CHECK-NEXT:    [[FMA:%.*]] = call <2 x float> @llvm.fma.v2f32(<2 x float> [[X:%.*]], <2 x float> <float 1.000000e+00, float 2.000000e+00>, <2 x float> [[Z:%.*]])
+; CHECK-NEXT:    ret <2 x float> [[FMA]]
+;
+  %fma = call <2 x float> @llvm.fma.v2f32(<2 x float> %x, <2 x float> <float 1.0, float 2.0>, <2 x float> %z)
+  ret <2 x float> %fma
+}
+
+define float @fma_x_1_z_fast(float %x, float %z) {
+; CHECK-LABEL: @fma_x_1_z_fast(
+; CHECK-NEXT:    [[FMA:%.*]] = fadd fast float [[X:%.*]], [[Z:%.*]]
+; CHECK-NEXT:    ret float [[FMA]]
+;
+  %fma = call fast float @llvm.fma.f32(float %x, float 1.0, float %z)
+  ret float %fma
+}
+
+define float @fma_1_1_z(float %z) {
+; CHECK-LABEL: @fma_1_1_z(
+; CHECK-NEXT:    [[FMA:%.*]] = fadd float [[Z:%.*]], 1.000000e+00
+; CHECK-NEXT:    ret float [[FMA]]
+;
+  %fma = call float @llvm.fma.f32(float 1.0, float 1.0, float %z)
+  ret float %fma
+}
+
+define float @fmuladd_x_1_z_fast(float %x, float %z) {
+; CHECK-LABEL: @fmuladd_x_1_z_fast(
+; CHECK-NEXT:    [[FMULADD:%.*]] = fadd fast float [[X:%.*]], [[Z:%.*]]
+; CHECK-NEXT:    ret float [[FMULADD]]
+;
+  %fmuladd = call fast float @llvm.fmuladd.f32(float %x, float 1.0, float %z)
+  ret float %fmuladd
+}
+
+attributes #0 = { nounwind }
+attributes #1 = { nounwind readnone }

Added: llvm/trunk/test/Transforms/InstCombine/fmul-exp.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/fmul-exp.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/fmul-exp.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/fmul-exp.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,85 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt -S -instcombine < %s | FileCheck %s
+
+declare double @llvm.exp.f64(double) nounwind readnone speculatable
+declare void @use(double)
+
+; exp(a) * exp(b) no reassoc flags
+define double @exp_a_exp_b(double %a, double %b) {
+; CHECK-LABEL: @exp_a_exp_b(
+; CHECK-NEXT:    [[TMP:%.*]] = call double @llvm.exp.f64(double [[A:%.*]])
+; CHECK-NEXT:    [[TMP1:%.*]] = call double @llvm.exp.f64(double [[B:%.*]])
+; CHECK-NEXT:    [[MUL:%.*]] = fmul double [[TMP]], [[TMP1]]
+; CHECK-NEXT:    ret double [[MUL]]
+;
+  %tmp = call double @llvm.exp.f64(double %a)
+  %tmp1 = call double @llvm.exp.f64(double %b)
+  %mul = fmul double %tmp, %tmp1
+  ret double %mul
+}
+
+; exp(a) * exp(b) reassoc, multiple uses
+define double @exp_a_exp_b_multiple_uses(double %a, double %b) {
+; CHECK-LABEL: @exp_a_exp_b_multiple_uses(
+; CHECK-NEXT:    [[TMP1:%.*]] = call double @llvm.exp.f64(double [[B:%.*]])
+; CHECK-NEXT:    [[TMP:%.*]] = fadd reassoc double [[A:%.*]], [[B]]
+; CHECK-NEXT:    [[TMP2:%.*]] = call reassoc double @llvm.exp.f64(double [[TMP]])
+; CHECK-NEXT:    call void @use(double [[TMP1]])
+; CHECK-NEXT:    ret double [[TMP2]]
+;
+  %tmp = call double @llvm.exp.f64(double %a)
+  %tmp1 = call double @llvm.exp.f64(double %b)
+  %mul = fmul reassoc double %tmp, %tmp1
+  call void @use(double %tmp1)
+  ret double %mul
+}
+
+; exp(a) * exp(b) reassoc, both with multiple uses
+define double @exp_a_exp_b_multiple_uses_both(double %a, double %b) {
+; CHECK-LABEL: @exp_a_exp_b_multiple_uses_both(
+; CHECK-NEXT:    [[TMP:%.*]] = call double @llvm.exp.f64(double [[A:%.*]])
+; CHECK-NEXT:    [[TMP1:%.*]] = call double @llvm.exp.f64(double [[B:%.*]])
+; CHECK-NEXT:    [[MUL:%.*]] = fmul reassoc double [[TMP]], [[TMP1]]
+; CHECK-NEXT:    call void @use(double [[TMP]])
+; CHECK-NEXT:    call void @use(double [[TMP1]])
+; CHECK-NEXT:    ret double [[MUL]]
+;
+  %tmp = call double @llvm.exp.f64(double %a)
+  %tmp1 = call double @llvm.exp.f64(double %b)
+  %mul = fmul reassoc double %tmp, %tmp1
+  call void @use(double %tmp)
+  call void @use(double %tmp1)
+  ret double %mul
+}
+
+; exp(a) * exp(b) => exp(a+b) with reassoc
+define double @exp_a_exp_b_reassoc(double %a, double %b) {
+; CHECK-LABEL: @exp_a_exp_b_reassoc(
+; CHECK-NEXT:    [[TMP:%.*]] = fadd reassoc double [[A:%.*]], [[B:%.*]]
+; CHECK-NEXT:    [[TMP1:%.*]] = call reassoc double @llvm.exp.f64(double [[TMP]])
+; CHECK-NEXT:    ret double [[TMP1]]
+;
+  %tmp = call double @llvm.exp.f64(double %a)
+  %tmp1 = call double @llvm.exp.f64(double %b)
+  %mul = fmul reassoc double %tmp, %tmp1
+  ret double %mul
+}
+
+; exp(a) * exp(b) * exp(c) * exp(d) => exp(a+b+c+d) with reassoc
+define double @exp_a_exp_b_exp_c_exp_d_fast(double %a, double %b, double %c, double %d) {
+; CHECK-LABEL: @exp_a_exp_b_exp_c_exp_d_fast(
+; CHECK-NEXT:    [[TMP:%.*]] = fadd reassoc double [[A:%.*]], [[B:%.*]]
+; CHECK-NEXT:    [[TMP1:%.*]] = fadd reassoc double [[TMP]], [[C:%.*]]
+; CHECK-NEXT:    [[TMP2:%.*]] = fadd reassoc double [[TMP1]], [[D:%.*]]
+; CHECK-NEXT:    [[TMP3:%.*]] = call reassoc double @llvm.exp.f64(double [[TMP2]])
+; CHECK-NEXT:    ret double [[TMP3]]
+;
+  %tmp = call double @llvm.exp.f64(double %a)
+  %tmp1 = call double @llvm.exp.f64(double %b)
+  %mul = fmul reassoc double %tmp, %tmp1
+  %tmp2 = call double @llvm.exp.f64(double %c)
+  %mul1 = fmul reassoc double %mul, %tmp2
+  %tmp3 = call double @llvm.exp.f64(double %d)
+  %mul2 = fmul reassoc double %mul1, %tmp3
+  ret double %mul2
+}

Added: llvm/trunk/test/Transforms/InstCombine/fmul-exp2.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/fmul-exp2.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/fmul-exp2.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/fmul-exp2.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,85 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt -S -instcombine < %s | FileCheck %s
+
+declare double @llvm.exp2.f64(double) nounwind readnone speculatable
+declare void @use(double)
+
+; exp2(a) * exp2(b) no reassoc flags
+define double @exp2_a_exp2_b(double %a, double %b) {
+; CHECK-LABEL: @exp2_a_exp2_b(
+; CHECK-NEXT:    [[TMP:%.*]] = call double @llvm.exp2.f64(double [[A:%.*]])
+; CHECK-NEXT:    [[TMP1:%.*]] = call double @llvm.exp2.f64(double [[B:%.*]])
+; CHECK-NEXT:    [[MUL:%.*]] = fmul double [[TMP]], [[TMP1]]
+; CHECK-NEXT:    ret double [[MUL]]
+;
+  %tmp = call double @llvm.exp2.f64(double %a)
+  %tmp1 = call double @llvm.exp2.f64(double %b)
+  %mul = fmul double %tmp, %tmp1
+  ret double %mul
+}
+
+; exp2(a) * exp2(b) reassoc, multiple uses
+define double @exp2_a_exp2_b_multiple_uses(double %a, double %b) {
+; CHECK-LABEL: @exp2_a_exp2_b_multiple_uses(
+; CHECK-NEXT:    [[TMP1:%.*]] = call double @llvm.exp2.f64(double [[B:%.*]])
+; CHECK-NEXT:    [[TMP:%.*]] = fadd reassoc double [[A:%.*]], [[B]]
+; CHECK-NEXT:    [[TMP2:%.*]] = call reassoc double @llvm.exp2.f64(double [[TMP]])
+; CHECK-NEXT:    call void @use(double [[TMP1]])
+; CHECK-NEXT:    ret double [[TMP2]]
+;
+  %tmp = call double @llvm.exp2.f64(double %a)
+  %tmp1 = call double @llvm.exp2.f64(double %b)
+  %mul = fmul reassoc double %tmp, %tmp1
+  call void @use(double %tmp1)
+  ret double %mul
+}
+
+; exp2(a) * exp2(b) reassoc, both with multiple uses
+define double @exp2_a_exp2_b_multiple_uses_both(double %a, double %b) {
+; CHECK-LABEL: @exp2_a_exp2_b_multiple_uses_both(
+; CHECK-NEXT:    [[TMP:%.*]] = call double @llvm.exp2.f64(double [[A:%.*]])
+; CHECK-NEXT:    [[TMP1:%.*]] = call double @llvm.exp2.f64(double [[B:%.*]])
+; CHECK-NEXT:    [[MUL:%.*]] = fmul reassoc double [[TMP]], [[TMP1]]
+; CHECK-NEXT:    call void @use(double [[TMP]])
+; CHECK-NEXT:    call void @use(double [[TMP1]])
+; CHECK-NEXT:    ret double [[MUL]]
+;
+  %tmp = call double @llvm.exp2.f64(double %a)
+  %tmp1 = call double @llvm.exp2.f64(double %b)
+  %mul = fmul reassoc double %tmp, %tmp1
+  call void @use(double %tmp)
+  call void @use(double %tmp1)
+  ret double %mul
+}
+
+; exp2(a) * exp2(b) => exp2(a+b) with reassoc
+define double @exp2_a_exp2_b_reassoc(double %a, double %b) {
+; CHECK-LABEL: @exp2_a_exp2_b_reassoc(
+; CHECK-NEXT:    [[TMP:%.*]] = fadd reassoc double [[A:%.*]], [[B:%.*]]
+; CHECK-NEXT:    [[TMP1:%.*]] = call reassoc double @llvm.exp2.f64(double [[TMP]])
+; CHECK-NEXT:    ret double [[TMP1]]
+;
+  %tmp = call double @llvm.exp2.f64(double %a)
+  %tmp1 = call double @llvm.exp2.f64(double %b)
+  %mul = fmul reassoc double %tmp, %tmp1
+  ret double %mul
+}
+
+; exp2(a) * exp2(b) * exp2(c) * exp2(d) => exp2(a+b+c+d) with reassoc
+define double @exp2_a_exp2_b_exp2_c_exp2_d(double %a, double %b, double %c, double %d) {
+; CHECK-LABEL: @exp2_a_exp2_b_exp2_c_exp2_d(
+; CHECK-NEXT:    [[TMP:%.*]] = fadd reassoc double [[A:%.*]], [[B:%.*]]
+; CHECK-NEXT:    [[TMP1:%.*]] = fadd reassoc double [[TMP]], [[C:%.*]]
+; CHECK-NEXT:    [[TMP2:%.*]] = fadd reassoc double [[TMP1]], [[D:%.*]]
+; CHECK-NEXT:    [[TMP3:%.*]] = call reassoc double @llvm.exp2.f64(double [[TMP2]])
+; CHECK-NEXT:    ret double [[TMP3]]
+;
+  %tmp = call double @llvm.exp2.f64(double %a)
+  %tmp1 = call double @llvm.exp2.f64(double %b)
+  %mul = fmul reassoc double %tmp, %tmp1
+  %tmp2 = call double @llvm.exp2.f64(double %c)
+  %mul1 = fmul reassoc double %mul, %tmp2
+  %tmp3 = call double @llvm.exp2.f64(double %d)
+  %mul2 = fmul reassoc double %mul1, %tmp3
+  ret double %mul2
+}

Added: llvm/trunk/test/Transforms/InstCombine/fmul-pow.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/fmul-pow.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/fmul-pow.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/fmul-pow.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,90 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt -S -instcombine < %s | FileCheck %s
+
+declare double @llvm.pow.f64(double, double)
+
+define double @pow_ab_a(double %a, double %b)  {
+; CHECK-LABEL: @pow_ab_a(
+; CHECK-NEXT:    [[TMP1:%.*]] = call double @llvm.pow.f64(double [[A:%.*]], double [[B:%.*]])
+; CHECK-NEXT:    [[MUL:%.*]] = fmul double [[TMP1]], [[A]]
+; CHECK-NEXT:    ret double [[MUL]]
+;
+  %1 = call double @llvm.pow.f64(double %a, double %b)
+  %mul = fmul double %1, %a
+  ret double %mul
+}
+
+define double @pow_ab_a_reassoc(double %a, double %b)  {
+; CHECK-LABEL: @pow_ab_a_reassoc(
+; CHECK-NEXT:    [[TMP1:%.*]] = call double @llvm.pow.f64(double [[A:%.*]], double [[B:%.*]])
+; CHECK-NEXT:    [[MUL:%.*]] = fmul reassoc double [[TMP1]], [[A]]
+; CHECK-NEXT:    ret double [[MUL]]
+;
+  %1 = call double @llvm.pow.f64(double %a, double %b)
+  %mul = fmul reassoc double %1, %a
+  ret double %mul
+}
+
+define double @pow_ab_a_reassoc_commute(double %a, double %b)  {
+; CHECK-LABEL: @pow_ab_a_reassoc_commute(
+; CHECK-NEXT:    [[TMP1:%.*]] = call double @llvm.pow.f64(double [[A:%.*]], double [[B:%.*]])
+; CHECK-NEXT:    [[MUL:%.*]] = fdiv reassoc double [[TMP1]], [[A]]
+; CHECK-NEXT:    ret double [[MUL]]
+;
+  %1 = fdiv double 1.0, %a
+  %2 = call double @llvm.pow.f64(double %a, double %b)
+  %mul = fmul reassoc double %1, %2
+  ret double %mul
+}
+
+define double @pow_ab_pow_cb(double %a, double %b, double %c) {
+; CHECK-LABEL: @pow_ab_pow_cb(
+; CHECK-NEXT:    [[TMP1:%.*]] = call double @llvm.pow.f64(double [[A:%.*]], double [[B:%.*]])
+; CHECK-NEXT:    [[TMP2:%.*]] = call double @llvm.pow.f64(double [[C:%.*]], double [[B]])
+; CHECK-NEXT:    [[MUL:%.*]] = fmul double [[TMP2]], [[TMP1]]
+; CHECK-NEXT:    ret double [[MUL]]
+;
+  %1 = call double @llvm.pow.f64(double %a, double %b)
+  %2 = call double @llvm.pow.f64(double %c, double %b)
+  %mul = fmul double %2, %1
+  ret double %mul
+}
+
+define double @pow_ab_pow_cb_reassoc(double %a, double %b, double %c) {
+; CHECK-LABEL: @pow_ab_pow_cb_reassoc(
+; CHECK-NEXT:    [[TMP1:%.*]] = call double @llvm.pow.f64(double [[A:%.*]], double [[B:%.*]])
+; CHECK-NEXT:    [[TMP2:%.*]] = call double @llvm.pow.f64(double [[C:%.*]], double [[B]])
+; CHECK-NEXT:    [[MUL:%.*]] = fmul reassoc double [[TMP2]], [[TMP1]]
+; CHECK-NEXT:    ret double [[MUL]]
+;
+  %1 = call double @llvm.pow.f64(double %a, double %b)
+  %2 = call double @llvm.pow.f64(double %c, double %b)
+  %mul = fmul reassoc double %2, %1
+  ret double %mul
+}
+
+define double @pow_ab_pow_ac(double %a, double %b, double %c) {
+; CHECK-LABEL: @pow_ab_pow_ac(
+; CHECK-NEXT:    [[TMP1:%.*]] = call double @llvm.pow.f64(double [[A:%.*]], double [[B:%.*]])
+; CHECK-NEXT:    [[TMP2:%.*]] = call double @llvm.pow.f64(double [[A]], double [[C:%.*]])
+; CHECK-NEXT:    [[MUL:%.*]] = fmul double [[TMP2]], [[TMP1]]
+; CHECK-NEXT:    ret double [[MUL]]
+;
+  %1 = call double @llvm.pow.f64(double %a, double %b)
+  %2 = call double @llvm.pow.f64(double %a, double %c)
+  %mul = fmul double %2, %1
+  ret double %mul
+}
+
+define double @pow_ab_x_pow_ac_reassoc(double %a, double %b, double %c) {
+; CHECK-LABEL: @pow_ab_x_pow_ac_reassoc(
+; CHECK-NEXT:    [[TMP1:%.*]] = call double @llvm.pow.f64(double [[A:%.*]], double [[B:%.*]])
+; CHECK-NEXT:    [[TMP2:%.*]] = call double @llvm.pow.f64(double [[A]], double [[C:%.*]])
+; CHECK-NEXT:    [[MUL:%.*]] = fmul reassoc double [[TMP2]], [[TMP1]]
+; CHECK-NEXT:    ret double [[MUL]]
+;
+  %1 = call double @llvm.pow.f64(double %a, double %b)
+  %2 = call double @llvm.pow.f64(double %a, double %c)
+  %mul = fmul reassoc double %2, %1
+  ret double %mul
+}

Added: llvm/trunk/test/Transforms/InstCombine/fmul-sqrt.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/fmul-sqrt.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/fmul-sqrt.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/fmul-sqrt.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,191 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt -S -instcombine < %s | FileCheck %s
+
+declare double @llvm.sqrt.f64(double) nounwind readnone speculatable
+declare <2 x float> @llvm.sqrt.v2f32(<2 x float>)
+declare void @use(double)
+
+; sqrt(a) * sqrt(b) no math flags
+
+define double @sqrt_a_sqrt_b(double %a, double %b) {
+; CHECK-LABEL: @sqrt_a_sqrt_b(
+; CHECK-NEXT:    [[TMP1:%.*]] = call double @llvm.sqrt.f64(double [[A:%.*]])
+; CHECK-NEXT:    [[TMP2:%.*]] = call double @llvm.sqrt.f64(double [[B:%.*]])
+; CHECK-NEXT:    [[MUL:%.*]] = fmul double [[TMP1]], [[TMP2]]
+; CHECK-NEXT:    ret double [[MUL]]
+;
+  %1 = call double @llvm.sqrt.f64(double %a)
+  %2 = call double @llvm.sqrt.f64(double %b)
+  %mul = fmul double %1, %2
+  ret double %mul
+}
+
+; sqrt(a) * sqrt(b) fast-math, multiple uses
+
+define double @sqrt_a_sqrt_b_multiple_uses(double %a, double %b) {
+; CHECK-LABEL: @sqrt_a_sqrt_b_multiple_uses(
+; CHECK-NEXT:    [[TMP1:%.*]] = call fast double @llvm.sqrt.f64(double [[A:%.*]])
+; CHECK-NEXT:    [[TMP2:%.*]] = call fast double @llvm.sqrt.f64(double [[B:%.*]])
+; CHECK-NEXT:    [[MUL:%.*]] = fmul fast double [[TMP1]], [[TMP2]]
+; CHECK-NEXT:    call void @use(double [[TMP2]])
+; CHECK-NEXT:    ret double [[MUL]]
+;
+  %1 = call fast double @llvm.sqrt.f64(double %a)
+  %2 = call fast double @llvm.sqrt.f64(double %b)
+  %mul = fmul fast double %1, %2
+  call void @use(double %2)
+  ret double %mul
+}
+
+; sqrt(a) * sqrt(b) => sqrt(a*b) with fast-math
+
+define double @sqrt_a_sqrt_b_reassoc_nnan(double %a, double %b) {
+; CHECK-LABEL: @sqrt_a_sqrt_b_reassoc_nnan(
+; CHECK-NEXT:    [[TMP1:%.*]] = fmul reassoc nnan double [[A:%.*]], [[B:%.*]]
+; CHECK-NEXT:    [[TMP2:%.*]] = call reassoc nnan double @llvm.sqrt.f64(double [[TMP1]])
+; CHECK-NEXT:    ret double [[TMP2]]
+;
+  %1 = call double @llvm.sqrt.f64(double %a)
+  %2 = call double @llvm.sqrt.f64(double %b)
+  %mul = fmul reassoc nnan double %1, %2
+  ret double %mul
+}
+
+; nnan disallows the possibility that both operands are negative,
+; so we won't return a number when the answer should be NaN.
+
+define double @sqrt_a_sqrt_b_reassoc(double %a, double %b) {
+; CHECK-LABEL: @sqrt_a_sqrt_b_reassoc(
+; CHECK-NEXT:    [[TMP1:%.*]] = call double @llvm.sqrt.f64(double [[A:%.*]])
+; CHECK-NEXT:    [[TMP2:%.*]] = call double @llvm.sqrt.f64(double [[B:%.*]])
+; CHECK-NEXT:    [[MUL:%.*]] = fmul reassoc double [[TMP1]], [[TMP2]]
+; CHECK-NEXT:    ret double [[MUL]]
+;
+  %1 = call double @llvm.sqrt.f64(double %a)
+  %2 = call double @llvm.sqrt.f64(double %b)
+  %mul = fmul reassoc double %1, %2
+  ret double %mul
+}
+
+; sqrt(a) * sqrt(b) * sqrt(c) * sqrt(d) => sqrt(a*b*c*d) with fast-math
+; 'reassoc nnan' on the fmuls is all that is required, but check propagation of other FMF.
+
+define double @sqrt_a_sqrt_b_sqrt_c_sqrt_d_reassoc(double %a, double %b, double %c, double %d) {
+; CHECK-LABEL: @sqrt_a_sqrt_b_sqrt_c_sqrt_d_reassoc(
+; CHECK-NEXT:    [[TMP1:%.*]] = fmul reassoc nnan arcp double [[A:%.*]], [[B:%.*]]
+; CHECK-NEXT:    [[TMP2:%.*]] = fmul reassoc nnan double [[TMP1]], [[C:%.*]]
+; CHECK-NEXT:    [[TMP3:%.*]] = fmul reassoc nnan ninf double [[TMP2]], [[D:%.*]]
+; CHECK-NEXT:    [[TMP4:%.*]] = call reassoc nnan ninf double @llvm.sqrt.f64(double [[TMP3]])
+; CHECK-NEXT:    ret double [[TMP4]]
+;
+  %1 = call double @llvm.sqrt.f64(double %a)
+  %2 = call double @llvm.sqrt.f64(double %b)
+  %3 = call double @llvm.sqrt.f64(double %c)
+  %4 = call double @llvm.sqrt.f64(double %d)
+  %mul = fmul reassoc nnan arcp double %1, %2
+  %mul1 = fmul reassoc nnan double %mul, %3
+  %mul2 = fmul reassoc nnan ninf double %mul1, %4
+  ret double %mul2
+}
+
+define double @rsqrt_squared(double %x) {
+; CHECK-LABEL: @rsqrt_squared(
+; CHECK-NEXT:    [[SQUARED:%.*]] = fdiv fast double 1.000000e+00, [[X:%.*]]
+; CHECK-NEXT:    ret double [[SQUARED]]
+;
+  %sqrt = call fast double @llvm.sqrt.f64(double %x)
+  %rsqrt = fdiv fast double 1.0, %sqrt
+  %squared = fmul fast double %rsqrt, %rsqrt
+  ret double %squared
+}
+
+define double @sqrt_divisor_squared(double %x, double %y) {
+; CHECK-LABEL: @sqrt_divisor_squared(
+; CHECK-NEXT:    [[TMP1:%.*]] = fmul reassoc nnan nsz double [[Y:%.*]], [[Y]]
+; CHECK-NEXT:    [[SQUARED:%.*]] = fdiv reassoc nnan nsz double [[TMP1]], [[X:%.*]]
+; CHECK-NEXT:    ret double [[SQUARED]]
+;
+  %sqrt = call double @llvm.sqrt.f64(double %x)
+  %div = fdiv double %y, %sqrt
+  %squared = fmul reassoc nnan nsz double %div, %div
+  ret double %squared
+}
+
+define <2 x float> @sqrt_dividend_squared(<2 x float> %x, <2 x float> %y) {
+; CHECK-LABEL: @sqrt_dividend_squared(
+; CHECK-NEXT:    [[TMP1:%.*]] = fmul fast <2 x float> [[Y:%.*]], [[Y]]
+; CHECK-NEXT:    [[SQUARED:%.*]] = fdiv fast <2 x float> [[X:%.*]], [[TMP1]]
+; CHECK-NEXT:    ret <2 x float> [[SQUARED]]
+;
+  %sqrt = call <2 x float> @llvm.sqrt.v2f32(<2 x float> %x)
+  %div = fdiv fast <2 x float> %sqrt, %y
+  %squared = fmul fast <2 x float> %div, %div
+  ret <2 x float> %squared
+}
+
+; We do not transform this because it would result in an extra instruction.
+; This might still be a good optimization for the backend.
+
+define double @sqrt_divisor_squared_extra_use(double %x, double %y) {
+; CHECK-LABEL: @sqrt_divisor_squared_extra_use(
+; CHECK-NEXT:    [[SQRT:%.*]] = call double @llvm.sqrt.f64(double [[X:%.*]])
+; CHECK-NEXT:    [[DIV:%.*]] = fdiv double [[Y:%.*]], [[SQRT]]
+; CHECK-NEXT:    call void @use(double [[DIV]])
+; CHECK-NEXT:    [[SQUARED:%.*]] = fmul reassoc nnan nsz double [[DIV]], [[DIV]]
+; CHECK-NEXT:    ret double [[SQUARED]]
+;
+  %sqrt = call double @llvm.sqrt.f64(double %x)
+  %div = fdiv double %y, %sqrt
+  call void @use(double %div)
+  %squared = fmul reassoc nnan nsz double %div, %div
+  ret double %squared
+}
+
+define double @sqrt_dividend_squared_extra_use(double %x, double %y) {
+; CHECK-LABEL: @sqrt_dividend_squared_extra_use(
+; CHECK-NEXT:    [[SQRT:%.*]] = call double @llvm.sqrt.f64(double [[X:%.*]])
+; CHECK-NEXT:    call void @use(double [[SQRT]])
+; CHECK-NEXT:    [[TMP1:%.*]] = fmul fast double [[Y:%.*]], [[Y]]
+; CHECK-NEXT:    [[SQUARED:%.*]] = fdiv fast double [[X]], [[TMP1]]
+; CHECK-NEXT:    ret double [[SQUARED]]
+;
+  %sqrt = call double @llvm.sqrt.f64(double %x)
+  call void @use(double %sqrt)
+  %div = fdiv fast double %sqrt, %y
+  %squared = fmul fast double %div, %div
+  ret double %squared
+}
+
+; Negative test - require 'nsz'.
+
+define double @sqrt_divisor_not_enough_FMF(double %x, double %y) {
+; CHECK-LABEL: @sqrt_divisor_not_enough_FMF(
+; CHECK-NEXT:    [[SQRT:%.*]] = call double @llvm.sqrt.f64(double [[X:%.*]])
+; CHECK-NEXT:    [[DIV:%.*]] = fdiv double [[Y:%.*]], [[SQRT]]
+; CHECK-NEXT:    [[SQUARED:%.*]] = fmul reassoc nnan double [[DIV]], [[DIV]]
+; CHECK-NEXT:    ret double [[SQUARED]]
+;
+  %sqrt = call double @llvm.sqrt.f64(double %x)
+  %div = fdiv double %y, %sqrt
+  %squared = fmul reassoc nnan double %div, %div
+  ret double %squared
+}
+
+; TODO: This is a special-case of the general pattern. If we have a constant
+; operand, the extra use limitation could be eased because this does not
+; result in an extra instruction (1.0 * 1.0 is constant folded).
+
+define double @rsqrt_squared_extra_use(double %x) {
+; CHECK-LABEL: @rsqrt_squared_extra_use(
+; CHECK-NEXT:    [[SQRT:%.*]] = call fast double @llvm.sqrt.f64(double [[X:%.*]])
+; CHECK-NEXT:    [[RSQRT:%.*]] = fdiv fast double 1.000000e+00, [[SQRT]]
+; CHECK-NEXT:    call void @use(double [[RSQRT]])
+; CHECK-NEXT:    [[SQUARED:%.*]] = fmul fast double [[RSQRT]], [[RSQRT]]
+; CHECK-NEXT:    ret double [[SQUARED]]
+;
+  %sqrt = call fast double @llvm.sqrt.f64(double %x)
+  %rsqrt = fdiv fast double 1.0, %sqrt
+  call void @use(double %rsqrt)
+  %squared = fmul fast double %rsqrt, %rsqrt
+  ret double %squared
+}

Added: llvm/trunk/test/Transforms/InstCombine/fmul.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/fmul.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/fmul.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/fmul.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,778 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt -S -instcombine < %s | FileCheck %s
+
+; (-0.0 - X) * C => X * -C
+define float @neg_constant(float %x) {
+; CHECK-LABEL: @neg_constant(
+; CHECK-NEXT:    [[MUL:%.*]] = fmul ninf float [[X:%.*]], -2.000000e+01
+; CHECK-NEXT:    ret float [[MUL]]
+;
+  %sub = fsub float -0.0, %x
+  %mul = fmul ninf float %sub, 2.0e+1
+  ret float %mul
+}
+
+define <2 x float> @neg_constant_vec(<2 x float> %x) {
+; CHECK-LABEL: @neg_constant_vec(
+; CHECK-NEXT:    [[MUL:%.*]] = fmul ninf <2 x float> [[X:%.*]], <float -2.000000e+00, float -3.000000e+00>
+; CHECK-NEXT:    ret <2 x float> [[MUL]]
+;
+  %sub = fsub <2 x float> <float -0.0, float -0.0>, %x
+  %mul = fmul ninf <2 x float> %sub, <float 2.0, float 3.0>
+  ret <2 x float> %mul
+}
+
+define <2 x float> @neg_constant_vec_undef(<2 x float> %x) {
+; CHECK-LABEL: @neg_constant_vec_undef(
+; CHECK-NEXT:    [[MUL:%.*]] = fmul ninf <2 x float> [[X:%.*]], <float -2.000000e+00, float -3.000000e+00>
+; CHECK-NEXT:    ret <2 x float> [[MUL]]
+;
+  %sub = fsub <2 x float> <float undef, float -0.0>, %x
+  %mul = fmul ninf <2 x float> %sub, <float 2.0, float 3.0>
+  ret <2 x float> %mul
+}
+
+; (0.0 - X) * C => X * -C
+define float @neg_nsz_constant(float %x) {
+; CHECK-LABEL: @neg_nsz_constant(
+; CHECK-NEXT:    [[MUL:%.*]] = fmul nnan float [[X:%.*]], -2.000000e+01
+; CHECK-NEXT:    ret float [[MUL]]
+;
+  %sub = fsub nsz float 0.0, %x
+  %mul = fmul nnan float %sub, 2.0e+1
+  ret float %mul
+}
+
+; (-0.0 - X) * (-0.0 - Y) => X * Y
+define float @neg_neg(float %x, float %y) {
+; CHECK-LABEL: @neg_neg(
+; CHECK-NEXT:    [[MUL:%.*]] = fmul arcp float [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    ret float [[MUL]]
+;
+  %sub1 = fsub float -0.0, %x
+  %sub2 = fsub float -0.0, %y
+  %mul = fmul arcp float %sub1, %sub2
+  ret float %mul
+}
+
+define <2 x float> @neg_neg_vec(<2 x float> %x, <2 x float> %y) {
+; CHECK-LABEL: @neg_neg_vec(
+; CHECK-NEXT:    [[MUL:%.*]] = fmul arcp <2 x float> [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    ret <2 x float> [[MUL]]
+;
+  %sub1 = fsub <2 x float> <float -0.0, float -0.0>, %x
+  %sub2 = fsub <2 x float> <float -0.0, float -0.0>, %y
+  %mul = fmul arcp <2 x float> %sub1, %sub2
+  ret <2 x float> %mul
+}
+
+define <2 x float> @neg_neg_vec_undef(<2 x float> %x, <2 x float> %y) {
+; CHECK-LABEL: @neg_neg_vec_undef(
+; CHECK-NEXT:    [[MUL:%.*]] = fmul arcp <2 x float> [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    ret <2 x float> [[MUL]]
+;
+  %sub1 = fsub <2 x float> <float -0.0, float undef>, %x
+  %sub2 = fsub <2 x float> <float undef, float -0.0>, %y
+  %mul = fmul arcp <2 x float> %sub1, %sub2
+  ret <2 x float> %mul
+}
+
+; (0.0 - X) * (0.0 - Y) => X * Y
+define float @neg_neg_nsz(float %x, float %y) {
+; CHECK-LABEL: @neg_neg_nsz(
+; CHECK-NEXT:    [[MUL:%.*]] = fmul afn float [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    ret float [[MUL]]
+;
+  %sub1 = fsub nsz float 0.0, %x
+  %sub2 = fsub nsz float 0.0, %y
+  %mul = fmul afn float %sub1, %sub2
+  ret float %mul
+}
+
+declare void @use_f32(float)
+
+define float @neg_neg_multi_use(float %x, float %y) {
+; CHECK-LABEL: @neg_neg_multi_use(
+; CHECK-NEXT:    [[NX:%.*]] = fsub float -0.000000e+00, [[X:%.*]]
+; CHECK-NEXT:    [[NY:%.*]] = fsub float -0.000000e+00, [[Y:%.*]]
+; CHECK-NEXT:    [[MUL:%.*]] = fmul afn float [[X]], [[Y]]
+; CHECK-NEXT:    call void @use_f32(float [[NX]])
+; CHECK-NEXT:    call void @use_f32(float [[NY]])
+; CHECK-NEXT:    ret float [[MUL]]
+;
+  %nx = fsub float -0.0, %x
+  %ny = fsub float -0.0, %y
+  %mul = fmul afn float %nx, %ny
+  call void @use_f32(float %nx)
+  call void @use_f32(float %ny)
+  ret float %mul
+}
+
+; (-0.0 - X) * Y => -0.0 - (X * Y)
+define float @neg_sink(float %x, float %y) {
+; CHECK-LABEL: @neg_sink(
+; CHECK-NEXT:    [[TMP1:%.*]] = fmul float [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    [[MUL:%.*]] = fsub float -0.000000e+00, [[TMP1]]
+; CHECK-NEXT:    ret float [[MUL]]
+;
+  %sub = fsub float -0.0, %x
+  %mul = fmul float %sub, %y
+  ret float %mul
+}
+
+define <2 x float> @neg_sink_vec(<2 x float> %x, <2 x float> %y) {
+; CHECK-LABEL: @neg_sink_vec(
+; CHECK-NEXT:    [[TMP1:%.*]] = fmul <2 x float> [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    [[MUL:%.*]] = fsub <2 x float> <float -0.000000e+00, float -0.000000e+00>, [[TMP1]]
+; CHECK-NEXT:    ret <2 x float> [[MUL]]
+;
+  %sub = fsub <2 x float> <float -0.0, float -0.0>, %x
+  %mul = fmul <2 x float> %sub, %y
+  ret <2 x float> %mul
+}
+
+define <2 x float> @neg_sink_vec_undef(<2 x float> %x, <2 x float> %y) {
+; CHECK-LABEL: @neg_sink_vec_undef(
+; CHECK-NEXT:    [[TMP1:%.*]] = fmul <2 x float> [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    [[MUL:%.*]] = fsub <2 x float> <float -0.000000e+00, float -0.000000e+00>, [[TMP1]]
+; CHECK-NEXT:    ret <2 x float> [[MUL]]
+;
+  %sub = fsub <2 x float> <float undef, float -0.0>, %x
+  %mul = fmul <2 x float> %sub, %y
+  ret <2 x float> %mul
+}
+
+; (0.0 - X) * Y => 0.0 - (X * Y)
+define float @neg_sink_nsz(float %x, float %y) {
+; CHECK-LABEL: @neg_sink_nsz(
+; CHECK-NEXT:    [[TMP1:%.*]] = fmul float [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    [[MUL:%.*]] = fsub float -0.000000e+00, [[TMP1]]
+; CHECK-NEXT:    ret float [[MUL]]
+;
+  %sub1 = fsub nsz float 0.0, %x
+  %mul = fmul float %sub1, %y
+  ret float %mul
+}
+
+; "(-0.0 - X) * Y => -0.0 - (X * Y)" is disabled if expression "-0.0 - X"
+; has multiple uses.
+define float @neg_sink_multi_use(float %x, float %y) {
+; CHECK-LABEL: @neg_sink_multi_use(
+; CHECK-NEXT:    [[SUB1:%.*]] = fsub float -0.000000e+00, [[X:%.*]]
+; CHECK-NEXT:    [[MUL:%.*]] = fmul float [[SUB1]], [[Y:%.*]]
+; CHECK-NEXT:    [[MUL2:%.*]] = fmul float [[MUL]], [[SUB1]]
+; CHECK-NEXT:    ret float [[MUL2]]
+;
+  %sub1 = fsub float -0.0, %x
+  %mul = fmul float %sub1, %y
+  %mul2 = fmul float %mul, %sub1
+  ret float %mul2
+}
+
+; Don't crash when attempting to cast a constant FMul to an instruction.
+define void @test8(i32* %inout) {
+; CHECK-LABEL: @test8(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    br label [[FOR_COND:%.*]]
+; CHECK:       for.cond:
+; CHECK-NEXT:    [[LOCAL_VAR_7_0:%.*]] = phi <4 x float> [ <float -0.000000e+00, float -0.000000e+00, float -0.000000e+00, float -0.000000e+00>, [[ENTRY:%.*]] ], [ [[TMP0:%.*]], [[FOR_BODY:%.*]] ]
+; CHECK-NEXT:    br i1 undef, label [[FOR_BODY]], label [[FOR_END:%.*]]
+; CHECK:       for.body:
+; CHECK-NEXT:    [[TMP0]] = insertelement <4 x float> [[LOCAL_VAR_7_0]], float 0.000000e+00, i32 2
+; CHECK-NEXT:    br label [[FOR_COND]]
+; CHECK:       for.end:
+; CHECK-NEXT:    ret void
+;
+entry:
+  %0 = load i32, i32* %inout, align 4
+  %conv = uitofp i32 %0 to float
+  %vecinit = insertelement <4 x float> <float 0.000000e+00, float 0.000000e+00, float 0.000000e+00, float undef>, float %conv, i32 3
+  %sub = fsub <4 x float> <float -0.000000e+00, float -0.000000e+00, float -0.000000e+00, float -0.000000e+00>, %vecinit
+  %1 = shufflevector <4 x float> %sub, <4 x float> undef, <4 x i32> <i32 1, i32 1, i32 1, i32 1>
+  %mul = fmul <4 x float> zeroinitializer, %1
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.body, %entry
+  %local_var_7.0 = phi <4 x float> [ %mul, %entry ], [ %2, %for.body ]
+  br i1 undef, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  %2 = insertelement <4 x float> %local_var_7.0, float 0.000000e+00, i32 2
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  ret void
+}
+
+; X * -1.0 => -0.0 - X
+define float @test9(float %x) {
+; CHECK-LABEL: @test9(
+; CHECK-NEXT:    [[MUL:%.*]] = fsub float -0.000000e+00, [[X:%.*]]
+; CHECK-NEXT:    ret float [[MUL]]
+;
+  %mul = fmul float %x, -1.0
+  ret float %mul
+}
+
+; PR18532
+define <4 x float> @test10(<4 x float> %x) {
+; CHECK-LABEL: @test10(
+; CHECK-NEXT:    [[MUL:%.*]] = fsub arcp afn <4 x float> <float -0.000000e+00, float -0.000000e+00, float -0.000000e+00, float -0.000000e+00>, [[X:%.*]]
+; CHECK-NEXT:    ret <4 x float> [[MUL]]
+;
+  %mul = fmul arcp afn <4 x float> %x, <float -1.0, float -1.0, float -1.0, float -1.0>
+  ret <4 x float> %mul
+}
+
+define float @test11(float %x, float %y) {
+; CHECK-LABEL: @test11(
+; CHECK-NEXT:    [[B:%.*]] = fadd fast float [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    [[C:%.*]] = fadd fast float [[B]], 3.000000e+00
+; CHECK-NEXT:    ret float [[C]]
+;
+  %a = fadd fast float %x, 1.0
+  %b = fadd fast float %y, 2.0
+  %c = fadd fast float %a, %b
+  ret float %c
+}
+
+declare double @llvm.sqrt.f64(double)
+
+; With unsafe/fast math, sqrt(X) * sqrt(X) is just X,
+; but make sure another use of the sqrt is intact.
+; Note that the remaining fmul is altered but is not 'fast'
+; itself because it was not marked 'fast' originally.
+; Thus, we have an overall fast result, but no more indication of
+; 'fast'ness in the code.
+define double @sqrt_squared2(double %f) {
+; CHECK-LABEL: @sqrt_squared2(
+; CHECK-NEXT:    [[SQRT:%.*]] = call double @llvm.sqrt.f64(double [[F:%.*]])
+; CHECK-NEXT:    [[MUL2:%.*]] = fmul double [[SQRT]], [[F]]
+; CHECK-NEXT:    ret double [[MUL2]]
+;
+  %sqrt = call double @llvm.sqrt.f64(double %f)
+  %mul1 = fmul fast double %sqrt, %sqrt
+  %mul2 = fmul double %mul1, %sqrt
+  ret double %mul2
+}
+
+declare float @llvm.fabs.f32(float) nounwind readnone
+
+define float @fabs_squared(float %x) {
+; CHECK-LABEL: @fabs_squared(
+; CHECK-NEXT:    [[MUL:%.*]] = fmul float [[X:%.*]], [[X]]
+; CHECK-NEXT:    ret float [[MUL]]
+;
+  %x.fabs = call float @llvm.fabs.f32(float %x)
+  %mul = fmul float %x.fabs, %x.fabs
+  ret float %mul
+}
+
+define float @fabs_squared_fast(float %x) {
+; CHECK-LABEL: @fabs_squared_fast(
+; CHECK-NEXT:    [[MUL:%.*]] = fmul fast float [[X:%.*]], [[X]]
+; CHECK-NEXT:    ret float [[MUL]]
+;
+  %x.fabs = call float @llvm.fabs.f32(float %x)
+  %mul = fmul fast float %x.fabs, %x.fabs
+  ret float %mul
+}
+
+define float @fabs_x_fabs(float %x, float %y) {
+; CHECK-LABEL: @fabs_x_fabs(
+; CHECK-NEXT:    [[X_FABS:%.*]] = call float @llvm.fabs.f32(float [[X:%.*]])
+; CHECK-NEXT:    [[Y_FABS:%.*]] = call float @llvm.fabs.f32(float [[Y:%.*]])
+; CHECK-NEXT:    [[MUL:%.*]] = fmul float [[X_FABS]], [[Y_FABS]]
+; CHECK-NEXT:    ret float [[MUL]]
+;
+  %x.fabs = call float @llvm.fabs.f32(float %x)
+  %y.fabs = call float @llvm.fabs.f32(float %y)
+  %mul = fmul float %x.fabs, %y.fabs
+  ret float %mul
+}
+
+; (X*Y) * X => (X*X) * Y
+; The transform only requires 'reassoc', but test other FMF in
+; the commuted variants to make sure FMF propagates as expected.
+
+define float @reassoc_common_operand1(float %x, float %y) {
+; CHECK-LABEL: @reassoc_common_operand1(
+; CHECK-NEXT:    [[TMP1:%.*]] = fmul reassoc float [[X:%.*]], [[X]]
+; CHECK-NEXT:    [[MUL2:%.*]] = fmul reassoc float [[TMP1]], [[Y:%.*]]
+; CHECK-NEXT:    ret float [[MUL2]]
+;
+  %mul1 = fmul float %x, %y
+  %mul2 = fmul reassoc float %mul1, %x
+  ret float %mul2
+}
+
+; (Y*X) * X => (X*X) * Y
+
+define float @reassoc_common_operand2(float %x, float %y) {
+; CHECK-LABEL: @reassoc_common_operand2(
+; CHECK-NEXT:    [[TMP1:%.*]] = fmul fast float [[X:%.*]], [[X]]
+; CHECK-NEXT:    [[MUL2:%.*]] = fmul fast float [[TMP1]], [[Y:%.*]]
+; CHECK-NEXT:    ret float [[MUL2]]
+;
+  %mul1 = fmul float %y, %x
+  %mul2 = fmul fast float %mul1, %x
+  ret float %mul2
+}
+
+; X * (X*Y) => (X*X) * Y
+
+define float @reassoc_common_operand3(float %x1, float %y) {
+; CHECK-LABEL: @reassoc_common_operand3(
+; CHECK-NEXT:    [[X:%.*]] = fdiv float [[X1:%.*]], 3.000000e+00
+; CHECK-NEXT:    [[TMP1:%.*]] = fmul reassoc nnan float [[X]], [[X]]
+; CHECK-NEXT:    [[MUL2:%.*]] = fmul reassoc nnan float [[TMP1]], [[Y:%.*]]
+; CHECK-NEXT:    ret float [[MUL2]]
+;
+  %x = fdiv float %x1, 3.0 ; thwart complexity-based canonicalization
+  %mul1 = fmul float %x, %y
+  %mul2 = fmul reassoc nnan float %x, %mul1
+  ret float %mul2
+}
+
+; X * (Y*X) => (X*X) * Y
+
+define float @reassoc_common_operand4(float %x1, float %y) {
+; CHECK-LABEL: @reassoc_common_operand4(
+; CHECK-NEXT:    [[X:%.*]] = fdiv float [[X1:%.*]], 3.000000e+00
+; CHECK-NEXT:    [[TMP1:%.*]] = fmul reassoc ninf float [[X]], [[X]]
+; CHECK-NEXT:    [[MUL2:%.*]] = fmul reassoc ninf float [[TMP1]], [[Y:%.*]]
+; CHECK-NEXT:    ret float [[MUL2]]
+;
+  %x = fdiv float %x1, 3.0 ; thwart complexity-based canonicalization
+  %mul1 = fmul float %y, %x
+  %mul2 = fmul reassoc ninf float %x, %mul1
+  ret float %mul2
+}
+
+; No change if the first fmul has another use.
+
+define float @reassoc_common_operand_multi_use(float %x, float %y) {
+; CHECK-LABEL: @reassoc_common_operand_multi_use(
+; CHECK-NEXT:    [[MUL1:%.*]] = fmul float [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    [[MUL2:%.*]] = fmul fast float [[MUL1]], [[X]]
+; CHECK-NEXT:    call void @use_f32(float [[MUL1]])
+; CHECK-NEXT:    ret float [[MUL2]]
+;
+  %mul1 = fmul float %x, %y
+  %mul2 = fmul fast float %mul1, %x
+  call void @use_f32(float %mul1)
+  ret float %mul2
+}
+
+declare float @llvm.log2.f32(float)
+
+; log2(Y * 0.5) * X = log2(Y) * X - X
+
+define float @log2half(float %x, float %y) {
+; CHECK-LABEL: @log2half(
+; CHECK-NEXT:    [[LOG2:%.*]] = call fast float @llvm.log2.f32(float [[Y:%.*]])
+; CHECK-NEXT:    [[TMP1:%.*]] = fmul fast float [[LOG2]], [[X:%.*]]
+; CHECK-NEXT:    [[MUL:%.*]] = fsub fast float [[TMP1]], [[X]]
+; CHECK-NEXT:    ret float [[MUL]]
+;
+  %halfy = fmul float %y, 0.5
+  %log2 = call float @llvm.log2.f32(float %halfy)
+  %mul = fmul fast float %log2, %x
+  ret float %mul
+}
+
+define float @log2half_commute(float %x1, float %y) {
+; CHECK-LABEL: @log2half_commute(
+; CHECK-NEXT:    [[LOG2:%.*]] = call fast float @llvm.log2.f32(float [[Y:%.*]])
+; CHECK-NEXT:    [[TMP1:%.*]] = fmul fast float [[LOG2]], [[X1:%.*]]
+; CHECK-NEXT:    [[TMP2:%.*]] = fsub fast float [[TMP1]], [[X1]]
+; CHECK-NEXT:    [[MUL:%.*]] = fmul fast float [[TMP2]], 0x3FC24924A0000000
+; CHECK-NEXT:    ret float [[MUL]]
+;
+  %x = fdiv float %x1, 7.0 ; thwart complexity-based canonicalization
+  %halfy = fmul float %y, 0.5
+  %log2 = call float @llvm.log2.f32(float %halfy)
+  %mul = fmul fast float %x, %log2
+  ret float %mul
+}
+
+; C1/X * C2 => (C1*C2) / X
+
+define float @fdiv_constant_numerator_fmul(float %x) {
+; CHECK-LABEL: @fdiv_constant_numerator_fmul(
+; CHECK-NEXT:    [[T3:%.*]] = fdiv reassoc float 1.200000e+07, [[X:%.*]]
+; CHECK-NEXT:    ret float [[T3]]
+;
+  %t1 = fdiv float 2.0e+3, %x
+  %t3 = fmul reassoc float %t1, 6.0e+3
+  ret float %t3
+}
+
+; C1/X * C2 => (C1*C2) / X is disabled if C1/X has multiple uses
+
+ at fmul2_external = external global float
+
+define float @fdiv_constant_numerator_fmul_extra_use(float %x) {
+; CHECK-LABEL: @fdiv_constant_numerator_fmul_extra_use(
+; CHECK-NEXT:    [[DIV:%.*]] = fdiv fast float 1.000000e+00, [[X:%.*]]
+; CHECK-NEXT:    store float [[DIV]], float* @fmul2_external, align 4
+; CHECK-NEXT:    [[MUL:%.*]] = fmul fast float [[DIV]], 2.000000e+00
+; CHECK-NEXT:    ret float [[MUL]]
+;
+  %div = fdiv fast float 1.0, %x
+  store float %div, float* @fmul2_external
+  %mul = fmul fast float %div, 2.0
+  ret float %mul
+}
+
+; X/C1 * C2 => X * (C2/C1) (if C2/C1 is normal FP)
+
+define float @fdiv_constant_denominator_fmul(float %x) {
+; CHECK-LABEL: @fdiv_constant_denominator_fmul(
+; CHECK-NEXT:    [[T3:%.*]] = fmul reassoc float [[X:%.*]], 3.000000e+00
+; CHECK-NEXT:    ret float [[T3]]
+;
+  %t1 = fdiv float %x, 2.0e+3
+  %t3 = fmul reassoc float %t1, 6.0e+3
+  ret float %t3
+}
+
+define <4 x float> @fdiv_constant_denominator_fmul_vec(<4 x float> %x) {
+; CHECK-LABEL: @fdiv_constant_denominator_fmul_vec(
+; CHECK-NEXT:    [[T3:%.*]] = fmul reassoc <4 x float> [[X:%.*]], <float 3.000000e+00, float 2.000000e+00, float 1.000000e+00, float 1.000000e+00>
+; CHECK-NEXT:    ret <4 x float> [[T3]]
+;
+  %t1 = fdiv <4 x float> %x, <float 2.0e+3, float 3.0e+3, float 2.0e+3, float 1.0e+3>
+  %t3 = fmul reassoc <4 x float> %t1, <float 6.0e+3, float 6.0e+3, float 2.0e+3, float 1.0e+3>
+  ret <4 x float> %t3
+}
+
+; Make sure fmul with constant expression doesn't assert.
+
+define <4 x float> @fdiv_constant_denominator_fmul_vec_constexpr(<4 x float> %x) {
+; CHECK-LABEL: @fdiv_constant_denominator_fmul_vec_constexpr(
+; CHECK-NEXT:    [[T3:%.*]] = fmul reassoc <4 x float> [[X:%.*]], <float 3.000000e+00, float 2.000000e+00, float 1.000000e+00, float 1.000000e+00>
+; CHECK-NEXT:    ret <4 x float> [[T3]]
+;
+  %constExprMul = bitcast i128 trunc (i160 bitcast (<5 x float> <float 6.0e+3, float 6.0e+3, float 2.0e+3, float 1.0e+3, float undef> to i160) to i128) to <4 x float>
+  %t1 = fdiv <4 x float> %x, <float 2.0e+3, float 3.0e+3, float 2.0e+3, float 1.0e+3>
+  %t3 = fmul reassoc <4 x float> %t1, %constExprMul
+  ret <4 x float> %t3
+}
+
+; This shows that at least part of instcombine does not check constant
+; values to see if it is creating denorms (0x3800000000000000 is a denorm
+; for 32-bit float), so protecting against denorms in other parts is
+; probably not doing the intended job.
+
+define float @fmul_constant_reassociation(float %x) {
+; CHECK-LABEL: @fmul_constant_reassociation(
+; CHECK-NEXT:    [[R:%.*]] = fmul reassoc nsz float [[X:%.*]], 0x3800000000000000
+; CHECK-NEXT:    ret float [[R]]
+;
+  %mul_flt_min = fmul reassoc nsz float %x, 0x3810000000000000
+  %r = fmul reassoc nsz float  %mul_flt_min, 0.5
+  ret float %r
+}
+
+; Canonicalization "X/C1 * C2 => X * (C2/C1)" still applies if C2/C1 is denormal
+; (otherwise, we should not have allowed the reassociation in the previous test).
+; 0x3810000000000000 == FLT_MIN
+
+define float @fdiv_constant_denominator_fmul_denorm(float %x) {
+; CHECK-LABEL: @fdiv_constant_denominator_fmul_denorm(
+; CHECK-NEXT:    [[T3:%.*]] = fmul fast float [[X:%.*]], 0x3760620000000000
+; CHECK-NEXT:    ret float [[T3]]
+;
+  %t1 = fdiv float %x, 2.0e+3
+  %t3 = fmul fast float %t1, 0x3810000000000000
+  ret float %t3
+}
+
+; X / C1 * C2 => X / (C2/C1) if C1/C2 is abnormal, but C2/C1 is a normal value.
+; TODO: We don't convert the fast fdiv to fmul because that would be multiplication
+; by a denormal, but we could do better when we know that denormals are not a problem.
+
+define float @fdiv_constant_denominator_fmul_denorm_try_harder(float %x) {
+; CHECK-LABEL: @fdiv_constant_denominator_fmul_denorm_try_harder(
+; CHECK-NEXT:    [[T3:%.*]] = fdiv reassoc float [[X:%.*]], 0x47E8000000000000
+; CHECK-NEXT:    ret float [[T3]]
+;
+  %t1 = fdiv float %x, 3.0
+  %t3 = fmul reassoc float %t1, 0x3810000000000000
+  ret float %t3
+}
+
+; Negative test: we should not have 2 divisions instead of the 1 we started with.
+
+define float @fdiv_constant_denominator_fmul_denorm_try_harder_extra_use(float %x) {
+; CHECK-LABEL: @fdiv_constant_denominator_fmul_denorm_try_harder_extra_use(
+; CHECK-NEXT:    [[T1:%.*]] = fdiv float [[X:%.*]], 3.000000e+00
+; CHECK-NEXT:    [[T3:%.*]] = fmul fast float [[T1]], 0x3810000000000000
+; CHECK-NEXT:    [[R:%.*]] = fadd float [[T1]], [[T3]]
+; CHECK-NEXT:    ret float [[R]]
+;
+  %t1 = fdiv float %x, 3.0e+0
+  %t3 = fmul fast float %t1, 0x3810000000000000
+  %r = fadd float %t1, %t3
+  ret float %r
+}
+
+; (X + C1) * C2 --> (X * C2) + C1*C2
+
+define float @fmul_fadd_distribute(float %x) {
+; CHECK-LABEL: @fmul_fadd_distribute(
+; CHECK-NEXT:    [[TMP1:%.*]] = fmul reassoc float [[X:%.*]], 3.000000e+00
+; CHECK-NEXT:    [[T3:%.*]] = fadd reassoc float [[TMP1]], 6.000000e+00
+; CHECK-NEXT:    ret float [[T3]]
+;
+  %t2 = fadd float %x, 2.0
+  %t3 = fmul reassoc float %t2, 3.0
+  ret float %t3
+}
+
+; (X - C1) * C2 --> (X * C2) - C1*C2
+
+define float @fmul_fsub_distribute1(float %x) {
+; CHECK-LABEL: @fmul_fsub_distribute1(
+; CHECK-NEXT:    [[TMP1:%.*]] = fmul reassoc float [[X:%.*]], 3.000000e+00
+; CHECK-NEXT:    [[T3:%.*]] = fadd reassoc float [[TMP1]], -6.000000e+00
+; CHECK-NEXT:    ret float [[T3]]
+;
+  %t2 = fsub float %x, 2.0
+  %t3 = fmul reassoc float %t2, 3.0
+  ret float %t3
+}
+
+; (C1 - X) * C2 --> C1*C2 - (X * C2)
+
+define float @fmul_fsub_distribute2(float %x) {
+; CHECK-LABEL: @fmul_fsub_distribute2(
+; CHECK-NEXT:    [[TMP1:%.*]] = fmul reassoc float [[X:%.*]], 3.000000e+00
+; CHECK-NEXT:    [[T3:%.*]] = fsub reassoc float 6.000000e+00, [[TMP1]]
+; CHECK-NEXT:    ret float [[T3]]
+;
+  %t2 = fsub float 2.0, %x
+  %t3 = fmul reassoc float %t2, 3.0
+  ret float %t3
+}
+
+; FIXME: This should only need 'reassoc'.
+; ((X*C1) + C2) * C3 => (X * (C1*C3)) + (C2*C3)
+
+define float @fmul_fadd_fmul_distribute(float %x) {
+; CHECK-LABEL: @fmul_fadd_fmul_distribute(
+; CHECK-NEXT:    [[TMP1:%.*]] = fmul fast float [[X:%.*]], 3.000000e+01
+; CHECK-NEXT:    [[T3:%.*]] = fadd fast float [[TMP1]], 1.000000e+01
+; CHECK-NEXT:    ret float [[T3]]
+;
+  %t1 = fmul float %x, 6.0
+  %t2 = fadd float %t1, 2.0
+  %t3 = fmul fast float %t2, 5.0
+  ret float %t3
+}
+
+define float @fmul_fadd_distribute_extra_use(float %x) {
+; CHECK-LABEL: @fmul_fadd_distribute_extra_use(
+; CHECK-NEXT:    [[T1:%.*]] = fmul float [[X:%.*]], 6.000000e+00
+; CHECK-NEXT:    [[T2:%.*]] = fadd float [[T1]], 2.000000e+00
+; CHECK-NEXT:    [[T3:%.*]] = fmul fast float [[T2]], 5.000000e+00
+; CHECK-NEXT:    call void @use_f32(float [[T2]])
+; CHECK-NEXT:    ret float [[T3]]
+;
+  %t1 = fmul float %x, 6.0
+  %t2 = fadd float %t1, 2.0
+  %t3 = fmul fast float %t2, 5.0
+  call void @use_f32(float %t2)
+  ret float %t3
+}
+
+; (X/C1 + C2) * C3 => X/(C1/C3) + C2*C3
+; 0x10000000000000 = DBL_MIN
+; TODO: We don't convert the fast fdiv to fmul because that would be multiplication
+; by a denormal, but we could do better when we know that denormals are not a problem.
+
+define double @fmul_fadd_fdiv_distribute2(double %x) {
+; CHECK-LABEL: @fmul_fadd_fdiv_distribute2(
+; CHECK-NEXT:    [[TMP1:%.*]] = fdiv reassoc double [[X:%.*]], 0x7FE8000000000000
+; CHECK-NEXT:    [[T3:%.*]] = fadd reassoc double [[TMP1]], 0x34000000000000
+; CHECK-NEXT:    ret double [[T3]]
+;
+  %t1 = fdiv double %x, 3.0
+  %t2 = fadd double %t1, 5.0
+  %t3 = fmul reassoc double %t2, 0x10000000000000
+  ret double %t3
+}
+
+; 5.0e-1 * DBL_MIN yields denormal, so "(f1*3.0 + 5.0e-1) * DBL_MIN" cannot
+; be simplified into f1 * (3.0*DBL_MIN) + (5.0e-1*DBL_MIN)
+
+define double @fmul_fadd_fdiv_distribute3(double %x) {
+; CHECK-LABEL: @fmul_fadd_fdiv_distribute3(
+; CHECK-NEXT:    [[TMP1:%.*]] = fdiv reassoc double [[X:%.*]], 0x7FE8000000000000
+; CHECK-NEXT:    [[T3:%.*]] = fadd reassoc double [[TMP1]], 0x34000000000000
+; CHECK-NEXT:    ret double [[T3]]
+;
+  %t1 = fdiv double %x, 3.0
+  %t2 = fadd double %t1, 5.0
+  %t3 = fmul reassoc double %t2, 0x10000000000000
+  ret double %t3
+}
+
+; FIXME: This should only need 'reassoc'.
+; (C2 - (X*C1)) * C3 => (C2*C3) - (X * (C1*C3))
+
+define float @fmul_fsub_fmul_distribute(float %x) {
+; CHECK-LABEL: @fmul_fsub_fmul_distribute(
+; CHECK-NEXT:    [[TMP1:%.*]] = fmul fast float [[X:%.*]], 3.000000e+01
+; CHECK-NEXT:    [[T3:%.*]] = fsub fast float 1.000000e+01, [[TMP1]]
+; CHECK-NEXT:    ret float [[T3]]
+;
+  %t1 = fmul float %x, 6.0
+  %t2 = fsub float 2.0, %t1
+  %t3 = fmul fast float %t2, 5.0
+  ret float %t3
+}
+
+define float @fmul_fsub_fmul_distribute_extra_use(float %x) {
+; CHECK-LABEL: @fmul_fsub_fmul_distribute_extra_use(
+; CHECK-NEXT:    [[T1:%.*]] = fmul float [[X:%.*]], 6.000000e+00
+; CHECK-NEXT:    [[T2:%.*]] = fsub float 2.000000e+00, [[T1]]
+; CHECK-NEXT:    [[T3:%.*]] = fmul fast float [[T2]], 5.000000e+00
+; CHECK-NEXT:    call void @use_f32(float [[T2]])
+; CHECK-NEXT:    ret float [[T3]]
+;
+  %t1 = fmul float %x, 6.0
+  %t2 = fsub float 2.0, %t1
+  %t3 = fmul fast float %t2, 5.0
+  call void @use_f32(float %t2)
+  ret float %t3
+}
+
+; FIXME: This should only need 'reassoc'.
+; ((X*C1) - C2) * C3 => (X * (C1*C3)) - C2*C3
+
+define float @fmul_fsub_fmul_distribute2(float %x) {
+; CHECK-LABEL: @fmul_fsub_fmul_distribute2(
+; CHECK-NEXT:    [[TMP1:%.*]] = fmul fast float [[X:%.*]], 3.000000e+01
+; CHECK-NEXT:    [[T3:%.*]] = fadd fast float [[TMP1]], -1.000000e+01
+; CHECK-NEXT:    ret float [[T3]]
+;
+  %t1 = fmul float %x, 6.0
+  %t2 = fsub float %t1, 2.0
+  %t3 = fmul fast float %t2, 5.0
+  ret float %t3
+}
+
+define float @fmul_fsub_fmul_distribute2_extra_use(float %x) {
+; CHECK-LABEL: @fmul_fsub_fmul_distribute2_extra_use(
+; CHECK-NEXT:    [[T1:%.*]] = fmul float [[X:%.*]], 6.000000e+00
+; CHECK-NEXT:    [[T2:%.*]] = fsub float 2.000000e+00, [[T1]]
+; CHECK-NEXT:    [[T3:%.*]] = fmul fast float [[T2]], 5.000000e+00
+; CHECK-NEXT:    call void @use_f32(float [[T2]])
+; CHECK-NEXT:    ret float [[T3]]
+;
+  %t1 = fmul float %x, 6.0
+  %t2 = fsub float 2.0, %t1
+  %t3 = fmul fast float %t2, 5.0
+  call void @use_f32(float %t2)
+  ret float %t3
+}
+
+; "(X*Y) * X => (X*X) * Y" is disabled if "X*Y" has multiple uses
+
+define float @common_factor(float %x, float %y) {
+; CHECK-LABEL: @common_factor(
+; CHECK-NEXT:    [[MUL:%.*]] = fmul float [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    [[MUL1:%.*]] = fmul fast float [[MUL]], [[X]]
+; CHECK-NEXT:    [[ADD:%.*]] = fadd float [[MUL1]], [[MUL]]
+; CHECK-NEXT:    ret float [[ADD]]
+;
+  %mul = fmul float %x, %y
+  %mul1 = fmul fast float %mul, %x
+  %add = fadd float %mul1, %mul
+  ret float %add
+}
+
+define double @fmul_fdiv_factor_squared(double %x, double %y) {
+; CHECK-LABEL: @fmul_fdiv_factor_squared(
+; CHECK-NEXT:    [[DIV:%.*]] = fdiv fast double [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    [[SQUARED:%.*]] = fmul fast double [[DIV]], [[DIV]]
+; CHECK-NEXT:    ret double [[SQUARED]]
+;
+  %div = fdiv fast double %x, %y
+  %squared = fmul fast double %div, %div
+  ret double %squared
+}
+
+define double @fmul_fdivs_factor_common_denominator(double %x, double %y, double %z) {
+; CHECK-LABEL: @fmul_fdivs_factor_common_denominator(
+; CHECK-NEXT:    [[TMP1:%.*]] = fmul fast double [[Y:%.*]], [[X:%.*]]
+; CHECK-NEXT:    [[TMP2:%.*]] = fmul fast double [[Z:%.*]], [[Z]]
+; CHECK-NEXT:    [[MUL:%.*]] = fdiv fast double [[TMP1]], [[TMP2]]
+; CHECK-NEXT:    ret double [[MUL]]
+;
+  %div1 = fdiv double %x, %z
+  %div2 = fdiv double %y, %z
+  %mul = fmul fast double %div1, %div2
+  ret double %mul
+}
+
+define double @fmul_fdivs_factor(double %x, double %y, double %z, double %w) {
+; CHECK-LABEL: @fmul_fdivs_factor(
+; CHECK-NEXT:    [[TMP1:%.*]] = fmul reassoc double [[Z:%.*]], [[X:%.*]]
+; CHECK-NEXT:    [[TMP2:%.*]] = fdiv reassoc double [[TMP1]], [[W:%.*]]
+; CHECK-NEXT:    [[MUL:%.*]] = fdiv reassoc double [[TMP2]], [[Y:%.*]]
+; CHECK-NEXT:    ret double [[MUL]]
+;
+  %div1 = fdiv double %x, %y
+  %div2 = fdiv double %z, %w
+  %mul = fmul reassoc double %div1, %div2
+  ret double %mul
+}
+
+define double @fmul_fdiv_factor(double %x, double %y, double %z) {
+; CHECK-LABEL: @fmul_fdiv_factor(
+; CHECK-NEXT:    [[TMP1:%.*]] = fmul reassoc double [[X:%.*]], [[Z:%.*]]
+; CHECK-NEXT:    [[MUL:%.*]] = fdiv reassoc double [[TMP1]], [[Y:%.*]]
+; CHECK-NEXT:    ret double [[MUL]]
+;
+  %div = fdiv double %x, %y
+  %mul = fmul reassoc double %div, %z
+  ret double %mul
+}
+
+define double @fmul_fdiv_factor_constant1(double %x, double %y) {
+; CHECK-LABEL: @fmul_fdiv_factor_constant1(
+; CHECK-NEXT:    [[TMP1:%.*]] = fmul reassoc double [[X:%.*]], 4.200000e+01
+; CHECK-NEXT:    [[MUL:%.*]] = fdiv reassoc double [[TMP1]], [[Y:%.*]]
+; CHECK-NEXT:    ret double [[MUL]]
+;
+  %div = fdiv double %x, %y
+  %mul = fmul reassoc double %div, 42.0
+  ret double %mul
+}
+
+define <2 x float> @fmul_fdiv_factor_constant2(<2 x float> %x, <2 x float> %y) {
+; CHECK-LABEL: @fmul_fdiv_factor_constant2(
+; CHECK-NEXT:    [[TMP1:%.*]] = fmul reassoc <2 x float> [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    [[MUL:%.*]] = fdiv reassoc <2 x float> [[TMP1]], <float 4.200000e+01, float 1.200000e+01>
+; CHECK-NEXT:    ret <2 x float> [[MUL]]
+;
+  %div = fdiv <2 x float> %x, <float 42.0, float 12.0>
+  %mul = fmul reassoc <2 x float> %div, %y
+  ret <2 x float> %mul
+}
+
+define float @fmul_fdiv_factor_extra_use(float %x, float %y) {
+; CHECK-LABEL: @fmul_fdiv_factor_extra_use(
+; CHECK-NEXT:    [[DIV:%.*]] = fdiv float [[X:%.*]], 4.200000e+01
+; CHECK-NEXT:    call void @use_f32(float [[DIV]])
+; CHECK-NEXT:    [[MUL:%.*]] = fmul reassoc float [[DIV]], [[Y:%.*]]
+; CHECK-NEXT:    ret float [[MUL]]
+;
+  %div = fdiv float %x, 42.0
+  call void @use_f32(float %div)
+  %mul = fmul reassoc float %div, %y
+  ret float %mul
+}

Added: llvm/trunk/test/Transforms/InstCombine/fneg.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/fneg.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/fneg.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/fneg.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,158 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt < %s -instcombine -S | FileCheck %s
+
+declare void @use(float)
+
+; -(X * C) --> X * (-C)
+
+define float @fmul_fneg(float %x) {
+; CHECK-LABEL: @fmul_fneg(
+; CHECK-NEXT:    [[R:%.*]] = fmul float [[X:%.*]], -4.200000e+01
+; CHECK-NEXT:    ret float [[R]]
+;
+  %m = fmul float %x, 42.0
+  %r = fsub float -0.0, %m
+  ret float %r
+}
+
+; Fast math is not required, but it should be propagated.
+
+define float @fmul_fneg_fmf(float %x) {
+; CHECK-LABEL: @fmul_fneg_fmf(
+; CHECK-NEXT:    [[R:%.*]] = fmul reassoc nsz float [[X:%.*]], -4.200000e+01
+; CHECK-NEXT:    ret float [[R]]
+;
+  %m = fmul float %x, 42.0
+  %r = fsub reassoc nsz float -0.0, %m
+  ret float %r
+}
+
+; Extra use prevents the fold. We don't want to replace the fneg with an fmul.
+
+define float @fmul_fneg_extra_use(float %x) {
+; CHECK-LABEL: @fmul_fneg_extra_use(
+; CHECK-NEXT:    [[M:%.*]] = fmul float [[X:%.*]], 4.200000e+01
+; CHECK-NEXT:    [[R:%.*]] = fsub float -0.000000e+00, [[M]]
+; CHECK-NEXT:    call void @use(float [[M]])
+; CHECK-NEXT:    ret float [[R]]
+;
+  %m = fmul float %x, 42.0
+  %r = fsub float -0.0, %m
+  call void @use(float %m)
+  ret float %r
+}
+
+; Try a vector. Use special constants (NaN, INF, undef) because they don't change anything.
+
+define <4 x double> @fmul_fneg_vec(<4 x double> %x) {
+; CHECK-LABEL: @fmul_fneg_vec(
+; CHECK-NEXT:    [[R:%.*]] = fmul <4 x double> [[X:%.*]], <double -4.200000e+01, double 0x7F80000000000000, double 0xFFF0000000000000, double 0x7FF8000000000000>
+; CHECK-NEXT:    ret <4 x double> [[R]]
+;
+  %m = fmul <4 x double> %x, <double 42.0, double 0x7FF80000000000000, double 0x7FF0000000000000, double undef>
+  %r = fsub <4 x double> <double -0.0, double -0.0, double -0.0, double -0.0>, %m
+  ret <4 x double> %r
+}
+
+; -(X / C) --> X / (-C)
+
+define float @fdiv_op1_constant_fneg(float %x) {
+; CHECK-LABEL: @fdiv_op1_constant_fneg(
+; CHECK-NEXT:    [[R:%.*]] = fdiv float [[X:%.*]], 4.200000e+01
+; CHECK-NEXT:    ret float [[R]]
+;
+  %d = fdiv float %x, -42.0
+  %r = fsub float -0.0, %d
+  ret float %r
+}
+
+; Fast math is not required, but it should be propagated.
+
+define float @fdiv_op1_constant_fneg_fmf(float %x) {
+; CHECK-LABEL: @fdiv_op1_constant_fneg_fmf(
+; CHECK-NEXT:    [[R:%.*]] = fdiv nnan float [[X:%.*]], 4.200000e+01
+; CHECK-NEXT:    ret float [[R]]
+;
+  %d = fdiv float %x, -42.0
+  %r = fsub nnan float -0.0, %d
+  ret float %r
+}
+
+; Extra use prevents the fold. We don't want to replace the fneg with an fdiv.
+
+define float @fdiv_op1_constant_fneg_extra_use(float %x) {
+; CHECK-LABEL: @fdiv_op1_constant_fneg_extra_use(
+; CHECK-NEXT:    [[D:%.*]] = fdiv float [[X:%.*]], 4.200000e+01
+; CHECK-NEXT:    [[R:%.*]] = fsub float -0.000000e+00, [[D]]
+; CHECK-NEXT:    call void @use(float [[D]])
+; CHECK-NEXT:    ret float [[R]]
+;
+  %d = fdiv float %x, 42.0
+  %r = fsub float -0.0, %d
+  call void @use(float %d)
+  ret float %r
+}
+
+; Try a vector. Use special constants (NaN, INF, undef) because they don't change anything.
+
+define <4 x double> @fdiv_op1_constant_fneg_vec(<4 x double> %x) {
+; CHECK-LABEL: @fdiv_op1_constant_fneg_vec(
+; CHECK-NEXT:    [[R:%.*]] = fdiv <4 x double> [[X:%.*]], <double 4.200000e+01, double 0x7FF800000ABCD000, double 0x7FF0000000000000, double 0x7FF8000000000000>
+; CHECK-NEXT:    ret <4 x double> [[R]]
+;
+  %d = fdiv <4 x double> %x, <double -42.0, double 0xFFF800000ABCD000, double 0xFFF0000000000000, double undef>
+  %r = fsub <4 x double> <double -0.0, double -0.0, double -0.0, double -0.0>, %d
+  ret <4 x double> %r
+}
+
+; -(C / X) --> (-C) / X
+
+define float @fdiv_op0_constant_fneg(float %x) {
+; CHECK-LABEL: @fdiv_op0_constant_fneg(
+; CHECK-NEXT:    [[R:%.*]] = fdiv float -4.200000e+01, [[X:%.*]]
+; CHECK-NEXT:    ret float [[R]]
+;
+  %d = fdiv float 42.0, %x
+  %r = fsub float -0.0, %d
+  ret float %r
+}
+
+; Fast math is not required, but it should be propagated.
+
+define float @fdiv_op0_constant_fneg_fmf(float %x) {
+; CHECK-LABEL: @fdiv_op0_constant_fneg_fmf(
+; CHECK-NEXT:    [[R:%.*]] = fdiv fast float -4.200000e+01, [[X:%.*]]
+; CHECK-NEXT:    ret float [[R]]
+;
+  %d = fdiv float 42.0, %x
+  %r = fsub fast float -0.0, %d
+  ret float %r
+}
+
+; Extra use prevents the fold. We don't want to replace the fneg with an fdiv.
+
+define float @fdiv_op0_constant_fneg_extra_use(float %x) {
+; CHECK-LABEL: @fdiv_op0_constant_fneg_extra_use(
+; CHECK-NEXT:    [[D:%.*]] = fdiv float -4.200000e+01, [[X:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = fsub float -0.000000e+00, [[D]]
+; CHECK-NEXT:    call void @use(float [[D]])
+; CHECK-NEXT:    ret float [[R]]
+;
+  %d = fdiv float -42.0, %x
+  %r = fsub float -0.0, %d
+  call void @use(float %d)
+  ret float %r
+}
+
+; Try a vector. Use special constants (NaN, INF, undef) because they don't change anything.
+
+define <4 x double> @fdiv_op0_constant_fneg_vec(<4 x double> %x) {
+; CHECK-LABEL: @fdiv_op0_constant_fneg_vec(
+; CHECK-NEXT:    [[R:%.*]] = fdiv <4 x double> <double 4.200000e+01, double 0x7F80000000000000, double 0x7FF0000000000000, double 0x7FF8000000000000>, [[X:%.*]]
+; CHECK-NEXT:    ret <4 x double> [[R]]
+;
+  %d = fdiv <4 x double> <double -42.0, double 0x7FF80000000000000, double 0xFFF0000000000000, double undef>, %x
+  %r = fsub <4 x double> <double -0.0, double -0.0, double -0.0, double -0.0>, %d
+  ret <4 x double> %r
+}
+

Added: llvm/trunk/test/Transforms/InstCombine/fold-bin-operand.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/fold-bin-operand.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/fold-bin-operand.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/fold-bin-operand.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,17 @@
+; RUN: opt < %s -instcombine -S | FileCheck %s
+target datalayout = "E-p:64:64:64-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"
+
+define i1 @f(i1 %x) {
+; CHECK-LABEL: @f(
+; CHECK: ret i1 false
+	%b = and i1 %x, icmp eq (i8* inttoptr (i32 1 to i8*), i8* inttoptr (i32 2 to i8*))
+	ret i1 %b
+}
+
+define i32 @g(i32 %x) {
+; CHECK-LABEL: @g(
+; CHECK: ret i32 %x
+	%b = add i32 %x, zext (i1 icmp eq (i8* inttoptr (i32 1000000 to i8*), i8* inttoptr (i32 2000000 to i8*)) to i32)
+	ret i32 %b
+}
+

Added: llvm/trunk/test/Transforms/InstCombine/fold-calls.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/fold-calls.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/fold-calls.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/fold-calls.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,19 @@
+; RUN: opt -instcombine -S < %s | FileCheck %s
+
+; This shouldn't fold, because sin(inf) is invalid.
+; CHECK-LABEL: @foo(
+; CHECK:   %t = call double @sin(double 0x7FF0000000000000)
+define double @foo() {
+  %t = call double @sin(double 0x7FF0000000000000)
+  ret double %t
+}
+
+; This should fold.
+; CHECK-LABEL: @bar(
+; CHECK:   ret double 0.0
+define double @bar() {
+  %t = call double @sin(double 0.0)
+  ret double %t
+}
+
+declare double @sin(double)

Added: llvm/trunk/test/Transforms/InstCombine/fold-fops-into-selects.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/fold-fops-into-selects.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/fold-fops-into-selects.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/fold-fops-into-selects.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,71 @@
+; RUN: opt < %s -instcombine -S | FileCheck %s
+
+define float @test1(i1 %A) {
+EntryBlock:
+  %cf = select i1 %A, float 1.000000e+00, float 0.000000e+00
+  %op = fsub float 1.000000e+00, %cf
+  ret float %op
+; CHECK-LABEL: @test1(
+; CHECK: select i1 %A, float 0.000000e+00, float 1.000000e+00
+}
+
+define float @test2(i1 %A, float %B) {
+EntryBlock:
+  %cf = select i1 %A, float 1.000000e+00, float %B
+  %op = fadd float 2.000000e+00, %cf
+  ret float %op
+; CHECK-LABEL: @test2(
+; CHECK: [[OP:%.*]] = fadd float %B, 2.000000e+00
+; CHECK: select i1 %A, float 3.000000e+00, float [[OP]]
+}
+
+define float @test3(i1 %A, float %B) {
+EntryBlock:
+  %cf = select i1 %A, float 1.000000e+00, float %B
+  %op = fsub float 2.000000e+00, %cf
+  ret float %op
+; CHECK-LABEL: @test3(
+; CHECK: [[OP:%.*]] = fsub float 2.000000e+00, %B
+; CHECK: select i1 %A, float 1.000000e+00, float [[OP]]
+}
+
+define float @test4(i1 %A, float %B) {
+EntryBlock:
+  %cf = select i1 %A, float 1.000000e+00, float %B
+  %op = fmul float 2.000000e+00, %cf
+  ret float %op
+; CHECK-LABEL: @test4(
+; CHECK: [[OP:%.*]] = fmul float %B, 2.000000e+00
+; CHECK: select i1 %A, float 2.000000e+00, float [[OP]]
+}
+
+define float @test5(i1 %A, float %B) {
+EntryBlock:
+  %cf = select i1 %A, float 1.000000e+00, float %B
+  %op = fdiv float 2.000000e+00, %cf
+  ret float %op
+; CHECK-LABEL: @test5(
+; CHECK: [[OP:%.*]] = fdiv float 2.000000e+00, %B
+; CHECK: select i1 %A, float 2.000000e+00, float [[OP]]
+}
+
+define float @test6(i1 %A, float %B) {
+EntryBlock:
+  %cf = select i1 %A, float 1.000000e+00, float %B
+  %op = fdiv float %cf, 2.000000e+00
+  ret float %op
+; CHECK-LABEL: @test6(
+; CHECK: [[OP:%.*]] = fmul float %B, 5.000000e-01
+; CHECK: select i1 %A, float 5.000000e-01, float [[OP]]
+}
+
+define float @test7(i1 %A, float %B) {
+EntryBlock:
+  %cf = select i1 %A, float 1.000000e+00, float %B
+  %op = fdiv float %cf, 3.000000e+00
+  ret float %op
+; CHECK-LABEL: @test7(
+; CHECK: [[OP:%.*]] = fdiv float %B, 3.000000e+00
+; CHECK: select i1 %A, float 0x3FD5555560000000, float [[OP]]
+}
+

Added: llvm/trunk/test/Transforms/InstCombine/fold-phi-load-metadata.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/fold-phi-load-metadata.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/fold-phi-load-metadata.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/fold-phi-load-metadata.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,69 @@
+; RUN: opt -instcombine -S < %s | FileCheck %s
+
+ at g1 = common global i32* null, align 8
+
+%struct.S1 = type { i32, float }
+%struct.S2 = type { float, i32 }
+
+; Check that instcombine preserves metadata when it merges two loads.
+;
+; CHECK: return:
+; CHECK: load i32*, i32** %{{[a-z0-9.]+}}, align 8, !nonnull ![[EMPTYNODE:[0-9]+]]
+; CHECK: load i32, i32* %{{[a-z0-9.]+}}, align 4, !tbaa ![[TBAA:[0-9]+]], !range ![[RANGE:[0-9]+]], !invariant.load ![[EMPTYNODE:[0-9]+]], !alias.scope ![[ALIAS_SCOPE:[0-9]+]], !noalias ![[NOALIAS:[0-9]+]]
+
+; Function Attrs: nounwind ssp uwtable
+define i32 @phi_load_metadata(%struct.S1* %s1, %struct.S2* %s2, i32 %c, i32** %x0, i32 **%x1) #0 {
+entry:
+  %tobool = icmp eq i32 %c, 0
+  br i1 %tobool, label %if.end, label %if.then
+
+if.then:                                          ; preds = %entry
+  %i = getelementptr inbounds %struct.S2, %struct.S2* %s2, i64 0, i32 1
+  %val = load i32, i32* %i, align 4, !tbaa !0, !alias.scope !13, !noalias !14, !invariant.load !17, !range !18
+  %p0 = load i32*, i32** %x0, align 8, !nonnull !17
+  br label %return
+
+if.end:                                           ; preds = %entry
+  %i2 = getelementptr inbounds %struct.S1, %struct.S1* %s1, i64 0, i32 0
+  %val2 = load i32, i32* %i2, align 4, !tbaa !2, !alias.scope !15, !noalias !16, !invariant.load !17, !range !19
+  %p1 = load i32*, i32** %x1, align 8, !nonnull !17
+  br label %return
+
+return:                                           ; preds = %if.end, %if.then
+  %retval = phi i32 [ %val, %if.then ], [ %val2, %if.end ]
+  %pval = phi i32* [ %p0, %if.then ], [ %p1, %if.end ]
+  store i32* %pval, i32** @g1, align 8
+  ret i32 %retval
+}
+
+; CHECK: ![[EMPTYNODE]] = !{}
+; CHECK: ![[TBAA]] = !{![[TAG1:[0-9]+]], ![[TAG1]], i64 0}
+; CHECK: ![[TAG1]] = !{!"int", !{{[0-9]+}}, i64 0}
+; CHECK: ![[RANGE]] = !{i32 10, i32 25}
+; CHECK: ![[ALIAS_SCOPE]] = !{![[SCOPE0:[0-9]+]], ![[SCOPE2:[0-9]+]], ![[SCOPE1:[0-9]+]]}
+; CHECK: ![[SCOPE0]] = distinct !{![[SCOPE0]], !{{[0-9]+}}, !"scope0"}
+; CHECK: ![[SCOPE2]] = distinct !{![[SCOPE2]], !{{[0-9]+}}, !"scope2"}
+; CHECK: ![[SCOPE1]] = distinct !{![[SCOPE1]], !{{[0-9]+}}, !"scope1"}
+; CHECK: ![[NOALIAS]] = !{![[SCOPE3:[0-9]+]]}
+; CHECK: ![[SCOPE3]] = distinct !{![[SCOPE3]], !{{[0-9]+}}, !"scope3"}
+
+!0 = !{!1, !4, i64 4}
+!1 = !{!"", !7, i64 0, !4, i64 4}
+!2 = !{!3, !4, i64 0}
+!3 = !{!"", !4, i64 0, !7, i64 4}
+!4 = !{!"int", !5, i64 0}
+!5 = !{!"omnipotent char", !6, i64 0}
+!6 = !{!"Simple C/C++ TBAA"}
+!7 = !{!"float", !5, i64 0}
+!8 = !{!8, !"some domain"}
+!9 = !{!9, !8, !"scope0"}
+!10 = !{!10, !8, !"scope1"}
+!11 = !{!11, !8, !"scope2"}
+!12 = !{!12, !8, !"scope3"}
+!13 = !{!9, !10}
+!14 = !{!11, !12}
+!15 = !{!9, !11}
+!16 = !{!10, !12}
+!17 = !{}
+!18 = !{i32 10, i32 20}
+!19 = !{i32 15, i32 25}

Added: llvm/trunk/test/Transforms/InstCombine/fold-phi.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/fold-phi.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/fold-phi.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/fold-phi.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,39 @@
+; RUN: opt < %s -instcombine -S | FileCheck %s
+
+; CHECK: no_crash
+define float @no_crash(float %a) nounwind {
+entry:
+  br label %for.body
+
+for.body:
+  %sum.057 = phi float [ 0.000000e+00, %entry ], [ %add5, %bb0 ]
+  %add5 = fadd float %sum.057, %a    ; PR14592
+  br i1 undef, label %bb0, label %end
+
+bb0:
+  br label %for.body
+
+end:
+  ret float %add5
+}
+
+; CHECK-LABEL: @pr21377(
+define void @pr21377(i32) {
+entry:
+  br label %while.body
+
+while.body:                                       ; preds = %if.end, %entry
+  %phi1 = phi i64 [ undef, %entry ], [ %or2, %if.end ]
+  %zext = zext i32 %0 to i64
+  br i1 undef, label %if.end, label %if.else
+
+if.else:                                          ; preds = %while.body
+  %or1 = or i64 %phi1, %zext
+  %and = and i64 %or1, 4294967295
+  br label %if.end
+
+if.end:                                           ; preds = %if.else, %while.body
+  %phi2 = phi i64 [ %and, %if.else ], [ undef, %while.body ]
+  %or2 = or i64 %phi2, %zext
+  br label %while.body
+}

Added: llvm/trunk/test/Transforms/InstCombine/fold-sqrt-sqrtf.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/fold-sqrt-sqrtf.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/fold-sqrt-sqrtf.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/fold-sqrt-sqrtf.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,17 @@
+; RUN: opt -instcombine -S -disable-simplify-libcalls < %s | FileCheck %s
+; rdar://10466410
+
+; Instcombine tries to fold (fptrunc (sqrt (fpext x))) -> (sqrtf x), but this
+; shouldn't fold when sqrtf isn't available.
+define float @foo(float %f) uwtable ssp {
+entry:
+; CHECK: %conv = fpext float %f to double
+; CHECK: %call = tail call double @sqrt(double %conv)
+; CHECK: %conv1 = fptrunc double %call to float
+  %conv = fpext float %f to double
+  %call = tail call double @sqrt(double %conv)
+  %conv1 = fptrunc double %call to float
+  ret float %conv1
+}
+
+declare double @sqrt(double)

Added: llvm/trunk/test/Transforms/InstCombine/fold-vector-select.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/fold-vector-select.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/fold-vector-select.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/fold-vector-select.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,150 @@
+; RUN: opt < %s -instcombine -S | FileCheck %s
+
+; CHECK-NOT: select
+
+define void @foo(<4 x i32> *%A, <4 x i32> *%B, <4 x i32> *%C, <4 x i32> *%D,
+                 <4 x i32> *%E, <4 x i32> *%F, <4 x i32> *%G, <4 x i32> *%H,
+                 <4 x i32> *%I, <4 x i32> *%J, <4 x i32> *%K, <4 x i32> *%L,
+                 <4 x i32> *%M, <4 x i32> *%N, <4 x i32> *%O, <4 x i32> *%P,
+                 <4 x i32> *%Q, <4 x i32> *%R, <4 x i32> *%S, <4 x i32> *%T,
+                 <4 x i32> *%U, <4 x i32> *%V, <4 x i32> *%W, <4 x i32> *%X,
+                 <4 x i32> *%Y, <4 x i32> *%Z, <4 x i32> *%BA, <4 x i32> *%BB,
+                 <4 x i32> *%BC, <4 x i32> *%BD, <4 x i32> *%BE, <4 x i32> *%BF,
+                 <4 x i32> *%BG, <4 x i32> *%BH, <4 x i32> *%BI, <4 x i32> *%BJ,
+                 <4 x i32> *%BK, <4 x i32> *%BL, <4 x i32> *%BM, <4 x i32> *%BN,
+                 <4 x i32> *%BO, <4 x i32> *%BP, <4 x i32> *%BQ, <4 x i32> *%BR,
+                 <4 x i32> *%BS, <4 x i32> *%BT, <4 x i32> *%BU, <4 x i32> *%BV,
+                 <4 x i32> *%BW, <4 x i32> *%BX, <4 x i32> *%BY, <4 x i32> *%BZ,
+                 <4 x i32> *%CA, <4 x i32> *%CB, <4 x i32> *%CC, <4 x i32> *%CD,
+                 <4 x i32> *%CE, <4 x i32> *%CF, <4 x i32> *%CG, <4 x i32> *%CH,
+                 <4 x i32> *%CI, <4 x i32> *%CJ, <4 x i32> *%CK, <4 x i32> *%CL) {
+ %a = select <4 x i1> <i1 false, i1 false, i1 false, i1 false>, <4 x i32> zeroinitializer, <4 x i32> <i32 9, i32 87, i32 57, i32 8>
+ %b = select <4 x i1> <i1 true, i1 false, i1 false, i1 false>, <4 x i32> zeroinitializer, <4 x i32> <i32 44, i32 99, i32 49, i32 29>
+ %c = select <4 x i1> <i1 false, i1 true, i1 false, i1 false>, <4 x i32> zeroinitializer, <4 x i32> <i32 15, i32 18, i32 53, i32 84>
+ %d = select <4 x i1> <i1 true, i1 true, i1 false, i1 false>, <4 x i32> zeroinitializer, <4 x i32> <i32 29, i32 82, i32 45, i32 16>
+ %e = select <4 x i1> <i1 false, i1 false, i1 true, i1 false>, <4 x i32> zeroinitializer, <4 x i32> <i32 11, i32 15, i32 32, i32 99>
+ %f = select <4 x i1> <i1 true, i1 false, i1 true, i1 false>, <4 x i32> zeroinitializer, <4 x i32> <i32 19, i32 86, i32 29, i32 33>
+ %g = select <4 x i1> <i1 false, i1 true, i1 true, i1 false>, <4 x i32> zeroinitializer, <4 x i32> <i32 44, i32 10, i32 26, i32 45>
+ %h = select <4 x i1> <i1 true, i1 true, i1 true, i1 false>, <4 x i32> zeroinitializer, <4 x i32> <i32 88, i32 70, i32 90, i32 48>
+ %i = select <4 x i1> <i1 false, i1 false, i1 false, i1 true>, <4 x i32> zeroinitializer, <4 x i32> <i32 30, i32 53, i32 42, i32 12>
+ %j = select <4 x i1> <i1 true, i1 false, i1 false, i1 true>, <4 x i32> zeroinitializer, <4 x i32> <i32 46, i32 24, i32 93, i32 26>
+ %k = select <4 x i1> <i1 false, i1 true, i1 false, i1 true>, <4 x i32> zeroinitializer, <4 x i32> <i32 33, i32 99, i32 15, i32 57>
+ %l = select <4 x i1> <i1 true, i1 true, i1 false, i1 true>, <4 x i32> zeroinitializer, <4 x i32> <i32 51, i32 60, i32 60, i32 50>
+ %m = select <4 x i1> <i1 false, i1 false, i1 true, i1 true>, <4 x i32> zeroinitializer, <4 x i32> <i32 50, i32 12, i32 7, i32 45>
+ %n = select <4 x i1> <i1 true, i1 false, i1 true, i1 true>, <4 x i32> zeroinitializer, <4 x i32> <i32 15, i32 65, i32 36, i32 36>
+ %o = select <4 x i1> <i1 false, i1 true, i1 true, i1 true>, <4 x i32> zeroinitializer, <4 x i32> <i32 54, i32 0, i32 17, i32 78>
+ %p = select <4 x i1> <i1 true, i1 true, i1 true, i1 true>, <4 x i32> zeroinitializer, <4 x i32> <i32 56, i32 13, i32 64, i32 48>
+ %q = select <4 x i1> <i1 false, i1 false, i1 false, i1 false>, <4 x i32> <i32 52, i32 69, i32 88, i32 11>, <4 x i32> zeroinitializer
+ %r = select <4 x i1> <i1 true, i1 false, i1 false, i1 false>, <4 x i32> <i32 5, i32 87, i32 68, i32 14>, <4 x i32> zeroinitializer
+ %s = select <4 x i1> <i1 false, i1 true, i1 false, i1 false>, <4 x i32> <i32 47, i32 17, i32 66, i32 63>, <4 x i32> zeroinitializer
+ %t = select <4 x i1> <i1 true, i1 true, i1 false, i1 false>, <4 x i32> <i32 64, i32 25, i32 73, i32 81>, <4 x i32> zeroinitializer
+ %u = select <4 x i1> <i1 false, i1 false, i1 true, i1 false>, <4 x i32> <i32 51, i32 41, i32 61, i32 63>, <4 x i32> zeroinitializer
+ %v = select <4 x i1> <i1 true, i1 false, i1 true, i1 false>, <4 x i32> <i32 39, i32 59, i32 17, i32 0>, <4 x i32> zeroinitializer
+ %w = select <4 x i1> <i1 false, i1 true, i1 true, i1 false>, <4 x i32> <i32 91, i32 99, i32 97, i32 29>, <4 x i32> zeroinitializer
+ %x = select <4 x i1> <i1 true, i1 true, i1 true, i1 false>, <4 x i32> <i32 89, i32 45, i32 89, i32 10>, <4 x i32> zeroinitializer
+ %y = select <4 x i1> <i1 false, i1 false, i1 false, i1 true>, <4 x i32> <i32 25, i32 70, i32 21, i32 27>, <4 x i32> zeroinitializer
+ %z = select <4 x i1> <i1 true, i1 false, i1 false, i1 true>, <4 x i32> <i32 40, i32 12, i32 27, i32 88>, <4 x i32> zeroinitializer
+ %ba = select <4 x i1> <i1 false, i1 true, i1 false, i1 true>, <4 x i32> <i32 36, i32 35, i32 90, i32 23>, <4 x i32> zeroinitializer
+ %bb = select <4 x i1> <i1 true, i1 true, i1 false, i1 true>, <4 x i32> <i32 83, i32 3, i32 64, i32 82>, <4 x i32> zeroinitializer
+ %bc = select <4 x i1> <i1 false, i1 false, i1 true, i1 true>, <4 x i32> <i32 15, i32 72, i32 2, i32 54>, <4 x i32> zeroinitializer
+ %bd = select <4 x i1> <i1 true, i1 false, i1 true, i1 true>, <4 x i32> <i32 32, i32 47, i32 100, i32 84>, <4 x i32> zeroinitializer
+ %be = select <4 x i1> <i1 false, i1 true, i1 true, i1 true>, <4 x i32> <i32 92, i32 57, i32 82, i32 1>, <4 x i32> zeroinitializer
+ %bf = select <4 x i1> <i1 true, i1 true, i1 true, i1 true>, <4 x i32> <i32 42, i32 14, i32 22, i32 89>, <4 x i32> zeroinitializer
+ %bg = select <4 x i1> <i1 false, i1 false, i1 false, i1 false>, <4 x i32> <i32 33, i32 10, i32 67, i32 66>, <4 x i32> <i32 42, i32 91, i32 47, i32 40>
+ %bh = select <4 x i1> <i1 true, i1 false, i1 false, i1 false>, <4 x i32> <i32 8, i32 13, i32 48, i32 0>, <4 x i32> <i32 84, i32 66, i32 87, i32 84>
+ %bi = select <4 x i1> <i1 false, i1 true, i1 false, i1 false>, <4 x i32> <i32 85, i32 96, i32 1, i32 94>, <4 x i32> <i32 54, i32 57, i32 7, i32 92>
+ %bj = select <4 x i1> <i1 true, i1 true, i1 false, i1 false>, <4 x i32> <i32 55, i32 21, i32 92, i32 68>, <4 x i32> <i32 51, i32 61, i32 62, i32 39>
+ %bk = select <4 x i1> <i1 false, i1 false, i1 true, i1 false>, <4 x i32> <i32 42, i32 18, i32 77, i32 74>, <4 x i32> <i32 82, i32 33, i32 30, i32 7>
+ %bl = select <4 x i1> <i1 true, i1 false, i1 true, i1 false>, <4 x i32> <i32 80, i32 92, i32 61, i32 84>, <4 x i32> <i32 43, i32 89, i32 92, i32 6>
+ %bm = select <4 x i1> <i1 false, i1 true, i1 true, i1 false>, <4 x i32> <i32 49, i32 14, i32 62, i32 62>, <4 x i32> <i32 35, i32 33, i32 92, i32 59>
+ %bn = select <4 x i1> <i1 true, i1 true, i1 true, i1 false>, <4 x i32> <i32 3, i32 97, i32 49, i32 18>, <4 x i32> <i32 56, i32 64, i32 19, i32 75>
+ %bo = select <4 x i1> <i1 false, i1 false, i1 false, i1 true>, <4 x i32> <i32 91, i32 57, i32 0, i32 1>, <4 x i32> <i32 43, i32 63, i32 64, i32 11>
+ %bp = select <4 x i1> <i1 true, i1 false, i1 false, i1 true>, <4 x i32> <i32 41, i32 65, i32 18, i32 11>, <4 x i32> <i32 86, i32 26, i32 31, i32 3>
+ %bq = select <4 x i1> <i1 false, i1 true, i1 false, i1 true>, <4 x i32> <i32 31, i32 46, i32 32, i32 68>, <4 x i32> <i32 100, i32 59, i32 62, i32 6>
+ %br = select <4 x i1> <i1 true, i1 true, i1 false, i1 true>, <4 x i32> <i32 76, i32 67, i32 87, i32 7>, <4 x i32> <i32 63, i32 48, i32 97, i32 24>
+ %bs = select <4 x i1> <i1 false, i1 false, i1 true, i1 true>, <4 x i32> <i32 83, i32 89, i32 19, i32 4>, <4 x i32> <i32 21, i32 2, i32 40, i32 21>
+ %bt = select <4 x i1> <i1 true, i1 false, i1 true, i1 true>, <4 x i32> <i32 45, i32 76, i32 81, i32 100>, <4 x i32> <i32 65, i32 26, i32 100, i32 46>
+ %bu = select <4 x i1> <i1 false, i1 true, i1 true, i1 true>, <4 x i32> <i32 16, i32 75, i32 31, i32 17>, <4 x i32> <i32 37, i32 66, i32 86, i32 65>
+ %bv = select <4 x i1> <i1 true, i1 true, i1 true, i1 true>, <4 x i32> <i32 13, i32 25, i32 43, i32 59>, <4 x i32> <i32 82, i32 78, i32 60, i32 52>
+ %bw = select <4 x i1> <i1 false, i1 false, i1 false, i1 false>, <4 x i32> zeroinitializer, <4 x i32> zeroinitializer
+ %bx = select <4 x i1> <i1 true, i1 false, i1 false, i1 false>, <4 x i32> zeroinitializer, <4 x i32> zeroinitializer
+ %by = select <4 x i1> <i1 false, i1 true, i1 false, i1 false>, <4 x i32> zeroinitializer, <4 x i32> zeroinitializer
+ %bz = select <4 x i1> <i1 true, i1 true, i1 false, i1 false>, <4 x i32> zeroinitializer, <4 x i32> zeroinitializer
+ %ca = select <4 x i1> <i1 false, i1 false, i1 true, i1 false>, <4 x i32> zeroinitializer, <4 x i32> zeroinitializer
+ %cb = select <4 x i1> <i1 true, i1 false, i1 true, i1 false>, <4 x i32> zeroinitializer, <4 x i32> zeroinitializer
+ %cc = select <4 x i1> <i1 false, i1 true, i1 true, i1 false>, <4 x i32> zeroinitializer, <4 x i32> zeroinitializer
+ %cd = select <4 x i1> <i1 true, i1 true, i1 true, i1 false>, <4 x i32> zeroinitializer, <4 x i32> zeroinitializer
+ %ce = select <4 x i1> <i1 false, i1 false, i1 false, i1 true>, <4 x i32> zeroinitializer, <4 x i32> zeroinitializer
+ %cf = select <4 x i1> <i1 true, i1 false, i1 false, i1 true>, <4 x i32> zeroinitializer, <4 x i32> zeroinitializer
+ %cg = select <4 x i1> <i1 false, i1 true, i1 false, i1 true>, <4 x i32> zeroinitializer, <4 x i32> zeroinitializer
+ %ch = select <4 x i1> <i1 true, i1 true, i1 false, i1 true>, <4 x i32> zeroinitializer, <4 x i32> zeroinitializer
+ %ci = select <4 x i1> <i1 false, i1 false, i1 true, i1 true>, <4 x i32> zeroinitializer, <4 x i32> zeroinitializer
+ %cj = select <4 x i1> <i1 true, i1 false, i1 true, i1 true>, <4 x i32> zeroinitializer, <4 x i32> zeroinitializer
+ %ck = select <4 x i1> <i1 false, i1 true, i1 true, i1 true>, <4 x i32> zeroinitializer, <4 x i32> zeroinitializer
+ %cl = select <4 x i1> <i1 true, i1 true, i1 true, i1 true>, <4 x i32> zeroinitializer, <4 x i32> zeroinitializer
+ store <4 x i32> %a, <4 x i32>* %A
+ store <4 x i32> %b, <4 x i32>* %B
+ store <4 x i32> %c, <4 x i32>* %C
+ store <4 x i32> %d, <4 x i32>* %D
+ store <4 x i32> %e, <4 x i32>* %E
+ store <4 x i32> %f, <4 x i32>* %F
+ store <4 x i32> %g, <4 x i32>* %G
+ store <4 x i32> %h, <4 x i32>* %H
+ store <4 x i32> %i, <4 x i32>* %I
+ store <4 x i32> %j, <4 x i32>* %J
+ store <4 x i32> %k, <4 x i32>* %K
+ store <4 x i32> %l, <4 x i32>* %L
+ store <4 x i32> %m, <4 x i32>* %M
+ store <4 x i32> %n, <4 x i32>* %N
+ store <4 x i32> %o, <4 x i32>* %O
+ store <4 x i32> %p, <4 x i32>* %P
+ store <4 x i32> %q, <4 x i32>* %Q
+ store <4 x i32> %r, <4 x i32>* %R
+ store <4 x i32> %s, <4 x i32>* %S
+ store <4 x i32> %t, <4 x i32>* %T
+ store <4 x i32> %u, <4 x i32>* %U
+ store <4 x i32> %v, <4 x i32>* %V
+ store <4 x i32> %w, <4 x i32>* %W
+ store <4 x i32> %x, <4 x i32>* %X
+ store <4 x i32> %y, <4 x i32>* %Y
+ store <4 x i32> %z, <4 x i32>* %Z
+ store <4 x i32> %ba, <4 x i32>* %BA
+ store <4 x i32> %bb, <4 x i32>* %BB
+ store <4 x i32> %bc, <4 x i32>* %BC
+ store <4 x i32> %bd, <4 x i32>* %BD
+ store <4 x i32> %be, <4 x i32>* %BE
+ store <4 x i32> %bf, <4 x i32>* %BF
+ store <4 x i32> %bg, <4 x i32>* %BG
+ store <4 x i32> %bh, <4 x i32>* %BH
+ store <4 x i32> %bi, <4 x i32>* %BI
+ store <4 x i32> %bj, <4 x i32>* %BJ
+ store <4 x i32> %bk, <4 x i32>* %BK
+ store <4 x i32> %bl, <4 x i32>* %BL
+ store <4 x i32> %bm, <4 x i32>* %BM
+ store <4 x i32> %bn, <4 x i32>* %BN
+ store <4 x i32> %bo, <4 x i32>* %BO
+ store <4 x i32> %bp, <4 x i32>* %BP
+ store <4 x i32> %bq, <4 x i32>* %BQ
+ store <4 x i32> %br, <4 x i32>* %BR
+ store <4 x i32> %bs, <4 x i32>* %BS
+ store <4 x i32> %bt, <4 x i32>* %BT
+ store <4 x i32> %bu, <4 x i32>* %BU
+ store <4 x i32> %bv, <4 x i32>* %BV
+ store <4 x i32> %bw, <4 x i32>* %BW
+ store <4 x i32> %bx, <4 x i32>* %BX
+ store <4 x i32> %by, <4 x i32>* %BY
+ store <4 x i32> %bz, <4 x i32>* %BZ
+ store <4 x i32> %ca, <4 x i32>* %CA
+ store <4 x i32> %cb, <4 x i32>* %CB
+ store <4 x i32> %cc, <4 x i32>* %CC
+ store <4 x i32> %cd, <4 x i32>* %CD
+ store <4 x i32> %ce, <4 x i32>* %CE
+ store <4 x i32> %cf, <4 x i32>* %CF
+ store <4 x i32> %cg, <4 x i32>* %CG
+ store <4 x i32> %ch, <4 x i32>* %CH
+ store <4 x i32> %ci, <4 x i32>* %CI
+ store <4 x i32> %cj, <4 x i32>* %CJ
+ store <4 x i32> %ck, <4 x i32>* %CK
+ store <4 x i32> %cl, <4 x i32>* %CL
+ ret void
+}

Added: llvm/trunk/test/Transforms/InstCombine/fold-vector-zero.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/fold-vector-zero.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/fold-vector-zero.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/fold-vector-zero.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,35 @@
+; RUN: opt < %s -instcombine -S | not grep zeroinitializer
+
+define void @foo(i64 %A, i64 %B) {
+bb8:
+	br label %bb30
+
+bb30:
+	%s0 = phi i64 [ 0, %bb8 ], [ %r21, %bb30 ]
+	%l0 = phi i64 [ -2222, %bb8 ], [ %r23, %bb30 ]
+	%r2 = add i64 %s0, %B
+	%r3 = inttoptr i64 %r2 to <2 x double>*
+	%r4 = load <2 x double>, <2 x double>* %r3, align 8
+	%r6 = bitcast <2 x double> %r4 to <2 x i64>
+	%r7 = bitcast <2 x double> zeroinitializer to <2 x i64>
+	%r8 = insertelement <2 x i64> undef, i64 9223372036854775807, i32 0
+	%r9 = insertelement <2 x i64> undef, i64 -9223372036854775808, i32 0
+	%r10 = insertelement <2 x i64> %r8, i64 9223372036854775807, i32 1
+	%r11 = insertelement <2 x i64> %r9, i64 -9223372036854775808, i32 1
+	%r12 = and <2 x i64> %r6, %r10
+	%r13 = and <2 x i64> %r7, %r11
+	%r14 = or <2 x i64> %r12, %r13
+	%r15 = bitcast <2 x i64> %r14 to <2 x double>
+	%r18 = add i64 %s0, %A
+	%r19 = inttoptr i64 %r18 to <2 x double>*
+	store <2 x double> %r15, <2 x double>* %r19, align 8
+	%r21 = add i64 16, %s0
+	%r23 = add i64 1, %l0
+	%r25 = icmp slt i64 %r23, 0
+	%r26 = zext i1 %r25 to i64
+	%r27 = icmp ne i64 %r26, 0
+	br i1 %r27, label %bb30, label %bb5
+
+bb5:
+	ret void
+}

Added: llvm/trunk/test/Transforms/InstCombine/fp-ret-bitcast.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/fp-ret-bitcast.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/fp-ret-bitcast.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/fp-ret-bitcast.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,28 @@
+; RUN: opt < %s -instcombine -S | \
+; RUN:    grep "call float bitcast" | count 1
+target datalayout = "E-p:64:64:64-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"
+	%struct.NSObject = type { %struct.objc_class* }
+ 	%struct.NSArray = type { %struct.NSObject }
+	%struct.objc_class = type opaque
+ 	%struct.objc_selector = type opaque
+
+@"\01L_OBJC_METH_VAR_NAME_112" = internal global [15 x i8] c"whiteComponent\00", section "__TEXT,__cstring,cstring_literals"
+@"\01L_OBJC_SELECTOR_REFERENCES_81" = internal global %struct.objc_selector* bitcast ([15 x i8]* @"\01L_OBJC_METH_VAR_NAME_112" to %struct.objc_selector*), section "__OBJC,__message_refs,literal_pointers,no_dead_strip"
+
+define void @bork() nounwind  {
+entry:
+	%color = alloca %struct.NSArray*
+	%color.466 = alloca %struct.NSObject*
+	%tmp103 = load %struct.NSArray*, %struct.NSArray** %color, align 4
+	%tmp103104 = getelementptr %struct.NSArray, %struct.NSArray* %tmp103, i32 0, i32 0
+	store %struct.NSObject* %tmp103104, %struct.NSObject** %color.466, align 4
+	%tmp105 = load %struct.objc_selector*, %struct.objc_selector** @"\01L_OBJC_SELECTOR_REFERENCES_81", align 4
+	%tmp106 = load %struct.NSObject*, %struct.NSObject** %color.466, align 4
+	%tmp107 = call float bitcast (void (%struct.NSObject*, ...)* @objc_msgSend_fpret to float (%struct.NSObject*, %struct.objc_selector*)*)( %struct.NSObject* %tmp106, %struct.objc_selector* %tmp105 ) nounwind
+	br label %exit
+
+exit:
+	ret void
+}
+
+declare void @objc_msgSend_fpret(%struct.NSObject*, ...)

Added: llvm/trunk/test/Transforms/InstCombine/fpcast.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/fpcast.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/fpcast.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/fpcast.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,125 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; Test some floating point casting cases
+; RUN: opt < %s -instcombine -S | FileCheck %s
+
+define i8 @test1() {
+; CHECK-LABEL: @test1(
+; CHECK-NEXT:    ret i8 -1
+;
+  %x = fptoui float 2.550000e+02 to i8
+  ret i8 %x
+}
+
+define i8 @test2() {
+; CHECK-LABEL: @test2(
+; CHECK-NEXT:    ret i8 -1
+;
+  %x = fptosi float -1.000000e+00 to i8
+  ret i8 %x
+}
+
+define half @test3(float %a) {
+; CHECK-LABEL: @test3(
+; CHECK-NEXT:    [[TMP1:%.*]] = fptrunc float [[A:%.*]] to half
+; CHECK-NEXT:    [[C:%.*]] = call half @llvm.fabs.f16(half [[TMP1]])
+; CHECK-NEXT:    ret half [[C]]
+;
+  %b = call float @llvm.fabs.f32(float %a)
+  %c = fptrunc float %b to half
+  ret half %c
+}
+
+define half @fneg_fptrunc(float %a) {
+; CHECK-LABEL: @fneg_fptrunc(
+; CHECK-NEXT:    [[TMP1:%.*]] = fptrunc float [[A:%.*]] to half
+; CHECK-NEXT:    [[C:%.*]] = fsub half 0xH8000, [[TMP1]]
+; CHECK-NEXT:    ret half [[C]]
+;
+  %b = fsub float -0.0, %a
+  %c = fptrunc float %b to half
+  ret half %c
+}
+
+define <2 x half> @fneg_fptrunc_vec_undef(<2 x float> %a) {
+; CHECK-LABEL: @fneg_fptrunc_vec_undef(
+; CHECK-NEXT:    [[TMP1:%.*]] = fptrunc <2 x float> [[A:%.*]] to <2 x half>
+; CHECK-NEXT:    [[C:%.*]] = fsub <2 x half> <half 0xH8000, half 0xH8000>, [[TMP1]]
+; CHECK-NEXT:    ret <2 x half> [[C]]
+;
+  %b = fsub <2 x float> <float -0.0, float undef>, %a
+  %c = fptrunc <2 x float> %b to <2 x half>
+  ret <2 x half> %c
+}
+
+define half @test4-fast(float %a) {
+; CHECK-LABEL: @test4-fast(
+; CHECK-NEXT:    [[TMP1:%.*]] = fptrunc float [[A:%.*]] to half
+; CHECK-NEXT:    [[C:%.*]] = fsub fast half 0xH8000, [[TMP1]]
+; CHECK-NEXT:    ret half [[C]]
+;
+  %b = fsub fast float -0.0, %a
+  %c = fptrunc float %b to half
+  ret half %c
+}
+
+define half @test5(float %a, float %b, float %c) {
+; CHECK-LABEL: @test5(
+; CHECK-NEXT:    [[D:%.*]] = fcmp ogt float [[A:%.*]], [[B:%.*]]
+; CHECK-NEXT:    [[E:%.*]] = select i1 [[D]], float [[C:%.*]], float 1.000000e+00
+; CHECK-NEXT:    [[F:%.*]] = fptrunc float [[E]] to half
+; CHECK-NEXT:    ret half [[F]]
+;
+  %d = fcmp ogt float %a, %b
+  %e = select i1 %d, float %c, float 1.0
+  %f = fptrunc float %e to half
+  ret half %f
+}
+
+declare float @llvm.fabs.f32(float) nounwind readonly
+
+define <1 x float> @test6(<1 x double> %V) {
+; CHECK-LABEL: @test6(
+; CHECK-NEXT:    [[FREM:%.*]] = frem <1 x double> [[V:%.*]], [[V]]
+; CHECK-NEXT:    [[TRUNC:%.*]] = fptrunc <1 x double> [[FREM]] to <1 x float>
+; CHECK-NEXT:    ret <1 x float> [[TRUNC]]
+;
+  %frem = frem <1 x double> %V, %V
+  %trunc = fptrunc <1 x double> %frem to <1 x float>
+  ret <1 x float> %trunc
+}
+
+define float @test7(double %V) {
+; CHECK-LABEL: @test7(
+; CHECK-NEXT:    [[FREM:%.*]] = frem double [[V:%.*]], 1.000000e+00
+; CHECK-NEXT:    [[TRUNC:%.*]] = fptrunc double [[FREM]] to float
+; CHECK-NEXT:    ret float [[TRUNC]]
+;
+  %frem = frem double %V, 1.000000e+00
+  %trunc = fptrunc double %frem to float
+  ret float %trunc
+}
+
+define float @test8(float %V) {
+; CHECK-LABEL: @test8(
+; CHECK-NEXT:    [[FEXT:%.*]] = fpext float [[V:%.*]] to double
+; CHECK-NEXT:    [[FREM:%.*]] = frem double [[FEXT]], 1.000000e-01
+; CHECK-NEXT:    [[TRUNC:%.*]] = fptrunc double [[FREM]] to float
+; CHECK-NEXT:    ret float [[TRUNC]]
+;
+  %fext = fpext float %V to double
+  %frem = frem double %fext, 1.000000e-01
+  %trunc = fptrunc double %frem to float
+  ret float %trunc
+}
+
+define half @test_fptrunc_fptrunc(double %V) {
+; CHECK-LABEL: @test_fptrunc_fptrunc(
+; CHECK-NEXT:    [[T1:%.*]] = fptrunc double [[V:%.*]] to float
+; CHECK-NEXT:    [[T2:%.*]] = fptrunc float [[T1]] to half
+; CHECK-NEXT:    ret half [[T2]]
+;
+  %t1 = fptrunc double %V to float
+  %t2 = fptrunc float %t1 to half
+  ret half %t2
+}
+

Added: llvm/trunk/test/Transforms/InstCombine/fpextend.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/fpextend.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/fpextend.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/fpextend.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,283 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt < %s -instcombine -S | FileCheck %s
+
+define float @test(float %x) nounwind  {
+; CHECK-LABEL: @test(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[TMP34:%.*]] = fadd float [[X:%.*]], 0.000000e+00
+; CHECK-NEXT:    ret float [[TMP34]]
+;
+entry:
+  %tmp1 = fpext float %x to double
+  %tmp3 = fadd double %tmp1, 0.000000e+00
+  %tmp34 = fptrunc double %tmp3 to float
+  ret float %tmp34
+}
+
+define float @test2(float %x, float %y) nounwind  {
+; CHECK-LABEL: @test2(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[TMP56:%.*]] = fmul float [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    ret float [[TMP56]]
+;
+entry:
+  %tmp1 = fpext float %x to double
+  %tmp23 = fpext float %y to double
+  %tmp5 = fmul double %tmp1, %tmp23
+  %tmp56 = fptrunc double %tmp5 to float
+  ret float %tmp56
+}
+
+define float @test3(float %x, float %y) nounwind  {
+; CHECK-LABEL: @test3(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[TMP56:%.*]] = fdiv float [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    ret float [[TMP56]]
+;
+entry:
+  %tmp1 = fpext float %x to double
+  %tmp23 = fpext float %y to double
+  %tmp5 = fdiv double %tmp1, %tmp23
+  %tmp56 = fptrunc double %tmp5 to float
+  ret float %tmp56
+}
+
+define float @test4(float %x) nounwind  {
+; CHECK-LABEL: @test4(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[TMP34:%.*]] = fsub float -0.000000e+00, [[X:%.*]]
+; CHECK-NEXT:    ret float [[TMP34]]
+;
+entry:
+  %tmp1 = fpext float %x to double
+  %tmp2 = fsub double -0.000000e+00, %tmp1
+  %tmp34 = fptrunc double %tmp2 to float
+  ret float %tmp34
+}
+
+; Test with vector splat constant
+define <2 x float> @test5(<2 x float> %x) nounwind  {
+; CHECK-LABEL: @test5(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[TMP34:%.*]] = fadd <2 x float> [[X:%.*]], zeroinitializer
+; CHECK-NEXT:    ret <2 x float> [[TMP34]]
+;
+entry:
+  %tmp1 = fpext <2 x float> %x to <2 x double>
+  %tmp3 = fadd <2 x double> %tmp1, <double 0.000000e+00, double 0.000000e+00>
+  %tmp34 = fptrunc <2 x double> %tmp3 to <2 x float>
+  ret <2 x float> %tmp34
+}
+
+; Test with a non-splat constant
+define <2 x float> @test6(<2 x float> %x) nounwind  {
+; CHECK-LABEL: @test6(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[TMP34:%.*]] = fadd <2 x float> [[X:%.*]], <float 0.000000e+00, float -0.000000e+00>
+; CHECK-NEXT:    ret <2 x float> [[TMP34]]
+;
+entry:
+  %tmp1 = fpext <2 x float> %x to <2 x double>
+  %tmp3 = fadd <2 x double> %tmp1, <double 0.000000e+00, double -0.000000e+00>
+  %tmp34 = fptrunc <2 x double> %tmp3 to <2 x float>
+  ret <2 x float> %tmp34
+}
+
+; Test with an undef element
+; TODO: Support undef elements.
+define <2 x float> @test6_undef(<2 x float> %x) nounwind  {
+; CHECK-LABEL: @test6_undef(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[TMP1:%.*]] = fpext <2 x float> [[X:%.*]] to <2 x double>
+; CHECK-NEXT:    [[TMP3:%.*]] = fadd <2 x double> [[TMP1]], <double 0.000000e+00, double undef>
+; CHECK-NEXT:    [[TMP34:%.*]] = fptrunc <2 x double> [[TMP3]] to <2 x float>
+; CHECK-NEXT:    ret <2 x float> [[TMP34]]
+;
+entry:
+  %tmp1 = fpext <2 x float> %x to <2 x double>
+  %tmp3 = fadd <2 x double> %tmp1, <double 0.000000e+00, double undef>
+  %tmp34 = fptrunc <2 x double> %tmp3 to <2 x float>
+  ret <2 x float> %tmp34
+}
+
+define <2 x float> @not_half_shrinkable(<2 x float> %x) {
+; CHECK-LABEL: @not_half_shrinkable(
+; CHECK-NEXT:    [[R:%.*]] = fadd <2 x float> [[X:%.*]], <float 0.000000e+00, float 2.049000e+03>
+; CHECK-NEXT:    ret <2 x float> [[R]]
+;
+  %ext = fpext <2 x float> %x to <2 x double>
+  %add = fadd <2 x double> %ext, <double 0.0, double 2049.0>
+  %r = fptrunc <2 x double> %add to <2 x float>
+  ret <2 x float>  %r
+}
+
+define half @test7(float %a) nounwind {
+; CHECK-LABEL: @test7(
+; CHECK-NEXT:    [[Z:%.*]] = fptrunc float [[A:%.*]] to half
+; CHECK-NEXT:    ret half [[Z]]
+;
+  %y = fpext float %a to double
+  %z = fptrunc double %y to half
+  ret half %z
+}
+
+define float @test8(half %a) nounwind {
+; CHECK-LABEL: @test8(
+; CHECK-NEXT:    [[Z:%.*]] = fpext half [[A:%.*]] to float
+; CHECK-NEXT:    ret float [[Z]]
+;
+  %y = fpext half %a to double
+  %z = fptrunc double %y to float
+  ret float %z
+}
+
+define float @test9(half %x, half %y) nounwind  {
+; CHECK-LABEL: @test9(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[TMP0:%.*]] = fpext half [[X:%.*]] to float
+; CHECK-NEXT:    [[TMP1:%.*]] = fpext half [[Y:%.*]] to float
+; CHECK-NEXT:    [[TMP56:%.*]] = fmul float [[TMP0]], [[TMP1]]
+; CHECK-NEXT:    ret float [[TMP56]]
+;
+entry:
+  %tmp1 = fpext half %x to double
+  %tmp23 = fpext half %y to double
+  %tmp5 = fmul double %tmp1, %tmp23
+  %tmp56 = fptrunc double %tmp5 to float
+  ret float %tmp56
+}
+
+define float @test10(half %x, float %y) nounwind  {
+; CHECK-LABEL: @test10(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[TMP0:%.*]] = fpext half [[X:%.*]] to float
+; CHECK-NEXT:    [[TMP56:%.*]] = fmul float [[TMP0]], [[Y:%.*]]
+; CHECK-NEXT:    ret float [[TMP56]]
+;
+entry:
+  %tmp1 = fpext half %x to double
+  %tmp23 = fpext float %y to double
+  %tmp5 = fmul double %tmp1, %tmp23
+  %tmp56 = fptrunc double %tmp5 to float
+  ret float %tmp56
+}
+
+define float @test11(half %x) nounwind  {
+; CHECK-LABEL: @test11(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[TMP0:%.*]] = fpext half [[X:%.*]] to float
+; CHECK-NEXT:    [[TMP34:%.*]] = fadd float [[TMP0]], 0.000000e+00
+; CHECK-NEXT:    ret float [[TMP34]]
+;
+entry:
+  %tmp1 = fpext half %x to double
+  %tmp3 = fadd double %tmp1, 0.000000e+00
+  %tmp34 = fptrunc double %tmp3 to float
+  ret float %tmp34
+}
+
+define float @test12(float %x, half %y) nounwind  {
+; CHECK-LABEL: @test12(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[TMP0:%.*]] = fpext half [[Y:%.*]] to float
+; CHECK-NEXT:    [[TMP34:%.*]] = fadd float [[TMP0]], [[X:%.*]]
+; CHECK-NEXT:    ret float [[TMP34]]
+;
+entry:
+  %tmp1 = fpext float %x to double
+  %tmp2 = fpext half %y to double
+  %tmp3 = fadd double %tmp1, %tmp2
+  %tmp34 = fptrunc double %tmp3 to float
+  ret float %tmp34
+}
+
+define float @test13(half %x, float %y) nounwind  {
+; CHECK-LABEL: @test13(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[TMP0:%.*]] = fpext half [[X:%.*]] to float
+; CHECK-NEXT:    [[TMP56:%.*]] = fdiv float [[TMP0]], [[Y:%.*]]
+; CHECK-NEXT:    ret float [[TMP56]]
+;
+entry:
+  %tmp1 = fpext half %x to double
+  %tmp23 = fpext float %y to double
+  %tmp5 = fdiv double %tmp1, %tmp23
+  %tmp56 = fptrunc double %tmp5 to float
+  ret float %tmp56
+}
+
+define float @test14(float %x, half %y) nounwind  {
+; CHECK-LABEL: @test14(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[TMP0:%.*]] = fpext half [[Y:%.*]] to float
+; CHECK-NEXT:    [[TMP56:%.*]] = fdiv float [[X:%.*]], [[TMP0]]
+; CHECK-NEXT:    ret float [[TMP56]]
+;
+entry:
+  %tmp1 = fpext float %x to double
+  %tmp23 = fpext half %y to double
+  %tmp5 = fdiv double %tmp1, %tmp23
+  %tmp56 = fptrunc double %tmp5 to float
+  ret float %tmp56
+}
+
+define float @test15(half %x, half %y) nounwind  {
+; CHECK-LABEL: @test15(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[TMP0:%.*]] = fpext half [[X:%.*]] to float
+; CHECK-NEXT:    [[TMP1:%.*]] = fpext half [[Y:%.*]] to float
+; CHECK-NEXT:    [[TMP56:%.*]] = fdiv float [[TMP0]], [[TMP1]]
+; CHECK-NEXT:    ret float [[TMP56]]
+;
+entry:
+  %tmp1 = fpext half %x to double
+  %tmp23 = fpext half %y to double
+  %tmp5 = fdiv double %tmp1, %tmp23
+  %tmp56 = fptrunc double %tmp5 to float
+  ret float %tmp56
+}
+
+define float @test16(half %x, float %y) nounwind  {
+; CHECK-LABEL: @test16(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[TMP0:%.*]] = fpext half [[X:%.*]] to float
+; CHECK-NEXT:    [[TMP1:%.*]] = frem float [[TMP0]], [[Y:%.*]]
+; CHECK-NEXT:    ret float [[TMP1]]
+;
+entry:
+  %tmp1 = fpext half %x to double
+  %tmp23 = fpext float %y to double
+  %tmp5 = frem double %tmp1, %tmp23
+  %tmp56 = fptrunc double %tmp5 to float
+  ret float %tmp56
+}
+
+define float @test17(float %x, half %y) nounwind  {
+; CHECK-LABEL: @test17(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[TMP0:%.*]] = fpext half [[Y:%.*]] to float
+; CHECK-NEXT:    [[TMP1:%.*]] = frem float [[X:%.*]], [[TMP0]]
+; CHECK-NEXT:    ret float [[TMP1]]
+;
+entry:
+  %tmp1 = fpext float %x to double
+  %tmp23 = fpext half %y to double
+  %tmp5 = frem double %tmp1, %tmp23
+  %tmp56 = fptrunc double %tmp5 to float
+  ret float %tmp56
+}
+
+define float @test18(half %x, half %y) nounwind  {
+; CHECK-LABEL: @test18(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[TMP0:%.*]] = frem half [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    [[TMP56:%.*]] = fpext half [[TMP0]] to float
+; CHECK-NEXT:    ret float [[TMP56]]
+;
+entry:
+  %tmp1 = fpext half %x to double
+  %tmp23 = fpext half %y to double
+  %tmp5 = frem double %tmp1, %tmp23
+  %tmp56 = fptrunc double %tmp5 to float
+  ret float %tmp56
+}

Added: llvm/trunk/test/Transforms/InstCombine/fpextend_x86.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/fpextend_x86.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/fpextend_x86.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/fpextend_x86.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,57 @@
+; RUN: opt < %s -instcombine -mtriple=x86_64-apple-macosx -S | FileCheck %s
+target triple = "x86_64-apple-macosx"
+
+define double @test1(double %a, double %b) nounwind {
+  %wa = fpext double %a to x86_fp80
+  %wb = fpext double %b to x86_fp80
+  %wr = fadd x86_fp80 %wa, %wb
+  %r = fptrunc x86_fp80 %wr to double
+  ret double %r
+; CHECK: test1
+; CHECK: fadd x86_fp80
+; CHECK: ret
+}
+
+define double @test2(double %a, double %b) nounwind {
+  %wa = fpext double %a to x86_fp80
+  %wb = fpext double %b to x86_fp80
+  %wr = fsub x86_fp80 %wa, %wb
+  %r = fptrunc x86_fp80 %wr to double
+  ret double %r
+; CHECK: test2
+; CHECK: fsub x86_fp80
+; CHECK: ret
+}
+
+define double @test3(double %a, double %b) nounwind {
+  %wa = fpext double %a to x86_fp80
+  %wb = fpext double %b to x86_fp80
+  %wr = fmul x86_fp80 %wa, %wb
+  %r = fptrunc x86_fp80 %wr to double
+  ret double %r
+; CHECK: test3
+; CHECK: fmul x86_fp80
+; CHECK: ret
+}
+
+define double @test4(double %a, half %b) nounwind {
+  %wa = fpext double %a to x86_fp80
+  %wb = fpext half %b to x86_fp80
+  %wr = fmul x86_fp80 %wa, %wb
+  %r = fptrunc x86_fp80 %wr to double
+  ret double %r
+; CHECK: test4
+; CHECK: fmul double
+; CHECK: ret
+}
+
+define double @test5(double %a, double %b) nounwind {
+  %wa = fpext double %a to x86_fp80
+  %wb = fpext double %b to x86_fp80
+  %wr = fdiv x86_fp80 %wa, %wb
+  %r = fptrunc x86_fp80 %wr to double
+  ret double %r
+; CHECK: test5
+; CHECK: fdiv x86_fp80
+; CHECK: ret
+}

Added: llvm/trunk/test/Transforms/InstCombine/fprintf-1.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/fprintf-1.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/fprintf-1.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/fprintf-1.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,98 @@
+; Test that the fprintf library call simplifier works correctly.
+;
+; RUN: opt < %s -instcombine -S | FileCheck %s
+; RUN: opt < %s -mtriple xcore-xmos-elf -instcombine -S | FileCheck %s -check-prefix=CHECK-IPRINTF
+
+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"
+
+%FILE = type { }
+
+ at hello_world = constant [13 x i8] c"hello world\0A\00"
+ at percent_c = constant [3 x i8] c"%c\00"
+ at percent_d = constant [3 x i8] c"%d\00"
+ at percent_f = constant [3 x i8] c"%f\00"
+ at percent_s = constant [3 x i8] c"%s\00"
+
+declare i32 @fprintf(%FILE*, i8*, ...)
+
+; Check fprintf(fp, "foo") -> fwrite("foo", 3, 1, fp).
+
+define void @test_simplify1(%FILE* %fp) {
+; CHECK-LABEL: @test_simplify1(
+  %fmt = getelementptr [13 x i8], [13 x i8]* @hello_world, i32 0, i32 0
+  call i32 (%FILE*, i8*, ...) @fprintf(%FILE* %fp, i8* %fmt)
+; CHECK-NEXT: call i32 @fwrite(i8* getelementptr inbounds ([13 x i8], [13 x i8]* @hello_world, i32 0, i32 0), i32 12, i32 1, %FILE* %fp)
+  ret void
+; CHECK-NEXT: ret void
+}
+
+; Check fprintf(fp, "%c", chr) -> fputc(chr, fp).
+
+define void @test_simplify2(%FILE* %fp) {
+; CHECK-LABEL: @test_simplify2(
+  %fmt = getelementptr [3 x i8], [3 x i8]* @percent_c, i32 0, i32 0
+  call i32 (%FILE*, i8*, ...) @fprintf(%FILE* %fp, i8* %fmt, i8 104)
+; CHECK-NEXT: call i32 @fputc(i32 104, %FILE* %fp)
+  ret void
+; CHECK-NEXT: ret void
+}
+
+; Check fprintf(fp, "%s", str) -> fputs(str, fp).
+; NOTE: The fputs simplifier simplifies this further to fwrite.
+
+define void @test_simplify3(%FILE* %fp) {
+; CHECK-LABEL: @test_simplify3(
+  %fmt = getelementptr [3 x i8], [3 x i8]* @percent_s, i32 0, i32 0
+  %str = getelementptr [13 x i8], [13 x i8]* @hello_world, i32 0, i32 0
+  call i32 (%FILE*, i8*, ...) @fprintf(%FILE* %fp, i8* %fmt, i8* %str)
+; CHECK-NEXT: call i32 @fwrite(i8* getelementptr inbounds ([13 x i8], [13 x i8]* @hello_world, i32 0, i32 0), i32 12, i32 1, %FILE* %fp)
+  ret void
+; CHECK-NEXT: ret void
+}
+
+; Check fprintf(fp, fmt, ...) -> fiprintf(fp, fmt, ...) if no floating point.
+
+define void @test_simplify4(%FILE* %fp) {
+; CHECK-IPRINTF-LABEL: @test_simplify4(
+  %fmt = getelementptr [3 x i8], [3 x i8]* @percent_d, i32 0, i32 0
+  call i32 (%FILE*, i8*, ...) @fprintf(%FILE* %fp, i8* %fmt, i32 187)
+; CHECK-IPRINTF-NEXT: call i32 (%FILE*, i8*, ...) @fiprintf(%FILE* %fp, i8* getelementptr inbounds ([3 x i8], [3 x i8]* @percent_d, i32 0, i32 0), i32 187)
+  ret void
+; CHECK-IPRINTF-NEXT: ret void
+}
+
+define void @test_simplify5(%FILE* %fp) {
+; CHECK-LABEL: @test_simplify5(
+  %fmt = getelementptr [13 x i8], [13 x i8]* @hello_world, i32 0, i32 0
+  call i32 (%FILE*, i8*, ...) @fprintf(%FILE* %fp, i8* %fmt) [ "deopt"() ]
+; CHECK-NEXT: call i32 @fwrite(i8* getelementptr inbounds ([13 x i8], [13 x i8]* @hello_world, i32 0, i32 0), i32 12, i32 1, %FILE* %fp) [ "deopt"() ]
+  ret void
+; CHECK-NEXT: ret void
+}
+
+define void @test_no_simplify1(%FILE* %fp) {
+; CHECK-IPRINTF-LABEL: @test_no_simplify1(
+  %fmt = getelementptr [3 x i8], [3 x i8]* @percent_f, i32 0, i32 0
+  call i32 (%FILE*, i8*, ...) @fprintf(%FILE* %fp, i8* %fmt, double 1.87)
+; CHECK-IPRINTF-NEXT: call i32 (%FILE*, i8*, ...) @fprintf(%FILE* %fp, i8* getelementptr inbounds ([3 x i8], [3 x i8]* @percent_f, i32 0, i32 0), double 1.870000e+00)
+  ret void
+; CHECK-IPRINTF-NEXT: ret void
+}
+
+define void @test_no_simplify2(%FILE* %fp, double %d) {
+; CHECK-LABEL: @test_no_simplify2(
+  %fmt = getelementptr [3 x i8], [3 x i8]* @percent_f, i32 0, i32 0
+  call i32 (%FILE*, i8*, ...) @fprintf(%FILE* %fp, i8* %fmt, double %d)
+; CHECK-NEXT: call i32 (%FILE*, i8*, ...) @fprintf(%FILE* %fp, i8* getelementptr inbounds ([3 x i8], [3 x i8]* @percent_f, i32 0, i32 0), double %d)
+  ret void
+; CHECK-NEXT: ret void
+}
+
+define i32 @test_no_simplify3(%FILE* %fp) {
+; CHECK-LABEL: @test_no_simplify3(
+  %fmt = getelementptr [13 x i8], [13 x i8]* @hello_world, i32 0, i32 0
+  %1 = call i32 (%FILE*, i8*, ...) @fprintf(%FILE* %fp, i8* %fmt)
+; CHECK-NEXT: call i32 (%FILE*, i8*, ...) @fprintf(%FILE* %fp, i8* getelementptr inbounds ([13 x i8], [13 x i8]* @hello_world, i32 0, i32 0))
+  ret i32 %1
+; CHECK-NEXT: ret i32 %1
+}

Added: llvm/trunk/test/Transforms/InstCombine/fputs-1.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/fputs-1.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/fputs-1.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/fputs-1.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,43 @@
+; Test that the fputs 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"
+
+%FILE = type { }
+
+ at empty = constant [1 x i8] zeroinitializer
+ at A = constant [2 x i8] c"A\00"
+ at hello = constant [7 x i8] c"hello\0A\00"
+
+declare i32 @fputs(i8*, %FILE*)
+
+; Check fputs(str, fp) --> fwrite(str, strlen(s), 1, fp).
+
+define void @test_simplify1(%FILE* %fp) {
+; CHECK-LABEL: @test_simplify1(
+  %str = getelementptr [1 x i8], [1 x i8]* @empty, i32 0, i32 0
+  call i32 @fputs(i8* %str, %FILE* %fp)
+  ret void
+; CHECK-NEXT: ret void
+}
+
+; NOTE: The fwrite simplifier simplifies this further to fputc.
+
+define void @test_simplify2(%FILE* %fp) {
+; CHECK-LABEL: @test_simplify2(
+  %str = getelementptr [2 x i8], [2 x i8]* @A, i32 0, i32 0
+  call i32 @fputs(i8* %str, %FILE* %fp)
+; CHECK-NEXT: call i32 @fputc(i32 65, %FILE* %fp)
+  ret void
+; CHECK-NEXT: ret void
+}
+
+define void @test_simplify3(%FILE* %fp) {
+; CHECK-LABEL: @test_simplify3(
+  %str = getelementptr [7 x i8], [7 x i8]* @hello, i32 0, i32 0
+  call i32 @fputs(i8* %str, %FILE* %fp)
+; CHECK-NEXT: call i32 @fwrite(i8* getelementptr inbounds ([7 x i8], [7 x i8]* @hello, i32 0, i32 0), i32 6, i32 1, %FILE* %fp)
+  ret void
+; CHECK-NEXT: ret void
+}

Added: llvm/trunk/test/Transforms/InstCombine/fputs-opt-size.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/fputs-opt-size.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/fputs-opt-size.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/fputs-opt-size.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,61 @@
+; When optimising for size, we don't want to rewrite fputs to fwrite
+; because it requires more arguments and thus extra MOVs are required.
+;
+; RUN: opt < %s -instcombine -S | FileCheck %s
+; RUN: opt < %s -instcombine -pgso -S | FileCheck %s -check-prefix=PGSO
+; RUN: opt < %s -instcombine -pgso=false -S | FileCheck %s -check-prefix=NPGSO
+
+%struct._IO_FILE = type { i32, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i8*, %struct._IO_marker*, %struct._IO_FILE*, i32, i32, i32, i16, i8, [1 x i8], i8*, i64, i8*, i8*, i8*, i8*, i32, i32, [40 x i8] }
+%struct._IO_marker = type { %struct._IO_marker*, %struct._IO_FILE*, i32 }
+
+ at .str = private unnamed_addr constant [10 x i8] c"mylog.txt\00", align 1
+ at .str.1 = private unnamed_addr constant [2 x i8] c"a\00", align 1
+ at .str.2 = private unnamed_addr constant [27 x i8] c"Hello world this is a test\00", align 1
+
+define i32 @main() local_unnamed_addr #0 {
+entry:
+; CHECK-LABEL: @main(
+; CHECK-NOT: call i64 @fwrite
+; CHECK: call i32 @fputs
+
+  %call = tail call %struct._IO_FILE* @fopen(i8* getelementptr inbounds ([10 x i8], [10 x i8]* @.str, i32 0, i32 0), i8* getelementptr inbounds ([2 x i8], [2 x i8]* @.str.1, i32 0, i32 0)) #2
+  %call1 = tail call i32 @fputs(i8* getelementptr inbounds ([27 x i8], [27 x i8]* @.str.2, i32 0, i32 0), %struct._IO_FILE* %call) #2
+  ret i32 0
+}
+
+declare noalias %struct._IO_FILE* @fopen(i8* nocapture readonly, i8* nocapture readonly) local_unnamed_addr #1
+declare i32 @fputs(i8* nocapture readonly, %struct._IO_FILE* nocapture) local_unnamed_addr #1
+
+attributes #0 = { nounwind optsize }
+attributes #1 = { nounwind optsize  }
+
+define i32 @main_pgso() local_unnamed_addr !prof !14 {
+entry:
+; PGSO-LABEL: @main_pgso(
+; PGSO-NOT: call i64 @fwrite
+; PGSO: call i32 @fputs
+; NPGSO-LABEL: @main_pgso(
+; NPGSO: call i64 @fwrite
+; NPGSO-NOT: call i32 @fputs
+
+  %call = tail call %struct._IO_FILE* @fopen(i8* getelementptr inbounds ([10 x i8], [10 x i8]* @.str, i32 0, i32 0), i8* getelementptr inbounds ([2 x i8], [2 x i8]* @.str.1, i32 0, i32 0)) #2
+  %call1 = tail call i32 @fputs(i8* getelementptr inbounds ([27 x i8], [27 x i8]* @.str.2, i32 0, i32 0), %struct._IO_FILE* %call) #2
+  ret i32 0
+}
+
+!llvm.module.flags = !{!0}
+!0 = !{i32 1, !"ProfileSummary", !1}
+!1 = !{!2, !3, !4, !5, !6, !7, !8, !9}
+!2 = !{!"ProfileFormat", !"InstrProf"}
+!3 = !{!"TotalCount", i64 10000}
+!4 = !{!"MaxCount", i64 10}
+!5 = !{!"MaxInternalCount", i64 1}
+!6 = !{!"MaxFunctionCount", i64 1000}
+!7 = !{!"NumCounts", i64 3}
+!8 = !{!"NumFunctions", i64 3}
+!9 = !{!"DetailedSummary", !10}
+!10 = !{!11, !12, !13}
+!11 = !{i32 10000, i64 100, i32 1}
+!12 = !{i32 999000, i64 100, i32 1}
+!13 = !{i32 999999, i64 1, i32 2}
+!14 = !{!"function_entry_count", i64 0}

Added: llvm/trunk/test/Transforms/InstCombine/fsh.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/fsh.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/fsh.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/fsh.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,638 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt < %s -instcombine -S | FileCheck %s
+
+declare i32 @llvm.fshl.i32(i32, i32, i32)
+declare i33 @llvm.fshr.i33(i33, i33, i33)
+declare <2 x i32> @llvm.fshr.v2i32(<2 x i32>, <2 x i32>, <2 x i32>)
+declare <2 x i31> @llvm.fshl.v2i31(<2 x i31>, <2 x i31>, <2 x i31>)
+
+; If the shift mask doesn't include any demanded bits, the funnel shift can be eliminated.
+
+define i32 @fshl_mask_simplify1(i32 %x, i32 %y, i32 %sh) {
+; CHECK-LABEL: @fshl_mask_simplify1(
+; CHECK-NEXT:    ret i32 [[X:%.*]]
+;
+  %maskedsh = and i32 %sh, 32
+  %r = call i32 @llvm.fshl.i32(i32 %x, i32 %y, i32 %maskedsh)
+  ret i32 %r
+}
+
+define <2 x i32> @fshr_mask_simplify2(<2 x i32> %x, <2 x i32> %y, <2 x i32> %sh) {
+; CHECK-LABEL: @fshr_mask_simplify2(
+; CHECK-NEXT:    ret <2 x i32> [[Y:%.*]]
+;
+  %maskedsh = and <2 x i32> %sh, <i32 64, i32 64>
+  %r = call <2 x i32> @llvm.fshr.v2i32(<2 x i32> %x, <2 x i32> %y, <2 x i32> %maskedsh)
+  ret <2 x i32> %r
+}
+
+; Negative test.
+
+define i32 @fshl_mask_simplify3(i32 %x, i32 %y, i32 %sh) {
+; CHECK-LABEL: @fshl_mask_simplify3(
+; CHECK-NEXT:    [[MASKEDSH:%.*]] = and i32 [[SH:%.*]], 16
+; CHECK-NEXT:    [[R:%.*]] = call i32 @llvm.fshl.i32(i32 [[X:%.*]], i32 [[Y:%.*]], i32 [[MASKEDSH]])
+; CHECK-NEXT:    ret i32 [[R]]
+;
+  %maskedsh = and i32 %sh, 16
+  %r = call i32 @llvm.fshl.i32(i32 %x, i32 %y, i32 %maskedsh)
+  ret i32 %r
+}
+
+; Check again with weird bitwidths - the analysis is invalid with non-power-of-2.
+
+define i33 @fshr_mask_simplify1(i33 %x, i33 %y, i33 %sh) {
+; CHECK-LABEL: @fshr_mask_simplify1(
+; CHECK-NEXT:    [[MASKEDSH:%.*]] = and i33 [[SH:%.*]], 64
+; CHECK-NEXT:    [[R:%.*]] = call i33 @llvm.fshr.i33(i33 [[X:%.*]], i33 [[Y:%.*]], i33 [[MASKEDSH]])
+; CHECK-NEXT:    ret i33 [[R]]
+;
+  %maskedsh = and i33 %sh, 64
+  %r = call i33 @llvm.fshr.i33(i33 %x, i33 %y, i33 %maskedsh)
+  ret i33 %r
+}
+
+; Check again with weird bitwidths - the analysis is invalid with non-power-of-2.
+
+define <2 x i31> @fshl_mask_simplify2(<2 x i31> %x, <2 x i31> %y, <2 x i31> %sh) {
+; CHECK-LABEL: @fshl_mask_simplify2(
+; CHECK-NEXT:    [[MASKEDSH:%.*]] = and <2 x i31> [[SH:%.*]], <i31 32, i31 32>
+; CHECK-NEXT:    [[R:%.*]] = call <2 x i31> @llvm.fshl.v2i31(<2 x i31> [[X:%.*]], <2 x i31> [[Y:%.*]], <2 x i31> [[MASKEDSH]])
+; CHECK-NEXT:    ret <2 x i31> [[R]]
+;
+  %maskedsh = and <2 x i31> %sh, <i31 32, i31 32>
+  %r = call <2 x i31> @llvm.fshl.v2i31(<2 x i31> %x, <2 x i31> %y, <2 x i31> %maskedsh)
+  ret <2 x i31> %r
+}
+
+; Check again with weird bitwidths - the analysis is invalid with non-power-of-2.
+
+define i33 @fshr_mask_simplify3(i33 %x, i33 %y, i33 %sh) {
+; CHECK-LABEL: @fshr_mask_simplify3(
+; CHECK-NEXT:    [[MASKEDSH:%.*]] = and i33 [[SH:%.*]], 32
+; CHECK-NEXT:    [[R:%.*]] = call i33 @llvm.fshr.i33(i33 [[X:%.*]], i33 [[Y:%.*]], i33 [[MASKEDSH]])
+; CHECK-NEXT:    ret i33 [[R]]
+;
+  %maskedsh = and i33 %sh, 32
+  %r = call i33 @llvm.fshr.i33(i33 %x, i33 %y, i33 %maskedsh)
+  ret i33 %r
+}
+
+; This mask op is unnecessary.
+
+define i32 @fshl_mask_not_required(i32 %x, i32 %y, i32 %sh) {
+; CHECK-LABEL: @fshl_mask_not_required(
+; CHECK-NEXT:    [[R:%.*]] = call i32 @llvm.fshl.i32(i32 [[X:%.*]], i32 [[Y:%.*]], i32 [[SH:%.*]])
+; CHECK-NEXT:    ret i32 [[R]]
+;
+  %maskedsh = and i32 %sh, 31
+  %r = call i32 @llvm.fshl.i32(i32 %x, i32 %y, i32 %maskedsh)
+  ret i32 %r
+}
+
+; This mask op can be reduced.
+
+define i32 @fshl_mask_reduce_constant(i32 %x, i32 %y, i32 %sh) {
+; CHECK-LABEL: @fshl_mask_reduce_constant(
+; CHECK-NEXT:    [[MASKEDSH:%.*]] = and i32 [[SH:%.*]], 1
+; CHECK-NEXT:    [[R:%.*]] = call i32 @llvm.fshl.i32(i32 [[X:%.*]], i32 [[Y:%.*]], i32 [[MASKEDSH]])
+; CHECK-NEXT:    ret i32 [[R]]
+;
+  %maskedsh = and i32 %sh, 33
+  %r = call i32 @llvm.fshl.i32(i32 %x, i32 %y, i32 %maskedsh)
+  ret i32 %r
+}
+
+; But this mask op is required.
+
+define i32 @fshl_mask_negative(i32 %x, i32 %y, i32 %sh) {
+; CHECK-LABEL: @fshl_mask_negative(
+; CHECK-NEXT:    [[MASKEDSH:%.*]] = and i32 [[SH:%.*]], 15
+; CHECK-NEXT:    [[R:%.*]] = call i32 @llvm.fshl.i32(i32 [[X:%.*]], i32 [[Y:%.*]], i32 [[MASKEDSH]])
+; CHECK-NEXT:    ret i32 [[R]]
+;
+  %maskedsh = and i32 %sh, 15
+  %r = call i32 @llvm.fshl.i32(i32 %x, i32 %y, i32 %maskedsh)
+  ret i32 %r
+}
+
+; The transform is not limited to mask ops.
+
+define <2 x i32> @fshr_set_but_not_demanded_vec(<2 x i32> %x, <2 x i32> %y, <2 x i32> %sh) {
+; CHECK-LABEL: @fshr_set_but_not_demanded_vec(
+; CHECK-NEXT:    [[R:%.*]] = call <2 x i32> @llvm.fshr.v2i32(<2 x i32> [[X:%.*]], <2 x i32> [[Y:%.*]], <2 x i32> [[SH:%.*]])
+; CHECK-NEXT:    ret <2 x i32> [[R]]
+;
+  %bogusbits = or <2 x i32> %sh, <i32 32, i32 32>
+  %r = call <2 x i32> @llvm.fshr.v2i32(<2 x i32> %x, <2 x i32> %y, <2 x i32> %bogusbits)
+  ret <2 x i32> %r
+}
+
+; Check again with weird bitwidths - the analysis is invalid with non-power-of-2.
+
+define <2 x i31> @fshl_set_but_not_demanded_vec(<2 x i31> %x, <2 x i31> %y, <2 x i31> %sh) {
+; CHECK-LABEL: @fshl_set_but_not_demanded_vec(
+; CHECK-NEXT:    [[BOGUSBITS:%.*]] = or <2 x i31> [[SH:%.*]], <i31 32, i31 32>
+; CHECK-NEXT:    [[R:%.*]] = call <2 x i31> @llvm.fshl.v2i31(<2 x i31> [[X:%.*]], <2 x i31> [[Y:%.*]], <2 x i31> [[BOGUSBITS]])
+; CHECK-NEXT:    ret <2 x i31> [[R]]
+;
+  %bogusbits = or <2 x i31> %sh, <i31 32, i31 32>
+  %r = call <2 x i31> @llvm.fshl.v2i31(<2 x i31> %x, <2 x i31> %y, <2 x i31> %bogusbits)
+  ret <2 x i31> %r
+}
+
+; Simplify one undef or zero operand and constant shift amount.
+
+define i32 @fshl_op0_undef(i32 %x) {
+; CHECK-LABEL: @fshl_op0_undef(
+; CHECK-NEXT:    [[R:%.*]] = lshr i32 [[X:%.*]], 25
+; CHECK-NEXT:    ret i32 [[R]]
+;
+  %r = call i32 @llvm.fshl.i32(i32 undef, i32 %x, i32 7)
+  ret i32 %r
+}
+
+define i32 @fshl_op0_zero(i32 %x) {
+; CHECK-LABEL: @fshl_op0_zero(
+; CHECK-NEXT:    [[R:%.*]] = lshr i32 [[X:%.*]], 25
+; CHECK-NEXT:    ret i32 [[R]]
+;
+  %r = call i32 @llvm.fshl.i32(i32 0, i32 %x, i32 7)
+  ret i32 %r
+}
+
+define i33 @fshr_op0_undef(i33 %x) {
+; CHECK-LABEL: @fshr_op0_undef(
+; CHECK-NEXT:    [[R:%.*]] = lshr i33 [[X:%.*]], 7
+; CHECK-NEXT:    ret i33 [[R]]
+;
+  %r = call i33 @llvm.fshr.i33(i33 undef, i33 %x, i33 7)
+  ret i33 %r
+}
+
+define i33 @fshr_op0_zero(i33 %x) {
+; CHECK-LABEL: @fshr_op0_zero(
+; CHECK-NEXT:    [[R:%.*]] = lshr i33 [[X:%.*]], 7
+; CHECK-NEXT:    ret i33 [[R]]
+;
+  %r = call i33 @llvm.fshr.i33(i33 0, i33 %x, i33 7)
+  ret i33 %r
+}
+
+define i32 @fshl_op1_undef(i32 %x) {
+; CHECK-LABEL: @fshl_op1_undef(
+; CHECK-NEXT:    [[R:%.*]] = shl i32 [[X:%.*]], 7
+; CHECK-NEXT:    ret i32 [[R]]
+;
+  %r = call i32 @llvm.fshl.i32(i32 %x, i32 undef, i32 7)
+  ret i32 %r
+}
+
+define i32 @fshl_op1_zero(i32 %x) {
+; CHECK-LABEL: @fshl_op1_zero(
+; CHECK-NEXT:    [[R:%.*]] = shl i32 [[X:%.*]], 7
+; CHECK-NEXT:    ret i32 [[R]]
+;
+  %r = call i32 @llvm.fshl.i32(i32 %x, i32 0, i32 7)
+  ret i32 %r
+}
+
+define i33 @fshr_op1_undef(i33 %x) {
+; CHECK-LABEL: @fshr_op1_undef(
+; CHECK-NEXT:    [[R:%.*]] = shl i33 [[X:%.*]], 26
+; CHECK-NEXT:    ret i33 [[R]]
+;
+  %r = call i33 @llvm.fshr.i33(i33 %x, i33 undef, i33 7)
+  ret i33 %r
+}
+
+define i33 @fshr_op1_zero(i33 %x) {
+; CHECK-LABEL: @fshr_op1_zero(
+; CHECK-NEXT:    [[R:%.*]] = shl i33 [[X:%.*]], 26
+; CHECK-NEXT:    ret i33 [[R]]
+;
+  %r = call i33 @llvm.fshr.i33(i33 %x, i33 0, i33 7)
+  ret i33 %r
+}
+
+define <2 x i31> @fshl_op0_zero_splat_vec(<2 x i31> %x) {
+; CHECK-LABEL: @fshl_op0_zero_splat_vec(
+; CHECK-NEXT:    [[R:%.*]] = lshr <2 x i31> [[X:%.*]], <i31 24, i31 24>
+; CHECK-NEXT:    ret <2 x i31> [[R]]
+;
+  %r = call <2 x i31> @llvm.fshl.v2i31(<2 x i31> zeroinitializer, <2 x i31> %x, <2 x i31> <i31 7, i31 7>)
+  ret <2 x i31> %r
+}
+
+define <2 x i31> @fshl_op1_undef_splat_vec(<2 x i31> %x) {
+; CHECK-LABEL: @fshl_op1_undef_splat_vec(
+; CHECK-NEXT:    [[R:%.*]] = shl <2 x i31> [[X:%.*]], <i31 7, i31 7>
+; CHECK-NEXT:    ret <2 x i31> [[R]]
+;
+  %r = call <2 x i31> @llvm.fshl.v2i31(<2 x i31> %x, <2 x i31> undef, <2 x i31> <i31 7, i31 7>)
+  ret <2 x i31> %r
+}
+
+define <2 x i32> @fshr_op0_undef_splat_vec(<2 x i32> %x) {
+; CHECK-LABEL: @fshr_op0_undef_splat_vec(
+; CHECK-NEXT:    [[R:%.*]] = lshr <2 x i32> [[X:%.*]], <i32 7, i32 7>
+; CHECK-NEXT:    ret <2 x i32> [[R]]
+;
+  %r = call <2 x i32> @llvm.fshr.v2i32(<2 x i32> undef, <2 x i32> %x, <2 x i32> <i32 7, i32 7>)
+  ret <2 x i32> %r
+}
+
+define <2 x i32> @fshr_op1_zero_splat_vec(<2 x i32> %x) {
+; CHECK-LABEL: @fshr_op1_zero_splat_vec(
+; CHECK-NEXT:    [[R:%.*]] = shl <2 x i32> [[X:%.*]], <i32 25, i32 25>
+; CHECK-NEXT:    ret <2 x i32> [[R]]
+;
+  %r = call <2 x i32> @llvm.fshr.v2i32(<2 x i32> %x, <2 x i32> zeroinitializer, <2 x i32> <i32 7, i32 7>)
+  ret <2 x i32> %r
+}
+
+define <2 x i31> @fshl_op0_zero_vec(<2 x i31> %x) {
+; CHECK-LABEL: @fshl_op0_zero_vec(
+; CHECK-NEXT:    [[R:%.*]] = lshr <2 x i31> [[X:%.*]], <i31 30, i31 29>
+; CHECK-NEXT:    ret <2 x i31> [[R]]
+;
+  %r = call <2 x i31> @llvm.fshl.v2i31(<2 x i31> zeroinitializer, <2 x i31> %x, <2 x i31> <i31 -1, i31 33>)
+  ret <2 x i31> %r
+}
+
+define <2 x i31> @fshl_op1_undef_vec(<2 x i31> %x) {
+; CHECK-LABEL: @fshl_op1_undef_vec(
+; CHECK-NEXT:    [[R:%.*]] = shl <2 x i31> [[X:%.*]], <i31 1, i31 2>
+; CHECK-NEXT:    ret <2 x i31> [[R]]
+;
+  %r = call <2 x i31> @llvm.fshl.v2i31(<2 x i31> %x, <2 x i31> undef, <2 x i31> <i31 -1, i31 33>)
+  ret <2 x i31> %r
+}
+
+define <2 x i32> @fshr_op0_undef_vec(<2 x i32> %x) {
+; CHECK-LABEL: @fshr_op0_undef_vec(
+; CHECK-NEXT:    [[R:%.*]] = lshr <2 x i32> [[X:%.*]], <i32 31, i32 1>
+; CHECK-NEXT:    ret <2 x i32> [[R]]
+;
+  %r = call <2 x i32> @llvm.fshr.v2i32(<2 x i32> undef, <2 x i32> %x, <2 x i32> <i32 -1, i32 33>)
+  ret <2 x i32> %r
+}
+
+define <2 x i32> @fshr_op1_zero_vec(<2 x i32> %x) {
+; CHECK-LABEL: @fshr_op1_zero_vec(
+; CHECK-NEXT:    [[R:%.*]] = shl <2 x i32> [[X:%.*]], <i32 1, i32 31>
+; CHECK-NEXT:    ret <2 x i32> [[R]]
+;
+  %r = call <2 x i32> @llvm.fshr.v2i32(<2 x i32> %x, <2 x i32> zeroinitializer, <2 x i32> <i32 -1, i32 33>)
+  ret <2 x i32> %r
+}
+
+; Only demand bits from one of the operands.
+
+define i32 @fshl_only_op0_demanded(i32 %x, i32 %y) {
+; CHECK-LABEL: @fshl_only_op0_demanded(
+; CHECK-NEXT:    [[Z:%.*]] = shl i32 [[X:%.*]], 7
+; CHECK-NEXT:    [[R:%.*]] = and i32 [[Z]], 128
+; CHECK-NEXT:    ret i32 [[R]]
+;
+  %z = call i32 @llvm.fshl.i32(i32 %x, i32 %y, i32 7)
+  %r = and i32 %z, 128
+  ret i32 %r
+}
+
+define i32 @fshl_only_op1_demanded(i32 %x, i32 %y) {
+; CHECK-LABEL: @fshl_only_op1_demanded(
+; CHECK-NEXT:    [[Z:%.*]] = lshr i32 [[Y:%.*]], 25
+; CHECK-NEXT:    [[R:%.*]] = and i32 [[Z]], 63
+; CHECK-NEXT:    ret i32 [[R]]
+;
+  %z = call i32 @llvm.fshl.i32(i32 %x, i32 %y, i32 7)
+  %r = and i32 %z, 63
+  ret i32 %r
+}
+
+define i33 @fshr_only_op1_demanded(i33 %x, i33 %y) {
+; CHECK-LABEL: @fshr_only_op1_demanded(
+; CHECK-NEXT:    [[Z:%.*]] = lshr i33 [[Y:%.*]], 7
+; CHECK-NEXT:    [[R:%.*]] = and i33 [[Z]], 12392
+; CHECK-NEXT:    ret i33 [[R]]
+;
+  %z = call i33 @llvm.fshr.i33(i33 %x, i33 %y, i33 7)
+  %r = and i33 %z, 12392
+  ret i33 %r
+}
+
+define i33 @fshr_only_op0_demanded(i33 %x, i33 %y) {
+; CHECK-LABEL: @fshr_only_op0_demanded(
+; CHECK-NEXT:    [[TMP1:%.*]] = lshr i33 [[X:%.*]], 4
+; CHECK-NEXT:    [[R:%.*]] = and i33 [[TMP1]], 7
+; CHECK-NEXT:    ret i33 [[R]]
+;
+  %z = call i33 @llvm.fshr.i33(i33 %x, i33 %y, i33 7)
+  %r = lshr i33 %z, 30
+  ret i33 %r
+}
+
+define <2 x i31> @fshl_only_op1_demanded_vec_splat(<2 x i31> %x, <2 x i31> %y) {
+; CHECK-LABEL: @fshl_only_op1_demanded_vec_splat(
+; CHECK-NEXT:    [[Z:%.*]] = lshr <2 x i31> [[Y:%.*]], <i31 24, i31 24>
+; CHECK-NEXT:    [[R:%.*]] = and <2 x i31> [[Z]], <i31 63, i31 31>
+; CHECK-NEXT:    ret <2 x i31> [[R]]
+;
+  %z = call <2 x i31> @llvm.fshl.v2i31(<2 x i31> %x, <2 x i31> %y, <2 x i31> <i31 7, i31 7>)
+  %r = and <2 x i31> %z, <i31 63, i31 31>
+  ret <2 x i31> %r
+}
+
+define i32 @fshl_constant_shift_amount_modulo_bitwidth(i32 %x, i32 %y) {
+; CHECK-LABEL: @fshl_constant_shift_amount_modulo_bitwidth(
+; CHECK-NEXT:    [[R:%.*]] = call i32 @llvm.fshl.i32(i32 [[X:%.*]], i32 [[Y:%.*]], i32 1)
+; CHECK-NEXT:    ret i32 [[R]]
+;
+  %r = call i32 @llvm.fshl.i32(i32 %x, i32 %y, i32 33)
+  ret i32 %r
+}
+
+define i33 @fshr_constant_shift_amount_modulo_bitwidth(i33 %x, i33 %y) {
+; CHECK-LABEL: @fshr_constant_shift_amount_modulo_bitwidth(
+; CHECK-NEXT:    [[R:%.*]] = call i33 @llvm.fshl.i33(i33 [[X:%.*]], i33 [[Y:%.*]], i33 32)
+; CHECK-NEXT:    ret i33 [[R]]
+;
+  %r = call i33 @llvm.fshr.i33(i33 %x, i33 %y, i33 34)
+  ret i33 %r
+}
+
+ at external_global = external global i8
+
+define i33 @fshr_constant_shift_amount_modulo_bitwidth_constexpr(i33 %x, i33 %y) {
+; CHECK-LABEL: @fshr_constant_shift_amount_modulo_bitwidth_constexpr(
+; CHECK-NEXT:    [[R:%.*]] = call i33 @llvm.fshr.i33(i33 [[X:%.*]], i33 [[Y:%.*]], i33 ptrtoint (i8* @external_global to i33))
+; CHECK-NEXT:    ret i33 [[R]]
+;
+  %shamt = ptrtoint i8* @external_global to i33
+  %r = call i33 @llvm.fshr.i33(i33 %x, i33 %y, i33 %shamt)
+  ret i33 %r
+}
+
+define <2 x i32> @fshr_constant_shift_amount_modulo_bitwidth_vec(<2 x i32> %x, <2 x i32> %y) {
+; CHECK-LABEL: @fshr_constant_shift_amount_modulo_bitwidth_vec(
+; CHECK-NEXT:    [[R:%.*]] = call <2 x i32> @llvm.fshl.v2i32(<2 x i32> [[X:%.*]], <2 x i32> [[Y:%.*]], <2 x i32> <i32 30, i32 1>)
+; CHECK-NEXT:    ret <2 x i32> [[R]]
+;
+  %r = call <2 x i32> @llvm.fshr.v2i32(<2 x i32> %x, <2 x i32> %y, <2 x i32> <i32 34, i32 -1>)
+  ret <2 x i32> %r
+}
+
+define <2 x i31> @fshl_constant_shift_amount_modulo_bitwidth_vec(<2 x i31> %x, <2 x i31> %y) {
+; CHECK-LABEL: @fshl_constant_shift_amount_modulo_bitwidth_vec(
+; CHECK-NEXT:    [[R:%.*]] = call <2 x i31> @llvm.fshl.v2i31(<2 x i31> [[X:%.*]], <2 x i31> [[Y:%.*]], <2 x i31> <i31 3, i31 1>)
+; CHECK-NEXT:    ret <2 x i31> [[R]]
+;
+  %r = call <2 x i31> @llvm.fshl.v2i31(<2 x i31> %x, <2 x i31> %y, <2 x i31> <i31 34, i31 -1>)
+  ret <2 x i31> %r
+}
+
+define <2 x i31> @fshl_constant_shift_amount_modulo_bitwidth_vec_const_expr(<2 x i31> %x, <2 x i31> %y) {
+; CHECK-LABEL: @fshl_constant_shift_amount_modulo_bitwidth_vec_const_expr(
+; CHECK-NEXT:    [[R:%.*]] = call <2 x i31> @llvm.fshl.v2i31(<2 x i31> [[X:%.*]], <2 x i31> [[Y:%.*]], <2 x i31> <i31 34, i31 ptrtoint (i8* @external_global to i31)>)
+; CHECK-NEXT:    ret <2 x i31> [[R]]
+;
+  %shamt = ptrtoint i8* @external_global to i31
+  %r = call <2 x i31> @llvm.fshl.v2i31(<2 x i31> %x, <2 x i31> %y, <2 x i31> <i31 34, i31 ptrtoint (i8* @external_global to i31)>)
+  ret <2 x i31> %r
+}
+
+; The shift modulo bitwidth is the same for all vector elements.
+
+define <2 x i31> @fshl_only_op1_demanded_vec_nonsplat(<2 x i31> %x, <2 x i31> %y) {
+; CHECK-LABEL: @fshl_only_op1_demanded_vec_nonsplat(
+; CHECK-NEXT:    [[Z:%.*]] = lshr <2 x i31> [[Y:%.*]], <i31 24, i31 24>
+; CHECK-NEXT:    [[R:%.*]] = and <2 x i31> [[Z]], <i31 63, i31 31>
+; CHECK-NEXT:    ret <2 x i31> [[R]]
+;
+  %z = call <2 x i31> @llvm.fshl.v2i31(<2 x i31> %x, <2 x i31> %y, <2 x i31> <i31 7, i31 38>)
+  %r = and <2 x i31> %z, <i31 63, i31 31>
+  ret <2 x i31> %r
+}
+
+define i32 @rotl_constant_shift_amount(i32 %x) {
+; CHECK-LABEL: @rotl_constant_shift_amount(
+; CHECK-NEXT:    [[R:%.*]] = call i32 @llvm.fshl.i32(i32 [[X:%.*]], i32 [[X]], i32 1)
+; CHECK-NEXT:    ret i32 [[R]]
+;
+  %r = call i32 @llvm.fshl.i32(i32 %x, i32 %x, i32 33)
+  ret i32 %r
+}
+
+define <2 x i31> @rotl_constant_shift_amount_vec(<2 x i31> %x) {
+; CHECK-LABEL: @rotl_constant_shift_amount_vec(
+; CHECK-NEXT:    [[R:%.*]] = call <2 x i31> @llvm.fshl.v2i31(<2 x i31> [[X:%.*]], <2 x i31> [[X]], <2 x i31> <i31 1, i31 1>)
+; CHECK-NEXT:    ret <2 x i31> [[R]]
+;
+  %r = call <2 x i31> @llvm.fshl.v2i31(<2 x i31> %x, <2 x i31> %x, <2 x i31> <i31 32, i31 -1>)
+  ret <2 x i31> %r
+}
+
+define i33 @rotr_constant_shift_amount(i33 %x) {
+; CHECK-LABEL: @rotr_constant_shift_amount(
+; CHECK-NEXT:    [[R:%.*]] = call i33 @llvm.fshl.i33(i33 [[X:%.*]], i33 [[X]], i33 32)
+; CHECK-NEXT:    ret i33 [[R]]
+;
+  %r = call i33 @llvm.fshr.i33(i33 %x, i33 %x, i33 34)
+  ret i33 %r
+}
+
+define <2 x i32> @rotr_constant_shift_amount_vec(<2 x i32> %x) {
+; CHECK-LABEL: @rotr_constant_shift_amount_vec(
+; CHECK-NEXT:    [[R:%.*]] = call <2 x i32> @llvm.fshl.v2i32(<2 x i32> [[X:%.*]], <2 x i32> [[X]], <2 x i32> <i32 31, i32 1>)
+; CHECK-NEXT:    ret <2 x i32> [[R]]
+;
+  %r = call <2 x i32> @llvm.fshr.v2i32(<2 x i32> %x, <2 x i32> %x, <2 x i32> <i32 33, i32 -1>)
+  ret <2 x i32> %r
+}
+
+; Demand bits from both operands -- cannot simplify.
+
+define i32 @fshl_both_ops_demanded(i32 %x, i32 %y) {
+; CHECK-LABEL: @fshl_both_ops_demanded(
+; CHECK-NEXT:    [[Z:%.*]] = call i32 @llvm.fshl.i32(i32 [[X:%.*]], i32 [[Y:%.*]], i32 7)
+; CHECK-NEXT:    [[R:%.*]] = and i32 [[Z]], 192
+; CHECK-NEXT:    ret i32 [[R]]
+;
+  %z = call i32 @llvm.fshl.i32(i32 %x, i32 %y, i32 7)
+  %r = and i32 %z, 192
+  ret i32 %r
+}
+
+define i33 @fshr_both_ops_demanded(i33 %x, i33 %y) {
+; CHECK-LABEL: @fshr_both_ops_demanded(
+; CHECK-NEXT:    [[Z:%.*]] = call i33 @llvm.fshl.i33(i33 [[X:%.*]], i33 [[Y:%.*]], i33 7)
+; CHECK-NEXT:    [[R:%.*]] = and i33 [[Z]], 192
+; CHECK-NEXT:    ret i33 [[R]]
+;
+  %z = call i33 @llvm.fshr.i33(i33 %x, i33 %y, i33 26)
+  %r = and i33 %z, 192
+  ret i33 %r
+}
+
+; Both operands are demanded, but there are known bits.
+
+define i32 @fshl_known_bits(i32 %x, i32 %y) {
+; CHECK-LABEL: @fshl_known_bits(
+; CHECK-NEXT:    ret i32 128
+;
+  %x2 = or i32 %x, 1   ; lo bit set
+  %y2 = lshr i32 %y, 1 ; hi bit clear
+  %z = call i32 @llvm.fshl.i32(i32 %x2, i32 %y2, i32 7)
+  %r = and i32 %z, 192
+  ret i32 %r
+}
+
+define i33 @fshr_known_bits(i33 %x, i33 %y) {
+; CHECK-LABEL: @fshr_known_bits(
+; CHECK-NEXT:    ret i33 128
+;
+  %x2 = or i33 %x, 1 ; lo bit set
+  %y2 = lshr i33 %y, 1 ; hi bit set
+  %z = call i33 @llvm.fshr.i33(i33 %x2, i33 %y2, i33 26)
+  %r = and i33 %z, 192
+  ret i33 %r
+}
+
+; This case fails to simplify due to multiple uses.
+
+define i33 @fshr_multi_use(i33 %a) {
+; CHECK-LABEL: @fshr_multi_use(
+; CHECK-NEXT:    [[B:%.*]] = call i33 @llvm.fshl.i33(i33 [[A:%.*]], i33 [[A]], i33 32)
+; CHECK-NEXT:    [[C:%.*]] = lshr i33 [[B]], 23
+; CHECK-NEXT:    [[D:%.*]] = xor i33 [[C]], [[B]]
+; CHECK-NEXT:    [[E:%.*]] = and i33 [[D]], 31
+; CHECK-NEXT:    ret i33 [[E]]
+;
+  %b = tail call i33 @llvm.fshr.i33(i33 %a, i33 %a, i33 1)
+  %c = lshr i33 %b, 23
+  %d = xor i33 %c, %b
+  %e = and i33 %d, 31
+  ret i33 %e
+}
+
+; This demonstrates the same simplification working if the fshr intrinsic
+; is expanded into shifts and or.
+
+define i33 @expanded_fshr_multi_use(i33 %a) {
+; CHECK-LABEL: @expanded_fshr_multi_use(
+; CHECK-NEXT:    [[TMP:%.*]] = lshr i33 [[A:%.*]], 1
+; CHECK-NEXT:    [[C:%.*]] = lshr i33 [[A]], 24
+; CHECK-NEXT:    [[D:%.*]] = xor i33 [[C]], [[TMP]]
+; CHECK-NEXT:    [[E:%.*]] = and i33 [[D]], 31
+; CHECK-NEXT:    ret i33 [[E]]
+;
+  %tmp = lshr i33 %a, 1
+  %tmp2 = shl i33 %a, 32
+  %b = or i33 %tmp, %tmp2
+  %c = lshr i33 %b, 23
+  %d = xor i33 %c, %b
+  %e = and i33 %d, 31
+  ret i33 %e
+}
+
+declare i16 @llvm.fshl.i16(i16, i16, i16)
+declare i16 @llvm.fshr.i16(i16, i16, i16)
+
+; Special-case: rotate a 16-bit value left/right by 8-bits is bswap.
+
+define i16 @fshl_bswap(i16 %x) {
+; CHECK-LABEL: @fshl_bswap(
+; CHECK-NEXT:    [[R:%.*]] = call i16 @llvm.fshl.i16(i16 [[X:%.*]], i16 [[X]], i16 8)
+; CHECK-NEXT:    ret i16 [[R]]
+;
+  %r = call i16 @llvm.fshl.i16(i16 %x, i16 %x, i16 8)
+  ret i16 %r
+}
+
+define i16 @fshr_bswap(i16 %x) {
+; CHECK-LABEL: @fshr_bswap(
+; CHECK-NEXT:    [[R:%.*]] = call i16 @llvm.fshl.i16(i16 [[X:%.*]], i16 [[X]], i16 8)
+; CHECK-NEXT:    ret i16 [[R]]
+;
+  %r = call i16 @llvm.fshr.i16(i16 %x, i16 %x, i16 8)
+  ret i16 %r
+}
+
+define i32 @fshl_mask_args_same1(i32 %a) {
+; CHECK-LABEL: @fshl_mask_args_same1(
+; CHECK-NEXT:    [[TMP2:%.*]] = lshr i32 [[A:%.*]], 16
+; CHECK-NEXT:    ret i32 [[TMP2]]
+;
+  %tmp1 = and i32 %a, 4294901760 ; 0xffff0000
+  %tmp2 = call i32 @llvm.fshl.i32(i32 %tmp1, i32 %tmp1, i32 16)
+  ret i32 %tmp2
+}
+
+define i32 @fshl_mask_args_same2(i32 %a) {
+; CHECK-LABEL: @fshl_mask_args_same2(
+; CHECK-NEXT:    [[TMP1:%.*]] = shl i32 [[A:%.*]], 8
+; CHECK-NEXT:    [[TMP2:%.*]] = and i32 [[TMP1]], 65280
+; CHECK-NEXT:    ret i32 [[TMP2]]
+;
+  %tmp1 = and i32 %a, 255
+  %tmp2 = call i32 @llvm.fshl.i32(i32 %tmp1, i32 %tmp1, i32 8)
+  ret i32 %tmp2
+}
+
+define i32 @fshl_mask_args_same3(i32 %a) {
+; CHECK-LABEL: @fshl_mask_args_same3(
+; CHECK-NEXT:    [[TMP2:%.*]] = shl i32 [[A:%.*]], 24
+; CHECK-NEXT:    ret i32 [[TMP2]]
+;
+  %tmp1 = and i32 %a, 255
+  %tmp2 = call i32 @llvm.fshl.i32(i32 %tmp1, i32 %tmp1, i32 24)
+  ret i32 %tmp2
+}
+
+define i32 @fshl_mask_args_different(i32 %a) {
+; CHECK-LABEL: @fshl_mask_args_different(
+; CHECK-NEXT:    [[TMP1:%.*]] = lshr i32 [[A:%.*]], 15
+; CHECK-NEXT:    [[TMP3:%.*]] = and i32 [[TMP1]], 130560
+; CHECK-NEXT:    ret i32 [[TMP3]]
+;
+  %tmp2 = and i32 %a, 4294901760 ; 0xfffff00f
+  %tmp1 = and i32 %a, 4278190080 ; 0xff00f00f
+  %tmp3 = call i32 @llvm.fshl.i32(i32 %tmp2, i32 %tmp1, i32 17)
+  ret i32 %tmp3
+}
+
+define <2 x i31> @fshr_mask_args_same_vector(<2 x i31> %a) {
+; CHECK-LABEL: @fshr_mask_args_same_vector(
+; CHECK-NEXT:    [[TMP3:%.*]] = shl <2 x i31> [[A:%.*]], <i31 10, i31 10>
+; CHECK-NEXT:    ret <2 x i31> [[TMP3]]
+;
+  %tmp1 = and <2 x i31> %a, <i31 1000, i31 1000>
+  %tmp2 = and <2 x i31> %a, <i31 6442450943, i31 6442450943>
+  %tmp3 = call <2 x i31> @llvm.fshl.v2i31(<2 x i31> %tmp2, <2 x i31> %tmp1, <2 x i31> <i31 10, i31 10>)
+  ret <2 x i31> %tmp3
+}
+
+define <2 x i32> @fshr_mask_args_same_vector2(<2 x i32> %a, <2 x i32> %b) {
+; CHECK-LABEL: @fshr_mask_args_same_vector2(
+; CHECK-NEXT:    [[TMP1:%.*]] = and <2 x i32> [[A:%.*]], <i32 1000000, i32 100000>
+; CHECK-NEXT:    [[TMP3:%.*]] = lshr exact <2 x i32> [[TMP1]], <i32 3, i32 3>
+; CHECK-NEXT:    ret <2 x i32> [[TMP3]]
+;
+  %tmp1 = and <2 x i32> %a, <i32 1000000, i32 100000>
+  %tmp2 = and <2 x i32> %a, <i32 6442450943, i32 6442450943>
+  %tmp3 = call <2 x i32> @llvm.fshr.v2i32(<2 x i32> %tmp1, <2 x i32> %tmp1, <2 x i32> <i32 3, i32 3>)
+  ret <2 x i32> %tmp3
+}
+
+define <2 x i31> @fshr_mask_args_same_vector3_different_but_still_prunable(<2 x i31> %a) {
+; CHECK-LABEL: @fshr_mask_args_same_vector3_different_but_still_prunable(
+; CHECK-NEXT:    [[TMP1:%.*]] = and <2 x i31> [[A:%.*]], <i31 1000, i31 1000>
+; CHECK-NEXT:    [[TMP3:%.*]] = call <2 x i31> @llvm.fshl.v2i31(<2 x i31> [[A]], <2 x i31> [[TMP1]], <2 x i31> <i31 10, i31 3>)
+; CHECK-NEXT:    ret <2 x i31> [[TMP3]]
+;
+  %tmp1 = and <2 x i31> %a, <i31 1000, i31 1000>
+  %tmp2 = and <2 x i31> %a, <i31 6442450943, i31 6442450943>
+  %tmp3 = call <2 x i31> @llvm.fshl.v2i31(<2 x i31> %tmp2, <2 x i31> %tmp1, <2 x i31> <i31 10, i31 3>)
+  ret <2 x i31> %tmp3
+}

Added: llvm/trunk/test/Transforms/InstCombine/fsub.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/fsub.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/fsub.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/fsub.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,271 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt < %s -instcombine -S | FileCheck %s
+
+; PR4374
+
+define float @test1(float %x, float %y) {
+; CHECK-LABEL: @test1(
+; CHECK-NEXT:    [[T1:%.*]] = fsub float [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    [[T2:%.*]] = fsub float -0.000000e+00, [[T1]]
+; CHECK-NEXT:    ret float [[T2]]
+;
+  %t1 = fsub float %x, %y
+  %t2 = fsub float -0.0, %t1
+  ret float %t2
+}
+
+; Can't do anything with the test above because -0.0 - 0.0 = -0.0, but if we have nsz:
+; -(X - Y) --> Y - X
+
+define float @neg_sub_nsz(float %x, float %y) {
+; CHECK-LABEL: @neg_sub_nsz(
+; CHECK-NEXT:    [[TMP1:%.*]] = fsub nsz float [[Y:%.*]], [[X:%.*]]
+; CHECK-NEXT:    ret float [[TMP1]]
+;
+  %t1 = fsub float %x, %y
+  %t2 = fsub nsz float -0.0, %t1
+  ret float %t2
+}
+
+; If the subtract has another use, we don't do the transform (even though it
+; doesn't increase the IR instruction count) because we assume that fneg is
+; easier to analyze and generally cheaper than generic fsub.
+
+declare void @use(float)
+declare void @use2(float, double)
+
+define float @neg_sub_nsz_extra_use(float %x, float %y) {
+; CHECK-LABEL: @neg_sub_nsz_extra_use(
+; CHECK-NEXT:    [[T1:%.*]] = fsub float [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    [[T2:%.*]] = fsub nsz float -0.000000e+00, [[T1]]
+; CHECK-NEXT:    call void @use(float [[T1]])
+; CHECK-NEXT:    ret float [[T2]]
+;
+  %t1 = fsub float %x, %y
+  %t2 = fsub nsz float -0.0, %t1
+  call void @use(float %t1)
+  ret float %t2
+}
+
+; With nsz: Z - (X - Y) --> Z + (Y - X)
+
+define float @sub_sub_nsz(float %x, float %y, float %z) {
+; CHECK-LABEL: @sub_sub_nsz(
+; CHECK-NEXT:    [[TMP1:%.*]] = fsub nsz float [[Y:%.*]], [[X:%.*]]
+; CHECK-NEXT:    [[T2:%.*]] = fadd nsz float [[TMP1]], [[Z:%.*]]
+; CHECK-NEXT:    ret float [[T2]]
+;
+  %t1 = fsub float %x, %y
+  %t2 = fsub nsz float %z, %t1
+  ret float %t2
+}
+
+; With nsz and reassoc: Y - ((X * 5) + Y) --> X * -5
+
+define float @sub_add_neg_x(float %x, float %y) {
+; CHECK-LABEL: @sub_add_neg_x(
+; CHECK-NEXT:    [[TMP1:%.*]] = fmul reassoc nsz float [[X:%.*]], -5.000000e+00
+; CHECK-NEXT:    ret float [[TMP1]]
+;
+  %mul = fmul float %x, 5.000000e+00
+  %add = fadd float %mul, %y
+  %r = fsub nsz reassoc float %y, %add
+  ret float %r
+}
+
+; Same as above: if 'Z' is not -0.0, swap fsub operands and convert to fadd.
+
+define float @sub_sub_known_not_negzero(float %x, float %y) {
+; CHECK-LABEL: @sub_sub_known_not_negzero(
+; CHECK-NEXT:    [[TMP1:%.*]] = fsub float [[Y:%.*]], [[X:%.*]]
+; CHECK-NEXT:    [[T2:%.*]] = fadd float [[TMP1]], 4.200000e+01
+; CHECK-NEXT:    ret float [[T2]]
+;
+  %t1 = fsub float %x, %y
+  %t2 = fsub float 42.0, %t1
+  ret float %t2
+}
+
+; <rdar://problem/7530098>
+
+define double @test2(double %x, double %y) {
+; CHECK-LABEL: @test2(
+; CHECK-NEXT:    [[T1:%.*]] = fadd double [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    [[T2:%.*]] = fsub double [[X]], [[T1]]
+; CHECK-NEXT:    ret double [[T2]]
+;
+  %t1 = fadd double %x, %y
+  %t2 = fsub double %x, %t1
+  ret double %t2
+}
+
+; X - C --> X + (-C)
+
+define float @constant_op1(float %x, float %y) {
+; CHECK-LABEL: @constant_op1(
+; CHECK-NEXT:    [[R:%.*]] = fadd float [[X:%.*]], -4.200000e+01
+; CHECK-NEXT:    ret float [[R]]
+;
+  %r = fsub float %x, 42.0
+  ret float %r
+}
+
+define <2 x float> @constant_op1_vec(<2 x float> %x, <2 x float> %y) {
+; CHECK-LABEL: @constant_op1_vec(
+; CHECK-NEXT:    [[R:%.*]] = fadd <2 x float> [[X:%.*]], <float -4.200000e+01, float 4.200000e+01>
+; CHECK-NEXT:    ret <2 x float> [[R]]
+;
+  %r = fsub <2 x float> %x, <float 42.0, float -42.0>
+  ret <2 x float> %r
+}
+
+define <2 x float> @constant_op1_vec_undef(<2 x float> %x, <2 x float> %y) {
+; CHECK-LABEL: @constant_op1_vec_undef(
+; CHECK-NEXT:    [[R:%.*]] = fadd <2 x float> [[X:%.*]], <float 0x7FF8000000000000, float 4.200000e+01>
+; CHECK-NEXT:    ret <2 x float> [[R]]
+;
+  %r = fsub <2 x float> %x, <float undef, float -42.0>
+  ret <2 x float> %r
+}
+
+; X - (-Y) --> X + Y
+
+define float @neg_op1(float %x, float %y) {
+; CHECK-LABEL: @neg_op1(
+; CHECK-NEXT:    [[R:%.*]] = fadd float [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    ret float [[R]]
+;
+  %negy = fsub float -0.0, %y
+  %r = fsub float %x, %negy
+  ret float %r
+}
+
+define <2 x float> @neg_op1_vec(<2 x float> %x, <2 x float> %y) {
+; CHECK-LABEL: @neg_op1_vec(
+; CHECK-NEXT:    [[R:%.*]] = fadd <2 x float> [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    ret <2 x float> [[R]]
+;
+  %negy = fsub <2 x float> <float -0.0, float -0.0>, %y
+  %r = fsub <2 x float> %x, %negy
+  ret <2 x float> %r
+}
+
+define <2 x float> @neg_op1_vec_undef(<2 x float> %x, <2 x float> %y) {
+; CHECK-LABEL: @neg_op1_vec_undef(
+; CHECK-NEXT:    [[R:%.*]] = fadd <2 x float> [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    ret <2 x float> [[R]]
+;
+  %negy = fsub <2 x float> <float -0.0, float undef>, %y
+  %r = fsub <2 x float> %x, %negy
+  ret <2 x float> %r
+}
+
+; Similar to above - but look through fpext/fptrunc casts to find the fneg.
+
+define double @neg_ext_op1(float %a, double %b) {
+; CHECK-LABEL: @neg_ext_op1(
+; CHECK-NEXT:    [[TMP1:%.*]] = fpext float [[A:%.*]] to double
+; CHECK-NEXT:    [[T3:%.*]] = fadd double [[TMP1]], [[B:%.*]]
+; CHECK-NEXT:    ret double [[T3]]
+;
+  %t1 = fsub float -0.0, %a
+  %t2 = fpext float %t1 to double
+  %t3 = fsub double %b, %t2
+  ret double %t3
+}
+
+; Verify that vectors work too.
+
+define <2 x float> @neg_trunc_op1(<2 x double> %a, <2 x float> %b) {
+; CHECK-LABEL: @neg_trunc_op1(
+; CHECK-NEXT:    [[TMP1:%.*]] = fptrunc <2 x double> [[A:%.*]] to <2 x float>
+; CHECK-NEXT:    [[T3:%.*]] = fadd <2 x float> [[TMP1]], [[B:%.*]]
+; CHECK-NEXT:    ret <2 x float> [[T3]]
+;
+  %t1 = fsub <2 x double> <double -0.0, double -0.0>, %a
+  %t2 = fptrunc <2 x double> %t1 to <2 x float>
+  %t3 = fsub <2 x float> %b, %t2
+  ret <2 x float> %t3
+}
+
+; No FMF needed, but they should propagate to the fadd.
+
+define double @neg_ext_op1_fast(float %a, double %b) {
+; CHECK-LABEL: @neg_ext_op1_fast(
+; CHECK-NEXT:    [[TMP1:%.*]] = fpext float [[A:%.*]] to double
+; CHECK-NEXT:    [[T3:%.*]] = fadd fast double [[TMP1]], [[B:%.*]]
+; CHECK-NEXT:    ret double [[T3]]
+;
+  %t1 = fsub float -0.0, %a
+  %t2 = fpext float %t1 to double
+  %t3 = fsub fast double %b, %t2
+  ret double %t3
+}
+
+; Extra use should prevent the transform.
+
+define float @neg_ext_op1_extra_use(half %a, float %b) {
+; CHECK-LABEL: @neg_ext_op1_extra_use(
+; CHECK-NEXT:    [[T1:%.*]] = fsub half 0xH8000, [[A:%.*]]
+; CHECK-NEXT:    [[T2:%.*]] = fpext half [[T1]] to float
+; CHECK-NEXT:    [[T3:%.*]] = fsub float [[B:%.*]], [[T2]]
+; CHECK-NEXT:    call void @use(float [[T2]])
+; CHECK-NEXT:    ret float [[T3]]
+;
+  %t1 = fsub half -0.0, %a
+  %t2 = fpext half %t1 to float
+  %t3 = fsub float %b, %t2
+  call void @use(float %t2)
+  ret float %t3
+}
+
+; One-use fptrunc is always hoisted above fneg, so the corresponding
+; multi-use bug for fptrunc isn't visible with a fold starting from
+; the last fsub.
+
+define float @neg_trunc_op1_extra_use(double %a, float %b) {
+; CHECK-LABEL: @neg_trunc_op1_extra_use(
+; CHECK-NEXT:    [[TMP1:%.*]] = fptrunc double [[A:%.*]] to float
+; CHECK-NEXT:    [[T2:%.*]] = fsub float -0.000000e+00, [[TMP1]]
+; CHECK-NEXT:    [[T3:%.*]] = fadd float [[TMP1]], [[B:%.*]]
+; CHECK-NEXT:    call void @use(float [[T2]])
+; CHECK-NEXT:    ret float [[T3]]
+;
+  %t1 = fsub double -0.0, %a
+  %t2 = fptrunc double %t1 to float
+  %t3 = fsub float %b, %t2
+  call void @use(float %t2)
+  ret float %t3
+}
+
+; Extra uses should prevent the transform.
+
+define float @neg_trunc_op1_extra_uses(double %a, float %b) {
+; CHECK-LABEL: @neg_trunc_op1_extra_uses(
+; CHECK-NEXT:    [[T1:%.*]] = fsub double -0.000000e+00, [[A:%.*]]
+; CHECK-NEXT:    [[T2:%.*]] = fptrunc double [[T1]] to float
+; CHECK-NEXT:    [[T3:%.*]] = fsub float [[B:%.*]], [[T2]]
+; CHECK-NEXT:    call void @use2(float [[T2]], double [[T1]])
+; CHECK-NEXT:    ret float [[T3]]
+;
+  %t1 = fsub double -0.0, %a
+  %t2 = fptrunc double %t1 to float
+  %t3 = fsub float %b, %t2
+  call void @use2(float %t2, double %t1)
+  ret float %t3
+}
+
+; Don't negate a constant expression to form fadd and induce infinite looping:
+; https://bugs.llvm.org/show_bug.cgi?id=37605
+
+ at b = external global i16, align 1
+
+define float @PR37605(float %conv) {
+; CHECK-LABEL: @PR37605(
+; CHECK-NEXT:    [[SUB:%.*]] = fsub float [[CONV:%.*]], bitcast (i32 ptrtoint (i16* @b to i32) to float)
+; CHECK-NEXT:    ret float [[SUB]]
+;
+  %sub = fsub float %conv, bitcast (i32 ptrtoint (i16* @b to i32) to float)
+  ret float %sub
+}
+

Added: llvm/trunk/test/Transforms/InstCombine/fwrite-1.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/fwrite-1.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/fwrite-1.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/fwrite-1.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,57 @@
+; Test that the fwrite 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"
+
+%FILE = type { }
+
+ at str = constant [1 x i8] zeroinitializer
+ at empty = constant [0 x i8] zeroinitializer
+
+declare i64 @fwrite(i8*, i64, i64, %FILE *)
+
+; Check fwrite(S, 1, 1, fp) -> fputc(S[0], fp).
+
+define void @test_simplify1(%FILE* %fp) {
+; CHECK-LABEL: @test_simplify1(
+  %str = getelementptr inbounds [1 x i8], [1 x i8]* @str, i64 0, i64 0
+  call i64 @fwrite(i8* %str, i64 1, i64 1, %FILE* %fp)
+; CHECK-NEXT: call i32 @fputc(i32 0, %FILE* %fp)
+  ret void
+; CHECK-NEXT: ret void
+}
+
+define void @test_simplify2(%FILE* %fp) {
+; CHECK-LABEL: @test_simplify2(
+  %str = getelementptr inbounds [0 x i8], [0 x i8]* @empty, i64 0, i64 0
+  call i64 @fwrite(i8* %str, i64 1, i64 0, %FILE* %fp)
+  ret void
+; CHECK-NEXT: ret void
+}
+
+define void @test_simplify3(%FILE* %fp) {
+; CHECK-LABEL: @test_simplify3(
+  %str = getelementptr inbounds [0 x i8], [0 x i8]* @empty, i64 0, i64 0
+  call i64 @fwrite(i8* %str, i64 0, i64 1, %FILE* %fp)
+  ret void
+; CHECK-NEXT: ret void
+}
+
+define i64 @test_no_simplify1(%FILE* %fp) {
+; CHECK-LABEL: @test_no_simplify1(
+  %str = getelementptr inbounds [1 x i8], [1 x i8]* @str, i64 0, i64 0
+  %ret = call i64 @fwrite(i8* %str, i64 1, i64 1, %FILE* %fp)
+; CHECK-NEXT: call i64 @fwrite
+  ret i64 %ret
+; CHECK-NEXT: ret i64 %ret
+}
+
+define void @test_no_simplify2(%FILE* %fp, i64 %size) {
+; CHECK-LABEL: @test_no_simplify2(
+  %str = getelementptr inbounds [1 x i8], [1 x i8]* @str, i64 0, i64 0
+  call i64 @fwrite(i8* %str, i64 %size, i64 1, %FILE* %fp)
+; CHECK-NEXT: call i64 @fwrite
+  ret void
+; CHECK-NEXT: ret void
+}

Added: llvm/trunk/test/Transforms/InstCombine/gc.relocate.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/gc.relocate.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/gc.relocate.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/gc.relocate.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,59 @@
+; 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"
+
+; Uses InstCombine with DataLayout to propagate dereferenceable
+; attribute via gc.relocate: if the derived ptr is dereferenceable(N),
+; then the return attribute of gc.relocate is dereferenceable(N).
+
+declare zeroext i1 @return_i1()
+declare token @llvm.experimental.gc.statepoint.p0f_i1f(i64, i32, i1 ()*, i32, i32, ...)
+declare i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token, i32, i32)
+
+define i32 @explicit_nonnull(i32 addrspace(1)* nonnull %dparam) gc "statepoint-example" {
+; Checks that a nonnull pointer
+; CHECK-LABEL: @explicit_nonnull
+; CHECK: ret i32 1
+entry:
+    %load = load i32, i32 addrspace(1)* %dparam
+    %tok = tail call token (i64, i32, i1 ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_i1f(i64 0, i32 0, i1 ()* @return_i1, i32 0, i32 0, i32 0, i32 0, i32 addrspace(1)* %dparam)
+    %relocate = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token %tok,  i32 7, i32 7)
+    %cmp = icmp eq i32 addrspace(1)* %relocate, null
+    %ret_val = select i1 %cmp, i32 0, i32 1
+    ret i32 %ret_val
+}
+
+define i32 @implicit_nonnull(i32 addrspace(1)* %dparam) gc "statepoint-example" {
+; Checks that a nonnull pointer
+; CHECK-LABEL: @implicit_nonnull
+; CHECK: ret i32 1
+entry:
+    %cond = icmp eq i32 addrspace(1)* %dparam, null
+    br i1 %cond, label %no_gc, label %gc
+gc:
+    %load = load i32, i32 addrspace(1)* %dparam
+    %tok = tail call token (i64, i32, i1 ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_i1f(i64 0, i32 0, i1 ()* @return_i1, i32 0, i32 0, i32 0, i32 0, i32 addrspace(1)* %dparam)
+    %relocate = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token %tok,  i32 7, i32 7)
+    %cmp = icmp eq i32 addrspace(1)* %relocate, null
+    %ret_val = select i1 %cmp, i32 0, i32 1
+    ret i32 %ret_val
+no_gc:
+    unreachable
+}
+
+
+; Make sure we don't crash when processing vectors
+define <2 x i8 addrspace(1)*> @vector(<2 x i8 addrspace(1)*> %obj) gc "statepoint-example" {
+entry:
+; CHECK-LABEL: @vector
+; CHECK: gc.statepoint
+; CHECK: gc.relocate
+  %safepoint_token = call token (i64, i32, void ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_isVoidf(i64 0, i32 0, void ()* @do_safepoint, i32 0, i32 0, i32 0, i32 0, <2 x i8 addrspace(1)*> %obj)
+  %obj.relocated = call coldcc <2 x i8 addrspace(1)*> @llvm.experimental.gc.relocate.v2p1i8(token %safepoint_token, i32 7, i32 7) ; (%obj, %obj)
+  ret <2 x i8 addrspace(1)*> %obj.relocated
+}
+
+declare void @do_safepoint()
+
+declare token @llvm.experimental.gc.statepoint.p0f_isVoidf(i64, i32, void ()*, i32, i32, ...)
+declare i8 addrspace(1)* @llvm.experimental.gc.relocate.p1i8(token, i32, i32)
+declare <2 x i8 addrspace(1)*> @llvm.experimental.gc.relocate.v2p1i8(token, i32, i32)

Added: llvm/trunk/test/Transforms/InstCombine/gep-addrspace.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/gep-addrspace.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/gep-addrspace.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/gep-addrspace.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
+
+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"
+target triple = "x86_64-pc-win32"
+
+%myStruct = type { float, [3 x float], [4 x float], i32 }
+
+; make sure that we are not crashing when creating an illegal type
+define void @func(%myStruct addrspace(1)* nocapture %p) nounwind {
+; CHECK-LABEL: @func(
+; CHECK-NEXT:    ret void
+;
+  %A = getelementptr inbounds %myStruct, %myStruct addrspace(1)* %p, i64 0
+  %B = addrspacecast %myStruct addrspace(1)* %A to %myStruct*
+  %C = getelementptr inbounds %myStruct, %myStruct* %B, i32 0, i32 1
+  %D = getelementptr inbounds [3 x float], [3 x float]* %C, i32 0, i32 2
+  %E = load float, float* %D, align 4
+  %F = fsub float %E, undef
+  ret void
+}
+
+ at array = internal addrspace(3) global [256 x float] zeroinitializer, align 4
+ at scalar = internal addrspace(3) global float 0.000000e+00, align 4
+
+define void @keep_necessary_addrspacecast(i64 %i, float** %out0, float** %out1) {
+; CHECK-LABEL: @keep_necessary_addrspacecast(
+; CHECK-NEXT:    [[T01:%.*]] = getelementptr [256 x float], [256 x float] addrspace(3)* @array, i64 0, i64 [[I:%.*]]
+; CHECK-NEXT:    [[T0:%.*]] = addrspacecast float addrspace(3)* [[T01]] to float*
+; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr float, float addrspace(3)* @scalar, i64 [[I]]
+; CHECK-NEXT:    [[T1:%.*]] = addrspacecast float addrspace(3)* [[TMP1]] to float*
+; CHECK-NEXT:    store float* [[T0]], float** [[OUT0:%.*]], align 4
+; CHECK-NEXT:    store float* [[T1]], float** [[OUT1:%.*]], align 4
+; CHECK-NEXT:    ret void
+;
+  %t0 = getelementptr [256 x float], [256 x float]* addrspacecast ([256 x float] addrspace(3)* @array to [256 x float]*), i64 0, i64 %i
+  %t1 = getelementptr [0 x float], [0 x float]* addrspacecast (float addrspace(3)* @scalar to [0 x float]*), i64 0, i64 %i
+  store float* %t0, float** %out0, align 4
+  store float* %t1, float** %out1, align 4
+  ret void
+}
+
+declare void @escape_alloca(i16*)
+
+; check that addrspacecast is not ignored (leading to an assertion failure)
+; when trying to mark a GEP as inbounds
+define { i8, i8 } @inbounds_after_addrspacecast() {
+; CHECK-LABEL: @inbounds_after_addrspacecast(
+; CHECK-NEXT:    [[T0:%.*]] = alloca i16, align 2
+; CHECK-NEXT:    call void @escape_alloca(i16* nonnull [[T0]])
+; CHECK-NEXT:    [[TMPCAST:%.*]] = bitcast i16* [[T0]] to [2 x i8]*
+; CHECK-NEXT:    [[T1:%.*]] = addrspacecast [2 x i8]* [[TMPCAST]] to [2 x i8] addrspace(11)*
+; CHECK-NEXT:    [[T2:%.*]] = getelementptr [2 x i8], [2 x i8] addrspace(11)* [[T1]], i64 0, i64 1
+; CHECK-NEXT:    [[T3:%.*]] = load i8, i8 addrspace(11)* [[T2]], align 1
+; CHECK-NEXT:    [[INSERT:%.*]] = insertvalue { i8, i8 } zeroinitializer, i8 [[T3]], 1
+; CHECK-NEXT:    ret { i8, i8 } [[INSERT]]
+;
+  %t0 = alloca i16, align 2
+  call void @escape_alloca(i16* %t0)
+  %tmpcast = bitcast i16* %t0 to [2 x i8]*
+  %t1 = addrspacecast [2 x i8]* %tmpcast to [2 x i8] addrspace(11)*
+  %t2 = getelementptr [2 x i8], [2 x i8] addrspace(11)* %t1, i64 0, i64 1
+  %t3 = load i8, i8 addrspace(11)* %t2, align 1
+  %insert = insertvalue { i8, i8 } zeroinitializer, i8 %t3, 1
+  ret { i8, i8 } %insert
+}
+
+
+declare spir_func <16 x i32> @my_extern_func()
+
+; check that a bitcast is not generated when we need an addrspace cast
+define void @bitcast_after_gep(<16 x i32>* %t0) {
+; CHECK-LABEL: @bitcast_after_gep(
+; CHECK-NEXT:    [[T4:%.*]] = addrspacecast <16 x i32>* [[T0:%.*]] to <16 x i32> addrspace(3)*
+; CHECK-NEXT:    [[CALL:%.*]] = call spir_func <16 x i32> @my_extern_func()
+; CHECK-NEXT:    store <16 x i32> [[CALL]], <16 x i32> addrspace(3)* [[T4]], align 64
+; CHECK-NEXT:    ret void
+;
+  %t1 = bitcast <16 x i32>* %t0 to [16 x i32]*
+  %t2 = addrspacecast [16 x i32]* %t1 to [16 x i32] addrspace(3)*
+  %t3 = getelementptr inbounds [16 x i32], [16 x i32] addrspace(3)* %t2, i64 0, i64 0
+  %t4 = bitcast i32 addrspace(3)* %t3 to <16 x i32> addrspace(3)*
+  %call = call spir_func <16 x i32> @my_extern_func()
+  store <16 x i32> %call, <16 x i32> addrspace(3)* %t4
+  ret void
+}

Added: llvm/trunk/test/Transforms/InstCombine/gep-combine-loop-invariant.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/gep-combine-loop-invariant.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/gep-combine-loop-invariant.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/gep-combine-loop-invariant.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,187 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt < %s -instcombine -S | FileCheck %s
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+define i32 @foo(i8* nocapture readnone %match, i32 %cur_match, i32 %best_len, i32 %scan_end, i32* nocapture readonly %prev, i32 %limit, i32 %chain_length, i8* nocapture readonly %win, i32 %wmask) {
+; CHECK-LABEL: @foo(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[IDX_EXT2:%.*]] = zext i32 [[CUR_MATCH:%.*]] to i64
+; CHECK-NEXT:    [[ADD_PTR4:%.*]] = getelementptr inbounds i8, i8* [[WIN:%.*]], i64 [[IDX_EXT2]]
+; CHECK-NEXT:    [[IDX_EXT1:%.*]] = zext i32 [[BEST_LEN:%.*]] to i64
+; CHECK-NEXT:    [[ADD_PTR25:%.*]] = getelementptr inbounds i8, i8* [[ADD_PTR4]], i64 [[IDX_EXT1]]
+; CHECK-NEXT:    [[ADD_PTR36:%.*]] = getelementptr inbounds i8, i8* [[ADD_PTR25]], i64 -1
+; CHECK-NEXT:    [[TMP0:%.*]] = bitcast i8* [[ADD_PTR36]] to i32*
+; CHECK-NEXT:    [[TMP1:%.*]] = load i32, i32* [[TMP0]], align 4
+; CHECK-NEXT:    [[CMP7:%.*]] = icmp eq i32 [[TMP1]], [[SCAN_END:%.*]]
+; CHECK-NEXT:    br i1 [[CMP7]], label [[DO_END:%.*]], label [[IF_THEN_LR_PH:%.*]]
+; CHECK:       if.then.lr.ph:
+; CHECK-NEXT:    br label [[IF_THEN:%.*]]
+; CHECK:       do.body:
+; CHECK-NEXT:    [[IDX_EXT:%.*]] = zext i32 [[TMP4:%.*]] to i64
+; CHECK-NEXT:    [[ADD_PTR:%.*]] = getelementptr inbounds i8, i8* [[WIN]], i64 [[IDX_EXT1]]
+; CHECK-NEXT:    [[ADD_PTR2:%.*]] = getelementptr inbounds i8, i8* [[ADD_PTR]], i64 -1
+; CHECK-NEXT:    [[ADD_PTR3:%.*]] = getelementptr inbounds i8, i8* [[ADD_PTR2]], i64 [[IDX_EXT]]
+; CHECK-NEXT:    [[TMP2:%.*]] = bitcast i8* [[ADD_PTR3]] to i32*
+; CHECK-NEXT:    [[TMP3:%.*]] = load i32, i32* [[TMP2]], align 4
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[TMP3]], [[SCAN_END]]
+; CHECK-NEXT:    br i1 [[CMP]], label [[DO_END]], label [[IF_THEN]]
+; CHECK:       if.then:
+; CHECK-NEXT:    [[CUR_MATCH_ADDR_09:%.*]] = phi i32 [ [[CUR_MATCH]], [[IF_THEN_LR_PH]] ], [ [[TMP4]], [[DO_BODY:%.*]] ]
+; CHECK-NEXT:    [[CHAIN_LENGTH_ADDR_08:%.*]] = phi i32 [ [[CHAIN_LENGTH:%.*]], [[IF_THEN_LR_PH]] ], [ [[DEC:%.*]], [[DO_BODY]] ]
+; CHECK-NEXT:    [[AND:%.*]] = and i32 [[CUR_MATCH_ADDR_09]], [[WMASK:%.*]]
+; CHECK-NEXT:    [[IDXPROM:%.*]] = zext i32 [[AND]] to i64
+; CHECK-NEXT:    [[ARRAYIDX:%.*]] = getelementptr inbounds i32, i32* [[PREV:%.*]], i64 [[IDXPROM]]
+; CHECK-NEXT:    [[TMP4]] = load i32, i32* [[ARRAYIDX]], align 4
+; CHECK-NEXT:    [[CMP4:%.*]] = icmp ugt i32 [[TMP4]], [[LIMIT:%.*]]
+; CHECK-NEXT:    br i1 [[CMP4]], label [[LAND_LHS_TRUE:%.*]], label [[DO_END]]
+; CHECK:       land.lhs.true:
+; CHECK-NEXT:    [[DEC]] = add i32 [[CHAIN_LENGTH_ADDR_08]], -1
+; CHECK-NEXT:    [[CMP5:%.*]] = icmp eq i32 [[DEC]], 0
+; CHECK-NEXT:    br i1 [[CMP5]], label [[DO_END]], label [[DO_BODY]]
+; CHECK:       do.end:
+; CHECK-NEXT:    [[CONT_0:%.*]] = phi i32 [ 1, [[ENTRY:%.*]] ], [ 0, [[IF_THEN]] ], [ 0, [[LAND_LHS_TRUE]] ], [ 1, [[DO_BODY]] ]
+; CHECK-NEXT:    ret i32 [[CONT_0]]
+;
+entry:
+  %idx.ext2 = zext i32 %cur_match to i64
+  %add.ptr4 = getelementptr inbounds i8, i8* %win, i64 %idx.ext2
+  %idx.ext1 = zext i32 %best_len to i64
+  %add.ptr25 = getelementptr inbounds i8, i8* %add.ptr4, i64 %idx.ext1
+  %add.ptr36 = getelementptr inbounds i8, i8* %add.ptr25, i64 -1
+  %0 = bitcast i8* %add.ptr36 to i32*
+  %1 = load i32, i32* %0, align 4
+  %cmp7 = icmp eq i32 %1, %scan_end
+  br i1 %cmp7, label %do.end, label %if.then.lr.ph
+
+if.then.lr.ph:                                    ; preds = %entry
+  br label %if.then
+
+do.body:                                          ; preds = %land.lhs.true
+  %chain_length.addr.0 = phi i32 [ %dec, %land.lhs.true ]
+  %cur_match.addr.0 = phi i32 [ %4, %land.lhs.true ]
+  %idx.ext = zext i32 %cur_match.addr.0 to i64
+  %add.ptr = getelementptr inbounds i8, i8* %win, i64 %idx.ext
+  %add.ptr2 = getelementptr inbounds i8, i8* %add.ptr, i64 %idx.ext1
+  %add.ptr3 = getelementptr inbounds i8, i8* %add.ptr2, i64 -1
+  %2 = bitcast i8* %add.ptr3 to i32*
+  %3 = load i32, i32* %2, align 4
+  %cmp = icmp eq i32 %3, %scan_end
+  br i1 %cmp, label %do.end, label %if.then
+
+if.then:                                          ; preds = %if.then.lr.ph, %do.body
+  %cur_match.addr.09 = phi i32 [ %cur_match, %if.then.lr.ph ], [ %cur_match.addr.0, %do.body ]
+  %chain_length.addr.08 = phi i32 [ %chain_length, %if.then.lr.ph ], [ %chain_length.addr.0, %do.body ]
+  %and = and i32 %cur_match.addr.09, %wmask
+  %idxprom = zext i32 %and to i64
+  %arrayidx = getelementptr inbounds i32, i32* %prev, i64 %idxprom
+  %4 = load i32, i32* %arrayidx, align 4
+  %cmp4 = icmp ugt i32 %4, %limit
+  br i1 %cmp4, label %land.lhs.true, label %do.end
+
+land.lhs.true:                                    ; preds = %if.then
+  %dec = add i32 %chain_length.addr.08, -1
+  %cmp5 = icmp eq i32 %dec, 0
+  br i1 %cmp5, label %do.end, label %do.body
+
+do.end:                                           ; preds = %do.body, %land.lhs.true, %if.then, %entry
+  %cont.0 = phi i32 [ 1, %entry ], [ 0, %if.then ], [ 0, %land.lhs.true ], [ 1, %do.body ]
+  ret i32 %cont.0
+}
+
+declare void @blackhole(<2 x i8*>)
+
+define void @PR37005(i8* %base, i8** %in) {
+; CHECK-LABEL: @PR37005(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    br label [[LOOP:%.*]]
+; CHECK:       loop:
+; CHECK-NEXT:    [[E2:%.*]] = getelementptr inbounds i8*, i8** [[IN:%.*]], i64 undef
+; CHECK-NEXT:    [[E4:%.*]] = getelementptr inbounds i8*, i8** [[E2]], <2 x i64> <i64 0, i64 1>
+; CHECK-NEXT:    [[PI1:%.*]] = ptrtoint <2 x i8**> [[E4]] to <2 x i64>
+; CHECK-NEXT:    [[LR1:%.*]] = lshr <2 x i64> [[PI1]], <i64 21, i64 21>
+; CHECK-NEXT:    [[SL1:%.*]] = shl nuw nsw <2 x i64> [[LR1]], <i64 7, i64 7>
+; CHECK-NEXT:    [[E51:%.*]] = getelementptr inbounds i8, i8* [[BASE:%.*]], i64 80
+; CHECK-NEXT:    [[E6:%.*]] = getelementptr inbounds i8, i8* [[E51]], <2 x i64> [[SL1]]
+; CHECK-NEXT:    call void @blackhole(<2 x i8*> [[E6]])
+; CHECK-NEXT:    br label [[LOOP]]
+;
+entry:
+  br label %loop
+
+loop:
+  %e1 = getelementptr inbounds i8*, i8** %in, i64 undef
+  %e2 = getelementptr inbounds i8*, i8** %e1, i64 6
+  %bc1 = bitcast i8** %e2 to <2 x i8*>*
+  %e3 = getelementptr inbounds <2 x i8*>, <2 x i8*>* %bc1, i64 0, i64 0
+  %e4 = getelementptr inbounds i8*, i8** %e3, <2 x i64> <i64 0, i64 1>
+  %pi1 = ptrtoint <2 x i8**> %e4 to <2 x i64>
+  %lr1 = lshr <2 x i64> %pi1, <i64 21, i64 21>
+  %sl1 = shl nuw nsw <2 x i64> %lr1, <i64 7, i64 7>
+  %e5 = getelementptr inbounds i8, i8* %base, <2 x i64> %sl1
+  %e6 = getelementptr inbounds i8, <2 x i8*> %e5, i64 80
+  call void @blackhole(<2 x i8*> %e6)
+  br label %loop
+}
+
+define void @PR37005_2(i8* %base, i8** %in) {
+; CHECK-LABEL: @PR37005_2(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    br label [[LOOP:%.*]]
+; CHECK:       loop:
+; CHECK-NEXT:    [[E2:%.*]] = getelementptr inbounds i8*, i8** [[IN:%.*]], i64 undef
+; CHECK-NEXT:    [[PI1:%.*]] = ptrtoint i8** [[E2]] to i64
+; CHECK-NEXT:    [[LR1:%.*]] = lshr i64 [[PI1]], 21
+; CHECK-NEXT:    [[SL1:%.*]] = shl nuw nsw i64 [[LR1]], 7
+; CHECK-NEXT:    [[E51:%.*]] = getelementptr inbounds i8, i8* [[BASE:%.*]], <2 x i64> <i64 80, i64 60>
+; CHECK-NEXT:    [[E6:%.*]] = getelementptr inbounds i8, <2 x i8*> [[E51]], i64 [[SL1]]
+; CHECK-NEXT:    call void @blackhole(<2 x i8*> [[E6]])
+; CHECK-NEXT:    br label [[LOOP]]
+;
+entry:
+  br label %loop
+
+loop:
+  %e1 = getelementptr inbounds i8*, i8** %in, i64 undef
+  %e2 = getelementptr inbounds i8*, i8** %e1, i64 6
+  %pi1 = ptrtoint i8** %e2 to i64
+  %lr1 = lshr i64 %pi1, 21
+  %sl1 = shl nuw nsw i64 %lr1, 7
+  %e5 = getelementptr inbounds i8, i8* %base, i64 %sl1
+  %e6 = getelementptr inbounds i8, i8* %e5, <2 x i64> <i64 80, i64 60>
+  call void @blackhole(<2 x i8*> %e6)
+  br label %loop
+}
+
+define void @PR37005_3(<2 x i8*> %base, i8** %in) {
+; CHECK-LABEL: @PR37005_3(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    br label [[LOOP:%.*]]
+; CHECK:       loop:
+; CHECK-NEXT:    [[E2:%.*]] = getelementptr inbounds i8*, i8** [[IN:%.*]], i64 undef
+; CHECK-NEXT:    [[E4:%.*]] = getelementptr inbounds i8*, i8** [[E2]], <2 x i64> <i64 0, i64 1>
+; CHECK-NEXT:    [[PI1:%.*]] = ptrtoint <2 x i8**> [[E4]] to <2 x i64>
+; CHECK-NEXT:    [[LR1:%.*]] = lshr <2 x i64> [[PI1]], <i64 21, i64 21>
+; CHECK-NEXT:    [[SL1:%.*]] = shl nuw nsw <2 x i64> [[LR1]], <i64 7, i64 7>
+; CHECK-NEXT:    [[E5:%.*]] = getelementptr inbounds i8, <2 x i8*> [[BASE:%.*]], i64 80
+; CHECK-NEXT:    [[E6:%.*]] = getelementptr inbounds i8, <2 x i8*> [[E5]], <2 x i64> [[SL1]]
+; CHECK-NEXT:    call void @blackhole(<2 x i8*> [[E6]])
+; CHECK-NEXT:    br label [[LOOP]]
+;
+entry:
+  br label %loop
+
+loop:
+  %e1 = getelementptr inbounds i8*, i8** %in, i64 undef
+  %e2 = getelementptr inbounds i8*, i8** %e1, i64 6
+  %bc1 = bitcast i8** %e2 to <2 x i8*>*
+  %e3 = getelementptr inbounds <2 x i8*>, <2 x i8*>* %bc1, i64 0, i64 0
+  %e4 = getelementptr inbounds i8*, i8** %e3, <2 x i64> <i64 0, i64 1>
+  %pi1 = ptrtoint <2 x i8**> %e4 to <2 x i64>
+  %lr1 = lshr <2 x i64> %pi1, <i64 21, i64 21>
+  %sl1 = shl nuw nsw <2 x i64> %lr1, <i64 7, i64 7>
+  %e5 = getelementptr inbounds i8, <2 x i8*> %base, <2 x i64> %sl1
+  %e6 = getelementptr inbounds i8, <2 x i8*> %e5, i64 80
+  call void @blackhole(<2 x i8*> %e6)
+  br label %loop
+}

Added: llvm/trunk/test/Transforms/InstCombine/gep-custom-dl.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/gep-custom-dl.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/gep-custom-dl.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/gep-custom-dl.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,154 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt < %s -instcombine -S | FileCheck %s
+
+target datalayout = "e-m:m-p:40:64:64:32-i32:32-i16:16-i8:8-n32"
+
+%struct.B = type { double }
+%struct.A = type { %struct.B, i32, i32 }
+%struct.C = type { [7 x i8] }
+
+
+ at Global = external global [10 x i8]
+
+; Test that two array indexing geps fold
+define i32* @test1(i32* %I) {
+; CHECK-LABEL: @test1(
+; CHECK-NEXT:    [[B:%.*]] = getelementptr i32, i32* [[I:%.*]], i32 21
+; CHECK-NEXT:    ret i32* [[B]]
+;
+  %A = getelementptr i32, i32* %I, i8 17
+  %B = getelementptr i32, i32* %A, i16 4
+  ret i32* %B
+}
+
+; Test that two getelementptr insts fold
+define i32* @test2({ i32 }* %I) {
+; CHECK-LABEL: @test2(
+; CHECK-NEXT:    [[B:%.*]] = getelementptr { i32 }, { i32 }* [[I:%.*]], i32 1, i32 0
+; CHECK-NEXT:    ret i32* [[B]]
+;
+  %A = getelementptr { i32 }, { i32 }* %I, i32 1
+  %B = getelementptr { i32 }, { i32 }* %A, i32 0, i32 0
+  ret i32* %B
+}
+
+define void @test3(i8 %B) {
+; This should be turned into a constexpr instead of being an instruction
+; CHECK-LABEL: @test3(
+; CHECK-NEXT:    store i8 [[B:%.*]], i8* getelementptr inbounds ([10 x i8], [10 x i8]* @Global, i32 0, i32 4), align 1
+; CHECK-NEXT:    ret void
+;
+  %A = getelementptr [10 x i8], [10 x i8]* @Global, i32 0, i32 4
+  store i8 %B, i8* %A
+  ret void
+}
+
+%as1_ptr_struct = type { i32 addrspace(1)* }
+%as2_ptr_struct = type { i32 addrspace(2)* }
+
+ at global_as2 = addrspace(2) global i32 zeroinitializer
+ at global_as1_as2_ptr = addrspace(1) global %as2_ptr_struct { i32 addrspace(2)* @global_as2 }
+
+; This should be turned into a constexpr instead of being an instruction
+define void @test_evaluate_gep_nested_as_ptrs(i32 addrspace(2)* %B) {
+; CHECK-LABEL: @test_evaluate_gep_nested_as_ptrs(
+; CHECK-NEXT:    store i32 addrspace(2)* [[B:%.*]], i32 addrspace(2)* addrspace(1)* getelementptr inbounds (%as2_ptr_struct, [[AS2_PTR_STRUCT:%.*]] addrspace(1)* @global_as1_as2_ptr, i32 0, i32 0), align 8
+; CHECK-NEXT:    ret void
+;
+  %A = getelementptr %as2_ptr_struct, %as2_ptr_struct addrspace(1)* @global_as1_as2_ptr, i32 0, i32 0
+  store i32 addrspace(2)* %B, i32 addrspace(2)* addrspace(1)* %A
+  ret void
+}
+
+ at arst = addrspace(1) global [4 x i8 addrspace(2)*] zeroinitializer
+
+define void @test_evaluate_gep_as_ptrs_array(i8 addrspace(2)* %B) {
+; CHECK-LABEL: @test_evaluate_gep_as_ptrs_array(
+; CHECK-NEXT:    store i8 addrspace(2)* [[B:%.*]], i8 addrspace(2)* addrspace(1)* getelementptr inbounds ([4 x i8 addrspace(2)*], [4 x i8 addrspace(2)*] addrspace(1)* @arst, i32 0, i32 2), align 16
+; CHECK-NEXT:    ret void
+;
+
+  %A = getelementptr [4 x i8 addrspace(2)*], [4 x i8 addrspace(2)*] addrspace(1)* @arst, i16 0, i16 2
+  store i8 addrspace(2)* %B, i8 addrspace(2)* addrspace(1)* %A
+  ret void
+}
+
+define i32* @test4(i32* %I, i32 %C, i32 %D) {
+; CHECK-LABEL: @test4(
+; CHECK-NEXT:    [[A:%.*]] = getelementptr i32, i32* [[I:%.*]], i32 [[C:%.*]]
+; CHECK-NEXT:    [[B:%.*]] = getelementptr i32, i32* [[A]], i32 [[D:%.*]]
+; CHECK-NEXT:    ret i32* [[B]]
+;
+  %A = getelementptr i32, i32* %I, i32 %C
+  %B = getelementptr i32, i32* %A, i32 %D
+  ret i32* %B
+}
+
+
+define i1 @test5({ i32, i32 }* %x, { i32, i32 }* %y) {
+; CHECK-LABEL: @test5(
+; CHECK-NEXT:    [[TMP_4:%.*]] = icmp eq { i32, i32 }* [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    ret i1 [[TMP_4]]
+;
+  %tmp.1 = getelementptr { i32, i32 }, { i32, i32 }* %x, i32 0, i32 1
+  %tmp.3 = getelementptr { i32, i32 }, { i32, i32 }* %y, i32 0, i32 1
+  ;; seteq x, y
+  %tmp.4 = icmp eq i32* %tmp.1, %tmp.3
+  ret i1 %tmp.4
+}
+
+%S = type { i32, [ 100 x i32] }
+
+define <2 x i1> @test6(<2 x i32> %X, <2 x %S*> %P) nounwind {
+; CHECK-LABEL: @test6(
+; CHECK-NEXT:    [[C:%.*]] = icmp eq <2 x i32> [[X:%.*]], <i32 1073741823, i32 1073741823>
+; CHECK-NEXT:    ret <2 x i1> [[C]]
+;
+  %A = getelementptr inbounds %S, <2 x %S*> %P, <2 x i32> zeroinitializer, <2 x i32> <i32 1, i32 1>, <2 x i32> %X
+  %B = getelementptr inbounds %S, <2 x %S*> %P, <2 x i32> <i32 0, i32 0>, <2 x i32> <i32 0, i32 0>
+  %C = icmp eq <2 x i32*> %A, %B
+  ret <2 x i1> %C
+}
+
+ at G = external global [3 x i8]
+define i8* @test7(i16 %Idx) {
+; CHECK-LABEL: @test7(
+; CHECK-NEXT:    [[ZE_IDX:%.*]] = zext i16 [[IDX:%.*]] to i32
+; CHECK-NEXT:    [[TMP:%.*]] = getelementptr [3 x i8], [3 x i8]* @G, i32 0, i32 [[ZE_IDX]]
+; CHECK-NEXT:    ret i8* [[TMP]]
+;
+  %ZE_Idx = zext i16 %Idx to i32
+  %tmp = getelementptr i8, i8* getelementptr ([3 x i8], [3 x i8]* @G, i32 0, i32 0), i32 %ZE_Idx
+  ret i8* %tmp
+}
+
+
+; Test folding of constantexpr geps into normal geps.
+ at Array = external global [40 x i32]
+define i32 *@test8(i32 %X) {
+; CHECK-LABEL: @test8(
+; CHECK-NEXT:    [[A:%.*]] = getelementptr [40 x i32], [40 x i32]* @Array, i32 0, i32 [[X:%.*]]
+; CHECK-NEXT:    ret i32* [[A]]
+;
+  %A = getelementptr i32, i32* getelementptr ([40 x i32], [40 x i32]* @Array, i32 0, i32 0), i32 %X
+  ret i32* %A
+}
+
+define i32 *@test9(i32 *%base, i8 %ind) {
+; CHECK-LABEL: @test9(
+; CHECK-NEXT:    [[TMP1:%.*]] = sext i8 [[IND:%.*]] to i32
+; CHECK-NEXT:    [[RES:%.*]] = getelementptr i32, i32* [[BASE:%.*]], i32 [[TMP1]]
+; CHECK-NEXT:    ret i32* [[RES]]
+;
+  %res = getelementptr i32, i32 *%base, i8 %ind
+  ret i32* %res
+}
+
+define i32 @test10() {
+; CHECK-LABEL: @test10(
+; CHECK-NEXT:    ret i32 8
+;
+  %A = getelementptr { i32, double }, { i32, double }* null, i32 0, i32 1
+  %B = ptrtoint double* %A to i32
+  ret i32 %B
+}

Added: llvm/trunk/test/Transforms/InstCombine/gep-sext.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/gep-sext.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/gep-sext.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/gep-sext.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,61 @@
+; 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"
+target triple = "x86_64-pc-win32"
+
+declare void @use(i32) readonly
+
+; We prefer to canonicalize the machine width gep indices early
+define void @test(i32* %p, i32 %index) {
+; CHECK-LABEL: @test
+; CHECK-NEXT: %1 = sext i32 %index to i64
+; CHECK-NEXT: %addr = getelementptr i32, i32* %p, i64 %1
+  %addr = getelementptr i32, i32* %p, i32 %index
+  %val = load i32, i32* %addr
+  call void @use(i32 %val)
+  ret void
+}
+; If they've already been canonicalized via zext, that's fine
+define void @test2(i32* %p, i32 %index) {
+; CHECK-LABEL: @test2
+; CHECK-NEXT: %i = zext i32 %index to i64
+; CHECK-NEXT: %addr = getelementptr i32, i32* %p, i64 %i
+  %i = zext i32 %index to i64
+  %addr = getelementptr i32, i32* %p, i64 %i
+  %val = load i32, i32* %addr
+  call void @use(i32 %val)
+  ret void
+}
+; If we can use a zext, we prefer that.  This requires
+; knowing that the index is positive.
+define void @test3(i32* %p, i32 %index) {
+; CHECK-LABEL: @test3
+; CHECK:   zext
+; CHECK-NOT: sext
+  %addr_begin = getelementptr i32, i32* %p, i64 40
+  %addr_fixed = getelementptr i32, i32* %addr_begin, i64 48
+  %val_fixed = load i32, i32* %addr_fixed, !range !0
+  %addr = getelementptr i32, i32* %addr_begin, i32 %val_fixed
+  %val = load i32, i32* %addr
+  call void @use(i32 %val)
+  ret void
+}
+; Replace sext with zext where possible
+define void @test4(i32* %p, i32 %index) {
+; CHECK-LABEL: @test4
+; CHECK:   zext
+; CHECK-NOT: sext
+  %addr_begin = getelementptr i32, i32* %p, i64 40
+  %addr_fixed = getelementptr i32, i32* %addr_begin, i64 48
+  %val_fixed = load i32, i32* %addr_fixed, !range !0
+  %i = sext i32 %val_fixed to i64
+  %addr = getelementptr i32, i32* %addr_begin, i64 %i
+  %val = load i32, i32* %addr
+  call void @use(i32 %val)
+  ret void
+}
+
+;;  !range !0
+!0 = !{i32 0, i32 2147483647}
+
+
+

Added: llvm/trunk/test/Transforms/InstCombine/gep-vector.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/gep-vector.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/gep-vector.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/gep-vector.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,72 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt -instcombine %s -S | FileCheck %s
+
+ at block = global [64 x [8192 x i8]] zeroinitializer, align 1
+
+define <2 x i8*> @vectorindex1() {
+; CHECK-LABEL: @vectorindex1(
+; CHECK-NEXT:    ret <2 x i8*> getelementptr inbounds ([64 x [8192 x i8]], [64 x [8192 x i8]]* @block, <2 x i64> zeroinitializer, <2 x i64> <i64 1, i64 2>, <2 x i64> zeroinitializer)
+;
+  %1 = getelementptr inbounds [64 x [8192 x i8]], [64 x [8192 x i8]]* @block, i64 0, <2 x i64> <i64 0, i64 1>, i64 8192
+  ret <2 x i8*> %1
+}
+
+define <2 x i8*> @vectorindex2() {
+; CHECK-LABEL: @vectorindex2(
+; CHECK-NEXT:    ret <2 x i8*> getelementptr inbounds ([64 x [8192 x i8]], [64 x [8192 x i8]]* @block, <2 x i64> zeroinitializer, <2 x i64> <i64 1, i64 2>, <2 x i64> <i64 8191, i64 1>)
+;
+  %1 = getelementptr inbounds [64 x [8192 x i8]], [64 x [8192 x i8]]* @block, i64 0, i64 1, <2 x i64> <i64 8191, i64 8193>
+  ret <2 x i8*> %1
+}
+
+define <2 x i8*> @vectorindex3() {
+; CHECK-LABEL: @vectorindex3(
+; CHECK-NEXT:    ret <2 x i8*> getelementptr inbounds ([64 x [8192 x i8]], [64 x [8192 x i8]]* @block, <2 x i64> zeroinitializer, <2 x i64> <i64 0, i64 2>, <2 x i64> <i64 8191, i64 1>)
+;
+  %1 = getelementptr inbounds [64 x [8192 x i8]], [64 x [8192 x i8]]* @block, i64 0, <2 x i64> <i64 0, i64 1>, <2 x i64> <i64 8191, i64 8193>
+  ret <2 x i8*> %1
+}
+
+define i32* @bitcast_vec_to_array_gep(<7 x i32>* %x, i64 %y, i64 %z) {
+; CHECK-LABEL: @bitcast_vec_to_array_gep(
+; CHECK-NEXT:    [[GEP:%.*]] = getelementptr <7 x i32>, <7 x i32>* [[X:%.*]], i64 [[Y:%.*]], i64 [[Z:%.*]]
+; CHECK-NEXT:    ret i32* [[GEP]]
+;
+  %arr_ptr = bitcast <7 x i32>* %x to [7 x i32]*
+  %gep = getelementptr [7 x i32], [7 x i32]* %arr_ptr, i64 %y, i64 %z
+  ret i32* %gep
+}
+
+define i32* @bitcast_array_to_vec_gep([3 x i32]* %x, i64 %y, i64 %z) {
+; CHECK-LABEL: @bitcast_array_to_vec_gep(
+; CHECK-NEXT:    [[GEP:%.*]] = getelementptr inbounds [3 x i32], [3 x i32]* [[X:%.*]], i64 [[Y:%.*]], i64 [[Z:%.*]]
+; CHECK-NEXT:    ret i32* [[GEP]]
+;
+  %vec_ptr = bitcast [3 x i32]* %x to <3 x i32>*
+  %gep = getelementptr inbounds <3 x i32>, <3 x i32>* %vec_ptr, i64 %y, i64 %z
+  ret i32* %gep
+}
+
+define i32 addrspace(3)* @bitcast_vec_to_array_addrspace(<7 x i32>* %x, i64 %y, i64 %z) {
+; CHECK-LABEL: @bitcast_vec_to_array_addrspace(
+; CHECK-NEXT:    [[GEP:%.*]] = getelementptr <7 x i32>, <7 x i32>* [[X:%.*]], i64 [[Y:%.*]], i64 [[Z:%.*]]
+; CHECK-NEXT:    [[TMP1:%.*]] = addrspacecast i32* [[GEP]] to i32 addrspace(3)*
+; CHECK-NEXT:    ret i32 addrspace(3)* [[TMP1]]
+;
+  %arr_ptr = bitcast <7 x i32>* %x to [7 x i32]*
+  %asc = addrspacecast [7 x i32]* %arr_ptr to [7 x i32] addrspace(3)*
+  %gep = getelementptr [7 x i32], [7 x i32] addrspace(3)* %asc, i64 %y, i64 %z
+  ret i32 addrspace(3)* %gep
+}
+
+define i32 addrspace(3)* @inbounds_bitcast_vec_to_array_addrspace(<7 x i32>* %x, i64 %y, i64 %z) {
+; CHECK-LABEL: @inbounds_bitcast_vec_to_array_addrspace(
+; CHECK-NEXT:    [[GEP:%.*]] = getelementptr inbounds <7 x i32>, <7 x i32>* [[X:%.*]], i64 [[Y:%.*]], i64 [[Z:%.*]]
+; CHECK-NEXT:    [[TMP1:%.*]] = addrspacecast i32* [[GEP]] to i32 addrspace(3)*
+; CHECK-NEXT:    ret i32 addrspace(3)* [[TMP1]]
+;
+  %arr_ptr = bitcast <7 x i32>* %x to [7 x i32]*
+  %asc = addrspacecast [7 x i32]* %arr_ptr to [7 x i32] addrspace(3)*
+  %gep = getelementptr inbounds [7 x i32], [7 x i32] addrspace(3)* %asc, i64 %y, i64 %z
+  ret i32 addrspace(3)* %gep
+}

Added: llvm/trunk/test/Transforms/InstCombine/gepgep.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/gepgep.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/gepgep.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/gepgep.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,13 @@
+; RUN: opt < %s -instcombine -disable-output
+
+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"
+target triple = "x86_64-unknown-linux-gnu"
+
+ at buffer = external global [64 x float]
+
+declare void @use(i8*)
+
+define void @f() {
+  call void @use(i8* getelementptr (i8, i8* getelementptr (i8, i8* bitcast ([64 x float]* @buffer to i8*), i64 and (i64 sub (i64 0, i64 ptrtoint ([64 x float]* @buffer to i64)), i64 63)), i64 64))
+  ret void
+}

Added: llvm/trunk/test/Transforms/InstCombine/gepphigep.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/gepphigep.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/gepphigep.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/gepphigep.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,186 @@
+; RUN: opt -instcombine -S  < %s | FileCheck %s
+
+%struct1 = type { %struct2*, i32, i32, i32 }
+%struct2 = type { i32, i32 }
+%struct3 = type { i32, %struct4, %struct4 }
+%struct4 = type { %struct2, %struct2 }
+
+define i32 @test1(%struct1* %dm, i1 %tmp4, i64 %tmp9, i64 %tmp19) {
+bb:
+  %tmp = getelementptr inbounds %struct1, %struct1* %dm, i64 0, i32 0
+  %tmp1 = load %struct2*, %struct2** %tmp, align 8
+  br i1 %tmp4, label %bb1, label %bb2
+
+bb1:
+  %tmp10 = getelementptr inbounds %struct2, %struct2* %tmp1, i64 %tmp9
+  %tmp11 = getelementptr inbounds %struct2, %struct2* %tmp10, i64 0, i32 0
+  store i32 0, i32* %tmp11, align 4
+  br label %bb3
+
+bb2:
+  %tmp20 = getelementptr inbounds %struct2, %struct2* %tmp1, i64 %tmp19
+  %tmp21 = getelementptr inbounds %struct2, %struct2* %tmp20, i64 0, i32 0
+  store i32 0, i32* %tmp21, align 4
+  br label %bb3
+
+bb3:
+  %phi = phi %struct2* [ %tmp10, %bb1 ], [ %tmp20, %bb2 ]
+  %tmp24 = getelementptr inbounds %struct2, %struct2* %phi, i64 0, i32 1
+  %tmp25 = load i32, i32* %tmp24, align 4
+  ret i32 %tmp25
+
+; CHECK-LABEL: @test1(
+; CHECK: getelementptr inbounds %struct2, %struct2* %tmp1, i64 %tmp9, i32 0
+; CHECK: getelementptr inbounds %struct2, %struct2* %tmp1, i64 %tmp19, i32 0
+; CHECK: %[[PHI:[0-9A-Za-z]+]] = phi i64 [ %tmp9, %bb1 ], [ %tmp19, %bb2 ]
+; CHECK: getelementptr inbounds %struct2, %struct2* %tmp1, i64 %[[PHI]], i32 1
+
+}
+
+define i32 @test2(%struct1* %dm, i1 %tmp4, i64 %tmp9, i64 %tmp19) {
+bb:
+  %tmp = getelementptr inbounds %struct1, %struct1* %dm, i64 0, i32 0
+  %tmp1 = load %struct2*, %struct2** %tmp, align 8
+  %tmp10 = getelementptr inbounds %struct2, %struct2* %tmp1, i64 %tmp9
+  %tmp11 = getelementptr inbounds %struct2, %struct2* %tmp10, i64 0, i32 0
+  store i32 0, i32* %tmp11, align 4
+  %tmp20 = getelementptr inbounds %struct2, %struct2* %tmp1, i64 %tmp19
+  %tmp21 = getelementptr inbounds %struct2, %struct2* %tmp20, i64 0, i32 0
+  store i32 0, i32* %tmp21, align 4
+  %tmp24 = getelementptr inbounds %struct2, %struct2* %tmp10, i64 0, i32 1
+  %tmp25 = load i32, i32* %tmp24, align 4
+  ret i32 %tmp25
+
+; CHECK-LABEL: @test2(
+; CHECK: getelementptr inbounds %struct2, %struct2* %tmp1, i64 %tmp9, i32 0
+; CHECK: getelementptr inbounds %struct2, %struct2* %tmp1, i64 %tmp19, i32 0
+; CHECK: getelementptr inbounds %struct2, %struct2* %tmp1, i64 %tmp9, i32 1
+}
+
+; Check that instcombine doesn't insert GEPs before landingpad.
+
+define i32 @test3(%struct3* %dm, i1 %tmp4, i64 %tmp9, i64 %tmp19, i64 %tmp20, i64 %tmp21) personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) {
+bb:
+  %tmp = getelementptr inbounds %struct3, %struct3* %dm, i64 0
+  br i1 %tmp4, label %bb1, label %bb2
+
+bb1:
+  %tmp1 = getelementptr inbounds %struct3, %struct3* %tmp, i64 %tmp19, i32 1
+  %tmp11 = getelementptr inbounds %struct4, %struct4* %tmp1, i64 0, i32 0, i32 0
+  store i32 0, i32* %tmp11, align 4
+  br label %bb3
+
+bb2:
+  %tmp2 = getelementptr inbounds %struct3, %struct3* %tmp, i64 %tmp20, i32 1
+  %tmp12 = getelementptr inbounds %struct4, %struct4* %tmp2, i64 0, i32 0, i32 1
+  store i32 0, i32* %tmp12, align 4
+  br label %bb3
+
+bb3:
+  %phi = phi %struct4* [ %tmp1, %bb1 ], [ %tmp2, %bb2 ]
+  %tmp22 = invoke i32 @foo1(i32 11) to label %bb4 unwind label %bb5
+
+bb4:
+  ret i32 0
+
+bb5:
+  %tmp27 = landingpad { i8*, i32 } catch i8* bitcast (i8** @_ZTIi to i8*)
+  %tmp34 = getelementptr inbounds %struct4, %struct4* %phi, i64 %tmp21, i32 1
+  %tmp35 = getelementptr inbounds %struct2, %struct2* %tmp34, i64 0, i32 1
+  %tmp25 = load i32, i32* %tmp35, align 4
+  ret i32 %tmp25
+
+; CHECK-LABEL: @test3(
+; CHECK: bb5:
+; CHECK-NEXT: {{.*}}landingpad { i8*, i32 }
+}
+
+ at _ZTIi = external constant i8*
+declare i32 @__gxx_personality_v0(...)
+declare i32 @foo1(i32)
+
+
+; Check that instcombine doesn't fold GEPs into themselves through a loop
+; back-edge.
+
+define i8* @test4(i32 %value, i8* %buffer) {
+entry:
+  %incptr = getelementptr inbounds i8, i8* %buffer, i64 1
+  %cmp = icmp ugt i32 %value, 127
+  br i1 %cmp, label %loop.header, label %exit
+
+loop.header:
+  br label %loop.body
+
+loop.body:
+  %loopptr = phi i8* [ %incptr, %loop.header ], [ %incptr2, %loop.body ]
+  %newval = phi i32 [ %value, %loop.header ], [ %shr, %loop.body ]
+  %shr = lshr i32 %newval, 7
+  %incptr2 = getelementptr inbounds i8, i8* %loopptr, i64 1
+  %cmp2 = icmp ugt i32 %shr, 127
+  br i1 %cmp2, label %loop.body, label %loop.exit
+
+loop.exit:
+  %exitptr = phi i8* [ %incptr2, %loop.body ]
+  br label %exit
+
+exit:
+  %ptr2 = phi i8* [ %exitptr, %loop.exit ], [ %incptr, %entry ]
+  %incptr3 = getelementptr inbounds i8, i8* %ptr2, i64 1
+  ret i8* %incptr3
+
+; CHECK-LABEL: @test4(
+; CHECK: loop.body:
+; CHECK: getelementptr{{.*}}i64 1
+; CHECK: exit:
+}
+
+ at .str.4 = external unnamed_addr constant [100 x i8], align 1
+
+; Instcombine shouldn't add new PHI nodes while folding GEPs if that will leave
+; old PHI nodes behind as this is not clearly beneficial.
+; CHECK-LABEL: @test5(
+define void @test5(i16 *%idx, i8 **%in) #0 {
+entry:
+  %0 = load i8*, i8** %in
+  %incdec.ptr = getelementptr inbounds i8, i8* %0, i32 1
+  %1 = load i8, i8* %incdec.ptr, align 1
+  %cmp23 = icmp eq i8 %1, 54
+  br i1 %cmp23, label %while.cond, label %if.then.25
+
+if.then.25:
+  call void @g(i8* getelementptr inbounds ([100 x i8], [100 x i8]* @.str.4, i32 0, i32 0))
+  br label %while.cond
+
+while.cond:
+; CHECK-LABEL: while.cond
+; CHECK-NOT: phi i8* [ %0, %entry ], [ %Ptr, %while.body ], [ %0, %if.then.25 ]
+  %Ptr = phi i8* [ %incdec.ptr, %entry ], [ %incdec.ptr32, %while.body], [%incdec.ptr, %if.then.25 ]
+  %2 = load i8, i8* %Ptr
+  %and = and i8 %2, 64
+  %lnot = icmp eq i8 %and, 0
+  br i1 %lnot, label %while.body, label %while.cond.33
+
+while.body:
+  %incdec.ptr32 = getelementptr inbounds i8, i8* %Ptr, i32 1
+  br label %while.cond
+
+while.cond.33:
+  %incdec.ptr34 = getelementptr inbounds i8, i8* %Ptr, i32 1
+  br label %while.cond.57
+
+while.cond.57:
+  %3 = load i8, i8* %incdec.ptr34, align 1
+  %conv59 = zext i8 %3 to i32
+  %arrayidx61 = getelementptr inbounds i16, i16* %idx, i32 %conv59
+  %4 = load i16, i16* %arrayidx61, align 2
+  %and63 = and i16 %4, 2048
+  %tobool64 = icmp eq i16 %and63, 0
+  br i1 %tobool64, label %while.cond.73, label %while.cond.57
+
+while.cond.73:
+  br label %while.cond.73
+
+}
+
+declare void @g(i8*)

Added: llvm/trunk/test/Transforms/InstCombine/getelementptr-folding.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/getelementptr-folding.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/getelementptr-folding.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/getelementptr-folding.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,13 @@
+; RUN: opt -instcombine -S < %s | FileCheck %s
+
+%struct.matrix_float3x3 = type { [3 x <3 x float>] }
+
+; We used to fold this by rewriting the indices to 0, 0, 2, 0.  This is
+; invalid because there is a 4-byte padding after each <3 x float> field.
+
+target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-apple-macosx10.11.0"
+
+ at matrix_identity_float3x3 = external global %struct.matrix_float3x3, align 16
+ at bbb = global float* getelementptr inbounds (%struct.matrix_float3x3, %struct.matrix_float3x3* @matrix_identity_float3x3, i64 0, i32 0, i64 1, i64 3)
+; CHECK: @bbb = global float* getelementptr inbounds (%struct.matrix_float3x3, %struct.matrix_float3x3* @matrix_identity_float3x3, i64 0, i32 0, i64 1, i64 3)

Added: llvm/trunk/test/Transforms/InstCombine/getelementptr.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/getelementptr.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/getelementptr.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/getelementptr.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,945 @@
+; RUN: opt < %s -instcombine -S | FileCheck %s
+
+target datalayout = "e-p:64:64-p1:16:16-p2:32:32:32-p3:64:64:64"
+
+%intstruct = type { i32 }
+%pair = type { i32, i32 }
+%struct.B = type { double }
+%struct.A = type { %struct.B, i32, i32 }
+%struct.C = type { [7 x i8] }
+
+
+ at Global = external global [10 x i8]
+ at Global_as1 = external addrspace(1) global [10 x i8]
+
+; Test noop elimination
+define i32* @test1(i32* %I) {
+        %A = getelementptr i32, i32* %I, i64 0
+        ret i32* %A
+; CHECK-LABEL: @test1(
+; CHECK: ret i32* %I
+}
+
+define i32 addrspace(1)* @test1_as1(i32 addrspace(1)* %I) {
+  %A = getelementptr i32, i32 addrspace(1)* %I, i64 0
+  ret i32 addrspace(1)* %A
+; CHECK-LABEL: @test1_as1(
+; CHECK: ret i32 addrspace(1)* %I
+}
+
+; Test noop elimination
+define i32* @test2(i32* %I) {
+        %A = getelementptr i32, i32* %I
+        ret i32* %A
+; CHECK-LABEL: @test2(
+; CHECK: ret i32* %I
+}
+
+; Test that two array indexing geps fold
+define i32* @test3(i32* %I) {
+        %A = getelementptr i32, i32* %I, i64 17
+        %B = getelementptr i32, i32* %A, i64 4
+        ret i32* %B
+; CHECK-LABEL: @test3(
+; CHECK: getelementptr i32, i32* %I, i64 21
+}
+
+; Test that two getelementptr insts fold
+define i32* @test4({ i32 }* %I) {
+        %A = getelementptr { i32 }, { i32 }* %I, i64 1
+        %B = getelementptr { i32 }, { i32 }* %A, i64 0, i32 0
+        ret i32* %B
+; CHECK-LABEL: @test4(
+; CHECK: getelementptr { i32 }, { i32 }* %I, i64 1, i32 0
+}
+
+define void @test5(i8 %B) {
+        ; This should be turned into a constexpr instead of being an instruction
+        %A = getelementptr [10 x i8], [10 x i8]* @Global, i64 0, i64 4
+        store i8 %B, i8* %A
+        ret void
+; CHECK-LABEL: @test5(
+; CHECK: store i8 %B, i8* getelementptr inbounds ([10 x i8], [10 x i8]* @Global, i64 0, i64 4)
+}
+
+define void @test5_as1(i8 %B) {
+        ; This should be turned into a constexpr instead of being an instruction
+        %A = getelementptr [10 x i8], [10 x i8] addrspace(1)* @Global_as1, i16 0, i16 4
+        store i8 %B, i8 addrspace(1)* %A
+        ret void
+; CHECK-LABEL: @test5_as1(
+; CHECK: store i8 %B, i8 addrspace(1)* getelementptr inbounds ([10 x i8], [10 x i8] addrspace(1)* @Global_as1, i16 0, i16 4)
+}
+
+%as1_ptr_struct = type { i32 addrspace(1)* }
+%as2_ptr_struct = type { i32 addrspace(2)* }
+
+ at global_as2 = addrspace(2) global i32 zeroinitializer
+ at global_as1_as2_ptr = addrspace(1) global %as2_ptr_struct { i32 addrspace(2)* @global_as2 }
+
+; This should be turned into a constexpr instead of being an instruction
+define void @test_evaluate_gep_nested_as_ptrs(i32 addrspace(2)* %B) {
+; CHECK-LABEL: @test_evaluate_gep_nested_as_ptrs(
+; CHECK-NEXT: store i32 addrspace(2)* %B, i32 addrspace(2)* addrspace(1)* getelementptr inbounds (%as2_ptr_struct, %as2_ptr_struct addrspace(1)* @global_as1_as2_ptr, i16 0, i32 0), align 8
+; CHECK-NEXT: ret void
+  %A = getelementptr %as2_ptr_struct, %as2_ptr_struct addrspace(1)* @global_as1_as2_ptr, i16 0, i32 0
+  store i32 addrspace(2)* %B, i32 addrspace(2)* addrspace(1)* %A
+  ret void
+}
+
+ at arst = addrspace(1) global [4 x i8 addrspace(2)*] zeroinitializer
+
+define void @test_evaluate_gep_as_ptrs_array(i8 addrspace(2)* %B) {
+; CHECK-LABEL: @test_evaluate_gep_as_ptrs_array(
+; CHECK-NEXT: store i8 addrspace(2)* %B, i8 addrspace(2)* addrspace(1)* getelementptr inbounds ([4 x i8 addrspace(2)*], [4 x i8 addrspace(2)*] addrspace(1)* @arst, i16 0, i16 2), align 4
+
+; CHECK-NEXT: ret void
+  %A = getelementptr [4 x i8 addrspace(2)*], [4 x i8 addrspace(2)*] addrspace(1)* @arst, i16 0, i16 2
+  store i8 addrspace(2)* %B, i8 addrspace(2)* addrspace(1)* %A
+  ret void
+}
+
+define i32* @test7(i32* %I, i64 %C, i64 %D) {
+        %A = getelementptr i32, i32* %I, i64 %C
+        %B = getelementptr i32, i32* %A, i64 %D
+        ret i32* %B
+; CHECK-LABEL: @test7(
+; CHECK: %A = getelementptr i32, i32* %I, i64 %C
+; CHECK: %B = getelementptr i32, i32* %A, i64 %D
+}
+
+define i8* @test8([10 x i32]* %X) {
+        ;; Fold into the cast.
+        %A = getelementptr [10 x i32], [10 x i32]* %X, i64 0, i64 0
+        %B = bitcast i32* %A to i8*
+        ret i8* %B
+; CHECK-LABEL: @test8(
+; CHECK: bitcast [10 x i32]* %X to i8*
+}
+
+define i32 @test9() {
+        %A = getelementptr { i32, double }, { i32, double }* null, i32 0, i32 1
+        %B = ptrtoint double* %A to i32
+        ret i32 %B
+; CHECK-LABEL: @test9(
+; CHECK: ret i32 8
+}
+
+define i1 @test10({ i32, i32 }* %x, { i32, i32 }* %y) {
+        %tmp.1 = getelementptr { i32, i32 }, { i32, i32 }* %x, i32 0, i32 1
+        %tmp.3 = getelementptr { i32, i32 }, { i32, i32 }* %y, i32 0, i32 1
+        ;; seteq x, y
+        %tmp.4 = icmp eq i32* %tmp.1, %tmp.3
+        ret i1 %tmp.4
+; CHECK-LABEL: @test10(
+; CHECK: icmp eq { i32, i32 }* %x, %y
+}
+
+define i1 @test11({ i32, i32 }* %X) {
+        %P = getelementptr { i32, i32 }, { i32, i32 }* %X, i32 0, i32 0
+        %Q = icmp eq i32* %P, null
+        ret i1 %Q
+; CHECK-LABEL: @test11(
+; CHECK: icmp eq { i32, i32 }* %X, null
+}
+
+
+; PR4748
+define i32 @test12(%struct.A* %a) {
+entry:
+  %g3 = getelementptr %struct.A, %struct.A* %a, i32 0, i32 1
+  store i32 10, i32* %g3, align 4
+
+  %g4 = getelementptr %struct.A, %struct.A* %a, i32 0, i32 0
+
+  %new_a = bitcast %struct.B* %g4 to %struct.A*
+
+  %g5 = getelementptr %struct.A, %struct.A* %new_a, i32 0, i32 1
+  %a_a = load i32, i32* %g5, align 4
+  ret i32 %a_a
+; CHECK-LABEL:      @test12(
+; CHECK:      getelementptr %struct.A, %struct.A* %a, i64 0, i32 1
+; CHECK-NEXT: store i32 10, i32* %g3
+; CHECK-NEXT: ret i32 10
+}
+
+
+; PR2235
+%S = type { i32, [ 100 x i32] }
+define i1 @test13(i64 %X, %S* %P) {
+        %A = getelementptr inbounds %S, %S* %P, i32 0, i32 1, i64 %X
+        %B = getelementptr inbounds %S, %S* %P, i32 0, i32 0
+	%C = icmp eq i32* %A, %B
+	ret i1 %C
+; CHECK-LABEL: @test13(
+; CHECK:    %C = icmp eq i64 %X, -1
+}
+
+; This is a test of icmp + shl nuw in disguise - 4611... is 0x3fff...
+define <2 x i1> @test13_vector(<2 x i64> %X, <2 x %S*> %P) nounwind {
+; CHECK-LABEL: @test13_vector(
+; CHECK-NEXT:    [[C:%.*]] = icmp eq <2 x i64> %X, <i64 4611686018427387903, i64 4611686018427387903>
+; CHECK-NEXT:    ret <2 x i1> [[C]]
+;
+  %A = getelementptr inbounds %S, <2 x %S*> %P, <2 x i64> zeroinitializer, <2 x i32> <i32 1, i32 1>, <2 x i64> %X
+  %B = getelementptr inbounds %S, <2 x %S*> %P, <2 x i64> <i64 0, i64 0>, <2 x i32> <i32 0, i32 0>
+  %C = icmp eq <2 x i32*> %A, %B
+  ret <2 x i1> %C
+}
+
+define i1 @test13_as1(i16 %X, %S addrspace(1)* %P) {
+; CHECK-LABEL: @test13_as1(
+; CHECK-NEXT:  %C = icmp eq i16 %X, -1
+; CHECK-NEXT: ret i1 %C
+  %A = getelementptr inbounds %S, %S addrspace(1)* %P, i16 0, i32 1, i16 %X
+  %B = getelementptr inbounds %S, %S addrspace(1)* %P, i16 0, i32 0
+  %C = icmp eq i32 addrspace(1)* %A, %B
+  ret i1 %C
+}
+
+; This is a test of icmp + shl nuw in disguise - 16383 is 0x3fff.
+define <2 x i1> @test13_vector_as1(<2 x i16> %X, <2 x %S addrspace(1)*> %P) {
+; CHECK-LABEL: @test13_vector_as1(
+; CHECK-NEXT:    [[C:%.*]] = icmp eq <2 x i16> %X, <i16 16383, i16 16383>
+; CHECK-NEXT:    ret <2 x i1> [[C]]
+;
+  %A = getelementptr inbounds %S, <2 x %S addrspace(1)*> %P, <2 x i16> <i16 0, i16 0>, <2 x i32> <i32 1, i32 1>, <2 x i16> %X
+  %B = getelementptr inbounds %S, <2 x %S addrspace(1)*> %P, <2 x i16> <i16 0, i16 0>, <2 x i32> <i32 0, i32 0>
+  %C = icmp eq <2 x i32 addrspace(1)*> %A, %B
+  ret <2 x i1> %C
+}
+
+define i1 @test13_i32(i32 %X, %S* %P) {
+; CHECK-LABEL: @test13_i32(
+; CHECK: %C = icmp eq i32 %X, -1
+  %A = getelementptr inbounds %S, %S* %P, i32 0, i32 1, i32 %X
+  %B = getelementptr inbounds %S, %S* %P, i32 0, i32 0
+  %C = icmp eq i32* %A, %B
+  ret i1 %C
+}
+
+define i1 @test13_i16(i16 %X, %S* %P) {
+; CHECK-LABEL: @test13_i16(
+; CHECK: %C = icmp eq i16 %X, -1
+  %A = getelementptr inbounds %S, %S* %P, i16 0, i32 1, i16 %X
+  %B = getelementptr inbounds %S, %S* %P, i16 0, i32 0
+  %C = icmp eq i32* %A, %B
+  ret i1 %C
+}
+
+define i1 @test13_i128(i128 %X, %S* %P) {
+; CHECK-LABEL: @test13_i128(
+; CHECK: %C = icmp eq i64 %1, -1
+  %A = getelementptr inbounds %S, %S* %P, i128 0, i32 1, i128 %X
+  %B = getelementptr inbounds %S, %S* %P, i128 0, i32 0
+  %C = icmp eq i32* %A, %B
+  ret i1 %C
+}
+
+
+ at G = external global [3 x i8]
+define i8* @test14(i32 %Idx) {
+        %idx = zext i32 %Idx to i64
+        %tmp = getelementptr i8, i8* getelementptr ([3 x i8], [3 x i8]* @G, i32 0, i32 0), i64 %idx
+        ret i8* %tmp
+; CHECK-LABEL: @test14(
+; CHECK: getelementptr [3 x i8], [3 x i8]* @G, i64 0, i64 %idx
+}
+
+
+; Test folding of constantexpr geps into normal geps.
+ at Array = external global [40 x i32]
+define i32 *@test15(i64 %X) {
+        %A = getelementptr i32, i32* getelementptr ([40 x i32], [40 x i32]* @Array, i64 0, i64 0), i64 %X
+        ret i32* %A
+; CHECK-LABEL: @test15(
+; CHECK: getelementptr [40 x i32], [40 x i32]* @Array, i64 0, i64 %X
+}
+
+
+define i32* @test16(i32* %X, i32 %Idx) {
+        %R = getelementptr i32, i32* %X, i32 %Idx
+        ret i32* %R
+; CHECK-LABEL: @test16(
+; CHECK: sext i32 %Idx to i64
+}
+
+
+define i1 @test17(i16* %P, i32 %I, i32 %J) {
+        %X = getelementptr inbounds i16, i16* %P, i32 %I
+        %Y = getelementptr inbounds i16, i16* %P, i32 %J
+        %C = icmp ult i16* %X, %Y
+        ret i1 %C
+; CHECK-LABEL: @test17(
+; CHECK: %C = icmp slt i32 %I, %J
+}
+
+define i1 @test18(i16* %P, i32 %I) {
+        %X = getelementptr inbounds i16, i16* %P, i32 %I
+        %C = icmp ult i16* %X, %P
+        ret i1 %C
+; CHECK-LABEL: @test18(
+; CHECK: %C = icmp slt i32 %I, 0
+}
+
+; Larger than the pointer size for a non-zero address space
+define i1 @test18_as1(i16 addrspace(1)* %P, i32 %I) {
+; CHECK-LABEL: @test18_as1(
+; CHECK-NEXT: %1 = trunc i32 %I to i16
+; CHECK-NEXT: %C = icmp slt i16 %1, 0
+; CHECK-NEXT: ret i1 %C
+  %X = getelementptr inbounds i16, i16 addrspace(1)* %P, i32 %I
+  %C = icmp ult i16 addrspace(1)* %X, %P
+  ret i1 %C
+}
+
+; Smaller than the pointer size for a non-zero address space
+define i1 @test18_as1_i32(i16 addrspace(1)* %P, i32 %I) {
+; CHECK-LABEL: @test18_as1_i32(
+; CHECK-NEXT: %1 = trunc i32 %I to i16
+; CHECK-NEXT: %C = icmp slt i16 %1, 0
+; CHECK-NEXT: ret i1 %C
+  %X = getelementptr inbounds i16, i16 addrspace(1)* %P, i32 %I
+  %C = icmp ult i16 addrspace(1)* %X, %P
+  ret i1 %C
+}
+
+; Smaller than pointer size
+define i1 @test18_i16(i16* %P, i16 %I) {
+; CHECK-LABEL: @test18_i16(
+; CHECK: %C = icmp slt i16 %I, 0
+  %X = getelementptr inbounds i16, i16* %P, i16 %I
+  %C = icmp ult i16* %X, %P
+  ret i1 %C
+}
+
+; Same as pointer size
+define i1 @test18_i64(i16* %P, i64 %I) {
+; CHECK-LABEL: @test18_i64(
+; CHECK: %C = icmp slt i64 %I, 0
+  %X = getelementptr inbounds i16, i16* %P, i64 %I
+  %C = icmp ult i16* %X, %P
+  ret i1 %C
+}
+
+; Larger than the pointer size
+define i1 @test18_i128(i16* %P, i128 %I) {
+; CHECK-LABEL: @test18_i128(
+; CHECK: %C = icmp slt i64 %1, 0
+  %X = getelementptr inbounds i16, i16* %P, i128 %I
+  %C = icmp ult i16* %X, %P
+  ret i1 %C
+}
+
+define i32 @test19(i32* %P, i32 %A, i32 %B) {
+        %tmp.4 = getelementptr inbounds i32, i32* %P, i32 %A
+        %tmp.9 = getelementptr inbounds i32, i32* %P, i32 %B
+        %tmp.10 = icmp eq i32* %tmp.4, %tmp.9
+        %tmp.11 = zext i1 %tmp.10 to i32
+        ret i32 %tmp.11
+; CHECK-LABEL: @test19(
+; CHECK: icmp eq i32 %A, %B
+}
+
+define i32 @test20(i32* %P, i32 %A, i32 %B) {
+        %tmp.4 = getelementptr inbounds i32, i32* %P, i32 %A
+        %tmp.6 = icmp eq i32* %tmp.4, %P
+        %tmp.7 = zext i1 %tmp.6 to i32
+        ret i32 %tmp.7
+; CHECK-LABEL: @test20(
+; CHECK: icmp eq i32 %A, 0
+}
+
+define i32 @test20_as1(i32 addrspace(1)* %P, i32 %A, i32 %B) {
+  %tmp.4 = getelementptr inbounds i32, i32 addrspace(1)* %P, i32 %A
+  %tmp.6 = icmp eq i32 addrspace(1)* %tmp.4, %P
+  %tmp.7 = zext i1 %tmp.6 to i32
+  ret i32 %tmp.7
+; CHECK-LABEL: @test20_as1(
+; CHECK: icmp eq i16 %1, 0
+}
+
+
+define i32 @test21() {
+        %pbob1 = alloca %intstruct
+        %pbob2 = getelementptr %intstruct, %intstruct* %pbob1
+        %pbobel = getelementptr %intstruct, %intstruct* %pbob2, i64 0, i32 0
+        %rval = load i32, i32* %pbobel
+        ret i32 %rval
+; CHECK-LABEL: @test21(
+; CHECK: getelementptr inbounds %intstruct, %intstruct* %pbob1, i64 0, i32 0
+}
+
+
+ at A = global i32 1               ; <i32*> [#uses=1]
+ at B = global i32 2               ; <i32*> [#uses=1]
+
+define i1 @test22() {
+        %C = icmp ult i32* getelementptr (i32, i32* @A, i64 1),
+                           getelementptr (i32, i32* @B, i64 2)
+        ret i1 %C
+; CHECK-LABEL: @test22(
+; CHECK: icmp ult (i32* getelementptr inbounds (i32, i32* @A, i64 1), i32* getelementptr (i32, i32* @B, i64 2))
+}
+
+
+%X = type { [10 x i32], float }
+
+define i1 @test23() {
+        %A = getelementptr %X, %X* null, i64 0, i32 0, i64 0                ; <i32*> [#uses=1]
+        %B = icmp ne i32* %A, null              ; <i1> [#uses=1]
+        ret i1 %B
+; CHECK-LABEL: @test23(
+; CHECK: ret i1 false
+}
+
+define void @test25() {
+entry:
+        %tmp = getelementptr { i64, i64, i64, i64 }, { i64, i64, i64, i64 }* null, i32 0, i32 3         ; <i64*> [#uses=1]
+        %tmp.upgrd.1 = load i64, i64* %tmp           ; <i64> [#uses=1]
+        %tmp8.ui = load i64, i64* null               ; <i64> [#uses=1]
+        %tmp8 = bitcast i64 %tmp8.ui to i64             ; <i64> [#uses=1]
+        %tmp9 = and i64 %tmp8, %tmp.upgrd.1             ; <i64> [#uses=1]
+        %sext = trunc i64 %tmp9 to i32          ; <i32> [#uses=1]
+        %tmp27.i = sext i32 %sext to i64                ; <i64> [#uses=1]
+        tail call void @foo25( i32 0, i64 %tmp27.i )
+        unreachable
+; CHECK-LABEL: @test25(
+}
+
+declare void @foo25(i32, i64)
+
+
+; PR1637
+define i1 @test26(i8* %arr) {
+        %X = getelementptr i8, i8* %arr, i32 1
+        %Y = getelementptr i8, i8* %arr, i32 1
+        %test = icmp uge i8* %X, %Y
+        ret i1 %test
+; CHECK-LABEL: @test26(
+; CHECK: ret i1 true
+}
+
+	%struct.__large_struct = type { [100 x i64] }
+	%struct.compat_siginfo = type { i32, i32, i32, { [29 x i32] } }
+	%struct.siginfo_t = type { i32, i32, i32, { { i32, i32, [0 x i8], %struct.sigval_t, i32 }, [88 x i8] } }
+	%struct.sigval_t = type { i8* }
+
+define i32 @test27(%struct.compat_siginfo* %to, %struct.siginfo_t* %from) {
+entry:
+	%from_addr = alloca %struct.siginfo_t*
+	%tmp344 = load %struct.siginfo_t*, %struct.siginfo_t** %from_addr, align 8
+	%tmp345 = getelementptr %struct.siginfo_t, %struct.siginfo_t* %tmp344, i32 0, i32 3
+	%tmp346 = getelementptr { { i32, i32, [0 x i8], %struct.sigval_t, i32 }, [88 x i8] }, { { i32, i32, [0 x i8], %struct.sigval_t, i32 }, [88 x i8] }* %tmp345, i32 0, i32 0
+	%tmp346347 = bitcast { i32, i32, [0 x i8], %struct.sigval_t, i32 }* %tmp346 to { i32, i32, %struct.sigval_t }*
+	%tmp348 = getelementptr { i32, i32, %struct.sigval_t }, { i32, i32, %struct.sigval_t }* %tmp346347, i32 0, i32 2
+	%tmp349 = getelementptr %struct.sigval_t, %struct.sigval_t* %tmp348, i32 0, i32 0
+	%tmp349350 = bitcast i8** %tmp349 to i32*
+	%tmp351 = load i32, i32* %tmp349350, align 8
+	%tmp360 = call i32 asm sideeffect "...",
+        "=r,ir,*m,i,0,~{dirflag},~{fpsr},~{flags}"( i32 %tmp351,
+         %struct.__large_struct* null, i32 -14, i32 0 )
+	unreachable
+; CHECK-LABEL: @test27(
+}
+
+; PR1978
+	%struct.x = type <{ i8 }>
+ at .str = internal constant [6 x i8] c"Main!\00"
+ at .str1 = internal constant [12 x i8] c"destroy %p\0A\00"
+
+define i32 @test28() nounwind  {
+entry:
+	%orientations = alloca [1 x [1 x %struct.x]]
+	%tmp3 = call i32 @puts( i8* getelementptr ([6 x i8], [6 x i8]* @.str, i32 0, i32 0) ) nounwind
+	%tmp45 = getelementptr inbounds [1 x [1 x %struct.x]], [1 x [1 x %struct.x]]* %orientations, i32 1, i32 0, i32 0
+	%orientations62 = getelementptr [1 x [1 x %struct.x]], [1 x [1 x %struct.x]]* %orientations, i32 0, i32 0, i32 0
+	br label %bb10
+
+bb10:
+	%indvar = phi i32 [ 0, %entry ], [ %indvar.next, %bb10 ]
+	%tmp.0.reg2mem.0.rec = mul i32 %indvar, -1
+	%tmp12.rec = add i32 %tmp.0.reg2mem.0.rec, -1
+	%tmp12 = getelementptr inbounds %struct.x, %struct.x* %tmp45, i32 %tmp12.rec
+	%tmp16 = call i32 (i8*, ...) @printf( i8* getelementptr ([12 x i8], [12 x i8]* @.str1, i32 0, i32 0), %struct.x* %tmp12 ) nounwind
+	%tmp84 = icmp eq %struct.x* %tmp12, %orientations62
+	%indvar.next = add i32 %indvar, 1
+	br i1 %tmp84, label %bb17, label %bb10
+
+bb17:
+	ret i32 0
+; CHECK-LABEL: @test28(
+; CHECK: icmp eq i32 %indvar, 0
+}
+
+declare i32 @puts(i8*)
+
+declare i32 @printf(i8*, ...)
+
+
+
+
+; rdar://6762290
+	%T = type <{ i64, i64, i64 }>
+define i32 @test29(i8* %start, i32 %X) nounwind {
+entry:
+	%tmp3 = load i64, i64* null
+	%add.ptr = getelementptr i8, i8* %start, i64 %tmp3
+	%tmp158 = load i32, i32* null
+	%add.ptr159 = getelementptr %T, %T* null, i32 %tmp158
+	%add.ptr209 = getelementptr i8, i8* %start, i64 0
+	%add.ptr212 = getelementptr i8, i8* %add.ptr209, i32 %X
+	%cmp214 = icmp ugt i8* %add.ptr212, %add.ptr
+	br i1 %cmp214, label %if.then216, label %if.end363
+
+if.then216:
+	ret i32 1
+
+if.end363:
+	ret i32 0
+; CHECK-LABEL: @test29(
+}
+
+
+; PR3694
+define i32 @test30(i32 %m, i32 %n) nounwind {
+entry:
+	%0 = alloca i32, i32 %n, align 4
+	%1 = bitcast i32* %0 to [0 x i32]*
+	call void @test30f(i32* %0) nounwind
+	%2 = getelementptr [0 x i32], [0 x i32]* %1, i32 0, i32 %m
+	%3 = load i32, i32* %2, align 4
+	ret i32 %3
+; CHECK-LABEL: @test30(
+; CHECK: getelementptr i32
+}
+
+declare void @test30f(i32*)
+
+
+
+define i1 @test31(i32* %A) {
+        %B = getelementptr i32, i32* %A, i32 1
+        %C = getelementptr i32, i32* %A, i64 1
+        %V = icmp eq i32* %B, %C
+        ret i1 %V
+; CHECK-LABEL: @test31(
+; CHECK: ret i1 true
+}
+
+
+; PR1345
+define i8* @test32(i8* %v) {
+	%A = alloca [4 x i8*], align 16
+	%B = getelementptr [4 x i8*], [4 x i8*]* %A, i32 0, i32 0
+	store i8* null, i8** %B
+	%C = bitcast [4 x i8*]* %A to { [16 x i8] }*
+	%D = getelementptr { [16 x i8] }, { [16 x i8] }* %C, i32 0, i32 0, i32 8
+	%E = bitcast i8* %D to i8**
+	store i8* %v, i8** %E
+	%F = getelementptr [4 x i8*], [4 x i8*]* %A, i32 0, i32 2
+	%G = load i8*, i8** %F
+	ret i8* %G
+; CHECK-LABEL: @test32(
+; CHECK: %D = getelementptr inbounds [4 x i8*], [4 x i8*]* %A, i64 0, i64 1
+; CHECK: %F = getelementptr inbounds [4 x i8*], [4 x i8*]* %A, i64 0, i64 2
+}
+
+; PR3290
+%struct.Key = type { { i32, i32 } }
+%struct.anon = type <{ i8, [3 x i8], i32 }>
+
+define i32* @test33(%struct.Key* %A) {
+; CHECK-LABEL: @test33(
+; CHECK: getelementptr %struct.Key, %struct.Key* %A, i64 0, i32 0, i32 1
+  %B = bitcast %struct.Key* %A to %struct.anon*
+  %C = getelementptr %struct.anon, %struct.anon* %B, i32 0, i32 2
+  ret i32* %C
+}
+
+define i32 addrspace(1)* @test33_as1(%struct.Key addrspace(1)* %A) {
+; CHECK-LABEL: @test33_as1(
+; CHECK: getelementptr %struct.Key, %struct.Key addrspace(1)* %A, i16 0, i32 0, i32 1
+  %B = bitcast %struct.Key addrspace(1)* %A to %struct.anon addrspace(1)*
+  %C = getelementptr %struct.anon, %struct.anon addrspace(1)* %B, i32 0, i32 2
+  ret i32 addrspace(1)* %C
+}
+
+define i32 addrspace(1)* @test33_array_as1([10 x i32] addrspace(1)* %A) {
+; CHECK-LABEL: @test33_array_as1(
+; CHECK: getelementptr [10 x i32], [10 x i32] addrspace(1)* %A, i16 0, i16 2
+  %B = bitcast [10 x i32] addrspace(1)* %A to [5 x i32] addrspace(1)*
+  %C = getelementptr [5 x i32], [5 x i32] addrspace(1)* %B, i32 0, i32 2
+  ret i32 addrspace(1)* %C
+}
+
+; Make sure the GEP indices use the right pointer sized integer
+define i32 addrspace(1)* @test33_array_struct_as1([10 x %struct.Key] addrspace(1)* %A) {
+; CHECK-LABEL: @test33_array_struct_as1(
+; CHECK: getelementptr [10 x %struct.Key], [10 x %struct.Key] addrspace(1)* %A, i16 0, i16 1, i32 0, i32 0
+  %B = bitcast [10 x %struct.Key] addrspace(1)* %A to [20 x i32] addrspace(1)*
+  %C = getelementptr [20 x i32], [20 x i32] addrspace(1)* %B, i32 0, i32 2
+  ret i32 addrspace(1)* %C
+}
+
+define i32 addrspace(1)* @test33_addrspacecast(%struct.Key* %A) {
+; CHECK-LABEL: @test33_addrspacecast(
+; CHECK: %C = getelementptr %struct.Key, %struct.Key* %A, i64 0, i32 0, i32 1
+; CHECK-NEXT: addrspacecast i32* %C to i32 addrspace(1)*
+; CHECK-NEXT: ret
+  %B = addrspacecast %struct.Key* %A to %struct.anon addrspace(1)*
+  %C = getelementptr %struct.anon, %struct.anon addrspace(1)* %B, i32 0, i32 2
+  ret i32 addrspace(1)* %C
+}
+
+	%T2 = type { i8*, i8 }
+define i8* @test34(i8* %Val, i64 %V) nounwind {
+entry:
+	%A = alloca %T2, align 8
+	%mrv_gep = bitcast %T2* %A to i64*
+	%B = getelementptr %T2, %T2* %A, i64 0, i32 0
+
+      	store i64 %V, i64* %mrv_gep
+	%C = load i8*, i8** %B, align 8
+	ret i8* %C
+; CHECK-LABEL: @test34(
+; CHECK: %[[C:.*]] = inttoptr i64 %V to i8*
+; CHECK: ret i8* %[[C]]
+}
+
+%t0 = type { i8*, [19 x i8] }
+%t1 = type { i8*, [0 x i8] }
+
+ at array = external global [11 x i8]
+
+ at s = external global %t0
+@"\01LC8" = external constant [17 x i8]
+
+; Instcombine should be able to fold this getelementptr.
+
+define i32 @test35() nounwind {
+  call i32 (i8*, ...) @printf(i8* getelementptr ([17 x i8], [17 x i8]* @"\01LC8", i32 0, i32 0),
+             i8* getelementptr (%t1, %t1* bitcast (%t0* @s to %t1*), i32 0, i32 1, i32 0)) nounwind
+  ret i32 0
+; CHECK-LABEL: @test35(
+; CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([17 x i8], [17 x i8]* @"\01LC8", i64 0, i64 0), i8* getelementptr inbounds (%t0, %t0* @s, i64 0, i32 1, i64 0)) [[$NUW:#[0-9]+]]
+}
+
+; Don't treat signed offsets as unsigned.
+define i8* @test36() nounwind {
+  ret i8* getelementptr ([11 x i8], [11 x i8]* @array, i32 0, i64 -1)
+; CHECK-LABEL: @test36(
+; CHECK: ret i8* getelementptr ([11 x i8], [11 x i8]* @array, i64 0, i64 -1)
+}
+
+; Instcombine shouldn't assume that gep(A,0,1) != gep(A,1,0).
+ at A37 = external constant [1 x i8]
+define i1 @test37() nounwind {
+; CHECK-LABEL: @test37(
+; CHECK: ret i1 true
+  %t = icmp eq i8* getelementptr ([1 x i8], [1 x i8]* @A37, i64 0, i64 1),
+                   getelementptr ([1 x i8], [1 x i8]* @A37, i64 1, i64 0)
+  ret i1 %t
+}
+
+; Test index promotion
+define i32* @test38(i32* %I, i32 %n) {
+        %A = getelementptr i32, i32* %I, i32 %n
+        ret i32* %A
+; CHECK-LABEL: @test38(
+; CHECK: = sext i32 %n to i64
+; CHECK: %A = getelementptr i32, i32* %I, i64 %
+}
+
+; Test that we don't duplicate work when the second gep is a "bitcast".
+%pr10322_t = type { i8* }
+declare void @pr10322_f2(%pr10322_t*)
+declare void @pr10322_f3(i8**)
+define void @pr10322_f1(%pr10322_t* %foo) {
+entry:
+  %arrayidx8 = getelementptr inbounds %pr10322_t, %pr10322_t* %foo, i64 2
+  call void @pr10322_f2(%pr10322_t* %arrayidx8) nounwind
+  %tmp2 = getelementptr inbounds %pr10322_t, %pr10322_t* %arrayidx8, i64 0, i32 0
+  call void @pr10322_f3(i8** %tmp2) nounwind
+  ret void
+
+; CHECK-LABEL: @pr10322_f1(
+; CHECK: %tmp2 = getelementptr inbounds %pr10322_t, %pr10322_t* %arrayidx8, i64 0, i32 0
+}
+
+; Test that we combine the last two geps in this sequence, before we
+; would wait for gep1 and gep2 to be combined and never combine 2 and 3.
+%three_gep_t = type {i32}
+%three_gep_t2 = type {%three_gep_t}
+
+define void @three_gep_f(%three_gep_t2* %x) {
+  %gep1 = getelementptr %three_gep_t2, %three_gep_t2* %x, i64 2
+  call void @three_gep_h(%three_gep_t2* %gep1)
+  %gep2 = getelementptr %three_gep_t2, %three_gep_t2* %gep1, i64 0, i32 0
+  %gep3 = getelementptr %three_gep_t, %three_gep_t* %gep2, i64 0, i32 0
+  call void @three_gep_g(i32* %gep3)
+
+; CHECK-LABEL: @three_gep_f(
+; CHECK: %gep3 = getelementptr %three_gep_t2, %three_gep_t2* %gep1, i64 0, i32 0, i32 0
+  ret void
+}
+
+declare void @three_gep_g(i32*)
+declare void @three_gep_h(%three_gep_t2*)
+
+%struct.ham = type { i32, %struct.zot*, %struct.zot*, %struct.zot* }
+%struct.zot = type { i64, i8 }
+
+define void @test39(%struct.ham* %arg, i8 %arg1) nounwind {
+  %tmp = getelementptr inbounds %struct.ham, %struct.ham* %arg, i64 0, i32 2
+  %tmp2 = load %struct.zot*, %struct.zot** %tmp, align 8
+  %tmp3 = bitcast %struct.zot* %tmp2 to i8*
+  %tmp4 = getelementptr inbounds i8, i8* %tmp3, i64 -8
+  store i8 %arg1, i8* %tmp4, align 8
+  ret void
+
+; CHECK-LABEL: @test39(
+; CHECK: getelementptr inbounds %struct.ham, %struct.ham* %arg, i64 0, i32 2
+; CHECK: getelementptr inbounds i8, i8* %{{.+}}, i64 -8
+}
+
+define i1 @pr16483([1 x i8]* %a, [1 x i8]* %b) {
+  %c = getelementptr [1 x i8], [1 x i8]* %a, i32 0, i32 0
+  %d = getelementptr [1 x i8], [1 x i8]* %b, i32 0, i32 0
+  %cmp = icmp ult i8* %c, %d
+  ret i1 %cmp
+
+; CHECK-LABEL: @pr16483(
+; CHECK-NEXT: icmp ult  [1 x i8]* %a, %b
+}
+
+define i8 @test_gep_bitcast_as1(i32 addrspace(1)* %arr, i16 %N) {
+; CHECK-LABEL: @test_gep_bitcast_as1(
+; CHECK: getelementptr i32, i32 addrspace(1)* %arr, i16 %N
+; CHECK: bitcast
+  %cast = bitcast i32 addrspace(1)* %arr to i8 addrspace(1)*
+  %V = mul i16 %N, 4
+  %t = getelementptr i8, i8 addrspace(1)* %cast, i16 %V
+  %x = load i8, i8 addrspace(1)* %t
+  ret i8 %x
+}
+
+; The element size of the array matches the element size of the pointer
+define i64 @test_gep_bitcast_array_same_size_element([100 x double]* %arr, i64 %N) {
+; CHECK-LABEL: @test_gep_bitcast_array_same_size_element(
+; CHECK: getelementptr [100 x double], [100 x double]* %arr, i64 0, i64 %V
+; CHECK: bitcast
+  %cast = bitcast [100 x double]* %arr to i64*
+  %V = mul i64 %N, 8
+  %t = getelementptr i64, i64* %cast, i64 %V
+  %x = load i64, i64* %t
+  ret i64 %x
+}
+
+; gep should be done in the original address space.
+define i64 @test_gep_bitcast_array_same_size_element_addrspacecast([100 x double]* %arr, i64 %N) {
+; CHECK-LABEL: @test_gep_bitcast_array_same_size_element_addrspacecast(
+; CHECK: getelementptr [100 x double], [100 x double]* %arr, i64 0, i64 %V
+; CHECK-NEXT: bitcast double*
+; CHECK-NEXT: %t = addrspacecast i64*
+; CHECK: load i64, i64 addrspace(3)* %t
+  %cast = addrspacecast [100 x double]* %arr to i64 addrspace(3)*
+  %V = mul i64 %N, 8
+  %t = getelementptr i64, i64 addrspace(3)* %cast, i64 %V
+  %x = load i64, i64 addrspace(3)* %t
+  ret i64 %x
+}
+
+; The element size of the array is different the element size of the pointer
+define i8 @test_gep_bitcast_array_different_size_element([100 x double]* %arr, i64 %N) {
+; CHECK-LABEL: @test_gep_bitcast_array_different_size_element(
+; CHECK: getelementptr [100 x double], [100 x double]* %arr, i64 0, i64 %N
+; CHECK: bitcast
+  %cast = bitcast [100 x double]* %arr to i8*
+  %V = mul i64 %N, 8
+  %t = getelementptr i8, i8* %cast, i64 %V
+  %x = load i8, i8* %t
+  ret i8 %x
+}
+
+define i64 @test_gep_bitcast_array_same_size_element_as1([100 x double] addrspace(1)* %arr, i16 %N) {
+; CHECK-LABEL: @test_gep_bitcast_array_same_size_element_as1(
+; CHECK: getelementptr [100 x double], [100 x double] addrspace(1)* %arr, i16 0, i16 %V
+; CHECK: bitcast
+  %cast = bitcast [100 x double] addrspace(1)* %arr to i64 addrspace(1)*
+  %V = mul i16 %N, 8
+  %t = getelementptr i64, i64 addrspace(1)* %cast, i16 %V
+  %x = load i64, i64 addrspace(1)* %t
+  ret i64 %x
+}
+
+define i8 @test_gep_bitcast_array_different_size_element_as1([100 x double] addrspace(1)* %arr, i16 %N) {
+; CHECK-LABEL: @test_gep_bitcast_array_different_size_element_as1(
+; CHECK: getelementptr [100 x double], [100 x double] addrspace(1)* %arr, i16 0, i16 %N
+; CHECK: bitcast
+  %cast = bitcast [100 x double] addrspace(1)* %arr to i8 addrspace(1)*
+  %V = mul i16 %N, 8
+  %t = getelementptr i8, i8 addrspace(1)* %cast, i16 %V
+  %x = load i8, i8 addrspace(1)* %t
+  ret i8 %x
+}
+
+define i64 @test40() {
+  %array = alloca [3 x i32], align 4
+  %gep = getelementptr inbounds [3 x i32], [3 x i32]* %array, i64 0, i64 2
+  %gepi8 = bitcast i32* %gep to i8*
+  %p = ptrtoint [3 x i32]* %array to i64
+  %np = sub i64 0, %p
+  %gep2 = getelementptr i8, i8* %gepi8, i64 %np
+  %ret = ptrtoint i8* %gep2 to i64
+  ret i64 %ret
+
+; CHECK-LABEL: @test40
+; CHECK-NEXT: ret i64 8
+}
+
+define i16 @test41([3 x i32] addrspace(1)* %array) {
+  %gep = getelementptr inbounds [3 x i32], [3 x i32] addrspace(1)* %array, i16 0, i16 2
+  %gepi8 = bitcast i32 addrspace(1)* %gep to i8 addrspace(1)*
+  %p = ptrtoint [3 x i32] addrspace(1)* %array to i16
+  %np = sub i16 0, %p
+  %gep2 = getelementptr i8, i8 addrspace(1)* %gepi8, i16 %np
+  %ret = ptrtoint i8 addrspace(1)* %gep2 to i16
+  ret i16 %ret
+
+; CHECK-LABEL: @test41(
+; CHECK-NEXT: ret i16 8
+}
+
+define i8* @test42(i8* %c1, i8* %c2) {
+  %ptrtoint = ptrtoint i8* %c1 to i64
+  %sub = sub i64 0, %ptrtoint
+  %gep = getelementptr inbounds i8, i8* %c2, i64 %sub
+  ret i8* %gep
+
+; CHECK-LABEL: @test42(
+; CHECK-NEXT:  [[PTRTOINT1:%.*]] = ptrtoint i8* %c1 to i64
+; CHECK-NEXT:  [[PTRTOINT2:%.*]] = ptrtoint i8* %c2 to i64
+; CHECK-NEXT:  [[SUB:%.*]] = sub i64 [[PTRTOINT2]], [[PTRTOINT1]]
+; CHECK-NEXT:  [[INTTOPTR:%.*]] = inttoptr i64 [[SUB]] to i8*
+; CHECK-NEXT:  ret i8* [[INTTOPTR]]
+}
+
+define i16* @test43(i16* %c1, i16* %c2) {
+  %ptrtoint = ptrtoint i16* %c1 to i64
+  %sub = sub i64 0, %ptrtoint
+  %shr = ashr i64 %sub, 1
+  %gep = getelementptr inbounds i16, i16* %c2, i64 %shr
+  ret i16* %gep
+
+; CHECK-LABEL: @test43(
+; CHECK-NEXT:  [[PTRTOINT1:%.*]] = ptrtoint i16* %c1 to i64
+; CHECK-NEXT:  [[PTRTOINT2:%.*]] = ptrtoint i16* %c2 to i64
+; CHECK-NEXT:  [[SUB:%.*]] = sub i64 [[PTRTOINT2]], [[PTRTOINT1]]
+; CHECK-NEXT:  [[INTTOPTR:%.*]] = inttoptr i64 [[SUB]] to i16*
+; CHECK-NEXT:  ret i16* [[INTTOPTR]]
+}
+
+define %struct.C* @test44(%struct.C* %c1, %struct.C* %c2) {
+  %ptrtoint = ptrtoint %struct.C* %c1 to i64
+  %sub = sub i64 0, %ptrtoint
+  %shr = sdiv i64 %sub, 7
+  %gep = getelementptr inbounds %struct.C, %struct.C* %c2, i64 %shr
+  ret %struct.C* %gep
+
+; CHECK-LABEL: @test44(
+; CHECK-NEXT:  [[PTRTOINT1:%.*]] = ptrtoint %struct.C* %c1 to i64
+; CHECK-NEXT:  [[PTRTOINT2:%.*]] = ptrtoint %struct.C* %c2 to i64
+; CHECK-NEXT:  [[SUB:%.*]] = sub i64 [[PTRTOINT2]], [[PTRTOINT1]]
+; CHECK-NEXT:  [[INTTOPTR:%.*]] = inttoptr i64 [[SUB]] to %struct.C*
+; CHECK-NEXT:  ret %struct.C* [[INTTOPTR]]
+}
+
+define %struct.C* @test45(%struct.C* %c1, %struct.C** %c2) {
+  %ptrtoint1 = ptrtoint %struct.C* %c1 to i64
+  %ptrtoint2 = ptrtoint %struct.C** %c2 to i64
+  %sub = sub i64 %ptrtoint2, %ptrtoint1 ; C2 - C1
+  %shr = sdiv i64 %sub, 7
+  %gep = getelementptr inbounds %struct.C, %struct.C* %c1, i64 %shr ; C1 + (C2 - C1)
+  ret %struct.C* %gep
+
+; CHECK-LABEL: @test45(
+; CHECK-NEXT:  [[BITCAST:%.*]] = bitcast %struct.C** %c2 to %struct.C*
+; CHECK-NEXT:  ret %struct.C* [[BITCAST]]
+}
+
+define %struct.C* @test46(%struct.C* %c1, %struct.C* %c2, i64 %N) {
+  %ptrtoint = ptrtoint %struct.C* %c1 to i64
+  %sub = sub i64 0, %ptrtoint
+  %sdiv = sdiv i64 %sub, %N
+  %gep = getelementptr inbounds %struct.C, %struct.C* %c2, i64 %sdiv
+  ret %struct.C* %gep
+
+; CHECK-LABEL: @test46(
+; CHECK-NEXT:  [[PTRTOINT:%.*]] = ptrtoint %struct.C* %c1 to i64
+; CHECK-NEXT:  [[SUB:%.*]] = sub i64 0, [[PTRTOINT]]
+; CHECK-NEXT:  [[SDIV:%.*]] = sdiv i64 [[SUB]], %N
+; CHECK-NEXT:  [[GEP:%.*]] = getelementptr inbounds %struct.C, %struct.C* %c2, i64 %sdiv
+; CHECK-NEXT:  ret %struct.C* [[GEP]]
+}
+
+define i32* @test47(i32* %I, i64 %C, i64 %D) {
+  %sub = sub i64 %D, %C
+  %A = getelementptr i32, i32* %I, i64 %C
+  %B = getelementptr i32, i32* %A, i64 %sub
+  ret i32* %B
+; CHECK-LABEL: @test47(
+; CHECK-NEXT: %B = getelementptr i32, i32* %I, i64 %D
+}
+
+define i32* @test48(i32* %I, i64 %C, i64 %D) {
+  %sub = sub i64 %D, %C
+  %A = getelementptr i32, i32* %I, i64 %sub
+  %B = getelementptr i32, i32* %A, i64 %C
+  ret i32* %B
+; CHECK-LABEL: @test48(
+; CHECK-NEXT: %B = getelementptr i32, i32* %I, i64 %D
+}
+
+define i32* @test49(i32* %I, i64 %C) {
+  %notC = xor i64 -1, %C
+  %A = getelementptr i32, i32* %I, i64 %C
+  %B = getelementptr i32, i32* %A, i64 %notC
+  ret i32* %B
+; CHECK-LABEL: @test49(
+; CHECK-NEXT: %B = getelementptr i32, i32* %I, i64 -1
+}
+
+define i32 addrspace(1)* @ascast_0_gep(i32* %p) nounwind {
+; CHECK-LABEL: @ascast_0_gep(
+; CHECK-NOT: getelementptr
+; CHECK: ret
+  %gep = getelementptr i32, i32* %p, i32 0
+  %x = addrspacecast i32* %gep to i32 addrspace(1)*
+  ret i32 addrspace(1)* %x
+}
+
+; Do not merge the GEP and the addrspacecast, because it would undo the
+; addrspacecast canonicalization.
+define i32 addrspace(1)* @ascast_0_0_gep([128 x i32]* %p) nounwind {
+; CHECK-LABEL: @ascast_0_0_gep(
+; CHECK-NEXT: getelementptr [128 x i32]
+; CHECK-NEXT: addrspacecast i32*
+; CHECK-NEXT: ret i32 addrspace(1)*
+  %gep = getelementptr [128 x i32], [128 x i32]* %p, i32 0, i32 0
+  %x = addrspacecast i32* %gep to i32 addrspace(1)*
+  ret i32 addrspace(1)* %x
+}
+
+define <2 x i32*> @PR32414(i32** %ptr) {
+; CHECK-LABEL: @PR32414(
+; CHECK-NEXT:    [[TMP0:%.*]] = bitcast i32** %ptr to i32*
+; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds i32, i32* [[TMP0]], <2 x i64> <i64 0, i64 1>
+; CHECK-NEXT:    ret <2 x i32*> [[TMP1]]
+;
+  %tmp0 = bitcast i32** %ptr to i32*
+  %tmp1 = getelementptr inbounds i32, i32* %tmp0, <2 x i64> <i64 0, i64 1>
+  ret <2 x i32*> %tmp1
+}
+
+; CHECK: attributes [[$NUW]] = { nounwind }

Added: llvm/trunk/test/Transforms/InstCombine/hoist_instr.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/hoist_instr.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/hoist_instr.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/hoist_instr.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,18 @@
+; RUN: opt < %s -instcombine -S | FileCheck %s
+
+;; This tests that the div is hoisted into the then block.
+define i32 @foo(i1 %C, i32 %A, i32 %B) {
+entry:
+        br i1 %C, label %then, label %endif
+
+then:           ; preds = %entry
+; CHECK: then:
+; CHECK-NEXT: sdiv i32
+        br label %endif
+
+endif:          ; preds = %then, %entry
+        %X = phi i32 [ %A, %then ], [ 15, %entry ]              ; <i32> [#uses=1]
+        %Y = sdiv i32 %X, 42            ; <i32> [#uses=1]
+        ret i32 %Y
+}
+

Added: llvm/trunk/test/Transforms/InstCombine/icmp-add.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/icmp-add.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/icmp-add.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/icmp-add.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,465 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt < %s -instcombine -S | FileCheck %s
+
+; PR1949
+
+define i1 @test1(i32 %a) {
+; CHECK-LABEL: @test1(
+; CHECK-NEXT:    [[C:%.*]] = icmp ugt i32 [[A:%.*]], -5
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %b = add i32 %a, 4
+  %c = icmp ult i32 %b, 4
+  ret i1 %c
+}
+
+define <2 x i1> @test1vec(<2 x i32> %a) {
+; CHECK-LABEL: @test1vec(
+; CHECK-NEXT:    [[C:%.*]] = icmp ugt <2 x i32> [[A:%.*]], <i32 -5, i32 -5>
+; CHECK-NEXT:    ret <2 x i1> [[C]]
+;
+  %b = add <2 x i32> %a, <i32 4, i32 4>
+  %c = icmp ult <2 x i32> %b, <i32 4, i32 4>
+  ret <2 x i1> %c
+}
+
+define i1 @test2(i32 %a) {
+; CHECK-LABEL: @test2(
+; CHECK-NEXT:    [[C:%.*]] = icmp ult i32 [[A:%.*]], 4
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %b = sub i32 %a, 4
+  %c = icmp ugt i32 %b, -5
+  ret i1 %c
+}
+
+define <2 x i1> @test2vec(<2 x i32> %a) {
+; CHECK-LABEL: @test2vec(
+; CHECK-NEXT:    [[C:%.*]] = icmp ult <2 x i32> [[A:%.*]], <i32 4, i32 4>
+; CHECK-NEXT:    ret <2 x i1> [[C]]
+;
+  %b = sub <2 x i32> %a, <i32 4, i32 4>
+  %c = icmp ugt <2 x i32> %b, <i32 -5, i32 -5>
+  ret <2 x i1> %c
+}
+
+define i1 @test3(i32 %a) {
+; CHECK-LABEL: @test3(
+; CHECK-NEXT:    [[C:%.*]] = icmp sgt i32 [[A:%.*]], 2147483643
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %b = add i32 %a, 4
+  %c = icmp slt i32 %b, 2147483652
+  ret i1 %c
+}
+
+define <2 x i1> @test3vec(<2 x i32> %a) {
+; CHECK-LABEL: @test3vec(
+; CHECK-NEXT:    [[C:%.*]] = icmp sgt <2 x i32> [[A:%.*]], <i32 2147483643, i32 2147483643>
+; CHECK-NEXT:    ret <2 x i1> [[C]]
+;
+  %b = add <2 x i32> %a, <i32 4, i32 4>
+  %c = icmp slt <2 x i32> %b, <i32 2147483652, i32 2147483652>
+  ret <2 x i1> %c
+}
+
+define i1 @test4(i32 %a) {
+; CHECK-LABEL: @test4(
+; CHECK-NEXT:    [[C:%.*]] = icmp slt i32 [[A:%.*]], -4
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %b = add i32 %a, 2147483652
+  %c = icmp sge i32 %b, 4
+  ret i1 %c
+}
+
+define { i32, i1 } @test4multiuse(i32 %a) {
+; CHECK-LABEL: @test4multiuse(
+; CHECK-NEXT:    [[B:%.*]] = add i32 [[A:%.*]], -2147483644
+; CHECK-NEXT:    [[C:%.*]] = icmp slt i32 [[B]], -4
+; CHECK-NEXT:    [[TMP:%.*]] = insertvalue { i32, i1 } undef, i32 [[B]], 0
+; CHECK-NEXT:    [[RES:%.*]] = insertvalue { i32, i1 } [[TMP]], i1 [[C]], 1
+; CHECK-NEXT:    ret { i32, i1 } [[RES]]
+;
+
+  %b = add i32 %a, -2147483644
+  %c = icmp slt i32 %b, -4
+
+  %tmp = insertvalue { i32, i1 } undef, i32 %b, 0
+  %res = insertvalue { i32, i1 } %tmp, i1 %c, 1
+
+  ret { i32, i1 } %res
+}
+
+define <2 x i1> @test4vec(<2 x i32> %a) {
+; CHECK-LABEL: @test4vec(
+; CHECK-NEXT:    [[C:%.*]] = icmp slt <2 x i32> [[A:%.*]], <i32 -4, i32 -4>
+; CHECK-NEXT:    ret <2 x i1> [[C]]
+;
+  %b = add <2 x i32> %a, <i32 2147483652, i32 2147483652>
+  %c = icmp sge <2 x i32> %b, <i32 4, i32 4>
+  ret <2 x i1> %c
+}
+
+; icmp Pred (add nsw X, C2), C --> icmp Pred X, (C - C2), when C - C2 does not overflow.
+; This becomes equality because it's at the limit.
+
+define i1 @nsw_slt1(i8 %a) {
+; CHECK-LABEL: @nsw_slt1(
+; CHECK-NEXT:    [[C:%.*]] = icmp eq i8 [[A:%.*]], -128
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %b = add nsw i8 %a, 100
+  %c = icmp slt i8 %b, -27
+  ret i1 %c
+}
+
+define <2 x i1> @nsw_slt1_splat_vec(<2 x i8> %a) {
+; CHECK-LABEL: @nsw_slt1_splat_vec(
+; CHECK-NEXT:    [[C:%.*]] = icmp eq <2 x i8> [[A:%.*]], <i8 -128, i8 -128>
+; CHECK-NEXT:    ret <2 x i1> [[C]]
+;
+  %b = add nsw <2 x i8> %a, <i8 100, i8 100>
+  %c = icmp slt <2 x i8> %b, <i8 -27, i8 -27>
+  ret <2 x i1> %c
+}
+
+; icmp Pred (add nsw X, C2), C --> icmp Pred X, (C - C2), when C - C2 does not overflow.
+; This becomes equality because it's at the limit.
+
+define i1 @nsw_slt2(i8 %a) {
+; CHECK-LABEL: @nsw_slt2(
+; CHECK-NEXT:    [[C:%.*]] = icmp ne i8 [[A:%.*]], 127
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %b = add nsw i8 %a, -100
+  %c = icmp slt i8 %b, 27
+  ret i1 %c
+}
+
+define <2 x i1> @nsw_slt2_splat_vec(<2 x i8> %a) {
+; CHECK-LABEL: @nsw_slt2_splat_vec(
+; CHECK-NEXT:    [[C:%.*]] = icmp ne <2 x i8> [[A:%.*]], <i8 127, i8 127>
+; CHECK-NEXT:    ret <2 x i1> [[C]]
+;
+  %b = add nsw <2 x i8> %a, <i8 -100, i8 -100>
+  %c = icmp slt <2 x i8> %b, <i8 27, i8 27>
+  ret <2 x i1> %c
+}
+
+; icmp Pred (add nsw X, C2), C --> icmp Pred X, (C - C2), when C - C2 does not overflow.
+; Less than the limit, so the predicate doesn't change.
+
+define i1 @nsw_slt3(i8 %a) {
+; CHECK-LABEL: @nsw_slt3(
+; CHECK-NEXT:    [[C:%.*]] = icmp slt i8 [[A:%.*]], -126
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %b = add nsw i8 %a, 100
+  %c = icmp slt i8 %b, -26
+  ret i1 %c
+}
+
+; icmp Pred (add nsw X, C2), C --> icmp Pred X, (C - C2), when C - C2 does not overflow.
+; Less than the limit, so the predicate doesn't change.
+
+define i1 @nsw_slt4(i8 %a) {
+; CHECK-LABEL: @nsw_slt4(
+; CHECK-NEXT:    [[C:%.*]] = icmp slt i8 [[A:%.*]], 126
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %b = add nsw i8 %a, -100
+  %c = icmp slt i8 %b, 26
+  ret i1 %c
+}
+
+; icmp Pred (add nsw X, C2), C --> icmp Pred X, (C - C2), when C - C2 does not overflow.
+; Try sgt to make sure that works too.
+
+define i1 @nsw_sgt1(i8 %a) {
+; CHECK-LABEL: @nsw_sgt1(
+; CHECK-NEXT:    [[C:%.*]] = icmp eq i8 [[A:%.*]], 127
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %b = add nsw i8 %a, -100
+  %c = icmp sgt i8 %b, 26
+  ret i1 %c
+}
+
+define <2 x i1> @nsw_sgt1_splat_vec(<2 x i8> %a) {
+; CHECK-LABEL: @nsw_sgt1_splat_vec(
+; CHECK-NEXT:    [[C:%.*]] = icmp eq <2 x i8> [[A:%.*]], <i8 127, i8 127>
+; CHECK-NEXT:    ret <2 x i1> [[C]]
+;
+  %b = add nsw <2 x i8> %a, <i8 -100, i8 -100>
+  %c = icmp sgt <2 x i8> %b, <i8 26, i8 26>
+  ret <2 x i1> %c
+}
+
+define i1 @nsw_sgt2(i8 %a) {
+; CHECK-LABEL: @nsw_sgt2(
+; CHECK-NEXT:    [[C:%.*]] = icmp sgt i8 [[A:%.*]], -126
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %b = add nsw i8 %a, 100
+  %c = icmp sgt i8 %b, -26
+  ret i1 %c
+}
+
+define <2 x i1> @nsw_sgt2_splat_vec(<2 x i8> %a) {
+; CHECK-LABEL: @nsw_sgt2_splat_vec(
+; CHECK-NEXT:    [[C:%.*]] = icmp sgt <2 x i8> [[A:%.*]], <i8 -126, i8 -126>
+; CHECK-NEXT:    ret <2 x i1> [[C]]
+;
+  %b = add nsw <2 x i8> %a, <i8 100, i8 100>
+  %c = icmp sgt <2 x i8> %b, <i8 -26, i8 -26>
+  ret <2 x i1> %c
+}
+
+; icmp Pred (add nsw X, C2), C --> icmp Pred X, (C - C2), when C - C2 does not overflow.
+; Comparison with 0 doesn't need special-casing.
+
+define i1 @slt_zero_add_nsw(i32 %a) {
+; CHECK-LABEL: @slt_zero_add_nsw(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i32 [[A:%.*]], -1
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %add = add nsw i32 %a, 1
+  %cmp = icmp slt i32 %add, 0
+  ret i1 %cmp
+}
+
+; The same fold should work with vectors.
+
+define <2 x i1> @slt_zero_add_nsw_splat_vec(<2 x i8> %a) {
+; CHECK-LABEL: @slt_zero_add_nsw_splat_vec(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp slt <2 x i8> [[A:%.*]], <i8 -1, i8 -1>
+; CHECK-NEXT:    ret <2 x i1> [[CMP]]
+;
+  %add = add nsw <2 x i8> %a, <i8 1, i8 1>
+  %cmp = icmp slt <2 x i8> %add, zeroinitializer
+  ret <2 x i1> %cmp
+}
+
+; Test the edges - instcombine should not interfere with simplification to constants.
+; Constant subtraction does not overflow, but this is false.
+
+define i1 @nsw_slt3_ov_no(i8 %a) {
+; CHECK-LABEL: @nsw_slt3_ov_no(
+; CHECK-NEXT:    ret i1 false
+;
+  %b = add nsw i8 %a, 100
+  %c = icmp slt i8 %b, -28
+  ret i1 %c
+}
+
+; Test the edges - instcombine should not interfere with simplification to constants.
+; Constant subtraction overflows. This is false.
+
+define i1 @nsw_slt4_ov(i8 %a) {
+; CHECK-LABEL: @nsw_slt4_ov(
+; CHECK-NEXT:    ret i1 false
+;
+  %b = add nsw i8 %a, 100
+  %c = icmp slt i8 %b, -29
+  ret i1 %c
+}
+
+; Test the edges - instcombine should not interfere with simplification to constants.
+; Constant subtraction overflows. This is true.
+
+define i1 @nsw_slt5_ov(i8 %a) {
+; CHECK-LABEL: @nsw_slt5_ov(
+; CHECK-NEXT:    ret i1 true
+;
+  %b = add nsw i8 %a, -100
+  %c = icmp slt i8 %b, 28
+  ret i1 %c
+}
+
+; InstCombine should not thwart this opportunity to simplify completely.
+
+define i1 @slt_zero_add_nsw_signbit(i8 %x) {
+; CHECK-LABEL: @slt_zero_add_nsw_signbit(
+; CHECK-NEXT:    ret i1 true
+;
+  %y = add nsw i8 %x, -128
+  %z = icmp slt i8 %y, 0
+  ret i1 %z
+}
+
+; InstCombine should not thwart this opportunity to simplify completely.
+
+define i1 @slt_zero_add_nuw_signbit(i8 %x) {
+; CHECK-LABEL: @slt_zero_add_nuw_signbit(
+; CHECK-NEXT:    ret i1 true
+;
+  %y = add nuw i8 %x, 128
+  %z = icmp slt i8 %y, 0
+  ret i1 %z
+}
+
+define i1 @reduce_add_ult(i32 %in) {
+; CHECK-LABEL: @reduce_add_ult(
+; CHECK-NEXT:    [[A18:%.*]] = icmp ult i32 [[IN:%.*]], 9
+; CHECK-NEXT:    ret i1 [[A18]]
+;
+  %a6 = add nuw i32 %in, 3
+  %a18 = icmp ult i32 %a6, 12
+  ret i1 %a18
+}
+
+define i1 @reduce_add_ugt(i32 %in) {
+; CHECK-LABEL: @reduce_add_ugt(
+; CHECK-NEXT:    [[A18:%.*]] = icmp ugt i32 [[IN:%.*]], 9
+; CHECK-NEXT:    ret i1 [[A18]]
+;
+  %a6 = add nuw i32 %in, 3
+  %a18 = icmp ugt i32 %a6, 12
+  ret i1 %a18
+}
+
+define i1 @reduce_add_ule(i32 %in) {
+; CHECK-LABEL: @reduce_add_ule(
+; CHECK-NEXT:    [[A18:%.*]] = icmp ult i32 [[IN:%.*]], 10
+; CHECK-NEXT:    ret i1 [[A18]]
+;
+  %a6 = add nuw i32 %in, 3
+  %a18 = icmp ule i32 %a6, 12
+  ret i1 %a18
+}
+
+define i1 @reduce_add_uge(i32 %in) {
+; CHECK-LABEL: @reduce_add_uge(
+; CHECK-NEXT:    [[A18:%.*]] = icmp ugt i32 [[IN:%.*]], 8
+; CHECK-NEXT:    ret i1 [[A18]]
+;
+  %a6 = add nuw i32 %in, 3
+  %a18 = icmp uge i32 %a6, 12
+  ret i1 %a18
+}
+
+define i1 @ult_add_ssubov(i32 %in) {
+; CHECK-LABEL: @ult_add_ssubov(
+; CHECK-NEXT:    ret i1 false
+;
+  %a6 = add nuw i32 %in, 71
+  %a18 = icmp ult i32 %a6, 3
+  ret i1 %a18
+}
+
+define i1 @ult_add_nonuw(i8 %in) {
+; CHECK-LABEL: @ult_add_nonuw(
+; CHECK-NEXT:    [[A6:%.*]] = add i8 [[IN:%.*]], 71
+; CHECK-NEXT:    [[A18:%.*]] = icmp ult i8 [[A6]], 12
+; CHECK-NEXT:    ret i1 [[A18]]
+;
+  %a6 = add i8 %in, 71
+  %a18 = icmp ult i8 %a6, 12
+  ret i1 %a18
+}
+
+define i1 @uge_add_nonuw(i32 %in) {
+; CHECK-LABEL: @uge_add_nonuw(
+; CHECK-NEXT:    [[A6:%.*]] = add i32 [[IN:%.*]], 3
+; CHECK-NEXT:    [[A18:%.*]] = icmp ugt i32 [[A6]], 11
+; CHECK-NEXT:    ret i1 [[A18]]
+;
+  %a6 = add i32 %in, 3
+  %a18 = icmp uge i32 %a6, 12
+  ret i1 %a18
+}
+
+; Test unsigned add overflow patterns. The div ops are only here to
+; thwart complexity based canonicalization of the operand order.
+
+define i1 @op_ugt_sum_commute1(i8 %p1, i8 %p2) {
+; CHECK-LABEL: @op_ugt_sum_commute1(
+; CHECK-NEXT:    [[X:%.*]] = sdiv i8 42, [[P1:%.*]]
+; CHECK-NEXT:    [[Y:%.*]] = sdiv i8 42, [[P2:%.*]]
+; CHECK-NEXT:    [[TMP1:%.*]] = xor i8 [[X]], -1
+; CHECK-NEXT:    [[C:%.*]] = icmp ugt i8 [[Y]], [[TMP1]]
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %x = sdiv i8 42, %p1
+  %y = sdiv i8 42, %p2
+  %a = add i8 %x, %y
+  %c = icmp ugt i8 %x, %a
+  ret i1 %c
+}
+
+define <2 x i1> @op_ugt_sum_vec_commute2(<2 x i8> %p1, <2 x i8> %p2) {
+; CHECK-LABEL: @op_ugt_sum_vec_commute2(
+; CHECK-NEXT:    [[X:%.*]] = sdiv <2 x i8> <i8 42, i8 -42>, [[P1:%.*]]
+; CHECK-NEXT:    [[Y:%.*]] = sdiv <2 x i8> <i8 42, i8 -42>, [[P2:%.*]]
+; CHECK-NEXT:    [[TMP1:%.*]] = xor <2 x i8> [[X]], <i8 -1, i8 -1>
+; CHECK-NEXT:    [[C:%.*]] = icmp ugt <2 x i8> [[Y]], [[TMP1]]
+; CHECK-NEXT:    ret <2 x i1> [[C]]
+;
+  %x = sdiv <2 x i8> <i8 42, i8 -42>, %p1
+  %y = sdiv <2 x i8> <i8 42, i8 -42>, %p2
+  %a = add <2 x i8> %y, %x
+  %c = icmp ugt <2 x i8> %x, %a
+  ret <2 x i1> %c
+}
+
+define i1 @sum_ugt_op_uses(i8 %p1, i8 %p2, i8* %p3) {
+; CHECK-LABEL: @sum_ugt_op_uses(
+; CHECK-NEXT:    [[X:%.*]] = sdiv i8 42, [[P1:%.*]]
+; CHECK-NEXT:    [[Y:%.*]] = sdiv i8 42, [[P2:%.*]]
+; CHECK-NEXT:    [[A:%.*]] = add nsw i8 [[X]], [[Y]]
+; CHECK-NEXT:    store i8 [[A]], i8* [[P3:%.*]], align 1
+; CHECK-NEXT:    [[C:%.*]] = icmp ugt i8 [[X]], [[A]]
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %x = sdiv i8 42, %p1
+  %y = sdiv i8 42, %p2
+  %a = add i8 %x, %y
+  store i8 %a, i8* %p3
+  %c = icmp ugt i8 %x, %a
+  ret i1 %c
+}
+
+define <2 x i1> @sum_ult_op_vec_commute1(<2 x i8> %p1, <2 x i8> %p2) {
+; CHECK-LABEL: @sum_ult_op_vec_commute1(
+; CHECK-NEXT:    [[X:%.*]] = sdiv <2 x i8> <i8 42, i8 -42>, [[P1:%.*]]
+; CHECK-NEXT:    [[Y:%.*]] = sdiv <2 x i8> <i8 -42, i8 42>, [[P2:%.*]]
+; CHECK-NEXT:    [[TMP1:%.*]] = xor <2 x i8> [[X]], <i8 -1, i8 -1>
+; CHECK-NEXT:    [[C:%.*]] = icmp ugt <2 x i8> [[Y]], [[TMP1]]
+; CHECK-NEXT:    ret <2 x i1> [[C]]
+;
+  %x = sdiv <2 x i8> <i8 42, i8 -42>, %p1
+  %y = sdiv <2 x i8> <i8 -42, i8 42>, %p2
+  %a = add <2 x i8> %x, %y
+  %c = icmp ult <2 x i8> %a, %x
+  ret <2 x i1> %c
+}
+
+define i1 @sum_ult_op_commute2(i8 %p1, i8 %p2) {
+; CHECK-LABEL: @sum_ult_op_commute2(
+; CHECK-NEXT:    [[X:%.*]] = sdiv i8 42, [[P1:%.*]]
+; CHECK-NEXT:    [[Y:%.*]] = sdiv i8 42, [[P2:%.*]]
+; CHECK-NEXT:    [[TMP1:%.*]] = xor i8 [[X]], -1
+; CHECK-NEXT:    [[C:%.*]] = icmp ugt i8 [[Y]], [[TMP1]]
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %x = sdiv i8 42, %p1
+  %y = sdiv i8 42, %p2
+  %a = add i8 %y, %x
+  %c = icmp ult i8 %a, %x
+  ret i1 %c
+}
+
+define i1 @sum_ult_op_uses(i8 %x, i8 %y, i8* %p) {
+; CHECK-LABEL: @sum_ult_op_uses(
+; CHECK-NEXT:    [[A:%.*]] = add i8 [[Y:%.*]], [[X:%.*]]
+; CHECK-NEXT:    store i8 [[A]], i8* [[P:%.*]], align 1
+; CHECK-NEXT:    [[C:%.*]] = icmp ult i8 [[A]], [[X]]
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %a = add i8 %y, %x
+  store i8 %a, i8* %p
+  %c = icmp ult i8 %a, %x
+  ret i1 %c
+}
+

Added: llvm/trunk/test/Transforms/InstCombine/icmp-bc-vec.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/icmp-bc-vec.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/icmp-bc-vec.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/icmp-bc-vec.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,127 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt < %s -instcombine -S | FileCheck %s
+
+; Tests to verify proper functioning of the icmp folding implemented in
+;  InstCombiner::foldICmpBitCastConstant
+; Specifically, folding:
+;   icmp <pred> iN X, C
+;  where X = bitcast <M x iK> (shufflevector <M x iK> %vec, undef, SC)) to iN
+;    and C is a splat of a K-bit pattern
+;    and SC is a constant vector = <C', C', C', ..., C'>
+; Into:
+;  %E = extractelement <M x iK> %vec, i32 C'
+;  icmp <pred> iK %E, trunc(C)
+
+define i1 @test_i1_0(i1 %val) {
+; CHECK-LABEL: @test_i1_0(
+; CHECK-NEXT:    [[COND:%.*]] = xor i1 [[VAL:%.*]], true
+; CHECK-NEXT:    ret i1 [[COND]]
+;
+  %insvec = insertelement <4 x i1> undef, i1 %val, i32 0
+  %vec = shufflevector <4 x i1> %insvec, <4 x i1> undef, <4 x i32> zeroinitializer
+  %cast = bitcast <4 x i1> %vec to i4
+  %cond = icmp eq i4 %cast, 0
+  ret i1 %cond
+}
+
+define i1 @test_i1_0_2(i1 %val) {
+; CHECK-LABEL: @test_i1_0_2(
+; CHECK-NEXT:    [[COND:%.*]] = xor i1 [[VAL:%.*]], true
+; CHECK-NEXT:    ret i1 [[COND]]
+;
+  %insvec = insertelement <4 x i1> undef, i1 %val, i32 2
+  %vec = shufflevector <4 x i1> %insvec, <4 x i1> undef, <4 x i32> <i32 2, i32 2, i32 2, i32 2>
+  %cast = bitcast <4 x i1> %vec to i4
+  %cond = icmp eq i4 %cast, 0
+  ret i1 %cond
+}
+
+define i1 @test_i1_m1(i1 %val) {
+; CHECK-LABEL: @test_i1_m1(
+; CHECK-NEXT:    ret i1 [[VAL:%.*]]
+;
+  %insvec = insertelement <4 x i1> undef, i1 %val, i32 0
+  %vec = shufflevector <4 x i1> %insvec, <4 x i1> undef, <4 x i32> zeroinitializer
+  %cast = bitcast <4 x i1> %vec to i4
+  %cond = icmp eq i4 %cast, -1
+  ret i1 %cond
+}
+
+define i1 @test_i8_pattern(i8 %val) {
+; CHECK-LABEL: @test_i8_pattern(
+; CHECK-NEXT:    [[COND:%.*]] = icmp eq i8 [[VAL:%.*]], 72
+; CHECK-NEXT:    ret i1 [[COND]]
+;
+  %insvec = insertelement <4 x i8> undef, i8 %val, i32 0
+  %vec = shufflevector <4 x i8> %insvec, <4 x i8> undef, <4 x i32> zeroinitializer
+  %cast = bitcast <4 x i8> %vec to i32
+  %cond = icmp eq i32 %cast, 1212696648
+  ret i1 %cond
+}
+
+define i1 @test_i8_pattern_2(i8 %val) {
+; CHECK-LABEL: @test_i8_pattern_2(
+; CHECK-NEXT:    [[COND:%.*]] = icmp eq i8 [[VAL:%.*]], 72
+; CHECK-NEXT:    ret i1 [[COND]]
+;
+  %insvec = insertelement <4 x i8> undef, i8 %val, i32 2
+  %vec = shufflevector <4 x i8> %insvec, <4 x i8> undef, <4 x i32> <i32 2, i32 2, i32 2, i32 2>
+  %cast = bitcast <4 x i8> %vec to i32
+  %cond = icmp eq i32 %cast, 1212696648
+  ret i1 %cond
+}
+
+; Make sure we don't try to fold if the shufflemask has differing element values
+define i1 @test_i8_pattern_3(<4 x i8> %invec) {
+; CHECK-LABEL: @test_i8_pattern_3(
+; CHECK-NEXT:    [[VEC:%.*]] = shufflevector <4 x i8> [[INVEC:%.*]], <4 x i8> undef, <4 x i32> <i32 1, i32 0, i32 3, i32 2>
+; CHECK-NEXT:    [[CAST:%.*]] = bitcast <4 x i8> [[VEC]] to i32
+; CHECK-NEXT:    [[COND:%.*]] = icmp eq i32 [[CAST]], 1212696648
+; CHECK-NEXT:    ret i1 [[COND]]
+;
+  %vec = shufflevector <4 x i8> %invec, <4 x i8> undef, <4 x i32> <i32 1, i32 0, i32 3, i32 2>
+  %cast = bitcast <4 x i8> %vec to i32
+  %cond = icmp eq i32 %cast, 1212696648
+  ret i1 %cond
+}
+
+; Make sure we don't try to fold if the compared-to constant isn't a splatted value
+define i1 @test_i8_nopattern(i8 %val) {
+; CHECK-LABEL: @test_i8_nopattern(
+; CHECK-NEXT:    [[INSVEC:%.*]] = insertelement <4 x i8> undef, i8 [[VAL:%.*]], i32 0
+; CHECK-NEXT:    [[VEC:%.*]] = shufflevector <4 x i8> [[INSVEC]], <4 x i8> undef, <4 x i32> zeroinitializer
+; CHECK-NEXT:    [[CAST:%.*]] = bitcast <4 x i8> [[VEC]] to i32
+; CHECK-NEXT:    [[COND:%.*]] = icmp eq i32 [[CAST]], 1212696647
+; CHECK-NEXT:    ret i1 [[COND]]
+;
+  %insvec = insertelement <4 x i8> undef, i8 %val, i32 0
+  %vec = shufflevector <4 x i8> %insvec, <4 x i8> undef, <4 x i32> zeroinitializer
+  %cast = bitcast <4 x i8> %vec to i32
+  %cond = icmp eq i32 %cast, 1212696647
+  ret i1 %cond
+}
+
+; Verify that we fold more than just the eq predicate
+define i1 @test_i8_ult_pattern(i8 %val) {
+; CHECK-LABEL: @test_i8_ult_pattern(
+; CHECK-NEXT:    [[COND:%.*]] = icmp ult i8 [[VAL:%.*]], 72
+; CHECK-NEXT:    ret i1 [[COND]]
+;
+  %insvec = insertelement <4 x i8> undef, i8 %val, i32 0
+  %vec = shufflevector <4 x i8> %insvec, <4 x i8> undef, <4 x i32> zeroinitializer
+  %cast = bitcast <4 x i8> %vec to i32
+  %cond = icmp ult i32 %cast, 1212696648
+  ret i1 %cond
+}
+
+define i1 @extending_shuffle_with_weird_types(<2 x i9> %v) {
+; CHECK-LABEL: @extending_shuffle_with_weird_types(
+; CHECK-NEXT:    [[TMP1:%.*]] = extractelement <2 x i9> [[V:%.*]], i32 0
+; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i9 [[TMP1]], 1
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %splat = shufflevector <2 x i9> %v, <2 x i9> undef, <3 x i32> zeroinitializer
+  %cast = bitcast <3 x i9> %splat to i27
+  %cmp = icmp slt i27 %cast, 262657 ; 0x040201
+  ret i1 %cmp
+}

Added: llvm/trunk/test/Transforms/InstCombine/icmp-custom-dl.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/icmp-custom-dl.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/icmp-custom-dl.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/icmp-custom-dl.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,247 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt < %s -instcombine -S | FileCheck %s
+
+target datalayout = "e-p:40:64:64:32-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"
+
+declare i32 @test58_d(i64 )
+
+define i1 @test59(i8* %foo) {
+; CHECK-LABEL: @test59(
+; CHECK-NEXT:    [[GEP1:%.*]] = getelementptr inbounds i8, i8* [[FOO:%.*]], i32 8
+; CHECK-NEXT:    [[TMP1:%.*]] = ptrtoint i8* [[GEP1]] to i32
+; CHECK-NEXT:    [[USE:%.*]] = zext i32 [[TMP1]] 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:    [[TMP1:%.*]] = trunc i64 [[I:%.*]] to i32
+; CHECK-NEXT:    [[TMP2:%.*]] = trunc i64 [[J:%.*]] to i32
+; CHECK-NEXT:    [[GEP1_IDX:%.*]] = shl nuw i32 [[TMP1]], 2
+; CHECK-NEXT:    [[TMP3:%.*]] = icmp slt i32 [[GEP1_IDX]], [[TMP2]]
+; CHECK-NEXT:    ret i1 [[TMP3]]
+;
+  %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:    [[TMP1:%.*]] = trunc i64 [[J:%.*]] to i32
+; CHECK-NEXT:    [[I_TR:%.*]] = trunc i64 [[I:%.*]] to i32
+; CHECK-NEXT:    [[TMP2:%.*]] = shl i32 [[I_TR]], 2
+; CHECK-NEXT:    [[TMP3:%.*]] = icmp slt i32 [[TMP2]], [[TMP1]]
+; CHECK-NEXT:    ret i1 [[TMP3]]
+;
+  %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:    [[TMP1:%.*]] = trunc i64 [[I:%.*]] to i32
+; CHECK-NEXT:    [[GEP1:%.*]] = getelementptr i32, i32* [[BIT]], i32 [[TMP1]]
+; CHECK-NEXT:    [[TMP2:%.*]] = trunc i64 [[J:%.*]] to i32
+; CHECK-NEXT:    [[GEP2:%.*]] = getelementptr i8, i8* [[FOO]], i32 [[TMP2]]
+; 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
+}
+
+
+; 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
+}
+

Added: llvm/trunk/test/Transforms/InstCombine/icmp-div-constant.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/icmp-div-constant.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/icmp-div-constant.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/icmp-div-constant.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,93 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt < %s -instcombine -S | FileCheck %s
+
+; PR30281 - https://llvm.org/bugs/show_bug.cgi?id=30281
+
+; All of these tests contain foldable division-by-constant instructions, but we
+; can't assert that those folds have occurred before we process the later icmp.
+
+define i32 @icmp_div(i16 %a, i16 %c) {
+; CHECK-LABEL: @icmp_div(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[TOBOOL:%.*]] = icmp eq i16 %a, 0
+; CHECK-NEXT:    br i1 [[TOBOOL]], label %then, label %exit
+; CHECK:       then:
+; CHECK-NEXT:    [[NOT_CMP:%.*]] = icmp eq i16 %c, 0
+; CHECK-NEXT:    [[PHITMP1:%.*]] = sext i1 [[NOT_CMP]] to i32
+; CHECK-NEXT:    br label %exit
+; CHECK:       exit:
+; CHECK-NEXT:    [[PHI:%.*]] = phi i32 [ -1, %entry ], [ [[PHITMP1]], %then ]
+; CHECK-NEXT:    ret i32 [[PHI]]
+;
+entry:
+  %tobool = icmp eq i16 %a, 0
+  br i1 %tobool, label %then, label %exit
+
+then:
+  %div = sdiv i16 %c, -1
+  %cmp = icmp ne i16 %div, 0
+  br label %exit
+
+exit:
+  %phi = phi i1 [ false, %entry ], [ %cmp, %then ]
+  %zext = zext i1 %phi to i32
+  %add = add nsw i32 %zext, -1
+  ret i32 %add
+}
+
+define i32 @icmp_div2(i16 %a, i16 %c) {
+; CHECK-LABEL: @icmp_div2(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[TOBOOL:%.*]] = icmp eq i16 %a, 0
+; CHECK-NEXT:    br i1 [[TOBOOL]], label %then, label %exit
+; CHECK:       then:
+; CHECK-NEXT:    br label %exit
+; CHECK:       exit:
+; CHECK-NEXT:    [[PHI:%.*]] = phi i32 [ -1, %entry ], [ 0, %then ]
+; CHECK-NEXT:    ret i32 [[PHI]]
+;
+entry:
+  %tobool = icmp eq i16 %a, 0
+  br i1 %tobool, label %then, label %exit
+
+then:
+  %div = sdiv i16 %c, 0
+  %cmp = icmp ne i16 %div, 0
+  br label %exit
+
+exit:
+  %phi = phi i1 [ false, %entry ], [ %cmp, %then ]
+  %zext = zext i1 %phi to i32
+  %add = add nsw i32 %zext, -1
+  ret i32 %add
+}
+
+define i32 @icmp_div3(i16 %a, i16 %c) {
+; CHECK-LABEL: @icmp_div3(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[TOBOOL:%.*]] = icmp eq i16 %a, 0
+; CHECK-NEXT:    br i1 [[TOBOOL]], label %then, label %exit
+; CHECK:       then:
+; CHECK-NEXT:    [[NOT_CMP:%.*]] = icmp eq i16 %c, 0
+; CHECK-NEXT:    [[PHITMP1:%.*]] = sext i1 [[NOT_CMP]] to i32
+; CHECK-NEXT:    br label %exit
+; CHECK:       exit:
+; CHECK-NEXT:    [[PHI:%.*]] = phi i32 [ -1, %entry ], [ [[PHITMP1]], %then ]
+; CHECK-NEXT:    ret i32 [[PHI]]
+;
+entry:
+  %tobool = icmp eq i16 %a, 0
+  br i1 %tobool, label %then, label %exit
+
+then:
+  %div = sdiv i16 %c, 1
+  %cmp = icmp ne i16 %div, 0
+  br label %exit
+
+exit:
+  %phi = phi i1 [ false, %entry ], [ %cmp, %then ]
+  %zext = zext i1 %phi to i32
+  %add = add nsw i32 %zext, -1
+  ret i32 %add
+}
+

Added: llvm/trunk/test/Transforms/InstCombine/icmp-dom.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/icmp-dom.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/icmp-dom.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/icmp-dom.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,350 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt < %s -instcombine -S | FileCheck %s
+
+define void @idom_sign_bit_check_edge_dominates(i64 %a) {
+; CHECK-LABEL: @idom_sign_bit_check_edge_dominates(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i64 [[A:%.*]], 0
+; CHECK-NEXT:    br i1 [[CMP]], label [[LAND_LHS_TRUE:%.*]], label [[LOR_RHS:%.*]]
+; CHECK:       land.lhs.true:
+; CHECK-NEXT:    br label [[LOR_END:%.*]]
+; CHECK:       lor.rhs:
+; CHECK-NEXT:    [[CMP2:%.*]] = icmp eq i64 [[A]], 0
+; CHECK-NEXT:    br i1 [[CMP2]], label [[LOR_END]], label [[LAND_RHS:%.*]]
+; CHECK:       land.rhs:
+; CHECK-NEXT:    br label [[LOR_END]]
+; CHECK:       lor.end:
+; CHECK-NEXT:    ret void
+;
+entry:
+  %cmp = icmp slt i64 %a, 0
+  br i1 %cmp, label %land.lhs.true, label %lor.rhs
+
+land.lhs.true:
+  br label %lor.end
+
+lor.rhs:
+  %cmp2 = icmp sgt i64 %a, 0
+  br i1 %cmp2, label %land.rhs, label %lor.end
+
+land.rhs:
+  br label %lor.end
+
+lor.end:
+  ret void
+}
+
+define void @idom_sign_bit_check_edge_not_dominates(i64 %a) {
+; CHECK-LABEL: @idom_sign_bit_check_edge_not_dominates(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i64 [[A:%.*]], 0
+; CHECK-NEXT:    br i1 [[CMP]], label [[LAND_LHS_TRUE:%.*]], label [[LOR_RHS:%.*]]
+; CHECK:       land.lhs.true:
+; CHECK-NEXT:    br i1 undef, label [[LOR_END:%.*]], label [[LOR_RHS]]
+; CHECK:       lor.rhs:
+; CHECK-NEXT:    [[CMP2:%.*]] = icmp sgt i64 [[A]], 0
+; CHECK-NEXT:    br i1 [[CMP2]], label [[LAND_RHS:%.*]], label [[LOR_END]]
+; CHECK:       land.rhs:
+; CHECK-NEXT:    br label [[LOR_END]]
+; CHECK:       lor.end:
+; CHECK-NEXT:    ret void
+;
+entry:
+  %cmp = icmp slt i64 %a, 0
+  br i1 %cmp, label %land.lhs.true, label %lor.rhs
+
+land.lhs.true:
+  br i1 undef, label %lor.end, label %lor.rhs
+
+lor.rhs:
+  %cmp2 = icmp sgt i64 %a, 0
+  br i1 %cmp2, label %land.rhs, label %lor.end
+
+land.rhs:
+  br label %lor.end
+
+lor.end:
+  ret void
+}
+
+define void @idom_sign_bit_check_edge_dominates_select(i64 %a, i64 %b) {
+; CHECK-LABEL: @idom_sign_bit_check_edge_dominates_select(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i64 [[A:%.*]], 5
+; CHECK-NEXT:    br i1 [[CMP]], label [[LAND_LHS_TRUE:%.*]], label [[LOR_RHS:%.*]]
+; CHECK:       land.lhs.true:
+; CHECK-NEXT:    br label [[LOR_END:%.*]]
+; CHECK:       lor.rhs:
+; CHECK-NEXT:    [[CMP3:%.*]] = icmp eq i64 [[A]], [[B:%.*]]
+; CHECK-NEXT:    br i1 [[CMP3]], label [[LOR_END]], label [[LAND_RHS:%.*]]
+; CHECK:       land.rhs:
+; CHECK-NEXT:    br label [[LOR_END]]
+; CHECK:       lor.end:
+; CHECK-NEXT:    ret void
+;
+entry:
+  %cmp = icmp slt i64 %a, 5
+  br i1 %cmp, label %land.lhs.true, label %lor.rhs
+
+land.lhs.true:
+  br label %lor.end
+
+lor.rhs:
+  %cmp2 = icmp sgt i64 %a, 5
+  %select = select i1 %cmp2, i64 %a, i64 5
+  %cmp3 = icmp ne i64 %select, %b
+  br i1 %cmp3, label %land.rhs, label %lor.end
+
+land.rhs:
+  br label %lor.end
+
+lor.end:
+  ret void
+}
+
+define void @idom_zbranch(i64 %a) {
+; CHECK-LABEL: @idom_zbranch(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt i64 [[A:%.*]], 0
+; CHECK-NEXT:    br i1 [[CMP]], label [[LOR_END:%.*]], label [[LOR_RHS:%.*]]
+; CHECK:       lor.rhs:
+; CHECK-NEXT:    [[CMP2:%.*]] = icmp slt i64 [[A]], 0
+; CHECK-NEXT:    br i1 [[CMP2]], label [[LAND_RHS:%.*]], label [[LOR_END]]
+; CHECK:       land.rhs:
+; CHECK-NEXT:    br label [[LOR_END]]
+; CHECK:       lor.end:
+; CHECK-NEXT:    ret void
+;
+entry:
+  %cmp = icmp sgt i64 %a, 0
+  br i1 %cmp, label %lor.end, label %lor.rhs
+
+lor.rhs:
+  %cmp2 = icmp slt i64 %a, 0
+  br i1 %cmp2, label %land.rhs, label %lor.end
+
+land.rhs:
+  br label %lor.end
+
+lor.end:
+  ret void
+}
+
+define void @idom_not_zbranch(i32 %a, i32 %b) {
+; CHECK-LABEL: @idom_not_zbranch(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt i32 [[A:%.*]], 0
+; CHECK-NEXT:    br i1 [[CMP]], label [[RETURN:%.*]], label [[IF_END:%.*]]
+; CHECK:       if.end:
+; CHECK-NEXT:    [[CMP2:%.*]] = icmp eq i32 [[A]], [[B:%.*]]
+; CHECK-NEXT:    br i1 [[CMP2]], label [[RETURN]], label [[IF_THEN3:%.*]]
+; CHECK:       if.then3:
+; CHECK-NEXT:    br label [[RETURN]]
+; CHECK:       return:
+; CHECK-NEXT:    ret void
+;
+entry:
+  %cmp = icmp sgt i32 %a, 0
+  br i1 %cmp, label %return, label %if.end
+
+if.end:
+  %cmp1 = icmp slt i32 %a, 0
+  %a. = select i1 %cmp1, i32 %a, i32 0
+  %cmp2 = icmp ne i32 %a., %b
+  br i1 %cmp2, label %if.then3, label %return
+
+if.then3:
+  br label %return
+
+return:
+  ret void
+}
+
+define void @trueblock_cmp_eq(i32 %a, i32 %b) {
+; CHECK-LABEL: @trueblock_cmp_eq(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt i32 [[A:%.*]], 0
+; CHECK-NEXT:    br i1 [[CMP]], label [[IF_END:%.*]], label [[RETURN:%.*]]
+; CHECK:       if.end:
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp eq i32 [[A]], 1
+; CHECK-NEXT:    br i1 [[CMP1]], label [[IF_THEN3:%.*]], label [[RETURN]]
+; CHECK:       if.then3:
+; CHECK-NEXT:    br label [[RETURN]]
+; CHECK:       return:
+; CHECK-NEXT:    ret void
+;
+entry:
+  %cmp = icmp sgt i32 %a, 0
+  br i1 %cmp, label %if.end, label %return
+
+if.end:
+  %cmp1 = icmp slt i32 %a, 2
+  br i1 %cmp1, label %if.then3, label %return
+
+if.then3:
+  br label %return
+
+return:
+  ret void
+}
+
+define i1 @trueblock_cmp_is_false(i32 %x, i32 %y) {
+; CHECK-LABEL: @trueblock_cmp_is_false(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt i32 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    br i1 [[CMP]], label [[T:%.*]], label [[F:%.*]]
+; CHECK:       t:
+; CHECK-NEXT:    ret i1 false
+; CHECK:       f:
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+entry:
+  %cmp = icmp sgt i32 %x, %y
+  br i1 %cmp, label %t, label %f
+t:
+  %cmp2 = icmp slt i32 %x, %y
+  ret i1 %cmp2
+f:
+  ret i1 %cmp
+}
+
+define i1 @trueblock_cmp_is_false_commute(i32 %x, i32 %y) {
+; CHECK-LABEL: @trueblock_cmp_is_false_commute(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    br i1 [[CMP]], label [[T:%.*]], label [[F:%.*]]
+; CHECK:       t:
+; CHECK-NEXT:    ret i1 false
+; CHECK:       f:
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+entry:
+  %cmp = icmp eq i32 %x, %y
+  br i1 %cmp, label %t, label %f
+t:
+  %cmp2 = icmp sgt i32 %y, %x
+  ret i1 %cmp2
+f:
+  ret i1 %cmp
+}
+
+define i1 @trueblock_cmp_is_true(i32 %x, i32 %y) {
+; CHECK-LABEL: @trueblock_cmp_is_true(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i32 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    br i1 [[CMP]], label [[T:%.*]], label [[F:%.*]]
+; CHECK:       t:
+; CHECK-NEXT:    ret i1 true
+; CHECK:       f:
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+entry:
+  %cmp = icmp ult i32 %x, %y
+  br i1 %cmp, label %t, label %f
+t:
+  %cmp2 = icmp ne i32 %x, %y
+  ret i1 %cmp2
+f:
+  ret i1 %cmp
+}
+
+define i1 @trueblock_cmp_is_true_commute(i32 %x, i32 %y) {
+; CHECK-LABEL: @trueblock_cmp_is_true_commute(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ugt i32 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    br i1 [[CMP]], label [[T:%.*]], label [[F:%.*]]
+; CHECK:       t:
+; CHECK-NEXT:    ret i1 true
+; CHECK:       f:
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+entry:
+  %cmp = icmp ugt i32 %x, %y
+  br i1 %cmp, label %t, label %f
+t:
+  %cmp2 = icmp ne i32 %y, %x
+  ret i1 %cmp2
+f:
+  ret i1 %cmp
+}
+
+define i1 @falseblock_cmp_is_false(i32 %x, i32 %y) {
+; CHECK-LABEL: @falseblock_cmp_is_false(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[CMP:%.*]] = icmp sle i32 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    br i1 [[CMP]], label [[T:%.*]], label [[F:%.*]]
+; CHECK:       t:
+; CHECK-NEXT:    ret i1 [[CMP]]
+; CHECK:       f:
+; CHECK-NEXT:    ret i1 false
+;
+entry:
+  %cmp = icmp sle i32 %x, %y
+  br i1 %cmp, label %t, label %f
+t:
+  ret i1 %cmp
+f:
+  %cmp2 = icmp slt i32 %x, %y
+  ret i1 %cmp2
+}
+
+define i1 @falseblock_cmp_is_false_commute(i32 %x, i32 %y) {
+; CHECK-LABEL: @falseblock_cmp_is_false_commute(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    br i1 [[CMP]], label [[T:%.*]], label [[F:%.*]]
+; CHECK:       t:
+; CHECK-NEXT:    ret i1 [[CMP]]
+; CHECK:       f:
+; CHECK-NEXT:    ret i1 false
+;
+entry:
+  %cmp = icmp eq i32 %x, %y
+  br i1 %cmp, label %t, label %f
+t:
+  ret i1 %cmp
+f:
+  %cmp2 = icmp eq i32 %y, %x
+  ret i1 %cmp2
+}
+
+define i1 @falseblock_cmp_is_true(i32 %x, i32 %y) {
+; CHECK-LABEL: @falseblock_cmp_is_true(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i32 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    br i1 [[CMP]], label [[T:%.*]], label [[F:%.*]]
+; CHECK:       t:
+; CHECK-NEXT:    ret i1 [[CMP]]
+; CHECK:       f:
+; CHECK-NEXT:    ret i1 true
+;
+entry:
+  %cmp = icmp ult i32 %x, %y
+  br i1 %cmp, label %t, label %f
+t:
+  ret i1 %cmp
+f:
+  %cmp2 = icmp uge i32 %x, %y
+  ret i1 %cmp2
+}
+
+define i1 @falseblock_cmp_is_true_commute(i32 %x, i32 %y) {
+; CHECK-LABEL: @falseblock_cmp_is_true_commute(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt i32 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    br i1 [[CMP]], label [[T:%.*]], label [[F:%.*]]
+; CHECK:       t:
+; CHECK-NEXT:    ret i1 [[CMP]]
+; CHECK:       f:
+; CHECK-NEXT:    ret i1 true
+;
+entry:
+  %cmp = icmp sgt i32 %x, %y
+  br i1 %cmp, label %t, label %f
+t:
+  ret i1 %cmp
+f:
+  %cmp2 = icmp sge i32 %y, %x
+  ret i1 %cmp2
+}
+

Added: llvm/trunk/test/Transforms/InstCombine/icmp-logical.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/icmp-logical.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/icmp-logical.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/icmp-logical.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,910 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt -instcombine -S -o - %s | FileCheck %s
+
+define i1 @masked_and_notallzeroes(i32 %A) {
+; CHECK-LABEL: @masked_and_notallzeroes(
+; CHECK-NEXT:    [[MASK1:%.*]] = and i32 [[A:%.*]], 7
+; CHECK-NEXT:    [[TST1:%.*]] = icmp ne i32 [[MASK1]], 0
+; CHECK-NEXT:    ret i1 [[TST1]]
+;
+  %mask1 = and i32 %A, 7
+  %tst1 = icmp ne i32 %mask1, 0
+  %mask2 = and i32 %A, 39
+  %tst2 = icmp ne i32 %mask2, 0
+  %res = and i1 %tst1, %tst2
+  ret i1 %res
+}
+
+define i1 @masked_or_allzeroes(i32 %A) {
+; CHECK-LABEL: @masked_or_allzeroes(
+; CHECK-NEXT:    [[MASK1:%.*]] = and i32 [[A:%.*]], 7
+; CHECK-NEXT:    [[TST1:%.*]] = icmp eq i32 [[MASK1]], 0
+; CHECK-NEXT:    ret i1 [[TST1]]
+;
+  %mask1 = and i32 %A, 7
+  %tst1 = icmp eq i32 %mask1, 0
+  %mask2 = and i32 %A, 39
+  %tst2 = icmp eq i32 %mask2, 0
+  %res = or i1 %tst1, %tst2
+  ret i1 %res
+}
+
+define i1 @masked_and_notallones(i32 %A) {
+; CHECK-LABEL: @masked_and_notallones(
+; CHECK-NEXT:    [[MASK1:%.*]] = and i32 [[A:%.*]], 7
+; CHECK-NEXT:    [[TST1:%.*]] = icmp ne i32 [[MASK1]], 7
+; CHECK-NEXT:    ret i1 [[TST1]]
+;
+  %mask1 = and i32 %A, 7
+  %tst1 = icmp ne i32 %mask1, 7
+  %mask2 = and i32 %A, 39
+  %tst2 = icmp ne i32 %mask2, 39
+  %res = and i1 %tst1, %tst2
+  ret i1 %res
+}
+
+define i1 @masked_or_allones(i32 %A) {
+; CHECK-LABEL: @masked_or_allones(
+; CHECK-NEXT:    [[MASK1:%.*]] = and i32 [[A:%.*]], 7
+; CHECK-NEXT:    [[TST1:%.*]] = icmp eq i32 [[MASK1]], 7
+; CHECK-NEXT:    ret i1 [[TST1]]
+;
+  %mask1 = and i32 %A, 7
+  %tst1 = icmp eq i32 %mask1, 7
+  %mask2 = and i32 %A, 39
+  %tst2 = icmp eq i32 %mask2, 39
+  %res = or i1 %tst1, %tst2
+  ret i1 %res
+}
+
+define i1 @masked_and_notA(i32 %A) {
+; CHECK-LABEL: @masked_and_notA(
+; CHECK-NEXT:    [[MASK2:%.*]] = and i32 [[A:%.*]], 78
+; CHECK-NEXT:    [[TST2:%.*]] = icmp ne i32 [[MASK2]], [[A]]
+; CHECK-NEXT:    ret i1 [[TST2]]
+;
+  %mask1 = and i32 %A, 14
+  %tst1 = icmp ne i32 %mask1, %A
+  %mask2 = and i32 %A, 78
+  %tst2 = icmp ne i32 %mask2, %A
+  %res = and i1 %tst1, %tst2
+  ret i1 %res
+}
+
+define i1 @masked_and_notA_slightly_optimized(i32 %A) {
+; CHECK-LABEL: @masked_and_notA_slightly_optimized(
+; CHECK-NEXT:    [[TMP0:%.*]] = icmp ugt i32 [[A:%.*]], 7
+; CHECK-NEXT:    [[MASK2:%.*]] = and i32 [[A]], 39
+; CHECK-NEXT:    [[TST2:%.*]] = icmp ne i32 [[MASK2]], [[A]]
+; CHECK-NEXT:    [[RES:%.*]] = and i1 [[TMP0]], [[TST2]]
+; CHECK-NEXT:    ret i1 [[RES]]
+;
+  %tmp0 = icmp uge i32 %A, 8
+  %mask2 = and i32 %A, 39
+  %tst2 = icmp ne i32 %mask2, %A
+  %res = and i1 %tmp0, %tst2
+  ret i1 %res
+}
+
+define i1 @masked_or_A(i32 %A) {
+; CHECK-LABEL: @masked_or_A(
+; CHECK-NEXT:    [[MASK2:%.*]] = and i32 [[A:%.*]], 78
+; CHECK-NEXT:    [[TST2:%.*]] = icmp eq i32 [[MASK2]], [[A]]
+; CHECK-NEXT:    ret i1 [[TST2]]
+;
+  %mask1 = and i32 %A, 14
+  %tst1 = icmp eq i32 %mask1, %A
+  %mask2 = and i32 %A, 78
+  %tst2 = icmp eq i32 %mask2, %A
+  %res = or i1 %tst1, %tst2
+  ret i1 %res
+}
+
+define i1 @masked_or_A_slightly_optimized(i32 %A) {
+; CHECK-LABEL: @masked_or_A_slightly_optimized(
+; CHECK-NEXT:    [[TMP0:%.*]] = icmp ult i32 [[A:%.*]], 8
+; CHECK-NEXT:    [[MASK2:%.*]] = and i32 [[A]], 39
+; CHECK-NEXT:    [[TST2:%.*]] = icmp eq i32 [[MASK2]], [[A]]
+; CHECK-NEXT:    [[RES:%.*]] = or i1 [[TMP0]], [[TST2]]
+; CHECK-NEXT:    ret i1 [[RES]]
+;
+  %tmp0 = icmp ult i32 %A, 8
+  %mask2 = and i32 %A, 39
+  %tst2 = icmp eq i32 %mask2, %A
+  %res = or i1 %tmp0, %tst2
+  ret i1 %res
+}
+
+define i1 @masked_or_allzeroes_notoptimised(i32 %A) {
+; CHECK-LABEL: @masked_or_allzeroes_notoptimised(
+; CHECK-NEXT:    [[MASK1:%.*]] = and i32 [[A:%.*]], 15
+; CHECK-NEXT:    [[TST1:%.*]] = icmp eq i32 [[MASK1]], 0
+; CHECK-NEXT:    [[MASK2:%.*]] = and i32 [[A]], 39
+; CHECK-NEXT:    [[TST2:%.*]] = icmp eq i32 [[MASK2]], 0
+; CHECK-NEXT:    [[RES:%.*]] = or i1 [[TST1]], [[TST2]]
+; CHECK-NEXT:    ret i1 [[RES]]
+;
+  %mask1 = and i32 %A, 15
+  %tst1 = icmp eq i32 %mask1, 0
+  %mask2 = and i32 %A, 39
+  %tst2 = icmp eq i32 %mask2, 0
+  %res = or i1 %tst1, %tst2
+  ret i1 %res
+}
+
+define i1 @nomask_lhs(i32 %in) {
+; CHECK-LABEL: @nomask_lhs(
+; CHECK-NEXT:    [[MASKED:%.*]] = and i32 [[IN:%.*]], 1
+; CHECK-NEXT:    [[TST2:%.*]] = icmp eq i32 [[MASKED]], 0
+; CHECK-NEXT:    ret i1 [[TST2]]
+;
+  %tst1 = icmp eq i32 %in, 0
+  %masked = and i32 %in, 1
+  %tst2 = icmp eq i32 %masked, 0
+  %val = or i1 %tst1, %tst2
+  ret i1 %val
+}
+
+define i1 @nomask_rhs(i32 %in) {
+; CHECK-LABEL: @nomask_rhs(
+; CHECK-NEXT:    [[MASKED:%.*]] = and i32 [[IN:%.*]], 1
+; CHECK-NEXT:    [[TST1:%.*]] = icmp eq i32 [[MASKED]], 0
+; CHECK-NEXT:    ret i1 [[TST1]]
+;
+  %masked = and i32 %in, 1
+  %tst1 = icmp eq i32 %masked, 0
+  %tst2 = icmp eq i32 %in, 0
+  %val = or i1 %tst1, %tst2
+  ret i1 %val
+}
+
+; TODO: This test simplifies to a constant, so the functionality and test could be in InstSimplify.
+
+define i1 @fold_mask_cmps_to_false(i32 %x) {
+; CHECK-LABEL: @fold_mask_cmps_to_false(
+; CHECK-NEXT:    ret i1 false
+;
+  %tmp1 = and i32 %x, 2147483647
+  %tmp2 = icmp eq i32 %tmp1, 0
+  %tmp3 = icmp eq i32 %x, 2147483647
+  %tmp4 = and i1 %tmp3, %tmp2
+  ret i1 %tmp4
+}
+
+; TODO: This test simplifies to a constant, so the functionality and test could be in InstSimplify.
+
+define i1 @fold_mask_cmps_to_true(i32 %x) {
+; CHECK-LABEL: @fold_mask_cmps_to_true(
+; CHECK-NEXT:    ret i1 true
+;
+  %tmp1 = and i32 %x, 2147483647
+  %tmp2 = icmp ne i32 %tmp1, 0
+  %tmp3 = icmp ne i32 %x, 2147483647
+  %tmp4 = or i1 %tmp3, %tmp2
+  ret i1 %tmp4
+}
+
+; PR32401 - https://bugs.llvm.org/show_bug.cgi?id=32401
+
+define i1 @cmpeq_bitwise(i8 %a, i8 %b, i8 %c, i8 %d) {
+; CHECK-LABEL: @cmpeq_bitwise(
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp eq i8 [[A:%.*]], [[B:%.*]]
+; CHECK-NEXT:    [[TMP2:%.*]] = icmp eq i8 [[C:%.*]], [[D:%.*]]
+; CHECK-NEXT:    [[CMP:%.*]] = and i1 [[TMP1]], [[TMP2]]
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %xor1 = xor i8 %a, %b
+  %xor2 = xor i8 %c, %d
+  %or = or i8 %xor1, %xor2
+  %cmp = icmp eq i8 %or, 0
+  ret i1 %cmp
+}
+
+define <2 x i1> @cmpne_bitwise(<2 x i64> %a, <2 x i64> %b, <2 x i64> %c, <2 x i64> %d) {
+; CHECK-LABEL: @cmpne_bitwise(
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp ne <2 x i64> [[A:%.*]], [[B:%.*]]
+; CHECK-NEXT:    [[TMP2:%.*]] = icmp ne <2 x i64> [[C:%.*]], [[D:%.*]]
+; CHECK-NEXT:    [[CMP:%.*]] = or <2 x i1> [[TMP1]], [[TMP2]]
+; CHECK-NEXT:    ret <2 x i1> [[CMP]]
+;
+  %xor1 = xor <2 x i64> %a, %b
+  %xor2 = xor <2 x i64> %c, %d
+  %or = or <2 x i64> %xor1, %xor2
+  %cmp = icmp ne <2 x i64> %or, zeroinitializer
+  ret <2 x i1> %cmp
+}
+
+; ((X & 12) != 0 & (X & 3) == 1) -> no change
+define i1 @masked_icmps_mask_notallzeros_bmask_mixed_0(i32 %x) {
+; CHECK-LABEL: @masked_icmps_mask_notallzeros_bmask_mixed_0(
+; CHECK-NEXT:    [[TMP1:%.*]] = and i32 [[X:%.*]], 12
+; CHECK-NEXT:    [[TMP2:%.*]] = icmp ne i32 [[TMP1]], 0
+; CHECK-NEXT:    [[TMP3:%.*]] = and i32 [[X]], 3
+; CHECK-NEXT:    [[TMP4:%.*]] = icmp eq i32 [[TMP3]], 1
+; CHECK-NEXT:    [[TMP5:%.*]] = and i1 [[TMP2]], [[TMP4]]
+; CHECK-NEXT:    ret i1 [[TMP5]]
+;
+  %tmp1 = and i32 %x, 12
+  %tmp2 = icmp ne i32 %tmp1, 0
+  %tmp3 = and i32 %x, 3
+  %tmp4 = icmp eq i32 %tmp3, 1
+  %tmp5 = and i1 %tmp2, %tmp4
+  ret i1 %tmp5
+}
+
+; ((X & 12) != 0 & (X & 7) == 1) -> (X & 15) == 9
+define i1 @masked_icmps_mask_notallzeros_bmask_mixed_1(i32 %x) {
+; CHECK-LABEL: @masked_icmps_mask_notallzeros_bmask_mixed_1(
+; CHECK-NEXT:    [[TMP1:%.*]] = and i32 [[X:%.*]], 15
+; CHECK-NEXT:    [[TMP2:%.*]] = icmp eq i32 [[TMP1]], 9
+; CHECK-NEXT:    ret i1 [[TMP2]]
+;
+  %tmp1 = and i32 %x, 12
+  %tmp2 = icmp ne i32 %tmp1, 0
+  %tmp3 = and i32 %x, 7
+  %tmp4 = icmp eq i32 %tmp3, 1
+  %tmp5 = and i1 %tmp2, %tmp4
+  ret i1 %tmp5
+}
+
+; ((X & 14) != 0 & (X & 3) == 1) -> no change
+define i1 @masked_icmps_mask_notallzeros_bmask_mixed_1b(i32 %x) {
+; CHECK-LABEL: @masked_icmps_mask_notallzeros_bmask_mixed_1b(
+; CHECK-NEXT:    [[TMP1:%.*]] = and i32 [[X:%.*]], 14
+; CHECK-NEXT:    [[TMP2:%.*]] = icmp ne i32 [[TMP1]], 0
+; CHECK-NEXT:    [[TMP3:%.*]] = and i32 [[X]], 3
+; CHECK-NEXT:    [[TMP4:%.*]] = icmp eq i32 [[TMP3]], 1
+; CHECK-NEXT:    [[TMP5:%.*]] = and i1 [[TMP2]], [[TMP4]]
+; CHECK-NEXT:    ret i1 [[TMP5]]
+;
+  %tmp1 = and i32 %x, 14
+  %tmp2 = icmp ne i32 %tmp1, 0
+  %tmp3 = and i32 %x, 3
+  %tmp4 = icmp eq i32 %tmp3, 1
+  %tmp5 = and i1 %tmp2, %tmp4
+  ret i1 %tmp5
+}
+
+; ((X & 3) != 0 & (X & 7) == 0) -> false
+define i1 @masked_icmps_mask_notallzeros_bmask_mixed_2(i32 %x) {
+; CHECK-LABEL: @masked_icmps_mask_notallzeros_bmask_mixed_2(
+; CHECK-NEXT:    ret i1 false
+;
+  %tmp1 = and i32 %x, 3
+  %tmp2 = icmp ne i32 %tmp1, 0
+  %tmp3 = and i32 %x, 7
+  %tmp4 = icmp eq i32 %tmp3, 0
+  %tmp5 = and i1 %tmp2, %tmp4
+  ret i1 %tmp5
+}
+
+; ((X & 15) != 0 & (X & 7) == 0) -> (X & 15) == 8
+define i1 @masked_icmps_mask_notallzeros_bmask_mixed_3(i32 %x) {
+; CHECK-LABEL: @masked_icmps_mask_notallzeros_bmask_mixed_3(
+; CHECK-NEXT:    [[TMP1:%.*]] = and i32 [[X:%.*]], 15
+; CHECK-NEXT:    [[TMP2:%.*]] = icmp eq i32 [[TMP1]], 8
+; CHECK-NEXT:    ret i1 [[TMP2]]
+;
+  %tmp1 = and i32 %x, 15
+  %tmp2 = icmp ne i32 %tmp1, 0
+  %tmp3 = and i32 %x, 7
+  %tmp4 = icmp eq i32 %tmp3, 0
+  %tmp5 = and i1 %tmp2, %tmp4
+  ret i1 %tmp5
+}
+
+; ((X & 15) != 0 & (X & 3) == 0) -> no change
+define i1 @masked_icmps_mask_notallzeros_bmask_mixed_3b(i32 %x) {
+; CHECK-LABEL: @masked_icmps_mask_notallzeros_bmask_mixed_3b(
+; CHECK-NEXT:    [[TMP1:%.*]] = and i32 [[X:%.*]], 15
+; CHECK-NEXT:    [[TMP2:%.*]] = icmp ne i32 [[TMP1]], 0
+; CHECK-NEXT:    [[TMP3:%.*]] = and i32 [[X]], 3
+; CHECK-NEXT:    [[TMP4:%.*]] = icmp eq i32 [[TMP3]], 0
+; CHECK-NEXT:    [[TMP5:%.*]] = and i1 [[TMP2]], [[TMP4]]
+; CHECK-NEXT:    ret i1 [[TMP5]]
+;
+  %tmp1 = and i32 %x, 15
+  %tmp2 = icmp ne i32 %tmp1, 0
+  %tmp3 = and i32 %x, 3
+  %tmp4 = icmp eq i32 %tmp3, 0
+  %tmp5 = and i1 %tmp2, %tmp4
+  ret i1 %tmp5
+}
+
+; ((X & 255) != 0 & (X & 15) == 8) -> (X & 15) == 8
+define i1 @masked_icmps_mask_notallzeros_bmask_mixed_4(i32 %x) {
+; CHECK-LABEL: @masked_icmps_mask_notallzeros_bmask_mixed_4(
+; CHECK-NEXT:    [[TMP3:%.*]] = and i32 [[X:%.*]], 15
+; CHECK-NEXT:    [[TMP4:%.*]] = icmp eq i32 [[TMP3]], 8
+; CHECK-NEXT:    ret i1 [[TMP4]]
+;
+  %tmp1 = and i32 %x, 255
+  %tmp2 = icmp ne i32 %tmp1, 0
+  %tmp3 = and i32 %x, 15
+  %tmp4 = icmp eq i32 %tmp3, 8
+  %tmp5 = and i1 %tmp2, %tmp4
+  ret i1 %tmp5
+}
+
+; ((X & 15) != 0 & (X & 15) == 8) -> (X & 15) == 8
+define i1 @masked_icmps_mask_notallzeros_bmask_mixed_5(i32 %x) {
+; CHECK-LABEL: @masked_icmps_mask_notallzeros_bmask_mixed_5(
+; CHECK-NEXT:    [[TMP3:%.*]] = and i32 [[X:%.*]], 15
+; CHECK-NEXT:    [[TMP4:%.*]] = icmp eq i32 [[TMP3]], 8
+; CHECK-NEXT:    ret i1 [[TMP4]]
+;
+  %tmp1 = and i32 %x, 15
+  %tmp2 = icmp ne i32 %tmp1, 0
+  %tmp3 = and i32 %x, 15
+  %tmp4 = icmp eq i32 %tmp3, 8
+  %tmp5 = and i1 %tmp2, %tmp4
+  ret i1 %tmp5
+}
+
+; ((X & 12) != 0 & (X & 15) == 8) -> (X & 15) == 8
+define i1 @masked_icmps_mask_notallzeros_bmask_mixed_6(i32 %x) {
+; CHECK-LABEL: @masked_icmps_mask_notallzeros_bmask_mixed_6(
+; CHECK-NEXT:    [[TMP3:%.*]] = and i32 [[X:%.*]], 15
+; CHECK-NEXT:    [[TMP4:%.*]] = icmp eq i32 [[TMP3]], 8
+; CHECK-NEXT:    ret i1 [[TMP4]]
+;
+  %tmp1 = and i32 %x, 12
+  %tmp2 = icmp ne i32 %tmp1, 0
+  %tmp3 = and i32 %x, 15
+  %tmp4 = icmp eq i32 %tmp3, 8
+  %tmp5 = and i1 %tmp2, %tmp4
+  ret i1 %tmp5
+}
+
+; ((X & 7) != 0 & (X & 15) == 8) -> false
+define i1 @masked_icmps_mask_notallzeros_bmask_mixed_7(i32 %x) {
+; CHECK-LABEL: @masked_icmps_mask_notallzeros_bmask_mixed_7(
+; CHECK-NEXT:    ret i1 false
+;
+  %tmp1 = and i32 %x, 7
+  %tmp2 = icmp ne i32 %tmp1, 0
+  %tmp3 = and i32 %x, 15
+  %tmp4 = icmp eq i32 %tmp3, 8
+  %tmp5 = and i1 %tmp2, %tmp4
+  ret i1 %tmp5
+}
+
+; ((X & 6) != 0 & (X & 15) == 8) -> false
+define i1 @masked_icmps_mask_notallzeros_bmask_mixed_7b(i32 %x) {
+; CHECK-LABEL: @masked_icmps_mask_notallzeros_bmask_mixed_7b(
+; CHECK-NEXT:    ret i1 false
+;
+  %tmp1 = and i32 %x, 6
+  %tmp2 = icmp ne i32 %tmp1, 0
+  %tmp3 = and i32 %x, 15
+  %tmp4 = icmp eq i32 %tmp3, 8
+  %tmp5 = and i1 %tmp2, %tmp4
+  ret i1 %tmp5
+}
+
+; ((X & 12) == 0 | (X & 3) != 1) -> !((X & 12) != 0 & (X & 3) == 1)) ->
+; no change
+define i1 @masked_icmps_mask_notallzeros_bmask_mixed_negated_0(i32 %x) {
+; CHECK-LABEL: @masked_icmps_mask_notallzeros_bmask_mixed_negated_0(
+; CHECK-NEXT:    [[TMP1:%.*]] = and i32 [[X:%.*]], 12
+; CHECK-NEXT:    [[TMP2:%.*]] = icmp eq i32 [[TMP1]], 0
+; CHECK-NEXT:    [[TMP3:%.*]] = and i32 [[X]], 3
+; CHECK-NEXT:    [[TMP4:%.*]] = icmp ne i32 [[TMP3]], 1
+; CHECK-NEXT:    [[TMP5:%.*]] = or i1 [[TMP2]], [[TMP4]]
+; CHECK-NEXT:    ret i1 [[TMP5]]
+;
+  %tmp1 = and i32 %x, 12
+  %tmp2 = icmp eq i32 %tmp1, 0
+  %tmp3 = and i32 %x, 3
+  %tmp4 = icmp ne i32 %tmp3, 1
+  %tmp5 = or i1 %tmp2, %tmp4
+  ret i1 %tmp5
+}
+
+; ((X & 12) == 0 | (X & 7) != 1) -> !((X & 12) != 0 & (X & 7) == 1) ->
+; !((X & 15) == 9) -> (X & 15) != 9
+define i1 @masked_icmps_mask_notallzeros_bmask_mixed_negated_1(i32 %x) {
+; CHECK-LABEL: @masked_icmps_mask_notallzeros_bmask_mixed_negated_1(
+; CHECK-NEXT:    [[TMP1:%.*]] = and i32 [[X:%.*]], 15
+; CHECK-NEXT:    [[TMP2:%.*]] = icmp ne i32 [[TMP1]], 9
+; CHECK-NEXT:    ret i1 [[TMP2]]
+;
+  %tmp1 = and i32 %x, 12
+  %tmp2 = icmp eq i32 %tmp1, 0
+  %tmp3 = and i32 %x, 7
+  %tmp4 = icmp ne i32 %tmp3, 1
+  %tmp5 = or i1 %tmp2, %tmp4
+  ret i1 %tmp5
+}
+
+; ((X & 14) == 0 | (X & 3) != 1) -> !((X & 14) != 0 & (X & 3) == 1) ->
+; no change.
+define i1 @masked_icmps_mask_notallzeros_bmask_mixed_negated_1b(i32 %x) {
+; CHECK-LABEL: @masked_icmps_mask_notallzeros_bmask_mixed_negated_1b(
+; CHECK-NEXT:    [[TMP1:%.*]] = and i32 [[X:%.*]], 14
+; CHECK-NEXT:    [[TMP2:%.*]] = icmp eq i32 [[TMP1]], 0
+; CHECK-NEXT:    [[TMP3:%.*]] = and i32 [[X]], 3
+; CHECK-NEXT:    [[TMP4:%.*]] = icmp ne i32 [[TMP3]], 1
+; CHECK-NEXT:    [[TMP5:%.*]] = or i1 [[TMP2]], [[TMP4]]
+; CHECK-NEXT:    ret i1 [[TMP5]]
+;
+  %tmp1 = and i32 %x, 14
+  %tmp2 = icmp eq i32 %tmp1, 0
+  %tmp3 = and i32 %x, 3
+  %tmp4 = icmp ne i32 %tmp3, 1
+  %tmp5 = or i1 %tmp2, %tmp4
+  ret i1 %tmp5
+}
+
+; ((X & 3) == 0 | (X & 7) != 0) -> !((X & 3) != 0 & (X & 7) == 0) ->
+; !(false) -> true
+define i1 @masked_icmps_mask_notallzeros_bmask_mixed_negated_2(i32 %x) {
+; CHECK-LABEL: @masked_icmps_mask_notallzeros_bmask_mixed_negated_2(
+; CHECK-NEXT:    ret i1 true
+;
+  %tmp1 = and i32 %x, 3
+  %tmp2 = icmp eq i32 %tmp1, 0
+  %tmp3 = and i32 %x, 7
+  %tmp4 = icmp ne i32 %tmp3, 0
+  %tmp5 = or i1 %tmp2, %tmp4
+  ret i1 %tmp5
+}
+
+; ((X & 15) == 0 | (X & 7) != 0) -> !((X & 15) != 0 & (X & 7) == 0) ->
+; !((X & 15) == 8) -> (X & 15) != 8
+define i1 @masked_icmps_mask_notallzeros_bmask_mixed_negated_3(i32 %x) {
+; CHECK-LABEL: @masked_icmps_mask_notallzeros_bmask_mixed_negated_3(
+; CHECK-NEXT:    [[TMP1:%.*]] = and i32 [[X:%.*]], 15
+; CHECK-NEXT:    [[TMP2:%.*]] = icmp ne i32 [[TMP1]], 8
+; CHECK-NEXT:    ret i1 [[TMP2]]
+;
+  %tmp1 = and i32 %x, 15
+  %tmp2 = icmp eq i32 %tmp1, 0
+  %tmp3 = and i32 %x, 7
+  %tmp4 = icmp ne i32 %tmp3, 0
+  %tmp5 = or i1 %tmp2, %tmp4
+  ret i1 %tmp5
+}
+
+; ((X & 15) == 0 | (X & 3) != 0) -> !((X & 15) != 0 & (X & 3) == 0) ->
+; no change.
+define i1 @masked_icmps_mask_notallzeros_bmask_mixed_negated_3b(i32 %x) {
+; CHECK-LABEL: @masked_icmps_mask_notallzeros_bmask_mixed_negated_3b(
+; CHECK-NEXT:    [[TMP1:%.*]] = and i32 [[X:%.*]], 15
+; CHECK-NEXT:    [[TMP2:%.*]] = icmp eq i32 [[TMP1]], 0
+; CHECK-NEXT:    [[TMP3:%.*]] = and i32 [[X]], 3
+; CHECK-NEXT:    [[TMP4:%.*]] = icmp ne i32 [[TMP3]], 0
+; CHECK-NEXT:    [[TMP5:%.*]] = or i1 [[TMP2]], [[TMP4]]
+; CHECK-NEXT:    ret i1 [[TMP5]]
+;
+  %tmp1 = and i32 %x, 15
+  %tmp2 = icmp eq i32 %tmp1, 0
+  %tmp3 = and i32 %x, 3
+  %tmp4 = icmp ne i32 %tmp3, 0
+  %tmp5 = or i1 %tmp2, %tmp4
+  ret i1 %tmp5
+}
+
+; ((X & 255) == 0 | (X & 15) != 8) -> !(((X & 255) != 0 & (X & 15) == 8)) ->
+; !((X & 15) == 8) -> ((X & 15) != 8)
+define i1 @masked_icmps_mask_notallzeros_bmask_mixed_negated_4(i32 %x) {
+; CHECK-LABEL: @masked_icmps_mask_notallzeros_bmask_mixed_negated_4(
+; CHECK-NEXT:    [[TMP3:%.*]] = and i32 [[X:%.*]], 15
+; CHECK-NEXT:    [[TMP4:%.*]] = icmp ne i32 [[TMP3]], 8
+; CHECK-NEXT:    ret i1 [[TMP4]]
+;
+  %tmp1 = and i32 %x, 255
+  %tmp2 = icmp eq i32 %tmp1, 0
+  %tmp3 = and i32 %x, 15
+  %tmp4 = icmp ne i32 %tmp3, 8
+  %tmp5 = or i1 %tmp2, %tmp4
+  ret i1 %tmp5
+}
+
+; ((X & 15) == 0 | (X & 15) != 8) -> !(((X & 15) != 0 & (X & 15) == 8)) ->
+; !((X & 15) == 8) -> ((X & 15) != 8)
+define i1 @masked_icmps_mask_notallzeros_bmask_mixed_negated_5(i32 %x) {
+; CHECK-LABEL: @masked_icmps_mask_notallzeros_bmask_mixed_negated_5(
+; CHECK-NEXT:    [[TMP3:%.*]] = and i32 [[X:%.*]], 15
+; CHECK-NEXT:    [[TMP4:%.*]] = icmp ne i32 [[TMP3]], 8
+; CHECK-NEXT:    ret i1 [[TMP4]]
+;
+  %tmp1 = and i32 %x, 15
+  %tmp2 = icmp eq i32 %tmp1, 0
+  %tmp3 = and i32 %x, 15
+  %tmp4 = icmp ne i32 %tmp3, 8
+  %tmp5 = or i1 %tmp2, %tmp4
+  ret i1 %tmp5
+}
+
+; ((X & 12) == 0 | (X & 15) != 8) -> !(((X & 12) != 0 & (X & 15) == 8)) ->
+; !((X & 15) == 8) -> ((X & 15) != 8
+define i1 @masked_icmps_mask_notallzeros_bmask_mixed_negated_6(i32 %x) {
+; CHECK-LABEL: @masked_icmps_mask_notallzeros_bmask_mixed_negated_6(
+; CHECK-NEXT:    [[TMP3:%.*]] = and i32 [[X:%.*]], 15
+; CHECK-NEXT:    [[TMP4:%.*]] = icmp ne i32 [[TMP3]], 8
+; CHECK-NEXT:    ret i1 [[TMP4]]
+;
+  %tmp1 = and i32 %x, 12
+  %tmp2 = icmp eq i32 %tmp1, 0
+  %tmp3 = and i32 %x, 15
+  %tmp4 = icmp ne i32 %tmp3, 8
+  %tmp5 = or i1 %tmp2, %tmp4
+  ret i1 %tmp5
+}
+
+; ((X & 7) == 0 | (X & 15) != 8) -> !(((X & 7) != 0 & (X & 15) == 8)) ->
+; !(false) -> true
+define i1 @masked_icmps_mask_notallzeros_bmask_mixed_negated_7(i32 %x) {
+; CHECK-LABEL: @masked_icmps_mask_notallzeros_bmask_mixed_negated_7(
+; CHECK-NEXT:    ret i1 true
+;
+  %tmp1 = and i32 %x, 7
+  %tmp2 = icmp eq i32 %tmp1, 0
+  %tmp3 = and i32 %x, 15
+  %tmp4 = icmp ne i32 %tmp3, 8
+  %tmp5 = or i1 %tmp2, %tmp4
+  ret i1 %tmp5
+}
+
+; ((X & 6) == 0 | (X & 15) != 8) -> !(((X & 6) != 0 & (X & 15) == 8)) ->
+; !(false) -> true
+define i1 @masked_icmps_mask_notallzeros_bmask_mixed_negated_7b(i32 %x) {
+; CHECK-LABEL: @masked_icmps_mask_notallzeros_bmask_mixed_negated_7b(
+; CHECK-NEXT:    ret i1 true
+;
+  %tmp1 = and i32 %x, 6
+  %tmp2 = icmp eq i32 %tmp1, 0
+  %tmp3 = and i32 %x, 15
+  %tmp4 = icmp ne i32 %tmp3, 8
+  %tmp5 = or i1 %tmp2, %tmp4
+  ret i1 %tmp5
+}
+
+
+; ((X & 12) != 0 & (X & 3) == 1) -> no change
+define i1 @masked_icmps_mask_notallzeros_bmask_mixed_swapped_0(i32 %x) {
+; CHECK-LABEL: @masked_icmps_mask_notallzeros_bmask_mixed_swapped_0(
+; CHECK-NEXT:    [[TMP1:%.*]] = and i32 [[X:%.*]], 12
+; CHECK-NEXT:    [[TMP2:%.*]] = icmp ne i32 [[TMP1]], 0
+; CHECK-NEXT:    [[TMP3:%.*]] = and i32 [[X]], 3
+; CHECK-NEXT:    [[TMP4:%.*]] = icmp eq i32 [[TMP3]], 1
+; CHECK-NEXT:    [[TMP5:%.*]] = and i1 [[TMP4]], [[TMP2]]
+; CHECK-NEXT:    ret i1 [[TMP5]]
+;
+  %tmp1 = and i32 %x, 12
+  %tmp2 = icmp ne i32 %tmp1, 0
+  %tmp3 = and i32 %x, 3
+  %tmp4 = icmp eq i32 %tmp3, 1
+  %tmp5 = and i1 %tmp4, %tmp2
+  ret i1 %tmp5
+}
+
+; ((X & 12) != 0 & (X & 7) == 1) -> (X & 15) == 9
+define i1 @masked_icmps_mask_notallzeros_bmask_mixed_swapped_1(i32 %x) {
+; CHECK-LABEL: @masked_icmps_mask_notallzeros_bmask_mixed_swapped_1(
+; CHECK-NEXT:    [[TMP1:%.*]] = and i32 [[X:%.*]], 15
+; CHECK-NEXT:    [[TMP2:%.*]] = icmp eq i32 [[TMP1]], 9
+; CHECK-NEXT:    ret i1 [[TMP2]]
+;
+  %tmp1 = and i32 %x, 12
+  %tmp2 = icmp ne i32 %tmp1, 0
+  %tmp3 = and i32 %x, 7
+  %tmp4 = icmp eq i32 %tmp3, 1
+  %tmp5 = and i1 %tmp4, %tmp2
+  ret i1 %tmp5
+}
+
+; ((X & 14) != 0 & (X & 3) == 1) -> no change
+define i1 @masked_icmps_mask_notallzeros_bmask_mixed_swapped_1b(i32 %x) {
+; CHECK-LABEL: @masked_icmps_mask_notallzeros_bmask_mixed_swapped_1b(
+; CHECK-NEXT:    [[TMP1:%.*]] = and i32 [[X:%.*]], 14
+; CHECK-NEXT:    [[TMP2:%.*]] = icmp ne i32 [[TMP1]], 0
+; CHECK-NEXT:    [[TMP3:%.*]] = and i32 [[X]], 3
+; CHECK-NEXT:    [[TMP4:%.*]] = icmp eq i32 [[TMP3]], 1
+; CHECK-NEXT:    [[TMP5:%.*]] = and i1 [[TMP4]], [[TMP2]]
+; CHECK-NEXT:    ret i1 [[TMP5]]
+;
+  %tmp1 = and i32 %x, 14
+  %tmp2 = icmp ne i32 %tmp1, 0
+  %tmp3 = and i32 %x, 3
+  %tmp4 = icmp eq i32 %tmp3, 1
+  %tmp5 = and i1 %tmp4, %tmp2
+  ret i1 %tmp5
+}
+
+; ((X & 3) != 0 & (X & 7) == 0) -> false
+define i1 @masked_icmps_mask_notallzeros_bmask_mixed_swapped_2(i32 %x) {
+; CHECK-LABEL: @masked_icmps_mask_notallzeros_bmask_mixed_swapped_2(
+; CHECK-NEXT:    ret i1 false
+;
+  %tmp1 = and i32 %x, 3
+  %tmp2 = icmp ne i32 %tmp1, 0
+  %tmp3 = and i32 %x, 7
+  %tmp4 = icmp eq i32 %tmp3, 0
+  %tmp5 = and i1 %tmp4, %tmp2
+  ret i1 %tmp5
+}
+
+; ((X & 15) != 0 & (X & 7) == 0) -> (X & 15) == 8
+define i1 @masked_icmps_mask_notallzeros_bmask_mixed_swapped_3(i32 %x) {
+; CHECK-LABEL: @masked_icmps_mask_notallzeros_bmask_mixed_swapped_3(
+; CHECK-NEXT:    [[TMP1:%.*]] = and i32 [[X:%.*]], 15
+; CHECK-NEXT:    [[TMP2:%.*]] = icmp eq i32 [[TMP1]], 8
+; CHECK-NEXT:    ret i1 [[TMP2]]
+;
+  %tmp1 = and i32 %x, 15
+  %tmp2 = icmp ne i32 %tmp1, 0
+  %tmp3 = and i32 %x, 7
+  %tmp4 = icmp eq i32 %tmp3, 0
+  %tmp5 = and i1 %tmp4, %tmp2
+  ret i1 %tmp5
+}
+
+; ((X & 15) != 0 & (X & 3) == 0) -> no change
+define i1 @masked_icmps_mask_notallzeros_bmask_mixed_swapped_3b(i32 %x) {
+; CHECK-LABEL: @masked_icmps_mask_notallzeros_bmask_mixed_swapped_3b(
+; CHECK-NEXT:    [[TMP1:%.*]] = and i32 [[X:%.*]], 15
+; CHECK-NEXT:    [[TMP2:%.*]] = icmp ne i32 [[TMP1]], 0
+; CHECK-NEXT:    [[TMP3:%.*]] = and i32 [[X]], 3
+; CHECK-NEXT:    [[TMP4:%.*]] = icmp eq i32 [[TMP3]], 0
+; CHECK-NEXT:    [[TMP5:%.*]] = and i1 [[TMP4]], [[TMP2]]
+; CHECK-NEXT:    ret i1 [[TMP5]]
+;
+  %tmp1 = and i32 %x, 15
+  %tmp2 = icmp ne i32 %tmp1, 0
+  %tmp3 = and i32 %x, 3
+  %tmp4 = icmp eq i32 %tmp3, 0
+  %tmp5 = and i1 %tmp4, %tmp2
+  ret i1 %tmp5
+}
+
+; ((X & 255) != 0 & (X & 15) == 8) -> (X & 15) == 8
+define i1 @masked_icmps_mask_notallzeros_bmask_mixed_swapped_4(i32 %x) {
+; CHECK-LABEL: @masked_icmps_mask_notallzeros_bmask_mixed_swapped_4(
+; CHECK-NEXT:    [[TMP3:%.*]] = and i32 [[X:%.*]], 15
+; CHECK-NEXT:    [[TMP4:%.*]] = icmp eq i32 [[TMP3]], 8
+; CHECK-NEXT:    ret i1 [[TMP4]]
+;
+  %tmp1 = and i32 %x, 255
+  %tmp2 = icmp ne i32 %tmp1, 0
+  %tmp3 = and i32 %x, 15
+  %tmp4 = icmp eq i32 %tmp3, 8
+  %tmp5 = and i1 %tmp4, %tmp2
+  ret i1 %tmp5
+}
+
+; ((X & 15) != 0 & (X & 15) == 8) -> (X & 15) == 8
+define i1 @masked_icmps_mask_notallzeros_bmask_mixed_swapped_5(i32 %x) {
+; CHECK-LABEL: @masked_icmps_mask_notallzeros_bmask_mixed_swapped_5(
+; CHECK-NEXT:    [[TMP3:%.*]] = and i32 [[X:%.*]], 15
+; CHECK-NEXT:    [[TMP4:%.*]] = icmp eq i32 [[TMP3]], 8
+; CHECK-NEXT:    ret i1 [[TMP4]]
+;
+  %tmp1 = and i32 %x, 15
+  %tmp2 = icmp ne i32 %tmp1, 0
+  %tmp3 = and i32 %x, 15
+  %tmp4 = icmp eq i32 %tmp3, 8
+  %tmp5 = and i1 %tmp4, %tmp2
+  ret i1 %tmp5
+}
+
+; ((X & 12) != 0 & (X & 15) == 8) -> (X & 15) == 8
+define i1 @masked_icmps_mask_notallzeros_bmask_mixed_swapped_6(i32 %x) {
+; CHECK-LABEL: @masked_icmps_mask_notallzeros_bmask_mixed_swapped_6(
+; CHECK-NEXT:    [[TMP3:%.*]] = and i32 [[X:%.*]], 15
+; CHECK-NEXT:    [[TMP4:%.*]] = icmp eq i32 [[TMP3]], 8
+; CHECK-NEXT:    ret i1 [[TMP4]]
+;
+  %tmp1 = and i32 %x, 12
+  %tmp2 = icmp ne i32 %tmp1, 0
+  %tmp3 = and i32 %x, 15
+  %tmp4 = icmp eq i32 %tmp3, 8
+  %tmp5 = and i1 %tmp4, %tmp2
+  ret i1 %tmp5
+}
+
+; ((X & 7) != 0 & (X & 15) == 8) -> false
+define i1 @masked_icmps_mask_notallzeros_bmask_mixed_swapped_7(i32 %x) {
+; CHECK-LABEL: @masked_icmps_mask_notallzeros_bmask_mixed_swapped_7(
+; CHECK-NEXT:    ret i1 false
+;
+  %tmp1 = and i32 %x, 7
+  %tmp2 = icmp ne i32 %tmp1, 0
+  %tmp3 = and i32 %x, 15
+  %tmp4 = icmp eq i32 %tmp3, 8
+  %tmp5 = and i1 %tmp4, %tmp2
+  ret i1 %tmp5
+}
+
+; ((X & 6) != 0 & (X & 15) == 8) -> false
+define i1 @masked_icmps_mask_notallzeros_bmask_mixed_swapped_7b(i32 %x) {
+; CHECK-LABEL: @masked_icmps_mask_notallzeros_bmask_mixed_swapped_7b(
+; CHECK-NEXT:    ret i1 false
+;
+  %tmp1 = and i32 %x, 6
+  %tmp2 = icmp ne i32 %tmp1, 0
+  %tmp3 = and i32 %x, 15
+  %tmp4 = icmp eq i32 %tmp3, 8
+  %tmp5 = and i1 %tmp4, %tmp2
+  ret i1 %tmp5
+}
+
+; ((X & 12) == 0 | (X & 3) != 1) -> !((X & 12) != 0 & (X & 3) == 1)) ->
+; no change
+define i1 @masked_icmps_mask_notallzeros_bmask_mixed_negated_swapped_0(i32 %x) {
+; CHECK-LABEL: @masked_icmps_mask_notallzeros_bmask_mixed_negated_swapped_0(
+; CHECK-NEXT:    [[TMP1:%.*]] = and i32 [[X:%.*]], 12
+; CHECK-NEXT:    [[TMP2:%.*]] = icmp eq i32 [[TMP1]], 0
+; CHECK-NEXT:    [[TMP3:%.*]] = and i32 [[X]], 3
+; CHECK-NEXT:    [[TMP4:%.*]] = icmp ne i32 [[TMP3]], 1
+; CHECK-NEXT:    [[TMP5:%.*]] = or i1 [[TMP4]], [[TMP2]]
+; CHECK-NEXT:    ret i1 [[TMP5]]
+;
+  %tmp1 = and i32 %x, 12
+  %tmp2 = icmp eq i32 %tmp1, 0
+  %tmp3 = and i32 %x, 3
+  %tmp4 = icmp ne i32 %tmp3, 1
+  %tmp5 = or i1 %tmp4, %tmp2
+  ret i1 %tmp5
+}
+
+; ((X & 12) == 0 | (X & 7) != 1) -> !((X & 12) != 0 & (X & 7) == 1) ->
+; !((X & 15) == 9) -> (X & 15) != 9
+define i1 @masked_icmps_mask_notallzeros_bmask_mixed_negated_swapped_1(i32 %x) {
+; CHECK-LABEL: @masked_icmps_mask_notallzeros_bmask_mixed_negated_swapped_1(
+; CHECK-NEXT:    [[TMP1:%.*]] = and i32 [[X:%.*]], 15
+; CHECK-NEXT:    [[TMP2:%.*]] = icmp ne i32 [[TMP1]], 9
+; CHECK-NEXT:    ret i1 [[TMP2]]
+;
+  %tmp1 = and i32 %x, 12
+  %tmp2 = icmp eq i32 %tmp1, 0
+  %tmp3 = and i32 %x, 7
+  %tmp4 = icmp ne i32 %tmp3, 1
+  %tmp5 = or i1 %tmp4, %tmp2
+  ret i1 %tmp5
+}
+
+; ((X & 14) == 0 | (X & 3) != 1) -> !((X & 14) != 0 & (X & 3) == 1) ->
+; no change.
+define i1 @masked_icmps_mask_notallzeros_bmask_mixed_negated_swapped_1b(i32 %x) {
+; CHECK-LABEL: @masked_icmps_mask_notallzeros_bmask_mixed_negated_swapped_1b(
+; CHECK-NEXT:    [[TMP1:%.*]] = and i32 [[X:%.*]], 14
+; CHECK-NEXT:    [[TMP2:%.*]] = icmp eq i32 [[TMP1]], 0
+; CHECK-NEXT:    [[TMP3:%.*]] = and i32 [[X]], 3
+; CHECK-NEXT:    [[TMP4:%.*]] = icmp ne i32 [[TMP3]], 1
+; CHECK-NEXT:    [[TMP5:%.*]] = or i1 [[TMP4]], [[TMP2]]
+; CHECK-NEXT:    ret i1 [[TMP5]]
+;
+  %tmp1 = and i32 %x, 14
+  %tmp2 = icmp eq i32 %tmp1, 0
+  %tmp3 = and i32 %x, 3
+  %tmp4 = icmp ne i32 %tmp3, 1
+  %tmp5 = or i1 %tmp4, %tmp2
+  ret i1 %tmp5
+}
+
+; ((X & 3) == 0 | (X & 7) != 0) -> !((X & 3) != 0 & (X & 7) == 0) ->
+; !(false) -> true
+define i1 @masked_icmps_mask_notallzeros_bmask_mixed_negated_swapped_2(i32 %x) {
+; CHECK-LABEL: @masked_icmps_mask_notallzeros_bmask_mixed_negated_swapped_2(
+; CHECK-NEXT:    ret i1 true
+;
+  %tmp1 = and i32 %x, 3
+  %tmp2 = icmp eq i32 %tmp1, 0
+  %tmp3 = and i32 %x, 7
+  %tmp4 = icmp ne i32 %tmp3, 0
+  %tmp5 = or i1 %tmp4, %tmp2
+  ret i1 %tmp5
+}
+
+; ((X & 15) == 0 | (X & 7) != 0) -> !((X & 15) != 0 & (X & 7) == 0) ->
+; !((X & 15) == 8) -> (X & 15) != 8
+define i1 @masked_icmps_mask_notallzeros_bmask_mixed_negated_swapped_3(i32 %x) {
+; CHECK-LABEL: @masked_icmps_mask_notallzeros_bmask_mixed_negated_swapped_3(
+; CHECK-NEXT:    [[TMP1:%.*]] = and i32 [[X:%.*]], 15
+; CHECK-NEXT:    [[TMP2:%.*]] = icmp ne i32 [[TMP1]], 8
+; CHECK-NEXT:    ret i1 [[TMP2]]
+;
+  %tmp1 = and i32 %x, 15
+  %tmp2 = icmp eq i32 %tmp1, 0
+  %tmp3 = and i32 %x, 7
+  %tmp4 = icmp ne i32 %tmp3, 0
+  %tmp5 = or i1 %tmp4, %tmp2
+  ret i1 %tmp5
+}
+
+; ((X & 15) == 0 | (X & 3) != 0) -> !((X & 15) != 0 & (X & 3) == 0) ->
+; no change.
+define i1 @masked_icmps_mask_notallzeros_bmask_mixed_negated_swapped_3b(i32 %x) {
+; CHECK-LABEL: @masked_icmps_mask_notallzeros_bmask_mixed_negated_swapped_3b(
+; CHECK-NEXT:    [[TMP1:%.*]] = and i32 [[X:%.*]], 15
+; CHECK-NEXT:    [[TMP2:%.*]] = icmp eq i32 [[TMP1]], 0
+; CHECK-NEXT:    [[TMP3:%.*]] = and i32 [[X]], 3
+; CHECK-NEXT:    [[TMP4:%.*]] = icmp ne i32 [[TMP3]], 0
+; CHECK-NEXT:    [[TMP5:%.*]] = or i1 [[TMP4]], [[TMP2]]
+; CHECK-NEXT:    ret i1 [[TMP5]]
+;
+  %tmp1 = and i32 %x, 15
+  %tmp2 = icmp eq i32 %tmp1, 0
+  %tmp3 = and i32 %x, 3
+  %tmp4 = icmp ne i32 %tmp3, 0
+  %tmp5 = or i1 %tmp4, %tmp2
+  ret i1 %tmp5
+}
+
+; ((X & 255) == 0 | (X & 15) != 8) -> !(((X & 255) != 0 & (X & 15) == 8)) ->
+; !((X & 15) == 8) -> ((X & 15) != 8)
+define i1 @masked_icmps_mask_notallzeros_bmask_mixed_negated_swapped_4(i32 %x) {
+; CHECK-LABEL: @masked_icmps_mask_notallzeros_bmask_mixed_negated_swapped_4(
+; CHECK-NEXT:    [[TMP3:%.*]] = and i32 [[X:%.*]], 15
+; CHECK-NEXT:    [[TMP4:%.*]] = icmp ne i32 [[TMP3]], 8
+; CHECK-NEXT:    ret i1 [[TMP4]]
+;
+  %tmp1 = and i32 %x, 255
+  %tmp2 = icmp eq i32 %tmp1, 0
+  %tmp3 = and i32 %x, 15
+  %tmp4 = icmp ne i32 %tmp3, 8
+  %tmp5 = or i1 %tmp4, %tmp2
+  ret i1 %tmp5
+}
+
+; ((X & 15) == 0 | (X & 15) != 8) -> !(((X & 15) != 0 & (X & 15) == 8)) ->
+; !((X & 15) == 8) -> ((X & 15) != 8)
+define i1 @masked_icmps_mask_notallzeros_bmask_mixed_negated_swapped_5(i32 %x) {
+; CHECK-LABEL: @masked_icmps_mask_notallzeros_bmask_mixed_negated_swapped_5(
+; CHECK-NEXT:    [[TMP3:%.*]] = and i32 [[X:%.*]], 15
+; CHECK-NEXT:    [[TMP4:%.*]] = icmp ne i32 [[TMP3]], 8
+; CHECK-NEXT:    ret i1 [[TMP4]]
+;
+  %tmp1 = and i32 %x, 15
+  %tmp2 = icmp eq i32 %tmp1, 0
+  %tmp3 = and i32 %x, 15
+  %tmp4 = icmp ne i32 %tmp3, 8
+  %tmp5 = or i1 %tmp4, %tmp2
+  ret i1 %tmp5
+}
+
+; ((X & 12) == 0 | (X & 15) != 8) -> !(((X & 12) != 0 & (X & 15) == 8)) ->
+; !((X & 15) == 8) -> ((X & 15) != 8
+define i1 @masked_icmps_mask_notallzeros_bmask_mixed_negated_swapped_6(i32 %x) {
+; CHECK-LABEL: @masked_icmps_mask_notallzeros_bmask_mixed_negated_swapped_6(
+; CHECK-NEXT:    [[TMP3:%.*]] = and i32 [[X:%.*]], 15
+; CHECK-NEXT:    [[TMP4:%.*]] = icmp ne i32 [[TMP3]], 8
+; CHECK-NEXT:    ret i1 [[TMP4]]
+;
+  %tmp1 = and i32 %x, 12
+  %tmp2 = icmp eq i32 %tmp1, 0
+  %tmp3 = and i32 %x, 15
+  %tmp4 = icmp ne i32 %tmp3, 8
+  %tmp5 = or i1 %tmp4, %tmp2
+  ret i1 %tmp5
+}
+
+; ((X & 7) == 0 | (X & 15) != 8) -> !(((X & 7) != 0 & (X & 15) == 8)) ->
+; !(false) -> true
+define i1 @masked_icmps_mask_notallzeros_bmask_mixed_negated_swapped_7(i32 %x) {
+; CHECK-LABEL: @masked_icmps_mask_notallzeros_bmask_mixed_negated_swapped_7(
+; CHECK-NEXT:    ret i1 true
+;
+  %tmp1 = and i32 %x, 7
+  %tmp2 = icmp eq i32 %tmp1, 0
+  %tmp3 = and i32 %x, 15
+  %tmp4 = icmp ne i32 %tmp3, 8
+  %tmp5 = or i1 %tmp4, %tmp2
+  ret i1 %tmp5
+}
+
+; ((X & 6) == 0 | (X & 15) != 8) -> !(((X & 6) != 0 & (X & 15) == 8)) ->
+; !(false) -> true
+define i1 @masked_icmps_mask_notallzeros_bmask_mixed_negated_swapped_7b(i32 %x) {
+; CHECK-LABEL: @masked_icmps_mask_notallzeros_bmask_mixed_negated_swapped_7b(
+; CHECK-NEXT:    ret i1 true
+;
+  %tmp1 = and i32 %x, 6
+  %tmp2 = icmp eq i32 %tmp1, 0
+  %tmp3 = and i32 %x, 15
+  %tmp4 = icmp ne i32 %tmp3, 8
+  %tmp5 = or i1 %tmp4, %tmp2
+  ret i1 %tmp5
+}

Added: llvm/trunk/test/Transforms/InstCombine/icmp-mul-zext.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/icmp-mul-zext.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/icmp-mul-zext.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/icmp-mul-zext.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,120 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt < %s -instcombine -S | FileCheck %s
+
+define i32 @sterix(i32, i8, i64) {
+; CHECK-LABEL: @sterix(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[CONV:%.*]] = zext i32 [[TMP0:%.*]] to i64
+; CHECK-NEXT:    [[CONV1:%.*]] = sext i8 [[TMP1:%.*]] to i32
+; CHECK-NEXT:    [[MUL:%.*]] = mul i32 [[CONV1]], 1945964878
+; CHECK-NEXT:    [[SH_PROM:%.*]] = trunc i64 [[TMP2:%.*]] to i32
+; CHECK-NEXT:    [[SHR:%.*]] = lshr i32 [[MUL]], [[SH_PROM]]
+; CHECK-NEXT:    [[CONV2:%.*]] = zext i32 [[SHR]] to i64
+; CHECK-NEXT:    [[MUL3:%.*]] = mul nuw nsw i64 [[CONV]], [[CONV2]]
+; CHECK-NEXT:    [[TMP3:%.*]] = icmp ugt i64 [[MUL3]], 4294967295
+; CHECK-NEXT:    br i1 [[TMP3]], label [[LOR_END:%.*]], label [[LOR_RHS:%.*]]
+; CHECK:       lor.rhs:
+; CHECK-NEXT:    [[AND:%.*]] = and i64 [[MUL3]], [[TMP2]]
+; CHECK-NEXT:    [[CONV4:%.*]] = trunc i64 [[AND]] to i32
+; CHECK-NEXT:    [[TOBOOL7:%.*]] = icmp eq i32 [[CONV4]], 0
+; CHECK-NEXT:    [[PHITMP:%.*]] = zext i1 [[TOBOOL7]] to i32
+; CHECK-NEXT:    br label [[LOR_END]]
+; CHECK:       lor.end:
+; CHECK-NEXT:    [[TMP4:%.*]] = phi i32 [ 1, [[ENTRY:%.*]] ], [ [[PHITMP]], [[LOR_RHS]] ]
+; CHECK-NEXT:    ret i32 [[TMP4]]
+;
+entry:
+  %conv = zext i32 %0 to i64
+  %conv1 = sext i8 %1 to i32
+  %mul = mul i32 %conv1, 1945964878
+  %sh_prom = trunc i64 %2 to i32
+  %shr = lshr i32 %mul, %sh_prom
+  %conv2 = zext i32 %shr to i64
+  %mul3 = mul nuw nsw i64 %conv, %conv2
+  %conv6 = and i64 %mul3, 4294967295
+  %tobool = icmp ne i64 %conv6, %mul3
+  br i1 %tobool, label %lor.end, label %lor.rhs
+
+lor.rhs:
+  %and = and i64 %2, %mul3
+  %conv4 = trunc i64 %and to i32
+  %tobool7 = icmp ne i32 %conv4, 0
+  %lnot = xor i1 %tobool7, true
+  br label %lor.end
+
+lor.end:
+  %3 = phi i1 [ true, %entry ], [ %lnot, %lor.rhs ]
+  %conv8 = zext i1 %3 to i32
+  ret i32 %conv8
+}
+
+; https://bugs.llvm.org/show_bug.cgi?id=33765
+
+ at glob = external global i16
+
+define void @PR33765(i8 %beth) {
+; CHECK-LABEL: @PR33765(
+; CHECK-NEXT:    [[CONV:%.*]] = zext i8 [[BETH:%.*]] to i32
+; CHECK-NEXT:    br i1 false, label [[IF_THEN9:%.*]], label [[IF_THEN9]]
+; CHECK:       if.then9:
+; CHECK-NEXT:    [[MUL:%.*]] = mul nuw nsw i32 [[CONV]], [[CONV]]
+; CHECK-NEXT:    [[TINKY:%.*]] = load i16, i16* @glob, align 2
+; CHECK-NEXT:    [[TMP1:%.*]] = trunc i32 [[MUL]] to i16
+; CHECK-NEXT:    [[CONV14:%.*]] = and i16 [[TINKY]], [[TMP1]]
+; CHECK-NEXT:    store i16 [[CONV14]], i16* @glob, align 2
+; CHECK-NEXT:    ret void
+;
+  %conv = zext i8 %beth to i32
+  %mul = mul nuw nsw i32 %conv, %conv
+  %conv3 = and i32 %mul, 255
+  %tobool8 = icmp ne i32 %mul, %conv3
+  br i1 %tobool8, label %if.then9, label %if.then9
+
+if.then9:
+  %tinky = load i16, i16* @glob
+  %conv13 = sext i16 %tinky to i32
+  %and = and i32 %mul, %conv13
+  %conv14 = trunc i32 %and to i16
+  store i16 %conv14, i16* @glob
+  ret void
+}
+
+; Repro case for bug involving mutating a list while
+; iterating it.
+
+declare i16 @aux(i8)
+
+define i16 @iter_breaker(i16 %a, i16 %b) {
+; CHECK-LABEL: @iter_breaker(
+; CHECK-NEXT:    [[UMUL:%.*]] = call { i16, i1 } @llvm.umul.with.overflow.i16(i16 [[A:%.*]], i16 [[B:%.*]])
+; CHECK-NEXT:    [[UMUL_VALUE:%.*]] = extractvalue { i16, i1 } [[UMUL]], 0
+; CHECK-NEXT:    [[DID_OVF:%.*]] = extractvalue { i16, i1 } [[UMUL]], 1
+; CHECK-NEXT:    br i1 [[DID_OVF]], label [[RET1:%.*]], label [[RET2:%.*]]
+; CHECK:       ret1:
+; CHECK-NEXT:    [[TRUNC_REMAIN:%.*]] = trunc i16 [[UMUL_VALUE]] to i8
+; CHECK-NEXT:    [[VAL:%.*]] = call i16 @aux(i8 [[TRUNC_REMAIN]])
+; CHECK-NEXT:    ret i16 [[VAL]]
+; CHECK:       ret2:
+; CHECK-NEXT:    ret i16 [[UMUL_VALUE]]
+;
+  %a_wide = zext i16 %a to i32
+  %b_wide = zext i16 %b to i32
+  %mul_wide = mul i32 %a_wide, %b_wide              ; uses of %mul_wide will be iterated
+
+  %trunc_remain = trunc i32 %mul_wide to i8         ; this use will be replaced w/ new value
+  ; when iteration visits it, switching
+  ; iteration to the uses of new value
+
+  %trunc_unnecessary = trunc i32 %mul_wide to i16   ; uses of %trunc_unnecessary will have
+  ; been updated to uses of new value
+
+  %did_ovf = icmp ugt i32 %mul_wide, 65535
+  br i1 %did_ovf, label %ret1, label %ret2
+
+ret1:
+  %val = call i16 @aux(i8 %trunc_remain)
+  ret i16 %val
+
+ret2:
+  ret i16 %trunc_unnecessary              ; crash visiting this use after corrupting iterator
+}

Added: llvm/trunk/test/Transforms/InstCombine/icmp-mul.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/icmp-mul.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/icmp-mul.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/icmp-mul.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,249 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt < %s -instcombine -S | FileCheck %s
+
+; Tests for slt/ult
+
+define i1 @slt_positive_multip_rem_zero(i8 %x) {
+; CHECK-LABEL: @slt_positive_multip_rem_zero(
+; CHECK-NEXT:    [[A:%.*]] = mul nsw i8 [[X:%.*]], 7
+; CHECK-NEXT:    [[B:%.*]] = icmp slt i8 [[A]], 21
+; CHECK-NEXT:    ret i1 [[B]]
+;
+  %a = mul nsw i8 %x, 7
+  %b = icmp slt i8 %a, 21
+  ret i1 %b
+}
+
+define i1 @slt_negative_multip_rem_zero(i8 %x) {
+; CHECK-LABEL: @slt_negative_multip_rem_zero(
+; CHECK-NEXT:    [[A:%.*]] = mul nsw i8 [[X:%.*]], -7
+; CHECK-NEXT:    [[B:%.*]] = icmp slt i8 [[A]], 21
+; CHECK-NEXT:    ret i1 [[B]]
+;
+  %a = mul nsw i8 %x, -7
+  %b = icmp slt i8 %a, 21
+  ret i1 %b
+}
+
+define i1 @slt_positive_multip_rem_nz(i8 %x) {
+; CHECK-LABEL: @slt_positive_multip_rem_nz(
+; CHECK-NEXT:    [[A:%.*]] = mul nsw i8 [[X:%.*]], 5
+; CHECK-NEXT:    [[B:%.*]] = icmp slt i8 [[A]], 21
+; CHECK-NEXT:    ret i1 [[B]]
+;
+  %a = mul nsw i8 %x, 5
+  %b = icmp slt i8 %a, 21
+  ret i1 %b
+}
+
+define i1 @ult_rem_zero(i8 %x) {
+; CHECK-LABEL: @ult_rem_zero(
+; CHECK-NEXT:    [[A:%.*]] = mul nuw i8 [[X:%.*]], 7
+; CHECK-NEXT:    [[B:%.*]] = icmp ult i8 [[A]], 21
+; CHECK-NEXT:    ret i1 [[B]]
+;
+  %a = mul nuw i8 %x, 7
+  %b = icmp ult i8 %a, 21
+  ret i1 %b
+}
+
+define i1 @ult_rem_nz(i8 %x) {
+; CHECK-LABEL: @ult_rem_nz(
+; CHECK-NEXT:    [[A:%.*]] = mul nuw i8 [[X:%.*]], 5
+; CHECK-NEXT:    [[B:%.*]] = icmp ult i8 [[A]], 21
+; CHECK-NEXT:    ret i1 [[B]]
+;
+  %a = mul nuw i8 %x, 5
+  %b = icmp ult i8 %a, 21
+  ret i1 %b
+}
+
+; Tests for sgt/ugt
+
+define i1 @sgt_positive_multip_rem_zero(i8 %x) {
+; CHECK-LABEL: @sgt_positive_multip_rem_zero(
+; CHECK-NEXT:    [[A:%.*]] = mul nsw i8 [[X:%.*]], 7
+; CHECK-NEXT:    [[B:%.*]] = icmp sgt i8 [[A]], 21
+; CHECK-NEXT:    ret i1 [[B]]
+;
+  %a = mul nsw i8 %x, 7
+  %b = icmp sgt i8 %a, 21
+  ret i1 %b
+}
+
+define i1 @sgt_negative_multip_rem_zero(i8 %x) {
+; CHECK-LABEL: @sgt_negative_multip_rem_zero(
+; CHECK-NEXT:    [[A:%.*]] = mul nsw i8 [[X:%.*]], -7
+; CHECK-NEXT:    [[B:%.*]] = icmp sgt i8 [[A]], 21
+; CHECK-NEXT:    ret i1 [[B]]
+;
+  %a = mul nsw i8 %x, -7
+  %b = icmp sgt i8 %a, 21
+  ret i1 %b
+}
+
+define i1 @sgt_positive_multip_rem_nz(i8 %x) {
+; CHECK-LABEL: @sgt_positive_multip_rem_nz(
+; CHECK-NEXT:    [[A:%.*]] = mul nsw i8 [[X:%.*]], 5
+; CHECK-NEXT:    [[B:%.*]] = icmp sgt i8 [[A]], 21
+; CHECK-NEXT:    ret i1 [[B]]
+;
+  %a = mul nsw i8 %x, 5
+  %b = icmp sgt i8 %a, 21
+  ret i1 %b
+}
+
+define i1 @ugt_rem_zero(i8 %x) {
+; CHECK-LABEL: @ugt_rem_zero(
+; CHECK-NEXT:    [[A:%.*]] = mul nuw i8 [[X:%.*]], 7
+; CHECK-NEXT:    [[B:%.*]] = icmp ugt i8 [[A]], 21
+; CHECK-NEXT:    ret i1 [[B]]
+;
+  %a = mul nuw i8 %x, 7
+  %b = icmp ugt i8 %a, 21
+  ret i1 %b
+}
+
+define i1 @ugt_rem_nz(i8 %x) {
+; CHECK-LABEL: @ugt_rem_nz(
+; CHECK-NEXT:    [[A:%.*]] = mul nuw i8 [[X:%.*]], 5
+; CHECK-NEXT:    [[B:%.*]] = icmp ugt i8 [[A]], 21
+; CHECK-NEXT:    ret i1 [[B]]
+;
+  %a = mul nuw i8 %x, 5
+  %b = icmp ugt i8 %a, 21
+  ret i1 %b
+}
+
+; Tests for eq/ne
+
+define i1 @eq_rem_zero(i8 %x) {
+; CHECK-LABEL: @eq_rem_zero(
+; CHECK-NEXT:    [[A:%.*]] = mul nuw i8 [[X:%.*]], 5
+; CHECK-NEXT:    [[B:%.*]] = icmp eq i8 [[A]], 20
+; CHECK-NEXT:    ret i1 [[B]]
+;
+  %a = mul nuw i8 %x, 5
+  %b = icmp eq i8 %a, 20
+  ret i1 %b
+}
+
+define i1 @ne_rem_zero(i8 %x) {
+; CHECK-LABEL: @ne_rem_zero(
+; CHECK-NEXT:    [[A:%.*]] = mul nuw i8 [[X:%.*]], 5
+; CHECK-NEXT:    [[B:%.*]] = icmp ne i8 [[A]], 30
+; CHECK-NEXT:    ret i1 [[B]]
+;
+  %a = mul nuw i8 %x, 5
+  %b = icmp ne i8 %a, 30
+  ret i1 %b
+}
+
+define i1 @eq_rem_nz(i8 %x) {
+; CHECK-LABEL: @eq_rem_nz(
+; CHECK-NEXT:    [[A:%.*]] = mul nuw i8 [[X:%.*]], 5
+; CHECK-NEXT:    [[B:%.*]] = icmp eq i8 [[A]], 31
+; CHECK-NEXT:    ret i1 [[B]]
+;
+  %a = mul nuw i8 %x, 5
+  %b = icmp eq i8 %a, 31
+  ret i1 %b
+}
+
+define i1 @ne_rem_nz(i8 %x) {
+; CHECK-LABEL: @ne_rem_nz(
+; CHECK-NEXT:    [[A:%.*]] = mul nuw i8 [[X:%.*]], 5
+; CHECK-NEXT:    [[B:%.*]] = icmp ne i8 [[A]], 31
+; CHECK-NEXT:    ret i1 [[B]]
+;
+  %a = mul nuw i8 %x, 5
+  %b = icmp ne i8 %a, 31
+  ret i1 %b
+}
+
+; Negative tests for the icmp mul folds
+
+define i1 @sgt_positive_multip_rem_zero_nonsw(i8 %x) {
+; CHECK-LABEL: @sgt_positive_multip_rem_zero_nonsw(
+; CHECK-NEXT:    [[A:%.*]] = mul i8 [[X:%.*]], 7
+; CHECK-NEXT:    [[B:%.*]] = icmp sgt i8 [[A]], 21
+; CHECK-NEXT:    ret i1 [[B]]
+;
+  %a = mul i8 %x, 7
+  %b = icmp sgt i8 %a, 21
+  ret i1 %b
+}
+
+define i1 @ult_multip_rem_zero_nonsw(i8 %x) {
+; CHECK-LABEL: @ult_multip_rem_zero_nonsw(
+; CHECK-NEXT:    [[A:%.*]] = mul i8 [[X:%.*]], 7
+; CHECK-NEXT:    [[B:%.*]] = icmp ult i8 [[A]], 21
+; CHECK-NEXT:    ret i1 [[B]]
+;
+  %a = mul i8 %x, 7
+  %b = icmp ult i8 %a, 21
+  ret i1 %b
+}
+
+define i1 @ugt_rem_zero_nonuw(i8 %x) {
+; CHECK-LABEL: @ugt_rem_zero_nonuw(
+; CHECK-NEXT:    [[A:%.*]] = mul i8 [[X:%.*]], 7
+; CHECK-NEXT:    [[B:%.*]] = icmp ugt i8 [[A]], 21
+; CHECK-NEXT:    ret i1 [[B]]
+;
+  %a = mul i8 %x, 7
+  %b = icmp ugt i8 %a, 21
+  ret i1 %b
+}
+
+define i1 @sgt_minnum(i8 %x) {
+; CHECK-LABEL: @sgt_minnum(
+; CHECK-NEXT:    [[A:%.*]] = mul nsw i8 [[X:%.*]], 7
+; CHECK-NEXT:    [[B:%.*]] = icmp ne i8 [[A]], -128
+; CHECK-NEXT:    ret i1 [[B]]
+;
+  %a = mul nsw i8 %x, 7
+  %b = icmp sgt i8 %a, -128
+  ret i1 %b
+}
+
+define i1 @ule_bignum(i8 %x) {
+; CHECK-LABEL: @ule_bignum(
+; CHECK-NEXT:    [[B:%.*]] = icmp eq i8 [[X:%.*]], 0
+; CHECK-NEXT:    ret i1 [[B]]
+;
+  %a = mul i8 %x, 2147483647
+  %b = icmp ule i8 %a, 0
+  ret i1 %b
+}
+
+define i1 @sgt_mulzero(i8 %x) {
+; CHECK-LABEL: @sgt_mulzero(
+; CHECK-NEXT:    ret i1 false
+;
+  %a = mul nsw i8 %x, 0
+  %b = icmp sgt i8 %a, 21
+  ret i1 %b
+}
+
+define i1 @eq_rem_zero_nonuw(i8 %x) {
+; CHECK-LABEL: @eq_rem_zero_nonuw(
+; CHECK-NEXT:    [[A:%.*]] = mul i8 [[X:%.*]], 5
+; CHECK-NEXT:    [[B:%.*]] = icmp eq i8 [[A]], 20
+; CHECK-NEXT:    ret i1 [[B]]
+;
+  %a = mul i8 %x, 5
+  %b = icmp eq i8 %a, 20
+  ret i1 %b
+}
+
+define i1 @ne_rem_zero_nonuw(i8 %x) {
+; CHECK-LABEL: @ne_rem_zero_nonuw(
+; CHECK-NEXT:    [[A:%.*]] = mul i8 [[X:%.*]], 5
+; CHECK-NEXT:    [[B:%.*]] = icmp ne i8 [[A]], 30
+; CHECK-NEXT:    ret i1 [[B]]
+;
+  %a = mul i8 %x, 5
+  %b = icmp ne i8 %a, 30
+  ret i1 %b
+}




More information about the llvm-commits mailing list