[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/smin-icmp.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/smin-icmp.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/smin-icmp.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/smin-icmp.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,333 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt -S -instcombine < %s | FileCheck %s
+
+; If we have an smin feeding a signed or equality icmp that shares an
+; operand with the smin, the compare should always be folded.
+; Test all 6 foldable predicates (eq,ne,sge,sgt,sle,slt) * 4 commutation
+; possibilities for each predicate. Note that folds to true/false or
+; folds to an existing instruction may be handled by InstSimplify.
+
+; smin(X, Y) == X --> X <= Y
+
+define i1 @eq_smin1(i32 %x, i32 %y) {
+; CHECK-LABEL: @eq_smin1(
+; CHECK-NEXT:    [[CMP2:%.*]] = icmp sle i32 %x, %y
+; CHECK-NEXT:    ret i1 [[CMP2]]
+;
+  %cmp1 = icmp slt i32 %x, %y
+  %sel = select i1 %cmp1, i32 %x, i32 %y
+  %cmp2 = icmp eq i32 %sel, %x
+  ret i1 %cmp2
+}
+
+; Commute min operands.
+
+define i1 @eq_smin2(i32 %x, i32 %y) {
+; CHECK-LABEL: @eq_smin2(
+; CHECK-NEXT:    [[CMP2:%.*]] = icmp sle i32 %x, %y
+; CHECK-NEXT:    ret i1 [[CMP2]]
+;
+  %cmp1 = icmp slt i32 %y, %x
+  %sel = select i1 %cmp1, i32 %y, i32 %x
+  %cmp2 = icmp eq i32 %sel, %x
+  ret i1 %cmp2
+}
+
+; Disguise the icmp predicate by commuting the min op to the RHS.
+
+define i1 @eq_smin3(i32 %a, i32 %y) {
+; CHECK-LABEL: @eq_smin3(
+; CHECK-NEXT:    [[X:%.*]] = add i32 %a, 3
+; CHECK-NEXT:    [[CMP2:%.*]] = icmp sle i32 [[X]], %y
+; CHECK-NEXT:    ret i1 [[CMP2]]
+;
+  %x = add i32 %a, 3 ; thwart complexity-based canonicalization
+  %cmp1 = icmp slt i32 %x, %y
+  %sel = select i1 %cmp1, i32 %x, i32 %y
+  %cmp2 = icmp eq i32 %x, %sel
+  ret i1 %cmp2
+}
+
+; Commute min operands.
+
+define i1 @eq_smin4(i32 %a, i32 %y) {
+; CHECK-LABEL: @eq_smin4(
+; CHECK-NEXT:    [[X:%.*]] = add i32 %a, 3
+; CHECK-NEXT:    [[CMP2:%.*]] = icmp sle i32 [[X]], %y
+; CHECK-NEXT:    ret i1 [[CMP2]]
+;
+  %x = add i32 %a, 3 ; thwart complexity-based canonicalization
+  %cmp1 = icmp slt i32 %y, %x
+  %sel = select i1 %cmp1, i32 %y, i32 %x
+  %cmp2 = icmp eq i32 %x, %sel
+  ret i1 %cmp2
+}
+
+; smin(X, Y) >= X --> X <= Y
+
+define i1 @sge_smin1(i32 %x, i32 %y) {
+; CHECK-LABEL: @sge_smin1(
+; CHECK-NEXT:    [[CMP2:%.*]] = icmp sle i32 %x, %y
+; CHECK-NEXT:    ret i1 [[CMP2]]
+;
+  %cmp1 = icmp slt i32 %x, %y
+  %sel = select i1 %cmp1, i32 %x, i32 %y
+  %cmp2 = icmp sge i32 %sel, %x
+  ret i1 %cmp2
+}
+
+; Commute min operands.
+
+define i1 @sge_smin2(i32 %x, i32 %y) {
+; CHECK-LABEL: @sge_smin2(
+; CHECK-NEXT:    [[CMP2:%.*]] = icmp sle i32 %x, %y
+; CHECK-NEXT:    ret i1 [[CMP2]]
+;
+  %cmp1 = icmp slt i32 %y, %x
+  %sel = select i1 %cmp1, i32 %y, i32 %x
+  %cmp2 = icmp sge i32 %sel, %x
+  ret i1 %cmp2
+}
+
+; Disguise the icmp predicate by commuting the min op to the RHS.
+
+define i1 @sge_smin3(i32 %a, i32 %y) {
+; CHECK-LABEL: @sge_smin3(
+; CHECK-NEXT:    [[X:%.*]] = add i32 %a, 3
+; CHECK-NEXT:    [[CMP2:%.*]] = icmp sle i32 [[X]], %y
+; CHECK-NEXT:    ret i1 [[CMP2]]
+;
+  %x = add i32 %a, 3 ; thwart complexity-based canonicalization
+  %cmp1 = icmp slt i32 %x, %y
+  %sel = select i1 %cmp1, i32 %x, i32 %y
+  %cmp2 = icmp sle i32 %x, %sel
+  ret i1 %cmp2
+}
+
+; Commute min operands.
+
+define i1 @sge_smin4(i32 %a, i32 %y) {
+; CHECK-LABEL: @sge_smin4(
+; CHECK-NEXT:    [[X:%.*]] = add i32 %a, 3
+; CHECK-NEXT:    [[CMP2:%.*]] = icmp sle i32 [[X]], %y
+; CHECK-NEXT:    ret i1 [[CMP2]]
+;
+  %x = add i32 %a, 3 ; thwart complexity-based canonicalization
+  %cmp1 = icmp slt i32 %y, %x
+  %sel = select i1 %cmp1, i32 %y, i32 %x
+  %cmp2 = icmp sle i32 %x, %sel
+  ret i1 %cmp2
+}
+
+; smin(X, Y) != X --> X > Y
+
+define i1 @ne_smin1(i32 %x, i32 %y) {
+; CHECK-LABEL: @ne_smin1(
+; CHECK-NEXT:    [[CMP2:%.*]] = icmp sgt i32 %x, %y
+; CHECK-NEXT:    ret i1 [[CMP2]]
+;
+  %cmp1 = icmp slt i32 %x, %y
+  %sel = select i1 %cmp1, i32 %x, i32 %y
+  %cmp2 = icmp ne i32 %sel, %x
+  ret i1 %cmp2
+}
+
+; Commute min operands.
+
+define i1 @ne_smin2(i32 %x, i32 %y) {
+; CHECK-LABEL: @ne_smin2(
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp slt i32 %y, %x
+; CHECK-NEXT:    ret i1 [[CMP1]]
+;
+  %cmp1 = icmp slt i32 %y, %x
+  %sel = select i1 %cmp1, i32 %y, i32 %x
+  %cmp2 = icmp ne i32 %sel, %x
+  ret i1 %cmp2
+}
+
+; Disguise the icmp predicate by commuting the min op to the RHS.
+
+define i1 @ne_smin3(i32 %a, i32 %y) {
+; CHECK-LABEL: @ne_smin3(
+; CHECK-NEXT:    [[X:%.*]] = add i32 %a, 3
+; CHECK-NEXT:    [[CMP2:%.*]] = icmp sgt i32 [[X]], %y
+; CHECK-NEXT:    ret i1 [[CMP2]]
+;
+  %x = add i32 %a, 3 ; thwart complexity-based canonicalization
+  %cmp1 = icmp slt i32 %x, %y
+  %sel = select i1 %cmp1, i32 %x, i32 %y
+  %cmp2 = icmp ne i32 %x, %sel
+  ret i1 %cmp2
+}
+
+; Commute min operands.
+
+define i1 @ne_smin4(i32 %a, i32 %y) {
+; CHECK-LABEL: @ne_smin4(
+; CHECK-NEXT:    [[X:%.*]] = add i32 %a, 3
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp sgt i32 [[X]], %y
+; CHECK-NEXT:    ret i1 [[CMP1]]
+;
+  %x = add i32 %a, 3 ; thwart complexity-based canonicalization
+  %cmp1 = icmp slt i32 %y, %x
+  %sel = select i1 %cmp1, i32 %y, i32 %x
+  %cmp2 = icmp ne i32 %x, %sel
+  ret i1 %cmp2
+}
+
+; smin(X, Y) < X --> X > Y
+
+define i1 @slt_smin1(i32 %x, i32 %y) {
+; CHECK-LABEL: @slt_smin1(
+; CHECK-NEXT:    [[CMP2:%.*]] = icmp sgt i32 %x, %y
+; CHECK-NEXT:    ret i1 [[CMP2]]
+;
+  %cmp1 = icmp slt i32 %x, %y
+  %sel = select i1 %cmp1, i32 %x, i32 %y
+  %cmp2 = icmp slt i32 %sel, %x
+  ret i1 %cmp2
+}
+
+; Commute min operands.
+
+define i1 @slt_smin2(i32 %x, i32 %y) {
+; CHECK-LABEL: @slt_smin2(
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp slt i32 %y, %x
+; CHECK-NEXT:    ret i1 [[CMP1]]
+;
+  %cmp1 = icmp slt i32 %y, %x
+  %sel = select i1 %cmp1, i32 %y, i32 %x
+  %cmp2 = icmp slt i32 %sel, %x
+  ret i1 %cmp2
+}
+
+; Disguise the icmp predicate by commuting the min op to the RHS.
+
+define i1 @slt_smin3(i32 %a, i32 %y) {
+; CHECK-LABEL: @slt_smin3(
+; CHECK-NEXT:    [[X:%.*]] = add i32 %a, 3
+; CHECK-NEXT:    [[CMP2:%.*]] = icmp sgt i32 [[X]], %y
+; CHECK-NEXT:    ret i1 [[CMP2]]
+;
+  %x = add i32 %a, 3 ; thwart complexity-based canonicalization
+  %cmp1 = icmp slt i32 %x, %y
+  %sel = select i1 %cmp1, i32 %x, i32 %y
+  %cmp2 = icmp sgt i32 %x, %sel
+  ret i1 %cmp2
+}
+
+; Commute min operands.
+
+define i1 @slt_smin4(i32 %a, i32 %y) {
+; CHECK-LABEL: @slt_smin4(
+; CHECK-NEXT:    [[X:%.*]] = add i32 %a, 3
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp sgt i32 [[X]], %y
+; CHECK-NEXT:    ret i1 [[CMP1]]
+;
+  %x = add i32 %a, 3 ; thwart complexity-based canonicalization
+  %cmp1 = icmp slt i32 %y, %x
+  %sel = select i1 %cmp1, i32 %y, i32 %x
+  %cmp2 = icmp sgt i32 %x, %sel
+  ret i1 %cmp2
+}
+
+; smin(X, Y) <= X --> true
+
+define i1 @sle_smin1(i32 %x, i32 %y) {
+; CHECK-LABEL: @sle_smin1(
+; CHECK-NEXT:    ret i1 true
+;
+  %cmp1 = icmp slt i32 %x, %y
+  %sel = select i1 %cmp1, i32 %x, i32 %y
+  %cmp2 = icmp sle i32 %sel, %x
+  ret i1 %cmp2
+}
+
+; Commute min operands.
+
+define i1 @sle_smin2(i32 %x, i32 %y) {
+; CHECK-LABEL: @sle_smin2(
+; CHECK-NEXT:    ret i1 true
+;
+  %cmp1 = icmp slt i32 %y, %x
+  %sel = select i1 %cmp1, i32 %y, i32 %x
+  %cmp2 = icmp sle i32 %sel, %x
+  ret i1 %cmp2
+}
+
+; Disguise the icmp predicate by commuting the min op to the RHS.
+
+define i1 @sle_smin3(i32 %a, i32 %y) {
+; CHECK-LABEL: @sle_smin3(
+; CHECK-NEXT:    ret i1 true
+;
+  %x = add i32 %a, 3 ; thwart complexity-based canonicalization
+  %cmp1 = icmp slt i32 %x, %y
+  %sel = select i1 %cmp1, i32 %x, i32 %y
+  %cmp2 = icmp sge i32 %x, %sel
+  ret i1 %cmp2
+}
+
+; Commute min operands.
+
+define i1 @sle_smin4(i32 %a, i32 %y) {
+; CHECK-LABEL: @sle_smin4(
+; CHECK-NEXT:    ret i1 true
+;
+  %x = add i32 %a, 3 ; thwart complexity-based canonicalization
+  %cmp1 = icmp slt i32 %y, %x
+  %sel = select i1 %cmp1, i32 %y, i32 %x
+  %cmp2 = icmp sge i32 %x, %sel
+  ret i1 %cmp2
+}
+
+; smin(X, Y) > X --> false
+
+define i1 @sgt_smin1(i32 %x, i32 %y) {
+; CHECK-LABEL: @sgt_smin1(
+; CHECK-NEXT:    ret i1 false
+;
+  %cmp1 = icmp slt i32 %x, %y
+  %sel = select i1 %cmp1, i32 %x, i32 %y
+  %cmp2 = icmp sgt i32 %sel, %x
+  ret i1 %cmp2
+}
+
+; Commute min operands.
+
+define i1 @sgt_smin2(i32 %x, i32 %y) {
+; CHECK-LABEL: @sgt_smin2(
+; CHECK-NEXT:    ret i1 false
+;
+  %cmp1 = icmp slt i32 %y, %x
+  %sel = select i1 %cmp1, i32 %y, i32 %x
+  %cmp2 = icmp sgt i32 %sel, %x
+  ret i1 %cmp2
+}
+
+; Disguise the icmp predicate by commuting the min op to the RHS.
+
+define i1 @sgt_smin3(i32 %a, i32 %y) {
+; CHECK-LABEL: @sgt_smin3(
+; CHECK-NEXT:    ret i1 false
+;
+  %x = add i32 %a, 3 ; thwart complexity-based canonicalization
+  %cmp1 = icmp slt i32 %x, %y
+  %sel = select i1 %cmp1, i32 %x, i32 %y
+  %cmp2 = icmp slt i32 %x, %sel
+  ret i1 %cmp2
+}
+
+; Commute min operands.
+
+define i1 @sgt_smin4(i32 %a, i32 %y) {
+; CHECK-LABEL: @sgt_smin4(
+; CHECK-NEXT:    ret i1 false
+;
+  %x = add i32 %a, 3 ; thwart complexity-based canonicalization
+  %cmp1 = icmp slt i32 %y, %x
+  %sel = select i1 %cmp1, i32 %y, i32 %x
+  %cmp2 = icmp slt i32 %x, %sel
+  ret i1 %cmp2
+}
+

Added: llvm/trunk/test/Transforms/InstCombine/snprintf.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/snprintf.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/snprintf.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/snprintf.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
+
+ at .str = private unnamed_addr constant [4 x i8] c"str\00", align 1
+ at .str.1 = private unnamed_addr constant [3 x i8] c"%%\00", align 1
+ at .str.2 = private unnamed_addr constant [3 x i8] c"%c\00", align 1
+ at .str.3 = private unnamed_addr constant [3 x i8] c"%s\00", align 1
+
+declare i32 @snprintf(i8*, i64, i8*, ...) #1
+
+define void @test_not_const_fmt(i8* %buf, i8* %fmt) #0 {
+; CHECK-LABEL: @test_not_const_fmt(
+; CHECK-NEXT:    [[CALL:%.*]] = call i32 (i8*, i64, i8*, ...) @snprintf(i8* [[BUF:%.*]], i64 32, i8* [[FMT:%.*]])
+; CHECK-NEXT:    ret void
+;
+  %call = call i32 (i8*, i64, i8*, ...) @snprintf(i8* %buf, i64 32, i8* %fmt) #2
+  ret void
+}
+
+define void @test_not_const_fmt_zero_size_return_value(i8* %buf, i8* %fmt) #0 {
+; CHECK-LABEL: @test_not_const_fmt_zero_size_return_value(
+; CHECK-NEXT:    [[CALL:%.*]] = call i32 (i8*, i64, i8*, ...) @snprintf(i8* [[BUF:%.*]], i64 0, i8* [[FMT:%.*]])
+; CHECK-NEXT:    ret void
+;
+  %call = call i32 (i8*, i64, i8*, ...) @snprintf(i8* %buf, i64 0, i8* %fmt) #2
+  ret void
+}
+
+
+define void @test_not_const_size(i8* %buf, i64 %size) #0 {
+; CHECK-LABEL: @test_not_const_size(
+; CHECK-NEXT:    [[CALL:%.*]] = call i32 (i8*, i64, i8*, ...) @snprintf(i8* [[BUF:%.*]], i64 [[SIZE:%.*]], i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str, i64 0, i64 0))
+; CHECK-NEXT:    ret void
+;
+  %call = call i32 (i8*, i64, i8*, ...) @snprintf(i8* %buf, i64 %size, i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str, i64 0, i64 0)) #2
+  ret void
+}
+
+
+define i32 @test_return_value(i8* %buf) #0 {
+; CHECK-LABEL: @test_return_value(
+; CHECK-NEXT:    ret i32 3
+;
+  %call = call i32 (i8*, i64, i8*, ...) @snprintf(i8* %buf, i64 0, i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str, i64 0, i64 0)) #2
+  ret i32 %call
+}
+
+define void @test_percentage(i8* %buf) #0 {
+; CHECK-LABEL: @test_percentage(
+; CHECK-NEXT:    [[CALL:%.*]] = call i32 (i8*, i64, i8*, ...) @snprintf(i8* [[BUF:%.*]], i64 32, i8* getelementptr inbounds ([3 x i8], [3 x i8]* @.str.1, i64 0, i64 0))
+; CHECK-NEXT:    ret void
+;
+  %call = call i32 (i8*, i64, i8*, ...) @snprintf(i8* %buf, i64 32, i8* getelementptr inbounds ([3 x i8], [3 x i8]* @.str.1, i64 0, i64 0)) #2
+  ret void
+}
+
+define i32 @test_null_buf_return_value() #0 {
+; CHECK-LABEL: @test_null_buf_return_value(
+; CHECK-NEXT:    ret i32 3
+;
+  %call = call i32 (i8*, i64, i8*, ...) @snprintf(i8* null, i64 0, i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str, i64 0, i64 0)) #2
+  ret i32 %call
+}
+
+define i32 @test_percentage_return_value() #0 {
+; CHECK-LABEL: @test_percentage_return_value(
+; CHECK-NEXT:    [[CALL:%.*]] = call i32 (i8*, i64, i8*, ...) @snprintf(i8* null, i64 0, i8* getelementptr inbounds ([3 x i8], [3 x i8]* @.str.1, i64 0, i64 0))
+; CHECK-NEXT:    ret i32 [[CALL]]
+;
+  %call = call i32 (i8*, i64, i8*, ...) @snprintf(i8* null, i64 0, i8* getelementptr inbounds ([3 x i8], [3 x i8]* @.str.1, i64 0, i64 0)) #3
+  ret i32 %call
+}
+
+
+define void @test_correct_copy(i8* %buf) #0 {
+; CHECK-LABEL: @test_correct_copy(
+; CHECK-NEXT:    [[TMP1:%.*]] = bitcast i8* [[BUF:%.*]] to i32*
+; CHECK-NEXT:    store i32 7500915, i32* [[TMP1]], align 1
+; CHECK-NEXT:    ret void
+;
+  %call = call i32 (i8*, i64, i8*, ...) @snprintf(i8* %buf, i64 32, i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str, i64 0, i64 0)) #2
+  ret void
+}
+
+define i32 @test_char_zero_size(i8* %buf) #0 {
+; CHECK-LABEL: @test_char_zero_size(
+; CHECK-NEXT:    ret i32 1
+;
+  %call = call i32 (i8*, i64, i8*, ...) @snprintf(i8* %buf, i64 0, i8* getelementptr inbounds ([3 x i8], [3 x i8]* @.str.2, i64 0, i64 0), i32 65) #2
+  ret i32 %call
+}
+
+define i32 @test_char_wrong_size(i8* %buf) #0 {
+; CHECK-LABEL: @test_char_wrong_size(
+; CHECK-NEXT:    [[CALL:%.*]] = call i32 (i8*, i64, i8*, ...) @snprintf(i8* [[BUF:%.*]], i64 1, i8* getelementptr inbounds ([3 x i8], [3 x i8]* @.str.2, i64 0, i64 0), i32 65)
+; CHECK-NEXT:    ret i32 [[CALL]]
+;
+  %call = call i32 (i8*, i64, i8*, ...) @snprintf(i8* %buf, i64 1, i8* getelementptr inbounds ([3 x i8], [3 x i8]* @.str.2, i64 0, i64 0), i32 65) #2
+  ret i32 %call
+}
+
+define i32 @test_char_ok_size(i8* %buf) #0 {
+; CHECK-LABEL: @test_char_ok_size(
+; CHECK-NEXT:    store i8 65, i8* [[BUF:%.*]], align 1
+; CHECK-NEXT:    [[NUL:%.*]] = getelementptr i8, i8* [[BUF]], i64 1
+; CHECK-NEXT:    store i8 0, i8* [[NUL]], align 1
+; CHECK-NEXT:    ret i32 1
+;
+  %call = call i32 (i8*, i64, i8*, ...) @snprintf(i8* %buf, i64 32, i8* getelementptr inbounds ([3 x i8], [3 x i8]* @.str.2, i64 0, i64 0), i32 65) #2
+  ret i32 %call
+}
+
+define i32 @test_str_zero_size(i8* %buf) #0 {
+; CHECK-LABEL: @test_str_zero_size(
+; CHECK-NEXT:    ret i32 3
+;
+  %call = call i32 (i8*, i64, i8*, ...) @snprintf(i8* %buf, i64 0, i8* getelementptr inbounds ([3 x i8], [3 x i8]* @.str.3, i64 0, i64 0), i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str, i64 0, i64 0)) #2
+  ret i32 %call
+}
+
+define i32 @test_str_wrong_size(i8* %buf) #0 {
+; CHECK-LABEL: @test_str_wrong_size(
+; CHECK-NEXT:    [[CALL:%.*]] = call i32 (i8*, i64, i8*, ...) @snprintf(i8* [[BUF:%.*]], i64 1, i8* getelementptr inbounds ([3 x i8], [3 x i8]* @.str.3, i64 0, i64 0), i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str, i64 0, i64 0))
+; CHECK-NEXT:    ret i32 [[CALL]]
+;
+  %call = call i32 (i8*, i64, i8*, ...) @snprintf(i8* %buf, i64 1, i8* getelementptr inbounds ([3 x i8], [3 x i8]* @.str.3, i64 0, i64 0), i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str, i64 0, i64 0)) #2
+  ret i32 %call
+}
+
+define i32 @test_str_ok_size(i8* %buf) #0 {
+; CHECK-LABEL: @test_str_ok_size(
+; CHECK-NEXT:    [[TMP1:%.*]] = bitcast i8* [[BUF:%.*]] to i32*
+; CHECK-NEXT:    store i32 7500915, i32* [[TMP1]], align 1
+; CHECK-NEXT:    ret i32 3
+;
+  %call = call i32 (i8*, i64, i8*, ...) @snprintf(i8* %buf, i64 32, i8* getelementptr inbounds ([3 x i8], [3 x i8]* @.str.3, i64 0, i64 0), i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str, i64 0, i64 0)) #2
+  ret i32 %call
+}

Added: llvm/trunk/test/Transforms/InstCombine/sprintf-1.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/sprintf-1.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/sprintf-1.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/sprintf-1.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,100 @@
+; Test that the sprintf 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"
+
+ at hello_world = constant [13 x i8] c"hello world\0A\00"
+ at null = constant [1 x i8] zeroinitializer
+ at null_hello = constant [7 x i8] c"\00hello\00"
+ at h = constant [2 x i8] c"h\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 @sprintf(i8*, i8*, ...)
+
+; Check sprintf(dst, fmt) -> llvm.memcpy(str, fmt, strlen(fmt) + 1, 1).
+
+define void @test_simplify1(i8* %dst) {
+; CHECK-LABEL: @test_simplify1(
+  %fmt = getelementptr [13 x i8], [13 x i8]* @hello_world, i32 0, i32 0
+  call i32 (i8*, i8*, ...) @sprintf(i8* %dst, i8* %fmt)
+; CHECK-NEXT: call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 1 %dst, i8* align 1 getelementptr inbounds ([13 x i8], [13 x i8]* @hello_world, i32 0, i32 0), i32 13, i1 false)
+  ret void
+; CHECK-NEXT: ret void
+}
+
+define void @test_simplify2(i8* %dst) {
+; CHECK-LABEL: @test_simplify2(
+  %fmt = getelementptr [1 x i8], [1 x i8]* @null, i32 0, i32 0
+  call i32 (i8*, i8*, ...) @sprintf(i8* %dst, i8* %fmt)
+; CHECK-NEXT: store i8 0, i8* %dst, align 1
+  ret void
+; CHECK-NEXT: ret void
+}
+
+define void @test_simplify3(i8* %dst) {
+; CHECK-LABEL: @test_simplify3(
+  %fmt = getelementptr [7 x i8], [7 x i8]* @null_hello, i32 0, i32 0
+  call i32 (i8*, i8*, ...) @sprintf(i8* %dst, i8* %fmt)
+; CHECK-NEXT: store i8 0, i8* %dst, align 1
+  ret void
+; CHECK-NEXT: ret void
+}
+
+; Check sprintf(dst, "%c", chr) -> *(i8*)dst = chr; *((i8*)dst + 1) = 0.
+
+define void @test_simplify4(i8* %dst) {
+; CHECK-LABEL: @test_simplify4(
+  %fmt = getelementptr [3 x i8], [3 x i8]* @percent_c, i32 0, i32 0
+  call i32 (i8*, i8*, ...) @sprintf(i8* %dst, i8* %fmt, i8 104)
+; CHECK-NEXT: store i8 104, i8* %dst, align 1
+; CHECK-NEXT: [[NUL:%[a-z0-9]+]] = getelementptr i8, i8* %dst, i32 1
+; CHECK-NEXT: store i8 0, i8* [[NUL]], align 1
+  ret void
+; CHECK-NEXT: ret void
+}
+
+; Check sprintf(dst, "%s", str) -> llvm.memcpy(dest, str, strlen(str) + 1, 1).
+
+define void @test_simplify5(i8* %dst, i8* %str) {
+; CHECK-LABEL: @test_simplify5(
+  %fmt = getelementptr [3 x i8], [3 x i8]* @percent_s, i32 0, i32 0
+  call i32 (i8*, i8*, ...) @sprintf(i8* %dst, i8* %fmt, i8* %str)
+; CHECK-NEXT: [[STRLEN:%[a-z0-9]+]] = call i32 @strlen(i8* %str)
+; CHECK-NEXT: [[LENINC:%[a-z0-9]+]] = add i32 [[STRLEN]], 1
+; CHECK-NEXT: call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 1 %dst, i8* align 1 %str, i32 [[LENINC]], i1 false)
+  ret void
+; CHECK-NEXT: ret void
+}
+
+; Check sprintf(dst, format, ...) -> siprintf(str, format, ...) if no floating.
+
+define void @test_simplify6(i8* %dst) {
+; CHECK-IPRINTF-LABEL: @test_simplify6(
+  %fmt = getelementptr [3 x i8], [3 x i8]* @percent_d, i32 0, i32 0
+  call i32 (i8*, i8*, ...) @sprintf(i8* %dst, i8* %fmt, i32 187)
+; CHECK-IPRINTF-NEXT: call i32 (i8*, i8*, ...) @siprintf(i8* %dst, 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_no_simplify1(i8* %dst) {
+; CHECK-IPRINTF-LABEL: @test_no_simplify1(
+  %fmt = getelementptr [3 x i8], [3 x i8]* @percent_f, i32 0, i32 0
+  call i32 (i8*, i8*, ...) @sprintf(i8* %dst, i8* %fmt, double 1.87)
+; CHECK-IPRINTF-NEXT: call i32 (i8*, i8*, ...) @sprintf(i8* %dst, 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(i8* %dst, i8* %fmt, double %d) {
+; CHECK-LABEL: @test_no_simplify2(
+  call i32 (i8*, i8*, ...) @sprintf(i8* %dst, i8* %fmt, double %d)
+; CHECK-NEXT: call i32 (i8*, i8*, ...) @sprintf(i8* %dst, i8* %fmt, double %d)
+  ret void
+; CHECK-NEXT: ret void
+}

Added: llvm/trunk/test/Transforms/InstCombine/sprintf-void.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/sprintf-void.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/sprintf-void.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/sprintf-void.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,21 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; 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"
+
+ at hello_world = constant [13 x i8] c"hello world\0A\00"
+
+declare void @sprintf(i8*, i8*, ...)
+
+; Check that a sprintf call, that would otherwise be optimized, but with
+; optimized out return type, doesn't crash the optimizer.
+
+define void @test_simplify1(i8* %dst) {
+; CHECK-LABEL: @test_simplify1(
+; CHECK-NEXT:    call void (i8*, i8*, ...) @sprintf(i8* [[DST:%.*]], i8* getelementptr inbounds ([13 x i8], [13 x i8]* @hello_world, i32 0, i32 0))
+; CHECK-NEXT:    ret void
+;
+  %fmt = getelementptr [13 x i8], [13 x i8]* @hello_world, i32 0, i32 0
+  call void (i8*, i8*, ...) @sprintf(i8* %dst, i8* %fmt)
+  ret void
+}

Added: llvm/trunk/test/Transforms/InstCombine/sqrt-nofast.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/sqrt-nofast.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/sqrt-nofast.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/sqrt-nofast.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,25 @@
+; Check that we skip transformations if the attribute unsafe-fp-math
+; is not set.
+; RUN: opt < %s -instcombine -S | FileCheck %s
+
+define float @mysqrt(float %x, float %y) #0 {
+entry:
+  %x.addr = alloca float, align 4
+  %y.addr = alloca float, align 4
+  store float %x, float* %x.addr, align 4
+  store float %y, float* %y.addr, align 4
+  %0 = load float, float* %x.addr, align 4
+  %1 = load float, float* %x.addr, align 4
+  %mul = fmul fast float %0, %1
+  %2 = call float @llvm.sqrt.f32(float %mul)
+  ret float %2
+}
+
+declare float @llvm.sqrt.f32(float) #1
+
+; CHECK: define float @mysqrt(float %x, float %y) {
+; CHECK: entry:
+; CHECK:   %mul = fmul fast float %x, %x
+; CHECK:   %0 = call float @llvm.sqrt.f32(float %mul)
+; CHECK:   ret float %0
+; CHECK: }

Added: llvm/trunk/test/Transforms/InstCombine/sqrt.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/sqrt.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/sqrt.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/sqrt.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,54 @@
+; RUN: opt -S -instcombine < %s | FileCheck %s
+
+define float @test1(float %x) nounwind readnone ssp {
+entry:
+; CHECK-LABEL: @test1(
+; CHECK-NOT: fpext
+; CHECK-NOT: sqrt(
+; CHECK: sqrtf(
+; CHECK-NOT: fptrunc
+  %conv = fpext float %x to double                ; <double> [#uses=1]
+  %call = tail call double @sqrt(double %conv) readnone nounwind ; <double> [#uses=1]
+  %conv1 = fptrunc double %call to float          ; <float> [#uses=1]
+; CHECK: ret float
+  ret float %conv1
+}
+
+; PR8096
+define float @test2(float %x) nounwind readnone ssp {
+entry:
+; CHECK-LABEL: @test2(
+; CHECK-NOT: fpext
+; CHECK-NOT: sqrt(
+; CHECK: sqrtf(
+; CHECK-NOT: fptrunc
+  %conv = fpext float %x to double                ; <double> [#uses=1]
+  %call = tail call double @sqrt(double %conv) nounwind ; <double> [#uses=1]
+  %conv1 = fptrunc double %call to float          ; <float> [#uses=1]
+; CHECK: ret float
+  ret float %conv1
+}
+
+; rdar://9763193
+; Can't fold (fptrunc (sqrt (fpext x))) -> (sqrtf x) since there is another
+; use of sqrt result.
+define float @test3(float* %v) nounwind uwtable ssp {
+entry:
+; CHECK-LABEL: @test3(
+; CHECK: sqrt(
+; CHECK-NOT: sqrtf(
+; CHECK: fptrunc
+  %arrayidx13 = getelementptr inbounds float, float* %v, i64 2
+  %tmp14 = load float, float* %arrayidx13
+  %mul18 = fmul float %tmp14, %tmp14
+  %add19 = fadd float undef, %mul18
+  %conv = fpext float %add19 to double
+  %call34 = call double @sqrt(double %conv) readnone
+  %call36 = call i32 (double) @foo(double %call34) nounwind
+  %conv38 = fptrunc double %call34 to float
+  ret float %conv38
+}
+
+declare i32 @foo(double)
+
+declare double @sqrt(double) readnone

Added: llvm/trunk/test/Transforms/InstCombine/srem-canonicalize.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/srem-canonicalize.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/srem-canonicalize.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/srem-canonicalize.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,63 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt < %s -instcombine -S | FileCheck %s
+
+define i32 @test_srem_canonicalize_op0(i32 %x, i32 %y) {
+; CHECK-LABEL: @test_srem_canonicalize_op0(
+; CHECK-NEXT:    [[TMP1:%.*]] = srem i32 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    [[SREM:%.*]] = sub nsw i32 0, [[TMP1]]
+; CHECK-NEXT:    ret i32 [[SREM]]
+;
+  %neg = sub nsw i32 0, %x
+  %srem = srem i32 %neg, %y
+  ret i32 %srem
+}
+
+; (X srem -Y) is not equal to -(X srem Y), don't canonicalize.
+define i32 @test_srem_canonicalize_op1(i32 %x, i32 %z) {
+; CHECK-LABEL: @test_srem_canonicalize_op1(
+; CHECK-NEXT:    [[Y:%.*]] = mul i32 [[Z:%.*]], 3
+; CHECK-NEXT:    [[NEG:%.*]] = sub nsw i32 0, [[X:%.*]]
+; CHECK-NEXT:    [[SREM:%.*]] = srem i32 [[Y]], [[NEG]]
+; CHECK-NEXT:    ret i32 [[SREM]]
+;
+  %y = mul i32 %z, 3
+  %neg = sub nsw i32 0, %x
+  %srem = srem i32 %y, %neg
+  ret i32 %srem
+}
+
+define i32 @test_srem_canonicalize_nonsw(i32 %x, i32 %y) {
+; CHECK-LABEL: @test_srem_canonicalize_nonsw(
+; CHECK-NEXT:    [[NEG:%.*]] = sub i32 0, [[X:%.*]]
+; CHECK-NEXT:    [[SREM:%.*]] = srem i32 [[NEG]], [[Y:%.*]]
+; CHECK-NEXT:    ret i32 [[SREM]]
+;
+  %neg = sub i32 0, %x
+  %srem = srem i32 %neg, %y
+  ret i32 %srem
+}
+
+define <2 x i32> @test_srem_canonicalize_vec(<2 x i32> %x, <2 x i32> %y) {
+; CHECK-LABEL: @test_srem_canonicalize_vec(
+; CHECK-NEXT:    [[TMP1:%.*]] = srem <2 x i32> [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    [[SREM:%.*]] = sub nsw <2 x i32> zeroinitializer, [[TMP1]]
+; CHECK-NEXT:    ret <2 x i32> [[SREM]]
+;
+  %neg = sub nsw <2 x i32> <i32 0, i32 0>, %x
+  %srem = srem <2 x i32> %neg, %y
+  ret <2 x i32> %srem
+}
+
+define i32 @test_srem_canonicalize_multiple_uses(i32 %x, i32 %y) {
+; CHECK-LABEL: @test_srem_canonicalize_multiple_uses(
+; CHECK-NEXT:    [[NEG:%.*]] = sub nsw i32 0, [[X:%.*]]
+; CHECK-NEXT:    [[SREM:%.*]] = srem i32 [[NEG]], [[Y:%.*]]
+; CHECK-NEXT:    [[SREM2:%.*]] = srem i32 [[SREM]], [[NEG]]
+; CHECK-NEXT:    ret i32 [[SREM2]]
+;
+  %neg = sub nsw i32 0, %x
+  %srem = srem i32 %neg, %y
+  %srem2 = srem i32 %srem, %neg
+  ret i32 %srem2
+}
+

Added: llvm/trunk/test/Transforms/InstCombine/srem-simplify-bug.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/srem-simplify-bug.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/srem-simplify-bug.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/srem-simplify-bug.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,9 @@
+; RUN: opt < %s -instcombine -S | grep "ret i1 false"
+; PR2276
+
+define i1 @f(i32 %x) {
+  %A = or i32 %x, 1
+  %B = srem i32 %A, 1
+  %C = icmp ne i32 %B, 0
+  ret i1 %C
+}

Added: llvm/trunk/test/Transforms/InstCombine/srem1.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/srem1.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/srem1.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/srem1.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,18 @@
+; RUN: opt < %s -instcombine
+; PR2670
+
+ at g_127 = external global i32		; <i32*> [#uses=1]
+
+define i32 @func_56(i32 %p_58, i32 %p_59, i32 %p_61, i16 signext %p_62) nounwind {
+entry:
+	%call = call i32 (...) @rshift_s_s( i32 %p_61, i32 1 )		; <i32> [#uses=1]
+	%conv = sext i32 %call to i64		; <i64> [#uses=1]
+	%or = or i64 -1734012817166602727, %conv		; <i64> [#uses=1]
+	%rem = srem i64 %or, 1		; <i64> [#uses=1]
+	%cmp = icmp eq i64 %rem, 1		; <i1> [#uses=1]
+	%cmp.ext = zext i1 %cmp to i32		; <i32> [#uses=1]
+	store i32 %cmp.ext, i32* @g_127
+	ret i32 undef
+}
+
+declare i32 @rshift_s_s(...)

Added: llvm/trunk/test/Transforms/InstCombine/ssub-with-overflow.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/ssub-with-overflow.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/ssub-with-overflow.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/ssub-with-overflow.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,162 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt < %s -instcombine -S | FileCheck %s
+
+declare { <2 x i32>, <2 x i1> } @llvm.ssub.with.overflow.v2i32(<2 x i32>, <2 x i32>)
+
+declare { <2 x i8>, <2 x i1> } @llvm.ssub.with.overflow.v2i8(<2 x i8>, <2 x i8>)
+
+declare { i32, i1 } @llvm.ssub.with.overflow.i32(i32, i32)
+
+declare { i8, i1 } @llvm.ssub.with.overflow.i8(i8, i8)
+
+define { i32, i1 } @simple_fold(i32 %x) {
+; CHECK-LABEL: @simple_fold(
+; CHECK-NEXT:    [[TMP1:%.*]] = call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 [[X:%.*]], i32 -20)
+; CHECK-NEXT:    ret { i32, i1 } [[TMP1]]
+;
+  %a = sub nsw i32 %x, 7
+  %b = tail call { i32, i1 } @llvm.ssub.with.overflow.i32(i32 %a, i32 13)
+  ret { i32, i1 } %b
+}
+
+define { i32, i1 } @fold_mixed_signs(i32 %x) {
+; CHECK-LABEL: @fold_mixed_signs(
+; CHECK-NEXT:    [[B:%.*]] = add nsw i32 [[X:%.*]], -6
+; CHECK-NEXT:    [[TMP1:%.*]] = insertvalue { i32, i1 } { i32 undef, i1 false }, i32 [[B]], 0
+; CHECK-NEXT:    ret { i32, i1 } [[TMP1]]
+;
+  %a = sub nsw i32 %x, 13
+  %b = tail call { i32, i1 } @llvm.ssub.with.overflow.i32(i32 %a, i32 -7)
+  ret { i32, i1 } %b
+}
+
+define { i8, i1 } @fold_on_constant_sub_no_overflow(i8 %x) {
+; CHECK-LABEL: @fold_on_constant_sub_no_overflow(
+; CHECK-NEXT:    [[TMP1:%.*]] = call { i8, i1 } @llvm.sadd.with.overflow.i8(i8 [[X:%.*]], i8 -128)
+; CHECK-NEXT:    ret { i8, i1 } [[TMP1]]
+;
+  %a = sub nsw i8 %x, 100
+  %b = tail call { i8, i1 } @llvm.ssub.with.overflow.i8(i8 %a, i8 28)
+  ret { i8, i1 } %b
+}
+
+define { i8, i1 } @no_fold_on_constant_sub_overflow(i8 %x) {
+; CHECK-LABEL: @no_fold_on_constant_sub_overflow(
+; CHECK-NEXT:    [[A:%.*]] = add nsw i8 [[X:%.*]], -100
+; CHECK-NEXT:    [[TMP1:%.*]] = call { i8, i1 } @llvm.sadd.with.overflow.i8(i8 [[A]], i8 -29)
+; CHECK-NEXT:    ret { i8, i1 } [[TMP1]]
+;
+  %a = sub nsw i8 %x, 100
+  %b = tail call { i8, i1 } @llvm.ssub.with.overflow.i8(i8 %a, i8 29)
+  ret { i8, i1 } %b
+}
+
+define { <2 x i32>, <2 x i1> } @fold_simple_splat_constant(<2 x i32> %x) {
+; CHECK-LABEL: @fold_simple_splat_constant(
+; CHECK-NEXT:    [[TMP1:%.*]] = call { <2 x i32>, <2 x i1> } @llvm.sadd.with.overflow.v2i32(<2 x i32> [[X:%.*]], <2 x i32> <i32 -42, i32 -42>)
+; CHECK-NEXT:    ret { <2 x i32>, <2 x i1> } [[TMP1]]
+;
+  %a = sub nsw <2 x i32> %x, <i32 12, i32 12>
+  %b = tail call { <2 x i32>, <2 x i1> } @llvm.ssub.with.overflow.v2i32(<2 x i32> %a, <2 x i32> <i32 30, i32 30>)
+  ret { <2 x i32>, <2 x i1> } %b
+}
+
+define { <2 x i32>, <2 x i1> } @no_fold_splat_undef_constant(<2 x i32> %x) {
+; CHECK-LABEL: @no_fold_splat_undef_constant(
+; CHECK-NEXT:    [[A:%.*]] = add <2 x i32> [[X:%.*]], <i32 -12, i32 undef>
+; CHECK-NEXT:    [[TMP1:%.*]] = call { <2 x i32>, <2 x i1> } @llvm.sadd.with.overflow.v2i32(<2 x i32> [[A]], <2 x i32> <i32 -30, i32 -30>)
+; CHECK-NEXT:    ret { <2 x i32>, <2 x i1> } [[TMP1]]
+;
+  %a = sub nsw <2 x i32> %x, <i32 12, i32 undef>
+  %b = tail call { <2 x i32>, <2 x i1> } @llvm.ssub.with.overflow.v2i32(<2 x i32> %a, <2 x i32> <i32 30, i32 30>)
+  ret { <2 x i32>, <2 x i1> } %b
+}
+
+define { <2 x i32>, <2 x i1> } @no_fold_splat_not_constant(<2 x i32> %x, <2 x i32> %y) {
+; CHECK-LABEL: @no_fold_splat_not_constant(
+; CHECK-NEXT:    [[A:%.*]] = sub nsw <2 x i32> [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    [[TMP1:%.*]] = call { <2 x i32>, <2 x i1> } @llvm.sadd.with.overflow.v2i32(<2 x i32> [[A]], <2 x i32> <i32 -30, i32 -30>)
+; CHECK-NEXT:    ret { <2 x i32>, <2 x i1> } [[TMP1]]
+;
+  %a = sub nsw <2 x i32> %x, %y
+  %b = tail call { <2 x i32>, <2 x i1> } @llvm.ssub.with.overflow.v2i32(<2 x i32> %a, <2 x i32> <i32 30, i32 30>)
+  ret { <2 x i32>, <2 x i1> } %b
+}
+
+define { i32, i1 } @fold_nuwnsw(i32 %x) {
+; CHECK-LABEL: @fold_nuwnsw(
+; CHECK-NEXT:    [[TMP1:%.*]] = call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 [[X:%.*]], i32 -42)
+; CHECK-NEXT:    ret { i32, i1 } [[TMP1]]
+;
+  %a = sub nuw nsw i32 %x, 12
+  %b = tail call { i32, i1 } @llvm.ssub.with.overflow.i32(i32 %a, i32 30)
+  ret { i32, i1 } %b
+}
+
+define { i32, i1 } @no_fold_nuw(i32 %x) {
+; CHECK-LABEL: @no_fold_nuw(
+; CHECK-NEXT:    [[A:%.*]] = add i32 [[X:%.*]], -12
+; CHECK-NEXT:    [[TMP1:%.*]] = call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 [[A]], i32 -30)
+; CHECK-NEXT:    ret { i32, i1 } [[TMP1]]
+;
+  %a = sub nuw i32 %x, 12
+  %b = tail call { i32, i1 } @llvm.ssub.with.overflow.i32(i32 %a, i32 30)
+  ret { i32, i1 } %b
+}
+
+define { i32, i1 } @no_fold_wrapped_sub(i32 %x) {
+; CHECK-LABEL: @no_fold_wrapped_sub(
+; CHECK-NEXT:    [[A:%.*]] = add i32 [[X:%.*]], -12
+; CHECK-NEXT:    [[B:%.*]] = tail call { i32, i1 } @llvm.ssub.with.overflow.i32(i32 30, i32 [[A]])
+; CHECK-NEXT:    ret { i32, i1 } [[B]]
+;
+  %a = sub i32 %x, 12
+  %b = tail call { i32, i1 } @llvm.ssub.with.overflow.i32(i32 30, i32 %a)
+  ret { i32, i1 } %b
+}
+
+define { i32, i1 } @fold_add_simple(i32 %x) {
+; CHECK-LABEL: @fold_add_simple(
+; CHECK-NEXT:    [[TMP1:%.*]] = call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 [[X:%.*]], i32 -42)
+; CHECK-NEXT:    ret { i32, i1 } [[TMP1]]
+;
+  %a = add nsw i32 %x, -12
+  %b = tail call { i32, i1 } @llvm.ssub.with.overflow.i32(i32 %a, i32 30)
+  ret { i32, i1 } %b
+}
+
+define { <2 x i32>, <2 x i1> } @keep_ssubo_undef(<2 x i32> %x) {
+; CHECK-LABEL: @keep_ssubo_undef(
+; CHECK-NEXT:    [[A:%.*]] = tail call { <2 x i32>, <2 x i1> } @llvm.ssub.with.overflow.v2i32(<2 x i32> [[X:%.*]], <2 x i32> <i32 30, i32 undef>)
+; CHECK-NEXT:    ret { <2 x i32>, <2 x i1> } [[A]]
+;
+  %a = tail call { <2 x i32>, <2 x i1> } @llvm.ssub.with.overflow.v2i32(<2 x i32> %x, <2 x i32> <i32 30, i32 undef>)
+  ret { <2 x i32>, <2 x i1> } %a
+}
+
+define { <2 x i32>, <2 x i1> } @keep_ssubo_non_splat(<2 x i32> %x) {
+; CHECK-LABEL: @keep_ssubo_non_splat(
+; CHECK-NEXT:    [[TMP1:%.*]] = call { <2 x i32>, <2 x i1> } @llvm.sadd.with.overflow.v2i32(<2 x i32> [[X:%.*]], <2 x i32> <i32 -30, i32 -31>)
+; CHECK-NEXT:    ret { <2 x i32>, <2 x i1> } [[TMP1]]
+;
+  %a = tail call { <2 x i32>, <2 x i1> } @llvm.ssub.with.overflow.v2i32(<2 x i32> %x, <2 x i32> <i32 30, i32 31>)
+  ret { <2 x i32>, <2 x i1> } %a
+}
+
+define { <2 x i8>, <2 x i1> } @keep_ssubo_one_element_is_128(<2 x i8> %x) {
+; CHECK-LABEL: @keep_ssubo_one_element_is_128(
+; CHECK-NEXT:    [[A:%.*]] = tail call { <2 x i8>, <2 x i1> } @llvm.ssub.with.overflow.v2i8(<2 x i8> [[X:%.*]], <2 x i8> <i8 0, i8 -128>)
+; CHECK-NEXT:    ret { <2 x i8>, <2 x i1> } [[A]]
+;
+  %a = tail call { <2 x i8>, <2 x i1> } @llvm.ssub.with.overflow.v2i8(<2 x i8> %x, <2 x i8> <i8 0, i8 -128>)
+  ret { <2 x i8>, <2 x i1> } %a
+}
+
+define { i8, i1 } @keep_ssubo_128(i8 %x) {
+; CHECK-LABEL: @keep_ssubo_128(
+; CHECK-NEXT:    [[A:%.*]] = tail call { i8, i1 } @llvm.ssub.with.overflow.i8(i8 [[X:%.*]], i8 -128)
+; CHECK-NEXT:    ret { i8, i1 } [[A]]
+;
+  %a = tail call { i8, i1 } @llvm.ssub.with.overflow.i8(i8 %x, i8 -128)
+  ret { i8, i1 } %a
+}

Added: llvm/trunk/test/Transforms/InstCombine/stack-overalign.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/stack-overalign.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/stack-overalign.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/stack-overalign.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,31 @@
+; RUN: opt < %s -instcombine -S | grep "align 32" | count 2
+
+; It's tempting to have an instcombine in which the src pointer of a
+; memcpy is aligned up to the alignment of the destination, however
+; there are pitfalls. If the src is an alloca, aligning it beyond what
+; the target's stack pointer is aligned at will require dynamic
+; stack realignment, which can require functions that don't otherwise
+; need a frame pointer to need one.
+;
+; Abstaining from this transform is not the only way to approach this
+; issue. Some late phase could be smart enough to reduce alloca
+; alignments when they are greater than they need to be. Or, codegen
+; could do dynamic alignment for just the one alloca, and leave the
+; main stack pointer at its standard alignment.
+;
+
+
+ at dst = global [1024 x i8] zeroinitializer, align 32
+
+define void @foo() nounwind {
+entry:
+  %src = alloca [1024 x i8], align 1
+  %src1 = getelementptr [1024 x i8], [1024 x i8]* %src, i32 0, i32 0
+  call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 32 getelementptr inbounds ([1024 x i8], [1024 x i8]* @dst, i32 0, i32 0), i8* align 32 %src1, i32 1024, i1 false)
+  call void @frob(i8* %src1) nounwind
+  ret void
+}
+
+declare void @frob(i8*)
+
+declare void @llvm.memcpy.p0i8.p0i8.i32(i8* nocapture, i8* nocapture, i32, i1) nounwind

Added: llvm/trunk/test/Transforms/InstCombine/stacksave-debuginfo.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/stacksave-debuginfo.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/stacksave-debuginfo.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/stacksave-debuginfo.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,47 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; dbg.value instrinsics should not affect peephole combining of stacksave/stackrestore.
+; PR37713
+; RUN: opt -instcombine %s -S | FileCheck %s
+
+declare i8* @llvm.stacksave() #0
+declare void @llvm.stackrestore(i8*) #0
+
+define i32* @test1(i32 %P) !dbg !6 {
+; CHECK-LABEL: @test1(
+; CHECK-NEXT:    [[TMP1:%.*]] = zext i32 [[P:%.*]] to i64, !dbg !12
+; CHECK-NEXT:    [[A:%.*]] = alloca i32, i64 [[TMP1]], align 4, !dbg !12
+; CHECK-NEXT:    call void @llvm.dbg.value(metadata i32* [[A]], metadata !11, metadata !DIExpression()), !dbg !12
+; CHECK-NEXT:    ret i32* [[A]], !dbg !13
+;
+  %tmp = call i8* @llvm.stacksave(), !dbg !12
+  call void @llvm.dbg.value(metadata i8* %tmp, metadata !9, metadata !DIExpression()), !dbg !12
+  call void @llvm.stackrestore(i8* %tmp), !dbg !13
+  %A = alloca i32, i32 %P, !dbg !14
+  call void @llvm.dbg.value(metadata i32* %A, metadata !11, metadata !DIExpression()), !dbg !14
+  ret i32* %A, !dbg !15
+}
+
+declare void @llvm.dbg.value(metadata, metadata, metadata) #1
+attributes #0 = { nounwind }
+attributes #1 = { nounwind readnone speculatable }
+
+!llvm.dbg.cu = !{!0}
+!llvm.debugify = !{!3, !4}
+!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: "patatino.ll", directory: "/")
+!2 = !{}
+!3 = !{i32 4}
+!4 = !{i32 2}
+!5 = !{i32 2, !"Debug Info Version", i32 3}
+!6 = distinct !DISubprogram(name: "test1", linkageName: "test1", scope: null, file: !1, line: 1, type: !7, isLocal: false, isDefinition: true, scopeLine: 1, isOptimized: true, unit: !0, retainedNodes: !8)
+!7 = !DISubroutineType(types: !2)
+!8 = !{!9, !11}
+!9 = !DILocalVariable(name: "1", scope: !6, file: !1, line: 1, type: !10)
+!10 = !DIBasicType(name: "ty64", size: 64, encoding: DW_ATE_unsigned)
+!11 = !DILocalVariable(name: "2", scope: !6, file: !1, line: 3, type: !10)
+!12 = !DILocation(line: 1, column: 1, scope: !6)
+!13 = !DILocation(line: 2, column: 1, scope: !6)
+!14 = !DILocation(line: 3, column: 1, scope: !6)
+!15 = !DILocation(line: 4, column: 1, scope: !6)

Added: llvm/trunk/test/Transforms/InstCombine/stacksaverestore.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/stacksaverestore.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/stacksaverestore.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/stacksaverestore.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,112 @@
+; RUN: opt < %s -instcombine -S | FileCheck %s
+
+ at glob = global i32 0
+
+declare i8* @llvm.stacksave()
+declare void @llvm.stackrestore(i8*)
+
+;; Test that llvm.stackrestore is removed when possible.
+define i32* @test1(i32 %P) {
+	%tmp = call i8* @llvm.stacksave( )
+	call void @llvm.stackrestore( i8* %tmp ) ;; not restoring anything
+	%A = alloca i32, i32 %P		
+	ret i32* %A
+}
+
+; CHECK-LABEL: define i32* @test1(
+; CHECK-NOT: call void @llvm.stackrestore
+; CHECK: ret i32*
+
+define void @test2(i8* %X) {
+	call void @llvm.stackrestore( i8* %X )  ;; no allocas before return.
+	ret void
+}
+
+; CHECK-LABEL: define void @test2(
+; CHECK-NOT: call void @llvm.stackrestore
+; CHECK: ret void
+
+define void @foo(i32 %size) nounwind  {
+entry:
+	%tmp118124 = icmp sgt i32 %size, 0		; <i1> [#uses=1]
+	br i1 %tmp118124, label %bb.preheader, label %return
+
+bb.preheader:		; preds = %entry
+	%tmp25 = add i32 %size, -1		; <i32> [#uses=1]
+	%tmp125 = icmp slt i32 %size, 1		; <i1> [#uses=1]
+	%smax = select i1 %tmp125, i32 1, i32 %size		; <i32> [#uses=1]
+	br label %bb
+
+bb:		; preds = %bb, %bb.preheader
+	%i.0.reg2mem.0 = phi i32 [ 0, %bb.preheader ], [ %indvar.next, %bb ]		; <i32> [#uses=2]
+	%tmp = call i8* @llvm.stacksave( )		; <i8*> [#uses=1]
+	%tmp23 = alloca i8, i32 %size		; <i8*> [#uses=2]
+	%tmp27 = getelementptr i8, i8* %tmp23, i32 %tmp25		; <i8*> [#uses=1]
+	store i8 0, i8* %tmp27, align 1
+	%tmp28 = call i8* @llvm.stacksave( )		; <i8*> [#uses=1]
+	%tmp52 = alloca i8, i32 %size		; <i8*> [#uses=1]
+	%tmp53 = call i8* @llvm.stacksave( )		; <i8*> [#uses=1]
+	%tmp77 = alloca i8, i32 %size		; <i8*> [#uses=1]
+	%tmp78 = call i8* @llvm.stacksave( )		; <i8*> [#uses=1]
+	%tmp102 = alloca i8, i32 %size		; <i8*> [#uses=1]
+	call void @bar( i32 %i.0.reg2mem.0, i8* %tmp23, i8* %tmp52, i8* %tmp77, i8* %tmp102, i32 %size ) nounwind 
+	call void @llvm.stackrestore( i8* %tmp78 )
+	call void @llvm.stackrestore( i8* %tmp53 )
+	call void @llvm.stackrestore( i8* %tmp28 )
+	call void @llvm.stackrestore( i8* %tmp )
+	%indvar.next = add i32 %i.0.reg2mem.0, 1		; <i32> [#uses=2]
+	%exitcond = icmp eq i32 %indvar.next, %smax		; <i1> [#uses=1]
+	br i1 %exitcond, label %return, label %bb
+
+return:		; preds = %bb, %entry
+	ret void
+}
+
+; CHECK-LABEL: define void @foo(
+; CHECK: %tmp = call i8* @llvm.stacksave()
+; CHECK: alloca i8
+; CHECK-NOT: stacksave
+; CHECK: call void @bar(
+; CHECK-NEXT: call void @llvm.stackrestore(i8* %tmp)
+; CHECK: ret void
+
+declare void @bar(i32, i8*, i8*, i8*, i8*, i32)
+
+declare void @inalloca_callee(i32* inalloca)
+
+define void @test3(i32 %c) {
+entry:
+  br label %loop
+
+loop:
+  %i = phi i32 [0, %entry], [%i1, %loop]
+  %save1 = call i8* @llvm.stacksave()
+  %argmem = alloca inalloca i32
+  store i32 0, i32* %argmem
+  call void @inalloca_callee(i32* inalloca %argmem)
+
+  ; This restore cannot be deleted, the restore below does not make it dead.
+  call void @llvm.stackrestore(i8* %save1)
+
+  ; FIXME: We should be able to remove this save/restore pair, but we don't.
+  %save2 = call i8* @llvm.stacksave()
+  store i32 0, i32* @glob
+  call void @llvm.stackrestore(i8* %save2)
+  %i1 = add i32 1, %i
+  %done = icmp eq i32 %i1, %c
+  br i1 %done, label %loop, label %return
+
+return:
+  ret void
+}
+
+; CHECK-LABEL: define void @test3(
+; CHECK: loop:
+; CHECK: %i = phi i32 [ 0, %entry ], [ %i1, %loop ]
+; CHECK: %save1 = call i8* @llvm.stacksave()
+; CHECK: %argmem = alloca inalloca i32
+; CHECK: store i32 0, i32* %argmem
+; CHECK: call void @inalloca_callee(i32* inalloca {{.*}} %argmem)
+; CHECK: call void @llvm.stackrestore(i8* %save1)
+; CHECK: br i1 %done, label %loop, label %return
+; CHECK: ret void

Added: llvm/trunk/test/Transforms/InstCombine/statepoint.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/statepoint.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/statepoint.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/statepoint.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,52 @@
+; RUN: opt < %s -instcombine -S | FileCheck %s
+; These tests check the optimizations specific to
+; pointers being relocated at a statepoint.
+
+
+declare void @func()
+
+define i1 @test_negative(i32 addrspace(1)* %p) gc "statepoint-example" {
+entry:
+  %safepoint_token = tail call token (i64, i32, void ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_isVoidf(i64 0, i32 0, void ()* @func, i32 0, i32 0, i32 0, i32 0, i32 addrspace(1)* %p)
+  %pnew = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token %safepoint_token,  i32 7, i32 7)
+  %cmp = icmp eq i32 addrspace(1)* %pnew, null
+  ret i1 %cmp
+; CHECK-LABEL: test_negative
+; CHECK: %pnew = call i32 addrspace(1)*
+; CHECK: ret i1 %cmp
+}
+
+define i1 @test_nonnull(i32 addrspace(1)* nonnull %p) gc "statepoint-example" {
+entry:
+  %safepoint_token = tail call token (i64, i32, void ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_isVoidf(i64 0, i32 0, void ()* @func, i32 0, i32 0, i32 0, i32 0, i32 addrspace(1)* %p)
+  %pnew = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token %safepoint_token,  i32 7, i32 7)
+  %cmp = icmp eq i32 addrspace(1)* %pnew, null
+  ret i1 %cmp
+; CHECK-LABEL: test_nonnull
+; CHECK: ret i1 false
+}
+
+define i1 @test_null() gc "statepoint-example" {
+entry:
+  %safepoint_token = tail call token (i64, i32, void ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_isVoidf(i64 0, i32 0, void ()* @func, i32 0, i32 0, i32 0, i32 0, i32 addrspace(1)* null)
+  %pnew = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token %safepoint_token,  i32 7, i32 7)
+  %cmp = icmp eq i32 addrspace(1)* %pnew, null
+  ret i1 %cmp
+; CHECK-LABEL: test_null
+; CHECK-NOT: %pnew
+; CHECK: ret i1 true
+}
+
+define i1 @test_undef() gc "statepoint-example" {
+entry:
+  %safepoint_token = tail call token (i64, i32, void ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_isVoidf(i64 0, i32 0, void ()* @func, i32 0, i32 0, i32 0, i32 0, i32 addrspace(1)* undef)
+  %pnew = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token %safepoint_token,  i32 7, i32 7)
+  %cmp = icmp eq i32 addrspace(1)* %pnew, null
+  ret i1 %cmp
+; CHECK-LABEL: test_undef
+; CHECK-NOT: %pnew
+; CHECK: ret i1 undef
+}
+
+declare token @llvm.experimental.gc.statepoint.p0f_isVoidf(i64, i32, void ()*, i32, i32, ...)
+declare i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token, i32, i32) #3

Added: llvm/trunk/test/Transforms/InstCombine/store-load-unaliased-gep.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/store-load-unaliased-gep.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/store-load-unaliased-gep.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/store-load-unaliased-gep.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,23 @@
+; RUN: opt -instcombine %s -S 2>&1 | FileCheck %s
+; RUN: opt -aa-pipeline=basic-aa -passes=instcombine %s -S 2>&1 | FileCheck %s
+
+; Checking successful store-load optimization of array length.
+; Function below should deduce just to "return length".
+; Doable only if instcombine has access to alias-analysis.
+
+define i32 @test1(i32 %length) {
+; CHECK-LABEL: entry:
+entry:
+  %array = alloca i32, i32 2
+  ; CHECK-NOT: %array
+
+  %length_gep = getelementptr inbounds i32, i32 * %array, i32 0
+  %value_gep = getelementptr inbounds i32, i32 * %array, i32 1
+  store i32 %length, i32 * %length_gep
+  store i32 0, i32 * %value_gep
+  %loaded_length = load i32, i32 * %length_gep
+  ; CHECK-NOT: %loaded_length = load i32
+
+  ret i32 %loaded_length
+  ; CHECK: ret i32 %length
+}

Added: llvm/trunk/test/Transforms/InstCombine/store.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/store.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/store.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/store.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,309 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt < %s -instcombine -S | FileCheck %s
+
+define void @test1(i32* %P) {
+; CHECK-LABEL: @test1(
+; CHECK-NEXT:    store i32 123, i32* undef, align 4
+; CHECK-NEXT:    store i32 undef, i32* null, align 536870912
+; CHECK-NEXT:    ret void
+;
+  store i32 undef, i32* %P
+  store i32 123, i32* undef
+  store i32 124, i32* null
+  ret void
+}
+
+define void @test2(i32* %P) {
+; CHECK-LABEL: @test2(
+; CHECK-NEXT:    ret void
+;
+  %X = load i32, i32* %P
+  %Y = add i32 %X, 0
+  store i32 %Y, i32* %P
+  ret void
+}
+
+define void @store_at_gep_off_null(i64 %offset) {
+; CHECK-LABEL: @store_at_gep_off_null(
+; CHECK-NEXT:    [[PTR:%.*]] = getelementptr i32, i32* null, i64 [[OFFSET:%.*]]
+; CHECK-NEXT:    store i32 undef, i32* [[PTR]], align 4
+; CHECK-NEXT:    ret void
+;
+  %ptr = getelementptr i32, i32 *null, i64 %offset
+  store i32 24, i32* %ptr
+  ret void
+}
+
+define void @store_at_gep_off_no_null_opt(i64 %offset) #0 {
+; CHECK-LABEL: @store_at_gep_off_no_null_opt(
+; CHECK-NEXT:    [[PTR:%.*]] = getelementptr i32, i32* null, i64 [[OFFSET:%.*]]
+; CHECK-NEXT:    store i32 24, i32* [[PTR]], align 4
+; CHECK-NEXT:    ret void
+;
+  %ptr = getelementptr i32, i32 *null, i64 %offset
+  store i32 24, i32* %ptr
+  ret void
+}
+
+attributes #0 = { "null-pointer-is-valid"="true" }
+
+;; Simple sinking tests
+
+; "if then else"
+define i32 @test3(i1 %C) {
+; CHECK-LABEL: @test3(
+; CHECK-NEXT:    br i1 [[C:%.*]], label [[COND:%.*]], label [[COND2:%.*]]
+; CHECK:       Cond:
+; CHECK-NEXT:    br label [[CONT:%.*]]
+; CHECK:       Cond2:
+; CHECK-NEXT:    br label [[CONT]]
+; CHECK:       Cont:
+; CHECK-NEXT:    [[STOREMERGE:%.*]] = phi i32 [ -987654321, [[COND]] ], [ 47, [[COND2]] ]
+; CHECK-NEXT:    ret i32 [[STOREMERGE]]
+;
+  %A = alloca i32
+  br i1 %C, label %Cond, label %Cond2
+
+Cond:
+  store i32 -987654321, i32* %A
+  br label %Cont
+
+Cond2:
+  store i32 47, i32* %A
+  br label %Cont
+
+Cont:
+  %V = load i32, i32* %A
+  ret i32 %V
+}
+
+; "if then"
+define i32 @test4(i1 %C) {
+; CHECK-LABEL: @test4(
+; CHECK-NEXT:    br i1 [[C:%.*]], label [[COND:%.*]], label [[CONT:%.*]]
+; CHECK:       Cond:
+; CHECK-NEXT:    br label [[CONT]]
+; CHECK:       Cont:
+; CHECK-NEXT:    [[STOREMERGE:%.*]] = phi i32 [ -987654321, [[COND]] ], [ 47, [[TMP0:%.*]] ]
+; CHECK-NEXT:    ret i32 [[STOREMERGE]]
+;
+  %A = alloca i32
+  store i32 47, i32* %A
+  br i1 %C, label %Cond, label %Cont
+
+Cond:
+  store i32 -987654321, i32* %A
+  br label %Cont
+
+Cont:
+  %V = load i32, i32* %A
+  ret i32 %V
+}
+
+; "if then"
+define void @test5(i1 %C, i32* %P) {
+; CHECK-LABEL: @test5(
+; CHECK-NEXT:    br i1 [[C:%.*]], label [[COND:%.*]], label [[CONT:%.*]]
+; CHECK:       Cond:
+; CHECK-NEXT:    br label [[CONT]]
+; CHECK:       Cont:
+; CHECK-NEXT:    [[STOREMERGE:%.*]] = phi i32 [ -987654321, [[COND]] ], [ 47, [[TMP0:%.*]] ]
+; CHECK-NEXT:    store i32 [[STOREMERGE]], i32* [[P:%.*]], align 1
+; CHECK-NEXT:    ret void
+;
+  store i32 47, i32* %P, align 1
+  br i1 %C, label %Cond, label %Cont
+
+Cond:
+  store i32 -987654321, i32* %P, align 1
+  br label %Cont
+
+Cont:
+  ret void
+}
+
+
+; PR14753 - merging two stores should preserve the TBAA tag.
+define void @test6(i32 %n, float* %a, i32* %gi) nounwind uwtable ssp {
+; CHECK-LABEL: @test6(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    br label [[FOR_COND:%.*]]
+; CHECK:       for.cond:
+; CHECK-NEXT:    [[STOREMERGE:%.*]] = phi i32 [ 42, [[ENTRY:%.*]] ], [ [[INC:%.*]], [[FOR_BODY:%.*]] ]
+; CHECK-NEXT:    store i32 [[STOREMERGE]], i32* [[GI:%.*]], align 4, !tbaa !0
+; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i32 [[STOREMERGE]], [[N:%.*]]
+; CHECK-NEXT:    br i1 [[CMP]], label [[FOR_BODY]], label [[FOR_END:%.*]]
+; CHECK:       for.body:
+; CHECK-NEXT:    [[IDXPROM:%.*]] = sext i32 [[STOREMERGE]] to i64
+; CHECK-NEXT:    [[ARRAYIDX:%.*]] = getelementptr inbounds float, float* [[A:%.*]], i64 [[IDXPROM]]
+; CHECK-NEXT:    store float 0.000000e+00, float* [[ARRAYIDX]], align 4, !tbaa !4
+; CHECK-NEXT:    [[TMP0:%.*]] = load i32, i32* [[GI]], align 4, !tbaa !0
+; CHECK-NEXT:    [[INC]] = add nsw i32 [[TMP0]], 1
+; CHECK-NEXT:    br label [[FOR_COND]]
+; CHECK:       for.end:
+; CHECK-NEXT:    ret void
+;
+entry:
+  store i32 42, i32* %gi, align 4, !tbaa !0
+  br label %for.cond
+
+for.cond:
+  %storemerge = phi i32 [ 0, %entry ], [ %inc, %for.body ]
+  %0 = load i32, i32* %gi, align 4, !tbaa !0
+  %cmp = icmp slt i32 %0, %n
+  br i1 %cmp, label %for.body, label %for.end
+
+for.body:
+  %idxprom = sext i32 %0 to i64
+  %arrayidx = getelementptr inbounds float, float* %a, i64 %idxprom
+  store float 0.000000e+00, float* %arrayidx, align 4, !tbaa !3
+  %1 = load i32, i32* %gi, align 4, !tbaa !0
+  %inc = add nsw i32 %1, 1
+  store i32 %inc, i32* %gi, align 4, !tbaa !0
+  br label %for.cond
+
+for.end:
+  ret void
+}
+
+define void @dse1(i32* %p) {
+; CHECK-LABEL: @dse1(
+; CHECK-NEXT:    store i32 0, i32* [[P:%.*]], align 4
+; CHECK-NEXT:    ret void
+;
+  store i32 0, i32* %p
+  store i32 0, i32* %p
+  ret void
+}
+
+; Slightly subtle: if we're mixing atomic and non-atomic access to the
+; same location, then the contents of the location are undefined if there's
+; an actual race.  As such, we're free to pick either store under the
+; assumption that we're not racing with any other thread.
+define void @dse2(i32* %p) {
+; CHECK-LABEL: @dse2(
+; CHECK-NEXT:    store i32 0, i32* [[P:%.*]], align 4
+; CHECK-NEXT:    ret void
+;
+  store atomic i32 0, i32* %p unordered, align 4
+  store i32 0, i32* %p
+  ret void
+}
+
+define void @dse3(i32* %p) {
+; CHECK-LABEL: @dse3(
+; CHECK-NEXT:    store atomic i32 0, i32* [[P:%.*]] unordered, align 4
+; CHECK-NEXT:    ret void
+;
+  store i32 0, i32* %p
+  store atomic i32 0, i32* %p unordered, align 4
+  ret void
+}
+
+define void @dse4(i32* %p) {
+; CHECK-LABEL: @dse4(
+; CHECK-NEXT:    store atomic i32 0, i32* [[P:%.*]] unordered, align 4
+; CHECK-NEXT:    ret void
+;
+  store atomic i32 0, i32* %p unordered, align 4
+  store atomic i32 0, i32* %p unordered, align 4
+  ret void
+}
+
+; Implementation limit - could remove unordered store here, but
+; currently don't.
+define void @dse5(i32* %p) {
+; CHECK-LABEL: @dse5(
+; CHECK-NEXT:    store atomic i32 0, i32* [[P:%.*]] unordered, align 4
+; CHECK-NEXT:    store atomic i32 0, i32* [[P]] seq_cst, align 4
+; CHECK-NEXT:    ret void
+;
+  store atomic i32 0, i32* %p unordered, align 4
+  store atomic i32 0, i32* %p seq_cst, align 4
+  ret void
+}
+
+define void @write_back1(i32* %p) {
+; CHECK-LABEL: @write_back1(
+; CHECK-NEXT:    ret void
+;
+  %v = load i32, i32* %p
+  store i32 %v, i32* %p
+  ret void
+}
+
+define void @write_back2(i32* %p) {
+; CHECK-LABEL: @write_back2(
+; CHECK-NEXT:    ret void
+;
+  %v = load atomic i32, i32* %p unordered, align 4
+  store i32 %v, i32* %p
+  ret void
+}
+
+define void @write_back3(i32* %p) {
+; CHECK-LABEL: @write_back3(
+; CHECK-NEXT:    ret void
+;
+  %v = load i32, i32* %p
+  store atomic i32 %v, i32* %p unordered, align 4
+  ret void
+}
+
+define void @write_back4(i32* %p) {
+; CHECK-LABEL: @write_back4(
+; CHECK-NEXT:    ret void
+;
+  %v = load atomic i32, i32* %p unordered, align 4
+  store atomic i32 %v, i32* %p unordered, align 4
+  ret void
+}
+
+; Can't remove store due to ordering side effect
+define void @write_back5(i32* %p) {
+; CHECK-LABEL: @write_back5(
+; CHECK-NEXT:    [[V:%.*]] = load atomic i32, i32* [[P:%.*]] unordered, align 4
+; CHECK-NEXT:    store atomic i32 [[V]], i32* [[P]] seq_cst, align 4
+; CHECK-NEXT:    ret void
+;
+  %v = load atomic i32, i32* %p unordered, align 4
+  store atomic i32 %v, i32* %p seq_cst, align 4
+  ret void
+}
+
+define void @write_back6(i32* %p) {
+; CHECK-LABEL: @write_back6(
+; CHECK-NEXT:    [[V:%.*]] = load atomic i32, i32* [[P:%.*]] seq_cst, align 4
+; CHECK-NEXT:    ret void
+;
+  %v = load atomic i32, i32* %p seq_cst, align 4
+  store atomic i32 %v, i32* %p unordered, align 4
+  ret void
+}
+
+define void @write_back7(i32* %p) {
+; CHECK-LABEL: @write_back7(
+; CHECK-NEXT:    [[V:%.*]] = load atomic volatile i32, i32* [[P:%.*]] seq_cst, align 4
+; CHECK-NEXT:    ret void
+;
+  %v = load atomic volatile i32, i32* %p seq_cst, align 4
+  store atomic i32 %v, i32* %p unordered, align 4
+  ret void
+}
+
+ at Unknown = external constant i32
+
+define void @store_to_constant() {
+; CHECK-LABEL: @store_to_constant(
+; CHECK-NEXT:    store i32 0, i32* @Unknown, align 4
+; CHECK-NEXT:    ret void
+;
+  store i32 0, i32* @Unknown
+  ret void
+}
+
+!0 = !{!4, !4, i64 0}
+!1 = !{!"omnipotent char", !2}
+!2 = !{!"Simple C/C++ TBAA"}
+!3 = !{!"float", !1}
+!4 = !{!"int", !1}

Added: llvm/trunk/test/Transforms/InstCombine/storemerge-dbg.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/storemerge-dbg.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/storemerge-dbg.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/storemerge-dbg.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,26 @@
+; RUN: opt < %s -debugify -instcombine -S | FileCheck %s
+
+declare i32 @escape(i32)
+
+; CHECK-LABEL: define {{.*}}@foo(
+define i32 @foo() {
+entry:
+  %baz = alloca i32
+  br i1 undef, label %lhs, label %rhs
+
+lhs:
+  store i32 1, i32* %baz
+  br label %cleanup
+
+rhs:
+  store i32 2, i32* %baz
+  br label %cleanup
+
+cleanup:
+  ; CHECK: %storemerge = phi i32 [ 1, %lhs ], [ 2, %rhs ], !dbg [[merge_loc:![0-9]+]]
+  %baz.val = load i32, i32* %baz
+  %ret.val = call i32 @escape(i32 %baz.val)
+  ret i32 %ret.val
+}
+
+; CHECK: [[merge_loc]] = !DILocation(line: 0

Added: llvm/trunk/test/Transforms/InstCombine/stpcpy-1.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/stpcpy-1.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/stpcpy-1.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/stpcpy-1.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,46 @@
+; Test that the stpcpy library call simplifier works correctly.
+; RUN: opt < %s -instcombine -S | FileCheck %s
+;
+; This transformation requires the pointer size, as it assumes that size_t is
+; the size of a pointer.
+target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:128:128-n8:16:32"
+
+ at hello = constant [6 x i8] c"hello\00"
+ at a = common global [32 x i8] zeroinitializer, align 1
+ at b = common global [32 x i8] zeroinitializer, align 1
+
+declare i8* @stpcpy(i8*, i8*)
+
+define i8* @test_simplify1() {
+; CHECK-LABEL: @test_simplify1(
+
+  %dst = getelementptr [32 x i8], [32 x i8]* @a, i32 0, i32 0
+  %src = getelementptr [6 x i8], [6 x i8]* @hello, i32 0, i32 0
+
+  %ret = call i8* @stpcpy(i8* %dst, i8* %src)
+; CHECK: @llvm.memcpy.p0i8.p0i8.i32
+; CHECK-NEXT: getelementptr inbounds ([32 x i8], [32 x i8]* @a, i32 0, i32 5)
+  ret i8* %ret
+}
+
+define i8* @test_simplify2() {
+; CHECK-LABEL: @test_simplify2(
+
+  %dst = getelementptr [32 x i8], [32 x i8]* @a, i32 0, i32 0
+
+  %ret = call i8* @stpcpy(i8* %dst, i8* %dst)
+; CHECK: [[LEN:%[a-z]+]] = call i32 @strlen
+; CHECK-NEXT: getelementptr inbounds [32 x i8], [32 x i8]* @a, i32 0, i32 [[LEN]]
+  ret i8* %ret
+}
+
+define i8* @test_no_simplify1() {
+; CHECK-LABEL: @test_no_simplify1(
+
+  %dst = getelementptr [32 x i8], [32 x i8]* @a, i32 0, i32 0
+  %src = getelementptr [32 x i8], [32 x i8]* @b, i32 0, i32 0
+
+  %ret = call i8* @stpcpy(i8* %dst, i8* %src)
+; CHECK: call i8* @stpcpy
+  ret i8* %ret
+}

Added: llvm/trunk/test/Transforms/InstCombine/stpcpy-2.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/stpcpy-2.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/stpcpy-2.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/stpcpy-2.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,22 @@
+; Test that the stpcpy library call simplifier works correctly.
+; RUN: opt < %s -instcombine -S | FileCheck %s
+;
+; This transformation requires the pointer size, as it assumes that size_t is
+; the size of a pointer.
+target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:128:128-n8:16:32"
+
+ at hello = constant [6 x i8] c"hello\00"
+ at a = common global [32 x i8] zeroinitializer, align 1
+
+declare i16* @stpcpy(i8*, i8*)
+
+define void @test_no_simplify1() {
+; CHECK-LABEL: @test_no_simplify1(
+
+  %dst = getelementptr [32 x i8], [32 x i8]* @a, i32 0, i32 0
+  %src = getelementptr [6 x i8], [6 x i8]* @hello, i32 0, i32 0
+
+  call i16* @stpcpy(i8* %dst, i8* %src)
+; CHECK: call i16* @stpcpy
+  ret void
+}

Added: llvm/trunk/test/Transforms/InstCombine/stpcpy_chk-1.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/stpcpy_chk-1.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/stpcpy_chk-1.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/stpcpy_chk-1.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,103 @@
+; Test lib call simplification of __stpcpy_chk calls with various values
+; for src, dst, and slen.
+;
+; 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"
+
+ at a = common global [60 x i8] zeroinitializer, align 1
+ at b = common global [60 x i8] zeroinitializer, align 1
+ at .str = private constant [12 x i8] c"abcdefghijk\00"
+
+; Check cases where slen >= strlen (src).
+
+define i8* @test_simplify1() {
+; CHECK-LABEL: @test_simplify1(
+  %dst = getelementptr inbounds [60 x i8], [60 x i8]* @a, i32 0, i32 0
+  %src = getelementptr inbounds [12 x i8], [12 x i8]* @.str, i32 0, i32 0
+
+; CHECK-NEXT: call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 1 getelementptr inbounds ([60 x i8], [60 x i8]* @a, i32 0, i32 0), i8* align 1 getelementptr inbounds ([12 x i8], [12 x i8]* @.str, i32 0, i32 0), i32 12, i1 false)
+; CHECK-NEXT: ret i8* getelementptr inbounds ([60 x i8], [60 x i8]* @a, i32 0, i32 11)
+  %ret = call i8* @__stpcpy_chk(i8* %dst, i8* %src, i32 60)
+  ret i8* %ret
+}
+
+define i8* @test_simplify2() {
+; CHECK-LABEL: @test_simplify2(
+  %dst = getelementptr inbounds [60 x i8], [60 x i8]* @a, i32 0, i32 0
+  %src = getelementptr inbounds [12 x i8], [12 x i8]* @.str, i32 0, i32 0
+
+; CHECK-NEXT: call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 1 getelementptr inbounds ([60 x i8], [60 x i8]* @a, i32 0, i32 0), i8* align 1 getelementptr inbounds ([12 x i8], [12 x i8]* @.str, i32 0, i32 0), i32 12, i1 false)
+; CHECK-NEXT: ret i8* getelementptr inbounds ([60 x i8], [60 x i8]* @a, i32 0, i32 11)
+  %ret = call i8* @__stpcpy_chk(i8* %dst, i8* %src, i32 12)
+  ret i8* %ret
+}
+
+define i8* @test_simplify3() {
+; CHECK-LABEL: @test_simplify3(
+  %dst = getelementptr inbounds [60 x i8], [60 x i8]* @a, i32 0, i32 0
+  %src = getelementptr inbounds [12 x i8], [12 x i8]* @.str, i32 0, i32 0
+
+; CHECK-NEXT: call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 1 getelementptr inbounds ([60 x i8], [60 x i8]* @a, i32 0, i32 0), i8* align 1 getelementptr inbounds ([12 x i8], [12 x i8]* @.str, i32 0, i32 0), i32 12, i1 false)
+; CHECK-NEXT: ret i8* getelementptr inbounds ([60 x i8], [60 x i8]* @a, i32 0, i32 11)
+  %ret = call i8* @__stpcpy_chk(i8* %dst, i8* %src, i32 -1)
+  ret i8* %ret
+}
+
+; Check cases where there are no string constants.
+
+define i8* @test_simplify4() {
+; CHECK-LABEL: @test_simplify4(
+  %dst = getelementptr inbounds [60 x i8], [60 x i8]* @a, i32 0, i32 0
+  %src = getelementptr inbounds [60 x i8], [60 x i8]* @b, i32 0, i32 0
+
+; CHECK-NEXT: %stpcpy = call i8* @stpcpy(i8* getelementptr inbounds ([60 x i8], [60 x i8]* @a, i32 0, i32 0), i8* getelementptr inbounds ([60 x i8], [60 x i8]* @b, i32 0, i32 0))
+; CHECK-NEXT: ret i8* %stpcpy
+  %ret = call i8* @__stpcpy_chk(i8* %dst, i8* %src, i32 -1)
+  ret i8* %ret
+}
+
+; Check case where the string length is not constant.
+
+define i8* @test_simplify5() {
+; CHECK-LABEL: @test_simplify5(
+  %dst = getelementptr inbounds [60 x i8], [60 x i8]* @a, i32 0, i32 0
+  %src = getelementptr inbounds [12 x i8], [12 x i8]* @.str, i32 0, i32 0
+
+; CHECK-NEXT: %len = call i32 @llvm.objectsize.i32.p0i8(i8* getelementptr inbounds ([60 x i8], [60 x i8]* @a, i32 0, i32 0), i1 false, i1 false, i1 false)
+; CHECK-NEXT: %1 = call i8* @__memcpy_chk(i8* getelementptr inbounds ([60 x i8], [60 x i8]* @a, i32 0, i32 0), i8* getelementptr inbounds ([12 x i8], [12 x i8]* @.str, i32 0, i32 0), i32 12, i32 %len)
+; CHECK-NEXT: ret i8* getelementptr inbounds ([60 x i8], [60 x i8]* @a, i32 0, i32 11)
+  %len = call i32 @llvm.objectsize.i32.p0i8(i8* %dst, i1 false, i1 false, i1 false)
+  %ret = call i8* @__stpcpy_chk(i8* %dst, i8* %src, i32 %len)
+  ret i8* %ret
+}
+
+; Check case where the source and destination are the same.
+
+define i8* @test_simplify6() {
+; CHECK-LABEL: @test_simplify6(
+  %dst = getelementptr inbounds [60 x i8], [60 x i8]* @a, i32 0, i32 0
+
+; CHECK-NEXT: %strlen = call i32 @strlen(i8* getelementptr inbounds ([60 x i8], [60 x i8]* @a, i32 0, i32 0))
+; CHECK-NEXT: %1 = getelementptr inbounds [60 x i8], [60 x i8]* @a, i32 0, i32 %strlen
+; CHECK-NEXT: ret i8* %1
+  %len = call i32 @llvm.objectsize.i32.p0i8(i8* %dst, i1 false, i1 false, i1 false)
+  %ret = call i8* @__stpcpy_chk(i8* %dst, i8* %dst, i32 %len)
+  ret i8* %ret
+}
+
+; Check case where slen < strlen (src).
+
+define i8* @test_no_simplify1() {
+; CHECK-LABEL: @test_no_simplify1(
+  %dst = getelementptr inbounds [60 x i8], [60 x i8]* @a, i32 0, i32 0
+  %src = getelementptr inbounds [60 x i8], [60 x i8]* @b, i32 0, i32 0
+
+; CHECK-NEXT: %ret = call i8* @__stpcpy_chk(i8* getelementptr inbounds ([60 x i8], [60 x i8]* @a, i32 0, i32 0), i8* getelementptr inbounds ([60 x i8], [60 x i8]* @b, i32 0, i32 0), i32 8)
+; CHECK-NEXT: ret i8* %ret
+  %ret = call i8* @__stpcpy_chk(i8* %dst, i8* %src, i32 8)
+  ret i8* %ret
+}
+
+declare i8* @__stpcpy_chk(i8*, i8*, i32) nounwind
+declare i32 @llvm.objectsize.i32.p0i8(i8*, i1, i1, i1) nounwind readonly

Added: llvm/trunk/test/Transforms/InstCombine/stpcpy_chk-2.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/stpcpy_chk-2.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/stpcpy_chk-2.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/stpcpy_chk-2.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,21 @@
+; Test that lib call simplification doesn't simplify __stpcpy_chk calls
+; with the wrong prototype.
+;
+; 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"
+
+ at a = common global [60 x i16] zeroinitializer, align 1
+ at .str = private constant [8 x i8] c"abcdefg\00"
+
+define void @test_no_simplify() {
+; CHECK-LABEL: @test_no_simplify(
+  %dst = getelementptr inbounds [60 x i16], [60 x i16]* @a, i32 0, i32 0
+  %src = getelementptr inbounds [8 x i8], [8 x i8]* @.str, i32 0, i32 0
+
+; CHECK-NEXT: call i16* @__strcpy_chk
+  call i16* @__strcpy_chk(i16* %dst, i8* %src, i32 8)
+  ret void
+}
+
+declare i16* @__strcpy_chk(i16*, i8*, i32)

Added: llvm/trunk/test/Transforms/InstCombine/str-int-2.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/str-int-2.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/str-int-2.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/str-int-2.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
+
+ at .str = private unnamed_addr constant [3 x i8] c"12\00", align 1
+ at .str.1 = private unnamed_addr constant [2 x i8] c"0\00", align 1
+ at .str.2 = private unnamed_addr constant [11 x i8] c"4294967296\00", align 1
+ at .str.3 = private unnamed_addr constant [24 x i8] c"10000000000000000000000\00", align 1
+ at .str.4 = private unnamed_addr constant [20 x i8] c"9923372036854775807\00", align 1
+ at .str.5 = private unnamed_addr constant [11 x i8] c"4994967295\00", align 1
+ at .str.6 = private unnamed_addr constant [10 x i8] c"499496729\00", align 1
+ at .str.7 = private unnamed_addr constant [11 x i8] c"4994967295\00", align 1
+
+declare i64 @strtol(i8*, i8**, i32)
+declare i32 @atoi(i8*)
+declare i64 @atol(i8*)
+declare i64 @atoll(i8*)
+declare i64 @strtoll(i8*, i8**, i32)
+
+define i64 @strtol_dec() #0 {
+; CHECK-LABEL: @strtol_dec(
+; CHECK-NEXT:    ret i64 12
+;
+  %call = call i64 @strtol(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @.str, i32 0, i32 0), i8** null, i32 10) #2
+  ret i64 %call
+}
+
+define i64 @strtol_base_zero() #0 {
+; CHECK-LABEL: @strtol_base_zero(
+; CHECK-NEXT:    ret i64 12
+;
+  %call = call i64 @strtol(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @.str, i32 0, i32 0), i8** null, i32 0) #2
+  ret i64 %call
+}
+
+define i64 @strtol_hex() #0 {
+; CHECK-LABEL: @strtol_hex(
+; CHECK-NEXT:    ret i64 18
+;
+  %call = call i64 @strtol(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @.str, i32 0, i32 0), i8** null, i32 16) #2
+  ret i64 %call
+}
+
+define i64 @strtol_endptr_not_null() #0 {
+; CHECK-LABEL: @strtol_endptr_not_null(
+; CHECK-NEXT:    [[END:%.*]] = alloca i8*, align 4
+; CHECK-NEXT:    [[CALL:%.*]] = call i64 @strtol(i8* getelementptr inbounds ([2 x i8], [2 x i8]* @.str.1, i64 0, i64 0), i8** nonnull [[END]], i32 10)
+; CHECK-NEXT:    ret i64 [[CALL]]
+;
+  %end = alloca i8*, align 4
+  %call = call i64 @strtol(i8* getelementptr inbounds ([2 x i8], [2 x i8]* @.str.1, i32 0, i32 0), i8** %end, i32 10) #2
+  ret i64 %call
+}
+
+define i32 @atoi_test() #0 {
+; CHECK-LABEL: @atoi_test(
+; CHECK-NEXT:    ret i32 12
+;
+  %call = call i32 @atoi(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @.str, i32 0, i32 0)) #4
+  ret i32 %call
+}
+
+define i64 @strtol_not_const_str(i8* %s) #0 {
+; CHECK-LABEL: @strtol_not_const_str(
+; CHECK-NEXT:    [[CALL:%.*]] = call i64 @strtol(i8* nocapture [[S:%.*]], i8** null, i32 10)
+; CHECK-NEXT:    ret i64 [[CALL]]
+;
+  %call = call i64 @strtol(i8* %s, i8** null, i32 10) #3
+  ret i64 %call
+}
+
+define i32 @atoi_not_const_str(i8* %s) #0 {
+; CHECK-LABEL: @atoi_not_const_str(
+; CHECK-NEXT:    [[CALL:%.*]] = call i32 @atoi(i8* [[S:%.*]])
+; CHECK-NEXT:    ret i32 [[CALL]]
+;
+  %call = call i32 @atoi(i8* %s) #4
+  ret i32 %call
+}
+
+define i64 @strtol_not_const_base(i32 %b) #0 {
+; CHECK-LABEL: @strtol_not_const_base(
+; CHECK-NEXT:    [[CALL:%.*]] = call i64 @strtol(i8* nocapture getelementptr inbounds ([3 x i8], [3 x i8]* @.str, i64 0, i64 0), i8** null, i32 [[B:%.*]])
+; CHECK-NEXT:    ret i64 [[CALL]]
+;
+  %call = call i64 @strtol(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @.str, i32 0, i32 0), i8** null, i32 %b) #2
+  ret i64 %call
+}
+
+define i64 @strtol_long_int() #0 {
+; CHECK-LABEL: @strtol_long_int(
+; CHECK-NEXT:    ret i64 4294967296
+;
+  %call = call i64 @strtol(i8* getelementptr inbounds ([11 x i8], [11 x i8]* @.str.2, i32 0, i32 0), i8** null, i32 10) #3
+  ret i64 %call
+}
+
+
+define i64 @strtol_big_overflow() #0 {
+; CHECK-LABEL: @strtol_big_overflow(
+; CHECK-NEXT:    [[CALL:%.*]] = call i64 @strtol(i8* nocapture getelementptr inbounds ([24 x i8], [24 x i8]* @.str.3, i64 0, i64 0), i8** null, i32 10)
+; CHECK-NEXT:    ret i64 [[CALL]]
+;
+  %call = call i64 @strtol(i8* nocapture getelementptr inbounds ([24 x i8], [24 x i8]* @.str.3, i64 0, i64 0), i8** null, i32 10) #2
+  ret i64 %call
+}
+
+define i64 @atol_test() #0 {
+; CHECK-LABEL: @atol_test(
+; CHECK-NEXT:    ret i64 499496729
+;
+; CHECK-NEXT
+  %call = call i64 @atol(i8* getelementptr inbounds ([10 x i8], [10 x i8]* @.str.6, i32 0, i32 0)) #4
+  ret i64 %call
+}
+
+define i64 @atoll_test() #0 {
+; CHECK-LABEL: @atoll_test(
+; CHECK-NEXT:    ret i64 4994967295
+;
+  %call = call i64 @atoll(i8* getelementptr inbounds ([11 x i8], [11 x i8]* @.str.5, i32 0, i32 0)) #3
+  ret i64 %call
+}
+
+define i64 @strtoll_test() #0 {
+; CHECK-LABEL: @strtoll_test(
+; CHECK-NEXT:    ret i64 4994967295
+;
+; CHECK-NEXT
+  %call = call i64 @strtoll(i8* getelementptr inbounds ([11 x i8], [11 x i8]* @.str.7, i32 0, i32 0), i8** null, i32 10) #5
+  ret i64 %call
+}

Added: llvm/trunk/test/Transforms/InstCombine/str-int.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/str-int.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/str-int.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/str-int.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,134 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt < %s -instcombine -S | FileCheck %s
+
+ at .str = private unnamed_addr constant [3 x i8] c"12\00", align 1
+ at .str.1 = private unnamed_addr constant [2 x i8] c"0\00", align 1
+ at .str.2 = private unnamed_addr constant [11 x i8] c"4294967296\00", align 1
+ at .str.3 = private unnamed_addr constant [24 x i8] c"10000000000000000000000\00", align 1
+ at .str.4 = private unnamed_addr constant [20 x i8] c"9923372036854775807\00", align 1
+ at .str.5 = private unnamed_addr constant [11 x i8] c"4994967295\00", align 1
+ at .str.6 = private unnamed_addr constant [10 x i8] c"499496729\00", align 1
+ at .str.7 = private unnamed_addr constant [11 x i8] c"4994967295\00", align 1
+
+declare i32 @strtol(i8*, i8**, i32)
+declare i32 @atoi(i8*)
+declare i32 @atol(i8*)
+declare i32 @atoll(i8*)
+declare i32 @strtoll(i8*, i8**, i32)
+
+define i32 @strtol_dec() #0 {
+; CHECK-LABEL: @strtol_dec(
+; CHECK-NEXT:    ret i32 12
+;
+  %call = call i32 @strtol(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @.str, i32 0, i32 0), i8** null, i32 10) #2
+  ret i32 %call
+}
+
+define i32 @strtol_base_zero() #0 {
+; CHECK-LABEL: @strtol_base_zero(
+; CHECK-NEXT:    ret i32 12
+;
+  %call = call i32 @strtol(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @.str, i32 0, i32 0), i8** null, i32 0) #2
+  ret i32 %call
+}
+
+define i32 @strtol_hex() #0 {
+; CHECK-LABEL: @strtol_hex(
+; CHECK-NEXT:    ret i32 18
+;
+  %call = call i32 @strtol(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @.str, i32 0, i32 0), i8** null, i32 16) #2
+  ret i32 %call
+}
+
+define i32 @strtol_endptr_not_null() #0 {
+; CHECK-LABEL: @strtol_endptr_not_null(
+; CHECK-NEXT:    [[END:%.*]] = alloca i8*, align 4
+; CHECK-NEXT:    [[CALL:%.*]] = call i32 @strtol(i8* getelementptr inbounds ([2 x i8], [2 x i8]* @.str.1, i64 0, i64 0), i8** nonnull [[END]], i32 10)
+; CHECK-NEXT:    ret i32 [[CALL]]
+;
+  %end = alloca i8*, align 4
+  %call = call i32 @strtol(i8* getelementptr inbounds ([2 x i8], [2 x i8]* @.str.1, i32 0, i32 0), i8** %end, i32 10) #2
+  ret i32 %call
+}
+
+define i32 @atoi_test() #0 {
+; CHECK-LABEL: @atoi_test(
+; CHECK-NEXT:    ret i32 12
+;
+  %call = call i32 @atoi(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @.str, i32 0, i32 0)) #4
+  ret i32 %call
+}
+
+define i32 @strtol_not_const_str(i8* %s) #0 {
+; CHECK-LABEL: @strtol_not_const_str(
+; CHECK-NEXT:    [[CALL:%.*]] = call i32 @strtol(i8* nocapture [[S:%.*]], i8** null, i32 10)
+; CHECK-NEXT:    ret i32 [[CALL]]
+;
+  %call = call i32 @strtol(i8* %s, i8** null, i32 10) #3
+  ret i32 %call
+}
+
+define i32 @atoi_not_const_str(i8* %s) #0 {
+; CHECK-LABEL: @atoi_not_const_str(
+; CHECK-NEXT:    [[CALL:%.*]] = call i32 @atoi(i8* [[S:%.*]])
+; CHECK-NEXT:    ret i32 [[CALL]]
+;
+  %call = call i32 @atoi(i8* %s) #4
+  ret i32 %call
+}
+
+define i32 @strtol_not_const_base(i32 %b) #0 {
+; CHECK-LABEL: @strtol_not_const_base(
+; CHECK-NEXT:    [[CALL:%.*]] = call i32 @strtol(i8* nocapture getelementptr inbounds ([3 x i8], [3 x i8]* @.str, i64 0, i64 0), i8** null, i32 [[B:%.*]])
+; CHECK-NEXT:    ret i32 [[CALL]]
+;
+  %call = call i32 @strtol(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @.str, i32 0, i32 0), i8** null, i32 %b) #2
+  ret i32 %call
+}
+
+define i32 @strtol_long_int() #0 {
+; CHECK-LABEL: @strtol_long_int(
+; CHECK-NEXT:    [[CALL:%.*]] = call i32 @strtol(i8* nocapture getelementptr inbounds ([11 x i8], [11 x i8]* @.str.2, i64 0, i64 0), i8** null, i32 10)
+; CHECK-NEXT:    ret i32 [[CALL]]
+;
+  %call = call i32 @strtol(i8* getelementptr inbounds ([11 x i8], [11 x i8]* @.str.2, i32 0, i32 0), i8** null, i32 10) #3
+  ret i32 %call
+}
+
+
+define i32 @strtol_big_overflow() #0 {
+; CHECK-LABEL: @strtol_big_overflow(
+; CHECK-NEXT:    [[CALL:%.*]] = call i32 @strtol(i8* nocapture getelementptr inbounds ([24 x i8], [24 x i8]* @.str.3, i64 0, i64 0), i8** null, i32 10)
+; CHECK-NEXT:    ret i32 [[CALL]]
+;
+  %call = call i32 @strtol(i8* nocapture getelementptr inbounds ([24 x i8], [24 x i8]* @.str.3, i32 0, i32 0), i8** null, i32 10) #2
+  ret i32 %call
+}
+
+define i32 @atol_test() #0 {
+; CHECK-LABEL: @atol_test(
+; CHECK-NEXT:    ret i32 499496729
+;
+; CHECK-NEXT
+  %call = call i32 @atol(i8* getelementptr inbounds ([10 x i8], [10 x i8]* @.str.6, i32 0, i32 0)) #4
+  ret i32 %call
+}
+
+define i32 @atoll_test() #0 {
+; CHECK-LABEL: @atoll_test(
+; CHECK-NEXT:    [[CALL:%.*]] = call i32 @atoll(i8* getelementptr inbounds ([11 x i8], [11 x i8]* @.str.5, i64 0, i64 0))
+; CHECK-NEXT:    ret i32 [[CALL]]
+;
+  %call = call i32 @atoll(i8* getelementptr inbounds ([11 x i8], [11 x i8]* @.str.5, i32 0, i32 0)) #3
+  ret i32 %call
+}
+
+define i32 @strtoll_test() #0 {
+; CHECK-LABEL: @strtoll_test(
+; CHECK-NEXT:    [[CALL:%.*]] = call i32 @strtoll(i8* nocapture getelementptr inbounds ([11 x i8], [11 x i8]* @.str.7, i64 0, i64 0), i8** null, i32 10)
+; CHECK-NEXT:    ret i32 [[CALL]]
+;
+; CHECK-NEXT
+  %call = call i32 @strtoll(i8* getelementptr inbounds ([11 x i8], [11 x i8]* @.str.7, i32 0, i32 0), i8** null, i32 10) #5
+  ret i32 %call
+}

Added: llvm/trunk/test/Transforms/InstCombine/strcat-1.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/strcat-1.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/strcat-1.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/strcat-1.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,38 @@
+; Test that the strcat libcall simplifier works correctly per the
+; bug found in PR3661.
+;
+; 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"
+
+ at hello = constant [6 x i8] c"hello\00"
+ at null = constant [1 x i8] zeroinitializer
+ at null_hello = constant [7 x i8] c"\00hello\00"
+
+declare i8* @strcat(i8*, i8*)
+declare i32 @puts(i8*)
+
+define i32 @main() {
+; CHECK-LABEL: @main(
+; CHECK-NOT: call i8* @strcat
+; CHECK: call i32 @puts
+
+  %target = alloca [1024 x i8]
+  %arg1 = getelementptr [1024 x i8], [1024 x i8]* %target, i32 0, i32 0
+  store i8 0, i8* %arg1
+
+  ; rslt1 = strcat(target, "hello\00")
+  %arg2 = getelementptr [6 x i8], [6 x i8]* @hello, i32 0, i32 0
+  %rslt1 = call i8* @strcat(i8* %arg1, i8* %arg2)
+
+  ; rslt2 = strcat(rslt1, "\00")
+  %arg3 = getelementptr [1 x i8], [1 x i8]* @null, i32 0, i32 0
+  %rslt2 = call i8* @strcat(i8* %rslt1, i8* %arg3)
+
+  ; rslt3 = strcat(rslt2, "\00hello\00")
+  %arg4 = getelementptr [7 x i8], [7 x i8]* @null_hello, i32 0, i32 0
+  %rslt3 = call i8* @strcat(i8* %rslt2, i8* %arg4)
+
+  call i32 @puts( i8* %rslt3 )
+  ret i32 0
+}

Added: llvm/trunk/test/Transforms/InstCombine/strcat-2.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/strcat-2.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/strcat-2.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/strcat-2.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,32 @@
+; Test that the strcat libcall 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"
+
+ at hello = constant [6 x i8] c"hello\00"
+ at empty = constant [1 x i8] c"\00"
+ at a = common global [32 x i8] zeroinitializer, align 1
+
+declare i8* @strcat(i8*, i8*)
+
+define void @test_simplify1() {
+; CHECK-LABEL: @test_simplify1(
+; CHECK-NOT: call i8* @strcat
+; CHECK: ret void
+
+  %dst = getelementptr [32 x i8], [32 x i8]* @a, i32 0, i32 0
+  %src = getelementptr [6 x i8], [6 x i8]* @hello, i32 0, i32 0
+  call i8* @strcat(i8* %dst, i8* %src)
+  ret void
+}
+
+define void @test_simplify2() {
+; CHECK-LABEL: @test_simplify2(
+; CHECK-NEXT: ret void
+
+  %dst = getelementptr [32 x i8], [32 x i8]* @a, i32 0, i32 0
+  %src = getelementptr [1 x i8], [1 x i8]* @empty, i32 0, i32 0
+  call i8* @strcat(i8* %dst, i8* %src)
+  ret void
+}

Added: llvm/trunk/test/Transforms/InstCombine/strcat-3.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/strcat-3.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/strcat-3.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/strcat-3.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,22 @@
+; Test that the strcat libcall 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"
+
+ at hello = constant [6 x i8] c"hello\00"
+ at empty = constant [1 x i8] c"\00"
+ at a = common global [32 x i8] zeroinitializer, align 1
+
+declare i16* @strcat(i8*, i8*)
+
+define void @test_nosimplify1() {
+; CHECK-LABEL: @test_nosimplify1(
+; CHECK: call i16* @strcat
+; CHECK: ret void
+
+  %dst = getelementptr [32 x i8], [32 x i8]* @a, i32 0, i32 0
+  %src = getelementptr [6 x i8], [6 x i8]* @hello, i32 0, i32 0
+  call i16* @strcat(i8* %dst, i8* %src)
+  ret void
+}

Added: llvm/trunk/test/Transforms/InstCombine/strchr-1.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/strchr-1.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/strchr-1.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/strchr-1.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,96 @@
+; Test that the strchr library call simplifier works correctly.
+; RUN: opt < %s -instcombine -S | FileCheck %s
+
+target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:128:128-n8:16:32"
+
+ at hello = constant [14 x i8] c"hello world\5Cn\00"
+ at null = constant [1 x i8] zeroinitializer
+ at newlines = constant [3 x i8] c"\0D\0A\00"
+ at chp = global i8* zeroinitializer
+
+declare i8* @strchr(i8*, i32)
+
+define void @test_simplify1() {
+; CHECK: store i8* getelementptr inbounds ([14 x i8], [14 x i8]* @hello, i32 0, i32 6)
+; CHECK-NOT: call i8* @strchr
+; CHECK: ret void
+
+  %str = getelementptr [14 x i8], [14 x i8]* @hello, i32 0, i32 0
+  %dst = call i8* @strchr(i8* %str, i32 119)
+  store i8* %dst, i8** @chp
+  ret void
+}
+
+define void @test_simplify2() {
+; CHECK: store i8* null, i8** @chp, align 4
+; CHECK-NOT: call i8* @strchr
+; CHECK: ret void
+
+  %str = getelementptr [1 x i8], [1 x i8]* @null, i32 0, i32 0
+  %dst = call i8* @strchr(i8* %str, i32 119)
+  store i8* %dst, i8** @chp
+  ret void
+}
+
+define void @test_simplify3() {
+; CHECK: store i8* getelementptr inbounds ([14 x i8], [14 x i8]* @hello, i32 0, i32 13)
+; CHECK-NOT: call i8* @strchr
+; CHECK: ret void
+
+  %src = getelementptr [14 x i8], [14 x i8]* @hello, i32 0, i32 0
+  %dst = call i8* @strchr(i8* %src, i32 0)
+  store i8* %dst, i8** @chp
+  ret void
+}
+
+define void @test_simplify4(i32 %chr) {
+; CHECK: call i8* @memchr
+; CHECK-NOT: call i8* @strchr
+; CHECK: ret void
+
+  %src = getelementptr [14 x i8], [14 x i8]* @hello, i32 0, i32 0
+  %dst = call i8* @strchr(i8* %src, i32 %chr)
+  store i8* %dst, i8** @chp
+  ret void
+}
+
+define void @test_simplify5() {
+; CHECK: store i8* getelementptr inbounds ([14 x i8], [14 x i8]* @hello, i32 0, i32 13)
+; CHECK-NOT: call i8* @strchr
+; CHECK: ret void
+
+  %src = getelementptr [14 x i8], [14 x i8]* @hello, i32 0, i32 0
+  %dst = call i8* @strchr(i8* %src, i32 65280)
+  store i8* %dst, i8** @chp
+  ret void
+}
+
+; Check transformation strchr(p, 0) -> p + strlen(p)
+define void @test_simplify6(i8* %str) {
+; CHECK: %strlen = call i32 @strlen(i8* %str)
+; CHECK-NOT: call i8* @strchr
+; CHECK: %strchr = getelementptr i8, i8* %str, i32 %strlen
+; CHECK: store i8* %strchr, i8** @chp, align 4
+; CHECK: ret void
+
+  %dst = call i8* @strchr(i8* %str, i32 0)
+  store i8* %dst, i8** @chp
+  ret void
+}
+
+; Check transformation strchr("\r\n", C) != nullptr -> (C & 9217) != 0
+define i1 @test_simplify7(i32 %C) {
+; CHECK-LABEL: @test_simplify7
+; CHECK-NEXT: [[TRUNC:%.*]] = trunc i32 %C to i16
+; CHECK-NEXT: [[TRUNC_AND:%.*]] = and i16 [[TRUNC]], 255
+; CHECK-NEXT: %memchr.bounds = icmp ult i16 [[TRUNC_AND]], 16
+; CHECK-NEXT: [[SHL:%.*]] = shl i16 1, [[TRUNC_AND]]
+; CHECK-NEXT: [[AND:%.*]] = and i16 [[SHL]], 9217
+; CHECK-NEXT: %memchr.bits = icmp ne i16 [[AND]], 0
+; CHECK-NEXT: %memchr1 = and i1 %memchr.bounds, %memchr.bits
+; CHECK-NEXT: ret i1 %memchr1
+
+  %dst = call i8* @strchr(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @newlines, i64 0, i64 0), i32 %C)
+  %cmp = icmp ne i8* %dst, null
+  ret i1 %cmp
+}

Added: llvm/trunk/test/Transforms/InstCombine/strchr-2.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/strchr-2.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/strchr-2.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/strchr-2.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,21 @@
+; Test that the strchr libcall 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"
+
+ at hello = constant [14 x i8] c"hello world\5Cn\00"
+ at chr = global i8 zeroinitializer
+
+declare i8 @strchr(i8*, i32)
+
+define void @test_nosimplify1() {
+; CHECK: test_nosimplify1
+; CHECK: call i8 @strchr
+; CHECK: ret void
+
+  %str = getelementptr [14 x i8], [14 x i8]* @hello, i32 0, i32 0
+  %dst = call i8 @strchr(i8* %str, i32 119)
+  store i8 %dst, i8* @chr
+  ret void
+}

Added: llvm/trunk/test/Transforms/InstCombine/strcmp-1.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/strcmp-1.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/strcmp-1.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/strcmp-1.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,104 @@
+; Test that the strcmp library call simplifier works correctly.
+; RUN: opt < %s -instcombine -S | FileCheck %s --check-prefix=NOBCMP
+; RUN: opt < %s -instcombine -mtriple=unknown-unknown-linux-gnu -S | FileCheck %s --check-prefix=BCMP
+
+target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:128:128"
+
+ at hello = constant [6 x i8] c"hello\00"
+ at hell = constant [5 x i8] c"hell\00"
+ at bell = constant [5 x i8] c"bell\00"
+ at null = constant [1 x i8] zeroinitializer
+
+declare i32 @strcmp(i8*, i8*)
+
+; strcmp("", x) -> -*x
+define i32 @test1(i8* %str2) {
+; CHECK-LABEL: @test1(
+; CHECK: %strcmpload = load i8, i8* %str
+; CHECK: %1 = zext i8 %strcmpload to i32
+; CHECK: %2 = sub nsw i32 0, %1
+; CHECK: ret i32 %2
+
+  %str1 = getelementptr inbounds [1 x i8], [1 x i8]* @null, i32 0, i32 0
+  %temp1 = call i32 @strcmp(i8* %str1, i8* %str2)
+  ret i32 %temp1
+
+}
+
+; strcmp(x, "") -> *x
+define i32 @test2(i8* %str1) {
+; CHECK-LABEL: @test2(
+; CHECK: %strcmpload = load i8, i8* %str
+; CHECK: %1 = zext i8 %strcmpload to i32
+; CHECK: ret i32 %1
+
+  %str2 = getelementptr inbounds [1 x i8], [1 x i8]* @null, i32 0, i32 0
+  %temp1 = call i32 @strcmp(i8* %str1, i8* %str2)
+  ret i32 %temp1
+}
+
+; strcmp(x, y)  -> cnst
+define i32 @test3() {
+; CHECK-LABEL: @test3(
+; CHECK: ret i32 -1
+
+  %str1 = getelementptr inbounds [5 x i8], [5 x i8]* @hell, i32 0, i32 0
+  %str2 = getelementptr inbounds [6 x i8], [6 x i8]* @hello, i32 0, i32 0
+  %temp1 = call i32 @strcmp(i8* %str1, i8* %str2)
+  ret i32 %temp1
+}
+
+define i32 @test4() {
+; CHECK-LABEL: @test4(
+; CHECK: ret i32 1
+
+  %str1 = getelementptr inbounds [5 x i8], [5 x i8]* @hell, i32 0, i32 0
+  %str2 = getelementptr inbounds [1 x i8], [1 x i8]* @null, i32 0, i32 0
+  %temp1 = call i32 @strcmp(i8* %str1, i8* %str2)
+  ret i32 %temp1
+}
+
+; strcmp(x, y)   -> memcmp(x, y, <known length>)
+; (This transform is rather difficult to trigger in a useful manner)
+define i32 @test5(i1 %b) {
+; CHECK-LABEL: @test5(
+; CHECK: %memcmp = call i32 @memcmp(i8* getelementptr inbounds ([6 x i8], [6 x i8]* @hello, i32 0, i32 0), i8* %str2, i32 5)
+; CHECK: ret i32 %memcmp
+
+  %str1 = getelementptr inbounds [6 x i8], [6 x i8]* @hello, i32 0, i32 0
+  %temp1 = getelementptr inbounds [5 x i8], [5 x i8]* @hell, i32 0, i32 0
+  %temp2 = getelementptr inbounds [5 x i8], [5 x i8]* @bell, i32 0, i32 0
+  %str2 = select i1 %b, i8* %temp1, i8* %temp2
+  %temp3 = call i32 @strcmp(i8* %str1, i8* %str2)
+  ret i32 %temp3
+}
+
+; strcmp(x,x)  -> 0
+define i32 @test6(i8* %str) {
+; CHECK-LABEL: @test6(
+; CHECK: ret i32 0
+
+  %temp1 = call i32 @strcmp(i8* %str, i8* %str)
+  ret i32 %temp1
+}
+
+; strcmp(x, y) == 0  -> bcmp(x, y, <known length>)
+define i1 @test7(i1 %b) {
+; BCMP-LABEL: @test7(
+; BCMP: %bcmp = call i32 @bcmp(i8* getelementptr inbounds ([6 x i8], [6 x i8]* @hello, i32 0, i32 0), i8* %str2, i32 5)
+; BCMP: %res = icmp eq i32 %bcmp, 0
+; BCMP: ret i1 %res
+
+; NOBCMP-LABEL: @test7(
+; NOBCMP: %memcmp = call i32 @memcmp(i8* getelementptr inbounds ([6 x i8], [6 x i8]* @hello, i32 0, i32 0), i8* %str2, i32 5)
+; NOBCMP: %res = icmp eq i32 %memcmp, 0
+; NOBCMP: ret i1 %res
+
+  %str1 = getelementptr inbounds [6 x i8], [6 x i8]* @hello, i32 0, i32 0
+  %temp1 = getelementptr inbounds [5 x i8], [5 x i8]* @hell, i32 0, i32 0
+  %temp2 = getelementptr inbounds [5 x i8], [5 x i8]* @bell, i32 0, i32 0
+  %str2 = select i1 %b, i8* %temp1, i8* %temp2
+  %temp3 = call i32 @strcmp(i8* %str1, i8* %str2)
+  %res = icmp eq i32 %temp3, 0
+  ret i1 %res
+}

Added: llvm/trunk/test/Transforms/InstCombine/strcmp-2.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/strcmp-2.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/strcmp-2.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/strcmp-2.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,20 @@
+; Test that the strcmp 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"
+
+ at hello = constant [6 x i8] c"hello\00"
+ at hell = constant [5 x i8] c"hell\00"
+
+declare i16 @strcmp(i8*, i8*)
+
+define i16 @test_nosimplify() {
+; CHECK-LABEL: @test_nosimplify(
+; CHECK: call i16 @strcmp
+; CHECK: ret i16 %temp1
+
+  %str1 = getelementptr inbounds [5 x i8], [5 x i8]* @hell, i32 0, i32 0
+  %str2 = getelementptr inbounds [6 x i8], [6 x i8]* @hello, i32 0, i32 0
+  %temp1 = call i16 @strcmp(i8* %str1, i8* %str2)
+  ret i16 %temp1
+}

Added: llvm/trunk/test/Transforms/InstCombine/strcmp-memcmp.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/strcmp-memcmp.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/strcmp-memcmp.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/strcmp-memcmp.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,560 @@
+; 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"
+
+ at key = constant [4 x i8] c"key\00", align 1
+ at abc = constant [8 x i8] c"abc\00de\00\00", align 1
+
+declare void @use(i32)
+
+define i32 @strcmp_memcmp([12 x i8]* dereferenceable (12) %buf) {
+; CHECK-LABEL: @strcmp_memcmp(
+; CHECK-NEXT:    [[STRING:%.*]] = getelementptr inbounds [12 x i8], [12 x i8]* [[BUF:%.*]], i64 0, i64 0
+; CHECK-NEXT:    [[MEMCMP:%.*]] = call i32 @memcmp(i8* nonnull [[STRING]], i8* getelementptr inbounds ([4 x i8], [4 x i8]* @key, i64 0, i64 0), i64 4)
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[MEMCMP]], 0
+; CHECK-NEXT:    [[CONV:%.*]] = zext i1 [[CMP]] to i32
+; CHECK-NEXT:    ret i32 [[CONV]]
+;
+  %string = getelementptr inbounds [12 x i8], [12 x i8]* %buf, i64 0, i64 0
+  %call = call i32 @strcmp(i8* nonnull %string, i8* getelementptr inbounds ([4 x i8], [4 x i8]* @key, i64 0, i64 0))
+  %cmp = icmp eq i32 %call, 0
+  %conv = zext i1 %cmp to i32
+  ret i32 %conv
+}
+
+declare i32 @strcmp(i8* nocapture, i8* nocapture)
+
+define i32 @strcmp_memcmp2([12 x i8]* dereferenceable (12) %buf) {
+; CHECK-LABEL: @strcmp_memcmp2(
+; CHECK-NEXT:    [[STRING:%.*]] = getelementptr inbounds [12 x i8], [12 x i8]* [[BUF:%.*]], i64 0, i64 0
+; CHECK-NEXT:    [[MEMCMP:%.*]] = call i32 @memcmp(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @key, i64 0, i64 0), i8* nonnull [[STRING]], i64 4)
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[MEMCMP]], 0
+; CHECK-NEXT:    [[CONV:%.*]] = zext i1 [[CMP]] to i32
+; CHECK-NEXT:    ret i32 [[CONV]]
+;
+  %string = getelementptr inbounds [12 x i8], [12 x i8]* %buf, i64 0, i64 0
+  %call = call i32 @strcmp(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @key, i64 0, i64 0), i8* nonnull %string)
+  %cmp = icmp eq i32 %call, 0
+  %conv = zext i1 %cmp to i32
+  ret i32 %conv
+}
+
+define i32 @strcmp_memcmp3([12 x i8]* dereferenceable (12) %buf) {
+; CHECK-LABEL: @strcmp_memcmp3(
+; CHECK-NEXT:    [[STRING:%.*]] = getelementptr inbounds [12 x i8], [12 x i8]* [[BUF:%.*]], i64 0, i64 0
+; CHECK-NEXT:    [[MEMCMP:%.*]] = call i32 @memcmp(i8* nonnull [[STRING]], i8* getelementptr inbounds ([4 x i8], [4 x i8]* @key, i64 0, i64 0), i64 4)
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ne i32 [[MEMCMP]], 0
+; CHECK-NEXT:    [[CONV:%.*]] = zext i1 [[CMP]] to i32
+; CHECK-NEXT:    ret i32 [[CONV]]
+;
+  %string = getelementptr inbounds [12 x i8], [12 x i8]* %buf, i64 0, i64 0
+  %call = call i32 @strcmp(i8* nonnull %string, i8* getelementptr inbounds ([4 x i8], [4 x i8]* @key, i64 0, i64 0))
+  %cmp = icmp ne i32 %call, 0
+  %conv = zext i1 %cmp to i32
+  ret i32 %conv
+}
+
+define i32 @strcmp_memcmp4([12 x i8]* dereferenceable (12) %buf) {
+; CHECK-LABEL: @strcmp_memcmp4(
+; CHECK-NEXT:    [[STRING:%.*]] = getelementptr inbounds [12 x i8], [12 x i8]* [[BUF:%.*]], i64 0, i64 0
+; CHECK-NEXT:    [[MEMCMP:%.*]] = call i32 @memcmp(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @key, i64 0, i64 0), i8* nonnull [[STRING]], i64 4)
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ne i32 [[MEMCMP]], 0
+; CHECK-NEXT:    [[CONV:%.*]] = zext i1 [[CMP]] to i32
+; CHECK-NEXT:    ret i32 [[CONV]]
+;
+  %string = getelementptr inbounds [12 x i8], [12 x i8]* %buf, i64 0, i64 0
+  %call = call i32 @strcmp(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @key, i64 0, i64 0), i8* nonnull %string)
+  %cmp = icmp ne i32 %call, 0
+  %conv = zext i1 %cmp to i32
+  ret i32 %conv
+}
+
+define i32 @strcmp_memcmp5([5 x i8]* dereferenceable (5) %buf) {
+; CHECK-LABEL: @strcmp_memcmp5(
+; CHECK-NEXT:    [[STRING:%.*]] = getelementptr inbounds [5 x i8], [5 x i8]* [[BUF:%.*]], i64 0, i64 0
+; CHECK-NEXT:    [[MEMCMP:%.*]] = call i32 @memcmp(i8* nonnull [[STRING]], i8* getelementptr inbounds ([4 x i8], [4 x i8]* @key, i64 0, i64 0), i64 4)
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[MEMCMP]], 0
+; CHECK-NEXT:    [[CONV:%.*]] = zext i1 [[CMP]] to i32
+; CHECK-NEXT:    ret i32 [[CONV]]
+;
+  %string = getelementptr inbounds [5 x i8], [5 x i8]* %buf, i64 0, i64 0
+  %call = call i32 @strcmp(i8* nonnull align 1 %string, i8* getelementptr inbounds ([4 x i8], [4 x i8]* @key, i64 0, i64 0))
+  %cmp = icmp eq i32 %call, 0
+  %conv = zext i1 %cmp to i32
+  ret i32 %conv
+}
+
+define i32 @strcmp_memcmp6([12 x i8]* dereferenceable (12) %buf) {
+; CHECK-LABEL: @strcmp_memcmp6(
+; CHECK-NEXT:    [[STRING:%.*]] = getelementptr inbounds [12 x i8], [12 x i8]* [[BUF:%.*]], i64 0, i64 0
+; CHECK-NEXT:    [[MEMCMP:%.*]] = call i32 @memcmp(i8* nonnull [[STRING]], i8* getelementptr inbounds ([4 x i8], [4 x i8]* @key, i64 0, i64 0), i64 4)
+; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt i32 [[MEMCMP]], 0
+; CHECK-NEXT:    [[CONV:%.*]] = zext i1 [[CMP]] to i32
+; CHECK-NEXT:    ret i32 [[CONV]]
+;
+  %string = getelementptr inbounds [12 x i8], [12 x i8]* %buf, i64 0, i64 0
+  %call = call i32 @strcmp(i8* nonnull %string, i8* getelementptr inbounds ([4 x i8], [4 x i8]* @key, i64 0, i64 0))
+  %cmp = icmp sgt i32 %call, 0
+  %conv = zext i1 %cmp to i32
+  ret i32 %conv
+}
+
+define i32 @strcmp_memcmp7([12 x i8]* dereferenceable (12) %buf) {
+; CHECK-LABEL: @strcmp_memcmp7(
+; CHECK-NEXT:    [[STRING:%.*]] = getelementptr inbounds [12 x i8], [12 x i8]* [[BUF:%.*]], i64 0, i64 0
+; CHECK-NEXT:    [[MEMCMP:%.*]] = call i32 @memcmp(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @key, i64 0, i64 0), i8* nonnull [[STRING]], i64 4)
+; CHECK-NEXT:    [[MEMCMP_LOBIT:%.*]] = lshr i32 [[MEMCMP]], 31
+; CHECK-NEXT:    ret i32 [[MEMCMP_LOBIT]]
+;
+  %string = getelementptr inbounds [12 x i8], [12 x i8]* %buf, i64 0, i64 0
+  %call = call i32 @strcmp(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @key, i64 0, i64 0), i8* nonnull %string)
+  %cmp = icmp slt i32 %call, 0
+  %conv = zext i1 %cmp to i32
+  ret i32 %conv
+}
+
+define i32 @strcmp_memcmp8([4 x i8]* dereferenceable (4) %buf) {
+; CHECK-LABEL: @strcmp_memcmp8(
+; CHECK-NEXT:    [[STRING:%.*]] = getelementptr inbounds [4 x i8], [4 x i8]* [[BUF:%.*]], i64 0, i64 0
+; CHECK-NEXT:    [[MEMCMP:%.*]] = call i32 @memcmp(i8* nonnull [[STRING]], i8* getelementptr inbounds ([4 x i8], [4 x i8]* @key, i64 0, i64 0), i64 4)
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[MEMCMP]], 0
+; CHECK-NEXT:    [[CONV:%.*]] = zext i1 [[CMP]] to i32
+; CHECK-NEXT:    ret i32 [[CONV]]
+;
+  %string = getelementptr inbounds [4 x i8], [4 x i8]* %buf, i64 0, i64 0
+  %call = call i32 @strcmp(i8* nonnull %string, i8* getelementptr inbounds ([4 x i8], [4 x i8]* @key, i64 0, i64 0))
+  %cmp = icmp eq i32 %call, 0
+  %conv = zext i1 %cmp to i32
+  ret i32 %conv
+}
+
+define i32 @strcmp_memcmp9([12 x i8]* dereferenceable (12) %buf) {
+; CHECK-LABEL: @strcmp_memcmp9(
+; CHECK-NEXT:    [[STRING:%.*]] = getelementptr inbounds [12 x i8], [12 x i8]* [[BUF:%.*]], i64 0, i64 0
+; CHECK-NEXT:    [[MEMCMP:%.*]] = call i32 @memcmp(i8* nonnull [[STRING]], i8* getelementptr inbounds ([8 x i8], [8 x i8]* @abc, i64 0, i64 0), i64 4)
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[MEMCMP]], 0
+; CHECK-NEXT:    [[CONV:%.*]] = zext i1 [[CMP]] to i32
+; CHECK-NEXT:    ret i32 [[CONV]]
+;
+  %string = getelementptr inbounds [12 x i8], [12 x i8]* %buf, i64 0, i64 0
+  %call = call i32 @strcmp(i8* nonnull %string, i8* getelementptr inbounds ([8 x i8], [8 x i8]* @abc, i64 0, i64 0))
+  %cmp = icmp eq i32 %call, 0
+  %conv = zext i1 %cmp to i32
+  ret i32 %conv
+}
+
+
+define i32 @strncmp_memcmp([12 x i8]* dereferenceable (12) %buf) {
+; CHECK-LABEL: @strncmp_memcmp(
+; CHECK-NEXT:    [[STRING:%.*]] = getelementptr inbounds [12 x i8], [12 x i8]* [[BUF:%.*]], i64 0, i64 0
+; CHECK-NEXT:    [[MEMCMP:%.*]] = call i32 @memcmp(i8* nonnull [[STRING]], i8* getelementptr inbounds ([4 x i8], [4 x i8]* @key, i64 0, i64 0), i64 2)
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[MEMCMP]], 0
+; CHECK-NEXT:    [[CONV:%.*]] = zext i1 [[CMP]] to i32
+; CHECK-NEXT:    ret i32 [[CONV]]
+;
+  %string = getelementptr inbounds [12 x i8], [12 x i8]* %buf, i64 0, i64 0
+  %call = call i32 @strncmp(i8* nonnull %string, i8* getelementptr inbounds ([4 x i8], [4 x i8]* @key, i64 0, i64 0), i64 2)
+  %cmp = icmp eq i32 %call, 0
+  %conv = zext i1 %cmp to i32
+  ret i32 %conv
+}
+
+declare i32 @strncmp(i8* nocapture, i8* nocapture, i64)
+
+define i32 @strncmp_memcmp2([12 x i8]* dereferenceable (12) %buf) {
+; CHECK-LABEL: @strncmp_memcmp2(
+; CHECK-NEXT:    [[STRING:%.*]] = getelementptr inbounds [12 x i8], [12 x i8]* [[BUF:%.*]], i64 0, i64 0
+; CHECK-NEXT:    [[MEMCMP:%.*]] = call i32 @memcmp(i8* nonnull [[STRING]], i8* getelementptr inbounds ([4 x i8], [4 x i8]* @key, i64 0, i64 0), i64 4)
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ne i32 [[MEMCMP]], 0
+; CHECK-NEXT:    [[CONV:%.*]] = zext i1 [[CMP]] to i32
+; CHECK-NEXT:    ret i32 [[CONV]]
+;
+  %string = getelementptr inbounds [12 x i8], [12 x i8]* %buf, i64 0, i64 0
+  %call = call i32 @strncmp(i8* nonnull %string, i8* getelementptr inbounds ([4 x i8], [4 x i8]* @key, i64 0, i64 0), i64 11)
+  %cmp = icmp ne i32 %call, 0
+  %conv = zext i1 %cmp to i32
+  ret i32 %conv
+}
+
+define i32 @strncmp_memcmp3([12 x i8]* dereferenceable (12) %buf) {
+; CHECK-LABEL: @strncmp_memcmp3(
+; CHECK-NEXT:    [[STRING:%.*]] = getelementptr inbounds [12 x i8], [12 x i8]* [[BUF:%.*]], i64 0, i64 0
+; CHECK-NEXT:    [[MEMCMP:%.*]] = call i32 @memcmp(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @key, i64 0, i64 0), i8* nonnull [[STRING]], i64 4)
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[MEMCMP]], 0
+; CHECK-NEXT:    [[CONV:%.*]] = zext i1 [[CMP]] to i32
+; CHECK-NEXT:    ret i32 [[CONV]]
+;
+  %string = getelementptr inbounds [12 x i8], [12 x i8]* %buf, i64 0, i64 0
+  %call = call i32 @strncmp(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @key, i64 0, i64 0), i8* nonnull %string, i64 11)
+  %cmp = icmp eq i32 %call, 0
+  %conv = zext i1 %cmp to i32
+  ret i32 %conv
+}
+
+define i32 @strncmp_memcmp4([12 x i8]* dereferenceable (12) %buf) {
+; CHECK-LABEL: @strncmp_memcmp4(
+; CHECK-NEXT:    [[STRING:%.*]] = getelementptr inbounds [12 x i8], [12 x i8]* [[BUF:%.*]], i64 0, i64 0
+; CHECK-NEXT:    [[MEMCMP:%.*]] = call i32 @memcmp(i8* nonnull [[STRING]], i8* getelementptr inbounds ([4 x i8], [4 x i8]* @key, i64 0, i64 0), i64 4)
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[MEMCMP]], 0
+; CHECK-NEXT:    [[CONV:%.*]] = zext i1 [[CMP]] to i32
+; CHECK-NEXT:    ret i32 [[CONV]]
+;
+  %string = getelementptr inbounds [12 x i8], [12 x i8]* %buf, i64 0, i64 0
+  %call = call i32 @strncmp(i8* nonnull %string, i8* getelementptr inbounds ([4 x i8], [4 x i8]* @key, i64 0, i64 0), i64 5)
+  %cmp = icmp eq i32 %call, 0
+  %conv = zext i1 %cmp to i32
+  ret i32 %conv
+}
+
+define i32 @strncmp_memcmp5([12 x i8]* dereferenceable (12) %buf) {
+; CHECK-LABEL: @strncmp_memcmp5(
+; CHECK-NEXT:    [[STRING:%.*]] = getelementptr inbounds [12 x i8], [12 x i8]* [[BUF:%.*]], i64 0, i64 0
+; CHECK-NEXT:    [[MEMCMP:%.*]] = call i32 @memcmp(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @key, i64 0, i64 0), i8* nonnull [[STRING]], i64 4)
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[MEMCMP]], 0
+; CHECK-NEXT:    [[CONV:%.*]] = zext i1 [[CMP]] to i32
+; CHECK-NEXT:    ret i32 [[CONV]]
+;
+  %string = getelementptr inbounds [12 x i8], [12 x i8]* %buf, i64 0, i64 0
+  %call = call i32 @strncmp(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @key, i64 0, i64 0), i8* nonnull %string, i64 5)
+  %cmp = icmp eq i32 %call, 0
+  %conv = zext i1 %cmp to i32
+  ret i32 %conv
+}
+
+
+define i32 @strncmp_memcmp6([12 x i8]* dereferenceable (12) %buf) {
+; CHECK-LABEL: @strncmp_memcmp6(
+; CHECK-NEXT:    [[STRING:%.*]] = getelementptr inbounds [12 x i8], [12 x i8]* [[BUF:%.*]], i64 0, i64 0
+; CHECK-NEXT:    [[MEMCMP:%.*]] = call i32 @memcmp(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @key, i64 0, i64 0), i8* nonnull [[STRING]], i64 4)
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ne i32 [[MEMCMP]], 0
+; CHECK-NEXT:    [[CONV:%.*]] = zext i1 [[CMP]] to i32
+; CHECK-NEXT:    ret i32 [[CONV]]
+;
+  %string = getelementptr inbounds [12 x i8], [12 x i8]* %buf, i64 0, i64 0
+  %call = call i32 @strncmp(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @key, i64 0, i64 0), i8* nonnull %string, i64 5)
+  %cmp = icmp ne i32 %call, 0
+  %conv = zext i1 %cmp to i32
+  ret i32 %conv
+}
+
+define i32 @strncmp_memcmp7([12 x i8]* dereferenceable (12) %buf) {
+; CHECK-LABEL: @strncmp_memcmp7(
+; CHECK-NEXT:    [[STRING:%.*]] = getelementptr inbounds [12 x i8], [12 x i8]* [[BUF:%.*]], i64 0, i64 0
+; CHECK-NEXT:    [[MEMCMP:%.*]] = call i32 @memcmp(i8* nonnull [[STRING]], i8* getelementptr inbounds ([4 x i8], [4 x i8]* @key, i64 0, i64 0), i64 4)
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[MEMCMP]], 0
+; CHECK-NEXT:    [[CONV:%.*]] = zext i1 [[CMP]] to i32
+; CHECK-NEXT:    ret i32 [[CONV]]
+;
+  %string = getelementptr inbounds [12 x i8], [12 x i8]* %buf, i64 0, i64 0
+  %call = call i32 @strncmp(i8* nonnull %string, i8* getelementptr inbounds ([4 x i8], [4 x i8]* @key, i64 0, i64 0), i64 4)
+  %cmp = icmp eq i32 %call, 0
+  %conv = zext i1 %cmp to i32
+  ret i32 %conv
+}
+
+define i32 @strncmp_memcmp8([12 x i8]* dereferenceable (12) %buf) {
+; CHECK-LABEL: @strncmp_memcmp8(
+; CHECK-NEXT:    [[STRING:%.*]] = getelementptr inbounds [12 x i8], [12 x i8]* [[BUF:%.*]], i64 0, i64 0
+; CHECK-NEXT:    [[MEMCMP:%.*]] = call i32 @memcmp(i8* nonnull [[STRING]], i8* getelementptr inbounds ([4 x i8], [4 x i8]* @key, i64 0, i64 0), i64 3)
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[MEMCMP]], 0
+; CHECK-NEXT:    [[CONV:%.*]] = zext i1 [[CMP]] to i32
+; CHECK-NEXT:    ret i32 [[CONV]]
+;
+  %string = getelementptr inbounds [12 x i8], [12 x i8]* %buf, i64 0, i64 0
+  %call = call i32 @strncmp(i8* nonnull %string, i8* getelementptr inbounds ([4 x i8], [4 x i8]* @key, i64 0, i64 0), i64 3)
+  %cmp = icmp eq i32 %call, 0
+  %conv = zext i1 %cmp to i32
+  ret i32 %conv
+}
+
+define i32 @strncmp_memcmp9([12 x i8]* dereferenceable (12) %buf) {
+; CHECK-LABEL: @strncmp_memcmp9(
+; CHECK-NEXT:    [[STRING:%.*]] = getelementptr inbounds [12 x i8], [12 x i8]* [[BUF:%.*]], i64 0, i64 0
+; CHECK-NEXT:    [[MEMCMP:%.*]] = call i32 @memcmp(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @key, i64 0, i64 0), i8* nonnull [[STRING]], i64 4)
+; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt i32 [[MEMCMP]], 0
+; CHECK-NEXT:    [[CONV:%.*]] = zext i1 [[CMP]] to i32
+; CHECK-NEXT:    ret i32 [[CONV]]
+;
+  %string = getelementptr inbounds [12 x i8], [12 x i8]* %buf, i64 0, i64 0
+  %call = call i32 @strncmp(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @key, i64 0, i64 0), i8* nonnull %string, i64 5)
+  %cmp = icmp sgt i32 %call, 0
+  %conv = zext i1 %cmp to i32
+  ret i32 %conv
+}
+
+define i32 @strncmp_memcmp10([12 x i8]* dereferenceable (12) %buf) {
+; CHECK-LABEL: @strncmp_memcmp10(
+; CHECK-NEXT:    [[STRING:%.*]] = getelementptr inbounds [12 x i8], [12 x i8]* [[BUF:%.*]], i64 0, i64 0
+; CHECK-NEXT:    [[MEMCMP:%.*]] = call i32 @memcmp(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @key, i64 0, i64 0), i8* nonnull [[STRING]], i64 4)
+; CHECK-NEXT:    [[MEMCMP_LOBIT:%.*]] = lshr i32 [[MEMCMP]], 31
+; CHECK-NEXT:    ret i32 [[MEMCMP_LOBIT]]
+;
+  %string = getelementptr inbounds [12 x i8], [12 x i8]* %buf, i64 0, i64 0
+  %call = call i32 @strncmp(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @key, i64 0, i64 0), i8* nonnull %string, i64 5)
+  %cmp = icmp slt i32 %call, 0
+  %conv = zext i1 %cmp to i32
+  ret i32 %conv
+}
+
+define i32 @strncmp_memcmp11([12 x i8]* dereferenceable (12) %buf) {
+; CHECK-LABEL: @strncmp_memcmp11(
+; CHECK-NEXT:    [[STRING:%.*]] = getelementptr inbounds [12 x i8], [12 x i8]* [[BUF:%.*]], i64 0, i64 0
+; CHECK-NEXT:    [[MEMCMP:%.*]] = call i32 @memcmp(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @key, i64 0, i64 0), i8* nonnull [[STRING]], i64 4)
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[MEMCMP]], 0
+; CHECK-NEXT:    [[CONV:%.*]] = zext i1 [[CMP]] to i32
+; CHECK-NEXT:    ret i32 [[CONV]]
+;
+  %string = getelementptr inbounds [12 x i8], [12 x i8]* %buf, i64 0, i64 0
+  %call = call i32 @strncmp(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @key, i64 0, i64 0), i8* nonnull %string, i64 12)
+  %cmp = icmp eq i32 %call, 0
+  %conv = zext i1 %cmp to i32
+  ret i32 %conv
+}
+
+define i32 @strncmp_memcmp12([12 x i8]* dereferenceable (12) %buf) {
+; CHECK-LABEL: @strncmp_memcmp12(
+; CHECK-NEXT:    [[STRING:%.*]] = getelementptr inbounds [12 x i8], [12 x i8]* [[BUF:%.*]], i64 0, i64 0
+; CHECK-NEXT:    [[MEMCMP:%.*]] = call i32 @memcmp(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @key, i64 0, i64 0), i8* nonnull [[STRING]], i64 4)
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[MEMCMP]], 0
+; CHECK-NEXT:    [[CONV:%.*]] = zext i1 [[CMP]] to i32
+; CHECK-NEXT:    ret i32 [[CONV]]
+;
+  %string = getelementptr inbounds [12 x i8], [12 x i8]* %buf, i64 0, i64 0
+  %call = call i32 @strncmp(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @key, i64 0, i64 0), i8* nonnull %string, i64 12)
+  %cmp = icmp eq i32 %call, 0
+  %conv = zext i1 %cmp to i32
+  ret i32 %conv
+}
+
+define i32 @strncmp_memcmp13([12 x i8]* dereferenceable (12) %buf) {
+; CHECK-LABEL: @strncmp_memcmp13(
+; CHECK-NEXT:    [[STRING:%.*]] = getelementptr inbounds [12 x i8], [12 x i8]* [[BUF:%.*]], i64 0, i64 0
+; CHECK-NEXT:    [[MEMCMP:%.*]] = call i32 @memcmp(i8* nonnull [[STRING]], i8* getelementptr inbounds ([8 x i8], [8 x i8]* @abc, i64 0, i64 0), i64 2)
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[MEMCMP]], 0
+; CHECK-NEXT:    [[CONV:%.*]] = zext i1 [[CMP]] to i32
+; CHECK-NEXT:    ret i32 [[CONV]]
+;
+  %string = getelementptr inbounds [12 x i8], [12 x i8]* %buf, i64 0, i64 0
+  %call = call i32 @strncmp(i8* nonnull %string, i8* getelementptr inbounds ([8 x i8], [8 x i8]* @abc, i64 0, i64 0), i64 2)
+  %cmp = icmp eq i32 %call, 0
+  %conv = zext i1 %cmp to i32
+  ret i32 %conv
+}
+
+define i32 @strncmp_memcmp14([12 x i8]* dereferenceable (12) %buf) {
+; CHECK-LABEL: @strncmp_memcmp14(
+; CHECK-NEXT:    [[STRING:%.*]] = getelementptr inbounds [12 x i8], [12 x i8]* [[BUF:%.*]], i64 0, i64 0
+; CHECK-NEXT:    [[MEMCMP:%.*]] = call i32 @memcmp(i8* nonnull [[STRING]], i8* getelementptr inbounds ([8 x i8], [8 x i8]* @abc, i64 0, i64 0), i64 4)
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[MEMCMP]], 0
+; CHECK-NEXT:    [[CONV:%.*]] = zext i1 [[CMP]] to i32
+; CHECK-NEXT:    ret i32 [[CONV]]
+;
+  %string = getelementptr inbounds [12 x i8], [12 x i8]* %buf, i64 0, i64 0
+  %call = call i32 @strncmp(i8* nonnull %string, i8* getelementptr inbounds ([8 x i8], [8 x i8]* @abc, i64 0, i64 0), i64 12)
+  %cmp = icmp eq i32 %call, 0
+  %conv = zext i1 %cmp to i32
+  ret i32 %conv
+}
+
+; Negative tests
+define i32 @strcmp_memcmp_bad([12 x i8]* dereferenceable (12) %buf) {
+; CHECK-LABEL: @strcmp_memcmp_bad(
+; CHECK-NEXT:    [[STRING:%.*]] = getelementptr inbounds [12 x i8], [12 x i8]* [[BUF:%.*]], i64 0, i64 0
+; CHECK-NEXT:    [[CALL:%.*]] = call i32 @strcmp(i8* nonnull [[STRING]], i8* getelementptr inbounds ([4 x i8], [4 x i8]* @key, i64 0, i64 0))
+; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt i32 [[CALL]], 3
+; CHECK-NEXT:    [[CONV:%.*]] = zext i1 [[CMP]] to i32
+; CHECK-NEXT:    ret i32 [[CONV]]
+;
+  %string = getelementptr inbounds [12 x i8], [12 x i8]* %buf, i64 0, i64 0
+  %call = call i32 @strcmp(i8* nonnull %string, i8* getelementptr inbounds ([4 x i8], [4 x i8]* @key, i64 0, i64 0))
+  %cmp = icmp sgt i32 %call, 3
+  %conv = zext i1 %cmp to i32
+  ret i32 %conv
+}
+
+define i32 @strcmp_memcmp_bad2([12 x i8]* dereferenceable (12) %buf) {
+; CHECK-LABEL: @strcmp_memcmp_bad2(
+; CHECK-NEXT:    [[STRING:%.*]] = getelementptr inbounds [12 x i8], [12 x i8]* [[BUF:%.*]], i64 0, i64 0
+; CHECK-NEXT:    [[CALL:%.*]] = call i32 @strcmp(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @key, i64 0, i64 0), i8* nonnull [[STRING]])
+; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i32 [[CALL]], 3
+; CHECK-NEXT:    [[CONV:%.*]] = zext i1 [[CMP]] to i32
+; CHECK-NEXT:    ret i32 [[CONV]]
+;
+  %string = getelementptr inbounds [12 x i8], [12 x i8]* %buf, i64 0, i64 0
+  %call = call i32 @strcmp(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @key, i64 0, i64 0), i8* nonnull %string)
+  %cmp = icmp slt i32 %call, 3
+  %conv = zext i1 %cmp to i32
+  ret i32 %conv
+}
+
+define i32 @strcmp_memcmp_bad3([12 x i8]* dereferenceable (12) %buf) {
+; CHECK-LABEL: @strcmp_memcmp_bad3(
+; CHECK-NEXT:    [[STRING:%.*]] = getelementptr inbounds [12 x i8], [12 x i8]* [[BUF:%.*]], i64 0, i64 0
+; CHECK-NEXT:    [[CALL:%.*]] = call i32 @strcmp(i8* nonnull [[STRING]], i8* getelementptr inbounds ([4 x i8], [4 x i8]* @key, i64 0, i64 0))
+; CHECK-NEXT:    ret i32 [[CALL]]
+;
+  %string = getelementptr inbounds [12 x i8], [12 x i8]* %buf, i64 0, i64 0
+  %call = call i32 @strcmp(i8* nonnull %string, i8* getelementptr inbounds ([4 x i8], [4 x i8]* @key, i64 0, i64 0))
+  ret i32 %call
+}
+
+
+define i32 @strcmp_memcmp_bad4(i8* nocapture readonly %buf) {
+; CHECK-LABEL: @strcmp_memcmp_bad4(
+; CHECK-NEXT:    [[CALL:%.*]] = tail call i32 @strcmp(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @key, i64 0, i64 0), i8* [[BUF:%.*]])
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[CALL]], 0
+; CHECK-NEXT:    [[CONV:%.*]] = zext i1 [[CMP]] to i32
+; CHECK-NEXT:    ret i32 [[CONV]]
+;
+  %call = tail call i32 @strcmp(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @key, i64 0, i64 0), i8* %buf)
+  %cmp = icmp eq i32 %call, 0
+  %conv = zext i1 %cmp to i32
+  ret i32 %conv
+}
+
+
+define i32 @strcmp_memcmp_bad5([3 x i8]* dereferenceable (3) %buf) {
+; CHECK-LABEL: @strcmp_memcmp_bad5(
+; CHECK-NEXT:    [[STRING:%.*]] = getelementptr inbounds [3 x i8], [3 x i8]* [[BUF:%.*]], i64 0, i64 0
+; CHECK-NEXT:    [[CALL:%.*]] = call i32 @strcmp(i8* nonnull [[STRING]], i8* getelementptr inbounds ([4 x i8], [4 x i8]* @key, i64 0, i64 0))
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[CALL]], 0
+; CHECK-NEXT:    [[CONV:%.*]] = zext i1 [[CMP]] to i32
+; CHECK-NEXT:    ret i32 [[CONV]]
+;
+  %string = getelementptr inbounds [3 x i8], [3 x i8]* %buf, i64 0, i64 0
+  %call = call i32 @strcmp(i8* nonnull %string, i8* getelementptr inbounds ([4 x i8], [4 x i8]* @key, i64 0, i64 0))
+  %cmp = icmp eq i32 %call, 0
+  %conv = zext i1 %cmp to i32
+  ret i32 %conv
+}
+
+define i32 @strcmp_memcmp_bad6([4 x i8]* dereferenceable (4) %buf, i8* nocapture readonly %k) {
+; CHECK-LABEL: @strcmp_memcmp_bad6(
+; CHECK-NEXT:    [[STRING:%.*]] = getelementptr inbounds [4 x i8], [4 x i8]* [[BUF:%.*]], i64 0, i64 0
+; CHECK-NEXT:    [[CALL:%.*]] = call i32 @strcmp(i8* nonnull [[STRING]], i8* [[K:%.*]])
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[CALL]], 0
+; CHECK-NEXT:    [[CONV:%.*]] = zext i1 [[CMP]] to i32
+; CHECK-NEXT:    ret i32 [[CONV]]
+;
+  %string = getelementptr inbounds [4 x i8], [4 x i8]* %buf, i64 0, i64 0
+  %call = call i32 @strcmp(i8* nonnull %string, i8* %k)
+  %cmp = icmp eq i32 %call, 0
+  %conv = zext i1 %cmp to i32
+  ret i32 %conv
+}
+
+define i32 @strcmp_memcmp_bad7(i8* nocapture readonly %k) {
+; CHECK-LABEL: @strcmp_memcmp_bad7(
+; CHECK-NEXT:    [[CALL:%.*]] = tail call i32 @strcmp(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @key, i64 0, i64 0), i8* [[K:%.*]])
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[CALL]], 0
+; CHECK-NEXT:    [[CONV:%.*]] = zext i1 [[CMP]] to i32
+; CHECK-NEXT:    ret i32 [[CONV]]
+;
+  %call = tail call i32 @strcmp(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @key, i64 0, i64 0), i8* %k)
+  %cmp = icmp eq i32 %call, 0
+  %conv = zext i1 %cmp to i32
+  ret i32 %conv
+}
+
+define i32 @strcmp_memcmp_bad8([4 x i8]* dereferenceable (4) %buf) {
+; CHECK-LABEL: @strcmp_memcmp_bad8(
+; CHECK-NEXT:    [[STRING:%.*]] = getelementptr inbounds [4 x i8], [4 x i8]* [[BUF:%.*]], i64 0, i64 0
+; CHECK-NEXT:    [[CALL:%.*]] = call i32 @strcmp(i8* nonnull [[STRING]], i8* getelementptr inbounds ([4 x i8], [4 x i8]* @key, i64 0, i64 0))
+; CHECK-NEXT:    tail call void @use(i32 [[CALL]])
+; CHECK-NEXT:    ret i32 0
+;
+  %string = getelementptr inbounds [4 x i8], [4 x i8]* %buf, i64 0, i64 0
+  %call = call i32 @strcmp(i8* nonnull %string, i8* getelementptr inbounds ([4 x i8], [4 x i8]* @key, i64 0, i64 0))
+  tail call void @use(i32 %call)
+  ret i32 0
+}
+
+define i32 @strncmp_memcmp_bad([12 x i8]* dereferenceable (12) %buf) {
+; CHECK-LABEL: @strncmp_memcmp_bad(
+; CHECK-NEXT:    [[STRING:%.*]] = getelementptr inbounds [12 x i8], [12 x i8]* [[BUF:%.*]], i64 0, i64 0
+; CHECK-NEXT:    [[CALL:%.*]] = call i32 @strncmp(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @key, i64 0, i64 0), i8* nonnull [[STRING]], i64 5)
+; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt i32 [[CALL]], 3
+; CHECK-NEXT:    [[CONV:%.*]] = zext i1 [[CMP]] to i32
+; CHECK-NEXT:    ret i32 [[CONV]]
+;
+  %string = getelementptr inbounds [12 x i8], [12 x i8]* %buf, i64 0, i64 0
+  %call = call i32 @strncmp(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @key, i64 0, i64 0), i8* nonnull %string, i64 5)
+  %cmp = icmp sgt i32 %call, 3
+  %conv = zext i1 %cmp to i32
+  ret i32 %conv
+}
+
+
+define i32 @strncmp_memcmp_bad1([12 x i8]* dereferenceable (12) %buf) {
+; CHECK-LABEL: @strncmp_memcmp_bad1(
+; CHECK-NEXT:    [[STRING:%.*]] = getelementptr inbounds [12 x i8], [12 x i8]* [[BUF:%.*]], i64 0, i64 0
+; CHECK-NEXT:    [[CALL:%.*]] = call i32 @strncmp(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @key, i64 0, i64 0), i8* nonnull [[STRING]], i64 5)
+; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i32 [[CALL]], 3
+; CHECK-NEXT:    [[CONV:%.*]] = zext i1 [[CMP]] to i32
+; CHECK-NEXT:    ret i32 [[CONV]]
+;
+  %string = getelementptr inbounds [12 x i8], [12 x i8]* %buf, i64 0, i64 0
+  %call = call i32 @strncmp(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @key, i64 0, i64 0), i8* nonnull %string, i64 5)
+  %cmp = icmp slt i32 %call, 3
+  %conv = zext i1 %cmp to i32
+  ret i32 %conv
+}
+
+define i32 @strncmp_memcmp_bad2([12 x i8]* dereferenceable (12) %buf, i64 %n) {
+; CHECK-LABEL: @strncmp_memcmp_bad2(
+; CHECK-NEXT:    [[STRING:%.*]] = getelementptr inbounds [12 x i8], [12 x i8]* [[BUF:%.*]], i64 0, i64 0
+; CHECK-NEXT:    [[CALL:%.*]] = call i32 @strncmp(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @key, i64 0, i64 0), i8* nonnull [[STRING]], i64 [[N:%.*]])
+; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i32 [[CALL]], 1
+; CHECK-NEXT:    [[CONV:%.*]] = zext i1 [[CMP]] to i32
+; CHECK-NEXT:    ret i32 [[CONV]]
+;
+  %string = getelementptr inbounds [12 x i8], [12 x i8]* %buf, i64 0, i64 0
+  %call = call i32 @strncmp(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @key, i64 0, i64 0), i8* nonnull %string, i64 %n)
+  %cmp = icmp slt i32 %call, 1
+  %conv = zext i1 %cmp to i32
+  ret i32 %conv
+}
+
+define i32 @strncmp_memcmp_bad3(i8* nocapture readonly %k) {
+; CHECK-LABEL: @strncmp_memcmp_bad3(
+; CHECK-NEXT:    [[CALL:%.*]] = tail call i32 @strncmp(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @key, i64 0, i64 0), i8* [[K:%.*]], i64 2)
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[CALL]], 0
+; CHECK-NEXT:    [[CONV:%.*]] = zext i1 [[CMP]] to i32
+; CHECK-NEXT:    ret i32 [[CONV]]
+;
+  %call = tail call i32 @strncmp(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @key, i64 0, i64 0), i8* %k, i64 2)
+  %cmp = icmp eq i32 %call, 0
+  %conv = zext i1 %cmp to i32
+  ret i32 %conv
+}
+
+define i32 @strncmp_memcmp_bad4([4 x i8]* dereferenceable (4) %buf) {
+; CHECK-LABEL: @strncmp_memcmp_bad4(
+; CHECK-NEXT:    [[STRING:%.*]] = getelementptr inbounds [4 x i8], [4 x i8]* [[BUF:%.*]], i64 0, i64 0
+; CHECK-NEXT:    [[CALL:%.*]] = call i32 @strncmp(i8* nonnull [[STRING]], i8* getelementptr inbounds ([4 x i8], [4 x i8]* @key, i64 0, i64 0), i64 2)
+; CHECK-NEXT:    tail call void @use(i32 [[CALL]])
+; CHECK-NEXT:    ret i32 0
+;
+  %string = getelementptr inbounds [4 x i8], [4 x i8]* %buf, i64 0, i64 0
+  %call = call i32 @strncmp(i8* nonnull %string, i8* getelementptr inbounds ([4 x i8], [4 x i8]* @key, i64 0, i64 0), i64 2)
+  tail call void @use(i32 %call)
+  ret i32 0
+}
+
+define i32 @strcmp_memcmp_msan([12 x i8]* dereferenceable (12) %buf) sanitize_memory {
+; CHECK-LABEL: @strcmp_memcmp_msan(
+; CHECK-NEXT:    [[STRING:%.*]] = getelementptr inbounds [12 x i8], [12 x i8]* [[BUF:%.*]], i64 0, i64 0
+; CHECK-NEXT:    [[CALL:%.*]] = call i32 @strcmp(i8* nonnull [[STRING]], i8* getelementptr inbounds ([4 x i8], [4 x i8]* @key, i64 0, i64 0))
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[CALL]], 0
+; CHECK-NEXT:    [[CONV:%.*]] = zext i1 [[CMP]] to i32
+; CHECK-NEXT:    ret i32 [[CONV]]
+;
+  %string = getelementptr inbounds [12 x i8], [12 x i8]* %buf, i64 0, i64 0
+  %call = call i32 @strcmp(i8* nonnull %string, i8* getelementptr inbounds ([4 x i8], [4 x i8]* @key, i64 0, i64 0))
+  %cmp = icmp eq i32 %call, 0
+  %conv = zext i1 %cmp to i32
+  ret i32 %conv
+}
+
+declare i32 @memcmp(i8* nocapture, i8* nocapture, i64)

Added: llvm/trunk/test/Transforms/InstCombine/strcpy-1.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/strcpy-1.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/strcpy-1.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/strcpy-1.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,45 @@
+; Test that the strcpy library call simplifier works correctly.
+; rdar://6839935
+; RUN: opt < %s -instcombine -S | FileCheck %s
+;
+; This transformation requires the pointer size, as it assumes that size_t is
+; the size of a pointer.
+target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:128:128-n8:16:32"
+
+ at hello = constant [6 x i8] c"hello\00"
+ at a = common global [32 x i8] zeroinitializer, align 1
+ at b = common global [32 x i8] zeroinitializer, align 1
+
+declare i8* @strcpy(i8*, i8*)
+
+define void @test_simplify1() {
+; CHECK-LABEL: @test_simplify1(
+
+  %dst = getelementptr [32 x i8], [32 x i8]* @a, i32 0, i32 0
+  %src = getelementptr [6 x i8], [6 x i8]* @hello, i32 0, i32 0
+
+  call i8* @strcpy(i8* %dst, i8* %src)
+; CHECK: @llvm.memcpy.p0i8.p0i8.i32
+  ret void
+}
+
+define i8* @test_simplify2() {
+; CHECK-LABEL: @test_simplify2(
+
+  %dst = getelementptr [32 x i8], [32 x i8]* @a, i32 0, i32 0
+
+  %ret = call i8* @strcpy(i8* %dst, i8* %dst)
+; CHECK: ret i8* getelementptr inbounds ([32 x i8], [32 x i8]* @a, i32 0, i32 0)
+  ret i8* %ret
+}
+
+define i8* @test_no_simplify1() {
+; CHECK-LABEL: @test_no_simplify1(
+
+  %dst = getelementptr [32 x i8], [32 x i8]* @a, i32 0, i32 0
+  %src = getelementptr [32 x i8], [32 x i8]* @b, i32 0, i32 0
+
+  %ret = call i8* @strcpy(i8* %dst, i8* %src)
+; CHECK: call i8* @strcpy
+  ret i8* %ret
+}

Added: llvm/trunk/test/Transforms/InstCombine/strcpy-2.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/strcpy-2.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/strcpy-2.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/strcpy-2.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,22 @@
+; Test that the strcpy library call simplifier works correctly.
+; RUN: opt < %s -instcombine -S | FileCheck %s
+;
+; This transformation requires the pointer size, as it assumes that size_t is
+; the size of a pointer.
+target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:128:128-n8:16:32"
+
+ at hello = constant [6 x i8] c"hello\00"
+ at a = common global [32 x i8] zeroinitializer, align 1
+
+declare i16* @strcpy(i8*, i8*)
+
+define void @test_no_simplify1() {
+; CHECK-LABEL: @test_no_simplify1(
+
+  %dst = getelementptr [32 x i8], [32 x i8]* @a, i32 0, i32 0
+  %src = getelementptr [6 x i8], [6 x i8]* @hello, i32 0, i32 0
+
+  call i16* @strcpy(i8* %dst, i8* %src)
+; CHECK: call i16* @strcpy
+  ret void
+}

Added: llvm/trunk/test/Transforms/InstCombine/strcpy_chk-1.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/strcpy_chk-1.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/strcpy_chk-1.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/strcpy_chk-1.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,103 @@
+; Test lib call simplification of __strcpy_chk calls with various values
+; for src, dst, and slen.
+;
+; 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"
+
+ at a = common global [60 x i8] zeroinitializer, align 1
+ at b = common global [60 x i8] zeroinitializer, align 1
+ at .str = private constant [12 x i8] c"abcdefghijk\00"
+
+; Check cases where slen >= strlen (src).
+
+define i8* @test_simplify1() {
+; CHECK-LABEL: @test_simplify1(
+  %dst = getelementptr inbounds [60 x i8], [60 x i8]* @a, i32 0, i32 0
+  %src = getelementptr inbounds [12 x i8], [12 x i8]* @.str, i32 0, i32 0
+
+; CHECK-NEXT: call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 1 getelementptr inbounds ([60 x i8], [60 x i8]* @a, i32 0, i32 0), i8* align 1 getelementptr inbounds ([12 x i8], [12 x i8]* @.str, i32 0, i32 0), i32 12, i1 false)
+; CHECK-NEXT: ret i8* getelementptr inbounds ([60 x i8], [60 x i8]* @a, i32 0, i32 0)
+  %ret = call i8* @__strcpy_chk(i8* %dst, i8* %src, i32 60)
+  ret i8* %ret
+}
+
+define i8* @test_simplify2() {
+; CHECK-LABEL: @test_simplify2(
+  %dst = getelementptr inbounds [60 x i8], [60 x i8]* @a, i32 0, i32 0
+  %src = getelementptr inbounds [12 x i8], [12 x i8]* @.str, i32 0, i32 0
+
+; CHECK-NEXT: call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 1 getelementptr inbounds ([60 x i8], [60 x i8]* @a, i32 0, i32 0), i8* align 1 getelementptr inbounds ([12 x i8], [12 x i8]* @.str, i32 0, i32 0), i32 12, i1 false)
+; CHECK-NEXT: ret i8* getelementptr inbounds ([60 x i8], [60 x i8]* @a, i32 0, i32 0)
+  %ret = call i8* @__strcpy_chk(i8* %dst, i8* %src, i32 12)
+  ret i8* %ret
+}
+
+define i8* @test_simplify3() {
+; CHECK-LABEL: @test_simplify3(
+  %dst = getelementptr inbounds [60 x i8], [60 x i8]* @a, i32 0, i32 0
+  %src = getelementptr inbounds [12 x i8], [12 x i8]* @.str, i32 0, i32 0
+
+; CHECK-NEXT: call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 1 getelementptr inbounds ([60 x i8], [60 x i8]* @a, i32 0, i32 0), i8* align 1 getelementptr inbounds ([12 x i8], [12 x i8]* @.str, i32 0, i32 0), i32 12, i1 false)
+; CHECK-NEXT: ret i8* getelementptr inbounds ([60 x i8], [60 x i8]* @a, i32 0, i32 0)
+  %ret = call i8* @__strcpy_chk(i8* %dst, i8* %src, i32 -1)
+  ret i8* %ret
+}
+
+; Check cases where there are no string constants.
+
+define i8* @test_simplify4() {
+; CHECK-LABEL: @test_simplify4(
+  %dst = getelementptr inbounds [60 x i8], [60 x i8]* @a, i32 0, i32 0
+  %src = getelementptr inbounds [60 x i8], [60 x i8]* @b, i32 0, i32 0
+
+; CHECK-NEXT: %strcpy = call i8* @strcpy(i8* getelementptr inbounds ([60 x i8], [60 x i8]* @a, i32 0, i32 0), i8* getelementptr inbounds ([60 x i8], [60 x i8]* @b, i32 0, i32 0))
+; CHECK-NEXT: ret i8* %strcpy
+  %ret = call i8* @__strcpy_chk(i8* %dst, i8* %src, i32 -1)
+  ret i8* %ret
+}
+
+; Check case where the string length is not constant.
+
+define i8* @test_simplify5() {
+; CHECK-LABEL: @test_simplify5(
+  %dst = getelementptr inbounds [60 x i8], [60 x i8]* @a, i32 0, i32 0
+  %src = getelementptr inbounds [12 x i8], [12 x i8]* @.str, i32 0, i32 0
+
+; CHECK-NEXT: %len = call i32 @llvm.objectsize.i32.p0i8(i8* getelementptr inbounds ([60 x i8], [60 x i8]* @a, i32 0, i32 0), i1 false, i1 false, i1 false)
+; CHECK-NEXT: %1 = call i8* @__memcpy_chk(i8* getelementptr inbounds ([60 x i8], [60 x i8]* @a, i32 0, i32 0), i8* getelementptr inbounds ([12 x i8], [12 x i8]* @.str, i32 0, i32 0), i32 12, i32 %len)
+; CHECK-NEXT: ret i8* %1
+  %len = call i32 @llvm.objectsize.i32.p0i8(i8* %dst, i1 false, i1 false, i1 false)
+  %ret = call i8* @__strcpy_chk(i8* %dst, i8* %src, i32 %len)
+  ret i8* %ret
+}
+
+; Check case where the source and destination are the same.
+
+define i8* @test_simplify6() {
+; CHECK-LABEL: @test_simplify6(
+  %dst = getelementptr inbounds [60 x i8], [60 x i8]* @a, i32 0, i32 0
+
+; CHECK-NEXT: %len = call i32 @llvm.objectsize.i32.p0i8(i8* getelementptr inbounds ([60 x i8], [60 x i8]* @a, i32 0, i32 0), i1 false, i1 false, i1 false)
+; CHECK-NEXT: %ret = call i8* @__strcpy_chk(i8* getelementptr inbounds ([60 x i8], [60 x i8]* @a, i32 0, i32 0), i8* getelementptr inbounds ([60 x i8], [60 x i8]* @a, i32 0, i32 0), i32 %len)
+; CHECK-NEXT: ret i8* %ret
+  %len = call i32 @llvm.objectsize.i32.p0i8(i8* %dst, i1 false, i1 false, i1 false)
+  %ret = call i8* @__strcpy_chk(i8* %dst, i8* %dst, i32 %len)
+  ret i8* %ret
+}
+
+; Check case where slen < strlen (src).
+
+define i8* @test_no_simplify1() {
+; CHECK-LABEL: @test_no_simplify1(
+  %dst = getelementptr inbounds [60 x i8], [60 x i8]* @a, i32 0, i32 0
+  %src = getelementptr inbounds [60 x i8], [60 x i8]* @b, i32 0, i32 0
+
+; CHECK-NEXT: %ret = call i8* @__strcpy_chk(i8* getelementptr inbounds ([60 x i8], [60 x i8]* @a, i32 0, i32 0), i8* getelementptr inbounds ([60 x i8], [60 x i8]* @b, i32 0, i32 0), i32 8)
+; CHECK-NEXT: ret i8* %ret
+  %ret = call i8* @__strcpy_chk(i8* %dst, i8* %src, i32 8)
+  ret i8* %ret
+}
+
+declare i8* @__strcpy_chk(i8*, i8*, i32) nounwind
+declare i32 @llvm.objectsize.i32.p0i8(i8*, i1, i1, i1) nounwind readonly

Added: llvm/trunk/test/Transforms/InstCombine/strcpy_chk-2.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/strcpy_chk-2.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/strcpy_chk-2.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/strcpy_chk-2.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,21 @@
+; Test that lib call simplification doesn't simplify __strcpy_chk calls
+; with the wrong prototype.
+;
+; 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"
+
+ at a = common global [60 x i16] zeroinitializer, align 1
+ at .str = private constant [8 x i8] c"abcdefg\00"
+
+define void @test_no_simplify() {
+; CHECK-LABEL: @test_no_simplify(
+  %dst = getelementptr inbounds [60 x i16], [60 x i16]* @a, i32 0, i32 0
+  %src = getelementptr inbounds [8 x i8], [8 x i8]* @.str, i32 0, i32 0
+
+; CHECK-NEXT: call i16* @__strcpy_chk
+  call i16* @__strcpy_chk(i16* %dst, i8* %src, i32 8)
+  ret void
+}
+
+declare i16* @__strcpy_chk(i16*, i8*, i32)

Added: llvm/trunk/test/Transforms/InstCombine/strcpy_chk-64.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/strcpy_chk-64.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/strcpy_chk-64.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/strcpy_chk-64.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,31 @@
+; 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-apple-darwin10.0.0"
+
+define void @func(i8* %i) nounwind ssp {
+; CHECK-LABEL: @func(
+; CHECK: @__strcpy_chk(i8* nonnull %arraydecay, i8* %i, i64 32)
+entry:
+  %s = alloca [32 x i8], align 16
+  %arraydecay = getelementptr inbounds [32 x i8], [32 x i8]* %s, i32 0, i32 0
+  %call = call i8* @__strcpy_chk(i8* %arraydecay, i8* %i, i64 32)
+  call void @func2(i8* %arraydecay)
+  ret void
+}
+
+define void @func_no_null_opt(i8* %i) nounwind ssp #0 {
+; CHECK-LABEL: @func_no_null_opt(
+; CHECK: @__strcpy_chk(i8* %arraydecay, i8* %i, i64 32)
+entry:
+  %s = alloca [32 x i8], align 16
+  %arraydecay = getelementptr inbounds [32 x i8], [32 x i8]* %s, i32 0, i32 0
+  %call = call i8* @__strcpy_chk(i8* %arraydecay, i8* %i, i64 32)
+  call void @func2(i8* %arraydecay)
+  ret void
+}
+
+declare i8* @__strcpy_chk(i8*, i8*, i64) nounwind
+
+declare void @func2(i8*)
+
+attributes #0 = { "null-pointer-is-valid"="true" }

Added: llvm/trunk/test/Transforms/InstCombine/strcspn-1.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/strcspn-1.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/strcspn-1.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/strcspn-1.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,57 @@
+; Test that the strcspn library call simplifier works correctly.
+;
+; 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"
+
+ at abcba = constant [6 x i8] c"abcba\00"
+ at abc = constant [4 x i8] c"abc\00"
+ at null = constant [1 x i8] zeroinitializer
+
+declare i64 @strcspn(i8*, i8*)
+
+; Check strcspn(s, "") -> strlen(s).
+
+define i64 @test_simplify1(i8* %str) {
+; CHECK-LABEL: @test_simplify1(
+  %pat = getelementptr [1 x i8], [1 x i8]* @null, i32 0, i32 0
+
+  %ret = call i64 @strcspn(i8* %str, i8* %pat)
+; CHECK-NEXT: [[VAR:%[a-z]+]] = call i64 @strlen(i8* %str)
+  ret i64 %ret
+; CHECK-NEXT: ret i64 [[VAR]]
+}
+
+; Check strcspn("", s) -> 0.
+
+define i64 @test_simplify2(i8* %pat) {
+; CHECK-LABEL: @test_simplify2(
+  %str = getelementptr [1 x i8], [1 x i8]* @null, i32 0, i32 0
+
+  %ret = call i64 @strcspn(i8* %str, i8* %pat)
+  ret i64 %ret
+; CHECK-NEXT: ret i64 0
+}
+
+; Check strcspn(s1, s2), where s1 and s2 are constants.
+
+define i64 @test_simplify3() {
+; CHECK-LABEL: @test_simplify3(
+  %str = getelementptr [6 x i8], [6 x i8]* @abcba, i32 0, i32 0
+  %pat = getelementptr [4 x i8], [4 x i8]* @abc, i32 0, i32 0
+
+  %ret = call i64 @strcspn(i8* %str, i8* %pat)
+  ret i64 %ret
+; CHECK-NEXT: ret i64 0
+}
+
+; Check cases that shouldn't be simplified.
+
+define i64 @test_no_simplify1(i8* %str, i8* %pat) {
+; CHECK-LABEL: @test_no_simplify1(
+
+  %ret = call i64 @strcspn(i8* %str, i8* %pat)
+; CHECK-NEXT: %ret = call i64 @strcspn(i8* %str, i8* %pat)
+  ret i64 %ret
+; CHECK-NEXT: ret i64 %ret
+}

Added: llvm/trunk/test/Transforms/InstCombine/strcspn-2.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/strcspn-2.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/strcspn-2.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/strcspn-2.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,21 @@
+; Test that the strcspn library call simplifier works correctly.
+;
+; 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"
+
+ at null = constant [1 x i8] zeroinitializer
+
+declare double @strcspn(i8*, i8*)
+
+; Check that strcspn functions with the wrong prototype aren't simplified.
+
+define double @test_no_simplify1(i8* %pat) {
+; CHECK-LABEL: @test_no_simplify1(
+  %str = getelementptr [1 x i8], [1 x i8]* @null, i32 0, i32 0
+
+  %ret = call double @strcspn(i8* %str, i8* %pat)
+; CHECK-NEXT: call double @strcspn
+  ret double %ret
+; CHECK-NEXT: ret double %ret
+}

Added: llvm/trunk/test/Transforms/InstCombine/strlen-1.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/strlen-1.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/strlen-1.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/strlen-1.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,204 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; Test that the strlen 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"
+
+ at hello = constant [6 x i8] c"hello\00"
+ at longer = constant [7 x i8] c"longer\00"
+ at null = constant [1 x i8] zeroinitializer
+ at null_hello = constant [7 x i8] c"\00hello\00"
+ at nullstring = constant i8 0
+ at a = common global [32 x i8] zeroinitializer, align 1
+ at null_hello_mid = constant [13 x i8] c"hello wor\00ld\00"
+
+declare i32 @strlen(i8*)
+
+; Check strlen(string constant) -> integer constant.
+
+define i32 @test_simplify1() {
+; CHECK-LABEL: @test_simplify1(
+; CHECK-NEXT:    ret i32 5
+;
+  %hello_p = getelementptr [6 x i8], [6 x i8]* @hello, i32 0, i32 0
+  %hello_l = call i32 @strlen(i8* %hello_p)
+  ret i32 %hello_l
+}
+
+define i32 @test_simplify2() {
+; CHECK-LABEL: @test_simplify2(
+; CHECK-NEXT:    ret i32 0
+;
+  %null_p = getelementptr [1 x i8], [1 x i8]* @null, i32 0, i32 0
+  %null_l = call i32 @strlen(i8* %null_p)
+  ret i32 %null_l
+}
+
+define i32 @test_simplify3() {
+; CHECK-LABEL: @test_simplify3(
+; CHECK-NEXT:    ret i32 0
+;
+  %null_hello_p = getelementptr [7 x i8], [7 x i8]* @null_hello, i32 0, i32 0
+  %null_hello_l = call i32 @strlen(i8* %null_hello_p)
+  ret i32 %null_hello_l
+}
+
+define i32 @test_simplify4() {
+; CHECK-LABEL: @test_simplify4(
+; CHECK-NEXT:    ret i32 0
+;
+  %len = tail call i32 @strlen(i8* @nullstring) nounwind
+  ret i32 %len
+}
+
+; Check strlen(x) == 0 --> *x == 0.
+
+define i1 @test_simplify5() {
+; CHECK-LABEL: @test_simplify5(
+; CHECK-NEXT:    ret i1 false
+;
+  %hello_p = getelementptr [6 x i8], [6 x i8]* @hello, i32 0, i32 0
+  %hello_l = call i32 @strlen(i8* %hello_p)
+  %eq_hello = icmp eq i32 %hello_l, 0
+  ret i1 %eq_hello
+}
+
+define i1 @test_simplify6(i8* %str_p) {
+; CHECK-LABEL: @test_simplify6(
+; CHECK-NEXT:    [[STRLENFIRST:%.*]] = load i8, i8* [[STR_P:%.*]], align 1
+; CHECK-NEXT:    [[EQ_NULL:%.*]] = icmp eq i8 [[STRLENFIRST]], 0
+; CHECK-NEXT:    ret i1 [[EQ_NULL]]
+;
+  %str_l = call i32 @strlen(i8* %str_p)
+  %eq_null = icmp eq i32 %str_l, 0
+  ret i1 %eq_null
+}
+
+; Check strlen(x) != 0 --> *x != 0.
+
+define i1 @test_simplify7() {
+; CHECK-LABEL: @test_simplify7(
+; CHECK-NEXT:    ret i1 true
+;
+  %hello_p = getelementptr [6 x i8], [6 x i8]* @hello, i32 0, i32 0
+  %hello_l = call i32 @strlen(i8* %hello_p)
+  %ne_hello = icmp ne i32 %hello_l, 0
+  ret i1 %ne_hello
+}
+
+define i1 @test_simplify8(i8* %str_p) {
+; CHECK-LABEL: @test_simplify8(
+; CHECK-NEXT:    [[STRLENFIRST:%.*]] = load i8, i8* [[STR_P:%.*]], align 1
+; CHECK-NEXT:    [[NE_NULL:%.*]] = icmp ne i8 [[STRLENFIRST]], 0
+; CHECK-NEXT:    ret i1 [[NE_NULL]]
+;
+  %str_l = call i32 @strlen(i8* %str_p)
+  %ne_null = icmp ne i32 %str_l, 0
+  ret i1 %ne_null
+}
+
+define i32 @test_simplify9(i1 %x) {
+; CHECK-LABEL: @test_simplify9(
+; CHECK-NEXT:    [[TMP1:%.*]] = select i1 %x, i32 5, i32 6
+; CHECK-NEXT:    ret i32 [[TMP1]]
+;
+  %hello = getelementptr [6 x i8], [6 x i8]* @hello, i32 0, i32 0
+  %longer = getelementptr [7 x i8], [7 x i8]* @longer, i32 0, i32 0
+  %s = select i1 %x, i8* %hello, i8* %longer
+  %l = call i32 @strlen(i8* %s)
+  ret i32 %l
+}
+
+; Check the case that should be simplified to a sub instruction.
+; strlen(@hello + x) --> 5 - x
+
+define i32 @test_simplify10(i32 %x) {
+; CHECK-LABEL: @test_simplify10(
+; CHECK-NEXT:    [[TMP1:%.*]] = sub i32 5, %x
+; CHECK-NEXT:    ret i32 [[TMP1]]
+;
+  %hello_p = getelementptr inbounds [6 x i8], [6 x i8]* @hello, i32 0, i32 %x
+  %hello_l = call i32 @strlen(i8* %hello_p)
+  ret i32 %hello_l
+}
+
+; strlen(@null_hello_mid + (x & 7)) --> 9 - (x & 7)
+
+define i32 @test_simplify11(i32 %x) {
+; CHECK-LABEL: @test_simplify11(
+; CHECK-NEXT:    [[AND:%.*]] = and i32 %x, 7
+; CHECK-NEXT:    [[TMP1:%.*]] = sub nuw nsw i32 9, [[AND]]
+; CHECK-NEXT:    ret i32 [[TMP1]]
+;
+  %and = and i32 %x, 7
+  %hello_p = getelementptr inbounds [13 x i8], [13 x i8]* @null_hello_mid, i32 0, i32 %and
+  %hello_l = call i32 @strlen(i8* %hello_p)
+  ret i32 %hello_l
+}
+
+; Check cases that shouldn't be simplified.
+
+define i32 @test_no_simplify1() {
+; CHECK-LABEL: @test_no_simplify1(
+; CHECK-NEXT:    [[A_L:%.*]] = call i32 @strlen(i8* getelementptr inbounds ([32 x i8], [32 x i8]* @a, i32 0, i32 0))
+; CHECK-NEXT:    ret i32 [[A_L]]
+;
+  %a_p = getelementptr [32 x i8], [32 x i8]* @a, i32 0, i32 0
+  %a_l = call i32 @strlen(i8* %a_p)
+  ret i32 %a_l
+}
+
+; strlen(@null_hello + x) should not be simplified to a sub instruction.
+
+define i32 @test_no_simplify2(i32 %x) {
+; CHECK-LABEL: @test_no_simplify2(
+; CHECK-NEXT:    [[HELLO_P:%.*]] = getelementptr inbounds [7 x i8], [7 x i8]* @null_hello, i32 0, i32 %x
+; CHECK-NEXT:    [[HELLO_L:%.*]] = call i32 @strlen(i8* nonnull [[HELLO_P]])
+; CHECK-NEXT:    ret i32 [[HELLO_L]]
+;
+  %hello_p = getelementptr inbounds [7 x i8], [7 x i8]* @null_hello, i32 0, i32 %x
+  %hello_l = call i32 @strlen(i8* %hello_p)
+  ret i32 %hello_l
+}
+
+define i32 @test_no_simplify2_no_null_opt(i32 %x) #0 {
+; CHECK-LABEL: @test_no_simplify2_no_null_opt(
+; CHECK-NEXT:    [[HELLO_P:%.*]] = getelementptr inbounds [7 x i8], [7 x i8]* @null_hello, i32 0, i32 %x
+; CHECK-NEXT:    [[HELLO_L:%.*]] = call i32 @strlen(i8* [[HELLO_P]])
+; CHECK-NEXT:    ret i32 [[HELLO_L]]
+;
+  %hello_p = getelementptr inbounds [7 x i8], [7 x i8]* @null_hello, i32 0, i32 %x
+  %hello_l = call i32 @strlen(i8* %hello_p)
+  ret i32 %hello_l
+}
+
+; strlen(@null_hello_mid + (x & 15)) should not be simplified to a sub instruction.
+
+define i32 @test_no_simplify3(i32 %x) {
+; CHECK-LABEL: @test_no_simplify3(
+; CHECK-NEXT:    [[AND:%.*]] = and i32 %x, 15
+; CHECK-NEXT:    [[HELLO_P:%.*]] = getelementptr inbounds [13 x i8], [13 x i8]* @null_hello_mid, i32 0, i32 [[AND]]
+; CHECK-NEXT:    [[HELLO_L:%.*]] = call i32 @strlen(i8* nonnull [[HELLO_P]])
+; CHECK-NEXT:    ret i32 [[HELLO_L]]
+;
+  %and = and i32 %x, 15
+  %hello_p = getelementptr inbounds [13 x i8], [13 x i8]* @null_hello_mid, i32 0, i32 %and
+  %hello_l = call i32 @strlen(i8* %hello_p)
+  ret i32 %hello_l
+}
+
+define i32 @test_no_simplify3_on_null_opt(i32 %x) #0 {
+; CHECK-LABEL: @test_no_simplify3_on_null_opt(
+; CHECK-NEXT:    [[AND:%.*]] = and i32 %x, 15
+; CHECK-NEXT:    [[HELLO_P:%.*]] = getelementptr inbounds [13 x i8], [13 x i8]* @null_hello_mid, i32 0, i32 [[AND]]
+; CHECK-NEXT:    [[HELLO_L:%.*]] = call i32 @strlen(i8* [[HELLO_P]])
+; CHECK-NEXT:    ret i32 [[HELLO_L]]
+;
+  %and = and i32 %x, 15
+  %hello_p = getelementptr inbounds [13 x i8], [13 x i8]* @null_hello_mid, i32 0, i32 %and
+  %hello_l = call i32 @strlen(i8* %hello_p)
+  ret i32 %hello_l
+}
+
+attributes #0 = { "null-pointer-is-valid"="true" }

Added: llvm/trunk/test/Transforms/InstCombine/strlen-2.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/strlen-2.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/strlen-2.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/strlen-2.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,18 @@
+; Test that the strlen 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"
+
+ at hello = constant [6 x i8] c"hello\00"
+
+declare i32 @strlen(i8*, i32)
+
+define i32 @test_no_simplify1() {
+; CHECK-LABEL: @test_no_simplify1(
+  %hello_p = getelementptr [6 x i8], [6 x i8]* @hello, i32 0, i32 0
+  %hello_l = call i32 @strlen(i8* %hello_p, i32 187)
+; CHECK-NEXT: %hello_l = call i32 @strlen
+  ret i32 %hello_l
+; CHECK-NEXT: ret i32 %hello_l
+}

Added: llvm/trunk/test/Transforms/InstCombine/strncat-1.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/strncat-1.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/strncat-1.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/strncat-1.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,37 @@
+; Test that the strncat libcall 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"
+
+ at hello = constant [6 x i8] c"hello\00"
+ at null = constant [1 x i8] zeroinitializer
+ at null_hello = constant [7 x i8] c"\00hello\00"
+
+declare i8* @strncat(i8*, i8*, i32)
+declare i32 @puts(i8*)
+
+define i32 @main() {
+; CHECK-LABEL: @main(
+; CHECK-NOT: call i8* @strncat
+; CHECK: call i32 @puts
+
+  %target = alloca [1024 x i8]
+  %arg1 = getelementptr [1024 x i8], [1024 x i8]* %target, i32 0, i32 0
+  store i8 0, i8* %arg1
+
+  ; rslt1 = strncat(target, "hello\00")
+  %arg2 = getelementptr [6 x i8], [6 x i8]* @hello, i32 0, i32 0
+  %rslt1 = call i8* @strncat(i8* %arg1, i8* %arg2, i32 6)
+
+  ; rslt2 = strncat(rslt1, "\00")
+  %arg3 = getelementptr [1 x i8], [1 x i8]* @null, i32 0, i32 0
+  %rslt2 = call i8* @strncat(i8* %rslt1, i8* %arg3, i32 42)
+
+  ; rslt3 = strncat(rslt2, "\00hello\00")
+  %arg4 = getelementptr [7 x i8], [7 x i8]* @null_hello, i32 0, i32 0
+  %rslt3 = call i8* @strncat(i8* %rslt2, i8* %arg4, i32 42)
+
+  call i32 @puts(i8* %rslt3)
+  ret i32 0
+}

Added: llvm/trunk/test/Transforms/InstCombine/strncat-2.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/strncat-2.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/strncat-2.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/strncat-2.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,53 @@
+; Test that the strncat libcall 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"
+
+ at hello = constant [6 x i8] c"hello\00"
+ at empty = constant [1 x i8] c"\00"
+ at a = common global [32 x i8] zeroinitializer, align 1
+
+declare i8* @strncat(i8*, i8*, i32)
+
+define void @test_simplify1() {
+; CHECK-LABEL: @test_simplify1(
+; CHECK-NOT: call i8* @strncat
+; CHECK: ret void
+
+  %dst = getelementptr [32 x i8], [32 x i8]* @a, i32 0, i32 0
+  %src = getelementptr [6 x i8], [6 x i8]* @hello, i32 0, i32 0
+  call i8* @strncat(i8* %dst, i8* %src, i32 13)
+  ret void
+}
+
+define void @test_simplify2() {
+; CHECK-LABEL: @test_simplify2(
+; CHECK-NEXT: ret void
+
+  %dst = getelementptr [32 x i8], [32 x i8]* @a, i32 0, i32 0
+  %src = getelementptr [1 x i8], [1 x i8]* @empty, i32 0, i32 0
+  call i8* @strncat(i8* %dst, i8* %src, i32 13)
+  ret void
+}
+
+define void @test_simplify3() {
+; CHECK-LABEL: @test_simplify3(
+; CHECK-NEXT: ret void
+
+  %dst = getelementptr [32 x i8], [32 x i8]* @a, i32 0, i32 0
+  %src = getelementptr [6 x i8], [6 x i8]* @hello, i32 0, i32 0
+  call i8* @strncat(i8* %dst, i8* %src, i32 0)
+  ret void
+}
+
+define void @test_nosimplify1() {
+; CHECK-LABEL: @test_nosimplify1(
+; CHECK: call i8* @strncat
+; CHECK: ret void
+
+  %dst = getelementptr [32 x i8], [32 x i8]* @a, i32 0, i32 0
+  %src = getelementptr [6 x i8], [6 x i8]* @hello, i32 0, i32 0
+  call i8* @strncat(i8* %dst, i8* %src, i32 1)
+  ret void
+}

Added: llvm/trunk/test/Transforms/InstCombine/strncat-3.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/strncat-3.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/strncat-3.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/strncat-3.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,22 @@
+; Test that the strncat libcall 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"
+
+ at hello = constant [6 x i8] c"hello\00"
+ at empty = constant [1 x i8] c"\00"
+ at a = common global [32 x i8] zeroinitializer, align 1
+
+declare i16* @strncat(i8*, i8*, i32)
+
+define void @test_nosimplify1() {
+; CHECK-LABEL: @test_nosimplify1(
+; CHECK: call i16* @strncat
+; CHECK: ret void
+
+  %dst = getelementptr [32 x i8], [32 x i8]* @a, i32 0, i32 0
+  %src = getelementptr [6 x i8], [6 x i8]* @hello, i32 0, i32 0
+  call i16* @strncat(i8* %dst, i8* %src, i32 13)
+  ret void
+}

Added: llvm/trunk/test/Transforms/InstCombine/strncmp-1.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/strncmp-1.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/strncmp-1.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/strncmp-1.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,99 @@
+; Test that the strncmp 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"
+
+ at hello = constant [6 x i8] c"hello\00"
+ at hell = constant [5 x i8] c"hell\00"
+ at bell = constant [5 x i8] c"bell\00"
+ at null = constant [1 x i8] zeroinitializer
+
+declare i32 @strncmp(i8*, i8*, i32)
+
+; strncmp("", x, n) -> -*x
+define i32 @test1(i8* %str2) {
+; CHECK-LABEL: @test1(
+; CHECK: %strcmpload = load i8, i8* %str
+; CHECK: %1 = zext i8 %strcmpload to i32
+; CHECK: %2 = sub nsw i32 0, %1
+; CHECK: ret i32 %2
+
+  %str1 = getelementptr inbounds [1 x i8], [1 x i8]* @null, i32 0, i32 0
+  %temp1 = call i32 @strncmp(i8* %str1, i8* %str2, i32 10)
+  ret i32 %temp1
+}
+
+; strncmp(x, "", n) -> *x
+define i32 @test2(i8* %str1) {
+; CHECK-LABEL: @test2(
+; CHECK: %strcmpload = load i8, i8* %str1
+; CHECK: %1 = zext i8 %strcmpload to i32
+; CHECK: ret i32 %1
+
+  %str2 = getelementptr inbounds [1 x i8], [1 x i8]* @null, i32 0, i32 0
+  %temp1 = call i32 @strncmp(i8* %str1, i8* %str2, i32 10)
+  ret i32 %temp1
+}
+
+; strncmp(x, y, n)  -> cnst
+define i32 @test3() {
+; CHECK-LABEL: @test3(
+; CHECK: ret i32 -1
+
+  %str1 = getelementptr inbounds [5 x i8], [5 x i8]* @hell, i32 0, i32 0
+  %str2 = getelementptr inbounds [6 x i8], [6 x i8]* @hello, i32 0, i32 0
+  %temp1 = call i32 @strncmp(i8* %str1, i8* %str2, i32 10)
+  ret i32 %temp1
+}
+
+define i32 @test4() {
+; CHECK-LABEL: @test4(
+; CHECK: ret i32 1
+
+  %str1 = getelementptr inbounds [5 x i8], [5 x i8]* @hell, i32 0, i32 0
+  %str2 = getelementptr inbounds [1 x i8], [1 x i8]* @null, i32 0, i32 0
+  %temp1 = call i32 @strncmp(i8* %str1, i8* %str2, i32 10)
+  ret i32 %temp1
+}
+
+define i32 @test5() {
+; CHECK-LABEL: @test5(
+; CHECK: ret i32 0
+
+  %str1 = getelementptr inbounds [5 x i8], [5 x i8]* @hell, i32 0, i32 0
+  %str2 = getelementptr inbounds [6 x i8], [6 x i8]* @hello, i32 0, i32 0
+  %temp1 = call i32 @strncmp(i8* %str1, i8* %str2, i32 4)
+  ret i32 %temp1
+}
+
+; strncmp(x,y,1) -> memcmp(x,y,1)
+define i32 @test6(i8* %str1, i8* %str2) {
+; CHECK-LABEL: @test6(
+; CHECK: [[LOAD1:%[a-z]+]] = load i8, i8* %str1, align 1
+; CHECK: [[ZEXT1:%[a-z]+]] = zext i8 [[LOAD1]] to i32
+; CHECK: [[LOAD2:%[a-z]+]] = load i8, i8* %str2, align 1
+; CHECK: [[ZEXT2:%[a-z]+]] = zext i8 [[LOAD2]] to i32
+; CHECK: [[RET:%[a-z]+]] = sub nsw i32 [[ZEXT1]], [[ZEXT2]]
+; CHECK: ret i32 [[RET]]
+
+  %temp1 = call i32 @strncmp(i8* %str1, i8* %str2, i32 1)
+  ret i32 %temp1
+}
+
+; strncmp(x,y,0)   -> 0
+define i32 @test7(i8* %str1, i8* %str2) {
+; CHECK-LABEL: @test7(
+; CHECK: ret i32 0
+
+  %temp1 = call i32 @strncmp(i8* %str1, i8* %str2, i32 0)
+  ret i32 %temp1
+}
+
+; strncmp(x,x,n)  -> 0
+define i32 @test8(i8* %str, i32 %n) {
+; CHECK-LABEL: @test8(
+; CHECK: ret i32 0
+
+  %temp1 = call i32 @strncmp(i8* %str, i8* %str, i32 %n)
+  ret i32 %temp1
+}

Added: llvm/trunk/test/Transforms/InstCombine/strncmp-2.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/strncmp-2.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/strncmp-2.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/strncmp-2.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,20 @@
+; Test that the strncmp 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"
+
+ at hello = constant [6 x i8] c"hello\00"
+ at hell = constant [5 x i8] c"hell\00"
+
+declare i16 @strncmp(i8*, i8*, i32)
+
+define i16 @test_nosimplify() {
+; CHECK-LABEL: @test_nosimplify(
+; CHECK: call i16 @strncmp
+; CHECK: ret i16 %temp1
+
+  %str1 = getelementptr inbounds [5 x i8], [5 x i8]* @hell, i32 0, i32 0
+  %str2 = getelementptr inbounds [6 x i8], [6 x i8]* @hello, i32 0, i32 0
+  %temp1 = call i16 @strncmp(i8* %str1, i8* %str2, i32 10)
+  ret i16 %temp1
+}

Added: llvm/trunk/test/Transforms/InstCombine/strncmp-wrong-datalayout.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/strncmp-wrong-datalayout.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/strncmp-wrong-datalayout.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/strncmp-wrong-datalayout.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,16 @@
+; Test that the strncpy simplification doesn't crash if datalayout specifies
+; 64 bit pointers while length is a 32 bit argument
+;
+; RUN: opt < %s -instcombine -S | FileCheck %s
+
+target datalayout = "e-p:64:64:64"
+
+declare i32 @strncmp(i8*, i8*, i32)
+
+define i32 @test6(i8* %str1, i8* %str2) {
+; CHECK-LABEL: @test6(
+; CHECK: call i32 @strncmp(i8* %str1, i8* %str2, i32 1)
+
+  %temp1 = call i32 @strncmp(i8* %str1, i8* %str2, i32 1)
+  ret i32 %temp1
+}

Added: llvm/trunk/test/Transforms/InstCombine/strncpy-1.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/strncpy-1.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/strncpy-1.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/strncpy-1.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,95 @@
+; Test that the strncpy 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"
+
+ at hello = constant [6 x i8] c"hello\00"
+ at null = constant [1 x i8] zeroinitializer
+ at null_hello = constant [7 x i8] c"\00hello\00"
+ at a = common global [32 x i8] zeroinitializer, align 1
+ at b = common global [32 x i8] zeroinitializer, align 1
+
+declare i8* @strncpy(i8*, i8*, i32)
+declare i32 @puts(i8*)
+
+; Check a bunch of strncpy invocations together.
+
+define i32 @test_simplify1() {
+; CHECK-LABEL: @test_simplify1(
+; CHECK-NOT: call i8* @strncpy
+; CHECK: call i32 @puts
+  %target = alloca [1024 x i8]
+  %arg1 = getelementptr [1024 x i8], [1024 x i8]* %target, i32 0, i32 0
+  store i8 0, i8* %arg1
+
+  %arg2 = getelementptr [6 x i8], [6 x i8]* @hello, i32 0, i32 0
+  %rslt1 = call i8* @strncpy(i8* %arg1, i8* %arg2, i32 6)
+
+  %arg3 = getelementptr [1 x i8], [1 x i8]* @null, i32 0, i32 0
+  %rslt2 = call i8* @strncpy(i8* %rslt1, i8* %arg3, i32 42)
+
+  %arg4 = getelementptr [7 x i8], [7 x i8]* @null_hello, i32 0, i32 0
+  %rslt3 = call i8* @strncpy(i8* %rslt2, i8* %arg4, i32 42)
+
+  call i32 @puts( i8* %rslt3 )
+  ret i32 0
+}
+
+; Check strncpy(x, "", y) -> memset(x, '\0', y, 1).
+
+define void @test_simplify2() {
+; CHECK-LABEL: @test_simplify2(
+  %dst = getelementptr [32 x i8], [32 x i8]* @a, i32 0, i32 0
+  %src = getelementptr [1 x i8], [1 x i8]* @null, i32 0, i32 0
+
+  call i8* @strncpy(i8* %dst, i8* %src, i32 32)
+; CHECK: call void @llvm.memset.p0i8.i32
+  ret void
+}
+
+; Check strncpy(x, y, 0) -> x.
+
+define i8* @test_simplify3() {
+; CHECK-LABEL: @test_simplify3(
+  %dst = getelementptr [32 x i8], [32 x i8]* @a, i32 0, i32 0
+  %src = getelementptr [6 x i8], [6 x i8]* @hello, i32 0, i32 0
+
+  %ret = call i8* @strncpy(i8* %dst, i8* %src, i32 0)
+  ret i8* %ret
+; CHECK: ret i8* getelementptr inbounds ([32 x i8], [32 x i8]* @a, i32 0, i32 0)
+}
+
+; Check  strncpy(x, s, c) -> memcpy(x, s, c, 1) [s and c are constant].
+
+define void @test_simplify4() {
+; CHECK-LABEL: @test_simplify4(
+  %dst = getelementptr [32 x i8], [32 x i8]* @a, i32 0, i32 0
+  %src = getelementptr [6 x i8], [6 x i8]* @hello, i32 0, i32 0
+
+  call i8* @strncpy(i8* %dst, i8* %src, i32 6)
+; CHECK: call void @llvm.memcpy.p0i8.p0i8.i32
+  ret void
+}
+
+; Check cases that shouldn't be simplified.
+
+define void @test_no_simplify1() {
+; CHECK-LABEL: @test_no_simplify1(
+  %dst = getelementptr [32 x i8], [32 x i8]* @a, i32 0, i32 0
+  %src = getelementptr [32 x i8], [32 x i8]* @b, i32 0, i32 0
+
+  call i8* @strncpy(i8* %dst, i8* %src, i32 32)
+; CHECK: call i8* @strncpy
+  ret void
+}
+
+define void @test_no_simplify2() {
+; CHECK-LABEL: @test_no_simplify2(
+  %dst = getelementptr [32 x i8], [32 x i8]* @a, i32 0, i32 0
+  %src = getelementptr [6 x i8], [6 x i8]* @hello, i32 0, i32 0
+
+  call i8* @strncpy(i8* %dst, i8* %src, i32 8)
+; CHECK: call i8* @strncpy
+  ret void
+}

Added: llvm/trunk/test/Transforms/InstCombine/strncpy-2.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/strncpy-2.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/strncpy-2.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/strncpy-2.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,22 @@
+; Test that the strncpy 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"
+
+ at hello = constant [6 x i8] c"hello\00"
+ at a = common global [32 x i8] zeroinitializer, align 1
+
+declare i16* @strncpy(i8*, i8*, i32)
+
+; Check that 'strncpy' functions with the wrong prototype aren't simplified.
+
+define void @test_no_simplify1() {
+; CHECK-LABEL: @test_no_simplify1(
+  %dst = getelementptr [32 x i8], [32 x i8]* @a, i32 0, i32 0
+  %src = getelementptr [6 x i8], [6 x i8]* @hello, i32 0, i32 0
+
+  call i16* @strncpy(i8* %dst, i8* %src, i32 6)
+; CHECK: call i16* @strncpy
+  ret void
+}

Added: llvm/trunk/test/Transforms/InstCombine/strncpy_chk-1.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/strncpy_chk-1.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/strncpy_chk-1.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/strncpy_chk-1.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,71 @@
+; Test lib call simplification of __strncpy_chk calls with various values
+; for len and dstlen.
+;
+; 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"
+
+ at a = common global [60 x i8] zeroinitializer, align 1
+ at b = common global [60 x i8] zeroinitializer, align 1
+ at .str = private constant [12 x i8] c"abcdefghijk\00"
+
+; Check cases where dstlen >= len
+
+define i8* @test_simplify1() {
+; CHECK-LABEL: @test_simplify1(
+  %dst = getelementptr inbounds [60 x i8], [60 x i8]* @a, i32 0, i32 0
+  %src = getelementptr inbounds [12 x i8], [12 x i8]* @.str, i32 0, i32 0
+
+; CHECK-NEXT: call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 1 getelementptr inbounds ([60 x i8], [60 x i8]* @a, i32 0, i32 0), i8* align 1 getelementptr inbounds ([12 x i8], [12 x i8]* @.str, i32 0, i32 0), i32 12, i1 false)
+; CHECK-NEXT: ret i8* getelementptr inbounds ([60 x i8], [60 x i8]* @a, i32 0, i32 0)
+  %ret = call i8* @__strncpy_chk(i8* %dst, i8* %src, i32 12, i32 60)
+  ret i8* %ret
+}
+
+define i8* @test_simplify2() {
+; CHECK-LABEL: @test_simplify2(
+  %dst = getelementptr inbounds [60 x i8], [60 x i8]* @a, i32 0, i32 0
+  %src = getelementptr inbounds [12 x i8], [12 x i8]* @.str, i32 0, i32 0
+
+; CHECK-NEXT: call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 1 getelementptr inbounds ([60 x i8], [60 x i8]* @a, i32 0, i32 0), i8* align 1 getelementptr inbounds ([12 x i8], [12 x i8]* @.str, i32 0, i32 0), i32 12, i1 false)
+; CHECK-NEXT: ret i8* getelementptr inbounds ([60 x i8], [60 x i8]* @a, i32 0, i32 0)
+  %ret = call i8* @__strncpy_chk(i8* %dst, i8* %src, i32 12, i32 12)
+  ret i8* %ret
+}
+
+define i8* @test_simplify3() {
+; CHECK-LABEL: @test_simplify3(
+  %dst = getelementptr inbounds [60 x i8], [60 x i8]* @a, i32 0, i32 0
+  %src = getelementptr inbounds [60 x i8], [60 x i8]* @b, i32 0, i32 0
+
+; CHECK-NEXT: %strncpy = call i8* @strncpy(i8* getelementptr inbounds ([60 x i8], [60 x i8]* @a, i32 0, i32 0), i8* getelementptr inbounds ([60 x i8], [60 x i8]* @b, i32 0, i32 0), i32 12)
+; CHECK-NEXT: ret i8* %strncpy
+  %ret = call i8* @__strncpy_chk(i8* %dst, i8* %src, i32 12, i32 60)
+  ret i8* %ret
+}
+
+; Check cases where dstlen < len
+
+define i8* @test_no_simplify1() {
+; CHECK-LABEL: @test_no_simplify1(
+  %dst = getelementptr inbounds [60 x i8], [60 x i8]* @a, i32 0, i32 0
+  %src = getelementptr inbounds [12 x i8], [12 x i8]* @.str, i32 0, i32 0
+
+; CHECK-NEXT: %ret = call i8* @__strncpy_chk(i8* getelementptr inbounds ([60 x i8], [60 x i8]* @a, i32 0, i32 0), i8* getelementptr inbounds ([12 x i8], [12 x i8]* @.str, i32 0, i32 0), i32 8, i32 4)
+; CHECK-NEXT: ret i8* %ret
+  %ret = call i8* @__strncpy_chk(i8* %dst, i8* %src, i32 8, i32 4)
+  ret i8* %ret
+}
+
+define i8* @test_no_simplify2() {
+; CHECK-LABEL: @test_no_simplify2(
+  %dst = getelementptr inbounds [60 x i8], [60 x i8]* @a, i32 0, i32 0
+  %src = getelementptr inbounds [60 x i8], [60 x i8]* @b, i32 0, i32 0
+
+; CHECK-NEXT: %ret = call i8* @__strncpy_chk(i8* getelementptr inbounds ([60 x i8], [60 x i8]* @a, i32 0, i32 0), i8* getelementptr inbounds ([60 x i8], [60 x i8]* @b, i32 0, i32 0), i32 8, i32 0)
+; CHECK-NEXT: ret i8* %ret
+  %ret = call i8* @__strncpy_chk(i8* %dst, i8* %src, i32 8, i32 0)
+  ret i8* %ret
+}
+
+declare i8* @__strncpy_chk(i8*, i8*, i32, i32)

Added: llvm/trunk/test/Transforms/InstCombine/strncpy_chk-2.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/strncpy_chk-2.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/strncpy_chk-2.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/strncpy_chk-2.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,21 @@
+; Test that lib call simplification doesn't simplify __strncpy_chk calls
+; with the wrong prototype.
+;
+; 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"
+
+ at a = common global [60 x i16] zeroinitializer, align 1
+ at b = common global [60 x i16] zeroinitializer, align 1
+
+define void @test_no_simplify() {
+; CHECK-LABEL: @test_no_simplify(
+  %dst = getelementptr inbounds [60 x i16], [60 x i16]* @a, i32 0, i32 0
+  %src = getelementptr inbounds [60 x i16], [60 x i16]* @b, i32 0, i32 0
+
+; CHECK-NEXT: call i16* @__strncpy_chk
+  call i16* @__strncpy_chk(i16* %dst, i16* %src, i32 60, i32 60)
+  ret void
+}
+
+declare i16* @__strncpy_chk(i16*, i16*, i32, i32)

Added: llvm/trunk/test/Transforms/InstCombine/strpbrk-1.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/strpbrk-1.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/strpbrk-1.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/strpbrk-1.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,68 @@
+; Test that the strpbrk 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"
+
+ at hello = constant [12 x i8] c"hello world\00"
+ at w = constant [2 x i8] c"w\00"
+ at null = constant [1 x i8] zeroinitializer
+
+declare i8* @strpbrk(i8*, i8*)
+
+; Check strpbrk(s, "") -> NULL.
+
+define i8* @test_simplify1(i8* %str) {
+; CHECK-LABEL: @test_simplify1(
+  %pat = getelementptr [1 x i8], [1 x i8]* @null, i32 0, i32 0
+
+  %ret = call i8* @strpbrk(i8* %str, i8* %pat)
+  ret i8* %ret
+; CHECK-NEXT: ret i8* null
+}
+
+; Check strpbrk("", s) -> NULL.
+
+define i8* @test_simplify2(i8* %pat) {
+; CHECK-LABEL: @test_simplify2(
+  %str = getelementptr [1 x i8], [1 x i8]* @null, i32 0, i32 0
+
+  %ret = call i8* @strpbrk(i8* %str, i8* %pat)
+  ret i8* %ret
+; CHECK-NEXT: ret i8* null
+}
+
+; Check strpbrk(s1, s2), where s1 and s2 are constants.
+
+define i8* @test_simplify3() {
+; CHECK-LABEL: @test_simplify3(
+  %str = getelementptr [12 x i8], [12 x i8]* @hello, i32 0, i32 0
+  %pat = getelementptr [2 x i8], [2 x i8]* @w, i32 0, i32 0
+
+  %ret = call i8* @strpbrk(i8* %str, i8* %pat)
+  ret i8* %ret
+; CHECK-NEXT: ret i8* getelementptr inbounds ([12 x i8], [12 x i8]* @hello, i32 0, i32 6)
+}
+
+; Check strpbrk(s, "a") -> strchr(s, 'a').
+
+define i8* @test_simplify4(i8* %str) {
+; CHECK-LABEL: @test_simplify4(
+  %pat = getelementptr [2 x i8], [2 x i8]* @w, i32 0, i32 0
+
+  %ret = call i8* @strpbrk(i8* %str, i8* %pat)
+; CHECK-NEXT: [[VAR:%[a-z]+]] = call i8* @strchr(i8* %str, i32 119)
+  ret i8* %ret
+; CHECK-NEXT: ret i8* [[VAR]]
+}
+
+; Check cases that shouldn't be simplified.
+
+define i8* @test_no_simplify1(i8* %str, i8* %pat) {
+; CHECK-LABEL: @test_no_simplify1(
+
+  %ret = call i8* @strpbrk(i8* %str, i8* %pat)
+; CHECK-NEXT: %ret = call i8* @strpbrk(i8* %str, i8* %pat)
+  ret i8* %ret
+; CHECK-NEXT: ret i8* %ret
+}

Added: llvm/trunk/test/Transforms/InstCombine/strpbrk-2.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/strpbrk-2.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/strpbrk-2.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/strpbrk-2.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,23 @@
+; Test that the strpbrk 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"
+
+ at hello = constant [12 x i8] c"hello world\00"
+ at w = constant [2 x i8] c"w\00"
+
+declare i16* @strpbrk(i8*, i8*)
+
+; Check that 'strpbrk' functions with the wrong prototype aren't simplified.
+
+define i16* @test_no_simplify1() {
+; CHECK-LABEL: @test_no_simplify1(
+  %str = getelementptr [12 x i8], [12 x i8]* @hello, i32 0, i32 0
+  %pat = getelementptr [2 x i8], [2 x i8]* @w, i32 0, i32 0
+
+  %ret = call i16* @strpbrk(i8* %str, i8* %pat)
+; CHECK-NEXT: %ret = call i16* @strpbrk
+  ret i16* %ret
+; CHECK-NEXT: ret i16* %ret
+}

Added: llvm/trunk/test/Transforms/InstCombine/strrchr-1.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/strrchr-1.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/strrchr-1.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/strrchr-1.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,65 @@
+; Test that the strrchr 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"
+
+ at hello = constant [14 x i8] c"hello world\5Cn\00"
+ at null = constant [1 x i8] zeroinitializer
+ at chp = global i8* zeroinitializer
+
+declare i8* @strrchr(i8*, i32)
+
+define void @test_simplify1() {
+; CHECK: store i8* getelementptr inbounds ([14 x i8], [14 x i8]* @hello, i32 0, i32 6)
+; CHECK-NOT: call i8* @strrchr
+; CHECK: ret void
+
+  %str = getelementptr [14 x i8], [14 x i8]* @hello, i32 0, i32 0
+  %dst = call i8* @strrchr(i8* %str, i32 119)
+  store i8* %dst, i8** @chp
+  ret void
+}
+
+define void @test_simplify2() {
+; CHECK: store i8* null, i8** @chp, align 4
+; CHECK-NOT: call i8* @strrchr
+; CHECK: ret void
+
+  %str = getelementptr [1 x i8], [1 x i8]* @null, i32 0, i32 0
+  %dst = call i8* @strrchr(i8* %str, i32 119)
+  store i8* %dst, i8** @chp
+  ret void
+}
+
+define void @test_simplify3() {
+; CHECK: store i8* getelementptr inbounds ([14 x i8], [14 x i8]* @hello, i32 0, i32 13)
+; CHECK-NOT: call i8* @strrchr
+; CHECK: ret void
+
+  %src = getelementptr [14 x i8], [14 x i8]* @hello, i32 0, i32 0
+  %dst = call i8* @strrchr(i8* %src, i32 0)
+  store i8* %dst, i8** @chp
+  ret void
+}
+
+define void @test_simplify4() {
+; CHECK: store i8* getelementptr inbounds ([14 x i8], [14 x i8]* @hello, i32 0, i32 13)
+; CHECK-NOT: call i8* @strrchr
+; CHECK: ret void
+
+  %src = getelementptr [14 x i8], [14 x i8]* @hello, i32 0, i32 0
+  %dst = call i8* @strrchr(i8* %src, i32 65280)
+  store i8* %dst, i8** @chp
+  ret void
+}
+
+define void @test_nosimplify1(i32 %chr) {
+; CHECK-LABEL: @test_nosimplify1(
+; CHECK: call i8* @strrchr
+; CHECK: ret void
+
+  %src = getelementptr [14 x i8], [14 x i8]* @hello, i32 0, i32 0
+  %dst = call i8* @strrchr(i8* %src, i32 %chr)
+  store i8* %dst, i8** @chp
+  ret void
+}

Added: llvm/trunk/test/Transforms/InstCombine/strrchr-2.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/strrchr-2.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/strrchr-2.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/strrchr-2.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,21 @@
+; Test that the strrchr libcall 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"
+
+ at hello = constant [14 x i8] c"hello world\5Cn\00"
+ at chr = global i8 zeroinitializer
+
+declare i8 @strrchr(i8*, i32)
+
+define void @test_nosimplify1() {
+; CHECK: test_nosimplify1
+; CHECK: call i8 @strrchr
+; CHECK: ret void
+
+  %str = getelementptr [14 x i8], [14 x i8]* @hello, i32 0, i32 0
+  %dst = call i8 @strrchr(i8* %str, i32 119)
+  store i8 %dst, i8* @chr
+  ret void
+}

Added: llvm/trunk/test/Transforms/InstCombine/strspn-1.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/strspn-1.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/strspn-1.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/strspn-1.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,56 @@
+; Test that the strspn 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"
+
+ at abcba = constant [6 x i8] c"abcba\00"
+ at abc = constant [4 x i8] c"abc\00"
+ at null = constant [1 x i8] zeroinitializer
+
+declare i64 @strspn(i8*, i8*)
+
+; Check strspn(s, "") -> 0.
+
+define i64 @test_simplify1(i8* %str) {
+; CHECK-LABEL: @test_simplify1(
+  %pat = getelementptr [1 x i8], [1 x i8]* @null, i32 0, i32 0
+
+  %ret = call i64 @strspn(i8* %str, i8* %pat)
+  ret i64 %ret
+; CHECK-NEXT: ret i64 0
+}
+
+; Check strspn("", s) -> 0.
+
+define i64 @test_simplify2(i8* %pat) {
+; CHECK-LABEL: @test_simplify2(
+  %str = getelementptr [1 x i8], [1 x i8]* @null, i32 0, i32 0
+
+  %ret = call i64 @strspn(i8* %str, i8* %pat)
+  ret i64 %ret
+; CHECK-NEXT: ret i64 0
+}
+
+; Check strspn(s1, s2), where s1 and s2 are constants.
+
+define i64 @test_simplify3() {
+; CHECK-LABEL: @test_simplify3(
+  %str = getelementptr [6 x i8], [6 x i8]* @abcba, i32 0, i32 0
+  %pat = getelementptr [4 x i8], [4 x i8]* @abc, i32 0, i32 0
+
+  %ret = call i64 @strspn(i8* %str, i8* %pat)
+  ret i64 %ret
+; CHECK-NEXT: ret i64 5
+}
+
+; Check cases that shouldn't be simplified.
+
+define i64 @test_no_simplify1(i8* %str, i8* %pat) {
+; CHECK-LABEL: @test_no_simplify1(
+
+  %ret = call i64 @strspn(i8* %str, i8* %pat)
+; CHECK-NEXT: %ret = call i64 @strspn(i8* %str, i8* %pat)
+  ret i64 %ret
+; CHECK-NEXT: ret i64 %ret
+}

Added: llvm/trunk/test/Transforms/InstCombine/strstr-1.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/strstr-1.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/strstr-1.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/strstr-1.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,65 @@
+; Test that the strstr library call simplifier works correctly.
+;
+; 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"
+
+ at .str = private constant [1 x i8] zeroinitializer
+ at .str1 = private constant [2 x i8] c"a\00"
+ at .str2 = private constant [6 x i8] c"abcde\00"
+ at .str3 = private constant [4 x i8] c"bcd\00"
+
+declare i8* @strstr(i8*, i8*)
+
+; Check strstr(str, "") -> str.
+
+define i8* @test_simplify1(i8* %str) {
+; CHECK-LABEL: @test_simplify1(
+  %pat = getelementptr inbounds [1 x i8], [1 x i8]* @.str, i32 0, i32 0
+  %ret = call i8* @strstr(i8* %str, i8* %pat)
+  ret i8* %ret
+; CHECK-NEXT: ret i8* %str
+}
+
+; Check strstr(str, "a") -> strchr(str, 'a').
+
+define i8* @test_simplify2(i8* %str) {
+; CHECK-LABEL: @test_simplify2(
+  %pat = getelementptr inbounds [2 x i8], [2 x i8]* @.str1, i32 0, i32 0
+  %ret = call i8* @strstr(i8* %str, i8* %pat)
+  ret i8* %ret
+; CHECK-NEXT: @strchr(i8* %str, i32 97)
+}
+
+; Check strstr("abcde", "bcd") -> "abcde" + 1.
+
+define i8* @test_simplify3() {
+; CHECK-LABEL: @test_simplify3(
+  %str = getelementptr inbounds [6 x i8], [6 x i8]* @.str2, i32 0, i32 0
+  %pat = getelementptr inbounds [4 x i8], [4 x i8]* @.str3, i32 0, i32 0
+  %ret = call i8* @strstr(i8* %str, i8* %pat)
+  ret i8* %ret
+; CHECK-NEXT: getelementptr inbounds ([6 x i8], [6 x i8]* @.str2, i64 0, i64 1)
+}
+
+; Check strstr(str, str) -> str.
+
+define i8* @test_simplify4(i8* %str) {
+; CHECK-LABEL: @test_simplify4(
+  %ret = call i8* @strstr(i8* %str, i8* %str)
+  ret i8* %ret
+; CHECK-NEXT: ret i8* %str
+}
+
+; Check strstr(str, pat) == str -> strncmp(str, pat, strlen(str)) == 0.
+
+define i1 @test_simplify5(i8* %str, i8* %pat) {
+; CHECK-LABEL: @test_simplify5(
+  %ret = call i8* @strstr(i8* %str, i8* %pat)
+  %cmp = icmp eq i8* %ret, %str
+  ret i1 %cmp
+; CHECK: [[LEN:%[a-z]+]] = call {{i[0-9]+}} @strlen(i8* %pat)
+; CHECK: [[NCMP:%[a-z]+]] = call {{i[0-9]+}} @strncmp(i8* %str, i8* %pat, {{i[0-9]+}} [[LEN]])
+; CHECK: icmp eq {{i[0-9]+}} [[NCMP]], 0
+; CHECK: ret i1
+}

Added: llvm/trunk/test/Transforms/InstCombine/strstr-2.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/strstr-2.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/strstr-2.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/strstr-2.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,18 @@
+; Test that the strstr library call simplifier works correctly.
+;
+; 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"
+
+ at null = private constant [1 x i8] zeroinitializer
+
+declare i8 @strstr(i8*, i8*)
+
+define i8 @test_no_simplify1(i8* %str) {
+; CHECK-LABEL: @test_no_simplify1(
+  %pat = getelementptr inbounds [1 x i8], [1 x i8]* @null, i32 0, i32 0
+  %ret = call i8 @strstr(i8* %str, i8* %pat)
+; CHECK-NEXT: call i8 @strstr
+  ret i8 %ret
+; CHECK-NEXT: ret i8 %ret
+}

Added: llvm/trunk/test/Transforms/InstCombine/strto-1.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/strto-1.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/strto-1.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/strto-1.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,82 @@
+; Test that the strto* library call simplifiers works correctly.
+;
+; RUN: opt < %s -instcombine -inferattrs -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 i64 @strtol(i8* %s, i8** %endptr, i32 %base)
+; CHECK: declare i64 @strtol(i8* readonly, i8** nocapture, i32)
+
+declare double @strtod(i8* %s, i8** %endptr, i32 %base)
+; CHECK: declare double @strtod(i8* readonly, i8** nocapture, i32)
+
+declare float @strtof(i8* %s, i8** %endptr, i32 %base)
+; CHECK: declare float @strtof(i8* readonly, i8** nocapture, i32)
+
+declare i64 @strtoul(i8* %s, i8** %endptr, i32 %base)
+; CHECK: declare i64 @strtoul(i8* readonly, i8** nocapture, i32)
+
+declare i64 @strtoll(i8* %s, i8** %endptr, i32 %base)
+; CHECK: declare i64 @strtoll(i8* readonly, i8** nocapture, i32)
+
+declare double @strtold(i8* %s, i8** %endptr)
+; CHECK: declare double @strtold(i8* readonly, i8** nocapture)
+
+declare i64 @strtoull(i8* %s, i8** %endptr, i32 %base)
+; CHECK: declare i64 @strtoull(i8* readonly, i8** nocapture, i32)
+
+define void @test_simplify1(i8* %x, i8** %endptr) {
+; CHECK-LABEL: @test_simplify1(
+  call i64 @strtol(i8* %x, i8** null, i32 10)
+; CHECK-NEXT: call i64 @strtol(i8* nocapture %x, i8** null, i32 10)
+  ret void
+}
+
+define void @test_simplify2(i8* %x, i8** %endptr) {
+; CHECK-LABEL: @test_simplify2(
+  call double @strtod(i8* %x, i8** null, i32 10)
+; CHECK-NEXT: call double @strtod(i8* nocapture %x, i8** null, i32 10)
+  ret void
+}
+
+define void @test_simplify3(i8* %x, i8** %endptr) {
+; CHECK-LABEL: @test_simplify3(
+  call float @strtof(i8* %x, i8** null, i32 10)
+; CHECK-NEXT: call float @strtof(i8* nocapture %x, i8** null, i32 10)
+  ret void
+}
+
+define void @test_simplify4(i8* %x, i8** %endptr) {
+; CHECK-LABEL: @test_simplify4(
+  call i64 @strtoul(i8* %x, i8** null, i32 10)
+; CHECK-NEXT: call i64 @strtoul(i8* nocapture %x, i8** null, i32 10)
+  ret void
+}
+
+define void @test_simplify5(i8* %x, i8** %endptr) {
+; CHECK-LABEL: @test_simplify5(
+  call i64 @strtoll(i8* %x, i8** null, i32 10)
+; CHECK-NEXT: call i64 @strtoll(i8* nocapture %x, i8** null, i32 10)
+  ret void
+}
+
+define void @test_simplify6(i8* %x, i8** %endptr) {
+; CHECK-LABEL: @test_simplify6(
+  call double @strtold(i8* %x, i8** null)
+; CHECK-NEXT: call double @strtold(i8* nocapture %x, i8** null)
+  ret void
+}
+
+define void @test_simplify7(i8* %x, i8** %endptr) {
+; CHECK-LABEL: @test_simplify7(
+  call i64 @strtoull(i8* %x, i8** null, i32 10)
+; CHECK-NEXT: call i64 @strtoull(i8* nocapture %x, i8** null, i32 10)
+  ret void
+}
+
+define void @test_no_simplify1(i8* %x, i8** %endptr) {
+; CHECK-LABEL: @test_no_simplify1(
+  call i64 @strtol(i8* %x, i8** %endptr, i32 10)
+; CHECK-NEXT: call i64 @strtol(i8* %x, i8** %endptr, i32 10)
+  ret void
+}

Added: llvm/trunk/test/Transforms/InstCombine/struct-assign-tbaa-new.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/struct-assign-tbaa-new.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/struct-assign-tbaa-new.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/struct-assign-tbaa-new.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,53 @@
+; RUN: opt -instcombine -S < %s | FileCheck %s
+;
+; Verify that instcombine preserves TBAA tags when converting a memcpy into
+; a scalar load and store.
+
+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 void @llvm.memcpy.p0i8.p0i8.i64(i8* nocapture, i8* nocapture, i64, i1) nounwind
+
+%A = type { float }
+
+define void @test1(%A* %a1, %A* %a2) {
+entry:
+; CHECK-LABEL: @test1
+; CHECK: %[[LOAD:.*]] = load i32, {{.*}}, !tbaa [[TAG_A:!.*]]
+; CHECK: store i32 %[[LOAD]], {{.*}}, !tbaa [[TAG_A]]
+; CHECK: ret
+  %0 = bitcast %A* %a1 to i8*
+  %1 = bitcast %A* %a2 to i8*
+  tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 4 %0, i8* align 4 %1, i64 4, i1 false), !tbaa !4  ; TAG_A
+  ret void
+}
+
+%B = type { i32 (i8*, i32*, double*)** }
+
+define i32 (i8*, i32*, double*)*** @test2() {
+; CHECK-LABEL: @test2
+; CHECK-NOT: memcpy
+; CHECK: ret
+  %tmp = alloca %B, align 8
+  %tmp1 = bitcast %B* %tmp to i8*
+  call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 8 %tmp1, i8* align 8 undef, i64 8, i1 false), !tbaa !7  ; TAG_B
+  %tmp2 = getelementptr %B, %B* %tmp, i32 0, i32 0
+  %tmp3 = load i32 (i8*, i32*, double*)**, i32 (i8*, i32*, double*)*** %tmp2
+  ret i32 (i8*, i32*, double*)*** %tmp2
+}
+
+!0 = !{!"root"}
+!1 = !{!0, !"char"}
+!2 = !{!1, !"float"}
+!3 = !{!1, i64 4, !"A", !2, i64 0, i64 4}
+!4 = !{!3, !3, i64 0, i64 4}
+!5 = !{!1, !"pointer"}
+!6 = !{!1, i64 8, !"B", !5, i64 0, i64 8}
+!7 = !{!6, !6, i64 0, i64 8}
+
+; CHECK-DAG: [[ROOT:!.*]] = !{!"root"}
+; CHECK-DAG: [[TYPE_char:!.*]] = !{[[ROOT]], !"char"}
+; CHECK-DAG: [[TYPE_float:!.*]] = !{[[TYPE_char]], !"float"}
+; CHECK-DAG: [[TYPE_A:!.*]] = !{[[TYPE_char]], i64 4, !"A", [[TYPE_float]], i64 0, i64 4}
+; CHECK-DAG: [[TAG_A]] = !{[[TYPE_A]], [[TYPE_A]], i64 0, i64 4}
+; Note that the memcpy() call in test2() transforms into an
+; undecorated 'store undef', so TAG_B is not present in the output.

Added: llvm/trunk/test/Transforms/InstCombine/struct-assign-tbaa.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/struct-assign-tbaa.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/struct-assign-tbaa.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/struct-assign-tbaa.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,46 @@
+; RUN: opt -instcombine -S < %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 void @llvm.memcpy.p0i8.p0i8.i64(i8* nocapture, i8* nocapture, i64, i1) nounwind
+
+; Verify that instcombine preserves TBAA tags when converting a memcpy into
+; a scalar load and store.
+
+%struct.test1 = type { float }
+
+; CHECK: @test
+; CHECK: %[[LOAD:.*]] = load i32, i32* %{{.*}}, align 4, !tbaa !0
+; CHECK: store i32 %[[LOAD:.*]], i32* %{{.*}}, align 4, !tbaa !0
+; CHECK: ret
+define void @test1(%struct.test1* nocapture %a, %struct.test1* nocapture %b) {
+entry:
+  %0 = bitcast %struct.test1* %a to i8*
+  %1 = bitcast %struct.test1* %b to i8*
+  tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 4 %0, i8* align 4 %1, i64 4, i1 false), !tbaa.struct !3
+  ret void
+}
+
+%struct.test2 = type { i32 (i8*, i32*, double*)** }
+
+define i32 (i8*, i32*, double*)*** @test2() {
+; CHECK-LABEL: @test2(
+; CHECK-NOT: memcpy
+; CHECK: ret
+  %tmp = alloca %struct.test2, align 8
+  %tmp1 = bitcast %struct.test2* %tmp to i8*
+  call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 8 %tmp1, i8* align 8 undef, i64 8, i1 false), !tbaa.struct !4
+  %tmp2 = getelementptr %struct.test2, %struct.test2* %tmp, i32 0, i32 0
+  %tmp3 = load i32 (i8*, i32*, double*)**, i32 (i8*, i32*, double*)*** %tmp2
+  ret i32 (i8*, i32*, double*)*** %tmp2
+}
+
+; CHECK: !0 = !{!1, !1, i64 0}
+; CHECK: !1 = !{!"float", !2}
+
+!0 = !{!"Simple C/C++ TBAA"}
+!1 = !{!"omnipotent char", !0}
+!2 = !{!5, !5, i64 0}
+!3 = !{i64 0, i64 4, !2}
+!4 = !{i64 0, i64 8, null}
+!5 = !{!"float", !0}

Added: llvm/trunk/test/Transforms/InstCombine/sub-minmax.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/sub-minmax.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/sub-minmax.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/sub-minmax.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,355 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt < %s -instcombine -S | FileCheck %s
+
+define i32 @max_na_b_minux_na(i32 %A, i32 %B) {
+; CHECK-LABEL: @max_na_b_minux_na(
+; CHECK-NEXT:    [[NOT:%.*]] = xor i32 [[A:%.*]], -1
+; CHECK-NEXT:    [[L0:%.*]] = icmp ult i32 [[NOT]], [[B:%.*]]
+; CHECK-NEXT:    [[L1:%.*]] = select i1 [[L0]], i32 [[NOT]], i32 [[B]]
+; CHECK-NEXT:    [[X:%.*]] = sub i32 [[L1]], [[NOT]]
+; CHECK-NEXT:    ret i32 [[X]]
+;
+  %not = xor i32 %A, -1
+  %l0 = icmp ult i32 %not, %B
+  %l1 = select i1 %l0, i32 %not, i32 %B
+  %x = sub i32 %l1, %not
+  ret i32 %x
+}
+
+define i32 @na_minus_max_na_b(i32 %A, i32 %B) {
+; CHECK-LABEL: @na_minus_max_na_b(
+; CHECK-NEXT:    [[NOT:%.*]] = xor i32 [[A:%.*]], -1
+; CHECK-NEXT:    [[L0:%.*]] = icmp ult i32 [[NOT]], [[B:%.*]]
+; CHECK-NEXT:    [[L1:%.*]] = select i1 [[L0]], i32 [[NOT]], i32 [[B]]
+; CHECK-NEXT:    [[X:%.*]] = sub i32 [[NOT]], [[L1]]
+; CHECK-NEXT:    ret i32 [[X]]
+;
+  %not = xor i32 %A, -1
+  %l0 = icmp ult i32 %not, %B
+  %l1 = select i1 %l0, i32 %not, i32 %B
+  %x = sub i32 %not, %l1
+  ret i32 %x
+}
+
+define i32 @max_b_na_minus_na(i32 %A, i32 %B) {
+; CHECK-LABEL: @max_b_na_minus_na(
+; CHECK-NEXT:    [[NOT:%.*]] = xor i32 [[A:%.*]], -1
+; CHECK-NEXT:    [[L0:%.*]] = icmp ugt i32 [[NOT]], [[B:%.*]]
+; CHECK-NEXT:    [[L1:%.*]] = select i1 [[L0]], i32 [[B]], i32 [[NOT]]
+; CHECK-NEXT:    [[X:%.*]] = sub i32 [[L1]], [[NOT]]
+; CHECK-NEXT:    ret i32 [[X]]
+;
+  %not = xor i32 %A, -1
+  %l0 = icmp ugt i32 %not, %B
+  %l1 = select i1 %l0, i32 %B, i32 %not
+  %x = sub i32 %l1, %not
+  ret i32 %x
+}
+
+define i32 @na_minus_max_b_na(i32 %A, i32 %B) {
+; CHECK-LABEL: @na_minus_max_b_na(
+; CHECK-NEXT:    [[NOT:%.*]] = xor i32 [[A:%.*]], -1
+; CHECK-NEXT:    [[L0:%.*]] = icmp ugt i32 [[NOT]], [[B:%.*]]
+; CHECK-NEXT:    [[L1:%.*]] = select i1 [[L0]], i32 [[B]], i32 [[NOT]]
+; CHECK-NEXT:    [[X:%.*]] = sub i32 [[NOT]], [[L1]]
+; CHECK-NEXT:    ret i32 [[X]]
+;
+  %not = xor i32 %A, -1
+  %l0 = icmp ugt i32 %not, %B
+  %l1 = select i1 %l0, i32 %B, i32 %not
+  %x = sub i32 %not, %l1
+  ret i32 %x
+}
+
+
+define i32 @max_na_bi_minux_na(i32 %A, i32 %Bi) {
+; CHECK-LABEL: @max_na_bi_minux_na(
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp ult i32 [[A:%.*]], [[BI:%.*]]
+; CHECK-NEXT:    [[TMP2:%.*]] = select i1 [[TMP1]], i32 [[BI]], i32 [[A]]
+; CHECK-NEXT:    [[X:%.*]] = sub i32 [[A]], [[TMP2]]
+; CHECK-NEXT:    ret i32 [[X]]
+;
+  %B =  xor i32 %Bi, -1
+  %not = xor i32 %A, -1
+  %l0 = icmp ult i32 %not, %B
+  %l1 = select i1 %l0, i32 %not, i32 %B
+  %x = sub i32 %l1, %not
+  ret i32 %x
+}
+
+define i32 @na_minus_max_na_bi(i32 %A, i32 %Bi) {
+; CHECK-LABEL: @na_minus_max_na_bi(
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp ult i32 [[A:%.*]], [[BI:%.*]]
+; CHECK-NEXT:    [[TMP2:%.*]] = select i1 [[TMP1]], i32 [[BI]], i32 [[A]]
+; CHECK-NEXT:    [[X:%.*]] = sub i32 [[TMP2]], [[A]]
+; CHECK-NEXT:    ret i32 [[X]]
+;
+  %B =  xor i32 %Bi, -1
+  %not = xor i32 %A, -1
+  %l0 = icmp ult i32 %not, %B
+  %l1 = select i1 %l0, i32 %not, i32 %B
+  %x = sub i32 %not, %l1
+  ret i32 %x
+}
+
+define i32 @max_bi_na_minus_na(i32 %A, i32 %Bi) {
+; CHECK-LABEL: @max_bi_na_minus_na(
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp ult i32 [[A:%.*]], [[BI:%.*]]
+; CHECK-NEXT:    [[TMP2:%.*]] = select i1 [[TMP1]], i32 [[BI]], i32 [[A]]
+; CHECK-NEXT:    [[X:%.*]] = sub i32 [[A]], [[TMP2]]
+; CHECK-NEXT:    ret i32 [[X]]
+;
+  %B =  xor i32 %Bi, -1
+  %not = xor i32 %A, -1
+  %l0 = icmp ugt i32 %not, %B
+  %l1 = select i1 %l0, i32 %B, i32 %not
+  %x = sub i32 %l1, %not
+  ret i32 %x
+}
+
+define i32 @na_minus_max_bi_na(i32 %A, i32 %Bi) {
+; CHECK-LABEL: @na_minus_max_bi_na(
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp ult i32 [[A:%.*]], [[BI:%.*]]
+; CHECK-NEXT:    [[TMP2:%.*]] = select i1 [[TMP1]], i32 [[BI]], i32 [[A]]
+; CHECK-NEXT:    [[X:%.*]] = sub i32 [[TMP2]], [[A]]
+; CHECK-NEXT:    ret i32 [[X]]
+;
+  %B =  xor i32 %Bi, -1
+  %not = xor i32 %A, -1
+  %l0 = icmp ugt i32 %not, %B
+  %l1 = select i1 %l0, i32 %B, i32 %not
+  %x = sub i32 %not, %l1
+  ret i32 %x
+}
+
+
+define i32 @max_na_bi_minux_na_use(i32 %A, i32 %Bi) {
+; CHECK-LABEL: @max_na_bi_minux_na_use(
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp ugt i32 [[A:%.*]], -32
+; CHECK-NEXT:    [[TMP2:%.*]] = select i1 [[TMP1]], i32 [[A]], i32 -32
+; CHECK-NEXT:    [[L1:%.*]] = xor i32 [[TMP2]], -1
+; CHECK-NEXT:    [[X:%.*]] = sub i32 [[A]], [[TMP2]]
+; CHECK-NEXT:    call void @use32(i32 [[L1]])
+; CHECK-NEXT:    ret i32 [[X]]
+;
+  %not = xor i32 %A, -1
+  %l0 = icmp ult i32 %not, 31
+  %l1 = select i1 %l0, i32 %not, i32 31
+  %x = sub i32 %l1, %not
+  call void @use32(i32 %l1)
+  ret i32 %x
+}
+
+define i32 @na_minus_max_na_bi_use(i32 %A, i32 %Bi) {
+; CHECK-LABEL: @na_minus_max_na_bi_use(
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp ugt i32 [[A:%.*]], -32
+; CHECK-NEXT:    [[TMP2:%.*]] = select i1 [[TMP1]], i32 [[A]], i32 -32
+; CHECK-NEXT:    [[L1:%.*]] = xor i32 [[TMP2]], -1
+; CHECK-NEXT:    [[X:%.*]] = sub i32 [[TMP2]], [[A]]
+; CHECK-NEXT:    call void @use32(i32 [[L1]])
+; CHECK-NEXT:    ret i32 [[X]]
+;
+  %not = xor i32 %A, -1
+  %l0 = icmp ult i32 %not, 31
+  %l1 = select i1 %l0, i32 %not, i32 31
+  %x = sub i32 %not, %l1
+  call void @use32(i32 %l1)
+  ret i32 %x
+}
+
+define i32 @max_bi_na_minus_na_use(i32 %A, i32 %Bi) {
+; CHECK-LABEL: @max_bi_na_minus_na_use(
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp ult i32 [[A:%.*]], [[BI:%.*]]
+; CHECK-NEXT:    [[TMP2:%.*]] = select i1 [[TMP1]], i32 [[BI]], i32 [[A]]
+; CHECK-NEXT:    [[L1:%.*]] = xor i32 [[TMP2]], -1
+; CHECK-NEXT:    [[X:%.*]] = sub i32 [[A]], [[TMP2]]
+; CHECK-NEXT:    call void @use32(i32 [[L1]])
+; CHECK-NEXT:    ret i32 [[X]]
+;
+  %not = xor i32 %A, -1
+  %B = xor i32 %Bi, -1
+  %l0 = icmp ult i32 %B, %not
+  %l1 = select i1 %l0, i32 %B, i32 %not
+  %x = sub i32 %l1, %not
+  call void @use32(i32 %l1)
+  ret i32 %x
+}
+
+define i32 @na_minus_max_bi_na_use(i32 %A, i32 %Bi) {
+; CHECK-LABEL: @na_minus_max_bi_na_use(
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp ult i32 [[A:%.*]], [[BI:%.*]]
+; CHECK-NEXT:    [[TMP2:%.*]] = select i1 [[TMP1]], i32 [[BI]], i32 [[A]]
+; CHECK-NEXT:    [[L1:%.*]] = xor i32 [[TMP2]], -1
+; CHECK-NEXT:    [[X:%.*]] = sub i32 [[TMP2]], [[A]]
+; CHECK-NEXT:    call void @use32(i32 [[L1]])
+; CHECK-NEXT:    ret i32 [[X]]
+;
+  %not = xor i32 %A, -1
+  %B = xor i32 %Bi, -1
+  %l0 = icmp ult i32 %B, %not
+  %l1 = select i1 %l0, i32 %B, i32 %not
+  %x = sub i32 %not, %l1
+  call void @use32(i32 %l1)
+  ret i32 %x
+}
+
+
+define i32 @max_na_bi_minux_na_use2(i32 %A, i32 %Bi) {
+; CHECK-LABEL: @max_na_bi_minux_na_use2(
+; CHECK-NEXT:    [[NOT:%.*]] = xor i32 [[A:%.*]], -1
+; CHECK-NEXT:    [[L0:%.*]] = icmp ult i32 [[NOT]], 31
+; CHECK-NEXT:    [[L1:%.*]] = select i1 [[L0]], i32 [[NOT]], i32 31
+; CHECK-NEXT:    [[X:%.*]] = sub i32 [[L1]], [[NOT]]
+; CHECK-NEXT:    call void @use32(i32 [[L1]])
+; CHECK-NEXT:    call void @use32(i32 [[NOT]])
+; CHECK-NEXT:    ret i32 [[X]]
+;
+  %not = xor i32 %A, -1
+  %l0 = icmp ult i32 %not, 31
+  %l1 = select i1 %l0, i32 %not, i32 31
+  %x = sub i32 %l1, %not
+  call void @use32(i32 %l1)
+  call void @use32(i32 %not)
+  ret i32 %x
+}
+
+define i32 @na_minus_max_na_bi_use2(i32 %A, i32 %Bi) {
+; CHECK-LABEL: @na_minus_max_na_bi_use2(
+; CHECK-NEXT:    [[NOT:%.*]] = xor i32 [[A:%.*]], -1
+; CHECK-NEXT:    [[L0:%.*]] = icmp ult i32 [[NOT]], 31
+; CHECK-NEXT:    [[L1:%.*]] = select i1 [[L0]], i32 [[NOT]], i32 31
+; CHECK-NEXT:    [[X:%.*]] = sub i32 [[NOT]], [[L1]]
+; CHECK-NEXT:    call void @use32(i32 [[L1]])
+; CHECK-NEXT:    call void @use32(i32 [[NOT]])
+; CHECK-NEXT:    ret i32 [[X]]
+;
+  %not = xor i32 %A, -1
+  %l0 = icmp ult i32 %not, 31
+  %l1 = select i1 %l0, i32 %not, i32 31
+  %x = sub i32 %not, %l1
+  call void @use32(i32 %l1)
+  call void @use32(i32 %not)
+  ret i32 %x
+}
+
+define i32 @max_bi_na_minus_na_use2(i32 %A, i32 %Bi) {
+; CHECK-LABEL: @max_bi_na_minus_na_use2(
+; CHECK-NEXT:    [[NOT:%.*]] = xor i32 [[A:%.*]], -1
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp ult i32 [[A]], [[BI:%.*]]
+; CHECK-NEXT:    [[TMP2:%.*]] = select i1 [[TMP1]], i32 [[BI]], i32 [[A]]
+; CHECK-NEXT:    [[L1:%.*]] = xor i32 [[TMP2]], -1
+; CHECK-NEXT:    [[X:%.*]] = sub i32 [[A]], [[TMP2]]
+; CHECK-NEXT:    call void @use32(i32 [[L1]])
+; CHECK-NEXT:    call void @use32(i32 [[NOT]])
+; CHECK-NEXT:    ret i32 [[X]]
+;
+  %not = xor i32 %A, -1
+  %B = xor i32 %Bi, -1
+  %l0 = icmp ult i32 %B, %not
+  %l1 = select i1 %l0, i32 %B, i32 %not
+  %x = sub i32 %l1, %not
+  call void @use32(i32 %l1)
+  call void @use32(i32 %not)
+  ret i32 %x
+}
+
+define i32 @na_minus_max_bi_na_use2(i32 %A, i32 %Bi) {
+; CHECK-LABEL: @na_minus_max_bi_na_use2(
+; CHECK-NEXT:    [[NOT:%.*]] = xor i32 [[A:%.*]], -1
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp ult i32 [[A]], [[BI:%.*]]
+; CHECK-NEXT:    [[TMP2:%.*]] = select i1 [[TMP1]], i32 [[BI]], i32 [[A]]
+; CHECK-NEXT:    [[L1:%.*]] = xor i32 [[TMP2]], -1
+; CHECK-NEXT:    [[X:%.*]] = sub i32 [[TMP2]], [[A]]
+; CHECK-NEXT:    call void @use32(i32 [[L1]])
+; CHECK-NEXT:    call void @use32(i32 [[NOT]])
+; CHECK-NEXT:    ret i32 [[X]]
+;
+  %not = xor i32 %A, -1
+  %B = xor i32 %Bi, -1
+  %l0 = icmp ult i32 %B, %not
+  %l1 = select i1 %l0, i32 %B, i32 %not
+  %x = sub i32 %not, %l1
+  call void @use32(i32 %l1)
+  call void @use32(i32 %not)
+  ret i32 %x
+}
+
+define i8 @umin_not_sub(i8 %x, i8 %y) {
+; CHECK-LABEL: @umin_not_sub(
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp ult i8 [[Y:%.*]], [[X:%.*]]
+; CHECK-NEXT:    [[TMP2:%.*]] = select i1 [[TMP1]], i8 [[X]], i8 [[Y]]
+; CHECK-NEXT:    [[MINXY:%.*]] = xor i8 [[TMP2]], -1
+; CHECK-NEXT:    [[SUBX:%.*]] = sub i8 [[TMP2]], [[X]]
+; CHECK-NEXT:    [[SUBY:%.*]] = sub i8 [[TMP2]], [[Y]]
+; CHECK-NEXT:    call void @use8(i8 [[SUBX]])
+; CHECK-NEXT:    call void @use8(i8 [[SUBY]])
+; CHECK-NEXT:    ret i8 [[MINXY]]
+;
+  %nx = xor i8 %x, -1
+  %ny = xor i8 %y, -1
+  %cmpxy = icmp ult i8 %nx, %ny
+  %minxy = select i1 %cmpxy, i8 %nx, i8 %ny
+  %subx = sub i8 %nx, %minxy
+  %suby = sub i8 %ny, %minxy
+  call void @use8(i8 %subx)
+  call void @use8(i8 %suby)
+  ret i8 %minxy
+}
+
+define i8 @umin_not_sub_rev(i8 %x, i8 %y) {
+; CHECK-LABEL: @umin_not_sub_rev(
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp ult i8 [[Y:%.*]], [[X:%.*]]
+; CHECK-NEXT:    [[TMP2:%.*]] = select i1 [[TMP1]], i8 [[X]], i8 [[Y]]
+; CHECK-NEXT:    [[MINXY:%.*]] = xor i8 [[TMP2]], -1
+; CHECK-NEXT:    [[SUBX:%.*]] = sub i8 [[X]], [[TMP2]]
+; CHECK-NEXT:    [[SUBY:%.*]] = sub i8 [[Y]], [[TMP2]]
+; CHECK-NEXT:    call void @use8(i8 [[SUBX]])
+; CHECK-NEXT:    call void @use8(i8 [[SUBY]])
+; CHECK-NEXT:    ret i8 [[MINXY]]
+;
+  %nx = xor i8 %x, -1
+  %ny = xor i8 %y, -1
+  %cmpxy = icmp ult i8 %nx, %ny
+  %minxy = select i1 %cmpxy, i8 %nx, i8 %ny
+  %subx = sub i8 %minxy, %nx
+  %suby = sub i8 %minxy, %ny
+  call void @use8(i8 %subx)
+  call void @use8(i8 %suby)
+  ret i8 %minxy
+}
+
+define void @umin3_not_all_ops_extra_uses_invert_subs(i8 %x, i8 %y, i8 %z) {
+; CHECK-LABEL: @umin3_not_all_ops_extra_uses_invert_subs(
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp ugt i8 [[X:%.*]], [[Z:%.*]]
+; CHECK-NEXT:    [[TMP2:%.*]] = select i1 [[TMP1]], i8 [[X]], i8 [[Z]]
+; CHECK-NEXT:    [[TMP3:%.*]] = icmp ugt i8 [[TMP2]], [[Y:%.*]]
+; CHECK-NEXT:    [[TMP4:%.*]] = select i1 [[TMP3]], i8 [[TMP2]], i8 [[Y]]
+; CHECK-NEXT:    [[TMP5:%.*]] = xor i8 [[TMP4]], -1
+; CHECK-NEXT:    [[XMIN:%.*]] = sub i8 [[TMP4]], [[X]]
+; CHECK-NEXT:    [[YMIN:%.*]] = sub i8 [[TMP4]], [[Y]]
+; CHECK-NEXT:    [[ZMIN:%.*]] = sub i8 [[TMP4]], [[Z]]
+; CHECK-NEXT:    call void @use8(i8 [[TMP5]])
+; CHECK-NEXT:    call void @use8(i8 [[XMIN]])
+; CHECK-NEXT:    call void @use8(i8 [[YMIN]])
+; CHECK-NEXT:    call void @use8(i8 [[ZMIN]])
+; CHECK-NEXT:    ret void
+;
+  %xn = xor i8 %x, -1
+  %yn = xor i8 %y, -1
+  %zn = xor i8 %z, -1
+  %cmpxz = icmp ult i8 %xn, %zn
+  %minxz = select i1 %cmpxz, i8 %xn, i8 %zn
+  %cmpxyz = icmp ult i8 %minxz, %yn
+  %minxyz = select i1 %cmpxyz, i8 %minxz, i8 %yn
+  %xmin = sub i8 %xn, %minxyz
+  %ymin = sub i8 %yn, %minxyz
+  %zmin = sub i8 %zn, %minxyz
+  call void @use8(i8 %minxyz)
+  call void @use8(i8 %xmin)
+  call void @use8(i8 %ymin)
+  call void @use8(i8 %zmin)
+  ret void
+}
+
+declare void @use8(i8)
+declare void @use32(i32 %u)

Added: llvm/trunk/test/Transforms/InstCombine/sub-not.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/sub-not.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/sub-not.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/sub-not.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,145 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt < %s -instcombine -S | FileCheck %s
+
+declare void @use(i8)
+
+define i8 @sub_not(i8 %x, i8 %y) {
+; CHECK-LABEL: @sub_not(
+; CHECK-NEXT:    [[TMP1:%.*]] = xor i8 [[X:%.*]], -1
+; CHECK-NEXT:    [[R:%.*]] = add i8 [[TMP1]], [[Y:%.*]]
+; CHECK-NEXT:    ret i8 [[R]]
+;
+  %s = sub i8 %x, %y
+  %r = xor i8 %s, -1
+  ret i8 %r
+}
+
+define i8 @sub_not_extra_use(i8 %x, i8 %y) {
+; CHECK-LABEL: @sub_not_extra_use(
+; CHECK-NEXT:    [[S:%.*]] = sub i8 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = xor i8 [[S]], -1
+; CHECK-NEXT:    call void @use(i8 [[S]])
+; CHECK-NEXT:    ret i8 [[R]]
+;
+  %s = sub i8 %x, %y
+  %r = xor i8 %s, -1
+  call void @use(i8 %s)
+  ret i8 %r
+}
+
+define <2 x i8> @sub_not_vec(<2 x i8> %x, <2 x i8> %y) {
+; CHECK-LABEL: @sub_not_vec(
+; CHECK-NEXT:    [[TMP1:%.*]] = xor <2 x i8> [[X:%.*]], <i8 -1, i8 -1>
+; CHECK-NEXT:    [[R:%.*]] = add <2 x i8> [[TMP1]], [[Y:%.*]]
+; CHECK-NEXT:    ret <2 x i8> [[R]]
+;
+  %s = sub <2 x i8> %x, %y
+  %r = xor <2 x i8> %s, <i8 -1, i8 undef>
+  ret <2 x i8> %r
+}
+
+define i8 @dec_sub(i8 %x, i8 %y) {
+; CHECK-LABEL: @dec_sub(
+; CHECK-NEXT:    [[TMP1:%.*]] = xor i8 [[Y:%.*]], -1
+; CHECK-NEXT:    [[R:%.*]] = add i8 [[TMP1]], [[X:%.*]]
+; CHECK-NEXT:    ret i8 [[R]]
+;
+  %s = sub i8 %x, %y
+  %r = add i8 %s, -1
+  ret i8 %r
+}
+
+define i8 @dec_sub_extra_use(i8 %x, i8 %y) {
+; CHECK-LABEL: @dec_sub_extra_use(
+; CHECK-NEXT:    [[S:%.*]] = sub i8 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = add i8 [[S]], -1
+; CHECK-NEXT:    call void @use(i8 [[S]])
+; CHECK-NEXT:    ret i8 [[R]]
+;
+  %s = sub i8 %x, %y
+  %r = add i8 %s, -1
+  call void @use(i8 %s)
+  ret i8 %r
+}
+
+define <2 x i8> @dec_sub_vec(<2 x i8> %x, <2 x i8> %y) {
+; CHECK-LABEL: @dec_sub_vec(
+; CHECK-NEXT:    [[TMP1:%.*]] = xor <2 x i8> [[Y:%.*]], <i8 -1, i8 -1>
+; CHECK-NEXT:    [[R:%.*]] = add <2 x i8> [[TMP1]], [[X:%.*]]
+; CHECK-NEXT:    ret <2 x i8> [[R]]
+;
+  %s = sub <2 x i8> %x, %y
+  %r = add <2 x i8> %s, <i8 -1, i8 undef>
+  ret <2 x i8> %r
+}
+
+define i8 @sub_inc(i8 %x, i8 %y) {
+; CHECK-LABEL: @sub_inc(
+; CHECK-NEXT:    [[TMP1:%.*]] = xor i8 [[X:%.*]], -1
+; CHECK-NEXT:    [[R:%.*]] = add i8 [[TMP1]], [[Y:%.*]]
+; CHECK-NEXT:    ret i8 [[R]]
+;
+  %s = add i8 %x, 1
+  %r = sub i8 %y, %s
+  ret i8 %r
+}
+
+define i8 @sub_inc_extra_use(i8 %x, i8 %y) {
+; CHECK-LABEL: @sub_inc_extra_use(
+; CHECK-NEXT:    [[S:%.*]] = add i8 [[X:%.*]], 1
+; CHECK-NEXT:    [[R:%.*]] = sub i8 [[Y:%.*]], [[S]]
+; CHECK-NEXT:    call void @use(i8 [[S]])
+; CHECK-NEXT:    ret i8 [[R]]
+;
+  %s = add i8 %x, 1
+  %r = sub i8 %y, %s
+  call void @use(i8 %s)
+  ret i8 %r
+}
+
+define <2 x i8> @sub_inc_vec(<2 x i8> %x, <2 x i8> %y) {
+; CHECK-LABEL: @sub_inc_vec(
+; CHECK-NEXT:    [[TMP1:%.*]] = xor <2 x i8> [[X:%.*]], <i8 -1, i8 -1>
+; CHECK-NEXT:    [[R:%.*]] = add <2 x i8> [[TMP1]], [[Y:%.*]]
+; CHECK-NEXT:    ret <2 x i8> [[R]]
+;
+  %s = add <2 x i8> %x, <i8 undef, i8 1>
+  %r = sub <2 x i8> %y, %s
+  ret <2 x i8> %r
+}
+
+define i8 @sub_dec(i8 %x, i8 %y) {
+; CHECK-LABEL: @sub_dec(
+; CHECK-NEXT:    [[TMP1:%.*]] = xor i8 [[Y:%.*]], -1
+; CHECK-NEXT:    [[R:%.*]] = add i8 [[TMP1]], [[X:%.*]]
+; CHECK-NEXT:    ret i8 [[R]]
+;
+  %s = add i8 %x, -1
+  %r = sub i8 %s, %y
+  ret i8 %r
+}
+
+define i8 @sub_dec_extra_use(i8 %x, i8 %y) {
+; CHECK-LABEL: @sub_dec_extra_use(
+; CHECK-NEXT:    [[S:%.*]] = add i8 [[X:%.*]], -1
+; CHECK-NEXT:    [[R:%.*]] = sub i8 [[S]], [[Y:%.*]]
+; CHECK-NEXT:    call void @use(i8 [[S]])
+; CHECK-NEXT:    ret i8 [[R]]
+;
+  %s = add i8 %x, -1
+  %r = sub i8 %s, %y
+  call void @use(i8 %s)
+  ret i8 %r
+}
+
+define <2 x i8> @sub_dec_vec(<2 x i8> %x, <2 x i8> %y) {
+; CHECK-LABEL: @sub_dec_vec(
+; CHECK-NEXT:    [[TMP1:%.*]] = xor <2 x i8> [[Y:%.*]], <i8 -1, i8 -1>
+; CHECK-NEXT:    [[R:%.*]] = add <2 x i8> [[TMP1]], [[X:%.*]]
+; CHECK-NEXT:    ret <2 x i8> [[R]]
+;
+  %s = add <2 x i8> %x, <i8 undef, i8 -1>
+  %r = sub <2 x i8> %s, %y
+  ret <2 x i8> %r
+}
+

Added: llvm/trunk/test/Transforms/InstCombine/sub-xor.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/sub-xor.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/sub-xor.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/sub-xor.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,50 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt -instcombine -S < %s | FileCheck %s
+
+define i32 @test1(i32 %x) {
+; CHECK-LABEL: @test1(
+; CHECK-NEXT:    [[AND:%.*]] = and i32 %x, 31
+; CHECK-NEXT:    [[SUB:%.*]] = xor i32 [[AND]], 63
+; CHECK-NEXT:    ret i32 [[SUB]]
+;
+  %and = and i32 %x, 31
+  %sub = sub i32 63, %and
+  ret i32 %sub
+}
+
+define <2 x i32> @test1vec(<2 x i32> %x) {
+; CHECK-LABEL: @test1vec(
+; CHECK-NEXT:    [[AND:%.*]] = and <2 x i32> %x, <i32 31, i32 31>
+; CHECK-NEXT:    [[SUB:%.*]] = xor <2 x i32> [[AND]], <i32 63, i32 63>
+; CHECK-NEXT:    ret <2 x i32> [[SUB]]
+;
+  %and = and <2 x i32> %x, <i32 31, i32 31>
+  %sub = sub <2 x i32> <i32 63, i32 63>, %and
+  ret <2 x i32> %sub
+}
+
+declare i32 @llvm.ctlz.i32(i32, i1) nounwind readnone
+
+define i32 @test2(i32 %x) nounwind {
+; CHECK-LABEL: @test2(
+; CHECK-NEXT:    [[COUNT:%.*]] = tail call i32 @llvm.ctlz.i32(i32 %x, i1 true)
+; CHECK-NEXT:    [[SUB:%.*]] = xor i32 [[COUNT]], 31
+; CHECK-NEXT:    ret i32 [[SUB]]
+;
+  %count = tail call i32 @llvm.ctlz.i32(i32 %x, i1 true) nounwind readnone
+  %sub = sub i32 31, %count
+  ret i32 %sub
+}
+
+define i32 @test3(i32 %x) {
+; CHECK-LABEL: @test3(
+; CHECK-NEXT:    [[AND:%.*]] = and i32 %x, 31
+; CHECK-NEXT:    [[ADD:%.*]] = sub nuw nsw i32 73, [[AND]]
+; CHECK-NEXT:    ret i32 [[ADD]]
+;
+  %and = and i32 %x, 31
+  %sub = xor i32 31, %and
+  %add = add i32 %sub, 42
+  ret i32 %add
+}
+

Added: llvm/trunk/test/Transforms/InstCombine/sub.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/sub.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/sub.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/sub.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,1294 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt < %s -instcombine -S | FileCheck %s
+
+target datalayout = "e-p:64:64:64-p1:16:16:16-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 i32 @sub_constant(i32 %x) {
+; CHECK-LABEL: @sub_constant(
+; CHECK-NEXT:    [[R:%.*]] = add i32 [[X:%.*]], -42
+; CHECK-NEXT:    ret i32 [[R]]
+;
+  %r = sub i32 %x, 42
+  ret i32 %r
+}
+
+ at g = global i32 0
+
+define i32 @sub_constant_expression(i32 %x) {
+; CHECK-LABEL: @sub_constant_expression(
+; CHECK-NEXT:    [[R:%.*]] = sub i32 [[X:%.*]], ptrtoint (i32* @g to i32)
+; CHECK-NEXT:    ret i32 [[R]]
+;
+  %r = sub i32 %x, ptrtoint (i32* @g to i32)
+  ret i32 %r
+}
+
+define <2 x i32> @sub_constant_vec(<2 x i32> %x) {
+; CHECK-LABEL: @sub_constant_vec(
+; CHECK-NEXT:    [[R:%.*]] = add <2 x i32> [[X:%.*]], <i32 -42, i32 12>
+; CHECK-NEXT:    ret <2 x i32> [[R]]
+;
+  %r = sub <2 x i32> %x, <i32 42, i32 -12>
+  ret <2 x i32> %r
+}
+
+define <3 x i33> @sub_constant_vec_weird_type(<3 x i33> %x) {
+; CHECK-LABEL: @sub_constant_vec_weird_type(
+; CHECK-NEXT:    [[R:%.*]] = add <3 x i33> [[X:%.*]], <i33 42, i33 -42, i33 12>
+; CHECK-NEXT:    ret <3 x i33> [[R]]
+;
+  %r = sub <3 x i33> %x, <i33 -42, i33 42, i33 -12>
+  ret <3 x i33> %r
+}
+
+define <4 x i32> @sub_constant_expression_vec(<4 x i32> %x) {
+; CHECK-LABEL: @sub_constant_expression_vec(
+; CHECK-NEXT:    [[R:%.*]] = sub <4 x i32> [[X:%.*]], bitcast (i128 ptrtoint (i32* @g to i128) to <4 x i32>)
+; CHECK-NEXT:    ret <4 x i32> [[R]]
+;
+  %r = sub <4 x i32> %x, bitcast (i128 ptrtoint (i32* @g to i128) to <4 x i32>)
+  ret <4 x i32> %r
+}
+
+define i32 @neg_sub(i32 %x, i32 %y) {
+; CHECK-LABEL: @neg_sub(
+; CHECK-NEXT:    [[R:%.*]] = add i32 [[Y:%.*]], [[X:%.*]]
+; CHECK-NEXT:    ret i32 [[R]]
+;
+  %neg = sub i32 0, %x
+  %r = sub i32 %y, %neg
+  ret i32 %r
+}
+
+define i32 @neg_nsw_sub(i32 %x, i32 %y) {
+; CHECK-LABEL: @neg_nsw_sub(
+; CHECK-NEXT:    [[R:%.*]] = add i32 [[Y:%.*]], [[X:%.*]]
+; CHECK-NEXT:    ret i32 [[R]]
+;
+  %neg = sub nsw i32 0, %x
+  %r = sub i32 %y, %neg
+  ret i32 %r
+}
+
+define i32 @neg_sub_nsw(i32 %x, i32 %y) {
+; CHECK-LABEL: @neg_sub_nsw(
+; CHECK-NEXT:    [[R:%.*]] = add i32 [[Y:%.*]], [[X:%.*]]
+; CHECK-NEXT:    ret i32 [[R]]
+;
+  %neg = sub i32 0, %x
+  %r = sub nsw i32 %y, %neg
+  ret i32 %r
+}
+
+define i32 @neg_nsw_sub_nsw(i32 %x, i32 %y) {
+; CHECK-LABEL: @neg_nsw_sub_nsw(
+; CHECK-NEXT:    [[R:%.*]] = add nsw i32 [[Y:%.*]], [[X:%.*]]
+; CHECK-NEXT:    ret i32 [[R]]
+;
+  %neg = sub nsw i32 0, %x
+  %r = sub nsw i32 %y, %neg
+  ret i32 %r
+}
+
+define <2 x i32> @neg_sub_vec(<2 x i32> %x, <2 x i32> %y) {
+; CHECK-LABEL: @neg_sub_vec(
+; CHECK-NEXT:    [[R:%.*]] = add <2 x i32> [[Y:%.*]], [[X:%.*]]
+; CHECK-NEXT:    ret <2 x i32> [[R]]
+;
+  %neg = sub <2 x i32> zeroinitializer, %x
+  %r = sub <2 x i32> %y, %neg
+  ret <2 x i32> %r
+}
+
+define <2 x i32> @neg_nsw_sub_vec(<2 x i32> %x, <2 x i32> %y) {
+; CHECK-LABEL: @neg_nsw_sub_vec(
+; CHECK-NEXT:    [[R:%.*]] = add <2 x i32> [[Y:%.*]], [[X:%.*]]
+; CHECK-NEXT:    ret <2 x i32> [[R]]
+;
+  %neg = sub nsw <2 x i32> zeroinitializer, %x
+  %r = sub <2 x i32> %y, %neg
+  ret <2 x i32> %r
+}
+
+define <2 x i32> @neg_sub_nsw_vec(<2 x i32> %x, <2 x i32> %y) {
+; CHECK-LABEL: @neg_sub_nsw_vec(
+; CHECK-NEXT:    [[R:%.*]] = add <2 x i32> [[Y:%.*]], [[X:%.*]]
+; CHECK-NEXT:    ret <2 x i32> [[R]]
+;
+  %neg = sub <2 x i32> zeroinitializer, %x
+  %r = sub nsw <2 x i32> %y, %neg
+  ret <2 x i32> %r
+}
+
+define <2 x i32> @neg_nsw_sub_nsw_vec(<2 x i32> %x, <2 x i32> %y) {
+; CHECK-LABEL: @neg_nsw_sub_nsw_vec(
+; CHECK-NEXT:    [[R:%.*]] = add nsw <2 x i32> [[Y:%.*]], [[X:%.*]]
+; CHECK-NEXT:    ret <2 x i32> [[R]]
+;
+  %neg = sub nsw <2 x i32> zeroinitializer, %x
+  %r = sub nsw <2 x i32> %y, %neg
+  ret <2 x i32> %r
+}
+
+define <2 x i32> @neg_sub_vec_undef(<2 x i32> %x, <2 x i32> %y) {
+; CHECK-LABEL: @neg_sub_vec_undef(
+; CHECK-NEXT:    [[R:%.*]] = add <2 x i32> [[Y:%.*]], [[X:%.*]]
+; CHECK-NEXT:    ret <2 x i32> [[R]]
+;
+  %neg = sub <2 x i32> <i32 0, i32 undef>, %x
+  %r = sub <2 x i32> %y, %neg
+  ret <2 x i32> %r
+}
+
+define <2 x i32> @neg_nsw_sub_vec_undef(<2 x i32> %x, <2 x i32> %y) {
+; CHECK-LABEL: @neg_nsw_sub_vec_undef(
+; CHECK-NEXT:    [[R:%.*]] = add <2 x i32> [[Y:%.*]], [[X:%.*]]
+; CHECK-NEXT:    ret <2 x i32> [[R]]
+;
+  %neg = sub nsw <2 x i32> <i32 undef, i32 0>, %x
+  %r = sub <2 x i32> %y, %neg
+  ret <2 x i32> %r
+}
+
+define <2 x i32> @neg_sub_nsw_vec_undef(<2 x i32> %x, <2 x i32> %y) {
+; CHECK-LABEL: @neg_sub_nsw_vec_undef(
+; CHECK-NEXT:    [[R:%.*]] = add <2 x i32> [[Y:%.*]], [[X:%.*]]
+; CHECK-NEXT:    ret <2 x i32> [[R]]
+;
+  %neg = sub <2 x i32> <i32 undef, i32 0>, %x
+  %r = sub nsw <2 x i32> %y, %neg
+  ret <2 x i32> %r
+}
+
+; This should not drop 'nsw'.
+
+define <2 x i32> @neg_nsw_sub_nsw_vec_undef(<2 x i32> %x, <2 x i32> %y) {
+; CHECK-LABEL: @neg_nsw_sub_nsw_vec_undef(
+; CHECK-NEXT:    [[R:%.*]] = add nsw <2 x i32> [[Y:%.*]], [[X:%.*]]
+; CHECK-NEXT:    ret <2 x i32> [[R]]
+;
+  %neg = sub nsw <2 x i32> <i32 0, i32 undef>, %x
+  %r = sub nsw <2 x i32> %y, %neg
+  ret <2 x i32> %r
+}
+
+; (~X) - (~Y) --> Y - X
+; Also, show that we can handle extra uses and vectors.
+
+declare void @use8(i8)
+
+define i8 @notnotsub(i8 %x, i8 %y) {
+; CHECK-LABEL: @notnotsub(
+; CHECK-NEXT:    [[NX:%.*]] = xor i8 [[X:%.*]], -1
+; CHECK-NEXT:    [[NY:%.*]] = xor i8 [[Y:%.*]], -1
+; CHECK-NEXT:    [[SUB:%.*]] = sub i8 [[Y]], [[X]]
+; CHECK-NEXT:    call void @use8(i8 [[NX]])
+; CHECK-NEXT:    call void @use8(i8 [[NY]])
+; CHECK-NEXT:    ret i8 [[SUB]]
+;
+  %nx = xor i8 %x, -1
+  %ny = xor i8 %y, -1
+  %sub = sub i8 %nx, %ny
+  call void @use8(i8 %nx)
+  call void @use8(i8 %ny)
+  ret i8 %sub
+}
+
+define <2 x i8> @notnotsub_vec(<2 x i8> %x, <2 x i8> %y) {
+; CHECK-LABEL: @notnotsub_vec(
+; CHECK-NEXT:    [[SUB:%.*]] = sub <2 x i8> [[Y:%.*]], [[X:%.*]]
+; CHECK-NEXT:    ret <2 x i8> [[SUB]]
+;
+  %nx = xor <2 x i8> %x, <i8 -1, i8 -1>
+  %ny = xor <2 x i8> %y, <i8 -1, i8 -1>
+  %sub = sub <2 x i8> %nx, %ny
+  ret <2 x i8> %sub
+}
+
+define <2 x i8> @notnotsub_vec_undef_elts(<2 x i8> %x, <2 x i8> %y) {
+; CHECK-LABEL: @notnotsub_vec_undef_elts(
+; CHECK-NEXT:    [[SUB:%.*]] = sub <2 x i8> [[Y:%.*]], [[X:%.*]]
+; CHECK-NEXT:    ret <2 x i8> [[SUB]]
+;
+  %nx = xor <2 x i8> %x, <i8 undef, i8 -1>
+  %ny = xor <2 x i8> %y, <i8 -1, i8 undef>
+  %sub = sub <2 x i8> %nx, %ny
+  ret <2 x i8> %sub
+}
+
+define i32 @test5(i32 %A, i32 %B, i32 %C) {
+; CHECK-LABEL: @test5(
+; CHECK-NEXT:    [[D1:%.*]] = sub i32 [[C:%.*]], [[B:%.*]]
+; CHECK-NEXT:    [[E:%.*]] = add i32 [[D1]], [[A:%.*]]
+; CHECK-NEXT:    ret i32 [[E]]
+;
+  %D = sub i32 %B, %C
+  %E = sub i32 %A, %D
+  ret i32 %E
+}
+
+define i32 @test6(i32 %A, i32 %B) {
+; CHECK-LABEL: @test6(
+; CHECK-NEXT:    [[B_NOT:%.*]] = xor i32 [[B:%.*]], -1
+; CHECK-NEXT:    [[D:%.*]] = and i32 [[B_NOT]], [[A:%.*]]
+; CHECK-NEXT:    ret i32 [[D]]
+;
+  %C = and i32 %A, %B
+  %D = sub i32 %A, %C
+  ret i32 %D
+}
+
+define i32 @test6commuted(i32 %A, i32 %B) {
+; CHECK-LABEL: @test6commuted(
+; CHECK-NEXT:    [[B_NOT:%.*]] = xor i32 [[B:%.*]], -1
+; CHECK-NEXT:    [[D:%.*]] = and i32 [[B_NOT]], [[A:%.*]]
+; CHECK-NEXT:    ret i32 [[D]]
+;
+  %C = and i32 %B, %A
+  %D = sub i32 %A, %C
+  ret i32 %D
+}
+
+define i32 @test7(i32 %A) {
+; CHECK-LABEL: @test7(
+; CHECK-NEXT:    [[B:%.*]] = xor i32 [[A:%.*]], -1
+; CHECK-NEXT:    ret i32 [[B]]
+;
+  %B = sub i32 -1, %A
+  ret i32 %B
+}
+
+define i32 @test8(i32 %A) {
+; CHECK-LABEL: @test8(
+; CHECK-NEXT:    [[C:%.*]] = shl i32 [[A:%.*]], 3
+; CHECK-NEXT:    ret i32 [[C]]
+;
+  %B = mul i32 9, %A
+  %C = sub i32 %B, %A
+  ret i32 %C
+}
+
+define i32 @test9(i32 %A) {
+; CHECK-LABEL: @test9(
+; CHECK-NEXT:    [[C:%.*]] = mul i32 [[A:%.*]], -2
+; CHECK-NEXT:    ret i32 [[C]]
+;
+  %B = mul i32 3, %A
+  %C = sub i32 %A, %B
+  ret i32 %C
+}
+
+define i1 @test11(i8 %A, i8 %B) {
+; CHECK-LABEL: @test11(
+; CHECK-NEXT:    [[D:%.*]] = icmp ne i8 [[A:%.*]], [[B:%.*]]
+; CHECK-NEXT:    ret i1 [[D]]
+;
+  %C = sub i8 %A, %B
+  %D = icmp ne i8 %C, 0
+  ret i1 %D
+}
+
+define <2 x i1> @test11vec(<2 x i8> %A, <2 x i8> %B) {
+; CHECK-LABEL: @test11vec(
+; CHECK-NEXT:    [[D:%.*]] = icmp ne <2 x i8> [[A:%.*]], [[B:%.*]]
+; CHECK-NEXT:    ret <2 x i1> [[D]]
+;
+  %C = sub <2 x i8> %A, %B
+  %D = icmp ne <2 x i8> %C, zeroinitializer
+  ret <2 x i1> %D
+}
+
+define i32 @test12(i32 %A) {
+; CHECK-LABEL: @test12(
+; CHECK-NEXT:    [[C:%.*]] = lshr i32 [[A:%.*]], 31
+; CHECK-NEXT:    ret i32 [[C]]
+;
+  %B = ashr i32 %A, 31
+  %C = sub i32 0, %B
+  ret i32 %C
+}
+
+define i32 @test13(i32 %A) {
+; CHECK-LABEL: @test13(
+; CHECK-NEXT:    [[C:%.*]] = ashr i32 [[A:%.*]], 31
+; CHECK-NEXT:    ret i32 [[C]]
+;
+  %B = lshr i32 %A, 31
+  %C = sub i32 0, %B
+  ret i32 %C
+}
+
+define <2 x i32> @test12vec(<2 x i32> %A) {
+; CHECK-LABEL: @test12vec(
+; CHECK-NEXT:    [[C:%.*]] = lshr <2 x i32> [[A:%.*]], <i32 31, i32 31>
+; CHECK-NEXT:    ret <2 x i32> [[C]]
+;
+  %B = ashr <2 x i32> %A, <i32 31, i32 31>
+  %C = sub <2 x i32> zeroinitializer, %B
+  ret <2 x i32> %C
+}
+
+define <2 x i32> @test13vec(<2 x i32> %A) {
+; CHECK-LABEL: @test13vec(
+; CHECK-NEXT:    [[C:%.*]] = ashr <2 x i32> [[A:%.*]], <i32 31, i32 31>
+; CHECK-NEXT:    ret <2 x i32> [[C]]
+;
+  %B = lshr <2 x i32> %A, <i32 31, i32 31>
+  %C = sub <2 x i32> zeroinitializer, %B
+  ret <2 x i32> %C
+}
+
+define i32 @test15(i32 %A, i32 %B) {
+; CHECK-LABEL: @test15(
+; CHECK-NEXT:    [[C:%.*]] = sub i32 0, [[A:%.*]]
+; CHECK-NEXT:    [[D:%.*]] = srem i32 [[B:%.*]], [[C]]
+; CHECK-NEXT:    ret i32 [[D]]
+;
+  %C = sub i32 0, %A
+  %D = srem i32 %B, %C
+  ret i32 %D
+}
+
+define i32 @test16(i32 %A) {
+; CHECK-LABEL: @test16(
+; CHECK-NEXT:    [[Y:%.*]] = sdiv i32 [[A:%.*]], -1123
+; CHECK-NEXT:    ret i32 [[Y]]
+;
+  %X = sdiv i32 %A, 1123
+  %Y = sub i32 0, %X
+  ret i32 %Y
+}
+
+; Can't fold subtract here because negation it might oveflow.
+; PR3142
+define i32 @test17(i32 %A) {
+; CHECK-LABEL: @test17(
+; CHECK-NEXT:    [[B:%.*]] = sub i32 0, [[A:%.*]]
+; CHECK-NEXT:    [[C:%.*]] = sdiv i32 [[B]], 1234
+; CHECK-NEXT:    ret i32 [[C]]
+;
+  %B = sub i32 0, %A
+  %C = sdiv i32 %B, 1234
+  ret i32 %C
+}
+
+define i64 @test18(i64 %Y) {
+; CHECK-LABEL: @test18(
+; CHECK-NEXT:    ret i64 0
+;
+  %tmp.4 = shl i64 %Y, 2
+  %tmp.12 = shl i64 %Y, 2
+  %tmp.8 = sub i64 %tmp.4, %tmp.12
+  ret i64 %tmp.8
+}
+
+define i1 @test20(i32 %g, i32 %h) {
+; CHECK-LABEL: @test20(
+; CHECK-NEXT:    [[TMP_4:%.*]] = icmp ne i32 [[H:%.*]], 0
+; CHECK-NEXT:    ret i1 [[TMP_4]]
+;
+  %tmp.2 = sub i32 %g, %h
+  %tmp.4 = icmp ne i32 %tmp.2, %g
+  ret i1 %tmp.4
+}
+
+define i1 @test21(i32 %g, i32 %h) {
+; CHECK-LABEL: @test21(
+; CHECK-NEXT:    [[TMP_4:%.*]] = icmp ne i32 [[H:%.*]], 0
+; CHECK-NEXT:    ret i1 [[TMP_4]]
+;
+  %tmp.2 = sub i32 %g, %h
+  %tmp.4 = icmp ne i32 %tmp.2, %g
+  ret i1 %tmp.4
+}
+
+; PR2298
+define zeroext i1 @test22(i32 %a, i32 %b)  nounwind  {
+; CHECK-LABEL: @test22(
+; CHECK-NEXT:    [[TMP5:%.*]] = icmp eq i32 [[B:%.*]], [[A:%.*]]
+; CHECK-NEXT:    ret i1 [[TMP5]]
+;
+  %tmp2 = sub i32 0, %a
+  %tmp4 = sub i32 0, %b
+  %tmp5 = icmp eq i32 %tmp2, %tmp4
+  ret i1 %tmp5
+}
+
+; rdar://7362831
+define i32 @test23(i8* %P, i64 %A){
+; CHECK-LABEL: @test23(
+; CHECK-NEXT:    [[TMP1:%.*]] = trunc i64 [[A:%.*]] to i32
+; CHECK-NEXT:    ret i32 [[TMP1]]
+;
+  %B = getelementptr inbounds i8, i8* %P, i64 %A
+  %C = ptrtoint i8* %B to i64
+  %D = trunc i64 %C to i32
+  %E = ptrtoint i8* %P to i64
+  %F = trunc i64 %E to i32
+  %G = sub i32 %D, %F
+  ret i32 %G
+}
+
+define i8 @test23_as1(i8 addrspace(1)* %P, i16 %A) {
+; CHECK-LABEL: @test23_as1(
+; CHECK-NEXT:    [[TMP1:%.*]] = trunc i16 [[A:%.*]] to i8
+; CHECK-NEXT:    ret i8 [[TMP1]]
+;
+  %B = getelementptr inbounds i8, i8 addrspace(1)* %P, i16 %A
+  %C = ptrtoint i8 addrspace(1)* %B to i16
+  %D = trunc i16 %C to i8
+  %E = ptrtoint i8 addrspace(1)* %P to i16
+  %F = trunc i16 %E to i8
+  %G = sub i8 %D, %F
+  ret i8 %G
+}
+
+define i64 @test24(i8* %P, i64 %A){
+; CHECK-LABEL: @test24(
+; CHECK-NEXT:    ret i64 [[A:%.*]]
+;
+  %B = getelementptr inbounds i8, i8* %P, i64 %A
+  %C = ptrtoint i8* %B to i64
+  %E = ptrtoint i8* %P to i64
+  %G = sub i64 %C, %E
+  ret i64 %G
+}
+
+define i16 @test24_as1(i8 addrspace(1)* %P, i16 %A) {
+; CHECK-LABEL: @test24_as1(
+; CHECK-NEXT:    ret i16 [[A:%.*]]
+;
+  %B = getelementptr inbounds i8, i8 addrspace(1)* %P, i16 %A
+  %C = ptrtoint i8 addrspace(1)* %B to i16
+  %E = ptrtoint i8 addrspace(1)* %P to i16
+  %G = sub i16 %C, %E
+  ret i16 %G
+}
+
+define i64 @test24a(i8* %P, i64 %A){
+; CHECK-LABEL: @test24a(
+; CHECK-NEXT:    [[DIFF_NEG:%.*]] = sub i64 0, [[A:%.*]]
+; CHECK-NEXT:    ret i64 [[DIFF_NEG]]
+;
+  %B = getelementptr inbounds i8, i8* %P, i64 %A
+  %C = ptrtoint i8* %B to i64
+  %E = ptrtoint i8* %P to i64
+  %G = sub i64 %E, %C
+  ret i64 %G
+}
+
+define i16 @test24a_as1(i8 addrspace(1)* %P, i16 %A) {
+; CHECK-LABEL: @test24a_as1(
+; CHECK-NEXT:    [[DIFF_NEG:%.*]] = sub i16 0, [[A:%.*]]
+; CHECK-NEXT:    ret i16 [[DIFF_NEG]]
+;
+  %B = getelementptr inbounds i8, i8 addrspace(1)* %P, i16 %A
+  %C = ptrtoint i8 addrspace(1)* %B to i16
+  %E = ptrtoint i8 addrspace(1)* %P to i16
+  %G = sub i16 %E, %C
+  ret i16 %G
+}
+
+
+ at Arr = external global [42 x i16]
+
+define i64 @test24b(i8* %P, i64 %A){
+; CHECK-LABEL: @test24b(
+; CHECK-NEXT:    [[B_IDX:%.*]] = shl nuw i64 [[A:%.*]], 1
+; CHECK-NEXT:    ret i64 [[B_IDX]]
+;
+  %B = getelementptr inbounds [42 x i16], [42 x i16]* @Arr, i64 0, i64 %A
+  %C = ptrtoint i16* %B to i64
+  %G = sub i64 %C, ptrtoint ([42 x i16]* @Arr to i64)
+  ret i64 %G
+}
+
+
+define i64 @test25(i8* %P, i64 %A){
+; CHECK-LABEL: @test25(
+; CHECK-NEXT:    [[B_IDX:%.*]] = shl nuw i64 [[A:%.*]], 1
+; CHECK-NEXT:    [[TMP1:%.*]] = add i64 [[B_IDX]], -84
+; CHECK-NEXT:    ret i64 [[TMP1]]
+;
+  %B = getelementptr inbounds [42 x i16], [42 x i16]* @Arr, i64 0, i64 %A
+  %C = ptrtoint i16* %B to i64
+  %G = sub i64 %C, ptrtoint (i16* getelementptr ([42 x i16], [42 x i16]* @Arr, i64 1, i64 0) to i64)
+  ret i64 %G
+}
+
+ at Arr_as1 = external addrspace(1) global [42 x i16]
+
+define i16 @test25_as1(i8 addrspace(1)* %P, i64 %A) {
+; CHECK-LABEL: @test25_as1(
+; CHECK-NEXT:    [[TMP1:%.*]] = trunc i64 [[A:%.*]] to i16
+; CHECK-NEXT:    [[B_IDX:%.*]] = shl nuw i16 [[TMP1]], 1
+; CHECK-NEXT:    [[TMP2:%.*]] = add i16 [[B_IDX]], -84
+; CHECK-NEXT:    ret i16 [[TMP2]]
+;
+  %B = getelementptr inbounds [42 x i16], [42 x i16] addrspace(1)* @Arr_as1, i64 0, i64 %A
+  %C = ptrtoint i16 addrspace(1)* %B to i16
+  %G = sub i16 %C, ptrtoint (i16 addrspace(1)* getelementptr ([42 x i16], [42 x i16] addrspace(1)* @Arr_as1, i64 1, i64 0) to i16)
+  ret i16 %G
+}
+
+define i32 @test26(i32 %x) {
+; CHECK-LABEL: @test26(
+; CHECK-NEXT:    [[NEG:%.*]] = shl i32 -3, [[X:%.*]]
+; CHECK-NEXT:    ret i32 [[NEG]]
+;
+  %shl = shl i32 3, %x
+  %neg = sub i32 0, %shl
+  ret i32 %neg
+}
+
+define i32 @test27(i32 %x, i32 %y) {
+; CHECK-LABEL: @test27(
+; CHECK-NEXT:    [[TMP1:%.*]] = shl i32 [[Y:%.*]], 3
+; CHECK-NEXT:    [[SUB:%.*]] = add i32 [[TMP1]], [[X:%.*]]
+; CHECK-NEXT:    ret i32 [[SUB]]
+;
+  %mul = mul i32 %y, -8
+  %sub = sub i32 %x, %mul
+  ret i32 %sub
+}
+
+define <2 x i32> @test27vec(<2 x i32> %x, <2 x i32> %y) {
+; CHECK-LABEL: @test27vec(
+; CHECK-NEXT:    [[TMP1:%.*]] = mul <2 x i32> [[Y:%.*]], <i32 8, i32 6>
+; CHECK-NEXT:    [[SUB:%.*]] = add <2 x i32> [[TMP1]], [[X:%.*]]
+; CHECK-NEXT:    ret <2 x i32> [[SUB]]
+;
+  %mul = mul <2 x i32> %y, <i32 -8, i32 -6>
+  %sub = sub <2 x i32> %x, %mul
+  ret <2 x i32> %sub
+}
+
+define <2 x i32> @test27vecsplat(<2 x i32> %x, <2 x i32> %y) {
+; CHECK-LABEL: @test27vecsplat(
+; CHECK-NEXT:    [[TMP1:%.*]] = shl <2 x i32> [[Y:%.*]], <i32 3, i32 3>
+; CHECK-NEXT:    [[SUB:%.*]] = add <2 x i32> [[TMP1]], [[X:%.*]]
+; CHECK-NEXT:    ret <2 x i32> [[SUB]]
+;
+  %mul = mul <2 x i32> %y, <i32 -8, i32 -8>
+  %sub = sub <2 x i32> %x, %mul
+  ret <2 x i32> %sub
+}
+
+define <2 x i32> @test27vecmixed(<2 x i32> %x, <2 x i32> %y) {
+; CHECK-LABEL: @test27vecmixed(
+; CHECK-NEXT:    [[TMP1:%.*]] = mul <2 x i32> [[Y:%.*]], <i32 8, i32 -8>
+; CHECK-NEXT:    [[SUB:%.*]] = add <2 x i32> [[TMP1]], [[X:%.*]]
+; CHECK-NEXT:    ret <2 x i32> [[SUB]]
+;
+  %mul = mul <2 x i32> %y, <i32 -8, i32 8>
+  %sub = sub <2 x i32> %x, %mul
+  ret <2 x i32> %sub
+}
+
+define i32 @test27commuted(i32 %x, i32 %y) {
+; CHECK-LABEL: @test27commuted(
+; CHECK-NEXT:    [[TMP1:%.*]] = shl i32 [[Y:%.*]], 3
+; CHECK-NEXT:    [[SUB:%.*]] = add i32 [[TMP1]], [[X:%.*]]
+; CHECK-NEXT:    ret i32 [[SUB]]
+;
+  %mul = mul i32 -8, %y
+  %sub = sub i32 %x, %mul
+  ret i32 %sub
+}
+
+define <2 x i32> @test27commutedvec(<2 x i32> %x, <2 x i32> %y) {
+; CHECK-LABEL: @test27commutedvec(
+; CHECK-NEXT:    [[TMP1:%.*]] = mul <2 x i32> [[Y:%.*]], <i32 8, i32 6>
+; CHECK-NEXT:    [[SUB:%.*]] = add <2 x i32> [[TMP1]], [[X:%.*]]
+; CHECK-NEXT:    ret <2 x i32> [[SUB]]
+;
+  %mul = mul <2 x i32> <i32 -8, i32 -6>, %y
+  %sub = sub <2 x i32> %x, %mul
+  ret <2 x i32> %sub
+}
+
+define <2 x i32> @test27commutedvecsplat(<2 x i32> %x, <2 x i32> %y) {
+; CHECK-LABEL: @test27commutedvecsplat(
+; CHECK-NEXT:    [[TMP1:%.*]] = shl <2 x i32> [[Y:%.*]], <i32 3, i32 3>
+; CHECK-NEXT:    [[SUB:%.*]] = add <2 x i32> [[TMP1]], [[X:%.*]]
+; CHECK-NEXT:    ret <2 x i32> [[SUB]]
+;
+  %mul = mul <2 x i32> <i32 -8, i32 -8>, %y
+  %sub = sub <2 x i32> %x, %mul
+  ret <2 x i32> %sub
+}
+
+define <2 x i32> @test27commutedvecmixed(<2 x i32> %x, <2 x i32> %y) {
+; CHECK-LABEL: @test27commutedvecmixed(
+; CHECK-NEXT:    [[TMP1:%.*]] = mul <2 x i32> [[Y:%.*]], <i32 8, i32 -8>
+; CHECK-NEXT:    [[SUB:%.*]] = add <2 x i32> [[TMP1]], [[X:%.*]]
+; CHECK-NEXT:    ret <2 x i32> [[SUB]]
+;
+  %mul = mul <2 x i32> <i32 -8, i32 8>, %y
+  %sub = sub <2 x i32> %x, %mul
+  ret <2 x i32> %sub
+}
+
+define i32 @test28(i32 %x, i32 %y, i32 %z) {
+; CHECK-LABEL: @test28(
+; CHECK-NEXT:    [[TMP1:%.*]] = mul i32 [[Z:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    [[SUB:%.*]] = add i32 [[TMP1]], [[X:%.*]]
+; CHECK-NEXT:    ret i32 [[SUB]]
+;
+  %neg = sub i32 0, %z
+  %mul = mul i32 %neg, %y
+  %sub = sub i32 %x, %mul
+  ret i32 %sub
+}
+
+define i32 @test28commuted(i32 %x, i32 %y, i32 %z) {
+; CHECK-LABEL: @test28commuted(
+; CHECK-NEXT:    [[TMP1:%.*]] = mul i32 [[Z:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    [[SUB:%.*]] = add i32 [[TMP1]], [[X:%.*]]
+; CHECK-NEXT:    ret i32 [[SUB]]
+;
+  %neg = sub i32 0, %z
+  %mul = mul i32 %y, %neg
+  %sub = sub i32 %x, %mul
+  ret i32 %sub
+}
+
+define i64 @test29(i8* %foo, i64 %i, i64 %j) {
+; CHECK-LABEL: @test29(
+; CHECK-NEXT:    [[TMP1:%.*]] = sub i64 [[I:%.*]], [[J:%.*]]
+; CHECK-NEXT:    ret i64 [[TMP1]]
+;
+  %gep1 = getelementptr inbounds i8, i8* %foo, i64 %i
+  %gep2 = getelementptr inbounds i8, i8* %foo, i64 %j
+  %cast1 = ptrtoint i8* %gep1 to i64
+  %cast2 = ptrtoint i8* %gep2 to i64
+  %sub = sub i64 %cast1, %cast2
+  ret i64 %sub
+}
+
+define i64 @test30(i8* %foo, i64 %i, i64 %j) {
+; CHECK-LABEL: @test30(
+; CHECK-NEXT:    [[GEP1_IDX:%.*]] = shl nuw i64 [[I:%.*]], 2
+; CHECK-NEXT:    [[TMP1:%.*]] = sub i64 [[GEP1_IDX]], [[J:%.*]]
+; CHECK-NEXT:    ret i64 [[TMP1]]
+;
+  %bit = bitcast i8* %foo to i32*
+  %gep1 = getelementptr inbounds i32, i32* %bit, i64 %i
+  %gep2 = getelementptr inbounds i8, i8* %foo, i64 %j
+  %cast1 = ptrtoint i32* %gep1 to i64
+  %cast2 = ptrtoint i8* %gep2 to i64
+  %sub = sub i64 %cast1, %cast2
+  ret i64 %sub
+}
+
+define i16 @test30_as1(i8 addrspace(1)* %foo, i16 %i, i16 %j) {
+; CHECK-LABEL: @test30_as1(
+; CHECK-NEXT:    [[GEP1_IDX:%.*]] = shl nuw i16 [[I:%.*]], 2
+; CHECK-NEXT:    [[TMP1:%.*]] = sub i16 [[GEP1_IDX]], [[J:%.*]]
+; CHECK-NEXT:    ret i16 [[TMP1]]
+;
+  %bit = bitcast i8 addrspace(1)* %foo to i32 addrspace(1)*
+  %gep1 = getelementptr inbounds i32, i32 addrspace(1)* %bit, i16 %i
+  %gep2 = getelementptr inbounds i8, i8 addrspace(1)* %foo, i16 %j
+  %cast1 = ptrtoint i32 addrspace(1)* %gep1 to i16
+  %cast2 = ptrtoint i8 addrspace(1)* %gep2 to i16
+  %sub = sub i16 %cast1, %cast2
+  ret i16 %sub
+}
+
+define <2 x i64> @test31(<2 x i64> %A) {
+; CHECK-LABEL: @test31(
+; CHECK-NEXT:    [[SUB:%.*]] = add <2 x i64> [[A:%.*]], <i64 3, i64 4>
+; CHECK-NEXT:    ret <2 x i64> [[SUB]]
+;
+  %xor = xor <2 x i64> %A, <i64 -1, i64 -1>
+  %sub = sub <2 x i64> <i64 2, i64 3>, %xor
+  ret <2 x i64> %sub
+}
+
+define <2 x i64> @test32(<2 x i64> %A) {
+; CHECK-LABEL: @test32(
+; CHECK-NEXT:    [[SUB:%.*]] = sub <2 x i64> <i64 3, i64 4>, [[A:%.*]]
+; CHECK-NEXT:    ret <2 x i64> [[SUB]]
+;
+  %add = add <2 x i64> %A, <i64 -1, i64 -1>
+  %sub = sub <2 x i64> <i64 2, i64 3>, %add
+  ret <2 x i64> %sub
+}
+
+define <2 x i64> @test35(<2 x i64> %A) {
+; CHECK-LABEL: @test35(
+; CHECK-NEXT:    [[SUB:%.*]] = mul <2 x i64> [[A:%.*]], <i64 -2, i64 -3>
+; CHECK-NEXT:    ret <2 x i64> [[SUB]]
+;
+  %mul = mul <2 x i64> %A, <i64 3, i64 4>
+  %sub = sub <2 x i64> %A, %mul
+  ret <2 x i64> %sub
+}
+
+define <2 x i64> @test36(<2 x i64> %A) {
+; CHECK-LABEL: @test36(
+; CHECK-NEXT:    [[SUB:%.*]] = mul <2 x i64> [[A:%.*]], <i64 7, i64 15>
+; CHECK-NEXT:    ret <2 x i64> [[SUB]]
+;
+  %shl = shl <2 x i64> %A, <i64 3, i64 4>
+  %sub = sub <2 x i64> %shl, %A
+  ret <2 x i64> %sub
+}
+
+define <2 x i32> @test37(<2 x i32> %A) {
+; CHECK-LABEL: @test37(
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp eq <2 x i32> [[A:%.*]], <i32 -2147483648, i32 -2147483648>
+; CHECK-NEXT:    [[SUB:%.*]] = sext <2 x i1> [[TMP1]] to <2 x i32>
+; CHECK-NEXT:    ret <2 x i32> [[SUB]]
+;
+  %div = sdiv <2 x i32> %A, <i32 -2147483648, i32 -2147483648>
+  %sub = sub nsw <2 x i32> zeroinitializer, %div
+  ret <2 x i32> %sub
+}
+
+define i32 @test38(i32 %A) {
+; CHECK-LABEL: @test38(
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp eq i32 [[A:%.*]], -2147483648
+; CHECK-NEXT:    [[SUB:%.*]] = sext i1 [[TMP1]] to i32
+; CHECK-NEXT:    ret i32 [[SUB]]
+;
+  %div = sdiv i32 %A, -2147483648
+  %sub = sub nsw i32 0, %div
+  ret i32 %sub
+}
+
+define i16 @test40(i16 %a, i16 %b) {
+; CHECK-LABEL: @test40(
+; CHECK-NEXT:    [[ASHR:%.*]] = ashr i16 [[A:%.*]], 1
+; CHECK-NEXT:    [[ASHR1:%.*]] = ashr i16 [[B:%.*]], 1
+; CHECK-NEXT:    [[SUB:%.*]] = sub nsw i16 [[ASHR]], [[ASHR1]]
+; CHECK-NEXT:    ret i16 [[SUB]]
+;
+  %ashr = ashr i16 %a, 1
+  %ashr1 = ashr i16 %b, 1
+  %sub = sub i16 %ashr, %ashr1
+  ret i16 %sub
+}
+
+define i32 @test41(i16 %a, i16 %b) {
+; CHECK-LABEL: @test41(
+; CHECK-NEXT:    [[CONV:%.*]] = sext i16 [[A:%.*]] to i32
+; CHECK-NEXT:    [[CONV1:%.*]] = sext i16 [[B:%.*]] to i32
+; CHECK-NEXT:    [[SUB:%.*]] = sub nsw i32 [[CONV]], [[CONV1]]
+; CHECK-NEXT:    ret i32 [[SUB]]
+;
+  %conv = sext i16 %a to i32
+  %conv1 = sext i16 %b to i32
+  %sub = sub i32 %conv, %conv1
+  ret i32 %sub
+}
+
+define i4 @test42(i4 %x, i4 %y) {
+; CHECK-LABEL: @test42(
+; CHECK-NEXT:    [[A:%.*]] = and i4 [[Y:%.*]], 7
+; CHECK-NEXT:    [[B:%.*]] = and i4 [[X:%.*]], 7
+; CHECK-NEXT:    [[C:%.*]] = sub nsw i4 [[A]], [[B]]
+; CHECK-NEXT:    ret i4 [[C]]
+;
+  %a = and i4 %y, 7
+  %b = and i4 %x, 7
+  %c = sub i4 %a, %b
+  ret i4 %c
+}
+
+define i4 @test43(i4 %x, i4 %y) {
+; CHECK-LABEL: @test43(
+; CHECK-NEXT:    [[A:%.*]] = or i4 [[X:%.*]], -8
+; CHECK-NEXT:    [[B:%.*]] = and i4 [[Y:%.*]], 7
+; CHECK-NEXT:    [[C:%.*]] = sub nuw i4 [[A]], [[B]]
+; CHECK-NEXT:    ret i4 [[C]]
+;
+  %a = or i4 %x, -8
+  %b = and i4 %y, 7
+  %c = sub i4 %a, %b
+  ret i4 %c
+}
+
+define i32 @test44(i32 %x) {
+; CHECK-LABEL: @test44(
+; CHECK-NEXT:    [[SUB:%.*]] = add nsw i32 [[X:%.*]], -32768
+; CHECK-NEXT:    ret i32 [[SUB]]
+;
+  %sub = sub nsw i32 %x, 32768
+  ret i32 %sub
+}
+
+define i32 @test45(i32 %x, i32 %y) {
+; CHECK-LABEL: @test45(
+; CHECK-NEXT:    [[SUB:%.*]] = and i32 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    ret i32 [[SUB]]
+;
+  %or = or i32 %x, %y
+  %xor = xor i32 %x, %y
+  %sub = sub i32 %or, %xor
+  ret i32 %sub
+}
+
+define i32 @test45commuted(i32 %x, i32 %y) {
+; CHECK-LABEL: @test45commuted(
+; CHECK-NEXT:    [[SUB:%.*]] = and i32 [[Y:%.*]], [[X:%.*]]
+; CHECK-NEXT:    ret i32 [[SUB]]
+;
+  %or = or i32 %x, %y
+  %xor = xor i32 %y, %x
+  %sub = sub i32 %or, %xor
+  ret i32 %sub
+}
+
+define i32 @test46(i32 %x, i32 %y) {
+; CHECK-LABEL: @test46(
+; CHECK-NEXT:    [[X_NOT:%.*]] = xor i32 [[X:%.*]], -1
+; CHECK-NEXT:    [[SUB:%.*]] = and i32 [[X_NOT]], [[Y:%.*]]
+; CHECK-NEXT:    ret i32 [[SUB]]
+;
+  %or = or i32 %x, %y
+  %sub = sub i32 %or, %x
+  ret i32 %sub
+}
+
+define i32 @test46commuted(i32 %x, i32 %y) {
+; CHECK-LABEL: @test46commuted(
+; CHECK-NEXT:    [[X_NOT:%.*]] = xor i32 [[X:%.*]], -1
+; CHECK-NEXT:    [[SUB:%.*]] = and i32 [[X_NOT]], [[Y:%.*]]
+; CHECK-NEXT:    ret i32 [[SUB]]
+;
+  %or = or i32 %y, %x
+  %sub = sub i32 %or, %x
+  ret i32 %sub
+}
+
+define i32 @test47(i1 %A, i32 %B, i32 %C, i32 %D) {
+; CHECK-LABEL: @test47(
+; CHECK-NEXT:    [[TMP1:%.*]] = sub i32 [[D:%.*]], [[C:%.*]]
+; CHECK-NEXT:    [[SUB:%.*]] = select i1 [[A:%.*]], i32 [[TMP1]], i32 0
+; CHECK-NEXT:    ret i32 [[SUB]]
+;
+  %sel0 = select i1 %A, i32 %D, i32 %B
+  %sel1 = select i1 %A, i32 %C, i32 %B
+  %sub = sub i32 %sel0, %sel1
+  ret i32 %sub
+}
+
+define i32 @test48(i1 %A, i32 %B, i32 %C, i32 %D) {
+; CHECK-LABEL: @test48(
+; CHECK-NEXT:    [[TMP1:%.*]] = sub i32 [[D:%.*]], [[C:%.*]]
+; CHECK-NEXT:    [[SUB:%.*]] = select i1 [[A:%.*]], i32 0, i32 [[TMP1]]
+; CHECK-NEXT:    ret i32 [[SUB]]
+;
+  %sel0 = select i1 %A, i32 %B, i32 %D
+  %sel1 = select i1 %A, i32 %B, i32 %C
+  %sub = sub i32 %sel0, %sel1
+  ret i32 %sub
+}
+
+define i32 @test49(i32 %X) {
+; CHECK-LABEL: @test49(
+; CHECK-NEXT:    [[SUB:%.*]] = sub i32 1, [[X:%.*]]
+; CHECK-NEXT:    [[RES:%.*]] = and i32 [[SUB]], 64
+; CHECK-NEXT:    ret i32 [[RES]]
+;
+  %sub = sub i32 129, %X
+  %res = and i32 %sub, 64
+  ret i32 %res
+}
+
+define i32 @test50(i32 %X) {
+; CHECK-LABEL: @test50(
+; CHECK-NEXT:    [[SUB:%.*]] = sub i32 1, [[X:%.*]]
+; CHECK-NEXT:    [[RES:%.*]] = and i32 [[SUB]], 127
+; CHECK-NEXT:    ret i32 [[RES]]
+;
+  %sub = sub i32 129, %X
+  %res = and i32 %sub, 127
+  ret i32 %res
+}
+
+define i32 @test51(i32 %X) {
+; CHECK-LABEL: @test51(
+; CHECK-NEXT:    [[SUB:%.*]] = sub i32 126, [[X:%.*]]
+; CHECK-NEXT:    [[RES:%.*]] = and i32 [[SUB]], 64
+; CHECK-NEXT:    ret i32 [[RES]]
+;
+  %sub = sub i32 254, %X
+  %res = and i32 %sub, 64
+  ret i32 %res
+}
+
+define i32 @test52(i32 %X) {
+; CHECK-LABEL: @test52(
+; CHECK-NEXT:    [[SUB:%.*]] = sub i32 126, [[X:%.*]]
+; CHECK-NEXT:    [[RES:%.*]] = and i32 [[SUB]], 127
+; CHECK-NEXT:    ret i32 [[RES]]
+;
+  %sub = sub i32 254, %X
+  %res = and i32 %sub, 127
+  ret i32 %res
+}
+
+define <2 x i1> @test53(<2 x i1> %A, <2 x i1> %B) {
+; CHECK-LABEL: @test53(
+; CHECK-NEXT:    [[SUB:%.*]] = xor <2 x i1> [[A:%.*]], [[B:%.*]]
+; CHECK-NEXT:    ret <2 x i1> [[SUB]]
+;
+  %sub = sub <2 x i1> %A, %B
+  ret <2 x i1> %sub
+}
+
+define i32 @test54(i1 %C) {
+; CHECK-LABEL: @test54(
+; CHECK-NEXT:    [[V:%.*]] = select i1 [[C:%.*]], i32 -877, i32 113
+; CHECK-NEXT:    ret i32 [[V]]
+;
+  %A = select i1 %C, i32 1000, i32 10
+  %V = sub i32 123, %A
+  ret i32 %V
+}
+
+define <2 x i32> @test54vec(i1 %C) {
+; CHECK-LABEL: @test54vec(
+; CHECK-NEXT:    [[V:%.*]] = select i1 [[C:%.*]], <2 x i32> <i32 -877, i32 -877>, <2 x i32> <i32 113, i32 113>
+; CHECK-NEXT:    ret <2 x i32> [[V]]
+;
+  %A = select i1 %C, <2 x i32> <i32 1000, i32 1000>, <2 x i32> <i32 10, i32 10>
+  %V = sub <2 x i32> <i32 123, i32 123>, %A
+  ret <2 x i32> %V
+}
+
+define <2 x i32> @test54vec2(i1 %C) {
+; CHECK-LABEL: @test54vec2(
+; CHECK-NEXT:    [[V:%.*]] = select i1 [[C:%.*]], <2 x i32> <i32 -877, i32 -2167>, <2 x i32> <i32 113, i32 303>
+; CHECK-NEXT:    ret <2 x i32> [[V]]
+;
+  %A = select i1 %C, <2 x i32> <i32 1000, i32 2500>, <2 x i32> <i32 10, i32 30>
+  %V = sub <2 x i32> <i32 123, i32 333>, %A
+  ret <2 x i32> %V
+}
+
+define i32 @test55(i1 %which) {
+; CHECK-LABEL: @test55(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    br i1 [[WHICH:%.*]], label [[FINAL:%.*]], label [[DELAY:%.*]]
+; CHECK:       delay:
+; CHECK-NEXT:    br label [[FINAL]]
+; CHECK:       final:
+; CHECK-NEXT:    [[A:%.*]] = phi i32 [ -877, [[ENTRY:%.*]] ], [ 113, [[DELAY]] ]
+; CHECK-NEXT:    ret i32 [[A]]
+;
+entry:
+  br i1 %which, label %final, label %delay
+
+delay:
+  br label %final
+
+final:
+  %A = phi i32 [ 1000, %entry ], [ 10, %delay ]
+  %value = sub i32 123, %A
+  ret i32 %value
+}
+
+define <2 x i32> @test55vec(i1 %which) {
+; CHECK-LABEL: @test55vec(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    br i1 [[WHICH:%.*]], label [[FINAL:%.*]], label [[DELAY:%.*]]
+; CHECK:       delay:
+; CHECK-NEXT:    br label [[FINAL]]
+; CHECK:       final:
+; CHECK-NEXT:    [[A:%.*]] = phi <2 x i32> [ <i32 -877, i32 -877>, [[ENTRY:%.*]] ], [ <i32 113, i32 113>, [[DELAY]] ]
+; CHECK-NEXT:    ret <2 x i32> [[A]]
+;
+entry:
+  br i1 %which, label %final, label %delay
+
+delay:
+  br label %final
+
+final:
+  %A = phi <2 x i32> [ <i32 1000, i32 1000>, %entry ], [ <i32 10, i32 10>, %delay ]
+  %value = sub <2 x i32> <i32 123, i32 123>, %A
+  ret <2 x i32> %value
+}
+
+define <2 x i32> @test55vec2(i1 %which) {
+; CHECK-LABEL: @test55vec2(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    br i1 [[WHICH:%.*]], label [[FINAL:%.*]], label [[DELAY:%.*]]
+; CHECK:       delay:
+; CHECK-NEXT:    br label [[FINAL]]
+; CHECK:       final:
+; CHECK-NEXT:    [[A:%.*]] = phi <2 x i32> [ <i32 -877, i32 -2167>, [[ENTRY:%.*]] ], [ <i32 113, i32 303>, [[DELAY]] ]
+; CHECK-NEXT:    ret <2 x i32> [[A]]
+;
+entry:
+  br i1 %which, label %final, label %delay
+
+delay:
+  br label %final
+
+final:
+  %A = phi <2 x i32> [ <i32 1000, i32 2500>, %entry ], [ <i32 10, i32 30>, %delay ]
+  %value = sub <2 x i32> <i32 123, i32 333>, %A
+  ret <2 x i32> %value
+}
+
+define i32 @test56(i32 %A, i32 %B) {
+; CHECK-LABEL: @test56(
+; CHECK-NEXT:    [[Y:%.*]] = sub i32 0, [[B:%.*]]
+; CHECK-NEXT:    ret i32 [[Y]]
+;
+  %X = add i32 %A, %B
+  %Y = sub i32 %A, %X
+  ret i32 %Y
+}
+
+define i32 @test57(i32 %A, i32 %B) {
+; CHECK-LABEL: @test57(
+; CHECK-NEXT:    [[Y:%.*]] = sub i32 0, [[B:%.*]]
+; CHECK-NEXT:    ret i32 [[Y]]
+;
+  %X = add i32 %B, %A
+  %Y = sub i32 %A, %X
+  ret i32 %Y
+}
+
+ at dummy_global1 = external global i8*
+ at dummy_global2 = external global i8*
+
+define i64 @test58([100 x [100 x i8]]* %foo, i64 %i, i64 %j) {
+; Note the reassociate pass and another instcombine pass will further optimize this to
+; "%sub = i64 %i, %j, ret i64 %sub"
+; gep1 and gep2 have only one use
+; CHECK-LABEL: @test58(
+; CHECK-NEXT:    [[GEP2_OFFS:%.*]] = add i64 [[J:%.*]], 4200
+; CHECK-NEXT:    [[GEP1_OFFS:%.*]] = add i64 [[I:%.*]], 4200
+; CHECK-NEXT:    [[TMP1:%.*]] = sub i64 [[GEP1_OFFS]], [[GEP2_OFFS]]
+; CHECK-NEXT:    ret i64 [[TMP1]]
+;
+  %gep1 = getelementptr inbounds [100 x [100 x i8]], [100 x [100 x i8]]* %foo, i64 0, i64 42, i64 %i
+  %gep2 = getelementptr inbounds [100 x [100 x i8]], [100 x [100 x i8]]* %foo, i64 0, i64 42, i64 %j
+  %cast1 = ptrtoint i8* %gep1 to i64
+  %cast2 = ptrtoint i8* %gep2 to i64
+  %sub = sub i64 %cast1, %cast2
+  ret i64 %sub
+}
+
+define i64 @test59([100 x [100 x i8]]* %foo, i64 %i) {
+; CHECK-LABEL: @test59(
+; CHECK-NEXT:    [[GEP1:%.*]] = getelementptr inbounds [100 x [100 x i8]], [100 x [100 x i8]]* [[FOO:%.*]], i64 0, i64 42, i64 [[I:%.*]]
+; CHECK-NEXT:    [[GEP2:%.*]] = getelementptr inbounds [100 x [100 x i8]], [100 x [100 x i8]]* [[FOO]], i64 0, i64 42, i64 0
+; CHECK-NEXT:    store i8* [[GEP1]], i8** @dummy_global1, align 8
+; CHECK-NEXT:    store i8* [[GEP2]], i8** @dummy_global2, align 8
+; CHECK-NEXT:    ret i64 [[I]]
+;
+; gep1 and gep2 have more than one uses
+  %gep1 = getelementptr inbounds [100 x [100 x i8]], [100 x [100 x i8]]* %foo, i64 0, i64 42, i64 %i
+  %gep2 = getelementptr inbounds [100 x [100 x i8]], [100 x [100 x i8]]* %foo, i64 0, i64 42, i64 0
+  %cast1 = ptrtoint i8* %gep1 to i64
+  %cast2 = ptrtoint i8* %gep2 to i64
+  %sub = sub i64 %cast1, %cast2
+  store i8* %gep1, i8** @dummy_global1
+  store i8* %gep2, i8** @dummy_global2
+  ret i64 %sub
+}
+
+define i64 @test60([100 x [100 x i8]]* %foo, i64 %i, i64 %j) {
+; CHECK-LABEL: @test60(
+; CHECK-NEXT:    [[GEP1:%.*]] = getelementptr inbounds [100 x [100 x i8]], [100 x [100 x i8]]* [[FOO:%.*]], i64 0, i64 [[J:%.*]], i64 [[I:%.*]]
+; CHECK-NEXT:    [[GEP2:%.*]] = getelementptr inbounds [100 x [100 x i8]], [100 x [100 x i8]]* [[FOO]], i64 0, i64 42, i64 0
+; CHECK-NEXT:    [[CAST1:%.*]] = ptrtoint i8* [[GEP1]] to i64
+; CHECK-NEXT:    [[CAST2:%.*]] = ptrtoint i8* [[GEP2]] to i64
+; CHECK-NEXT:    [[SUB:%.*]] = sub i64 [[CAST1]], [[CAST2]]
+; CHECK-NEXT:    store i8* [[GEP1]], i8** @dummy_global1, align 8
+; CHECK-NEXT:    ret i64 [[SUB]]
+;
+; gep1 has a non-constant index and more than one uses. Shouldn't duplicate the arithmetic.
+  %gep1 = getelementptr inbounds [100 x [100 x i8]], [100 x [100 x i8]]* %foo, i64 0, i64 %j, i64 %i
+  %gep2 = getelementptr inbounds [100 x [100 x i8]], [100 x [100 x i8]]* %foo, i64 0, i64 42, i64 0
+  %cast1 = ptrtoint i8* %gep1 to i64
+  %cast2 = ptrtoint i8* %gep2 to i64
+  %sub = sub i64 %cast1, %cast2
+  store i8* %gep1, i8** @dummy_global1
+  ret i64 %sub
+}
+
+define i64 @test61([100 x [100 x i8]]* %foo, i64 %i, i64 %j) {
+; CHECK-LABEL: @test61(
+; CHECK-NEXT:    [[GEP1:%.*]] = getelementptr inbounds [100 x [100 x i8]], [100 x [100 x i8]]* [[FOO:%.*]], i64 0, i64 42, i64 0
+; CHECK-NEXT:    [[GEP2:%.*]] = getelementptr inbounds [100 x [100 x i8]], [100 x [100 x i8]]* [[FOO]], i64 0, i64 [[J:%.*]], i64 [[I:%.*]]
+; CHECK-NEXT:    [[CAST1:%.*]] = ptrtoint i8* [[GEP1]] to i64
+; CHECK-NEXT:    [[CAST2:%.*]] = ptrtoint i8* [[GEP2]] to i64
+; CHECK-NEXT:    [[SUB:%.*]] = sub i64 [[CAST1]], [[CAST2]]
+; CHECK-NEXT:    store i8* [[GEP2]], i8** @dummy_global2, align 8
+; CHECK-NEXT:    ret i64 [[SUB]]
+;
+; gep2 has a non-constant index and more than one uses. Shouldn't duplicate the arithmetic.
+  %gep1 = getelementptr inbounds [100 x [100 x i8]], [100 x [100 x i8]]* %foo, i64 0, i64 42, i64 0
+  %gep2 = getelementptr inbounds [100 x [100 x i8]], [100 x [100 x i8]]* %foo, i64 0, i64 %j, i64 %i
+  %cast1 = ptrtoint i8* %gep1 to i64
+  %cast2 = ptrtoint i8* %gep2 to i64
+  %sub = sub i64 %cast1, %cast2
+  store i8* %gep2, i8** @dummy_global2
+  ret i64 %sub
+}
+
+define i32 @test62(i32 %A) {
+; CHECK-LABEL: @test62(
+; CHECK-NEXT:    [[B:%.*]] = shl i32 [[A:%.*]], 1
+; CHECK-NEXT:    [[C:%.*]] = sub i32 2, [[B]]
+; CHECK-NEXT:    ret i32 [[C]]
+;
+  %B = sub i32 1, %A
+  %C = shl i32 %B, 1
+  ret i32 %C
+}
+
+define <2 x i32> @test62vec(<2 x i32> %A) {
+; CHECK-LABEL: @test62vec(
+; CHECK-NEXT:    [[B:%.*]] = shl <2 x i32> [[A:%.*]], <i32 1, i32 1>
+; CHECK-NEXT:    [[C:%.*]] = sub <2 x i32> <i32 2, i32 2>, [[B]]
+; CHECK-NEXT:    ret <2 x i32> [[C]]
+;
+  %B = sub <2 x i32> <i32 1, i32 1>, %A
+  %C = shl <2 x i32> %B, <i32 1, i32 1>
+  ret <2 x i32> %C
+}
+
+define i32 @test63(i32 %A) {
+; CHECK-LABEL: @test63(
+; CHECK-NEXT:    [[B:%.*]] = shl i32 [[A:%.*]], 1
+; CHECK-NEXT:    ret i32 [[B]]
+;
+  %B = sub i32 1, %A
+  %C = shl i32 %B, 1
+  %D = sub i32 2, %C
+  ret i32 %D
+}
+
+define <2 x i32> @test63vec(<2 x i32> %A) {
+; CHECK-LABEL: @test63vec(
+; CHECK-NEXT:    [[B:%.*]] = shl <2 x i32> [[A:%.*]], <i32 1, i32 1>
+; CHECK-NEXT:    ret <2 x i32> [[B]]
+;
+  %B = sub <2 x i32> <i32 1, i32 1>, %A
+  %C = shl <2 x i32> %B, <i32 1, i32 1>
+  %D = sub <2 x i32> <i32 2, i32 2>, %C
+  ret <2 x i32> %D
+}
+
+; FIXME: Transform (neg (max ~X, C)) -> ((min X, ~C) + 1). Same for min.
+define i32 @test64(i32 %x) {
+; CHECK-LABEL: @test64(
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp slt i32 [[X:%.*]], 255
+; CHECK-NEXT:    [[TMP2:%.*]] = select i1 [[TMP1]], i32 [[X]], i32 255
+; CHECK-NEXT:    [[RES:%.*]] = add nsw i32 [[TMP2]], 1
+; CHECK-NEXT:    ret i32 [[RES]]
+;
+  %1 = xor i32 %x, -1
+  %2 = icmp sgt i32 %1, -256
+  %3 = select i1 %2, i32 %1, i32 -256
+  %res = sub i32 0, %3
+  ret i32 %res
+}
+
+define i32 @test65(i32 %x) {
+; CHECK-LABEL: @test65(
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp sgt i32 [[X:%.*]], -256
+; CHECK-NEXT:    [[TMP2:%.*]] = select i1 [[TMP1]], i32 [[X]], i32 -256
+; CHECK-NEXT:    [[RES:%.*]] = add i32 [[TMP2]], 1
+; CHECK-NEXT:    ret i32 [[RES]]
+;
+  %1 = xor i32 %x, -1
+  %2 = icmp slt i32 %1, 255
+  %3 = select i1 %2, i32 %1, i32 255
+  %res = sub i32 0, %3
+  ret i32 %res
+}
+
+define i32 @test66(i32 %x) {
+; CHECK-LABEL: @test66(
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp ult i32 [[X:%.*]], -101
+; CHECK-NEXT:    [[TMP2:%.*]] = select i1 [[TMP1]], i32 [[X]], i32 -101
+; CHECK-NEXT:    [[RES:%.*]] = add nuw i32 [[TMP2]], 1
+; CHECK-NEXT:    ret i32 [[RES]]
+;
+  %1 = xor i32 %x, -1
+  %2 = icmp ugt i32 %1, 100
+  %3 = select i1 %2, i32 %1, i32 100
+  %res = sub i32 0, %3
+  ret i32 %res
+}
+
+define i32 @test67(i32 %x) {
+; CHECK-LABEL: @test67(
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp ugt i32 [[X:%.*]], 100
+; CHECK-NEXT:    [[TMP2:%.*]] = select i1 [[TMP1]], i32 [[X]], i32 100
+; CHECK-NEXT:    [[RES:%.*]] = add i32 [[TMP2]], 1
+; CHECK-NEXT:    ret i32 [[RES]]
+;
+  %1 = xor i32 %x, -1
+  %2 = icmp ult i32 %1, -101
+  %3 = select i1 %2, i32 %1, i32 -101
+  %res = sub i32 0, %3
+  ret i32 %res
+}
+
+; Check splat vectors too
+define <2 x i32> @test68(<2 x i32> %x) {
+; CHECK-LABEL: @test68(
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp slt <2 x i32> [[X:%.*]], <i32 255, i32 255>
+; CHECK-NEXT:    [[TMP2:%.*]] = select <2 x i1> [[TMP1]], <2 x i32> [[X]], <2 x i32> <i32 255, i32 255>
+; CHECK-NEXT:    [[RES:%.*]] = add nsw <2 x i32> [[TMP2]], <i32 1, i32 1>
+; CHECK-NEXT:    ret <2 x i32> [[RES]]
+;
+  %1 = xor <2 x i32> %x, <i32 -1, i32 -1>
+  %2 = icmp sgt <2 x i32> %1, <i32 -256, i32 -256>
+  %3 = select <2 x i1> %2, <2 x i32> %1, <2 x i32> <i32 -256, i32 -256>
+  %res = sub <2 x i32> zeroinitializer, %3
+  ret <2 x i32> %res
+}
+
+; And non-splat constant vectors.
+define <2 x i32> @test69(<2 x i32> %x) {
+; CHECK-LABEL: @test69(
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp slt <2 x i32> [[X:%.*]], <i32 255, i32 127>
+; CHECK-NEXT:    [[TMP2:%.*]] = select <2 x i1> [[TMP1]], <2 x i32> [[X]], <2 x i32> <i32 255, i32 127>
+; CHECK-NEXT:    [[RES:%.*]] = add <2 x i32> [[TMP2]], <i32 1, i32 1>
+; CHECK-NEXT:    ret <2 x i32> [[RES]]
+;
+  %1 = xor <2 x i32> %x, <i32 -1, i32 -1>
+  %2 = icmp sgt <2 x i32> %1, <i32 -256, i32 -128>
+  %3 = select <2 x i1> %2, <2 x i32> %1, <2 x i32> <i32 -256, i32 -128>
+  %res = sub <2 x i32> zeroinitializer, %3
+  ret <2 x i32> %res
+}
+
+define i32 @nsw_inference1(i32 %x, i32 %y) {
+; CHECK-LABEL: @nsw_inference1(
+; CHECK-NEXT:    [[X2:%.*]] = or i32 [[X:%.*]], 1024
+; CHECK-NEXT:    [[Y2:%.*]] = and i32 [[Y:%.*]], 1
+; CHECK-NEXT:    [[Z:%.*]] = sub nuw nsw i32 [[X2]], [[Y2]]
+; CHECK-NEXT:    ret i32 [[Z]]
+;
+  %x2 = or i32 %x, 1024
+  %y2 = and i32 %y, 1
+  %z = sub i32 %x2, %y2
+  ret i32 %z
+}
+
+define i32 @nsw_inference2(i32 %x, i32 %y) {
+; CHECK-LABEL: @nsw_inference2(
+; CHECK-NEXT:    [[X2:%.*]] = and i32 [[X:%.*]], -1025
+; CHECK-NEXT:    [[Y2:%.*]] = or i32 [[Y:%.*]], -2
+; CHECK-NEXT:    [[Z:%.*]] = sub nsw i32 [[X2]], [[Y2]]
+; CHECK-NEXT:    ret i32 [[Z]]
+;
+  %x2 = and i32 %x, -1025
+  %y2 = or i32 %y, -2
+  %z = sub i32 %x2, %y2
+  ret i32 %z
+}

Added: llvm/trunk/test/Transforms/InstCombine/switch-constant-expr.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/switch-constant-expr.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/switch-constant-expr.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/switch-constant-expr.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,44 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt < %s -instcombine -S | FileCheck %s
+
+ at g = global i32 0
+
+; PR30486
+define i32 @single_case() {
+; CHECK-LABEL: @single_case(
+; CHECK-NEXT:    switch i32 ptrtoint (i32* @g to i32), label %x [
+; CHECK-NEXT:    ]
+; CHECK:       x:
+; CHECK-NEXT:    ret i32 0
+;
+  switch i32 add (i32 ptrtoint (i32* @g to i32), i32 -1), label %x []
+x:
+  ret i32 0
+}
+
+define i32 @multiple_cases() {
+; CHECK-LABEL: @multiple_cases(
+; CHECK-NEXT:    switch i32 ptrtoint (i32* @g to i32), label %x [
+; CHECK-NEXT:    i32 2, label %one
+; CHECK-NEXT:    i32 3, label %two
+; CHECK-NEXT:    ]
+; CHECK:       x:
+; CHECK-NEXT:    ret i32 0
+; CHECK:       one:
+; CHECK-NEXT:    ret i32 1
+; CHECK:       two:
+; CHECK-NEXT:    ret i32 2
+;
+  switch i32 add (i32 ptrtoint (i32* @g to i32), i32 -1), label %x [
+  i32 1, label %one
+  i32 2, label %two
+  ]
+x:
+  ret i32 0
+
+one:
+  ret i32 1
+
+two:
+  ret i32 2
+}

Added: llvm/trunk/test/Transforms/InstCombine/switch-truncate-crash.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/switch-truncate-crash.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/switch-truncate-crash.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/switch-truncate-crash.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,7 @@
+; RUN: opt -instcombine < %s
+
+define void @test() {
+  switch i32 0, label %out [i32 0, label %out]
+out:
+  ret void
+}

Added: llvm/trunk/test/Transforms/InstCombine/tan-nofastmath.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/tan-nofastmath.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/tan-nofastmath.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/tan-nofastmath.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,17 @@
+; RUN: opt < %s -instcombine -S | FileCheck %s
+
+define float @mytan(float %x) {
+entry:
+  %call = call float @atanf(float %x)
+  %call1 = call float @tanf(float %call) 
+  ret float %call1
+}
+
+; CHECK-LABEL: define float @mytan(
+; CHECK:   %call = call float @atanf(float %x)
+; CHECK-NEXT:   %call1 = call float @tanf(float %call)
+; CHECK-NEXT:   ret float %call1
+; CHECK-NEXT: }
+
+declare float @tanf(float)
+declare float @atanf(float)

Added: llvm/trunk/test/Transforms/InstCombine/tan.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/tan.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/tan.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/tan.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,23 @@
+; RUN: opt < %s -instcombine -S | FileCheck %s
+
+define float @mytan(float %x) {
+  %call = call fast float @atanf(float %x)
+  %call1 = call fast float @tanf(float %call)
+  ret float %call1
+}
+
+; CHECK-LABEL: define float @mytan(
+; CHECK:   ret float %x
+
+define float @test2(float ()* %fptr) {
+  %call1 = call fast float %fptr()
+  %tan = call fast float @tanf(float %call1)
+  ret float %tan
+}
+
+; CHECK-LABEL: @test2
+; CHECK: tanf
+
+declare float @tanf(float)
+declare float @atanf(float)
+

Added: llvm/trunk/test/Transforms/InstCombine/tbaa-store-to-load.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/tbaa-store-to-load.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/tbaa-store-to-load.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/tbaa-store-to-load.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,18 @@
+; RUN: opt -S -instcombine < %s 2>&1 | FileCheck %s
+
+define i64 @f(i64* %p1, i64* %p2) {
+top:
+  ; check that the tbaa is preserved
+  ; CHECK-LABEL: @f(
+  ; CHECK: %v1 = load i64, i64* %p1, align 8, !tbaa !0
+  ; CHECK: store i64 %v1, i64* %p2, align 8
+  ; CHECK: ret i64 %v1
+  %v1 = load i64, i64* %p1, align 8, !tbaa !0
+  store i64 %v1, i64* %p2, align 8
+  %v2 = load i64, i64* %p2, align 8
+  ret i64 %v2
+}
+
+!0 = !{!1, !1, i64 0}
+!1 = !{!"scalar type", !2}
+!2 = !{!"load_tbaa"}

Added: llvm/trunk/test/Transforms/InstCombine/toascii-1.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/toascii-1.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/toascii-1.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/toascii-1.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,59 @@
+; Test that the toascii library call simplifier works correctly.
+;
+; RUN: opt < %s -instcombine -S | FileCheck %s
+
+target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:128:128"
+
+declare i32 @toascii(i32)
+
+; Check isascii(c) -> c & 0x7f.
+
+define i32 @test_simplify1() {
+; CHECK-LABEL: @test_simplify1(
+  %ret = call i32 @toascii(i32 0)
+  ret i32 %ret
+; CHECK-NEXT: ret i32 0
+}
+
+define i32 @test_simplify2() {
+; CHECK-LABEL: @test_simplify2(
+  %ret = call i32 @toascii(i32 1)
+  ret i32 %ret
+; CHECK-NEXT: ret i32 1
+}
+
+define i32 @test_simplify3() {
+; CHECK-LABEL: @test_simplify3(
+  %ret = call i32 @toascii(i32 127)
+  ret i32 %ret
+; CHECK-NEXT: ret i32 127
+}
+
+define i32 @test_simplify4() {
+; CHECK-LABEL: @test_simplify4(
+  %ret = call i32 @toascii(i32 128)
+  ret i32 %ret
+; CHECK-NEXT: ret i32 0
+}
+
+define i32 @test_simplify5() {
+; CHECK-LABEL: @test_simplify5(
+  %ret = call i32 @toascii(i32 255)
+  ret i32 %ret
+; CHECK-NEXT: ret i32 127
+}
+
+define i32 @test_simplify6() {
+; CHECK-LABEL: @test_simplify6(
+  %ret = call i32 @toascii(i32 256)
+  ret i32 %ret
+; CHECK-NEXT: ret i32 0
+}
+
+define i32 @test_simplify7(i32 %x) {
+; CHECK-LABEL: @test_simplify7(
+  %ret = call i32 @toascii(i32 %x)
+; CHECK-NEXT: [[AND:%[a-z0-9]+]] = and i32 %x, 127
+  ret i32 %ret
+; CHECK-NEXT: ret i32 [[AND]]
+}

Added: llvm/trunk/test/Transforms/InstCombine/token.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/token.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/token.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/token.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,106 @@
+; RUN: opt < %s -instcombine -S | FileCheck %s
+target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-pc-windows-msvc18.0.0"
+
+declare i32 @__CxxFrameHandler3(...)
+
+define void @test1() personality i32 (...)* @__CxxFrameHandler3 {
+bb:
+  unreachable
+
+unreachable:
+  %cl = cleanuppad within none []
+  cleanupret from %cl unwind to caller
+}
+
+; CHECK-LABEL: define void @test1(
+; CHECK: unreachable:
+; CHECK:   %cl = cleanuppad within none []
+; CHECK:   cleanupret from %cl unwind to caller
+
+define void @test2(i8 %A, i8 %B) personality i32 (...)* @__CxxFrameHandler3 {
+bb:
+  %X = zext i8 %A to i32
+  invoke void @g(i32 0)
+    to label %cont
+    unwind label %catch
+
+cont:
+  %Y = zext i8 %B to i32
+  invoke void @g(i32 0)
+    to label %unreachable
+    unwind label %catch
+
+catch:
+  %phi = phi i32 [ %X, %bb ], [ %Y, %cont ]
+  %cs = catchswitch within none [label %doit] unwind to caller
+
+doit:
+  %cl = catchpad within %cs []
+  call void @g(i32 %phi)
+  unreachable
+
+unreachable:
+  unreachable
+}
+
+; CHECK-LABEL: define void @test2(
+; CHECK:  %X = zext i8 %A to i32
+; CHECK:  %Y = zext i8 %B to i32
+; CHECK:  %phi = phi i32 [ %X, %bb ], [ %Y, %cont ]
+
+define void @test3(i8 %A, i8 %B) personality i32 (...)* @__CxxFrameHandler3 {
+bb:
+  %X = zext i8 %A to i32
+  invoke void @g(i32 0)
+    to label %cont
+    unwind label %catch
+
+cont:
+  %Y = zext i8 %B to i32
+  invoke void @g(i32 0)
+    to label %cont2
+    unwind label %catch
+
+cont2:
+  invoke void @g(i32 0)
+    to label %unreachable
+    unwind label %catch
+
+catch:
+  %phi = phi i32 [ %X, %bb ], [ %Y, %cont ], [ %Y, %cont2 ]
+  %cs = catchswitch within none [label %doit] unwind to caller
+
+doit:
+  %cl = catchpad within %cs []
+  call void @g(i32 %phi)
+  unreachable
+
+unreachable:
+  unreachable
+}
+
+; CHECK-LABEL: define void @test3(
+; CHECK:  %X = zext i8 %A to i32
+; CHECK:  %Y = zext i8 %B to i32
+; CHECK:  %phi = phi i32 [ %X, %bb ], [ %Y, %cont ], [ %Y, %cont2 ]
+
+declare void @foo()
+declare token @llvm.experimental.gc.statepoint.p0f_isVoidf(i64, i32, void ()*, i32, i32, ...)
+
+define void @test4(i8 addrspace(1)* %obj) gc "statepoint-example" {
+bb:
+  unreachable
+
+unreachable:
+  call token (i64, i32, void ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_isVoidf(i64 0, i32 0, void ()* @foo, i32 0, i32 0, i32 0, i32 5, i32 0, i32 -1, i32 0, i32 0, i32 0)
+  ret void
+}
+
+; CHECK-LABEL: define void @test4(
+; CHECK: unreachable:
+; CHECK:   call token (i64, i32, void ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_isVoidf(i64 0, i32 0, void ()* @foo, i32 0, i32 0, i32 0, i32 5, i32 0, i32 -1, i32 0, i32 0, i32 0)
+; CHECK:   ret void
+
+
+declare void @g(i32)

Added: llvm/trunk/test/Transforms/InstCombine/trunc-binop-ext.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/trunc-binop-ext.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/trunc-binop-ext.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/trunc-binop-ext.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,317 @@
+; RUN: opt < %s -instcombine -S | FileCheck %s
+
+define i16 @narrow_sext_and(i16 %x16, i32 %y32) {
+; CHECK-LABEL: @narrow_sext_and(
+; CHECK-NEXT:    [[TMP1:%.*]] = trunc i32 %y32 to i16
+; CHECK-NEXT:    [[R:%.*]] = and i16 [[TMP1]], %x16
+; CHECK-NEXT:    ret i16 [[R]]
+;
+  %x32 = sext i16 %x16 to i32
+  %b = and i32 %x32, %y32
+  %r = trunc i32 %b to i16
+  ret i16 %r
+}
+
+define i16 @narrow_zext_and(i16 %x16, i32 %y32) {
+; CHECK-LABEL: @narrow_zext_and(
+; CHECK-NEXT:    [[TMP1:%.*]] = trunc i32 %y32 to i16
+; CHECK-NEXT:    [[R:%.*]] = and i16 [[TMP1]], %x16
+; CHECK-NEXT:    ret i16 [[R]]
+;
+  %x32 = zext i16 %x16 to i32
+  %b = and i32 %x32, %y32
+  %r = trunc i32 %b to i16
+  ret i16 %r
+}
+
+define i16 @narrow_sext_or(i16 %x16, i32 %y32) {
+; CHECK-LABEL: @narrow_sext_or(
+; CHECK-NEXT:    [[TMP1:%.*]] = trunc i32 %y32 to i16
+; CHECK-NEXT:    [[R:%.*]] = or i16 [[TMP1]], %x16
+; CHECK-NEXT:    ret i16 [[R]]
+;
+  %x32 = sext i16 %x16 to i32
+  %b = or i32 %x32, %y32
+  %r = trunc i32 %b to i16
+  ret i16 %r
+}
+
+define i16 @narrow_zext_or(i16 %x16, i32 %y32) {
+; CHECK-LABEL: @narrow_zext_or(
+; CHECK-NEXT:    [[TMP1:%.*]] = trunc i32 %y32 to i16
+; CHECK-NEXT:    [[R:%.*]] = or i16 [[TMP1]], %x16
+; CHECK-NEXT:    ret i16 [[R]]
+;
+  %x32 = zext i16 %x16 to i32
+  %b = or i32 %x32, %y32
+  %r = trunc i32 %b to i16
+  ret i16 %r
+}
+
+define i16 @narrow_sext_xor(i16 %x16, i32 %y32) {
+; CHECK-LABEL: @narrow_sext_xor(
+; CHECK-NEXT:    [[TMP1:%.*]] = trunc i32 %y32 to i16
+; CHECK-NEXT:    [[R:%.*]] = xor i16 [[TMP1]], %x16
+; CHECK-NEXT:    ret i16 [[R]]
+;
+  %x32 = sext i16 %x16 to i32
+  %b = xor i32 %x32, %y32
+  %r = trunc i32 %b to i16
+  ret i16 %r
+}
+
+define i16 @narrow_zext_xor(i16 %x16, i32 %y32) {
+; CHECK-LABEL: @narrow_zext_xor(
+; CHECK-NEXT:    [[TMP1:%.*]] = trunc i32 %y32 to i16
+; CHECK-NEXT:    [[R:%.*]] = xor i16 [[TMP1]], %x16
+; CHECK-NEXT:    ret i16 [[R]]
+;
+  %x32 = zext i16 %x16 to i32
+  %b = xor i32 %x32, %y32
+  %r = trunc i32 %b to i16
+  ret i16 %r
+}
+
+define i16 @narrow_sext_add(i16 %x16, i32 %y32) {
+; CHECK-LABEL: @narrow_sext_add(
+; CHECK-NEXT:    [[TMP1:%.*]] = trunc i32 %y32 to i16
+; CHECK-NEXT:    [[R:%.*]] = add i16 [[TMP1]], %x16
+; CHECK-NEXT:    ret i16 [[R]]
+;
+  %x32 = sext i16 %x16 to i32
+  %b = add i32 %x32, %y32
+  %r = trunc i32 %b to i16
+  ret i16 %r
+}
+
+define i16 @narrow_zext_add(i16 %x16, i32 %y32) {
+; CHECK-LABEL: @narrow_zext_add(
+; CHECK-NEXT:    [[TMP1:%.*]] = trunc i32 %y32 to i16
+; CHECK-NEXT:    [[R:%.*]] = add i16 [[TMP1]], %x16
+; CHECK-NEXT:    ret i16 [[R]]
+;
+  %x32 = zext i16 %x16 to i32
+  %b = add i32 %x32, %y32
+  %r = trunc i32 %b to i16
+  ret i16 %r
+}
+
+define i16 @narrow_sext_sub(i16 %x16, i32 %y32) {
+; CHECK-LABEL: @narrow_sext_sub(
+; CHECK-NEXT:    [[TMP1:%.*]] = trunc i32 %y32 to i16
+; CHECK-NEXT:    [[R:%.*]] = sub i16 %x16, [[TMP1]]
+; CHECK-NEXT:    ret i16 [[R]]
+;
+  %x32 = sext i16 %x16 to i32
+  %b = sub i32 %x32, %y32
+  %r = trunc i32 %b to i16
+  ret i16 %r
+}
+
+define i16 @narrow_zext_sub(i16 %x16, i32 %y32) {
+; CHECK-LABEL: @narrow_zext_sub(
+; CHECK-NEXT:    [[TMP1:%.*]] = trunc i32 %y32 to i16
+; CHECK-NEXT:    [[R:%.*]] = sub i16 %x16, [[TMP1]]
+; CHECK-NEXT:    ret i16 [[R]]
+;
+  %x32 = zext i16 %x16 to i32
+  %b = sub i32 %x32, %y32
+  %r = trunc i32 %b to i16
+  ret i16 %r
+}
+
+define i16 @narrow_sext_mul(i16 %x16, i32 %y32) {
+; CHECK-LABEL: @narrow_sext_mul(
+; CHECK-NEXT:    [[TMP1:%.*]] = trunc i32 %y32 to i16
+; CHECK-NEXT:    [[R:%.*]] = mul i16 [[TMP1]], %x16
+; CHECK-NEXT:    ret i16 [[R]]
+;
+  %x32 = sext i16 %x16 to i32
+  %b = mul i32 %x32, %y32
+  %r = trunc i32 %b to i16
+  ret i16 %r
+}
+
+define i16 @narrow_zext_mul(i16 %x16, i32 %y32) {
+; CHECK-LABEL: @narrow_zext_mul(
+; CHECK-NEXT:    [[TMP1:%.*]] = trunc i32 %y32 to i16
+; CHECK-NEXT:    [[R:%.*]] = mul i16 [[TMP1]], %x16
+; CHECK-NEXT:    ret i16 [[R]]
+;
+  %x32 = zext i16 %x16 to i32
+  %b = mul i32 %x32, %y32
+  %r = trunc i32 %b to i16
+  ret i16 %r
+}
+
+; Verify that the commuted patterns work. The div is to ensure that complexity-based
+; canonicalization doesn't swap the binop operands. Use vector types to show those work too.
+
+define <2 x i16> @narrow_sext_and_commute(<2 x i16> %x16, <2 x i32> %y32) {
+; CHECK-LABEL: @narrow_sext_and_commute(
+; CHECK-NEXT:    [[Y32OP0:%.*]] = sdiv <2 x i32> %y32, <i32 7, i32 -17>
+; CHECK-NEXT:    [[TMP1:%.*]] = trunc <2 x i32> [[Y32OP0]] to <2 x i16>
+; CHECK-NEXT:    [[R:%.*]] = and <2 x i16> [[TMP1]], %x16
+; CHECK-NEXT:    ret <2 x i16> [[R]]
+;
+  %y32op0 = sdiv <2 x i32> %y32, <i32 7, i32 -17>
+  %x32 = sext <2 x i16> %x16 to <2 x i32>
+  %b = and <2 x i32> %y32op0, %x32
+  %r = trunc <2 x i32> %b to <2 x i16>
+  ret <2 x i16> %r
+}
+
+define <2 x i16> @narrow_zext_and_commute(<2 x i16> %x16, <2 x i32> %y32) {
+; CHECK-LABEL: @narrow_zext_and_commute(
+; CHECK-NEXT:    [[Y32OP0:%.*]] = sdiv <2 x i32> %y32, <i32 7, i32 -17>
+; CHECK-NEXT:    [[TMP1:%.*]] = trunc <2 x i32> [[Y32OP0]] to <2 x i16>
+; CHECK-NEXT:    [[R:%.*]] = and <2 x i16> [[TMP1]], %x16
+; CHECK-NEXT:    ret <2 x i16> [[R]]
+;
+  %y32op0 = sdiv <2 x i32> %y32, <i32 7, i32 -17>
+  %x32 = zext <2 x i16> %x16 to <2 x i32>
+  %b = and <2 x i32> %y32op0, %x32
+  %r = trunc <2 x i32> %b to <2 x i16>
+  ret <2 x i16> %r
+}
+
+define <2 x i16> @narrow_sext_or_commute(<2 x i16> %x16, <2 x i32> %y32) {
+; CHECK-LABEL: @narrow_sext_or_commute(
+; CHECK-NEXT:    [[Y32OP0:%.*]] = sdiv <2 x i32> %y32, <i32 7, i32 -17>
+; CHECK-NEXT:    [[TMP1:%.*]] = trunc <2 x i32> [[Y32OP0]] to <2 x i16>
+; CHECK-NEXT:    [[R:%.*]] = or <2 x i16> [[TMP1]], %x16
+; CHECK-NEXT:    ret <2 x i16> [[R]]
+;
+  %y32op0 = sdiv <2 x i32> %y32, <i32 7, i32 -17>
+  %x32 = sext <2 x i16> %x16 to <2 x i32>
+  %b = or <2 x i32> %y32op0, %x32
+  %r = trunc <2 x i32> %b to <2 x i16>
+  ret <2 x i16> %r
+}
+
+define <2 x i16> @narrow_zext_or_commute(<2 x i16> %x16, <2 x i32> %y32) {
+; CHECK-LABEL: @narrow_zext_or_commute(
+; CHECK-NEXT:    [[Y32OP0:%.*]] = sdiv <2 x i32> %y32, <i32 7, i32 -17>
+; CHECK-NEXT:    [[TMP1:%.*]] = trunc <2 x i32> [[Y32OP0]] to <2 x i16>
+; CHECK-NEXT:    [[R:%.*]] = or <2 x i16> [[TMP1]], %x16
+; CHECK-NEXT:    ret <2 x i16> [[R]]
+;
+  %y32op0 = sdiv <2 x i32> %y32, <i32 7, i32 -17>
+  %x32 = zext <2 x i16> %x16 to <2 x i32>
+  %b = or <2 x i32> %y32op0, %x32
+  %r = trunc <2 x i32> %b to <2 x i16>
+  ret <2 x i16> %r
+}
+
+define <2 x i16> @narrow_sext_xor_commute(<2 x i16> %x16, <2 x i32> %y32) {
+; CHECK-LABEL: @narrow_sext_xor_commute(
+; CHECK-NEXT:    [[Y32OP0:%.*]] = sdiv <2 x i32> %y32, <i32 7, i32 -17>
+; CHECK-NEXT:    [[TMP1:%.*]] = trunc <2 x i32> [[Y32OP0]] to <2 x i16>
+; CHECK-NEXT:    [[R:%.*]] = xor <2 x i16> [[TMP1]], %x16
+; CHECK-NEXT:    ret <2 x i16> [[R]]
+;
+  %y32op0 = sdiv <2 x i32> %y32, <i32 7, i32 -17>
+  %x32 = sext <2 x i16> %x16 to <2 x i32>
+  %b = xor <2 x i32> %y32op0, %x32
+  %r = trunc <2 x i32> %b to <2 x i16>
+  ret <2 x i16> %r
+}
+
+define <2 x i16> @narrow_zext_xor_commute(<2 x i16> %x16, <2 x i32> %y32) {
+; CHECK-LABEL: @narrow_zext_xor_commute(
+; CHECK-NEXT:    [[Y32OP0:%.*]] = sdiv <2 x i32> %y32, <i32 7, i32 -17>
+; CHECK-NEXT:    [[TMP1:%.*]] = trunc <2 x i32> [[Y32OP0]] to <2 x i16>
+; CHECK-NEXT:    [[R:%.*]] = xor <2 x i16> [[TMP1]], %x16
+; CHECK-NEXT:    ret <2 x i16> [[R]]
+;
+  %y32op0 = sdiv <2 x i32> %y32, <i32 7, i32 -17>
+  %x32 = zext <2 x i16> %x16 to <2 x i32>
+  %b = xor <2 x i32> %y32op0, %x32
+  %r = trunc <2 x i32> %b to <2 x i16>
+  ret <2 x i16> %r
+}
+
+define <2 x i16> @narrow_sext_add_commute(<2 x i16> %x16, <2 x i32> %y32) {
+; CHECK-LABEL: @narrow_sext_add_commute(
+; CHECK-NEXT:    [[Y32OP0:%.*]] = sdiv <2 x i32> %y32, <i32 7, i32 -17>
+; CHECK-NEXT:    [[TMP1:%.*]] = trunc <2 x i32> [[Y32OP0]] to <2 x i16>
+; CHECK-NEXT:    [[R:%.*]] = add <2 x i16> [[TMP1]], %x16
+; CHECK-NEXT:    ret <2 x i16> [[R]]
+;
+  %y32op0 = sdiv <2 x i32> %y32, <i32 7, i32 -17>
+  %x32 = sext <2 x i16> %x16 to <2 x i32>
+  %b = add <2 x i32> %y32op0, %x32
+  %r = trunc <2 x i32> %b to <2 x i16>
+  ret <2 x i16> %r
+}
+
+define <2 x i16> @narrow_zext_add_commute(<2 x i16> %x16, <2 x i32> %y32) {
+; CHECK-LABEL: @narrow_zext_add_commute(
+; CHECK-NEXT:    [[Y32OP0:%.*]] = sdiv <2 x i32> %y32, <i32 7, i32 -17>
+; CHECK-NEXT:    [[TMP1:%.*]] = trunc <2 x i32> [[Y32OP0]] to <2 x i16>
+; CHECK-NEXT:    [[R:%.*]] = add <2 x i16> [[TMP1]], %x16
+; CHECK-NEXT:    ret <2 x i16> [[R]]
+;
+  %y32op0 = sdiv <2 x i32> %y32, <i32 7, i32 -17>
+  %x32 = zext <2 x i16> %x16 to <2 x i32>
+  %b = add <2 x i32> %y32op0, %x32
+  %r = trunc <2 x i32> %b to <2 x i16>
+  ret <2 x i16> %r
+}
+
+define <2 x i16> @narrow_sext_sub_commute(<2 x i16> %x16, <2 x i32> %y32) {
+; CHECK-LABEL: @narrow_sext_sub_commute(
+; CHECK-NEXT:    [[Y32OP0:%.*]] = sdiv <2 x i32> %y32, <i32 7, i32 -17>
+; CHECK-NEXT:    [[TMP1:%.*]] = trunc <2 x i32> [[Y32OP0]] to <2 x i16>
+; CHECK-NEXT:    [[R:%.*]] = sub <2 x i16> [[TMP1]], %x16
+; CHECK-NEXT:    ret <2 x i16> [[R]]
+;
+  %y32op0 = sdiv <2 x i32> %y32, <i32 7, i32 -17>
+  %x32 = sext <2 x i16> %x16 to <2 x i32>
+  %b = sub <2 x i32> %y32op0, %x32
+  %r = trunc <2 x i32> %b to <2 x i16>
+  ret <2 x i16> %r
+}
+
+define <2 x i16> @narrow_zext_sub_commute(<2 x i16> %x16, <2 x i32> %y32) {
+; CHECK-LABEL: @narrow_zext_sub_commute(
+; CHECK-NEXT:    [[Y32OP0:%.*]] = sdiv <2 x i32> %y32, <i32 7, i32 -17>
+; CHECK-NEXT:    [[TMP1:%.*]] = trunc <2 x i32> [[Y32OP0]] to <2 x i16>
+; CHECK-NEXT:    [[R:%.*]] = sub <2 x i16> [[TMP1]], %x16
+; CHECK-NEXT:    ret <2 x i16> [[R]]
+;
+  %y32op0 = sdiv <2 x i32> %y32, <i32 7, i32 -17>
+  %x32 = zext <2 x i16> %x16 to <2 x i32>
+  %b = sub <2 x i32> %y32op0, %x32
+  %r = trunc <2 x i32> %b to <2 x i16>
+  ret <2 x i16> %r
+}
+
+define <2 x i16> @narrow_sext_mul_commute(<2 x i16> %x16, <2 x i32> %y32) {
+; CHECK-LABEL: @narrow_sext_mul_commute(
+; CHECK-NEXT:    [[Y32OP0:%.*]] = sdiv <2 x i32> %y32, <i32 7, i32 -17>
+; CHECK-NEXT:    [[TMP1:%.*]] = trunc <2 x i32> [[Y32OP0]] to <2 x i16>
+; CHECK-NEXT:    [[R:%.*]] = mul <2 x i16> [[TMP1]], %x16
+; CHECK-NEXT:    ret <2 x i16> [[R]]
+;
+  %y32op0 = sdiv <2 x i32> %y32, <i32 7, i32 -17>
+  %x32 = sext <2 x i16> %x16 to <2 x i32>
+  %b = mul <2 x i32> %y32op0, %x32
+  %r = trunc <2 x i32> %b to <2 x i16>
+  ret <2 x i16> %r
+}
+
+define <2 x i16> @narrow_zext_mul_commute(<2 x i16> %x16, <2 x i32> %y32) {
+; CHECK-LABEL: @narrow_zext_mul_commute(
+; CHECK-NEXT:    [[Y32OP0:%.*]] = sdiv <2 x i32> %y32, <i32 7, i32 -17>
+; CHECK-NEXT:    [[TMP1:%.*]] = trunc <2 x i32> [[Y32OP0]] to <2 x i16>
+; CHECK-NEXT:    [[R:%.*]] = mul <2 x i16> [[TMP1]], %x16
+; CHECK-NEXT:    ret <2 x i16> [[R]]
+;
+  %y32op0 = sdiv <2 x i32> %y32, <i32 7, i32 -17>
+  %x32 = zext <2 x i16> %x16 to <2 x i32>
+  %b = mul <2 x i32> %y32op0, %x32
+  %r = trunc <2 x i32> %b to <2 x i16>
+  ret <2 x i16> %r
+}
+

Added: llvm/trunk/test/Transforms/InstCombine/trunc.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/trunc.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/trunc.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/trunc.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,626 @@
+; 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"
+
+; Instcombine should be able to eliminate all of these ext casts.
+
+declare void @use(i32)
+
+define i64 @test1(i64 %a) {
+; CHECK-LABEL: @test1(
+; CHECK-NEXT:    [[B:%.*]] = trunc i64 %a to i32
+; CHECK-NEXT:    [[C:%.*]] = and i64 %a, 15
+; CHECK-NEXT:    call void @use(i32 [[B]])
+; CHECK-NEXT:    ret i64 [[C]]
+;
+  %b = trunc i64 %a to i32
+  %c = and i32 %b, 15
+  %d = zext i32 %c to i64
+  call void @use(i32 %b)
+  ret i64 %d
+}
+
+define i64 @test2(i64 %a) {
+; CHECK-LABEL: @test2(
+; CHECK-NEXT:    [[B:%.*]] = trunc i64 %a to i32
+; CHECK-NEXT:    [[D1:%.*]] = shl i64 %a, 36
+; CHECK-NEXT:    [[D:%.*]] = ashr exact i64 [[D1]], 36
+; CHECK-NEXT:    call void @use(i32 [[B]])
+; CHECK-NEXT:    ret i64 [[D]]
+;
+  %b = trunc i64 %a to i32
+  %c = shl i32 %b, 4
+  %q = ashr i32 %c, 4
+  %d = sext i32 %q to i64
+  call void @use(i32 %b)
+  ret i64 %d
+}
+
+define i64 @test3(i64 %a) {
+; CHECK-LABEL: @test3(
+; CHECK-NEXT:    [[B:%.*]] = trunc i64 %a to i32
+; CHECK-NEXT:    [[C:%.*]] = and i64 %a, 8
+; CHECK-NEXT:    call void @use(i32 [[B]])
+; CHECK-NEXT:    ret i64 [[C]]
+;
+  %b = trunc i64 %a to i32
+  %c = and i32 %b, 8
+  %d = zext i32 %c to i64
+  call void @use(i32 %b)
+  ret i64 %d
+}
+
+define i64 @test4(i64 %a) {
+; CHECK-LABEL: @test4(
+; CHECK-NEXT:    [[B:%.*]] = trunc i64 %a to i32
+; CHECK-NEXT:    [[C:%.*]] = and i64 %a, 8
+; CHECK-NEXT:    [[X:%.*]] = xor i64 [[C]], 8
+; CHECK-NEXT:    call void @use(i32 [[B]])
+; CHECK-NEXT:    ret i64 [[X]]
+;
+  %b = trunc i64 %a to i32
+  %c = and i32 %b, 8
+  %x = xor i32 %c, 8
+  %d = zext i32 %x to i64
+  call void @use(i32 %b)
+  ret i64 %d
+}
+
+define i32 @test5(i32 %A) {
+; CHECK-LABEL: @test5(
+; CHECK-NEXT:    [[C:%.*]] = lshr i32 %A, 16
+; CHECK-NEXT:    ret i32 [[C]]
+;
+  %B = zext i32 %A to i128
+  %C = lshr i128 %B, 16
+  %D = trunc i128 %C to i32
+  ret i32 %D
+}
+
+define i32 @test6(i64 %A) {
+; CHECK-LABEL: @test6(
+; CHECK-NEXT:    [[C:%.*]] = lshr i64 %A, 32
+; CHECK-NEXT:    [[D:%.*]] = trunc i64 [[C]] to i32
+; CHECK-NEXT:    ret i32 [[D]]
+;
+  %B = zext i64 %A to i128
+  %C = lshr i128 %B, 32
+  %D = trunc i128 %C to i32
+  ret i32 %D
+}
+
+; Test case where 'ashr' demanded bits does not contain any of the high bits,
+; but does contain sign bits, where the sign bit is not known to be zero.
+define i16 @ashr_mul_sign_bits(i8 %X, i8 %Y) {
+; CHECK-LABEL: @ashr_mul_sign_bits(
+; CHECK-NEXT:    [[A:%.*]] = sext i8 %X to i16
+; CHECK-NEXT:    [[B:%.*]] = sext i8 %Y to i16
+; CHECK-NEXT:    [[C:%.*]] = mul nsw i16 [[A]], [[B]]
+; CHECK-NEXT:    [[D:%.*]] = ashr i16 [[C]], 3
+; CHECK-NEXT:    ret i16 [[D]]
+  %A = sext i8 %X to i32
+  %B = sext i8 %Y to i32
+  %C = mul i32 %A, %B
+  %D = ashr i32 %C, 3
+  %E = trunc i32 %D to i16
+  ret i16 %E
+}
+
+define i16 @ashr_mul(i8 %X, i8 %Y) {
+; CHECK-LABEL: @ashr_mul(
+; CHECK-NEXT:    [[A:%.*]] = sext i8 %X to i16
+; CHECK-NEXT:    [[B:%.*]] = sext i8 %Y to i16
+; CHECK-NEXT:    [[C:%.*]] = mul nsw i16 [[A]], [[B]]
+; CHECK-NEXT:    [[D:%.*]] = ashr i16 [[C]], 8
+; CHECK-NEXT:    ret i16 [[D]]
+  %A = sext i8 %X to i20
+  %B = sext i8 %Y to i20
+  %C = mul i20 %A, %B
+  %D = ashr i20 %C, 8
+  %E = trunc i20 %D to i16
+  ret i16 %E
+}
+
+define i32 @trunc_ashr(i32 %X) {
+; CHECK-LABEL: @trunc_ashr(
+; CHECK-NEXT:    [[B:%.*]] = or i32 [[X:%.*]], -2147483648
+; CHECK-NEXT:    [[C:%.*]] = ashr i32 [[B]], 8
+; CHECK-NEXT:    ret i32 [[C]]
+;
+  %A = zext i32 %X to i36
+  %B = or i36 %A, -2147483648 ; 0xF80000000
+  %C = ashr i36 %B, 8
+  %T = trunc i36 %C to i32
+  ret i32  %T
+}
+
+define <2 x i32> @trunc_ashr_vec(<2 x i32> %X) {
+; CHECK-LABEL: @trunc_ashr_vec(
+; CHECK-NEXT:    [[B:%.*]] = or <2 x i32> [[X:%.*]], <i32 -2147483648, i32 -2147483648>
+; CHECK-NEXT:    [[C:%.*]] = ashr <2 x i32> [[B]], <i32 8, i32 8>
+; CHECK-NEXT:    ret <2 x i32> [[C]]
+;
+  %A = zext <2 x i32> %X to <2 x i36>
+  %B = or <2 x i36> %A, <i36 -2147483648, i36 -2147483648> ; 0xF80000000
+  %C = ashr <2 x i36> %B, <i36 8, i36 8>
+  %T = trunc <2 x i36> %C to <2 x i32>
+  ret <2 x i32>  %T
+}
+
+define i92 @test7(i64 %A) {
+; CHECK-LABEL: @test7(
+; CHECK-NEXT:    [[TMP1:%.*]] = lshr i64 %A, 32
+; CHECK-NEXT:    [[D:%.*]] = zext i64 [[TMP1]] to i92
+; CHECK-NEXT:    ret i92 [[D]]
+;
+  %B = zext i64 %A to i128
+  %C = lshr i128 %B, 32
+  %D = trunc i128 %C to i92
+  ret i92 %D
+}
+
+define i64 @test8(i32 %A, i32 %B) {
+; CHECK-LABEL: @test8(
+; CHECK-NEXT:    [[TMP38:%.*]] = zext i32 %A to i64
+; CHECK-NEXT:    [[TMP32:%.*]] = zext i32 %B to i64
+; CHECK-NEXT:    [[TMP33:%.*]] = shl nuw i64 [[TMP32]], 32
+; CHECK-NEXT:    [[INS35:%.*]] = or i64 [[TMP33]], [[TMP38]]
+; CHECK-NEXT:    ret i64 [[INS35]]
+;
+  %tmp38 = zext i32 %A to i128
+  %tmp32 = zext i32 %B to i128
+  %tmp33 = shl i128 %tmp32, 32
+  %ins35 = or i128 %tmp33, %tmp38
+  %tmp42 = trunc i128 %ins35 to i64
+  ret i64 %tmp42
+}
+
+define i8 @test9(i32 %X) {
+; CHECK-LABEL: @test9(
+; CHECK-NEXT:    [[TMP1:%.*]] = trunc i32 %X to i8
+; CHECK-NEXT:    [[Z:%.*]] = and i8 [[TMP1]], 42
+; CHECK-NEXT:    ret i8 [[Z]]
+;
+  %Y = and i32 %X, 42
+  %Z = trunc i32 %Y to i8
+  ret i8 %Z
+}
+
+; rdar://8808586
+define i8 @test10(i32 %X) {
+; CHECK-LABEL: @test10(
+; CHECK-NEXT:    [[Y:%.*]] = trunc i32 %X to i8
+; CHECK-NEXT:    [[Z:%.*]] = and i8 [[Y]], 42
+; CHECK-NEXT:    ret i8 [[Z]]
+;
+  %Y = trunc i32 %X to i8
+  %Z = and i8 %Y, 42
+  ret i8 %Z
+}
+
+; PR25543
+; https://llvm.org/bugs/show_bug.cgi?id=25543
+; This is an extractelement.
+
+define i32 @trunc_bitcast1(<4 x i32> %v) {
+; CHECK-LABEL: @trunc_bitcast1(
+; CHECK-NEXT:    [[EXT:%.*]] = extractelement <4 x i32> %v, i32 1
+; CHECK-NEXT:    ret i32 [[EXT]]
+;
+  %bc = bitcast <4 x i32> %v to i128
+  %shr = lshr i128 %bc, 32
+  %ext = trunc i128 %shr to i32
+  ret i32 %ext
+}
+
+; A bitcast may still be required.
+
+define i32 @trunc_bitcast2(<2 x i64> %v) {
+; CHECK-LABEL: @trunc_bitcast2(
+; CHECK-NEXT:    [[BC1:%.*]] = bitcast <2 x i64> %v to <4 x i32>
+; CHECK-NEXT:    [[EXT:%.*]] = extractelement <4 x i32> [[BC1]], i32 2
+; CHECK-NEXT:    ret i32 [[EXT]]
+;
+  %bc = bitcast <2 x i64> %v to i128
+  %shr = lshr i128 %bc, 64
+  %ext = trunc i128 %shr to i32
+  ret i32 %ext
+}
+
+; The right shift is optional.
+
+define i32 @trunc_bitcast3(<4 x i32> %v) {
+; CHECK-LABEL: @trunc_bitcast3(
+; CHECK-NEXT:    [[EXT:%.*]] = extractelement <4 x i32> %v, i32 0
+; CHECK-NEXT:    ret i32 [[EXT]]
+;
+  %bc = bitcast <4 x i32> %v to i128
+  %ext = trunc i128 %bc to i32
+  ret i32 %ext
+}
+
+define i32 @trunc_shl_31_i32_i64(i64 %val) {
+; CHECK-LABEL: @trunc_shl_31_i32_i64(
+; CHECK-NEXT:    [[VAL_TR:%.*]] = trunc i64 %val to i32
+; CHECK-NEXT:    [[TRUNC:%.*]] = shl i32 [[VAL_TR]], 31
+; CHECK-NEXT:    ret i32 [[TRUNC]]
+;
+  %shl = shl i64 %val, 31
+  %trunc = trunc i64 %shl to i32
+  ret i32 %trunc
+}
+
+define i32 @trunc_shl_nsw_31_i32_i64(i64 %val) {
+; CHECK-LABEL: @trunc_shl_nsw_31_i32_i64(
+; CHECK-NEXT:    [[VAL_TR:%.*]] = trunc i64 %val to i32
+; CHECK-NEXT:    [[TRUNC:%.*]] = shl i32 [[VAL_TR]], 31
+; CHECK-NEXT:    ret i32 [[TRUNC]]
+;
+  %shl = shl nsw i64 %val, 31
+  %trunc = trunc i64 %shl to i32
+  ret i32 %trunc
+}
+
+define i32 @trunc_shl_nuw_31_i32_i64(i64 %val) {
+; CHECK-LABEL: @trunc_shl_nuw_31_i32_i64(
+; CHECK-NEXT:    [[VAL_TR:%.*]] = trunc i64 %val to i32
+; CHECK-NEXT:    [[TRUNC:%.*]] = shl i32 [[VAL_TR]], 31
+; CHECK-NEXT:    ret i32 [[TRUNC]]
+;
+  %shl = shl nuw i64 %val, 31
+  %trunc = trunc i64 %shl to i32
+  ret i32 %trunc
+}
+
+define i32 @trunc_shl_nsw_nuw_31_i32_i64(i64 %val) {
+; CHECK-LABEL: @trunc_shl_nsw_nuw_31_i32_i64(
+; CHECK-NEXT:    [[VAL_TR:%.*]] = trunc i64 %val to i32
+; CHECK-NEXT:    [[TRUNC:%.*]] = shl i32 [[VAL_TR]], 31
+; CHECK-NEXT:    ret i32 [[TRUNC]]
+;
+  %shl = shl nsw nuw i64 %val, 31
+  %trunc = trunc i64 %shl to i32
+  ret i32 %trunc
+}
+
+define i16 @trunc_shl_15_i16_i64(i64 %val) {
+; CHECK-LABEL: @trunc_shl_15_i16_i64(
+; CHECK-NEXT:    [[VAL_TR:%.*]] = trunc i64 %val to i16
+; CHECK-NEXT:    [[TRUNC:%.*]] = shl i16 [[VAL_TR]], 15
+; CHECK-NEXT:    ret i16 [[TRUNC]]
+;
+  %shl = shl i64 %val, 15
+  %trunc = trunc i64 %shl to i16
+  ret i16 %trunc
+}
+
+define i16 @trunc_shl_15_i16_i32(i32 %val) {
+; CHECK-LABEL: @trunc_shl_15_i16_i32(
+; CHECK-NEXT:    [[VAL_TR:%.*]] = trunc i32 %val to i16
+; CHECK-NEXT:    [[TRUNC:%.*]] = shl i16 [[VAL_TR]], 15
+; CHECK-NEXT:    ret i16 [[TRUNC]]
+;
+  %shl = shl i32 %val, 15
+  %trunc = trunc i32 %shl to i16
+  ret i16 %trunc
+}
+
+define i8 @trunc_shl_7_i8_i64(i64 %val) {
+; CHECK-LABEL: @trunc_shl_7_i8_i64(
+; CHECK-NEXT:    [[VAL_TR:%.*]] = trunc i64 %val to i8
+; CHECK-NEXT:    [[TRUNC:%.*]] = shl i8 [[VAL_TR]], 7
+; CHECK-NEXT:    ret i8 [[TRUNC]]
+;
+  %shl = shl i64 %val, 7
+  %trunc = trunc i64 %shl to i8
+  ret i8 %trunc
+}
+
+define i2 @trunc_shl_1_i2_i64(i64 %val) {
+; CHECK-LABEL: @trunc_shl_1_i2_i64(
+; CHECK-NEXT:    [[SHL:%.*]] = shl i64 %val, 1
+; CHECK-NEXT:    [[TRUNC:%.*]] = trunc i64 [[SHL]] to i2
+; CHECK-NEXT:    ret i2 [[TRUNC]]
+;
+  %shl = shl i64 %val, 1
+  %trunc = trunc i64 %shl to i2
+  ret i2 %trunc
+}
+
+define i32 @trunc_shl_1_i32_i64(i64 %val) {
+; CHECK-LABEL: @trunc_shl_1_i32_i64(
+; CHECK-NEXT:    [[VAL_TR:%.*]] = trunc i64 %val to i32
+; CHECK-NEXT:    [[TRUNC:%.*]] = shl i32 [[VAL_TR]], 1
+; CHECK-NEXT:    ret i32 [[TRUNC]]
+;
+  %shl = shl i64 %val, 1
+  %trunc = trunc i64 %shl to i32
+  ret i32 %trunc
+}
+
+define i32 @trunc_shl_16_i32_i64(i64 %val) {
+; CHECK-LABEL: @trunc_shl_16_i32_i64(
+; CHECK-NEXT:    [[VAL_TR:%.*]] = trunc i64 %val to i32
+; CHECK-NEXT:    [[TRUNC:%.*]] = shl i32 [[VAL_TR]], 16
+; CHECK-NEXT:    ret i32 [[TRUNC]]
+;
+  %shl = shl i64 %val, 16
+  %trunc = trunc i64 %shl to i32
+  ret i32 %trunc
+}
+
+define i32 @trunc_shl_33_i32_i64(i64 %val) {
+; CHECK-LABEL: @trunc_shl_33_i32_i64(
+; CHECK-NEXT:    ret i32 0
+;
+  %shl = shl i64 %val, 33
+  %trunc = trunc i64 %shl to i32
+  ret i32 %trunc
+}
+
+define i32 @trunc_shl_32_i32_i64(i64 %val) {
+; CHECK-LABEL: @trunc_shl_32_i32_i64(
+; CHECK-NEXT:    ret i32 0
+;
+  %shl = shl i64 %val, 32
+  %trunc = trunc i64 %shl to i32
+  ret i32 %trunc
+}
+
+; TODO: Should be able to handle vectors
+define <2 x i32> @trunc_shl_16_v2i32_v2i64(<2 x i64> %val) {
+; CHECK-LABEL: @trunc_shl_16_v2i32_v2i64(
+; CHECK-NEXT:    [[SHL:%.*]] = shl <2 x i64> %val, <i64 16, i64 16>
+; CHECK-NEXT:    [[TRUNC:%.*]] = trunc <2 x i64> [[SHL]] to <2 x i32>
+; CHECK-NEXT:    ret <2 x i32> [[TRUNC]]
+;
+  %shl = shl <2 x i64> %val, <i64 16, i64 16>
+  %trunc = trunc <2 x i64> %shl to <2 x i32>
+  ret <2 x i32> %trunc
+}
+
+define <2 x i32> @trunc_shl_nosplat_v2i32_v2i64(<2 x i64> %val) {
+; CHECK-LABEL: @trunc_shl_nosplat_v2i32_v2i64(
+; CHECK-NEXT:    [[SHL:%.*]] = shl <2 x i64> %val, <i64 15, i64 16>
+; CHECK-NEXT:    [[TRUNC:%.*]] = trunc <2 x i64> [[SHL]] to <2 x i32>
+; CHECK-NEXT:    ret <2 x i32> [[TRUNC]]
+;
+  %shl = shl <2 x i64> %val, <i64 15, i64 16>
+  %trunc = trunc <2 x i64> %shl to <2 x i32>
+  ret <2 x i32> %trunc
+}
+
+define void @trunc_shl_31_i32_i64_multi_use(i64 %val, i32 addrspace(1)* %ptr0, i64 addrspace(1)* %ptr1) {
+; CHECK-LABEL: @trunc_shl_31_i32_i64_multi_use(
+; CHECK-NEXT:    [[SHL:%.*]] = shl i64 %val, 31
+; CHECK-NEXT:    [[TRUNC:%.*]] = trunc i64 [[SHL]] to i32
+; CHECK-NEXT:    store volatile i32 [[TRUNC]], i32 addrspace(1)* %ptr0, align 4
+; CHECK-NEXT:    store volatile i64 [[SHL]], i64 addrspace(1)* %ptr1, align 8
+; CHECK-NEXT:    ret void
+;
+  %shl = shl i64 %val, 31
+  %trunc = trunc i64 %shl to i32
+  store volatile i32 %trunc, i32 addrspace(1)* %ptr0
+  store volatile i64 %shl, i64 addrspace(1)* %ptr1
+  ret void
+}
+
+define i32 @trunc_shl_lshr_infloop(i64 %arg) {
+; CHECK-LABEL: @trunc_shl_lshr_infloop(
+; CHECK-NEXT:    [[TMP0:%.*]] = lshr i64 %arg, 1
+; CHECK-NEXT:    [[TMP1:%.*]] = shl i64 [[TMP0]], 2
+; CHECK-NEXT:    [[TMP2:%.*]] = trunc i64 [[TMP1]] to i32
+; CHECK-NEXT:    ret i32 [[TMP2]]
+;
+  %tmp0 = lshr i64 %arg, 1
+  %tmp1 = shl i64 %tmp0, 2
+  %tmp2 = trunc i64 %tmp1 to i32
+  ret i32 %tmp2
+}
+
+define i32 @trunc_shl_ashr_infloop(i64 %arg) {
+; CHECK-LABEL: @trunc_shl_ashr_infloop(
+; CHECK-NEXT:    [[TMP0:%.*]] = ashr i64 %arg, 3
+; CHECK-NEXT:    [[TMP1:%.*]] = shl nsw i64 [[TMP0]], 2
+; CHECK-NEXT:    [[TMP2:%.*]] = trunc i64 [[TMP1]] to i32
+; CHECK-NEXT:    ret i32 [[TMP2]]
+;
+  %tmp0 = ashr i64 %arg, 3
+  %tmp1 = shl i64 %tmp0, 2
+  %tmp2 = trunc i64 %tmp1 to i32
+  ret i32 %tmp2
+}
+
+define i32 @trunc_shl_shl_infloop(i64 %arg) {
+; CHECK-LABEL: @trunc_shl_shl_infloop(
+; CHECK-NEXT:    [[ARG_TR:%.*]] = trunc i64 %arg to i32
+; CHECK-NEXT:    [[TMP2:%.*]] = shl i32 [[ARG_TR]], 3
+; CHECK-NEXT:    ret i32 [[TMP2]]
+;
+  %tmp0 = shl i64 %arg, 1
+  %tmp1 = shl i64 %tmp0, 2
+  %tmp2 = trunc i64 %tmp1 to i32
+  ret i32 %tmp2
+}
+
+define i32 @trunc_shl_lshr_var(i64 %arg, i64 %val) {
+; CHECK-LABEL: @trunc_shl_lshr_var(
+; CHECK-NEXT:    [[TMP0:%.*]] = lshr i64 %arg, %val
+; CHECK-NEXT:    [[TMP0_TR:%.*]] = trunc i64 [[TMP0]] to i32
+; CHECK-NEXT:    [[TMP2:%.*]] = shl i32 [[TMP0_TR]], 2
+; CHECK-NEXT:    ret i32 [[TMP2]]
+;
+  %tmp0 = lshr i64 %arg, %val
+  %tmp1 = shl i64 %tmp0, 2
+  %tmp2 = trunc i64 %tmp1 to i32
+  ret i32 %tmp2
+}
+
+define i32 @trunc_shl_ashr_var(i64 %arg, i64 %val) {
+; CHECK-LABEL: @trunc_shl_ashr_var(
+; CHECK-NEXT:    [[TMP0:%.*]] = ashr i64 %arg, %val
+; CHECK-NEXT:    [[TMP0_TR:%.*]] = trunc i64 [[TMP0]] to i32
+; CHECK-NEXT:    [[TMP2:%.*]] = shl i32 [[TMP0_TR]], 2
+; CHECK-NEXT:    ret i32 [[TMP2]]
+;
+  %tmp0 = ashr i64 %arg, %val
+  %tmp1 = shl i64 %tmp0, 2
+  %tmp2 = trunc i64 %tmp1 to i32
+  ret i32 %tmp2
+}
+
+define i32 @trunc_shl_shl_var(i64 %arg, i64 %val) {
+; CHECK-LABEL: @trunc_shl_shl_var(
+; CHECK-NEXT:    [[TMP0:%.*]] = shl i64 %arg, %val
+; CHECK-NEXT:    [[TMP0_TR:%.*]] = trunc i64 [[TMP0]] to i32
+; CHECK-NEXT:    [[TMP2:%.*]] = shl i32 [[TMP0_TR]], 2
+; CHECK-NEXT:    ret i32 [[TMP2]]
+;
+  %tmp0 = shl i64 %arg, %val
+  %tmp1 = shl i64 %tmp0, 2
+  %tmp2 = trunc i64 %tmp1 to i32
+  ret i32 %tmp2
+}
+
+define <8 x i16> @trunc_shl_v8i15_v8i32_15(<8 x i32> %a) {
+; CHECK-LABEL: @trunc_shl_v8i15_v8i32_15(
+; CHECK-NEXT:    [[SHL:%.*]] = shl <8 x i32> %a, <i32 15, i32 15, i32 15, i32 15, i32 15, i32 15, i32 15, i32 15>
+; CHECK-NEXT:    [[CONV:%.*]] = trunc <8 x i32> [[SHL]] to <8 x i16>
+; CHECK-NEXT:    ret <8 x i16> [[CONV]]
+;
+  %shl = shl <8 x i32> %a, <i32 15, i32 15, i32 15, i32 15, i32 15, i32 15, i32 15, i32 15>
+  %conv = trunc <8 x i32> %shl to <8 x i16>
+  ret <8 x i16> %conv
+}
+
+define <8 x i16> @trunc_shl_v8i16_v8i32_16(<8 x i32> %a) {
+; CHECK-LABEL: @trunc_shl_v8i16_v8i32_16(
+; CHECK-NEXT:    ret <8 x i16> zeroinitializer
+;
+  %shl = shl <8 x i32> %a, <i32 16, i32 16, i32 16, i32 16, i32 16, i32 16, i32 16, i32 16>
+  %conv = trunc <8 x i32> %shl to <8 x i16>
+  ret <8 x i16> %conv
+}
+
+define <8 x i16> @trunc_shl_v8i16_v8i32_17(<8 x i32> %a) {
+; CHECK-LABEL: @trunc_shl_v8i16_v8i32_17(
+; CHECK-NEXT:    ret <8 x i16> zeroinitializer
+;
+  %shl = shl <8 x i32> %a, <i32 17, i32 17, i32 17, i32 17, i32 17, i32 17, i32 17, i32 17>
+  %conv = trunc <8 x i32> %shl to <8 x i16>
+  ret <8 x i16> %conv
+}
+
+define <8 x i16> @trunc_shl_v8i16_v8i32_4(<8 x i32> %a) {
+; CHECK-LABEL: @trunc_shl_v8i16_v8i32_4(
+; CHECK-NEXT:    [[SHL:%.*]] = shl <8 x i32> %a, <i32 4, i32 4, i32 4, i32 4, i32 4, i32 4, i32 4, i32 4>
+; CHECK-NEXT:    [[CONV:%.*]] = trunc <8 x i32> [[SHL]] to <8 x i16>
+; CHECK-NEXT:    ret <8 x i16> [[CONV]]
+;
+  %shl = shl <8 x i32> %a, <i32 4, i32 4, i32 4, i32 4, i32 4, i32 4, i32 4, i32 4>
+  %conv = trunc <8 x i32> %shl to <8 x i16>
+  ret <8 x i16> %conv
+}
+
+; Although the mask is the same value, we don't create a shuffle for types that the backend may not be able to handle:
+; trunc (shuffle X, C, Mask) --> shuffle (trunc X), C', Mask
+
+define <4 x i8> @wide_shuf(<4 x i32> %x) {
+; CHECK-LABEL: @wide_shuf(
+; CHECK-NEXT:    [[SHUF:%.*]] = shufflevector <4 x i32> %x, <4 x i32> <i32 undef, i32 3634, i32 90, i32 undef>, <4 x i32> <i32 1, i32 5, i32 6, i32 2>
+; CHECK-NEXT:    [[TRUNC:%.*]] = trunc <4 x i32> [[SHUF]] to <4 x i8>
+; CHECK-NEXT:    ret <4 x i8> [[TRUNC]]
+;
+  %shuf = shufflevector <4 x i32> %x, <4 x i32> <i32 35, i32 3634, i32 90, i32 -1>, <4 x i32> <i32 1, i32 5, i32 6, i32 2>
+  %trunc = trunc <4 x i32> %shuf to <4 x i8>
+  ret <4 x i8> %trunc
+}
+
+; trunc (shuffle X, undef, SplatMask) --> shuffle (trunc X), undef, SplatMask
+
+define <4 x i8> @wide_splat1(<4 x i32> %x) {
+; CHECK-LABEL: @wide_splat1(
+; CHECK-NEXT:    [[TMP1:%.*]] = trunc <4 x i32> %x to <4 x i8>
+; CHECK-NEXT:    [[TRUNC:%.*]] = shufflevector <4 x i8> [[TMP1]], <4 x i8> undef, <4 x i32> <i32 2, i32 2, i32 2, i32 2>
+; CHECK-NEXT:    ret <4 x i8> [[TRUNC]]
+;
+  %shuf = shufflevector <4 x i32> %x, <4 x i32> undef, <4 x i32> <i32 2, i32 2, i32 2, i32 2>
+  %trunc = trunc <4 x i32> %shuf to <4 x i8>
+  ret <4 x i8> %trunc
+}
+
+; Test weird types.
+; trunc (shuffle X, undef, SplatMask) --> shuffle (trunc X), undef, SplatMask
+
+define <3 x i31> @wide_splat2(<3 x i33> %x) {
+; CHECK-LABEL: @wide_splat2(
+; CHECK-NEXT:    [[TMP1:%.*]] = trunc <3 x i33> %x to <3 x i31>
+; CHECK-NEXT:    [[TRUNC:%.*]] = shufflevector <3 x i31> [[TMP1]], <3 x i31> undef, <3 x i32> <i32 1, i32 1, i32 1>
+; CHECK-NEXT:    ret <3 x i31> [[TRUNC]]
+;
+  %shuf = shufflevector <3 x i33> %x, <3 x i33> undef, <3 x i32> <i32 1, i32 1, i32 1>
+  %trunc = trunc <3 x i33> %shuf to <3 x i31>
+  ret <3 x i31> %trunc
+}
+
+; FIXME:
+; trunc (shuffle X, undef, SplatMask) --> shuffle (trunc X), undef, SplatMask
+; A mask with undef elements should still be considered a splat mask.
+
+define <3 x i31> @wide_splat3(<3 x i33> %x) {
+; CHECK-LABEL: @wide_splat3(
+; CHECK-NEXT:    [[SHUF:%.*]] = shufflevector <3 x i33> %x, <3 x i33> undef, <3 x i32> <i32 undef, i32 1, i32 1>
+; CHECK-NEXT:    [[TRUNC:%.*]] = trunc <3 x i33> [[SHUF]] to <3 x i31>
+; CHECK-NEXT:    ret <3 x i31> [[TRUNC]]
+;
+  %shuf = shufflevector <3 x i33> %x, <3 x i33> undef, <3 x i32> <i32 undef, i32 1, i32 1>
+  %trunc = trunc <3 x i33> %shuf to <3 x i31>
+  ret <3 x i31> %trunc
+}
+
+; TODO: The shuffle extends the length of the input vector. Should we shrink this?
+
+define <8 x i8> @wide_lengthening_splat(<4 x i16> %v) {
+; CHECK-LABEL: @wide_lengthening_splat(
+; CHECK-NEXT:    [[SHUF:%.*]] = shufflevector <4 x i16> %v, <4 x i16> undef, <8 x i32> zeroinitializer
+; CHECK-NEXT:    [[TR:%.*]] = trunc <8 x i16> [[SHUF]] to <8 x i8>
+; CHECK-NEXT:    ret <8 x i8> [[TR]]
+;
+  %shuf = shufflevector <4 x i16> %v, <4 x i16> %v, <8 x i32> zeroinitializer
+  %tr = trunc <8 x i16> %shuf to <8 x i8>
+  ret <8 x i8> %tr
+}
+
+define <2 x i8> @narrow_add_vec_constant(<2 x i32> %x) {
+; CHECK-LABEL: @narrow_add_vec_constant(
+; CHECK-NEXT:    [[TMP1:%.*]] = trunc <2 x i32> %x to <2 x i8>
+; CHECK-NEXT:    [[TR:%.*]] = add <2 x i8> [[TMP1]], <i8 0, i8 127>
+; CHECK-NEXT:    ret <2 x i8> [[TR]]
+;
+  %add = add <2 x i32> %x, <i32 256, i32 -129>
+  %tr = trunc <2 x i32> %add to <2 x i8>
+  ret <2 x i8> %tr
+}
+
+define <2 x i8> @narrow_mul_vec_constant(<2 x i32> %x) {
+; CHECK-LABEL: @narrow_mul_vec_constant(
+; CHECK-NEXT:    [[TMP1:%.*]] = trunc <2 x i32> %x to <2 x i8>
+; CHECK-NEXT:    [[TR:%.*]] = mul <2 x i8> [[TMP1]], <i8 0, i8 127>
+; CHECK-NEXT:    ret <2 x i8> [[TR]]
+;
+  %add = mul <2 x i32> %x, <i32 256, i32 -129>
+  %tr = trunc <2 x i32> %add to <2 x i8>
+  ret <2 x i8> %tr
+}
+
+define <2 x i8> @narrow_sub_vec_constant(<2 x i32> %x) {
+; CHECK-LABEL: @narrow_sub_vec_constant(
+; CHECK-NEXT:    [[TMP1:%.*]] = trunc <2 x i32> %x to <2 x i8>
+; CHECK-NEXT:    [[TR:%.*]] = sub <2 x i8> <i8 0, i8 127>, [[TMP1]]
+; CHECK-NEXT:    ret <2 x i8> [[TR]]
+;
+  %sub = sub <2 x i32> <i32 256, i32 -129>, %x
+  %tr = trunc <2 x i32> %sub to <2 x i8>
+  ret <2 x i8> %tr
+}
+

Added: llvm/trunk/test/Transforms/InstCombine/type_pun.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/type_pun.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/type_pun.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/type_pun.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,155 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt < %s -instcombine -S | FileCheck %s
+
+; Ensure that type punning using a union of vector and same-sized array
+; generates an extract instead of a shuffle with an uncommon vector size:
+;
+;   typedef uint32_t v4i32 __attribute__((vector_size(16)));
+;   union { v4i32 v; uint32_t a[4]; };
+;
+; This cleans up behind SROA, which inserts the uncommon vector size when
+; cleaning up the alloca/store/GEP/load.
+
+
+; Provide legal integer types.
+target datalayout = "p:32:32"
+
+
+; Extracting the zeroth element in an i32 array.
+define i32 @type_pun_zeroth(<16 x i8> %in) {
+; CHECK-LABEL: @type_pun_zeroth(
+; CHECK-NEXT:    [[SROA_BC:%.*]] = bitcast <16 x i8> [[IN:%.*]] to <4 x i32>
+; CHECK-NEXT:    [[SROA_EXTRACT:%.*]] = extractelement <4 x i32> [[SROA_BC]], i32 0
+; CHECK-NEXT:    ret i32 [[SROA_EXTRACT]]
+;
+  %sroa = shufflevector <16 x i8> %in, <16 x i8> undef, <4 x i32> <i32 0, i32 1, i32 2, i32 3>
+  %1 = bitcast <4 x i8> %sroa to i32
+  ret i32 %1
+}
+
+; Extracting the first element in an i32 array.
+define i32 @type_pun_first(<16 x i8> %in) {
+; CHECK-LABEL: @type_pun_first(
+; CHECK-NEXT:    [[SROA_BC:%.*]] = bitcast <16 x i8> [[IN:%.*]] to <4 x i32>
+; CHECK-NEXT:    [[SROA_EXTRACT:%.*]] = extractelement <4 x i32> [[SROA_BC]], i32 1
+; CHECK-NEXT:    ret i32 [[SROA_EXTRACT]]
+;
+  %sroa = shufflevector <16 x i8> %in, <16 x i8> undef, <4 x i32> <i32 4, i32 5, i32 6, i32 7>
+  %1 = bitcast <4 x i8> %sroa to i32
+  ret i32 %1
+}
+
+; Extracting an i32 that isn't aligned to any natural boundary.
+define i32 @type_pun_misaligned(<16 x i8> %in) {
+; CHECK-LABEL: @type_pun_misaligned(
+; CHECK-NEXT:    [[SROA_EXTRACT:%.*]] = shufflevector <16 x i8> [[IN:%.*]], <16 x i8> undef, <16 x i32> <i32 6, i32 7, i32 8, i32 9, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef>
+; CHECK-NEXT:    [[SROA_BC:%.*]] = bitcast <16 x i8> [[SROA_EXTRACT]] to <4 x i32>
+; CHECK-NEXT:    [[SROA_EXTRACT1:%.*]] = extractelement <4 x i32> [[SROA_BC]], i32 0
+; CHECK-NEXT:    ret i32 [[SROA_EXTRACT1]]
+;
+  %sroa = shufflevector <16 x i8> %in, <16 x i8> undef, <4 x i32> <i32 6, i32 7, i32 8, i32 9>
+  %1 = bitcast <4 x i8> %sroa to i32
+  ret i32 %1
+}
+
+; Type punning to an array of pointers.
+define i32* @type_pun_pointer(<16 x i8> %in) {
+; CHECK-LABEL: @type_pun_pointer(
+; CHECK-NEXT:    [[SROA_BC:%.*]] = bitcast <16 x i8> [[IN:%.*]] to <4 x i32>
+; CHECK-NEXT:    [[SROA_EXTRACT:%.*]] = extractelement <4 x i32> [[SROA_BC]], i32 0
+; CHECK-NEXT:    [[TMP1:%.*]] = inttoptr i32 [[SROA_EXTRACT]] to i32*
+; CHECK-NEXT:    ret i32* [[TMP1]]
+;
+  %sroa = shufflevector <16 x i8> %in, <16 x i8> undef, <4 x i32> <i32 0, i32 1, i32 2, i32 3>
+  %1 = bitcast <4 x i8> %sroa to i32
+  %2 = inttoptr i32 %1 to i32*
+  ret i32* %2
+}
+
+; Type punning to an array of 32-bit floating-point values.
+define float @type_pun_float(<16 x i8> %in) {
+; CHECK-LABEL: @type_pun_float(
+; CHECK-NEXT:    [[SROA_BC:%.*]] = bitcast <16 x i8> [[IN:%.*]] to <4 x float>
+; CHECK-NEXT:    [[SROA_EXTRACT:%.*]] = extractelement <4 x float> [[SROA_BC]], i32 0
+; CHECK-NEXT:    ret float [[SROA_EXTRACT]]
+;
+  %sroa = shufflevector <16 x i8> %in, <16 x i8> undef, <4 x i32> <i32 0, i32 1, i32 2, i32 3>
+  %1 = bitcast <4 x i8> %sroa to float
+  ret float %1
+}
+
+; Type punning to an array of 64-bit floating-point values.
+define double @type_pun_double(<16 x i8> %in) {
+; CHECK-LABEL: @type_pun_double(
+; CHECK-NEXT:    [[SROA_BC:%.*]] = bitcast <16 x i8> [[IN:%.*]] to <2 x double>
+; CHECK-NEXT:    [[SROA_EXTRACT:%.*]] = extractelement <2 x double> [[SROA_BC]], i32 0
+; CHECK-NEXT:    ret double [[SROA_EXTRACT]]
+;
+  %sroa = shufflevector <16 x i8> %in, <16 x i8> undef, <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7>
+  %1 = bitcast <8 x i8> %sroa to double
+  ret double %1
+}
+
+; Type punning to same-size floating-point and integer values.
+; Verify that multiple uses with different bitcast types are properly handled.
+define { float, i32 } @type_pun_float_i32(<16 x i8> %in) {
+; CHECK-LABEL: @type_pun_float_i32(
+; CHECK-NEXT:    [[SROA_BC:%.*]] = bitcast <16 x i8> [[IN:%.*]] to <4 x i32>
+; CHECK-NEXT:    [[SROA_EXTRACT:%.*]] = extractelement <4 x i32> [[SROA_BC]], i32 0
+; CHECK-NEXT:    [[SROA_BC1:%.*]] = bitcast <16 x i8> [[IN]] to <4 x float>
+; CHECK-NEXT:    [[SROA_EXTRACT2:%.*]] = extractelement <4 x float> [[SROA_BC1]], i32 0
+; CHECK-NEXT:    [[TMP1:%.*]] = insertvalue { float, i32 } undef, float [[SROA_EXTRACT2]], 0
+; CHECK-NEXT:    [[TMP2:%.*]] = insertvalue { float, i32 } [[TMP1]], i32 [[SROA_EXTRACT]], 1
+; CHECK-NEXT:    ret { float, i32 } [[TMP2]]
+;
+  %sroa = shufflevector <16 x i8> %in, <16 x i8> undef, <4 x i32> <i32 0, i32 1, i32 2, i32 3>
+  %f = bitcast <4 x i8> %sroa to float
+  %i = bitcast <4 x i8> %sroa to i32
+  %1 = insertvalue { float, i32 } undef, float %f, 0
+  %2 = insertvalue { float, i32 } %1, i32 %i, 1
+  ret { float, i32 } %2
+}
+
+; Type punning two i32 values, with control flow.
+; Verify that the bitcast is shared and dominates usage.
+define i32 @type_pun_i32_ctrl(<16 x i8> %in) {
+; CHECK-LABEL: @type_pun_i32_ctrl(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[SROA_BC:%.*]] = bitcast <16 x i8> [[IN:%.*]] to <4 x i32>
+; CHECK-NEXT:    br i1 undef, label [[LEFT:%.*]], label [[RIGHT:%.*]]
+; CHECK:       left:
+; CHECK-NEXT:    [[SROA_EXTRACT1:%.*]] = extractelement <4 x i32> [[SROA_BC]], i32 0
+; CHECK-NEXT:    br label [[TAIL:%.*]]
+; CHECK:       right:
+; CHECK-NEXT:    [[SROA_EXTRACT:%.*]] = extractelement <4 x i32> [[SROA_BC]], i32 0
+; CHECK-NEXT:    br label [[TAIL]]
+; CHECK:       tail:
+; CHECK-NEXT:    [[I:%.*]] = phi i32 [ [[SROA_EXTRACT1]], [[LEFT]] ], [ [[SROA_EXTRACT]], [[RIGHT]] ]
+; CHECK-NEXT:    ret i32 [[I]]
+;
+entry:
+  %sroa = shufflevector <16 x i8> %in, <16 x i8> undef, <4 x i32> <i32 0, i32 1, i32 2, i32 3>
+  br i1 undef, label %left, label %right
+left:
+  %lhs = bitcast <4 x i8> %sroa to i32
+  br label %tail
+right:
+  %rhs = bitcast <4 x i8> %sroa to i32
+  br label %tail
+tail:
+  %i = phi i32 [ %lhs, %left ], [ %rhs, %right ]
+  ret i32 %i
+}
+
+; Extracting a type that won't fit in a vector isn't handled. The function
+; should stay the same.
+define i40 @type_pun_unhandled(<16 x i8> %in) {
+; CHECK-LABEL: @type_pun_unhandled(
+; CHECK-NEXT:    [[SROA:%.*]] = shufflevector <16 x i8> [[IN:%.*]], <16 x i8> undef, <5 x i32> <i32 4, i32 5, i32 6, i32 7, i32 8>
+; CHECK-NEXT:    [[TMP1:%.*]] = bitcast <5 x i8> [[SROA]] to i40
+; CHECK-NEXT:    ret i40 [[TMP1]]
+;
+  %sroa = shufflevector <16 x i8> %in, <16 x i8> undef, <5 x i32> <i32 4, i32 5, i32 6, i32 7, i32 8>
+  %1 = bitcast <5 x i8> %sroa to i40
+  ret i40 %1
+}

Added: llvm/trunk/test/Transforms/InstCombine/uadd-with-overflow.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/uadd-with-overflow.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/uadd-with-overflow.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/uadd-with-overflow.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,126 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt < %s -instcombine -S | FileCheck %s
+
+declare { <2 x i32>, <2 x i1> } @llvm.uadd.with.overflow.v2i32(<2 x i32>, <2 x i32>)
+
+declare { <2 x i8>, <2 x i1> } @llvm.uadd.with.overflow.v2i8(<2 x i8>, <2 x i8>)
+
+declare { i32, i1 } @llvm.uadd.with.overflow.i32(i32, i32)
+
+declare { i8, i1 } @llvm.uadd.with.overflow.i8(i8, i8)
+
+define { i32, i1 } @simple_fold(i32 %x) {
+; CHECK-LABEL: @simple_fold(
+; CHECK-NEXT:    [[TMP1:%.*]] = call { i32, i1 } @llvm.uadd.with.overflow.i32(i32 [[X:%.*]], i32 20)
+; CHECK-NEXT:    ret { i32, i1 } [[TMP1]]
+;
+  %a = add nuw i32 %x, 7
+  %b = tail call { i32, i1 } @llvm.uadd.with.overflow.i32(i32 %a, i32 13)
+  ret { i32, i1 } %b
+}
+
+define { i8, i1 } @fold_on_constant_add_no_overflow(i8 %x) {
+; CHECK-LABEL: @fold_on_constant_add_no_overflow(
+; CHECK-NEXT:    [[TMP1:%.*]] = call { i8, i1 } @llvm.uadd.with.overflow.i8(i8 [[X:%.*]], i8 -1)
+; CHECK-NEXT:    ret { i8, i1 } [[TMP1]]
+;
+  %a = add nuw i8 %x, 200
+  %b = tail call { i8, i1 } @llvm.uadd.with.overflow.i8(i8 %a, i8 55)
+  ret { i8, i1 } %b
+}
+
+define { i8, i1 } @no_fold_on_constant_add_overflow(i8 %x) {
+; CHECK-LABEL: @no_fold_on_constant_add_overflow(
+; CHECK-NEXT:    [[TMP1:%.*]] = insertvalue { i8, i1 } { i8 undef, i1 true }, i8 [[X:%.*]], 0
+; CHECK-NEXT:    ret { i8, i1 } [[TMP1]]
+;
+  %a = add nuw i8 %x, 200
+  %b = tail call { i8, i1 } @llvm.uadd.with.overflow.i8(i8 %a, i8 56)
+  ret { i8, i1 } %b
+}
+
+define { <2 x i8>, <2 x i1> } @no_fold_vector_no_overflow(<2 x i8> %x) {
+; CHECK-LABEL: @no_fold_vector_no_overflow(
+; CHECK-NEXT:    [[A:%.*]] = add nuw <2 x i8> [[X:%.*]], <i8 -57, i8 -56>
+; CHECK-NEXT:    [[B:%.*]] = tail call { <2 x i8>, <2 x i1> } @llvm.uadd.with.overflow.v2i8(<2 x i8> [[A]], <2 x i8> <i8 55, i8 55>)
+; CHECK-NEXT:    ret { <2 x i8>, <2 x i1> } [[B]]
+;
+  %a = add nuw <2 x i8> %x, <i8 199, i8 200>
+  %b = tail call { <2 x i8>, <2 x i1> } @llvm.uadd.with.overflow.v2i8(<2 x i8> %a, <2 x i8> <i8 55, i8 55>)
+  ret { <2 x i8>, <2 x i1> } %b
+}
+
+define { <2 x i8>, <2 x i1> } @no_fold_vector_overflow(<2 x i8> %x) {
+; CHECK-LABEL: @no_fold_vector_overflow(
+; CHECK-NEXT:    [[A:%.*]] = add nuw <2 x i8> [[X:%.*]], <i8 -56, i8 -55>
+; CHECK-NEXT:    [[B:%.*]] = tail call { <2 x i8>, <2 x i1> } @llvm.uadd.with.overflow.v2i8(<2 x i8> [[A]], <2 x i8> <i8 55, i8 55>)
+; CHECK-NEXT:    ret { <2 x i8>, <2 x i1> } [[B]]
+;
+  %a = add nuw <2 x i8> %x, <i8 200, i8 201>
+  %b = tail call { <2 x i8>, <2 x i1> } @llvm.uadd.with.overflow.v2i8(<2 x i8> %a, <2 x i8> <i8 55, i8 55>)
+  ret { <2 x i8>, <2 x i1> } %b
+}
+
+define { <2 x i32>, <2 x i1> } @fold_simple_splat_constant(<2 x i32> %x) {
+; CHECK-LABEL: @fold_simple_splat_constant(
+; CHECK-NEXT:    [[TMP1:%.*]] = call { <2 x i32>, <2 x i1> } @llvm.uadd.with.overflow.v2i32(<2 x i32> [[X:%.*]], <2 x i32> <i32 42, i32 42>)
+; CHECK-NEXT:    ret { <2 x i32>, <2 x i1> } [[TMP1]]
+;
+  %a = add nuw <2 x i32> %x, <i32 12, i32 12>
+  %b = tail call { <2 x i32>, <2 x i1> } @llvm.uadd.with.overflow.v2i32(<2 x i32> %a, <2 x i32> <i32 30, i32 30>)
+  ret { <2 x i32>, <2 x i1> } %b
+}
+
+define { <2 x i32>, <2 x i1> } @no_fold_splat_undef_constant(<2 x i32> %x) {
+; CHECK-LABEL: @no_fold_splat_undef_constant(
+; CHECK-NEXT:    [[A:%.*]] = add nuw <2 x i32> [[X:%.*]], <i32 12, i32 undef>
+; CHECK-NEXT:    [[B:%.*]] = tail call { <2 x i32>, <2 x i1> } @llvm.uadd.with.overflow.v2i32(<2 x i32> [[A]], <2 x i32> <i32 30, i32 30>)
+; CHECK-NEXT:    ret { <2 x i32>, <2 x i1> } [[B]]
+;
+  %a = add nuw <2 x i32> %x, <i32 12, i32 undef>
+  %b = tail call { <2 x i32>, <2 x i1> } @llvm.uadd.with.overflow.v2i32(<2 x i32> %a, <2 x i32> <i32 30, i32 30>)
+  ret { <2 x i32>, <2 x i1> } %b
+}
+
+define { <2 x i32>, <2 x i1> } @no_fold_splat_not_constant(<2 x i32> %x, <2 x i32> %y) {
+; CHECK-LABEL: @no_fold_splat_not_constant(
+; CHECK-NEXT:    [[A:%.*]] = add nuw <2 x i32> [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    [[B:%.*]] = tail call { <2 x i32>, <2 x i1> } @llvm.uadd.with.overflow.v2i32(<2 x i32> [[A]], <2 x i32> <i32 30, i32 30>)
+; CHECK-NEXT:    ret { <2 x i32>, <2 x i1> } [[B]]
+;
+  %a = add nuw <2 x i32> %x, %y
+  %b = tail call { <2 x i32>, <2 x i1> } @llvm.uadd.with.overflow.v2i32(<2 x i32> %a, <2 x i32> <i32 30, i32 30>)
+  ret { <2 x i32>, <2 x i1> } %b
+}
+
+define { i32, i1 } @fold_nuwnsw(i32 %x) {
+; CHECK-LABEL: @fold_nuwnsw(
+; CHECK-NEXT:    [[TMP1:%.*]] = call { i32, i1 } @llvm.uadd.with.overflow.i32(i32 [[X:%.*]], i32 42)
+; CHECK-NEXT:    ret { i32, i1 } [[TMP1]]
+;
+  %a = add nuw nsw i32 %x, 12
+  %b = tail call { i32, i1 } @llvm.uadd.with.overflow.i32(i32 %a, i32 30)
+  ret { i32, i1 } %b
+}
+
+define { i32, i1 } @no_fold_nsw(i32 %x) {
+; CHECK-LABEL: @no_fold_nsw(
+; CHECK-NEXT:    [[A:%.*]] = add nsw i32 [[X:%.*]], 12
+; CHECK-NEXT:    [[B:%.*]] = tail call { i32, i1 } @llvm.uadd.with.overflow.i32(i32 [[A]], i32 30)
+; CHECK-NEXT:    ret { i32, i1 } [[B]]
+;
+  %a = add nsw i32 %x, 12
+  %b = tail call { i32, i1 } @llvm.uadd.with.overflow.i32(i32 %a, i32 30)
+  ret { i32, i1 } %b
+}
+
+define { i32, i1 } @no_fold_wrapped_add(i32 %x) {
+; CHECK-LABEL: @no_fold_wrapped_add(
+; CHECK-NEXT:    [[A:%.*]] = add i32 [[X:%.*]], 12
+; CHECK-NEXT:    [[B:%.*]] = tail call { i32, i1 } @llvm.uadd.with.overflow.i32(i32 [[A]], i32 30)
+; CHECK-NEXT:    ret { i32, i1 } [[B]]
+;
+  %a = add i32 %x, 12
+  %b = tail call { i32, i1 } @llvm.uadd.with.overflow.i32(i32 30, i32 %a)
+  ret { i32, i1 } %b
+}

Added: llvm/trunk/test/Transforms/InstCombine/uaddo.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/uaddo.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/uaddo.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/uaddo.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,182 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt < %s -instcombine -S | FileCheck %s
+
+define i32 @uaddo_commute1(i32 %x, i32 %y, i32 %z) {
+; CHECK-LABEL: @uaddo_commute1(
+; CHECK-NEXT:    [[NOTY:%.*]] = xor i32 [[Y:%.*]], -1
+; CHECK-NEXT:    [[A:%.*]] = add i32 [[X:%.*]], [[Y]]
+; CHECK-NEXT:    [[C:%.*]] = icmp ult i32 [[NOTY]], [[X]]
+; CHECK-NEXT:    [[R:%.*]] = select i1 [[C]], i32 [[Z:%.*]], i32 [[A]]
+; CHECK-NEXT:    ret i32 [[R]]
+;
+  %noty = xor i32 %y, -1
+  %a = add i32 %x, %y
+  %c = icmp ugt i32 %x, %noty
+  %r = select i1 %c, i32 %z, i32 %a
+  ret i32 %r
+}
+
+define <2 x i32> @uaddo_commute2(<2 x i32> %x, <2 x i32> %y, <2 x i32> %z) {
+; CHECK-LABEL: @uaddo_commute2(
+; CHECK-NEXT:    [[NOTY:%.*]] = xor <2 x i32> [[Y:%.*]], <i32 -1, i32 -1>
+; CHECK-NEXT:    [[A:%.*]] = add <2 x i32> [[Y]], [[X:%.*]]
+; CHECK-NEXT:    [[C:%.*]] = icmp ult <2 x i32> [[NOTY]], [[X]]
+; CHECK-NEXT:    [[R:%.*]] = select <2 x i1> [[C]], <2 x i32> [[Z:%.*]], <2 x i32> [[A]]
+; CHECK-NEXT:    ret <2 x i32> [[R]]
+;
+  %noty = xor <2 x i32> %y, <i32 -1, i32 -1>
+  %a = add <2 x i32> %y, %x
+  %c = icmp ugt <2 x i32> %x, %noty
+  %r = select <2 x i1> %c, <2 x i32> %z, <2 x i32> %a
+  ret <2 x i32> %r
+}
+
+define i32 @uaddo_commute3(i32 %x, i32 %y, i32 %z) {
+; CHECK-LABEL: @uaddo_commute3(
+; CHECK-NEXT:    [[NOTY:%.*]] = xor i32 [[Y:%.*]], -1
+; CHECK-NEXT:    [[A:%.*]] = add i32 [[X:%.*]], [[Y]]
+; CHECK-NEXT:    [[C:%.*]] = icmp ult i32 [[NOTY]], [[X]]
+; CHECK-NEXT:    [[R:%.*]] = select i1 [[C]], i32 [[Z:%.*]], i32 [[A]]
+; CHECK-NEXT:    ret i32 [[R]]
+;
+  %noty = xor i32 %y, -1
+  %a = add i32 %x, %y
+  %c = icmp ult i32 %noty, %x
+  %r = select i1 %c, i32 %z, i32 %a
+  ret i32 %r
+}
+
+define i32 @uaddo_commute4(i32 %x, i32 %y, i32 %z) {
+; CHECK-LABEL: @uaddo_commute4(
+; CHECK-NEXT:    [[NOTY:%.*]] = xor i32 [[Y:%.*]], -1
+; CHECK-NEXT:    [[A:%.*]] = add i32 [[Y]], [[X:%.*]]
+; CHECK-NEXT:    [[C:%.*]] = icmp ult i32 [[NOTY]], [[X]]
+; CHECK-NEXT:    [[R:%.*]] = select i1 [[C]], i32 [[Z:%.*]], i32 [[A]]
+; CHECK-NEXT:    ret i32 [[R]]
+;
+  %noty = xor i32 %y, -1
+  %a = add i32 %y, %x
+  %c = icmp ult i32 %noty, %x
+  %r = select i1 %c, i32 %z, i32 %a
+  ret i32 %r
+}
+
+define i32 @uaddo_commute5(i32 %x, i32 %y, i32 %z) {
+; CHECK-LABEL: @uaddo_commute5(
+; CHECK-NEXT:    [[NOTY:%.*]] = xor i32 [[Y:%.*]], -1
+; CHECK-NEXT:    [[A:%.*]] = add i32 [[X:%.*]], [[Y]]
+; CHECK-NEXT:    [[C:%.*]] = icmp ult i32 [[NOTY]], [[X]]
+; CHECK-NEXT:    [[R:%.*]] = select i1 [[C]], i32 [[A]], i32 [[Z:%.*]]
+; CHECK-NEXT:    ret i32 [[R]]
+;
+  %noty = xor i32 %y, -1
+  %a = add i32 %x, %y
+  %c = icmp ugt i32 %x, %noty
+  %r = select i1 %c, i32 %a, i32 %z
+  ret i32 %r
+}
+
+define i32 @uaddo_commute6(i32 %x, i32 %y, i32 %z) {
+; CHECK-LABEL: @uaddo_commute6(
+; CHECK-NEXT:    [[NOTY:%.*]] = xor i32 [[Y:%.*]], -1
+; CHECK-NEXT:    [[A:%.*]] = add i32 [[Y]], [[X:%.*]]
+; CHECK-NEXT:    [[C:%.*]] = icmp ult i32 [[NOTY]], [[X]]
+; CHECK-NEXT:    [[R:%.*]] = select i1 [[C]], i32 [[A]], i32 [[Z:%.*]]
+; CHECK-NEXT:    ret i32 [[R]]
+;
+  %noty = xor i32 %y, -1
+  %a = add i32 %y, %x
+  %c = icmp ugt i32 %x, %noty
+  %r = select i1 %c, i32 %a, i32 %z
+  ret i32 %r
+}
+
+define i32 @uaddo_commute7(i32 %x, i32 %y, i32 %z) {
+; CHECK-LABEL: @uaddo_commute7(
+; CHECK-NEXT:    [[NOTY:%.*]] = xor i32 [[Y:%.*]], -1
+; CHECK-NEXT:    [[A:%.*]] = add i32 [[X:%.*]], [[Y]]
+; CHECK-NEXT:    [[C:%.*]] = icmp ult i32 [[NOTY]], [[X]]
+; CHECK-NEXT:    [[R:%.*]] = select i1 [[C]], i32 [[A]], i32 [[Z:%.*]]
+; CHECK-NEXT:    ret i32 [[R]]
+;
+  %noty = xor i32 %y, -1
+  %a = add i32 %x, %y
+  %c = icmp ult i32 %noty, %x
+  %r = select i1 %c, i32 %a, i32 %z
+  ret i32 %r
+}
+
+define i32 @uaddo_commute8(i32 %x, i32 %y, i32 %z) {
+; CHECK-LABEL: @uaddo_commute8(
+; CHECK-NEXT:    [[NOTY:%.*]] = xor i32 [[Y:%.*]], -1
+; CHECK-NEXT:    [[A:%.*]] = add i32 [[Y]], [[X:%.*]]
+; CHECK-NEXT:    [[C:%.*]] = icmp ult i32 [[NOTY]], [[X]]
+; CHECK-NEXT:    [[R:%.*]] = select i1 [[C]], i32 [[A]], i32 [[Z:%.*]]
+; CHECK-NEXT:    ret i32 [[R]]
+;
+  %noty = xor i32 %y, -1
+  %a = add i32 %y, %x
+  %c = icmp ult i32 %noty, %x
+  %r = select i1 %c, i32 %a, i32 %z
+  ret i32 %r
+}
+
+define i32 @uaddo_wrong_pred1(i32 %x, i32 %y, i32 %z) {
+; CHECK-LABEL: @uaddo_wrong_pred1(
+; CHECK-NEXT:    [[NOTY:%.*]] = xor i32 [[Y:%.*]], -1
+; CHECK-NEXT:    [[A:%.*]] = add i32 [[X:%.*]], [[Y]]
+; CHECK-NEXT:    [[C:%.*]] = icmp ugt i32 [[NOTY]], [[X]]
+; CHECK-NEXT:    [[R:%.*]] = select i1 [[C]], i32 [[Z:%.*]], i32 [[A]]
+; CHECK-NEXT:    ret i32 [[R]]
+;
+  %noty = xor i32 %y, -1
+  %a = add i32 %x, %y
+  %c = icmp ult i32 %x, %noty
+  %r = select i1 %c, i32 %z, i32 %a
+  ret i32 %r
+}
+
+define i32 @uaddo_wrong_pred2(i32 %x, i32 %y, i32 %z) {
+; CHECK-LABEL: @uaddo_wrong_pred2(
+; CHECK-NEXT:    [[NOTY:%.*]] = xor i32 [[Y:%.*]], -1
+; CHECK-NEXT:    [[A:%.*]] = add i32 [[X:%.*]], [[Y]]
+; CHECK-NEXT:    [[C:%.*]] = icmp ugt i32 [[NOTY]], [[X]]
+; CHECK-NEXT:    [[R:%.*]] = select i1 [[C]], i32 [[A]], i32 [[Z:%.*]]
+; CHECK-NEXT:    ret i32 [[R]]
+;
+  %noty = xor i32 %y, -1
+  %a = add i32 %x, %y
+  %c = icmp uge i32 %x, %noty
+  %r = select i1 %c, i32 %z, i32 %a
+  ret i32 %r
+}
+
+; icmp canonicalization should be consistent for these cases.
+; Either the compare depends on the sum or not.
+
+define i1 @uaddo_1(i8 %x, i8* %p) {
+; CHECK-LABEL: @uaddo_1(
+; CHECK-NEXT:    [[A:%.*]] = add i8 [[X:%.*]], 1
+; CHECK-NEXT:    store i8 [[A]], i8* [[P:%.*]], align 1
+; CHECK-NEXT:    [[C:%.*]] = icmp eq i8 [[A]], 0
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %a = add i8 %x, 1
+  store i8 %a, i8* %p
+  %c = icmp ult i8 %a, 1
+  ret i1 %c
+}
+
+define i1 @uaddo_neg1(i8 %x, i8* %p) {
+; CHECK-LABEL: @uaddo_neg1(
+; CHECK-NEXT:    [[A:%.*]] = add i8 [[X:%.*]], -1
+; CHECK-NEXT:    store i8 [[A]], i8* [[P:%.*]], align 1
+; CHECK-NEXT:    [[C:%.*]] = icmp ne i8 [[X]], 0
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %a = add i8 %x, -1
+  store i8 %a, i8* %p
+  %c = icmp ne i8 %a, -1
+  ret i1 %c
+}
+

Added: llvm/trunk/test/Transforms/InstCombine/udiv-simplify.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/udiv-simplify.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/udiv-simplify.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/udiv-simplify.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,106 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt < %s -instcombine -S | FileCheck %s
+
+define i64 @test1(i32 %x) nounwind {
+; CHECK-LABEL: @test1(
+; CHECK-NEXT:    ret i64 0
+;
+  %y = lshr i32 %x, 1
+  %r = udiv i32 %y, -1
+  %z = sext i32 %r to i64
+  ret i64 %z
+}
+define i64 @test2(i32 %x) nounwind {
+; CHECK-LABEL: @test2(
+; CHECK-NEXT:    ret i64 0
+;
+  %y = lshr i32 %x, 31
+  %r = udiv i32 %y, 3
+  %z = sext i32 %r to i64
+  ret i64 %z
+}
+
+; The udiv instructions shouldn't be optimized away, and the
+; sext instructions should be optimized to zext.
+
+define i64 @test1_PR2274(i32 %x, i32 %g) nounwind {
+; CHECK-LABEL: @test1_PR2274(
+; CHECK-NEXT:    [[Y:%.*]] = lshr i32 [[X:%.*]], 30
+; CHECK-NEXT:    [[R:%.*]] = udiv i32 [[Y]], [[G:%.*]]
+; CHECK-NEXT:    [[TMP1:%.*]] = zext i32 [[R]] to i64
+; CHECK-NEXT:    ret i64 [[TMP1]]
+;
+  %y = lshr i32 %x, 30
+  %r = udiv i32 %y, %g
+  %z = sext i32 %r to i64
+  ret i64 %z
+}
+define i64 @test2_PR2274(i32 %x, i32 %v) nounwind {
+; CHECK-LABEL: @test2_PR2274(
+; CHECK-NEXT:    [[Y:%.*]] = lshr i32 [[X:%.*]], 31
+; CHECK-NEXT:    [[R:%.*]] = udiv i32 [[Y]], [[V:%.*]]
+; CHECK-NEXT:    [[TMP1:%.*]] = zext i32 [[R]] to i64
+; CHECK-NEXT:    ret i64 [[TMP1]]
+;
+  %y = lshr i32 %x, 31
+  %r = udiv i32 %y, %v
+  %z = sext i32 %r to i64
+  ret i64 %z
+}
+
+; The udiv should be simplified according to the rule:
+; X udiv (C1 << N), where C1 is `1<<C2` --> X >> (N+C2)
+ at b = external global [1 x i16]
+
+define i32 @PR30366(i1 %a) {
+; CHECK-LABEL: @PR30366(
+; CHECK-NEXT:    [[Z:%.*]] = zext i1 [[A:%.*]] to i32
+; CHECK-NEXT:    [[D:%.*]] = lshr i32 [[Z]], zext (i16 ptrtoint ([1 x i16]* @b to i16) to i32)
+; CHECK-NEXT:    ret i32 [[D]]
+;
+  %z = zext i1 %a to i32
+  %d = udiv i32 %z, zext (i16 shl (i16 1, i16 ptrtoint ([1 x i16]* @b to i16)) to i32)
+  ret i32 %d
+}
+
+; OSS-Fuzz #4857
+; https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=4857
+define i177 @ossfuzz_4857(i177 %X, i177 %Y) {
+; CHECK-LABEL: @ossfuzz_4857(
+; CHECK-NEXT:    store i1 false, i1* undef, align 1
+; CHECK-NEXT:    ret i177 0
+;
+  %B5 = udiv i177 %Y, -1
+  %B4 = add i177 %B5, -1
+  %B2 = add i177 %B4, -1
+  %B6 = mul i177 %B5, %B2
+  %B3 = add i177 %B2, %B2
+  %B9 = xor i177 %B4, %B3
+  %B13 = ashr i177 %Y, %B2
+  %B22 = add i177 %B9, %B13
+  %B1 = udiv i177 %B5, %B6
+  %C9 = icmp ult i177 %Y, %B22
+  store i1 %C9, i1* undef
+  ret i177 %B1
+}
+
+define i32 @udiv_demanded(i32 %a) {
+; CHECK-LABEL: @udiv_demanded(
+; CHECK-NEXT:    [[U:%.*]] = udiv i32 [[A:%.*]], 12
+; CHECK-NEXT:    ret i32 [[U]]
+;
+  %o = or i32 %a, 3
+  %u = udiv i32 %o, 12
+  ret i32 %u
+}
+
+define i32 @udiv_exact_demanded(i32 %a) {
+; CHECK-LABEL: @udiv_exact_demanded(
+; CHECK-NEXT:    [[O:%.*]] = and i32 [[A:%.*]], -3
+; CHECK-NEXT:    [[U:%.*]] = udiv exact i32 [[O]], 12
+; CHECK-NEXT:    ret i32 [[U]]
+;
+  %o = and i32 %a, -3
+  %u = udiv exact i32 %o, 12
+  ret i32 %u
+}

Added: llvm/trunk/test/Transforms/InstCombine/udiv_select_to_select_shift.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/udiv_select_to_select_shift.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/udiv_select_to_select_shift.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/udiv_select_to_select_shift.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,38 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt < %s -instcombine -S | FileCheck %s
+
+; Test that this transform works:
+; udiv X, (Select Cond, C1, C2) --> Select Cond, (shr X, C1), (shr X, C2)
+
+define i64 @test(i64 %X, i1 %Cond ) {
+; CHECK-LABEL: @test(
+; CHECK-NEXT:    [[QUOTIENT1:%.*]] = lshr i64 [[X:%.*]], 4
+; CHECK-NEXT:    [[QUOTIENT2:%.*]] = lshr i64 [[X]], 3
+; CHECK-NEXT:    [[SUM:%.*]] = add nuw nsw i64 [[QUOTIENT1]], [[QUOTIENT2]]
+; CHECK-NEXT:    ret i64 [[SUM]]
+;
+  %divisor1 = select i1 %Cond, i64 16, i64 8
+  %quotient1 = udiv i64 %X, %divisor1
+  %divisor2 = select i1 %Cond, i64 8, i64 0
+  %quotient2 = udiv i64 %X, %divisor2
+  %sum = add i64 %quotient1, %quotient2
+  ret i64 %sum
+}
+
+; https://bugs.llvm.org/show_bug.cgi?id=34856
+; This would assert/crash because we didn't propagate the condition with the correct vector type.
+
+define <2 x i32> @PR34856(<2 x i32> %t0, <2 x i32> %t1) {
+; CHECK-LABEL: @PR34856(
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp ugt <2 x i32> [[T1:%.*]], <i32 -8, i32 -8>
+; CHECK-NEXT:    [[DIV1:%.*]] = zext <2 x i1> [[TMP1]] to <2 x i32>
+; CHECK-NEXT:    ret <2 x i32> [[DIV1]]
+;
+  %cmp = icmp eq <2 x i32> %t0, <i32 1, i32 1>
+  %zext = zext <2 x i1> %cmp to <2 x i32>
+  %neg = select <2 x i1> %cmp, <2 x i32> zeroinitializer, <2 x i32> <i32 -7, i32 -7>
+  %div1 = udiv <2 x i32> %t1, %neg
+  %use_cmp_again = add <2 x i32> %div1, %zext
+  ret <2 x i32> %use_cmp_again
+}
+

Added: llvm/trunk/test/Transforms/InstCombine/udivrem-change-width.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/udivrem-change-width.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/udivrem-change-width.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/udivrem-change-width.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,288 @@
+; RUN: opt < %s -instcombine -S | FileCheck %s
+
+target datalayout = "n8:32"
+
+; PR4548
+define i8 @udiv_i8(i8 %a, i8 %b) {
+; CHECK-LABEL: @udiv_i8(
+; CHECK-NEXT:    [[DIV:%.*]] = udiv i8 %a, %b
+; CHECK-NEXT:    ret i8 [[DIV]]
+;
+  %za = zext i8 %a to i32
+  %zb = zext i8 %b to i32
+  %udiv = udiv i32 %za, %zb
+  %conv3 = trunc i32 %udiv to i8
+  ret i8 %conv3
+}
+
+define <2 x i8> @udiv_i8_vec(<2 x i8> %a, <2 x i8> %b) {
+; CHECK-LABEL: @udiv_i8_vec(
+; CHECK-NEXT:    [[DIV:%.*]] = udiv <2 x i8> %a, %b
+; CHECK-NEXT:    ret <2 x i8> [[DIV]]
+;
+  %za = zext <2 x i8> %a to <2 x i32>
+  %zb = zext <2 x i8> %b to <2 x i32>
+  %udiv = udiv <2 x i32> %za, %zb
+  %conv3 = trunc <2 x i32> %udiv to <2 x i8>
+  ret <2 x i8> %conv3
+}
+
+define i8 @urem_i8(i8 %a, i8 %b) {
+; CHECK-LABEL: @urem_i8(
+; CHECK-NEXT:    [[TMP1:%.*]] = urem i8 %a, %b
+; CHECK-NEXT:    ret i8 [[TMP1]]
+;
+  %za = zext i8 %a to i32
+  %zb = zext i8 %b to i32
+  %udiv = urem i32 %za, %zb
+  %conv3 = trunc i32 %udiv to i8
+  ret i8 %conv3
+}
+
+define <2 x i8> @urem_i8_vec(<2 x i8> %a, <2 x i8> %b) {
+; CHECK-LABEL: @urem_i8_vec(
+; CHECK-NEXT:    [[TMP1:%.*]] = urem <2 x i8> %a, %b
+; CHECK-NEXT:    ret <2 x i8> [[TMP1]]
+;
+  %za = zext <2 x i8> %a to <2 x i32>
+  %zb = zext <2 x i8> %b to <2 x i32>
+  %udiv = urem <2 x i32> %za, %zb
+  %conv3 = trunc <2 x i32> %udiv to <2 x i8>
+  ret <2 x i8> %conv3
+}
+
+define i32 @udiv_i32(i8 %a, i8 %b) {
+; CHECK-LABEL: @udiv_i32(
+; CHECK-NEXT:    [[DIV:%.*]] = udiv i8 %a, %b
+; CHECK-NEXT:    [[UDIV:%.*]] = zext i8 [[DIV]] to i32
+; CHECK-NEXT:    ret i32 [[UDIV]]
+;
+  %za = zext i8 %a to i32
+  %zb = zext i8 %b to i32
+  %udiv = udiv i32 %za, %zb
+  ret i32 %udiv
+}
+
+define <2 x i32> @udiv_i32_vec(<2 x i8> %a, <2 x i8> %b) {
+; CHECK-LABEL: @udiv_i32_vec(
+; CHECK-NEXT:    [[DIV:%.*]] = udiv <2 x i8> %a, %b
+; CHECK-NEXT:    [[UDIV:%.*]] = zext <2 x i8> [[DIV]] to <2 x i32>
+; CHECK-NEXT:    ret <2 x i32> [[UDIV]]
+;
+  %za = zext <2 x i8> %a to <2 x i32>
+  %zb = zext <2 x i8> %b to <2 x i32>
+  %udiv = udiv <2 x i32> %za, %zb
+  ret <2 x i32> %udiv
+}
+
+define i32 @udiv_i32_multiuse(i8 %a, i8 %b) {
+; CHECK-LABEL: @udiv_i32_multiuse(
+; CHECK-NEXT:    [[ZA:%.*]] = zext i8 %a to i32
+; CHECK-NEXT:    [[ZB:%.*]] = zext i8 %b to i32
+; CHECK-NEXT:    [[UDIV:%.*]] = udiv i32 [[ZA]], [[ZB]]
+; CHECK-NEXT:    [[EXTRA_USES:%.*]] = add nuw nsw i32 [[ZA]], [[ZB]]
+; CHECK-NEXT:    [[R:%.*]] = mul nuw nsw i32 [[UDIV]], [[EXTRA_USES]]
+; CHECK-NEXT:    ret i32 [[R]]
+;
+  %za = zext i8 %a to i32
+  %zb = zext i8 %b to i32
+  %udiv = udiv i32 %za, %zb
+  %extra_uses = add i32 %za, %zb
+  %r = mul i32 %udiv, %extra_uses
+  ret i32 %r
+}
+
+define i32 @udiv_illegal_type(i9 %a, i9 %b) {
+; CHECK-LABEL: @udiv_illegal_type(
+; CHECK-NEXT:    [[DIV:%.*]] = udiv i9 %a, %b
+; CHECK-NEXT:    [[UDIV:%.*]] = zext i9 [[DIV]] to i32
+; CHECK-NEXT:    ret i32 [[UDIV]]
+;
+  %za = zext i9 %a to i32
+  %zb = zext i9 %b to i32
+  %udiv = udiv i32 %za, %zb
+  ret i32 %udiv
+}
+
+define i32 @urem_i32(i8 %a, i8 %b) {
+; CHECK-LABEL: @urem_i32(
+; CHECK-NEXT:    [[TMP1:%.*]] = urem i8 %a, %b
+; CHECK-NEXT:    [[UREM:%.*]] = zext i8 [[TMP1]] to i32
+; CHECK-NEXT:    ret i32 [[UREM]]
+;
+  %za = zext i8 %a to i32
+  %zb = zext i8 %b to i32
+  %urem = urem i32 %za, %zb
+  ret i32 %urem
+}
+
+define <2 x i32> @urem_i32_vec(<2 x i8> %a, <2 x i8> %b) {
+; CHECK-LABEL: @urem_i32_vec(
+; CHECK-NEXT:    [[TMP1:%.*]] = urem <2 x i8> %a, %b
+; CHECK-NEXT:    [[UREM:%.*]] = zext <2 x i8> [[TMP1]] to <2 x i32>
+; CHECK-NEXT:    ret <2 x i32> [[UREM]]
+;
+  %za = zext <2 x i8> %a to <2 x i32>
+  %zb = zext <2 x i8> %b to <2 x i32>
+  %urem = urem <2 x i32> %za, %zb
+  ret <2 x i32> %urem
+}
+
+define i32 @urem_i32_multiuse(i8 %a, i8 %b) {
+; CHECK-LABEL: @urem_i32_multiuse(
+; CHECK-NEXT:    [[ZA:%.*]] = zext i8 %a to i32
+; CHECK-NEXT:    [[ZB:%.*]] = zext i8 %b to i32
+; CHECK-NEXT:    [[UREM:%.*]] = urem i32 [[ZA]], [[ZB]]
+; CHECK-NEXT:    [[EXTRA_USES:%.*]] = add nuw nsw i32 [[ZA]], [[ZB]]
+; CHECK-NEXT:    [[R:%.*]] = mul nuw nsw i32 [[UREM]], [[EXTRA_USES]]
+; CHECK-NEXT:    ret i32 [[R]]
+;
+  %za = zext i8 %a to i32
+  %zb = zext i8 %b to i32
+  %urem = urem i32 %za, %zb
+  %extra_uses = add i32 %za, %zb
+  %r = mul i32 %urem, %extra_uses
+  ret i32 %r
+}
+
+define i32 @urem_illegal_type(i9 %a, i9 %b) {
+; CHECK-LABEL: @urem_illegal_type(
+; CHECK-NEXT:    [[TMP1:%.*]] = urem i9 %a, %b
+; CHECK-NEXT:    [[UREM:%.*]] = zext i9 [[TMP1]] to i32
+; CHECK-NEXT:    ret i32 [[UREM]]
+;
+  %za = zext i9 %a to i32
+  %zb = zext i9 %b to i32
+  %urem = urem i32 %za, %zb
+  ret i32 %urem
+}
+
+define i32 @udiv_i32_c(i8 %a) {
+; CHECK-LABEL: @udiv_i32_c(
+; CHECK-NEXT:    [[DIV:%.*]] = udiv i8 %a, 10
+; CHECK-NEXT:    [[UDIV:%.*]] = zext i8 [[DIV]] to i32
+; CHECK-NEXT:    ret i32 [[UDIV]]
+;
+  %za = zext i8 %a to i32
+  %udiv = udiv i32 %za, 10
+  ret i32 %udiv
+}
+
+define <2 x i32> @udiv_i32_c_vec(<2 x i8> %a) {
+; CHECK-LABEL: @udiv_i32_c_vec(
+; CHECK-NEXT:    [[TMP1:%.*]] = udiv <2 x i8> %a, <i8 10, i8 17>
+; CHECK-NEXT:    [[UDIV:%.*]] = zext <2 x i8> [[TMP1]] to <2 x i32>
+; CHECK-NEXT:    ret <2 x i32> [[UDIV]]
+;
+  %za = zext <2 x i8> %a to <2 x i32>
+  %udiv = udiv <2 x i32> %za, <i32 10, i32 17>
+  ret <2 x i32> %udiv
+}
+
+define i32 @udiv_i32_c_multiuse(i8 %a) {
+; CHECK-LABEL: @udiv_i32_c_multiuse(
+; CHECK-NEXT:    [[ZA:%.*]] = zext i8 %a to i32
+; CHECK-NEXT:    [[UDIV:%.*]] = udiv i32 [[ZA]], 10
+; CHECK-NEXT:    [[EXTRA_USE:%.*]] = add nuw nsw i32 [[UDIV]], [[ZA]]
+; CHECK-NEXT:    ret i32 [[EXTRA_USE]]
+;
+  %za = zext i8 %a to i32
+  %udiv = udiv i32 %za, 10
+  %extra_use = add i32 %za, %udiv
+  ret i32 %extra_use
+}
+
+define i32 @udiv_illegal_type_c(i9 %a) {
+; CHECK-LABEL: @udiv_illegal_type_c(
+; CHECK-NEXT:    [[DIV:%.*]] = udiv i9 %a, 10
+; CHECK-NEXT:    [[UDIV:%.*]] = zext i9 [[DIV]] to i32
+; CHECK-NEXT:    ret i32 [[UDIV]]
+;
+  %za = zext i9 %a to i32
+  %udiv = udiv i32 %za, 10
+  ret i32 %udiv
+}
+
+define i32 @urem_i32_c(i8 %a) {
+; CHECK-LABEL: @urem_i32_c(
+; CHECK-NEXT:    [[TMP1:%.*]] = urem i8 %a, 10
+; CHECK-NEXT:    [[UREM:%.*]] = zext i8 [[TMP1]] to i32
+; CHECK-NEXT:    ret i32 [[UREM]]
+;
+  %za = zext i8 %a to i32
+  %urem = urem i32 %za, 10
+  ret i32 %urem
+}
+
+define <2 x i32> @urem_i32_c_vec(<2 x i8> %a) {
+; CHECK-LABEL: @urem_i32_c_vec(
+; CHECK-NEXT:    [[TMP1:%.*]] = urem <2 x i8> %a, <i8 10, i8 17>
+; CHECK-NEXT:    [[UREM:%.*]] = zext <2 x i8> [[TMP1]] to <2 x i32>
+; CHECK-NEXT:    ret <2 x i32> [[UREM]]
+;
+  %za = zext <2 x i8> %a to <2 x i32>
+  %urem = urem <2 x i32> %za, <i32 10, i32 17>
+  ret <2 x i32> %urem
+}
+
+define i32 @urem_i32_c_multiuse(i8 %a) {
+; CHECK-LABEL: @urem_i32_c_multiuse(
+; CHECK-NEXT:    [[ZA:%.*]] = zext i8 %a to i32
+; CHECK-NEXT:    [[UREM:%.*]] = urem i32 [[ZA]], 10
+; CHECK-NEXT:    [[EXTRA_USE:%.*]] = add nuw nsw i32 [[UREM]], [[ZA]]
+; CHECK-NEXT:    ret i32 [[EXTRA_USE]]
+;
+  %za = zext i8 %a to i32
+  %urem = urem i32 %za, 10
+  %extra_use = add i32 %za, %urem
+  ret i32 %extra_use
+}
+
+define i32 @urem_illegal_type_c(i9 %a) {
+; CHECK-LABEL: @urem_illegal_type_c(
+; CHECK-NEXT:    [[TMP1:%.*]] = urem i9 %a, 10
+; CHECK-NEXT:    [[UREM:%.*]] = zext i9 [[TMP1]] to i32
+; CHECK-NEXT:    ret i32 [[UREM]]
+;
+  %za = zext i9 %a to i32
+  %urem = urem i32 %za, 10
+  ret i32 %urem
+}
+
+define i32 @udiv_c_i32(i8 %a) {
+; CHECK-LABEL: @udiv_c_i32(
+; CHECK-NEXT:    [[TMP1:%.*]] = udiv i8 10, %a
+; CHECK-NEXT:    [[UDIV:%.*]] = zext i8 [[TMP1]] to i32
+; CHECK-NEXT:    ret i32 [[UDIV]]
+;
+  %za = zext i8 %a to i32
+  %udiv = udiv i32 10, %za
+  ret i32 %udiv
+}
+
+define i32 @urem_c_i32(i8 %a) {
+; CHECK-LABEL: @urem_c_i32(
+; CHECK-NEXT:    [[TMP1:%.*]] = urem i8 10, %a
+; CHECK-NEXT:    [[UREM:%.*]] = zext i8 [[TMP1]] to i32
+; CHECK-NEXT:    ret i32 [[UREM]]
+;
+  %za = zext i8 %a to i32
+  %urem = urem i32 10, %za
+  ret i32 %urem
+}
+
+; Make sure constexpr is handled.
+
+ at b = external global [1 x i8]
+
+define i32 @udiv_constexpr(i8 %a) {
+; CHECK-LABEL: @udiv_constexpr(
+; CHECK-NEXT:    [[TMP1:%.*]] = udiv i8 %a, ptrtoint ([1 x i8]* @b to i8)
+; CHECK-NEXT:    [[D:%.*]] = zext i8 [[TMP1]] to i32
+; CHECK-NEXT:    ret i32 [[D]]
+;
+  %za = zext i8 %a to i32
+  %d = udiv i32 %za, zext (i8 ptrtoint ([1 x i8]* @b to i8) to i32)
+  ret i32 %d
+}
+

Added: llvm/trunk/test/Transforms/InstCombine/umax-icmp.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/umax-icmp.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/umax-icmp.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/umax-icmp.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
+
+; If we have a umax feeding an unsigned or equality icmp that shares an
+; operand with the umax, the compare should always be folded.
+; Test all 4 foldable predicates (eq,ne,ugt,ule) * 4 commutation
+; possibilities for each predicate. Note that folds to true/false
+; (predicate = uge/ult) or folds to an existing instruction should be
+; handled by InstSimplify.
+
+; umax(X, Y) == X --> X >= Y
+
+define i1 @eq_umax1(i32 %x, i32 %y) {
+; CHECK-LABEL: @eq_umax1(
+; CHECK-NEXT:    [[CMP2:%.*]] = icmp uge i32 %x, %y
+; CHECK-NEXT:    ret i1 [[CMP2]]
+;
+  %cmp1 = icmp ugt i32 %x, %y
+  %sel = select i1 %cmp1, i32 %x, i32 %y
+  %cmp2 = icmp eq i32 %sel, %x
+  ret i1 %cmp2
+}
+
+; Commute max operands.
+
+define i1 @eq_umax2(i32 %x, i32 %y) {
+; CHECK-LABEL: @eq_umax2(
+; CHECK-NEXT:    [[CMP2:%.*]] = icmp uge i32 %x, %y
+; CHECK-NEXT:    ret i1 [[CMP2]]
+;
+  %cmp1 = icmp ugt i32 %y, %x
+  %sel = select i1 %cmp1, i32 %y, i32 %x
+  %cmp2 = icmp eq i32 %sel, %x
+  ret i1 %cmp2
+}
+
+; Disguise the icmp predicate by commuting the max op to the RHS.
+
+define i1 @eq_umax3(i32 %a, i32 %y) {
+; CHECK-LABEL: @eq_umax3(
+; CHECK-NEXT:    [[X:%.*]] = add i32 %a, 3
+; CHECK-NEXT:    [[CMP2:%.*]] = icmp uge i32 [[X]], %y
+; CHECK-NEXT:    ret i1 [[CMP2]]
+;
+  %x = add i32 %a, 3 ; thwart complexity-based canonicalization
+  %cmp1 = icmp ugt i32 %x, %y
+  %sel = select i1 %cmp1, i32 %x, i32 %y
+  %cmp2 = icmp eq i32 %x, %sel
+  ret i1 %cmp2
+}
+
+; Commute max operands.
+
+define i1 @eq_umax4(i32 %a, i32 %y) {
+; CHECK-LABEL: @eq_umax4(
+; CHECK-NEXT:    [[X:%.*]] = add i32 %a, 3
+; CHECK-NEXT:    [[CMP2:%.*]] = icmp uge i32 [[X]], %y
+; CHECK-NEXT:    ret i1 [[CMP2]]
+;
+  %x = add i32 %a, 3 ; thwart complexity-based canonicalization
+  %cmp1 = icmp ugt i32 %y, %x
+  %sel = select i1 %cmp1, i32 %y, i32 %x
+  %cmp2 = icmp eq i32 %x, %sel
+  ret i1 %cmp2
+}
+
+; umax(X, Y) <= X --> X >= Y
+
+define i1 @ule_umax1(i32 %x, i32 %y) {
+; CHECK-LABEL: @ule_umax1(
+; CHECK-NEXT:    [[CMP2:%.*]] = icmp uge i32 %x, %y
+; CHECK-NEXT:    ret i1 [[CMP2]]
+;
+  %cmp1 = icmp ugt i32 %x, %y
+  %sel = select i1 %cmp1, i32 %x, i32 %y
+  %cmp2 = icmp ule i32 %sel, %x
+  ret i1 %cmp2
+}
+
+; Commute max operands.
+
+define i1 @ule_umax2(i32 %x, i32 %y) {
+; CHECK-LABEL: @ule_umax2(
+; CHECK-NEXT:    [[CMP2:%.*]] = icmp uge i32 %x, %y
+; CHECK-NEXT:    ret i1 [[CMP2]]
+;
+  %cmp1 = icmp ugt i32 %y, %x
+  %sel = select i1 %cmp1, i32 %y, i32 %x
+  %cmp2 = icmp ule i32 %sel, %x
+  ret i1 %cmp2
+}
+
+; Disguise the icmp predicate by commuting the max op to the RHS.
+
+define i1 @ule_umax3(i32 %a, i32 %y) {
+; CHECK-LABEL: @ule_umax3(
+; CHECK-NEXT:    [[X:%.*]] = add i32 %a, 3
+; CHECK-NEXT:    [[CMP2:%.*]] = icmp uge i32 [[X]], %y
+; CHECK-NEXT:    ret i1 [[CMP2]]
+;
+  %x = add i32 %a, 3 ; thwart complexity-based canonicalization
+  %cmp1 = icmp ugt i32 %x, %y
+  %sel = select i1 %cmp1, i32 %x, i32 %y
+  %cmp2 = icmp uge i32 %x, %sel
+  ret i1 %cmp2
+}
+
+; Commute max operands.
+
+define i1 @ule_umax4(i32 %a, i32 %y) {
+; CHECK-LABEL: @ule_umax4(
+; CHECK-NEXT:    [[X:%.*]] = add i32 %a, 3
+; CHECK-NEXT:    [[CMP2:%.*]] = icmp uge i32 [[X]], %y
+; CHECK-NEXT:    ret i1 [[CMP2]]
+;
+  %x = add i32 %a, 3 ; thwart complexity-based canonicalization
+  %cmp1 = icmp ugt i32 %y, %x
+  %sel = select i1 %cmp1, i32 %y, i32 %x
+  %cmp2 = icmp uge i32 %x, %sel
+  ret i1 %cmp2
+}
+
+; umax(X, Y) != X --> X < Y
+
+define i1 @ne_umax1(i32 %x, i32 %y) {
+; CHECK-LABEL: @ne_umax1(
+; CHECK-NEXT:    [[CMP2:%.*]] = icmp ult i32 %x, %y
+; CHECK-NEXT:    ret i1 [[CMP2]]
+;
+  %cmp1 = icmp ugt i32 %x, %y
+  %sel = select i1 %cmp1, i32 %x, i32 %y
+  %cmp2 = icmp ne i32 %sel, %x
+  ret i1 %cmp2
+}
+
+; Commute max operands.
+
+define i1 @ne_umax2(i32 %x, i32 %y) {
+; CHECK-LABEL: @ne_umax2(
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp ugt i32 %y, %x
+; CHECK-NEXT:    ret i1 [[CMP1]]
+;
+  %cmp1 = icmp ugt i32 %y, %x
+  %sel = select i1 %cmp1, i32 %y, i32 %x
+  %cmp2 = icmp ne i32 %sel, %x
+  ret i1 %cmp2
+}
+
+; Disguise the icmp predicate by commuting the max op to the RHS.
+
+define i1 @ne_umax3(i32 %a, i32 %y) {
+; CHECK-LABEL: @ne_umax3(
+; CHECK-NEXT:    [[X:%.*]] = add i32 %a, 3
+; CHECK-NEXT:    [[CMP2:%.*]] = icmp ult i32 [[X]], %y
+; CHECK-NEXT:    ret i1 [[CMP2]]
+;
+  %x = add i32 %a, 3 ; thwart complexity-based canonicalization
+  %cmp1 = icmp ugt i32 %x, %y
+  %sel = select i1 %cmp1, i32 %x, i32 %y
+  %cmp2 = icmp ne i32 %x, %sel
+  ret i1 %cmp2
+}
+
+; Commute max operands.
+
+define i1 @ne_umax4(i32 %a, i32 %y) {
+; CHECK-LABEL: @ne_umax4(
+; CHECK-NEXT:    [[X:%.*]] = add i32 %a, 3
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp ult i32 [[X]], %y
+; CHECK-NEXT:    ret i1 [[CMP1]]
+;
+  %x = add i32 %a, 3 ; thwart complexity-based canonicalization
+  %cmp1 = icmp ugt i32 %y, %x
+  %sel = select i1 %cmp1, i32 %y, i32 %x
+  %cmp2 = icmp ne i32 %x, %sel
+  ret i1 %cmp2
+}
+
+; umax(X, Y) > X --> X < Y
+
+define i1 @ugt_umax1(i32 %x, i32 %y) {
+; CHECK-LABEL: @ugt_umax1(
+; CHECK-NEXT:    [[CMP2:%.*]] = icmp ult i32 %x, %y
+; CHECK-NEXT:    ret i1 [[CMP2]]
+;
+  %cmp1 = icmp ugt i32 %x, %y
+  %sel = select i1 %cmp1, i32 %x, i32 %y
+  %cmp2 = icmp ugt i32 %sel, %x
+  ret i1 %cmp2
+}
+
+; Commute max operands.
+
+define i1 @ugt_umax2(i32 %x, i32 %y) {
+; CHECK-LABEL: @ugt_umax2(
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp ugt i32 %y, %x
+; CHECK-NEXT:    ret i1 [[CMP1]]
+;
+  %cmp1 = icmp ugt i32 %y, %x
+  %sel = select i1 %cmp1, i32 %y, i32 %x
+  %cmp2 = icmp ugt i32 %sel, %x
+  ret i1 %cmp2
+}
+
+; Disguise the icmp predicate by commuting the max op to the RHS.
+
+define i1 @ugt_umax3(i32 %a, i32 %y) {
+; CHECK-LABEL: @ugt_umax3(
+; CHECK-NEXT:    [[X:%.*]] = add i32 %a, 3
+; CHECK-NEXT:    [[CMP2:%.*]] = icmp ult i32 [[X]], %y
+; CHECK-NEXT:    ret i1 [[CMP2]]
+;
+  %x = add i32 %a, 3 ; thwart complexity-based canonicalization
+  %cmp1 = icmp ugt i32 %x, %y
+  %sel = select i1 %cmp1, i32 %x, i32 %y
+  %cmp2 = icmp ult i32 %x, %sel
+  ret i1 %cmp2
+}
+
+; Commute max operands.
+
+define i1 @ugt_umax4(i32 %a, i32 %y) {
+; CHECK-LABEL: @ugt_umax4(
+; CHECK-NEXT:    [[X:%.*]] = add i32 %a, 3
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp ult i32 [[X]], %y
+; CHECK-NEXT:    ret i1 [[CMP1]]
+;
+  %x = add i32 %a, 3 ; thwart complexity-based canonicalization
+  %cmp1 = icmp ugt i32 %y, %x
+  %sel = select i1 %cmp1, i32 %y, i32 %x
+  %cmp2 = icmp ult i32 %x, %sel
+  ret i1 %cmp2
+}
+

Added: llvm/trunk/test/Transforms/InstCombine/umin-icmp.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/umin-icmp.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/umin-icmp.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/umin-icmp.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
+
+; If we have a umin feeding an unsigned or equality icmp that shares an
+; operand with the umin, the compare should always be folded.
+; Test all 4 foldable predicates (eq,ne,uge,ult) * 4 commutation
+; possibilities for each predicate. Note that folds to true/false
+; (predicate is ule/ugt) or folds to an existing instruction should be
+; handled by InstSimplify.
+
+; umin(X, Y) == X --> X <= Y
+
+define i1 @eq_umin1(i32 %x, i32 %y) {
+; CHECK-LABEL: @eq_umin1(
+; CHECK-NEXT:    [[CMP2:%.*]] = icmp ule i32 %x, %y
+; CHECK-NEXT:    ret i1 [[CMP2]]
+;
+  %cmp1 = icmp ult i32 %x, %y
+  %sel = select i1 %cmp1, i32 %x, i32 %y
+  %cmp2 = icmp eq i32 %sel, %x
+  ret i1 %cmp2
+}
+
+; Commute min operands.
+
+define i1 @eq_umin2(i32 %x, i32 %y) {
+; CHECK-LABEL: @eq_umin2(
+; CHECK-NEXT:    [[CMP2:%.*]] = icmp ule i32 %x, %y
+; CHECK-NEXT:    ret i1 [[CMP2]]
+;
+  %cmp1 = icmp ult i32 %y, %x
+  %sel = select i1 %cmp1, i32 %y, i32 %x
+  %cmp2 = icmp eq i32 %sel, %x
+  ret i1 %cmp2
+}
+
+; Disguise the icmp predicate by commuting the min op to the RHS.
+
+define i1 @eq_umin3(i32 %a, i32 %y) {
+; CHECK-LABEL: @eq_umin3(
+; CHECK-NEXT:    [[X:%.*]] = add i32 %a, 3
+; CHECK-NEXT:    [[CMP2:%.*]] = icmp ule i32 [[X]], %y
+; CHECK-NEXT:    ret i1 [[CMP2]]
+;
+  %x = add i32 %a, 3 ; thwart complexity-based canonicalization
+  %cmp1 = icmp ult i32 %x, %y
+  %sel = select i1 %cmp1, i32 %x, i32 %y
+  %cmp2 = icmp eq i32 %x, %sel
+  ret i1 %cmp2
+}
+
+; Commute min operands.
+
+define i1 @eq_umin4(i32 %a, i32 %y) {
+; CHECK-LABEL: @eq_umin4(
+; CHECK-NEXT:    [[X:%.*]] = add i32 %a, 3
+; CHECK-NEXT:    [[CMP2:%.*]] = icmp ule i32 [[X]], %y
+; CHECK-NEXT:    ret i1 [[CMP2]]
+;
+  %x = add i32 %a, 3 ; thwart complexity-based canonicalization
+  %cmp1 = icmp ult i32 %y, %x
+  %sel = select i1 %cmp1, i32 %y, i32 %x
+  %cmp2 = icmp eq i32 %x, %sel
+  ret i1 %cmp2
+}
+
+; umin(X, Y) >= X --> X <= Y
+
+define i1 @uge_umin1(i32 %x, i32 %y) {
+; CHECK-LABEL: @uge_umin1(
+; CHECK-NEXT:    [[CMP2:%.*]] = icmp ule i32 %x, %y
+; CHECK-NEXT:    ret i1 [[CMP2]]
+;
+  %cmp1 = icmp ult i32 %x, %y
+  %sel = select i1 %cmp1, i32 %x, i32 %y
+  %cmp2 = icmp uge i32 %sel, %x
+  ret i1 %cmp2
+}
+
+; Commute min operands.
+
+define i1 @uge_umin2(i32 %x, i32 %y) {
+; CHECK-LABEL: @uge_umin2(
+; CHECK-NEXT:    [[CMP2:%.*]] = icmp ule i32 %x, %y
+; CHECK-NEXT:    ret i1 [[CMP2]]
+;
+  %cmp1 = icmp ult i32 %y, %x
+  %sel = select i1 %cmp1, i32 %y, i32 %x
+  %cmp2 = icmp uge i32 %sel, %x
+  ret i1 %cmp2
+}
+
+; Disguise the icmp predicate by commuting the min op to the RHS.
+
+define i1 @uge_umin3(i32 %a, i32 %y) {
+; CHECK-LABEL: @uge_umin3(
+; CHECK-NEXT:    [[X:%.*]] = add i32 %a, 3
+; CHECK-NEXT:    [[CMP2:%.*]] = icmp ule i32 [[X]], %y
+; CHECK-NEXT:    ret i1 [[CMP2]]
+;
+  %x = add i32 %a, 3 ; thwart complexity-based canonicalization
+  %cmp1 = icmp ult i32 %x, %y
+  %sel = select i1 %cmp1, i32 %x, i32 %y
+  %cmp2 = icmp ule i32 %x, %sel
+  ret i1 %cmp2
+}
+
+; Commute min operands.
+
+define i1 @uge_umin4(i32 %a, i32 %y) {
+; CHECK-LABEL: @uge_umin4(
+; CHECK-NEXT:    [[X:%.*]] = add i32 %a, 3
+; CHECK-NEXT:    [[CMP2:%.*]] = icmp ule i32 [[X]], %y
+; CHECK-NEXT:    ret i1 [[CMP2]]
+;
+  %x = add i32 %a, 3 ; thwart complexity-based canonicalization
+  %cmp1 = icmp ult i32 %y, %x
+  %sel = select i1 %cmp1, i32 %y, i32 %x
+  %cmp2 = icmp ule i32 %x, %sel
+  ret i1 %cmp2
+}
+
+; umin(X, Y) != X --> X > Y
+
+define i1 @ne_umin1(i32 %x, i32 %y) {
+; CHECK-LABEL: @ne_umin1(
+; CHECK-NEXT:    [[CMP2:%.*]] = icmp ugt i32 %x, %y
+; CHECK-NEXT:    ret i1 [[CMP2]]
+;
+  %cmp1 = icmp ult i32 %x, %y
+  %sel = select i1 %cmp1, i32 %x, i32 %y
+  %cmp2 = icmp ne i32 %sel, %x
+  ret i1 %cmp2
+}
+
+; Commute min operands.
+
+define i1 @ne_umin2(i32 %x, i32 %y) {
+; CHECK-LABEL: @ne_umin2(
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp ult i32 %y, %x
+; CHECK-NEXT:    ret i1 [[CMP1]]
+;
+  %cmp1 = icmp ult i32 %y, %x
+  %sel = select i1 %cmp1, i32 %y, i32 %x
+  %cmp2 = icmp ne i32 %sel, %x
+  ret i1 %cmp2
+}
+
+; Disguise the icmp predicate by commuting the min op to the RHS.
+
+define i1 @ne_umin3(i32 %a, i32 %y) {
+; CHECK-LABEL: @ne_umin3(
+; CHECK-NEXT:    [[X:%.*]] = add i32 %a, 3
+; CHECK-NEXT:    [[CMP2:%.*]] = icmp ugt i32 [[X]], %y
+; CHECK-NEXT:    ret i1 [[CMP2]]
+;
+  %x = add i32 %a, 3 ; thwart complexity-based canonicalization
+  %cmp1 = icmp ult i32 %x, %y
+  %sel = select i1 %cmp1, i32 %x, i32 %y
+  %cmp2 = icmp ne i32 %x, %sel
+  ret i1 %cmp2
+}
+
+; Commute min operands.
+
+define i1 @ne_umin4(i32 %a, i32 %y) {
+; CHECK-LABEL: @ne_umin4(
+; CHECK-NEXT:    [[X:%.*]] = add i32 %a, 3
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp ugt i32 [[X]], %y
+; CHECK-NEXT:    ret i1 [[CMP1]]
+;
+  %x = add i32 %a, 3 ; thwart complexity-based canonicalization
+  %cmp1 = icmp ult i32 %y, %x
+  %sel = select i1 %cmp1, i32 %y, i32 %x
+  %cmp2 = icmp ne i32 %x, %sel
+  ret i1 %cmp2
+}
+
+; umin(X, Y) < X --> X > Y
+
+define i1 @ult_umin1(i32 %x, i32 %y) {
+; CHECK-LABEL: @ult_umin1(
+; CHECK-NEXT:    [[CMP2:%.*]] = icmp ugt i32 %x, %y
+; CHECK-NEXT:    ret i1 [[CMP2]]
+;
+  %cmp1 = icmp ult i32 %x, %y
+  %sel = select i1 %cmp1, i32 %x, i32 %y
+  %cmp2 = icmp ult i32 %sel, %x
+  ret i1 %cmp2
+}
+
+; Commute min operands.
+
+define i1 @ult_umin2(i32 %x, i32 %y) {
+; CHECK-LABEL: @ult_umin2(
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp ult i32 %y, %x
+; CHECK-NEXT:    ret i1 [[CMP1]]
+;
+  %cmp1 = icmp ult i32 %y, %x
+  %sel = select i1 %cmp1, i32 %y, i32 %x
+  %cmp2 = icmp ult i32 %sel, %x
+  ret i1 %cmp2
+}
+
+; Disguise the icmp predicate by commuting the min op to the RHS.
+
+define i1 @ult_umin3(i32 %a, i32 %y) {
+; CHECK-LABEL: @ult_umin3(
+; CHECK-NEXT:    [[X:%.*]] = add i32 %a, 3
+; CHECK-NEXT:    [[CMP2:%.*]] = icmp ugt i32 [[X]], %y
+; CHECK-NEXT:    ret i1 [[CMP2]]
+;
+  %x = add i32 %a, 3 ; thwart complexity-based canonicalization
+  %cmp1 = icmp ult i32 %x, %y
+  %sel = select i1 %cmp1, i32 %x, i32 %y
+  %cmp2 = icmp ugt i32 %x, %sel
+  ret i1 %cmp2
+}
+
+; Commute min operands.
+
+define i1 @ult_umin4(i32 %a, i32 %y) {
+; CHECK-LABEL: @ult_umin4(
+; CHECK-NEXT:    [[X:%.*]] = add i32 %a, 3
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp ugt i32 [[X]], %y
+; CHECK-NEXT:    ret i1 [[CMP1]]
+;
+  %x = add i32 %a, 3 ; thwart complexity-based canonicalization
+  %cmp1 = icmp ult i32 %y, %x
+  %sel = select i1 %cmp1, i32 %y, i32 %x
+  %cmp2 = icmp ugt i32 %x, %sel
+  ret i1 %cmp2
+}
+

Added: llvm/trunk/test/Transforms/InstCombine/unavailable-debug.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/unavailable-debug.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/unavailable-debug.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/unavailable-debug.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,81 @@
+; RUN: opt < %s -instcombine -S | FileCheck %s
+
+; Make sure to update the debug value after dead code elimination.
+; CHECK: %call = call signext i8 @b(i32 6), !dbg !39
+; CHECK-NEXT: call void @llvm.dbg.value(metadata i32 undef, metadata !30, metadata !DIExpression()), !dbg !38
+
+ at e = common local_unnamed_addr global i8 0, align 1, !dbg !0
+ at c = common local_unnamed_addr global i32 0, align 4, !dbg !6
+ at d = common local_unnamed_addr global i32 0, align 4, !dbg !10
+
+define signext i8 @b(i32 %f) local_unnamed_addr #0 !dbg !18 {
+entry:
+  call void @llvm.dbg.value(metadata i32 %f, metadata !22, metadata !DIExpression()), !dbg !23
+  %conv = trunc i32 %f to i8, !dbg !24
+  ret i8 %conv, !dbg !25
+}
+
+define i32 @main() local_unnamed_addr #0 !dbg !26 {
+entry:
+  %0 = load i8, i8* @e, align 1, !dbg !31, !tbaa !32
+  %conv = sext i8 %0 to i32, !dbg !31
+  store i32 %conv, i32* @c, align 4, !dbg !35, !tbaa !36
+  call void @llvm.dbg.value(metadata i32 -1372423381, metadata !30, metadata !DIExpression()), !dbg !38
+  %call = call signext i8 @b(i32 6), !dbg !39
+  %conv1 = sext i8 %call to i32, !dbg !39
+  call void @llvm.dbg.value(metadata i32 %conv1, metadata !30, metadata !DIExpression()), !dbg !38
+  %1 = load i32, i32* @d, align 4, !dbg !40, !tbaa !36
+  %call2 = call i32 (...) @optimize_me_not(), !dbg !41
+  ret i32 0, !dbg !42
+}
+
+declare i32 @optimize_me_not(...) local_unnamed_addr #1
+declare void @llvm.dbg.value(metadata, metadata, metadata) #2
+
+!llvm.dbg.cu = !{!2}
+!llvm.module.flags = !{!13, !14, !15, !16}
+!llvm.ident = !{!17}
+
+!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression())
+!1 = distinct !DIGlobalVariable(name: "e", scope: !2, file: !3, line: 3, type: !12, isLocal: false, isDefinition: true)
+!2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, producer: "clang version 9.0.0 (https://github.com/llvm/llvm-project b306ef12f046353ea5bda4b3b77759e57909a0db)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !5, nameTableKind: GNU)
+!3 = !DIFile(filename: "a.c", directory: "/Users/davide/llvm/build/bin")
+!4 = !{}
+!5 = !{!6, !10, !0}
+!6 = !DIGlobalVariableExpression(var: !7, expr: !DIExpression())
+!7 = distinct !DIGlobalVariable(name: "c", scope: !2, file: !3, line: 2, type: !8, isLocal: false, isDefinition: true)
+!8 = !DIDerivedType(tag: DW_TAG_typedef, name: "a", file: !3, line: 1, baseType: !9)
+!9 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!10 = !DIGlobalVariableExpression(var: !11, expr: !DIExpression())
+!11 = distinct !DIGlobalVariable(name: "d", scope: !2, file: !3, line: 2, type: !8, isLocal: false, isDefinition: true)
+!12 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char)
+!13 = !{i32 2, !"Dwarf Version", i32 4}
+!14 = !{i32 2, !"Debug Info Version", i32 3}
+!15 = !{i32 1, !"wchar_size", i32 4}
+!16 = !{i32 7, !"PIC Level", i32 2}
+!17 = !{!"clang version 9.0.0 (https://github.com/llvm/llvm-project b306ef12f046353ea5bda4b3b77759e57909a0db)"}
+!18 = distinct !DISubprogram(name: "b", scope: !3, file: !3, line: 4, type: !19, scopeLine: 4, flags: DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !2, retainedNodes: !21)
+!19 = !DISubroutineType(types: !20)
+!20 = !{!12, !9}
+!21 = !{!22}
+!22 = !DILocalVariable(name: "f", arg: 1, scope: !18, file: !3, line: 4, type: !9)
+!23 = !DILocation(line: 4, column: 9, scope: !18)
+!24 = !DILocation(line: 4, column: 21, scope: !18)
+!25 = !DILocation(line: 4, column: 14, scope: !18)
+!26 = distinct !DISubprogram(name: "main", scope: !3, file: !3, line: 5, type: !27, scopeLine: 5, flags: DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !2, retainedNodes: !29)
+!27 = !DISubroutineType(types: !28)
+!28 = !{!9}
+!29 = !{!30}
+!30 = !DILocalVariable(name: "l_1499", scope: !26, file: !3, line: 7, type: !8)
+!31 = !DILocation(line: 6, column: 7, scope: !26)
+!32 = !{!33, !33, i64 0}
+!33 = !{!"omnipotent char", !34, i64 0}
+!34 = !{!"Simple C/C++ TBAA"}
+!35 = !DILocation(line: 6, column: 5, scope: !26)
+!36 = !{!37, !37, i64 0}
+!37 = !{!"int", !33, i64 0}
+!38 = !DILocation(line: 7, column: 5, scope: !26)
+!39 = !DILocation(line: 8, column: 12, scope: !26)
+!40 = !DILocation(line: 9, column: 11, scope: !26)
+!41 = !DILocation(line: 10, column: 3, scope: !26)
+!42 = !DILocation(line: 11, column: 1, scope: !26)

Added: llvm/trunk/test/Transforms/InstCombine/unfold-masked-merge-with-const-mask-scalar.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/unfold-masked-merge-with-const-mask-scalar.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/unfold-masked-merge-with-const-mask-scalar.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/unfold-masked-merge-with-const-mask-scalar.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,289 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt < %s -instcombine -S | FileCheck %s
+
+; If we have a masked merge, in the form of: (M is constant)
+;   ((x ^ y) & M) ^ y
+; Unfold it to
+;   (x & M) | (y & ~M)
+
+define i4 @scalar0 (i4 %x, i4 %y) {
+; CHECK-LABEL: @scalar0(
+; CHECK-NEXT:    [[TMP1:%.*]] = and i4 [[X:%.*]], 1
+; CHECK-NEXT:    [[TMP2:%.*]] = and i4 [[Y:%.*]], -2
+; CHECK-NEXT:    [[R:%.*]] = or i4 [[TMP1]], [[TMP2]]
+; CHECK-NEXT:    ret i4 [[R]]
+;
+  %n0 = xor i4 %x, %y
+  %n1 = and i4 %n0, 1
+  %r  = xor i4 %n1, %y
+  ret i4 %r
+}
+
+define i4 @scalar1 (i4 %x, i4 %y) {
+; CHECK-LABEL: @scalar1(
+; CHECK-NEXT:    [[TMP1:%.*]] = and i4 [[X:%.*]], -2
+; CHECK-NEXT:    [[TMP2:%.*]] = and i4 [[Y:%.*]], 1
+; CHECK-NEXT:    [[R:%.*]] = or i4 [[TMP1]], [[TMP2]]
+; CHECK-NEXT:    ret i4 [[R]]
+;
+  %n0 = xor i4 %x, %y
+  %n1 = and i4 %n0, -2
+  %r  = xor i4 %n1, %y
+  ret i4 %r
+}
+
+; ============================================================================ ;
+; Various cases with %x and/or %y being a constant
+; ============================================================================ ;
+
+define i4 @in_constant_varx_mone(i4 %x, i4 %mask) {
+; CHECK-LABEL: @in_constant_varx_mone(
+; CHECK-NEXT:    [[R1:%.*]] = or i4 [[X:%.*]], -2
+; CHECK-NEXT:    ret i4 [[R1]]
+;
+  %n0 = xor i4 %x, -1 ; %x
+  %n1 = and i4 %n0, 1
+  %r = xor i4 %n1, -1
+  ret i4 %r
+}
+
+define i4 @in_constant_varx_14(i4 %x, i4 %mask) {
+; CHECK-LABEL: @in_constant_varx_14(
+; CHECK-NEXT:    [[R1:%.*]] = or i4 [[X:%.*]], -2
+; CHECK-NEXT:    ret i4 [[R1]]
+;
+  %n0 = xor i4 %x, 14 ; %x
+  %n1 = and i4 %n0, 1
+  %r = xor i4 %n1, 14
+  ret i4 %r
+}
+
+define i4 @in_constant_mone_vary(i4 %y, i4 %mask) {
+; CHECK-LABEL: @in_constant_mone_vary(
+; CHECK-NEXT:    [[N0:%.*]] = and i4 [[Y:%.*]], 1
+; CHECK-NEXT:    [[N1:%.*]] = xor i4 [[N0]], 1
+; CHECK-NEXT:    [[R:%.*]] = xor i4 [[N1]], [[Y]]
+; CHECK-NEXT:    ret i4 [[R]]
+;
+  %n0 = xor i4 %y, -1 ; %x
+  %n1 = and i4 %n0, 1
+  %r = xor i4 %n1, %y
+  ret i4 %r
+}
+
+define i4 @in_constant_14_vary(i4 %y, i4 %mask) {
+; CHECK-LABEL: @in_constant_14_vary(
+; CHECK-NEXT:    [[R:%.*]] = and i4 [[Y:%.*]], -2
+; CHECK-NEXT:    ret i4 [[R]]
+;
+  %n0 = xor i4 %y, 14 ; %x
+  %n1 = and i4 %n0, 1
+  %r = xor i4 %n1, %y
+  ret i4 %r
+}
+
+; ============================================================================ ;
+; Commutativity
+; ============================================================================ ;
+
+; Used to make sure that the IR complexity sorting does not interfere.
+declare i4 @gen4()
+
+define i4 @c_1_0_0 (i4 %x, i4 %y) {
+; CHECK-LABEL: @c_1_0_0(
+; CHECK-NEXT:    [[TMP1:%.*]] = and i4 [[X:%.*]], -2
+; CHECK-NEXT:    [[TMP2:%.*]] = and i4 [[Y:%.*]], 1
+; CHECK-NEXT:    [[R:%.*]] = or i4 [[TMP1]], [[TMP2]]
+; CHECK-NEXT:    ret i4 [[R]]
+;
+  %n0 = xor i4 %y, %x ; swapped order
+  %n1 = and i4 %n0, -2
+  %r  = xor i4 %n1, %y
+  ret i4 %r
+}
+
+define i4 @c_0_1_0 (i4 %x, i4 %y) {
+; CHECK-LABEL: @c_0_1_0(
+; CHECK-NEXT:    [[TMP1:%.*]] = and i4 [[Y:%.*]], -2
+; CHECK-NEXT:    [[TMP2:%.*]] = and i4 [[X:%.*]], 1
+; CHECK-NEXT:    [[R:%.*]] = or i4 [[TMP1]], [[TMP2]]
+; CHECK-NEXT:    ret i4 [[R]]
+;
+  %n0 = xor i4 %x, %y
+  %n1 = and i4 %n0, -2
+  %r  = xor i4 %n1, %x ; %x instead of %y
+  ret i4 %r
+}
+
+define i4 @c_0_0_1 () {
+; CHECK-LABEL: @c_0_0_1(
+; CHECK-NEXT:    [[X:%.*]] = call i4 @gen4()
+; CHECK-NEXT:    [[Y:%.*]] = call i4 @gen4()
+; CHECK-NEXT:    [[TMP1:%.*]] = and i4 [[X]], -2
+; CHECK-NEXT:    [[TMP2:%.*]] = and i4 [[Y]], 1
+; CHECK-NEXT:    [[R:%.*]] = or i4 [[TMP1]], [[TMP2]]
+; CHECK-NEXT:    ret i4 [[R]]
+;
+  %x  = call i4 @gen4()
+  %y  = call i4 @gen4()
+  %n0 = xor i4 %x, %y
+  %n1 = and i4 %n0, -2
+  %r  = xor i4 %y, %n1 ; swapped order
+  ret i4 %r
+}
+
+define i4 @c_1_1_0 (i4 %x, i4 %y) {
+; CHECK-LABEL: @c_1_1_0(
+; CHECK-NEXT:    [[TMP1:%.*]] = and i4 [[Y:%.*]], -2
+; CHECK-NEXT:    [[TMP2:%.*]] = and i4 [[X:%.*]], 1
+; CHECK-NEXT:    [[R:%.*]] = or i4 [[TMP1]], [[TMP2]]
+; CHECK-NEXT:    ret i4 [[R]]
+;
+  %n0 = xor i4 %y, %x ; swapped order
+  %n1 = and i4 %n0, -2
+  %r  = xor i4 %n1, %x ; %x instead of %y
+  ret i4 %r
+}
+
+define i4 @c_1_0_1 (i4 %x) {
+; CHECK-LABEL: @c_1_0_1(
+; CHECK-NEXT:    [[Y:%.*]] = call i4 @gen4()
+; CHECK-NEXT:    [[TMP1:%.*]] = and i4 [[X:%.*]], -2
+; CHECK-NEXT:    [[TMP2:%.*]] = and i4 [[Y]], 1
+; CHECK-NEXT:    [[R:%.*]] = or i4 [[TMP1]], [[TMP2]]
+; CHECK-NEXT:    ret i4 [[R]]
+;
+  %y  = call i4 @gen4()
+  %n0 = xor i4 %y, %x ; swapped order
+  %n1 = and i4 %n0, -2
+  %r  = xor i4 %y, %n1 ; swapped order
+  ret i4 %r
+}
+
+define i4 @c_0_1_1 (i4 %y) {
+; CHECK-LABEL: @c_0_1_1(
+; CHECK-NEXT:    [[X:%.*]] = call i4 @gen4()
+; CHECK-NEXT:    [[TMP1:%.*]] = and i4 [[Y:%.*]], -2
+; CHECK-NEXT:    [[TMP2:%.*]] = and i4 [[X]], 1
+; CHECK-NEXT:    [[R:%.*]] = or i4 [[TMP1]], [[TMP2]]
+; CHECK-NEXT:    ret i4 [[R]]
+;
+  %x  = call i4 @gen4()
+  %n0 = xor i4 %x, %y
+  %n1 = and i4 %n0, -2
+  %r  = xor i4 %x, %n1 ; swapped order, %x instead of %y
+  ret i4 %r
+}
+
+define i4 @c_1_1_1 () {
+; CHECK-LABEL: @c_1_1_1(
+; CHECK-NEXT:    [[X:%.*]] = call i4 @gen4()
+; CHECK-NEXT:    [[Y:%.*]] = call i4 @gen4()
+; CHECK-NEXT:    [[TMP1:%.*]] = and i4 [[Y]], -2
+; CHECK-NEXT:    [[TMP2:%.*]] = and i4 [[X]], 1
+; CHECK-NEXT:    [[R:%.*]] = or i4 [[TMP1]], [[TMP2]]
+; CHECK-NEXT:    ret i4 [[R]]
+;
+  %x  = call i4 @gen4()
+  %y  = call i4 @gen4()
+  %n0 = xor i4 %y, %x ; swapped order
+  %n1 = and i4 %n0, -2
+  %r  = xor i4 %x, %n1 ; swapped order, %x instead of %y
+  ret i4 %r
+}
+
+define i4 @commutativity_constant_14_vary(i4 %y, i4 %mask) {
+; CHECK-LABEL: @commutativity_constant_14_vary(
+; CHECK-NEXT:    [[R:%.*]] = and i4 [[Y:%.*]], -2
+; CHECK-NEXT:    ret i4 [[R]]
+;
+  %n0 = xor i4 %y, 14 ; %x
+  %n1 = and i4 %n0, 1
+  %r = xor i4 %y, %n1 ; swapped
+  ret i4 %r
+}
+
+; ============================================================================ ;
+; Negative tests. Should not be folded.
+; ============================================================================ ;
+
+; One use only.
+
+declare void @use4(i4)
+
+define i4 @n_oneuse_D (i4 %x, i4 %y) {
+; CHECK-LABEL: @n_oneuse_D(
+; CHECK-NEXT:    [[N0:%.*]] = xor i4 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    [[N1:%.*]] = and i4 [[N0]], -2
+; CHECK-NEXT:    [[R:%.*]] = xor i4 [[N1]], [[Y]]
+; CHECK-NEXT:    call void @use4(i4 [[N0]])
+; CHECK-NEXT:    ret i4 [[R]]
+;
+  %n0 = xor i4 %x, %y ; two uses of %n0, which is going to be replaced
+  %n1 = and i4 %n0, -2
+  %r  = xor i4 %n1, %y
+  call void @use4(i4 %n0)
+  ret i4 %r
+}
+
+define i4 @n_oneuse_A (i4 %x, i4 %y) {
+; CHECK-LABEL: @n_oneuse_A(
+; CHECK-NEXT:    [[N0:%.*]] = xor i4 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    [[N1:%.*]] = and i4 [[N0]], -2
+; CHECK-NEXT:    [[R:%.*]] = xor i4 [[N1]], [[Y]]
+; CHECK-NEXT:    call void @use4(i4 [[N1]])
+; CHECK-NEXT:    ret i4 [[R]]
+;
+  %n0 = xor i4 %x, %y
+  %n1 = and i4 %n0, -2 ; two uses of %n1, which is going to be replaced
+  %r  = xor i4 %n1, %y
+  call void @use4(i4 %n1)
+  ret i4 %r
+}
+
+define i4 @n_oneuse_AD (i4 %x, i4 %y) {
+; CHECK-LABEL: @n_oneuse_AD(
+; CHECK-NEXT:    [[N0:%.*]] = xor i4 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    [[N1:%.*]] = and i4 [[N0]], -2
+; CHECK-NEXT:    [[R:%.*]] = xor i4 [[N1]], [[Y]]
+; CHECK-NEXT:    call void @use4(i4 [[N0]])
+; CHECK-NEXT:    call void @use4(i4 [[N1]])
+; CHECK-NEXT:    ret i4 [[R]]
+;
+  %n0 = xor i4 %x, %y
+  %n1 = and i4 %n0, -2 ; two uses of %n1, which is going to be replaced
+  %r  = xor i4 %n1, %y
+  call void @use4(i4 %n0)
+  call void @use4(i4 %n1)
+  ret i4 %r
+}
+
+; Mask is not constant
+
+define i4 @n_var_mask (i4 %x, i4 %y, i4 %m) {
+; CHECK-LABEL: @n_var_mask(
+; CHECK-NEXT:    [[N0:%.*]] = xor i4 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    [[N1:%.*]] = and i4 [[N0]], [[M:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = xor i4 [[N1]], [[Y]]
+; CHECK-NEXT:    ret i4 [[R]]
+;
+  %n0 = xor i4 %x, %y
+  %n1 = and i4 %n0, %m
+  %r  = xor i4 %n1, %y
+  ret i4 %r
+}
+
+; Some third variable is used
+
+define i4 @n_third_var (i4 %x, i4 %y, i4 %z) {
+; CHECK-LABEL: @n_third_var(
+; CHECK-NEXT:    [[N0:%.*]] = xor i4 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    [[N1:%.*]] = and i4 [[N0]], -2
+; CHECK-NEXT:    [[R:%.*]] = xor i4 [[N1]], [[Z:%.*]]
+; CHECK-NEXT:    ret i4 [[R]]
+;
+  %n0 = xor i4 %x, %y
+  %n1 = and i4 %n0, -2
+  %r  = xor i4 %n1, %z ; not %x or %y
+  ret i4 %r
+}

Added: llvm/trunk/test/Transforms/InstCombine/unfold-masked-merge-with-const-mask-vector.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/unfold-masked-merge-with-const-mask-vector.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/unfold-masked-merge-with-const-mask-vector.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/unfold-masked-merge-with-const-mask-vector.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
+
+; If we have a masked merge, in the form of: (M is constant)
+;   ((x ^ y) & M) ^ y
+; Unfold it to
+;   (x & M) | (y & ~M)
+
+define <2 x i4> @splat (<2 x i4> %x, <2 x i4> %y) {
+; CHECK-LABEL: @splat(
+; CHECK-NEXT:    [[TMP1:%.*]] = and <2 x i4> [[X:%.*]], <i4 -2, i4 -2>
+; CHECK-NEXT:    [[TMP2:%.*]] = and <2 x i4> [[Y:%.*]], <i4 1, i4 1>
+; CHECK-NEXT:    [[R:%.*]] = or <2 x i4> [[TMP1]], [[TMP2]]
+; CHECK-NEXT:    ret <2 x i4> [[R]]
+;
+  %n0 = xor <2 x i4> %x, %y
+  %n1 = and <2 x i4> %n0, <i4 -2, i4 -2>
+  %r  = xor <2 x i4> %n1, %y
+  ret <2 x i4> %r
+}
+
+define <3 x i4> @splat_undef (<3 x i4> %x, <3 x i4> %y) {
+; CHECK-LABEL: @splat_undef(
+; CHECK-NEXT:    [[TMP1:%.*]] = and <3 x i4> [[X:%.*]], <i4 -2, i4 undef, i4 -2>
+; CHECK-NEXT:    [[TMP2:%.*]] = and <3 x i4> [[Y:%.*]], <i4 1, i4 undef, i4 1>
+; CHECK-NEXT:    [[R:%.*]] = or <3 x i4> [[TMP1]], [[TMP2]]
+; CHECK-NEXT:    ret <3 x i4> [[R]]
+;
+  %n0 = xor <3 x i4> %x, %y
+  %n1 = and <3 x i4> %n0, <i4 -2, i4 undef, i4 -2>
+  %r  = xor <3 x i4> %n1, %y
+  ret <3 x i4> %r
+}
+
+define <2 x i4> @nonsplat (<2 x i4> %x, <2 x i4> %y) {
+; CHECK-LABEL: @nonsplat(
+; CHECK-NEXT:    [[TMP1:%.*]] = and <2 x i4> [[X:%.*]], <i4 -2, i4 1>
+; CHECK-NEXT:    [[TMP2:%.*]] = and <2 x i4> [[Y:%.*]], <i4 1, i4 -2>
+; CHECK-NEXT:    [[R:%.*]] = or <2 x i4> [[TMP1]], [[TMP2]]
+; CHECK-NEXT:    ret <2 x i4> [[R]]
+;
+  %n0 = xor <2 x i4> %x, %y
+  %n1 = and <2 x i4> %n0, <i4 -2, i4 1>
+  %r  = xor <2 x i4> %n1, %y
+  ret <2 x i4> %r
+}
+
+; ============================================================================ ;
+; Various cases with %x and/or %y being a constant
+; ============================================================================ ;
+
+define <2 x i4> @in_constant_varx_mone(<2 x i4> %x, <2 x i4> %mask) {
+; CHECK-LABEL: @in_constant_varx_mone(
+; CHECK-NEXT:    [[R1:%.*]] = or <2 x i4> [[X:%.*]], <i4 -2, i4 -2>
+; CHECK-NEXT:    ret <2 x i4> [[R1]]
+;
+  %n0 = xor <2 x i4> %x, <i4 -1, i4 -1> ; %x
+  %n1 = and <2 x i4> %n0, <i4 1, i4 1>
+  %r = xor <2 x i4> %n1, <i4 -1, i4 -1>
+  ret <2 x i4> %r
+}
+
+define <2 x i4> @in_constant_varx_14(<2 x i4> %x, <2 x i4> %mask) {
+; CHECK-LABEL: @in_constant_varx_14(
+; CHECK-NEXT:    [[R1:%.*]] = or <2 x i4> [[X:%.*]], <i4 -2, i4 -2>
+; CHECK-NEXT:    ret <2 x i4> [[R1]]
+;
+  %n0 = xor <2 x i4> %x, <i4 14, i4 14> ; %x
+  %n1 = and <2 x i4> %n0, <i4 1, i4 1>
+  %r = xor <2 x i4> %n1, <i4 14, i4 14>
+  ret <2 x i4> %r
+}
+
+define <2 x i4> @in_constant_varx_14_nonsplat(<2 x i4> %x, <2 x i4> %mask) {
+; CHECK-LABEL: @in_constant_varx_14_nonsplat(
+; CHECK-NEXT:    [[TMP1:%.*]] = and <2 x i4> [[X:%.*]], <i4 1, i4 1>
+; CHECK-NEXT:    [[R:%.*]] = or <2 x i4> [[TMP1]], <i4 -2, i4 6>
+; CHECK-NEXT:    ret <2 x i4> [[R]]
+;
+  %n0 = xor <2 x i4> %x, <i4 14, i4 7> ; %x
+  %n1 = and <2 x i4> %n0, <i4 1, i4 1>
+  %r = xor <2 x i4> %n1, <i4 14, i4 7>
+  ret <2 x i4> %r
+}
+
+define <3 x i4> @in_constant_varx_14_undef(<3 x i4> %x, <3 x i4> %mask) {
+; CHECK-LABEL: @in_constant_varx_14_undef(
+; CHECK-NEXT:    [[TMP1:%.*]] = and <3 x i4> [[X:%.*]], <i4 1, i4 undef, i4 1>
+; CHECK-NEXT:    [[R:%.*]] = or <3 x i4> [[TMP1]], <i4 -2, i4 undef, i4 6>
+; CHECK-NEXT:    ret <3 x i4> [[R]]
+;
+  %n0 = xor <3 x i4> %x, <i4 14, i4 undef, i4 7> ; %x
+  %n1 = and <3 x i4> %n0, <i4 1, i4 undef, i4 1>
+  %r = xor <3 x i4> %n1, <i4 14, i4 undef, i4 7>
+  ret <3 x i4> %r
+}
+
+define <2 x i4> @in_constant_mone_vary(<2 x i4> %y, <2 x i4> %mask) {
+; CHECK-LABEL: @in_constant_mone_vary(
+; CHECK-NEXT:    [[N0:%.*]] = and <2 x i4> [[Y:%.*]], <i4 1, i4 1>
+; CHECK-NEXT:    [[N1:%.*]] = xor <2 x i4> [[N0]], <i4 1, i4 1>
+; CHECK-NEXT:    [[R:%.*]] = xor <2 x i4> [[N1]], [[Y]]
+; CHECK-NEXT:    ret <2 x i4> [[R]]
+;
+  %n0 = xor <2 x i4> %y, <i4 -1, i4 -1> ; %x
+  %n1 = and <2 x i4> %n0, <i4 1, i4 1>
+  %r = xor <2 x i4> %n1, %y
+  ret <2 x i4> %r
+}
+
+define <2 x i4> @in_constant_14_vary(<2 x i4> %y, <2 x i4> %mask) {
+; CHECK-LABEL: @in_constant_14_vary(
+; CHECK-NEXT:    [[R:%.*]] = and <2 x i4> [[Y:%.*]], <i4 -2, i4 -2>
+; CHECK-NEXT:    ret <2 x i4> [[R]]
+;
+  %n0 = xor <2 x i4> %y, <i4 14, i4 14> ; %x
+  %n1 = and <2 x i4> %n0, <i4 1, i4 1>
+  %r = xor <2 x i4> %n1, %y
+  ret <2 x i4> %r
+}
+
+define <2 x i4> @in_constant_14_vary_nonsplat(<2 x i4> %y, <2 x i4> %mask) {
+; CHECK-LABEL: @in_constant_14_vary_nonsplat(
+; CHECK-NEXT:    [[TMP1:%.*]] = and <2 x i4> [[Y:%.*]], <i4 -2, i4 -2>
+; CHECK-NEXT:    [[R:%.*]] = or <2 x i4> [[TMP1]], <i4 0, i4 1>
+; CHECK-NEXT:    ret <2 x i4> [[R]]
+;
+  %n0 = xor <2 x i4> %y, <i4 14, i4 7> ; %x
+  %n1 = and <2 x i4> %n0, <i4 1, i4 1>
+  %r = xor <2 x i4> %n1, %y
+  ret <2 x i4> %r
+}
+
+define <3 x i4> @in_constant_14_vary_undef(<3 x i4> %y, <3 x i4> %mask) {
+; CHECK-LABEL: @in_constant_14_vary_undef(
+; CHECK-NEXT:    [[TMP1:%.*]] = and <3 x i4> [[Y:%.*]], <i4 -2, i4 undef, i4 -2>
+; CHECK-NEXT:    [[R:%.*]] = or <3 x i4> [[TMP1]], <i4 0, i4 undef, i4 1>
+; CHECK-NEXT:    ret <3 x i4> [[R]]
+;
+  %n0 = xor <3 x i4> %y, <i4 14, i4 undef, i4 7> ; %x
+  %n1 = and <3 x i4> %n0, <i4 1, i4 undef, i4 1>
+  %r = xor <3 x i4> %n1, %y
+  ret <3 x i4> %r
+}
+
+; ============================================================================ ;
+; Commutativity
+; ============================================================================ ;
+
+; Used to make sure that the IR complexity sorting does not interfere.
+declare <2 x i4> @gen4()
+
+define <2 x i4> @c_1_0_0 (<2 x i4> %x, <2 x i4> %y) {
+; CHECK-LABEL: @c_1_0_0(
+; CHECK-NEXT:    [[TMP1:%.*]] = and <2 x i4> [[X:%.*]], <i4 -2, i4 -2>
+; CHECK-NEXT:    [[TMP2:%.*]] = and <2 x i4> [[Y:%.*]], <i4 1, i4 1>
+; CHECK-NEXT:    [[R:%.*]] = or <2 x i4> [[TMP1]], [[TMP2]]
+; CHECK-NEXT:    ret <2 x i4> [[R]]
+;
+  %n0 = xor <2 x i4> %y, %x ; swapped order
+  %n1 = and <2 x i4> %n0, <i4 -2, i4 -2>
+  %r  = xor <2 x i4> %n1, %y
+  ret <2 x i4> %r
+}
+
+define <2 x i4> @c_0_1_0 (<2 x i4> %x, <2 x i4> %y) {
+; CHECK-LABEL: @c_0_1_0(
+; CHECK-NEXT:    [[TMP1:%.*]] = and <2 x i4> [[Y:%.*]], <i4 -2, i4 -2>
+; CHECK-NEXT:    [[TMP2:%.*]] = and <2 x i4> [[X:%.*]], <i4 1, i4 1>
+; CHECK-NEXT:    [[R:%.*]] = or <2 x i4> [[TMP1]], [[TMP2]]
+; CHECK-NEXT:    ret <2 x i4> [[R]]
+;
+  %n0 = xor <2 x i4> %x, %y
+  %n1 = and <2 x i4> %n0, <i4 -2, i4 -2>
+  %r  = xor <2 x i4> %n1, %x ; %x instead of %y
+  ret <2 x i4> %r
+}
+
+define <2 x i4> @c_0_0_1 () {
+; CHECK-LABEL: @c_0_0_1(
+; CHECK-NEXT:    [[X:%.*]] = call <2 x i4> @gen4()
+; CHECK-NEXT:    [[Y:%.*]] = call <2 x i4> @gen4()
+; CHECK-NEXT:    [[TMP1:%.*]] = and <2 x i4> [[X]], <i4 -2, i4 -2>
+; CHECK-NEXT:    [[TMP2:%.*]] = and <2 x i4> [[Y]], <i4 1, i4 1>
+; CHECK-NEXT:    [[R:%.*]] = or <2 x i4> [[TMP1]], [[TMP2]]
+; CHECK-NEXT:    ret <2 x i4> [[R]]
+;
+  %x  = call <2 x i4> @gen4()
+  %y  = call <2 x i4> @gen4()
+  %n0 = xor <2 x i4> %x, %y
+  %n1 = and <2 x i4> %n0, <i4 -2, i4 -2>
+  %r  = xor <2 x i4> %y, %n1 ; swapped order
+  ret <2 x i4> %r
+}
+
+define <2 x i4> @c_1_1_0 (<2 x i4> %x, <2 x i4> %y) {
+; CHECK-LABEL: @c_1_1_0(
+; CHECK-NEXT:    [[TMP1:%.*]] = and <2 x i4> [[Y:%.*]], <i4 -2, i4 -2>
+; CHECK-NEXT:    [[TMP2:%.*]] = and <2 x i4> [[X:%.*]], <i4 1, i4 1>
+; CHECK-NEXT:    [[R:%.*]] = or <2 x i4> [[TMP1]], [[TMP2]]
+; CHECK-NEXT:    ret <2 x i4> [[R]]
+;
+  %n0 = xor <2 x i4> %y, %x ; swapped order
+  %n1 = and <2 x i4> %n0, <i4 -2, i4 -2>
+  %r  = xor <2 x i4> %n1, %x ; %x instead of %y
+  ret <2 x i4> %r
+}
+
+define <2 x i4> @c_1_0_1 (<2 x i4> %x) {
+; CHECK-LABEL: @c_1_0_1(
+; CHECK-NEXT:    [[Y:%.*]] = call <2 x i4> @gen4()
+; CHECK-NEXT:    [[TMP1:%.*]] = and <2 x i4> [[X:%.*]], <i4 -2, i4 -2>
+; CHECK-NEXT:    [[TMP2:%.*]] = and <2 x i4> [[Y]], <i4 1, i4 1>
+; CHECK-NEXT:    [[R:%.*]] = or <2 x i4> [[TMP1]], [[TMP2]]
+; CHECK-NEXT:    ret <2 x i4> [[R]]
+;
+  %y  = call <2 x i4> @gen4()
+  %n0 = xor <2 x i4> %y, %x ; swapped order
+  %n1 = and <2 x i4> %n0, <i4 -2, i4 -2>
+  %r  = xor <2 x i4> %y, %n1 ; swapped order
+  ret <2 x i4> %r
+}
+
+define <2 x i4> @c_0_1_1 (<2 x i4> %y) {
+; CHECK-LABEL: @c_0_1_1(
+; CHECK-NEXT:    [[X:%.*]] = call <2 x i4> @gen4()
+; CHECK-NEXT:    [[TMP1:%.*]] = and <2 x i4> [[Y:%.*]], <i4 -2, i4 -2>
+; CHECK-NEXT:    [[TMP2:%.*]] = and <2 x i4> [[X]], <i4 1, i4 1>
+; CHECK-NEXT:    [[R:%.*]] = or <2 x i4> [[TMP1]], [[TMP2]]
+; CHECK-NEXT:    ret <2 x i4> [[R]]
+;
+  %x  = call <2 x i4> @gen4()
+  %n0 = xor <2 x i4> %x, %y
+  %n1 = and <2 x i4> %n0, <i4 -2, i4 -2>
+  %r  = xor <2 x i4> %x, %n1 ; swapped order, %x instead of %y
+  ret <2 x i4> %r
+}
+
+define <2 x i4> @c_1_1_1 () {
+; CHECK-LABEL: @c_1_1_1(
+; CHECK-NEXT:    [[X:%.*]] = call <2 x i4> @gen4()
+; CHECK-NEXT:    [[Y:%.*]] = call <2 x i4> @gen4()
+; CHECK-NEXT:    [[TMP1:%.*]] = and <2 x i4> [[Y]], <i4 -2, i4 -2>
+; CHECK-NEXT:    [[TMP2:%.*]] = and <2 x i4> [[X]], <i4 1, i4 1>
+; CHECK-NEXT:    [[R:%.*]] = or <2 x i4> [[TMP1]], [[TMP2]]
+; CHECK-NEXT:    ret <2 x i4> [[R]]
+;
+  %x  = call <2 x i4> @gen4()
+  %y  = call <2 x i4> @gen4()
+  %n0 = xor <2 x i4> %y, %x ; swapped order
+  %n1 = and <2 x i4> %n0, <i4 -2, i4 -2>
+  %r  = xor <2 x i4> %x, %n1 ; swapped order, %x instead of %y
+  ret <2 x i4> %r
+}
+
+define <2 x i4> @commutativity_constant_14_vary(<2 x i4> %y, <2 x i4> %mask) {
+; CHECK-LABEL: @commutativity_constant_14_vary(
+; CHECK-NEXT:    [[R:%.*]] = and <2 x i4> [[Y:%.*]], <i4 -2, i4 -2>
+; CHECK-NEXT:    ret <2 x i4> [[R]]
+;
+  %n0 = xor <2 x i4> %y, <i4 14, i4 14> ; %x
+  %n1 = and <2 x i4> %n0, <i4 1, i4 1>
+  %r = xor <2 x i4> %y, %n1 ; swapped
+  ret <2 x i4> %r
+}
+
+; ============================================================================ ;
+; Negative tests. Should not be folded.
+; ============================================================================ ;
+
+; One use only.
+
+declare void @use4(<2 x i4>)
+
+define <2 x i4> @n_oneuse_D (<2 x i4> %x, <2 x i4> %y) {
+; CHECK-LABEL: @n_oneuse_D(
+; CHECK-NEXT:    [[N0:%.*]] = xor <2 x i4> [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    [[N1:%.*]] = and <2 x i4> [[N0]], <i4 -2, i4 -2>
+; CHECK-NEXT:    [[R:%.*]] = xor <2 x i4> [[N1]], [[Y]]
+; CHECK-NEXT:    call void @use4(<2 x i4> [[N0]])
+; CHECK-NEXT:    ret <2 x i4> [[R]]
+;
+  %n0 = xor <2 x i4> %x, %y ; two uses of %n0, which is going to be replaced
+  %n1 = and <2 x i4> %n0, <i4 -2, i4 -2>
+  %r  = xor <2 x i4> %n1, %y
+  call void @use4(<2 x i4> %n0)
+  ret <2 x i4> %r
+}
+
+define <2 x i4> @n_oneuse_A (<2 x i4> %x, <2 x i4> %y) {
+; CHECK-LABEL: @n_oneuse_A(
+; CHECK-NEXT:    [[N0:%.*]] = xor <2 x i4> [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    [[N1:%.*]] = and <2 x i4> [[N0]], <i4 -2, i4 -2>
+; CHECK-NEXT:    [[R:%.*]] = xor <2 x i4> [[N1]], [[Y]]
+; CHECK-NEXT:    call void @use4(<2 x i4> [[N1]])
+; CHECK-NEXT:    ret <2 x i4> [[R]]
+;
+  %n0 = xor <2 x i4> %x, %y
+  %n1 = and <2 x i4> %n0, <i4 -2, i4 -2> ; two uses of %n1, which is going to be replaced
+  %r  = xor <2 x i4> %n1, %y
+  call void @use4(<2 x i4> %n1)
+  ret <2 x i4> %r
+}
+
+define <2 x i4> @n_oneuse_AD (<2 x i4> %x, <2 x i4> %y) {
+; CHECK-LABEL: @n_oneuse_AD(
+; CHECK-NEXT:    [[N0:%.*]] = xor <2 x i4> [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    [[N1:%.*]] = and <2 x i4> [[N0]], <i4 -2, i4 -2>
+; CHECK-NEXT:    [[R:%.*]] = xor <2 x i4> [[N1]], [[Y]]
+; CHECK-NEXT:    call void @use4(<2 x i4> [[N0]])
+; CHECK-NEXT:    call void @use4(<2 x i4> [[N1]])
+; CHECK-NEXT:    ret <2 x i4> [[R]]
+;
+  %n0 = xor <2 x i4> %x, %y
+  %n1 = and <2 x i4> %n0, <i4 -2, i4 -2> ; two uses of %n1, which is going to be replaced
+  %r  = xor <2 x i4> %n1, %y
+  call void @use4(<2 x i4> %n0)
+  call void @use4(<2 x i4> %n1)
+  ret <2 x i4> %r
+}
+
+; Mask is not constant
+
+define <2 x i4> @n_var_mask (<2 x i4> %x, <2 x i4> %y, <2 x i4> %m) {
+; CHECK-LABEL: @n_var_mask(
+; CHECK-NEXT:    [[N0:%.*]] = xor <2 x i4> [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    [[N1:%.*]] = and <2 x i4> [[N0]], [[M:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = xor <2 x i4> [[N1]], [[Y]]
+; CHECK-NEXT:    ret <2 x i4> [[R]]
+;
+  %n0 = xor <2 x i4> %x, %y
+  %n1 = and <2 x i4> %n0, %m
+  %r  = xor <2 x i4> %n1, %y
+  ret <2 x i4> %r
+}
+
+; Some third variable is used
+
+define <2 x i4> @n_differenty(<2 x i4> %x, <2 x i4> %mask) {
+; CHECK-LABEL: @n_differenty(
+; CHECK-NEXT:    [[N0:%.*]] = xor <2 x i4> [[X:%.*]], <i4 -2, i4 7>
+; CHECK-NEXT:    [[N1:%.*]] = and <2 x i4> [[N0]], <i4 1, i4 1>
+; CHECK-NEXT:    [[R:%.*]] = xor <2 x i4> [[N1]], <i4 7, i4 -2>
+; CHECK-NEXT:    ret <2 x i4> [[R]]
+;
+  %n0 = xor <2 x i4> %x, <i4 14, i4 7> ; %x
+  %n1 = and <2 x i4> %n0, <i4 1, i4 1>
+  %r = xor <2 x i4> %n1, <i4 7, i4 14>
+  ret <2 x i4> %r
+}

Added: llvm/trunk/test/Transforms/InstCombine/unlocked-stdio-mingw.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/unlocked-stdio-mingw.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/unlocked-stdio-mingw.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/unlocked-stdio-mingw.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,23 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt < %s -instcombine -S -mtriple=x86_64-w64-mingw32 | FileCheck %s
+
+%struct._iobuf = type { i8*, i32, i8*, i32, i32, i32, i32, i8* }
+
+ at .str = private unnamed_addr constant [5 x i8] c"file\00", align 1
+ at .str.1 = private unnamed_addr constant [2 x i8] c"w\00", align 1
+
+; Check that this still uses the plain fputc instead of fputc_unlocked
+; for MinGW targets.
+define void @external_fputc_test() {
+; CHECK-LABEL: @external_fputc_test(
+; CHECK-NEXT:    [[CALL:%.*]] = call %struct._iobuf* @fopen(i8* getelementptr inbounds ([5 x i8], [5 x i8]* @.str, i64 0, i64 0), i8* getelementptr inbounds ([2 x i8], [2 x i8]* @.str.1, i64 0, i64 0))
+; CHECK-NEXT:    [[CALL1:%.*]] = call i32 @fputc(i32 99, %struct._iobuf* [[CALL]])
+; CHECK-NEXT:    ret void
+;
+  %call = call %struct._iobuf* @fopen(i8* getelementptr inbounds ([5 x i8], [5 x i8]* @.str, i64 0, i64 0), i8* getelementptr inbounds ([2 x i8], [2 x i8]* @.str.1, i64 0, i64 0))
+  %call1 = call i32 @fputc(i32 99, %struct._iobuf* %call)
+  ret void
+}
+
+declare %struct._iobuf* @fopen(i8*, i8*)
+declare i32 @fputc(i32, %struct._iobuf* nocapture)

Added: llvm/trunk/test/Transforms/InstCombine/unlocked-stdio.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/unlocked-stdio.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/unlocked-stdio.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/unlocked-stdio.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,224 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt < %s -instcombine -S -mtriple=x86_64-unknown-linux-gnu | FileCheck %s
+
+%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 .str = private unnamed_addr constant [5 x i8] c"file\00", align 1
+ at .str.1 = private unnamed_addr constant [2 x i8] c"w\00", align 1
+ at .str.2 = private unnamed_addr constant [4 x i8] c"str\00", align 1
+ at stdout = external global %struct._IO_FILE*, align 8
+ at global_file = common global %struct._IO_FILE* null, align 8
+
+define void @external_fgetc_test(%struct._IO_FILE* %f) {
+; CHECK-LABEL: @external_fgetc_test(
+; CHECK-NEXT:    [[CALL:%.*]] = call i32 @fgetc(%struct._IO_FILE* [[F:%.*]])
+; CHECK-NEXT:    ret void
+;
+  %call = call i32 @fgetc(%struct._IO_FILE* %f)
+  ret void
+}
+
+declare i32 @fgetc(%struct._IO_FILE* nocapture) #0
+
+define void @external_fgetc_test2() {
+; CHECK-LABEL: @external_fgetc_test2(
+; CHECK-NEXT:    [[CALL:%.*]] = call %struct._IO_FILE* @fopen(i8* getelementptr inbounds ([5 x i8], [5 x i8]* @.str, i64 0, i64 0), i8* getelementptr inbounds ([2 x i8], [2 x i8]* @.str.1, i64 0, i64 0))
+; CHECK-NEXT:    [[FPUTC_UNLOCKED:%.*]] = call i32 @fputc_unlocked(i32 99, %struct._IO_FILE* [[CALL]])
+; CHECK-NEXT:    ret void
+;
+  %call = call %struct._IO_FILE* @fopen(i8* getelementptr inbounds ([5 x i8], [5 x i8]* @.str, i64 0, i64 0), i8* getelementptr inbounds ([2 x i8], [2 x i8]* @.str.1, i64 0, i64 0))
+  %call1 = call i32 @fputc(i32 99, %struct._IO_FILE* %call)
+  ret void
+}
+
+declare %struct._IO_FILE* @fopen(i8*, i8*)
+declare i32 @fputc(i32, %struct._IO_FILE* nocapture) #0
+
+define internal void @fgetc_test() {
+; CHECK-LABEL: @fgetc_test(
+; CHECK-NEXT:    [[CALL:%.*]] = call %struct._IO_FILE* @fopen(i8* getelementptr inbounds ([5 x i8], [5 x i8]* @.str, i64 0, i64 0), i8* getelementptr inbounds ([2 x i8], [2 x i8]* @.str.1, i64 0, i64 0))
+; CHECK-NEXT:    [[FGETC_UNLOCKED:%.*]] = call i32 @fgetc_unlocked(%struct._IO_FILE* [[CALL]])
+; CHECK-NEXT:    ret void
+;
+  %call = call %struct._IO_FILE* @fopen(i8* getelementptr inbounds ([5 x i8], [5 x i8]* @.str, i64 0, i64 0), i8* getelementptr inbounds ([2 x i8], [2 x i8]* @.str.1, i64 0, i64 0))
+  %call1 = call i32 @fgetc(%struct._IO_FILE* %call)
+  ret void
+}
+
+define void @external_fgetc_internal_test() {
+; CHECK-LABEL: @external_fgetc_internal_test(
+; CHECK-NEXT:    call void @fgetc_test()
+; CHECK-NEXT:    ret void
+;
+  call void @fgetc_test()
+  ret void
+}
+
+define internal void @fwrite_test() {
+; CHECK-LABEL: @fwrite_test(
+; CHECK-NEXT:    [[S:%.*]] = alloca [10 x i8], align 1
+; CHECK-NEXT:    [[CALL:%.*]] = call %struct._IO_FILE* @fopen(i8* getelementptr inbounds ([5 x i8], [5 x i8]* @.str, i64 0, i64 0), i8* getelementptr inbounds ([2 x i8], [2 x i8]* @.str.1, i64 0, i64 0))
+; CHECK-NEXT:    [[ARRAYDECAY:%.*]] = getelementptr inbounds [10 x i8], [10 x i8]* [[S]], i64 0, i64 0
+; CHECK-NEXT:    [[TMP1:%.*]] = call i64 @fwrite_unlocked(i8* nonnull [[ARRAYDECAY]], i64 10, i64 10, %struct._IO_FILE* [[CALL]])
+; CHECK-NEXT:    ret void
+;
+  %s = alloca [10 x i8], align 1
+  %call = call %struct._IO_FILE* @fopen(i8* getelementptr inbounds ([5 x i8], [5 x i8]* @.str, i64 0, i64 0), i8* getelementptr inbounds ([2 x i8], [2 x i8]* @.str.1, i64 0, i64 0))
+  %arraydecay = getelementptr inbounds [10 x i8], [10 x i8]* %s, i64 0, i64 0
+  %call1 = call i64 @fwrite(i8* nonnull %arraydecay, i64 10, i64 10, %struct._IO_FILE* %call)
+  ret void
+}
+
+define internal void @fread_test() {
+; CHECK-LABEL: @fread_test(
+; CHECK-NEXT:    [[S:%.*]] = alloca [10 x i8], align 1
+; CHECK-NEXT:    [[CALL:%.*]] = call %struct._IO_FILE* @fopen(i8* getelementptr inbounds ([5 x i8], [5 x i8]* @.str, i64 0, i64 0), i8* getelementptr inbounds ([2 x i8], [2 x i8]* @.str.1, i64 0, i64 0))
+; CHECK-NEXT:    [[ARRAYDECAY:%.*]] = getelementptr inbounds [10 x i8], [10 x i8]* [[S]], i64 0, i64 0
+; CHECK-NEXT:    [[TMP1:%.*]] = call i64 @fread_unlocked(i8* nonnull [[ARRAYDECAY]], i64 10, i64 10, %struct._IO_FILE* [[CALL]])
+; CHECK-NEXT:    ret void
+;
+  %s = alloca [10 x i8], align 1
+  %call = call %struct._IO_FILE* @fopen(i8* getelementptr inbounds ([5 x i8], [5 x i8]* @.str, i64 0, i64 0), i8* getelementptr inbounds ([2 x i8], [2 x i8]* @.str.1, i64 0, i64 0))
+  %arraydecay = getelementptr inbounds [10 x i8], [10 x i8]* %s, i64 0, i64 0
+  %call1 = call i64 @fread(i8* nonnull %arraydecay, i64 10, i64 10, %struct._IO_FILE* %call)
+  ret void
+}
+
+define internal void @fputs_test() {
+; CHECK-LABEL: @fputs_test(
+; CHECK-NEXT:    [[CALL:%.*]] = call %struct._IO_FILE* @fopen(i8* getelementptr inbounds ([5 x i8], [5 x i8]* @.str, i64 0, i64 0), i8* getelementptr inbounds ([2 x i8], [2 x i8]* @.str.1, i64 0, i64 0))
+; CHECK-NEXT:    [[TMP1:%.*]] = call i64 @fwrite_unlocked(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str.2, i64 0, i64 0), i64 3, i64 1, %struct._IO_FILE* [[CALL]])
+; CHECK-NEXT:    ret void
+;
+  %call = call %struct._IO_FILE* @fopen(i8* getelementptr inbounds ([5 x i8], [5 x i8]* @.str, i64 0, i64 0), i8* getelementptr inbounds ([2 x i8], [2 x i8]* @.str.1, i64 0, i64 0))
+  %call1 = call i32 @fputs(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str.2, i64 0, i64 0), %struct._IO_FILE* %call)
+  ret void
+}
+
+define internal void @fgets_test() {
+; CHECK-LABEL: @fgets_test(
+; CHECK-NEXT:    [[BUF:%.*]] = alloca [10 x i8], align 1
+; CHECK-NEXT:    [[CALL:%.*]] = call %struct._IO_FILE* @fopen(i8* getelementptr inbounds ([5 x i8], [5 x i8]* @.str, i64 0, i64 0), i8* getelementptr inbounds ([2 x i8], [2 x i8]* @.str.1, i64 0, i64 0))
+; CHECK-NEXT:    [[ARRAYDECAY:%.*]] = getelementptr inbounds [10 x i8], [10 x i8]* [[BUF]], i64 0, i64 0
+; CHECK-NEXT:    [[FGETS_UNLOCKED:%.*]] = call i8* @fgets_unlocked(i8* nonnull [[ARRAYDECAY]], i32 10, %struct._IO_FILE* [[CALL]])
+; CHECK-NEXT:    ret void
+;
+  %buf = alloca [10 x i8], align 1
+  %call = call %struct._IO_FILE* @fopen(i8* getelementptr inbounds ([5 x i8], [5 x i8]* @.str, i64 0, i64 0), i8* getelementptr inbounds ([2 x i8], [2 x i8]* @.str.1, i64 0, i64 0))
+  %arraydecay = getelementptr inbounds [10 x i8], [10 x i8]* %buf, i64 0, i64 0
+  %call1 = call i8* @fgets(i8* nonnull %arraydecay, i32 10, %struct._IO_FILE* %call)
+  ret void
+}
+
+define internal void @fputc_test() {
+; CHECK-LABEL: @fputc_test(
+; CHECK-NEXT:    [[CALL:%.*]] = call %struct._IO_FILE* @fopen(i8* getelementptr inbounds ([5 x i8], [5 x i8]* @.str, i64 0, i64 0), i8* getelementptr inbounds ([2 x i8], [2 x i8]* @.str.1, i64 0, i64 0))
+; CHECK-NEXT:    [[FPUTC_UNLOCKED:%.*]] = call i32 @fputc_unlocked(i32 99, %struct._IO_FILE* [[CALL]])
+; CHECK-NEXT:    ret void
+;
+  %call = call %struct._IO_FILE* @fopen(i8* getelementptr inbounds ([5 x i8], [5 x i8]* @.str, i64 0, i64 0), i8* getelementptr inbounds ([2 x i8], [2 x i8]* @.str.1, i64 0, i64 0))
+  %call1 = call i32 @fputc(i32 99, %struct._IO_FILE* %call)
+  ret void
+}
+
+define i32 @main() {
+; CHECK-LABEL: @main(
+; CHECK-NEXT:    call void @fwrite_test()
+; CHECK-NEXT:    call void @fread_test()
+; CHECK-NEXT:    call void @fputs_test()
+; CHECK-NEXT:    call void @fgets_test()
+; CHECK-NEXT:    call void @fputc_test()
+; CHECK-NEXT:    call void @fgetc_test()
+; CHECK-NEXT:    ret i32 0
+;
+  call void @fwrite_test()
+  call void @fread_test()
+  call void @fputs_test()
+  call void @fgets_test()
+  call void @fputc_test()
+  call void @fgetc_test()
+  ret i32 0
+}
+
+declare i32 @fclose(%struct._IO_FILE* nocapture)
+
+define void @test_with_fclose() {
+; CHECK-LABEL: @test_with_fclose(
+; CHECK-NEXT:    [[CALL:%.*]] = call %struct._IO_FILE* @fopen(i8* getelementptr inbounds ([5 x i8], [5 x i8]* @.str, i64 0, i64 0), i8* getelementptr inbounds ([2 x i8], [2 x i8]* @.str.1, i64 0, i64 0))
+; CHECK-NEXT:    [[TMP1:%.*]] = call i64 @fwrite_unlocked(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str.2, i64 0, i64 0), i64 3, i64 1, %struct._IO_FILE* [[CALL]])
+; CHECK-NEXT:    [[CALL2:%.*]] = call i32 @fclose(%struct._IO_FILE* [[CALL]])
+; CHECK-NEXT:    ret void
+;
+  %call = call %struct._IO_FILE* @fopen(i8* getelementptr inbounds ([5 x i8], [5 x i8]* @.str, i64 0, i64 0), i8* getelementptr inbounds ([2 x i8], [2 x i8]* @.str.1, i64 0, i64 0)) #2
+  %call1 = call i64 @fwrite(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str.2, i64 0, i64 0), i64 3, i64 1, %struct._IO_FILE* %call)
+  %call2 = call i32 @fclose(%struct._IO_FILE* %call) #2
+  ret void
+}
+
+declare void @modify_file(%struct._IO_FILE*)
+
+define void @test_captured_by_function(){
+; CHECK-LABEL: @test_captured_by_function(
+; CHECK-NEXT:    [[CALL:%.*]] = call %struct._IO_FILE* @fopen(i8* getelementptr inbounds ([5 x i8], [5 x i8]* @.str, i64 0, i64 0), i8* getelementptr inbounds ([2 x i8], [2 x i8]* @.str.1, i64 0, i64 0))
+; CHECK-NEXT:    call void @modify_file(%struct._IO_FILE* [[CALL]])
+; CHECK-NEXT:    [[CALL1:%.*]] = call i64 @fwrite(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str.2, i64 0, i64 0), i64 3, i64 1, %struct._IO_FILE* [[CALL]])
+; CHECK-NEXT:    [[CALL2:%.*]] = call i32 @fclose(%struct._IO_FILE* [[CALL]])
+; CHECK-NEXT:    ret void
+;
+  %call = call %struct._IO_FILE* @fopen(i8* getelementptr inbounds ([5 x i8], [5 x i8]* @.str, i64 0, i64 0), i8* getelementptr inbounds ([2 x i8], [2 x i8]* @.str.1, i64 0, i64 0)) #2
+  call void @modify_file(%struct._IO_FILE* %call) #2
+  %call1 = call i64 @fwrite(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str.2, i64 0, i64 0), i64 3, i64 1, %struct._IO_FILE* %call)
+  %call2 = call i32 @fclose(%struct._IO_FILE* %call) #2
+  ret void
+}
+
+define void @test_captured_by_global_value() {
+; CHECK-LABEL: @test_captured_by_global_value(
+; CHECK-NEXT:    [[CALL:%.*]] = call %struct._IO_FILE* @fopen(i8* getelementptr inbounds ([5 x i8], [5 x i8]* @.str, i64 0, i64 0), i8* getelementptr inbounds ([2 x i8], [2 x i8]* @.str.1, i64 0, i64 0))
+; CHECK-NEXT:    [[DOTCAST:%.*]] = ptrtoint %struct._IO_FILE* [[CALL]] to i64
+; CHECK-NEXT:    store i64 [[DOTCAST]], i64* bitcast (%struct._IO_FILE** @global_file to i64*), align 8
+; CHECK-NEXT:    [[CALL1:%.*]] = call i64 @fwrite(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str.2, i64 0, i64 0), i64 3, i64 1, %struct._IO_FILE* [[CALL]])
+; CHECK-NEXT:    [[CALL2:%.*]] = call i32 @fclose(%struct._IO_FILE* [[CALL]])
+; CHECK-NEXT:    ret void
+;
+  %call = call %struct._IO_FILE* @fopen(i8* getelementptr inbounds ([5 x i8], [5 x i8]* @.str, i64 0, i64 0), i8* getelementptr inbounds ([2 x i8], [2 x i8]* @.str.1, i64 0, i64 0)) #2
+  %.cast = ptrtoint %struct._IO_FILE* %call to i64
+  store i64 %.cast, i64* bitcast (%struct._IO_FILE** @global_file to i64*), align 8
+  %call1 = call i64 @fwrite(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str.2, i64 0, i64 0), i64 3, i64 1, %struct._IO_FILE* %call)
+  %call2 = call i32 @fclose(%struct._IO_FILE* %call) #2
+  ret void
+}
+
+define void @test_captured_by_standard_stream(i8* nocapture readonly %s) {
+; CHECK-LABEL: @test_captured_by_standard_stream(
+; CHECK-NEXT:    [[CALL:%.*]] = tail call %struct._IO_FILE* @fopen(i8* getelementptr inbounds ([5 x i8], [5 x i8]* @.str, i64 0, i64 0), i8* getelementptr inbounds ([2 x i8], [2 x i8]* @.str.1, i64 0, i64 0))
+; CHECK-NEXT:    [[TMP:%.*]] = load %struct._IO_FILE*, %struct._IO_FILE** @stdout, align 8
+; CHECK-NEXT:    [[CALL1:%.*]] = tail call i32 @fputs(i8* [[S:%.*]], %struct._IO_FILE* [[TMP]])
+; CHECK-NEXT:    [[CALL2:%.*]] = tail call i32 @fclose(%struct._IO_FILE* [[TMP]])
+; CHECK-NEXT:    ret void
+;
+  %call = tail call %struct._IO_FILE* @fopen(i8* getelementptr inbounds ([5 x i8], [5 x i8]* @.str, i64 0, i64 0), i8* getelementptr inbounds ([2 x i8], [2 x i8]* @.str.1, i64 0, i64 0))
+  %tmp = load %struct._IO_FILE*, %struct._IO_FILE** @stdout, align 8
+  %call1 = tail call i32 @fputs(i8* %s, %struct._IO_FILE* %tmp)
+  %call2 = tail call i32 @fclose(%struct._IO_FILE* %tmp)
+  ret void
+}
+
+define void @test_captured_by_arg(i8* nocapture readonly %s, %struct._IO_FILE* nocapture %file) {
+; CHECK-LABEL: @test_captured_by_arg(
+; CHECK-NEXT:    [[CALL:%.*]] = tail call %struct._IO_FILE* @fopen(i8* getelementptr inbounds ([5 x i8], [5 x i8]* @.str, i64 0, i64 0), i8* getelementptr inbounds ([2 x i8], [2 x i8]* @.str.1, i64 0, i64 0))
+; CHECK-NEXT:    [[CALL1:%.*]] = tail call i32 @fputs(i8* [[S:%.*]], %struct._IO_FILE* [[FILE:%.*]])
+; CHECK-NEXT:    [[CALL2:%.*]] = tail call i32 @fclose(%struct._IO_FILE* [[FILE]])
+; CHECK-NEXT:    ret void
+;
+  %call = tail call %struct._IO_FILE* @fopen(i8* getelementptr inbounds ([5 x i8], [5 x i8]* @.str, i64 0, i64 0), i8* getelementptr inbounds ([2 x i8], [2 x i8]* @.str.1, i64 0, i64 0))
+  %call1 = tail call i32 @fputs(i8* %s, %struct._IO_FILE* %file)
+  %call2 = tail call i32 @fclose(%struct._IO_FILE* %file)
+  ret void
+}
+
+declare i64 @fwrite(i8* nocapture, i64, i64, %struct._IO_FILE* nocapture)
+declare i64 @fread(i8* nocapture, i64, i64, %struct._IO_FILE* nocapture)
+declare i32 @fputs(i8* nocapture readonly, %struct._IO_FILE* nocapture)
+declare i8* @fgets(i8*, i32, %struct._IO_FILE* nocapture)

Added: llvm/trunk/test/Transforms/InstCombine/unordered-fcmp-select.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/unordered-fcmp-select.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/unordered-fcmp-select.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/unordered-fcmp-select.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,125 @@
+; RUN: opt -S -instcombine < %s | FileCheck %s
+
+; CHECK-LABEL: @select_max_ugt(
+; CHECK: %cmp.inv = fcmp ole float %a, %b
+; CHECK-NEXT: %sel = select i1 %cmp.inv, float %b, float %a
+; CHECK-NEXT: ret float %sel
+define float @select_max_ugt(float %a, float %b) {
+  %cmp = fcmp ugt float %a, %b
+  %sel = select i1 %cmp, float %a, float %b
+  ret float %sel
+}
+
+; CHECK-LABEL: @select_max_uge(
+; CHECK: %cmp.inv = fcmp olt float %a, %b
+; CHECK-NEXT: %sel = select i1 %cmp.inv, float %b, float %a
+; CHECK-NEXT: ret float %sel
+define float @select_max_uge(float %a, float %b) {
+  %cmp = fcmp uge float %a, %b
+  %sel = select i1 %cmp, float %a, float %b
+  ret float %sel
+}
+
+; CHECK-LABEL: @select_min_ugt(
+; CHECK: %cmp.inv = fcmp ole float %a, %b
+; CHECK-NEXT: %sel = select i1 %cmp.inv, float %a, float %b
+; CHECK-NEXT: ret float %sel
+define float @select_min_ugt(float %a, float %b) {
+  %cmp = fcmp ugt float %a, %b
+  %sel = select i1 %cmp, float %b, float %a
+  ret float %sel
+}
+
+; CHECK-LABEL: @select_min_uge(
+; CHECK: %cmp.inv = fcmp olt float %a, %b
+; CHECK-NEXT: %sel = select i1 %cmp.inv, float %a, float %b
+; CHECK-NEXT: ret float %sel
+define float @select_min_uge(float %a, float %b) {
+  %cmp = fcmp uge float %a, %b
+  %sel = select i1 %cmp, float %b, float %a
+  ret float %sel
+}
+
+; CHECK-LABEL: @select_max_ult(
+; CHECK: %cmp.inv = fcmp oge float %a, %b
+; CHECK-NEXT: %sel = select i1 %cmp.inv, float %a, float %b
+; CHECK-NEXT: ret float %sel
+define float @select_max_ult(float %a, float %b) {
+  %cmp = fcmp ult float %a, %b
+  %sel = select i1 %cmp, float %b, float %a
+  ret float %sel
+}
+
+; CHECK-LABEL: @select_max_ule(
+; CHECK: %cmp.inv = fcmp ogt float %a, %b
+; CHECK-NEXT: %sel = select i1 %cmp.inv, float %a, float %b
+; CHECK: ret float %sel
+define float @select_max_ule(float %a, float %b) {
+  %cmp = fcmp ule float %a, %b
+  %sel = select i1 %cmp, float %b, float %a
+  ret float %sel
+}
+
+; CHECK-LABEL: @select_min_ult(
+; CHECK: %cmp.inv = fcmp oge float %a, %b
+; CHECK-NEXT: %sel = select i1 %cmp.inv, float %b, float %a
+; CHECK-NEXT: ret float %sel
+define float @select_min_ult(float %a, float %b) {
+  %cmp = fcmp ult float %a, %b
+  %sel = select i1 %cmp, float %a, float %b
+  ret float %sel
+}
+
+; CHECK-LABEL: @select_min_ule(
+; CHECK: %cmp.inv = fcmp ogt float %a, %b
+; CHECK-NEXT: %sel = select i1 %cmp.inv, float %b, float %a
+; CHECK-NEXT: ret float %sel
+define float @select_min_ule(float %a, float %b) {
+  %cmp = fcmp ule float %a, %b
+  %sel = select i1 %cmp, float %a, float %b
+  ret float %sel
+}
+
+; CHECK-LABEL: @select_fcmp_une(
+; CHECK:  %cmp.inv = fcmp oeq float %a, %b
+; CHECK-NEXT:  %sel = select i1 %cmp.inv, float %b, float %a
+; CHECK-NEXT: ret float %sel
+define float @select_fcmp_une(float %a, float %b) {
+  %cmp = fcmp une float %a, %b
+  %sel = select i1 %cmp, float %a, float %b
+  ret float %sel
+}
+
+; CHECK-LABEL: @select_fcmp_ueq
+; CHECK:  %cmp.inv = fcmp one float %a, %b
+; CHECK-NEXT:  %sel = select i1 %cmp.inv, float %b, float %a
+; CHECK-NEXT: ret float %sel
+define float @select_fcmp_ueq(float %a, float %b) {
+  %cmp = fcmp ueq float %a, %b
+  %sel = select i1 %cmp, float %a, float %b
+  ret float %sel
+}
+
+declare void @foo(i1)
+
+; CHECK-LABEL: @select_max_ugt_2_use_cmp(
+; CHECK: fcmp ugt
+; CHECK-NOT: fcmp
+; CHECK: ret
+define float @select_max_ugt_2_use_cmp(float %a, float %b) {
+  %cmp = fcmp ugt float %a, %b
+  call void @foo(i1 %cmp)
+  %sel = select i1 %cmp, float %a, float %b
+  ret float %sel
+}
+
+; CHECK-LABEL: @select_min_uge_2_use_cmp(
+; CHECK: fcmp uge
+; CHECK-NOT: fcmp
+; CHECK: ret
+define float @select_min_uge_2_use_cmp(float %a, float %b) {
+  %cmp = fcmp uge float %a, %b
+  call void @foo(i1 %cmp)
+  %sel = select i1 %cmp, float %b, float %a
+  ret float %sel
+}

Added: llvm/trunk/test/Transforms/InstCombine/unpack-fca.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/unpack-fca.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/unpack-fca.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/unpack-fca.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,239 @@
+; RUN: opt -instcombine -S < %s | FileCheck %s
+
+target datalayout = "e-i64:64-f80:128-n8:16:32:64"
+target triple = "x86_64-unknown-linux-gnu"
+
+%A__vtbl = type { i8*, i32 (%A*)* }
+%A = type { %A__vtbl* }
+%B = type { i8*, i64 }
+
+ at A__vtblZ = constant %A__vtbl { i8* null, i32 (%A*)* @A.foo }
+
+declare i32 @A.foo(%A* nocapture %this)
+
+define void @storeA(%A* %a.ptr) {
+; CHECK-LABEL: storeA
+; CHECK-NEXT: [[GEP:%[a-z0-9\.]+]] = getelementptr inbounds %A, %A* %a.ptr, i64 0, i32 0
+; CHECK-NEXT: store %A__vtbl* @A__vtblZ, %A__vtbl** [[GEP]], align 8
+; CHECK-NEXT: ret void
+  store %A { %A__vtbl* @A__vtblZ }, %A* %a.ptr, align 8
+  ret void
+}
+
+define void @storeB(%B* %b.ptr) {
+; CHECK-LABEL: storeB
+; CHECK-NEXT: [[GEP1:%[a-z0-9\.]+]] = getelementptr inbounds %B, %B* %b.ptr, i64 0, i32 0
+; CHECK-NEXT: store i8* null, i8** [[GEP1]], align 8
+; CHECK-NEXT: [[GEP2:%[a-z0-9\.]+]] = getelementptr inbounds %B, %B* %b.ptr, i64 0, i32 1
+; CHECK-NEXT: store i64 42, i64* [[GEP2]], align 8
+; CHECK-NEXT: ret void
+  store %B { i8* null, i64 42 }, %B* %b.ptr, align 8
+  ret void
+}
+
+define void @storeStructOfA({ %A }* %sa.ptr) {
+; CHECK-LABEL: storeStructOfA
+; CHECK-NEXT: [[GEP:%[a-z0-9\.]+]] = getelementptr inbounds { %A }, { %A }* %sa.ptr, i64 0, i32 0, i32 0
+; CHECK-NEXT: store %A__vtbl* @A__vtblZ, %A__vtbl** [[GEP]], align 8
+; CHECK-NEXT: ret void
+  store { %A } { %A { %A__vtbl* @A__vtblZ } }, { %A }* %sa.ptr, align 8
+  ret void
+}
+
+define void @storeArrayOfA([1 x %A]* %aa.ptr) {
+; CHECK-LABEL: storeArrayOfA
+; CHECK-NEXT: [[GEP:%[a-z0-9\.]+]] = getelementptr inbounds [1 x %A], [1 x %A]* %aa.ptr, i64 0, i64 0, i32 0
+; CHECK-NEXT: store %A__vtbl* @A__vtblZ, %A__vtbl** [[GEP]], align 8
+; CHECK-NEXT: ret void
+  store [1 x %A] [%A { %A__vtbl* @A__vtblZ }], [1 x %A]* %aa.ptr, align 8
+  ret void
+}
+
+define void @storeLargeArrayOfA([2000 x %A]* %aa.ptr) {
+; CHECK-LABEL: storeLargeArrayOfA
+; CHECK-NEXT: store [2000 x %A]
+; CHECK-NEXT: ret void
+  %i1 = insertvalue [2000 x %A] undef, %A { %A__vtbl* @A__vtblZ }, 1
+  store [2000 x %A] %i1, [2000 x %A]* %aa.ptr, align 8
+  ret void
+}
+
+define void @storeStructOfArrayOfA({ [1 x %A] }* %saa.ptr) {
+; CHECK-LABEL: storeStructOfArrayOfA
+; CHECK-NEXT: [[GEP:%[a-z0-9\.]+]] = getelementptr inbounds { [1 x %A] }, { [1 x %A] }* %saa.ptr, i64 0, i32 0, i64 0, i32 0
+; CHECK-NEXT: store %A__vtbl* @A__vtblZ, %A__vtbl** [[GEP]], align 8
+; CHECK-NEXT: ret void
+  store { [1 x %A] } { [1 x %A] [%A { %A__vtbl* @A__vtblZ }] }, { [1 x %A] }* %saa.ptr, align 8
+  ret void
+}
+
+define void @storeArrayOfB([2 x %B]* %ab.ptr, [2 x %B] %ab) {
+; CHECK-LABEL: storeArrayOfB
+; CHECK-NEXT: [[EVB0:%[a-z0-9\.]+]] = extractvalue [2 x %B] %ab, 0
+; CHECK-NEXT: [[GEP0:%[a-z0-9\.]+]] = getelementptr inbounds [2 x %B], [2 x %B]* %ab.ptr, i64 0, i64 0, i32 0
+; CHECK-NEXT: [[EV0:%[a-z0-9\.]+]] = extractvalue %B [[EVB0]], 0
+; CHECK-NEXT: store i8* [[EV0]], i8** [[GEP0]], align 8
+; CHECK-NEXT: [[GEP1:%[a-z0-9\.]+]] = getelementptr inbounds [2 x %B], [2 x %B]* %ab.ptr, i64 0, i64 0, i32 1
+; CHECK-NEXT: [[EV1:%[a-z0-9\.]+]] = extractvalue %B [[EVB0]], 1
+; CHECK-NEXT: store i64 [[EV1]], i64* [[GEP1]], align 8
+; CHECK-NEXT: [[EVB1:%[a-z0-9\.]+]] = extractvalue [2 x %B] %ab, 1
+; CHECK-NEXT: [[GEP2:%[a-z0-9\.]+]] = getelementptr inbounds [2 x %B], [2 x %B]* %ab.ptr, i64 0, i64 1, i32 0
+; CHECK-NEXT: [[EV2:%[a-z0-9\.]+]] = extractvalue %B [[EVB1]], 0
+; CHECK-NEXT: store i8* [[EV2]], i8** [[GEP2]], align 8
+; CHECK-NEXT: [[GEP3:%[a-z0-9\.]+]] = getelementptr inbounds [2 x %B], [2 x %B]* %ab.ptr, i64 0, i64 1, i32 1
+; CHECK-NEXT: [[EV3:%[a-z0-9\.]+]] = extractvalue %B [[EVB1]], 1
+; CHECK-NEXT: store i64 [[EV3]], i64* [[GEP3]], align 8
+; CHECK-NEXT: ret void
+  store [2 x %B] %ab, [2 x %B]* %ab.ptr, align 8
+  ret void
+}
+
+define %A @loadA(%A* %a.ptr) {
+; CHECK-LABEL: loadA
+; CHECK-NEXT: [[GEP:%[a-z0-9\.]+]] = getelementptr inbounds %A, %A* %a.ptr, i64 0, i32 0
+; CHECK-NEXT: [[LOAD:%[a-z0-9\.]+]] = load %A__vtbl*, %A__vtbl** [[GEP]], align 8
+; CHECK-NEXT: [[IV:%[a-z0-9\.]+]] = insertvalue %A undef, %A__vtbl* [[LOAD]], 0
+; CHECK-NEXT: ret %A [[IV]]
+  %1 = load %A, %A* %a.ptr, align 8
+  ret %A %1
+}
+
+define %B @loadB(%B* %b.ptr) {
+; CHECK-LABEL: loadB
+; CHECK-NEXT: [[GEP1:%[a-z0-9\.]+]] = getelementptr inbounds %B, %B* %b.ptr, i64 0, i32 0
+; CHECK-NEXT: [[LOAD1:%[a-z0-9\.]+]] = load i8*, i8** [[GEP1]], align 8
+; CHECK-NEXT: [[IV1:%[a-z0-9\.]+]] = insertvalue %B undef, i8* [[LOAD1]], 0
+; CHECK-NEXT: [[GEP2:%[a-z0-9\.]+]] = getelementptr inbounds %B, %B* %b.ptr, i64 0, i32 1
+; CHECK-NEXT: [[LOAD2:%[a-z0-9\.]+]] = load i64, i64* [[GEP2]], align 8
+; CHECK-NEXT: [[IV2:%[a-z0-9\.]+]] = insertvalue %B [[IV1]], i64 [[LOAD2]], 1
+; CHECK-NEXT: ret %B [[IV2]]
+  %1 = load %B, %B* %b.ptr, align 8
+  ret %B %1
+}
+
+define { %A } @loadStructOfA({ %A }* %sa.ptr) {
+; CHECK-LABEL: loadStructOfA
+; CHECK-NEXT: [[GEP:%[a-z0-9\.]+]] = getelementptr inbounds { %A }, { %A }* %sa.ptr, i64 0, i32 0, i32 0
+; CHECK-NEXT: [[LOAD:%[a-z0-9\.]+]] = load %A__vtbl*, %A__vtbl** [[GEP]], align 8
+; CHECK-NEXT: [[IV1:%[a-z0-9\.]+]] = insertvalue %A undef, %A__vtbl* [[LOAD]], 0
+; CHECK-NEXT: [[IV2:%[a-z0-9\.]+]] = insertvalue { %A } undef, %A [[IV1]], 0
+; CHECK-NEXT: ret { %A } [[IV2]]
+  %1 = load { %A }, { %A }* %sa.ptr, align 8
+  ret { %A } %1
+}
+
+define [1 x %A] @loadArrayOfA([1 x %A]* %aa.ptr) {
+; CHECK-LABEL: loadArrayOfA
+; CHECK-NEXT: [[GEP:%[a-z0-9\.]+]] = getelementptr inbounds [1 x %A], [1 x %A]* %aa.ptr, i64 0, i64 0, i32 0
+; CHECK-NEXT: [[LOAD:%[a-z0-9\.]+]] = load %A__vtbl*, %A__vtbl** [[GEP]], align 8
+; CHECK-NEXT: [[IV1:%[a-z0-9\.]+]] = insertvalue %A undef, %A__vtbl* [[LOAD]], 0
+; CHECK-NEXT: [[IV2:%[a-z0-9\.]+]] = insertvalue [1 x %A] undef, %A [[IV1]], 0
+; CHECK-NEXT: ret [1 x %A] [[IV2]]
+  %1 = load [1 x %A], [1 x %A]* %aa.ptr, align 8
+  ret [1 x %A] %1
+}
+
+define { [1 x %A] } @loadStructOfArrayOfA({ [1 x %A] }* %saa.ptr) {
+; CHECK-LABEL: loadStructOfArrayOfA
+; CHECK-NEXT: [[GEP:%[a-z0-9\.]+]] = getelementptr inbounds { [1 x %A] }, { [1 x %A] }* %saa.ptr, i64 0, i32 0, i64 0, i32 0
+; CHECK-NEXT: [[LOAD:%[a-z0-9\.]+]] = load %A__vtbl*, %A__vtbl** [[GEP]], align 8
+; CHECK-NEXT: [[IV1:%[a-z0-9\.]+]] = insertvalue %A undef, %A__vtbl* [[LOAD]], 0
+; CHECK-NEXT: [[IV2:%[a-z0-9\.]+]] = insertvalue [1 x %A] undef, %A [[IV1]], 0
+; CHECK-NEXT: [[IV3:%[a-z0-9\.]+]] = insertvalue { [1 x %A] } undef, [1 x %A] [[IV2]], 0
+; CHECK-NEXT: ret { [1 x %A] } [[IV3]]
+  %1 = load { [1 x %A] }, { [1 x %A] }* %saa.ptr, align 8
+  ret { [1 x %A] } %1
+}
+
+define { %A } @structOfA({ %A }* %sa.ptr) {
+; CHECK-LABEL: structOfA
+; CHECK-NEXT: [[GEP:%[a-z0-9\.]+]] = getelementptr inbounds { %A }, { %A }* %sa.ptr, i64 0, i32 0, i32 0
+; CHECK-NEXT: store %A__vtbl* @A__vtblZ, %A__vtbl** [[GEP]], align 8
+; CHECK-NEXT: ret { %A } { %A { %A__vtbl* @A__vtblZ } }
+  store { %A } { %A { %A__vtbl* @A__vtblZ } }, { %A }* %sa.ptr, align 8
+  %1 = load { %A }, { %A }* %sa.ptr, align 8
+  ret { %A } %1
+}
+
+define %B @structB(%B* %b.ptr) {
+; CHECK-LABEL: structB
+; CHECK-NEXT: [[GEP1:%[a-z0-9\.]+]] = getelementptr inbounds %B, %B* %b.ptr, i64 0, i32 0
+; CHECK-NEXT: store i8* null, i8** [[GEP1]], align 8
+; CHECK-NEXT: [[GEP2:%[a-z0-9\.]+]] = getelementptr inbounds %B, %B* %b.ptr, i64 0, i32 1
+; CHECK-NEXT: store i64 42, i64* [[GEP2]], align 8
+; CHECK-NEXT: ret %B { i8* null, i64 42 }
+  store %B { i8* null, i64 42 }, %B* %b.ptr, align 8
+  %1 = load %B, %B* %b.ptr, align 8
+  ret %B %1
+}
+
+define [2 x %B] @loadArrayOfB([2 x %B]* %ab.ptr) {
+; CHECK-LABEL: loadArrayOfB
+; CHECK-NEXT: [[GEP1:%[a-z0-9\.]+]] = getelementptr inbounds [2 x %B], [2 x %B]* %ab.ptr, i64 0, i64 0, i32 0
+; CHECK-NEXT: [[LOAD1:%[a-z0-9\.]+]] = load i8*, i8** [[GEP1]], align 8
+; CHECK-NEXT: [[IV1:%[a-z0-9\.]+]] = insertvalue %B undef, i8* [[LOAD1]], 0
+; CHECK-NEXT: [[GEP2:%[a-z0-9\.]+]] = getelementptr inbounds [2 x %B], [2 x %B]* %ab.ptr, i64 0, i64 0, i32 1
+; CHECK-NEXT: [[LOAD2:%[a-z0-9\.]+]] = load i64, i64* [[GEP2]], align 8
+; CHECK-NEXT: [[IV2:%[a-z0-9\.]+]] = insertvalue %B [[IV1]], i64 [[LOAD2]], 1
+; CHECK-NEXT: [[IV3:%[a-z0-9\.]+]] = insertvalue [2 x %B] undef, %B [[IV2]], 0
+; CHECK-NEXT: [[GEP3:%[a-z0-9\.]+]] = getelementptr inbounds [2 x %B], [2 x %B]* %ab.ptr, i64 0, i64 1, i32 0
+; CHECK-NEXT: [[LOAD3:%[a-z0-9\.]+]] = load i8*, i8** [[GEP3]], align 8
+; CHECK-NEXT: [[IV4:%[a-z0-9\.]+]] = insertvalue %B undef, i8* [[LOAD3]], 0
+; CHECK-NEXT: [[GEP4:%[a-z0-9\.]+]] = getelementptr inbounds [2 x %B], [2 x %B]* %ab.ptr, i64 0, i64 1, i32 1
+; CHECK-NEXT: [[LOAD4:%[a-z0-9\.]+]] = load i64, i64* [[GEP4]], align 8
+; CHECK-NEXT: [[IV5:%[a-z0-9\.]+]] = insertvalue %B [[IV4]], i64 [[LOAD4]], 1
+; CHECK-NEXT: [[IV6:%[a-z0-9\.]+]] = insertvalue [2 x %B] [[IV3]], %B [[IV5]], 1
+; CHECK-NEXT: ret [2 x %B] [[IV6]]
+  %1 = load [2 x %B], [2 x %B]* %ab.ptr, align 8
+  ret [2 x %B] %1
+}
+
+define [2000 x %B] @loadLargeArrayOfB([2000 x %B]* %ab.ptr) {
+; CHECK-LABEL: loadLargeArrayOfB
+; CHECK-NEXT: load [2000 x %B], [2000 x %B]* %ab.ptr, align 8
+; CHECK-NEXT: ret [2000 x %B]
+  %1 = load [2000 x %B], [2000 x %B]* %ab.ptr, align 8
+  ret [2000 x %B] %1
+}
+
+%struct.S = type <{ i8, %struct.T }>
+%struct.T = type { i32, i32 }
+
+; Make sure that we do not increase alignment of packed struct element
+define i32 @packed_alignment(%struct.S* dereferenceable(9) %s) {
+; CHECK-LABEL: packed_alignment
+; CHECK-NEXT: %tv.elt1 = getelementptr inbounds %struct.S, %struct.S* %s, i64 0, i32 1, i32 1
+; CHECK-NEXT: %tv.unpack2 = load i32, i32* %tv.elt1, align 1
+; CHECK-NEXT: ret i32 %tv.unpack2
+  %t = getelementptr inbounds %struct.S, %struct.S* %s, i32 0, i32 1
+  %tv = load %struct.T, %struct.T* %t, align 1
+  %v = extractvalue %struct.T %tv, 1
+  ret i32 %v
+}
+
+%struct.U = type {i8, i8, i8, i8, i8, i8, i8, i8, i64}
+
+define void @check_alignment(%struct.U* %u, %struct.U* %v) {
+; CHECK-LABEL: check_alignment
+; CHECK: load i8, i8* {{.*}}, align 8
+; CHECK: load i8, i8* {{.*}}, align 1
+; CHECK: load i8, i8* {{.*}}, align 2
+; CHECK: load i8, i8* {{.*}}, align 1
+; CHECK: load i8, i8* {{.*}}, align 4
+; CHECK: load i8, i8* {{.*}}, align 1
+; CHECK: load i8, i8* {{.*}}, align 2
+; CHECK: load i8, i8* {{.*}}, align 1
+; CHECK: load i64, i64* {{.*}}, align 8
+; CHECK: store i8 {{.*}}, i8* {{.*}}, align 8
+; CHECK: store i8 {{.*}}, i8* {{.*}}, align 1
+; CHECK: store i8 {{.*}}, i8* {{.*}}, align 2
+; CHECK: store i8 {{.*}}, i8* {{.*}}, align 1
+; CHECK: store i8 {{.*}}, i8* {{.*}}, align 4
+; CHECK: store i8 {{.*}}, i8* {{.*}}, align 1
+; CHECK: store i8 {{.*}}, i8* {{.*}}, align 2
+; CHECK: store i8 {{.*}}, i8* {{.*}}, align 1
+; CHECK: store i64 {{.*}}, i64* {{.*}}, align 8
+  %1 = load %struct.U, %struct.U* %u
+  store %struct.U %1, %struct.U* %v
+  ret void
+}

Added: llvm/trunk/test/Transforms/InstCombine/unrecognized_three-way-comparison.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/unrecognized_three-way-comparison.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/unrecognized_three-way-comparison.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/unrecognized_three-way-comparison.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,459 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; 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 void @foo(i32 %x)
+
+define i32 @compare_against_arbitrary_value(i32 %x, i32 %c) {
+; CHECK-LABEL: @compare_against_arbitrary_value(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[TMP0:%.*]] = icmp sgt i32 [[X:%.*]], [[C:%.*]]
+; CHECK-NEXT:    br i1 [[TMP0]], label [[CALLFOO:%.*]], label [[EXIT:%.*]]
+; CHECK:       callfoo:
+; CHECK-NEXT:    call void @foo(i32 1)
+; CHECK-NEXT:    br label [[EXIT]]
+; CHECK:       exit:
+; CHECK-NEXT:    ret i32 42
+;
+
+entry:
+  %cmp1 = icmp eq i32 %x, %c
+  %cmp2 = icmp slt i32 %x, %c
+  %select1 = select i1 %cmp2, i32 -1, i32 1
+  %select2 = select i1 %cmp1, i32 0, i32 %select1
+  %cond = icmp sgt i32 %select2, 0
+  br i1 %cond, label %callfoo, label %exit
+
+callfoo:
+  call void @foo(i32 %select2)
+  br label %exit
+
+exit:
+  ret i32 42
+}
+
+define i32 @compare_against_zero(i32 %x) {
+; CHECK-LABEL: @compare_against_zero(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[TMP0:%.*]] = icmp sgt i32 [[X:%.*]], 0
+; CHECK-NEXT:    br i1 [[TMP0]], label [[CALLFOO:%.*]], label [[EXIT:%.*]]
+; CHECK:       callfoo:
+; CHECK-NEXT:    call void @foo(i32 1)
+; CHECK-NEXT:    br label [[EXIT]]
+; CHECK:       exit:
+; CHECK-NEXT:    ret i32 42
+;
+
+entry:
+  %cmp1 = icmp eq i32 %x, 0
+  %cmp2 = icmp slt i32 %x, 0
+  %select1 = select i1 %cmp2, i32 -1, i32 1
+  %select2 = select i1 %cmp1, i32 0, i32 %select1
+  %cond = icmp sgt i32 %select2, 0
+  br i1 %cond, label %callfoo, label %exit
+
+callfoo:
+  call void @foo(i32 %select2)
+  br label %exit
+
+exit:
+  ret i32 42
+}
+
+define i32 @compare_against_one(i32 %x) {
+; CHECK-LABEL: @compare_against_one(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[TMP0:%.*]] = icmp sgt i32 [[X:%.*]], 1
+; CHECK-NEXT:    br i1 [[TMP0]], label [[CALLFOO:%.*]], label [[EXIT:%.*]]
+; CHECK:       callfoo:
+; CHECK-NEXT:    call void @foo(i32 1)
+; CHECK-NEXT:    br label [[EXIT]]
+; CHECK:       exit:
+; CHECK-NEXT:    ret i32 42
+;
+
+entry:
+  %cmp1 = icmp eq i32 %x, 1
+  %cmp2 = icmp slt i32 %x, 1
+  %select1 = select i1 %cmp2, i32 -1, i32 1
+  %select2 = select i1 %cmp1, i32 0, i32 %select1
+  %cond = icmp sgt i32 %select2, 0
+  br i1 %cond, label %callfoo, label %exit
+
+callfoo:
+  call void @foo(i32 %select2)
+  br label %exit
+
+exit:
+  ret i32 42
+}
+
+define i32 @compare_against_two(i32 %x) {
+; CHECK-LABEL: @compare_against_two(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[TMP0:%.*]] = icmp sgt i32 [[X:%.*]], 2
+; CHECK-NEXT:    br i1 [[TMP0]], label [[CALLFOO:%.*]], label [[EXIT:%.*]]
+; CHECK:       callfoo:
+; CHECK-NEXT:    call void @foo(i32 1)
+; CHECK-NEXT:    br label [[EXIT]]
+; CHECK:       exit:
+; CHECK-NEXT:    ret i32 42
+;
+
+entry:
+  %cmp1 = icmp eq i32 %x, 2
+  %cmp2 = icmp slt i32 %x, 2
+  %select1 = select i1 %cmp2, i32 -1, i32 1
+  %select2 = select i1 %cmp1, i32 0, i32 %select1
+  %cond = icmp sgt i32 %select2, 0
+  br i1 %cond, label %callfoo, label %exit
+
+callfoo:
+  call void @foo(i32 %select2)
+  br label %exit
+
+exit:
+  ret i32 42
+}
+
+define i32 @compare_against_three(i32 %x) {
+; CHECK-LABEL: @compare_against_three(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[TMP0:%.*]] = icmp sgt i32 [[X:%.*]], 3
+; CHECK-NEXT:    br i1 [[TMP0]], label [[CALLFOO:%.*]], label [[EXIT:%.*]]
+; CHECK:       callfoo:
+; CHECK-NEXT:    call void @foo(i32 1)
+; CHECK-NEXT:    br label [[EXIT]]
+; CHECK:       exit:
+; CHECK-NEXT:    ret i32 42
+;
+
+entry:
+  %cmp1 = icmp eq i32 %x, 3
+  %cmp2 = icmp slt i32 %x, 3
+  %select1 = select i1 %cmp2, i32 -1, i32 1
+  %select2 = select i1 %cmp1, i32 0, i32 %select1
+  %cond = icmp sgt i32 %select2, 0
+  br i1 %cond, label %callfoo, label %exit
+
+callfoo:
+  call void @foo(i32 %select2)
+  br label %exit
+
+exit:
+  ret i32 42
+}
+
+define i32 @compare_against_four(i32 %x) {
+; CHECK-LABEL: @compare_against_four(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[TMP0:%.*]] = icmp sgt i32 [[X:%.*]], 4
+; CHECK-NEXT:    br i1 [[TMP0]], label [[CALLFOO:%.*]], label [[EXIT:%.*]]
+; CHECK:       callfoo:
+; CHECK-NEXT:    call void @foo(i32 1)
+; CHECK-NEXT:    br label [[EXIT]]
+; CHECK:       exit:
+; CHECK-NEXT:    ret i32 42
+;
+
+entry:
+  %cmp1 = icmp eq i32 %x, 4
+  %cmp2 = icmp slt i32 %x, 4
+  %select1 = select i1 %cmp2, i32 -1, i32 1
+  %select2 = select i1 %cmp1, i32 0, i32 %select1
+  %cond = icmp sgt i32 %select2, 0
+  br i1 %cond, label %callfoo, label %exit
+
+callfoo:
+  call void @foo(i32 %select2)
+  br label %exit
+
+exit:
+  ret i32 42
+}
+
+define i32 @compare_against_five(i32 %x) {
+; CHECK-LABEL: @compare_against_five(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[TMP0:%.*]] = icmp sgt i32 [[X:%.*]], 5
+; CHECK-NEXT:    br i1 [[TMP0]], label [[CALLFOO:%.*]], label [[EXIT:%.*]]
+; CHECK:       callfoo:
+; CHECK-NEXT:    call void @foo(i32 1)
+; CHECK-NEXT:    br label [[EXIT]]
+; CHECK:       exit:
+; CHECK-NEXT:    ret i32 42
+;
+
+entry:
+  %cmp1 = icmp eq i32 %x, 5
+  %cmp2 = icmp slt i32 %x, 5
+  %select1 = select i1 %cmp2, i32 -1, i32 1
+  %select2 = select i1 %cmp1, i32 0, i32 %select1
+  %cond = icmp sgt i32 %select2, 0
+  br i1 %cond, label %callfoo, label %exit
+
+callfoo:
+  call void @foo(i32 %select2)
+  br label %exit
+
+exit:
+  ret i32 42
+}
+
+define i32 @compare_against_six(i32 %x) {
+; CHECK-LABEL: @compare_against_six(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[TMP0:%.*]] = icmp sgt i32 [[X:%.*]], 6
+; CHECK-NEXT:    br i1 [[TMP0]], label [[CALLFOO:%.*]], label [[EXIT:%.*]]
+; CHECK:       callfoo:
+; CHECK-NEXT:    call void @foo(i32 1)
+; CHECK-NEXT:    br label [[EXIT]]
+; CHECK:       exit:
+; CHECK-NEXT:    ret i32 42
+;
+
+entry:
+  %cmp1 = icmp eq i32 %x, 6
+  %cmp2 = icmp slt i32 %x, 6
+  %select1 = select i1 %cmp2, i32 -1, i32 1
+  %select2 = select i1 %cmp1, i32 0, i32 %select1
+  %cond = icmp sgt i32 %select2, 0
+  br i1 %cond, label %callfoo, label %exit
+
+callfoo:
+  call void @foo(i32 %select2)
+  br label %exit
+
+exit:
+  ret i32 42
+}
+
+; Same as @compare_against_arbitrary_value, but now the three-way comparison
+; returns not idiomatic comparator's result (-1, 0, 1) but some other constants.
+define i32 @compare_against_arbitrary_value_non_idiomatic_1(i32 %x, i32 %c) {
+; CHECK-LABEL: @compare_against_arbitrary_value_non_idiomatic_1(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[TMP0:%.*]] = icmp sgt i32 [[X:%.*]], [[C:%.*]]
+; CHECK-NEXT:    br i1 [[TMP0]], label [[CALLFOO:%.*]], label [[EXIT:%.*]]
+; CHECK:       callfoo:
+; CHECK-NEXT:    call void @foo(i32 425)
+; CHECK-NEXT:    br label [[EXIT]]
+; CHECK:       exit:
+; CHECK-NEXT:    ret i32 42
+;
+
+entry:
+  %cmp1 = icmp eq i32 %x, %c
+  %cmp2 = icmp slt i32 %x, %c
+  %select1 = select i1 %cmp2, i32 -6, i32 425
+  %select2 = select i1 %cmp1, i32 0, i32 %select1
+  %cond = icmp sgt i32 %select2, 0
+  br i1 %cond, label %callfoo, label %exit
+
+callfoo:
+  call void @foo(i32 %select2)
+  br label %exit
+
+exit:
+  ret i32 42
+}
+
+define i32 @compare_against_zero_non_idiomatic_add(i32 %x) {
+; CHECK-LABEL: @compare_against_zero_non_idiomatic_add(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[TMP0:%.*]] = icmp sgt i32 [[X:%.*]], 0
+; CHECK-NEXT:    br i1 [[TMP0]], label [[CALLFOO:%.*]], label [[EXIT:%.*]]
+; CHECK:       callfoo:
+; CHECK-NEXT:    call void @foo(i32 425)
+; CHECK-NEXT:    br label [[EXIT]]
+; CHECK:       exit:
+; CHECK-NEXT:    ret i32 42
+;
+
+entry:
+  %cmp1 = icmp eq i32 %x, 0
+  %cmp2 = icmp slt i32 %x, 0
+  %select1 = select i1 %cmp2, i32 -6, i32 425
+  %select2 = select i1 %cmp1, i32 0, i32 %select1
+  %cond = icmp sgt i32 %select2, 0
+  br i1 %cond, label %callfoo, label %exit
+
+callfoo:
+  call void @foo(i32 %select2)
+  br label %exit
+
+exit:
+  ret i32 42
+}
+
+; Same as @compare_against_arbitrary_value, but now the three-way comparison
+; returns not idiomatic comparator's result (-1, 0, 1) but some other constants.
+define i32 @compare_against_arbitrary_value_non_idiomatic_2(i32 %x, i32 %c) {
+; CHECK-LABEL: @compare_against_arbitrary_value_non_idiomatic_2(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[TMP0:%.*]] = icmp sgt i32 [[X:%.*]], [[C:%.*]]
+; CHECK-NEXT:    br i1 [[TMP0]], label [[CALLFOO:%.*]], label [[EXIT:%.*]]
+; CHECK:       callfoo:
+; CHECK-NEXT:    call void @foo(i32 425)
+; CHECK-NEXT:    br label [[EXIT]]
+; CHECK:       exit:
+; CHECK-NEXT:    ret i32 42
+;
+
+entry:
+  %cmp1 = icmp eq i32 %x, %c
+  %cmp2 = icmp slt i32 %x, %c
+  %select1 = select i1 %cmp2, i32 -5, i32 425
+  %select2 = select i1 %cmp1, i32 0, i32 %select1
+  %cond = icmp sgt i32 %select2, 0
+  br i1 %cond, label %callfoo, label %exit
+
+callfoo:
+  call void @foo(i32 %select2)
+  br label %exit
+
+exit:
+  ret i32 42
+}
+
+define i32 @compare_against_zero_non_idiomatic_or(i32 %x) {
+; CHECK-LABEL: @compare_against_zero_non_idiomatic_or(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[TMP0:%.*]] = icmp sgt i32 [[X:%.*]], 0
+; CHECK-NEXT:    br i1 [[TMP0]], label [[CALLFOO:%.*]], label [[EXIT:%.*]]
+; CHECK:       callfoo:
+; CHECK-NEXT:    call void @foo(i32 425)
+; CHECK-NEXT:    br label [[EXIT]]
+; CHECK:       exit:
+; CHECK-NEXT:    ret i32 42
+;
+
+entry:
+  %cmp1 = icmp eq i32 %x, 0
+  %cmp2 = icmp slt i32 %x, 0
+  %select1 = select i1 %cmp2, i32 -5, i32 425
+  %select2 = select i1 %cmp1, i32 0, i32 %select1
+  %cond = icmp sgt i32 %select2, 0
+  br i1 %cond, label %callfoo, label %exit
+
+callfoo:
+  call void @foo(i32 %select2)
+  br label %exit
+
+exit:
+  ret i32 42
+}
+
+define i32 @compare_against_arbitrary_value_type_mismatch(i64 %x, i64 %c) {
+; CHECK-LABEL: @compare_against_arbitrary_value_type_mismatch(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[TMP0:%.*]] = icmp sgt i64 [[X:%.*]], [[C:%.*]]
+; CHECK-NEXT:    br i1 [[TMP0]], label [[CALLFOO:%.*]], label [[EXIT:%.*]]
+; CHECK:       callfoo:
+; CHECK-NEXT:    call void @foo(i32 1)
+; CHECK-NEXT:    br label [[EXIT]]
+; CHECK:       exit:
+; CHECK-NEXT:    ret i32 42
+;
+
+entry:
+  %cmp1 = icmp eq i64 %x, %c
+  %cmp2 = icmp slt i64 %x, %c
+  %select1 = select i1 %cmp2, i32 -1, i32 1
+  %select2 = select i1 %cmp1, i32 0, i32 %select1
+  %cond = icmp sgt i32 %select2, 0
+  br i1 %cond, label %callfoo, label %exit
+
+callfoo:
+  call void @foo(i32 %select2)
+  br label %exit
+
+exit:
+  ret i32 42
+}
+
+define i32 @compare_against_zero_type_mismatch_idiomatic(i64 %x) {
+; CHECK-LABEL: @compare_against_zero_type_mismatch_idiomatic(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[TMP0:%.*]] = icmp sgt i64 [[X:%.*]], 0
+; CHECK-NEXT:    br i1 [[TMP0]], label [[CALLFOO:%.*]], label [[EXIT:%.*]]
+; CHECK:       callfoo:
+; CHECK-NEXT:    call void @foo(i32 1)
+; CHECK-NEXT:    br label [[EXIT]]
+; CHECK:       exit:
+; CHECK-NEXT:    ret i32 42
+;
+
+entry:
+  %cmp1 = icmp eq i64 %x, 0
+  %cmp2 = icmp slt i64 %x, 0
+  %select1 = select i1 %cmp2, i32 -1, i32 1
+  %select2 = select i1 %cmp1, i32 0, i32 %select1
+  %cond = icmp sgt i32 %select2, 0
+  br i1 %cond, label %callfoo, label %exit
+
+callfoo:
+  call void @foo(i32 %select2)
+  br label %exit
+
+exit:
+  ret i32 42
+}
+
+define i32 @compare_against_zero_type_mismatch_non_idiomatic_1(i64 %x) {
+; CHECK-LABEL: @compare_against_zero_type_mismatch_non_idiomatic_1(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[TMP0:%.*]] = icmp sgt i64 [[X:%.*]], 0
+; CHECK-NEXT:    br i1 [[TMP0]], label [[CALLFOO:%.*]], label [[EXIT:%.*]]
+; CHECK:       callfoo:
+; CHECK-NEXT:    call void @foo(i32 1)
+; CHECK-NEXT:    br label [[EXIT]]
+; CHECK:       exit:
+; CHECK-NEXT:    ret i32 42
+;
+
+entry:
+  %cmp1 = icmp eq i64 %x, 0
+  %cmp2 = icmp slt i64 %x, 0
+  %select1 = select i1 %cmp2, i32 -7, i32 1
+  %select2 = select i1 %cmp1, i32 0, i32 %select1
+  %cond = icmp sgt i32 %select2, 0
+  br i1 %cond, label %callfoo, label %exit
+
+callfoo:
+  call void @foo(i32 %select2)
+  br label %exit
+
+exit:
+  ret i32 42
+}
+
+define i32 @compare_against_zero_type_mismatch_non_idiomatic_2(i64 %x) {
+; CHECK-LABEL: @compare_against_zero_type_mismatch_non_idiomatic_2(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[TMP0:%.*]] = icmp sgt i64 [[X:%.*]], 0
+; CHECK-NEXT:    br i1 [[TMP0]], label [[CALLFOO:%.*]], label [[EXIT:%.*]]
+; CHECK:       callfoo:
+; CHECK-NEXT:    call void @foo(i32 1)
+; CHECK-NEXT:    br label [[EXIT]]
+; CHECK:       exit:
+; CHECK-NEXT:    ret i32 42
+;
+
+entry:
+  %cmp1 = icmp eq i64 %x, 0
+  %cmp2 = icmp slt i64 %x, 0
+  %select1 = select i1 %cmp2, i32 -6, i32 1
+  %select2 = select i1 %cmp1, i32 0, i32 %select1
+  %cond = icmp sgt i32 %select2, 0
+  br i1 %cond, label %callfoo, label %exit
+
+callfoo:
+  call void @foo(i32 %select2)
+  br label %exit
+
+exit:
+  ret i32 42
+}
+

Added: llvm/trunk/test/Transforms/InstCombine/unsigned_saturated_sub.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/unsigned_saturated_sub.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/unsigned_saturated_sub.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/unsigned_saturated_sub.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,160 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt -instcombine -S < %s | FileCheck %s
+
+; Canonicalization of unsigned saturated subtraction idioms to
+; usub.sat() intrinsics is tested here.
+
+declare void @use(i64)
+
+; (a > b) ? a - b : 0 -> usub.sat(a, b)
+
+define i64 @max_sub_ugt(i64 %a, i64 %b) {
+; CHECK-LABEL: @max_sub_ugt(
+; CHECK-NEXT:    [[TMP1:%.*]] = call i64 @llvm.usub.sat.i64(i64 [[A:%.*]], i64 [[B:%.*]])
+; CHECK-NEXT:    ret i64 [[TMP1]]
+;
+  %cmp = icmp ugt i64 %a, %b
+  %sub = sub i64 %a, %b
+  %sel = select i1 %cmp, i64 %sub ,i64 0
+  ret i64 %sel
+}
+
+; (a >= b) ? a - b : 0 -> usub.sat(a, b)
+
+define i64 @max_sub_uge(i64 %a, i64 %b) {
+; CHECK-LABEL: @max_sub_uge(
+; CHECK-NEXT:    [[TMP1:%.*]] = call i64 @llvm.usub.sat.i64(i64 [[A:%.*]], i64 [[B:%.*]])
+; CHECK-NEXT:    ret i64 [[TMP1]]
+;
+  %cmp = icmp uge i64 %a, %b
+  %sub = sub i64 %a, %b
+  %sel = select i1 %cmp, i64 %sub ,i64 0
+  ret i64 %sel
+}
+
+; Again, with vectors:
+; (a > b) ? a - b : 0 -> usub.sat(a, b)
+
+define <4 x i32> @max_sub_ugt_vec(<4 x i32> %a, <4 x i32> %b) {
+; CHECK-LABEL: @max_sub_ugt_vec(
+; CHECK-NEXT:    [[TMP1:%.*]] = call <4 x i32> @llvm.usub.sat.v4i32(<4 x i32> [[A:%.*]], <4 x i32> [[B:%.*]])
+; CHECK-NEXT:    ret <4 x i32> [[TMP1]]
+;
+  %cmp = icmp ugt <4 x i32> %a, %b
+  %sub = sub <4 x i32> %a, %b
+  %sel = select <4 x i1> %cmp, <4 x i32> %sub, <4 x i32> zeroinitializer
+  ret <4 x i32> %sel
+}
+
+; Use extra ops to thwart icmp swapping canonicalization.
+; (b < a) ? a - b : 0 -> usub.sat(a, b)
+
+define i64 @max_sub_ult(i64 %a, i64 %b) {
+; CHECK-LABEL: @max_sub_ult(
+; CHECK-NEXT:    [[TMP1:%.*]] = call i64 @llvm.usub.sat.i64(i64 [[A:%.*]], i64 [[B:%.*]])
+; CHECK-NEXT:    [[EXTRASUB:%.*]] = sub i64 [[B]], [[A]]
+; CHECK-NEXT:    call void @use(i64 [[EXTRASUB]])
+; CHECK-NEXT:    ret i64 [[TMP1]]
+;
+  %cmp = icmp ult i64 %b, %a
+  %sub = sub i64 %a, %b
+  %sel = select i1 %cmp, i64 %sub ,i64 0
+  %extrasub = sub i64 %b, %a
+  call void @use(i64 %extrasub)
+  ret i64 %sel
+}
+
+; (b > a) ? 0 : a - b -> usub.sat(a, b)
+
+define i64 @max_sub_ugt_sel_swapped(i64 %a, i64 %b) {
+; CHECK-LABEL: @max_sub_ugt_sel_swapped(
+; CHECK-NEXT:    [[TMP1:%.*]] = call i64 @llvm.usub.sat.i64(i64 [[A:%.*]], i64 [[B:%.*]])
+; CHECK-NEXT:    [[EXTRASUB:%.*]] = sub i64 [[B]], [[A]]
+; CHECK-NEXT:    call void @use(i64 [[EXTRASUB]])
+; CHECK-NEXT:    ret i64 [[TMP1]]
+;
+  %cmp = icmp ugt i64 %b, %a
+  %sub = sub i64 %a, %b
+  %sel = select i1 %cmp, i64 0 ,i64 %sub
+  %extrasub = sub i64 %b, %a
+  call void @use(i64 %extrasub)
+  ret i64 %sel
+}
+
+; (a < b) ? 0 : a - b -> usub.sat(a, b)
+
+define i64 @max_sub_ult_sel_swapped(i64 %a, i64 %b) {
+; CHECK-LABEL: @max_sub_ult_sel_swapped(
+; CHECK-NEXT:    [[TMP1:%.*]] = call i64 @llvm.usub.sat.i64(i64 [[A:%.*]], i64 [[B:%.*]])
+; CHECK-NEXT:    ret i64 [[TMP1]]
+;
+  %cmp = icmp ult i64 %a, %b
+  %sub = sub i64 %a, %b
+  %sel = select i1 %cmp, i64 0 ,i64 %sub
+  ret i64 %sel
+}
+
+; ((a > b) ? b - a : 0) -> -usub.sat(a, b)
+
+define i64 @neg_max_sub_ugt(i64 %a, i64 %b) {
+; CHECK-LABEL: @neg_max_sub_ugt(
+; CHECK-NEXT:    [[TMP1:%.*]] = call i64 @llvm.usub.sat.i64(i64 [[A:%.*]], i64 [[B:%.*]])
+; CHECK-NEXT:    [[TMP2:%.*]] = sub i64 0, [[TMP1]]
+; CHECK-NEXT:    [[EXTRASUB:%.*]] = sub i64 [[A]], [[B]]
+; CHECK-NEXT:    call void @use(i64 [[EXTRASUB]])
+; CHECK-NEXT:    ret i64 [[TMP2]]
+;
+  %cmp = icmp ugt i64 %a, %b
+  %sub = sub i64 %b, %a
+  %sel = select i1 %cmp, i64 %sub ,i64 0
+  %extrasub = sub i64 %a, %b
+  call void @use(i64 %extrasub)
+  ret i64 %sel
+}
+
+; ((b < a) ? b - a : 0) -> -usub.sat(a, b)
+
+define i64 @neg_max_sub_ult(i64 %a, i64 %b) {
+; CHECK-LABEL: @neg_max_sub_ult(
+; CHECK-NEXT:    [[TMP1:%.*]] = call i64 @llvm.usub.sat.i64(i64 [[A:%.*]], i64 [[B:%.*]])
+; CHECK-NEXT:    [[TMP2:%.*]] = sub i64 0, [[TMP1]]
+; CHECK-NEXT:    ret i64 [[TMP2]]
+;
+  %cmp = icmp ult i64 %b, %a
+  %sub = sub i64 %b, %a
+  %sel = select i1 %cmp, i64 %sub ,i64 0
+  ret i64 %sel
+}
+
+; ((b > a) ? 0 : b - a) -> -usub.sat(a, b)
+
+define i64 @neg_max_sub_ugt_sel_swapped(i64 %a, i64 %b) {
+; CHECK-LABEL: @neg_max_sub_ugt_sel_swapped(
+; CHECK-NEXT:    [[TMP1:%.*]] = call i64 @llvm.usub.sat.i64(i64 [[A:%.*]], i64 [[B:%.*]])
+; CHECK-NEXT:    [[TMP2:%.*]] = sub i64 0, [[TMP1]]
+; CHECK-NEXT:    ret i64 [[TMP2]]
+;
+  %cmp = icmp ugt i64 %b, %a
+  %sub = sub i64 %b, %a
+  %sel = select i1 %cmp, i64 0 ,i64 %sub
+  ret i64 %sel
+}
+
+; ((a < b) ? 0 : b - a) -> -usub.sat(a, b)
+
+define i64 @neg_max_sub_ult_sel_swapped(i64 %a, i64 %b) {
+; CHECK-LABEL: @neg_max_sub_ult_sel_swapped(
+; CHECK-NEXT:    [[TMP1:%.*]] = call i64 @llvm.usub.sat.i64(i64 [[A:%.*]], i64 [[B:%.*]])
+; CHECK-NEXT:    [[TMP2:%.*]] = sub i64 0, [[TMP1]]
+; CHECK-NEXT:    [[EXTRASUB:%.*]] = sub i64 [[A]], [[B]]
+; CHECK-NEXT:    call void @use(i64 [[EXTRASUB]])
+; CHECK-NEXT:    ret i64 [[TMP2]]
+;
+  %cmp = icmp ult i64 %a, %b
+  %sub = sub i64 %b, %a
+  %sel = select i1 %cmp, i64 0 ,i64 %sub
+  %extrasub = sub i64 %a, %b
+  call void @use(i64 %extrasub)
+  ret i64 %sel
+}
+

Added: llvm/trunk/test/Transforms/InstCombine/urem-simplify-bug.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/urem-simplify-bug.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/urem-simplify-bug.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/urem-simplify-bug.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,36 @@
+; RUN: opt < %s -instcombine -S | FileCheck %s
+
+ at .str = internal constant [5 x i8] c"foo\0A\00"
+ at .str1 = internal constant [5 x i8] c"bar\0A\00"
+
+define i32 @main() nounwind  {
+entry:
+  %x = call i32 @func_11() nounwind
+  %tmp3 = or i32 %x, -5
+  %tmp5 = urem i32 251, %tmp3
+  %tmp6 = icmp ne i32 %tmp5, 0
+  %tmp67 = zext i1 %tmp6 to i32
+  %tmp9 = urem i32 %tmp67, 95
+  %tmp10 = and i32 %tmp9, 1
+  %tmp12 = icmp eq i32 %tmp10, 0
+  br i1 %tmp12, label %bb14, label %bb
+
+bb:
+  br label %bb15
+
+bb14:
+  br label %bb15
+
+bb15:
+  %iftmp.0.0 = phi i8* [ getelementptr ([5 x i8], [5 x i8]* @.str1, i32 0, i32 0), %bb14 ], [ getelementptr ([5 x i8], [5 x i8]* @.str, i32 0, i32 0), %bb ]
+  %tmp17 = call i32 (i8*, ...) @printf(i8* %iftmp.0.0) nounwind
+  ret i32 0
+}
+
+; CHECK-LABEL: define i32 @main(
+; CHECK: call i32 @func_11()
+; CHECK-NEXT: br i1 false, label %bb14, label %bb
+
+declare i32 @func_11()
+
+declare i32 @printf(i8*, ...) nounwind

Added: llvm/trunk/test/Transforms/InstCombine/vararg.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/vararg.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/vararg.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/vararg.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,30 @@
+; RUN: opt < %s -instcombine -S | FileCheck %s
+
+%struct.__va_list = type { i8*, i8*, i8*, i32, i32 }
+
+declare void @llvm.lifetime.start.p0i8(i64, i8* nocapture)
+declare void @llvm.lifetime.end.p0i8(i64, i8* nocapture)
+declare void @llvm.va_start(i8*)
+declare void @llvm.va_end(i8*)
+declare void @llvm.va_copy(i8*, i8*)
+
+define i32 @func(i8* nocapture readnone %fmt, ...) {
+; CHECK-LABEL: @func(
+; CHECK: entry:
+; CHECK-NEXT: ret i32 0
+entry:
+  %va0 = alloca %struct.__va_list, align 8
+  %va1 = alloca %struct.__va_list, align 8
+  %0 = bitcast %struct.__va_list* %va0 to i8*
+  %1 = bitcast %struct.__va_list* %va1 to i8*
+  call void @llvm.lifetime.start.p0i8(i64 32, i8* %0)
+  call void @llvm.va_start(i8* %0)
+  call void @llvm.lifetime.start.p0i8(i64 32, i8* %1)
+  call void @llvm.va_copy(i8* %1, i8* %0)
+  call void @llvm.va_end(i8* %1)
+  call void @llvm.lifetime.end.p0i8(i64 32, i8* %1)
+  call void @llvm.va_end(i8* %0)
+  call void @llvm.lifetime.end.p0i8(i64 32, i8* %0)
+  ret i32 0
+}
+

Added: llvm/trunk/test/Transforms/InstCombine/vec-binop-select.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/vec-binop-select.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/vec-binop-select.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/vec-binop-select.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,275 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt < %s -instcombine -S | FileCheck %s
+
+; Non-canonical mask
+
+define <4 x i32> @and(<4 x i32> %x, <4 x i32> %y) {
+; CHECK-LABEL: @and(
+; CHECK-NEXT:    [[R:%.*]] = and <4 x i32> [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    ret <4 x i32> [[R]]
+;
+  %sel1 = shufflevector <4 x i32> %x, <4 x i32> %y, <4 x i32> <i32 0, i32 5, i32 6, i32 3>
+  %sel2 = shufflevector <4 x i32> %x, <4 x i32> %y, <4 x i32> <i32 4, i32 1, i32 2, i32 7>
+  %r = and <4 x i32> %sel1, %sel2
+  ret <4 x i32> %r
+}
+
+define <4 x i32> @or(<4 x i32> %x, <4 x i32> %y) {
+; CHECK-LABEL: @or(
+; CHECK-NEXT:    [[R:%.*]] = or <4 x i32> [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    ret <4 x i32> [[R]]
+;
+  %sel1 = shufflevector <4 x i32> %x, <4 x i32> %y, <4 x i32> <i32 0, i32 5, i32 6, i32 3>
+  %sel2 = shufflevector <4 x i32> %y, <4 x i32> %x, <4 x i32> <i32 0, i32 5, i32 6, i32 3>
+  %r = or <4 x i32> %sel1, %sel2
+  ret <4 x i32> %r
+}
+
+; Non-canonical masks
+
+define <4 x i32> @xor(<4 x i32> %x, <4 x i32> %y) {
+; CHECK-LABEL: @xor(
+; CHECK-NEXT:    [[R:%.*]] = xor <4 x i32> [[Y:%.*]], [[X:%.*]]
+; CHECK-NEXT:    ret <4 x i32> [[R]]
+;
+  %sel1 = shufflevector <4 x i32> %x, <4 x i32> %y, <4 x i32> <i32 4, i32 1, i32 6, i32 3>
+  %sel2 = shufflevector <4 x i32> %y, <4 x i32> %x, <4 x i32> <i32 4, i32 1, i32 6, i32 3>
+  %r = xor <4 x i32> %sel1, %sel2
+  ret <4 x i32> %r
+}
+
+; Flags
+
+define <4 x i32> @add(<4 x i32> %x, <4 x i32> %y) {
+; CHECK-LABEL: @add(
+; CHECK-NEXT:    [[R:%.*]] = add nsw <4 x i32> [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    ret <4 x i32> [[R]]
+;
+  %sel1 = shufflevector <4 x i32> %x, <4 x i32> %y, <4 x i32> <i32 0, i32 5, i32 2, i32 7>
+  %sel2 = shufflevector <4 x i32> %y, <4 x i32> %x, <4 x i32> <i32 0, i32 5, i32 2, i32 7>
+  %r = add nsw <4 x i32> %sel1, %sel2
+  ret <4 x i32> %r
+}
+
+; Negative test - wrong operand
+
+define <4 x i32> @add_wrong_op(<4 x i32> %x, <4 x i32> %y, <4 x i32> %z) {
+; CHECK-LABEL: @add_wrong_op(
+; CHECK-NEXT:    [[SEL1:%.*]] = shufflevector <4 x i32> [[X:%.*]], <4 x i32> [[Y:%.*]], <4 x i32> <i32 0, i32 5, i32 2, i32 7>
+; CHECK-NEXT:    [[SEL2:%.*]] = shufflevector <4 x i32> [[Y]], <4 x i32> [[Z:%.*]], <4 x i32> <i32 0, i32 5, i32 2, i32 7>
+; CHECK-NEXT:    [[R:%.*]] = add nsw <4 x i32> [[SEL1]], [[SEL2]]
+; CHECK-NEXT:    ret <4 x i32> [[R]]
+;
+  %sel1 = shufflevector <4 x i32> %x, <4 x i32> %y, <4 x i32> <i32 0, i32 5, i32 2, i32 7>
+  %sel2 = shufflevector <4 x i32> %y, <4 x i32> %z, <4 x i32> <i32 0, i32 5, i32 2, i32 7>
+  %r = add nsw <4 x i32> %sel1, %sel2
+  ret <4 x i32> %r
+}
+
+; Negative test - wrong mask (but we could handle this...)
+
+define <4 x i32> @add_non_select_mask(<4 x i32> %x, <4 x i32> %y) {
+; CHECK-LABEL: @add_non_select_mask(
+; CHECK-NEXT:    [[SEL1:%.*]] = shufflevector <4 x i32> [[X:%.*]], <4 x i32> [[Y:%.*]], <4 x i32> <i32 1, i32 5, i32 2, i32 7>
+; CHECK-NEXT:    [[SEL2:%.*]] = shufflevector <4 x i32> [[Y]], <4 x i32> [[X]], <4 x i32> <i32 1, i32 5, i32 2, i32 7>
+; CHECK-NEXT:    [[R:%.*]] = add nsw <4 x i32> [[SEL1]], [[SEL2]]
+; CHECK-NEXT:    ret <4 x i32> [[R]]
+;
+  %sel1 = shufflevector <4 x i32> %x, <4 x i32> %y, <4 x i32> <i32 1, i32 5, i32 2, i32 7>
+  %sel2 = shufflevector <4 x i32> %y, <4 x i32> %x, <4 x i32> <i32 1, i32 5, i32 2, i32 7>
+  %r = add nsw <4 x i32> %sel1, %sel2
+  ret <4 x i32> %r
+}
+
+; Negative test - wrong mask (but we could handle this...)
+
+define <4 x i32> @add_masks_with_undefs(<4 x i32> %x, <4 x i32> %y) {
+; CHECK-LABEL: @add_masks_with_undefs(
+; CHECK-NEXT:    [[SEL1:%.*]] = shufflevector <4 x i32> [[X:%.*]], <4 x i32> [[Y:%.*]], <4 x i32> <i32 undef, i32 5, i32 2, i32 7>
+; CHECK-NEXT:    [[SEL2:%.*]] = shufflevector <4 x i32> [[Y]], <4 x i32> [[X]], <4 x i32> <i32 undef, i32 5, i32 2, i32 7>
+; CHECK-NEXT:    [[R:%.*]] = add nsw <4 x i32> [[SEL1]], [[SEL2]]
+; CHECK-NEXT:    ret <4 x i32> [[R]]
+;
+  %sel1 = shufflevector <4 x i32> %x, <4 x i32> %y, <4 x i32> <i32 undef, i32 5, i32 2, i32 7>
+  %sel2 = shufflevector <4 x i32> %y, <4 x i32> %x, <4 x i32> <i32 undef, i32 5, i32 2, i32 7>
+  %r = add nsw <4 x i32> %sel1, %sel2
+  ret <4 x i32> %r
+}
+
+; Non-commutative opcode
+
+define <4 x i32> @sub(<4 x i32> %x, <4 x i32> %y) {
+; CHECK-LABEL: @sub(
+; CHECK-NEXT:    [[SEL1:%.*]] = shufflevector <4 x i32> [[X:%.*]], <4 x i32> [[Y:%.*]], <4 x i32> <i32 0, i32 1, i32 6, i32 3>
+; CHECK-NEXT:    [[SEL2:%.*]] = shufflevector <4 x i32> [[Y]], <4 x i32> [[X]], <4 x i32> <i32 0, i32 1, i32 6, i32 3>
+; CHECK-NEXT:    [[R:%.*]] = sub <4 x i32> [[SEL1]], [[SEL2]]
+; CHECK-NEXT:    ret <4 x i32> [[R]]
+;
+  %sel1 = shufflevector <4 x i32> %x, <4 x i32> %y, <4 x i32> <i32 0, i32 1, i32 6, i32 3>
+  %sel2 = shufflevector <4 x i32> %y, <4 x i32> %x, <4 x i32> <i32 0, i32 1, i32 6, i32 3>
+  %r = sub <4 x i32> %sel1, %sel2
+  ret <4 x i32> %r
+}
+
+define <4 x i32> @mul(<4 x i32> %x, <4 x i32> %y) {
+; CHECK-LABEL: @mul(
+; CHECK-NEXT:    [[R:%.*]] = mul nuw <4 x i32> [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    ret <4 x i32> [[R]]
+;
+  %sel1 = shufflevector <4 x i32> %x, <4 x i32> %y, <4 x i32> <i32 0, i32 1, i32 6, i32 3>
+  %sel2 = shufflevector <4 x i32> %y, <4 x i32> %x, <4 x i32> <i32 0, i32 1, i32 6, i32 3>
+  %r = mul nuw <4 x i32> %sel1, %sel2
+  ret <4 x i32> %r
+}
+
+define <4 x i32> @sdiv(<4 x i32> %x, <4 x i32> %y) {
+; CHECK-LABEL: @sdiv(
+; CHECK-NEXT:    [[SEL1:%.*]] = shufflevector <4 x i32> [[X:%.*]], <4 x i32> [[Y:%.*]], <4 x i32> <i32 0, i32 1, i32 6, i32 7>
+; CHECK-NEXT:    [[SEL2:%.*]] = shufflevector <4 x i32> [[Y]], <4 x i32> [[X]], <4 x i32> <i32 0, i32 1, i32 6, i32 7>
+; CHECK-NEXT:    [[R:%.*]] = sdiv <4 x i32> [[SEL1]], [[SEL2]]
+; CHECK-NEXT:    ret <4 x i32> [[R]]
+;
+  %sel1 = shufflevector <4 x i32> %x, <4 x i32> %y, <4 x i32> <i32 0, i32 1, i32 6, i32 7>
+  %sel2 = shufflevector <4 x i32> %y, <4 x i32> %x, <4 x i32> <i32 0, i32 1, i32 6, i32 7>
+  %r = sdiv <4 x i32> %sel1, %sel2
+  ret <4 x i32> %r
+}
+
+define <4 x i32> @udiv(<4 x i32> %x, <4 x i32> %y) {
+; CHECK-LABEL: @udiv(
+; CHECK-NEXT:    [[SEL1:%.*]] = shufflevector <4 x i32> [[X:%.*]], <4 x i32> [[Y:%.*]], <4 x i32> <i32 0, i32 1, i32 6, i32 3>
+; CHECK-NEXT:    [[SEL2:%.*]] = shufflevector <4 x i32> [[Y]], <4 x i32> [[X]], <4 x i32> <i32 0, i32 1, i32 6, i32 3>
+; CHECK-NEXT:    [[R:%.*]] = udiv <4 x i32> [[SEL1]], [[SEL2]]
+; CHECK-NEXT:    ret <4 x i32> [[R]]
+;
+  %sel1 = shufflevector <4 x i32> %x, <4 x i32> %y, <4 x i32> <i32 0, i32 1, i32 6, i32 3>
+  %sel2 = shufflevector <4 x i32> %y, <4 x i32> %x, <4 x i32> <i32 0, i32 1, i32 6, i32 3>
+  %r = udiv <4 x i32> %sel1, %sel2
+  ret <4 x i32> %r
+}
+
+define <4 x i32> @srem(<4 x i32> %x, <4 x i32> %y) {
+; CHECK-LABEL: @srem(
+; CHECK-NEXT:    [[SEL1:%.*]] = shufflevector <4 x i32> [[X:%.*]], <4 x i32> [[Y:%.*]], <4 x i32> <i32 0, i32 1, i32 6, i32 7>
+; CHECK-NEXT:    [[SEL2:%.*]] = shufflevector <4 x i32> [[Y]], <4 x i32> [[X]], <4 x i32> <i32 0, i32 1, i32 6, i32 7>
+; CHECK-NEXT:    [[R:%.*]] = srem <4 x i32> [[SEL1]], [[SEL2]]
+; CHECK-NEXT:    ret <4 x i32> [[R]]
+;
+  %sel1 = shufflevector <4 x i32> %x, <4 x i32> %y, <4 x i32> <i32 0, i32 1, i32 6, i32 7>
+  %sel2 = shufflevector <4 x i32> %y, <4 x i32> %x, <4 x i32> <i32 0, i32 1, i32 6, i32 7>
+  %r = srem <4 x i32> %sel1, %sel2
+  ret <4 x i32> %r
+}
+
+define <4 x i32> @urem(<4 x i32> %x, <4 x i32> %y) {
+; CHECK-LABEL: @urem(
+; CHECK-NEXT:    [[SEL1:%.*]] = shufflevector <4 x i32> [[X:%.*]], <4 x i32> [[Y:%.*]], <4 x i32> <i32 0, i32 1, i32 6, i32 3>
+; CHECK-NEXT:    [[SEL2:%.*]] = shufflevector <4 x i32> [[Y]], <4 x i32> [[X]], <4 x i32> <i32 0, i32 1, i32 6, i32 3>
+; CHECK-NEXT:    [[R:%.*]] = urem <4 x i32> [[SEL1]], [[SEL2]]
+; CHECK-NEXT:    ret <4 x i32> [[R]]
+;
+  %sel1 = shufflevector <4 x i32> %x, <4 x i32> %y, <4 x i32> <i32 0, i32 1, i32 6, i32 3>
+  %sel2 = shufflevector <4 x i32> %y, <4 x i32> %x, <4 x i32> <i32 0, i32 1, i32 6, i32 3>
+  %r = urem <4 x i32> %sel1, %sel2
+  ret <4 x i32> %r
+}
+
+define <4 x i32> @shl(<4 x i32> %x, <4 x i32> %y) {
+; CHECK-LABEL: @shl(
+; CHECK-NEXT:    [[SEL1:%.*]] = shufflevector <4 x i32> [[X:%.*]], <4 x i32> [[Y:%.*]], <4 x i32> <i32 0, i32 1, i32 6, i32 7>
+; CHECK-NEXT:    [[SEL2:%.*]] = shufflevector <4 x i32> [[Y]], <4 x i32> [[X]], <4 x i32> <i32 0, i32 1, i32 6, i32 7>
+; CHECK-NEXT:    [[R:%.*]] = shl nsw <4 x i32> [[SEL1]], [[SEL2]]
+; CHECK-NEXT:    ret <4 x i32> [[R]]
+;
+  %sel1 = shufflevector <4 x i32> %x, <4 x i32> %y, <4 x i32> <i32 0, i32 1, i32 6, i32 7>
+  %sel2 = shufflevector <4 x i32> %y, <4 x i32> %x, <4 x i32> <i32 0, i32 1, i32 6, i32 7>
+  %r = shl nsw <4 x i32> %sel1, %sel2
+  ret <4 x i32> %r
+}
+
+define <4 x i32> @lshr(<4 x i32> %x, <4 x i32> %y) {
+; CHECK-LABEL: @lshr(
+; CHECK-NEXT:    [[SEL1:%.*]] = shufflevector <4 x i32> [[X:%.*]], <4 x i32> [[Y:%.*]], <4 x i32> <i32 0, i32 5, i32 6, i32 3>
+; CHECK-NEXT:    [[SEL2:%.*]] = shufflevector <4 x i32> [[Y]], <4 x i32> [[X]], <4 x i32> <i32 0, i32 5, i32 6, i32 3>
+; CHECK-NEXT:    [[R:%.*]] = lshr exact <4 x i32> [[SEL1]], [[SEL2]]
+; CHECK-NEXT:    ret <4 x i32> [[R]]
+;
+  %sel1 = shufflevector <4 x i32> %x, <4 x i32> %y, <4 x i32> <i32 0, i32 5, i32 6, i32 3>
+  %sel2 = shufflevector <4 x i32> %y, <4 x i32> %x, <4 x i32> <i32 0, i32 5, i32 6, i32 3>
+  %r = lshr exact <4 x i32> %sel1, %sel2
+  ret <4 x i32> %r
+}
+
+define <4 x i32> @ashr(<4 x i32> %x, <4 x i32> %y) {
+; CHECK-LABEL: @ashr(
+; CHECK-NEXT:    [[SEL1:%.*]] = shufflevector <4 x i32> [[Y:%.*]], <4 x i32> [[X:%.*]], <4 x i32> <i32 0, i32 5, i32 2, i32 7>
+; CHECK-NEXT:    [[SEL2:%.*]] = shufflevector <4 x i32> [[X]], <4 x i32> [[Y]], <4 x i32> <i32 0, i32 5, i32 2, i32 7>
+; CHECK-NEXT:    [[R:%.*]] = ashr <4 x i32> [[SEL1]], [[SEL2]]
+; CHECK-NEXT:    ret <4 x i32> [[R]]
+;
+  %sel1 = shufflevector <4 x i32> %x, <4 x i32> %y, <4 x i32> <i32 4, i32 1, i32 6, i32 3>
+  %sel2 = shufflevector <4 x i32> %y, <4 x i32> %x, <4 x i32> <i32 4, i32 1, i32 6, i32 3>
+  %r = ashr <4 x i32> %sel1, %sel2
+  ret <4 x i32> %r
+}
+
+define <4 x float> @fadd(<4 x float> %x, <4 x float> %y) {
+; CHECK-LABEL: @fadd(
+; CHECK-NEXT:    [[R:%.*]] = fadd <4 x float> [[Y:%.*]], [[X:%.*]]
+; CHECK-NEXT:    ret <4 x float> [[R]]
+;
+  %sel1 = shufflevector <4 x float> %x, <4 x float> %y, <4 x i32> <i32 4, i32 1, i32 6, i32 3>
+  %sel2 = shufflevector <4 x float> %y, <4 x float> %x, <4 x i32> <i32 4, i32 1, i32 6, i32 3>
+  %r = fadd <4 x float> %sel1, %sel2
+  ret <4 x float> %r
+}
+
+define <4 x float> @fsub(<4 x float> %x, <4 x float> %y) {
+; CHECK-LABEL: @fsub(
+; CHECK-NEXT:    [[SEL1:%.*]] = shufflevector <4 x float> [[Y:%.*]], <4 x float> [[X:%.*]], <4 x i32> <i32 0, i32 5, i32 2, i32 7>
+; CHECK-NEXT:    [[SEL2:%.*]] = shufflevector <4 x float> [[X]], <4 x float> [[Y]], <4 x i32> <i32 0, i32 5, i32 2, i32 7>
+; CHECK-NEXT:    [[R:%.*]] = fsub fast <4 x float> [[SEL1]], [[SEL2]]
+; CHECK-NEXT:    ret <4 x float> [[R]]
+;
+  %sel1 = shufflevector <4 x float> %x, <4 x float> %y, <4 x i32> <i32 4, i32 1, i32 6, i32 3>
+  %sel2 = shufflevector <4 x float> %y, <4 x float> %x, <4 x i32> <i32 4, i32 1, i32 6, i32 3>
+  %r = fsub fast <4 x float> %sel1, %sel2
+  ret <4 x float> %r
+}
+
+define <4 x double> @fmul(<4 x double> %x, <4 x double> %y) {
+; CHECK-LABEL: @fmul(
+; CHECK-NEXT:    [[R:%.*]] = fmul nnan <4 x double> [[Y:%.*]], [[X:%.*]]
+; CHECK-NEXT:    ret <4 x double> [[R]]
+;
+  %sel1 = shufflevector <4 x double> %x, <4 x double> %y, <4 x i32> <i32 4, i32 1, i32 6, i32 3>
+  %sel2 = shufflevector <4 x double> %y, <4 x double> %x, <4 x i32> <i32 4, i32 1, i32 6, i32 3>
+  %r = fmul nnan <4 x double> %sel1, %sel2
+  ret <4 x double> %r
+}
+
+define <4 x double> @fdiv(<4 x double> %x, <4 x double> %y) {
+; CHECK-LABEL: @fdiv(
+; CHECK-NEXT:    [[SEL1:%.*]] = shufflevector <4 x double> [[Y:%.*]], <4 x double> [[X:%.*]], <4 x i32> <i32 0, i32 5, i32 2, i32 7>
+; CHECK-NEXT:    [[SEL2:%.*]] = shufflevector <4 x double> [[X]], <4 x double> [[Y]], <4 x i32> <i32 0, i32 5, i32 2, i32 7>
+; CHECK-NEXT:    [[R:%.*]] = fdiv nnan arcp <4 x double> [[SEL1]], [[SEL2]]
+; CHECK-NEXT:    ret <4 x double> [[R]]
+;
+  %sel1 = shufflevector <4 x double> %x, <4 x double> %y, <4 x i32> <i32 4, i32 1, i32 6, i32 3>
+  %sel2 = shufflevector <4 x double> %y, <4 x double> %x, <4 x i32> <i32 4, i32 1, i32 6, i32 3>
+  %r = fdiv arcp nnan <4 x double> %sel1, %sel2
+  ret <4 x double> %r
+}
+
+define <4 x double> @frem(<4 x double> %x, <4 x double> %y) {
+; CHECK-LABEL: @frem(
+; CHECK-NEXT:    [[SEL1:%.*]] = shufflevector <4 x double> [[Y:%.*]], <4 x double> [[X:%.*]], <4 x i32> <i32 0, i32 5, i32 2, i32 7>
+; CHECK-NEXT:    [[SEL2:%.*]] = shufflevector <4 x double> [[X]], <4 x double> [[Y]], <4 x i32> <i32 0, i32 5, i32 2, i32 7>
+; CHECK-NEXT:    [[R:%.*]] = frem <4 x double> [[SEL1]], [[SEL2]]
+; CHECK-NEXT:    ret <4 x double> [[R]]
+;
+  %sel1 = shufflevector <4 x double> %x, <4 x double> %y, <4 x i32> <i32 4, i32 1, i32 6, i32 3>
+  %sel2 = shufflevector <4 x double> %y, <4 x double> %x, <4 x i32> <i32 4, i32 1, i32 6, i32 3>
+  %r = frem <4 x double> %sel1, %sel2
+  ret <4 x double> %r
+}

Added: llvm/trunk/test/Transforms/InstCombine/vec_demanded_elts.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/vec_demanded_elts.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/vec_demanded_elts.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/vec_demanded_elts.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,640 @@
+; 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"
+
+define i32 @test2(float %f) {
+; CHECK-LABEL: @test2(
+; CHECK-NEXT:    [[TMP5:%.*]] = fmul float [[F:%.*]], [[F]]
+; CHECK-NEXT:    [[TMP21:%.*]] = bitcast float [[TMP5]] to i32
+; CHECK-NEXT:    ret i32 [[TMP21]]
+;
+  %tmp5 = fmul float %f, %f
+  %tmp9 = insertelement <4 x float> undef, float %tmp5, i32 0
+  %tmp10 = insertelement <4 x float> %tmp9, float 0.000000e+00, i32 1
+  %tmp11 = insertelement <4 x float> %tmp10, float 0.000000e+00, i32 2
+  %tmp12 = insertelement <4 x float> %tmp11, float 0.000000e+00, i32 3
+  %tmp19 = bitcast <4 x float> %tmp12 to <4 x i32>
+  %tmp21 = extractelement <4 x i32> %tmp19, i32 0
+  ret i32 %tmp21
+}
+
+define void @get_image() nounwind {
+; CHECK-LABEL: @get_image(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[TMP0:%.*]] = call i32 @fgetc(i8* null) #0
+; CHECK-NEXT:    br i1 false, label [[BB2:%.*]], label [[BB3:%.*]]
+; CHECK:       bb2:
+; CHECK-NEXT:    br label [[BB3]]
+; CHECK:       bb3:
+; CHECK-NEXT:    unreachable
+;
+entry:
+  %0 = call i32 @fgetc(i8* null) nounwind               ; <i32> [#uses=1]
+  %1 = trunc i32 %0 to i8         ; <i8> [#uses=1]
+  %tmp2 = insertelement <100 x i8> zeroinitializer, i8 %1, i32 1          ; <<100 x i8>> [#uses=1]
+  %tmp1 = extractelement <100 x i8> %tmp2, i32 0          ; <i8> [#uses=1]
+  %2 = icmp eq i8 %tmp1, 80               ; <i1> [#uses=1]
+  br i1 %2, label %bb2, label %bb3
+
+bb2:            ; preds = %entry
+  br label %bb3
+
+bb3:            ; preds = %bb2, %entry
+  unreachable
+}
+
+; PR4340
+define void @vac(<4 x float>* nocapture %a) nounwind {
+; CHECK-LABEL: @vac(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    store <4 x float> zeroinitializer, <4 x float>* [[A:%.*]], align 16
+; CHECK-NEXT:    ret void
+;
+entry:
+  %tmp1 = load <4 x float>, <4 x float>* %a		; <<4 x float>> [#uses=1]
+  %vecins = insertelement <4 x float> %tmp1, float 0.000000e+00, i32 0	; <<4 x float>> [#uses=1]
+  %vecins4 = insertelement <4 x float> %vecins, float 0.000000e+00, i32 1; <<4 x float>> [#uses=1]
+  %vecins6 = insertelement <4 x float> %vecins4, float 0.000000e+00, i32 2; <<4 x float>> [#uses=1]
+  %vecins8 = insertelement <4 x float> %vecins6, float 0.000000e+00, i32 3; <<4 x float>> [#uses=1]
+  store <4 x float> %vecins8, <4 x float>* %a
+  ret void
+}
+
+declare i32 @fgetc(i8*)
+
+define <4 x float> @dead_shuffle_elt(<4 x float> %x, <2 x float> %y) nounwind {
+; CHECK-LABEL: @dead_shuffle_elt(
+; CHECK-NEXT:    [[SHUFFLE_I:%.*]] = shufflevector <2 x float> [[Y:%.*]], <2 x float> undef, <4 x i32> <i32 0, i32 1, i32 undef, i32 undef>
+; CHECK-NEXT:    [[SHUFFLE9_I:%.*]] = shufflevector <4 x float> [[SHUFFLE_I]], <4 x float> [[X:%.*]], <4 x i32> <i32 0, i32 1, i32 6, i32 7>
+; CHECK-NEXT:    ret <4 x float> [[SHUFFLE9_I]]
+;
+  %shuffle.i = shufflevector <2 x float> %y, <2 x float> %y, <4 x i32> <i32 0, i32 1, i32 0, i32 1>
+  %shuffle9.i = shufflevector <4 x float> %x, <4 x float> %shuffle.i, <4 x i32> <i32 4, i32 5, i32 2, i32 3>
+  ret <4 x float> %shuffle9.i
+}
+
+define <2 x float> @test_fptrunc(double %f) {
+; CHECK-LABEL: @test_fptrunc(
+; CHECK-NEXT:    [[TMP1:%.*]] = insertelement <2 x double> <double undef, double 0.000000e+00>, double [[F:%.*]], i32 0
+; CHECK-NEXT:    [[TMP2:%.*]] = fptrunc <2 x double> [[TMP1]] to <2 x float>
+; CHECK-NEXT:    ret <2 x float> [[TMP2]]
+;
+  %tmp9 = insertelement <4 x double> undef, double %f, i32 0
+  %tmp10 = insertelement <4 x double> %tmp9, double 0.000000e+00, i32 1
+  %tmp11 = insertelement <4 x double> %tmp10, double 0.000000e+00, i32 2
+  %tmp12 = insertelement <4 x double> %tmp11, double 0.000000e+00, i32 3
+  %tmp5 = fptrunc <4 x double> %tmp12 to <4 x float>
+  %ret = shufflevector <4 x float> %tmp5, <4 x float> undef, <2 x i32> <i32 0, i32 1>
+  ret <2 x float> %ret
+}
+
+define <2 x double> @test_fpext(float %f) {
+; CHECK-LABEL: @test_fpext(
+; CHECK-NEXT:    [[TMP1:%.*]] = insertelement <2 x float> <float undef, float 0.000000e+00>, float [[F:%.*]], i32 0
+; CHECK-NEXT:    [[TMP2:%.*]] = fpext <2 x float> [[TMP1]] to <2 x double>
+; CHECK-NEXT:    ret <2 x double> [[TMP2]]
+;
+  %tmp9 = insertelement <4 x float> undef, float %f, i32 0
+  %tmp10 = insertelement <4 x float> %tmp9, float 0.000000e+00, i32 1
+  %tmp11 = insertelement <4 x float> %tmp10, float 0.000000e+00, i32 2
+  %tmp12 = insertelement <4 x float> %tmp11, float 0.000000e+00, i32 3
+  %tmp5 = fpext <4 x float> %tmp12 to <4 x double>
+  %ret = shufflevector <4 x double> %tmp5, <4 x double> undef, <2 x i32> <i32 0, i32 1>
+  ret <2 x double> %ret
+}
+
+define <4 x double> @test_shuffle(<4 x double> %f) {
+; CHECK-LABEL: @test_shuffle(
+; CHECK-NEXT:    [[RET1:%.*]] = insertelement <4 x double> [[F:%.*]], double 1.000000e+00, i32 3
+; CHECK-NEXT:    ret <4 x double> [[RET1]]
+;
+  %ret = shufflevector <4 x double> %f, <4 x double> <double undef, double 1.0, double undef, double undef>, <4 x i32> <i32 0, i32 1, i32 2, i32 5>
+  ret <4 x double> %ret
+}
+
+define <4 x float> @test_select(float %f, float %g) {
+; CHECK-LABEL: @test_select(
+; CHECK-NEXT:    [[A3:%.*]] = insertelement <4 x float> <float undef, float undef, float undef, float 3.000000e+00>, float [[F:%.*]], i32 0
+; CHECK-NEXT:    [[RET:%.*]] = shufflevector <4 x float> [[A3]], <4 x float> <float undef, float 4.000000e+00, float 5.000000e+00, float undef>, <4 x i32> <i32 0, i32 5, i32 6, i32 3>
+; CHECK-NEXT:    ret <4 x float> [[RET]]
+;
+  %a0 = insertelement <4 x float> undef, float %f, i32 0
+  %a1 = insertelement <4 x float> %a0, float 1.000000e+00, i32 1
+  %a2 = insertelement <4 x float> %a1, float 2.000000e+00, i32 2
+  %a3 = insertelement <4 x float> %a2, float 3.000000e+00, i32 3
+  %b0 = insertelement <4 x float> undef, float %g, i32 0
+  %b1 = insertelement <4 x float> %b0, float 4.000000e+00, i32 1
+  %b2 = insertelement <4 x float> %b1, float 5.000000e+00, i32 2
+  %b3 = insertelement <4 x float> %b2, float 6.000000e+00, i32 3
+  %ret = select <4 x i1> <i1 true, i1 false, i1 false, i1 true>, <4 x float> %a3, <4 x float> %b3
+  ret <4 x float> %ret
+}
+
+; Check that instcombine doesn't wrongly fold away the select completely.
+
+define <2 x i64> @PR24922(<2 x i64> %v) {
+; CHECK-LABEL: @PR24922(
+; CHECK-NEXT:    [[RESULT1:%.*]] = insertelement <2 x i64> [[V:%.*]], i64 0, i32 0
+; CHECK-NEXT:    ret <2 x i64> [[RESULT1]]
+;
+  %result = select <2 x i1> <i1 icmp eq (i64 extractelement (<2 x i64> bitcast (<4 x i32> <i32 15, i32 15, i32 15, i32 15> to <2 x i64>), i64 0), i64 0), i1 true>, <2 x i64> %v, <2 x i64> zeroinitializer
+  ret <2 x i64> %result
+}
+
+; The shuffle only demands the 0th (undef) element of 'out123', so everything should fold away.
+
+define <4 x float> @inselt_shuf_no_demand(float %a1, float %a2, float %a3) {
+; CHECK-LABEL: @inselt_shuf_no_demand(
+; CHECK-NEXT:    ret <4 x float> undef
+;
+  %out1 = insertelement <4 x float> undef, float %a1, i32 1
+  %out12 = insertelement <4 x float> %out1, float %a2, i32 2
+  %out123 = insertelement <4 x float> %out12, float %a3, i32 3
+  %shuffle = shufflevector <4 x float> %out123, <4 x float> undef, <4 x i32> <i32 0, i32 undef, i32 undef, i32 undef>
+  ret <4 x float> %shuffle
+}
+
+; The shuffle only demands the 0th (undef) element of 'out123', so everything should fold away.
+
+define <4 x float> @inselt_shuf_no_demand_commute(float %a1, float %a2, float %a3) {
+; CHECK-LABEL: @inselt_shuf_no_demand_commute(
+; CHECK-NEXT:    ret <4 x float> undef
+;
+  %out1 = insertelement <4 x float> undef, float %a1, i32 1
+  %out12 = insertelement <4 x float> %out1, float %a2, i32 2
+  %out123 = insertelement <4 x float> %out12, float %a3, i32 3
+  %shuffle = shufflevector <4 x float> undef, <4 x float> %out123, <4 x i32> <i32 4, i32 undef, i32 undef, i32 undef>
+  ret <4 x float> %shuffle
+}
+
+; The add uses 'out012' giving it multiple uses after the shuffle is transformed to also
+; use 'out012'. The analysis should be able to see past that.
+
+define <4 x i32> @inselt_shuf_no_demand_multiuse(i32 %a0, i32 %a1, <4 x i32> %b) {
+; CHECK-LABEL: @inselt_shuf_no_demand_multiuse(
+; CHECK-NEXT:    [[OUT0:%.*]] = insertelement <4 x i32> undef, i32 [[A0:%.*]], i32 0
+; CHECK-NEXT:    [[OUT01:%.*]] = insertelement <4 x i32> [[OUT0]], i32 [[A1:%.*]], i32 1
+; CHECK-NEXT:    [[FOO:%.*]] = add <4 x i32> [[OUT01]], [[B:%.*]]
+; CHECK-NEXT:    ret <4 x i32> [[FOO]]
+;
+  %out0 = insertelement <4 x i32> undef, i32 %a0, i32 0
+  %out01 = insertelement <4 x i32> %out0, i32 %a1, i32 1
+  %out012 = insertelement <4 x i32> %out01, i32 %a0, i32 2
+  %foo = add <4 x i32> %out012, %b
+  %out0123 = insertelement <4 x i32> %foo, i32 %a1, i32 3
+  %shuffle = shufflevector <4 x i32> %out0123, <4 x i32> undef, <4 x i32> <i32 0, i32 1, i32 undef, i32 undef>
+  ret <4 x i32> %shuffle
+}
+
+define <4 x float> @inselt_shuf_no_demand_bogus_insert_index_in_chain(float %a1, float %a2, float %a3, i32 %variable_index) {
+; CHECK-LABEL: @inselt_shuf_no_demand_bogus_insert_index_in_chain(
+; CHECK-NEXT:    [[OUT12:%.*]] = insertelement <4 x float> undef, float [[A2:%.*]], i32 [[VARIABLE_INDEX:%.*]]
+; CHECK-NEXT:    ret <4 x float> [[OUT12]]
+;
+  %out1 = insertelement <4 x float> undef, float %a1, i32 1
+  %out12 = insertelement <4 x float> %out1, float %a2, i32 %variable_index ; something unexpected
+  %out123 = insertelement <4 x float> %out12, float %a3, i32 3
+  %shuffle = shufflevector <4 x float> %out123, <4 x float> undef, <4 x i32> <i32 0, i32 undef, i32 undef, i32 undef>
+  ret <4 x float> %shuffle
+}
+
+; Test undef replacement in constant vector elements with binops.
+
+define <3 x i8> @shuf_add(<3 x i8> %x) {
+; CHECK-LABEL: @shuf_add(
+; CHECK-NEXT:    [[BO:%.*]] = add <3 x i8> [[X:%.*]], <i8 undef, i8 2, i8 3>
+; CHECK-NEXT:    [[R:%.*]] = shufflevector <3 x i8> [[BO]], <3 x i8> undef, <3 x i32> <i32 1, i32 undef, i32 2>
+; CHECK-NEXT:    ret <3 x i8> [[R]]
+;
+  %bo = add nsw <3 x i8> %x, <i8 1, i8 2, i8 3>
+  %r = shufflevector <3 x i8> %bo, <3 x i8> undef, <3 x i32> <i32 1, i32 undef, i32 2>
+  ret <3 x i8> %r
+}
+
+define <3 x i8> @shuf_sub(<3 x i8> %x) {
+; CHECK-LABEL: @shuf_sub(
+; CHECK-NEXT:    [[BO:%.*]] = sub <3 x i8> <i8 1, i8 undef, i8 3>, [[X:%.*]]
+; CHECK-NEXT:    ret <3 x i8> [[BO]]
+;
+  %bo = sub nuw <3 x i8> <i8 1, i8 2, i8 3>, %x
+  %r = shufflevector <3 x i8> %bo, <3 x i8> undef, <3 x i32> <i32 0, i32 undef, i32 2>
+  ret <3 x i8> %r
+}
+
+define <3 x i8> @shuf_mul(<3 x i8> %x) {
+; CHECK-LABEL: @shuf_mul(
+; CHECK-NEXT:    [[BO:%.*]] = mul <3 x i8> [[X:%.*]], <i8 1, i8 undef, i8 3>
+; CHECK-NEXT:    [[R:%.*]] = shufflevector <3 x i8> [[BO]], <3 x i8> undef, <3 x i32> <i32 0, i32 2, i32 0>
+; CHECK-NEXT:    ret <3 x i8> [[R]]
+;
+  %bo = mul nsw <3 x i8> %x, <i8 1, i8 2, i8 3>
+  %r = shufflevector <3 x i8> %bo, <3 x i8> undef, <3 x i32> <i32 0, i32 2, i32 0>
+  ret <3 x i8> %r
+}
+
+define <3 x i8> @shuf_and(<3 x i8> %x) {
+; CHECK-LABEL: @shuf_and(
+; CHECK-NEXT:    [[BO:%.*]] = and <3 x i8> [[X:%.*]], <i8 1, i8 2, i8 undef>
+; CHECK-NEXT:    [[R:%.*]] = shufflevector <3 x i8> [[BO]], <3 x i8> undef, <3 x i32> <i32 1, i32 1, i32 0>
+; CHECK-NEXT:    ret <3 x i8> [[R]]
+;
+  %bo = and <3 x i8> %x, <i8 1, i8 2, i8 3>
+  %r = shufflevector <3 x i8> %bo, <3 x i8> undef, <3 x i32> <i32 1, i32 1, i32 0>
+  ret <3 x i8> %r
+}
+
+define <3 x i8> @shuf_or(<3 x i8> %x) {
+; CHECK-LABEL: @shuf_or(
+; CHECK-NEXT:    [[BO:%.*]] = or <3 x i8> [[X:%.*]], <i8 1, i8 2, i8 undef>
+; CHECK-NEXT:    [[R:%.*]] = shufflevector <3 x i8> [[BO]], <3 x i8> undef, <3 x i32> <i32 1, i32 undef, i32 0>
+; CHECK-NEXT:    ret <3 x i8> [[R]]
+;
+  %bo = or <3 x i8> %x, <i8 1, i8 2, i8 3>
+  %r = shufflevector <3 x i8> %bo, <3 x i8> undef, <3 x i32> <i32 1, i32 undef, i32 0>
+  ret <3 x i8> %r
+}
+
+define <3 x i8> @shuf_xor(<3 x i8> %x) {
+; CHECK-LABEL: @shuf_xor(
+; CHECK-NEXT:    [[BO:%.*]] = xor <3 x i8> [[X:%.*]], <i8 1, i8 undef, i8 3>
+; CHECK-NEXT:    [[R:%.*]] = shufflevector <3 x i8> [[BO]], <3 x i8> undef, <3 x i32> <i32 2, i32 undef, i32 0>
+; CHECK-NEXT:    ret <3 x i8> [[R]]
+;
+  %bo = xor <3 x i8> %x, <i8 1, i8 2, i8 3>
+  %r = shufflevector <3 x i8> %bo, <3 x i8> undef, <3 x i32> <i32 2, i32 undef, i32 0>
+  ret <3 x i8> %r
+}
+
+define <3 x i8> @shuf_lshr_const_op0(<3 x i8> %x) {
+; CHECK-LABEL: @shuf_lshr_const_op0(
+; CHECK-NEXT:    [[BO:%.*]] = lshr <3 x i8> <i8 1, i8 2, i8 3>, [[X:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = shufflevector <3 x i8> [[BO]], <3 x i8> undef, <3 x i32> <i32 2, i32 1, i32 undef>
+; CHECK-NEXT:    ret <3 x i8> [[R]]
+;
+  %bo = lshr <3 x i8> <i8 1, i8 2, i8 3>, %x
+  %r = shufflevector <3 x i8> %bo, <3 x i8> undef, <3 x i32> <i32 2, i32 1, i32 undef>
+  ret <3 x i8> %r
+}
+
+define <3 x i8> @shuf_lshr_const_op1(<3 x i8> %x) {
+; CHECK-LABEL: @shuf_lshr_const_op1(
+; CHECK-NEXT:    [[BO:%.*]] = lshr exact <3 x i8> [[X:%.*]], <i8 1, i8 2, i8 3>
+; CHECK-NEXT:    [[R:%.*]] = shufflevector <3 x i8> [[BO]], <3 x i8> undef, <3 x i32> <i32 2, i32 1, i32 undef>
+; CHECK-NEXT:    ret <3 x i8> [[R]]
+;
+  %bo = lshr exact <3 x i8> %x, <i8 1, i8 2, i8 3>
+  %r = shufflevector <3 x i8> %bo, <3 x i8> undef, <3 x i32> <i32 2, i32 1, i32 undef>
+  ret <3 x i8> %r
+}
+
+define <3 x i8> @shuf_ashr_const_op0(<3 x i8> %x) {
+; CHECK-LABEL: @shuf_ashr_const_op0(
+; CHECK-NEXT:    [[BO:%.*]] = lshr <3 x i8> <i8 1, i8 2, i8 3>, [[X:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = shufflevector <3 x i8> [[BO]], <3 x i8> undef, <3 x i32> <i32 0, i32 undef, i32 1>
+; CHECK-NEXT:    ret <3 x i8> [[R]]
+;
+  %bo = ashr <3 x i8> <i8 1, i8 2, i8 3>, %x
+  %r = shufflevector <3 x i8> %bo, <3 x i8> undef, <3 x i32> <i32 0, i32 undef, i32 1>
+  ret <3 x i8> %r
+}
+
+define <3 x i8> @shuf_ashr_const_op1(<3 x i8> %x) {
+; CHECK-LABEL: @shuf_ashr_const_op1(
+; CHECK-NEXT:    [[BO:%.*]] = ashr exact <3 x i8> [[X:%.*]], <i8 1, i8 2, i8 3>
+; CHECK-NEXT:    [[R:%.*]] = shufflevector <3 x i8> [[BO]], <3 x i8> undef, <3 x i32> <i32 0, i32 undef, i32 1>
+; CHECK-NEXT:    ret <3 x i8> [[R]]
+;
+  %bo = ashr exact <3 x i8> %x, <i8 1, i8 2, i8 3>
+  %r = shufflevector <3 x i8> %bo, <3 x i8> undef, <3 x i32> <i32 0, i32 undef, i32 1>
+  ret <3 x i8> %r
+}
+
+define <3 x i8> @shuf_shl_const_op0(<3 x i8> %x) {
+; CHECK-LABEL: @shuf_shl_const_op0(
+; CHECK-NEXT:    [[BO:%.*]] = shl nsw <3 x i8> <i8 1, i8 2, i8 3>, [[X:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = shufflevector <3 x i8> [[BO]], <3 x i8> undef, <3 x i32> <i32 2, i32 undef, i32 0>
+; CHECK-NEXT:    ret <3 x i8> [[R]]
+;
+  %bo = shl nsw <3 x i8> <i8 1, i8 2, i8 3>, %x
+  %r = shufflevector <3 x i8> %bo, <3 x i8> undef, <3 x i32> <i32 2, i32 undef, i32 0>
+  ret <3 x i8> %r
+}
+
+define <3 x i8> @shuf_shl_const_op1(<3 x i8> %x) {
+; CHECK-LABEL: @shuf_shl_const_op1(
+; CHECK-NEXT:    [[BO:%.*]] = shl nuw <3 x i8> [[X:%.*]], <i8 1, i8 2, i8 3>
+; CHECK-NEXT:    [[R:%.*]] = shufflevector <3 x i8> [[BO]], <3 x i8> undef, <3 x i32> <i32 2, i32 undef, i32 0>
+; CHECK-NEXT:    ret <3 x i8> [[R]]
+;
+  %bo = shl nuw <3 x i8> %x, <i8 1, i8 2, i8 3>
+  %r = shufflevector <3 x i8> %bo, <3 x i8> undef, <3 x i32> <i32 2, i32 undef, i32 0>
+  ret <3 x i8> %r
+}
+
+define <3 x i8> @shuf_sdiv_const_op0(<3 x i8> %x) {
+; CHECK-LABEL: @shuf_sdiv_const_op0(
+; CHECK-NEXT:    [[BO:%.*]] = sdiv exact <3 x i8> <i8 1, i8 2, i8 3>, [[X:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = shufflevector <3 x i8> [[BO]], <3 x i8> undef, <3 x i32> <i32 0, i32 undef, i32 1>
+; CHECK-NEXT:    ret <3 x i8> [[R]]
+;
+  %bo = sdiv exact <3 x i8> <i8 1, i8 2, i8 3>, %x
+  %r = shufflevector <3 x i8> %bo, <3 x i8> undef, <3 x i32> <i32 0, i32 undef, i32 1>
+  ret <3 x i8> %r
+}
+
+define <3 x i8> @shuf_sdiv_const_op1(<3 x i8> %x) {
+; CHECK-LABEL: @shuf_sdiv_const_op1(
+; CHECK-NEXT:    [[BO:%.*]] = sdiv <3 x i8> [[X:%.*]], <i8 1, i8 2, i8 3>
+; CHECK-NEXT:    [[R:%.*]] = shufflevector <3 x i8> [[BO]], <3 x i8> undef, <3 x i32> <i32 1, i32 undef, i32 0>
+; CHECK-NEXT:    ret <3 x i8> [[R]]
+;
+  %bo = sdiv <3 x i8> %x, <i8 1, i8 2, i8 3>
+  %r = shufflevector <3 x i8> %bo, <3 x i8> undef, <3 x i32> <i32 1, i32 undef, i32 0>
+  ret <3 x i8> %r
+}
+
+define <3 x i8> @shuf_srem_const_op0(<3 x i8> %x) {
+; CHECK-LABEL: @shuf_srem_const_op0(
+; CHECK-NEXT:    [[BO:%.*]] = srem <3 x i8> <i8 1, i8 2, i8 3>, [[X:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = shufflevector <3 x i8> [[BO]], <3 x i8> undef, <3 x i32> <i32 1, i32 undef, i32 2>
+; CHECK-NEXT:    ret <3 x i8> [[R]]
+;
+  %bo = srem <3 x i8> <i8 1, i8 2, i8 3>, %x
+  %r = shufflevector <3 x i8> %bo, <3 x i8> undef, <3 x i32> <i32 1, i32 undef, i32 2>
+  ret <3 x i8> %r
+}
+
+define <3 x i8> @shuf_srem_const_op1(<3 x i8> %x) {
+; CHECK-LABEL: @shuf_srem_const_op1(
+; CHECK-NEXT:    [[BO:%.*]] = srem <3 x i8> [[X:%.*]], <i8 1, i8 2, i8 3>
+; CHECK-NEXT:    [[R:%.*]] = shufflevector <3 x i8> [[BO]], <3 x i8> undef, <3 x i32> <i32 2, i32 undef, i32 1>
+; CHECK-NEXT:    ret <3 x i8> [[R]]
+;
+  %bo = srem <3 x i8> %x, <i8 1, i8 2, i8 3>
+  %r = shufflevector <3 x i8> %bo, <3 x i8> undef, <3 x i32> <i32 2, i32 undef, i32 1>
+  ret <3 x i8> %r
+}
+
+define <3 x i8> @shuf_udiv_const_op0(<3 x i8> %x) {
+; CHECK-LABEL: @shuf_udiv_const_op0(
+; CHECK-NEXT:    [[BO:%.*]] = udiv exact <3 x i8> <i8 1, i8 2, i8 3>, [[X:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = shufflevector <3 x i8> [[BO]], <3 x i8> undef, <3 x i32> <i32 2, i32 undef, i32 0>
+; CHECK-NEXT:    ret <3 x i8> [[R]]
+;
+  %bo = udiv exact <3 x i8> <i8 1, i8 2, i8 3>, %x
+  %r = shufflevector <3 x i8> %bo, <3 x i8> undef, <3 x i32> <i32 2, i32 undef, i32 0>
+  ret <3 x i8> %r
+}
+
+define <3 x i8> @shuf_udiv_const_op1(<3 x i8> %x) {
+; CHECK-LABEL: @shuf_udiv_const_op1(
+; CHECK-NEXT:    [[BO:%.*]] = udiv <3 x i8> [[X:%.*]], <i8 1, i8 2, i8 3>
+; CHECK-NEXT:    [[R:%.*]] = shufflevector <3 x i8> [[BO]], <3 x i8> undef, <3 x i32> <i32 2, i32 undef, i32 0>
+; CHECK-NEXT:    ret <3 x i8> [[R]]
+;
+  %bo = udiv <3 x i8> %x, <i8 1, i8 2, i8 3>
+  %r = shufflevector <3 x i8> %bo, <3 x i8> undef, <3 x i32> <i32 2, i32 undef, i32 0>
+  ret <3 x i8> %r
+}
+
+define <3 x i8> @shuf_urem_const_op0(<3 x i8> %x) {
+; CHECK-LABEL: @shuf_urem_const_op0(
+; CHECK-NEXT:    [[BO:%.*]] = urem <3 x i8> <i8 1, i8 2, i8 3>, [[X:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = shufflevector <3 x i8> [[BO]], <3 x i8> undef, <3 x i32> <i32 2, i32 1, i32 undef>
+; CHECK-NEXT:    ret <3 x i8> [[R]]
+;
+  %bo = urem <3 x i8> <i8 1, i8 2, i8 3>, %x
+  %r = shufflevector <3 x i8> %bo, <3 x i8> undef, <3 x i32> <i32 2, i32 1, i32 undef>
+  ret <3 x i8> %r
+}
+
+define <3 x i8> @shuf_urem_const_op1(<3 x i8> %x) {
+; CHECK-LABEL: @shuf_urem_const_op1(
+; CHECK-NEXT:    [[BO:%.*]] = urem <3 x i8> [[X:%.*]], <i8 1, i8 2, i8 3>
+; CHECK-NEXT:    [[R:%.*]] = shufflevector <3 x i8> [[BO]], <3 x i8> undef, <3 x i32> <i32 undef, i32 1, i32 0>
+; CHECK-NEXT:    ret <3 x i8> [[R]]
+;
+  %bo = urem <3 x i8> %x, <i8 1, i8 2, i8 3>
+  %r = shufflevector <3 x i8> %bo, <3 x i8> undef, <3 x i32> <i32 undef, i32 1, i32 0>
+  ret <3 x i8> %r
+}
+
+define <3 x float> @shuf_fadd(<3 x float> %x) {
+; CHECK-LABEL: @shuf_fadd(
+; CHECK-NEXT:    [[BO:%.*]] = fadd <3 x float> [[X:%.*]], <float 1.000000e+00, float 2.000000e+00, float undef>
+; CHECK-NEXT:    [[R:%.*]] = shufflevector <3 x float> [[BO]], <3 x float> undef, <3 x i32> <i32 undef, i32 1, i32 0>
+; CHECK-NEXT:    ret <3 x float> [[R]]
+;
+  %bo = fadd <3 x float> %x, <float 1.0, float 2.0, float 3.0>
+  %r = shufflevector <3 x float> %bo, <3 x float> undef, <3 x i32> <i32 undef, i32 1, i32 0>
+  ret <3 x float> %r
+}
+
+define <3 x float> @shuf_fsub(<3 x float> %x) {
+; CHECK-LABEL: @shuf_fsub(
+; CHECK-NEXT:    [[BO:%.*]] = fsub fast <3 x float> <float 1.000000e+00, float undef, float 3.000000e+00>, [[X:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = shufflevector <3 x float> [[BO]], <3 x float> undef, <3 x i32> <i32 undef, i32 0, i32 2>
+; CHECK-NEXT:    ret <3 x float> [[R]]
+;
+  %bo = fsub fast <3 x float> <float 1.0, float 2.0, float 3.0>, %x
+  %r = shufflevector <3 x float> %bo, <3 x float> undef, <3 x i32> <i32 undef, i32 0, i32 2>
+  ret <3 x float> %r
+}
+
+define <3 x float> @shuf_fmul(<3 x float> %x) {
+; CHECK-LABEL: @shuf_fmul(
+; CHECK-NEXT:    [[BO:%.*]] = fmul reassoc <3 x float> [[X:%.*]], <float 1.000000e+00, float 2.000000e+00, float undef>
+; CHECK-NEXT:    [[R:%.*]] = shufflevector <3 x float> [[BO]], <3 x float> undef, <3 x i32> <i32 undef, i32 1, i32 0>
+; CHECK-NEXT:    ret <3 x float> [[R]]
+;
+  %bo = fmul reassoc <3 x float> %x, <float 1.0, float 2.0, float 3.0>
+  %r = shufflevector <3 x float> %bo, <3 x float> undef, <3 x i32> <i32 undef, i32 1, i32 0>
+  ret <3 x float> %r
+}
+
+define <3 x float> @shuf_fdiv_const_op0(<3 x float> %x) {
+; CHECK-LABEL: @shuf_fdiv_const_op0(
+; CHECK-NEXT:    [[BO:%.*]] = fdiv reassoc ninf <3 x float> <float 1.000000e+00, float undef, float 3.000000e+00>, [[X:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = shufflevector <3 x float> [[BO]], <3 x float> undef, <3 x i32> <i32 undef, i32 0, i32 2>
+; CHECK-NEXT:    ret <3 x float> [[R]]
+;
+  %bo = fdiv ninf reassoc <3 x float> <float 1.0, float 2.0, float 3.0>, %x
+  %r = shufflevector <3 x float> %bo, <3 x float> undef, <3 x i32> <i32 undef, i32 0, i32 2>
+  ret <3 x float> %r
+}
+
+define <3 x float> @shuf_fdiv_const_op1(<3 x float> %x) {
+; CHECK-LABEL: @shuf_fdiv_const_op1(
+; CHECK-NEXT:    [[BO:%.*]] = fdiv nnan ninf <3 x float> [[X:%.*]], <float 1.000000e+00, float 2.000000e+00, float undef>
+; CHECK-NEXT:    [[R:%.*]] = shufflevector <3 x float> [[BO]], <3 x float> undef, <3 x i32> <i32 undef, i32 1, i32 0>
+; CHECK-NEXT:    ret <3 x float> [[R]]
+;
+  %bo = fdiv ninf nnan <3 x float> %x, <float 1.0, float 2.0, float 3.0>
+  %r = shufflevector <3 x float> %bo, <3 x float> undef, <3 x i32> <i32 undef, i32 1, i32 0>
+  ret <3 x float> %r
+}
+
+define <3 x float> @shuf_frem_const_op0(<3 x float> %x) {
+; CHECK-LABEL: @shuf_frem_const_op0(
+; CHECK-NEXT:    [[BO:%.*]] = frem nnan <3 x float> <float 1.000000e+00, float undef, float 3.000000e+00>, [[X:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = shufflevector <3 x float> [[BO]], <3 x float> undef, <3 x i32> <i32 undef, i32 2, i32 0>
+; CHECK-NEXT:    ret <3 x float> [[R]]
+;
+  %bo = frem nnan <3 x float> <float 1.0, float 2.0, float 3.0>, %x
+  %r = shufflevector <3 x float> %bo, <3 x float> undef, <3 x i32> <i32 undef, i32 2, i32 0>
+  ret <3 x float> %r
+}
+
+define <3 x float> @shuf_frem_const_op1(<3 x float> %x) {
+; CHECK-LABEL: @shuf_frem_const_op1(
+; CHECK-NEXT:    [[BO:%.*]] = frem reassoc ninf <3 x float> [[X:%.*]], <float undef, float 2.000000e+00, float 3.000000e+00>
+; CHECK-NEXT:    [[R:%.*]] = shufflevector <3 x float> [[BO]], <3 x float> undef, <3 x i32> <i32 1, i32 undef, i32 2>
+; CHECK-NEXT:    ret <3 x float> [[R]]
+;
+  %bo = frem ninf reassoc <3 x float> %x, <float 1.0, float 2.0, float 3.0>
+  %r = shufflevector <3 x float> %bo, <3 x float> undef, <3 x i32> <i32 1, i32 undef, i32 2>
+  ret <3 x float> %r
+}
+
+;; TODO: getelementptr tests below show missing simplifications for
+;; vector demanded elements on vector geps.
+
+define i32* @gep_vbase_w_s_idx(<2 x i32*> %base) {
+; CHECK-LABEL: @gep_vbase_w_s_idx(
+; CHECK-NEXT:    [[GEP:%.*]] = getelementptr i32, <2 x i32*> [[BASE:%.*]], i64 1
+; CHECK-NEXT:    [[EE:%.*]] = extractelement <2 x i32*> [[GEP]], i32 1
+; CHECK-NEXT:    ret i32* [[EE]]
+;
+  %gep = getelementptr i32, <2 x i32*> %base, i64 1
+  %ee = extractelement <2 x i32*> %gep, i32 1
+  ret i32* %ee
+}
+
+define i32* @gep_splat_base_w_s_idx(i32* %base) {
+; CHECK-LABEL: @gep_splat_base_w_s_idx(
+; CHECK-NEXT:    [[BASEVEC2:%.*]] = insertelement <2 x i32*> undef, i32* [[BASE:%.*]], i32 1
+; CHECK-NEXT:    [[GEP:%.*]] = getelementptr i32, <2 x i32*> [[BASEVEC2]], i64 1
+; CHECK-NEXT:    [[EE:%.*]] = extractelement <2 x i32*> [[GEP]], i32 1
+; CHECK-NEXT:    ret i32* [[EE]]
+;
+  %basevec1 = insertelement <2 x i32*> undef, i32* %base, i32 0
+  %basevec2 = shufflevector <2 x i32*> %basevec1, <2 x i32*> undef, <2 x i32> zeroinitializer
+  %gep = getelementptr i32, <2 x i32*> %basevec2, i64 1
+  %ee = extractelement <2 x i32*> %gep, i32 1
+  ret i32* %ee
+}
+
+
+define i32* @gep_splat_base_w_cv_idx(i32* %base) {
+; CHECK-LABEL: @gep_splat_base_w_cv_idx(
+; CHECK-NEXT:    [[BASEVEC2:%.*]] = insertelement <2 x i32*> undef, i32* [[BASE:%.*]], i32 1
+; CHECK-NEXT:    [[GEP:%.*]] = getelementptr i32, <2 x i32*> [[BASEVEC2]], <2 x i64> <i64 undef, i64 1>
+; CHECK-NEXT:    [[EE:%.*]] = extractelement <2 x i32*> [[GEP]], i32 1
+; CHECK-NEXT:    ret i32* [[EE]]
+;
+  %basevec1 = insertelement <2 x i32*> undef, i32* %base, i32 0
+  %basevec2 = shufflevector <2 x i32*> %basevec1, <2 x i32*> undef, <2 x i32> zeroinitializer
+  %gep = getelementptr i32, <2 x i32*> %basevec2, <2 x i64> <i64 0, i64 1>
+  %ee = extractelement <2 x i32*> %gep, i32 1
+  ret i32* %ee
+}
+
+define i32* @gep_splat_base_w_vidx(i32* %base, <2 x i64> %idxvec) {
+; CHECK-LABEL: @gep_splat_base_w_vidx(
+; CHECK-NEXT:    [[BASEVEC2:%.*]] = insertelement <2 x i32*> undef, i32* [[BASE:%.*]], i32 1
+; CHECK-NEXT:    [[GEP:%.*]] = getelementptr i32, <2 x i32*> [[BASEVEC2]], <2 x i64> [[IDXVEC:%.*]]
+; CHECK-NEXT:    [[EE:%.*]] = extractelement <2 x i32*> [[GEP]], i32 1
+; CHECK-NEXT:    ret i32* [[EE]]
+;
+  %basevec1 = insertelement <2 x i32*> undef, i32* %base, i32 0
+  %basevec2 = shufflevector <2 x i32*> %basevec1, <2 x i32*> undef, <2 x i32> zeroinitializer
+  %gep = getelementptr i32, <2 x i32*> %basevec2, <2 x i64> %idxvec
+  %ee = extractelement <2 x i32*> %gep, i32 1
+  ret i32* %ee
+}
+
+
+ at GLOBAL = internal global i32 zeroinitializer
+
+define i32* @gep_cvbase_w_s_idx(<2 x i32*> %base, i64 %raw_addr) {
+; CHECK-LABEL: @gep_cvbase_w_s_idx(
+; CHECK-NEXT:    [[GEP:%.*]] = getelementptr i32, <2 x i32*> <i32* undef, i32* @GLOBAL>, i64 [[RAW_ADDR:%.*]]
+; CHECK-NEXT:    [[EE:%.*]] = extractelement <2 x i32*> [[GEP]], i32 1
+; CHECK-NEXT:    ret i32* [[EE]]
+;
+  %gep = getelementptr i32, <2 x i32*> <i32* @GLOBAL, i32* @GLOBAL>, i64 %raw_addr
+  %ee = extractelement <2 x i32*> %gep, i32 1
+  ret i32* %ee
+}
+
+define i32* @gep_cvbase_w_cv_idx(<2 x i32*> %base, i64 %raw_addr) {
+; CHECK-LABEL: @gep_cvbase_w_cv_idx(
+; CHECK-NEXT:    ret i32* extractelement (<2 x i32*> getelementptr (i32, <2 x i32*> <i32* @GLOBAL, i32* @GLOBAL>, <2 x i64> <i64 0, i64 1>), i32 1)
+;
+  %gep = getelementptr i32, <2 x i32*> <i32* @GLOBAL, i32* @GLOBAL>, <2 x i64> <i64 0, i64 1>
+  %ee = extractelement <2 x i32*> %gep, i32 1
+  ret i32* %ee
+}
+
+
+define i32* @gep_sbase_w_cv_idx(i32* %base) {
+; CHECK-LABEL: @gep_sbase_w_cv_idx(
+; CHECK-NEXT:    [[GEP:%.*]] = getelementptr i32, i32* [[BASE:%.*]], <2 x i64> <i64 undef, i64 1>
+; CHECK-NEXT:    [[EE:%.*]] = extractelement <2 x i32*> [[GEP]], i32 1
+; CHECK-NEXT:    ret i32* [[EE]]
+;
+  %gep = getelementptr i32, i32* %base, <2 x i64> <i64 0, i64 1>
+  %ee = extractelement <2 x i32*> %gep, i32 1
+  ret i32* %ee
+}
+
+define i32* @gep_sbase_w_splat_idx(i32* %base, i64 %idx) {
+; CHECK-LABEL: @gep_sbase_w_splat_idx(
+; CHECK-NEXT:    [[IDXVEC2:%.*]] = insertelement <2 x i64> undef, i64 [[IDX:%.*]], i32 1
+; CHECK-NEXT:    [[GEP:%.*]] = getelementptr i32, i32* [[BASE:%.*]], <2 x i64> [[IDXVEC2]]
+; CHECK-NEXT:    [[EE:%.*]] = extractelement <2 x i32*> [[GEP]], i32 1
+; CHECK-NEXT:    ret i32* [[EE]]
+;
+  %idxvec1 = insertelement <2 x i64> undef, i64 %idx, i32 0
+  %idxvec2 = shufflevector <2 x i64> %idxvec1, <2 x i64> undef, <2 x i32> zeroinitializer
+  %gep = getelementptr i32, i32* %base, <2 x i64> %idxvec2
+  %ee = extractelement <2 x i32*> %gep, i32 1
+  ret i32* %ee
+}
+define i32* @gep_splat_both(i32* %base, i64 %idx) {
+; CHECK-LABEL: @gep_splat_both(
+; CHECK-NEXT:    [[BASEVEC2:%.*]] = insertelement <2 x i32*> undef, i32* [[BASE:%.*]], i32 1
+; CHECK-NEXT:    [[IDXVEC2:%.*]] = insertelement <2 x i64> undef, i64 [[IDX:%.*]], i32 1
+; CHECK-NEXT:    [[GEP:%.*]] = getelementptr i32, <2 x i32*> [[BASEVEC2]], <2 x i64> [[IDXVEC2]]
+; CHECK-NEXT:    [[EE:%.*]] = extractelement <2 x i32*> [[GEP]], i32 1
+; CHECK-NEXT:    ret i32* [[EE]]
+;
+  %basevec1 = insertelement <2 x i32*> undef, i32* %base, i32 0
+  %basevec2 = shufflevector <2 x i32*> %basevec1, <2 x i32*> undef, <2 x i32> zeroinitializer
+  %idxvec1 = insertelement <2 x i64> undef, i64 %idx, i32 0
+  %idxvec2 = shufflevector <2 x i64> %idxvec1, <2 x i64> undef, <2 x i32> zeroinitializer
+  %gep = getelementptr i32, <2 x i32*> %basevec2, <2 x i64> %idxvec2
+  %ee = extractelement <2 x i32*> %gep, i32 1
+  ret i32* %ee
+}
+
+define <2 x i32*> @gep_all_lanes_undef(i32* %base, i64 %idx) {;
+; CHECK-LABEL: @gep_all_lanes_undef(
+; CHECK-NEXT:    ret <2 x i32*> undef
+;
+  %basevec = insertelement <2 x i32*> undef, i32* %base, i32 0
+  %idxvec = insertelement <2 x i64> undef, i64 %idx, i32 1
+  %gep = getelementptr i32, <2 x i32*> %basevec, <2 x i64> %idxvec
+  ret <2 x i32*> %gep
+}
+
+define i32* @gep_demanded_lane_undef(i32* %base, i64 %idx) {
+; CHECK-LABEL: @gep_demanded_lane_undef(
+; CHECK-NEXT:    ret i32* undef
+;
+  %basevec = insertelement <2 x i32*> undef, i32* %base, i32 0
+  %idxvec = insertelement <2 x i64> undef, i64 %idx, i32 1
+  %gep = getelementptr i32, <2 x i32*> %basevec, <2 x i64> %idxvec
+  %ee = extractelement <2 x i32*> %gep, i32 1
+  ret i32* %ee
+}

Added: llvm/trunk/test/Transforms/InstCombine/vec_extract_2elts.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/vec_extract_2elts.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/vec_extract_2elts.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/vec_extract_2elts.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,12 @@
+; RUN: opt < %s -instcombine -S | FileCheck %s
+
+define void @test(<4 x i32> %v, i64 *%r1, i64 *%r2) {
+;CHECK: %1 = extractelement <4 x i32> %v, i32 0
+;CHECK: %2 = zext i32 %1 to i64
+        %1 = zext <4 x i32> %v to <4 x i64>
+        %2 = extractelement <4 x i64> %1, i32 0
+        store i64 %2, i64 *%r1
+        store i64 %2, i64 *%r2
+        ret void
+}
+

Added: llvm/trunk/test/Transforms/InstCombine/vec_extract_var_elt.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/vec_extract_var_elt.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/vec_extract_var_elt.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/vec_extract_var_elt.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,26 @@
+; RUN: opt < %s -instcombine -S | FileCheck %s
+
+define void @test (float %b, <8 x float> * %p)  {
+; CHECK: extractelement
+; CHECK: fptosi
+  %1 = load <8 x float> , <8 x float> * %p
+  %2 = bitcast <8 x float> %1 to <8 x i32>
+  %3 = bitcast <8 x i32> %2 to <8 x float>
+  %a = fptosi <8 x float> %3 to <8 x i32>
+  %4 = fptosi float %b to i32
+  %5 = add i32 %4, -2
+  %6 = extractelement <8 x i32> %a, i32 %5
+  %7 = insertelement <8 x i32> undef, i32 %6, i32 7
+  %8 = sitofp <8 x i32> %7 to <8 x float>
+  store <8 x float> %8, <8 x float>* %p
+  ret void    
+}
+
+; PR18600
+define i32 @test2(i32 %i) {
+  %e = extractelement <4 x i32> bitcast (<2 x i64> <i64 1, i64 2> to <4 x i32>), i32 %i
+  ret i32 %e
+
+; CHECK-LABEL: @test2
+; CHECK: extractelement
+}

Added: llvm/trunk/test/Transforms/InstCombine/vec_gep_scalar_arg.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/vec_gep_scalar_arg.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/vec_gep_scalar_arg.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/vec_gep_scalar_arg.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,16 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt -instcombine -S < %s | FileCheck %s
+
+define <4 x i16*> @PR41270([4 x i16]* %x) {
+; CHECK-LABEL: @PR41270(
+; CHECK-NEXT:    [[TMP1:%.*]] = insertelement <4 x [4 x i16]*> undef, [4 x i16]* [[X:%.*]], i32 0
+; CHECK-NEXT:    [[TMP2:%.*]] = getelementptr inbounds [4 x i16], <4 x [4 x i16]*> [[TMP1]], i64 0, i64 3
+; CHECK-NEXT:    ret <4 x i16*> [[TMP2]]
+;
+  %ins = insertelement <4 x [4 x i16]*> undef, [4 x i16]* %x, i32 0
+  %splat = shufflevector <4 x [4 x i16]*> %ins, <4 x [4 x i16]*> undef, <4 x i32> zeroinitializer
+  %t2 = getelementptr inbounds [4 x i16], <4 x [4 x i16]*> %splat, i32 0, i32 3
+  %t3 = extractelement <4 x i16*> %t2, i32 3
+  %ins2 = insertelement <4 x i16*> undef, i16* %t3, i32 0
+  ret <4 x i16*> %ins2
+}

Added: llvm/trunk/test/Transforms/InstCombine/vec_insertelt.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/vec_insertelt.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/vec_insertelt.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/vec_insertelt.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,8 @@
+; RUN: opt < %s -instcombine -S | FileCheck %s
+; CHECK: ret <4 x i32> %A
+
+; PR1286
+define <4 x i32> @test1(<4 x i32> %A) {
+	%B = insertelement <4 x i32> %A, i32 undef, i32 1
+	ret <4 x i32> %B
+}

Added: llvm/trunk/test/Transforms/InstCombine/vec_phi_extract.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/vec_phi_extract.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/vec_phi_extract.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/vec_phi_extract.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,107 @@
+; RUN: opt < %s -instcombine -S | FileCheck %s
+
+define void @f(i64 %val, i32  %limit, i32 *%ptr) {
+; CHECK-LABEL: @f
+; CHECK: %0 = trunc i64 %val to i32
+; CHECK: %1 = phi i32 [ %0, %entry ], [ {{.*}}, %loop ]
+entry:
+  %tempvector = insertelement <16 x i64> undef, i64 %val, i32 0
+  %vector = shufflevector <16 x i64> %tempvector, <16 x i64> undef, <16 x i32> zeroinitializer
+  %0 = add <16 x i64> %vector, <i64 0, i64 1, i64 2, i64 3, i64 4, i64 5, i64 6, i64 7, i64 8, i64 9, i64 10, i64 11, i64 12, i64 13, i64 14, i64 15>
+  %1 = trunc <16 x i64> %0 to <16 x i32>
+  br label %loop
+
+loop:
+  %2 = phi <16 x i32> [ %1, %entry ], [ %inc, %loop ]
+  %elt = extractelement <16 x i32> %2, i32 0
+  %end = icmp ult i32 %elt, %limit
+  %3 = add i32 10, %elt
+  %4 = sext i32 %elt to i64
+  %5 = getelementptr i32, i32* %ptr, i64 %4
+  store i32 %3, i32* %5
+  %inc = add <16 x i32> %2, <i32 16, i32 16, i32 16, i32 16, i32 16, i32 16, i32 16, i32 16, i32 16, i32 16, i32 16, i32 16, i32 16, i32 16, i32 16, i32 16>
+  br i1 %end, label %loop, label %ret
+
+ret:
+  ret void
+}
+
+define void @copy(i64 %val, i32  %limit, i32 *%ptr) {
+; CHECK-LABEL: @copy
+; CHECK: %0 = trunc i64 %val to i32
+; CHECK: %1 = phi i32 [ %0, %entry ], [ {{.*}}, %loop ]
+entry:
+  %tempvector = insertelement <16 x i64> undef, i64 %val, i32 0
+  %vector = shufflevector <16 x i64> %tempvector, <16 x i64> undef, <16 x i32> zeroinitializer
+  %0 = add <16 x i64> %vector, <i64 0, i64 1, i64 2, i64 3, i64 4, i64 5, i64 6, i64 7, i64 8, i64 9, i64 10, i64 11, i64 12, i64 13, i64 14, i64 15>
+  %1 = trunc <16 x i64> %0 to <16 x i32>
+  br label %loop
+
+loop:
+  %2 = phi <16 x i32> [ %1, %entry ], [ %inc, %loop ]
+  %elt = extractelement <16 x i32> %2, i32 0
+  %eltcopy = extractelement <16 x i32> %2, i32 0
+  %end = icmp ult i32 %elt, %limit
+  %3 = add i32 10, %eltcopy
+  %4 = sext i32 %elt to i64
+  %5 = getelementptr i32, i32* %ptr, i64 %4
+  store i32 %3, i32* %5
+  %inc = add <16 x i32> %2, <i32 16, i32 16, i32 16, i32 16, i32 16, i32 16, i32 16, i32 16, i32 16, i32 16, i32 16, i32 16, i32 16, i32 16, i32 16, i32 16>
+  br i1 %end, label %loop, label %ret
+
+ret:
+  ret void
+}
+
+define void @nocopy(i64 %val, i32  %limit, i32 *%ptr) {
+; CHECK-LABEL: @nocopy
+; CHECK-NOT: phi i32
+; CHECK: phi <16 x i32> [ %3, %entry ], [ %inc, %loop ]
+entry:
+  %tempvector = insertelement <16 x i64> undef, i64 %val, i32 0
+  %vector = shufflevector <16 x i64> %tempvector, <16 x i64> undef, <16 x i32> zeroinitializer
+  %0 = add <16 x i64> %vector, <i64 0, i64 1, i64 2, i64 3, i64 4, i64 5, i64 6, i64 7, i64 8, i64 9, i64 10, i64 11, i64 12, i64 13, i64 14, i64 15>
+  %1 = trunc <16 x i64> %0 to <16 x i32>
+  br label %loop
+
+loop:
+  %2 = phi <16 x i32> [ %1, %entry ], [ %inc, %loop ]
+  %elt = extractelement <16 x i32> %2, i32 0
+  %eltcopy = extractelement <16 x i32> %2, i32 1
+  %end = icmp ult i32 %elt, %limit
+  %3 = add i32 10, %eltcopy
+  %4 = sext i32 %elt to i64
+  %5 = getelementptr i32, i32* %ptr, i64 %4
+  store i32 %3, i32* %5
+  %inc = add <16 x i32> %2, <i32 16, i32 16, i32 16, i32 16, i32 16, i32 16, i32 16, i32 16, i32 16, i32 16, i32 16, i32 16, i32 16, i32 16, i32 16, i32 16>
+  br i1 %end, label %loop, label %ret
+
+ret:
+  ret void
+}
+
+define i1 @g(<3 x i32> %input_2) {
+; CHECK-LABEL: @g
+; CHECK: extractelement <3 x i32> %input_2, i32 0
+entry:
+  br label %for.cond
+
+for.cond:
+  %input_2.addr.0 = phi <3 x i32> [ %input_2, %entry ], [ %div45, %for.body ]
+  %input_1.addr.1 = phi <3 x i32> [ undef, %entry ], [ %dec43, %for.body ]
+  br i1 undef, label %for.end, label %for.body
+
+; CHECK-NOT: extractelement <3 x i32> %{{.*}}, i32 0
+for.body:
+  %dec43 = add <3 x i32> %input_1.addr.1, <i32 -1, i32 -1, i32 -1>
+  %sub44 = sub <3 x i32> <i32 -1, i32 -1, i32 -1>, %dec43
+  %div45 = sdiv <3 x i32> %input_2.addr.0, %sub44
+  br label %for.cond
+
+for.end:
+  %0 = extractelement <3 x i32> %input_2.addr.0, i32 0
+  %.89 = select i1 false, i32 0, i32 %0
+  %tobool313 = icmp eq i32 %.89, 0
+  ret i1 %tobool313
+}
+

Added: llvm/trunk/test/Transforms/InstCombine/vec_sext.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/vec_sext.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/vec_sext.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/vec_sext.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,63 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt < %s -instcombine -S | FileCheck %s
+
+define <4 x i32> @vec_select(<4 x i32> %a, <4 x i32> %b) {
+; CHECK-LABEL: @vec_select(
+; CHECK-NEXT:    [[SUB:%.*]] = sub nsw <4 x i32> zeroinitializer, [[A:%.*]]
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp sgt <4 x i32> [[B:%.*]], <i32 -1, i32 -1, i32 -1, i32 -1>
+; CHECK-NEXT:    [[TMP2:%.*]] = select <4 x i1> [[TMP1]], <4 x i32> [[A]], <4 x i32> [[SUB]]
+; CHECK-NEXT:    ret <4 x i32> [[TMP2]]
+;
+  %cmp = icmp slt <4 x i32> %b, zeroinitializer
+  %sext = sext <4 x i1> %cmp to <4 x i32>
+  %sub = sub nsw <4 x i32> zeroinitializer, %a
+  %t0 = icmp slt <4 x i32> %sext, zeroinitializer
+  %sext3 = sext <4 x i1> %t0 to <4 x i32>
+  %t1 = xor <4 x i32> %sext3, <i32 -1, i32 -1, i32 -1, i32 -1>
+  %t2 = and <4 x i32> %a, %t1
+  %t3 = and <4 x i32> %sext3, %sub
+  %cond = or <4 x i32> %t2, %t3
+  ret <4 x i32> %cond
+}
+
+define <4 x i32> @vec_select_alternate_sign_bit_test(<4 x i32> %a, <4 x i32> %b) {
+; CHECK-LABEL: @vec_select_alternate_sign_bit_test(
+; CHECK-NEXT:    [[SUB:%.*]] = sub nsw <4 x i32> zeroinitializer, [[A:%.*]]
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp sgt <4 x i32> [[B:%.*]], <i32 -1, i32 -1, i32 -1, i32 -1>
+; CHECK-NEXT:    [[TMP2:%.*]] = select <4 x i1> [[TMP1]], <4 x i32> [[SUB]], <4 x i32> [[A]]
+; CHECK-NEXT:    ret <4 x i32> [[TMP2]]
+;
+  %cmp = icmp sgt <4 x i32> %b, <i32 -1, i32 -1, i32 -1, i32 -1>
+  %sext = sext <4 x i1> %cmp to <4 x i32>
+  %sub = sub nsw <4 x i32> zeroinitializer, %a
+  %t0 = icmp slt <4 x i32> %sext, zeroinitializer
+  %sext3 = sext <4 x i1> %t0 to <4 x i32>
+  %t1 = xor <4 x i32> %sext3, <i32 -1, i32 -1, i32 -1, i32 -1>
+  %t2 = and <4 x i32> %a, %t1
+  %t3 = and <4 x i32> %sext3, %sub
+  %cond = or <4 x i32> %t2, %t3
+  ret <4 x i32> %cond
+}
+
+define <2 x i32> @is_negative_undef_elt(<2 x i32> %a) {
+; CHECK-LABEL: @is_negative_undef_elt(
+; CHECK-NEXT:    [[A_LOBIT:%.*]] = ashr <2 x i32> [[A:%.*]], <i32 31, i32 31>
+; CHECK-NEXT:    ret <2 x i32> [[A_LOBIT]]
+;
+  %cmp = icmp slt <2 x i32> %a, <i32 0, i32 undef>
+  %sext = sext <2 x i1> %cmp to <2 x i32>
+  ret <2 x i32> %sext
+
+}
+
+define <2 x i32> @is_positive_undef_elt(<2 x i32> %a) {
+; CHECK-LABEL: @is_positive_undef_elt(
+; CHECK-NEXT:    [[A_LOBIT:%.*]] = ashr <2 x i32> [[A:%.*]], <i32 31, i32 31>
+; CHECK-NEXT:    [[A_LOBIT_NOT:%.*]] = xor <2 x i32> [[A_LOBIT]], <i32 -1, i32 -1>
+; CHECK-NEXT:    ret <2 x i32> [[A_LOBIT_NOT]]
+;
+  %cmp = icmp sgt <2 x i32> %a, <i32 undef, i32 -1>
+  %sext = sext <2 x i1> %cmp to <2 x i32>
+  ret <2 x i32> %sext
+}
+

Added: llvm/trunk/test/Transforms/InstCombine/vec_shuffle.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/vec_shuffle.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/vec_shuffle.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/vec_shuffle.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,1142 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt < %s -instcombine -S | FileCheck %s
+
+define <4 x float> @test1(<4 x float> %v1) {
+; CHECK-LABEL: @test1(
+; CHECK-NEXT:    ret <4 x float> [[V1:%.*]]
+;
+  %v2 = shufflevector <4 x float> %v1, <4 x float> undef, <4 x i32> <i32 0, i32 1, i32 2, i32 3>
+  ret <4 x float> %v2
+}
+
+define <4 x float> @test2(<4 x float> %v1) {
+; CHECK-LABEL: @test2(
+; CHECK-NEXT:    ret <4 x float> [[V1:%.*]]
+;
+  %v2 = shufflevector <4 x float> %v1, <4 x float> %v1, <4 x i32> <i32 0, i32 5, i32 2, i32 7>
+  ret <4 x float> %v2
+}
+
+define float @test3(<4 x float> %A, <4 x float> %B, float %f) {
+; CHECK-LABEL: @test3(
+; CHECK-NEXT:    ret float [[F:%.*]]
+;
+  %C = insertelement <4 x float> %A, float %f, i32 0
+  %D = shufflevector <4 x float> %C, <4 x float> %B, <4 x i32> <i32 5, i32 0, i32 2, i32 7>
+  %E = extractelement <4 x float> %D, i32 1
+  ret float %E
+}
+
+define i32 @test4(<4 x i32> %X) {
+; CHECK-LABEL: @test4(
+; CHECK-NEXT:    [[R:%.*]] = extractelement <4 x i32> [[X:%.*]], i32 0
+; CHECK-NEXT:    ret i32 [[R]]
+;
+  %t = shufflevector <4 x i32> %X, <4 x i32> undef, <4 x i32> zeroinitializer
+  %r = extractelement <4 x i32> %t, i32 0
+  ret i32 %r
+}
+
+define i32 @test5(<4 x i32> %X) {
+; CHECK-LABEL: @test5(
+; CHECK-NEXT:    [[R:%.*]] = extractelement <4 x i32> [[X:%.*]], i32 3
+; CHECK-NEXT:    ret i32 [[R]]
+;
+  %t = shufflevector <4 x i32> %X, <4 x i32> undef, <4 x i32> <i32 3, i32 2, i32 undef, i32 undef>
+  %r = extractelement <4 x i32> %t, i32 0
+  ret i32 %r
+}
+
+define float @test6(<4 x float> %X) {
+; CHECK-LABEL: @test6(
+; CHECK-NEXT:    [[R:%.*]] = extractelement <4 x float> [[X:%.*]], i32 0
+; CHECK-NEXT:    ret float [[R]]
+;
+  %X1 = bitcast <4 x float> %X to <4 x i32>
+  %t = shufflevector <4 x i32> %X1, <4 x i32> undef, <4 x i32> zeroinitializer
+  %t2 = bitcast <4 x i32> %t to <4 x float>
+  %r = extractelement <4 x float> %t2, i32 0
+  ret float %r
+}
+
+define <4 x float> @test7(<4 x float> %x) {
+; CHECK-LABEL: @test7(
+; CHECK-NEXT:    ret <4 x float> [[X:%.*]]
+;
+  %r = shufflevector <4 x float> %x, <4 x float> undef, <4 x i32> < i32 0, i32 1, i32 6, i32 7 >
+  ret <4 x float> %r
+}
+
+; This should turn into a single shuffle.
+define <4 x float> @test8(<4 x float> %x, <4 x float> %y) {
+; CHECK-LABEL: @test8(
+; CHECK-NEXT:    [[T134:%.*]] = shufflevector <4 x float> [[X:%.*]], <4 x float> [[Y:%.*]], <4 x i32> <i32 1, i32 undef, i32 3, i32 4>
+; CHECK-NEXT:    ret <4 x float> [[T134]]
+;
+  %t4 = extractelement <4 x float> %x, i32 1
+  %t2 = extractelement <4 x float> %x, i32 3
+  %t1 = extractelement <4 x float> %y, i32 0
+  %t128 = insertelement <4 x float> undef, float %t4, i32 0
+  %t130 = insertelement <4 x float> %t128, float undef, i32 1
+  %t132 = insertelement <4 x float> %t130, float %t2, i32 2
+  %t134 = insertelement <4 x float> %t132, float %t1, i32 3
+  ret <4 x float> %t134
+}
+
+; Test fold of two shuffles where the first shuffle vectors inputs are a
+; different length then the second.
+define <4 x i8> @test9(<16 x i8> %t6) {
+; CHECK-LABEL: @test9(
+; CHECK-NEXT:    [[T9:%.*]] = shufflevector <16 x i8> [[T6:%.*]], <16 x i8> undef, <4 x i32> <i32 13, i32 9, i32 4, i32 13>
+; CHECK-NEXT:    ret <4 x i8> [[T9]]
+;
+  %t7 = shufflevector <16 x i8> %t6, <16 x i8> undef, <4 x i32> < i32 13, i32 9, i32 4, i32 13 >
+  %t9 = shufflevector <4 x i8> %t7, <4 x i8> undef, <4 x i32> < i32 3, i32 1, i32 2, i32 0 >
+  ret <4 x i8> %t9
+}
+
+; Same as test9, but make sure that "undef" mask values are not confused with
+; mask values of 2*N, where N is the mask length.  These shuffles should not
+; be folded (because [8,9,4,8] may not be a mask supported by the target).
+
+define <4 x i8> @test9a(<16 x i8> %t6) {
+; CHECK-LABEL: @test9a(
+; CHECK-NEXT:    [[T7:%.*]] = shufflevector <16 x i8> [[T6:%.*]], <16 x i8> undef, <4 x i32> <i32 undef, i32 9, i32 4, i32 8>
+; CHECK-NEXT:    [[T9:%.*]] = shufflevector <4 x i8> [[T7]], <4 x i8> undef, <4 x i32> <i32 3, i32 1, i32 2, i32 undef>
+; CHECK-NEXT:    ret <4 x i8> [[T9]]
+;
+  %t7 = shufflevector <16 x i8> %t6, <16 x i8> undef, <4 x i32> < i32 undef, i32 9, i32 4, i32 8 >
+  %t9 = shufflevector <4 x i8> %t7, <4 x i8> undef, <4 x i32> < i32 3, i32 1, i32 2, i32 0 >
+  ret <4 x i8> %t9
+}
+
+; Test fold of two shuffles where the first shuffle vectors inputs are a
+; different length then the second.
+define <4 x i8> @test9b(<4 x i8> %t6, <4 x i8> %t7) {
+; CHECK-LABEL: @test9b(
+; CHECK-NEXT:    [[T9:%.*]] = shufflevector <4 x i8> [[T6:%.*]], <4 x i8> [[T7:%.*]], <4 x i32> <i32 0, i32 1, i32 4, i32 5>
+; CHECK-NEXT:    ret <4 x i8> [[T9]]
+;
+  %t1 = shufflevector <4 x i8> %t6, <4 x i8> %t7, <8 x i32> <i32 0, i32 1, i32 4, i32 5, i32 4, i32 5, i32 2, i32 3>
+  %t9 = shufflevector <8 x i8> %t1, <8 x i8> undef, <4 x i32> <i32 0, i32 1, i32 4, i32 5>
+  ret <4 x i8> %t9
+}
+
+; Redundant vector splats should be removed.  Radar 8597790.
+define <4 x i32> @test10(<4 x i32> %t5) {
+; CHECK-LABEL: @test10(
+; CHECK-NEXT:    [[T7:%.*]] = shufflevector <4 x i32> [[T5:%.*]], <4 x i32> undef, <4 x i32> <i32 1, i32 1, i32 1, i32 1>
+; CHECK-NEXT:    ret <4 x i32> [[T7]]
+;
+  %t6 = shufflevector <4 x i32> %t5, <4 x i32> undef, <4 x i32> <i32 1, i32 undef, i32 undef, i32 undef>
+  %t7 = shufflevector <4 x i32> %t6, <4 x i32> undef, <4 x i32> zeroinitializer
+  ret <4 x i32> %t7
+}
+
+; Test fold of two shuffles where the two shufflevector inputs's op1 are the same.
+
+define <8 x i8> @test11(<16 x i8> %t6) {
+; CHECK-LABEL: @test11(
+; CHECK-NEXT:    [[T3:%.*]] = shufflevector <16 x i8> [[T6:%.*]], <16 x i8> undef, <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7>
+; CHECK-NEXT:    ret <8 x i8> [[T3]]
+;
+  %t1 = shufflevector <16 x i8> %t6, <16 x i8> undef, <4 x i32> <i32 0, i32 1, i32 2, i32 3>
+  %t2 = shufflevector <16 x i8> %t6, <16 x i8> undef, <4 x i32> <i32 4, i32 5, i32 6, i32 7>
+  %t3 = shufflevector <4 x i8> %t1, <4 x i8> %t2, <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7>
+  ret <8 x i8> %t3
+}
+
+; Test fold of two shuffles where the first shufflevector's inputs are the same as the second.
+
+define <8 x i8> @test12(<8 x i8> %t6, <8 x i8> %t2) {
+; CHECK-LABEL: @test12(
+; CHECK-NEXT:    [[T3:%.*]] = shufflevector <8 x i8> [[T6:%.*]], <8 x i8> [[T2:%.*]], <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 9, i32 8, i32 11, i32 12>
+; CHECK-NEXT:    ret <8 x i8> [[T3]]
+;
+  %t1 = shufflevector <8 x i8> %t6, <8 x i8> undef, <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 5, i32 4, i32 undef, i32 7>
+  %t3 = shufflevector <8 x i8> %t1, <8 x i8> %t2, <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 9, i32 8, i32 11, i32 12>
+  ret <8 x i8> %t3
+}
+
+; Test fold of two shuffles where the first shufflevector's inputs are the same as the second.
+
+define <8 x i8> @test12a(<8 x i8> %t6, <8 x i8> %t2) {
+; CHECK-LABEL: @test12a(
+; CHECK-NEXT:    [[T3:%.*]] = shufflevector <8 x i8> [[T2:%.*]], <8 x i8> [[T6:%.*]], <8 x i32> <i32 0, i32 3, i32 1, i32 4, i32 8, i32 9, i32 10, i32 11>
+; CHECK-NEXT:    ret <8 x i8> [[T3]]
+;
+  %t1 = shufflevector <8 x i8> %t6, <8 x i8> undef, <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 5, i32 4, i32 undef, i32 7>
+  %t3 = shufflevector <8 x i8> %t2, <8 x i8> %t1, <8 x i32> <i32 0, i32 3, i32 1, i32 4, i32 8, i32 9, i32 10, i32 11>
+  ret <8 x i8> %t3
+}
+
+; The mask length of the 1st shuffle can be reduced to eliminate the 2nd shuffle.
+
+define <2 x i8> @extract_subvector_of_shuffle(<2 x i8> %x, <2 x i8> %y) {
+; CHECK-LABEL: @extract_subvector_of_shuffle(
+; CHECK-NEXT:    [[EXTRACT_SUBV:%.*]] = shufflevector <2 x i8> [[X:%.*]], <2 x i8> [[Y:%.*]], <2 x i32> <i32 0, i32 2>
+; CHECK-NEXT:    ret <2 x i8> [[EXTRACT_SUBV]]
+;
+  %shuf = shufflevector <2 x i8> %x, <2 x i8> %y, <3 x i32> <i32 0, i32 2, i32 0>
+  %extract_subv = shufflevector <3 x i8> %shuf, <3 x i8> undef, <2 x i32> <i32 0, i32 1>
+  ret <2 x i8> %extract_subv
+}
+
+; Undef elements in either mask are ok. Undefs from the 2nd shuffle mask should propagate to the new shuffle.
+; The type of the inputs does not have to match the output type.
+
+define <4 x i8> @extract_subvector_of_shuffle_undefs_types(<2 x i8> %x, <2 x i8> %y) {
+; CHECK-LABEL: @extract_subvector_of_shuffle_undefs_types(
+; CHECK-NEXT:    [[EXTRACT_SUBV:%.*]] = shufflevector <2 x i8> [[X:%.*]], <2 x i8> [[Y:%.*]], <4 x i32> <i32 undef, i32 2, i32 0, i32 undef>
+; CHECK-NEXT:    ret <4 x i8> [[EXTRACT_SUBV]]
+;
+  %shuf = shufflevector <2 x i8> %x, <2 x i8> %y, <5 x i32> <i32 undef, i32 2, i32 0, i32 1, i32 0>
+  %extract_subv = shufflevector <5 x i8> %shuf, <5 x i8> undef, <4 x i32> <i32 0, i32 1, i32 2, i32 undef>
+  ret <4 x i8> %extract_subv
+}
+
+; Extra uses are not ok - we only do the transform when we can eliminate an instruction.
+
+declare void @use_v5i8(<5 x i8>)
+
+define <4 x i8> @extract_subvector_of_shuffle_extra_use(<2 x i8> %x, <2 x i8> %y) {
+; CHECK-LABEL: @extract_subvector_of_shuffle_extra_use(
+; CHECK-NEXT:    [[SHUF:%.*]] = shufflevector <2 x i8> [[X:%.*]], <2 x i8> [[Y:%.*]], <5 x i32> <i32 undef, i32 2, i32 0, i32 1, i32 0>
+; CHECK-NEXT:    call void @use_v5i8(<5 x i8> [[SHUF]])
+; CHECK-NEXT:    [[EXTRACT_SUBV:%.*]] = shufflevector <5 x i8> [[SHUF]], <5 x i8> undef, <4 x i32> <i32 0, i32 1, i32 2, i32 undef>
+; CHECK-NEXT:    ret <4 x i8> [[EXTRACT_SUBV]]
+;
+  %shuf = shufflevector <2 x i8> %x, <2 x i8> %y, <5 x i32> <i32 undef, i32 2, i32 0, i32 1, i32 0>
+  call void @use_v5i8(<5 x i8> %shuf)
+  %extract_subv = shufflevector <5 x i8> %shuf, <5 x i8> undef, <4 x i32> <i32 0, i32 1, i32 2, i32 undef>
+  ret <4 x i8> %extract_subv
+}
+
+define <2 x i8> @test13a(i8 %x1, i8 %x2) {
+; CHECK-LABEL: @test13a(
+; CHECK-NEXT:    [[TMP1:%.*]] = insertelement <2 x i8> undef, i8 [[X1:%.*]], i32 1
+; CHECK-NEXT:    [[TMP2:%.*]] = insertelement <2 x i8> [[TMP1]], i8 [[X2:%.*]], i32 0
+; CHECK-NEXT:    [[TMP3:%.*]] = add <2 x i8> [[TMP2]], <i8 7, i8 5>
+; CHECK-NEXT:    ret <2 x i8> [[TMP3]]
+;
+  %A = insertelement <2 x i8> undef, i8 %x1, i32 0
+  %B = insertelement <2 x i8> %A, i8 %x2, i32 1
+  %C = add <2 x i8> %B, <i8 5, i8 7>
+  %D = shufflevector <2 x i8> %C, <2 x i8> undef, <2 x i32> <i32 1, i32 0>
+  ret <2 x i8> %D
+}
+
+; Increasing length of vector ops is not a good canonicalization.
+
+define <3 x i32> @add_wider(i32 %y, i32 %z) {
+; CHECK-LABEL: @add_wider(
+; CHECK-NEXT:    [[I0:%.*]] = insertelement <2 x i32> undef, i32 [[Y:%.*]], i32 0
+; CHECK-NEXT:    [[I1:%.*]] = insertelement <2 x i32> [[I0]], i32 [[Z:%.*]], i32 1
+; CHECK-NEXT:    [[A:%.*]] = add <2 x i32> [[I1]], <i32 255, i32 255>
+; CHECK-NEXT:    [[EXT:%.*]] = shufflevector <2 x i32> [[A]], <2 x i32> undef, <3 x i32> <i32 0, i32 1, i32 undef>
+; CHECK-NEXT:    ret <3 x i32> [[EXT]]
+;
+  %i0 = insertelement <2 x i32> undef, i32 %y, i32 0
+  %i1 = insertelement <2 x i32> %i0, i32 %z, i32 1
+  %a = add <2 x i32> %i1, <i32 255, i32 255>
+  %ext = shufflevector <2 x i32> %a, <2 x i32> undef, <3 x i32> <i32 0, i32 1, i32 undef>
+  ret <3 x i32> %ext
+}
+
+; Increasing length of vector ops must be safe from illegal undef propagation.
+
+define <3 x i32> @div_wider(i32 %y, i32 %z) {
+; CHECK-LABEL: @div_wider(
+; CHECK-NEXT:    [[I0:%.*]] = insertelement <2 x i32> undef, i32 [[Y:%.*]], i32 0
+; CHECK-NEXT:    [[I1:%.*]] = insertelement <2 x i32> [[I0]], i32 [[Z:%.*]], i32 1
+; CHECK-NEXT:    [[A:%.*]] = sdiv <2 x i32> [[I1]], <i32 255, i32 255>
+; CHECK-NEXT:    [[EXT:%.*]] = shufflevector <2 x i32> [[A]], <2 x i32> undef, <3 x i32> <i32 0, i32 1, i32 undef>
+; CHECK-NEXT:    ret <3 x i32> [[EXT]]
+;
+  %i0 = insertelement <2 x i32> undef, i32 %y, i32 0
+  %i1 = insertelement <2 x i32> %i0, i32 %z, i32 1
+  %a = sdiv <2 x i32> %i1, <i32 255, i32 255>
+  %ext = shufflevector <2 x i32> %a, <2 x i32> undef, <3 x i32> <i32 0, i32 1, i32 undef>
+  ret <3 x i32> %ext
+}
+
+; Increasing length of insertelements (no math ops) is a good canonicalization.
+
+define <3 x i8> @fold_inselts_with_widening_shuffle(i8 %x, i8 %y) {
+; CHECK-LABEL: @fold_inselts_with_widening_shuffle(
+; CHECK-NEXT:    [[TMP1:%.*]] = insertelement <3 x i8> undef, i8 [[X:%.*]], i32 0
+; CHECK-NEXT:    [[TMP2:%.*]] = insertelement <3 x i8> [[TMP1]], i8 [[Y:%.*]], i32 1
+; CHECK-NEXT:    ret <3 x i8> [[TMP2]]
+;
+  %ins0 = insertelement <2 x i8> undef, i8 %x, i32 0
+  %ins1 = insertelement <2 x i8> %ins0, i8 %y, i32 1
+  %widen = shufflevector <2 x i8> %ins1, <2 x i8> undef, <3 x i32> <i32 0, i32 1, i32 undef>
+  ret <3 x i8> %widen
+}
+
+define <2 x i8> @test13b(i8 %x) {
+; CHECK-LABEL: @test13b(
+; CHECK-NEXT:    [[B:%.*]] = insertelement <2 x i8> undef, i8 [[X:%.*]], i32 1
+; CHECK-NEXT:    ret <2 x i8> [[B]]
+;
+  %A = insertelement <2 x i8> undef, i8 %x, i32 0
+  %B = shufflevector <2 x i8> %A, <2 x i8> undef, <2 x i32> <i32 undef, i32 0>
+  ret <2 x i8> %B
+}
+
+define <2 x i8> @test13c(i8 %x1, i8 %x2) {
+; CHECK-LABEL: @test13c(
+; CHECK-NEXT:    [[TMP1:%.*]] = insertelement <2 x i8> undef, i8 [[X1:%.*]], i32 0
+; CHECK-NEXT:    [[TMP2:%.*]] = insertelement <2 x i8> [[TMP1]], i8 [[X2:%.*]], i32 1
+; CHECK-NEXT:    ret <2 x i8> [[TMP2]]
+;
+  %A = insertelement <4 x i8> undef, i8 %x1, i32 0
+  %B = insertelement <4 x i8> %A, i8 %x2, i32 2
+  %C = shufflevector <4 x i8> %B, <4 x i8> undef, <2 x i32> <i32 0, i32 2>
+  ret <2 x i8> %C
+}
+
+define void @test14(i16 %conv10) {
+; CHECK-LABEL: @test14(
+; CHECK-NEXT:    store <4 x i16> <i16 undef, i16 undef, i16 undef, i16 23>, <4 x i16>* undef, align 8
+; CHECK-NEXT:    ret void
+;
+  %t = alloca <4 x i16>, align 8
+  %vecinit6 = insertelement <4 x i16> undef, i16 23, i32 3
+  store <4 x i16> %vecinit6, <4 x i16>* undef
+  %t1 = load <4 x i16>, <4 x i16>* undef
+  %vecinit11 = insertelement <4 x i16> undef, i16 %conv10, i32 3
+  %div = udiv <4 x i16> %t1, %vecinit11
+  store <4 x i16> %div, <4 x i16>* %t
+  %t4 = load <4 x i16>, <4 x i16>* %t
+  %t5 = shufflevector <4 x i16> %t4, <4 x i16> undef, <2 x i32> <i32 2, i32 0>
+  %cmp = icmp ule <2 x i16> %t5, undef
+  %sext = sext <2 x i1> %cmp to <2 x i16>
+  ret void
+}
+
+; Check that sequences of insert/extract element are
+; collapsed into valid shuffle instruction with correct shuffle indexes.
+
+define <4 x float> @test15a(<4 x float> %LHS, <4 x float> %RHS) {
+; CHECK-LABEL: @test15a(
+; CHECK-NEXT:    [[T4:%.*]] = shufflevector <4 x float> [[LHS:%.*]], <4 x float> [[RHS:%.*]], <4 x i32> <i32 4, i32 0, i32 6, i32 6>
+; CHECK-NEXT:    ret <4 x float> [[T4]]
+;
+  %t1 = extractelement <4 x float> %LHS, i32 0
+  %t2 = insertelement <4 x float> %RHS, float %t1, i32 1
+  %t3 = extractelement <4 x float> %RHS, i32 2
+  %t4 = insertelement <4 x float> %t2, float %t3, i32 3
+  ret <4 x float> %t4
+}
+
+define <4 x float> @test15b(<4 x float> %LHS, <4 x float> %RHS) {
+; CHECK-LABEL: @test15b(
+; CHECK-NEXT:    [[T5:%.*]] = shufflevector <4 x float> [[LHS:%.*]], <4 x float> [[RHS:%.*]], <4 x i32> <i32 4, i32 3, i32 6, i32 6>
+; CHECK-NEXT:    ret <4 x float> [[T5]]
+;
+  %t0 = extractelement <4 x float> %LHS, i32 3
+  %t1 = insertelement <4 x float> %RHS, float %t0, i32 0
+  %t2 = extractelement <4 x float> %t1, i32 0
+  %t3 = insertelement <4 x float> %RHS, float %t2, i32 1
+  %t4 = extractelement <4 x float> %RHS, i32 2
+  %t5 = insertelement <4 x float> %t3, float %t4, i32 3
+  ret <4 x float> %t5
+}
+
+define <1 x i32> @test16a(i32 %ele) {
+; CHECK-LABEL: @test16a(
+; CHECK-NEXT:    ret <1 x i32> <i32 2>
+;
+  %t0 = insertelement <2 x i32> <i32 1, i32 undef>, i32 %ele, i32 1
+  %t1 = shl <2 x i32> %t0, <i32 1, i32 1>
+  %t2 = shufflevector <2 x i32> %t1, <2 x i32> undef, <1 x i32> <i32 0>
+  ret <1 x i32> %t2
+}
+
+define <4 x i8> @test16b(i8 %ele) {
+; CHECK-LABEL: @test16b(
+; CHECK-NEXT:    ret <4 x i8> <i8 2, i8 2, i8 2, i8 2>
+;
+  %t0 = insertelement <8 x i8> <i8 1, i8 1, i8 1, i8 1, i8 1, i8 1, i8 undef, i8 1>, i8 %ele, i32 6
+  %t1 = shl <8 x i8> %t0, <i8 1, i8 1, i8 1, i8 1, i8 1, i8 1, i8 1, i8 1>
+  %t2 = shufflevector <8 x i8> %t1, <8 x i8> undef, <4 x i32> <i32 1, i32 2, i32 3, i32 4>
+  ret <4 x i8> %t2
+}
+
+; If composition of two shuffles is identity, shuffles can be removed.
+define <4 x i32> @shuffle_17ident(<4 x i32> %v) {
+; CHECK-LABEL: @shuffle_17ident(
+; CHECK-NEXT:    ret <4 x i32> [[V:%.*]]
+;
+  %shuffle = shufflevector <4 x i32> %v, <4 x i32> zeroinitializer, <4 x i32> <i32 1, i32 2, i32 3, i32 0>
+  %shuffle2 = shufflevector <4 x i32> %shuffle, <4 x i32> zeroinitializer, <4 x i32> <i32 3, i32 0, i32 1, i32 2>
+  ret <4 x i32> %shuffle2
+}
+
+; swizzle can be put after operation
+define <4 x i32> @shuffle_17and(<4 x i32> %v1, <4 x i32> %v2) {
+; CHECK-LABEL: @shuffle_17and(
+; CHECK-NEXT:    [[TMP1:%.*]] = and <4 x i32> [[V1:%.*]], [[V2:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = shufflevector <4 x i32> [[TMP1]], <4 x i32> undef, <4 x i32> <i32 1, i32 2, i32 3, i32 0>
+; CHECK-NEXT:    ret <4 x i32> [[R]]
+;
+  %t1 = shufflevector <4 x i32> %v1, <4 x i32> zeroinitializer, <4 x i32> <i32 1, i32 2, i32 3, i32 0>
+  %t2 = shufflevector <4 x i32> %v2, <4 x i32> zeroinitializer, <4 x i32> <i32 1, i32 2, i32 3, i32 0>
+  %r = and <4 x i32> %t1, %t2
+  ret <4 x i32> %r
+}
+
+declare void @use(<2 x float>)
+
+; One extra use is ok to transform.
+
+define <2 x float> @shuffle_fadd_multiuse(<2 x float> %v1, <2 x float> %v2) {
+; CHECK-LABEL: @shuffle_fadd_multiuse(
+; CHECK-NEXT:    [[T1:%.*]] = shufflevector <2 x float> [[V1:%.*]], <2 x float> undef, <2 x i32> <i32 1, i32 0>
+; CHECK-NEXT:    [[TMP1:%.*]] = fadd <2 x float> [[V1]], [[V2:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = shufflevector <2 x float> [[TMP1]], <2 x float> undef, <2 x i32> <i32 1, i32 0>
+; CHECK-NEXT:    call void @use(<2 x float> [[T1]])
+; CHECK-NEXT:    ret <2 x float> [[R]]
+;
+  %t1 = shufflevector <2 x float> %v1, <2 x float> undef, <2 x i32> <i32 1, i32 0>
+  %t2 = shufflevector <2 x float> %v2, <2 x float> undef, <2 x i32> <i32 1, i32 0>
+  %r = fadd <2 x float> %t1, %t2
+  call void @use(<2 x float> %t1)
+  ret <2 x float> %r
+}
+
+define <2 x float> @shuffle_fdiv_multiuse(<2 x float> %v1, <2 x float> %v2) {
+; CHECK-LABEL: @shuffle_fdiv_multiuse(
+; CHECK-NEXT:    [[T2:%.*]] = shufflevector <2 x float> [[V2:%.*]], <2 x float> undef, <2 x i32> <i32 1, i32 0>
+; CHECK-NEXT:    [[TMP1:%.*]] = fdiv <2 x float> [[V1:%.*]], [[V2]]
+; CHECK-NEXT:    [[R:%.*]] = shufflevector <2 x float> [[TMP1]], <2 x float> undef, <2 x i32> <i32 1, i32 0>
+; CHECK-NEXT:    call void @use(<2 x float> [[T2]])
+; CHECK-NEXT:    ret <2 x float> [[R]]
+;
+  %t1 = shufflevector <2 x float> %v1, <2 x float> undef, <2 x i32> <i32 1, i32 0>
+  %t2 = shufflevector <2 x float> %v2, <2 x float> undef, <2 x i32> <i32 1, i32 0>
+  %r = fdiv <2 x float> %t1, %t2
+  call void @use(<2 x float> %t2)
+  ret <2 x float> %r
+}
+
+; But 2 extra uses would require an extra instruction.
+
+define <2 x float> @shuffle_fsub_multiuse(<2 x float> %v1, <2 x float> %v2) {
+; CHECK-LABEL: @shuffle_fsub_multiuse(
+; CHECK-NEXT:    [[T1:%.*]] = shufflevector <2 x float> [[V1:%.*]], <2 x float> undef, <2 x i32> <i32 1, i32 0>
+; CHECK-NEXT:    [[T2:%.*]] = shufflevector <2 x float> [[V2:%.*]], <2 x float> undef, <2 x i32> <i32 1, i32 0>
+; CHECK-NEXT:    [[R:%.*]] = fsub <2 x float> [[T1]], [[T2]]
+; CHECK-NEXT:    call void @use(<2 x float> [[T1]])
+; CHECK-NEXT:    call void @use(<2 x float> [[T2]])
+; CHECK-NEXT:    ret <2 x float> [[R]]
+;
+  %t1 = shufflevector <2 x float> %v1, <2 x float> undef, <2 x i32> <i32 1, i32 0>
+  %t2 = shufflevector <2 x float> %v2, <2 x float> undef, <2 x i32> <i32 1, i32 0>
+  %r = fsub <2 x float> %t1, %t2
+  call void @use(<2 x float> %t1)
+  call void @use(<2 x float> %t2)
+  ret <2 x float> %r
+}
+
+define <4 x i32> @shuffle_17add(<4 x i32> %v1, <4 x i32> %v2) {
+; CHECK-LABEL: @shuffle_17add(
+; CHECK-NEXT:    [[TMP1:%.*]] = add <4 x i32> [[V1:%.*]], [[V2:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = shufflevector <4 x i32> [[TMP1]], <4 x i32> undef, <4 x i32> <i32 1, i32 2, i32 3, i32 0>
+; CHECK-NEXT:    ret <4 x i32> [[R]]
+;
+  %t1 = shufflevector <4 x i32> %v1, <4 x i32> zeroinitializer, <4 x i32> <i32 1, i32 2, i32 3, i32 0>
+  %t2 = shufflevector <4 x i32> %v2, <4 x i32> zeroinitializer, <4 x i32> <i32 1, i32 2, i32 3, i32 0>
+  %r = add <4 x i32> %t1, %t2
+  ret <4 x i32> %r
+}
+
+define <4 x i32> @shuffle_17addnsw(<4 x i32> %v1, <4 x i32> %v2) {
+; CHECK-LABEL: @shuffle_17addnsw(
+; CHECK-NEXT:    [[TMP1:%.*]] = add nsw <4 x i32> [[V1:%.*]], [[V2:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = shufflevector <4 x i32> [[TMP1]], <4 x i32> undef, <4 x i32> <i32 1, i32 2, i32 3, i32 0>
+; CHECK-NEXT:    ret <4 x i32> [[R]]
+;
+  %t1 = shufflevector <4 x i32> %v1, <4 x i32> zeroinitializer, <4 x i32> <i32 1, i32 2, i32 3, i32 0>
+  %t2 = shufflevector <4 x i32> %v2, <4 x i32> zeroinitializer, <4 x i32> <i32 1, i32 2, i32 3, i32 0>
+  %r = add nsw <4 x i32> %t1, %t2
+  ret <4 x i32> %r
+}
+
+define <4 x i32> @shuffle_17addnuw(<4 x i32> %v1, <4 x i32> %v2) {
+; CHECK-LABEL: @shuffle_17addnuw(
+; CHECK-NEXT:    [[TMP1:%.*]] = add nuw <4 x i32> [[V1:%.*]], [[V2:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = shufflevector <4 x i32> [[TMP1]], <4 x i32> undef, <4 x i32> <i32 1, i32 2, i32 3, i32 0>
+; CHECK-NEXT:    ret <4 x i32> [[R]]
+;
+  %t1 = shufflevector <4 x i32> %v1, <4 x i32> zeroinitializer, <4 x i32> <i32 1, i32 2, i32 3, i32 0>
+  %t2 = shufflevector <4 x i32> %v2, <4 x i32> zeroinitializer, <4 x i32> <i32 1, i32 2, i32 3, i32 0>
+  %r = add nuw <4 x i32> %t1, %t2
+  ret <4 x i32> %r
+}
+
+define <4 x float> @shuffle_17fsub_fast(<4 x float> %v1, <4 x float> %v2) {
+; CHECK-LABEL: @shuffle_17fsub_fast(
+; CHECK-NEXT:    [[TMP1:%.*]] = fsub fast <4 x float> [[V1:%.*]], [[V2:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = shufflevector <4 x float> [[TMP1]], <4 x float> undef, <4 x i32> <i32 1, i32 2, i32 3, i32 0>
+; CHECK-NEXT:    ret <4 x float> [[R]]
+;
+  %t1 = shufflevector <4 x float> %v1, <4 x float> zeroinitializer, <4 x i32> <i32 1, i32 2, i32 3, i32 0>
+  %t2 = shufflevector <4 x float> %v2, <4 x float> zeroinitializer, <4 x i32> <i32 1, i32 2, i32 3, i32 0>
+  %r = fsub fast <4 x float> %t1, %t2
+  ret <4 x float> %r
+}
+
+define <4 x i32> @add_const(<4 x i32> %v) {
+; CHECK-LABEL: @add_const(
+; CHECK-NEXT:    [[TMP1:%.*]] = add <4 x i32> [[V:%.*]], <i32 44, i32 41, i32 42, i32 43>
+; CHECK-NEXT:    [[R:%.*]] = shufflevector <4 x i32> [[TMP1]], <4 x i32> undef, <4 x i32> <i32 1, i32 2, i32 3, i32 0>
+; CHECK-NEXT:    ret <4 x i32> [[R]]
+;
+  %t1 = shufflevector <4 x i32> %v, <4 x i32> undef, <4 x i32> <i32 1, i32 2, i32 3, i32 0>
+  %r = add <4 x i32> %t1, <i32 41, i32 42, i32 43, i32 44>
+  ret <4 x i32> %r
+}
+
+define <4 x i32> @sub_const(<4 x i32> %v) {
+; CHECK-LABEL: @sub_const(
+; CHECK-NEXT:    [[TMP1:%.*]] = sub <4 x i32> <i32 44, i32 43, i32 42, i32 41>, [[V:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = shufflevector <4 x i32> [[TMP1]], <4 x i32> undef, <4 x i32> <i32 3, i32 2, i32 1, i32 0>
+; CHECK-NEXT:    ret <4 x i32> [[R]]
+;
+  %t1 = shufflevector <4 x i32> %v, <4 x i32> undef, <4 x i32> <i32 3, i32 2, i32 1, i32 0>
+  %r = sub <4 x i32> <i32 41, i32 42, i32 43, i32 44>, %t1
+  ret <4 x i32> %r
+}
+
+; Math before shuffle requires an extra shuffle.
+
+define <2 x float> @fadd_const_multiuse(<2 x float> %v) {
+; CHECK-LABEL: @fadd_const_multiuse(
+; CHECK-NEXT:    [[T1:%.*]] = shufflevector <2 x float> [[V:%.*]], <2 x float> undef, <2 x i32> <i32 1, i32 0>
+; CHECK-NEXT:    [[R:%.*]] = fadd <2 x float> [[T1]], <float 4.100000e+01, float 4.200000e+01>
+; CHECK-NEXT:    call void @use(<2 x float> [[T1]])
+; CHECK-NEXT:    ret <2 x float> [[R]]
+;
+  %t1 = shufflevector <2 x float> %v, <2 x float> undef, <2 x i32> <i32 1, i32 0>
+  %r = fadd <2 x float> %t1, <float 41.0, float 42.0>
+  call void @use(<2 x float> %t1)
+  ret <2 x float> %r
+}
+
+; Math before splat allows replacing constant elements with undef lanes.
+
+define <4 x i32> @mul_const_splat(<4 x i32> %v) {
+; CHECK-LABEL: @mul_const_splat(
+; CHECK-NEXT:    [[TMP1:%.*]] = mul <4 x i32> [[V:%.*]], <i32 undef, i32 42, i32 undef, i32 undef>
+; CHECK-NEXT:    [[R:%.*]] = shufflevector <4 x i32> [[TMP1]], <4 x i32> undef, <4 x i32> <i32 1, i32 1, i32 1, i32 1>
+; CHECK-NEXT:    ret <4 x i32> [[R]]
+;
+  %t1 = shufflevector <4 x i32> %v, <4 x i32> undef, <4 x i32> <i32 1, i32 1, i32 1, i32 1>
+  %r = mul <4 x i32> <i32 42, i32 42, i32 42, i32 42>, %t1
+  ret <4 x i32> %r
+}
+
+; Take 2 elements of a vector and shift each of those by a different amount
+
+define <4 x i32> @lshr_const_half_splat(<4 x i32> %v) {
+; CHECK-LABEL: @lshr_const_half_splat(
+; CHECK-NEXT:    [[TMP1:%.*]] = lshr <4 x i32> <i32 undef, i32 8, i32 9, i32 undef>, [[V:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = shufflevector <4 x i32> [[TMP1]], <4 x i32> undef, <4 x i32> <i32 1, i32 1, i32 2, i32 2>
+; CHECK-NEXT:    ret <4 x i32> [[R]]
+;
+  %t1 = shufflevector <4 x i32> %v, <4 x i32> undef, <4 x i32> <i32 1, i32 1, i32 2, i32 2>
+  %r = lshr <4 x i32> <i32 8, i32 8, i32 9, i32 9>, %t1
+  ret <4 x i32> %r
+}
+
+; We can't change this because there's no pre-shuffle version of the fmul constant.
+
+define <2 x float> @fmul_const_invalid_constant(<2 x float> %v) {
+; CHECK-LABEL: @fmul_const_invalid_constant(
+; CHECK-NEXT:    [[T1:%.*]] = shufflevector <2 x float> [[V:%.*]], <2 x float> undef, <2 x i32> zeroinitializer
+; CHECK-NEXT:    [[R:%.*]] = fmul <2 x float> [[T1]], <float 4.100000e+01, float 4.200000e+01>
+; CHECK-NEXT:    ret <2 x float> [[R]]
+;
+  %t1 = shufflevector <2 x float> %v, <2 x float> undef, <2 x i32> <i32 0, i32 0>
+  %r = fmul <2 x float> %t1, <float 41.0, float 42.0>
+  ret <2 x float> %r
+}
+
+; Reduce the width of the binop by moving it ahead of a shuffle.
+
+define <4 x i8> @widening_shuffle_add_1(<2 x i8> %x) {
+; CHECK-LABEL: @widening_shuffle_add_1(
+; CHECK-NEXT:    [[TMP1:%.*]] = add <2 x i8> [[X:%.*]], <i8 42, i8 43>
+; CHECK-NEXT:    [[R:%.*]] = shufflevector <2 x i8> [[TMP1]], <2 x i8> undef, <4 x i32> <i32 0, i32 1, i32 undef, i32 undef>
+; CHECK-NEXT:    ret <4 x i8> [[R]]
+;
+  %widex = shufflevector <2 x i8> %x, <2 x i8> undef, <4 x i32> <i32 0, i32 1, i32 undef, i32 undef>
+  %r = add <4 x i8> %widex, <i8 42, i8 43, i8 44, i8 45>
+  ret <4 x i8> %r
+}
+
+; Reduce the width of the binop by moving it ahead of a shuffle.
+
+define <4 x i8> @widening_shuffle_add_2(<2 x i8> %x) {
+; CHECK-LABEL: @widening_shuffle_add_2(
+; CHECK-NEXT:    [[TMP1:%.*]] = add <2 x i8> [[X:%.*]], <i8 43, i8 42>
+; CHECK-NEXT:    [[R:%.*]] = shufflevector <2 x i8> [[TMP1]], <2 x i8> undef, <4 x i32> <i32 1, i32 0, i32 undef, i32 undef>
+; CHECK-NEXT:    ret <4 x i8> [[R]]
+;
+  %widex = shufflevector <2 x i8> %x, <2 x i8> undef, <4 x i32> <i32 1, i32 0, i32 undef, i32 undef>
+  %r = add <4 x i8> %widex, <i8 42, i8 43, i8 44, i8 45>
+  ret <4 x i8> %r
+}
+
+; Negative test - widening shuffles have the same mask/constant constraint as non-size-changing shuffles.
+
+define <4 x i8> @widening_shuffle_add_invalid_constant(<2 x i8> %x) {
+; CHECK-LABEL: @widening_shuffle_add_invalid_constant(
+; CHECK-NEXT:    [[WIDEX:%.*]] = shufflevector <2 x i8> [[X:%.*]], <2 x i8> undef, <4 x i32> <i32 1, i32 1, i32 undef, i32 undef>
+; CHECK-NEXT:    [[R:%.*]] = add <4 x i8> [[WIDEX]], <i8 42, i8 43, i8 44, i8 45>
+; CHECK-NEXT:    ret <4 x i8> [[R]]
+;
+  %widex = shufflevector <2 x i8> %x, <2 x i8> undef, <4 x i32> <i32 1, i32 1, i32 undef, i32 undef>
+  %r = add <4 x i8> %widex, <i8 42, i8 43, i8 44, i8 45>
+  ret <4 x i8> %r
+}
+
+; Negative test - widening shuffles have an additional constraint: they must not extend with anything but undefs.
+
+define <4 x i8> @widening_shuffle_add_invalid_mask(<2 x i8> %x) {
+; CHECK-LABEL: @widening_shuffle_add_invalid_mask(
+; CHECK-NEXT:    [[WIDEX:%.*]] = shufflevector <2 x i8> [[X:%.*]], <2 x i8> undef, <4 x i32> <i32 0, i32 1, i32 undef, i32 0>
+; CHECK-NEXT:    [[R:%.*]] = add <4 x i8> [[WIDEX]], <i8 42, i8 43, i8 44, i8 45>
+; CHECK-NEXT:    ret <4 x i8> [[R]]
+;
+  %widex = shufflevector <2 x i8> %x, <2 x i8> undef, <4 x i32> <i32 0, i32 1, i32 undef, i32 0>
+  %r = add <4 x i8> %widex, <i8 42, i8 43, i8 44, i8 45>
+  ret <4 x i8> %r
+}
+
+; A binop that produces undef in the high lanes can be moved before the shuffle.
+; This is ok because 'shl C, undef --> undef'.
+
+define <4 x i16> @widening_shuffle_shl_constant_op0(<2 x i16> %v) {
+; CHECK-LABEL: @widening_shuffle_shl_constant_op0(
+; CHECK-NEXT:    [[TMP1:%.*]] = shl <2 x i16> <i16 42, i16 -42>, [[V:%.*]]
+; CHECK-NEXT:    [[BO:%.*]] = shufflevector <2 x i16> [[TMP1]], <2 x i16> undef, <4 x i32> <i32 0, i32 1, i32 undef, i32 undef>
+; CHECK-NEXT:    ret <4 x i16> [[BO]]
+;
+  %shuf = shufflevector <2 x i16> %v, <2 x i16> undef, <4 x i32> <i32 0, i32 1, i32 undef, i32 undef>
+  %bo = shl <4 x i16> <i16 42, i16 -42, i16 -1, i16 -1>, %shuf
+  ret <4 x i16> %bo
+}
+
+; A binop that produces undef in the high lanes can be moved before the shuffle.
+; This is ok because 'shl undef, 0 --> undef'.
+
+define <4 x i16> @widening_shuffle_shl_constant_op1(<2 x i16> %v) {
+; CHECK-LABEL: @widening_shuffle_shl_constant_op1(
+; CHECK-NEXT:    [[TMP1:%.*]] = shl <2 x i16> [[V:%.*]], <i16 2, i16 4>
+; CHECK-NEXT:    [[BO:%.*]] = shufflevector <2 x i16> [[TMP1]], <2 x i16> undef, <4 x i32> <i32 0, i32 1, i32 undef, i32 undef>
+; CHECK-NEXT:    ret <4 x i16> [[BO]]
+;
+  %shuf = shufflevector <2 x i16> %v, <2 x i16> undef, <4 x i32> <i32 0, i32 1, i32 undef, i32 undef>
+  %bo = shl <4 x i16> %shuf, <i16 2, i16 4, i16 0, i16 0>
+  ret <4 x i16> %bo
+}
+
+; A binop that does not produce undef in the high lanes can not be moved before the shuffle.
+; This is not ok because 'shl undef, 1 (or 2)' --> 0' but moving the shuffle results in undef instead.
+
+define <4 x i16> @widening_shuffle_shl_constant_op1_non0(<2 x i16> %v) {
+; CHECK-LABEL: @widening_shuffle_shl_constant_op1_non0(
+; CHECK-NEXT:    [[SHUF:%.*]] = shufflevector <2 x i16> [[V:%.*]], <2 x i16> undef, <4 x i32> <i32 0, i32 1, i32 undef, i32 undef>
+; CHECK-NEXT:    [[BO:%.*]] = shl <4 x i16> [[SHUF]], <i16 2, i16 4, i16 1, i16 2>
+; CHECK-NEXT:    ret <4 x i16> [[BO]]
+;
+  %shuf = shufflevector <2 x i16> %v, <2 x i16> undef, <4 x i32> <i32 0, i32 1, i32 undef, i32 undef>
+  %bo = shl <4 x i16> %shuf, <i16 2, i16 4, i16 1, i16 2>
+  ret <4 x i16> %bo
+}
+
+; A binop that does not produce undef in the high lanes can not be moved before the shuffle.
+; This is not ok because 'or -1, undef --> -1' but moving the shuffle results in undef instead.
+
+define <4 x i16> @widening_shuffle_or(<2 x i16> %v) {
+; CHECK-LABEL: @widening_shuffle_or(
+; CHECK-NEXT:    [[SHUF:%.*]] = shufflevector <2 x i16> [[V:%.*]], <2 x i16> undef, <4 x i32> <i32 0, i32 1, i32 undef, i32 undef>
+; CHECK-NEXT:    [[BO:%.*]] = or <4 x i16> [[SHUF]], <i16 42, i16 -42, i16 -1, i16 -1>
+; CHECK-NEXT:    ret <4 x i16> [[BO]]
+;
+  %shuf = shufflevector <2 x i16> %v, <2 x i16> undef, <4 x i32> <i32 0, i32 1, i32 undef, i32 undef>
+  %bo = or <4 x i16> %shuf, <i16 42, i16 -42, i16 -1, i16 -1>
+  ret <4 x i16> %bo
+}
+
+define <4 x i32> @shuffle_17add2(<4 x i32> %v) {
+; CHECK-LABEL: @shuffle_17add2(
+; CHECK-NEXT:    [[TMP1:%.*]] = shl <4 x i32> [[V:%.*]], <i32 1, i32 1, i32 1, i32 1>
+; CHECK-NEXT:    ret <4 x i32> [[TMP1]]
+;
+  %t1 = shufflevector <4 x i32> %v, <4 x i32> zeroinitializer, <4 x i32> <i32 3, i32 2, i32 1, i32 0>
+  %t2 = add <4 x i32> %t1, %t1
+  %r = shufflevector <4 x i32> %t2, <4 x i32> zeroinitializer, <4 x i32> <i32 3, i32 2, i32 1, i32 0>
+  ret <4 x i32> %r
+}
+
+define <4 x i32> @shuffle_17mulsplat(<4 x i32> %v) {
+; CHECK-LABEL: @shuffle_17mulsplat(
+; CHECK-NEXT:    [[TMP1:%.*]] = mul <4 x i32> [[V:%.*]], [[V]]
+; CHECK-NEXT:    [[M1:%.*]] = shufflevector <4 x i32> [[TMP1]], <4 x i32> undef, <4 x i32> zeroinitializer
+; CHECK-NEXT:    ret <4 x i32> [[M1]]
+;
+  %s1 = shufflevector <4 x i32> %v, <4 x i32> zeroinitializer, <4 x i32> zeroinitializer
+  %m1 = mul <4 x i32> %s1, %s1
+  %s2 = shufflevector <4 x i32> %m1, <4 x i32> zeroinitializer, <4 x i32> <i32 1, i32 1, i32 1, i32 1>
+  ret <4 x i32> %s2
+}
+
+; Do not reorder shuffle and binop if LHS of shuffles are of different size
+define <2 x i32> @pr19717(<4 x i32> %in0, <2 x i32> %in1) {
+; CHECK-LABEL: @pr19717(
+; CHECK-NEXT:    [[SHUFFLE:%.*]] = shufflevector <4 x i32> [[IN0:%.*]], <4 x i32> undef, <2 x i32> zeroinitializer
+; CHECK-NEXT:    [[SHUFFLE4:%.*]] = shufflevector <2 x i32> [[IN1:%.*]], <2 x i32> undef, <2 x i32> zeroinitializer
+; CHECK-NEXT:    [[MUL:%.*]] = mul <2 x i32> [[SHUFFLE]], [[SHUFFLE4]]
+; CHECK-NEXT:    ret <2 x i32> [[MUL]]
+;
+  %shuffle = shufflevector <4 x i32> %in0, <4 x i32> %in0, <2 x i32> zeroinitializer
+  %shuffle4 = shufflevector <2 x i32> %in1, <2 x i32> %in1, <2 x i32> zeroinitializer
+  %mul = mul <2 x i32> %shuffle, %shuffle4
+  ret <2 x i32> %mul
+}
+
+define <4 x i16> @pr19717a(<8 x i16> %in0, <8 x i16> %in1) {
+; CHECK-LABEL: @pr19717a(
+; CHECK-NEXT:    [[TMP1:%.*]] = mul <8 x i16> [[IN0:%.*]], [[IN1:%.*]]
+; CHECK-NEXT:    [[MUL:%.*]] = shufflevector <8 x i16> [[TMP1]], <8 x i16> undef, <4 x i32> <i32 5, i32 5, i32 5, i32 5>
+; CHECK-NEXT:    ret <4 x i16> [[MUL]]
+;
+  %shuffle = shufflevector <8 x i16> %in0, <8 x i16> %in0, <4 x i32> <i32 5, i32 5, i32 5, i32 5>
+  %shuffle1 = shufflevector <8 x i16> %in1, <8 x i16> %in1, <4 x i32> <i32 5, i32 5, i32 5, i32 5>
+  %mul = mul <4 x i16> %shuffle, %shuffle1
+  ret <4 x i16> %mul
+}
+
+define <8 x i8> @pr19730(<16 x i8> %in0) {
+; CHECK-LABEL: @pr19730(
+; CHECK-NEXT:    [[SHUFFLE:%.*]] = shufflevector <16 x i8> [[IN0:%.*]], <16 x i8> undef, <8 x i32> <i32 7, i32 6, i32 5, i32 4, i32 3, i32 2, i32 1, i32 0>
+; CHECK-NEXT:    [[SHUFFLE1:%.*]] = shufflevector <8 x i8> [[SHUFFLE]], <8 x i8> undef, <8 x i32> <i32 7, i32 6, i32 5, i32 4, i32 3, i32 2, i32 1, i32 0>
+; CHECK-NEXT:    ret <8 x i8> [[SHUFFLE1]]
+;
+  %shuffle = shufflevector <16 x i8> %in0, <16 x i8> undef, <8 x i32> <i32 7, i32 6, i32 5, i32 4, i32 3, i32 2, i32 1, i32 0>
+  %shuffle1 = shufflevector <8 x i8> %shuffle, <8 x i8> undef, <8 x i32> <i32 7, i32 6, i32 5, i32 4, i32 3, i32 2, i32 1, i32 0>
+  ret <8 x i8> %shuffle1
+}
+
+define i32 @pr19737(<4 x i32> %in0) {
+; CHECK-LABEL: @pr19737(
+; CHECK-NEXT:    [[TMP1:%.*]] = extractelement <4 x i32> [[IN0:%.*]], i32 0
+; CHECK-NEXT:    ret i32 [[TMP1]]
+;
+  %shuffle.i = shufflevector <4 x i32> zeroinitializer, <4 x i32> %in0, <4 x i32> <i32 0, i32 4, i32 2, i32 6>
+  %neg.i = xor <4 x i32> %shuffle.i, <i32 -1, i32 -1, i32 -1, i32 -1>
+  %and.i = and <4 x i32> %in0, %neg.i
+  %rv = extractelement <4 x i32> %and.i, i32 0
+  ret i32 %rv
+}
+
+; In PR20059 ( http://llvm.org/pr20059 ), shufflevector operations are reordered/removed
+; for an srem operation. This is not a valid optimization because it may cause a trap
+; on div-by-zero.
+
+define <4 x i32> @pr20059(<4 x i32> %p1, <4 x i32> %p2) {
+; CHECK-LABEL: @pr20059(
+; CHECK-NEXT:    [[SPLAT1:%.*]] = shufflevector <4 x i32> [[P1:%.*]], <4 x i32> undef, <4 x i32> zeroinitializer
+; CHECK-NEXT:    [[SPLAT2:%.*]] = shufflevector <4 x i32> [[P2:%.*]], <4 x i32> undef, <4 x i32> zeroinitializer
+; CHECK-NEXT:    [[RETVAL:%.*]] = srem <4 x i32> [[SPLAT1]], [[SPLAT2]]
+; CHECK-NEXT:    ret <4 x i32> [[RETVAL]]
+;
+  %splat1 = shufflevector <4 x i32> %p1, <4 x i32> undef, <4 x i32> zeroinitializer
+  %splat2 = shufflevector <4 x i32> %p2, <4 x i32> undef, <4 x i32> zeroinitializer
+  %retval = srem <4 x i32> %splat1, %splat2
+  ret <4 x i32> %retval
+}
+
+define <4 x i32> @pr20114(<4 x i32> %__mask) {
+; CHECK-LABEL: @pr20114(
+; CHECK-NEXT:    [[MASK01_I:%.*]] = shufflevector <4 x i32> [[__MASK:%.*]], <4 x i32> undef, <4 x i32> <i32 0, i32 0, i32 1, i32 1>
+; CHECK-NEXT:    [[MASKED_NEW_I_I_I:%.*]] = and <4 x i32> [[MASK01_I]], bitcast (<2 x i64> <i64 ptrtoint (<4 x i32> (<4 x i32>)* @pr20114 to i64), i64 ptrtoint (<4 x i32> (<4 x i32>)* @pr20114 to i64)> to <4 x i32>)
+; CHECK-NEXT:    ret <4 x i32> [[MASKED_NEW_I_I_I]]
+;
+  %mask01.i = shufflevector <4 x i32> %__mask, <4 x i32> undef, <4 x i32> <i32 0, i32 0, i32 1, i32 1>
+  %masked_new.i.i.i = and <4 x i32> bitcast (<2 x i64> <i64 ptrtoint (<4 x i32> (<4 x i32>)* @pr20114 to i64), i64 ptrtoint (<4 x i32> (<4 x i32>)* @pr20114 to i64)> to <4 x i32>), %mask01.i
+  ret <4 x i32> %masked_new.i.i.i
+}
+
+define <2 x i32*> @pr23113(<4 x i32*> %A) {
+; CHECK-LABEL: @pr23113(
+; CHECK-NEXT:    [[TMP1:%.*]] = shufflevector <4 x i32*> [[A:%.*]], <4 x i32*> undef, <2 x i32> <i32 0, i32 1>
+; CHECK-NEXT:    ret <2 x i32*> [[TMP1]]
+;
+  %1 = shufflevector <4 x i32*> %A, <4 x i32*> undef, <2 x i32> <i32 0, i32 1>
+  ret <2 x i32*> %1
+}
+
+; Unused lanes in the new binop should not kill the entire op (although it may simplify anyway as shown here).
+
+define <2 x i32> @PR37648(<2 x i32> %x) {
+; CHECK-LABEL: @PR37648(
+; CHECK-NEXT:    ret <2 x i32> zeroinitializer
+;
+  %splat = shufflevector <2 x i32> %x, <2 x i32> undef, <2 x i32> zeroinitializer
+  %r = urem <2 x i32> %splat, <i32 1, i32 1>
+  ret <2 x i32> %r
+}
+
+; Test shuffle followed by binop with splat constant for all 18 binop opcodes.
+; Test with constant as operand 0 and operand 1 for non-commutative opcodes.
+
+define <2 x i32> @add_splat_constant(<2 x i32> %x) {
+; CHECK-LABEL: @add_splat_constant(
+; CHECK-NEXT:    [[TMP1:%.*]] = add <2 x i32> [[X:%.*]], <i32 42, i32 undef>
+; CHECK-NEXT:    [[R:%.*]] = shufflevector <2 x i32> [[TMP1]], <2 x i32> undef, <2 x i32> zeroinitializer
+; CHECK-NEXT:    ret <2 x i32> [[R]]
+;
+  %splat = shufflevector <2 x i32> %x, <2 x i32> undef, <2 x i32> zeroinitializer
+  %r = add <2 x i32> %splat, <i32 42, i32 42>
+  ret <2 x i32> %r
+}
+
+define <2 x i32> @sub_splat_constant0(<2 x i32> %x) {
+; CHECK-LABEL: @sub_splat_constant0(
+; CHECK-NEXT:    [[TMP1:%.*]] = sub <2 x i32> <i32 42, i32 undef>, [[X:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = shufflevector <2 x i32> [[TMP1]], <2 x i32> undef, <2 x i32> zeroinitializer
+; CHECK-NEXT:    ret <2 x i32> [[R]]
+;
+  %splat = shufflevector <2 x i32> %x, <2 x i32> undef, <2 x i32> zeroinitializer
+  %r = sub <2 x i32> <i32 42, i32 42>, %splat
+  ret <2 x i32> %r
+}
+
+define <2 x i32> @sub_splat_constant1(<2 x i32> %x) {
+; CHECK-LABEL: @sub_splat_constant1(
+; CHECK-NEXT:    [[TMP1:%.*]] = add <2 x i32> [[X:%.*]], <i32 -42, i32 undef>
+; CHECK-NEXT:    [[R:%.*]] = shufflevector <2 x i32> [[TMP1]], <2 x i32> undef, <2 x i32> zeroinitializer
+; CHECK-NEXT:    ret <2 x i32> [[R]]
+;
+  %splat = shufflevector <2 x i32> %x, <2 x i32> undef, <2 x i32> zeroinitializer
+  %r = sub <2 x i32> %splat, <i32 42, i32 42>
+  ret <2 x i32> %r
+}
+
+define <2 x i32> @mul_splat_constant(<2 x i32> %x) {
+; CHECK-LABEL: @mul_splat_constant(
+; CHECK-NEXT:    [[TMP1:%.*]] = mul <2 x i32> [[X:%.*]], <i32 42, i32 undef>
+; CHECK-NEXT:    [[R:%.*]] = shufflevector <2 x i32> [[TMP1]], <2 x i32> undef, <2 x i32> zeroinitializer
+; CHECK-NEXT:    ret <2 x i32> [[R]]
+;
+  %splat = shufflevector <2 x i32> %x, <2 x i32> undef, <2 x i32> zeroinitializer
+  %r = mul <2 x i32> %splat, <i32 42, i32 42>
+  ret <2 x i32> %r
+}
+
+define <2 x i32> @shl_splat_constant0(<2 x i32> %x) {
+; CHECK-LABEL: @shl_splat_constant0(
+; CHECK-NEXT:    [[TMP1:%.*]] = shl <2 x i32> <i32 5, i32 undef>, [[X:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = shufflevector <2 x i32> [[TMP1]], <2 x i32> undef, <2 x i32> zeroinitializer
+; CHECK-NEXT:    ret <2 x i32> [[R]]
+;
+  %splat = shufflevector <2 x i32> %x, <2 x i32> undef, <2 x i32> zeroinitializer
+  %r = shl <2 x i32> <i32 5, i32 5>, %splat
+  ret <2 x i32> %r
+}
+
+define <2 x i32> @shl_splat_constant1(<2 x i32> %x) {
+; CHECK-LABEL: @shl_splat_constant1(
+; CHECK-NEXT:    [[TMP1:%.*]] = shl <2 x i32> [[X:%.*]], <i32 5, i32 0>
+; CHECK-NEXT:    [[R:%.*]] = shufflevector <2 x i32> [[TMP1]], <2 x i32> undef, <2 x i32> zeroinitializer
+; CHECK-NEXT:    ret <2 x i32> [[R]]
+;
+  %splat = shufflevector <2 x i32> %x, <2 x i32> undef, <2 x i32> zeroinitializer
+  %r = shl <2 x i32> %splat, <i32 5, i32 5>
+  ret <2 x i32> %r
+}
+
+define <2 x i32> @ashr_splat_constant0(<2 x i32> %x) {
+; CHECK-LABEL: @ashr_splat_constant0(
+; CHECK-NEXT:    [[TMP1:%.*]] = ashr <2 x i32> <i32 5, i32 undef>, [[X:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = shufflevector <2 x i32> [[TMP1]], <2 x i32> undef, <2 x i32> zeroinitializer
+; CHECK-NEXT:    ret <2 x i32> [[R]]
+;
+  %splat = shufflevector <2 x i32> %x, <2 x i32> undef, <2 x i32> zeroinitializer
+  %r = ashr <2 x i32> <i32 5, i32 5>, %splat
+  ret <2 x i32> %r
+}
+
+define <2 x i32> @ashr_splat_constant1(<2 x i32> %x) {
+; CHECK-LABEL: @ashr_splat_constant1(
+; CHECK-NEXT:    [[TMP1:%.*]] = ashr <2 x i32> [[X:%.*]], <i32 5, i32 0>
+; CHECK-NEXT:    [[R:%.*]] = shufflevector <2 x i32> [[TMP1]], <2 x i32> undef, <2 x i32> zeroinitializer
+; CHECK-NEXT:    ret <2 x i32> [[R]]
+;
+  %splat = shufflevector <2 x i32> %x, <2 x i32> undef, <2 x i32> zeroinitializer
+  %r = ashr <2 x i32> %splat, <i32 5, i32 5>
+  ret <2 x i32> %r
+}
+
+define <2 x i32> @lshr_splat_constant0(<2 x i32> %x) {
+; CHECK-LABEL: @lshr_splat_constant0(
+; CHECK-NEXT:    [[TMP1:%.*]] = lshr <2 x i32> <i32 5, i32 undef>, [[X:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = shufflevector <2 x i32> [[TMP1]], <2 x i32> undef, <2 x i32> zeroinitializer
+; CHECK-NEXT:    ret <2 x i32> [[R]]
+;
+  %splat = shufflevector <2 x i32> %x, <2 x i32> undef, <2 x i32> zeroinitializer
+  %r = lshr <2 x i32> <i32 5, i32 5>, %splat
+  ret <2 x i32> %r
+}
+
+define <2 x i32> @lshr_splat_constant1(<2 x i32> %x) {
+; CHECK-LABEL: @lshr_splat_constant1(
+; CHECK-NEXT:    [[TMP1:%.*]] = lshr <2 x i32> [[X:%.*]], <i32 5, i32 0>
+; CHECK-NEXT:    [[R:%.*]] = shufflevector <2 x i32> [[TMP1]], <2 x i32> undef, <2 x i32> zeroinitializer
+; CHECK-NEXT:    ret <2 x i32> [[R]]
+;
+  %splat = shufflevector <2 x i32> %x, <2 x i32> undef, <2 x i32> zeroinitializer
+  %r = lshr <2 x i32> %splat, <i32 5, i32 5>
+  ret <2 x i32> %r
+}
+
+define <2 x i32> @urem_splat_constant0(<2 x i32> %x) {
+; CHECK-LABEL: @urem_splat_constant0(
+; CHECK-NEXT:    [[SPLAT:%.*]] = shufflevector <2 x i32> [[X:%.*]], <2 x i32> undef, <2 x i32> zeroinitializer
+; CHECK-NEXT:    [[R:%.*]] = urem <2 x i32> <i32 42, i32 42>, [[SPLAT]]
+; CHECK-NEXT:    ret <2 x i32> [[R]]
+;
+  %splat = shufflevector <2 x i32> %x, <2 x i32> undef, <2 x i32> zeroinitializer
+  %r = urem <2 x i32> <i32 42, i32 42>, %splat
+  ret <2 x i32> %r
+}
+
+define <2 x i32> @urem_splat_constant1(<2 x i32> %x) {
+; CHECK-LABEL: @urem_splat_constant1(
+; CHECK-NEXT:    [[TMP1:%.*]] = urem <2 x i32> [[X:%.*]], <i32 42, i32 1>
+; CHECK-NEXT:    [[R:%.*]] = shufflevector <2 x i32> [[TMP1]], <2 x i32> undef, <2 x i32> zeroinitializer
+; CHECK-NEXT:    ret <2 x i32> [[R]]
+;
+  %splat = shufflevector <2 x i32> %x, <2 x i32> undef, <2 x i32> zeroinitializer
+  %r = urem <2 x i32> %splat, <i32 42, i32 42>
+  ret <2 x i32> %r
+}
+
+define <2 x i32> @srem_splat_constant0(<2 x i32> %x) {
+; CHECK-LABEL: @srem_splat_constant0(
+; CHECK-NEXT:    [[SPLAT:%.*]] = shufflevector <2 x i32> [[X:%.*]], <2 x i32> undef, <2 x i32> zeroinitializer
+; CHECK-NEXT:    [[R:%.*]] = srem <2 x i32> <i32 42, i32 42>, [[SPLAT]]
+; CHECK-NEXT:    ret <2 x i32> [[R]]
+;
+  %splat = shufflevector <2 x i32> %x, <2 x i32> undef, <2 x i32> zeroinitializer
+  %r = srem <2 x i32> <i32 42, i32 42>, %splat
+  ret <2 x i32> %r
+}
+
+define <2 x i32> @srem_splat_constant1(<2 x i32> %x) {
+; CHECK-LABEL: @srem_splat_constant1(
+; CHECK-NEXT:    [[TMP1:%.*]] = srem <2 x i32> [[X:%.*]], <i32 42, i32 1>
+; CHECK-NEXT:    [[R:%.*]] = shufflevector <2 x i32> [[TMP1]], <2 x i32> undef, <2 x i32> zeroinitializer
+; CHECK-NEXT:    ret <2 x i32> [[R]]
+;
+  %splat = shufflevector <2 x i32> %x, <2 x i32> undef, <2 x i32> zeroinitializer
+  %r = srem <2 x i32> %splat, <i32 42, i32 42>
+  ret <2 x i32> %r
+}
+
+define <2 x i32> @udiv_splat_constant0(<2 x i32> %x) {
+; CHECK-LABEL: @udiv_splat_constant0(
+; CHECK-NEXT:    [[SPLAT:%.*]] = shufflevector <2 x i32> [[X:%.*]], <2 x i32> undef, <2 x i32> zeroinitializer
+; CHECK-NEXT:    [[R:%.*]] = udiv <2 x i32> <i32 42, i32 42>, [[SPLAT]]
+; CHECK-NEXT:    ret <2 x i32> [[R]]
+;
+  %splat = shufflevector <2 x i32> %x, <2 x i32> undef, <2 x i32> zeroinitializer
+  %r = udiv <2 x i32> <i32 42, i32 42>, %splat
+  ret <2 x i32> %r
+}
+
+define <2 x i32> @udiv_splat_constant1(<2 x i32> %x) {
+; CHECK-LABEL: @udiv_splat_constant1(
+; CHECK-NEXT:    [[TMP1:%.*]] = udiv <2 x i32> [[X:%.*]], <i32 42, i32 1>
+; CHECK-NEXT:    [[R:%.*]] = shufflevector <2 x i32> [[TMP1]], <2 x i32> undef, <2 x i32> zeroinitializer
+; CHECK-NEXT:    ret <2 x i32> [[R]]
+;
+  %splat = shufflevector <2 x i32> %x, <2 x i32> undef, <2 x i32> zeroinitializer
+  %r = udiv <2 x i32> %splat, <i32 42, i32 42>
+  ret <2 x i32> %r
+}
+
+define <2 x i32> @sdiv_splat_constant0(<2 x i32> %x) {
+; CHECK-LABEL: @sdiv_splat_constant0(
+; CHECK-NEXT:    [[SPLAT:%.*]] = shufflevector <2 x i32> [[X:%.*]], <2 x i32> undef, <2 x i32> zeroinitializer
+; CHECK-NEXT:    [[R:%.*]] = sdiv <2 x i32> <i32 42, i32 42>, [[SPLAT]]
+; CHECK-NEXT:    ret <2 x i32> [[R]]
+;
+  %splat = shufflevector <2 x i32> %x, <2 x i32> undef, <2 x i32> zeroinitializer
+  %r = sdiv <2 x i32> <i32 42, i32 42>, %splat
+  ret <2 x i32> %r
+}
+
+define <2 x i32> @sdiv_splat_constant1(<2 x i32> %x) {
+; CHECK-LABEL: @sdiv_splat_constant1(
+; CHECK-NEXT:    [[TMP1:%.*]] = sdiv <2 x i32> [[X:%.*]], <i32 42, i32 1>
+; CHECK-NEXT:    [[R:%.*]] = shufflevector <2 x i32> [[TMP1]], <2 x i32> undef, <2 x i32> zeroinitializer
+; CHECK-NEXT:    ret <2 x i32> [[R]]
+;
+  %splat = shufflevector <2 x i32> %x, <2 x i32> undef, <2 x i32> zeroinitializer
+  %r = sdiv <2 x i32> %splat, <i32 42, i32 42>
+  ret <2 x i32> %r
+}
+
+define <2 x i32> @and_splat_constant(<2 x i32> %x) {
+; CHECK-LABEL: @and_splat_constant(
+; CHECK-NEXT:    [[TMP1:%.*]] = and <2 x i32> [[X:%.*]], <i32 42, i32 undef>
+; CHECK-NEXT:    [[R:%.*]] = shufflevector <2 x i32> [[TMP1]], <2 x i32> undef, <2 x i32> zeroinitializer
+; CHECK-NEXT:    ret <2 x i32> [[R]]
+;
+  %splat = shufflevector <2 x i32> %x, <2 x i32> undef, <2 x i32> zeroinitializer
+  %r = and <2 x i32> %splat, <i32 42, i32 42>
+  ret <2 x i32> %r
+}
+
+define <2 x i32> @or_splat_constant(<2 x i32> %x) {
+; CHECK-LABEL: @or_splat_constant(
+; CHECK-NEXT:    [[TMP1:%.*]] = or <2 x i32> [[X:%.*]], <i32 42, i32 undef>
+; CHECK-NEXT:    [[R:%.*]] = shufflevector <2 x i32> [[TMP1]], <2 x i32> undef, <2 x i32> zeroinitializer
+; CHECK-NEXT:    ret <2 x i32> [[R]]
+;
+  %splat = shufflevector <2 x i32> %x, <2 x i32> undef, <2 x i32> zeroinitializer
+  %r = or <2 x i32> %splat, <i32 42, i32 42>
+  ret <2 x i32> %r
+}
+
+define <2 x i32> @xor_splat_constant(<2 x i32> %x) {
+; CHECK-LABEL: @xor_splat_constant(
+; CHECK-NEXT:    [[TMP1:%.*]] = xor <2 x i32> [[X:%.*]], <i32 42, i32 undef>
+; CHECK-NEXT:    [[R:%.*]] = shufflevector <2 x i32> [[TMP1]], <2 x i32> undef, <2 x i32> zeroinitializer
+; CHECK-NEXT:    ret <2 x i32> [[R]]
+;
+  %splat = shufflevector <2 x i32> %x, <2 x i32> undef, <2 x i32> zeroinitializer
+  %r = xor <2 x i32> %splat, <i32 42, i32 42>
+  ret <2 x i32> %r
+}
+
+define <2 x float> @fadd_splat_constant(<2 x float> %x) {
+; CHECK-LABEL: @fadd_splat_constant(
+; CHECK-NEXT:    [[TMP1:%.*]] = fadd <2 x float> [[X:%.*]], <float 4.200000e+01, float undef>
+; CHECK-NEXT:    [[R:%.*]] = shufflevector <2 x float> [[TMP1]], <2 x float> undef, <2 x i32> zeroinitializer
+; CHECK-NEXT:    ret <2 x float> [[R]]
+;
+  %splat = shufflevector <2 x float> %x, <2 x float> undef, <2 x i32> zeroinitializer
+  %r = fadd <2 x float> %splat, <float 42.0, float 42.0>
+  ret <2 x float> %r
+}
+
+define <2 x float> @fsub_splat_constant0(<2 x float> %x) {
+; CHECK-LABEL: @fsub_splat_constant0(
+; CHECK-NEXT:    [[TMP1:%.*]] = fsub <2 x float> <float 4.200000e+01, float undef>, [[X:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = shufflevector <2 x float> [[TMP1]], <2 x float> undef, <2 x i32> zeroinitializer
+; CHECK-NEXT:    ret <2 x float> [[R]]
+;
+  %splat = shufflevector <2 x float> %x, <2 x float> undef, <2 x i32> zeroinitializer
+  %r = fsub <2 x float> <float 42.0, float 42.0>, %splat
+  ret <2 x float> %r
+}
+
+define <2 x float> @fsub_splat_constant1(<2 x float> %x) {
+; CHECK-LABEL: @fsub_splat_constant1(
+; CHECK-NEXT:    [[TMP1:%.*]] = fadd <2 x float> [[X:%.*]], <float -4.200000e+01, float undef>
+; CHECK-NEXT:    [[R:%.*]] = shufflevector <2 x float> [[TMP1]], <2 x float> undef, <2 x i32> zeroinitializer
+; CHECK-NEXT:    ret <2 x float> [[R]]
+;
+  %splat = shufflevector <2 x float> %x, <2 x float> undef, <2 x i32> zeroinitializer
+  %r = fsub <2 x float> %splat, <float 42.0, float 42.0>
+  ret <2 x float> %r
+}
+
+define <2 x float> @fneg(<2 x float> %x) {
+; CHECK-LABEL: @fneg(
+; CHECK-NEXT:    [[TMP1:%.*]] = fsub <2 x float> <float -0.000000e+00, float undef>, [[X:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = shufflevector <2 x float> [[TMP1]], <2 x float> undef, <2 x i32> zeroinitializer
+; CHECK-NEXT:    ret <2 x float> [[R]]
+;
+  %splat = shufflevector <2 x float> %x, <2 x float> undef, <2 x i32> zeroinitializer
+  %r = fsub <2 x float> <float -0.0, float -0.0>, %splat
+  ret <2 x float> %r
+}
+
+define <2 x float> @fmul_splat_constant(<2 x float> %x) {
+; CHECK-LABEL: @fmul_splat_constant(
+; CHECK-NEXT:    [[TMP1:%.*]] = fmul <2 x float> [[X:%.*]], <float 4.200000e+01, float undef>
+; CHECK-NEXT:    [[R:%.*]] = shufflevector <2 x float> [[TMP1]], <2 x float> undef, <2 x i32> zeroinitializer
+; CHECK-NEXT:    ret <2 x float> [[R]]
+;
+  %splat = shufflevector <2 x float> %x, <2 x float> undef, <2 x i32> zeroinitializer
+  %r = fmul <2 x float> %splat, <float 42.0, float 42.0>
+  ret <2 x float> %r
+}
+
+define <2 x float> @fdiv_splat_constant0(<2 x float> %x) {
+; CHECK-LABEL: @fdiv_splat_constant0(
+; CHECK-NEXT:    [[TMP1:%.*]] = fdiv <2 x float> <float 4.200000e+01, float undef>, [[X:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = shufflevector <2 x float> [[TMP1]], <2 x float> undef, <2 x i32> zeroinitializer
+; CHECK-NEXT:    ret <2 x float> [[R]]
+;
+  %splat = shufflevector <2 x float> %x, <2 x float> undef, <2 x i32> zeroinitializer
+  %r = fdiv <2 x float> <float 42.0, float 42.0>, %splat
+  ret <2 x float> %r
+}
+
+define <2 x float> @fdiv_splat_constant1(<2 x float> %x) {
+; CHECK-LABEL: @fdiv_splat_constant1(
+; CHECK-NEXT:    [[TMP1:%.*]] = fdiv <2 x float> [[X:%.*]], <float 4.200000e+01, float undef>
+; CHECK-NEXT:    [[R:%.*]] = shufflevector <2 x float> [[TMP1]], <2 x float> undef, <2 x i32> zeroinitializer
+; CHECK-NEXT:    ret <2 x float> [[R]]
+;
+  %splat = shufflevector <2 x float> %x, <2 x float> undef, <2 x i32> zeroinitializer
+  %r = fdiv <2 x float> %splat, <float 42.0, float 42.0>
+  ret <2 x float> %r
+}
+
+define <2 x float> @frem_splat_constant0(<2 x float> %x) {
+; CHECK-LABEL: @frem_splat_constant0(
+; CHECK-NEXT:    [[TMP1:%.*]] = frem <2 x float> <float 4.200000e+01, float undef>, [[X:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = shufflevector <2 x float> [[TMP1]], <2 x float> undef, <2 x i32> zeroinitializer
+; CHECK-NEXT:    ret <2 x float> [[R]]
+;
+  %splat = shufflevector <2 x float> %x, <2 x float> undef, <2 x i32> zeroinitializer
+  %r = frem <2 x float> <float 42.0, float 42.0>, %splat
+  ret <2 x float> %r
+}
+
+define <2 x float> @frem_splat_constant1(<2 x float> %x) {
+; CHECK-LABEL: @frem_splat_constant1(
+; CHECK-NEXT:    [[TMP1:%.*]] = frem <2 x float> [[X:%.*]], <float 4.200000e+01, float undef>
+; CHECK-NEXT:    [[R:%.*]] = shufflevector <2 x float> [[TMP1]], <2 x float> undef, <2 x i32> zeroinitializer
+; CHECK-NEXT:    ret <2 x float> [[R]]
+;
+  %splat = shufflevector <2 x float> %x, <2 x float> undef, <2 x i32> zeroinitializer
+  %r = frem <2 x float> %splat, <float 42.0, float 42.0>
+  ret <2 x float> %r
+}
+
+; Equivalent shuffle masks, but only one is a narrowing op.
+
+define <2 x i1> @PR40734(<1 x i1> %x, <4 x i1> %y) {
+; CHECK-LABEL: @PR40734(
+; CHECK-NEXT:    [[WIDEN:%.*]] = shufflevector <1 x i1> zeroinitializer, <1 x i1> [[X:%.*]], <2 x i32> <i32 0, i32 1>
+; CHECK-NEXT:    [[NARROW:%.*]] = shufflevector <4 x i1> [[Y:%.*]], <4 x i1> undef, <2 x i32> <i32 0, i32 1>
+; CHECK-NEXT:    [[R:%.*]] = and <2 x i1> [[WIDEN]], [[NARROW]]
+; CHECK-NEXT:    ret <2 x i1> [[R]]
+;
+  %widen = shufflevector <1 x i1> zeroinitializer, <1 x i1> %x, <2 x i32> <i32 0, i32 1>
+  %narrow = shufflevector <4 x i1> %y, <4 x i1> undef, <2 x i32> <i32 0, i32 1>
+  %r = and <2 x i1> %widen, %narrow
+  ret <2 x i1> %r
+}
+

Added: llvm/trunk/test/Transforms/InstCombine/vector-casts.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/vector-casts.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/vector-casts.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/vector-casts.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,413 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt < %s -instcombine -S | FileCheck %s
+
+; Can't get smaller than this.
+
+define <2 x i1> @trunc(<2 x i64> %a) {
+; CHECK-LABEL: @trunc(
+; CHECK-NEXT:    [[T:%.*]] = trunc <2 x i64> [[A:%.*]] to <2 x i1>
+; CHECK-NEXT:    ret <2 x i1> [[T]]
+;
+  %t = trunc <2 x i64> %a to <2 x i1>
+  ret <2 x i1> %t
+}
+
+; This is trunc.
+
+define <2 x i1> @and_cmp_is_trunc(<2 x i64> %a) {
+; CHECK-LABEL: @and_cmp_is_trunc(
+; CHECK-NEXT:    [[R:%.*]] = trunc <2 x i64> [[A:%.*]] to <2 x i1>
+; CHECK-NEXT:    ret <2 x i1> [[R]]
+;
+  %t = and <2 x i64> %a, <i64 1, i64 1>
+  %r = icmp ne <2 x i64> %t, zeroinitializer
+  ret <2 x i1> %r
+}
+
+; This is trunc.
+
+define <2 x i1> @and_cmp_is_trunc_even_with_undef_elt(<2 x i64> %a) {
+; CHECK-LABEL: @and_cmp_is_trunc_even_with_undef_elt(
+; CHECK-NEXT:    [[R:%.*]] = trunc <2 x i64> [[A:%.*]] to <2 x i1>
+; CHECK-NEXT:    ret <2 x i1> [[R]]
+;
+  %t = and <2 x i64> %a, <i64 undef, i64 1>
+  %r = icmp ne <2 x i64> %t, zeroinitializer
+  ret <2 x i1> %r
+}
+
+; TODO: This could be just 1 instruction (trunc), but our undef matching is incomplete.
+
+define <2 x i1> @and_cmp_is_trunc_even_with_undef_elts(<2 x i64> %a) {
+; CHECK-LABEL: @and_cmp_is_trunc_even_with_undef_elts(
+; CHECK-NEXT:    [[T:%.*]] = and <2 x i64> [[A:%.*]], <i64 undef, i64 1>
+; CHECK-NEXT:    [[R:%.*]] = icmp ne <2 x i64> [[T]], <i64 undef, i64 0>
+; CHECK-NEXT:    ret <2 x i1> [[R]]
+;
+  %t = and <2 x i64> %a, <i64 undef, i64 1>
+  %r = icmp ne <2 x i64> %t, <i64 undef, i64 0>
+  ret <2 x i1> %r
+}
+
+; The ashr turns into an lshr.
+define <2 x i64> @test2(<2 x i64> %a) {
+; CHECK-LABEL: @test2(
+; CHECK-NEXT:    [[B:%.*]] = lshr <2 x i64> [[A:%.*]], <i64 1, i64 1>
+; CHECK-NEXT:    [[TMP1:%.*]] = and <2 x i64> [[B]], <i64 32767, i64 32767>
+; CHECK-NEXT:    ret <2 x i64> [[TMP1]]
+;
+  %b = and <2 x i64> %a, <i64 65535, i64 65535>
+  %t = ashr <2 x i64> %b, <i64 1, i64 1>
+  ret <2 x i64> %t
+}
+
+define <2 x i64> @test3(<4 x float> %a, <4 x float> %b) {
+; CHECK-LABEL: @test3(
+; CHECK-NEXT:    [[TMP1:%.*]] = fcmp ord <4 x float> [[A:%.*]], [[B:%.*]]
+; CHECK-NEXT:    [[AND:%.*]] = sext <4 x i1> [[TMP1]] to <4 x i32>
+; CHECK-NEXT:    [[CONV:%.*]] = bitcast <4 x i32> [[AND]] to <2 x i64>
+; CHECK-NEXT:    ret <2 x i64> [[CONV]]
+;
+  %cmp = fcmp ord <4 x float> %a, zeroinitializer
+  %sext = sext <4 x i1> %cmp to <4 x i32>
+  %cmp4 = fcmp ord <4 x float> %b, zeroinitializer
+  %sext5 = sext <4 x i1> %cmp4 to <4 x i32>
+  %and = and <4 x i32> %sext, %sext5
+  %conv = bitcast <4 x i32> %and to <2 x i64>
+  ret <2 x i64> %conv
+}
+
+define <2 x i64> @test4(<4 x float> %a, <4 x float> %b) {
+; CHECK-LABEL: @test4(
+; CHECK-NEXT:    [[TMP1:%.*]] = fcmp uno <4 x float> [[A:%.*]], [[B:%.*]]
+; CHECK-NEXT:    [[OR:%.*]] = sext <4 x i1> [[TMP1]] to <4 x i32>
+; CHECK-NEXT:    [[CONV:%.*]] = bitcast <4 x i32> [[OR]] to <2 x i64>
+; CHECK-NEXT:    ret <2 x i64> [[CONV]]
+;
+  %cmp = fcmp uno <4 x float> %a, zeroinitializer
+  %sext = sext <4 x i1> %cmp to <4 x i32>
+  %cmp4 = fcmp uno <4 x float> %b, zeroinitializer
+  %sext5 = sext <4 x i1> %cmp4 to <4 x i32>
+  %or = or <4 x i32> %sext, %sext5
+  %conv = bitcast <4 x i32> %or to <2 x i64>
+  ret <2 x i64> %conv
+}
+
+; rdar://7434900
+define <2 x i64> @test5(<4 x float> %a, <4 x float> %b) {
+; CHECK-LABEL: @test5(
+; CHECK-NEXT:    [[CMP:%.*]] = fcmp ult <4 x float> [[A:%.*]], zeroinitializer
+; CHECK-NEXT:    [[CMP4:%.*]] = fcmp ult <4 x float> [[B:%.*]], zeroinitializer
+; CHECK-NEXT:    [[AND1:%.*]] = and <4 x i1> [[CMP]], [[CMP4]]
+; CHECK-NEXT:    [[AND:%.*]] = sext <4 x i1> [[AND1]] to <4 x i32>
+; CHECK-NEXT:    [[CONV:%.*]] = bitcast <4 x i32> [[AND]] to <2 x i64>
+; CHECK-NEXT:    ret <2 x i64> [[CONV]]
+;
+  %cmp = fcmp ult <4 x float> %a, zeroinitializer
+  %sext = sext <4 x i1> %cmp to <4 x i32>
+  %cmp4 = fcmp ult <4 x float> %b, zeroinitializer
+  %sext5 = sext <4 x i1> %cmp4 to <4 x i32>
+  %and = and <4 x i32> %sext, %sext5
+  %conv = bitcast <4 x i32> %and to <2 x i64>
+  ret <2 x i64> %conv
+}
+
+define <2 x i64> @test6(<4 x float> %a, <4 x float> %b) {
+; CHECK-LABEL: @test6(
+; CHECK-NEXT:    [[CMP:%.*]] = fcmp ult <4 x float> [[A:%.*]], zeroinitializer
+; CHECK-NEXT:    [[CMP4:%.*]] = fcmp ult <4 x float> [[B:%.*]], zeroinitializer
+; CHECK-NEXT:    [[AND1:%.*]] = or <4 x i1> [[CMP]], [[CMP4]]
+; CHECK-NEXT:    [[AND:%.*]] = sext <4 x i1> [[AND1]] to <4 x i32>
+; CHECK-NEXT:    [[CONV:%.*]] = bitcast <4 x i32> [[AND]] to <2 x i64>
+; CHECK-NEXT:    ret <2 x i64> [[CONV]]
+;
+  %cmp = fcmp ult <4 x float> %a, zeroinitializer
+  %sext = sext <4 x i1> %cmp to <4 x i32>
+  %cmp4 = fcmp ult <4 x float> %b, zeroinitializer
+  %sext5 = sext <4 x i1> %cmp4 to <4 x i32>
+  %and = or <4 x i32> %sext, %sext5
+  %conv = bitcast <4 x i32> %and to <2 x i64>
+  ret <2 x i64> %conv
+}
+
+define <2 x i64> @test7(<4 x float> %a, <4 x float> %b) {
+; CHECK-LABEL: @test7(
+; CHECK-NEXT:    [[CMP:%.*]] = fcmp ult <4 x float> [[A:%.*]], zeroinitializer
+; CHECK-NEXT:    [[CMP4:%.*]] = fcmp ult <4 x float> [[B:%.*]], zeroinitializer
+; CHECK-NEXT:    [[AND1:%.*]] = xor <4 x i1> [[CMP]], [[CMP4]]
+; CHECK-NEXT:    [[AND:%.*]] = sext <4 x i1> [[AND1]] to <4 x i32>
+; CHECK-NEXT:    [[CONV:%.*]] = bitcast <4 x i32> [[AND]] to <2 x i64>
+; CHECK-NEXT:    ret <2 x i64> [[CONV]]
+;
+  %cmp = fcmp ult <4 x float> %a, zeroinitializer
+  %sext = sext <4 x i1> %cmp to <4 x i32>
+  %cmp4 = fcmp ult <4 x float> %b, zeroinitializer
+  %sext5 = sext <4 x i1> %cmp4 to <4 x i32>
+  %and = xor <4 x i32> %sext, %sext5
+  %conv = bitcast <4 x i32> %and to <2 x i64>
+  ret <2 x i64> %conv
+}
+
+define void @convert(<2 x i32>* %dst.addr, <2 x i64> %src) {
+; CHECK-LABEL: @convert(
+; CHECK-NEXT:    [[VAL:%.*]] = trunc <2 x i64> [[SRC:%.*]] to <2 x i32>
+; CHECK-NEXT:    [[ADD:%.*]] = add <2 x i32> [[VAL]], <i32 1, i32 1>
+; CHECK-NEXT:    store <2 x i32> [[ADD]], <2 x i32>* [[DST_ADDR:%.*]], align 8
+; CHECK-NEXT:    ret void
+;
+  %val = trunc <2 x i64> %src to <2 x i32>
+  %add = add <2 x i32> %val, <i32 1, i32 1>
+  store <2 x i32> %add, <2 x i32>* %dst.addr
+  ret void
+}
+
+define <2 x i65> @foo(<2 x i64> %t) {
+; CHECK-LABEL: @foo(
+; CHECK-NEXT:    [[A_MASK:%.*]] = and <2 x i64> [[T:%.*]], <i64 4294967295, i64 4294967295>
+; CHECK-NEXT:    [[B:%.*]] = zext <2 x i64> [[A_MASK]] to <2 x i65>
+; CHECK-NEXT:    ret <2 x i65> [[B]]
+;
+  %a = trunc <2 x i64> %t to <2 x i32>
+  %b = zext <2 x i32> %a to <2 x i65>
+  ret <2 x i65> %b
+}
+
+define <2 x i64> @bar(<2 x i65> %t) {
+; CHECK-LABEL: @bar(
+; CHECK-NEXT:    [[TMP1:%.*]] = trunc <2 x i65> [[T:%.*]] to <2 x i64>
+; CHECK-NEXT:    [[B:%.*]] = and <2 x i64> [[TMP1]], <i64 4294967295, i64 4294967295>
+; CHECK-NEXT:    ret <2 x i64> [[B]]
+;
+  %a = trunc <2 x i65> %t to <2 x i32>
+  %b = zext <2 x i32> %a to <2 x i64>
+  ret <2 x i64> %b
+}
+
+define <2 x i64> @bars(<2 x i65> %t) {
+; CHECK-LABEL: @bars(
+; CHECK-NEXT:    [[A:%.*]] = trunc <2 x i65> [[T:%.*]] to <2 x i32>
+; CHECK-NEXT:    [[B:%.*]] = sext <2 x i32> [[A]] to <2 x i64>
+; CHECK-NEXT:    ret <2 x i64> [[B]]
+;
+  %a = trunc <2 x i65> %t to <2 x i32>
+  %b = sext <2 x i32> %a to <2 x i64>
+  ret <2 x i64> %b
+}
+
+define <2 x i64> @quxs(<2 x i64> %t) {
+; CHECK-LABEL: @quxs(
+; CHECK-NEXT:    [[TMP1:%.*]] = shl <2 x i64> [[T:%.*]], <i64 32, i64 32>
+; CHECK-NEXT:    [[B:%.*]] = ashr exact <2 x i64> [[TMP1]], <i64 32, i64 32>
+; CHECK-NEXT:    ret <2 x i64> [[B]]
+;
+  %a = trunc <2 x i64> %t to <2 x i32>
+  %b = sext <2 x i32> %a to <2 x i64>
+  ret <2 x i64> %b
+}
+
+define <2 x i64> @quxt(<2 x i64> %t) {
+; CHECK-LABEL: @quxt(
+; CHECK-NEXT:    [[A:%.*]] = shl <2 x i64> [[T:%.*]], <i64 32, i64 32>
+; CHECK-NEXT:    [[B:%.*]] = ashr exact <2 x i64> [[A]], <i64 32, i64 32>
+; CHECK-NEXT:    ret <2 x i64> [[B]]
+;
+  %a = shl <2 x i64> %t, <i64 32, i64 32>
+  %b = ashr <2 x i64> %a, <i64 32, i64 32>
+  ret <2 x i64> %b
+}
+
+define <2 x double> @fa(<2 x double> %t) {
+; CHECK-LABEL: @fa(
+; CHECK-NEXT:    [[A:%.*]] = fptrunc <2 x double> [[T:%.*]] to <2 x float>
+; CHECK-NEXT:    [[B:%.*]] = fpext <2 x float> [[A]] to <2 x double>
+; CHECK-NEXT:    ret <2 x double> [[B]]
+;
+  %a = fptrunc <2 x double> %t to <2 x float>
+  %b = fpext <2 x float> %a to <2 x double>
+  ret <2 x double> %b
+}
+
+define <2 x double> @fb(<2 x double> %t) {
+; CHECK-LABEL: @fb(
+; CHECK-NEXT:    [[A:%.*]] = fptoui <2 x double> [[T:%.*]] to <2 x i64>
+; CHECK-NEXT:    [[B:%.*]] = uitofp <2 x i64> [[A]] to <2 x double>
+; CHECK-NEXT:    ret <2 x double> [[B]]
+;
+  %a = fptoui <2 x double> %t to <2 x i64>
+  %b = uitofp <2 x i64> %a to <2 x double>
+  ret <2 x double> %b
+}
+
+define <2 x double> @fc(<2 x double> %t) {
+; CHECK-LABEL: @fc(
+; CHECK-NEXT:    [[A:%.*]] = fptosi <2 x double> [[T:%.*]] to <2 x i64>
+; CHECK-NEXT:    [[B:%.*]] = sitofp <2 x i64> [[A]] to <2 x double>
+; CHECK-NEXT:    ret <2 x double> [[B]]
+;
+  %a = fptosi <2 x double> %t to <2 x i64>
+  %b = sitofp <2 x i64> %a to <2 x double>
+  ret <2 x double> %b
+}
+
+; PR9228
+define <4 x float> @f(i32 %a) {
+; CHECK-LABEL: @f(
+; CHECK-NEXT:    ret <4 x float> undef
+;
+  %dim = insertelement <4 x i32> undef, i32 %a, i32 0
+  %dim30 = insertelement <4 x i32> %dim, i32 %a, i32 1
+  %dim31 = insertelement <4 x i32> %dim30, i32 %a, i32 2
+  %dim32 = insertelement <4 x i32> %dim31, i32 %a, i32 3
+
+  %offset_ptr = getelementptr <4 x float>, <4 x float>* null, i32 1
+  %offset_int = ptrtoint <4 x float>* %offset_ptr to i64
+  %sizeof32 = trunc i64 %offset_int to i32
+
+  %smearinsert33 = insertelement <4 x i32> undef, i32 %sizeof32, i32 0
+  %smearinsert34 = insertelement <4 x i32> %smearinsert33, i32 %sizeof32, i32 1
+  %smearinsert35 = insertelement <4 x i32> %smearinsert34, i32 %sizeof32, i32 2
+  %smearinsert36 = insertelement <4 x i32> %smearinsert35, i32 %sizeof32, i32 3
+
+  %delta_scale = mul <4 x i32> %dim32, %smearinsert36
+  %offset_delta = add <4 x i32> zeroinitializer, %delta_scale
+
+  %offset_varying_delta = add <4 x i32> %offset_delta, undef
+
+  ret <4 x float> undef
+}
+
+define <8 x i32> @pr24458(<8 x float> %n) {
+; CHECK-LABEL: @pr24458(
+; CHECK-NEXT:    ret <8 x i32> <i32 -1, i32 -1, i32 -1, i32 -1, i32 -1, i32 -1, i32 -1, i32 -1>
+;
+  %notequal_b_load_.i = fcmp une <8 x float> %n, zeroinitializer
+  %equal_a_load72_.i = fcmp ueq <8 x float> %n, zeroinitializer
+  %notequal_b_load__to_boolvec.i = sext <8 x i1> %notequal_b_load_.i to <8 x i32>
+  %equal_a_load72__to_boolvec.i = sext <8 x i1> %equal_a_load72_.i to <8 x i32>
+  %wrong = or <8 x i32> %notequal_b_load__to_boolvec.i, %equal_a_load72__to_boolvec.i
+  ret <8 x i32> %wrong
+}
+
+; Hoist a trunc to a scalar if we're inserting into an undef vector.
+; trunc (inselt undef, X, Index) --> inselt undef, (trunc X), Index
+
+define <3 x i16> @trunc_inselt_undef(i32 %x) {
+; CHECK-LABEL: @trunc_inselt_undef(
+; CHECK-NEXT:    [[TMP1:%.*]] = trunc i32 [[X:%.*]] to i16
+; CHECK-NEXT:    [[TRUNC:%.*]] = insertelement <3 x i16> undef, i16 [[TMP1]], i32 1
+; CHECK-NEXT:    ret <3 x i16> [[TRUNC]]
+;
+  %vec = insertelement <3 x i32> undef, i32 %x, i32 1
+  %trunc = trunc <3 x i32> %vec to <3 x i16>
+  ret <3 x i16> %trunc
+}
+
+; Hoist a trunc to a scalar if we're inserting into an undef vector.
+; trunc (inselt undef, X, Index) --> inselt undef, (trunc X), Index
+
+define <2 x float> @fptrunc_inselt_undef(double %x, i32 %index) {
+; CHECK-LABEL: @fptrunc_inselt_undef(
+; CHECK-NEXT:    [[TMP1:%.*]] = fptrunc double [[X:%.*]] to float
+; CHECK-NEXT:    [[TRUNC:%.*]] = insertelement <2 x float> undef, float [[TMP1]], i32 [[INDEX:%.*]]
+; CHECK-NEXT:    ret <2 x float> [[TRUNC]]
+;
+  %vec = insertelement <2 x double> <double undef, double undef>, double %x, i32 %index
+  %trunc = fptrunc <2 x double> %vec to <2 x float>
+  ret <2 x float> %trunc
+}
+
+; TODO: Strengthen the backend, so we can have this canonicalization.
+; Insert a scalar int into a constant vector and truncate:
+; trunc (inselt C, X, Index) --> inselt C, (trunc X), Index
+
+define <3 x i16> @trunc_inselt1(i32 %x) {
+; CHECK-LABEL: @trunc_inselt1(
+; CHECK-NEXT:    [[VEC:%.*]] = insertelement <3 x i32> <i32 3, i32 undef, i32 65536>, i32 [[X:%.*]], i32 1
+; CHECK-NEXT:    [[TRUNC:%.*]] = trunc <3 x i32> [[VEC]] to <3 x i16>
+; CHECK-NEXT:    ret <3 x i16> [[TRUNC]]
+;
+  %vec = insertelement <3 x i32> <i32 3, i32 -2, i32 65536>, i32 %x, i32 1
+  %trunc = trunc <3 x i32> %vec to <3 x i16>
+  ret <3 x i16> %trunc
+}
+
+; TODO: Strengthen the backend, so we can have this canonicalization.
+; Insert a scalar FP into a constant vector and FP truncate:
+; fptrunc (inselt C, X, Index) --> inselt C, (fptrunc X), Index
+
+define <2 x float> @fptrunc_inselt1(double %x, i32 %index) {
+; CHECK-LABEL: @fptrunc_inselt1(
+; CHECK-NEXT:    [[VEC:%.*]] = insertelement <2 x double> <double undef, double 3.000000e+00>, double [[X:%.*]], i32 [[INDEX:%.*]]
+; CHECK-NEXT:    [[TRUNC:%.*]] = fptrunc <2 x double> [[VEC]] to <2 x float>
+; CHECK-NEXT:    ret <2 x float> [[TRUNC]]
+;
+  %vec = insertelement <2 x double> <double undef, double 3.0>, double %x, i32 %index
+  %trunc = fptrunc <2 x double> %vec to <2 x float>
+  ret <2 x float> %trunc
+}
+
+; TODO: Strengthen the backend, so we can have this canonicalization.
+; Insert a scalar int constant into a vector and truncate:
+; trunc (inselt X, C, Index) --> inselt (trunc X), C', Index
+
+define <8 x i16> @trunc_inselt2(<8 x i32> %x, i32 %index) {
+; CHECK-LABEL: @trunc_inselt2(
+; CHECK-NEXT:    [[VEC:%.*]] = insertelement <8 x i32> [[X:%.*]], i32 1048576, i32 [[INDEX:%.*]]
+; CHECK-NEXT:    [[TRUNC:%.*]] = trunc <8 x i32> [[VEC]] to <8 x i16>
+; CHECK-NEXT:    ret <8 x i16> [[TRUNC]]
+;
+  %vec = insertelement <8 x i32> %x, i32 1048576, i32 %index
+  %trunc = trunc <8 x i32> %vec to <8 x i16>
+  ret <8 x i16> %trunc
+}
+
+; TODO: Strengthen the backend, so we can have this canonicalization.
+; Insert a scalar FP constant into a vector and FP truncate:
+; fptrunc (inselt X, C, Index) --> inselt (fptrunc X), C', Index
+
+define <3 x float> @fptrunc_inselt2(<3 x double> %x) {
+; CHECK-LABEL: @fptrunc_inselt2(
+; CHECK-NEXT:    [[VEC:%.*]] = insertelement <3 x double> [[X:%.*]], double 4.000000e+00, i32 2
+; CHECK-NEXT:    [[TRUNC:%.*]] = fptrunc <3 x double> [[VEC]] to <3 x float>
+; CHECK-NEXT:    ret <3 x float> [[TRUNC]]
+;
+  %vec = insertelement <3 x double> %x, double 4.0, i32 2
+  %trunc = fptrunc <3 x double> %vec to <3 x float>
+  ret <3 x float> %trunc
+}
+
+; Converting to a wide type might reduce instruction count,
+; but we can not do that unless the backend can recover from
+; the creation of a potentially illegal op (like a 64-bit vmul).
+; PR40032 - https://bugs.llvm.org/show_bug.cgi?id=40032
+
+define <2 x i64> @sext_less_casting_with_wideop(<2 x i64> %x, <2 x i64> %y) {
+; CHECK-LABEL: @sext_less_casting_with_wideop(
+; CHECK-NEXT:    [[XNARROW:%.*]] = trunc <2 x i64> [[X:%.*]] to <2 x i32>
+; CHECK-NEXT:    [[YNARROW:%.*]] = trunc <2 x i64> [[Y:%.*]] to <2 x i32>
+; CHECK-NEXT:    [[MUL:%.*]] = mul <2 x i32> [[XNARROW]], [[YNARROW]]
+; CHECK-NEXT:    [[R:%.*]] = sext <2 x i32> [[MUL]] to <2 x i64>
+; CHECK-NEXT:    ret <2 x i64> [[R]]
+;
+  %xnarrow = trunc <2 x i64> %x to <2 x i32>
+  %ynarrow = trunc <2 x i64> %y to <2 x i32>
+  %mul = mul <2 x i32> %xnarrow, %ynarrow
+  %r = sext <2 x i32> %mul to <2 x i64>
+  ret <2 x i64> %r
+}
+
+define <2 x i64> @zext_less_casting_with_wideop(<2 x i64> %x, <2 x i64> %y) {
+; CHECK-LABEL: @zext_less_casting_with_wideop(
+; CHECK-NEXT:    [[XNARROW:%.*]] = trunc <2 x i64> [[X:%.*]] to <2 x i32>
+; CHECK-NEXT:    [[YNARROW:%.*]] = trunc <2 x i64> [[Y:%.*]] to <2 x i32>
+; CHECK-NEXT:    [[MUL:%.*]] = mul <2 x i32> [[XNARROW]], [[YNARROW]]
+; CHECK-NEXT:    [[R:%.*]] = zext <2 x i32> [[MUL]] to <2 x i64>
+; CHECK-NEXT:    ret <2 x i64> [[R]]
+;
+  %xnarrow = trunc <2 x i64> %x to <2 x i32>
+  %ynarrow = trunc <2 x i64> %y to <2 x i32>
+  %mul = mul <2 x i32> %xnarrow, %ynarrow
+  %r = zext <2 x i32> %mul to <2 x i64>
+  ret <2 x i64> %r
+}
+

Added: llvm/trunk/test/Transforms/InstCombine/vector-concat-binop.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/vector-concat-binop.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/vector-concat-binop.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/vector-concat-binop.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,282 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt -S -instcombine %s | FileCheck %s
+
+define <4 x i8> @add(<2 x i8> %a, <2 x i8> %b, <2 x i8> %c, <2 x i8> %d) {
+; CHECK-LABEL: @add(
+; CHECK-NEXT:    [[TMP1:%.*]] = and <2 x i8> [[A:%.*]], [[C:%.*]]
+; CHECK-NEXT:    [[TMP2:%.*]] = and <2 x i8> [[B:%.*]], [[D:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = shufflevector <2 x i8> [[TMP1]], <2 x i8> [[TMP2]], <4 x i32> <i32 0, i32 1, i32 2, i32 3>
+; CHECK-NEXT:    ret <4 x i8> [[R]]
+;
+  %concat1 = shufflevector <2 x i8> %a, <2 x i8> %b, <4 x i32> <i32 0, i32 1, i32 2, i32 3>
+  %concat2 = shufflevector <2 x i8> %c, <2 x i8> %d, <4 x i32> <i32 0, i32 1, i32 2, i32 3>
+  %r = and <4 x i8> %concat1, %concat2
+  ret <4 x i8> %r
+}
+
+; Flags should propagate.
+
+define <4 x i8> @sub(<2 x i8> %a, <2 x i8> %b, <2 x i8> %c, <2 x i8> %d) {
+; CHECK-LABEL: @sub(
+; CHECK-NEXT:    [[TMP1:%.*]] = sub nsw <2 x i8> [[A:%.*]], [[C:%.*]]
+; CHECK-NEXT:    [[TMP2:%.*]] = sub nsw <2 x i8> [[B:%.*]], [[D:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = shufflevector <2 x i8> [[TMP1]], <2 x i8> [[TMP2]], <4 x i32> <i32 0, i32 1, i32 2, i32 3>
+; CHECK-NEXT:    ret <4 x i8> [[R]]
+;
+  %concat1 = shufflevector <2 x i8> %a, <2 x i8> %b, <4 x i32> <i32 0, i32 1, i32 2, i32 3>
+  %concat2 = shufflevector <2 x i8> %c, <2 x i8> %d, <4 x i32> <i32 0, i32 1, i32 2, i32 3>
+  %r = sub nsw <4 x i8> %concat1, %concat2
+  ret <4 x i8> %r
+}
+
+; Flags should propagate.
+
+define <4 x i8> @mul(<2 x i8> %a, <2 x i8> %b, <2 x i8> %c, <2 x i8> %d) {
+; CHECK-LABEL: @mul(
+; CHECK-NEXT:    [[TMP1:%.*]] = mul nuw <2 x i8> [[A:%.*]], [[C:%.*]]
+; CHECK-NEXT:    [[TMP2:%.*]] = mul nuw <2 x i8> [[B:%.*]], [[D:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = shufflevector <2 x i8> [[TMP1]], <2 x i8> [[TMP2]], <4 x i32> <i32 0, i32 1, i32 2, i32 3>
+; CHECK-NEXT:    ret <4 x i8> [[R]]
+;
+  %concat1 = shufflevector <2 x i8> %a, <2 x i8> %b, <4 x i32> <i32 0, i32 1, i32 2, i32 3>
+  %concat2 = shufflevector <2 x i8> %c, <2 x i8> %d, <4 x i32> <i32 0, i32 1, i32 2, i32 3>
+  %r = mul nuw <4 x i8> %concat1, %concat2
+  ret <4 x i8> %r
+}
+
+; Undef in shuffle mask does not necessarily propagate.
+
+define <4 x i8> @and(<2 x i8> %a, <2 x i8> %b, <2 x i8> %c, <2 x i8> %d) {
+; CHECK-LABEL: @and(
+; CHECK-NEXT:    [[CONCAT1:%.*]] = shufflevector <2 x i8> [[A:%.*]], <2 x i8> [[B:%.*]], <4 x i32> <i32 undef, i32 1, i32 2, i32 3>
+; CHECK-NEXT:    [[CONCAT2:%.*]] = shufflevector <2 x i8> [[C:%.*]], <2 x i8> [[D:%.*]], <4 x i32> <i32 0, i32 1, i32 2, i32 3>
+; CHECK-NEXT:    [[R:%.*]] = and <4 x i8> [[CONCAT1]], [[CONCAT2]]
+; CHECK-NEXT:    ret <4 x i8> [[R]]
+;
+  %concat1 = shufflevector <2 x i8> %a, <2 x i8> %b, <4 x i32> <i32 undef, i32 1, i32 2, i32 3>
+  %concat2 = shufflevector <2 x i8> %c, <2 x i8> %d, <4 x i32> <i32 0, i32 1, i32 2, i32 3>
+  %r = and <4 x i8> %concat1, %concat2
+  ret <4 x i8> %r
+}
+
+; Undef in shuffle mask does not necessarily propagate.
+
+define <4 x i8> @or(<2 x i8> %a, <2 x i8> %b, <2 x i8> %c, <2 x i8> %d) {
+; CHECK-LABEL: @or(
+; CHECK-NEXT:    [[CONCAT1:%.*]] = shufflevector <2 x i8> [[A:%.*]], <2 x i8> [[B:%.*]], <4 x i32> <i32 0, i32 1, i32 2, i32 3>
+; CHECK-NEXT:    [[CONCAT2:%.*]] = shufflevector <2 x i8> [[C:%.*]], <2 x i8> [[D:%.*]], <4 x i32> <i32 0, i32 undef, i32 2, i32 3>
+; CHECK-NEXT:    [[R:%.*]] = or <4 x i8> [[CONCAT1]], [[CONCAT2]]
+; CHECK-NEXT:    ret <4 x i8> [[R]]
+;
+  %concat1 = shufflevector <2 x i8> %a, <2 x i8> %b, <4 x i32> <i32 0, i32 1, i32 2, i32 3>
+  %concat2 = shufflevector <2 x i8> %c, <2 x i8> %d, <4 x i32> <i32 0, i32 undef, i32 2, i32 3>
+  %r = or <4 x i8> %concat1, %concat2
+  ret <4 x i8> %r
+}
+
+; Undefs in shuffle mask do not necessarily propagate.
+
+define <4 x i8> @xor(<2 x i8> %a, <2 x i8> %b, <2 x i8> %c, <2 x i8> %d) {
+; CHECK-LABEL: @xor(
+; CHECK-NEXT:    [[CONCAT1:%.*]] = shufflevector <2 x i8> [[A:%.*]], <2 x i8> [[B:%.*]], <4 x i32> <i32 0, i32 undef, i32 2, i32 3>
+; CHECK-NEXT:    [[CONCAT2:%.*]] = shufflevector <2 x i8> [[C:%.*]], <2 x i8> [[D:%.*]], <4 x i32> <i32 0, i32 1, i32 undef, i32 3>
+; CHECK-NEXT:    [[R:%.*]] = xor <4 x i8> [[CONCAT1]], [[CONCAT2]]
+; CHECK-NEXT:    ret <4 x i8> [[R]]
+;
+  %concat1 = shufflevector <2 x i8> %a, <2 x i8> %b, <4 x i32> <i32 0, i32 undef, i32 2, i32 3>
+  %concat2 = shufflevector <2 x i8> %c, <2 x i8> %d, <4 x i32> <i32 0, i32 1, i32 undef, i32 3>
+  %r = xor <4 x i8> %concat1, %concat2
+  ret <4 x i8> %r
+}
+
+define <4 x i8> @shl(<2 x i8> %a, <2 x i8> %b, <2 x i8> %c, <2 x i8> %d) {
+; CHECK-LABEL: @shl(
+; CHECK-NEXT:    [[TMP1:%.*]] = shl nuw <2 x i8> [[A:%.*]], [[C:%.*]]
+; CHECK-NEXT:    [[TMP2:%.*]] = shl nuw <2 x i8> [[B:%.*]], [[D:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = shufflevector <2 x i8> [[TMP1]], <2 x i8> [[TMP2]], <4 x i32> <i32 0, i32 1, i32 undef, i32 3>
+; CHECK-NEXT:    ret <4 x i8> [[R]]
+;
+  %concat1 = shufflevector <2 x i8> %a, <2 x i8> %b, <4 x i32> <i32 0, i32 1, i32 undef, i32 3>
+  %concat2 = shufflevector <2 x i8> %c, <2 x i8> %d, <4 x i32> <i32 0, i32 1, i32 undef, i32 3>
+  %r = shl nuw <4 x i8> %concat1, %concat2
+  ret <4 x i8> %r
+}
+
+define <4 x i8> @lshr(<2 x i8> %a, <2 x i8> %b, <2 x i8> %c, <2 x i8> %d) {
+; CHECK-LABEL: @lshr(
+; CHECK-NEXT:    [[TMP1:%.*]] = lshr exact <2 x i8> [[A:%.*]], [[C:%.*]]
+; CHECK-NEXT:    [[TMP2:%.*]] = lshr exact <2 x i8> [[B:%.*]], [[D:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = shufflevector <2 x i8> [[TMP1]], <2 x i8> [[TMP2]], <4 x i32> <i32 0, i32 undef, i32 undef, i32 3>
+; CHECK-NEXT:    ret <4 x i8> [[R]]
+;
+  %concat1 = shufflevector <2 x i8> %a, <2 x i8> %b, <4 x i32> <i32 0, i32 undef, i32 undef, i32 3>
+  %concat2 = shufflevector <2 x i8> %c, <2 x i8> %d, <4 x i32> <i32 0, i32 undef, i32 undef, i32 3>
+  %r = lshr exact <4 x i8> %concat1, %concat2
+  ret <4 x i8> %r
+}
+
+; Extra-uses prevent the transform.
+declare void @use(<4 x i8>)
+
+define <4 x i8> @ashr(<2 x i8> %a, <2 x i8> %b, <2 x i8> %c, <2 x i8> %d) {
+; CHECK-LABEL: @ashr(
+; CHECK-NEXT:    [[CONCAT1:%.*]] = shufflevector <2 x i8> [[A:%.*]], <2 x i8> [[B:%.*]], <4 x i32> <i32 0, i32 1, i32 2, i32 3>
+; CHECK-NEXT:    call void @use(<4 x i8> [[CONCAT1]])
+; CHECK-NEXT:    [[CONCAT2:%.*]] = shufflevector <2 x i8> [[C:%.*]], <2 x i8> [[D:%.*]], <4 x i32> <i32 0, i32 1, i32 2, i32 3>
+; CHECK-NEXT:    [[R:%.*]] = ashr <4 x i8> [[CONCAT1]], [[CONCAT2]]
+; CHECK-NEXT:    ret <4 x i8> [[R]]
+;
+  %concat1 = shufflevector <2 x i8> %a, <2 x i8> %b, <4 x i32> <i32 0, i32 1, i32 2, i32 3>
+  call void @use(<4 x i8> %concat1)
+  %concat2 = shufflevector <2 x i8> %c, <2 x i8> %d, <4 x i32> <i32 0, i32 1, i32 2, i32 3>
+  %r = ashr <4 x i8> %concat1, %concat2
+  ret <4 x i8> %r
+}
+
+; TODO: Div/rem with undef in any element in the divisor is undef, so this should be simplified away?
+
+define <4 x i8> @sdiv(<2 x i8> %a, <2 x i8> %b, <2 x i8> %c, <2 x i8> %d) {
+; CHECK-LABEL: @sdiv(
+; CHECK-NEXT:    [[TMP1:%.*]] = sdiv exact <2 x i8> [[A:%.*]], [[C:%.*]]
+; CHECK-NEXT:    [[TMP2:%.*]] = sdiv exact <2 x i8> [[B:%.*]], [[D:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = shufflevector <2 x i8> [[TMP1]], <2 x i8> [[TMP2]], <4 x i32> <i32 0, i32 1, i32 undef, i32 3>
+; CHECK-NEXT:    ret <4 x i8> [[R]]
+;
+  %concat1 = shufflevector <2 x i8> %a, <2 x i8> %b, <4 x i32> <i32 0, i32 1, i32 undef, i32 3>
+  %concat2 = shufflevector <2 x i8> %c, <2 x i8> %d, <4 x i32> <i32 0, i32 1, i32 undef, i32 3>
+  %r = sdiv exact <4 x i8> %concat1, %concat2
+  ret <4 x i8> %r
+}
+
+define <4 x i8> @srem(<2 x i8> %a, <2 x i8> %b, <2 x i8> %c, <2 x i8> %d) {
+; CHECK-LABEL: @srem(
+; CHECK-NEXT:    [[TMP1:%.*]] = srem <2 x i8> [[A:%.*]], [[C:%.*]]
+; CHECK-NEXT:    [[TMP2:%.*]] = srem <2 x i8> [[B:%.*]], [[D:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = shufflevector <2 x i8> [[TMP1]], <2 x i8> [[TMP2]], <4 x i32> <i32 0, i32 1, i32 2, i32 3>
+; CHECK-NEXT:    ret <4 x i8> [[R]]
+;
+  %concat1 = shufflevector <2 x i8> %a, <2 x i8> %b, <4 x i32> <i32 0, i32 1, i32 2, i32 3>
+  %concat2 = shufflevector <2 x i8> %c, <2 x i8> %d, <4 x i32> <i32 0, i32 1, i32 2, i32 3>
+  %r = srem <4 x i8> %concat1, %concat2
+  ret <4 x i8> %r
+}
+
+define <4 x i8> @udiv(<2 x i8> %a, <2 x i8> %b, <2 x i8> %c, <2 x i8> %d) {
+; CHECK-LABEL: @udiv(
+; CHECK-NEXT:    [[TMP1:%.*]] = udiv exact <2 x i8> [[A:%.*]], [[C:%.*]]
+; CHECK-NEXT:    [[TMP2:%.*]] = udiv exact <2 x i8> [[B:%.*]], [[D:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = shufflevector <2 x i8> [[TMP1]], <2 x i8> [[TMP2]], <4 x i32> <i32 0, i32 1, i32 2, i32 3>
+; CHECK-NEXT:    ret <4 x i8> [[R]]
+;
+  %concat1 = shufflevector <2 x i8> %a, <2 x i8> %b, <4 x i32> <i32 0, i32 1, i32 2, i32 3>
+  %concat2 = shufflevector <2 x i8> %c, <2 x i8> %d, <4 x i32> <i32 0, i32 1, i32 2, i32 3>
+  %r = udiv exact <4 x i8> %concat1, %concat2
+  ret <4 x i8> %r
+}
+
+; TODO: Div/rem with undef in any element in the divisor is undef, so this should be simplified away?
+
+define <4 x i8> @urem(<2 x i8> %a, <2 x i8> %b, <2 x i8> %c, <2 x i8> %d) {
+; CHECK-LABEL: @urem(
+; CHECK-NEXT:    [[TMP1:%.*]] = urem <2 x i8> [[A:%.*]], [[C:%.*]]
+; CHECK-NEXT:    [[TMP2:%.*]] = urem <2 x i8> [[B:%.*]], [[D:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = shufflevector <2 x i8> [[TMP1]], <2 x i8> [[TMP2]], <4 x i32> <i32 undef, i32 1, i32 2, i32 3>
+; CHECK-NEXT:    ret <4 x i8> [[R]]
+;
+  %concat1 = shufflevector <2 x i8> %a, <2 x i8> %b, <4 x i32> <i32 undef, i32 1, i32 2, i32 3>
+  %concat2 = shufflevector <2 x i8> %c, <2 x i8> %d, <4 x i32> <i32 undef, i32 1, i32 2, i32 3>
+  %r = urem <4 x i8> %concat1, %concat2
+  ret <4 x i8> %r
+}
+
+define <4 x float> @fadd(<2 x float> %a, <2 x float> %b, <2 x float> %c, <2 x float> %d) {
+; CHECK-LABEL: @fadd(
+; CHECK-NEXT:    [[TMP1:%.*]] = fadd <2 x float> [[A:%.*]], [[C:%.*]]
+; CHECK-NEXT:    [[TMP2:%.*]] = fadd <2 x float> [[B:%.*]], [[D:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = shufflevector <2 x float> [[TMP1]], <2 x float> [[TMP2]], <4 x i32> <i32 0, i32 1, i32 2, i32 3>
+; CHECK-NEXT:    ret <4 x float> [[R]]
+;
+  %concat1 = shufflevector <2 x float> %a, <2 x float> %b, <4 x i32> <i32 0, i32 1, i32 2, i32 3>
+  %concat2 = shufflevector <2 x float> %c, <2 x float> %d, <4 x i32> <i32 0, i32 1, i32 2, i32 3>
+  %r = fadd <4 x float> %concat1, %concat2
+  ret <4 x float> %r
+}
+
+; Fast-math-flags propagate.
+
+define <4 x float> @fsub(<2 x float> %a, <2 x float> %b, <2 x float> %c, <2 x float> %d) {
+; CHECK-LABEL: @fsub(
+; CHECK-NEXT:    [[TMP1:%.*]] = fsub fast <2 x float> [[A:%.*]], [[C:%.*]]
+; CHECK-NEXT:    [[TMP2:%.*]] = fsub fast <2 x float> [[B:%.*]], [[D:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = shufflevector <2 x float> [[TMP1]], <2 x float> [[TMP2]], <4 x i32> <i32 0, i32 1, i32 undef, i32 3>
+; CHECK-NEXT:    ret <4 x float> [[R]]
+;
+  %concat1 = shufflevector <2 x float> %a, <2 x float> %b, <4 x i32> <i32 0, i32 1, i32 undef, i32 3>
+  %concat2 = shufflevector <2 x float> %c, <2 x float> %d, <4 x i32> <i32 0, i32 1, i32 undef, i32 3>
+  %r = fsub fast <4 x float> %concat1, %concat2
+  ret <4 x float> %r
+}
+
+; Extra-uses prevent the transform.
+declare void @use2(<4 x float>)
+
+define <4 x float> @fmul(<2 x float> %a, <2 x float> %b, <2 x float> %c, <2 x float> %d) {
+; CHECK-LABEL: @fmul(
+; CHECK-NEXT:    [[CONCAT1:%.*]] = shufflevector <2 x float> [[A:%.*]], <2 x float> [[B:%.*]], <4 x i32> <i32 undef, i32 1, i32 undef, i32 3>
+; CHECK-NEXT:    [[CONCAT2:%.*]] = shufflevector <2 x float> [[C:%.*]], <2 x float> [[D:%.*]], <4 x i32> <i32 undef, i32 1, i32 undef, i32 3>
+; CHECK-NEXT:    call void @use2(<4 x float> [[CONCAT2]])
+; CHECK-NEXT:    [[R:%.*]] = fmul nnan <4 x float> [[CONCAT1]], [[CONCAT2]]
+; CHECK-NEXT:    ret <4 x float> [[R]]
+;
+  %concat1 = shufflevector <2 x float> %a, <2 x float> %b, <4 x i32> <i32 undef, i32 1, i32 undef, i32 3>
+  %concat2 = shufflevector <2 x float> %c, <2 x float> %d, <4 x i32> <i32 undef, i32 1, i32 undef, i32 3>
+  call void @use2(<4 x float> %concat2)
+  %r = fmul nnan <4 x float> %concat1, %concat2
+  ret <4 x float> %r
+}
+
+; Fast-math-flags propagate.
+
+define <4 x float> @fdiv(<2 x float> %a, <2 x float> %b, <2 x float> %c, <2 x float> %d) {
+; CHECK-LABEL: @fdiv(
+; CHECK-NEXT:    [[TMP1:%.*]] = fdiv ninf arcp <2 x float> [[A:%.*]], [[C:%.*]]
+; CHECK-NEXT:    [[TMP2:%.*]] = fdiv ninf arcp <2 x float> [[B:%.*]], [[D:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = shufflevector <2 x float> [[TMP1]], <2 x float> [[TMP2]], <4 x i32> <i32 0, i32 1, i32 2, i32 3>
+; CHECK-NEXT:    ret <4 x float> [[R]]
+;
+  %concat1 = shufflevector <2 x float> %a, <2 x float> %b, <4 x i32> <i32 0, i32 1, i32 2, i32 3>
+  %concat2 = shufflevector <2 x float> %c, <2 x float> %d, <4 x i32> <i32 0, i32 1, i32 2, i32 3>
+  %r = fdiv ninf arcp <4 x float> %concat1, %concat2
+  ret <4 x float> %r
+}
+
+define <4 x float> @frem(<2 x float> %a, <2 x float> %b, <2 x float> %c, <2 x float> %d) {
+; CHECK-LABEL: @frem(
+; CHECK-NEXT:    [[TMP1:%.*]] = frem <2 x float> [[A:%.*]], [[C:%.*]]
+; CHECK-NEXT:    [[TMP2:%.*]] = frem <2 x float> [[B:%.*]], [[D:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = shufflevector <2 x float> [[TMP1]], <2 x float> [[TMP2]], <4 x i32> <i32 0, i32 undef, i32 2, i32 3>
+; CHECK-NEXT:    ret <4 x float> [[R]]
+;
+  %concat1 = shufflevector <2 x float> %a, <2 x float> %b, <4 x i32> <i32 0, i32 undef, i32 2, i32 3>
+  %concat2 = shufflevector <2 x float> %c, <2 x float> %d, <4 x i32> <i32 0, i32 undef, i32 2, i32 3>
+  %r = frem <4 x float> %concat1, %concat2
+  ret <4 x float> %r
+}
+
+; https://bugs.llvm.org/show_bug.cgi?id=33026 - all of the shuffles can be eliminated.
+
+define <4 x i32> @PR33026(<4 x i32> %a, <4 x i32> %b, <4 x i32> %c, <4 x i32> %d) {
+; CHECK-LABEL: @PR33026(
+; CHECK-NEXT:    [[TMP1:%.*]] = and <4 x i32> [[A:%.*]], [[C:%.*]]
+; CHECK-NEXT:    [[TMP2:%.*]] = and <4 x i32> [[B:%.*]], [[D:%.*]]
+; CHECK-NEXT:    [[SUB:%.*]] = sub <4 x i32> [[TMP1]], [[TMP2]]
+; CHECK-NEXT:    ret <4 x i32> [[SUB]]
+;
+  %concat1 = shufflevector <4 x i32> %a, <4 x i32> %b, <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7>
+  %concat2 = shufflevector <4 x i32> %c, <4 x i32> %d, <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7>
+  %and = and <8 x i32> %concat1, %concat2
+  %extract1 = shufflevector <8 x i32> %and, <8 x i32> undef, <4 x i32> <i32 0, i32 1, i32 2, i32 3>
+  %extract2 = shufflevector <8 x i32> %and, <8 x i32> undef, <4 x i32> <i32 4, i32 5, i32 6, i32 7>
+  %sub = sub <4 x i32> %extract1, %extract2
+  ret <4 x i32> %sub
+}

Added: llvm/trunk/test/Transforms/InstCombine/vector-mul.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/vector-mul.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/vector-mul.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/vector-mul.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,445 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt < %s -instcombine -S | FileCheck %s
+
+; Check that instcombine rewrites multiply by a vector
+; of known constant power-of-2 elements with vector shift.
+
+define <4 x i8> @Zero_i8(<4 x i8> %InVec)  {
+; CHECK-LABEL: @Zero_i8(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    ret <4 x i8> zeroinitializer
+;
+entry:
+  %mul = mul <4 x i8> %InVec, <i8 0, i8 0, i8 0, i8 0>
+  ret <4 x i8> %mul
+}
+
+define <4 x i8> @Identity_i8(<4 x i8> %InVec)  {
+; CHECK-LABEL: @Identity_i8(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    ret <4 x i8> [[INVEC:%.*]]
+;
+entry:
+  %mul = mul <4 x i8> %InVec, <i8 1, i8 1, i8 1, i8 1>
+  ret <4 x i8> %mul
+}
+
+define <4 x i8> @AddToSelf_i8(<4 x i8> %InVec)  {
+; CHECK-LABEL: @AddToSelf_i8(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[MUL:%.*]] = shl <4 x i8> [[INVEC:%.*]], <i8 1, i8 1, i8 1, i8 1>
+; CHECK-NEXT:    ret <4 x i8> [[MUL]]
+;
+entry:
+  %mul = mul <4 x i8> %InVec, <i8 2, i8 2, i8 2, i8 2>
+  ret <4 x i8> %mul
+}
+
+define <4 x i8> @SplatPow2Test1_i8(<4 x i8> %InVec)  {
+; CHECK-LABEL: @SplatPow2Test1_i8(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[MUL:%.*]] = shl <4 x i8> [[INVEC:%.*]], <i8 2, i8 2, i8 2, i8 2>
+; CHECK-NEXT:    ret <4 x i8> [[MUL]]
+;
+entry:
+  %mul = mul <4 x i8> %InVec, <i8 4, i8 4, i8 4, i8 4>
+  ret <4 x i8> %mul
+}
+
+define <4 x i8> @SplatPow2Test2_i8(<4 x i8> %InVec)  {
+; CHECK-LABEL: @SplatPow2Test2_i8(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[MUL:%.*]] = shl <4 x i8> [[INVEC:%.*]], <i8 3, i8 3, i8 3, i8 3>
+; CHECK-NEXT:    ret <4 x i8> [[MUL]]
+;
+entry:
+  %mul = mul <4 x i8> %InVec, <i8 8, i8 8, i8 8, i8 8>
+  ret <4 x i8> %mul
+}
+
+define <4 x i8> @MulTest1_i8(<4 x i8> %InVec)  {
+; CHECK-LABEL: @MulTest1_i8(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[MUL:%.*]] = shl <4 x i8> [[INVEC:%.*]], <i8 0, i8 1, i8 2, i8 3>
+; CHECK-NEXT:    ret <4 x i8> [[MUL]]
+;
+entry:
+  %mul = mul <4 x i8> %InVec, <i8 1, i8 2, i8 4, i8 8>
+  ret <4 x i8> %mul
+}
+
+define <4 x i8> @MulTest2_i8(<4 x i8> %InVec)  {
+; CHECK-LABEL: @MulTest2_i8(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[MUL:%.*]] = mul <4 x i8> [[INVEC:%.*]], <i8 3, i8 3, i8 3, i8 3>
+; CHECK-NEXT:    ret <4 x i8> [[MUL]]
+;
+entry:
+  %mul = mul <4 x i8> %InVec, <i8 3, i8 3, i8 3, i8 3>
+  ret <4 x i8> %mul
+}
+
+define <4 x i8> @MulTest3_i8(<4 x i8> %InVec)  {
+; CHECK-LABEL: @MulTest3_i8(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[MUL:%.*]] = shl <4 x i8> [[INVEC:%.*]], <i8 2, i8 2, i8 1, i8 1>
+; CHECK-NEXT:    ret <4 x i8> [[MUL]]
+;
+entry:
+  %mul = mul <4 x i8> %InVec, <i8 4, i8 4, i8 2, i8 2>
+  ret <4 x i8> %mul
+}
+
+define <4 x i8> @MulTest4_i8(<4 x i8> %InVec)  {
+; CHECK-LABEL: @MulTest4_i8(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[MUL:%.*]] = mul <4 x i8> [[INVEC:%.*]], <i8 4, i8 4, i8 0, i8 1>
+; CHECK-NEXT:    ret <4 x i8> [[MUL]]
+;
+entry:
+  %mul = mul <4 x i8> %InVec, <i8 4, i8 4, i8 0, i8 1>
+  ret <4 x i8> %mul
+}
+
+define <4 x i16> @Zero_i16(<4 x i16> %InVec)  {
+; CHECK-LABEL: @Zero_i16(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    ret <4 x i16> zeroinitializer
+;
+entry:
+  %mul = mul <4 x i16> %InVec, <i16 0, i16 0, i16 0, i16 0>
+  ret <4 x i16> %mul
+}
+
+define <4 x i16> @Identity_i16(<4 x i16> %InVec)  {
+; CHECK-LABEL: @Identity_i16(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    ret <4 x i16> [[INVEC:%.*]]
+;
+entry:
+  %mul = mul <4 x i16> %InVec, <i16 1, i16 1, i16 1, i16 1>
+  ret <4 x i16> %mul
+}
+
+define <4 x i16> @AddToSelf_i16(<4 x i16> %InVec)  {
+; CHECK-LABEL: @AddToSelf_i16(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[MUL:%.*]] = shl <4 x i16> [[INVEC:%.*]], <i16 1, i16 1, i16 1, i16 1>
+; CHECK-NEXT:    ret <4 x i16> [[MUL]]
+;
+entry:
+  %mul = mul <4 x i16> %InVec, <i16 2, i16 2, i16 2, i16 2>
+  ret <4 x i16> %mul
+}
+
+define <4 x i16> @SplatPow2Test1_i16(<4 x i16> %InVec)  {
+; CHECK-LABEL: @SplatPow2Test1_i16(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[MUL:%.*]] = shl <4 x i16> [[INVEC:%.*]], <i16 2, i16 2, i16 2, i16 2>
+; CHECK-NEXT:    ret <4 x i16> [[MUL]]
+;
+entry:
+  %mul = mul <4 x i16> %InVec, <i16 4, i16 4, i16 4, i16 4>
+  ret <4 x i16> %mul
+}
+
+define <4 x i16> @SplatPow2Test2_i16(<4 x i16> %InVec)  {
+; CHECK-LABEL: @SplatPow2Test2_i16(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[MUL:%.*]] = shl <4 x i16> [[INVEC:%.*]], <i16 3, i16 3, i16 3, i16 3>
+; CHECK-NEXT:    ret <4 x i16> [[MUL]]
+;
+entry:
+  %mul = mul <4 x i16> %InVec, <i16 8, i16 8, i16 8, i16 8>
+  ret <4 x i16> %mul
+}
+
+define <4 x i16> @MulTest1_i16(<4 x i16> %InVec)  {
+; CHECK-LABEL: @MulTest1_i16(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[MUL:%.*]] = shl <4 x i16> [[INVEC:%.*]], <i16 0, i16 1, i16 2, i16 3>
+; CHECK-NEXT:    ret <4 x i16> [[MUL]]
+;
+entry:
+  %mul = mul <4 x i16> %InVec, <i16 1, i16 2, i16 4, i16 8>
+  ret <4 x i16> %mul
+}
+
+define <4 x i16> @MulTest2_i16(<4 x i16> %InVec)  {
+; CHECK-LABEL: @MulTest2_i16(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[MUL:%.*]] = mul <4 x i16> [[INVEC:%.*]], <i16 3, i16 3, i16 3, i16 3>
+; CHECK-NEXT:    ret <4 x i16> [[MUL]]
+;
+entry:
+  %mul = mul <4 x i16> %InVec, <i16 3, i16 3, i16 3, i16 3>
+  ret <4 x i16> %mul
+}
+
+define <4 x i16> @MulTest3_i16(<4 x i16> %InVec)  {
+; CHECK-LABEL: @MulTest3_i16(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[MUL:%.*]] = shl <4 x i16> [[INVEC:%.*]], <i16 2, i16 2, i16 1, i16 1>
+; CHECK-NEXT:    ret <4 x i16> [[MUL]]
+;
+entry:
+  %mul = mul <4 x i16> %InVec, <i16 4, i16 4, i16 2, i16 2>
+  ret <4 x i16> %mul
+}
+
+define <4 x i16> @MulTest4_i16(<4 x i16> %InVec)  {
+; CHECK-LABEL: @MulTest4_i16(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[MUL:%.*]] = mul <4 x i16> [[INVEC:%.*]], <i16 4, i16 4, i16 0, i16 2>
+; CHECK-NEXT:    ret <4 x i16> [[MUL]]
+;
+entry:
+  %mul = mul <4 x i16> %InVec, <i16 4, i16 4, i16 0, i16 2>
+  ret <4 x i16> %mul
+}
+
+define <4 x i32> @Zero_i32(<4 x i32> %InVec)  {
+; CHECK-LABEL: @Zero_i32(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    ret <4 x i32> zeroinitializer
+;
+entry:
+  %mul = mul <4 x i32> %InVec, <i32 0, i32 0, i32 0, i32 0>
+  ret <4 x i32> %mul
+}
+
+define <4 x i32> @Identity_i32(<4 x i32> %InVec)  {
+; CHECK-LABEL: @Identity_i32(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    ret <4 x i32> [[INVEC:%.*]]
+;
+entry:
+  %mul = mul <4 x i32> %InVec, <i32 1, i32 1, i32 1, i32 1>
+  ret <4 x i32> %mul
+}
+
+define <4 x i32> @AddToSelf_i32(<4 x i32> %InVec)  {
+; CHECK-LABEL: @AddToSelf_i32(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[MUL:%.*]] = shl <4 x i32> [[INVEC:%.*]], <i32 1, i32 1, i32 1, i32 1>
+; CHECK-NEXT:    ret <4 x i32> [[MUL]]
+;
+entry:
+  %mul = mul <4 x i32> %InVec, <i32 2, i32 2, i32 2, i32 2>
+  ret <4 x i32> %mul
+}
+
+define <4 x i32> @SplatPow2Test1_i32(<4 x i32> %InVec)  {
+; CHECK-LABEL: @SplatPow2Test1_i32(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[MUL:%.*]] = shl <4 x i32> [[INVEC:%.*]], <i32 2, i32 2, i32 2, i32 2>
+; CHECK-NEXT:    ret <4 x i32> [[MUL]]
+;
+entry:
+  %mul = mul <4 x i32> %InVec, <i32 4, i32 4, i32 4, i32 4>
+  ret <4 x i32> %mul
+}
+
+define <4 x i32> @SplatPow2Test2_i32(<4 x i32> %InVec)  {
+; CHECK-LABEL: @SplatPow2Test2_i32(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[MUL:%.*]] = shl <4 x i32> [[INVEC:%.*]], <i32 3, i32 3, i32 3, i32 3>
+; CHECK-NEXT:    ret <4 x i32> [[MUL]]
+;
+entry:
+  %mul = mul <4 x i32> %InVec, <i32 8, i32 8, i32 8, i32 8>
+  ret <4 x i32> %mul
+}
+
+define <4 x i32> @MulTest1_i32(<4 x i32> %InVec)  {
+; CHECK-LABEL: @MulTest1_i32(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[MUL:%.*]] = shl <4 x i32> [[INVEC:%.*]], <i32 0, i32 1, i32 2, i32 3>
+; CHECK-NEXT:    ret <4 x i32> [[MUL]]
+;
+entry:
+  %mul = mul <4 x i32> %InVec, <i32 1, i32 2, i32 4, i32 8>
+  ret <4 x i32> %mul
+}
+
+define <4 x i32> @MulTest2_i32(<4 x i32> %InVec)  {
+; CHECK-LABEL: @MulTest2_i32(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[MUL:%.*]] = mul <4 x i32> [[INVEC:%.*]], <i32 3, i32 3, i32 3, i32 3>
+; CHECK-NEXT:    ret <4 x i32> [[MUL]]
+;
+entry:
+  %mul = mul <4 x i32> %InVec, <i32 3, i32 3, i32 3, i32 3>
+  ret <4 x i32> %mul
+}
+
+define <4 x i32> @MulTest3_i32(<4 x i32> %InVec)  {
+; CHECK-LABEL: @MulTest3_i32(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[MUL:%.*]] = shl <4 x i32> [[INVEC:%.*]], <i32 2, i32 2, i32 1, i32 1>
+; CHECK-NEXT:    ret <4 x i32> [[MUL]]
+;
+entry:
+  %mul = mul <4 x i32> %InVec, <i32 4, i32 4, i32 2, i32 2>
+  ret <4 x i32> %mul
+}
+
+define <4 x i32> @MulTest4_i32(<4 x i32> %InVec)  {
+; CHECK-LABEL: @MulTest4_i32(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[MUL:%.*]] = mul <4 x i32> [[INVEC:%.*]], <i32 4, i32 4, i32 0, i32 1>
+; CHECK-NEXT:    ret <4 x i32> [[MUL]]
+;
+entry:
+  %mul = mul <4 x i32> %InVec, <i32 4, i32 4, i32 0, i32 1>
+  ret <4 x i32> %mul
+}
+
+define <4 x i64> @Zero_i64(<4 x i64> %InVec)  {
+; CHECK-LABEL: @Zero_i64(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    ret <4 x i64> zeroinitializer
+;
+entry:
+  %mul = mul <4 x i64> %InVec, <i64 0, i64 0, i64 0, i64 0>
+  ret <4 x i64> %mul
+}
+
+define <4 x i64> @Identity_i64(<4 x i64> %InVec)  {
+; CHECK-LABEL: @Identity_i64(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    ret <4 x i64> [[INVEC:%.*]]
+;
+entry:
+  %mul = mul <4 x i64> %InVec, <i64 1, i64 1, i64 1, i64 1>
+  ret <4 x i64> %mul
+}
+
+define <4 x i64> @AddToSelf_i64(<4 x i64> %InVec)  {
+; CHECK-LABEL: @AddToSelf_i64(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[MUL:%.*]] = shl <4 x i64> [[INVEC:%.*]], <i64 1, i64 1, i64 1, i64 1>
+; CHECK-NEXT:    ret <4 x i64> [[MUL]]
+;
+entry:
+  %mul = mul <4 x i64> %InVec, <i64 2, i64 2, i64 2, i64 2>
+  ret <4 x i64> %mul
+}
+
+define <4 x i64> @SplatPow2Test1_i64(<4 x i64> %InVec)  {
+; CHECK-LABEL: @SplatPow2Test1_i64(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[MUL:%.*]] = shl <4 x i64> [[INVEC:%.*]], <i64 2, i64 2, i64 2, i64 2>
+; CHECK-NEXT:    ret <4 x i64> [[MUL]]
+;
+entry:
+  %mul = mul <4 x i64> %InVec, <i64 4, i64 4, i64 4, i64 4>
+  ret <4 x i64> %mul
+}
+
+define <4 x i64> @SplatPow2Test2_i64(<4 x i64> %InVec)  {
+; CHECK-LABEL: @SplatPow2Test2_i64(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[MUL:%.*]] = shl <4 x i64> [[INVEC:%.*]], <i64 3, i64 3, i64 3, i64 3>
+; CHECK-NEXT:    ret <4 x i64> [[MUL]]
+;
+entry:
+  %mul = mul <4 x i64> %InVec, <i64 8, i64 8, i64 8, i64 8>
+  ret <4 x i64> %mul
+}
+
+define <4 x i64> @MulTest1_i64(<4 x i64> %InVec)  {
+; CHECK-LABEL: @MulTest1_i64(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[MUL:%.*]] = shl <4 x i64> [[INVEC:%.*]], <i64 0, i64 1, i64 2, i64 3>
+; CHECK-NEXT:    ret <4 x i64> [[MUL]]
+;
+entry:
+  %mul = mul <4 x i64> %InVec, <i64 1, i64 2, i64 4, i64 8>
+  ret <4 x i64> %mul
+}
+
+define <4 x i64> @MulTest2_i64(<4 x i64> %InVec)  {
+; CHECK-LABEL: @MulTest2_i64(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[MUL:%.*]] = mul <4 x i64> [[INVEC:%.*]], <i64 3, i64 3, i64 3, i64 3>
+; CHECK-NEXT:    ret <4 x i64> [[MUL]]
+;
+entry:
+  %mul = mul <4 x i64> %InVec, <i64 3, i64 3, i64 3, i64 3>
+  ret <4 x i64> %mul
+}
+
+define <4 x i64> @MulTest3_i64(<4 x i64> %InVec)  {
+; CHECK-LABEL: @MulTest3_i64(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[MUL:%.*]] = shl <4 x i64> [[INVEC:%.*]], <i64 2, i64 2, i64 1, i64 1>
+; CHECK-NEXT:    ret <4 x i64> [[MUL]]
+;
+entry:
+  %mul = mul <4 x i64> %InVec, <i64 4, i64 4, i64 2, i64 2>
+  ret <4 x i64> %mul
+}
+
+define <4 x i64> @MulTest4_i64(<4 x i64> %InVec)  {
+; CHECK-LABEL: @MulTest4_i64(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[MUL:%.*]] = mul <4 x i64> [[INVEC:%.*]], <i64 4, i64 4, i64 0, i64 1>
+; CHECK-NEXT:    ret <4 x i64> [[MUL]]
+;
+entry:
+  %mul = mul <4 x i64> %InVec, <i64 4, i64 4, i64 0, i64 1>
+  ret <4 x i64> %mul
+}
+
+; Test also that the following rewriting rule works with vectors
+; of integers as well:
+;   ((X << C1)*C2) == (X * (C2 << C1))
+
+define <4 x i8> @ShiftMulTest1(<4 x i8> %InVec) {
+; CHECK-LABEL: @ShiftMulTest1(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[MUL:%.*]] = mul <4 x i8> [[INVEC:%.*]], <i8 12, i8 12, i8 12, i8 12>
+; CHECK-NEXT:    ret <4 x i8> [[MUL]]
+;
+entry:
+  %shl = shl <4 x i8> %InVec, <i8 2, i8 2, i8 2, i8 2>
+  %mul = mul <4 x i8> %shl, <i8 3, i8 3, i8 3, i8 3>
+  ret <4 x i8> %mul
+}
+
+define <4 x i16> @ShiftMulTest2(<4 x i16> %InVec) {
+; CHECK-LABEL: @ShiftMulTest2(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[MUL:%.*]] = mul <4 x i16> [[INVEC:%.*]], <i16 12, i16 12, i16 12, i16 12>
+; CHECK-NEXT:    ret <4 x i16> [[MUL]]
+;
+entry:
+  %shl = shl <4 x i16> %InVec, <i16 2, i16 2, i16 2, i16 2>
+  %mul = mul <4 x i16> %shl, <i16 3, i16 3, i16 3, i16 3>
+  ret <4 x i16> %mul
+}
+
+define <4 x i32> @ShiftMulTest3(<4 x i32> %InVec) {
+; CHECK-LABEL: @ShiftMulTest3(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[MUL:%.*]] = mul <4 x i32> [[INVEC:%.*]], <i32 12, i32 12, i32 12, i32 12>
+; CHECK-NEXT:    ret <4 x i32> [[MUL]]
+;
+entry:
+  %shl = shl <4 x i32> %InVec, <i32 2, i32 2, i32 2, i32 2>
+  %mul = mul <4 x i32> %shl, <i32 3, i32 3, i32 3, i32 3>
+  ret <4 x i32> %mul
+}
+
+define <4 x i64> @ShiftMulTest4(<4 x i64> %InVec) {
+; CHECK-LABEL: @ShiftMulTest4(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[MUL:%.*]] = mul <4 x i64> [[INVEC:%.*]], <i64 12, i64 12, i64 12, i64 12>
+; CHECK-NEXT:    ret <4 x i64> [[MUL]]
+;
+entry:
+  %shl = shl <4 x i64> %InVec, <i64 2, i64 2, i64 2, i64 2>
+  %mul = mul <4 x i64> %shl, <i64 3, i64 3, i64 3, i64 3>
+  ret <4 x i64> %mul
+}

Added: llvm/trunk/test/Transforms/InstCombine/vector-type.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/vector-type.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/vector-type.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/vector-type.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,15 @@
+; The code in InstCombiner::FoldSelectOpOp was calling
+; Type::getVectorNumElements without checking first if the type was a vector.
+
+; RUN: opt < %s -instcombine -S
+
+define i32 @vselect1(i32 %a.coerce, i32 %b.coerce, i32 %c.coerce) {
+entry:
+  %0 = bitcast i32 %a.coerce to <2 x i16>
+  %1 = bitcast i32 %b.coerce to <2 x i16>
+  %2 = bitcast i32 %c.coerce to <2 x i16>
+  %cmp = icmp sge <2 x i16> %2, zeroinitializer
+  %or = select <2 x i1> %cmp, <2 x i16> %0, <2 x i16> %1
+  %3 = bitcast <2 x i16> %or to i32
+  ret i32 %3
+}

Added: llvm/trunk/test/Transforms/InstCombine/vector-udiv.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/vector-udiv.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/vector-udiv.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/vector-udiv.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,99 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt < %s -instcombine -S | FileCheck %s
+
+define <4 x i32> @test_v4i32_splatconst_pow2(<4 x i32> %a0) {
+; CHECK-LABEL: @test_v4i32_splatconst_pow2(
+; CHECK-NEXT:    [[TMP1:%.*]] = lshr <4 x i32> [[A0:%.*]], <i32 1, i32 1, i32 1, i32 1>
+; CHECK-NEXT:    ret <4 x i32> [[TMP1]]
+;
+  %1 = udiv <4 x i32> %a0, <i32 2, i32 2, i32 2, i32 2>
+  ret <4 x i32> %1
+}
+
+define <4 x i32> @test_v4i32_const_pow2(<4 x i32> %a0) {
+; CHECK-LABEL: @test_v4i32_const_pow2(
+; CHECK-NEXT:    [[TMP1:%.*]] = lshr <4 x i32> [[A0:%.*]], <i32 0, i32 1, i32 2, i32 3>
+; CHECK-NEXT:    ret <4 x i32> [[TMP1]]
+;
+  %1 = udiv <4 x i32> %a0, <i32 1, i32 2, i32 4, i32 8>
+  ret <4 x i32> %1
+}
+
+; X udiv C, where C >= signbit
+define <4 x i32> @test_v4i32_negconstsplat(<4 x i32> %a0) {
+; CHECK-LABEL: @test_v4i32_negconstsplat(
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp ugt <4 x i32> [[A0:%.*]], <i32 -4, i32 -4, i32 -4, i32 -4>
+; CHECK-NEXT:    [[TMP2:%.*]] = zext <4 x i1> [[TMP1]] to <4 x i32>
+; CHECK-NEXT:    ret <4 x i32> [[TMP2]]
+;
+  %1 = udiv <4 x i32> %a0, <i32 -3, i32 -3, i32 -3, i32 -3>
+  ret <4 x i32> %1
+}
+
+define <4 x i32> @test_v4i32_negconst(<4 x i32> %a0) {
+; CHECK-LABEL: @test_v4i32_negconst(
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp ugt <4 x i32> [[A0:%.*]], <i32 -4, i32 -6, i32 -8, i32 -10>
+; CHECK-NEXT:    [[TMP2:%.*]] = zext <4 x i1> [[TMP1]] to <4 x i32>
+; CHECK-NEXT:    ret <4 x i32> [[TMP2]]
+;
+  %1 = udiv <4 x i32> %a0, <i32 -3, i32 -5, i32 -7, i32 -9>
+  ret <4 x i32> %1
+}
+
+define <4 x i32> @test_v4i32_negconst_undef(<4 x i32> %a0) {
+; CHECK-LABEL: @test_v4i32_negconst_undef(
+; CHECK-NEXT:    ret <4 x i32> undef
+;
+  %1 = udiv <4 x i32> %a0, <i32 -3, i32 -5, i32 -7, i32 undef>
+  ret <4 x i32> %1
+}
+
+; X udiv (C1 << N), where C1 is "1<<C2"  -->  X >> (N+C2)
+define <4 x i32> @test_v4i32_shl_splatconst_pow2(<4 x i32> %a0, <4 x i32> %a1) {
+; CHECK-LABEL: @test_v4i32_shl_splatconst_pow2(
+; CHECK-NEXT:    [[TMP1:%.*]] = add <4 x i32> [[A1:%.*]], <i32 2, i32 2, i32 2, i32 2>
+; CHECK-NEXT:    [[TMP2:%.*]] = lshr <4 x i32> [[A0:%.*]], [[TMP1]]
+; CHECK-NEXT:    ret <4 x i32> [[TMP2]]
+;
+  %1 = shl <4 x i32> <i32 4, i32 4, i32 4, i32 4>, %a1
+  %2 = udiv <4 x i32> %a0, %1
+  ret <4 x i32> %2
+}
+
+define <4 x i32> @test_v4i32_shl_const_pow2(<4 x i32> %a0, <4 x i32> %a1) {
+; CHECK-LABEL: @test_v4i32_shl_const_pow2(
+; CHECK-NEXT:    [[TMP1:%.*]] = add <4 x i32> [[A1:%.*]], <i32 2, i32 3, i32 4, i32 5>
+; CHECK-NEXT:    [[TMP2:%.*]] = lshr <4 x i32> [[A0:%.*]], [[TMP1]]
+; CHECK-NEXT:    ret <4 x i32> [[TMP2]]
+;
+  %1 = shl <4 x i32> <i32 4, i32 8, i32 16, i32 32>, %a1
+  %2 = udiv <4 x i32> %a0, %1
+  ret <4 x i32> %2
+}
+
+; X udiv (zext (C1 << N)), where C1 is "1<<C2"  -->  X >> (N+C2)
+define <4 x i32> @test_v4i32_zext_shl_splatconst_pow2(<4 x i32> %a0, <4 x i16> %a1) {
+; CHECK-LABEL: @test_v4i32_zext_shl_splatconst_pow2(
+; CHECK-NEXT:    [[TMP1:%.*]] = add <4 x i16> [[A1:%.*]], <i16 2, i16 2, i16 2, i16 2>
+; CHECK-NEXT:    [[TMP2:%.*]] = zext <4 x i16> [[TMP1]] to <4 x i32>
+; CHECK-NEXT:    [[TMP3:%.*]] = lshr <4 x i32> [[A0:%.*]], [[TMP2]]
+; CHECK-NEXT:    ret <4 x i32> [[TMP3]]
+;
+  %1 = shl <4 x i16> <i16 4, i16 4, i16 4, i16 4>, %a1
+  %2 = zext <4 x i16> %1 to <4 x i32>
+  %3 = udiv <4 x i32> %a0, %2
+  ret <4 x i32> %3
+}
+
+define <4 x i32> @test_v4i32_zext_shl_const_pow2(<4 x i32> %a0, <4 x i16> %a1) {
+; CHECK-LABEL: @test_v4i32_zext_shl_const_pow2(
+; CHECK-NEXT:    [[TMP1:%.*]] = add <4 x i16> [[A1:%.*]], <i16 2, i16 3, i16 4, i16 5>
+; CHECK-NEXT:    [[TMP2:%.*]] = zext <4 x i16> [[TMP1]] to <4 x i32>
+; CHECK-NEXT:    [[TMP3:%.*]] = lshr <4 x i32> [[A0:%.*]], [[TMP2]]
+; CHECK-NEXT:    ret <4 x i32> [[TMP3]]
+;
+  %1 = shl <4 x i16> <i16 4, i16 8, i16 16, i16 32>, %a1
+  %2 = zext <4 x i16> %1 to <4 x i32>
+  %3 = udiv <4 x i32> %a0, %2
+  ret <4 x i32> %3
+}

Added: llvm/trunk/test/Transforms/InstCombine/vector-urem.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/vector-urem.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/vector-urem.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/vector-urem.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,78 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt < %s -instcombine -S | FileCheck %s
+
+define <4 x i32> @test_v4i32_splatconst_pow2(<4 x i32> %a0) {
+; CHECK-LABEL: @test_v4i32_splatconst_pow2(
+; CHECK-NEXT:    [[TMP1:%.*]] = and <4 x i32> [[A0:%.*]], <i32 1, i32 1, i32 1, i32 1>
+; CHECK-NEXT:    ret <4 x i32> [[TMP1]]
+;
+  %1 = urem <4 x i32> %a0, <i32 2, i32 2, i32 2, i32 2>
+  ret <4 x i32> %1
+}
+
+define <4 x i32> @test_v4i32_const_pow2(<4 x i32> %a0) {
+; CHECK-LABEL: @test_v4i32_const_pow2(
+; CHECK-NEXT:    [[TMP1:%.*]] = and <4 x i32> [[A0:%.*]], <i32 0, i32 1, i32 3, i32 7>
+; CHECK-NEXT:    ret <4 x i32> [[TMP1]]
+;
+  %1 = urem <4 x i32> %a0, <i32 1, i32 2, i32 4, i32 8>
+  ret <4 x i32> %1
+}
+
+define <4 x i32> @test_v4i32_const_pow2_undef(<4 x i32> %a0) {
+; CHECK-LABEL: @test_v4i32_const_pow2_undef(
+; CHECK-NEXT:    ret <4 x i32> undef
+;
+  %1 = urem <4 x i32> %a0, <i32 1, i32 2, i32 4, i32 undef>
+  ret <4 x i32> %1
+}
+
+define <4 x i32> @test_v4i32_one(<4 x i32> %a0) {
+; CHECK-LABEL: @test_v4i32_one(
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp ne <4 x i32> [[A0:%.*]], <i32 1, i32 1, i32 1, i32 1>
+; CHECK-NEXT:    [[TMP2:%.*]] = zext <4 x i1> [[TMP1]] to <4 x i32>
+; CHECK-NEXT:    ret <4 x i32> [[TMP2]]
+;
+  %1 = urem <4 x i32> <i32 1, i32 1, i32 1, i32 1>, %a0
+  ret <4 x i32> %1
+}
+
+define <4 x i32> @test_v4i32_one_undef(<4 x i32> %a0) {
+; CHECK-LABEL: @test_v4i32_one_undef(
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp ne <4 x i32> [[A0:%.*]], <i32 1, i32 1, i32 1, i32 undef>
+; CHECK-NEXT:    [[TMP2:%.*]] = zext <4 x i1> [[TMP1]] to <4 x i32>
+; CHECK-NEXT:    ret <4 x i32> [[TMP2]]
+;
+  %1 = urem <4 x i32> <i32 1, i32 1, i32 1, i32 undef>, %a0
+  ret <4 x i32> %1
+}
+
+define <4 x i32> @test_v4i32_negconstsplat(<4 x i32> %a0) {
+; CHECK-LABEL: @test_v4i32_negconstsplat(
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp ult <4 x i32> [[A0:%.*]], <i32 -3, i32 -3, i32 -3, i32 -3>
+; CHECK-NEXT:    [[TMP2:%.*]] = add <4 x i32> [[A0]], <i32 3, i32 3, i32 3, i32 3>
+; CHECK-NEXT:    [[TMP3:%.*]] = select <4 x i1> [[TMP1]], <4 x i32> [[A0]], <4 x i32> [[TMP2]]
+; CHECK-NEXT:    ret <4 x i32> [[TMP3]]
+;
+  %1 = urem <4 x i32> %a0, <i32 -3, i32 -3, i32 -3, i32 -3>
+  ret <4 x i32> %1
+}
+
+define <4 x i32> @test_v4i32_negconst(<4 x i32> %a0) {
+; CHECK-LABEL: @test_v4i32_negconst(
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp ult <4 x i32> [[A0:%.*]], <i32 -3, i32 -5, i32 -7, i32 -9>
+; CHECK-NEXT:    [[TMP2:%.*]] = add <4 x i32> [[A0]], <i32 3, i32 5, i32 7, i32 9>
+; CHECK-NEXT:    [[TMP3:%.*]] = select <4 x i1> [[TMP1]], <4 x i32> [[A0]], <4 x i32> [[TMP2]]
+; CHECK-NEXT:    ret <4 x i32> [[TMP3]]
+;
+  %1 = urem <4 x i32> %a0, <i32 -3, i32 -5, i32 -7, i32 -9>
+  ret <4 x i32> %1
+}
+
+define <4 x i32> @test_v4i32_negconst_undef(<4 x i32> %a0) {
+; CHECK-LABEL: @test_v4i32_negconst_undef(
+; CHECK-NEXT:    ret <4 x i32> undef
+;
+  %1 = urem <4 x i32> %a0, <i32 -3, i32 -5, i32 -7, i32 undef>
+  ret <4 x i32> %1
+}

Added: llvm/trunk/test/Transforms/InstCombine/vector-xor.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/vector-xor.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/vector-xor.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/vector-xor.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,281 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt < %s -instcombine -S | FileCheck %s
+
+; (A&B)^(A&C) -> A&(B^C) etc
+
+define <4 x i32> @test_v4i32_xor_repeated_and_0(<4 x i32> %a, <4 x i32> %b, <4 x i32> %c) {
+; CHECK-LABEL: @test_v4i32_xor_repeated_and_0(
+; CHECK-NEXT:    [[TMP1:%.*]] = xor <4 x i32> [[B:%.*]], [[C:%.*]]
+; CHECK-NEXT:    [[TMP2:%.*]] = and <4 x i32> [[TMP1]], [[A:%.*]]
+; CHECK-NEXT:    ret <4 x i32> [[TMP2]]
+;
+  %1 = and <4 x i32> %a, %b
+  %2 = and <4 x i32> %a, %c
+  %3 = xor <4 x i32> %1, %2
+  ret <4 x i32> %3
+}
+
+define <4 x i32> @test_v4i32_xor_repeated_and_1(<4 x i32> %a, <4 x i32> %b, <4 x i32> %c) {
+; CHECK-LABEL: @test_v4i32_xor_repeated_and_1(
+; CHECK-NEXT:    [[TMP1:%.*]] = xor <4 x i32> [[B:%.*]], [[C:%.*]]
+; CHECK-NEXT:    [[TMP2:%.*]] = and <4 x i32> [[TMP1]], [[A:%.*]]
+; CHECK-NEXT:    ret <4 x i32> [[TMP2]]
+;
+  %1 = and <4 x i32> %a, %b
+  %2 = and <4 x i32> %c, %a
+  %3 = xor <4 x i32> %1, %2
+  ret <4 x i32> %3
+}
+
+; xor(bswap(a), c) to bswap(xor(a, bswap(c)))
+
+declare <4 x i32> @llvm.bswap.v4i32(<4 x i32>)
+
+define <4 x i32> @test_v4i32_xor_bswap_splatconst(<4 x i32> %a0) {
+; CHECK-LABEL: @test_v4i32_xor_bswap_splatconst(
+; CHECK-NEXT:    [[TMP1:%.*]] = xor <4 x i32> [[A0:%.*]], <i32 -16777216, i32 -16777216, i32 -16777216, i32 -16777216>
+; CHECK-NEXT:    [[TMP2:%.*]] = call <4 x i32> @llvm.bswap.v4i32(<4 x i32> [[TMP1]])
+; CHECK-NEXT:    ret <4 x i32> [[TMP2]]
+;
+  %1 = call <4 x i32> @llvm.bswap.v4i32(<4 x i32> %a0)
+  %2 = xor  <4 x i32> %1, <i32 255, i32 255, i32 255, i32 255>
+  ret <4 x i32> %2
+}
+
+define <4 x i32> @test_v4i32_xor_bswap_const(<4 x i32> %a0) {
+; CHECK-LABEL: @test_v4i32_xor_bswap_const(
+; CHECK-NEXT:    [[TMP1:%.*]] = call <4 x i32> @llvm.bswap.v4i32(<4 x i32> [[A0:%.*]])
+; CHECK-NEXT:    [[TMP2:%.*]] = xor <4 x i32> [[TMP1]], <i32 0, i32 -16777216, i32 2, i32 3>
+; CHECK-NEXT:    ret <4 x i32> [[TMP2]]
+;
+  %1 = call <4 x i32> @llvm.bswap.v4i32(<4 x i32> %a0)
+  %2 = xor  <4 x i32> %1, <i32 0, i32 -16777216, i32 2, i32 3>
+  ret <4 x i32> %2
+}
+
+define <4 x i32> @test_v4i32_xor_bswap_const_undef(<4 x i32> %a0) {
+; CHECK-LABEL: @test_v4i32_xor_bswap_const_undef(
+; CHECK-NEXT:    [[TMP1:%.*]] = call <4 x i32> @llvm.bswap.v4i32(<4 x i32> [[A0:%.*]])
+; CHECK-NEXT:    [[TMP2:%.*]] = xor <4 x i32> [[TMP1]], <i32 undef, i32 0, i32 2, i32 3>
+; CHECK-NEXT:    ret <4 x i32> [[TMP2]]
+;
+  %1 = call <4 x i32> @llvm.bswap.v4i32(<4 x i32> %a0)
+  %2 = xor  <4 x i32> %1, <i32 undef, i32 0, i32 2, i32 3>
+  ret <4 x i32> %2
+}
+
+; DeMorgan's Law: ~(~X & Y) --> (X | ~Y)
+
+define <4 x i32> @test_v4i32_demorgan_and(<4 x i32> %x, <4 x i32> %y) {
+; CHECK-LABEL: @test_v4i32_demorgan_and(
+; CHECK-NEXT:    [[Y_NOT:%.*]] = xor <4 x i32> [[Y:%.*]], <i32 -1, i32 -1, i32 -1, i32 -1>
+; CHECK-NEXT:    [[TMP1:%.*]] = or <4 x i32> [[Y_NOT]], [[X:%.*]]
+; CHECK-NEXT:    ret <4 x i32> [[TMP1]]
+;
+  %1 = xor <4 x i32> <i32 -1, i32 -1, i32 -1, i32 -1>, %x
+  %2 = and <4 x i32> %1, %y
+  %3 = xor <4 x i32> <i32 -1, i32 -1, i32 -1, i32 -1>, %2
+  ret <4 x i32> %3
+}
+
+; DeMorgan's Law: ~(~X | Y) --> (X & ~Y)
+
+define <4 x i32> @test_v4i32_demorgan_or(<4 x i32> %x, <4 x i32> %y) {
+; CHECK-LABEL: @test_v4i32_demorgan_or(
+; CHECK-NEXT:    [[Y_NOT:%.*]] = xor <4 x i32> [[Y:%.*]], <i32 -1, i32 -1, i32 -1, i32 -1>
+; CHECK-NEXT:    [[TMP1:%.*]] = and <4 x i32> [[Y_NOT]], [[X:%.*]]
+; CHECK-NEXT:    ret <4 x i32> [[TMP1]]
+;
+  %1 = xor <4 x i32> <i32 -1, i32 -1, i32 -1, i32 -1>, %x
+  %2 = or  <4 x i32> %1, %y
+  %3 = xor <4 x i32> <i32 -1, i32 -1, i32 -1, i32 -1>, %2
+  ret <4 x i32> %3
+}
+
+; ~(~X >>s Y) --> (X >>s Y)
+
+define <4 x i32> @test_v4i32_not_ashr_not(<4 x i32> %x, <4 x i32> %y) {
+; CHECK-LABEL: @test_v4i32_not_ashr_not(
+; CHECK-NEXT:    [[TMP1:%.*]] = ashr <4 x i32> [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    ret <4 x i32> [[TMP1]]
+;
+  %1 = xor  <4 x i32> <i32 -1, i32 -1, i32 -1, i32 -1>, %x
+  %2 = ashr <4 x i32> %1, %y
+  %3 = xor  <4 x i32> <i32 -1, i32 -1, i32 -1, i32 -1>, %2
+  ret <4 x i32> %3
+}
+
+define <4 x i32> @test_v4i32_not_ashr_not_undef(<4 x i32> %x, <4 x i32> %y) {
+; CHECK-LABEL: @test_v4i32_not_ashr_not_undef(
+; CHECK-NEXT:    [[TMP1:%.*]] = ashr <4 x i32> [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    ret <4 x i32> [[TMP1]]
+;
+  %1 = xor  <4 x i32> <i32 -1, i32 -1, i32 -1, i32 undef>, %x
+  %2 = ashr <4 x i32> %1, %y
+  %3 = xor  <4 x i32> <i32 -1, i32 -1, i32 undef, i32 -1>, %2
+  ret <4 x i32> %3
+}
+
+; ~(C >>s Y) --> ~C >>u Y (when inverting the replicated sign bits)
+
+define <4 x i32> @test_v4i32_not_ashr_negative_splatconst(<4 x i32> %a0) {
+; CHECK-LABEL: @test_v4i32_not_ashr_negative_splatconst(
+; CHECK-NEXT:    [[TMP1:%.*]] = lshr <4 x i32> <i32 2, i32 2, i32 2, i32 2>, [[A0:%.*]]
+; CHECK-NEXT:    ret <4 x i32> [[TMP1]]
+;
+  %1 = ashr <4 x i32> <i32 -3, i32 -3, i32 -3, i32 -3>, %a0
+  %2 = xor  <4 x i32> <i32 -1, i32 -1, i32 -1, i32 -1>, %1
+  ret <4 x i32> %2
+}
+
+define <4 x i32> @test_v4i32_not_ashr_negative_const(<4 x i32> %a0) {
+; CHECK-LABEL: @test_v4i32_not_ashr_negative_const(
+; CHECK-NEXT:    [[TMP1:%.*]] = lshr <4 x i32> <i32 2, i32 4, i32 6, i32 8>, [[A0:%.*]]
+; CHECK-NEXT:    ret <4 x i32> [[TMP1]]
+;
+  %1 = ashr <4 x i32> <i32 -3, i32 -5, i32 -7, i32 -9>, %a0
+  %2 = xor  <4 x i32> <i32 -1, i32 -1, i32 -1, i32 -1>, %1
+  ret <4 x i32> %2
+}
+
+define <4 x i32> @test_v4i32_not_ashr_negative_const_undef(<4 x i32> %a0) {
+; CHECK-LABEL: @test_v4i32_not_ashr_negative_const_undef(
+; CHECK-NEXT:    [[TMP1:%.*]] = lshr <4 x i32> <i32 2, i32 4, i32 undef, i32 8>, [[A0:%.*]]
+; CHECK-NEXT:    ret <4 x i32> [[TMP1]]
+;
+  %1 = ashr <4 x i32> <i32 -3, i32 -5, i32 undef, i32 -9>, %a0
+  %2 = xor  <4 x i32> <i32 -1, i32 -1, i32 -1, i32 undef>, %1
+  ret <4 x i32> %2
+}
+
+; ~(C >>u Y) --> ~C >>s Y (when inverting the replicated sign bits)
+
+define <4 x i32> @test_v4i32_not_lshr_nonnegative_splatconst(<4 x i32> %a0) {
+; CHECK-LABEL: @test_v4i32_not_lshr_nonnegative_splatconst(
+; CHECK-NEXT:    [[TMP1:%.*]] = ashr <4 x i32> <i32 -4, i32 -4, i32 -4, i32 -4>, [[A0:%.*]]
+; CHECK-NEXT:    ret <4 x i32> [[TMP1]]
+;
+  %1 = lshr <4 x i32> <i32  3, i32  3, i32  3, i32  3>, %a0
+  %2 = xor  <4 x i32> <i32 -1, i32 -1, i32 -1, i32 -1>, %1
+  ret <4 x i32> %2
+}
+
+define <4 x i32> @test_v4i32_not_lshr_nonnegative_const(<4 x i32> %a0) {
+; CHECK-LABEL: @test_v4i32_not_lshr_nonnegative_const(
+; CHECK-NEXT:    [[TMP1:%.*]] = ashr <4 x i32> <i32 -4, i32 -6, i32 -8, i32 -10>, [[A0:%.*]]
+; CHECK-NEXT:    ret <4 x i32> [[TMP1]]
+;
+  %1 = lshr <4 x i32> <i32  3, i32  5, i32  7, i32  9>, %a0
+  %2 = xor  <4 x i32> <i32 -1, i32 -1, i32 -1, i32 -1>, %1
+  ret <4 x i32> %2
+}
+
+define <4 x i32> @test_v4i32_not_lshr_nonnegative_const_undef(<4 x i32> %a0) {
+; CHECK-LABEL: @test_v4i32_not_lshr_nonnegative_const_undef(
+; CHECK-NEXT:    [[TMP1:%.*]] = ashr <4 x i32> <i32 -4, i32 -6, i32 undef, i32 -10>, [[A0:%.*]]
+; CHECK-NEXT:    ret <4 x i32> [[TMP1]]
+;
+  %1 = lshr <4 x i32> <i32  3, i32  5, i32 undef, i32  9>, %a0
+  %2 = xor  <4 x i32> <i32 -1, i32 -1, i32 -1, i32 undef>, %1
+  ret <4 x i32> %2
+}
+
+; ~(C-X) == X-C-1 == X+(-C-1)
+
+define <4 x i32> @test_v4i32_not_sub_splatconst(<4 x i32> %a0) {
+; CHECK-LABEL: @test_v4i32_not_sub_splatconst(
+; CHECK-NEXT:    [[TMP1:%.*]] = add <4 x i32> [[A0:%.*]], <i32 -4, i32 -4, i32 -4, i32 -4>
+; CHECK-NEXT:    ret <4 x i32> [[TMP1]]
+;
+  %1 = sub <4 x i32> <i32  3, i32  3, i32  3, i32  3>, %a0
+  %2 = xor <4 x i32> <i32 -1, i32 -1, i32 -1, i32 -1>, %1
+  ret <4 x i32> %2
+}
+
+define <4 x i32> @test_v4i32_not_sub_const(<4 x i32> %a0) {
+; CHECK-LABEL: @test_v4i32_not_sub_const(
+; CHECK-NEXT:    [[TMP1:%.*]] = add <4 x i32> [[A0:%.*]], <i32 -4, i32 -6, i32 0, i32 -16>
+; CHECK-NEXT:    ret <4 x i32> [[TMP1]]
+;
+  %1 = sub <4 x i32> <i32  3, i32  5, i32 -1, i32 15>, %a0
+  %2 = xor <4 x i32> <i32 -1, i32 -1, i32 -1, i32 -1>, %1
+  ret <4 x i32> %2
+}
+
+define <4 x i32> @test_v4i32_not_sub_const_undef(<4 x i32> %a0) {
+; CHECK-LABEL: @test_v4i32_not_sub_const_undef(
+; CHECK-NEXT:    [[TMP1:%.*]] = add <4 x i32> [[A0:%.*]], <i32 -4, i32 undef, i32 0, i32 -16>
+; CHECK-NEXT:    ret <4 x i32> [[TMP1]]
+;
+  %1 = sub <4 x i32> <i32  3, i32 undef, i32 -1, i32 15>, %a0
+  %2 = xor <4 x i32> <i32 -1, i32 -1, i32 -1, i32 undef>, %1
+  ret <4 x i32> %2
+}
+
+; (C - X) ^ signmask -> (C + signmask - X)
+
+define <4 x i32> @test_v4i32_xor_signmask_sub_splatconst(<4 x i32> %a0) {
+; CHECK-LABEL: @test_v4i32_xor_signmask_sub_splatconst(
+; CHECK-NEXT:    [[TMP1:%.*]] = sub <4 x i32> <i32 -2147483645, i32 -2147483645, i32 -2147483645, i32 -2147483645>, [[A0:%.*]]
+; CHECK-NEXT:    ret <4 x i32> [[TMP1]]
+;
+  %1 = sub <4 x i32> <i32  3, i32  3, i32  3, i32  3>, %a0
+  %2 = xor <4 x i32> <i32 -2147483648, i32 -2147483648, i32 -2147483648, i32 -2147483648>, %1
+  ret <4 x i32> %2
+}
+
+define <4 x i32> @test_v4i32_xor_signmask_sub_const(<4 x i32> %a0) {
+; CHECK-LABEL: @test_v4i32_xor_signmask_sub_const(
+; CHECK-NEXT:    [[TMP1:%.*]] = sub <4 x i32> <i32 3, i32 5, i32 -1, i32 15>, [[A0:%.*]]
+; CHECK-NEXT:    [[TMP2:%.*]] = xor <4 x i32> [[TMP1]], <i32 -2147483648, i32 -2147483648, i32 -2147483648, i32 -2147483648>
+; CHECK-NEXT:    ret <4 x i32> [[TMP2]]
+;
+  %1 = sub <4 x i32> <i32  3, i32 5, i32 -1, i32 15>, %a0
+  %2 = xor <4 x i32> <i32 -2147483648, i32 -2147483648, i32 -2147483648, i32 -2147483648>, %1
+  ret <4 x i32> %2
+}
+
+define <4 x i32> @test_v4i32_xor_signmask_sub_const_undef(<4 x i32> %a0) {
+; CHECK-LABEL: @test_v4i32_xor_signmask_sub_const_undef(
+; CHECK-NEXT:    [[TMP1:%.*]] = sub <4 x i32> <i32 3, i32 undef, i32 -1, i32 15>, [[A0:%.*]]
+; CHECK-NEXT:    [[TMP2:%.*]] = xor <4 x i32> [[TMP1]], <i32 -2147483648, i32 -2147483648, i32 -2147483648, i32 undef>
+; CHECK-NEXT:    ret <4 x i32> [[TMP2]]
+;
+  %1 = sub <4 x i32> <i32  3, i32 undef, i32 -1, i32 15>, %a0
+  %2 = xor <4 x i32> <i32 -2147483648, i32 -2147483648, i32 -2147483648, i32 undef>, %1
+  ret <4 x i32> %2
+}
+
+; (X + C) ^ signmask -> (X + C + signmask)
+
+define <4 x i32> @test_v4i32_xor_signmask_add_splatconst(<4 x i32> %a0) {
+; CHECK-LABEL: @test_v4i32_xor_signmask_add_splatconst(
+; CHECK-NEXT:    [[TMP1:%.*]] = add <4 x i32> [[A0:%.*]], <i32 -2147483645, i32 -2147483645, i32 -2147483645, i32 -2147483645>
+; CHECK-NEXT:    ret <4 x i32> [[TMP1]]
+;
+  %1 = add <4 x i32> <i32  3, i32  3, i32  3, i32  3>, %a0
+  %2 = xor <4 x i32> <i32 -2147483648, i32 -2147483648, i32 -2147483648, i32 -2147483648>, %1
+  ret <4 x i32> %2
+}
+
+define <4 x i32> @test_v4i32_xor_signmask_add_const(<4 x i32> %a0) {
+; CHECK-LABEL: @test_v4i32_xor_signmask_add_const(
+; CHECK-NEXT:    [[TMP1:%.*]] = add <4 x i32> [[A0:%.*]], <i32 3, i32 5, i32 -1, i32 15>
+; CHECK-NEXT:    [[TMP2:%.*]] = xor <4 x i32> [[TMP1]], <i32 -2147483648, i32 -2147483648, i32 -2147483648, i32 -2147483648>
+; CHECK-NEXT:    ret <4 x i32> [[TMP2]]
+;
+  %1 = add <4 x i32> <i32  3, i32 5, i32 -1, i32 15>, %a0
+  %2 = xor <4 x i32> <i32 -2147483648, i32 -2147483648, i32 -2147483648, i32 -2147483648>, %1
+  ret <4 x i32> %2
+}
+
+define <4 x i32> @test_v4i32_xor_signmask_add_const_undef(<4 x i32> %a0) {
+; CHECK-LABEL: @test_v4i32_xor_signmask_add_const_undef(
+; CHECK-NEXT:    [[TMP1:%.*]] = add <4 x i32> [[A0:%.*]], <i32 3, i32 undef, i32 -1, i32 15>
+; CHECK-NEXT:    [[TMP2:%.*]] = xor <4 x i32> [[TMP1]], <i32 -2147483648, i32 -2147483648, i32 -2147483648, i32 undef>
+; CHECK-NEXT:    ret <4 x i32> [[TMP2]]
+;
+  %1 = add <4 x i32> <i32  3, i32 undef, i32 -1, i32 15>, %a0
+  %2 = xor <4 x i32> <i32 -2147483648, i32 -2147483648, i32 -2147483648, i32 undef>, %1
+  ret <4 x i32> %2
+}

Added: llvm/trunk/test/Transforms/InstCombine/vector_gep1.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/vector_gep1.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/vector_gep1.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/vector_gep1.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,64 @@
+; 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-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+ at G1 = global i8 zeroinitializer
+
+define <2 x i1> @test(<2 x i8*> %a, <2 x i8*> %b) {
+; CHECK-LABEL: @test(
+; CHECK-NEXT:    [[C:%.*]] = icmp eq <2 x i8*> [[A:%.*]], [[B:%.*]]
+; CHECK-NEXT:    ret <2 x i1> [[C]]
+;
+  %c = icmp eq <2 x i8*> %a, %b
+  ret <2 x i1> %c
+}
+
+define <2 x i1> @test2(<2 x i8*> %a) {
+; CHECK-LABEL: @test2(
+; CHECK-NEXT:    ret <2 x i1> zeroinitializer
+;
+  %c = inttoptr <2 x i32> <i32 1, i32 2> to <2 x i8*>
+  %d = icmp ult <2 x i8*> %c, zeroinitializer
+  ret <2 x i1> %d
+}
+
+define <2 x i1> @test3(<2 x i8*> %a) {
+; CHECK-LABEL: @test3(
+; CHECK-NEXT:    ret <2 x i1> zeroinitializer
+;
+  %g = getelementptr i8, <2 x i8*> %a, <2 x i32> <i32 1, i32 0>
+  %B = icmp ult <2 x i8*> %g, zeroinitializer
+  ret <2 x i1> %B
+}
+
+define <1 x i1> @test4(<1 x i8*> %a) {
+; CHECK-LABEL: @test4(
+; CHECK-NEXT:    ret <1 x i1> zeroinitializer
+;
+  %g = getelementptr i8, <1 x i8*> %a, <1 x i32> <i32 1>
+  %B = icmp ult <1 x i8*> %g, zeroinitializer
+  ret <1 x i1> %B
+}
+
+define <2 x i1> @test5(<2 x i8*> %a) {
+; CHECK-LABEL: @test5(
+; CHECK-NEXT:    ret <2 x i1> zeroinitializer
+;
+  %w = getelementptr i8, <2 x i8*> %a, <2 x i32> zeroinitializer
+  %e = getelementptr i8, <2 x i8*> %w, <2 x i32> <i32 5, i32 9>
+  %g = getelementptr i8, <2 x i8*> %e, <2 x i32> <i32 1, i32 0>
+  %B = icmp ult <2 x i8*> %g, zeroinitializer
+  ret <2 x i1> %B
+}
+
+define <2 x i32*> @test7(<2 x {i32, i32}*> %a) {
+; CHECK-LABEL: @test7(
+; CHECK-NEXT:    [[W:%.*]] = getelementptr { i32, i32 }, <2 x { i32, i32 }*> [[A:%.*]], <2 x i64> <i64 5, i64 9>, <2 x i32> zeroinitializer
+; CHECK-NEXT:    ret <2 x i32*> [[W]]
+;
+  %w = getelementptr {i32, i32}, <2 x {i32, i32}*> %a, <2 x i32> <i32 5, i32 9>, <2 x i32> zeroinitializer
+  ret <2 x i32*> %w
+}
+

Added: llvm/trunk/test/Transforms/InstCombine/vector_gep2.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/vector_gep2.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/vector_gep2.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/vector_gep2.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,44 @@
+; 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-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+define <2 x i8*> @testa(<2 x i8*> %a) {
+; CHECK-LABEL: @testa(
+; CHECK-NEXT:    [[G:%.*]] = getelementptr i8, <2 x i8*> [[A:%.*]], <2 x i64> <i64 0, i64 1>
+; CHECK-NEXT:    ret <2 x i8*> [[G]]
+;
+  %g = getelementptr i8, <2 x i8*> %a, <2 x i32> <i32 0, i32 1>
+  ret <2 x i8*> %g
+}
+
+define <8 x double*> @vgep_s_v8i64(double* %a, <8 x i64>%i) {
+; CHECK-LABEL: @vgep_s_v8i64(
+; CHECK-NEXT:    [[VECTORGEP:%.*]] = getelementptr double, double* [[A:%.*]], <8 x i64> [[I:%.*]]
+; CHECK-NEXT:    ret <8 x double*> [[VECTORGEP]]
+;
+  %VectorGep = getelementptr double, double* %a, <8 x i64> %i
+  ret <8 x double*> %VectorGep
+}
+
+define <8 x double*> @vgep_s_v8i32(double* %a, <8 x i32>%i) {
+; CHECK-LABEL: @vgep_s_v8i32(
+; CHECK-NEXT:    [[TMP1:%.*]] = sext <8 x i32> [[I:%.*]] to <8 x i64>
+; CHECK-NEXT:    [[VECTORGEP:%.*]] = getelementptr double, double* [[A:%.*]], <8 x i64> [[TMP1]]
+; CHECK-NEXT:    ret <8 x double*> [[VECTORGEP]]
+;
+  %VectorGep = getelementptr double, double* %a, <8 x i32> %i
+  ret <8 x double*> %VectorGep
+}
+
+define <8 x i8*> @vgep_v8iPtr_i32(<8 x i8*> %a, i32 %i) {
+; CHECK-LABEL: @vgep_v8iPtr_i32(
+; CHECK-NEXT:    [[TMP1:%.*]] = sext i32 [[I:%.*]] to i64
+; CHECK-NEXT:    [[VECTORGEP:%.*]] = getelementptr i8, <8 x i8*> [[A:%.*]], i64 [[TMP1]]
+; CHECK-NEXT:    ret <8 x i8*> [[VECTORGEP]]
+;
+  %VectorGep = getelementptr i8, <8 x i8*> %a, i32 %i
+  ret <8 x i8*> %VectorGep
+}
+

Added: llvm/trunk/test/Transforms/InstCombine/vector_insertelt_shuffle.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/vector_insertelt_shuffle.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/vector_insertelt_shuffle.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/vector_insertelt_shuffle.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
+
+; insertelements should fold to shuffle
+define <4 x float> @foo(<4 x float> %x) {
+; CHECK-LABEL: @foo(
+; CHECK-NEXT:    [[INS2:%.*]] = shufflevector <4 x float> %x, <4 x float> <float undef, float 1.000000e+00, float 2.000000e+00, float undef>, <4 x i32> <i32 0, i32 5, i32 6, i32 3>
+; CHECK-NEXT:    ret <4 x float> [[INS2]]
+;
+  %ins1 = insertelement<4 x float> %x, float 1.0, i32 1
+  %ins2 = insertelement<4 x float> %ins1, float 2.0, i32 2
+  ret <4 x float> %ins2
+}
+
+; Insert of a constant is canonicalized ahead of insert of a variable.
+
+define <4 x float> @bar(<4 x float> %x, float %a) {
+; CHECK-LABEL: @bar(
+; CHECK-NEXT:    [[TMP1:%.*]] = insertelement <4 x float> %x, float 2.000000e+00, i32 2
+; CHECK-NEXT:    [[INS2:%.*]] = insertelement <4 x float> [[TMP1]], float %a, i32 1
+; CHECK-NEXT:    ret <4 x float> [[INS2]]
+;
+  %ins1 = insertelement<4 x float> %x, float %a, i32 1
+  %ins2 = insertelement<4 x float> %ins1, float 2.0, i32 2
+  ret <4 x float> %ins2
+}
+
+define <4 x float> @baz(<4 x float> %x, i32 %a) {
+; CHECK-LABEL: @baz(
+; CHECK-NEXT:    [[INS1:%.*]] = insertelement <4 x float> %x, float 1.000000e+00, i32 1
+; CHECK-NEXT:    [[INS2:%.*]] = insertelement <4 x float> [[INS1]], float 2.000000e+00, i32 %a
+; CHECK-NEXT:    ret <4 x float> [[INS2]]
+;
+  %ins1 = insertelement<4 x float> %x, float 1.0, i32 1
+  %ins2 = insertelement<4 x float> %ins1, float 2.0, i32 %a
+  ret <4 x float> %ins2
+}
+
+; insertelements should fold to shuffle
+define <4 x float> @bazz(<4 x float> %x, i32 %a) {
+; CHECK-LABEL: @bazz(
+; CHECK-NEXT:    [[INS1:%.*]] = insertelement <4 x float> %x, float 1.000000e+00, i32 3
+; CHECK-NEXT:    [[INS2:%.*]] = insertelement <4 x float> [[INS1]], float 5.000000e+00, i32 %a
+; CHECK-NEXT:    [[INS5:%.*]] = shufflevector <4 x float> [[INS2]], <4 x float> <float undef, float 1.000000e+00, float 2.000000e+00, float undef>, <4 x i32> <i32 0, i32 5, i32 6, i32 3>
+; CHECK-NEXT:    [[INS6:%.*]] = insertelement <4 x float> [[INS5]], float 7.000000e+00, i32 %a
+; CHECK-NEXT:    ret <4 x float> [[INS6]]
+;
+  %ins1 = insertelement<4 x float> %x, float 1.0, i32 3
+  %ins2 = insertelement<4 x float> %ins1, float 5.0, i32 %a
+  %ins3 = insertelement<4 x float> %ins2, float 3.0, i32 2
+  %ins4 = insertelement<4 x float> %ins3, float 1.0, i32 1
+  %ins5 = insertelement<4 x float> %ins4, float 2.0, i32 2
+  %ins6 = insertelement<4 x float> %ins5, float 7.0, i32 %a
+  ret <4 x float> %ins6
+}
+
+; Out of bounds index folds to undef
+define <4 x float> @bazzz(<4 x float> %x) {
+; CHECK-LABEL: @bazzz(
+; CHECK-NEXT:   ret <4 x float> <float undef, float undef, float 2.000000e+00, float undef>
+;
+  %ins1 = insertelement<4 x float> %x, float 1.0, i32 5
+  %ins2 = insertelement<4 x float> %ins1, float 2.0, i32 2
+  ret <4 x float> %ins2
+}
+
+define <4 x float> @bazzzz(<4 x float> %x) {
+; CHECK-LABEL: @bazzzz(
+; CHECK-NEXT:   ret <4 x float> <float undef, float undef, float 2.000000e+00, float undef>
+;
+  %ins1 = insertelement<4 x float> %x, float 1.0, i32 undef
+  %ins2 = insertelement<4 x float> %ins1, float 2.0, i32 2
+  ret <4 x float> %ins2
+}
+
+define <4 x float> @bazzzzz() {
+; CHECK-LABEL: @bazzzzz(
+; CHECK-NEXT:    ret <4 x float> <float 1.000000e+00, float 5.000000e+00, float 1.000000e+01, float 4.000000e+00>
+;
+  %ins1 = insertelement <4 x float> insertelement (<4 x float> <float 1.0, float 2.0, float 3.0, float undef>, float 4.0, i32 3), float 5.0, i32 1
+  %ins2 = insertelement<4 x float> %ins1, float 10.0, i32 2
+  ret <4 x float> %ins2
+}
+
+define <4 x float> @bazzzzzz(<4 x float> %x, i32 %a) {
+; CHECK-LABEL: @bazzzzzz(
+; CHECK-NEXT:    ret <4 x float> <float undef, float 5.000000e+00, float undef, float 4.000000e+00>
+;
+  %ins1 = insertelement <4 x float> insertelement (<4 x float> shufflevector (<4 x float> undef, <4 x float> <float 1.0, float 2.0, float 3.0, float 4.0> , <4 x i32> <i32 0, i32 5, i32 undef, i32 6> ), float 4.0, i32 3), float 5.0, i32 1
+  ret <4 x float> %ins1
+}
+
+

Added: llvm/trunk/test/Transforms/InstCombine/volatile_store.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/volatile_store.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/volatile_store.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/volatile_store.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,22 @@
+; NOTE: Assertions have been autogenerated by update_test_checks.py
+; RUN: opt < %s -instcombine -S | FileCheck %s
+
+ at x = weak global i32 0
+
+define void @self_assign_1() {
+; CHECK-LABEL: @self_assign_1(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[TMP:%.*]] = load volatile i32, i32* @x, align 4
+; CHECK-NEXT:    store volatile i32 [[TMP]], i32* @x, align 4
+; CHECK-NEXT:    br label %return
+; CHECK:       return:
+; CHECK-NEXT:    ret void
+;
+entry:
+  %tmp = load volatile i32, i32* @x
+  store volatile i32 %tmp, i32* @x
+  br label %return
+
+return:
+  ret void
+}

Added: llvm/trunk/test/Transforms/InstCombine/wcslen-1.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/wcslen-1.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/wcslen-1.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/wcslen-1.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,222 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; Test that the wcslen library call simplifier works correctly.
+;
+; RUN: opt < %s -instcombine -S | FileCheck %s
+
+target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
+
+declare i64 @wcslen(i32*)
+
+!0 = !{i32 1, !"wchar_size", i32 4}
+!llvm.module.flags = !{!0}
+
+ at hello = constant [6 x i32] [i32 104, i32 101, i32 108, i32 108, i32 111, i32 0]
+ at longer = constant [7 x i32] [i32 108, i32 111, i32 110, i32 103, i32 101, i32 114, i32 0]
+ at null = constant [1 x i32] zeroinitializer
+ at null_hello = constant [7 x i32] [i32 0, i32 104, i32 101, i32 108, i32 108, i32 111, i32 0]
+ at nullstring = constant i32 0
+ at a = common global [32 x i32] zeroinitializer, align 1
+ at null_hello_mid = constant [13 x i32] [i32 104, i32 101, i32 108, i32 108, i32 111, i32 32, i32 119, i32 111, i32 114, i32 0, i32 108, i32 100, i32 0]
+
+define i64 @test_simplify1() {
+; CHECK-LABEL: @test_simplify1(
+; CHECK-NEXT:    ret i64 5
+;
+  %hello_p = getelementptr [6 x i32], [6 x i32]* @hello, i64 0, i64 0
+  %hello_l = call i64 @wcslen(i32* %hello_p)
+  ret i64 %hello_l
+}
+
+define i64 @test_simplify2() {
+; CHECK-LABEL: @test_simplify2(
+; CHECK-NEXT:    ret i64 0
+;
+  %null_p = getelementptr [1 x i32], [1 x i32]* @null, i64 0, i64 0
+  %null_l = call i64 @wcslen(i32* %null_p)
+  ret i64 %null_l
+}
+
+define i64 @test_simplify3() {
+; CHECK-LABEL: @test_simplify3(
+; CHECK-NEXT:    ret i64 0
+;
+  %null_hello_p = getelementptr [7 x i32], [7 x i32]* @null_hello, i64 0, i64 0
+  %null_hello_l = call i64 @wcslen(i32* %null_hello_p)
+  ret i64 %null_hello_l
+}
+
+define i64 @test_simplify4() {
+; CHECK-LABEL: @test_simplify4(
+; CHECK-NEXT:    ret i64 0
+;
+  %len = tail call i64 @wcslen(i32* @nullstring) nounwind
+  ret i64 %len
+}
+
+; Check wcslen(x) == 0 --> *x == 0.
+
+define i1 @test_simplify5() {
+; CHECK-LABEL: @test_simplify5(
+; CHECK-NEXT:    ret i1 false
+;
+  %hello_p = getelementptr [6 x i32], [6 x i32]* @hello, i64 0, i64 0
+  %hello_l = call i64 @wcslen(i32* %hello_p)
+  %eq_hello = icmp eq i64 %hello_l, 0
+  ret i1 %eq_hello
+}
+
+define i1 @test_simplify6(i32* %str_p) {
+; CHECK-LABEL: @test_simplify6(
+; CHECK-NEXT:    [[STRLENFIRST:%.*]] = load i32, i32* [[STR_P:%.*]], align 4
+; CHECK-NEXT:    [[EQ_NULL:%.*]] = icmp eq i32 [[STRLENFIRST]], 0
+; CHECK-NEXT:    ret i1 [[EQ_NULL]]
+;
+  %str_l = call i64 @wcslen(i32* %str_p)
+  %eq_null = icmp eq i64 %str_l, 0
+  ret i1 %eq_null
+}
+
+; Check wcslen(x) != 0 --> *x != 0.
+
+define i1 @test_simplify7() {
+; CHECK-LABEL: @test_simplify7(
+; CHECK-NEXT:    ret i1 true
+;
+  %hello_p = getelementptr [6 x i32], [6 x i32]* @hello, i64 0, i64 0
+  %hello_l = call i64 @wcslen(i32* %hello_p)
+  %ne_hello = icmp ne i64 %hello_l, 0
+  ret i1 %ne_hello
+}
+
+define i1 @test_simplify8(i32* %str_p) {
+; CHECK-LABEL: @test_simplify8(
+; CHECK-NEXT:    [[STRLENFIRST:%.*]] = load i32, i32* [[STR_P:%.*]], align 4
+; CHECK-NEXT:    [[NE_NULL:%.*]] = icmp ne i32 [[STRLENFIRST]], 0
+; CHECK-NEXT:    ret i1 [[NE_NULL]]
+;
+  %str_l = call i64 @wcslen(i32* %str_p)
+  %ne_null = icmp ne i64 %str_l, 0
+  ret i1 %ne_null
+}
+
+define i64 @test_simplify9(i1 %x) {
+; CHECK-LABEL: @test_simplify9(
+; CHECK-NEXT:    [[TMP1:%.*]] = select i1 [[X:%.*]], i64 5, i64 6
+; CHECK-NEXT:    ret i64 [[TMP1]]
+;
+  %hello = getelementptr [6 x i32], [6 x i32]* @hello, i64 0, i64 0
+  %longer = getelementptr [7 x i32], [7 x i32]* @longer, i64 0, i64 0
+  %s = select i1 %x, i32* %hello, i32* %longer
+  %l = call i64 @wcslen(i32* %s)
+  ret i64 %l
+}
+
+; Check the case that should be simplified to a sub instruction.
+; wcslen(@hello + x) --> 5 - x
+
+define i64 @test_simplify10(i32 %x) {
+; CHECK-LABEL: @test_simplify10(
+; CHECK-NEXT:    [[TMP1:%.*]] = sext i32 [[X:%.*]] to i64
+; CHECK-NEXT:    [[TMP2:%.*]] = sub nsw i64 5, [[TMP1]]
+; CHECK-NEXT:    ret i64 [[TMP2]]
+;
+  %hello_p = getelementptr inbounds [6 x i32], [6 x i32]* @hello, i32 0, i32 %x
+  %hello_l = call i64 @wcslen(i32* %hello_p)
+  ret i64 %hello_l
+}
+
+; wcslen(@null_hello_mid + (x & 7)) --> 9 - (x & 7)
+
+define i64 @test_simplify11(i32 %x) {
+; CHECK-LABEL: @test_simplify11(
+; CHECK-NEXT:    [[AND:%.*]] = and i32 [[X:%.*]], 7
+; CHECK-NEXT:    [[NARROW:%.*]] = sub nuw nsw i32 9, [[AND]]
+; CHECK-NEXT:    [[TMP1:%.*]] = zext i32 [[NARROW]] to i64
+; CHECK-NEXT:    ret i64 [[TMP1]]
+;
+  %and = and i32 %x, 7
+  %hello_p = getelementptr inbounds [13 x i32], [13 x i32]* @null_hello_mid, i32 0, i32 %and
+  %hello_l = call i64 @wcslen(i32* %hello_p)
+  ret i64 %hello_l
+}
+
+; Check cases that shouldn't be simplified.
+
+define i64 @test_no_simplify1() {
+; CHECK-LABEL: @test_no_simplify1(
+; CHECK-NEXT:    [[A_L:%.*]] = call i64 @wcslen(i32* getelementptr inbounds ([32 x i32], [32 x i32]* @a, i64 0, i64 0))
+; CHECK-NEXT:    ret i64 [[A_L]]
+;
+  %a_p = getelementptr [32 x i32], [32 x i32]* @a, i64 0, i64 0
+  %a_l = call i64 @wcslen(i32* %a_p)
+  ret i64 %a_l
+}
+
+; wcslen(@null_hello + x) should not be simplified to a sub instruction.
+
+define i64 @test_no_simplify2(i32 %x) {
+; CHECK-LABEL: @test_no_simplify2(
+; CHECK-NEXT:    [[TMP1:%.*]] = sext i32 [[X:%.*]] to i64
+; CHECK-NEXT:    [[HELLO_P:%.*]] = getelementptr inbounds [7 x i32], [7 x i32]* @null_hello, i64 0, i64 [[TMP1]]
+; CHECK-NEXT:    [[HELLO_L:%.*]] = call i64 @wcslen(i32* nonnull [[HELLO_P]])
+; CHECK-NEXT:    ret i64 [[HELLO_L]]
+;
+  %hello_p = getelementptr inbounds [7 x i32], [7 x i32]* @null_hello, i32 0, i32 %x
+  %hello_l = call i64 @wcslen(i32* %hello_p)
+  ret i64 %hello_l
+}
+
+define i64 @test_no_simplify2_no_null_opt(i32 %x) #0 {
+; CHECK-LABEL: @test_no_simplify2_no_null_opt(
+; CHECK-NEXT:    [[TMP1:%.*]] = sext i32 [[X:%.*]] to i64
+; CHECK-NEXT:    [[HELLO_P:%.*]] = getelementptr inbounds [7 x i32], [7 x i32]* @null_hello, i64 0, i64 [[TMP1]]
+; CHECK-NEXT:    [[HELLO_L:%.*]] = call i64 @wcslen(i32* [[HELLO_P]])
+; CHECK-NEXT:    ret i64 [[HELLO_L]]
+;
+  %hello_p = getelementptr inbounds [7 x i32], [7 x i32]* @null_hello, i32 0, i32 %x
+  %hello_l = call i64 @wcslen(i32* %hello_p)
+  ret i64 %hello_l
+}
+
+; wcslen(@null_hello_mid + (x & 15)) should not be simplified to a sub instruction.
+
+define i64 @test_no_simplify3(i32 %x) {
+; CHECK-LABEL: @test_no_simplify3(
+; CHECK-NEXT:    [[AND:%.*]] = and i32 [[X:%.*]], 15
+; CHECK-NEXT:    [[TMP1:%.*]] = zext i32 [[AND]] to i64
+; CHECK-NEXT:    [[HELLO_P:%.*]] = getelementptr inbounds [13 x i32], [13 x i32]* @null_hello_mid, i64 0, i64 [[TMP1]]
+; CHECK-NEXT:    [[HELLO_L:%.*]] = call i64 @wcslen(i32* nonnull [[HELLO_P]])
+; CHECK-NEXT:    ret i64 [[HELLO_L]]
+;
+  %and = and i32 %x, 15
+  %hello_p = getelementptr inbounds [13 x i32], [13 x i32]* @null_hello_mid, i32 0, i32 %and
+  %hello_l = call i64 @wcslen(i32* %hello_p)
+  ret i64 %hello_l
+}
+
+define i64 @test_no_simplify3_no_null_opt(i32 %x) #0 {
+; CHECK-LABEL: @test_no_simplify3_no_null_opt(
+; CHECK-NEXT:    [[AND:%.*]] = and i32 [[X:%.*]], 15
+; CHECK-NEXT:    [[TMP1:%.*]] = zext i32 [[AND]] to i64
+; CHECK-NEXT:    [[HELLO_P:%.*]] = getelementptr inbounds [13 x i32], [13 x i32]* @null_hello_mid, i64 0, i64 [[TMP1]]
+; CHECK-NEXT:    [[HELLO_L:%.*]] = call i64 @wcslen(i32* [[HELLO_P]])
+; CHECK-NEXT:    ret i64 [[HELLO_L]]
+;
+  %and = and i32 %x, 15
+  %hello_p = getelementptr inbounds [13 x i32], [13 x i32]* @null_hello_mid, i32 0, i32 %and
+  %hello_l = call i64 @wcslen(i32* %hello_p)
+  ret i64 %hello_l
+}
+
+ at str16 = constant [1 x i16] [i16 0]
+
+define i64 @test_no_simplify4() {
+; CHECK-LABEL: @test_no_simplify4(
+; CHECK-NEXT:    [[L:%.*]] = call i64 @wcslen(i32* bitcast ([1 x i16]* @str16 to i32*))
+; CHECK-NEXT:    ret i64 [[L]]
+;
+  %l = call i64 @wcslen(i32* bitcast ([1 x i16]* @str16 to i32*))
+  ret i64 %l
+}
+
+attributes #0 = { "null-pointer-is-valid"="true" }

Added: llvm/trunk/test/Transforms/InstCombine/wcslen-2.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/wcslen-2.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/wcslen-2.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/wcslen-2.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,21 @@
+; Test that the wcslen library call simplifier works correctly.
+;
+; RUN: opt < %s -instcombine -S | FileCheck %s
+
+target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
+
+!0 = !{i32 1, !"wchar_size", i32 4}
+!llvm.module.flags = !{!0}
+
+ at hello = constant [6 x i32] [i32 104, i32 101, i32 108, i32 108, i32 111, i32 0]
+
+declare i64 @wcslen(i32*, i32)
+
+define i64 @test_no_simplify1() {
+; CHECK-LABEL: @test_no_simplify1(
+  %hello_p = getelementptr [6 x i32], [6 x i32]* @hello, i64 0, i64 0
+  %hello_l = call i64 @wcslen(i32* %hello_p, i32 187)
+; CHECK-NEXT: %hello_l = call i64 @wcslen
+  ret i64 %hello_l
+; CHECK-NEXT: ret i64 %hello_l
+}

Added: llvm/trunk/test/Transforms/InstCombine/wcslen-3.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/wcslen-3.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/wcslen-3.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/wcslen-3.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,197 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; Test that the wcslen library call simplifier works correctly.
+;
+; RUN: opt < %s -instcombine -S | FileCheck %s
+
+; Test behavior for wchar_size==2
+!llvm.module.flags = !{!0}
+!0 = !{i32 1, !"wchar_size", i32 2}
+
+target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
+
+declare i64 @wcslen(i16*)
+
+ at hello = constant [6 x i16] [i16 104, i16 101, i16 108, i16 108, i16 111, i16 0]
+ at longer = constant [7 x i16] [i16 108, i16 111, i16 110, i16 103, i16 101, i16 114, i16 0]
+ at null = constant [1 x i16] zeroinitializer
+ at null_hello = constant [7 x i16] [i16 0, i16 104, i16 101, i16 108, i16 108, i16 111, i16 0]
+ at nullstring = constant i16 0
+ at a = common global [32 x i16] zeroinitializer, align 1
+ at null_hello_mid = constant [13 x i16] [i16 104, i16 101, i16 108, i16 108, i16 111, i16 32, i16 119, i16 111, i16 114, i16 0, i16 108, i16 100, i16 0]
+
+define i64 @test_simplify1() {
+; CHECK-LABEL: @test_simplify1(
+; CHECK-NEXT:    ret i64 5
+;
+  %hello_p = getelementptr [6 x i16], [6 x i16]* @hello, i64 0, i64 0
+  %hello_l = call i64 @wcslen(i16* %hello_p)
+  ret i64 %hello_l
+}
+
+define i64 @test_simplify2() {
+; CHECK-LABEL: @test_simplify2(
+; CHECK-NEXT:    ret i64 0
+;
+  %null_p = getelementptr [1 x i16], [1 x i16]* @null, i64 0, i64 0
+  %null_l = call i64 @wcslen(i16* %null_p)
+  ret i64 %null_l
+}
+
+define i64 @test_simplify3() {
+; CHECK-LABEL: @test_simplify3(
+; CHECK-NEXT:    ret i64 0
+;
+  %null_hello_p = getelementptr [7 x i16], [7 x i16]* @null_hello, i64 0, i64 0
+  %null_hello_l = call i64 @wcslen(i16* %null_hello_p)
+  ret i64 %null_hello_l
+}
+
+define i64 @test_simplify4() {
+; CHECK-LABEL: @test_simplify4(
+; CHECK-NEXT:    ret i64 0
+;
+  %len = tail call i64 @wcslen(i16* @nullstring) nounwind
+  ret i64 %len
+}
+
+; Check wcslen(x) == 0 --> *x == 0.
+
+define i1 @test_simplify5() {
+; CHECK-LABEL: @test_simplify5(
+; CHECK-NEXT:    ret i1 false
+;
+  %hello_p = getelementptr [6 x i16], [6 x i16]* @hello, i64 0, i64 0
+  %hello_l = call i64 @wcslen(i16* %hello_p)
+  %eq_hello = icmp eq i64 %hello_l, 0
+  ret i1 %eq_hello
+}
+
+define i1 @test_simplify6(i16* %str_p) {
+; CHECK-LABEL: @test_simplify6(
+; CHECK-NEXT:    [[STRLENFIRST:%.*]] = load i16, i16* [[STR_P:%.*]], align 2
+; CHECK-NEXT:    [[EQ_NULL:%.*]] = icmp eq i16 [[STRLENFIRST]], 0
+; CHECK-NEXT:    ret i1 [[EQ_NULL]]
+;
+  %str_l = call i64 @wcslen(i16* %str_p)
+  %eq_null = icmp eq i64 %str_l, 0
+  ret i1 %eq_null
+}
+
+; Check wcslen(x) != 0 --> *x != 0.
+
+define i1 @test_simplify7() {
+; CHECK-LABEL: @test_simplify7(
+; CHECK-NEXT:    ret i1 true
+;
+  %hello_p = getelementptr [6 x i16], [6 x i16]* @hello, i64 0, i64 0
+  %hello_l = call i64 @wcslen(i16* %hello_p)
+  %ne_hello = icmp ne i64 %hello_l, 0
+  ret i1 %ne_hello
+}
+
+define i1 @test_simplify8(i16* %str_p) {
+; CHECK-LABEL: @test_simplify8(
+; CHECK-NEXT:    [[STRLENFIRST:%.*]] = load i16, i16* [[STR_P:%.*]], align 2
+; CHECK-NEXT:    [[NE_NULL:%.*]] = icmp ne i16 [[STRLENFIRST]], 0
+; CHECK-NEXT:    ret i1 [[NE_NULL]]
+;
+  %str_l = call i64 @wcslen(i16* %str_p)
+  %ne_null = icmp ne i64 %str_l, 0
+  ret i1 %ne_null
+}
+
+define i64 @test_simplify9(i1 %x) {
+; CHECK-LABEL: @test_simplify9(
+; CHECK-NEXT:    [[TMP1:%.*]] = select i1 [[X:%.*]], i64 5, i64 6
+; CHECK-NEXT:    ret i64 [[TMP1]]
+;
+  %hello = getelementptr [6 x i16], [6 x i16]* @hello, i64 0, i64 0
+  %longer = getelementptr [7 x i16], [7 x i16]* @longer, i64 0, i64 0
+  %s = select i1 %x, i16* %hello, i16* %longer
+  %l = call i64 @wcslen(i16* %s)
+  ret i64 %l
+}
+
+; Check the case that should be simplified to a sub instruction.
+; wcslen(@hello + x) --> 5 - x
+
+define i64 @test_simplify10(i16 %x) {
+; CHECK-LABEL: @test_simplify10(
+; CHECK-NEXT:    [[TMP1:%.*]] = sext i16 [[X:%.*]] to i64
+; CHECK-NEXT:    [[TMP2:%.*]] = sub nsw i64 5, [[TMP1]]
+; CHECK-NEXT:    ret i64 [[TMP2]]
+;
+  %hello_p = getelementptr inbounds [6 x i16], [6 x i16]* @hello, i16 0, i16 %x
+  %hello_l = call i64 @wcslen(i16* %hello_p)
+  ret i64 %hello_l
+}
+
+; wcslen(@null_hello_mid + (x & 7)) --> 9 - (x & 7)
+
+define i64 @test_simplify11(i16 %x) {
+; CHECK-LABEL: @test_simplify11(
+; CHECK-NEXT:    [[AND:%.*]] = and i16 [[X:%.*]], 7
+; CHECK-NEXT:    [[NARROW:%.*]] = sub nuw nsw i16 9, [[AND]]
+; CHECK-NEXT:    [[TMP1:%.*]] = zext i16 [[NARROW]] to i64
+; CHECK-NEXT:    ret i64 [[TMP1]]
+;
+  %and = and i16 %x, 7
+  %hello_p = getelementptr inbounds [13 x i16], [13 x i16]* @null_hello_mid, i16 0, i16 %and
+  %hello_l = call i64 @wcslen(i16* %hello_p)
+  ret i64 %hello_l
+}
+
+; Check cases that shouldn't be simplified.
+
+define i64 @test_no_simplify1() {
+; CHECK-LABEL: @test_no_simplify1(
+; CHECK-NEXT:    [[A_L:%.*]] = call i64 @wcslen(i16* getelementptr inbounds ([32 x i16], [32 x i16]* @a, i64 0, i64 0))
+; CHECK-NEXT:    ret i64 [[A_L]]
+;
+  %a_p = getelementptr [32 x i16], [32 x i16]* @a, i64 0, i64 0
+  %a_l = call i64 @wcslen(i16* %a_p)
+  ret i64 %a_l
+}
+
+; wcslen(@null_hello + x) should not be simplified to a sub instruction.
+
+define i64 @test_no_simplify2(i16 %x) {
+; CHECK-LABEL: @test_no_simplify2(
+; CHECK-NEXT:    [[TMP1:%.*]] = sext i16 [[X:%.*]] to i64
+; CHECK-NEXT:    [[HELLO_P:%.*]] = getelementptr inbounds [7 x i16], [7 x i16]* @null_hello, i64 0, i64 [[TMP1]]
+; CHECK-NEXT:    [[HELLO_L:%.*]] = call i64 @wcslen(i16* nonnull [[HELLO_P]])
+; CHECK-NEXT:    ret i64 [[HELLO_L]]
+;
+  %hello_p = getelementptr inbounds [7 x i16], [7 x i16]* @null_hello, i16 0, i16 %x
+  %hello_l = call i64 @wcslen(i16* %hello_p)
+  ret i64 %hello_l
+}
+
+; wcslen(@null_hello_mid + (x & 15)) should not be simplified to a sub instruction.
+
+define i64 @test_no_simplify3(i16 %x) {
+; CHECK-LABEL: @test_no_simplify3(
+; CHECK-NEXT:    [[AND:%.*]] = and i16 [[X:%.*]], 15
+; CHECK-NEXT:    [[TMP1:%.*]] = zext i16 [[AND]] to i64
+; CHECK-NEXT:    [[HELLO_P:%.*]] = getelementptr inbounds [13 x i16], [13 x i16]* @null_hello_mid, i64 0, i64 [[TMP1]]
+; CHECK-NEXT:    [[HELLO_L:%.*]] = call i64 @wcslen(i16* nonnull [[HELLO_P]])
+; CHECK-NEXT:    ret i64 [[HELLO_L]]
+;
+  %and = and i16 %x, 15
+  %hello_p = getelementptr inbounds [13 x i16], [13 x i16]* @null_hello_mid, i16 0, i16 %and
+  %hello_l = call i64 @wcslen(i16* %hello_p)
+  ret i64 %hello_l
+}
+
+ at str32 = constant [1 x i32] [i32 0]
+
+; This could in principle be simplified, but the current implementation bails on
+; type mismatches.
+define i64 @test_no_simplify4() {
+; CHECK-LABEL: @test_no_simplify4(
+; CHECK-NEXT:    [[L:%.*]] = call i64 @wcslen(i16* bitcast ([1 x i32]* @str32 to i16*))
+; CHECK-NEXT:    ret i64 [[L]]
+;
+  %l = call i64 @wcslen(i16* bitcast ([1 x i32]* @str32 to i16*))
+  ret i64 %l
+}

Added: llvm/trunk/test/Transforms/InstCombine/wcslen-4.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/wcslen-4.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/wcslen-4.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/wcslen-4.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,20 @@
+; Test that the wcslen library call simplifier works correctly.
+;
+; RUN: opt < %s -instcombine -S | FileCheck %s
+
+target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
+
+; Without the wchar_size metadata we should see no optimization happening.
+
+ at hello = constant [6 x i32] [i32 104, i32 101, i32 108, i32 108, i32 111, i32 0]
+
+declare i64 @wcslen(i32*)
+
+define i64 @test_no_simplify1() {
+; CHECK-LABEL: @test_no_simplify1(
+; CHECK-NEXT: %hello_l = call i64 @wcslen(i32* getelementptr inbounds ([6 x i32], [6 x i32]* @hello, i64 0, i64 0))
+; CHECK-NEXT: ret i64 %hello_l
+  %hello_p = getelementptr [6 x i32], [6 x i32]* @hello, i64 0, i64 0
+  %hello_l = call i64 @wcslen(i32* %hello_p)
+  ret i64 %hello_l
+}

Added: llvm/trunk/test/Transforms/InstCombine/weak-symbols.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/weak-symbols.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/weak-symbols.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/weak-symbols.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,33 @@
+; PR4738 - Test that the library call simplifier doesn't assume anything about
+; weak symbols.
+;
+; RUN: opt < %s -instcombine -S | FileCheck %s
+
+ at real_init = weak_odr constant [2 x i8] c"y\00"
+ at fake_init = weak constant [2 x i8] c"y\00"
+ at .str = private constant [2 x i8] c"y\00"
+
+define i32 @foo() nounwind {
+; CHECK-LABEL: define i32 @foo(
+; CHECK: call i32 @strcmp
+; CHECK: ret i32 %temp1
+
+entry:
+  %str1 = getelementptr inbounds [2 x i8], [2 x i8]* @fake_init, i64 0, i64 0
+  %str2 = getelementptr inbounds [2 x i8], [2 x i8]* @.str, i64 0, i64 0
+  %temp1 = call i32 @strcmp(i8* %str1, i8* %str2) nounwind readonly
+  ret i32 %temp1
+}
+
+define i32 @bar() nounwind {
+; CHECK-LABEL: define i32 @bar(
+; CHECK: ret i32 0
+
+entry:
+  %str1 = getelementptr inbounds [2 x i8], [2 x i8]* @real_init, i64 0, i64 0
+  %str2 = getelementptr inbounds [2 x i8], [2 x i8]* @.str, i64 0, i64 0
+  %temp1 = call i32 @strcmp(i8* %str1, i8* %str2) nounwind readonly
+  ret i32 %temp1
+}
+
+declare i32 @strcmp(i8*, i8*) nounwind readonly

Added: llvm/trunk/test/Transforms/InstCombine/win-math.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/win-math.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/win-math.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/win-math.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,335 @@
+; RUN: opt < %s -O2 -S -mtriple=i386-pc-windows-msvc18   | FileCheck %s --check-prefixes=CHECK,MSVCXX,MSVC32
+; RUN: opt < %s -O2 -S -mtriple=i386-pc-windows-msvc     | FileCheck %s --check-prefixes=CHECK,MSVC19,MSVC51
+; RUN: opt < %s -O2 -S -mtriple=x86_64-pc-windows-msvc17 | FileCheck %s --check-prefixes=CHECK,MSVCXX,MSVC64
+; RUN: opt < %s -O2 -S -mtriple=x86_64-pc-win32          | FileCheck %s --check-prefixes=CHECK,MSVC19,MSVC83
+; RUN: opt < %s -O2 -S -mtriple=i386-pc-mingw32          | FileCheck %s --check-prefixes=CHECK,MINGW32
+; RUN: opt < %s -O2 -S -mtriple=x86_64-pc-mingw32        | FileCheck %s --check-prefixes=CHECK,MINGW64
+
+; x86 win32 msvcrt does not provide entry points for single-precision libm.
+; x86-64 win32 msvcrt does, but with exceptions
+; msvcrt does not provide all of C99 math, but mingw32 does.
+
+declare double @acos(double %x)
+define float @float_acos(float %x) nounwind readnone {
+; CHECK-LABEL: @float_acos(
+; MSVCXX-NOT: float @acosf
+; MSVCXX: double @acos
+; MSVC19-NOT: float @acosf
+; MSVC19: double @acos
+    %1 = fpext float %x to double
+    %2 = call double @acos(double %1)
+    %3 = fptrunc double %2 to float
+    ret float %3
+}
+
+declare double @asin(double %x)
+define float @float_asin(float %x) nounwind readnone {
+; CHECK-LABEL: @float_asin(
+; MSVCXX-NOT: float @asinf
+; MSVCXX: double @asin
+; MSVC19-NOT: float @asinf
+; MSVC19: double @asin
+    %1 = fpext float %x to double
+    %2 = call double @asin(double %1)
+    %3 = fptrunc double %2 to float
+    ret float %3
+}
+
+declare double @atan(double %x)
+define float @float_atan(float %x) nounwind readnone {
+; CHECK-LABEL: @float_atan(
+; MSVCXX-NOT: float @atanf
+; MSVCXX: double @atan
+; MSVC19-NOT: float @atanf
+; MSVC19: double @atan
+    %1 = fpext float %x to double
+    %2 = call double @atan(double %1)
+    %3 = fptrunc double %2 to float
+    ret float %3
+}
+
+declare double @atan2(double %x, double %y)
+define float @float_atan2(float %x, float %y) nounwind readnone {
+; CHECK-LABEL: @float_atan2(
+; MSVCXX-NOT: float @atan2f
+; MSVCXX: double @atan2
+; MSVC19-NOT: float @atan2f
+; MSVC19: double @atan2
+    %1 = fpext float %x to double
+    %2 = fpext float %y to double
+    %3 = call double @atan2(double %1, double %2)
+    %4 = fptrunc double %3 to float
+    ret float %4
+}
+
+declare double @ceil(double %x)
+define float @float_ceil(float %x) nounwind readnone {
+; CHECK-LABEL: @float_ceil(
+; MSVCXX-NOT: float @ceilf
+; MSVCXX: float @llvm.ceil.f32
+; MSVC19-NOT: double @ceil
+; MSVC19: float @llvm.ceil.f32
+; MINGW32-NOT: double @ceil
+; MINGW32: float @llvm.ceil.f32
+; MINGW64-NOT: double @ceil
+; MINGW64: float @llvm.ceil.f32
+    %1 = fpext float %x to double
+    %2 = call double @ceil(double %1)
+    %3 = fptrunc double %2 to float
+    ret float %3
+}
+
+declare double @_copysign(double %x)
+define float @float_copysign(float %x) nounwind readnone {
+; CHECK-LABEL: @float_copysign(
+; MSVCXX-NOT: float @_copysignf
+; MSVCXX: double @_copysign
+; MSVC19-NOT: float @_copysignf
+; MSVC19: double @_copysign
+    %1 = fpext float %x to double
+    %2 = call double @_copysign(double %1)
+    %3 = fptrunc double %2 to float
+    ret float %3
+}
+
+declare double @cos(double %x)
+define float @float_cos(float %x) nounwind readnone {
+; CHECK-LABEL: @float_cos(
+; MSVCXX-NOT: float @cosf
+; MSVCXX: double @cos
+; MSVC19-NOT: float @cosf
+; MSVC19: double @cos
+    %1 = fpext float %x to double
+    %2 = call double @cos(double %1)
+    %3 = fptrunc double %2 to float
+    ret float %3
+}
+
+declare double @cosh(double %x)
+define float @float_cosh(float %x) nounwind readnone {
+; CHECK-LABEL: @float_cosh(
+; MSVCXX-NOT: float @coshf
+; MSVCXX: double @cosh
+; MSVC19-NOT: float @coshf
+; MSVC19: double @cosh
+    %1 = fpext float %x to double
+    %2 = call double @cosh(double %1)
+    %3 = fptrunc double %2 to float
+    ret float %3
+}
+
+declare double @exp(double %x, double %y)
+define float @float_exp(float %x, float %y) nounwind readnone {
+; CHECK-LABEL: @float_exp(
+; MSVCXX-NOT: float @expf
+; MSVCXX: double @exp
+; MSVC19-NOT: float @expf
+; MSVC19: double @exp
+    %1 = fpext float %x to double
+    %2 = fpext float %y to double
+    %3 = call double @exp(double %1, double %2)
+    %4 = fptrunc double %3 to float
+    ret float %4
+}
+
+declare double @fabs(double %x, double %y)
+define float @float_fabs(float %x, float %y) nounwind readnone {
+; CHECK-LABEL: @float_fabs(
+; MSVCXX-NOT: float @fabsf
+; MSVCXX: double @fabs
+; MSVC19-NOT: float @fabsf
+; MSVC19: double @fabs
+    %1 = fpext float %x to double
+    %2 = fpext float %y to double
+    %3 = call double @fabs(double %1, double %2)
+    %4 = fptrunc double %3 to float
+    ret float %4
+}
+
+declare double @floor(double %x)
+define float @float_floor(float %x) nounwind readnone {
+; CHECK-LABEL: @float_floor(
+; MSVCXX-NOT: float @floorf
+; MSVCXX: float @llvm.floor.f32
+; MSVC19-NOT: double @floor
+; MSVC19: float @llvm.floor.f32
+; MINGW32-NOT: double @floor
+; MINGW32: float @llvm.floor.f32
+; MINGW64-NOT: double @floor
+; MINGW64: float @llvm.floor.f32
+    %1 = fpext float %x to double
+    %2 = call double @floor(double %1)
+    %3 = fptrunc double %2 to float
+    ret float %3
+}
+
+declare double @fmod(double %x, double %y)
+define float @float_fmod(float %x, float %y) nounwind readnone {
+; MSVCXX-LABEL: @float_fmod(
+; MSVCXX-NOT: float @fmodf
+; MSVCXX: double @fmod
+; MSVC19-NOT: float @fmodf
+; MSVC19: double @fmod
+    %1 = fpext float %x to double
+    %2 = fpext float %y to double
+    %3 = call double @fmod(double %1, double %2)
+    %4 = fptrunc double %3 to float
+    ret float %4
+}
+
+declare double @log(double %x)
+define float @float_log(float %x) nounwind readnone {
+; CHECK-LABEL: @float_log(
+; MSVCXX-NOT: float @logf
+; MSVCXX: double @log
+; MSVC19-NOT: float @logf
+; MSVC19: double @log
+    %1 = fpext float %x to double
+    %2 = call double @log(double %1)
+    %3 = fptrunc double %2 to float
+    ret float %3
+}
+
+declare double @logb(double %x)
+define float @float_logb(float %x) nounwind readnone {
+; CHECK-LABEL: @float_logb(
+; MSVCXX-NOT: float @logbf
+; MSVCXX: double @logb
+; MSVC19-NOT: float @logbf
+; MSVC19: double @logb
+    %1 = fpext float %x to double
+    %2 = call double @logb(double %1)
+    %3 = fptrunc double %2 to float
+    ret float %3
+}
+
+declare double @pow(double %x, double %y)
+define float @float_pow(float %x, float %y) nounwind readnone {
+; CHECK-LABEL: @float_pow(
+; MSVCXX-NOT: float @powf
+; MSVCXX: double @pow
+; MSVC19-NOT: float @powf
+; MSVC19: double @pow
+    %1 = fpext float %x to double
+    %2 = fpext float %y to double
+    %3 = call double @pow(double %1, double %2)
+    %4 = fptrunc double %3 to float
+    ret float %4
+}
+
+declare double @sin(double %x)
+define float @float_sin(float %x) nounwind readnone {
+; CHECK-LABEL: @float_sin(
+; MSVCXX-NOT: float @sinf
+; MSVCXX: double @sin
+; MSVC19-NOT: float @sinf
+; MSVC19: double @sin
+    %1 = fpext float %x to double
+    %2 = call double @sin(double %1)
+    %3 = fptrunc double %2 to float
+    ret float %3
+}
+
+declare double @sinh(double %x)
+define float @float_sinh(float %x) nounwind readnone {
+; CHECK-LABEL: @float_sinh(
+; MSVCXX-NOT: float @sinhf
+; MSVCXX: double @sinh
+; MSVC19-NOT: float @sinhf
+; MSVC19: double @sinh
+    %1 = fpext float %x to double
+    %2 = call double @sinh(double %1)
+    %3 = fptrunc double %2 to float
+    ret float %3
+}
+
+declare double @sqrt(double %x)
+define float @float_sqrt(float %x) nounwind readnone {
+; CHECK-LABEL: @float_sqrt(
+; MSVC32-NOT: float @sqrtf
+; MSVC32: double @sqrt
+; MSVC51-NOT: float @sqrtf
+; MSVC51: double @sqrt
+; MSVC64-NOT: double @sqrt
+; MSVC64: float @sqrtf
+; MSVC83-NOT: double @sqrt
+; MSVC83: float @sqrtf
+; MINGW32-NOT: double @sqrt
+; MINGW32: float @sqrtf
+; MINGW64-NOT: double @sqrt
+; MINGW64: float @sqrtf
+    %1 = fpext float %x to double
+    %2 = call double @sqrt(double %1)
+    %3 = fptrunc double %2 to float
+    ret float %3
+}
+
+declare double @tan(double %x)
+define float @float_tan(float %x) nounwind readnone {
+; CHECK-LABEL: @float_tan(
+; MSVCXX-NOT: float @tanf
+; MSVCXX: double @tan
+; MSVC19-NOT: float @tanf
+; MSVC19: double @tan
+    %1 = fpext float %x to double
+    %2 = call double @tan(double %1)
+    %3 = fptrunc double %2 to float
+    ret float %3
+}
+
+declare double @tanh(double %x)
+define float @float_tanh(float %x) nounwind readnone {
+; CHECK-LABEL: @float_tanh(
+; MSVCXX-NOT: float @tanhf
+; MSVCXX: double @tanh
+; MSVC19-NOT: float @tanhf
+; MSVC19: double @tanh
+    %1 = fpext float %x to double
+    %2 = call double @tanh(double %1)
+    %3 = fptrunc double %2 to float
+    ret float %3
+}
+
+; win32 does not have roundf; mingw32 does
+declare double @round(double %x)
+define float @float_round(float %x) nounwind readnone {
+; CHECK-LABEL: @float_round(
+; MSVCXX-NOT: double @roundf
+; MSVCXX: double @round
+; MSVC19-NOT: double @round
+; MSVC19: float @llvm.round.f32
+; MINGW32-NOT: double @round
+; MINGW32: float @llvm.round.f32
+; MINGW64-NOT: double @round
+; MINGW64: float @llvm.round.f32
+    %1 = fpext float %x to double
+    %2 = call double @round(double %1)
+    %3 = fptrunc double %2 to float
+    ret float %3
+}
+
+declare float @powf(float, float)
+
+; win32 lacks sqrtf & fabsf, win64 lacks fabsf, but
+; calls to the intrinsics can be emitted instead.
+define float @float_powsqrt(float %x) nounwind readnone {
+; CHECK-LABEL: @float_powsqrt(
+; MSVC32-NOT: float @sqrtf
+; MSVC32: float @powf
+; MSVC51-NOT: float @sqrtf
+; MSVC51: float @powf
+; MSVC64-NOT: float @powf
+; MSVC64: float @sqrtf
+; MSVC64: float @llvm.fabs.f32(
+; MSVC83-NOT: float @powf
+; MSVC83: float @sqrtf
+; MSVC83: float @llvm.fabs.f32(
+; MINGW32-NOT: float @powf
+; MINGW32: float @sqrtf
+; MINGW32: float @llvm.fabs.f32
+; MINGW64-NOT: float @powf
+; MINGW64: float @sqrtf
+; MINGW64: float @llvm.fabs.f32(
+    %1 = call float @powf(float %x, float 0.5)
+    ret float %1
+}

Added: llvm/trunk/test/Transforms/InstCombine/with_overflow.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/with_overflow.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/with_overflow.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/with_overflow.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,606 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt -instcombine -S < %s | FileCheck %s
+
+declare { i8, i1 } @llvm.uadd.with.overflow.i8(i8, i8) nounwind readnone
+declare { i8, i1 } @llvm.sadd.with.overflow.i8(i8, i8) nounwind readnone
+declare { i8, i1 } @llvm.usub.with.overflow.i8(i8, i8) nounwind readnone
+declare { i8, i1 } @llvm.ssub.with.overflow.i8(i8, i8) nounwind readnone
+declare { i8, i1 } @llvm.umul.with.overflow.i8(i8, i8) nounwind readnone
+declare { i8, i1 } @llvm.smul.with.overflow.i8(i8, i8) nounwind readnone
+declare { i32, i1 } @llvm.sadd.with.overflow.i32(i32, i32) nounwind readnone
+declare { i32, i1 } @llvm.uadd.with.overflow.i32(i32, i32) nounwind readnone
+declare { i32, i1 } @llvm.ssub.with.overflow.i32(i32, i32) nounwind readnone
+declare { i32, i1 } @llvm.usub.with.overflow.i32(i32, i32) nounwind readnone
+declare { i32, i1 } @llvm.smul.with.overflow.i32(i32, i32) nounwind readnone
+declare { i32, i1 } @llvm.umul.with.overflow.i32(i32, i32) nounwind readnone
+
+define i8 @uaddtest1(i8 %A, i8 %B) {
+; CHECK-LABEL: @uaddtest1(
+; CHECK-NEXT:    [[Y:%.*]] = add i8 [[A:%.*]], [[B:%.*]]
+; CHECK-NEXT:    ret i8 [[Y]]
+;
+  %x = call { i8, i1 } @llvm.uadd.with.overflow.i8(i8 %A, i8 %B)
+  %y = extractvalue { i8, i1 } %x, 0
+  ret i8 %y
+}
+
+define i8 @uaddtest2(i8 %A, i8 %B, i1* %overflowPtr) {
+; CHECK-LABEL: @uaddtest2(
+; CHECK-NEXT:    [[AND_A:%.*]] = and i8 [[A:%.*]], 127
+; CHECK-NEXT:    [[AND_B:%.*]] = and i8 [[B:%.*]], 127
+; CHECK-NEXT:    [[X:%.*]] = add nuw i8 [[AND_A]], [[AND_B]]
+; CHECK-NEXT:    store i1 false, i1* [[OVERFLOWPTR:%.*]], align 1
+; CHECK-NEXT:    ret i8 [[X]]
+;
+  %and.A = and i8 %A, 127
+  %and.B = and i8 %B, 127
+  %x = call { i8, i1 } @llvm.uadd.with.overflow.i8(i8 %and.A, i8 %and.B)
+  %y = extractvalue { i8, i1 } %x, 0
+  %z = extractvalue { i8, i1 } %x, 1
+  store i1 %z, i1* %overflowPtr
+  ret i8 %y
+}
+
+define i8 @uaddtest3(i8 %A, i8 %B, i1* %overflowPtr) {
+; CHECK-LABEL: @uaddtest3(
+; CHECK-NEXT:    [[OR_A:%.*]] = or i8 [[A:%.*]], -128
+; CHECK-NEXT:    [[OR_B:%.*]] = or i8 [[B:%.*]], -128
+; CHECK-NEXT:    [[X:%.*]] = add i8 [[OR_A]], [[OR_B]]
+; CHECK-NEXT:    store i1 true, i1* [[OVERFLOWPTR:%.*]], align 1
+; CHECK-NEXT:    ret i8 [[X]]
+;
+  %or.A = or i8 %A, -128
+  %or.B = or i8 %B, -128
+  %x = call { i8, i1 } @llvm.uadd.with.overflow.i8(i8 %or.A, i8 %or.B)
+  %y = extractvalue { i8, i1 } %x, 0
+  %z = extractvalue { i8, i1 } %x, 1
+  store i1 %z, i1* %overflowPtr
+  ret i8 %y
+}
+
+define i8 @uaddtest4(i8 %A, i1* %overflowPtr) {
+; CHECK-LABEL: @uaddtest4(
+; CHECK-NEXT:    ret i8 undef
+;
+  %x = call { i8, i1 } @llvm.uadd.with.overflow.i8(i8 undef, i8 %A)
+  %y = extractvalue { i8, i1 } %x, 0
+  %z = extractvalue { i8, i1 } %x, 1
+  store i1 %z, i1* %overflowPtr
+  ret i8 %y
+}
+
+define i8 @uaddtest5(i8 %A, i1* %overflowPtr) {
+; CHECK-LABEL: @uaddtest5(
+; CHECK-NEXT:    store i1 false, i1* [[OVERFLOWPTR:%.*]], align 1
+; CHECK-NEXT:    ret i8 [[A:%.*]]
+;
+  %x = call { i8, i1 } @llvm.uadd.with.overflow.i8(i8 0, i8 %A)
+  %y = extractvalue { i8, i1 } %x, 0
+  %z = extractvalue { i8, i1 } %x, 1
+  store i1 %z, i1* %overflowPtr
+  ret i8 %y
+}
+
+define i1 @uaddtest6(i8 %A, i8 %B) {
+; CHECK-LABEL: @uaddtest6(
+; CHECK-NEXT:    [[Z:%.*]] = icmp ugt i8 [[A:%.*]], 3
+; CHECK-NEXT:    ret i1 [[Z]]
+;
+  %x = call { i8, i1 } @llvm.uadd.with.overflow.i8(i8 %A, i8 -4)
+  %z = extractvalue { i8, i1 } %x, 1
+  ret i1 %z
+}
+
+define i8 @uaddtest7(i8 %A, i8 %B) {
+; CHECK-LABEL: @uaddtest7(
+; CHECK-NEXT:    [[Z:%.*]] = add i8 [[A:%.*]], [[B:%.*]]
+; CHECK-NEXT:    ret i8 [[Z]]
+;
+  %x = call { i8, i1 } @llvm.uadd.with.overflow.i8(i8 %A, i8 %B)
+  %z = extractvalue { i8, i1 } %x, 0
+  ret i8 %z
+}
+
+; PR20194
+define { i32, i1 } @saddtest_nsw(i8 %a, i8 %b) {
+; CHECK-LABEL: @saddtest_nsw(
+; CHECK-NEXT:    [[AA:%.*]] = sext i8 [[A:%.*]] to i32
+; CHECK-NEXT:    [[BB:%.*]] = sext i8 [[B:%.*]] to i32
+; CHECK-NEXT:    [[X:%.*]] = add nsw i32 [[AA]], [[BB]]
+; CHECK-NEXT:    [[TMP1:%.*]] = insertvalue { i32, i1 } { i32 undef, i1 false }, i32 [[X]], 0
+; CHECK-NEXT:    ret { i32, i1 } [[TMP1]]
+;
+  %aa = sext i8 %a to i32
+  %bb = sext i8 %b to i32
+  %x = call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 %aa, i32 %bb)
+  ret { i32, i1 } %x
+}
+
+define { i32, i1 } @uaddtest_nuw(i32 %a, i32 %b) {
+; CHECK-LABEL: @uaddtest_nuw(
+; CHECK-NEXT:    [[AA:%.*]] = and i32 [[A:%.*]], 2147483647
+; CHECK-NEXT:    [[BB:%.*]] = and i32 [[B:%.*]], 2147483647
+; CHECK-NEXT:    [[X:%.*]] = add nuw i32 [[AA]], [[BB]]
+; CHECK-NEXT:    [[TMP1:%.*]] = insertvalue { i32, i1 } { i32 undef, i1 false }, i32 [[X]], 0
+; CHECK-NEXT:    ret { i32, i1 } [[TMP1]]
+;
+  %aa = and i32 %a, 2147483647
+  %bb = and i32 %b, 2147483647
+  %x = call { i32, i1 } @llvm.uadd.with.overflow.i32(i32 %aa, i32 %bb)
+  ret { i32, i1 } %x
+}
+
+define { i32, i1 } @ssubtest_nsw(i8 %a, i8 %b) {
+; CHECK-LABEL: @ssubtest_nsw(
+; CHECK-NEXT:    [[AA:%.*]] = sext i8 [[A:%.*]] to i32
+; CHECK-NEXT:    [[BB:%.*]] = sext i8 [[B:%.*]] to i32
+; CHECK-NEXT:    [[X:%.*]] = sub nsw i32 [[AA]], [[BB]]
+; CHECK-NEXT:    [[TMP1:%.*]] = insertvalue { i32, i1 } { i32 undef, i1 false }, i32 [[X]], 0
+; CHECK-NEXT:    ret { i32, i1 } [[TMP1]]
+;
+  %aa = sext i8 %a to i32
+  %bb = sext i8 %b to i32
+  %x = call { i32, i1 } @llvm.ssub.with.overflow.i32(i32 %aa, i32 %bb)
+  ret { i32, i1 } %x
+}
+
+define { i32, i1 } @usubtest_nuw(i32 %a, i32 %b) {
+; CHECK-LABEL: @usubtest_nuw(
+; CHECK-NEXT:    [[AA:%.*]] = or i32 [[A:%.*]], -2147483648
+; CHECK-NEXT:    [[BB:%.*]] = and i32 [[B:%.*]], 2147483647
+; CHECK-NEXT:    [[X:%.*]] = sub nuw i32 [[AA]], [[BB]]
+; CHECK-NEXT:    [[TMP1:%.*]] = insertvalue { i32, i1 } { i32 undef, i1 false }, i32 [[X]], 0
+; CHECK-NEXT:    ret { i32, i1 } [[TMP1]]
+;
+  %aa = or i32 %a, 2147483648
+  %bb = and i32 %b, 2147483647
+  %x = call { i32, i1 } @llvm.usub.with.overflow.i32(i32 %aa, i32 %bb)
+  ret { i32, i1 } %x
+}
+
+define { i32, i1 } @smultest1_nsw(i32 %a, i32 %b) {
+; CHECK-LABEL: @smultest1_nsw(
+; CHECK-NEXT:    [[AA:%.*]] = and i32 [[A:%.*]], 4095
+; CHECK-NEXT:    [[BB:%.*]] = and i32 [[B:%.*]], 524287
+; CHECK-NEXT:    [[X:%.*]] = mul nuw nsw i32 [[AA]], [[BB]]
+; CHECK-NEXT:    [[TMP1:%.*]] = insertvalue { i32, i1 } { i32 undef, i1 false }, i32 [[X]], 0
+; CHECK-NEXT:    ret { i32, i1 } [[TMP1]]
+;
+  %aa = and i32 %a, 4095 ; 0xfff
+  %bb = and i32 %b, 524287; 0x7ffff
+  %x = call { i32, i1 } @llvm.smul.with.overflow.i32(i32 %aa, i32 %bb)
+  ret { i32, i1 } %x
+}
+
+define { i32, i1 } @smultest2_nsw(i32 %a, i32 %b) {
+; CHECK-LABEL: @smultest2_nsw(
+; CHECK-NEXT:    [[AA:%.*]] = ashr i32 [[A:%.*]], 16
+; CHECK-NEXT:    [[BB:%.*]] = ashr i32 [[B:%.*]], 16
+; CHECK-NEXT:    [[X:%.*]] = mul nsw i32 [[AA]], [[BB]]
+; CHECK-NEXT:    [[TMP1:%.*]] = insertvalue { i32, i1 } { i32 undef, i1 false }, i32 [[X]], 0
+; CHECK-NEXT:    ret { i32, i1 } [[TMP1]]
+;
+  %aa = ashr i32 %a, 16
+  %bb = ashr i32 %b, 16
+  %x = call { i32, i1 } @llvm.smul.with.overflow.i32(i32 %aa, i32 %bb)
+  ret { i32, i1 } %x
+}
+
+define { i32, i1 } @smultest3_sw(i32 %a, i32 %b) {
+; CHECK-LABEL: @smultest3_sw(
+; CHECK-NEXT:    [[AA:%.*]] = ashr i32 [[A:%.*]], 16
+; CHECK-NEXT:    [[BB:%.*]] = ashr i32 [[B:%.*]], 15
+; CHECK-NEXT:    [[X:%.*]] = call { i32, i1 } @llvm.smul.with.overflow.i32(i32 [[AA]], i32 [[BB]])
+; CHECK-NEXT:    ret { i32, i1 } [[X]]
+;
+  %aa = ashr i32 %a, 16
+  %bb = ashr i32 %b, 15
+  %x = call { i32, i1 } @llvm.smul.with.overflow.i32(i32 %aa, i32 %bb)
+  ret { i32, i1 } %x
+}
+
+define { i32, i1 } @umultest_nuw(i32 %a, i32 %b) {
+; CHECK-LABEL: @umultest_nuw(
+; CHECK-NEXT:    [[AA:%.*]] = and i32 [[A:%.*]], 65535
+; CHECK-NEXT:    [[BB:%.*]] = and i32 [[B:%.*]], 65535
+; CHECK-NEXT:    [[X:%.*]] = mul nuw i32 [[AA]], [[BB]]
+; CHECK-NEXT:    [[TMP1:%.*]] = insertvalue { i32, i1 } { i32 undef, i1 false }, i32 [[X]], 0
+; CHECK-NEXT:    ret { i32, i1 } [[TMP1]]
+;
+  %aa = and i32 %a, 65535 ; 0xffff
+  %bb = and i32 %b, 65535 ; 0xffff
+  %x = call { i32, i1 } @llvm.umul.with.overflow.i32(i32 %aa, i32 %bb)
+  ret { i32, i1 } %x
+}
+
+define i8 @umultest1(i8 %A, i1* %overflowPtr) {
+; CHECK-LABEL: @umultest1(
+; CHECK-NEXT:    store i1 false, i1* [[OVERFLOWPTR:%.*]], align 1
+; CHECK-NEXT:    ret i8 0
+;
+  %x = call { i8, i1 } @llvm.umul.with.overflow.i8(i8 0, i8 %A)
+  %y = extractvalue { i8, i1 } %x, 0
+  %z = extractvalue { i8, i1 } %x, 1
+  store i1 %z, i1* %overflowPtr
+  ret i8 %y
+}
+
+define i8 @umultest2(i8 %A, i1* %overflowPtr) {
+; CHECK-LABEL: @umultest2(
+; CHECK-NEXT:    store i1 false, i1* [[OVERFLOWPTR:%.*]], align 1
+; CHECK-NEXT:    ret i8 [[A:%.*]]
+;
+  %x = call { i8, i1 } @llvm.umul.with.overflow.i8(i8 1, i8 %A)
+  %y = extractvalue { i8, i1 } %x, 0
+  %z = extractvalue { i8, i1 } %x, 1
+  store i1 %z, i1* %overflowPtr
+  ret i8 %y
+}
+
+define i32 @umultest3(i32 %n) nounwind {
+; CHECK-LABEL: @umultest3(
+; CHECK-NEXT:    [[SHR:%.*]] = lshr i32 [[N:%.*]], 2
+; CHECK-NEXT:    [[MUL:%.*]] = mul nuw i32 [[SHR]], 3
+; CHECK-NEXT:    ret i32 [[MUL]]
+;
+  %shr = lshr i32 %n, 2
+  %mul = call { i32, i1 } @llvm.umul.with.overflow.i32(i32 %shr, i32 3)
+  %ov = extractvalue { i32, i1 } %mul, 1
+  %res = extractvalue { i32, i1 } %mul, 0
+  %ret = select i1 %ov, i32 -1, i32 %res
+  ret i32 %ret
+}
+
+define i32 @umultest4(i32 %n) nounwind {
+; CHECK-LABEL: @umultest4(
+; CHECK-NEXT:    [[SHR:%.*]] = lshr i32 [[N:%.*]], 1
+; CHECK-NEXT:    [[MUL:%.*]] = call { i32, i1 } @llvm.umul.with.overflow.i32(i32 [[SHR]], i32 4)
+; CHECK-NEXT:    [[OV:%.*]] = extractvalue { i32, i1 } [[MUL]], 1
+; CHECK-NEXT:    [[RES:%.*]] = extractvalue { i32, i1 } [[MUL]], 0
+; CHECK-NEXT:    [[RET:%.*]] = select i1 [[OV]], i32 -1, i32 [[RES]]
+; CHECK-NEXT:    ret i32 [[RET]]
+;
+  %shr = lshr i32 %n, 1
+  %mul = call { i32, i1 } @llvm.umul.with.overflow.i32(i32 %shr, i32 4)
+  %ov = extractvalue { i32, i1 } %mul, 1
+  %res = extractvalue { i32, i1 } %mul, 0
+  %ret = select i1 %ov, i32 -1, i32 %res
+  ret i32 %ret
+}
+
+define { i32, i1 } @umultest5(i32 %x, i32 %y) nounwind {
+; CHECK-LABEL: @umultest5(
+; CHECK-NEXT:    [[OR_X:%.*]] = or i32 [[X:%.*]], -2147483648
+; CHECK-NEXT:    [[OR_Y:%.*]] = or i32 [[Y:%.*]], -2147483648
+; CHECK-NEXT:    [[MUL:%.*]] = mul i32 [[OR_X]], [[OR_Y]]
+; CHECK-NEXT:    [[TMP1:%.*]] = insertvalue { i32, i1 } { i32 undef, i1 true }, i32 [[MUL]], 0
+; CHECK-NEXT:    ret { i32, i1 } [[TMP1]]
+;
+  %or_x = or i32 %x, 2147483648
+  %or_y = or i32 %y, 2147483648
+  %mul = call { i32, i1 } @llvm.umul.with.overflow.i32(i32 %or_x, i32 %or_y)
+  ret { i32, i1 } %mul
+}
+
+define i1 @overflow_div_add(i32 %v1, i32 %v2) nounwind {
+; CHECK-LABEL: @overflow_div_add(
+; CHECK-NEXT:    ret i1 false
+;
+  %div = sdiv i32 %v1, 2
+  %t = call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 %div, i32 1)
+  %obit = extractvalue { i32, i1 } %t, 1
+  ret i1 %obit
+}
+
+define i1 @overflow_div_sub(i32 %v1, i32 %v2) nounwind {
+  ; Check cases where the known sign bits are larger than the word size.
+; CHECK-LABEL: @overflow_div_sub(
+; CHECK-NEXT:    ret i1 false
+;
+  %a = ashr i32 %v1, 18
+  %div = sdiv i32 %a, 65536
+  %t = call { i32, i1 } @llvm.ssub.with.overflow.i32(i32 %div, i32 1)
+  %obit = extractvalue { i32, i1 } %t, 1
+  ret i1 %obit
+}
+
+define i1 @overflow_mod_mul(i32 %v1, i32 %v2) nounwind {
+; CHECK-LABEL: @overflow_mod_mul(
+; CHECK-NEXT:    ret i1 false
+;
+  %rem = srem i32 %v1, 1000
+  %t = call { i32, i1 } @llvm.smul.with.overflow.i32(i32 %rem, i32 %rem)
+  %obit = extractvalue { i32, i1 } %t, 1
+  ret i1 %obit
+}
+
+define i1 @overflow_mod_overflow_mul(i32 %v1, i32 %v2) nounwind {
+; CHECK-LABEL: @overflow_mod_overflow_mul(
+; CHECK-NEXT:    [[REM:%.*]] = srem i32 [[V1:%.*]], 65537
+; CHECK-NEXT:    [[T:%.*]] = call { i32, i1 } @llvm.smul.with.overflow.i32(i32 [[REM]], i32 [[REM]])
+; CHECK-NEXT:    [[OBIT:%.*]] = extractvalue { i32, i1 } [[T]], 1
+; CHECK-NEXT:    ret i1 [[OBIT]]
+;
+  %rem = srem i32 %v1, 65537
+  ; This may overflow because the result of the mul operands may be greater than 16bits
+  ; and the result greater than 32.
+  %t = call { i32, i1 } @llvm.smul.with.overflow.i32(i32 %rem, i32 %rem)
+  %obit = extractvalue { i32, i1 } %t, 1
+  ret i1 %obit
+}
+
+define { i32, i1 } @ssubtest_reorder(i8 %a) {
+; CHECK-LABEL: @ssubtest_reorder(
+; CHECK-NEXT:    [[AA:%.*]] = sext i8 [[A:%.*]] to i32
+; CHECK-NEXT:    [[X:%.*]] = sub nsw i32 0, [[AA]]
+; CHECK-NEXT:    [[TMP1:%.*]] = insertvalue { i32, i1 } { i32 undef, i1 false }, i32 [[X]], 0
+; CHECK-NEXT:    ret { i32, i1 } [[TMP1]]
+;
+  %aa = sext i8 %a to i32
+  %x = call { i32, i1 } @llvm.ssub.with.overflow.i32(i32 0, i32 %aa)
+  ret { i32, i1 } %x
+}
+
+define { i32, i1 } @never_overflows_ssub_test0(i32 %a) {
+; CHECK-LABEL: @never_overflows_ssub_test0(
+; CHECK-NEXT:    [[X:%.*]] = insertvalue { i32, i1 } { i32 undef, i1 false }, i32 [[A:%.*]], 0
+; CHECK-NEXT:    ret { i32, i1 } [[X]]
+;
+  %x = call { i32, i1 } @llvm.ssub.with.overflow.i32(i32 %a, i32 0)
+  ret { i32, i1 } %x
+}
+
+define i1 @uadd_res_ult_x(i32 %x, i32 %y, i1* %p) nounwind {
+; CHECK-LABEL: @uadd_res_ult_x(
+; CHECK-NEXT:    [[A:%.*]] = call { i32, i1 } @llvm.uadd.with.overflow.i32(i32 [[X:%.*]], i32 [[Y:%.*]])
+; CHECK-NEXT:    [[B:%.*]] = extractvalue { i32, i1 } [[A]], 1
+; CHECK-NEXT:    store i1 [[B]], i1* [[P:%.*]], align 1
+; CHECK-NEXT:    [[C:%.*]] = extractvalue { i32, i1 } [[A]], 0
+; CHECK-NEXT:    [[D:%.*]] = icmp ult i32 [[C]], [[X]]
+; CHECK-NEXT:    ret i1 [[D]]
+;
+  %a = call { i32, i1 } @llvm.uadd.with.overflow.i32(i32 %x, i32 %y)
+  %b = extractvalue { i32, i1 } %a, 1
+  store i1 %b, i1* %p
+  %c = extractvalue { i32, i1 } %a, 0
+  %d = icmp ult i32 %c, %x
+  ret i1 %d
+}
+
+define i1 @uadd_res_ult_y(i32 %x, i32 %y, i1* %p) nounwind {
+; CHECK-LABEL: @uadd_res_ult_y(
+; CHECK-NEXT:    [[A:%.*]] = call { i32, i1 } @llvm.uadd.with.overflow.i32(i32 [[X:%.*]], i32 [[Y:%.*]])
+; CHECK-NEXT:    [[B:%.*]] = extractvalue { i32, i1 } [[A]], 1
+; CHECK-NEXT:    store i1 [[B]], i1* [[P:%.*]], align 1
+; CHECK-NEXT:    [[C:%.*]] = extractvalue { i32, i1 } [[A]], 0
+; CHECK-NEXT:    [[D:%.*]] = icmp ult i32 [[C]], [[Y]]
+; CHECK-NEXT:    ret i1 [[D]]
+;
+  %a = call { i32, i1 } @llvm.uadd.with.overflow.i32(i32 %x, i32 %y)
+  %b = extractvalue { i32, i1 } %a, 1
+  store i1 %b, i1* %p
+  %c = extractvalue { i32, i1 } %a, 0
+  %d = icmp ult i32 %c, %y
+  ret i1 %d
+}
+
+define i1 @uadd_res_ugt_x(i32 %xx, i32 %y, i1* %p) nounwind {
+; CHECK-LABEL: @uadd_res_ugt_x(
+; CHECK-NEXT:    [[X:%.*]] = urem i32 42, [[XX:%.*]]
+; CHECK-NEXT:    [[A:%.*]] = call { i32, i1 } @llvm.uadd.with.overflow.i32(i32 [[X]], i32 [[Y:%.*]])
+; CHECK-NEXT:    [[B:%.*]] = extractvalue { i32, i1 } [[A]], 1
+; CHECK-NEXT:    store i1 [[B]], i1* [[P:%.*]], align 1
+; CHECK-NEXT:    [[C:%.*]] = extractvalue { i32, i1 } [[A]], 0
+; CHECK-NEXT:    [[D:%.*]] = icmp ugt i32 [[X]], [[C]]
+; CHECK-NEXT:    ret i1 [[D]]
+;
+  %x = urem i32 42, %xx ; Thwart complexity-based canonicalization
+  %a = call { i32, i1 } @llvm.uadd.with.overflow.i32(i32 %x, i32 %y)
+  %b = extractvalue { i32, i1 } %a, 1
+  store i1 %b, i1* %p
+  %c = extractvalue { i32, i1 } %a, 0
+  %d = icmp ugt i32 %x, %c
+  ret i1 %d
+}
+
+define i1 @uadd_res_ugt_y(i32 %x, i32 %yy, i1* %p) nounwind {
+; CHECK-LABEL: @uadd_res_ugt_y(
+; CHECK-NEXT:    [[Y:%.*]] = urem i32 42, [[YY:%.*]]
+; CHECK-NEXT:    [[A:%.*]] = call { i32, i1 } @llvm.uadd.with.overflow.i32(i32 [[X:%.*]], i32 [[Y]])
+; CHECK-NEXT:    [[B:%.*]] = extractvalue { i32, i1 } [[A]], 1
+; CHECK-NEXT:    store i1 [[B]], i1* [[P:%.*]], align 1
+; CHECK-NEXT:    [[C:%.*]] = extractvalue { i32, i1 } [[A]], 0
+; CHECK-NEXT:    [[D:%.*]] = icmp ugt i32 [[Y]], [[C]]
+; CHECK-NEXT:    ret i1 [[D]]
+;
+  %y = urem i32 42, %yy ; Thwart complexity-based canonicalization
+  %a = call { i32, i1 } @llvm.uadd.with.overflow.i32(i32 %x, i32 %y)
+  %b = extractvalue { i32, i1 } %a, 1
+  store i1 %b, i1* %p
+  %c = extractvalue { i32, i1 } %a, 0
+  %d = icmp ugt i32 %y, %c
+  ret i1 %d
+}
+
+define i1 @uadd_res_ult_const(i32 %x, i1* %p) nounwind {
+; CHECK-LABEL: @uadd_res_ult_const(
+; CHECK-NEXT:    [[A:%.*]] = call { i32, i1 } @llvm.uadd.with.overflow.i32(i32 [[X:%.*]], i32 42)
+; CHECK-NEXT:    [[B:%.*]] = extractvalue { i32, i1 } [[A]], 1
+; CHECK-NEXT:    store i1 [[B]], i1* [[P:%.*]], align 1
+; CHECK-NEXT:    [[C:%.*]] = extractvalue { i32, i1 } [[A]], 0
+; CHECK-NEXT:    [[D:%.*]] = icmp ult i32 [[C]], 42
+; CHECK-NEXT:    ret i1 [[D]]
+;
+  %a = call { i32, i1 } @llvm.uadd.with.overflow.i32(i32 %x, i32 42)
+  %b = extractvalue { i32, i1 } %a, 1
+  store i1 %b, i1* %p
+  %c = extractvalue { i32, i1 } %a, 0
+  %d = icmp ult i32 %c, 42
+  ret i1 %d
+}
+
+define i1 @uadd_res_ult_const_one(i32 %x, i1* %p) nounwind {
+; CHECK-LABEL: @uadd_res_ult_const_one(
+; CHECK-NEXT:    [[A:%.*]] = call { i32, i1 } @llvm.uadd.with.overflow.i32(i32 [[X:%.*]], i32 1)
+; CHECK-NEXT:    [[B:%.*]] = extractvalue { i32, i1 } [[A]], 1
+; CHECK-NEXT:    store i1 [[B]], i1* [[P:%.*]], align 1
+; CHECK-NEXT:    [[C:%.*]] = extractvalue { i32, i1 } [[A]], 0
+; CHECK-NEXT:    [[D:%.*]] = icmp eq i32 [[C]], 0
+; CHECK-NEXT:    ret i1 [[D]]
+;
+  %a = call { i32, i1 } @llvm.uadd.with.overflow.i32(i32 %x, i32 1)
+  %b = extractvalue { i32, i1 } %a, 1
+  store i1 %b, i1* %p
+  %c = extractvalue { i32, i1 } %a, 0
+  %d = icmp ult i32 %c, 1
+  ret i1 %d
+}
+
+define i1 @uadd_res_ult_const_minus_one(i32 %x, i1* %p) nounwind {
+; CHECK-LABEL: @uadd_res_ult_const_minus_one(
+; CHECK-NEXT:    [[A:%.*]] = call { i32, i1 } @llvm.uadd.with.overflow.i32(i32 [[X:%.*]], i32 -1)
+; CHECK-NEXT:    [[B:%.*]] = extractvalue { i32, i1 } [[A]], 1
+; CHECK-NEXT:    store i1 [[B]], i1* [[P:%.*]], align 1
+; CHECK-NEXT:    [[C:%.*]] = extractvalue { i32, i1 } [[A]], 0
+; CHECK-NEXT:    [[D:%.*]] = icmp ne i32 [[C]], -1
+; CHECK-NEXT:    ret i1 [[D]]
+;
+  %a = call { i32, i1 } @llvm.uadd.with.overflow.i32(i32 %x, i32 -1)
+  %b = extractvalue { i32, i1 } %a, 1
+  store i1 %b, i1* %p
+  %c = extractvalue { i32, i1 } %a, 0
+  %d = icmp ult i32 %c, -1
+  ret i1 %d
+}
+
+define { i32, i1 } @sadd_canonicalize_constant_arg0(i32 %x) nounwind {
+; CHECK-LABEL: @sadd_canonicalize_constant_arg0(
+; CHECK-NEXT:    [[A:%.*]] = call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 [[X:%.*]], i32 42)
+; CHECK-NEXT:    ret { i32, i1 } [[A]]
+;
+  %a = call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 42, i32 %x)
+  ret { i32, i1 } %a
+}
+
+define { i32, i1 } @uadd_canonicalize_constant_arg0(i32 %x) nounwind {
+; CHECK-LABEL: @uadd_canonicalize_constant_arg0(
+; CHECK-NEXT:    [[A:%.*]] = call { i32, i1 } @llvm.uadd.with.overflow.i32(i32 [[X:%.*]], i32 42)
+; CHECK-NEXT:    ret { i32, i1 } [[A]]
+;
+  %a = call { i32, i1 } @llvm.uadd.with.overflow.i32(i32 42, i32 %x)
+  ret { i32, i1 } %a
+}
+
+define { i32, i1 } @ssub_no_canonicalize_constant_arg0(i32 %x) nounwind {
+; CHECK-LABEL: @ssub_no_canonicalize_constant_arg0(
+; CHECK-NEXT:    [[A:%.*]] = call { i32, i1 } @llvm.ssub.with.overflow.i32(i32 42, i32 [[X:%.*]])
+; CHECK-NEXT:    ret { i32, i1 } [[A]]
+;
+  %a = call { i32, i1 } @llvm.ssub.with.overflow.i32(i32 42, i32 %x)
+  ret { i32, i1 } %a
+}
+
+define { i32, i1 } @usub_no_canonicalize_constant_arg0(i32 %x) nounwind {
+; CHECK-LABEL: @usub_no_canonicalize_constant_arg0(
+; CHECK-NEXT:    [[A:%.*]] = call { i32, i1 } @llvm.usub.with.overflow.i32(i32 42, i32 [[X:%.*]])
+; CHECK-NEXT:    ret { i32, i1 } [[A]]
+;
+  %a = call { i32, i1 } @llvm.usub.with.overflow.i32(i32 42, i32 %x)
+  ret { i32, i1 } %a
+}
+
+define { i32, i1 } @smul_canonicalize_constant_arg0(i32 %x) nounwind {
+; CHECK-LABEL: @smul_canonicalize_constant_arg0(
+; CHECK-NEXT:    [[A:%.*]] = call { i32, i1 } @llvm.smul.with.overflow.i32(i32 [[X:%.*]], i32 42)
+; CHECK-NEXT:    ret { i32, i1 } [[A]]
+;
+  %a = call { i32, i1 } @llvm.smul.with.overflow.i32(i32 42, i32 %x)
+  ret { i32, i1 } %a
+}
+
+define { i32, i1 } @umul_canonicalize_constant_arg0(i32 %x) nounwind {
+; CHECK-LABEL: @umul_canonicalize_constant_arg0(
+; CHECK-NEXT:    [[A:%.*]] = call { i32, i1 } @llvm.umul.with.overflow.i32(i32 [[X:%.*]], i32 42)
+; CHECK-NEXT:    ret { i32, i1 } [[A]]
+;
+  %a = call { i32, i1 } @llvm.umul.with.overflow.i32(i32 42, i32 %x)
+  ret { i32, i1 } %a
+}
+
+; Always overflow tests
+
+define { i8, i1 } @uadd_always_overflow(i8 %x) nounwind {
+; CHECK-LABEL: @uadd_always_overflow(
+; CHECK-NEXT:    [[Y:%.*]] = or i8 [[X:%.*]], -64
+; CHECK-NEXT:    [[A:%.*]] = add nsw i8 [[Y]], 64
+; CHECK-NEXT:    [[TMP1:%.*]] = insertvalue { i8, i1 } { i8 undef, i1 true }, i8 [[A]], 0
+; CHECK-NEXT:    ret { i8, i1 } [[TMP1]]
+;
+  %y = or i8 %x, 192
+  %a = call { i8, i1 } @llvm.uadd.with.overflow.i8(i8 %y, i8 64)
+  ret { i8, i1 } %a
+}
+
+define { i8, i1 } @usub_always_overflow(i8 %x) nounwind {
+; CHECK-LABEL: @usub_always_overflow(
+; CHECK-NEXT:    [[Y:%.*]] = or i8 [[X:%.*]], 64
+; CHECK-NEXT:    [[A:%.*]] = sub nsw i8 63, [[Y]]
+; CHECK-NEXT:    [[TMP1:%.*]] = insertvalue { i8, i1 } { i8 undef, i1 true }, i8 [[A]], 0
+; CHECK-NEXT:    ret { i8, i1 } [[TMP1]]
+;
+  %y = or i8 %x, 64
+  %a = call { i8, i1 } @llvm.usub.with.overflow.i8(i8 63, i8 %y)
+  ret { i8, i1 } %a
+}
+
+define { i8, i1 } @umul_always_overflow(i8 %x) nounwind {
+; CHECK-LABEL: @umul_always_overflow(
+; CHECK-NEXT:    [[A:%.*]] = shl i8 [[X:%.*]], 1
+; CHECK-NEXT:    [[TMP1:%.*]] = insertvalue { i8, i1 } { i8 undef, i1 true }, i8 [[A]], 0
+; CHECK-NEXT:    ret { i8, i1 } [[TMP1]]
+;
+  %y = or i8 %x, 128
+  %a = call { i8, i1 } @llvm.umul.with.overflow.i8(i8 %y, i8 2)
+  ret { i8, i1 } %a
+}
+
+define { i8, i1 } @sadd_always_overflow(i8 %x) nounwind {
+; CHECK-LABEL: @sadd_always_overflow(
+; CHECK-NEXT:    [[C:%.*]] = icmp sgt i8 [[X:%.*]], 100
+; CHECK-NEXT:    [[Y:%.*]] = select i1 [[C]], i8 [[X]], i8 100
+; CHECK-NEXT:    [[A:%.*]] = add nuw i8 [[Y]], 28
+; CHECK-NEXT:    [[TMP1:%.*]] = insertvalue { i8, i1 } { i8 undef, i1 true }, i8 [[A]], 0
+; CHECK-NEXT:    ret { i8, i1 } [[TMP1]]
+;
+  %c = icmp sgt i8 %x, 100
+  %y = select i1 %c, i8 %x, i8 100
+  %a = call { i8, i1 } @llvm.sadd.with.overflow.i8(i8 %y, i8 28)
+  ret { i8, i1 } %a
+}
+
+define { i8, i1 } @ssub_always_overflow(i8 %x) nounwind {
+; CHECK-LABEL: @ssub_always_overflow(
+; CHECK-NEXT:    [[C:%.*]] = icmp sgt i8 [[X:%.*]], 29
+; CHECK-NEXT:    [[Y:%.*]] = select i1 [[C]], i8 [[X]], i8 29
+; CHECK-NEXT:    [[A:%.*]] = sub nuw i8 -100, [[Y]]
+; CHECK-NEXT:    [[TMP1:%.*]] = insertvalue { i8, i1 } { i8 undef, i1 true }, i8 [[A]], 0
+; CHECK-NEXT:    ret { i8, i1 } [[TMP1]]
+;
+  %c = icmp sgt i8 %x, 29
+  %y = select i1 %c, i8 %x, i8 29
+  %a = call { i8, i1 } @llvm.ssub.with.overflow.i8(i8 -100, i8 %y)
+  ret { i8, i1 } %a
+}
+
+define { i8, i1 } @smul_always_overflow(i8 %x) nounwind {
+; CHECK-LABEL: @smul_always_overflow(
+; CHECK-NEXT:    [[C:%.*]] = icmp sgt i8 [[X:%.*]], 100
+; CHECK-NEXT:    [[Y:%.*]] = select i1 [[C]], i8 [[X]], i8 100
+; CHECK-NEXT:    [[A:%.*]] = call { i8, i1 } @llvm.smul.with.overflow.i8(i8 [[Y]], i8 2)
+; CHECK-NEXT:    ret { i8, i1 } [[A]]
+;
+  %c = icmp sgt i8 %x, 100
+  %y = select i1 %c, i8 %x, i8 100
+  %a = call { i8, i1 } @llvm.smul.with.overflow.i8(i8 %y, i8 2)
+  ret { i8, i1 } %a
+}

Added: llvm/trunk/test/Transforms/InstCombine/xor-icmps.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/xor-icmps.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/xor-icmps.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/xor-icmps.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,173 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt < %s -instcombine -S | FileCheck %s
+
+define i1 @eq_zero(i4 %x, i4 %y) {
+; CHECK-LABEL: @eq_zero(
+; CHECK-NEXT:    [[I0:%.*]] = icmp eq i4 [[X:%.*]], 0
+; CHECK-NEXT:    [[I1:%.*]] = icmp eq i4 [[Y:%.*]], 0
+; CHECK-NEXT:    [[R:%.*]] = xor i1 [[I0]], [[I1]]
+; CHECK-NEXT:    ret i1 [[R]]
+;
+  %i0 = icmp eq i4 %x, 0
+  %i1 = icmp eq i4 %y, 0
+  %r = xor i1 %i0, %i1
+  ret i1 %r
+}
+
+define i1 @ne_zero(i4 %x, i4 %y) {
+; CHECK-LABEL: @ne_zero(
+; CHECK-NEXT:    [[I0:%.*]] = icmp ne i4 [[X:%.*]], 0
+; CHECK-NEXT:    [[I1:%.*]] = icmp ne i4 [[Y:%.*]], 0
+; CHECK-NEXT:    [[R:%.*]] = xor i1 [[I0]], [[I1]]
+; CHECK-NEXT:    ret i1 [[R]]
+;
+  %i0 = icmp ne i4 %x, 0
+  %i1 = icmp ne i4 %y, 0
+  %r = xor i1 %i0, %i1
+  ret i1 %r
+}
+
+define i1 @eq_ne_zero(i4 %x, i4 %y) {
+; CHECK-LABEL: @eq_ne_zero(
+; CHECK-NEXT:    [[I0:%.*]] = icmp eq i4 [[X:%.*]], 0
+; CHECK-NEXT:    [[I1:%.*]] = icmp ne i4 [[Y:%.*]], 0
+; CHECK-NEXT:    [[R:%.*]] = xor i1 [[I0]], [[I1]]
+; CHECK-NEXT:    ret i1 [[R]]
+;
+  %i0 = icmp eq i4 %x, 0
+  %i1 = icmp ne i4 %y, 0
+  %r = xor i1 %i0, %i1
+  ret i1 %r
+}
+
+define i1 @slt_zero(i4 %x, i4 %y) {
+; CHECK-LABEL: @slt_zero(
+; CHECK-NEXT:    [[TMP1:%.*]] = xor i4 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    [[TMP2:%.*]] = icmp slt i4 [[TMP1]], 0
+; CHECK-NEXT:    ret i1 [[TMP2]]
+;
+  %i0 = icmp slt i4 %x, 0
+  %i1 = icmp slt i4 %y, 0
+  %r = xor i1 %i0, %i1
+  ret i1 %r
+}
+
+; Don't increase the instruction count.
+
+declare void @use(i1)
+
+define i1 @slt_zero_extra_uses(i4 %x, i4 %y) {
+; CHECK-LABEL: @slt_zero_extra_uses(
+; CHECK-NEXT:    [[I0:%.*]] = icmp slt i4 [[X:%.*]], 0
+; CHECK-NEXT:    [[I1:%.*]] = icmp slt i4 [[Y:%.*]], 0
+; CHECK-NEXT:    [[R:%.*]] = xor i1 [[I0]], [[I1]]
+; CHECK-NEXT:    call void @use(i1 [[I0]])
+; CHECK-NEXT:    call void @use(i1 [[I1]])
+; CHECK-NEXT:    ret i1 [[R]]
+;
+  %i0 = icmp slt i4 %x, 0
+  %i1 = icmp slt i4 %y, 0
+  %r = xor i1 %i0, %i1
+  call void @use(i1 %i0)
+  call void @use(i1 %i1)
+  ret i1 %r
+}
+
+define i1 @sgt_zero(i4 %x, i4 %y) {
+; CHECK-LABEL: @sgt_zero(
+; CHECK-NEXT:    [[I0:%.*]] = icmp sgt i4 [[X:%.*]], 0
+; CHECK-NEXT:    [[I1:%.*]] = icmp sgt i4 [[Y:%.*]], 0
+; CHECK-NEXT:    [[R:%.*]] = xor i1 [[I0]], [[I1]]
+; CHECK-NEXT:    ret i1 [[R]]
+;
+  %i0 = icmp sgt i4 %x, 0
+  %i1 = icmp sgt i4 %y, 0
+  %r = xor i1 %i0, %i1
+  ret i1 %r
+}
+
+define i1 @sgt_minus1(i4 %x, i4 %y) {
+; CHECK-LABEL: @sgt_minus1(
+; CHECK-NEXT:    [[TMP1:%.*]] = xor i4 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    [[TMP2:%.*]] = icmp slt i4 [[TMP1]], 0
+; CHECK-NEXT:    ret i1 [[TMP2]]
+;
+  %i0 = icmp sgt i4 %x, -1
+  %i1 = icmp sgt i4 %y, -1
+  %r = xor i1 %i0, %i1
+  ret i1 %r
+}
+
+define i1 @slt_zero_sgt_minus1(i4 %x, i4 %y) {
+; CHECK-LABEL: @slt_zero_sgt_minus1(
+; CHECK-NEXT:    [[TMP1:%.*]] = xor i4 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    [[TMP2:%.*]] = icmp sgt i4 [[TMP1]], -1
+; CHECK-NEXT:    ret i1 [[TMP2]]
+;
+  %i0 = icmp slt i4 %x, 0
+  %i1 = icmp sgt i4 %y, -1
+  %r = xor i1 %i0, %i1
+  ret i1 %r
+}
+
+define <2 x i1> @sgt_minus1_slt_zero_sgt(<2 x i4> %x, <2 x i4> %y) {
+; CHECK-LABEL: @sgt_minus1_slt_zero_sgt(
+; CHECK-NEXT:    [[TMP1:%.*]] = xor <2 x i4> [[Y:%.*]], [[X:%.*]]
+; CHECK-NEXT:    [[TMP2:%.*]] = icmp sgt <2 x i4> [[TMP1]], <i4 -1, i4 -1>
+; CHECK-NEXT:    ret <2 x i1> [[TMP2]]
+;
+  %i1 = icmp sgt <2 x i4> %x, <i4 -1, i4 -1>
+  %i0 = icmp slt <2 x i4> %y, zeroinitializer
+  %r = xor <2 x i1> %i0, %i1
+  ret <2 x i1> %r
+}
+
+; Don't try (crash) if the operand types don't match.
+
+define i1 @different_type_cmp_ops(i32 %x, i64 %y) {
+; CHECK-LABEL: @different_type_cmp_ops(
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp slt i32 [[X:%.*]], 0
+; CHECK-NEXT:    [[CMP2:%.*]] = icmp slt i64 [[Y:%.*]], 0
+; CHECK-NEXT:    [[R:%.*]] = xor i1 [[CMP1]], [[CMP2]]
+; CHECK-NEXT:    ret i1 [[R]]
+;
+  %cmp1 = icmp slt i32 %x, 0
+  %cmp2 = icmp slt i64 %y, 0
+  %r = xor i1 %cmp1, %cmp2
+  ret i1 %r
+}
+
+define i1 @test13(i8 %A, i8 %B) {
+; CHECK-LABEL: @test13(
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp ne i8 [[A:%.*]], [[B:%.*]]
+; CHECK-NEXT:    ret i1 [[TMP1]]
+;
+  %C = icmp ult i8 %A, %B
+  %D = icmp ugt i8 %A, %B
+  %E = xor i1 %C, %D
+  ret i1 %E
+}
+
+define i1 @test14(i8 %A, i8 %B) {
+; CHECK-LABEL: @test14(
+; CHECK-NEXT:    ret i1 true
+;
+  %C = icmp eq i8 %A, %B
+  %D = icmp ne i8 %B, %A
+  %E = xor i1 %C, %D
+  ret i1 %E
+}
+
+define i1 @xor_icmp_ptr(i8* %c, i8* %d) {
+; CHECK-LABEL: @xor_icmp_ptr(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i8* [[C:%.*]], null
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp slt i8* [[D:%.*]], null
+; CHECK-NEXT:    [[XOR:%.*]] = xor i1 [[CMP]], [[CMP1]]
+; CHECK-NEXT:    ret i1 [[XOR]]
+;
+  %cmp = icmp slt i8* %c, null
+  %cmp1 = icmp slt i8* %d, null
+  %xor = xor i1 %cmp, %cmp1
+  ret i1 %xor
+}
+

Added: llvm/trunk/test/Transforms/InstCombine/xor-undef.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/xor-undef.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/xor-undef.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/xor-undef.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,6 @@
+; RUN: opt < %s -instcombine -S | grep zeroinitializer
+
+define <2 x i64> @f() {
+	%tmp = xor <2 x i64> undef, undef
+        ret <2 x i64> %tmp
+}

Added: llvm/trunk/test/Transforms/InstCombine/xor.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/xor.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/xor.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/xor.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,914 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt < %s -instcombine -S | FileCheck %s
+
+ at G1 = global i32 0
+ at G2 = global i32 0
+
+define i1 @test0(i1 %A) {
+; CHECK-LABEL: @test0(
+; CHECK-NEXT:    ret i1 [[A:%.*]]
+;
+  %B = xor i1 %A, false
+  ret i1 %B
+}
+
+define i32 @test1(i32 %A) {
+; CHECK-LABEL: @test1(
+; CHECK-NEXT:    ret i32 [[A:%.*]]
+;
+  %B = xor i32 %A, 0
+  ret i32 %B
+}
+
+define i1 @test2(i1 %A) {
+; CHECK-LABEL: @test2(
+; CHECK-NEXT:    ret i1 false
+;
+  %B = xor i1 %A, %A
+  ret i1 %B
+}
+
+define i32 @test3(i32 %A) {
+; CHECK-LABEL: @test3(
+; CHECK-NEXT:    ret i32 0
+;
+  %B = xor i32 %A, %A
+  ret i32 %B
+}
+
+define i32 @test4(i32 %A) {
+; CHECK-LABEL: @test4(
+; CHECK-NEXT:    ret i32 -1
+;
+  %NotA = xor i32 -1, %A
+  %B = xor i32 %A, %NotA
+  ret i32 %B
+}
+
+define i32 @test5(i32 %A) {
+; CHECK-LABEL: @test5(
+; CHECK-NEXT:    [[TMP1:%.*]] = and i32 [[A:%.*]], -124
+; CHECK-NEXT:    ret i32 [[TMP1]]
+;
+  %t1 = or i32 %A, 123
+  %r = xor i32 %t1, 123
+  ret i32 %r
+}
+
+define i8 @test6(i8 %A) {
+; CHECK-LABEL: @test6(
+; CHECK-NEXT:    ret i8 [[A:%.*]]
+;
+  %B = xor i8 %A, 17
+  %C = xor i8 %B, 17
+  ret i8 %C
+}
+
+define i32 @test7(i32 %A, i32 %B) {
+; CHECK-LABEL: @test7(
+; CHECK-NEXT:    [[A1:%.*]] = and i32 [[A:%.*]], 7
+; CHECK-NEXT:    [[B1:%.*]] = and i32 [[B:%.*]], 128
+; CHECK-NEXT:    [[C11:%.*]] = or i32 [[A1]], [[B1]]
+; CHECK-NEXT:    ret i32 [[C11]]
+;
+  %A1 = and i32 %A, 7
+  %B1 = and i32 %B, 128
+  %C1 = xor i32 %A1, %B1
+  ret i32 %C1
+}
+
+define i8 @test8(i1 %c) {
+; CHECK-LABEL: @test8(
+; CHECK-NEXT:    br i1 [[C:%.*]], label [[FALSE:%.*]], label [[TRUE:%.*]]
+; CHECK:       True:
+; CHECK-NEXT:    ret i8 1
+; CHECK:       False:
+; CHECK-NEXT:    ret i8 3
+;
+  %d = xor i1 %c, true
+  br i1 %d, label %True, label %False
+
+True:
+  ret i8 1
+
+False:
+  ret i8 3
+}
+
+define i1 @test9(i8 %A) {
+; CHECK-LABEL: @test9(
+; CHECK-NEXT:    [[C:%.*]] = icmp eq i8 [[A:%.*]], 89
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %B = xor i8 %A, 123
+  %C = icmp eq i8 %B, 34
+  ret i1 %C
+}
+
+define <2 x i1> @test9vec(<2 x i8> %a) {
+; CHECK-LABEL: @test9vec(
+; CHECK-NEXT:    [[C:%.*]] = icmp eq <2 x i8> [[A:%.*]], <i8 89, i8 89>
+; CHECK-NEXT:    ret <2 x i1> [[C]]
+;
+  %b = xor <2 x i8> %a, <i8 123, i8 123>
+  %c = icmp eq <2 x i8> %b, <i8 34, i8 34>
+  ret <2 x i1> %c
+}
+
+define i8 @test10(i8 %A) {
+; CHECK-LABEL: @test10(
+; CHECK-NEXT:    [[B:%.*]] = and i8 [[A:%.*]], 3
+; CHECK-NEXT:    [[C1:%.*]] = or i8 [[B]], 4
+; CHECK-NEXT:    ret i8 [[C1]]
+;
+  %B = and i8 %A, 3
+  %C = xor i8 %B, 4
+  ret i8 %C
+}
+
+define i8 @test11(i8 %A) {
+; CHECK-LABEL: @test11(
+; CHECK-NEXT:    [[B:%.*]] = and i8 [[A:%.*]], -13
+; CHECK-NEXT:    [[TMP1:%.*]] = or i8 [[B]], 8
+; CHECK-NEXT:    ret i8 [[TMP1]]
+;
+  %B = or i8 %A, 12
+  %C = xor i8 %B, 4
+  ret i8 %C
+}
+
+define i1 @test12(i8 %A) {
+; CHECK-LABEL: @test12(
+; CHECK-NEXT:    [[C:%.*]] = icmp ne i8 [[A:%.*]], 4
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %B = xor i8 %A, 4
+  %c = icmp ne i8 %B, 0
+  ret i1 %c
+}
+
+define <2 x i1> @test12vec(<2 x i8> %a) {
+; CHECK-LABEL: @test12vec(
+; CHECK-NEXT:    [[C:%.*]] = icmp ne <2 x i8> [[A:%.*]], <i8 4, i8 4>
+; CHECK-NEXT:    ret <2 x i1> [[C]]
+;
+  %b = xor <2 x i8> %a, <i8 4, i8 4>
+  %c = icmp ne <2 x i8> %b, zeroinitializer
+  ret <2 x i1> %c
+}
+
+define i32 @test18(i32 %A) {
+; CHECK-LABEL: @test18(
+; CHECK-NEXT:    [[C:%.*]] = add i32 [[A:%.*]], 124
+; CHECK-NEXT:    ret i32 [[C]]
+;
+  %B = xor i32 %A, -1
+  %C = sub i32 123, %B
+  ret i32 %C
+}
+
+define i32 @test19(i32 %A, i32 %B) {
+; CHECK-LABEL: @test19(
+; CHECK-NEXT:    ret i32 [[B:%.*]]
+;
+  %C = xor i32 %A, %B
+  %D = xor i32 %C, %A
+  ret i32 %D
+}
+
+define void @test20(i32 %A, i32 %B) {
+; CHECK-LABEL: @test20(
+; CHECK-NEXT:    store i32 [[B:%.*]], i32* @G1, align 4
+; CHECK-NEXT:    store i32 [[A:%.*]], i32* @G2, align 4
+; CHECK-NEXT:    ret void
+;
+  %t2 = xor i32 %B, %A
+  %t5 = xor i32 %t2, %B
+  %t8 = xor i32 %t5, %t2
+  store i32 %t8, i32* @G1
+  store i32 %t5, i32* @G2
+  ret void
+}
+
+define i32 @test22(i1 %X) {
+; CHECK-LABEL: @test22(
+; CHECK-NEXT:    [[Z:%.*]] = zext i1 [[X:%.*]] to i32
+; CHECK-NEXT:    ret i32 [[Z]]
+;
+  %Y = xor i1 %X, true
+  %Z = zext i1 %Y to i32
+  %Q = xor i32 %Z, 1
+  ret i32 %Q
+}
+
+; Look through a zext between xors.
+
+define i32 @fold_zext_xor_sandwich(i1 %X) {
+; CHECK-LABEL: @fold_zext_xor_sandwich(
+; CHECK-NEXT:    [[Z:%.*]] = zext i1 [[X:%.*]] to i32
+; CHECK-NEXT:    [[Q:%.*]] = xor i32 [[Z]], 3
+; CHECK-NEXT:    ret i32 [[Q]]
+;
+  %Y = xor i1 %X, true
+  %Z = zext i1 %Y to i32
+  %Q = xor i32 %Z, 2
+  ret i32 %Q
+}
+
+define <2 x i32> @fold_zext_xor_sandwich_vec(<2 x i1> %X) {
+; CHECK-LABEL: @fold_zext_xor_sandwich_vec(
+; CHECK-NEXT:    [[Z:%.*]] = zext <2 x i1> [[X:%.*]] to <2 x i32>
+; CHECK-NEXT:    [[Q:%.*]] = xor <2 x i32> [[Z]], <i32 3, i32 3>
+; CHECK-NEXT:    ret <2 x i32> [[Q]]
+;
+  %Y = xor <2 x i1> %X, <i1 true, i1 true>
+  %Z = zext <2 x i1> %Y to <2 x i32>
+  %Q = xor <2 x i32> %Z, <i32 2, i32 2>
+  ret <2 x i32> %Q
+}
+
+define i1 @test23(i32 %a, i32 %b) {
+; CHECK-LABEL: @test23(
+; CHECK-NEXT:    [[T4:%.*]] = icmp eq i32 [[B:%.*]], 0
+; CHECK-NEXT:    ret i1 [[T4]]
+;
+  %t2 = xor i32 %b, %a
+  %t4 = icmp eq i32 %t2, %a
+  ret i1 %t4
+}
+
+define i1 @test24(i32 %c, i32 %d) {
+; CHECK-LABEL: @test24(
+; CHECK-NEXT:    [[T4:%.*]] = icmp ne i32 [[D:%.*]], 0
+; CHECK-NEXT:    ret i1 [[T4]]
+;
+  %t2 = xor i32 %d, %c
+  %t4 = icmp ne i32 %t2, %c
+  ret i1 %t4
+}
+
+define i32 @test25(i32 %g, i32 %h) {
+; CHECK-LABEL: @test25(
+; CHECK-NEXT:    [[T4:%.*]] = and i32 [[H:%.*]], [[G:%.*]]
+; CHECK-NEXT:    ret i32 [[T4]]
+;
+  %h2 = xor i32 %h, -1
+  %t2 = and i32 %h2, %g
+  %t4 = xor i32 %t2, %g
+  ret i32 %t4
+}
+
+define i32 @test27(i32 %b, i32 %c, i32 %d) {
+; CHECK-LABEL: @test27(
+; CHECK-NEXT:    [[T6:%.*]] = icmp eq i32 [[B:%.*]], [[C:%.*]]
+; CHECK-NEXT:    [[T7:%.*]] = zext i1 [[T6]] to i32
+; CHECK-NEXT:    ret i32 [[T7]]
+;
+  %t2 = xor i32 %d, %b
+  %t5 = xor i32 %d, %c
+  %t6 = icmp eq i32 %t2, %t5
+  %t7 = zext i1 %t6 to i32
+  ret i32 %t7
+}
+
+define i32 @test28(i32 %indvar) {
+; CHECK-LABEL: @test28(
+; CHECK-NEXT:    [[T214:%.*]] = add i32 [[INDVAR:%.*]], 1
+; CHECK-NEXT:    ret i32 [[T214]]
+;
+  %t7 = add i32 %indvar, -2147483647
+  %t214 = xor i32 %t7, -2147483648
+  ret i32 %t214
+}
+
+define <2 x i32> @test28vec(<2 x i32> %indvar) {
+; CHECK-LABEL: @test28vec(
+; CHECK-NEXT:    [[T214:%.*]] = add <2 x i32> [[INDVAR:%.*]], <i32 1, i32 1>
+; CHECK-NEXT:    ret <2 x i32> [[T214]]
+;
+  %t7 = add <2 x i32> %indvar, <i32 -2147483647, i32 -2147483647>
+  %t214 = xor <2 x i32> %t7, <i32 -2147483648, i32 -2147483648>
+  ret <2 x i32> %t214
+}
+
+define i32 @test28_sub(i32 %indvar) {
+; CHECK-LABEL: @test28_sub(
+; CHECK-NEXT:    [[T214:%.*]] = sub i32 1, [[INDVAR:%.*]]
+; CHECK-NEXT:    ret i32 [[T214]]
+;
+  %t7 = sub i32 -2147483647, %indvar
+  %t214 = xor i32 %t7, -2147483648
+  ret i32 %t214
+}
+
+define <2 x i32> @test28_subvec(<2 x i32> %indvar) {
+; CHECK-LABEL: @test28_subvec(
+; CHECK-NEXT:    [[T214:%.*]] = sub <2 x i32> <i32 1, i32 1>, [[INDVAR:%.*]]
+; CHECK-NEXT:    ret <2 x i32> [[T214]]
+;
+  %t7 = sub <2 x i32> <i32 -2147483647, i32 -2147483647>, %indvar
+  %t214 = xor <2 x i32> %t7, <i32 -2147483648, i32 -2147483648>
+  ret <2 x i32> %t214
+}
+
+define i32 @test29(i1 %C) {
+; CHECK-LABEL: @test29(
+; CHECK-NEXT:    [[V:%.*]] = select i1 [[C:%.*]], i32 915, i32 113
+; CHECK-NEXT:    ret i32 [[V]]
+;
+  %A = select i1 %C, i32 1000, i32 10
+  %V = xor i32 %A, 123
+  ret i32 %V
+}
+
+define <2 x i32> @test29vec(i1 %C) {
+; CHECK-LABEL: @test29vec(
+; CHECK-NEXT:    [[V:%.*]] = select i1 [[C:%.*]], <2 x i32> <i32 915, i32 915>, <2 x i32> <i32 113, i32 113>
+; CHECK-NEXT:    ret <2 x i32> [[V]]
+;
+  %A = select i1 %C, <2 x i32> <i32 1000, i32 1000>, <2 x i32> <i32 10, i32 10>
+  %V = xor <2 x i32> %A, <i32 123, i32 123>
+  ret <2 x i32> %V
+}
+
+define <2 x i32> @test29vec2(i1 %C) {
+; CHECK-LABEL: @test29vec2(
+; CHECK-NEXT:    [[V:%.*]] = select i1 [[C:%.*]], <2 x i32> <i32 915, i32 2185>, <2 x i32> <i32 113, i32 339>
+; CHECK-NEXT:    ret <2 x i32> [[V]]
+;
+  %A = select i1 %C, <2 x i32> <i32 1000, i32 2500>, <2 x i32> <i32 10, i32 30>
+  %V = xor <2 x i32> %A, <i32 123, i32 333>
+  ret <2 x i32> %V
+}
+
+define i32 @test30(i1 %which) {
+; CHECK-LABEL: @test30(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    br i1 [[WHICH:%.*]], label [[FINAL:%.*]], label [[DELAY:%.*]]
+; CHECK:       delay:
+; CHECK-NEXT:    br label [[FINAL]]
+; CHECK:       final:
+; CHECK-NEXT:    [[A:%.*]] = phi i32 [ 915, [[ENTRY:%.*]] ], [ 113, [[DELAY]] ]
+; CHECK-NEXT:    ret i32 [[A]]
+;
+entry:
+  br i1 %which, label %final, label %delay
+
+delay:
+  br label %final
+
+final:
+  %A = phi i32 [ 1000, %entry ], [ 10, %delay ]
+  %value = xor i32 %A, 123
+  ret i32 %value
+}
+
+define <2 x i32> @test30vec(i1 %which) {
+; CHECK-LABEL: @test30vec(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    br i1 [[WHICH:%.*]], label [[FINAL:%.*]], label [[DELAY:%.*]]
+; CHECK:       delay:
+; CHECK-NEXT:    br label [[FINAL]]
+; CHECK:       final:
+; CHECK-NEXT:    [[A:%.*]] = phi <2 x i32> [ <i32 915, i32 915>, [[ENTRY:%.*]] ], [ <i32 113, i32 113>, [[DELAY]] ]
+; CHECK-NEXT:    ret <2 x i32> [[A]]
+;
+entry:
+  br i1 %which, label %final, label %delay
+
+delay:
+  br label %final
+
+final:
+  %A = phi <2 x i32> [ <i32 1000, i32 1000>, %entry ], [ <i32 10, i32 10>, %delay ]
+  %value = xor <2 x i32> %A, <i32 123, i32 123>
+  ret <2 x i32> %value
+}
+
+define <2 x i32> @test30vec2(i1 %which) {
+; CHECK-LABEL: @test30vec2(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    br i1 [[WHICH:%.*]], label [[FINAL:%.*]], label [[DELAY:%.*]]
+; CHECK:       delay:
+; CHECK-NEXT:    br label [[FINAL]]
+; CHECK:       final:
+; CHECK-NEXT:    [[A:%.*]] = phi <2 x i32> [ <i32 915, i32 2185>, [[ENTRY:%.*]] ], [ <i32 113, i32 339>, [[DELAY]] ]
+; CHECK-NEXT:    ret <2 x i32> [[A]]
+;
+entry:
+  br i1 %which, label %final, label %delay
+
+delay:
+  br label %final
+
+final:
+  %A = phi <2 x i32> [ <i32 1000, i32 2500>, %entry ], [ <i32 10, i32 30>, %delay ]
+  %value = xor <2 x i32> %A, <i32 123, i32 333>
+  ret <2 x i32> %value
+}
+
+; B ^ (B | A) --> A & ~B
+; The division ops are here to thwart complexity-based canonicalization: all ops are binops.
+
+define i32 @or_xor_commute1(i32 %p1, i32 %p2) {
+; CHECK-LABEL: @or_xor_commute1(
+; CHECK-NEXT:    [[A:%.*]] = udiv i32 42, [[P1:%.*]]
+; CHECK-NEXT:    [[B:%.*]] = udiv i32 42, [[P2:%.*]]
+; CHECK-NEXT:    [[TMP1:%.*]] = xor i32 [[B]], -1
+; CHECK-NEXT:    [[R:%.*]] = and i32 [[A]], [[TMP1]]
+; CHECK-NEXT:    ret i32 [[R]]
+;
+  %a = udiv i32 42, %p1
+  %b = udiv i32 42, %p2
+  %o = or i32 %b, %a
+  %r = xor i32 %b, %o
+  ret i32 %r
+}
+
+; B ^ (B | A) --> A & ~B
+; The division ops are here to thwart complexity-based canonicalization: all ops are binops.
+
+define i32 @or_xor_commute2(i32 %p1, i32 %p2) {
+; CHECK-LABEL: @or_xor_commute2(
+; CHECK-NEXT:    [[A:%.*]] = udiv i32 42, [[P1:%.*]]
+; CHECK-NEXT:    [[B:%.*]] = udiv i32 42, [[P2:%.*]]
+; CHECK-NEXT:    [[TMP1:%.*]] = xor i32 [[B]], -1
+; CHECK-NEXT:    [[R:%.*]] = and i32 [[A]], [[TMP1]]
+; CHECK-NEXT:    ret i32 [[R]]
+;
+  %a = udiv i32 42, %p1
+  %b = udiv i32 42, %p2
+  %o = or i32 %a, %b
+  %r = xor i32 %o, %b
+  ret i32 %r
+}
+
+; B ^ (B | A) --> A & ~B
+; The division ops are here to thwart complexity-based canonicalization: all ops are binops.
+
+define i32 @or_xor_commute3(i32 %p1, i32 %p2) {
+; CHECK-LABEL: @or_xor_commute3(
+; CHECK-NEXT:    [[A:%.*]] = udiv i32 42, [[P1:%.*]]
+; CHECK-NEXT:    [[B:%.*]] = udiv i32 42, [[P2:%.*]]
+; CHECK-NEXT:    [[TMP1:%.*]] = xor i32 [[B]], -1
+; CHECK-NEXT:    [[R:%.*]] = and i32 [[A]], [[TMP1]]
+; CHECK-NEXT:    ret i32 [[R]]
+;
+  %a = udiv i32 42, %p1
+  %b = udiv i32 42, %p2
+  %o = or i32 %b, %a
+  %r = xor i32 %o, %b
+  ret i32 %r
+}
+
+; B ^ (B | A) --> A & ~B
+; The division ops are here to thwart complexity-based canonicalization: all ops are binops.
+
+define i32 @or_xor_commute4(i32 %p1, i32 %p2) {
+; CHECK-LABEL: @or_xor_commute4(
+; CHECK-NEXT:    [[A:%.*]] = udiv i32 42, [[P1:%.*]]
+; CHECK-NEXT:    [[B:%.*]] = udiv i32 42, [[P2:%.*]]
+; CHECK-NEXT:    [[TMP1:%.*]] = xor i32 [[B]], -1
+; CHECK-NEXT:    [[R:%.*]] = and i32 [[A]], [[TMP1]]
+; CHECK-NEXT:    ret i32 [[R]]
+;
+  %a = udiv i32 42, %p1
+  %b = udiv i32 42, %p2
+  %o = or i32 %a, %b
+  %r = xor i32 %b, %o
+  ret i32 %r
+}
+
+define i32 @or_xor_extra_use(i32 %a, i32 %b, i32* %p) {
+; CHECK-LABEL: @or_xor_extra_use(
+; CHECK-NEXT:    [[O:%.*]] = or i32 [[A:%.*]], [[B:%.*]]
+; CHECK-NEXT:    store i32 [[O]], i32* [[P:%.*]], align 4
+; CHECK-NEXT:    [[R:%.*]] = xor i32 [[O]], [[B]]
+; CHECK-NEXT:    ret i32 [[R]]
+;
+  %o = or i32 %a, %b
+  store i32 %o, i32* %p
+  %r = xor i32 %b, %o
+  ret i32 %r
+}
+
+; B ^ (B & A) --> ~A & B
+; The division ops are here to thwart complexity-based canonicalization: all ops are binops.
+
+define i32 @and_xor_commute1(i32 %p1, i32 %p2) {
+; CHECK-LABEL: @and_xor_commute1(
+; CHECK-NEXT:    [[A:%.*]] = udiv i32 42, [[P1:%.*]]
+; CHECK-NEXT:    [[B:%.*]] = udiv i32 42, [[P2:%.*]]
+; CHECK-NEXT:    [[TMP1:%.*]] = xor i32 [[A]], -1
+; CHECK-NEXT:    [[R:%.*]] = and i32 [[B]], [[TMP1]]
+; CHECK-NEXT:    ret i32 [[R]]
+;
+  %a = udiv i32 42, %p1
+  %b = udiv i32 42, %p2
+  %o = and i32 %b, %a
+  %r = xor i32 %b, %o
+  ret i32 %r
+}
+
+; B ^ (B & A) --> ~A & B
+; The division ops are here to thwart complexity-based canonicalization: all ops are binops.
+
+define i32 @and_xor_commute2(i32 %p1, i32 %p2) {
+; CHECK-LABEL: @and_xor_commute2(
+; CHECK-NEXT:    [[A:%.*]] = udiv i32 42, [[P1:%.*]]
+; CHECK-NEXT:    [[B:%.*]] = udiv i32 42, [[P2:%.*]]
+; CHECK-NEXT:    [[TMP1:%.*]] = xor i32 [[A]], -1
+; CHECK-NEXT:    [[R:%.*]] = and i32 [[B]], [[TMP1]]
+; CHECK-NEXT:    ret i32 [[R]]
+;
+  %a = udiv i32 42, %p1
+  %b = udiv i32 42, %p2
+  %o = and i32 %a, %b
+  %r = xor i32 %o, %b
+  ret i32 %r
+}
+
+; B ^ (B & A) --> ~A & B
+; The division ops are here to thwart complexity-based canonicalization: all ops are binops.
+
+define i32 @and_xor_commute3(i32 %p1, i32 %p2) {
+; CHECK-LABEL: @and_xor_commute3(
+; CHECK-NEXT:    [[A:%.*]] = udiv i32 42, [[P1:%.*]]
+; CHECK-NEXT:    [[B:%.*]] = udiv i32 42, [[P2:%.*]]
+; CHECK-NEXT:    [[TMP1:%.*]] = xor i32 [[A]], -1
+; CHECK-NEXT:    [[R:%.*]] = and i32 [[B]], [[TMP1]]
+; CHECK-NEXT:    ret i32 [[R]]
+;
+  %a = udiv i32 42, %p1
+  %b = udiv i32 42, %p2
+  %o = and i32 %b, %a
+  %r = xor i32 %o, %b
+  ret i32 %r
+}
+
+; B ^ (B & A) --> ~A & B
+; The division ops are here to thwart complexity-based canonicalization: all ops are binops.
+
+define i32 @and_xor_commute4(i32 %p1, i32 %p2) {
+; CHECK-LABEL: @and_xor_commute4(
+; CHECK-NEXT:    [[A:%.*]] = udiv i32 42, [[P1:%.*]]
+; CHECK-NEXT:    [[B:%.*]] = udiv i32 42, [[P2:%.*]]
+; CHECK-NEXT:    [[TMP1:%.*]] = xor i32 [[A]], -1
+; CHECK-NEXT:    [[R:%.*]] = and i32 [[B]], [[TMP1]]
+; CHECK-NEXT:    ret i32 [[R]]
+;
+  %a = udiv i32 42, %p1
+  %b = udiv i32 42, %p2
+  %o = and i32 %a, %b
+  %r = xor i32 %b, %o
+  ret i32 %r
+}
+
+define i32 @and_xor_extra_use(i32 %a, i32 %b, i32* %p) {
+; CHECK-LABEL: @and_xor_extra_use(
+; CHECK-NEXT:    [[O:%.*]] = and i32 [[A:%.*]], [[B:%.*]]
+; CHECK-NEXT:    store i32 [[O]], i32* [[P:%.*]], align 4
+; CHECK-NEXT:    [[R:%.*]] = xor i32 [[O]], [[B]]
+; CHECK-NEXT:    ret i32 [[R]]
+;
+  %o = and i32 %a, %b
+  store i32 %o, i32* %p
+  %r = xor i32 %b, %o
+  ret i32 %r
+}
+
+; (~X | C2) ^ C1 --> ((X & ~C2) ^ -1) ^ C1 --> (X & ~C2) ^ ~C1
+; The extra use (store) is here because the simpler case
+; may be transformed using demanded bits.
+
+define i8 @xor_or_not(i8 %x, i8* %p) {
+; CHECK-LABEL: @xor_or_not(
+; CHECK-NEXT:    [[NX:%.*]] = xor i8 [[X:%.*]], -1
+; CHECK-NEXT:    store i8 [[NX]], i8* [[P:%.*]], align 1
+; CHECK-NEXT:    [[TMP1:%.*]] = and i8 [[X]], -8
+; CHECK-NEXT:    [[R:%.*]] = xor i8 [[TMP1]], -13
+; CHECK-NEXT:    ret i8 [[R]]
+;
+  %nx = xor i8 %x, -1
+  store i8 %nx, i8* %p
+  %or = or i8 %nx, 7
+  %r = xor i8 %or, 12
+  ret i8 %r
+}
+
+; Don't do this if the 'or' has extra uses.
+
+define i8 @xor_or_not_uses(i8 %x, i8* %p) {
+; CHECK-LABEL: @xor_or_not_uses(
+; CHECK-NEXT:    [[TMP1:%.*]] = or i8 [[X:%.*]], 7
+; CHECK-NEXT:    [[OR:%.*]] = xor i8 [[TMP1]], -8
+; CHECK-NEXT:    store i8 [[OR]], i8* [[P:%.*]], align 1
+; CHECK-NEXT:    [[R:%.*]] = xor i8 [[TMP1]], -12
+; CHECK-NEXT:    ret i8 [[R]]
+;
+  %nx = xor i8 %x, -1
+  %or = or i8 %nx, 7
+  store i8 %or, i8* %p
+  %r = xor i8 %or, 12
+  ret i8 %r
+}
+
+; (~X & C2) ^ C1 --> ((X | ~C2) ^ -1) ^ C1 --> (X | ~C2) ^ ~C1
+; The extra use (store) is here because the simpler case
+; may be transformed using demanded bits.
+
+define i8 @xor_and_not(i8 %x, i8* %p) {
+; CHECK-LABEL: @xor_and_not(
+; CHECK-NEXT:    [[NX:%.*]] = xor i8 [[X:%.*]], -1
+; CHECK-NEXT:    store i8 [[NX]], i8* [[P:%.*]], align 1
+; CHECK-NEXT:    [[TMP1:%.*]] = or i8 [[X]], -43
+; CHECK-NEXT:    [[R:%.*]] = xor i8 [[TMP1]], -32
+; CHECK-NEXT:    ret i8 [[R]]
+;
+  %nx = xor i8 %x, -1
+  store i8 %nx, i8* %p
+  %and = and i8 %nx, 42
+  %r = xor i8 %and, 31
+  ret i8 %r
+}
+
+; Don't do this if the 'and' has extra uses.
+
+define i8 @xor_and_not_uses(i8 %x, i8* %p) {
+; CHECK-LABEL: @xor_and_not_uses(
+; CHECK-NEXT:    [[NX:%.*]] = and i8 [[X:%.*]], 42
+; CHECK-NEXT:    [[AND:%.*]] = xor i8 [[NX]], 42
+; CHECK-NEXT:    store i8 [[AND]], i8* [[P:%.*]], align 1
+; CHECK-NEXT:    [[R:%.*]] = xor i8 [[NX]], 53
+; CHECK-NEXT:    ret i8 [[R]]
+;
+  %nx = xor i8 %x, -1
+  %and = and i8 %nx, 42
+  store i8 %and, i8* %p
+  %r = xor i8 %and, 31
+  ret i8 %r
+}
+
+; The tests 39-47 are related to the canonicalization:
+; %notx = xor i32 %x, -1
+; %cmp = icmp sgt i32 %notx, %y
+; %smax = select i1 %cmp, i32 %notx, i32 %y
+; %res = xor i32 %smax, -1
+;   =>
+; %noty = xor i32 %y, -1
+; %cmp2 = icmp slt %x, %noty
+; %res = select i1 %cmp2, i32 %x, i32 %noty
+;
+; Same transformations is valid for smin/umax/umin.
+
+define i32 @test39(i32 %x) {
+; CHECK-LABEL: @test39(
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp slt i32 [[X:%.*]], 255
+; CHECK-NEXT:    [[RES:%.*]] = select i1 [[TMP1]], i32 [[X]], i32 255
+; CHECK-NEXT:    ret i32 [[RES]]
+;
+  %1 = xor i32 %x, -1
+  %2 = icmp sgt i32 %1, -256
+  %3 = select i1 %2, i32 %1, i32 -256
+  %res = xor i32 %3, -1
+  ret i32 %res
+}
+
+define i32 @test40(i32 %x, i32 %y) {
+; CHECK-LABEL: @test40(
+; CHECK-NEXT:    [[TMP1:%.*]] = xor i32 [[Y:%.*]], -1
+; CHECK-NEXT:    [[TMP2:%.*]] = icmp sgt i32 [[TMP1]], [[X:%.*]]
+; CHECK-NEXT:    [[RES:%.*]] = select i1 [[TMP2]], i32 [[X]], i32 [[TMP1]]
+; CHECK-NEXT:    ret i32 [[RES]]
+;
+  %notx = xor i32 %x, -1
+  %cmp1 = icmp sgt i32 %notx, %y
+  %smax = select i1 %cmp1, i32 %notx, i32 %y
+  %res = xor i32 %smax, -1
+  ret i32 %res
+}
+
+define i32 @test41(i32 %x, i32 %y) {
+; CHECK-LABEL: @test41(
+; CHECK-NEXT:    [[TMP1:%.*]] = xor i32 [[Y:%.*]], -1
+; CHECK-NEXT:    [[TMP2:%.*]] = icmp slt i32 [[TMP1]], [[X:%.*]]
+; CHECK-NEXT:    [[RES:%.*]] = select i1 [[TMP2]], i32 [[X]], i32 [[TMP1]]
+; CHECK-NEXT:    ret i32 [[RES]]
+;
+  %notx = xor i32 %x, -1
+  %cmp1 = icmp slt i32 %notx, %y
+  %smin = select i1 %cmp1, i32 %notx, i32 %y
+  %res = xor i32 %smin, -1
+  ret i32 %res
+}
+
+define i32 @test42(i32 %x, i32 %y) {
+; CHECK-LABEL: @test42(
+; CHECK-NEXT:    [[TMP1:%.*]] = xor i32 [[Y:%.*]], -1
+; CHECK-NEXT:    [[TMP2:%.*]] = icmp ugt i32 [[TMP1]], [[X:%.*]]
+; CHECK-NEXT:    [[RES:%.*]] = select i1 [[TMP2]], i32 [[X]], i32 [[TMP1]]
+; CHECK-NEXT:    ret i32 [[RES]]
+;
+  %notx = xor i32 %x, -1
+  %cmp1 = icmp ugt i32 %notx, %y
+  %umax = select i1 %cmp1, i32 %notx, i32 %y
+  %res = xor i32 %umax, -1
+  ret i32 %res
+}
+
+define i32 @test43(i32 %x, i32 %y) {
+; CHECK-LABEL: @test43(
+; CHECK-NEXT:    [[TMP1:%.*]] = xor i32 [[Y:%.*]], -1
+; CHECK-NEXT:    [[TMP2:%.*]] = icmp ult i32 [[TMP1]], [[X:%.*]]
+; CHECK-NEXT:    [[RES:%.*]] = select i1 [[TMP2]], i32 [[X]], i32 [[TMP1]]
+; CHECK-NEXT:    ret i32 [[RES]]
+;
+  %notx = xor i32 %x, -1
+  %cmp1 = icmp ult i32 %notx, %y
+  %umin = select i1 %cmp1, i32 %notx, i32 %y
+  %res = xor i32 %umin, -1
+  ret i32 %res
+}
+
+define i32 @test44(i32 %x, i32 %y) {
+; CHECK-LABEL: @test44(
+; CHECK-NEXT:    [[TMP1:%.*]] = sub i32 -4, [[Y:%.*]]
+; CHECK-NEXT:    [[TMP2:%.*]] = icmp ugt i32 [[TMP1]], [[X:%.*]]
+; CHECK-NEXT:    [[RES:%.*]] = select i1 [[TMP2]], i32 [[TMP1]], i32 [[X]]
+; CHECK-NEXT:    ret i32 [[RES]]
+;
+  %z = add i32 %y, 3 ; thwart complexity-based canonicalization
+  %notx = xor i32 %x, -1
+  %cmp1 = icmp ult i32 %z, %notx
+  %umin = select i1 %cmp1, i32 %z, i32 %notx
+  %res = xor i32 %umin, -1
+  ret i32 %res
+}
+
+define i32 @test45(i32 %x, i32 %y) {
+; CHECK-LABEL: @test45(
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp ult i32 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    [[TMP2:%.*]] = select i1 [[TMP1]], i32 [[Y]], i32 [[X]]
+; CHECK-NEXT:    ret i32 [[TMP2]]
+;
+  %z = xor i32 %y, -1
+  %notx = xor i32 %x, -1
+  %cmp1 = icmp ult i32 %z, %notx
+  %umin = select i1 %cmp1, i32 %z, i32 %notx
+  %res = xor i32 %umin, -1
+  ret i32 %res
+}
+
+; Check that we work with splat vectors also.
+define <4 x i32> @test46(<4 x i32> %x) {
+; CHECK-LABEL: @test46(
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp slt <4 x i32> [[X:%.*]], <i32 255, i32 255, i32 255, i32 255>
+; CHECK-NEXT:    [[TMP2:%.*]] = select <4 x i1> [[TMP1]], <4 x i32> [[X]], <4 x i32> <i32 255, i32 255, i32 255, i32 255>
+; CHECK-NEXT:    ret <4 x i32> [[TMP2]]
+;
+  %1 = xor <4 x i32> %x, <i32 -1, i32 -1, i32 -1, i32 -1>
+  %2 = icmp sgt <4 x i32> %1, <i32 -256, i32 -256, i32 -256, i32 -256>
+  %3 = select <4 x i1> %2, <4 x i32> %1, <4 x i32> <i32 -256, i32 -256, i32 -256, i32 -256>
+  %4 = xor <4 x i32> %3, <i32 -1, i32 -1, i32 -1, i32 -1>
+  ret <4 x i32> %4
+}
+
+; Test case when select pattern has more than one use.
+define i32 @test47(i32 %x, i32 %y, i32 %z) {
+; CHECK-LABEL: @test47(
+; CHECK-NEXT:    [[NOTX:%.*]] = xor i32 [[X:%.*]], -1
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp ugt i32 [[NOTX]], [[Y:%.*]]
+; CHECK-NEXT:    [[UMAX:%.*]] = select i1 [[CMP1]], i32 [[NOTX]], i32 [[Y]]
+; CHECK-NEXT:    [[UMIN:%.*]] = xor i32 [[UMAX]], -1
+; CHECK-NEXT:    [[ADD:%.*]] = add i32 [[UMAX]], [[Z:%.*]]
+; CHECK-NEXT:    [[RES:%.*]] = mul i32 [[ADD]], [[UMIN]]
+; CHECK-NEXT:    ret i32 [[RES]]
+;
+  %notx = xor i32 %x, -1
+  %cmp1 = icmp ugt i32 %notx, %y
+  %umax = select i1 %cmp1, i32 %notx, i32 %y
+  %umin = xor i32 %umax, -1
+  %add = add i32 %umax, %z
+  %res = mul i32 %umin, %add
+  ret i32 %res
+}
+
+define i32 @test48(i32 %x) {
+; CHECK-LABEL: @test48(
+; CHECK-NEXT:    [[TMP1:%.*]] = add i32 [[X:%.*]], 1
+; CHECK-NEXT:    [[TMP2:%.*]] = icmp slt i32 [[TMP1]], -1
+; CHECK-NEXT:    [[D:%.*]] = select i1 [[TMP2]], i32 [[TMP1]], i32 -1
+; CHECK-NEXT:    ret i32 [[D]]
+;
+  %a = sub i32 -2, %x
+  %b = icmp sgt i32 %a, 0
+  %c = select i1 %b, i32 %a, i32 0
+  %d = xor i32 %c, -1
+  ret i32 %d
+}
+
+define <2 x i32> @test48vec(<2 x i32> %x) {
+; CHECK-LABEL: @test48vec(
+; CHECK-NEXT:    [[TMP1:%.*]] = add <2 x i32> [[X:%.*]], <i32 1, i32 1>
+; CHECK-NEXT:    [[TMP2:%.*]] = icmp slt <2 x i32> [[TMP1]], <i32 -1, i32 -1>
+; CHECK-NEXT:    [[D:%.*]] = select <2 x i1> [[TMP2]], <2 x i32> [[TMP1]], <2 x i32> <i32 -1, i32 -1>
+; CHECK-NEXT:    ret <2 x i32> [[D]]
+;
+  %a = sub <2 x i32> <i32 -2, i32 -2>, %x
+  %b = icmp sgt <2 x i32> %a, zeroinitializer
+  %c = select <2 x i1> %b, <2 x i32> %a, <2 x i32> zeroinitializer
+  %d = xor <2 x i32> %c, <i32 -1, i32 -1>
+  ret <2 x i32> %d
+}
+
+define i32 @test49(i32 %x) {
+; CHECK-LABEL: @test49(
+; CHECK-NEXT:    [[TMP1:%.*]] = sub i32 1, [[X:%.*]]
+; CHECK-NEXT:    [[TMP2:%.*]] = icmp sgt i32 [[TMP1]], 0
+; CHECK-NEXT:    [[D:%.*]] = select i1 [[TMP2]], i32 [[TMP1]], i32 0
+; CHECK-NEXT:    ret i32 [[D]]
+;
+  %a = add i32 %x, -2
+  %b = icmp slt i32 %a, -1
+  %c = select i1 %b, i32 %a, i32 -1
+  %d = xor i32 %c, -1
+  ret i32 %d
+}
+
+define <2 x i32> @test49vec(<2 x i32> %x) {
+; CHECK-LABEL: @test49vec(
+; CHECK-NEXT:    [[TMP1:%.*]] = sub <2 x i32> <i32 1, i32 1>, [[X:%.*]]
+; CHECK-NEXT:    [[TMP2:%.*]] = icmp sgt <2 x i32> [[TMP1]], zeroinitializer
+; CHECK-NEXT:    [[D:%.*]] = select <2 x i1> [[TMP2]], <2 x i32> [[TMP1]], <2 x i32> zeroinitializer
+; CHECK-NEXT:    ret <2 x i32> [[D]]
+;
+  %a = add <2 x i32> %x, <i32 -2, i32 -2>
+  %b = icmp slt <2 x i32> %a, <i32 -1, i32 -1>
+  %c = select <2 x i1> %b, <2 x i32> %a, <2 x i32> <i32 -1, i32 -1>
+  %d = xor <2 x i32> %c, <i32 -1, i32 -1>
+  ret <2 x i32> %d
+}
+
+define i32 @test50(i32 %x, i32 %y) {
+; CHECK-LABEL: @test50(
+; CHECK-NEXT:    [[TMP1:%.*]] = sub i32 1, [[X:%.*]]
+; CHECK-NEXT:    [[TMP2:%.*]] = add i32 [[Y:%.*]], 1
+; CHECK-NEXT:    [[TMP3:%.*]] = icmp slt i32 [[TMP2]], [[TMP1]]
+; CHECK-NEXT:    [[E:%.*]] = select i1 [[TMP3]], i32 [[TMP1]], i32 [[TMP2]]
+; CHECK-NEXT:    ret i32 [[E]]
+;
+  %a = add i32 %x, -2
+  %b = sub i32 -2, %y
+  %c = icmp slt i32 %a, %b
+  %d = select i1 %c, i32 %a, i32 %b
+  %e = xor i32 %d, -1
+  ret i32 %e
+}
+
+define <2 x i32> @test50vec(<2 x i32> %x, <2 x i32> %y) {
+; CHECK-LABEL: @test50vec(
+; CHECK-NEXT:    [[TMP1:%.*]] = sub <2 x i32> <i32 1, i32 1>, [[X:%.*]]
+; CHECK-NEXT:    [[TMP2:%.*]] = add <2 x i32> [[Y:%.*]], <i32 1, i32 1>
+; CHECK-NEXT:    [[TMP3:%.*]] = icmp slt <2 x i32> [[TMP2]], [[TMP1]]
+; CHECK-NEXT:    [[E:%.*]] = select <2 x i1> [[TMP3]], <2 x i32> [[TMP1]], <2 x i32> [[TMP2]]
+; CHECK-NEXT:    ret <2 x i32> [[E]]
+;
+  %a = add <2 x i32> %x, <i32 -2, i32 -2>
+  %b = sub <2 x i32> <i32 -2, i32 -2>, %y
+  %c = icmp slt <2 x i32> %a, %b
+  %d = select <2 x i1> %c, <2 x i32> %a, <2 x i32> %b
+  %e = xor <2 x i32> %d, <i32 -1, i32 -1>
+  ret <2 x i32> %e
+}
+
+define i32 @test51(i32 %x, i32 %y) {
+; CHECK-LABEL: @test51(
+; CHECK-NEXT:    [[TMP1:%.*]] = sub i32 -3, [[X:%.*]]
+; CHECK-NEXT:    [[TMP2:%.*]] = add i32 [[Y:%.*]], -3
+; CHECK-NEXT:    [[TMP3:%.*]] = icmp sgt i32 [[TMP2]], [[TMP1]]
+; CHECK-NEXT:    [[E:%.*]] = select i1 [[TMP3]], i32 [[TMP1]], i32 [[TMP2]]
+; CHECK-NEXT:    ret i32 [[E]]
+;
+  %a = add i32 %x, 2
+  %b = sub i32 2, %y
+  %c = icmp sgt i32 %a, %b
+  %d = select i1 %c, i32 %a, i32 %b
+  %e = xor i32 %d, -1
+  ret i32 %e
+}
+
+define <2 x i32> @test51vec(<2 x i32> %x, <2 x i32> %y) {
+; CHECK-LABEL: @test51vec(
+; CHECK-NEXT:    [[TMP1:%.*]] = sub <2 x i32> <i32 -3, i32 -3>, [[X:%.*]]
+; CHECK-NEXT:    [[TMP2:%.*]] = add <2 x i32> [[Y:%.*]], <i32 -3, i32 -3>
+; CHECK-NEXT:    [[TMP3:%.*]] = icmp sgt <2 x i32> [[TMP2]], [[TMP1]]
+; CHECK-NEXT:    [[E:%.*]] = select <2 x i1> [[TMP3]], <2 x i32> [[TMP1]], <2 x i32> [[TMP2]]
+; CHECK-NEXT:    ret <2 x i32> [[E]]
+;
+  %a = add <2 x i32> %x, <i32 2, i32 2>
+  %b = sub <2 x i32> <i32 2, i32 2>, %y
+  %c = icmp sgt <2 x i32> %a, %b
+  %d = select <2 x i1> %c, <2 x i32> %a, <2 x i32> %b
+  %e = xor <2 x i32> %d, <i32 -1, i32 -1>
+  ret <2 x i32> %e
+}

Added: llvm/trunk/test/Transforms/InstCombine/xor2.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/xor2.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/xor2.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/xor2.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,513 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt < %s -instcombine -S | FileCheck %s
+
+; PR1253
+define i1 @test0(i32 %A) {
+; CHECK-LABEL: @test0(
+; CHECK-NEXT:    [[C:%.*]] = icmp slt i32 [[A:%.*]], 0
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %B = xor i32 %A, -2147483648
+  %C = icmp sgt i32 %B, -1
+  ret i1 %C
+}
+
+define <2 x i1> @test0vec(<2 x i32> %A) {
+; CHECK-LABEL: @test0vec(
+; CHECK-NEXT:    [[C:%.*]] = icmp slt <2 x i32> [[A:%.*]], zeroinitializer
+; CHECK-NEXT:    ret <2 x i1> [[C]]
+;
+  %B = xor <2 x i32> %A, <i32 -2147483648, i32 -2147483648>
+  %C = icmp sgt <2 x i32> %B, <i32 -1, i32 -1>
+  ret <2 x i1> %C
+}
+
+define i1 @test1(i32 %A) {
+; CHECK-LABEL: @test1(
+; CHECK-NEXT:    [[C:%.*]] = icmp slt i32 [[A:%.*]], 0
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %B = xor i32 %A, 12345
+  %C = icmp slt i32 %B, 0
+  ret i1 %C
+}
+
+; PR1014
+define i32 @test2(i32 %tmp1) {
+; CHECK-LABEL: @test2(
+; CHECK-NEXT:    [[OVM:%.*]] = and i32 [[TMP1:%.*]], 32
+; CHECK-NEXT:    [[OV1101:%.*]] = or i32 [[OVM]], 8
+; CHECK-NEXT:    ret i32 [[OV1101]]
+;
+  %ovm = and i32 %tmp1, 32
+  %ov3 = add i32 %ovm, 145
+  %ov110 = xor i32 %ov3, 153
+  ret i32 %ov110
+}
+
+define i32 @test3(i32 %tmp1) {
+; CHECK-LABEL: @test3(
+; CHECK-NEXT:    [[OVM:%.*]] = and i32 [[TMP1:%.*]], 32
+; CHECK-NEXT:    [[OV1101:%.*]] = or i32 [[OVM]], 8
+; CHECK-NEXT:    ret i32 [[OV1101]]
+;
+  %ovm = or i32 %tmp1, 145
+  %ov31 = and i32 %ovm, 177
+  %ov110 = xor i32 %ov31, 153
+  ret i32 %ov110
+}
+
+; defect-2 in rdar://12329730
+; (X^C1) >> C2) ^ C3 -> (X>>C2) ^ ((C1>>C2)^C3)
+;   where the "X" has more than one use
+define i32 @test5(i32 %val1) {
+; CHECK-LABEL: @test5(
+; CHECK-NEXT:    [[XOR:%.*]] = xor i32 [[VAL1:%.*]], 1234
+; CHECK-NEXT:    [[SHR:%.*]] = lshr i32 [[VAL1]], 8
+; CHECK-NEXT:    [[XOR1:%.*]] = xor i32 [[SHR]], 5
+; CHECK-NEXT:    [[ADD:%.*]] = add i32 [[XOR1]], [[XOR]]
+; CHECK-NEXT:    ret i32 [[ADD]]
+;
+  %xor = xor i32 %val1, 1234
+  %shr = lshr i32 %xor, 8
+  %xor1 = xor i32 %shr, 1
+  %add = add i32 %xor1, %xor
+  ret i32 %add
+}
+
+; defect-1 in rdar://12329730
+; Simplify (X^Y) -> X or Y in the user's context if we know that
+; only bits from X or Y are demanded.
+; e.g. the "x ^ 1234" can be optimized into x in the context of "t >> 16".
+;  Put in other word, t >> 16 -> x >> 16.
+; unsigned foo(unsigned x) { unsigned t = x ^ 1234; ;  return (t >> 16) + t;}
+define i32 @test6(i32 %x) {
+; CHECK-LABEL: @test6(
+; CHECK-NEXT:    [[XOR:%.*]] = xor i32 [[X:%.*]], 1234
+; CHECK-NEXT:    [[SHR:%.*]] = lshr i32 [[X]], 16
+; CHECK-NEXT:    [[ADD:%.*]] = add i32 [[SHR]], [[XOR]]
+; CHECK-NEXT:    ret i32 [[ADD]]
+;
+  %xor = xor i32 %x, 1234
+  %shr = lshr i32 %xor, 16
+  %add = add i32 %shr, %xor
+  ret i32 %add
+}
+
+
+; (A | B) ^ (~A) -> (A | ~B)
+define i32 @test7(i32 %a, i32 %b) {
+; CHECK-LABEL: @test7(
+; CHECK-NEXT:    [[B_NOT:%.*]] = xor i32 [[B:%.*]], -1
+; CHECK-NEXT:    [[XOR:%.*]] = or i32 [[B_NOT]], [[A:%.*]]
+; CHECK-NEXT:    ret i32 [[XOR]]
+;
+  %or = or i32 %a, %b
+  %neg = xor i32 %a, -1
+  %xor = xor i32 %or, %neg
+  ret i32 %xor
+}
+
+; (~A) ^ (A | B) -> (A | ~B)
+define i32 @test8(i32 %a, i32 %b) {
+; CHECK-LABEL: @test8(
+; CHECK-NEXT:    [[B_NOT:%.*]] = xor i32 [[B:%.*]], -1
+; CHECK-NEXT:    [[XOR:%.*]] = or i32 [[B_NOT]], [[A:%.*]]
+; CHECK-NEXT:    ret i32 [[XOR]]
+;
+  %neg = xor i32 %a, -1
+  %or = or i32 %a, %b
+  %xor = xor i32 %neg, %or
+  ret i32 %xor
+}
+
+; (A & B) ^ (A ^ B) -> (A | B)
+define i32 @test9(i32 %b, i32 %c) {
+; CHECK-LABEL: @test9(
+; CHECK-NEXT:    [[XOR2:%.*]] = or i32 [[B:%.*]], [[C:%.*]]
+; CHECK-NEXT:    ret i32 [[XOR2]]
+;
+  %and = and i32 %b, %c
+  %xor = xor i32 %b, %c
+  %xor2 = xor i32 %and, %xor
+  ret i32 %xor2
+}
+
+; (A & B) ^ (B ^ A) -> (A | B)
+define i32 @test9b(i32 %b, i32 %c) {
+; CHECK-LABEL: @test9b(
+; CHECK-NEXT:    [[XOR2:%.*]] = or i32 [[B:%.*]], [[C:%.*]]
+; CHECK-NEXT:    ret i32 [[XOR2]]
+;
+  %and = and i32 %b, %c
+  %xor = xor i32 %c, %b
+  %xor2 = xor i32 %and, %xor
+  ret i32 %xor2
+}
+
+; (A ^ B) ^ (A & B) -> (A | B)
+define i32 @test10(i32 %b, i32 %c) {
+; CHECK-LABEL: @test10(
+; CHECK-NEXT:    [[XOR2:%.*]] = or i32 [[B:%.*]], [[C:%.*]]
+; CHECK-NEXT:    ret i32 [[XOR2]]
+;
+  %xor = xor i32 %b, %c
+  %and = and i32 %b, %c
+  %xor2 = xor i32 %xor, %and
+  ret i32 %xor2
+}
+
+; (A ^ B) ^ (A & B) -> (A | B)
+define i32 @test10b(i32 %b, i32 %c) {
+; CHECK-LABEL: @test10b(
+; CHECK-NEXT:    [[XOR2:%.*]] = or i32 [[B:%.*]], [[C:%.*]]
+; CHECK-NEXT:    ret i32 [[XOR2]]
+;
+  %xor = xor i32 %b, %c
+  %and = and i32 %c, %b
+  %xor2 = xor i32 %xor, %and
+  ret i32 %xor2
+}
+
+define i32 @test11(i32 %A, i32 %B) {
+; CHECK-LABEL: @test11(
+; CHECK-NEXT:    ret i32 0
+;
+  %xor1 = xor i32 %B, %A
+  %not = xor i32 %A, -1
+  %xor2 = xor i32 %not, %B
+  %and = and i32 %xor1, %xor2
+  ret i32 %and
+}
+
+define i32 @test11b(i32 %A, i32 %B) {
+; CHECK-LABEL: @test11b(
+; CHECK-NEXT:    ret i32 0
+;
+  %xor1 = xor i32 %B, %A
+  %not = xor i32 %A, -1
+  %xor2 = xor i32 %not, %B
+  %and = and i32 %xor2, %xor1
+  ret i32 %and
+}
+
+define i32 @test11c(i32 %A, i32 %B) {
+; CHECK-LABEL: @test11c(
+; CHECK-NEXT:    [[XOR1:%.*]] = xor i32 [[A:%.*]], [[B:%.*]]
+; CHECK-NEXT:    [[NOT:%.*]] = xor i32 [[A]], -1
+; CHECK-NEXT:    [[XOR2:%.*]] = xor i32 [[NOT]], [[B]]
+; CHECK-NEXT:    [[AND:%.*]] = and i32 [[XOR1]], [[XOR2]]
+; CHECK-NEXT:    ret i32 [[AND]]
+;
+  %xor1 = xor i32 %A, %B
+  %not = xor i32 %A, -1
+  %xor2 = xor i32 %not, %B
+  %and = and i32 %xor1, %xor2
+  ret i32 %and
+}
+
+define i32 @test11d(i32 %A, i32 %B) {
+; CHECK-LABEL: @test11d(
+; CHECK-NEXT:    [[XOR1:%.*]] = xor i32 [[A:%.*]], [[B:%.*]]
+; CHECK-NEXT:    [[NOT:%.*]] = xor i32 [[A]], -1
+; CHECK-NEXT:    [[XOR2:%.*]] = xor i32 [[NOT]], [[B]]
+; CHECK-NEXT:    [[AND:%.*]] = and i32 [[XOR2]], [[XOR1]]
+; CHECK-NEXT:    ret i32 [[AND]]
+;
+  %xor1 = xor i32 %A, %B
+  %not = xor i32 %A, -1
+  %xor2 = xor i32 %not, %B
+  %and = and i32 %xor2, %xor1
+  ret i32 %and
+}
+
+define i32 @test11e(i32 %A, i32 %B, i32 %C) {
+; CHECK-LABEL: @test11e(
+; CHECK-NEXT:    [[FORCE:%.*]] = mul i32 [[B:%.*]], [[C:%.*]]
+; CHECK-NEXT:    [[XOR1:%.*]] = xor i32 [[FORCE]], [[A:%.*]]
+; CHECK-NEXT:    [[NOT:%.*]] = xor i32 [[A]], -1
+; CHECK-NEXT:    [[XOR2:%.*]] = xor i32 [[FORCE]], [[NOT]]
+; CHECK-NEXT:    [[AND:%.*]] = and i32 [[XOR1]], [[XOR2]]
+; CHECK-NEXT:    ret i32 [[AND]]
+;
+  %force = mul i32 %B, %C
+  %xor1 = xor i32 %force, %A
+  %not = xor i32 %A, -1
+  %xor2 = xor i32 %force, %not
+  %and = and i32 %xor1, %xor2
+  ret i32 %and
+}
+
+define i32 @test11f(i32 %A, i32 %B, i32 %C) {
+; CHECK-LABEL: @test11f(
+; CHECK-NEXT:    [[FORCE:%.*]] = mul i32 [[B:%.*]], [[C:%.*]]
+; CHECK-NEXT:    [[XOR1:%.*]] = xor i32 [[FORCE]], [[A:%.*]]
+; CHECK-NEXT:    [[NOT:%.*]] = xor i32 [[A]], -1
+; CHECK-NEXT:    [[XOR2:%.*]] = xor i32 [[FORCE]], [[NOT]]
+; CHECK-NEXT:    [[AND:%.*]] = and i32 [[XOR2]], [[XOR1]]
+; CHECK-NEXT:    ret i32 [[AND]]
+;
+  %force = mul i32 %B, %C
+  %xor1 = xor i32 %force, %A
+  %not = xor i32 %A, -1
+  %xor2 = xor i32 %force, %not
+  %and = and i32 %xor2, %xor1
+  ret i32 %and
+}
+
+define i32 @test12(i32 %a, i32 %b) {
+; CHECK-LABEL: @test12(
+; CHECK-NEXT:    [[TMP1:%.*]] = and i32 [[A:%.*]], [[B:%.*]]
+; CHECK-NEXT:    [[XOR:%.*]] = xor i32 [[TMP1]], -1
+; CHECK-NEXT:    ret i32 [[XOR]]
+;
+  %negb = xor i32 %b, -1
+  %and = and i32 %a, %negb
+  %nega = xor i32 %a, -1
+  %xor = xor i32 %and, %nega
+  ret i32 %xor
+}
+
+define i32 @test12commuted(i32 %a, i32 %b) {
+; CHECK-LABEL: @test12commuted(
+; CHECK-NEXT:    [[TMP1:%.*]] = and i32 [[A:%.*]], [[B:%.*]]
+; CHECK-NEXT:    [[XOR:%.*]] = xor i32 [[TMP1]], -1
+; CHECK-NEXT:    ret i32 [[XOR]]
+;
+  %negb = xor i32 %b, -1
+  %and = and i32 %negb, %a
+  %nega = xor i32 %a, -1
+  %xor = xor i32 %and, %nega
+  ret i32 %xor
+}
+
+; This is a test of canonicalization via operand complexity.
+; The final xor has a binary operator and a (fake) unary operator,
+; so binary (more complex) should come first.
+
+define i32 @test13(i32 %a, i32 %b) {
+; CHECK-LABEL: @test13(
+; CHECK-NEXT:    [[TMP1:%.*]] = and i32 [[A:%.*]], [[B:%.*]]
+; CHECK-NEXT:    [[XOR:%.*]] = xor i32 [[TMP1]], -1
+; CHECK-NEXT:    ret i32 [[XOR]]
+;
+  %nega = xor i32 %a, -1
+  %negb = xor i32 %b, -1
+  %and = and i32 %a, %negb
+  %xor = xor i32 %nega, %and
+  ret i32 %xor
+}
+
+define i32 @test13commuted(i32 %a, i32 %b) {
+; CHECK-LABEL: @test13commuted(
+; CHECK-NEXT:    [[TMP1:%.*]] = and i32 [[A:%.*]], [[B:%.*]]
+; CHECK-NEXT:    [[XOR:%.*]] = xor i32 [[TMP1]], -1
+; CHECK-NEXT:    ret i32 [[XOR]]
+;
+  %nega = xor i32 %a, -1
+  %negb = xor i32 %b, -1
+  %and = and i32 %negb, %a
+  %xor = xor i32 %nega, %and
+  ret i32 %xor
+}
+
+; (A ^ C) ^ (A | B) -> ((~A) & B) ^ C
+
+define i32 @xor_or_xor_common_op_commute1(i32 %a, i32 %b, i32 %c) {
+; CHECK-LABEL: @xor_or_xor_common_op_commute1(
+; CHECK-NEXT:    [[TMP1:%.*]] = xor i32 [[A:%.*]], -1
+; CHECK-NEXT:    [[TMP2:%.*]] = and i32 [[TMP1]], [[B:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = xor i32 [[TMP2]], [[C:%.*]]
+; CHECK-NEXT:    ret i32 [[R]]
+;
+  %ac = xor i32 %a, %c
+  %ab = or i32 %a, %b
+  %r = xor i32 %ac, %ab
+  ret i32 %r
+}
+
+; (C ^ A) ^ (A | B) -> ((~A) & B) ^ C
+
+define i32 @xor_or_xor_common_op_commute2(i32 %a, i32 %b, i32 %c) {
+; CHECK-LABEL: @xor_or_xor_common_op_commute2(
+; CHECK-NEXT:    [[TMP1:%.*]] = xor i32 [[A:%.*]], -1
+; CHECK-NEXT:    [[TMP2:%.*]] = and i32 [[TMP1]], [[B:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = xor i32 [[TMP2]], [[C:%.*]]
+; CHECK-NEXT:    ret i32 [[R]]
+;
+  %ac = xor i32 %c, %a
+  %ab = or i32 %a, %b
+  %r = xor i32 %ac, %ab
+  ret i32 %r
+}
+
+; (A ^ C) ^ (B | A) -> ((~A) & B) ^ C
+
+define i32 @xor_or_xor_common_op_commute3(i32 %a, i32 %b, i32 %c) {
+; CHECK-LABEL: @xor_or_xor_common_op_commute3(
+; CHECK-NEXT:    [[TMP1:%.*]] = xor i32 [[A:%.*]], -1
+; CHECK-NEXT:    [[TMP2:%.*]] = and i32 [[TMP1]], [[B:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = xor i32 [[TMP2]], [[C:%.*]]
+; CHECK-NEXT:    ret i32 [[R]]
+;
+  %ac = xor i32 %a, %c
+  %ab = or i32 %b, %a
+  %r = xor i32 %ac, %ab
+  ret i32 %r
+}
+
+; (C ^ A) ^ (B | A) -> ((~A) & B) ^ C
+
+define i32 @xor_or_xor_common_op_commute4(i32 %a, i32 %b, i32 %c) {
+; CHECK-LABEL: @xor_or_xor_common_op_commute4(
+; CHECK-NEXT:    [[TMP1:%.*]] = xor i32 [[A:%.*]], -1
+; CHECK-NEXT:    [[TMP2:%.*]] = and i32 [[TMP1]], [[B:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = xor i32 [[TMP2]], [[C:%.*]]
+; CHECK-NEXT:    ret i32 [[R]]
+;
+  %ac = xor i32 %c, %a
+  %ab = or i32 %b, %a
+  %r = xor i32 %ac, %ab
+  ret i32 %r
+}
+
+; (A | B) ^ (A ^ C) -> ((~A) & B) ^ C
+
+define i32 @xor_or_xor_common_op_commute5(i32 %a, i32 %b, i32 %c) {
+; CHECK-LABEL: @xor_or_xor_common_op_commute5(
+; CHECK-NEXT:    [[TMP1:%.*]] = xor i32 [[A:%.*]], -1
+; CHECK-NEXT:    [[TMP2:%.*]] = and i32 [[TMP1]], [[B:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = xor i32 [[TMP2]], [[C:%.*]]
+; CHECK-NEXT:    ret i32 [[R]]
+;
+  %ac = xor i32 %a, %c
+  %ab = or i32 %a, %b
+  %r = xor i32 %ab, %ac
+  ret i32 %r
+}
+
+; (A | B) ^ (C ^ A) -> ((~A) & B) ^ C
+
+define i32 @xor_or_xor_common_op_commute6(i32 %a, i32 %b, i32 %c) {
+; CHECK-LABEL: @xor_or_xor_common_op_commute6(
+; CHECK-NEXT:    [[TMP1:%.*]] = xor i32 [[A:%.*]], -1
+; CHECK-NEXT:    [[TMP2:%.*]] = and i32 [[TMP1]], [[B:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = xor i32 [[TMP2]], [[C:%.*]]
+; CHECK-NEXT:    ret i32 [[R]]
+;
+  %ac = xor i32 %c, %a
+  %ab = or i32 %a, %b
+  %r = xor i32 %ab, %ac
+  ret i32 %r
+}
+
+; (B | A) ^ (A ^ C) -> ((~A) & B) ^ C
+
+define i32 @xor_or_xor_common_op_commute7(i32 %a, i32 %b, i32 %c) {
+; CHECK-LABEL: @xor_or_xor_common_op_commute7(
+; CHECK-NEXT:    [[TMP1:%.*]] = xor i32 [[A:%.*]], -1
+; CHECK-NEXT:    [[TMP2:%.*]] = and i32 [[TMP1]], [[B:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = xor i32 [[TMP2]], [[C:%.*]]
+; CHECK-NEXT:    ret i32 [[R]]
+;
+  %ac = xor i32 %a, %c
+  %ab = or i32 %b, %a
+  %r = xor i32 %ab, %ac
+  ret i32 %r
+}
+
+; (B | A) ^ (C ^ A) -> ((~A) & B) ^ C
+
+define i32 @xor_or_xor_common_op_commute8(i32 %a, i32 %b, i32 %c) {
+; CHECK-LABEL: @xor_or_xor_common_op_commute8(
+; CHECK-NEXT:    [[TMP1:%.*]] = xor i32 [[A:%.*]], -1
+; CHECK-NEXT:    [[TMP2:%.*]] = and i32 [[TMP1]], [[B:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = xor i32 [[TMP2]], [[C:%.*]]
+; CHECK-NEXT:    ret i32 [[R]]
+;
+  %ac = xor i32 %c, %a
+  %ab = or i32 %b, %a
+  %r = xor i32 %ab, %ac
+  ret i32 %r
+}
+
+define i32 @xor_or_xor_common_op_extra_use1(i32 %a, i32 %b, i32 %c, i32* %p) {
+; CHECK-LABEL: @xor_or_xor_common_op_extra_use1(
+; CHECK-NEXT:    [[AC:%.*]] = xor i32 [[A:%.*]], [[C:%.*]]
+; CHECK-NEXT:    store i32 [[AC]], i32* [[P:%.*]], align 4
+; CHECK-NEXT:    [[AB:%.*]] = or i32 [[A]], [[B:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = xor i32 [[AC]], [[AB]]
+; CHECK-NEXT:    ret i32 [[R]]
+;
+  %ac = xor i32 %a, %c
+  store i32 %ac, i32* %p
+  %ab = or i32 %a, %b
+  %r = xor i32 %ac, %ab
+  ret i32 %r
+}
+
+define i32 @xor_or_xor_common_op_extra_use2(i32 %a, i32 %b, i32 %c, i32* %p) {
+; CHECK-LABEL: @xor_or_xor_common_op_extra_use2(
+; CHECK-NEXT:    [[AC:%.*]] = xor i32 [[A:%.*]], [[C:%.*]]
+; CHECK-NEXT:    [[AB:%.*]] = or i32 [[A]], [[B:%.*]]
+; CHECK-NEXT:    store i32 [[AB]], i32* [[P:%.*]], align 4
+; CHECK-NEXT:    [[R:%.*]] = xor i32 [[AC]], [[AB]]
+; CHECK-NEXT:    ret i32 [[R]]
+;
+  %ac = xor i32 %a, %c
+  %ab = or i32 %a, %b
+  store i32 %ab, i32* %p
+  %r = xor i32 %ac, %ab
+  ret i32 %r
+}
+
+define i32 @xor_or_xor_common_op_extra_use3(i32 %a, i32 %b, i32 %c, i32* %p1, i32* %p2) {
+; CHECK-LABEL: @xor_or_xor_common_op_extra_use3(
+; CHECK-NEXT:    [[AC:%.*]] = xor i32 [[A:%.*]], [[C:%.*]]
+; CHECK-NEXT:    store i32 [[AC]], i32* [[P1:%.*]], align 4
+; CHECK-NEXT:    [[AB:%.*]] = or i32 [[A]], [[B:%.*]]
+; CHECK-NEXT:    store i32 [[AB]], i32* [[P2:%.*]], align 4
+; CHECK-NEXT:    [[R:%.*]] = xor i32 [[AC]], [[AB]]
+; CHECK-NEXT:    ret i32 [[R]]
+;
+  %ac = xor i32 %a, %c
+  store i32 %ac, i32* %p1
+  %ab = or i32 %a, %b
+  store i32 %ab, i32* %p2
+  %r = xor i32 %ac, %ab
+  ret i32 %r
+}
+
+define i8 @test15(i8 %A, i8 %B) {
+; CHECK-LABEL: @test15(
+; CHECK-NEXT:    [[XOR1:%.*]] = xor i8 [[B:%.*]], [[A:%.*]]
+; CHECK-NEXT:    [[NOT:%.*]] = xor i8 [[A]], 33
+; CHECK-NEXT:    [[XOR2:%.*]] = xor i8 [[NOT]], [[B]]
+; CHECK-NEXT:    [[AND:%.*]] = and i8 [[XOR1]], -34
+; CHECK-NEXT:    [[RES:%.*]] = mul i8 [[AND]], [[XOR2]]
+; CHECK-NEXT:    ret i8 [[RES]]
+;
+  %xor1 = xor i8 %B, %A
+  %not = xor i8 %A, 33
+  %xor2 = xor i8 %not, %B
+  %and = and i8 %xor1, %xor2
+  %res = mul i8 %and, %xor2 ; to increase the use count for the xor
+  ret i8 %res
+}
+
+define i8 @test16(i8 %A, i8 %B) {
+; CHECK-LABEL: @test16(
+; CHECK-NEXT:    [[XOR1:%.*]] = xor i8 [[B:%.*]], [[A:%.*]]
+; CHECK-NEXT:    [[NOT:%.*]] = xor i8 [[A]], 33
+; CHECK-NEXT:    [[XOR2:%.*]] = xor i8 [[NOT]], [[B]]
+; CHECK-NEXT:    [[AND:%.*]] = and i8 [[XOR1]], -34
+; CHECK-NEXT:    [[RES:%.*]] = mul i8 [[AND]], [[XOR2]]
+; CHECK-NEXT:    ret i8 [[RES]]
+;
+  %xor1 = xor i8 %B, %A
+  %not = xor i8 %A, 33
+  %xor2 = xor i8 %not, %B
+  %and = and i8 %xor2, %xor1
+  %res = mul i8 %and, %xor2 ; to increase the use count for the xor
+  ret i8 %res
+}

Added: llvm/trunk/test/Transforms/InstCombine/zero-point-zero-add.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/zero-point-zero-add.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/zero-point-zero-add.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/zero-point-zero-add.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,24 @@
+; NOTE: Assertions have been autogenerated by update_test_checks.py
+; RUN: opt < %s -instcombine -S | FileCheck %s
+
+declare double @fabs(double) readonly
+
+define double @test(double %X) {
+; CHECK-LABEL: @test(
+; CHECK-NEXT:    [[Y:%.*]] = fadd double %X, 0.000000e+00
+; CHECK-NEXT:    ret double [[Y]]
+;
+  %Y = fadd double %X, 0.0          ;; Should be a single add x, 0.0
+  %Z = fadd double %Y, 0.0
+  ret double %Z
+}
+
+define double @test1(double %X) {
+; CHECK-LABEL: @test1(
+; CHECK-NEXT:    [[Y:%.*]] = call double @llvm.fabs.f64(double %X)
+; CHECK-NEXT:    ret double [[Y]]
+;
+  %Y = call double @fabs(double %X)
+  %Z = fadd double %Y, 0.0
+  ret double %Z
+}

Added: llvm/trunk/test/Transforms/InstCombine/zeroext-and-reduce.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/zeroext-and-reduce.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/zeroext-and-reduce.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/zeroext-and-reduce.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,15 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt < %s -instcombine -S | FileCheck %s
+
+define i32 @test1(i8 %X) {
+; CHECK-LABEL: @test1(
+; CHECK-NEXT:    [[TMP1:%.*]] = and i8 %X, 8
+; CHECK-NEXT:    [[Z:%.*]] = zext i8 [[TMP1]] to i32
+; CHECK-NEXT:    ret i32 [[Z]]
+;
+  %Y = zext i8 %X to i32
+  %Z = and i32 %Y, 65544
+  ret i32 %Z
+}
+
+

Added: llvm/trunk/test/Transforms/InstCombine/zext-bool-add-sub.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/zext-bool-add-sub.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/zext-bool-add-sub.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/zext-bool-add-sub.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,404 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt < %s -instcombine -S | FileCheck %s
+
+; rdar://11748024
+
+define i32 @a(i1 zeroext %x, i1 zeroext %y) {
+; CHECK-LABEL: @a(
+; CHECK-NEXT:    [[SUB:%.*]] = select i1 [[X:%.*]], i32 2, i32 1
+; CHECK-NEXT:    [[TMP1:%.*]] = zext i1 [[Y:%.*]] to i32
+; CHECK-NEXT:    [[ADD:%.*]] = sub nsw i32 [[SUB]], [[TMP1]]
+; CHECK-NEXT:    ret i32 [[ADD]]
+;
+  %conv = zext i1 %x to i32
+  %conv3 = zext i1 %y to i32
+  %conv3.neg = sub i32 0, %conv3
+  %sub = add i32 %conv, 1
+  %add = add i32 %sub, %conv3.neg
+  ret i32 %add
+}
+
+define i32 @PR30273_select(i1 %a, i1 %b) {
+; CHECK-LABEL: @PR30273_select(
+; CHECK-NEXT:    [[ZEXT:%.*]] = zext i1 [[A:%.*]] to i32
+; CHECK-NEXT:    [[SEL1:%.*]] = select i1 [[A]], i32 2, i32 1
+; CHECK-NEXT:    [[SEL2:%.*]] = select i1 [[B:%.*]], i32 [[SEL1]], i32 [[ZEXT]]
+; CHECK-NEXT:    ret i32 [[SEL2]]
+;
+  %zext = zext i1 %a to i32
+  %sel1 = select i1 %a, i32 2, i32 1
+  %sel2 = select i1 %b, i32 %sel1, i32 %zext
+  ret i32 %sel2
+}
+
+define i32 @PR30273_zext_add(i1 %a, i1 %b) {
+; CHECK-LABEL: @PR30273_zext_add(
+; CHECK-NEXT:    [[CONV:%.*]] = zext i1 [[A:%.*]] to i32
+; CHECK-NEXT:    [[CONV3:%.*]] = zext i1 [[B:%.*]] to i32
+; CHECK-NEXT:    [[ADD:%.*]] = add nuw nsw i32 [[CONV3]], [[CONV]]
+; CHECK-NEXT:    ret i32 [[ADD]]
+;
+  %conv = zext i1 %a to i32
+  %conv3 = zext i1 %b to i32
+  %add = add nuw nsw i32 %conv3, %conv
+  ret i32 %add
+}
+
+define i32 @PR30273_three_bools(i1 %x, i1 %y, i1 %z) {
+; CHECK-LABEL: @PR30273_three_bools(
+; CHECK-NEXT:    [[FROMBOOL:%.*]] = zext i1 [[X:%.*]] to i32
+; CHECK-NEXT:    [[ADD1:%.*]] = select i1 [[X]], i32 2, i32 1
+; CHECK-NEXT:    [[SEL1:%.*]] = select i1 [[Y:%.*]], i32 [[ADD1]], i32 [[FROMBOOL]]
+; CHECK-NEXT:    [[ADD2:%.*]] = zext i1 [[Z:%.*]] to i32
+; CHECK-NEXT:    [[SEL2:%.*]] = add nuw nsw i32 [[SEL1]], [[ADD2]]
+; CHECK-NEXT:    ret i32 [[SEL2]]
+;
+  %frombool = zext i1 %x to i32
+  %add1 = add nsw i32 %frombool, 1
+  %sel1 = select i1 %y, i32 %add1, i32 %frombool
+  %add2 = add nsw i32 %sel1, 1
+  %sel2 = select i1 %z, i32 %add2, i32 %sel1
+  ret i32 %sel2
+}
+
+define i32 @zext_add_scalar(i1 %x) {
+; CHECK-LABEL: @zext_add_scalar(
+; CHECK-NEXT:    [[ADD:%.*]] = select i1 [[X:%.*]], i32 43, i32 42
+; CHECK-NEXT:    ret i32 [[ADD]]
+;
+  %zext = zext i1 %x to i32
+  %add = add i32 %zext, 42
+  ret i32 %add
+}
+
+define <2 x i32> @zext_add_vec_splat(<2 x i1> %x) {
+; CHECK-LABEL: @zext_add_vec_splat(
+; CHECK-NEXT:    [[ADD:%.*]] = select <2 x i1> [[X:%.*]], <2 x i32> <i32 43, i32 43>, <2 x i32> <i32 42, i32 42>
+; CHECK-NEXT:    ret <2 x i32> [[ADD]]
+;
+  %zext = zext <2 x i1> %x to <2 x i32>
+  %add = add <2 x i32> %zext, <i32 42, i32 42>
+  ret <2 x i32> %add
+}
+
+define <2 x i32> @zext_add_vec(<2 x i1> %x) {
+; CHECK-LABEL: @zext_add_vec(
+; CHECK-NEXT:    [[ADD:%.*]] = select <2 x i1> [[X:%.*]], <2 x i32> <i32 43, i32 24>, <2 x i32> <i32 42, i32 23>
+; CHECK-NEXT:    ret <2 x i32> [[ADD]]
+;
+  %zext = zext <2 x i1> %x to <2 x i32>
+  %add = add <2 x i32> %zext, <i32 42, i32 23>
+  ret <2 x i32> %add
+}
+
+declare void @use(i64)
+
+define i64 @zext_negate(i1 %A) {
+; CHECK-LABEL: @zext_negate(
+; CHECK-NEXT:    [[SUB:%.*]] = sext i1 [[A:%.*]] to i64
+; CHECK-NEXT:    ret i64 [[SUB]]
+;
+  %ext = zext i1 %A to i64
+  %sub = sub i64 0, %ext
+  ret i64 %sub
+}
+
+define i64 @zext_negate_extra_use(i1 %A) {
+; CHECK-LABEL: @zext_negate_extra_use(
+; CHECK-NEXT:    [[EXT:%.*]] = zext i1 [[A:%.*]] to i64
+; CHECK-NEXT:    [[SUB:%.*]] = sext i1 [[A]] to i64
+; CHECK-NEXT:    call void @use(i64 [[EXT]])
+; CHECK-NEXT:    ret i64 [[SUB]]
+;
+  %ext = zext i1 %A to i64
+  %sub = sub i64 0, %ext
+  call void @use(i64 %ext)
+  ret i64 %sub
+}
+
+define <2 x i64> @zext_negate_vec(<2 x i1> %A) {
+; CHECK-LABEL: @zext_negate_vec(
+; CHECK-NEXT:    [[SUB:%.*]] = sext <2 x i1> [[A:%.*]] to <2 x i64>
+; CHECK-NEXT:    ret <2 x i64> [[SUB]]
+;
+  %ext = zext <2 x i1> %A to <2 x i64>
+  %sub = sub <2 x i64> zeroinitializer, %ext
+  ret <2 x i64> %sub
+}
+
+define <2 x i64> @zext_negate_vec_undef_elt(<2 x i1> %A) {
+; CHECK-LABEL: @zext_negate_vec_undef_elt(
+; CHECK-NEXT:    [[SUB:%.*]] = sext <2 x i1> [[A:%.*]] to <2 x i64>
+; CHECK-NEXT:    ret <2 x i64> [[SUB]]
+;
+  %ext = zext <2 x i1> %A to <2 x i64>
+  %sub = sub <2 x i64> <i64 0, i64 undef>, %ext
+  ret <2 x i64> %sub
+}
+
+define i64 @zext_sub_const(i1 %A) {
+; CHECK-LABEL: @zext_sub_const(
+; CHECK-NEXT:    [[SUB:%.*]] = select i1 [[A:%.*]], i64 41, i64 42
+; CHECK-NEXT:    ret i64 [[SUB]]
+;
+  %ext = zext i1 %A to i64
+  %sub = sub i64 42, %ext
+  ret i64 %sub
+}
+
+define i64 @zext_sub_const_extra_use(i1 %A) {
+; CHECK-LABEL: @zext_sub_const_extra_use(
+; CHECK-NEXT:    [[EXT:%.*]] = zext i1 [[A:%.*]] to i64
+; CHECK-NEXT:    [[SUB:%.*]] = select i1 [[A]], i64 41, i64 42
+; CHECK-NEXT:    call void @use(i64 [[EXT]])
+; CHECK-NEXT:    ret i64 [[SUB]]
+;
+  %ext = zext i1 %A to i64
+  %sub = sub i64 42, %ext
+  call void @use(i64 %ext)
+  ret i64 %sub
+}
+
+define <2 x i64> @zext_sub_const_vec(<2 x i1> %A) {
+; CHECK-LABEL: @zext_sub_const_vec(
+; CHECK-NEXT:    [[SUB:%.*]] = select <2 x i1> [[A:%.*]], <2 x i64> <i64 41, i64 2>, <2 x i64> <i64 42, i64 3>
+; CHECK-NEXT:    ret <2 x i64> [[SUB]]
+;
+  %ext = zext <2 x i1> %A to <2 x i64>
+  %sub = sub <2 x i64> <i64 42, i64 3>, %ext
+  ret <2 x i64> %sub
+}
+
+define <2 x i64> @zext_sub_const_vec_undef_elt(<2 x i1> %A) {
+; CHECK-LABEL: @zext_sub_const_vec_undef_elt(
+; CHECK-NEXT:    [[SUB:%.*]] = select <2 x i1> [[A:%.*]], <2 x i64> <i64 41, i64 undef>, <2 x i64> <i64 42, i64 undef>
+; CHECK-NEXT:    ret <2 x i64> [[SUB]]
+;
+  %ext = zext <2 x i1> %A to <2 x i64>
+  %sub = sub <2 x i64> <i64 42, i64 undef>, %ext
+  ret <2 x i64> %sub
+}
+
+define i64 @sext_negate(i1 %A) {
+; CHECK-LABEL: @sext_negate(
+; CHECK-NEXT:    [[SUB:%.*]] = zext i1 [[A:%.*]] to i64
+; CHECK-NEXT:    ret i64 [[SUB]]
+;
+  %ext = sext i1 %A to i64
+  %sub = sub i64 0, %ext
+  ret i64 %sub
+}
+
+define i64 @sext_negate_extra_use(i1 %A) {
+; CHECK-LABEL: @sext_negate_extra_use(
+; CHECK-NEXT:    [[EXT:%.*]] = sext i1 [[A:%.*]] to i64
+; CHECK-NEXT:    [[SUB:%.*]] = zext i1 [[A]] to i64
+; CHECK-NEXT:    call void @use(i64 [[EXT]])
+; CHECK-NEXT:    ret i64 [[SUB]]
+;
+  %ext = sext i1 %A to i64
+  %sub = sub i64 0, %ext
+  call void @use(i64 %ext)
+  ret i64 %sub
+}
+
+define <2 x i64> @sext_negate_vec(<2 x i1> %A) {
+; CHECK-LABEL: @sext_negate_vec(
+; CHECK-NEXT:    [[SUB:%.*]] = zext <2 x i1> [[A:%.*]] to <2 x i64>
+; CHECK-NEXT:    ret <2 x i64> [[SUB]]
+;
+  %ext = sext <2 x i1> %A to <2 x i64>
+  %sub = sub <2 x i64> zeroinitializer, %ext
+  ret <2 x i64> %sub
+}
+
+define <2 x i64> @sext_negate_vec_undef_elt(<2 x i1> %A) {
+; CHECK-LABEL: @sext_negate_vec_undef_elt(
+; CHECK-NEXT:    [[SUB:%.*]] = zext <2 x i1> [[A:%.*]] to <2 x i64>
+; CHECK-NEXT:    ret <2 x i64> [[SUB]]
+;
+  %ext = sext <2 x i1> %A to <2 x i64>
+  %sub = sub <2 x i64> <i64 0, i64 undef>, %ext
+  ret <2 x i64> %sub
+}
+
+define i64 @sext_sub_const(i1 %A) {
+; CHECK-LABEL: @sext_sub_const(
+; CHECK-NEXT:    [[SUB:%.*]] = select i1 [[A:%.*]], i64 43, i64 42
+; CHECK-NEXT:    ret i64 [[SUB]]
+;
+  %ext = sext i1 %A to i64
+  %sub = sub i64 42, %ext
+  ret i64 %sub
+}
+
+define i64 @sext_sub_const_extra_use(i1 %A) {
+; CHECK-LABEL: @sext_sub_const_extra_use(
+; CHECK-NEXT:    [[EXT:%.*]] = sext i1 [[A:%.*]] to i64
+; CHECK-NEXT:    [[SUB:%.*]] = select i1 [[A]], i64 43, i64 42
+; CHECK-NEXT:    call void @use(i64 [[EXT]])
+; CHECK-NEXT:    ret i64 [[SUB]]
+;
+  %ext = sext i1 %A to i64
+  %sub = sub i64 42, %ext
+  call void @use(i64 %ext)
+  ret i64 %sub
+}
+
+define <2 x i64> @sext_sub_const_vec(<2 x i1> %A) {
+; CHECK-LABEL: @sext_sub_const_vec(
+; CHECK-NEXT:    [[SUB:%.*]] = select <2 x i1> [[A:%.*]], <2 x i64> <i64 43, i64 4>, <2 x i64> <i64 42, i64 3>
+; CHECK-NEXT:    ret <2 x i64> [[SUB]]
+;
+  %ext = sext <2 x i1> %A to <2 x i64>
+  %sub = sub <2 x i64> <i64 42, i64 3>, %ext
+  ret <2 x i64> %sub
+}
+
+define <2 x i64> @sext_sub_const_vec_undef_elt(<2 x i1> %A) {
+; CHECK-LABEL: @sext_sub_const_vec_undef_elt(
+; CHECK-NEXT:    [[SUB:%.*]] = select <2 x i1> [[A:%.*]], <2 x i64> <i64 undef, i64 43>, <2 x i64> <i64 undef, i64 42>
+; CHECK-NEXT:    ret <2 x i64> [[SUB]]
+;
+  %ext = sext <2 x i1> %A to <2 x i64>
+  %sub = sub <2 x i64> <i64 undef, i64 42>, %ext
+  ret <2 x i64> %sub
+}
+
+define i8 @sext_sub(i8 %x, i1 %y) {
+; CHECK-LABEL: @sext_sub(
+; CHECK-NEXT:    [[TMP1:%.*]] = zext i1 [[Y:%.*]] to i8
+; CHECK-NEXT:    [[SUB:%.*]] = add i8 [[TMP1]], [[X:%.*]]
+; CHECK-NEXT:    ret i8 [[SUB]]
+;
+  %sext = sext i1 %y to i8
+  %sub = sub i8 %x, %sext
+  ret i8 %sub
+}
+
+; Vectors get the same transform.
+
+define <2 x i8> @sext_sub_vec(<2 x i8> %x, <2 x i1> %y) {
+; CHECK-LABEL: @sext_sub_vec(
+; CHECK-NEXT:    [[TMP1:%.*]] = zext <2 x i1> [[Y:%.*]] to <2 x i8>
+; CHECK-NEXT:    [[SUB:%.*]] = add <2 x i8> [[TMP1]], [[X:%.*]]
+; CHECK-NEXT:    ret <2 x i8> [[SUB]]
+;
+  %sext = sext <2 x i1> %y to <2 x i8>
+  %sub = sub <2 x i8> %x, %sext
+  ret <2 x i8> %sub
+}
+
+; NSW is preserved.
+
+define <2 x i8> @sext_sub_vec_nsw(<2 x i8> %x, <2 x i1> %y) {
+; CHECK-LABEL: @sext_sub_vec_nsw(
+; CHECK-NEXT:    [[TMP1:%.*]] = zext <2 x i1> [[Y:%.*]] to <2 x i8>
+; CHECK-NEXT:    [[SUB:%.*]] = add nsw <2 x i8> [[TMP1]], [[X:%.*]]
+; CHECK-NEXT:    ret <2 x i8> [[SUB]]
+;
+  %sext = sext <2 x i1> %y to <2 x i8>
+  %sub = sub nsw <2 x i8> %x, %sext
+  ret <2 x i8> %sub
+}
+
+; We favor the canonical zext+add over keeping the NUW.
+
+define i8 @sext_sub_nuw(i8 %x, i1 %y) {
+; CHECK-LABEL: @sext_sub_nuw(
+; CHECK-NEXT:    [[TMP1:%.*]] = zext i1 [[Y:%.*]] to i8
+; CHECK-NEXT:    [[SUB:%.*]] = add i8 [[TMP1]], [[X:%.*]]
+; CHECK-NEXT:    ret i8 [[SUB]]
+;
+  %sext = sext i1 %y to i8
+  %sub = sub nuw i8 %x, %sext
+  ret i8 %sub
+}
+
+define i32 @sextbool_add(i1 %c, i32 %x) {
+; CHECK-LABEL: @sextbool_add(
+; CHECK-NEXT:    [[TMP1:%.*]] = zext i1 [[C:%.*]] to i32
+; CHECK-NEXT:    [[S:%.*]] = sub i32 [[X:%.*]], [[TMP1]]
+; CHECK-NEXT:    ret i32 [[S]]
+;
+  %b = sext i1 %c to i32
+  %s = add i32 %b, %x
+  ret i32 %s
+}
+
+define i32 @sextbool_add_commute(i1 %c, i32 %px) {
+; CHECK-LABEL: @sextbool_add_commute(
+; CHECK-NEXT:    [[X:%.*]] = urem i32 [[PX:%.*]], 42
+; CHECK-NEXT:    [[TMP1:%.*]] = zext i1 [[C:%.*]] to i32
+; CHECK-NEXT:    [[S:%.*]] = sub nsw i32 [[X]], [[TMP1]]
+; CHECK-NEXT:    ret i32 [[S]]
+;
+  %x = urem i32 %px, 42 ; thwart complexity-based canonicalization
+  %b = sext i1 %c to i32
+  %s = add i32 %x, %b
+  ret i32 %s
+}
+
+; Negative test - extra use prevents canonicalization.
+
+declare void @use32(i32)
+
+define i32 @sextbool_add_uses(i1 %c, i32 %x) {
+; CHECK-LABEL: @sextbool_add_uses(
+; CHECK-NEXT:    [[B:%.*]] = sext i1 [[C:%.*]] to i32
+; CHECK-NEXT:    call void @use32(i32 [[B]])
+; CHECK-NEXT:    [[S:%.*]] = add i32 [[B]], [[X:%.*]]
+; CHECK-NEXT:    ret i32 [[S]]
+;
+  %b = sext i1 %c to i32
+  call void @use32(i32 %b)
+  %s = add i32 %b, %x
+  ret i32 %s
+}
+
+define <4 x i32> @sextbool_add_vector(<4 x i1> %c, <4 x i32> %x) {
+; CHECK-LABEL: @sextbool_add_vector(
+; CHECK-NEXT:    [[TMP1:%.*]] = zext <4 x i1> [[C:%.*]] to <4 x i32>
+; CHECK-NEXT:    [[S:%.*]] = sub <4 x i32> [[X:%.*]], [[TMP1]]
+; CHECK-NEXT:    ret <4 x i32> [[S]]
+;
+  %b = sext <4 x i1> %c to <4 x i32>
+  %s = add <4 x i32> %x, %b
+  ret <4 x i32> %s
+}
+
+define i32 @zextbool_sub(i1 %c, i32 %x) {
+; CHECK-LABEL: @zextbool_sub(
+; CHECK-NEXT:    [[B:%.*]] = zext i1 [[C:%.*]] to i32
+; CHECK-NEXT:    [[S:%.*]] = sub i32 [[B]], [[X:%.*]]
+; CHECK-NEXT:    ret i32 [[S]]
+;
+  %b = zext i1 %c to i32
+  %s = sub i32 %b, %x
+  ret i32 %s
+}
+
+define i32 @zextbool_sub_uses(i1 %c, i32 %x) {
+; CHECK-LABEL: @zextbool_sub_uses(
+; CHECK-NEXT:    [[B:%.*]] = zext i1 [[C:%.*]] to i32
+; CHECK-NEXT:    call void @use32(i32 [[B]])
+; CHECK-NEXT:    [[S:%.*]] = sub i32 [[X:%.*]], [[B]]
+; CHECK-NEXT:    ret i32 [[S]]
+;
+  %b = zext i1 %c to i32
+  call void @use32(i32 %b)
+  %s = sub i32 %x, %b
+  ret i32 %s
+}
+
+define <4 x i32> @zextbool_sub_vector(<4 x i1> %c, <4 x i32> %x) {
+; CHECK-LABEL: @zextbool_sub_vector(
+; CHECK-NEXT:    [[B:%.*]] = zext <4 x i1> [[C:%.*]] to <4 x i32>
+; CHECK-NEXT:    [[S:%.*]] = sub <4 x i32> [[X:%.*]], [[B]]
+; CHECK-NEXT:    ret <4 x i32> [[S]]
+;
+  %b = zext <4 x i1> %c to <4 x i32>
+  %s = sub <4 x i32> %x, %b
+  ret <4 x i32> %s
+}
+

Added: llvm/trunk/test/Transforms/InstCombine/zext-fold.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/zext-fold.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/zext-fold.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/zext-fold.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,18 @@
+; NOTE: Assertions have been autogenerated by update_test_checks.py
+; RUN: opt < %s -instcombine -S | FileCheck %s
+
+; PR1570
+
+define i32 @test2(float %X, float %Y) {
+; CHECK-LABEL: @test2(
+; CHECK-NEXT:    [[TMP3:%.*]] = fcmp ord float %X, %Y
+; CHECK-NEXT:    [[TOBOOLNOT5:%.*]] = zext i1 [[TMP3]] to i32
+; CHECK-NEXT:    ret i32 [[TOBOOLNOT5]]
+;
+  %tmp3 = fcmp uno float %X, %Y
+  %tmp34 = zext i1 %tmp3 to i8
+  %tmp = xor i8 %tmp34, 1
+  %toBoolnot5 = zext i8 %tmp to i32
+  ret i32 %toBoolnot5
+}
+

Added: llvm/trunk/test/Transforms/InstCombine/zext-or-icmp.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/zext-or-icmp.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/zext-or-icmp.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/zext-or-icmp.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,51 @@
+; RUN: opt < %s -instcombine -S | FileCheck %s
+
+; Remove an icmp by using its operand in the subsequent logic directly.
+
+define i8 @zext_or_icmp_icmp(i8 %a, i8 %b) {
+  %mask = and i8 %a, 1
+  %toBool1 = icmp eq i8 %mask, 0
+  %toBool2 = icmp eq i8 %b, 0
+  %bothCond = or i1 %toBool1, %toBool2
+  %zext = zext i1 %bothCond to i8
+  ret i8 %zext
+
+; CHECK-LABEL: zext_or_icmp_icmp(
+; CHECK-NEXT:    %mask = and i8 %a, 1
+; CHECK-NEXT:    %toBool2 = icmp eq i8 %b, 0
+; CHECK-NEXT:    %toBool22 = zext i1 %toBool2 to i8
+; CHECK-NEXT:    %1 = xor i8 %mask, 1
+; CHECK-NEXT:    %zext = or i8 %1, %toBool22
+; CHECK-NEXT:    ret i8 %zext
+}
+
+; Here, widening the or from i1 to i32 and removing one of the icmps would
+; widen an undef value (created by the out-of-range shift), increasing the
+; range of valid values for the return, so we can't do it.
+define i32 @dont_widen_undef() {
+entry:
+  br label %block2
+
+block1:
+  br label %block2
+
+block2:
+  %m.011 = phi i32 [ 33, %entry ], [ 0, %block1 ]
+  %cmp.i = icmp ugt i32 %m.011, 1
+  %m.1.op = lshr i32 1, %m.011
+  %sext.mask = and i32 %m.1.op, 65535
+  %cmp115 = icmp ne i32 %sext.mask, 0
+  %cmp1 = or i1 %cmp.i, %cmp115
+  %conv2 = zext i1 %cmp1 to i32
+  ret i32 %conv2
+
+; CHECK-LABEL: dont_widen_undef(
+; CHECK:         %m.011 = phi i32 [ 33, %entry ], [ 0, %block1 ]
+; CHECK-NEXT:    %cmp.i = icmp ugt i32 %m.011, 1
+; CHECK-NEXT:    %m.1.op = lshr i32 1, %m.011
+; CHECK-NEXT:    %sext.mask = and i32 %m.1.op, 65535
+; CHECK-NEXT:    %cmp115 = icmp ne i32 %sext.mask, 0
+; CHECK-NEXT:    %cmp1 = or i1 %cmp.i, %cmp115
+; CHECK-NEXT:    %conv2 = zext i1 %cmp1 to i32
+; CHECK-NEXT:    ret i32 %conv2
+}

Added: llvm/trunk/test/Transforms/InstCombine/zext-phi.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/zext-phi.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/zext-phi.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/zext-phi.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,32 @@
+; RUN: opt < %s -instcombine -S | FileCheck %s
+
+target datalayout = "e-m:e-i64:64-n8:16:32:64"
+
+; Although i1 is not in the datalayout, we should treat it
+; as a legal type because it is a fundamental type in IR.
+; This means we should shrink the phi (sink the zexts).
+
+define i64 @sink_i1_casts(i1 %cond1, i1 %cond2) {
+; CHECK-LABEL: @sink_i1_casts(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    br i1 %cond1, label %if, label %end
+; CHECK:       if:
+; CHECK-NEXT:    br label %end
+; CHECK:       end:
+; CHECK-NEXT:    [[PHI_IN:%.*]] = phi i1 [ %cond1, %entry ], [ %cond2, %if ]
+; CHECK-NEXT:    [[PHI:%.*]] = zext i1 [[PHI_IN]] to i64
+; CHECK-NEXT:    ret i64 [[PHI]]
+;
+entry:
+  %z1 = zext i1 %cond1 to i64
+  br i1 %cond1, label %if, label %end
+
+if:
+  %z2 = zext i1 %cond2 to i64
+  br label %end
+
+end:
+  %phi = phi i64 [ %z1, %entry ], [ %z2, %if ]
+  ret i64 %phi
+}
+

Added: llvm/trunk/test/Transforms/InstCombine/zext.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/zext.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/zext.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/zext.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,174 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt < %s -instcombine -S | FileCheck %s
+
+define i64 @test_sext_zext(i16 %A) {
+; CHECK-LABEL: @test_sext_zext(
+; CHECK-NEXT:    [[C2:%.*]] = zext i16 %A to i64
+; CHECK-NEXT:    ret i64 [[C2]]
+;
+  %c1 = zext i16 %A to i32
+  %c2 = sext i32 %c1 to i64
+  ret i64 %c2
+}
+
+define <2 x i64> @test2(<2 x i1> %A) {
+; CHECK-LABEL: @test2(
+; CHECK-NEXT:    [[XOR:%.*]] = xor <2 x i1> %A, <i1 true, i1 true>
+; CHECK-NEXT:    [[ZEXT:%.*]] = zext <2 x i1> [[XOR]] to <2 x i64>
+; CHECK-NEXT:    ret <2 x i64> [[ZEXT]]
+;
+  %xor = xor <2 x i1> %A, <i1 true, i1 true>
+  %zext = zext <2 x i1> %xor to <2 x i64>
+  ret <2 x i64> %zext
+}
+
+define <2 x i64> @test3(<2 x i64> %A) {
+; CHECK-LABEL: @test3(
+; CHECK-NEXT:    [[AND:%.*]] = and <2 x i64> %A, <i64 23, i64 42>
+; CHECK-NEXT:    ret <2 x i64> [[AND]]
+;
+  %trunc = trunc <2 x i64> %A to <2 x i32>
+  %and = and <2 x i32> %trunc, <i32 23, i32 42>
+  %zext = zext <2 x i32> %and to <2 x i64>
+  ret <2 x i64> %zext
+}
+
+define <2 x i64> @test4(<2 x i64> %A) {
+; CHECK-LABEL: @test4(
+; CHECK-NEXT:    [[AND:%.*]] = and <2 x i64> [[A:%.*]], <i64 23, i64 42>
+; CHECK-NEXT:    [[XOR:%.*]] = xor <2 x i64> [[AND]], <i64 23, i64 42>
+; CHECK-NEXT:    ret <2 x i64> [[XOR]]
+;
+  %trunc = trunc <2 x i64> %A to <2 x i32>
+  %and = and <2 x i32> %trunc, <i32 23, i32 42>
+  %xor = xor <2 x i32> %and, <i32 23, i32 42>
+  %zext = zext <2 x i32> %xor to <2 x i64>
+  ret <2 x i64> %zext
+}
+
+define i64 @fold_xor_zext_sandwich(i1 %a) {
+; CHECK-LABEL: @fold_xor_zext_sandwich(
+; CHECK-NEXT:    [[TMP1:%.*]] = xor i1 %a, true
+; CHECK-NEXT:    [[ZEXT2:%.*]] = zext i1 [[TMP1]] to i64
+; CHECK-NEXT:    ret i64 [[ZEXT2]]
+;
+  %zext1 = zext i1 %a to i32
+  %xor = xor i32 %zext1, 1
+  %zext2 = zext i32 %xor to i64
+  ret i64 %zext2
+}
+
+define <2 x i64> @fold_xor_zext_sandwich_vec(<2 x i1> %a) {
+; CHECK-LABEL: @fold_xor_zext_sandwich_vec(
+; CHECK-NEXT:    [[TMP1:%.*]] = xor <2 x i1> %a, <i1 true, i1 true>
+; CHECK-NEXT:    [[ZEXT2:%.*]] = zext <2 x i1> [[TMP1]] to <2 x i64>
+; CHECK-NEXT:    ret <2 x i64> [[ZEXT2]]
+;
+  %zext1 = zext <2 x i1> %a to <2 x i32>
+  %xor = xor <2 x i32> %zext1, <i32 1, i32 1>
+  %zext2 = zext <2 x i32> %xor to <2 x i64>
+  ret <2 x i64> %zext2
+}
+
+; Assert that zexts in and(zext(icmp), zext(icmp)) can be folded.
+
+define i8 @fold_and_zext_icmp(i64 %a, i64 %b, i64 %c) {
+; CHECK-LABEL: @fold_and_zext_icmp(
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp sgt i64 %a, %b
+; CHECK-NEXT:    [[TMP2:%.*]] = icmp slt i64 %a, %c
+; CHECK-NEXT:    [[TMP3:%.*]] = and i1 [[TMP1]], [[TMP2]]
+; CHECK-NEXT:    [[TMP4:%.*]] = zext i1 [[TMP3]] to i8
+; CHECK-NEXT:    ret i8 [[TMP4]]
+;
+  %1 = icmp sgt i64 %a, %b
+  %2 = zext i1 %1 to i8
+  %3 = icmp slt i64 %a, %c
+  %4 = zext i1 %3 to i8
+  %5 = and i8 %2, %4
+  ret i8 %5
+}
+
+; Assert that zexts in or(zext(icmp), zext(icmp)) can be folded.
+
+define i8 @fold_or_zext_icmp(i64 %a, i64 %b, i64 %c) {
+; CHECK-LABEL: @fold_or_zext_icmp(
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp sgt i64 %a, %b
+; CHECK-NEXT:    [[TMP2:%.*]] = icmp slt i64 %a, %c
+; CHECK-NEXT:    [[TMP3:%.*]] = or i1 [[TMP1]], [[TMP2]]
+; CHECK-NEXT:    [[TMP4:%.*]] = zext i1 [[TMP3]] to i8
+; CHECK-NEXT:    ret i8 [[TMP4]]
+;
+  %1 = icmp sgt i64 %a, %b
+  %2 = zext i1 %1 to i8
+  %3 = icmp slt i64 %a, %c
+  %4 = zext i1 %3 to i8
+  %5 = or i8 %2, %4
+  ret i8 %5
+}
+
+; Assert that zexts in xor(zext(icmp), zext(icmp)) can be folded.
+
+define i8 @fold_xor_zext_icmp(i64 %a, i64 %b, i64 %c) {
+; CHECK-LABEL: @fold_xor_zext_icmp(
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp sgt i64 %a, %b
+; CHECK-NEXT:    [[TMP2:%.*]] = icmp slt i64 %a, %c
+; CHECK-NEXT:    [[TMP3:%.*]] = xor i1 [[TMP1]], [[TMP2]]
+; CHECK-NEXT:    [[TMP4:%.*]] = zext i1 [[TMP3]] to i8
+; CHECK-NEXT:    ret i8 [[TMP4]]
+;
+  %1 = icmp sgt i64 %a, %b
+  %2 = zext i1 %1 to i8
+  %3 = icmp slt i64 %a, %c
+  %4 = zext i1 %3 to i8
+  %5 = xor i8 %2, %4
+  ret i8 %5
+}
+
+; Assert that zexts in logic(zext(icmp), zext(icmp)) are also folded accross
+; nested logical operators.
+
+define i8 @fold_nested_logic_zext_icmp(i64 %a, i64 %b, i64 %c, i64 %d) {
+; CHECK-LABEL: @fold_nested_logic_zext_icmp(
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp sgt i64 %a, %b
+; CHECK-NEXT:    [[TMP2:%.*]] = icmp slt i64 %a, %c
+; CHECK-NEXT:    [[TMP3:%.*]] = and i1 [[TMP1]], [[TMP2]]
+; CHECK-NEXT:    [[TMP4:%.*]] = icmp eq i64 %a, %d
+; CHECK-NEXT:    [[TMP5:%.*]] = or i1 [[TMP3]], [[TMP4]]
+; CHECK-NEXT:    [[TMP6:%.*]] = zext i1 [[TMP5]] to i8
+; CHECK-NEXT:    ret i8 [[TMP6]]
+;
+  %1 = icmp sgt i64 %a, %b
+  %2 = zext i1 %1 to i8
+  %3 = icmp slt i64 %a, %c
+  %4 = zext i1 %3 to i8
+  %5 = and i8 %2, %4
+  %6 = icmp eq i64 %a, %d
+  %7 = zext i1 %6 to i8
+  %8 = or i8 %5, %7
+  ret i8 %8
+}
+
+; This test is for Integer BitWidth > 64 && BitWidth <= 1024.
+
+define i1024 @sext_zext_apint1(i77 %A) {
+; CHECK-LABEL: @sext_zext_apint1(
+; CHECK-NEXT:    [[C2:%.*]] = zext i77 %A to i1024
+; CHECK-NEXT:    ret i1024 [[C2]]
+;
+  %c1 = zext i77 %A to i533
+  %c2 = sext i533 %c1 to i1024
+  ret i1024 %c2
+}
+
+; This test is for Integer BitWidth <= 64 && BitWidth % 2 != 0.
+
+define i47 @sext_zext_apint2(i11 %A) {
+; CHECK-LABEL: @sext_zext_apint2(
+; CHECK-NEXT:    [[C2:%.*]] = zext i11 %A to i47
+; CHECK-NEXT:    ret i47 [[C2]]
+;
+  %c1 = zext i11 %A to i39
+  %c2 = sext i39 %c1 to i47
+  ret i47 %c2
+}
+

Added: llvm/trunk/test/Transforms/InstMerge/exceptions.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstMerge/exceptions.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstMerge/exceptions.ll (added)
+++ llvm/trunk/test/Transforms/InstMerge/exceptions.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,61 @@
+; RUN: opt -basicaa -memdep -mldst-motion -S < %s | FileCheck %s
+; RUN: opt -aa-pipeline=basic-aa -passes='require<memdep>',mldst-motion \
+; RUN:   -S < %s | FileCheck %s
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+ at r = common global i32 0, align 4
+ at s = common global i32 0, align 4
+
+; CHECK-LABEL: define void @test1(
+define void @test1(i1 %cmp, i32* noalias %p) {
+entry:
+  br i1 %cmp, label %if.then, label %if.else
+
+if.then:                                          ; preds = %entry
+  call void @may_exit() nounwind
+  %arrayidx = getelementptr inbounds i32, i32* %p, i64 1
+  %0 = load i32, i32* %arrayidx, align 4
+  store i32 %0, i32* @r, align 4
+  br label %if.end
+; CHECK:       call void @may_exit()
+; CHECK-NEXT:  %[[gep:.*]] = getelementptr inbounds i32, i32* %p, i64 1
+; CHECK-NEXT:  %[[load:.*]] = load i32, i32* %[[gep]], align 4
+; CHECK-NEXT:  store i32 %[[load]], i32* @r, align 4
+
+if.else:                                          ; preds = %entry
+  %arrayidx1 = getelementptr inbounds i32, i32* %p, i64 1
+  %1 = load i32, i32* %arrayidx1, align 4
+  store i32 %1, i32* @s, align 4
+  br label %if.end
+
+if.end:                                           ; preds = %if.else, %if.then
+  ret void
+}
+
+; CHECK-LABEL: define void @test2(
+define void @test2(i1 %cmp, i32* noalias %p) {
+entry:
+  br i1 %cmp, label %if.then, label %if.else
+
+if.then:                                          ; preds = %entry
+  %arrayidx = getelementptr inbounds i32, i32* %p, i64 1
+  store i32 1, i32* %arrayidx, align 4
+  call void @may_throw()
+; CHECK:       %[[gep:.*]] = getelementptr inbounds i32, i32* %p, i64 1
+; CHECK-NEXT:  store i32 1, i32* %[[gep]], align 4
+; CHECK-NEXT:  call void @may_throw()
+  br label %if.end
+
+if.else:                                          ; preds = %entry
+  %arrayidx1 = getelementptr inbounds i32, i32* %p, i64 1
+  store i32 2, i32* %arrayidx1, align 4
+  br label %if.end
+
+if.end:                                           ; preds = %if.else, %if.then
+  ret void
+}
+
+declare void @may_throw()
+declare void @may_exit() nounwind

Added: llvm/trunk/test/Transforms/InstMerge/st_sink_barrier_call.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstMerge/st_sink_barrier_call.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstMerge/st_sink_barrier_call.ll (added)
+++ llvm/trunk/test/Transforms/InstMerge/st_sink_barrier_call.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,43 @@
+; Test to make sure that a function call that needs to be a barrier to sinking stores is indeed a barrier.
+; Stores sunks into the footer.
+; RUN: opt -basicaa -memdep -mldst-motion -S < %s | FileCheck %s
+target datalayout = "e-m:o-i64:64-i128:128-n32:64-S128"
+
+%struct.node = type { i32, %struct.node*, %struct.node*, %struct.node*, i32, i32, i32, i32 }
+
+declare i32 @foo(i32 %x)
+
+; Function Attrs: nounwind uwtable
+define void @sink_store(%struct.node* nocapture %r, i32 %index) {
+entry:
+  %node.0.in16 = getelementptr inbounds %struct.node, %struct.node* %r, i64 0, i32 2
+  %node.017 = load %struct.node*, %struct.node** %node.0.in16, align 8
+  %index.addr = alloca i32, align 4
+  store i32 %index, i32* %index.addr, align 4
+  %0 = load i32, i32* %index.addr, align 4
+  %cmp = icmp slt i32 %0, 0
+  br i1 %cmp, label %if.then, label %if.else
+
+; CHECK: if.then
+if.then:                                          ; preds = %entry
+  %1 = load i32, i32* %index.addr, align 4
+  %p1 = getelementptr inbounds %struct.node, %struct.node* %node.017, i32 0, i32 6
+  ; CHECK: store i32
+  store i32 %1, i32* %p1, align 4
+  br label %if.end
+  
+; CHECK: if.else
+if.else:                                          ; preds = %entry
+  %2 = load i32, i32* %index.addr, align 4
+  %add = add nsw i32 %2, 1
+  %p3 = getelementptr inbounds %struct.node, %struct.node* %node.017, i32 0, i32 6
+  ; CHECK: store i32
+  store i32 %add, i32* %p3, align 4
+  call i32 @foo(i32 5)				  ;barrier
+  br label %if.end
+
+; CHECK: if.end
+if.end:                                           ; preds = %if.else, %if.then
+; CHECK-NOT: store
+  ret void
+}

Added: llvm/trunk/test/Transforms/InstMerge/st_sink_bugfix_22613.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstMerge/st_sink_bugfix_22613.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstMerge/st_sink_bugfix_22613.ll (added)
+++ llvm/trunk/test/Transforms/InstMerge/st_sink_bugfix_22613.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,106 @@
+; ModuleID = 'bug.c'
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+; RUN: opt -O2 -S < %s | FileCheck %s
+
+; CHECK-LABEL: main
+; CHECK: if.end
+; CHECK: store
+; CHECK: memset
+; CHECK: if.then
+; CHECK: store
+; CHECK: memset
+
+ at d = common global i32 0, align 4
+ at b = common global i32 0, align 4
+ at f = common global [1 x [3 x i8]] zeroinitializer, align 1
+ at e = common global i32 0, align 4
+ at c = common global i32 0, align 4
+ at a = common global i32 0, align 4
+
+; Function Attrs: nounwind uwtable
+define void @fn1() {
+entry:
+  store i32 0, i32* @d, align 4
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc8, %entry
+  %0 = load i32, i32* @d, align 4
+  %cmp = icmp slt i32 %0, 2
+  br i1 %cmp, label %for.body, label %for.end10
+
+for.body:                                         ; preds = %for.cond
+  %1 = load i32, i32* @d, align 4
+  %idxprom = sext i32 %1 to i64
+  %2 = load i32, i32* @b, align 4
+  %idxprom1 = sext i32 %2 to i64
+  %arrayidx = getelementptr inbounds [1 x [3 x i8]], [1 x [3 x i8]]* @f, i32 0, i64 %idxprom1
+  %arrayidx2 = getelementptr inbounds [3 x i8], [3 x i8]* %arrayidx, i32 0, i64 %idxprom
+  store i8 0, i8* %arrayidx2, align 1
+  store i32 0, i32* @e, align 4
+  br label %for.cond3
+
+for.cond3:                                        ; preds = %for.inc, %for.body
+  %3 = load i32, i32* @e, align 4
+  %cmp4 = icmp slt i32 %3, 3
+  br i1 %cmp4, label %for.body5, label %for.end
+
+for.body5:                                        ; preds = %for.cond3
+  %4 = load i32, i32* @c, align 4
+  %tobool = icmp ne i32 %4, 0
+  br i1 %tobool, label %if.then, label %if.end
+
+if.then:                                          ; preds = %for.body5
+  %5 = load i32, i32* @a, align 4
+  %dec = add nsw i32 %5, -1
+  store i32 %dec, i32* @a, align 4
+  br label %if.end
+
+if.end:                                           ; preds = %if.then, %for.body5
+  %6 = load i32, i32* @e, align 4
+  %idxprom6 = sext i32 %6 to i64
+  %arrayidx7 = getelementptr inbounds [3 x i8], [3 x i8]* getelementptr inbounds ([1 x [3 x i8]], [1 x [3 x i8]]* @f, i32 0, i64 0), i32 0, i64 %idxprom6
+  store i8 1, i8* %arrayidx7, align 1
+  br label %for.inc
+
+for.inc:                                          ; preds = %if.end
+  %7 = load i32, i32* @e, align 4
+  %inc = add nsw i32 %7, 1
+  store i32 %inc, i32* @e, align 4
+  br label %for.cond3
+
+for.end:                                          ; preds = %for.cond3
+  br label %for.inc8
+
+for.inc8:                                         ; preds = %for.end
+  %8 = load i32, i32* @d, align 4
+  %inc9 = add nsw i32 %8, 1
+  store i32 %inc9, i32* @d, align 4
+  br label %for.cond
+
+for.end10:                                        ; preds = %for.cond
+  ret void
+}
+
+; Function Attrs: nounwind uwtable
+define i32 @main() {
+entry:
+  %retval = alloca i32, align 4
+  store i32 0, i32* %retval
+  call void @fn1()
+  %0 = load i8, i8* getelementptr inbounds ([1 x [3 x i8]], [1 x [3 x i8]]* @f, i32 0, i64 0, i64 1), align 1
+  %conv = sext i8 %0 to i32
+  %cmp = icmp ne i32 %conv, 1
+  br i1 %cmp, label %if.then, label %if.end
+
+if.then:                                          ; preds = %entry
+  call void @abort()
+  unreachable
+
+if.end:                                           ; preds = %entry
+  ret i32 0
+}
+
+; Function Attrs: noreturn nounwind
+declare void @abort()

Added: llvm/trunk/test/Transforms/InstMerge/st_sink_check_debug.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstMerge/st_sink_check_debug.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstMerge/st_sink_check_debug.ll (added)
+++ llvm/trunk/test/Transforms/InstMerge/st_sink_check_debug.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,33 @@
+; RUN: opt < %s -S -debugify -mldst-motion -o - | FileCheck %s
+
+%struct.S = type { i32 }
+
+define dso_local void @foo(%struct.S* %this, i32 %bar) {
+entry:
+  %this.addr = alloca %struct.S*, align 8
+  %bar.addr = alloca i32, align 4
+  store %struct.S* %this, %struct.S** %this.addr, align 8
+  store i32 %bar, i32* %bar.addr, align 4
+  %this1 = load %struct.S*, %struct.S** %this.addr, align 8
+  %0 = load i32, i32* %bar.addr, align 4
+  %tobool = icmp ne i32 %0, 0
+  br i1 %tobool, label %if.then, label %if.else
+
+if.then:                                          ; preds = %entry
+  %foo = getelementptr inbounds %struct.S, %struct.S* %this1, i32 0, i32 0
+  store i32 1, i32* %foo, align 4
+  br label %if.end
+
+if.else:                                          ; preds = %entry
+  %foo2 = getelementptr inbounds %struct.S, %struct.S* %this1, i32 0, i32 0
+  store i32 0, i32* %foo2, align 4
+  br label %if.end
+
+if.end:                                           ; preds = %if.else, %if.then
+  ret void
+}
+
+; CHECK:      @foo
+; CHECK:      if.end: ; preds = %if.else, %if.then
+; CHECK-NEXT:   %.sink = phi {{.*}} !dbg ![[DBG:[0-9]+]]
+; CHECK: ![[DBG]] = !DILocation(line: 0,

Added: llvm/trunk/test/Transforms/InstMerge/st_sink_debuginvariant.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstMerge/st_sink_debuginvariant.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstMerge/st_sink_debuginvariant.ll (added)
+++ llvm/trunk/test/Transforms/InstMerge/st_sink_debuginvariant.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,156 @@
+; RUN: opt < %s -S -mldst-motion -o - | FileCheck %s
+; RUN: opt < %s -S -strip-debug -mldst-motion -o - | FileCheck %s
+
+; Verify that the amount of stores that are sunk is invariant regarding debug
+; info.  This used to fail due to including dbg.value instructions when
+; calculating the size of a basic block for the "MagicCompileTimeControl"
+; check in MergedLoadStoreMotion::mergeStores.
+
+; CHECK-LABEL: return:
+; CHECK-NEXT:    %.sink = phi i16 [ 5, %if.end ], [ 6, %if.then ]
+; CHECK-NEXT:    %0 = getelementptr inbounds %struct.S0, %struct.S0* %agg.result, i16 0, i32 0
+; CHECK-NEXT:    store i16 %.sink, i16* %0
+; CHECK-NEXT:    %1 = getelementptr inbounds %struct.S0, %struct.S0* %agg.result, i16 0, i32 1
+; CHECK-NEXT:    store i16 0, i16* %1
+; CHECK-NEXT:    ret void
+
+%struct.S0 = type { i16, i16 }
+
+ at g_173 = dso_local local_unnamed_addr global i16 0, !dbg !0
+
+; Function Attrs: noinline norecurse nounwind
+define dso_local void @func_34(%struct.S0* noalias sret %agg.result) local_unnamed_addr #0 !dbg !11 {
+entry:
+  br i1 undef, label %if.end, label %if.then, !dbg !18
+
+if.then:                                          ; preds = %entry
+  call void @llvm.dbg.value(metadata i16 5, metadata !19, metadata !DIExpression()), !dbg !22
+  call void @llvm.dbg.value(metadata i16 5, metadata !19, metadata !DIExpression()), !dbg !22
+  call void @llvm.dbg.value(metadata i16 5, metadata !19, metadata !DIExpression()), !dbg !22
+  call void @llvm.dbg.value(metadata i16 5, metadata !19, metadata !DIExpression()), !dbg !22
+  call void @llvm.dbg.value(metadata i16 5, metadata !19, metadata !DIExpression()), !dbg !22
+  call void @llvm.dbg.value(metadata i16 5, metadata !19, metadata !DIExpression()), !dbg !22
+  call void @llvm.dbg.value(metadata i16 5, metadata !19, metadata !DIExpression()), !dbg !22
+  call void @llvm.dbg.value(metadata i16 5, metadata !19, metadata !DIExpression()), !dbg !22
+  call void @llvm.dbg.value(metadata i16 5, metadata !19, metadata !DIExpression()), !dbg !22
+  call void @llvm.dbg.value(metadata i16 5, metadata !19, metadata !DIExpression()), !dbg !22
+  call void @llvm.dbg.value(metadata i16 5, metadata !19, metadata !DIExpression()), !dbg !22
+  call void @llvm.dbg.value(metadata i16 5, metadata !19, metadata !DIExpression()), !dbg !22
+  call void @llvm.dbg.value(metadata i16 5, metadata !19, metadata !DIExpression()), !dbg !22
+  call void @llvm.dbg.value(metadata i16 5, metadata !19, metadata !DIExpression()), !dbg !22
+  call void @llvm.dbg.value(metadata i16 5, metadata !19, metadata !DIExpression()), !dbg !22
+  call void @llvm.dbg.value(metadata i16 5, metadata !19, metadata !DIExpression()), !dbg !22
+  call void @llvm.dbg.value(metadata i16 5, metadata !19, metadata !DIExpression()), !dbg !22
+  call void @llvm.dbg.value(metadata i16 5, metadata !19, metadata !DIExpression()), !dbg !22
+  call void @llvm.dbg.value(metadata i16 5, metadata !19, metadata !DIExpression()), !dbg !22
+  call void @llvm.dbg.value(metadata i16 5, metadata !19, metadata !DIExpression()), !dbg !22
+  call void @llvm.dbg.value(metadata i16 5, metadata !19, metadata !DIExpression()), !dbg !22
+  call void @llvm.dbg.value(metadata i16 5, metadata !19, metadata !DIExpression()), !dbg !22
+  call void @llvm.dbg.value(metadata i16 5, metadata !19, metadata !DIExpression()), !dbg !22
+  call void @llvm.dbg.value(metadata i16 5, metadata !19, metadata !DIExpression()), !dbg !22
+  call void @llvm.dbg.value(metadata i16 5, metadata !19, metadata !DIExpression()), !dbg !22
+  call void @llvm.dbg.value(metadata i16 5, metadata !19, metadata !DIExpression()), !dbg !22
+  call void @llvm.dbg.value(metadata i16 5, metadata !19, metadata !DIExpression()), !dbg !22
+  call void @llvm.dbg.value(metadata i16 5, metadata !19, metadata !DIExpression()), !dbg !22
+  call void @llvm.dbg.value(metadata i16 5, metadata !19, metadata !DIExpression()), !dbg !22
+  call void @llvm.dbg.value(metadata i16 5, metadata !19, metadata !DIExpression()), !dbg !22
+  call void @llvm.dbg.value(metadata i16 5, metadata !19, metadata !DIExpression()), !dbg !22
+  call void @llvm.dbg.value(metadata i16 5, metadata !19, metadata !DIExpression()), !dbg !22
+  call void @llvm.dbg.value(metadata i16 5, metadata !19, metadata !DIExpression()), !dbg !22
+  call void @llvm.dbg.value(metadata i16 5, metadata !19, metadata !DIExpression()), !dbg !22
+  call void @llvm.dbg.value(metadata i16 5, metadata !19, metadata !DIExpression()), !dbg !22
+  call void @llvm.dbg.value(metadata i16 5, metadata !19, metadata !DIExpression()), !dbg !22
+  call void @llvm.dbg.value(metadata i16 5, metadata !19, metadata !DIExpression()), !dbg !22
+  call void @llvm.dbg.value(metadata i16 5, metadata !19, metadata !DIExpression()), !dbg !22
+  call void @llvm.dbg.value(metadata i16 5, metadata !19, metadata !DIExpression()), !dbg !22
+  call void @llvm.dbg.value(metadata i16 5, metadata !19, metadata !DIExpression()), !dbg !22
+  call void @llvm.dbg.value(metadata i16 5, metadata !19, metadata !DIExpression()), !dbg !22
+  call void @llvm.dbg.value(metadata i16 5, metadata !19, metadata !DIExpression()), !dbg !22
+  call void @llvm.dbg.value(metadata i16 5, metadata !19, metadata !DIExpression()), !dbg !22
+  call void @llvm.dbg.value(metadata i16 5, metadata !19, metadata !DIExpression()), !dbg !22
+  call void @llvm.dbg.value(metadata i16 5, metadata !19, metadata !DIExpression()), !dbg !22
+  call void @llvm.dbg.value(metadata i16 5, metadata !19, metadata !DIExpression()), !dbg !22
+  call void @llvm.dbg.value(metadata i16 5, metadata !19, metadata !DIExpression()), !dbg !22
+  call void @llvm.dbg.value(metadata i16 5, metadata !19, metadata !DIExpression()), !dbg !22
+  call void @llvm.dbg.value(metadata i16 5, metadata !19, metadata !DIExpression()), !dbg !22
+  call void @llvm.dbg.value(metadata i16 5, metadata !19, metadata !DIExpression()), !dbg !22
+  call void @llvm.dbg.value(metadata i16 5, metadata !19, metadata !DIExpression()), !dbg !22
+  call void @llvm.dbg.value(metadata i16 5, metadata !19, metadata !DIExpression()), !dbg !22
+  call void @llvm.dbg.value(metadata i16 5, metadata !19, metadata !DIExpression()), !dbg !22
+  call void @llvm.dbg.value(metadata i16 5, metadata !19, metadata !DIExpression()), !dbg !22
+  call void @llvm.dbg.value(metadata i16 5, metadata !19, metadata !DIExpression()), !dbg !22
+  call void @llvm.dbg.value(metadata i16 5, metadata !19, metadata !DIExpression()), !dbg !22
+  call void @llvm.dbg.value(metadata i16 5, metadata !19, metadata !DIExpression()), !dbg !22
+  call void @llvm.dbg.value(metadata i16 5, metadata !19, metadata !DIExpression()), !dbg !22
+  call void @llvm.dbg.value(metadata i16 5, metadata !19, metadata !DIExpression()), !dbg !22
+  call void @llvm.dbg.value(metadata i16 5, metadata !19, metadata !DIExpression()), !dbg !22
+  call void @llvm.dbg.value(metadata i16 5, metadata !19, metadata !DIExpression()), !dbg !22
+  call void @llvm.dbg.value(metadata i16 5, metadata !19, metadata !DIExpression()), !dbg !22
+  call void @llvm.dbg.value(metadata i16 5, metadata !19, metadata !DIExpression()), !dbg !22
+  call void @llvm.dbg.value(metadata i16 5, metadata !19, metadata !DIExpression()), !dbg !22
+  call void @llvm.dbg.value(metadata i16 5, metadata !19, metadata !DIExpression()), !dbg !22
+  call void @llvm.dbg.value(metadata i16 5, metadata !19, metadata !DIExpression()), !dbg !22
+  call void @llvm.dbg.value(metadata i16 5, metadata !19, metadata !DIExpression()), !dbg !22
+  call void @llvm.dbg.value(metadata i16 5, metadata !19, metadata !DIExpression()), !dbg !22
+  call void @llvm.dbg.value(metadata i16 5, metadata !19, metadata !DIExpression()), !dbg !22
+  call void @llvm.dbg.value(metadata i16 5, metadata !19, metadata !DIExpression()), !dbg !22
+  call void @llvm.dbg.value(metadata i16 5, metadata !19, metadata !DIExpression()), !dbg !22
+  call void @llvm.dbg.value(metadata i16 5, metadata !19, metadata !DIExpression()), !dbg !22
+  %l_303.sroa.0.0..sroa_idx = getelementptr inbounds %struct.S0, %struct.S0* %agg.result, i16 0, i32 0, !dbg !23
+  store i16 6, i16* %l_303.sroa.0.0..sroa_idx, !dbg !23
+  %l_303.sroa.2.0..sroa_idx1 = getelementptr inbounds %struct.S0, %struct.S0* %agg.result, i16 0, i32 1, !dbg !23
+  store i16 0, i16* %l_303.sroa.2.0..sroa_idx1, !dbg !23
+  br label %return, !dbg !24
+
+if.end:                                           ; preds = %entry
+  %f037 = getelementptr inbounds %struct.S0, %struct.S0* %agg.result, i16 0, i32 0, !dbg !25
+  store i16 5, i16* %f037, !dbg !25
+  %f138 = getelementptr inbounds %struct.S0, %struct.S0* %agg.result, i16 0, i32 1, !dbg !25
+  store i16 0, i16* %f138, !dbg !25
+  store i16 0, i16* @g_173, !dbg !27
+  br label %return, !dbg !28
+
+return:                                           ; preds = %if.end, %if.then
+  ret void, !dbg !29
+}
+
+; Function Attrs: nounwind readnone speculatable
+declare void @llvm.dbg.value(metadata, metadata, metadata) #1
+
+attributes #0 = { noinline norecurse nounwind }
+attributes #1 = { nounwind readnone speculatable }
+
+!llvm.dbg.cu = !{!2}
+!llvm.module.flags = !{!7, !8, !9}
+!llvm.ident = !{!10}
+
+!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression())
+!1 = distinct !DIGlobalVariable(name: "g_173", scope: !2, file: !3, line: 7, type: !6, isLocal: false, isDefinition: true)
+!2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, producer: "clang version 7.0.0 (x)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !5)
+!3 = !DIFile(filename: "csmith11794002068761.c", directory: "")
+!4 = !{}
+!5 = !{!0}
+!6 = !DIBasicType(name: "int", size: 16, encoding: DW_ATE_signed)
+!7 = !{i32 2, !"Dwarf Version", i32 4}
+!8 = !{i32 2, !"Debug Info Version", i32 3}
+!9 = !{i32 1, !"wchar_size", i32 1}
+!10 = !{!"clang version 7.0.0 (x)"}
+!11 = distinct !DISubprogram(name: "func_34", scope: !3, file: !3, line: 16, type: !12, isLocal: false, isDefinition: true, scopeLine: 16, isOptimized: false, unit: !2, retainedNodes: !4)
+!12 = !DISubroutineType(types: !13)
+!13 = !{!14}
+!14 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "S0", file: !3, line: 2, size: 32, elements: !15)
+!15 = !{!16, !17}
+!16 = !DIDerivedType(tag: DW_TAG_member, name: "f0", scope: !14, file: !3, line: 3, baseType: !6, size: 16)
+!17 = !DIDerivedType(tag: DW_TAG_member, name: "f1", scope: !14, file: !3, line: 4, baseType: !6, size: 16, offset: 16)
+!18 = !DILocation(line: 18, column: 7, scope: !11)
+!19 = !DILocalVariable(name: "left", scope: !20, file: !3, line: 23, type: !6)
+!20 = distinct !DILexicalBlock(scope: !21, file: !3, line: 18, column: 14)
+!21 = distinct !DILexicalBlock(scope: !11, file: !3, line: 18, column: 7)
+!22 = !DILocation(line: 23, column: 9, scope: !20)
+!23 = !DILocation(line: 26, column: 12, scope: !20)
+!24 = !DILocation(line: 26, column: 5, scope: !20)
+!25 = !DILocation(line: 29, column: 23, scope: !26)
+!26 = distinct !DILexicalBlock(scope: !11, file: !3, line: 28, column: 3)
+!27 = !DILocation(line: 30, column: 11, scope: !26)
+!28 = !DILocation(line: 31, column: 5, scope: !26)
+!29 = !DILocation(line: 33, column: 1, scope: !11)

Added: llvm/trunk/test/Transforms/InstMerge/st_sink_no_barrier_call.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstMerge/st_sink_no_barrier_call.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstMerge/st_sink_no_barrier_call.ll (added)
+++ llvm/trunk/test/Transforms/InstMerge/st_sink_no_barrier_call.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,45 @@
+; Test to make sure that stores in a diamond get merged with a non barrier function call after the store instruction
+; Stores sunks into the footer.
+; RUN: opt -basicaa -memdep -mldst-motion -S < %s | FileCheck %s
+target datalayout = "e-m:o-i64:64-i128:128-n32:64-S128"
+
+%struct.node = type { i32, %struct.node*, %struct.node*, %struct.node*, i32, i32, i32, i32 }
+
+declare i32 @foo(i32 %x) #0
+
+; Function Attrs: nounwind uwtable
+define void @sink_store(%struct.node* nocapture %r, i32 %index) {
+entry:
+  %node.0.in16 = getelementptr inbounds %struct.node, %struct.node* %r, i64 0, i32 2
+  %node.017 = load %struct.node*, %struct.node** %node.0.in16, align 8
+  %index.addr = alloca i32, align 4
+  store i32 %index, i32* %index.addr, align 4
+  %0 = load i32, i32* %index.addr, align 4
+  %cmp = icmp slt i32 %0, 0
+  br i1 %cmp, label %if.then, label %if.else
+
+; CHECK: if.then
+if.then:                                          ; preds = %entry
+  %1 = load i32, i32* %index.addr, align 4
+  %p1 = getelementptr inbounds %struct.node, %struct.node* %node.017, i32 0, i32 6
+  ; CHECK-NOT: store i32
+  store i32 %1, i32* %p1, align 4
+  br label %if.end
+  
+; CHECK: if.else
+if.else:                                          ; preds = %entry
+  %2 = load i32, i32* %index.addr, align 4
+  %add = add nsw i32 %2, 1
+  %p3 = getelementptr inbounds %struct.node, %struct.node* %node.017, i32 0, i32 6
+  ; CHECK-NOT: store i32
+  store i32 %add, i32* %p3, align 4
+  call i32 @foo(i32 5) nounwind				  ;not a barrier
+  br label %if.end
+
+; CHECK: if.end
+if.end:                                           ; preds = %if.else, %if.then
+; CHECK: store
+  ret void
+}
+
+attributes #0 = { readnone } 

Added: llvm/trunk/test/Transforms/InstMerge/st_sink_no_barrier_load.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstMerge/st_sink_no_barrier_load.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstMerge/st_sink_no_barrier_load.ll (added)
+++ llvm/trunk/test/Transforms/InstMerge/st_sink_no_barrier_load.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,43 @@
+; Test to make sure that stores in a diamond get merged with a non barrier load after the store instruction
+; Stores sunks into the footer.
+; RUN: opt -basicaa -memdep -mldst-motion -S < %s | FileCheck %s
+target datalayout = "e-m:o-i64:64-i128:128-n32:64-S128"
+
+%struct.node = type { i32, %struct.node*, %struct.node*, %struct.node*, i32, i32, i32, i32 }
+
+; Function Attrs: nounwind uwtable
+define void @sink_store(%struct.node* nocapture %r, i32 %index) {
+entry:
+  %node.0.in16 = getelementptr inbounds %struct.node, %struct.node* %r, i64 0, i32 2
+  %node.017 = load %struct.node*, %struct.node** %node.0.in16, align 8
+  %index.addr = alloca i32, align 4
+  store i32 %index, i32* %index.addr, align 4
+  %0 = load i32, i32* %index.addr, align 4
+  %cmp = icmp slt i32 %0, 0
+  br i1 %cmp, label %if.then, label %if.else
+
+; CHECK: if.then
+if.then:                                          ; preds = %entry
+  %1 = load i32, i32* %index.addr, align 4
+  %p1 = getelementptr inbounds %struct.node, %struct.node* %node.017, i32 0, i32 6
+  ; CHECK-NOT: store i32
+  store i32 %1, i32* %p1, align 4
+  %p2 = getelementptr inbounds %struct.node, %struct.node* %node.017, i32 5, i32 6
+  ; CHECK: load i32, i32*
+  %not_barrier = load i32 , i32 * %p2, align 4
+  br label %if.end
+
+; CHECK: if.else
+if.else:                                          ; preds = %entry
+  %2 = load i32, i32* %index.addr, align 4
+  %add = add nsw i32 %2, 1
+  %p3 = getelementptr inbounds %struct.node, %struct.node* %node.017, i32 0, i32 6
+  ; CHECK-NOT: store i32
+  store i32 %add, i32* %p3, align 4
+  br label %if.end
+
+; CHECK: if.end
+if.end:                                           ; preds = %if.else, %if.then
+; CHECK: store
+  ret void
+}

Added: llvm/trunk/test/Transforms/InstMerge/st_sink_no_barrier_store.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstMerge/st_sink_no_barrier_store.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstMerge/st_sink_no_barrier_store.ll (added)
+++ llvm/trunk/test/Transforms/InstMerge/st_sink_no_barrier_store.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,42 @@
+; Test to make sure that stores in a diamond get merged with a non barrier store after the store instruction to be sunk
+; Stores sunks into the footer.
+; RUN: opt -basicaa -memdep -mldst-motion -S < %s | FileCheck %s
+target datalayout = "e-m:o-i64:64-i128:128-n32:64-S128"
+
+%struct.node = type { i32, %struct.node*, %struct.node*, %struct.node*, i32, i32, i32, i32 }
+
+; Function Attrs: nounwind uwtable
+define void @sink_store(%struct.node* nocapture %r, i32 %index) {
+entry:
+  %node.0.in16 = getelementptr inbounds %struct.node, %struct.node* %r, i64 0, i32 2
+  %node.017 = load %struct.node*, %struct.node** %node.0.in16, align 8
+  %index.addr = alloca i32, align 4
+  store i32 %index, i32* %index.addr, align 4
+  %0 = load i32, i32* %index.addr, align 4
+  %cmp = icmp slt i32 %0, 0
+  br i1 %cmp, label %if.then, label %if.else
+
+; CHECK: if.then
+if.then:                                          ; preds = %entry
+  %1 = load i32, i32* %index.addr, align 4
+  %p1 = getelementptr inbounds %struct.node, %struct.node* %node.017, i32 0, i32 6
+  ; CHECK-NOT: store i32
+  store i32 %1, i32* %p1, align 4
+  br label %if.end
+
+; CHECK: if.else
+if.else:                                          ; preds = %entry
+  %2 = load i32, i32* %index.addr, align 4
+  %add = add nsw i32 %2, 1
+  %p2 = getelementptr inbounds %struct.node, %struct.node* %node.017, i32 0, i32 6
+  store i32 %add, i32* %p2, align 4
+  %p3 = getelementptr inbounds %struct.node, %struct.node* %node.017, i32 5, i32 6
+  ; CHECK: store i32
+  store i32 %add, i32* %p3, align 4  			  ; This is not a barrier
+  br label %if.end
+
+; CHECK: if.end
+if.end:                                           ; preds = %if.else, %if.then
+; CHECK: store
+  ret void
+}

Added: llvm/trunk/test/Transforms/InstMerge/st_sink_two_stores.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstMerge/st_sink_two_stores.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstMerge/st_sink_two_stores.ll (added)
+++ llvm/trunk/test/Transforms/InstMerge/st_sink_two_stores.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,47 @@
+; Test to make sure that stores in a diamond get merged
+; Stores sunks into the footer.
+; RUN: opt -basicaa -memdep -mldst-motion -S < %s | FileCheck %s
+target datalayout = "e-m:o-i64:64-i128:128-n32:64-S128"
+
+%struct.node = type { i32, %struct.node*, %struct.node*, %struct.node*, i32, i32, i32, i32 }
+
+; Function Attrs: nounwind uwtable
+define void @sink_store(%struct.node* nocapture %r, i32 %index) {
+entry:
+  %node.0.in16 = getelementptr inbounds %struct.node, %struct.node* %r, i64 0, i32 2
+  %node.017 = load %struct.node*, %struct.node** %node.0.in16, align 8
+  %index.addr = alloca i32, align 4
+  store i32 %index, i32* %index.addr, align 4
+  %0 = load i32, i32* %index.addr, align 4
+  %cmp = icmp slt i32 %0, 0
+  br i1 %cmp, label %if.then, label %if.else
+
+; CHECK: if.then
+if.then:                                          ; preds = %entry
+  %1 = load i32, i32* %index.addr, align 4
+  %p1 = getelementptr inbounds %struct.node, %struct.node* %node.017, i32 0, i32 6
+  ; CHECK-NOT: store i32
+  store i32 %1, i32* %p1, align 4
+  %p2 = getelementptr inbounds %struct.node, %struct.node* %node.017, i32 4, i32 6
+  ; CHECK-NOT: store i32
+  store i32 %1, i32* %p2, align 4
+  br label %if.end
+
+; CHECK: if.else
+if.else:                                          ; preds = %entry
+  %2 = load i32, i32* %index.addr, align 4
+  %add = add nsw i32 %2, 1
+  %p3 = getelementptr inbounds %struct.node, %struct.node* %node.017, i32 0, i32 6
+  ; CHECK-NOT: store i32
+  store i32 %add, i32* %p3, align 4
+  %p4 = getelementptr inbounds %struct.node, %struct.node* %node.017, i32 4, i32 6
+  ; CHECK-NOT: store i32
+  store i32 %2, i32* %p4, align 4  
+  br label %if.end
+
+; CHECK: if.end
+if.end:                                           ; preds = %if.else, %if.then
+; CHECK: store
+; CHECK: store
+  ret void
+}

Added: llvm/trunk/test/Transforms/InstMerge/st_sink_with_barrier.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstMerge/st_sink_with_barrier.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstMerge/st_sink_with_barrier.ll (added)
+++ llvm/trunk/test/Transforms/InstMerge/st_sink_with_barrier.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,42 @@
+; Test to make sure that load from the same address as a store and appears after the store prevents the store from being sunk
+; RUN: opt -basicaa -memdep -mldst-motion -S < %s | FileCheck %s
+target datalayout = "e-m:o-i64:64-i128:128-n32:64-S128"
+
+%struct.node = type { i32, %struct.node*, %struct.node*, %struct.node*, i32, i32, i32, i32 }
+
+; Function Attrs: nounwind uwtable
+define void @sink_store(%struct.node* nocapture %r, i32 %index) {
+entry:
+  %node.0.in16 = getelementptr inbounds %struct.node, %struct.node* %r, i64 0, i32 2
+  %node.017 = load %struct.node*, %struct.node** %node.0.in16, align 8
+  %index.addr = alloca i32, align 4
+  store i32 %index, i32* %index.addr, align 4
+  %0 = load i32, i32* %index.addr, align 4
+  %cmp = icmp slt i32 %0, 0
+  br i1 %cmp, label %if.then, label %if.else
+
+; CHECK: if.then
+if.then:                                          ; preds = %entry
+  %1 = load i32, i32* %index.addr, align 4
+  %p1 = getelementptr inbounds %struct.node, %struct.node* %node.017, i32 0, i32 6
+  ; CHECK: store i32
+  store i32 %1, i32* %p1, align 4
+  %p2 = getelementptr inbounds %struct.node, %struct.node* %node.017, i32 0, i32 6
+  ; CHECK: load i32, i32*
+  %barrier = load i32 , i32 * %p2, align 4
+  br label %if.end
+
+; CHECK: if.else
+if.else:                                          ; preds = %entry
+  %2 = load i32, i32* %index.addr, align 4
+  %add = add nsw i32 %2, 1
+  %p3 = getelementptr inbounds %struct.node, %struct.node* %node.017, i32 0, i32 6
+  ; CHECK: store i32
+  store i32 %add, i32* %p3, align 4
+  br label %if.end
+
+; CHECK: if.end
+if.end:                                           ; preds = %if.else, %if.then
+; CHECK-NOT: store
+  ret void
+}

Added: llvm/trunk/test/Transforms/InstNamer/basic.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstNamer/basic.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstNamer/basic.ll (added)
+++ llvm/trunk/test/Transforms/InstNamer/basic.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,19 @@
+; RUN: opt -S -instnamer < %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 @f_0(i32) {
+; CHECK-LABEL: @f_0(
+; CHECK: bb:
+; CHECK-NEXT:   %tmp = add i32 %arg, 2
+; CHECK-NEXT:   br label %bb1
+; CHECK: bb1:
+; CHECK-NEXT:   ret i32 %tmp
+
+  %2 = add i32 %0, 2
+  br label %3
+
+; <label>:3:
+  ret i32 %2
+}

Added: llvm/trunk/test/Transforms/InstSimplify/2010-12-20-Boolean.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstSimplify/2010-12-20-Boolean.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstSimplify/2010-12-20-Boolean.ll (added)
+++ llvm/trunk/test/Transforms/InstSimplify/2010-12-20-Boolean.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,34 @@
+; NOTE: Assertions have been autogenerated by update_test_checks.py
+; RUN: opt < %s -instsimplify -S | FileCheck %s
+
+define i1 @add(i1 %x) {
+; CHECK-LABEL: @add(
+; CHECK:         ret i1 false
+;
+  %z = add i1 %x, %x
+  ret i1 %z
+}
+
+define i1 @sub(i1 %x) {
+; CHECK-LABEL: @sub(
+; CHECK:         ret i1 %x
+;
+  %z = sub i1 false, %x
+  ret i1 %z
+}
+
+define i1 @mul(i1 %x) {
+; CHECK-LABEL: @mul(
+; CHECK:         ret i1 %x
+;
+  %z = mul i1 %x, %x
+  ret i1 %z
+}
+
+define i1 @ne(i1 %x) {
+; CHECK-LABEL: @ne(
+; CHECK:         ret i1 %x
+;
+  %z = icmp ne i1 %x, 0
+  ret i1 %z
+}

Added: llvm/trunk/test/Transforms/InstSimplify/2011-01-14-Thread.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstSimplify/2011-01-14-Thread.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstSimplify/2011-01-14-Thread.ll (added)
+++ llvm/trunk/test/Transforms/InstSimplify/2011-01-14-Thread.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,9 @@
+; RUN: opt < %s -instsimplify -S | FileCheck %s
+
+define i32 @shift_select(i1 %cond) {
+; CHECK-LABEL: @shift_select(
+  %s = select i1 %cond, i32 0, i32 1
+  %r = lshr i32 %s, 1
+  ret i32 %r
+; CHECK: ret i32 0
+}

Added: llvm/trunk/test/Transforms/InstSimplify/2011-02-01-Vector.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstSimplify/2011-02-01-Vector.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstSimplify/2011-02-01-Vector.ll (added)
+++ llvm/trunk/test/Transforms/InstSimplify/2011-02-01-Vector.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,8 @@
+; RUN: opt < %s -instsimplify -S | FileCheck %s
+
+define <2 x i32> @sdiv(<2 x i32> %x) {
+; CHECK-LABEL: @sdiv(
+  %div = sdiv <2 x i32> %x, <i32 1, i32 1>
+  ret <2 x i32> %div
+; CHECK: ret <2 x i32> %x
+}

Added: llvm/trunk/test/Transforms/InstSimplify/2011-09-05-InsertExtractValue.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstSimplify/2011-09-05-InsertExtractValue.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstSimplify/2011-09-05-InsertExtractValue.ll (added)
+++ llvm/trunk/test/Transforms/InstSimplify/2011-09-05-InsertExtractValue.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,55 @@
+; RUN: opt < %s -instsimplify -S | FileCheck %s
+
+declare void @bar()
+
+define void @test1() personality i32 (i32, i64, i8*, i8*)* @__gxx_personality_v0 {
+entry:
+  invoke void @bar() to label %cont unwind label %lpad
+cont:
+  ret void
+lpad:
+  %ex = landingpad { i8*, i32 } cleanup
+  %exc_ptr = extractvalue { i8*, i32 } %ex, 0
+  %filter = extractvalue { i8*, i32 } %ex, 1
+  %exc_ptr2 = insertvalue { i8*, i32 } undef, i8* %exc_ptr, 0
+  %filter2 = insertvalue { i8*, i32 } %exc_ptr2, i32 %filter, 1
+  resume { i8*, i32 } %filter2
+; CHECK-LABEL: @test1(
+; CHECK-NOT: extractvalue
+; CHECK-NOT: insertvalue
+}
+
+declare i32 @__gxx_personality_v0(i32, i64, i8*, i8*)
+
+define { i8, i32 } @test2({ i8*, i32 } %x) {
+  %ex = extractvalue { i8*, i32 } %x, 1
+  %ins = insertvalue { i8, i32 } undef, i32 %ex, 1
+  ret { i8, i32 } %ins
+; CHECK-LABEL: @test2(
+}
+
+define i32 @test3(i32 %a, float %b) {
+  %agg1 = insertvalue {i32, float} undef, i32 %a, 0
+  %agg2 = insertvalue {i32, float} %agg1, float %b, 1
+  %ev = extractvalue {i32, float} %agg2, 0
+  ret i32 %ev
+; CHECK-LABEL: @test3(
+; CHECK: ret i32 %a
+}
+
+define i8 @test4(<8 x i8> %V) {
+  %add     = add <8 x i8> %V, bitcast (double 0x319BEB8FD172E36 to <8 x i8>)
+  %extract = extractelement <8 x i8> %add, i32 6
+  ret i8 %extract
+; CHECK-LABEL: @test4(
+; CHECK: %[[add:.*]] = add <8 x i8> %V, bitcast (<1 x double> <double 0x319BEB8FD172E36> to <8 x i8>)
+; CHECK-NEXT: %[[extract:.*]] = extractelement <8 x i8> %[[add]], i32 6
+; CHECK-NEXT: ret i8 %[[extract]]
+}
+
+define i32 @test5(<4 x i32> %V) {
+  %extract = extractelement <4 x i32> %V, i32 undef
+  ret i32 %extract
+}
+; CHECK-LABEL: @test5(
+; CHECK: ret i32 undef

Added: llvm/trunk/test/Transforms/InstSimplify/2011-10-27-BinOpCrash.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstSimplify/2011-10-27-BinOpCrash.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstSimplify/2011-10-27-BinOpCrash.ll (added)
+++ llvm/trunk/test/Transforms/InstSimplify/2011-10-27-BinOpCrash.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,12 @@
+; RUN: opt < %s -instcombine
+
+ at _ZN11xercesc_2_5L11gDigitCharsE = external constant [32 x i16], align 2
+ at _ZN11xercesc_2_5L10gBaseCharsE = external constant [354 x i16], align 2
+ at _ZN11xercesc_2_5L17gIdeographicCharsE = external constant [7 x i16], align 2
+ at _ZN11xercesc_2_5L15gCombiningCharsE = external constant [163 x i16], align 2
+
+define i32 @_ZN11xercesc_2_515XMLRangeFactory11buildRangesEv(i32 %x) {
+  %a = add i32 %x, add (i32 add (i32 ashr (i32 add (i32 mul (i32 ptrtoint ([32 x i16]* @_ZN11xercesc_2_5L11gDigitCharsE to i32), i32 -1), i32 ptrtoint (i16* getelementptr inbounds ([32 x i16], [32 x i16]* @_ZN11xercesc_2_5L11gDigitCharsE, i32 0, i32 30) to i32)), i32 1), i32 ashr (i32 add (i32 mul (i32 ptrtoint ([7 x i16]* @_ZN11xercesc_2_5L17gIdeographicCharsE to i32), i32 -1), i32 ptrtoint (i16* getelementptr inbounds ([7 x i16], [7 x i16]* @_ZN11xercesc_2_5L17gIdeographicCharsE, i32 0, i32 4) to i32)), i32 1)), i32 8)
+  %b = add i32 %a, %x
+  ret i32 %b
+}

Added: llvm/trunk/test/Transforms/InstSimplify/2011-11-23-MaskedBitsCrash.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstSimplify/2011-11-23-MaskedBitsCrash.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstSimplify/2011-11-23-MaskedBitsCrash.ll (added)
+++ llvm/trunk/test/Transforms/InstSimplify/2011-11-23-MaskedBitsCrash.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,17 @@
+; RUN: opt < %s -instsimplify
+
+; The mul can be proved to always overflow (turning a negative value
+; into a positive one) and thus results in undefined behaviour.  At
+; the same time we were deducing from the nsw flag that that mul could
+; be assumed to have a negative value (since if not it has an undefined
+; value, which can be taken to be negative).  We were reporting the mul
+; as being both positive and negative, firing an assertion!
+define i1 @test1(i32 %a) {
+entry:
+  %0 = or i32 %a, 1
+  %1 = shl i32 %0, 31
+  %2 = mul nsw i32 %1, 4
+  %3 = and i32 %2, -4
+  %4 = icmp ne i32 %3, 0
+  ret i1 %4
+}

Added: llvm/trunk/test/Transforms/InstSimplify/2013-04-19-ConstantFoldingCrash.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstSimplify/2013-04-19-ConstantFoldingCrash.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstSimplify/2013-04-19-ConstantFoldingCrash.ll (added)
+++ llvm/trunk/test/Transforms/InstSimplify/2013-04-19-ConstantFoldingCrash.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,9 @@
+; RUN: opt < %s -instsimplify
+
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128"
+
+; PR15791
+define <2 x i64> @test1() {
+  %a = and <2 x i64> undef, bitcast (<4 x i32> <i32 undef, i32 undef, i32 undef, i32 2147483647> to <2 x i64>)
+  ret <2 x i64> %a
+}

Added: llvm/trunk/test/Transforms/InstSimplify/AndOrXor.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstSimplify/AndOrXor.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstSimplify/AndOrXor.ll (added)
+++ llvm/trunk/test/Transforms/InstSimplify/AndOrXor.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,1134 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt < %s -instsimplify -S | FileCheck %s
+
+define i8 @and0(i8 %x) {
+; CHECK-LABEL: @and0(
+; CHECK-NEXT:    ret i8 0
+;
+  %r = and i8 %x, 0
+  ret i8 %r
+}
+
+define <2 x i8> @and0_vec_undef_elt(<2 x i8> %x) {
+; CHECK-LABEL: @and0_vec_undef_elt(
+; CHECK-NEXT:    ret <2 x i8> zeroinitializer
+;
+  %r = and <2 x i8> %x, <i8 undef, i8 0>
+  ret <2 x i8> %r
+}
+
+; add nsw (xor X, signbit), signbit --> X
+
+define <2 x i32> @add_nsw_signbit(<2 x i32> %x) {
+; CHECK-LABEL: @add_nsw_signbit(
+; CHECK-NEXT:    ret <2 x i32> [[X:%.*]]
+;
+  %y = xor <2 x i32> %x, <i32 -2147483648, i32 -2147483648>
+  %z = add nsw <2 x i32> %y, <i32 -2147483648, i32 -2147483648>
+  ret <2 x i32> %z
+}
+
+; Undef elements in either constant vector are ok.
+
+define <2 x i32> @add_nsw_signbit_undef(<2 x i32> %x) {
+; CHECK-LABEL: @add_nsw_signbit_undef(
+; CHECK-NEXT:    ret <2 x i32> [[X:%.*]]
+;
+  %y = xor <2 x i32> %x, <i32 undef, i32 -2147483648>
+  %z = add nsw <2 x i32> %y, <i32 -2147483648, i32 undef>
+  ret <2 x i32> %z
+}
+
+; add nuw (xor X, signbit), signbit --> X
+
+define <2 x i5> @add_nuw_signbit(<2 x i5> %x) {
+; CHECK-LABEL: @add_nuw_signbit(
+; CHECK-NEXT:    ret <2 x i5> [[X:%.*]]
+;
+  %y = xor <2 x i5> %x, <i5 -16, i5 -16>
+  %z = add nuw <2 x i5> %y, <i5 -16, i5 -16>
+  ret <2 x i5> %z
+}
+
+; Undef elements in either constant vector are ok.
+
+define <2 x i5> @add_nuw_signbit_undef(<2 x i5> %x) {
+; CHECK-LABEL: @add_nuw_signbit_undef(
+; CHECK-NEXT:    ret <2 x i5> [[X:%.*]]
+;
+  %y = xor <2 x i5> %x, <i5 -16, i5 undef>
+  %z = add nuw <2 x i5> %y, <i5 undef, i5 -16>
+  ret <2 x i5> %z
+}
+
+define i64 @pow2(i32 %x) {
+; CHECK-LABEL: @pow2(
+; CHECK-NEXT:    [[NEGX:%.*]] = sub i32 0, [[X:%.*]]
+; CHECK-NEXT:    [[X2:%.*]] = and i32 [[X]], [[NEGX]]
+; CHECK-NEXT:    [[E:%.*]] = zext i32 [[X2]] to i64
+; CHECK-NEXT:    ret i64 [[E]]
+;
+  %negx = sub i32 0, %x
+  %x2 = and i32 %x, %negx
+  %e = zext i32 %x2 to i64
+  %nege = sub i64 0, %e
+  %e2 = and i64 %e, %nege
+  ret i64 %e2
+}
+
+define i64 @pow2b(i32 %x) {
+; CHECK-LABEL: @pow2b(
+; CHECK-NEXT:    [[SH:%.*]] = shl i32 2, [[X:%.*]]
+; CHECK-NEXT:    [[E:%.*]] = zext i32 [[SH]] to i64
+; CHECK-NEXT:    ret i64 [[E]]
+;
+  %sh = shl i32 2, %x
+  %e = zext i32 %sh to i64
+  %nege = sub i64 0, %e
+  %e2 = and i64 %e, %nege
+  ret i64 %e2
+}
+
+define i1 @and_of_icmps0(i32 %b) {
+; CHECK-LABEL: @and_of_icmps0(
+; CHECK-NEXT:    ret i1 false
+;
+  %1 = add i32 %b, 2
+  %2 = icmp ult i32 %1, 4
+  %cmp3 = icmp sgt i32 %b, 2
+  %cmp = and i1 %2, %cmp3
+  ret i1 %cmp
+}
+
+define <2 x i1> @and_of_icmps0_vec(<2 x i32> %b) {
+; CHECK-LABEL: @and_of_icmps0_vec(
+; CHECK-NEXT:    ret <2 x i1> zeroinitializer
+;
+  %1 = add <2 x i32> %b, <i32 2, i32 2>
+  %2 = icmp ult <2 x i32> %1, <i32 4, i32 4>
+  %cmp3 = icmp sgt <2 x i32> %b, <i32 2, i32 2>
+  %cmp = and <2 x i1> %2, %cmp3
+  ret <2 x i1> %cmp
+}
+
+define i1 @and_of_icmps1(i32 %b) {
+; CHECK-LABEL: @and_of_icmps1(
+; CHECK-NEXT:    ret i1 false
+;
+  %1 = add nsw i32 %b, 2
+  %2 = icmp slt i32 %1, 4
+  %cmp3 = icmp sgt i32 %b, 2
+  %cmp = and i1 %2, %cmp3
+  ret i1 %cmp
+}
+
+define <2 x i1> @and_of_icmps1_vec(<2 x i32> %b) {
+; CHECK-LABEL: @and_of_icmps1_vec(
+; CHECK-NEXT:    ret <2 x i1> zeroinitializer
+;
+  %1 = add nsw <2 x i32> %b, <i32 2, i32 2>
+  %2 = icmp slt <2 x i32> %1, <i32 4, i32 4>
+  %cmp3 = icmp sgt <2 x i32> %b, <i32 2, i32 2>
+  %cmp = and <2 x i1> %2, %cmp3
+  ret <2 x i1> %cmp
+}
+
+define i1 @and_of_icmps2(i32 %b) {
+; CHECK-LABEL: @and_of_icmps2(
+; CHECK-NEXT:    ret i1 false
+;
+  %1 = add i32 %b, 2
+  %2 = icmp ule i32 %1, 3
+  %cmp3 = icmp sgt i32 %b, 2
+  %cmp = and i1 %2, %cmp3
+  ret i1 %cmp
+}
+
+define <2 x i1> @and_of_icmps2_vec(<2 x i32> %b) {
+; CHECK-LABEL: @and_of_icmps2_vec(
+; CHECK-NEXT:    ret <2 x i1> zeroinitializer
+;
+  %1 = add <2 x i32> %b, <i32 2, i32 2>
+  %2 = icmp ule <2 x i32> %1, <i32 3, i32 3>
+  %cmp3 = icmp sgt <2 x i32> %b, <i32 2, i32 2>
+  %cmp = and <2 x i1> %2, %cmp3
+  ret <2 x i1> %cmp
+}
+
+define i1 @and_of_icmps3(i32 %b) {
+; CHECK-LABEL: @and_of_icmps3(
+; CHECK-NEXT:    ret i1 false
+;
+  %1 = add nsw i32 %b, 2
+  %2 = icmp sle i32 %1, 3
+  %cmp3 = icmp sgt i32 %b, 2
+  %cmp = and i1 %2, %cmp3
+  ret i1 %cmp
+}
+
+define <2 x i1> @and_of_icmps3_vec(<2 x i32> %b) {
+; CHECK-LABEL: @and_of_icmps3_vec(
+; CHECK-NEXT:    ret <2 x i1> zeroinitializer
+;
+  %1 = add nsw <2 x i32> %b, <i32 2, i32 2>
+  %2 = icmp sle <2 x i32> %1, <i32 3, i32 3>
+  %cmp3 = icmp sgt <2 x i32> %b, <i32 2, i32 2>
+  %cmp = and <2 x i1> %2, %cmp3
+  ret <2 x i1> %cmp
+}
+
+define i1 @and_of_icmps4(i32 %b) {
+; CHECK-LABEL: @and_of_icmps4(
+; CHECK-NEXT:    ret i1 false
+;
+  %1 = add nuw i32 %b, 2
+  %2 = icmp ult i32 %1, 4
+  %cmp3 = icmp ugt i32 %b, 2
+  %cmp = and i1 %2, %cmp3
+  ret i1 %cmp
+}
+
+define <2 x i1> @and_of_icmps4_vec(<2 x i32> %b) {
+; CHECK-LABEL: @and_of_icmps4_vec(
+; CHECK-NEXT:    ret <2 x i1> zeroinitializer
+;
+  %1 = add nuw <2 x i32> %b, <i32 2, i32 2>
+  %2 = icmp ult <2 x i32> %1, <i32 4, i32 4>
+  %cmp3 = icmp ugt <2 x i32> %b, <i32 2, i32 2>
+  %cmp = and <2 x i1> %2, %cmp3
+  ret <2 x i1> %cmp
+}
+
+define i1 @and_of_icmps5(i32 %b) {
+; CHECK-LABEL: @and_of_icmps5(
+; CHECK-NEXT:    ret i1 false
+;
+  %1 = add nuw i32 %b, 2
+  %2 = icmp ule i32 %1, 3
+  %cmp3 = icmp ugt i32 %b, 2
+  %cmp = and i1 %2, %cmp3
+  ret i1 %cmp
+}
+
+define <2 x i1> @and_of_icmps5_vec(<2 x i32> %b) {
+; CHECK-LABEL: @and_of_icmps5_vec(
+; CHECK-NEXT:    ret <2 x i1> zeroinitializer
+;
+  %1 = add nuw <2 x i32> %b, <i32 2, i32 2>
+  %2 = icmp ule <2 x i32> %1, <i32 3, i32 3>
+  %cmp3 = icmp ugt <2 x i32> %b, <i32 2, i32 2>
+  %cmp = and <2 x i1> %2, %cmp3
+  ret <2 x i1> %cmp
+}
+
+define i1 @or_of_icmps0(i32 %b) {
+; CHECK-LABEL: @or_of_icmps0(
+; CHECK-NEXT:    ret i1 true
+;
+  %1 = add i32 %b, 2
+  %2 = icmp uge i32 %1, 4
+  %cmp3 = icmp sle i32 %b, 2
+  %cmp = or i1 %2, %cmp3
+  ret i1 %cmp
+}
+
+define <2 x i1> @or_of_icmps0_vec(<2 x i32> %b) {
+; CHECK-LABEL: @or_of_icmps0_vec(
+; CHECK-NEXT:    ret <2 x i1> <i1 true, i1 true>
+;
+  %1 = add <2 x i32> %b, <i32 2, i32 2>
+  %2 = icmp uge <2 x i32> %1, <i32 4, i32 4>
+  %cmp3 = icmp sle <2 x i32> %b, <i32 2, i32 2>
+  %cmp = or <2 x i1> %2, %cmp3
+  ret <2 x i1> %cmp
+}
+
+define i1 @or_of_icmps1(i32 %b) {
+; CHECK-LABEL: @or_of_icmps1(
+; CHECK-NEXT:    ret i1 true
+;
+  %1 = add nsw i32 %b, 2
+  %2 = icmp sge i32 %1, 4
+  %cmp3 = icmp sle i32 %b, 2
+  %cmp = or i1 %2, %cmp3
+  ret i1 %cmp
+}
+
+define <2 x i1> @or_of_icmps1_vec(<2 x i32> %b) {
+; CHECK-LABEL: @or_of_icmps1_vec(
+; CHECK-NEXT:    ret <2 x i1> <i1 true, i1 true>
+;
+  %1 = add nsw <2 x i32> %b, <i32 2, i32 2>
+  %2 = icmp sge <2 x i32> %1, <i32 4, i32 4>
+  %cmp3 = icmp sle <2 x i32> %b, <i32 2, i32 2>
+  %cmp = or <2 x i1> %2, %cmp3
+  ret <2 x i1> %cmp
+}
+
+define i1 @or_of_icmps2(i32 %b) {
+; CHECK-LABEL: @or_of_icmps2(
+; CHECK-NEXT:    ret i1 true
+;
+  %1 = add i32 %b, 2
+  %2 = icmp ugt i32 %1, 3
+  %cmp3 = icmp sle i32 %b, 2
+  %cmp = or i1 %2, %cmp3
+  ret i1 %cmp
+}
+
+define <2 x i1> @or_of_icmps2_vec(<2 x i32> %b) {
+; CHECK-LABEL: @or_of_icmps2_vec(
+; CHECK-NEXT:    ret <2 x i1> <i1 true, i1 true>
+;
+  %1 = add <2 x i32> %b, <i32 2, i32 2>
+  %2 = icmp ugt <2 x i32> %1, <i32 3, i32 3>
+  %cmp3 = icmp sle <2 x i32> %b, <i32 2, i32 2>
+  %cmp = or <2 x i1> %2, %cmp3
+  ret <2 x i1> %cmp
+}
+
+define i1 @or_of_icmps3(i32 %b) {
+; CHECK-LABEL: @or_of_icmps3(
+; CHECK-NEXT:    ret i1 true
+;
+  %1 = add nsw i32 %b, 2
+  %2 = icmp sgt i32 %1, 3
+  %cmp3 = icmp sle i32 %b, 2
+  %cmp = or i1 %2, %cmp3
+  ret i1 %cmp
+}
+
+define <2 x i1> @or_of_icmps3_vec(<2 x i32> %b) {
+; CHECK-LABEL: @or_of_icmps3_vec(
+; CHECK-NEXT:    ret <2 x i1> <i1 true, i1 true>
+;
+  %1 = add nsw <2 x i32> %b, <i32 2, i32 2>
+  %2 = icmp sgt <2 x i32> %1, <i32 3, i32 3>
+  %cmp3 = icmp sle <2 x i32> %b, <i32 2, i32 2>
+  %cmp = or <2 x i1> %2, %cmp3
+  ret <2 x i1> %cmp
+}
+
+define i1 @or_of_icmps4(i32 %b) {
+; CHECK-LABEL: @or_of_icmps4(
+; CHECK-NEXT:    ret i1 true
+;
+  %1 = add nuw i32 %b, 2
+  %2 = icmp uge i32 %1, 4
+  %cmp3 = icmp ule i32 %b, 2
+  %cmp = or i1 %2, %cmp3
+  ret i1 %cmp
+}
+
+define <2 x i1> @or_of_icmps4_vec(<2 x i32> %b) {
+; CHECK-LABEL: @or_of_icmps4_vec(
+; CHECK-NEXT:    ret <2 x i1> <i1 true, i1 true>
+;
+  %1 = add nuw <2 x i32> %b, <i32 2, i32 2>
+  %2 = icmp uge <2 x i32> %1, <i32 4, i32 4>
+  %cmp3 = icmp ule <2 x i32> %b, <i32 2, i32 2>
+  %cmp = or <2 x i1> %2, %cmp3
+  ret <2 x i1> %cmp
+}
+
+define i1 @or_of_icmps5(i32 %b) {
+; CHECK-LABEL: @or_of_icmps5(
+; CHECK-NEXT:    ret i1 true
+;
+  %1 = add nuw i32 %b, 2
+  %2 = icmp ugt i32 %1, 3
+  %cmp3 = icmp ule i32 %b, 2
+  %cmp = or i1 %2, %cmp3
+  ret i1 %cmp
+}
+
+define <2 x i1> @or_of_icmps5_vec(<2 x i32> %b) {
+; CHECK-LABEL: @or_of_icmps5_vec(
+; CHECK-NEXT:    ret <2 x i1> <i1 true, i1 true>
+;
+  %1 = add nuw <2 x i32> %b, <i32 2, i32 2>
+  %2 = icmp ugt <2 x i32> %1, <i32 3, i32 3>
+  %cmp3 = icmp ule <2 x i32> %b, <i32 2, i32 2>
+  %cmp = or <2 x i1> %2, %cmp3
+  ret <2 x i1> %cmp
+}
+
+define i32 @neg_nuw(i32 %x) {
+; CHECK-LABEL: @neg_nuw(
+; CHECK-NEXT:    ret i32 0
+;
+  %neg = sub nuw i32 0, %x
+  ret i32 %neg
+}
+
+define i1 @and_icmp1(i32 %x, i32 %y) {
+; CHECK-LABEL: @and_icmp1(
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp ult i32 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    ret i1 [[TMP1]]
+;
+  %1 = icmp ult i32 %x, %y
+  %2 = icmp ne i32 %y, 0
+  %3 = and i1 %1, %2
+  ret i1 %3
+}
+
+define i1 @and_icmp2(i32 %x, i32 %y) {
+; CHECK-LABEL: @and_icmp2(
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp ugt i32 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    ret i1 [[TMP1]]
+;
+  %1 = icmp ugt i32 %x, %y
+  %2 = icmp ne i32 %x, 0
+  %3 = and i1 %1, %2
+  ret i1 %3
+}
+
+define i1 @and_icmp3(i32 %x, i32 %y) {
+; CHECK-LABEL: @and_icmp3(
+; CHECK-NEXT:    ret i1 false
+;
+  %1 = icmp ult i32 %x, %y
+  %2 = icmp eq i32 %y, 0
+  %3 = and i1 %1, %2
+  ret i1 %3
+}
+
+define i1 @and_icmp4(i32 %x, i32 %y) {
+; CHECK-LABEL: @and_icmp4(
+; CHECK-NEXT:    ret i1 false
+;
+  %1 = icmp ugt i32 %x, %y
+  %2 = icmp eq i32 %x, 0
+  %3 = and i1 %1, %2
+  ret i1 %3
+}
+
+define i1 @or_icmp1(i32 %x, i32 %y) {
+; CHECK-LABEL: @or_icmp1(
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp ne i32 [[Y:%.*]], 0
+; CHECK-NEXT:    ret i1 [[TMP1]]
+;
+  %1 = icmp ult i32 %x, %y
+  %2 = icmp ne i32 %y, 0
+  %3 = or i1 %1, %2
+  ret i1 %3
+}
+
+define i1 @or_icmp2(i32 %x, i32 %y) {
+; CHECK-LABEL: @or_icmp2(
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp ne i32 [[X:%.*]], 0
+; CHECK-NEXT:    ret i1 [[TMP1]]
+;
+  %1 = icmp ugt i32 %x, %y
+  %2 = icmp ne i32 %x, 0
+  %3 = or i1 %1, %2
+  ret i1 %3
+}
+
+define i1 @or_icmp3(i32 %x, i32 %y) {
+; CHECK-LABEL: @or_icmp3(
+; CHECK-NEXT:    ret i1 true
+;
+  %1 = icmp uge i32 %x, %y
+  %2 = icmp ne i32 %y, 0
+  %3 = or i1 %1, %2
+  ret i1 %3
+}
+
+define i1 @or_icmp4(i32 %x, i32 %y) {
+; CHECK-LABEL: @or_icmp4(
+; CHECK-NEXT:    ret i1 true
+;
+  %1 = icmp ule i32 %x, %y
+  %2 = icmp ne i32 %x, 0
+  %3 = or i1 %1, %2
+  ret i1 %3
+}
+
+define i1 @or_icmp5(i32 %x, i32 %y) {
+; CHECK-LABEL: @or_icmp5(
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp uge i32 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    ret i1 [[TMP1]]
+;
+  %1 = icmp uge i32 %x, %y
+  %2 = icmp eq i32 %y, 0
+  %3 = or i1 %1, %2
+  ret i1 %3
+}
+
+define i1 @or_icmp6(i32 %x, i32 %y) {
+; CHECK-LABEL: @or_icmp6(
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp ule i32 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    ret i1 [[TMP1]]
+;
+  %1 = icmp ule i32 %x, %y
+  %2 = icmp eq i32 %x, 0
+  %3 = or i1 %1, %2
+  ret i1 %3
+}
+
+; PR27869 - Look through casts to eliminate cmps and bitwise logic.
+
+define i32 @and_of_zexted_icmps(i32 %i) {
+; CHECK-LABEL: @and_of_zexted_icmps(
+; CHECK-NEXT:    ret i32 0
+;
+  %cmp0 = icmp eq i32 %i, 0
+  %conv0 = zext i1 %cmp0 to i32
+  %cmp1 = icmp ugt i32 %i, 4
+  %conv1 = zext i1 %cmp1 to i32
+  %and = and i32 %conv0, %conv1
+  ret i32 %and
+}
+
+; Make sure vectors work too.
+
+define <4 x i32> @and_of_zexted_icmps_vec(<4 x i32> %i) {
+; CHECK-LABEL: @and_of_zexted_icmps_vec(
+; CHECK-NEXT:    ret <4 x i32> zeroinitializer
+;
+  %cmp0 = icmp eq <4 x i32> %i, zeroinitializer
+  %conv0 = zext <4 x i1> %cmp0 to <4 x i32>
+  %cmp1 = icmp slt <4 x i32> %i, zeroinitializer
+  %conv1 = zext <4 x i1> %cmp1 to <4 x i32>
+  %and = and <4 x i32> %conv0, %conv1
+  ret <4 x i32> %and
+}
+
+; Try a different cast and weird types.
+
+define i5 @and_of_sexted_icmps(i3 %i) {
+; CHECK-LABEL: @and_of_sexted_icmps(
+; CHECK-NEXT:    ret i5 0
+;
+  %cmp0 = icmp eq i3 %i, 0
+  %conv0 = sext i1 %cmp0 to i5
+  %cmp1 = icmp ugt i3 %i, 1
+  %conv1 = sext i1 %cmp1 to i5
+  %and = and i5 %conv0, %conv1
+  ret i5 %and
+}
+
+; Try a different cast and weird vector types.
+
+define i3 @and_of_bitcast_icmps_vec(<3 x i65> %i) {
+; CHECK-LABEL: @and_of_bitcast_icmps_vec(
+; CHECK-NEXT:    ret i3 0
+;
+  %cmp0 = icmp sgt <3 x i65> %i, zeroinitializer
+  %conv0 = bitcast <3 x i1> %cmp0 to i3
+  %cmp1 = icmp slt <3 x i65> %i, zeroinitializer
+  %conv1 = bitcast <3 x i1> %cmp1 to i3
+  %and = and i3 %conv0, %conv1
+  ret i3 %and
+}
+
+; We can't do this if the casts are different.
+
+define i16 @and_of_different_cast_icmps(i8 %i) {
+; CHECK-LABEL: @and_of_different_cast_icmps(
+; CHECK-NEXT:    [[CMP0:%.*]] = icmp eq i8 [[I:%.*]], 0
+; CHECK-NEXT:    [[CONV0:%.*]] = zext i1 [[CMP0]] to i16
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp eq i8 [[I]], 1
+; CHECK-NEXT:    [[CONV1:%.*]] = sext i1 [[CMP1]] to i16
+; CHECK-NEXT:    [[AND:%.*]] = and i16 [[CONV0]], [[CONV1]]
+; CHECK-NEXT:    ret i16 [[AND]]
+;
+  %cmp0 = icmp eq i8 %i, 0
+  %conv0 = zext i1 %cmp0 to i16
+  %cmp1 = icmp eq i8 %i, 1
+  %conv1 = sext i1 %cmp1 to i16
+  %and = and i16 %conv0, %conv1
+  ret i16 %and
+}
+
+define <2 x i3> @and_of_different_cast_icmps_vec(<2 x i8> %i, <2 x i16> %j) {
+; CHECK-LABEL: @and_of_different_cast_icmps_vec(
+; CHECK-NEXT:    [[CMP0:%.*]] = icmp eq <2 x i8> [[I:%.*]], zeroinitializer
+; CHECK-NEXT:    [[CONV0:%.*]] = zext <2 x i1> [[CMP0]] to <2 x i3>
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp ugt <2 x i16> [[J:%.*]], <i16 1, i16 1>
+; CHECK-NEXT:    [[CONV1:%.*]] = zext <2 x i1> [[CMP1]] to <2 x i3>
+; CHECK-NEXT:    [[AND:%.*]] = and <2 x i3> [[CONV0]], [[CONV1]]
+; CHECK-NEXT:    ret <2 x i3> [[AND]]
+;
+  %cmp0 = icmp eq <2 x i8> %i, zeroinitializer
+  %conv0 = zext <2 x i1> %cmp0 to <2 x i3>
+  %cmp1 = icmp ugt <2 x i16> %j, <i16 1, i16 1>
+  %conv1 = zext <2 x i1> %cmp1 to <2 x i3>
+  %and = and <2 x i3> %conv0, %conv1
+  ret <2 x i3> %and
+}
+
+define i32 @or_of_zexted_icmps(i32 %i) {
+; CHECK-LABEL: @or_of_zexted_icmps(
+; CHECK-NEXT:    ret i32 1
+;
+  %cmp0 = icmp ne i32 %i, 0
+  %conv0 = zext i1 %cmp0 to i32
+  %cmp1 = icmp uge i32 4, %i
+  %conv1 = zext i1 %cmp1 to i32
+  %or = or i32 %conv0, %conv1
+  ret i32 %or
+}
+
+; Try a different cast and weird vector types.
+
+define i3 @or_of_bitcast_icmps_vec(<3 x i65> %i) {
+; CHECK-LABEL: @or_of_bitcast_icmps_vec(
+; CHECK-NEXT:    ret i3 bitcast (<3 x i1> <i1 true, i1 true, i1 true> to i3)
+;
+  %cmp0 = icmp sge <3 x i65> %i, zeroinitializer
+  %conv0 = bitcast <3 x i1> %cmp0 to i3
+  %cmp1 = icmp slt <3 x i65> %i, zeroinitializer
+  %conv1 = bitcast <3 x i1> %cmp1 to i3
+  %or = or i3 %conv0, %conv1
+  ret i3 %or
+}
+
+; We can't simplify if the casts are different.
+
+define i16 @or_of_different_cast_icmps(i8 %i) {
+; CHECK-LABEL: @or_of_different_cast_icmps(
+; CHECK-NEXT:    [[CMP0:%.*]] = icmp ne i8 [[I:%.*]], 0
+; CHECK-NEXT:    [[CONV0:%.*]] = zext i1 [[CMP0]] to i16
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp ne i8 [[I]], 1
+; CHECK-NEXT:    [[CONV1:%.*]] = sext i1 [[CMP1]] to i16
+; CHECK-NEXT:    [[OR:%.*]] = or i16 [[CONV0]], [[CONV1]]
+; CHECK-NEXT:    ret i16 [[OR]]
+;
+  %cmp0 = icmp ne i8 %i, 0
+  %conv0 = zext i1 %cmp0 to i16
+  %cmp1 = icmp ne i8 %i, 1
+  %conv1 = sext i1 %cmp1 to i16
+  %or = or i16 %conv0, %conv1
+  ret i16 %or
+}
+
+; (A & ~B) | (A ^ B) -> A ^ B
+
+define i32 @test43(i32 %a, i32 %b) {
+; CHECK-LABEL: @test43(
+; CHECK-NEXT:    [[XOR:%.*]] = xor i32 [[A:%.*]], [[B:%.*]]
+; CHECK-NEXT:    ret i32 [[XOR]]
+;
+  %neg = xor i32 %b, -1
+  %and = and i32 %a, %neg
+  %xor = xor i32 %a, %b
+  %or = or i32 %and, %xor
+  ret i32 %or
+}
+
+define i32 @test43_commuted_and(i32 %a, i32 %b) {
+; CHECK-LABEL: @test43_commuted_and(
+; CHECK-NEXT:    [[XOR:%.*]] = xor i32 [[A:%.*]], [[B:%.*]]
+; CHECK-NEXT:    ret i32 [[XOR]]
+;
+  %neg = xor i32 %b, -1
+  %and = and i32 %neg, %a
+  %xor = xor i32 %a, %b
+  %or = or i32 %and, %xor
+  ret i32 %or
+}
+
+; Commute operands of the 'or'.
+; (A ^ B) | (A & ~B) -> A ^ B
+
+define i32 @test44(i32 %a, i32 %b) {
+; CHECK-LABEL: @test44(
+; CHECK-NEXT:    [[XOR:%.*]] = xor i32 [[A:%.*]], [[B:%.*]]
+; CHECK-NEXT:    ret i32 [[XOR]]
+;
+  %xor = xor i32 %a, %b
+  %neg = xor i32 %b, -1
+  %and = and i32 %a, %neg
+  %or = or i32 %xor, %and
+  ret i32 %or
+}
+
+define i32 @test44_commuted_and(i32 %a, i32 %b) {
+; CHECK-LABEL: @test44_commuted_and(
+; CHECK-NEXT:    [[XOR:%.*]] = xor i32 [[A:%.*]], [[B:%.*]]
+; CHECK-NEXT:    ret i32 [[XOR]]
+;
+  %xor = xor i32 %a, %b
+  %neg = xor i32 %b, -1
+  %and = and i32 %neg, %a
+  %or = or i32 %xor, %and
+  ret i32 %or
+}
+
+; (~A & ~B) | (~A ^ B) -> ~A ^ B
+
+define i32 @test45(i32 %a, i32 %b) {
+; CHECK-LABEL: @test45(
+; CHECK-NEXT:    [[NEGB:%.*]] = xor i32 [[B:%.*]], -1
+; CHECK-NEXT:    [[XOR:%.*]] = xor i32 [[A:%.*]], [[NEGB]]
+; CHECK-NEXT:    ret i32 [[XOR]]
+;
+  %nega = xor i32 %a, -1
+  %negb = xor i32 %b, -1
+  %and = and i32 %nega, %negb
+  %xor = xor i32 %a, %negb
+  %or = or i32 %and, %xor
+  ret i32 %or
+}
+
+define i32 @test45_commuted_and(i32 %a, i32 %b) {
+; CHECK-LABEL: @test45_commuted_and(
+; CHECK-NEXT:    [[NEGB:%.*]] = xor i32 [[B:%.*]], -1
+; CHECK-NEXT:    [[XOR:%.*]] = xor i32 [[A:%.*]], [[NEGB]]
+; CHECK-NEXT:    ret i32 [[XOR]]
+;
+  %nega = xor i32 %a, -1
+  %negb = xor i32 %b, -1
+  %and = and i32 %negb, %nega
+  %xor = xor i32 %a, %negb
+  %or = or i32 %and, %xor
+  ret i32 %or
+}
+
+; Commute operands of the 'or'.
+; (~A ^ B) | (~A & ~B) -> ~A ^ B
+
+define i32 @test46(i32 %a, i32 %b) {
+; CHECK-LABEL: @test46(
+; CHECK-NEXT:    [[NEGB:%.*]] = xor i32 [[B:%.*]], -1
+; CHECK-NEXT:    [[XOR:%.*]] = xor i32 [[A:%.*]], [[NEGB]]
+; CHECK-NEXT:    ret i32 [[XOR]]
+;
+  %nega = xor i32 %a, -1
+  %negb = xor i32 %b, -1
+  %and = and i32 %nega, %negb
+  %xor = xor i32 %a, %negb
+  %or = or i32 %xor, %and
+  ret i32 %or
+}
+
+; (~A & ~B) | (~A ^ B) -> ~A ^ B
+
+define i32 @test46_commuted_and(i32 %a, i32 %b) {
+; CHECK-LABEL: @test46_commuted_and(
+; CHECK-NEXT:    [[NEGB:%.*]] = xor i32 [[B:%.*]], -1
+; CHECK-NEXT:    [[XOR:%.*]] = xor i32 [[A:%.*]], [[NEGB]]
+; CHECK-NEXT:    ret i32 [[XOR]]
+;
+  %nega = xor i32 %a, -1
+  %negb = xor i32 %b, -1
+  %and = and i32 %negb, %nega
+  %xor = xor i32 %a, %negb
+  %or = or i32 %xor, %and
+  ret i32 %or
+}
+
+; (~A ^ B) | (A & B) -> ~A ^ B
+
+define i32 @test47(i32 %a, i32 %b) {
+; CHECK-LABEL: @test47(
+; CHECK-NEXT:    [[NEGA:%.*]] = xor i32 [[A:%.*]], -1
+; CHECK-NEXT:    [[XOR:%.*]] = xor i32 [[NEGA]], [[B:%.*]]
+; CHECK-NEXT:    ret i32 [[XOR]]
+;
+  %nega = xor i32 %a, -1
+  %and = and i32 %a, %b
+  %xor = xor i32 %nega, %b
+  %or = or i32 %xor, %and
+  ret i32 %or
+}
+
+define i32 @test48(i32 %a, i32 %b) {
+; CHECK-LABEL: @test48(
+; CHECK-NEXT:    [[NEGA:%.*]] = xor i32 [[A:%.*]], -1
+; CHECK-NEXT:    [[XOR:%.*]] = xor i32 [[B:%.*]], [[NEGA]]
+; CHECK-NEXT:    ret i32 [[XOR]]
+;
+  %nega = xor i32 %a, -1
+  %and = and i32 %a, %b
+  %xor = xor i32 %b, %nega
+  %or = or i32 %xor, %and
+  ret i32 %or
+}
+
+define i32 @test49(i32 %a, i32 %b) {
+; CHECK-LABEL: @test49(
+; CHECK-NEXT:    [[NEGA:%.*]] = xor i32 [[A:%.*]], -1
+; CHECK-NEXT:    [[XOR:%.*]] = xor i32 [[B:%.*]], [[NEGA]]
+; CHECK-NEXT:    ret i32 [[XOR]]
+;
+  %nega = xor i32 %a, -1
+  %and = and i32 %b, %a
+  %xor = xor i32 %b, %nega
+  %or = or i32 %xor, %and
+  ret i32 %or
+}
+
+define i32 @test50(i32 %a, i32 %b) {
+; CHECK-LABEL: @test50(
+; CHECK-NEXT:    [[NEGA:%.*]] = xor i32 [[A:%.*]], -1
+; CHECK-NEXT:    [[XOR:%.*]] = xor i32 [[NEGA]], [[B:%.*]]
+; CHECK-NEXT:    ret i32 [[XOR]]
+;
+  %nega = xor i32 %a, -1
+  %and = and i32 %b, %a
+  %xor = xor i32 %nega, %b
+  %or = or i32 %xor, %and
+  ret i32 %or
+}
+
+define i32 @test51(i32 %a, i32 %b) {
+; CHECK-LABEL: @test51(
+; CHECK-NEXT:    [[NEGA:%.*]] = xor i32 [[A:%.*]], -1
+; CHECK-NEXT:    [[XOR:%.*]] = xor i32 [[NEGA]], [[B:%.*]]
+; CHECK-NEXT:    ret i32 [[XOR]]
+;
+  %nega = xor i32 %a, -1
+  %and = and i32 %a, %b
+  %xor = xor i32 %nega, %b
+  %or = or i32 %and, %xor
+  ret i32 %or
+}
+
+define i32 @test52(i32 %a, i32 %b) {
+; CHECK-LABEL: @test52(
+; CHECK-NEXT:    [[NEGA:%.*]] = xor i32 [[A:%.*]], -1
+; CHECK-NEXT:    [[XOR:%.*]] = xor i32 [[B:%.*]], [[NEGA]]
+; CHECK-NEXT:    ret i32 [[XOR]]
+;
+  %nega = xor i32 %a, -1
+  %and = and i32 %a, %b
+  %xor = xor i32 %b, %nega
+  %or = or i32 %and, %xor
+  ret i32 %or
+}
+
+define i32 @test53(i32 %a, i32 %b) {
+; CHECK-LABEL: @test53(
+; CHECK-NEXT:    [[NEGA:%.*]] = xor i32 [[A:%.*]], -1
+; CHECK-NEXT:    [[XOR:%.*]] = xor i32 [[B:%.*]], [[NEGA]]
+; CHECK-NEXT:    ret i32 [[XOR]]
+;
+  %nega = xor i32 %a, -1
+  %and = and i32 %b, %a
+  %xor = xor i32 %b, %nega
+  %or = or i32 %and, %xor
+  ret i32 %or
+}
+
+define i32 @test54(i32 %a, i32 %b) {
+; CHECK-LABEL: @test54(
+; CHECK-NEXT:    [[NEGA:%.*]] = xor i32 [[A:%.*]], -1
+; CHECK-NEXT:    [[XOR:%.*]] = xor i32 [[NEGA]], [[B:%.*]]
+; CHECK-NEXT:    ret i32 [[XOR]]
+;
+  %nega = xor i32 %a, -1
+  %and = and i32 %b, %a
+  %xor = xor i32 %nega, %b
+  %or = or i32 %and, %xor
+  ret i32 %or
+}
+
+; (A & B) | ~(A ^ B) -> ~(A ^ B)
+
+define i32 @test55(i32 %a, i32 %b) {
+; CHECK-LABEL: @test55(
+; CHECK-NEXT:    [[AND:%.*]] = and i32 [[A:%.*]], [[B:%.*]]
+; CHECK-NEXT:    [[XOR:%.*]] = xor i32 [[A]], [[B]]
+; CHECK-NEXT:    [[XNOR:%.*]] = xor i32 [[XOR]], -1
+; CHECK-NEXT:    [[OR:%.*]] = or i32 [[AND]], [[XNOR]]
+; CHECK-NEXT:    ret i32 [[OR]]
+;
+  %and = and i32 %a, %b
+  %xor = xor i32 %a, %b
+  %xnor = xor i32 %xor, -1
+  %or = or i32 %and, %xnor
+  ret i32 %or
+}
+
+; ~(A ^ B) | (A & B) -> ~(A ^ B)
+
+define i32 @test56(i32 %a, i32 %b) {
+; CHECK-LABEL: @test56(
+; CHECK-NEXT:    [[AND:%.*]] = and i32 [[A:%.*]], [[B:%.*]]
+; CHECK-NEXT:    [[XOR:%.*]] = xor i32 [[A]], [[B]]
+; CHECK-NEXT:    [[XNOR:%.*]] = xor i32 [[XOR]], -1
+; CHECK-NEXT:    [[OR:%.*]] = or i32 [[XNOR]], [[AND]]
+; CHECK-NEXT:    ret i32 [[OR]]
+;
+  %and = and i32 %a, %b
+  %xor = xor i32 %a, %b
+  %xnor = xor i32 %xor, -1
+  %or = or i32 %xnor, %and
+  ret i32 %or
+}
+
+; (B & A) | ~(A ^ B) -> ~(A ^ B)
+
+define i32 @test57(i32 %a, i32 %b) {
+; CHECK-LABEL: @test57(
+; CHECK-NEXT:    [[AND:%.*]] = and i32 [[B:%.*]], [[A:%.*]]
+; CHECK-NEXT:    [[XOR:%.*]] = xor i32 [[A]], [[B]]
+; CHECK-NEXT:    [[XNOR:%.*]] = xor i32 [[XOR]], -1
+; CHECK-NEXT:    [[OR:%.*]] = or i32 [[AND]], [[XNOR]]
+; CHECK-NEXT:    ret i32 [[OR]]
+;
+  %and = and i32 %b, %a
+  %xor = xor i32 %a, %b
+  %xnor = xor i32 %xor, -1
+  %or = or i32 %and, %xnor
+  ret i32 %or
+}
+
+; ~(A ^ B) | (A & B) -> ~(A ^ B)
+
+define i32 @test58(i32 %a, i32 %b) {
+; CHECK-LABEL: @test58(
+; CHECK-NEXT:    [[AND:%.*]] = and i32 [[B:%.*]], [[A:%.*]]
+; CHECK-NEXT:    [[XOR:%.*]] = xor i32 [[A]], [[B]]
+; CHECK-NEXT:    [[XNOR:%.*]] = xor i32 [[XOR]], -1
+; CHECK-NEXT:    [[OR:%.*]] = or i32 [[XNOR]], [[AND]]
+; CHECK-NEXT:    ret i32 [[OR]]
+;
+  %and = and i32 %b, %a
+  %xor = xor i32 %a, %b
+  %xnor = xor i32 %xor, -1
+  %or = or i32 %xnor, %and
+  ret i32 %or
+}
+
+define i8 @lshr_perfect_mask(i8 %x) {
+; CHECK-LABEL: @lshr_perfect_mask(
+; CHECK-NEXT:    [[SH:%.*]] = lshr i8 [[X:%.*]], 5
+; CHECK-NEXT:    ret i8 [[SH]]
+;
+  %sh = lshr i8 %x, 5
+  %mask = and i8 %sh, 7  ; 0x07
+  ret i8 %mask
+}
+
+define <2 x i8> @lshr_oversized_mask_splat(<2 x i8> %x) {
+; CHECK-LABEL: @lshr_oversized_mask_splat(
+; CHECK-NEXT:    [[SH:%.*]] = lshr <2 x i8> [[X:%.*]], <i8 5, i8 5>
+; CHECK-NEXT:    ret <2 x i8> [[SH]]
+;
+  %sh = lshr <2 x i8> %x, <i8 5, i8 5>
+  %mask = and <2 x i8> %sh, <i8 135, i8 135>  ; 0x87
+  ret <2 x i8> %mask
+}
+
+define i8 @lshr_undersized_mask(i8 %x) {
+; CHECK-LABEL: @lshr_undersized_mask(
+; CHECK-NEXT:    [[SH:%.*]] = lshr i8 [[X:%.*]], 5
+; CHECK-NEXT:    [[MASK:%.*]] = and i8 [[SH]], -2
+; CHECK-NEXT:    ret i8 [[MASK]]
+;
+  %sh = lshr i8 %x, 5
+  %mask = and i8 %sh, -2  ; 0xFE
+  ret i8 %mask
+}
+
+define <2 x i8> @shl_perfect_mask_splat(<2 x i8> %x) {
+; CHECK-LABEL: @shl_perfect_mask_splat(
+; CHECK-NEXT:    [[SH:%.*]] = shl <2 x i8> [[X:%.*]], <i8 6, i8 6>
+; CHECK-NEXT:    ret <2 x i8> [[SH]]
+;
+  %sh = shl <2 x i8> %x, <i8 6, i8 6>
+  %mask = and <2 x i8> %sh, <i8 192, i8 192>  ; 0xC0
+  ret <2 x i8> %mask
+}
+
+define i8 @shl_oversized_mask(i8 %x) {
+; CHECK-LABEL: @shl_oversized_mask(
+; CHECK-NEXT:    [[SH:%.*]] = shl i8 [[X:%.*]], 6
+; CHECK-NEXT:    ret i8 [[SH]]
+;
+  %sh = shl i8 %x, 6
+  %mask = and i8 %sh, 195  ; 0xC3
+  ret i8 %mask
+}
+
+define <2 x i8> @shl_undersized_mask_splat(<2 x i8> %x) {
+; CHECK-LABEL: @shl_undersized_mask_splat(
+; CHECK-NEXT:    [[SH:%.*]] = shl <2 x i8> [[X:%.*]], <i8 6, i8 6>
+; CHECK-NEXT:    [[MASK:%.*]] = and <2 x i8> [[SH]], <i8 -120, i8 -120>
+; CHECK-NEXT:    ret <2 x i8> [[MASK]]
+;
+  %sh = shl <2 x i8> %x, <i8 6, i8 6>
+  %mask = and <2 x i8> %sh, <i8 136, i8 136>  ; 0x88
+  ret <2 x i8> %mask
+}
+
+define i32 @reversed_not(i32 %a) {
+; CHECK-LABEL: @reversed_not(
+; CHECK-NEXT:    ret i32 -1
+;
+  %nega = xor i32 -1, %a
+  %or = or i32 %a, %nega
+  ret i32 %or
+}
+
+define i64 @shl_or_and1(i32 %a, i1 %b) {
+; CHECK-LABEL: @shl_or_and1(
+; CHECK-NEXT:    [[TMP2:%.*]] = zext i1 [[B:%.*]] to i64
+; CHECK-NEXT:    ret i64 [[TMP2]]
+;
+  %tmp1 = zext i32 %a to i64
+  %tmp2 = zext i1 %b to i64
+  %tmp3 = shl nuw i64 %tmp1, 32
+  %tmp4 = or i64 %tmp2, %tmp3
+  %tmp5 = and i64 %tmp4, 1
+  ret i64 %tmp5
+}
+
+define i64 @shl_or_and2(i32 %a, i1 %b) {
+; CHECK-LABEL: @shl_or_and2(
+; CHECK-NEXT:    [[TMP1:%.*]] = zext i1 [[B:%.*]] to i64
+; CHECK-NEXT:    [[TMP3:%.*]] = shl nuw i64 [[TMP1]], 32
+; CHECK-NEXT:    ret i64 [[TMP3]]
+;
+  %tmp1 = zext i1 %b to i64
+  %tmp2 = zext i32 %a to i64
+  %tmp3 = shl nuw i64 %tmp1, 32
+  %tmp4 = or i64 %tmp2, %tmp3
+  %tmp5 = and i64 %tmp4, 4294967296
+  ret i64 %tmp5
+}
+
+; concatenate two 32-bit integers and extract lower 32-bit
+define i64 @shl_or_and3(i32 %a, i32 %b) {
+; CHECK-LABEL: @shl_or_and3(
+; CHECK-NEXT:    [[TMP2:%.*]] = zext i32 [[B:%.*]] to i64
+; CHECK-NEXT:    ret i64 [[TMP2]]
+;
+  %tmp1 = zext i32 %a to i64
+  %tmp2 = zext i32 %b to i64
+  %tmp3 = shl nuw i64 %tmp1, 32
+  %tmp4 = or i64 %tmp2, %tmp3
+  %tmp5 = and i64 %tmp4, 4294967295
+  ret i64 %tmp5
+}
+
+; concatenate two 16-bit integers and extract higher 16-bit
+define i32 @shl_or_and4(i16 %a, i16 %b) {
+; CHECK-LABEL: @shl_or_and4(
+; CHECK-NEXT:    [[TMP1:%.*]] = zext i16 [[A:%.*]] to i32
+; CHECK-NEXT:    [[TMP3:%.*]] = shl nuw i32 [[TMP1]], 16
+; CHECK-NEXT:    ret i32 [[TMP3]]
+;
+  %tmp1 = zext i16 %a to i32
+  %tmp2 = zext i16 %b to i32
+  %tmp3 = shl nuw i32 %tmp1, 16
+  %tmp4 = or i32 %tmp2, %tmp3
+  %tmp5 = and i32 %tmp4, 4294901760 ; mask with 0xFFFF0000
+  ret i32 %tmp5
+}
+
+define i128 @shl_or_and5(i64 %a, i1 %b) {
+; CHECK-LABEL: @shl_or_and5(
+; CHECK-NEXT:    [[TMP2:%.*]] = zext i1 [[B:%.*]] to i128
+; CHECK-NEXT:    ret i128 [[TMP2]]
+;
+  %tmp1 = zext i64 %a to i128
+  %tmp2 = zext i1 %b to i128
+  %tmp3 = shl nuw i128 %tmp1, 64
+  %tmp4 = or i128 %tmp2, %tmp3
+  %tmp5 = and i128 %tmp4, 1
+  ret i128 %tmp5
+}
+
+; A variation of above test cases; it fails due to the mask value
+define i32 @shl_or_and6(i16 %a, i16 %b) {
+; CHECK-LABEL: @shl_or_and6(
+; CHECK-NEXT:    [[TMP1:%.*]] = zext i16 [[A:%.*]] to i32
+; CHECK-NEXT:    [[TMP2:%.*]] = zext i16 [[B:%.*]] to i32
+; CHECK-NEXT:    [[TMP3:%.*]] = shl nuw i32 [[TMP1]], 16
+; CHECK-NEXT:    [[TMP4:%.*]] = or i32 [[TMP2]], [[TMP3]]
+; CHECK-NEXT:    [[TMP5:%.*]] = and i32 [[TMP4]], -65535
+; CHECK-NEXT:    ret i32 [[TMP5]]
+;
+  %tmp1 = zext i16 %a to i32
+  %tmp2 = zext i16 %b to i32
+  %tmp3 = shl nuw i32 %tmp1, 16
+  %tmp4 = or i32 %tmp2, %tmp3
+  %tmp5 = and i32 %tmp4, 4294901761 ; mask with 0xFFFF0001
+  ret i32 %tmp5
+}
+
+; A variation of above test cases; it fails due to the mask value
+define i32 @shl_or_and7(i16 %a, i16 %b) {
+; CHECK-LABEL: @shl_or_and7(
+; CHECK-NEXT:    [[TMP1:%.*]] = zext i16 [[A:%.*]] to i32
+; CHECK-NEXT:    [[TMP2:%.*]] = zext i16 [[B:%.*]] to i32
+; CHECK-NEXT:    [[TMP3:%.*]] = shl nuw i32 [[TMP1]], 16
+; CHECK-NEXT:    [[TMP4:%.*]] = or i32 [[TMP2]], [[TMP3]]
+; CHECK-NEXT:    [[TMP5:%.*]] = and i32 [[TMP4]], -131072
+; CHECK-NEXT:    ret i32 [[TMP5]]
+;
+  %tmp1 = zext i16 %a to i32
+  %tmp2 = zext i16 %b to i32
+  %tmp3 = shl nuw i32 %tmp1, 16
+  %tmp4 = or i32 %tmp2, %tmp3
+  %tmp5 = and i32 %tmp4, 4294836224 ; mask with 0xFFFE0000
+  ret i32 %tmp5
+}
+
+; A variation of above test cases; it fails due to the mask value
+define i32 @shl_or_and8(i16 %a, i16 %b) {
+; CHECK-LABEL: @shl_or_and8(
+; CHECK-NEXT:    [[TMP1:%.*]] = zext i16 [[A:%.*]] to i32
+; CHECK-NEXT:    [[TMP2:%.*]] = zext i16 [[B:%.*]] to i32
+; CHECK-NEXT:    [[TMP3:%.*]] = shl nuw i32 [[TMP1]], 16
+; CHECK-NEXT:    [[TMP4:%.*]] = or i32 [[TMP2]], [[TMP3]]
+; CHECK-NEXT:    [[TMP5:%.*]] = and i32 [[TMP4]], 131071
+; CHECK-NEXT:    ret i32 [[TMP5]]
+;
+  %tmp1 = zext i16 %a to i32
+  %tmp2 = zext i16 %b to i32
+  %tmp3 = shl nuw i32 %tmp1, 16
+  %tmp4 = or i32 %tmp2, %tmp3
+  %tmp5 = and i32 %tmp4, 131071 ; mask with 0x1FFFF
+  ret i32 %tmp5
+}
+
+define <2 x i64> @shl_or_and1v(<2 x i32> %a, <2 x i1> %b) {
+; CHECK-LABEL: @shl_or_and1v(
+; CHECK-NEXT:    [[TMP2:%.*]] = zext <2 x i1> [[B:%.*]] to <2 x i64>
+; CHECK-NEXT:    ret <2 x i64> [[TMP2]]
+;
+  %tmp1 = zext <2 x i32> %a to <2 x i64>
+  %tmp2 = zext <2 x i1> %b to <2 x i64>
+  %tmp3 = shl nuw <2 x i64> %tmp1, <i64 32, i64 32>
+  %tmp4 = or <2 x i64> %tmp3, %tmp2
+  %tmp5 = and <2 x i64> %tmp4, <i64 1, i64 1>
+  ret <2 x i64> %tmp5
+}
+
+define <2 x i64> @shl_or_and2v(<2 x i32> %a, <2 x i1> %b) {
+; CHECK-LABEL: @shl_or_and2v(
+; CHECK-NEXT:    [[TMP1:%.*]] = zext <2 x i1> [[B:%.*]] to <2 x i64>
+; CHECK-NEXT:    [[TMP3:%.*]] = shl nuw <2 x i64> [[TMP1]], <i64 32, i64 32>
+; CHECK-NEXT:    ret <2 x i64> [[TMP3]]
+;
+  %tmp1 = zext <2 x i1> %b to <2 x i64>
+  %tmp2 = zext <2 x i32> %a to <2 x i64>
+  %tmp3 = shl nuw <2 x i64> %tmp1, <i64 32, i64 32>
+  %tmp4 = or <2 x i64> %tmp2, %tmp3
+  %tmp5 = and <2 x i64> %tmp4, <i64 4294967296, i64 4294967296>
+  ret <2 x i64> %tmp5
+}
+
+define <2 x i32> @shl_or_and3v(<2 x i16> %a, <2 x i16> %b) {
+; A variation of above test case, but fails due to the mask value
+; CHECK-LABEL: @shl_or_and3v(
+; CHECK-NEXT:    [[TMP1:%.*]] = zext <2 x i16> [[A:%.*]] to <2 x i32>
+; CHECK-NEXT:    [[TMP2:%.*]] = zext <2 x i16> [[B:%.*]] to <2 x i32>
+; CHECK-NEXT:    [[TMP3:%.*]] = shl nuw <2 x i32> [[TMP1]], <i32 16, i32 16>
+; CHECK-NEXT:    [[TMP4:%.*]] = or <2 x i32> [[TMP2]], [[TMP3]]
+; CHECK-NEXT:    [[TMP5:%.*]] = and <2 x i32> [[TMP4]], <i32 -65535, i32 -65535>
+; CHECK-NEXT:    ret <2 x i32> [[TMP5]]
+;
+  %tmp1 = zext <2 x i16> %a to <2 x i32>
+  %tmp2 = zext <2 x i16> %b to <2 x i32>
+  %tmp3 = shl nuw <2 x i32> %tmp1, <i32 16, i32 16>
+  %tmp4 = or <2 x i32> %tmp2, %tmp3
+  %tmp5 = and <2 x i32> %tmp4, <i32 4294901761, i32 4294901761> ; mask with 0xFFFF0001
+  ret <2 x i32> %tmp5
+}

Added: llvm/trunk/test/Transforms/InstSimplify/add-mask.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstSimplify/add-mask.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstSimplify/add-mask.ll (added)
+++ llvm/trunk/test/Transforms/InstSimplify/add-mask.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,79 @@
+; NOTE: Assertions have been autogenerated by update_test_checks.py
+; RUN: opt -S -instsimplify < %s | FileCheck %s
+
+define i1 @test(i32 %a) {
+; CHECK-LABEL: @test(
+; CHECK:         ret i1 false
+;
+  %rhs = add i32 %a, -1
+  %and = and i32 %a, %rhs
+  %res = icmp eq i32 %and, 1
+  ret i1 %res
+}
+
+define i1 @test2(i32 %a) {
+; CHECK-LABEL: @test2(
+; CHECK:         ret i1 false
+;
+  %rhs = add i32 %a, 1
+  %and = and i32 %a, %rhs
+  %res = icmp eq i32 %and, 1
+  ret i1 %res
+}
+
+define i1 @test3(i32 %a) {
+; CHECK-LABEL: @test3(
+; CHECK:         ret i1 false
+;
+  %rhs = add i32 %a, 7
+  %and = and i32 %a, %rhs
+  %res = icmp eq i32 %and, 1
+  ret i1 %res
+}
+
+ at B = external global i32
+declare void @llvm.assume(i1)
+
+; Known bits without a constant
+define i1 @test4(i32 %a) {
+; CHECK-LABEL: @test4(
+; CHECK:         [[B:%.*]] = load i32, i32* @B
+; CHECK-NEXT:    [[B_AND:%.*]] = and i32 [[B]], 1
+; CHECK-NEXT:    [[B_CND:%.*]] = icmp eq i32 [[B_AND]], 1
+; CHECK-NEXT:    call void @llvm.assume(i1 [[B_CND]])
+; CHECK-NEXT:    ret i1 false
+;
+  %b = load i32, i32* @B
+  %b.and = and i32 %b, 1
+  %b.cnd = icmp eq i32 %b.and, 1
+  call void @llvm.assume(i1 %b.cnd)
+
+  %rhs = add i32 %a, %b
+  %and = and i32 %a, %rhs
+  %res = icmp eq i32 %and, 1
+  ret i1 %res
+}
+
+; Negative test - even number
+define i1 @test5(i32 %a) {
+; CHECK-LABEL: @test5(
+; CHECK:         [[RHS:%.*]] = add i32 %a, 2
+; CHECK-NEXT:    [[AND:%.*]] = and i32 %a, [[RHS]]
+; CHECK-NEXT:    [[RES:%.*]] = icmp eq i32 [[AND]], 1
+; CHECK-NEXT:    ret i1 [[RES]]
+;
+  %rhs = add i32 %a, 2
+  %and = and i32 %a, %rhs
+  %res = icmp eq i32 %and, 1
+  ret i1 %res
+}
+
+define i1 @test6(i32 %a) {
+; CHECK-LABEL: @test6(
+; CHECK:         ret i1 false
+;
+  %lhs = add i32 %a, -1
+  %and = and i32 %lhs, %a
+  %res = icmp eq i32 %and, 1
+  ret i1 %res
+}

Added: llvm/trunk/test/Transforms/InstSimplify/add.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstSimplify/add.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstSimplify/add.ll (added)
+++ llvm/trunk/test/Transforms/InstSimplify/add.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,51 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt < %s -instsimplify -S | FileCheck %s
+
+define i32 @common_sub_operand(i32 %X, i32 %Y) {
+; CHECK-LABEL: @common_sub_operand(
+; CHECK-NEXT:    ret i32 [[X:%.*]]
+;
+  %Z = sub i32 %X, %Y
+  %Q = add i32 %Z, %Y
+  ret i32 %Q
+}
+
+define i32 @negated_operand(i32 %x) {
+; CHECK-LABEL: @negated_operand(
+; CHECK-NEXT:    ret i32 0
+;
+  %negx = sub i32 0, %x
+  %r = add i32 %negx, %x
+  ret i32 %r
+}
+
+define <2 x i32> @negated_operand_commute_vec(<2 x i32> %x) {
+; CHECK-LABEL: @negated_operand_commute_vec(
+; CHECK-NEXT:    ret <2 x i32> zeroinitializer
+;
+  %negx = sub <2 x i32> zeroinitializer, %x
+  %r = add <2 x i32> %x, %negx
+  ret <2 x i32> %r
+}
+
+define i8 @knownnegation(i8 %x, i8 %y) {
+; CHECK-LABEL: @knownnegation(
+; CHECK-NEXT:    ret i8 0 
+;
+  %xy = sub i8 %x, %y
+  %yx = sub i8 %y, %x
+  %r = add i8 %xy, %yx
+  ret i8 %r
+}
+
+define <2 x i8> @knownnegation_commute_vec(<2 x i8> %x, <2 x i8> %y) {
+; CHECK-LABEL: @knownnegation_commute_vec(
+; CHECK-NEXT:    ret <2 x i8> zeroinitializer
+;
+  %xy = sub <2 x i8> %x, %y
+  %yx = sub <2 x i8> %y, %x
+  %r = add <2 x i8> %yx, %xy
+  ret <2 x i8> %r
+}
+
+

Added: llvm/trunk/test/Transforms/InstSimplify/addsub.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstSimplify/addsub.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstSimplify/addsub.ll (added)
+++ llvm/trunk/test/Transforms/InstSimplify/addsub.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,78 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt < %s -instsimplify -S | FileCheck %s
+
+define i1 @test1(i1 %a) {
+; CHECK-LABEL: @test1(
+; CHECK-NEXT:    ret i1 true
+;
+  %b = xor i1 %a, true
+  %res = sub i1 %a, %b
+  ret i1 %res
+}
+
+define <2 x i1> @test2(<2 x i1> %a) {
+; CHECK-LABEL: @test2(
+; CHECK-NEXT:    ret <2 x i1> <i1 true, i1 true>
+;
+  %b = xor <2 x i1> %a, <i1 true, i1 true>
+  %res = sub <2 x i1> %a, %b
+  ret <2 x i1> %res
+}
+
+define i1 @test5(i1 %a) {
+; CHECK-LABEL: @test5(
+; CHECK-NEXT:    ret i1 false
+;
+  %res = add i1 %a, %a
+  ret i1 %res
+}
+
+define <2 x i1> @test6(<2 x i1> %a) {
+; CHECK-LABEL: @test6(
+; CHECK-NEXT:    ret <2 x i1> zeroinitializer
+;
+  %res = add <2 x i1> %a, %a
+  ret <2 x i1> %res
+}
+
+define i1 @test7(i1 %a) {
+; CHECK-LABEL: @test7(
+; CHECK-NEXT:    ret i1 [[A:%.*]]
+;
+  %c = xor i1 %a, true
+  %res = add i1 %c, true
+  ret i1 %res
+}
+
+; TODO: simplify this to %a
+define i1 @test8(i1 %a) {
+; CHECK-LABEL: @test8(
+; CHECK-NEXT:    [[C:%.*]] = add i1 [[A:%.*]], true
+; CHECK-NEXT:    [[RES:%.*]] = xor i1 [[C]], true
+; CHECK-NEXT:    ret i1 [[RES]]
+;
+  %c = add i1 %a, true
+  %res = xor i1 %c, true
+  ret i1 %res
+}
+
+define i1 @test9(i1 %a) {
+; CHECK-LABEL: @test9(
+; CHECK-NEXT:    ret i1 [[A:%.*]]
+;
+  %c = xor i1 %a, true
+  %res = sub i1 %c, true
+  ret i1 %res
+}
+
+; TODO: simplify this to %a
+define i1 @test10(i1 %a) {
+; CHECK-LABEL: @test10(
+; CHECK-NEXT:    [[C:%.*]] = sub i1 [[A:%.*]], true
+; CHECK-NEXT:    [[RES:%.*]] = xor i1 [[C]], true
+; CHECK-NEXT:    ret i1 [[RES]]
+;
+  %c = sub i1 %a, true
+  %res = xor i1 %c, true
+  ret i1 %res
+}

Added: llvm/trunk/test/Transforms/InstSimplify/and-icmps-same-ops.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstSimplify/and-icmps-same-ops.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstSimplify/and-icmps-same-ops.ll (added)
+++ llvm/trunk/test/Transforms/InstSimplify/and-icmps-same-ops.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,1239 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt < %s -instsimplify -S | FileCheck %s
+
+; There are 10 * 10 combinations of icmp predicates that can be AND'd together.
+; The majority of these can be simplified to always false or just one of the icmps.
+
+define i1 @eq_eq(i8 %a, i8 %b) {
+; CHECK-LABEL: @eq_eq(
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp eq i8 %a, %b
+; CHECK-NEXT:    ret i1 [[CMP1]]
+;
+  %cmp1 = icmp eq i8 %a, %b
+  %cmp2 = icmp eq i8 %a, %b
+  %and = and i1 %cmp1, %cmp2
+  ret i1 %and
+}
+
+define i1 @eq_ne(i8 %a, i8 %b) {
+; CHECK-LABEL: @eq_ne(
+; CHECK-NEXT:    ret i1 false
+;
+  %cmp1 = icmp eq i8 %a, %b
+  %cmp2 = icmp ne i8 %a, %b
+  %and = and i1 %cmp1, %cmp2
+  ret i1 %and
+}
+
+define i1 @eq_sge(i8 %a, i8 %b) {
+; CHECK-LABEL: @eq_sge(
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp eq i8 %a, %b
+; CHECK-NEXT:    ret i1 [[CMP1]]
+;
+  %cmp1 = icmp eq i8 %a, %b
+  %cmp2 = icmp sge i8 %a, %b
+  %and = and i1 %cmp1, %cmp2
+  ret i1 %and
+}
+
+define i1 @eq_sgt(i8 %a, i8 %b) {
+; CHECK-LABEL: @eq_sgt(
+; CHECK-NEXT:    ret i1 false
+;
+  %cmp1 = icmp eq i8 %a, %b
+  %cmp2 = icmp sgt i8 %a, %b
+  %and = and i1 %cmp1, %cmp2
+  ret i1 %and
+}
+
+define i1 @eq_sle(i8 %a, i8 %b) {
+; CHECK-LABEL: @eq_sle(
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp eq i8 %a, %b
+; CHECK-NEXT:    ret i1 [[CMP1]]
+;
+  %cmp1 = icmp eq i8 %a, %b
+  %cmp2 = icmp sle i8 %a, %b
+  %and = and i1 %cmp1, %cmp2
+  ret i1 %and
+}
+
+define i1 @eq_slt(i8 %a, i8 %b) {
+; CHECK-LABEL: @eq_slt(
+; CHECK-NEXT:    ret i1 false
+;
+  %cmp1 = icmp eq i8 %a, %b
+  %cmp2 = icmp slt i8 %a, %b
+  %and = and i1 %cmp1, %cmp2
+  ret i1 %and
+}
+
+define i1 @eq_uge(i8 %a, i8 %b) {
+; CHECK-LABEL: @eq_uge(
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp eq i8 %a, %b
+; CHECK-NEXT:    ret i1 [[CMP1]]
+;
+  %cmp1 = icmp eq i8 %a, %b
+  %cmp2 = icmp uge i8 %a, %b
+  %and = and i1 %cmp1, %cmp2
+  ret i1 %and
+}
+
+define i1 @eq_ugt(i8 %a, i8 %b) {
+; CHECK-LABEL: @eq_ugt(
+; CHECK-NEXT:    ret i1 false
+;
+  %cmp1 = icmp eq i8 %a, %b
+  %cmp2 = icmp ugt i8 %a, %b
+  %and = and i1 %cmp1, %cmp2
+  ret i1 %and
+}
+
+define i1 @eq_ule(i8 %a, i8 %b) {
+; CHECK-LABEL: @eq_ule(
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp eq i8 %a, %b
+; CHECK-NEXT:    ret i1 [[CMP1]]
+;
+  %cmp1 = icmp eq i8 %a, %b
+  %cmp2 = icmp ule i8 %a, %b
+  %and = and i1 %cmp1, %cmp2
+  ret i1 %and
+}
+
+define i1 @eq_ult(i8 %a, i8 %b) {
+; CHECK-LABEL: @eq_ult(
+; CHECK-NEXT:    ret i1 false
+;
+  %cmp1 = icmp eq i8 %a, %b
+  %cmp2 = icmp ult i8 %a, %b
+  %and = and i1 %cmp1, %cmp2
+  ret i1 %and
+}
+
+;
+
+define i1 @ne_eq(i8 %a, i8 %b) {
+; CHECK-LABEL: @ne_eq(
+; CHECK-NEXT:    ret i1 false
+;
+  %cmp1 = icmp ne i8 %a, %b
+  %cmp2 = icmp eq i8 %a, %b
+  %and = and i1 %cmp1, %cmp2
+  ret i1 %and
+}
+
+define i1 @ne_ne(i8 %a, i8 %b) {
+; CHECK-LABEL: @ne_ne(
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp ne i8 %a, %b
+; CHECK-NEXT:    ret i1 [[CMP1]]
+;
+  %cmp1 = icmp ne i8 %a, %b
+  %cmp2 = icmp ne i8 %a, %b
+  %and = and i1 %cmp1, %cmp2
+  ret i1 %and
+}
+
+define i1 @ne_sge(i8 %a, i8 %b) {
+; CHECK-LABEL: @ne_sge(
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp ne i8 %a, %b
+; CHECK-NEXT:    [[CMP2:%.*]] = icmp sge i8 %a, %b
+; CHECK-NEXT:    [[AND:%.*]] = and i1 [[CMP1]], [[CMP2]]
+; CHECK-NEXT:    ret i1 [[AND]]
+;
+  %cmp1 = icmp ne i8 %a, %b
+  %cmp2 = icmp sge i8 %a, %b
+  %and = and i1 %cmp1, %cmp2
+  ret i1 %and
+}
+
+define i1 @ne_sgt(i8 %a, i8 %b) {
+; CHECK-LABEL: @ne_sgt(
+; CHECK-NEXT:    [[CMP2:%.*]] = icmp sgt i8 %a, %b
+; CHECK-NEXT:    ret i1 [[CMP2]]
+;
+  %cmp1 = icmp ne i8 %a, %b
+  %cmp2 = icmp sgt i8 %a, %b
+  %and = and i1 %cmp1, %cmp2
+  ret i1 %and
+}
+
+define i1 @ne_sle(i8 %a, i8 %b) {
+; CHECK-LABEL: @ne_sle(
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp ne i8 %a, %b
+; CHECK-NEXT:    [[CMP2:%.*]] = icmp sle i8 %a, %b
+; CHECK-NEXT:    [[AND:%.*]] = and i1 [[CMP1]], [[CMP2]]
+; CHECK-NEXT:    ret i1 [[AND]]
+;
+  %cmp1 = icmp ne i8 %a, %b
+  %cmp2 = icmp sle i8 %a, %b
+  %and = and i1 %cmp1, %cmp2
+  ret i1 %and
+}
+
+define i1 @ne_slt(i8 %a, i8 %b) {
+; CHECK-LABEL: @ne_slt(
+; CHECK-NEXT:    [[CMP2:%.*]] = icmp slt i8 %a, %b
+; CHECK-NEXT:    ret i1 [[CMP2]]
+;
+  %cmp1 = icmp ne i8 %a, %b
+  %cmp2 = icmp slt i8 %a, %b
+  %and = and i1 %cmp1, %cmp2
+  ret i1 %and
+}
+
+define i1 @ne_uge(i8 %a, i8 %b) {
+; CHECK-LABEL: @ne_uge(
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp ne i8 %a, %b
+; CHECK-NEXT:    [[CMP2:%.*]] = icmp uge i8 %a, %b
+; CHECK-NEXT:    [[AND:%.*]] = and i1 [[CMP1]], [[CMP2]]
+; CHECK-NEXT:    ret i1 [[AND]]
+;
+  %cmp1 = icmp ne i8 %a, %b
+  %cmp2 = icmp uge i8 %a, %b
+  %and = and i1 %cmp1, %cmp2
+  ret i1 %and
+}
+
+define i1 @ne_ugt(i8 %a, i8 %b) {
+; CHECK-LABEL: @ne_ugt(
+; CHECK-NEXT:    [[CMP2:%.*]] = icmp ugt i8 %a, %b
+; CHECK-NEXT:    ret i1 [[CMP2]]
+;
+  %cmp1 = icmp ne i8 %a, %b
+  %cmp2 = icmp ugt i8 %a, %b
+  %and = and i1 %cmp1, %cmp2
+  ret i1 %and
+}
+
+define i1 @ne_ule(i8 %a, i8 %b) {
+; CHECK-LABEL: @ne_ule(
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp ne i8 %a, %b
+; CHECK-NEXT:    [[CMP2:%.*]] = icmp ule i8 %a, %b
+; CHECK-NEXT:    [[AND:%.*]] = and i1 [[CMP1]], [[CMP2]]
+; CHECK-NEXT:    ret i1 [[AND]]
+;
+  %cmp1 = icmp ne i8 %a, %b
+  %cmp2 = icmp ule i8 %a, %b
+  %and = and i1 %cmp1, %cmp2
+  ret i1 %and
+}
+
+define i1 @ne_ult(i8 %a, i8 %b) {
+; CHECK-LABEL: @ne_ult(
+; CHECK-NEXT:    [[CMP2:%.*]] = icmp ult i8 %a, %b
+; CHECK-NEXT:    ret i1 [[CMP2]]
+;
+  %cmp1 = icmp ne i8 %a, %b
+  %cmp2 = icmp ult i8 %a, %b
+  %and = and i1 %cmp1, %cmp2
+  ret i1 %and
+}
+
+;
+
+define i1 @sge_eq(i8 %a, i8 %b) {
+; CHECK-LABEL: @sge_eq(
+; CHECK-NEXT:    [[CMP2:%.*]] = icmp eq i8 %a, %b
+; CHECK-NEXT:    ret i1 [[CMP2]]
+;
+  %cmp1 = icmp sge i8 %a, %b
+  %cmp2 = icmp eq i8 %a, %b
+  %and = and i1 %cmp1, %cmp2
+  ret i1 %and
+}
+
+define i1 @sge_ne(i8 %a, i8 %b) {
+; CHECK-LABEL: @sge_ne(
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp sge i8 %a, %b
+; CHECK-NEXT:    [[CMP2:%.*]] = icmp ne i8 %a, %b
+; CHECK-NEXT:    [[AND:%.*]] = and i1 [[CMP1]], [[CMP2]]
+; CHECK-NEXT:    ret i1 [[AND]]
+;
+  %cmp1 = icmp sge i8 %a, %b
+  %cmp2 = icmp ne i8 %a, %b
+  %and = and i1 %cmp1, %cmp2
+  ret i1 %and
+}
+
+define i1 @sge_sge(i8 %a, i8 %b) {
+; CHECK-LABEL: @sge_sge(
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp sge i8 %a, %b
+; CHECK-NEXT:    ret i1 [[CMP1]]
+;
+  %cmp1 = icmp sge i8 %a, %b
+  %cmp2 = icmp sge i8 %a, %b
+  %and = and i1 %cmp1, %cmp2
+  ret i1 %and
+}
+
+define i1 @sge_sgt(i8 %a, i8 %b) {
+; CHECK-LABEL: @sge_sgt(
+; CHECK-NEXT:    [[CMP2:%.*]] = icmp sgt i8 %a, %b
+; CHECK-NEXT:    ret i1 [[CMP2]]
+;
+  %cmp1 = icmp sge i8 %a, %b
+  %cmp2 = icmp sgt i8 %a, %b
+  %and = and i1 %cmp1, %cmp2
+  ret i1 %and
+}
+
+define i1 @sge_sle(i8 %a, i8 %b) {
+; CHECK-LABEL: @sge_sle(
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp sge i8 %a, %b
+; CHECK-NEXT:    [[CMP2:%.*]] = icmp sle i8 %a, %b
+; CHECK-NEXT:    [[AND:%.*]] = and i1 [[CMP1]], [[CMP2]]
+; CHECK-NEXT:    ret i1 [[AND]]
+;
+  %cmp1 = icmp sge i8 %a, %b
+  %cmp2 = icmp sle i8 %a, %b
+  %and = and i1 %cmp1, %cmp2
+  ret i1 %and
+}
+
+define i1 @sge_slt(i8 %a, i8 %b) {
+; CHECK-LABEL: @sge_slt(
+; CHECK-NEXT:    ret i1 false
+;
+  %cmp1 = icmp sge i8 %a, %b
+  %cmp2 = icmp slt i8 %a, %b
+  %and = and i1 %cmp1, %cmp2
+  ret i1 %and
+}
+
+define i1 @sge_uge(i8 %a, i8 %b) {
+; CHECK-LABEL: @sge_uge(
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp sge i8 %a, %b
+; CHECK-NEXT:    [[CMP2:%.*]] = icmp uge i8 %a, %b
+; CHECK-NEXT:    [[AND:%.*]] = and i1 [[CMP1]], [[CMP2]]
+; CHECK-NEXT:    ret i1 [[AND]]
+;
+  %cmp1 = icmp sge i8 %a, %b
+  %cmp2 = icmp uge i8 %a, %b
+  %and = and i1 %cmp1, %cmp2
+  ret i1 %and
+}
+
+define i1 @sge_ugt(i8 %a, i8 %b) {
+; CHECK-LABEL: @sge_ugt(
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp sge i8 %a, %b
+; CHECK-NEXT:    [[CMP2:%.*]] = icmp ugt i8 %a, %b
+; CHECK-NEXT:    [[AND:%.*]] = and i1 [[CMP1]], [[CMP2]]
+; CHECK-NEXT:    ret i1 [[AND]]
+;
+  %cmp1 = icmp sge i8 %a, %b
+  %cmp2 = icmp ugt i8 %a, %b
+  %and = and i1 %cmp1, %cmp2
+  ret i1 %and
+}
+
+define i1 @sge_ule(i8 %a, i8 %b) {
+; CHECK-LABEL: @sge_ule(
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp sge i8 %a, %b
+; CHECK-NEXT:    [[CMP2:%.*]] = icmp ule i8 %a, %b
+; CHECK-NEXT:    [[AND:%.*]] = and i1 [[CMP1]], [[CMP2]]
+; CHECK-NEXT:    ret i1 [[AND]]
+;
+  %cmp1 = icmp sge i8 %a, %b
+  %cmp2 = icmp ule i8 %a, %b
+  %and = and i1 %cmp1, %cmp2
+  ret i1 %and
+}
+
+define i1 @sge_ult(i8 %a, i8 %b) {
+; CHECK-LABEL: @sge_ult(
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp sge i8 %a, %b
+; CHECK-NEXT:    [[CMP2:%.*]] = icmp ult i8 %a, %b
+; CHECK-NEXT:    [[AND:%.*]] = and i1 [[CMP1]], [[CMP2]]
+; CHECK-NEXT:    ret i1 [[AND]]
+;
+  %cmp1 = icmp sge i8 %a, %b
+  %cmp2 = icmp ult i8 %a, %b
+  %and = and i1 %cmp1, %cmp2
+  ret i1 %and
+}
+
+;
+
+define i1 @sgt_eq(i8 %a, i8 %b) {
+; CHECK-LABEL: @sgt_eq(
+; CHECK-NEXT:    ret i1 false
+;
+  %cmp1 = icmp sgt i8 %a, %b
+  %cmp2 = icmp eq i8 %a, %b
+  %and = and i1 %cmp1, %cmp2
+  ret i1 %and
+}
+
+define i1 @sgt_ne(i8 %a, i8 %b) {
+; CHECK-LABEL: @sgt_ne(
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp sgt i8 %a, %b
+; CHECK-NEXT:    ret i1 [[CMP1]]
+;
+  %cmp1 = icmp sgt i8 %a, %b
+  %cmp2 = icmp ne i8 %a, %b
+  %and = and i1 %cmp1, %cmp2
+  ret i1 %and
+}
+
+define i1 @sgt_sge(i8 %a, i8 %b) {
+; CHECK-LABEL: @sgt_sge(
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp sgt i8 %a, %b
+; CHECK-NEXT:    ret i1 [[CMP1]]
+;
+  %cmp1 = icmp sgt i8 %a, %b
+  %cmp2 = icmp sge i8 %a, %b
+  %and = and i1 %cmp1, %cmp2
+  ret i1 %and
+}
+
+define i1 @sgt_sgt(i8 %a, i8 %b) {
+; CHECK-LABEL: @sgt_sgt(
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp sgt i8 %a, %b
+; CHECK-NEXT:    ret i1 [[CMP1]]
+;
+  %cmp1 = icmp sgt i8 %a, %b
+  %cmp2 = icmp sgt i8 %a, %b
+  %and = and i1 %cmp1, %cmp2
+  ret i1 %and
+}
+
+define i1 @sgt_sle(i8 %a, i8 %b) {
+; CHECK-LABEL: @sgt_sle(
+; CHECK-NEXT:    ret i1 false
+;
+  %cmp1 = icmp sgt i8 %a, %b
+  %cmp2 = icmp sle i8 %a, %b
+  %and = and i1 %cmp1, %cmp2
+  ret i1 %and
+}
+
+define i1 @sgt_slt(i8 %a, i8 %b) {
+; CHECK-LABEL: @sgt_slt(
+; CHECK-NEXT:    ret i1 false
+;
+  %cmp1 = icmp sgt i8 %a, %b
+  %cmp2 = icmp slt i8 %a, %b
+  %and = and i1 %cmp1, %cmp2
+  ret i1 %and
+}
+
+define i1 @sgt_uge(i8 %a, i8 %b) {
+; CHECK-LABEL: @sgt_uge(
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp sgt i8 %a, %b
+; CHECK-NEXT:    [[CMP2:%.*]] = icmp uge i8 %a, %b
+; CHECK-NEXT:    [[AND:%.*]] = and i1 [[CMP1]], [[CMP2]]
+; CHECK-NEXT:    ret i1 [[AND]]
+;
+  %cmp1 = icmp sgt i8 %a, %b
+  %cmp2 = icmp uge i8 %a, %b
+  %and = and i1 %cmp1, %cmp2
+  ret i1 %and
+}
+
+define i1 @sgt_ugt(i8 %a, i8 %b) {
+; CHECK-LABEL: @sgt_ugt(
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp sgt i8 %a, %b
+; CHECK-NEXT:    [[CMP2:%.*]] = icmp ugt i8 %a, %b
+; CHECK-NEXT:    [[AND:%.*]] = and i1 [[CMP1]], [[CMP2]]
+; CHECK-NEXT:    ret i1 [[AND]]
+;
+  %cmp1 = icmp sgt i8 %a, %b
+  %cmp2 = icmp ugt i8 %a, %b
+  %and = and i1 %cmp1, %cmp2
+  ret i1 %and
+}
+
+define i1 @sgt_ule(i8 %a, i8 %b) {
+; CHECK-LABEL: @sgt_ule(
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp sgt i8 %a, %b
+; CHECK-NEXT:    [[CMP2:%.*]] = icmp ule i8 %a, %b
+; CHECK-NEXT:    [[AND:%.*]] = and i1 [[CMP1]], [[CMP2]]
+; CHECK-NEXT:    ret i1 [[AND]]
+;
+  %cmp1 = icmp sgt i8 %a, %b
+  %cmp2 = icmp ule i8 %a, %b
+  %and = and i1 %cmp1, %cmp2
+  ret i1 %and
+}
+
+define i1 @sgt_ult(i8 %a, i8 %b) {
+; CHECK-LABEL: @sgt_ult(
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp sgt i8 %a, %b
+; CHECK-NEXT:    [[CMP2:%.*]] = icmp ult i8 %a, %b
+; CHECK-NEXT:    [[AND:%.*]] = and i1 [[CMP1]], [[CMP2]]
+; CHECK-NEXT:    ret i1 [[AND]]
+;
+  %cmp1 = icmp sgt i8 %a, %b
+  %cmp2 = icmp ult i8 %a, %b
+  %and = and i1 %cmp1, %cmp2
+  ret i1 %and
+}
+
+;
+
+define i1 @sle_eq(i8 %a, i8 %b) {
+; CHECK-LABEL: @sle_eq(
+; CHECK-NEXT:    [[CMP2:%.*]] = icmp eq i8 %a, %b
+; CHECK-NEXT:    ret i1 [[CMP2]]
+;
+  %cmp1 = icmp sle i8 %a, %b
+  %cmp2 = icmp eq i8 %a, %b
+  %and = and i1 %cmp1, %cmp2
+  ret i1 %and
+}
+
+define i1 @sle_ne(i8 %a, i8 %b) {
+; CHECK-LABEL: @sle_ne(
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp sle i8 %a, %b
+; CHECK-NEXT:    [[CMP2:%.*]] = icmp ne i8 %a, %b
+; CHECK-NEXT:    [[AND:%.*]] = and i1 [[CMP1]], [[CMP2]]
+; CHECK-NEXT:    ret i1 [[AND]]
+;
+  %cmp1 = icmp sle i8 %a, %b
+  %cmp2 = icmp ne i8 %a, %b
+  %and = and i1 %cmp1, %cmp2
+  ret i1 %and
+}
+
+define i1 @sle_sge(i8 %a, i8 %b) {
+; CHECK-LABEL: @sle_sge(
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp sle i8 %a, %b
+; CHECK-NEXT:    [[CMP2:%.*]] = icmp sge i8 %a, %b
+; CHECK-NEXT:    [[AND:%.*]] = and i1 [[CMP1]], [[CMP2]]
+; CHECK-NEXT:    ret i1 [[AND]]
+;
+  %cmp1 = icmp sle i8 %a, %b
+  %cmp2 = icmp sge i8 %a, %b
+  %and = and i1 %cmp1, %cmp2
+  ret i1 %and
+}
+
+define i1 @sle_sgt(i8 %a, i8 %b) {
+; CHECK-LABEL: @sle_sgt(
+; CHECK-NEXT:    ret i1 false
+;
+  %cmp1 = icmp sle i8 %a, %b
+  %cmp2 = icmp sgt i8 %a, %b
+  %and = and i1 %cmp1, %cmp2
+  ret i1 %and
+}
+
+define i1 @sle_sle(i8 %a, i8 %b) {
+; CHECK-LABEL: @sle_sle(
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp sle i8 %a, %b
+; CHECK-NEXT:    ret i1 [[CMP1]]
+;
+  %cmp1 = icmp sle i8 %a, %b
+  %cmp2 = icmp sle i8 %a, %b
+  %and = and i1 %cmp1, %cmp2
+  ret i1 %and
+}
+
+define i1 @sle_slt(i8 %a, i8 %b) {
+; CHECK-LABEL: @sle_slt(
+; CHECK-NEXT:    [[CMP2:%.*]] = icmp slt i8 %a, %b
+; CHECK-NEXT:    ret i1 [[CMP2]]
+;
+  %cmp1 = icmp sle i8 %a, %b
+  %cmp2 = icmp slt i8 %a, %b
+  %and = and i1 %cmp1, %cmp2
+  ret i1 %and
+}
+
+define i1 @sle_uge(i8 %a, i8 %b) {
+; CHECK-LABEL: @sle_uge(
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp sle i8 %a, %b
+; CHECK-NEXT:    [[CMP2:%.*]] = icmp uge i8 %a, %b
+; CHECK-NEXT:    [[AND:%.*]] = and i1 [[CMP1]], [[CMP2]]
+; CHECK-NEXT:    ret i1 [[AND]]
+;
+  %cmp1 = icmp sle i8 %a, %b
+  %cmp2 = icmp uge i8 %a, %b
+  %and = and i1 %cmp1, %cmp2
+  ret i1 %and
+}
+
+define i1 @sle_ugt(i8 %a, i8 %b) {
+; CHECK-LABEL: @sle_ugt(
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp sle i8 %a, %b
+; CHECK-NEXT:    [[CMP2:%.*]] = icmp ugt i8 %a, %b
+; CHECK-NEXT:    [[AND:%.*]] = and i1 [[CMP1]], [[CMP2]]
+; CHECK-NEXT:    ret i1 [[AND]]
+;
+  %cmp1 = icmp sle i8 %a, %b
+  %cmp2 = icmp ugt i8 %a, %b
+  %and = and i1 %cmp1, %cmp2
+  ret i1 %and
+}
+
+define i1 @sle_ule(i8 %a, i8 %b) {
+; CHECK-LABEL: @sle_ule(
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp sle i8 %a, %b
+; CHECK-NEXT:    [[CMP2:%.*]] = icmp ule i8 %a, %b
+; CHECK-NEXT:    [[AND:%.*]] = and i1 [[CMP1]], [[CMP2]]
+; CHECK-NEXT:    ret i1 [[AND]]
+;
+  %cmp1 = icmp sle i8 %a, %b
+  %cmp2 = icmp ule i8 %a, %b
+  %and = and i1 %cmp1, %cmp2
+  ret i1 %and
+}
+
+define i1 @sle_ult(i8 %a, i8 %b) {
+; CHECK-LABEL: @sle_ult(
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp sle i8 %a, %b
+; CHECK-NEXT:    [[CMP2:%.*]] = icmp ult i8 %a, %b
+; CHECK-NEXT:    [[AND:%.*]] = and i1 [[CMP1]], [[CMP2]]
+; CHECK-NEXT:    ret i1 [[AND]]
+;
+  %cmp1 = icmp sle i8 %a, %b
+  %cmp2 = icmp ult i8 %a, %b
+  %and = and i1 %cmp1, %cmp2
+  ret i1 %and
+}
+
+;
+
+define i1 @slt_eq(i8 %a, i8 %b) {
+; CHECK-LABEL: @slt_eq(
+; CHECK-NEXT:    ret i1 false
+;
+  %cmp1 = icmp slt i8 %a, %b
+  %cmp2 = icmp eq i8 %a, %b
+  %and = and i1 %cmp1, %cmp2
+  ret i1 %and
+}
+
+define i1 @slt_ne(i8 %a, i8 %b) {
+; CHECK-LABEL: @slt_ne(
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp slt i8 %a, %b
+; CHECK-NEXT:    ret i1 [[CMP1]]
+;
+  %cmp1 = icmp slt i8 %a, %b
+  %cmp2 = icmp ne i8 %a, %b
+  %and = and i1 %cmp1, %cmp2
+  ret i1 %and
+}
+
+define i1 @slt_sge(i8 %a, i8 %b) {
+; CHECK-LABEL: @slt_sge(
+; CHECK-NEXT:    ret i1 false
+;
+  %cmp1 = icmp slt i8 %a, %b
+  %cmp2 = icmp sge i8 %a, %b
+  %and = and i1 %cmp1, %cmp2
+  ret i1 %and
+}
+
+define i1 @slt_sgt(i8 %a, i8 %b) {
+; CHECK-LABEL: @slt_sgt(
+; CHECK-NEXT:    ret i1 false
+;
+  %cmp1 = icmp slt i8 %a, %b
+  %cmp2 = icmp sgt i8 %a, %b
+  %and = and i1 %cmp1, %cmp2
+  ret i1 %and
+}
+
+define i1 @slt_sle(i8 %a, i8 %b) {
+; CHECK-LABEL: @slt_sle(
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp slt i8 %a, %b
+; CHECK-NEXT:    ret i1 [[CMP1]]
+;
+  %cmp1 = icmp slt i8 %a, %b
+  %cmp2 = icmp sle i8 %a, %b
+  %and = and i1 %cmp1, %cmp2
+  ret i1 %and
+}
+
+define i1 @slt_slt(i8 %a, i8 %b) {
+; CHECK-LABEL: @slt_slt(
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp slt i8 %a, %b
+; CHECK-NEXT:    ret i1 [[CMP1]]
+;
+  %cmp1 = icmp slt i8 %a, %b
+  %cmp2 = icmp slt i8 %a, %b
+  %and = and i1 %cmp1, %cmp2
+  ret i1 %and
+}
+
+define i1 @slt_uge(i8 %a, i8 %b) {
+; CHECK-LABEL: @slt_uge(
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp slt i8 %a, %b
+; CHECK-NEXT:    [[CMP2:%.*]] = icmp uge i8 %a, %b
+; CHECK-NEXT:    [[AND:%.*]] = and i1 [[CMP1]], [[CMP2]]
+; CHECK-NEXT:    ret i1 [[AND]]
+;
+  %cmp1 = icmp slt i8 %a, %b
+  %cmp2 = icmp uge i8 %a, %b
+  %and = and i1 %cmp1, %cmp2
+  ret i1 %and
+}
+
+define i1 @slt_ugt(i8 %a, i8 %b) {
+; CHECK-LABEL: @slt_ugt(
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp slt i8 %a, %b
+; CHECK-NEXT:    [[CMP2:%.*]] = icmp ugt i8 %a, %b
+; CHECK-NEXT:    [[AND:%.*]] = and i1 [[CMP1]], [[CMP2]]
+; CHECK-NEXT:    ret i1 [[AND]]
+;
+  %cmp1 = icmp slt i8 %a, %b
+  %cmp2 = icmp ugt i8 %a, %b
+  %and = and i1 %cmp1, %cmp2
+  ret i1 %and
+}
+
+define i1 @slt_ule(i8 %a, i8 %b) {
+; CHECK-LABEL: @slt_ule(
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp slt i8 %a, %b
+; CHECK-NEXT:    [[CMP2:%.*]] = icmp ule i8 %a, %b
+; CHECK-NEXT:    [[AND:%.*]] = and i1 [[CMP1]], [[CMP2]]
+; CHECK-NEXT:    ret i1 [[AND]]
+;
+  %cmp1 = icmp slt i8 %a, %b
+  %cmp2 = icmp ule i8 %a, %b
+  %and = and i1 %cmp1, %cmp2
+  ret i1 %and
+}
+
+define i1 @slt_ult(i8 %a, i8 %b) {
+; CHECK-LABEL: @slt_ult(
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp slt i8 %a, %b
+; CHECK-NEXT:    [[CMP2:%.*]] = icmp ult i8 %a, %b
+; CHECK-NEXT:    [[AND:%.*]] = and i1 [[CMP1]], [[CMP2]]
+; CHECK-NEXT:    ret i1 [[AND]]
+;
+  %cmp1 = icmp slt i8 %a, %b
+  %cmp2 = icmp ult i8 %a, %b
+  %and = and i1 %cmp1, %cmp2
+  ret i1 %and
+}
+
+;
+
+define i1 @uge_eq(i8 %a, i8 %b) {
+; CHECK-LABEL: @uge_eq(
+; CHECK-NEXT:    [[CMP2:%.*]] = icmp eq i8 %a, %b
+; CHECK-NEXT:    ret i1 [[CMP2]]
+;
+  %cmp1 = icmp uge i8 %a, %b
+  %cmp2 = icmp eq i8 %a, %b
+  %and = and i1 %cmp1, %cmp2
+  ret i1 %and
+}
+
+define i1 @uge_ne(i8 %a, i8 %b) {
+; CHECK-LABEL: @uge_ne(
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp uge i8 %a, %b
+; CHECK-NEXT:    [[CMP2:%.*]] = icmp ne i8 %a, %b
+; CHECK-NEXT:    [[AND:%.*]] = and i1 [[CMP1]], [[CMP2]]
+; CHECK-NEXT:    ret i1 [[AND]]
+;
+  %cmp1 = icmp uge i8 %a, %b
+  %cmp2 = icmp ne i8 %a, %b
+  %and = and i1 %cmp1, %cmp2
+  ret i1 %and
+}
+
+define i1 @uge_sge(i8 %a, i8 %b) {
+; CHECK-LABEL: @uge_sge(
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp uge i8 %a, %b
+; CHECK-NEXT:    [[CMP2:%.*]] = icmp sge i8 %a, %b
+; CHECK-NEXT:    [[AND:%.*]] = and i1 [[CMP1]], [[CMP2]]
+; CHECK-NEXT:    ret i1 [[AND]]
+;
+  %cmp1 = icmp uge i8 %a, %b
+  %cmp2 = icmp sge i8 %a, %b
+  %and = and i1 %cmp1, %cmp2
+  ret i1 %and
+}
+
+define i1 @uge_sgt(i8 %a, i8 %b) {
+; CHECK-LABEL: @uge_sgt(
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp uge i8 %a, %b
+; CHECK-NEXT:    [[CMP2:%.*]] = icmp sgt i8 %a, %b
+; CHECK-NEXT:    [[AND:%.*]] = and i1 [[CMP1]], [[CMP2]]
+; CHECK-NEXT:    ret i1 [[AND]]
+;
+  %cmp1 = icmp uge i8 %a, %b
+  %cmp2 = icmp sgt i8 %a, %b
+  %and = and i1 %cmp1, %cmp2
+  ret i1 %and
+}
+
+define i1 @uge_sle(i8 %a, i8 %b) {
+; CHECK-LABEL: @uge_sle(
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp uge i8 %a, %b
+; CHECK-NEXT:    [[CMP2:%.*]] = icmp sle i8 %a, %b
+; CHECK-NEXT:    [[AND:%.*]] = and i1 [[CMP1]], [[CMP2]]
+; CHECK-NEXT:    ret i1 [[AND]]
+;
+  %cmp1 = icmp uge i8 %a, %b
+  %cmp2 = icmp sle i8 %a, %b
+  %and = and i1 %cmp1, %cmp2
+  ret i1 %and
+}
+
+define i1 @uge_slt(i8 %a, i8 %b) {
+; CHECK-LABEL: @uge_slt(
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp uge i8 %a, %b
+; CHECK-NEXT:    [[CMP2:%.*]] = icmp slt i8 %a, %b
+; CHECK-NEXT:    [[AND:%.*]] = and i1 [[CMP1]], [[CMP2]]
+; CHECK-NEXT:    ret i1 [[AND]]
+;
+  %cmp1 = icmp uge i8 %a, %b
+  %cmp2 = icmp slt i8 %a, %b
+  %and = and i1 %cmp1, %cmp2
+  ret i1 %and
+}
+
+define i1 @uge_uge(i8 %a, i8 %b) {
+; CHECK-LABEL: @uge_uge(
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp uge i8 %a, %b
+; CHECK-NEXT:    ret i1 [[CMP1]]
+;
+  %cmp1 = icmp uge i8 %a, %b
+  %cmp2 = icmp uge i8 %a, %b
+  %and = and i1 %cmp1, %cmp2
+  ret i1 %and
+}
+
+define i1 @uge_ugt(i8 %a, i8 %b) {
+; CHECK-LABEL: @uge_ugt(
+; CHECK-NEXT:    [[CMP2:%.*]] = icmp ugt i8 %a, %b
+; CHECK-NEXT:    ret i1 [[CMP2]]
+;
+  %cmp1 = icmp uge i8 %a, %b
+  %cmp2 = icmp ugt i8 %a, %b
+  %and = and i1 %cmp1, %cmp2
+  ret i1 %and
+}
+
+define i1 @uge_ule(i8 %a, i8 %b) {
+; CHECK-LABEL: @uge_ule(
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp uge i8 %a, %b
+; CHECK-NEXT:    [[CMP2:%.*]] = icmp ule i8 %a, %b
+; CHECK-NEXT:    [[AND:%.*]] = and i1 [[CMP1]], [[CMP2]]
+; CHECK-NEXT:    ret i1 [[AND]]
+;
+  %cmp1 = icmp uge i8 %a, %b
+  %cmp2 = icmp ule i8 %a, %b
+  %and = and i1 %cmp1, %cmp2
+  ret i1 %and
+}
+
+define i1 @uge_ult(i8 %a, i8 %b) {
+; CHECK-LABEL: @uge_ult(
+; CHECK-NEXT:    ret i1 false
+;
+  %cmp1 = icmp uge i8 %a, %b
+  %cmp2 = icmp ult i8 %a, %b
+  %and = and i1 %cmp1, %cmp2
+  ret i1 %and
+}
+
+;
+
+define i1 @ugt_eq(i8 %a, i8 %b) {
+; CHECK-LABEL: @ugt_eq(
+; CHECK-NEXT:    ret i1 false
+;
+  %cmp1 = icmp ugt i8 %a, %b
+  %cmp2 = icmp eq i8 %a, %b
+  %and = and i1 %cmp1, %cmp2
+  ret i1 %and
+}
+
+define i1 @ugt_ne(i8 %a, i8 %b) {
+; CHECK-LABEL: @ugt_ne(
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp ugt i8 %a, %b
+; CHECK-NEXT:    ret i1 [[CMP1]]
+;
+  %cmp1 = icmp ugt i8 %a, %b
+  %cmp2 = icmp ne i8 %a, %b
+  %and = and i1 %cmp1, %cmp2
+  ret i1 %and
+}
+
+define i1 @ugt_sge(i8 %a, i8 %b) {
+; CHECK-LABEL: @ugt_sge(
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp ugt i8 %a, %b
+; CHECK-NEXT:    [[CMP2:%.*]] = icmp sge i8 %a, %b
+; CHECK-NEXT:    [[AND:%.*]] = and i1 [[CMP1]], [[CMP2]]
+; CHECK-NEXT:    ret i1 [[AND]]
+;
+  %cmp1 = icmp ugt i8 %a, %b
+  %cmp2 = icmp sge i8 %a, %b
+  %and = and i1 %cmp1, %cmp2
+  ret i1 %and
+}
+
+define i1 @ugt_sgt(i8 %a, i8 %b) {
+; CHECK-LABEL: @ugt_sgt(
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp ugt i8 %a, %b
+; CHECK-NEXT:    [[CMP2:%.*]] = icmp sgt i8 %a, %b
+; CHECK-NEXT:    [[AND:%.*]] = and i1 [[CMP1]], [[CMP2]]
+; CHECK-NEXT:    ret i1 [[AND]]
+;
+  %cmp1 = icmp ugt i8 %a, %b
+  %cmp2 = icmp sgt i8 %a, %b
+  %and = and i1 %cmp1, %cmp2
+  ret i1 %and
+}
+
+define i1 @ugt_sle(i8 %a, i8 %b) {
+; CHECK-LABEL: @ugt_sle(
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp ugt i8 %a, %b
+; CHECK-NEXT:    [[CMP2:%.*]] = icmp sle i8 %a, %b
+; CHECK-NEXT:    [[AND:%.*]] = and i1 [[CMP1]], [[CMP2]]
+; CHECK-NEXT:    ret i1 [[AND]]
+;
+  %cmp1 = icmp ugt i8 %a, %b
+  %cmp2 = icmp sle i8 %a, %b
+  %and = and i1 %cmp1, %cmp2
+  ret i1 %and
+}
+
+define i1 @ugt_slt(i8 %a, i8 %b) {
+; CHECK-LABEL: @ugt_slt(
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp ugt i8 %a, %b
+; CHECK-NEXT:    [[CMP2:%.*]] = icmp slt i8 %a, %b
+; CHECK-NEXT:    [[AND:%.*]] = and i1 [[CMP1]], [[CMP2]]
+; CHECK-NEXT:    ret i1 [[AND]]
+;
+  %cmp1 = icmp ugt i8 %a, %b
+  %cmp2 = icmp slt i8 %a, %b
+  %and = and i1 %cmp1, %cmp2
+  ret i1 %and
+}
+
+define i1 @ugt_uge(i8 %a, i8 %b) {
+; CHECK-LABEL: @ugt_uge(
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp ugt i8 %a, %b
+; CHECK-NEXT:    ret i1 [[CMP1]]
+;
+  %cmp1 = icmp ugt i8 %a, %b
+  %cmp2 = icmp uge i8 %a, %b
+  %and = and i1 %cmp1, %cmp2
+  ret i1 %and
+}
+
+define i1 @ugt_ugt(i8 %a, i8 %b) {
+; CHECK-LABEL: @ugt_ugt(
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp ugt i8 %a, %b
+; CHECK-NEXT:    ret i1 [[CMP1]]
+;
+  %cmp1 = icmp ugt i8 %a, %b
+  %cmp2 = icmp ugt i8 %a, %b
+  %and = and i1 %cmp1, %cmp2
+  ret i1 %and
+}
+
+define i1 @ugt_ule(i8 %a, i8 %b) {
+; CHECK-LABEL: @ugt_ule(
+; CHECK-NEXT:    ret i1 false
+;
+  %cmp1 = icmp ugt i8 %a, %b
+  %cmp2 = icmp ule i8 %a, %b
+  %and = and i1 %cmp1, %cmp2
+  ret i1 %and
+}
+
+define i1 @ugt_ult(i8 %a, i8 %b) {
+; CHECK-LABEL: @ugt_ult(
+; CHECK-NEXT:    ret i1 false
+;
+  %cmp1 = icmp ugt i8 %a, %b
+  %cmp2 = icmp ult i8 %a, %b
+  %and = and i1 %cmp1, %cmp2
+  ret i1 %and
+}
+
+;
+
+define i1 @ule_eq(i8 %a, i8 %b) {
+; CHECK-LABEL: @ule_eq(
+; CHECK-NEXT:    [[CMP2:%.*]] = icmp eq i8 %a, %b
+; CHECK-NEXT:    ret i1 [[CMP2]]
+;
+  %cmp1 = icmp ule i8 %a, %b
+  %cmp2 = icmp eq i8 %a, %b
+  %and = and i1 %cmp1, %cmp2
+  ret i1 %and
+}
+
+define i1 @ule_ne(i8 %a, i8 %b) {
+; CHECK-LABEL: @ule_ne(
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp ule i8 %a, %b
+; CHECK-NEXT:    [[CMP2:%.*]] = icmp ne i8 %a, %b
+; CHECK-NEXT:    [[AND:%.*]] = and i1 [[CMP1]], [[CMP2]]
+; CHECK-NEXT:    ret i1 [[AND]]
+;
+  %cmp1 = icmp ule i8 %a, %b
+  %cmp2 = icmp ne i8 %a, %b
+  %and = and i1 %cmp1, %cmp2
+  ret i1 %and
+}
+
+define i1 @ule_sge(i8 %a, i8 %b) {
+; CHECK-LABEL: @ule_sge(
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp ule i8 %a, %b
+; CHECK-NEXT:    [[CMP2:%.*]] = icmp sge i8 %a, %b
+; CHECK-NEXT:    [[AND:%.*]] = and i1 [[CMP1]], [[CMP2]]
+; CHECK-NEXT:    ret i1 [[AND]]
+;
+  %cmp1 = icmp ule i8 %a, %b
+  %cmp2 = icmp sge i8 %a, %b
+  %and = and i1 %cmp1, %cmp2
+  ret i1 %and
+}
+
+define i1 @ule_sgt(i8 %a, i8 %b) {
+; CHECK-LABEL: @ule_sgt(
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp ule i8 %a, %b
+; CHECK-NEXT:    [[CMP2:%.*]] = icmp sgt i8 %a, %b
+; CHECK-NEXT:    [[AND:%.*]] = and i1 [[CMP1]], [[CMP2]]
+; CHECK-NEXT:    ret i1 [[AND]]
+;
+  %cmp1 = icmp ule i8 %a, %b
+  %cmp2 = icmp sgt i8 %a, %b
+  %and = and i1 %cmp1, %cmp2
+  ret i1 %and
+}
+
+define i1 @ule_sle(i8 %a, i8 %b) {
+; CHECK-LABEL: @ule_sle(
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp ule i8 %a, %b
+; CHECK-NEXT:    [[CMP2:%.*]] = icmp sle i8 %a, %b
+; CHECK-NEXT:    [[AND:%.*]] = and i1 [[CMP1]], [[CMP2]]
+; CHECK-NEXT:    ret i1 [[AND]]
+;
+  %cmp1 = icmp ule i8 %a, %b
+  %cmp2 = icmp sle i8 %a, %b
+  %and = and i1 %cmp1, %cmp2
+  ret i1 %and
+}
+
+define i1 @ule_slt(i8 %a, i8 %b) {
+; CHECK-LABEL: @ule_slt(
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp ule i8 %a, %b
+; CHECK-NEXT:    [[CMP2:%.*]] = icmp slt i8 %a, %b
+; CHECK-NEXT:    [[AND:%.*]] = and i1 [[CMP1]], [[CMP2]]
+; CHECK-NEXT:    ret i1 [[AND]]
+;
+  %cmp1 = icmp ule i8 %a, %b
+  %cmp2 = icmp slt i8 %a, %b
+  %and = and i1 %cmp1, %cmp2
+  ret i1 %and
+}
+
+define i1 @ule_uge(i8 %a, i8 %b) {
+; CHECK-LABEL: @ule_uge(
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp ule i8 %a, %b
+; CHECK-NEXT:    [[CMP2:%.*]] = icmp uge i8 %a, %b
+; CHECK-NEXT:    [[AND:%.*]] = and i1 [[CMP1]], [[CMP2]]
+; CHECK-NEXT:    ret i1 [[AND]]
+;
+  %cmp1 = icmp ule i8 %a, %b
+  %cmp2 = icmp uge i8 %a, %b
+  %and = and i1 %cmp1, %cmp2
+  ret i1 %and
+}
+
+define i1 @ule_ugt(i8 %a, i8 %b) {
+; CHECK-LABEL: @ule_ugt(
+; CHECK-NEXT:    ret i1 false
+;
+  %cmp1 = icmp ule i8 %a, %b
+  %cmp2 = icmp ugt i8 %a, %b
+  %and = and i1 %cmp1, %cmp2
+  ret i1 %and
+}
+
+define i1 @ule_ule(i8 %a, i8 %b) {
+; CHECK-LABEL: @ule_ule(
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp ule i8 %a, %b
+; CHECK-NEXT:    ret i1 [[CMP1]]
+;
+  %cmp1 = icmp ule i8 %a, %b
+  %cmp2 = icmp ule i8 %a, %b
+  %and = and i1 %cmp1, %cmp2
+  ret i1 %and
+}
+
+define i1 @ule_ult(i8 %a, i8 %b) {
+; CHECK-LABEL: @ule_ult(
+; CHECK-NEXT:    [[CMP2:%.*]] = icmp ult i8 %a, %b
+; CHECK-NEXT:    ret i1 [[CMP2]]
+;
+  %cmp1 = icmp ule i8 %a, %b
+  %cmp2 = icmp ult i8 %a, %b
+  %and = and i1 %cmp1, %cmp2
+  ret i1 %and
+}
+
+;
+
+define i1 @ult_eq(i8 %a, i8 %b) {
+; CHECK-LABEL: @ult_eq(
+; CHECK-NEXT:    ret i1 false
+;
+  %cmp1 = icmp ult i8 %a, %b
+  %cmp2 = icmp eq i8 %a, %b
+  %and = and i1 %cmp1, %cmp2
+  ret i1 %and
+}
+
+define i1 @ult_ne(i8 %a, i8 %b) {
+; CHECK-LABEL: @ult_ne(
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp ult i8 %a, %b
+; CHECK-NEXT:    ret i1 [[CMP1]]
+;
+  %cmp1 = icmp ult i8 %a, %b
+  %cmp2 = icmp ne i8 %a, %b
+  %and = and i1 %cmp1, %cmp2
+  ret i1 %and
+}
+
+define i1 @ult_sge(i8 %a, i8 %b) {
+; CHECK-LABEL: @ult_sge(
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp ult i8 %a, %b
+; CHECK-NEXT:    [[CMP2:%.*]] = icmp sge i8 %a, %b
+; CHECK-NEXT:    [[AND:%.*]] = and i1 [[CMP1]], [[CMP2]]
+; CHECK-NEXT:    ret i1 [[AND]]
+;
+  %cmp1 = icmp ult i8 %a, %b
+  %cmp2 = icmp sge i8 %a, %b
+  %and = and i1 %cmp1, %cmp2
+  ret i1 %and
+}
+
+define i1 @ult_sgt(i8 %a, i8 %b) {
+; CHECK-LABEL: @ult_sgt(
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp ult i8 %a, %b
+; CHECK-NEXT:    [[CMP2:%.*]] = icmp sgt i8 %a, %b
+; CHECK-NEXT:    [[AND:%.*]] = and i1 [[CMP1]], [[CMP2]]
+; CHECK-NEXT:    ret i1 [[AND]]
+;
+  %cmp1 = icmp ult i8 %a, %b
+  %cmp2 = icmp sgt i8 %a, %b
+  %and = and i1 %cmp1, %cmp2
+  ret i1 %and
+}
+
+define i1 @ult_sle(i8 %a, i8 %b) {
+; CHECK-LABEL: @ult_sle(
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp ult i8 %a, %b
+; CHECK-NEXT:    [[CMP2:%.*]] = icmp sle i8 %a, %b
+; CHECK-NEXT:    [[AND:%.*]] = and i1 [[CMP1]], [[CMP2]]
+; CHECK-NEXT:    ret i1 [[AND]]
+;
+  %cmp1 = icmp ult i8 %a, %b
+  %cmp2 = icmp sle i8 %a, %b
+  %and = and i1 %cmp1, %cmp2
+  ret i1 %and
+}
+
+define i1 @ult_slt(i8 %a, i8 %b) {
+; CHECK-LABEL: @ult_slt(
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp ult i8 %a, %b
+; CHECK-NEXT:    [[CMP2:%.*]] = icmp slt i8 %a, %b
+; CHECK-NEXT:    [[AND:%.*]] = and i1 [[CMP1]], [[CMP2]]
+; CHECK-NEXT:    ret i1 [[AND]]
+;
+  %cmp1 = icmp ult i8 %a, %b
+  %cmp2 = icmp slt i8 %a, %b
+  %and = and i1 %cmp1, %cmp2
+  ret i1 %and
+}
+
+define i1 @ult_uge(i8 %a, i8 %b) {
+; CHECK-LABEL: @ult_uge(
+; CHECK-NEXT:    ret i1 false
+;
+  %cmp1 = icmp ult i8 %a, %b
+  %cmp2 = icmp uge i8 %a, %b
+  %and = and i1 %cmp1, %cmp2
+  ret i1 %and
+}
+
+define i1 @ult_ugt(i8 %a, i8 %b) {
+; CHECK-LABEL: @ult_ugt(
+; CHECK-NEXT:    ret i1 false
+;
+  %cmp1 = icmp ult i8 %a, %b
+  %cmp2 = icmp ugt i8 %a, %b
+  %and = and i1 %cmp1, %cmp2
+  ret i1 %and
+}
+
+define i1 @ult_ule(i8 %a, i8 %b) {
+; CHECK-LABEL: @ult_ule(
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp ult i8 %a, %b
+; CHECK-NEXT:    ret i1 [[CMP1]]
+;
+  %cmp1 = icmp ult i8 %a, %b
+  %cmp2 = icmp ule i8 %a, %b
+  %and = and i1 %cmp1, %cmp2
+  ret i1 %and
+}
+
+define i1 @ult_ult(i8 %a, i8 %b) {
+; CHECK-LABEL: @ult_ult(
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp ult i8 %a, %b
+; CHECK-NEXT:    ret i1 [[CMP1]]
+;
+  %cmp1 = icmp ult i8 %a, %b
+  %cmp2 = icmp ult i8 %a, %b
+  %and = and i1 %cmp1, %cmp2
+  ret i1 %and
+}
+
+; Check a couple of vector variants to make sure those work too.
+
+define <2 x i1> @ult_uge_vec(<2 x i8> %a, <2 x i8> %b) {
+; CHECK-LABEL: @ult_uge_vec(
+; CHECK-NEXT:    ret <2 x i1> zeroinitializer
+;
+  %cmp1 = icmp ult <2 x i8> %a, %b
+  %cmp2 = icmp uge <2 x i8> %a, %b
+  %and = and <2 x i1> %cmp1, %cmp2
+  ret <2 x i1> %and
+}
+
+define <2 x i1> @ult_ule_vec(<2 x i8> %a, <2 x i8> %b) {
+; CHECK-LABEL: @ult_ule_vec(
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp ult <2 x i8> %a, %b
+; CHECK-NEXT:    ret <2 x i1> [[CMP1]]
+;
+  %cmp1 = icmp ult <2 x i8> %a, %b
+  %cmp2 = icmp ule <2 x i8> %a, %b
+  %and = and <2 x i1> %cmp1, %cmp2
+  ret <2 x i1> %and
+}
+
+define i1 @ult_uge_swap(i8 %a, i8 %b) {
+; CHECK-LABEL: @ult_uge_swap(
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp ult i8 %a, %b
+; CHECK-NEXT:    [[CMP2:%.*]] = icmp uge i8 %b, %a
+; CHECK-NEXT:    [[AND:%.*]] = and i1 [[CMP1]], [[CMP2]]
+; CHECK-NEXT:    ret i1 [[AND]]
+;
+  %cmp1 = icmp ult i8 %a, %b
+  %cmp2 = icmp uge i8 %b, %a
+  %and = and i1 %cmp1, %cmp2
+  ret i1 %and
+}
+
+define i1 @ult_ult_swap(i8 %a, i8 %b) {
+; CHECK-LABEL: @ult_ult_swap(
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp ult i8 %a, %b
+; CHECK-NEXT:    [[CMP2:%.*]] = icmp ult i8 %b, %a
+; CHECK-NEXT:    [[AND:%.*]] = and i1 [[CMP1]], [[CMP2]]
+; CHECK-NEXT:    ret i1 [[AND]]
+;
+  %cmp1 = icmp ult i8 %a, %b
+  %cmp2 = icmp ult i8 %b, %a
+  %and = and i1 %cmp1, %cmp2
+  ret i1 %and
+}
+

Added: llvm/trunk/test/Transforms/InstSimplify/and-or-icmp-zero.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstSimplify/and-or-icmp-zero.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstSimplify/and-or-icmp-zero.ll (added)
+++ llvm/trunk/test/Transforms/InstSimplify/and-or-icmp-zero.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,263 @@
+; RUN: opt < %s -instsimplify -S | FileCheck %s
+
+; In the next 16 tests (4 commutes * 2 (and/or) * 2 optional ptrtoint casts),
+; eliminate the simple (not) null check because that compare is implied by the
+; masked compare of the same operand.
+; Vary types between scalar and vector and weird for extra coverage.
+
+; or (icmp eq (and X, ?), 0), (icmp eq X, 0) --> icmp eq (and X, ?), 0
+
+define i1 @or_cmps_eq_zero_with_mask_commute1(i64 %x, i64 %y) {
+; CHECK-LABEL: @or_cmps_eq_zero_with_mask_commute1(
+; CHECK-NEXT:    [[SOMEBITS:%.*]] = and i64 %x, %y
+; CHECK-NEXT:    [[SOMEBITS_ARE_ZERO:%.*]] = icmp eq i64 [[SOMEBITS]], 0
+; CHECK-NEXT:    ret i1 [[SOMEBITS_ARE_ZERO]]
+;
+  %isnull = icmp eq i64 %x, 0
+  %somebits = and i64 %x, %y
+  %somebits_are_zero = icmp eq i64 %somebits, 0
+  %r = or i1 %somebits_are_zero, %isnull
+  ret i1 %r
+}
+
+; or (icmp eq X, 0), (icmp eq (and X, ?), 0) --> icmp eq (and X, ?), 0
+
+define <2 x i1> @or_cmps_eq_zero_with_mask_commute2(<2 x i64> %x, <2 x i64> %y) {
+; CHECK-LABEL: @or_cmps_eq_zero_with_mask_commute2(
+; CHECK-NEXT:    [[SOMEBITS:%.*]] = and <2 x i64> %x, %y
+; CHECK-NEXT:    [[SOMEBITS_ARE_ZERO:%.*]] = icmp eq <2 x i64> [[SOMEBITS]], zeroinitializer
+; CHECK-NEXT:    ret <2 x i1> [[SOMEBITS_ARE_ZERO]]
+;
+  %isnull = icmp eq <2 x i64> %x, zeroinitializer
+  %somebits = and <2 x i64> %x, %y
+  %somebits_are_zero = icmp eq <2 x i64> %somebits, zeroinitializer
+  %r = or <2 x i1> %isnull, %somebits_are_zero
+  ret <2 x i1> %r
+}
+
+; or (icmp eq (and ?, X), 0), (icmp eq X, 0) --> icmp eq (and ?, X), 0
+
+define i1 @or_cmps_eq_zero_with_mask_commute3(i4 %x, i4 %y) {
+; CHECK-LABEL: @or_cmps_eq_zero_with_mask_commute3(
+; CHECK-NEXT:    [[SOMEBITS:%.*]] = and i4 %y, %x
+; CHECK-NEXT:    [[SOMEBITS_ARE_ZERO:%.*]] = icmp eq i4 [[SOMEBITS]], 0
+; CHECK-NEXT:    ret i1 [[SOMEBITS_ARE_ZERO]]
+;
+  %isnull = icmp eq i4 %x, 0
+  %somebits = and i4 %y, %x
+  %somebits_are_zero = icmp eq i4 %somebits, 0
+  %r = or i1 %somebits_are_zero, %isnull
+  ret i1 %r
+}
+
+; or (icmp eq X, 0), (icmp eq (and ?, X), 0) --> icmp eq (and ?, X), 0
+
+define <2 x i1> @or_cmps_eq_zero_with_mask_commute4(<2 x i4> %x, <2 x i4> %y) {
+; CHECK-LABEL: @or_cmps_eq_zero_with_mask_commute4(
+; CHECK-NEXT:    [[SOMEBITS:%.*]] = and <2 x i4> %y, %x
+; CHECK-NEXT:    [[SOMEBITS_ARE_ZERO:%.*]] = icmp eq <2 x i4> [[SOMEBITS]], zeroinitializer
+; CHECK-NEXT:    ret <2 x i1> [[SOMEBITS_ARE_ZERO]]
+;
+  %isnull = icmp eq <2 x i4> %x, zeroinitializer
+  %somebits = and <2 x i4> %y, %x
+  %somebits_are_zero = icmp eq <2 x i4> %somebits, zeroinitializer
+  %r = or <2 x i1> %isnull, %somebits_are_zero
+  ret <2 x i1> %r
+}
+
+; and (icmp ne (and X, ?), 0), (icmp ne X, 0) --> icmp ne (and X, ?), 0
+
+define <3 x i1> @and_cmps_eq_zero_with_mask_commute1(<3 x i4> %x, <3 x i4> %y) {
+; CHECK-LABEL: @and_cmps_eq_zero_with_mask_commute1(
+; CHECK-NEXT:    [[SOMEBITS:%.*]] = and <3 x i4> %x, %y
+; CHECK-NEXT:    [[SOMEBITS_ARE_NOT_ZERO:%.*]] = icmp ne <3 x i4> [[SOMEBITS]], zeroinitializer
+; CHECK-NEXT:    ret <3 x i1> [[SOMEBITS_ARE_NOT_ZERO]]
+;
+  %isnotnull = icmp ne <3 x i4> %x, zeroinitializer
+  %somebits = and <3 x i4> %x, %y
+  %somebits_are_not_zero = icmp ne <3 x i4> %somebits, zeroinitializer
+  %r = and <3 x i1> %somebits_are_not_zero, %isnotnull
+  ret <3 x i1> %r
+}
+
+; and (icmp ne X, 0), (icmp ne (and X, ?), 0) --> icmp ne (and X, ?), 0
+
+define i1 @and_cmps_eq_zero_with_mask_commute2(i4 %x, i4 %y) {
+; CHECK-LABEL: @and_cmps_eq_zero_with_mask_commute2(
+; CHECK-NEXT:    [[SOMEBITS:%.*]] = and i4 %x, %y
+; CHECK-NEXT:    [[SOMEBITS_ARE_NOT_ZERO:%.*]] = icmp ne i4 [[SOMEBITS]], 0
+; CHECK-NEXT:    ret i1 [[SOMEBITS_ARE_NOT_ZERO]]
+;
+  %isnotnull = icmp ne i4 %x, 0
+  %somebits = and i4 %x, %y
+  %somebits_are_not_zero = icmp ne i4 %somebits, 0
+  %r = and i1 %isnotnull, %somebits_are_not_zero
+  ret i1 %r
+}
+
+; and (icmp ne (and ?, X), 0), (icmp ne X, 0) --> icmp ne (and ?, X), 0
+
+define <3 x i1> @and_cmps_eq_zero_with_mask_commute3(<3 x i64> %x, <3 x i64> %y) {
+; CHECK-LABEL: @and_cmps_eq_zero_with_mask_commute3(
+; CHECK-NEXT:    [[SOMEBITS:%.*]] = and <3 x i64> %y, %x
+; CHECK-NEXT:    [[SOMEBITS_ARE_NOT_ZERO:%.*]] = icmp ne <3 x i64> [[SOMEBITS]], zeroinitializer
+; CHECK-NEXT:    ret <3 x i1> [[SOMEBITS_ARE_NOT_ZERO]]
+;
+  %isnotnull = icmp ne <3 x i64> %x, zeroinitializer
+  %somebits = and <3 x i64> %y, %x
+  %somebits_are_not_zero = icmp ne <3 x i64> %somebits, zeroinitializer
+  %r = and <3 x i1> %somebits_are_not_zero, %isnotnull
+  ret <3 x i1> %r
+}
+
+; and (icmp ne X, 0), (icmp ne (and ?, X), 0) --> icmp ne (and ?, X), 0
+
+define i1 @and_cmps_eq_zero_with_mask_commute4(i64 %x, i64 %y) {
+; CHECK-LABEL: @and_cmps_eq_zero_with_mask_commute4(
+; CHECK-NEXT:    [[SOMEBITS:%.*]] = and i64 %y, %x
+; CHECK-NEXT:    [[SOMEBITS_ARE_NOT_ZERO:%.*]] = icmp ne i64 [[SOMEBITS]], 0
+; CHECK-NEXT:    ret i1 [[SOMEBITS_ARE_NOT_ZERO]]
+;
+  %isnotnull = icmp ne i64 %x, 0
+  %somebits = and i64 %y, %x
+  %somebits_are_not_zero = icmp ne i64 %somebits, 0
+  %r = and i1 %isnotnull, %somebits_are_not_zero
+  ret i1 %r
+}
+
+; or (icmp eq (and (ptrtoint P), ?), 0), (icmp eq P, 0) --> icmp eq (and (ptrtoint P), ?), 0
+
+define i1 @or_cmps_ptr_eq_zero_with_mask_commute1(i64* %p, i64 %y) {
+; CHECK-LABEL: @or_cmps_ptr_eq_zero_with_mask_commute1(
+; CHECK-NEXT:    [[X:%.*]] = ptrtoint i64* %p to i64
+; CHECK-NEXT:    [[SOMEBITS:%.*]] = and i64 [[X]], %y
+; CHECK-NEXT:    [[SOMEBITS_ARE_ZERO:%.*]] = icmp eq i64 [[SOMEBITS]], 0
+; CHECK-NEXT:    ret i1 [[SOMEBITS_ARE_ZERO]]
+;
+  %isnull = icmp eq i64* %p, null
+  %x = ptrtoint i64* %p to i64
+  %somebits = and i64 %x, %y
+  %somebits_are_zero = icmp eq i64 %somebits, 0
+  %r = or i1 %somebits_are_zero, %isnull
+  ret i1 %r
+}
+
+; or (icmp eq P, 0), (icmp eq (and (ptrtoint P), ?), 0) --> icmp eq (and (ptrtoint P), ?), 0
+
+define <2 x i1> @or_cmps_ptr_eq_zero_with_mask_commute2(<2 x i64*> %p, <2 x i64> %y) {
+; CHECK-LABEL: @or_cmps_ptr_eq_zero_with_mask_commute2(
+; CHECK-NEXT:    [[X:%.*]] = ptrtoint <2 x i64*> %p to <2 x i64>
+; CHECK-NEXT:    [[SOMEBITS:%.*]] = and <2 x i64> [[X]], %y
+; CHECK-NEXT:    [[SOMEBITS_ARE_ZERO:%.*]] = icmp eq <2 x i64> [[SOMEBITS]], zeroinitializer
+; CHECK-NEXT:    ret <2 x i1> [[SOMEBITS_ARE_ZERO]]
+;
+  %isnull = icmp eq <2 x i64*> %p, zeroinitializer
+  %x = ptrtoint <2 x i64*> %p to <2 x i64>
+  %somebits = and <2 x i64> %x, %y
+  %somebits_are_zero = icmp eq <2 x i64> %somebits, zeroinitializer
+  %r = or <2 x i1> %isnull, %somebits_are_zero
+  ret <2 x i1> %r
+}
+
+; or (icmp eq (and ?, (ptrtoint P)), 0), (icmp eq P, 0) --> icmp eq (and ?, (ptrtoint P)), 0
+
+define i1 @or_cmps_ptr_eq_zero_with_mask_commute3(i4* %p, i4 %y) {
+; CHECK-LABEL: @or_cmps_ptr_eq_zero_with_mask_commute3(
+; CHECK-NEXT:    [[X:%.*]] = ptrtoint i4* %p to i4
+; CHECK-NEXT:    [[SOMEBITS:%.*]] = and i4 %y, [[X]]
+; CHECK-NEXT:    [[SOMEBITS_ARE_ZERO:%.*]] = icmp eq i4 [[SOMEBITS]], 0
+; CHECK-NEXT:    ret i1 [[SOMEBITS_ARE_ZERO]]
+;
+  %isnull = icmp eq i4* %p, null
+  %x = ptrtoint i4* %p to i4
+  %somebits = and i4 %y, %x
+  %somebits_are_zero = icmp eq i4 %somebits, 0
+  %r = or i1 %somebits_are_zero, %isnull
+  ret i1 %r
+}
+
+; or (icmp eq P, 0), (icmp eq (and ?, (ptrtoint P)), 0) --> icmp eq (and ?, (ptrtoint P)), 0
+
+define <2 x i1> @or_cmps_ptr_eq_zero_with_mask_commute4(<2 x i4*> %p, <2 x i4> %y) {
+; CHECK-LABEL: @or_cmps_ptr_eq_zero_with_mask_commute4(
+; CHECK-NEXT:    [[X:%.*]] = ptrtoint <2 x i4*> %p to <2 x i4>
+; CHECK-NEXT:    [[SOMEBITS:%.*]] = and <2 x i4> %y, [[X]]
+; CHECK-NEXT:    [[SOMEBITS_ARE_ZERO:%.*]] = icmp eq <2 x i4> [[SOMEBITS]], zeroinitializer
+; CHECK-NEXT:    ret <2 x i1> [[SOMEBITS_ARE_ZERO]]
+;
+  %isnull = icmp eq <2 x i4*> %p, zeroinitializer
+  %x = ptrtoint <2 x i4*> %p to <2 x i4>
+  %somebits = and <2 x i4> %y, %x
+  %somebits_are_zero = icmp eq <2 x i4> %somebits, zeroinitializer
+  %r = or <2 x i1> %isnull, %somebits_are_zero
+  ret <2 x i1> %r
+}
+
+; and (icmp ne (and (ptrtoint P), ?), 0), (icmp ne P, 0) --> icmp ne (and (ptrtoint P), ?), 0
+
+define <3 x i1> @and_cmps_ptr_eq_zero_with_mask_commute1(<3 x i4*> %p, <3 x i4> %y) {
+; CHECK-LABEL: @and_cmps_ptr_eq_zero_with_mask_commute1(
+; CHECK-NEXT:    [[X:%.*]] = ptrtoint <3 x i4*> %p to <3 x i4>
+; CHECK-NEXT:    [[SOMEBITS:%.*]] = and <3 x i4> [[X]], %y
+; CHECK-NEXT:    [[SOMEBITS_ARE_NOT_ZERO:%.*]] = icmp ne <3 x i4> [[SOMEBITS]], zeroinitializer
+; CHECK-NEXT:    ret <3 x i1> [[SOMEBITS_ARE_NOT_ZERO]]
+;
+  %isnotnull = icmp ne <3 x i4*> %p, zeroinitializer
+  %x = ptrtoint <3 x i4*> %p to <3 x i4>
+  %somebits = and <3 x i4> %x, %y
+  %somebits_are_not_zero = icmp ne <3 x i4> %somebits, zeroinitializer
+  %r = and <3 x i1> %somebits_are_not_zero, %isnotnull
+  ret <3 x i1> %r
+}
+
+; and (icmp ne P, 0), (icmp ne (and (ptrtoint P), ?), 0) --> icmp ne (and (ptrtoint P), ?), 0
+
+define i1 @and_cmps_ptr_eq_zero_with_mask_commute2(i4* %p, i4 %y) {
+; CHECK-LABEL: @and_cmps_ptr_eq_zero_with_mask_commute2(
+; CHECK-NEXT:    [[X:%.*]] = ptrtoint i4* %p to i4
+; CHECK-NEXT:    [[SOMEBITS:%.*]] = and i4 [[X]], %y
+; CHECK-NEXT:    [[SOMEBITS_ARE_NOT_ZERO:%.*]] = icmp ne i4 [[SOMEBITS]], 0
+; CHECK-NEXT:    ret i1 [[SOMEBITS_ARE_NOT_ZERO]]
+;
+  %isnotnull = icmp ne i4* %p, null
+  %x = ptrtoint i4* %p to i4
+  %somebits = and i4 %x, %y
+  %somebits_are_not_zero = icmp ne i4 %somebits, 0
+  %r = and i1 %isnotnull, %somebits_are_not_zero
+  ret i1 %r
+}
+
+; and (icmp ne (and ?, (ptrtoint P)), 0), (icmp ne P, 0) --> icmp ne (and ?, (ptrtoint P)), 0
+
+define <3 x i1> @and_cmps_ptr_eq_zero_with_mask_commute3(<3 x i64*> %p, <3 x i64> %y) {
+; CHECK-LABEL: @and_cmps_ptr_eq_zero_with_mask_commute3(
+; CHECK-NEXT:    [[X:%.*]] = ptrtoint <3 x i64*> %p to <3 x i64>
+; CHECK-NEXT:    [[SOMEBITS:%.*]] = and <3 x i64> %y, [[X]]
+; CHECK-NEXT:    [[SOMEBITS_ARE_NOT_ZERO:%.*]] = icmp ne <3 x i64> [[SOMEBITS]], zeroinitializer
+; CHECK-NEXT:    ret <3 x i1> [[SOMEBITS_ARE_NOT_ZERO]]
+;
+  %isnotnull = icmp ne <3 x i64*> %p, zeroinitializer
+  %x = ptrtoint <3 x i64*> %p to <3 x i64>
+  %somebits = and <3 x i64> %y, %x
+  %somebits_are_not_zero = icmp ne <3 x i64> %somebits, zeroinitializer
+  %r = and <3 x i1> %somebits_are_not_zero, %isnotnull
+  ret <3 x i1> %r
+}
+
+; and (icmp ne P, 0), (icmp ne (and ?, (ptrtoint P)), 0) --> icmp ne (and ?, (ptrtoint P)), 0
+
+define i1 @and_cmps_ptr_eq_zero_with_mask_commute4(i64* %p, i64 %y) {
+; CHECK-LABEL: @and_cmps_ptr_eq_zero_with_mask_commute4(
+; CHECK-NEXT:    [[X:%.*]] = ptrtoint i64* %p to i64
+; CHECK-NEXT:    [[SOMEBITS:%.*]] = and i64 %y, [[X]]
+; CHECK-NEXT:    [[SOMEBITS_ARE_NOT_ZERO:%.*]] = icmp ne i64 [[SOMEBITS]], 0
+; CHECK-NEXT:    ret i1 [[SOMEBITS_ARE_NOT_ZERO]]
+;
+  %isnotnull = icmp ne i64* %p, null
+  %x = ptrtoint i64* %p to i64
+  %somebits = and i64 %y, %x
+  %somebits_are_not_zero = icmp ne i64 %somebits, 0
+  %r = and i1 %isnotnull, %somebits_are_not_zero
+  ret i1 %r
+}
+

Added: llvm/trunk/test/Transforms/InstSimplify/assume.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstSimplify/assume.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstSimplify/assume.ll (added)
+++ llvm/trunk/test/Transforms/InstSimplify/assume.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,93 @@
+; NOTE: Assertions have been autogenerated by update_test_checks.py
+; RUN: opt -instsimplify -S < %s 2>&1 -pass-remarks-analysis=.* | FileCheck %s
+
+; Verify that warnings are emitted for the 2nd and 3rd tests.
+
+; CHECK: remark: /tmp/s.c:1:13: Detected conflicting code assumptions.
+; CHECK: remark: /tmp/s.c:4:10: Detected conflicting code assumptions.
+; CHECK: remark: /tmp/s.c:5:50: Detected conflicting code assumptions.
+
+define void @test1() {
+; CHECK-LABEL: @test1(
+; CHECK:         ret void
+;
+  call void @llvm.assume(i1 1)
+  ret void
+
+}
+
+; The alloca guarantees that the low bits of %a are zero because of alignment.
+; The assume says the opposite. The assume is processed last, so that's the 
+; return value. There's no way to win (we can't undo transforms that happened
+; based on half-truths), so just don't crash.
+
+define i64 @PR31809() !dbg !7 {
+; CHECK-LABEL: @PR31809(
+; CHECK-NEXT:    ret i64 3
+;
+  %a = alloca i32
+  %t1 = ptrtoint i32* %a to i64, !dbg !9
+  %cond = icmp eq i64 %t1, 3
+  call void @llvm.assume(i1 %cond)
+  ret i64 %t1
+}
+
+; Similar to above: there's no way to know which assumption is truthful,
+; so just don't crash. The second icmp+assume gets processed later, so that
+; determines the return value.
+
+define i8 @conflicting_assumptions(i8 %x) !dbg !10 {
+; CHECK-LABEL: @conflicting_assumptions(
+; CHECK-NEXT:    call void @llvm.assume(i1 false)
+; CHECK-NEXT:    [[COND2:%.*]] = icmp eq i8 %x, 4
+; CHECK-NEXT:    call void @llvm.assume(i1 [[COND2]])
+; CHECK-NEXT:    ret i8 5
+;
+  %add = add i8 %x, 1, !dbg !11
+  %cond1 = icmp eq i8 %x, 3
+  call void @llvm.assume(i1 %cond1)
+  %cond2 = icmp eq i8 %x, 4
+  call void @llvm.assume(i1 %cond2)
+  ret i8 %add
+}
+
+; Another case of conflicting assumptions. This would crash because we'd
+; try to set more known bits than existed in the known bits struct.
+
+define void @PR36270(i32 %b) !dbg !13 {
+; CHECK-LABEL: @PR36270(
+; CHECK-NEXT:    tail call void @llvm.assume(i1 false)
+; CHECK-NEXT:    unreachable
+;
+  %B7 = xor i32 -1, 2147483647
+  %and1 = and i32 %b, 3
+  %B12 = lshr i32 %B7, %and1, !dbg !14
+  %C1 = icmp ult i32 %and1, %B12
+  tail call void @llvm.assume(i1 %C1)
+  %cmp2 = icmp eq i32 0, %B12
+  tail call void @llvm.assume(i1 %cmp2)
+  unreachable
+}
+
+declare void @llvm.assume(i1) nounwind
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!3, !4, !5}
+!llvm.ident = !{!6}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 4.0.0 (trunk 282540) (llvm/trunk 282542)", isOptimized: true, runtimeVersion: 0, emissionKind: LineTablesOnly, enums: !2)
+!1 = !DIFile(filename: "/tmp/s.c", directory: "/tmp")
+!2 = !{}
+!3 = !{i32 2, !"Dwarf Version", i32 4}
+!4 = !{i32 2, !"Debug Info Version", i32 3}
+!5 = !{i32 1, !"PIC Level", i32 2}
+!6 = !{!"clang version 4.0.0 (trunk 282540) (llvm/trunk 282542)"}
+!7 = distinct !DISubprogram(name: "foo", scope: !1, file: !1, line: 1, type: !8, isLocal: false, isDefinition: true, scopeLine: 1, isOptimized: true, unit: !0, retainedNodes: !2)
+!8 = !DISubroutineType(types: !2)
+!9 = !DILocation(line: 1, column: 13, scope: !7)
+!10 = distinct !DISubprogram(name: "bar", scope: !1, file: !1, line: 3, type: !8, isLocal: false, isDefinition: true, scopeLine: 3, isOptimized: true, unit: !0, retainedNodes: !2)
+!11 = !DILocation(line: 4, column: 10, scope: !10)
+!12 = !DILocation(line: 4, column: 3, scope: !10)
+!13 = distinct !DISubprogram(name: "PR36270", scope: !1, file: !1, line: 3, type: !8, isLocal: false, isDefinition: true, scopeLine: 3, isOptimized: true, unit: !0, retainedNodes: !2)
+!14 = !DILocation(line: 5, column: 50, scope: !13)
+

Added: llvm/trunk/test/Transforms/InstSimplify/bitcast-vector-fold.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstSimplify/bitcast-vector-fold.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstSimplify/bitcast-vector-fold.ll (added)
+++ llvm/trunk/test/Transforms/InstSimplify/bitcast-vector-fold.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 -instsimplify -S | FileCheck %s
+target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-f64:32:64-v64:64:64-v128:128:128"
+
+define <2 x i64> @test1() {
+; CHECK-LABEL: @test1(
+; CHECK-NEXT:    ret <2 x i64> <i64 4294967296, i64 12884901890>
+;
+  %tmp3 = bitcast <4 x i32> < i32 0, i32 1, i32 2, i32 3 > to <2 x i64>
+  ret <2 x i64> %tmp3
+}
+
+define <4 x i32> @test2() {
+; CHECK-LABEL: @test2(
+; CHECK-NEXT:    ret <4 x i32> <i32 0, i32 0, i32 1, i32 0>
+;
+  %tmp3 = bitcast <2 x i64> < i64 0, i64 1 > to <4 x i32>
+  ret <4 x i32> %tmp3
+}
+
+define <2 x double> @test3() {
+; CHECK-LABEL: @test3(
+; CHECK-NEXT:    ret <2 x double> <double 0x100000000, double 0x300000002>
+;
+  %tmp3 = bitcast <4 x i32> < i32 0, i32 1, i32 2, i32 3 > to <2 x double>
+  ret <2 x double> %tmp3
+}
+
+define <4 x float> @test4() {
+; CHECK-LABEL: @test4(
+; CHECK-NEXT:    ret <4 x float> <float 0.000000e+00, float 0.000000e+00, float 0x36A0000000000000, float 0.000000e+00>
+;
+  %tmp3 = bitcast <2 x i64> < i64 0, i64 1 > to <4 x float>
+  ret <4 x float> %tmp3
+}
+
+define <2 x i64> @test5() {
+; CHECK-LABEL: @test5(
+; CHECK-NEXT:    ret <2 x i64> <i64 4575657221408423936, i64 4629700418010611712>
+;
+  %tmp3 = bitcast <4 x float> <float 0.0, float 1.0, float 2.0, float 3.0> to <2 x i64>
+  ret <2 x i64> %tmp3
+}
+
+define <4 x i32> @test6() {
+; CHECK-LABEL: @test6(
+; CHECK-NEXT:    ret <4 x i32> <i32 0, i32 1071644672, i32 0, i32 1072693248>
+;
+  %tmp3 = bitcast <2 x double> <double 0.5, double 1.0> to <4 x i32>
+  ret <4 x i32> %tmp3
+}
+
+define i32 @test7() {
+; CHECK-LABEL: @test7(
+; CHECK-NEXT:    ret i32 1118464
+;
+  %tmp3 = bitcast <2 x half> <half 0xH1100, half 0xH0011> to i32
+  ret i32 %tmp3
+}
+
+define <4 x i32> @test8(<1 x i64> %y) {
+; CHECK-LABEL: @test8(
+; CHECK-NEXT:    ret <4 x i32> zeroinitializer
+;
+  %c = bitcast <2 x i64> <i64 0, i64 0> to <4 x i32>
+  ret <4 x i32> %c
+}
+
+define <4 x i32> @test9(<1 x i64> %y) {
+; CHECK-LABEL: @test9(
+; CHECK-NEXT:    ret <4 x i32> <i32 -1, i32 -1, i32 -1, i32 -1>
+;
+  %c = bitcast <2 x i64> <i64 -1, i64 -1> to <4 x i32>
+  ret <4 x i32> %c
+}
+
+define <1 x i1> @test10() {
+; CHECK-LABEL: @test10(
+; CHECK-NEXT:    ret <1 x i1> <i1 icmp eq (i64 bitcast (<1 x double> <double 0xFFFFFFFFFFFFFFFF> to i64), i64 0)>
+;
+  %ret = icmp eq <1 x i64> <i64 bitcast (<1 x double> <double 0xFFFFFFFFFFFFFFFF> to i64)>, zeroinitializer
+  ret <1 x i1> %ret
+}
+
+; from MultiSource/Benchmarks/Bullet
+define <2 x float> @foo() {
+; CHECK-LABEL: @foo(
+; CHECK-NEXT:    ret <2 x float> <float 0xFFFFFFFFE0000000, float 0xFFFFFFFFE0000000>
+;
+  %cast = bitcast i64 -1 to <2 x float>
+  ret <2 x float> %cast
+}
+
+
+define <2 x double> @foo2() {
+; CHECK-LABEL: @foo2(
+; CHECK-NEXT:    ret <2 x double> <double 0xFFFFFFFFFFFFFFFF, double 0xFFFFFFFFFFFFFFFF>
+;
+  %cast = bitcast i128 -1 to <2 x double>
+  ret <2 x double> %cast
+}
+
+define <1 x float> @foo3() {
+; CHECK-LABEL: @foo3(
+; CHECK-NEXT:    ret <1 x float> <float 0xFFFFFFFFE0000000>
+;
+  %cast = bitcast i32 -1 to <1 x float>
+  ret <1 x float> %cast
+}
+
+define float @foo4() {
+; CHECK-LABEL: @foo4(
+; CHECK-NEXT:    ret float 0xFFFFFFFFE0000000
+;
+  %cast = bitcast <1 x i32 ><i32 -1> to float
+  ret float %cast
+}
+
+define double @foo5() {
+; CHECK-LABEL: @foo5(
+; CHECK-NEXT:    ret double 0xFFFFFFFFFFFFFFFF
+;
+  %cast = bitcast <2 x i32 ><i32 -1, i32 -1> to double
+  ret double %cast
+}
+
+define <2 x double> @foo6() {
+; CHECK-LABEL: @foo6(
+; CHECK-NEXT:    ret <2 x double> <double 0xFFFFFFFFFFFFFFFF, double 0xFFFFFFFFFFFFFFFF>
+;
+  %cast = bitcast <4 x i32><i32 -1, i32 -1, i32 -1, i32 -1> to <2 x double>
+  ret <2 x double> %cast
+}
+
+define <4 x i32> @bitcast_constexpr_4i32_2i64_u2() {
+; CHECK-LABEL: @bitcast_constexpr_4i32_2i64_u2(
+; CHECK-NEXT:    ret <4 x i32> <i32 undef, i32 undef, i32 2, i32 0>
+;
+  %cast = bitcast <2 x i64><i64 undef, i64 2> to <4 x i32>
+  ret <4 x i32> %cast
+}
+
+define <4 x i32> @bitcast_constexpr_4i32_2i64_1u() {
+; CHECK-LABEL: @bitcast_constexpr_4i32_2i64_1u(
+; CHECK-NEXT:    ret <4 x i32> <i32 1, i32 0, i32 undef, i32 undef>
+;
+  %cast = bitcast <2 x i64><i64 1, i64 undef> to <4 x i32>
+  ret <4 x i32> %cast
+}
+
+define <4 x i32> @bitcast_constexpr_4i32_2i64() {
+; CHECK-LABEL: @bitcast_constexpr_4i32_2i64(
+; CHECK-NEXT:    ret <4 x i32> <i32 undef, i32 undef, i32 2, i32 0>
+;
+  %cast = bitcast <2 x i64><i64 undef, i64 2> to <4 x i32>
+  ret <4 x i32> %cast
+}
+
+define <8 x i16> @bitcast_constexpr_8i16_2i64_u2() {
+; CHECK-LABEL: @bitcast_constexpr_8i16_2i64_u2(
+; CHECK-NEXT:    ret <8 x i16> <i16 undef, i16 undef, i16 undef, i16 undef, i16 2, i16 0, i16 0, i16 0>
+;
+  %cast = bitcast <2 x i64><i64 undef, i64 2> to <8 x i16>
+  ret <8 x i16> %cast
+}
+
+define <8 x i16> @bitcast_constexpr_8i16_2i64_1u() {
+; CHECK-LABEL: @bitcast_constexpr_8i16_2i64_1u(
+; CHECK-NEXT:    ret <8 x i16> <i16 1, i16 0, i16 0, i16 0, i16 undef, i16 undef, i16 undef, i16 undef>
+;
+  %cast = bitcast <2 x i64><i64 1, i64 undef> to <8 x i16>
+  ret <8 x i16> %cast
+}
+
+define <8 x i16> @bitcast_constexpr_8i16_2i64_u65536() {
+; CHECK-LABEL: @bitcast_constexpr_8i16_2i64_u65536(
+; CHECK-NEXT:    ret <8 x i16> <i16 undef, i16 undef, i16 undef, i16 undef, i16 0, i16 1, i16 0, i16 0>
+;
+  %cast = bitcast <2 x i64><i64 undef, i64 65536> to <8 x i16>
+  ret <8 x i16> %cast
+}
+
+define <16 x i8> @bitcast_constexpr_16i8_2i64_u2() {
+; CHECK-LABEL: @bitcast_constexpr_16i8_2i64_u2(
+; CHECK-NEXT:    ret <16 x i8> <i8 undef, i8 undef, i8 undef, i8 undef, i8 undef, i8 undef, i8 undef, i8 undef, i8 2, i8 0, i8 0, i8 0, i8 0, i8 0, i8 0, i8 0>
+;
+  %cast = bitcast <2 x i64><i64 undef, i64 2> to <16 x i8>
+  ret <16 x i8> %cast
+}
+
+define <16 x i8> @bitcast_constexpr_16i8_2i64_256u() {
+; CHECK-LABEL: @bitcast_constexpr_16i8_2i64_256u(
+; CHECK-NEXT:    ret <16 x i8> <i8 0, i8 1, i8 0, i8 0, i8 0, i8 0, i8 0, i8 0, i8 undef, i8 undef, i8 undef, i8 undef, i8 undef, i8 undef, i8 undef, i8 undef>
+;
+  %cast = bitcast <2 x i64><i64 256, i64 undef> to <16 x i8>
+  ret <16 x i8> %cast
+}
+
+define <16 x i8> @bitcast_constexpr_16i8_2i64_u256() {
+; CHECK-LABEL: @bitcast_constexpr_16i8_2i64_u256(
+; CHECK-NEXT:    ret <16 x i8> <i8 undef, i8 undef, i8 undef, i8 undef, i8 undef, i8 undef, i8 undef, i8 undef, i8 0, i8 1, i8 0, i8 0, i8 0, i8 0, i8 0, i8 0>
+;
+  %cast = bitcast <2 x i64><i64 undef, i64 256> to <16 x i8>
+  ret <16 x i8> %cast
+}
+
+define <8 x i16> @bitcast_constexpr_8i16_4i32_uu22() {
+; CHECK-LABEL: @bitcast_constexpr_8i16_4i32_uu22(
+; CHECK-NEXT:    ret <8 x i16> <i16 undef, i16 undef, i16 undef, i16 undef, i16 2, i16 0, i16 2, i16 0>
+;
+  %cast = bitcast <4 x i32><i32 undef, i32 undef, i32 2, i32 2> to <8 x i16>
+  ret <8 x i16> %cast
+}
+
+define <8 x i16> @bitcast_constexpr_8i16_4i32_10uu() {
+; CHECK-LABEL: @bitcast_constexpr_8i16_4i32_10uu(
+; CHECK-NEXT:    ret <8 x i16> <i16 1, i16 0, i16 0, i16 0, i16 undef, i16 undef, i16 undef, i16 undef>
+;
+  %cast = bitcast <4 x i32><i32 1, i32 0, i32 undef, i32 undef> to <8 x i16>
+  ret <8 x i16> %cast
+}
+
+define <8 x i16> @bitcast_constexpr_8i16_4i32_u257u256() {
+; CHECK-LABEL: @bitcast_constexpr_8i16_4i32_u257u256(
+; CHECK-NEXT:    ret <8 x i16> <i16 undef, i16 undef, i16 0, i16 1, i16 undef, i16 undef, i16 0, i16 1>
+;
+  %cast = bitcast <4 x i32><i32 undef, i32 65536, i32 undef, i32 65536> to <8 x i16>
+  ret <8 x i16> %cast
+}
+
+define <16 x i8> @bitcast_constexpr_16i8_4i32_u2u2() {
+; CHECK-LABEL: @bitcast_constexpr_16i8_4i32_u2u2(
+; CHECK-NEXT:    ret <16 x i8> <i8 undef, i8 undef, i8 undef, i8 undef, i8 2, i8 0, i8 0, i8 0, i8 undef, i8 undef, i8 undef, i8 undef, i8 2, i8 0, i8 0, i8 0>
+;
+  %cast = bitcast <4 x i32><i32 undef, i32 2, i32 undef, i32 2> to <16 x i8>
+  ret <16 x i8> %cast
+}
+
+define <16 x i8> @bitcast_constexpr_16i8_4i32_1u1u() {
+; CHECK-LABEL: @bitcast_constexpr_16i8_4i32_1u1u(
+; CHECK-NEXT:    ret <16 x i8> <i8 1, i8 0, i8 0, i8 0, i8 undef, i8 undef, i8 undef, i8 undef, i8 1, i8 0, i8 0, i8 0, i8 undef, i8 undef, i8 undef, i8 undef>
+;
+  %cast = bitcast <4 x i32><i32 1, i32 undef, i32 1, i32 undef> to <16 x i8>
+  ret <16 x i8> %cast
+}
+
+define <16 x i8> @bitcast_constexpr_16i8_4i32_u256uu() {
+; CHECK-LABEL: @bitcast_constexpr_16i8_4i32_u256uu(
+; CHECK-NEXT:    ret <16 x i8> <i8 undef, i8 undef, i8 undef, i8 undef, i8 0, i8 1, i8 0, i8 0, i8 undef, i8 undef, i8 undef, i8 undef, i8 undef, i8 undef, i8 undef, i8 undef>
+;
+  %cast = bitcast <4 x i32><i32 undef, i32 256, i32 undef, i32 undef> to <16 x i8>
+  ret <16 x i8> %cast
+}
+
+define <16 x i8> @bitcast_constexpr_16i8_8i16_u2u2u2u2() {
+; CHECK-LABEL: @bitcast_constexpr_16i8_8i16_u2u2u2u2(
+; CHECK-NEXT:    ret <16 x i8> <i8 undef, i8 undef, i8 2, i8 0, i8 undef, i8 undef, i8 2, i8 0, i8 undef, i8 undef, i8 2, i8 0, i8 undef, i8 undef, i8 2, i8 0>
+;
+  %cast = bitcast <8 x i16><i16 undef, i16 2, i16 undef, i16 2, i16 undef, i16 2, i16 undef, i16 2> to <16 x i8>
+  ret <16 x i8> %cast
+}
+
+define <16 x i8> @bitcast_constexpr_16i8_8i16_1u1u1u1u() {
+; CHECK-LABEL: @bitcast_constexpr_16i8_8i16_1u1u1u1u(
+; CHECK-NEXT:    ret <16 x i8> <i8 1, i8 0, i8 undef, i8 undef, i8 1, i8 0, i8 undef, i8 undef, i8 1, i8 0, i8 undef, i8 undef, i8 1, i8 0, i8 undef, i8 undef>
+;
+  %cast = bitcast <8 x i16><i16 1, i16 undef, i16 1, i16 undef, i16 1, i16 undef, i16 1, i16 undef> to <16 x i8>
+  ret <16 x i8> %cast
+}
+
+define <16 x i8> @bitcast_constexpr_16i8_8i16_u256uuu256uu() {
+; CHECK-LABEL: @bitcast_constexpr_16i8_8i16_u256uuu256uu(
+; CHECK-NEXT:    ret <16 x i8> <i8 undef, i8 undef, i8 0, i8 1, i8 undef, i8 undef, i8 undef, i8 undef, i8 undef, i8 undef, i8 0, i8 1, i8 undef, i8 undef, i8 undef, i8 undef>
+;
+  %cast = bitcast <8 x i16><i16 undef, i16 256, i16 undef, i16 undef, i16 undef, i16 256, i16 undef, i16 undef> to <16 x i8>
+  ret <16 x i8> %cast
+}

Added: llvm/trunk/test/Transforms/InstSimplify/bitreverse-fold.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstSimplify/bitreverse-fold.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstSimplify/bitreverse-fold.ll (added)
+++ llvm/trunk/test/Transforms/InstSimplify/bitreverse-fold.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,110 @@
+; RUN: opt < %s -instsimplify -S | FileCheck %s
+
+define i32 @identity_bitreverse_i32(i32 %p) {
+; CHECK-LABEL: @identity_bitreverse_i32(
+; CHECK-NEXT: ret i32 %p
+  %a = call i32 @llvm.bitreverse.i32(i32 %p)
+  %b = call i32 @llvm.bitreverse.i32(i32 %a)
+  ret i32 %b
+}
+
+; CHECK-LABEL: @identity_bitreverse_v2i32(
+; CHECK-NEXT: ret <2 x i32> %p
+define <2 x i32> @identity_bitreverse_v2i32(<2 x i32> %p) {
+  %a = call <2 x i32> @llvm.bitreverse.v2i32(<2 x i32> %p)
+  %b = call <2 x i32> @llvm.bitreverse.v2i32(<2 x i32> %a)
+  ret <2 x i32> %b
+}
+
+; CHECK-LABEL: @reverse_0_i32(
+; CHECK-NEXT: ret i32 0
+define i32 @reverse_0_i32() {
+  %x = call i32 @llvm.bitreverse.i32(i32 0)
+  ret i32 %x
+}
+
+; CHECK-LABEL: @reverse_1_i32(
+; CHECK-NEXT: ret i32 -2147483648
+define i32 @reverse_1_i32() {
+  %x = call i32 @llvm.bitreverse.i32(i32 1)
+  ret i32 %x
+}
+
+; CHECK-LABEL: @reverse_neg1_i32(
+; CHECK-NEXT: ret i32 -1
+define i32 @reverse_neg1_i32() {
+  %x = call i32 @llvm.bitreverse.i32(i32 -1)
+  ret i32 %x
+}
+
+; CHECK-LABEL: @reverse_undef_i32(
+; CHECK-NEXT: ret i32 undef
+define i32 @reverse_undef_i32() {
+  %x = call i32 @llvm.bitreverse.i32(i32 undef)
+  ret i32 %x
+}
+
+; CHECK-LABEL: @reverse_false_i1(
+; CHECK-NEXT: ret i1 false
+define i1 @reverse_false_i1() {
+  %x = call i1 @llvm.bitreverse.i1(i1 false)
+  ret i1 %x
+}
+
+; CHECK-LABEL: @reverse_true_i1(
+; CHECK-NEXT: ret i1 true
+define i1 @reverse_true_i1() {
+  %x = call i1 @llvm.bitreverse.i1(i1 true)
+  ret i1 %x
+}
+
+; CHECK-LABEL: @reverse_undef_i1(
+; CHECK-NEXT: ret i1 undef
+define i1 @reverse_undef_i1() {
+  %x = call i1 @llvm.bitreverse.i1(i1 undef)
+  ret i1 %x
+}
+
+; CHECK-LABEL: @reverse_false_v2i1(
+; CHECK-NEXT: ret <2 x i1> zeroinitializer
+define <2 x i1> @reverse_false_v2i1() {
+  %x = call <2  x i1> @llvm.bitreverse.v2i1(<2 x i1> zeroinitializer)
+  ret <2 x i1> %x
+}
+
+; CHECK-LABEL: @reverse_true_v2i1(
+; CHECK-NEXT: ret <2 x i1> <i1 true, i1 true>
+define <2 x i1> @reverse_true_v2i1() {
+  %x = call <2 x i1> @llvm.bitreverse.v2i1(<2 x i1> <i1 true, i1 true>)
+  ret <2 x i1> %x
+}
+
+; CHECK-LABEL: @bitreverse_920_1234_v2i32(
+; CHECK-NEXT: ret <2 x i32> <i32 432013312, i32 1260388352>
+define <2 x i32> @bitreverse_920_1234_v2i32() {
+  %x = call <2 x i32> @llvm.bitreverse.v2i32(<2 x i32> <i32 920, i32 1234>)
+  ret <2 x i32> %x
+}
+
+; CHECK-LABEL: @reverse_100_i3(
+; CHECK-NEXT: ret i3 1
+define i3 @reverse_100_i3() {
+  %x = call i3 @llvm.bitreverse.i3(i3 100)
+  ret i3 %x
+}
+
+; CHECK-LABEL: @reverse_6_3_v2i3(
+; CHECK-NEXT: ret <2 x i3> <i3 3, i3 -2>
+define <2 x i3> @reverse_6_3_v2i3() {
+  %x = call <2  x i3> @llvm.bitreverse.v2i3(<2 x i3> <i3 6, i3 3>)
+  ret <2 x i3> %x
+}
+
+declare i1 @llvm.bitreverse.i1(i1) readnone
+declare <2 x i1> @llvm.bitreverse.v2i1(<2 x i1>) readnone
+
+declare i3 @llvm.bitreverse.i3(i3) readnone
+declare <2 x i3> @llvm.bitreverse.v2i3(<2 x i3>) readnone
+
+declare i32 @llvm.bitreverse.i32(i32) readnone
+declare <2 x i32> @llvm.bitreverse.v2i32(<2 x i32>) readnone

Added: llvm/trunk/test/Transforms/InstSimplify/bitreverse.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstSimplify/bitreverse.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstSimplify/bitreverse.ll (added)
+++ llvm/trunk/test/Transforms/InstSimplify/bitreverse.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,31 @@
+; RUN: opt < %s -S -instsimplify | FileCheck %s
+
+declare i32 @llvm.bitreverse.i32(i32)
+
+; CHECK-LABEL: @test1(
+; CHECK: ret i1 false
+define i1 @test1(i32 %arg) {
+  %a = or i32 %arg, 1
+  %b = call i32 @llvm.bitreverse.i32(i32 %a)
+  %res = icmp eq i32 %b, 0
+  ret i1 %res
+}
+
+; CHECK-LABEL: @test2(
+; CHECK: ret i1 false
+define i1 @test2(i32 %arg) {
+  %a = or i32 %arg, 1024
+  %b = call i32 @llvm.bitreverse.i32(i32 %a)
+  %res = icmp eq i32 %b, 0
+  ret i1 %res
+}
+
+; CHECK-LABEL: @test3(
+; CHECK: ret i1 false
+define i1 @test3(i32 %arg) {
+  %a = and i32 %arg, 1
+  %b = call i32 @llvm.bitreverse.i32(i32 %a)
+  %and = and i32 %b, 1
+  %res = icmp eq i32 %and, 1
+  ret i1 %res
+}

Added: llvm/trunk/test/Transforms/InstSimplify/bswap.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstSimplify/bswap.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstSimplify/bswap.ll (added)
+++ llvm/trunk/test/Transforms/InstSimplify/bswap.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,46 @@
+; NOTE: Assertions have been autogenerated by update_test_checks.py
+; RUN: opt < %s -S -instsimplify | FileCheck %s
+
+declare i16 @llvm.bswap.i16(i16)
+
+define i1 @test1(i16 %arg) {
+; CHECK-LABEL: @test1(
+; CHECK:         ret i1 false
+;
+  %a = or i16 %arg, 1
+  %b = call i16 @llvm.bswap.i16(i16 %a)
+  %res = icmp eq i16 %b, 0
+  ret i1 %res
+}
+
+define i1 @test2(i16 %arg) {
+; CHECK-LABEL: @test2(
+; CHECK:         ret i1 false
+;
+  %a = or i16 %arg, 1024
+  %b = call i16 @llvm.bswap.i16(i16 %a)
+  %res = icmp eq i16 %b, 0
+  ret i1 %res
+}
+
+define i1 @test3(i16 %arg) {
+; CHECK-LABEL: @test3(
+; CHECK:         ret i1 false
+;
+  %a = and i16 %arg, 1
+  %b = call i16 @llvm.bswap.i16(i16 %a)
+  %and = and i16 %b, 1
+  %res = icmp eq i16 %and, 1
+  ret i1 %res
+}
+
+define i1 @test4(i16 %arg) {
+; CHECK-LABEL: @test4(
+; CHECK:         ret i1 false
+;
+  %a = and i16 %arg, 511
+  %b = call i16 @llvm.bswap.i16(i16 %a)
+  %and = and i16 %b, 256
+  %res = icmp eq i16 %and, 1
+  ret i1 %res
+}

Added: llvm/trunk/test/Transforms/InstSimplify/call.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstSimplify/call.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstSimplify/call.ll (added)
+++ llvm/trunk/test/Transforms/InstSimplify/call.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,744 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt < %s -instsimplify -S | FileCheck %s
+; RUN: opt < %s -passes=instsimplify -S | FileCheck %s
+
+declare {i8, i1} @llvm.uadd.with.overflow.i8(i8 %a, i8 %b)
+declare {i8, i1} @llvm.sadd.with.overflow.i8(i8 %a, i8 %b)
+declare {i8, i1} @llvm.usub.with.overflow.i8(i8 %a, i8 %b)
+declare {i8, i1} @llvm.ssub.with.overflow.i8(i8 %a, i8 %b)
+declare {i8, i1} @llvm.umul.with.overflow.i8(i8 %a, i8 %b)
+declare {i8, i1} @llvm.smul.with.overflow.i8(i8 %a, i8 %b)
+
+define i1 @test_uadd1() {
+; CHECK-LABEL: @test_uadd1(
+; CHECK-NEXT:    ret i1 true
+;
+  %x = call {i8, i1} @llvm.uadd.with.overflow.i8(i8 254, i8 3)
+  %overflow = extractvalue {i8, i1} %x, 1
+  ret i1 %overflow
+}
+
+define i8 @test_uadd2() {
+; CHECK-LABEL: @test_uadd2(
+; CHECK-NEXT:    ret i8 42
+;
+  %x = call {i8, i1} @llvm.uadd.with.overflow.i8(i8 254, i8 44)
+  %result = extractvalue {i8, i1} %x, 0
+  ret i8 %result
+}
+
+define {i8, i1} @test_uadd3(i8 %v) {
+; CHECK-LABEL: @test_uadd3(
+; CHECK-NEXT:    ret { i8, i1 } undef
+;
+  %result = call {i8, i1} @llvm.uadd.with.overflow.i8(i8 %v, i8 undef)
+  ret {i8, i1} %result
+}
+
+define {i8, i1} @test_uadd4(i8 %v) {
+; CHECK-LABEL: @test_uadd4(
+; CHECK-NEXT:    ret { i8, i1 } undef
+;
+  %result = call {i8, i1} @llvm.uadd.with.overflow.i8(i8 undef, i8 %v)
+  ret {i8, i1} %result
+}
+
+define i1 @test_sadd1() {
+; CHECK-LABEL: @test_sadd1(
+; CHECK-NEXT:    ret i1 true
+;
+  %x = call {i8, i1} @llvm.sadd.with.overflow.i8(i8 126, i8 3)
+  %overflow = extractvalue {i8, i1} %x, 1
+  ret i1 %overflow
+}
+
+define i8 @test_sadd2() {
+; CHECK-LABEL: @test_sadd2(
+; CHECK-NEXT:    ret i8 -86
+;
+  %x = call {i8, i1} @llvm.sadd.with.overflow.i8(i8 126, i8 44)
+  %result = extractvalue {i8, i1} %x, 0
+  ret i8 %result
+}
+
+define {i8, i1} @test_sadd3(i8 %v) {
+; CHECK-LABEL: @test_sadd3(
+; CHECK-NEXT:    ret { i8, i1 } undef
+;
+  %result = call {i8, i1} @llvm.sadd.with.overflow.i8(i8 %v, i8 undef)
+  ret {i8, i1} %result
+}
+
+define {i8, i1} @test_sadd4(i8 %v) {
+; CHECK-LABEL: @test_sadd4(
+; CHECK-NEXT:    ret { i8, i1 } undef
+;
+  %result = call {i8, i1} @llvm.sadd.with.overflow.i8(i8 undef, i8 %v)
+  ret {i8, i1} %result
+}
+
+define {i8, i1} @test_usub1(i8 %V) {
+; CHECK-LABEL: @test_usub1(
+; CHECK-NEXT:    ret { i8, i1 } zeroinitializer
+;
+  %x = call {i8, i1} @llvm.usub.with.overflow.i8(i8 %V, i8 %V)
+  ret {i8, i1} %x
+}
+
+define {i8, i1} @test_usub2(i8 %V) {
+; CHECK-LABEL: @test_usub2(
+; CHECK-NEXT:    ret { i8, i1 } undef
+;
+  %x = call {i8, i1} @llvm.usub.with.overflow.i8(i8 %V, i8 undef)
+  ret {i8, i1} %x
+}
+
+define {i8, i1} @test_usub3(i8 %V) {
+; CHECK-LABEL: @test_usub3(
+; CHECK-NEXT:    ret { i8, i1 } undef
+;
+  %x = call {i8, i1} @llvm.usub.with.overflow.i8(i8 undef, i8 %V)
+  ret {i8, i1} %x
+}
+
+define {i8, i1} @test_ssub1(i8 %V) {
+; CHECK-LABEL: @test_ssub1(
+; CHECK-NEXT:    ret { i8, i1 } zeroinitializer
+;
+  %x = call {i8, i1} @llvm.ssub.with.overflow.i8(i8 %V, i8 %V)
+  ret {i8, i1} %x
+}
+
+define {i8, i1} @test_ssub2(i8 %V) {
+; CHECK-LABEL: @test_ssub2(
+; CHECK-NEXT:    ret { i8, i1 } undef
+;
+  %x = call {i8, i1} @llvm.ssub.with.overflow.i8(i8 %V, i8 undef)
+  ret {i8, i1} %x
+}
+
+define {i8, i1} @test_ssub3(i8 %V) {
+; CHECK-LABEL: @test_ssub3(
+; CHECK-NEXT:    ret { i8, i1 } undef
+;
+  %x = call {i8, i1} @llvm.ssub.with.overflow.i8(i8 undef, i8 %V)
+  ret {i8, i1} %x
+}
+
+define {i8, i1} @test_umul1(i8 %V) {
+; CHECK-LABEL: @test_umul1(
+; CHECK-NEXT:    ret { i8, i1 } zeroinitializer
+;
+  %x = call {i8, i1} @llvm.umul.with.overflow.i8(i8 %V, i8 0)
+  ret {i8, i1} %x
+}
+
+define {i8, i1} @test_umul2(i8 %V) {
+; CHECK-LABEL: @test_umul2(
+; CHECK-NEXT:    ret { i8, i1 } zeroinitializer
+;
+  %x = call {i8, i1} @llvm.umul.with.overflow.i8(i8 %V, i8 undef)
+  ret {i8, i1} %x
+}
+
+define {i8, i1} @test_umul3(i8 %V) {
+; CHECK-LABEL: @test_umul3(
+; CHECK-NEXT:    ret { i8, i1 } zeroinitializer
+;
+  %x = call {i8, i1} @llvm.umul.with.overflow.i8(i8 0, i8 %V)
+  ret {i8, i1} %x
+}
+
+define {i8, i1} @test_umul4(i8 %V) {
+; CHECK-LABEL: @test_umul4(
+; CHECK-NEXT:    ret { i8, i1 } zeroinitializer
+;
+  %x = call {i8, i1} @llvm.umul.with.overflow.i8(i8 undef, i8 %V)
+  ret {i8, i1} %x
+}
+
+define {i8, i1} @test_smul1(i8 %V) {
+; CHECK-LABEL: @test_smul1(
+; CHECK-NEXT:    ret { i8, i1 } zeroinitializer
+;
+  %x = call {i8, i1} @llvm.smul.with.overflow.i8(i8 %V, i8 0)
+  ret {i8, i1} %x
+}
+
+define {i8, i1} @test_smul2(i8 %V) {
+; CHECK-LABEL: @test_smul2(
+; CHECK-NEXT:    ret { i8, i1 } zeroinitializer
+;
+  %x = call {i8, i1} @llvm.smul.with.overflow.i8(i8 %V, i8 undef)
+  ret {i8, i1} %x
+}
+
+define {i8, i1} @test_smul3(i8 %V) {
+; CHECK-LABEL: @test_smul3(
+; CHECK-NEXT:    ret { i8, i1 } zeroinitializer
+;
+  %x = call {i8, i1} @llvm.smul.with.overflow.i8(i8 0, i8 %V)
+  ret {i8, i1} %x
+}
+
+define {i8, i1} @test_smul4(i8 %V) {
+; CHECK-LABEL: @test_smul4(
+; CHECK-NEXT:    ret { i8, i1 } zeroinitializer
+;
+  %x = call {i8, i1} @llvm.smul.with.overflow.i8(i8 undef, i8 %V)
+  ret {i8, i1} %x
+}
+
+; Test a non-intrinsic that we know about as a library call.
+declare float @fabs(float %x)
+
+define float @test_fabs_libcall() {
+; CHECK-LABEL: @test_fabs_libcall(
+; CHECK-NEXT:    [[X:%.*]] = call float @fabs(float -4.200000e+01)
+; CHECK-NEXT:    ret float 4.200000e+01
+;
+
+  %x = call float @fabs(float -42.0)
+; This is still a real function call, so instsimplify won't nuke it -- other
+; passes have to do that.
+
+  ret float %x
+}
+
+
+declare float @llvm.fabs.f32(float) nounwind readnone
+declare float @llvm.floor.f32(float) nounwind readnone
+declare float @llvm.ceil.f32(float) nounwind readnone
+declare float @llvm.trunc.f32(float) nounwind readnone
+declare float @llvm.rint.f32(float) nounwind readnone
+declare float @llvm.nearbyint.f32(float) nounwind readnone
+declare float @llvm.canonicalize.f32(float) nounwind readnone
+
+; Test idempotent intrinsics
+define float @test_idempotence(float %a) {
+; CHECK-LABEL: @test_idempotence(
+; CHECK-NEXT:    [[A0:%.*]] = call float @llvm.fabs.f32(float [[A:%.*]])
+; CHECK-NEXT:    [[B0:%.*]] = call float @llvm.floor.f32(float [[A]])
+; CHECK-NEXT:    [[C0:%.*]] = call float @llvm.ceil.f32(float [[A]])
+; CHECK-NEXT:    [[D0:%.*]] = call float @llvm.trunc.f32(float [[A]])
+; CHECK-NEXT:    [[E0:%.*]] = call float @llvm.rint.f32(float [[A]])
+; CHECK-NEXT:    [[F0:%.*]] = call float @llvm.nearbyint.f32(float [[A]])
+; CHECK-NEXT:    [[G0:%.*]] = call float @llvm.canonicalize.f32(float [[A]])
+; CHECK-NEXT:    [[R0:%.*]] = fadd float [[A0]], [[B0]]
+; CHECK-NEXT:    [[R1:%.*]] = fadd float [[R0]], [[C0]]
+; CHECK-NEXT:    [[R2:%.*]] = fadd float [[R1]], [[D0]]
+; CHECK-NEXT:    [[R3:%.*]] = fadd float [[R2]], [[E0]]
+; CHECK-NEXT:    [[R4:%.*]] = fadd float [[R3]], [[F0]]
+; CHECK-NEXT:    [[R5:%.*]] = fadd float [[R4]], [[G0]]
+; CHECK-NEXT:    ret float [[R5]]
+;
+
+  %a0 = call float @llvm.fabs.f32(float %a)
+  %a1 = call float @llvm.fabs.f32(float %a0)
+
+  %b0 = call float @llvm.floor.f32(float %a)
+  %b1 = call float @llvm.floor.f32(float %b0)
+
+  %c0 = call float @llvm.ceil.f32(float %a)
+  %c1 = call float @llvm.ceil.f32(float %c0)
+
+  %d0 = call float @llvm.trunc.f32(float %a)
+  %d1 = call float @llvm.trunc.f32(float %d0)
+
+  %e0 = call float @llvm.rint.f32(float %a)
+  %e1 = call float @llvm.rint.f32(float %e0)
+
+  %f0 = call float @llvm.nearbyint.f32(float %a)
+  %f1 = call float @llvm.nearbyint.f32(float %f0)
+
+  %g0 = call float @llvm.canonicalize.f32(float %a)
+  %g1 = call float @llvm.canonicalize.f32(float %g0)
+
+  %r0 = fadd float %a1, %b1
+  %r1 = fadd float %r0, %c1
+  %r2 = fadd float %r1, %d1
+  %r3 = fadd float %r2, %e1
+  %r4 = fadd float %r3, %f1
+  %r5 = fadd float %r4, %g1
+
+  ret float %r5
+}
+
+define i8* @operator_new() {
+; CHECK-LABEL: @operator_new(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[CALL:%.*]] = tail call noalias i8* @_Znwm(i64 8)
+; CHECK-NEXT:    br i1 false, label [[CAST_END:%.*]], label [[CAST_NOTNULL:%.*]]
+; CHECK:       cast.notnull:
+; CHECK-NEXT:    [[ADD_PTR:%.*]] = getelementptr inbounds i8, i8* [[CALL]], i64 4
+; CHECK-NEXT:    br label [[CAST_END]]
+; CHECK:       cast.end:
+; CHECK-NEXT:    [[CAST_RESULT:%.*]] = phi i8* [ [[ADD_PTR]], [[CAST_NOTNULL]] ], [ null, [[ENTRY:%.*]] ]
+; CHECK-NEXT:    ret i8* [[CAST_RESULT]]
+;
+entry:
+  %call = tail call noalias i8* @_Znwm(i64 8)
+  %cmp = icmp eq i8* %call, null
+  br i1 %cmp, label %cast.end, label %cast.notnull
+
+cast.notnull:                                     ; preds = %entry
+  %add.ptr = getelementptr inbounds i8, i8* %call, i64 4
+  br label %cast.end
+
+cast.end:                                         ; preds = %cast.notnull, %entry
+  %cast.result = phi i8* [ %add.ptr, %cast.notnull ], [ null, %entry ]
+  ret i8* %cast.result
+
+}
+
+declare nonnull noalias i8* @_Znwm(i64)
+
+%"struct.std::nothrow_t" = type { i8 }
+ at _ZSt7nothrow = external global %"struct.std::nothrow_t"
+
+define i8* @operator_new_nothrow_t() {
+; CHECK-LABEL: @operator_new_nothrow_t(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[CALL:%.*]] = tail call noalias i8* @_ZnamRKSt9nothrow_t(i64 8, %"struct.std::nothrow_t"* @_ZSt7nothrow)
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i8* [[CALL]], null
+; CHECK-NEXT:    br i1 [[CMP]], label [[CAST_END:%.*]], label [[CAST_NOTNULL:%.*]]
+; CHECK:       cast.notnull:
+; CHECK-NEXT:    [[ADD_PTR:%.*]] = getelementptr inbounds i8, i8* [[CALL]], i64 4
+; CHECK-NEXT:    br label [[CAST_END]]
+; CHECK:       cast.end:
+; CHECK-NEXT:    [[CAST_RESULT:%.*]] = phi i8* [ [[ADD_PTR]], [[CAST_NOTNULL]] ], [ null, [[ENTRY:%.*]] ]
+; CHECK-NEXT:    ret i8* [[CAST_RESULT]]
+;
+entry:
+  %call = tail call noalias i8* @_ZnamRKSt9nothrow_t(i64 8, %"struct.std::nothrow_t"* @_ZSt7nothrow)
+  %cmp = icmp eq i8* %call, null
+  br i1 %cmp, label %cast.end, label %cast.notnull
+
+cast.notnull:                                     ; preds = %entry
+  %add.ptr = getelementptr inbounds i8, i8* %call, i64 4
+  br label %cast.end
+
+cast.end:                                         ; preds = %cast.notnull, %entry
+  %cast.result = phi i8* [ %add.ptr, %cast.notnull ], [ null, %entry ]
+  ret i8* %cast.result
+
+}
+
+declare i8* @_ZnamRKSt9nothrow_t(i64, %"struct.std::nothrow_t"*) nounwind
+
+define i8* @malloc_can_return_null() {
+; CHECK-LABEL: @malloc_can_return_null(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[CALL:%.*]] = tail call noalias i8* @malloc(i64 8)
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i8* [[CALL]], null
+; CHECK-NEXT:    br i1 [[CMP]], label [[CAST_END:%.*]], label [[CAST_NOTNULL:%.*]]
+; CHECK:       cast.notnull:
+; CHECK-NEXT:    [[ADD_PTR:%.*]] = getelementptr inbounds i8, i8* [[CALL]], i64 4
+; CHECK-NEXT:    br label [[CAST_END]]
+; CHECK:       cast.end:
+; CHECK-NEXT:    [[CAST_RESULT:%.*]] = phi i8* [ [[ADD_PTR]], [[CAST_NOTNULL]] ], [ null, [[ENTRY:%.*]] ]
+; CHECK-NEXT:    ret i8* [[CAST_RESULT]]
+;
+entry:
+  %call = tail call noalias i8* @malloc(i64 8)
+  %cmp = icmp eq i8* %call, null
+  br i1 %cmp, label %cast.end, label %cast.notnull
+
+cast.notnull:                                     ; preds = %entry
+  %add.ptr = getelementptr inbounds i8, i8* %call, i64 4
+  br label %cast.end
+
+cast.end:                                         ; preds = %cast.notnull, %entry
+  %cast.result = phi i8* [ %add.ptr, %cast.notnull ], [ null, %entry ]
+  ret i8* %cast.result
+
+}
+
+define i32 @call_null() {
+; CHECK-LABEL: @call_null(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[CALL:%.*]] = call i32 null()
+; CHECK-NEXT:    ret i32 undef
+;
+entry:
+  %call = call i32 null()
+  ret i32 %call
+}
+
+define i32 @call_undef() {
+; CHECK-LABEL: @call_undef(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[CALL:%.*]] = call i32 undef()
+; CHECK-NEXT:    ret i32 undef
+;
+entry:
+  %call = call i32 undef()
+  ret i32 %call
+}
+
+ at GV = private constant [8 x i32] [i32 42, i32 43, i32 44, i32 45, i32 46, i32 47, i32 48, i32 49]
+
+define <8 x i32> @partial_masked_load() {
+; CHECK-LABEL: @partial_masked_load(
+; CHECK-NEXT:    ret <8 x i32> <i32 undef, i32 undef, i32 42, i32 43, i32 44, i32 45, i32 46, i32 47>
+;
+  %masked.load = call <8 x i32> @llvm.masked.load.v8i32.p0v8i32(<8 x i32>* bitcast (i32* getelementptr ([8 x i32], [8 x i32]* @GV, i64 0, i64 -2) to <8 x i32>*), i32 4, <8 x i1> <i1 false, i1 false, i1 true, i1 true, i1 true, i1 true, i1 true, i1 true>, <8 x i32> undef)
+  ret <8 x i32> %masked.load
+}
+
+define <8 x i32> @masked_load_undef_mask(<8 x i32>* %V) {
+; CHECK-LABEL: @masked_load_undef_mask(
+; CHECK-NEXT:    ret <8 x i32> <i32 1, i32 0, i32 1, i32 0, i32 1, i32 0, i32 1, i32 0>
+;
+  %masked.load = call <8 x i32> @llvm.masked.load.v8i32.p0v8i32(<8 x i32>* %V, i32 4, <8 x i1> undef, <8 x i32> <i32 1, i32 0, i32 1, i32 0, i32 1, i32 0, i32 1, i32 0>)
+  ret <8 x i32> %masked.load
+}
+
+declare noalias i8* @malloc(i64)
+
+declare <8 x i32> @llvm.masked.load.v8i32.p0v8i32(<8 x i32>*, i32, <8 x i1>, <8 x i32>)
+
+declare double @llvm.powi.f64(double, i32)
+declare <2 x double> @llvm.powi.v2f64(<2 x double>, i32)
+
+define double @constant_fold_powi() {
+; CHECK-LABEL: @constant_fold_powi(
+; CHECK-NEXT:    ret double 9.000000e+00
+;
+  %t0 = call double @llvm.powi.f64(double 3.00000e+00, i32 2)
+  ret double %t0
+}
+
+define <2 x double> @constant_fold_powi_vec() {
+; CHECK-LABEL: @constant_fold_powi_vec(
+; CHECK-NEXT:    ret <2 x double> <double 9.000000e+00, double 2.500000e+01>
+;
+  %t0 = call <2 x double> @llvm.powi.v2f64(<2 x double> <double 3.00000e+00, double 5.00000e+00>, i32 2)
+  ret <2 x double> %t0
+}
+
+declare i8 @llvm.fshl.i8(i8, i8, i8)
+declare i9 @llvm.fshr.i9(i9, i9, i9)
+declare <2 x i7> @llvm.fshl.v2i7(<2 x i7>, <2 x i7>, <2 x i7>)
+declare <2 x i8> @llvm.fshr.v2i8(<2 x i8>, <2 x i8>, <2 x i8>)
+
+define i8 @fshl_no_shift(i8 %x, i8 %y) {
+; CHECK-LABEL: @fshl_no_shift(
+; CHECK-NEXT:    ret i8 [[X:%.*]]
+;
+  %z = call i8 @llvm.fshl.i8(i8 %x, i8 %y, i8 0)
+  ret i8 %z
+}
+
+define i9 @fshr_no_shift(i9 %x, i9 %y) {
+; CHECK-LABEL: @fshr_no_shift(
+; CHECK-NEXT:    ret i9 [[Y:%.*]]
+;
+  %z = call i9 @llvm.fshr.i9(i9 %x, i9 %y, i9 0)
+  ret i9 %z
+}
+
+define i8 @fshl_no_shift_modulo_bitwidth(i8 %x, i8 %y) {
+; CHECK-LABEL: @fshl_no_shift_modulo_bitwidth(
+; CHECK-NEXT:    ret i8 [[X:%.*]]
+;
+  %z = call i8 @llvm.fshl.i8(i8 %x, i8 %y, i8 40)
+  ret i8 %z
+}
+
+define i9 @fshr_no_shift_modulo_bitwidth(i9 %x, i9 %y) {
+; CHECK-LABEL: @fshr_no_shift_modulo_bitwidth(
+; CHECK-NEXT:    ret i9 [[Y:%.*]]
+;
+  %z = call i9 @llvm.fshr.i9(i9 %x, i9 %y, i9 189)
+  ret i9 %z
+}
+
+define <2 x i7> @fshl_no_shift_modulo_bitwidth_splat(<2 x i7> %x, <2 x i7> %y) {
+; CHECK-LABEL: @fshl_no_shift_modulo_bitwidth_splat(
+; CHECK-NEXT:    ret <2 x i7> [[X:%.*]]
+;
+  %z = call <2 x i7> @llvm.fshl.v2i7(<2 x i7> %x, <2 x i7> %y, <2 x i7> <i7 21, i7 21>)
+  ret <2 x i7> %z
+}
+
+define <2 x i8> @fshr_no_shift_modulo_bitwidth_splat(<2 x i8> %x, <2 x i8> %y) {
+; CHECK-LABEL: @fshr_no_shift_modulo_bitwidth_splat(
+; CHECK-NEXT:    ret <2 x i8> [[Y:%.*]]
+;
+  %z = call <2 x i8> @llvm.fshr.v2i8(<2 x i8> %x, <2 x i8> %y, <2 x i8> <i8 72, i8 72>)
+  ret <2 x i8> %z
+}
+
+; If y is poison, eliminating the guard is not safe.
+
+define i8 @fshl_zero_shift_guard(i8 %x, i8 %y, i8 %sh) {
+; CHECK-LABEL: @fshl_zero_shift_guard(
+; CHECK-NEXT:    [[C:%.*]] = icmp eq i8 [[SH:%.*]], 0
+; CHECK-NEXT:    [[F:%.*]] = call i8 @llvm.fshl.i8(i8 [[X:%.*]], i8 [[Y:%.*]], i8 [[SH]])
+; CHECK-NEXT:    [[S:%.*]] = select i1 [[C]], i8 [[X]], i8 [[F]]
+; CHECK-NEXT:    ret i8 [[S]]
+;
+  %c = icmp eq i8 %sh, 0
+  %f = call i8 @llvm.fshl.i8(i8 %x, i8 %y, i8 %sh)
+  %s = select i1 %c, i8 %x, i8 %f
+  ret i8 %s
+}
+
+; If y is poison, eliminating the guard is not safe.
+
+define i8 @fshl_zero_shift_guard_swapped(i8 %x, i8 %y, i8 %sh) {
+; CHECK-LABEL: @fshl_zero_shift_guard_swapped(
+; CHECK-NEXT:    [[C:%.*]] = icmp ne i8 [[SH:%.*]], 0
+; CHECK-NEXT:    [[F:%.*]] = call i8 @llvm.fshl.i8(i8 [[X:%.*]], i8 [[Y:%.*]], i8 [[SH]])
+; CHECK-NEXT:    [[S:%.*]] = select i1 [[C]], i8 [[F]], i8 [[X]]
+; CHECK-NEXT:    ret i8 [[S]]
+;
+  %c = icmp ne i8 %sh, 0
+  %f = call i8 @llvm.fshl.i8(i8 %x, i8 %y, i8 %sh)
+  %s = select i1 %c, i8 %f, i8 %x
+  ret i8 %s
+}
+
+; When the shift amount is 0, fshl returns its 1st parameter (x), so everything is deleted.
+
+define i8 @fshl_zero_shift_guard_inverted(i8 %x, i8 %y, i8 %sh) {
+; CHECK-LABEL: @fshl_zero_shift_guard_inverted(
+; CHECK-NEXT:    ret i8 [[X:%.*]]
+;
+  %c = icmp eq i8 %sh, 0
+  %f = call i8 @llvm.fshl.i8(i8 %x, i8 %y, i8 %sh)
+  %s = select i1 %c, i8 %f, i8 %x
+  ret i8 %s
+}
+
+; When the shift amount is 0, fshl returns its 1st parameter (x), so everything is deleted.
+
+define i8 @fshl_zero_shift_guard_inverted_swapped(i8 %x, i8 %y, i8 %sh) {
+; CHECK-LABEL: @fshl_zero_shift_guard_inverted_swapped(
+; CHECK-NEXT:    ret i8 [[X:%.*]]
+;
+  %c = icmp ne i8 %sh, 0
+  %f = call i8 @llvm.fshl.i8(i8 %x, i8 %y, i8 %sh)
+  %s = select i1 %c, i8 %x, i8 %f
+  ret i8 %s
+}
+
+; If x is poison, eliminating the guard is not safe.
+
+define i9 @fshr_zero_shift_guard(i9 %x, i9 %y, i9 %sh) {
+; CHECK-LABEL: @fshr_zero_shift_guard(
+; CHECK-NEXT:    [[C:%.*]] = icmp eq i9 [[SH:%.*]], 0
+; CHECK-NEXT:    [[F:%.*]] = call i9 @llvm.fshr.i9(i9 [[X:%.*]], i9 [[Y:%.*]], i9 [[SH]])
+; CHECK-NEXT:    [[S:%.*]] = select i1 [[C]], i9 [[Y]], i9 [[F]]
+; CHECK-NEXT:    ret i9 [[S]]
+;
+  %c = icmp eq i9 %sh, 0
+  %f = call i9 @llvm.fshr.i9(i9 %x, i9 %y, i9 %sh)
+  %s = select i1 %c, i9 %y, i9 %f
+  ret i9 %s
+}
+
+; If x is poison, eliminating the guard is not safe.
+
+define i9 @fshr_zero_shift_guard_swapped(i9 %x, i9 %y, i9 %sh) {
+; CHECK-LABEL: @fshr_zero_shift_guard_swapped(
+; CHECK-NEXT:    [[C:%.*]] = icmp ne i9 [[SH:%.*]], 0
+; CHECK-NEXT:    [[F:%.*]] = call i9 @llvm.fshr.i9(i9 [[X:%.*]], i9 [[Y:%.*]], i9 [[SH]])
+; CHECK-NEXT:    [[S:%.*]] = select i1 [[C]], i9 [[F]], i9 [[Y]]
+; CHECK-NEXT:    ret i9 [[S]]
+;
+  %c = icmp ne i9 %sh, 0
+  %f = call i9 @llvm.fshr.i9(i9 %x, i9 %y, i9 %sh)
+  %s = select i1 %c, i9 %f, i9 %y
+  ret i9 %s
+}
+
+; When the shift amount is 0, fshr returns its 2nd parameter (y), so everything is deleted.
+
+define i9 @fshr_zero_shift_guard_inverted(i9 %x, i9 %y, i9 %sh) {
+; CHECK-LABEL: @fshr_zero_shift_guard_inverted(
+; CHECK-NEXT:    ret i9 [[Y:%.*]]
+;
+  %c = icmp eq i9 %sh, 0
+  %f = call i9 @llvm.fshr.i9(i9 %x, i9 %y, i9 %sh)
+  %s = select i1 %c, i9 %f, i9 %y
+  ret i9 %s
+}
+
+; When the shift amount is 0, fshr returns its 2nd parameter (y), so everything is deleted.
+
+define i9 @fshr_zero_shift_guard_inverted_swapped(i9 %x, i9 %y, i9 %sh) {
+; CHECK-LABEL: @fshr_zero_shift_guard_inverted_swapped(
+; CHECK-NEXT:    ret i9 [[Y:%.*]]
+;
+  %c = icmp ne i9 %sh, 0
+  %f = call i9 @llvm.fshr.i9(i9 %x, i9 %y, i9 %sh)
+  %s = select i1 %c, i9 %y, i9 %f
+  ret i9 %s
+}
+
+; When the shift amount is 0, fshl returns its 1st parameter (x), so the guard is not needed.
+
+define i8 @rotl_zero_shift_guard(i8 %x, i8 %sh) {
+; CHECK-LABEL: @rotl_zero_shift_guard(
+; CHECK-NEXT:    [[F:%.*]] = call i8 @llvm.fshl.i8(i8 [[X:%.*]], i8 [[X]], i8 [[SH:%.*]])
+; CHECK-NEXT:    ret i8 [[F]]
+;
+  %c = icmp eq i8 %sh, 0
+  %f = call i8 @llvm.fshl.i8(i8 %x, i8 %x, i8 %sh)
+  %s = select i1 %c, i8 %x, i8 %f
+  ret i8 %s
+}
+
+; When the shift amount is 0, fshl returns its 1st parameter (x), so the guard is not needed.
+
+define i8 @rotl_zero_shift_guard_swapped(i8 %x, i8 %sh) {
+; CHECK-LABEL: @rotl_zero_shift_guard_swapped(
+; CHECK-NEXT:    [[F:%.*]] = call i8 @llvm.fshl.i8(i8 [[X:%.*]], i8 [[X]], i8 [[SH:%.*]])
+; CHECK-NEXT:    ret i8 [[F]]
+;
+  %c = icmp ne i8 %sh, 0
+  %f = call i8 @llvm.fshl.i8(i8 %x, i8 %x, i8 %sh)
+  %s = select i1 %c, i8 %f, i8 %x
+  ret i8 %s
+}
+
+; When the shift amount is 0, fshl returns its 1st parameter (x), so everything is deleted.
+
+define i8 @rotl_zero_shift_guard_inverted(i8 %x, i8 %sh) {
+; CHECK-LABEL: @rotl_zero_shift_guard_inverted(
+; CHECK-NEXT:    ret i8 [[X:%.*]]
+;
+  %c = icmp eq i8 %sh, 0
+  %f = call i8 @llvm.fshl.i8(i8 %x, i8 %x, i8 %sh)
+  %s = select i1 %c, i8 %f, i8 %x
+  ret i8 %s
+}
+
+; When the shift amount is 0, fshl returns its 1st parameter (x), so everything is deleted.
+
+define i8 @rotl_zero_shift_guard_inverted_swapped(i8 %x, i8 %sh) {
+; CHECK-LABEL: @rotl_zero_shift_guard_inverted_swapped(
+; CHECK-NEXT:    ret i8 [[X:%.*]]
+;
+  %c = icmp ne i8 %sh, 0
+  %f = call i8 @llvm.fshl.i8(i8 %x, i8 %x, i8 %sh)
+  %s = select i1 %c, i8 %x, i8 %f
+  ret i8 %s
+}
+
+; When the shift amount is 0, fshr returns its 2nd parameter (x), so the guard is not needed.
+
+define i9 @rotr_zero_shift_guard(i9 %x, i9 %sh) {
+; CHECK-LABEL: @rotr_zero_shift_guard(
+; CHECK-NEXT:    [[F:%.*]] = call i9 @llvm.fshr.i9(i9 [[X:%.*]], i9 [[X]], i9 [[SH:%.*]])
+; CHECK-NEXT:    ret i9 [[F]]
+;
+  %c = icmp eq i9 %sh, 0
+  %f = call i9 @llvm.fshr.i9(i9 %x, i9 %x, i9 %sh)
+  %s = select i1 %c, i9 %x, i9 %f
+  ret i9 %s
+}
+
+; When the shift amount is 0, fshr returns its 2nd parameter (x), so the guard is not needed.
+
+define i9 @rotr_zero_shift_guard_swapped(i9 %x, i9 %sh) {
+; CHECK-LABEL: @rotr_zero_shift_guard_swapped(
+; CHECK-NEXT:    [[F:%.*]] = call i9 @llvm.fshr.i9(i9 [[X:%.*]], i9 [[X]], i9 [[SH:%.*]])
+; CHECK-NEXT:    ret i9 [[F]]
+;
+  %c = icmp ne i9 %sh, 0
+  %f = call i9 @llvm.fshr.i9(i9 %x, i9 %x, i9 %sh)
+  %s = select i1 %c, i9 %f, i9 %x
+  ret i9 %s
+}
+
+; When the shift amount is 0, fshr returns its 2nd parameter (x), so everything is deleted.
+
+define i9 @rotr_zero_shift_guard_inverted(i9 %x, i9 %sh) {
+; CHECK-LABEL: @rotr_zero_shift_guard_inverted(
+; CHECK-NEXT:    ret i9 [[X:%.*]]
+;
+  %c = icmp eq i9 %sh, 0
+  %f = call i9 @llvm.fshr.i9(i9 %x, i9 %x, i9 %sh)
+  %s = select i1 %c, i9 %f, i9 %x
+  ret i9 %s
+}
+
+; When the shift amount is 0, fshr returns its 2nd parameter (x), so everything is deleted.
+
+define i9 @rotr_zero_shift_guard_inverted_swapped(i9 %x, i9 %sh) {
+; CHECK-LABEL: @rotr_zero_shift_guard_inverted_swapped(
+; CHECK-NEXT:    ret i9 [[X:%.*]]
+;
+  %c = icmp ne i9 %sh, 0
+  %f = call i9 @llvm.fshr.i9(i9 %x, i9 %x, i9 %sh)
+  %s = select i1 %c, i9 %x, i9 %f
+  ret i9 %s
+}
+
+; Negative test - make sure we're matching the correct parameter of fshl.
+
+define i8 @fshl_zero_shift_guard_wrong_select_op(i8 %x, i8 %y, i8 %sh) {
+; CHECK-LABEL: @fshl_zero_shift_guard_wrong_select_op(
+; CHECK-NEXT:    [[C:%.*]] = icmp eq i8 [[SH:%.*]], 0
+; CHECK-NEXT:    [[F:%.*]] = call i8 @llvm.fshl.i8(i8 [[X:%.*]], i8 [[Y:%.*]], i8 [[SH]])
+; CHECK-NEXT:    [[S:%.*]] = select i1 [[C]], i8 [[Y]], i8 [[F]]
+; CHECK-NEXT:    ret i8 [[S]]
+;
+  %c = icmp eq i8 %sh, 0
+  %f = call i8 @llvm.fshl.i8(i8 %x, i8 %y, i8 %sh)
+  %s = select i1 %c, i8 %y, i8 %f
+  ret i8 %s
+}
+
+; Vector types work too.
+
+define <2 x i8> @rotr_zero_shift_guard_splat(<2 x i8> %x, <2 x i8> %sh) {
+; CHECK-LABEL: @rotr_zero_shift_guard_splat(
+; CHECK-NEXT:    [[F:%.*]] = call <2 x i8> @llvm.fshr.v2i8(<2 x i8> [[X:%.*]], <2 x i8> [[X]], <2 x i8> [[SH:%.*]])
+; CHECK-NEXT:    ret <2 x i8> [[F]]
+;
+  %c = icmp eq <2 x i8> %sh, zeroinitializer
+  %f = call <2 x i8> @llvm.fshr.v2i8(<2 x i8> %x, <2 x i8> %x, <2 x i8> %sh)
+  %s = select <2 x i1> %c, <2 x i8> %x, <2 x i8> %f
+  ret <2 x i8> %s
+}
+
+; If first two operands of funnel shift are undef, the result is undef
+
+define i8 @fshl_ops_undef(i8 %shamt) {
+; CHECK-LABEL: @fshl_ops_undef(
+; CHECK-NEXT:    ret i8 undef
+;
+  %r = call i8 @llvm.fshl.i8(i8 undef, i8 undef, i8 %shamt)
+  ret i8 %r
+}
+
+define i9 @fshr_ops_undef(i9 %shamt) {
+; CHECK-LABEL: @fshr_ops_undef(
+; CHECK-NEXT:    ret i9 undef
+;
+  %r = call i9 @llvm.fshr.i9(i9 undef, i9 undef, i9 %shamt)
+  ret i9 %r
+}
+
+; If shift amount is undef, treat it as zero, returning operand 0 or 1
+
+define i8 @fshl_shift_undef(i8 %x, i8 %y) {
+; CHECK-LABEL: @fshl_shift_undef(
+; CHECK-NEXT:    ret i8 [[X:%.*]]
+;
+  %r = call i8 @llvm.fshl.i8(i8 %x, i8 %y, i8 undef)
+  ret i8 %r
+}
+
+define i9 @fshr_shift_undef(i9 %x, i9 %y) {
+; CHECK-LABEL: @fshr_shift_undef(
+; CHECK-NEXT:    ret i9 [[Y:%.*]]
+;
+  %r = call i9 @llvm.fshr.i9(i9 %x, i9 %y, i9 undef)
+  ret i9 %r
+}
+

Added: llvm/trunk/test/Transforms/InstSimplify/cast-unsigned-icmp-cmp-0.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstSimplify/cast-unsigned-icmp-cmp-0.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstSimplify/cast-unsigned-icmp-cmp-0.ll (added)
+++ llvm/trunk/test/Transforms/InstSimplify/cast-unsigned-icmp-cmp-0.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,188 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt < %s -instsimplify -S | FileCheck %s
+
+; This is related to https://bugs.llvm.org/show_bug.cgi?id=36682
+
+; All of these can be simplified to a constant true or false value.
+;   * slt i32 %b, 0  -> false
+;   * sgt i32 %b, -1 -> true
+
+define i1 @i32_cast_cmp_slt_int_0_uitofp_float(i32 %i) {
+; CHECK-LABEL: @i32_cast_cmp_slt_int_0_uitofp_float(
+; CHECK-NEXT:    ret i1 false
+;
+  %f = uitofp i32 %i to float
+  %b = bitcast float %f to i32
+  %cmp = icmp slt i32 %b, 0
+  ret i1 %cmp
+}
+
+define <2 x i1> @i32_cast_cmp_slt_int_0_uitofp_float_vec(<2 x i32> %i) {
+; CHECK-LABEL: @i32_cast_cmp_slt_int_0_uitofp_float_vec(
+; CHECK-NEXT:    ret <2 x i1> zeroinitializer
+;
+  %f = uitofp <2 x i32> %i to <2 x float>
+  %b = bitcast <2 x float> %f to <2 x i32>
+  %cmp = icmp slt <2 x i32> %b, <i32 0, i32 0>
+  ret <2 x i1> %cmp
+}
+
+define <3 x i1> @i32_cast_cmp_slt_int_0_uitofp_float_vec_undef(<3 x i32> %i) {
+; CHECK-LABEL: @i32_cast_cmp_slt_int_0_uitofp_float_vec_undef(
+; CHECK-NEXT:    ret <3 x i1> zeroinitializer
+;
+  %f = uitofp <3 x i32> %i to <3 x float>
+  %b = bitcast <3 x float> %f to <3 x i32>
+  %cmp = icmp slt <3 x i32> %b, <i32 0, i32 undef, i32 0>
+  ret <3 x i1> %cmp
+}
+
+define i1 @i32_cast_cmp_sgt_int_m1_uitofp_float(i32 %i) {
+; CHECK-LABEL: @i32_cast_cmp_sgt_int_m1_uitofp_float(
+; CHECK-NEXT:    ret i1 true
+;
+  %f = uitofp i32 %i to float
+  %b = bitcast float %f to i32
+  %cmp = icmp sgt i32 %b, -1
+  ret i1 %cmp
+}
+
+define <2 x i1> @i32_cast_cmp_sgt_int_m1_uitofp_float_vec(<2 x i32> %i) {
+; CHECK-LABEL: @i32_cast_cmp_sgt_int_m1_uitofp_float_vec(
+; CHECK-NEXT:    ret <2 x i1> <i1 true, i1 true>
+;
+  %f = uitofp <2 x i32> %i to <2 x float>
+  %b = bitcast <2 x float> %f to <2 x i32>
+  %cmp = icmp sgt <2 x i32> %b, <i32 -1, i32 -1>
+  ret <2 x i1> %cmp
+}
+
+define <3 x i1> @i32_cast_cmp_sgt_int_m1_uitofp_float_vec_undef(<3 x i32> %i) {
+; CHECK-LABEL: @i32_cast_cmp_sgt_int_m1_uitofp_float_vec_undef(
+; CHECK-NEXT:    ret <3 x i1> <i1 true, i1 true, i1 true>
+;
+  %f = uitofp <3 x i32> %i to <3 x float>
+  %b = bitcast <3 x float> %f to <3 x i32>
+  %cmp = icmp sgt <3 x i32> %b, <i32 -1, i32 undef, i32 -1>
+  ret <3 x i1> %cmp
+}
+
+define i1 @i32_cast_cmp_slt_int_0_uitofp_double(i32 %i) {
+; CHECK-LABEL: @i32_cast_cmp_slt_int_0_uitofp_double(
+; CHECK-NEXT:    ret i1 false
+;
+  %f = uitofp i32 %i to double
+  %b = bitcast double %f to i64
+  %cmp = icmp slt i64 %b, 0
+  ret i1 %cmp
+}
+
+define <2 x i1> @i32_cast_cmp_slt_int_0_uitofp_double_vec(<2 x i32> %i) {
+; CHECK-LABEL: @i32_cast_cmp_slt_int_0_uitofp_double_vec(
+; CHECK-NEXT:    ret <2 x i1> zeroinitializer
+;
+  %f = uitofp <2 x i32> %i to <2 x double>
+  %b = bitcast <2 x double> %f to <2 x i64>
+  %cmp = icmp slt <2 x i64> %b, <i64 0, i64 0>
+  ret <2 x i1> %cmp
+}
+
+define <3 x i1> @i32_cast_cmp_slt_int_0_uitofp_double_vec_undef(<3 x i32> %i) {
+; CHECK-LABEL: @i32_cast_cmp_slt_int_0_uitofp_double_vec_undef(
+; CHECK-NEXT:    ret <3 x i1> zeroinitializer
+;
+  %f = uitofp <3 x i32> %i to <3 x double>
+  %b = bitcast <3 x double> %f to <3 x i64>
+  %cmp = icmp slt <3 x i64> %b, <i64 0, i64 undef, i64 0>
+  ret <3 x i1> %cmp
+}
+
+define i1 @i32_cast_cmp_sgt_int_m1_uitofp_double(i32 %i) {
+; CHECK-LABEL: @i32_cast_cmp_sgt_int_m1_uitofp_double(
+; CHECK-NEXT:    ret i1 true
+;
+  %f = uitofp i32 %i to double
+  %b = bitcast double %f to i64
+  %cmp = icmp sgt i64 %b, -1
+  ret i1 %cmp
+}
+
+define <2 x i1> @i32_cast_cmp_sgt_int_m1_uitofp_double_vec(<2 x i32> %i) {
+; CHECK-LABEL: @i32_cast_cmp_sgt_int_m1_uitofp_double_vec(
+; CHECK-NEXT:    ret <2 x i1> <i1 true, i1 true>
+;
+  %f = uitofp <2 x i32> %i to <2 x double>
+  %b = bitcast <2 x double> %f to <2 x i64>
+  %cmp = icmp sgt <2 x i64> %b, <i64 -1, i64 -1>
+  ret <2 x i1> %cmp
+}
+
+define <3 x i1> @i32_cast_cmp_sgt_int_m1_uitofp_double_vec_undef(<3 x i32> %i) {
+; CHECK-LABEL: @i32_cast_cmp_sgt_int_m1_uitofp_double_vec_undef(
+; CHECK-NEXT:    ret <3 x i1> <i1 true, i1 true, i1 true>
+;
+  %f = uitofp <3 x i32> %i to <3 x double>
+  %b = bitcast <3 x double> %f to <3 x i64>
+  %cmp = icmp sgt <3 x i64> %b, <i64 -1, i64 undef, i64 -1>
+  ret <3 x i1> %cmp
+}
+
+define i1 @i32_cast_cmp_slt_int_0_uitofp_half(i32 %i) {
+; CHECK-LABEL: @i32_cast_cmp_slt_int_0_uitofp_half(
+; CHECK-NEXT:    ret i1 false
+;
+  %f = uitofp i32 %i to half
+  %b = bitcast half %f to i16
+  %cmp = icmp slt i16 %b, 0
+  ret i1 %cmp
+}
+
+define <2 x i1> @i32_cast_cmp_slt_int_0_uitofp_half_vec(<2 x i32> %i) {
+; CHECK-LABEL: @i32_cast_cmp_slt_int_0_uitofp_half_vec(
+; CHECK-NEXT:    ret <2 x i1> zeroinitializer
+;
+  %f = uitofp <2 x i32> %i to <2 x half>
+  %b = bitcast <2 x half> %f to <2 x i16>
+  %cmp = icmp slt <2 x i16> %b, <i16 0, i16 0>
+  ret <2 x i1> %cmp
+}
+
+define <3 x i1> @i32_cast_cmp_slt_int_0_uitofp_half_vec_undef(<3 x i32> %i) {
+; CHECK-LABEL: @i32_cast_cmp_slt_int_0_uitofp_half_vec_undef(
+; CHECK-NEXT:    ret <3 x i1> zeroinitializer
+;
+  %f = uitofp <3 x i32> %i to <3 x half>
+  %b = bitcast <3 x half> %f to <3 x i16>
+  %cmp = icmp slt <3 x i16> %b, <i16 0, i16 undef, i16 0>
+  ret <3 x i1> %cmp
+}
+
+define i1 @i32_cast_cmp_sgt_int_m1_uitofp_half(i32 %i) {
+; CHECK-LABEL: @i32_cast_cmp_sgt_int_m1_uitofp_half(
+; CHECK-NEXT:    ret i1 true
+;
+  %f = uitofp i32 %i to half
+  %b = bitcast half %f to i16
+  %cmp = icmp sgt i16 %b, -1
+  ret i1 %cmp
+}
+
+define <2 x i1> @i32_cast_cmp_sgt_int_m1_uitofp_half_vec(<2 x i32> %i) {
+; CHECK-LABEL: @i32_cast_cmp_sgt_int_m1_uitofp_half_vec(
+; CHECK-NEXT:    ret <2 x i1> <i1 true, i1 true>
+;
+  %f = uitofp <2 x i32> %i to <2 x half>
+  %b = bitcast <2 x half> %f to <2 x i16>
+  %cmp = icmp sgt <2 x i16> %b, <i16 -1, i16 -1>
+  ret <2 x i1> %cmp
+}
+
+define <3 x i1> @i32_cast_cmp_sgt_int_m1_uitofp_half_vec_undef(<3 x i32> %i) {
+; CHECK-LABEL: @i32_cast_cmp_sgt_int_m1_uitofp_half_vec_undef(
+; CHECK-NEXT:    ret <3 x i1> <i1 true, i1 true, i1 true>
+;
+  %f = uitofp <3 x i32> %i to <3 x half>
+  %b = bitcast <3 x half> %f to <3 x i16>
+  %cmp = icmp sgt <3 x i16> %b, <i16 -1, i16 undef, i16 -1>
+  ret <3 x i1> %cmp
+}

Added: llvm/trunk/test/Transforms/InstSimplify/cast.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstSimplify/cast.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstSimplify/cast.ll (added)
+++ llvm/trunk/test/Transforms/InstSimplify/cast.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,54 @@
+; RUN: opt -S -instsimplify < %s | FileCheck %s
+target datalayout = "p:32:32"
+
+define i1 @test1(i1 %V) {
+entry:
+  %Z = zext i1 %V to i32
+  %T = trunc i32 %Z to i1
+  ret i1 %T
+; CHECK-LABEL: define i1 @test1(
+; CHECK: ret i1 %V
+}
+
+define i8* @test2(i8* %V) {
+entry:
+  %BC1 = bitcast i8* %V to i32*
+  %BC2 = bitcast i32* %BC1 to i8*
+  ret i8* %BC2
+; CHECK-LABEL: define i8* @test2(
+; CHECK: ret i8* %V
+}
+
+define i8* @test3(i8* %V) {
+entry:
+  %BC = bitcast i8* %V to i8*
+  ret i8* %BC
+; CHECK-LABEL: define i8* @test3(
+; CHECK: ret i8* %V
+}
+
+define i32 @test4() {
+; CHECK-LABEL: @test4(
+  %alloca = alloca i32, align 4                                     ; alloca + 0
+  %gep = getelementptr inbounds i32, i32* %alloca, i32 1            ; alloca + 4
+  %bc = bitcast i32* %gep to [4 x i8]*                              ; alloca + 4
+  %pti = ptrtoint i32* %alloca to i32                               ; alloca
+  %sub = sub i32 0, %pti                                            ; -alloca
+  %add = getelementptr [4 x i8], [4 x i8]* %bc, i32 0, i32 %sub     ; alloca + 4 - alloca == 4
+  %add_to_int = ptrtoint i8* %add to i32                            ; 4
+  ret i32 %add_to_int                                               ; 4
+; CHECK-NEXT: ret i32 4
+}
+
+define i32 @test5() {
+; CHECK-LABEL: @test5(
+  %alloca = alloca i32, align 4                                     ; alloca + 0
+  %gep = getelementptr inbounds i32, i32* %alloca, i32 1            ; alloca + 4
+  %bc = bitcast i32* %gep to [4 x i8]*                              ; alloca + 4
+  %pti = ptrtoint i32* %alloca to i32                               ; alloca
+  %sub = xor i32 %pti, -1                                           ; ~alloca
+  %add = getelementptr [4 x i8], [4 x i8]* %bc, i32 0, i32 %sub     ; alloca + 4 - alloca - 1 == 3
+  %add_to_int = ptrtoint i8* %add to i32                            ; 4
+  ret i32 %add_to_int                                               ; 4
+; CHECK-NEXT: ret i32 3
+}

Added: llvm/trunk/test/Transforms/InstSimplify/cmp_of_min_max.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstSimplify/cmp_of_min_max.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstSimplify/cmp_of_min_max.ll (added)
+++ llvm/trunk/test/Transforms/InstSimplify/cmp_of_min_max.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 -instsimplify -S | FileCheck %s
+
+define i1 @test_umax1(i32 %n) {
+; CHECK-LABEL: @test_umax1(
+; CHECK-NEXT:    ret i1 true
+;
+  %c1 = icmp ugt i32 %n, 10
+  %s = select i1 %c1, i32 %n, i32 10
+  %c2 = icmp ugt i32 %s, 9
+  ret i1 %c2
+}
+
+define i1 @test_umax2(i32 %n) {
+; CHECK-LABEL: @test_umax2(
+; CHECK-NEXT:    [[C1:%.*]] = icmp ugt i32 [[N:%.*]], 10
+; CHECK-NEXT:    ret i1 [[C1]]
+;
+  %c1 = icmp ugt i32 %n, 10
+  %s = select i1 %c1, i32 %n, i32 10
+  %c2 = icmp ugt i32 %s, 10
+  ret i1 %c2
+}
+
+define i1 @test_umax3(i32 %n) {
+; CHECK-LABEL: @test_umax3(
+; CHECK-NEXT:    [[C1:%.*]] = icmp ugt i32 [[N:%.*]], 10
+; CHECK-NEXT:    [[S:%.*]] = select i1 [[C1]], i32 [[N]], i32 10
+; CHECK-NEXT:    [[C2:%.*]] = icmp ugt i32 [[S]], 11
+; CHECK-NEXT:    ret i1 [[C2]]
+;
+  %c1 = icmp ugt i32 %n, 10
+  %s = select i1 %c1, i32 %n, i32 10
+  %c2 = icmp ugt i32 %s, 11
+  ret i1 %c2
+}
+
+define i1 @test_umin1(i32 %n) {
+; CHECK-LABEL: @test_umin1(
+; CHECK-NEXT:    ret i1 true
+;
+  %c1 = icmp ult i32 %n, 10
+  %s = select i1 %c1, i32 %n, i32 10
+  %c2 = icmp ult i32 %s, 11
+  ret i1 %c2
+}
+
+define i1 @test_umin2(i32 %n) {
+; CHECK-LABEL: @test_umin2(
+; CHECK-NEXT:    [[C1:%.*]] = icmp ult i32 [[N:%.*]], 10
+; CHECK-NEXT:    ret i1 [[C1]]
+;
+  %c1 = icmp ult i32 %n, 10
+  %s = select i1 %c1, i32 %n, i32 10
+  %c2 = icmp ult i32 %s, 10
+  ret i1 %c2
+}
+
+define i1 @test_umin3(i32 %n) {
+; CHECK-LABEL: @test_umin3(
+; CHECK-NEXT:    [[C1:%.*]] = icmp ult i32 [[N:%.*]], 10
+; CHECK-NEXT:    [[S:%.*]] = select i1 [[C1]], i32 [[N]], i32 10
+; CHECK-NEXT:    [[C2:%.*]] = icmp ult i32 [[S]], 9
+; CHECK-NEXT:    ret i1 [[C2]]
+;
+  %c1 = icmp ult i32 %n, 10
+  %s = select i1 %c1, i32 %n, i32 10
+  %c2 = icmp ult i32 %s, 9
+  ret i1 %c2
+}
+
+define i1 @test_smax1(i32 %n) {
+; CHECK-LABEL: @test_smax1(
+; CHECK-NEXT:    ret i1 true
+;
+  %c1 = icmp sgt i32 %n, -10
+  %s = select i1 %c1, i32 %n, i32 -10
+  %c2 = icmp sgt i32 %s, -11
+  ret i1 %c2
+}
+
+define i1 @test_smax2(i32 %n) {
+; CHECK-LABEL: @test_smax2(
+; CHECK-NEXT:    [[C1:%.*]] = icmp sgt i32 [[N:%.*]], -10
+; CHECK-NEXT:    ret i1 [[C1]]
+;
+  %c1 = icmp sgt i32 %n, -10
+  %s = select i1 %c1, i32 %n, i32 -10
+  %c2 = icmp sgt i32 %s, -10
+  ret i1 %c2
+}
+
+define i1 @test_smax3(i32 %n) {
+; CHECK-LABEL: @test_smax3(
+; CHECK-NEXT:    [[C1:%.*]] = icmp sgt i32 [[N:%.*]], -10
+; CHECK-NEXT:    [[S:%.*]] = select i1 [[C1]], i32 [[N]], i32 -10
+; CHECK-NEXT:    [[C2:%.*]] = icmp sgt i32 [[S]], -9
+; CHECK-NEXT:    ret i1 [[C2]]
+;
+  %c1 = icmp sgt i32 %n, -10
+  %s = select i1 %c1, i32 %n, i32 -10
+  %c2 = icmp sgt i32 %s, -9
+  ret i1 %c2
+}
+
+define i1 @test_smin1(i32 %n) {
+; CHECK-LABEL: @test_smin1(
+; CHECK-NEXT:    ret i1 true
+;
+  %c1 = icmp slt i32 %n, 10
+  %s = select i1 %c1, i32 %n, i32 10
+  %c2 = icmp slt i32 %s, 11
+  ret i1 %c2
+}
+
+define i1 @test_smin2(i32 %n) {
+; CHECK-LABEL: @test_smin2(
+; CHECK-NEXT:    [[C1:%.*]] = icmp slt i32 [[N:%.*]], 10
+; CHECK-NEXT:    ret i1 [[C1]]
+;
+  %c1 = icmp slt i32 %n, 10
+  %s = select i1 %c1, i32 %n, i32 10
+  %c2 = icmp slt i32 %s, 10
+  ret i1 %c2
+}
+
+define i1 @test_smin3(i32 %n) {
+; CHECK-LABEL: @test_smin3(
+; CHECK-NEXT:    [[C1:%.*]] = icmp slt i32 [[N:%.*]], 10
+; CHECK-NEXT:    [[S:%.*]] = select i1 [[C1]], i32 [[N]], i32 10
+; CHECK-NEXT:    [[C2:%.*]] = icmp slt i32 [[S]], 9
+; CHECK-NEXT:    ret i1 [[C2]]
+;
+  %c1 = icmp slt i32 %n, 10
+  %s = select i1 %c1, i32 %n, i32 10
+  %c2 = icmp slt i32 %s, 9
+  ret i1 %c2
+}

Added: llvm/trunk/test/Transforms/InstSimplify/compare.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstSimplify/compare.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstSimplify/compare.ll (added)
+++ llvm/trunk/test/Transforms/InstSimplify/compare.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,1361 @@
+; RUN: opt < %s -instsimplify -S | FileCheck %s
+target datalayout = "p:32:32"
+
+define i1 @ptrtoint() {
+; CHECK-LABEL: @ptrtoint(
+  %a = alloca i8
+  %tmp = ptrtoint i8* %a to i32
+  %r = icmp eq i32 %tmp, 0
+  ret i1 %r
+; CHECK: ret i1 false
+}
+
+define i1 @bitcast() {
+; CHECK-LABEL: @bitcast(
+  %a = alloca i32
+  %b = alloca i64
+  %x = bitcast i32* %a to i8*
+  %y = bitcast i64* %b to i8*
+  %cmp = icmp eq i8* %x, %y
+  ret i1 %cmp
+; CHECK-NEXT: ret i1 false
+}
+
+define i1 @gep() {
+; CHECK-LABEL: @gep(
+  %a = alloca [3 x i8], align 8
+  %x = getelementptr inbounds [3 x i8], [3 x i8]* %a, i32 0, i32 0
+  %cmp = icmp eq i8* %x, null
+  ret i1 %cmp
+; CHECK-NEXT: ret i1 false
+}
+
+define i1 @gep2() {
+; CHECK-LABEL: @gep2(
+  %a = alloca [3 x i8], align 8
+  %x = getelementptr inbounds [3 x i8], [3 x i8]* %a, i32 0, i32 0
+  %y = getelementptr inbounds [3 x i8], [3 x i8]* %a, i32 0, i32 0
+  %cmp = icmp eq i8* %x, %y
+  ret i1 %cmp
+; CHECK-NEXT: ret i1 true
+}
+
+; PR11238
+%gept = type { i32, i32 }
+ at gepy = global %gept zeroinitializer, align 8
+ at gepz = extern_weak global %gept
+
+define i1 @gep3() {
+; CHECK-LABEL: @gep3(
+  %x = alloca %gept, align 8
+  %a = getelementptr %gept, %gept* %x, i64 0, i32 0
+  %b = getelementptr %gept, %gept* %x, i64 0, i32 1
+  %equal = icmp eq i32* %a, %b
+  ret i1 %equal
+; CHECK-NEXT: ret i1 false
+}
+
+define i1 @gep4() {
+; CHECK-LABEL: @gep4(
+  %x = alloca %gept, align 8
+  %a = getelementptr %gept, %gept* @gepy, i64 0, i32 0
+  %b = getelementptr %gept, %gept* @gepy, i64 0, i32 1
+  %equal = icmp eq i32* %a, %b
+  ret i1 %equal
+; CHECK-NEXT: ret i1 false
+}
+
+ at a = common global [1 x i32] zeroinitializer, align 4
+
+define i1 @PR31262() {
+; CHECK-LABEL: @PR31262(
+; CHECK-NEXT:    ret i1 icmp uge (i32* getelementptr ([1 x i32], [1 x i32]* @a, i32 0, i32 undef), i32* getelementptr inbounds ([1 x i32], [1 x i32]* @a, i32 0, i32 0))
+;
+  %idx = getelementptr inbounds [1 x i32], [1 x i32]* @a, i64 0, i64 undef
+  %cmp = icmp uge i32* %idx, getelementptr inbounds ([1 x i32], [1 x i32]* @a, i32 0, i32 0)
+  ret i1 %cmp
+}
+
+define i1 @gep5() {
+; CHECK-LABEL: @gep5(
+  %x = alloca %gept, align 8
+  %a = getelementptr inbounds %gept, %gept* %x, i64 0, i32 1
+  %b = getelementptr %gept, %gept* @gepy, i64 0, i32 0
+  %equal = icmp eq i32* %a, %b
+  ret i1 %equal
+; CHECK-NEXT: ret i1 false
+}
+
+define i1 @gep6(%gept* %x) {
+; Same as @gep3 but potentially null.
+; CHECK-LABEL: @gep6(
+  %a = getelementptr %gept, %gept* %x, i64 0, i32 0
+  %b = getelementptr %gept, %gept* %x, i64 0, i32 1
+  %equal = icmp eq i32* %a, %b
+  ret i1 %equal
+; CHECK-NEXT: ret i1 false
+}
+
+define i1 @gep7(%gept* %x) {
+; CHECK-LABEL: @gep7(
+  %a = getelementptr %gept, %gept* %x, i64 0, i32 0
+  %b = getelementptr %gept, %gept* @gepz, i64 0, i32 0
+  %equal = icmp eq i32* %a, %b
+  ret i1 %equal
+; CHECK: ret i1 %equal
+}
+
+define i1 @gep8(%gept* %x) {
+; CHECK-LABEL: @gep8(
+  %a = getelementptr %gept, %gept* %x, i32 1
+  %b = getelementptr %gept, %gept* %x, i32 -1
+  %equal = icmp ugt %gept* %a, %b
+  ret i1 %equal
+; CHECK: ret i1 %equal
+}
+
+define i1 @gep9(i8* %ptr) {
+; CHECK-LABEL: @gep9(
+; CHECK-NOT: ret
+; CHECK: ret i1 true
+
+entry:
+  %first1 = getelementptr inbounds i8, i8* %ptr, i32 0
+  %first2 = getelementptr inbounds i8, i8* %first1, i32 1
+  %first3 = getelementptr inbounds i8, i8* %first2, i32 2
+  %first4 = getelementptr inbounds i8, i8* %first3, i32 4
+  %last1 = getelementptr inbounds i8, i8* %first2, i32 48
+  %last2 = getelementptr inbounds i8, i8* %last1, i32 8
+  %last3 = getelementptr inbounds i8, i8* %last2, i32 -4
+  %last4 = getelementptr inbounds i8, i8* %last3, i32 -4
+  %first.int = ptrtoint i8* %first4 to i32
+  %last.int = ptrtoint i8* %last4 to i32
+  %cmp = icmp ne i32 %last.int, %first.int
+  ret i1 %cmp
+}
+
+define i1 @gep10(i8* %ptr) {
+; CHECK-LABEL: @gep10(
+; CHECK-NOT: ret
+; CHECK: ret i1 true
+
+entry:
+  %first1 = getelementptr inbounds i8, i8* %ptr, i32 -2
+  %first2 = getelementptr inbounds i8, i8* %first1, i32 44
+  %last1 = getelementptr inbounds i8, i8* %ptr, i32 48
+  %last2 = getelementptr inbounds i8, i8* %last1, i32 -6
+  %first.int = ptrtoint i8* %first2 to i32
+  %last.int = ptrtoint i8* %last2 to i32
+  %cmp = icmp eq i32 %last.int, %first.int
+  ret i1 %cmp
+}
+
+define i1 @gep11(i8* %ptr) {
+; CHECK-LABEL: @gep11(
+; CHECK-NOT: ret
+; CHECK: ret i1 true
+
+entry:
+  %first1 = getelementptr inbounds i8, i8* %ptr, i32 -2
+  %last1 = getelementptr inbounds i8, i8* %ptr, i32 48
+  %last2 = getelementptr inbounds i8, i8* %last1, i32 -6
+  %cmp = icmp ult i8* %first1, %last2
+  ret i1 %cmp
+}
+
+define i1 @gep12(i8* %ptr) {
+; CHECK-LABEL: @gep12(
+; CHECK-NOT: ret
+; CHECK: ret i1 %cmp
+
+entry:
+  %first1 = getelementptr inbounds i8, i8* %ptr, i32 -2
+  %last1 = getelementptr inbounds i8, i8* %ptr, i32 48
+  %last2 = getelementptr inbounds i8, i8* %last1, i32 -6
+  %cmp = icmp slt i8* %first1, %last2
+  ret i1 %cmp
+}
+
+define i1 @gep13(i8* %ptr) {
+; CHECK-LABEL: @gep13(
+; We can prove this GEP is non-null because it is inbounds.
+  %x = getelementptr inbounds i8, i8* %ptr, i32 1
+  %cmp = icmp eq i8* %x, null
+  ret i1 %cmp
+; CHECK-NEXT: ret i1 false
+}
+
+define i1 @gep13_no_null_opt(i8* %ptr) #0 {
+; We can't prove this GEP is non-null.
+; CHECK-LABEL: @gep13_no_null_opt(
+; CHECK: getelementptr
+; CHECK: icmp
+; CHECK: ret
+  %x = getelementptr inbounds i8, i8* %ptr, i32 1
+  %cmp = icmp eq i8* %x, null
+  ret i1 %cmp
+}
+
+define i1 @gep14({ {}, i8 }* %ptr) {
+; CHECK-LABEL: @gep14(
+; We can't simplify this because the offset of one in the GEP actually doesn't
+; move the pointer.
+  %x = getelementptr inbounds { {}, i8 }, { {}, i8 }* %ptr, i32 0, i32 1
+  %cmp = icmp eq i8* %x, null
+  ret i1 %cmp
+; CHECK-NOT: ret i1 false
+}
+
+define i1 @gep15({ {}, [4 x {i8, i8}]}* %ptr, i32 %y) {
+; CHECK-LABEL: @gep15(
+; We can prove this GEP is non-null even though there is a user value, as we
+; would necessarily violate inbounds on one side or the other.
+  %x = getelementptr inbounds { {}, [4 x {i8, i8}]}, { {}, [4 x {i8, i8}]}* %ptr, i32 0, i32 1, i32 %y, i32 1
+  %cmp = icmp eq i8* %x, null
+  ret i1 %cmp
+; CHECK-NEXT: ret i1 false
+}
+
+define i1 @gep15_no_null_opt({ {}, [4 x {i8, i8}]}* %ptr, i32 %y) #0 {
+; We can't prove this GEP is non-null.
+; CHECK-LABEL: @gep15_no_null_opt(
+; CHECK: getelementptr
+; CHECK: icmp
+; CHECK: ret
+  %x = getelementptr inbounds { {}, [4 x {i8, i8}]}, { {}, [4 x {i8, i8}]}* %ptr, i32 0, i32 1, i32 %y, i32 1
+  %cmp = icmp eq i8* %x, null
+  ret i1 %cmp
+}
+
+define i1 @gep16(i8* %ptr, i32 %a) {
+; CHECK-LABEL: @gep16(
+; We can prove this GEP is non-null because it is inbounds and because we know
+; %b is non-zero even though we don't know its value.
+  %b = or i32 %a, 1
+  %x = getelementptr inbounds i8, i8* %ptr, i32 %b
+  %cmp = icmp eq i8* %x, null
+  ret i1 %cmp
+; CHECK-NEXT: ret i1 false
+}
+
+define i1 @gep16_no_null_opt(i8* %ptr, i32 %a) #0 {
+; We can't prove this GEP is non-null.
+; CHECK-LABEL: @gep16_no_null_opt(
+; CHECK getelementptr inbounds i8, i8* %ptr, i32 %b
+; CHECK: %cmp = icmp eq i8* %x, null
+; CHECK-NEXT: ret i1 %cmp
+  %b = or i32 %a, 1
+  %x = getelementptr inbounds i8, i8* %ptr, i32 %b
+  %cmp = icmp eq i8* %x, null
+  ret i1 %cmp
+}
+
+define i1 @gep17() {
+; CHECK-LABEL: @gep17(
+  %alloca = alloca i32, align 4
+  %bc = bitcast i32* %alloca to [4 x i8]*
+  %gep1 = getelementptr inbounds i32, i32* %alloca, i32 1
+  %pti1 = ptrtoint i32* %gep1 to i32
+  %gep2 = getelementptr inbounds [4 x i8], [4 x i8]* %bc, i32 0, i32 1
+  %pti2 = ptrtoint i8* %gep2 to i32
+  %cmp = icmp ugt i32 %pti1, %pti2
+  ret i1 %cmp
+; CHECK-NEXT: ret i1 true
+}
+
+define i1 @zext(i32 %x) {
+; CHECK-LABEL: @zext(
+  %e1 = zext i32 %x to i64
+  %e2 = zext i32 %x to i64
+  %r = icmp eq i64 %e1, %e2
+  ret i1 %r
+; CHECK: ret i1 true
+}
+
+define i1 @zext2(i1 %x) {
+; CHECK-LABEL: @zext2(
+  %e = zext i1 %x to i32
+  %c = icmp ne i32 %e, 0
+  ret i1 %c
+; CHECK: ret i1 %x
+}
+
+define i1 @zext3() {
+; CHECK-LABEL: @zext3(
+  %e = zext i1 1 to i32
+  %c = icmp ne i32 %e, 0
+  ret i1 %c
+; CHECK: ret i1 true
+}
+
+define i1 @sext(i32 %x) {
+; CHECK-LABEL: @sext(
+  %e1 = sext i32 %x to i64
+  %e2 = sext i32 %x to i64
+  %r = icmp eq i64 %e1, %e2
+  ret i1 %r
+; CHECK: ret i1 true
+}
+
+define i1 @sext2(i1 %x) {
+; CHECK-LABEL: @sext2(
+  %e = sext i1 %x to i32
+  %c = icmp ne i32 %e, 0
+  ret i1 %c
+; CHECK: ret i1 %x
+}
+
+define i1 @sext3() {
+; CHECK-LABEL: @sext3(
+  %e = sext i1 1 to i32
+  %c = icmp ne i32 %e, 0
+  ret i1 %c
+; CHECK: ret i1 true
+}
+
+define i1 @add(i32 %x, i32 %y) {
+; CHECK-LABEL: @add(
+  %l = lshr i32 %x, 1
+  %q = lshr i32 %y, 1
+  %r = or i32 %q, 1
+  %s = add i32 %l, %r
+  %c = icmp eq i32 %s, 0
+  ret i1 %c
+; CHECK: ret i1 false
+}
+
+define i1 @add2(i8 %x, i8 %y) {
+; CHECK-LABEL: @add2(
+  %l = or i8 %x, 128
+  %r = or i8 %y, 129
+  %s = add i8 %l, %r
+  %c = icmp eq i8 %s, 0
+  ret i1 %c
+; CHECK: ret i1 false
+}
+
+define i1 @add3(i8 %x, i8 %y) {
+; CHECK-LABEL: @add3(
+  %l = zext i8 %x to i32
+  %r = zext i8 %y to i32
+  %s = add i32 %l, %r
+  %c = icmp eq i32 %s, 0
+  ret i1 %c
+; CHECK: ret i1 %c
+}
+
+define i1 @add4(i32 %x, i32 %y) {
+; CHECK-LABEL: @add4(
+  %z = add nsw i32 %y, 1
+  %s1 = add nsw i32 %x, %y
+  %s2 = add nsw i32 %x, %z
+  %c = icmp slt i32 %s1, %s2
+  ret i1 %c
+; CHECK: ret i1 true
+}
+
+define i1 @add5(i32 %x, i32 %y) {
+; CHECK-LABEL: @add5(
+  %z = add nuw i32 %y, 1
+  %s1 = add nuw i32 %x, %z
+  %s2 = add nuw i32 %x, %y
+  %c = icmp ugt i32 %s1, %s2
+  ret i1 %c
+; CHECK: ret i1 true
+}
+
+define i1 @add6(i64 %A, i64 %B) {
+; CHECK-LABEL: @add6(
+  %s1 = add i64 %A, %B
+  %s2 = add i64 %B, %A
+  %cmp = icmp eq i64 %s1, %s2
+  ret i1 %cmp
+; CHECK: ret i1 true
+}
+
+define i1 @addpowtwo(i32 %x, i32 %y) {
+; CHECK-LABEL: @addpowtwo(
+  %l = lshr i32 %x, 1
+  %r = shl i32 1, %y
+  %s = add i32 %l, %r
+  %c = icmp eq i32 %s, 0
+  ret i1 %c
+; CHECK: ret i1 false
+}
+
+define i1 @or(i32 %x) {
+; CHECK-LABEL: @or(
+  %o = or i32 %x, 1
+  %c = icmp eq i32 %o, 0
+  ret i1 %c
+; CHECK: ret i1 false
+}
+
+; Do not simplify if we cannot guarantee that the ConstantExpr is a non-zero
+; constant.
+ at GV = common global i32* null
+define i1 @or_constexp(i32 %x) {
+; CHECK-LABEL: @or_constexp(
+entry:
+  %0 = and i32 ptrtoint (i32** @GV to i32), 32
+  %o = or i32 %x, %0
+  %c = icmp eq i32 %o, 0
+  ret i1 %c
+; CHECK: or
+; CHECK-NEXT: icmp eq
+; CHECK-NOT: ret i1 false
+}
+
+define i1 @shl1(i32 %x) {
+; CHECK-LABEL: @shl1(
+  %s = shl i32 1, %x
+  %c = icmp eq i32 %s, 0
+  ret i1 %c
+; CHECK: ret i1 false
+}
+
+define i1 @shl3(i32 %X) {
+; CHECK: @shl3
+  %sub = shl nuw i32 4, %X
+  %cmp = icmp eq i32 %sub, 31
+  ret i1 %cmp
+; CHECK-NEXT: ret i1 false
+}
+
+define i1 @lshr1(i32 %x) {
+; CHECK-LABEL: @lshr1(
+  %s = lshr i32 -1, %x
+  %c = icmp eq i32 %s, 0
+  ret i1 %c
+; CHECK: ret i1 false
+}
+
+define i1 @lshr3(i32 %x) {
+; CHECK-LABEL: @lshr3(
+  %s = lshr i32 %x, %x
+  %c = icmp eq i32 %s, 0
+  ret i1 %c
+; CHECK: ret i1 true
+}
+
+define i1 @lshr4(i32 %X, i32 %Y) {
+; CHECK-LABEL: @lshr4(
+  %A = lshr i32 %X, %Y
+  %C = icmp ule i32 %A, %X
+  ret i1 %C
+; CHECK: ret i1 true
+}
+
+define i1 @lshr5(i32 %X, i32 %Y) {
+; CHECK-LABEL: @lshr5(
+  %A = lshr i32 %X, %Y
+  %C = icmp ugt i32 %A, %X
+  ret i1 %C
+; CHECK: ret i1 false
+}
+
+define i1 @lshr6(i32 %X, i32 %Y) {
+; CHECK-LABEL: @lshr6(
+  %A = lshr i32 %X, %Y
+  %C = icmp ult i32 %X, %A
+  ret i1 %C
+; CHECK: ret i1 false
+}
+
+define i1 @lshr7(i32 %X, i32 %Y) {
+; CHECK-LABEL: @lshr7(
+  %A = lshr i32 %X, %Y
+  %C = icmp uge i32 %X, %A
+  ret i1 %C
+; CHECK: ret i1 true
+}
+
+define i1 @ashr1(i32 %x) {
+; CHECK-LABEL: @ashr1(
+  %s = ashr i32 -1, %x
+  %c = icmp eq i32 %s, 0
+  ret i1 %c
+; CHECK: ret i1 false
+}
+
+define i1 @ashr3(i32 %x) {
+; CHECK-LABEL: @ashr3(
+  %s = ashr i32 %x, %x
+  %c = icmp eq i32 %s, 0
+  ret i1 %c
+; CHECK: ret i1 true
+}
+
+define i1 @select1(i1 %cond) {
+; CHECK-LABEL: @select1(
+  %s = select i1 %cond, i32 1, i32 0
+  %c = icmp eq i32 %s, 1
+  ret i1 %c
+; CHECK: ret i1 %cond
+}
+
+define i1 @select2(i1 %cond) {
+; CHECK-LABEL: @select2(
+  %x = zext i1 %cond to i32
+  %s = select i1 %cond, i32 %x, i32 0
+  %c = icmp ne i32 %s, 0
+  ret i1 %c
+; CHECK: ret i1 %cond
+}
+
+define i1 @select3(i1 %cond) {
+; CHECK-LABEL: @select3(
+  %x = zext i1 %cond to i32
+  %s = select i1 %cond, i32 1, i32 %x
+  %c = icmp ne i32 %s, 0
+  ret i1 %c
+; CHECK: ret i1 %cond
+}
+
+define i1 @select4(i1 %cond) {
+; CHECK-LABEL: @select4(
+  %invert = xor i1 %cond, 1
+  %s = select i1 %invert, i32 0, i32 1
+  %c = icmp ne i32 %s, 0
+  ret i1 %c
+; CHECK: ret i1 %cond
+}
+
+define i1 @select5(i32 %x) {
+; CHECK-LABEL: @select5(
+  %c = icmp eq i32 %x, 0
+  %s = select i1 %c, i32 1, i32 %x
+  %c2 = icmp eq i32 %s, 0
+  ret i1 %c2
+; CHECK: ret i1 false
+}
+
+define i1 @select6(i32 %x) {
+; CHECK-LABEL: @select6(
+  %c = icmp sgt i32 %x, 0
+  %s = select i1 %c, i32 %x, i32 4
+  %c2 = icmp eq i32 %s, 0
+  ret i1 %c2
+; CHECK: ret i1 %c2
+}
+
+define i1 @urem1(i32 %X, i32 %Y) {
+; CHECK-LABEL: @urem1(
+  %A = urem i32 %X, %Y
+  %B = icmp ult i32 %A, %Y
+  ret i1 %B
+; CHECK: ret i1 true
+}
+
+define i1 @urem2(i32 %X, i32 %Y) {
+; CHECK-LABEL: @urem2(
+  %A = urem i32 %X, %Y
+  %B = icmp eq i32 %A, %Y
+  ret i1 %B
+; CHECK: ret i1 false
+}
+
+define i1 @urem4(i32 %X) {
+; CHECK-LABEL: @urem4(
+  %A = urem i32 %X, 15
+  %B = icmp ult i32 %A, 10
+  ret i1 %B
+; CHECK: ret i1 %B
+}
+
+define i1 @urem5(i16 %X, i32 %Y) {
+; CHECK-LABEL: @urem5(
+  %A = zext i16 %X to i32
+  %B = urem i32 %A, %Y
+  %C = icmp slt i32 %B, %Y
+  ret i1 %C
+; CHECK-NOT: ret i1 true
+}
+
+define i1 @urem6(i32 %X, i32 %Y) {
+; CHECK-LABEL: @urem6(
+  %A = urem i32 %X, %Y
+  %B = icmp ugt i32 %Y, %A
+  ret i1 %B
+; CHECK: ret i1 true
+}
+
+define i1 @urem7(i32 %X) {
+; CHECK-LABEL: @urem7(
+  %A = urem i32 1, %X
+  %B = icmp sgt i32 %A, %X
+  ret i1 %B
+; CHECK-NOT: ret i1 false
+}
+
+; PR9343 #15
+; CHECK-LABEL: @srem2(
+; CHECK: ret i1 false
+define i1 @srem2(i16 %X, i32 %Y) {
+  %A = zext i16 %X to i32
+  %B = add nsw i32 %A, 1
+  %C = srem i32 %B, %Y
+  %D = icmp slt i32 %C, 0
+  ret i1 %D
+}
+
+; CHECK-LABEL: @srem3(
+; CHECK-NEXT: ret i1 false
+define i1 @srem3(i16 %X, i32 %Y) {
+  %A = zext i16 %X to i32
+  %B = or i32 2147483648, %A
+  %C = sub nsw i32 1, %B
+  %D = srem i32 %C, %Y
+  %E = icmp slt i32 %D, 0
+  ret i1 %E
+}
+
+define i1 @udiv2(i32 %Z) {
+; CHECK-LABEL: @udiv2(
+; CHECK-NEXT:    ret i1 true
+;
+  %A = udiv exact i32 10, %Z
+  %B = udiv exact i32 20, %Z
+  %C = icmp ult i32 %A, %B
+  ret i1 %C
+}
+
+; Exact sdiv and equality preds can simplify.
+
+define i1 @sdiv_exact_equality(i32 %Z) {
+; CHECK-LABEL: @sdiv_exact_equality(
+; CHECK-NEXT:    ret i1 false
+;
+  %A = sdiv exact i32 10, %Z
+  %B = sdiv exact i32 20, %Z
+  %C = icmp eq i32 %A, %B
+  ret i1 %C
+}
+
+; But not other preds: PR32949 - https://bugs.llvm.org/show_bug.cgi?id=32949
+
+define i1 @sdiv_exact_not_equality(i32 %Z) {
+; CHECK-LABEL: @sdiv_exact_not_equality(
+; CHECK-NEXT:    [[A:%.*]] = sdiv exact i32 10, %Z
+; CHECK-NEXT:    [[B:%.*]] = sdiv exact i32 20, %Z
+; CHECK-NEXT:    [[C:%.*]] = icmp ult i32 [[A]], [[B]]
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %A = sdiv exact i32 10, %Z
+  %B = sdiv exact i32 20, %Z
+  %C = icmp ult i32 %A, %B
+  ret i1 %C
+}
+
+define i1 @udiv3(i32 %X, i32 %Y) {
+; CHECK-LABEL: @udiv3(
+  %A = udiv i32 %X, %Y
+  %C = icmp ugt i32 %A, %X
+  ret i1 %C
+; CHECK: ret i1 false
+}
+
+define i1 @udiv4(i32 %X, i32 %Y) {
+; CHECK-LABEL: @udiv4(
+  %A = udiv i32 %X, %Y
+  %C = icmp ule i32 %A, %X
+  ret i1 %C
+; CHECK: ret i1 true
+}
+
+; PR11340
+define i1 @udiv6(i32 %X) nounwind {
+; CHECK-LABEL: @udiv6(
+  %A = udiv i32 1, %X
+  %C = icmp eq i32 %A, 0
+  ret i1 %C
+; CHECK: ret i1 %C
+}
+
+define i1 @udiv7(i32 %X, i32 %Y) {
+; CHECK-LABEL: @udiv7(
+  %A = udiv i32 %X, %Y
+  %C = icmp ult i32 %X, %A
+  ret i1 %C
+; CHECK: ret i1 false
+}
+
+define i1 @udiv8(i32 %X, i32 %Y) {
+; CHECK-LABEL: @udiv8(
+  %A = udiv i32 %X, %Y
+  %C = icmp uge i32 %X, %A
+  ret i1 %C
+; CHECK: ret i1 true
+}
+
+define i1 @mul1(i32 %X) {
+; CHECK-LABEL: @mul1(
+; Square of a non-zero number is non-zero if there is no overflow.
+  %Y = or i32 %X, 1
+  %M = mul nuw i32 %Y, %Y
+  %C = icmp eq i32 %M, 0
+  ret i1 %C
+; CHECK: ret i1 false
+}
+
+define i1 @mul2(i32 %X) {
+; CHECK-LABEL: @mul2(
+; Square of a non-zero number is positive if there is no signed overflow.
+  %Y = or i32 %X, 1
+  %M = mul nsw i32 %Y, %Y
+  %C = icmp sgt i32 %M, 0
+  ret i1 %C
+; CHECK: ret i1 true
+}
+
+define i1 @mul3(i32 %X, i32 %Y) {
+; CHECK-LABEL: @mul3(
+; Product of non-negative numbers is non-negative if there is no signed overflow.
+  %XX = mul nsw i32 %X, %X
+  %YY = mul nsw i32 %Y, %Y
+  %M = mul nsw i32 %XX, %YY
+  %C = icmp sge i32 %M, 0
+  ret i1 %C
+; CHECK: ret i1 true
+}
+
+define <2 x i1> @vectorselect1(<2 x i1> %cond) {
+; CHECK-LABEL: @vectorselect1(
+  %invert = xor <2 x i1> %cond, <i1 1, i1 1>
+  %s = select <2 x i1> %invert, <2 x i32> <i32 0, i32 0>, <2 x i32> <i32 1, i32 1>
+  %c = icmp ne <2 x i32> %s, <i32 0, i32 0>
+  ret <2 x i1> %c
+; CHECK: ret <2 x i1> %cond
+}
+
+; PR11948
+define <2 x i1> @vectorselectcrash(i32 %arg1) {
+  %tobool40 = icmp ne i32 %arg1, 0
+  %cond43 = select i1 %tobool40, <2 x i16> <i16 -5, i16 66>, <2 x i16> <i16 46, i16 1>
+  %cmp45 = icmp ugt <2 x i16> %cond43, <i16 73, i16 21>
+  ret <2 x i1> %cmp45
+}
+
+; PR12013
+define i1 @alloca_compare(i64 %idx) {
+  %sv = alloca { i32, i32, [124 x i32] }
+  %1 = getelementptr inbounds { i32, i32, [124 x i32] }, { i32, i32, [124 x i32] }* %sv, i32 0, i32 2, i64 %idx
+  %2 = icmp eq i32* %1, null
+  ret i1 %2
+  ; CHECK: alloca_compare
+  ; CHECK: ret i1 false
+}
+
+define i1 @alloca_compare_no_null_opt(i64 %idx) #0 {
+; CHECK-LABEL: alloca_compare_no_null_opt(
+; CHECK: %sv = alloca { i32, i32, [124 x i32] }
+; CHECK: %cmp = getelementptr inbounds { i32, i32, [124 x i32] }, { i32, i32, [124 x i32] }* %sv, i32 0, i32 2, i64 %idx
+; CHECK: %X = icmp eq i32* %cmp, null
+; CHECK: ret i1 %X
+  %sv = alloca { i32, i32, [124 x i32] }
+  %cmp = getelementptr inbounds { i32, i32, [124 x i32] }, { i32, i32, [124 x i32] }* %sv, i32 0, i32 2, i64 %idx
+  %X = icmp eq i32* %cmp, null
+  ret i1 %X
+}
+; PR12075
+define i1 @infinite_gep() {
+  ret i1 1
+
+unreachableblock:
+  %X = getelementptr i32, i32 *%X, i32 1
+  %Y = icmp eq i32* %X, null
+  ret i1 %Y
+}
+
+; It's not valid to fold a comparison of an argument with an alloca, even though
+; that's tempting. An argument can't *alias* an alloca, however the aliasing rule
+; relies on restrictions against guessing an object's address and dereferencing.
+; There are no restrictions against guessing an object's address and comparing.
+
+define i1 @alloca_argument_compare(i64* %arg) {
+  %alloc = alloca i64
+  %cmp = icmp eq i64* %arg, %alloc
+  ret i1 %cmp
+  ; CHECK: alloca_argument_compare
+  ; CHECK: ret i1 %cmp
+}
+
+; As above, but with the operands reversed.
+
+define i1 @alloca_argument_compare_swapped(i64* %arg) {
+  %alloc = alloca i64
+  %cmp = icmp eq i64* %alloc, %arg
+  ret i1 %cmp
+  ; CHECK: alloca_argument_compare_swapped
+  ; CHECK: ret i1 %cmp
+}
+
+; Don't assume that a noalias argument isn't equal to a global variable's
+; address. This is an example where AliasAnalysis' NoAlias concept is
+; different from actual pointer inequality.
+
+ at y = external global i32
+define zeroext i1 @external_compare(i32* noalias %x) {
+  %cmp = icmp eq i32* %x, @y
+  ret i1 %cmp
+  ; CHECK: external_compare
+  ; CHECK: ret i1 %cmp
+}
+
+define i1 @alloca_gep(i64 %a, i64 %b) {
+; CHECK-LABEL: @alloca_gep(
+; We can prove this GEP is non-null because it is inbounds and the pointer
+; is non-null.
+  %strs = alloca [1000 x [1001 x i8]], align 16
+  %x = getelementptr inbounds [1000 x [1001 x i8]], [1000 x [1001 x i8]]* %strs, i64 0, i64 %a, i64 %b
+  %cmp = icmp eq i8* %x, null
+  ret i1 %cmp
+; CHECK-NEXT: ret i1 false
+}
+
+define i1 @alloca_gep_no_null_opt(i64 %a, i64 %b) #0 {
+; CHECK-LABEL: @alloca_gep_no_null_opt(
+; We can't prove this GEP is non-null.
+; CHECK: alloca
+; CHECK: getelementptr
+; CHECK: icmp
+; CHECK: ret
+  %strs = alloca [1000 x [1001 x i8]], align 16
+  %x = getelementptr inbounds [1000 x [1001 x i8]], [1000 x [1001 x i8]]* %strs, i64 0, i64 %a, i64 %b
+  %cmp = icmp eq i8* %x, null
+  ret i1 %cmp
+}
+
+define i1 @non_inbounds_gep_compare(i64* %a) {
+; CHECK-LABEL: @non_inbounds_gep_compare(
+; Equality compares with non-inbounds GEPs can be folded.
+  %x = getelementptr i64, i64* %a, i64 42
+  %y = getelementptr inbounds i64, i64* %x, i64 -42
+  %z = getelementptr i64, i64* %a, i64 -42
+  %w = getelementptr inbounds i64, i64* %z, i64 42
+  %cmp = icmp eq i64* %y, %w
+  ret i1 %cmp
+; CHECK-NEXT: ret i1 true
+}
+
+define i1 @non_inbounds_gep_compare2(i64* %a) {
+; CHECK-LABEL: @non_inbounds_gep_compare2(
+; Equality compares with non-inbounds GEPs can be folded.
+  %x = getelementptr i64, i64* %a, i64 4294967297
+  %y = getelementptr i64, i64* %a, i64 1
+  %cmp = icmp eq i64* %y, %y
+  ret i1 %cmp
+; CHECK-NEXT: ret i1 true
+}
+
+define i1 @compare_always_true_slt(i16 %a) {
+  %1 = zext i16 %a to i32
+  %2 = sub nsw i32 0, %1
+  %3 = icmp slt i32 %2, 1
+  ret i1 %3
+
+; CHECK-LABEL: @compare_always_true_slt
+; CHECK-NEXT: ret i1 true
+}
+
+define i1 @compare_always_true_sle(i16 %a) {
+  %1 = zext i16 %a to i32
+  %2 = sub nsw i32 0, %1
+  %3 = icmp sle i32 %2, 0
+  ret i1 %3
+
+; CHECK-LABEL: @compare_always_true_sle
+; CHECK-NEXT: ret i1 true
+}
+
+define i1 @compare_always_false_sgt(i16 %a) {
+  %1 = zext i16 %a to i32
+  %2 = sub nsw i32 0, %1
+  %3 = icmp sgt i32 %2, 0
+  ret i1 %3
+
+; CHECK-LABEL: @compare_always_false_sgt
+; CHECK-NEXT: ret i1 false
+}
+
+define i1 @compare_always_false_sge(i16 %a) {
+  %1 = zext i16 %a to i32
+  %2 = sub nsw i32 0, %1
+  %3 = icmp sge i32 %2, 1
+  ret i1 %3
+
+; CHECK-LABEL: @compare_always_false_sge
+; CHECK-NEXT: ret i1 false
+}
+
+define i1 @compare_always_false_eq(i16 %a) {
+  %1 = zext i16 %a to i32
+  %2 = sub nsw i32 0, %1
+  %3 = icmp eq i32 %2, 1
+  ret i1 %3
+
+; CHECK-LABEL: @compare_always_false_eq
+; CHECK-NEXT: ret i1 false
+}
+
+define i1 @compare_always_false_ne(i16 %a) {
+  %1 = zext i16 %a to i32
+  %2 = sub nsw i32 0, %1
+  %3 = icmp ne i32 %2, 1
+  ret i1 %3
+
+; CHECK-LABEL: @compare_always_false_ne
+; CHECK-NEXT: ret i1 true
+}
+
+define i1 @lshr_ugt_false(i32 %a) {
+  %shr = lshr i32 1, %a
+  %cmp = icmp ugt i32 %shr, 1
+  ret i1 %cmp
+; CHECK-LABEL: @lshr_ugt_false
+; CHECK-NEXT: ret i1 false
+}
+
+define i1 @nonnull_arg(i32* nonnull %i) {
+  %cmp = icmp eq i32* %i, null
+  ret i1 %cmp
+; CHECK-LABEL: @nonnull_arg
+; CHECK: ret i1 false
+}
+
+define i1 @nonnull_arg_no_null_opt(i32* nonnull %i) #0 {
+  %cmp = icmp eq i32* %i, null
+  ret i1 %cmp
+; CHECK-LABEL: @nonnull_arg_no_null_opt
+; CHECK: ret i1 false
+}
+
+define i1 @nonnull_deref_arg(i32* dereferenceable(4) %i) {
+  %cmp = icmp eq i32* %i, null
+  ret i1 %cmp
+; CHECK-LABEL: @nonnull_deref_arg
+; CHECK: ret i1 false
+}
+
+define i1 @nonnull_deref_arg_no_null_opt(i32* dereferenceable(4) %i) #0 {
+  %cmp = icmp eq i32* %i, null
+  ret i1 %cmp
+; CHECK-LABEL: @nonnull_deref_arg_no_null_opt
+; CHECK-NEXT: icmp
+; CHECK: ret
+}
+define i1 @nonnull_deref_as_arg(i32 addrspace(1)* dereferenceable(4) %i) {
+  %cmp = icmp eq i32 addrspace(1)* %i, null
+  ret i1 %cmp
+; CHECK-LABEL: @nonnull_deref_as_arg
+; CHECK: icmp
+; CHECK: ret
+}
+
+declare nonnull i32* @returns_nonnull_helper()
+define i1 @returns_nonnull() {
+  %call = call nonnull i32* @returns_nonnull_helper()
+  %cmp = icmp eq i32* %call, null
+  ret i1 %cmp
+; CHECK-LABEL: @returns_nonnull
+; CHECK: ret i1 false
+}
+
+declare dereferenceable(4) i32* @returns_nonnull_deref_helper()
+define i1 @returns_nonnull_deref() {
+  %call = call dereferenceable(4) i32* @returns_nonnull_deref_helper()
+  %cmp = icmp eq i32* %call, null
+  ret i1 %cmp
+; CHECK-LABEL: @returns_nonnull_deref
+; CHECK: ret i1 false
+}
+
+define i1 @returns_nonnull_deref_no_null_opt () #0 {
+  %call = call dereferenceable(4) i32* @returns_nonnull_deref_helper()
+  %cmp = icmp eq i32* %call, null
+  ret i1 %cmp
+; CHECK-LABEL: @returns_nonnull_deref_no_null_opt
+; CHECK: icmp
+; CHECK: ret
+}
+
+declare dereferenceable(4) i32 addrspace(1)* @returns_nonnull_deref_as_helper()
+define i1 @returns_nonnull_as_deref() {
+  %call = call dereferenceable(4) i32 addrspace(1)* @returns_nonnull_deref_as_helper()
+  %cmp = icmp eq i32 addrspace(1)* %call, null
+  ret i1 %cmp
+; CHECK-LABEL: @returns_nonnull_as_deref
+; CHECK: icmp
+; CHECK: ret
+}
+
+define i1 @nonnull_load(i32** %addr) {
+  %ptr = load i32*, i32** %addr, !nonnull !{}
+  %cmp = icmp eq i32* %ptr, null
+  ret i1 %cmp
+; CHECK-LABEL: @nonnull_load
+; CHECK: ret i1 false
+}
+
+define i1 @nonnull_load_as_outer(i32* addrspace(1)* %addr) {
+  %ptr = load i32*, i32* addrspace(1)* %addr, !nonnull !{}
+  %cmp = icmp eq i32* %ptr, null
+  ret i1 %cmp
+; CHECK-LABEL: @nonnull_load_as_outer
+; CHECK: ret i1 false
+}
+define i1 @nonnull_load_as_inner(i32 addrspace(1)** %addr) {
+  %ptr = load i32 addrspace(1)*, i32 addrspace(1)** %addr, !nonnull !{}
+  %cmp = icmp eq i32 addrspace(1)* %ptr, null
+  ret i1 %cmp
+; CHECK-LABEL: @nonnull_load_as_inner
+; CHECK: ret i1 false
+}
+
+; If a bit is known to be zero for A and known to be one for B,
+; then A and B cannot be equal.
+define i1 @icmp_eq_const(i32 %a) {
+; CHECK-LABEL: @icmp_eq_const(
+; CHECK-NEXT:    ret i1 false
+;
+  %b = mul nsw i32 %a, -2
+  %c = icmp eq i32 %b, 1
+  ret i1 %c
+}
+
+define <2 x i1> @icmp_eq_const_vec(<2 x i32> %a) {
+; CHECK-LABEL: @icmp_eq_const_vec(
+; CHECK-NEXT:    ret <2 x i1> zeroinitializer
+;
+  %b = mul nsw <2 x i32> %a, <i32 -2, i32 -2>
+  %c = icmp eq <2 x i32> %b, <i32 1, i32 1>
+  ret <2 x i1> %c
+}
+
+define i1 @icmp_ne_const(i32 %a) {
+; CHECK-LABEL: @icmp_ne_const(
+; CHECK-NEXT:    ret i1 true
+;
+  %b = mul nsw i32 %a, -2
+  %c = icmp ne i32 %b, 1
+  ret i1 %c
+}
+
+define <2 x i1> @icmp_ne_const_vec(<2 x i32> %a) {
+; CHECK-LABEL: @icmp_ne_const_vec(
+; CHECK-NEXT:    ret <2 x i1> <i1 true, i1 true>
+;
+  %b = mul nsw <2 x i32> %a, <i32 -2, i32 -2>
+  %c = icmp ne <2 x i32> %b, <i32 1, i32 1>
+  ret <2 x i1> %c
+}
+
+define i1 @icmp_sdiv_int_min(i32 %a) {
+  %div = sdiv i32 -2147483648, %a
+  %cmp = icmp ne i32 %div, -1073741824
+  ret i1 %cmp
+
+; CHECK-LABEL: @icmp_sdiv_int_min
+; CHECK-NEXT: [[DIV:%.*]] = sdiv i32 -2147483648, %a
+; CHECK-NEXT: [[CMP:%.*]] = icmp ne i32 [[DIV]], -1073741824
+; CHECK-NEXT: ret i1 [[CMP]]
+}
+
+define i1 @icmp_sdiv_pr20288(i64 %a) {
+   %div = sdiv i64 %a, -8589934592
+   %cmp = icmp ne i64 %div, 1073741824
+   ret i1 %cmp
+
+; CHECK-LABEL: @icmp_sdiv_pr20288
+; CHECK-NEXT: [[DIV:%.*]] = sdiv i64 %a, -8589934592
+; CHECK-NEXT: [[CMP:%.*]] = icmp ne i64 [[DIV]], 1073741824
+; CHECK-NEXT: ret i1 [[CMP]]
+}
+
+define i1 @icmp_sdiv_neg1(i64 %a) {
+ %div = sdiv i64 %a, -1
+ %cmp = icmp ne i64 %div, 1073741824
+ ret i1 %cmp
+
+; CHECK-LABEL: @icmp_sdiv_neg1
+; CHECK-NEXT: [[DIV:%.*]] = sdiv i64 %a, -1
+; CHECK-NEXT: [[CMP:%.*]] = icmp ne i64 [[DIV]], 1073741824
+; CHECK-NEXT: ret i1 [[CMP]]
+}
+
+define i1 @icmp_known_bits(i4 %x, i4 %y) {
+  %and1 = and i4 %y, -7
+  %and2 = and i4 %x, -7
+  %or1 = or i4 %and1, 2
+  %or2 = or i4 %and2, 2
+  %add = add i4 %or1, %or2
+  %cmp = icmp eq i4 %add, 0
+  ret i1 %cmp
+
+; CHECK-LABEL: @icmp_known_bits
+; CHECK-NEXT: ret i1 false
+}
+
+define i1 @icmp_shl_nuw_1(i64 %a) {
+ %shl = shl nuw i64 1, %a
+ %cmp = icmp ne i64 %shl, 0
+ ret i1 %cmp
+
+; CHECK-LABEL: @icmp_shl_nuw_1
+; CHECK-NEXT: ret i1 true
+}
+
+define i1 @icmp_shl_1_V_ugt_2147483648(i32 %V) {
+  %shl = shl i32 1, %V
+  %cmp = icmp ugt i32 %shl, 2147483648
+  ret i1 %cmp
+
+; CHECK-LABEL: @icmp_shl_1_V_ugt_2147483648(
+; CHECK-NEXT: ret i1 false
+}
+
+define i1 @icmp_shl_1_V_ule_2147483648(i32 %V) {
+  %shl = shl i32 1, %V
+  %cmp = icmp ule i32 %shl, 2147483648
+  ret i1 %cmp
+
+; CHECK-LABEL: @icmp_shl_1_V_ule_2147483648(
+; CHECK-NEXT: ret i1 true
+}
+
+define i1 @icmp_shl_1_V_eq_31(i32 %V) {
+  %shl = shl i32 1, %V
+  %cmp = icmp eq i32 %shl, 31
+  ret i1 %cmp
+
+; CHECK-LABEL: @icmp_shl_1_V_eq_31(
+; CHECK-NEXT: ret i1 false
+}
+
+define i1 @icmp_shl_1_V_ne_31(i32 %V) {
+  %shl = shl i32 1, %V
+  %cmp = icmp ne i32 %shl, 31
+  ret i1 %cmp
+
+; CHECK-LABEL: @icmp_shl_1_V_ne_31(
+; CHECK-NEXT: ret i1 true
+}
+
+define i1 @tautological1(i32 %A, i32 %B) {
+  %C = and i32 %A, %B
+  %D = icmp ugt i32 %C, %A
+  ret i1 %D
+; CHECK-LABEL: @tautological1(
+; CHECK: ret i1 false
+}
+
+define i1 @tautological2(i32 %A, i32 %B) {
+  %C = and i32 %A, %B
+  %D = icmp ule i32 %C, %A
+  ret i1 %D
+; CHECK-LABEL: @tautological2(
+; CHECK: ret i1 true
+}
+
+define i1 @tautological3(i32 %A, i32 %B) {
+  %C = or i32 %A, %B
+  %D = icmp ule i32 %A, %C
+  ret i1 %D
+; CHECK-LABEL: @tautological3(
+; CHECK: ret i1 true
+}
+
+define i1 @tautological4(i32 %A, i32 %B) {
+  %C = or i32 %A, %B
+  %D = icmp ugt i32 %A, %C
+  ret i1 %D
+; CHECK-LABEL: @tautological4(
+; CHECK: ret i1 false
+}
+
+define i1 @tautological5(i32 %A, i32 %B) {
+  %C = or i32 %A, %B
+  %D = icmp ult i32 %C, %A
+  ret i1 %D
+; CHECK-LABEL: @tautological5(
+; CHECK: ret i1 false
+}
+
+define i1 @tautological6(i32 %A, i32 %B) {
+  %C = or i32 %A, %B
+  %D = icmp uge i32 %C, %A
+  ret i1 %D
+; CHECK-LABEL: @tautological6(
+; CHECK: ret i1 true
+}
+
+define i1 @tautological7(i32 %A, i32 %B) {
+  %C = and i32 %A, %B
+  %D = icmp uge i32 %A, %C
+  ret i1 %D
+; CHECK-LABEL: @tautological7(
+; CHECK: ret i1 true
+}
+
+define i1 @tautological8(i32 %A, i32 %B) {
+  %C = and i32 %A, %B
+  %D = icmp ult i32 %A, %C
+  ret i1 %D
+; CHECK-LABEL: @tautological8(
+; CHECK: ret i1 false
+}
+
+declare void @helper_i1(i1)
+; Series of tests for icmp s[lt|ge] (or A, B), A and icmp s[gt|le] A, (or A, B)
+define void @icmp_slt_sge_or(i32 %Ax, i32 %Bx) {
+; 'p' for positive, 'n' for negative, 'x' for potentially either.
+; %D is 'icmp slt (or A, B), A'
+; %E is 'icmp sge (or A, B), A' making it the not of %D
+; %F is 'icmp sgt A, (or A, B)' making it the same as %D
+; %G is 'icmp sle A, (or A, B)' making it the not of %D
+  %Aneg = or i32 %Ax, 2147483648
+  %Apos = and i32 %Ax, 2147483647
+  %Bneg = or i32 %Bx, 2147483648
+  %Bpos = and i32 %Bx, 2147483647
+
+  %Cpp = or i32 %Apos, %Bpos
+  %Dpp = icmp slt i32 %Cpp, %Apos
+  %Epp = icmp sge i32 %Cpp, %Apos
+  %Fpp = icmp sgt i32 %Apos, %Cpp
+  %Gpp = icmp sle i32 %Apos, %Cpp
+  %Cpx = or i32 %Apos, %Bx
+  %Dpx = icmp slt i32 %Cpx, %Apos
+  %Epx = icmp sge i32 %Cpx, %Apos
+  %Fpx = icmp sgt i32 %Apos, %Cpx
+  %Gpx = icmp sle i32 %Apos, %Cpx
+  %Cpn = or i32 %Apos, %Bneg
+  %Dpn = icmp slt i32 %Cpn, %Apos
+  %Epn = icmp sge i32 %Cpn, %Apos
+  %Fpn = icmp sgt i32 %Apos, %Cpn
+  %Gpn = icmp sle i32 %Apos, %Cpn
+
+  %Cxp = or i32 %Ax, %Bpos
+  %Dxp = icmp slt i32 %Cxp, %Ax
+  %Exp = icmp sge i32 %Cxp, %Ax
+  %Fxp = icmp sgt i32 %Ax, %Cxp
+  %Gxp = icmp sle i32 %Ax, %Cxp
+  %Cxx = or i32 %Ax, %Bx
+  %Dxx = icmp slt i32 %Cxx, %Ax
+  %Exx = icmp sge i32 %Cxx, %Ax
+  %Fxx = icmp sgt i32 %Ax, %Cxx
+  %Gxx = icmp sle i32 %Ax, %Cxx
+  %Cxn = or i32 %Ax, %Bneg
+  %Dxn = icmp slt i32 %Cxn, %Ax
+  %Exn = icmp sge i32 %Cxn, %Ax
+  %Fxn = icmp sgt i32 %Ax, %Cxn
+  %Gxn = icmp sle i32 %Ax, %Cxn
+
+  %Cnp = or i32 %Aneg, %Bpos
+  %Dnp = icmp slt i32 %Cnp, %Aneg
+  %Enp = icmp sge i32 %Cnp, %Aneg
+  %Fnp = icmp sgt i32 %Aneg, %Cnp
+  %Gnp = icmp sle i32 %Aneg, %Cnp
+  %Cnx = or i32 %Aneg, %Bx
+  %Dnx = icmp slt i32 %Cnx, %Aneg
+  %Enx = icmp sge i32 %Cnx, %Aneg
+  %Fnx = icmp sgt i32 %Aneg, %Cnx
+  %Gnx = icmp sle i32 %Aneg, %Cnx
+  %Cnn = or i32 %Aneg, %Bneg
+  %Dnn = icmp slt i32 %Cnn, %Aneg
+  %Enn = icmp sge i32 %Cnn, %Aneg
+  %Fnn = icmp sgt i32 %Aneg, %Cnn
+  %Gnn = icmp sle i32 %Aneg, %Cnn
+
+  call void @helper_i1(i1 %Dpp)
+  call void @helper_i1(i1 %Epp)
+  call void @helper_i1(i1 %Fpp)
+  call void @helper_i1(i1 %Gpp)
+  call void @helper_i1(i1 %Dpx)
+  call void @helper_i1(i1 %Epx)
+  call void @helper_i1(i1 %Fpx)
+  call void @helper_i1(i1 %Gpx)
+  call void @helper_i1(i1 %Dpn)
+  call void @helper_i1(i1 %Epn)
+  call void @helper_i1(i1 %Fpn)
+  call void @helper_i1(i1 %Gpn)
+  call void @helper_i1(i1 %Dxp)
+  call void @helper_i1(i1 %Exp)
+  call void @helper_i1(i1 %Fxp)
+  call void @helper_i1(i1 %Gxp)
+  call void @helper_i1(i1 %Dxx)
+  call void @helper_i1(i1 %Exx)
+  call void @helper_i1(i1 %Fxx)
+  call void @helper_i1(i1 %Gxx)
+  call void @helper_i1(i1 %Dxn)
+  call void @helper_i1(i1 %Exn)
+  call void @helper_i1(i1 %Fxn)
+  call void @helper_i1(i1 %Gxn)
+  call void @helper_i1(i1 %Dnp)
+  call void @helper_i1(i1 %Enp)
+  call void @helper_i1(i1 %Fnp)
+  call void @helper_i1(i1 %Gnp)
+  call void @helper_i1(i1 %Dnx)
+  call void @helper_i1(i1 %Enx)
+  call void @helper_i1(i1 %Fnx)
+  call void @helper_i1(i1 %Gnx)
+  call void @helper_i1(i1 %Dnn)
+  call void @helper_i1(i1 %Enn)
+  call void @helper_i1(i1 %Fnn)
+  call void @helper_i1(i1 %Gnn)
+; CHECK-LABEL: @icmp_slt_sge_or
+; CHECK: call void @helper_i1(i1 false)
+; CHECK: call void @helper_i1(i1 true)
+; CHECK: call void @helper_i1(i1 false)
+; CHECK: call void @helper_i1(i1 true)
+; CHECK: call void @helper_i1(i1 %Dpx)
+; CHECK: call void @helper_i1(i1 %Epx)
+; CHECK: call void @helper_i1(i1 %Fpx)
+; CHECK: call void @helper_i1(i1 %Gpx)
+; CHECK: call void @helper_i1(i1 true)
+; CHECK: call void @helper_i1(i1 false)
+; CHECK: call void @helper_i1(i1 true)
+; CHECK: call void @helper_i1(i1 false)
+; CHECK: call void @helper_i1(i1 false)
+; CHECK: call void @helper_i1(i1 true)
+; CHECK: call void @helper_i1(i1 false)
+; CHECK: call void @helper_i1(i1 true)
+; CHECK: call void @helper_i1(i1 %Dxx)
+; CHECK: call void @helper_i1(i1 %Exx)
+; CHECK: call void @helper_i1(i1 %Fxx)
+; CHECK: call void @helper_i1(i1 %Gxx)
+; CHECK: call void @helper_i1(i1 %Dxn)
+; CHECK: call void @helper_i1(i1 %Exn)
+; CHECK: call void @helper_i1(i1 %Fxn)
+; CHECK: call void @helper_i1(i1 %Gxn)
+; CHECK: call void @helper_i1(i1 false)
+; CHECK: call void @helper_i1(i1 true)
+; CHECK: call void @helper_i1(i1 false)
+; CHECK: call void @helper_i1(i1 true)
+; CHECK: call void @helper_i1(i1 false)
+; CHECK: call void @helper_i1(i1 true)
+; CHECK: call void @helper_i1(i1 false)
+; CHECK: call void @helper_i1(i1 true)
+; CHECK: call void @helper_i1(i1 false)
+; CHECK: call void @helper_i1(i1 true)
+; CHECK: call void @helper_i1(i1 false)
+; CHECK: call void @helper_i1(i1 true)
+  ret void
+}
+
+define i1 @constant_fold_inttoptr_null() {
+; CHECK-LABEL: @constant_fold_inttoptr_null(
+; CHECK-NEXT:    ret i1 false
+;
+  %x = icmp eq i32* inttoptr (i64 32 to i32*), null
+  ret i1 %x
+}
+
+define i1 @constant_fold_null_inttoptr() {
+; CHECK-LABEL: @constant_fold_null_inttoptr(
+; CHECK-NEXT:    ret i1 false
+;
+  %x = icmp eq i32* null, inttoptr (i64 32 to i32*)
+  ret i1 %x
+}
+
+attributes #0 = { "null-pointer-is-valid"="true" }

Added: llvm/trunk/test/Transforms/InstSimplify/constantfold-add-nuw-allones-to-allones.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstSimplify/constantfold-add-nuw-allones-to-allones.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstSimplify/constantfold-add-nuw-allones-to-allones.ll (added)
+++ llvm/trunk/test/Transforms/InstSimplify/constantfold-add-nuw-allones-to-allones.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,140 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt < %s -instsimplify -S | FileCheck %s
+
+; %ret = add nuw i8 %x, C
+; nuw means no unsigned wrap, from -1 to 0.
+; So if C is -1, %x can only be 0, and the result is always -1.
+
+define i8 @add_nuw (i8 %x) {
+; CHECK-LABEL: @add_nuw(
+; CHECK-NEXT:    ret i8 -1
+;
+  %ret = add nuw i8 %x, -1
+  ; nuw here means that %x can only be 0
+  ret i8 %ret
+}
+
+define i8 @add_nuw_nsw (i8 %x) {
+; CHECK-LABEL: @add_nuw_nsw(
+; CHECK-NEXT:    ret i8 -1
+;
+  %ret = add nuw nsw i8 %x, -1
+  ; nuw here means that %x can only be 0
+  ret i8 %ret
+}
+
+define i8 @add_nuw_commute (i8 %x) {
+; CHECK-LABEL: @add_nuw_commute(
+; CHECK-NEXT:    ret i8 -1
+;
+  %ret = add nuw i8 -1, %x ; swapped
+  ; nuw here means that %x can only be 0
+  ret i8 %ret
+}
+
+; ============================================================================ ;
+; Positive tests with value range known
+; ============================================================================ ;
+
+declare void @llvm.assume(i1 %cond);
+
+define i8 @knownbits_allones(i8 %x, i8 %y) {
+; CHECK-LABEL: @knownbits_allones(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i8 [[Y:%.*]], -2
+; CHECK-NEXT:    tail call void @llvm.assume(i1 [[CMP]])
+; CHECK-NEXT:    [[RET:%.*]] = add nuw i8 [[X:%.*]], [[Y]]
+; CHECK-NEXT:    ret i8 [[RET]]
+;
+  %cmp = icmp slt i8 %y, 254
+  tail call void @llvm.assume(i1 %cmp)
+  %ret = add nuw i8 %x, %y
+  ret i8 %ret
+}
+
+; ============================================================================ ;
+; Vectors
+; ============================================================================ ;
+
+define <2 x i8> @add_vec(<2 x i8> %x) {
+; CHECK-LABEL: @add_vec(
+; CHECK-NEXT:    ret <2 x i8> <i8 -1, i8 -1>
+;
+  %ret = add nuw <2 x i8> %x, <i8 -1, i8 -1>
+  ret <2 x i8> %ret
+}
+
+define <3 x i8> @add_vec_undef(<3 x i8> %x) {
+; CHECK-LABEL: @add_vec_undef(
+; CHECK-NEXT:    ret <3 x i8> <i8 -1, i8 undef, i8 -1>
+;
+  %ret = add nuw <3 x i8> %x, <i8 -1, i8 undef, i8 -1>
+  ret <3 x i8> %ret
+}
+
+; ============================================================================ ;
+; Negative tests. Should not be folded.
+; ============================================================================ ;
+
+define i8 @bad_add (i8 %x) {
+; CHECK-LABEL: @bad_add(
+; CHECK-NEXT:    [[RET:%.*]] = add i8 [[X:%.*]], -1
+; CHECK-NEXT:    ret i8 [[RET]]
+;
+  %ret = add i8 %x, -1 ; need nuw
+  ret i8 %ret
+}
+
+define i8 @bad_add_nsw (i8 %x) {
+; CHECK-LABEL: @bad_add_nsw(
+; CHECK-NEXT:    [[RET:%.*]] = add nsw i8 [[X:%.*]], -1
+; CHECK-NEXT:    ret i8 [[RET]]
+;
+  %ret = add nsw i8 %x, -1 ; need nuw
+  ret i8 %ret
+}
+
+; Second `add` operand is not `-1` constant
+
+define i8 @bad_add0(i8 %x, i8 %addop2) {
+; CHECK-LABEL: @bad_add0(
+; CHECK-NEXT:    [[RET:%.*]] = add nuw i8 [[X:%.*]], [[ADDOP2:%.*]]
+; CHECK-NEXT:    ret i8 [[RET]]
+;
+  %ret = add nuw i8 %x, %addop2
+  ret i8 %ret
+}
+
+; Bad constant
+
+define i8 @bad_add1(i8 %x) {
+; CHECK-LABEL: @bad_add1(
+; CHECK-NEXT:    [[RET:%.*]] = add nuw i8 [[X:%.*]], 1
+; CHECK-NEXT:    ret i8 [[RET]]
+;
+  %ret = add nuw i8 %x, 1 ; not -1
+  ret i8 %ret
+}
+
+define <2 x i8> @bad_add_vec_nonsplat(<2 x i8> %x) {
+; CHECK-LABEL: @bad_add_vec_nonsplat(
+; CHECK-NEXT:    [[RET:%.*]] = add nuw <2 x i8> [[X:%.*]], <i8 -1, i8 1>
+; CHECK-NEXT:    ret <2 x i8> [[RET]]
+;
+  %ret = add nuw <2 x i8> %x, <i8 -1, i8 1>
+  ret <2 x i8> %ret
+}
+
+; Bad known bits
+
+define i8 @bad_knownbits(i8 %x, i8 %y) {
+; CHECK-LABEL: @bad_knownbits(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i8 [[X:%.*]], -3
+; CHECK-NEXT:    tail call void @llvm.assume(i1 [[CMP]])
+; CHECK-NEXT:    [[RET:%.*]] = add nuw i8 [[X]], [[Y:%.*]]
+; CHECK-NEXT:    ret i8 [[RET]]
+;
+  %cmp = icmp slt i8 %x, 253
+  tail call void @llvm.assume(i1 %cmp)
+  %ret = add nuw i8 %x, %y
+  ret i8 %ret
+}

Added: llvm/trunk/test/Transforms/InstSimplify/constantfold-shl-nuw-C-to-C.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstSimplify/constantfold-shl-nuw-C-to-C.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstSimplify/constantfold-shl-nuw-C-to-C.ll (added)
+++ llvm/trunk/test/Transforms/InstSimplify/constantfold-shl-nuw-C-to-C.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,212 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt < %s -instsimplify -S | FileCheck %s
+
+; %r = shl nuw i8 C, %x
+; As per langref: If the nuw keyword is present, then the shift produces
+;                 a poison value if it shifts out any non-zero bits.
+; Thus, if the sign bit is set on C, then %x can only be 0, which means that
+; %r can only be C.
+
+define i8 @shl_nuw (i8 %x) {
+; CHECK-LABEL: @shl_nuw(
+; CHECK-NEXT:    ret i8 -1
+;
+  %ret = shl nuw i8 -1, %x
+  ; nuw here means that %x can only be 0
+  ret i8 %ret
+}
+
+define i8 @shl_nuw_nsw (i8 %x) {
+; CHECK-LABEL: @shl_nuw_nsw(
+; CHECK-NEXT:    ret i8 -1
+;
+  %ret = shl nuw nsw i8 -1, %x
+  ; nuw here means that %x can only be 0
+  ret i8 %ret
+}
+
+define i8 @shl_128 (i8 %x) {
+; CHECK-LABEL: @shl_128(
+; CHECK-NEXT:    ret i8 -128
+;
+  %ret = shl nuw i8 128, %x
+  ; 128 == 1<<7 == just the sign bit is set
+  ret i8 %ret
+}
+
+; ============================================================================ ;
+; Positive tests with value range known
+; ============================================================================ ;
+
+declare void @llvm.assume(i1 %cond);
+
+define i8 @knownbits_negative(i8 %x, i8 %y) {
+; CHECK-LABEL: @knownbits_negative(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i8 [[X:%.*]], 0
+; CHECK-NEXT:    tail call void @llvm.assume(i1 [[CMP]])
+; CHECK-NEXT:    [[RET:%.*]] = shl nuw i8 [[X]], [[Y:%.*]]
+; CHECK-NEXT:    ret i8 [[RET]]
+;
+  %cmp = icmp slt i8 %x, 0
+  tail call void @llvm.assume(i1 %cmp)
+  %ret = shl nuw i8 %x, %y
+  ret i8 %ret
+}
+
+define i8 @knownbits_negativeorzero(i8 %x, i8 %y) {
+; CHECK-LABEL: @knownbits_negativeorzero(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i8 [[X:%.*]], 1
+; CHECK-NEXT:    tail call void @llvm.assume(i1 [[CMP]])
+; CHECK-NEXT:    [[RET:%.*]] = shl nuw i8 [[X]], [[Y:%.*]]
+; CHECK-NEXT:    ret i8 [[RET]]
+;
+  %cmp = icmp slt i8 %x, 1
+  tail call void @llvm.assume(i1 %cmp)
+  %ret = shl nuw i8 %x, %y
+  ret i8 %ret
+}
+
+; ============================================================================ ;
+; Vectors
+; ============================================================================ ;
+
+define <2 x i8> @shl_vec(<2 x i8> %x) {
+; CHECK-LABEL: @shl_vec(
+; CHECK-NEXT:    ret <2 x i8> <i8 -1, i8 -1>
+;
+  %ret = shl nuw <2 x i8> <i8 -1, i8 -1>, %x
+  ret <2 x i8> %ret
+}
+
+define <3 x i8> @shl_vec_undef(<3 x i8> %x) {
+; CHECK-LABEL: @shl_vec_undef(
+; CHECK-NEXT:    ret <3 x i8> <i8 -1, i8 undef, i8 -1>
+;
+  %ret = shl nuw <3 x i8> <i8 -1, i8 undef, i8 -1>, %x
+  ret <3 x i8> %ret
+}
+
+define <2 x i8> @shl_vec_nonsplat(<2 x i8> %x) {
+; CHECK-LABEL: @shl_vec_nonsplat(
+; CHECK-NEXT:    ret <2 x i8> <i8 -1, i8 -2>
+;
+  %ret = shl nuw <2 x i8> <i8 -1, i8 -2>, %x
+  ret <2 x i8> %ret
+}
+
+; ============================================================================ ;
+; Negative tests. Should not be folded.
+; ============================================================================ ;
+
+define i8 @shl_127 (i8 %x) {
+; CHECK-LABEL: @shl_127(
+; CHECK-NEXT:    [[RET:%.*]] = shl nuw i8 127, [[X:%.*]]
+; CHECK-NEXT:    ret i8 [[RET]]
+;
+  %ret = shl nuw i8 127, %x
+  ; 127 == (1<<7)-1 == all bits except the sign bit are set.
+  ret i8 %ret
+}
+
+define i8 @bad_shl (i8 %x) {
+; CHECK-LABEL: @bad_shl(
+; CHECK-NEXT:    [[RET:%.*]] = shl i8 -1, [[X:%.*]]
+; CHECK-NEXT:    ret i8 [[RET]]
+;
+  %ret = shl i8 -1, %x ; need nuw
+  ret i8 %ret
+}
+
+define i8 @bad_nsw (i8 %x) {
+; CHECK-LABEL: @bad_nsw(
+; CHECK-NEXT:    [[RET:%.*]] = shl nsw i8 -1, [[X:%.*]]
+; CHECK-NEXT:    ret i8 [[RET]]
+;
+  %ret = shl nsw i8 -1, %x ; need nuw
+  ret i8 %ret
+}
+
+; First `shl` operand is not `-1` constant
+
+define i8 @bad_shl0(i8 %shlop1, i8 %x) {
+; CHECK-LABEL: @bad_shl0(
+; CHECK-NEXT:    [[RET:%.*]] = shl nuw i8 [[SHLOP1:%.*]], [[X:%.*]]
+; CHECK-NEXT:    ret i8 [[RET]]
+;
+  %ret = shl nuw i8 %shlop1, %x
+  ret i8 %ret
+}
+
+; Bad shl nuw constant
+
+define i8 @bad_shl1(i8 %x) {
+; CHECK-LABEL: @bad_shl1(
+; CHECK-NEXT:    [[RET:%.*]] = shl nuw i8 1, [[X:%.*]]
+; CHECK-NEXT:    ret i8 [[RET]]
+;
+  %ret = shl nuw i8 1, %x ; not -1
+  ret i8 %ret
+}
+
+define <2 x i8> @bad_shl_vec_nonsplat(<2 x i8> %x) {
+; CHECK-LABEL: @bad_shl_vec_nonsplat(
+; CHECK-NEXT:    [[RET:%.*]] = shl nuw <2 x i8> <i8 -1, i8 1>, [[X:%.*]]
+; CHECK-NEXT:    ret <2 x i8> [[RET]]
+;
+  %ret = shl nuw <2 x i8> <i8 -1, i8 1>, %x
+  ret <2 x i8> %ret
+}
+
+; Bad known bits
+
+define i8 @bad_knownbits(i8 %x, i8 %y) {
+; CHECK-LABEL: @bad_knownbits(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i8 [[X:%.*]], 2
+; CHECK-NEXT:    tail call void @llvm.assume(i1 [[CMP]])
+; CHECK-NEXT:    [[RET:%.*]] = shl nuw i8 [[X]], [[Y:%.*]]
+; CHECK-NEXT:    ret i8 [[RET]]
+;
+  %cmp = icmp slt i8 %x, 2
+  tail call void @llvm.assume(i1 %cmp)
+  %ret = shl nuw i8 %x, %y
+  ret i8 %ret
+}
+
+define i8 @bad_knownbits_minusoneormore(i8 %x, i8 %y) {
+; CHECK-LABEL: @bad_knownbits_minusoneormore(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt i8 [[X:%.*]], -2
+; CHECK-NEXT:    tail call void @llvm.assume(i1 [[CMP]])
+; CHECK-NEXT:    [[RET:%.*]] = shl nuw i8 [[X]], [[Y:%.*]]
+; CHECK-NEXT:    ret i8 [[RET]]
+;
+  %cmp = icmp sgt i8 %x, -2
+  tail call void @llvm.assume(i1 %cmp)
+  %ret = shl nuw i8 %x, %y
+  ret i8 %ret
+}
+
+define i8 @bad_knownbits_zeroorpositive(i8 %x, i8 %y) {
+; CHECK-LABEL: @bad_knownbits_zeroorpositive(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt i8 [[X:%.*]], -1
+; CHECK-NEXT:    tail call void @llvm.assume(i1 [[CMP]])
+; CHECK-NEXT:    [[RET:%.*]] = shl nuw i8 [[X]], [[Y:%.*]]
+; CHECK-NEXT:    ret i8 [[RET]]
+;
+  %cmp = icmp sgt i8 %x, -1
+  tail call void @llvm.assume(i1 %cmp)
+  %ret = shl nuw i8 %x, %y
+  ret i8 %ret
+}
+
+define i8 @bad_knownbits_positive(i8 %x, i8 %y) {
+; CHECK-LABEL: @bad_knownbits_positive(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt i8 [[X:%.*]], 0
+; CHECK-NEXT:    tail call void @llvm.assume(i1 [[CMP]])
+; CHECK-NEXT:    [[RET:%.*]] = shl nuw i8 [[X]], [[Y:%.*]]
+; CHECK-NEXT:    ret i8 [[RET]]
+;
+  %cmp = icmp sgt i8 %x, 0
+  tail call void @llvm.assume(i1 %cmp)
+  %ret = shl nuw i8 %x, %y
+  ret i8 %ret
+}

Added: llvm/trunk/test/Transforms/InstSimplify/dead-code-removal.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstSimplify/dead-code-removal.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstSimplify/dead-code-removal.ll (added)
+++ llvm/trunk/test/Transforms/InstSimplify/dead-code-removal.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,15 @@
+; RUN: opt -instsimplify -S < %s | FileCheck %s
+
+define void @foo() nounwind {
+  br i1 undef, label %1, label %4
+
+; <label>:1                                       ; preds = %1, %0
+; CHECK-NOT: phi
+; CHECK-NOT: sub
+  %2 = phi i32 [ %3, %1 ], [ undef, %0 ]
+  %3 = sub i32 0, undef
+  br label %1
+
+; <label>:4                                       ; preds = %0
+  ret void
+}

Added: llvm/trunk/test/Transforms/InstSimplify/div.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstSimplify/div.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstSimplify/div.ll (added)
+++ llvm/trunk/test/Transforms/InstSimplify/div.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,196 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt < %s -instsimplify -S | FileCheck %s
+
+define i32 @zero_dividend(i32 %A) {
+; CHECK-LABEL: @zero_dividend(
+; CHECK-NEXT:    ret i32 0
+;
+  %B = sdiv i32 0, %A
+  ret i32 %B
+}
+
+define <2 x i32> @zero_dividend_vector(<2 x i32> %A) {
+; CHECK-LABEL: @zero_dividend_vector(
+; CHECK-NEXT:    ret <2 x i32> zeroinitializer
+;
+  %B = udiv <2 x i32> zeroinitializer, %A
+  ret <2 x i32> %B
+}
+
+define <2 x i32> @zero_dividend_vector_undef_elt(<2 x i32> %A) {
+; CHECK-LABEL: @zero_dividend_vector_undef_elt(
+; CHECK-NEXT:    ret <2 x i32> zeroinitializer
+;
+  %B = sdiv <2 x i32> <i32 0, i32 undef>, %A
+  ret <2 x i32> %B
+}
+
+; Division-by-zero is undef. UB in any vector lane means the whole op is undef.
+
+define <2 x i8> @sdiv_zero_elt_vec_constfold(<2 x i8> %x) {
+; CHECK-LABEL: @sdiv_zero_elt_vec_constfold(
+; CHECK-NEXT:    ret <2 x i8> undef
+;
+  %div = sdiv <2 x i8> <i8 1, i8 2>, <i8 0, i8 -42>
+  ret <2 x i8> %div
+}
+
+define <2 x i8> @udiv_zero_elt_vec_constfold(<2 x i8> %x) {
+; CHECK-LABEL: @udiv_zero_elt_vec_constfold(
+; CHECK-NEXT:    ret <2 x i8> undef
+;
+  %div = udiv <2 x i8> <i8 1, i8 2>, <i8 42, i8 0>
+  ret <2 x i8> %div
+}
+
+define <2 x i8> @sdiv_zero_elt_vec(<2 x i8> %x) {
+; CHECK-LABEL: @sdiv_zero_elt_vec(
+; CHECK-NEXT:    ret <2 x i8> undef
+;
+  %div = sdiv <2 x i8> %x, <i8 -42, i8 0>
+  ret <2 x i8> %div
+}
+
+define <2 x i8> @udiv_zero_elt_vec(<2 x i8> %x) {
+; CHECK-LABEL: @udiv_zero_elt_vec(
+; CHECK-NEXT:    ret <2 x i8> undef
+;
+  %div = udiv <2 x i8> %x, <i8 0, i8 42>
+  ret <2 x i8> %div
+}
+
+define <2 x i8> @sdiv_undef_elt_vec(<2 x i8> %x) {
+; CHECK-LABEL: @sdiv_undef_elt_vec(
+; CHECK-NEXT:    ret <2 x i8> undef
+;
+  %div = sdiv <2 x i8> %x, <i8 -42, i8 undef>
+  ret <2 x i8> %div
+}
+
+define <2 x i8> @udiv_undef_elt_vec(<2 x i8> %x) {
+; CHECK-LABEL: @udiv_undef_elt_vec(
+; CHECK-NEXT:    ret <2 x i8> undef
+;
+  %div = udiv <2 x i8> %x, <i8 undef, i8 42>
+  ret <2 x i8> %div
+}
+
+; Division-by-zero is undef. UB in any vector lane means the whole op is undef.
+; Thus, we can simplify this: if any element of 'y' is 0, we can do anything.
+; Therefore, assume that all elements of 'y' must be 1.
+
+define <2 x i1> @sdiv_bool_vec(<2 x i1> %x, <2 x i1> %y) {
+; CHECK-LABEL: @sdiv_bool_vec(
+; CHECK-NEXT:    ret <2 x i1> [[X:%.*]]
+;
+  %div = sdiv <2 x i1> %x, %y
+  ret <2 x i1> %div
+}
+
+define <2 x i1> @udiv_bool_vec(<2 x i1> %x, <2 x i1> %y) {
+; CHECK-LABEL: @udiv_bool_vec(
+; CHECK-NEXT:    ret <2 x i1> [[X:%.*]]
+;
+  %div = udiv <2 x i1> %x, %y
+  ret <2 x i1> %div
+}
+
+define i32 @zext_bool_udiv_divisor(i1 %x, i32 %y) {
+; CHECK-LABEL: @zext_bool_udiv_divisor(
+; CHECK-NEXT:    ret i32 [[Y:%.*]]
+;
+  %ext = zext i1 %x to i32
+  %r = udiv i32 %y, %ext
+  ret i32 %r
+}
+
+define <2 x i32> @zext_bool_sdiv_divisor_vec(<2 x i1> %x, <2 x i32> %y) {
+; CHECK-LABEL: @zext_bool_sdiv_divisor_vec(
+; CHECK-NEXT:    ret <2 x i32> [[Y:%.*]]
+;
+  %ext = zext <2 x i1> %x to <2 x i32>
+  %r = sdiv <2 x i32> %y, %ext
+  ret <2 x i32> %r
+}
+
+define i32 @udiv_dividend_known_smaller_than_constant_divisor(i32 %x) {
+; CHECK-LABEL: @udiv_dividend_known_smaller_than_constant_divisor(
+; CHECK-NEXT:    ret i32 0
+;
+  %and = and i32 %x, 250
+  %div = udiv i32 %and, 251
+  ret i32 %div
+}
+
+define i32 @not_udiv_dividend_known_smaller_than_constant_divisor(i32 %x) {
+; CHECK-LABEL: @not_udiv_dividend_known_smaller_than_constant_divisor(
+; CHECK-NEXT:    [[AND:%.*]] = and i32 [[X:%.*]], 251
+; CHECK-NEXT:    [[DIV:%.*]] = udiv i32 [[AND]], 251
+; CHECK-NEXT:    ret i32 [[DIV]]
+;
+  %and = and i32 %x, 251
+  %div = udiv i32 %and, 251
+  ret i32 %div
+}
+
+define i32 @udiv_constant_dividend_known_smaller_than_divisor(i32 %x) {
+; CHECK-LABEL: @udiv_constant_dividend_known_smaller_than_divisor(
+; CHECK-NEXT:    ret i32 0
+;
+  %or = or i32 %x, 251
+  %div = udiv i32 250, %or
+  ret i32 %div
+}
+
+define i32 @not_udiv_constant_dividend_known_smaller_than_divisor(i32 %x) {
+; CHECK-LABEL: @not_udiv_constant_dividend_known_smaller_than_divisor(
+; CHECK-NEXT:    [[OR:%.*]] = or i32 [[X:%.*]], 251
+; CHECK-NEXT:    [[DIV:%.*]] = udiv i32 251, [[OR]]
+; CHECK-NEXT:    ret i32 [[DIV]]
+;
+  %or = or i32 %x, 251
+  %div = udiv i32 251, %or
+  ret i32 %div
+}
+
+; This would require computing known bits on both x and y. Is it worth doing?
+
+define i32 @udiv_dividend_known_smaller_than_divisor(i32 %x, i32 %y) {
+; CHECK-LABEL: @udiv_dividend_known_smaller_than_divisor(
+; CHECK-NEXT:    [[AND:%.*]] = and i32 [[X:%.*]], 250
+; CHECK-NEXT:    [[OR:%.*]] = or i32 [[Y:%.*]], 251
+; CHECK-NEXT:    [[DIV:%.*]] = udiv i32 [[AND]], [[OR]]
+; CHECK-NEXT:    ret i32 [[DIV]]
+;
+  %and = and i32 %x, 250
+  %or = or i32 %y, 251
+  %div = udiv i32 %and, %or
+  ret i32 %div
+}
+
+define i32 @not_udiv_dividend_known_smaller_than_divisor(i32 %x, i32 %y) {
+; CHECK-LABEL: @not_udiv_dividend_known_smaller_than_divisor(
+; CHECK-NEXT:    [[AND:%.*]] = and i32 [[X:%.*]], 251
+; CHECK-NEXT:    [[OR:%.*]] = or i32 [[Y:%.*]], 251
+; CHECK-NEXT:    [[DIV:%.*]] = udiv i32 [[AND]], [[OR]]
+; CHECK-NEXT:    ret i32 [[DIV]]
+;
+  %and = and i32 %x, 251
+  %or = or i32 %y, 251
+  %div = udiv i32 %and, %or
+  ret i32 %div
+}
+
+declare i32 @external()
+
+define i32 @div1() {
+; CHECK-LABEL: @div1(
+; CHECK-NEXT:    [[CALL:%.*]] = call i32 @external(), !range !0
+; CHECK-NEXT:    ret i32 0
+;
+  %call = call i32 @external(), !range !0
+  %urem = udiv i32 %call, 3
+  ret i32 %urem
+}
+
+!0 = !{i32 0, i32 3}

Added: llvm/trunk/test/Transforms/InstSimplify/exact-nsw-nuw.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstSimplify/exact-nsw-nuw.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstSimplify/exact-nsw-nuw.ll (added)
+++ llvm/trunk/test/Transforms/InstSimplify/exact-nsw-nuw.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,69 @@
+; RUN: opt < %s -instsimplify -S | FileCheck %s
+
+; PR8862
+
+define i32 @shift1(i32 %A, i32 %B) {
+; CHECK-LABEL: @shift1(
+; CHECK-NEXT:    ret i32 %A
+;
+  %C = lshr exact i32 %A, %B
+  %D = shl nuw i32 %C, %B
+  ret i32 %D
+}
+
+define i32 @shift2(i32 %A, i32 %B) {
+; CHECK-LABEL: @shift2(
+; CHECK-NEXT:    [[C:%.*]] = lshr i32 %A, %B
+; CHECK-NEXT:    [[D:%.*]] = shl nuw i32 [[C]], %B
+; CHECK-NEXT:    ret i32 [[D]]
+;
+  %C = lshr i32 %A, %B
+  %D = shl nuw i32 %C, %B
+  ret i32 %D
+}
+
+define i32 @shift3(i32 %A, i32 %B) {
+; CHECK-LABEL: @shift3(
+; CHECK-NEXT:    ret i32 %A
+;
+  %C = ashr exact i32 %A, %B
+  %D = shl nuw i32 %C, %B
+  ret i32 %D
+}
+
+define i32 @shift4(i32 %A, i32 %B) {
+; CHECK-LABEL: @shift4(
+; CHECK-NEXT:    ret i32 %A
+;
+  %C = shl nuw i32 %A, %B
+  %D = lshr i32 %C, %B
+  ret i32 %D
+}
+
+define i32 @shift5(i32 %A, i32 %B) {
+; CHECK-LABEL: @shift5(
+; CHECK-NEXT:    ret i32 %A
+;
+  %C = shl nsw i32 %A, %B
+  %D = ashr i32 %C, %B
+  ret i32 %D
+}
+
+define i32 @div1(i32 %V) {
+; CHECK-LABEL: @div1(
+; CHECK-NEXT:    ret i32 0
+;
+  %A = udiv i32 %V, -2147483648
+  %B = udiv i32 %A, -2147483648
+  ret i32 %B
+}
+
+define i32 @div2(i32 %V) {
+; CHECK-LABEL: @div2(
+; CHECK-NEXT:    ret i32 0
+;
+  %A = sdiv i32 %V, -1
+  %B = sdiv i32 %A, -2147483648
+  ret i32 %B
+}
+

Added: llvm/trunk/test/Transforms/InstSimplify/extract-element.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstSimplify/extract-element.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstSimplify/extract-element.ll (added)
+++ llvm/trunk/test/Transforms/InstSimplify/extract-element.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,56 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt < %s -instsimplify -S | FileCheck %s
+
+; Weird Types
+
+define i129 @vec_extract_negidx(<3 x i129> %a) {
+; CHECK-LABEL: @vec_extract_negidx(
+; CHECK-NEXT:    ret i129 undef
+;
+  %E1 = extractelement <3 x i129> %a, i129 -1
+  ret i129 %E1
+}
+
+define i129 @vec_extract_out_of_bounds(<3 x i129> %a) {
+; CHECK-LABEL: @vec_extract_out_of_bounds(
+; CHECK-NEXT:    ret i129 undef
+;
+  %E1 = extractelement <3 x i129> %a, i129 3
+  ret i129 %E1
+}
+
+define i129 @vec_extract_out_of_bounds2(<3 x i129> %a) {
+; CHECK-LABEL: @vec_extract_out_of_bounds2(
+; CHECK-NEXT:    ret i129 undef
+;
+  %E1 = extractelement <3 x i129> %a, i129 999999999999999
+  ret i129 %E1
+}
+
+
+define i129 @vec_extract_undef_index(<3 x i129> %a) {
+; CHECK-LABEL: @vec_extract_undef_index(
+; CHECK-NEXT:    ret i129 undef
+;
+  %E1 = extractelement <3 x i129> %a, i129 undef
+  ret i129 %E1
+}
+
+
+define i129 @vec_extract_in_bounds(<3 x i129> %a) {
+; CHECK-LABEL: @vec_extract_in_bounds(
+; CHECK-NEXT:    [[E1:%.*]] = extractelement <3 x i129> [[A:%.*]], i129 2
+; CHECK-NEXT:    ret i129 [[E1]]
+;
+  %E1 = extractelement <3 x i129> %a, i129 2
+  ret i129 %E1
+}
+
+define float @extract_element_splat_constant_vector_variable_index(i32 %y) {
+; CHECK-LABEL: @extract_element_splat_constant_vector_variable_index(
+; CHECK-NEXT:    ret float 2.000000e+00
+;
+  %r = extractelement <4 x float> <float 2.0, float 2.0, float 2.0, float 2.0>, i32 %y
+  ret float %r
+}
+

Added: llvm/trunk/test/Transforms/InstSimplify/fast-math.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstSimplify/fast-math.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstSimplify/fast-math.ll (added)
+++ llvm/trunk/test/Transforms/InstSimplify/fast-math.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,462 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt < %s -instsimplify -S | FileCheck %s
+
+;; x * 0 ==> 0 when no-nans and no-signed-zero
+define float @mul_zero_1(float %a) {
+; CHECK-LABEL: @mul_zero_1(
+; CHECK-NEXT:    ret float 0.000000e+00
+;
+  %b = fmul nsz nnan float %a, 0.0
+  ret float %b
+}
+
+define float @mul_zero_2(float %a) {
+; CHECK-LABEL: @mul_zero_2(
+; CHECK-NEXT:    ret float 0.000000e+00
+;
+  %b = fmul fast float 0.0, %a
+  ret float %b
+}
+
+define <2 x float> @mul_zero_nsz_nnan_vec_undef(<2 x float> %a) {
+; CHECK-LABEL: @mul_zero_nsz_nnan_vec_undef(
+; CHECK-NEXT:    ret <2 x float> zeroinitializer
+;
+  %b = fmul nsz nnan <2 x float> %a, <float 0.0, float undef>
+  ret <2 x float> %b
+}
+
+;; x * 0 =/=> 0 when there could be nans or -0
+define float @no_mul_zero_1(float %a) {
+; CHECK-LABEL: @no_mul_zero_1(
+; CHECK-NEXT:    [[B:%.*]] = fmul nsz float [[A:%.*]], 0.000000e+00
+; CHECK-NEXT:    ret float [[B]]
+;
+  %b = fmul nsz float %a, 0.0
+  ret float %b
+}
+
+define float @no_mul_zero_2(float %a) {
+; CHECK-LABEL: @no_mul_zero_2(
+; CHECK-NEXT:    [[B:%.*]] = fmul nnan float [[A:%.*]], 0.000000e+00
+; CHECK-NEXT:    ret float [[B]]
+;
+  %b = fmul nnan float %a, 0.0
+  ret float %b
+}
+
+define float @no_mul_zero_3(float %a) {
+; CHECK-LABEL: @no_mul_zero_3(
+; CHECK-NEXT:    [[B:%.*]] = fmul float [[A:%.*]], 0.000000e+00
+; CHECK-NEXT:    ret float [[B]]
+;
+  %b = fmul float %a, 0.0
+  ret float %b
+}
+
+; -X + X --> 0.0 (with nnan on the fadd)
+
+define float @fadd_fnegx(float %x) {
+; CHECK-LABEL: @fadd_fnegx(
+; CHECK-NEXT:    ret float 0.000000e+00
+;
+  %negx = fsub float -0.0, %x
+  %r = fadd nnan float %negx, %x
+  ret float %r
+}
+
+; X + -X --> 0.0 (with nnan on the fadd)
+
+define <2 x float> @fadd_fnegx_commute_vec(<2 x float> %x) {
+; CHECK-LABEL: @fadd_fnegx_commute_vec(
+; CHECK-NEXT:    ret <2 x float> zeroinitializer
+;
+  %negx = fsub <2 x float> <float -0.0, float -0.0>, %x
+  %r = fadd nnan <2 x float> %x, %negx
+  ret <2 x float> %r
+}
+
+define <2 x float> @fadd_fnegx_commute_vec_undef(<2 x float> %x) {
+; CHECK-LABEL: @fadd_fnegx_commute_vec_undef(
+; CHECK-NEXT:    ret <2 x float> zeroinitializer
+;
+  %negx = fsub <2 x float> <float undef, float -0.0>, %x
+  %r = fadd nnan <2 x float> %x, %negx
+  ret <2 x float> %r
+}
+
+; https://bugs.llvm.org/show_bug.cgi?id=26958
+; https://bugs.llvm.org/show_bug.cgi?id=27151
+
+define float @fadd_fneg_nan(float %x) {
+; CHECK-LABEL: @fadd_fneg_nan(
+; CHECK-NEXT:    [[T:%.*]] = fsub nnan float -0.000000e+00, [[X:%.*]]
+; CHECK-NEXT:    [[COULD_BE_NAN:%.*]] = fadd ninf float [[T]], [[X]]
+; CHECK-NEXT:    ret float [[COULD_BE_NAN]]
+;
+  %t = fsub nnan float -0.0, %x
+  %could_be_nan = fadd ninf float %t, %x
+  ret float %could_be_nan
+}
+
+define float @fadd_fneg_nan_commute(float %x) {
+; CHECK-LABEL: @fadd_fneg_nan_commute(
+; CHECK-NEXT:    [[T:%.*]] = fsub nnan ninf float -0.000000e+00, [[X:%.*]]
+; CHECK-NEXT:    [[COULD_BE_NAN:%.*]] = fadd float [[X]], [[T]]
+; CHECK-NEXT:    ret float [[COULD_BE_NAN]]
+;
+  %t = fsub nnan ninf float -0.0, %x
+  %could_be_nan = fadd float %x, %t
+  ret float %could_be_nan
+}
+
+; X + (0.0 - X) --> 0.0 (with nnan on the fadd)
+
+define float @fadd_fsub_nnan_ninf(float %x) {
+; CHECK-LABEL: @fadd_fsub_nnan_ninf(
+; CHECK-NEXT:    ret float 0.000000e+00
+;
+  %sub = fsub float 0.0, %x
+  %zero = fadd nnan ninf float %x, %sub
+  ret float %zero
+}
+
+; (0.0 - X) + X --> 0.0 (with nnan on the fadd)
+
+define <2 x float> @fadd_fsub_nnan_ninf_commute_vec(<2 x float> %x) {
+; CHECK-LABEL: @fadd_fsub_nnan_ninf_commute_vec(
+; CHECK-NEXT:    ret <2 x float> zeroinitializer
+;
+  %sub = fsub <2 x float> zeroinitializer, %x
+  %zero = fadd nnan ninf <2 x float> %sub, %x
+  ret <2 x float> %zero
+}
+
+; 'ninf' is not required because 'nnan' allows us to assume
+; that X is not INF or -INF (adding opposite INFs would be NaN).
+
+define float @fadd_fsub_nnan(float %x) {
+; CHECK-LABEL: @fadd_fsub_nnan(
+; CHECK-NEXT:    ret float 0.000000e+00
+;
+  %sub = fsub float 0.0, %x
+  %zero = fadd nnan float %sub, %x
+  ret float %zero
+}
+
+; fsub nnan x, x ==> 0.0
+define float @fsub_x_x(float %a) {
+; CHECK-LABEL: @fsub_x_x(
+; CHECK-NEXT:    [[NO_ZERO1:%.*]] = fsub ninf float [[A:%.*]], [[A]]
+; CHECK-NEXT:    [[NO_ZERO2:%.*]] = fsub float [[A]], [[A]]
+; CHECK-NEXT:    [[NO_ZERO:%.*]] = fadd float [[NO_ZERO1]], [[NO_ZERO2]]
+; CHECK-NEXT:    ret float [[NO_ZERO]]
+;
+; X - X ==> 0
+  %zero1 = fsub nnan float %a, %a
+
+; Dont fold
+  %no_zero1 = fsub ninf float %a, %a
+  %no_zero2 = fsub float %a, %a
+  %no_zero = fadd float %no_zero1, %no_zero2
+
+; Should get folded
+  %ret = fadd nsz float %no_zero, %zero1
+
+  ret float %ret
+}
+
+; fsub nsz 0.0, (fsub 0.0, X) ==> X
+define float @fsub_0_0_x(float %a) {
+; CHECK-LABEL: @fsub_0_0_x(
+; CHECK-NEXT:    ret float [[A:%.*]]
+;
+  %t1 = fsub float 0.0, %a
+  %ret = fsub nsz float 0.0, %t1
+  ret float %ret
+}
+
+define <2 x float> @fsub_0_0_x_vec_undef1(<2 x float> %a) {
+; CHECK-LABEL: @fsub_0_0_x_vec_undef1(
+; CHECK-NEXT:    ret <2 x float> [[A:%.*]]
+;
+  %t1 = fsub <2 x float> <float 0.0, float undef>, %a
+  %ret = fsub nsz <2 x float> zeroinitializer, %t1
+  ret <2 x float> %ret
+}
+
+define <2 x float> @fsub_0_0_x_vec_undef2(<2 x float> %a) {
+; CHECK-LABEL: @fsub_0_0_x_vec_undef2(
+; CHECK-NEXT:    ret <2 x float> [[A:%.*]]
+;
+  %t1 = fsub <2 x float> zeroinitializer, %a
+  %ret = fsub nsz <2 x float> <float undef, float -0.0>, %t1
+  ret <2 x float> %ret
+}
+
+; fadd nsz X, 0 ==> X
+
+define <2 x float> @fadd_zero_nsz_vec(<2 x float> %x) {
+; CHECK-LABEL: @fadd_zero_nsz_vec(
+; CHECK-NEXT:    ret <2 x float> [[X:%.*]]
+;
+  %r = fadd nsz <2 x float> %x, zeroinitializer
+  ret <2 x float> %r
+}
+
+define <2 x float> @fadd_zero_nsz_vec_undef(<2 x float> %x) {
+; CHECK-LABEL: @fadd_zero_nsz_vec_undef(
+; CHECK-NEXT:    ret <2 x float> [[X:%.*]]
+;
+  %r = fadd nsz <2 x float> %x, <float 0.0, float undef>
+  ret <2 x float> %r
+}
+
+define float @nofold_fadd_x_0(float %a) {
+; CHECK-LABEL: @nofold_fadd_x_0(
+; CHECK-NEXT:    [[NO_ZERO1:%.*]] = fadd ninf float [[A:%.*]], 0.000000e+00
+; CHECK-NEXT:    [[NO_ZERO2:%.*]] = fadd nnan float [[A]], 0.000000e+00
+; CHECK-NEXT:    [[NO_ZERO:%.*]] = fadd float [[NO_ZERO1]], [[NO_ZERO2]]
+; CHECK-NEXT:    ret float [[NO_ZERO]]
+;
+; Dont fold
+  %no_zero1 = fadd ninf float %a, 0.0
+  %no_zero2 = fadd nnan float %a, 0.0
+  %no_zero = fadd float %no_zero1, %no_zero2
+  ret float %no_zero
+}
+
+define float @fold_fadd_nsz_x_0(float %a) {
+; CHECK-LABEL: @fold_fadd_nsz_x_0(
+; CHECK-NEXT:    ret float [[A:%.*]]
+;
+  %add = fadd nsz float %a, 0.0
+  ret float %add
+}
+
+define float @fold_fadd_cannot_be_neg0_nsz_src_x_0(float %a, float %b) {
+; CHECK-LABEL: @fold_fadd_cannot_be_neg0_nsz_src_x_0(
+; CHECK-NEXT:    [[NSZ:%.*]] = fmul nsz float [[A:%.*]], [[B:%.*]]
+; CHECK-NEXT:    ret float [[NSZ]]
+;
+  %nsz = fmul nsz float %a, %b
+  %add = fadd float %nsz, 0.0
+  ret float %add
+}
+
+define float @fold_fadd_cannot_be_neg0_fabs_src_x_0(float %a) {
+; CHECK-LABEL: @fold_fadd_cannot_be_neg0_fabs_src_x_0(
+; CHECK-NEXT:    [[FABS:%.*]] = call float @llvm.fabs.f32(float [[A:%.*]])
+; CHECK-NEXT:    ret float [[FABS]]
+;
+  %fabs = call float @llvm.fabs.f32(float %a)
+  %add = fadd float %fabs, 0.0
+  ret float %add
+}
+
+define float @fold_fadd_cannot_be_neg0_sqrt_nsz_src_x_0(float %a, float %b) {
+; CHECK-LABEL: @fold_fadd_cannot_be_neg0_sqrt_nsz_src_x_0(
+; CHECK-NEXT:    [[NSZ:%.*]] = fmul nsz float [[A:%.*]], [[B:%.*]]
+; CHECK-NEXT:    [[SQRT:%.*]] = call float @llvm.sqrt.f32(float [[NSZ]])
+; CHECK-NEXT:    ret float [[SQRT]]
+;
+  %nsz = fmul nsz float %a, %b
+  %sqrt = call float @llvm.sqrt.f32(float %nsz)
+  %add = fadd float %sqrt, 0.0
+  ret float %add
+}
+
+define float @fold_fadd_cannot_be_neg0_canonicalize_nsz_src_x_0(float %a, float %b) {
+; CHECK-LABEL: @fold_fadd_cannot_be_neg0_canonicalize_nsz_src_x_0(
+; CHECK-NEXT:    [[NSZ:%.*]] = fmul nsz float [[A:%.*]], [[B:%.*]]
+; CHECK-NEXT:    [[CANON:%.*]] = call float @llvm.canonicalize.f32(float [[NSZ]])
+; CHECK-NEXT:    ret float [[CANON]]
+;
+  %nsz = fmul nsz float %a, %b
+  %canon = call float @llvm.canonicalize.f32(float %nsz)
+  %add = fadd float %canon, 0.0
+  ret float %add
+}
+
+; fdiv nsz nnan 0, X ==> 0
+; 0 / X -> 0
+
+define double @fdiv_zero_by_x(double %x) {
+; CHECK-LABEL: @fdiv_zero_by_x(
+; CHECK-NEXT:    ret double 0.000000e+00
+;
+  %r = fdiv nnan nsz double 0.0, %x
+  ret double %r
+}
+
+define <2 x double> @fdiv_zero_by_x_vec_undef(<2 x double> %x) {
+; CHECK-LABEL: @fdiv_zero_by_x_vec_undef(
+; CHECK-NEXT:    ret <2 x double> zeroinitializer
+;
+  %r = fdiv nnan nsz <2 x double> <double 0.0, double undef>, %x
+  ret <2 x double> %r
+}
+
+; 0 % X -> 0
+; nsz is not necessary - frem result always has the sign of the dividend
+
+define double @frem_zero_by_x(double %x) {
+; CHECK-LABEL: @frem_zero_by_x(
+; CHECK-NEXT:    ret double 0.000000e+00
+;
+  %r = frem nnan double 0.0, %x
+  ret double %r
+}
+
+define <2 x double> @frem_poszero_by_x_vec_undef(<2 x double> %x) {
+; CHECK-LABEL: @frem_poszero_by_x_vec_undef(
+; CHECK-NEXT:    ret <2 x double> zeroinitializer
+;
+  %r = frem nnan <2 x double> <double 0.0, double undef>, %x
+  ret <2 x double> %r
+}
+
+; -0 % X -> -0
+; nsz is not necessary - frem result always has the sign of the dividend
+
+define double @frem_negzero_by_x(double %x) {
+; CHECK-LABEL: @frem_negzero_by_x(
+; CHECK-NEXT:    ret double -0.000000e+00
+;
+  %r = frem nnan double -0.0, %x
+  ret double %r
+}
+
+define <2 x double> @frem_negzero_by_x_vec_undef(<2 x double> %x) {
+; CHECK-LABEL: @frem_negzero_by_x_vec_undef(
+; CHECK-NEXT:    ret <2 x double> <double -0.000000e+00, double -0.000000e+00>
+;
+  %r = frem nnan <2 x double> <double undef, double -0.0>, %x
+  ret <2 x double> %r
+}
+
+define float @fdiv_self(float %f) {
+; CHECK-LABEL: @fdiv_self(
+; CHECK-NEXT:    ret float 1.000000e+00
+;
+  %div = fdiv nnan float %f, %f
+  ret float %div
+}
+
+define float @fdiv_self_invalid(float %f) {
+; CHECK-LABEL: @fdiv_self_invalid(
+; CHECK-NEXT:    [[DIV:%.*]] = fdiv float [[F:%.*]], [[F]]
+; CHECK-NEXT:    ret float [[DIV]]
+;
+  %div = fdiv float %f, %f
+  ret float %div
+}
+
+define float @fdiv_neg1(float %f) {
+; CHECK-LABEL: @fdiv_neg1(
+; CHECK-NEXT:    ret float -1.000000e+00
+;
+  %neg = fsub fast float -0.000000e+00, %f
+  %div = fdiv nnan float %neg, %f
+  ret float %div
+}
+
+define float @fdiv_neg2(float %f) {
+; CHECK-LABEL: @fdiv_neg2(
+; CHECK-NEXT:    ret float -1.000000e+00
+;
+  %neg = fsub fast float 0.000000e+00, %f
+  %div = fdiv nnan float %neg, %f
+  ret float %div
+}
+
+define float @fdiv_neg_invalid(float %f) {
+; CHECK-LABEL: @fdiv_neg_invalid(
+; CHECK-NEXT:    [[NEG:%.*]] = fsub fast float -0.000000e+00, [[F:%.*]]
+; CHECK-NEXT:    [[DIV:%.*]] = fdiv float [[NEG]], [[F]]
+; CHECK-NEXT:    ret float [[DIV]]
+;
+  %neg = fsub fast float -0.000000e+00, %f
+  %div = fdiv float %neg, %f
+  ret float %div
+}
+
+define float @fdiv_neg_swapped1(float %f) {
+; CHECK-LABEL: @fdiv_neg_swapped1(
+; CHECK-NEXT:    ret float -1.000000e+00
+;
+  %neg = fsub float -0.000000e+00, %f
+  %div = fdiv nnan float %f, %neg
+  ret float %div
+}
+
+define float @fdiv_neg_swapped2(float %f) {
+; CHECK-LABEL: @fdiv_neg_swapped2(
+; CHECK-NEXT:    ret float -1.000000e+00
+;
+  %neg = fsub float 0.000000e+00, %f
+  %div = fdiv nnan float %f, %neg
+  ret float %div
+}
+
+define <2 x float> @fdiv_neg_vec_undef_elt(<2 x float> %f) {
+; CHECK-LABEL: @fdiv_neg_vec_undef_elt(
+; CHECK-NEXT:    ret <2 x float> <float -1.000000e+00, float -1.000000e+00>
+;
+  %neg = fsub <2 x float> <float 0.0, float undef>, %f
+  %div = fdiv nnan <2 x float> %f, %neg
+  ret <2 x float> %div
+}
+
+; PR21126: http://llvm.org/bugs/show_bug.cgi?id=21126
+; With loose math, sqrt(X) * sqrt(X) is just X.
+
+declare double @llvm.sqrt.f64(double)
+
+define double @sqrt_squared(double %f) {
+; CHECK-LABEL: @sqrt_squared(
+; CHECK-NEXT:    ret double [[F:%.*]]
+;
+  %sqrt = call double @llvm.sqrt.f64(double %f)
+  %mul = fmul reassoc nnan nsz double %sqrt, %sqrt
+  ret double %mul
+}
+
+; Negative tests for the above transform: we need all 3 of those flags.
+
+define double @sqrt_squared_not_fast_enough1(double %f) {
+; CHECK-LABEL: @sqrt_squared_not_fast_enough1(
+; CHECK-NEXT:    [[SQRT:%.*]] = call double @llvm.sqrt.f64(double [[F:%.*]])
+; CHECK-NEXT:    [[MUL:%.*]] = fmul nnan nsz double [[SQRT]], [[SQRT]]
+; CHECK-NEXT:    ret double [[MUL]]
+;
+  %sqrt = call double @llvm.sqrt.f64(double %f)
+  %mul = fmul nnan nsz double %sqrt, %sqrt
+  ret double %mul
+}
+
+define double @sqrt_squared_not_fast_enough2(double %f) {
+; CHECK-LABEL: @sqrt_squared_not_fast_enough2(
+; CHECK-NEXT:    [[SQRT:%.*]] = call double @llvm.sqrt.f64(double [[F:%.*]])
+; CHECK-NEXT:    [[MUL:%.*]] = fmul reassoc nnan double [[SQRT]], [[SQRT]]
+; CHECK-NEXT:    ret double [[MUL]]
+;
+  %sqrt = call double @llvm.sqrt.f64(double %f)
+  %mul = fmul reassoc nnan double %sqrt, %sqrt
+  ret double %mul
+}
+
+define double @sqrt_squared_not_fast_enough3(double %f) {
+; CHECK-LABEL: @sqrt_squared_not_fast_enough3(
+; CHECK-NEXT:    [[SQRT:%.*]] = call double @llvm.sqrt.f64(double [[F:%.*]])
+; CHECK-NEXT:    [[MUL:%.*]] = fmul reassoc nsz double [[SQRT]], [[SQRT]]
+; CHECK-NEXT:    ret double [[MUL]]
+;
+  %sqrt = call double @llvm.sqrt.f64(double %f)
+  %mul = fmul reassoc nsz double %sqrt, %sqrt
+  ret double %mul
+}
+
+declare float @llvm.fabs.f32(float)
+declare float @llvm.sqrt.f32(float)
+declare float @llvm.canonicalize.f32(float)

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

Added: llvm/trunk/test/Transforms/InstSimplify/fdiv.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstSimplify/fdiv.ll?rev=358552&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstSimplify/fdiv.ll (added)
+++ llvm/trunk/test/Transforms/InstSimplify/fdiv.ll Tue Apr 16 21:52:47 2019
@@ -0,0 +1,52 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt < %s -instsimplify -S | FileCheck %s
+
+define float @fdiv_constant_fold() {
+; CHECK-LABEL: @fdiv_constant_fold(
+; CHECK-NEXT:    ret float 1.500000e+00
+;
+  %f = fdiv float 3.0, 2.0
+  ret float %f
+}
+
+define float @frem_constant_fold() {
+; CHECK-LABEL: @frem_constant_fold(
+; CHECK-NEXT:    ret float 1.000000e+00
+;
+  %f = frem float 3.0, 2.0
+  ret float %f
+}
+
+define double @fmul_fdiv_common_operand(double %x, double %y) {
+; CHECK-LABEL: @fmul_fdiv_common_operand(
+; CHECK-NEXT:    ret double %x
+;
+  %m = fmul double %x, %y
+  %d = fdiv reassoc nnan double %m, %y
+  ret double %d
+}
+
+; Negative test - the fdiv must be reassociative and not allow NaNs.
+
+define double @fmul_fdiv_common_operand_too_strict(double %x, double %y) {
+; CHECK-LABEL: @fmul_fdiv_common_operand_too_strict(
+; CHECK-NEXT:    [[M:%.*]] = fmul fast double %x, %y
+; CHECK-NEXT:    [[D:%.*]] = fdiv reassoc double [[M]], %y
+; CHECK-NEXT:    ret double [[D]]
+;
+  %m = fmul fast double %x, %y
+  %d = fdiv reassoc double %m, %y
+  ret double %d
+}
+
+; Commute the fmul operands. Use a vector type to verify that works too.
+
+define <2 x float> @fmul_fdiv_common_operand_commute_vec(<2 x float> %x, <2 x float> %y) {
+; CHECK-LABEL: @fmul_fdiv_common_operand_commute_vec(
+; CHECK-NEXT:    ret <2 x float> %x
+;
+  %m = fmul <2 x float> %y, %x
+  %d = fdiv fast <2 x float> %m, %y
+  ret <2 x float> %d
+}
+




More information about the llvm-commits mailing list