LLVM: lib/CodeGen/AssignmentTrackingAnalysis.cpp Source File (original) (raw)

1

2

3

4

5

6

7

8

35#include <assert.h>

36#include

37#include

38#include

39#include

40#include <unordered_map>

41

42using namespace llvm;

43#define DEBUG_TYPE "debug-ata"

44

45STATISTIC(NumDefsScanned, "Number of dbg locs that get scanned for removal");

46STATISTIC(NumDefsRemoved, "Number of dbg locs removed");

47STATISTIC(NumWedgesScanned, "Number of dbg wedges scanned");

48STATISTIC(NumWedgesChanged, "Number of dbg wedges changed");

49

52 cl::desc("Maximum num basic blocks before debug info dropped"),

54

55

58

61

62

63

64

67

68

69

73 return static_cast<VariableID>(Wrapped::getEmptyKey());

74 }

76 return static_cast<VariableID>(Wrapped::getTombstoneKey());

77 }

79 return Wrapped::getHashValue(static_cast<unsigned>(Val));

80 }

82 return LHS == RHS;

83 }

84};

85

87

93

94

95

96

98 friend FunctionVarLocs;

100

101

102 std::unordered_map<VarLocInsertPt, SmallVector> VarLocsBeforeInst;

103

105

106public:

108

109

111 return static_cast<VariableID>(Variables.insert(V));

112 }

113

114

116 return Variables[static_cast<unsigned>(ID)];

117 }

118

119

120

122 auto R = VarLocsBeforeInst.find(Before);

123 if (R == VarLocsBeforeInst.end())

124 return nullptr;

125 return &R->second;

126 }

127

128

130 VarLocsBeforeInst[Before] = std::move(Wedge);

131 }

132

133

138 VarLoc.Expr = Expr;

139 VarLoc.DL = DL;

141 SingleLocVars.emplace_back(VarLoc);

142 }

143

144

149 VarLoc.Expr = Expr;

150 VarLoc.DL = DL;

152 VarLocsBeforeInst[Before].emplace_back(VarLoc);

153 }

154};

155

157

158

159 unsigned Counter = -1;

160 OS << "=== Variables ===\n";

162 ++Counter;

163

164 if (Counter == 0) {

165 continue;

166 }

167 OS << "[" << Counter << "] " << V.getVariable()->getName();

168 if (auto F = V.getFragment())

169 OS << " bits [" << F->OffsetInBits << ", "

170 << F->OffsetInBits + F->SizeInBits << ")";

171 if (const auto *IA = V.getInlinedAt())

172 OS << " inlined-at " << *IA;

173 OS << "\n";

174 }

175

177 OS << "DEF Var=[" << (unsigned)Loc.VariableID << "]"

178 << " Expr=" << *Loc.Expr << " Values=(";

179 for (auto *Op : Loc.Values.location_ops()) {

180 errs() << Op->getName() << " ";

181 }

182 errs() << ")\n";

183 };

184

185

186 OS << "=== Single location vars ===\n";

188 ++It) {

189 PrintLoc(*It);

190 }

191

192

193 OS << "=== In-line variable defs ===";

195 OS << "\n" << BB.getName() << ":\n";

198 PrintLoc(*It);

199 }

200 OS << I << "\n";

201 }

202 }

203}

204

206

207 for (const auto &VarLoc : Builder.SingleLocVars)

208 VarLocRecords.emplace_back(VarLoc);

209

210 SingleVarLocEnd = VarLocRecords.size();

211

212

213

214

215

216 for (auto &P : Builder.VarLocsBeforeInst) {

217

218

220 continue;

222 unsigned BlockStart = VarLocRecords.size();

223

224

225

227

228

229 auto It = Builder.VarLocsBeforeInst.find(&DVR);

230 if (It == Builder.VarLocsBeforeInst.end())

231 continue;

232 for (const VarLocInfo &VarLoc : It->second)

233 VarLocRecords.emplace_back(VarLoc);

234 }

235 for (const VarLocInfo &VarLoc : P.second)

236 VarLocRecords.emplace_back(VarLoc);

237 unsigned BlockEnd = VarLocRecords.size();

238

239 if (BlockEnd != BlockStart)

240 VarLocsBeforeInst[I] = {BlockStart, BlockEnd};

241 }

242

243

244 assert(Variables.empty() && "Expect clear before init");

245

246

247 Variables.reserve(Builder.Variables.size() + 1);

248 Variables.push_back(DebugVariable(nullptr, std::nullopt, nullptr));

249 Variables.append(Builder.Variables.begin(), Builder.Variables.end());

250}

251

253 Variables.clear();

254 VarLocRecords.clear();

255 VarLocsBeforeInst.clear();

256 SingleVarLocEnd = 0;

257}

258

259

260

261

262

263static std::pair<Value *, DIExpression *>

266 APInt OffsetInBytes(DL.getTypeSizeInBits(Start->getType()), false);

268 Start->stripAndAccumulateInBoundsConstantOffsets(DL, OffsetInBytes);

271 Ops = {dwarf::DW_OP_plus_uconst, OffsetInBytes.getZExtValue()};

273 Expression, Ops, false, false);

274 }

277}

278

279

280

281

282static std::optional<int64_t>

285 const unsigned NumElements = DIExpr->getNumElements();

286 const auto Elements = DIExpr->getElements();

287 unsigned ExpectedDerefIdx = 0;

288

289 if (NumElements > 2 && Elements[0] == dwarf::DW_OP_plus_uconst) {

290 Offset = Elements[1];

291 ExpectedDerefIdx = 2;

292 } else if (NumElements > 3 && Elements[0] == dwarf::DW_OP_constu) {

293 ExpectedDerefIdx = 3;

294 if (Elements[2] == dwarf::DW_OP_plus)

295 Offset = Elements[1];

296 else if (Elements[2] == dwarf::DW_OP_minus)

297 Offset = -Elements[1];

298 else

299 return std::nullopt;

300 }

301

302

303 if (ExpectedDerefIdx >= NumElements)

304 return std::nullopt;

305

306

307

308 if (Elements[ExpectedDerefIdx] != dwarf::DW_OP_deref)

309 return std::nullopt;

310

311

312 if (NumElements == ExpectedDerefIdx + 1)

313 return Offset;

314 unsigned ExpectedFragFirstIdx = ExpectedDerefIdx + 1;

315 unsigned ExpectedFragFinalIdx = ExpectedFragFirstIdx + 2;

316 if (NumElements == ExpectedFragFinalIdx + 1 &&

318 return Offset;

319

320

321 return std::nullopt;

322}

323

324

325using DebugAggregate = std::pair<const DILocalVariable *, const DILocation *>;

329

331

332

333

334

335

340 return true;

342 return false;

343 }

345}

346

347namespace {

348

349

350

351

352

353

354

355

356

357

358

359

360

361

362

363

364

365

366class MemLocFragmentFill {

368 FunctionVarLocsBuilder *FnVarLocs;

369 const DenseSet *VarsWithStackSlot;

370 bool CoalesceAdjacentFragments;

371

372

373 using BaseAddress = unsigned;

374 using OffsetInBitsTy = unsigned;

375 using FragTraits = IntervalMapHalfOpenInfo;

376 using FragsInMemMap = IntervalMap<

377 OffsetInBitsTy, BaseAddress,

378 IntervalMapImpl::NodeSizer<OffsetInBitsTy, BaseAddress>::LeafSize,

379 FragTraits>;

380 FragsInMemMap::Allocator IntervalMapAlloc;

381 using VarFragMap = DenseMap<unsigned, FragsInMemMap>;

382

383

384

385 UniqueVector Bases;

386 UniqueVector Aggregates;

387 DenseMap<const BasicBlock *, VarFragMap> LiveIn;

388 DenseMap<const BasicBlock *, VarFragMap> LiveOut;

389

390 struct FragMemLoc {

391 unsigned Var;

392 unsigned Base;

393 unsigned OffsetInBits;

394 unsigned SizeInBits;

396 };

397 using InsertMap = MapVector<VarLocInsertPt, SmallVector>;

398

399

400

401

402

403

404 DenseMap<const BasicBlock *, InsertMap> BBInsertBeforeMap;

405

406 static bool intervalMapsAreEqual(const FragsInMemMap &A,

407 const FragsInMemMap &B) {

408 auto AIt = A.begin(), AEnd = A.end();

409 auto BIt = B.begin(), BEnd = B.end();

410 for (; AIt != AEnd; ++AIt, ++BIt) {

411 if (BIt == BEnd)

412 return false;

413 if (AIt.start() != BIt.start() || AIt.stop() != BIt.stop())

414 return false;

415 if (*AIt != *BIt)

416 return false;

417 }

418

419 return BIt == BEnd;

420 }

421

422 static bool varFragMapsAreEqual(const VarFragMap &A, const VarFragMap &B) {

423 if (A.size() != B.size())

424 return false;

425 for (const auto &APair : A) {

426 auto BIt = B.find(APair.first);

427 if (BIt == B.end())

428 return false;

429 if (!intervalMapsAreEqual(APair.second, BIt->second))

430 return false;

431 }

432 return true;

433 }

434

435

436 std::string toString(unsigned BaseID) {

437 if (BaseID)

438 return Bases[BaseID].getVariableLocationOp(0)->getName().str();

439 else

440 return "None";

441 }

442

443

444 std::string toString(FragsInMemMap::const_iterator It, bool Newline = true) {

446 std::stringstream S(String);

447 if (It.valid()) {

448 S << "[" << It.start() << ", " << It.stop()

449 << "): " << toString(It.value());

450 } else {

451 S << "invalid iterator (end)";

452 }

453 if (Newline)

454 S << "\n";

455 return S.str();

456 };

457

458 FragsInMemMap meetFragments(const FragsInMemMap &A, const FragsInMemMap &B) {

459 FragsInMemMap Result(IntervalMapAlloc);

460 for (auto AIt = A.begin(), AEnd = A.end(); AIt != AEnd; ++AIt) {

462

463

464

465

466

467 if (B.overlaps(AIt.start(), AIt.stop()))

468 continue;

469

470

471 auto FirstOverlap = B.find(AIt.start());

472 assert(FirstOverlap != B.end());

473 bool IntersectStart = FirstOverlap.start() < AIt.start();

475 << ", IntersectStart: " << IntersectStart << "\n");

476

477

478 auto LastOverlap = B.find(AIt.stop());

479 bool IntersectEnd =

480 LastOverlap != B.end() && LastOverlap.start() < AIt.stop();

482 << ", IntersectEnd: " << IntersectEnd << "\n");

483

484

485 if (IntersectStart && IntersectEnd && FirstOverlap == LastOverlap) {

486

487

488

489

490

493 if (*AIt && *AIt == *FirstOverlap)

494 Result.insert(AIt.start(), AIt.stop(), *AIt);

495 } else {

496

497

498

499

500

501

502 auto Next = FirstOverlap;

503 if (IntersectStart) {

504 LLVM_DEBUG(dbgs() << "- insert intersection of a and "

506 if (*AIt && *AIt == *FirstOverlap)

507 Result.insert(AIt.start(), FirstOverlap.stop(), *AIt);

509 }

510

511

512

513

514 if (IntersectEnd) {

515 LLVM_DEBUG(dbgs() << "- insert intersection of a and "

517 if (*AIt && *AIt == *LastOverlap)

518 Result.insert(LastOverlap.start(), AIt.stop(), *AIt);

519 }

520

521

522

523

524

525

526

527 while (Next != B.end() && Next.start() < AIt.stop() &&

528 Next.stop() <= AIt.stop()) {

530 << "- insert intersection of a and " << toString(Next));

531 if (*AIt && *AIt == *Next)

534 }

535 }

536 }

538 }

539

540

541 void meetVars(VarFragMap &A, const VarFragMap &B) {

542

543

544

545 for (auto It = A.begin(), End = A.end(); It != End; ++It) {

546 unsigned AVar = It->first;

547 FragsInMemMap &AFrags = It->second;

548 auto BIt = B.find(AVar);

549 if (BIt == B.end()) {

550 A.erase(It);

551 continue;

552 }

554 << Aggregates[AVar].first->getName() << "\n");

555 AFrags = meetFragments(AFrags, BIt->second);

556 }

557 }

