Index: include/llvm/CodeGen/GCs.h =================================================================== --- include/llvm/CodeGen/GCs.h +++ include/llvm/CodeGen/GCs.h @@ -21,6 +21,9 @@ /// 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(); 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 @@ -9,6 +9,7 @@ CallingConvLower.cpp CodeGen.cpp CodeGenPrepare.cpp + CoreCLRGC.cpp CriticalAntiDepBreaker.cpp DFAPacketizer.cpp DeadMachineInstructionElim.cpp Index: lib/CodeGen/CoreCLRGC.cpp =================================================================== --- /dev/null +++ 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 @@ -504,8 +504,11 @@ static bool shouldRewriteFunction(Function &F) { // TODO: This should check the GCStrategy if (F.hasGC()) { + const char *FunctionGCName = F.getGC(); const std::string StatepointExampleName("statepoint-example"); - return StatepointExampleName == F.getGC(); + const std::string CoreCLRName("coreclr"); + return (StatepointExampleName == FunctionGCName) || + (CoreCLRName == FunctionGCName); } else return false; } Index: lib/Transforms/Scalar/RewriteStatepointsForGC.cpp =================================================================== --- lib/Transforms/Scalar/RewriteStatepointsForGC.cpp +++ lib/Transforms/Scalar/RewriteStatepointsForGC.cpp @@ -1929,8 +1929,11 @@ static bool shouldRewriteStatepointsIn(Function &F) { // TODO: This should check the GCStrategy if (F.hasGC()) { + const char *FunctionGCName = F.getGC(); const std::string StatepointExampleName("statepoint-example"); - return StatepointExampleName == F.getGC(); + const std::string CoreCLRName("coreclr"); + return (StatepointExampleName == FunctionGCName) || + (CoreCLRName == FunctionGCName); } else return false; } Index: test/Transforms/PlaceSafepoints/statepoint-coreclr.ll =================================================================== --- /dev/null +++ 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 +}