diff options
author | Manoj Gupta <manojgupta@google.com> | 2018-07-09 22:27:23 +0000 |
---|---|---|
committer | Manoj Gupta <manojgupta@google.com> | 2018-07-09 22:27:23 +0000 |
commit | 77eeac3d9e9418ac0aea131d20ac84b656977814 (patch) | |
tree | 0ca98362b1ae59875a26b0df269bf09a1854d982 /llvm/test/Transforms/GlobalOpt | |
parent | 0230f7c763c5b5f988f629506f0ce050fbacaed4 (diff) | |
download | bcm5719-llvm-77eeac3d9e9418ac0aea131d20ac84b656977814.tar.gz bcm5719-llvm-77eeac3d9e9418ac0aea131d20ac84b656977814.zip |
llvm: Add support for "-fno-delete-null-pointer-checks"
Summary:
Support for this option is needed for building Linux kernel.
This is a very frequently requested feature by kernel developers.
More details : https://lkml.org/lkml/2018/4/4/601
GCC option description for -fdelete-null-pointer-checks:
This Assume that programs cannot safely dereference null pointers,
and that no code or data element resides at address zero.
-fno-delete-null-pointer-checks is the inverse of this implying that
null pointer dereferencing is not undefined.
This feature is implemented in LLVM IR in this CL as the function attribute
"null-pointer-is-valid"="true" in IR (Under review at D47894).
The CL updates several passes that assumed null pointer dereferencing is
undefined to not optimize when the "null-pointer-is-valid"="true"
attribute is present.
Reviewers: t.p.northover, efriedma, jyknight, chandlerc, rnk, srhines, void, george.burgess.iv
Reviewed By: efriedma, george.burgess.iv
Subscribers: eraman, haicheng, george.burgess.iv, drinkcat, theraven, reames, sanjoy, xbolva00, llvm-commits
Differential Revision: https://reviews.llvm.org/D47895
llvm-svn: 336613
Diffstat (limited to 'llvm/test/Transforms/GlobalOpt')
18 files changed, 456 insertions, 1 deletions
diff --git a/llvm/test/Transforms/GlobalOpt/MallocSROA-section-no-null-opt.ll b/llvm/test/Transforms/GlobalOpt/MallocSROA-section-no-null-opt.ll new file mode 100644 index 00000000000..c9b3f6fc1cd --- /dev/null +++ b/llvm/test/Transforms/GlobalOpt/MallocSROA-section-no-null-opt.ll @@ -0,0 +1,34 @@ +; RUN: opt -globalopt -S < %s | FileCheck %s +; CHECK: @Y +; CHECK: section ".foo" + +%struct.xyz = type { double, i32 } + +@Y = internal global %struct.xyz* null ,section ".foo" ; <%struct.xyz**> [#uses=2] +@numf2s = external global i32 ; <i32*> [#uses=1] + +define void @init_net() #0 { +; CHECK-LABEL: init_net( +; CHECK: load i32, i32* @numf2s +; CHECK: call i8* @malloc +; CHECK: store %struct.xyz* {{.*}}, %struct.xyz** @Y +entry: + %0 = load i32, i32* @numf2s, align 4 ; <i32> [#uses=1] + %mallocsize2 = shl i32 %0, 4 ; <i32> [#uses=1] + %malloccall3 = tail call i8* @malloc(i32 %mallocsize2) ; <i8*> [#uses=1] + %1 = bitcast i8* %malloccall3 to %struct.xyz* ; <%struct.xyz*> [#uses=1] + store %struct.xyz* %1, %struct.xyz** @Y, align 8 + ret void +} + +define %struct.xyz* @load_train() #0 { +; CHECK-LABEL: load_train( +; CHECK: load %struct.xyz*, %struct.xyz** @Y +entry: + %0 = load %struct.xyz*, %struct.xyz** @Y, align 8 ; <%struct.xyz*> [#uses=0] + ret %struct.xyz* %0 +} + +declare noalias i8* @malloc(i32) + +attributes #0 = { "null-pointer-is-valid"="true" } diff --git a/llvm/test/Transforms/GlobalOpt/heap-sra-1-no-null-opt.ll b/llvm/test/Transforms/GlobalOpt/heap-sra-1-no-null-opt.ll new file mode 100644 index 00000000000..c826e7f7a04 --- /dev/null +++ b/llvm/test/Transforms/GlobalOpt/heap-sra-1-no-null-opt.ll @@ -0,0 +1,40 @@ +; RUN: opt < %s -globalopt -S | FileCheck %s +target datalayout = "E-p:64:64:64-a0:0:8-f32:32:32-f64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-v64:64:64-v128:128:128" + +%struct.foo = type { i32, i32 } +@X = internal global %struct.foo* null +; CHECK: @X +; CHECK-NOT: @X.f0 + +define void @bar(i64 %Size) nounwind noinline #0 { +entry: + %mallocsize = mul i64 %Size, 8 ; <i64> [#uses=1] + %malloccall = tail call i8* @malloc(i64 %mallocsize) ; <i8*> [#uses=1] + %.sub = bitcast i8* %malloccall to %struct.foo* ; <%struct.foo*> [#uses=1] + store %struct.foo* %.sub, %struct.foo** @X, align 4 + ret void +} + +declare noalias i8* @malloc(i64) + +define i32 @baz() nounwind readonly noinline #0 { +bb1.thread: + %0 = load %struct.foo*, %struct.foo** @X, align 4 + br label %bb1 + +bb1: ; preds = %bb1, %bb1.thread + %i.0.reg2mem.0 = phi i32 [ 0, %bb1.thread ], [ %indvar.next, %bb1 ] + %sum.0.reg2mem.0 = phi i32 [ 0, %bb1.thread ], [ %3, %bb1 ] + %1 = getelementptr %struct.foo, %struct.foo* %0, i32 %i.0.reg2mem.0, i32 0 + %2 = load i32, i32* %1, align 4 + %3 = add i32 %2, %sum.0.reg2mem.0 + %indvar.next = add i32 %i.0.reg2mem.0, 1 + %exitcond = icmp eq i32 %indvar.next, 1200 + br i1 %exitcond, label %bb2, label %bb1 + +bb2: ; preds = %bb1 + ret i32 %3 +} + +attributes #0 = { "null-pointer-is-valid"="true" } + diff --git a/llvm/test/Transforms/GlobalOpt/heap-sra-1.ll b/llvm/test/Transforms/GlobalOpt/heap-sra-1.ll index 6035eaaefcc..28a20ada03f 100644 --- a/llvm/test/Transforms/GlobalOpt/heap-sra-1.ll +++ b/llvm/test/Transforms/GlobalOpt/heap-sra-1.ll @@ -36,3 +36,10 @@ bb2: ; preds = %bb1 ret i32 %3 } +define void @bam(i64 %Size) nounwind noinline #0 { +entry: + %0 = load %struct.foo*, %struct.foo** @X, align 4 + ret void +} + +attributes #0 = { "null-pointer-is-valid"="true" } diff --git a/llvm/test/Transforms/GlobalOpt/heap-sra-2-no-null-opt.ll b/llvm/test/Transforms/GlobalOpt/heap-sra-2-no-null-opt.ll new file mode 100644 index 00000000000..c33bcba9921 --- /dev/null +++ b/llvm/test/Transforms/GlobalOpt/heap-sra-2-no-null-opt.ll @@ -0,0 +1,39 @@ +; RUN: opt < %s -globalopt -S | FileCheck %s +target datalayout = "E-p:64:64:64-a0:0:8-f32:32:32-f64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-v64:64:64-v128:128:128" + +%struct.foo = type { i32, i32 } +@X = internal global %struct.foo* null ; <%struct.foo**> [#uses=2] +; CHECK: @X +; CHECK-NOT: @X.f0 + +define void @bar(i32 %Size) nounwind noinline #0 { +entry: + %malloccall = tail call i8* @malloc(i64 8000000) ; <i8*> [#uses=1] + %0 = bitcast i8* %malloccall to [1000000 x %struct.foo]* ; <[1000000 x %struct.foo]*> [#uses=1] + %.sub = getelementptr [1000000 x %struct.foo], [1000000 x %struct.foo]* %0, i32 0, i32 0 ; <%struct.foo*> [#uses=1] + store %struct.foo* %.sub, %struct.foo** @X, align 4 + ret void +} + +declare noalias i8* @malloc(i64) + +define i32 @baz() nounwind readonly noinline #0 { +bb1.thread: + %0 = load %struct.foo*, %struct.foo** @X, align 4 ; <%struct.foo*> [#uses=1] + br label %bb1 + +bb1: ; preds = %bb1, %bb1.thread + %i.0.reg2mem.0 = phi i32 [ 0, %bb1.thread ], [ %indvar.next, %bb1 ] ; <i32> [#uses=2] + %sum.0.reg2mem.0 = phi i32 [ 0, %bb1.thread ], [ %3, %bb1 ] ; <i32> [#uses=1] + %1 = getelementptr %struct.foo, %struct.foo* %0, i32 %i.0.reg2mem.0, i32 0 ; <i32*> [#uses=1] + %2 = load i32, i32* %1, align 4 ; <i32> [#uses=1] + %3 = add i32 %2, %sum.0.reg2mem.0 ; <i32> [#uses=2] + %indvar.next = add i32 %i.0.reg2mem.0, 1 ; <i32> [#uses=2] + %exitcond = icmp eq i32 %indvar.next, 1200 ; <i1> [#uses=1] + br i1 %exitcond, label %bb2, label %bb1 + +bb2: ; preds = %bb1 + ret i32 %3 +} + +attributes #0 = { "null-pointer-is-valid"="true" } diff --git a/llvm/test/Transforms/GlobalOpt/heap-sra-2.ll b/llvm/test/Transforms/GlobalOpt/heap-sra-2.ll index d66c627b184..ec05b22b33b 100644 --- a/llvm/test/Transforms/GlobalOpt/heap-sra-2.ll +++ b/llvm/test/Transforms/GlobalOpt/heap-sra-2.ll @@ -36,3 +36,10 @@ bb2: ; preds = %bb1 ret i32 %3 } +define void @bam(i64 %Size) nounwind noinline #0 { +entry: + %0 = load %struct.foo*, %struct.foo** @X, align 4 + ret void +} + +attributes #0 = { "null-pointer-is-valid"="true" } diff --git a/llvm/test/Transforms/GlobalOpt/heap-sra-3-no-null-opt.ll b/llvm/test/Transforms/GlobalOpt/heap-sra-3-no-null-opt.ll new file mode 100644 index 00000000000..ba3b0a418a1 --- /dev/null +++ b/llvm/test/Transforms/GlobalOpt/heap-sra-3-no-null-opt.ll @@ -0,0 +1,41 @@ +; RUN: opt < %s -globalopt -S | FileCheck %s +target datalayout = "E-p:64:64:64-a0:0:8-f32:32:32-f64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-v64:64:64-v128:128:128" + +%struct.foo = type { i32, i32 } +@X = internal global %struct.foo* null +; CHECK: @X +; CHECK-NOT: @X.f0 + +define void @bar(i64 %Size) nounwind noinline #0 { +entry: + %mallocsize = mul i64 8, %Size ; <i64> [#uses=1] +; CHECK: mul i64 8, %Size + %malloccall = tail call i8* @malloc(i64 %mallocsize) ; <i8*> [#uses=1] + %.sub = bitcast i8* %malloccall to %struct.foo* ; <%struct.foo*> [#uses=1] + store %struct.foo* %.sub, %struct.foo** @X, align 4 + ret void +} + +declare noalias i8* @malloc(i64) + +define i32 @baz() nounwind readonly noinline #0 { +bb1.thread: +; CHECK: load %struct.foo*, %struct.foo** @X, align 4 + %0 = load %struct.foo*, %struct.foo** @X, align 4 + br label %bb1 + +bb1: ; preds = %bb1, %bb1.thread + %i.0.reg2mem.0 = phi i32 [ 0, %bb1.thread ], [ %indvar.next, %bb1 ] + %sum.0.reg2mem.0 = phi i32 [ 0, %bb1.thread ], [ %3, %bb1 ] + %1 = getelementptr %struct.foo, %struct.foo* %0, i32 %i.0.reg2mem.0, i32 0 + %2 = load i32, i32* %1, align 4 + %3 = add i32 %2, %sum.0.reg2mem.0 + %indvar.next = add i32 %i.0.reg2mem.0, 1 + %exitcond = icmp eq i32 %indvar.next, 1200 + br i1 %exitcond, label %bb2, label %bb1 + +bb2: ; preds = %bb1 + ret i32 %3 +} + +attributes #0 = { "null-pointer-is-valid"="true" } diff --git a/llvm/test/Transforms/GlobalOpt/heap-sra-3.ll b/llvm/test/Transforms/GlobalOpt/heap-sra-3.ll index 6a34364b49f..67058c8aba2 100644 --- a/llvm/test/Transforms/GlobalOpt/heap-sra-3.ll +++ b/llvm/test/Transforms/GlobalOpt/heap-sra-3.ll @@ -37,3 +37,10 @@ bb2: ; preds = %bb1 ret i32 %3 } +define void @bam(i64 %Size) nounwind noinline #0 { +entry: + %0 = load %struct.foo*, %struct.foo** @X, align 4 + ret void +} + +attributes #0 = { "null-pointer-is-valid"="true" } diff --git a/llvm/test/Transforms/GlobalOpt/heap-sra-4-no-null-opt.ll b/llvm/test/Transforms/GlobalOpt/heap-sra-4-no-null-opt.ll new file mode 100644 index 00000000000..607c93d1e8a --- /dev/null +++ b/llvm/test/Transforms/GlobalOpt/heap-sra-4-no-null-opt.ll @@ -0,0 +1,44 @@ +; RUN: opt < %s -globalopt -S | FileCheck %s +target datalayout = "E-p:64:64:64-a0:0:8-f32:32:32-f64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-v64:64:64-v128:128:128" + +%struct.foo = type { i32, i32 } + +@X = internal global %struct.foo* null +; CHECK: @X +; CHECK-NOT: @X.f0 + +define void @bar(i64 %Size) nounwind noinline #0 { +entry: + %mallocsize = shl i64 %Size, 3 ; <i64> [#uses=1] + %malloccall = tail call i8* @malloc(i64 %mallocsize) ; <i8*> [#uses=1] +; CHECK: shl i64 %Size, 3 + %.sub = bitcast i8* %malloccall to %struct.foo* ; <%struct.foo*> [#uses=1] + store %struct.foo* %.sub, %struct.foo** @X, align 4 + ret void +} + +declare noalias i8* @malloc(i64) + +define i32 @baz() nounwind readonly noinline #0 { +; CHECK-LABEL: @baz( +bb1.thread: +; CHECK: load %struct.foo*, %struct.foo** @X, align 4 + %0 = load %struct.foo*, %struct.foo** @X, align 4 + br label %bb1 + +bb1: ; preds = %bb1, %bb1.thread + %i.0.reg2mem.0 = phi i32 [ 0, %bb1.thread ], [ %indvar.next, %bb1 ] + %sum.0.reg2mem.0 = phi i32 [ 0, %bb1.thread ], [ %3, %bb1 ] + %1 = getelementptr %struct.foo, %struct.foo* %0, i32 %i.0.reg2mem.0, i32 0 + %2 = load i32, i32* %1, align 4 +; CHECK: load i32, i32* %1, align 4 + %3 = add i32 %2, %sum.0.reg2mem.0 + %indvar.next = add i32 %i.0.reg2mem.0, 1 + %exitcond = icmp eq i32 %indvar.next, 1200 + br i1 %exitcond, label %bb2, label %bb1 + +bb2: ; preds = %bb1 + ret i32 %3 +} + +attributes #0 = { "null-pointer-is-valid"="true" } diff --git a/llvm/test/Transforms/GlobalOpt/heap-sra-4.ll b/llvm/test/Transforms/GlobalOpt/heap-sra-4.ll index 2176b9fcbee..71832f34923 100644 --- a/llvm/test/Transforms/GlobalOpt/heap-sra-4.ll +++ b/llvm/test/Transforms/GlobalOpt/heap-sra-4.ll @@ -37,3 +37,11 @@ bb2: ; preds = %bb1 ret i32 %3 } +define void @bam(i64 %Size) nounwind noinline #0 { +entry: + %0 = load %struct.foo*, %struct.foo** @X, align 4 + ret void +} + +attributes #0 = { "null-pointer-is-valid"="true" } + diff --git a/llvm/test/Transforms/GlobalOpt/heap-sra-phi-no-null-opt.ll b/llvm/test/Transforms/GlobalOpt/heap-sra-phi-no-null-opt.ll new file mode 100644 index 00000000000..06c74e5bfc4 --- /dev/null +++ b/llvm/test/Transforms/GlobalOpt/heap-sra-phi-no-null-opt.ll @@ -0,0 +1,54 @@ +; RUN: opt < %s -globalopt -S | FileCheck %s +target datalayout = "E-p:64:64:64-a0:0:8-f32:32:32-f64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-v64:64:64-v128:128:128" + +%struct.foo = type { i32, i32 } + +@X = internal global %struct.foo* null ; <%struct.foo**> [#uses=2] +; CHECK: @X +; CHECK-NOT: @X.f0 + +define void @bar(i32 %Size) nounwind noinline #0 { +; CHECK-LABEL: @bar( +entry: + %malloccall = tail call i8* @malloc(i64 8000000) ; <i8*> [#uses=1] + %tmp = bitcast i8* %malloccall to [1000000 x %struct.foo]* ; <[1000000 x %struct.foo]*> [#uses=1] + %.sub = getelementptr [1000000 x %struct.foo], [1000000 x %struct.foo]* %tmp, i32 0, i32 0 ; <%struct.foo*> [#uses=1] + store %struct.foo* %.sub, %struct.foo** @X, align 4 + ret void +} + +declare noalias i8* @malloc(i64) + +define i32 @baz() nounwind readonly noinline #0 { +; CHECK-LABEL: @baz( +bb1.thread: + %tmpLD1 = load %struct.foo*, %struct.foo** @X, align 4 ; <%struct.foo*> [#uses=1] +; CHECK: load %struct.foo*, %struct.foo** @X, align 4 + br label %bb1 + +bb1: ; preds = %bb1, %bb1.thread + %tmp = phi %struct.foo* [%tmpLD1, %bb1.thread ], [ %tmpLD2, %bb1 ] ; <i32> [#uses=2] +; CHECK: %tmp = phi %struct.foo* [ %tmpLD1, %bb1.thread ], [ %tmpLD2, %bb1 ] + %i.0.reg2mem.0 = phi i32 [ 0, %bb1.thread ], [ %indvar.next, %bb1 ] ; <i32> [#uses=2] + %sum.0.reg2mem.0 = phi i32 [ 0, %bb1.thread ], [ %tmp3, %bb1 ] ; <i32> [#uses=1] + %tmp1 = getelementptr %struct.foo, %struct.foo* %tmp, i32 %i.0.reg2mem.0, i32 0 ; <i32*> [#uses=1] + %tmp2 = load i32, i32* %tmp1, align 4 ; <i32> [#uses=1] +; CHECK: load i32, i32* %tmp1, align 4 + %tmp6 = add i32 %tmp2, %sum.0.reg2mem.0 ; <i32> [#uses=2] + %tmp4 = getelementptr %struct.foo, %struct.foo* %tmp, i32 %i.0.reg2mem.0, i32 1 ; <i32*> [#uses=1] + %tmp5 = load i32 , i32 * %tmp4 +; CHECK: load i32, i32* %tmp4 + %tmp3 = add i32 %tmp5, %tmp6 + %indvar.next = add i32 %i.0.reg2mem.0, 1 ; <i32> [#uses=2] + + %tmpLD2 = load %struct.foo*, %struct.foo** @X, align 4 ; <%struct.foo*> [#uses=1] +; CHECK: load %struct.foo*, %struct.foo** @X, align 4 + + %exitcond = icmp eq i32 %indvar.next, 1200 ; <i1> [#uses=1] + br i1 %exitcond, label %bb2, label %bb1 + +bb2: ; preds = %bb1 + ret i32 %tmp3 +} + +attributes #0 = { "null-pointer-is-valid"="true" } diff --git a/llvm/test/Transforms/GlobalOpt/heap-sra-phi.ll b/llvm/test/Transforms/GlobalOpt/heap-sra-phi.ll index 995f9dc142c..770220dd07b 100644 --- a/llvm/test/Transforms/GlobalOpt/heap-sra-phi.ll +++ b/llvm/test/Transforms/GlobalOpt/heap-sra-phi.ll @@ -42,3 +42,11 @@ bb1: ; preds = %bb1, %bb1.thread bb2: ; preds = %bb1 ret i32 %tmp3 } + +define void @bam(i64 %Size) nounwind noinline #0 { +entry: + %0 = load %struct.foo*, %struct.foo** @X, align 4 + ret void +} + +attributes #0 = { "null-pointer-is-valid"="true" } diff --git a/llvm/test/Transforms/GlobalOpt/load-store-global-no-null-opt.ll b/llvm/test/Transforms/GlobalOpt/load-store-global-no-null-opt.ll new file mode 100644 index 00000000000..d319d162ff4 --- /dev/null +++ b/llvm/test/Transforms/GlobalOpt/load-store-global-no-null-opt.ll @@ -0,0 +1,28 @@ +; RUN: opt < %s -globalopt -S | FileCheck %s + +@a = internal global i64* null, align 8 +; CHECK: @a + +; PR13968 +define void @qux_no_null_opt() nounwind #0 { +; CHECK-LABEL: @qux_no_null_opt( +; CHECK: getelementptr i64*, i64** @a, i32 1 +; CHECK: store i64* inttoptr (i64 1 to i64*), i64** @a + %b = bitcast i64** @a to i8* + %g = getelementptr i64*, i64** @a, i32 1 + %cmp = icmp ne i8* null, %b + %cmp2 = icmp eq i8* null, %b + %cmp3 = icmp eq i64** null, %g + store i64* inttoptr (i64 1 to i64*), i64** @a, align 8 + %l = load i64*, i64** @a, align 8 + ret void +} + +define i64* @bar() { + %X = load i64*, i64** @a, align 8 + ret i64* %X +; CHECK-LABEL: @bar( +; CHECK: load +} + +attributes #0 = { "null-pointer-is-valid"="true" } diff --git a/llvm/test/Transforms/GlobalOpt/malloc-promote-1-no-null-opt.ll b/llvm/test/Transforms/GlobalOpt/malloc-promote-1-no-null-opt.ll new file mode 100644 index 00000000000..fc6dab31640 --- /dev/null +++ b/llvm/test/Transforms/GlobalOpt/malloc-promote-1-no-null-opt.ll @@ -0,0 +1,31 @@ +; RUN: opt < %s -globalopt -S | FileCheck %s +target datalayout = "E-p:64:64:64-a0:0:8-f32:32:32-f64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-v64:64:64-v128:128:128" + +@G = internal global i32* null ; <i32**> [#uses=3] +; CHECK: global + +define void @init() #0 { +; CHECK-LABEL: @init( +; CHECK: store +; CHECK: load + %malloccall = tail call i8* @malloc(i64 4) ; <i8*> [#uses=1] + %P = bitcast i8* %malloccall to i32* ; <i32*> [#uses=1] + store i32* %P, i32** @G + %GV = load i32*, i32** @G ; <i32*> [#uses=1] + store i32 0, i32* %GV + ret void +} + +declare noalias i8* @malloc(i64) + +define i32 @get() #0 { +; CHECK-LABEL: @get( +; CHECK: load i32*, i32** @G +; CHECK-NEXT: load i32, i32* %GV + %GV = load i32*, i32** @G ; <i32*> [#uses=1] + %V = load i32, i32* %GV ; <i32> [#uses=1] + ret i32 %V +; CHECK: ret i32 %V +} + +attributes #0 = { "null-pointer-is-valid"="true" } diff --git a/llvm/test/Transforms/GlobalOpt/malloc-promote-1.ll b/llvm/test/Transforms/GlobalOpt/malloc-promote-1.ll index d5087dea344..a8f127474e3 100644 --- a/llvm/test/Transforms/GlobalOpt/malloc-promote-1.ll +++ b/llvm/test/Transforms/GlobalOpt/malloc-promote-1.ll @@ -1,7 +1,7 @@ ; RUN: opt < %s -globalopt -S | FileCheck %s target datalayout = "E-p:64:64:64-a0:0:8-f32:32:32-f64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-v64:64:64-v128:128:128" -@G = internal global i32* null ; <i32**> [#uses=3] +@G = internal global i32* null ; <i32**> [#uses=4] ; CHECK-NOT: global define void @init() { @@ -22,3 +22,11 @@ define i32 @get() { ; CHECK: ret i32 0 } +define void @foo(i64 %Size) nounwind noinline #0 { +entry: + %0 = load i32*, i32** @G, align 4 + ret void +} + +attributes #0 = { "null-pointer-is-valid"="true" } + diff --git a/llvm/test/Transforms/GlobalOpt/malloc-promote-2-no-null-opt.ll b/llvm/test/Transforms/GlobalOpt/malloc-promote-2-no-null-opt.ll new file mode 100644 index 00000000000..009a33435fd --- /dev/null +++ b/llvm/test/Transforms/GlobalOpt/malloc-promote-2-no-null-opt.ll @@ -0,0 +1,24 @@ +; RUN: opt < %s -globalopt -S | FileCheck %s +target datalayout = "E-p:64:64:64-a0:0:8-f32:32:32-f64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-v64:64:64-v128:128:128" + +@G = internal global i32* null + +define void @t() #0 { +; CHECK: @t() +; CHECK: call i8* @malloc +; CHECK: bitcast +; CHECK: store +; CHECK: load +; CHECK: getelementptr +; CHECK: store + %malloccall = tail call i8* @malloc(i64 mul (i64 100, i64 4)) + %P = bitcast i8* %malloccall to i32* + store i32* %P, i32** @G + %GV = load i32*, i32** @G + %GVe = getelementptr i32, i32* %GV, i32 40 + store i32 20, i32* %GVe + ret void +} + +declare noalias i8* @malloc(i64) +attributes #0 = { "null-pointer-is-valid"="true" } diff --git a/llvm/test/Transforms/GlobalOpt/malloc-promote-2.ll b/llvm/test/Transforms/GlobalOpt/malloc-promote-2.ll index 335ed82a8cf..64f379365c7 100644 --- a/llvm/test/Transforms/GlobalOpt/malloc-promote-2.ll +++ b/llvm/test/Transforms/GlobalOpt/malloc-promote-2.ll @@ -17,3 +17,11 @@ define void @t() { } declare noalias i8* @malloc(i64) + +define void @foo(i64 %Size) nounwind noinline #0 { +entry: + %0 = load i32*, i32** @G, align 4 + ret void +} + +attributes #0 = { "null-pointer-is-valid"="true" } diff --git a/llvm/test/Transforms/GlobalOpt/storepointer-compare-no-null-opt.ll b/llvm/test/Transforms/GlobalOpt/storepointer-compare-no-null-opt.ll new file mode 100644 index 00000000000..709df17e0b5 --- /dev/null +++ b/llvm/test/Transforms/GlobalOpt/storepointer-compare-no-null-opt.ll @@ -0,0 +1,40 @@ +; RUN: opt < %s -globalopt -S | FileCheck %s +; CHECK: global + +@G = internal global void ()* null ; <void ()**> [#uses=2] + +define internal void @Actual() { +; CHECK-LABEL: Actual( + ret void +} + +define void @init() { +; CHECK-LABEL: init( +; CHECK: store void ()* @Actual, void ()** @G + store void ()* @Actual, void ()** @G + ret void +} + +define void @doit() #0 { +; CHECK-LABEL: doit( + %FP = load void ()*, void ()** @G ; <void ()*> [#uses=2] +; CHECK: %FP = load void ()*, void ()** @G + %CC = icmp eq void ()* %FP, null ; <i1> [#uses=1] +; CHECK: %CC = icmp eq void ()* %FP, null + br i1 %CC, label %isNull, label %DoCall +; CHECK: br i1 %CC, label %isNull, label %DoCall + +DoCall: ; preds = %0 +; CHECK: DoCall: +; CHECK: call void %FP() +; CHECK: ret void + call void %FP( ) + ret void + +isNull: ; preds = %0 +; CHECK: isNull: +; CHECK: ret void + ret void +} + +attributes #0 = { "null-pointer-is-valid"="true" } diff --git a/llvm/test/Transforms/GlobalOpt/storepointer-no-null-opt.ll b/llvm/test/Transforms/GlobalOpt/storepointer-no-null-opt.ll new file mode 100644 index 00000000000..c9a63f0080d --- /dev/null +++ b/llvm/test/Transforms/GlobalOpt/storepointer-no-null-opt.ll @@ -0,0 +1,27 @@ +; RUN: opt < %s -globalopt -S | FileCheck %s + +@G = internal global void ()* null ; <void ()**> [#uses=2] +; CHECK: global + +define internal void @Actual() { +; CHECK-LABEL: Actual( + ret void +} + +define void @init() { +; CHECK-LABEL: init( +; CHECK: store void ()* @Actual, void ()** @G + store void ()* @Actual, void ()** @G + ret void +} + +define void @doit() #0 { +; CHECK-LABEL: doit( +; CHECK: %FP = load void ()*, void ()** @G +; CHECK: call void %FP() + %FP = load void ()*, void ()** @G ; <void ()*> [#uses=1] + call void %FP( ) + ret void +} + +attributes #0 = { "null-pointer-is-valid"="true" } |