LLVM: lib/Transforms/Utils/Debugify.cpp Source File (original) (raw)

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

30#include

31

32#define DEBUG_TYPE "debugify"

33

34using namespace llvm;

35

36namespace {

37

39 cl::desc("Suppress verbose debugify output"));

40

42 "debugify-func-limit",

43 cl::desc("Set max number of processed functions per pass."),

45

46enum class Level {

47 Locations,

48 LocationsAndVariables

49};

50

52 "debugify-level", cl::desc("Kind of debug info to add"),

54 clEnumValN(Level::LocationsAndVariables, "location+variables",

55 "Locations and Variables")),

56 cl::init(Level::LocationsAndVariables));

57

59

61 return Ty->isSized() ? M.getDataLayout().getTypeAllocSizeInBits(Ty) : 0;

62}

63

64bool isFunctionSkipped(Function &F) {

65 return F.isDeclaration() || F.hasExactDefinition();

66}

67

68

69

70

71

74 return I;

76 return I;

78}

79}

80

84

85 if (M.getNamedMetadata("llvm.dbg.cu")) {

86 dbg() << Banner << "Skipping module with debug info\n";

87 return false;

88 }

89

93

94

96 auto getCachedDIType = [&](Type *Ty) -> DIType * {

99 if (!DTy) {

100 std::string Name = "ty" + utostr(Size);

102 }

103 return DTy;

104 };

105

106 unsigned NextLine = 1;

107 unsigned NextVar = 1;

110 true, "", 0);

111

112

114 if (isFunctionSkipped(F))

115 continue;

116

117 bool InsertedDbgVal = false;

120 DISubprogram::SPFlagDefinition | DISubprogram::SPFlagOptimized;

121 if (F.hasPrivateLinkage() || F.hasInternalLinkage())

122 SPFlags |= DISubprogram::SPFlagLocalToUnit;

123 auto SP = DIB.createFunction(CU, F.getName(), F.getName(), File, NextLine,

124 SPType, NextLine, DINode::FlagZero, SPFlags);

125 F.setSubprogram(SP);

126

127

128

129 auto insertDbgVal = [&](Instruction &TemplateInst,

131 std::string Name = utostr(NextVar++);

132 Value *V = &TemplateInst;

134 V = ConstantInt::get(Int32Ty, 0);

137 getCachedDIType(V->getType()),

138 true);

139 DIB.insertDbgValueIntrinsic(V, LocalVar, DIB.createExpression(), Loc,

140 InsertBefore);

141 };

142

144

146 I.setDebugLoc(DILocation::get(Ctx, NextLine++, 1, SP));

147

148 if (DebugifyLevel < Level::LocationsAndVariables)

149 continue;

150

151

152 if (BB.isEHPad())

153 continue;

154

155

156

157 Instruction *LastInst = findTerminatingInstruction(BB);

158 assert(LastInst && "Expected basic block with a terminator");

159

160

161

163 assert(InsertPt != BB.end() && "Expected to find an insertion point");

165

166

167 for (Instruction *I = &*BB.begin(); I != LastInst; I = I->getNextNode()) {

168

169 if (I->getType()->isVoidTy())

170 continue;

171

172

173

174 if (!isa(I) && I->isEHPad())

175 InsertBefore = I->getNextNode();

176

177 insertDbgVal(*I, InsertBefore);

178 InsertedDbgVal = true;

179 }

180 }

181

182

183

184

185

186 if (DebugifyLevel == Level::LocationsAndVariables && !InsertedDbgVal) {

187 auto *Term = findTerminatingInstruction(F.getEntryBlock());

188 insertDbgVal(*Term, Term);

189 }

190 if (ApplyToMF)

191 ApplyToMF(DIB, F);

193 }

195

196

197 NamedMDNode *NMD = M.getOrInsertNamedMetadata("llvm.debugify");

198 auto addDebugifyOperand = [&](unsigned N) {

201 };

202 addDebugifyOperand(NextLine - 1);

203 addDebugifyOperand(NextVar - 1);

205 "llvm.debugify should have exactly 2 operands!");

206

207

208 StringRef DIVersionKey = "Debug Info Version";

209 if (M.getModuleFlag(DIVersionKey))

211

212 return true;

213}

214

215static bool

219 StringRef NameOfWrappedPass = "") {

220 Module &M = *F.getParent();

221 auto FuncIt = F.getIterator();

224 "FunctionDebugify: ", nullptr);

225 assert(DebugInfoBeforePass);

227 "FunctionDebugify (original debuginfo)",

228 NameOfWrappedPass);

229}

230

231static bool

235 StringRef NameOfWrappedPass = "") {

238 "ModuleDebugify: ", nullptr);

240 "ModuleDebugify (original debuginfo)",

241 NameOfWrappedPass);

242}

243

245 bool Changed = false;

246

247

248 NamedMDNode *DebugifyMD = M.getNamedMetadata("llvm.debugify");

249 if (DebugifyMD) {

250 M.eraseNamedMetadata(DebugifyMD);

251 Changed = true;

252 }

253

254 if (auto *MIRDebugifyMD = M.getNamedMetadata("llvm.mir.debugify")) {

255 M.eraseNamedMetadata(MIRDebugifyMD);

256 Changed = true;

257 }

258

259

260

262

263

264 Function *DbgValF = M.getFunction("llvm.dbg.value");

