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;
141 SingleLocVars.emplace_back(VarLoc);
142 }
143
144
149 VarLoc.Expr = Expr;
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) {
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 (.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 ->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 (->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;
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(.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 (.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 (.Source ||
.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 ()
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