558

559 bool meet(const BasicBlock &BB,

560 const SmallPtrSet<BasicBlock *, 16> &Visited) {

562 << "\n");

563

564 VarFragMap BBLiveIn;

565 bool FirstMeet = true;

566

567

568 for (const BasicBlock *Pred : predecessors(&BB)) {

569

570

571

572 if (!Visited.count(Pred))

573 continue;

574

575 auto PredLiveOut = LiveOut.find(Pred);

576 assert(PredLiveOut != LiveOut.end());

577

578 if (FirstMeet) {

579 LLVM_DEBUG(dbgs() << "BBLiveIn = " << Pred->getName() << "\n");

580 BBLiveIn = PredLiveOut->second;

581 FirstMeet = false;

582 } else {

583 LLVM_DEBUG(dbgs() << "BBLiveIn = meet BBLiveIn, " << Pred->getName()

584 << "\n");

585 meetVars(BBLiveIn, PredLiveOut->second);

586 }

587

588

589

590

591 if (BBLiveIn.size() == 0)

592 break;

593 }

594

595

597 if (Inserted) {

599 << "\n");

600 CurrentLiveInEntry->second = std::move(BBLiveIn);

601 return true;

602 }

603

604

605

606 if (!varFragMapsAreEqual(BBLiveIn, CurrentLiveInEntry->second)) {

608 CurrentLiveInEntry->second = std::move(BBLiveIn);

609 return true;

610 }

611

613 return false;

614 }

615

616 void insertMemLoc(BasicBlock &BB, VarLocInsertPt Before, unsigned Var,

617 unsigned StartBit, unsigned EndBit, unsigned Base,

619 assert(StartBit < EndBit && "Cannot create fragment of size <= 0");

621 return;

622 FragMemLoc Loc;

623 Loc.Var = Var;

624 Loc.OffsetInBits = StartBit;

625 Loc.SizeInBits = EndBit - StartBit;

626 assert(Base && "Expected a non-zero ID for Base address");

627 Loc.Base = Base;

628 Loc.DL = DL;

629 BBInsertBeforeMap[&BB][Before].push_back(Loc);

631 << " bits [" << StartBit << ", " << EndBit << ")\n");

632 }

633

634

635

636

637

638 void coalesceFragments(BasicBlock &BB, VarLocInsertPt Before, unsigned Var,

639 unsigned StartBit, unsigned EndBit, unsigned Base,

640 DebugLoc DL, const FragsInMemMap &FragMap) {

641 if (!CoalesceAdjacentFragments)

642 return;

643

644

645

646

647

648 auto CoalescedFrag = FragMap.find(StartBit);

649

650 if (CoalescedFrag.start() == StartBit && CoalescedFrag.stop() == EndBit)

651 return;

652

653 LLVM_DEBUG(dbgs() << "- Insert loc for bits " << CoalescedFrag.start()

654 << " to " << CoalescedFrag.stop() << "\n");

655 insertMemLoc(BB, Before, Var, CoalescedFrag.start(), CoalescedFrag.stop(),

657 }

658

659 void addDef(const VarLocInfo &VarLoc, VarLocInsertPt Before, BasicBlock &BB,

660 VarFragMap &LiveSet) {

663 return;

664

665

666

668 return;

671

672

673 const DIExpression *DIExpr = VarLoc.Expr;

674 unsigned StartBit;

675 unsigned EndBit;

677 StartBit = Frag->OffsetInBits;

678 EndBit = StartBit + Frag->SizeInBits;

679 } else {

681 StartBit = 0;

683 }

684

685

686

687

688

689

690

691

693 const unsigned Base =

694 DerefOffsetInBytes && *DerefOffsetInBytes * 8 == StartBit

696 : 0;

698 << StartBit << ", " << EndBit << "): " << toString(Base)

699 << "\n");

700

701

702

703

704

705 auto FragIt = LiveSet.find(Var);

706

707

708 if (FragIt == LiveSet.end()) {

709

710 auto P = LiveSet.try_emplace(Var, FragsInMemMap(IntervalMapAlloc));

711 assert(P.second && "Var already in map?");

712

713 P.first->second.insert(StartBit, EndBit, Base);

714 return;

715 }

716

717

718 FragsInMemMap &FragMap = FragIt->second;

719

720

721 if (!FragMap.overlaps(StartBit, EndBit)) {

723 FragMap.insert(StartBit, EndBit, Base);

724 coalesceFragments(BB, Before, Var, StartBit, EndBit, Base, VarLoc.DL,

725 FragMap);

726 return;

727 }

728

729

730

731 auto FirstOverlap = FragMap.find(StartBit);

732 assert(FirstOverlap != FragMap.end());

733 bool IntersectStart = FirstOverlap.start() < StartBit;

734

735

736 auto LastOverlap = FragMap.find(EndBit);

737 bool IntersectEnd = LastOverlap.valid() && LastOverlap.start() < EndBit;

738

739

740 if (IntersectStart && IntersectEnd && FirstOverlap == LastOverlap) {

741 LLVM_DEBUG(dbgs() << "- Intersect single interval @ both ends\n");

742

743

744

745

746

747

748

749 auto EndBitOfOverlap = FirstOverlap.stop();

750 unsigned OverlapValue = FirstOverlap.value();

751

752

753 FirstOverlap.setStop(StartBit);

754 insertMemLoc(BB, Before, Var, FirstOverlap.start(), StartBit,

755 OverlapValue, VarLoc.DL);

756

757

758 FragMap.insert(EndBit, EndBitOfOverlap, OverlapValue);

759 insertMemLoc(BB, Before, Var, EndBit, EndBitOfOverlap, OverlapValue,

760 VarLoc.DL);

761

762

763 FragMap.insert(StartBit, EndBit, Base);

764 } else {

765

766

767

768

769

770

771

772

773 if (IntersectStart) {

774 LLVM_DEBUG(dbgs() << "- Intersect interval at start\n");

775

776 FirstOverlap.setStop(StartBit);

777 insertMemLoc(BB, Before, Var, FirstOverlap.start(), StartBit,

778 *FirstOverlap, VarLoc.DL);

779 }

780

781

782

783

784 if (IntersectEnd) {

785 LLVM_DEBUG(dbgs() << "- Intersect interval at end\n");

786

787 LastOverlap.setStart(EndBit);

788 insertMemLoc(BB, Before, Var, EndBit, LastOverlap.stop(), *LastOverlap,

789 VarLoc.DL);

790 }

791

792 LLVM_DEBUG(dbgs() << "- Erase intervals contained within\n");

793

794

795

796

797

798

799

800

801

802

803

804 auto It = FirstOverlap;

805 if (IntersectStart)

806 ++It;

807 while (It.valid() && It.start() >= StartBit && It.stop() <= EndBit) {

809 It.erase();

810 }

811

812 assert(!FragMap.overlaps(StartBit, EndBit));

813 LLVM_DEBUG(dbgs() << "- Insert DEF into now-empty space\n");

814 FragMap.insert(StartBit, EndBit, Base);

815 }

816

817 coalesceFragments(BB, Before, Var, StartBit, EndBit, Base, VarLoc.DL,

818 FragMap);

819 }

820

821 bool skipVariable(const DILocalVariable *V) { return V->getSizeInBits(); }

822

823 void process(BasicBlock &BB, VarFragMap &LiveSet) {

824 BBInsertBeforeMap[&BB].clear();

825 for (auto &I : BB) {

826 for (DbgVariableRecord &DVR : filterDbgVars(I.getDbgRecordRange())) {

827 if (const auto *Locs = FnVarLocs->getWedge(&DVR)) {

828 for (const VarLocInfo &Loc : *Locs) {

829 addDef(Loc, &DVR, *I.getParent(), LiveSet);

830 }

831 }

832 }

833 if (const auto *Locs = FnVarLocs->getWedge(&I)) {

834 for (const VarLocInfo &Loc : *Locs) {

835 addDef(Loc, &I, *I.getParent(), LiveSet);

836 }

837 }

838 }

839 }

840

841public:

842 MemLocFragmentFill(Function &Fn,

843 const DenseSet *VarsWithStackSlot,

844 bool CoalesceAdjacentFragments)

845 : Fn(Fn), VarsWithStackSlot(VarsWithStackSlot),

846 CoalesceAdjacentFragments(CoalesceAdjacentFragments) {}

847

848

849

850

851

852

853

854

855

856

857

858

859

860

861

862

863

864

865

866

867

868 void run(FunctionVarLocsBuilder *FnVarLocs) {

870 return;

871

872 this->FnVarLocs = FnVarLocs;

873

874

875

876 ReversePostOrderTraversal<Function *> RPOT(&Fn);

877 std::priority_queue<unsigned int, std::vector,

878 std::greater>

879 Worklist;

880 std::priority_queue<unsigned int, std::vector,

881 std::greater>

882 Pending;

883 DenseMap<unsigned int, BasicBlock *> OrderToBB;

884 DenseMap<BasicBlock *, unsigned int> BBToOrder;

885 {

886 unsigned int RPONumber = 0;

887 for (BasicBlock *BB : RPOT) {

888 OrderToBB[RPONumber] = BB;

889 BBToOrder[BB] = RPONumber;

890 Worklist.push(RPONumber);

891 ++RPONumber;

892 }

893 LiveIn.reserve(RPONumber);

894 LiveOut.reserve(RPONumber);

895 }

896

897

898

899

900

901

902

903

904

905

906 SmallPtrSet<BasicBlock *, 16> Visited;

907 while (!Worklist.empty() || !Pending.empty()) {

908

909

910

911 SmallPtrSet<BasicBlock *, 16> OnPending;

913 while (!Worklist.empty()) {

914 BasicBlock *BB = OrderToBB[Worklist.top()];

916 Worklist.pop();

917 bool InChanged = meet(*BB, Visited);

918

919 InChanged |= Visited.insert(BB).second;

920 if (InChanged) {

922 << BB->getName() << " has new InLocs, process it\n");

923

924

925

926 VarFragMap LiveSet = LiveIn[BB];

927

928

929 process(*BB, LiveSet);

930

931

932 if (!varFragMapsAreEqual(LiveOut[BB], LiveSet)) {

934 << " has new OutLocs, add succs to worklist: [ ");

935 LiveOut[BB] = std::move(LiveSet);

936 for (BasicBlock *Succ : successors(BB)) {

937 if (OnPending.insert(Succ).second) {

939 Pending.push(BBToOrder[Succ]);

940 }

941 }

943 }

944 }

945 }