265 if (DbgValF) {

267 "Not all debug info stripped?");

269 Changed = true;

270 }

271

272

273

274 NamedMDNode *NMD = M.getModuleFlagsMetadata();

275 if (!NMD)

276 return Changed;

279 for (MDNode *Flag : Flags) {

280 auto *Key = cast(Flag->getOperand(1));

281 if (Key->getString() == "Debug Info Version") {

282 Changed = true;

283 continue;

284 }

286 }

287

290

291 return Changed;

292}

293

299 LLVM_DEBUG(dbgs() << Banner << ": (before) " << NameOfWrappedPass << '\n');

300

301 if (!M.getNamedMetadata("llvm.dbg.cu")) {

302 dbg() << Banner << ": Skipping module without debug info\n";

303 return false;

304 }

305

307

309

311 continue;

312

313 if (isFunctionSkipped(F))

314 continue;

315

316

317 if (++FunctionsCnt >= DebugifyFunctionsLimit)

318 break;

319

320 auto *SP = F.getSubprogram();

322 if (SP) {

323 LLVM_DEBUG(dbgs() << " Collecting subprogram: " << *SP << '\n');

324 for (const DINode *DN : SP->getRetainedNodes()) {

325 if (const auto *DV = dyn_cast(DN)) {

327 }

328 }

329 }

330

332

334

335 if (isa(I))

336 continue;

337

338

339 if (DebugifyLevel > Level::Locations) {

340 auto HandleDbgVariable = [&](auto *DbgVar) {

341 if (!SP)

342 return;

343

344 if (DbgVar->getDebugLoc().getInlinedAt())

345 return;

346

347 if (DbgVar->isKillLocation())

348 return;

349

350 auto *Var = DbgVar->getVariable();

352 };

354 HandleDbgVariable(&DVR);

355 if (auto *DVI = dyn_cast(&I))

356 HandleDbgVariable(DVI);

357 }

358

359

360 if (isa(&I))

361 continue;

362

363 LLVM_DEBUG(dbgs() << " Collecting info for inst: " << I << '\n');

365

366 const DILocation *Loc = I.getDebugLoc().get();

367 bool HasLoc = Loc != nullptr;

369 }

370 }

371 }

372

373 return true;

374}

375

376

380 StringRef FileNameFromCU, bool ShouldWriteIntoJSON,

382 bool Preserved = true;

383 for (const auto &F : DIFunctionsAfter) {

384 if (F.second)

385 continue;

386 auto SPIt = DIFunctionsBefore.find(F.first);

387 if (SPIt == DIFunctionsBefore.end()) {

388 if (ShouldWriteIntoJSON)

390 {"name", F.first->getName()},

391 {"action", "not-generate"}}));

392 else

393 dbg() << "ERROR: " << NameOfWrappedPass

394 << " did not generate DISubprogram for " << F.first->getName()

395 << " from " << FileNameFromCU << '\n';

396 Preserved = false;

397 } else {

398 auto SP = SPIt->second;

399 if (!SP)

400 continue;

401

402

403 if (ShouldWriteIntoJSON)

405 {"name", F.first->getName()},

406 {"action", "drop"}}));

407 else

408 dbg() << "ERROR: " << NameOfWrappedPass << " dropped DISubprogram of "

409 << F.first->getName() << " from " << FileNameFromCU << '\n';

410 Preserved = false;

411 }

412 }

413

414 return Preserved;

415}

416

417

418

424 bool ShouldWriteIntoJSON,

426 bool Preserved = true;

427 for (const auto &L : DILocsAfter) {

428 if (L.second)

429 continue;

430 auto Instr = L.first;

431

432

433

434 auto WeakInstrPtr = InstToDelete.find(Instr);

435 if (WeakInstrPtr != InstToDelete.end() && !WeakInstrPtr->second)

436 continue;

437

438 auto FnName = Instr->getFunction()->getName();

439 auto BB = Instr->getParent();

440 auto BBName = BB->hasName() ? BB->getName() : "no-name";

442

443 auto InstrIt = DILocsBefore.find(Instr);

444 if (InstrIt == DILocsBefore.end()) {

445 if (ShouldWriteIntoJSON)

447 {"fn-name", FnName.str()},

448 {"bb-name", BBName.str()},

449 {"instr", InstName},

450 {"action", "not-generate"}}));

451 else

452 dbg() << "WARNING: " << NameOfWrappedPass

453 << " did not generate DILocation for " << *Instr

454 << " (BB: " << BBName << ", Fn: " << FnName

455 << ", File: " << FileNameFromCU << ")\n";

456 Preserved = false;

457 } else {

458 if (!InstrIt->second)

459 continue;

460

461

462 if (ShouldWriteIntoJSON)

464 {"fn-name", FnName.str()},

465 {"bb-name", BBName.str()},

466 {"instr", InstName},

467 {"action", "drop"}}));

468 else

469 dbg() << "WARNING: " << NameOfWrappedPass << " dropped DILocation of "

470 << *Instr << " (BB: " << BBName << ", Fn: " << FnName

471 << ", File: " << FileNameFromCU << ")\n";

472 Preserved = false;

473 }

474 }

475

476 return Preserved;

477}

478

479

484 bool Preserved = true;

