@@ -1,27 +1,30 @@
; RUN: opt < %s -functionattrs -S | FileCheck %s
; RUN: opt < %s -passes=function-attrs -S | FileCheck %s
; RUN: opt -functionattrs -S < %s | FileCheck %s --check-prefixes=FNATTR,EITHER
; RUN: opt -passes=function-attrs -S < %s | FileCheck %s --check-prefixes=FNATTR,EITHER
; RUN: opt -attributor -attributor-manifest-internal -attributor-disable=false -S < %s | FileCheck %s --check-prefixes=ATTRIBUTOR,EITHER
; RUN: opt -passes=attributor -attributor-manifest-internal -attributor-disable=false -S < %s | FileCheck %s --check-prefixes=ATTRIBUTOR,EITHER
@g = global i32* null ; <i32**> [#uses=1]
; CHECK: define i32* @c1(i32* readnone returned %q)
; FNATTR: define i32* @c1(i32* readnone returned %q)
; ATTRIBUTOR: define i32* @c1(i32* returned "no-capture-maybe-returned" %q)
define i32* @c1 (i32* %q ) {
ret i32* %q
}
; CHECK : define void @c2(i32* %q)
; EITHER : 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
}
; CHECK : define void @c3(i32* %q)
; EITHER : define void @c3(i32* %q)
define void @c3 (i32* %q ) {
call void @c2 (i32* %q )
ret void
}
; CHECK : define i1 @c4(i32* %q, i32 %bitno)
; EITHER : define i1 @c4(i32* %q, i32 %bitno)
define i1 @c4 (i32* %q , i32 %bitno ) {
%tmp = ptrtoint i32* %q to i32
%tmp2 = lshr i32 %tmp , %bitno
Expand All
@@ -35,7 +38,7 @@ l1:
@lookup_table = global [2 x i1 ] [ i1 0 , i1 1 ]
; CHECK : define i1 @c5(i32* %q, i32 %bitno)
; EITHER : define i1 @c5(i32* %q, i32 %bitno)
define i1 @c5 (i32* %q , i32 %bitno ) {
%tmp = ptrtoint i32* %q to i32
%tmp2 = lshr i32 %tmp , %bitno
Expand All
@@ -48,7 +51,8 @@ define i1 @c5(i32* %q, i32 %bitno) {
declare void @throw_if_bit_set (i8* , i8 ) readonly
; CHECK: define i1 @c6(i8* readonly %q, i8 %bit)
; FNATTR: define i1 @c6(i8* readonly %q, i8 %bit)
; ATTRIBUTOR: define i1 @c6(i8* %q, i8 %bit)
define i1 @c6 (i8* %q , i8 %bit ) personality i32 (...)* @__gxx_personality_v0 {
invoke void @throw_if_bit_set (i8* %q , i8 %bit )
to label %ret0 unwind label %ret1
Expand All
@@ -70,15 +74,16 @@ define i1* @lookup_bit(i32* %q, i32 %bitno) readnone nounwind {
ret i1* %lookup
}
; CHECK: define i1 @c7(i32* readonly %q, i32 %bitno)
; FNATTR: define i1 @c7(i32* readonly %q, i32 %bitno)
; ATTRIBUTOR: define i1 @c7(i32* %q, i32 %bitno)
define i1 @c7 (i32* %q , i32 %bitno ) {
%ptr = call i1* @lookup_bit (i32* %q , i32 %bitno )
%val = load i1 , i1* %ptr
ret i1 %val
}
; CHECK : define i32 @nc1(i32* %q, i32* nocapture %p, i1 %b)
; EITHER : define i32 @nc1(i32* %q, i32* nocapture %p, i1 %b)
define i32 @nc1 (i32* %q , i32* %p , i1 %b ) {
e:
br label %l
Expand All
@@ -93,7 +98,7 @@ l:
ret i32 %val
}
; CHECK : define i32 @nc1_addrspace(i32* %q, i32 addrspace(1)* nocapture %p, i1 %b)
; EITHER : define i32 @nc1_addrspace(i32* %q, i32 addrspace(1)* nocapture %p, i1 %b)
define i32 @nc1_addrspace (i32* %q , i32 addrspace (1 )* %p , i1 %b ) {
e:
br label %l
Expand All
@@ -108,78 +113,93 @@ l:
ret i32 %val
}
; CHECK : define void @nc2(i32* nocapture %p, i32* %q)
; EITHER : define void @nc2(i32* nocapture %p, i32* %q)
define void @nc2 (i32* %p , i32* %q ) {
%1 = call i32 @nc1 (i32* %q , i32* %p , i1 0 ) ; <i32> [#uses=0]
ret void
}
; CHECK : define void @nc3(void ()* nocapture %p)
; EITHER : define void @nc3(void ()* nocapture %p)
define void @nc3 (void ()* %p ) {
call void %p ()
ret void
}
declare void @external (i8* ) readonly nounwind
; CHECK: define void @nc4(i8* nocapture readonly %p)
; FNATTR: define void @nc4(i8* nocapture readonly %p)
; ATTRIBUTOR: define void @nc4(i8* nocapture %p)
define void @nc4 (i8* %p ) {
call void @external (i8* %p )
ret void
}
; CHECK : define void @nc5(void (i8*)* nocapture %f, i8* nocapture %p)
; EITHER : define void @nc5(void (i8*)* nocapture %f, i8* nocapture %p)
define void @nc5 (void (i8* )* %f , i8* %p ) {
call void %f (i8* %p ) readonly nounwind
call void %f (i8* nocapture %p )
ret void
}
; CHECK: define void @test1_1(i8* nocapture readnone %x1_1, i8* %y1_1)
; FNATTR: define void @test1_1(i8* nocapture readnone %x1_1, i8* %y1_1, i1 %c)
; ATTRIBUTOR: define void @test1_1(i8* nocapture %x1_1, i8* nocapture %y1_1, i1 %c)
; 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 )
define void @test1_1 (i8* %x1_1 , i8* %y1_1 , i1 %c ) {
call i8* @test1_2 (i8* %x1_1 , i8* %y1_1 , i1 %c )
store i32* null , i32** @g
ret void
}
; CHECK: define i8* @test1_2(i8* nocapture readnone %x1_2, i8* returned %y1_2)
define i8* @test1_2 (i8* %x1_2 , i8* %y1_2 ) {
call void @test1_1 (i8* %x1_2 , i8* %y1_2 )
; FNATTR: define i8* @test1_2(i8* nocapture readnone %x1_2, i8* returned %y1_2, i1 %c)
; ATTRIBUTOR: define i8* @test1_2(i8* nocapture %x1_2, i8* returned "no-capture-maybe-returned" %y1_2, i1 %c)
define i8* @test1_2 (i8* %x1_2 , i8* %y1_2 , i1 %c ) {
br i1 %c , label %t , label %f
t:
call void @test1_1 (i8* %x1_2 , i8* %y1_2 , i1 %c )
store i32* null , i32** @g
br label %f
f:
ret i8* %y1_2
}
; CHECK: define void @test2(i8* nocapture readnone %x2)
; FNATTR: define void @test2(i8* nocapture readnone %x2)
; ATTRIBUTOR: define void @test2(i8* nocapture %x2)
define void @test2 (i8* %x2 ) {
call void @test2 (i8* %x2 )
store i32* null , i32** @g
ret void
}
; CHECK: define void @test3(i8* nocapture readnone %x3, i8* nocapture readnone %y3, i8* nocapture readnone %z3)
; FNATTR: define void @test3(i8* nocapture readnone %x3, i8* nocapture readnone %y3, i8* nocapture readnone %z3)
; ATTRIBUTOR: define void @test3(i8* nocapture %x3, i8* nocapture %y3, i8* nocapture %z3)
define void @test3 (i8* %x3 , i8* %y3 , i8* %z3 ) {
call void @test3 (i8* %z3 , i8* %y3 , i8* %x3 )
store i32* null , i32** @g
ret void
}
; CHECK: define void @test4_1(i8* %x4_1)
define void @test4_1 (i8* %x4_1 ) {
call i8* @test4_2 (i8* %x4_1 , i8* %x4_1 , i8* %x4_1 )
; FNATTR: define void @test4_1(i8* %x4_1, i1 %c)
; ATTRIBUTOR: define void @test4_1(i8* nocapture %x4_1, i1 %c)
define void @test4_1 (i8* %x4_1 , i1 %c ) {
call i8* @test4_2 (i8* %x4_1 , i8* %x4_1 , i8* %x4_1 , i1 %c )
store i32* null , i32** @g
ret void
}
; CHECK: define i8* @test4_2(i8* nocapture readnone %x4_2, i8* readnone returned %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 )
; FNATTR: define i8* @test4_2(i8* nocapture readnone %x4_2, i8* readnone returned %y4_2, i8* nocapture readnone %z4_2, i1 %c)
; ATTRIBUTOR: define i8* @test4_2(i8* nocapture %x4_2, i8* returned "no-capture-maybe-returned" %y4_2, i8* nocapture %z4_2, i1 %c)
define i8* @test4_2 (i8* %x4_2 , i8* %y4_2 , i8* %z4_2 , i1 %c ) {
br i1 %c , label %t , label %f
t:
call void @test4_1 (i8* null , i1 %c )
store i32* null , i32** @g
br label %f
f:
ret i8* %y4_2
}
declare i8* @test5_1 (i8* %x5_1 )
; CHECK : define void @test5_2(i8* %x5_2)
; EITHER : define void @test5_2(i8* %x5_2)
define void @test5_2 (i8* %x5_2 ) {
call i8* @test5_1 (i8* %x5_2 )
store i32* null , i32** @g
Expand All
@@ -188,40 +208,40 @@ define void @test5_2(i8* %x5_2) {
declare void @test6_1 (i8* %x6_1 , i8* nocapture %y6_1 , ...)
; CHECK : define void @test6_2(i8* %x6_2, i8* nocapture %y6_2, i8* %z6_2)
; EITHER : define void @test6_2(i8* %x6_2, i8* nocapture %y6_2, i8* %z6_2)
define void @test6_2 (i8* %x6_2 , i8* %y6_2 , i8* %z6_2 ) {
call void (i8* , i8* , ...) @test6_1 (i8* %x6_2 , i8* %y6_2 , i8* %z6_2 )
store i32* null , i32** @g
ret void
}
; CHECK : define void @test_cmpxchg(i32* nocapture %p)
; EITHER : define void @test_cmpxchg(i32* nocapture %p)
define void @test_cmpxchg (i32* %p ) {
cmpxchg i32* %p , i32 0 , i32 1 acquire monotonic
ret void
}
; CHECK : define void @test_cmpxchg_ptr(i32** nocapture %p, i32* %q)
; EITHER : define void @test_cmpxchg_ptr(i32** nocapture %p, i32* %q)
define void @test_cmpxchg_ptr (i32** %p , i32* %q ) {
cmpxchg i32** %p , i32* null , i32* %q acquire monotonic
ret void
}
; CHECK : define void @test_atomicrmw(i32* nocapture %p)
; EITHER : define void @test_atomicrmw(i32* nocapture %p)
define void @test_atomicrmw (i32* %p ) {
atomicrmw add i32* %p , i32 1 seq_cst
ret void
}
; CHECK : define void @test_volatile(i32* %x)
; EITHER : define void @test_volatile(i32* %x)
define void @test_volatile (i32* %x ) {
entry:
%gep = getelementptr i32 , i32* %x , i64 1
store volatile i32 0 , i32* %gep , align 4
ret void
}
; CHECK : nocaptureLaunder(i8* nocapture %p)
; EITHER : nocaptureLaunder(i8* nocapture %p)
define void @nocaptureLaunder (i8* %p ) {
entry:
%b = call i8* @llvm.launder.invariant.group.p0i8 (i8* %p )
Expand All
@@ -230,14 +250,14 @@ entry:
}
@g2 = global i8* null
; CHECK : define void @captureLaunder(i8* %p)
; EITHER : define void @captureLaunder(i8* %p)
define void @captureLaunder (i8* %p ) {
%b = call i8* @llvm.launder.invariant.group.p0i8 (i8* %p )
store i8* %b , i8** @g2
ret void
}
; CHECK : @nocaptureStrip(i8* nocapture %p)
; EITHER : @nocaptureStrip(i8* nocapture %p)
define void @nocaptureStrip (i8* %p ) {
entry:
%b = call i8* @llvm.strip.invariant.group.p0i8 (i8* %p )
Expand All
@@ -246,49 +266,55 @@ entry:
}
@g3 = global i8* null
; CHECK : define void @captureStrip(i8* %p)
; EITHER : define void @captureStrip(i8* %p)
define void @captureStrip (i8* %p ) {
%b = call i8* @llvm.strip.invariant.group.p0i8 (i8* %p )
store i8* %b , i8** @g3
ret void
}
; CHECK: define i1 @captureICmp(i32* readnone %x)
; FNATTR: define i1 @captureICmp(i32* readnone %x)
; ATTRIBUTOR: define i1 @captureICmp(i32* %x)
define i1 @captureICmp (i32* %x ) {
%1 = icmp eq i32* %x , null
ret i1 %1
}
; CHECK: define i1 @captureICmpRev(i32* readnone %x)
; FNATTR: define i1 @captureICmpRev(i32* readnone %x)
; ATTRIBUTOR: define i1 @captureICmpRev(i32* %x)
define i1 @captureICmpRev (i32* %x ) {
%1 = icmp eq i32* null , %x
ret i1 %1
}
; CHECK: define i1 @nocaptureInboundsGEPICmp(i32* nocapture readnone %x)
; FNATTR: define i1 @nocaptureInboundsGEPICmp(i32* nocapture readnone %x)
; ATTRIBUTOR: define i1 @nocaptureInboundsGEPICmp(i32* nocapture %x)
define i1 @nocaptureInboundsGEPICmp (i32* %x ) {
%1 = getelementptr inbounds i32 , i32* %x , i32 5
%2 = bitcast i32* %1 to i8*
%3 = icmp eq i8* %2 , null
ret i1 %3
}
; CHECK: define i1 @nocaptureInboundsGEPICmpRev(i32* nocapture readnone %x)
; FNATTR: define i1 @nocaptureInboundsGEPICmpRev(i32* nocapture readnone %x)
; ATTRIBUTOR: define i1 @nocaptureInboundsGEPICmpRev(i32* nocapture %x)
define i1 @nocaptureInboundsGEPICmpRev (i32* %x ) {
%1 = getelementptr inbounds i32 , i32* %x , i32 5
%2 = bitcast i32* %1 to i8*
%3 = icmp eq i8* null , %2
ret i1 %3
}
; CHECK: define i1 @nocaptureDereferenceableOrNullICmp(i32* nocapture readnone dereferenceable_or_null(4) %x)
; FNATTR: define i1 @nocaptureDereferenceableOrNullICmp(i32* nocapture readnone dereferenceable_or_null(4) %x)
; ATTRIBUTOR: define i1 @nocaptureDereferenceableOrNullICmp(i32* nocapture dereferenceable_or_null(4) %x)
define i1 @nocaptureDereferenceableOrNullICmp (i32* dereferenceable_or_null (4 ) %x ) {
%1 = bitcast i32* %x to i8*
%2 = icmp eq i8* %1 , null
ret i1 %2
}
; CHECK: define i1 @captureDereferenceableOrNullICmp(i32* readnone dereferenceable_or_null(4) %x)
; FNATTR: define i1 @captureDereferenceableOrNullICmp(i32* readnone dereferenceable_or_null(4) %x)
; ATTRIBUTOR: define i1 @captureDereferenceableOrNullICmp(i32* dereferenceable_or_null(4) %x)
define i1 @captureDereferenceableOrNullICmp (i32* dereferenceable_or_null (4 ) %x ) "null-pointer-is-valid" ="true" {
%1 = bitcast i32* %x to i8*
%2 = icmp eq i8* %1 , null
Expand Down