LLVM  14.0.0git
XRayInstrumentation.cpp
Go to the documentation of this file.
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 
16 #include "llvm/ADT/STLExtras.h"
17 #include "llvm/ADT/SmallVector.h"
18 #include "llvm/ADT/Triple.h"
27 #include "llvm/IR/Attributes.h"
28 #include "llvm/IR/Function.h"
29 #include "llvm/InitializePasses.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  if (T.shouldUpdateCallSiteInfo())
115  MF.eraseCallSiteInfo(&T);
116  }
117  }
118  }
119 
120  for (auto &I : Terminators)
121  I->eraseFromParent();
122 }
123 
124 void XRayInstrumentation::prependRetWithPatchableExit(
125  MachineFunction &MF, const TargetInstrInfo *TII,
126  InstrumentationOptions op) {
127  for (auto &MBB : MF)
128  for (auto &T : MBB.terminators()) {
129  unsigned Opc = 0;
130  if (T.isReturn() &&
131  (op.HandleAllReturns || T.getOpcode() == TII->getReturnOpcode())) {
132  Opc = TargetOpcode::PATCHABLE_FUNCTION_EXIT;
133  }
134  if (TII->isTailCall(T) && op.HandleTailcall) {
135  Opc = TargetOpcode::PATCHABLE_TAIL_CALL;
136  }
137  if (Opc != 0) {
138  // Prepend the return instruction with PATCHABLE_FUNCTION_EXIT or
139  // PATCHABLE_TAIL_CALL .
140  BuildMI(MBB, T, T.getDebugLoc(), TII->get(Opc));
141  }
142  }
143 }
144 
145 bool XRayInstrumentation::runOnMachineFunction(MachineFunction &MF) {
146  auto &F = MF.getFunction();
147  auto InstrAttr = F.getFnAttribute("function-instrument");
148  bool AlwaysInstrument = InstrAttr.isStringAttribute() &&
149  InstrAttr.getValueAsString() == "xray-always";
150  bool NeverInstrument = InstrAttr.isStringAttribute() &&
151  InstrAttr.getValueAsString() == "xray-never";
152  if (NeverInstrument && !AlwaysInstrument)
153  return false;
154  auto ThresholdAttr = F.getFnAttribute("xray-instruction-threshold");
155  auto IgnoreLoopsAttr = F.getFnAttribute("xray-ignore-loops");
156  unsigned int XRayThreshold = 0;
157  if (!AlwaysInstrument) {
158  if (!ThresholdAttr.isStringAttribute())
159  return false; // XRay threshold attribute not found.
160  if (ThresholdAttr.getValueAsString().getAsInteger(10, XRayThreshold))
161  return false; // Invalid value for threshold.
162 
163  bool IgnoreLoops = IgnoreLoopsAttr.isValid();
164 
165  // Count the number of MachineInstr`s in MachineFunction
166  int64_t MICount = 0;
167  for (const auto &MBB : MF)
168  MICount += MBB.size();
169 
170  bool TooFewInstrs = MICount < XRayThreshold;
171 
172  if (!IgnoreLoops) {
173  // Get MachineDominatorTree or compute it on the fly if it's unavailable
174  auto *MDT = getAnalysisIfAvailable<MachineDominatorTree>();
175  MachineDominatorTree ComputedMDT;
176  if (!MDT) {
177  ComputedMDT.getBase().recalculate(MF);
178  MDT = &ComputedMDT;
179  }
180 
181  // Get MachineLoopInfo or compute it on the fly if it's unavailable
182  auto *MLI = getAnalysisIfAvailable<MachineLoopInfo>();
183  MachineLoopInfo ComputedMLI;
184  if (!MLI) {
185  ComputedMLI.getBase().analyze(MDT->getBase());
186  MLI = &ComputedMLI;
187  }
188 
189  // Check if we have a loop.
190  // FIXME: Maybe make this smarter, and see whether the loops are dependent
191  // on inputs or side-effects?
192  if (MLI->empty() && TooFewInstrs)
193  return false; // Function is too small and has no loops.
194  } else if (TooFewInstrs) {
195  // Function is too small
196  return false;
197  }
198  }
199 
200  // We look for the first non-empty MachineBasicBlock, so that we can insert
201  // the function instrumentation in the appropriate place.
202  auto MBI = llvm::find_if(
203  MF, [&](const MachineBasicBlock &MBB) { return !MBB.empty(); });
204  if (MBI == MF.end())
205  return false; // The function is empty.
206 
207  auto *TII = MF.getSubtarget().getInstrInfo();
208  auto &FirstMBB = *MBI;
209  auto &FirstMI = *FirstMBB.begin();
210 
211  if (!MF.getSubtarget().isXRaySupported()) {
212  FirstMI.emitError("An attempt to perform XRay instrumentation for an"
213  " unsupported target.");
214  return false;
215  }
216 
217  if (!F.hasFnAttribute("xray-skip-entry")) {
218  // First, insert an PATCHABLE_FUNCTION_ENTER as the first instruction of the
219  // MachineFunction.
220  BuildMI(FirstMBB, FirstMI, FirstMI.getDebugLoc(),
221  TII->get(TargetOpcode::PATCHABLE_FUNCTION_ENTER));
222  }
223 
224  if (!F.hasFnAttribute("xray-skip-exit")) {
225  switch (MF.getTarget().getTargetTriple().getArch()) {
226  case Triple::ArchType::arm:
227  case Triple::ArchType::thumb:
228  case Triple::ArchType::aarch64:
229  case Triple::ArchType::mips:
230  case Triple::ArchType::mipsel:
231  case Triple::ArchType::mips64:
232  case Triple::ArchType::mips64el: {
233  // For the architectures which don't have a single return instruction
234  InstrumentationOptions op;
235  op.HandleTailcall = false;
236  op.HandleAllReturns = true;
237  prependRetWithPatchableExit(MF, TII, op);
238  break;
239  }
240  case Triple::ArchType::ppc64le: {
241  // PPC has conditional returns. Turn them into branch and plain returns.
242  InstrumentationOptions op;
243  op.HandleTailcall = false;
244  op.HandleAllReturns = true;
245  replaceRetWithPatchableRet(MF, TII, op);
246  break;
247  }
248  default: {
249  // For the architectures that have a single return instruction (such as
250  // RETQ on x86_64).
251  InstrumentationOptions op;
252  op.HandleTailcall = true;
253  op.HandleAllReturns = false;
254  replaceRetWithPatchableRet(MF, TII, op);
255  break;
256  }
257  }
258  }
259  return true;
260 }
261 
262 char XRayInstrumentation::ID = 0;
264 INITIALIZE_PASS_BEGIN(XRayInstrumentation, "xray-instrumentation",
265  "Insert XRay ops", false, false)
267 INITIALIZE_PASS_END(XRayInstrumentation, "xray-instrumentation",
268  "Insert XRay ops", false, false)
llvm::HexagonInstrInfo::isTailCall
bool isTailCall(const MachineInstr &MI) const override
Definition: HexagonInstrInfo.cpp:2611
instrumentation
xray instrumentation
Definition: XRayInstrumentation.cpp:267
llvm::MachineInstrBuilder::addImm
const MachineInstrBuilder & addImm(int64_t Val) const
Add a new immediate operand.
Definition: MachineInstrBuilder.h:131
llvm
This file implements support for optimizing divisions by a constant.
Definition: AllocatorList.h:23
T
llvm::MachineInstrBuilder::add
const MachineInstrBuilder & add(const MachineOperand &MO) const
Definition: MachineInstrBuilder.h:224
Pass.h
op
#define op(i)
llvm::SmallVector< MachineInstr *, 4 >
llvm::MachineFunctionPass
MachineFunctionPass - This class adapts the FunctionPass interface to allow convenient creation of pa...
Definition: MachineFunctionPass.h:30
MachineBasicBlock.h
TargetInstrInfo.h
STLExtras.h
llvm::MachineBasicBlock::terminators
iterator_range< iterator > terminators()
Definition: MachineBasicBlock.h:288
llvm::MachineFunctionPass::getAnalysisUsage
void getAnalysisUsage(AnalysisUsage &AU) const override
getAnalysisUsage - Subclasses that override getAnalysisUsage must call this.
Definition: MachineFunctionPass.cpp:102
F
#define F(x, y, z)
Definition: MD5.cpp:56
llvm::MachineLoopInfo
Definition: MachineLoopInfo.h:90
llvm::TargetInstrInfo
TargetInstrInfo - Interface to description of machine instruction set.
Definition: TargetInstrInfo.h:97
MachineLoopInfo.h
TargetMachine.h
llvm::PassRegistry::getPassRegistry
static PassRegistry * getPassRegistry()
getPassRegistry - Access the global registry object, which is automatically initialized at applicatio...
Definition: PassRegistry.cpp:31
llvm::AnalysisUsage
Represent the analysis usage information of a pass.
Definition: PassAnalysisSupport.h:47
INITIALIZE_PASS_BEGIN
INITIALIZE_PASS_BEGIN(XRayInstrumentation, "xray-instrumentation", "Insert XRay ops", false, false) INITIALIZE_PASS_END(XRayInstrumentation
false
Definition: StackSlotColoring.cpp:142
TII
const HexagonInstrInfo * TII
Definition: HexagonCopyToCombine.cpp:129
llvm::MachineBasicBlock
Definition: MachineBasicBlock.h:95
INITIALIZE_PASS_END
#define INITIALIZE_PASS_END(passName, arg, name, cfg, analysis)
Definition: PassSupport.h:58
llvm::MachineDominatorTree::getBase
DomTreeT & getBase()
Definition: MachineDominators.h:87
INITIALIZE_PASS_DEPENDENCY
INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass)
I
#define I(x, y, z)
Definition: MD5.cpp:59
MachineFunctionPass.h
llvm::MachineBasicBlock::size
unsigned size() const
Definition: MachineBasicBlock.h:239
ops
xray Insert XRay ops
Definition: XRayInstrumentation.cpp:268
llvm::MachineFunction
Definition: MachineFunction.h:234
Triple.h
llvm::DominatorTreeBase::recalculate
void recalculate(ParentType &Func)
recalculate - compute a dominator tree for the given function
Definition: GenericDomTree.h:778
llvm::XRayInstrumentationID
char & XRayInstrumentationID
This pass inserts the XRay instrumentation sleds if they are supported by the target platform.
Definition: XRayInstrumentation.cpp:263
llvm::AnalysisUsage::setPreservesCFG
void setPreservesCFG()
This function should be called by the pass, iff they do not:
Definition: Pass.cpp:253
llvm::AnalysisUsage::addPreserved
AnalysisUsage & addPreserved()
Add the specified Pass class to the set of analyses preserved by this pass.
Definition: PassAnalysisSupport.h:98
TargetSubtargetInfo.h
llvm::find_if
auto find_if(R &&Range, UnaryPredicate P)
Provide wrappers to std::find_if which take ranges instead of having to pass begin/end explicitly.
Definition: STLExtras.h:1578
MBB
MachineBasicBlock & MBB
Definition: AArch64SLSHardening.cpp:74
Attributes.h
llvm::MachineFunction::getFunction
Function & getFunction()
Return the LLVM function that this machine code represents.
Definition: MachineFunction.h:596
llvm::initializeXRayInstrumentationPass
void initializeXRayInstrumentationPass(PassRegistry &)
Function.h
llvm::MachineLoopInfo::getBase
LoopInfoBase< MachineBasicBlock, MachineLoop > & getBase()
Definition: MachineLoopInfo.h:106
SmallVector.h
MachineInstrBuilder.h
llvm::BuildMI
MachineInstrBuilder BuildMI(MachineFunction &MF, const DebugLoc &DL, const MCInstrDesc &MCID)
Builder interface. Specify how to create the initial instruction itself.
Definition: MachineInstrBuilder.h:328
llvm::MachineBasicBlock::empty
bool empty() const
Definition: MachineBasicBlock.h:240
llvm::MachineDominatorTree
DominatorTree Class - Concrete subclass of DominatorTreeBase that is used to compute a normal dominat...
Definition: MachineDominators.h:45
MachineFunction.h
InitializePasses.h
MachineDominators.h
llvm::Intrinsic::ID
unsigned ID
Definition: TargetTransformInfo.h:37