diff llvm/test/Transforms/FunctionAttrs/writeonly.ll @ 252:1f2b6ac9f198 llvm-original

LLVM16-1
author Shinji KONO <kono@ie.u-ryukyu.ac.jp>
date Fri, 18 Aug 2023 09:04:13 +0900
parents c4bab56944e8
children
line wrap: on
line diff
--- a/llvm/test/Transforms/FunctionAttrs/writeonly.ll	Wed Nov 09 17:47:54 2022 +0900
+++ b/llvm/test/Transforms/FunctionAttrs/writeonly.ll	Fri Aug 18 09:04:13 2023 +0900
@@ -1,24 +1,38 @@
 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --check-attributes
-; RUN: opt < %s -passes=function-attrs -S | FileCheck %s
+; RUN: opt -passes=function-attrs -S < %s | FileCheck --check-prefixes=COMMON,FNATTRS %s
+; RUN: opt -passes=attributor-light -S < %s | FileCheck --check-prefixes=COMMON,ATTRIBUTOR %s
 
 define void @nouses-argworn-funrn(ptr writeonly %.aaa) {
-; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind readnone willreturn
-; CHECK-LABEL: define {{[^@]+}}@nouses-argworn-funrn
-; CHECK-SAME: (ptr nocapture readnone [[DOTAAA:%.*]]) #[[ATTR0:[0-9]+]] {
-; CHECK-NEXT:  nouses-argworn-funrn_entry:
-; CHECK-NEXT:    ret void
+; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
+; FNATTRS-LABEL: define {{[^@]+}}@nouses-argworn-funrn
+; FNATTRS-SAME: (ptr nocapture readnone [[DOTAAA:%.*]]) #[[ATTR0:[0-9]+]] {
+; FNATTRS-NEXT:  nouses-argworn-funrn_entry:
+; FNATTRS-NEXT:    ret void
+;
+; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
+; ATTRIBUTOR-LABEL: define {{[^@]+}}@nouses-argworn-funrn
+; ATTRIBUTOR-SAME: (ptr nocapture nofree readnone [[DOTAAA:%.*]]) #[[ATTR0:[0-9]+]] {
+; ATTRIBUTOR-NEXT:  nouses-argworn-funrn_entry:
+; ATTRIBUTOR-NEXT:    ret void
 ;
 nouses-argworn-funrn_entry:
   ret void
 }
 
 define void @nouses-argworn-funro(ptr writeonly %.aaa, ptr %.bbb) {
-; CHECK: Function Attrs: argmemonly mustprogress nofree norecurse nosync nounwind readonly willreturn
-; CHECK-LABEL: define {{[^@]+}}@nouses-argworn-funro
-; CHECK-SAME: (ptr nocapture readnone [[DOTAAA:%.*]], ptr nocapture readonly [[DOTBBB:%.*]]) #[[ATTR1:[0-9]+]] {
-; CHECK-NEXT:  nouses-argworn-funro_entry:
-; CHECK-NEXT:    [[VAL:%.*]] = load i32, ptr [[DOTBBB]], align 4
-; CHECK-NEXT:    ret void
+; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: read)
+; FNATTRS-LABEL: define {{[^@]+}}@nouses-argworn-funro
+; FNATTRS-SAME: (ptr nocapture readnone [[DOTAAA:%.*]], ptr nocapture readonly [[DOTBBB:%.*]]) #[[ATTR1:[0-9]+]] {
+; FNATTRS-NEXT:  nouses-argworn-funro_entry:
+; FNATTRS-NEXT:    [[VAL:%.*]] = load i32, ptr [[DOTBBB]], align 4
+; FNATTRS-NEXT:    ret void
+;
+; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: read)
+; ATTRIBUTOR-LABEL: define {{[^@]+}}@nouses-argworn-funro
+; ATTRIBUTOR-SAME: (ptr nocapture nofree readnone [[DOTAAA:%.*]], ptr nocapture nofree nonnull readonly [[DOTBBB:%.*]]) #[[ATTR1:[0-9]+]] {
+; ATTRIBUTOR-NEXT:  nouses-argworn-funro_entry:
+; ATTRIBUTOR-NEXT:    [[VAL:%.*]] = load i32, ptr [[DOTBBB]], align 4
+; ATTRIBUTOR-NEXT:    ret void
 ;
 nouses-argworn-funro_entry:
   %val = load i32 , ptr %.bbb
