Extend 'readonly' and 'readnone' to work on function arguments as well as
functions. Make the function attributes pass add it to known library functions
and when it can deduce it.

llvm-svn: 185735
diff --git a/llvm/test/Transforms/FunctionAttrs/2009-01-02-LocalStores.ll b/llvm/test/Transforms/FunctionAttrs/2009-01-02-LocalStores.ll
index f38c03a..0cf1cb7c6 100644
--- a/llvm/test/Transforms/FunctionAttrs/2009-01-02-LocalStores.ll
+++ b/llvm/test/Transforms/FunctionAttrs/2009-01-02-LocalStores.ll
@@ -1,14 +1,23 @@
-; RUN: opt < %s -functionattrs -S | not grep "nocapture *%%q"
-; RUN: opt < %s -functionattrs -S | grep "nocapture *%%p"
+; RUN: opt < %s -functionattrs -S | FileCheck %s
 
+; CHECK: define i32* @a(i32** nocapture readonly %p)
 define i32* @a(i32** %p) {
 	%tmp = load i32** %p
 	ret i32* %tmp
 }
 
+; CHECK: define i32* @b(i32* %q)
 define i32* @b(i32 *%q) {
 	%mem = alloca i32*
 	store i32* %q, i32** %mem
 	%tmp = call i32* @a(i32** %mem)
 	ret i32* %tmp
 }
+
+; CHECK: define i32* @c(i32* readnone %r)
+@g = global i32 0
+define i32* @c(i32 *%r) {
+	%a = icmp eq i32* %r, null
+	store i32 1, i32* @g
+	ret i32* %r
+}
diff --git a/llvm/test/Transforms/FunctionAttrs/2009-01-04-Annotate.ll b/llvm/test/Transforms/FunctionAttrs/2009-01-04-Annotate.ll
index d414b73..fa06cc7 100644
--- a/llvm/test/Transforms/FunctionAttrs/2009-01-04-Annotate.ll
+++ b/llvm/test/Transforms/FunctionAttrs/2009-01-04-Annotate.ll
@@ -1,6 +1,6 @@
 ; RUN: opt < %s -functionattrs -S | FileCheck %s
 
-; CHECK: declare noalias i8* @fopen(i8* nocapture, i8* nocapture) #0
+; CHECK: declare noalias i8* @fopen(i8* nocapture readonly, i8* nocapture readonly) #0
 declare i8* @fopen(i8*, i8*)
 
 ; CHECK: declare i8 @strlen(i8* nocapture) #1
diff --git a/llvm/test/Transforms/FunctionAttrs/annotate-1.ll b/llvm/test/Transforms/FunctionAttrs/annotate-1.ll
index ca78212..adb7bce 100644
--- a/llvm/test/Transforms/FunctionAttrs/annotate-1.ll
+++ b/llvm/test/Transforms/FunctionAttrs/annotate-1.ll
@@ -2,7 +2,7 @@
 ; RUN: opt < %s -mtriple=x86_64-apple-macosx10.8.0 -functionattrs -S | FileCheck -check-prefix=POSIX %s
 
 declare i8* @fopen(i8*, i8*)