946 Worklist.swap(Pending);

947

948

949 assert(Pending.empty() && "Pending should be empty");

950 }

951

952

953 for (auto &Pair : BBInsertBeforeMap) {

954 InsertMap &Map = Pair.second;

955 for (auto &Pair : Map) {

956 auto InsertBefore = Pair.first;

957 assert(InsertBefore && "should never be null");

958 auto FragMemLocs = Pair.second;

960

961 for (auto &FragMemLoc : FragMemLocs) {

962 DIExpression *Expr = DIExpression::get(Ctx, {});

963 if (FragMemLoc.SizeInBits !=

964 *Aggregates[FragMemLoc.Var].first->getSizeInBits())

966 Expr, FragMemLoc.OffsetInBits, FragMemLoc.SizeInBits);

968 FragMemLoc.OffsetInBits / 8);

969 DebugVariable Var(Aggregates[FragMemLoc.Var].first, Expr,

970 FragMemLoc.DL.getInlinedAt());

971 FnVarLocs->addVarLoc(InsertBefore, Var, Expr, FragMemLoc.DL,

972 Bases[FragMemLoc.Base]);

973 }

974 }

975 }

976 }

977};

978

979

980

981

982class AssignmentTrackingLowering {

983public:

984

985

986

987

988

989

990

991

992

993

994

995

996

997

998

999

1000

1001

1002

1003

1004

1005

1006

1007 enum class LocKind { Mem, Val, None };

1008

1009

1010

1011

1012

1013

1014

1015

1016

1017

1018

1019

1020

1021

1022

1023 struct Assignment {

1024 enum S { Known, NoneOrPhi } Status;

1025

1026 DIAssignID *ID;

1027

1028

1029 DbgVariableRecord *Source = nullptr;

1030

1031 bool isSameSourceAssignment(const Assignment &Other) const {

1032

1033

1034 return std::tie(Status, ID) == std::tie(Other.Status, Other.ID);

1035 }

1036 void dump(raw_ostream &OS) {

1037 static const char *LUT[] = {"Known", "NoneOrPhi"};

1038 OS << LUT[Status] << "(id=";

1039 if (ID)

1040 OS << ID;

1041 else

1042 OS << "null";

1043 OS << ", s=";

1044 if (!Source)

1045 OS << "null";

1046 else

1048 OS << ")";

1049 }

1050

1051 static Assignment make(DIAssignID *ID, DbgVariableRecord *Source) {

1052 assert((!Source || Source->isDbgAssign()) &&

1053 "Cannot make an assignment from a non-assign DbgVariableRecord");

1054 return Assignment(Known, ID, Source);

1055 }

1056 static Assignment makeFromMemDef(DIAssignID *ID) {

1057 return Assignment(Known, ID);

1058 }

1059 static Assignment makeNoneOrPhi() { return Assignment(NoneOrPhi, nullptr); }

1060

1061 Assignment() : Status(NoneOrPhi), ID(nullptr) {}

1062 Assignment(S Status, DIAssignID *ID) : Status(Status), ID(ID) {

1063

1064 assert(Status == NoneOrPhi || ID);

1065 }

1066 Assignment(S Status, DIAssignID *ID, DbgVariableRecord *Source)

1068

1069 assert(Status == NoneOrPhi || ID);

1070 }

1071 };

1072

1073 using AssignmentMap = SmallVector;

1074 using LocMap = SmallVector;

1075 using OverlapMap = DenseMap<VariableID, SmallVector>;

1076 using UntaggedStoreAssignmentMap =

1079 using UnknownStoreAssignmentMap =

1080 DenseMap<const Instruction *, SmallVector>;

1081

1082private:

1083

1084

1085 unsigned TrackedVariablesVectorSize = 0;

1086

1088

1089

1090 UntaggedStoreAssignmentMap UntaggedStoreVars;

1091

1092

1093 UnknownStoreAssignmentMap UnknownStoreVars;

1094

1095

1096 using InstInsertMap = MapVector<VarLocInsertPt, SmallVector>;

1097 InstInsertMap InsertBeforeMap;

1098

1099

1100 void resetInsertionPoint(Instruction &After);

1101 void resetInsertionPoint(DbgVariableRecord &After);

1102

1103 void emitDbgValue(LocKind Kind, DbgVariableRecord *, VarLocInsertPt After);

1104

1105 static bool mapsAreEqual(const BitVector &Mask, const AssignmentMap &A,

1106 const AssignmentMap &B) {

1108 return A[VarID].isSameSourceAssignment(B[VarID]);

1109 });

1110 }

1111

1112

1113

1114

1115 struct BlockInfo {

1116

1117 BitVector VariableIDsInBlock;

1118

1119

1120 AssignmentMap StackHomeValue;

1121

1122 AssignmentMap DebugValue;

1123

1124

1125

1126

1127

1128

1129

1130

1131

1132

1134

1135 public:

1136 enum AssignmentKind { Stack, Debug };

1137 const AssignmentMap &getAssignmentMap(AssignmentKind Kind) const {

1138 switch (Kind) {

1140 return StackHomeValue;

1142 return DebugValue;

1143 }

1145 }

1146 AssignmentMap &getAssignmentMap(AssignmentKind Kind) {

1147 return const_cast<AssignmentMap &>(

1148 const_cast<const BlockInfo *>(this)->getAssignmentMap(Kind));

1149 }

1150

1151 bool isVariableTracked(VariableID Var) const {

1152 return VariableIDsInBlock[static_cast<unsigned>(Var)];

1153 }

1154

1155 const Assignment &getAssignment(AssignmentKind Kind, VariableID Var) const {

1156 assert(isVariableTracked(Var) && "Var not tracked in block");

1157 return getAssignmentMap(Kind)[static_cast<unsigned>(Var)];

1158 }

1159

1160 LocKind getLocKind(VariableID Var) const {

1161 assert(isVariableTracked(Var) && "Var not tracked in block");

1162 return LiveLoc[static_cast<unsigned>(Var)];

1163 }

1164

1165

1166

1167 void setLocKind(VariableID Var, LocKind K) {

1168 VariableIDsInBlock.set(static_cast<unsigned>(Var));

1169 LiveLoc[static_cast<unsigned>(Var)] = K;

1170 }

1171

1172

1173

1174

1175 void setAssignment(AssignmentKind Kind, VariableID Var,

1176 const Assignment &AV) {

1177 VariableIDsInBlock.set(static_cast<unsigned>(Var));

1178 getAssignmentMap(Kind)[static_cast<unsigned>(Var)] = AV;

1179 }

1180

1181

1182

1183

1184 bool hasAssignment(AssignmentKind Kind, VariableID Var,

1185 const Assignment &AV) const {

1186 if (!isVariableTracked(Var))

1187 return false;

1188 return AV.isSameSourceAssignment(getAssignment(Kind, Var));

1189 }

1190

1191

1192

1194 return VariableIDsInBlock == Other.VariableIDsInBlock &&

1195 LiveLoc == Other.LiveLoc &&

1196 mapsAreEqual(VariableIDsInBlock, StackHomeValue,

1197 Other.StackHomeValue) &&

1198 mapsAreEqual(VariableIDsInBlock, DebugValue, Other.DebugValue);

1199 }

1202 return LiveLoc.size() == DebugValue.size() &&

1203 LiveLoc.size() == StackHomeValue.size();

1204 }

1205

1206

1207 void init(int NumVars) {

1208 StackHomeValue.clear();

1209 DebugValue.clear();

1210 LiveLoc.clear();

1211 VariableIDsInBlock = BitVector(NumVars);

1212 StackHomeValue.insert(StackHomeValue.begin(), NumVars,

1213 Assignment::makeNoneOrPhi());

1214 DebugValue.insert(DebugValue.begin(), NumVars,

1215 Assignment::makeNoneOrPhi());

1216 LiveLoc.insert(LiveLoc.begin(), NumVars, LocKind::None);

1217 }

1218

1219

1220 template <typename ElmtType, typename FnInputType>

1224 ElmtType (*Fn)(FnInputType, FnInputType)) {

1226 }

1227

1228

1229 static BlockInfo join(const BlockInfo &A, const BlockInfo &B, int NumVars) {

1230

1231

1232

1233

1234

1235

1236

1237

1238

1239

1240

1241

1242

1243

1244

1245 BlockInfo Join;

1246 Join.init(NumVars);

1247

1248 BitVector Intersect = A.VariableIDsInBlock;

1249 Intersect &= B.VariableIDsInBlock;

1250

1252 joinElmt(VarID, Join.LiveLoc, A.LiveLoc, B.LiveLoc, joinKind);

1253 joinElmt(VarID, Join.DebugValue, A.DebugValue, B.DebugValue,

1254 joinAssignment);

1255 joinElmt(VarID, Join.StackHomeValue, A.StackHomeValue, B.StackHomeValue,

1256 joinAssignment);

1257 }

1258

1259 Join.VariableIDsInBlock = A.VariableIDsInBlock;

1260 Join.VariableIDsInBlock |= B.VariableIDsInBlock;

1261 assert(Join.isValid());

1262 return Join;

1263 }

1264 };

1265

1267 const DataLayout &Layout;

1268 const DenseSet *VarsWithStackSlot;

1269 FunctionVarLocsBuilder *FnVarLocs;

1270 DenseMap<const BasicBlock *, BlockInfo> LiveIn;

1271 DenseMap<const BasicBlock *, BlockInfo> LiveOut;

1272

1273

1274 DenseSet VarsTouchedThisFrame;

1275

1276

1277 DenseSet NotAlwaysStackHomed;

1278

1279 VariableID getVariableID(const DebugVariable &Var) {

1281 }

1282

1283

1284

1285

1286

1287 bool join(const BasicBlock &BB, const SmallPtrSet<BasicBlock *, 16> &Visited);

1288

1289

1290

1291

1292

1293

1294

1295

1296

1297

1298

1299

1300

1301

1302

1303

1304

1305

1306

1307 static LocKind joinKind(LocKind A, LocKind B);

1308 static Assignment joinAssignment(const Assignment &A, const Assignment &B);

1309 BlockInfo joinBlockInfo(const BlockInfo &A, const BlockInfo &B);

1310

1311

1312

1313

1314

