Index: include/llvm/CodeGen/GCMetadata.h =================================================================== --- include/llvm/CodeGen/GCMetadata.h +++ include/llvm/CodeGen/GCMetadata.h @@ -164,14 +164,10 @@ /// Records both the function level information used by GCRoots and a /// cache of the 'active' gc strategy objects for the current Module. class GCModuleInfo : public ImmutablePass { - typedef StringMap strategy_map_type; - typedef std::vector> list_type; - - strategy_map_type StrategyMap; + typedef std::vector list_type; + /// A list of GCStrategies which are active in this Module. These are no + /// longer owning pointers. list_type StrategyList; - - GCStrategy *getOrCreateStrategy(const Module *M, const std::string &Name); - public: /// List of per function info objects. In theory, Each of these /// may be associated with a different GC. Index: include/llvm/CodeGen/GCStrategy.h =================================================================== --- include/llvm/CodeGen/GCStrategy.h +++ include/llvm/CodeGen/GCStrategy.h @@ -51,20 +51,23 @@ #define LLVM_CODEGEN_GCSTRATEGY_H #include "llvm/CodeGen/GCMetadata.h" -#include "llvm/CodeGen/MachineFunction.h" +#include "llvm/Support/ErrorHandling.h" #include "llvm/Support/Registry.h" #include namespace llvm { + + class MachineFunction; + /// GCStrategy describes a garbage collector algorithm's code generation /// requirements, and provides overridable hooks for those needs which cannot - /// be abstractly described. GCStrategy objects currently must be looked up - /// through the GCModuleInfo analysis pass. They are owned by the analysis - /// pass and recreated every time that pass is invalidated. + /// be abstractly described. GCStrategy objects must be looked up through + /// the Function. The objects themselves are owned by the Context and must + /// be immutable. class GCStrategy { private: std::string Name; - friend class GCModuleInfo; + friend class LLVMContextImpl; protected: unsigned NeededSafePoints; ///< Bitmask of required safe points. Index: include/llvm/IR/Function.h =================================================================== --- include/llvm/IR/Function.h +++ include/llvm/IR/Function.h @@ -29,6 +29,7 @@ namespace llvm { class FunctionType; +class GCStrategy; class LLVMContext; // Traits for intrusive list of basic blocks... @@ -225,6 +226,10 @@ void setGC(const char *Str); void clearGC(); + /// Returns the GCStrategy associated with the specified garbage collector + /// algorithm or nullptr if one is not set. + GCStrategy *getGCStrategy() const; + /// @brief adds the attribute to the list of attributes. void addAttribute(unsigned i, Attribute::AttrKind attr); Index: lib/CodeGen/GCMetadata.cpp =================================================================== --- lib/CodeGen/GCMetadata.cpp +++ lib/CodeGen/GCMetadata.cpp @@ -61,27 +61,6 @@ initializeGCModuleInfoPass(*PassRegistry::getPassRegistry()); } -GCStrategy *GCModuleInfo::getOrCreateStrategy(const Module *M, - const std::string &Name) { - strategy_map_type::iterator NMI = StrategyMap.find(Name); - if (NMI != StrategyMap.end()) - return NMI->getValue(); - - for (GCRegistry::iterator I = GCRegistry::begin(), - E = GCRegistry::end(); I != E; ++I) { - if (Name == I->getName()) { - std::unique_ptr S = I->instantiate(); - S->Name = Name; - StrategyMap[Name] = S.get(); - StrategyList.push_back(std::move(S)); - return StrategyList.back().get(); - } - } - - dbgs() << "unsupported GC: " << Name << "\n"; - llvm_unreachable(nullptr); -} - GCFunctionInfo &GCModuleInfo::getFunctionInfo(const Function &F) { assert(!F.isDeclaration() && "Can only get GCFunctionInfo for a definition!"); assert(F.hasGC()); @@ -90,7 +69,15 @@ if (I != FInfoMap.end()) return *I->second; - GCStrategy *S = getOrCreateStrategy(F.getParent(), F.getGC()); + GCStrategy *S = F.getGCStrategy(); + if (!S) { + dbgs() << "unsupported GC: " << F.getGC() << "\n"; + llvm_unreachable(nullptr); + } + // Save the fact this strategy is associated with this module. Note that + // these are non-owning references, the GCStrategy remains owned by the + // Context. + StrategyList.push_back(S); Functions.push_back(make_unique(F, *S)); GCFunctionInfo *GFI = Functions.back().get(); FInfoMap[&F] = GFI; @@ -100,7 +87,6 @@ void GCModuleInfo::clear() { Functions.clear(); FInfoMap.clear(); - StrategyMap.clear(); StrategyList.clear(); } Index: lib/IR/Function.cpp =================================================================== --- lib/IR/Function.cpp +++ lib/IR/Function.cpp @@ -386,6 +386,14 @@ } } +GCStrategy *Function::getGCStrategy() const { + // Lookup the GCStrategy (which is owned by the Context), given the name of + // the GC in question. + const char* Name = getGC(); + LLVMContextImpl* pImpl = getParent()->getContext().pImpl; + return pImpl->getGCStrategy(Name); +} + /// copyAttributesFrom - copy all additional attributes (those not needed to /// create a Function) from the Function Src to this one. void Function::copyAttributesFrom(const GlobalValue *Src) { Index: lib/IR/LLVMContextImpl.h =================================================================== --- lib/IR/LLVMContextImpl.h +++ lib/IR/LLVMContextImpl.h @@ -41,6 +41,7 @@ class DiagnosticInfoOptimizationRemark; class DiagnosticInfoOptimizationRemarkMissed; class DiagnosticInfoOptimizationRemarkAnalysis; +class GCStrategy; class LLVMContext; class Type; class Value; @@ -346,6 +347,17 @@ int getOrAddScopeRecordIdxEntry(MDNode *N, int ExistingIdx); int getOrAddScopeInlinedAtIdxEntry(MDNode *Scope, MDNode *IA,int ExistingIdx); + + /// An owning list of all GCStrategies which have been created + SmallVector, 1> GCStrategyList; + /// A helper map to speedup lookups into the above list + StringMap GCStrategyMap; + + /// Lookup the GCStrategy object associated with the given gc name. If one + /// can't be found, returns nullptr. The lifetime of the returned objects + /// is dictated by the lifetime of the associated context. No caller should + /// attempt to delete the returned objects. + GCStrategy *getGCStrategy(const StringRef &Name); LLVMContextImpl(LLVMContext &C); ~LLVMContextImpl(); Index: lib/IR/LLVMContextImpl.cpp =================================================================== --- lib/IR/LLVMContextImpl.cpp +++ lib/IR/LLVMContextImpl.cpp @@ -13,6 +13,7 @@ #include "LLVMContextImpl.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/CodeGen/GCStrategy.h" #include "llvm/IR/Attributes.h" #include "llvm/IR/DiagnosticInfo.h" #include "llvm/IR/Module.h" @@ -172,3 +173,27 @@ void GetElementPtrConstantExpr::anchor() { } void CompareConstantExpr::anchor() { } + +GCStrategy *LLVMContextImpl::getGCStrategy(const StringRef &Name) { + // TODO: Arguably, just doing a linear search would be faster for small N + auto NMI = GCStrategyMap.find(Name); + if (NMI != GCStrategyMap.end()) + return NMI->getValue(); + + for (GCRegistry::iterator I = GCRegistry::begin(), + E = GCRegistry::end(); I != E; ++I) { + if (Name == I->getName()) { + std::unique_ptr S = I->instantiate(); + S->Name = Name; + GCStrategyMap[Name] = S.get(); + GCStrategyList.push_back(std::move(S)); + return GCStrategyList.back().get(); + } + } + + // No GCStrategy found for that name, error reporting is the job of our + // callers. + return nullptr; +} + +