From 1af3705c7fe23db9d5308bfdf07bfbd04398b895 Mon Sep 17 00:00:00 2001 From: Philip Reames Date: Wed, 27 May 2020 09:14:54 -0700 Subject: [PATCH] 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 --- .../CodeGen/SelectionDAG/SelectionDAGBuilder.cpp | 1 + .../CodeGen/SelectionDAG/StatepointLowering.cpp | 22 +++++++++++++++++++--- llvm/lib/IR/Verifier.cpp | 14 ++++++++++++++ .../X86/statepoint-gctransition-call-lowering.ll | 15 +++++++++++++++ llvm/test/CodeGen/X86/statepoint-regs.ll | 17 +++++++++++++++++ 5 files changed, 66 insertions(+), 3 deletions(-) diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp index dd03e41..c1b4d74 100644 --- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp @@ -2775,6 +2775,7 @@ void SelectionDAGBuilder::visitInvoke(const InvokeInst &I) { // Deopt bundles are lowered in LowerCallSiteWithDeoptBundle, and we don't // have to do anything here to lower funclet bundles. assert(!I.hasOperandBundlesOtherThan({LLVMContext::OB_deopt, + LLVMContext::OB_gc_transition, LLVMContext::OB_funclet, LLVMContext::OB_cfguardtarget}) && "Cannot lower invokes with arbitrary operand bundles yet!"); diff --git a/llvm/lib/CodeGen/SelectionDAG/StatepointLowering.cpp b/llvm/lib/CodeGen/SelectionDAG/StatepointLowering.cpp index d64515d..9a35bd4 100644 --- a/llvm/lib/CodeGen/SelectionDAG/StatepointLowering.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/StatepointLowering.cpp @@ -866,10 +866,26 @@ SelectionDAGBuilder::LowerStatepoint(ImmutableStatepoint ISP, SI.GCArgs = ArrayRef(ISP.gc_args_begin(), ISP.gc_args_end()); SI.StatepointInstr = ISP.getInstruction(); - SI.GCTransitionArgs = ArrayRef(ISP.gc_transition_args_begin(), - ISP.gc_transition_args_end()); SI.ID = ISP.getID(); - SI.DeoptState = ArrayRef(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(Inputs.begin(), Inputs.end()); + } else { + SI.DeoptState = ArrayRef(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(Inputs.begin(), Inputs.end()); + } else { + SI.GCTransitionArgs = ArrayRef(ISP.gc_transition_args_begin(), + ISP.gc_transition_args_end()); + } + SI.StatepointFlags = ISP.getFlags(); SI.NumPatchBytes = ISP.getNumPatchBytes(); SI.EHPadBB = EHPadBB; diff --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp index 5ca6762..f4680ff 100644 --- a/llvm/lib/IR/Verifier.cpp +++ b/llvm/lib/IR/Verifier.cpp @@ -2085,6 +2085,13 @@ void Verifier::verifyStatepoint(const CallBase &Call) { "gc.statepoint number of transition arguments must be positive", Call); 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); Assert(isa(NumDeoptArgsV), "gc.statepoint number of deoptimization arguments " @@ -2096,6 +2103,13 @@ void Verifier::verifyStatepoint(const CallBase &Call) { "must be positive", 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 = 7 + NumCallArgs + NumTransitionArgs + NumDeoptArgs; Assert(ExpectedNumArgs <= (int)Call.arg_size(), diff --git a/llvm/test/CodeGen/X86/statepoint-gctransition-call-lowering.ll b/llvm/test/CodeGen/X86/statepoint-gctransition-call-lowering.ll index 90f2002..c98badf 100644 --- a/llvm/test/CodeGen/X86/statepoint-gctransition-call-lowering.ll +++ b/llvm/test/CodeGen/X86/statepoint-gctransition-call-lowering.ll @@ -116,6 +116,21 @@ entry: 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 i1 @llvm.experimental.gc.result.i1(token) diff --git a/llvm/test/CodeGen/X86/statepoint-regs.ll b/llvm/test/CodeGen/X86/statepoint-regs.ll index 0f5bad8..b137b18 100644 --- a/llvm/test/CodeGen/X86/statepoint-regs.ll +++ b/llvm/test/CodeGen/X86/statepoint-regs.ll @@ -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) 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: .long Ltmp18-_test_fpconst_deopt ; CHECK-NEXT: .short 0 -- 2.7.4