@@ -30,12 +44,19 @@
 @d-ccc = internal global %_type_of_d-ccc <{ ptr null, i8 1, i8 13, i8 0, i8 -127 }>, align 8
 
 define void @nouses-argworn-funwo(ptr writeonly %.aaa) {
-; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn writeonly
-; CHECK-LABEL: define {{[^@]+}}@nouses-argworn-funwo
-; CHECK-SAME: (ptr nocapture readnone [[DOTAAA:%.*]]) #[[ATTR2:[0-9]+]] {
-; CHECK-NEXT:  nouses-argworn-funwo_entry:
-; CHECK-NEXT:    store i8 0, ptr getelementptr inbounds ([[_TYPE_OF_D_CCC:%.*]], ptr @d-ccc, i32 0, i32 3), align 1
-; CHECK-NEXT:    ret void
+; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(write, argmem: none, inaccessiblemem: none)
+; FNATTRS-LABEL: define {{[^@]+}}@nouses-argworn-funwo
+; FNATTRS-SAME: (ptr nocapture readnone [[DOTAAA:%.*]]) #[[ATTR2:[0-9]+]] {
+; FNATTRS-NEXT:  nouses-argworn-funwo_entry:
+; FNATTRS-NEXT:    store i8 0, ptr getelementptr inbounds ([[_TYPE_OF_D_CCC:%.*]], ptr @d-ccc, i32 0, i32 3), align 1
+; FNATTRS-NEXT:    ret void
+;
+; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(write)
+; ATTRIBUTOR-LABEL: define {{[^@]+}}@nouses-argworn-funwo
+; ATTRIBUTOR-SAME: (ptr nocapture nofree readnone [[DOTAAA:%.*]]) #[[ATTR2:[0-9]+]] {
+; ATTRIBUTOR-NEXT:  nouses-argworn-funwo_entry:
+; ATTRIBUTOR-NEXT:    store i8 0, ptr getelementptr inbounds ([[_TYPE_OF_D_CCC:%.*]], ptr @d-ccc, i32 0, i32 3), align 1
+; ATTRIBUTOR-NEXT:    ret void
 ;
 nouses-argworn-funwo_entry:
   store i8 0, ptr getelementptr inbounds (%_type_of_d-ccc, ptr @d-ccc, i32 0, i32 3)
@@ -43,11 +64,17 @@
 }
 
 define void @test_store(ptr %p) {
-; CHECK: Function Attrs: argmemonly mustprogress nofree norecurse nosync nounwind willreturn writeonly
-; CHECK-LABEL: define {{[^@]+}}@test_store
-; CHECK-SAME: (ptr nocapture writeonly [[P:%.*]]) #[[ATTR3:[0-9]+]] {
-; CHECK-NEXT:    store i8 0, ptr [[P]], align 1
-; CHECK-NEXT:    ret void
+; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: write)
+; FNATTRS-LABEL: define {{[^@]+}}@test_store
+; FNATTRS-SAME: (ptr nocapture writeonly [[P:%.*]]) #[[ATTR3:[0-9]+]] {
+; FNATTRS-NEXT:    store i8 0, ptr [[P]], align 1
+; FNATTRS-NEXT:    ret void
+;
+; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: write)
+; ATTRIBUTOR-LABEL: define {{[^@]+}}@test_store
+; ATTRIBUTOR-SAME: (ptr nocapture nofree nonnull writeonly [[P:%.*]]) #[[ATTR3:[0-9]+]] {
+; ATTRIBUTOR-NEXT:    store i8 0, ptr [[P]], align 1
+; ATTRIBUTOR-NEXT:    ret void
 ;
   store i8 0, ptr %p
   ret void
