LLVM: lib/CodeGen/XRayInstrumentation.cpp Source File (original) (raw)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
33
34using namespace llvm;
35
36namespace {
37
38struct InstrumentationOptions {
39
40 bool HandleTailcall;
41
42
43
44 bool HandleAllReturns;
45};
46
48 static char ID;
49
52 }
53
59 }
60
62
63private:
64
65
66
67
68
69
72 InstrumentationOptions);
73
74
75
76
77
78
79
80
81
84 InstrumentationOptions);
85};
86
87}
88
89void XRayInstrumentation::replaceRetWithPatchableRet(
91 InstrumentationOptions op) {
92
93
95 for (auto &MBB : MF) {
97 unsigned Opc = 0;
98 if (T.isReturn() &&
99 (op.HandleAllReturns || T.getOpcode() == TII->getReturnOpcode())) {
100
101
102 Opc = TargetOpcode::PATCHABLE_RET;
103 }
105
106
107 Opc = TargetOpcode::PATCHABLE_TAIL_CALL;
108 }
109 if (Opc != 0) {
110 auto MIB = BuildMI(MBB, T, T.getDebugLoc(), TII->get(Opc))
112 for (auto &MO : T.operands())
113 MIB.add(MO);
115 if (T.shouldUpdateAdditionalCallInfo())
116 MF.eraseAdditionalCallInfo(&T);
117 }
118 }
119 }
120
121 for (auto &I : Terminators)
122 I->eraseFromParent();
123}
124
125void XRayInstrumentation::prependRetWithPatchableExit(
127 InstrumentationOptions op) {
128 for (auto &MBB : MF)
130 unsigned Opc = 0;
131 if (T.isReturn() &&
132 (op.HandleAllReturns || T.getOpcode() == TII->getReturnOpcode())) {
133 Opc = TargetOpcode::PATCHABLE_FUNCTION_EXIT;
134 }
136 Opc = TargetOpcode::PATCHABLE_TAIL_CALL;
137 }
138 if (Opc != 0) {
139
140
142 }
143 }
144}
145
146bool XRayInstrumentation::runOnMachineFunction(MachineFunction &MF) {
148 auto InstrAttr = F.getFnAttribute("function-instrument");
149 bool AlwaysInstrument = InstrAttr.isStringAttribute() &&
150 InstrAttr.getValueAsString() == "xray-always";
151 bool NeverInstrument = InstrAttr.isStringAttribute() &&
152 InstrAttr.getValueAsString() == "xray-never";
153 if (NeverInstrument && !AlwaysInstrument)
154 return false;
155 auto IgnoreLoopsAttr = F.getFnAttribute("xray-ignore-loops");
156
158 if (!AlwaysInstrument) {
159 bool IgnoreLoops = IgnoreLoopsAttr.isValid();
160 XRayThreshold = F.getFnAttributeAsParsedInteger(
161 "xray-instruction-threshold", std::numeric_limits<uint64_t>::max());
162 if (XRayThreshold == std::numeric_limits<uint64_t>::max())
163 return false;
164
165
167 for (const auto &MBB : MF)
169
170 bool TooFewInstrs = MICount < XRayThreshold;
171
172 if (!IgnoreLoops) {
173
174 auto *MDTWrapper =
175 getAnalysisIfAvailable();
176 auto *MDT = MDTWrapper ? &MDTWrapper->getDomTree() : nullptr;
178 if (!MDT) {
180 MDT = &ComputedMDT;
181 }
182
183
184 auto *MLIWrapper = getAnalysisIfAvailable();
185 auto *MLI = MLIWrapper ? &MLIWrapper->getLI() : nullptr;
187 if (!MLI) {
188 ComputedMLI.analyze(*MDT);
189 MLI = &ComputedMLI;
190 }
191
192
193
194
195 if (MLI->empty() && TooFewInstrs)
196 return false;
197 } else if (TooFewInstrs) {
198
199 return false;
200 }
201 }
202
203
204
207 if (MBI == MF.end())
208 return false;
209
210 auto *TII = MF.getSubtarget().getInstrInfo();
211 auto &FirstMBB = *MBI;
212 auto &FirstMI = *FirstMBB.begin();
213
214 if (!MF.getSubtarget().isXRaySupported()) {
215
218 Fn, "An attempt to perform XRay instrumentation for an"
219 " unsupported target."));
220
221 return false;
222 }
223
224 if (.hasFnAttribute("xray-skip-entry")) {
225
226
227 BuildMI(FirstMBB, FirstMI, FirstMI.getDebugLoc(),
228 TII->get(TargetOpcode::PATCHABLE_FUNCTION_ENTER));
229 }
230
231 if (.hasFnAttribute("xray-skip-exit")) {
232 switch (MF.getTarget().getTargetTriple().getArch()) {
233 case Triple::ArchType::arm:
234 case Triple::ArchType::thumb:
235 case Triple::ArchType::aarch64:
236 case Triple::ArchType::hexagon:
237 case Triple::ArchType::loongarch64:
238 case Triple::ArchType::mips:
239 case Triple::ArchType::mipsel:
240 case Triple::ArchType::mips64:
241 case Triple::ArchType::mips64el:
242 case Triple::ArchType::riscv32:
243 case Triple::ArchType::riscv64: {
244
245 InstrumentationOptions op;
246
247 op.HandleTailcall = MF.getTarget().getTargetTriple().isRISCV();
248 op.HandleAllReturns = true;
249 prependRetWithPatchableExit(MF, TII, op);
250 break;
251 }
252 case Triple::ArchType::ppc64le:
253 case Triple::ArchType::systemz: {
254
255 InstrumentationOptions op;
256 op.HandleTailcall = false;
257 op.HandleAllReturns = true;
258 replaceRetWithPatchableRet(MF, TII, op);
259 break;
260 }
261 default: {
262
263
264 InstrumentationOptions op;
265 op.HandleTailcall = true;
266 op.HandleAllReturns = false;
267 replaceRetWithPatchableRet(MF, TII, op);
268 break;
269 }
270 }
271 }
272 return true;
273}
274
275char XRayInstrumentation::ID = 0;
278 "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.
Represent the analysis usage information of a pass.
AnalysisUsage & addPreserved()
Add the specified Pass class to the set of analyses preserved by this pass.
void setPreservesCFG()
This function should be called by the pass, iff they do not:
Diagnostic information for unsupported feature in backend.
void recalculate(ParentType &Func)
recalculate - compute a dominator tree for the given function
LLVMContext & getContext() const
getContext - Return a reference to the LLVMContext associated with this function.
Module * getParent()
Get the module that this global value is contained inside of...
bool isTailCall(const MachineInstr &MI) const override
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.
virtual bool runOnMachineFunction(MachineFunction &MF)=0
runOnMachineFunction - This method must be overloaded to perform the desired machine code transformat...
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
Function * getFunction(StringRef Name) const
Look up the specified function in the module symbol table.
static PassRegistry * getPassRegistry()
getPassRegistry - Access the global registry object, which is automatically initialized at applicatio...
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
TargetInstrInfo - Interface to description of machine instruction set.
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
This is an optimization pass for GlobalISel generic memory operations.
MachineInstrBuilder BuildMI(MachineFunction &MF, const MIMetadata &MIMD, const MCInstrDesc &MCID)
Builder interface. Specify how to create the initial instruction itself.
void initializeXRayInstrumentationPass(PassRegistry &)
char & XRayInstrumentationID
This pass inserts the XRay instrumentation sleds if they are supported by the target platform.
auto find_if(R &&Range, UnaryPredicate P)
Provide wrappers to std::find_if which take ranges instead of having to pass begin/end explicitly.