485 for (const auto &V : DIVarsBefore) {

486 auto VarIt = DIVarsAfter.find(V.first);

487 if (VarIt == DIVarsAfter.end())

488 continue;

489

490 unsigned NumOfDbgValsAfter = VarIt->second;

491

492 if (V.second > NumOfDbgValsAfter) {

493 if (ShouldWriteIntoJSON)

495 {{"metadata", "dbg-var-intrinsic"},

496 {"name", V.first->getName()},

498 {"action", "drop"}}));

499 else

500 dbg() << "WARNING: " << NameOfWrappedPass

501 << " drops dbg.value()/dbg.declare() for " << V.first->getName()

502 << " from "

503 << "function " << V.first->getScope()->getSubprogram()->getName()

504 << " (file " << FileNameFromCU << ")\n";

505 Preserved = false;

506 }

507 }

508

509 return Preserved;

510}

511

512

516 std::error_code EC;

517 raw_fd_ostream OS_FILE{OrigDIVerifyBugsReportFilePath, EC,

519 if (EC) {

520 errs() << "Could not open file: " << EC.message() << ", "

521 << OrigDIVerifyBugsReportFilePath << '\n';

522 return;

523 }

524

525 if (auto L = OS_FILE.lock()) {

526 OS_FILE << "{\"file\":\"" << FileNameFromCU << "\", ";

527

529 NameOfWrappedPass != "" ? NameOfWrappedPass : "no-name";

530 OS_FILE << "\"pass\":\"" << PassName << "\", ";

531

533 OS_FILE << "\"bugs\": " << BugsToPrint;

534

535 OS_FILE << "}\n";

536 }

537 OS_FILE.close();

538}

539

544 StringRef OrigDIVerifyBugsReportFilePath) {

545 LLVM_DEBUG(dbgs() << Banner << ": (after) " << NameOfWrappedPass << '\n');

546

547 if (!M.getNamedMetadata("llvm.dbg.cu")) {

548 dbg() << Banner << ": Skipping module without debug info\n";

549 return false;

550 }

551

552

554

555

557 if (isFunctionSkipped(F))

558 continue;

559

560

562 continue;

563

564

565 auto *SP = F.getSubprogram();

567

568 if (SP) {

569 LLVM_DEBUG(dbgs() << " Collecting subprogram: " << *SP << '\n');

570 for (const DINode *DN : SP->getRetainedNodes()) {

571 if (const auto *DV = dyn_cast(DN)) {

573 }

574 }

575 }

576

578

580

581 if (isa(I))

582 continue;

583

584

585 if (DebugifyLevel > Level::Locations) {

586 auto HandleDbgVariable = [&](auto *DbgVar) {

587 if (!SP)

588 return;

589

590 if (DbgVar->getDebugLoc().getInlinedAt())

591 return;

592

593 if (DbgVar->isKillLocation())

594 return;

595

596 auto *Var = DbgVar->getVariable();

598 };

600 HandleDbgVariable(&DVR);

601 if (auto *DVI = dyn_cast(&I))

602 HandleDbgVariable(DVI);

603 }

604

605

606 if (isa(&I))

607 continue;

608

609 LLVM_DEBUG(dbgs() << " Collecting info for inst: " << I << '\n');

610

611 const DILocation *Loc = I.getDebugLoc().get();

612 bool HasLoc = Loc != nullptr;

613

615 }

616 }

617 }

618

619

621 (cast(M.getNamedMetadata("llvm.dbg.cu")->getOperand(0)))

623

624 auto DIFunctionsBefore = DebugInfoBeforePass.DIFunctions;

625 auto DIFunctionsAfter = DebugInfoAfterPass.DIFunctions;

626

627 auto DILocsBefore = DebugInfoBeforePass.DILocations;

628 auto DILocsAfter = DebugInfoAfterPass.DILocations;

629

630 auto InstToDelete = DebugInfoBeforePass.InstToDelete;

631

632 auto DIVarsBefore = DebugInfoBeforePass.DIVariables;

633 auto DIVarsAfter = DebugInfoAfterPass.DIVariables;

634

635 bool ShouldWriteIntoJSON = !OrigDIVerifyBugsReportFilePath.empty();

637

638 bool ResultForFunc =

639 checkFunctions(DIFunctionsBefore, DIFunctionsAfter, NameOfWrappedPass,

640 FileNameFromCU, ShouldWriteIntoJSON, Bugs);

642 DILocsBefore, DILocsAfter, InstToDelete, NameOfWrappedPass,

643 FileNameFromCU, ShouldWriteIntoJSON, Bugs);

644

645 bool ResultForVars = checkVars(DIVarsBefore, DIVarsAfter, NameOfWrappedPass,

646 FileNameFromCU, ShouldWriteIntoJSON, Bugs);

647

648 bool Result = ResultForFunc && ResultForInsts && ResultForVars;

649

650 StringRef ResultBanner = NameOfWrappedPass != "" ? NameOfWrappedPass : Banner;

651 if (ShouldWriteIntoJSON && !Bugs.empty())

652 writeJSON(OrigDIVerifyBugsReportFilePath, FileNameFromCU, NameOfWrappedPass,

653 Bugs);

654

655 if (Result)

656 dbg() << ResultBanner << ": PASS\n";

657 else

658 dbg() << ResultBanner << ": FAIL\n";

659

660

661

662

663 DebugInfoBeforePass = DebugInfoAfterPass;

