}),
AG(AG), CGSCC(CGSCC) {}
+ ~InformationCache() {
+ DeleteContainerSeconds(FuncInfoMap);
+ }
+
/// A map type from opcodes to instructions with this opcode.
using OpcodeInstMapTy = DenseMap<unsigned, SmallVector<Instruction *, 32>>;
/// Return the map that relates "interesting" opcodes with all instructions
/// with that opcode in \p F.
OpcodeInstMapTy &getOpcodeInstMapForFunction(const Function &F) {
- return FuncInstOpcodeMap[&F];
+ return getFunctionInfo(F).OpcodeInstMap;
}
/// A vector type to hold instructions.
- using InstructionVectorTy = std::vector<Instruction *>;
+ using InstructionVectorTy = SmallVector<Instruction *, 4>;
/// Return the instructions in \p F that may read or write memory.
InstructionVectorTy &getReadOrWriteInstsForFunction(const Function &F) {
- return FuncRWInstsMap[&F];
+ return getFunctionInfo(F).RWInsts;
}
/// Return MustBeExecutedContextExplorer
/// Return true if \p Arg is involved in a must-tail call, thus the argument
/// of the caller or callee.
- bool isInvolvedInMustTailCall(const Argument &Arg) const {
- return FunctionsCalledViaMustTail.count(Arg.getParent()) ||
- FunctionsWithMustTailCall.count(Arg.getParent());
+ bool isInvolvedInMustTailCall(const Argument &Arg) {
+ FunctionInfo &FI = getFunctionInfo(*Arg.getParent());
+ return FI.CalledViaMustTail || FI.ContainsMustTailCall;
}
/// Return the analysis result from a pass \p AP for function \p F.
const RetainedKnowledgeMap &getKnowledgeMap() const { return KnowledgeMap; }
private:
- /// A map type from functions to opcode to instruction maps.
- using FuncInstOpcodeMapTy = DenseMap<const Function *, OpcodeInstMapTy>;
+ struct FunctionInfo {
+ /// A nested map that remembers all instructions in a function with a
+ /// certain instruction opcode (Instruction::getOpcode()).
+ OpcodeInstMapTy OpcodeInstMap;
- /// A map type from functions to their read or write instructions.
- using FuncRWInstsMapTy = DenseMap<const Function *, InstructionVectorTy>;
+ /// A map from functions to their instructions that may read or write
+ /// memory.
+ InstructionVectorTy RWInsts;
- /// A nested map that remembers all instructions in a function with a certain
- /// instruction opcode (Instruction::getOpcode()).
- FuncInstOpcodeMapTy FuncInstOpcodeMap;
+ /// Function is called by a `musttail` call.
+ bool CalledViaMustTail;
- /// A map from functions to their instructions that may read or write memory.
- FuncRWInstsMapTy FuncRWInstsMap;
+ /// Function contains a `musttail` call.
+ bool ContainsMustTailCall;
+ };
- /// Functions called by a `musttail` call.
- SmallPtrSet<Function *, 8> FunctionsCalledViaMustTail;
+ /// A map type from functions to informatio about it.
+ DenseMap<const Function *, FunctionInfo *> FuncInfoMap;
- /// Functions containing a `musttail` call.
- SmallPtrSet<Function *, 8> FunctionsWithMustTailCall;
+ /// Return information about the function \p F, potentially by creating it.
+ FunctionInfo &getFunctionInfo(const Function &F) {
+ FunctionInfo *&FI = FuncInfoMap[&F];
+ if (!FI) {
+ FI = new FunctionInfo();
+ initializeInformationCache(F, *FI);
+ }
+ return *FI;
+ }
+
+ /// Initialize the function information cache \p FI for the function \p F.
+ ///
+ /// This method needs to be called for all function that might be looked at
+ /// through the information cache interface *prior* to looking at them.
+ void initializeInformationCache(const Function &F, FunctionInfo &FI);
/// The datalayout used in the module.
const DataLayout &DL;
/// various places.
void identifyDefaultAbstractAttributes(Function &F);
- /// Initialize the information cache for queries regarding function \p F.
- ///
- /// This method needs to be called for all function that might be looked at
- /// through the information cache interface *prior* to looking at them.
- void initializeInformationCache(Function &F);
-
/// Determine whether the function \p F is IPO amendable
///
/// If a function is exactly defined or it has alwaysinline attribute
#define DEBUG_TYPE "attributor"
-STATISTIC(NumFnDeleted,
- "Number of function deleted");
+STATISTIC(NumFnDeleted, "Number of function deleted");
STATISTIC(NumFnWithExactDefinition,
"Number of functions with exact definitions");
STATISTIC(NumFnWithoutExactDefinition,
llvm_unreachable("Expected enum or string attribute!");
}
-
Argument *IRPosition::getAssociatedArgument() const {
if (getPositionKind() == IRP_ARGUMENT)
return cast<Argument>(&getAnchorValue());
return Changed;
}
-void Attributor::initializeInformationCache(Function &F) {
+void InformationCache::initializeInformationCache(const Function &CF,
+ FunctionInfo &FI) {
+ // As we do not modify the function here we can remove the const
+ // withouth breaking implicit assumptions. At the end of the day, we could
+ // initialize the cache eagerly which would look the same to the users.
+ Function &F = const_cast<Function &>(CF);
// Walk all instructions to find interesting instructions that might be
// queried by abstract attributes during their initialization or update.
// This has to happen before we create attributes.
- auto &ReadOrWriteInsts = InfoCache.FuncRWInstsMap[&F];
- auto &InstOpcodeMap = InfoCache.FuncInstOpcodeMap[&F];
for (Instruction &I : instructions(&F)) {
bool IsInterestingOpcode = false;
// For `must-tail` calls we remember the caller and callee.
if (IntrinsicInst *Assume = dyn_cast<IntrinsicInst>(&I)) {
if (Assume->getIntrinsicID() == Intrinsic::assume)
- fillMapFromAssume(*Assume, InfoCache.KnowledgeMap);
+ fillMapFromAssume(*Assume, KnowledgeMap);
} else if (cast<CallInst>(I).isMustTailCall()) {
- InfoCache.FunctionsWithMustTailCall.insert(&F);
- InfoCache.FunctionsCalledViaMustTail.insert(
- cast<CallInst>(I).getCalledFunction());
+ FI.ContainsMustTailCall = true;
+ if (const Function *Callee = cast<CallInst>(I).getCalledFunction())
+ getFunctionInfo(*Callee).CalledViaMustTail = true;
}
LLVM_FALLTHROUGH;
case Instruction::CallBr:
IsInterestingOpcode = true;
}
if (IsInterestingOpcode)
- InstOpcodeMap[I.getOpcode()].push_back(&I);
+ FI.OpcodeInstMap[I.getOpcode()].push_back(&I);
if (I.mayReadOrWriteMemory())
- ReadOrWriteInsts.push_back(&I);
+ FI.RWInsts.push_back(&I);
}
if (F.hasFnAttribute(Attribute::AlwaysInline) &&
isInlineViable(F).isSuccess())
- InfoCache.InlineableFunctions.insert(&F);
+ InlineableFunctions.insert(&F);
}
void Attributor::recordDependence(const AbstractAttribute &FromAA,
// In non-module runs we need to look at the call sites of a function to
// determine if it is part of a must-tail call edge. This will influence what
// attributes we can derive.
- if (!isModulePass() && !InfoCache.FunctionsCalledViaMustTail.count(&F))
+ InformationCache::FunctionInfo &FI = InfoCache.getFunctionInfo(F);
+ if (!isModulePass() && !FI.CalledViaMustTail) {
for (const Use &U : F.uses())
if (ImmutableCallSite ICS = ImmutableCallSite(U.getUser()))
if (ICS.isCallee(&U) && ICS.isMustTailCall())
- InfoCache.FunctionsCalledViaMustTail.insert(&F);
+ FI.CalledViaMustTail = true;
+ }
IRPosition FPos = IRPosition::function(F);
// while we identify default attribute opportunities.
Attributor A(Functions, InfoCache, CGUpdater, DepRecInterval);
- // Note: _Don't_ combine/fuse this loop with the one below because
- // when A.identifyDefaultAbstractAttributes() is called for one
- // function, it assumes that the information cach has been
- // initialized for _all_ functions.
- for (Function *F : Functions)
- A.initializeInformationCache(*F);
-
// Create shallow wrappers for all functions that are not IPO amendable
if (AllowShallowWrappers)
for (Function *F : Functions)