clang: lib/CodeGen/CodeGenPGO.cpp Source File (original) (raw)

1

2

3

4

5

6

7

8

9

10

11

12

18#include "llvm/IR/Intrinsics.h"

19#include "llvm/IR/MDBuilder.h"

20#include "llvm/Support/CommandLine.h"

21#include "llvm/Support/Endian.h"

22#include "llvm/Support/MD5.h"

23#include

24

25namespace llvm {

27}

28

29static llvm:🆑:opt

31 llvm:🆑:desc("Enable value profiling"),

32 llvm:🆑:Hidden, llvm:🆑:init(false));

33

34using namespace clang;

35using namespace CodeGen;

36

37void CodeGenPGO::setFuncName(StringRef Name,

38 llvm::GlobalValue::LinkageTypes Linkage) {

39 llvm::IndexedInstrProfReader *PGOReader = CGM.getPGOReader();

40 FuncName = llvm::getPGOFuncName(

42 PGOReader ? PGOReader->getVersion() : llvm::IndexedInstrProf::Version);

43

44

46 FuncNameVar = llvm::createPGOFuncNameVar(CGM.getModule(), Linkage, FuncName);

47}

48

49void CodeGenPGO::setFuncName(llvm::Function *Fn) {

50 setFuncName(Fn->getName(), Fn->getLinkage());

51

52 llvm::createPGOFuncNameMetadata(*Fn, FuncName);

53}

54

55

60

61

64

65namespace {

66

67

68

69

70

71

72

73

74

75

76class PGOHash {

78 unsigned Count;

80 llvm::MD5 MD5;

81

82 static const int NumBitsPerType = 6;

83 static const unsigned NumTypesPerWord = sizeof(uint64_t) * 8 / NumBitsPerType;

84 static const unsigned TooBig = 1u << NumBitsPerType;

85

86public:

87

88

89

90

91

92

93

94 enum HashType : unsigned char {

109 BinaryOperatorLAnd,

110 BinaryOperatorLOr,

112

113

114 EndOfScope,

115 IfThenBranch,

116 IfElseBranch,

122 ThrowExpr,

123 UnaryOperatorLNot,

124 BinaryOperatorLT,

125 BinaryOperatorGT,

126 BinaryOperatorLE,

127 BinaryOperatorGE,

128 BinaryOperatorEQ,

129 BinaryOperatorNE,

130

131

132

133 LastHashType

134 };

135 static_assert(LastHashType <= TooBig, "Too many types in HashType");

136

138 : Working(0), Count(0), HashVersion(HashVersion) {}

139 void combine(HashType Type);

141 PGOHashVersion getHashVersion() const { return HashVersion; }

142};

143const int PGOHash::NumBitsPerType;

144const unsigned PGOHash::NumTypesPerWord;

145const unsigned PGOHash::TooBig;

146

147

148static PGOHashVersion getPGOHashVersion(llvm::IndexedInstrProfReader *PGOReader,

150 if (PGOReader->getVersion() <= 4)

152 if (PGOReader->getVersion() <= 5)

155}

156

157

158struct MapRegionCounters : public RecursiveASTVisitor {

160

161

162 unsigned NextCounter;

163

164 PGOHash Hash;

165

166 llvm::DenseMap<const Stmt *, CounterPair> &CounterMap;

167

169

170 unsigned MCDCMaxCond;

171

173

175

176 MapRegionCounters(PGOHashVersion HashVersion, uint64_t ProfileVersion,

177 llvm::DenseMap<const Stmt *, CounterPair> &CounterMap,

178 MCDC::State &MCDCState, unsigned MCDCMaxCond,

180 : NextCounter(0), Hash(HashVersion), CounterMap(CounterMap),

181 MCDCState(MCDCState), MCDCMaxCond(MCDCMaxCond),

182 ProfileVersion(ProfileVersion), Diag(Diag) {}

183

184

185

186 bool TraverseBlockExpr(BlockExpr *BE) { return true; }

187 bool TraverseLambdaExpr(LambdaExpr *LE) {

188

189 for (auto C : zip(LE->captures(), LE->capture_inits()))

190 TraverseLambdaCapture(LE, &std::get<0>(C), std::get<1>(C));

191 return true;

192 }

193 bool TraverseCapturedStmt(CapturedStmt *CS) { return true; }

194

195 bool VisitDecl(const Decl *D) {

197 default:

198 break;

199 case Decl::Function:

200 case Decl::CXXMethod:

201 case Decl::CXXConstructor:

202 case Decl::CXXDestructor:

203 case Decl::CXXConversion:

204 case Decl::ObjCMethod:

205 case Decl::Block:

206 case Decl::Captured:

207 CounterMap[D->getBody()] = NextCounter++;

208 break;

209 }

210 return true;

211 }

212

213

214

215 PGOHash::HashType updateCounterMappings(Stmt *S) {

217 if (Type != PGOHash::None)

218 CounterMap[S] = NextCounter++;

220 }

221

222

223

224

225

226

227

228

229

230

231 unsigned NumCond = 0;

232 bool SplitNestedLogicalOp = false;

235

236

237 bool dataTraverseStmtPre(Stmt *S) {

238

239 if (MCDCMaxCond == 0)

240 return true;

241

242

243

244 if (LogOpStack.empty()) {

245 NumCond = 0;

246 SplitNestedLogicalOp = false;

247 }

248

249 if (const Expr *E = dyn_cast(S)) {

252

253

254

255

256

257

258

259 SplitNestedLogicalOp = SplitNestedLogicalOp || !NonLogOpStack.empty();

260

261 LogOpStack.push_back(BinOp);

262 return true;

263 }

264 }

265

266

267

268 if (!LogOpStack.empty())

269 NonLogOpStack.push_back(S);

270

271 return true;

272 }

273

274

275

276

277 bool dataTraverseStmtPost(Stmt *S) {

278

279 if (MCDCMaxCond == 0)

280 return true;

281

282 if (const Expr *E = dyn_cast(S)) {

285 assert(LogOpStack.back() == BinOp);

286 LogOpStack.pop_back();

287

288

289 if (LogOpStack.empty()) {

290

291 if (SplitNestedLogicalOp) {

292 unsigned DiagID = Diag.getCustomDiagID(

294 "unsupported MC/DC boolean expression; "

295 "contains an operation with a nested boolean expression. "

296 "Expression will not be covered");

297 Diag.Report(S->getBeginLoc(), DiagID);

298 return true;

299 }

300

301

302 if (NumCond > MCDCMaxCond) {

303 unsigned DiagID = Diag.getCustomDiagID(

305 "unsupported MC/DC boolean expression; "

306 "number of conditions (%0) exceeds max (%1). "

307 "Expression will not be covered");

308 Diag.Report(S->getBeginLoc(), DiagID) << NumCond << MCDCMaxCond;

309 return true;

310 }

311

312

314 }

315 return true;

316 }

317 }

318

319 if (!LogOpStack.empty())

320 NonLogOpStack.pop_back();

321

322 return true;

323 }

