Start migrating away from statepoint's inline length prefixed argument bundles

In the current statepoint design, we have four distinct groups of operands to the call: call args, gc transition args, deopt args, and gc args. This format prexisted the support in IR for operand bundles and was in fact one of the inspirations for the extension. However, we never went back and rearchitected statepoints to fully leverage bundles.

This change is the first in a small sequence to do so. All this does is extend the SelectionDAG lowering code to allow deopt and gc transition operands to be specified in either inline argument bundles or operand bundles.

Differential Revision: https://reviews.llvm.org/D8059
This commit is contained in:
Philip Reames 2020-05-27 09:14:54 -07:00
parent 495f18292b
commit 1af3705c7f
5 changed files with 66 additions and 3 deletions

View File

@ -2775,6 +2775,7 @@ void SelectionDAGBuilder::visitInvoke(const InvokeInst &I) {
// Deopt bundles are lowered in LowerCallSiteWithDeoptBundle, and we don't // Deopt bundles are lowered in LowerCallSiteWithDeoptBundle, and we don't
// have to do anything here to lower funclet bundles. // have to do anything here to lower funclet bundles.
assert(!I.hasOperandBundlesOtherThan({LLVMContext::OB_deopt, assert(!I.hasOperandBundlesOtherThan({LLVMContext::OB_deopt,
LLVMContext::OB_gc_transition,
LLVMContext::OB_funclet, LLVMContext::OB_funclet,
LLVMContext::OB_cfguardtarget}) && LLVMContext::OB_cfguardtarget}) &&
"Cannot lower invokes with arbitrary operand bundles yet!"); "Cannot lower invokes with arbitrary operand bundles yet!");

View File

@ -866,10 +866,26 @@ SelectionDAGBuilder::LowerStatepoint(ImmutableStatepoint ISP,
SI.GCArgs = ArrayRef<const Use>(ISP.gc_args_begin(), ISP.gc_args_end()); SI.GCArgs = ArrayRef<const Use>(ISP.gc_args_begin(), ISP.gc_args_end());
SI.StatepointInstr = ISP.getInstruction(); SI.StatepointInstr = ISP.getInstruction();
SI.GCTransitionArgs = ArrayRef<const Use>(ISP.gc_transition_args_begin(),
ISP.gc_transition_args_end());
SI.ID = ISP.getID(); SI.ID = ISP.getID();
SI.DeoptState = ArrayRef<const Use>(ISP.deopt_begin(), ISP.deopt_end());
if (auto Opt = ISP.getCall()->getOperandBundle(LLVMContext::OB_deopt)) {
assert(ISP.deopt_begin() == ISP.deopt_end() &&
"can't list both deopt operands and deopt bundle");
auto &Inputs = Opt->Inputs;
SI.DeoptState = ArrayRef<const Use>(Inputs.begin(), Inputs.end());
} else {
SI.DeoptState = ArrayRef<const Use>(ISP.deopt_begin(), ISP.deopt_end());
}
if (auto Opt = ISP.getCall()->getOperandBundle(LLVMContext::OB_gc_transition)) {
assert(ISP.gc_transition_args_begin() == ISP.gc_transition_args_end() &&
"can't list both gc_transition operands and bundle");
auto &Inputs = Opt->Inputs;
SI.GCTransitionArgs = ArrayRef<const Use>(Inputs.begin(), Inputs.end());
} else {
SI.GCTransitionArgs = ArrayRef<const Use>(ISP.gc_transition_args_begin(),
ISP.gc_transition_args_end());
}
SI.StatepointFlags = ISP.getFlags(); SI.StatepointFlags = ISP.getFlags();
SI.NumPatchBytes = ISP.getNumPatchBytes(); SI.NumPatchBytes = ISP.getNumPatchBytes();
SI.EHPadBB = EHPadBB; SI.EHPadBB = EHPadBB;

View File

@ -2085,6 +2085,13 @@ void Verifier::verifyStatepoint(const CallBase &Call) {
"gc.statepoint number of transition arguments must be positive", Call); "gc.statepoint number of transition arguments must be positive", Call);
const int EndTransitionArgsInx = EndCallArgsInx + 1 + NumTransitionArgs; const int EndTransitionArgsInx = EndCallArgsInx + 1 + NumTransitionArgs;
// We're migrating away from inline operands to operand bundles, enforce
// the either/or property during transition.
if (Call.getOperandBundle(LLVMContext::OB_gc_transition)) {
Assert(NumTransitionArgs == 0,
"can't use both deopt operands and deopt bundle on a statepoint");
}
const Value *NumDeoptArgsV = Call.getArgOperand(EndTransitionArgsInx + 1); const Value *NumDeoptArgsV = Call.getArgOperand(EndTransitionArgsInx + 1);
Assert(isa<ConstantInt>(NumDeoptArgsV), Assert(isa<ConstantInt>(NumDeoptArgsV),
"gc.statepoint number of deoptimization arguments " "gc.statepoint number of deoptimization arguments "
@ -2096,6 +2103,13 @@ void Verifier::verifyStatepoint(const CallBase &Call) {
"must be positive", "must be positive",
Call); Call);
// We're migrating away from inline operands to operand bundles, enforce
// the either/or property during transition.
if (Call.getOperandBundle(LLVMContext::OB_deopt)) {
Assert(NumDeoptArgs == 0,
"can't use both deopt operands and deopt bundle on a statepoint");
}
const int ExpectedNumArgs = const int ExpectedNumArgs =
7 + NumCallArgs + NumTransitionArgs + NumDeoptArgs; 7 + NumCallArgs + NumTransitionArgs + NumDeoptArgs;
Assert(ExpectedNumArgs <= (int)Call.arg_size(), Assert(ExpectedNumArgs <= (int)Call.arg_size(),

View File

@ -116,6 +116,21 @@ entry:
ret i32 %call1 ret i32 %call1
} }
; Same as test_transition_args_2 except using bundle format
define i32 @test_bundle() gc "statepoint-example" {
; CHECK-LABEL: test_bundle
; CHECK: pushq %rax
; CHECK: callq return_i32
; CHECK: popq %rcx
; CHECK: retq
entry:
%val = alloca i32
%arg = alloca i8
%safepoint_token = call token (i64, i32, i32 (i32, i8*)*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_i32i32p0i8f(i64 0, i32 0, i32 (i32, i8*)* @return_i32_with_args, i32 2, i32 1, i32 0, i8* %arg, i32 0, i32 0) ["gc-transition" (i32* %val, i64 42)]
%call1 = call i32 @llvm.experimental.gc.result.i32(token %safepoint_token)
ret i32 %call1
}
declare token @llvm.experimental.gc.statepoint.p0f_i1f(i64, i32, i1 ()*, i32, i32, ...) declare token @llvm.experimental.gc.statepoint.p0f_i1f(i64, i32, i1 ()*, i32, i32, ...)
declare i1 @llvm.experimental.gc.result.i1(token) declare i1 @llvm.experimental.gc.result.i1(token)

View File

@ -691,6 +691,23 @@ define i32 addrspace(1)* @test_fpconst_deopt(i32 addrspace(1)* %in) gc "statepo
%out = call coldcc i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token %statepoint_token, i32 27, i32 27) %out = call coldcc i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token %statepoint_token, i32 27, i32 27)
ret i32 addrspace(1)* %out ret i32 addrspace(1)* %out
} }
; Same as test1, but using deopt bundle
define void @test1b(i32 %a) gc "statepoint-example" {
; CHECK-LABEL: test1b:
; CHECK: ## %bb.0: ## %entry
; CHECK-NEXT: pushq %rax
; CHECK-NEXT: .cfi_def_cfa_offset 16
; CHECK-NEXT: movl %edi, {{[-0-9]+}}(%r{{[sb]}}p) ## 4-byte Spill
; CHECK-NEXT: callq _bar ## 4-byte Folded Reload
; CHECK-NEXT: Ltmp19:
; CHECK-NEXT: popq %rax
; CHECK-NEXT: retq
entry:
%statepoint_token1 = call token (i64, i32, void ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_isVoidf(i64 2882400000, i32 0, void ()* @bar, i32 0, i32 0, i32 0, i32 0) ["deopt" (i32 %a)]
ret void
}
; CHECK-LABEL: __LLVM_StackMaps: ; CHECK-LABEL: __LLVM_StackMaps:
; CHECK: .long Ltmp18-_test_fpconst_deopt ; CHECK: .long Ltmp18-_test_fpconst_deopt
; CHECK-NEXT: .short 0 ; CHECK-NEXT: .short 0