forked from OSchip/llvm-project
Lower stackmap intrinsics directly to their target opcode in the DAG builder.
llvm-svn: 193769
This commit is contained in:
parent
2af716afbe
commit
74f4c749cf
|
@ -800,6 +800,19 @@ def LIFETIME_END : Instruction {
|
|||
let AsmString = "LIFETIME_END";
|
||||
let neverHasSideEffects = 1;
|
||||
}
|
||||
def STACKMAP : Instruction {
|
||||
let OutOperandList = (outs);
|
||||
let InOperandList = (ins i32imm:$id, i32imm:$nbytes, variable_ops);
|
||||
let isCall = 1;
|
||||
let mayLoad = 1;
|
||||
}
|
||||
def PATCHPOINT : Instruction {
|
||||
let OutOperandList = (outs);
|
||||
let InOperandList = (ins i32imm:$id, i32imm:$nbytes, unknown:$callee,
|
||||
i32imm:$nargs, variable_ops);
|
||||
let isCall = 1;
|
||||
let mayLoad = 1;
|
||||
}
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
|
|
@ -1920,6 +1920,8 @@ public:
|
|||
ArgListEntry() : isSExt(false), isZExt(false), isInReg(false),
|
||||
isSRet(false), isNest(false), isByVal(false), isReturned(false),
|
||||
Alignment(0) { }
|
||||
|
||||
void setAttributes(ImmutableCallSite *CS, unsigned AttrIdx);
|
||||
};
|
||||
typedef std::vector<ArgListEntry> ArgListTy;
|
||||
|
||||
|
|
|
@ -92,7 +92,19 @@ namespace TargetOpcode {
|
|||
|
||||
/// Lifetime markers.
|
||||
LIFETIME_START = 15,
|
||||
LIFETIME_END = 16
|
||||
LIFETIME_END = 16,
|
||||
|
||||
/// A Stackmap instruction captures the location of live variables at its
|
||||
/// position in the instruction stream. It is followed by a shadow of bytes
|
||||
/// that must lie within the function and not contain another stackmap.
|
||||
STACKMAP = 17,
|
||||
|
||||
/// Patchable call instruction - this instruction represents a call to a
|
||||
/// constant address, followed by a series of NOPs. It is intended to
|
||||
/// support optimizations for dynamic languages (such as javascript) that
|
||||
/// rewrite calls to runtimes with more efficient code sequences.
|
||||
/// This also implies a stack map.
|
||||
PATCHPOINT = 18
|
||||
};
|
||||
} // end namespace TargetOpcode
|
||||
} // end namespace llvm
|
||||
|
|
|
@ -5309,6 +5309,15 @@ SelectionDAGBuilder::visitIntrinsicCall(const CallInst &I, unsigned Intrinsic) {
|
|||
case Intrinsic::donothing:
|
||||
// ignore
|
||||
return 0;
|
||||
case Intrinsic::experimental_stackmap: {
|
||||
visitStackmap(I);
|
||||
return 0;
|
||||
}
|
||||
case Intrinsic::experimental_patchpoint_void:
|
||||
case Intrinsic::experimental_patchpoint_i64: {
|
||||
visitPatchpoint(I);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -5373,15 +5382,8 @@ void SelectionDAGBuilder::LowerCallTo(ImmutableCallSite CS, SDValue Callee,
|
|||
SDValue ArgNode = getValue(V);
|
||||
Entry.Node = ArgNode; Entry.Ty = V->getType();
|
||||
|
||||
unsigned attrInd = i - CS.arg_begin() + 1;
|
||||
Entry.isSExt = CS.paramHasAttr(attrInd, Attribute::SExt);
|
||||
Entry.isZExt = CS.paramHasAttr(attrInd, Attribute::ZExt);
|
||||
Entry.isInReg = CS.paramHasAttr(attrInd, Attribute::InReg);
|
||||
Entry.isSRet = CS.paramHasAttr(attrInd, Attribute::StructRet);
|
||||
Entry.isNest = CS.paramHasAttr(attrInd, Attribute::Nest);
|
||||
Entry.isByVal = CS.paramHasAttr(attrInd, Attribute::ByVal);
|
||||
Entry.isReturned = CS.paramHasAttr(attrInd, Attribute::Returned);
|
||||
Entry.Alignment = CS.getParamAlignment(attrInd);
|
||||
// Skip the first return-type Attribute to get to params.
|
||||
Entry.setAttributes(&CS, i - CS.arg_begin() + 1);
|
||||
Args.push_back(Entry);
|
||||
}
|
||||
|
||||
|
@ -5463,8 +5465,8 @@ void SelectionDAGBuilder::LowerCallTo(ImmutableCallSite CS, SDValue Callee,
|
|||
}
|
||||
|
||||
if (!Result.second.getNode()) {
|
||||
// As a special case, a null chain means that a tail call has been emitted and
|
||||
// the DAG root is already updated.
|
||||
// As a special case, a null chain means that a tail call has been emitted
|
||||
// and the DAG root is already updated.
|
||||
HasTailCall = true;
|
||||
|
||||
// Since there's no actual continuation from this block, nothing can be
|
||||
|
@ -6721,6 +6723,189 @@ void SelectionDAGBuilder::visitVACopy(const CallInst &I) {
|
|||
DAG.getSrcValue(I.getArgOperand(1))));
|
||||
}
|
||||
|
||||
/// \brief Lower an argument list according to the target calling convention.
|
||||
///
|
||||
/// \return A tuple of <return-value, token-chain>
|
||||
///
|
||||
/// This is a helper for lowering intrinsics that follow a target calling
|
||||
/// convention or require stack pointer adjustment. Only a subset of the
|
||||
/// intrinsic's operands need to participate in the calling convention.
|
||||
std::pair<SDValue, SDValue>
|
||||
SelectionDAGBuilder::LowerCallOperands(const CallInst &CI, unsigned ArgIdx,
|
||||
unsigned NumArgs, SDValue Callee) {
|
||||
TargetLowering::ArgListTy Args;
|
||||
Args.reserve(NumArgs);
|
||||
|
||||
// Populate the argument list.
|
||||
// Attributes for args start at offset 1, after the return attribute.
|
||||
ImmutableCallSite CS(&CI);
|
||||
for (unsigned ArgI = ArgIdx, ArgE = ArgIdx + NumArgs, AttrI = ArgIdx + 1;
|
||||
ArgI != ArgE; ++ArgI) {
|
||||
const Value *V = CI.getOperand(ArgI);
|
||||
|
||||
assert(!V->getType()->isEmptyTy() && "Empty type passed to intrinsic.");
|
||||
|
||||
TargetLowering::ArgListEntry Entry;
|
||||
Entry.Node = getValue(V);
|
||||
Entry.Ty = V->getType();
|
||||
Entry.setAttributes(&CS, AttrI);
|
||||
Args.push_back(Entry);
|
||||
}
|
||||
|
||||
TargetLowering::CallLoweringInfo CLI(getRoot(), CI.getType(),
|
||||
/*retSExt*/ false, /*retZExt*/ false, /*isVarArg*/ false, /*isInReg*/ false,
|
||||
NumArgs, CI.getCallingConv(), /*isTailCall*/ false, /*doesNotReturn*/ false,
|
||||
/*isReturnValueUsed*/ CI.use_empty(), Callee, Args, DAG, getCurSDLoc());
|
||||
|
||||
const TargetLowering *TLI = TM.getTargetLowering();
|
||||
return TLI->LowerCallTo(CLI);
|
||||
}
|
||||
|
||||
/// \brief Lower llvm.experimental.stackmap directly to its target opcode.
|
||||
void SelectionDAGBuilder::visitStackmap(const CallInst &CI) {
|
||||
// void @llvm.experimental.stackmap(i32 <id>, i32 <numShadowBytes>,
|
||||
// [live variables...])
|
||||
|
||||
assert(CI.getType()->isVoidTy() && "Stackmap cannot return a value.");
|
||||
|
||||
SDValue Callee = getValue(CI.getCalledValue());
|
||||
|
||||
// Lower into a call sequence with no args and no return value.
|
||||
std::pair<SDValue, SDValue> Result = LowerCallOperands(CI, 0, 0, Callee);
|
||||
// Set the root to the target-lowered call chain.
|
||||
SDValue Chain = Result.second;
|
||||
DAG.setRoot(Chain);
|
||||
|
||||
/// Get a call instruction from the call sequence chain.
|
||||
/// Tail calls are not allowed.
|
||||
SDNode *CallEnd = Chain.getNode();
|
||||
assert(CallEnd->getOpcode() == ISD::CALLSEQ_END &&
|
||||
"Expected a callseq node.");
|
||||
SDNode *Call = CallEnd->getOperand(0).getNode();
|
||||
bool hasGlue = Call->getGluedNode();
|
||||
|
||||
assert(Call->getNumOperands() == hasGlue ? 2 : 1 &&
|
||||
"Unexpected extra stackmap call arguments.");
|
||||
|
||||
// Replace the target specific call node with the stackmap intrinsic.
|
||||
SmallVector<SDValue, 8> Ops;
|
||||
|
||||
// Add the <id> and <numShadowBytes> constants.
|
||||
for (unsigned i = 0; i < 2; ++i) {
|
||||
SDValue tmp = getValue(CI.getOperand(i));
|
||||
Ops.push_back(DAG.getTargetConstant(
|
||||
cast<ConstantSDNode>(tmp)->getZExtValue(), MVT::i32));
|
||||
}
|
||||
// Push live variables for the stack map.
|
||||
for (unsigned i = 2, e = CI.getNumArgOperands(); i != e; ++i)
|
||||
Ops.push_back(getValue(CI.getArgOperand(i)));
|
||||
|
||||
// Push the chain (this is originally the first operand of the call, but
|
||||
// becomes now the last or second to last operand).
|
||||
Ops.push_back(*(Call->op_begin()));
|
||||
|
||||
// Push the glue flag (last operand).
|
||||
if (hasGlue)
|
||||
Ops.push_back(*(Call->op_end()-1));
|
||||
|
||||
// Replace the target specific call node with STACKMAP in-place. This way we
|
||||
// don't have to call ReplaceAllUsesWith and STACKMAP will take the call's
|
||||
// place in the chain.
|
||||
SDVTList NodeTys = DAG.getVTList(MVT::Other, MVT::Glue);
|
||||
DAG.SelectNodeTo(Call, TargetOpcode::STACKMAP, NodeTys, &Ops[0], Ops.size());
|
||||
}
|
||||
|
||||
/// \brief Lower llvm.experimental.patchpoint directly to its target opcode.
|
||||
void SelectionDAGBuilder::visitPatchpoint(const CallInst &CI) {
|
||||
// void|i64 @llvm.experimental.patchpoint.void|i64(i32 <id>,
|
||||
// i32 <numNopBytes>,
|
||||
// i8* <target>, i32 <numArgs>,
|
||||
// [Args...], [live variables...])
|
||||
|
||||
SDValue Callee = getValue(CI.getOperand(2)); // <target>
|
||||
|
||||
// Get the real number of arguments participating in the call <numArgs>
|
||||
unsigned NumArgs =
|
||||
cast<ConstantSDNode>(getValue(CI.getArgOperand(3)))->getZExtValue();
|
||||
|
||||
// Skip the four meta args: <id>, <numNopBytes>, <target>, <numArgs>
|
||||
assert(CI.getNumArgOperands() >= NumArgs + 4 &&
|
||||
"Not enough arguments provided to the patchpoint intrinsic");
|
||||
|
||||
std::pair<SDValue, SDValue> Result =
|
||||
LowerCallOperands(CI, 4, NumArgs, Callee);
|
||||
// Set the root to the target-lowered call chain.
|
||||
SDValue Chain = Result.second;
|
||||
DAG.setRoot(Chain);
|
||||
|
||||
SDNode *CallEnd = Chain.getNode();
|
||||
if (!CI.getType()->isVoidTy()) {
|
||||
setValue(&CI, Result.first);
|
||||
if (CallEnd->getOpcode() == ISD::CopyFromReg)
|
||||
CallEnd = CallEnd->getOperand(0).getNode();
|
||||
}
|
||||
/// Get a call instruction from the call sequence chain.
|
||||
/// Tail calls are not allowed.
|
||||
assert(CallEnd->getOpcode() == ISD::CALLSEQ_END &&
|
||||
"Expected a callseq node.");
|
||||
SDNode *Call = CallEnd->getOperand(0).getNode();
|
||||
bool hasGlue = Call->getGluedNode();
|
||||
|
||||
// Replace the target specific call node with the patchable intrinsic.
|
||||
SmallVector<SDValue, 8> Ops;
|
||||
|
||||
// Add the <id> and <numNopBytes> constants.
|
||||
for (unsigned i = 0; i < 2; ++i) {
|
||||
SDValue tmp = getValue(CI.getOperand(i));
|
||||
Ops.push_back(DAG.getTargetConstant(
|
||||
cast<ConstantSDNode>(tmp)->getZExtValue(), MVT::i32));
|
||||
}
|
||||
// Assume that the Callee is a constant address.
|
||||
Ops.push_back(
|
||||
DAG.getIntPtrConstant(cast<ConstantSDNode>(Callee)->getZExtValue()));
|
||||
|
||||
// Adjust <numArgs> to account for any stack arguments.
|
||||
// Call Node: Chain, Target, {Args}, RegMask, [Glue]
|
||||
unsigned NumCallArgs = Call->getNumOperands() - (hasGlue ? 4 : 3);
|
||||
Ops.push_back(DAG.getTargetConstant(NumCallArgs, MVT::i32));
|
||||
|
||||
// Push the arguments from the call instruction.
|
||||
SDNode::op_iterator e = hasGlue ? Call->op_end()-2 : Call->op_end()-1;
|
||||
for (SDNode::op_iterator i = Call->op_begin()+2; i != e; ++i)
|
||||
Ops.push_back(*i);
|
||||
|
||||
// Push live variables for the stack map.
|
||||
for (unsigned i = NumArgs + 4, e = CI.getNumArgOperands(); i != e; ++i) {
|
||||
SDValue OpVal = getValue(CI.getArgOperand(i));
|
||||
if (ConstantSDNode *C = dyn_cast<ConstantSDNode>(OpVal)) {
|
||||
Ops.push_back(
|
||||
DAG.getTargetConstant(C->getSExtValue(), MVT::i64));
|
||||
} else
|
||||
Ops.push_back(OpVal);
|
||||
}
|
||||
|
||||
// Push the register mask info.
|
||||
if (hasGlue)
|
||||
Ops.push_back(*(Call->op_end()-2));
|
||||
else
|
||||
Ops.push_back(*(Call->op_end()-1));
|
||||
|
||||
// Push the chain (this is originally the first operand of the call, but
|
||||
// becomes now the last or second to last operand).
|
||||
Ops.push_back(*(Call->op_begin()));
|
||||
|
||||
// Push the glue flag (last operand).
|
||||
if (hasGlue)
|
||||
Ops.push_back(*(Call->op_end()-1));
|
||||
|
||||
// Replace the target specific call node with PATCHPOINT in-place. This
|
||||
// way we don't have to call ReplaceAllUsesWith and PATCHPOINT will
|
||||
// take the call's place in the chain.
|
||||
SDVTList NodeTys = DAG.getVTList(MVT::Other, MVT::Glue);
|
||||
DAG.SelectNodeTo(Call, TargetOpcode::PATCHPOINT, NodeTys, &Ops[0],
|
||||
Ops.size());
|
||||
}
|
||||
|
||||
/// TargetLowering::LowerCallTo - This is the default LowerCallTo
|
||||
/// implementation, which just calls LowerCall.
|
||||
/// FIXME: When all targets are
|
||||
|
|
|
@ -619,6 +619,11 @@ public:
|
|||
void LowerCallTo(ImmutableCallSite CS, SDValue Callee, bool IsTailCall,
|
||||
MachineBasicBlock *LandingPad = NULL);
|
||||
|
||||
std::pair<SDValue, SDValue> LowerCallOperands(const CallInst &CI,
|
||||
unsigned ArgIdx,
|
||||
unsigned NumArgs,
|
||||
SDValue Callee);
|
||||
|
||||
/// UpdateSplitBlock - When an MBB was split during scheduling, update the
|
||||
/// references that ned to refer to the last resulting block.
|
||||
void UpdateSplitBlock(MachineBasicBlock *First, MachineBasicBlock *Last);
|
||||
|
@ -752,6 +757,8 @@ private:
|
|||
void visitVAArg(const VAArgInst &I);
|
||||
void visitVAEnd(const CallInst &I);
|
||||
void visitVACopy(const CallInst &I);
|
||||
void visitStackmap(const CallInst &I);
|
||||
void visitPatchpoint(const CallInst &I);
|
||||
|
||||
void visitUserOp1(const Instruction &I) {
|
||||
llvm_unreachable("UserOp1 should not exist at instruction selection time!");
|
||||
|
|
|
@ -64,6 +64,19 @@ bool TargetLowering::isInTailCallPosition(SelectionDAG &DAG, SDNode *Node,
|
|||
return isUsedByReturnOnly(Node, Chain);
|
||||
}
|
||||
|
||||
/// \brief Set CallLoweringInfo attribute flags based on a call instruction
|
||||
/// and called function attributes.
|
||||
void TargetLowering::ArgListEntry::setAttributes(ImmutableCallSite *CS,
|
||||
unsigned AttrIdx) {
|
||||
isSExt = CS->paramHasAttr(AttrIdx, Attribute::SExt);
|
||||
isZExt = CS->paramHasAttr(AttrIdx, Attribute::ZExt);
|
||||
isInReg = CS->paramHasAttr(AttrIdx, Attribute::InReg);
|
||||
isSRet = CS->paramHasAttr(AttrIdx, Attribute::StructRet);
|
||||
isNest = CS->paramHasAttr(AttrIdx, Attribute::Nest);
|
||||
isByVal = CS->paramHasAttr(AttrIdx, Attribute::ByVal);
|
||||
isReturned = CS->paramHasAttr(AttrIdx, Attribute::Returned);
|
||||
Alignment = CS->getParamAlignment(AttrIdx);
|
||||
}
|
||||
|
||||
/// Generate a libcall taking the given operands as arguments and returning a
|
||||
/// result of type RetVT.
|
||||
|
|
|
@ -321,6 +321,8 @@ void CodeGenTarget::ComputeInstrsByEnum() const {
|
|||
"BUNDLE",
|
||||
"LIFETIME_START",
|
||||
"LIFETIME_END",
|
||||
"STACKMAP",
|
||||
"PATCHPOINT",
|
||||
0
|
||||
};
|
||||
const DenseMap<const Record*, CodeGenInstruction*> &Insts = getInstructions();
|
||||
|
|
Loading…
Reference in New Issue