324

325

326

327

328

329

331 if (S->isLogicalOp()) {

332 if (CodeGenFunction::isInstrumentedCondition(S->getLHS()))

333 NumCond++;

334

335 if (CodeGenFunction::isInstrumentedCondition(S->getRHS())) {

336 if (ProfileVersion >= llvm::IndexedInstrProf::Version7)

337 CounterMap[S->getRHS()] = NextCounter++;

338

339 NumCond++;

340 }

341 }

342 return Base::VisitBinaryOperator(S);

343 }

344

347 CounterMap[S->getTrueExpr()] = NextCounter++;

349 CounterMap[S->getFalseExpr()] = NextCounter++;

350 return Base::VisitConditionalOperator(S);

351 }

352

353

354 bool VisitStmt(Stmt *S) {

355 auto Type = updateCounterMappings(S);

356 if (Hash.getHashVersion() != PGO_HASH_V1)

357 Type = getHashType(Hash.getHashVersion(), S);

358 if (Type != PGOHash::None)

359 Hash.combine(Type);

360 return true;

361 }

362

363 bool TraverseIfStmt(IfStmt *If) {

364

365 if (Hash.getHashVersion() == PGO_HASH_V1)

366 return Base::TraverseIfStmt(If);

367

368

369

371 for (Stmt *CS : If->children()) {

372 if (!CS || NoSingleByteCoverage)

373 continue;

374 if (CS == If->getThen())

375 CounterMap[If->getThen()] = NextCounter++;

376 else if (CS == If->getElse())

377 CounterMap[If->getElse()] = NextCounter++;

378 }

379

380

381 VisitStmt(If);

382

383 for (Stmt *CS : If->children()) {

384 if (!CS)

385 continue;

386 if (CS == If->getThen())

387 Hash.combine(PGOHash::IfThenBranch);

388 else if (CS == If->getElse())

389 Hash.combine(PGOHash::IfElseBranch);

390 TraverseStmt(CS);

391 }

392 Hash.combine(PGOHash::EndOfScope);

393 return true;

394 }

395

396 bool TraverseWhileStmt(WhileStmt *While) {

397

398

401 if (!CS || NoSingleByteCoverage)

402 continue;

403 if (CS == While->getCond())

404 CounterMap[While->getCond()] = NextCounter++;

405 else if (CS == While->getBody())

406 CounterMap[While->getBody()] = NextCounter++;

407 }

408

409 Base::TraverseWhileStmt(While);

410 if (Hash.getHashVersion() != PGO_HASH_V1)

411 Hash.combine(PGOHash::EndOfScope);

412 return true;

413 }

414

415 bool TraverseDoStmt(DoStmt *Do) {

416

417

420 if (!CS || NoSingleByteCoverage)

421 continue;

423 CounterMap[Do->getCond()] = NextCounter++;

424 else if (CS == Do->getBody())

425 CounterMap[Do->getBody()] = NextCounter++;

426 }

427

428 Base::TraverseDoStmt(Do);

429 if (Hash.getHashVersion() != PGO_HASH_V1)

430 Hash.combine(PGOHash::EndOfScope);

431 return true;

432 }

433

434 bool TraverseForStmt(ForStmt *For) {

435

436

439 if (!CS || NoSingleByteCoverage)

440 continue;

441 if (CS == For->getCond())

442 CounterMap[For->getCond()] = NextCounter++;

443 else if (CS == For->getInc())

444 CounterMap[For->getInc()] = NextCounter++;

445 else if (CS == For->getBody())

446 CounterMap[For->getBody()] = NextCounter++;

447 }

448

449 Base::TraverseForStmt(For);

450 if (Hash.getHashVersion() != PGO_HASH_V1)

451 Hash.combine(PGOHash::EndOfScope);

452 return true;

453 }

454

455 bool TraverseCXXForRangeStmt(CXXForRangeStmt *ForRange) {

456

459 if (!CS || NoSingleByteCoverage)

460 continue;

461 if (CS == ForRange->getBody())

462 CounterMap[ForRange->getBody()] = NextCounter++;

463 }

464

465 Base::TraverseCXXForRangeStmt(ForRange);

466 if (Hash.getHashVersion() != PGO_HASH_V1)

467 Hash.combine(PGOHash::EndOfScope);

468 return true;

469 }

470

471

472

473

474#define DEFINE_NESTABLE_TRAVERSAL(N) \

475 bool Traverse##N(N *S) { \

476 Base::Traverse##N(S); \

477 if (Hash.getHashVersion() != PGO_HASH_V1) \

478 Hash.combine(PGOHash::EndOfScope); \

479 return true; \

480 }

481

485

486

487 PGOHash::HashType getHashType(PGOHashVersion HashVersion, const Stmt *S) {

488 switch (S->getStmtClass()) {

489 default:

490 break;

491 case Stmt::LabelStmtClass:

492 return PGOHash::LabelStmt;

493 case Stmt::WhileStmtClass:

494 return PGOHash::WhileStmt;

495 case Stmt::DoStmtClass:

496 return PGOHash::DoStmt;

497 case Stmt::ForStmtClass:

498 return PGOHash::ForStmt;

499 case Stmt::CXXForRangeStmtClass:

500 return PGOHash::CXXForRangeStmt;

501 case Stmt::ObjCForCollectionStmtClass:

502 return PGOHash::ObjCForCollectionStmt;

503 case Stmt::SwitchStmtClass:

504 return PGOHash::SwitchStmt;

505 case Stmt::CaseStmtClass:

506 return PGOHash::CaseStmt;

507 case Stmt::DefaultStmtClass:

508 return PGOHash::DefaultStmt;

509 case Stmt::IfStmtClass:

510 return PGOHash::IfStmt;

511 case Stmt::CXXTryStmtClass:

512 return PGOHash::CXXTryStmt;

513 case Stmt::CXXCatchStmtClass:

514 return PGOHash::CXXCatchStmt;

515 case Stmt::ConditionalOperatorClass:

516 return PGOHash::ConditionalOperator;

517 case Stmt::BinaryConditionalOperatorClass:

518 return PGOHash::BinaryConditionalOperator;

519 case Stmt::BinaryOperatorClass: {

522 return PGOHash::BinaryOperatorLAnd;

524 return PGOHash::BinaryOperatorLOr;

527 default:

528 break;

529 case BO_LT:

530 return PGOHash::BinaryOperatorLT;

531 case BO_GT:

532 return PGOHash::BinaryOperatorGT;

533 case BO_LE:

534 return PGOHash::BinaryOperatorLE;

535 case BO_GE:

536 return PGOHash::BinaryOperatorGE;

537 case BO_EQ:

538 return PGOHash::BinaryOperatorEQ;

539 case BO_NE:

540 return PGOHash::BinaryOperatorNE;

541 }

542 }

543 break;

544 }

