Files
clang-p2996/llvm/test/Transforms/FunctionAttrs/writeonly.ll
Philip Reames 0b09313cd5 [funcattrs] Infer writeonly argument attribute [part 2]
This builds on the code from D114963, and extends it to handle calls both direct and indirect. With the revised code structure (from series of previously landed NFCs), this is pretty straight forward.

One thing to note is that we can not infer writeonly for arguments which might be captured. If the pointer can be read back by the caller, and then read through, we have no way to track that. This is the same restriction we have for readonly, except that we get no mileage out of the "callee can be readonly" exception since a writeonly param on a readonly function is either a) readnone or b) UB. This means we can't actually infer much unless nocapture has already been inferred.

Differential Revision: https://reviews.llvm.org/D115003
2022-01-04 09:07:54 -08:00

124 lines
3.4 KiB
LLVM

; RUN: opt < %s -function-attrs -S | FileCheck %s
; RUN: opt < %s -passes=function-attrs -S | FileCheck %s
; CHECK: define void @nouses-argworn-funrn(i32* nocapture readnone %.aaa) #0 {
define void @nouses-argworn-funrn(i32* writeonly %.aaa) {
nouses-argworn-funrn_entry:
ret void
}
; CHECK: define void @nouses-argworn-funro(i32* nocapture readnone %.aaa, i32* nocapture readonly %.bbb) #1 {
define void @nouses-argworn-funro(i32* writeonly %.aaa, i32* %.bbb) {
nouses-argworn-funro_entry:
%val = load i32 , i32* %.bbb
ret void
}
%_type_of_d-ccc = type <{ i8*, i8, i8, i8, i8 }>
@d-ccc = internal global %_type_of_d-ccc <{ i8* null, i8 1, i8 13, i8 0, i8 -127 }>, align 8
; CHECK: define void @nouses-argworn-funwo(i32* nocapture readnone %.aaa) #2 {
define void @nouses-argworn-funwo(i32* writeonly %.aaa) {
nouses-argworn-funwo_entry:
store i8 0, i8* getelementptr inbounds (%_type_of_d-ccc, %_type_of_d-ccc* @d-ccc, i32 0, i32 3)
ret void
}
; CHECK: define void @test_store(i8* nocapture writeonly %p)
define void @test_store(i8* %p) {
store i8 0, i8* %p
ret void
}
@G = external global i8*
; CHECK: define i8 @test_store_capture(i8* %p)
define i8 @test_store_capture(i8* %p) {
store i8* %p, i8** @G
%p2 = load i8*, i8** @G
%v = load i8, i8* %p2
ret i8 %v
}
; CHECK: define void @test_addressing(i8* nocapture writeonly %p)
define void @test_addressing(i8* %p) {
%gep = getelementptr i8, i8* %p, i64 8
%bitcast = bitcast i8* %gep to i32*
store i32 0, i32* %bitcast
ret void
}
; CHECK: define void @test_readwrite(i8* nocapture %p)
define void @test_readwrite(i8* %p) {
%v = load i8, i8* %p
store i8 %v, i8* %p
ret void
}
; CHECK: define void @test_volatile(i8* %p)
define void @test_volatile(i8* %p) {
store volatile i8 0, i8* %p
ret void
}
; CHECK: define void @test_atomicrmw(i8* nocapture %p)
define void @test_atomicrmw(i8* %p) {
atomicrmw add i8* %p, i8 0 seq_cst
ret void
}
declare void @direct1_callee(i8* %p)
; CHECK: define void @direct1(i8* %p)
define void @direct1(i8* %p) {
call void @direct1_callee(i8* %p)
ret void
}
declare void @direct2_callee(i8* %p) writeonly
; writeonly w/o nocapture is not enough
; CHECK: define void @direct2(i8* %p)
define void @direct2(i8* %p) {
call void @direct2_callee(i8* %p)
; read back from global, read through pointer...
ret void
}
; CHECK: define void @direct2b(i8* nocapture writeonly %p)
define void @direct2b(i8* %p) {
call void @direct2_callee(i8* nocapture %p)
ret void
}
declare void @direct3_callee(i8* nocapture writeonly %p)
; CHECK: define void @direct3(i8* nocapture writeonly %p)
define void @direct3(i8* %p) {
call void @direct3_callee(i8* %p)
ret void
}
; CHECK: define void @fptr_test1(i8* %p, void (i8*)* nocapture readonly %f)
define void @fptr_test1(i8* %p, void (i8*)* %f) {
call void %f(i8* %p)
ret void
}
; CHECK: define void @fptr_test2(i8* nocapture writeonly %p, void (i8*)* nocapture readonly %f)
define void @fptr_test2(i8* %p, void (i8*)* %f) {
call void %f(i8* nocapture writeonly %p)
ret void
}
; CHECK: define void @fptr_test3(i8* nocapture writeonly %p, void (i8*)* nocapture readonly %f)
define void @fptr_test3(i8* %p, void (i8*)* %f) {
call void %f(i8* nocapture %p) writeonly
ret void
}
; CHECK: attributes #0 = { {{.*}}readnone{{.*}} }
; CHECK: attributes #1 = { {{.*}}readonly{{.*}} }
; CHECK: attributes #2 = { {{.*}}writeonly{{.*}} }