Index: llvm/lib/Transforms/IPO/FunctionAttrs.cpp =================================================================== --- llvm/lib/Transforms/IPO/FunctionAttrs.cpp +++ llvm/lib/Transforms/IPO/FunctionAttrs.cpp @@ -720,10 +720,16 @@ // The accessors used on call site here do the right thing for calls and // invokes with operand bundles. - if (!CB.onlyReadsMemory() && !CB.onlyReadsMemory(UseIndex)) - return Attribute::None; - if (!CB.doesNotAccessMemory(UseIndex)) + if (CB.doesNotAccessMemory(UseIndex)) { + /* nop */ + } else if (CB.onlyReadsMemory() || CB.onlyReadsMemory(UseIndex)) { IsRead = true; + } else if (CB.hasFnAttr(Attribute::WriteOnly) || + CB.dataOperandHasImpliedAttr(UseIndex, Attribute::WriteOnly)) { + IsWrite = true; + } else { + return Attribute::None; + } break; } Index: llvm/test/Analysis/TypeBasedAliasAnalysis/functionattrs.ll =================================================================== --- llvm/test/Analysis/TypeBasedAliasAnalysis/functionattrs.ll +++ llvm/test/Analysis/TypeBasedAliasAnalysis/functionattrs.ll @@ -49,7 +49,7 @@ ret void } -; CHECK: define void @test2_no(i8* nocapture %p, i8* nocapture readonly %q, i64 %n) #5 { +; CHECK: define void @test2_no(i8* nocapture writeonly %p, i8* nocapture readonly %q, i64 %n) #5 { define void @test2_no(i8* %p, i8* %q, i64 %n) nounwind { call void @llvm.memcpy.p0i8.p0i8.i64(i8* %p, i8* %q, i64 %n, i1 false), !tbaa !2 ret void Index: llvm/test/Other/cgscc-devirt-iteration.ll =================================================================== --- llvm/test/Other/cgscc-devirt-iteration.ll +++ llvm/test/Other/cgscc-devirt-iteration.ll @@ -112,7 +112,7 @@ ; CHECK-NOT: read ; CHECK-SAME: noinline ; BEFORE-LABEL: define void @test3(i8* %src, i8* %dest, i64 %size) -; AFTER-LABEL: define void @test3(i8* nocapture readonly %src, i8* nocapture %dest, i64 %size) +; AFTER-LABEL: define void @test3(i8* nocapture readonly %src, i8* nocapture writeonly %dest, i64 %size) %fptr = alloca i8* (i8*, i8*, i64)* store i8* (i8*, i8*, i64)* @memcpy, i8* (i8*, i8*, i64)** %fptr %f = load i8* (i8*, i8*, i64)*, i8* (i8*, i8*, i64)** %fptr Index: llvm/test/Transforms/FunctionAttrs/norecurse.ll =================================================================== --- llvm/test/Transforms/FunctionAttrs/norecurse.ll +++ llvm/test/Transforms/FunctionAttrs/norecurse.ll @@ -50,7 +50,7 @@ ; CHECK: Function Attrs ; CHECK-SAME: nounwind ; CHECK-NOT: norecurse -; CHECK-NEXT: define void @intrinsic(i8* nocapture %dest, i8* nocapture readonly %src, i32 %len) +; CHECK-NEXT: define void @intrinsic(i8* nocapture writeonly %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, i1 false) ret void Index: llvm/test/Transforms/FunctionAttrs/writeonly.ll =================================================================== --- llvm/test/Transforms/FunctionAttrs/writeonly.ll +++ llvm/test/Transforms/FunctionAttrs/writeonly.ll @@ -78,15 +78,23 @@ 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 } -declare void @direct3_callee(i8* writeonly %p) +; 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* %p) +; CHECK: define void @direct3(i8* nocapture writeonly %p) define void @direct3(i8* %p) { call void @direct3_callee(i8* %p) ret void @@ -98,15 +106,15 @@ ret void } -; CHECK: define void @fptr_test2(i8* %p, void (i8*)* nocapture readonly %f) +; 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* writeonly %p) + call void %f(i8* nocapture writeonly %p) ret void } -; CHECK: define void @fptr_test3(i8* %p, void (i8*)* nocapture readonly %f) +; 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* %p) writeonly + call void %f(i8* nocapture %p) writeonly ret void }