diff options
Diffstat (limited to 'test/Transforms/InstCombine')
-rw-r--r-- | test/Transforms/InstCombine/2008-09-29-FoldingOr.ll | 10 | ||||
-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.cfg | 2 | ||||
-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.ll | 52 | ||||
-rw-r--r-- | test/Transforms/InstCombine/lshr.ll | 72 | ||||
-rw-r--r-- | test/Transforms/InstCombine/memchr.ll | 9 | ||||
-rw-r--r-- | test/Transforms/InstCombine/set.ll | 94 | ||||
-rw-r--r-- | test/Transforms/InstCombine/wcslen-1.ll | 191 | ||||
-rw-r--r-- | test/Transforms/InstCombine/wcslen-2.ll | 18 | ||||
-rw-r--r-- | test/Transforms/InstCombine/wcslen-3.ll | 197 |
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 +} |