1315 void process(BasicBlock &BB, BlockInfo *LiveSet);

1316

1317

1318

1319

1320 void processNonDbgInstruction(Instruction &I, BlockInfo *LiveSet);

1321

1322

1323 void processTaggedInstruction(Instruction &I, BlockInfo *LiveSet);

1324

1325

1326 void processUntaggedInstruction(Instruction &I, BlockInfo *LiveSet);

1327 void processUnknownStoreToVariable(Instruction &I, VariableID &Var,

1328 BlockInfo *LiveSet);

1329 void processDbgAssign(DbgVariableRecord *Assign, BlockInfo *LiveSet);

1330 void processDbgVariableRecord(DbgVariableRecord &DVR, BlockInfo *LiveSet);

1331 void processDbgValue(DbgVariableRecord *DbgValue, BlockInfo *LiveSet);

1332

1333 void addMemDef(BlockInfo *LiveSet, VariableID Var, const Assignment &AV);

1334

1335 void addDbgDef(BlockInfo *LiveSet, VariableID Var, const Assignment &AV);

1336

1337

1338

1339 void setLocKind(BlockInfo *LiveSet, VariableID Var, LocKind K);

1340

1341

1342 LocKind getLocKind(BlockInfo *LiveSet, VariableID Var);

1343

1344 bool hasVarWithAssignment(BlockInfo *LiveSet, BlockInfo::AssignmentKind Kind,

1345 VariableID Var, const Assignment &AV);

1346

1347

1349

1350

1351

1353

1354

1355 bool emitPromotedVarLocs(FunctionVarLocsBuilder *FnVarLocs);

1356

1357public:

1358 AssignmentTrackingLowering(Function &Fn, const DataLayout &Layout,

1359 const DenseSet *VarsWithStackSlot)

1360 : Fn(Fn), Layout(Layout), VarsWithStackSlot(VarsWithStackSlot) {}

1361

1362

1363 bool run(FunctionVarLocsBuilder *FnVarLocs);

1364};

1365}

1366

1368AssignmentTrackingLowering::getContainedFragments(VariableID Var) const {

1369 auto R = VarContains.find(Var);

1370 if (R == VarContains.end())

1371 return {};

1372 return R->second;

1373}

1374

1375void AssignmentTrackingLowering::touchFragment(VariableID Var) {

1376 VarsTouchedThisFrame.insert(Var);

1377}

1378

1379void AssignmentTrackingLowering::setLocKind(BlockInfo *LiveSet, VariableID Var,

1380 LocKind K) {

1381 auto SetKind = [this](BlockInfo *LiveSet, VariableID Var, LocKind K) {

1382 LiveSet->setLocKind(Var, K);

1383 touchFragment(Var);

1384 };

1385 SetKind(LiveSet, Var, K);

1386

1387

1388 for (VariableID Frag : getContainedFragments(Var))

1389 SetKind(LiveSet, Frag, K);

1390}

1391

1392AssignmentTrackingLowering::LocKind

1393AssignmentTrackingLowering::getLocKind(BlockInfo *LiveSet, VariableID Var) {

1394 return LiveSet->getLocKind(Var);

1395}

1396

1397void AssignmentTrackingLowering::addMemDef(BlockInfo *LiveSet, VariableID Var,

1398 const Assignment &AV) {

1399 LiveSet->setAssignment(BlockInfo::Stack, Var, AV);

1400

1401

1402

1403

1404 Assignment FragAV = AV;

1405 FragAV.Source = nullptr;

1406 for (VariableID Frag : getContainedFragments(Var))

1407 LiveSet->setAssignment(BlockInfo::Stack, Frag, FragAV);

1408}

1409

1410void AssignmentTrackingLowering::addDbgDef(BlockInfo *LiveSet, VariableID Var,

1411 const Assignment &AV) {

1412 LiveSet->setAssignment(BlockInfo::Debug, Var, AV);

1413

1414

1415

1416

1417 Assignment FragAV = AV;

1418 FragAV.Source = nullptr;

1419 for (VariableID Frag : getContainedFragments(Var))

1420 LiveSet->setAssignment(BlockInfo::Debug, Frag, FragAV);

1421}

1422

1426

1429 "Cannot get a DIAssignID from a non-assign DbgVariableRecord!");

1431}

1432

1433

1434bool AssignmentTrackingLowering::hasVarWithAssignment(

1435 BlockInfo *LiveSet, BlockInfo::AssignmentKind Kind, VariableID Var,

1436 const Assignment &AV) {

1437 if (!LiveSet->hasAssignment(Kind, Var, AV))

1438 return false;

1439

1440

1441

1442 for (VariableID Frag : getContainedFragments(Var))

1443 if (!LiveSet->hasAssignment(Kind, Frag, AV))

1444 return false;

1445 return true;

1446}

1447

1448#ifndef NDEBUG

1449const char *locStr(AssignmentTrackingLowering::LocKind Loc) {

1450 using LocKind = AssignmentTrackingLowering::LocKind;

1451 switch (Loc) {

1452 case LocKind::Val:

1453 return "Val";

1454 case LocKind::Mem:

1455 return "Mem";

1456 case LocKind::None:

1457 return "None";

1458 };

1460}

1461#endif

1462

1467 return &*NextIt;

1468}

1471 if (Next->hasDbgRecords())

1472 return Next;

1473 return &*Next->getDbgRecordRange().begin();

1474}

1480

1481void AssignmentTrackingLowering::emitDbgValue(

1482 AssignmentTrackingLowering::LocKind Kind, DbgVariableRecord *Source,

1484

1488 if (!Val)

1491

1492

1494 assert(InsertBefore && "Shouldn't be inserting after a terminator");

1495

1499 VarLoc.Expr = Expr;

1501 VarLoc.DL = DL;

1502

1503 InsertBeforeMap[InsertBefore].push_back(VarLoc);

1504 };

1505

1506

1507 if (Kind == LocKind::Mem) {

1510

1511

1512 if (Assign->isKillAddress()) {

1513

1514 Kind = LocKind::Val;

1515 } else {

1519 "fragment info should be stored in value-expression only");

1520

1521

1522 if (auto OptFragInfo = Source->getExpression()->getFragmentInfo()) {

1523 auto FragInfo = *OptFragInfo;

1525 Expr, FragInfo.OffsetInBits, FragInfo.SizeInBits);

1526 }

1527

1528 std::tie(Val, Expr) =

1531 return;

1532 }

1533 }

1534

1535 if (Kind == LocKind::Val) {

1536 Emit(Source->getRawLocation(), Source->getExpression());

1537 return;

1538 }

1539

1540 if (Kind == LocKind::None) {

1541 Emit(nullptr, Source->getExpression());

1542 return;

1543 }

1544}

1545

1546void AssignmentTrackingLowering::processNonDbgInstruction(

1547 Instruction &I, AssignmentTrackingLowering::BlockInfo *LiveSet) {

1548 if (I.hasMetadata(LLVMContext::MD_DIAssignID))

1549 processTaggedInstruction(I, LiveSet);

1550 else

1551 processUntaggedInstruction(I, LiveSet);

1552}

1553

1554void AssignmentTrackingLowering::processUnknownStoreToVariable(

1556

1557

1558 addMemDef(LiveSet, Var, Assignment::makeNoneOrPhi());

1559

1560

1561 if (getLocKind(LiveSet, Var) != LocKind::Mem)

1562 return;

1563

1564

1565 Assignment DbgAV = LiveSet->getAssignment(BlockInfo::Debug, Var);

1566 if (DbgAV.Status != Assignment::NoneOrPhi && DbgAV.Source) {

1567 LLVM_DEBUG(dbgs() << "Switching to fallback debug value: ";

1568 DbgAV.dump(dbgs()); dbgs() << "\n");

1569 setLocKind(LiveSet, Var, LocKind::Val);

1570 emitDbgValue(LocKind::Val, DbgAV.Source, &I);

1571 return;

1572 }

1573

1574

1576 assert(InsertBefore && "Shouldn't be inserting after a terminator");

1577

1578

1582 Fn.getContext(), 0, 0, V.getVariable()->getScope(), InlinedAt);

1583

1589 VarLoc.DL = DILoc;

1590 InsertBeforeMap[InsertBefore].push_back(VarLoc);

1591}

1592

1593void AssignmentTrackingLowering::processUntaggedInstruction(

1594 Instruction &I, AssignmentTrackingLowering::BlockInfo *LiveSet) {

1595

1596

1597

1598

1599

1600

1601

1602

1603

1604

1605

1606 assert(I.hasMetadata(LLVMContext::MD_DIAssignID));

1607 auto It = UntaggedStoreVars.find(&I);

1608 if (It == UntaggedStoreVars.end()) {

1609

1610

1611

1612

1613

1614

1615 if (auto UnhandledStoreIt = UnknownStoreVars.find(&I);

1616 UnhandledStoreIt != UnknownStoreVars.end()) {

1617 LLVM_DEBUG(dbgs() << "Processing untagged unknown store " << I << "\n");

1618 for (auto &Var : UnhandledStoreIt->second)

1619 processUnknownStoreToVariable(I, Var, LiveSet);

1620 }

1621 return;

1622 }

1623

1624 LLVM_DEBUG(dbgs() << "processUntaggedInstruction on UNTAGGED INST " << I

1625 << "\n");

1626

1627

1628 for (auto [Var, Info] : It->second) {

1629

1630

1631

1632 addMemDef(LiveSet, Var, Assignment::makeNoneOrPhi());

1633 addDbgDef(LiveSet, Var, Assignment::makeNoneOrPhi());

1634 setLocKind(LiveSet, Var, LocKind::Mem);

1636 << "\n");

1637

1638

1639

1642 if (auto Frag = V.getFragment()) {

1644 Frag->SizeInBits);

1645 assert(R && "unexpected createFragmentExpression failure");

1647 }

1649 if (Info.OffsetInBits)

1650 Ops = {dwarf::DW_OP_plus_uconst, Info.OffsetInBits / 8};

1653 false);

1654

1655

1657 assert(InsertBefore && "Shouldn't be inserting after a terminator");

1658

1659

1662 Fn.getContext(), 0, 0, V.getVariable()->getScope(), InlinedAt);

1663

1669 VarLoc.DL = DILoc;

1670

1671 InsertBeforeMap[InsertBefore].push_back(VarLoc);

1672 }

1673}

1674

1675void AssignmentTrackingLowering::processTaggedInstruction(

1676 Instruction &I, AssignmentTrackingLowering::BlockInfo *LiveSet) {

1678

1679

1680

1681

1682 if (LinkedDPAssigns.empty())

1683 return;

1684

1685 LLVM_DEBUG(dbgs() << "processTaggedInstruction on " << I << "\n");

1688

1689

1691 "expected Assign's variable to have stack slot");

1692

1693 Assignment AV = Assignment::makeFromMemDef(getIDFromInst(I));

1694 addMemDef(LiveSet, Var, AV);

1695

1696 LLVM_DEBUG(dbgs() << " linked to " << *Assign << "\n");

