Index: llvm/lib/Transforms/IPO/FunctionAttrs.cpp =================================================================== --- llvm/lib/Transforms/IPO/FunctionAttrs.cpp +++ llvm/lib/Transforms/IPO/FunctionAttrs.cpp @@ -720,9 +720,20 @@ // Note that we don't allow any calls at all here, or else our result // will be dependent on the iteration order through the functions in the // SCC. - SmallPtrSet Self; - Self.insert(&*A); - Attribute::AttrKind R = determinePointerReadAttrs(&*A, Self); + + Attribute::AttrKind R = Attribute::ReadNone; + // Strengthen the attribute of a pointer argument A from WriteOnly + // to ReadNone when its uses is empty i.e. there is no actual + // write through nor read from the pointer argument A. + if (A->hasAttribute(Attribute::WriteOnly) && + (A->materialized_use_empty())) { + A->removeAttr(Attribute::WriteOnly); + } else { + SmallPtrSet Self; + Self.insert(&*A); + R = determinePointerReadAttrs(&*A, Self); + } + if (R != Attribute::None) { A->addAttr(R); Changed = true; Index: llvm/test/Transforms/FunctionAttrs/writeonly.ll =================================================================== --- /dev/null +++ llvm/test/Transforms/FunctionAttrs/writeonly.ll @@ -0,0 +1,30 @@ +; RUN: opt < %s -functionattrs -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: attributes #0 = { norecurse nounwind readnone } +; CHECK: attributes #1 = { norecurse nounwind readonly } +; CHECK: attributes #2 = { norecurse nounwind writeonly }