Index: llvm/trunk/docs/LangRef.rst =================================================================== --- llvm/trunk/docs/LangRef.rst +++ llvm/trunk/docs/LangRef.rst @@ -1602,6 +1602,18 @@ 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 Index: llvm/trunk/docs/Statepoints.rst =================================================================== --- llvm/trunk/docs/Statepoints.rst +++ llvm/trunk/docs/Statepoints.rst @@ -251,7 +251,9 @@ 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 ^^^^^^^^^^^^^^^^^^ Index: llvm/trunk/include/llvm/IR/LLVMContext.h =================================================================== --- llvm/trunk/include/llvm/IR/LLVMContext.h +++ llvm/trunk/include/llvm/IR/LLVMContext.h @@ -71,8 +71,9 @@ /// 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. Index: llvm/trunk/lib/IR/LLVMContext.cpp =================================================================== --- llvm/trunk/lib/IR/LLVMContext.cpp +++ llvm/trunk/lib/IR/LLVMContext.cpp @@ -137,6 +137,11 @@ 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; } Index: llvm/trunk/lib/IR/Verifier.cpp =================================================================== --- llvm/trunk/lib/IR/Verifier.cpp +++ llvm/trunk/lib/IR/Verifier.cpp @@ -2513,17 +2513,21 @@ 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, Index: llvm/trunk/lib/Transforms/Scalar/RewriteStatepointsForGC.cpp =================================================================== --- llvm/trunk/lib/Transforms/Scalar/RewriteStatepointsForGC.cpp +++ llvm/trunk/lib/Transforms/Scalar/RewriteStatepointsForGC.cpp @@ -1404,8 +1404,11 @@ 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, Index: llvm/trunk/test/Transforms/RewriteStatepointsForGC/deopt-bundles/basic.ll =================================================================== --- llvm/trunk/test/Transforms/RewriteStatepointsForGC/deopt-bundles/basic.ll +++ llvm/trunk/test/Transforms/RewriteStatepointsForGC/deopt-bundles/basic.ll @@ -63,3 +63,11 @@ %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 +} Index: llvm/trunk/test/Verifier/operand-bundles.ll =================================================================== --- llvm/trunk/test/Verifier/operand-bundles.ll +++ llvm/trunk/test/Verifier/operand-bundles.ll @@ -47,3 +47,16 @@ %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 +}