LLVM  8.0.1
XRayInstrumentation.cpp
Go to the documentation of this file.
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 
17 #include "llvm/ADT/STLExtras.h"
18 #include "llvm/ADT/SmallVector.h"
19 #include "llvm/ADT/Triple.h"
28 #include "llvm/IR/Attributes.h"
29 #include "llvm/IR/Function.h"
30 #include "llvm/Pass.h"
32 
33 using namespace llvm;
34 
35 namespace {
36 
37 struct InstrumentationOptions {
38  // Whether to emit PATCHABLE_TAIL_CALL.
39  bool HandleTailcall;
40 
41  // Whether to emit PATCHABLE_RET/PATCHABLE_FUNCTION_EXIT for all forms of
42  // return, e.g. conditional return.
43  bool HandleAllReturns;
44 };
45 
46 struct XRayInstrumentation : public MachineFunctionPass {
47  static char ID;
48 
49  XRayInstrumentation() : MachineFunctionPass(ID) {
51  }
52 
53  void getAnalysisUsage(AnalysisUsage &AU) const override {
54  AU.setPreservesCFG();
58  }
59 
60  bool runOnMachineFunction(MachineFunction &MF) override;
61 
62 private:
63  // Replace the original RET instruction with the exit sled code ("patchable
64  // ret" pseudo-instruction), so that at runtime XRay can replace the sled
65  // with a code jumping to XRay trampoline, which calls the tracing handler
66  // and, in the end, issues the RET instruction.
67  // This is the approach to go on CPUs which have a single RET instruction,
68  // like x86/x86_64.
69  void replaceRetWithPatchableRet(MachineFunction &MF,
70  const TargetInstrInfo *TII,
71  InstrumentationOptions);
72 
73  // Prepend the original return instruction with the exit sled code ("patchable
74  // function exit" pseudo-instruction), preserving the original return
75  // instruction just after the exit sled code.
76  // This is the approach to go on CPUs which have multiple options for the
77  // return instruction, like ARM. For such CPUs we can't just jump into the
78  // XRay trampoline and issue a single return instruction there. We rather
79  // have to call the trampoline and return from it to the original return
80  // instruction of the function being instrumented.
81  void prependRetWithPatchableExit(MachineFunction &MF,
82  const TargetInstrInfo *TII,
83  InstrumentationOptions);
84 };
85 
86 } // end anonymous namespace
87 
88 void XRayInstrumentation::replaceRetWithPatchableRet(
90  InstrumentationOptions op) {
91  // We look for *all* terminators and returns, then replace those with
92  // PATCHABLE_RET instructions.
94  for (auto &MBB : MF) {
95  for (auto &T : MBB.terminators()) {
96  unsigned Opc = 0;
97  if (T.isReturn() &&
98  (op.HandleAllReturns || T.getOpcode() == TII->getReturnOpcode())) {
99  // Replace return instructions with:
100  // PATCHABLE_RET <Opcode>, <Operand>...
101  Opc = TargetOpcode::PATCHABLE_RET;
102  }
103  if (TII->isTailCall(T) && op.HandleTailcall) {
104  // Treat the tail call as a return instruction, which has a
105  // different-looking sled than the normal return case.
106  Opc = TargetOpcode::PATCHABLE_TAIL_CALL;
107  }
108  if (Opc != 0) {
109  auto MIB = BuildMI(MBB, T, T.getDebugLoc(), TII->get(Opc))
110  .addImm(T.getOpcode());
111  for (auto &MO : T.operands())
112  MIB.add(MO);
113  Terminators.push_back(&T);
114  }
115  }
116  }
117 
118  for (auto &I : Terminators)
119  I->eraseFromParent();
120 }
121 
122 void XRayInstrumentation::prependRetWithPatchableExit(
123  MachineFunction &MF, const TargetInstrInfo *TII,
124  InstrumentationOptions op) {
125  for (auto &MBB : MF)
126  for (auto &T : MBB.terminators()) {
127  unsigned Opc = 0;
128  if (T.isReturn() &&
129  (op.HandleAllReturns || T.getOpcode() == TII->getReturnOpcode())) {
130  Opc = TargetOpcode::PATCHABLE_FUNCTION_EXIT;
131  }
132  if (TII->isTailCall(T) && op.HandleTailcall) {
133  Opc = TargetOpcode::PATCHABLE_TAIL_CALL;
134  }
135  if (Opc != 0) {
136  // Prepend the return instruction with PATCHABLE_FUNCTION_EXIT or
137  // PATCHABLE_TAIL_CALL .
138  BuildMI(MBB, T, T.getDebugLoc(), TII->get(Opc));
139  }
140  }
141 }
142 
143 bool XRayInstrumentation::runOnMachineFunction(MachineFunction &MF) {
144  auto &F = MF.getFunction();
145  auto InstrAttr = F.getFnAttribute("function-instrument");
146  bool AlwaysInstrument = !InstrAttr.hasAttribute(Attribute::None) &&
147  InstrAttr.isStringAttribute() &&
148  InstrAttr.getValueAsString() == "xray-always";
149  Attribute Attr = F.getFnAttribute("xray-instruction-threshold");
150  unsigned XRayThreshold = 0;
151  if (!AlwaysInstrument) {
152  if (Attr.hasAttribute(Attribute::None) || !Attr.isStringAttribute())
153  return false; // XRay threshold attribute not found.
154  if (Attr.getValueAsString().getAsInteger(10, XRayThreshold))
155  return false; // Invalid value for threshold.
156 
157  // Count the number of MachineInstr`s in MachineFunction
158  int64_t MICount = 0;
159  for (const auto &MBB : MF)
160  MICount += MBB.size();
161 
162  // Get MachineDominatorTree or compute it on the fly if it's unavailable
163  auto *MDT = getAnalysisIfAvailable<MachineDominatorTree>();
164  MachineDominatorTree ComputedMDT;
165  if (!MDT) {
166  ComputedMDT.getBase().recalculate(MF);
167  MDT = &ComputedMDT;
168  }
169 
170  // Get MachineLoopInfo or compute it on the fly if it's unavailable
171  auto *MLI = getAnalysisIfAvailable<MachineLoopInfo>();
172  MachineLoopInfo ComputedMLI;
173  if (!MLI) {
174  ComputedMLI.getBase().analyze(MDT->getBase());
175  MLI = &ComputedMLI;
176  }
177 
178  // Check if we have a loop.
179  // FIXME: Maybe make this smarter, and see whether the loops are dependent
180  // on inputs or side-effects?
181  if (MLI->empty() && MICount < XRayThreshold)
182  return false; // Function is too small and has no loops.
183  }
184 
185  // We look for the first non-empty MachineBasicBlock, so that we can insert
186  // the function instrumentation in the appropriate place.
187  auto MBI = llvm::find_if(
188  MF, [&](const MachineBasicBlock &MBB) { return !MBB.empty(); });
189  if (MBI == MF.end())
190  return false; // The function is empty.
191 
192  auto *TII = MF.getSubtarget().getInstrInfo();
193  auto &FirstMBB = *MBI;
194  auto &FirstMI = *FirstMBB.begin();
195 
196  if (!MF.getSubtarget().isXRaySupported()) {
197  FirstMI.emitError("An attempt to perform XRay instrumentation for an"
198  " unsupported target.");
199  return false;
200  }
201 
202  // First, insert an PATCHABLE_FUNCTION_ENTER as the first instruction of the
203  // MachineFunction.
204  BuildMI(FirstMBB, FirstMI, FirstMI.getDebugLoc(),
205  TII->get(TargetOpcode::PATCHABLE_FUNCTION_ENTER));
206 
207  switch (MF.getTarget().getTargetTriple().getArch()) {
208  case Triple::ArchType::arm:
209  case Triple::ArchType::thumb:
210  case Triple::ArchType::aarch64:
211  case Triple::ArchType::mips:
212  case Triple::ArchType::mipsel:
213  case Triple::ArchType::mips64:
214  case Triple::ArchType::mips64el: {
215  // For the architectures which don't have a single return instruction
216  InstrumentationOptions op;
217  op.HandleTailcall = false;
218  op.HandleAllReturns = true;
219  prependRetWithPatchableExit(MF, TII, op);
220  break;
221  }
222  case Triple::ArchType::ppc64le: {
223  // PPC has conditional returns. Turn them into branch and plain returns.
224  InstrumentationOptions op;
225  op.HandleTailcall = false;
226  op.HandleAllReturns = true;
227  replaceRetWithPatchableRet(MF, TII, op);
228  break;
229  }
230  default: {
231  // For the architectures that have a single return instruction (such as
232  // RETQ on x86_64).
233  InstrumentationOptions op;
234  op.HandleTailcall = true;
235  op.HandleAllReturns = false;
236  replaceRetWithPatchableRet(MF, TII, op);
237  break;
238  }
239  }
240  return true;
241 }
242 
243 char XRayInstrumentation::ID = 0;
245 INITIALIZE_PASS_BEGIN(XRayInstrumentation, "xray-instrumentation",
246  "Insert XRay ops", false, false)
248 INITIALIZE_PASS_END(XRayInstrumentation, "xray-instrumentation",
249  "Insert XRay ops", false, false)
const MachineInstrBuilder & add(const MachineOperand &MO) const
AnalysisUsage & addPreserved()
Add the specified Pass class to the set of analyses preserved by this pass.
static PassRegistry * getPassRegistry()
getPassRegistry - Access the global registry object, which is automatically initialized at applicatio...
This class represents lattice values for constants.
Definition: AllocatorList.h:24
void push_back(const T &Elt)
Definition: SmallVector.h:218
F(f)
#define op(i)
#define INITIALIZE_PASS_DEPENDENCY(depName)
Definition: PassSupport.h:51
MachineFunctionPass - This class adapts the FunctionPass interface to allow convenient creation of pa...
bool isStringAttribute() const
Return true if the attribute is a string (target-dependent) attribute.
Definition: Attributes.cpp:170
const HexagonInstrInfo * TII
This file contains the simple types necessary to represent the attributes associated with functions a...
No attributes have been set.
Definition: Attributes.h:72
char & XRayInstrumentationID
This pass inserts the XRay instrumentation sleds if they are supported by the target platform...
TargetInstrInfo - Interface to description of machine instruction set.
void initializeXRayInstrumentationPass(PassRegistry &)
MachineInstrBuilder BuildMI(MachineFunction &MF, const DebugLoc &DL, const MCInstrDesc &MCID)
Builder interface. Specify how to create the initial instruction itself.
xray instrumentation
bool hasAttribute(AttrKind Val) const
Return true if the attribute is present.
Definition: Attributes.cpp:202
void getAnalysisUsage(AnalysisUsage &AU) const override
getAnalysisUsage - Subclasses that override getAnalysisUsage must call this.
Represent the analysis usage information of a pass.
auto find_if(R &&Range, UnaryPredicate P) -> decltype(adl_begin(Range))
Provide wrappers to std::find_if which take ranges instead of having to pass begin/end explicitly...
Definition: STLExtras.h:1214
INITIALIZE_PASS_END(RegBankSelect, DEBUG_TYPE, "Assign register bank of generic virtual registers", false, false) RegBankSelect
std::enable_if< std::numeric_limits< T >::is_signed, bool >::type getAsInteger(unsigned Radix, T &Result) const
Parse the current string as an integer of the specified radix.
Definition: StringRef.h:497
void setPreservesCFG()
This function should be called by the pass, iff they do not:
Definition: Pass.cpp:286
virtual bool isTailCall(const MachineInstr &Inst) const
Determines whether Inst is a tail call instruction.
const Function & getFunction() const
Return the LLVM function that this machine code represents.
unsigned getReturnOpcode() const
INITIALIZE_PASS_BEGIN(XRayInstrumentation, "xray-instrumentation", "Insert XRay ops", false, false) INITIALIZE_PASS_END(XRayInstrumentation
xray Insert XRay ops
StringRef getValueAsString() const
Return the attribute&#39;s value as a string.
Definition: Attributes.cpp:195
const MCInstrDesc & get(unsigned Opcode) const
Return the machine instruction descriptor that corresponds to the specified instruction opcode...
Definition: MCInstrInfo.h:45
#define I(x, y, z)
Definition: MD5.cpp:58
DomTreeBase< MachineBasicBlock > & getBase()
DominatorTree Class - Concrete subclass of DominatorTreeBase that is used to compute a normal dominat...
LoopInfoBase< MachineBasicBlock, MachineLoop > & getBase()