Lower stackmap intrinsics directly to their target opcode in the DAG builder.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@193769 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Andrew Trick 2013-10-31 17:18:24 +00:00
parent 233012c25b
commit 2343e3b228
7 changed files with 246 additions and 12 deletions

View File

@ -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;
}
}
//===----------------------------------------------------------------------===//

View File

@ -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;

View File

@ -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

View File

@ -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

View File

@ -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!");

View File

@ -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.

View File

@ -321,6 +321,8 @@ void CodeGenTarget::ComputeInstrsByEnum() const {
"BUNDLE",
"LIFETIME_START",
"LIFETIME_END",
"STACKMAP",
"PATCHPOINT",
0
};
const DenseMap<const Record*, CodeGenInstruction*> &Insts = getInstructions();