LLVM: lib/CodeGen/XRayInstrumentation.cpp Source File (original) (raw)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
36
37using namespace llvm;
38
39namespace {
40
41struct InstrumentationOptions {
42
43 bool HandleTailcall;
44
45
46
47 bool HandleAllReturns;
48};
49
51 static char ID;
52
53 XRayInstrumentationLegacy() : MachineFunctionPass(ID) {
55 }
56
57 void getAnalysisUsage(AnalysisUsage &AU) const override {
59 AU.addPreserved();
60 AU.addPreserved();
62 }
63
64 bool runOnMachineFunction(MachineFunction &MF) override;
65};
66
67struct XRayInstrumentation {
68 XRayInstrumentation(MachineDominatorTree *MDT, MachineLoopInfo *MLI)
69 : MDT(MDT), MLI(MLI) {}
70
71 bool run(MachineFunction &MF);
72
73
74
75 static bool alwaysInstrument(Function &F) {
76 auto InstrAttr = F.getFnAttribute("function-instrument");
77 return InstrAttr.isStringAttribute() &&
78 InstrAttr.getValueAsString() == "xray-always";
79 }
80
81 static bool needMDTAndMLIAnalyses(Function &F) {
82 auto IgnoreLoopsAttr = F.getFnAttribute("xray-ignore-loops");
83 auto AlwaysInstrument = XRayInstrumentation::alwaysInstrument(F);
84 return !AlwaysInstrument && !IgnoreLoopsAttr.isValid();
85 }
86
87private:
88
89
90
91
92
93
94 void replaceRetWithPatchableRet(MachineFunction &MF,
95 const TargetInstrInfo *TII,
96 InstrumentationOptions);
97
98
99
100
101
102
103
104
105
106 void prependRetWithPatchableExit(MachineFunction &MF,
107 const TargetInstrInfo *TII,
108 InstrumentationOptions);
109
110 MachineDominatorTree *MDT;
111 MachineLoopInfo *MLI;
112};
113
114}
115
116void XRayInstrumentation::replaceRetWithPatchableRet(
118 InstrumentationOptions op) {
119
120
121 SmallVector<MachineInstr *, 4> Terminators;
122 for (auto &MBB : MF) {
124 unsigned Opc = 0;
125 if (T.isReturn() &&
126 (op.HandleAllReturns || T.getOpcode() == TII->getReturnOpcode())) {
127
128
129 Opc = TargetOpcode::PATCHABLE_RET;
130 }
132
133
134 Opc = TargetOpcode::PATCHABLE_TAIL_CALL;
135 }
136 if (Opc != 0) {
139 for (auto &MO : T.operands())
140 MIB.add(MO);
142 if (T.shouldUpdateAdditionalCallInfo())
143 MF.eraseAdditionalCallInfo(&T);
144 }
145 }
146 }
147
148 for (auto &I : Terminators)
149 I->eraseFromParent();
150}
151
152void XRayInstrumentation::prependRetWithPatchableExit(
153 MachineFunction &MF, const TargetInstrInfo *TII,
154 InstrumentationOptions op) {
155 for (auto &MBB : MF)
157 unsigned Opc = 0;
158 if (T.isReturn() &&
159 (op.HandleAllReturns || T.getOpcode() == TII->getReturnOpcode())) {
160 Opc = TargetOpcode::PATCHABLE_FUNCTION_EXIT;
161 }
163 Opc = TargetOpcode::PATCHABLE_TAIL_CALL;
164 }
165 if (Opc != 0) {
166
167
169 }
170 }
171}
172
173PreservedAnalyses
178
179 if (XRayInstrumentation::needMDTAndMLIAnalyses(MF.getFunction())) {
182 }
183
184 if (!XRayInstrumentation(MDT, MLI).run(MF))
186
189 return PA;
190}
191
192bool XRayInstrumentationLegacy::runOnMachineFunction(MachineFunction &MF) {
195 if (XRayInstrumentation::needMDTAndMLIAnalyses(MF.getFunction())) {
196 auto *MDTWrapper =
197 getAnalysisIfAvailable();
198 MDT = MDTWrapper ? &MDTWrapper->getDomTree() : nullptr;
199 auto *MLIWrapper = getAnalysisIfAvailable();
200 MLI = MLIWrapper ? &MLIWrapper->getLI() : nullptr;
201 }
202 return XRayInstrumentation(MDT, MLI).run(MF);
203}
204
205bool XRayInstrumentation::run(MachineFunction &MF) {
207 auto InstrAttr = F.getFnAttribute("function-instrument");
208 bool AlwaysInstrument = alwaysInstrument(F);
209 bool NeverInstrument = InstrAttr.isStringAttribute() &&
210 InstrAttr.getValueAsString() == "xray-never";
211 if (NeverInstrument && !AlwaysInstrument)
212 return false;
213 auto IgnoreLoopsAttr = F.getFnAttribute("xray-ignore-loops");
214
215 uint64_t XRayThreshold = 0;
216 if (!AlwaysInstrument) {
217 bool IgnoreLoops = IgnoreLoopsAttr.isValid();
218 XRayThreshold = F.getFnAttributeAsParsedInteger(
219 "xray-instruction-threshold", std::numeric_limits<uint64_t>::max());
220 if (XRayThreshold == std::numeric_limits<uint64_t>::max())
221 return false;
222
223
224 uint64_t MICount = 0;
225 for (const auto &MBB : MF)
227
228 bool TooFewInstrs = MICount < XRayThreshold;
229
230 if (!IgnoreLoops) {
231
232 MachineDominatorTree ComputedMDT;
233 if (!MDT) {
235 MDT = &ComputedMDT;
236 }
237
238
239 MachineLoopInfo ComputedMLI;
240 if (!MLI) {
241 ComputedMLI.analyze(*MDT);
242 MLI = &ComputedMLI;
243 }
244
245
246
247
248 if (MLI->empty() && TooFewInstrs)
249 return false;
250 } else if (TooFewInstrs) {
251
252 return false;
253 }
254 }
255
256
257
259 MF, [&](const MachineBasicBlock &MBB) { return .empty(); });
260 if (MBI == MF.end())
261 return false;
262
263 auto *TII = MF.getSubtarget().getInstrInfo();
264 auto &FirstMBB = *MBI;
265 auto &FirstMI = *FirstMBB.begin();
266
267 if (!MF.getSubtarget().isXRaySupported()) {
268
269 const Function &Fn = FirstMBB.getParent()->getFunction();
271 Fn, "An attempt to perform XRay instrumentation for an"
272 " unsupported target."));
273
274 return false;
275 }
276
277 if (.hasFnAttribute("xray-skip-entry")) {
278
279
280 BuildMI(FirstMBB, FirstMI, FirstMI.getDebugLoc(),
281 TII->get(TargetOpcode::PATCHABLE_FUNCTION_ENTER));
282 }
283
284 if (.hasFnAttribute("xray-skip-exit")) {
285 switch (MF.getTarget().getTargetTriple().getArch()) {
286 case Triple::ArchType::arm:
287 case Triple::ArchType::thumb:
288 case Triple::ArchType::aarch64:
289 case Triple::ArchType::hexagon:
290 case Triple::ArchType::loongarch64:
291 case Triple::ArchType::mips:
292 case Triple::ArchType::mipsel:
293 case Triple::ArchType::mips64:
294 case Triple::ArchType::mips64el:
295 case Triple::ArchType::riscv32:
296 case Triple::ArchType::riscv64: {
297
298 InstrumentationOptions op;
299
300 op.HandleTailcall = MF.getTarget().getTargetTriple().isAArch64() ||
301 MF.getTarget().getTargetTriple().isRISCV();
302 op.HandleAllReturns = true;
303 prependRetWithPatchableExit(MF, TII, op);
304 break;
305 }
306 case Triple::ArchType::ppc64le:
307 case Triple::ArchType::systemz: {
308
309 InstrumentationOptions op;
310 op.HandleTailcall = false;
311 op.HandleAllReturns = true;
312 replaceRetWithPatchableRet(MF, TII, op);
313 break;
314 }
315 default: {
316
317
318 InstrumentationOptions op;
319 op.HandleTailcall = true;
320 op.HandleAllReturns = false;
321 replaceRetWithPatchableRet(MF, TII, op);
322 break;
323 }
324 }
325 }
326 return true;
327}
328
329char XRayInstrumentationLegacy::ID = 0;
332 "Insert XRay ops", false, false)
This file contains the simple types necessary to represent the attributes associated with functions a...
const HexagonInstrInfo * TII
#define INITIALIZE_PASS_DEPENDENCY(depName)
#define INITIALIZE_PASS_END(passName, arg, name, cfg, analysis)
#define INITIALIZE_PASS_BEGIN(passName, arg, name, cfg, analysis)
This file defines the SmallVector class.
PassT::Result * getCachedResult(IRUnitT &IR) const
Get the cached result of an analysis pass for a given IR unit.
AnalysisUsage & addPreserved()
Add the specified Pass class to the set of analyses preserved by this pass.
LLVM_ABI void setPreservesCFG()
This function should be called by the pass, iff they do not:
Represents analyses that only rely on functions' control flow.
void recalculate(ParentType &Func)
recalculate - compute a dominator tree for the given function
Attribute getFnAttribute(Attribute::AttrKind Kind) const
Return the attribute for the given attribute kind.
LLVMContext & getContext() const
getContext - Return a reference to the LLVMContext associated with this function.
bool isTailCall(const MachineInstr &MI) const override
LLVM_ABI void diagnose(const DiagnosticInfo &DI)
Report a message to the currently installed diagnostic handler.
void analyze(const DominatorTreeBase< BlockT, false > &DomTree)
Create the loop forest using a stable algorithm.
iterator_range< iterator > terminators()
Analysis pass which computes a MachineDominatorTree.
DominatorTree Class - Concrete subclass of DominatorTreeBase that is used to compute a normal dominat...
MachineFunctionPass - This class adapts the FunctionPass interface to allow convenient creation of pa...
void getAnalysisUsage(AnalysisUsage &AU) const override
getAnalysisUsage - Subclasses that override getAnalysisUsage must call this.
Function & getFunction()
Return the LLVM function that this machine code represents.
const MachineInstrBuilder & addImm(int64_t Val) const
Add a new immediate operand.
const MachineInstrBuilder & add(const MachineOperand &MO) const
Analysis pass that exposes the MachineLoopInfo for a machine function.
static LLVM_ABI PassRegistry * getPassRegistry()
getPassRegistry - Access the global registry object, which is automatically initialized at applicatio...
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
void push_back(const T &Elt)
TargetInstrInfo - Interface to description of machine instruction set.
PreservedAnalyses run(MachineFunction &MF, MachineFunctionAnalysisManager &MFAM)
Definition XRayInstrumentation.cpp:174
PointerTypeMap run(const Module &M)
Compute the PointerTypeMap for the module M.
This is an optimization pass for GlobalISel generic memory operations.
LLVM_ABI void initializeXRayInstrumentationLegacyPass(PassRegistry &)
MachineInstrBuilder BuildMI(MachineFunction &MF, const MIMetadata &MIMD, const MCInstrDesc &MCID)
Builder interface. Specify how to create the initial instruction itself.
AnalysisManager< MachineFunction > MachineFunctionAnalysisManager
LLVM_ABI PreservedAnalyses getMachineFunctionPassPreservedAnalyses()
Returns the minimum set of Analyses that all machine function passes must preserve.
LLVM_ABI char & XRayInstrumentationID
This pass inserts the XRay instrumentation sleds if they are supported by the target platform.
Definition XRayInstrumentation.cpp:330
auto find_if(R &&Range, UnaryPredicate P)
Provide wrappers to std::find_if which take ranges instead of having to pass begin/end explicitly.