41#include <unordered_map>
44#define DEBUG_TYPE "debug-ata"
46STATISTIC(NumDefsScanned,
"Number of dbg locs that get scanned for removal");
47STATISTIC(NumDefsRemoved,
"Number of dbg locs removed");
48STATISTIC(NumWedgesScanned,
"Number of dbg wedges scanned");
49STATISTIC(NumWedgesChanged,
"Number of dbg wedges changed");
53 cl::desc(
"Maximum num basic blocks before debug info dropped"),
74 return static_cast<VariableID>(Wrapped::getEmptyKey());
77 return Wrapped::getHashValue(
static_cast<unsigned>(Val));
96 friend FunctionVarLocs;
100 std::unordered_map<VarLocInsertPt, SmallVector<VarLocInfo>> VarLocsBeforeInst;
109 return static_cast<VariableID>(Variables.insert(V));
114 return Variables[
static_cast<unsigned>(
ID)];
120 auto R = VarLocsBeforeInst.find(Before);
121 if (R == VarLocsBeforeInst.end())
128 VarLocsBeforeInst[Before] = std::move(Wedge);
137 VarLoc.
DL = std::move(
DL);
139 SingleLocVars.emplace_back(VarLoc);
148 VarLoc.
DL = std::move(
DL);
150 VarLocsBeforeInst[Before].emplace_back(VarLoc);
157 unsigned Counter = -1;
158 OS <<
"=== Variables ===\n";
165 OS <<
"[" << Counter <<
"] " << V.getVariable()->getName();
166 if (
auto F = V.getFragment())
167 OS <<
" bits [" <<
F->OffsetInBits <<
", "
168 <<
F->OffsetInBits +
F->SizeInBits <<
")";
169 if (
const auto *IA = V.getInlinedAt())
170 OS <<
" inlined-at " << *IA;
175 OS <<
"DEF Var=[" << (
unsigned)
Loc.VariableID <<
"]"
176 <<
" Expr=" << *
Loc.Expr <<
" Values=(";
177 for (
auto *
Op :
Loc.Values.location_ops()) {
178 errs() <<
Op->getName() <<
" ";
184 OS <<
"=== Single location vars ===\n";
191 OS <<
"=== In-line variable defs ===";
193 OS <<
"\n" << BB.getName() <<
":\n";
205 for (
const auto &VarLoc : Builder.SingleLocVars)
206 VarLocRecords.emplace_back(VarLoc);
208 SingleVarLocEnd = VarLocRecords.size();
214 for (
auto &
P : Builder.VarLocsBeforeInst) {
220 unsigned BlockStart = VarLocRecords.size();
227 auto It = Builder.VarLocsBeforeInst.find(&DVR);
228 if (It == Builder.VarLocsBeforeInst.end())
231 VarLocRecords.emplace_back(VarLoc);
234 VarLocRecords.emplace_back(VarLoc);
235 unsigned BlockEnd = VarLocRecords.size();
237 if (BlockEnd != BlockStart)
238 VarLocsBeforeInst[
I] = {BlockStart, BlockEnd};
242 assert(Variables.empty() &&
"Expect clear before init");
245 Variables.reserve(Builder.Variables.size() + 1);
246 Variables.push_back(
DebugVariable(
nullptr, std::nullopt,
nullptr));
247 Variables.append(Builder.Variables.begin(), Builder.Variables.end());
252 VarLocRecords.clear();
253 VarLocsBeforeInst.clear();
261static std::pair<Value *, DIExpression *>
264 APInt OffsetInBytes(
DL.getTypeSizeInBits(Start->getType()),
false);
266 Start->stripAndAccumulateInBoundsConstantOffsets(
DL, OffsetInBytes);
280static std::optional<int64_t>
285 unsigned ExpectedDerefIdx = 0;
287 if (NumElements > 2 && Elements[0] == dwarf::DW_OP_plus_uconst) {
289 ExpectedDerefIdx = 2;
290 }
else if (NumElements > 3 && Elements[0] == dwarf::DW_OP_constu) {
291 ExpectedDerefIdx = 3;
292 if (Elements[2] == dwarf::DW_OP_plus)
294 else if (Elements[2] == dwarf::DW_OP_minus)
301 if (ExpectedDerefIdx >= NumElements)
306 if (Elements[ExpectedDerefIdx] != dwarf::DW_OP_deref)
310 if (NumElements == ExpectedDerefIdx + 1)
312 unsigned ExpectedFragFirstIdx = ExpectedDerefIdx + 1;
313 unsigned ExpectedFragFinalIdx = ExpectedFragFirstIdx + 2;
314 if (NumElements == ExpectedFragFinalIdx + 1 &&
364class MemLocFragmentFill {
366 FunctionVarLocsBuilder *FnVarLocs;
367 const DenseSet<DebugAggregate> *VarsWithStackSlot;
368 bool CoalesceAdjacentFragments;
371 using BaseAddress = unsigned;
372 using OffsetInBitsTy = unsigned;
373 using FragTraits = IntervalMapHalfOpenInfo<OffsetInBitsTy>;
374 using FragsInMemMap = IntervalMap<
375 OffsetInBitsTy, BaseAddress,
376 IntervalMapImpl::NodeSizer<OffsetInBitsTy, BaseAddress>::LeafSize,
378 FragsInMemMap::Allocator IntervalMapAlloc;
379 using VarFragMap = DenseMap<unsigned, FragsInMemMap>;
383 UniqueVector<RawLocationWrapper> Bases;
385 DenseMap<const BasicBlock *, VarFragMap> LiveIn;
386 DenseMap<const BasicBlock *, VarFragMap> LiveOut;
391 unsigned OffsetInBits;
395 using InsertMap = MapVector<VarLocInsertPt, SmallVector<FragMemLoc>>;
402 DenseMap<const BasicBlock *, InsertMap> BBInsertBeforeMap;
404 static bool intervalMapsAreEqual(
const FragsInMemMap &
A,
405 const FragsInMemMap &
B) {
406 auto AIt =
A.
begin(), AEnd =
A.end();
407 auto BIt =
B.begin(), BEnd =
B.end();
408 for (; AIt != AEnd; ++AIt, ++BIt) {
411 if (AIt.start() != BIt.start() || AIt.stop() != BIt.stop())
420 static bool varFragMapsAreEqual(
const VarFragMap &
A,
const VarFragMap &
B) {
421 if (
A.size() !=
B.size())
423 for (
const auto &APair :
A) {
424 auto BIt =
B.find(APair.first);
427 if (!intervalMapsAreEqual(APair.second, BIt->second))
434 std::string
toString(
unsigned BaseID) {
436 return Bases[BaseID].getVariableLocationOp(0)->getName().str();
442 std::string
toString(FragsInMemMap::const_iterator It,
bool Newline =
true) {
444 std::stringstream S(
String);
446 S <<
"[" << It.start() <<
", " << It.stop()
449 S <<
"invalid iterator (end)";
456 FragsInMemMap meetFragments(
const FragsInMemMap &
A,
const FragsInMemMap &
B) {
457 FragsInMemMap
Result(IntervalMapAlloc);
458 for (
auto AIt =
A.begin(), AEnd =
A.end(); AIt != AEnd; ++AIt) {
465 if (!
B.overlaps(AIt.start(), AIt.stop()))
469 auto FirstOverlap =
B.find(AIt.start());
470 assert(FirstOverlap !=
B.end());
471 bool IntersectStart = FirstOverlap.start() < AIt.start();
473 <<
", IntersectStart: " << IntersectStart <<
"\n");
476 auto LastOverlap =
B.find(AIt.stop());
478 LastOverlap !=
B.end() && LastOverlap.start() < AIt.stop();
480 <<
", IntersectEnd: " << IntersectEnd <<
"\n");
483 if (IntersectStart && IntersectEnd && FirstOverlap == LastOverlap) {
491 if (*AIt && *AIt == *FirstOverlap)
492 Result.insert(AIt.start(), AIt.stop(), *AIt);
500 auto Next = FirstOverlap;
501 if (IntersectStart) {
504 if (*AIt && *AIt == *FirstOverlap)
505 Result.insert(AIt.start(), FirstOverlap.stop(), *AIt);
515 if (*AIt && *AIt == *LastOverlap)
516 Result.insert(LastOverlap.start(), AIt.stop(), *AIt);
525 while (
Next !=
B.end() &&
Next.start() < AIt.stop() &&
526 Next.stop() <= AIt.stop()) {
528 <<
"- insert intersection of a and " <<
toString(
Next));
529 if (*AIt && *AIt == *
Next)
539 void meetVars(VarFragMap &
A,
const VarFragMap &
B) {
543 A.remove_if([&](
auto &Entry) {
544 auto BIt =
B.find(
Entry.first);
549 Entry.second = meetFragments(
Entry.second, BIt->second);
554 bool meet(
const BasicBlock &BB,
555 const SmallPtrSet<BasicBlock *, 16> &Visited) {
560 bool FirstMeet =
true;
567 if (!Visited.
count(Pred))
570 auto PredLiveOut = LiveOut.
find(Pred);
575 BBLiveIn = PredLiveOut->second;
578 LLVM_DEBUG(
dbgs() <<
"BBLiveIn = meet BBLiveIn, " << Pred->getName()
580 meetVars(BBLiveIn, PredLiveOut->second);
586 if (BBLiveIn.size() == 0)
595 CurrentLiveInEntry->second = std::move(BBLiveIn);
601 if (!varFragMapsAreEqual(BBLiveIn, CurrentLiveInEntry->second)) {
603 CurrentLiveInEntry->second = std::move(BBLiveIn);
611 void insertMemLoc(BasicBlock &BB,
VarLocInsertPt Before,
unsigned Var,
612 unsigned StartBit,
unsigned EndBit,
unsigned Base,
614 assert(StartBit < EndBit &&
"Cannot create fragment of size <= 0");
619 Loc.OffsetInBits = StartBit;
620 Loc.SizeInBits = EndBit - StartBit;
621 assert(
Base &&
"Expected a non-zero ID for Base address");
624 BBInsertBeforeMap[&BB][Before].push_back(Loc);
626 <<
" bits [" << StartBit <<
", " << EndBit <<
")\n");
633 void coalesceFragments(BasicBlock &BB,
VarLocInsertPt Before,
unsigned Var,
634 unsigned StartBit,
unsigned EndBit,
unsigned Base,
636 if (!CoalesceAdjacentFragments)
643 auto CoalescedFrag = FragMap.find(StartBit);
645 if (CoalescedFrag.start() == StartBit && CoalescedFrag.stop() == EndBit)
648 LLVM_DEBUG(
dbgs() <<
"- Insert loc for bits " << CoalescedFrag.start()
649 <<
" to " << CoalescedFrag.stop() <<
"\n");
650 insertMemLoc(BB, Before, Var, CoalescedFrag.start(), CoalescedFrag.stop(),
654 void addDef(
const VarLocInfo &VarLoc,
VarLocInsertPt Before, BasicBlock &BB,
655 VarFragMap &LiveSet) {
668 const DIExpression *DIExpr = VarLoc.
Expr;
672 StartBit = Frag->OffsetInBits;
673 EndBit = StartBit + Frag->SizeInBits;
688 const unsigned Base =
689 DerefOffsetInBytes && *DerefOffsetInBytes * 8 == StartBit
693 << StartBit <<
", " << EndBit <<
"): " <<
toString(
Base)
700 auto FragIt = LiveSet.find(Var);
703 if (FragIt == LiveSet.end()) {
705 auto P = LiveSet.try_emplace(Var, FragsInMemMap(IntervalMapAlloc));
706 assert(
P.second &&
"Var already in map?");
708 P.first->second.insert(StartBit, EndBit,
Base);
713 FragsInMemMap &FragMap = FragIt->second;
716 if (!FragMap.overlaps(StartBit, EndBit)) {
718 FragMap.insert(StartBit, EndBit,
Base);
719 coalesceFragments(BB, Before, Var, StartBit, EndBit,
Base, VarLoc.
DL,
726 auto FirstOverlap = FragMap.find(StartBit);
727 assert(FirstOverlap != FragMap.end());
728 bool IntersectStart = FirstOverlap.start() < StartBit;
731 auto LastOverlap = FragMap.find(EndBit);
732 bool IntersectEnd = LastOverlap.valid() && LastOverlap.start() < EndBit;
735 if (IntersectStart && IntersectEnd && FirstOverlap == LastOverlap) {
736 LLVM_DEBUG(
dbgs() <<
"- Intersect single interval @ both ends\n");
744 auto EndBitOfOverlap = FirstOverlap.stop();
745 unsigned OverlapValue = FirstOverlap.value();
748 FirstOverlap.setStop(StartBit);
749 insertMemLoc(BB, Before, Var, FirstOverlap.start(), StartBit,
750 OverlapValue, VarLoc.
DL);
753 FragMap.insert(EndBit, EndBitOfOverlap, OverlapValue);
754 insertMemLoc(BB, Before, Var, EndBit, EndBitOfOverlap, OverlapValue,
758 FragMap.insert(StartBit, EndBit,
Base);
768 if (IntersectStart) {
771 FirstOverlap.setStop(StartBit);
772 insertMemLoc(BB, Before, Var, FirstOverlap.start(), StartBit,
773 *FirstOverlap, VarLoc.
DL);
782 LastOverlap.setStart(EndBit);
783 insertMemLoc(BB, Before, Var, EndBit, LastOverlap.stop(), *LastOverlap,
799 auto It = FirstOverlap;
802 while (It.valid() && It.start() >= StartBit && It.stop() <= EndBit) {
807 assert(!FragMap.overlaps(StartBit, EndBit));
809 FragMap.insert(StartBit, EndBit,
Base);
812 coalesceFragments(BB, Before, Var, StartBit, EndBit,
Base, VarLoc.
DL,
816 bool skipVariable(
const DILocalVariable *V) {
return !
V->getSizeInBits(); }
818 void process(BasicBlock &BB, VarFragMap &LiveSet) {
819 BBInsertBeforeMap[&BB].
clear();
821 for (DbgVariableRecord &DVR :
filterDbgVars(
I.getDbgRecordRange())) {
822 if (
const auto *Locs = FnVarLocs->
getWedge(&DVR)) {
823 for (
const VarLocInfo &Loc : *Locs) {
824 addDef(Loc, &DVR, *
I.getParent(), LiveSet);
828 if (
const auto *Locs = FnVarLocs->
getWedge(&
I)) {
829 for (
const VarLocInfo &Loc : *Locs) {
830 addDef(Loc, &
I, *
I.getParent(), LiveSet);
837 MemLocFragmentFill(Function &Fn,
838 const DenseSet<DebugAggregate> *VarsWithStackSlot,
839 bool CoalesceAdjacentFragments)
840 : Fn(Fn), VarsWithStackSlot(VarsWithStackSlot),
841 CoalesceAdjacentFragments(CoalesceAdjacentFragments) {}
863 void run(FunctionVarLocsBuilder *FnVarLocs) {
867 this->FnVarLocs = FnVarLocs;
871 ReversePostOrderTraversal<Function *> RPOT(&Fn);
872 std::priority_queue<unsigned int, std::vector<unsigned int>,
873 std::greater<unsigned int>>
875 std::priority_queue<unsigned int, std::vector<unsigned int>,
876 std::greater<unsigned int>>
878 DenseMap<unsigned int, BasicBlock *> OrderToBB;
879 DenseMap<BasicBlock *, unsigned int> BBToOrder;
881 unsigned int RPONumber = 0;
882 for (BasicBlock *BB : RPOT) {
883 OrderToBB[RPONumber] = BB;
884 BBToOrder[BB] = RPONumber;
885 Worklist.push(RPONumber);
901 SmallPtrSet<BasicBlock *, 16> Visited;
902 while (!Worklist.empty() || !Pending.empty()) {
906 SmallPtrSet<BasicBlock *, 16> OnPending;
908 while (!Worklist.empty()) {
912 bool InChanged = meet(*BB, Visited);
914 InChanged |= Visited.
insert(BB).second;
917 << BB->
getName() <<
" has new InLocs, process it\n");
921 VarFragMap LiveSet = LiveIn[BB];
924 process(*BB, LiveSet);
927 if (!varFragMapsAreEqual(LiveOut[BB], LiveSet)) {
929 <<
" has new OutLocs, add succs to worklist: [ ");
930 LiveOut[BB] = std::move(LiveSet);
932 if (OnPending.
insert(Succ).second) {
934 Pending.push(BBToOrder[Succ]);
941 Worklist.swap(Pending);
944 assert(Pending.empty() &&
"Pending should be empty");
948 for (
auto &Pair : BBInsertBeforeMap) {
949 InsertMap &
Map = Pair.second;
950 for (
auto &Pair : Map) {
951 auto InsertBefore = Pair.first;
952 assert(InsertBefore &&
"should never be null");
953 auto FragMemLocs = Pair.second;
956 for (
auto &FragMemLoc : FragMemLocs) {
957 DIExpression *Expr = DIExpression::get(Ctx, {});
958 if (FragMemLoc.SizeInBits !=
959 *
Aggregates[FragMemLoc.Var].first->getSizeInBits())
961 Expr, FragMemLoc.OffsetInBits, FragMemLoc.SizeInBits);
963 FragMemLoc.OffsetInBits / 8);
964 DebugVariable Var(
Aggregates[FragMemLoc.Var].first, Expr,
965 FragMemLoc.DL.getInlinedAt());
966 FnVarLocs->
addVarLoc(InsertBefore, Var, Expr, FragMemLoc.DL,
967 Bases[FragMemLoc.Base]);
977class AssignmentTrackingLowering {
1002 enum class LocKind { Mem, Val,
None };
1019 enum S { Known, NoneOrPhi } Status;
1024 DbgVariableRecord *
Source =
nullptr;
1026 bool isSameSourceAssignment(
const Assignment &
Other)
const {
1029 return std::tie(Status,
ID) == std::tie(
Other.Status,
Other.ID);
1031 void dump(raw_ostream &OS) {
1032 static const char *
LUT[] = {
"Known",
"NoneOrPhi"};
1033 OS <<
LUT[Status] <<
"(id=";
1046 static Assignment make(DIAssignID *
ID, DbgVariableRecord *Source) {
1048 "Cannot make an assignment from a non-assign DbgVariableRecord");
1049 return Assignment(Known,
ID, Source);
1051 static Assignment makeFromMemDef(DIAssignID *
ID) {
1052 return Assignment(Known,
ID);
1054 static Assignment makeNoneOrPhi() {
return Assignment(NoneOrPhi,
nullptr); }
1056 Assignment() : Status(NoneOrPhi),
ID(nullptr) {}
1057 Assignment(S Status, DIAssignID *
ID) : Status(Status),
ID(
ID) {
1061 Assignment(S Status, DIAssignID *
ID, DbgVariableRecord *Source)
1068 using AssignmentMap = SmallVector<Assignment>;
1069 using LocMap = SmallVector<LocKind>;
1070 using OverlapMap = DenseMap<VariableID, SmallVector<VariableID>>;
1071 using UntaggedStoreAssignmentMap =
1074 using UnknownStoreAssignmentMap =
1075 DenseMap<const Instruction *, SmallVector<VariableID>>;
1076 using EscapingCallVarsMap =
1083 unsigned TrackedVariablesVectorSize = 0;
1088 UntaggedStoreAssignmentMap UntaggedStoreVars;
1091 UnknownStoreAssignmentMap UnknownStoreVars;
1095 EscapingCallVarsMap EscapingCallVars;
1098 using InstInsertMap = MapVector<VarLocInsertPt, SmallVector<VarLocInfo>>;
1099 InstInsertMap InsertBeforeMap;
1102 void resetInsertionPoint(Instruction &After);
1103 void resetInsertionPoint(DbgVariableRecord &After);
1105 void emitDbgValue(LocKind Kind, DbgVariableRecord *,
VarLocInsertPt After);
1107 static bool mapsAreEqual(
const BitVector &Mask,
const AssignmentMap &
A,
1108 const AssignmentMap &
B) {
1110 return A[VarID].isSameSourceAssignment(B[VarID]);
1119 BitVector VariableIDsInBlock;
1122 AssignmentMap StackHomeValue;
1124 AssignmentMap DebugValue;
1139 const AssignmentMap &getAssignmentMap(AssignmentKind Kind)
const {
1142 return StackHomeValue;
1148 AssignmentMap &getAssignmentMap(AssignmentKind Kind) {
1149 return const_cast<AssignmentMap &
>(
1150 const_cast<const BlockInfo *
>(
this)->getAssignmentMap(Kind));
1153 bool isVariableTracked(
VariableID Var)
const {
1154 return VariableIDsInBlock[
static_cast<unsigned>(Var)];
1157 const Assignment &getAssignment(AssignmentKind Kind,
VariableID Var)
const {
1158 assert(isVariableTracked(Var) &&
"Var not tracked in block");
1159 return getAssignmentMap(Kind)[
static_cast<unsigned>(Var)];
1163 assert(isVariableTracked(Var) &&
"Var not tracked in block");
1164 return LiveLoc[
static_cast<unsigned>(Var)];
1170 VariableIDsInBlock.
set(
static_cast<unsigned>(Var));
1171 LiveLoc[
static_cast<unsigned>(Var)] = K;
1177 void setAssignment(AssignmentKind Kind,
VariableID Var,
1178 const Assignment &AV) {
1179 VariableIDsInBlock.
set(
static_cast<unsigned>(Var));
1180 getAssignmentMap(Kind)[
static_cast<unsigned>(Var)] = AV;
1186 bool hasAssignment(AssignmentKind Kind,
VariableID Var,
1187 const Assignment &AV)
const {
1188 if (!isVariableTracked(Var))
1190 return AV.isSameSourceAssignment(getAssignment(Kind, Var));
1196 return VariableIDsInBlock ==
Other.VariableIDsInBlock &&
1197 LiveLoc ==
Other.LiveLoc &&
1198 mapsAreEqual(VariableIDsInBlock, StackHomeValue,
1199 Other.StackHomeValue) &&
1200 mapsAreEqual(VariableIDsInBlock, DebugValue,
Other.DebugValue);
1204 return LiveLoc.size() == DebugValue.size() &&
1205 LiveLoc.size() == StackHomeValue.size();
1209 void init(
int NumVars) {
1210 StackHomeValue.clear();
1213 VariableIDsInBlock = BitVector(NumVars);
1214 StackHomeValue.insert(StackHomeValue.begin(), NumVars,
1215 Assignment::makeNoneOrPhi());
1216 DebugValue.insert(DebugValue.begin(), NumVars,
1217 Assignment::makeNoneOrPhi());
1218 LiveLoc.
insert(LiveLoc.
begin(), NumVars, LocKind::None);
1222 template <
typename ElmtType,
typename FnInputType>
1226 ElmtType (*Fn)(FnInputType, FnInputType)) {
1231 static BlockInfo
join(
const BlockInfo &
A,
const BlockInfo &
B,
int NumVars) {
1250 BitVector Intersect =
A.VariableIDsInBlock;
1251 Intersect &=
B.VariableIDsInBlock;
1254 joinElmt(
VarID, Join.LiveLoc,
A.LiveLoc,
B.LiveLoc, joinKind);
1255 joinElmt(
VarID, Join.DebugValue,
A.DebugValue,
B.DebugValue,
1257 joinElmt(
VarID, Join.StackHomeValue,
A.StackHomeValue,
B.StackHomeValue,
1261 Join.VariableIDsInBlock =
A.VariableIDsInBlock;
1262 Join.VariableIDsInBlock |=
B.VariableIDsInBlock;
1269 const DataLayout &Layout;
1270 const DenseSet<DebugAggregate> *VarsWithStackSlot;
1271 FunctionVarLocsBuilder *FnVarLocs;
1272 DenseMap<const BasicBlock *, BlockInfo> LiveIn;
1273 DenseMap<const BasicBlock *, BlockInfo> LiveOut;
1276 DenseSet<VariableID> VarsTouchedThisFrame;
1279 DenseSet<DebugAggregate> NotAlwaysStackHomed;
1281 VariableID getVariableID(
const DebugVariable &Var) {
1289 bool join(
const BasicBlock &BB,
const SmallPtrSet<BasicBlock *, 16> &Visited);
1309 static LocKind joinKind(LocKind
A, LocKind
B);
1310 static Assignment joinAssignment(
const Assignment &
A,
const Assignment &
B);
1311 BlockInfo joinBlockInfo(
const BlockInfo &
A,
const BlockInfo &
B);
1317 void process(BasicBlock &BB, BlockInfo *LiveSet);
1322 void processNonDbgInstruction(Instruction &
I, BlockInfo *LiveSet);
1325 void processTaggedInstruction(Instruction &
I, BlockInfo *LiveSet);
1328 void processUntaggedInstruction(Instruction &
I, BlockInfo *LiveSet);
1329 void processUnknownStoreToVariable(Instruction &
I,
VariableID &Var,
1330 BlockInfo *LiveSet);
1331 void processEscapingCall(Instruction &
I, BlockInfo *LiveSet);
1332 void processDbgAssign(DbgVariableRecord *Assign, BlockInfo *LiveSet);
1333 void processDbgVariableRecord(DbgVariableRecord &DVR, BlockInfo *LiveSet);
1334 void processDbgValue(DbgVariableRecord *DbgValue, BlockInfo *LiveSet);
1336 void addMemDef(BlockInfo *LiveSet,
VariableID Var,
const Assignment &AV);
1338 void addDbgDef(BlockInfo *LiveSet,
VariableID Var,
const Assignment &AV);
1342 void setLocKind(BlockInfo *LiveSet,
VariableID Var, LocKind K);
1345 LocKind getLocKind(BlockInfo *LiveSet,
VariableID Var);
1347 bool hasVarWithAssignment(BlockInfo *LiveSet, BlockInfo::AssignmentKind Kind,
1358 bool emitPromotedVarLocs(FunctionVarLocsBuilder *FnVarLocs);
1361 AssignmentTrackingLowering(Function &Fn,
const DataLayout &Layout,
1362 const DenseSet<DebugAggregate> *VarsWithStackSlot)
1363 : Fn(Fn), Layout(Layout), VarsWithStackSlot(VarsWithStackSlot) {}
1366 bool run(FunctionVarLocsBuilder *FnVarLocs);
1371AssignmentTrackingLowering::getContainedFragments(
VariableID Var)
const {
1372 auto R = VarContains.find(Var);
1373 if (R == VarContains.end())
1378void AssignmentTrackingLowering::touchFragment(
VariableID Var) {
1379 VarsTouchedThisFrame.insert(Var);
1382void AssignmentTrackingLowering::setLocKind(BlockInfo *LiveSet,
VariableID Var,
1384 auto SetKind = [
this](BlockInfo *LiveSet,
VariableID Var, LocKind
K) {
1385 LiveSet->setLocKind(Var, K);
1388 SetKind(LiveSet, Var, K);
1391 for (
VariableID Frag : getContainedFragments(Var))
1392 SetKind(LiveSet, Frag, K);
1395AssignmentTrackingLowering::LocKind
1396AssignmentTrackingLowering::getLocKind(BlockInfo *LiveSet,
VariableID Var) {
1397 return LiveSet->getLocKind(Var);
1400void AssignmentTrackingLowering::addMemDef(BlockInfo *LiveSet,
VariableID Var,
1401 const Assignment &AV) {
1402 LiveSet->setAssignment(BlockInfo::Stack, Var, AV);
1407 Assignment FragAV = AV;
1408 FragAV.Source =
nullptr;
1409 for (
VariableID Frag : getContainedFragments(Var))
1410 LiveSet->setAssignment(BlockInfo::Stack, Frag, FragAV);
1413void AssignmentTrackingLowering::addDbgDef(BlockInfo *LiveSet,
VariableID Var,
1414 const Assignment &AV) {
1415 LiveSet->setAssignment(BlockInfo::Debug, Var, AV);
1420 Assignment FragAV = AV;
1421 FragAV.Source =
nullptr;
1422 for (
VariableID Frag : getContainedFragments(Var))
1423 LiveSet->setAssignment(BlockInfo::Debug, Frag, FragAV);
1432 "Cannot get a DIAssignID from a non-assign DbgVariableRecord!");
1437bool AssignmentTrackingLowering::hasVarWithAssignment(
1438 BlockInfo *LiveSet, BlockInfo::AssignmentKind Kind,
VariableID Var,
1439 const Assignment &AV) {
1440 if (!LiveSet->hasAssignment(Kind, Var, AV))
1445 for (
VariableID Frag : getContainedFragments(Var))
1446 if (!LiveSet->hasAssignment(Kind, Frag, AV))
1452const char *
locStr(AssignmentTrackingLowering::LocKind
Loc) {
1453 using LocKind = AssignmentTrackingLowering::LocKind;
1474 if (!
Next->hasDbgRecords())
1476 return &*
Next->getDbgRecordRange().begin();
1484void AssignmentTrackingLowering::emitDbgValue(
1497 assert(InsertBefore &&
"Shouldn't be inserting after a terminator");
1506 InsertBeforeMap[InsertBefore].
push_back(VarLoc);
1510 if (Kind == LocKind::Mem) {
1515 if (
Assign->isKillAddress()) {
1517 Kind = LocKind::Val;
1522 "fragment info should be stored in value-expression only");
1525 if (
auto OptFragInfo =
Source->getExpression()->getFragmentInfo()) {
1526 auto FragInfo = *OptFragInfo;
1528 Expr, FragInfo.OffsetInBits, FragInfo.SizeInBits);
1531 std::tie(Val, Expr) =
1538 if (Kind == LocKind::Val) {
1539 Emit(
Source->getRawLocation(),
Source->getExpression());
1543 if (Kind == LocKind::None) {
1544 Emit(
nullptr,
Source->getExpression());
1549void AssignmentTrackingLowering::processNonDbgInstruction(
1550 Instruction &
I, AssignmentTrackingLowering::BlockInfo *LiveSet) {
1551 if (
I.hasMetadata(LLVMContext::MD_DIAssignID))
1552 processTaggedInstruction(
I, LiveSet);
1554 processUntaggedInstruction(
I, LiveSet);
1559 processEscapingCall(
I, LiveSet);
1562void AssignmentTrackingLowering::processUnknownStoreToVariable(
1566 addMemDef(LiveSet, Var, Assignment::makeNoneOrPhi());
1569 if (getLocKind(LiveSet, Var) != LocKind::Mem)
1573 Assignment DbgAV = LiveSet->getAssignment(BlockInfo::Debug, Var);
1574 if (DbgAV.Status != Assignment::NoneOrPhi && DbgAV.Source) {
1576 DbgAV.dump(
dbgs());
dbgs() <<
"\n");
1577 setLocKind(LiveSet, Var, LocKind::Val);
1578 emitDbgValue(LocKind::Val, DbgAV.Source, &
I);
1584 assert(InsertBefore &&
"Shouldn't be inserting after a terminator");
1590 Fn.
getContext(), 0, 0,
V.getVariable()->getScope(), InlinedAt);
1598 InsertBeforeMap[InsertBefore].push_back(VarLoc);
1601void AssignmentTrackingLowering::processUntaggedInstruction(
1602 Instruction &
I, AssignmentTrackingLowering::BlockInfo *LiveSet) {
1614 assert(!
I.hasMetadata(LLVMContext::MD_DIAssignID));
1615 auto It = UntaggedStoreVars.find(&
I);
1616 if (It == UntaggedStoreVars.end()) {
1623 if (
auto UnhandledStoreIt = UnknownStoreVars.find(&
I);
1624 UnhandledStoreIt != UnknownStoreVars.end()) {
1625 LLVM_DEBUG(
dbgs() <<
"Processing untagged unknown store " <<
I <<
"\n");
1626 for (
auto &Var : UnhandledStoreIt->second)
1627 processUnknownStoreToVariable(
I, Var, LiveSet);
1632 LLVM_DEBUG(
dbgs() <<
"processUntaggedInstruction on UNTAGGED INST " <<
I
1636 for (
auto [Var, Info] : It->second) {
1640 addMemDef(LiveSet, Var, Assignment::makeNoneOrPhi());
1641 addDbgDef(LiveSet, Var, Assignment::makeNoneOrPhi());
1642 setLocKind(LiveSet, Var, LocKind::Mem);
1650 if (
auto Frag =
V.getFragment()) {
1653 assert(R &&
"unexpected createFragmentExpression failure");
1657 if (
Info.OffsetInBits)
1658 Ops = {dwarf::DW_OP_plus_uconst,
Info.OffsetInBits / 8};
1665 assert(InsertBefore &&
"Shouldn't be inserting after a terminator");
1670 Fn.
getContext(), 0, 0,
V.getVariable()->getScope(), InlinedAt);
1679 InsertBeforeMap[InsertBefore].push_back(VarLoc);
1683void AssignmentTrackingLowering::processEscapingCall(
1684 Instruction &
I, AssignmentTrackingLowering::BlockInfo *LiveSet) {
1685 auto It = EscapingCallVars.find(&
I);
1686 if (It == EscapingCallVars.end())
1693 for (
auto &[Var, Addr, AddrExpr] : It->second) {
1699 addMemDef(LiveSet, Var, Assignment::makeNoneOrPhi());
1700 addDbgDef(LiveSet, Var, Assignment::makeNoneOrPhi());
1701 setLocKind(LiveSet, Var, LocKind::Mem);
1705 <<
", setting LocKind to Mem\n");
1712 if (
auto Frag =
V.getFragment()) {
1715 assert(R &&
"unexpected createFragmentExpression failure");
1723 assert(InsertBefore &&
"Shouldn't be inserting after a terminator");
1727 Fn.
getContext(), 0, 0,
V.getVariable()->getScope(), InlinedAt);
1735 InsertBeforeMap[InsertBefore].push_back(VarLoc);
1739void AssignmentTrackingLowering::processTaggedInstruction(
1740 Instruction &
I, AssignmentTrackingLowering::BlockInfo *LiveSet) {
1746 if (LinkedDPAssigns.empty())
1755 "expected Assign's variable to have stack slot");
1758 addMemDef(LiveSet, Var, AV);
1766 if (hasVarWithAssignment(LiveSet, BlockInfo::Debug, Var, AV)) {
1772 LiveSet->DebugValue[
static_cast<unsigned>(Var)].dump(
dbgs());
1774 setLocKind(LiveSet, Var, LocKind::Mem);
1775 emitDbgValue(LocKind::Mem, Assign, &
I);
1784 LocKind PrevLoc = getLocKind(LiveSet, Var);
1786 case LocKind::Val: {
1790 setLocKind(LiveSet, Var, LocKind::Val);
1792 case LocKind::Mem: {
1796 Assignment DbgAV = LiveSet->getAssignment(BlockInfo::Debug, Var);
1797 if (DbgAV.Status == Assignment::NoneOrPhi) {
1800 setLocKind(LiveSet, Var, LocKind::None);
1801 emitDbgValue(LocKind::None, Assign, &
I);
1805 setLocKind(LiveSet, Var, LocKind::Val);
1807 emitDbgValue(LocKind::Val, DbgAV.Source, &
I);
1810 emitDbgValue(LocKind::None, Assign, &
I);
1814 case LocKind::None: {
1818 setLocKind(LiveSet, Var, LocKind::None);
1825 BlockInfo *LiveSet) {
1832 Assignment AV = Assignment::make(
getIDFromMarker(*DbgAssign), DbgAssign);
1833 addDbgDef(LiveSet, Var, AV);
1835 LLVM_DEBUG(
dbgs() <<
"processDbgAssign on " << *DbgAssign <<
"\n";);
1841 if (hasVarWithAssignment(LiveSet, BlockInfo::Stack, Var, AV)) {
1849 <<
"Val, Stack matches Debug program but address is killed\n";);
1850 Kind = LocKind::Val;
1853 Kind = LocKind::Mem;
1855 setLocKind(LiveSet, Var, Kind);
1856 emitDbgValue(Kind, DbgAssign, DbgAssign);
1861 setLocKind(LiveSet, Var, LocKind::Val);
1862 emitDbgValue(LocKind::Val, DbgAssign, DbgAssign);
1867 BlockInfo *LiveSet) {
1880 Assignment AV = Assignment::makeNoneOrPhi();
1881 addDbgDef(LiveSet, Var, AV);
1885 <<
" -> Val, dbg.value override");
1887 setLocKind(LiveSet, Var, LocKind::Val);
1892 if (
auto F =
DbgValue.getExpression()->getFragmentInfo())
1893 return F->SizeInBits == 0;
1897void AssignmentTrackingLowering::processDbgVariableRecord(
1904 processDbgAssign(&DVR, LiveSet);
1906 processDbgValue(&DVR, LiveSet);
1909void AssignmentTrackingLowering::resetInsertionPoint(
Instruction &After) {
1912 if (R == InsertBeforeMap.end())
1918 if (R == InsertBeforeMap.end())
1923void AssignmentTrackingLowering::process(
BasicBlock &BB, BlockInfo *LiveSet) {
1926 bool ProcessedLeadingDbgRecords = !BB.
begin()->hasDbgRecords();
1928 assert(VarsTouchedThisFrame.empty());
1935 if (ProcessedLeadingDbgRecords) {
1940 if (
II->isTerminator())
1942 resetInsertionPoint(*
II);
1943 processNonDbgInstruction(*
II, LiveSet);
1944 assert(LiveSet->isValid());
1950 if (
II != EI &&
II->hasDbgRecords()) {
1955 resetInsertionPoint(DVR);
1956 processDbgVariableRecord(DVR, LiveSet);
1957 assert(LiveSet->isValid());
1960 ProcessedLeadingDbgRecords =
true;
1968 for (
auto Var : VarsTouchedThisFrame) {
1969 LocKind
Loc = getLocKind(LiveSet, Var);
1977 if (
Loc != LocKind::Mem) {
1980 NotAlwaysStackHomed.insert(Aggr);
1983 VarsTouchedThisFrame.clear();
1987AssignmentTrackingLowering::LocKind
1988AssignmentTrackingLowering::joinKind(LocKind
A, LocKind
B) {
1991 return A ==
B ?
A : LocKind::None;
1994AssignmentTrackingLowering::Assignment
1995AssignmentTrackingLowering::joinAssignment(
const Assignment &
A,
1996 const Assignment &
B) {
2003 if (!
A.isSameSourceAssignment(
B))
2004 return Assignment::makeNoneOrPhi();
2005 if (
A.Status == Assignment::NoneOrPhi)
2006 return Assignment::makeNoneOrPhi();
2022 if (
A.Source ==
B.Source)
2024 if (!
A.Source || !
B.Source)
2026 if (
A.Source->isEquivalentTo(*
B.Source))
2031 assert(
A.Status ==
B.Status &&
A.Status == Assignment::Known);
2033 return Assignment::make(
A.ID, Source);
2036AssignmentTrackingLowering::BlockInfo
2037AssignmentTrackingLowering::joinBlockInfo(
const BlockInfo &
A,
2038 const BlockInfo &
B) {
2039 return BlockInfo::join(
A,
B, TrackedVariablesVectorSize);
2042bool AssignmentTrackingLowering::join(
2054 if (Visited.
count(Pred))
2059 if (VisitedPreds.
empty()) {
2061 bool DidInsert = It.second;
2063 It.first->second.init(TrackedVariablesVectorSize);
2068 if (VisitedPreds.
size() == 1) {
2069 const BlockInfo &PredLiveOut = LiveOut.
find(VisitedPreds[0])->second;
2076 if (PredLiveOut != CurrentLiveInEntry->second) {
2077 CurrentLiveInEntry->second = PredLiveOut;
2085 const BlockInfo &PredLiveOut0 = LiveOut.
find(VisitedPreds[0])->second;
2086 const BlockInfo &PredLiveOut1 = LiveOut.
find(VisitedPreds[1])->second;
2087 BlockInfo BBLiveIn = joinBlockInfo(PredLiveOut0, PredLiveOut1);
2092 const auto &PredLiveOut = LiveOut.
find(Pred);
2094 "block should have been processed already");
2095 BBLiveIn = joinBlockInfo(std::move(BBLiveIn), PredLiveOut->second);
2099 auto CurrentLiveInEntry = LiveIn.
find(&BB);
2102 if (CurrentLiveInEntry == LiveIn.
end())
2104 else if (BBLiveIn != CurrentLiveInEntry->second)
2105 CurrentLiveInEntry->second = std::move(BBLiveIn);
2114 auto ALeft =
A.OffsetInBits;
2115 auto BLeft =
B.OffsetInBits;
2119 auto ARight = ALeft +
A.SizeInBits;
2120 auto BRight = BLeft +
B.SizeInBits;
2121 if (BRight > ARight)
2126static std::optional<at::AssignmentInfo>
2136 return std::nullopt;
2144 if (
ID != Intrinsic::experimental_vp_strided_store &&
2145 ID != Intrinsic::masked_store &&
ID != Intrinsic::vp_scatter &&
2146 ID != Intrinsic::masked_scatter &&
ID != Intrinsic::vp_store &&
2147 ID != Intrinsic::masked_compressstore)
2183 AssignmentTrackingLowering::UntaggedStoreAssignmentMap &UntaggedStoreVars,
2184 AssignmentTrackingLowering::UnknownStoreAssignmentMap &UnknownStoreVars,
2185 AssignmentTrackingLowering::EscapingCallVarsMap &EscapingCallVars,
2186 unsigned &TrackedVariablesVectorSize) {
2200 if (
Record->isDbgDeclare()) {
2206 if (!VarsWithStackSlot.
contains(DA))
2208 if (Seen.
insert(DV).second)
2209 FragmentMap[DA].push_back(DV);
2211 for (
auto &BB : Fn) {
2212 for (
auto &
I : BB) {
2214 ProcessDbgRecord(&DVR);
2218 std::optional<DIExpression::FragmentInfo> FragInfo;
2223 I.getDataLayout(), Info->Base,
2224 Info->OffsetInBits, Info->SizeInBits, Assign, FragInfo) ||
2225 (FragInfo && FragInfo->SizeInBits == 0))
2234 FragInfo = Assign->getExpression()->getFragmentInfo();
2238 Assign->getDebugLoc().getInlinedAt());
2240 if (!VarsWithStackSlot.
contains(DA))
2244 UntaggedStoreVars[&
I].push_back(
2247 if (Seen.
insert(DV).second)
2248 FragmentMap[DA].push_back(DV);
2251 HandleDbgAssignForStore(DVR);
2259 Assign->getDebugLoc().getInlinedAt());
2261 if (!VarsWithStackSlot.
contains(DA))
2268 HandleDbgAssignForUnknownStore(DVR);
2281 if (CB->onlyReadsMemory())
2285 for (
unsigned ArgIdx = 0; ArgIdx < CB->arg_size(); ++ArgIdx) {
2286 Value *Arg = CB->getArgOperand(ArgIdx);
2290 if (CB->paramHasAttr(ArgIdx, Attribute::ReadOnly) ||
2291 CB->paramHasAttr(ArgIdx, Attribute::ReadNone))
2294 if (CB->paramHasAttr(ArgIdx, Attribute::ByVal))
2309 if (!VarsWithStackSlot.
contains(DA))
2313 EscapingCallVars[&
I].push_back(
2322 for (
auto &Pair : FragmentMap) {
2324 std::sort(Frags.
begin(), Frags.
end(),
2326 return Elmt.getFragmentOrDefault().SizeInBits >
2327 Next.getFragmentOrDefault().SizeInBits;
2334 AssignmentTrackingLowering::OverlapMap Map;
2335 for (
auto &Pair : FragmentMap) {
2336 auto &Frags = Pair.second;
2337 for (
auto It = Frags.begin(), IEnd = Frags.end(); It != IEnd; ++It) {
2347 for (; OtherIt != IEnd; ++OtherIt) {
2351 Map[OtherVar].push_back(ThisVar);
2362 for (
auto *DVR : DPDeclares)
2369bool AssignmentTrackingLowering::run(FunctionVarLocsBuilder *FnVarLocsBuilder) {
2372 <<
": too many blocks (" << Fn.
size() <<
")\n");
2377 FnVarLocs = FnVarLocsBuilder;
2387 Fn, FnVarLocs, *VarsWithStackSlot, UntaggedStoreVars, UnknownStoreVars,
2388 EscapingCallVars, TrackedVariablesVectorSize);
2392 std::priority_queue<unsigned int, std::vector<unsigned int>,
2393 std::greater<unsigned int>>
2395 std::priority_queue<unsigned int, std::vector<unsigned int>,
2396 std::greater<unsigned int>>
2401 unsigned int RPONumber = 0;
2403 OrderToBB[RPONumber] = BB;
2404 BBToOrder[BB] = RPONumber;
2405 Worklist.push(RPONumber);
2423 while (!Worklist.empty()) {
2428 while (!Worklist.empty()) {
2432 bool InChanged =
join(*BB, Visited);
2434 InChanged |= Visited.
insert(BB).second;
2439 BlockInfo LiveSet = LiveIn[BB];
2442 process(*BB, &LiveSet);
2445 if (LiveOut[BB] != LiveSet) {
2447 <<
" has new OutLocs, add succs to worklist: [ ");
2448 LiveOut[BB] = std::move(LiveSet);
2450 if (OnPending.
insert(Succ).second) {
2452 Pending.push(BBToOrder[Succ]);
2459 Worklist.swap(Pending);
2462 assert(Pending.empty() &&
"Pending should be empty");
2468 bool InsertedAnyIntrinsics =
false;
2477 for (
const auto &Pair : InsertBeforeMap) {
2478 auto &Vec = Pair.second;
2484 if (NotAlwaysStackHomed.contains(Aggr))
2494 NotAlwaysStackHomed.insert(Aggr);
2503 if (AlwaysStackHomed.
insert(Aggr).second) {
2512 InsertedAnyIntrinsics =
true;
2518 for (
const auto &[InsertBefore, Vec] : InsertBeforeMap) {
2525 if (AlwaysStackHomed.
contains(Aggr))
2528 InsertedAnyIntrinsics =
true;
2531 FnVarLocs->
setWedge(InsertBefore, std::move(NewDefs));
2534 InsertedAnyIntrinsics |= emitPromotedVarLocs(FnVarLocs);
2536 return InsertedAnyIntrinsics;
2539bool AssignmentTrackingLowering::emitPromotedVarLocs(
2540 FunctionVarLocsBuilder *FnVarLocs) {
2541 bool InsertedAnyIntrinsics =
false;
2550 assert(InsertBefore &&
"Unexpected: debug intrinsics after a terminator");
2554 InsertedAnyIntrinsics =
true;
2556 for (
auto &BB : Fn) {
2557 for (
auto &
I : BB) {
2561 TranslateDbgRecord(&DVR);
2564 return InsertedAnyIntrinsics;
2584 VariableDefinedBytes.
clear();
2586 auto HandleLocsForWedge = [&](
auto *WedgePosition) {
2588 const auto *Locs = FnVarLocs.
getWedge(WedgePosition);
2593 bool ChangedThisWedge =
false;
2598 for (
auto RIt = Locs->rbegin(), REnd = Locs->rend(); RIt != REnd; ++RIt) {
2602 uint64_t SizeInBits = Aggr.first->getSizeInBits().value_or(0);
2606 const uint64_t MaxSizeBytes = 2048;
2608 if (SizeInBytes == 0 || SizeInBytes > MaxSizeBytes) {
2622 bool FirstDefinition = InsertResult.second;
2623 BitVector &DefinedBytes = InsertResult.first->second;
2626 RIt->Expr->getFragmentInfo().value_or(
2628 bool InvalidFragment = Fragment.endInBits() > SizeInBits;
2629 uint64_t StartInBytes = Fragment.startInBits() / 8;
2633 if (FirstDefinition || InvalidFragment ||
2635 if (!InvalidFragment)
2636 DefinedBytes.
set(StartInBytes, EndInBytes);
2643 ChangedThisWedge =
true;
2648 if (ChangedThisWedge) {
2649 std::reverse(NewDefsReversed.
begin(), NewDefsReversed.
end());
2650 FnVarLocs.
setWedge(WedgePosition, std::move(NewDefsReversed));
2655 HandleLocsForWedge(&
I);
2657 HandleLocsForWedge(&DVR);
2682 auto HandleLocsForWedge = [&](
auto *WedgePosition) {
2683 const auto *Locs = FnVarLocs.
getWedge(WedgePosition);
2688 bool ChangedThisWedge =
false;
2696 std::nullopt,
Loc.DL.getInlinedAt());
2701 if (Inserted || VMI->second.first !=
Loc.Values ||
2702 VMI->second.second !=
Loc.Expr) {
2703 VMI->second = {
Loc.Values,
Loc.Expr};
2709 ChangedThisWedge =
true;
2714 if (ChangedThisWedge) {
2715 FnVarLocs.
setWedge(WedgePosition, std::move(NewDefs));
2722 HandleLocsForWedge(&DVR);
2723 HandleLocsForWedge(&
I);
2748 VarsWithDef[
A].
insert(V.getFragmentOrDefault());
2754 auto FragsIt = VarsWithDef.
find(
A);
2755 if (FragsIt == VarsWithDef.
end())
2758 return DIExpression::fragmentsOverlap(Frag, V.getFragmentOrDefault());
2769 auto HandleLocsForWedge = [&](
auto *WedgePosition) {
2770 const auto *Locs = FnVarLocs.
getWedge(WedgePosition);
2775 bool ChangedThisWedge =
false;
2783 Loc.DL.getInlinedAt()};
2788 if (
Loc.Values.isKillLocation(
Loc.Expr) && !HasDefinedBits(Aggr, Var)) {
2791 ChangedThisWedge =
true;
2795 DefineBits(Aggr, Var);
2800 if (ChangedThisWedge) {
2801 FnVarLocs.
setWedge(WedgePosition, std::move(NewDefs));
2807 HandleLocsForWedge(&DVR);
2808 HandleLocsForWedge(&
I);
2816 bool MadeChanges =
false;
2830 for (
auto &BB : Fn) {
2831 for (
auto &
I : BB) {
2857 AssignmentTrackingLowering
Pass(Fn, Layout, &VarsWithStackSlot);
2862 MemLocFragmentFill
Pass(Fn, &VarsWithStackSlot,
2864 Pass.run(FnVarLocs);
2881 auto &
DL =
F.getDataLayout();
2905 LLVM_DEBUG(
dbgs() <<
"AssignmentTrackingAnalysis run on " <<
F.getName()
2915 Results->init(Builder);
2918 Results->print(
errs(),
F);
2930 "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.
VarLocInsertPt getNextNode(const DbgRecord *DVR)
static void analyzeFunction(Function &Fn, const DataLayout &Layout, FunctionVarLocsBuilder *FnVarLocs)
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.
static DenseSet< DebugAggregate > findVarsWithStackSlot(Function &Fn)
static bool fullyContains(DIExpression::FragmentInfo A, DIExpression::FragmentInfo B)
Return true if A fully contains B.
static std::optional< at::AssignmentInfo > getUntaggedStoreAssignmentInfo(const Instruction &I, const DataLayout &Layout)
static bool removeUndefDbgLocsFromEntryBlock(const BasicBlock *BB, FunctionVarLocsBuilder &FnVarLocs)
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)
PointerUnion< const Instruction *, const DbgRecord * > VarLocInsertPt
static bool removeRedundantDbgLocsUsingForwardScan(const BasicBlock *BB, FunctionVarLocsBuilder &FnVarLocs)
Remove redundant location defs using a forward scan.
static bool removeRedundantDbgLocs(const BasicBlock *BB, FunctionVarLocsBuilder &FnVarLocs)
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 AssignmentTrackingLowering::OverlapMap buildOverlapMapAndRecordDeclares(Function &Fn, FunctionVarLocsBuilder *FnVarLocs, const DenseSet< DebugAggregate > &VarsWithStackSlot, AssignmentTrackingLowering::UntaggedStoreAssignmentMap &UntaggedStoreVars, AssignmentTrackingLowering::UnknownStoreAssignmentMap &UnknownStoreVars, AssignmentTrackingLowering::EscapingCallVarsMap &EscapingCallVars, unsigned &TrackedVariablesVectorSize)
Build a map of {Variable x: Variables y} where all variable fragments contained within the variable f...
static DIAssignID * getIDFromMarker(const DbgVariableRecord &DVR)
static DebugAggregate getAggregate(const DebugVariable &Var)
static bool hasZeroSizedFragment(DbgVariableRecord &DbgValue)
static DIAssignID * getIDFromInst(const Instruction &I)
AllocaInst * getUnknownStore(const Instruction &I, const DataLayout &Layout)
static std::optional< int64_t > getDerefOffsetInBytes(const DIExpression *DIExpr)
Extract the offset used in DIExpr.
static bool removeRedundantDbgLocsUsingBackwardScan(const BasicBlock *BB, FunctionVarLocsBuilder &FnVarLocs)
Remove redundant definitions within sequences of consecutive location defs.
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)
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")
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.
void setWedge(VarLocInsertPt Before, SmallVector< VarLocInfo > &&Wedge)
Replace the defs that come just before /p Before with /p Wedge.
const SmallVectorImpl< VarLocInfo > * getWedge(VarLocInsertPt Before) const
Return ptr to wedge of defs or nullptr if no defs come just before /p Before.
unsigned getNumVariables() const
void addSingleLocVar(DebugVariable Var, DIExpression *Expr, DebugLoc DL, RawLocationWrapper R)
Add a def for a variable that is valid for its lifetime.
VariableID insertVariable(DebugVariable V)
Find or insert V and return the ID.
void addVarLoc(VarLocInsertPt Before, DebugVariable Var, DIExpression *Expr, DebugLoc DL, RawLocationWrapper R)
Add a def to the wedge of defs just before /p Before.
const DebugVariable & getVariable(VariableID ID) const
Get a variable from its ID.
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
Represent a constant reference to an array (0 or more elements consecutively in memory),...
AssignmentTrackingAnalysis()
bool runOnFunction(Function &F) override
runOnFunction - Virtual method overriden by subclasses to do the per-function processing of the pass.
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
Returns the index of the first unset bit in the range [Begin, End).
BitVector & set()
Set all bits in the bitvector.
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 Value * getAddress() const
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.
DIExpression * getAddressExpression() const
LLVM_ABI Result run(Function &F, FunctionAnalysisManager &FAM)
LLVM_ABI PreservedAnalyses run(Function &F, FunctionAnalysisManager &FAM)
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.
LLVM_ABI void print(raw_ostream &OS, const Function &Fn) const
const VarLocInfo * locs_begin(const Instruction *Before) const
First variable location definition that comes before Before.
const VarLocInfo * single_locs_begin() const
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.
LLVM_ABI void init(FunctionVarLocsBuilder &Builder)
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 bits of the poi...
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.
Implements a dense probed hash-table based set with some number of buckets stored inline.
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.
bool isPointerTy() const
True if this is an instance of PointerType.
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.
Type * getType() const
All values are typed, get the type of this value.
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.
DXILDebugInfoMap run(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<X> - 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<X> - 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<X> - Return the argument parameter cast to the specified type.
auto predecessors(const MachineBasicBlock *BB)
AnalysisManager< Function > FunctionAnalysisManager
Convenience typedef for the Function analysis manager.
LLVM_ABI const Value * getUnderlyingObject(const Value *V, unsigned MaxLookup=MaxLookupSearchDepth)
This method strips off any GEP address adjustments, pointer casts or llvm.threadlocal....
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 bool isEqual(const VariableID &LHS, const VariableID &RHS)
static unsigned getHashValue(const VariableID &Val)
static VariableID getEmptyKey()
DenseMapInfo< unsigned > Wrapped
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