545 }

546

548 switch (S->getStmtClass()) {

549 default:

550 break;

551 case Stmt::GotoStmtClass:

552 return PGOHash::GotoStmt;

553 case Stmt::IndirectGotoStmtClass:

554 return PGOHash::IndirectGotoStmt;

555 case Stmt::BreakStmtClass:

556 return PGOHash::BreakStmt;

557 case Stmt::ContinueStmtClass:

558 return PGOHash::ContinueStmt;

559 case Stmt::ReturnStmtClass:

560 return PGOHash::ReturnStmt;

561 case Stmt::CXXThrowExprClass:

562 return PGOHash::ThrowExpr;

563 case Stmt::UnaryOperatorClass: {

564 const UnaryOperator *UO = cast(S);

566 return PGOHash::UnaryOperatorLNot;

567 break;

568 }

569 }

570 }

571

572 return PGOHash::None;

573 }

574};

575

576

577

578struct ComputeRegionCounts : public ConstStmtVisitor {

579

581

582

583

584 bool RecordNextStmtCount;

585

586

588

589

590 llvm::DenseMap<const Stmt *, uint64_t> &CountMap;

591

592

593 struct BreakContinue {

596 BreakContinue() = default;

597 };

599

600 ComputeRegionCounts(llvm::DenseMap<const Stmt *, uint64_t> &CountMap,

603

604 void RecordStmtCount(const Stmt *S) {

605 if (RecordNextStmtCount) {

607 RecordNextStmtCount = false;

608 }

609 }

610

611

612 uint64_t setCount(uint64_t Count) {

613 CurrentCount = Count;

614 return Count;

615 }

616

617 void VisitStmt(const Stmt *S) {

618 RecordStmtCount(S);

619 for (const Stmt *Child : S->children())

620 if (Child)

621 this->Visit(Child);

622 }

623

625

629 }

630

631

632

633

634 void VisitLambdaExpr(const LambdaExpr *LE) {}

635

637

641 }

642

644

648 }

649

650 void VisitBlockDecl(const BlockDecl *D) {

651

655 }

656

657 void VisitReturnStmt(const ReturnStmt *S) {

658 RecordStmtCount(S);

659 if (S->getRetValue())

660 Visit(S->getRetValue());

661 CurrentCount = 0;

662 RecordNextStmtCount = true;

663 }

664

666 RecordStmtCount(E);

667 if (E->getSubExpr())

668 Visit(E->getSubExpr());

669 CurrentCount = 0;

670 RecordNextStmtCount = true;

671 }

672

673 void VisitGotoStmt(const GotoStmt *S) {

674 RecordStmtCount(S);

675 CurrentCount = 0;

676 RecordNextStmtCount = true;

677 }

678

679 void VisitLabelStmt(const LabelStmt *S) {

680 RecordNextStmtCount = false;

681

684 Visit(S->getSubStmt());

685 }

686

687 void VisitBreakStmt(const BreakStmt *S) {

688 RecordStmtCount(S);

689 assert(!BreakContinueStack.empty() && "break not in a loop or switch!");

690 BreakContinueStack.back().BreakCount += CurrentCount;

691 CurrentCount = 0;

692 RecordNextStmtCount = true;

693 }

694

695 void VisitContinueStmt(const ContinueStmt *S) {

696 RecordStmtCount(S);

697 assert(!BreakContinueStack.empty() && "continue stmt not in a loop!");

698 BreakContinueStack.back().ContinueCount += CurrentCount;

699 CurrentCount = 0;

700 RecordNextStmtCount = true;

701 }

702

703 void VisitWhileStmt(const WhileStmt *S) {

704 RecordStmtCount(S);

705 uint64_t ParentCount = CurrentCount;

706

707 BreakContinueStack.push_back(BreakContinue());

708

709

711 CountMap[S->getBody()] = CurrentCount;

712 Visit(S->getBody());

713 uint64_t BackedgeCount = CurrentCount;

714

715

716

717

718

719 BreakContinue BC = BreakContinueStack.pop_back_val();

721 setCount(ParentCount + BackedgeCount + BC.ContinueCount);

722 CountMap[S->getCond()] = CondCount;

723 Visit(S->getCond());

724 setCount(BC.BreakCount + CondCount - BodyCount);

725 RecordNextStmtCount = true;

726 }

727

728 void VisitDoStmt(const DoStmt *S) {

729 RecordStmtCount(S);

731

732 BreakContinueStack.push_back(BreakContinue());

733

734 uint64_t BodyCount = setCount(LoopCount + CurrentCount);

735 CountMap[S->getBody()] = BodyCount;

736 Visit(S->getBody());

737 uint64_t BackedgeCount = CurrentCount;

738

739 BreakContinue BC = BreakContinueStack.pop_back_val();

740

741

742 uint64_t CondCount = setCount(BackedgeCount + BC.ContinueCount);

743 CountMap[S->getCond()] = CondCount;

744 Visit(S->getCond());

745 setCount(BC.BreakCount + CondCount - LoopCount);

746 RecordNextStmtCount = true;

747 }

748

