forked from OSchip/llvm-project
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:
parent
495f18292b
commit
1af3705c7f
|
@ -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!");
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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(),
|
||||||
|
|
|
@ -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)
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue