diff --git a/llvm/lib/Analysis/AliasAnalysis.cpp b/llvm/lib/Analysis/AliasAnalysis.cpp --- a/llvm/lib/Analysis/AliasAnalysis.cpp +++ b/llvm/lib/Analysis/AliasAnalysis.cpp @@ -235,35 +235,37 @@ // Try to refine the mod-ref info further using other API entry points to the // aggregate set of AA results. - auto MRB = getModRefBehavior(Call); - if (MRB.onlyAccessesInaccessibleMem()) - return ModRefInfo::NoModRef; - // TODO: Exclude inaccessible memory location here. - Result &= MRB.getModRef(); + // We can completely ignore inaccessible memory here, because MemoryLocations + // can only reference accessible memory. + auto MRB = getModRefBehavior(Call).getWithoutLoc( + FunctionModRefBehavior::InaccessibleMem); + if (MRB.doesNotAccessMemory()) + return ModRefInfo::NoModRef; - if (MRB.onlyAccessesArgPointees() || MRB.onlyAccessesInaccessibleOrArgMem()) { + ModRefInfo ArgMR = MRB.getModRef(FunctionModRefBehavior::ArgMem); + ModRefInfo OtherMR = + MRB.getWithoutLoc(FunctionModRefBehavior::ArgMem).getModRef(); + if ((ArgMR | OtherMR) != OtherMR) { + // Refine the modref info for argument memory. We only bother to do this + // if ArgMR is not a subset of OtherMR, otherwise this won't have an impact + // on the final result. ModRefInfo AllArgsMask = ModRefInfo::NoModRef; - if (MRB.doesAccessArgPointees()) { - for (const auto &I : llvm::enumerate(Call->args())) { - const Value *Arg = I.value(); - if (!Arg->getType()->isPointerTy()) - continue; - unsigned ArgIdx = I.index(); - MemoryLocation ArgLoc = - MemoryLocation::getForArgument(Call, ArgIdx, TLI); - AliasResult ArgAlias = alias(ArgLoc, Loc, AAQI); - if (ArgAlias != AliasResult::NoAlias) - AllArgsMask |= getArgModRefInfo(Call, ArgIdx); - } + for (const auto &I : llvm::enumerate(Call->args())) { + const Value *Arg = I.value(); + if (!Arg->getType()->isPointerTy()) + continue; + unsigned ArgIdx = I.index(); + MemoryLocation ArgLoc = MemoryLocation::getForArgument(Call, ArgIdx, TLI); + AliasResult ArgAlias = alias(ArgLoc, Loc, AAQI); + if (ArgAlias != AliasResult::NoAlias) + AllArgsMask |= getArgModRefInfo(Call, ArgIdx); } - // Return NoModRef if no alias found with any argument. - if (isNoModRef(AllArgsMask)) - return ModRefInfo::NoModRef; - // Logical & between other AA analyses and argument analysis. - Result &= AllArgsMask; + ArgMR &= AllArgsMask; } + Result &= ArgMR | OtherMR; + // If Loc is a constant memory location, the call definitely could not // modify the memory location. if (isModSet(Result) && pointsToConstantMemory(Loc, AAQI, /*OrLocal*/ false)) diff --git a/llvm/lib/Analysis/BasicAliasAnalysis.cpp b/llvm/lib/Analysis/BasicAliasAnalysis.cpp --- a/llvm/lib/Analysis/BasicAliasAnalysis.cpp +++ b/llvm/lib/Analysis/BasicAliasAnalysis.cpp @@ -769,12 +769,16 @@ else if (Call->onlyAccessesInaccessibleMemOrArgMem()) Min = FunctionModRefBehavior::inaccessibleOrArgMemOnly(MR); - // If the call has operand bundles then aliasing attributes from the function - // it calls do not directly apply to the call. This can be made more precise - // in the future. - if (!Call->hasOperandBundles()) - if (const Function *F = Call->getCalledFunction()) - Min &= getBestAAResults().getModRefBehavior(F); + if (const Function *F = Call->getCalledFunction()) { + FunctionModRefBehavior FMRB = getBestAAResults().getModRefBehavior(F); + // Operand bundles on the call may also read or write memory, in addition + // to the behavior of the called function. + if (Call->hasReadingOperandBundles()) + FMRB |= FunctionModRefBehavior::readOnly(); + if (Call->hasClobberingOperandBundles()) + FMRB |= FunctionModRefBehavior::writeOnly(); + Min &= FMRB; + } return Min; } @@ -976,26 +980,6 @@ return ModRefInfo::NoModRef; } - // Ideally, there should be no need to special case for memcpy/memove - // intrinsics here since general machinery (based on memory attributes) should - // already handle it just fine. Unfortunately, it doesn't due to deficiency in - // operand bundles support. At the moment it's not clear if complexity behind - // enhancing general mechanism worths it. - // TODO: Consider improving operand bundles support in general mechanism. - if (auto *Inst = dyn_cast(Call)) { - AliasResult SrcAA = - getBestAAResults().alias(MemoryLocation::getForSource(Inst), Loc, AAQI); - AliasResult DestAA = - getBestAAResults().alias(MemoryLocation::getForDest(Inst), Loc, AAQI); - // It's also possible for Loc to alias both src and dest, or neither. - ModRefInfo rv = ModRefInfo::NoModRef; - if (SrcAA != AliasResult::NoAlias || Call->hasReadingOperandBundles()) - rv |= ModRefInfo::Ref; - if (DestAA != AliasResult::NoAlias || Call->hasClobberingOperandBundles()) - rv |= ModRefInfo::Mod; - return rv; - } - // Guard intrinsics are marked as arbitrarily writing so that proper control // dependencies are maintained but they never mods any particular memory // location. diff --git a/llvm/test/Feature/OperandBundles/basic-aa-argmemonly.ll b/llvm/test/Feature/OperandBundles/basic-aa-argmemonly.ll --- a/llvm/test/Feature/OperandBundles/basic-aa-argmemonly.ll +++ b/llvm/test/Feature/OperandBundles/basic-aa-argmemonly.ll @@ -33,19 +33,14 @@ ; heap, but they don't write to any location in the heap if the callee does not ; deoptimize the caller. This fact, combined with the fact that ; @argmemonly_function is, well, an argmemonly function, can be used to conclude -; that %P is not written to at the callsite. However LLVM currently cannot -; describe the "does not write to non-args, and reads the entire heap" effect on -; a callsite. +; that %P is not written to at the callsite. ; CHECK-LABEL: @test2( %v1 = load i32, i32* %P -; CHECK: %v1 = load i32, i32* %P call void @argmemonly_function(i32* %P2) [ "deopt"() ] ; CHECK: call void @argmemonly_function( %v2 = load i32, i32* %P -; CHECK: %v2 = load i32, i32* %P %diff = sub i32 %v1, %v2 -; CHECK: %diff = sub i32 %v1, %v2 ret i32 %diff -; CHECK: ret i32 %diff +; CHECK: ret i32 0 }