749 void VisitForStmt(const ForStmt *S) {

750 RecordStmtCount(S);

751 if (S->getInit())

752 Visit(S->getInit());

753

754 uint64_t ParentCount = CurrentCount;

755

756 BreakContinueStack.push_back(BreakContinue());

757

758

760 CountMap[S->getBody()] = BodyCount;

761 Visit(S->getBody());

762 uint64_t BackedgeCount = CurrentCount;

763 BreakContinue BC = BreakContinueStack.pop_back_val();

764

765

766

767 if (S->getInc()) {

768 uint64_t IncCount = setCount(BackedgeCount + BC.ContinueCount);

769 CountMap[S->getInc()] = IncCount;

770 Visit(S->getInc());

771 }

772

773

775 setCount(ParentCount + BackedgeCount + BC.ContinueCount);

776 if (S->getCond()) {

777 CountMap[S->getCond()] = CondCount;

778 Visit(S->getCond());

779 }

780 setCount(BC.BreakCount + CondCount - BodyCount);

781 RecordNextStmtCount = true;

782 }

783

785 RecordStmtCount(S);

786 if (S->getInit())

787 Visit(S->getInit());

788 Visit(S->getLoopVarStmt());

789 Visit(S->getRangeStmt());

790 Visit(S->getBeginStmt());

791 Visit(S->getEndStmt());

792

793 uint64_t ParentCount = CurrentCount;

794 BreakContinueStack.push_back(BreakContinue());

795

796

798 CountMap[S->getBody()] = BodyCount;

799 Visit(S->getBody());

800 uint64_t BackedgeCount = CurrentCount;

801 BreakContinue BC = BreakContinueStack.pop_back_val();

802

803

804

805 uint64_t IncCount = setCount(BackedgeCount + BC.ContinueCount);

806 CountMap[S->getInc()] = IncCount;

807 Visit(S->getInc());

808

809

811 setCount(ParentCount + BackedgeCount + BC.ContinueCount);

812 CountMap[S->getCond()] = CondCount;

813 Visit(S->getCond());

814 setCount(BC.BreakCount + CondCount - BodyCount);

815 RecordNextStmtCount = true;

816 }

817

819 RecordStmtCount(S);

820 Visit(S->getElement());

821 uint64_t ParentCount = CurrentCount;

822 BreakContinueStack.push_back(BreakContinue());

823

825 CountMap[S->getBody()] = BodyCount;

826 Visit(S->getBody());

827 uint64_t BackedgeCount = CurrentCount;

828 BreakContinue BC = BreakContinueStack.pop_back_val();

829

830 setCount(BC.BreakCount + ParentCount + BackedgeCount + BC.ContinueCount -

831 BodyCount);

832 RecordNextStmtCount = true;

833 }

834

835 void VisitSwitchStmt(const SwitchStmt *S) {

836 RecordStmtCount(S);

837 if (S->getInit())

838 Visit(S->getInit());

839 Visit(S->getCond());

840 CurrentCount = 0;

841 BreakContinueStack.push_back(BreakContinue());

842 Visit(S->getBody());

843

844 BreakContinue BC = BreakContinueStack.pop_back_val();

845 if (!BreakContinueStack.empty())

846 BreakContinueStack.back().ContinueCount += BC.ContinueCount;

847

849 RecordNextStmtCount = true;

850 }

851

852 void VisitSwitchCase(const SwitchCase *S) {

853 RecordNextStmtCount = false;

854

855

856

858 setCount(CurrentCount + CaseCount);

859

860

862 RecordNextStmtCount = true;

863 Visit(S->getSubStmt());

864 }

865

866 void VisitIfStmt(const IfStmt *S) {

867 RecordStmtCount(S);

868

869 if (S->isConsteval()) {

870 const Stmt *Stm = S->isNegatedConsteval() ? S->getThen() : S->getElse();

871 if (Stm)

872 Visit(Stm);

873 return;

874 }

875

876 uint64_t ParentCount = CurrentCount;

877 if (S->getInit())

878 Visit(S->getInit());

879 Visit(S->getCond());

880

881

882

884 CountMap[S->getThen()] = ThenCount;

885 Visit(S->getThen());

886 uint64_t OutCount = CurrentCount;

887

888 uint64_t ElseCount = ParentCount - ThenCount;

889 if (S->getElse()) {

890 setCount(ElseCount);

891 CountMap[S->getElse()] = ElseCount;

892 Visit(S->getElse());

893 OutCount += CurrentCount;

894 } else

895 OutCount += ElseCount;

896 setCount(OutCount);

897 RecordNextStmtCount = true;

898 }

899

900 void VisitCXXTryStmt(const CXXTryStmt *S) {

901 RecordStmtCount(S);

902 Visit(S->getTryBlock());

903 for (unsigned I = 0, E = S->getNumHandlers(); I < E; ++I)

904 Visit(S->getHandler(I));

905

907 RecordNextStmtCount = true;

908 }

909

910 void VisitCXXCatchStmt(const CXXCatchStmt *S) {

911 RecordNextStmtCount = false;

912

915 Visit(S->getHandlerBlock());

916 }

917

919 RecordStmtCount(E);

920 uint64_t ParentCount = CurrentCount;

921 Visit(E->getCond());

922

923

924

926 CountMap[E->getTrueExpr()] = TrueCount;

927 Visit(E->getTrueExpr());

928 uint64_t OutCount = CurrentCount;

929

930 uint64_t FalseCount = setCount(ParentCount - TrueCount);

931 CountMap[E->getFalseExpr()] = FalseCount;

932 Visit(E->getFalseExpr());

933 OutCount += CurrentCount;

934

935 setCount(OutCount);

936 RecordNextStmtCount = true;

937 }

938

940 RecordStmtCount(E);

941 uint64_t ParentCount = CurrentCount;

942 Visit(E->getLHS());

943

945 CountMap[E->getRHS()] = RHSCount;

946 Visit(E->getRHS());

947 setCount(ParentCount + RHSCount - CurrentCount);

948 RecordNextStmtCount = true;

949 }

950

952 RecordStmtCount(E);

953 uint64_t ParentCount = CurrentCount;

954 Visit(E->getLHS());

955

957 CountMap[E->getRHS()] = RHSCount;

958 Visit(E->getRHS());

959 setCount(ParentCount + RHSCount - CurrentCount);

960 RecordNextStmtCount = true;

961 }

962};

963}

964

965void PGOHash::combine(HashType Type) {

966

967 assert(Type && "Hash is invalid: unexpected type 0");

968 assert(unsigned(Type) < TooBig && "Hash is invalid: too many types");

969

970

971 if (Count && Count % NumTypesPerWord == 0) {

972 using namespace llvm::support;

974 endian::byte_swap<uint64_t, llvm::endianness::little>(Working);

975 MD5.update(llvm::ArrayRef((uint8_t *)&Swapped, sizeof(Swapped)));

976 Working = 0;

977 }

978

979

980 ++Count;

981 Working = Working << NumBitsPerType | Type;

982}

