39#include <unordered_map>
42#define DEBUG_TYPE "debug-ata"
44STATISTIC(NumDefsScanned,
"Number of dbg locs that get scanned for removal");
45STATISTIC(NumDefsRemoved,
"Number of dbg locs removed");
46STATISTIC(NumWedgesScanned,
"Number of dbg wedges scanned");
47STATISTIC(NumWedgesChanged,
"Number of dbg wedges changed");
51 cl::desc(
"Maximum num basic blocks before debug info dropped"),
72 return static_cast<VariableID>(Wrapped::getEmptyKey());
75 return static_cast<VariableID>(Wrapped::getTombstoneKey());
78 return Wrapped::getHashValue(
static_cast<unsigned>(Val));
106 std::unordered_map<VarLocInsertPt, SmallVector<VarLocInfo>> VarLocsBeforeInst;
120 return Variables[
static_cast<unsigned>(
ID)];
126 auto R = VarLocsBeforeInst.find(
Before);
127 if (R == VarLocsBeforeInst.end())
134 VarLocsBeforeInst[
Before] = std::move(Wedge);
156 VarLocsBeforeInst[
Before].emplace_back(VarLoc);
163 unsigned Counter = -1;
164 OS <<
"=== Variables ===\n";
171 OS <<
"[" << Counter <<
"] " << V.getVariable()->getName();
172 if (
auto F = V.getFragment())
173 OS <<
" bits [" <<
F->OffsetInBits <<
", "
174 <<
F->OffsetInBits +
F->SizeInBits <<
")";
175 if (
const auto *IA = V.getInlinedAt())
176 OS <<
" inlined-at " << *IA;
181 OS <<
"DEF Var=[" << (
unsigned)Loc.VariableID <<
"]"
182 <<
" Expr=" << *Loc.Expr <<
" Values=(";
183 for (
auto *
Op : Loc.Values.location_ops()) {
184 errs() <<
Op->getName() <<
" ";
190 OS <<
"=== Single location vars ===\n";
197 OS <<
"=== In-line variable defs ===";
199 OS <<
"\n" << BB.getName() <<
":\n";
211 for (
const auto &VarLoc : Builder.SingleLocVars)
214 SingleVarLocEnd = VarLocRecords.
size();
220 for (
auto &
P : Builder.VarLocsBeforeInst) {
223 if (isa<const DbgRecord *>(
P.first))
226 unsigned BlockStart = VarLocRecords.
size();
233 if (!Builder.VarLocsBeforeInst.count(&DVR))
235 for (
const VarLocInfo &VarLoc : Builder.VarLocsBeforeInst[&DVR])
240 unsigned BlockEnd = VarLocRecords.
size();
242 if (BlockEnd != BlockStart)
243 VarLocsBeforeInst[
I] = {BlockStart, BlockEnd};
247 assert(Variables.empty() &&
"Expect clear before init");
250 Variables.reserve(Builder.Variables.
size() + 1);
251 Variables.push_back(
DebugVariable(
nullptr, std::nullopt,
nullptr));
252 Variables.append(Builder.Variables.
begin(), Builder.Variables.
end());
257 VarLocRecords.
clear();
258 VarLocsBeforeInst.clear();
266static std::pair<Value *, DIExpression *>
269 APInt OffsetInBytes(
DL.getTypeSizeInBits(Start->getType()),
false);
271 Start->stripAndAccumulateInBoundsConstantOffsets(
DL, OffsetInBytes);
274 Ops = {dwarf::DW_OP_plus_uconst, OffsetInBytes.
getZExtValue()};
285static std::optional<int64_t>
290 unsigned ExpectedDerefIdx = 0;
292 if (NumElements > 2 && Elements[0] == dwarf::DW_OP_plus_uconst) {
294 ExpectedDerefIdx = 2;
295 }
else if (NumElements > 3 && Elements[0] == dwarf::DW_OP_constu) {
296 ExpectedDerefIdx = 3;
297 if (Elements[2] == dwarf::DW_OP_plus)
299 else if (Elements[2] == dwarf::DW_OP_minus)
306 if (ExpectedDerefIdx >= NumElements)
311 if (Elements[ExpectedDerefIdx] != dwarf::DW_OP_deref)
315 if (NumElements == ExpectedDerefIdx + 1)
317 unsigned ExpectedFragFirstIdx = ExpectedDerefIdx + 1;
318 unsigned ExpectedFragFinalIdx = ExpectedFragFirstIdx + 2;
319 if (NumElements == ExpectedFragFinalIdx + 1 &&
345 Triple(
F.getParent()->getTargetTriple()));
373class MemLocFragmentFill {
377 bool CoalesceAdjacentFragments;
384 OffsetInBitsTy, BaseAddress,
387 FragsInMemMap::Allocator IntervalMapAlloc;
400 unsigned OffsetInBits;
413 static bool intervalMapsAreEqual(
const FragsInMemMap &
A,
414 const FragsInMemMap &
B) {
415 auto AIt =
A.begin(), AEnd =
A.end();
416 auto BIt =
B.begin(), BEnd =
B.end();
417 for (; AIt != AEnd; ++AIt, ++BIt) {
420 if (AIt.start() != BIt.start() || AIt.stop() != BIt.stop())
429 static bool varFragMapsAreEqual(
const VarFragMap &
A,
const VarFragMap &
B) {
430 if (
A.size() !=
B.size())
432 for (
const auto &APair :
A) {
433 auto BIt =
B.find(APair.first);
436 if (!intervalMapsAreEqual(APair.second, BIt->second))
443 std::string
toString(
unsigned BaseID) {
445 return Bases[BaseID].getVariableLocationOp(0)->getName().str();
451 std::string
toString(FragsInMemMap::const_iterator It,
bool Newline =
true) {
453 std::stringstream S(
String);
455 S <<
"[" << It.start() <<
", " << It.stop()
458 S <<
"invalid iterator (end)";
465 FragsInMemMap meetFragments(
const FragsInMemMap &
A,
const FragsInMemMap &
B) {
466 FragsInMemMap
Result(IntervalMapAlloc);
467 for (
auto AIt =
A.begin(), AEnd =
A.end(); AIt != AEnd; ++AIt) {
474 if (!
B.overlaps(AIt.start(), AIt.stop()))
478 auto FirstOverlap =
B.find(AIt.start());
479 assert(FirstOverlap !=
B.end());
480 bool IntersectStart = FirstOverlap.start() < AIt.start();
482 <<
", IntersectStart: " << IntersectStart <<
"\n");
485 auto LastOverlap =
B.find(AIt.stop());
487 LastOverlap !=
B.end() && LastOverlap.start() < AIt.stop();
489 <<
", IntersectEnd: " << IntersectEnd <<
"\n");
492 if (IntersectStart && IntersectEnd && FirstOverlap == LastOverlap) {
500 if (*AIt && *AIt == *FirstOverlap)
501 Result.insert(AIt.start(), AIt.stop(), *AIt);
509 auto Next = FirstOverlap;
510 if (IntersectStart) {
513 if (*AIt && *AIt == *FirstOverlap)
514 Result.insert(AIt.start(), FirstOverlap.stop(), *AIt);
524 if (*AIt && *AIt == *LastOverlap)
525 Result.insert(LastOverlap.start(), AIt.stop(), *AIt);
534 while (Next !=
B.end() && Next.start() < AIt.stop() &&
535 Next.stop() <= AIt.stop()) {
537 <<
"- insert intersection of a and " <<
toString(Next));
538 if (*AIt && *AIt == *Next)
539 Result.insert(Next.start(), Next.stop(), *Next);
548 void meetVars(VarFragMap &
A,
const VarFragMap &
B) {
552 for (
auto It =
A.begin(),
End =
A.end(); It !=
End; ++It) {
553 unsigned AVar = It->first;
554 FragsInMemMap &AFrags = It->second;
555 auto BIt =
B.find(AVar);
556 if (BIt ==
B.end()) {
561 <<
Aggregates[AVar].first->getName() <<
"\n");
562 AFrags = meetFragments(AFrags, BIt->second);
572 bool FirstMeet =
true;
579 if (!Visited.
count(Pred))
582 auto PredLiveOut = LiveOut.
find(Pred);
587 BBLiveIn = PredLiveOut->second;
590 LLVM_DEBUG(
dbgs() <<
"BBLiveIn = meet BBLiveIn, " << Pred->getName()
592 meetVars(BBLiveIn, PredLiveOut->second);
598 if (BBLiveIn.size() == 0)
602 auto CurrentLiveInEntry = LiveIn.
find(&BB);
604 if (CurrentLiveInEntry == LiveIn.
end()) {
607 LiveIn[&BB] = std::move(BBLiveIn);
613 if (!varFragMapsAreEqual(BBLiveIn, CurrentLiveInEntry->second)) {
615 CurrentLiveInEntry->second = std::move(BBLiveIn);
624 unsigned StartBit,
unsigned EndBit,
unsigned Base,
626 assert(StartBit < EndBit &&
"Cannot create fragment of size <= 0");
631 Loc.OffsetInBits = StartBit;
632 Loc.SizeInBits = EndBit - StartBit;
633 assert(
Base &&
"Expected a non-zero ID for Base address");
636 BBInsertBeforeMap[&BB][
Before].push_back(Loc);
638 <<
" bits [" << StartBit <<
", " << EndBit <<
")\n");
646 unsigned StartBit,
unsigned EndBit,
unsigned Base,
648 if (!CoalesceAdjacentFragments)
655 auto CoalescedFrag = FragMap.find(StartBit);
657 if (CoalescedFrag.start() == StartBit && CoalescedFrag.stop() == EndBit)
660 LLVM_DEBUG(
dbgs() <<
"- Insert loc for bits " << CoalescedFrag.start()
661 <<
" to " << CoalescedFrag.stop() <<
"\n");
662 insertMemLoc(BB,
Before, Var, CoalescedFrag.start(), CoalescedFrag.stop(),
667 VarFragMap &LiveSet) {
684 StartBit = Frag->OffsetInBits;
685 EndBit = StartBit + Frag->SizeInBits;
700 const unsigned Base =
701 DerefOffsetInBytes && *DerefOffsetInBytes * 8 == StartBit
705 << StartBit <<
", " << EndBit <<
"): " <<
toString(
Base)
712 auto FragIt = LiveSet.find(Var);
715 if (FragIt == LiveSet.end()) {
717 auto P = LiveSet.try_emplace(Var, FragsInMemMap(IntervalMapAlloc));
718 assert(
P.second &&
"Var already in map?");
720 P.first->second.insert(StartBit, EndBit,
Base);
725 FragsInMemMap &FragMap = FragIt->second;
728 if (!FragMap.overlaps(StartBit, EndBit)) {
730 FragMap.insert(StartBit, EndBit,
Base);
731 coalesceFragments(BB,
Before, Var, StartBit, EndBit,
Base, VarLoc.
DL,
738 auto FirstOverlap = FragMap.find(StartBit);
739 assert(FirstOverlap != FragMap.end());
740 bool IntersectStart = FirstOverlap.start() < StartBit;
743 auto LastOverlap = FragMap.find(EndBit);
744 bool IntersectEnd = LastOverlap.valid() && LastOverlap.start() < EndBit;
747 if (IntersectStart && IntersectEnd && FirstOverlap == LastOverlap) {
748 LLVM_DEBUG(
dbgs() <<
"- Intersect single interval @ both ends\n");
756 auto EndBitOfOverlap = FirstOverlap.stop();
757 unsigned OverlapValue = FirstOverlap.value();
760 FirstOverlap.setStop(StartBit);
761 insertMemLoc(BB,
Before, Var, FirstOverlap.start(), StartBit,
762 OverlapValue, VarLoc.
DL);
765 FragMap.insert(EndBit, EndBitOfOverlap, OverlapValue);
766 insertMemLoc(BB,
Before, Var, EndBit, EndBitOfOverlap, OverlapValue,
770 FragMap.insert(StartBit, EndBit,
Base);
780 if (IntersectStart) {
783 FirstOverlap.setStop(StartBit);
784 insertMemLoc(BB,
Before, Var, FirstOverlap.start(), StartBit,
785 *FirstOverlap, VarLoc.
DL);
794 LastOverlap.setStart(EndBit);
795 insertMemLoc(BB,
Before, Var, EndBit, LastOverlap.stop(), *LastOverlap,
811 auto It = FirstOverlap;
814 while (It.valid() && It.start() >= StartBit && It.stop() <= EndBit) {
819 assert(!FragMap.overlaps(StartBit, EndBit));
821 FragMap.insert(StartBit, EndBit,
Base);
824 coalesceFragments(BB,
Before, Var, StartBit, EndBit,
Base, VarLoc.
DL,
830 void process(
BasicBlock &BB, VarFragMap &LiveSet) {
831 BBInsertBeforeMap[&BB].
clear();
834 if (
const auto *Locs = FnVarLocs->
getWedge(&DVR)) {
836 addDef(Loc, &DVR, *
I.getParent(), LiveSet);
840 if (
const auto *Locs = FnVarLocs->
getWedge(&
I)) {
842 addDef(Loc, &
I, *
I.getParent(), LiveSet);
851 bool CoalesceAdjacentFragments)
852 : Fn(Fn), VarsWithStackSlot(VarsWithStackSlot),
853 CoalesceAdjacentFragments(CoalesceAdjacentFragments) {}
879 this->FnVarLocs = FnVarLocs;
884 std::priority_queue<unsigned int, std::vector<unsigned int>,
885 std::greater<unsigned int>>
887 std::priority_queue<unsigned int, std::vector<unsigned int>,
888 std::greater<unsigned int>>
893 unsigned int RPONumber = 0;
895 OrderToBB[RPONumber] = BB;
896 BBToOrder[BB] = RPONumber;
897 Worklist.push(RPONumber);
900 LiveIn.
init(RPONumber);
901 LiveOut.
init(RPONumber);
914 while (!Worklist.empty() || !Pending.empty()) {
920 while (!Worklist.empty()) {
924 bool InChanged = meet(*BB, Visited);
926 InChanged |= Visited.
insert(BB).second;
929 << BB->
getName() <<
" has new InLocs, process it\n");
933 VarFragMap LiveSet = LiveIn[BB];
936 process(*BB, LiveSet);
939 if (!varFragMapsAreEqual(LiveOut[BB], LiveSet)) {
941 <<
" has new OutLocs, add succs to worklist: [ ");
942 LiveOut[BB] = std::move(LiveSet);
944 if (OnPending.
insert(Succ).second) {
946 Pending.push(BBToOrder[Succ]);
953 Worklist.swap(Pending);
956 assert(Pending.empty() &&
"Pending should be empty");
960 for (
auto &Pair : BBInsertBeforeMap) {
961 InsertMap &
Map = Pair.second;
962 for (
auto &Pair : Map) {
963 auto InsertBefore = Pair.first;
964 assert(InsertBefore &&
"should never be null");
965 auto FragMemLocs = Pair.second;
968 for (
auto &FragMemLoc : FragMemLocs) {
969 DIExpression *Expr = DIExpression::get(Ctx, std::nullopt);
970 if (FragMemLoc.SizeInBits !=
971 *
Aggregates[FragMemLoc.Var].first->getSizeInBits())
973 Expr, FragMemLoc.OffsetInBits, FragMemLoc.SizeInBits);
975 FragMemLoc.OffsetInBits / 8);
977 FragMemLoc.DL.getInlinedAt());
978 FnVarLocs->
addVarLoc(InsertBefore, Var, Expr, FragMemLoc.DL,
979 Bases[FragMemLoc.Base]);
989class AssignmentTrackingLowering {
1014 enum class LocKind { Mem, Val,
None };
1032 enum S { Known, NoneOrPhi }
Status;
1039 bool isSameSourceAssignment(
const Assignment &
Other)
const {
1045 static const char *LUT[] = {
"Known",
"NoneOrPhi"};
1054 else if (isa<DbgAssignIntrinsic *>(Source))
1062 return Assignment(Known,
ID, Source);
1066 "Cannot make an assignment from a non-assign DbgVariableRecord");
1067 return Assignment(Known,
ID, Source);
1070 return Assignment(Known,
ID, Source);
1073 return Assignment(Known,
ID);
1075 static Assignment makeNoneOrPhi() {
return Assignment(NoneOrPhi,
nullptr); }
1077 Assignment() :
Status(NoneOrPhi),
ID(nullptr) {}
1102 using UntaggedStoreAssignmentMap =
1109 unsigned TrackedVariablesVectorSize = 0;
1114 UntaggedStoreAssignmentMap UntaggedStoreVars;
1118 InstInsertMap InsertBeforeMap;
1131 template <
typename T>
1134 static bool mapsAreEqual(
const BitVector &Mask,
const AssignmentMap &
A,
1135 const AssignmentMap &
B) {
1137 return A[VarID].isSameSourceAssignment(B[VarID]);
1149 AssignmentMap StackHomeValue;
1151 AssignmentMap DebugValue;
1166 const AssignmentMap &getAssignmentMap(AssignmentKind Kind)
const {
1169 return StackHomeValue;
1175 AssignmentMap &getAssignmentMap(AssignmentKind Kind) {
1176 return const_cast<AssignmentMap &
>(
1177 const_cast<const BlockInfo *
>(
this)->getAssignmentMap(Kind));
1180 bool isVariableTracked(
VariableID Var)
const {
1181 return VariableIDsInBlock[
static_cast<unsigned>(Var)];
1184 const Assignment &getAssignment(AssignmentKind Kind,
VariableID Var)
const {
1185 assert(isVariableTracked(Var) &&
"Var not tracked in block");
1186 return getAssignmentMap(Kind)[
static_cast<unsigned>(Var)];
1190 assert(isVariableTracked(Var) &&
"Var not tracked in block");
1191 return LiveLoc[
static_cast<unsigned>(Var)];
1197 VariableIDsInBlock.
set(
static_cast<unsigned>(Var));
1198 LiveLoc[
static_cast<unsigned>(Var)] = K;
1204 void setAssignment(AssignmentKind Kind,
VariableID Var,
1205 const Assignment &AV) {
1206 VariableIDsInBlock.
set(
static_cast<unsigned>(Var));
1207 getAssignmentMap(Kind)[
static_cast<unsigned>(Var)] = AV;
1213 bool hasAssignment(AssignmentKind Kind,
VariableID Var,
1214 const Assignment &AV)
const {
1215 if (!isVariableTracked(Var))
1217 return AV.isSameSourceAssignment(getAssignment(Kind, Var));
1223 return VariableIDsInBlock ==
Other.VariableIDsInBlock &&
1224 LiveLoc ==
Other.LiveLoc &&
1225 mapsAreEqual(VariableIDsInBlock, StackHomeValue,
1226 Other.StackHomeValue) &&
1227 mapsAreEqual(VariableIDsInBlock, DebugValue,
Other.DebugValue);
1231 return LiveLoc.size() == DebugValue.size() &&
1232 LiveLoc.size() == StackHomeValue.size();
1236 void init(
int NumVars) {
1237 StackHomeValue.clear();
1240 VariableIDsInBlock =
BitVector(NumVars);
1241 StackHomeValue.insert(StackHomeValue.begin(), NumVars,
1242 Assignment::makeNoneOrPhi());
1243 DebugValue.insert(DebugValue.begin(), NumVars,
1244 Assignment::makeNoneOrPhi());
1245 LiveLoc.
insert(LiveLoc.
begin(), NumVars, LocKind::None);
1249 template <
typename ElmtType,
typename FnInputType>
1253 ElmtType (*Fn)(FnInputType, FnInputType)) {
1258 static BlockInfo join(
const BlockInfo &
A,
const BlockInfo &
B,
int NumVars) {
1278 Intersect &=
B.VariableIDsInBlock;
1280 for (
auto VarID : Intersect.
set_bits()) {
1281 joinElmt(VarID, Join.LiveLoc,
A.LiveLoc,
B.LiveLoc, joinKind);
1282 joinElmt(VarID, Join.DebugValue,
A.DebugValue,
B.DebugValue,
1284 joinElmt(VarID, Join.StackHomeValue,
A.StackHomeValue,
B.StackHomeValue,
1288 Join.VariableIDsInBlock =
A.VariableIDsInBlock;
1289 Join.VariableIDsInBlock |=
B.VariableIDsInBlock;
1336 static LocKind joinKind(LocKind
A, LocKind
B);
1337 static Assignment joinAssignment(
const Assignment &
A,
const Assignment &
B);
1338 BlockInfo joinBlockInfo(
const BlockInfo &
A,
const BlockInfo &
B);
1344 void process(
BasicBlock &BB, BlockInfo *LiveSet);
1349 void processNonDbgInstruction(
Instruction &
I, BlockInfo *LiveSet);
1353 void processTaggedInstruction(
Instruction &
I, BlockInfo *LiveSet);
1356 void processUntaggedInstruction(
Instruction &
I, BlockInfo *LiveSet);
1357 void processDbgAssign(AssignRecord Assign, BlockInfo *LiveSet);
1359 void processDbgValue(
1361 BlockInfo *LiveSet);
1363 void addMemDef(BlockInfo *LiveSet,
VariableID Var,
const Assignment &AV);
1365 void addDbgDef(BlockInfo *LiveSet,
VariableID Var,
const Assignment &AV);
1369 void setLocKind(BlockInfo *LiveSet,
VariableID Var, LocKind K);
1372 LocKind getLocKind(BlockInfo *LiveSet,
VariableID Var);
1374 bool hasVarWithAssignment(BlockInfo *LiveSet, BlockInfo::AssignmentKind Kind,
1390 : Fn(Fn), Layout(Layout), VarsWithStackSlot(VarsWithStackSlot) {}
1398AssignmentTrackingLowering::getContainedFragments(
VariableID Var)
const {
1399 auto R = VarContains.
find(Var);
1400 if (R == VarContains.
end())
1401 return std::nullopt;
1405void AssignmentTrackingLowering::touchFragment(
VariableID Var) {
1406 VarsTouchedThisFrame.insert(Var);
1409void AssignmentTrackingLowering::setLocKind(BlockInfo *LiveSet,
VariableID Var,
1411 auto SetKind = [
this](BlockInfo *LiveSet,
VariableID Var, LocKind
K) {
1412 LiveSet->setLocKind(Var, K);
1415 SetKind(LiveSet, Var, K);
1418 for (
VariableID Frag : getContainedFragments(Var))
1419 SetKind(LiveSet, Frag, K);
1422AssignmentTrackingLowering::LocKind
1423AssignmentTrackingLowering::getLocKind(BlockInfo *LiveSet,
VariableID Var) {
1424 return LiveSet->getLocKind(Var);
1427void AssignmentTrackingLowering::addMemDef(BlockInfo *LiveSet,
VariableID Var,
1428 const Assignment &AV) {
1429 LiveSet->setAssignment(BlockInfo::Stack, Var, AV);
1434 Assignment FragAV = AV;
1435 FragAV.Source =
nullptr;
1436 for (
VariableID Frag : getContainedFragments(Var))
1437 LiveSet->setAssignment(BlockInfo::Stack, Frag, FragAV);
1440void AssignmentTrackingLowering::addDbgDef(BlockInfo *LiveSet,
VariableID Var,
1441 const Assignment &AV) {
1442 LiveSet->setAssignment(BlockInfo::Debug, Var, AV);
1447 Assignment FragAV = AV;
1448 FragAV.Source =
nullptr;
1449 for (
VariableID Frag : getContainedFragments(Var))
1450 LiveSet->setAssignment(BlockInfo::Debug, Frag, FragAV);
1454 return cast<DIAssignID>(
I.getMetadata(LLVMContext::MD_DIAssignID));
1463 "Cannot get a DIAssignID from a non-assign DbgVariableRecord!");
1468bool AssignmentTrackingLowering::hasVarWithAssignment(
1469 BlockInfo *LiveSet, BlockInfo::AssignmentKind Kind,
VariableID Var,
1470 const Assignment &AV) {
1471 if (!LiveSet->hasAssignment(Kind, Var, AV))
1476 for (
VariableID Frag : getContainedFragments(Var))
1477 if (!LiveSet->hasAssignment(Kind, Frag, AV))
1483const char *
locStr(AssignmentTrackingLowering::LocKind Loc) {
1484 using LocKind = AssignmentTrackingLowering::LocKind;
1510 if (isa<const Instruction *>(InsertPt))
1511 return getNextNode(cast<const Instruction *>(InsertPt));
1512 return getNextNode(cast<const DbgRecord *>(InsertPt));
1516 return cast<DbgAssignIntrinsic>(DVI);
1521 "Attempted to cast non-assign DbgVariableRecord to DVRAssign.");
1525void AssignmentTrackingLowering::emitDbgValue(
1526 AssignmentTrackingLowering::LocKind Kind,
1528 if (isa<DbgAssignIntrinsic *>(Source))
1529 emitDbgValue(Kind, cast<DbgAssignIntrinsic *>(Source),
After);
1531 emitDbgValue(Kind, cast<DbgVariableRecord *>(Source),
After);
1533template <
typename T>
1534void AssignmentTrackingLowering::emitDbgValue(
1535 AssignmentTrackingLowering::LocKind Kind,
const T Source,
1547 assert(InsertBefore &&
"Shouldn't be inserting after a terminator");
1556 InsertBeforeMap[InsertBefore].
push_back(VarLoc);
1560 if (Kind == LocKind::Mem) {
1564 if (
Assign->isKillAddress()) {
1566 Kind = LocKind::Val;
1571 "fragment info should be stored in value-expression only");
1574 if (
auto OptFragInfo =
Source->getExpression()->getFragmentInfo()) {
1575 auto FragInfo = *OptFragInfo;
1577 Expr, FragInfo.OffsetInBits, FragInfo.SizeInBits);
1580 std::tie(Val, Expr) =
1587 if (Kind == LocKind::Val) {
1588 Emit(
Source->getRawLocation(),
Source->getExpression());
1592 if (Kind == LocKind::None) {
1593 Emit(
nullptr,
Source->getExpression());
1598void AssignmentTrackingLowering::processNonDbgInstruction(
1599 Instruction &
I, AssignmentTrackingLowering::BlockInfo *LiveSet) {
1600 if (
I.hasMetadata(LLVMContext::MD_DIAssignID))
1601 processTaggedInstruction(
I, LiveSet);
1603 processUntaggedInstruction(
I, LiveSet);
1606void AssignmentTrackingLowering::processUntaggedInstruction(
1607 Instruction &
I, AssignmentTrackingLowering::BlockInfo *LiveSet) {
1619 assert(!
I.hasMetadata(LLVMContext::MD_DIAssignID));
1620 auto It = UntaggedStoreVars.find(&
I);
1621 if (It == UntaggedStoreVars.end())
1624 LLVM_DEBUG(
dbgs() <<
"processUntaggedInstruction on UNTAGGED INST " <<
I
1628 for (
auto [Var, Info] : It->second) {
1632 addMemDef(LiveSet, Var, Assignment::makeNoneOrPhi());
1633 addDbgDef(LiveSet, Var, Assignment::makeNoneOrPhi());
1634 setLocKind(LiveSet, Var, LocKind::Mem);
1642 if (
auto Frag =
V.getFragment()) {
1645 assert(R &&
"unexpected createFragmentExpression failure");
1649 if (
Info.OffsetInBits)
1650 Ops = {dwarf::DW_OP_plus_uconst,
Info.OffsetInBits / 8};
1657 assert(InsertBefore &&
"Shouldn't be inserting after a terminator");
1662 Fn.
getContext(), 0, 0,
V.getVariable()->getScope(), InlinedAt);
1671 InsertBeforeMap[InsertBefore].push_back(VarLoc);
1675void AssignmentTrackingLowering::processTaggedInstruction(
1676 Instruction &
I, AssignmentTrackingLowering::BlockInfo *LiveSet) {
1683 if (Linked.empty() && LinkedDPAssigns.empty())
1687 auto ProcessLinkedAssign = [&](
auto *
Assign) {
1692 "expected Assign's variable to have stack slot");
1695 addMemDef(LiveSet, Var, AV);
1703 if (hasVarWithAssignment(LiveSet, BlockInfo::Debug, Var, AV)) {
1709 LiveSet->DebugValue[
static_cast<unsigned>(Var)].
dump(
dbgs());
1711 setLocKind(LiveSet, Var, LocKind::Mem);
1712 emitDbgValue(LocKind::Mem, Assign, &
I);
1721 LocKind PrevLoc = getLocKind(LiveSet, Var);
1723 case LocKind::Val: {
1727 setLocKind(LiveSet, Var, LocKind::Val);
1729 case LocKind::Mem: {
1733 Assignment DbgAV = LiveSet->getAssignment(BlockInfo::Debug, Var);
1734 if (DbgAV.Status == Assignment::NoneOrPhi) {
1737 setLocKind(LiveSet, Var, LocKind::None);
1738 emitDbgValue(LocKind::None, Assign, &
I);
1742 setLocKind(LiveSet, Var, LocKind::Val);
1744 emitDbgValue(LocKind::Val, DbgAV.Source, &
I);
1747 emitDbgValue(LocKind::None, Assign, &
I);
1751 case LocKind::None: {
1755 setLocKind(LiveSet, Var, LocKind::None);
1760 ProcessLinkedAssign(DAI);
1762 ProcessLinkedAssign(DVR);
1765void AssignmentTrackingLowering::processDbgAssign(AssignRecord Assign,
1766 BlockInfo *LiveSet) {
1767 auto ProcessDbgAssignImpl = [&](
auto *DbgAssign) {
1774 Assignment AV = Assignment::make(
getIDFromMarker(*DbgAssign), DbgAssign);
1775 addDbgDef(LiveSet, Var, AV);
1777 LLVM_DEBUG(
dbgs() <<
"processDbgAssign on " << *DbgAssign <<
"\n";);
1783 if (hasVarWithAssignment(LiveSet, BlockInfo::Stack, Var, AV)) {
1788 if (DbgAssign->isKillAddress()) {
1791 <<
"Val, Stack matches Debug program but address is killed\n";);
1792 Kind = LocKind::Val;
1795 Kind = LocKind::Mem;
1797 setLocKind(LiveSet, Var, Kind);
1798 emitDbgValue(Kind, DbgAssign, DbgAssign);
1803 setLocKind(LiveSet, Var, LocKind::Val);
1804 emitDbgValue(LocKind::Val, DbgAssign, DbgAssign);
1807 if (isa<DbgVariableRecord *>(Assign))
1808 return ProcessDbgAssignImpl(cast<DbgVariableRecord *>(Assign));
1809 return ProcessDbgAssignImpl(cast<DbgAssignIntrinsic *>(Assign));
1812void AssignmentTrackingLowering::processDbgValue(
1814 BlockInfo *LiveSet) {
1815 auto ProcessDbgValueImpl = [&](
auto *
DbgValue) {
1828 Assignment AV = Assignment::makeNoneOrPhi();
1829 addDbgDef(LiveSet, Var, AV);
1833 <<
" -> Val, dbg.value override");
1835 setLocKind(LiveSet, Var, LocKind::Val);
1838 if (isa<DbgVariableRecord *>(DbgValueRecord))
1839 return ProcessDbgValueImpl(cast<DbgVariableRecord *>(DbgValueRecord));
1840 return ProcessDbgValueImpl(cast<DbgValueInst *>(DbgValueRecord));
1844 if (
auto F =
DbgValue.getExpression()->getFragmentInfo())
1845 return F->SizeInBits == 0;
1849void AssignmentTrackingLowering::processDbgInstruction(
1851 auto *DVI = dyn_cast<DbgVariableIntrinsic>(&
I);
1859 if (
auto *DAI = dyn_cast<DbgAssignIntrinsic>(&
I))
1860 processDbgAssign(DAI, LiveSet);
1861 else if (
auto *DVI = dyn_cast<DbgValueInst>(&
I))
1862 processDbgValue(DVI, LiveSet);
1864void AssignmentTrackingLowering::processDbgVariableRecord(
1871 processDbgAssign(&DVR, LiveSet);
1873 processDbgValue(&DVR, LiveSet);
1877 assert(!
After.isTerminator() &&
"Can't insert after a terminator");
1879 if (R == InsertBeforeMap.end())
1885 if (R == InsertBeforeMap.end())
1890void AssignmentTrackingLowering::process(
BasicBlock &BB, BlockInfo *LiveSet) {
1893 bool ProcessedLeadingDbgRecords = !BB.
begin()->hasDbgRecords();
1895 assert(VarsTouchedThisFrame.empty());
1902 if (ProcessedLeadingDbgRecords) {
1907 if (!isa<DbgInfoIntrinsic>(&*
II)) {
1908 if (
II->isTerminator())
1910 resetInsertionPoint(*
II);
1911 processNonDbgInstruction(*
II, LiveSet);
1912 assert(LiveSet->isValid());
1919 if (
II != EI &&
II->hasDbgRecords()) {
1924 resetInsertionPoint(DVR);
1925 processDbgVariableRecord(DVR, LiveSet);
1926 assert(LiveSet->isValid());
1929 ProcessedLeadingDbgRecords =
true;
1931 auto *
Dbg = dyn_cast<DbgInfoIntrinsic>(&*
II);
1934 resetInsertionPoint(*
II);
1935 processDbgInstruction(*Dbg, LiveSet);
1936 assert(LiveSet->isValid());
1946 for (
auto Var : VarsTouchedThisFrame) {
1947 LocKind Loc = getLocKind(LiveSet, Var);
1955 if (Loc != LocKind::Mem) {
1958 NotAlwaysStackHomed.insert(Aggr);
1961 VarsTouchedThisFrame.clear();
1965AssignmentTrackingLowering::LocKind
1966AssignmentTrackingLowering::joinKind(LocKind
A, LocKind
B) {
1969 return A ==
B ?
A : LocKind::None;
1972AssignmentTrackingLowering::Assignment
1973AssignmentTrackingLowering::joinAssignment(
const Assignment &
A,
1974 const Assignment &
B) {
1981 if (!
A.isSameSourceAssignment(
B))
1982 return Assignment::makeNoneOrPhi();
1983 if (
A.Status == Assignment::NoneOrPhi)
1984 return Assignment::makeNoneOrPhi();
1999 auto JoinSource = [&]() -> AssignRecord {
2000 if (
A.Source ==
B.Source)
2002 if (!
A.Source || !
B.Source)
2003 return AssignRecord();
2004 assert(isa<DbgVariableRecord *>(
A.Source) ==
2005 isa<DbgVariableRecord *>(
B.Source));
2006 if (isa<DbgVariableRecord *>(
A.Source) &&
2007 cast<DbgVariableRecord *>(
A.Source)->isEquivalentTo(
2008 *cast<DbgVariableRecord *>(
B.Source)))
2010 if (isa<DbgAssignIntrinsic *>(
A.Source) &&
2011 cast<DbgAssignIntrinsic *>(
A.Source)->isIdenticalTo(
2012 cast<DbgAssignIntrinsic *>(
B.Source)))
2014 return AssignRecord();
2016 AssignRecord
Source = JoinSource();
2017 assert(
A.Status ==
B.Status &&
A.Status == Assignment::Known);
2019 return Assignment::make(
A.ID, Source);
2022AssignmentTrackingLowering::BlockInfo
2023AssignmentTrackingLowering::joinBlockInfo(
const BlockInfo &
A,
2024 const BlockInfo &
B) {
2025 return BlockInfo::join(
A,
B, TrackedVariablesVectorSize);
2028bool AssignmentTrackingLowering::join(
2040 if (Visited.
count(Pred))
2045 if (VisitedPreds.
empty()) {
2047 bool DidInsert = It.second;
2049 It.first->second.init(TrackedVariablesVectorSize);
2054 if (VisitedPreds.
size() == 1) {
2055 const BlockInfo &PredLiveOut = LiveOut.
find(VisitedPreds[0])->second;
2056 auto CurrentLiveInEntry = LiveIn.
find(&BB);
2060 if (CurrentLiveInEntry == LiveIn.
end())
2061 LiveIn.
insert(std::make_pair(&BB, PredLiveOut));
2062 else if (PredLiveOut != CurrentLiveInEntry->second)
2063 CurrentLiveInEntry->second = PredLiveOut;
2071 const BlockInfo &PredLiveOut0 = LiveOut.
find(VisitedPreds[0])->second;
2072 const BlockInfo &PredLiveOut1 = LiveOut.
find(VisitedPreds[1])->second;
2073 BlockInfo BBLiveIn = joinBlockInfo(PredLiveOut0, PredLiveOut1);
2078 const auto &PredLiveOut = LiveOut.
find(Pred);
2080 "block should have been processed already");
2081 BBLiveIn = joinBlockInfo(std::move(BBLiveIn), PredLiveOut->second);
2085 auto CurrentLiveInEntry = LiveIn.
find(&BB);
2088 if (CurrentLiveInEntry == LiveIn.
end())
2090 else if (BBLiveIn != CurrentLiveInEntry->second)
2091 CurrentLiveInEntry->second = std::move(BBLiveIn);
2100 auto ALeft =
A.OffsetInBits;
2101 auto BLeft =
B.OffsetInBits;
2105 auto ARight = ALeft +
A.SizeInBits;
2106 auto BRight = BLeft +
B.SizeInBits;
2107 if (BRight > ARight)
2112static std::optional<at::AssignmentInfo>
2117 if (
const auto *SI = dyn_cast<StoreInst>(&
I))
2119 if (
const auto *
MI = dyn_cast<MemIntrinsic>(&
I))
2122 return std::nullopt;
2126 return dyn_cast<DbgDeclareInst>(DVI);
2155 unsigned &TrackedVariablesVectorSize) {
2168 auto ProcessDbgRecord = [&](
auto *
Record,
auto &DeclareList) {
2175 if (!VarsWithStackSlot.
contains(DA))
2177 if (Seen.
insert(DV).second)
2178 FragmentMap[DA].push_back(DV);
2180 for (
auto &BB : Fn) {
2181 for (
auto &
I : BB) {
2183 ProcessDbgRecord(&DVR, DPDeclares);
2184 if (
auto *DII = dyn_cast<DbgVariableIntrinsic>(&
I)) {
2185 ProcessDbgRecord(DII, InstDeclares);
2189 auto HandleDbgAssignForStore = [&](
auto *Assign) {
2190 std::optional<DIExpression::FragmentInfo> FragInfo;
2195 I.getDataLayout(),
Info->Base,
2196 Info->OffsetInBits,
Info->SizeInBits, Assign, FragInfo) ||
2197 (FragInfo && FragInfo->SizeInBits == 0))
2206 FragInfo = Assign->getExpression()->getFragmentInfo();
2210 Assign->getDebugLoc().getInlinedAt());
2212 if (!VarsWithStackSlot.
contains(DA))
2216 UntaggedStoreVars[&
I].push_back(
2219 if (Seen.
insert(DV).second)
2220 FragmentMap[DA].push_back(DV);
2223 HandleDbgAssignForStore(DAI);
2225 HandleDbgAssignForStore(DVR);
2232 for (
auto &Pair : FragmentMap) {
2234 std::sort(Frags.
begin(), Frags.
end(),
2236 return Elmt.getFragmentOrDefault().SizeInBits >
2237 Next.getFragmentOrDefault().SizeInBits;
2245 for (
auto &Pair : FragmentMap) {
2246 auto &Frags = Pair.second;
2247 for (
auto It = Frags.begin(), IEnd = Frags.end(); It != IEnd; ++It) {
2257 for (; OtherIt != IEnd; ++OtherIt) {
2261 Map[OtherVar].push_back(ThisVar);
2272 for (
auto *DDI : InstDeclares)
2274 DDI->getDebugLoc(), DDI->getWrappedLocation());
2275 for (
auto *DVR : DPDeclares)
2285 <<
": too many blocks (" << Fn.
size() <<
")\n");
2290 FnVarLocs = FnVarLocsBuilder;
2300 Fn, FnVarLocs, *VarsWithStackSlot, UntaggedStoreVars,
2301 TrackedVariablesVectorSize);
2305 std::priority_queue<unsigned int, std::vector<unsigned int>,
2306 std::greater<unsigned int>>
2308 std::priority_queue<unsigned int, std::vector<unsigned int>,
2309 std::greater<unsigned int>>
2314 unsigned int RPONumber = 0;
2316 OrderToBB[RPONumber] = BB;
2317 BBToOrder[BB] = RPONumber;
2318 Worklist.push(RPONumber);
2321 LiveIn.
init(RPONumber);
2322 LiveOut.
init(RPONumber);
2336 while (!Worklist.empty()) {
2341 while (!Worklist.empty()) {
2345 bool InChanged = join(*BB, Visited);
2347 InChanged |= Visited.
insert(BB).second;
2352 BlockInfo LiveSet = LiveIn[BB];
2355 process(*BB, &LiveSet);
2358 if (LiveOut[BB] != LiveSet) {
2360 <<
" has new OutLocs, add succs to worklist: [ ");
2361 LiveOut[BB] = std::move(LiveSet);
2363 if (OnPending.
insert(Succ).second) {
2365 Pending.push(BBToOrder[Succ]);
2372 Worklist.swap(Pending);
2375 assert(Pending.empty() &&
"Pending should be empty");
2381 bool InsertedAnyIntrinsics =
false;
2390 for (
const auto &Pair : InsertBeforeMap) {
2391 auto &Vec = Pair.second;
2397 if (NotAlwaysStackHomed.contains(Aggr))
2407 NotAlwaysStackHomed.insert(Aggr);
2416 if (AlwaysStackHomed.
insert(Aggr).second) {
2425 InsertedAnyIntrinsics =
true;
2431 for (
const auto &[InsertBefore, Vec] : InsertBeforeMap) {
2438 if (AlwaysStackHomed.
contains(Aggr))
2441 InsertedAnyIntrinsics =
true;
2444 FnVarLocs->
setWedge(InsertBefore, std::move(NewDefs));
2447 InsertedAnyIntrinsics |= emitPromotedVarLocs(FnVarLocs);
2449 return InsertedAnyIntrinsics;
2452bool AssignmentTrackingLowering::emitPromotedVarLocs(
2454 bool InsertedAnyIntrinsics =
false;
2457 auto TranslateDbgRecord = [&](
auto *
Record) {
2463 assert(InsertBefore &&
"Unexpected: debug intrinsics after a terminator");
2467 InsertedAnyIntrinsics =
true;
2469 for (
auto &BB : Fn) {
2470 for (
auto &
I : BB) {
2474 TranslateDbgRecord(&DVR);
2475 auto *DVI = dyn_cast<DbgValueInst>(&
I);
2477 TranslateDbgRecord(DVI);
2480 return InsertedAnyIntrinsics;
2493 bool Changed =
false;
2499 if (!isa<DbgVariableIntrinsic>(
I)) {
2501 VariableDefinedBytes.
clear();
2504 auto HandleLocsForWedge = [&](
auto *WedgePosition) {
2506 const auto *Locs = FnVarLocs.
getWedge(WedgePosition);
2511 bool ChangedThisWedge =
false;
2516 for (
auto RIt = Locs->rbegin(), REnd = Locs->rend(); RIt != REnd; ++RIt) {
2520 uint64_t SizeInBits = Aggr.first->getSizeInBits().value_or(0);
2524 const uint64_t MaxSizeBytes = 2048;
2526 if (SizeInBytes == 0 || SizeInBytes > MaxSizeBytes) {
2540 bool FirstDefinition = InsertResult.second;
2541 BitVector &DefinedBytes = InsertResult.first->second;
2544 RIt->Expr->getFragmentInfo().value_or(
2546 bool InvalidFragment = Fragment.
endInBits() > SizeInBits;
2551 if (FirstDefinition || InvalidFragment ||
2553 if (!InvalidFragment)
2554 DefinedBytes.
set(StartInBytes, EndInBytes);
2561 ChangedThisWedge =
true;
2566 if (ChangedThisWedge) {
2567 std::reverse(NewDefsReversed.
begin(), NewDefsReversed.
end());
2568 FnVarLocs.
setWedge(WedgePosition, std::move(NewDefsReversed));
2573 HandleLocsForWedge(&
I);
2575 HandleLocsForWedge(&DVR);
2591 bool Changed =
false;
2600 auto HandleLocsForWedge = [&](
auto *WedgePosition) {
2601 const auto *Locs = FnVarLocs.
getWedge(WedgePosition);
2606 bool ChangedThisWedge =
false;
2614 std::nullopt, Loc.DL.getInlinedAt());
2615 auto VMI = VariableMap.
find(Key);
2619 if (VMI == VariableMap.
end() || VMI->second.first != Loc.Values ||
2620 VMI->second.second != Loc.Expr) {
2621 VariableMap[Key] = {Loc.Values, Loc.Expr};
2627 ChangedThisWedge =
true;
2632 if (ChangedThisWedge) {
2633 FnVarLocs.
setWedge(WedgePosition, std::move(NewDefs));
2640 HandleLocsForWedge(&DVR);
2641 HandleLocsForWedge(&
I);
2666 VarsWithDef[
A].
insert(V.getFragmentOrDefault());
2672 auto FragsIt = VarsWithDef.
find(
A);
2673 if (FragsIt == VarsWithDef.
end())
2676 return DIExpression::fragmentsOverlap(Frag, V.getFragmentOrDefault());
2680 bool Changed =
false;
2688 auto HandleLocsForWedge = [&](
auto *WedgePosition) {
2689 const auto *Locs = FnVarLocs.
getWedge(WedgePosition);
2694 bool ChangedThisWedge =
false;
2702 Loc.DL.getInlinedAt()};
2707 if (Loc.Values.isKillLocation(Loc.Expr) && !HasDefinedBits(Aggr, Var)) {
2710 ChangedThisWedge =
true;
2714 DefineBits(Aggr, Var);
2719 if (ChangedThisWedge) {
2720 FnVarLocs.
setWedge(WedgePosition, std::move(NewDefs));
2726 HandleLocsForWedge(&DVR);
2727 HandleLocsForWedge(&
I);
2735 bool MadeChanges =
false;
2749 for (
auto &BB : Fn) {
2750 for (
auto &
I : BB) {
2757 Result.insert({DAI->getVariable(), DAI->getDebugLoc().getInlinedAt()});
2774 bool Changed =
false;
2779 AssignmentTrackingLowering
Pass(Fn, Layout, &VarsWithStackSlot);
2780 Changed =
Pass.run(FnVarLocs);
2784 MemLocFragmentFill
Pass(Fn, &VarsWithStackSlot,
2786 Pass.run(FnVarLocs);
2803 auto &
DL =
F.getDataLayout();
2827 LLVM_DEBUG(
dbgs() <<
"AssignmentTrackingAnalysis run on " <<
F.getName()
2837 Results->init(Builder);
2840 Results->print(
errs(),
F);
2852 "Assignment Tracking Analysis",
false,
true)
for(const MachineOperand &MO :llvm::drop_begin(OldMI.operands(), Desc.getNumOperands()))
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 DIAssignID * getIDFromMarker(const DbgAssignIntrinsic &DAI)
static DenseSet< DebugAggregate > findVarsWithStackSlot(Function &Fn)
static bool fullyContains(DIExpression::FragmentInfo A, DIExpression::FragmentInfo B)
Return true if A fully contains B.
static DebugAggregate getAggregate(const DbgVariableIntrinsic *DII)
static std::optional< at::AssignmentInfo > getUntaggedStoreAssignmentInfo(const Instruction &I, const DataLayout &Layout)
static AssignmentTrackingLowering::OverlapMap buildOverlapMapAndRecordDeclares(Function &Fn, FunctionVarLocsBuilder *FnVarLocs, const DenseSet< DebugAggregate > &VarsWithStackSlot, AssignmentTrackingLowering::UntaggedStoreAssignmentMap &UntaggedStoreVars, unsigned &TrackedVariablesVectorSize)
Build a map of {Variable x: Variables y} where all variable fragments contained within the variable f...
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 DIAssignID * getIDFromInst(const Instruction &I)
DbgAssignIntrinsic * CastToDbgAssign(DbgVariableIntrinsic *DVI)
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 bool hasZeroSizedFragment(T &DbgValue)
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)
DbgDeclareInst * DynCastToDbgDeclare(DbgVariableIntrinsic *DVI)
This file implements the BitVector class.
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
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.
std::optional< std::vector< StOtherPiece > > Other
This file implements a coalescing interval map for small objects.
Module.h This file contains the declarations for the Module class.
uint64_t IntrinsicInst * II
FunctionAnalysisManager FAM
This header defines various interfaces for pass management in LLVM.
#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_>.
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
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
A container for analyses that lazily runs them and caches their results.
PassT::Result & getResult(IRUnitT &IR, ExtraArgTs... ExtraArgs)
Get the result of an analysis pass for a given IR unit.
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...
ArrayRef< T > drop_front(size_t N=1) const
Drop the first N elements of the array.
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.
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 DIExpression * append(const DIExpression *Expr, ArrayRef< uint64_t > Ops)
Append the opcodes Ops to DIExpr.
unsigned getNumElements() const
bool startsWithDeref() const
Return whether the first element a DW_OP_deref.
static 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 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 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 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.
std::optional< uint64_t > getSizeInBits() const
Determines the size of the variable's type.
StringRef getName() const
This class represents an Operation in the Expression.
A parsed version of the target data layout string in and methods for querying it.
This represents the llvm.dbg.assign instruction.
DIAssignID * getAssignID() const
This represents the llvm.dbg.declare instruction.
This is the common base class for debug info intrinsics.
Instruction * MarkedInstr
Link back to the Instruction that owns this marker.
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
This is the common base class for debug info intrinsics for variables.
DILocalVariable * getVariable() const
Record of a variable value-assignment, aka a non instruction representation of the dbg....
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)
PreservedAnalyses run(Function &F, FunctionAnalysisManager &FAM)
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 init(unsigned InitNumEntries)
Implements a dense probed hash-table based set.
Class representing an expression and its matching format.
FunctionPass class - This class is used to implement most global optimizations.
Data structure describing the variable locations in a function.
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.
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.
iterator_range< simple_ilist< DbgRecord >::iterator > getDbgRecordRange() const
Return a range over the DbgRecords attached to this instruction.
const DebugLoc & getDebugLoc() const
Return the debug location for this node as a DebugLoc.
bool hasDbgRecords() const
Returns true if any DbgRecords are attached to this instruction.
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)
This class implements a map that also provides access to all stored values in a deterministic order.
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 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...
reference emplace_back(ArgTypes &&... Args)
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Target - Wrapper for Target specific information.
Triple - Helper class for working with autoconf configuration names.
static 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.
size_t size() const
size - Returns the number of entries in the vector.
iterator end()
Return an iterator to the end of the vector.
iterator begin()
Return an iterator to the start of the vector.
LLVM Value Representation.
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.
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...
void deleteAll(Function *F)
Remove all Assignment Tracking related intrinsics and metadata from F.
AssignmentMarkerRange getAssignmentMarkers(DIAssignID *ID)
Return a range of dbg.assign intrinsics which use \ID as an operand.
SmallVector< DbgVariableRecord * > getDVRAssignmentMarkers(const Instruction *Inst)
std::optional< AssignmentInfo > getAssignmentInfo(const DataLayout &DL, const MemIntrinsic *I)
bool calculateFragmentIntersect(const DataLayout &DL, const Value *Dest, uint64_t SliceOffsetInBits, uint64_t SliceSizeInBits, const DbgAssignIntrinsic *DbgAssign, 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)
std::optional< const char * > toString(const std::optional< DWARFFormValue > &V)
Take an optional DWARFFormValue and try to extract a string value from it.
@ DW_OP_LLVM_fragment
Only used in LLVM metadata.
PointerTypeMap run(const Module &M)
Compute the PointerTypeMap for the module M.
This is an optimization pass for GlobalISel generic memory operations.
void dump(const SparseBitVector< ElementSize > &LHS, raw_ostream &out)
bool all_of(R &&range, UnaryPredicate P)
Provide wrappers to std::all_of which take ranges instead of having to pass begin/end explicitly.
auto successors(const MachineBasicBlock *BB)
bool operator!=(uint64_t V1, const APInt &V2)
bool operator==(const AddressRangeValuePair &LHS, const AddressRangeValuePair &RHS)
Printable print(const GCNRegPressure &RP, const GCNSubtarget *ST=nullptr)
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)
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.
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).
bool isAssignmentTrackingEnabled(const Module &M)
Return true if assignment tracking is enabled for module M.
auto predecessors(const MachineBasicBlock *BB)
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...
uint64_t startInBits() const
Return the index of the first bit of the fragment.
uint64_t endInBits() const
Return the index of the bit after the end of the fragment, e.g.
static VariableID getTombstoneKey()
static bool isEqual(const VariableID &LHS, const VariableID &RHS)
static unsigned getHashValue(const VariableID &Val)
static VariableID getEmptyKey()
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
result_type operator()(const argument_type &Arg) const