diff options
author | Sanjay Patel <spatel@rotateright.com> | 2017-02-13 23:10:51 +0000 |
---|---|---|
committer | Sanjay Patel <spatel@rotateright.com> | 2017-02-13 23:10:51 +0000 |
commit | 4f74216da08f8ae1947a858dbb0c4912f21141d4 (patch) | |
tree | aef84f1bfcc11be8204046f3ca79ad10df264115 /llvm/test/Transforms/FunctionAttrs | |
parent | e1958a083a78f33566fd2b40838c10864807b9e2 (diff) | |
download | bcm5719-llvm-4f74216da08f8ae1947a858dbb0c4912f21141d4.tar.gz bcm5719-llvm-4f74216da08f8ae1947a858dbb0c4912f21141d4.zip |
[FunctionAttrs] try to extend nonnull-ness of arguments from a callsite back to its parent function
As discussed here:
http://lists.llvm.org/pipermail/llvm-dev/2016-December/108182.html
...we should be able to propagate 'nonnull' info from a callsite back to its parent.
The original motivation for this patch is our botched optimization of "dyn_cast" (PR28430),
but this won't solve that problem.
The transform is currently disabled by default while we wait for clang to work-around
potential security problems:
http://lists.llvm.org/pipermail/cfe-dev/2017-January/052066.html
Differential Revision: https://reviews.llvm.org/D27855
llvm-svn: 294998
Diffstat (limited to 'llvm/test/Transforms/FunctionAttrs')
-rw-r--r-- | llvm/test/Transforms/FunctionAttrs/nonnull.ll | 146 |
1 files changed, 145 insertions, 1 deletions
diff --git a/llvm/test/Transforms/FunctionAttrs/nonnull.ll b/llvm/test/Transforms/FunctionAttrs/nonnull.ll index 1fb64b7434a..4a1ff14b204 100644 --- a/llvm/test/Transforms/FunctionAttrs/nonnull.ll +++ b/llvm/test/Transforms/FunctionAttrs/nonnull.ll @@ -1,4 +1,4 @@ -; RUN: opt -S -functionattrs %s | FileCheck %s +; RUN: opt -S -functionattrs -enable-nonnull-arg-prop %s | FileCheck %s declare nonnull i8* @ret_nonnull() ; Return a pointer trivially nonnull (call return attribute) @@ -71,4 +71,148 @@ exit: ret i8* %phi } +; Test propagation of nonnull callsite args back to caller. + +declare void @use1(i8* %x) +declare void @use2(i8* %x, i8* %y); +declare void @use3(i8* %x, i8* %y, i8* %z); + +declare void @use1nonnull(i8* nonnull %x); +declare void @use2nonnull(i8* nonnull %x, i8* nonnull %y); +declare void @use3nonnull(i8* nonnull %x, i8* nonnull %y, i8* nonnull %z); + +declare i8 @use1safecall(i8* %x) readonly nounwind ; readonly+nounwind guarantees that execution continues to successor + +; Can't extend non-null to parent for any argument because the 2nd call is not guaranteed to execute. + +define void @parent1(i8* %a, i8* %b, i8* %c) { +; CHECK-LABEL: @parent1(i8* %a, i8* %b, i8* %c) +; CHECK-NEXT: call void @use3(i8* %c, i8* %a, i8* %b) +; CHECK-NEXT: call void @use3nonnull(i8* %b, i8* %c, i8* %a) +; CHECK-NEXT: ret void +; + call void @use3(i8* %c, i8* %a, i8* %b) + call void @use3nonnull(i8* %b, i8* %c, i8* %a) + ret void +} + +; Extend non-null to parent for all arguments. + +define void @parent2(i8* %a, i8* %b, i8* %c) { +; CHECK-LABEL: @parent2(i8* nonnull %a, i8* nonnull %b, i8* nonnull %c) +; CHECK-NEXT: call void @use3nonnull(i8* %b, i8* %c, i8* %a) +; CHECK-NEXT: call void @use3(i8* %c, i8* %a, i8* %b) +; CHECK-NEXT: ret void +; + call void @use3nonnull(i8* %b, i8* %c, i8* %a) + call void @use3(i8* %c, i8* %a, i8* %b) + ret void +} + +; Extend non-null to parent for 1st argument. + +define void @parent3(i8* %a, i8* %b, i8* %c) { +; CHECK-LABEL: @parent3(i8* nonnull %a, i8* %b, i8* %c) +; CHECK-NEXT: call void @use1nonnull(i8* %a) +; CHECK-NEXT: call void @use3(i8* %c, i8* %b, i8* %a) +; CHECK-NEXT: ret void +; + call void @use1nonnull(i8* %a) + call void @use3(i8* %c, i8* %b, i8* %a) + ret void +} + +; Extend non-null to parent for last 2 arguments. + +define void @parent4(i8* %a, i8* %b, i8* %c) { +; CHECK-LABEL: @parent4(i8* %a, i8* nonnull %b, i8* nonnull %c) +; CHECK-NEXT: call void @use2nonnull(i8* %c, i8* %b) +; CHECK-NEXT: call void @use2(i8* %a, i8* %c) +; CHECK-NEXT: call void @use1(i8* %b) +; CHECK-NEXT: ret void +; + call void @use2nonnull(i8* %c, i8* %b) + call void @use2(i8* %a, i8* %c) + call void @use1(i8* %b) + ret void +} + +; The callsite must execute in order for the attribute to transfer to the parent. +; It appears benign to extend non-null to the parent in this case, but we can't do that +; because it would incorrectly propagate the wrong information to its callers. + +define void @parent5(i8* %a, i1 %a_is_notnull) { +; CHECK-LABEL: @parent5(i8* %a, i1 %a_is_notnull) +; CHECK-NEXT: br i1 %a_is_notnull, label %t, label %f +; CHECK: t: +; CHECK-NEXT: call void @use1nonnull(i8* %a) +; CHECK-NEXT: ret void +; CHECK: f: +; CHECK-NEXT: ret void +; + br i1 %a_is_notnull, label %t, label %f +t: + call void @use1nonnull(i8* %a) + ret void +f: + ret void +} + +; The callsite must execute in order for the attribute to transfer to the parent. +; The volatile load might trap, so there's no guarantee that we'll ever get to the call. + +define i8 @parent6(i8* %a, i8* %b) { +; CHECK-LABEL: @parent6(i8* %a, i8* %b) +; CHECK-NEXT: [[C:%.*]] = load volatile i8, i8* %b +; CHECK-NEXT: call void @use1nonnull(i8* %a) +; CHECK-NEXT: ret i8 [[C]] +; + %c = load volatile i8, i8* %b + call void @use1nonnull(i8* %a) + ret i8 %c +} + +; The nonnull callsite is guaranteed to execute, so the argument must be nonnull throughout the parent. + +define i8 @parent7(i8* %a) { +; CHECK-LABEL: @parent7(i8* nonnull %a) +; CHECK-NEXT: [[RET:%.*]] = call i8 @use1safecall(i8* %a) +; CHECK-NEXT: call void @use1nonnull(i8* %a) +; CHECK-NEXT: ret i8 [[RET]] +; + %ret = call i8 @use1safecall(i8* %a) + call void @use1nonnull(i8* %a) + ret i8 %ret +} + +; Make sure that an invoke works similarly to a call. + +declare i32 @esfp(...) + +define i1 @parent8(i8* %a, i8* %bogus1, i8* %b) personality i8* bitcast (i32 (...)* @esfp to i8*){ +; CHECK-LABEL: @parent8(i8* nonnull %a, i8* nocapture readnone %bogus1, i8* nonnull %b) +; CHECK-NEXT: entry: +; CHECK-NEXT: invoke void @use2nonnull(i8* %a, i8* %b) +; CHECK-NEXT: to label %cont unwind label %exc +; CHECK: cont: +; CHECK-NEXT: [[NULL_CHECK:%.*]] = icmp eq i8* %b, null +; CHECK-NEXT: ret i1 [[NULL_CHECK]] +; CHECK: exc: +; CHECK-NEXT: [[LP:%.*]] = landingpad { i8*, i32 } +; CHECK-NEXT: filter [0 x i8*] zeroinitializer +; CHECK-NEXT: unreachable +; +entry: + invoke void @use2nonnull(i8* %a, i8* %b) + to label %cont unwind label %exc + +cont: + %null_check = icmp eq i8* %b, null + ret i1 %null_check + +exc: + %lp = landingpad { i8*, i32 } + filter [0 x i8*] zeroinitializer + unreachable +} |