Add writeonly IR attribute

Summary:
This complements the earlier addition of IntrWriteMem and IntrWriteArgMem
LLVM intrinsic properties, see D18291.

Also start using the attribute for memset, memcpy, and memmove intrinsics,
and remove their special-casing in BasicAliasAnalysis.

Reviewers: reames, joker.eph

Subscribers: joker.eph, llvm-commits

Differential Revision: http://reviews.llvm.org/D18714

llvm-svn: 274485
diff --git a/llvm/test/Analysis/BasicAA/cs-cs.ll b/llvm/test/Analysis/BasicAA/cs-cs.ll
index dc298f16..3bc4d72 100644
--- a/llvm/test/Analysis/BasicAA/cs-cs.ll
+++ b/llvm/test/Analysis/BasicAA/cs-cs.ll
@@ -9,6 +9,7 @@
 declare void @llvm.memcpy.p0i8.p0i8.i64(i8* nocapture, i8* nocapture, i64, i32, i1) nounwind
 
 declare void @a_readonly_func(i8 *) noinline nounwind readonly
+declare void @a_writeonly_func(i8 *) noinline nounwind writeonly
 
 define <8 x i16> @test1(i8* %p, <8 x i16> %y) {
 entry:
@@ -22,18 +23,18 @@
 ; CHECK-LABEL: Function: test1:
 
 ; CHECK: NoAlias:      i8* %p, i8* %q
-; CHECK: Just Ref:  Ptr: i8* %p        <->  %a = call <8 x i16> @llvm.arm.neon.vld1.v8i16.p0i8(i8* %p, i32 16) #4
-; CHECK: NoModRef:  Ptr: i8* %q        <->  %a = call <8 x i16> @llvm.arm.neon.vld1.v8i16.p0i8(i8* %p, i32 16) #4
+; CHECK: Just Ref:  Ptr: i8* %p        <->  %a = call <8 x i16> @llvm.arm.neon.vld1.v8i16.p0i8(i8* %p, i32 16) #5
+; CHECK: NoModRef:  Ptr: i8* %q        <->  %a = call <8 x i16> @llvm.arm.neon.vld1.v8i16.p0i8(i8* %p, i32 16) #5
 ; CHECK: NoModRef:  Ptr: i8* %p        <->  call void @llvm.arm.neon.vst1.p0i8.v8i16(i8* %q, <8 x i16> %y, i32 16)
 ; CHECK: Both ModRef:  Ptr: i8* %q     <->  call void @llvm.arm.neon.vst1.p0i8.v8i16(i8* %q, <8 x i16> %y, i32 16)
-; CHECK: Just Ref:  Ptr: i8* %p        <->  %b = call <8 x i16> @llvm.arm.neon.vld1.v8i16.p0i8(i8* %p, i32 16) #4
-; CHECK: NoModRef:  Ptr: i8* %q        <->  %b = call <8 x i16> @llvm.arm.neon.vld1.v8i16.p0i8(i8* %p, i32 16) #4
-; CHECK: NoModRef:   %a = call <8 x i16> @llvm.arm.neon.vld1.v8i16.p0i8(i8* %p, i32 16) #4 <->   call void @llvm.arm.neon.vst1.p0i8.v8i16(i8* %q, <8 x i16> %y, i32 16)
-; CHECK: NoModRef:   %a = call <8 x i16> @llvm.arm.neon.vld1.v8i16.p0i8(i8* %p, i32 16) #4 <->   %b = call <8 x i16> @llvm.arm.neon.vld1.v8i16.p0i8(i8* %p, i32 16) #4
-; CHECK: NoModRef:   call void @llvm.arm.neon.vst1.p0i8.v8i16(i8* %q, <8 x i16> %y, i32 16) <->   %a = call <8 x i16> @llvm.arm.neon.vld1.v8i16.p0i8(i8* %p, i32 16) #4
-; CHECK: NoModRef:   call void @llvm.arm.neon.vst1.p0i8.v8i16(i8* %q, <8 x i16> %y, i32 16) <->   %b = call <8 x i16> @llvm.arm.neon.vld1.v8i16.p0i8(i8* %p, i32 16) #4
-; CHECK: NoModRef:   %b = call <8 x i16> @llvm.arm.neon.vld1.v8i16.p0i8(i8* %p, i32 16) #4 <->   %a = call <8 x i16> @llvm.arm.neon.vld1.v8i16.p0i8(i8* %p, i32 16) #4
-; CHECK: NoModRef:   %b = call <8 x i16> @llvm.arm.neon.vld1.v8i16.p0i8(i8* %p, i32 16) #4 <->   call void @llvm.arm.neon.vst1.p0i8.v8i16(i8* %q, <8 x i16> %y, i32 16)
+; CHECK: Just Ref:  Ptr: i8* %p        <->  %b = call <8 x i16> @llvm.arm.neon.vld1.v8i16.p0i8(i8* %p, i32 16) #5
+; CHECK: NoModRef:  Ptr: i8* %q        <->  %b = call <8 x i16> @llvm.arm.neon.vld1.v8i16.p0i8(i8* %p, i32 16) #5
+; CHECK: NoModRef:   %a = call <8 x i16> @llvm.arm.neon.vld1.v8i16.p0i8(i8* %p, i32 16) #5 <->   call void @llvm.arm.neon.vst1.p0i8.v8i16(i8* %q, <8 x i16> %y, i32 16)
+; CHECK: NoModRef:   %a = call <8 x i16> @llvm.arm.neon.vld1.v8i16.p0i8(i8* %p, i32 16) #5 <->   %b = call <8 x i16> @llvm.arm.neon.vld1.v8i16.p0i8(i8* %p, i32 16) #5
+; CHECK: NoModRef:   call void @llvm.arm.neon.vst1.p0i8.v8i16(i8* %q, <8 x i16> %y, i32 16) <->   %a = call <8 x i16> @llvm.arm.neon.vld1.v8i16.p0i8(i8* %p, i32 16) #5
+; CHECK: NoModRef:   call void @llvm.arm.neon.vst1.p0i8.v8i16(i8* %q, <8 x i16> %y, i32 16) <->   %b = call <8 x i16> @llvm.arm.neon.vld1.v8i16.p0i8(i8* %p, i32 16) #5
+; CHECK: NoModRef:   %b = call <8 x i16> @llvm.arm.neon.vld1.v8i16.p0i8(i8* %p, i32 16) #5 <->   %a = call <8 x i16> @llvm.arm.neon.vld1.v8i16.p0i8(i8* %p, i32 16) #5
+; CHECK: NoModRef:   %b = call <8 x i16> @llvm.arm.neon.vld1.v8i16.p0i8(i8* %p, i32 16) #5 <->   call void @llvm.arm.neon.vst1.p0i8.v8i16(i8* %q, <8 x i16> %y, i32 16)
 }
 
 define void @test2(i8* %P, i8* %Q) nounwind ssp {
@@ -233,9 +234,23 @@
 ; CHECK: Just Ref:   call void @a_readonly_func(i8* %P) <->   call void @llvm.memset.p0i8.i64(i8* %P, i8 -51, i64 32, i32 8, i1 false)
 }
 
