Index: llvm/include/llvm/CodeGen/LinkAllCodegenComponents.h =================================================================== --- llvm/include/llvm/CodeGen/LinkAllCodegenComponents.h +++ llvm/include/llvm/CodeGen/LinkAllCodegenComponents.h @@ -14,7 +14,6 @@ #ifndef LLVM_CODEGEN_LINKALLCODEGENCOMPONENTS_H #define LLVM_CODEGEN_LINKALLCODEGENCOMPONENTS_H -#include "llvm/IR/BuiltinGCs.h" #include "llvm/CodeGen/Passes.h" #include "llvm/CodeGen/SchedulerRegistry.h" #include "llvm/Target/TargetMachine.h" @@ -35,8 +34,6 @@ (void) llvm::createGreedyRegisterAllocator(); (void) llvm::createDefaultPBQPRegisterAllocator(); - llvm::linkAllBuiltinGCs(); - (void) llvm::createBURRListDAGScheduler(nullptr, llvm::CodeGenOpt::Default); (void) llvm::createSourceListDAGScheduler(nullptr, Index: llvm/include/llvm/IR/GCStrategy.h =================================================================== --- llvm/include/llvm/IR/GCStrategy.h +++ llvm/include/llvm/IR/GCStrategy.h @@ -57,6 +57,7 @@ namespace llvm { class Type; +class Value; /// GCStrategy describes a garbage collector algorithm's code generation /// requirements, and provides overridable hooks for those needs which cannot @@ -101,6 +102,12 @@ } ///@} + /// Return true if Value is a pointer can be freed in this GC strategy. + /// Returns true if this value can be freed. Returns false if V can never + /// be freed. Note a GCStrategy can always return 'None' (i.e. an empty + /// optional indicating it can't reliably distinguish). + virtual Optional canBeFreed(const Value *V) const { return None; } + /** @name GCRoot Specific Properties * These properties and overrides only apply to collector strategies using * GCRoot. Index: llvm/lib/IR/BuiltinGCs.cpp =================================================================== --- llvm/lib/IR/BuiltinGCs.cpp +++ llvm/lib/IR/BuiltinGCs.cpp @@ -14,6 +14,11 @@ #include "llvm/IR/BuiltinGCs.h" #include "llvm/IR/GCStrategy.h" #include "llvm/IR/DerivedTypes.h" +#include "llvm/IR/Function.h" +#include "llvm/IR/Instruction.h" +#include "llvm/IR/Module.h" +#include "llvm/IR/Statepoint.h" +#include "llvm/IR/Value.h" #include "llvm/Support/Casting.h" using namespace llvm; @@ -82,6 +87,29 @@ // GC usage. return (1 == PT->getAddressSpace()); } + + virtual Optional canBeFreed(const Value *V) const override { + if (!*isGCManagedPointer(V->getType())) + return None; + + const Module *M = nullptr; + if (auto *I = dyn_cast(V)) + M = I->getModule(); + else if (auto *A = dyn_cast(V)) + M = A->getParent()->getParent(); + else + return None; + + // It is cheaper to scan for a declaration than to scan for a use in this + // function. Note that gc.statepoint is a type overloaded function so the + // usual trick of requesting declaration of the intrinsic from the module + // doesn't work. + for (auto &Fn : *M) + if (Fn.getIntrinsicID() == Intrinsic::experimental_gc_statepoint) + return true; + + return false; + } }; /// A GCStrategy for the CoreCLR Runtime. The strategy is similar to Index: llvm/lib/IR/GCStrategy.cpp =================================================================== --- llvm/lib/IR/GCStrategy.cpp +++ llvm/lib/IR/GCStrategy.cpp @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #include "llvm/IR/GCStrategy.h" +#include "llvm/IR/BuiltinGCs.h" using namespace llvm; @@ -36,3 +37,7 @@ } else report_fatal_error(std::string("unsupported GC: ") + Name.str()); } + +struct ForceGCLinking { + ForceGCLinking() { llvm::linkAllBuiltinGCs(); } +} ForceGCLinking; // Force link by creating a global definition. Index: llvm/lib/IR/Value.cpp =================================================================== --- llvm/lib/IR/Value.cpp +++ llvm/lib/IR/Value.cpp @@ -20,6 +20,7 @@ #include "llvm/IR/DataLayout.h" #include "llvm/IR/DerivedTypes.h" #include "llvm/IR/DerivedUser.h" +#include "llvm/IR/GCStrategy.h" #include "llvm/IR/GetElementPtrTypeIterator.h" #include "llvm/IR/InstrTypes.h" #include "llvm/IR/Instructions.h" @@ -762,27 +763,13 @@ // which is why we need the explicit opt in on a per collector basis. if (!F->hasGC()) return true; - - const auto &GCName = F->getGC(); - const StringRef StatepointExampleName("statepoint-example"); - if (GCName != StatepointExampleName) + auto GCStrategy = getGCStrategy(F->getGC()); + Optional CanBeFreedByGC = GCStrategy->canBeFreed(this); + if (CanBeFreedByGC) + return *CanBeFreedByGC; + else + // If GC could not figure it out, conservatively answer "yes". return true; - - auto *PT = cast(this->getType()); - if (PT->getAddressSpace() != 1) - // For the sake of this example GC, we arbitrarily pick addrspace(1) as our - // GC managed heap. This must match the same check in - // RewriteStatepointsForGC (and probably needs better factored.) - return true; - - // It is cheaper to scan for a declaration than to scan for a use in this - // function. Note that gc.statepoint is a type overloaded function so the - // usual trick of requesting declaration of the intrinsic from the module - // doesn't work. - for (auto &Fn : *F->getParent()) - if (Fn.getIntrinsicID() == Intrinsic::experimental_gc_statepoint) - return true; - return false; } uint64_t Value::getPointerDereferenceableBytes(const DataLayout &DL,