1698 << " -> ");

1699

1700

1701

1702 if (hasVarWithAssignment(LiveSet, BlockInfo::Debug, Var, AV)) {

1703

1704

1705 LLVM_DEBUG(dbgs() << "Mem, Stack matches Debug program\n";);

1708 LiveSet->DebugValue[static_cast<unsigned>(Var)].dump(dbgs());

1709 dbgs() << "\n");

1710 setLocKind(LiveSet, Var, LocKind::Mem);

1711 emitDbgValue(LocKind::Mem, Assign, &I);

1712 return;

1713 }

1714

1715

1716

1717

1718

1719

1720 LocKind PrevLoc = getLocKind(LiveSet, Var);

1721 switch (PrevLoc) {

1722 case LocKind::Val: {

1723

1724

1726 setLocKind(LiveSet, Var, LocKind::Val);

1727 } break;

1728 case LocKind::Mem: {

1729

1730

1731

1732 Assignment DbgAV = LiveSet->getAssignment(BlockInfo::Debug, Var);

1733 if (DbgAV.Status == Assignment::NoneOrPhi) {

1734

1735 LLVM_DEBUG(dbgs() << "None, No Debug value available\n";);

1736 setLocKind(LiveSet, Var, LocKind::None);

1737 emitDbgValue(LocKind::None, Assign, &I);

1738 } else {

1739

1740 LLVM_DEBUG(dbgs() << "Val, Debug value is Known\n";);

1741 setLocKind(LiveSet, Var, LocKind::Val);

1742 if (DbgAV.Source) {

1743 emitDbgValue(LocKind::Val, DbgAV.Source, &I);

1744 } else {

1745

1746 emitDbgValue(LocKind::None, Assign, &I);

1747 }

1748 }

1749 } break;

1750 case LocKind::None: {

1751

1752

1754 setLocKind(LiveSet, Var, LocKind::None);

1755 } break;

1756 }

1757 }

1758}

1759

1760void AssignmentTrackingLowering::processDbgAssign(DbgVariableRecord *DbgAssign,

1761 BlockInfo *LiveSet) {

1762

1763

1765 return;

1766

1768 Assignment AV = Assignment::make(getIDFromMarker(*DbgAssign), DbgAssign);

1769 addDbgDef(LiveSet, Var, AV);

1770

1771 LLVM_DEBUG(dbgs() << "processDbgAssign on " << *DbgAssign << "\n";);

1773 << " -> ");

1774

1775

1776

1777 if (hasVarWithAssignment(LiveSet, BlockInfo::Stack, Var, AV)) {

1778

1779

1780

1781 LocKind Kind;

1785 << "Val, Stack matches Debug program but address is killed\n";);

1786 Kind = LocKind::Val;

1787 } else {

1788 LLVM_DEBUG(dbgs() << "Mem, Stack matches Debug program\n";);

1789 Kind = LocKind::Mem;

1790 };

1791 setLocKind(LiveSet, Var, Kind);

1792 emitDbgValue(Kind, DbgAssign, DbgAssign);

1793 } else {

1794

1795

1796 LLVM_DEBUG(dbgs() << "Val, Stack contents is unknown\n";);

1797 setLocKind(LiveSet, Var, LocKind::Val);

1798 emitDbgValue(LocKind::Val, DbgAssign, DbgAssign);

1799 }

1800}

1801

1803 BlockInfo *LiveSet) {

1804

1805

1807 return;

1808

1810

1811

1812

1813

1814

1815

1816 Assignment AV = Assignment::makeNoneOrPhi();

1817 addDbgDef(LiveSet, Var, AV);

1818

1821 << " -> Val, dbg.value override");

1822

1823 setLocKind(LiveSet, Var, LocKind::Val);

1825}

1826

1828 if (auto F = DbgValue.getExpression()->getFragmentInfo())

1829 return F->SizeInBits == 0;

1830 return false;

1831}

1832

1833void AssignmentTrackingLowering::processDbgVariableRecord(

1834 DbgVariableRecord &DVR, AssignmentTrackingLowering::BlockInfo *LiveSet) {

1835

1837 return;

1838

1840 processDbgAssign(&DVR, LiveSet);

1842 processDbgValue(&DVR, LiveSet);

1843}

1844

1845void AssignmentTrackingLowering::resetInsertionPoint(Instruction &After) {

1847 auto *R = InsertBeforeMap.find(getNextNode(&After));

1848 if (R == InsertBeforeMap.end())

1849 return;

1850 R->second.clear();

1851}

1852void AssignmentTrackingLowering::resetInsertionPoint(DbgVariableRecord &After) {

1853 auto *R = InsertBeforeMap.find(getNextNode(&After));

1854 if (R == InsertBeforeMap.end())

1855 return;

1856 R->second.clear();

1857}

1858

1859void AssignmentTrackingLowering::process(BasicBlock &BB, BlockInfo *LiveSet) {

1860

1861

1862 bool ProcessedLeadingDbgRecords = !BB.begin()->hasDbgRecords();

1863 for (auto II = BB.begin(), EI = BB.end(); II != EI;) {

1864 assert(VarsTouchedThisFrame.empty());

1865

1866

1867

1868

1869

1870

1871 if (ProcessedLeadingDbgRecords) {

1872

1873

1874

1875

1876 if (II->isTerminator())

1877 break;

1878 resetInsertionPoint(*II);

1879 processNonDbgInstruction(*II, LiveSet);

1880 assert(LiveSet->isValid());

1881 ++II;

1882 }

1883

1884

1885

1886 if (II != EI && II->hasDbgRecords()) {

1887

1888

1889

1891 resetInsertionPoint(DVR);

1892 processDbgVariableRecord(DVR, LiveSet);

1893 assert(LiveSet->isValid());

1894 }

1895 }

1896 ProcessedLeadingDbgRecords = true;

1897

1898

1899

1900

1901

1902

1903

1904 for (auto Var : VarsTouchedThisFrame) {

1905 LocKind Loc = getLocKind(LiveSet, Var);

1906

1907

1908

1909

1910

1911

1912

1913 if (Loc != LocKind::Mem) {

1916 NotAlwaysStackHomed.insert(Aggr);

1917 }

1918 }

1919 VarsTouchedThisFrame.clear();

1920 }

1921}

1922

1923AssignmentTrackingLowering::LocKind

1924AssignmentTrackingLowering::joinKind(LocKind A, LocKind B) {

1925

1926

1927 return A == B ? A : LocKind::None;

1928}

1929

1930AssignmentTrackingLowering::Assignment

1931AssignmentTrackingLowering::joinAssignment(const Assignment &A,

1932 const Assignment &B) {

1933

1934

1935

1936

1937

1938

1939 if (A.isSameSourceAssignment(B))

1940 return Assignment::makeNoneOrPhi();

1941 if (A.Status == Assignment::NoneOrPhi)

1942 return Assignment::makeNoneOrPhi();

1943

1944

1945

1946

1947

1948

1949

1950

1951

1952

1953

1954

1955

1956

1958 if (A.Source == B.Source)

1959 return A.Source;

1960 if (A.Source || B.Source)

1961 return nullptr;

1962 if (A.Source->isEquivalentTo(*B.Source))

1963 return A.Source;

1964 return nullptr;

1965 };

1967 assert(A.Status == B.Status && A.Status == Assignment::Known);

1969 return Assignment::make(A.ID, Source);

1970}

1971

1972AssignmentTrackingLowering::BlockInfo

1973AssignmentTrackingLowering::joinBlockInfo(const BlockInfo &A,

1974 const BlockInfo &B) {

1975 return BlockInfo::join(A, B, TrackedVariablesVectorSize);

1976}

1977

1978bool AssignmentTrackingLowering::join(

1980

1982

1983

1984

1985

1986

1987

1988

1990 if (Visited.count(Pred))

1992 }

1993

1994

1995 if (VisitedPreds.empty()) {

1996 auto It = LiveIn.try_emplace(&BB, BlockInfo());

1997 bool DidInsert = It.second;

1998 if (DidInsert)

1999 It.first->second.init(TrackedVariablesVectorSize);

2000 return DidInsert;

2001 }

2002

2003

2004 if (VisitedPreds.size() == 1) {

2005 const BlockInfo &PredLiveOut = LiveOut.find(VisitedPreds[0])->second;

2006

2007

2008

2009 auto [CurrentLiveInEntry, Inserted] = LiveIn.try_emplace(&BB, PredLiveOut);

2010 if (Inserted)

2011 return true;

2012 if (PredLiveOut != CurrentLiveInEntry->second) {

2013 CurrentLiveInEntry->second = PredLiveOut;

2014 return true;

2015 }

2016 return false;

2017 }

2018

2019

2021 const BlockInfo &PredLiveOut0 = LiveOut.find(VisitedPreds[0])->second;

2022 const BlockInfo &PredLiveOut1 = LiveOut.find(VisitedPreds[1])->second;

2023 BlockInfo BBLiveIn = joinBlockInfo(PredLiveOut0, PredLiveOut1);

2024

2025

2028 const auto &PredLiveOut = LiveOut.find(Pred);

2029 assert(PredLiveOut != LiveOut.end() &&

2030 "block should have been processed already");

2031 BBLiveIn = joinBlockInfo(std::move(BBLiveIn), PredLiveOut->second);

2032 }

2033

2034

2035 auto CurrentLiveInEntry = LiveIn.find(&BB);

2036

2037

2038 if (CurrentLiveInEntry == LiveIn.end())

2039 LiveIn.try_emplace(&BB, std::move(BBLiveIn));

2040 else if (BBLiveIn != CurrentLiveInEntry->second)

2041 CurrentLiveInEntry->second = std::move(BBLiveIn);

2042 else

2043 return false;

2044 return true;

2045}

2046

2047

2050 auto ALeft = A.OffsetInBits;

2051 auto BLeft = B.OffsetInBits;

2052 if (BLeft < ALeft)

2053 return false;

2054

2055 auto ARight = ALeft + A.SizeInBits;

2056 auto BRight = BLeft + B.SizeInBits;

2057 if (BRight > ARight)

2058 return false;

2059 return true;

2060}

2061

2062static std::optionalat::AssignmentInfo

2064

2065

2066

2071

2072 return std::nullopt;

2073}

2074

2077 if (II)

2078 return nullptr;

2080 if (ID != Intrinsic::experimental_vp_strided_store &&

2081 ID != Intrinsic::masked_store && ID != Intrinsic::vp_scatter &&

2082 ID != Intrinsic::masked_scatter && ID != Intrinsic::vp_store &&

2083 ID != Intrinsic::masked_compressstore)

2084 return nullptr;

2086

2087

2089 Value *Base = MemOp->stripAndAccumulateConstantOffsets(Layout, Offset, true);

2090

2091

2093}

2094

2095

2096

2097

2098

2099

2100

2101

2102

2103

2104

2105

2106

2107

2108

2109

2110

2111

2112

2113

2117 AssignmentTrackingLowering::UntaggedStoreAssignmentMap &UntaggedStoreVars,

