Add a GCStrategy for CoreCLR
authorSwaroop Sridhar <Swaroop.Sridhar@microsoft.com>
Wed, 20 May 2015 01:07:23 +0000 (01:07 +0000)
committerSwaroop Sridhar <Swaroop.Sridhar@microsoft.com>
Wed, 20 May 2015 01:07:23 +0000 (01:07 +0000)
This change adds a new GC strategy for supporting the CoreCLR runtime.

This strategy is currently identical to Statepoint-example GC,
but is necessary for several upcoming changes specific to CoreCLR, such as:

1. Base-pointers not explicitly reported for interior pointers
2. Different format for stack-map encoding
3. Location of Safe-point polls: polls are only needed before loop-back edges and before tail-calls (not needed at function-entry)
4. Runtime specific handshake between calls to managed/unmanaged functions.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@237753 91177308-0d34-0410-b5e6-96231b3b80d8

include/llvm/CodeGen/GCs.h
include/llvm/CodeGen/LinkAllCodegenComponents.h
lib/CodeGen/CMakeLists.txt
lib/CodeGen/CoreCLRGC.cpp [new file with mode: 0644]
lib/Transforms/Scalar/PlaceSafepoints.cpp
lib/Transforms/Scalar/RewriteStatepointsForGC.cpp
test/Transforms/PlaceSafepoints/statepoint-coreclr.ll [new file with mode: 0644]

index 5bae41ea03057d5434799b09a039f4276199f844..64a01a3c1b494cd34fa9cb92b04614b762771fea 100644 (file)
@@ -21,6 +21,9 @@ class GCMetadataPrinter;
 /// 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.\r
+void linkCoreCLRGC();
+
 /// Creates an ocaml-compatible garbage collector.
 void linkOcamlGC();
 
