mirror of
https://github.com/RPCS3/llvm.git
synced 2025-05-15 18:06:08 +00:00

Teach FunctionAttr to infer the nonnull attribute on return values of functions which never return a potentially null value. This is done both via a conservative local analysis for the function itself and a optimistic per-SCC analysis. If no function in the SCC returns anything which could be null (other than values from other functions in the SCC), we can conclude no function returned a null pointer. Even if some function within the SCC returns a null pointer, we may be able to locally conclude that some don't. Differential Revision: http://reviews.llvm.org/D9688 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@246476 91177308-0d34-0410-b5e6-96231b3b80d8
75 lines
1.7 KiB
LLVM
75 lines
1.7 KiB
LLVM
; RUN: opt -S -functionattrs %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
|
|
}
|
|
|
|
|