summaryrefslogtreecommitdiffstats
path: root/llvm/test/Transforms/FunctionAttrs
diff options
context:
space:
mode:
authorSanjay Patel <spatel@rotateright.com>2017-02-13 23:10:51 +0000
committerSanjay Patel <spatel@rotateright.com>2017-02-13 23:10:51 +0000
commit4f74216da08f8ae1947a858dbb0c4912f21141d4 (patch)
treeaef84f1bfcc11be8204046f3ca79ad10df264115 /llvm/test/Transforms/FunctionAttrs
parente1958a083a78f33566fd2b40838c10864807b9e2 (diff)
downloadbcm5719-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.ll146
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
+}
OpenPOWER on IntegriCloud