From: Lang Hames Date: Wed, 22 Apr 2015 06:02:31 +0000 (+0000) Subject: [patchpoint] Add support for symbolic patchpoint targets to SelectionDAG and the X-Git-Url: http://plrg.eecs.uci.edu/git/?p=oota-llvm.git;a=commitdiff_plain;h=a1c0ce85180dd1c96ebc1ed48eb693c87a07aa7d [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 --- diff --git a/include/llvm/MC/MCInstBuilder.h b/include/llvm/MC/MCInstBuilder.h index c5acb26eeca..d16f6b5452e 100644 --- a/include/llvm/MC/MCInstBuilder.h +++ b/include/llvm/MC/MCInstBuilder.h @@ -58,6 +58,12 @@ public: return *this; } + /// \brief Add an operand. + MCInstBuilder &addOperand(const MCOperand &Op) { + Inst.addOperand(Op); + return *this; + } + operator MCInst&() { return Inst; } diff --git a/lib/CodeGen/SelectionDAG/FastISel.cpp b/lib/CodeGen/SelectionDAG/FastISel.cpp index dafbc63dbd0..2b624adac94 100644 --- a/lib/CodeGen/SelectionDAG/FastISel.cpp +++ b/lib/CodeGen/SelectionDAG/FastISel.cpp @@ -711,7 +711,7 @@ bool FastISel::selectPatchpoint(const CallInst *I) { CallingConv::ID CC = I->getCallingConv(); bool IsAnyRegCC = CC == CallingConv::AnyReg; 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 assert(isa(I->getOperand(PatchPointOpers::NArgPos)) && @@ -757,23 +757,25 @@ bool FastISel::selectPatchpoint(const CallInst *I) { cast(I->getOperand(PatchPointOpers::NBytesPos)); Ops.push_back(MachineOperand::CreateImm(NumBytes->getZExtValue())); - // Assume that the callee is a constant address or null pointer. - // FIXME: handle function symbols in the future. - uint64_t CalleeAddr; - if (const auto *C = dyn_cast(Callee)) - CalleeAddr = cast(C->getOperand(0))->getZExtValue(); - else if (const auto *C = dyn_cast(Callee)) { - if (C->getOpcode() == Instruction::IntToPtr) - CalleeAddr = cast(C->getOperand(0))->getZExtValue(); - else + // Add the call target. + if (const auto *C = dyn_cast(Callee)) { + uint64_t CalleeConstAddr = + cast(C->getOperand(0))->getZExtValue(); + Ops.push_back(MachineOperand::CreateImm(CalleeConstAddr)); + } else if (const auto *C = dyn_cast(Callee)) { + if (C->getOpcode() == Instruction::IntToPtr) { + uint64_t CalleeConstAddr = + cast(C->getOperand(0))->getZExtValue(); + Ops.push_back(MachineOperand::CreateImm(CalleeConstAddr)); + } else llvm_unreachable("Unsupported ConstantExpr."); + } else if (const auto *GV = dyn_cast(Callee)) { + Ops.push_back(MachineOperand::CreateGA(GV, 0)); } else if (isa(Callee)) - CalleeAddr = 0; + Ops.push_back(MachineOperand::CreateImm(0)); else llvm_unreachable("Unsupported callee address."); - Ops.push_back(MachineOperand::CreateImm(CalleeAddr)); - // Adjust to account for any arguments that have been passed on // the stack instead. unsigned NumCallRegArgs = IsAnyRegCC ? NumArgs : CLI.OutRegs.size(); diff --git a/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp b/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp index 746a9efaa4d..2c813138f84 100644 --- a/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp +++ b/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp @@ -7001,7 +7001,16 @@ void SelectionDAGBuilder::visitPatchpoint(ImmutableCallSite CS, CallingConv::ID CC = CS.getCallingConv(); bool IsAnyRegCC = CC == CallingConv::AnyReg; bool HasDef = !CS->getType()->isVoidTy(); - SDValue Callee = getValue(CS->getOperand(2)); // + SDValue Callee = getValue(CS->getOperand(PatchPointOpers::TargetPos)); + + // Handle immediate and symbolic callees. + if (auto* ConstCallee = dyn_cast(Callee)) + Callee = DAG.getIntPtrConstant(ConstCallee->getZExtValue(), + /*isTarget=*/true); + else if (auto* SymbolicCallee = dyn_cast(Callee)) + Callee = DAG.getTargetGlobalAddress(SymbolicCallee->getGlobal(), + SDLoc(SymbolicCallee), + SymbolicCallee->getValueType(0)); // Get the real number of arguments participating in the call SDValue NArgVal = getValue(CS.getArgument(PatchPointOpers::NArgPos)); @@ -7041,11 +7050,8 @@ void SelectionDAGBuilder::visitPatchpoint(ImmutableCallSite CS, Ops.push_back(DAG.getTargetConstant( cast(NBytesVal)->getZExtValue(), MVT::i32)); - // Assume that the Callee is a constant address. - // FIXME: handle function symbols in the future. - Ops.push_back( - DAG.getIntPtrConstant(cast(Callee)->getZExtValue(), - /*isTarget=*/true)); + // Add the callee. + Ops.push_back(Callee); // Adjust to account for any arguments that have been passed on the // stack instead. diff --git a/lib/Target/X86/X86AsmPrinter.h b/lib/Target/X86/X86AsmPrinter.h index d101b8ca0e4..9c6c683608b 100644 --- a/lib/Target/X86/X86AsmPrinter.h +++ b/lib/Target/X86/X86AsmPrinter.h @@ -81,7 +81,7 @@ class LLVM_LIBRARY_VISIBILITY X86AsmPrinter : public AsmPrinter { void InsertStackMapShadows(MachineFunction &MF); void LowerSTACKMAP(const MachineInstr &MI); - void LowerPATCHPOINT(const MachineInstr &MI); + void LowerPATCHPOINT(const MachineInstr &MI, X86MCInstLower &MCIL); void LowerTlsAddr(X86MCInstLower &MCInstLowering, const MachineInstr &MI); diff --git a/lib/Target/X86/X86MCInstLower.cpp b/lib/Target/X86/X86MCInstLower.cpp index cd3076d0b1c..98dc376ed6a 100644 --- a/lib/Target/X86/X86MCInstLower.cpp +++ b/lib/Target/X86/X86MCInstLower.cpp @@ -867,7 +867,8 @@ void X86AsmPrinter::LowerSTACKMAP(const MachineInstr &MI) { // Lower a patchpoint of the form: // [], , , , , , ... -void X86AsmPrinter::LowerPATCHPOINT(const MachineInstr &MI) { +void X86AsmPrinter::LowerPATCHPOINT(const MachineInstr &MI, + X86MCInstLower &MCIL) { assert(Subtarget->is64Bit() && "Patchpoint currently only supports X86-64"); SMShadowTracker.emitShadowPadding(OutStreamer, getSubtargetInfo()); @@ -877,8 +878,29 @@ void X86AsmPrinter::LowerPATCHPOINT(const MachineInstr &MI) { PatchPointOpers opers(&MI); unsigned ScratchIdx = opers.getNextScratchIdx(); unsigned EncodedBytes = 0; - int64_t CallTarget = opers.getMetaOper(PatchPointOpers::TargetPos).getImm(); - if (CallTarget) { + const MachineOperand &CalleeMO = + 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. // This is encoded with 12-13 bytes, depending on which register is used. unsigned ScratchReg = MI.getOperand(ScratchIdx).getReg(); @@ -886,10 +908,12 @@ void X86AsmPrinter::LowerPATCHPOINT(const MachineInstr &MI) { EncodedBytes = 13; else EncodedBytes = 12; - EmitAndCountInstruction(MCInstBuilder(X86::MOV64ri).addReg(ScratchReg) - .addImm(CallTarget)); + + EmitAndCountInstruction( + MCInstBuilder(X86::MOV64ri).addReg(ScratchReg).addOperand(CalleeMCOp)); EmitAndCountInstruction(MCInstBuilder(X86::CALL64r).addReg(ScratchReg)); } + // Emit padding. unsigned NumBytes = opers.getMetaOper(PatchPointOpers::NBytesPos).getImm(); assert(NumBytes >= EncodedBytes && @@ -1091,7 +1115,7 @@ void X86AsmPrinter::EmitInstruction(const MachineInstr *MI) { return LowerSTACKMAP(*MI); case TargetOpcode::PATCHPOINT: - return LowerPATCHPOINT(*MI); + return LowerPATCHPOINT(*MI, MCInstLowering); case X86::MORESTACK_RET: EmitAndCountInstruction(MCInstBuilder(getRetOpcode(*Subtarget))); diff --git a/test/CodeGen/X86/patchpoint.ll b/test/CodeGen/X86/patchpoint.ll index eda13fd1e24..82b15c36c2b 100644 --- a/test/CodeGen/X86/patchpoint.ll +++ b/test/CodeGen/X86/patchpoint.ll @@ -21,6 +21,22 @@ entry: 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 ; as a leaf function. ;