664

666 return Result;

667}

668

669namespace {

670

671template

672bool diagnoseMisSizedDbgValue(Module &M, DbgValTy *DbgVal) {

673

674

675

676

677

678

679

680

681 if (DbgVal->getExpression()->getNumElements())

682 return false;

683

684 Value *V = DbgVal->getVariableLocationOp(0);

685 if (!V)

686 return false;

687

688 Type *Ty = V->getType();

689 uint64_t ValueOperandSize = getAllocSizeInBits(M, Ty);

690 std::optional<uint64_t> DbgVarSize = DbgVal->getFragmentSizeInBits();

691 if (!ValueOperandSize || !DbgVarSize)

692 return false;

693

694 bool HasBadSize = false;

696 auto Signedness = DbgVal->getVariable()->getSignedness();

697 if (Signedness && *Signedness == DIBasicType::Signedness::Signed)

698 HasBadSize = ValueOperandSize < *DbgVarSize;

699 } else {

700 HasBadSize = ValueOperandSize != *DbgVarSize;

701 }

702

703 if (HasBadSize) {

704 dbg() << "ERROR: dbg.value operand has size " << ValueOperandSize

705 << ", but its variable has size " << *DbgVarSize << ": ";

706 DbgVal->print(dbg());

707 dbg() << "\n";

708 }

709 return HasBadSize;

710}

711

712bool checkDebugifyMetadata(Module &M,

716

717 NamedMDNode *NMD = M.getNamedMetadata("llvm.debugify");

718 if (!NMD) {

719 dbg() << Banner << ": Skipping module without debugify metadata\n";

720 return false;

721 }

722

723 auto getDebugifyOperand = [&](unsigned Idx) -> unsigned {

725 ->getZExtValue();

726 };

728 "llvm.debugify should have exactly 2 operands!");

729 unsigned OriginalNumLines = getDebugifyOperand(0);

730 unsigned OriginalNumVars = getDebugifyOperand(1);

731 bool HasErrors = false;

732

733

735 if (StatsMap && !NameOfWrappedPass.empty())

736 Stats = &StatsMap->operator[](NameOfWrappedPass);

737

738 BitVector MissingLines{OriginalNumLines, true};

739 BitVector MissingVars{OriginalNumVars, true};

741 if (isFunctionSkipped(F))

742 continue;

743

744

746 if (isa(&I))

747 continue;

748

749 auto DL = I.getDebugLoc();

750 if (DL && DL.getLine() != 0) {

751 MissingLines.reset(DL.getLine() - 1);

752 continue;

753 }

754

755 if (!isa(&I) && DL) {

756 dbg() << "WARNING: Instruction with empty DebugLoc in function ";

757 dbg() << F.getName() << " --";

758 I.print(dbg());

759 dbg() << "\n";

760 }

761 }

762

763

764 auto CheckForMisSized = [&](auto *DbgVal) {

765 unsigned Var = ~0U;

766 (void)to_integer(DbgVal->getVariable()->getName(), Var, 10);

767 assert(Var <= OriginalNumVars && "Unexpected name for DILocalVariable");

768 bool HasBadSize = diagnoseMisSizedDbgValue(M, DbgVal);

769 if (!HasBadSize)

770 MissingVars.reset(Var - 1);

771 HasErrors |= HasBadSize;

772 };

775 if (DVR.isDbgValue() || DVR.isDbgAssign())

776 CheckForMisSized(&DVR);

777 auto *DVI = dyn_cast(&I);

778 if (!DVI)

779 continue;

780 CheckForMisSized(DVI);

781 }

782 }

783

784

785 for (unsigned Idx : MissingLines.set_bits())

786 dbg() << "WARNING: Missing line " << Idx + 1 << "\n";

787

788 for (unsigned Idx : MissingVars.set_bits())

789 dbg() << "WARNING: Missing variable " << Idx + 1 << "\n";

790

791

793 Stats->NumDbgLocsExpected += OriginalNumLines;

794 Stats->NumDbgLocsMissing += MissingLines.count();

795 Stats->NumDbgValuesExpected += OriginalNumVars;

796 Stats->NumDbgValuesMissing += MissingVars.count();

797 }

798

799 dbg() << Banner;

800 if (!NameOfWrappedPass.empty())

801 dbg() << " [" << NameOfWrappedPass << "]";

802 dbg() << ": " << (HasErrors ? "FAIL" : "PASS") << '\n';

803

804

805 bool Ret = false;

806 if (Strip)

808

809 return Ret;

810}

811

812

813

814struct DebugifyModulePass : public ModulePass {

817 applyDebugify(M, Mode, DebugInfoBeforePass, NameOfWrappedPass);

819 }

820

821 DebugifyModulePass(enum DebugifyMode Mode = DebugifyMode::SyntheticDebugInfo,

822 StringRef NameOfWrappedPass = "",

824 : ModulePass(ID), NameOfWrappedPass(NameOfWrappedPass),

825 DebugInfoBeforePass(DebugInfoBeforePass), Mode(Mode) {}

826

829 }

830

831 static char ID;

832

833private:

837};

838

839

840

841struct DebugifyFunctionPass : public FunctionPass {

844 applyDebugify(F, Mode, DebugInfoBeforePass, NameOfWrappedPass);

846 }

847