983

984uint64_t PGOHash::finalize() {

985

986 if (Count <= NumTypesPerWord)

987

988

989

990 return Working;

991

992

993 if (Working) {

994

995

997 MD5.update({(uint8_t)Working});

998 } else {

999 using namespace llvm::support;

1001 endian::byte_swap<uint64_t, llvm::endianness::little>(Working);

1002 MD5.update(llvm::ArrayRef((uint8_t *)&Swapped, sizeof(Swapped)));

1003 }

1004 }

1005

1006

1007 llvm::MD5::MD5Result Result;

1009 return Result.low();

1010}

1011

1015 return;

1016

1017

1019 D->hasAttr())

1020 return;

1021

1023 llvm::IndexedInstrProfReader *PGOReader = CGM.getPGOReader();

1024 if (!InstrumentRegions && !PGOReader)

1025 return;

1027 return;

1028

1029

1030

1032 if (const auto *CCD = dyn_cast(D))

1035 return;

1036 }

1038 return;

1039

1041 if (Fn->hasFnAttribute(llvm::Attribute::NoProfile))

1042 return;

1043 if (Fn->hasFnAttribute(llvm::Attribute::SkipProfile))

1044 return;

1045

1049 return;

1050

1051 setFuncName(Fn);

1052

1053 mapRegionCounters(D);

1055 emitCounterRegionMapping(D);

1056 if (PGOReader) {

1057 loadRegionCounts(PGOReader, SM.isInMainFile(D->getLocation()));

1058 computeRegionCounts(D);

1059 applyFunctionAttributes(PGOReader, Fn);

1060 }

1061}

1062

1063void CodeGenPGO::mapRegionCounters(const Decl *D) {

1064

1065

1067 uint64_t ProfileVersion = llvm::IndexedInstrProf::Version;

1069 HashVersion = getPGOHashVersion(PGOReader, CGM);

1070 ProfileVersion = PGOReader->getVersion();

1071 }

1072

1073

1074

1075

1076

1077

1078

1079

1080

1081

1082 unsigned MCDCMaxConditions =

1084 : 0);

1085

1086 RegionCounterMap.reset(new llvm::DenseMap<const Stmt *, CounterPair>);

1088 MapRegionCounters Walker(HashVersion, ProfileVersion, *RegionCounterMap,

1089 *RegionMCDCState, MCDCMaxConditions, CGM.getDiags());

1090 if (const FunctionDecl *FD = dyn_cast_or_null(D))

1091 Walker.TraverseDecl(const_cast<FunctionDecl *>(FD));

1092 else if (const ObjCMethodDecl *MD = dyn_cast_or_null(D))

1093 Walker.TraverseDecl(const_cast<ObjCMethodDecl *>(MD));

1094 else if (const BlockDecl *BD = dyn_cast_or_null(D))

1095 Walker.TraverseDecl(const_cast<BlockDecl *>(BD));

1096 else if (const CapturedDecl *CD = dyn_cast_or_null(D))

1097 Walker.TraverseDecl(const_cast<CapturedDecl *>(CD));

1098 assert(Walker.NextCounter > 0 && "no entry counter mapped for decl");

1099 NumRegionCounters = Walker.NextCounter;

1100 FunctionHash = Walker.Hash.finalize();

1101}

1102

1103bool CodeGenPGO::skipRegionMappingForDecl(const Decl *D) {

1105 return true;

1106

1107

1108

1109

1110

1113 D->hasAttr()) ||

1115 (D->hasAttr() ||

1116 (D->hasAttr() && D->hasAttr())))))

1117 return true;

1118

1119

1123}

1124

1125void CodeGenPGO::emitCounterRegionMapping(const Decl *D) {

1126 if (skipRegionMappingForDecl(D))

1127 return;

1128

1129 std::string CoverageMapping;

1130 llvm::raw_string_ostream OS(CoverageMapping);

1131 RegionMCDCState->BranchByStmt.clear();

1134 CGM.getLangOpts(), RegionCounterMap.get(), RegionMCDCState.get());

1135 MappingGen.emitCounterMapping(D, OS);

1136

1137 if (CoverageMapping.empty())

1138 return;

1139

1141 FuncNameVar, FuncName, FunctionHash, CoverageMapping);

1142}

1143

1144void

1146 llvm::GlobalValue::LinkageTypes Linkage) {

1147 if (skipRegionMappingForDecl(D))

1148 return;

1149

1150 std::string CoverageMapping;

1151 llvm::raw_string_ostream OS(CoverageMapping);

1156

1157 if (CoverageMapping.empty())

1158 return;

1159

1160 setFuncName(Name, Linkage);

1162 FuncNameVar, FuncName, FunctionHash, CoverageMapping, false);

1163}

1164

1165void CodeGenPGO::computeRegionCounts(const Decl *D) {

1166 StmtCountMap.reset(new llvm::DenseMap<const Stmt *, uint64_t>);

1167 ComputeRegionCounts Walker(*StmtCountMap, *this);

1168 if (const FunctionDecl *FD = dyn_cast_or_null(D))

1169 Walker.VisitFunctionDecl(FD);

1170 else if (const ObjCMethodDecl *MD = dyn_cast_or_null(D))

1171 Walker.VisitObjCMethodDecl(MD);

1172 else if (const BlockDecl *BD = dyn_cast_or_null(D))

1173 Walker.VisitBlockDecl(BD);

1174 else if (const CapturedDecl *CD = dyn_cast_or_null(D))

1175 Walker.VisitCapturedDecl(const_cast<CapturedDecl *>(CD));

1176}

1177

1178void

1179CodeGenPGO::applyFunctionAttributes(llvm::IndexedInstrProfReader *PGOReader,

1180 llvm::Function *Fn) {

1182 return;

1183

1185 Fn->setEntryCount(FunctionCount);

1186}

1187

1189 if (!RegionCounterMap)

1190 return {false, false};

1191

1192 auto I = RegionCounterMap->find(S);

1193 if (I == RegionCounterMap->end())

1194 return {false, false};

1195

1196 return {I->second.Executed.hasValue(), I->second.Skipped.hasValue()};

1197}

1198

