[patchpoint] Add support for symbolic patchpoint targets to SelectionDAG and the

X86 backend.

The code generated for symbolic targets is identical to the code generated for
constant targets, except that a relocation is emitted to fix up the actual
target address at link-time. This allows IR and object files containing
patchpoints to be cached across JIT-invocations where the target address may
change.



git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@235483 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Lang Hames 2015-04-22 06:02:31 +00:00
parent 3aaf26d335
commit a1c0ce8518
6 changed files with 80 additions and 26 deletions

View File

@ -58,6 +58,12 @@ public:
return *this; return *this;
} }
/// \brief Add an operand.
MCInstBuilder &addOperand(const MCOperand &Op) {
Inst.addOperand(Op);
return *this;
}
operator MCInst&() { operator MCInst&() {
return Inst; return Inst;
} }

View File

@ -711,7 +711,7 @@ bool FastISel::selectPatchpoint(const CallInst *I) {
CallingConv::ID CC = I->getCallingConv(); CallingConv::ID CC = I->getCallingConv();
bool IsAnyRegCC = CC == CallingConv::AnyReg; bool IsAnyRegCC = CC == CallingConv::AnyReg;
bool HasDef = !I->getType()->isVoidTy(); bool HasDef = !I->getType()->isVoidTy();
Value *Callee = I->getOperand(PatchPointOpers::TargetPos); Value *Callee = I->getOperand(PatchPointOpers::TargetPos)->stripPointerCasts();
// Get the real number of arguments participating in the call <numArgs> // Get the real number of arguments participating in the call <numArgs>
assert(isa<ConstantInt>(I->getOperand(PatchPointOpers::NArgPos)) && assert(isa<ConstantInt>(I->getOperand(PatchPointOpers::NArgPos)) &&
@ -757,23 +757,25 @@ bool FastISel::selectPatchpoint(const CallInst *I) {
cast<ConstantInt>(I->getOperand(PatchPointOpers::NBytesPos)); cast<ConstantInt>(I->getOperand(PatchPointOpers::NBytesPos));
Ops.push_back(MachineOperand::CreateImm(NumBytes->getZExtValue())); Ops.push_back(MachineOperand::CreateImm(NumBytes->getZExtValue()));
// Assume that the callee is a constant address or null pointer. // Add the call target.
// FIXME: handle function symbols in the future. if (const auto *C = dyn_cast<IntToPtrInst>(Callee)) {
uint64_t CalleeAddr; uint64_t CalleeConstAddr =
if (const auto *C = dyn_cast<IntToPtrInst>(Callee)) cast<ConstantInt>(C->getOperand(0))->getZExtValue();
CalleeAddr = cast<ConstantInt>(C->getOperand(0))->getZExtValue(); Ops.push_back(MachineOperand::CreateImm(CalleeConstAddr));
else if (const auto *C = dyn_cast<ConstantExpr>(Callee)) { } else if (const auto *C = dyn_cast<ConstantExpr>(Callee)) {
if (C->getOpcode() == Instruction::IntToPtr) if (C->getOpcode() == Instruction::IntToPtr) {
CalleeAddr = cast<ConstantInt>(C->getOperand(0))->getZExtValue(); uint64_t CalleeConstAddr =
else cast<ConstantInt>(C->getOperand(0))->getZExtValue();
Ops.push_back(MachineOperand::CreateImm(CalleeConstAddr));
} else
llvm_unreachable("Unsupported ConstantExpr."); llvm_unreachable("Unsupported ConstantExpr.");
} else if (const auto *GV = dyn_cast<GlobalValue>(Callee)) {
Ops.push_back(MachineOperand::CreateGA(GV, 0));
} else if (isa<ConstantPointerNull>(Callee)) } else if (isa<ConstantPointerNull>(Callee))
CalleeAddr = 0; Ops.push_back(MachineOperand::CreateImm(0));
else else
llvm_unreachable("Unsupported callee address."); llvm_unreachable("Unsupported callee address.");
Ops.push_back(MachineOperand::CreateImm(CalleeAddr));
// Adjust <numArgs> to account for any arguments that have been passed on // Adjust <numArgs> to account for any arguments that have been passed on
// the stack instead. // the stack instead.
unsigned NumCallRegArgs = IsAnyRegCC ? NumArgs : CLI.OutRegs.size(); unsigned NumCallRegArgs = IsAnyRegCC ? NumArgs : CLI.OutRegs.size();

View File

@ -7001,7 +7001,16 @@ void SelectionDAGBuilder::visitPatchpoint(ImmutableCallSite CS,
CallingConv::ID CC = CS.getCallingConv(); CallingConv::ID CC = CS.getCallingConv();
bool IsAnyRegCC = CC == CallingConv::AnyReg; bool IsAnyRegCC = CC == CallingConv::AnyReg;
bool HasDef = !CS->getType()->isVoidTy(); bool HasDef = !CS->getType()->isVoidTy();
SDValue Callee = getValue(CS->getOperand(2)); // <target> SDValue Callee = getValue(CS->getOperand(PatchPointOpers::TargetPos));
// Handle immediate and symbolic callees.
if (auto* ConstCallee = dyn_cast<ConstantSDNode>(Callee))
Callee = DAG.getIntPtrConstant(ConstCallee->getZExtValue(),
/*isTarget=*/true);
else if (auto* SymbolicCallee = dyn_cast<GlobalAddressSDNode>(Callee))
Callee = DAG.getTargetGlobalAddress(SymbolicCallee->getGlobal(),
SDLoc(SymbolicCallee),
SymbolicCallee->getValueType(0));
// Get the real number of arguments participating in the call <numArgs> // Get the real number of arguments participating in the call <numArgs>
SDValue NArgVal = getValue(CS.getArgument(PatchPointOpers::NArgPos)); SDValue NArgVal = getValue(CS.getArgument(PatchPointOpers::NArgPos));
@ -7041,11 +7050,8 @@ void SelectionDAGBuilder::visitPatchpoint(ImmutableCallSite CS,
Ops.push_back(DAG.getTargetConstant( Ops.push_back(DAG.getTargetConstant(
cast<ConstantSDNode>(NBytesVal)->getZExtValue(), MVT::i32)); cast<ConstantSDNode>(NBytesVal)->getZExtValue(), MVT::i32));
// Assume that the Callee is a constant address. // Add the callee.
// FIXME: handle function symbols in the future. Ops.push_back(Callee);
Ops.push_back(
DAG.getIntPtrConstant(cast<ConstantSDNode>(Callee)->getZExtValue(),
/*isTarget=*/true));
// Adjust <numArgs> to account for any arguments that have been passed on the // Adjust <numArgs> to account for any arguments that have been passed on the
// stack instead. // stack instead.

View File

@ -81,7 +81,7 @@ class LLVM_LIBRARY_VISIBILITY X86AsmPrinter : public AsmPrinter {
void InsertStackMapShadows(MachineFunction &MF); void InsertStackMapShadows(MachineFunction &MF);
void LowerSTACKMAP(const MachineInstr &MI); void LowerSTACKMAP(const MachineInstr &MI);
void LowerPATCHPOINT(const MachineInstr &MI); void LowerPATCHPOINT(const MachineInstr &MI, X86MCInstLower &MCIL);
void LowerTlsAddr(X86MCInstLower &MCInstLowering, const MachineInstr &MI); void LowerTlsAddr(X86MCInstLower &MCInstLowering, const MachineInstr &MI);

View File

@ -867,7 +867,8 @@ void X86AsmPrinter::LowerSTACKMAP(const MachineInstr &MI) {
// Lower a patchpoint of the form: // Lower a patchpoint of the form:
// [<def>], <id>, <numBytes>, <target>, <numArgs>, <cc>, ... // [<def>], <id>, <numBytes>, <target>, <numArgs>, <cc>, ...
void X86AsmPrinter::LowerPATCHPOINT(const MachineInstr &MI) { void X86AsmPrinter::LowerPATCHPOINT(const MachineInstr &MI,
X86MCInstLower &MCIL) {
assert(Subtarget->is64Bit() && "Patchpoint currently only supports X86-64"); assert(Subtarget->is64Bit() && "Patchpoint currently only supports X86-64");
SMShadowTracker.emitShadowPadding(OutStreamer, getSubtargetInfo()); SMShadowTracker.emitShadowPadding(OutStreamer, getSubtargetInfo());
@ -877,8 +878,29 @@ void X86AsmPrinter::LowerPATCHPOINT(const MachineInstr &MI) {
PatchPointOpers opers(&MI); PatchPointOpers opers(&MI);
unsigned ScratchIdx = opers.getNextScratchIdx(); unsigned ScratchIdx = opers.getNextScratchIdx();
unsigned EncodedBytes = 0; unsigned EncodedBytes = 0;
int64_t CallTarget = opers.getMetaOper(PatchPointOpers::TargetPos).getImm(); const MachineOperand &CalleeMO =
if (CallTarget) { opers.getMetaOper(PatchPointOpers::TargetPos);
// Check for null target. If target is non-null (i.e. is non-zero or is
// symbolic) then emit a call.
if (!(CalleeMO.isImm() && !CalleeMO.getImm())) {
MCOperand CalleeMCOp;
switch (CalleeMO.getType()) {
default:
/// FIXME: Add a verifier check for bad callee types.
llvm_unreachable("Unrecognized callee operand type.");
case MachineOperand::MO_Immediate:
if (CalleeMO.getImm())
CalleeMCOp = MCOperand::CreateImm(CalleeMO.getImm());
break;
case MachineOperand::MO_ExternalSymbol:
case MachineOperand::MO_GlobalAddress:
CalleeMCOp =
MCIL.LowerSymbolOperand(CalleeMO,
MCIL.GetSymbolFromOperand(CalleeMO));
break;
}
// Emit MOV to materialize the target address and the CALL to target. // Emit MOV to materialize the target address and the CALL to target.
// This is encoded with 12-13 bytes, depending on which register is used. // This is encoded with 12-13 bytes, depending on which register is used.
unsigned ScratchReg = MI.getOperand(ScratchIdx).getReg(); unsigned ScratchReg = MI.getOperand(ScratchIdx).getReg();
@ -886,10 +908,12 @@ void X86AsmPrinter::LowerPATCHPOINT(const MachineInstr &MI) {
EncodedBytes = 13; EncodedBytes = 13;
else else
EncodedBytes = 12; EncodedBytes = 12;
EmitAndCountInstruction(MCInstBuilder(X86::MOV64ri).addReg(ScratchReg)
.addImm(CallTarget)); EmitAndCountInstruction(
MCInstBuilder(X86::MOV64ri).addReg(ScratchReg).addOperand(CalleeMCOp));
EmitAndCountInstruction(MCInstBuilder(X86::CALL64r).addReg(ScratchReg)); EmitAndCountInstruction(MCInstBuilder(X86::CALL64r).addReg(ScratchReg));
} }
// Emit padding. // Emit padding.
unsigned NumBytes = opers.getMetaOper(PatchPointOpers::NBytesPos).getImm(); unsigned NumBytes = opers.getMetaOper(PatchPointOpers::NBytesPos).getImm();
assert(NumBytes >= EncodedBytes && assert(NumBytes >= EncodedBytes &&
@ -1091,7 +1115,7 @@ void X86AsmPrinter::EmitInstruction(const MachineInstr *MI) {
return LowerSTACKMAP(*MI); return LowerSTACKMAP(*MI);
case TargetOpcode::PATCHPOINT: case TargetOpcode::PATCHPOINT:
return LowerPATCHPOINT(*MI); return LowerPATCHPOINT(*MI, MCInstLowering);
case X86::MORESTACK_RET: case X86::MORESTACK_RET:
EmitAndCountInstruction(MCInstBuilder(getRetOpcode(*Subtarget))); EmitAndCountInstruction(MCInstBuilder(getRetOpcode(*Subtarget)));

View File

@ -21,6 +21,22 @@ entry:
ret i64 %result ret i64 %result
} }
; Trivial symbolic patchpoint codegen.
;
declare i64 @foo(i64 %p1, i64 %p2)
define i64 @trivial_symbolic_patchpoint_codegen(i64 %p1, i64 %p2) {
entry:
; CHECK-LABEL: trivial_symbolic_patchpoint_codegen:
; CHECK: movabsq $_foo, %r11
; CHECK-NEXT: callq *%r11
; CHECK-NEXT: xchgw %ax, %ax
; CHECK: retq
%result = tail call i64 (i64, i32, i8*, i32, ...) @llvm.experimental.patchpoint.i64(i64 9, i32 15, i8* bitcast (i64 (i64, i64)* @foo to i8*), i32 2, i64 %p1, i64 %p2)
ret i64 %result
}
; Caller frame metadata with stackmaps. This should not be optimized ; Caller frame metadata with stackmaps. This should not be optimized
; as a leaf function. ; as a leaf function.
; ;