Index: llvm/include/llvm/Analysis/AliasAnalysis.h =================================================================== --- llvm/include/llvm/Analysis/AliasAnalysis.h +++ llvm/include/llvm/Analysis/AliasAnalysis.h @@ -265,6 +265,11 @@ return anyLoc(ModRefInfo::Ref); } + /// Create FunctionModRefBehavior that can write any memory. + static FunctionModRefBehavior writeOnly() { + return anyLoc(ModRefInfo::Mod); + } + /// Create FunctionModRefBehavior that can only access argument memory. static FunctionModRefBehavior argMemOnly(ModRefInfo MR) { return FunctionModRefBehavior(ArgMem, MR); @@ -361,6 +366,17 @@ return *this; } + /// Union (in-place) with another FunctionModRefBehavior. + FunctionModRefBehavior operator|(FunctionModRefBehavior Other) const { + return FunctionModRefBehavior(Data | Other.Data); + } + + /// Union with another FunctionModRefBehavior. + FunctionModRefBehavior &operator|=(FunctionModRefBehavior Other) { + Data |= Other.Data; + return *this; + } + /// Check whether this is the same as another FunctionModRefBehavior. bool operator==(FunctionModRefBehavior Other) const { return Data == Other.Data; Index: llvm/lib/Analysis/AliasAnalysis.cpp =================================================================== --- llvm/lib/Analysis/AliasAnalysis.cpp +++ llvm/lib/Analysis/AliasAnalysis.cpp @@ -235,35 +235,34 @@ // 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()) + auto MRB = getModRefBehavior(Call).withoutLoc( + FunctionModRefBehavior::InaccessibleMem); + if (MRB.doesNotAccessMemory()) return ModRefInfo::NoModRef; - // TODO: Exclude inaccessible memory location here. - Result &= MRB.getModRef(); - - if (MRB.onlyAccessesArgPointees() || MRB.onlyAccessesInaccessibleOrArgMem()) { + ModRefInfo ArgMR = MRB.getModRef(FunctionModRefBehavior::ArgMem); + ModRefInfo OtherMR = + MRB.withoutLoc(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)) Index: llvm/lib/Analysis/BasicAliasAnalysis.cpp =================================================================== --- llvm/lib/Analysis/BasicAliasAnalysis.cpp +++ llvm/lib/Analysis/BasicAliasAnalysis.cpp @@ -764,12 +764,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; } @@ -971,26 +975,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.