You've already forked linux-packaging-mono
Imported Upstream version 5.18.0.167
Former-commit-id: 289509151e0fee68a1b591a20c9f109c3c789d3a
This commit is contained in:
parent
e19d552987
commit
b084638f15
@ -1,11 +0,0 @@
|
||||
; RUN: opt < %s -functionattrs -S | grep readnone
|
||||
|
||||
define i32 @a() {
|
||||
%tmp = call i32 @b( ) ; <i32> [#uses=1]
|
||||
ret i32 %tmp
|
||||
}
|
||||
|
||||
define i32 @b() {
|
||||
%tmp = call i32 @a( ) ; <i32> [#uses=1]
|
||||
ret i32 %tmp
|
||||
}
|
@ -1,25 +0,0 @@
|
||||
; RUN: opt < %s -basicaa -functionattrs -S | FileCheck %s
|
||||
@x = global i32 0
|
||||
|
||||
; CHECK: declare i32 @e() #0
|
||||
declare i32 @e() readnone
|
||||
|
||||
; CHECK: define i32 @f() #0
|
||||
define i32 @f() {
|
||||
%tmp = call i32 @e( ) ; <i32> [#uses=1]
|
||||
ret i32 %tmp
|
||||
}
|
||||
|
||||
; CHECK: define i32 @g() #1
|
||||
define i32 @g() readonly {
|
||||
ret i32 0
|
||||
}
|
||||
|
||||
; CHECK: define i32 @h() #1
|
||||
define i32 @h() readnone {
|
||||
%tmp = load i32, i32* @x ; <i32> [#uses=1]
|
||||
ret i32 %tmp
|
||||
}
|
||||
|
||||
; CHECK: attributes #0 = { readnone }
|
||||
; CHECK: attributes #1 = { norecurse readnone }
|
@ -1,13 +0,0 @@
|
||||
; RUN: opt < %s -basicaa -functionattrs -S | FileCheck %s
|
||||
|
||||
; CHECK: define i32 @f() #0
|
||||
define i32 @f() {
|
||||
entry:
|
||||
%tmp = call i32 @e( )
|
||||
ret i32 %tmp
|
||||
}
|
||||
|
||||
; CHECK: declare i32 @e() #0
|
||||
declare i32 @e() readonly
|
||||
|
||||
; CHECK: attributes #0 = { readonly }
|
@ -1,9 +0,0 @@
|
||||
; RUN: opt < %s -functionattrs -S | not grep read
|
||||
; PR2792
|
||||
|
||||
@g = global i32 0 ; <i32*> [#uses=1]
|
||||
|
||||
define i32 @f() {
|
||||
%t = load volatile i32, i32* @g ; <i32> [#uses=1]
|
||||
ret i32 %t
|
||||
}
|
@ -1,8 +0,0 @@
|
||||
; RUN: opt < %s -basicaa -functionattrs -S | grep readnone
|
||||
|
||||
@s = external constant i8 ; <i8*> [#uses=1]
|
||||
|
||||
define i8 @f() {
|
||||
%tmp = load i8, i8* @s ; <i8> [#uses=1]
|
||||
ret i8 %tmp
|
||||
}
|
@ -1,23 +0,0 @@
|
||||
; RUN: opt < %s -functionattrs -S | FileCheck %s
|
||||
|
||||
; CHECK: define i32* @a(i32** nocapture readonly %p)
|
||||
define i32* @a(i32** %p) {
|
||||
%tmp = load i32*, 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 returned %r)
|
||||
@g = global i32 0
|
||||
define i32* @c(i32 *%r) {
|
||||
%a = icmp eq i32* %r, null
|
||||
store i32 1, i32* @g
|
||||
ret i32* %r
|
||||
}
|
@ -1,12 +0,0 @@
|
||||
; RUN: opt < %s -functionattrs -S | FileCheck %s
|
||||
; PR8279
|
||||
|
||||
@g = constant i32 1
|
||||
|
||||
define void @foo() {
|
||||
; CHECK: void @foo() #0 {
|
||||
%tmp = load volatile i32, i32* @g
|
||||
ret void
|
||||
}
|
||||
|
||||
; CHECK: attributes #0 = { norecurse }
|
@ -1,4 +0,0 @@
|
||||
; RUN: opt -S -o - -functionattrs %s | FileCheck %s
|
||||
|
||||
; CHECK-NOT: readnone
|
||||
declare void @llvm.assume(i1)
|
@ -1,23 +0,0 @@
|
||||
; RUN: opt -basicaa -functionattrs -S < %s | FileCheck %s
|
||||
|
||||
; Atomic load/store to local doesn't affect whether a function is
|
||||
; readnone/readonly.
|
||||
define i32 @test1(i32 %x) uwtable ssp {
|
||||
; CHECK: define i32 @test1(i32 %x) #0 {
|
||||
entry:
|
||||
%x.addr = alloca i32, align 4
|
||||
store atomic i32 %x, i32* %x.addr seq_cst, align 4
|
||||
%r = load atomic i32, i32* %x.addr seq_cst, align 4
|
||||
ret i32 %r
|
||||
}
|
||||
|
||||
; A function with an Acquire load is not readonly.
|
||||
define i32 @test2(i32* %x) uwtable ssp {
|
||||
; CHECK: define i32 @test2(i32* nocapture readonly %x) #1 {
|
||||
entry:
|
||||
%r = load atomic i32, i32* %x seq_cst, align 4
|
||||
ret i32 %r
|
||||
}
|
||||
|
||||
; CHECK: attributes #0 = { norecurse readnone ssp uwtable }
|
||||
; CHECK: attributes #1 = { norecurse ssp uwtable }
|
@ -1,16 +0,0 @@
|
||||
; RUN: opt < %s -functionattrs -S | FileCheck %s
|
||||
|
||||
; See PR26774
|
||||
|
||||
; CHECK-LABEL: define void @bar(i8* readonly) {
|
||||
define void @bar(i8* readonly) {
|
||||
call void @foo(i8* %0)
|
||||
ret void
|
||||
}
|
||||
|
||||
|
||||
; CHECK-LABEL: define linkonce_odr void @foo(i8* readonly) {
|
||||
define linkonce_odr void @foo(i8* readonly) {
|
||||
call void @bar(i8* %0)
|
||||
ret void
|
||||
}
|
@ -1,106 +0,0 @@
|
||||
; RUN: opt -functionattrs -S < %s | FileCheck %s
|
||||
|
||||
; CHECK: Function Attrs
|
||||
; CHECK-NOT: convergent
|
||||
; CHECK-NEXT: define i32 @nonleaf()
|
||||
define i32 @nonleaf() convergent {
|
||||
%a = call i32 @leaf()
|
||||
ret i32 %a
|
||||
}
|
||||
|
||||
; CHECK: Function Attrs
|
||||
; CHECK-NOT: convergent
|
||||
; CHECK-NEXT: define i32 @leaf()
|
||||
define i32 @leaf() convergent {
|
||||
ret i32 0
|
||||
}
|
||||
|
||||
; CHECK: Function Attrs
|
||||
; CHECK-SAME: convergent
|
||||
; CHECK-NEXT: declare i32 @k()
|
||||
declare i32 @k() convergent
|
||||
|
||||
; CHECK: Function Attrs
|
||||
; CHECK-SAME: convergent
|
||||
; CHECK-NEXT: define i32 @extern()
|
||||
define i32 @extern() convergent {
|
||||
%a = call i32 @k() convergent
|
||||
ret i32 %a
|
||||
}
|
||||
|
||||
; Convergent should not be removed on the function here. Although the call is
|
||||
; not explicitly convergent, it picks up the convergent attr from the callee.
|
||||
;
|
||||
; CHECK: Function Attrs
|
||||
; CHECK-SAME: convergent
|
||||
; CHECK-NEXT: define i32 @extern_non_convergent_call()
|
||||
define i32 @extern_non_convergent_call() convergent {
|
||||
%a = call i32 @k()
|
||||
ret i32 %a
|
||||
}
|
||||
|
||||
; CHECK: Function Attrs
|
||||
; CHECK-SAME: convergent
|
||||
; CHECK-NEXT: define i32 @indirect_convergent_call(
|
||||
define i32 @indirect_convergent_call(i32 ()* %f) convergent {
|
||||
%a = call i32 %f() convergent
|
||||
ret i32 %a
|
||||
}
|
||||
; Give indirect_non_convergent_call the norecurse attribute so we get a
|
||||
; "Function Attrs" comment in the output.
|
||||
;
|
||||
; CHECK: Function Attrs
|
||||
; CHECK-NOT: convergent
|
||||
; CHECK-NEXT: define i32 @indirect_non_convergent_call(
|
||||
define i32 @indirect_non_convergent_call(i32 ()* %f) convergent norecurse {
|
||||
%a = call i32 %f()
|
||||
ret i32 %a
|
||||
}
|
||||
|
||||
; CHECK: Function Attrs
|
||||
; CHECK-SAME: convergent
|
||||
; CHECK-NEXT: declare void @llvm.nvvm.barrier0()
|
||||
declare void @llvm.nvvm.barrier0() convergent
|
||||
|
||||
; CHECK: Function Attrs
|
||||
; CHECK-SAME: convergent
|
||||
; CHECK-NEXT: define i32 @intrinsic()
|
||||
define i32 @intrinsic() convergent {
|
||||
; Implicitly convergent, because the intrinsic is convergent.
|
||||
call void @llvm.nvvm.barrier0()
|
||||
ret i32 0
|
||||
}
|
||||
|
||||
; CHECK: Function Attrs
|
||||
; CHECK-NOT: convergent
|
||||
; CHECK-NEXT: define i32 @recursive1()
|
||||
define i32 @recursive1() convergent {
|
||||
%a = call i32 @recursive2() convergent
|
||||
ret i32 %a
|
||||
}
|
||||
|
||||
; CHECK: Function Attrs
|
||||
; CHECK-NOT: convergent
|
||||
; CHECK-NEXT: define i32 @recursive2()
|
||||
define i32 @recursive2() convergent {
|
||||
%a = call i32 @recursive1() convergent
|
||||
ret i32 %a
|
||||
}
|
||||
|
||||
; CHECK: Function Attrs
|
||||
; CHECK-SAME: convergent
|
||||
; CHECK-NEXT: define i32 @noopt()
|
||||
define i32 @noopt() convergent optnone noinline {
|
||||
%a = call i32 @noopt_friend() convergent
|
||||
ret i32 0
|
||||
}
|
||||
|
||||
; A function which is mutually-recursive with a convergent, optnone function
|
||||
; shouldn't have its convergent attribute stripped.
|
||||
; CHECK: Function Attrs
|
||||
; CHECK-SAME: convergent
|
||||
; CHECK-NEXT: define i32 @noopt_friend()
|
||||
define i32 @noopt_friend() convergent {
|
||||
%a = call i32 @noopt()
|
||||
ret i32 0
|
||||
}
|
@ -1,21 +0,0 @@
|
||||
; RUN: opt -S < %s -functionattrs | FileCheck %s
|
||||
|
||||
declare void @llvm.sideeffect()
|
||||
|
||||
; Don't add readnone or similar attributes when an @llvm.sideeffect() intrinsic
|
||||
; is present.
|
||||
|
||||
; CHECK: define void @test() {
|
||||
define void @test() {
|
||||
call void @llvm.sideeffect()
|
||||
ret void
|
||||
}
|
||||
|
||||
; CHECK: define void @loop() {
|
||||
define void @loop() {
|
||||
br label %loop
|
||||
|
||||
loop:
|
||||
call void @llvm.sideeffect()
|
||||
br label %loop
|
||||
}
|
@ -1,220 +0,0 @@
|
||||
; RUN: opt < %s -functionattrs -S | FileCheck %s
|
||||
@g = global i32* null ; <i32**> [#uses=1]
|
||||
|
||||
; CHECK: define i32* @c1(i32* readnone returned %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
|
||||
}
|
||||
|
||||
; CHECK: 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)
|
||||
define i1 @c4(i32* %q, i32 %bitno) {
|
||||
%tmp = ptrtoint i32* %q to i32
|
||||
%tmp2 = lshr i32 %tmp, %bitno
|
||||
%bit = trunc i32 %tmp2 to i1
|
||||
br i1 %bit, label %l1, label %l0
|
||||
l0:
|
||||
ret i1 0 ; escaping value not caught by def-use chaining.
|
||||
l1:
|
||||
ret i1 1 ; escaping value not caught by def-use chaining.
|
||||
}
|
||||
|
||||
@lookup_table = global [2 x i1] [ i1 0, i1 1 ]
|
||||
|
||||
; CHECK: 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
|
||||
%bit = and i32 %tmp2, 1
|
||||
; subtle escape mechanism follows
|
||||
%lookup = getelementptr [2 x i1], [2 x i1]* @lookup_table, i32 0, i32 %bit
|
||||
%val = load i1, i1* %lookup
|
||||
ret i1 %val
|
||||
}
|
||||
|
||||
declare void @throw_if_bit_set(i8*, i8) readonly
|
||||
|
||||
; CHECK: define i1 @c6(i8* readonly %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
|
||||
ret0:
|
||||
ret i1 0
|
||||
ret1:
|
||||
%exn = landingpad {i8*, i32}
|
||||
cleanup
|
||||
ret i1 1
|
||||
}
|
||||
|
||||
declare i32 @__gxx_personality_v0(...)
|
||||
|
||||
define i1* @lookup_bit(i32* %q, i32 %bitno) readnone nounwind {
|
||||
%tmp = ptrtoint i32* %q to i32
|
||||
%tmp2 = lshr i32 %tmp, %bitno
|
||||
%bit = and i32 %tmp2, 1
|
||||
%lookup = getelementptr [2 x i1], [2 x i1]* @lookup_table, i32 0, i32 %bit
|
||||
ret i1* %lookup
|
||||
}
|
||||
|
||||
; CHECK: define i1 @c7(i32* readonly %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)
|
||||
define i32 @nc1(i32* %q, i32* %p, i1 %b) {
|
||||
e:
|
||||
br label %l
|
||||
l:
|
||||
%x = phi i32* [ %p, %e ]
|
||||
%y = phi i32* [ %q, %e ]
|
||||
%tmp = bitcast i32* %x to i32* ; <i32*> [#uses=2]
|
||||
%tmp2 = select i1 %b, i32* %tmp, i32* %y
|
||||
%val = load i32, i32* %tmp2 ; <i32> [#uses=1]
|
||||
store i32 0, i32* %tmp
|
||||
store i32* %y, i32** @g
|
||||
ret i32 %val
|
||||
}
|
||||
|
||||
; CHECK: 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
|
||||
l:
|
||||
%x = phi i32 addrspace(1)* [ %p, %e ]
|
||||
%y = phi i32* [ %q, %e ]
|
||||
%tmp = addrspacecast i32 addrspace(1)* %x to i32* ; <i32*> [#uses=2]
|
||||
%tmp2 = select i1 %b, i32* %tmp, i32* %y
|
||||
%val = load i32, i32* %tmp2 ; <i32> [#uses=1]
|
||||
store i32 0, i32* %tmp
|
||||
store i32* %y, i32** @g
|
||||
ret i32 %val
|
||||
}
|
||||
|
||||
; CHECK: 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)
|
||||
define void @nc3(void ()* %p) {
|
||||
call void %p()
|
||||
ret void
|
||||
}
|
||||
|
||||
declare void @external(i8*) readonly nounwind
|
||||
; CHECK: define void @nc4(i8* nocapture readonly %p)
|
||||
define void @nc4(i8* %p) {
|
||||
call void @external(i8* %p)
|
||||
ret void
|
||||
}
|
||||
|
||||
; CHECK: 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)
|
||||
; 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 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)
|
||||
store i32* null, i32** @g
|
||||
ret i8* %y1_2
|
||||
}
|
||||
|
||||
; 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 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
|
||||
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)
|
||||
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)
|
||||
store i32* null, i32** @g
|
||||
ret i8* %y4_2
|
||||
}
|
||||
|
||||
declare i8* @test5_1(i8* %x5_1)
|
||||
|
||||
; CHECK: 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
|
||||
ret void
|
||||
}
|
||||
|
||||
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)
|
||||
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)
|
||||
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)
|
||||
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)
|
||||
define void @test_atomicrmw(i32* %p) {
|
||||
atomicrmw add i32* %p, i32 1 seq_cst
|
||||
ret void
|
||||
}
|
||||
|
||||
; CHECK: 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
|
||||
}
|
@ -1,10 +0,0 @@
|
||||
; RUN: opt -S -functionattrs %s | FileCheck %s
|
||||
|
||||
@a = external global i8, !absolute_symbol !0
|
||||
|
||||
; CHECK-NOT: define nonnull
|
||||
define i8* @foo() {
|
||||
ret i8* @a
|
||||
}
|
||||
|
||||
!0 = !{i64 0, i64 256}
|
@ -1,229 +0,0 @@
|
||||
; RUN: opt -S -functionattrs -enable-nonnull-arg-prop %s | FileCheck %s
|
||||
declare nonnull i8* @ret_nonnull()
|
||||
|
||||
; Return a pointer trivially nonnull (call return attribute)
|
||||
define i8* @test1() {
|
||||
; CHECK: define nonnull i8* @test1
|
||||
%ret = call i8* @ret_nonnull()
|
||||
ret i8* %ret
|
||||
}
|
||||
|
||||
; Return a pointer trivially nonnull (argument attribute)
|
||||
define i8* @test2(i8* nonnull %p) {
|
||||
; CHECK: define nonnull i8* @test2
|
||||
ret i8* %p
|
||||
}
|
||||
|
||||
; Given an SCC where one of the functions can not be marked nonnull,
|
||||
; can we still mark the other one which is trivially nonnull
|
||||
define i8* @scc_binder() {
|
||||
; CHECK: define i8* @scc_binder
|
||||
call i8* @test3()
|
||||
ret i8* null
|
||||
}
|
||||
|
||||
define i8* @test3() {
|
||||
; CHECK: define nonnull i8* @test3
|
||||
call i8* @scc_binder()
|
||||
%ret = call i8* @ret_nonnull()
|
||||
ret i8* %ret
|
||||
}
|
||||
|
||||
; Given a mutual recursive set of functions, we can mark them
|
||||
; nonnull if neither can ever return null. (In this case, they
|
||||
; just never return period.)
|
||||
define i8* @test4_helper() {
|
||||
; CHECK: define noalias nonnull i8* @test4_helper
|
||||
%ret = call i8* @test4()
|
||||
ret i8* %ret
|
||||
}
|
||||
|
||||
define i8* @test4() {
|
||||
; CHECK: define noalias nonnull i8* @test4
|
||||
%ret = call i8* @test4_helper()
|
||||
ret i8* %ret
|
||||
}
|
||||
|
||||
; Given a mutual recursive set of functions which *can* return null
|
||||
; make sure we haven't marked them as nonnull.
|
||||
define i8* @test5_helper() {
|
||||
; CHECK: define noalias i8* @test5_helper
|
||||
%ret = call i8* @test5()
|
||||
ret i8* null
|
||||
}
|
||||
|
||||
define i8* @test5() {
|
||||
; CHECK: define noalias i8* @test5
|
||||
%ret = call i8* @test5_helper()
|
||||
ret i8* %ret
|
||||
}
|
||||
|
||||
; Local analysis, but going through a self recursive phi
|
||||
define i8* @test6() {
|
||||
entry:
|
||||
; CHECK: define nonnull i8* @test6
|
||||
%ret = call i8* @ret_nonnull()
|
||||
br label %loop
|
||||
loop:
|
||||
%phi = phi i8* [%ret, %entry], [%phi, %loop]
|
||||
br i1 undef, label %loop, label %exit
|
||||
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
|
||||
}
|
||||
|
||||
; CHECK: define nonnull i32* @gep1(
|
||||
define i32* @gep1(i32* %p) {
|
||||
%q = getelementptr inbounds i32, i32* %p, i32 1
|
||||
ret i32* %q
|
||||
}
|
||||
|
||||
; CHECK: define i32 addrspace(3)* @gep2(
|
||||
define i32 addrspace(3)* @gep2(i32 addrspace(3)* %p) {
|
||||
%q = getelementptr inbounds i32, i32 addrspace(3)* %p, i32 1
|
||||
ret i32 addrspace(3)* %q
|
||||
}
|
@ -1,65 +0,0 @@
|
||||
; RUN: opt < %s -basicaa -functionattrs -rpo-functionattrs -S | FileCheck %s
|
||||
; RUN: opt < %s -aa-pipeline=basic-aa -passes='cgscc(function-attrs),rpo-functionattrs' -S | FileCheck %s
|
||||
|
||||
; CHECK: define i32 @leaf() #0
|
||||
define i32 @leaf() {
|
||||
ret i32 1
|
||||
}
|
||||
|
||||
; CHECK: define i32 @self_rec() #1
|
||||
define i32 @self_rec() {
|
||||
%a = call i32 @self_rec()
|
||||
ret i32 4
|
||||
}
|
||||
|
||||
; CHECK: define i32 @indirect_rec() #1
|
||||
define i32 @indirect_rec() {
|
||||
%a = call i32 @indirect_rec2()
|
||||
ret i32 %a
|
||||
}
|
||||
; CHECK: define i32 @indirect_rec2() #1
|
||||
define i32 @indirect_rec2() {
|
||||
%a = call i32 @indirect_rec()
|
||||
ret i32 %a
|
||||
}
|
||||
|
||||
; CHECK: define i32 @extern() #1
|
||||
define i32 @extern() {
|
||||
%a = call i32 @k()
|
||||
ret i32 %a
|
||||
}
|
||||
declare i32 @k() readnone
|
||||
|
||||
; CHECK: define void @intrinsic(i8* nocapture %dest, i8* nocapture readonly %src, i32 %len) {
|
||||
define void @intrinsic(i8* %dest, i8* %src, i32 %len) {
|
||||
call void @llvm.memcpy.p0i8.p0i8.i32(i8* %dest, i8* %src, i32 %len, i32 1, i1 false)
|
||||
ret void
|
||||
}
|
||||
declare void @llvm.memcpy.p0i8.p0i8.i32(i8*, i8*, i32, i32, i1)
|
||||
|
||||
; CHECK: define internal i32 @called_by_norecurse() #0
|
||||
define internal i32 @called_by_norecurse() {
|
||||
%a = call i32 @k()
|
||||
ret i32 %a
|
||||
}
|
||||
define void @m() norecurse {
|
||||
%a = call i32 @called_by_norecurse()
|
||||
ret void
|
||||
}
|
||||
|
||||
; CHECK: define internal i32 @called_by_norecurse_indirectly() #0
|
||||
define internal i32 @called_by_norecurse_indirectly() {
|
||||
%a = call i32 @k()
|
||||
ret i32 %a
|
||||
}
|
||||
define internal void @o() {
|
||||
%a = call i32 @called_by_norecurse_indirectly()
|
||||
ret void
|
||||
}
|
||||
define void @p() norecurse {
|
||||
call void @o()
|
||||
ret void
|
||||
}
|
||||
|
||||
; CHECK: attributes #0 = { norecurse readnone }
|
||||
; CHECK: attributes #1 = { readnone }
|
@ -1,13 +0,0 @@
|
||||
; RUN: opt -S -functionattrs < %s | FileCheck %s
|
||||
|
||||
define void @f() {
|
||||
; CHECK-LABEL: define void @f() {
|
||||
call void @g() [ "unknown"() ]
|
||||
ret void
|
||||
}
|
||||
|
||||
define void @g() {
|
||||
; CHECK-LABEL: define void @g() {
|
||||
call void @f()
|
||||
ret void
|
||||
}
|
@ -1,135 +0,0 @@
|
||||
; RUN: opt -O3 -S < %s | FileCheck %s
|
||||
; Show 'optnone' suppresses optimizations.
|
||||
|
||||
; Two attribute groups that differ only by 'optnone'.
|
||||
; 'optnone' requires 'noinline' so #0 is 'noinline' by itself,
|
||||
; even though it would otherwise be irrelevant to this example.
|
||||
attributes #0 = { noinline }
|
||||
attributes #1 = { noinline optnone }
|
||||
|
||||
; int iadd(int a, int b){ return a + b; }
|
||||
|
||||
define i32 @iadd_optimize(i32 %a, i32 %b) #0 {
|
||||
entry:
|
||||
%a.addr = alloca i32, align 4
|
||||
%b.addr = alloca i32, align 4
|
||||
store i32 %a, i32* %a.addr, align 4
|
||||
store i32 %b, i32* %b.addr, align 4
|
||||
%0 = load i32, i32* %a.addr, align 4
|
||||
%1 = load i32, i32* %b.addr, align 4
|
||||
%add = add nsw i32 %0, %1
|
||||
ret i32 %add
|
||||
}
|
||||
|
||||
; CHECK-LABEL: @iadd_optimize
|
||||
; CHECK-NOT: alloca
|
||||
; CHECK-NOT: store
|
||||
; CHECK-NOT: load
|
||||
; CHECK: ret
|
||||
|
||||
define i32 @iadd_optnone(i32 %a, i32 %b) #1 {
|
||||
entry:
|
||||
%a.addr = alloca i32, align 4
|
||||
%b.addr = alloca i32, align 4
|
||||
store i32 %a, i32* %a.addr, align 4
|
||||
store i32 %b, i32* %b.addr, align 4
|
||||
%0 = load i32, i32* %a.addr, align 4
|
||||
%1 = load i32, i32* %b.addr, align 4
|
||||
%add = add nsw i32 %0, %1
|
||||
ret i32 %add
|
||||
}
|
||||
|
||||
; CHECK-LABEL: @iadd_optnone
|
||||
; CHECK: alloca i32
|
||||
; CHECK: alloca i32
|
||||
; CHECK: store i32
|
||||
; CHECK: store i32
|
||||
; CHECK: load i32
|
||||
; CHECK: load i32
|
||||
; CHECK: add nsw i32
|
||||
; CHECK: ret i32
|
||||
|
||||
; float fsub(float a, float b){ return a - b; }
|
||||
|
||||
define float @fsub_optimize(float %a, float %b) #0 {
|
||||
entry:
|
||||
%a.addr = alloca float, align 4
|
||||
%b.addr = alloca float, align 4
|
||||
store float %a, float* %a.addr, align 4
|
||||
store float %b, float* %b.addr, align 4
|
||||
%0 = load float, float* %a.addr, align 4
|
||||
%1 = load float, float* %b.addr, align 4
|
||||
%sub = fsub float %0, %1
|
||||
ret float %sub
|
||||
}
|
||||
|
||||
; CHECK-LABEL: @fsub_optimize
|
||||
; CHECK-NOT: alloca
|
||||
; CHECK-NOT: store
|
||||
; CHECK-NOT: load
|
||||
; CHECK: ret
|
||||
|
||||
define float @fsub_optnone(float %a, float %b) #1 {
|
||||
entry:
|
||||
%a.addr = alloca float, align 4
|
||||
%b.addr = alloca float, align 4
|
||||
store float %a, float* %a.addr, align 4
|
||||
store float %b, float* %b.addr, align 4
|
||||
%0 = load float, float* %a.addr, align 4
|
||||
%1 = load float, float* %b.addr, align 4
|
||||
%sub = fsub float %0, %1
|
||||
ret float %sub
|
||||
}
|
||||
|
||||
; CHECK-LABEL: @fsub_optnone
|
||||
; CHECK: alloca float
|
||||
; CHECK: alloca float
|
||||
; CHECK: store float
|
||||
; CHECK: store float
|
||||
; CHECK: load float
|
||||
; CHECK: load float
|
||||
; CHECK: fsub float
|
||||
; CHECK: ret float
|
||||
|
||||
; typedef float __attribute__((ext_vector_type(4))) float4;
|
||||
; float4 vmul(float4 a, float4 b){ return a * b; }
|
||||
|
||||
define <4 x float> @vmul_optimize(<4 x float> %a, <4 x float> %b) #0 {
|
||||
entry:
|
||||
%a.addr = alloca <4 x float>, align 16
|
||||
%b.addr = alloca <4 x float>, align 16
|
||||
store <4 x float> %a, <4 x float>* %a.addr, align 16
|
||||
store <4 x float> %b, <4 x float>* %b.addr, align 16
|
||||
%0 = load <4 x float>, <4 x float>* %a.addr, align 16
|
||||
%1 = load <4 x float>, <4 x float>* %b.addr, align 16
|
||||
%mul = fmul <4 x float> %0, %1
|
||||
ret <4 x float> %mul
|
||||
}
|
||||
|
||||
; CHECK-LABEL: @vmul_optimize
|
||||
; CHECK-NOT: alloca
|
||||
; CHECK-NOT: store
|
||||
; CHECK-NOT: load
|
||||
; CHECK: ret
|
||||
|
||||
define <4 x float> @vmul_optnone(<4 x float> %a, <4 x float> %b) #1 {
|
||||
entry:
|
||||
%a.addr = alloca <4 x float>, align 16
|
||||
%b.addr = alloca <4 x float>, align 16
|
||||
store <4 x float> %a, <4 x float>* %a.addr, align 16
|
||||
store <4 x float> %b, <4 x float>* %b.addr, align 16
|
||||
%0 = load <4 x float>, <4 x float>* %a.addr, align 16
|
||||
%1 = load <4 x float>, <4 x float>* %b.addr, align 16
|
||||
%mul = fmul <4 x float> %0, %1
|
||||
ret <4 x float> %mul
|
||||
}
|
||||
|
||||
; CHECK-LABEL: @vmul_optnone
|
||||
; CHECK: alloca <4 x float>
|
||||
; CHECK: alloca <4 x float>
|
||||
; CHECK: store <4 x float>
|
||||
; CHECK: store <4 x float>
|
||||
; CHECK: load <4 x float>
|
||||
; CHECK: load <4 x float>
|
||||
; CHECK: fmul <4 x float>
|
||||
; CHECK: ret
|
@ -1,24 +0,0 @@
|
||||
; RUN: opt < %s -functionattrs -S | FileCheck %s
|
||||
|
||||
@x = global i32 0
|
||||
|
||||
define void @test_opt(i8* %p) {
|
||||
; CHECK-LABEL: @test_opt
|
||||
; CHECK: (i8* nocapture readnone %p) #0 {
|
||||
ret void
|
||||
}
|
||||
|
||||
define void @test_optnone(i8* %p) noinline optnone {
|
||||
; CHECK-LABEL: @test_optnone
|
||||
; CHECK: (i8* %p) #1 {
|
||||
ret void
|
||||
}
|
||||
|
||||
declare i8 @strlen(i8*) noinline optnone
|
||||
; CHECK-LABEL: @strlen
|
||||
; CHECK: (i8*) #1
|
||||
|
||||
; CHECK-LABEL: attributes #0
|
||||
; CHECK: = { norecurse readnone }
|
||||
; CHECK-LABEL: attributes #1
|
||||
; CHECK: = { noinline optnone }
|
@ -1,30 +0,0 @@
|
||||
; RUN: opt -functionattrs -S < %s | FileCheck %s
|
||||
|
||||
; This checks for an iterator wraparound bug in FunctionAttrs. The previous
|
||||
; "incorrect" behavior was inferring readonly for the %x argument in @caller.
|
||||
; Inferring readonly for %x *is* actually correct, since @va_func is marked
|
||||
; readonly, but FunctionAttrs was inferring readonly for the wrong reasons (and
|
||||
; we _need_ the readonly on @va_func to trigger the problematic code path). It
|
||||
; is possible that in the future FunctionAttrs becomes smart enough to infer
|
||||
; readonly for %x for the right reasons, and at that point this test will have
|
||||
; to be marked invalid.
|
||||
|
||||
declare void @llvm.va_start(i8*)
|
||||
declare void @llvm.va_end(i8*)
|
||||
|
||||
define void @va_func(i32* readonly %b, ...) readonly nounwind {
|
||||
; CHECK-LABEL: define void @va_func(i32* nocapture readonly %b, ...)
|
||||
entry:
|
||||
%valist = alloca i8
|
||||
call void @llvm.va_start(i8* %valist)
|
||||
call void @llvm.va_end(i8* %valist)
|
||||
%x = call i32 @caller(i32* %b)
|
||||
ret void
|
||||
}
|
||||
|
||||
define i32 @caller(i32* %x) {
|
||||
; CHECK-LABEL: define i32 @caller(i32* nocapture %x)
|
||||
entry:
|
||||
call void(i32*,...) @va_func(i32* null, i32 0, i32 0, i32 0, i32* %x)
|
||||
ret i32 42
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user