From e6a9ed76ea485d664091c9e0c27c0d7186cbfd1d Mon Sep 17 00:00:00 2001 From: Sanjoy Das Date: Wed, 20 Jan 2016 19:50:25 +0000 Subject: [PATCH] Add a "gc-transition" operand bundle Summary: This adds a new kind of operand bundle to LLVM denoted by the `"gc-transition"` tag. Inputs to `"gc-transition"` operand bundle are lowered into the "transition args" section of `gc.statepoint` by `RewriteStatepointsForGC`. This removes the last bit of functionality that was unsupported in the deopt bundle based code path in `RewriteStatepointsForGC`. Reviewers: pgavlin, JosephTremoulet, reames Subscribers: sanjoy, mcrosier, llvm-commits Differential Revision: http://reviews.llvm.org/D16342 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@258338 91177308-0d34-0410-b5e6-96231b3b80d8 --- docs/LangRef.rst | 12 ++++++++++++ docs/Statepoints.rst | 4 +++- include/llvm/IR/LLVMContext.h | 5 +++-- lib/IR/LLVMContext.cpp | 5 +++++ lib/IR/Verifier.cpp | 14 +++++++++----- lib/Transforms/Scalar/RewriteStatepointsForGC.cpp | 7 +++++-- .../RewriteStatepointsForGC/deopt-bundles/basic.ll | 8 ++++++++ test/Verifier/operand-bundles.ll | 13 +++++++++++++ 8 files changed, 58 insertions(+), 10 deletions(-) diff --git a/docs/LangRef.rst b/docs/LangRef.rst index 5f8a3a5a4a98..1932cb6d8437 100644 --- a/docs/LangRef.rst +++ b/docs/LangRef.rst @@ -1602,6 +1602,18 @@ it is undefined behavior to execute a ``call`` or ``invoke`` which: Similarly, if no funclet EH pads have been entered-but-not-yet-exited, executing a ``call`` or ``invoke`` with a ``"funclet"`` bundle is undefined behavior. +GC Transition Operand Bundles +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +GC transition operand bundles are characterized by the +``"gc-transition"`` operand bundle tag. These operand bundles mark a +call as a transition between a function with one GC strategy to a +function with a different GC strategy. If coordinating the transition +between GC strategies requires additional code generation at the call +site, these bundles may contain any values that are needed by the +generated code. For more details, see :ref:`GC Transitions +`. + .. _moduleasm: Module-Level Inline Assembly diff --git a/docs/Statepoints.rst b/docs/Statepoints.rst index 084aa62a5cb7..b0e4f8131790 100644 --- a/docs/Statepoints.rst +++ b/docs/Statepoints.rst @@ -251,7 +251,9 @@ we get: Note that in this example %p and %obj.relocate are the same address and we could replace one with the other, potentially removing the derived pointer -from the live set at the safepoint entirely. +from the live set at the safepoint entirely. + +.. _gc_transition_args: GC Transitions ^^^^^^^^^^^^^^^^^^ diff --git a/include/llvm/IR/LLVMContext.h b/include/llvm/IR/LLVMContext.h index 56aa3010d925..5b8512b762ed 100644 --- a/include/llvm/IR/LLVMContext.h +++ b/include/llvm/IR/LLVMContext.h @@ -71,8 +71,9 @@ class LLVMContext { /// Additionally, this scheme allows LLVM to efficiently check for specific /// operand bundle tags without comparing strings. enum { - OB_deopt = 0, // "deopt" - OB_funclet = 1, // "funclet" + OB_deopt = 0, // "deopt" + OB_funclet = 1, // "funclet" + OB_gc_transition = 2, // "gc-transition" }; /// getMDKindID - Return a unique non-zero ID for the specified metadata kind. diff --git a/lib/IR/LLVMContext.cpp b/lib/IR/LLVMContext.cpp index 48b53b0f532a..5e6fe69af977 100644 --- a/lib/IR/LLVMContext.cpp +++ b/lib/IR/LLVMContext.cpp @@ -137,6 +137,11 @@ LLVMContext::LLVMContext() : pImpl(new LLVMContextImpl(*this)) { assert(FuncletEntry->second == LLVMContext::OB_funclet && "funclet operand bundle id drifted!"); (void)FuncletEntry; + + auto *GCTransitionEntry = pImpl->getOrInsertBundleTag("gc-transition"); + assert(GCTransitionEntry->second == LLVMContext::OB_gc_transition && + "gc-transition operand bundle id drifted!"); + (void)GCTransitionEntry; } LLVMContext::~LLVMContext() { delete pImpl; } diff --git a/lib/IR/Verifier.cpp b/lib/IR/Verifier.cpp index 401846087528..3dff4d1451ff 100644 --- a/lib/IR/Verifier.cpp +++ b/lib/IR/Verifier.cpp @@ -2513,17 +2513,21 @@ void Verifier::VerifyCallSite(CallSite CS) { if (Intrinsic::ID ID = (Intrinsic::ID)F->getIntrinsicID()) visitIntrinsicCallSite(ID, CS); - // Verify that a callsite has at most one "deopt" and one "funclet" operand - // bundle. - bool FoundDeoptBundle = false, FoundFuncletBundle = false; + // Verify that a callsite has at most one "deopt", at most one "funclet" and + // at most one "gc-transition" operand bundle. + bool FoundDeoptBundle = false, FoundFuncletBundle = false, + FoundGCTransitionBundle = false; for (unsigned i = 0, e = CS.getNumOperandBundles(); i < e; ++i) { OperandBundleUse BU = CS.getOperandBundleAt(i); uint32_t Tag = BU.getTagID(); if (Tag == LLVMContext::OB_deopt) { Assert(!FoundDeoptBundle, "Multiple deopt operand bundles", I); FoundDeoptBundle = true; - } - if (Tag == LLVMContext::OB_funclet) { + } else if (Tag == LLVMContext::OB_gc_transition) { + Assert(!FoundGCTransitionBundle, "Multiple gc-transition operand bundles", + I); + FoundGCTransitionBundle = true; + } else if (Tag == LLVMContext::OB_funclet) { Assert(!FoundFuncletBundle, "Multiple funclet operand bundles", I); FoundFuncletBundle = true; Assert(BU.Inputs.size() == 1, diff --git a/lib/Transforms/Scalar/RewriteStatepointsForGC.cpp b/lib/Transforms/Scalar/RewriteStatepointsForGC.cpp index e4e79c6c2c1c..cefacbd962e2 100644 --- a/lib/Transforms/Scalar/RewriteStatepointsForGC.cpp +++ b/lib/Transforms/Scalar/RewriteStatepointsForGC.cpp @@ -1404,8 +1404,11 @@ makeStatepointExplicitImpl(const CallSite CS, /* to replace */ if (UseDeoptBundles) { CallArgs = {CS.arg_begin(), CS.arg_end()}; DeoptArgs = GetDeoptBundleOperands(CS); - // TODO: we don't fill in TransitionArgs or Flags in this branch, but we - // could have an operand bundle for that too. + if (auto TransitionBundle = + CS.getOperandBundle(LLVMContext::OB_gc_transition)) { + Flags |= uint32_t(StatepointFlags::GCTransition); + TransitionArgs = TransitionBundle->Inputs; + } AttributeSet OriginalAttrs = CS.getAttributes(); Attribute AttrID = OriginalAttrs.getAttribute(AttributeSet::FunctionIndex, diff --git a/test/Transforms/RewriteStatepointsForGC/deopt-bundles/basic.ll b/test/Transforms/RewriteStatepointsForGC/deopt-bundles/basic.ll index c0dc6940e5db..1881897d7d45 100644 --- a/test/Transforms/RewriteStatepointsForGC/deopt-bundles/basic.ll +++ b/test/Transforms/RewriteStatepointsForGC/deopt-bundles/basic.ll @@ -63,3 +63,11 @@ define i32 addrspace(1)* @f3(i32 addrspace(1)* %arg) gc "statepoint-example" pe %lpad = landingpad token cleanup resume token undef } + +define i32 addrspace(1)* @f4(i32 addrspace(1)* %arg) gc "statepoint-example" { +; CHECK-LABEL: @f4( + entry: +; CHECK: @llvm.experimental.gc.statepoint.p0f_isVoidf(i64 2882400000, i32 0, void ()* @g, i32 0, i32 1, i32 2, i32 400, i8 90, + call void @g() [ "gc-transition"(i32 400, i8 90) ] + ret i32 addrspace(1)* %arg +} diff --git a/test/Verifier/operand-bundles.ll b/test/Verifier/operand-bundles.ll index d822568a0445..2598a7889f3f 100644 --- a/test/Verifier/operand-bundles.ll +++ b/test/Verifier/operand-bundles.ll @@ -47,3 +47,16 @@ define void @f_deopt(i32* %ptr) { %x = add i32 42, 1 ret void } + +define void @f_gc_transition(i32* %ptr) { +; CHECK: Multiple gc-transition operand bundles +; CHECK-NEXT: call void @g() [ "gc-transition"(i32 42, i64 100, i32 %x), "gc-transition"(float 0.000000e+00, i64 100, i32 %l) ] +; CHECK-NOT: call void @g() [ "gc-transition"(i32 42, i64 120, i32 %x) ] + + entry: + %l = load i32, i32* %ptr + call void @g() [ "gc-transition"(i32 42, i64 100, i32 %x), "gc-transition"(float 0.0, i64 100, i32 %l) ] + call void @g() [ "gc-transition"(i32 42, i64 120) ] ;; The verifier should not complain about this one + %x = add i32 42, 1 + ret void +}