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 Wrapped::getHashValue(
static_cast<unsigned>(Val));
93 friend FunctionVarLocs;
97 std::unordered_map<VarLocInsertPt, SmallVector<VarLocInfo>> VarLocsBeforeInst;
106 return static_cast<VariableID>(Variables.insert(V));
111 return Variables[
static_cast<unsigned>(
ID)];
117 auto R = VarLocsBeforeInst.find(Before);
118 if (R == VarLocsBeforeInst.end())
125 VarLocsBeforeInst[Before] = std::move(Wedge);
134 VarLoc.
DL = std::move(
DL);
136 SingleLocVars.emplace_back(VarLoc);
145 VarLoc.
DL = std::move(
DL);
147 VarLocsBeforeInst[Before].emplace_back(VarLoc);
154 unsigned Counter = -1;
155 OS <<
"=== Variables ===\n";
162 OS <<
"[" << Counter <<
"] " << V.getVariable()->getName();
163 if (
auto F = V.getFragment())
164 OS <<
" bits [" <<
F->OffsetInBits <<
", "
165 <<
F->OffsetInBits +
F->SizeInBits <<
")";
166 if (
const auto *IA = V.getInlinedAt())
167 OS <<
" inlined-at " << *IA;
172 OS <<
"DEF Var=[" << (
unsigned)
Loc.VariableID <<
"]"
173 <<
" Expr=" << *
Loc.Expr <<
" Values=(";
174 for (
auto *
Op :
Loc.Values.location_ops()) {
175 errs() <<
Op->getName() <<
" ";
181 OS <<
"=== Single location vars ===\n";
188 OS <<
"=== In-line variable defs ===";
190 OS <<
"\n" << BB.getName() <<
":\n";
202 for (
const auto &VarLoc : Builder.SingleLocVars)
203 VarLocRecords.emplace_back(VarLoc);
205 SingleVarLocEnd = VarLocRecords.size();
211 for (
auto &
P : Builder.VarLocsBeforeInst) {
217 unsigned BlockStart = VarLocRecords.size();
224 auto It = Builder.VarLocsBeforeInst.find(&DVR);
225 if (It == Builder.VarLocsBeforeInst.end())
228 VarLocRecords.emplace_back(VarLoc);
231 VarLocRecords.emplace_back(VarLoc);
232 unsigned BlockEnd = VarLocRecords.size();
234 if (BlockEnd != BlockStart)
235 VarLocsBeforeInst[
I] = {BlockStart, BlockEnd};
239 assert(Variables.empty() &&
"Expect clear before init");
242 Variables.reserve(Builder.Variables.size() + 1);
243 Variables.push_back(
DebugVariable(
nullptr, std::nullopt,
nullptr));
244 Variables.append(Builder.Variables.begin(), Builder.Variables.end());
249 VarLocRecords.clear();
250 VarLocsBeforeInst.clear();
258static std::pair<Value *, DIExpression *>
261 APInt OffsetInBytes(
DL.getTypeSizeInBits(Start->getType()),
false);
263 Start->stripAndAccumulateInBoundsConstantOffsets(
DL, OffsetInBytes);
277static std::optional<int64_t>
282 unsigned ExpectedDerefIdx = 0;
284 if (NumElements > 2 && Elements[0] == dwarf::DW_OP_plus_uconst) {
286 ExpectedDerefIdx = 2;
287 }
else if (NumElements > 3 && Elements[0] == dwarf::DW_OP_constu) {
288 ExpectedDerefIdx = 3;
289 if (Elements[2] == dwarf::DW_OP_plus)
291 else if (Elements[2] == dwarf::DW_OP_minus)
298 if (ExpectedDerefIdx >= NumElements)
303 if (Elements[ExpectedDerefIdx] != dwarf::DW_OP_deref)
307 if (NumElements == ExpectedDerefIdx + 1)
309 unsigned ExpectedFragFirstIdx = ExpectedDerefIdx + 1;
310 unsigned ExpectedFragFinalIdx = ExpectedFragFirstIdx + 2;
311 if (NumElements == ExpectedFragFinalIdx + 1 &&
361class MemLocFragmentFill {
363 FunctionVarLocsBuilder *FnVarLocs;
364 const DenseSet<DebugAggregate> *VarsWithStackSlot;
365 bool CoalesceAdjacentFragments;
368 using BaseAddress = unsigned;
369 using OffsetInBitsTy = unsigned;
370 using FragTraits = IntervalMapHalfOpenInfo<OffsetInBitsTy>;
371 using FragsInMemMap = IntervalMap<
372 OffsetInBitsTy, BaseAddress,
373 IntervalMapImpl::NodeSizer<OffsetInBitsTy, BaseAddress>::LeafSize,
375 FragsInMemMap::Allocator IntervalMapAlloc;
376 using VarFragMap = DenseMap<unsigned, FragsInMemMap>;
380 UniqueVector<RawLocationWrapper> Bases;
382 DenseMap<const BasicBlock *, VarFragMap> LiveIn;
383 DenseMap<const BasicBlock *, VarFragMap> LiveOut;
388 unsigned OffsetInBits;
392 using InsertMap = MapVector<VarLocInsertPt, SmallVector<FragMemLoc>>;
399 DenseMap<const BasicBlock *, InsertMap> BBInsertBeforeMap;
401 static bool intervalMapsAreEqual(
const FragsInMemMap &
A,
402 const FragsInMemMap &
B) {
403 auto AIt =
A.
begin(), AEnd =
A.end();
404 auto BIt =
B.begin(), BEnd =
B.end();
405 for (; AIt != AEnd; ++AIt, ++BIt) {
408 if (AIt.start() != BIt.start() || AIt.stop() != BIt.stop())
417 static bool varFragMapsAreEqual(
const VarFragMap &
A,
const VarFragMap &
B) {
418 if (
A.size() !=
B.size())
420 for (
const auto &APair :
A) {
421 auto BIt =
B.find(APair.first);
424 if (!intervalMapsAreEqual(APair.second, BIt->second))
431 std::string
toString(
unsigned BaseID) {
433 return Bases[BaseID].getVariableLocationOp(0)->getName().str();
439 std::string
toString(FragsInMemMap::const_iterator It,
bool Newline =
true) {
441 std::stringstream S(
String);
443 S <<
"[" << It.start() <<
", " << It.stop()
446 S <<
"invalid iterator (end)";
453 FragsInMemMap meetFragments(
const FragsInMemMap &
A,
const FragsInMemMap &
B) {
454 FragsInMemMap
Result(IntervalMapAlloc);
455 for (
auto AIt =
A.begin(), AEnd =
A.end(); AIt != AEnd; ++AIt) {
462 if (!
B.overlaps(AIt.start(), AIt.stop()))
466 auto FirstOverlap =
B.find(AIt.start());
467 assert(FirstOverlap !=
B.end());
468 bool IntersectStart = FirstOverlap.start() < AIt.start();
470 <<
", IntersectStart: " << IntersectStart <<
"\n");
473 auto LastOverlap =
B.find(AIt.stop());
475 LastOverlap !=
B.end() && LastOverlap.start() < AIt.stop();
477 <<
", IntersectEnd: " << IntersectEnd <<
"\n");
480 if (IntersectStart && IntersectEnd && FirstOverlap == LastOverlap) {
488 if (*AIt && *AIt == *FirstOverlap)
489 Result.insert(AIt.start(), AIt.stop(), *AIt);
497 auto Next = FirstOverlap;
498 if (IntersectStart) {
501 if (*AIt && *AIt == *FirstOverlap)
502 Result.insert(AIt.start(), FirstOverlap.stop(), *AIt);
512 if (*AIt && *AIt == *LastOverlap)
513 Result.insert(LastOverlap.start(), AIt.stop(), *AIt);
522 while (
Next !=
B.end() &&
Next.start() < AIt.stop() &&
523 Next.stop() <= AIt.stop()) {
525 <<
"- insert intersection of a and " <<
toString(
Next));
526 if (*AIt && *AIt == *
Next)
536 void meetVars(VarFragMap &
A,
const VarFragMap &
B) {
540 A.remove_if([&](
auto &Entry) {
541 auto BIt =
B.find(
Entry.first);
546 Entry.second = meetFragments(
Entry.second, BIt->second);
551 bool meet(
const BasicBlock &BB,
552 const SmallPtrSet<BasicBlock *, 16> &Visited) {
557 bool FirstMeet =
true;
564 if (!Visited.
count(Pred))
567 auto PredLiveOut = LiveOut.
find(Pred);
572 BBLiveIn = PredLiveOut->second;
575 LLVM_DEBUG(
dbgs() <<
"BBLiveIn = meet BBLiveIn, " << Pred->getName()
577 meetVars(BBLiveIn, PredLiveOut->second);
583 if (BBLiveIn.size() == 0)
592 CurrentLiveInEntry->second = std::move(BBLiveIn);
598 if (!varFragMapsAreEqual(BBLiveIn, CurrentLiveInEntry->second)) {
600 CurrentLiveInEntry->second = std::move(BBLiveIn);
608 void insertMemLoc(BasicBlock &BB,
VarLocInsertPt Before,
unsigned Var,
609 unsigned StartBit,
unsigned EndBit,
unsigned Base,
611 assert(StartBit < EndBit &&
"Cannot create fragment of size <= 0");
616 Loc.OffsetInBits = StartBit;
617 Loc.SizeInBits = EndBit - StartBit;
618 assert(
Base &&
"Expected a non-zero ID for Base address");
621 BBInsertBeforeMap[&BB][Before].push_back(Loc);
623 <<
" bits [" << StartBit <<
", " << EndBit <<
")\n");
630 void coalesceFragments(BasicBlock &BB,
VarLocInsertPt Before,
unsigned Var,
631 unsigned StartBit,
unsigned EndBit,
unsigned Base,
633 if (!CoalesceAdjacentFragments)
640 auto CoalescedFrag = FragMap.find(StartBit);
642 if (CoalescedFrag.start() == StartBit && CoalescedFrag.stop() == EndBit)
645 LLVM_DEBUG(
dbgs() <<
"- Insert loc for bits " << CoalescedFrag.start()
646 <<
" to " << CoalescedFrag.stop() <<
"\n");
647 insertMemLoc(BB, Before, Var, CoalescedFrag.start(), CoalescedFrag.stop(),
651 void addDef(
const VarLocInfo &VarLoc,
VarLocInsertPt Before, BasicBlock &BB,
652 VarFragMap &LiveSet) {
665 const DIExpression *DIExpr = VarLoc.
Expr;
669 StartBit = Frag->OffsetInBits;
670 EndBit = StartBit + Frag->SizeInBits;
685 const unsigned Base =
686 DerefOffsetInBytes && *DerefOffsetInBytes * 8 == StartBit
690 << StartBit <<
", " << EndBit <<
"): " <<
toString(
Base)
697 auto FragIt = LiveSet.find(Var);
700 if (FragIt == LiveSet.end()) {
702 auto P = LiveSet.try_emplace(Var, FragsInMemMap(IntervalMapAlloc));
703 assert(
P.second &&
"Var already in map?");
705 P.first->second.insert(StartBit, EndBit,
Base);
710 FragsInMemMap &FragMap = FragIt->second;
713 if (!FragMap.overlaps(StartBit, EndBit)) {
715 FragMap.insert(StartBit, EndBit,
Base);
716 coalesceFragments(BB, Before, Var, StartBit, EndBit,
Base, VarLoc.
DL,
723 auto FirstOverlap = FragMap.find(StartBit);
724 assert(FirstOverlap != FragMap.end());
725 bool IntersectStart = FirstOverlap.start() < StartBit;
728 auto LastOverlap = FragMap.find(EndBit);
729 bool IntersectEnd = LastOverlap.valid() && LastOverlap.start() < EndBit;
732 if (IntersectStart && IntersectEnd && FirstOverlap == LastOverlap) {
733 LLVM_DEBUG(
dbgs() <<
"- Intersect single interval @ both ends\n");
741 auto EndBitOfOverlap = FirstOverlap.stop();
742 unsigned OverlapValue = FirstOverlap.value();
745 FirstOverlap.setStop(StartBit);
746 insertMemLoc(BB, Before, Var, FirstOverlap.start(), StartBit,
747 OverlapValue, VarLoc.
DL);
750 FragMap.insert(EndBit, EndBitOfOverlap, OverlapValue);
751 insertMemLoc(BB, Before, Var, EndBit, EndBitOfOverlap, OverlapValue,
755 FragMap.insert(StartBit, EndBit,
Base);
765 if (IntersectStart) {
768 FirstOverlap.setStop(StartBit);
769 insertMemLoc(BB, Before, Var, FirstOverlap.start(), StartBit,
770 *FirstOverlap, VarLoc.
DL);
779 LastOverlap.setStart(EndBit);
780 insertMemLoc(BB, Before, Var, EndBit, LastOverlap.stop(), *LastOverlap,
796 auto It = FirstOverlap;
799 while (It.valid() && It.start() >= StartBit && It.stop() <= EndBit) {
804 assert(!FragMap.overlaps(StartBit, EndBit));
806 FragMap.insert(StartBit, EndBit,
Base);
809 coalesceFragments(BB, Before, Var, StartBit, EndBit,
Base, VarLoc.
DL,
813 bool skipVariable(
const DILocalVariable *V) {
return !
V->getSizeInBits(); }
815 void process(BasicBlock &BB, VarFragMap &LiveSet) {
816 BBInsertBeforeMap[&BB].
clear();
818 for (DbgVariableRecord &DVR :
filterDbgVars(
I.getDbgRecordRange())) {
819 if (
const auto *Locs = FnVarLocs->
getWedge(&DVR)) {
820 for (
const VarLocInfo &Loc : *Locs) {
821 addDef(Loc, &DVR, *
I.getParent(), LiveSet);
825 if (
const auto *Locs = FnVarLocs->
getWedge(&
I)) {
826 for (
const VarLocInfo &Loc : *Locs) {
827 addDef(Loc, &
I, *
I.getParent(), LiveSet);
834 MemLocFragmentFill(Function &Fn,
835 const DenseSet<DebugAggregate> *VarsWithStackSlot,
836 bool CoalesceAdjacentFragments)
837 : Fn(Fn), VarsWithStackSlot(VarsWithStackSlot),
838 CoalesceAdjacentFragments(CoalesceAdjacentFragments) {}
860 void run(FunctionVarLocsBuilder *FnVarLocs) {
864 this->FnVarLocs = FnVarLocs;
868 ReversePostOrderTraversal<Function *> RPOT(&Fn);
869 std::priority_queue<unsigned int, std::vector<unsigned int>,
870 std::greater<unsigned int>>
872 std::priority_queue<unsigned int, std::vector<unsigned int>,
873 std::greater<unsigned int>>
875 DenseMap<unsigned int, BasicBlock *> OrderToBB;
876 DenseMap<BasicBlock *, unsigned int> BBToOrder;
878 unsigned int RPONumber = 0;
879 for (BasicBlock *BB : RPOT) {
880 OrderToBB[RPONumber] = BB;
881 BBToOrder[BB] = RPONumber;
882 Worklist.push(RPONumber);
898 SmallPtrSet<BasicBlock *, 16> Visited;
899 while (!Worklist.empty() || !Pending.empty()) {
903 SmallPtrSet<BasicBlock *, 16> OnPending;
905 while (!Worklist.empty()) {
909 bool InChanged = meet(*BB, Visited);
911 InChanged |= Visited.
insert(BB).second;
914 << BB->
getName() <<
" has new InLocs, process it\n");
918 VarFragMap LiveSet = LiveIn[BB];
921 process(*BB, LiveSet);
924 if (!varFragMapsAreEqual(LiveOut[BB], LiveSet)) {
926 <<
" has new OutLocs, add succs to worklist: [ ");
927 LiveOut[BB] = std::move(LiveSet);
929 if (OnPending.
insert(Succ).second) {
931 Pending.push(BBToOrder[Succ]);
938 Worklist.swap(Pending);
941 assert(Pending.empty() &&
"Pending should be empty");
945 for (
auto &Pair : BBInsertBeforeMap) {
946 InsertMap &
Map = Pair.second;
947 for (
auto &Pair : Map) {
948 auto InsertBefore = Pair.first;
949 assert(InsertBefore &&
"should never be null");
950 auto FragMemLocs = Pair.second;
953 for (
auto &FragMemLoc : FragMemLocs) {
954 DIExpression *Expr = DIExpression::get(Ctx, {});
955 if (FragMemLoc.SizeInBits !=
956 *
Aggregates[FragMemLoc.Var].first->getSizeInBits())
958 Expr, FragMemLoc.OffsetInBits, FragMemLoc.SizeInBits);
960 FragMemLoc.OffsetInBits / 8);
961 DebugVariable Var(
Aggregates[FragMemLoc.Var].first, Expr,
962 FragMemLoc.DL.getInlinedAt());
963 FnVarLocs->
addVarLoc(InsertBefore, Var, Expr, FragMemLoc.DL,
964 Bases[FragMemLoc.Base]);
974class AssignmentTrackingLowering {
999 enum class LocKind { Mem, Val,
None };
1016 enum S { Known, NoneOrPhi } Status;
1021 DbgVariableRecord *
Source =
nullptr;
1023 bool isSameSourceAssignment(
const Assignment &
Other)
const {
1026 return std::tie(Status,
ID) == std::tie(
Other.Status,
Other.ID);
1028 void dump(raw_ostream &OS) {
1029 static const char *
LUT[] = {
"Known",
"NoneOrPhi"};
1030 OS <<
LUT[Status] <<
"(id=";
1043 static Assignment make(DIAssignID *
ID, DbgVariableRecord *Source) {
1045 "Cannot make an assignment from a non-assign DbgVariableRecord");
1046 return Assignment(Known,
ID, Source);
1048 static Assignment makeFromMemDef(DIAssignID *
ID) {
1049 return Assignment(Known,
ID);
1051 static Assignment makeNoneOrPhi() {
return Assignment(NoneOrPhi,
nullptr); }
1053 Assignment() : Status(NoneOrPhi),
ID(nullptr) {}
1054 Assignment(S Status, DIAssignID *
ID) : Status(Status),
ID(
ID) {
1058 Assignment(S Status, DIAssignID *
ID, DbgVariableRecord *Source)
1065 using AssignmentMap = SmallVector<Assignment>;
1066 using LocMap = SmallVector<LocKind>;
1067 using OverlapMap = DenseMap<VariableID, SmallVector<VariableID>>;
1068 using UntaggedStoreAssignmentMap =
1071 using UnknownStoreAssignmentMap =
1072 DenseMap<const Instruction *, SmallVector<VariableID>>;
1073 using EscapingCallVarsMap =
1080 unsigned TrackedVariablesVectorSize = 0;
1085 UntaggedStoreAssignmentMap UntaggedStoreVars;
1088 UnknownStoreAssignmentMap UnknownStoreVars;
1092 EscapingCallVarsMap EscapingCallVars;
1095 using InstInsertMap = MapVector<VarLocInsertPt, SmallVector<VarLocInfo>>;
1096 InstInsertMap InsertBeforeMap;
1099 void resetInsertionPoint(Instruction &After);
1100 void resetInsertionPoint(DbgVariableRecord &After);
1102 void emitDbgValue(LocKind Kind, DbgVariableRecord *,
VarLocInsertPt After);
1104 static bool mapsAreEqual(
const BitVector &Mask,
const AssignmentMap &
A,
1105 const AssignmentMap &
B) {
1107 return A[VarID].isSameSourceAssignment(B[VarID]);
1116 BitVector VariableIDsInBlock;
1119 AssignmentMap StackHomeValue;
1121 AssignmentMap DebugValue;
1136 const AssignmentMap &getAssignmentMap(AssignmentKind Kind)
const {
1139 return StackHomeValue;
1145 AssignmentMap &getAssignmentMap(AssignmentKind Kind) {
1146 return const_cast<AssignmentMap &
>(
1147 const_cast<const BlockInfo *
>(
this)->getAssignmentMap(Kind));
1150 bool isVariableTracked(
VariableID Var)
const {
1151 return VariableIDsInBlock[
static_cast<unsigned>(Var)];
1154 const Assignment &getAssignment(AssignmentKind Kind,
VariableID Var)
const {
1155 assert(isVariableTracked(Var) &&
"Var not tracked in block");
1156 return getAssignmentMap(Kind)[
static_cast<unsigned>(Var)];
1160 assert(isVariableTracked(Var) &&
"Var not tracked in block");
1161 return LiveLoc[
static_cast<unsigned>(Var)];
1167 VariableIDsInBlock.
set(
static_cast<unsigned>(Var));
1168 LiveLoc[
static_cast<unsigned>(Var)] = K;
1174 void setAssignment(AssignmentKind Kind,
VariableID Var,
1175 const Assignment &AV) {
1176 VariableIDsInBlock.
set(
static_cast<unsigned>(Var));
1177 getAssignmentMap(Kind)[
static_cast<unsigned>(Var)] = AV;
1183 bool hasAssignment(AssignmentKind Kind,
VariableID Var,
1184 const Assignment &AV)
const {
1185 if (!isVariableTracked(Var))
1187 return AV.isSameSourceAssignment(getAssignment(Kind, Var));
1193 return VariableIDsInBlock ==
Other.VariableIDsInBlock &&
1194 LiveLoc ==
Other.LiveLoc &&
1195 mapsAreEqual(VariableIDsInBlock, StackHomeValue,
1196 Other.StackHomeValue) &&
1197 mapsAreEqual(VariableIDsInBlock, DebugValue,
Other.DebugValue);
1201 return LiveLoc.size() == DebugValue.size() &&
1202 LiveLoc.size() == StackHomeValue.size();
1206 void init(
int NumVars) {
1207 StackHomeValue.clear();
1210 VariableIDsInBlock = BitVector(NumVars);
1211 StackHomeValue.insert(StackHomeValue.begin(), NumVars,
1212 Assignment::makeNoneOrPhi());
1213 DebugValue.insert(DebugValue.begin(), NumVars,
1214 Assignment::makeNoneOrPhi());
1215 LiveLoc.
insert(LiveLoc.
begin(), NumVars, LocKind::None);
1219 template <
typename ElmtType,
typename FnInputType>
1223 ElmtType (*Fn)(FnInputType, FnInputType)) {
1228 static BlockInfo
join(
const BlockInfo &
A,
const BlockInfo &
B,
int NumVars) {
1247 BitVector Intersect =
A.VariableIDsInBlock;
1248 Intersect &=
B.VariableIDsInBlock;
1251 joinElmt(
VarID, Join.LiveLoc,
A.LiveLoc,
B.LiveLoc, joinKind);
1252 joinElmt(
VarID, Join.DebugValue,
A.DebugValue,
B.DebugValue,
1254 joinElmt(
VarID, Join.StackHomeValue,
A.StackHomeValue,
B.StackHomeValue,
1258 Join.VariableIDsInBlock =
A.VariableIDsInBlock;
1259 Join.VariableIDsInBlock |=
B.VariableIDsInBlock;
1266 const DataLayout &Layout;
1267 const DenseSet<DebugAggregate> *VarsWithStackSlot;
1268 FunctionVarLocsBuilder *FnVarLocs;
1269 DenseMap<const BasicBlock *, BlockInfo> LiveIn;
1270 DenseMap<const BasicBlock *, BlockInfo> LiveOut;
1273 DenseSet<VariableID> VarsTouchedThisFrame;
1276 DenseSet<DebugAggregate> NotAlwaysStackHomed;
1278 VariableID getVariableID(
const DebugVariable &Var) {
1286 bool join(
const BasicBlock &BB,
const SmallPtrSet<BasicBlock *, 16> &Visited);
1306 static LocKind joinKind(LocKind
A, LocKind
B);
1307 static Assignment joinAssignment(
const Assignment &
A,
const Assignment &
B);
1308 BlockInfo joinBlockInfo(
const BlockInfo &
A,
const BlockInfo &
B);
1314 void process(BasicBlock &BB, BlockInfo *LiveSet);
1319 void processNonDbgInstruction(Instruction &
I, BlockInfo *LiveSet);
1322 void processTaggedInstruction(Instruction &
I, BlockInfo *LiveSet);
1325 void processUntaggedInstruction(Instruction &
I, BlockInfo *LiveSet);
1326 void processUnknownStoreToVariable(Instruction &
I,
VariableID &Var,
1327 BlockInfo *LiveSet);
1328 void processEscapingCall(Instruction &
I, BlockInfo *LiveSet);
1329 void processDbgAssign(DbgVariableRecord *Assign, BlockInfo *LiveSet);
1330 void processDbgVariableRecord(DbgVariableRecord &DVR, BlockInfo *LiveSet);
1331 void processDbgValue(DbgVariableRecord *DbgValue, BlockInfo *LiveSet);
1333 void addMemDef(BlockInfo *LiveSet,
VariableID Var,
const Assignment &AV);
1335 void addDbgDef(BlockInfo *LiveSet,
VariableID Var,
const Assignment &AV);
1339 void setLocKind(BlockInfo *LiveSet,
VariableID Var, LocKind K);
1342 LocKind getLocKind(BlockInfo *LiveSet,
VariableID Var);
1344 bool hasVarWithAssignment(BlockInfo *LiveSet, BlockInfo::AssignmentKind Kind,
1355 bool emitPromotedVarLocs(FunctionVarLocsBuilder *FnVarLocs);
1358 AssignmentTrackingLowering(Function &Fn,
const DataLayout &Layout,
1359 const DenseSet<DebugAggregate> *VarsWithStackSlot)
1360 : Fn(Fn), Layout(Layout), VarsWithStackSlot(VarsWithStackSlot) {}
1363 bool run(FunctionVarLocsBuilder *FnVarLocs);
1368AssignmentTrackingLowering::getContainedFragments(
VariableID Var)
const {
1369 auto R = VarContains.find(Var);
1370 if (R == VarContains.end())
1375void AssignmentTrackingLowering::touchFragment(
VariableID Var) {
1376 VarsTouchedThisFrame.insert(Var);
1379void AssignmentTrackingLowering::setLocKind(BlockInfo *LiveSet,
VariableID Var,
1381 auto SetKind = [
this](BlockInfo *LiveSet,
VariableID Var, LocKind
K) {
1382 LiveSet->setLocKind(Var, K);
1385 SetKind(LiveSet, Var, K);
1388 for (
VariableID Frag : getContainedFragments(Var))
1389 SetKind(LiveSet, Frag, K);
1392AssignmentTrackingLowering::LocKind
1393AssignmentTrackingLowering::getLocKind(BlockInfo *LiveSet,
VariableID Var) {
1394 return LiveSet->getLocKind(Var);
1397void AssignmentTrackingLowering::addMemDef(BlockInfo *LiveSet,
VariableID Var,
1398 const Assignment &AV) {
1399 LiveSet->setAssignment(BlockInfo::Stack, Var, AV);
1404 Assignment FragAV = AV;
1405 FragAV.Source =
nullptr;
1406 for (
VariableID Frag : getContainedFragments(Var))
1407 LiveSet->setAssignment(BlockInfo::Stack, Frag, FragAV);
1410void AssignmentTrackingLowering::addDbgDef(BlockInfo *LiveSet,
VariableID Var,
1411 const Assignment &AV) {
1412 LiveSet->setAssignment(BlockInfo::Debug, Var, AV);
1417 Assignment FragAV = AV;
1418 FragAV.Source =
nullptr;
1419 for (
VariableID Frag : getContainedFragments(Var))
1420 LiveSet->setAssignment(BlockInfo::Debug, Frag, FragAV);
1429 "Cannot get a DIAssignID from a non-assign DbgVariableRecord!");
1434bool AssignmentTrackingLowering::hasVarWithAssignment(
1435 BlockInfo *LiveSet, BlockInfo::AssignmentKind Kind,
VariableID Var,
1436 const Assignment &AV) {
1437 if (!LiveSet->hasAssignment(Kind, Var, AV))
1442 for (
VariableID Frag : getContainedFragments(Var))
1443 if (!LiveSet->hasAssignment(Kind, Frag, AV))
1449const char *
locStr(AssignmentTrackingLowering::LocKind
Loc) {
1450 using LocKind = AssignmentTrackingLowering::LocKind;
1471 if (!
Next->hasDbgRecords())
1473 return &*
Next->getDbgRecordRange().begin();
1481void AssignmentTrackingLowering::emitDbgValue(
1494 assert(InsertBefore &&
"Shouldn't be inserting after a terminator");
1503 InsertBeforeMap[InsertBefore].
push_back(VarLoc);
1507 if (Kind == LocKind::Mem) {
1512 if (
Assign->isKillAddress()) {
1514 Kind = LocKind::Val;
1519 "fragment info should be stored in value-expression only");
1522 if (
auto OptFragInfo =
Source->getExpression()->getFragmentInfo()) {
1523 auto FragInfo = *OptFragInfo;
1525 Expr, FragInfo.OffsetInBits, FragInfo.SizeInBits);
1528 std::tie(Val, Expr) =
1535 if (Kind == LocKind::Val) {
1536 Emit(
Source->getRawLocation(),
Source->getExpression());
1540 if (Kind == LocKind::None) {
1541 Emit(
nullptr,
Source->getExpression());
1546void AssignmentTrackingLowering::processNonDbgInstruction(
1547 Instruction &
I, AssignmentTrackingLowering::BlockInfo *LiveSet) {
1548 if (
I.hasMetadata(LLVMContext::MD_DIAssignID))
1549 processTaggedInstruction(
I, LiveSet);
1551 processUntaggedInstruction(
I, LiveSet);
1556 processEscapingCall(
I, LiveSet);
1559void AssignmentTrackingLowering::processUnknownStoreToVariable(
1563 addMemDef(LiveSet, Var, Assignment::makeNoneOrPhi());
1566 if (getLocKind(LiveSet, Var) != LocKind::Mem)
1570 Assignment DbgAV = LiveSet->getAssignment(BlockInfo::Debug, Var);
1571 if (DbgAV.Status != Assignment::NoneOrPhi && DbgAV.Source) {
1573 DbgAV.dump(
dbgs());
dbgs() <<
"\n");
1574 setLocKind(LiveSet, Var, LocKind::Val);
1575 emitDbgValue(LocKind::Val, DbgAV.Source, &
I);
1581 assert(InsertBefore &&
"Shouldn't be inserting after a terminator");
1587 Fn.
getContext(), 0, 0,
V.getVariable()->getScope(), InlinedAt);
1595 InsertBeforeMap[InsertBefore].push_back(VarLoc);
1598void AssignmentTrackingLowering::processUntaggedInstruction(
1599 Instruction &
I, AssignmentTrackingLowering::BlockInfo *LiveSet) {
1611 assert(!
I.hasMetadata(LLVMContext::MD_DIAssignID));
1612 auto It = UntaggedStoreVars.find(&
I);
1613 if (It == UntaggedStoreVars.end()) {
1620 if (
auto UnhandledStoreIt = UnknownStoreVars.find(&
I);
1621 UnhandledStoreIt != UnknownStoreVars.end()) {
1622 LLVM_DEBUG(
dbgs() <<
"Processing untagged unknown store " <<
I <<
"\n");
1623 for (
auto &Var : UnhandledStoreIt->second)
1624 processUnknownStoreToVariable(
I, Var, LiveSet);
1629 LLVM_DEBUG(
dbgs() <<
"processUntaggedInstruction on UNTAGGED INST " <<
I
1633 for (
auto [Var, Info] : It->second) {
1637 addMemDef(LiveSet, Var, Assignment::makeNoneOrPhi());
1638 addDbgDef(LiveSet, Var, Assignment::makeNoneOrPhi());
1639 setLocKind(LiveSet, Var, LocKind::Mem);
1647 if (
auto Frag =
V.getFragment()) {
1650 assert(R &&
"unexpected createFragmentExpression failure");
1654 if (
Info.OffsetInBits)
1655 Ops = {dwarf::DW_OP_plus_uconst,
Info.OffsetInBits / 8};
1662 assert(InsertBefore &&
"Shouldn't be inserting after a terminator");
1667 Fn.
getContext(), 0, 0,
V.getVariable()->getScope(), InlinedAt);
1676 InsertBeforeMap[InsertBefore].push_back(VarLoc);
1680void AssignmentTrackingLowering::processEscapingCall(
1681 Instruction &
I, AssignmentTrackingLowering::BlockInfo *LiveSet) {
1682 auto It = EscapingCallVars.find(&
I);
1683 if (It == EscapingCallVars.end())
1690 for (
auto &[Var, Addr, AddrExpr] : It->second) {
1696 addMemDef(LiveSet, Var, Assignment::makeNoneOrPhi());
1697 addDbgDef(LiveSet, Var, Assignment::makeNoneOrPhi());
1698 setLocKind(LiveSet, Var, LocKind::Mem);
1702 <<
", setting LocKind to Mem\n");
1709 if (
auto Frag =
V.getFragment()) {
1712 assert(R &&
"unexpected createFragmentExpression failure");
1720 assert(InsertBefore &&
"Shouldn't be inserting after a terminator");
1724 Fn.
getContext(), 0, 0,
V.getVariable()->getScope(), InlinedAt);
1732 InsertBeforeMap[InsertBefore].push_back(VarLoc);
1736void AssignmentTrackingLowering::processTaggedInstruction(
1737 Instruction &
I, AssignmentTrackingLowering::BlockInfo *LiveSet) {
1743 if (LinkedDPAssigns.empty())
1752 "expected Assign's variable to have stack slot");
1755 addMemDef(LiveSet, Var, AV);
1763 if (hasVarWithAssignment(LiveSet, BlockInfo::Debug, Var, AV)) {
1769 LiveSet->DebugValue[
static_cast<unsigned>(Var)].dump(
dbgs());
1771 setLocKind(LiveSet, Var, LocKind::Mem);
1772 emitDbgValue(LocKind::Mem, Assign, &
I);
1781 LocKind PrevLoc = getLocKind(LiveSet, Var);
1783 case LocKind::Val: {
1787 setLocKind(LiveSet, Var, LocKind::Val);
1789 case LocKind::Mem: {
1793 Assignment DbgAV = LiveSet->getAssignment(BlockInfo::Debug, Var);
1794 if (DbgAV.Status == Assignment::NoneOrPhi) {
1797 setLocKind(LiveSet, Var, LocKind::None);
1798 emitDbgValue(LocKind::None, Assign, &
I);
1802 setLocKind(LiveSet, Var, LocKind::Val);
1804 emitDbgValue(LocKind::Val, DbgAV.Source, &
I);
1807 emitDbgValue(LocKind::None, Assign, &
I);
1811 case LocKind::None: {
1815 setLocKind(LiveSet, Var, LocKind::None);
1822 BlockInfo *LiveSet) {
1829 Assignment AV = Assignment::make(
getIDFromMarker(*DbgAssign), DbgAssign);
1830 addDbgDef(LiveSet, Var, AV);
1832 LLVM_DEBUG(
dbgs() <<
"processDbgAssign on " << *DbgAssign <<
"\n";);
1838 if (hasVarWithAssignment(LiveSet, BlockInfo::Stack, Var, AV)) {
1846 <<
"Val, Stack matches Debug program but address is killed\n";);
1847 Kind = LocKind::Val;
1850 Kind = LocKind::Mem;
1852 setLocKind(LiveSet, Var, Kind);
1853 emitDbgValue(Kind, DbgAssign, DbgAssign);
1858 setLocKind(LiveSet, Var, LocKind::Val);
1859 emitDbgValue(LocKind::Val, DbgAssign, DbgAssign);
1864 BlockInfo *LiveSet) {
1877 Assignment AV = Assignment::makeNoneOrPhi();
1878 addDbgDef(LiveSet, Var, AV);
1882 <<
" -> Val, dbg.value override");
1884 setLocKind(LiveSet, Var, LocKind::Val);
1889 if (
auto F =
DbgValue.getExpression()->getFragmentInfo())
1890 return F->SizeInBits == 0;
1894void AssignmentTrackingLowering::processDbgVariableRecord(
1901 processDbgAssign(&DVR, LiveSet);
1903 processDbgValue(&DVR, LiveSet);
1906void AssignmentTrackingLowering::resetInsertionPoint(
Instruction &After) {
1909 if (R == InsertBeforeMap.end())
1915 if (R == InsertBeforeMap.end())
1920void AssignmentTrackingLowering::process(
BasicBlock &BB, BlockInfo *LiveSet) {
1923 bool ProcessedLeadingDbgRecords = !BB.
begin()->hasDbgRecords();
1925 assert(VarsTouchedThisFrame.empty());
1932 if (ProcessedLeadingDbgRecords) {
1937 if (
II->isTerminator())
1939 resetInsertionPoint(*
II);
1940 processNonDbgInstruction(*
II, LiveSet);
1941 assert(LiveSet->isValid());
1947 if (
II != EI &&
II->hasDbgRecords()) {
1952 resetInsertionPoint(DVR);
1953 processDbgVariableRecord(DVR, LiveSet);
1954 assert(LiveSet->isValid());
1957 ProcessedLeadingDbgRecords =
true;
1965 for (
auto Var : VarsTouchedThisFrame) {
1966 LocKind
Loc = getLocKind(LiveSet, Var);
1974 if (
Loc != LocKind::Mem) {
1977 NotAlwaysStackHomed.insert(Aggr);
1980 VarsTouchedThisFrame.clear();
1984AssignmentTrackingLowering::LocKind
1985AssignmentTrackingLowering::joinKind(LocKind
A, LocKind
B) {
1988 return A ==
B ?
A : LocKind::None;
1991AssignmentTrackingLowering::Assignment
1992AssignmentTrackingLowering::joinAssignment(
const Assignment &
A,
1993 const Assignment &
B) {
2000 if (!
A.isSameSourceAssignment(
B))
2001 return Assignment::makeNoneOrPhi();
2002 if (
A.Status == Assignment::NoneOrPhi)
2003 return Assignment::makeNoneOrPhi();
2019 if (
A.Source ==
B.Source)
2021 if (!
A.Source || !
B.Source)
2023 if (
A.Source->isEquivalentTo(*
B.Source))
2028 assert(
A.Status ==
B.Status &&
A.Status == Assignment::Known);
2030 return Assignment::make(
A.ID, Source);
2033AssignmentTrackingLowering::BlockInfo
2034AssignmentTrackingLowering::joinBlockInfo(
const BlockInfo &
A,
2035 const BlockInfo &
B) {
2036 return BlockInfo::join(
A,
B, TrackedVariablesVectorSize);
2039bool AssignmentTrackingLowering::join(
2051 if (Visited.
count(Pred))
2056 if (VisitedPreds.
empty()) {
2058 bool DidInsert = It.second;
2060 It.first->second.init(TrackedVariablesVectorSize);
2065 if (VisitedPreds.
size() == 1) {
2066 const BlockInfo &PredLiveOut = LiveOut.
find(VisitedPreds[0])->second;
2073 if (PredLiveOut != CurrentLiveInEntry->second) {
2074 CurrentLiveInEntry->second = PredLiveOut;
2082 const BlockInfo &PredLiveOut0 = LiveOut.
find(VisitedPreds[0])->second;
2083 const BlockInfo &PredLiveOut1 = LiveOut.
find(VisitedPreds[1])->second;
2084 BlockInfo BBLiveIn = joinBlockInfo(PredLiveOut0, PredLiveOut1);
2089 const auto &PredLiveOut = LiveOut.
find(Pred);
2091 "block should have been processed already");
2092 BBLiveIn = joinBlockInfo(std::move(BBLiveIn), PredLiveOut->second);
2096 auto CurrentLiveInEntry = LiveIn.
find(&BB);
2099 if (CurrentLiveInEntry == LiveIn.
end())
2101 else if (BBLiveIn != CurrentLiveInEntry->second)
2102 CurrentLiveInEntry->second = std::move(BBLiveIn);
2111 auto ALeft =
A.OffsetInBits;
2112 auto BLeft =
B.OffsetInBits;
2116 auto ARight = ALeft +
A.SizeInBits;
2117 auto BRight = BLeft +
B.SizeInBits;
2118 if (BRight > ARight)
2123static std::optional<at::AssignmentInfo>
2133 return std::nullopt;
2141 if (
ID != Intrinsic::experimental_vp_strided_store &&
2142 ID != Intrinsic::masked_store &&
ID != Intrinsic::vp_scatter &&
2143 ID != Intrinsic::masked_scatter &&
ID != Intrinsic::vp_store &&
2144 ID != Intrinsic::masked_compressstore)
2180 AssignmentTrackingLowering::UntaggedStoreAssignmentMap &UntaggedStoreVars,
2181 AssignmentTrackingLowering::UnknownStoreAssignmentMap &UnknownStoreVars,
2182 AssignmentTrackingLowering::EscapingCallVarsMap &EscapingCallVars,
2183 unsigned &TrackedVariablesVectorSize) {
2197 if (
Record->isDbgDeclare()) {
2203 if (!VarsWithStackSlot.
contains(DA))
2205 if (Seen.
insert(DV).second)
2206 FragmentMap[DA].push_back(DV);
2208 for (
auto &BB : Fn) {
2209 for (
auto &
I : BB) {
2211 ProcessDbgRecord(&DVR);
2215 std::optional<DIExpression::FragmentInfo> FragInfo;
2220 I.getDataLayout(), Info->Base,
2221 Info->OffsetInBits, Info->SizeInBits, Assign, FragInfo) ||
2222 (FragInfo && FragInfo->SizeInBits == 0))
2231 FragInfo = Assign->getExpression()->getFragmentInfo();
2235 Assign->getDebugLoc().getInlinedAt());
2237 if (!VarsWithStackSlot.
contains(DA))
2241 UntaggedStoreVars[&
I].push_back(
2244 if (Seen.
insert(DV).second)
2245 FragmentMap[DA].push_back(DV);
2248 HandleDbgAssignForStore(DVR);
2256 Assign->getDebugLoc().getInlinedAt());
2258 if (!VarsWithStackSlot.
contains(DA))
2265 HandleDbgAssignForUnknownStore(DVR);
2278 if (CB->onlyReadsMemory())
2282 for (
unsigned ArgIdx = 0; ArgIdx < CB->arg_size(); ++ArgIdx) {
2283 Value *Arg = CB->getArgOperand(ArgIdx);
2287 if (CB->paramHasAttr(ArgIdx, Attribute::ReadOnly) ||
2288 CB->paramHasAttr(ArgIdx, Attribute::ReadNone))
2291 if (CB->paramHasAttr(ArgIdx, Attribute::ByVal))
2306 if (!VarsWithStackSlot.
contains(DA))
2310 EscapingCallVars[&
I].push_back(
2319 for (
auto &Pair : FragmentMap) {
2321 std::sort(Frags.
begin(), Frags.
end(),
2323 return Elmt.getFragmentOrDefault().SizeInBits >
2324 Next.getFragmentOrDefault().SizeInBits;
2331 AssignmentTrackingLowering::OverlapMap Map;
2332 for (
auto &Pair : FragmentMap) {
2333 auto &Frags = Pair.second;
2334 for (
auto It = Frags.begin(), IEnd = Frags.end(); It != IEnd; ++It) {
2344 for (; OtherIt != IEnd; ++OtherIt) {
2348 Map[OtherVar].push_back(ThisVar);
2359 for (
auto *DVR : DPDeclares)
2366bool AssignmentTrackingLowering::run(FunctionVarLocsBuilder *FnVarLocsBuilder) {
2369 <<
": too many blocks (" << Fn.
size() <<
")\n");
2374 FnVarLocs = FnVarLocsBuilder;
2384 Fn, FnVarLocs, *VarsWithStackSlot, UntaggedStoreVars, UnknownStoreVars,
2385 EscapingCallVars, TrackedVariablesVectorSize);
2389 std::priority_queue<unsigned int, std::vector<unsigned int>,
2390 std::greater<unsigned int>>
2392 std::priority_queue<unsigned int, std::vector<unsigned int>,
2393 std::greater<unsigned int>>
2398 unsigned int RPONumber = 0;
2400 OrderToBB[RPONumber] = BB;
2401 BBToOrder[BB] = RPONumber;
2402 Worklist.push(RPONumber);
2420 while (!Worklist.empty()) {
2425 while (!Worklist.empty()) {
2429 bool InChanged =
join(*BB, Visited);
2431 InChanged |= Visited.
insert(BB).second;
2436 BlockInfo LiveSet = LiveIn[BB];
2439 process(*BB, &LiveSet);
2442 if (LiveOut[BB] != LiveSet) {
2444 <<
" has new OutLocs, add succs to worklist: [ ");
2445 LiveOut[BB] = std::move(LiveSet);
2447 if (OnPending.
insert(Succ).second) {
2449 Pending.push(BBToOrder[Succ]);
2456 Worklist.swap(Pending);
2459 assert(Pending.empty() &&
"Pending should be empty");
2465 bool InsertedAnyIntrinsics =
false;
2474 for (
const auto &Pair : InsertBeforeMap) {
2475 auto &Vec = Pair.second;
2481 if (NotAlwaysStackHomed.contains(Aggr))
2491 NotAlwaysStackHomed.insert(Aggr);
2500 if (AlwaysStackHomed.
insert(Aggr).second) {
2509 InsertedAnyIntrinsics =
true;
2515 for (
const auto &[InsertBefore, Vec] : InsertBeforeMap) {
2522 if (AlwaysStackHomed.
contains(Aggr))
2525 InsertedAnyIntrinsics =
true;
2528 FnVarLocs->
setWedge(InsertBefore, std::move(NewDefs));
2531 InsertedAnyIntrinsics |= emitPromotedVarLocs(FnVarLocs);
2533 return InsertedAnyIntrinsics;
2536bool AssignmentTrackingLowering::emitPromotedVarLocs(
2537 FunctionVarLocsBuilder *FnVarLocs) {
2538 bool InsertedAnyIntrinsics =
false;
2547 assert(InsertBefore &&
"Unexpected: debug intrinsics after a terminator");
2551 InsertedAnyIntrinsics =
true;
2553 for (
auto &BB : Fn) {
2554 for (
auto &
I : BB) {
2558 TranslateDbgRecord(&DVR);
2561 return InsertedAnyIntrinsics;
2581 VariableDefinedBytes.
clear();
2583 auto HandleLocsForWedge = [&](
auto *WedgePosition) {
2585 const auto *Locs = FnVarLocs.
getWedge(WedgePosition);
2590 bool ChangedThisWedge =
false;
2595 for (
auto RIt = Locs->rbegin(), REnd = Locs->rend(); RIt != REnd; ++RIt) {
2599 uint64_t SizeInBits = Aggr.first->getSizeInBits().value_or(0);
2603 const uint64_t MaxSizeBytes = 2048;
2605 if (SizeInBytes == 0 || SizeInBytes > MaxSizeBytes) {
2619 bool FirstDefinition = InsertResult.second;
2620 BitVector &DefinedBytes = InsertResult.first->second;
2623 RIt->Expr->getFragmentInfo().value_or(
2625 bool InvalidFragment = Fragment.endInBits() > SizeInBits;
2626 uint64_t StartInBytes = Fragment.startInBits() / 8;
2630 if (FirstDefinition || InvalidFragment ||
2632 if (!InvalidFragment)
2633 DefinedBytes.
set(StartInBytes, EndInBytes);
2640 ChangedThisWedge =
true;
2645 if (ChangedThisWedge) {
2646 std::reverse(NewDefsReversed.
begin(), NewDefsReversed.
end());
2647 FnVarLocs.
setWedge(WedgePosition, std::move(NewDefsReversed));
2652 HandleLocsForWedge(&
I);
2654 HandleLocsForWedge(&DVR);
2679 auto HandleLocsForWedge = [&](
auto *WedgePosition) {
2680 const auto *Locs = FnVarLocs.
getWedge(WedgePosition);
2685 bool ChangedThisWedge =
false;
2693 std::nullopt,
Loc.DL.getInlinedAt());
2698 if (Inserted || VMI->second.first !=
Loc.Values ||
2699 VMI->second.second !=
Loc.Expr) {
2700 VMI->second = {
Loc.Values,
Loc.Expr};
2706 ChangedThisWedge =
true;
2711 if (ChangedThisWedge) {
2712 FnVarLocs.
setWedge(WedgePosition, std::move(NewDefs));
2719 HandleLocsForWedge(&DVR);
2720 HandleLocsForWedge(&
I);
2745 VarsWithDef[
A].
insert(V.getFragmentOrDefault());
2751 auto FragsIt = VarsWithDef.
find(
A);
2752 if (FragsIt == VarsWithDef.
end())
2755 return DIExpression::fragmentsOverlap(Frag, V.getFragmentOrDefault());
2766 auto HandleLocsForWedge = [&](
auto *WedgePosition) {
2767 const auto *Locs = FnVarLocs.
getWedge(WedgePosition);
2772 bool ChangedThisWedge =
false;
2780 Loc.DL.getInlinedAt()};
2785 if (
Loc.Values.isKillLocation(
Loc.Expr) && !HasDefinedBits(Aggr, Var)) {
2788 ChangedThisWedge =
true;
2792 DefineBits(Aggr, Var);
2797 if (ChangedThisWedge) {
2798 FnVarLocs.
setWedge(WedgePosition, std::move(NewDefs));
2804 HandleLocsForWedge(&DVR);
2805 HandleLocsForWedge(&
I);
2813 bool MadeChanges =
false;
2827 for (
auto &BB : Fn) {
2828 for (
auto &
I : BB) {
2854 AssignmentTrackingLowering
Pass(Fn, Layout, &VarsWithStackSlot);
2859 MemLocFragmentFill
Pass(Fn, &VarsWithStackSlot,
2861 Pass.run(FnVarLocs);
2878 auto &
DL =
F.getDataLayout();
2902 LLVM_DEBUG(
dbgs() <<
"AssignmentTrackingAnalysis run on " <<
F.getName()
2912 Results->init(Builder);
2915 Results->print(
errs(),
F);
2927 "Assignment Tracking Analysis",
false,
true)
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
Function Alias Analysis Results
std::pair< const DILocalVariable *, const DILocation * > DebugAggregate
A whole (unfragmented) source variable.
VarLocInsertPt getNextNode(const DbgRecord *DVR)
static void analyzeFunction(Function &Fn, const DataLayout &Layout, FunctionVarLocsBuilder *FnVarLocs)
static std::pair< Value *, DIExpression * > walkToAllocaAndPrependOffsetDeref(const DataLayout &DL, Value *Start, DIExpression *Expression)
Walk backwards along constant GEPs and bitcasts to the base storage from Start as far as possible.
static DenseSet< DebugAggregate > findVarsWithStackSlot(Function &Fn)
static bool fullyContains(DIExpression::FragmentInfo A, DIExpression::FragmentInfo B)
Return true if A fully contains B.
static std::optional< at::AssignmentInfo > getUntaggedStoreAssignmentInfo(const Instruction &I, const DataLayout &Layout)
static bool removeUndefDbgLocsFromEntryBlock(const BasicBlock *BB, FunctionVarLocsBuilder &FnVarLocs)
static cl::opt< bool > PrintResults("print-debug-ata", cl::init(false), cl::Hidden)
Print the results of the analysis. Respects -filter-print-funcs.
const char * locStr(AssignmentTrackingLowering::LocKind Loc)
PointerUnion< const Instruction *, const DbgRecord * > VarLocInsertPt
static bool removeRedundantDbgLocsUsingForwardScan(const BasicBlock *BB, FunctionVarLocsBuilder &FnVarLocs)
Remove redundant location defs using a forward scan.
static bool removeRedundantDbgLocs(const BasicBlock *BB, FunctionVarLocsBuilder &FnVarLocs)
static cl::opt< bool > EnableMemLocFragFill("mem-loc-frag-fill", cl::init(true), cl::Hidden)
Option for debugging the pass, determines if the memory location fragment filling happens after gener...
static AssignmentTrackingLowering::OverlapMap buildOverlapMapAndRecordDeclares(Function &Fn, FunctionVarLocsBuilder *FnVarLocs, const DenseSet< DebugAggregate > &VarsWithStackSlot, AssignmentTrackingLowering::UntaggedStoreAssignmentMap &UntaggedStoreVars, AssignmentTrackingLowering::UnknownStoreAssignmentMap &UnknownStoreVars, AssignmentTrackingLowering::EscapingCallVarsMap &EscapingCallVars, unsigned &TrackedVariablesVectorSize)
Build a map of {Variable x: Variables y} where all variable fragments contained within the variable f...
static DIAssignID * getIDFromMarker(const DbgVariableRecord &DVR)
static DebugAggregate getAggregate(const DebugVariable &Var)
static bool hasZeroSizedFragment(DbgVariableRecord &DbgValue)
static DIAssignID * getIDFromInst(const Instruction &I)
AllocaInst * getUnknownStore(const Instruction &I, const DataLayout &Layout)
static std::optional< int64_t > getDerefOffsetInBytes(const DIExpression *DIExpr)
Extract the offset used in DIExpr.
static bool removeRedundantDbgLocsUsingBackwardScan(const BasicBlock *BB, FunctionVarLocsBuilder &FnVarLocs)
Remove redundant definitions within sequences of consecutive location defs.
static cl::opt< cl::boolOrDefault > CoalesceAdjacentFragmentsOpt("debug-ata-coalesce-frags", cl::Hidden)
Coalesce adjacent dbg locs describing memory locations that have contiguous fragments.
static cl::opt< unsigned > MaxNumBlocks("debug-ata-max-blocks", cl::init(10000), cl::desc("Maximum num basic blocks before debug info dropped"), cl::Hidden)
static bool shouldCoalesceFragments(Function &F)
This file implements the BitVector class.
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
static ManagedStatic< cl::opt< bool, true >, CreateDebug > Debug
This file defines DenseMapInfo traits for DenseMap.
This file contains constants used for implementing Dwarf debug support.
Module.h This file contains the declarations for the Module class.
This header defines various interfaces for pass management in LLVM.
This file implements a coalescing interval map for small objects.
const AbstractManglingParser< Derived, Alloc >::OperatorInfo AbstractManglingParser< Derived, Alloc >::Ops[]
IntervalMap< SlotIndex, DbgVariableValue, 4 > LocMap
Map of where a user value is live to that value.
print mir2vec MIR2Vec Vocabulary Printer Pass
uint64_t IntrinsicInst * II
FunctionAnalysisManager FAM
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
This file builds on the ADT/GraphTraits.h file to build a generic graph post order iterator.
static bool isValid(const char C)
Returns true if C is a valid mangled character: <0-9a-zA-Z_>.
Scalar Replacement Of Aggregates
This file defines the 'Statistic' class, which is designed to be an easy way to expose various metric...
#define STATISTIC(VARNAME, DESC)
Helper class to build FunctionVarLocs, since that class isn't easy to modify.
void setWedge(VarLocInsertPt Before, SmallVector< VarLocInfo > &&Wedge)
Replace the defs that come just before /p Before with /p Wedge.
const SmallVectorImpl< VarLocInfo > * getWedge(VarLocInsertPt Before) const
Return ptr to wedge of defs or nullptr if no defs come just before /p Before.
unsigned getNumVariables() const
void addSingleLocVar(DebugVariable Var, DIExpression *Expr, DebugLoc DL, RawLocationWrapper R)
Add a def for a variable that is valid for its lifetime.
VariableID insertVariable(DebugVariable V)
Find or insert V and return the ID.
void addVarLoc(VarLocInsertPt Before, DebugVariable Var, DIExpression *Expr, DebugLoc DL, RawLocationWrapper R)
Add a def to the wedge of defs just before /p Before.
const DebugVariable & getVariable(VariableID ID) const
Get a variable from its ID.
Class recording the (high level) value of a variable.
Class for arbitrary precision integers.
uint64_t getZExtValue() const
Get zero extended value.
bool getBoolValue() const
Convert APInt to a boolean value.
an instruction to allocate memory on the stack
Represent a constant reference to an array (0 or more elements consecutively in memory),...
AssignmentTrackingAnalysis()
bool runOnFunction(Function &F) override
runOnFunction - Virtual method overriden by subclasses to do the per-function processing of the pass.
LLVM Basic Block Representation.
iterator begin()
Instruction iterator methods.
LLVM_ABI bool isEntryBlock() const
Return true if this is the entry block of the containing function.
int find_first_unset_in(unsigned Begin, unsigned End) const
Returns the index of the first unset bit in the range [Begin, End).
BitVector & set()
Set all bits in the bitvector.
iterator_range< const_set_bits_iterator > set_bits() const
A structured debug information entry.
static LLVM_ABI DIExpression * append(const DIExpression *Expr, ArrayRef< uint64_t > Ops)
Append the opcodes Ops to DIExpr.
unsigned getNumElements() const
DbgVariableFragmentInfo FragmentInfo
LLVM_ABI bool startsWithDeref() const
Return whether the first element a DW_OP_deref.
static LLVM_ABI std::optional< FragmentInfo > getFragmentInfo(expr_op_iterator Start, expr_op_iterator End)
Retrieve the details of this fragment expression.
ArrayRef< uint64_t > getElements() const
static LLVM_ABI std::optional< DIExpression * > createFragmentExpression(const DIExpression *Expr, unsigned OffsetInBits, unsigned SizeInBits)
Create a DIExpression to describe one part of an aggregate variable that is fragmented across multipl...
static LLVM_ABI DIExpression * prepend(const DIExpression *Expr, uint8_t Flags, int64_t Offset=0)
Prepend DIExpr with a deref and offset operation and optionally turn it into a stack value or/and an ...
static LLVM_ABI DIExpression * prependOpcodes(const DIExpression *Expr, SmallVectorImpl< uint64_t > &Ops, bool StackValue=false, bool EntryValue=false)
Prepend DIExpr with the given opcodes and optionally turn it into a stack value.
LLVM_ABI std::optional< uint64_t > getSizeInBits() const
Determines the size of the variable's type.
StringRef getName() const
A parsed version of the target data layout string in and methods for querying it.
LLVM_ABI unsigned getIndexTypeSizeInBits(Type *Ty) const
The size in bits of the index used in GEP calculation for this type.
Instruction * MarkedInstr
Link back to the Instruction that owns this marker.
LLVM_ABI iterator_range< simple_ilist< DbgRecord >::iterator > getDbgRecordRange()
Produce a range over all the DbgRecords in this Marker.
Base class for non-instruction debug metadata records that have positions within IR.
DebugLoc getDebugLoc() const
Record of a variable value-assignment, aka a non instruction representation of the dbg....
LLVM_ABI Value * getAddress() const
LLVM_ABI bool isKillAddress() const
Check whether this kills the address component.
LLVM_ABI DIAssignID * getAssignID() const
DIExpression * getExpression() const
DILocalVariable * getVariable() const
Metadata * getRawLocation() const
Returns the metadata operand for the first location description.
DIExpression * getAddressExpression() const
LLVM_ABI Result run(Function &F, FunctionAnalysisManager &FAM)
LLVM_ABI PreservedAnalyses run(Function &F, FunctionAnalysisManager &FAM)
LLVM_ABI DILocation * getInlinedAt() const
Identifies a unique instance of a variable.
const DILocation * getInlinedAt() const
const DILocalVariable * getVariable() const
iterator find(const_arg_type_t< KeyT > Val)
std::pair< iterator, bool > try_emplace(KeyT &&Key, Ts &&...Args)
std::pair< iterator, bool > insert(const std::pair< KeyT, ValueT > &KV)
void reserve(size_type NumEntries)
Grow the densemap so that it can contain at least NumEntries items before resizing again.
Implements a dense probed hash-table based set.
Class representing an expression and its matching format.
Data structure describing the variable locations in a function.
LLVM_ABI void print(raw_ostream &OS, const Function &Fn) const
const VarLocInfo * locs_begin(const Instruction *Before) const
First variable location definition that comes before Before.
const VarLocInfo * single_locs_begin() const
const VarLocInfo * locs_end(const Instruction *Before) const
One past the last variable location definition that comes before Before.
const VarLocInfo * single_locs_end() const
One past the last single-location variable location definition.
LLVM_ABI void init(FunctionVarLocsBuilder &Builder)
const DataLayout & getDataLayout() const
Get the data layout of the module this function belongs to.
LLVMContext & getContext() const
getContext - Return a reference to the LLVMContext associated with this function.
bool isTerminator() const
const_iterator begin() const
void insert(KeyT a, KeyT b, ValT y)
insert - Add a mapping of [a;b] to y, coalesce with adjacent intervals.
void clear()
clear - Remove all entries.
static MDTuple * get(LLVMContext &Context, ArrayRef< Metadata * > MDs)
void push_back(MachineInstr *MI)
Pass interface - Implemented by all 'passes'.
A discriminated union of two or more pointer types, with the discriminator in the low bits of the poi...
void * getOpaqueValue() const
static LLVM_ABI PoisonValue * get(Type *T)
Static factory methods - Return an 'poison' object of the specified type.
A set of analyses that are preserved following a run of a transformation pass.
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
Lightweight class that wraps the location operand metadata of a debug intrinsic.
Implements a dense probed hash-table based set with some number of buckets stored inline.
size_type count(ConstPtrType Ptr) const
count - Return 1 if the specified pointer is in the set, 0 otherwise.
std::pair< iterator, bool > insert(PtrType Ptr)
Inserts Ptr if and only if there is no element in the container equal to Ptr.
SmallPtrSet - This class implements a set which is optimized for holding SmallSize or less elements.
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
bool isPointerTy() const
True if this is an instance of PointerType.
static LLVM_ABI IntegerType * getInt1Ty(LLVMContext &C)
UniqueVector - This class produces a sequential ID number (base 1) for each unique entry that is adde...
unsigned insert(const T &Entry)
insert - Append entry to the vector if it doesn't already exist.
LLVM Value Representation.
Type * getType() const
All values are typed, get the type of this value.
LLVM_ABI StringRef getName() const
Return a constant reference to the value's name.
std::pair< iterator, bool > insert(const ValueT &V)
bool contains(const_arg_type_t< ValueT > V) const
Check if the set contains the given element.
size_type count(const_arg_type_t< ValueT > V) const
Return 1 if the specified key is in the set, 0 otherwise.
self_iterator getIterator()
NodeTy * getNextNode()
Get the next node, or nullptr for the list tail.
This class implements an extremely fast bulk output stream that can only output to a stream.
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
DenseMap< FragmentOfVar, SmallVector< DIExpression::FragmentInfo, 1 > > OverlapMap
constexpr std::underlying_type_t< E > Mask()
Get a bitmask with 1s in all places up to the high-order bit of E's largest value.
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
@ Tail
Attemps to make calls as fast as possible while guaranteeing that tail call optimization can always b...
@ BasicBlock
Various leaf nodes.
LLVM_ABI void deleteAll(Function *F)
Remove all Assignment Tracking related intrinsics and metadata from F.
SmallVector< DbgVariableRecord * > getDVRAssignmentMarkers(const Instruction *Inst)
Return a range of dbg_assign records for which Inst performs the assignment they encode.
LLVM_ABI std::optional< AssignmentInfo > getAssignmentInfo(const DataLayout &DL, const MemIntrinsic *I)
LLVM_ABI bool calculateFragmentIntersect(const DataLayout &DL, const Value *Dest, uint64_t SliceOffsetInBits, uint64_t SliceSizeInBits, const DbgVariableRecord *DVRAssign, std::optional< DIExpression::FragmentInfo > &Result)
Calculate the fragment of the variable in DAI covered from (Dest + SliceOffsetInBits) to to (Dest + S...
initializer< Ty > init(const Ty &Val)
@ DW_OP_LLVM_fragment
Only used in LLVM metadata.
DXILDebugInfoMap run(Module &M)
friend class Instruction
Iterator for Instructions in a `BasicBlock.
This is an optimization pass for GlobalISel generic memory operations.
void dump(const SparseBitVector< ElementSize > &LHS, raw_ostream &out)
std::tuple< const DIScope *, const DIScope *, const DILocalVariable * > VarID
A unique key that represents a debug variable.
bool all_of(R &&range, UnaryPredicate P)
Provide wrappers to std::all_of which take ranges instead of having to pass begin/end explicitly.
Printable print(const GCNRegPressure &RP, const GCNSubtarget *ST=nullptr, unsigned DynamicVGPRBlockSize=0)
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
auto successors(const MachineBasicBlock *BB)
bool operator!=(uint64_t V1, const APInt &V2)
bool operator==(const AddressRangeValuePair &LHS, const AddressRangeValuePair &RHS)
bool any_of(R &&range, UnaryPredicate P)
Provide wrappers to std::any_of which take ranges instead of having to pass begin/end explicitly.
auto reverse(ContainerTy &&C)
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
bool isFunctionInPrintList(StringRef FunctionName)
VariableID
Type wrapper for integer ID for Variables. 0 is reserved.
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
bool isa(const From &Val)
isa<X> - Return true if the parameter to the template is an instance of one of the template type argu...
LLVM_ATTRIBUTE_VISIBILITY_DEFAULT AnalysisKey InnerAnalysisManagerProxy< AnalysisManagerT, IRUnitT, ExtraArgTs... >::Key
LLVM_ABI raw_fd_ostream & errs()
This returns a reference to a raw_ostream for standard error.
constexpr T divideCeil(U Numerator, V Denominator)
Returns the integer ceil(Numerator / Denominator).
std::string join(IteratorT Begin, IteratorT End, StringRef Separator)
Joins the strings in the range [Begin, End), adding Separator between the elements.
LLVM_ABI bool isAssignmentTrackingEnabled(const Module &M)
Return true if assignment tracking is enabled for module M.
FunctionAddr VTableAddr Next
DWARFExpression::Operation Op
ArrayRef(const T &OneElt) -> ArrayRef< T >
std::string toString(const APInt &I, unsigned Radix, bool Signed, bool formatAsCLiteral=false, bool UpperCase=true, bool InsertSeparators=false)
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
auto predecessors(const MachineBasicBlock *BB)
AnalysisManager< Function > FunctionAnalysisManager
Convenience typedef for the Function analysis manager.
LLVM_ABI const Value * getUnderlyingObject(const Value *V, unsigned MaxLookup=MaxLookupSearchDepth)
This method strips off any GEP address adjustments, pointer casts or llvm.threadlocal....
static auto filterDbgVars(iterator_range< simple_ilist< DbgRecord >::iterator > R)
Filter the DbgRecord range to DbgVariableRecord types only and downcast.
bool debuginfoShouldUseDebugInstrRef(const Triple &T)
Implement std::hash so that hash_code can be used in STL containers.
A special type used by analysis passes to provide an address that identifies that particular analysis...
static bool isEqual(const VariableID &LHS, const VariableID &RHS)
static unsigned getHashValue(const VariableID &Val)
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