XRayInstrumentation.cpp 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  1. //===- XRayInstrumentation.cpp - Adds XRay instrumentation to functions. --===//
  2. //
  3. // The LLVM Compiler Infrastructure
  4. //
  5. // This file is distributed under the University of Illinois Open Source
  6. // License. See LICENSE.TXT for details.
  7. //
  8. //===----------------------------------------------------------------------===//
  9. //
  10. // This file implements a MachineFunctionPass that inserts the appropriate
  11. // XRay instrumentation instructions. We look for XRay-specific attributes
  12. // on the function to determine whether we should insert the replacement
  13. // operations.
  14. //
  15. //===---------------------------------------------------------------------===//
  16. #include "llvm/ADT/SmallVector.h"
  17. #include "llvm/ADT/STLExtras.h"
  18. #include "llvm/ADT/Triple.h"
  19. #include "llvm/CodeGen/MachineBasicBlock.h"
  20. #include "llvm/CodeGen/MachineDominators.h"
  21. #include "llvm/CodeGen/MachineFunction.h"
  22. #include "llvm/CodeGen/MachineFunctionPass.h"
  23. #include "llvm/CodeGen/MachineInstrBuilder.h"
  24. #include "llvm/CodeGen/MachineLoopInfo.h"
  25. #include "llvm/IR/Attributes.h"
  26. #include "llvm/IR/Function.h"
  27. #include "llvm/Pass.h"
  28. #include "llvm/Target/TargetInstrInfo.h"
  29. #include "llvm/Target/TargetMachine.h"
  30. #include "llvm/Target/TargetSubtargetInfo.h"
  31. using namespace llvm;
  32. namespace {
  33. struct XRayInstrumentation : public MachineFunctionPass {
  34. static char ID;
  35. XRayInstrumentation() : MachineFunctionPass(ID) {
  36. initializeXRayInstrumentationPass(*PassRegistry::getPassRegistry());
  37. }
  38. void getAnalysisUsage(AnalysisUsage &AU) const override {
  39. AU.setPreservesCFG();
  40. AU.addRequired<MachineLoopInfo>();
  41. AU.addPreserved<MachineLoopInfo>();
  42. AU.addPreserved<MachineDominatorTree>();
  43. MachineFunctionPass::getAnalysisUsage(AU);
  44. }
  45. bool runOnMachineFunction(MachineFunction &MF) override;
  46. private:
  47. // Replace the original RET instruction with the exit sled code ("patchable
  48. // ret" pseudo-instruction), so that at runtime XRay can replace the sled
  49. // with a code jumping to XRay trampoline, which calls the tracing handler
  50. // and, in the end, issues the RET instruction.
  51. // This is the approach to go on CPUs which have a single RET instruction,
  52. // like x86/x86_64.
  53. void replaceRetWithPatchableRet(MachineFunction &MF,
  54. const TargetInstrInfo *TII);
  55. // Prepend the original return instruction with the exit sled code ("patchable
  56. // function exit" pseudo-instruction), preserving the original return
  57. // instruction just after the exit sled code.
  58. // This is the approach to go on CPUs which have multiple options for the
  59. // return instruction, like ARM. For such CPUs we can't just jump into the
  60. // XRay trampoline and issue a single return instruction there. We rather
  61. // have to call the trampoline and return from it to the original return
  62. // instruction of the function being instrumented.
  63. void prependRetWithPatchableExit(MachineFunction &MF,
  64. const TargetInstrInfo *TII);
  65. };
  66. } // end anonymous namespace
  67. void XRayInstrumentation::replaceRetWithPatchableRet(
  68. MachineFunction &MF, const TargetInstrInfo *TII) {
  69. // We look for *all* terminators and returns, then replace those with
  70. // PATCHABLE_RET instructions.
  71. SmallVector<MachineInstr *, 4> Terminators;
  72. for (auto &MBB : MF) {
  73. for (auto &T : MBB.terminators()) {
  74. unsigned Opc = 0;
  75. if (T.isReturn() && T.getOpcode() == TII->getReturnOpcode()) {
  76. // Replace return instructions with:
  77. // PATCHABLE_RET <Opcode>, <Operand>...
  78. Opc = TargetOpcode::PATCHABLE_RET;
  79. }
  80. if (TII->isTailCall(T)) {
  81. // Treat the tail call as a return instruction, which has a
  82. // different-looking sled than the normal return case.
  83. Opc = TargetOpcode::PATCHABLE_TAIL_CALL;
  84. }
  85. if (Opc != 0) {
  86. auto MIB = BuildMI(MBB, T, T.getDebugLoc(), TII->get(Opc))
  87. .addImm(T.getOpcode());
  88. for (auto &MO : T.operands())
  89. MIB.add(MO);
  90. Terminators.push_back(&T);
  91. }
  92. }
  93. }
  94. for (auto &I : Terminators)
  95. I->eraseFromParent();
  96. }
  97. void XRayInstrumentation::prependRetWithPatchableExit(
  98. MachineFunction &MF, const TargetInstrInfo *TII) {
  99. for (auto &MBB : MF) {
  100. for (auto &T : MBB.terminators()) {
  101. unsigned Opc = 0;
  102. if (T.isReturn()) {
  103. Opc = TargetOpcode::PATCHABLE_FUNCTION_EXIT;
  104. }
  105. if (TII->isTailCall(T)) {
  106. Opc = TargetOpcode::PATCHABLE_TAIL_CALL;
  107. }
  108. if (Opc != 0) {
  109. // Prepend the return instruction with PATCHABLE_FUNCTION_EXIT or
  110. // PATCHABLE_TAIL_CALL .
  111. BuildMI(MBB, T, T.getDebugLoc(), TII->get(Opc));
  112. }
  113. }
  114. }
  115. }
  116. bool XRayInstrumentation::runOnMachineFunction(MachineFunction &MF) {
  117. auto &F = *MF.getFunction();
  118. auto InstrAttr = F.getFnAttribute("function-instrument");
  119. bool AlwaysInstrument = !InstrAttr.hasAttribute(Attribute::None) &&
  120. InstrAttr.isStringAttribute() &&
  121. InstrAttr.getValueAsString() == "xray-always";
  122. Attribute Attr = F.getFnAttribute("xray-instruction-threshold");
  123. unsigned XRayThreshold = 0;
  124. if (!AlwaysInstrument) {
  125. if (Attr.hasAttribute(Attribute::None) || !Attr.isStringAttribute())
  126. return false; // XRay threshold attribute not found.
  127. if (Attr.getValueAsString().getAsInteger(10, XRayThreshold))
  128. return false; // Invalid value for threshold.
  129. // Check if we have a loop.
  130. // FIXME: Maybe make this smarter, and see whether the loops are dependent
  131. // on inputs or side-effects?
  132. MachineLoopInfo &MLI = getAnalysis<MachineLoopInfo>();
  133. if (MLI.empty() && F.size() < XRayThreshold)
  134. return false; // Function is too small and has no loops.
  135. }
  136. // We look for the first non-empty MachineBasicBlock, so that we can insert
  137. // the function instrumentation in the appropriate place.
  138. auto MBI = llvm::find_if(
  139. MF, [&](const MachineBasicBlock &MBB) { return !MBB.empty(); });
  140. if (MBI == MF.end())
  141. return false; // The function is empty.
  142. auto *TII = MF.getSubtarget().getInstrInfo();
  143. auto &FirstMBB = *MBI;
  144. auto &FirstMI = *FirstMBB.begin();
  145. if (!MF.getSubtarget().isXRaySupported()) {
  146. FirstMI.emitError("An attempt to perform XRay instrumentation for an"
  147. " unsupported target.");
  148. return false;
  149. }
  150. // First, insert an PATCHABLE_FUNCTION_ENTER as the first instruction of the
  151. // MachineFunction.
  152. BuildMI(FirstMBB, FirstMI, FirstMI.getDebugLoc(),
  153. TII->get(TargetOpcode::PATCHABLE_FUNCTION_ENTER));
  154. switch (MF.getTarget().getTargetTriple().getArch()) {
  155. case Triple::ArchType::arm:
  156. case Triple::ArchType::thumb:
  157. case Triple::ArchType::aarch64:
  158. case Triple::ArchType::ppc64le:
  159. case Triple::ArchType::mips:
  160. case Triple::ArchType::mipsel:
  161. case Triple::ArchType::mips64:
  162. case Triple::ArchType::mips64el:
  163. // For the architectures which don't have a single return instruction
  164. prependRetWithPatchableExit(MF, TII);
  165. break;
  166. default:
  167. // For the architectures that have a single return instruction (such as
  168. // RETQ on x86_64).
  169. replaceRetWithPatchableRet(MF, TII);
  170. break;
  171. }
  172. return true;
  173. }
  174. char XRayInstrumentation::ID = 0;
  175. char &llvm::XRayInstrumentationID = XRayInstrumentation::ID;
  176. INITIALIZE_PASS_BEGIN(XRayInstrumentation, "xray-instrumentation",
  177. "Insert XRay ops", false, false)
  178. INITIALIZE_PASS_DEPENDENCY(MachineLoopInfo)
  179. INITIALIZE_PASS_END(XRayInstrumentation, "xray-instrumentation",
  180. "Insert XRay ops", false, false)