PatchableFunction.cpp 3.6 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798
  1. //===-- PatchableFunction.cpp - Patchable prologues for LLVM -------------===//
  2. //
  3. // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  4. // See https://llvm.org/LICENSE.txt for license information.
  5. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  6. //
  7. //===----------------------------------------------------------------------===//
  8. //
  9. // This file implements edits function bodies in place to support the
  10. // "patchable-function" attribute.
  11. //
  12. //===----------------------------------------------------------------------===//
  13. #include "llvm/CodeGen/MachineFunction.h"
  14. #include "llvm/CodeGen/MachineFunctionPass.h"
  15. #include "llvm/CodeGen/MachineInstrBuilder.h"
  16. #include "llvm/CodeGen/TargetInstrInfo.h"
  17. #include "llvm/CodeGen/TargetSubtargetInfo.h"
  18. #include "llvm/InitializePasses.h"
  19. #include "llvm/Pass.h"
  20. #include "llvm/PassRegistry.h"
  21. using namespace llvm;
  22. namespace {
  23. struct PatchableFunction : public MachineFunctionPass {
  24. static char ID; // Pass identification, replacement for typeid
  25. PatchableFunction() : MachineFunctionPass(ID) {
  26. initializePatchableFunctionPass(*PassRegistry::getPassRegistry());
  27. }
  28. bool runOnMachineFunction(MachineFunction &F) override;
  29. MachineFunctionProperties getRequiredProperties() const override {
  30. return MachineFunctionProperties().set(
  31. MachineFunctionProperties::Property::NoVRegs);
  32. }
  33. };
  34. }
  35. bool PatchableFunction::runOnMachineFunction(MachineFunction &MF) {
  36. if (MF.getFunction().hasFnAttribute("patchable-function-entry")) {
  37. MachineBasicBlock &FirstMBB = *MF.begin();
  38. const TargetInstrInfo *TII = MF.getSubtarget().getInstrInfo();
  39. // The initial .loc covers PATCHABLE_FUNCTION_ENTER.
  40. BuildMI(FirstMBB, FirstMBB.begin(), DebugLoc(),
  41. TII->get(TargetOpcode::PATCHABLE_FUNCTION_ENTER));
  42. return true;
  43. }
  44. if (!MF.getFunction().hasFnAttribute("patchable-function"))
  45. return false;
  46. #ifndef NDEBUG
  47. Attribute PatchAttr = MF.getFunction().getFnAttribute("patchable-function");
  48. StringRef PatchType = PatchAttr.getValueAsString();
  49. assert(PatchType == "prologue-short-redirect" && "Only possibility today!");
  50. #endif
  51. auto &FirstMBB = *MF.begin();
  52. auto *TII = MF.getSubtarget().getInstrInfo();
  53. MachineBasicBlock::iterator FirstActualI = llvm::find_if(
  54. FirstMBB, [](const MachineInstr &MI) { return !MI.isMetaInstruction(); });
  55. if (FirstActualI == FirstMBB.end()) {
  56. // As of Microsoft documentation on /hotpatch feature, we must ensure that
  57. // "the first instruction of each function is at least two bytes, and no
  58. // jump within the function goes to the first instruction"
  59. // When the first MBB is empty, insert a patchable no-op. This ensures the
  60. // first instruction is patchable in two special cases:
  61. // - the function is empty (e.g. unreachable)
  62. // - the function jumps back to the first instruction, which is in a
  63. // successor MBB.
  64. BuildMI(&FirstMBB, DebugLoc(), TII->get(TargetOpcode::PATCHABLE_OP))
  65. .addImm(2)
  66. .addImm(TargetOpcode::PATCHABLE_OP);
  67. MF.ensureAlignment(Align(16));
  68. return true;
  69. }
  70. auto MIB = BuildMI(FirstMBB, FirstActualI, FirstActualI->getDebugLoc(),
  71. TII->get(TargetOpcode::PATCHABLE_OP))
  72. .addImm(2)
  73. .addImm(FirstActualI->getOpcode());
  74. for (auto &MO : FirstActualI->operands())
  75. MIB.add(MO);
  76. FirstActualI->eraseFromParent();
  77. MF.ensureAlignment(Align(16));
  78. return true;
  79. }
  80. char PatchableFunction::ID = 0;
  81. char &llvm::PatchableFunctionID = PatchableFunction::ID;
  82. INITIALIZE_PASS(PatchableFunction, "patchable-function",
  83. "Implement the 'patchable-function' attribute", false, false)