2118 AssignmentTrackingLowering::UnknownStoreAssignmentMap &UnknownStoreVars,

2119 unsigned &TrackedVariablesVectorSize) {

2121

2123

2124

2125

2126

2127

2128

2129

2130

2133 if (Record->isDbgDeclare()) {

2135 return;

2136 }

2139 if (!VarsWithStackSlot.contains(DA))

2140 return;

2141 if (Seen.insert(DV).second)

2142 FragmentMap[DA].push_back(DV);

2143 };

2144 for (auto &BB : Fn) {

2145 for (auto &I : BB) {

2147 ProcessDbgRecord(&DVR);

2149

2151 std::optionalDIExpression::FragmentInfo FragInfo;

2152

2153

2154

2156 I.getDataLayout(), Info->Base,

2157 Info->OffsetInBits, Info->SizeInBits, Assign, FragInfo) ||

2158 (FragInfo && FragInfo->SizeInBits == 0))

2159 return;

2160

2161

2162

2163

2164

2165

2166 if (!FragInfo)

2167 FragInfo = Assign->getExpression()->getFragmentInfo();

2168

2171 Assign->getDebugLoc().getInlinedAt());

2173 if (!VarsWithStackSlot.contains(DA))

2174 return;

2175

2176

2177 UntaggedStoreVars[&I].push_back(

2179

2180 if (Seen.insert(DV).second)

2181 FragmentMap[DA].push_back(DV);

2182 };

2184 HandleDbgAssignForStore(DVR);

2186

2187 auto HandleDbgAssignForUnknownStore = [&](DbgVariableRecord *Assign) {

2188

2189

2191 DebugVariable(Assign->getVariable(), std::nullopt,

2192 Assign->getDebugLoc().getInlinedAt());

2194 if (!VarsWithStackSlot.contains(DA))

2195 return;

2196

2197

2198 UnknownStoreVars[&I].push_back(FnVarLocs->insertVariable(DV));

2199 };

2201 HandleDbgAssignForUnknownStore(DVR);

2202 }

2203 }

2204 }

2205

2206

2207

2208 for (auto &Pair : FragmentMap) {

2210 std::sort(Frags.begin(), Frags.end(),

2212 return Elmt.getFragmentOrDefault().SizeInBits >

2213 Next.getFragmentOrDefault().SizeInBits;

2214 });

2215

2216 assert(std::adjacent_find(Frags.begin(), Frags.end()) == Frags.end());

2217 }

2218

2219

2220 AssignmentTrackingLowering::OverlapMap Map;

2221 for (auto &Pair : FragmentMap) {

2222 auto &Frags = Pair.second;

2223 for (auto It = Frags.begin(), IEnd = Frags.end(); It != IEnd; ++It) {

2225

2226

2227

2228

2229

2231 ++OtherIt;

2233 for (; OtherIt != IEnd; ++OtherIt) {

2237 Map[OtherVar].push_back(ThisVar);

2238 }

2239 }

2240 }

2241

2242

2243

2244 TrackedVariablesVectorSize = FnVarLocs->getNumVariables() + 1;

2245

2246

2247

2248 for (auto *DVR : DPDeclares)

2252 return Map;

2253}

2254

2255bool AssignmentTrackingLowering::run(FunctionVarLocsBuilder *FnVarLocsBuilder) {

2258 << ": too many blocks (" << Fn.size() << ")\n");

2260 return false;

2261 }

2262

2263 FnVarLocs = FnVarLocsBuilder;

2264

2265

2266

2267

2268

2269

2270

2271

2273 Fn, FnVarLocs, *VarsWithStackSlot, UntaggedStoreVars, UnknownStoreVars,

2274 TrackedVariablesVectorSize);

2275

2276

2278 std::priority_queue<unsigned int, std::vector,

2279 std::greater>

2280 Worklist;

2281 std::priority_queue<unsigned int, std::vector,

2282 std::greater>

2283 Pending;

2286 {

2287 unsigned int RPONumber = 0;

2289 OrderToBB[RPONumber] = BB;

2290 BBToOrder[BB] = RPONumber;

2291 Worklist.push(RPONumber);

2292 ++RPONumber;

2293 }

2294 LiveIn.reserve(RPONumber);

2295 LiveOut.reserve(RPONumber);

2296 }

2297

2298

2299

2300

2301

2302

2303

2304

2305

2306

2307

2309 while (!Worklist.empty()) {

2310

2311

2314 while (!Worklist.empty()) {

2315 BasicBlock *BB = OrderToBB[Worklist.top()];

2317 Worklist.pop();

2318 bool InChanged = join(*BB, Visited);

2319

2320 InChanged |= Visited.insert(BB).second;

2321 if (InChanged) {

2323

2324

2325 BlockInfo LiveSet = LiveIn[BB];

2326

2327

2328 process(*BB, &LiveSet);

2329

2330

2331 if (LiveOut[BB] != LiveSet) {

2333 << " has new OutLocs, add succs to worklist: [ ");

2334 LiveOut[BB] = std::move(LiveSet);

2336 if (OnPending.insert(Succ).second) {

2338 Pending.push(BBToOrder[Succ]);

2339 }

2340 }

2342 }

2343 }

2344 }

2345 Worklist.swap(Pending);

2346

2347

2348 assert(Pending.empty() && "Pending should be empty");

2349 }

2350

2351

2352

2353

2354 bool InsertedAnyIntrinsics = false;

2355

2356

2357

2358

2359

2360

2361

2363 for (const auto &Pair : InsertBeforeMap) {

2364 auto &Vec = Pair.second;

2368

2369

2370 if (NotAlwaysStackHomed.contains(Aggr))

2371 continue;

2372

2373

2374

2375

2376

2380 NotAlwaysStackHomed.insert(Aggr);

2381 continue;

2382 }

2383

2384

2385

2386

2387

2388

2389 if (AlwaysStackHomed.insert(Aggr).second) {

2391

2392

2393

2398 InsertedAnyIntrinsics = true;

2399 }

2400 }

2401 }

2402

2403

2404 for (const auto &[InsertBefore, Vec] : InsertBeforeMap) {

2406 for (const VarLocInfo &VarLoc : Vec) {

2409

2410

2411 if (AlwaysStackHomed.contains(Aggr))

2412 continue;

2414 InsertedAnyIntrinsics = true;

2415 }

2416

2417 FnVarLocs->setWedge(InsertBefore, std::move(NewDefs));

2418 }

2419

2420 InsertedAnyIntrinsics |= emitPromotedVarLocs(FnVarLocs);

2421

2422 return InsertedAnyIntrinsics;

2423}

2424

2425bool AssignmentTrackingLowering::emitPromotedVarLocs(

2426 FunctionVarLocsBuilder *FnVarLocs) {

2427 bool InsertedAnyIntrinsics = false;

2428

2429

2431

2432

2434 return;

2436 assert(InsertBefore && "Unexpected: debug intrinsics after a terminator");

2438 Record->getExpression(), Record->getDebugLoc(),

2440 InsertedAnyIntrinsics = true;

2441 };

2442 for (auto &BB : Fn) {

2443 for (auto &I : BB) {

2444

2447 TranslateDbgRecord(&DVR);

2448 }

2449 }

2450 return InsertedAnyIntrinsics;

2451}

2452

2453

2454

2455

2456

2457

2458

2459

2460static bool

2465

2466

2467

2469

2470 VariableDefinedBytes.clear();

2471

2472 auto HandleLocsForWedge = [&](auto *WedgePosition) {

2473

2474 const auto *Locs = FnVarLocs.getWedge(WedgePosition);

2475 if (!Locs)

2476 return;

2477

2478 NumWedgesScanned++;

2479 bool ChangedThisWedge = false;

2480

2482

2483

2484 for (auto RIt = Locs->rbegin(), REnd = Locs->rend(); RIt != REnd; ++RIt) {

2485 NumDefsScanned++;

2488 uint64_t SizeInBits = Aggr.first->getSizeInBits().value_or(0);

2490

2491

2492 const uint64_t MaxSizeBytes = 2048;

2493

2494 if (SizeInBytes == 0 || SizeInBytes > MaxSizeBytes) {

2495

2496

2497

2498 NewDefsReversed.push_back(*RIt);

2499 continue;

2500 }

2501

2502

2503

2504

2505

2506 auto InsertResult =

2508 bool FirstDefinition = InsertResult.second;

2509 BitVector &DefinedBytes = InsertResult.first->second;

2510

2512 RIt->Expr->getFragmentInfo().value_or(

2514 bool InvalidFragment = Fragment.endInBits() > SizeInBits;

2515 uint64_t StartInBytes = Fragment.startInBits() / 8;

2517

2518

2519 if (FirstDefinition || InvalidFragment ||

2521 if (!InvalidFragment)

2522 DefinedBytes.set(StartInBytes, EndInBytes);

2523 NewDefsReversed.push_back(*RIt);

2524 continue;

2525 }

2526

2527

2528

2529 ChangedThisWedge = true;

2530 NumDefsRemoved++;

2531 }

2532

2533

2534 if (ChangedThisWedge) {

2535 std::reverse(NewDefsReversed.begin(), NewDefsReversed.end());

2536 FnVarLocs.setWedge(WedgePosition, std::move(NewDefsReversed));

2537 NumWedgesChanged++;

2539 }

2540 };

2541 HandleLocsForWedge(&I);

2543 HandleLocsForWedge(&DVR);

2544 }

2545

2547}

2548

2549

2550

2551

2552

2553

2554

2555

2556static bool

2561 VariableMap;

2562

2563

2564

2565

2567

2568 auto HandleLocsForWedge = [&](auto *WedgePosition) {

2569 const auto *Locs = FnVarLocs.getWedge(WedgePosition);

2570 if (!Locs)

2571 return;

2572

2573 NumWedgesScanned++;

2574 bool ChangedThisWedge = false;

2575

2577

2578

2580 NumDefsScanned++;

2582 std::nullopt, Loc.DL.getInlinedAt());

2583 auto [VMI, Inserted] = VariableMap.try_emplace(Key);

2584

2585

2586

2587 if (Inserted || VMI->second.first != Loc.Values ||

2588 VMI->second.second != Loc.Expr) {

2589 VMI->second = {Loc.Values, Loc.Expr};

2591 continue;

2592 }

2593

2594

2595 ChangedThisWedge = true;

2596 NumDefsRemoved++;

2597 }

2598

2599

2600 if (ChangedThisWedge) {

2601 FnVarLocs.setWedge(WedgePosition, std::move(NewDefs));

2602 NumWedgesChanged++;

2604 }

2605 };

2606

2608 HandleLocsForWedge(&DVR);

2609 HandleLocsForWedge(&I);

2610 }

2611

2613}

2614

2615static bool

2619

2620

2621

2622

2623

2624

2625

2626

2627

2628

2629

2631 VarsWithDef;

2632

2634 VarsWithDef[A].insert(V.getFragmentOrDefault());

2635 };

2636

2637