@@ -55,13 +82,21 @@
 
 @G = external global ptr
 define i8 @test_store_capture(ptr %p) {
-; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn
-; CHECK-LABEL: define {{[^@]+}}@test_store_capture
-; CHECK-SAME: (ptr [[P:%.*]]) #[[ATTR4:[0-9]+]] {
-; CHECK-NEXT:    store ptr [[P]], ptr @G, align 8
-; CHECK-NEXT:    [[P2:%.*]] = load ptr, ptr @G, align 8
-; CHECK-NEXT:    [[V:%.*]] = load i8, ptr [[P2]], align 1
-; CHECK-NEXT:    ret i8 [[V]]
+; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(readwrite, argmem: read, inaccessiblemem: none)
+; FNATTRS-LABEL: define {{[^@]+}}@test_store_capture
+; FNATTRS-SAME: (ptr [[P:%.*]]) #[[ATTR4:[0-9]+]] {
+; FNATTRS-NEXT:    store ptr [[P]], ptr @G, align 8
+; FNATTRS-NEXT:    [[P2:%.*]] = load ptr, ptr @G, align 8
+; FNATTRS-NEXT:    [[V:%.*]] = load i8, ptr [[P2]], align 1
+; FNATTRS-NEXT:    ret i8 [[V]]
+;
+; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn
+; ATTRIBUTOR-LABEL: define {{[^@]+}}@test_store_capture
+; ATTRIBUTOR-SAME: (ptr nofree [[P:%.*]]) #[[ATTR4:[0-9]+]] {
+; ATTRIBUTOR-NEXT:    store ptr [[P]], ptr @G, align 8
+; ATTRIBUTOR-NEXT:    [[P2:%.*]] = load ptr, ptr @G, align 8
+; ATTRIBUTOR-NEXT:    [[V:%.*]] = load i8, ptr [[P2]], align 1
+; ATTRIBUTOR-NEXT:    ret i8 [[V]]
 ;
   store ptr %p, ptr @G
   %p2 = load ptr, ptr @G
@@ -70,12 +105,19 @@
 }
 
 define void @test_addressing(ptr %p) {
-; CHECK: Function Attrs: argmemonly mustprogress nofree norecurse nosync nounwind willreturn writeonly
-; CHECK-LABEL: define {{[^@]+}}@test_addressing
-; CHECK-SAME: (ptr nocapture writeonly [[P:%.*]]) #[[ATTR3]] {
-; CHECK-NEXT:    [[GEP:%.*]] = getelementptr i8, ptr [[P]], i64 8
-; CHECK-NEXT:    store i32 0, ptr [[GEP]], align 4
-; CHECK-NEXT:    ret void
+; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: write)
+; FNATTRS-LABEL: define {{[^@]+}}@test_addressing
+; FNATTRS-SAME: (ptr nocapture writeonly [[P:%.*]]) #[[ATTR3]] {
+; FNATTRS-NEXT:    [[GEP:%.*]] = getelementptr i8, ptr [[P]], i64 8
+; FNATTRS-NEXT:    store i32 0, ptr [[GEP]], align 4
+; FNATTRS-NEXT:    ret void
+;
+; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: write)
+; ATTRIBUTOR-LABEL: define {{[^@]+}}@test_addressing
+; ATTRIBUTOR-SAME: (ptr nocapture nofree writeonly [[P:%.*]]) #[[ATTR3]] {
+; ATTRIBUTOR-NEXT:    [[GEP:%.*]] = getelementptr i8, ptr [[P]], i64 8
+; ATTRIBUTOR-NEXT:    store i32 0, ptr [[GEP]], align 4
+; ATTRIBUTOR-NEXT:    ret void
 ;
   %gep = getelementptr i8, ptr %p, i64 8
   store i32 0, ptr %gep
