XRayInstrumentation.cpp 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269
  1. //===- XRayInstrumentation.cpp - Adds XRay instrumentation to functions. --===//
  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 a MachineFunctionPass that inserts the appropriate
  10. // XRay instrumentation instructions. We look for XRay-specific attributes
  11. // on the function to determine whether we should insert the replacement
  12. // operations.
  13. //
  14. //===---------------------------------------------------------------------===//
  15. #include "llvm/ADT/STLExtras.h"
  16. #include "llvm/ADT/SmallVector.h"
  17. #include "llvm/ADT/Triple.h"
  18. #include "llvm/CodeGen/MachineBasicBlock.h"
  19. #include "llvm/CodeGen/MachineDominators.h"
  20. #include "llvm/CodeGen/MachineFunction.h"
  21. #include "llvm/CodeGen/MachineFunctionPass.h"
  22. #include "llvm/CodeGen/MachineInstrBuilder.h"
  23. #include "llvm/CodeGen/MachineLoopInfo.h"
  24. #include "llvm/CodeGen/TargetInstrInfo.h"
  25. #include "llvm/CodeGen/TargetSubtargetInfo.h"
  26. #include "llvm/IR/Attributes.h"
  27. #include "llvm/IR/Function.h"
  28. #include "llvm/InitializePasses.h"
  29. #include "llvm/Pass.h"
  30. #include "llvm/Target/TargetMachine.h"
  31. using namespace llvm;
  32. namespace {
  33. struct InstrumentationOptions {
  34. // Whether to emit PATCHABLE_TAIL_CALL.
  35. bool HandleTailcall;
  36. // Whether to emit PATCHABLE_RET/PATCHABLE_FUNCTION_EXIT for all forms of
  37. // return, e.g. conditional return.
  38. bool HandleAllReturns;
  39. };
  40. struct XRayInstrumentation : public MachineFunctionPass {
  41. static char ID;
  42. XRayInstrumentation() : MachineFunctionPass(ID) {
  43. initializeXRayInstrumentationPass(*PassRegistry::getPassRegistry());
  44. }
  45. void getAnalysisUsage(AnalysisUsage &AU) const override {
  46. AU.setPreservesCFG();
  47. AU.addPreserved<MachineLoopInfo>();
  48. AU.addPreserved<MachineDominatorTree>();
  49. MachineFunctionPass::getAnalysisUsage(AU);
  50. }
  51. bool runOnMachineFunction(MachineFunction &MF) override;
  52. private:
  53. // Replace the original RET instruction with the exit sled code ("patchable
  54. // ret" pseudo-instruction), so that at runtime XRay can replace the sled
  55. // with a code jumping to XRay trampoline, which calls the tracing handler
  56. // and, in the end, issues the RET instruction.
  57. // This is the approach to go on CPUs which have a single RET instruction,
  58. // like x86/x86_64.
  59. void replaceRetWithPatchableRet(MachineFunction &MF,
  60. const TargetInstrInfo *TII,
  61. InstrumentationOptions);
  62. // Prepend the original return instruction with the exit sled code ("patchable
  63. // function exit" pseudo-instruction), preserving the original return
  64. // instruction just after the exit sled code.
  65. // This is the approach to go on CPUs which have multiple options for the
  66. // return instruction, like ARM. For such CPUs we can't just jump into the
  67. // XRay trampoline and issue a single return instruction there. We rather
  68. // have to call the trampoline and return from it to the original return
  69. // instruction of the function being instrumented.
  70. void prependRetWithPatchableExit(MachineFunction &MF,
  71. const TargetInstrInfo *TII,
  72. InstrumentationOptions);
  73. };
  74. } // end anonymous namespace
  75. void XRayInstrumentation::replaceRetWithPatchableRet(
  76. MachineFunction &MF, const TargetInstrInfo *TII,
  77. InstrumentationOptions op) {
  78. // We look for *all* terminators and returns, then replace those with
  79. // PATCHABLE_RET instructions.
  80. SmallVector<MachineInstr *, 4> Terminators;
  81. for (auto &MBB : MF) {
  82. for (auto &T : MBB.terminators()) {
  83. unsigned Opc = 0;
  84. if (T.isReturn() &&
  85. (op.HandleAllReturns || T.getOpcode() == TII->getReturnOpcode())) {
  86. // Replace return instructions with:
  87. // PATCHABLE_RET <Opcode>, <Operand>...
  88. Opc = TargetOpcode::PATCHABLE_RET;
  89. }
  90. if (TII->isTailCall(T) && op.HandleTailcall) {
  91. // Treat the tail call as a return instruction, which has a
  92. // different-looking sled than the normal return case.
  93. Opc = TargetOpcode::PATCHABLE_TAIL_CALL;
  94. }
  95. if (Opc != 0) {
  96. auto MIB = BuildMI(MBB, T, T.getDebugLoc(), TII->get(Opc))
  97. .addImm(T.getOpcode());
  98. for (auto &MO : T.operands())
  99. MIB.add(MO);
  100. Terminators.push_back(&T);
  101. if (T.shouldUpdateCallSiteInfo())
  102. MF.eraseCallSiteInfo(&T);
  103. }
  104. }
  105. }
  106. for (auto &I : Terminators)
  107. I->eraseFromParent();
  108. }
  109. void XRayInstrumentation::prependRetWithPatchableExit(
  110. MachineFunction &MF, const TargetInstrInfo *TII,
  111. InstrumentationOptions op) {
  112. for (auto &MBB : MF)
  113. for (auto &T : MBB.terminators()) {
  114. unsigned Opc = 0;
  115. if (T.isReturn() &&
  116. (op.HandleAllReturns || T.getOpcode() == TII->getReturnOpcode())) {
  117. Opc = TargetOpcode::PATCHABLE_FUNCTION_EXIT;
  118. }
  119. if (TII->isTailCall(T) && op.HandleTailcall) {
  120. Opc = TargetOpcode::PATCHABLE_TAIL_CALL;
  121. }
  122. if (Opc != 0) {
  123. // Prepend the return instruction with PATCHABLE_FUNCTION_EXIT or
  124. // PATCHABLE_TAIL_CALL .
  125. BuildMI(MBB, T, T.getDebugLoc(), TII->get(Opc));
  126. }
  127. }
  128. }
  129. bool XRayInstrumentation::runOnMachineFunction(MachineFunction &MF) {
  130. auto &F = MF.getFunction();
  131. auto InstrAttr = F.getFnAttribute("function-instrument");
  132. bool AlwaysInstrument = InstrAttr.isStringAttribute() &&
  133. InstrAttr.getValueAsString() == "xray-always";
  134. bool NeverInstrument = InstrAttr.isStringAttribute() &&
  135. InstrAttr.getValueAsString() == "xray-never";
  136. if (NeverInstrument && !AlwaysInstrument)
  137. return false;
  138. auto ThresholdAttr = F.getFnAttribute("xray-instruction-threshold");
  139. auto IgnoreLoopsAttr = F.getFnAttribute("xray-ignore-loops");
  140. unsigned int XRayThreshold = 0;
  141. if (!AlwaysInstrument) {
  142. if (!ThresholdAttr.isStringAttribute())
  143. return false; // XRay threshold attribute not found.
  144. if (ThresholdAttr.getValueAsString().getAsInteger(10, XRayThreshold))
  145. return false; // Invalid value for threshold.
  146. bool IgnoreLoops = IgnoreLoopsAttr.isValid();
  147. // Count the number of MachineInstr`s in MachineFunction
  148. int64_t MICount = 0;
  149. for (const auto &MBB : MF)
  150. MICount += MBB.size();
  151. bool TooFewInstrs = MICount < XRayThreshold;
  152. if (!IgnoreLoops) {
  153. // Get MachineDominatorTree or compute it on the fly if it's unavailable
  154. auto *MDT = getAnalysisIfAvailable<MachineDominatorTree>();
  155. MachineDominatorTree ComputedMDT;
  156. if (!MDT) {
  157. ComputedMDT.getBase().recalculate(MF);
  158. MDT = &ComputedMDT;
  159. }
  160. // Get MachineLoopInfo or compute it on the fly if it's unavailable
  161. auto *MLI = getAnalysisIfAvailable<MachineLoopInfo>();
  162. MachineLoopInfo ComputedMLI;
  163. if (!MLI) {
  164. ComputedMLI.getBase().analyze(MDT->getBase());
  165. MLI = &ComputedMLI;
  166. }
  167. // Check if we have a loop.
  168. // FIXME: Maybe make this smarter, and see whether the loops are dependent
  169. // on inputs or side-effects?
  170. if (MLI->empty() && TooFewInstrs)
  171. return false; // Function is too small and has no loops.
  172. } else if (TooFewInstrs) {
  173. // Function is too small
  174. return false;
  175. }
  176. }
  177. // We look for the first non-empty MachineBasicBlock, so that we can insert
  178. // the function instrumentation in the appropriate place.
  179. auto MBI = llvm::find_if(
  180. MF, [&](const MachineBasicBlock &MBB) { return !MBB.empty(); });
  181. if (MBI == MF.end())
  182. return false; // The function is empty.
  183. auto *TII = MF.getSubtarget().getInstrInfo();
  184. auto &FirstMBB = *MBI;
  185. auto &FirstMI = *FirstMBB.begin();
  186. if (!MF.getSubtarget().isXRaySupported()) {
  187. FirstMI.emitError("An attempt to perform XRay instrumentation for an"
  188. " unsupported target.");
  189. return false;
  190. }
  191. if (!F.hasFnAttribute("xray-skip-entry")) {
  192. // First, insert an PATCHABLE_FUNCTION_ENTER as the first instruction of the
  193. // MachineFunction.
  194. BuildMI(FirstMBB, FirstMI, FirstMI.getDebugLoc(),
  195. TII->get(TargetOpcode::PATCHABLE_FUNCTION_ENTER));
  196. }
  197. if (!F.hasFnAttribute("xray-skip-exit")) {
  198. switch (MF.getTarget().getTargetTriple().getArch()) {
  199. case Triple::ArchType::arm:
  200. case Triple::ArchType::thumb:
  201. case Triple::ArchType::aarch64:
  202. case Triple::ArchType::hexagon:
  203. case Triple::ArchType::mips:
  204. case Triple::ArchType::mipsel:
  205. case Triple::ArchType::mips64:
  206. case Triple::ArchType::mips64el: {
  207. // For the architectures which don't have a single return instruction
  208. InstrumentationOptions op;
  209. op.HandleTailcall = false;
  210. op.HandleAllReturns = true;
  211. prependRetWithPatchableExit(MF, TII, op);
  212. break;
  213. }
  214. case Triple::ArchType::ppc64le: {
  215. // PPC has conditional returns. Turn them into branch and plain returns.
  216. InstrumentationOptions op;
  217. op.HandleTailcall = false;
  218. op.HandleAllReturns = true;
  219. replaceRetWithPatchableRet(MF, TII, op);
  220. break;
  221. }
  222. default: {
  223. // For the architectures that have a single return instruction (such as
  224. // RETQ on x86_64).
  225. InstrumentationOptions op;
  226. op.HandleTailcall = true;
  227. op.HandleAllReturns = false;
  228. replaceRetWithPatchableRet(MF, TII, op);
  229. break;
  230. }
  231. }
  232. }
  233. return true;
  234. }
  235. char XRayInstrumentation::ID = 0;
  236. char &llvm::XRayInstrumentationID = XRayInstrumentation::ID;
  237. INITIALIZE_PASS_BEGIN(XRayInstrumentation, "xray-instrumentation",
  238. "Insert XRay ops", false, false)
  239. INITIALIZE_PASS_DEPENDENCY(MachineLoopInfo)
  240. INITIALIZE_PASS_END(XRayInstrumentation, "xray-instrumentation",
  241. "Insert XRay ops", false, false)