index e7ccbfa617e52f93e57a1d6bab7d9a621ec0e8f7..fee131e4a3c6b73211796a3ac98e7e1edf9b0e66 100644 (file)
@@ -36,6 +36,7 @@ namespace {
       (void) llvm::createGreedyRegisterAllocator();
       (void) llvm::createDefaultPBQPRegisterAllocator();
 
+      llvm::linkCoreCLRGC();
       llvm::linkOcamlGC();
       llvm::linkErlangGC();
       llvm::linkShadowStackGC();
index 6ce5b13ea3938344ff83544bf52dd543d624e031..9fc3e0bcec9a6345f445a865050d0925d2ec3d9e 100644 (file)
@@ -9,6 +9,7 @@ add_llvm_library(LLVMCodeGen
   CallingConvLower.cpp
   CodeGen.cpp
   CodeGenPrepare.cpp
+  CoreCLRGC.cpp
   CriticalAntiDepBreaker.cpp
   DFAPacketizer.cpp
   DeadMachineInstructionElim.cpp
diff --git a/lib/CodeGen/CoreCLRGC.cpp b/lib/CodeGen/CoreCLRGC.cpp
new file mode 100644 (file)
index 0000000..2726180
--- /dev/null
@@ -0,0 +1,55 @@
+//===-- CoreCLRGC.cpp - CoreCLR Runtime GC Strategy -----------------------===//\r
+//\r
+//                     The LLVM Compiler Infrastructure\r
+//\r
+// This file is distributed under the University of Illinois Open Source\r
+// License. See LICENSE.TXT for details.\r
+//\r
+//===----------------------------------------------------------------------===//\r
+//\r
+// This file contains a GCStrategy for the CoreCLR Runtime.\r
+// The strategy is similar to Statepoint-example GC, but differs from it in\r
+// certain aspects, such as:\r
+// 1) Base-pointers need not be explicitly tracked and reported for\r
+//    interior pointers\r
+// 2) Uses a different format for encoding stack-maps\r
+// 3) Location of Safe-point polls: polls are only needed before loop-back edges\r
+//    and before tail-calls (not needed at function-entry)\r
+//\r
+// The above differences in behavior are to be implemented in upcoming checkins.\r
+//\r
+//===----------------------------------------------------------------------===//\r
+\r
+#include "llvm/CodeGen/GCStrategy.h"\r
+#include "llvm/IR/DerivedTypes.h"\r
+#include "llvm/IR/Value.h"\r
+\r
+using namespace llvm;\r
+\r
+namespace {\r
+class CoreCLRGC : public GCStrategy {\r
+public:\r
+  CoreCLRGC() {\r
+    UseStatepoints = true;\r
+    // These options are all gc.root specific, we specify them so that the\r
+    // gc.root lowering code doesn't run.\r
+    InitRoots = false;\r
+    NeededSafePoints = 0;\r
+    UsesMetadata = false;\r
+    CustomRoots = false;\r
+  }\r
+  Optional<bool> isGCManagedPointer(const Value *V) const override {\r
+    // Method is only valid on pointer typed values.\r
+    PointerType *PT = cast<PointerType>(V->getType());\r
+    // We pick addrspace(1) as our GC managed heap. \r
+    return (1 == PT->getAddressSpace());\r
+  }\r
+};\r
+}\r
+\r
+static GCRegistry::Add<CoreCLRGC> X("coreclr",\r
+                                    "CoreCLR-compatible GC");\r
+\r
+namespace llvm {\r
+void linkCoreCLRGC() {}\r
+}\r
index fc1453b31751cdbfe0d12ca55186f4803043b289..9e7a4d8febcb7f65e4dfd368fd0962ed5770c676 100644 (file)
@@ -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"
@@ -523,8 +524,11 @@ static bool isGCSafepointPoll(Function &F) {
 static bool shouldRewriteFunction(Function &F) {
   // TODO: This should check the GCStrategy
   if (F.hasGC()) {
-    const std::string StatepointExampleName("statepoint-example");
-    return StatepointExampleName == F.getGC();
+    const char *FunctionGCName = F.getGC();\r
+    const StringRef StatepointExampleName("statepoint-example");\r
+    const StringRef CoreCLRName("coreclr");\r
+    return (StatepointExampleName == FunctionGCName) ||\r
+      (CoreCLRName == FunctionGCName);
   } else
     return false;
 }
index a692d61bfa6f736b05fa90dccaf99408ad8a67bd..505070552c188e10d6eb444a1e1fbe145863dc3d 100644 (file)
@@ -19,6 +19,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"
@@ -2201,9 +2202,13 @@ static bool insertParsePoints(Function &F, DominatorTree &DT, Pass *P,
 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
+    const char *FunctionGCName = F.getGC();\r
+    const StringRef StatepointExampleName("statepoint-example");\r
+    const StringRef CoreCLRName("coreclr");\r
+    return (StatepointExampleName == FunctionGCName) ||\r
+      (CoreCLRName == FunctionGCName);
+  }
+  else
     return false;
 }
 
diff --git a/test/Transforms/PlaceSafepoints/statepoint-coreclr.ll b/test/Transforms/PlaceSafepoints/statepoint-coreclr.ll
new file mode 100644 (file)
index 0000000..dc46896
--- /dev/null
@@ -0,0 +1,31 @@
+; RUN: opt %s -S -place-safepoints | FileCheck %s\r
+\r
+; Basic test to make sure that safepoints are placed\r
+; for CoreCLR GC\r
+\r
+declare void @foo()\r
+\r
+define void @test_simple_call() gc "coreclr" {\r
+; CHECK-LABEL: test_simple_call\r
+entry:\r
+  br label %other\r
+other:\r
+; CHECK-LABEL: other\r
+; CHECK: statepoint\r
+; CHECK-NOT: gc.result\r
+  call void @foo()\r
+  ret void\r
+}\r
+\r
+; This function is inlined when inserting a poll.  To avoid recursive\r
+; issues, make sure we don't place safepoints in it.\r
+declare void @do_safepoint()\r
+define void @gc.safepoint_poll() {\r
+; CHECK-LABEL: gc.safepoint_poll\r
+; CHECK-LABEL: entry\r
+; CHECK-NEXT: do_safepoint\r
+; CHECK-NEXT: ret void\r
+entry:\r
+  call void @do_safepoint()\r
+  ret void\r
+}\r