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 auto It = Builder.VarLocsBeforeInst.find(&DVR);
234 if (It == Builder.VarLocsBeforeInst.end())
241 unsigned BlockEnd = VarLocRecords.
size();
243 if (BlockEnd != BlockStart)
244 VarLocsBeforeInst[
I] = {BlockStart, BlockEnd};
248 assert(Variables.empty() &&
"Expect clear before init");
251 Variables.reserve(Builder.Variables.
size() + 1);
252 Variables.push_back(
DebugVariable(
nullptr, std::nullopt,
nullptr));
253 Variables.append(Builder.Variables.
begin(), Builder.Variables.
end());
258 VarLocRecords.
clear();
259 VarLocsBeforeInst.clear();
267static std::pair<Value *, DIExpression *>
270 APInt OffsetInBytes(
DL.getTypeSizeInBits(Start->getType()),
false);
272 Start->stripAndAccumulateInBoundsConstantOffsets(
DL, OffsetInBytes);
275 Ops = {dwarf::DW_OP_plus_uconst, OffsetInBytes.
getZExtValue()};
286static std::optional<int64_t>
291 unsigned ExpectedDerefIdx = 0;
293 if (NumElements > 2 && Elements[0] == dwarf::DW_OP_plus_uconst) {
295 ExpectedDerefIdx = 2;
296 }
else if (NumElements > 3 && Elements[0] == dwarf::DW_OP_constu) {
297 ExpectedDerefIdx = 3;
298 if (Elements[2] == dwarf::DW_OP_plus)
300 else if (Elements[2] == dwarf::DW_OP_minus)
307 if (ExpectedDerefIdx >= NumElements)
312 if (Elements[ExpectedDerefIdx] != dwarf::DW_OP_deref)
316 if (NumElements == ExpectedDerefIdx + 1)
318 unsigned ExpectedFragFirstIdx = ExpectedDerefIdx + 1;
319 unsigned ExpectedFragFinalIdx = ExpectedFragFirstIdx + 2;
320 if (NumElements == ExpectedFragFinalIdx + 1 &&
346 Triple(
F.getParent()->getTargetTriple()));
374class MemLocFragmentFill {
378 bool CoalesceAdjacentFragments;
385 OffsetInBitsTy, BaseAddress,
388 FragsInMemMap::Allocator IntervalMapAlloc;
401 unsigned OffsetInBits;
414 static bool intervalMapsAreEqual(
const FragsInMemMap &
A,
415 const FragsInMemMap &
B) {
416 auto AIt =
A.begin(), AEnd =
A.end();
417 auto BIt =
B.begin(), BEnd =
B.end();
418 for (; AIt != AEnd; ++AIt, ++BIt) {
421 if (AIt.start() != BIt.start() || AIt.stop() != BIt.stop())
430 static bool varFragMapsAreEqual(
const VarFragMap &
A,
const VarFragMap &
B) {
431 if (
A.size() !=
B.size())
433 for (
const auto &APair :
A) {
434 auto BIt =
B.find(APair.first);
437 if (!intervalMapsAreEqual(APair.second, BIt->second))
444 std::string
toString(
unsigned BaseID) {
446 return Bases[BaseID].getVariableLocationOp(0)->getName().str();
452 std::string
toString(FragsInMemMap::const_iterator It,
bool Newline =
true) {
454 std::stringstream S(
String);
456 S <<
"[" << It.start() <<
", " << It.stop()
459 S <<
"invalid iterator (end)";
466 FragsInMemMap meetFragments(
const FragsInMemMap &
A,
const FragsInMemMap &
B) {
467 FragsInMemMap
Result(IntervalMapAlloc);
468 for (
auto AIt =
A.begin(), AEnd =
A.end(); AIt != AEnd; ++AIt) {
475 if (!
B.overlaps(AIt.start(), AIt.stop()))
479 auto FirstOverlap =
B.find(AIt.start());
480 assert(FirstOverlap !=
B.end());
481 bool IntersectStart = FirstOverlap.start() < AIt.start();
483 <<
", IntersectStart: " << IntersectStart <<
"\n");
486 auto LastOverlap =
B.find(AIt.stop());
488 LastOverlap !=
B.end() && LastOverlap.start() < AIt.stop();
490 <<
", IntersectEnd: " << IntersectEnd <<
"\n");
493 if (IntersectStart && IntersectEnd && FirstOverlap == LastOverlap) {
501 if (*AIt && *AIt == *FirstOverlap)
502 Result.insert(AIt.start(), AIt.stop(), *AIt);
510 auto Next = FirstOverlap;
511 if (IntersectStart) {
514 if (*AIt && *AIt == *FirstOverlap)
515 Result.insert(AIt.start(), FirstOverlap.stop(), *AIt);
525 if (*AIt && *AIt == *LastOverlap)
526 Result.insert(LastOverlap.start(), AIt.stop(), *AIt);
535 while (Next !=
B.end() && Next.start() < AIt.stop() &&
536 Next.stop() <= AIt.stop()) {
538 <<
"- insert intersection of a and " <<
toString(Next));
539 if (*AIt && *AIt == *Next)
540 Result.insert(Next.start(), Next.stop(), *Next);
549 void meetVars(VarFragMap &
A,
const VarFragMap &
B) {
553 for (
auto It =
A.begin(),
End =
A.end(); It !=
End; ++It) {
554 unsigned AVar = It->first;
555 FragsInMemMap &AFrags = It->second;
556 auto BIt =
B.find(AVar);
557 if (BIt ==
B.end()) {
562 <<
Aggregates[AVar].first->getName() <<
"\n");
563 AFrags = meetFragments(AFrags, BIt->second);
573 bool FirstMeet =
true;
580 if (!Visited.
count(Pred))
583 auto PredLiveOut = LiveOut.
find(Pred);
588 BBLiveIn = PredLiveOut->second;
591 LLVM_DEBUG(
dbgs() <<
"BBLiveIn = meet BBLiveIn, " << Pred->getName()
593 meetVars(BBLiveIn, PredLiveOut->second);
599 if (BBLiveIn.size() == 0)
603 auto CurrentLiveInEntry = LiveIn.
find(&BB);
605 if (CurrentLiveInEntry == LiveIn.
end()) {
608 LiveIn[&BB] = std::move(BBLiveIn);
614 if (!varFragMapsAreEqual(BBLiveIn, CurrentLiveInEntry->second)) {
616 CurrentLiveInEntry->second = std::move(BBLiveIn);
625 unsigned StartBit,
unsigned EndBit,
unsigned Base,
627 assert(StartBit < EndBit &&
"Cannot create fragment of size <= 0");
632 Loc.OffsetInBits = StartBit;
633 Loc.SizeInBits = EndBit - StartBit;
634 assert(
Base &&
"Expected a non-zero ID for Base address");
637 BBInsertBeforeMap[&BB][
Before].push_back(Loc);
639 <<
" bits [" << StartBit <<
", " << EndBit <<
")\n");
647 unsigned StartBit,
unsigned EndBit,
unsigned Base,
649 if (!CoalesceAdjacentFragments)
656 auto CoalescedFrag = FragMap.find(StartBit);
658 if (CoalescedFrag.start() == StartBit && CoalescedFrag.stop() == EndBit)
661 LLVM_DEBUG(
dbgs() <<
"- Insert loc for bits " << CoalescedFrag.start()
662 <<
" to " << CoalescedFrag.stop() <<
"\n");
663 insertMemLoc(BB,
Before, Var, CoalescedFrag.start(), CoalescedFrag.stop(),
668 VarFragMap &LiveSet) {
685 StartBit = Frag->OffsetInBits;
686 EndBit = StartBit + Frag->SizeInBits;
701 const unsigned Base =
702 DerefOffsetInBytes && *DerefOffsetInBytes * 8 == StartBit
706 << StartBit <<
", " << EndBit <<
"): " <<
toString(
Base)
713 auto FragIt = LiveSet.find(Var);
716 if (FragIt == LiveSet.end()) {
718 auto P = LiveSet.try_emplace(Var, FragsInMemMap(IntervalMapAlloc));
719 assert(
P.second &&
"Var already in map?");
721 P.first->second.insert(StartBit, EndBit,
Base);
726 FragsInMemMap &FragMap = FragIt->second;
729 if (!FragMap.overlaps(StartBit, EndBit)) {
731 FragMap.insert(StartBit, EndBit,
Base);
732 coalesceFragments(BB,
Before, Var, StartBit, EndBit,
Base, VarLoc.
DL,
739 auto FirstOverlap = FragMap.find(StartBit);
740 assert(FirstOverlap != FragMap.end());
741 bool IntersectStart = FirstOverlap.start() < StartBit;
744 auto LastOverlap = FragMap.find(EndBit);
745 bool IntersectEnd = LastOverlap.valid() && LastOverlap.start() < EndBit;
748 if (IntersectStart && IntersectEnd && FirstOverlap == LastOverlap) {
749 LLVM_DEBUG(
dbgs() <<
"- Intersect single interval @ both ends\n");
757 auto EndBitOfOverlap = FirstOverlap.stop();
758 unsigned OverlapValue = FirstOverlap.value();
761 FirstOverlap.setStop(StartBit);
762 insertMemLoc(BB,
Before, Var, FirstOverlap.start(), StartBit,
763 OverlapValue, VarLoc.
DL);
766 FragMap.insert(EndBit, EndBitOfOverlap, OverlapValue);
767 insertMemLoc(BB,
Before, Var, EndBit, EndBitOfOverlap, OverlapValue,
771 FragMap.insert(StartBit, EndBit,
Base);
781 if (IntersectStart) {
784 FirstOverlap.setStop(StartBit);
785 insertMemLoc(BB,
Before, Var, FirstOverlap.start(), StartBit,
786 *FirstOverlap, VarLoc.
DL);
795 LastOverlap.setStart(EndBit);
796 insertMemLoc(BB,
Before, Var, EndBit, LastOverlap.stop(), *LastOverlap,
812 auto It = FirstOverlap;
815 while (It.valid() && It.start() >= StartBit && It.stop() <= EndBit) {
820 assert(!FragMap.overlaps(StartBit, EndBit));
822 FragMap.insert(StartBit, EndBit,
Base);
825 coalesceFragments(BB,
Before, Var, StartBit, EndBit,
Base, VarLoc.
DL,
831 void process(
BasicBlock &BB, VarFragMap &LiveSet) {
832 BBInsertBeforeMap[&BB].
clear();
835 if (
const auto *Locs = FnVarLocs->
getWedge(&DVR)) {
837 addDef(Loc, &DVR, *
I.getParent(), LiveSet);
841 if (
const auto *Locs = FnVarLocs->
getWedge(&
I)) {
843 addDef(Loc, &
I, *
I.getParent(), LiveSet);
852 bool CoalesceAdjacentFragments)
853 : Fn(Fn), VarsWithStackSlot(VarsWithStackSlot),
854 CoalesceAdjacentFragments(CoalesceAdjacentFragments) {}
880 this->FnVarLocs = FnVarLocs;
885 std::priority_queue<unsigned int, std::vector<unsigned int>,
886 std::greater<unsigned int>>
888 std::priority_queue<unsigned int, std::vector<unsigned int>,
889 std::greater<unsigned int>>
894 unsigned int RPONumber = 0;
896 OrderToBB[RPONumber] = BB;
897 BBToOrder[BB] = RPONumber;
898 Worklist.push(RPONumber);
901 LiveIn.
init(RPONumber);
902 LiveOut.
init(RPONumber);
915 while (!Worklist.empty() || !Pending.empty()) {
921 while (!Worklist.empty()) {
925 bool InChanged = meet(*BB, Visited);
927 InChanged |= Visited.
insert(BB).second;
930 << BB->
getName() <<
" has new InLocs, process it\n");
934 VarFragMap LiveSet = LiveIn[BB];
937 process(*BB, LiveSet);
940 if (!varFragMapsAreEqual(LiveOut[BB], LiveSet)) {
942 <<
" has new OutLocs, add succs to worklist: [ ");
943 LiveOut[BB] = std::move(LiveSet);
945 if (OnPending.
insert(Succ).second) {
947 Pending.push(BBToOrder[Succ]);
954 Worklist.swap(Pending);
957 assert(Pending.empty() &&
"Pending should be empty");
961 for (
auto &Pair : BBInsertBeforeMap) {
962 InsertMap &
Map = Pair.second;
963 for (
auto &Pair : Map) {
964 auto InsertBefore = Pair.first;
965 assert(InsertBefore &&
"should never be null");
966 auto FragMemLocs = Pair.second;
969 for (
auto &FragMemLoc : FragMemLocs) {
971 if (FragMemLoc.SizeInBits !=
972 *
Aggregates[FragMemLoc.Var].first->getSizeInBits())
974 Expr, FragMemLoc.OffsetInBits, FragMemLoc.SizeInBits);
976 FragMemLoc.OffsetInBits / 8);
978 FragMemLoc.DL.getInlinedAt());
979 FnVarLocs->
addVarLoc(InsertBefore, Var, Expr, FragMemLoc.DL,
980 Bases[FragMemLoc.Base]);
990class AssignmentTrackingLowering {
1015 enum class LocKind { Mem, Val,
None };
1033 enum S { Known, NoneOrPhi }
Status;
1040 bool isSameSourceAssignment(
const Assignment &
Other)
const {
1046 static const char *
LUT[] = {
"Known",
"NoneOrPhi"};
1055 else if (
const auto *DAI = dyn_cast<DbgAssignIntrinsic *>(Source))
1058 OS << cast<DbgVariableRecord *>(Source);
1063 return Assignment(Known,
ID, Source);
1067 "Cannot make an assignment from a non-assign DbgVariableRecord");
1068 return Assignment(Known,
ID, Source);
1071 return Assignment(Known,
ID, Source);
1074 return Assignment(Known,
ID);
1076 static Assignment makeNoneOrPhi() {
return Assignment(NoneOrPhi,
nullptr); }
1078 Assignment() :
Status(NoneOrPhi),
ID(nullptr) {}
1103 using UntaggedStoreAssignmentMap =
1110 unsigned TrackedVariablesVectorSize = 0;
1115 UntaggedStoreAssignmentMap UntaggedStoreVars;
1119 InstInsertMap InsertBeforeMap;
1132 template <
typename T>
1135 static bool mapsAreEqual(
const BitVector &Mask,
const AssignmentMap &
A,
1136 const AssignmentMap &
B) {
1138 return A[VarID].isSameSourceAssignment(B[VarID]);
1150 AssignmentMap StackHomeValue;
1152 AssignmentMap DebugValue;
1167 const AssignmentMap &getAssignmentMap(AssignmentKind Kind)
const {
1170 return StackHomeValue;
1176 AssignmentMap &getAssignmentMap(AssignmentKind Kind) {
1177 return const_cast<AssignmentMap &
>(
1178 const_cast<const BlockInfo *
>(
this)->getAssignmentMap(Kind));
1181 bool isVariableTracked(
VariableID Var)
const {
1182 return VariableIDsInBlock[
static_cast<unsigned>(Var)];
1185 const Assignment &getAssignment(AssignmentKind Kind,
VariableID Var)
const {
1186 assert(isVariableTracked(Var) &&
"Var not tracked in block");
1187 return getAssignmentMap(Kind)[
static_cast<unsigned>(Var)];
1191 assert(isVariableTracked(Var) &&
"Var not tracked in block");
1192 return LiveLoc[
static_cast<unsigned>(Var)];
1198 VariableIDsInBlock.
set(
static_cast<unsigned>(Var));
1199 LiveLoc[
static_cast<unsigned>(Var)] = K;
1205 void setAssignment(AssignmentKind Kind,
VariableID Var,
1206 const Assignment &AV) {
1207 VariableIDsInBlock.
set(
static_cast<unsigned>(Var));
1208 getAssignmentMap(Kind)[
static_cast<unsigned>(Var)] = AV;
1214 bool hasAssignment(AssignmentKind Kind,
VariableID Var,
1215 const Assignment &AV)
const {
1216 if (!isVariableTracked(Var))
1218 return AV.isSameSourceAssignment(getAssignment(Kind, Var));
1224 return VariableIDsInBlock ==
Other.VariableIDsInBlock &&
1225 LiveLoc ==
Other.LiveLoc &&
1226 mapsAreEqual(VariableIDsInBlock, StackHomeValue,
1227 Other.StackHomeValue) &&
1228 mapsAreEqual(VariableIDsInBlock, DebugValue,
Other.DebugValue);
1232 return LiveLoc.size() == DebugValue.size() &&
1233 LiveLoc.size() == StackHomeValue.size();
1237 void init(
int NumVars) {
1238 StackHomeValue.clear();
1241 VariableIDsInBlock =
BitVector(NumVars);
1242 StackHomeValue.insert(StackHomeValue.begin(), NumVars,
1243 Assignment::makeNoneOrPhi());
1244 DebugValue.insert(DebugValue.begin(), NumVars,
1245 Assignment::makeNoneOrPhi());
1246 LiveLoc.
insert(LiveLoc.
begin(), NumVars, LocKind::None);
1250 template <
typename ElmtType,
typename FnInputType>
1254 ElmtType (*Fn)(FnInputType, FnInputType)) {
1259 static BlockInfo join(
const BlockInfo &
A,
const BlockInfo &
B,
int NumVars) {
1279 Intersect &=
B.VariableIDsInBlock;
1282 joinElmt(
VarID, Join.LiveLoc,
A.LiveLoc,
B.LiveLoc, joinKind);
1283 joinElmt(
VarID, Join.DebugValue,
A.DebugValue,
B.DebugValue,
1285 joinElmt(
VarID, Join.StackHomeValue,
A.StackHomeValue,
B.StackHomeValue,
1289 Join.VariableIDsInBlock =
A.VariableIDsInBlock;
1290 Join.VariableIDsInBlock |=
B.VariableIDsInBlock;
1337 static LocKind joinKind(LocKind
A, LocKind
B);
1338 static Assignment joinAssignment(
const Assignment &
A,
const Assignment &
B);
1339 BlockInfo joinBlockInfo(
const BlockInfo &
A,
const BlockInfo &
B);
1345 void process(
BasicBlock &BB, BlockInfo *LiveSet);
1350 void processNonDbgInstruction(
Instruction &
I, BlockInfo *LiveSet);
1354 void processTaggedInstruction(
Instruction &
I, BlockInfo *LiveSet);
1357 void processUntaggedInstruction(
Instruction &
I, BlockInfo *LiveSet);
1358 void processDbgAssign(AssignRecord Assign, BlockInfo *LiveSet);
1360 void processDbgValue(
1362 BlockInfo *LiveSet);
1364 void addMemDef(BlockInfo *LiveSet,
VariableID Var,
const Assignment &AV);
1366 void addDbgDef(BlockInfo *LiveSet,
VariableID Var,
const Assignment &AV);
1370 void setLocKind(BlockInfo *LiveSet,
VariableID Var, LocKind K);
1373 LocKind getLocKind(BlockInfo *LiveSet,
VariableID Var);
1375 bool hasVarWithAssignment(BlockInfo *LiveSet, BlockInfo::AssignmentKind Kind,
1391 : Fn(Fn), Layout(Layout), VarsWithStackSlot(VarsWithStackSlot) {}
1399AssignmentTrackingLowering::getContainedFragments(
VariableID Var)
const {
1400 auto R = VarContains.
find(Var);
1401 if (R == VarContains.
end())
1406void AssignmentTrackingLowering::touchFragment(
VariableID Var) {
1407 VarsTouchedThisFrame.insert(Var);
1410void AssignmentTrackingLowering::setLocKind(BlockInfo *LiveSet,
VariableID Var,
1412 auto SetKind = [
this](BlockInfo *LiveSet,
VariableID Var, LocKind
K) {
1413 LiveSet->setLocKind(Var, K);
1416 SetKind(LiveSet, Var, K);
1419 for (
VariableID Frag : getContainedFragments(Var))
1420 SetKind(LiveSet, Frag, K);
1423AssignmentTrackingLowering::LocKind
1424AssignmentTrackingLowering::getLocKind(BlockInfo *LiveSet,
VariableID Var) {
1425 return LiveSet->getLocKind(Var);
1428void AssignmentTrackingLowering::addMemDef(BlockInfo *LiveSet,
VariableID Var,
1429 const Assignment &AV) {
1430 LiveSet->setAssignment(BlockInfo::Stack, Var, AV);
1435 Assignment FragAV = AV;
1436 FragAV.Source =
nullptr;
1437 for (
VariableID Frag : getContainedFragments(Var))
1438 LiveSet->setAssignment(BlockInfo::Stack, Frag, FragAV);
1441void AssignmentTrackingLowering::addDbgDef(BlockInfo *LiveSet,
VariableID Var,
1442 const Assignment &AV) {
1443 LiveSet->setAssignment(BlockInfo::Debug, Var, AV);
1448 Assignment FragAV = AV;
1449 FragAV.Source =
nullptr;
1450 for (
VariableID Frag : getContainedFragments(Var))
1451 LiveSet->setAssignment(BlockInfo::Debug, Frag, FragAV);
1455 return cast<DIAssignID>(
I.getMetadata(LLVMContext::MD_DIAssignID));
1464 "Cannot get a DIAssignID from a non-assign DbgVariableRecord!");
1469bool AssignmentTrackingLowering::hasVarWithAssignment(
1470 BlockInfo *LiveSet, BlockInfo::AssignmentKind Kind,
VariableID Var,
1471 const Assignment &AV) {
1472 if (!LiveSet->hasAssignment(Kind, Var, AV))
1477 for (
VariableID Frag : getContainedFragments(Var))
1478 if (!LiveSet->hasAssignment(Kind, Frag, AV))
1484const char *
locStr(AssignmentTrackingLowering::LocKind Loc) {
1485 using LocKind = AssignmentTrackingLowering::LocKind;
1511 if (isa<const Instruction *>(InsertPt))
1512 return getNextNode(cast<const Instruction *>(InsertPt));
1513 return getNextNode(cast<const DbgRecord *>(InsertPt));
1517 return cast<DbgAssignIntrinsic>(DVI);
1522 "Attempted to cast non-assign DbgVariableRecord to DVRAssign.");
1526void AssignmentTrackingLowering::emitDbgValue(
1527 AssignmentTrackingLowering::LocKind Kind,
1529 if (isa<DbgAssignIntrinsic *>(Source))
1530 emitDbgValue(Kind, cast<DbgAssignIntrinsic *>(Source),
After);
1532 emitDbgValue(Kind, cast<DbgVariableRecord *>(Source),
After);
1534template <
typename T>
1535void AssignmentTrackingLowering::emitDbgValue(
1536 AssignmentTrackingLowering::LocKind Kind,
const T Source,
1548 assert(InsertBefore &&
"Shouldn't be inserting after a terminator");
1557 InsertBeforeMap[InsertBefore].
push_back(VarLoc);
1561 if (Kind == LocKind::Mem) {
1565 if (
Assign->isKillAddress()) {
1567 Kind = LocKind::Val;
1572 "fragment info should be stored in value-expression only");
1575 if (
auto OptFragInfo =
Source->getExpression()->getFragmentInfo()) {
1576 auto FragInfo = *OptFragInfo;
1578 Expr, FragInfo.OffsetInBits, FragInfo.SizeInBits);
1581 std::tie(Val, Expr) =
1588 if (Kind == LocKind::Val) {
1589 Emit(
Source->getRawLocation(),
Source->getExpression());
1593 if (Kind == LocKind::None) {
1594 Emit(
nullptr,
Source->getExpression());
1599void AssignmentTrackingLowering::processNonDbgInstruction(
1600 Instruction &
I, AssignmentTrackingLowering::BlockInfo *LiveSet) {
1601 if (
I.hasMetadata(LLVMContext::MD_DIAssignID))
1602 processTaggedInstruction(
I, LiveSet);
1604 processUntaggedInstruction(
I, LiveSet);
1607void AssignmentTrackingLowering::processUntaggedInstruction(
1608 Instruction &
I, AssignmentTrackingLowering::BlockInfo *LiveSet) {
1620 assert(!
I.hasMetadata(LLVMContext::MD_DIAssignID));
1621 auto It = UntaggedStoreVars.find(&
I);
1622 if (It == UntaggedStoreVars.end())
1625 LLVM_DEBUG(
dbgs() <<
"processUntaggedInstruction on UNTAGGED INST " <<
I
1629 for (
auto [Var, Info] : It->second) {
1633 addMemDef(LiveSet, Var, Assignment::makeNoneOrPhi());
1634 addDbgDef(LiveSet, Var, Assignment::makeNoneOrPhi());
1635 setLocKind(LiveSet, Var, LocKind::Mem);
1643 if (
auto Frag =
V.getFragment()) {
1646 assert(R &&
"unexpected createFragmentExpression failure");
1650 if (
Info.OffsetInBits)
1651 Ops = {dwarf::DW_OP_plus_uconst,
Info.OffsetInBits / 8};
1658 assert(InsertBefore &&
"Shouldn't be inserting after a terminator");
1663 Fn.
getContext(), 0, 0,
V.getVariable()->getScope(), InlinedAt);
1672 InsertBeforeMap[InsertBefore].push_back(VarLoc);
1676void AssignmentTrackingLowering::processTaggedInstruction(
1677 Instruction &
I, AssignmentTrackingLowering::BlockInfo *LiveSet) {
1684 if (Linked.empty() && LinkedDPAssigns.empty())
1688 auto ProcessLinkedAssign = [&](
auto *
Assign) {
1693 "expected Assign's variable to have stack slot");
1696 addMemDef(LiveSet, Var, AV);
1704 if (hasVarWithAssignment(LiveSet, BlockInfo::Debug, Var, AV)) {
1710 LiveSet->DebugValue[
static_cast<unsigned>(Var)].
dump(
dbgs());
1712 setLocKind(LiveSet, Var, LocKind::Mem);
1713 emitDbgValue(LocKind::Mem, Assign, &
I);
1722 LocKind PrevLoc = getLocKind(LiveSet, Var);
1724 case LocKind::Val: {
1728 setLocKind(LiveSet, Var, LocKind::Val);
1730 case LocKind::Mem: {
1734 Assignment DbgAV = LiveSet->getAssignment(BlockInfo::Debug, Var);
1735 if (DbgAV.Status == Assignment::NoneOrPhi) {
1738 setLocKind(LiveSet, Var, LocKind::None);
1739 emitDbgValue(LocKind::None, Assign, &
I);
1743 setLocKind(LiveSet, Var, LocKind::Val);
1745 emitDbgValue(LocKind::Val, DbgAV.Source, &
I);
1748 emitDbgValue(LocKind::None, Assign, &
I);
1752 case LocKind::None: {
1756 setLocKind(LiveSet, Var, LocKind::None);
1761 ProcessLinkedAssign(DAI);
1763 ProcessLinkedAssign(DVR);
1766void AssignmentTrackingLowering::processDbgAssign(AssignRecord Assign,
1767 BlockInfo *LiveSet) {
1768 auto ProcessDbgAssignImpl = [&](
auto *DbgAssign) {
1775 Assignment AV = Assignment::make(
getIDFromMarker(*DbgAssign), DbgAssign);
1776 addDbgDef(LiveSet, Var, AV);
1778 LLVM_DEBUG(
dbgs() <<
"processDbgAssign on " << *DbgAssign <<
"\n";);
1784 if (hasVarWithAssignment(LiveSet, BlockInfo::Stack, Var, AV)) {
1789 if (DbgAssign->isKillAddress()) {
1792 <<
"Val, Stack matches Debug program but address is killed\n";);
1793 Kind = LocKind::Val;
1796 Kind = LocKind::Mem;
1798 setLocKind(LiveSet, Var, Kind);
1799 emitDbgValue(Kind, DbgAssign, DbgAssign);
1804 setLocKind(LiveSet, Var, LocKind::Val);
1805 emitDbgValue(LocKind::Val, DbgAssign, DbgAssign);
1808 if (isa<DbgVariableRecord *>(Assign))
1809 return ProcessDbgAssignImpl(cast<DbgVariableRecord *>(Assign));
1810 return ProcessDbgAssignImpl(cast<DbgAssignIntrinsic *>(Assign));
1813void AssignmentTrackingLowering::processDbgValue(
1815 BlockInfo *LiveSet) {
1816 auto ProcessDbgValueImpl = [&](
auto *
DbgValue) {
1829 Assignment AV = Assignment::makeNoneOrPhi();
1830 addDbgDef(LiveSet, Var, AV);
1834 <<
" -> Val, dbg.value override");
1836 setLocKind(LiveSet, Var, LocKind::Val);
1839 if (isa<DbgVariableRecord *>(DbgValueRecord))
1840 return ProcessDbgValueImpl(cast<DbgVariableRecord *>(DbgValueRecord));
1841 return ProcessDbgValueImpl(cast<DbgValueInst *>(DbgValueRecord));
1845 if (
auto F =
DbgValue.getExpression()->getFragmentInfo())
1846 return F->SizeInBits == 0;
1850void AssignmentTrackingLowering::processDbgInstruction(
1852 auto *DVI = dyn_cast<DbgVariableIntrinsic>(&
I);
1860 if (
auto *DAI = dyn_cast<DbgAssignIntrinsic>(&
I))
1861 processDbgAssign(DAI, LiveSet);
1862 else if (
auto *DVI = dyn_cast<DbgValueInst>(&
I))
1863 processDbgValue(DVI, LiveSet);
1865void AssignmentTrackingLowering::processDbgVariableRecord(
1872 processDbgAssign(&DVR, LiveSet);
1874 processDbgValue(&DVR, LiveSet);
1878 assert(!
After.isTerminator() &&
"Can't insert after a terminator");
1880 if (R == InsertBeforeMap.end())
1886 if (R == InsertBeforeMap.end())
1891void AssignmentTrackingLowering::process(
BasicBlock &BB, BlockInfo *LiveSet) {
1894 bool ProcessedLeadingDbgRecords = !BB.
begin()->hasDbgRecords();
1896 assert(VarsTouchedThisFrame.empty());
1903 if (ProcessedLeadingDbgRecords) {
1908 if (!isa<DbgInfoIntrinsic>(&*
II)) {
1909 if (
II->isTerminator())
1911 resetInsertionPoint(*
II);
1912 processNonDbgInstruction(*
II, LiveSet);
1913 assert(LiveSet->isValid());
1920 if (
II != EI &&
II->hasDbgRecords()) {
1925 resetInsertionPoint(DVR);
1926 processDbgVariableRecord(DVR, LiveSet);
1927 assert(LiveSet->isValid());
1930 ProcessedLeadingDbgRecords =
true;
1932 auto *
Dbg = dyn_cast<DbgInfoIntrinsic>(&*
II);
1935 resetInsertionPoint(*
II);
1936 processDbgInstruction(*Dbg, LiveSet);
1937 assert(LiveSet->isValid());
1947 for (
auto Var : VarsTouchedThisFrame) {
1948 LocKind Loc = getLocKind(LiveSet, Var);
1956 if (Loc != LocKind::Mem) {
1959 NotAlwaysStackHomed.insert(Aggr);
1962 VarsTouchedThisFrame.clear();
1966AssignmentTrackingLowering::LocKind
1967AssignmentTrackingLowering::joinKind(LocKind
A, LocKind
B) {
1970 return A ==
B ?
A : LocKind::None;
1973AssignmentTrackingLowering::Assignment
1974AssignmentTrackingLowering::joinAssignment(
const Assignment &
A,
1975 const Assignment &
B) {
1982 if (!
A.isSameSourceAssignment(
B))
1983 return Assignment::makeNoneOrPhi();
1984 if (
A.Status == Assignment::NoneOrPhi)
1985 return Assignment::makeNoneOrPhi();
2000 auto JoinSource = [&]() -> AssignRecord {
2001 if (
A.Source ==
B.Source)
2003 if (!
A.Source || !
B.Source)
2004 return AssignRecord();
2005 assert(isa<DbgVariableRecord *>(
A.Source) ==
2006 isa<DbgVariableRecord *>(
B.Source));
2007 if (isa<DbgVariableRecord *>(
A.Source) &&
2008 cast<DbgVariableRecord *>(
A.Source)->isEquivalentTo(
2009 *cast<DbgVariableRecord *>(
B.Source)))
2011 if (isa<DbgAssignIntrinsic *>(
A.Source) &&
2012 cast<DbgAssignIntrinsic *>(
A.Source)->isIdenticalTo(
2013 cast<DbgAssignIntrinsic *>(
B.Source)))
2015 return AssignRecord();
2017 AssignRecord
Source = JoinSource();
2018 assert(
A.Status ==
B.Status &&
A.Status == Assignment::Known);
2020 return Assignment::make(
A.ID, Source);
2023AssignmentTrackingLowering::BlockInfo
2024AssignmentTrackingLowering::joinBlockInfo(
const BlockInfo &
A,
2025 const BlockInfo &
B) {
2026 return BlockInfo::join(
A,
B, TrackedVariablesVectorSize);
2029bool AssignmentTrackingLowering::join(
2041 if (Visited.
count(Pred))
2046 if (VisitedPreds.
empty()) {
2048 bool DidInsert = It.second;
2050 It.first->second.init(TrackedVariablesVectorSize);
2055 if (VisitedPreds.
size() == 1) {
2056 const BlockInfo &PredLiveOut = LiveOut.
find(VisitedPreds[0])->second;
2057 auto CurrentLiveInEntry = LiveIn.
find(&BB);
2061 if (CurrentLiveInEntry == LiveIn.
end())
2062 LiveIn.
insert(std::make_pair(&BB, PredLiveOut));
2063 else if (PredLiveOut != CurrentLiveInEntry->second)
2064 CurrentLiveInEntry->second = PredLiveOut;
2072 const BlockInfo &PredLiveOut0 = LiveOut.
find(VisitedPreds[0])->second;
2073 const BlockInfo &PredLiveOut1 = LiveOut.
find(VisitedPreds[1])->second;
2074 BlockInfo BBLiveIn = joinBlockInfo(PredLiveOut0, PredLiveOut1);
2079 const auto &PredLiveOut = LiveOut.
find(Pred);
2081 "block should have been processed already");
2082 BBLiveIn = joinBlockInfo(std::move(BBLiveIn), PredLiveOut->second);
2086 auto CurrentLiveInEntry = LiveIn.
find(&BB);
2089 if (CurrentLiveInEntry == LiveIn.
end())
2091 else if (BBLiveIn != CurrentLiveInEntry->second)
2092 CurrentLiveInEntry->second = std::move(BBLiveIn);
2101 auto ALeft =
A.OffsetInBits;
2102 auto BLeft =
B.OffsetInBits;
2106 auto ARight = ALeft +
A.SizeInBits;
2107 auto BRight = BLeft +
B.SizeInBits;
2108 if (BRight > ARight)
2113static std::optional<at::AssignmentInfo>
2118 if (
const auto *SI = dyn_cast<StoreInst>(&
I))
2120 if (
const auto *
MI = dyn_cast<MemIntrinsic>(&
I))
2123 return std::nullopt;
2127 return dyn_cast<DbgDeclareInst>(DVI);
2156 unsigned &TrackedVariablesVectorSize) {
2169 auto ProcessDbgRecord = [&](
auto *
Record,
auto &DeclareList) {
2176 if (!VarsWithStackSlot.
contains(DA))
2178 if (Seen.
insert(DV).second)
2179 FragmentMap[DA].push_back(DV);
2181 for (
auto &BB : Fn) {
2182 for (
auto &
I : BB) {
2184 ProcessDbgRecord(&DVR, DPDeclares);
2185 if (
auto *DII = dyn_cast<DbgVariableIntrinsic>(&
I)) {
2186 ProcessDbgRecord(DII, InstDeclares);
2190 auto HandleDbgAssignForStore = [&](
auto *Assign) {
2191 std::optional<DIExpression::FragmentInfo> FragInfo;
2196 I.getDataLayout(),
Info->Base,
2197 Info->OffsetInBits,
Info->SizeInBits, Assign, FragInfo) ||
2198 (FragInfo && FragInfo->SizeInBits == 0))
2207 FragInfo = Assign->getExpression()->getFragmentInfo();
2211 Assign->getDebugLoc().getInlinedAt());
2213 if (!VarsWithStackSlot.
contains(DA))
2217 UntaggedStoreVars[&
I].push_back(
2220 if (Seen.
insert(DV).second)
2221 FragmentMap[DA].push_back(DV);
2224 HandleDbgAssignForStore(DAI);
2226 HandleDbgAssignForStore(DVR);
2233 for (
auto &Pair : FragmentMap) {
2235 std::sort(Frags.
begin(), Frags.
end(),
2237 return Elmt.getFragmentOrDefault().SizeInBits >
2238 Next.getFragmentOrDefault().SizeInBits;
2246 for (
auto &Pair : FragmentMap) {
2247 auto &Frags = Pair.second;
2248 for (
auto It = Frags.begin(), IEnd = Frags.end(); It != IEnd; ++It) {
2258 for (; OtherIt != IEnd; ++OtherIt) {
2262 Map[OtherVar].push_back(ThisVar);
2273 for (
auto *DDI : InstDeclares)
2275 DDI->getDebugLoc(), DDI->getWrappedLocation());
2276 for (
auto *DVR : DPDeclares)
2286 <<
": too many blocks (" << Fn.
size() <<
")\n");
2291 FnVarLocs = FnVarLocsBuilder;
2301 Fn, FnVarLocs, *VarsWithStackSlot, UntaggedStoreVars,
2302 TrackedVariablesVectorSize);
2306 std::priority_queue<unsigned int, std::vector<unsigned int>,
2307 std::greater<unsigned int>>
2309 std::priority_queue<unsigned int, std::vector<unsigned int>,
2310 std::greater<unsigned int>>
2315 unsigned int RPONumber = 0;
2317 OrderToBB[RPONumber] = BB;
2318 BBToOrder[BB] = RPONumber;
2319 Worklist.push(RPONumber);
2322 LiveIn.
init(RPONumber);
2323 LiveOut.
init(RPONumber);
2337 while (!Worklist.empty()) {
2342 while (!Worklist.empty()) {
2346 bool InChanged = join(*BB, Visited);
2348 InChanged |= Visited.
insert(BB).second;
2353 BlockInfo LiveSet = LiveIn[BB];
2356 process(*BB, &LiveSet);
2359 if (LiveOut[BB] != LiveSet) {
2361 <<
" has new OutLocs, add succs to worklist: [ ");
2362 LiveOut[BB] = std::move(LiveSet);
2364 if (OnPending.
insert(Succ).second) {
2366 Pending.push(BBToOrder[Succ]);
2373 Worklist.swap(Pending);
2376 assert(Pending.empty() &&
"Pending should be empty");
2382 bool InsertedAnyIntrinsics =
false;
2391 for (
const auto &Pair : InsertBeforeMap) {
2392 auto &Vec = Pair.second;
2398 if (NotAlwaysStackHomed.contains(Aggr))
2408 NotAlwaysStackHomed.insert(Aggr);
2417 if (AlwaysStackHomed.
insert(Aggr).second) {
2426 InsertedAnyIntrinsics =
true;
2432 for (
const auto &[InsertBefore, Vec] : InsertBeforeMap) {
2439 if (AlwaysStackHomed.
contains(Aggr))
2442 InsertedAnyIntrinsics =
true;
2445 FnVarLocs->
setWedge(InsertBefore, std::move(NewDefs));
2448 InsertedAnyIntrinsics |= emitPromotedVarLocs(FnVarLocs);
2450 return InsertedAnyIntrinsics;
2453bool AssignmentTrackingLowering::emitPromotedVarLocs(
2455 bool InsertedAnyIntrinsics =
false;
2458 auto TranslateDbgRecord = [&](
auto *
Record) {
2464 assert(InsertBefore &&
"Unexpected: debug intrinsics after a terminator");
2468 InsertedAnyIntrinsics =
true;
2470 for (
auto &BB : Fn) {
2471 for (
auto &
I : BB) {
2475 TranslateDbgRecord(&DVR);
2476 auto *DVI = dyn_cast<DbgValueInst>(&
I);
2478 TranslateDbgRecord(DVI);
2481 return InsertedAnyIntrinsics;
2494 bool Changed =
false;
2500 if (!isa<DbgVariableIntrinsic>(
I)) {
2502 VariableDefinedBytes.
clear();
2505 auto HandleLocsForWedge = [&](
auto *WedgePosition) {
2507 const auto *Locs = FnVarLocs.
getWedge(WedgePosition);
2512 bool ChangedThisWedge =
false;
2517 for (
auto RIt = Locs->rbegin(), REnd = Locs->rend(); RIt != REnd; ++RIt) {
2521 uint64_t SizeInBits = Aggr.first->getSizeInBits().value_or(0);
2525 const uint64_t MaxSizeBytes = 2048;
2527 if (SizeInBytes == 0 || SizeInBytes > MaxSizeBytes) {
2541 bool FirstDefinition = InsertResult.second;
2542 BitVector &DefinedBytes = InsertResult.first->second;
2545 RIt->Expr->getFragmentInfo().value_or(
2547 bool InvalidFragment = Fragment.
endInBits() > SizeInBits;
2552 if (FirstDefinition || InvalidFragment ||
2554 if (!InvalidFragment)
2555 DefinedBytes.
set(StartInBytes, EndInBytes);
2562 ChangedThisWedge =
true;
2567 if (ChangedThisWedge) {
2568 std::reverse(NewDefsReversed.
begin(), NewDefsReversed.
end());
2569 FnVarLocs.
setWedge(WedgePosition, std::move(NewDefsReversed));
2574 HandleLocsForWedge(&
I);
2576 HandleLocsForWedge(&DVR);
2592 bool Changed =
false;
2601 auto HandleLocsForWedge = [&](
auto *WedgePosition) {
2602 const auto *Locs = FnVarLocs.
getWedge(WedgePosition);
2607 bool ChangedThisWedge =
false;
2615 std::nullopt, Loc.DL.getInlinedAt());
2616 auto VMI = VariableMap.
find(Key);
2620 if (VMI == VariableMap.
end() || VMI->second.first != Loc.Values ||
2621 VMI->second.second != Loc.Expr) {
2622 VariableMap[Key] = {Loc.Values, Loc.Expr};
2628 ChangedThisWedge =
true;
2633 if (ChangedThisWedge) {
2634 FnVarLocs.
setWedge(WedgePosition, std::move(NewDefs));
2641 HandleLocsForWedge(&DVR);
2642 HandleLocsForWedge(&
I);
2667 VarsWithDef[
A].
insert(V.getFragmentOrDefault());
2673 auto FragsIt = VarsWithDef.
find(
A);
2674 if (FragsIt == VarsWithDef.
end())
2677 return DIExpression::fragmentsOverlap(Frag, V.getFragmentOrDefault());
2681 bool Changed =
false;
2689 auto HandleLocsForWedge = [&](
auto *WedgePosition) {
2690 const auto *Locs = FnVarLocs.
getWedge(WedgePosition);
2695 bool ChangedThisWedge =
false;
2703 Loc.DL.getInlinedAt()};
2708 if (Loc.Values.isKillLocation(Loc.Expr) && !HasDefinedBits(Aggr, Var)) {
2711 ChangedThisWedge =
true;
2715 DefineBits(Aggr, Var);
2720 if (ChangedThisWedge) {
2721 FnVarLocs.
setWedge(WedgePosition, std::move(NewDefs));
2727 HandleLocsForWedge(&DVR);
2728 HandleLocsForWedge(&
I);
2736 bool MadeChanges =
false;
2750 for (
auto &BB : Fn) {
2751 for (
auto &
I : BB) {
2758 Result.insert({DAI->getVariable(), DAI->getDebugLoc().getInlinedAt()});
2775 bool Changed =
false;
2780 AssignmentTrackingLowering
Pass(Fn, Layout, &VarsWithStackSlot);
2781 Changed =
Pass.run(FnVarLocs);
2785 MemLocFragmentFill
Pass(Fn, &VarsWithStackSlot,
2787 Pass.run(FnVarLocs);
2804 auto &
DL =
F.getDataLayout();
2828 LLVM_DEBUG(
dbgs() <<
"AssignmentTrackingAnalysis run on " <<
F.getName()
2838 Results->init(Builder);
2841 Results->print(
errs(),
F);
2853 "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
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.
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_>.
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.
bool isDbgDeclare() const
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.
@ Tail
Attemps to make calls as fast as possible while guaranteeing that tail call optimization can always b...
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
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)
@ 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.
std::tuple< const DIScope *, const DIScope *, const DILocalVariable * > VarID
A unique key that represents a debug variable.
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)
const char * toString(DWARFSectionKind Kind)
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