848 DebugifyFunctionPass(

849 enum DebugifyMode Mode = DebugifyMode::SyntheticDebugInfo,

850 StringRef NameOfWrappedPass = "",

852 : FunctionPass(ID), NameOfWrappedPass(NameOfWrappedPass),

853 DebugInfoBeforePass(DebugInfoBeforePass), Mode(Mode) {}

854

857 }

858

859 static char ID;

860

861private:

865};

866

867

868

869struct CheckDebugifyModulePass : public ModulePass {

872 if (Mode == DebugifyMode::SyntheticDebugInfo)

873 Result = checkDebugifyMetadata(M, M.functions(), NameOfWrappedPass,

874 "CheckModuleDebugify", Strip, StatsMap);

875 else

877 M, M.functions(), *DebugInfoBeforePass,

878 "CheckModuleDebugify (original debuginfo)", NameOfWrappedPass,

879 OrigDIVerifyBugsReportFilePath);

880

882 }

883

884 CheckDebugifyModulePass(

885 bool Strip = false, StringRef NameOfWrappedPass = "",

887 enum DebugifyMode Mode = DebugifyMode::SyntheticDebugInfo,

889 StringRef OrigDIVerifyBugsReportFilePath = "")

890 : ModulePass(ID), NameOfWrappedPass(NameOfWrappedPass),

891 OrigDIVerifyBugsReportFilePath(OrigDIVerifyBugsReportFilePath),

892 StatsMap(StatsMap), DebugInfoBeforePass(DebugInfoBeforePass), Mode(Mode),

893 Strip(Strip) {}

894

897 }

898

899 static char ID;

900

901private:

903 StringRef OrigDIVerifyBugsReportFilePath;

907 bool Strip;

908};

909

910

911

912struct CheckDebugifyFunctionPass : public FunctionPass {

915 auto FuncIt = F.getIterator();

917 if (Mode == DebugifyMode::SyntheticDebugInfo)

918 Result = checkDebugifyMetadata(M, make_range(FuncIt, std::next(FuncIt)),

919 NameOfWrappedPass, "CheckFunctionDebugify",

920 Strip, StatsMap);

921 else

923 M, make_range(FuncIt, std::next(FuncIt)), *DebugInfoBeforePass,

924 "CheckFunctionDebugify (original debuginfo)", NameOfWrappedPass,

925 OrigDIVerifyBugsReportFilePath);

926

928 }

929

930 CheckDebugifyFunctionPass(

931 bool Strip = false, StringRef NameOfWrappedPass = "",

933 enum DebugifyMode Mode = DebugifyMode::SyntheticDebugInfo,

935 StringRef OrigDIVerifyBugsReportFilePath = "")

936 : FunctionPass(ID), NameOfWrappedPass(NameOfWrappedPass),

937 OrigDIVerifyBugsReportFilePath(OrigDIVerifyBugsReportFilePath),

938 StatsMap(StatsMap), DebugInfoBeforePass(DebugInfoBeforePass), Mode(Mode),

939 Strip(Strip) {}

940

943 }

944

945 static char ID;

946

947private:

949 StringRef OrigDIVerifyBugsReportFilePath;

953 bool Strip;

954};

955

956}

957

959 std::error_code EC;

961 if (EC) {

962 errs() << "Could not open file: " << EC.message() << ", " << Path << '\n';

963 return;

964 }

965

966 OS << "Pass Name" << ',' << "# of missing debug values" << ','

967 << "# of missing locations" << ',' << "Missing/Expected value ratio" << ','

968 << "Missing/Expected location ratio" << '\n';

969 for (const auto &Entry : Map) {

972

973 OS << Pass << ',' << Stats.NumDbgValuesMissing << ','

974 << Stats.NumDbgLocsMissing << ',' << Stats.getMissingValueRatio() << ','

975 << Stats.getEmptyLocationRatio() << '\n';

976 }

977}

978

983 return new DebugifyModulePass();

985 return new DebugifyModulePass(Mode, NameOfWrappedPass, DebugInfoBeforePass);

986}

987

993 return new DebugifyFunctionPass();

995 return new DebugifyFunctionPass(Mode, NameOfWrappedPass, DebugInfoBeforePass);

996}

997

999 if (Mode == DebugifyMode::SyntheticDebugInfo)

1001 "ModuleDebugify: ", nullptr);

1002 else

1004 "ModuleDebugify (original debuginfo)",

1005 NameOfWrappedPass);

1006

1009 return PA;

1010}

1011

1015 StringRef OrigDIVerifyBugsReportFilePath) {

1017 return new CheckDebugifyModulePass(Strip, NameOfWrappedPass, StatsMap);

1019 return new CheckDebugifyModulePass(false, NameOfWrappedPass, nullptr, Mode,

1020 DebugInfoBeforePass,

1021 OrigDIVerifyBugsReportFilePath);

1022}

1023

1027 StringRef OrigDIVerifyBugsReportFilePath) {

1029 return new CheckDebugifyFunctionPass(Strip, NameOfWrappedPass, StatsMap);

1031 return new CheckDebugifyFunctionPass(false, NameOfWrappedPass, nullptr, Mode,

1032 DebugInfoBeforePass,

1033 OrigDIVerifyBugsReportFilePath);

1034}

1035

1038 if (Mode == DebugifyMode::SyntheticDebugInfo)