@@ -83,12 +125,19 @@
 }
 
 define void @test_readwrite(ptr %p) {
-; CHECK: Function Attrs: argmemonly mustprogress nofree norecurse nosync nounwind willreturn
-; CHECK-LABEL: define {{[^@]+}}@test_readwrite
-; CHECK-SAME: (ptr nocapture [[P:%.*]]) #[[ATTR5:[0-9]+]] {
-; CHECK-NEXT:    [[V:%.*]] = load i8, ptr [[P]], align 1
-; CHECK-NEXT:    store i8 [[V]], ptr [[P]], align 1
-; CHECK-NEXT:    ret void
+; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: readwrite)
+; FNATTRS-LABEL: define {{[^@]+}}@test_readwrite
+; FNATTRS-SAME: (ptr nocapture [[P:%.*]]) #[[ATTR5:[0-9]+]] {
+; FNATTRS-NEXT:    [[V:%.*]] = load i8, ptr [[P]], align 1
+; FNATTRS-NEXT:    store i8 [[V]], ptr [[P]], align 1
+; FNATTRS-NEXT:    ret void
+;
+; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: readwrite)
+; ATTRIBUTOR-LABEL: define {{[^@]+}}@test_readwrite
+; ATTRIBUTOR-SAME: (ptr nocapture nofree nonnull [[P:%.*]]) #[[ATTR5:[0-9]+]] {
+; ATTRIBUTOR-NEXT:    [[V:%.*]] = load i8, ptr [[P]], align 1
+; ATTRIBUTOR-NEXT:    store i8 [[V]], ptr [[P]], align 1
+; ATTRIBUTOR-NEXT:    ret void
 ;
   %v = load i8, ptr %p
   store i8 %v, ptr %p
