Index: include/llvm/CodeGen/GCs.h =================================================================== --- include/llvm/CodeGen/GCs.h +++ include/llvm/CodeGen/GCs.h @@ -18,12 +18,15 @@ class GCStrategy; class GCMetadataPrinter; -/// FIXME: Collector instances are not useful on their own. These no longer -/// serve any purpose except to link in the plugins. - -/// Creates an ocaml-compatible garbage collector. -void linkOcamlGC(); - +/// FIXME: Collector instances are not useful on their own. These no longer +/// serve any purpose except to link in the plugins. + +/// Creates a CoreCLR-compatible garbage collector. +void linkCoreCLRGC(); + +/// Creates an ocaml-compatible garbage collector. +void linkOcamlGC(); + /// Creates an ocaml-compatible metadata printer. void linkOcamlGCPrinter(); Index: include/llvm/CodeGen/LinkAllCodegenComponents.h =================================================================== --- include/llvm/CodeGen/LinkAllCodegenComponents.h +++ include/llvm/CodeGen/LinkAllCodegenComponents.h @@ -40,6 +40,7 @@ llvm::linkErlangGC(); llvm::linkShadowStackGC(); llvm::linkStatepointExampleGC(); + llvm::linkCoreCLRGC(); (void) llvm::createBURRListDAGScheduler(nullptr, llvm::CodeGenOpt::Default); Index: lib/CodeGen/CMakeLists.txt =================================================================== --- lib/CodeGen/CMakeLists.txt +++ lib/CodeGen/CMakeLists.txt @@ -6,12 +6,13 @@ BasicTargetTransformInfo.cpp BranchFolding.cpp CalcSpillWeights.cpp - CallingConvLower.cpp - CodeGen.cpp - CodeGenPrepare.cpp - CriticalAntiDepBreaker.cpp - DFAPacketizer.cpp - DeadMachineInstructionElim.cpp + CallingConvLower.cpp + CodeGen.cpp + CodeGenPrepare.cpp + CoreCLRGC.cpp + CriticalAntiDepBreaker.cpp + DFAPacketizer.cpp + DeadMachineInstructionElim.cpp DwarfEHPrepare.cpp EarlyIfConversion.cpp EdgeBundles.cpp Index: lib/CodeGen/CoreCLRGC.cpp =================================================================== --- lib/CodeGen/CoreCLRGC.cpp +++ lib/CodeGen/CoreCLRGC.cpp @@ -0,0 +1,59 @@ +//===-- CoreCLRGC.cpp - CoreCLR Runtime GC Strategy -----------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains a GCStrategy for the CoreCLR Runtime. +// The strategy is similar to Statepoint-example GC, but differes from it in +// certain aspects, such as: +// 1) Base-pointers need not be explicitly tracked and reported for +// interior pointers +// 2) Uses a different format for encoding stack-maps +// 3) Location of Safe-point polls: polls are only needed before loop-back edges +// and before tail-calls (not needed at function-entry) +// +// The above differences in behavior are to be implemented in upcoming checkins. +// +//===----------------------------------------------------------------------===// + +#include "llvm/CodeGen/GCStrategy.h" +#include "llvm/IR/DerivedTypes.h" +#include "llvm/IR/Value.h" + +using namespace llvm; + +namespace { +class CoreCLRGC : public GCStrategy { +public: + CoreCLRGC() { + UseStatepoints = true; + // These options are all gc.root specific, we specify them so that the + // gc.root lowering code doesn't run. + InitRoots = false; + NeededSafePoints = 0; + UsesMetadata = false; + CustomRoots = false; + } + Optional isGCManagedPointer(const Value *V) const override { + // Method is only valid on pointer typed values. + PointerType *PT = cast(V->getType()); + // For the sake of this example GC, we arbitrarily pick addrspace(1) as our + // GC managed heap. We know that a pointer into this heap needs to be + // updated and that no other pointer does. Note that addrspace(1) is used + // only as an example, it has no special meaning, and is not reserved for + // GC usage. + return (1 == PT->getAddressSpace()); + } +}; +} + +static GCRegistry::Add X("coreclr", + "CoreCLR-compatible GC"); + +namespace llvm { +void linkCoreCLRGC() {} +} Index: lib/Transforms/Scalar/PlaceSafepoints.cpp =================================================================== --- lib/Transforms/Scalar/PlaceSafepoints.cpp +++ lib/Transforms/Scalar/PlaceSafepoints.cpp @@ -53,6 +53,7 @@ #include "llvm/ADT/SetOperations.h" #include "llvm/ADT/SetVector.h" #include "llvm/ADT/Statistic.h" +#include "llvm/ADT/StringRef.h" #include "llvm/Analysis/LoopPass.h" #include "llvm/Analysis/LoopInfo.h" #include "llvm/Analysis/ScalarEvolution.h" @@ -501,14 +502,17 @@ /// Returns true if this function should be rewritten to include safepoint /// polls and parseable call sites. The main point of this function is to be /// an extension point for custom logic. -static bool shouldRewriteFunction(Function &F) { - // TODO: This should check the GCStrategy - if (F.hasGC()) { - const std::string StatepointExampleName("statepoint-example"); - return StatepointExampleName == F.getGC(); - } else - return false; -} +static bool shouldRewriteFunction(Function &F) { + // TODO: This should check the GCStrategy + if (F.hasGC()) { + const char *FunctionGCName = F.getGC(); + const StringRef StatepointExampleName("statepoint-example"); + const StringRef CoreCLRName("coreclr"); + return (StatepointExampleName == FunctionGCName) || + (CoreCLRName == FunctionGCName); + } else + return false; +} // TODO: These should become properties of the GCStrategy, possibly with // command line overrides. Index: lib/Transforms/Scalar/RewriteStatepointsForGC.cpp =================================================================== --- lib/Transforms/Scalar/RewriteStatepointsForGC.cpp +++ lib/Transforms/Scalar/RewriteStatepointsForGC.cpp @@ -18,6 +18,7 @@ #include "llvm/ADT/Statistic.h" #include "llvm/ADT/DenseSet.h" #include "llvm/ADT/SetVector.h" +#include "llvm/ADT/StringRef.h" #include "llvm/IR/BasicBlock.h" #include "llvm/IR/CallSite.h" #include "llvm/IR/Dominators.h" @@ -1926,14 +1927,17 @@ /// Returns true if this function should be rewritten by this pass. The main /// point of this function is as an extension point for custom logic. -static bool shouldRewriteStatepointsIn(Function &F) { - // TODO: This should check the GCStrategy - if (F.hasGC()) { - const std::string StatepointExampleName("statepoint-example"); - return StatepointExampleName == F.getGC(); - } else - return false; -} +static bool shouldRewriteStatepointsIn(Function &F) { + // TODO: This should check the GCStrategy + if (F.hasGC()) { + const char *FunctionGCName = F.getGC(); + const StringRef StatepointExampleName("statepoint-example"); + const StringRef CoreCLRName("coreclr"); + return (StatepointExampleName == FunctionGCName) || + (CoreCLRName == FunctionGCName); + } else + return false; +} bool RewriteStatepointsForGC::runOnFunction(Function &F) { // Nothing to do for declarations. Index: test/Transforms/PlaceSafepoints/statepoint-coreclr.ll =================================================================== --- test/Transforms/PlaceSafepoints/statepoint-coreclr.ll +++ test/Transforms/PlaceSafepoints/statepoint-coreclr.ll @@ -0,0 +1,31 @@ +; RUN: opt %s -S -place-safepoints | FileCheck %s + +; Basic test to make sure that safepoints are placed +; for CoreCLR GC + +declare void @foo() + +define void @test_simple_call() gc "coreclr" { +; CHECK-LABEL: test_simple_call +entry: + br label %other +other: +; CHECK-LABEL: other +; CHECK: statepoint +; CHECK-NOT: gc.result + call void @foo() + ret void +} + +; This function is inlined when inserting a poll. To avoid recursive +; issues, make sure we don't place safepoints in it. +declare void @do_safepoint() +define void @gc.safepoint_poll() { +; CHECK-LABEL: gc.safepoint_poll +; CHECK-LABEL: entry +; CHECK-NEXT: do_safepoint +; CHECK-NEXT: ret void +entry: + call void @do_safepoint() + ret void +}