-attributes #0 = { nounwind readonly argmemonly }
-attributes #1 = { nounwind argmemonly }
+define void @test7(i8* %P) nounwind ssp {
+  call void @a_writeonly_func(i8* %P)
+  call void @a_readonly_func(i8* %P)
+  ret void
+
+; CHECK-LABEL: Function: test7:
+
+; CHECK: Just Mod:  Ptr: i8* %P        <->  call void @a_writeonly_func(i8* %P)
+; CHECK: Just Ref:  Ptr: i8* %P        <->  call void @a_readonly_func(i8* %P)
+; CHECK: Just Mod:   call void @a_writeonly_func(i8* %P) <->   call void @a_readonly_func(i8* %P)
+; CHECK: Just Ref:   call void @a_readonly_func(i8* %P) <->   call void @a_writeonly_func(i8* %P)
+}
+
+attributes #0 = { argmemonly nounwind readonly }
+attributes #1 = { argmemonly nounwind }
 attributes #2 = { noinline nounwind readonly }
-attributes #3 = { nounwind ssp }
-attributes #4 = { nounwind }
+attributes #3 = { noinline nounwind writeonly }
+attributes #4 = { nounwind ssp }
+attributes #5 = { nounwind }
 
diff --git a/llvm/test/Bindings/llvm-c/Inputs/invalid.ll.bc b/llvm/test/Bindings/llvm-c/Inputs/invalid.ll.bc
index 60c7aff..c675332 100644
--- a/llvm/test/Bindings/llvm-c/Inputs/invalid.ll.bc
+++ b/llvm/test/Bindings/llvm-c/Inputs/invalid.ll.bc
Binary files differ
diff --git a/llvm/test/Bindings/llvm-c/invalid-bitcode.test b/llvm/test/Bindings/llvm-c/invalid-bitcode.test
index 262cb88..c6aaaeb 100644
--- a/llvm/test/Bindings/llvm-c/invalid-bitcode.test
+++ b/llvm/test/Bindings/llvm-c/invalid-bitcode.test
@@ -1,13 +1,13 @@
 ; RUN: not llvm-c-test --module-dump < %S/Inputs/invalid.ll.bc 2>&1 | FileCheck %s
 ; RUN: not llvm-c-test --lazy-module-dump < %S/Inputs/invalid.ll.bc 2>&1 | FileCheck %s
 
