1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | #include "CodeGenPGO.h" |
14 | #include "CodeGenFunction.h" |
15 | #include "CoverageMappingGen.h" |
16 | #include "clang/AST/RecursiveASTVisitor.h" |
17 | #include "clang/AST/StmtVisitor.h" |
18 | #include "llvm/IR/Intrinsics.h" |
19 | #include "llvm/IR/MDBuilder.h" |
20 | #include "llvm/Support/Endian.h" |
21 | #include "llvm/Support/FileSystem.h" |
22 | #include "llvm/Support/MD5.h" |
23 | |
24 | static llvm::cl::opt<bool> |
25 | EnableValueProfiling("enable-value-profiling", llvm::cl::ZeroOrMore, |
26 | llvm::cl::desc("Enable value profiling"), |
27 | llvm::cl::Hidden, llvm::cl::init(false)); |
28 | |
29 | using namespace clang; |
30 | using namespace CodeGen; |
31 | |
32 | void CodeGenPGO::setFuncName(StringRef Name, |
33 | llvm::GlobalValue::LinkageTypes Linkage) { |
34 | llvm::IndexedInstrProfReader *PGOReader = CGM.getPGOReader(); |
35 | FuncName = llvm::getPGOFuncName( |
36 | Name, Linkage, CGM.getCodeGenOpts().MainFileName, |
37 | PGOReader ? PGOReader->getVersion() : llvm::IndexedInstrProf::Version); |
38 | |
39 | |
40 | if (CGM.getCodeGenOpts().hasProfileClangInstr()) |
41 | FuncNameVar = llvm::createPGOFuncNameVar(CGM.getModule(), Linkage, FuncName); |
42 | } |
43 | |
44 | void CodeGenPGO::setFuncName(llvm::Function *Fn) { |
45 | setFuncName(Fn->getName(), Fn->getLinkage()); |
46 | |
47 | llvm::createPGOFuncNameMetadata(*Fn, FuncName); |
48 | } |
49 | |
50 | |
51 | enum PGOHashVersion : unsigned { |
52 | PGO_HASH_V1, |
53 | PGO_HASH_V2, |
54 | |
55 | |
56 | PGO_HASH_LATEST = PGO_HASH_V2 |
57 | }; |
58 | |
59 | namespace { |
60 | |
61 | |
62 | |
63 | |
64 | |
65 | |
66 | |
67 | |
68 | |
69 | |
70 | class PGOHash { |
71 | uint64_t Working; |
72 | unsigned Count; |
73 | PGOHashVersion HashVersion; |
74 | llvm::MD5 MD5; |
75 | |
76 | static const int NumBitsPerType = 6; |
77 | static const unsigned NumTypesPerWord = sizeof(uint64_t) * 8 / NumBitsPerType; |
78 | static const unsigned TooBig = 1u << NumBitsPerType; |
79 | |
80 | public: |
81 | |
82 | |
83 | |
84 | |
85 | |
86 | |
87 | |
88 | enum HashType : unsigned char { |
89 | None = 0, |
90 | LabelStmt = 1, |
91 | WhileStmt, |
92 | DoStmt, |
93 | ForStmt, |
94 | CXXForRangeStmt, |
95 | ObjCForCollectionStmt, |
96 | SwitchStmt, |
97 | CaseStmt, |
98 | DefaultStmt, |
99 | IfStmt, |
100 | CXXTryStmt, |
101 | CXXCatchStmt, |
102 | ConditionalOperator, |
103 | BinaryOperatorLAnd, |
104 | BinaryOperatorLOr, |
105 | BinaryConditionalOperator, |
106 | |
107 | |
108 | EndOfScope, |
109 | IfThenBranch, |
110 | IfElseBranch, |
111 | GotoStmt, |
112 | IndirectGotoStmt, |
113 | BreakStmt, |
114 | ContinueStmt, |
115 | ReturnStmt, |
116 | ThrowExpr, |
117 | UnaryOperatorLNot, |
118 | BinaryOperatorLT, |
119 | BinaryOperatorGT, |
120 | BinaryOperatorLE, |
121 | BinaryOperatorGE, |
122 | BinaryOperatorEQ, |
123 | BinaryOperatorNE, |
124 | |
125 | |
126 | |
127 | LastHashType |
128 | }; |
129 | static_assert(LastHashType <= TooBig, "Too many types in HashType"); |
130 | |
131 | PGOHash(PGOHashVersion HashVersion) |
132 | : Working(0), Count(0), HashVersion(HashVersion), MD5() {} |
133 | void combine(HashType Type); |
134 | uint64_t finalize(); |
135 | PGOHashVersion getHashVersion() const { return HashVersion; } |
136 | }; |
137 | const int PGOHash::NumBitsPerType; |
138 | const unsigned PGOHash::NumTypesPerWord; |
139 | const unsigned PGOHash::TooBig; |
140 | |
141 | |
142 | static PGOHashVersion getPGOHashVersion(llvm::IndexedInstrProfReader *PGOReader, |
143 | CodeGenModule &CGM) { |
144 | if (PGOReader->getVersion() <= 4) |
145 | return PGO_HASH_V1; |
146 | return PGO_HASH_V2; |
147 | } |
148 | |
149 | |
150 | struct MapRegionCounters : public RecursiveASTVisitor<MapRegionCounters> { |
151 | using Base = RecursiveASTVisitor<MapRegionCounters>; |
152 | |
153 | |
154 | unsigned NextCounter; |
155 | |
156 | PGOHash Hash; |
157 | |
158 | llvm::DenseMap<const Stmt *, unsigned> &CounterMap; |
159 | |
160 | MapRegionCounters(PGOHashVersion HashVersion, |
161 | llvm::DenseMap<const Stmt *, unsigned> &CounterMap) |
162 | : NextCounter(0), Hash(HashVersion), CounterMap(CounterMap) {} |
163 | |
164 | |
165 | |
166 | bool TraverseBlockExpr(BlockExpr *BE) { return true; } |
167 | bool TraverseLambdaExpr(LambdaExpr *LE) { |
168 | |
169 | for (const auto &C : zip(LE->captures(), LE->capture_inits())) |
170 | TraverseLambdaCapture(LE, &std::get<0>(C), std::get<1>(C)); |
171 | return true; |
172 | } |
173 | bool TraverseCapturedStmt(CapturedStmt *CS) { return true; } |
174 | |
175 | bool VisitDecl(const Decl *D) { |
176 | switch (D->getKind()) { |
177 | default: |
178 | break; |
179 | case Decl::Function: |
180 | case Decl::CXXMethod: |
181 | case Decl::CXXConstructor: |
182 | case Decl::CXXDestructor: |
183 | case Decl::CXXConversion: |
184 | case Decl::ObjCMethod: |
185 | case Decl::Block: |
186 | case Decl::Captured: |
187 | CounterMap[D->getBody()] = NextCounter++; |
188 | break; |
189 | } |
190 | return true; |
191 | } |
192 | |
193 | |
194 | |
195 | PGOHash::HashType updateCounterMappings(Stmt *S) { |
196 | auto Type = getHashType(PGO_HASH_V1, S); |
197 | if (Type != PGOHash::None) |
198 | CounterMap[S] = NextCounter++; |
199 | return Type; |
200 | } |
201 | |
202 | |
203 | bool VisitStmt(Stmt *S) { |
204 | auto Type = updateCounterMappings(S); |
205 | if (Hash.getHashVersion() != PGO_HASH_V1) |
206 | Type = getHashType(Hash.getHashVersion(), S); |
207 | if (Type != PGOHash::None) |
208 | Hash.combine(Type); |
209 | return true; |
210 | } |
211 | |
212 | bool TraverseIfStmt(IfStmt *If) { |
213 | |
214 | if (Hash.getHashVersion() == PGO_HASH_V1) |
215 | return Base::TraverseIfStmt(If); |
216 | |
217 | |
218 | VisitStmt(If); |
219 | for (Stmt *CS : If->children()) { |
220 | if (!CS) |
221 | continue; |
222 | if (CS == If->getThen()) |
223 | Hash.combine(PGOHash::IfThenBranch); |
224 | else if (CS == If->getElse()) |
225 | Hash.combine(PGOHash::IfElseBranch); |
226 | TraverseStmt(CS); |
227 | } |
228 | Hash.combine(PGOHash::EndOfScope); |
229 | return true; |
230 | } |
231 | |
232 | |
233 | |
234 | |
235 | #define DEFINE_NESTABLE_TRAVERSAL(N) \ |
236 | bool Traverse##N(N *S) { \ |
237 | Base::Traverse##N(S); \ |
238 | if (Hash.getHashVersion() != PGO_HASH_V1) \ |
239 | Hash.combine(PGOHash::EndOfScope); \ |
240 | return true; \ |
241 | } |
242 | |
243 | DEFINE_NESTABLE_TRAVERSAL(WhileStmt) |
244 | DEFINE_NESTABLE_TRAVERSAL(DoStmt) |
245 | DEFINE_NESTABLE_TRAVERSAL(ForStmt) |
246 | DEFINE_NESTABLE_TRAVERSAL(CXXForRangeStmt) |
247 | DEFINE_NESTABLE_TRAVERSAL(ObjCForCollectionStmt) |
248 | DEFINE_NESTABLE_TRAVERSAL(CXXTryStmt) |
249 | DEFINE_NESTABLE_TRAVERSAL(CXXCatchStmt) |
250 | |
251 | |
252 | PGOHash::HashType getHashType(PGOHashVersion HashVersion, const Stmt *S) { |
253 | switch (S->getStmtClass()) { |
254 | default: |
255 | break; |
256 | case Stmt::LabelStmtClass: |
257 | return PGOHash::LabelStmt; |
258 | case Stmt::WhileStmtClass: |
259 | return PGOHash::WhileStmt; |
260 | case Stmt::DoStmtClass: |
261 | return PGOHash::DoStmt; |
262 | case Stmt::ForStmtClass: |
263 | return PGOHash::ForStmt; |
264 | case Stmt::CXXForRangeStmtClass: |
265 | return PGOHash::CXXForRangeStmt; |
266 | case Stmt::ObjCForCollectionStmtClass: |
267 | return PGOHash::ObjCForCollectionStmt; |
268 | case Stmt::SwitchStmtClass: |
269 | return PGOHash::SwitchStmt; |
270 | case Stmt::CaseStmtClass: |
271 | return PGOHash::CaseStmt; |
272 | case Stmt::DefaultStmtClass: |
273 | return PGOHash::DefaultStmt; |
274 | case Stmt::IfStmtClass: |
275 | return PGOHash::IfStmt; |
276 | case Stmt::CXXTryStmtClass: |
277 | return PGOHash::CXXTryStmt; |
278 | case Stmt::CXXCatchStmtClass: |
279 | return PGOHash::CXXCatchStmt; |
280 | case Stmt::ConditionalOperatorClass: |
281 | return PGOHash::ConditionalOperator; |
282 | case Stmt::BinaryConditionalOperatorClass: |
283 | return PGOHash::BinaryConditionalOperator; |
284 | case Stmt::BinaryOperatorClass: { |
285 | const BinaryOperator *BO = cast<BinaryOperator>(S); |
286 | if (BO->getOpcode() == BO_LAnd) |
287 | return PGOHash::BinaryOperatorLAnd; |
288 | if (BO->getOpcode() == BO_LOr) |
289 | return PGOHash::BinaryOperatorLOr; |
290 | if (HashVersion == PGO_HASH_V2) { |
291 | switch (BO->getOpcode()) { |
292 | default: |
293 | break; |
294 | case BO_LT: |
295 | return PGOHash::BinaryOperatorLT; |
296 | case BO_GT: |
297 | return PGOHash::BinaryOperatorGT; |
298 | case BO_LE: |
299 | return PGOHash::BinaryOperatorLE; |
300 | case BO_GE: |
301 | return PGOHash::BinaryOperatorGE; |
302 | case BO_EQ: |
303 | return PGOHash::BinaryOperatorEQ; |
304 | case BO_NE: |
305 | return PGOHash::BinaryOperatorNE; |
306 | } |
307 | } |
308 | break; |
309 | } |
310 | } |
311 | |
312 | if (HashVersion == PGO_HASH_V2) { |
313 | switch (S->getStmtClass()) { |
314 | default: |
315 | break; |
316 | case Stmt::GotoStmtClass: |
317 | return PGOHash::GotoStmt; |
318 | case Stmt::IndirectGotoStmtClass: |
319 | return PGOHash::IndirectGotoStmt; |
320 | case Stmt::BreakStmtClass: |
321 | return PGOHash::BreakStmt; |
322 | case Stmt::ContinueStmtClass: |
323 | return PGOHash::ContinueStmt; |
324 | case Stmt::ReturnStmtClass: |
325 | return PGOHash::ReturnStmt; |
326 | case Stmt::CXXThrowExprClass: |
327 | return PGOHash::ThrowExpr; |
328 | case Stmt::UnaryOperatorClass: { |
329 | const UnaryOperator *UO = cast<UnaryOperator>(S); |
330 | if (UO->getOpcode() == UO_LNot) |
331 | return PGOHash::UnaryOperatorLNot; |
332 | break; |
333 | } |
334 | } |
335 | } |
336 | |
337 | return PGOHash::None; |
338 | } |
339 | }; |
340 | |
341 | |
342 | |
343 | struct ComputeRegionCounts : public ConstStmtVisitor<ComputeRegionCounts> { |
344 | |
345 | CodeGenPGO &PGO; |
346 | |
347 | |
348 | |
349 | bool RecordNextStmtCount; |
350 | |
351 | |
352 | uint64_t CurrentCount; |
353 | |
354 | |
355 | llvm::DenseMap<const Stmt *, uint64_t> &CountMap; |
356 | |
357 | |
358 | struct BreakContinue { |
359 | uint64_t BreakCount; |
360 | uint64_t ContinueCount; |
361 | BreakContinue() : BreakCount(0), ContinueCount(0) {} |
362 | }; |
363 | SmallVector<BreakContinue, 8> BreakContinueStack; |
364 | |
365 | ComputeRegionCounts(llvm::DenseMap<const Stmt *, uint64_t> &CountMap, |
366 | CodeGenPGO &PGO) |
367 | : PGO(PGO), RecordNextStmtCount(false), CountMap(CountMap) {} |
368 | |
369 | void RecordStmtCount(const Stmt *S) { |
370 | if (RecordNextStmtCount) { |
371 | CountMap[S] = CurrentCount; |
372 | RecordNextStmtCount = false; |
373 | } |
374 | } |
375 | |
376 | |
377 | uint64_t setCount(uint64_t Count) { |
378 | CurrentCount = Count; |
379 | return Count; |
380 | } |
381 | |
382 | void VisitStmt(const Stmt *S) { |
383 | RecordStmtCount(S); |
384 | for (const Stmt *Child : S->children()) |
385 | if (Child) |
386 | this->Visit(Child); |
387 | } |
388 | |
389 | void VisitFunctionDecl(const FunctionDecl *D) { |
390 | |
391 | uint64_t BodyCount = setCount(PGO.getRegionCount(D->getBody())); |
392 | CountMap[D->getBody()] = BodyCount; |
393 | Visit(D->getBody()); |
394 | } |
395 | |
396 | |
397 | |
398 | |
399 | void VisitLambdaExpr(const LambdaExpr *LE) {} |
400 | |
401 | void VisitCapturedDecl(const CapturedDecl *D) { |
402 | |
403 | uint64_t BodyCount = setCount(PGO.getRegionCount(D->getBody())); |
404 | CountMap[D->getBody()] = BodyCount; |
405 | Visit(D->getBody()); |
406 | } |
407 | |
408 | void VisitObjCMethodDecl(const ObjCMethodDecl *D) { |
409 | |
410 | uint64_t BodyCount = setCount(PGO.getRegionCount(D->getBody())); |
411 | CountMap[D->getBody()] = BodyCount; |
412 | Visit(D->getBody()); |
413 | } |
414 | |
415 | void VisitBlockDecl(const BlockDecl *D) { |
416 | |
417 | uint64_t BodyCount = setCount(PGO.getRegionCount(D->getBody())); |
418 | CountMap[D->getBody()] = BodyCount; |
419 | Visit(D->getBody()); |
420 | } |
421 | |
422 | void VisitReturnStmt(const ReturnStmt *S) { |
423 | RecordStmtCount(S); |
424 | if (S->getRetValue()) |
425 | Visit(S->getRetValue()); |
426 | CurrentCount = 0; |
427 | RecordNextStmtCount = true; |
428 | } |
429 | |
430 | void VisitCXXThrowExpr(const CXXThrowExpr *E) { |
431 | RecordStmtCount(E); |
432 | if (E->getSubExpr()) |
433 | Visit(E->getSubExpr()); |
434 | CurrentCount = 0; |
435 | RecordNextStmtCount = true; |
436 | } |
437 | |
438 | void VisitGotoStmt(const GotoStmt *S) { |
439 | RecordStmtCount(S); |
440 | CurrentCount = 0; |
441 | RecordNextStmtCount = true; |
442 | } |
443 | |
444 | void VisitLabelStmt(const LabelStmt *S) { |
445 | RecordNextStmtCount = false; |
446 | |
447 | uint64_t BlockCount = setCount(PGO.getRegionCount(S)); |
448 | CountMap[S] = BlockCount; |
449 | Visit(S->getSubStmt()); |
450 | } |
451 | |
452 | void VisitBreakStmt(const BreakStmt *S) { |
453 | RecordStmtCount(S); |
454 | (0) . __assert_fail ("!BreakContinueStack.empty() && \"break not in a loop or switch!\"", "/home/seafit/code_projects/clang_source/clang/lib/CodeGen/CodeGenPGO.cpp", 454, __PRETTY_FUNCTION__))" file_link="../../../include/assert.h.html#88" macro="true">assert(!BreakContinueStack.empty() && "break not in a loop or switch!"); |
455 | BreakContinueStack.back().BreakCount += CurrentCount; |
456 | CurrentCount = 0; |
457 | RecordNextStmtCount = true; |
458 | } |
459 | |
460 | void VisitContinueStmt(const ContinueStmt *S) { |
461 | RecordStmtCount(S); |
462 | (0) . __assert_fail ("!BreakContinueStack.empty() && \"continue stmt not in a loop!\"", "/home/seafit/code_projects/clang_source/clang/lib/CodeGen/CodeGenPGO.cpp", 462, __PRETTY_FUNCTION__))" file_link="../../../include/assert.h.html#88" macro="true">assert(!BreakContinueStack.empty() && "continue stmt not in a loop!"); |
463 | BreakContinueStack.back().ContinueCount += CurrentCount; |
464 | CurrentCount = 0; |
465 | RecordNextStmtCount = true; |
466 | } |
467 | |
468 | void VisitWhileStmt(const WhileStmt *S) { |
469 | RecordStmtCount(S); |
470 | uint64_t ParentCount = CurrentCount; |
471 | |
472 | BreakContinueStack.push_back(BreakContinue()); |
473 | |
474 | |
475 | uint64_t BodyCount = setCount(PGO.getRegionCount(S)); |
476 | CountMap[S->getBody()] = CurrentCount; |
477 | Visit(S->getBody()); |
478 | uint64_t BackedgeCount = CurrentCount; |
479 | |
480 | |
481 | |
482 | |
483 | |
484 | BreakContinue BC = BreakContinueStack.pop_back_val(); |
485 | uint64_t CondCount = |
486 | setCount(ParentCount + BackedgeCount + BC.ContinueCount); |
487 | CountMap[S->getCond()] = CondCount; |
488 | Visit(S->getCond()); |
489 | setCount(BC.BreakCount + CondCount - BodyCount); |
490 | RecordNextStmtCount = true; |
491 | } |
492 | |
493 | void VisitDoStmt(const DoStmt *S) { |
494 | RecordStmtCount(S); |
495 | uint64_t LoopCount = PGO.getRegionCount(S); |
496 | |
497 | BreakContinueStack.push_back(BreakContinue()); |
498 | |
499 | uint64_t BodyCount = setCount(LoopCount + CurrentCount); |
500 | CountMap[S->getBody()] = BodyCount; |
501 | Visit(S->getBody()); |
502 | uint64_t BackedgeCount = CurrentCount; |
503 | |
504 | BreakContinue BC = BreakContinueStack.pop_back_val(); |
505 | |
506 | |
507 | uint64_t CondCount = setCount(BackedgeCount + BC.ContinueCount); |
508 | CountMap[S->getCond()] = CondCount; |
509 | Visit(S->getCond()); |
510 | setCount(BC.BreakCount + CondCount - LoopCount); |
511 | RecordNextStmtCount = true; |
512 | } |
513 | |
514 | void VisitForStmt(const ForStmt *S) { |
515 | RecordStmtCount(S); |
516 | if (S->getInit()) |
517 | Visit(S->getInit()); |
518 | |
519 | uint64_t ParentCount = CurrentCount; |
520 | |
521 | BreakContinueStack.push_back(BreakContinue()); |
522 | |
523 | |
524 | uint64_t BodyCount = setCount(PGO.getRegionCount(S)); |
525 | CountMap[S->getBody()] = BodyCount; |
526 | Visit(S->getBody()); |
527 | uint64_t BackedgeCount = CurrentCount; |
528 | BreakContinue BC = BreakContinueStack.pop_back_val(); |
529 | |
530 | |
531 | |
532 | if (S->getInc()) { |
533 | uint64_t IncCount = setCount(BackedgeCount + BC.ContinueCount); |
534 | CountMap[S->getInc()] = IncCount; |
535 | Visit(S->getInc()); |
536 | } |
537 | |
538 | |
539 | uint64_t CondCount = |
540 | setCount(ParentCount + BackedgeCount + BC.ContinueCount); |
541 | if (S->getCond()) { |
542 | CountMap[S->getCond()] = CondCount; |
543 | Visit(S->getCond()); |
544 | } |
545 | setCount(BC.BreakCount + CondCount - BodyCount); |
546 | RecordNextStmtCount = true; |
547 | } |
548 | |
549 | void VisitCXXForRangeStmt(const CXXForRangeStmt *S) { |
550 | RecordStmtCount(S); |
551 | if (S->getInit()) |
552 | Visit(S->getInit()); |
553 | Visit(S->getLoopVarStmt()); |
554 | Visit(S->getRangeStmt()); |
555 | Visit(S->getBeginStmt()); |
556 | Visit(S->getEndStmt()); |
557 | |
558 | uint64_t ParentCount = CurrentCount; |
559 | BreakContinueStack.push_back(BreakContinue()); |
560 | |
561 | |
562 | uint64_t BodyCount = setCount(PGO.getRegionCount(S)); |
563 | CountMap[S->getBody()] = BodyCount; |
564 | Visit(S->getBody()); |
565 | uint64_t BackedgeCount = CurrentCount; |
566 | BreakContinue BC = BreakContinueStack.pop_back_val(); |
567 | |
568 | |
569 | |
570 | uint64_t IncCount = setCount(BackedgeCount + BC.ContinueCount); |
571 | CountMap[S->getInc()] = IncCount; |
572 | Visit(S->getInc()); |
573 | |
574 | |
575 | uint64_t CondCount = |
576 | setCount(ParentCount + BackedgeCount + BC.ContinueCount); |
577 | CountMap[S->getCond()] = CondCount; |
578 | Visit(S->getCond()); |
579 | setCount(BC.BreakCount + CondCount - BodyCount); |
580 | RecordNextStmtCount = true; |
581 | } |
582 | |
583 | void VisitObjCForCollectionStmt(const ObjCForCollectionStmt *S) { |
584 | RecordStmtCount(S); |
585 | Visit(S->getElement()); |
586 | uint64_t ParentCount = CurrentCount; |
587 | BreakContinueStack.push_back(BreakContinue()); |
588 | |
589 | uint64_t BodyCount = setCount(PGO.getRegionCount(S)); |
590 | CountMap[S->getBody()] = BodyCount; |
591 | Visit(S->getBody()); |
592 | uint64_t BackedgeCount = CurrentCount; |
593 | BreakContinue BC = BreakContinueStack.pop_back_val(); |
594 | |
595 | setCount(BC.BreakCount + ParentCount + BackedgeCount + BC.ContinueCount - |
596 | BodyCount); |
597 | RecordNextStmtCount = true; |
598 | } |
599 | |
600 | void VisitSwitchStmt(const SwitchStmt *S) { |
601 | RecordStmtCount(S); |
602 | if (S->getInit()) |
603 | Visit(S->getInit()); |
604 | Visit(S->getCond()); |
605 | CurrentCount = 0; |
606 | BreakContinueStack.push_back(BreakContinue()); |
607 | Visit(S->getBody()); |
608 | |
609 | BreakContinue BC = BreakContinueStack.pop_back_val(); |
610 | if (!BreakContinueStack.empty()) |
611 | BreakContinueStack.back().ContinueCount += BC.ContinueCount; |
612 | |
613 | setCount(PGO.getRegionCount(S)); |
614 | RecordNextStmtCount = true; |
615 | } |
616 | |
617 | void VisitSwitchCase(const SwitchCase *S) { |
618 | RecordNextStmtCount = false; |
619 | |
620 | |
621 | |
622 | uint64_t CaseCount = PGO.getRegionCount(S); |
623 | setCount(CurrentCount + CaseCount); |
624 | |
625 | |
626 | CountMap[S] = CaseCount; |
627 | RecordNextStmtCount = true; |
628 | Visit(S->getSubStmt()); |
629 | } |
630 | |
631 | void VisitIfStmt(const IfStmt *S) { |
632 | RecordStmtCount(S); |
633 | uint64_t ParentCount = CurrentCount; |
634 | if (S->getInit()) |
635 | Visit(S->getInit()); |
636 | Visit(S->getCond()); |
637 | |
638 | |
639 | |
640 | uint64_t ThenCount = setCount(PGO.getRegionCount(S)); |
641 | CountMap[S->getThen()] = ThenCount; |
642 | Visit(S->getThen()); |
643 | uint64_t OutCount = CurrentCount; |
644 | |
645 | uint64_t ElseCount = ParentCount - ThenCount; |
646 | if (S->getElse()) { |
647 | setCount(ElseCount); |
648 | CountMap[S->getElse()] = ElseCount; |
649 | Visit(S->getElse()); |
650 | OutCount += CurrentCount; |
651 | } else |
652 | OutCount += ElseCount; |
653 | setCount(OutCount); |
654 | RecordNextStmtCount = true; |
655 | } |
656 | |
657 | void VisitCXXTryStmt(const CXXTryStmt *S) { |
658 | RecordStmtCount(S); |
659 | Visit(S->getTryBlock()); |
660 | for (unsigned I = 0, E = S->getNumHandlers(); I < E; ++I) |
661 | Visit(S->getHandler(I)); |
662 | |
663 | setCount(PGO.getRegionCount(S)); |
664 | RecordNextStmtCount = true; |
665 | } |
666 | |
667 | void VisitCXXCatchStmt(const CXXCatchStmt *S) { |
668 | RecordNextStmtCount = false; |
669 | |
670 | uint64_t CatchCount = setCount(PGO.getRegionCount(S)); |
671 | CountMap[S] = CatchCount; |
672 | Visit(S->getHandlerBlock()); |
673 | } |
674 | |
675 | void VisitAbstractConditionalOperator(const AbstractConditionalOperator *E) { |
676 | RecordStmtCount(E); |
677 | uint64_t ParentCount = CurrentCount; |
678 | Visit(E->getCond()); |
679 | |
680 | |
681 | |
682 | uint64_t TrueCount = setCount(PGO.getRegionCount(E)); |
683 | CountMap[E->getTrueExpr()] = TrueCount; |
684 | Visit(E->getTrueExpr()); |
685 | uint64_t OutCount = CurrentCount; |
686 | |
687 | uint64_t FalseCount = setCount(ParentCount - TrueCount); |
688 | CountMap[E->getFalseExpr()] = FalseCount; |
689 | Visit(E->getFalseExpr()); |
690 | OutCount += CurrentCount; |
691 | |
692 | setCount(OutCount); |
693 | RecordNextStmtCount = true; |
694 | } |
695 | |
696 | void VisitBinLAnd(const BinaryOperator *E) { |
697 | RecordStmtCount(E); |
698 | uint64_t ParentCount = CurrentCount; |
699 | Visit(E->getLHS()); |
700 | |
701 | uint64_t RHSCount = setCount(PGO.getRegionCount(E)); |
702 | CountMap[E->getRHS()] = RHSCount; |
703 | Visit(E->getRHS()); |
704 | setCount(ParentCount + RHSCount - CurrentCount); |
705 | RecordNextStmtCount = true; |
706 | } |
707 | |
708 | void VisitBinLOr(const BinaryOperator *E) { |
709 | RecordStmtCount(E); |
710 | uint64_t ParentCount = CurrentCount; |
711 | Visit(E->getLHS()); |
712 | |
713 | uint64_t RHSCount = setCount(PGO.getRegionCount(E)); |
714 | CountMap[E->getRHS()] = RHSCount; |
715 | Visit(E->getRHS()); |
716 | setCount(ParentCount + RHSCount - CurrentCount); |
717 | RecordNextStmtCount = true; |
718 | } |
719 | }; |
720 | } |
721 | |
722 | void PGOHash::combine(HashType Type) { |
723 | |
724 | (0) . __assert_fail ("Type && \"Hash is invalid. unexpected type 0\"", "/home/seafit/code_projects/clang_source/clang/lib/CodeGen/CodeGenPGO.cpp", 724, __PRETTY_FUNCTION__))" file_link="../../../include/assert.h.html#88" macro="true">assert(Type && "Hash is invalid: unexpected type 0"); |
725 | (0) . __assert_fail ("unsigned(Type) < TooBig && \"Hash is invalid. too many types\"", "/home/seafit/code_projects/clang_source/clang/lib/CodeGen/CodeGenPGO.cpp", 725, __PRETTY_FUNCTION__))" file_link="../../../include/assert.h.html#88" macro="true">assert(unsigned(Type) < TooBig && "Hash is invalid: too many types"); |
726 | |
727 | |
728 | if (Count && Count % NumTypesPerWord == 0) { |
729 | using namespace llvm::support; |
730 | uint64_t Swapped = endian::byte_swap<uint64_t, little>(Working); |
731 | MD5.update(llvm::makeArrayRef((uint8_t *)&Swapped, sizeof(Swapped))); |
732 | Working = 0; |
733 | } |
734 | |
735 | |
736 | ++Count; |
737 | Working = Working << NumBitsPerType | Type; |
738 | } |
739 | |
740 | uint64_t PGOHash::finalize() { |
741 | |
742 | if (Count <= NumTypesPerWord) |
743 | |
744 | |
745 | |
746 | return Working; |
747 | |
748 | |
749 | if (Working) |
750 | MD5.update(Working); |
751 | |
752 | |
753 | llvm::MD5::MD5Result Result; |
754 | MD5.final(Result); |
755 | using namespace llvm::support; |
756 | return Result.low(); |
757 | } |
758 | |
759 | void CodeGenPGO::assignRegionCounters(GlobalDecl GD, llvm::Function *Fn) { |
760 | const Decl *D = GD.getDecl(); |
761 | if (!D->hasBody()) |
762 | return; |
763 | |
764 | bool InstrumentRegions = CGM.getCodeGenOpts().hasProfileClangInstr(); |
765 | llvm::IndexedInstrProfReader *PGOReader = CGM.getPGOReader(); |
766 | if (!InstrumentRegions && !PGOReader) |
767 | return; |
768 | if (D->isImplicit()) |
769 | return; |
770 | |
771 | |
772 | |
773 | if (CGM.getTarget().getCXXABI().hasConstructorVariants()) { |
774 | if (const auto *CCD = dyn_cast<CXXConstructorDecl>(D)) |
775 | if (GD.getCtorType() != Ctor_Base && |
776 | CodeGenFunction::IsConstructorDelegationValid(CCD)) |
777 | return; |
778 | } |
779 | if (isa<CXXDestructorDecl>(D) && GD.getDtorType() != Dtor_Base) |
780 | return; |
781 | |
782 | CGM.ClearUnusedCoverageMapping(D); |
783 | setFuncName(Fn); |
784 | |
785 | mapRegionCounters(D); |
786 | if (CGM.getCodeGenOpts().CoverageMapping) |
787 | emitCounterRegionMapping(D); |
788 | if (PGOReader) { |
789 | SourceManager &SM = CGM.getContext().getSourceManager(); |
790 | loadRegionCounts(PGOReader, SM.isInMainFile(D->getLocation())); |
791 | computeRegionCounts(D); |
792 | applyFunctionAttributes(PGOReader, Fn); |
793 | } |
794 | } |
795 | |
796 | void CodeGenPGO::mapRegionCounters(const Decl *D) { |
797 | |
798 | |
799 | PGOHashVersion HashVersion = PGO_HASH_LATEST; |
800 | if (auto *PGOReader = CGM.getPGOReader()) |
801 | HashVersion = getPGOHashVersion(PGOReader, CGM); |
802 | |
803 | RegionCounterMap.reset(new llvm::DenseMap<const Stmt *, unsigned>); |
804 | MapRegionCounters Walker(HashVersion, *RegionCounterMap); |
805 | if (const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D)) |
806 | Walker.TraverseDecl(const_cast<FunctionDecl *>(FD)); |
807 | else if (const ObjCMethodDecl *MD = dyn_cast_or_null<ObjCMethodDecl>(D)) |
808 | Walker.TraverseDecl(const_cast<ObjCMethodDecl *>(MD)); |
809 | else if (const BlockDecl *BD = dyn_cast_or_null<BlockDecl>(D)) |
810 | Walker.TraverseDecl(const_cast<BlockDecl *>(BD)); |
811 | else if (const CapturedDecl *CD = dyn_cast_or_null<CapturedDecl>(D)) |
812 | Walker.TraverseDecl(const_cast<CapturedDecl *>(CD)); |
813 | (0) . __assert_fail ("Walker.NextCounter > 0 && \"no entry counter mapped for decl\"", "/home/seafit/code_projects/clang_source/clang/lib/CodeGen/CodeGenPGO.cpp", 813, __PRETTY_FUNCTION__))" file_link="../../../include/assert.h.html#88" macro="true">assert(Walker.NextCounter > 0 && "no entry counter mapped for decl"); |
814 | NumRegionCounters = Walker.NextCounter; |
815 | FunctionHash = Walker.Hash.finalize(); |
816 | } |
817 | |
818 | bool CodeGenPGO::skipRegionMappingForDecl(const Decl *D) { |
819 | if (!D->getBody()) |
820 | return true; |
821 | |
822 | |
823 | const auto &SM = CGM.getContext().getSourceManager(); |
824 | auto Loc = D->getBody()->getBeginLoc(); |
825 | return SM.isInSystemHeader(Loc); |
826 | } |
827 | |
828 | void CodeGenPGO::emitCounterRegionMapping(const Decl *D) { |
829 | if (skipRegionMappingForDecl(D)) |
830 | return; |
831 | |
832 | std::string CoverageMapping; |
833 | llvm::raw_string_ostream OS(CoverageMapping); |
834 | CoverageMappingGen MappingGen(*CGM.getCoverageMapping(), |
835 | CGM.getContext().getSourceManager(), |
836 | CGM.getLangOpts(), RegionCounterMap.get()); |
837 | MappingGen.emitCounterMapping(D, OS); |
838 | OS.flush(); |
839 | |
840 | if (CoverageMapping.empty()) |
841 | return; |
842 | |
843 | CGM.getCoverageMapping()->addFunctionMappingRecord( |
844 | FuncNameVar, FuncName, FunctionHash, CoverageMapping); |
845 | } |
846 | |
847 | void |
848 | CodeGenPGO::emitEmptyCounterMapping(const Decl *D, StringRef Name, |
849 | llvm::GlobalValue::LinkageTypes Linkage) { |
850 | if (skipRegionMappingForDecl(D)) |
851 | return; |
852 | |
853 | std::string CoverageMapping; |
854 | llvm::raw_string_ostream OS(CoverageMapping); |
855 | CoverageMappingGen MappingGen(*CGM.getCoverageMapping(), |
856 | CGM.getContext().getSourceManager(), |
857 | CGM.getLangOpts()); |
858 | MappingGen.emitEmptyMapping(D, OS); |
859 | OS.flush(); |
860 | |
861 | if (CoverageMapping.empty()) |
862 | return; |
863 | |
864 | setFuncName(Name, Linkage); |
865 | CGM.getCoverageMapping()->addFunctionMappingRecord( |
866 | FuncNameVar, FuncName, FunctionHash, CoverageMapping, false); |
867 | } |
868 | |
869 | void CodeGenPGO::computeRegionCounts(const Decl *D) { |
870 | StmtCountMap.reset(new llvm::DenseMap<const Stmt *, uint64_t>); |
871 | ComputeRegionCounts Walker(*StmtCountMap, *this); |
872 | if (const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D)) |
873 | Walker.VisitFunctionDecl(FD); |
874 | else if (const ObjCMethodDecl *MD = dyn_cast_or_null<ObjCMethodDecl>(D)) |
875 | Walker.VisitObjCMethodDecl(MD); |
876 | else if (const BlockDecl *BD = dyn_cast_or_null<BlockDecl>(D)) |
877 | Walker.VisitBlockDecl(BD); |
878 | else if (const CapturedDecl *CD = dyn_cast_or_null<CapturedDecl>(D)) |
879 | Walker.VisitCapturedDecl(const_cast<CapturedDecl *>(CD)); |
880 | } |
881 | |
882 | void |
883 | CodeGenPGO::applyFunctionAttributes(llvm::IndexedInstrProfReader *PGOReader, |
884 | llvm::Function *Fn) { |
885 | if (!haveRegionCounts()) |
886 | return; |
887 | |
888 | uint64_t FunctionCount = getRegionCount(nullptr); |
889 | Fn->setEntryCount(FunctionCount); |
890 | } |
891 | |
892 | void CodeGenPGO::emitCounterIncrement(CGBuilderTy &Builder, const Stmt *S, |
893 | llvm::Value *StepV) { |
894 | if (!CGM.getCodeGenOpts().hasProfileClangInstr() || !RegionCounterMap) |
895 | return; |
896 | if (!Builder.GetInsertBlock()) |
897 | return; |
898 | |
899 | unsigned Counter = (*RegionCounterMap)[S]; |
900 | auto *I8PtrTy = llvm::Type::getInt8PtrTy(CGM.getLLVMContext()); |
901 | |
902 | llvm::Value *Args[] = {llvm::ConstantExpr::getBitCast(FuncNameVar, I8PtrTy), |
903 | Builder.getInt64(FunctionHash), |
904 | Builder.getInt32(NumRegionCounters), |
905 | Builder.getInt32(Counter), StepV}; |
906 | if (!StepV) |
907 | Builder.CreateCall(CGM.getIntrinsic(llvm::Intrinsic::instrprof_increment), |
908 | makeArrayRef(Args, 4)); |
909 | else |
910 | Builder.CreateCall( |
911 | CGM.getIntrinsic(llvm::Intrinsic::instrprof_increment_step), |
912 | makeArrayRef(Args)); |
913 | } |
914 | |
915 | |
916 | |
917 | void CodeGenPGO::valueProfile(CGBuilderTy &Builder, uint32_t ValueKind, |
918 | llvm::Instruction *ValueSite, llvm::Value *ValuePtr) { |
919 | |
920 | if (!EnableValueProfiling) |
921 | return; |
922 | |
923 | if (!ValuePtr || !ValueSite || !Builder.GetInsertBlock()) |
924 | return; |
925 | |
926 | if (isa<llvm::Constant>(ValuePtr)) |
927 | return; |
928 | |
929 | bool InstrumentValueSites = CGM.getCodeGenOpts().hasProfileClangInstr(); |
930 | if (InstrumentValueSites && RegionCounterMap) { |
931 | auto BuilderInsertPoint = Builder.saveIP(); |
932 | Builder.SetInsertPoint(ValueSite); |
933 | llvm::Value *Args[5] = { |
934 | llvm::ConstantExpr::getBitCast(FuncNameVar, Builder.getInt8PtrTy()), |
935 | Builder.getInt64(FunctionHash), |
936 | Builder.CreatePtrToInt(ValuePtr, Builder.getInt64Ty()), |
937 | Builder.getInt32(ValueKind), |
938 | Builder.getInt32(NumValueSites[ValueKind]++) |
939 | }; |
940 | Builder.CreateCall( |
941 | CGM.getIntrinsic(llvm::Intrinsic::instrprof_value_profile), Args); |
942 | Builder.restoreIP(BuilderInsertPoint); |
943 | return; |
944 | } |
945 | |
946 | llvm::IndexedInstrProfReader *PGOReader = CGM.getPGOReader(); |
947 | if (PGOReader && haveRegionCounts()) { |
948 | |
949 | |
950 | |
951 | |
952 | |
953 | |
954 | if (NumValueSites[ValueKind] >= ProfRecord->getNumValueSites(ValueKind)) |
955 | return; |
956 | |
957 | llvm::annotateValueSite(CGM.getModule(), *ValueSite, *ProfRecord, |
958 | (llvm::InstrProfValueKind)ValueKind, |
959 | NumValueSites[ValueKind]); |
960 | |
961 | NumValueSites[ValueKind]++; |
962 | } |
963 | } |
964 | |
965 | void CodeGenPGO::loadRegionCounts(llvm::IndexedInstrProfReader *PGOReader, |
966 | bool IsInMainFile) { |
967 | CGM.getPGOStats().addVisited(IsInMainFile); |
968 | RegionCounts.clear(); |
969 | llvm::Expected<llvm::InstrProfRecord> RecordExpected = |
970 | PGOReader->getInstrProfRecord(FuncName, FunctionHash); |
971 | if (auto E = RecordExpected.takeError()) { |
972 | auto IPE = llvm::InstrProfError::take(std::move(E)); |
973 | if (IPE == llvm::instrprof_error::unknown_function) |
974 | CGM.getPGOStats().addMissing(IsInMainFile); |
975 | else if (IPE == llvm::instrprof_error::hash_mismatch) |
976 | CGM.getPGOStats().addMismatched(IsInMainFile); |
977 | else if (IPE == llvm::instrprof_error::malformed) |
978 | |
979 | CGM.getPGOStats().addMismatched(IsInMainFile); |
980 | return; |
981 | } |
982 | ProfRecord = |
983 | llvm::make_unique<llvm::InstrProfRecord>(std::move(RecordExpected.get())); |
984 | RegionCounts = ProfRecord->Counts; |
985 | } |
986 | |
987 | |
988 | |
989 | |
990 | |
991 | static uint64_t calculateWeightScale(uint64_t MaxWeight) { |
992 | return MaxWeight < UINT32_MAX ? 1 : MaxWeight / UINT32_MAX + 1; |
993 | } |
994 | |
995 | |
996 | |
997 | |
998 | |
999 | |
1000 | |
1001 | |
1002 | |
1003 | |
1004 | static uint32_t scaleBranchWeight(uint64_t Weight, uint64_t Scale) { |
1005 | (0) . __assert_fail ("Scale && \"scale by 0?\"", "/home/seafit/code_projects/clang_source/clang/lib/CodeGen/CodeGenPGO.cpp", 1005, __PRETTY_FUNCTION__))" file_link="../../../include/assert.h.html#88" macro="true">assert(Scale && "scale by 0?"); |
1006 | uint64_t Scaled = Weight / Scale + 1; |
1007 | (0) . __assert_fail ("Scaled <= UINT32_MAX && \"overflow 32-bits\"", "/home/seafit/code_projects/clang_source/clang/lib/CodeGen/CodeGenPGO.cpp", 1007, __PRETTY_FUNCTION__))" file_link="../../../include/assert.h.html#88" macro="true">assert(Scaled <= UINT32_MAX && "overflow 32-bits"); |
1008 | return Scaled; |
1009 | } |
1010 | |
1011 | llvm::MDNode *CodeGenFunction::createProfileWeights(uint64_t TrueCount, |
1012 | uint64_t FalseCount) { |
1013 | |
1014 | if (!TrueCount && !FalseCount) |
1015 | return nullptr; |
1016 | |
1017 | |
1018 | uint64_t Scale = calculateWeightScale(std::max(TrueCount, FalseCount)); |
1019 | |
1020 | llvm::MDBuilder MDHelper(CGM.getLLVMContext()); |
1021 | return MDHelper.createBranchWeights(scaleBranchWeight(TrueCount, Scale), |
1022 | scaleBranchWeight(FalseCount, Scale)); |
1023 | } |
1024 | |
1025 | llvm::MDNode * |
1026 | CodeGenFunction::createProfileWeights(ArrayRef<uint64_t> Weights) { |
1027 | |
1028 | if (Weights.size() < 2) |
1029 | return nullptr; |
1030 | |
1031 | |
1032 | uint64_t MaxWeight = *std::max_element(Weights.begin(), Weights.end()); |
1033 | if (MaxWeight == 0) |
1034 | return nullptr; |
1035 | |
1036 | |
1037 | uint64_t Scale = calculateWeightScale(MaxWeight); |
1038 | |
1039 | SmallVector<uint32_t, 16> ScaledWeights; |
1040 | ScaledWeights.reserve(Weights.size()); |
1041 | for (uint64_t W : Weights) |
1042 | ScaledWeights.push_back(scaleBranchWeight(W, Scale)); |
1043 | |
1044 | llvm::MDBuilder MDHelper(CGM.getLLVMContext()); |
1045 | return MDHelper.createBranchWeights(ScaledWeights); |
1046 | } |
1047 | |
1048 | llvm::MDNode *CodeGenFunction::createProfileWeightsForLoop(const Stmt *Cond, |
1049 | uint64_t LoopCount) { |
1050 | if (!PGO.haveRegionCounts()) |
1051 | return nullptr; |
1052 | Optional<uint64_t> CondCount = PGO.getStmtCount(Cond); |
1053 | (0) . __assert_fail ("CondCount.hasValue() && \"missing expected loop condition count\"", "/home/seafit/code_projects/clang_source/clang/lib/CodeGen/CodeGenPGO.cpp", 1053, __PRETTY_FUNCTION__))" file_link="../../../include/assert.h.html#88" macro="true">assert(CondCount.hasValue() && "missing expected loop condition count"); |
1054 | if (*CondCount == 0) |
1055 | return nullptr; |
1056 | return createProfileWeights(LoopCount, |
1057 | std::max(*CondCount, LoopCount) - LoopCount); |
1058 | } |
1059 | |