1039 checkDebugifyMetadata(M, M.functions(), NameOfWrappedPass,

1040 "CheckModuleDebugify", Strip, StatsMap);

1041 else

1043 M, M.functions(), *DebugInfoBeforePass,

1044 "CheckModuleDebugify (original debuginfo)", NameOfWrappedPass,

1045 OrigDIVerifyBugsReportFilePath);

1046

1048}

1049

1051 return isSpecialPass(PassID, {"PassManager", "PassAdaptor",

1052 "AnalysisManagerProxy", "PrintFunctionPass",

1053 "PrintModulePass", "BitcodeWriterPass",

1054 "ThinLTOBitcodeWriterPass", "VerifierPass"});

1055}

1056

1061 return;

1064 if (const auto **CF = llvm::any_cast<const Function *>(&IR)) {

1068 .getManager()

1069 .invalidate(F, PA);

1070 } else if (const auto **CM = llvm::any_cast<const Module *>(&IR)) {

1074 }

1075 });

1079 return;

1082 if (const auto **CF = llvm::any_cast<const Function *>(&IR)) {

1083 auto &F = *const_cast<Function *>(*CF);

1084 Module &M = *F.getParent();

1085 auto It = F.getIterator();

1086 if (Mode == DebugifyMode::SyntheticDebugInfo)

1087 checkDebugifyMetadata(M, make_range(It, std::next(It)), P,

1088 "CheckFunctionDebugify", true,

1089 DIStatsMap);

1090 else

1092 *DebugInfoBeforePass,

1093 "CheckModuleDebugify (original debuginfo)",

1094 P, OrigDIVerifyBugsReportFilePath);

1096 .getManager()

1097 .invalidate(F, PA);

1098 } else if (const auto **CM = llvm::any_cast<const Module *>(&IR)) {

1100 if (Mode == DebugifyMode::SyntheticDebugInfo)

1101 checkDebugifyMetadata(M, M.functions(), P, "CheckModuleDebugify",

1102 true, DIStatsMap);

1103 else

1105 "CheckModuleDebugify (original debuginfo)",

1106 P, OrigDIVerifyBugsReportFilePath);

1108 }

1109 });

1110}

1111

1112char DebugifyModulePass::ID = 0;

1114 "Attach debug info to everything");

1115

1116char CheckDebugifyModulePass::ID = 0;

1118 CDM("check-debugify", "Check debug info from -debugify");

1119

1120char DebugifyFunctionPass::ID = 0;

1122 "Attach debug info to a function");

1123

1124char CheckDebugifyFunctionPass::ID = 0;

1126 CDF("check-debugify-function", "Check debug info from -debugify-function");

MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL

Expand Atomic instructions

This file implements the BitVector class.

#define clEnumValN(ENUMVAL, FLAGNAME, DESC)

static DISubprogram * getSubprogram(bool IsDistinct, Ts &&...Args)

Returns the sub type a function will return at a given Idx Should correspond to the result type of an ExtractValue instruction executed with just that one unsigned Idx

static RegisterPass< CheckDebugifyModulePass > CDM("check-debugify", "Check debug info from -debugify")

ModulePass * createDebugifyModulePass(enum DebugifyMode Mode, llvm::StringRef NameOfWrappedPass, DebugInfoPerPass *DebugInfoBeforePass)

FunctionPass * createDebugifyFunctionPass(enum DebugifyMode Mode, llvm::StringRef NameOfWrappedPass, DebugInfoPerPass *DebugInfoBeforePass)

static bool isIgnoredPass(StringRef PassID)

static bool applyDebugify(Function &F, enum DebugifyMode Mode=DebugifyMode::SyntheticDebugInfo, DebugInfoPerPass *DebugInfoBeforePass=nullptr, StringRef NameOfWrappedPass="")

ModulePass * createCheckDebugifyModulePass(bool Strip, StringRef NameOfWrappedPass, DebugifyStatsMap *StatsMap, enum DebugifyMode Mode, DebugInfoPerPass *DebugInfoBeforePass, StringRef OrigDIVerifyBugsReportFilePath)

static void writeJSON(StringRef OrigDIVerifyBugsReportFilePath, StringRef FileNameFromCU, StringRef NameOfWrappedPass, llvm::json::Array &Bugs)

static RegisterPass< DebugifyFunctionPass > DF("debugify-function", "Attach debug info to a function")

static RegisterPass< DebugifyModulePass > DM("debugify", "Attach debug info to everything")

static bool checkFunctions(const DebugFnMap &DIFunctionsBefore, const DebugFnMap &DIFunctionsAfter, StringRef NameOfWrappedPass, StringRef FileNameFromCU, bool ShouldWriteIntoJSON, llvm::json::Array &Bugs)

static RegisterPass< CheckDebugifyFunctionPass > CDF("check-debugify-function", "Check debug info from -debugify-function")

FunctionPass * createCheckDebugifyFunctionPass(bool Strip, StringRef NameOfWrappedPass, DebugifyStatsMap *StatsMap, enum DebugifyMode Mode, DebugInfoPerPass *DebugInfoBeforePass, StringRef OrigDIVerifyBugsReportFilePath)

static bool checkVars(const DebugVarMap &DIVarsBefore, const DebugVarMap &DIVarsAfter, StringRef NameOfWrappedPass, StringRef FileNameFromCU, bool ShouldWriteIntoJSON, llvm::json::Array &Bugs)