-CHECK: Error parsing bitcode: Unknown attribute kind (52)
+CHECK: Error parsing bitcode: Unknown attribute kind (63)
 
 
 ; RUN: not llvm-c-test --new-module-dump < %S/Inputs/invalid.ll.bc 2>&1 | FileCheck --check-prefix=NEW %s
 ; RUN: not llvm-c-test --lazy-new-module-dump < %S/Inputs/invalid.ll.bc 2>&1 | FileCheck --check-prefix=NEW %s
 
-NEW: Error with new bitcode parser: Unknown attribute kind (52)
+NEW: Error with new bitcode parser: Unknown attribute kind (63)
 
 ; RUN: llvm-c-test --test-diagnostic-handler < %S/Inputs/invalid.ll.bc 2>&1 | FileCheck --check-prefix=DIAGNOSTIC %s
 
diff --git a/llvm/test/Bitcode/attributes.ll b/llvm/test/Bitcode/attributes.ll
index d230aa7a..9fdf54b 100644
--- a/llvm/test/Bitcode/attributes.ll
+++ b/llvm/test/Bitcode/attributes.ll
@@ -204,7 +204,7 @@
 ; CHECK: define void @f34()
 {
         call void @nobuiltin() nobuiltin
-; CHECK: call void @nobuiltin() #32
+; CHECK: call void @nobuiltin() #33
         ret void;
 }
 
@@ -328,6 +328,12 @@
   ret i8* null
 }
 
+; CHECK: define void @f56() #32
+define void @f56() writeonly
+{
+  ret void
+}
+
 ; CHECK: attributes #0 = { noreturn }
 ; CHECK: attributes #1 = { nounwind }
 ; CHECK: attributes #2 = { readnone }
@@ -360,4 +366,5 @@
 ; CHECK: attributes #29 = { inaccessiblemem_or_argmemonly }
 ; CHECK: attributes #30 = { allocsize(0) }
 ; CHECK: attributes #31 = { allocsize(0,1) }
-; CHECK: attributes #32 = { nobuiltin }
+; CHECK: attributes #32 = { writeonly }
+; CHECK: attributes #33 = { nobuiltin }
diff --git a/llvm/test/Bitcode/compatibility.ll b/llvm/test/Bitcode/compatibility.ll
index 827bc6a..1827060 100644
--- a/llvm/test/Bitcode/compatibility.ll
+++ b/llvm/test/Bitcode/compatibility.ll
@@ -1244,7 +1244,7 @@
   ; CHECK: select <2 x i1> <i1 true, i1 false>, <2 x i8> <i8 2, i8 3>, <2 x i8> <i8 3, i8 2>
 
   call void @f.nobuiltin() builtin
