Index: include/llvm/Analysis/FunctionAttrsAnalysis.h =================================================================== --- /dev/null +++ include/llvm/Analysis/FunctionAttrsAnalysis.h @@ -0,0 +1,41 @@ +//===-- FunctionAttrs.h - Compute function attrs --------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// \file +/// Provides analysis for computing function attributes +//===----------------------------------------------------------------------===// + +#ifndef LLVM_ANALYSIS_FUNCTIONATTRSANALYSIS_H +#define LLVM_ANALYSIS_FUNCTIONATTRSANALYSIS_H + +#include "llvm/ADT/SetVector.h" +#include "llvm/ADT/SmallSet.h" +#include "llvm/Analysis/AliasAnalysis.h" + +namespace llvm { + +class AAResults; + +/// The three kinds of memory access relevant to 'readonly' and +/// 'readnone' attributes. +enum MemoryAccessKind { MAK_ReadNone = 0, MAK_ReadOnly = 1, MAK_MayWrite = 2 }; + +typedef SmallSetVector SCCNodeSet; + +/// Returns the memory access properties of this copy of the function. +MemoryAccessKind computeFunctionBodyMemoryAccess( + const Function &F, AAResults &AAR, + DenseMap *CSModRefMap = nullptr); + +MemoryAccessKind +checkFunctionMemoryAccess(const Function &F, bool ThisBody, AAResults &AAR, + const SCCNodeSet &SCCNodes, + DenseMap *CSModRefMap); +} // namespace llvm + +#endif // LLVM_ANALYSIS_FUNCTIONATTRSANALYSIS_H Index: include/llvm/Analysis/ModuleSummaryAnalysis.h =================================================================== --- include/llvm/Analysis/ModuleSummaryAnalysis.h +++ include/llvm/Analysis/ModuleSummaryAnalysis.h @@ -22,6 +22,7 @@ namespace llvm { class BlockFrequencyInfo; class ProfileSummaryInfo; +class AAResults; /// Direct function to compute a \c ModuleSummaryIndex from a given module. /// @@ -32,7 +33,8 @@ ModuleSummaryIndex buildModuleSummaryIndex( const Module &M, std::function GetBFICallback, - ProfileSummaryInfo *PSI); + ProfileSummaryInfo *PSI, + std::function GetAARCallback = nullptr); /// Analysis pass to provide the ModuleSummaryIndex object. class ModuleSummaryIndexAnalysis Index: include/llvm/IR/ModuleSummaryIndex.h =================================================================== --- include/llvm/IR/ModuleSummaryIndex.h +++ include/llvm/IR/ModuleSummaryIndex.h @@ -55,13 +55,20 @@ Critical = 4 }; HotnessType Hotness = HotnessType::Unknown; + enum class ModRefType : uint8_t { ReadNone = 0, ReadOnly = 1, MayWrite = 2 }; + ModRefType ModRef = ModRefType::ReadNone; CalleeInfo() = default; - explicit CalleeInfo(HotnessType Hotness) : Hotness(Hotness) {} + explicit CalleeInfo(HotnessType Hotness, ModRefType ModRef) + : Hotness(Hotness), ModRef(ModRef) {} void updateHotness(const HotnessType OtherHotness) { Hotness = std::max(Hotness, OtherHotness); } + + void updateModRef(const ModRefType OtherModRef) { + ModRef = std::max(ModRef, OtherModRef); + } }; class GlobalValueSummary; @@ -290,8 +297,8 @@ /// Function attribute flags. Used to track if a function accesses memory, /// recurses or aliases. struct FFlags { - unsigned ReadNone : 1; - unsigned ReadOnly : 1; + unsigned ReadNone : 1; // TODO: change to ReadNoneIgnoringCalls + unsigned ReadOnly : 1; // TODO: change to ReadOnlyIgnoringCalls unsigned NoRecurse : 1; unsigned ReturnDoesNotAlias : 1; }; Index: include/llvm/Transforms/IPO/FunctionAttrs.h =================================================================== --- include/llvm/Transforms/IPO/FunctionAttrs.h +++ include/llvm/Transforms/IPO/FunctionAttrs.h @@ -20,19 +20,6 @@ namespace llvm { -class AAResults; - -/// The three kinds of memory access relevant to 'readonly' and -/// 'readnone' attributes. -enum MemoryAccessKind { - MAK_ReadNone = 0, - MAK_ReadOnly = 1, - MAK_MayWrite = 2 -}; - -/// Returns the memory access properties of this copy of the function. -MemoryAccessKind computeFunctionBodyMemoryAccess(Function &F, AAResults &AAR); - /// Computes function attributes in post-order over the call graph. /// /// By operating in post-order, this pass computes precise attributes for Index: lib/Analysis/CMakeLists.txt =================================================================== --- lib/Analysis/CMakeLists.txt +++ lib/Analysis/CMakeLists.txt @@ -28,6 +28,7 @@ DomPrinter.cpp DominanceFrontier.cpp EHPersonalities.cpp + FunctionAttrsAnalysis.cpp GlobalsModRef.cpp IVUsers.cpp IndirectCallPromotionAnalysis.cpp Index: lib/Analysis/FunctionAttrsAnalysis.cpp =================================================================== --- /dev/null +++ lib/Analysis/FunctionAttrsAnalysis.cpp @@ -0,0 +1,165 @@ +//===- FunctionAttrs.cpp - Pass which marks functions attributes ----------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This file implements interprocedural passes which walk the +/// call-graph deducing and/or propagating function attributes. +/// +//===----------------------------------------------------------------------===// + +#include "llvm/Analysis/FunctionAttrsAnalysis.h" +#include "llvm/Analysis/AliasAnalysis.h" +#include "llvm/Analysis/BasicAliasAnalysis.h" +#include "llvm/IR/GlobalVariable.h" +#include "llvm/IR/InstIterator.h" +using namespace llvm; + +/// Returns the memory access attribute for function F using AAR for AA results, +/// where SCCNodes is the current SCC. +/// +/// If ThisBody is true, this function may examine the function body and will +/// return a result pertaining to this copy of the function. If it is false, the +/// result will be based only on AA results for the function declaration; it +/// will be assumed that some other (perhaps less optimized) version of the +/// function may be selected at link time. +MemoryAccessKind llvm::checkFunctionMemoryAccess( + const Function &F, bool ThisBody, AAResults &AAR, + const SCCNodeSet &SCCNodes, + DenseMap *CSModRefMap) { + FunctionModRefBehavior MRB = AAR.getModRefBehavior(&F); + if (MRB == FMRB_DoesNotAccessMemory) + // Already perfect! + return MAK_ReadNone; + + if (!ThisBody) { + if (AliasAnalysis::onlyReadsMemory(MRB)) + return MAK_ReadOnly; + + // Conservatively assume it writes to memory. + return MAK_MayWrite; + } + + // Scan the function body for instructions that may read or write memory. + bool ReadsMemory = false; + for (auto II = inst_begin(F), E = inst_end(F); II != E; ++II) { + const Instruction *I = &*II; + + // Some instructions can be ignored even if they read or write memory. + // Detect these now, skipping to the next instruction if one is found. + ImmutableCallSite CS(cast(I)); + if (CS) { + // Ignore calls to functions in the same SCC, as long as the call sites + // don't have operand bundles. Calls with operand bundles are allowed to + // have memory effects not described by the memory effects of the call + // target. + if (!CS.hasOperandBundles() && CS.getCalledFunction() && + SCCNodes.count(const_cast(CS.getCalledFunction()))) + continue; + + ModRefInfo *SaveModRef = nullptr; + if (!CS.hasOperandBundles() && CS.getCalledFunction() && CSModRefMap) { + auto Result = + CSModRefMap->try_emplace(CS.getCalledFunction(), MRI_NoModRef); + SaveModRef = &Result.first->second; + } + + FunctionModRefBehavior MRB = AAR.getModRefBehavior(CS); + + // If the call doesn't access memory, we're done. + if (!(MRB & MRI_ModRef)) + continue; + + if (!AliasAnalysis::onlyAccessesArgPointees(MRB)) { + // The call could access any memory. If that includes writes, give up. + if (MRB & MRI_Mod) { + if (SaveModRef) + (*SaveModRef) = MRI_Mod; + else + return MAK_MayWrite; + } + // If it reads, note it. + else if (MRB & MRI_Ref) { + if (SaveModRef && *SaveModRef == MRI_NoModRef) + (*SaveModRef) = MRI_Ref; + else + ReadsMemory = true; + } + continue; + } + + // Check whether all pointer arguments point to local memory, and + // ignore calls that only access local memory. + for (auto CI = CS.arg_begin(), CE = CS.arg_end(); CI != CE; ++CI) { + Value *Arg = *CI; + if (!Arg->getType()->isPtrOrPtrVectorTy()) + continue; + + AAMDNodes AAInfo; + I->getAAMetadata(AAInfo); + MemoryLocation Loc(Arg, MemoryLocation::UnknownSize, AAInfo); + + // Skip accesses to local or constant memory as they don't impact the + // externally visible mod/ref behavior. + if (AAR.pointsToConstantMemory(Loc, /*OrLocal=*/true)) + continue; + + if (MRB & MRI_Mod) { + if (SaveModRef) + (*SaveModRef) = MRI_Mod; + else + // Writes non-local memory. Give up. + return MAK_MayWrite; + } else if (MRB & MRI_Ref) { + if (SaveModRef && *SaveModRef == MRI_NoModRef) + (*SaveModRef) = MRI_Ref; + else + // Ok, it reads non-local memory. + ReadsMemory = true; + } + } + continue; + } else if (const LoadInst *LI = dyn_cast(I)) { + // Ignore non-volatile loads from local memory. (Atomic is okay here.) + if (!LI->isVolatile()) { + MemoryLocation Loc = MemoryLocation::get(LI); + if (AAR.pointsToConstantMemory(Loc, /*OrLocal=*/true)) + continue; + } + } else if (const StoreInst *SI = dyn_cast(I)) { + // Ignore non-volatile stores to local memory. (Atomic is okay here.) + if (!SI->isVolatile()) { + MemoryLocation Loc = MemoryLocation::get(SI); + if (AAR.pointsToConstantMemory(Loc, /*OrLocal=*/true)) + continue; + } + } else if (const VAArgInst *VI = dyn_cast(I)) { + // Ignore vaargs on local memory. + MemoryLocation Loc = MemoryLocation::get(VI); + if (AAR.pointsToConstantMemory(Loc, /*OrLocal=*/true)) + continue; + } + + // Any remaining instructions need to be taken seriously! Check if they + // read or write memory. + if (I->mayWriteToMemory()) + // Writes memory. Just give up. + return MAK_MayWrite; + + // If this instruction may read memory, remember that. + ReadsMemory |= I->mayReadFromMemory(); + } + + return ReadsMemory ? MAK_ReadOnly : MAK_ReadNone; +} + +MemoryAccessKind llvm::computeFunctionBodyMemoryAccess( + const Function &F, AAResults &AAR, + DenseMap *CSModRefMap) { + return checkFunctionMemoryAccess(F, /*ThisBody=*/true, AAR, {}, CSModRefMap); +} Index: lib/Analysis/ModuleSummaryAnalysis.cpp =================================================================== --- lib/Analysis/ModuleSummaryAnalysis.cpp +++ lib/Analysis/ModuleSummaryAnalysis.cpp @@ -16,9 +16,11 @@ #include "llvm/ADT/MapVector.h" #include "llvm/ADT/SetVector.h" #include "llvm/ADT/Triple.h" +#include "llvm/Analysis/AliasAnalysis.h" #include "llvm/Analysis/BlockFrequencyInfo.h" #include "llvm/Analysis/BlockFrequencyInfoImpl.h" #include "llvm/Analysis/BranchProbabilityInfo.h" +#include "llvm/Analysis/FunctionAttrsAnalysis.h" #include "llvm/Analysis/IndirectCallPromotionAnalysis.h" #include "llvm/Analysis/LoopInfo.h" #include "llvm/Analysis/ProfileSummaryInfo.h" @@ -171,11 +173,12 @@ } } -static void -computeFunctionSummary(ModuleSummaryIndex &Index, const Module &M, - const Function &F, BlockFrequencyInfo *BFI, - ProfileSummaryInfo *PSI, bool HasLocalsInUsed, - DenseSet &CantBePromoted) { +static void computeFunctionSummary(ModuleSummaryIndex &Index, const Module &M, + const Function &F, BlockFrequencyInfo *BFI, + ProfileSummaryInfo *PSI, + bool HasLocalsInUsed, + DenseSet &CantBePromoted, + AAResults *AAR) { // Summary not currently supported for anonymous functions, they should // have been named. assert(F.hasName()); @@ -192,6 +195,16 @@ TypeCheckedLoadConstVCalls; ICallPromotionAnalysis ICallAnalysis; + DenseMap CSModRefMap; + bool ReadNone, ReadOnly; + if (AAR) { + auto MAK = computeFunctionBodyMemoryAccess(F, *AAR, &CSModRefMap); + ReadNone = MAK == MAK_ReadNone; + ReadOnly = MAK == MAK_ReadOnly; + } else { + ReadNone = F.hasFnAttribute(Attribute::ReadNone); + ReadOnly = F.hasFnAttribute(Attribute::ReadOnly); + } bool HasInlineAsmMaybeReferencingInternal = false; SmallPtrSet Visited; for (const BasicBlock &BB : F) @@ -243,6 +256,18 @@ CallGraphEdges[Index.getOrInsertValueInfo( cast(CalledValue))] .updateHotness(Hotness); + auto I = CSModRefMap.find(CalledFunction); + if (I != CSModRefMap.end()) { + ModRefInfo MRI = I->second; + CalleeInfo::ModRefType ModRef = CalleeInfo::ModRefType::ReadNone; + if (MRI & MRI_Mod) + ModRef = CalleeInfo::ModRefType::MayWrite; + else if (MRI & MRI_Ref) + ModRef = CalleeInfo::ModRefType::ReadOnly; + CallGraphEdges[Index.getOrInsertValueInfo( + cast(CalledValue))] + .updateModRef(ModRef); + } } else { // Skip inline assembly calls. if (CI && CI->isInlineAsm()) @@ -277,8 +302,8 @@ GlobalValueSummary::GVFlags Flags(F.getLinkage(), NotEligibleForImport, /* Live = */ false); FunctionSummary::FFlags FunFlags{ - F.hasFnAttribute(Attribute::ReadNone), - F.hasFnAttribute(Attribute::ReadOnly), + ReadNone, + ReadOnly, F.hasFnAttribute(Attribute::NoRecurse), F.returnDoesNotAlias(), }; @@ -335,7 +360,8 @@ ModuleSummaryIndex llvm::buildModuleSummaryIndex( const Module &M, std::function GetBFICallback, - ProfileSummaryInfo *PSI) { + ProfileSummaryInfo *PSI, + std::function GetAARCallback) { assert(PSI); ModuleSummaryIndex Index; @@ -374,9 +400,10 @@ BFIPtr = llvm::make_unique(F, BPI, LI); BFI = BFIPtr.get(); } + AAResults *AAR = GetAARCallback ? GetAARCallback(F) : nullptr; computeFunctionSummary(Index, M, F, BFI, PSI, !LocalsUsed.empty(), - CantBePromoted); + CantBePromoted, AAR); } // Compute summaries for all variables defined in module, and save in the @@ -510,7 +537,10 @@ return &FAM.getResult( *const_cast(&F)); }, - &PSI); + &PSI, + [&FAM](const Function &F) { + return &FAM.getResult(*const_cast(&F)); + }); } char ModuleSummaryIndexWrapperPass::ID = 0; @@ -518,6 +548,7 @@ "Module Summary Analysis", false, true) INITIALIZE_PASS_DEPENDENCY(BlockFrequencyInfoWrapperPass) INITIALIZE_PASS_DEPENDENCY(ProfileSummaryInfoWrapperPass) +INITIALIZE_PASS_DEPENDENCY(AAResultsWrapperPass) INITIALIZE_PASS_END(ModuleSummaryIndexWrapperPass, "module-summary-analysis", "Module Summary Analysis", false, true) @@ -539,7 +570,12 @@ *const_cast(&F)) .getBFI()); }, - &PSI); + &PSI, + [this](const Function &F) { + return &( + this->getAnalysis(*const_cast(&F)) + .getAAResults()); + }); return false; } @@ -552,4 +588,5 @@ AU.setPreservesAll(); AU.addRequired(); AU.addRequired(); + AU.addRequired(); } Index: lib/Bitcode/Reader/BitcodeReader.cpp =================================================================== --- lib/Bitcode/Reader/BitcodeReader.cpp +++ lib/Bitcode/Reader/BitcodeReader.cpp @@ -5017,13 +5017,16 @@ for (unsigned I = 0, E = Record.size(); I != E; ++I) { CalleeInfo::HotnessType Hotness = CalleeInfo::HotnessType::Unknown; ValueInfo Callee = getValueInfoFromValueId(Record[I]).first; + CalleeInfo::ModRefType ModRef = CalleeInfo::ModRefType::MayWrite; + if (Record.size() > (I + 1 + IsOldProfileFormat + HasProfile)) + ModRef = static_cast(Record[++I]); if (IsOldProfileFormat) { I += 1; // Skip old callsitecount field if (HasProfile) I += 1; // Skip old profilecount field } else if (HasProfile) Hotness = static_cast(Record[++I]); - Ret.push_back(FunctionSummary::EdgeTy{Callee, CalleeInfo{Hotness}}); + Ret.push_back(FunctionSummary::EdgeTy{Callee, CalleeInfo{Hotness, ModRef}}); } return Ret; } @@ -5101,7 +5104,7 @@ // numrefs x valueid, n x (valueid)] // FS_PERMODULE_PROFILE: [valueid, flags, instcount, fflags, numrefs, // numrefs x valueid, - // n x (valueid, hotness)] + // n x (valueid, modref, hotness)] case bitc::FS_PERMODULE: case bitc::FS_PERMODULE_PROFILE: { unsigned ValueID = Record[0]; @@ -5196,7 +5199,7 @@ // FS_COMBINED: [valueid, modid, flags, instcount, fflags, numrefs, // numrefs x valueid, n x (valueid)] // FS_COMBINED_PROFILE: [valueid, modid, flags, instcount, fflags, numrefs, - // numrefs x valueid, n x (valueid, hotness)] + // numrefs x valueid, n x (valueid, modref, hotness)] case bitc::FS_COMBINED: case bitc::FS_COMBINED_PROFILE: { unsigned ValueID = Record[0]; Index: lib/Bitcode/Writer/BitcodeWriter.cpp =================================================================== --- lib/Bitcode/Writer/BitcodeWriter.cpp +++ lib/Bitcode/Writer/BitcodeWriter.cpp @@ -3311,6 +3311,7 @@ bool HasProfileData = F.getEntryCount().hasValue(); for (auto &ECI : FS->calls()) { NameVals.push_back(getValueId(ECI.first)); + NameVals.push_back(static_cast(ECI.second.ModRef)); if (HasProfileData) NameVals.push_back(static_cast(ECI.second.Hotness)); } @@ -3391,9 +3392,9 @@ Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // instcount Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 4)); // fflags Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 4)); // numrefs - // numrefs x valueid, n x (valueid) + // numrefs x valueid, n x (valueid, modref) Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Array)); - Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 16)); unsigned FSCallsAbbrev = Stream.EmitAbbrev(std::move(Abbv)); // Abbrev for FS_PERMODULE_PROFILE. @@ -3404,9 +3405,9 @@ Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // instcount Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 4)); // fflags Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 4)); // numrefs - // numrefs x valueid, n x (valueid, hotness) + // numrefs x valueid, n x (valueid, modref, hotness) Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Array)); - Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 16)); unsigned FSCallsProfileAbbrev = Stream.EmitAbbrev(std::move(Abbv)); // Abbrev for FS_PERMODULE_GLOBALVAR_INIT_REFS. @@ -3490,9 +3491,9 @@ Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // instcount Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 4)); // fflags Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 4)); // numrefs - // numrefs x valueid, n x (valueid) + // numrefs x valueid, n x (valueid, modref) Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Array)); - Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 16)); unsigned FSCallsAbbrev = Stream.EmitAbbrev(std::move(Abbv)); // Abbrev for FS_COMBINED_PROFILE. @@ -3504,9 +3505,9 @@ Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // instcount Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 4)); // fflags Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 4)); // numrefs - // numrefs x valueid, n x (valueid, hotness) + // numrefs x valueid, n x (valueid, modref, hotness) Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Array)); - Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 16)); unsigned FSCallsProfileAbbrev = Stream.EmitAbbrev(std::move(Abbv)); // Abbrev for FS_COMBINED_GLOBALVAR_INIT_REFS. @@ -3626,6 +3627,7 @@ continue; } NameVals.push_back(*CallValueId); + NameVals.push_back(static_cast(EI.second.ModRef)); if (HasProfileData) NameVals.push_back(static_cast(EI.second.Hotness)); } Index: lib/Transforms/IPO/FunctionAttrs.cpp =================================================================== --- lib/Transforms/IPO/FunctionAttrs.cpp +++ lib/Transforms/IPO/FunctionAttrs.cpp @@ -25,6 +25,7 @@ #include "llvm/Analysis/CallGraph.h" #include "llvm/Analysis/CallGraphSCCPass.h" #include "llvm/Analysis/CaptureTracking.h" +#include "llvm/Analysis/FunctionAttrsAnalysis.h" #include "llvm/Analysis/TargetLibraryInfo.h" #include "llvm/Analysis/ValueTracking.h" #include "llvm/IR/GlobalVariable.h" @@ -56,130 +57,6 @@ cl::desc("Try to propagate nonnull argument attributes from callsites to " "caller functions.")); -namespace { -typedef SmallSetVector SCCNodeSet; -} - -/// Returns the memory access attribute for function F using AAR for AA results, -/// where SCCNodes is the current SCC. -/// -/// If ThisBody is true, this function may examine the function body and will -/// return a result pertaining to this copy of the function. If it is false, the -/// result will be based only on AA results for the function declaration; it -/// will be assumed that some other (perhaps less optimized) version of the -/// function may be selected at link time. -static MemoryAccessKind checkFunctionMemoryAccess(Function &F, bool ThisBody, - AAResults &AAR, - const SCCNodeSet &SCCNodes) { - FunctionModRefBehavior MRB = AAR.getModRefBehavior(&F); - if (MRB == FMRB_DoesNotAccessMemory) - // Already perfect! - return MAK_ReadNone; - - if (!ThisBody) { - if (AliasAnalysis::onlyReadsMemory(MRB)) - return MAK_ReadOnly; - - // Conservatively assume it writes to memory. - return MAK_MayWrite; - } - - // Scan the function body for instructions that may read or write memory. - bool ReadsMemory = false; - for (inst_iterator II = inst_begin(F), E = inst_end(F); II != E; ++II) { - Instruction *I = &*II; - - // Some instructions can be ignored even if they read or write memory. - // Detect these now, skipping to the next instruction if one is found. - CallSite CS(cast(I)); - if (CS) { - // Ignore calls to functions in the same SCC, as long as the call sites - // don't have operand bundles. Calls with operand bundles are allowed to - // have memory effects not described by the memory effects of the call - // target. - if (!CS.hasOperandBundles() && CS.getCalledFunction() && - SCCNodes.count(CS.getCalledFunction())) - continue; - FunctionModRefBehavior MRB = AAR.getModRefBehavior(CS); - - // If the call doesn't access memory, we're done. - if (!(MRB & MRI_ModRef)) - continue; - - if (!AliasAnalysis::onlyAccessesArgPointees(MRB)) { - // The call could access any memory. If that includes writes, give up. - if (MRB & MRI_Mod) - return MAK_MayWrite; - // If it reads, note it. - if (MRB & MRI_Ref) - ReadsMemory = true; - continue; - } - - // Check whether all pointer arguments point to local memory, and - // ignore calls that only access local memory. - for (CallSite::arg_iterator CI = CS.arg_begin(), CE = CS.arg_end(); - CI != CE; ++CI) { - Value *Arg = *CI; - if (!Arg->getType()->isPtrOrPtrVectorTy()) - continue; - - AAMDNodes AAInfo; - I->getAAMetadata(AAInfo); - MemoryLocation Loc(Arg, MemoryLocation::UnknownSize, AAInfo); - - // Skip accesses to local or constant memory as they don't impact the - // externally visible mod/ref behavior. - if (AAR.pointsToConstantMemory(Loc, /*OrLocal=*/true)) - continue; - - if (MRB & MRI_Mod) - // Writes non-local memory. Give up. - return MAK_MayWrite; - if (MRB & MRI_Ref) - // Ok, it reads non-local memory. - ReadsMemory = true; - } - continue; - } else if (LoadInst *LI = dyn_cast(I)) { - // Ignore non-volatile loads from local memory. (Atomic is okay here.) - if (!LI->isVolatile()) { - MemoryLocation Loc = MemoryLocation::get(LI); - if (AAR.pointsToConstantMemory(Loc, /*OrLocal=*/true)) - continue; - } - } else if (StoreInst *SI = dyn_cast(I)) { - // Ignore non-volatile stores to local memory. (Atomic is okay here.) - if (!SI->isVolatile()) { - MemoryLocation Loc = MemoryLocation::get(SI); - if (AAR.pointsToConstantMemory(Loc, /*OrLocal=*/true)) - continue; - } - } else if (VAArgInst *VI = dyn_cast(I)) { - // Ignore vaargs on local memory. - MemoryLocation Loc = MemoryLocation::get(VI); - if (AAR.pointsToConstantMemory(Loc, /*OrLocal=*/true)) - continue; - } - - // Any remaining instructions need to be taken seriously! Check if they - // read or write memory. - if (I->mayWriteToMemory()) - // Writes memory. Just give up. - return MAK_MayWrite; - - // If this instruction may read memory, remember that. - ReadsMemory |= I->mayReadFromMemory(); - } - - return ReadsMemory ? MAK_ReadOnly : MAK_ReadNone; -} - -MemoryAccessKind llvm::computeFunctionBodyMemoryAccess(Function &F, - AAResults &AAR) { - return checkFunctionMemoryAccess(F, /*ThisBody=*/true, AAR, {}); -} - /// Deduce readonly/readnone attributes for the SCC. template static bool addReadAttrs(const SCCNodeSet &SCCNodes, AARGetterT &&AARGetter) { @@ -193,8 +70,8 @@ // Non-exact function definitions may not be selected at link time, and an // alternative version that writes to memory may be selected. See the // comment on GlobalValue::isDefinitionExact for more details. - switch (checkFunctionMemoryAccess(*F, F->hasExactDefinition(), - AAR, SCCNodes)) { + switch (checkFunctionMemoryAccess(*F, F->hasExactDefinition(), AAR, + SCCNodes, nullptr)) { case MAK_MayWrite: return false; case MAK_ReadOnly: Index: lib/Transforms/IPO/ThinLTOBitcodeWriter.cpp =================================================================== --- lib/Transforms/IPO/ThinLTOBitcodeWriter.cpp +++ lib/Transforms/IPO/ThinLTOBitcodeWriter.cpp @@ -9,6 +9,7 @@ #include "llvm/Transforms/IPO/ThinLTOBitcodeWriter.h" #include "llvm/Analysis/BasicAliasAnalysis.h" +#include "llvm/Analysis/FunctionAttrsAnalysis.h" #include "llvm/Analysis/ModuleSummaryAnalysis.h" #include "llvm/Analysis/ProfileSummaryInfo.h" #include "llvm/Analysis/TypeMetadataUtils.h" @@ -23,7 +24,6 @@ #include "llvm/Support/ScopedPrinter.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Transforms/IPO.h" -#include "llvm/Transforms/IPO/FunctionAttrs.h" #include "llvm/Transforms/Utils/Cloning.h" #include "llvm/Transforms/Utils/ModuleUtils.h" using namespace llvm; Index: lib/Transforms/IPO/WholeProgramDevirt.cpp =================================================================== --- lib/Transforms/IPO/WholeProgramDevirt.cpp +++ lib/Transforms/IPO/WholeProgramDevirt.cpp @@ -51,6 +51,7 @@ #include "llvm/ADT/iterator_range.h" #include "llvm/Analysis/AliasAnalysis.h" #include "llvm/Analysis/BasicAliasAnalysis.h" +#include "llvm/Analysis/FunctionAttrsAnalysis.h" #include "llvm/Analysis/TypeMetadataUtils.h" #include "llvm/IR/CallSite.h" #include "llvm/IR/Constants.h" @@ -79,7 +80,6 @@ #include "llvm/Support/FileSystem.h" #include "llvm/Support/MathExtras.h" #include "llvm/Transforms/IPO.h" -#include "llvm/Transforms/IPO/FunctionAttrs.h" #include "llvm/Transforms/Utils/Evaluator.h" #include #include Index: test/Bitcode/thinlto-alias.ll =================================================================== --- test/Bitcode/thinlto-alias.ll +++ test/Bitcode/thinlto-alias.ll @@ -14,7 +14,7 @@ ; CHECK-NEXT: +; CHECK-NEXT: ; CHECK-NEXT: ; CHECK: ; COMBINED-NEXT: -; COMBINED-NEXT: +; COMBINED-NEXT: ; COMBINED-NEXT: +; CHECK-NEXT: ; CHECK-NEXT: ; CHECK-NEXT: Index: test/Bitcode/thinlto-function-summary-callgraph-pgo.ll =================================================================== --- test/Bitcode/thinlto-function-summary-callgraph-pgo.ll +++ test/Bitcode/thinlto-function-summary-callgraph-pgo.ll @@ -17,7 +17,7 @@ ; CHECK: +; CHECK-NEXT: ; CHECK-NEXT: ; CHECK: +; COMBINED-NEXT: ; COMBINED-NEXT: ; ModuleID = 'thinlto-function-summary-callgraph.ll' Index: test/Bitcode/thinlto-function-summary-callgraph-profile-summary.ll =================================================================== --- test/Bitcode/thinlto-function-summary-callgraph-profile-summary.ll +++ test/Bitcode/thinlto-function-summary-callgraph-profile-summary.ll @@ -29,7 +29,7 @@ ; CHECK-NEXT: ; op4=hot1 op6=cold op8=hot2 op10=hot4 op12=none1 op14=hot3 op16=none2 op18=none3 op20=123 -; CHECK-NEXT: +; CHECK-NEXT: ; CHECK-NEXT: ; CHECK: +; COMBINED-NEXT: ; COMBINED_NEXT: Index: test/Bitcode/thinlto-function-summary-callgraph-sample-profile-summary.ll =================================================================== --- test/Bitcode/thinlto-function-summary-callgraph-sample-profile-summary.ll +++ test/Bitcode/thinlto-function-summary-callgraph-sample-profile-summary.ll @@ -31,7 +31,7 @@ ; CHECK-NEXT: ; op4=none1 op6=hot1 op8=cold1 op10=none2 op12=hot2 op14=cold2 op16=none3 op18=hot3 op20=cold3 op22=123 -; CHECK-NEXT: +; CHECK-NEXT: ; CHECK-NEXT: ; CHECK: +; COMBINED-NEXT: ; COMBINED_NEXT: Index: test/Bitcode/thinlto-function-summary-callgraph.ll =================================================================== --- test/Bitcode/thinlto-function-summary-callgraph.ll +++ test/Bitcode/thinlto-function-summary-callgraph.ll @@ -32,7 +32,7 @@ ; COMBINED-NEXT: +; COMBINED-NEXT: ; COMBINED-NEXT: ; ModuleID = 'thinlto-function-summary-callgraph.ll' Index: test/Bitcode/thinlto-function-summary-functionattrs.ll =================================================================== --- test/Bitcode/thinlto-function-summary-functionattrs.ll +++ test/Bitcode/thinlto-function-summary-functionattrs.ll @@ -2,21 +2,11 @@ ; RUN: llvm-bcanalyzer -dump %t.o | FileCheck %s ; CHECK: +; CHECK-DAG: ; Function W contains a call to func3 as well as a reference to globalvar: ; op0=W op4=globalvar op5=func3 -; CHECK-DAG: +; CHECK-DAG: ; Function X contains call to foo, as well as address reference to foo ; which is in the same instruction as the call: ; op0=X op4=foo op5=foo -; CHECK-DAG: +; CHECK-DAG: ; Function Y contains call to func2, and ensures we don't incorrectly add ; a reference to it when reached while earlier analyzing the phi using its ; return value: ; op0=Y op4=func2 -; CHECK-DAG: +; CHECK-DAG: ; Function Z contains call to func2, and ensures we don't incorrectly add ; a reference to it when reached while analyzing subsequent use of its return ; value: ; op0=Z op4=func2 -; CHECK-DAG: +; CHECK-DAG: ; Variable bar initialization contains address reference to func: ; op0=bar op2=func ; CHECK-DAG: