summaryrefslogtreecommitdiff
path: root/test/Transforms/InstCombine
diff options
context:
space:
mode:
Diffstat (limited to 'test/Transforms/InstCombine')
-rw-r--r--test/Transforms/InstCombine/2008-09-29-FoldingOr.ll10
-rw-r--r--test/Transforms/InstCombine/AMDGPU/amdgcn-demanded-vector-elts.ll (renamed from test/Transforms/InstCombine/amdgcn-demanded-vector-elts.ll)0
-rw-r--r--test/Transforms/InstCombine/NVPTX/lit.local.cfg2
-rw-r--r--test/Transforms/InstCombine/NVPTX/nvvm-intrins.ll (renamed from test/Transforms/InstCombine/nvvm-intrins.ll)0
-rw-r--r--test/Transforms/InstCombine/cast.ll52
-rw-r--r--test/Transforms/InstCombine/lshr.ll72
-rw-r--r--test/Transforms/InstCombine/memchr.ll9
-rw-r--r--test/Transforms/InstCombine/set.ll94
-rw-r--r--test/Transforms/InstCombine/wcslen-1.ll191
-rw-r--r--test/Transforms/InstCombine/wcslen-2.ll18
-rw-r--r--test/Transforms/InstCombine/wcslen-3.ll197
11 files changed, 625 insertions, 20 deletions
diff --git a/test/Transforms/InstCombine/2008-09-29-FoldingOr.ll b/test/Transforms/InstCombine/2008-09-29-FoldingOr.ll
deleted file mode 100644
index 4d00d495a07f4..0000000000000
--- a/test/Transforms/InstCombine/2008-09-29-FoldingOr.ll
+++ /dev/null
@@ -1,10 +0,0 @@
-; RUN: opt < %s -instcombine -S | grep "or i1"
-; PR2844
-
-define i32 @test(i32 %p_74) {
- %A = icmp eq i32 %p_74, 0 ; <i1> [#uses=1]
- %B = icmp slt i32 %p_74, -638208501 ; <i1> [#uses=1]
- %or.cond = or i1 %A, %B ; <i1> [#uses=1]
- %iftmp.10.0 = select i1 %or.cond, i32 0, i32 1 ; <i32> [#uses=1]
- ret i32 %iftmp.10.0
-}
diff --git a/test/Transforms/InstCombine/amdgcn-demanded-vector-elts.ll b/test/Transforms/InstCombine/AMDGPU/amdgcn-demanded-vector-elts.ll
index 0c4842c159880..0c4842c159880 100644
--- a/test/Transforms/InstCombine/amdgcn-demanded-vector-elts.ll
+++ b/test/Transforms/InstCombine/AMDGPU/amdgcn-demanded-vector-elts.ll
diff --git a/test/Transforms/InstCombine/NVPTX/lit.local.cfg b/test/Transforms/InstCombine/NVPTX/lit.local.cfg
new file mode 100644
index 0000000000000..2cb98eb371b21
--- /dev/null
+++ b/test/Transforms/InstCombine/NVPTX/lit.local.cfg
@@ -0,0 +1,2 @@
+if not 'NVPTX' in config.root.targets:
+ config.unsupported = True
diff --git a/test/Transforms/InstCombine/nvvm-intrins.ll b/test/Transforms/InstCombine/NVPTX/nvvm-intrins.ll
index cb65b8fdc5477..cb65b8fdc5477 100644
--- a/test/Transforms/InstCombine/nvvm-intrins.ll
+++ b/test/Transforms/InstCombine/NVPTX/nvvm-intrins.ll
diff --git a/test/Transforms/InstCombine/cast.ll b/test/Transforms/InstCombine/cast.ll
index a4375a5cd57e8..486a617097e17 100644
--- a/test/Transforms/InstCombine/cast.ll
+++ b/test/Transforms/InstCombine/cast.ll
@@ -1470,3 +1470,55 @@ define i32 @test93(i32 %A) {
%D = trunc i96 %C to i32
ret i32 %D
}
+
+; The following four tests sext + lshr + trunc patterns.
+; PR33078
+
+define i8 @pr33078_1(i8 %A) {
+; CHECK-LABEL: @pr33078_1(
+; CHECK-NEXT: [[C:%.*]] = ashr i8 [[A:%.*]], 7
+; CHECK-NEXT: ret i8 [[C]]
+;
+ %B = sext i8 %A to i16
+ %C = lshr i16 %B, 8
+ %D = trunc i16 %C to i8
+ ret i8 %D
+}
+
+define i12 @pr33078_2(i8 %A) {
+; CHECK-LABEL: @pr33078_2(
+; CHECK-NEXT: [[C:%.*]] = ashr i8 [[A:%.*]], 4
+; CHECK-NEXT: [[D:%.*]] = sext i8 [[C]] to i12
+; CHECK-NEXT: ret i12 [[D]]
+;
+ %B = sext i8 %A to i16
+ %C = lshr i16 %B, 4
+ %D = trunc i16 %C to i12
+ ret i12 %D
+}
+
+define i4 @pr33078_3(i8 %A) {
+; CHECK-LABEL: @pr33078_3(
+; CHECK-NEXT: [[B:%.*]] = sext i8 [[A:%.*]] to i16
+; CHECK-NEXT: [[C:%.*]] = lshr i16 [[B]], 12
+; CHECK-NEXT: [[D:%.*]] = trunc i16 [[C]] to i4
+; CHECK-NEXT: ret i4 [[D]]
+;
+ %B = sext i8 %A to i16
+ %C = lshr i16 %B, 12
+ %D = trunc i16 %C to i4
+ ret i4 %D
+}
+
+define i8 @pr33078_4(i3 %x) {
+; Don't turn this in an `ashr`. This was getting miscompiled
+; CHECK-LABEL: @pr33078_4(
+; CHECK-NEXT: [[B:%.*]] = sext i3 %x to i16
+; CHECK-NEXT: [[C:%.*]] = lshr i16 [[B]], 13
+; CHECK-NEXT: [[D:%.*]] = trunc i16 [[C]] to i8
+; CHECK-NEXT: ret i8 [[D]]
+ %B = sext i3 %x to i16
+ %C = lshr i16 %B, 13
+ %D = trunc i16 %C to i8
+ ret i8 %D
+}
diff --git a/test/Transforms/InstCombine/lshr.ll b/test/Transforms/InstCombine/lshr.ll
index b81371b030429..0cad7f833ab6f 100644
--- a/test/Transforms/InstCombine/lshr.ll
+++ b/test/Transforms/InstCombine/lshr.ll
@@ -100,3 +100,75 @@ define <2 x i8> @lshr_exact_splat_vec(<2 x i8> %x) {
ret <2 x i8> %lshr
}
+; FIXME: The bool bit got smeared across a wide val, but then we zero'd out those bits. This is just a zext.
+
+define i16 @bool_zext(i1 %x) {
+; CHECK-LABEL: @bool_zext(
+; CHECK-NEXT: [[SEXT:%.*]] = sext i1 %x to i16
+; CHECK-NEXT: [[HIBIT:%.*]] = lshr i16 [[SEXT]], 15
+; CHECK-NEXT: ret i16 [[HIBIT]]
+;
+ %sext = sext i1 %x to i16
+ %hibit = lshr i16 %sext, 15
+ ret i16 %hibit
+}
+
+define <2 x i8> @bool_zext_splat(<2 x i1> %x) {
+; CHECK-LABEL: @bool_zext_splat(
+; CHECK-NEXT: [[SEXT:%.*]] = sext <2 x i1> %x to <2 x i8>
+; CHECK-NEXT: [[HIBIT:%.*]] = lshr <2 x i8> [[SEXT]], <i8 7, i8 7>
+; CHECK-NEXT: ret <2 x i8> [[HIBIT]]
+;
+ %sext = sext <2 x i1> %x to <2 x i8>
+ %hibit = lshr <2 x i8> %sext, <i8 7, i8 7>
+ ret <2 x i8> %hibit
+}
+
+; FIXME: The replicated sign bits are all that's left. This could be ashr+zext.
+
+define i16 @smear_sign_and_widen(i4 %x) {
+; CHECK-LABEL: @smear_sign_and_widen(
+; CHECK-NEXT: [[SEXT:%.*]] = sext i4 %x to i16
+; CHECK-NEXT: [[HIBIT:%.*]] = lshr i16 [[SEXT]], 12
+; CHECK-NEXT: ret i16 [[HIBIT]]
+;
+ %sext = sext i4 %x to i16
+ %hibit = lshr i16 %sext, 12
+ ret i16 %hibit
+}
+
+define <2 x i8> @smear_sign_and_widen_splat(<2 x i6> %x) {
+; CHECK-LABEL: @smear_sign_and_widen_splat(
+; CHECK-NEXT: [[SEXT:%.*]] = sext <2 x i6> %x to <2 x i8>
+; CHECK-NEXT: [[HIBIT:%.*]] = lshr <2 x i8> [[SEXT]], <i8 2, i8 2>
+; CHECK-NEXT: ret <2 x i8> [[HIBIT]]
+;
+ %sext = sext <2 x i6> %x to <2 x i8>
+ %hibit = lshr <2 x i8> %sext, <i8 2, i8 2>
+ ret <2 x i8> %hibit
+}
+
+; FIXME: All of the replicated sign bits are wiped out by the lshr. This could be lshr+zext.
+
+define i16 @fake_sext(i3 %x) {
+; CHECK-LABEL: @fake_sext(
+; CHECK-NEXT: [[SEXT:%.*]] = sext i3 %x to i16
+; CHECK-NEXT: [[SH:%.*]] = lshr i16 [[SEXT]], 15
+; CHECK-NEXT: ret i16 [[SH]]
+;
+ %sext = sext i3 %x to i16
+ %sh = lshr i16 %sext, 15
+ ret i16 %sh
+}
+
+define <2 x i8> @fake_sext_splat(<2 x i3> %x) {
+; CHECK-LABEL: @fake_sext_splat(
+; CHECK-NEXT: [[SEXT:%.*]] = sext <2 x i3> %x to <2 x i8>
+; CHECK-NEXT: [[SH:%.*]] = lshr <2 x i8> [[SEXT]], <i8 7, i8 7>
+; CHECK-NEXT: ret <2 x i8> [[SH]]
+;
+ %sext = sext <2 x i3> %x to <2 x i8>
+ %sh = lshr <2 x i8> %sext, <i8 7, i8 7>
+ ret <2 x i8> %sh
+}
+
diff --git a/test/Transforms/InstCombine/memchr.ll b/test/Transforms/InstCombine/memchr.ll
index b0573567bf604..5a081c222fb02 100644
--- a/test/Transforms/InstCombine/memchr.ll
+++ b/test/Transforms/InstCombine/memchr.ll
@@ -190,3 +190,12 @@ define i1 @test15(i32 %C) {
%cmp = icmp ne i8* %dst, null
ret i1 %cmp
}
+
+@s = internal constant [1 x i8] [i8 0], align 1
+define i8* @pr32124() {
+; CHECK-LABEL: @pr32124(
+; CHECK-NEXT: ret i8* getelementptr inbounds ([1 x i8], [1 x i8]* @s, i32 0, i32 0)
+;
+ %res = tail call i8* @memchr(i8* getelementptr ([1 x i8], [1 x i8]* @s, i64 0, i64 0), i32 0, i32 1)
+ ret i8* %res
+}
diff --git a/test/Transforms/InstCombine/set.ll b/test/Transforms/InstCombine/set.ll
index 494a603790114..db2b4c3558e81 100644
--- a/test/Transforms/InstCombine/set.ll
+++ b/test/Transforms/InstCombine/set.ll
@@ -110,8 +110,8 @@ define i1 @test12(i1 %A) {
define i1 @test13(i1 %A, i1 %B) {
; CHECK-LABEL: @test13(
-; CHECK-NEXT: [[CTMP:%.*]] = xor i1 %B, true
-; CHECK-NEXT: [[C:%.*]] = or i1 [[CTMP]], %A
+; CHECK-NEXT: [[TMP1:%.*]] = xor i1 %B, true
+; CHECK-NEXT: [[C:%.*]] = or i1 [[TMP1]], %A
; CHECK-NEXT: ret i1 [[C]]
;
%C = icmp uge i1 %A, %B
@@ -120,8 +120,8 @@ define i1 @test13(i1 %A, i1 %B) {
define <2 x i1> @test13vec(<2 x i1> %A, <2 x i1> %B) {
; CHECK-LABEL: @test13vec(
-; CHECK-NEXT: [[CTMP:%.*]] = xor <2 x i1> %B, <i1 true, i1 true>
-; CHECK-NEXT: [[C:%.*]] = or <2 x i1> [[CTMP]], %A
+; CHECK-NEXT: [[TMP1:%.*]] = xor <2 x i1> %B, <i1 true, i1 true>
+; CHECK-NEXT: [[C:%.*]] = or <2 x i1> [[TMP1]], %A
; CHECK-NEXT: ret <2 x i1> [[C]]
;
%C = icmp uge <2 x i1> %A, %B
@@ -130,8 +130,8 @@ define <2 x i1> @test13vec(<2 x i1> %A, <2 x i1> %B) {
define i1 @test14(i1 %A, i1 %B) {
; CHECK-LABEL: @test14(
-; CHECK-NEXT: [[CTMP:%.*]] = xor i1 %A, %B
-; CHECK-NEXT: [[C:%.*]] = xor i1 [[CTMP]], true
+; CHECK-NEXT: [[TMP1:%.*]] = xor i1 %A, %B
+; CHECK-NEXT: [[C:%.*]] = xor i1 [[TMP1]], true
; CHECK-NEXT: ret i1 [[C]]
;
%C = icmp eq i1 %A, %B
@@ -140,14 +140,88 @@ define i1 @test14(i1 %A, i1 %B) {
define <3 x i1> @test14vec(<3 x i1> %A, <3 x i1> %B) {
; CHECK-LABEL: @test14vec(
-; CHECK-NEXT: [[CTMP:%.*]] = xor <3 x i1> %A, %B
-; CHECK-NEXT: [[C:%.*]] = xor <3 x i1> [[CTMP]], <i1 true, i1 true, i1 true>
+; CHECK-NEXT: [[TMP1:%.*]] = xor <3 x i1> %A, %B
+; CHECK-NEXT: [[C:%.*]] = xor <3 x i1> [[TMP1]], <i1 true, i1 true, i1 true>
; CHECK-NEXT: ret <3 x i1> [[C]]
;
%C = icmp eq <3 x i1> %A, %B
ret <3 x i1> %C
}
+define i1 @bool_eq0(i64 %a) {
+; CHECK-LABEL: @bool_eq0(
+; CHECK-NEXT: [[TMP1:%.*]] = icmp sgt i64 %a, 1
+; CHECK-NEXT: ret i1 [[TMP1]]
+;
+ %b = icmp sgt i64 %a, 0
+ %c = icmp eq i64 %a, 1
+ %notc = icmp eq i1 %c, false
+ %and = and i1 %b, %notc
+ ret i1 %and
+}
+
+; FIXME: This is equivalent to the previous test.
+
+define i1 @xor_of_icmps(i64 %a) {
+; CHECK-LABEL: @xor_of_icmps(
+; CHECK-NEXT: [[B:%.*]] = icmp sgt i64 %a, 0
+; CHECK-NEXT: [[C:%.*]] = icmp eq i64 %a, 1
+; CHECK-NEXT: [[XOR:%.*]] = xor i1 [[C]], [[B]]
+; CHECK-NEXT: ret i1 [[XOR]]
+;
+ %b = icmp sgt i64 %a, 0
+ %c = icmp eq i64 %a, 1
+ %xor = xor i1 %c, %b
+ ret i1 %xor
+}
+
+; FIXME: This is also equivalent to the previous test.
+
+define i1 @xor_of_icmps_commute(i64 %a) {
+; CHECK-LABEL: @xor_of_icmps_commute(
+; CHECK-NEXT: [[B:%.*]] = icmp sgt i64 %a, 0
+; CHECK-NEXT: [[C:%.*]] = icmp eq i64 %a, 1
+; CHECK-NEXT: [[XOR:%.*]] = xor i1 [[B]], [[C]]
+; CHECK-NEXT: ret i1 [[XOR]]
+;
+ %b = icmp sgt i64 %a, 0
+ %c = icmp eq i64 %a, 1
+ %xor = xor i1 %b, %c
+ ret i1 %xor
+}
+
+; FIXME: This is (a != 5).
+
+define i1 @xor_of_icmps_folds_more(i64 %a) {
+; CHECK-LABEL: @xor_of_icmps_folds_more(
+; CHECK-NEXT: [[B:%.*]] = icmp sgt i64 %a, 4
+; CHECK-NEXT: [[C:%.*]] = icmp slt i64 %a, 6
+; CHECK-NEXT: [[XOR:%.*]] = xor i1 [[B]], [[C]]
+; CHECK-NEXT: ret i1 [[XOR]]
+;
+ %b = icmp sgt i64 %a, 4
+ %c = icmp slt i64 %a, 6
+ %xor = xor i1 %b, %c
+ ret i1 %xor
+}
+
+; https://bugs.llvm.org/show_bug.cgi?id=2844
+
+define i32 @PR2844(i32 %x) {
+; CHECK-LABEL: @PR2844(
+; CHECK-NEXT: [[A:%.*]] = icmp eq i32 %x, 0
+; CHECK-NEXT: [[B:%.*]] = icmp sgt i32 %x, -638208502
+; CHECK-NEXT: [[NOT_OR:%.*]] = xor i1 [[A]], [[B]]
+; CHECK-NEXT: [[SEL:%.*]] = zext i1 [[NOT_OR]] to i32
+; CHECK-NEXT: ret i32 [[SEL]]
+;
+ %A = icmp eq i32 %x, 0
+ %B = icmp slt i32 %x, -638208501
+ %or = or i1 %A, %B
+ %sel = select i1 %or, i32 0, i32 1
+ ret i32 %sel
+}
+
define i1 @test16(i32 %A) {
; CHECK-LABEL: @test16(
; CHECK-NEXT: ret i1 false
@@ -191,8 +265,8 @@ endif:
define i1 @test19(i1 %A, i1 %B) {
; CHECK-LABEL: @test19(
-; CHECK-NEXT: [[CTMP:%.*]] = xor i1 %A, %B
-; CHECK-NEXT: [[C:%.*]] = xor i1 [[CTMP]], true
+; CHECK-NEXT: [[TMP1:%.*]] = xor i1 %A, %B
+; CHECK-NEXT: [[C:%.*]] = xor i1 [[TMP1]], true
; CHECK-NEXT: ret i1 [[C]]
;
%a = zext i1 %A to i32
diff --git a/test/Transforms/InstCombine/wcslen-1.ll b/test/Transforms/InstCombine/wcslen-1.ll
new file mode 100644
index 0000000000000..d4e51750f6da7
--- /dev/null
+++ b/test/Transforms/InstCombine/wcslen-1.ll
@@ -0,0 +1,191 @@
+; 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*)
+
+@hello = constant [6 x i32] [i32 104, i32 101, i32 108, i32 108, i32 111, i32 0]
+@longer = constant [7 x i32] [i32 108, i32 111, i32 110, i32 103, i32 101, i32 114, i32 0]
+@null = constant [1 x i32] zeroinitializer
+@null_hello = constant [7 x i32] [i32 0, i32 104, i32 101, i32 108, i32 108, i32 111, i32 0]
+@nullstring = constant i32 0
+@a = common global [32 x i32] zeroinitializer, align 1
+@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: [[TMP1:%.*]] = zext i32 [[AND]] to i64
+; CHECK-NEXT: [[TMP2:%.*]] = sub nsw i64 9, [[TMP1]]
+; CHECK-NEXT: ret i64 [[TMP2]]
+;
+ %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* [[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* [[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
+}
+
+@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
+}
diff --git a/test/Transforms/InstCombine/wcslen-2.ll b/test/Transforms/InstCombine/wcslen-2.ll
new file mode 100644
index 0000000000000..c1a70312a2b36
--- /dev/null
+++ b/test/Transforms/InstCombine/wcslen-2.ll
@@ -0,0 +1,18 @@
+; 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"
+
+@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
+}
diff --git a/test/Transforms/InstCombine/wcslen-3.ll b/test/Transforms/InstCombine/wcslen-3.ll
new file mode 100644
index 0000000000000..c766ff21412d0
--- /dev/null
+++ b/test/Transforms/InstCombine/wcslen-3.ll
@@ -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*)
+
+@hello = constant [6 x i16] [i16 104, i16 101, i16 108, i16 108, i16 111, i16 0]
+@longer = constant [7 x i16] [i16 108, i16 111, i16 110, i16 103, i16 101, i16 114, i16 0]
+@null = constant [1 x i16] zeroinitializer
+@null_hello = constant [7 x i16] [i16 0, i16 104, i16 101, i16 108, i16 108, i16 111, i16 0]
+@nullstring = constant i16 0
+@a = common global [32 x i16] zeroinitializer, align 1
+@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: [[TMP1:%.*]] = zext i16 [[AND]] to i64
+; CHECK-NEXT: [[TMP2:%.*]] = sub nsw i64 9, [[TMP1]]
+; CHECK-NEXT: ret i64 [[TMP2]]
+;
+ %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* [[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* [[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
+}
+
+@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
+}