@@ -96,22 +145,34 @@
 }
 
 define void @test_volatile(ptr %p) {
-; CHECK: Function Attrs: inaccessiblemem_or_argmemonly nofree norecurse nounwind
-; CHECK-LABEL: define {{[^@]+}}@test_volatile
-; CHECK-SAME: (ptr [[P:%.*]]) #[[ATTR6:[0-9]+]] {
-; CHECK-NEXT:    store volatile i8 0, ptr [[P]], align 1
-; CHECK-NEXT:    ret void
+; FNATTRS: Function Attrs: nofree norecurse nounwind memory(argmem: readwrite, inaccessiblemem: readwrite)
+; FNATTRS-LABEL: define {{[^@]+}}@test_volatile
+; FNATTRS-SAME: (ptr [[P:%.*]]) #[[ATTR6:[0-9]+]] {
+; FNATTRS-NEXT:    store volatile i8 0, ptr [[P]], align 1
+; FNATTRS-NEXT:    ret void
+;
+; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nounwind willreturn memory(argmem: readwrite)
+; ATTRIBUTOR-LABEL: define {{[^@]+}}@test_volatile
+; ATTRIBUTOR-SAME: (ptr nofree [[P:%.*]]) #[[ATTR6:[0-9]+]] {
+; ATTRIBUTOR-NEXT:    store volatile i8 0, ptr [[P]], align 1
+; ATTRIBUTOR-NEXT:    ret void
 ;
   store volatile i8 0, ptr %p
   ret void
 }
 
 define void @test_atomicrmw(ptr %p) {
-; CHECK: Function Attrs: argmemonly mustprogress nofree norecurse nounwind willreturn
-; CHECK-LABEL: define {{[^@]+}}@test_atomicrmw
-; CHECK-SAME: (ptr nocapture [[P:%.*]]) #[[ATTR7:[0-9]+]] {
-; CHECK-NEXT:    [[TMP1:%.*]] = atomicrmw add ptr [[P]], i8 0 seq_cst, align 1
-; CHECK-NEXT:    ret void
+; FNATTRS: Function Attrs: mustprogress nofree norecurse nounwind willreturn memory(argmem: readwrite)
+; FNATTRS-LABEL: define {{[^@]+}}@test_atomicrmw
+; FNATTRS-SAME: (ptr nocapture [[P:%.*]]) #[[ATTR7:[0-9]+]] {
+; FNATTRS-NEXT:    [[TMP1:%.*]] = atomicrmw add ptr [[P]], i8 0 seq_cst, align 1
+; FNATTRS-NEXT:    ret void
+;
+; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nounwind willreturn memory(argmem: readwrite)
+; ATTRIBUTOR-LABEL: define {{[^@]+}}@test_atomicrmw
+; ATTRIBUTOR-SAME: (ptr nocapture nofree nonnull [[P:%.*]]) #[[ATTR6]] {
+; ATTRIBUTOR-NEXT:    [[TMP1:%.*]] = atomicrmw add ptr [[P]], i8 0 seq_cst, align 1
+; ATTRIBUTOR-NEXT:    ret void
 ;
   atomicrmw add ptr %p, i8 0  seq_cst
   ret void
@@ -121,10 +182,10 @@
 declare void @direct1_callee(ptr %p)
 
 define void @direct1(ptr %p) {
-; CHECK-LABEL: define {{[^@]+}}@direct1
-; CHECK-SAME: (ptr [[P:%.*]]) {
-; CHECK-NEXT:    call void @direct1_callee(ptr [[P]])
-; CHECK-NEXT:    ret void
+; COMMON-LABEL: define {{[^@]+}}@direct1
+; COMMON-SAME: (ptr [[P:%.*]]) {
+; COMMON-NEXT:    call void @direct1_callee(ptr [[P]])
+; COMMON-NEXT:    ret void
 ;
   call void @direct1_callee(ptr %p)
   ret void
@@ -134,11 +195,17 @@
 
 ; writeonly w/o nocapture is not enough
 define void @direct2(ptr %p) {
-; CHECK: Function Attrs: writeonly
-; CHECK-LABEL: define {{[^@]+}}@direct2
-; CHECK-SAME: (ptr [[P:%.*]]) #[[ATTR8:[0-9]+]] {
-; CHECK-NEXT:    call void @direct2_callee(ptr [[P]])
-; CHECK-NEXT:    ret void
+; FNATTRS: Function Attrs: memory(write)
+; FNATTRS-LABEL: define {{[^@]+}}@direct2
+; FNATTRS-SAME: (ptr [[P:%.*]]) #[[ATTR8:[0-9]+]] {
+; FNATTRS-NEXT:    call void @direct2_callee(ptr [[P]])
+; FNATTRS-NEXT:    ret void
+;
+; ATTRIBUTOR: Function Attrs: memory(write)
+; ATTRIBUTOR-LABEL: define {{[^@]+}}@direct2
+; ATTRIBUTOR-SAME: (ptr writeonly [[P:%.*]]) #[[ATTR7:[0-9]+]] {
+; ATTRIBUTOR-NEXT:    call void @direct2_callee(ptr [[P]]) #[[ATTR7]]
+; ATTRIBUTOR-NEXT:    ret void
 ;
   call void @direct2_callee(ptr %p)
   ; read back from global, read through pointer...
@@ -146,11 +213,17 @@
 }
 
 define void @direct2b(ptr %p) {
-; CHECK: Function Attrs: writeonly
-; CHECK-LABEL: define {{[^@]+}}@direct2b
-; CHECK-SAME: (ptr nocapture writeonly [[P:%.*]]) #[[ATTR8]] {
-; CHECK-NEXT:    call void @direct2_callee(ptr nocapture [[P]])
-; CHECK-NEXT:    ret void
+; FNATTRS: Function Attrs: memory(write)
+; FNATTRS-LABEL: define {{[^@]+}}@direct2b
+; FNATTRS-SAME: (ptr nocapture [[P:%.*]]) #[[ATTR8]] {
+; FNATTRS-NEXT:    call void @direct2_callee(ptr nocapture [[P]])
+; FNATTRS-NEXT:    ret void
+;
+; ATTRIBUTOR: Function Attrs: memory(write)
+; ATTRIBUTOR-LABEL: define {{[^@]+}}@direct2b
+; ATTRIBUTOR-SAME: (ptr nocapture writeonly [[P:%.*]]) #[[ATTR7]] {
+; ATTRIBUTOR-NEXT:    call void @direct2_callee(ptr nocapture writeonly [[P]]) #[[ATTR7]]
+; ATTRIBUTOR-NEXT:    ret void
 ;
   call void @direct2_callee(ptr nocapture %p)
   ret void
@@ -159,61 +232,87 @@
 declare void @direct3_callee(ptr nocapture writeonly %p)
 
 define void @direct3(ptr %p) {
-; CHECK-LABEL: define {{[^@]+}}@direct3
-; CHECK-SAME: (ptr nocapture writeonly [[P:%.*]]) {
-; CHECK-NEXT:    call void @direct3_callee(ptr [[P]])
-; CHECK-NEXT:    ret void
+; FNATTRS-LABEL: define {{[^@]+}}@direct3
+; FNATTRS-SAME: (ptr nocapture writeonly [[P:%.*]]) {
+; FNATTRS-NEXT:    call void @direct3_callee(ptr [[P]])
+; FNATTRS-NEXT:    ret void
+;
+; ATTRIBUTOR-LABEL: define {{[^@]+}}@direct3
+; ATTRIBUTOR-SAME: (ptr nocapture writeonly [[P:%.*]]) {
+; ATTRIBUTOR-NEXT:    call void @direct3_callee(ptr nocapture writeonly [[P]])
+; ATTRIBUTOR-NEXT:    ret void
 ;
   call void @direct3_callee(ptr %p)
   ret void
 }
 
 define void @direct3b(ptr %p) {
-; CHECK-LABEL: define {{[^@]+}}@direct3b
-; CHECK-SAME: (ptr [[P:%.*]]) {
-; CHECK-NEXT:    call void @direct3_callee(ptr [[P]]) [ "may-read-and-capture"(ptr [[P]]) ]
-; CHECK-NEXT:    ret void
+; COMMON-LABEL: define {{[^@]+}}@direct3b
+; COMMON-SAME: (ptr [[P:%.*]]) {
+; COMMON-NEXT:    call void @direct3_callee(ptr [[P]]) [ "may-read-and-capture"(ptr [[P]]) ]
+; COMMON-NEXT:    ret void
 ;
   call void @direct3_callee(ptr %p) ["may-read-and-capture"(ptr %p)]
   ret void
 }
 
 define void @direct3c(ptr %p) {
-; CHECK-LABEL: define {{[^@]+}}@direct3c
-; CHECK-SAME: (ptr nocapture [[P:%.*]]) {
-; CHECK-NEXT:    call void @direct3_callee(ptr [[P]]) [ "may-read"() ]
-; CHECK-NEXT:    ret void
+; FNATTRS-LABEL: define {{[^@]+}}@direct3c
+; FNATTRS-SAME: (ptr nocapture [[P:%.*]]) {
+; FNATTRS-NEXT:    call void @direct3_callee(ptr [[P]]) [ "may-read"() ]
+; FNATTRS-NEXT:    ret void
+;
+; ATTRIBUTOR-LABEL: define {{[^@]+}}@direct3c
+; ATTRIBUTOR-SAME: (ptr nocapture [[P:%.*]]) {
+; ATTRIBUTOR-NEXT:    call void @direct3_callee(ptr nocapture [[P]]) [ "may-read"() ]
+; ATTRIBUTOR-NEXT:    ret void
 ;
   call void @direct3_callee(ptr %p) ["may-read"()]
   ret void
 }
 
 define void @fptr_test1(ptr %p, ptr %f) {
-; CHECK-LABEL: define {{[^@]+}}@fptr_test1
-; CHECK-SAME: (ptr [[P:%.*]], ptr nocapture readonly [[F:%.*]]) {
-; CHECK-NEXT:    call void [[F]](ptr [[P]])
-; CHECK-NEXT:    ret void
+; FNATTRS-LABEL: define {{[^@]+}}@fptr_test1
+; FNATTRS-SAME: (ptr [[P:%.*]], ptr nocapture readonly [[F:%.*]]) {
+; FNATTRS-NEXT:    call void [[F]](ptr [[P]])
+; FNATTRS-NEXT:    ret void
+;
+; ATTRIBUTOR-LABEL: define {{[^@]+}}@fptr_test1
+; ATTRIBUTOR-SAME: (ptr [[P:%.*]], ptr nocapture nofree nonnull [[F:%.*]]) {
+; ATTRIBUTOR-NEXT:    call void [[F]](ptr [[P]])
+; ATTRIBUTOR-NEXT:    ret void
 ;
   call void %f(ptr %p)
   ret void
 }
 
 define void @fptr_test2(ptr %p, ptr %f) {
-; CHECK-LABEL: define {{[^@]+}}@fptr_test2
-; CHECK-SAME: (ptr nocapture writeonly [[P:%.*]], ptr nocapture readonly [[F:%.*]]) {
-; CHECK-NEXT:    call void [[F]](ptr nocapture writeonly [[P]])
-; CHECK-NEXT:    ret void
+; FNATTRS-LABEL: define {{[^@]+}}@fptr_test2
+; FNATTRS-SAME: (ptr nocapture writeonly [[P:%.*]], ptr nocapture readonly [[F:%.*]]) {
+; FNATTRS-NEXT:    call void [[F]](ptr nocapture writeonly [[P]])
+; FNATTRS-NEXT:    ret void
+;
+; ATTRIBUTOR-LABEL: define {{[^@]+}}@fptr_test2
+; ATTRIBUTOR-SAME: (ptr nocapture [[P:%.*]], ptr nocapture nofree nonnull [[F:%.*]]) {
+; ATTRIBUTOR-NEXT:    call void [[F]](ptr nocapture writeonly [[P]])
+; ATTRIBUTOR-NEXT:    ret void
 ;
   call void %f(ptr nocapture writeonly %p)
   ret void
 }
 
 define void @fptr_test3(ptr %p, ptr %f) {
-; CHECK: Function Attrs: writeonly
-; CHECK-LABEL: define {{[^@]+}}@fptr_test3
-; CHECK-SAME: (ptr nocapture writeonly [[P:%.*]], ptr nocapture readonly [[F:%.*]]) #[[ATTR8]] {
-; CHECK-NEXT:    call void [[F]](ptr nocapture [[P]]) #[[ATTR8]]
-; CHECK-NEXT:    ret void
+; FNATTRS: Function Attrs: memory(write)
+; FNATTRS-LABEL: define {{[^@]+}}@fptr_test3
+; FNATTRS-SAME: (ptr nocapture [[P:%.*]], ptr nocapture readonly [[F:%.*]]) #[[ATTR8]] {
+; FNATTRS-NEXT:    call void [[F]](ptr nocapture [[P]]) #[[ATTR8]]
+; FNATTRS-NEXT:    ret void
+;
+; ATTRIBUTOR: Function Attrs: memory(write)
+; ATTRIBUTOR-LABEL: define {{[^@]+}}@fptr_test3
+; ATTRIBUTOR-SAME: (ptr nocapture writeonly [[P:%.*]], ptr nocapture nofree nonnull writeonly [[F:%.*]]) #[[ATTR7]] {
+; ATTRIBUTOR-NEXT:    call void [[F]](ptr nocapture [[P]]) #[[ATTR7]]
+; ATTRIBUTOR-NEXT:    ret void
 ;
   call void %f(ptr nocapture %p) writeonly
   ret void