1200 llvm::Value *StepV) {

1201 if (!RegionCounterMap || !Builder.GetInsertBlock())

1202 return;

1203

1204 unsigned Counter = (*RegionCounterMap)[S].Executed;

1205

1206

1207

1208 auto *NormalizedFuncNameVarPtr =

1209 llvm::ConstantExpr::getPointerBitCastOrAddrSpaceCast(

1210 FuncNameVar, llvm::PointerType::get(CGM.getLLVMContext(), 0));

1211

1212 llvm::Value *Args[] = {

1213 NormalizedFuncNameVarPtr, Builder.getInt64(FunctionHash),

1214 Builder.getInt32(NumRegionCounters), Builder.getInt32(Counter), StepV};

1215

1217 Builder.CreateCall(CGM.getIntrinsic(llvm::Intrinsic::instrprof_cover),

1219 else if (!StepV)

1220 Builder.CreateCall(CGM.getIntrinsic(llvm::Intrinsic::instrprof_increment),

1222 else

1223 Builder.CreateCall(

1224 CGM.getIntrinsic(llvm::Intrinsic::instrprof_increment_step), Args);

1225}

1226

1227bool CodeGenPGO::canEmitMCDCCoverage(const CGBuilderTy &Builder) {

1229 CGM.getCodeGenOpts().MCDCCoverage && Builder.GetInsertBlock());

1230}

1231

1233 if (!canEmitMCDCCoverage(Builder) || !RegionMCDCState)

1234 return;

1235

1236 auto *I8PtrTy = llvm::PointerType::getUnqual(CGM.getLLVMContext());

1237

1238

1239

1240

1241 llvm::Value *Args[3] = {llvm::ConstantExpr::getBitCast(FuncNameVar, I8PtrTy),

1242 Builder.getInt64(FunctionHash),

1243 Builder.getInt32(RegionMCDCState->BitmapBits)};

1244 Builder.CreateCall(

1245 CGM.getIntrinsic(llvm::Intrinsic::instrprof_mcdc_parameters), Args);

1246}

1247

1249 const Expr *S,

1250 Address MCDCCondBitmapAddr,

1252 if (!canEmitMCDCCoverage(Builder) || !RegionMCDCState)

1253 return;

1254

1255 S = S->IgnoreParens();

1256

1257 auto DecisionStateIter = RegionMCDCState->DecisionByStmt.find(S);

1258 if (DecisionStateIter == RegionMCDCState->DecisionByStmt.end())

1259 return;

1260

1261

1262

1263 if (DecisionStateIter->second.Indices.size() == 0)

1264 return;

1265

1266

1267 unsigned MCDCTestVectorBitmapOffset = DecisionStateIter->second.BitmapIdx;

1268 auto *I8PtrTy = llvm::PointerType::getUnqual(CGM.getLLVMContext());

1269

1270

1271

1272

1273

1274

1275 llvm::Value *Args[4] = {llvm::ConstantExpr::getBitCast(FuncNameVar, I8PtrTy),

1276 Builder.getInt64(FunctionHash),

1277 Builder.getInt32(MCDCTestVectorBitmapOffset),

1279 Builder.CreateCall(

1280 CGM.getIntrinsic(llvm::Intrinsic::instrprof_mcdc_tvbitmap_update), Args);

1281}

1282

1284 Address MCDCCondBitmapAddr) {

1285 if (!canEmitMCDCCoverage(Builder) || !RegionMCDCState)

1286 return;

1287

1288 S = S->IgnoreParens();

1289

1290 if (!RegionMCDCState->DecisionByStmt.contains(S))

1291 return;

1292

1293

1294 Builder.CreateStore(Builder.getInt32(0), MCDCCondBitmapAddr);

1295}

1296

1298 Address MCDCCondBitmapAddr,

1299 llvm::Value *Val,

1301 if (!canEmitMCDCCoverage(Builder) || !RegionMCDCState)

1302 return;

1303

1304

1305

1306

1307

1308

1309

1310

1312

1313 auto BranchStateIter = RegionMCDCState->BranchByStmt.find(S);

1314 if (BranchStateIter == RegionMCDCState->BranchByStmt.end())

1315 return;

1316

1317

1318 const auto &Branch = BranchStateIter->second;

1319 assert(Branch.ID >= 0 && "Condition has no ID!");

1320 assert(Branch.DecisionStmt);

1321

1322

1323 const auto DecisionIter =

1324 RegionMCDCState->DecisionByStmt.find(Branch.DecisionStmt);

1325 if (DecisionIter == RegionMCDCState->DecisionByStmt.end())

1326 return;

1327

1328 const auto &TVIdxs = DecisionIter->second.Indices[Branch.ID];

1329

1330 auto *CurTV = Builder.CreateLoad(MCDCCondBitmapAddr,

1331 "mcdc." + Twine(Branch.ID + 1) + ".cur");

1332 auto *NewTV = Builder.CreateAdd(CurTV, Builder.getInt32(TVIdxs[true]));

1333 NewTV = Builder.CreateSelect(

1334 Val, NewTV, Builder.CreateAdd(CurTV, Builder.getInt32(TVIdxs[false])));

1335 Builder.CreateStore(NewTV, MCDCCondBitmapAddr);

1336}

1337

1340 M.addModuleFlag(llvm::Module::Warning, "EnableValueProfiling",

1342}

1343

1347 const StringRef VarName(INSTR_PROF_QUOTE(INSTR_PROF_RAW_VERSION_VAR));

1348 llvm::Type *IntTy64 = llvm::Type::getInt64Ty(M.getContext());

1349 uint64_t ProfileVersion =

1350 (INSTR_PROF_RAW_VERSION | VARIANT_MASK_BYTE_COVERAGE);

1351

1352 auto IRLevelVersionVariable = new llvm::GlobalVariable(

1353 M, IntTy64, true, llvm::GlobalValue::WeakAnyLinkage,

1354 llvm::Constant::getIntegerValue(IntTy64,

1355 llvm::APInt(64, ProfileVersion)),

1356 VarName);

1357

1358 IRLevelVersionVariable->setVisibility(llvm::GlobalValue::HiddenVisibility);

1359 llvm::Triple TT(M.getTargetTriple());

1360 if (TT.supportsCOMDAT()) {

1361 IRLevelVersionVariable->setLinkage(llvm::GlobalValue::ExternalLinkage);

1362 IRLevelVersionVariable->setComdat(M.getOrInsertComdat(VarName));

1363 }

1364 IRLevelVersionVariable->setDSOLocal(true);

1365 }

1366}

1367

1368

1369