static bool checkInstructions(const DebugInstMap &DILocsBefore, const DebugInstMap &DILocsAfter, const WeakInstValueMap &InstToDelete, StringRef NameOfWrappedPass, StringRef FileNameFromCU, bool ShouldWriteIntoJSON, llvm::json::Array &Bugs)

DebugifyMode

Used to check whether we track synthetic or original debug info.

static SmallString< 128 > getFilename(const DISubprogram *SP)

Extract a filename for a DISubprogram.

Module.h This file contains the declarations for the Module class.

This file supports working with JSON data.

Legalize the Machine IR a function s Machine IR

block placement Basic Block Placement Stats

ModuleAnalysisManager MAM

PassInstrumentationCallbacks PIC

This file defines the Pass Instrumentation classes that provide instrumentation points into the pass ...

static StringRef getName(Value *V)

assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())

static const char PassName[]

llvm::PreservedAnalyses run(llvm::Module &M, llvm::ModuleAnalysisManager &AM)

llvm::PreservedAnalyses run(llvm::Module &M, llvm::ModuleAnalysisManager &AM)

A container for analyses that lazily runs them and caches their results.

void invalidate(IRUnitT &IR, const PreservedAnalyses &PA)

Invalidate cached analyses for an IR unit.

PassT::Result & getResult(IRUnitT &IR, ExtraArgTs... ExtraArgs)

Get the result of an analysis pass for a given IR unit.

Represent the analysis usage information of a pass.

void setPreservesAll()

Set by analyses that do not transform their input at all.

LLVM Basic Block Representation.

const CallInst * getTerminatingDeoptimizeCall() const

Returns the call instruction calling @llvm.experimental.deoptimize prior to the terminating return in...

InstListType::iterator iterator

Instruction iterators...

const Instruction * getTerminator() const LLVM_READONLY

Returns the terminator instruction if the block is well formed or null if the block is not well forme...

const CallInst * getTerminatingMustTailCall() const

Returns the call instruction marked 'musttail' prior to the terminating return instruction of this ba...

Represents analyses that only rely on functions' control flow.

void finalize()

Construct any deferred debug info descriptors.

DISubroutineType * createSubroutineType(DITypeRefArray ParameterTypes, DINode::DIFlags Flags=DINode::FlagZero, unsigned CC=0)

Create subroutine type.

void finalizeSubprogram(DISubprogram *SP)

Finalize a specific subprogram - no new variables may be added to this subprogram afterwards.

DICompileUnit * createCompileUnit(unsigned Lang, DIFile *File, StringRef Producer, bool isOptimized, StringRef Flags, unsigned RV, StringRef SplitName=StringRef(), DICompileUnit::DebugEmissionKind Kind=DICompileUnit::DebugEmissionKind::FullDebug, uint64_t DWOId=0, bool SplitDebugInlining=true, bool DebugInfoForProfiling=false, DICompileUnit::DebugNameTableKind NameTableKind=DICompileUnit::DebugNameTableKind::Default, bool RangesBaseAddress=false, StringRef SysRoot={}, StringRef SDK={})

A CompileUnit provides an anchor for all debugging information generated during this instance of comp...

DISubprogram * createFunction(DIScope *Scope, StringRef Name, StringRef LinkageName, DIFile *File, unsigned LineNo, DISubroutineType *Ty, unsigned ScopeLine, DINode::DIFlags Flags=DINode::FlagZero, DISubprogram::DISPFlags SPFlags=DISubprogram::SPFlagZero, DITemplateParameterArray TParams=nullptr, DISubprogram *Decl=nullptr, DITypeArray ThrownTypes=nullptr, DINodeArray Annotations=nullptr, StringRef TargetFuncName="")

Create a new descriptor for the specified subprogram.

DIBasicType * createBasicType(StringRef Name, uint64_t SizeInBits, unsigned Encoding, DINode::DIFlags Flags=DINode::FlagZero, uint32_t NumExtraInhabitants=0)

Create debugging information entry for a basic type.

DITypeRefArray getOrCreateTypeArray(ArrayRef< Metadata * > Elements)

Get a DITypeRefArray, create one if required.

DIExpression * createExpression(ArrayRef< uint64_t > Addr={})

Create a new descriptor for the specified variable which has a complex address expression for its add...

DILocalVariable * createAutoVariable(DIScope *Scope, StringRef Name, DIFile *File, unsigned LineNo, DIType *Ty, bool AlwaysPreserve=false, DINode::DIFlags Flags=DINode::FlagZero, uint32_t AlignInBits=0)

Create a new descriptor for an auto variable.

DIFile * createFile(StringRef Filename, StringRef Directory, std::optional< DIFile::ChecksumInfo< StringRef > > Checksum=std::nullopt, std::optional< StringRef > Source=std::nullopt)

Create a file descriptor to hold debugging information for a file.

Tagged DWARF-like metadata node.

DISPFlags

Debug info subprogram flags.

Record of a variable value-assignment, aka a non instruction representation of the dbg....

DILocation * get() const

Get the underlying DILocation.

void registerCallbacks(PassInstrumentationCallbacks &PIC, ModuleAnalysisManager &MAM)

FunctionPass class - This class is used to implement most global optimizations.

virtual bool runOnFunction(Function &F)=0