2638

2640 auto FragsIt = VarsWithDef.find(A);

2641 if (FragsIt == VarsWithDef.end())

2642 return false;

2643 return llvm::any_of(FragsIt->second, [V](auto Frag) {

2644 return DIExpression::fragmentsOverlap(Frag, V.getFragmentOrDefault());

2645 });

2646 };

2647

2649

2650

2651

2652

2654

2655 auto HandleLocsForWedge = [&](auto *WedgePosition) {

2656 const auto *Locs = FnVarLocs.getWedge(WedgePosition);

2657 if (!Locs)

2658 return;

2659

2660 NumWedgesScanned++;

2661 bool ChangedThisWedge = false;

2662

2664

2665

2667 NumDefsScanned++;

2669 Loc.DL.getInlinedAt()};

2671

2672

2673

2674 if (Loc.Values.isKillLocation(Loc.Expr) && !HasDefinedBits(Aggr, Var)) {

2675

2676 NumDefsRemoved++;

2677 ChangedThisWedge = true;

2678 continue;

2679 }

2680

2681 DefineBits(Aggr, Var);

2683 }

2684

2685

2686 if (ChangedThisWedge) {

2687 FnVarLocs.setWedge(WedgePosition, std::move(NewDefs));

2688 NumWedgesChanged++;

2690 }

2691 };

2693 HandleLocsForWedge(&DVR);

2694 HandleLocsForWedge(&I);

2695 }

2696

2698}

2699

2702 bool MadeChanges = false;

2707

2708 if (MadeChanges)

2710 << "\n");

2711 return MadeChanges;

2712}

2713

2716 for (auto &BB : Fn) {

2717 for (auto &I : BB) {

2718

2719

2720

2721

2722

2725 }

2726 }

2727 }

2728 return Result;

2729}

2730

2733

2734

2735

2737

2739

2740

2741

2742 {

2743 AssignmentTrackingLowering Pass(Fn, Layout, &VarsWithStackSlot);

2745 }

2746

2748 MemLocFragmentFill Pass(Fn, &VarsWithStackSlot,

2750 Pass.run(FnVarLocs);

2751

2752

2753

2754

2755

2756 for (auto &BB : Fn)

2758 }

2759}

2760

2766

2767 auto &DL = F.getDataLayout();

2768

2771

2772

2776}

2777

2778AnalysisKey DebugAssignmentTrackingAnalysis::Key;

2779

2786

2789 return false;

2790

2791 LLVM_DEBUG(dbgs() << "AssignmentTrackingAnalysis run on " << F.getName()

2792 << "\n");

2793

2794

2795 Results->clear();

2796

2799

2800

2801 Results->init(Builder);

2802

2804 Results->print(errs(), F);

2805

2806

2807 return false;

2808}

2809

2812

2814

2816 "Assignment Tracking Analysis", false, true)

assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")

MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL

Function Alias Analysis Results

std::pair< const DILocalVariable *, const DILocation * > DebugAggregate

A whole (unfragmented) source variable.

Definition AssignmentTrackingAnalysis.cpp:325

VarLocInsertPt getNextNode(const DbgRecord *DVR)

Definition AssignmentTrackingAnalysis.cpp:1463

static void analyzeFunction(Function &Fn, const DataLayout &Layout, FunctionVarLocsBuilder *FnVarLocs)

Definition AssignmentTrackingAnalysis.cpp:2731

static std::pair< Value *, DIExpression * > walkToAllocaAndPrependOffsetDeref(const DataLayout &DL, Value *Start, DIExpression *Expression)

Walk backwards along constant GEPs and bitcasts to the base storage from Start as far as possible.

Definition AssignmentTrackingAnalysis.cpp:264

static DenseSet< DebugAggregate > findVarsWithStackSlot(Function &Fn)

Definition AssignmentTrackingAnalysis.cpp:2714

static AssignmentTrackingLowering::OverlapMap buildOverlapMapAndRecordDeclares(Function &Fn, FunctionVarLocsBuilder *FnVarLocs, const DenseSet< DebugAggregate > &VarsWithStackSlot, AssignmentTrackingLowering::UntaggedStoreAssignmentMap &UntaggedStoreVars, AssignmentTrackingLowering::UnknownStoreAssignmentMap &UnknownStoreVars, unsigned &TrackedVariablesVectorSize)

Build a map of {Variable x: Variables y} where all variable fragments contained within the variable f...

Definition AssignmentTrackingAnalysis.cpp:2114

static bool fullyContains(DIExpression::FragmentInfo A, DIExpression::FragmentInfo B)

Return true if A fully contains B.

Definition AssignmentTrackingAnalysis.cpp:2048

static std::optional< at::AssignmentInfo > getUntaggedStoreAssignmentInfo(const Instruction &I, const DataLayout &Layout)

Definition AssignmentTrackingAnalysis.cpp:2063

static bool removeUndefDbgLocsFromEntryBlock(const BasicBlock *BB, FunctionVarLocsBuilder &FnVarLocs)

Definition AssignmentTrackingAnalysis.cpp:2616

static cl::opt< bool > PrintResults("print-debug-ata", cl::init(false), cl::Hidden)

Print the results of the analysis. Respects -filter-print-funcs.

const char * locStr(AssignmentTrackingLowering::LocKind Loc)

Definition AssignmentTrackingAnalysis.cpp:1449

PointerUnion< const Instruction *, const DbgRecord * > VarLocInsertPt

Definition AssignmentTrackingAnalysis.cpp:86

static bool removeRedundantDbgLocsUsingForwardScan(const BasicBlock *BB, FunctionVarLocsBuilder &FnVarLocs)

Remove redundant location defs using a forward scan.

Definition AssignmentTrackingAnalysis.cpp:2557

static bool removeRedundantDbgLocs(const BasicBlock *BB, FunctionVarLocsBuilder &FnVarLocs)

Definition AssignmentTrackingAnalysis.cpp:2700

static cl::opt< bool > EnableMemLocFragFill("mem-loc-frag-fill", cl::init(true), cl::Hidden)

Option for debugging the pass, determines if the memory location fragment filling happens after gener...

static DIAssignID * getIDFromMarker(const DbgVariableRecord &DVR)

Definition AssignmentTrackingAnalysis.cpp:1427

static DebugAggregate getAggregate(const DebugVariable &Var)

Definition AssignmentTrackingAnalysis.cpp:326

static bool hasZeroSizedFragment(DbgVariableRecord &DbgValue)

Definition AssignmentTrackingAnalysis.cpp:1827

static DIAssignID * getIDFromInst(const Instruction &I)

Definition AssignmentTrackingAnalysis.cpp:1423

AllocaInst * getUnknownStore(const Instruction &I, const DataLayout &Layout)

Definition AssignmentTrackingAnalysis.cpp:2075

static std::optional< int64_t > getDerefOffsetInBytes(const DIExpression *DIExpr)

Extract the offset used in DIExpr.

Definition AssignmentTrackingAnalysis.cpp:283

static bool removeRedundantDbgLocsUsingBackwardScan(const BasicBlock *BB, FunctionVarLocsBuilder &FnVarLocs)

Remove redundant definitions within sequences of consecutive location defs.

Definition AssignmentTrackingAnalysis.cpp:2461

static cl::opt< cl::boolOrDefault > CoalesceAdjacentFragmentsOpt("debug-ata-coalesce-frags", cl::Hidden)

Coalesce adjacent dbg locs describing memory locations that have contiguous fragments.

static cl::opt< unsigned > MaxNumBlocks("debug-ata-max-blocks", cl::init(10000), cl::desc("Maximum num basic blocks before debug info dropped"), cl::Hidden)

static bool shouldCoalesceFragments(Function &F)

Definition AssignmentTrackingAnalysis.cpp:330

This file implements the BitVector class.

static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")

static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")

Analysis containing CSE Info

static ManagedStatic< cl::opt< bool, true >, CreateDebug > Debug

This file defines DenseMapInfo traits for DenseMap.

This file contains constants used for implementing Dwarf debug support.

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

This header defines various interfaces for pass management in LLVM.

This file implements a coalescing interval map for small objects.

const AbstractManglingParser< Derived, Alloc >::OperatorInfo AbstractManglingParser< Derived, Alloc >::Ops[]

IntervalMap< SlotIndex, DbgVariableValue, 4 > LocMap

Map of where a user value is live to that value.

print mir2vec MIR2Vec Vocabulary Printer Pass

uint64_t IntrinsicInst * II

FunctionAnalysisManager FAM

#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)

This file builds on the ADT/GraphTraits.h file to build a generic graph post order iterator.

static bool isValid(const char C)

Returns true if C is a valid mangled character: <0-9a-zA-Z_>.

Scalar Replacement Of Aggregates

This file defines the 'Statistic' class, which is designed to be an easy way to expose various metric...

#define STATISTIC(VARNAME, DESC)

Helper class to build FunctionVarLocs, since that class isn't easy to modify.

Definition AssignmentTrackingAnalysis.cpp:97

void setWedge(VarLocInsertPt Before, SmallVector< VarLocInfo > &&Wedge)

Replace the defs that come just before /p Before with /p Wedge.

Definition AssignmentTrackingAnalysis.cpp:129

const SmallVectorImpl< VarLocInfo > * getWedge(VarLocInsertPt Before) const

Return ptr to wedge of defs or nullptr if no defs come just before /p Before.

Definition AssignmentTrackingAnalysis.cpp:121

unsigned getNumVariables() const

Definition AssignmentTrackingAnalysis.cpp:107

void addSingleLocVar(DebugVariable Var, DIExpression *Expr, DebugLoc DL, RawLocationWrapper R)

Add a def for a variable that is valid for its lifetime.

Definition AssignmentTrackingAnalysis.cpp:134

VariableID insertVariable(DebugVariable V)

Find or insert V and return the ID.

Definition AssignmentTrackingAnalysis.cpp:110

void addVarLoc(VarLocInsertPt Before, DebugVariable Var, DIExpression *Expr, DebugLoc DL, RawLocationWrapper R)

Add a def to the wedge of defs just before /p Before.

Definition AssignmentTrackingAnalysis.cpp:145

const DebugVariable & getVariable(VariableID ID) const

Get a variable from its ID.

Definition AssignmentTrackingAnalysis.cpp:115

Class recording the (high level) value of a variable.

Class for arbitrary precision integers.

uint64_t getZExtValue() const

Get zero extended value.

bool getBoolValue() const

Convert APInt to a boolean value.

an instruction to allocate memory on the stack

ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...

AssignmentTrackingAnalysis()

Definition AssignmentTrackingAnalysis.cpp:2810

bool runOnFunction(Function &F) override

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

Definition AssignmentTrackingAnalysis.cpp:2787

LLVM Basic Block Representation.

iterator begin()

Instruction iterator methods.

LLVM_ABI bool isEntryBlock() const

Return true if this is the entry block of the containing function.

int find_first_unset_in(unsigned Begin, unsigned End) const

