Index: docs/LangRef.rst =================================================================== --- docs/LangRef.rst +++ docs/LangRef.rst @@ -1602,6 +1602,14 @@ 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. + +TODO + .. _moduleasm: Module-Level Inline Assembly Index: include/llvm/IR/LLVMContext.h =================================================================== --- include/llvm/IR/LLVMContext.h +++ 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: lib/IR/LLVMContext.cpp =================================================================== --- lib/IR/LLVMContext.cpp +++ 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: lib/IR/Verifier.cpp =================================================================== --- lib/IR/Verifier.cpp +++ lib/IR/Verifier.cpp @@ -2514,7 +2514,8 @@ // Verify that a callsite has at most one "deopt" and one "funclet" operand // bundle. - bool FoundDeoptBundle = false, FoundFuncletBundle = false; + 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(); @@ -2522,6 +2523,11 @@ Assert(!FoundDeoptBundle, "Multiple deopt operand bundles", I); FoundDeoptBundle = true; } + if (Tag == LLVMContext::OB_gc_transition) { + Assert(!FoundGCTransitionBundle, "Multiple gc-transition operand bundles", + I); + FoundGCTransitionBundle = true; + } if (Tag == LLVMContext::OB_funclet) { Assert(!FoundFuncletBundle, "Multiple funclet operand bundles", I); FoundFuncletBundle = true; Index: lib/Transforms/Scalar/RewriteStatepointsForGC.cpp =================================================================== --- lib/Transforms/Scalar/RewriteStatepointsForGC.cpp +++ 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: test/Transforms/RewriteStatepointsForGC/deopt-bundles/basic.ll =================================================================== --- test/Transforms/RewriteStatepointsForGC/deopt-bundles/basic.ll +++ 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: test/Verifier/operand-bundles.ll =================================================================== --- test/Verifier/operand-bundles.ll +++ 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 +}