runOnFunction - Virtual method overriden by subclasses to do the per-function processing of the pass.

void eraseFromParent()

eraseFromParent - This method unlinks 'this' from the containing module and deletes it.

bool isDeclaration() const

Return true if the primary definition of this global value is outside of the current translation unit...

An analysis over an "outer" IR unit that provides access to an analysis manager over an "inner" IR un...

const DebugLoc & getDebugLoc() const

Return the debug location for this node as a DebugLoc.

const char * getOpcodeName() const

This is an important class for using LLVM in a threaded context.

const MDOperand & getOperand(unsigned I) const

static MDTuple * get(LLVMContext &Context, ArrayRef< Metadata * > MDs)

size_type count(const KeyT &Key) const

iterator find(const KeyT &Key)

std::pair< iterator, bool > insert(const std::pair< KeyT, ValueT > &KV)

ModulePass class - This class is used to implement unstructured interprocedural optimizations and ana...

virtual bool runOnModule(Module &M)=0

runOnModule - Virtual method overriden by subclasses to process the module being operated on.

A Module instance is used to store all the information related to an LLVM module.

@ Warning

Emits a warning if two values disagree.

void eraseFromParent()

Drop all references and remove the node from parent module.

MDNode * getOperand(unsigned i) const

unsigned getNumOperands() const

void clearOperands()

Drop all references to this node's operands.

iterator_range< op_iterator > operands()

void addOperand(MDNode *M)

Pass interface - Implemented by all 'passes'.

virtual void getAnalysisUsage(AnalysisUsage &) const

getAnalysisUsage - This function should be overriden by passes that need analysis information to do t...

A set of analyses that are preserved following a run of a transformation pass.

static PreservedAnalyses all()

Construct a special preserved set that preserves all passes.

void preserveSet()

Mark an analysis set as preserved.

This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.

StringRef - Represent a constant reference to a string, i.e.

constexpr bool empty() const

empty - Check if the string is empty.

The instances of the Type class are immutable: once they are created, they are never changed.

bool isSized(SmallPtrSetImpl< Type * > *Visited=nullptr) const

Return true if it makes sense to take the size of this type.

static IntegerType * getInt32Ty(LLVMContext &C)

bool isIntegerTy() const

True if this is an instance of IntegerType.

bool isVoidTy() const

Return true if this is 'void'.

LLVM Value Representation.

Type * getType() const

All values are typed, get the type of this value.

A range adaptor for a pair of iterators.

An Array is a JSON array, which contains heterogeneous JSON values.

void push_back(const Value &E)

An Object is a JSON object, which maps strings to heterogenous JSON values.

A Value is an JSON value of unknown type.

A raw_ostream that writes to a file descriptor.

This class implements an extremely fast bulk output stream that can only output to a stream.

unsigned ID

LLVM IR allows to use arbitrary numbers as calling convention identifiers.

ValuesClass values(OptsTy... Options)

Helper to build a ValuesClass by forwarding a variable number of arguments as an initializer list to ...

initializer< Ty > init(const Ty &Val)

@ OF_TextWithCRLF

The file should be opened in text mode and use a carriage linefeed '\r '.

@ OF_Append

The file should be opened in append mode.

This is an optimization pass for GlobalISel generic memory operations.

bool applyDebugifyMetadata(Module &M, iterator_range< Module::iterator > Functions, StringRef Banner, std::function< bool(DIBuilder &, Function &)> ApplyToMF)

Add synthesized debug information to a module.

iterator_range< T > make_range(T x, T y)

Convenience function for iterating over sub-ranges.

bool stripDebugifyMetadata(Module &M)

Strip out all of the metadata and debug info inserted by debugify.

void exportDebugifyStats(StringRef Path, const DebugifyStatsMap &Map)

bool collectDebugInfoMetadata(Module &M, iterator_range< Module::iterator > Functions, DebugInfoPerPass &DebugInfoBeforePass, StringRef Banner, StringRef NameOfWrappedPass)

Collect original debug information before a pass.

bool checkDebugInfoMetadata(Module &M, iterator_range< Module::iterator > Functions, DebugInfoPerPass &DebugInfoBeforePass, StringRef Banner, StringRef NameOfWrappedPass, StringRef OrigDIVerifyBugsReportFilePath)

Check original debug information after a pass.

raw_ostream & dbgs()

dbgs() - This returns a reference to a raw_ostream for debugging messages.

bool isSpecialPass(StringRef PassID, const std::vector< StringRef > &Specials)

raw_ostream & nulls()

This returns a reference to a raw_ostream which simply discards output.

raw_fd_ostream & errs()

This returns a reference to a raw_ostream for standard error.

bool StripDebugInfo(Module &M)

Strip debug info in the module if it exists.

static auto filterDbgVars(iterator_range< simple_ilist< DbgRecord >::iterator > R)

Filter the DbgRecord range to DbgVariableRecord types only and downcast.

Used to track the Debug Info Metadata information.

WeakInstValueMap InstToDelete

Track how much debugify information (in the synthetic mode only) has been lost.

This class manages callbacks registration, as well as provides a way for PassInstrumentation to pass ...

void registerBeforeNonSkippedPassCallback(CallableT C)

void registerAfterPassCallback(CallableT C, bool ToFront=false)

RegisterPass template - This template class is used to notify the system that a Pass is available ...