41#include <unordered_map>
44#define DEBUG_TYPE "debug-ata"
46STATISTIC(NumDefsScanned,
"Number of dbg locs that get scanned for removal");
47STATISTIC(NumDefsRemoved,
"Number of dbg locs removed");
48STATISTIC(NumWedgesScanned,
"Number of dbg wedges scanned");
49STATISTIC(NumWedgesChanged,
"Number of dbg wedges changed");
53 cl::desc(
"Maximum num basic blocks before debug info dropped"),
74 return static_cast<VariableID>(Wrapped::getEmptyKey());
77 return static_cast<VariableID>(Wrapped::getTombstoneKey());
80 return Wrapped::getHashValue(
static_cast<unsigned>(Val));
99 friend FunctionVarLocs;
103 std::unordered_map<VarLocInsertPt, SmallVector<VarLocInfo>> VarLocsBeforeInst;
112 return static_cast<VariableID>(Variables.insert(V));
117 return Variables[
static_cast<unsigned>(
ID)];
123 auto R = VarLocsBeforeInst.find(Before);
124 if (R == VarLocsBeforeInst.end())
131 VarLocsBeforeInst[Before] = std::move(Wedge);
140 VarLoc.
DL = std::move(
DL);
142 SingleLocVars.emplace_back(VarLoc);
151 VarLoc.
DL = std::move(
DL);
153 VarLocsBeforeInst[Before].emplace_back(VarLoc);
160 unsigned Counter = -1;
161 OS <<
"=== Variables ===\n";
168 OS <<
"[" << Counter <<
"] " << V.getVariable()->getName();
169 if (
auto F = V.getFragment())
170 OS <<
" bits [" <<
F->OffsetInBits <<
", "
171 <<
F->OffsetInBits +
F->SizeInBits <<
")";
172 if (
const auto *IA = V.getInlinedAt())
173 OS <<
" inlined-at " << *IA;
178 OS <<
"DEF Var=[" << (
unsigned)
Loc.VariableID <<
"]"
179 <<
" Expr=" << *
Loc.Expr <<
" Values=(";
180 for (
auto *
Op :
Loc.Values.location_ops()) {
181 errs() <<
Op->getName() <<
" ";
187 OS <<
"=== Single location vars ===\n";
194 OS <<
"=== In-line variable defs ===";
196 OS <<
"\n" << BB.getName() <<
":\n";
208 for (
const auto &VarLoc : Builder.SingleLocVars)
209 VarLocRecords.emplace_back(VarLoc);
211 SingleVarLocEnd = VarLocRecords.size();
217 for (
auto &
P : Builder.VarLocsBeforeInst) {
223 unsigned BlockStart = VarLocRecords.size();
230 auto It = Builder.VarLocsBeforeInst.find(&DVR);
231 if (It == Builder.VarLocsBeforeInst.end())
234 VarLocRecords.emplace_back(VarLoc);
237 VarLocRecords.emplace_back(VarLoc);
238 unsigned BlockEnd = VarLocRecords.size();
240 if (BlockEnd != BlockStart)
241 VarLocsBeforeInst[
I] = {BlockStart, BlockEnd};
245 assert(Variables.empty() &&
"Expect clear before init");
248 Variables.reserve(Builder.Variables.size() + 1);
249 Variables.push_back(
DebugVariable(
nullptr, std::nullopt,
nullptr));
250 Variables.append(Builder.Variables.begin(), Builder.Variables.end());
255 VarLocRecords.clear();
256 VarLocsBeforeInst.clear();
264static std::pair<Value *, DIExpression *>
267 APInt OffsetInBytes(
DL.getTypeSizeInBits(Start->getType()),
false);
269 Start->stripAndAccumulateInBoundsConstantOffsets(
DL, OffsetInBytes);
283static std::optional<int64_t>
288 unsigned ExpectedDerefIdx = 0;
290 if (NumElements > 2 && Elements[0] == dwarf::DW_OP_plus_uconst) {
292 ExpectedDerefIdx = 2;
293 }
else if (NumElements > 3 && Elements[0] == dwarf::DW_OP_constu) {
294 ExpectedDerefIdx = 3;
295 if (Elements[2] == dwarf::DW_OP_plus)
297 else if (Elements[2] == dwarf::DW_OP_minus)
304 if (ExpectedDerefIdx >= NumElements)
309 if (Elements[ExpectedDerefIdx] != dwarf::DW_OP_deref)
313 if (NumElements == ExpectedDerefIdx + 1)
315 unsigned ExpectedFragFirstIdx = ExpectedDerefIdx + 1;
316 unsigned ExpectedFragFinalIdx = ExpectedFragFirstIdx + 2;
317 if (NumElements == ExpectedFragFinalIdx + 1 &&
367class MemLocFragmentFill {
369 FunctionVarLocsBuilder *FnVarLocs;
370 const DenseSet<DebugAggregate> *VarsWithStackSlot;
371 bool CoalesceAdjacentFragments;
374 using BaseAddress = unsigned;
375 using OffsetInBitsTy = unsigned;
376 using FragTraits = IntervalMapHalfOpenInfo<OffsetInBitsTy>;
377 using FragsInMemMap = IntervalMap<
378 OffsetInBitsTy, BaseAddress,
379 IntervalMapImpl::NodeSizer<OffsetInBitsTy, BaseAddress>::LeafSize,
381 FragsInMemMap::Allocator IntervalMapAlloc;
382 using VarFragMap = DenseMap<unsigned, FragsInMemMap>;
386 UniqueVector<RawLocationWrapper> Bases;
388 DenseMap<const BasicBlock *, VarFragMap> LiveIn;
389 DenseMap<const BasicBlock *, VarFragMap> LiveOut;
394 unsigned OffsetInBits;
398 using InsertMap = MapVector<VarLocInsertPt, SmallVector<FragMemLoc>>;
405 DenseMap<const BasicBlock *, InsertMap> BBInsertBeforeMap;
407 static bool intervalMapsAreEqual(
const FragsInMemMap &
A,
408 const FragsInMemMap &
B) {
409 auto AIt =
A.
begin(), AEnd =
A.end();
410 auto BIt =
B.begin(), BEnd =
B.end();
411 for (; AIt != AEnd; ++AIt, ++BIt) {
414 if (AIt.start() != BIt.start() || AIt.stop() != BIt.stop())
423 static bool varFragMapsAreEqual(
const VarFragMap &
A,
const VarFragMap &
B) {
424 if (
A.size() !=
B.size())
426 for (
const auto &APair :
A) {
427 auto BIt =
B.find(APair.first);
430 if (!intervalMapsAreEqual(APair.second, BIt->second))
437 std::string
toString(
unsigned BaseID) {
439 return Bases[BaseID].getVariableLocationOp(0)->getName().str();
445 std::string
toString(FragsInMemMap::const_iterator It,
bool Newline =
true) {
447 std::stringstream S(
String);
449 S <<
"[" << It.start() <<
", " << It.stop()
452 S <<
"invalid iterator (end)";
459 FragsInMemMap meetFragments(
const FragsInMemMap &
A,
const FragsInMemMap &
B) {
460 FragsInMemMap
Result(IntervalMapAlloc);
461 for (
auto AIt =
A.begin(), AEnd =
A.end(); AIt != AEnd; ++AIt) {
468 if (!
B.overlaps(AIt.start(), AIt.stop()))
472 auto FirstOverlap =
B.find(AIt.start());
473 assert(FirstOverlap !=
B.end());
474 bool IntersectStart = FirstOverlap.start() < AIt.start();
476 <<
", IntersectStart: " << IntersectStart <<
"\n");
479 auto LastOverlap =
B.find(AIt.stop());
481 LastOverlap !=
B.end() && LastOverlap.start() < AIt.stop();
483 <<
", IntersectEnd: " << IntersectEnd <<
"\n");
486 if (IntersectStart && IntersectEnd && FirstOverlap == LastOverlap) {
494 if (*AIt && *AIt == *FirstOverlap)
495 Result.insert(AIt.start(), AIt.stop(), *AIt);
503 auto Next = FirstOverlap;
504 if (IntersectStart) {
507 if (*AIt && *AIt == *FirstOverlap)
508 Result.insert(AIt.start(), FirstOverlap.stop(), *AIt);
518 if (*AIt && *AIt == *LastOverlap)
519 Result.insert(LastOverlap.start(), AIt.stop(), *AIt);
528 while (
Next !=
B.end() &&
Next.start() < AIt.stop() &&
529 Next.stop() <= AIt.stop()) {
531 <<
"- insert intersection of a and " <<
toString(
Next));
532 if (*AIt && *AIt == *
Next)
542 void meetVars(VarFragMap &
A,
const VarFragMap &
B) {
546 A.remove_if([&](
auto &Entry) {
547 auto BIt =
B.find(
Entry.first);
552 Entry.second = meetFragments(
Entry.second, BIt->second);
557 bool meet(
const BasicBlock &BB,
558 const SmallPtrSet<BasicBlock *, 16> &Visited) {
563 bool FirstMeet =
true;
570 if (!Visited.
count(Pred))
573 auto PredLiveOut = LiveOut.
find(Pred);
578 BBLiveIn = PredLiveOut->second;
581 LLVM_DEBUG(
dbgs() <<
"BBLiveIn = meet BBLiveIn, " << Pred->getName()
583 meetVars(BBLiveIn, PredLiveOut->second);
589 if (BBLiveIn.size() == 0)
598 CurrentLiveInEntry->second = std::move(BBLiveIn);
604 if (!varFragMapsAreEqual(BBLiveIn, CurrentLiveInEntry->second)) {
606 CurrentLiveInEntry->second = std::move(BBLiveIn);
614 void insertMemLoc(BasicBlock &BB,
VarLocInsertPt Before,
unsigned Var,
615 unsigned StartBit,
unsigned EndBit,
unsigned Base,
617 assert(StartBit < EndBit &&
"Cannot create fragment of size <= 0");
622 Loc.OffsetInBits = StartBit;
623 Loc.SizeInBits = EndBit - StartBit;
624 assert(
Base &&
"Expected a non-zero ID for Base address");
627 BBInsertBeforeMap[&BB][Before].push_back(Loc);
629 <<
" bits [" << StartBit <<
", " << EndBit <<
")\n");
636 void coalesceFragments(BasicBlock &BB,
VarLocInsertPt Before,
unsigned Var,
637 unsigned StartBit,
unsigned EndBit,
unsigned Base,
639 if (!CoalesceAdjacentFragments)
646 auto CoalescedFrag = FragMap.find(StartBit);
648 if (CoalescedFrag.start() == StartBit && CoalescedFrag.stop() == EndBit)
651 LLVM_DEBUG(
dbgs() <<
"- Insert loc for bits " << CoalescedFrag.start()
652 <<
" to " << CoalescedFrag.stop() <<
"\n");
653 insertMemLoc(BB, Before, Var, CoalescedFrag.start(), CoalescedFrag.stop(),
657 void addDef(
const VarLocInfo &VarLoc,
VarLocInsertPt Before, BasicBlock &BB,
658 VarFragMap &LiveSet) {
671 const DIExpression *DIExpr = VarLoc.
Expr;
675 StartBit = Frag->OffsetInBits;
676 EndBit = StartBit + Frag->SizeInBits;
691 const unsigned Base =
692 DerefOffsetInBytes && *DerefOffsetInBytes * 8 == StartBit
696 << StartBit <<
", " << EndBit <<
"): " <<
toString(
Base)
703 auto FragIt = LiveSet.find(Var);
706 if (FragIt == LiveSet.end()) {
708 auto P = LiveSet.try_emplace(Var, FragsInMemMap(IntervalMapAlloc));
709 assert(
P.second &&
"Var already in map?");
711 P.first->second.insert(StartBit, EndBit,
Base);
716 FragsInMemMap &FragMap = FragIt->second;
719 if (!FragMap.overlaps(StartBit, EndBit)) {
721 FragMap.insert(StartBit, EndBit,
Base);
722 coalesceFragments(BB, Before, Var, StartBit, EndBit,
Base, VarLoc.
DL,
729 auto FirstOverlap = FragMap.find(StartBit);
730 assert(FirstOverlap != FragMap.end());
731 bool IntersectStart = FirstOverlap.start() < StartBit;
734 auto LastOverlap = FragMap.find(EndBit);
735 bool IntersectEnd = LastOverlap.valid() && LastOverlap.start() < EndBit;
738 if (IntersectStart && IntersectEnd && FirstOverlap == LastOverlap) {
739 LLVM_DEBUG(
dbgs() <<
"- Intersect single interval @ both ends\n");
747 auto EndBitOfOverlap = FirstOverlap.stop();
748 unsigned OverlapValue = FirstOverlap.value();
751 FirstOverlap.setStop(StartBit);
752 insertMemLoc(BB, Before, Var, FirstOverlap.start(), StartBit,
753 OverlapValue, VarLoc.
DL);
756 FragMap.insert(EndBit, EndBitOfOverlap, OverlapValue);
757 insertMemLoc(BB, Before, Var, EndBit, EndBitOfOverlap, OverlapValue,
761 FragMap.insert(StartBit, EndBit,
Base);
771 if (IntersectStart) {
774 FirstOverlap.setStop(StartBit);
775 insertMemLoc(BB, Before, Var, FirstOverlap.start(), StartBit,
776 *FirstOverlap, VarLoc.
DL);
785 LastOverlap.setStart(EndBit);
786 insertMemLoc(BB, Before, Var, EndBit, LastOverlap.stop(), *LastOverlap,
802 auto It = FirstOverlap;
805 while (It.valid() && It.start() >= StartBit && It.stop() <= EndBit) {
810 assert(!FragMap.overlaps(StartBit, EndBit));
812 FragMap.insert(StartBit, EndBit,
Base);
815 coalesceFragments(BB, Before, Var, StartBit, EndBit,
Base, VarLoc.
DL,
819 bool skipVariable(
const DILocalVariable *V) {
return !
V->getSizeInBits(); }
821 void process(BasicBlock &BB, VarFragMap &LiveSet) {
822 BBInsertBeforeMap[&BB].
clear();
824 for (DbgVariableRecord &DVR :
filterDbgVars(
I.getDbgRecordRange())) {
825 if (
const auto *Locs = FnVarLocs->
getWedge(&DVR)) {
826 for (
const VarLocInfo &Loc : *Locs) {
827 addDef(Loc, &DVR, *
I.getParent(), LiveSet);
831 if (
const auto *Locs = FnVarLocs->
getWedge(&
I)) {
832 for (
const VarLocInfo &Loc : *Locs) {
833 addDef(Loc, &
I, *
I.getParent(), LiveSet);
840 MemLocFragmentFill(Function &Fn,
841 const DenseSet<DebugAggregate> *VarsWithStackSlot,
842 bool CoalesceAdjacentFragments)
843 : Fn(Fn), VarsWithStackSlot(VarsWithStackSlot),
844 CoalesceAdjacentFragments(CoalesceAdjacentFragments) {}
866 void run(FunctionVarLocsBuilder *FnVarLocs) {
870 this->FnVarLocs = FnVarLocs;
874 ReversePostOrderTraversal<Function *> RPOT(&Fn);
875 std::priority_queue<unsigned int, std::vector<unsigned int>,
876 std::greater<unsigned int>>
878 std::priority_queue<unsigned int, std::vector<unsigned int>,
879 std::greater<unsigned int>>
881 DenseMap<unsigned int, BasicBlock *> OrderToBB;
882 DenseMap<BasicBlock *, unsigned int> BBToOrder;
884 unsigned int RPONumber = 0;
885 for (BasicBlock *BB : RPOT) {
886 OrderToBB[RPONumber] = BB;
887 BBToOrder[BB] = RPONumber;
888 Worklist.push(RPONumber);
904 SmallPtrSet<BasicBlock *, 16> Visited;
905 while (!Worklist.empty() || !Pending.empty()) {
909 SmallPtrSet<BasicBlock *, 16> OnPending;
911 while (!Worklist.empty()) {
915 bool InChanged = meet(*BB, Visited);
917 InChanged |= Visited.
insert(BB).second;
920 << BB->
getName() <<
" has new InLocs, process it\n");
924 VarFragMap LiveSet = LiveIn[BB];
927 process(*BB, LiveSet);
930 if (!varFragMapsAreEqual(LiveOut[BB], LiveSet)) {
932 <<
" has new OutLocs, add succs to worklist: [ ");
933 LiveOut[BB] = std::move(LiveSet);
935 if (OnPending.
insert(Succ).second) {
937 Pending.push(BBToOrder[Succ]);
944 Worklist.swap(Pending);
947 assert(Pending.empty() &&
"Pending should be empty");
951 for (
auto &Pair : BBInsertBeforeMap) {
952 InsertMap &
Map = Pair.second;
953 for (
auto &Pair : Map) {
954 auto InsertBefore = Pair.first;
955 assert(InsertBefore &&
"should never be null");
956 auto FragMemLocs = Pair.second;
959 for (
auto &FragMemLoc : FragMemLocs) {
960 DIExpression *Expr = DIExpression::get(Ctx, {});
961 if (FragMemLoc.SizeInBits !=
962 *
Aggregates[FragMemLoc.Var].first->getSizeInBits())
964 Expr, FragMemLoc.OffsetInBits, FragMemLoc.SizeInBits);
966 FragMemLoc.OffsetInBits / 8);
967 DebugVariable Var(
Aggregates[FragMemLoc.Var].first, Expr,
968 FragMemLoc.DL.getInlinedAt());
969 FnVarLocs->
addVarLoc(InsertBefore, Var, Expr, FragMemLoc.DL,
970 Bases[FragMemLoc.Base]);
980class AssignmentTrackingLowering {
1005 enum class LocKind { Mem, Val,
None };
1022 enum S { Known, NoneOrPhi } Status;
1027 DbgVariableRecord *
Source =
nullptr;
1029 bool isSameSourceAssignment(
const Assignment &
Other)
const {
1032 return std::tie(Status,
ID) == std::tie(
Other.Status,
Other.ID);
1034 void dump(raw_ostream &OS) {
1035 static const char *
LUT[] = {
"Known",
"NoneOrPhi"};
1036 OS <<
LUT[Status] <<
"(id=";
1049 static Assignment make(DIAssignID *
ID, DbgVariableRecord *Source) {
1051 "Cannot make an assignment from a non-assign DbgVariableRecord");
1052 return Assignment(Known,
ID, Source);
1054 static Assignment makeFromMemDef(DIAssignID *
ID) {
1055 return Assignment(Known,
ID);
1057 static Assignment makeNoneOrPhi() {
return Assignment(NoneOrPhi,
nullptr); }
1059 Assignment() : Status(NoneOrPhi),
ID(nullptr) {}
1060 Assignment(S Status, DIAssignID *
ID) : Status(Status),
ID(
ID) {
1064 Assignment(S Status, DIAssignID *
ID, DbgVariableRecord *Source)
1071 using AssignmentMap = SmallVector<Assignment>;
1072 using LocMap = SmallVector<LocKind>;
1073 using OverlapMap = DenseMap<VariableID, SmallVector<VariableID>>;
1074 using UntaggedStoreAssignmentMap =
1077 using UnknownStoreAssignmentMap =
1078 DenseMap<const Instruction *, SmallVector<VariableID>>;
1079 using EscapingCallVarsMap =
1086 unsigned TrackedVariablesVectorSize = 0;
1091 UntaggedStoreAssignmentMap UntaggedStoreVars;
1094 UnknownStoreAssignmentMap UnknownStoreVars;
1098 EscapingCallVarsMap EscapingCallVars;
1101 using InstInsertMap = MapVector<VarLocInsertPt, SmallVector<VarLocInfo>>;
1102 InstInsertMap InsertBeforeMap;
1105 void resetInsertionPoint(Instruction &After);
1106 void resetInsertionPoint(DbgVariableRecord &After);
1108 void emitDbgValue(LocKind Kind, DbgVariableRecord *,
VarLocInsertPt After);
1110 static bool mapsAreEqual(
const BitVector &Mask,
const AssignmentMap &
A,
1111 const AssignmentMap &
B) {
1113 return A[VarID].isSameSourceAssignment(B[VarID]);
1122 BitVector VariableIDsInBlock;
1125 AssignmentMap StackHomeValue;
1127 AssignmentMap DebugValue;
1142 const AssignmentMap &getAssignmentMap(AssignmentKind Kind)
const {
1145 return StackHomeValue;
1151 AssignmentMap &getAssignmentMap(AssignmentKind Kind) {
1152 return const_cast<AssignmentMap &
>(
1153 const_cast<const BlockInfo *
>(
this)->getAssignmentMap(Kind));
1156 bool isVariableTracked(
VariableID Var)
const {
1157 return VariableIDsInBlock[
static_cast<unsigned>(Var)];
1160 const Assignment &getAssignment(AssignmentKind Kind,
VariableID Var)
const {
1161 assert(isVariableTracked(Var) &&
"Var not tracked in block");
1162 return getAssignmentMap(Kind)[
static_cast<unsigned>(Var)];
1166 assert(isVariableTracked(Var) &&
"Var not tracked in block");
1167 return LiveLoc[
static_cast<unsigned>(Var)];
1173 VariableIDsInBlock.
set(
static_cast<unsigned>(Var));
1174 LiveLoc[
static_cast<unsigned>(Var)] = K;
1180 void setAssignment(AssignmentKind Kind,
VariableID Var,
1181 const Assignment &AV) {
1182 VariableIDsInBlock.
set(
static_cast<unsigned>(Var));
1183 getAssignmentMap(Kind)[
static_cast<unsigned>(Var)] = AV;
1189 bool hasAssignment(AssignmentKind Kind,
VariableID Var,
1190 const Assignment &AV)
const {
1191 if (!isVariableTracked(Var))
1193 return AV.isSameSourceAssignment(getAssignment(Kind, Var));
1199 return VariableIDsInBlock ==
Other.VariableIDsInBlock &&
1200 LiveLoc ==
Other.LiveLoc &&
1201 mapsAreEqual(VariableIDsInBlock, StackHomeValue,
1202 Other.StackHomeValue) &&
1203 mapsAreEqual(VariableIDsInBlock, DebugValue,
Other.DebugValue);
1207 return LiveLoc.size() == DebugValue.size() &&
1208 LiveLoc.size() == StackHomeValue.size();
1212 void init(
int NumVars) {
1213 StackHomeValue.clear();
1216 VariableIDsInBlock = BitVector(NumVars);
1217 StackHomeValue.insert(StackHomeValue.begin(), NumVars,
1218 Assignment::makeNoneOrPhi());
1219 DebugValue.insert(DebugValue.begin(), NumVars,
1220 Assignment::makeNoneOrPhi());
1221 LiveLoc.
insert(LiveLoc.
begin(), NumVars, LocKind::None);
1225 template <
typename ElmtType,
typename FnInputType>
1229 ElmtType (*Fn)(FnInputType, FnInputType)) {
1234 static BlockInfo
join(
const BlockInfo &
A,
const BlockInfo &
B,
int NumVars) {
1253 BitVector Intersect =
A.VariableIDsInBlock;
1254 Intersect &=
B.VariableIDsInBlock;
1257 joinElmt(
VarID, Join.LiveLoc,
A.LiveLoc,
B.LiveLoc, joinKind);
1258 joinElmt(
VarID, Join.DebugValue,
A.DebugValue,
B.DebugValue,
1260 joinElmt(
VarID, Join.StackHomeValue,
A.StackHomeValue,
B.StackHomeValue,
1264 Join.VariableIDsInBlock =
A.VariableIDsInBlock;
1265 Join.VariableIDsInBlock |=
B.VariableIDsInBlock;
1272 const DataLayout &Layout;
1273 const DenseSet<DebugAggregate> *VarsWithStackSlot;
1274 FunctionVarLocsBuilder *FnVarLocs;
1275 DenseMap<const BasicBlock *, BlockInfo> LiveIn;
1276 DenseMap<const BasicBlock *, BlockInfo> LiveOut;
1279 DenseSet<VariableID> VarsTouchedThisFrame;
1282 DenseSet<DebugAggregate> NotAlwaysStackHomed;
1284 VariableID getVariableID(
const DebugVariable &Var) {
1292 bool join(
const BasicBlock &BB,
const SmallPtrSet<BasicBlock *, 16> &Visited);
1312 static LocKind joinKind(LocKind
A, LocKind
B);
1313 static Assignment joinAssignment(
const Assignment &
A,
const Assignment &
B);
1314 BlockInfo joinBlockInfo(
const BlockInfo &
A,
const BlockInfo &
B);
1320 void process(BasicBlock &BB, BlockInfo *LiveSet);
1325 void processNonDbgInstruction(Instruction &
I, BlockInfo *LiveSet);
1328 void processTaggedInstruction(Instruction &
I, BlockInfo *LiveSet);
1331 void processUntaggedInstruction(Instruction &
I, BlockInfo *LiveSet);
1332 void processUnknownStoreToVariable(Instruction &
I,
VariableID &Var,
1333 BlockInfo *LiveSet);
1334 void processEscapingCall(Instruction &
I, BlockInfo *LiveSet);
1335 void processDbgAssign(DbgVariableRecord *Assign, BlockInfo *LiveSet);
1336 void processDbgVariableRecord(DbgVariableRecord &DVR, BlockInfo *LiveSet);
1337 void processDbgValue(DbgVariableRecord *DbgValue, BlockInfo *LiveSet);
1339 void addMemDef(BlockInfo *LiveSet,
VariableID Var,
const Assignment &AV);
1341 void addDbgDef(BlockInfo *LiveSet,
VariableID Var,
const Assignment &AV);
1345 void setLocKind(BlockInfo *LiveSet,
VariableID Var, LocKind K);
1348 LocKind getLocKind(BlockInfo *LiveSet,
VariableID Var);
1350 bool hasVarWithAssignment(BlockInfo *LiveSet, BlockInfo::AssignmentKind Kind,
1361 bool emitPromotedVarLocs(FunctionVarLocsBuilder *FnVarLocs);
1364 AssignmentTrackingLowering(Function &Fn,
const DataLayout &Layout,
1365 const DenseSet<DebugAggregate> *VarsWithStackSlot)
1366 : Fn(Fn), Layout(Layout), VarsWithStackSlot(VarsWithStackSlot) {}
1369 bool run(FunctionVarLocsBuilder *FnVarLocs);
1374AssignmentTrackingLowering::getContainedFragments(
VariableID Var)
const {
1375 auto R = VarContains.find(Var);
1376 if (R == VarContains.end())
1381void AssignmentTrackingLowering::touchFragment(
VariableID Var) {
1382 VarsTouchedThisFrame.insert(Var);
1385void AssignmentTrackingLowering::setLocKind(BlockInfo *LiveSet,
VariableID Var,
1387 auto SetKind = [
this](BlockInfo *LiveSet,
VariableID Var, LocKind
K) {
1388 LiveSet->setLocKind(Var, K);
1391 SetKind(LiveSet, Var, K);
1394 for (
VariableID Frag : getContainedFragments(Var))
1395 SetKind(LiveSet, Frag, K);
1398AssignmentTrackingLowering::LocKind
1399AssignmentTrackingLowering::getLocKind(BlockInfo *LiveSet,
VariableID Var) {
1400 return LiveSet->getLocKind(Var);
1403void AssignmentTrackingLowering::addMemDef(BlockInfo *LiveSet,
VariableID Var,
1404 const Assignment &AV) {
1405 LiveSet->setAssignment(BlockInfo::Stack, Var, AV);
1410 Assignment FragAV = AV;
1411 FragAV.Source =
nullptr;
1412 for (
VariableID Frag : getContainedFragments(Var))
1413 LiveSet->setAssignment(BlockInfo::Stack, Frag, FragAV);
1416void AssignmentTrackingLowering::addDbgDef(BlockInfo *LiveSet,
VariableID Var,
1417 const Assignment &AV) {
1418 LiveSet->setAssignment(BlockInfo::Debug, Var, AV);
1423 Assignment FragAV = AV;
1424 FragAV.Source =
nullptr;
1425 for (
VariableID Frag : getContainedFragments(Var))
1426 LiveSet->setAssignment(BlockInfo::Debug, Frag, FragAV);
1435 "Cannot get a DIAssignID from a non-assign DbgVariableRecord!");
1440bool AssignmentTrackingLowering::hasVarWithAssignment(
1441 BlockInfo *LiveSet, BlockInfo::AssignmentKind Kind,
VariableID Var,
1442 const Assignment &AV) {
1443 if (!LiveSet->hasAssignment(Kind, Var, AV))
1448 for (
VariableID Frag : getContainedFragments(Var))
1449 if (!LiveSet->hasAssignment(Kind, Frag, AV))
1455const char *
locStr(AssignmentTrackingLowering::LocKind
Loc) {
1456 using LocKind = AssignmentTrackingLowering::LocKind;
1477 if (!
Next->hasDbgRecords())
1479 return &*
Next->getDbgRecordRange().begin();
1487void AssignmentTrackingLowering::emitDbgValue(
1500 assert(InsertBefore &&
"Shouldn't be inserting after a terminator");
1509 InsertBeforeMap[InsertBefore].
push_back(VarLoc);
1513 if (Kind == LocKind::Mem) {
1518 if (
Assign->isKillAddress()) {
1520 Kind = LocKind::Val;
1525 "fragment info should be stored in value-expression only");
1528 if (
auto OptFragInfo =
Source->getExpression()->getFragmentInfo()) {
1529 auto FragInfo = *OptFragInfo;
1531 Expr, FragInfo.OffsetInBits, FragInfo.SizeInBits);
1534 std::tie(Val, Expr) =
1541 if (Kind == LocKind::Val) {
1542 Emit(
Source->getRawLocation(),
Source->getExpression());
1546 if (Kind == LocKind::None) {
1547 Emit(
nullptr,
Source->getExpression());
1552void AssignmentTrackingLowering::processNonDbgInstruction(
1553 Instruction &
I, AssignmentTrackingLowering::BlockInfo *LiveSet) {
1554 if (
I.hasMetadata(LLVMContext::MD_DIAssignID))
1555 processTaggedInstruction(
I, LiveSet);
1557 processUntaggedInstruction(
I, LiveSet);
1562 processEscapingCall(
I, LiveSet);
1565void AssignmentTrackingLowering::processUnknownStoreToVariable(
1569 addMemDef(LiveSet, Var, Assignment::makeNoneOrPhi());
1572 if (getLocKind(LiveSet, Var) != LocKind::Mem)
1576 Assignment DbgAV = LiveSet->getAssignment(BlockInfo::Debug, Var);
1577 if (DbgAV.Status != Assignment::NoneOrPhi && DbgAV.Source) {
1579 DbgAV.dump(
dbgs());
dbgs() <<
"\n");
1580 setLocKind(LiveSet, Var, LocKind::Val);
1581 emitDbgValue(LocKind::Val, DbgAV.Source, &
I);
1587 assert(InsertBefore &&
"Shouldn't be inserting after a terminator");
1593 Fn.
getContext(), 0, 0,
V.getVariable()->getScope(), InlinedAt);
1601 InsertBeforeMap[InsertBefore].push_back(VarLoc);
1604void AssignmentTrackingLowering::processUntaggedInstruction(
1605 Instruction &
I, AssignmentTrackingLowering::BlockInfo *LiveSet) {
1617 assert(!
I.hasMetadata(LLVMContext::MD_DIAssignID));
1618 auto It = UntaggedStoreVars.find(&
I);
1619 if (It == UntaggedStoreVars.end()) {
1626 if (
auto UnhandledStoreIt = UnknownStoreVars.find(&
I);
1627 UnhandledStoreIt != UnknownStoreVars.end()) {
1628 LLVM_DEBUG(
dbgs() <<
"Processing untagged unknown store " <<
I <<
"\n");
1629 for (
auto &Var : UnhandledStoreIt->second)
1630 processUnknownStoreToVariable(
I, Var, LiveSet);
1635 LLVM_DEBUG(
dbgs() <<
"processUntaggedInstruction on UNTAGGED INST " <<
I
1639 for (
auto [Var, Info] : It->second) {
1643 addMemDef(LiveSet, Var, Assignment::makeNoneOrPhi());
1644 addDbgDef(LiveSet, Var, Assignment::makeNoneOrPhi());
1645 setLocKind(LiveSet, Var, LocKind::Mem);
1653 if (
auto Frag =
V.getFragment()) {
1656 assert(R &&
"unexpected createFragmentExpression failure");
1660 if (
Info.OffsetInBits)
1661 Ops = {dwarf::DW_OP_plus_uconst,
Info.OffsetInBits / 8};
1668 assert(InsertBefore &&
"Shouldn't be inserting after a terminator");
1673 Fn.
getContext(), 0, 0,
V.getVariable()->getScope(), InlinedAt);
1682 InsertBeforeMap[InsertBefore].push_back(VarLoc);
1686void AssignmentTrackingLowering::processEscapingCall(
1687 Instruction &
I, AssignmentTrackingLowering::BlockInfo *LiveSet) {
1688 auto It = EscapingCallVars.find(&
I);
1689 if (It == EscapingCallVars.end())
1696 for (
auto &[Var, Addr, AddrExpr] : It->second) {
1702 addMemDef(LiveSet, Var, Assignment::makeNoneOrPhi());
1703 addDbgDef(LiveSet, Var, Assignment::makeNoneOrPhi());
1704 setLocKind(LiveSet, Var, LocKind::Mem);
1708 <<
", setting LocKind to Mem\n");
1715 if (
auto Frag =
V.getFragment()) {
1718 assert(R &&
"unexpected createFragmentExpression failure");
1726 assert(InsertBefore &&
"Shouldn't be inserting after a terminator");
1730 Fn.
getContext(), 0, 0,
V.getVariable()->getScope(), InlinedAt);
1738 InsertBeforeMap[InsertBefore].push_back(VarLoc);
1742void AssignmentTrackingLowering::processTaggedInstruction(
1743 Instruction &
I, AssignmentTrackingLowering::BlockInfo *LiveSet) {
1749 if (LinkedDPAssigns.empty())
1758 "expected Assign's variable to have stack slot");
1761 addMemDef(LiveSet, Var, AV);
1769 if (hasVarWithAssignment(LiveSet, BlockInfo::Debug, Var, AV)) {
1775 LiveSet->DebugValue[
static_cast<unsigned>(Var)].dump(
dbgs());
1777 setLocKind(LiveSet, Var, LocKind::Mem);
1778 emitDbgValue(LocKind::Mem, Assign, &
I);
1787 LocKind PrevLoc = getLocKind(LiveSet, Var);
1789 case LocKind::Val: {
1793 setLocKind(LiveSet, Var, LocKind::Val);
1795 case LocKind::Mem: {
1799 Assignment DbgAV = LiveSet->getAssignment(BlockInfo::Debug, Var);
1800 if (DbgAV.Status == Assignment::NoneOrPhi) {
1803 setLocKind(LiveSet, Var, LocKind::None);
1804 emitDbgValue(LocKind::None, Assign, &
I);
1808 setLocKind(LiveSet, Var, LocKind::Val);
1810 emitDbgValue(LocKind::Val, DbgAV.Source, &
I);
1813 emitDbgValue(LocKind::None, Assign, &
I);
1817 case LocKind::None: {
1821 setLocKind(LiveSet, Var, LocKind::None);
1828 BlockInfo *LiveSet) {
1835 Assignment AV = Assignment::make(
getIDFromMarker(*DbgAssign), DbgAssign);
1836 addDbgDef(LiveSet, Var, AV);
1838 LLVM_DEBUG(
dbgs() <<
"processDbgAssign on " << *DbgAssign <<
"\n";);
1844 if (hasVarWithAssignment(LiveSet, BlockInfo::Stack, Var, AV)) {
1852 <<
"Val, Stack matches Debug program but address is killed\n";);
1853 Kind = LocKind::Val;
1856 Kind = LocKind::Mem;
1858 setLocKind(LiveSet, Var, Kind);
1859 emitDbgValue(Kind, DbgAssign, DbgAssign);
1864 setLocKind(LiveSet, Var, LocKind::Val);
1865 emitDbgValue(LocKind::Val, DbgAssign, DbgAssign);
1870 BlockInfo *LiveSet) {
1883 Assignment AV = Assignment::makeNoneOrPhi();
1884 addDbgDef(LiveSet, Var, AV);
1888 <<
" -> Val, dbg.value override");
1890 setLocKind(LiveSet, Var, LocKind::Val);
1895 if (
auto F =
DbgValue.getExpression()->getFragmentInfo())
1896 return F->SizeInBits == 0;
1900void AssignmentTrackingLowering::processDbgVariableRecord(
1907 processDbgAssign(&DVR, LiveSet);
1909 processDbgValue(&DVR, LiveSet);
1912void AssignmentTrackingLowering::resetInsertionPoint(
Instruction &After) {
1915 if (R == InsertBeforeMap.end())
1921 if (R == InsertBeforeMap.end())
1926void AssignmentTrackingLowering::process(
BasicBlock &BB, BlockInfo *LiveSet) {
1929 bool ProcessedLeadingDbgRecords = !BB.
begin()->hasDbgRecords();
1931 assert(VarsTouchedThisFrame.empty());
1938 if (ProcessedLeadingDbgRecords) {
1943 if (
II->isTerminator())
1945 resetInsertionPoint(*
II);
1946 processNonDbgInstruction(*
II, LiveSet);
1947 assert(LiveSet->isValid());
1953 if (
II != EI &&
II->hasDbgRecords()) {
1958 resetInsertionPoint(DVR);
1959 processDbgVariableRecord(DVR, LiveSet);
1960 assert(LiveSet->isValid());
1963 ProcessedLeadingDbgRecords =
true;
1971 for (
auto Var : VarsTouchedThisFrame) {
1972 LocKind
Loc = getLocKind(LiveSet, Var);
1980 if (
Loc != LocKind::Mem) {
1983 NotAlwaysStackHomed.insert(Aggr);
1986 VarsTouchedThisFrame.clear();
1990AssignmentTrackingLowering::LocKind
1991AssignmentTrackingLowering::joinKind(LocKind
A, LocKind
B) {
1994 return A ==
B ?
A : LocKind::None;
1997AssignmentTrackingLowering::Assignment
1998AssignmentTrackingLowering::joinAssignment(
const Assignment &
A,
1999 const Assignment &
B) {
2006 if (!
A.isSameSourceAssignment(
B))
2007 return Assignment::makeNoneOrPhi();
2008 if (
A.Status == Assignment::NoneOrPhi)
2009 return Assignment::makeNoneOrPhi();
2025 if (
A.Source ==
B.Source)
2027 if (!
A.Source || !
B.Source)
2029 if (
A.Source->isEquivalentTo(*
B.Source))
2034 assert(
A.Status ==
B.Status &&
A.Status == Assignment::Known);
2036 return Assignment::make(
A.ID, Source);
2039AssignmentTrackingLowering::BlockInfo
2040AssignmentTrackingLowering::joinBlockInfo(
const BlockInfo &
A,
2041 const BlockInfo &
B) {
2042 return BlockInfo::join(
A,
B, TrackedVariablesVectorSize);
2045bool AssignmentTrackingLowering::join(
2057 if (Visited.
count(Pred))
2062 if (VisitedPreds.
empty()) {
2064 bool DidInsert = It.second;
2066 It.first->second.init(TrackedVariablesVectorSize);
2071 if (VisitedPreds.
size() == 1) {
2072 const BlockInfo &PredLiveOut = LiveOut.
find(VisitedPreds[0])->second;
2079 if (PredLiveOut != CurrentLiveInEntry->second) {
2080 CurrentLiveInEntry->second = PredLiveOut;
2088 const BlockInfo &PredLiveOut0 = LiveOut.
find(VisitedPreds[0])->second;
2089 const BlockInfo &PredLiveOut1 = LiveOut.
find(VisitedPreds[1])->second;
2090 BlockInfo BBLiveIn = joinBlockInfo(PredLiveOut0, PredLiveOut1);
2095 const auto &PredLiveOut = LiveOut.
find(Pred);
2097 "block should have been processed already");
2098 BBLiveIn = joinBlockInfo(std::move(BBLiveIn), PredLiveOut->second);
2102 auto CurrentLiveInEntry = LiveIn.
find(&BB);
2105 if (CurrentLiveInEntry == LiveIn.
end())
2107 else if (BBLiveIn != CurrentLiveInEntry->second)
2108 CurrentLiveInEntry->second = std::move(BBLiveIn);
2117 auto ALeft =
A.OffsetInBits;
2118 auto BLeft =
B.OffsetInBits;
2122 auto ARight = ALeft +
A.SizeInBits;
2123 auto BRight = BLeft +
B.SizeInBits;
2124 if (BRight > ARight)
2129static std::optional<at::AssignmentInfo>
2139 return std::nullopt;
2147 if (
ID != Intrinsic::experimental_vp_strided_store &&
2148 ID != Intrinsic::masked_store &&
ID != Intrinsic::vp_scatter &&
2149 ID != Intrinsic::masked_scatter &&
ID != Intrinsic::vp_store &&
2150 ID != Intrinsic::masked_compressstore)
2186 AssignmentTrackingLowering::UntaggedStoreAssignmentMap &UntaggedStoreVars,
2187 AssignmentTrackingLowering::UnknownStoreAssignmentMap &UnknownStoreVars,
2188 AssignmentTrackingLowering::EscapingCallVarsMap &EscapingCallVars,
2189 unsigned &TrackedVariablesVectorSize) {
2203 if (
Record->isDbgDeclare()) {
2209 if (!VarsWithStackSlot.
contains(DA))
2211 if (Seen.
insert(DV).second)
2212 FragmentMap[DA].push_back(DV);
2214 for (
auto &BB : Fn) {
2215 for (
auto &
I : BB) {
2217 ProcessDbgRecord(&DVR);
2221 std::optional<DIExpression::FragmentInfo> FragInfo;
2226 I.getDataLayout(), Info->Base,
2227 Info->OffsetInBits, Info->SizeInBits, Assign, FragInfo) ||
2228 (FragInfo && FragInfo->SizeInBits == 0))
2237 FragInfo = Assign->getExpression()->getFragmentInfo();
2241 Assign->getDebugLoc().getInlinedAt());
2243 if (!VarsWithStackSlot.
contains(DA))
2247 UntaggedStoreVars[&
I].push_back(
2250 if (Seen.
insert(DV).second)
2251 FragmentMap[DA].push_back(DV);
2254 HandleDbgAssignForStore(DVR);
2262 Assign->getDebugLoc().getInlinedAt());
2264 if (!VarsWithStackSlot.
contains(DA))
2271 HandleDbgAssignForUnknownStore(DVR);
2284 if (CB->onlyReadsMemory())
2288 for (
unsigned ArgIdx = 0; ArgIdx < CB->arg_size(); ++ArgIdx) {
2289 Value *Arg = CB->getArgOperand(ArgIdx);
2293 if (CB->paramHasAttr(ArgIdx, Attribute::ReadOnly) ||
2294 CB->paramHasAttr(ArgIdx, Attribute::ReadNone))
2297 if (CB->paramHasAttr(ArgIdx, Attribute::ByVal))
2312 if (!VarsWithStackSlot.
contains(DA))
2316 EscapingCallVars[&
I].push_back(
2325 for (
auto &Pair : FragmentMap) {
2327 std::sort(Frags.
begin(), Frags.
end(),
2329 return Elmt.getFragmentOrDefault().SizeInBits >
2330 Next.getFragmentOrDefault().SizeInBits;
2337 AssignmentTrackingLowering::OverlapMap Map;
2338 for (
auto &Pair : FragmentMap) {
2339 auto &Frags = Pair.second;
2340 for (
auto It = Frags.begin(), IEnd = Frags.end(); It != IEnd; ++It) {
2350 for (; OtherIt != IEnd; ++OtherIt) {
2354 Map[OtherVar].push_back(ThisVar);
2365 for (
auto *DVR : DPDeclares)
2372bool AssignmentTrackingLowering::run(FunctionVarLocsBuilder *FnVarLocsBuilder) {
2375 <<
": too many blocks (" << Fn.
size() <<
")\n");
2380 FnVarLocs = FnVarLocsBuilder;
2390 Fn, FnVarLocs, *VarsWithStackSlot, UntaggedStoreVars, UnknownStoreVars,
2391 EscapingCallVars, TrackedVariablesVectorSize);
2395 std::priority_queue<unsigned int, std::vector<unsigned int>,
2396 std::greater<unsigned int>>
2398 std::priority_queue<unsigned int, std::vector<unsigned int>,
2399 std::greater<unsigned int>>
2404 unsigned int RPONumber = 0;
2406 OrderToBB[RPONumber] = BB;
2407 BBToOrder[BB] = RPONumber;
2408 Worklist.push(RPONumber);
2426 while (!Worklist.empty()) {
2431 while (!Worklist.empty()) {
2435 bool InChanged =
join(*BB, Visited);
2437 InChanged |= Visited.
insert(BB).second;
2442 BlockInfo LiveSet = LiveIn[BB];
2445 process(*BB, &LiveSet);
2448 if (LiveOut[BB] != LiveSet) {
2450 <<
" has new OutLocs, add succs to worklist: [ ");
2451 LiveOut[BB] = std::move(LiveSet);
2453 if (OnPending.
insert(Succ).second) {
2455 Pending.push(BBToOrder[Succ]);
2462 Worklist.swap(Pending);
2465 assert(Pending.empty() &&
"Pending should be empty");
2471 bool InsertedAnyIntrinsics =
false;
2480 for (
const auto &Pair : InsertBeforeMap) {
2481 auto &Vec = Pair.second;
2487 if (NotAlwaysStackHomed.contains(Aggr))
2497 NotAlwaysStackHomed.insert(Aggr);
2506 if (AlwaysStackHomed.
insert(Aggr).second) {
2515 InsertedAnyIntrinsics =
true;
2521 for (
const auto &[InsertBefore, Vec] : InsertBeforeMap) {
2528 if (AlwaysStackHomed.
contains(Aggr))
2531 InsertedAnyIntrinsics =
true;
2534 FnVarLocs->
setWedge(InsertBefore, std::move(NewDefs));
2537 InsertedAnyIntrinsics |= emitPromotedVarLocs(FnVarLocs);
2539 return InsertedAnyIntrinsics;
2542bool AssignmentTrackingLowering::emitPromotedVarLocs(
2543 FunctionVarLocsBuilder *FnVarLocs) {
2544 bool InsertedAnyIntrinsics =
false;
2553 assert(InsertBefore &&
"Unexpected: debug intrinsics after a terminator");
2557 InsertedAnyIntrinsics =
true;
2559 for (
auto &BB : Fn) {
2560 for (
auto &
I : BB) {
2564 TranslateDbgRecord(&DVR);
2567 return InsertedAnyIntrinsics;
2587 VariableDefinedBytes.
clear();
2589 auto HandleLocsForWedge = [&](
auto *WedgePosition) {
2591 const auto *Locs = FnVarLocs.
getWedge(WedgePosition);
2596 bool ChangedThisWedge =
false;
2601 for (
auto RIt = Locs->rbegin(), REnd = Locs->rend(); RIt != REnd; ++RIt) {
2605 uint64_t SizeInBits = Aggr.first->getSizeInBits().value_or(0);
2609 const uint64_t MaxSizeBytes = 2048;
2611 if (SizeInBytes == 0 || SizeInBytes > MaxSizeBytes) {
2625 bool FirstDefinition = InsertResult.second;
2626 BitVector &DefinedBytes = InsertResult.first->second;
2629 RIt->Expr->getFragmentInfo().value_or(
2631 bool InvalidFragment = Fragment.endInBits() > SizeInBits;
2632 uint64_t StartInBytes = Fragment.startInBits() / 8;
2636 if (FirstDefinition || InvalidFragment ||
2638 if (!InvalidFragment)
2639 DefinedBytes.
set(StartInBytes, EndInBytes);
2646 ChangedThisWedge =
true;
2651 if (ChangedThisWedge) {
2652 std::reverse(NewDefsReversed.
begin(), NewDefsReversed.
end());
2653 FnVarLocs.
setWedge(WedgePosition, std::move(NewDefsReversed));
2658 HandleLocsForWedge(&
I);
2660 HandleLocsForWedge(&DVR);
2685 auto HandleLocsForWedge = [&](
auto *WedgePosition) {
2686 const auto *Locs = FnVarLocs.
getWedge(WedgePosition);
2691 bool ChangedThisWedge =
false;
2699 std::nullopt,
Loc.DL.getInlinedAt());
2704 if (Inserted || VMI->second.first !=
Loc.Values ||
2705 VMI->second.second !=
Loc.Expr) {
2706 VMI->second = {
Loc.Values,
Loc.Expr};
2712 ChangedThisWedge =
true;
2717 if (ChangedThisWedge) {
2718 FnVarLocs.
setWedge(WedgePosition, std::move(NewDefs));
2725 HandleLocsForWedge(&DVR);
2726 HandleLocsForWedge(&
I);
2751 VarsWithDef[
A].
insert(V.getFragmentOrDefault());
2757 auto FragsIt = VarsWithDef.
find(
A);
2758 if (FragsIt == VarsWithDef.
end())
2761 return DIExpression::fragmentsOverlap(Frag, V.getFragmentOrDefault());
2772 auto HandleLocsForWedge = [&](
auto *WedgePosition) {
2773 const auto *Locs = FnVarLocs.
getWedge(WedgePosition);
2778 bool ChangedThisWedge =
false;
2786 Loc.DL.getInlinedAt()};
2791 if (
Loc.Values.isKillLocation(
Loc.Expr) && !HasDefinedBits(Aggr, Var)) {
2794 ChangedThisWedge =
true;
2798 DefineBits(Aggr, Var);
2803 if (ChangedThisWedge) {
2804 FnVarLocs.
setWedge(WedgePosition, std::move(NewDefs));
2810 HandleLocsForWedge(&DVR);
2811 HandleLocsForWedge(&
I);
2819 bool MadeChanges =
false;
2833 for (
auto &BB : Fn) {
2834 for (
auto &
I : BB) {
2860 AssignmentTrackingLowering
Pass(Fn, Layout, &VarsWithStackSlot);
2865 MemLocFragmentFill
Pass(Fn, &VarsWithStackSlot,
2867 Pass.run(FnVarLocs);
2884 auto &
DL =
F.getDataLayout();
2908 LLVM_DEBUG(
dbgs() <<
"AssignmentTrackingAnalysis run on " <<
F.getName()
2918 Results->init(Builder);
2921 Results->print(
errs(),
F);
2933 "Assignment Tracking Analysis",
false,
true)
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
Function Alias Analysis Results
std::pair< const DILocalVariable *, const DILocation * > DebugAggregate
A whole (unfragmented) source variable.
VarLocInsertPt getNextNode(const DbgRecord *DVR)
static void analyzeFunction(Function &Fn, const DataLayout &Layout, FunctionVarLocsBuilder *FnVarLocs)
static std::pair< Value *, DIExpression * > walkToAllocaAndPrependOffsetDeref(const DataLayout &DL, Value *Start, DIExpression *Expression)
Walk backwards along constant GEPs and bitcasts to the base storage from Start as far as possible.
static DenseSet< DebugAggregate > findVarsWithStackSlot(Function &Fn)
static bool fullyContains(DIExpression::FragmentInfo A, DIExpression::FragmentInfo B)
Return true if A fully contains B.
static std::optional< at::AssignmentInfo > getUntaggedStoreAssignmentInfo(const Instruction &I, const DataLayout &Layout)
static bool removeUndefDbgLocsFromEntryBlock(const BasicBlock *BB, FunctionVarLocsBuilder &FnVarLocs)
static cl::opt< bool > PrintResults("print-debug-ata", cl::init(false), cl::Hidden)
Print the results of the analysis. Respects -filter-print-funcs.
const char * locStr(AssignmentTrackingLowering::LocKind Loc)
PointerUnion< const Instruction *, const DbgRecord * > VarLocInsertPt
static bool removeRedundantDbgLocsUsingForwardScan(const BasicBlock *BB, FunctionVarLocsBuilder &FnVarLocs)
Remove redundant location defs using a forward scan.
static bool removeRedundantDbgLocs(const BasicBlock *BB, FunctionVarLocsBuilder &FnVarLocs)
static cl::opt< bool > EnableMemLocFragFill("mem-loc-frag-fill", cl::init(true), cl::Hidden)
Option for debugging the pass, determines if the memory location fragment filling happens after gener...
static AssignmentTrackingLowering::OverlapMap buildOverlapMapAndRecordDeclares(Function &Fn, FunctionVarLocsBuilder *FnVarLocs, const DenseSet< DebugAggregate > &VarsWithStackSlot, AssignmentTrackingLowering::UntaggedStoreAssignmentMap &UntaggedStoreVars, AssignmentTrackingLowering::UnknownStoreAssignmentMap &UnknownStoreVars, AssignmentTrackingLowering::EscapingCallVarsMap &EscapingCallVars, unsigned &TrackedVariablesVectorSize)
Build a map of {Variable x: Variables y} where all variable fragments contained within the variable f...
static DIAssignID * getIDFromMarker(const DbgVariableRecord &DVR)
static DebugAggregate getAggregate(const DebugVariable &Var)
static bool hasZeroSizedFragment(DbgVariableRecord &DbgValue)
static DIAssignID * getIDFromInst(const Instruction &I)
AllocaInst * getUnknownStore(const Instruction &I, const DataLayout &Layout)
static std::optional< int64_t > getDerefOffsetInBytes(const DIExpression *DIExpr)
Extract the offset used in DIExpr.
static bool removeRedundantDbgLocsUsingBackwardScan(const BasicBlock *BB, FunctionVarLocsBuilder &FnVarLocs)
Remove redundant definitions within sequences of consecutive location defs.
static cl::opt< cl::boolOrDefault > CoalesceAdjacentFragmentsOpt("debug-ata-coalesce-frags", cl::Hidden)
Coalesce adjacent dbg locs describing memory locations that have contiguous fragments.
static cl::opt< unsigned > MaxNumBlocks("debug-ata-max-blocks", cl::init(10000), cl::desc("Maximum num basic blocks before debug info dropped"), cl::Hidden)
static bool shouldCoalesceFragments(Function &F)
This file implements the BitVector class.
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
static ManagedStatic< cl::opt< bool, true >, CreateDebug > Debug
This file defines DenseMapInfo traits for DenseMap.
This file contains constants used for implementing Dwarf debug support.
Module.h This file contains the declarations for the Module class.
This header defines various interfaces for pass management in LLVM.
This file implements a coalescing interval map for small objects.
const AbstractManglingParser< Derived, Alloc >::OperatorInfo AbstractManglingParser< Derived, Alloc >::Ops[]
IntervalMap< SlotIndex, DbgVariableValue, 4 > LocMap
Map of where a user value is live to that value.
print mir2vec MIR2Vec Vocabulary Printer Pass
uint64_t IntrinsicInst * II
FunctionAnalysisManager FAM
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
This file builds on the ADT/GraphTraits.h file to build a generic graph post order iterator.
static bool isValid(const char C)
Returns true if C is a valid mangled character: <0-9a-zA-Z_>.
Scalar Replacement Of Aggregates
This file defines the 'Statistic' class, which is designed to be an easy way to expose various metric...
#define STATISTIC(VARNAME, DESC)
Helper class to build FunctionVarLocs, since that class isn't easy to modify.
void setWedge(VarLocInsertPt Before, SmallVector< VarLocInfo > &&Wedge)
Replace the defs that come just before /p Before with /p Wedge.
const SmallVectorImpl< VarLocInfo > * getWedge(VarLocInsertPt Before) const
Return ptr to wedge of defs or nullptr if no defs come just before /p Before.
unsigned getNumVariables() const
void addSingleLocVar(DebugVariable Var, DIExpression *Expr, DebugLoc DL, RawLocationWrapper R)
Add a def for a variable that is valid for its lifetime.
VariableID insertVariable(DebugVariable V)
Find or insert V and return the ID.
void addVarLoc(VarLocInsertPt Before, DebugVariable Var, DIExpression *Expr, DebugLoc DL, RawLocationWrapper R)
Add a def to the wedge of defs just before /p Before.
const DebugVariable & getVariable(VariableID ID) const
Get a variable from its ID.
Class recording the (high level) value of a variable.
Class for arbitrary precision integers.
uint64_t getZExtValue() const
Get zero extended value.
bool getBoolValue() const
Convert APInt to a boolean value.
an instruction to allocate memory on the stack
Represent a constant reference to an array (0 or more elements consecutively in memory),...
AssignmentTrackingAnalysis()
bool runOnFunction(Function &F) override
runOnFunction - Virtual method overriden by subclasses to do the per-function processing of the pass.
LLVM Basic Block Representation.
iterator begin()
Instruction iterator methods.
LLVM_ABI bool isEntryBlock() const
Return true if this is the entry block of the containing function.
int find_first_unset_in(unsigned Begin, unsigned End) const
Returns the index of the first unset bit in the range [Begin, End).
BitVector & set()
Set all bits in the bitvector.
iterator_range< const_set_bits_iterator > set_bits() const
A structured debug information entry.
static LLVM_ABI DIExpression * append(const DIExpression *Expr, ArrayRef< uint64_t > Ops)
Append the opcodes Ops to DIExpr.
unsigned getNumElements() const
DbgVariableFragmentInfo FragmentInfo
LLVM_ABI bool startsWithDeref() const
Return whether the first element a DW_OP_deref.
static LLVM_ABI std::optional< FragmentInfo > getFragmentInfo(expr_op_iterator Start, expr_op_iterator End)
Retrieve the details of this fragment expression.
ArrayRef< uint64_t > getElements() const
static LLVM_ABI std::optional< DIExpression * > createFragmentExpression(const DIExpression *Expr, unsigned OffsetInBits, unsigned SizeInBits)
Create a DIExpression to describe one part of an aggregate variable that is fragmented across multipl...
static LLVM_ABI DIExpression * prepend(const DIExpression *Expr, uint8_t Flags, int64_t Offset=0)
Prepend DIExpr with a deref and offset operation and optionally turn it into a stack value or/and an ...
static LLVM_ABI DIExpression * prependOpcodes(const DIExpression *Expr, SmallVectorImpl< uint64_t > &Ops, bool StackValue=false, bool EntryValue=false)
Prepend DIExpr with the given opcodes and optionally turn it into a stack value.
LLVM_ABI std::optional< uint64_t > getSizeInBits() const
Determines the size of the variable's type.
StringRef getName() const
A parsed version of the target data layout string in and methods for querying it.
LLVM_ABI unsigned getIndexTypeSizeInBits(Type *Ty) const
The size in bits of the index used in GEP calculation for this type.
Instruction * MarkedInstr
Link back to the Instruction that owns this marker.
LLVM_ABI iterator_range< simple_ilist< DbgRecord >::iterator > getDbgRecordRange()
Produce a range over all the DbgRecords in this Marker.
Base class for non-instruction debug metadata records that have positions within IR.
DebugLoc getDebugLoc() const
Record of a variable value-assignment, aka a non instruction representation of the dbg....
LLVM_ABI Value * getAddress() const
LLVM_ABI bool isKillAddress() const
Check whether this kills the address component.
LLVM_ABI DIAssignID * getAssignID() const
DIExpression * getExpression() const
DILocalVariable * getVariable() const
Metadata * getRawLocation() const
Returns the metadata operand for the first location description.
DIExpression * getAddressExpression() const
LLVM_ABI Result run(Function &F, FunctionAnalysisManager &FAM)
LLVM_ABI PreservedAnalyses run(Function &F, FunctionAnalysisManager &FAM)
LLVM_ABI DILocation * getInlinedAt() const
Identifies a unique instance of a variable.
const DILocation * getInlinedAt() const
const DILocalVariable * getVariable() const
iterator find(const_arg_type_t< KeyT > Val)
std::pair< iterator, bool > try_emplace(KeyT &&Key, Ts &&...Args)
std::pair< iterator, bool > insert(const std::pair< KeyT, ValueT > &KV)
void reserve(size_type NumEntries)
Grow the densemap so that it can contain at least NumEntries items before resizing again.
Implements a dense probed hash-table based set.
Class representing an expression and its matching format.
Data structure describing the variable locations in a function.
LLVM_ABI void print(raw_ostream &OS, const Function &Fn) const
const VarLocInfo * locs_begin(const Instruction *Before) const
First variable location definition that comes before Before.
const VarLocInfo * single_locs_begin() const
const VarLocInfo * locs_end(const Instruction *Before) const
One past the last variable location definition that comes before Before.
const VarLocInfo * single_locs_end() const
One past the last single-location variable location definition.
LLVM_ABI void init(FunctionVarLocsBuilder &Builder)
const DataLayout & getDataLayout() const
Get the data layout of the module this function belongs to.
LLVMContext & getContext() const
getContext - Return a reference to the LLVMContext associated with this function.
bool isTerminator() const
const_iterator begin() const
void insert(KeyT a, KeyT b, ValT y)
insert - Add a mapping of [a;b] to y, coalesce with adjacent intervals.
void clear()
clear - Remove all entries.
static MDTuple * get(LLVMContext &Context, ArrayRef< Metadata * > MDs)
void push_back(MachineInstr *MI)
Pass interface - Implemented by all 'passes'.
A discriminated union of two or more pointer types, with the discriminator in the low bits of the poi...
void * getOpaqueValue() const
static LLVM_ABI PoisonValue * get(Type *T)
Static factory methods - Return an 'poison' object of the specified type.
A set of analyses that are preserved following a run of a transformation pass.
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
Lightweight class that wraps the location operand metadata of a debug intrinsic.
Implements a dense probed hash-table based set with some number of buckets stored inline.
size_type count(ConstPtrType Ptr) const
count - Return 1 if the specified pointer is in the set, 0 otherwise.
std::pair< iterator, bool > insert(PtrType Ptr)
Inserts Ptr if and only if there is no element in the container equal to Ptr.
SmallPtrSet - This class implements a set which is optimized for holding SmallSize or less elements.
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
bool isPointerTy() const
True if this is an instance of PointerType.
static LLVM_ABI IntegerType * getInt1Ty(LLVMContext &C)
UniqueVector - This class produces a sequential ID number (base 1) for each unique entry that is adde...
unsigned insert(const T &Entry)
insert - Append entry to the vector if it doesn't already exist.
LLVM Value Representation.
Type * getType() const
All values are typed, get the type of this value.
LLVM_ABI StringRef getName() const
Return a constant reference to the value's name.
std::pair< iterator, bool > insert(const ValueT &V)
bool contains(const_arg_type_t< ValueT > V) const
Check if the set contains the given element.
size_type count(const_arg_type_t< ValueT > V) const
Return 1 if the specified key is in the set, 0 otherwise.
self_iterator getIterator()
NodeTy * getNextNode()
Get the next node, or nullptr for the list tail.
This class implements an extremely fast bulk output stream that can only output to a stream.
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
DenseMap< FragmentOfVar, SmallVector< DIExpression::FragmentInfo, 1 > > OverlapMap
constexpr std::underlying_type_t< E > Mask()
Get a bitmask with 1s in all places up to the high-order bit of E's largest value.
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
@ Tail
Attemps to make calls as fast as possible while guaranteeing that tail call optimization can always b...
@ BasicBlock
Various leaf nodes.
LLVM_ABI void deleteAll(Function *F)
Remove all Assignment Tracking related intrinsics and metadata from F.
SmallVector< DbgVariableRecord * > getDVRAssignmentMarkers(const Instruction *Inst)
Return a range of dbg_assign records for which Inst performs the assignment they encode.
LLVM_ABI std::optional< AssignmentInfo > getAssignmentInfo(const DataLayout &DL, const MemIntrinsic *I)
LLVM_ABI bool calculateFragmentIntersect(const DataLayout &DL, const Value *Dest, uint64_t SliceOffsetInBits, uint64_t SliceSizeInBits, const DbgVariableRecord *DVRAssign, std::optional< DIExpression::FragmentInfo > &Result)
Calculate the fragment of the variable in DAI covered from (Dest + SliceOffsetInBits) to to (Dest + S...
initializer< Ty > init(const Ty &Val)
@ DW_OP_LLVM_fragment
Only used in LLVM metadata.
DXILDebugInfoMap run(Module &M)
friend class Instruction
Iterator for Instructions in a `BasicBlock.
This is an optimization pass for GlobalISel generic memory operations.
void dump(const SparseBitVector< ElementSize > &LHS, raw_ostream &out)
std::tuple< const DIScope *, const DIScope *, const DILocalVariable * > VarID
A unique key that represents a debug variable.
bool all_of(R &&range, UnaryPredicate P)
Provide wrappers to std::all_of which take ranges instead of having to pass begin/end explicitly.
Printable print(const GCNRegPressure &RP, const GCNSubtarget *ST=nullptr, unsigned DynamicVGPRBlockSize=0)
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
auto successors(const MachineBasicBlock *BB)
bool operator!=(uint64_t V1, const APInt &V2)
bool operator==(const AddressRangeValuePair &LHS, const AddressRangeValuePair &RHS)
bool any_of(R &&range, UnaryPredicate P)
Provide wrappers to std::any_of which take ranges instead of having to pass begin/end explicitly.
auto reverse(ContainerTy &&C)
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
bool isFunctionInPrintList(StringRef FunctionName)
VariableID
Type wrapper for integer ID for Variables. 0 is reserved.
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
bool isa(const From &Val)
isa<X> - Return true if the parameter to the template is an instance of one of the template type argu...
LLVM_ATTRIBUTE_VISIBILITY_DEFAULT AnalysisKey InnerAnalysisManagerProxy< AnalysisManagerT, IRUnitT, ExtraArgTs... >::Key
LLVM_ABI raw_fd_ostream & errs()
This returns a reference to a raw_ostream for standard error.
constexpr T divideCeil(U Numerator, V Denominator)
Returns the integer ceil(Numerator / Denominator).
std::string join(IteratorT Begin, IteratorT End, StringRef Separator)
Joins the strings in the range [Begin, End), adding Separator between the elements.
LLVM_ABI bool isAssignmentTrackingEnabled(const Module &M)
Return true if assignment tracking is enabled for module M.
FunctionAddr VTableAddr Next
DWARFExpression::Operation Op
ArrayRef(const T &OneElt) -> ArrayRef< T >
std::string toString(const APInt &I, unsigned Radix, bool Signed, bool formatAsCLiteral=false, bool UpperCase=true, bool InsertSeparators=false)
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
auto predecessors(const MachineBasicBlock *BB)
AnalysisManager< Function > FunctionAnalysisManager
Convenience typedef for the Function analysis manager.
LLVM_ABI const Value * getUnderlyingObject(const Value *V, unsigned MaxLookup=MaxLookupSearchDepth)
This method strips off any GEP address adjustments, pointer casts or llvm.threadlocal....
static auto filterDbgVars(iterator_range< simple_ilist< DbgRecord >::iterator > R)
Filter the DbgRecord range to DbgVariableRecord types only and downcast.
bool debuginfoShouldUseDebugInstrRef(const Triple &T)
Implement std::hash so that hash_code can be used in STL containers.
A special type used by analysis passes to provide an address that identifies that particular analysis...
static VariableID getTombstoneKey()
static bool isEqual(const VariableID &LHS, const VariableID &RHS)
static unsigned getHashValue(const VariableID &Val)
static VariableID getEmptyKey()
DenseMapInfo< unsigned > Wrapped
An information struct used to provide DenseMap with the various necessary components for a given valu...
Variable location definition used by FunctionVarLocs.
RawLocationWrapper Values
llvm::VariableID VariableID
std::size_t operator()(const VarLocInsertPt &Arg) const