-; CHECK: declare noalias i8* @fopen(i8* nocapture, i8* nocapture) [[G0:#[0-9]]] 
+; CHECK: declare noalias i8* @fopen(i8* nocapture readonly, i8* nocapture readonly) [[G0:#[0-9]]] 
 
 declare i8 @strlen(i8*)
 ; CHECK: declare i8 @strlen(i8* nocapture) [[G1:#[0-9]]]
diff --git a/llvm/test/Transforms/FunctionAttrs/atomic.ll b/llvm/test/Transforms/FunctionAttrs/atomic.ll
index 027ee0f..d5a8db7 100644
--- a/llvm/test/Transforms/FunctionAttrs/atomic.ll
+++ b/llvm/test/Transforms/FunctionAttrs/atomic.ll
@@ -13,7 +13,7 @@
 
 ; A function with an Acquire load is not readonly.
 define i32 @test2(i32* %x) uwtable ssp {
-; CHECK: define i32 @test2(i32* nocapture %x) #1 {
+; CHECK: define i32 @test2(i32* nocapture readonly %x) #1 {
 entry:
   %r = load atomic i32* %x seq_cst, align 4
   ret i32 %r
diff --git a/llvm/test/Transforms/FunctionAttrs/nocapture.ll b/llvm/test/Transforms/FunctionAttrs/nocapture.ll
index 3027acd..110bd03 100644
--- a/llvm/test/Transforms/FunctionAttrs/nocapture.ll
+++ b/llvm/test/Transforms/FunctionAttrs/nocapture.ll
@@ -1,12 +1,13 @@
 ; RUN: opt < %s -functionattrs -S | FileCheck %s
 @g = global i32* null		; <i32**> [#uses=1]
 
-; CHECK: define i32* @c1(i32* %q)
+; CHECK: define i32* @c1(i32* readnone %q)
 define i32* @c1(i32* %q) {
 	ret i32* %q
 }
 
 ; CHECK: define void @c2(i32* %q)
+; It would also be acceptable to mark %q as readnone. Update @c3 too.
 define void @c2(i32* %q) {
 	store i32* %q, i32** @g
 	ret void
@@ -45,7 +46,7 @@
 
 declare void @throw_if_bit_set(i8*, i8) readonly
 
-; CHECK: define i1 @c6(i8* %q, i8 %bit)
+; CHECK: define i1 @c6(i8* readonly %q, i8 %bit)
 define i1 @c6(i8* %q, i8 %bit) {
 	invoke void @throw_if_bit_set(i8* %q, i8 %bit)
 		to label %ret0 unwind label %ret1
@@ -67,7 +68,7 @@
 	ret i1* %lookup
 }
 
-; CHECK: define i1 @c7(i32* %q, i32 %bitno)
+; CHECK: define i1 @c7(i32* readnone %q, i32 %bitno)
 define i1 @c7(i32* %q, i32 %bitno) {
 	%ptr = call i1* @lookup_bit(i32* %q, i32 %bitno)
 	%val = load i1* %ptr
@@ -103,7 +104,7 @@
 }
 
 declare void @external(i8*) readonly nounwind
-; CHECK: define void @nc4(i8* nocapture %p)
+; CHECK: define void @nc4(i8* nocapture readonly %p)
 define void @nc4(i8* %p) {
 	call void @external(i8* %p)
 	ret void
@@ -116,28 +117,29 @@
 	ret void
 }
 
-; CHECK: define void @test1_1(i8* nocapture %x1_1, i8* %y1_1)
+; CHECK: define void @test1_1(i8* nocapture readnone %x1_1, i8* %y1_1)
+; It would be acceptable to add readnone to %y1_1 and %y1_2.
 define void @test1_1(i8* %x1_1, i8* %y1_1) {
   call i8* @test1_2(i8* %x1_1, i8* %y1_1)
   store i32* null, i32** @g
   ret void
 }
 
-; CHECK: define i8* @test1_2(i8* nocapture %x1_2, i8* %y1_2)
+; CHECK: define i8* @test1_2(i8* nocapture readnone %x1_2, i8* %y1_2)
 define i8* @test1_2(i8* %x1_2, i8* %y1_2) {
   call void @test1_1(i8* %x1_2, i8* %y1_2)
   store i32* null, i32** @g
   ret i8* %y1_2
 }
 
-; CHECK: define void @test2(i8* nocapture %x2)
+; CHECK: define void @test2(i8* nocapture readnone %x2)
 define void @test2(i8* %x2) {
   call void @test2(i8* %x2)
   store i32* null, i32** @g
   ret void
 }
 
-; CHECK: define void @test3(i8* nocapture %x3, i8* nocapture %y3, i8* nocapture %z3)
+; CHECK: define void @test3(i8* nocapture readnone %x3, i8* nocapture readnone %y3, i8* nocapture readnone %z3)
 define void @test3(i8* %x3, i8* %y3, i8* %z3) {
   call void @test3(i8* %z3, i8* %y3, i8* %x3)
   store i32* null, i32** @g
@@ -151,7 +153,7 @@
   ret void
 }
 
-; CHECK: define i8* @test4_2(i8* nocapture %x4_2, i8* %y4_2, i8* nocapture %z4_2)
+; CHECK: define i8* @test4_2(i8* nocapture readnone %x4_2, i8* readnone %y4_2, i8* nocapture readnone %z4_2)
 define i8* @test4_2(i8* %x4_2, i8* %y4_2, i8* %z4_2) {
   call void @test4_1(i8* null)
   store i32* null, i32** @g
diff --git a/llvm/test/Transforms/FunctionAttrs/readattrs.ll b/llvm/test/Transforms/FunctionAttrs/readattrs.ll
new file mode 100644
index 0000000..0842f56
--- /dev/null
+++ b/llvm/test/Transforms/FunctionAttrs/readattrs.ll
@@ -0,0 +1,47 @@
+; RUN: opt < %s -functionattrs -S | FileCheck %s
+@x = global i32 0
+
+declare void @test1_1(i8* %x1_1, i8* readonly %y1_1, ...)
+
+; CHECK: define void @test1_2(i8* %x1_2, i8* readonly %y1_2, i8* %z1_2)
+define void @test1_2(i8* %x1_2, i8* %y1_2, i8* %z1_2) {
+  call void (i8*, i8*, ...)* @test1_1(i8* %x1_2, i8* %y1_2, i8* %z1_2)
+  store i32 0, i32* @x
+  ret void
+}
+
+; CHECK: define i8* @test2(i8* readnone %p)
+define i8* @test2(i8* %p) {
+  store i32 0, i32* @x
+  ret i8* %p
+}
+
+; CHECK: define i1 @test3(i8* readnone %p, i8* readnone %q)
+define i1 @test3(i8* %p, i8* %q) {
+  %A = icmp ult i8* %p, %q
+  ret i1 %A
+}
+
+declare void @test4_1(i8* nocapture) readonly
+
+; CHECK: define void @test4_2(i8* nocapture readonly %p)
+define void @test4_2(i8* %p) {
+  call void @test4_1(i8* %p)
+  ret void
+}
+
+; CHECK: define void @test5(i8** nocapture %p, i8* %q)
+; Missed optz'n: we could make %q readnone, but don't break test6!
+define void @test5(i8** %p, i8* %q) {
+  store i8* %q, i8** %p
+  ret void
+}
+
+declare void @test6_1()
+; CHECK: define void @test6_2(i8** nocapture %p, i8* %q)
+; This is not a missed optz'n.
+define void @test6_2(i8** %p, i8* %q) {
+  store i8* %q, i8** %p
+  call void @test6_1()
+  ret void
+}