[StatepointLowering] Don't create temporary instructions. NFCI.

Summary:
Instead of creating a temporary call instruction and lowering that, use
SelectionDAGBuilder::lowerCallOperands.

Reviewers: reames

Subscribers: llvm-commits

Differential Revision: http://reviews.llvm.org/D9480

llvm-svn: 236563
This commit is contained in:
Sanjoy Das 2015-05-06 02:36:20 +00:00
parent 5191911a57
commit c6bf3e9f12
3 changed files with 105 additions and 71 deletions

View File

@ -72,6 +72,13 @@ class StatepointBase {
ValueTy *actualCallee() {
return StatepointCS.getArgument(0);
}
/// Return the type of the value returned by the call underlying the
/// statepoint.
Type *actualReturnType() {
auto *FTy = cast<FunctionType>(
cast<PointerType>(actualCallee()->getType())->getElementType());
return FTy->getReturnType();
}
/// Number of arguments to be passed to the actual callee.
int numCallArgs() {
return cast<ConstantInt>(StatepointCS.getArgument(1))->getZExtValue();
@ -82,14 +89,16 @@ class StatepointBase {
return cast<ConstantInt>(StatepointCS.getArgument(3 + numCallArgs()))->getZExtValue();
}
int callArgsBeginOffset() { return 3; }
typename CallSiteTy::arg_iterator call_args_begin() {
// 3 = callTarget, #callArgs, flag
int Offset = 3;
int Offset = callArgsBeginOffset();
assert(Offset <= (int)StatepointCS.arg_size());
return StatepointCS.arg_begin() + Offset;
}
typename CallSiteTy::arg_iterator call_args_end() {
int Offset = 3 + numCallArgs();
int Offset = callArgsBeginOffset() + numCallArgs();
assert(Offset <= (int)StatepointCS.arg_size());
return StatepointCS.arg_begin() + Offset;
}

View File

@ -222,33 +222,61 @@ static void removeDuplicatesGCPtrs(SmallVectorImpl<const Value *> &Bases,
/// Extract call from statepoint, lower it and return pointer to the
/// call node. Also update NodeMap so that getValue(statepoint) will
/// reference lowered call result
static SDNode *lowerCallFromStatepoint(ImmutableStatepoint StatepointSite,
MachineBasicBlock *LandingPad,
SelectionDAGBuilder &Builder) {
static SDNode *
lowerCallFromStatepoint(ImmutableStatepoint ISP, MachineBasicBlock *LandingPad,
SelectionDAGBuilder &Builder,
SmallVectorImpl<SDValue> &PendingExports) {
ImmutableCallSite CS(StatepointSite.getCallSite());
ImmutableCallSite CS(ISP.getCallSite());
// Lower the actual call itself - This is a bit of a hack, but we want to
// avoid modifying the actual lowering code. This is similiar in intent to
// the LowerCallOperands mechanism used by PATCHPOINT, but is structured
// differently. Hopefully, this is slightly more robust w.r.t. calling
// convention, return values, and other function attributes.
Value *ActualCallee = const_cast<Value *>(StatepointSite.actualCallee());
SDValue ActualCallee = Builder.getValue(ISP.actualCallee());
std::vector<Value *> Args;
CallInst::const_op_iterator arg_begin = StatepointSite.call_args_begin();
CallInst::const_op_iterator arg_end = StatepointSite.call_args_end();
Args.insert(Args.end(), arg_begin, arg_end);
// TODO: remove the creation of a new instruction! We should not be
// modifying the IR (even temporarily) at this point.
CallInst *Tmp = CallInst::Create(ActualCallee, Args);
Tmp->setTailCall(CS.isTailCall());
Tmp->setCallingConv(CS.getCallingConv());
Tmp->setAttributes(CS.getAttributes());
Builder.LowerCallTo(Tmp, Builder.getValue(ActualCallee), false, LandingPad);
// Handle immediate and symbolic callees.
if (auto *ConstCallee = dyn_cast<ConstantSDNode>(ActualCallee.getNode()))
ActualCallee = Builder.DAG.getIntPtrConstant(ConstCallee->getZExtValue(),
Builder.getCurSDLoc(),
/*isTarget=*/true);
else if (auto *SymbolicCallee =
dyn_cast<GlobalAddressSDNode>(ActualCallee.getNode()))
ActualCallee = Builder.DAG.getTargetGlobalAddress(
SymbolicCallee->getGlobal(), SDLoc(SymbolicCallee),
SymbolicCallee->getValueType(0));
assert(CS.getCallingConv() != CallingConv::AnyReg &&
"anyregcc is not supported on statepoints!");
Type *DefTy = ISP.actualReturnType();
bool HasDef = !DefTy->isVoidTy();
SDValue ReturnValue, CallEndVal;
std::tie(ReturnValue, CallEndVal) = Builder.lowerCallOperands(
ISP.getCallSite(), ISP.callArgsBeginOffset(), ISP.numCallArgs(),
ActualCallee, DefTy, LandingPad, false /* IsPatchPoint */);
SDNode *CallEnd = CallEndVal.getNode();
// Get a call instruction from the call sequence chain. Tail calls are not
// allowed. The following code is essentially reverse engineering X86's
// LowerCallTo.
//
// We are expecting DAG to have the following form:
//
// ch = eh_label (only in case of invoke statepoint)
// ch, glue = callseq_start ch
// ch, glue = X86::Call ch, glue
// ch, glue = callseq_end ch, glue
// get_return_value ch, glue
//
// get_return_value can either be a CopyFromReg to grab the return value from
// %RAX, or it can be a LOAD to load a value returned by reference via a stack
// slot.
if (HasDef && (CallEnd->getOpcode() == ISD::CopyFromReg ||
CallEnd->getOpcode() == ISD::LOAD))
CallEnd = CallEnd->getOperand(0).getNode();
assert(CallEnd->getOpcode() == ISD::CALLSEQ_END && "expected!");
// Handle the return value of the call iff any.
const bool HasDef = !Tmp->getType()->isVoidTy();
if (HasDef) {
if (CS.isInvoke()) {
// Result value will be used in different basic block for invokes
@ -258,62 +286,29 @@ static SDNode *lowerCallFromStatepoint(ImmutableStatepoint StatepointSite,
// register with correct type and save value into it manually.
// TODO: To eliminate this problem we can remove gc.result intrinsics
// completelly and make statepoint call to return a tuple.
unsigned reg = Builder.FuncInfo.CreateRegs(Tmp->getType());
Builder.CopyValueToVirtualRegister(Tmp, reg);
Builder.FuncInfo.ValueMap[CS.getInstruction()] = reg;
unsigned Reg = Builder.FuncInfo.CreateRegs(ISP.actualReturnType());
RegsForValue RFV(*Builder.DAG.getContext(),
Builder.DAG.getTargetLoweringInfo(), Reg,
ISP.actualReturnType());
SDValue Chain = Builder.DAG.getEntryNode();
RFV.getCopyToRegs(ReturnValue, Builder.DAG, Builder.getCurSDLoc(), Chain,
nullptr);
PendingExports.push_back(Chain);
Builder.FuncInfo.ValueMap[CS.getInstruction()] = Reg;
} else {
// The value of the statepoint itself will be the value of call itself.
// We'll replace the actually call node shortly. gc_result will grab
// this value.
Builder.setValue(CS.getInstruction(), Builder.getValue(Tmp));
Builder.setValue(CS.getInstruction(), ReturnValue);
}
} else {
// The token value is never used from here on, just generate a poison value
Builder.setValue(CS.getInstruction(),
Builder.DAG.getIntPtrConstant(-1, Builder.getCurSDLoc()));
}
// Remove the fake entry we created so we don't have a hanging reference
// after we delete this node.
Builder.removeValue(Tmp);
delete Tmp;
Tmp = nullptr;
// Search for the call node
// The following code is essentially reverse engineering X86's
// LowerCallTo.
// We are expecting DAG to have the following form:
// ch = eh_label (only in case of invoke statepoint)
// ch, glue = callseq_start ch
// ch, glue = X86::Call ch, glue
// ch, glue = callseq_end ch, glue
// ch = eh_label ch (only in case of invoke statepoint)
//
// DAG root will be either last eh_label or callseq_end.
SDNode *CallNode = nullptr;
// We just emitted a call, so it should be last thing generated
SDValue Chain = Builder.DAG.getRoot();
// Find closest CALLSEQ_END walking back through lowered nodes if needed
SDNode *CallEnd = Chain.getNode();
int Sanity = 0;
while (CallEnd->getOpcode() != ISD::CALLSEQ_END) {
assert(CallEnd->getNumOperands() >= 1 &&
CallEnd->getOperand(0).getValueType() == MVT::Other);
CallEnd = CallEnd->getOperand(0).getNode();
assert(Sanity < 20 && "should have found call end already");
Sanity++;
}
assert(CallEnd->getOpcode() == ISD::CALLSEQ_END &&
"Expected a callseq node.");
assert(CallEnd->getGluedNode());
// Step back inside the CALLSEQ
CallNode = CallEnd->getGluedNode();
return CallNode;
return CallEnd->getOperand(0).getNode();
}
/// Callect all gc pointers coming into statepoint intrinsic, clean them up,
@ -586,7 +581,8 @@ void SelectionDAGBuilder::LowerStatepoint(
lowerStatepointMetaArgs(LoweredMetaArgs, ISP, *this);
// Get call node, we will replace it later with statepoint
SDNode *CallNode = lowerCallFromStatepoint(ISP, LandingPad, *this);
SDNode *CallNode =
lowerCallFromStatepoint(ISP, LandingPad, *this, PendingExports);
// Construct the actual STATEPOINT node with all the appropriate arguments
// and return values.

View File

@ -0,0 +1,29 @@
; RUN: llc < %s | FileCheck %s
declare i1024 @g()
define i1024 @f() gc "statepoint-example" {
; CHECK-LABEL: _f
; CHECK: callq _g
%1 = invoke i32 (i1024 ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_i1024f(i1024 ()* @g, i32 0, i32 0, i32 0)
to label %normal unwind label %except
normal: ; preds = %0
%x1 = call i1024 @llvm.experimental.gc.result.i1024(i32 %1)
ret i1024 %x1
except: ; preds = %0
%landing_pad = landingpad { i8*, i32 } personality i32 ()* @personality_function
cleanup
ret i1024 0
}
declare i32 @personality_function()
; Function Attrs: nounwind
declare i32 @llvm.experimental.gc.statepoint.p0f_i1024f(i1024 ()*, i32, i32, ...) #0
; Function Attrs: nounwind
declare i1024 @llvm.experimental.gc.result.i1024(i32) #0
attributes #0 = { nounwind }