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 MBB.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 (F.hasFnAttribute("xray-skip-entry")) {

278

279

280 BuildMI(FirstMBB, FirstMI, FirstMI.getDebugLoc(),

281 TII->get(TargetOpcode::PATCHABLE_FUNCTION_ENTER));

282 }

283

284 if (F.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.