diff --git a/llvm/include/llvm/Transforms/IPO/FunctionAttrs.h b/llvm/include/llvm/Transforms/IPO/FunctionAttrs.h --- a/llvm/include/llvm/Transforms/IPO/FunctionAttrs.h +++ b/llvm/include/llvm/Transforms/IPO/FunctionAttrs.h @@ -15,10 +15,12 @@ #ifndef LLVM_TRANSFORMS_IPO_FUNCTIONATTRS_H #define LLVM_TRANSFORMS_IPO_FUNCTIONATTRS_H +#include "llvm/Analysis/AliasAnalysis.h" #include "llvm/Analysis/CGSCCPassManager.h" #include "llvm/Analysis/LazyCallGraph.h" #include "llvm/IR/ModuleSummaryIndex.h" #include "llvm/IR/PassManager.h" +#include namespace llvm { @@ -27,17 +29,9 @@ class Module; class Pass; -/// The three kinds of memory access relevant to 'readonly' and -/// 'readnone' attributes. -enum MemoryAccessKind { - MAK_ReadNone = 0, - MAK_ReadOnly = 1, - MAK_MayWrite = 2, - MAK_WriteOnly = 3 -}; - /// Returns the memory access properties of this copy of the function. -MemoryAccessKind computeFunctionBodyMemoryAccess(Function &F, AAResults &AAR); +FunctionModRefBehavior computeFunctionBodyMemoryAccess(Function &F, + AAResults &AAR); /// Propagate function attributes for function summaries along the index's /// callgraph during thinlink 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 @@ -121,28 +121,33 @@ /// 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) { +static FunctionModRefBehavior +checkFunctionMemoryAccess(Function &F, bool ThisBody, AAResults &AAR, + const SCCNodeSet &SCCNodes) { FunctionModRefBehavior MRB = AAR.getModRefBehavior(&F); if (MRB == FMRB_DoesNotAccessMemory) // Already perfect! - return MAK_ReadNone; + return MRB; if (!ThisBody) { if (AliasAnalysis::onlyReadsMemory(MRB)) - return MAK_ReadOnly; + return FMRB_OnlyReadsMemory; if (AliasAnalysis::onlyWritesMemory(MRB)) - return MAK_WriteOnly; + return FMRB_OnlyWritesMemory; // Conservatively assume it reads and writes to memory. - return MAK_MayWrite; + return FMRB_UnknownModRefBehavior; } // Scan the function body for instructions that may read or write memory. bool ReadsMemory = false; bool WritesMemory = false; + bool AccessesNonArgs = false; + auto IsNonArgumentObject = [](const Value *Ptr) { + const Value *UO = getUnderlyingObject(Ptr); + return !UO || !isa(UO); + }; for (Instruction &I : instructions(F)) { // Some instructions can be ignored even if they read or write memory. // Detect these now, skipping to the next instruction if one is found. @@ -188,6 +193,8 @@ MemoryLocation Loc = MemoryLocation::getBeforeOrAfter(Arg, I.getAAMetadata()); + AccessesNonArgs |= IsNonArgumentObject(Loc.Ptr); + // Skip accesses to local or constant memory as they don't impact the // externally visible mod/ref behavior. if (AAR.pointsToConstantMemory(Loc, /*OrLocal=*/true)) @@ -232,18 +239,18 @@ ReadsMemory |= I.mayReadFromMemory(); } - if (WritesMemory) { + if (WritesMemory) { if (!ReadsMemory) - return MAK_WriteOnly; + return FMRB_OnlyWritesMemory; else - return MAK_MayWrite; + return FMRB_UnknownModRefBehavior; } - return ReadsMemory ? MAK_ReadOnly : MAK_ReadNone; + return ReadsMemory ? FMRB_OnlyReadsMemory : FMRB_DoesNotAccessMemory; } -MemoryAccessKind llvm::computeFunctionBodyMemoryAccess(Function &F, - AAResults &AAR) { +FunctionModRefBehavior llvm::computeFunctionBodyMemoryAccess(Function &F, + AAResults &AAR) { return checkFunctionMemoryAccess(F, /*ThisBody=*/true, AAR, {}); } @@ -262,20 +269,14 @@ // 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)) { - case MAK_MayWrite: + FunctionModRefBehavior FMRB = + checkFunctionMemoryAccess(*F, F->hasExactDefinition(), AAR, SCCNodes); + if (isModAndRefSet(createModRefInfo(FMRB))) return; - case MAK_ReadOnly: - ReadsMemory = true; - break; - case MAK_WriteOnly: - WritesMemory = true; - break; - case MAK_ReadNone: - // Nothing to do! - break; - } + if (FMRB == FMRB_DoesNotAccessMemory) + continue; + ReadsMemory |= AliasAnalysis::onlyReadsMemory(FMRB); + WritesMemory |= AliasAnalysis::onlyWritesMemory(FMRB); } // If the SCC contains both functions that read and functions that write, then diff --git a/llvm/lib/Transforms/IPO/ThinLTOBitcodeWriter.cpp b/llvm/lib/Transforms/IPO/ThinLTOBitcodeWriter.cpp --- a/llvm/lib/Transforms/IPO/ThinLTOBitcodeWriter.cpp +++ b/llvm/lib/Transforms/IPO/ThinLTOBitcodeWriter.cpp @@ -311,7 +311,8 @@ return; } if (!F->isDeclaration() && - computeFunctionBodyMemoryAccess(*F, AARGetter(*F)) == MAK_ReadNone) + computeFunctionBodyMemoryAccess(*F, AARGetter(*F)) == + FMRB_DoesNotAccessMemory) EligibleVirtualFns.insert(F); }); } diff --git a/llvm/lib/Transforms/IPO/WholeProgramDevirt.cpp b/llvm/lib/Transforms/IPO/WholeProgramDevirt.cpp --- a/llvm/lib/Transforms/IPO/WholeProgramDevirt.cpp +++ b/llvm/lib/Transforms/IPO/WholeProgramDevirt.cpp @@ -1702,7 +1702,7 @@ for (VirtualCallTarget &Target : TargetsForSlot) { if (Target.Fn->isDeclaration() || computeFunctionBodyMemoryAccess(*Target.Fn, AARGetter(*Target.Fn)) != - MAK_ReadNone || + FMRB_DoesNotAccessMemory || Target.Fn->arg_empty() || !Target.Fn->arg_begin()->use_empty() || Target.Fn->getReturnType() != RetType) return false;