find_first_unset_in - Returns the index of the first unset bit in the range [Begin,...

iterator_range< const_set_bits_iterator > set_bits() const

A structured debug information entry.

static LLVM_ABI DIExpression * append(const DIExpression *Expr, ArrayRef< uint64_t > Ops)

Append the opcodes Ops to DIExpr.

unsigned getNumElements() const

DbgVariableFragmentInfo FragmentInfo

LLVM_ABI bool startsWithDeref() const

Return whether the first element a DW_OP_deref.

static LLVM_ABI std::optional< FragmentInfo > getFragmentInfo(expr_op_iterator Start, expr_op_iterator End)

Retrieve the details of this fragment expression.

ArrayRef< uint64_t > getElements() const

static LLVM_ABI std::optional< DIExpression * > createFragmentExpression(const DIExpression *Expr, unsigned OffsetInBits, unsigned SizeInBits)

Create a DIExpression to describe one part of an aggregate variable that is fragmented across multipl...

static LLVM_ABI DIExpression * prepend(const DIExpression *Expr, uint8_t Flags, int64_t Offset=0)

Prepend DIExpr with a deref and offset operation and optionally turn it into a stack value or/and an ...

static LLVM_ABI DIExpression * prependOpcodes(const DIExpression *Expr, SmallVectorImpl< uint64_t > &Ops, bool StackValue=false, bool EntryValue=false)

Prepend DIExpr with the given opcodes and optionally turn it into a stack value.

LLVM_ABI std::optional< uint64_t > getSizeInBits() const

Determines the size of the variable's type.

StringRef getName() const

A parsed version of the target data layout string in and methods for querying it.

LLVM_ABI unsigned getIndexTypeSizeInBits(Type *Ty) const

The size in bits of the index used in GEP calculation for this type.

Instruction * MarkedInstr

Link back to the Instruction that owns this marker.

LLVM_ABI iterator_range< simple_ilist< DbgRecord >::iterator > getDbgRecordRange()

Produce a range over all the DbgRecords in this Marker.

Base class for non-instruction debug metadata records that have positions within IR.

DebugLoc getDebugLoc() const

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

LLVM_ABI bool isKillAddress() const

Check whether this kills the address component.

LLVM_ABI DIAssignID * getAssignID() const

DIExpression * getExpression() const

DILocalVariable * getVariable() const

Metadata * getRawLocation() const

Returns the metadata operand for the first location description.

Result run(Function &F, FunctionAnalysisManager &FAM)

Definition AssignmentTrackingAnalysis.cpp:2762

PreservedAnalyses run(Function &F, FunctionAnalysisManager &FAM)

Definition AssignmentTrackingAnalysis.cpp:2781

LLVM_ABI DILocation * getInlinedAt() const

Identifies a unique instance of a variable.

const DILocation * getInlinedAt() const

const DILocalVariable * getVariable() const

iterator find(const_arg_type_t< KeyT > Val)

std::pair< iterator, bool > try_emplace(KeyT &&Key, Ts &&...Args)

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

void reserve(size_type NumEntries)

Grow the densemap so that it can contain at least NumEntries items before resizing again.

Implements a dense probed hash-table based set.

Class representing an expression and its matching format.

Data structure describing the variable locations in a function.

void print(raw_ostream &OS, const Function &Fn) const

Definition AssignmentTrackingAnalysis.cpp:156

const VarLocInfo * locs_begin(const Instruction *Before) const

First variable location definition that comes before Before.

const VarLocInfo * single_locs_begin() const

void clear()

Definition AssignmentTrackingAnalysis.cpp:252

const VarLocInfo * locs_end(const Instruction *Before) const

One past the last variable location definition that comes before Before.

const VarLocInfo * single_locs_end() const

One past the last single-location variable location definition.

void init(FunctionVarLocsBuilder &Builder)

Definition AssignmentTrackingAnalysis.cpp:205

const DataLayout & getDataLayout() const

Get the data layout of the module this function belongs to.

LLVMContext & getContext() const

getContext - Return a reference to the LLVMContext associated with this function.

bool isTerminator() const

const_iterator begin() const

void insert(KeyT a, KeyT b, ValT y)

insert - Add a mapping of [a;b] to y, coalesce with adjacent intervals.

void clear()

clear - Remove all entries.

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

void push_back(MachineInstr *MI)

Pass interface - Implemented by all 'passes'.

A discriminated union of two or more pointer types, with the discriminator in the low bit of the poin...

void * getOpaqueValue() const

static LLVM_ABI PoisonValue * get(Type *T)

Static factory methods - Return an 'poison' object of the specified type.

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.

Lightweight class that wraps the location operand metadata of a debug intrinsic.

size_type count(ConstPtrType Ptr) const

count - Return 1 if the specified pointer is in the set, 0 otherwise.

std::pair< iterator, bool > insert(PtrType Ptr)

Inserts Ptr if and only if there is no element in the container equal to Ptr.

SmallPtrSet - This class implements a set which is optimized for holding SmallSize or less elements.

This class consists of common code factored out of the SmallVector class to reduce code duplication b...

void push_back(const T &Elt)

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

static LLVM_ABI IntegerType * getInt1Ty(LLVMContext &C)

UniqueVector - This class produces a sequential ID number (base 1) for each unique entry that is adde...

unsigned insert(const T &Entry)

insert - Append entry to the vector if it doesn't already exist.

LLVM Value Representation.

LLVM_ABI StringRef getName() const

Return a constant reference to the value's name.

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

bool contains(const_arg_type_t< ValueT > V) const

Check if the set contains the given element.

size_type count(const_arg_type_t< ValueT > V) const

Return 1 if the specified key is in the set, 0 otherwise.

self_iterator getIterator()

NodeTy * getNextNode()

Get the next node, or nullptr for the list tail.

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

#define llvm_unreachable(msg)

Marks that the current location is not supposed to be reachable.

DenseMap< FragmentOfVar, SmallVector< DIExpression::FragmentInfo, 1 > > OverlapMap

constexpr std::underlying_type_t< E > Mask()

Get a bitmask with 1s in all places up to the high-order bit of E's largest value.

unsigned ID

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

@ Tail

Attemps to make calls as fast as possible while guaranteeing that tail call optimization can always b...

@ BasicBlock

Various leaf nodes.

LLVM_ABI void deleteAll(Function *F)

Remove all Assignment Tracking related intrinsics and metadata from F.

SmallVector< DbgVariableRecord * > getDVRAssignmentMarkers(const Instruction *Inst)

Return a range of dbg_assign records for which Inst performs the assignment they encode.

LLVM_ABI std::optional< AssignmentInfo > getAssignmentInfo(const DataLayout &DL, const MemIntrinsic *I)

LLVM_ABI bool calculateFragmentIntersect(const DataLayout &DL, const Value *Dest, uint64_t SliceOffsetInBits, uint64_t SliceSizeInBits, const DbgVariableRecord *DVRAssign, std::optional< DIExpression::FragmentInfo > &Result)

Calculate the fragment of the variable in DAI covered from (Dest + SliceOffsetInBits) to to (Dest + S...

initializer< Ty > init(const Ty &Val)

@ DW_OP_LLVM_fragment

Only used in LLVM metadata.

PointerTypeMap run(const Module &M)

Compute the PointerTypeMap for the module M.

friend class Instruction

Iterator for Instructions in a `BasicBlock.

This is an optimization pass for GlobalISel generic memory operations.

void dump(const SparseBitVector< ElementSize > &LHS, raw_ostream &out)

std::tuple< const DIScope *, const DIScope *, const DILocalVariable * > VarID

A unique key that represents a debug variable.

bool all_of(R &&range, UnaryPredicate P)

Provide wrappers to std::all_of which take ranges instead of having to pass begin/end explicitly.

Printable print(const GCNRegPressure &RP, const GCNSubtarget *ST=nullptr, unsigned DynamicVGPRBlockSize=0)

decltype(auto) dyn_cast(const From &Val)

dyn_cast - Return the argument parameter cast to the specified type.

auto successors(const MachineBasicBlock *BB)

bool operator!=(uint64_t V1, const APInt &V2)

bool operator==(const AddressRangeValuePair &LHS, const AddressRangeValuePair &RHS)

bool any_of(R &&range, UnaryPredicate P)

Provide wrappers to std::any_of which take ranges instead of having to pass begin/end explicitly.

auto reverse(ContainerTy &&C)

LLVM_ABI raw_ostream & dbgs()

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

bool isFunctionInPrintList(StringRef FunctionName)

VariableID

Type wrapper for integer ID for Variables. 0 is reserved.

class LLVM_GSL_OWNER SmallVector

Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...

bool isa(const From &Val)

isa - Return true if the parameter to the template is an instance of one of the template type argu...

LLVM_ATTRIBUTE_VISIBILITY_DEFAULT AnalysisKey InnerAnalysisManagerProxy< AnalysisManagerT, IRUnitT, ExtraArgTs... >::Key

LLVM_ABI raw_fd_ostream & errs()

This returns a reference to a raw_ostream for standard error.

constexpr T divideCeil(U Numerator, V Denominator)

Returns the integer ceil(Numerator / Denominator).

std::string join(IteratorT Begin, IteratorT End, StringRef Separator)

Joins the strings in the range [Begin, End), adding Separator between the elements.

LLVM_ABI bool isAssignmentTrackingEnabled(const Module &M)

Return true if assignment tracking is enabled for module M.

FunctionAddr VTableAddr Next

DWARFExpression::Operation Op

ArrayRef(const T &OneElt) -> ArrayRef< T >

std::string toString(const APInt &I, unsigned Radix, bool Signed, bool formatAsCLiteral=false, bool UpperCase=true, bool InsertSeparators=false)

decltype(auto) cast(const From &Val)

cast - Return the argument parameter cast to the specified type.

auto predecessors(const MachineBasicBlock *BB)

AnalysisManager< Function > FunctionAnalysisManager

Convenience typedef for the Function analysis manager.

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

Filter the DbgRecord range to DbgVariableRecord types only and downcast.

bool debuginfoShouldUseDebugInstrRef(const Triple &T)

Implement std::hash so that hash_code can be used in STL containers.

A special type used by analysis passes to provide an address that identifies that particular analysis...

static VariableID getTombstoneKey()

Definition AssignmentTrackingAnalysis.cpp:75

static bool isEqual(const VariableID &LHS, const VariableID &RHS)

Definition AssignmentTrackingAnalysis.cpp:81

static unsigned getHashValue(const VariableID &Val)

Definition AssignmentTrackingAnalysis.cpp:78

static VariableID getEmptyKey()

Definition AssignmentTrackingAnalysis.cpp:72

DenseMapInfo< unsigned > Wrapped

Definition AssignmentTrackingAnalysis.cpp:71

An information struct used to provide DenseMap with the various necessary components for a given valu...

Variable location definition used by FunctionVarLocs.

RawLocationWrapper Values

llvm::VariableID VariableID

std::size_t operator()(const VarLocInsertPt &Arg) const

Definition AssignmentTrackingAnalysis.cpp:89