diff --git a/llvm/lib/Transforms/IPO/FunctionAttrs.cpp b/llvm/lib/Transforms/IPO/FunctionAttrs.cpp --- a/llvm/lib/Transforms/IPO/FunctionAttrs.cpp +++ b/llvm/lib/Transforms/IPO/FunctionAttrs.cpp @@ -710,22 +710,13 @@ if (CB.doesNotAccessMemory()) continue; - Function *F = CB.getCalledFunction(); - if (!F) { - if (CB.onlyReadsMemory()) { - IsRead = true; - continue; - } - return Attribute::None; - } - - if (CB.isArgOperand(U) && UseIndex < F->arg_size() && - SCCNodes.count(F->getArg(UseIndex))) { - // This is an argument which is part of the speculative SCC. Note that - // only operands corresponding to formal arguments of the callee can - // participate in the speculation. - break; - } + if (Function *F = CB.getCalledFunction()) + if (CB.isArgOperand(U) && UseIndex < F->arg_size() && + SCCNodes.count(F->getArg(UseIndex))) + // This is an argument which is part of the speculative SCC. Note + // that only operands corresponding to formal arguments of the callee + // can participate in the speculation. + break; // The accessors used on call site here do the right thing for calls and // invokes with operand bundles. diff --git a/llvm/test/Transforms/FunctionAttrs/readattrs.ll b/llvm/test/Transforms/FunctionAttrs/readattrs.ll --- a/llvm/test/Transforms/FunctionAttrs/readattrs.ll +++ b/llvm/test/Transforms/FunctionAttrs/readattrs.ll @@ -146,3 +146,42 @@ store i8 0, i8* %addr.ld ret void } + + +; CHECK: define void @fptr_test1a(i8* nocapture readnone %p, void (i8*)* nocapture readonly %f) +define void @fptr_test1a(i8* %p, void (i8*)* %f) { + call void %f(i8* nocapture readnone %p) + ret void +} + +; CHECK: define void @fptr_test1b(i8* %p, void (i8*)* nocapture readonly %f) +define void @fptr_test1b(i8* %p, void (i8*)* %f) { + ; Can't infer readnone here because call might capture %p + call void %f(i8* readnone %p) + ret void +} + +; CHECK: define void @fptr_test1c(i8* readnone %p, void (i8*)* nocapture readonly %f) +define void @fptr_test1c(i8* %p, void (i8*)* %f) { + call void %f(i8* readnone %p) readonly + ret void +} + +; CHECK: define void @fptr_test2a(i8* nocapture readonly %p, void (i8*)* nocapture readonly %f) +define void @fptr_test2a(i8* %p, void (i8*)* %f) { + call void %f(i8* nocapture readonly %p) + ret void +} + +; CHECK: define void @fptr_test2b(i8* %p, void (i8*)* nocapture readonly %f) +define void @fptr_test2b(i8* %p, void (i8*)* %f) { + ; Can't infer readonly here because call might capture %p + call void %f(i8* readonly %p) + ret void +} + +; CHECK: define void @fptr_test2c(i8* readonly %p, void (i8*)* nocapture readonly %f) +define void @fptr_test2c(i8* %p, void (i8*)* %f) { + call void %f(i8* readonly %p) readonly + ret void +}