diff options
Diffstat (limited to 'test/Transforms/InstCombine/select.ll')
-rw-r--r-- | test/Transforms/InstCombine/select.ll | 386 |
1 files changed, 321 insertions, 65 deletions
diff --git a/test/Transforms/InstCombine/select.ll b/test/Transforms/InstCombine/select.ll index d625f3b1b33d..054f00a0de49 100644 --- a/test/Transforms/InstCombine/select.ll +++ b/test/Transforms/InstCombine/select.ll @@ -1,7 +1,8 @@ +; RUN: opt < %s -instcombine -S | FileCheck %s ; This test makes sure that these instructions are properly eliminated. ; PR1822 -; RUN: opt < %s -instcombine -S | FileCheck %s +target datalayout = "e-p:64:64-p1:16:16-p2:32:32:32-p3:64:64:64" define i32 @test1(i32 %A, i32 %B) { %C = select i1 false, i32 %A, i32 %B @@ -307,6 +308,26 @@ define i32 @test16(i1 %C, i32* %P) { ; CHECK: ret i32 %V } +;; It may be legal to load from a null address in a non-zero address space +define i32 @test16_neg(i1 %C, i32 addrspace(1)* %P) { + %P2 = select i1 %C, i32 addrspace(1)* %P, i32 addrspace(1)* null + %V = load i32 addrspace(1)* %P2 + ret i32 %V +; CHECK-LABEL: @test16_neg +; CHECK-NEXT: %P2 = select i1 %C, i32 addrspace(1)* %P, i32 addrspace(1)* null +; CHECK-NEXT: %V = load i32 addrspace(1)* %P2 +; CHECK: ret i32 %V +} +define i32 @test16_neg2(i1 %C, i32 addrspace(1)* %P) { + %P2 = select i1 %C, i32 addrspace(1)* null, i32 addrspace(1)* %P + %V = load i32 addrspace(1)* %P2 + ret i32 %V +; CHECK-LABEL: @test16_neg2 +; CHECK-NEXT: %P2 = select i1 %C, i32 addrspace(1)* null, i32 addrspace(1)* %P +; CHECK-NEXT: %V = load i32 addrspace(1)* %P2 +; CHECK: ret i32 %V +} + define i1 @test17(i32* %X, i1 %C) { %R = select i1 %C, i32* %X, i32* null %RV = icmp eq i32* %R, null @@ -916,9 +937,9 @@ define i32 @select_icmp_eq_and_4096_0_or_4096(i32 %x, i32 %y) { } ; CHECK-LABEL: @select_icmp_eq_0_and_1_or_1( -; CHECK-NEXT: [[AND:%[a-z0-9]+]] = and i64 %x, 1 -; CHECK-NEXT: [[ZEXT:%[a-z0-9]+]] = trunc i64 [[AND]] to i32 -; CHECK-NEXT: [[OR:%[a-z0-9]+]] = or i32 [[XOR]], %y +; CHECK-NEXT: [[TRUNC:%.+]] = trunc i64 %x to i32 +; CHECK-NEXT: [[AND:%.+]] = and i32 [[TRUNC]], 1 +; CHECK-NEXT: [[OR:%.+]] = or i32 [[XOR]], %y ; CHECK-NEXT: ret i32 [[OR]] define i32 @select_icmp_eq_0_and_1_or_1(i64 %x, i32 %y) { %and = and i64 %x, 1 @@ -957,11 +978,11 @@ define i32 @select_icmp_ne_0_and_32_or_4096(i32 %x, i32 %y) { } ; CHECK-LABEL: @select_icmp_ne_0_and_1073741824_or_8( -; CHECK-NEXT: [[LSHR:%[a-z0-9]+]] = lshr i32 %x, 27 -; CHECK-NEXT: [[AND:%[a-z0-9]+]] = and i32 [[LSHR]], 8 -; CHECK-NEXT: [[TRUNC:%[a-z0-9]+]] = trunc i32 [[AND]] to i8 -; CHECK-NEXT: [[XOR:%[a-z0-9]+]] = xor i8 [[TRUNC]], 8 -; CHECK-NEXT: [[OR:%[a-z0-9]+]] = or i8 [[XOR]], %y +; CHECK-NEXT: [[LSHR:%.+]] = lshr i32 %x, 27 +; CHECK-NEXT: [[TRUNC:%.+]] = trunc i32 [[LSHR]] to i8 +; CHECK-NEXT: [[AND:%.+]] = and i8 [[TRUNC]], 8 +; CHECK-NEXT: [[XOR:%.+]] = xor i8 [[AND]], 8 +; CHECK-NEXT: [[OR:%.+]] = or i8 [[XOR]], %y ; CHECK-NEXT: ret i8 [[OR]] define i8 @select_icmp_ne_0_and_1073741824_or_8(i32 %x, i8 %y) { %and = and i32 %x, 1073741824 @@ -996,17 +1017,6 @@ define <2 x i32> @select_icmp_eq_and_1_0_or_vector_of_2s(i32 %x, <2 x i32> %y) { ret <2 x i32> %select } -; CHECK-LABEL: @select_icmp_and_8_eq_0_or_8( -; CHECK-NEXT: [[OR:%[a-z0-9]+]] = or i32 %x, 8 -; CHECK-NEXT: ret i32 [[OR]] -define i32 @select_icmp_and_8_eq_0_or_8(i32 %x) { - %and = and i32 %x, 8 - %cmp = icmp eq i32 %and, 0 - %or = or i32 %x, 8 - %or.x = select i1 %cmp, i32 %or, i32 %x - ret i32 %or.x -} - ; CHECK-LABEL: @select_icmp_and_8_ne_0_xor_8( ; CHECK-NEXT: [[AND:%[a-z0-9]+]] = and i32 %x, -9 ; CHECK-NEXT: ret i32 [[AND]] @@ -1029,27 +1039,6 @@ define i32 @select_icmp_and_8_eq_0_xor_8(i32 %x) { ret i32 %xor.x } -; CHECK-LABEL: @select_icmp_and_8_ne_0_and_not_8( -; CHECK-NEXT: [[AND:%[a-z0-9]+]] = and i32 %x, -9 -; CHECK-NEXT: ret i32 [[AND]] -define i32 @select_icmp_and_8_ne_0_and_not_8(i32 %x) { - %and = and i32 %x, 8 - %cmp = icmp eq i32 %and, 0 - %and1 = and i32 %x, -9 - %x.and1 = select i1 %cmp, i32 %x, i32 %and1 - ret i32 %x.and1 -} - -; CHECK-LABEL: @select_icmp_and_8_eq_0_and_not_8( -; CHECK-NEXT: ret i32 %x -define i32 @select_icmp_and_8_eq_0_and_not_8(i32 %x) { - %and = and i32 %x, 8 - %cmp = icmp eq i32 %and, 0 - %and1 = and i32 %x, -9 - %and1.x = select i1 %cmp, i32 %and1, i32 %x - ret i32 %and1.x -} - ; CHECK-LABEL: @select_icmp_x_and_8_eq_0_y_xor_8( ; CHECK: select i1 %cmp, i64 %y, i64 %xor define i64 @select_icmp_x_and_8_eq_0_y_xor_8(i32 %x, i64 %y) { @@ -1060,16 +1049,6 @@ define i64 @select_icmp_x_and_8_eq_0_y_xor_8(i32 %x, i64 %y) { ret i64 %y.xor } -; CHECK-LABEL: @select_icmp_x_and_8_eq_0_y_and_not_8( -; CHECK: select i1 %cmp, i64 %y, i64 %and1 -define i64 @select_icmp_x_and_8_eq_0_y_and_not_8(i32 %x, i64 %y) { - %and = and i32 %x, 8 - %cmp = icmp eq i32 %and, 0 - %and1 = and i64 %y, -9 - %y.and1 = select i1 %cmp, i64 %y, i64 %and1 - ret i64 %y.and1 -} - ; CHECK-LABEL: @select_icmp_x_and_8_ne_0_y_xor_8( ; CHECK: select i1 %cmp, i64 %xor, i64 %y define i64 @select_icmp_x_and_8_ne_0_y_xor_8(i32 %x, i64 %y) { @@ -1080,16 +1059,6 @@ define i64 @select_icmp_x_and_8_ne_0_y_xor_8(i32 %x, i64 %y) { ret i64 %xor.y } -; CHECK-LABEL: @select_icmp_x_and_8_ne_0_y_and_not_8( -; CHECK: select i1 %cmp, i64 %and1, i64 %y -define i64 @select_icmp_x_and_8_ne_0_y_and_not_8(i32 %x, i64 %y) { - %and = and i32 %x, 8 - %cmp = icmp eq i32 %and, 0 - %and1 = and i64 %y, -9 - %and1.y = select i1 %cmp, i64 %and1, i64 %y - ret i64 %and1.y -} - ; CHECK-LABEL: @select_icmp_x_and_8_ne_0_y_or_8( ; CHECK: xor i64 %1, 8 ; CHECK: or i64 %2, %y @@ -1101,6 +1070,39 @@ define i64 @select_icmp_x_and_8_ne_0_y_or_8(i32 %x, i64 %y) { ret i64 %or.y } +; CHECK-LABEL: @select_icmp_and_2147483648_ne_0_xor_2147483648( +; CHECK-NEXT: [[AND:%[a-z0-9]+]] = and i32 %x, 2147483647 +; CHECK-NEXT: ret i32 [[AND]] +define i32 @select_icmp_and_2147483648_ne_0_xor_2147483648(i32 %x) { + %and = and i32 %x, 2147483648 + %cmp = icmp eq i32 %and, 0 + %xor = xor i32 %x, 2147483648 + %x.xor = select i1 %cmp, i32 %x, i32 %xor + ret i32 %x.xor +} + +; CHECK-LABEL: @select_icmp_and_2147483648_eq_0_xor_2147483648( +; CHECK-NEXT: [[OR:%[a-z0-9]+]] = or i32 %x, -2147483648 +; CHECK-NEXT: ret i32 [[OR]] +define i32 @select_icmp_and_2147483648_eq_0_xor_2147483648(i32 %x) { + %and = and i32 %x, 2147483648 + %cmp = icmp eq i32 %and, 0 + %xor = xor i32 %x, 2147483648 + %xor.x = select i1 %cmp, i32 %xor, i32 %x + ret i32 %xor.x +} + +; CHECK-LABEL: @select_icmp_x_and_2147483648_ne_0_or_2147483648( +; CHECK-NEXT: [[OR:%[a-z0-9]+]] = or i32 %x, -2147483648 +; CHECK-NEXT: ret i32 [[OR]] +define i32 @select_icmp_x_and_2147483648_ne_0_or_2147483648(i32 %x) { + %and = and i32 %x, 2147483648 + %cmp = icmp eq i32 %and, 0 + %or = or i32 %x, 2147483648 + %or.x = select i1 %cmp, i32 %or, i32 %x + ret i32 %or.x +} + define i32 @test65(i64 %x) { %1 = and i64 %x, 16 %2 = icmp ne i64 %1, 0 @@ -1108,10 +1110,11 @@ define i32 @test65(i64 %x) { ret i32 %3 ; CHECK-LABEL: @test65( -; CHECK: and i64 %x, 16 -; CHECK: trunc i64 %1 to i32 -; CHECK: lshr exact i32 %2, 3 -; CHECK: xor i32 %3, 42 +; CHECK: %[[TRUNC:.*]] = trunc i64 %x to i32 +; CHECK: %[[LSHR:.*]] = lshr i32 %[[TRUNC]], 3 +; CHECK: %[[AND:.*]] = and i32 %[[LSHR]], 2 +; CHECK: %[[XOR:.*]] = xor i32 %[[AND]], 42 +; CHECK: ret i32 %[[XOR]] } define i32 @test66(i64 %x) { @@ -1236,3 +1239,256 @@ define i32 @test75(i32 %x) { ; CHECK-NEXT: [[SEL:%[a-z0-9]+]] = select i1 [[CMP]], i32 68, i32 %x ; CHECK-NEXT: ret i32 [[SEL]] } + +@under_aligned = external global i32, align 1 + +define i32 @test76(i1 %flag, i32* %x) { +; The load here must not be speculated around the select. One side of the +; select is trivially dereferencable but may have a lower alignment than the +; load does. +; CHECK-LABEL: @test76( +; CHECK: store i32 0, i32* %x +; CHECK: %[[P:.*]] = select i1 %flag, i32* @under_aligned, i32* %x +; CHECK: load i32* %[[P]] + + store i32 0, i32* %x + %p = select i1 %flag, i32* @under_aligned, i32* %x + %v = load i32* %p + ret i32 %v +} + +declare void @scribble_on_i32(i32*) + +define i32 @test77(i1 %flag, i32* %x) { +; The load here must not be speculated around the select. One side of the +; select is trivially dereferencable but may have a lower alignment than the +; load does. +; CHECK-LABEL: @test77( +; CHECK: %[[A:.*]] = alloca i32, align 1 +; CHECK: call void @scribble_on_i32(i32* %[[A]]) +; CHECK: store i32 0, i32* %x +; CHECK: %[[P:.*]] = select i1 %flag, i32* %[[A]], i32* %x +; CHECK: load i32* %[[P]] + + %under_aligned = alloca i32, align 1 + call void @scribble_on_i32(i32* %under_aligned) + store i32 0, i32* %x + %p = select i1 %flag, i32* %under_aligned, i32* %x + %v = load i32* %p + ret i32 %v +} + +define i32 @test78(i1 %flag, i32* %x, i32* %y, i32* %z) { +; Test that we can speculate the loads around the select even when we can't +; fold the load completely away. +; CHECK-LABEL: @test78( +; CHECK: %[[V1:.*]] = load i32* %x +; CHECK-NEXT: %[[V2:.*]] = load i32* %y +; CHECK-NEXT: %[[S:.*]] = select i1 %flag, i32 %[[V1]], i32 %[[V2]] +; CHECK-NEXT: ret i32 %[[S]] +entry: + store i32 0, i32* %x + store i32 0, i32* %y + ; Block forwarding by storing to %z which could alias either %x or %y. + store i32 42, i32* %z + %p = select i1 %flag, i32* %x, i32* %y + %v = load i32* %p + ret i32 %v +} + +define float @test79(i1 %flag, float* %x, i32* %y, i32* %z) { +; Test that we can speculate the loads around the select even when we can't +; fold the load completely away. +; CHECK-LABEL: @test79( +; CHECK: %[[V1:.*]] = load float* %x +; CHECK-NEXT: %[[V2:.*]] = load float* %y +; CHECK-NEXT: %[[S:.*]] = select i1 %flag, float %[[V1]], float %[[V2]] +; CHECK-NEXT: ret float %[[S]] +entry: + %x1 = bitcast float* %x to i32* + %y1 = bitcast i32* %y to float* + store i32 0, i32* %x1 + store i32 0, i32* %y + ; Block forwarding by storing to %z which could alias either %x or %y. + store i32 42, i32* %z + %p = select i1 %flag, float* %x, float* %y1 + %v = load float* %p + ret float %v +} + +define i32 @test80(i1 %flag) { +; Test that when we speculate the loads around the select they fold throug +; load->load folding and load->store folding. +; CHECK-LABEL: @test80( +; CHECK: %[[X:.*]] = alloca i32 +; CHECK-NEXT: %[[Y:.*]] = alloca i32 +; CHECK: %[[V:.*]] = load i32* %[[X]] +; CHECK-NEXT: store i32 %[[V]], i32* %[[Y]] +; CHECK-NEXT: ret i32 %[[V]] +entry: + %x = alloca i32 + %y = alloca i32 + call void @scribble_on_i32(i32* %x) + call void @scribble_on_i32(i32* %y) + %tmp = load i32* %x + store i32 %tmp, i32* %y + %p = select i1 %flag, i32* %x, i32* %y + %v = load i32* %p + ret i32 %v +} + +define float @test81(i1 %flag) { +; Test that we can speculate the load around the select even though they use +; differently typed pointers. +; CHECK-LABEL: @test81( +; CHECK: %[[X:.*]] = alloca i32 +; CHECK-NEXT: %[[Y:.*]] = alloca i32 +; CHECK: %[[V:.*]] = load i32* %[[X]] +; CHECK-NEXT: store i32 %[[V]], i32* %[[Y]] +; CHECK-NEXT: %[[C:.*]] = bitcast i32 %[[V]] to float +; CHECK-NEXT: ret float %[[C]] +entry: + %x = alloca float + %y = alloca i32 + %x1 = bitcast float* %x to i32* + %y1 = bitcast i32* %y to float* + call void @scribble_on_i32(i32* %x1) + call void @scribble_on_i32(i32* %y) + %tmp = load i32* %x1 + store i32 %tmp, i32* %y + %p = select i1 %flag, float* %x, float* %y1 + %v = load float* %p + ret float %v +} + +define i32 @test82(i1 %flag) { +; Test that we can speculate the load around the select even though they use +; differently typed pointers. +; CHECK-LABEL: @test82( +; CHECK: %[[X:.*]] = alloca float +; CHECK-NEXT: %[[Y:.*]] = alloca i32 +; CHECK-NEXT: %[[X1:.*]] = bitcast float* %[[X]] to i32* +; CHECK-NEXT: %[[Y1:.*]] = bitcast i32* %[[Y]] to float* +; CHECK: %[[V:.*]] = load float* %[[X]] +; CHECK-NEXT: store float %[[V]], float* %[[Y1]] +; CHECK-NEXT: %[[C:.*]] = bitcast float %[[V]] to i32 +; CHECK-NEXT: ret i32 %[[C]] +entry: + %x = alloca float + %y = alloca i32 + %x1 = bitcast float* %x to i32* + %y1 = bitcast i32* %y to float* + call void @scribble_on_i32(i32* %x1) + call void @scribble_on_i32(i32* %y) + %tmp = load float* %x + store float %tmp, float* %y1 + %p = select i1 %flag, i32* %x1, i32* %y + %v = load i32* %p + ret i32 %v +} + +declare void @scribble_on_i64(i64*) +declare void @scribble_on_i128(i128*) + +define i8* @test83(i1 %flag) { +; Test that we can speculate the load around the select even though they use +; differently typed pointers and requires inttoptr casts. +; CHECK-LABEL: @test83( +; CHECK: %[[X:.*]] = alloca i8* +; CHECK-NEXT: %[[Y:.*]] = alloca i8* +; CHECK-DAG: %[[X2:.*]] = bitcast i8** %[[X]] to i64* +; CHECK-DAG: %[[Y2:.*]] = bitcast i8** %[[Y]] to i64* +; CHECK: %[[V:.*]] = load i64* %[[X2]] +; CHECK-NEXT: store i64 %[[V]], i64* %[[Y2]] +; CHECK-NEXT: %[[C:.*]] = inttoptr i64 %[[V]] to i8* +; CHECK-NEXT: ret i8* %[[S]] +entry: + %x = alloca i8* + %y = alloca i64 + %x1 = bitcast i8** %x to i64* + %y1 = bitcast i64* %y to i8** + call void @scribble_on_i64(i64* %x1) + call void @scribble_on_i64(i64* %y) + %tmp = load i64* %x1 + store i64 %tmp, i64* %y + %p = select i1 %flag, i8** %x, i8** %y1 + %v = load i8** %p + ret i8* %v +} + +define i64 @test84(i1 %flag) { +; Test that we can speculate the load around the select even though they use +; differently typed pointers and requires a ptrtoint cast. +; CHECK-LABEL: @test84( +; CHECK: %[[X:.*]] = alloca i8* +; CHECK-NEXT: %[[Y:.*]] = alloca i8* +; CHECK: %[[V:.*]] = load i8** %[[X]] +; CHECK-NEXT: store i8* %[[V]], i8** %[[Y]] +; CHECK-NEXT: %[[C:.*]] = ptrtoint i8* %[[V]] to i64 +; CHECK-NEXT: ret i64 %[[C]] +entry: + %x = alloca i8* + %y = alloca i64 + %x1 = bitcast i8** %x to i64* + %y1 = bitcast i64* %y to i8** + call void @scribble_on_i64(i64* %x1) + call void @scribble_on_i64(i64* %y) + %tmp = load i8** %x + store i8* %tmp, i8** %y1 + %p = select i1 %flag, i64* %x1, i64* %y + %v = load i64* %p + ret i64 %v +} + +define i8* @test85(i1 %flag) { +; Test that we can't speculate the load around the select. The load of the +; pointer doesn't load all of the stored integer bits. We could fix this, but it +; would require endianness checks and other nastiness. +; CHECK-LABEL: @test85( +; CHECK: %[[T:.*]] = load i128* +; CHECK-NEXT: store i128 %[[T]], i128* +; CHECK-NEXT: %[[X:.*]] = load i8** +; CHECK-NEXT: %[[Y:.*]] = load i8** +; CHECK-NEXT: %[[V:.*]] = select i1 %flag, i8* %[[X]], i8* %[[Y]] +; CHECK-NEXT: ret i8* %[[V]] +entry: + %x = alloca [2 x i8*] + %y = alloca i128 + %x1 = bitcast [2 x i8*]* %x to i8** + %x2 = bitcast i8** %x1 to i128* + %y1 = bitcast i128* %y to i8** + call void @scribble_on_i128(i128* %x2) + call void @scribble_on_i128(i128* %y) + %tmp = load i128* %x2 + store i128 %tmp, i128* %y + %p = select i1 %flag, i8** %x1, i8** %y1 + %v = load i8** %p + ret i8* %v +} + +define i128 @test86(i1 %flag) { +; Test that we can't speculate the load around the select when the integer size +; is larger than the pointer size. The store of the pointer doesn't store to all +; the bits of the integer. +; +; CHECK-LABEL: @test86( +; CHECK: %[[T:.*]] = load i8** +; CHECK-NEXT: store i8* %[[T]], i8** +; CHECK-NEXT: %[[X:.*]] = load i128* +; CHECK-NEXT: %[[Y:.*]] = load i128* +; CHECK-NEXT: %[[V:.*]] = select i1 %flag, i128 %[[X]], i128 %[[Y]] +; CHECK-NEXT: ret i128 %[[V]] +entry: + %x = alloca [2 x i8*] + %y = alloca i128 + %x1 = bitcast [2 x i8*]* %x to i8** + %x2 = bitcast i8** %x1 to i128* + %y1 = bitcast i128* %y to i8** + call void @scribble_on_i128(i128* %x2) + call void @scribble_on_i128(i128* %y) + %tmp = load i8** %x1 + store i8* %tmp, i8** %y1 + %p = select i1 %flag, i128* %x2, i128* %y + %v = load i128* %p + ret i128 %v +} |