summaryrefslogtreecommitdiffstats
path: root/test/Transforms/InstSimplify
diff options
context:
space:
mode:
authordim <dim@FreeBSD.org>2013-04-08 18:41:23 +0000
committerdim <dim@FreeBSD.org>2013-04-08 18:41:23 +0000
commit169d2bd06003c39970bc94c99669a34b61bb7e45 (patch)
tree06099edc18d30894081a822b756f117cbe0b8207 /test/Transforms/InstSimplify
parent0ac5f94c68a3d8fbd1380dbba26d891ea7816b5e (diff)
downloadFreeBSD-src-169d2bd06003c39970bc94c99669a34b61bb7e45.zip
FreeBSD-src-169d2bd06003c39970bc94c99669a34b61bb7e45.tar.gz
Vendor import of llvm trunk r178860:
http://llvm.org/svn/llvm-project/llvm/trunk@178860
Diffstat (limited to 'test/Transforms/InstSimplify')
-rw-r--r--test/Transforms/InstSimplify/call-callconv.ll48
-rw-r--r--test/Transforms/InstSimplify/call.ll103
-rw-r--r--test/Transforms/InstSimplify/compare.ll86
-rw-r--r--test/Transforms/InstSimplify/fast-math.ll107
-rw-r--r--test/Transforms/InstSimplify/floating-point-arithmetic.ll35
-rw-r--r--test/Transforms/InstSimplify/past-the-end.ll77
-rw-r--r--test/Transforms/InstSimplify/ptr_diff.ll30
-rw-r--r--test/Transforms/InstSimplify/vector_gep.ll2
8 files changed, 487 insertions, 1 deletions
diff --git a/test/Transforms/InstSimplify/call-callconv.ll b/test/Transforms/InstSimplify/call-callconv.ll
new file mode 100644
index 0000000..e475be7
--- /dev/null
+++ b/test/Transforms/InstSimplify/call-callconv.ll
@@ -0,0 +1,48 @@
+; RUN: opt < %s -instcombine -S | FileCheck %s
+; Verify that the non-default calling conv doesn't prevent the libcall simplification
+
+@.str = private unnamed_addr constant [4 x i8] c"abc\00", align 1
+
+define arm_aapcscc i32 @_abs(i32 %i) nounwind readnone {
+; CHECK: _abs
+ %call = tail call arm_aapcscc i32 @abs(i32 %i) nounwind readnone
+ ret i32 %call
+; CHECK: %[[ISPOS:.*]] = icmp sgt i32 %i, -1
+; CHECK: %[[NEG:.*]] = sub i32 0, %i
+; CHECK: %[[RET:.*]] = select i1 %[[ISPOS]], i32 %i, i32 %[[NEG]]
+; CHECK: ret i32 %[[RET]]
+}
+
+declare arm_aapcscc i32 @abs(i32) nounwind readnone
+
+define arm_aapcscc i32 @_labs(i32 %i) nounwind readnone {
+; CHECK: _labs
+ %call = tail call arm_aapcscc i32 @labs(i32 %i) nounwind readnone
+ ret i32 %call
+; CHECK: %[[ISPOS:.*]] = icmp sgt i32 %i, -1
+; CHECK: %[[NEG:.*]] = sub i32 0, %i
+; CHECK: %[[RET:.*]] = select i1 %[[ISPOS]], i32 %i, i32 %[[NEG]]
+; CHECK: ret i32 %[[RET]]
+}
+
+declare arm_aapcscc i32 @labs(i32) nounwind readnone
+
+define arm_aapcscc i32 @_strlen1() {
+; CHECK: _strlen1
+ %call = tail call arm_aapcscc i32 @strlen(i8* getelementptr inbounds ([4 x i8]* @.str, i32 0, i32 0))
+ ret i32 %call
+; CHECK: ret i32 3
+}
+
+declare arm_aapcscc i32 @strlen(i8*)
+
+define arm_aapcscc zeroext i1 @_strlen2(i8* %str) {
+; CHECK: _strlen2
+ %call = tail call arm_aapcscc i32 @strlen(i8* %str)
+ %cmp = icmp ne i32 %call, 0
+ ret i1 %cmp
+
+; CHECK: %[[STRLENFIRST:.*]] = load i8* %str
+; CHECK: %[[CMP:.*]] = icmp ne i8 %[[STRLENFIRST]], 0
+; CHECK: ret i1 %[[CMP]]
+}
diff --git a/test/Transforms/InstSimplify/call.ll b/test/Transforms/InstSimplify/call.ll
new file mode 100644
index 0000000..cf2f847
--- /dev/null
+++ b/test/Transforms/InstSimplify/call.ll
@@ -0,0 +1,103 @@
+; RUN: opt < %s -instsimplify -S | FileCheck %s
+
+declare {i8, i1} @llvm.uadd.with.overflow.i8(i8 %a, i8 %b)
+
+define i1 @test_uadd1() {
+; CHECK: @test_uadd1
+ %x = call {i8, i1} @llvm.uadd.with.overflow.i8(i8 254, i8 3)
+ %overflow = extractvalue {i8, i1} %x, 1
+ ret i1 %overflow
+; CHECK-NEXT: ret i1 true
+}
+
+define i8 @test_uadd2() {
+; CHECK: @test_uadd2
+ %x = call {i8, i1} @llvm.uadd.with.overflow.i8(i8 254, i8 44)
+ %result = extractvalue {i8, i1} %x, 0
+ ret i8 %result
+; CHECK-NEXT: ret i8 42
+}
+
+declare i256 @llvm.cttz.i256(i256 %src, i1 %is_zero_undef)
+
+define i256 @test_cttz() {
+; CHECK: @test_cttz
+ %x = call i256 @llvm.cttz.i256(i256 10, i1 false)
+ ret i256 %x
+; CHECK-NEXT: ret i256 1
+}
+
+declare i256 @llvm.ctpop.i256(i256 %src)
+
+define i256 @test_ctpop() {
+; CHECK: @test_ctpop
+ %x = call i256 @llvm.ctpop.i256(i256 10)
+ ret i256 %x
+; CHECK-NEXT: ret i256 2
+}
+
+; Test a non-intrinsic that we know about as a library call.
+declare float @fabs(float %x)
+
+define float @test_fabs_libcall() {
+; CHECK: @test_fabs_libcall
+
+ %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.
+; CHECK-NEXT: call float @fabs
+
+ ret float %x
+; CHECK-NEXT: ret float 4.2{{0+}}e+01
+}
+
+
+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
+
+; Test idempotent intrinsics
+define float @test_idempotence(float %a) {
+; CHECK: @test_idempotence
+
+; CHECK: fabs
+; CHECK-NOT: fabs
+ %a0 = call float @llvm.fabs.f32(float %a)
+ %a1 = call float @llvm.fabs.f32(float %a0)
+
+; CHECK: floor
+; CHECK-NOT: floor
+ %b0 = call float @llvm.floor.f32(float %a)
+ %b1 = call float @llvm.floor.f32(float %b0)
+
+; CHECK: ceil
+; CHECK-NOT: ceil
+ %c0 = call float @llvm.ceil.f32(float %a)
+ %c1 = call float @llvm.ceil.f32(float %c0)
+
+; CHECK: trunc
+; CHECK-NOT: trunc
+ %d0 = call float @llvm.trunc.f32(float %a)
+ %d1 = call float @llvm.trunc.f32(float %d0)
+
+; CHECK: rint
+; CHECK-NOT: rint
+ %e0 = call float @llvm.rint.f32(float %a)
+ %e1 = call float @llvm.rint.f32(float %e0)
+
+; CHECK: nearbyint
+; CHECK-NOT: nearbyint
+ %f0 = call float @llvm.nearbyint.f32(float %a)
+ %f1 = call float @llvm.nearbyint.f32(float %f0)
+
+ %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
+
+ ret float %r4
+}
diff --git a/test/Transforms/InstSimplify/compare.ll b/test/Transforms/InstSimplify/compare.ll
index ce2bb79..b764c76 100644
--- a/test/Transforms/InstSimplify/compare.ll
+++ b/test/Transforms/InstSimplify/compare.ll
@@ -165,6 +165,46 @@ entry:
ret i1 %cmp
}
+define i1 @gep13(i8* %ptr) {
+; CHECK: @gep13
+; We can prove this GEP is non-null because it is inbounds.
+ %x = getelementptr inbounds i8* %ptr, i32 1
+ %cmp = icmp eq i8* %x, null
+ ret i1 %cmp
+; CHECK-NEXT: ret i1 false
+}
+
+define i1 @gep14({ {}, i8 }* %ptr) {
+; CHECK: @gep14
+; We can't simplify this because the offset of one in the GEP actually doesn't
+; move the pointer.
+ %x = getelementptr inbounds { {}, 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: @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}]}* %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 @gep16(i8* %ptr, i32 %a) {
+; CHECK: @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* %ptr, i32 %b
+ %cmp = icmp eq i8* %x, null
+ ret i1 %cmp
+; CHECK-NEXT: ret i1 false
+}
+
define i1 @zext(i32 %x) {
; CHECK: @zext
%e1 = zext i32 %x to i64
@@ -607,3 +647,49 @@ unreachableblock:
%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.
+
+@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: @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]]* %strs, i64 0, i64 %a, i64 %b
+ %cmp = icmp eq i8* %x, null
+ ret i1 %cmp
+; CHECK-NEXT: ret i1 false
+}
diff --git a/test/Transforms/InstSimplify/fast-math.ll b/test/Transforms/InstSimplify/fast-math.ll
new file mode 100644
index 0000000..154b967
--- /dev/null
+++ b/test/Transforms/InstSimplify/fast-math.ll
@@ -0,0 +1,107 @@
+; RUN: opt < %s -instsimplify -S | FileCheck %s
+
+;; x * 0 ==> 0 when no-nans and no-signed-zero
+; CHECK: mul_zero_1
+define float @mul_zero_1(float %a) {
+ %b = fmul nsz nnan float %a, 0.0
+; CHECK: ret float 0.0
+ ret float %b
+}
+; CHECK: mul_zero_2
+define float @mul_zero_2(float %a) {
+ %b = fmul fast float 0.0, %a
+; CHECK: ret float 0.0
+ ret float %b
+}
+
+;; x * 0 =/=> 0 when there could be nans or -0
+; CHECK: no_mul_zero_1
+define float @no_mul_zero_1(float %a) {
+ %b = fmul nsz float %a, 0.0
+; CHECK: ret float %b
+ ret float %b
+}
+; CHECK: no_mul_zero_2
+define float @no_mul_zero_2(float %a) {
+ %b = fmul nnan float %a, 0.0
+; CHECK: ret float %b
+ ret float %b
+}
+; CHECK: no_mul_zero_3
+define float @no_mul_zero_3(float %a) {
+ %b = fmul float %a, 0.0
+; CHECK: ret float %b
+ ret float %b
+}
+
+; fadd [nnan ninf] X, (fsub [nnan ninf] 0, X) ==> 0
+; where nnan and ninf have to occur at least once somewhere in this
+; expression
+; CHECK: fadd_fsub_0
+define float @fadd_fsub_0(float %a) {
+; X + -X ==> 0
+ %t1 = fsub nnan ninf float 0.0, %a
+ %zero1 = fadd nnan ninf float %t1, %a
+
+ %t2 = fsub nnan float 0.0, %a
+ %zero2 = fadd ninf float %t2, %a
+
+ %t3 = fsub nnan ninf float 0.0, %a
+ %zero3 = fadd float %t3, %a
+
+ %t4 = fsub float 0.0, %a
+ %zero4 = fadd nnan ninf float %t4, %a
+
+; Dont fold this
+; CHECK: %nofold = fsub float 0.0
+ %nofold = fsub float 0.0, %a
+; CHECK: %no_zero = fadd nnan float %nofold, %a
+ %no_zero = fadd nnan float %nofold, %a
+
+; Coalesce the folded zeros
+ %zero5 = fadd float %zero1, %zero2
+ %zero6 = fadd float %zero3, %zero4
+ %zero7 = fadd float %zero5, %zero6
+
+; Should get folded
+ %ret = fadd nsz float %no_zero, %zero7
+
+; CHECK: ret float %no_zero
+ ret float %ret
+}
+
+; fsub nnan ninf x, x ==> 0.0
+; CHECK: @fsub_x_x
+define float @fsub_x_x(float %a) {
+; X - X ==> 0
+ %zero1 = fsub nnan ninf float %a, %a
+
+; Dont fold
+; CHECK: %no_zero1 = fsub
+ %no_zero1 = fsub ninf float %a, %a
+; CHECK: %no_zero2 = fsub
+ %no_zero2 = fsub nnan float %a, %a
+; CHECK: %no_zero = fadd
+ %no_zero = fadd float %no_zero1, %no_zero2
+
+; Should get folded
+ %ret = fadd nsz float %no_zero, %zero1
+
+; CHECK: ret float %no_zero
+ ret float %ret
+}
+
+; fadd nsz X, 0 ==> X
+; CHECK: @nofold_fadd_x_0
+define float @nofold_fadd_x_0(float %a) {
+; Dont fold
+; CHECK: %no_zero1 = fadd
+ %no_zero1 = fadd ninf float %a, 0.0
+; CHECK: %no_zero2 = fadd
+ %no_zero2 = fadd nnan float %a, 0.0
+; CHECK: %no_zero = fadd
+ %no_zero = fadd float %no_zero1, %no_zero2
+
+; CHECK: ret float %no_zero
+ ret float %no_zero
+}
diff --git a/test/Transforms/InstSimplify/floating-point-arithmetic.ll b/test/Transforms/InstSimplify/floating-point-arithmetic.ll
new file mode 100644
index 0000000..f9c364c
--- /dev/null
+++ b/test/Transforms/InstSimplify/floating-point-arithmetic.ll
@@ -0,0 +1,35 @@
+; RUN: opt < %s -instsimplify -S | FileCheck %s
+
+; fsub 0, (fsub 0, X) ==> X
+; CHECK: @fsub_0_0_x
+define float @fsub_0_0_x(float %a) {
+ %t1 = fsub float -0.0, %a
+ %ret = fsub float -0.0, %t1
+
+; CHECK: ret float %a
+ ret float %ret
+}
+
+; fsub X, 0 ==> X
+; CHECK: @fsub_x_0
+define float @fsub_x_0(float %a) {
+ %ret = fsub float %a, 0.0
+; CHECK ret float %a
+ ret float %ret
+}
+
+; fadd X, -0 ==> X
+; CHECK: @fadd_x_n0
+define float @fadd_x_n0(float %a) {
+ %ret = fadd float %a, -0.0
+; CHECK ret float %a
+ ret float %ret
+}
+
+; fmul X, 1.0 ==> X
+; CHECK: @fmul_X_1
+define double @fmul_X_1(double %a) {
+ %b = fmul double 1.000000e+00, %a ; <double> [#uses=1]
+ ; CHECK: ret double %a
+ ret double %b
+}
diff --git a/test/Transforms/InstSimplify/past-the-end.ll b/test/Transforms/InstSimplify/past-the-end.ll
new file mode 100644
index 0000000..075da4a
--- /dev/null
+++ b/test/Transforms/InstSimplify/past-the-end.ll
@@ -0,0 +1,77 @@
+; RUN: opt < %s -instsimplify -S | FileCheck %s
+target datalayout = "p:32:32"
+
+; Check some past-the-end subtleties.
+
+@opte_a = global i32 0
+@opte_b = global i32 0
+
+; Comparing base addresses of two distinct globals. Never equal.
+
+define zeroext i1 @no_offsets() {
+ %t = icmp eq i32* @opte_a, @opte_b
+ ret i1 %t
+ ; CHECK: no_offsets(
+ ; CHECK: ret i1 false
+}
+
+; Comparing past-the-end addresses of two distinct globals. Never equal.
+
+define zeroext i1 @both_past_the_end() {
+ %x = getelementptr i32* @opte_a, i32 1
+ %y = getelementptr i32* @opte_b, i32 1
+ %t = icmp eq i32* %x, %y
+ ret i1 %t
+ ; CHECK: both_past_the_end(
+ ; CHECK-NOT: ret i1 true
+ ; TODO: refine this
+}
+
+; Comparing past-the-end addresses of one global to the base address
+; of another. Can't fold this.
+
+define zeroext i1 @just_one_past_the_end() {
+ %x = getelementptr i32* @opte_a, i32 1
+ %t = icmp eq i32* %x, @opte_b
+ ret i1 %t
+ ; CHECK: just_one_past_the_end(
+ ; CHECK: ret i1 icmp eq (i32* getelementptr inbounds (i32* @opte_a, i32 1), i32* @opte_b)
+}
+
+; Comparing base addresses of two distinct allocas. Never equal.
+
+define zeroext i1 @no_alloca_offsets() {
+ %m = alloca i32
+ %n = alloca i32
+ %t = icmp eq i32* %m, %n
+ ret i1 %t
+ ; CHECK: no_alloca_offsets(
+ ; CHECK: ret i1 false
+}
+
+; Comparing past-the-end addresses of two distinct allocas. Never equal.
+
+define zeroext i1 @both_past_the_end_alloca() {
+ %m = alloca i32
+ %n = alloca i32
+ %x = getelementptr i32* %m, i32 1
+ %y = getelementptr i32* %n, i32 1
+ %t = icmp eq i32* %x, %y
+ ret i1 %t
+ ; CHECK: both_past_the_end_alloca(
+ ; CHECK-NOT: ret i1 true
+ ; TODO: refine this
+}
+
+; Comparing past-the-end addresses of one alloca to the base address
+; of another. Can't fold this.
+
+define zeroext i1 @just_one_past_the_end_alloca() {
+ %m = alloca i32
+ %n = alloca i32
+ %x = getelementptr i32* %m, i32 1
+ %t = icmp eq i32* %x, %n
+ ret i1 %t
+ ; CHECK: just_one_past_the_end_alloca(
+ ; CHECK: ret i1 %t
+}
diff --git a/test/Transforms/InstSimplify/ptr_diff.ll b/test/Transforms/InstSimplify/ptr_diff.ll
index 1eb1fd4..8b4aa79 100644
--- a/test/Transforms/InstSimplify/ptr_diff.ll
+++ b/test/Transforms/InstSimplify/ptr_diff.ll
@@ -46,3 +46,33 @@ define i64 @ptrdiff3(i8* %ptr) {
%diff = sub i64 %last.int, %first.int
ret i64 %diff
}
+
+define <4 x i32> @ptrdiff4(<4 x i8*> %arg) nounwind {
+; Handle simple cases of vectors of pointers.
+; CHECK: @ptrdiff4
+; CHECK: ret <4 x i32> zeroinitializer
+ %p1 = ptrtoint <4 x i8*> %arg to <4 x i32>
+ %bc = bitcast <4 x i8*> %arg to <4 x i32*>
+ %p2 = ptrtoint <4 x i32*> %bc to <4 x i32>
+ %sub = sub <4 x i32> %p1, %p2
+ ret <4 x i32> %sub
+}
+
+%struct.ham = type { i32, [2 x [2 x i32]] }
+
+@global = internal global %struct.ham zeroinitializer, align 4
+
+define i32 @ptrdiff5() nounwind {
+bb:
+ %tmp = getelementptr inbounds %struct.ham* @global, i32 0, i32 1
+ %tmp1 = getelementptr inbounds [2 x [2 x i32]]* %tmp, i32 0, i32 0
+ %tmp2 = bitcast [2 x i32]* %tmp1 to i32*
+ %tmp3 = ptrtoint i32* %tmp2 to i32
+ %tmp4 = getelementptr inbounds %struct.ham* @global, i32 0, i32 1
+ %tmp5 = getelementptr inbounds [2 x [2 x i32]]* %tmp4, i32 0, i32 0
+ %tmp6 = ptrtoint [2 x i32]* %tmp5 to i32
+ %tmp7 = sub i32 %tmp3, %tmp6
+ ret i32 %tmp7
+; CHECK: @ptrdiff5
+; CHECK: ret i32 0
+}
diff --git a/test/Transforms/InstSimplify/vector_gep.ll b/test/Transforms/InstSimplify/vector_gep.ll
index f65260e..5ac1dde 100644
--- a/test/Transforms/InstSimplify/vector_gep.ll
+++ b/test/Transforms/InstSimplify/vector_gep.ll
@@ -1,4 +1,4 @@
-;RUN: opt -instsimplify %s -disable-output
+;RUN: opt -instsimplify -disable-output < %s
declare void @helper(<2 x i8*>)
define void @test(<2 x i8*> %a) {
%A = getelementptr <2 x i8*> %a, <2 x i32> <i32 0, i32 0>
OpenPOWER on IntegriCloud