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

llvm-svn: 258338
This commit is contained in:
Sanjoy Das 2016-01-20 19:50:25 +00:00
parent af69f1c690
commit a34ce95b60
8 changed files with 58 additions and 10 deletions

View File

@ -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

View File

@ -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
^^^^^^^^^^^^^^^^^^

View File

@ -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.

View File

@ -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; }

View File

@ -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,

View File

@ -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,

View File

@ -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
}

View File

@ -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
}