diff options
-rw-r--r-- | llvm/docs/LangRef.rst | 12 | ||||
-rw-r--r-- | llvm/docs/Statepoints.rst | 4 | ||||
-rw-r--r-- | llvm/include/llvm/IR/LLVMContext.h | 5 | ||||
-rw-r--r-- | llvm/lib/IR/LLVMContext.cpp | 5 | ||||
-rw-r--r-- | llvm/lib/IR/Verifier.cpp | 14 | ||||
-rw-r--r-- | llvm/lib/Transforms/Scalar/RewriteStatepointsForGC.cpp | 7 | ||||
-rw-r--r-- | llvm/test/Transforms/RewriteStatepointsForGC/deopt-bundles/basic.ll | 8 | ||||
-rw-r--r-- | llvm/test/Verifier/operand-bundles.ll | 13 |
8 files changed, 58 insertions, 10 deletions
diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst index 5f8a3a5a4a9..1932cb6d843 100644 --- a/llvm/docs/LangRef.rst +++ b/llvm/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 +<gc_transition_args>`. + .. _moduleasm: Module-Level Inline Assembly diff --git a/llvm/docs/Statepoints.rst b/llvm/docs/Statepoints.rst index 084aa62a5cb..b0e4f813179 100644 --- a/llvm/docs/Statepoints.rst +++ b/llvm/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/llvm/include/llvm/IR/LLVMContext.h b/llvm/include/llvm/IR/LLVMContext.h index 56aa3010d92..5b8512b762e 100644 --- a/llvm/include/llvm/IR/LLVMContext.h +++ b/llvm/include/llvm/IR/LLVMContext.h @@ -71,8 +71,9 @@ public: /// 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/llvm/lib/IR/LLVMContext.cpp b/llvm/lib/IR/LLVMContext.cpp index 48b53b0f532..5e6fe69af97 100644 --- a/llvm/lib/IR/LLVMContext.cpp +++ b/llvm/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/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp index 40184608752..3dff4d1451f 100644 --- a/llvm/lib/IR/Verifier.cpp +++ b/llvm/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/llvm/lib/Transforms/Scalar/RewriteStatepointsForGC.cpp b/llvm/lib/Transforms/Scalar/RewriteStatepointsForGC.cpp index e4e79c6c2c1..cefacbd962e 100644 --- a/llvm/lib/Transforms/Scalar/RewriteStatepointsForGC.cpp +++ b/llvm/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/llvm/test/Transforms/RewriteStatepointsForGC/deopt-bundles/basic.ll b/llvm/test/Transforms/RewriteStatepointsForGC/deopt-bundles/basic.ll index c0dc6940e5d..1881897d7d4 100644 --- a/llvm/test/Transforms/RewriteStatepointsForGC/deopt-bundles/basic.ll +++ b/llvm/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/llvm/test/Verifier/operand-bundles.ll b/llvm/test/Verifier/operand-bundles.ll index d822568a044..2598a7889f3 100644 --- a/llvm/test/Verifier/operand-bundles.ll +++ b/llvm/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 +} |