105#include "llvm/Config/llvm-config.h"
137#define DEBUG_TYPE "livedebugvalues"
142 cl::desc(
"Act like old LiveDebugValues did"),
156 cl::desc(
"livedebugvalues-stack-ws-limit"),
305 unsigned Location : 24;
306 unsigned Quality : 8;
311 : Location(L.asU64()), Quality(static_cast<
unsigned>(Q)) {}
326 return A.first <
B.first;
331 std::optional<LocationQuality>
361 bool IsValueValid =
true;
362 unsigned LastUseBeforeDef = 0;
378 IsValueValid =
false;
390 auto ValuesPreferredLoc = std::lower_bound(
394 assert(ValuesPreferredLoc != ValueToLoc.
end() &&
395 ValuesPreferredLoc->first == Num);
397 if (ValuesPreferredLoc->second.isIllegal()) {
403 LastUseBeforeDef = std::max(LastUseBeforeDef,
404 static_cast<unsigned>(Num.
getInst()));
408 IsValueValid =
false;
414 LocIdx M = ValuesPreferredLoc->second.getLoc();
424 if (LastUseBeforeDef) {
435 auto Result =
ActiveVLocs.insert(std::make_pair(VarID, NewValue));
437 Result.first->second = NewValue;
467 for (
const auto &VLoc : VLocs)
469 for (
DbgOpID OpID : VLoc.second.getDbgOpIDs())
470 if (!OpID.ID.IsConst)
490 auto VIt = std::lower_bound(ValueToLoc.
begin(), ValueToLoc.
end(), Probe,
492 if (VIt == ValueToLoc.
end() || VIt->first != VNum)
495 auto &Previous = VIt->second;
498 std::optional<LocationQuality> ReplacementQuality =
500 if (ReplacementQuality)
505 for (
const auto &Var : VLocs) {
535 for (
auto &
Use : MIt->second) {
540 assert(!
Op.isUndef() &&
"UseBeforeDef erroneously created for a "
541 "DbgValue with undef values.");
550 if (ValueToLoc.
empty())
559 auto VIt = ValueToLoc.
find(LocValueID);
560 if (VIt == ValueToLoc.
end())
563 auto &Previous = VIt->second;
566 std::optional<LocationQuality> ReplacementQuality =
568 if (ReplacementQuality)
574 for (
auto &
Use : MIt->second) {
585 LocIdx NewLoc = ValueToLoc.
find(
Op.ID)->second.getLoc();
594 if (DbgOps.
size() !=
Use.Values.size())
647 return Reg != SP && Reg !=
FP;
664 auto NonVariadicExpression =
666 if (!NonVariadicExpression)
668 DIExpr = *NonVariadicExpression;
694 MI.getDebugLoc()->getInlinedAt());
699 if (
MI.isUndefDebugValue() ||
704 for (
LocIdx Loc : It->second.loc_indices())
734 MI.getDebugLoc()->getInlinedAt());
742 for (
LocIdx Loc : It->second.loc_indices())
747 if (NewLocs.
empty()) {
767 for (
LocIdx Loc : LostVLocIt->second.loc_indices()) {
777 for (
const auto &LostMLoc : LostMLocs)
792 It->second.Ops.assign(NewLocs);
793 It->second.Properties = Properties;
802 bool MakeUndef =
true) {
824 std::optional<LocIdx> NewLoc;
826 if (Loc.Value == OldValue)
831 if (!NewLoc && !MakeUndef) {
834 auto &Prop =
ActiveVLocs.find(VarID)->second.Properties;
861 DbgOps.
insert(DbgOps.
begin(), ActiveVLocIt->second.Ops.size(),
873 for (
LocIdx Loc : ActiveVLocIt->second.loc_indices()) {
879 ActiveVLocIt->second.Ops = DbgOps;
886 for (
auto &LocVarIt : LostMLocs) {
889 "Variable was using this MLoc, but ActiveMLocs[MLoc] has no "
891 LostMLocIt->second.erase(LocVarIt.second);
897 VarLocs[NewLoc->asU64()] = OldValue;
902 ActiveMLocIt->second.clear();
903 if (!NewMLocs.
empty())
933 std::replace(ActiveVLocIt->second.Ops.begin(),
934 ActiveVLocIt->second.Ops.end(),
SrcOp,
DstOp);
938 ActiveVLocIt->second.Properties);
963 MIB.addMetadata(Properties.
DIExpr);
1024 LocIdxToIDNum(
ValueIDNum::EmptyValue), LocIdxToLocID(0) {
1062 if (
Size > 60000 || Offs > 60000)
1098 if (MaskPair.first->clobbersPhysReg(
ID)) {
1100 ValNum = {
CurBB, MaskPair.second, NewIdx};
1121 Masks.push_back(std::make_pair(MO, InstID));
1127 if (SpillID.
id() == 0) {
1131 return std::nullopt;
1136 for (
unsigned StackIdx = 0; StackIdx <
NumSlotIdxes; ++StackIdx) {
1157 return Twine(
"slot ")
1174 std::string MLocName =
LocIdxToName(Location.Value.getLoc());
1175 std::string DefName = Location.Value.asString(MLocName);
1183 dbgs() <<
"Idx " << Location.Idx.asU64() <<
" " << foo <<
"\n";
1195 ?
TII.
get(TargetOpcode::DBG_VALUE_LIST)
1196 :
TII.
get(TargetOpcode::DBG_VALUE);
1198#ifdef EXPENSIVE_CHECKS
1201 return Op.IsConst || !
Op.Loc.isIllegal();
1203 "Did not expect illegal ops in DbgOps.");
1206 "Expected to have either one DbgOp per MI LocationOp, or none.");
1219 auto EmitUndef = [&]() {
1231 bool Indirect = Properties.
Indirect;
1253 unsigned short Offset = StackIdx.second;
1264 unsigned Base = Spill.SpillBase;
1280 bool UseDerefSize =
false;
1282 unsigned DerefSizeInBytes = ValueSizeInBits / 8;
1284 unsigned VariableSizeInBits = Fragment->SizeInBits;
1285 if (VariableSizeInBits != ValueSizeInBits || Expr->
isComplex())
1286 UseDerefSize =
true;
1288 if (*
Size != ValueSizeInBits) {
1289 UseDerefSize =
true;
1295 bool StackValue =
false;
1302 OffsetOps.
push_back(dwarf::DW_OP_deref);
1309 OffsetOps.
push_back(dwarf::DW_OP_deref_size);
1315 OffsetOps.
push_back(dwarf::DW_OP_deref);
1348 if (CalleeSavedRegs.
test(*RAI))
1362std::optional<SpillLocationNo>
1363InstrRefBasedLDV::extractSpillBaseRegAndOffset(
const MachineInstr &
MI) {
1365 "Spill instruction does not have exactly one memory operand?");
1366 auto MMOI =
MI.memoperands_begin();
1369 "Inconsistent memory operand in spill instruction");
1370 int FI = cast<FixedStackPseudoSourceValue>(PVal)->getFrameIndex();
1377std::optional<LocIdx>
1379 std::optional<SpillLocationNo>
SpillLoc = extractSpillBaseRegAndOffset(
MI);
1381 return std::nullopt;
1387 auto *MemOperand = *
MI.memoperands_begin();
1389 assert(SizeInBits.
hasValue() &&
"Expected to find a valid size!");
1396 return std::nullopt;
1404bool InstrRefBasedLDV::transferDebugValue(
const MachineInstr &
MI) {
1405 if (!
MI.isDebugValue())
1408 assert(
MI.getDebugVariable()->isValidLocationForIntrinsic(
MI.getDebugLoc()) &&
1409 "Expected inlined-at fields to agree");
1414 if (Scope ==
nullptr)
1420 if (MO.isReg() && MO.getReg() != 0)
1421 (void)MTracker->
readReg(MO.getReg());
1430 if (!
MI.isUndefDebugValue()) {
1436 }
else if (MO.isImm() || MO.isFPImm() || MO.isCImm()) {
1453std::optional<ValueIDNum> InstrRefBasedLDV::getValueForInstrRef(
1469 LowerBoundIt->Src == SoughtSub.Src) {
1470 std::tie(InstNo, OpNo) = LowerBoundIt->Dest;
1471 SoughtSub.Src = LowerBoundIt->Dest;
1472 if (
unsigned Subreg = LowerBoundIt->Subreg)
1473 SeenSubregs.push_back(Subreg);
1479 std::optional<ValueIDNum> NewID;
1483 auto InstrIt = DebugInstrNumToInstr.find(InstNo);
1485 if (InstrIt != DebugInstrNumToInstr.end()) {
1486 const MachineInstr &TargetInstr = *InstrIt->second.first;
1495 NewID =
ValueIDNum(BlockNo, InstrIt->second.second, *L);
1508 NewID =
ValueIDNum(BlockNo, InstrIt->second.second, L);
1514 {
dbgs() <<
"Seen instruction reference to illegal operand\n"; });
1518 }
else if (PHIIt != DebugPHINumToValue.
end() && PHIIt->InstrNum == InstNo) {
1521 assert(MLiveOuts && MLiveIns);
1522 NewID = resolveDbgPHIs(*
MI.getParent()->getParent(), *MLiveOuts, *MLiveIns,
1535 if (NewID && !SeenSubregs.empty()) {
1543 for (
unsigned Subreg :
reverse(SeenSubregs)) {
1547 Size = (
Size == 0) ? ThisSize : std::min(
Size, ThisSize);
1555 if (NewID && !MTracker->
isSpill(L)) {
1561 if (TRCI->contains(Reg))
1563 assert(TRC &&
"Couldn't find target register class?");
1575 if (SubregSize ==
Size && SubregOffset ==
Offset) {
1583 NewID = std::nullopt;
1588 NewID =
ValueIDNum(NewID->getBlock(), NewID->getInst(), NewLoc);
1593 NewID = std::nullopt;
1603 if (!
MI.isDebugRef())
1608 if (!VTracker && !TTracker)
1616 "Expected inlined-at fields to agree");
1621 if (Scope ==
nullptr)
1627 assert(!MO.
isReg() &&
"DBG_INSTR_REF should not contain registers");
1638 std::optional<ValueIDNum> NewID =
1639 getValueForInstrRef(InstNo, OpNo,
MI, MLiveOuts, MLiveIns);
1656 VTracker->
defVar(
MI, Properties, DbgOpIDs);
1665 for (
DbgOpID OpID : DbgOpIDs) {
1675 for (
const DbgOp &
Op : DbgOps) {
1677 if (FoundLocs.
insert({Op.ID, TransferTracker::LocationAndQuality()})
1682 for (
auto Location : MTracker->
locations()) {
1685 auto ValueToFindIt =
find(ValuesToFind,
ID);
1686 if (ValueToFindIt == ValuesToFind.
end())
1688 auto &Previous = FoundLocs.
find(
ID)->second;
1691 std::optional<TransferTracker::LocationQuality> ReplacementQuality =
1693 if (ReplacementQuality) {
1695 if (Previous.isBest()) {
1696 ValuesToFind.
erase(ValueToFindIt);
1697 if (ValuesToFind.
empty())
1721 if (!DbgOps.empty() && NewLocs.
empty()) {
1722 bool IsValidUseBeforeDef =
true;
1724 for (
auto ValueLoc : FoundLocs) {
1726 LocIdx FoundLoc = ValueLoc.second.getLoc();
1732 IsValidUseBeforeDef =
false;
1735 LastUseBeforeDef = std::max(LastUseBeforeDef, NewID.
getInst());
1737 if (IsValidUseBeforeDef) {
1740 DbgOps, LastUseBeforeDef);
1749 MTracker->
emitLoc(NewLocs, V,
MI.getDebugLoc().get(), Properties);
1758 if (!
MI.isDebugPHI())
1762 if (VTracker || TTracker)
1768 unsigned InstrNum =
MI.getOperand(1).getImm();
1770 auto EmitBadPHI = [
this, &
MI, InstrNum]() ->
bool {
1776 {InstrNum,
MI.getParent(), std::nullopt, std::nullopt});
1785 auto PHIRec = DebugPHIRecord(
1792 }
else if (MO.
isFI()) {
1799 return EmitBadPHI();
1810 return EmitBadPHI();
1813 assert(
MI.getNumOperands() == 3 &&
"Stack DBG_PHI with no size?");
1814 unsigned slotBitSize =
MI.getOperand(2).getImm();
1816 unsigned SpillID = MTracker->
getLocID(*SpillNo, {slotBitSize, 0});
1821 auto DbgPHI = DebugPHIRecord({InstrNum,
MI.getParent(), Result,
SpillLoc});
1829 {
dbgs() <<
"Seen DBG_PHI with unrecognised operand format\n"; });
1830 return EmitBadPHI();
1839 if (
MI.isImplicitDef()) {
1849 }
else if (
MI.isMetaInstruction())
1857 bool CallChangesSP =
false;
1858 if (AdjustsStackInCalls &&
MI.isCall() &&
MI.getOperand(0).isSymbol() &&
1859 !strcmp(
MI.getOperand(0).getSymbolName(), StackProbeSymbolName.
data()))
1860 CallChangesSP =
true;
1864 auto IgnoreSPAlias = [
this, &
MI, CallChangesSP](
Register R) ->
bool {
1867 return MI.isCall() && MTracker->
SPAliases.count(R);
1879 !IgnoreSPAlias(MO.
getReg())) {
1892 MTracker->
defReg(DeadReg, CurBB, CurInst);
1894 for (
const auto *MO : RegMaskPtrs)
1899 if (std::optional<SpillLocationNo> SpillNo =
1900 extractSpillBaseRegAndOffset(
MI)) {
1917 for (
uint32_t DeadReg : DeadRegs) {
1924 if (!RegMaskPtrs.empty()) {
1931 if (IgnoreSPAlias(Reg))
1934 for (
const auto *MO : RegMaskPtrs)
1942 if (std::optional<SpillLocationNo> SpillNo =
1943 extractSpillBaseRegAndOffset(
MI)) {
1953void InstrRefBasedLDV::performCopy(
Register SrcRegNum,
Register DstRegNum) {
1956 MTracker->
defReg(*RAI, CurBB, CurInst);
1959 MTracker->
setReg(DstRegNum, SrcValue);
1963 unsigned SrcSubReg = SRI.getSubReg();
1964 unsigned SubRegIdx = SRI.getSubRegIndex();
1965 unsigned DstSubReg = TRI->
getSubReg(DstRegNum, SubRegIdx);
1980 MTracker->
setReg(DstSubReg, CpyValue);
1984std::optional<SpillLocationNo>
1988 if (!
MI.hasOneMemOperand())
1989 return std::nullopt;
1992 auto MMOI =
MI.memoperands_begin();
1995 return std::nullopt;
1997 if (!
MI.getSpillSize(TII) && !
MI.getFoldedSpillSize(TII))
1998 return std::nullopt;
2001 return extractSpillBaseRegAndOffset(
MI);
2006 if (!isSpillInstruction(
MI, MF))
2014std::optional<SpillLocationNo>
2017 if (!
MI.hasOneMemOperand())
2018 return std::nullopt;
2022 if (
MI.getRestoreSize(TII)) {
2023 Reg =
MI.getOperand(0).getReg();
2024 return extractSpillBaseRegAndOffset(
MI);
2026 return std::nullopt;
2029bool InstrRefBasedLDV::transferSpillOrRestoreInst(
MachineInstr &
MI) {
2058 if (std::optional<SpillLocationNo> Loc = isSpillInstruction(
MI, MF)) {
2061 for (
unsigned SlotIdx = 0; SlotIdx < MTracker->
NumSlotIdxes; ++SlotIdx) {
2063 std::optional<LocIdx> MLoc = MTracker->
getSpillMLoc(SpillID);
2072 MTracker->
setMLoc(*MLoc, Def);
2079 if (isLocationSpill(
MI, MF, Reg)) {
2084 auto DoTransfer = [&](
Register SrcReg,
unsigned SpillID) {
2085 auto ReadValue = MTracker->
readReg(SrcReg);
2087 MTracker->
setMLoc(DstLoc, ReadValue);
2100 unsigned SpillID = MTracker->
getLocID(Loc, SubregIdx);
2101 DoTransfer(SR, SpillID);
2107 DoTransfer(Reg, SpillID);
2109 std::optional<SpillLocationNo> Loc = isRestoreInstruction(
MI, MF, Reg);
2121 MTracker->
defReg(*RAI, CurBB, CurInst);
2125 auto DoTransfer = [&](
Register DestReg,
unsigned SpillID) {
2127 auto ReadValue = MTracker->
readMLoc(SrcIdx);
2128 MTracker->
setReg(DestReg, ReadValue);
2133 unsigned SpillID = MTracker->
getLocID(*Loc, Subreg);
2134 DoTransfer(SR, SpillID);
2139 unsigned SpillID = MTracker->
getLocID(*Loc, {
Size, 0});
2140 DoTransfer(Reg, SpillID);
2157 if (SrcReg == DestReg)
2186 if (MLocIt == TTracker->
ActiveMLocs.
end() || MLocIt->second.empty())
2189 ClobberedLocs[ClobberedLoc] =
Value;
2194 InstrRefBasedLDV::performCopy(SrcReg, DestReg);
2200 for (
auto LocVal : ClobberedLocs) {
2201 TTracker->
clobberMloc(LocVal.first, LocVal.second,
MI.getIterator(),
false);
2214 MTracker->
defReg(SrcReg, CurBB, CurInst);
2228 MI.getDebugLoc()->getInlinedAt());
2229 FragmentInfo ThisFragment = MIVar.getFragmentOrDefault();
2234 auto SeenIt = SeenFragments.
find(MIVar.getVariable());
2235 if (SeenIt == SeenFragments.
end()) {
2237 OneFragment.
insert(ThisFragment);
2238 SeenFragments.
insert({MIVar.getVariable(), OneFragment});
2240 OverlapFragments.
insert({{MIVar.getVariable(), ThisFragment}, {}});
2247 OverlapFragments.
insert({{MIVar.getVariable(), ThisFragment}, {}});
2248 if (!IsInOLapMap.second)
2251 auto &ThisFragmentsOverlaps = IsInOLapMap.first->second;
2252 auto &AllSeenFragments = SeenIt->second;
2257 for (
const auto &ASeenFragment : AllSeenFragments) {
2261 ThisFragmentsOverlaps.push_back(ASeenFragment);
2264 auto ASeenFragmentsOverlaps =
2265 OverlapFragments.
find({MIVar.getVariable(), ASeenFragment});
2266 assert(ASeenFragmentsOverlaps != OverlapFragments.
end() &&
2267 "Previously seen var fragment has no vector of overlaps");
2268 ASeenFragmentsOverlaps->second.push_back(ThisFragment);
2272 AllSeenFragments.insert(ThisFragment);
2281 if (transferDebugValue(
MI))
2283 if (transferDebugInstrRef(
MI, MLiveOuts, MLiveIns))
2285 if (transferDebugPHI(
MI))
2287 if (transferRegisterCopy(
MI))
2289 if (transferSpillOrRestoreInst(
MI))
2291 transferRegisterDef(
MI);
2294void InstrRefBasedLDV::produceMLocTransferFunction(
2310 for (
auto &BV : BlockMasks)
2314 for (
auto &
MBB : MF) {
2326 for (
auto &
MI :
MBB) {
2329 process(
MI,
nullptr,
nullptr);
2332 if (
MI.isDebugValueLike())
2333 accumulateFragmentMap(
MI);
2337 if (
uint64_t InstrNo =
MI.peekDebugInstrNum()) {
2338 auto InstrAndPos = std::make_pair(&
MI, CurInst);
2340 DebugInstrNumToInstr.insert(std::make_pair(InstrNo, InstrAndPos));
2343 assert(InsertResult.second);
2354 for (
auto Location : MTracker->
locations()) {
2357 if (
P.isPHI() &&
P.getLoc() ==
Idx.asU64())
2361 auto &TransferMap = MLocTransfer[CurBB];
2362 auto Result = TransferMap.insert(std::make_pair(
Idx.asU64(),
P));
2369 for (
auto &
P : MTracker->
Masks) {
2370 BlockMasks[CurBB].clearBitsNotInMask(
P.first->getRegMask(), BVWords);
2376 for (
auto Location : MTracker->
locations()) {
2394 for (
unsigned Bit : BV.
set_bits()) {
2397 auto &TransferMap = MLocTransfer[
I];
2406 TransferMap.insert(std::make_pair(
Idx.asU64(), NotGeneratedNum));
2411 ValueID = NotGeneratedNum;
2417bool InstrRefBasedLDV::mlocJoin(
2421 bool Changed =
false;
2432 return BBToOrder.find(
A)->second < BBToOrder.find(
B)->second;
2437 if (BlockOrders.size() == 0) {
2442 <<
" from entry which may lead out of "
2443 "bound access to VarLocs\n");
2449 for (
auto Location : MTracker->
locations()) {
2454 ValueIDNum FirstVal = OutLocs[*BlockOrders[0]][
Idx.asU64()];
2459 if (InLocs[
Idx.asU64()] != FirstVal) {
2460 InLocs[
Idx.asU64()] = FirstVal;
2468 bool Disagree =
false;
2469 for (
unsigned int I = 1;
I < BlockOrders.size(); ++
I) {
2471 const ValueIDNum &PredLiveOut = OutLocs[*PredMBB][
Idx.asU64()];
2474 if (FirstVal == PredLiveOut)
2487 InLocs[
Idx.asU64()] = FirstVal;
2496void InstrRefBasedLDV::findStackIndexInterference(
2516 if (!Pair.first.second)
2522void InstrRefBasedLDV::placeMLocPHIs(
2526 findStackIndexInterference(StackUnits);
2538 for (
auto Location : MTracker->
locations()) {
2547 bool AnyIllegal =
false;
2556 FoundRegUnits.
insert(*URoot);
2562 NormalLocsToPHI.
insert(L);
2566 RegUnitsToPHIUp.
insert(FoundRegUnits.
begin(), FoundRegUnits.
end());
2572 auto CollectPHIsForLoc = [&](
LocIdx L) {
2575 for (
unsigned int I = 0;
I < OrderToBB.size(); ++
I) {
2577 const auto &TransferFunc = MLocTransfer[
MBB->
getNumber()];
2578 if (TransferFunc.contains(L))
2585 if (!DefBlocks.
empty())
2591 BlockPHIPlacement(AllBlocks, DefBlocks, PHIBlocks);
2594 auto InstallPHIsAtLoc = [&PHIBlocks, &MInLocs](
LocIdx L) {
2600 for (
LocIdx L : NormalLocsToPHI) {
2601 CollectPHIsForLoc(L);
2603 InstallPHIsAtLoc(L);
2609 for (
unsigned Idx : StackUnits) {
2612 CollectPHIsForLoc(L);
2613 InstallPHIsAtLoc(L);
2619 unsigned ThisSize, ThisOffset;
2620 std::tie(ThisSize, ThisOffset) = Pair.first;
2626 InstallPHIsAtLoc(ThisL);
2632 for (
Register R : RegUnitsToPHIUp) {
2634 CollectPHIsForLoc(L);
2637 InstallPHIsAtLoc(L);
2647 InstallPHIsAtLoc(AliasLoc);
2652void InstrRefBasedLDV::buildMLocValueMap(
2655 std::priority_queue<unsigned int, std::vector<unsigned int>,
2656 std::greater<unsigned int>>
2667 for (
unsigned int I = 0;
I < BBToOrder.size(); ++
I) {
2669 OnWorklist.
insert(OrderToBB[
I]);
2670 AllBlocks.
insert(OrderToBB[
I]);
2674 for (
auto Location : MTracker->
locations())
2683 placeMLocPHIs(MF, AllBlocks, MInLocs, MLocTransfer);
2694 while (!Worklist.empty() || !Pending.empty()) {
2698 while (!Worklist.empty()) {
2705 InLocsChanged = mlocJoin(*
MBB, Visited, MOutLocs, MInLocs[*
MBB]);
2706 InLocsChanged |= Visited.
insert(
MBB).second;
2719 for (
auto &
P : MLocTransfer[CurBB]) {
2720 if (
P.second.getBlock() == CurBB &&
P.second.isPHI()) {
2723 ToRemap.
push_back(std::make_pair(
P.first, NewID));
2726 assert(
P.second.getBlock() == CurBB);
2727 ToRemap.
push_back(std::make_pair(
P.first,
P.second));
2733 for (
auto &
P : ToRemap)
2739 bool OLChanged =
false;
2740 for (
auto Location : MTracker->
locations()) {
2756 if (BBToOrder[s] > BBToOrder[
MBB]) {
2758 if (OnWorklist.
insert(s).second)
2759 Worklist.push(BBToOrder[s]);
2762 if (OnPending.
insert(s).second)
2763 Pending.push(BBToOrder[s]);
2768 Worklist.swap(Pending);
2773 assert(Pending.empty() &&
"Pending should be empty");
2780void InstrRefBasedLDV::BlockPHIPlacement(
2789 IDF.setLiveInBlocks(AllBlocks);
2790 IDF.setDefiningBlocks(DefBlocks);
2791 IDF.calculate(PHIBlocks);
2794bool InstrRefBasedLDV::pickVPHILoc(
2800 if (BlockOrders.
empty())
2807 auto FirstValueIt = LiveOuts.
find(BlockOrders[0]);
2808 if (FirstValueIt == LiveOuts.end())
2810 const DbgValue &FirstValue = *FirstValueIt->second;
2812 for (
const auto p : BlockOrders) {
2813 auto OutValIt = LiveOuts.find(p);
2814 if (OutValIt == LiveOuts.end())
2817 const DbgValue &OutVal = *OutValIt->second;
2840 if (FirstValOp != OutValOp) {
2861 std::optional<ValueIDNum> JoinedOpLoc =
2862 pickOperandPHILoc(
Idx,
MBB, LiveOuts, MOutLocs, BlockOrders);
2870 OutValues.
append(NewDbgOps);
2874std::optional<ValueIDNum> InstrRefBasedLDV::pickOperandPHILoc(
2884 for (
const auto p : BlockOrders) {
2885 auto OutValIt = LiveOuts.find(p);
2886 assert(OutValIt != LiveOuts.end());
2887 const DbgValue &OutVal = *OutValIt->second;
2889 DbgOp OutValOp = DbgOpStore.
find(OutValOpID);
2902 for (
unsigned int I = 0;
I < NumLocs; ++
I) {
2903 if (MOutLocs[*p][
I] == ValToLookFor)
2914 for (
unsigned int I = 0;
I < NumLocs; ++
I) {
2916 if (MOutLocs[*p][
I] == MPHI)
2927 for (
unsigned int I = 1;
I < Locs.
size(); ++
I) {
2928 auto &LocVec = Locs[
I];
2930 std::set_intersection(CandidateLocs.
begin(), CandidateLocs.
end(),
2931 LocVec.begin(), LocVec.end(), std::inserter(NewCandidates, NewCandidates.
begin()));
2932 CandidateLocs = NewCandidates;
2934 if (CandidateLocs.
empty())
2935 return std::nullopt;
2947bool InstrRefBasedLDV::vlocJoin(
2952 bool Changed =
false;
2958 return BBToOrder[
A] < BBToOrder[
B];
2963 unsigned CurBlockRPONum = BBToOrder[&
MBB];
2969 int BackEdgesStart = 0;
2970 for (
auto *p : BlockOrders) {
2973 if (!BlocksToExplore.
contains(p)) {
2979 DbgValue &OutLoc = *VLOCOutLocs.find(p)->second;
2983 unsigned ThisBBRPONum = BBToOrder[
p];
2984 if (ThisBBRPONum < CurBlockRPONum)
2987 Values.
push_back(std::make_pair(p, &OutLoc));
2993 if (Bail || Values.
size() == 0)
2999 const DbgValue &FirstVal = *Values[0].second;
3005 Changed = LiveIn != FirstVal;
3014 for (
const auto &V : Values) {
3015 if (!
V.second->Properties.isJoinable(FirstVal.
Properties))
3019 if (!
V.second->hasJoinableLocOps(FirstVal))
3024 bool Disagree =
false;
3025 for (
auto &V : Values) {
3026 if (*
V.second == FirstVal)
3032 if (
V.second->hasIdenticalValidLocOps(FirstVal))
3039 std::distance(Values.begin(), &V) >= BackEdgesStart)
3047 Changed = LiveIn != FirstVal;
3054 Changed = LiveIn != VPHI;
3061void InstrRefBasedLDV::getBlocksForScope(
3071 BlocksToExplore.
insert(AssignBlocks.
begin(), AssignBlocks.
end());
3081 for (
const auto *
MBB : BlocksToExplore) {
3091 if (BlocksToExplore.count(succ))
3093 if (!ArtificialBlocks.count(succ))
3096 DFS.push_back({succ, succ->succ_begin()});
3100 while (!DFS.empty()) {
3104 if (CurSucc == CurBB->
succ_end()) {
3111 if (!ToAdd.
count(*CurSucc) && ArtificialBlocks.count(*CurSucc)) {
3113 DFS.push_back({*CurSucc, (*CurSucc)->succ_begin()});
3121 BlocksToExplore.insert(ToAdd.
begin(), ToAdd.
end());
3124void InstrRefBasedLDV::buildVLocValueMap(
3134 std::priority_queue<unsigned int, std::vector<unsigned int>,
3135 std::greater<unsigned int>>
3146 getBlocksForScope(DILoc, BlocksToExplore, AssignBlocks);
3152 if (BlocksToExplore.
size() == 1)
3159 for (
const auto *
MBB : BlocksToExplore)
3165 for (
const auto *
MBB : BlocksToExplore)
3169 for (
unsigned int I : BlockOrderNums)
3171 BlockOrderNums.clear();
3172 unsigned NumBlocks = BlockOrders.
size();
3182 for (
unsigned int I = 0;
I < NumBlocks; ++
I) {
3191 LiveOutIdx.reserve(NumBlocks);
3192 LiveInIdx.reserve(NumBlocks);
3193 for (
unsigned I = 0;
I < NumBlocks; ++
I) {
3194 LiveOutIdx[BlockOrders[
I]] = &LiveOuts[
I];
3195 LiveInIdx[BlockOrders[
I]] = &LiveIns[
I];
3205 for (
unsigned int I = 0;
I < NumBlocks; ++
I) {
3207 LiveIns[
I] = EmptyDbgValue;
3208 LiveOuts[
I] = EmptyDbgValue;
3215 auto &TransferFunc = AllTheVLocs[ExpMBB->getNumber()].Vars;
3216 if (TransferFunc.contains(VarID))
3224 if (DefBlocks.
size() == 1) {
3225 placePHIsForSingleVarDefinition(MutBlocksToExplore, *DefBlocks.
begin(),
3226 AllTheVLocs, VarID, Output);
3231 BlockPHIPlacement(MutBlocksToExplore, DefBlocks, PHIBlocks);
3235 unsigned BlockNo = PHIMBB->getNumber();
3236 DbgValue *LiveIn = LiveInIdx[PHIMBB];
3240 for (
auto *
MBB : BlockOrders) {
3241 Worklist.push(BBToOrder[
MBB]);
3252 bool FirstTrip =
true;
3253 while (!Worklist.empty() || !Pending.empty()) {
3254 while (!Worklist.empty()) {
3255 auto *
MBB = OrderToBB[Worklist.top()];
3259 auto LiveInsIt = LiveInIdx.find(
MBB);
3260 assert(LiveInsIt != LiveInIdx.end());
3261 DbgValue *LiveIn = LiveInsIt->second;
3265 bool InLocsChanged =
3266 vlocJoin(*
MBB, LiveOutIdx, BlocksToExplore, *LiveIn);
3281 if (pickVPHILoc(JoinedOps, *
MBB, LiveOutIdx, MOutLocs, Preds)) {
3283 InLocsChanged |= NewLocPicked;
3289 if (!InLocsChanged && !FirstTrip)
3293 bool OLChanged =
false;
3297 auto TransferIt = VTracker.
Vars.find(VarID);
3298 if (TransferIt != VTracker.
Vars.end()) {
3302 if (*LiveOut != NewVal) {
3308 if (*LiveOut != TransferIt->second) {
3309 *LiveOut = TransferIt->second;
3315 if (*LiveOut != *LiveIn) {
3330 if (!LiveInIdx.contains(s))
3333 if (BBToOrder[s] > BBToOrder[
MBB]) {
3334 if (OnWorklist.
insert(s).second)
3335 Worklist.push(BBToOrder[s]);
3336 }
else if (OnPending.
insert(s).second && (FirstTrip || OLChanged)) {
3337 Pending.push(BBToOrder[s]);
3341 Worklist.swap(Pending);
3351 for (
auto *
MBB : BlockOrders) {
3359 [[maybe_unused]]
auto &[Var, DILoc] = DVMap.
lookupDVID(VarID);
3361 Var.getFragment() &&
3362 "Fragment info missing during value prop");
3363 Output[
MBB->
getNumber()].push_back(std::make_pair(VarID, *BlockLiveIn));
3367 BlockOrders.clear();
3368 BlocksToExplore.clear();
3371void InstrRefBasedLDV::placePHIsForSingleVarDefinition(
3387 auto ValueIt = VLocs.
Vars.find(VarID);
3398 for (
auto *ScopeBlock : InScopeBlocks) {
3402 Output[ScopeBlock->getNumber()].push_back({VarID,
Value});
3409#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
3412 for (
const auto &
P : mloc_transfer) {
3415 dbgs() <<
"Loc " << foo <<
" --> " << bar <<
"\n";
3424 EmptyExpr = DIExpression::get(Context, {});
3426 auto hasNonArtificialLocation = [](
const MachineInstr &
MI) ->
bool {
3428 return DL.getLine() != 0;
3434 unsigned int Size = 0;
3435 for (
auto &
MBB : MF) {
3438 ArtificialBlocks.insert(&
MBB);
3443 unsigned int RPONumber = 0;
3444 OrderToBB.reserve(
Size);
3445 BBToOrder.reserve(
Size);
3448 OrderToBB.push_back(
MBB);
3449 BBToOrder[
MBB] = RPONumber;
3456 if (!BBToOrder.contains(&
MBB))
3462#ifdef EXPENSIVE_CHECKS
3465 if (MF.DebugValueSubstitutions.size() > 2) {
3466 for (
auto It = MF.DebugValueSubstitutions.begin();
3467 It != std::prev(MF.DebugValueSubstitutions.end()); ++It) {
3468 assert(It->Src != std::next(It)->Src &&
"Duplicate variable location "
3469 "substitution seen");
3478void InstrRefBasedLDV::makeDepthFirstEjectionMap(
3480 const ScopeToDILocT &ScopeToDILocation,
3481 ScopeToAssignBlocksT &ScopeToAssignBlocks) {
3488 WorkStack.
push_back({TopScope, TopScope->getChildren().
size() - 1});
3490 while (!WorkStack.
empty()) {
3491 auto &ScopePosition = WorkStack.
back();
3493 ssize_t ChildNum = ScopePosition.second--;
3496 if (ChildNum >= 0) {
3499 auto &ChildScope =
Children[ChildNum];
3501 std::make_pair(ChildScope, ChildScope->getChildren().size() - 1));
3508 auto DILocationIt = ScopeToDILocation.find(WS);
3509 if (DILocationIt != ScopeToDILocation.end()) {
3510 getBlocksForScope(DILocationIt->second, BlocksToExplore,
3511 ScopeToAssignBlocks.find(WS)->second);
3512 for (
const auto *
MBB : BlocksToExplore) {
3514 if (EjectionMap[BBNum] == 0)
3518 BlocksToExplore.clear();
3524bool InstrRefBasedLDV::depthFirstVLocAndEmit(
3525 unsigned MaxNumBlocks,
const ScopeToDILocT &ScopeToDILocation,
3526 const ScopeToVarsT &ScopeToVars, ScopeToAssignBlocksT &ScopeToAssignBlocks,
3531 new TransferTracker(TII, MTracker, MF, DVMap, *TRI, CalleeSavedRegs, TPC);
3542 makeDepthFirstEjectionMap(EjectionMap, ScopeToDILocation,
3543 ScopeToAssignBlocks);
3550 AllTheVLocs[BBNum].
clear();
3556 TTracker->
loadInlocs(
MBB, MInLocs[
MBB], DbgOpStore, Output[BBNum], NumLocs);
3560 for (
auto &
MI :
MBB) {
3561 process(
MI, &MOutLocs, &MInLocs);
3570 Output[BBNum].clear();
3571 AllTheVLocs[BBNum].
clear();
3577 unsigned HighestDFSIn = 0;
3580 while (!WorkStack.
empty()) {
3581 auto &ScopePosition = WorkStack.
back();
3583 ssize_t ChildNum = ScopePosition.second++;
3590 auto DILocIt = ScopeToDILocation.find(WS);
3591 if (HighestDFSIn <= WS->getDFSIn() && DILocIt != ScopeToDILocation.end()) {
3593 auto &VarsWeCareAbout = ScopeToVars.find(WS)->second;
3594 auto &BlocksInScope = ScopeToAssignBlocks.find(WS)->second;
3596 buildVLocValueMap(DILoc, VarsWeCareAbout, BlocksInScope, Output, MOutLocs,
3597 MInLocs, AllTheVLocs);
3600 HighestDFSIn = std::max(HighestDFSIn, WS->
getDFSIn());
3604 if (ChildNum < (ssize_t)
Children.size()) {
3606 auto &ChildScope =
Children[ChildNum];
3607 WorkStack.
push_back(std::make_pair(ChildScope, 0));
3613 auto DILocationIt = ScopeToDILocation.find(WS);
3614 if (DILocationIt == ScopeToDILocation.end())
3617 getBlocksForScope(DILocationIt->second, BlocksToExplore,
3618 ScopeToAssignBlocks.find(WS)->second);
3619 for (
const auto *
MBB : BlocksToExplore)
3623 BlocksToExplore.clear();
3632 for (
auto *
MBB : ArtificialBlocks)
3636 return emitTransfers();
3639bool InstrRefBasedLDV::emitTransfers() {
3653 for (
const auto &Pair :
P.Insts)
3658 if (
P.Pos->isTerminator())
3662 for (
const auto &Pair :
P.Insts)
3676 unsigned InputDbgValLimit) {
3684 this->DomTree = DomTree;
3695 STI.getFrameLowering()->stackProbeFunctionModifiesSP();
3696 if (AdjustsStackInCalls)
3697 StackProbeSymbolName = STI.getTargetLowering()->getStackProbeSymbolName(MF);
3709 for (
auto &
MBB : MF)
3720 produceMLocTransferFunction(MF, MLocTransfer,
MaxNumBlocks);
3733 buildMLocValueMap(MF, MInLocs, MOutLocs, MLocTransfer);
3737 for (
auto &DBG_PHI : DebugPHINumToValue) {
3739 if (!DBG_PHI.ValueRead)
3753 Num = ResolvedValue;
3762 VTracker = &vlocs[CurBB];
3766 for (
auto &
MI : *
MBB) {
3767 process(
MI, &MOutLocs, &MInLocs);
3785 unsigned VarAssignCount = 0;
3786 for (
unsigned int I = 0;
I < OrderToBB.size(); ++
I) {
3787 auto *
MBB = OrderToBB[
I];
3790 for (
auto &idx : VTracker->
Vars) {
3793 assert(ScopeLoc !=
nullptr);
3797 assert(Scope !=
nullptr);
3799 ScopeToVars[
Scope].insert(VarID);
3800 ScopeToAssignBlocks[
Scope].insert(VTracker->
MBB);
3801 ScopeToDILocation[
Scope] = ScopeLoc;
3806 bool Changed =
false;
3812 VarAssignCount > InputDbgValLimit) {
3813 LLVM_DEBUG(
dbgs() <<
"Disabling InstrRefBasedLDV: " << MF.getName()
3816 <<
" variable assignments, exceeding limits.\n");
3821 Changed = depthFirstVLocAndEmit(
3822 MaxNumBlocks, ScopeToDILocation, ScopeToVars, ScopeToAssignBlocks,
3823 SavedLiveIns, MOutLocs, MInLocs, vlocs, MF, *TPC);
3832 ArtificialBlocks.clear();
3836 DebugInstrNumToInstr.clear();
3837 DebugPHINumToValue.clear();
3838 OverlapFragments.
clear();
3839 SeenFragments.
clear();
3840 SeenDbgPHIs.clear();
3866 LDVSSABlock *ParentBlock;
3867 BlockValueNum PHIValNum;
3868 LDVSSAPhi(BlockValueNum PHIValNum, LDVSSABlock *ParentBlock)
3869 : ParentBlock(ParentBlock), PHIValNum(PHIValNum) {}
3871 LDVSSABlock *
getParent() {
return ParentBlock; }
3876class LDVSSABlockIterator {
3879 LDVSSAUpdater &Updater;
3882 LDVSSAUpdater &Updater)
3883 : PredIt(PredIt), Updater(Updater) {}
3885 bool operator!=(
const LDVSSABlockIterator &OtherIt)
const {
3886 return OtherIt.PredIt != PredIt;
3889 LDVSSABlockIterator &operator++() {
3903 LDVSSAUpdater &Updater;
3909 : BB(BB), Updater(Updater) {}
3912 return LDVSSABlockIterator(BB.
succ_begin(), Updater);
3916 return LDVSSABlockIterator(BB.
succ_end(), Updater);
3920 LDVSSAPhi *newPHI(BlockValueNum
Value) {
3921 PHIList.emplace_back(
Value,
this);
3922 return &PHIList.back();
3926 PHIListT &phis() {
return PHIList; }
3932class LDVSSAUpdater {
3947 : Loc(
L), MLiveIns(MLiveIns) {}
3950 for (
auto &
Block : BlockMap)
3951 delete Block.second;
3958 ~LDVSSAUpdater() { reset(); }
3963 auto it = BlockMap.find(BB);
3964 if (it == BlockMap.end()) {
3965 BlockMap[BB] =
new LDVSSABlock(*BB, *
this);
3966 it = BlockMap.find(BB);
3973 BlockValueNum getValue(LDVSSABlock *LDVBB) {
3974 return MLiveIns[LDVBB->BB][Loc.
asU64()].asU64();
3978LDVSSABlock *LDVSSABlockIterator::operator*() {
3979 return Updater.getSSALDVBlock(*PredIt);
3985 out <<
"SSALDVPHI " <<
PHI.PHIValNum;
4011 class PHI_iterator {
4037 return PHI_iterator(
PHI,
true);
4045 Preds->
push_back(BB->Updater.getSSALDVBlock(Pred));
4051 static BlockValueNum
GetPoisonVal(LDVSSABlock *BB, LDVSSAUpdater *Updater) {
4055 BlockValueNum Num =
ValueIDNum(BB->BB.getNumber(), 0, Updater->Loc).
asU64();
4056 Updater->PoisonMap[&BB->BB] = Num;
4066 LDVSSAUpdater *Updater) {
4067 BlockValueNum PHIValNum = Updater->getValue(BB);
4068 LDVSSAPhi *
PHI = BB->newPHI(PHIValNum);
4069 Updater->PHIs[PHIValNum] =
PHI;
4076 PHI->IncomingValues.push_back(std::make_pair(Pred, Val));
4081 static LDVSSAPhi *
ValueIsPHI(BlockValueNum Val, LDVSSAUpdater *Updater) {
4082 return Updater->PHIs.lookup(Val);
4088 LDVSSAPhi *
PHI = ValueIsPHI(Val, Updater);
4089 if (
PHI &&
PHI->IncomingValues.size() == 0)
4101std::optional<ValueIDNum> InstrRefBasedLDV::resolveDbgPHIs(
4106 auto SeenDbgPHIIt = SeenDbgPHIs.find(std::make_pair(&Here, InstrNum));
4107 if (SeenDbgPHIIt != SeenDbgPHIs.end())
4108 return SeenDbgPHIIt->second;
4110 std::optional<ValueIDNum>
Result =
4111 resolveDbgPHIsImpl(MF, MLiveOuts, MLiveIns, Here, InstrNum);
4112 SeenDbgPHIs.insert({std::make_pair(&Here, InstrNum),
Result});
4116std::optional<ValueIDNum> InstrRefBasedLDV::resolveDbgPHIsImpl(
4121 auto RangePair = std::equal_range(DebugPHINumToValue.begin(),
4122 DebugPHINumToValue.end(), InstrNum);
4123 auto LowerIt = RangePair.first;
4124 auto UpperIt = RangePair.second;
4127 if (LowerIt == UpperIt)
4128 return std::nullopt;
4134 auto DBGPHIRange =
make_range(LowerIt, UpperIt);
4135 for (
const DebugPHIRecord &DBG_PHI : DBGPHIRange)
4136 if (!DBG_PHI.ValueRead)
4137 return std::nullopt;
4140 if (std::distance(LowerIt, UpperIt) == 1)
4141 return *LowerIt->ValueRead;
4147 LocIdx Loc = *LowerIt->ReadLoc;
4156 LDVSSAUpdater Updater(Loc, MLiveIns);
4164 for (
const auto &DBG_PHI : DBGPHIRange) {
4165 LDVSSABlock *
Block = Updater.getSSALDVBlock(DBG_PHI.MBB);
4170 LDVSSABlock *HereBlock = Updater.getSSALDVBlock(Here.
getParent());
4171 const auto &AvailIt = AvailableValues.
find(HereBlock);
4172 if (AvailIt != AvailableValues.
end()) {
4181 BlockValueNum ResultInt = Impl.GetValue(Updater.getSSALDVBlock(Here.
getParent()));
4198 for (
const auto &DBG_PHI : DBGPHIRange) {
4199 LDVSSABlock *
Block = Updater.getSSALDVBlock(DBG_PHI.MBB);
4201 ValidatedValues.
insert(std::make_pair(
Block, Num));
4206 for (
auto &
PHI : CreatedPHIs)
4209 llvm::sort(SortedPHIs, [&](LDVSSAPhi *
A, LDVSSAPhi *
B) {
4210 return BBToOrder[&
A->getParent()->BB] < BBToOrder[&
B->getParent()->BB];
4213 for (
auto &
PHI : SortedPHIs) {
4217 for (
auto &PHIIt :
PHI->IncomingValues) {
4219 if (Updater.PoisonMap.contains(&PHIIt.first->BB))
4220 return std::nullopt;
4223 const ValueTable &BlockLiveOuts = MLiveOuts[PHIIt.first->BB];
4225 auto VVal = ValidatedValues.
find(PHIIt.first);
4226 if (VVal == ValidatedValues.
end()) {
4231 ValueToCheck = ThisBlockValueNum;
4235 ValueToCheck = VVal->second;
4238 if (BlockLiveOuts[Loc.
asU64()] != ValueToCheck)
4239 return std::nullopt;
4243 ValidatedValues.
insert({
PHI->ParentBlock, ThisBlockValueNum});
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
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 const Function * getParent(const Value *V)
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
#define LLVM_DUMP_METHOD
Mark debug helper function definitions like dump() that should not be stripped from debug builds.
Returns the sub type a function will return at a given Idx Should correspond to the result type of an ExtractValue instruction executed with just that one unsigned Idx
This file defines the DenseMap class.
This file contains constants used for implementing Dwarf debug support.
static GCMetadataPrinterRegistry::Add< ErlangGCPrinter > X("erlang", "erlang-compatible garbage collector")
Compute iterated dominance frontiers using a linear time algorithm.
const HexagonInstrInfo * TII
static cl::opt< unsigned > StackWorkingSetLimit("livedebugvalues-max-stack-slots", cl::Hidden, cl::desc("livedebugvalues-stack-ws-limit"), cl::init(250))
static cl::opt< bool > EmulateOldLDV("emulate-old-livedebugvalues", cl::Hidden, cl::desc("Act like old LiveDebugValues did"), cl::init(false))
static cl::opt< unsigned > InputBBLimit("livedebugvalues-input-bb-limit", cl::desc("Maximum input basic blocks before DBG_VALUE limit applies"), cl::init(10000), cl::Hidden)
unsigned const TargetRegisterInfo * TRI
const char LLVMTargetMachineRef TM
This file builds on the ADT/GraphTraits.h file to build a generic graph post order iterator.
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
This file defines the SmallPtrSet class.
This file defines the SmallSet class.
This file defines the SmallVector class.
This file describes how to lower LLVM code to machine code.
Target-Independent Code Generator Pass Configuration Options pass.
Class storing the complete set of values that are observed by DbgValues within the current function.
DbgOp find(DbgOpID ID) const
Returns the DbgOp associated with ID.
DbgOpID insert(DbgOp Op)
If Op does not already exist in this map, it is inserted and the corresponding DbgOpID is returned.
Meta qualifiers for a value.
const DIExpression * DIExpr
bool isJoinable(const DbgValueProperties &Other) const
unsigned getLocationOpCount() const
Class recording the (high level) value of a variable.
int BlockNo
For a NoVal or VPHI DbgValue, which block it was generated in.
DbgValueProperties Properties
Qualifiers for the ValueIDNum above.
ArrayRef< DbgOpID > getDbgOpIDs() const
void setDbgOpIDs(ArrayRef< DbgOpID > NewIDs)
void dump(const MLocTracker *MTrack=nullptr, const DbgOpIDMap *OpStore=nullptr) const
bool isUnjoinedPHI() const
DbgOpID getDbgOpID(unsigned Index) const
KindT Kind
Discriminator for whether this is a constant or an in-program value.
unsigned getLocationOpCount() const
Mapping from DebugVariable to/from a unique identifying number.
const VarAndLoc & lookupDVID(DebugVariableID ID) const
DebugVariableID insertDVID(DebugVariable &Var, const DILocation *Loc)
DebugVariableID getDVID(const DebugVariable &Var) const
DenseMap< const MachineBasicBlock *, DbgValue * > LiveIdxT
Live in/out structure for the variable values: a per-block map of variables to their values.
DenseMap< const LexicalScope *, const DILocation * > ScopeToDILocT
Mapping from lexical scopes to a DILocation in that scope.
std::optional< LocIdx > findLocationForMemOperand(const MachineInstr &MI)
SmallVector< SmallVector< VarAndLoc, 8 >, 8 > LiveInsT
Vector (per block) of a collection (inner smallvector) of live-ins.
InstrRefBasedLDV()
Default construct and initialize the pass.
DIExpression::FragmentInfo FragmentInfo
bool hasFoldedStackStore(const MachineInstr &MI)
bool isCalleeSaved(LocIdx L) const
DenseMap< const LexicalScope *, SmallPtrSet< MachineBasicBlock *, 4 > > ScopeToAssignBlocksT
Mapping from lexical scopes to blocks where variables in that scope are assigned.
bool isCalleeSavedReg(Register R) const
LLVM_DUMP_METHOD void dump_mloc_transfer(const MLocTransferMap &mloc_transfer) const
DenseMap< const LexicalScope *, SmallSet< DebugVariableID, 4 > > ScopeToVarsT
Mapping from lexical scopes to variables in that scope.
Handle-class for a particular "location".
static LocIdx MakeIllegalLoc()
Tracker for what values are in machine locations.
unsigned getLocSizeInBits(LocIdx L) const
How large is this location (aka, how wide is a value defined there?).
bool isRegisterTracked(Register R)
Is register R currently tracked by MLocTracker?
std::optional< SpillLocationNo > getOrTrackSpillLoc(SpillLoc L)
Find LocIdx for SpillLoc L, creating a new one if it's not tracked.
void loadFromArray(ValueTable &Locs, unsigned NewCurBB)
Load values for each location from array of ValueIDNums.
IndexedMap< unsigned, LocIdxToIndexFunctor > LocIdxToLocID
Inverse map of LocIDToLocIdx.
unsigned getSpillIDWithIdx(SpillLocationNo Spill, unsigned Idx)
Given a spill number, and a slot within the spill, calculate the ID number for that location.
iterator_range< MLocIterator > locations()
Return a range over all locations currently tracked.
SmallSet< Register, 8 > SPAliases
When clobbering register masks, we chose to not believe the machine model and don't clobber SP.
unsigned getLocID(Register Reg)
Produce location ID number for a Register.
const TargetLowering & TLI
const TargetRegisterInfo & TRI
unsigned NumRegs
Cached local copy of the number of registers the target has.
unsigned getNumLocs() const
DenseMap< StackSlotPos, unsigned > StackSlotIdxes
Map from a size/offset pair describing a position in a stack slot, to a numeric identifier for that p...
LocIdx lookupOrTrackRegister(unsigned ID)
void setReg(Register R, ValueIDNum ValueID)
Set a register to a value number.
SpillLocationNo locIDToSpill(unsigned ID) const
Return the spill number that a location ID corresponds to.
void reset()
Wipe any un-necessary location records after traversing a block.
DenseMap< unsigned, StackSlotPos > StackIdxesToPos
Inverse of StackSlotIdxes.
std::string IDAsString(const ValueIDNum &Num) const
void writeRegMask(const MachineOperand *MO, unsigned CurBB, unsigned InstID)
Record a RegMask operand being executed.
std::pair< unsigned short, unsigned short > StackSlotPos
Pair for describing a position within a stack slot – first the size in bits, then the offset.
const TargetInstrInfo & TII
bool isSpill(LocIdx Idx) const
Return true if Idx is a spill machine location.
LocIdx getRegMLoc(Register R)
Determine the LocIdx of an existing register.
MachineInstrBuilder emitLoc(const SmallVectorImpl< ResolvedDbgOp > &DbgOps, const DebugVariable &Var, const DILocation *DILoc, const DbgValueProperties &Properties)
Create a DBG_VALUE based on debug operands DbgOps.
void setMLoc(LocIdx L, ValueIDNum Num)
Set a locaiton to a certain value.
LocToValueType LocIdxToIDNum
Map of LocIdxes to the ValueIDNums that they store.
std::vector< LocIdx > LocIDToLocIdx
"Map" of machine location IDs (i.e., raw register or spill number) to the LocIdx key / number for tha...
SmallVector< std::pair< const MachineOperand *, unsigned >, 32 > Masks
Collection of register mask operands that have been observed.
unsigned NumSlotIdxes
Number of slot indexes the target has – distinct segments of a stack slot that can take on the value ...
UniqueVector< SpillLoc > SpillLocs
Unique-ification of spill.
ValueIDNum readMLoc(LocIdx L)
Read the value of a particular location.
void setMPhis(unsigned NewCurBB)
Reset all locations to contain a PHI value at the designated block.
ValueIDNum readReg(Register R)
void defReg(Register R, unsigned BB, unsigned Inst)
Record a definition of the specified register at the given block / inst.
LLVM_DUMP_METHOD void dump()
LocIdx trackRegister(unsigned ID)
Create a LocIdx for an untracked register ID.
MLocTracker(MachineFunction &MF, const TargetInstrInfo &TII, const TargetRegisterInfo &TRI, const TargetLowering &TLI)
LLVM_DUMP_METHOD void dump_mloc_map()
StackSlotPos locIDToSpillIdx(unsigned ID) const
Returns the spill-slot size/offs that a location ID corresponds to.
LocIdx getSpillMLoc(unsigned SpillID)
std::string LocIdxToName(LocIdx Idx) const
Thin wrapper around an integer – designed to give more type safety to spill location numbers.
Collection of DBG_VALUEs observed when traversing a block.
SmallDenseMap< DebugVariableID, const DILocation *, 8 > Scopes
void defVar(const MachineInstr &MI, const DbgValueProperties &Properties, const SmallVectorImpl< DbgOpID > &DebugOps)
MapVector< DebugVariableID, DbgValue > Vars
Map DebugVariable to the latest Value it's defined to have.
Unique identifier for a value defined by an instruction, as a value type.
static ValueIDNum fromU64(uint64_t v)
std::string asString(const std::string &mlocname) const
static ValueIDNum EmptyValue
static ValueIDNum TombstoneValue
uint64_t getBlock() const
LocationAndQuality(LocIdx L, LocationQuality Q)
LocationQuality getQuality() const
Tracker for converting machine value locations and variable values into variable locations (the outpu...
const DebugVariableMap & DVMap
DenseSet< DebugVariableID > UseBeforeDefVariables
The set of variables that are in UseBeforeDefs and can become a location once the relevant value is d...
const BitVector & CalleeSavedRegs
void loadInlocs(MachineBasicBlock &MBB, ValueTable &MLocs, DbgOpIDMap &DbgOpStore, const SmallVectorImpl< std::pair< DebugVariableID, DbgValue > > &VLocs, unsigned NumLocs)
Load object with live-in variable values.
const TargetLowering * TLI
void addUseBeforeDef(DebugVariableID VarID, const DbgValueProperties &Properties, const SmallVectorImpl< DbgOp > &DbgOps, unsigned Inst)
Record that Var has value ID, a value that becomes available later in the function.
SmallVector< ValueIDNum, 32 > VarLocs
Local cache of what-value-is-in-what-LocIdx.
MLocTracker * MTracker
This machine location tracker is assumed to always contain the up-to-date value mapping for all machi...
void transferMlocs(LocIdx Src, LocIdx Dst, MachineBasicBlock::iterator Pos)
Transfer variables based on Src to be based on Dst.
std::optional< LocationQuality > getLocQualityIfBetter(LocIdx L, LocationQuality Min) const
SmallVector< std::pair< DebugVariableID, MachineInstr * >, 4 > PendingDbgValues
Temporary cache of DBG_VALUEs to be entered into the Transfers collection.
bool isEntryValueVariable(const DebugVariable &Var, const DIExpression *Expr) const
void checkInstForNewValues(unsigned Inst, MachineBasicBlock::iterator pos)
After the instruction at index Inst and position pos has been processed, check whether it defines a v...
const TargetInstrInfo * TII
DenseMap< LocIdx, SmallSet< DebugVariableID, 4 > > ActiveMLocs
Map from LocIdxes to which DebugVariables are based that location.
MachineInstrBuilder emitMOLoc(const MachineOperand &MO, const DebugVariable &Var, const DbgValueProperties &Properties)
TransferTracker(const TargetInstrInfo *TII, MLocTracker *MTracker, MachineFunction &MF, const DebugVariableMap &DVMap, const TargetRegisterInfo &TRI, const BitVector &CalleeSavedRegs, const TargetPassConfig &TPC)
bool isEntryValueValue(const ValueIDNum &Val) const
const TargetRegisterInfo & TRI
void redefVar(const MachineInstr &MI)
Change a variable value after encountering a DBG_VALUE inside a block.
bool recoverAsEntryValue(DebugVariableID VarID, const DbgValueProperties &Prop, const ValueIDNum &Num)
bool isCalleeSaved(LocIdx L) const
void clobberMloc(LocIdx MLoc, MachineBasicBlock::iterator Pos, bool MakeUndef=true)
Account for a location mloc being clobbered.
void flushDbgValues(MachineBasicBlock::iterator Pos, MachineBasicBlock *MBB)
Helper to move created DBG_VALUEs into Transfers collection.
DenseMap< DebugVariableID, ResolvedDbgValue > ActiveVLocs
Map from DebugVariable to it's current location and qualifying meta information.
DenseMap< unsigned, SmallVector< UseBeforeDef, 1 > > UseBeforeDefs
Map from instruction index (within the block) to the set of UseBeforeDefs that become defined at that...
void clobberMloc(LocIdx MLoc, ValueIDNum OldValue, MachineBasicBlock::iterator Pos, bool MakeUndef=true)
Overload that takes an explicit value OldValue for when the value in MLoc has changed and the Transfe...
SmallVector< Transfer, 32 > Transfers
Collection of transfers (DBG_VALUEs) to be inserted.
bool ShouldEmitDebugEntryValues
void redefVar(const MachineInstr &MI, const DbgValueProperties &Properties, SmallVectorImpl< ResolvedDbgOp > &NewLocs)
Handle a change in variable location within a block.
void loadVarInloc(MachineBasicBlock &MBB, DbgOpIDMap &DbgOpStore, const SmallVectorImpl< ValueLocPair > &ValueToLoc, DebugVariableID VarID, DbgValue Value)
For a variable Var with the live-in value Value, attempts to resolve the DbgValue to a concrete DBG_V...
std::pair< ValueIDNum, LocationAndQuality > ValueLocPair
static bool ValueToLocSort(const ValueLocPair &A, const ValueLocPair &B)
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...
bool test(unsigned Idx) const
iterator_range< const_set_bits_iterator > set_bits() const
unsigned getNumElements() const
bool isImplicit() const
Return whether this is an implicit location description.
static bool fragmentsOverlap(const FragmentInfo &A, const FragmentInfo &B)
Check if fragments overlap between a pair of FragmentInfos.
static DIExpression * appendOpsToArg(const DIExpression *Expr, ArrayRef< uint64_t > Ops, unsigned ArgNo, bool StackValue=false)
Create a copy of Expr by appending the given list of Ops to each instance of the operand DW_OP_LLVM_a...
bool isComplex() const
Return whether the location is computed on the expression stack, meaning it cannot be a simple regist...
static std::optional< FragmentInfo > getFragmentInfo(expr_op_iterator Start, expr_op_iterator End)
Retrieve the details of this fragment expression.
static std::optional< const DIExpression * > convertToNonVariadicExpression(const DIExpression *Expr)
If Expr is a valid single-location expression, i.e.
bool isDeref() const
Return whether there is exactly one operator and it is a DW_OP_deref;.
static DIExpression * prepend(const DIExpression *Expr, uint8_t Flags, int64_t Offset=0)
Prepend DIExpr with a deref and offset operation and optionally turn it into a stack value or/and an ...
bool isSingleLocationExpression() const
Return whether the evaluated expression makes use of a single location at the start of the expression...
DILocalScope * getScope() const
Get the local scope for this variable.
bool isValidLocationForIntrinsic(const DILocation *DL) const
Check that a location is valid for this variable.
std::optional< uint64_t > getSizeInBits() const
Determines the size of the variable's type.
This class represents an Operation in the Expression.
Identifies a unique instance of a variable.
const DILocation * getInlinedAt() const
std::optional< FragmentInfo > getFragment() const
const DILocalVariable * getVariable() const
iterator find(const_arg_type_t< KeyT > Val)
bool erase(const KeyT &Val)
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.
DISubprogram * getSubprogram() const
Get the attached subprogram.
LLVMContext & getContext() const
getContext - Return a reference to the LLVMContext associated with this function.
Determine the iterated dominance frontier, given a set of defining blocks, and optionally,...
StorageT::size_type size() const
This is an important class for using LLVM in a threaded context.
LexicalScope - This class is used to track scope information.
unsigned getDFSIn() const
SmallVectorImpl< LexicalScope * > & getChildren()
unsigned getDFSOut() const
void initialize(const MachineFunction &)
initialize - Scan machine function and constuct lexical scope nest, resets the instance if necessary.
LexicalScope * findLexicalScope(const DILocation *DL)
findLexicalScope - Find lexical scope, either regular or inlined, for the given DebugLoc.
void getMachineBasicBlocks(const DILocation *DL, SmallPtrSetImpl< const MachineBasicBlock * > &MBBs)
getMachineBasicBlocks - Populate given set using machine basic blocks which have machine instructions...
LexicalScope * getCurrentFunctionScope() const
getCurrentFunctionScope - Return lexical scope for the current function.
TypeSize getValue() const
Describe properties that are true of each instruction in the target description file.
const MCInstrDesc & get(unsigned Opcode) const
Return the machine instruction descriptor that corresponds to the specified instruction opcode.
MCRegAliasIterator enumerates all registers aliasing Reg.
MCRegUnitRootIterator enumerates the root registers of a register unit.
bool isValid() const
Check if the iterator is at the end of the list.
unsigned getNumSubRegIndices() const
Return the number of sub-register indices understood by the target.
iterator_range< MCSubRegIterator > subregs(MCRegister Reg) const
Return an iterator range over all sub-registers of Reg, excluding Reg.
unsigned getSubRegIndex(MCRegister RegNo, MCRegister SubRegNo) const
For a given register pair, return the sub-register index if the second register is a sub-register of ...
iterator_range< MCRegUnitIterator > regunits(MCRegister Reg) const
Returns an iterator range over all regunits for Reg.
unsigned getNumRegs() const
Return the number of registers this target has (useful for sizing arrays holding per register informa...
Iterator that enumerates the sub-registers of a Reg and the associated sub-register indices.
bool isValid() const
Returns true if this iterator is not yet at the end.
LLVMContext & getContext() const
instr_iterator instr_begin()
SmallVectorImpl< MachineBasicBlock * >::const_iterator const_succ_iterator
instr_iterator insert(instr_iterator I, MachineInstr *M)
Insert MI into the instruction list before I, possibly inside a bundle.
int getNumber() const
MachineBasicBlocks are uniquely numbered at the function level, unless they're not in a MachineFuncti...
succ_iterator succ_begin()
bool isEntryBlock() const
Returns true if this is the entry block of the function.
SmallVectorImpl< MachineBasicBlock * >::iterator pred_iterator
Instructions::iterator instr_iterator
const MachineFunction * getParent() const
Return the MachineFunction containing this basic block.
std::string getFullName() const
Return a formatted string to identify this block and its parent function.
iterator_range< succ_iterator > successors()
iterator_range< pred_iterator > predecessors()
instr_iterator insertAfterBundle(instr_iterator I, MachineInstr *MI)
If I is bundled then insert MI into the instruction list after the end of the bundle,...
DominatorTree Class - Concrete subclass of DominatorTreeBase that is used to compute a normal dominat...
bool properlyDominates(const MachineDomTreeNode *A, const MachineDomTreeNode *B) const
MachineDominatorTree & getBase()
bool adjustsStack() const
Return true if this function adjusts the stack – e.g., when calling another function.
bool isDeadObjectIndex(int ObjectIdx) const
Returns true if the specified index corresponds to a dead object.
Replacement definition for a debug instruction reference.
SmallVector< DebugSubstitution, 8 > DebugValueSubstitutions
Debug value substitutions: a collection of DebugSubstitution objects, recording changes in where a va...
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
MachineFrameInfo & getFrameInfo()
getFrameInfo - Return the frame info object for the current function.