1371 llvm::Instruction *ValueSite, llvm::Value *ValuePtr) {

1372

1374 return;

1375

1376 if (!ValuePtr || !ValueSite || !Builder.GetInsertBlock())

1377 return;

1378

1379 if (isallvm::Constant(ValuePtr))

1380 return;

1381

1383 if (InstrumentValueSites && RegionCounterMap) {

1384 auto BuilderInsertPoint = Builder.saveIP();

1385 Builder.SetInsertPoint(ValueSite);

1386 llvm::Value *Args[5] = {

1387 FuncNameVar,

1388 Builder.getInt64(FunctionHash),

1389 Builder.CreatePtrToInt(ValuePtr, Builder.getInt64Ty()),

1390 Builder.getInt32(ValueKind),

1391 Builder.getInt32(NumValueSites[ValueKind]++)

1392 };

1393 Builder.CreateCall(

1394 CGM.getIntrinsic(llvm::Intrinsic::instrprof_value_profile), Args);

1395 Builder.restoreIP(BuilderInsertPoint);

1396 return;

1397 }

1398

1399 llvm::IndexedInstrProfReader *PGOReader = CGM.getPGOReader();

1401

1402

1403

1404

1405

1406

1407 if (NumValueSites[ValueKind] >= ProfRecord->getNumValueSites(ValueKind))

1408 return;

1409

1410 llvm::annotateValueSite(CGM.getModule(), *ValueSite, *ProfRecord,

1411 (llvm::InstrProfValueKind)ValueKind,

1412 NumValueSites[ValueKind]);

1413

1414 NumValueSites[ValueKind]++;

1415 }

1416}

1417

1418void CodeGenPGO::loadRegionCounts(llvm::IndexedInstrProfReader *PGOReader,

1419 bool IsInMainFile) {

1421 RegionCounts.clear();

1423 PGOReader->getInstrProfRecord(FuncName, FunctionHash);

1424 if (auto E = RecordExpected.takeError()) {

1425 auto IPE = std::get<0>(llvm::InstrProfError::take(std::move(E)));

1426 if (IPE == llvm::instrprof_error::unknown_function)

1428 else if (IPE == llvm::instrprof_error::hash_mismatch)

1430 else if (IPE == llvm::instrprof_error::malformed)

1431

1433 return;

1434 }

1435 ProfRecord =

1436 std::make_uniquellvm::InstrProfRecord(std::move(RecordExpected.get()));

1437 RegionCounts = ProfRecord->Counts;

1438}

1439

1440

1441

1442

1443

1445 return MaxWeight < UINT32_MAX ? 1 : MaxWeight / UINT32_MAX + 1;

1446}

1447

1448

1449

1450

1451

1452

1453

1454

1455

1456

1458 assert(Scale && "scale by 0?");

1459 uint64_t Scaled = Weight / Scale + 1;

1460 assert(Scaled <= UINT32_MAX && "overflow 32-bits");

1461 return Scaled;

1462}

1463

