LLVM  4.0.0
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/CodeGen/Analysis.h"
21 #include "llvm/CodeGen/Passes.h"
25 
26 using namespace llvm;
27 
28 namespace {
29 struct XRayInstrumentation : public MachineFunctionPass {
30  static char ID;
31 
32  XRayInstrumentation() : MachineFunctionPass(ID) {
34  }
35 
36  bool runOnMachineFunction(MachineFunction &MF) override;
37 
38 private:
39  // Replace the original RET instruction with the exit sled code ("patchable
40  // ret" pseudo-instruction), so that at runtime XRay can replace the sled
41  // with a code jumping to XRay trampoline, which calls the tracing handler
42  // and, in the end, issues the RET instruction.
43  // This is the approach to go on CPUs which have a single RET instruction,
44  // like x86/x86_64.
45  void replaceRetWithPatchableRet(MachineFunction &MF,
46  const TargetInstrInfo *TII);
47 
48  // Prepend the original return instruction with the exit sled code ("patchable
49  // function exit" pseudo-instruction), preserving the original return
50  // instruction just after the exit sled code.
51  // This is the approach to go on CPUs which have multiple options for the
52  // return instruction, like ARM. For such CPUs we can't just jump into the
53  // XRay trampoline and issue a single return instruction there. We rather
54  // have to call the trampoline and return from it to the original return
55  // instruction of the function being instrumented.
56  void prependRetWithPatchableExit(MachineFunction &MF,
57  const TargetInstrInfo *TII);
58 };
59 } // anonymous namespace
60 
61 void XRayInstrumentation::replaceRetWithPatchableRet(MachineFunction &MF,
62  const TargetInstrInfo *TII)
63 {
64  // We look for *all* terminators and returns, then replace those with
65  // PATCHABLE_RET instructions.
67  for (auto &MBB : MF) {
68  for (auto &T : MBB.terminators()) {
69  unsigned Opc = 0;
70  if (T.isReturn() && T.getOpcode() == TII->getReturnOpcode()) {
71  // Replace return instructions with:
72  // PATCHABLE_RET <Opcode>, <Operand>...
73  Opc = TargetOpcode::PATCHABLE_RET;
74  }
75  if (TII->isTailCall(T)) {
76  // Treat the tail call as a return instruction, which has a
77  // different-looking sled than the normal return case.
78  Opc = TargetOpcode::PATCHABLE_TAIL_CALL;
79  }
80  if (Opc != 0) {
81  auto MIB = BuildMI(MBB, T, T.getDebugLoc(), TII->get(Opc))
82  .addImm(T.getOpcode());
83  for (auto &MO : T.operands())
84  MIB.addOperand(MO);
85  Terminators.push_back(&T);
86  }
87  }
88  }
89 
90  for (auto &I : Terminators)
91  I->eraseFromParent();
92 }
93 
94 void XRayInstrumentation::prependRetWithPatchableExit(MachineFunction &MF,
95  const TargetInstrInfo *TII)
96 {
97  for (auto &MBB : MF) {
98  for (auto &T : MBB.terminators()) {
99  unsigned Opc = 0;
100  if (T.isReturn()) {
101  Opc = TargetOpcode::PATCHABLE_FUNCTION_EXIT;
102  }
103  if (TII->isTailCall(T)) {
104  Opc = TargetOpcode::PATCHABLE_TAIL_CALL;
105  }
106  if (Opc != 0) {
107  // Prepend the return instruction with PATCHABLE_FUNCTION_EXIT or
108  // PATCHABLE_TAIL_CALL .
109  BuildMI(MBB, T, T.getDebugLoc(),TII->get(Opc));
110  }
111  }
112  }
113 }
114 
115 bool XRayInstrumentation::runOnMachineFunction(MachineFunction &MF) {
116  auto &F = *MF.getFunction();
117  auto InstrAttr = F.getFnAttribute("function-instrument");
118  bool AlwaysInstrument = !InstrAttr.hasAttribute(Attribute::None) &&
119  InstrAttr.isStringAttribute() &&
120  InstrAttr.getValueAsString() == "xray-always";
121  Attribute Attr = F.getFnAttribute("xray-instruction-threshold");
122  unsigned XRayThreshold = 0;
123  if (!AlwaysInstrument) {
124  if (Attr.hasAttribute(Attribute::None) || !Attr.isStringAttribute())
125  return false; // XRay threshold attribute not found.
126  if (Attr.getValueAsString().getAsInteger(10, XRayThreshold))
127  return false; // Invalid value for threshold.
128  if (F.size() < XRayThreshold)
129  return false; // Function is too small.
130  }
131 
132  // We look for the first non-empty MachineBasicBlock, so that we can insert
133  // the function instrumentation in the appropriate place.
134  auto MBI =
135  find_if(MF, [&](const MachineBasicBlock &MBB) { return !MBB.empty(); });
136  if (MBI == MF.end())
137  return false; // The function is empty.
138 
139  auto *TII = MF.getSubtarget().getInstrInfo();
140  auto &FirstMBB = *MBI;
141  auto &FirstMI = *FirstMBB.begin();
142 
143  if (!MF.getSubtarget().isXRaySupported()) {
144  FirstMI.emitError("An attempt to perform XRay instrumentation for an"
145  " unsupported target.");
146  return false;
147  }
148 
149  // FIXME: Do the loop triviality analysis here or in an earlier pass.
150 
151  // First, insert an PATCHABLE_FUNCTION_ENTER as the first instruction of the
152  // MachineFunction.
153  BuildMI(FirstMBB, FirstMI, FirstMI.getDebugLoc(),
154  TII->get(TargetOpcode::PATCHABLE_FUNCTION_ENTER));
155 
156  switch (MF.getTarget().getTargetTriple().getArch()) {
157  case Triple::ArchType::arm:
158  case Triple::ArchType::thumb:
159  case Triple::ArchType::aarch64:
160  // For the architectures which don't have a single return instruction
161  prependRetWithPatchableExit(MF, TII);
162  break;
163  default:
164  // For the architectures that have a single return instruction (such as
165  // RETQ on x86_64).
166  replaceRetWithPatchableRet(MF, TII);
167  break;
168  }
169  return true;
170 }
171 
172 char XRayInstrumentation::ID = 0;
174 INITIALIZE_PASS(XRayInstrumentation, "xray-instrumentation", "Insert XRay ops",
175  false, false)
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:494
static PassRegistry * getPassRegistry()
getPassRegistry - Access the global registry object, which is automatically initialized at applicatio...
const Function * getFunction() const
getFunction - Return the LLVM function that this machine code represents
bool hasAttribute(AttrKind Val) const
Return true if the attribute is present.
Definition: Attributes.cpp:185
const Triple & getTargetTriple() const
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
MachineFunctionPass - This class adapts the FunctionPass interface to allow convenient creation of pa...
const HexagonInstrInfo * TII
iterator_range< iterator > terminators()
No attributes have been set.
Definition: Attributes.h:69
char & XRayInstrumentationID
This pass inserts the XRay instrumentation sleds if they are supported by the target platform...
#define F(x, y, z)
Definition: MD5.cpp:51
MachineBasicBlock * MBB
ArchType getArch() const
getArch - Get the parsed architecture type of this triple.
Definition: Triple.h:270
virtual bool isXRaySupported() const
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.
virtual bool isTailCall(const MachineInstr &Inst) const
Determines whether |Inst| is a tail call instruction.
unsigned getReturnOpcode() const
const MCInstrDesc & get(unsigned Opcode) const
Return the machine instruction descriptor that corresponds to the specified instruction opcode...
Definition: MCInstrInfo.h:45
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
Definition: PassSupport.h:36
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small...
Definition: SmallVector.h:843
#define I(x, y, z)
Definition: MD5.cpp:54
const TargetMachine & getTarget() const
getTarget - Return the target machine this machine code is compiled with
bool isStringAttribute() const
Return true if the attribute is a string (target-dependent) attribute.
Definition: Attributes.cpp:153
StringRef getValueAsString() const
Return the attribute's value as a string.
Definition: Attributes.cpp:178
virtual const TargetInstrInfo * getInstrInfo() const
const MachineInstrBuilder & addOperand(const MachineOperand &MO) const
auto find_if(R &&Range, UnaryPredicate P) -> decltype(std::begin(Range))
Provide wrappers to std::find_if which take ranges instead of having to pass begin/end explicitly...
Definition: STLExtras.h:764