generated for this function needs to follow certain conventions that
make it possible for a runtime function to patch over it later.
The exact effect of this attribute depends on its string value,
- for which there currently is one legal possibility:
+ for which there currently are two legal possiblities:
* ``"prologue-short-redirect"`` - This style of patchable
function is intended to support patching a function prologue to
``"prologue-short-redirect"`` is currently only supported on
x86-64.
+ * ``"ms-hotpatch"`` - This style of patchable function is similar to
+ ``"prologue-short-redirect"``, but it also imposes several additional
+ guarantees to support the style of hotpatching used on Windows. On
+ 32-bit x86, the first instruction will be a ``mov %edi, %edi``
+ instruction; this is frequently used as a magic value indicating a
+ hotpatchable function. On other architectures, however, the first
+ instruction can be anything allowed in a Windows-style prologue;
+ this is because all functions on the non-i386 architectures Windows
+ supports are assumed to be hotpatchable. Additionally, when not
+ targeting a Visual C++-style toolchain, patch space will be provided
+ prior to the function's entry point of an architecturally specific
+ size. These sizes are compatible with GCC: on 32-bit x86, the patch
+ space is 64 bytes long; on x86-64, it is 128 bytes long. The patch
+ space is not provided for MSVC toolchains because the
+ `/FUNCTIONPADMIN <https://msdn.microsoft.com/en-us/library/ms173524.aspx>`_
+ option, which provides this space, is expected to be used there.
+
+ ``"ms-hotpatch"`` is currently only supported on x86 and x86-64.
This attribute by itself does not imply restrictions on
inter-procedural optimizations. All of the semantic effects the
#define LLVM_ANALYSIS_TARGETTRANSFORMINFO_H
#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/CodeGen/MachineBasicBlock.h"
#include "llvm/IR/IntrinsicInst.h"
#include "llvm/IR/Intrinsics.h"
#include "llvm/IR/Operator.h"
/// target-independent defaults.
void getUnrollingPreferences(Loop *L, UnrollingPreferences &UP) const;
+ /// \brief Emit a patchable operation in the given basic block at the
+ /// given insertion point.
+ ///
+ /// Most of the time, this will be a straight-up \c TargetOpcode::PATCHABLE_OP
+ /// instruction, which will be lowered by the target to a no-op that can
+ /// be safely replaced with a short jump. However, some targets under certain
+ /// conditions can have peculiar requirements for this instruction; these
+ /// targets can provide their own implementation of this to emit the correct
+ /// instruction.
+ void emitPatchableOp(StringRef PatchType, MachineBasicBlock &MBB,
+ MachineBasicBlock::iterator &MBBI) const;
+
/// @}
/// \name Scalar Target Information
virtual bool isSourceOfDivergence(const Value *V) = 0;
virtual bool isLoweredToCall(const Function *F) = 0;
virtual void getUnrollingPreferences(Loop *L, UnrollingPreferences &UP) = 0;
+ virtual void emitPatchableOp(StringRef Kind,
+ MachineBasicBlock &MBB,
+ MachineBasicBlock::iterator &MBBI) const = 0;
virtual bool isLegalAddImmediate(int64_t Imm) = 0;
virtual bool isLegalICmpImmediate(int64_t Imm) = 0;
virtual bool isLegalAddressingMode(Type *Ty, GlobalValue *BaseGV,
void getUnrollingPreferences(Loop *L, UnrollingPreferences &UP) override {
return Impl.getUnrollingPreferences(L, UP);
}
+ void emitPatchableOp(StringRef Kind, MachineBasicBlock &MBB,
+ MachineBasicBlock::iterator &MBBI) const override {
+ return Impl.emitPatchableOp(Kind, MBB, MBBI);
+ }
bool isLegalAddImmediate(int64_t Imm) override {
return Impl.isLegalAddImmediate(Imm);
}
#include "llvm/IR/Operator.h"
#include "llvm/IR/Type.h"
#include "llvm/Analysis/VectorUtils.h"
+#include "llvm/CodeGen/MachineBasicBlock.h"
+#include "llvm/CodeGen/MachineInstrBuilder.h"
+#include "llvm/Target/TargetInstrInfo.h"
+#include "llvm/Target/TargetSubtargetInfo.h"
namespace llvm {
void getUnrollingPreferences(Loop *, TTI::UnrollingPreferences &) {}
+ void emitPatchableOp(StringRef, MachineBasicBlock &MBB,
+ MachineBasicBlock::iterator &MBBI) const {
+ auto *TII = MBB.getParent()->getSubtarget().getInstrInfo();
+ auto MIB = BuildMI(MBB, MBBI, MBBI->getDebugLoc(),
+ TII->get(TargetOpcode::PATCHABLE_OP))
+ .addImm(2)
+ .addImm(MBBI->getOpcode());
+
+ for (auto &MO : MBBI->operands())
+ MIB.addOperand(MO);
+
+ MBBI->eraseFromParent();
+ }
+
bool isLegalAddImmediate(int64_t Imm) { return false; }
bool isLegalICmpImmediate(int64_t Imm) { return false; }
return TTIImpl->getUnrollingPreferences(L, UP);
}
+void TargetTransformInfo::emitPatchableOp(
+ StringRef PatchType, MachineBasicBlock &MBB,
+ MachineBasicBlock::iterator &MBBI) const {
+ return TTIImpl->emitPatchableOp(PatchType, MBB, MBBI);
+}
+
bool TargetTransformInfo::isLegalAddImmediate(int64_t Imm) const {
return TTIImpl->isLegalAddImmediate(Imm);
}
//===----------------------------------------------------------------------===//
#include "llvm/CodeGen/Passes.h"
+#include "llvm/Analysis/TargetTransformInfo.h"
+#include "llvm/CodeGen/Analysis.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
-#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/Target/TargetFrameLowering.h"
-#include "llvm/Target/TargetInstrInfo.h"
-#include "llvm/Target/TargetSubtargetInfo.h"
using namespace llvm;
initializePatchableFunctionPass(*PassRegistry::getPassRegistry());
}
+ void getAnalysisUsage(AnalysisUsage &AU) const override;
bool runOnMachineFunction(MachineFunction &F) override;
- MachineFunctionProperties getRequiredProperties() const override {
+ MachineFunctionProperties getRequiredProperties() const override {
return MachineFunctionProperties().set(
MachineFunctionProperties::Property::AllVRegsAllocated);
}
}
}
+void PatchableFunction::getAnalysisUsage(AnalysisUsage &AU) const {
+ MachineFunctionPass::getAnalysisUsage(AU);
+ AU.addRequired<TargetTransformInfoWrapperPass>();
+}
+
bool PatchableFunction::runOnMachineFunction(MachineFunction &MF) {
if (!MF.getFunction()->hasFnAttribute("patchable-function"))
return false;
-#ifndef NDEBUG
Attribute PatchAttr = MF.getFunction()->getFnAttribute("patchable-function");
StringRef PatchType = PatchAttr.getValueAsString();
- assert(PatchType == "prologue-short-redirect" && "Only possibility today!");
-#endif
+ assert((PatchType == "prologue-short-redirect" ||
+ PatchType == "ms-hotpatch") && "Only possibilities today!");
auto &FirstMBB = *MF.begin();
MachineBasicBlock::iterator FirstActualI = FirstMBB.begin();
for (; doesNotGeneratecode(*FirstActualI); ++FirstActualI)
assert(FirstActualI != FirstMBB.end());
- auto *TII = MF.getSubtarget().getInstrInfo();
- auto MIB = BuildMI(FirstMBB, FirstActualI, FirstActualI->getDebugLoc(),
- TII->get(TargetOpcode::PATCHABLE_OP))
- .addImm(2)
- .addImm(FirstActualI->getOpcode());
-
- for (auto &MO : FirstActualI->operands())
- MIB.addOperand(MO);
+ const TargetTransformInfo &TTI =
+ getAnalysis<TargetTransformInfoWrapperPass>().getTTI(*MF.getFunction());
+ TTI.emitPatchableOp(PatchType, FirstMBB, FirstActualI);
- FirstActualI->eraseFromParent();
MF.ensureAlignment(4);
return true;
}
return false;
}
+void X86AsmPrinter::EmitConstantPool() {
+ if (MF) {
+ // If an MS hotpatch function, we need to ensure 64 (32-bit) or 128 (64-bit)
+ // bytes of padding precede the label. This is the scratch space used
+ // by the hotpatching mechanism to insert the patch code. The movl %edi,
+ // %edi instruction emitted as the very first instruction of a hotpatch
+ // function is usually overwritten with a short jump instruction when the
+ // patch is installed, so it will jump directly into this space. (But
+ // don't add the space when targeting MSVC. There, the /FUNCTIONPADMIN
+ // option to link.exe is expected to be used.)
+ const Function *Fn = MF->getFunction();
+ if (!Subtarget->isTargetKnownWindowsMSVC() &&
+ Fn->hasFnAttribute("patchable-function") &&
+ Fn->getFnAttribute("patchable-function").getValueAsString() ==
+ "ms-hotpatch") {
+ // Emit INT3 instructions instead of NOPs. If a patch runs off the end,
+ // best to let the patcher know with a crash/debug break than to silently
+ // continue, only to run into the jump back into the patch.
+ OutStreamer->emitFill(Subtarget->is64Bit() ? 128 : 64, 0xcc);
+ }
+ }
+
+ AsmPrinter::EmitConstantPool();
+}
+
/// printSymbolOperand - Print a raw symbol reference operand. This handles
/// jump tables, constant pools, global address and external symbols, all of
/// which print to a label with various suffixes for relocation types etc.
SMShadowTracker.emitShadowPadding(*OutStreamer, getSubtargetInfo());
}
+ void EmitConstantPool() override;
+
bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
unsigned AsmVariant, const char *ExtraCode,
raw_ostream &OS) override;
bool NeedsWinCFI = IsWin64Prologue && Fn->needsUnwindTableEntry();
bool NeedsDwarfCFI =
!IsWin64Prologue && (MMI.hasDebugInfo() || Fn->needsUnwindTableEntry());
+ bool IsMSHotpatch =
+ Fn->hasFnAttribute("patchable-function") &&
+ Fn->getFnAttribute("patchable-function").getValueAsString() ==
+ "ms-hotpatch";
unsigned FramePtr = TRI->getFrameRegister(MF);
const unsigned MachineFramePtr =
STI.isTarget64BitILP32()
if (!IsWin64Prologue && !IsFunclet) {
// Update EBP with the new base value.
BuildMI(MBB, MBBI, DL,
- TII.get(Uses64BitFramePtr ? X86::MOV64rr : X86::MOV32rr),
+ TII.get(IsMSHotpatch ?
+ (Uses64BitFramePtr ? X86::MOV64rr_REV : X86::MOV32rr_REV):
+ (Uses64BitFramePtr ? X86::MOV64rr : X86::MOV32rr)),
FramePtr)
.addReg(StackPtr)
.setMIFlag(MachineInstr::FrameSetup);
X86MachineFunctionInfo *FuncInfo = MF.getInfo<X86MachineFunctionInfo>();
const TargetFrameLowering &TFI = *Subtarget.getFrameLowering();
- const Function *Fn = MF.getFunction();
- if (Fn->hasExternalLinkage() &&
- Subtarget.isTargetCygMing() &&
- Fn->getName() == "main")
+ const Function* Fn = MF.getFunction();
+ if ((Fn->hasExternalLinkage() &&
+ Subtarget.isTargetCygMing() &&
+ Fn->getName() == "main") ||
+ (!Subtarget.is64Bit() && Fn->hasFnAttribute("patchable-function") &&
+ Fn->getFnAttribute("patchable-function").getValueAsString() ==
+ "ms-hotpatch"))
FuncInfo->setForceFramePointer(true);
MachineFrameInfo &MFI = MF.getFrameInfo();
// correct.
return (CallerBits & CalleeBits) == CalleeBits;
}
+
+void X86TTIImpl::emitPatchableOp(StringRef PatchType,
+ MachineBasicBlock &MBB,
+ MachineBasicBlock::iterator &MBBI) const {
+ if (PatchType != "ms-hotpatch" || !ST->is32Bit()) {
+ BaseT::emitPatchableOp(PatchType, MBB, MBBI);
+ return;
+ }
+
+ auto &TII = *MBB.getParent()->getSubtarget().getInstrInfo();
+ BuildMI(MBB, MBBI, MBBI->getDebugLoc(),
+ TII.get(X86::MOV32rr_REV), X86::EDI)
+ .addReg(X86::EDI)
+ .setMIFlag(MachineInstr::FrameSetup);
+}
: BaseT(std::move(static_cast<BaseT &>(Arg))), ST(std::move(Arg.ST)),
TLI(std::move(Arg.TLI)) {}
+ /// \name Generic TTI Implementations
+ /// @{
+ void emitPatchableOp(StringRef PatchType, MachineBasicBlock &MBB,
+ MachineBasicBlock::iterator &MBBI) const;
+
+ /// @}
+
/// \name Scalar TTI Implementations
/// @{
TTI::PopcntSupportKind getPopcntSupport(unsigned TyWidth);
--- /dev/null
+; RUN: llc < %s -march=x86 -filetype=asm | FileCheck -check-prefix=CHECK-32 %s
+; RUN: llc < %s -march=x86-64 -filetype=asm | FileCheck -check-prefix=CHECK-64 %s
+; RUN: llc < %s -mtriple=i386-windows-msvc -filetype=asm | FileCheck -check-prefix=MSVC-32 %s
+; RUN: llc < %s -mtriple=x86_64-windows-msvc -filetype=asm | FileCheck -check-prefix=MSVC-64 %s
+
+; CHECK-32: .space 64,204
+; CHECK-32: .p2align 4, 0x90
+; CHECK-32-LABEL: foo:
+; CHECK-32: movl %edi, %edi
+; CHECK-32-NEXT: pushl %ebp
+; CHECK-32-NEXT: movl %esp, %ebp
+; CHECK-64: .space 128,204
+; CHECK-64: .p2align 4, 0x90
+; CHECK-64-LABEL: foo:
+; CHECK-64: xchgw %ax, %ax
+; MSVC-32-NOT: .space 64,204
+; MSVC-32-LABEL: _foo:
+; MSVC-32: movl %edi, %edi
+; MSVC-32-NEXT: pushl %ebp
+; MSVC-32-NEXT: movl %esp, %ebp
+; MSVC-64-NOT: .space 128,204
+; MSVC-64-LABEL: foo:
+; MSVC-64: xchgw %ax, %ax
+define void @foo() nounwind "patchable-function"="ms-hotpatch" {
+entry:
+ ret void
+}