-  ; CHECK: call void @f.nobuiltin() #39
+  ; CHECK: call void @f.nobuiltin() #40
 
   call fastcc noalias i32* @f.noalias() noinline
   ; CHECK: call fastcc noalias i32* @f.noalias() #12
@@ -1590,6 +1590,8 @@
   ret void
 }
 
+declare void @f.writeonly() writeonly
+; CHECK: declare void @f.writeonly() #39
 
 ; CHECK: attributes #0 = { alignstack=4 }
 ; CHECK: attributes #1 = { alignstack=8 }
@@ -1630,7 +1632,8 @@
 ; CHECK: attributes #36 = { argmemonly nounwind readonly }
 ; CHECK: attributes #37 = { argmemonly nounwind }
 ; CHECK: attributes #38 = { nounwind readonly }
-; CHECK: attributes #39 = { builtin }
+; CHECK: attributes #39 = { writeonly }
+; CHECK: attributes #40 = { builtin }
 
 ;; Metadata
 
diff --git a/llvm/test/Bitcode/invalid.ll b/llvm/test/Bitcode/invalid.ll
index c56f0ff..4bbb457 100644
--- a/llvm/test/Bitcode/invalid.ll
+++ b/llvm/test/Bitcode/invalid.ll
@@ -1,6 +1,6 @@
 ; RUN:  not llvm-dis < %s.bc 2>&1 | FileCheck %s
 
-; CHECK: llvm-dis{{(\.EXE|\.exe)?}}: error: Unknown attribute kind (52)
+; CHECK: llvm-dis{{(\.EXE|\.exe)?}}: error: Unknown attribute kind (63)
 
 ; invalid.ll.bc has an invalid attribute number.
 ; The test checks that LLVM reports the error and doesn't access freed memory
diff --git a/llvm/test/Bitcode/invalid.ll.bc b/llvm/test/Bitcode/invalid.ll.bc
index 60c7aff..a2b611e 100644
--- a/llvm/test/Bitcode/invalid.ll.bc
+++ b/llvm/test/Bitcode/invalid.ll.bc
Binary files differ
diff --git a/llvm/test/LTO/X86/Inputs/invalid.ll.bc b/llvm/test/LTO/X86/Inputs/invalid.ll.bc
index 60c7aff..c675332 100644
--- a/llvm/test/LTO/X86/Inputs/invalid.ll.bc
+++ b/llvm/test/LTO/X86/Inputs/invalid.ll.bc
Binary files differ
diff --git a/llvm/test/LTO/X86/invalid.ll b/llvm/test/LTO/X86/invalid.ll
index b9d0bca..cc3127b 100644
--- a/llvm/test/LTO/X86/invalid.ll
+++ b/llvm/test/LTO/X86/invalid.ll
@@ -1,4 +1,4 @@
 ; RUN: not llvm-lto %S/Inputs/invalid.ll.bc 2>&1 | FileCheck %s
 
 
-; CHECK: llvm-lto{{.*}}: error loading file '{{.*}}/Inputs/invalid.ll.bc': Unknown attribute kind (52)
+; CHECK: llvm-lto{{.*}}: error loading file '{{.*}}/Inputs/invalid.ll.bc': Unknown attribute kind (63)
diff --git a/llvm/test/Verifier/writeonly.ll b/llvm/test/Verifier/writeonly.ll
new file mode 100644
index 0000000..0eeaebb
--- /dev/null
+++ b/llvm/test/Verifier/writeonly.ll
@@ -0,0 +1,13 @@
+; RUN: not llvm-as %s -o /dev/null 2>&1 | FileCheck %s
+
+declare void @a() readnone writeonly
+; CHECK: Attributes {{.*}} are incompatible
+
+declare void @b() readonly writeonly
+; CHECK: Attributes {{.*}} are incompatible
+
+declare void @c(i32* readnone writeonly %p)
+; CHECK: Attributes {{.*}} are incompatible
+
+declare void @d(i32* readonly writeonly %p)
+; CHECK: Attributes {{.*}} are incompatible