1464llvm::MDNode *CodeGenFunction::createProfileWeights(uint64_t TrueCount,

1465 uint64_t FalseCount) const {

1466

1467 if (!TrueCount && !FalseCount)

1468 return nullptr;

1469

1470

1472

1474 return MDHelper.createBranchWeights(scaleBranchWeight(TrueCount, Scale),

1476}

1477

1478llvm::MDNode *

1479CodeGenFunction::createProfileWeights(ArrayRef<uint64_t> Weights) const {

1480

1481 if (Weights.size() < 2)

1482 return nullptr;

1483

1484

1485 uint64_t MaxWeight = *std::max_element(Weights.begin(), Weights.end());

1486 if (MaxWeight == 0)

1487 return nullptr;

1488

1489

1491

1493 ScaledWeights.reserve(Weights.size());

1494 for (uint64_t W : Weights)

1496

1498 return MDHelper.createBranchWeights(ScaledWeights);

1499}

1500

1501llvm::MDNode *

1502CodeGenFunction::createProfileWeightsForLoop(const Stmt *Cond,

1503 uint64_t LoopCount) const {

1505 return nullptr;

1506 std::optional<uint64_t> CondCount = PGO.getStmtCount(Cond);

1507 if (!CondCount || *CondCount == 0)

1508 return nullptr;

1509 return createProfileWeights(LoopCount,

1510 std::max(*CondCount, LoopCount) - LoopCount);

1511}

llvm::ImmutableMap< CountKey, unsigned > CountMap

#define DEFINE_NESTABLE_TRAVERSAL(N)

static llvm:🆑:opt< bool > EnableValueProfiling("enable-value-profiling", llvm:🆑:desc("Enable value profiling"), llvm:🆑:Hidden, llvm:🆑:init(false))

PGOHashVersion

The version of the PGO hash algorithm.

static uint64_t calculateWeightScale(uint64_t MaxWeight)

Calculate what to divide by to scale weights.

static uint32_t scaleBranchWeight(uint64_t Weight, uint64_t Scale)

Scale an individual branch weight (and add 1).

static DiagnosticBuilder Diag(DiagnosticsEngine *Diags, const LangOptions &Features, FullSourceLoc TokLoc, const char *TokBegin, const char *TokRangeBegin, const char *TokRangeEnd, unsigned DiagID)

Produce a diagnostic highlighting some portion of a literal.

SourceManager & getSourceManager()

AbstractConditionalOperator - An abstract base class for ConditionalOperator and BinaryConditionalOpe...

BinaryConditionalOperator - The GNU extension to the conditional operator which allows the middle ope...

A builtin binary operation expression such as "x + y" or "x <= y".

static bool isLogicalOp(Opcode Opc)

Represents a block literal declaration, which is like an unnamed FunctionDecl.

BlockExpr - Adaptor class for mixing a BlockDecl with expressions.

BreakStmt - This represents a break.

CXXCatchStmt - This represents a C++ catch block.

CXXForRangeStmt - This represents C++0x [stmt.ranged]'s ranged for statement, represented as 'for (ra...

A C++ throw-expression (C++ [except.throw]).

CXXTryStmt - A C++ try block, including all handlers.

Represents the body of a CapturedStmt, and serves as its DeclContext.

This captures a statement into a function.

CaseStmt - Represent a case statement.

bool hasProfileClangInstr() const

Check if Clang profile instrumenation is on.

std::string MainFileName

The user provided name for the "main file", if non-empty.

Like RawAddress, an abstract representation of an aligned address, but the pointer contained in this ...

llvm::Value * emitRawPointer(CodeGenFunction &CGF) const

Return the pointer contained in this class after authenticating it and adding offset to it if necessa...

CodeGenFunction - This class organizes the per-function state that is used while generating LLVM code...

static const Expr * stripCond(const Expr *C)

Ignore parentheses and logical-NOT to track conditions consistently.

static bool IsConstructorDelegationValid(const CXXConstructorDecl *Ctor)

This class organizes the cross-function state that is used while generating LLVM code.

llvm::Module & getModule() const

DiagnosticsEngine & getDiags() const

const LangOptions & getLangOpts() const

const TargetInfo & getTarget() const

llvm::IndexedInstrProfReader * getPGOReader() const

CoverageMappingModuleGen * getCoverageMapping() const

InstrProfStats & getPGOStats()

ASTContext & getContext() const

const CodeGenOptions & getCodeGenOpts() const

llvm::LLVMContext & getLLVMContext()

llvm::Function * getIntrinsic(unsigned IID, ArrayRef< llvm::Type * > Tys={})

void ClearUnusedCoverageMapping(const Decl *D)

Remove the deferred empty coverage mapping as this declaration is actually instrumented.

void assignRegionCounters(GlobalDecl GD, llvm::Function *Fn)

Assign counters to regions and configure them for PGO of a given function.

std::pair< bool, bool > getIsCounterPair(const Stmt *S) const

std::optional< uint64_t > getStmtCount(const Stmt *S) const

Check if an execution count is known for a given statement.

void emitMCDCTestVectorBitmapUpdate(CGBuilderTy &Builder, const Expr *S, Address MCDCCondBitmapAddr, CodeGenFunction &CGF)

uint64_t getRegionCount(const Stmt *S)

Return the region count for the counter at the given index.

void setValueProfilingFlag(llvm::Module &M)

void valueProfile(CGBuilderTy &Builder, uint32_t ValueKind, llvm::Instruction *ValueSite, llvm::Value *ValuePtr)

void emitMCDCCondBitmapUpdate(CGBuilderTy &Builder, const Expr *S, Address MCDCCondBitmapAddr, llvm::Value *Val, CodeGenFunction &CGF)

void emitMCDCCondBitmapReset(CGBuilderTy &Builder, const Expr *S, Address MCDCCondBitmapAddr)

void setProfileVersion(llvm::Module &M)

void emitEmptyCounterMapping(const Decl *D, StringRef FuncName, llvm::GlobalValue::LinkageTypes Linkage)

Emit a coverage mapping range with a counter zero for an unused declaration.

void emitMCDCParameters(CGBuilderTy &Builder)

bool haveRegionCounts() const

Whether or not we have PGO region data for the current function.

void emitCounterSetOrIncrement(CGBuilderTy &Builder, const Stmt *S, llvm::Value *StepV)

Organizes the per-function state that is used while generating code coverage mapping data.

void emitEmptyMapping(const Decl *D, llvm::raw_ostream &OS)

Emit the coverage mapping data for an unused function.

void addFunctionMappingRecord(llvm::GlobalVariable *FunctionName, StringRef FunctionNameValue, uint64_t FunctionHash, const std::string &CoverageMapping, bool IsUsed=true)

Add a function's coverage mapping record to the collection of the function mapping records.

void addMissing(bool MainFile)

Record that a function we've visited has no profile data.

void addMismatched(bool MainFile)

Record that a function we've visited has mismatched profile data.

void addVisited(bool MainFile)

Record that we've visited a function and whether or not that function was in the main source file.

ConditionalOperator - The ?: ternary operator.

ConstStmtVisitor - This class implements a simple visitor for Stmt subclasses.

ContinueStmt - This represents a continue.

Decl - This represents one declaration (or definition), e.g.

bool isImplicit() const

isImplicit - Indicates whether the declaration was implicitly generated by the implementation.

virtual Stmt * getBody() const

getBody - If this Decl represents a declaration for a body of code, such as a function or method defi...

virtual bool hasBody() const

Returns true if this Decl represents a declaration for a body of code, such as a function or method d...

SourceLocation getLocation() const

Concrete class used by the front-end to report problems and issues.

DoStmt - This represents a 'do/while' stmt.

This represents one expression.

Expr * IgnoreParens() LLVM_READONLY

Skip past any parentheses which might surround this expression until reaching a fixed point.

ForStmt - This represents a 'for (init;cond;inc)' stmt.

Represents a function declaration or definition.

GlobalDecl - represents a global declaration.

CXXCtorType getCtorType() const

CXXDtorType getDtorType() const

const Decl * getDecl() const

GotoStmt - This represents a direct goto.

IfStmt - This represents an if/then/else.

IndirectGotoStmt - This represents an indirect goto.

LabelStmt - Represents a label, which has a substatement.

A C++ lambda expression, which produces a function object (of unspecified type) that can be invoked l...

Represents Objective-C's collection statement.

ObjCMethodDecl - Represents an instance or class method declaration.

A class that does preorder or postorder depth-first traversal on the entire Clang AST and visits each...

ReturnStmt - This represents a return, optionally of an expression: return; return 4;.

This class handles loading and caching of source files into memory.

Stmt - This represents one statement.

SourceLocation getBeginLoc() const LLVM_READONLY

SwitchStmt - This represents a 'switch' stmt.

bool hasConstructorVariants() const

Does this ABI have different entrypoints for complete-object and base-subobject constructors?

TargetCXXABI getCXXABI() const

Get the C++ ABI currently in use.

The base class of the type hierarchy.

UnaryOperator - This represents the unary-expression's (except sizeof and alignof),...

WhileStmt - This represents a 'while' stmt.

@ Type

The l-value was considered opaque, so the alignment was determined from a type.

bool LE(InterpState &S, CodePtr OpPC)

The JSON file list parser is used to communicate input to InstallAPI.

@ Ctor_Base

Base object ctor.

@ If

'if' clause, allowed on all the Compute Constructs, Data Constructs, Executable Constructs,...

Linkage

Describes the different kinds of linkage (C++ [basic.link], C99 6.2.2) that an entity may have.

@ Result

The result type of a method or function.

@ Dtor_Base

Base object dtor.

void finalize(TemplateInstantiationCallbackPtrs &Callbacks, const Sema &TheSema)

@ None

The alignment was not explicit in code.

cl::opt< bool > SystemHeadersCoverage

Diagnostic wrappers for TextAPI types for error reporting.

cl::opt< bool > EnableSingleByteCoverage

Per-Function MC/DC state.

llvm::DenseMap< const Stmt *, Decision > DecisionByStmt