1838b4a53SJeremy Morse //===- InstrRefBasedImpl.h - Tracking Debug Value MIs ---------------------===// 2838b4a53SJeremy Morse // 3838b4a53SJeremy Morse // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4838b4a53SJeremy Morse // See https://llvm.org/LICENSE.txt for license information. 5838b4a53SJeremy Morse // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6838b4a53SJeremy Morse // 7838b4a53SJeremy Morse //===----------------------------------------------------------------------===// 8838b4a53SJeremy Morse 9838b4a53SJeremy Morse #ifndef LLVM_LIB_CODEGEN_LIVEDEBUGVALUES_INSTRREFBASEDLDV_H 10838b4a53SJeremy Morse #define LLVM_LIB_CODEGEN_LIVEDEBUGVALUES_INSTRREFBASEDLDV_H 11838b4a53SJeremy Morse 12838b4a53SJeremy Morse #include "llvm/ADT/DenseMap.h" 13989f1c72Sserge-sans-paille #include "llvm/ADT/IndexedMap.h" 14838b4a53SJeremy Morse #include "llvm/ADT/SmallPtrSet.h" 15838b4a53SJeremy Morse #include "llvm/ADT/SmallVector.h" 16838b4a53SJeremy Morse #include "llvm/ADT/UniqueVector.h" 17838b4a53SJeremy Morse #include "llvm/CodeGen/LexicalScopes.h" 18838b4a53SJeremy Morse #include "llvm/CodeGen/MachineBasicBlock.h" 19838b4a53SJeremy Morse #include "llvm/CodeGen/MachineInstr.h" 20989f1c72Sserge-sans-paille #include "llvm/CodeGen/TargetRegisterInfo.h" 21838b4a53SJeremy Morse #include "llvm/IR/DebugInfoMetadata.h" 220ca43d44SKrzysztof Parzyszek #include <optional> 23838b4a53SJeremy Morse 24838b4a53SJeremy Morse #include "LiveDebugValues.h" 25838b4a53SJeremy Morse 26838b4a53SJeremy Morse class TransferTracker; 27838b4a53SJeremy Morse 28838b4a53SJeremy Morse // Forward dec of unit test class, so that we can peer into the LDV object. 29838b4a53SJeremy Morse class InstrRefLDVTest; 30838b4a53SJeremy Morse 31838b4a53SJeremy Morse namespace LiveDebugValues { 32838b4a53SJeremy Morse 33838b4a53SJeremy Morse class MLocTracker; 34b5ba5d2aSStephen Tozer class DbgOpIDMap; 35838b4a53SJeremy Morse 36838b4a53SJeremy Morse using namespace llvm; 37838b4a53SJeremy Morse 38676efd0fSJeremy Morse using DebugVariableID = unsigned; 39676efd0fSJeremy Morse using VarAndLoc = std::pair<DebugVariable, const DILocation *>; 40676efd0fSJeremy Morse 41676efd0fSJeremy Morse /// Mapping from DebugVariable to/from a unique identifying number. Each 42676efd0fSJeremy Morse /// DebugVariable consists of three pointers, and after a small amount of 43676efd0fSJeremy Morse /// work to identify overlapping fragments of variables we mostly only use 44676efd0fSJeremy Morse /// DebugVariables as identities of variables. It's much more compile-time 45676efd0fSJeremy Morse /// efficient to use an ID number instead, which this class provides. 46676efd0fSJeremy Morse class DebugVariableMap { 47676efd0fSJeremy Morse DenseMap<DebugVariable, unsigned> VarToIdx; 48676efd0fSJeremy Morse SmallVector<VarAndLoc> IdxToVar; 49676efd0fSJeremy Morse 50676efd0fSJeremy Morse public: 51676efd0fSJeremy Morse DebugVariableID getDVID(const DebugVariable &Var) const { 52676efd0fSJeremy Morse auto It = VarToIdx.find(Var); 53676efd0fSJeremy Morse assert(It != VarToIdx.end()); 54676efd0fSJeremy Morse return It->second; 55676efd0fSJeremy Morse } 56676efd0fSJeremy Morse 57676efd0fSJeremy Morse DebugVariableID insertDVID(DebugVariable &Var, const DILocation *Loc) { 58676efd0fSJeremy Morse unsigned Size = VarToIdx.size(); 59676efd0fSJeremy Morse auto ItPair = VarToIdx.insert({Var, Size}); 60676efd0fSJeremy Morse if (ItPair.second) { 61676efd0fSJeremy Morse IdxToVar.push_back({Var, Loc}); 62676efd0fSJeremy Morse return Size; 63676efd0fSJeremy Morse } 64676efd0fSJeremy Morse 65676efd0fSJeremy Morse return ItPair.first->second; 66676efd0fSJeremy Morse } 67676efd0fSJeremy Morse 68676efd0fSJeremy Morse const VarAndLoc &lookupDVID(DebugVariableID ID) const { return IdxToVar[ID]; } 69676efd0fSJeremy Morse 70676efd0fSJeremy Morse void clear() { 71676efd0fSJeremy Morse VarToIdx.clear(); 72676efd0fSJeremy Morse IdxToVar.clear(); 73676efd0fSJeremy Morse } 74676efd0fSJeremy Morse }; 75676efd0fSJeremy Morse 76838b4a53SJeremy Morse /// Handle-class for a particular "location". This value-type uniquely 77838b4a53SJeremy Morse /// symbolises a register or stack location, allowing manipulation of locations 78838b4a53SJeremy Morse /// without concern for where that location is. Practically, this allows us to 79838b4a53SJeremy Morse /// treat the state of the machine at a particular point as an array of values, 80838b4a53SJeremy Morse /// rather than a map of values. 81838b4a53SJeremy Morse class LocIdx { 82838b4a53SJeremy Morse unsigned Location; 83838b4a53SJeremy Morse 84838b4a53SJeremy Morse // Default constructor is private, initializing to an illegal location number. 85838b4a53SJeremy Morse // Use only for "not an entry" elements in IndexedMaps. 86838b4a53SJeremy Morse LocIdx() : Location(UINT_MAX) {} 87838b4a53SJeremy Morse 88838b4a53SJeremy Morse public: 89838b4a53SJeremy Morse #define NUM_LOC_BITS 24 90838b4a53SJeremy Morse LocIdx(unsigned L) : Location(L) { 91838b4a53SJeremy Morse assert(L < (1 << NUM_LOC_BITS) && "Machine locations must fit in 24 bits"); 92838b4a53SJeremy Morse } 93838b4a53SJeremy Morse 94838b4a53SJeremy Morse static LocIdx MakeIllegalLoc() { return LocIdx(); } 954136897bSJeremy Morse static LocIdx MakeTombstoneLoc() { 964136897bSJeremy Morse LocIdx L = LocIdx(); 974136897bSJeremy Morse --L.Location; 984136897bSJeremy Morse return L; 994136897bSJeremy Morse } 100838b4a53SJeremy Morse 101838b4a53SJeremy Morse bool isIllegal() const { return Location == UINT_MAX; } 102838b4a53SJeremy Morse 103838b4a53SJeremy Morse uint64_t asU64() const { return Location; } 104838b4a53SJeremy Morse 105838b4a53SJeremy Morse bool operator==(unsigned L) const { return Location == L; } 106838b4a53SJeremy Morse 107838b4a53SJeremy Morse bool operator==(const LocIdx &L) const { return Location == L.Location; } 108838b4a53SJeremy Morse 109838b4a53SJeremy Morse bool operator!=(unsigned L) const { return !(*this == L); } 110838b4a53SJeremy Morse 111838b4a53SJeremy Morse bool operator!=(const LocIdx &L) const { return !(*this == L); } 112838b4a53SJeremy Morse 113838b4a53SJeremy Morse bool operator<(const LocIdx &Other) const { 114838b4a53SJeremy Morse return Location < Other.Location; 115838b4a53SJeremy Morse } 116838b4a53SJeremy Morse }; 117838b4a53SJeremy Morse 118838b4a53SJeremy Morse // The location at which a spilled value resides. It consists of a register and 119838b4a53SJeremy Morse // an offset. 120838b4a53SJeremy Morse struct SpillLoc { 121838b4a53SJeremy Morse unsigned SpillBase; 122838b4a53SJeremy Morse StackOffset SpillOffset; 123838b4a53SJeremy Morse bool operator==(const SpillLoc &Other) const { 124838b4a53SJeremy Morse return std::make_pair(SpillBase, SpillOffset) == 125838b4a53SJeremy Morse std::make_pair(Other.SpillBase, Other.SpillOffset); 126838b4a53SJeremy Morse } 127838b4a53SJeremy Morse bool operator<(const SpillLoc &Other) const { 128838b4a53SJeremy Morse return std::make_tuple(SpillBase, SpillOffset.getFixed(), 129838b4a53SJeremy Morse SpillOffset.getScalable()) < 130838b4a53SJeremy Morse std::make_tuple(Other.SpillBase, Other.SpillOffset.getFixed(), 131838b4a53SJeremy Morse Other.SpillOffset.getScalable()); 132838b4a53SJeremy Morse } 133838b4a53SJeremy Morse }; 134838b4a53SJeremy Morse 135838b4a53SJeremy Morse /// Unique identifier for a value defined by an instruction, as a value type. 136838b4a53SJeremy Morse /// Casts back and forth to a uint64_t. Probably replacable with something less 137838b4a53SJeremy Morse /// bit-constrained. Each value identifies the instruction and machine location 138838b4a53SJeremy Morse /// where the value is defined, although there may be no corresponding machine 139838b4a53SJeremy Morse /// operand for it (ex: regmasks clobbering values). The instructions are 140838b4a53SJeremy Morse /// one-based, and definitions that are PHIs have instruction number zero. 141838b4a53SJeremy Morse /// 142838b4a53SJeremy Morse /// The obvious limits of a 1M block function or 1M instruction blocks are 143838b4a53SJeremy Morse /// problematic; but by that point we should probably have bailed out of 144838b4a53SJeremy Morse /// trying to analyse the function. 145838b4a53SJeremy Morse class ValueIDNum { 1464136897bSJeremy Morse union { 1474136897bSJeremy Morse struct { 148838b4a53SJeremy Morse uint64_t BlockNo : 20; /// The block where the def happens. 149838b4a53SJeremy Morse uint64_t InstNo : 20; /// The Instruction where the def happens. 150838b4a53SJeremy Morse /// One based, is distance from start of block. 1514136897bSJeremy Morse uint64_t LocNo 1524136897bSJeremy Morse : NUM_LOC_BITS; /// The machine location where the def happens. 1534136897bSJeremy Morse } s; 1544136897bSJeremy Morse uint64_t Value; 1554136897bSJeremy Morse } u; 1564136897bSJeremy Morse 1574136897bSJeremy Morse static_assert(sizeof(u) == 8, "Badly packed ValueIDNum?"); 158838b4a53SJeremy Morse 159838b4a53SJeremy Morse public: 160838b4a53SJeremy Morse // Default-initialize to EmptyValue. This is necessary to make IndexedMaps 161838b4a53SJeremy Morse // of values to work. 1624136897bSJeremy Morse ValueIDNum() { u.Value = EmptyValue.asU64(); } 163838b4a53SJeremy Morse 1644136897bSJeremy Morse ValueIDNum(uint64_t Block, uint64_t Inst, uint64_t Loc) { 1654136897bSJeremy Morse u.s = {Block, Inst, Loc}; 166838b4a53SJeremy Morse } 167838b4a53SJeremy Morse 1684136897bSJeremy Morse ValueIDNum(uint64_t Block, uint64_t Inst, LocIdx Loc) { 1694136897bSJeremy Morse u.s = {Block, Inst, Loc.asU64()}; 1704136897bSJeremy Morse } 1714136897bSJeremy Morse 1724136897bSJeremy Morse uint64_t getBlock() const { return u.s.BlockNo; } 1734136897bSJeremy Morse uint64_t getInst() const { return u.s.InstNo; } 1744136897bSJeremy Morse uint64_t getLoc() const { return u.s.LocNo; } 1754136897bSJeremy Morse bool isPHI() const { return u.s.InstNo == 0; } 1764136897bSJeremy Morse 1774136897bSJeremy Morse uint64_t asU64() const { return u.Value; } 1784136897bSJeremy Morse 179838b4a53SJeremy Morse static ValueIDNum fromU64(uint64_t v) { 1804136897bSJeremy Morse ValueIDNum Val; 1814136897bSJeremy Morse Val.u.Value = v; 1824136897bSJeremy Morse return Val; 183838b4a53SJeremy Morse } 184838b4a53SJeremy Morse 185838b4a53SJeremy Morse bool operator<(const ValueIDNum &Other) const { 186838b4a53SJeremy Morse return asU64() < Other.asU64(); 187838b4a53SJeremy Morse } 188838b4a53SJeremy Morse 189838b4a53SJeremy Morse bool operator==(const ValueIDNum &Other) const { 1904136897bSJeremy Morse return u.Value == Other.u.Value; 191838b4a53SJeremy Morse } 192838b4a53SJeremy Morse 193838b4a53SJeremy Morse bool operator!=(const ValueIDNum &Other) const { return !(*this == Other); } 194838b4a53SJeremy Morse 195838b4a53SJeremy Morse std::string asString(const std::string &mlocname) const { 196838b4a53SJeremy Morse return Twine("Value{bb: ") 1974136897bSJeremy Morse .concat(Twine(u.s.BlockNo) 1984136897bSJeremy Morse .concat(Twine(", inst: ") 1994136897bSJeremy Morse .concat((u.s.InstNo ? Twine(u.s.InstNo) 2004136897bSJeremy Morse : Twine("live-in")) 2014136897bSJeremy Morse .concat(Twine(", loc: ").concat( 2024136897bSJeremy Morse Twine(mlocname))) 203838b4a53SJeremy Morse .concat(Twine("}"))))) 204838b4a53SJeremy Morse .str(); 205838b4a53SJeremy Morse } 206838b4a53SJeremy Morse 207838b4a53SJeremy Morse static ValueIDNum EmptyValue; 2084136897bSJeremy Morse static ValueIDNum TombstoneValue; 209838b4a53SJeremy Morse }; 210838b4a53SJeremy Morse 211b5ba5d2aSStephen Tozer } // End namespace LiveDebugValues 212b5ba5d2aSStephen Tozer 213b5ba5d2aSStephen Tozer namespace llvm { 214b5ba5d2aSStephen Tozer using namespace LiveDebugValues; 215b5ba5d2aSStephen Tozer 216b5ba5d2aSStephen Tozer template <> struct DenseMapInfo<LocIdx> { 217b5ba5d2aSStephen Tozer static inline LocIdx getEmptyKey() { return LocIdx::MakeIllegalLoc(); } 218b5ba5d2aSStephen Tozer static inline LocIdx getTombstoneKey() { return LocIdx::MakeTombstoneLoc(); } 219b5ba5d2aSStephen Tozer 220b5ba5d2aSStephen Tozer static unsigned getHashValue(const LocIdx &Loc) { return Loc.asU64(); } 221b5ba5d2aSStephen Tozer 222b5ba5d2aSStephen Tozer static bool isEqual(const LocIdx &A, const LocIdx &B) { return A == B; } 223b5ba5d2aSStephen Tozer }; 224b5ba5d2aSStephen Tozer 225b5ba5d2aSStephen Tozer template <> struct DenseMapInfo<ValueIDNum> { 226b5ba5d2aSStephen Tozer static inline ValueIDNum getEmptyKey() { return ValueIDNum::EmptyValue; } 227b5ba5d2aSStephen Tozer static inline ValueIDNum getTombstoneKey() { 228b5ba5d2aSStephen Tozer return ValueIDNum::TombstoneValue; 229b5ba5d2aSStephen Tozer } 230b5ba5d2aSStephen Tozer 231b5ba5d2aSStephen Tozer static unsigned getHashValue(const ValueIDNum &Val) { 232b5ba5d2aSStephen Tozer return hash_value(Val.asU64()); 233b5ba5d2aSStephen Tozer } 234b5ba5d2aSStephen Tozer 235b5ba5d2aSStephen Tozer static bool isEqual(const ValueIDNum &A, const ValueIDNum &B) { 236b5ba5d2aSStephen Tozer return A == B; 237b5ba5d2aSStephen Tozer } 238b5ba5d2aSStephen Tozer }; 239b5ba5d2aSStephen Tozer 240b5ba5d2aSStephen Tozer } // end namespace llvm 241b5ba5d2aSStephen Tozer 242b5ba5d2aSStephen Tozer namespace LiveDebugValues { 243b5ba5d2aSStephen Tozer using namespace llvm; 244b5ba5d2aSStephen Tozer 245ab49dce0SJeremy Morse /// Type for a table of values in a block. 2461b531d54SFelipe de Azevedo Piovezan using ValueTable = SmallVector<ValueIDNum, 0>; 247ab49dce0SJeremy Morse 248acacec3bSFelipe de Azevedo Piovezan /// A collection of ValueTables, one per BB in a function, with convenient 249acacec3bSFelipe de Azevedo Piovezan /// accessor methods. 250acacec3bSFelipe de Azevedo Piovezan struct FuncValueTable { 251acacec3bSFelipe de Azevedo Piovezan FuncValueTable(int NumBBs, int NumLocs) { 252acacec3bSFelipe de Azevedo Piovezan Storage.reserve(NumBBs); 253acacec3bSFelipe de Azevedo Piovezan for (int i = 0; i != NumBBs; ++i) 254acacec3bSFelipe de Azevedo Piovezan Storage.push_back( 255acacec3bSFelipe de Azevedo Piovezan std::make_unique<ValueTable>(NumLocs, ValueIDNum::EmptyValue)); 256acacec3bSFelipe de Azevedo Piovezan } 257acacec3bSFelipe de Azevedo Piovezan 258acacec3bSFelipe de Azevedo Piovezan /// Returns the ValueTable associated with MBB. 259acacec3bSFelipe de Azevedo Piovezan ValueTable &operator[](const MachineBasicBlock &MBB) const { 260acacec3bSFelipe de Azevedo Piovezan return (*this)[MBB.getNumber()]; 261acacec3bSFelipe de Azevedo Piovezan } 262acacec3bSFelipe de Azevedo Piovezan 263acacec3bSFelipe de Azevedo Piovezan /// Returns the ValueTable associated with the MachineBasicBlock whose number 264acacec3bSFelipe de Azevedo Piovezan /// is MBBNum. 265acacec3bSFelipe de Azevedo Piovezan ValueTable &operator[](int MBBNum) const { 266acacec3bSFelipe de Azevedo Piovezan auto &TablePtr = Storage[MBBNum]; 267acacec3bSFelipe de Azevedo Piovezan assert(TablePtr && "Trying to access a deleted table"); 268acacec3bSFelipe de Azevedo Piovezan return *TablePtr; 269acacec3bSFelipe de Azevedo Piovezan } 270acacec3bSFelipe de Azevedo Piovezan 271acacec3bSFelipe de Azevedo Piovezan /// Returns the ValueTable associated with the entry MachineBasicBlock. 272acacec3bSFelipe de Azevedo Piovezan ValueTable &tableForEntryMBB() const { return (*this)[0]; } 273acacec3bSFelipe de Azevedo Piovezan 274acacec3bSFelipe de Azevedo Piovezan /// Returns true if the ValueTable associated with MBB has not been freed. 275acacec3bSFelipe de Azevedo Piovezan bool hasTableFor(MachineBasicBlock &MBB) const { 276acacec3bSFelipe de Azevedo Piovezan return Storage[MBB.getNumber()] != nullptr; 277acacec3bSFelipe de Azevedo Piovezan } 278acacec3bSFelipe de Azevedo Piovezan 279acacec3bSFelipe de Azevedo Piovezan /// Frees the memory of the ValueTable associated with MBB. 280acacec3bSFelipe de Azevedo Piovezan void ejectTableForBlock(const MachineBasicBlock &MBB) { 281acacec3bSFelipe de Azevedo Piovezan Storage[MBB.getNumber()].reset(); 282acacec3bSFelipe de Azevedo Piovezan } 283acacec3bSFelipe de Azevedo Piovezan 284acacec3bSFelipe de Azevedo Piovezan private: 285acacec3bSFelipe de Azevedo Piovezan /// ValueTables are stored as unique_ptrs to allow for deallocation during 286acacec3bSFelipe de Azevedo Piovezan /// LDV; this was measured to have a significant impact on compiler memory 287acacec3bSFelipe de Azevedo Piovezan /// usage. 288acacec3bSFelipe de Azevedo Piovezan SmallVector<std::unique_ptr<ValueTable>, 0> Storage; 289acacec3bSFelipe de Azevedo Piovezan }; 290ab49dce0SJeremy Morse 291e7084ceaSJeremy Morse /// Thin wrapper around an integer -- designed to give more type safety to 292e7084ceaSJeremy Morse /// spill location numbers. 293e7084ceaSJeremy Morse class SpillLocationNo { 294e7084ceaSJeremy Morse public: 295e7084ceaSJeremy Morse explicit SpillLocationNo(unsigned SpillNo) : SpillNo(SpillNo) {} 296e7084ceaSJeremy Morse unsigned SpillNo; 297e7084ceaSJeremy Morse unsigned id() const { return SpillNo; } 298e7084ceaSJeremy Morse 299e7084ceaSJeremy Morse bool operator<(const SpillLocationNo &Other) const { 300e7084ceaSJeremy Morse return SpillNo < Other.SpillNo; 301e7084ceaSJeremy Morse } 302e7084ceaSJeremy Morse 303e7084ceaSJeremy Morse bool operator==(const SpillLocationNo &Other) const { 304e7084ceaSJeremy Morse return SpillNo == Other.SpillNo; 305e7084ceaSJeremy Morse } 306e7084ceaSJeremy Morse bool operator!=(const SpillLocationNo &Other) const { 307e7084ceaSJeremy Morse return !(*this == Other); 308e7084ceaSJeremy Morse } 309e7084ceaSJeremy Morse }; 310e7084ceaSJeremy Morse 311838b4a53SJeremy Morse /// Meta qualifiers for a value. Pair of whatever expression is used to qualify 31287a55137SBrian Tracy /// the value, and Boolean of whether or not it's indirect. 313838b4a53SJeremy Morse class DbgValueProperties { 314838b4a53SJeremy Morse public: 31511ce014aSStephen Tozer DbgValueProperties(const DIExpression *DIExpr, bool Indirect, bool IsVariadic) 31611ce014aSStephen Tozer : DIExpr(DIExpr), Indirect(Indirect), IsVariadic(IsVariadic) {} 317838b4a53SJeremy Morse 318838b4a53SJeremy Morse /// Extract properties from an existing DBG_VALUE instruction. 319838b4a53SJeremy Morse DbgValueProperties(const MachineInstr &MI) { 320838b4a53SJeremy Morse assert(MI.isDebugValue()); 32111ce014aSStephen Tozer assert(MI.getDebugExpression()->getNumLocationOperands() == 0 || 32211ce014aSStephen Tozer MI.isDebugValueList() || MI.isUndefDebugValue()); 32311ce014aSStephen Tozer IsVariadic = MI.isDebugValueList(); 324838b4a53SJeremy Morse DIExpr = MI.getDebugExpression(); 32511ce014aSStephen Tozer Indirect = MI.isDebugOffsetImm(); 326838b4a53SJeremy Morse } 327838b4a53SJeremy Morse 3286d169089SStephen Tozer bool isJoinable(const DbgValueProperties &Other) const { 3296d169089SStephen Tozer return DIExpression::isEqualExpression(DIExpr, Indirect, Other.DIExpr, 3306d169089SStephen Tozer Other.Indirect); 3316d169089SStephen Tozer } 3326d169089SStephen Tozer 333838b4a53SJeremy Morse bool operator==(const DbgValueProperties &Other) const { 33411ce014aSStephen Tozer return std::tie(DIExpr, Indirect, IsVariadic) == 33511ce014aSStephen Tozer std::tie(Other.DIExpr, Other.Indirect, Other.IsVariadic); 336838b4a53SJeremy Morse } 337838b4a53SJeremy Morse 338838b4a53SJeremy Morse bool operator!=(const DbgValueProperties &Other) const { 339838b4a53SJeremy Morse return !(*this == Other); 340838b4a53SJeremy Morse } 341838b4a53SJeremy Morse 34211ce014aSStephen Tozer unsigned getLocationOpCount() const { 34311ce014aSStephen Tozer return IsVariadic ? DIExpr->getNumLocationOperands() : 1; 34411ce014aSStephen Tozer } 34511ce014aSStephen Tozer 346838b4a53SJeremy Morse const DIExpression *DIExpr; 347838b4a53SJeremy Morse bool Indirect; 34811ce014aSStephen Tozer bool IsVariadic; 349838b4a53SJeremy Morse }; 350838b4a53SJeremy Morse 351b5ba5d2aSStephen Tozer /// TODO: Might pack better if we changed this to a Struct of Arrays, since 352b5ba5d2aSStephen Tozer /// MachineOperand is width 32, making this struct width 33. We could also 353b5ba5d2aSStephen Tozer /// potentially avoid storing the whole MachineOperand (sizeof=32), instead 354b5ba5d2aSStephen Tozer /// choosing to store just the contents portion (sizeof=8) and a Kind enum, 355b5ba5d2aSStephen Tozer /// since we already know it is some type of immediate value. 356b5ba5d2aSStephen Tozer /// Stores a single debug operand, which can either be a MachineOperand for 357b5ba5d2aSStephen Tozer /// directly storing immediate values, or a ValueIDNum representing some value 358b5ba5d2aSStephen Tozer /// computed at some point in the program. IsConst is used as a discriminator. 359b5ba5d2aSStephen Tozer struct DbgOp { 360b5ba5d2aSStephen Tozer union { 361b5ba5d2aSStephen Tozer ValueIDNum ID; 362b5ba5d2aSStephen Tozer MachineOperand MO; 363b5ba5d2aSStephen Tozer }; 364b5ba5d2aSStephen Tozer bool IsConst; 365b5ba5d2aSStephen Tozer 366b5ba5d2aSStephen Tozer DbgOp() : ID(ValueIDNum::EmptyValue), IsConst(false) {} 367b5ba5d2aSStephen Tozer DbgOp(ValueIDNum ID) : ID(ID), IsConst(false) {} 368b5ba5d2aSStephen Tozer DbgOp(MachineOperand MO) : MO(MO), IsConst(true) {} 369b5ba5d2aSStephen Tozer 370b5ba5d2aSStephen Tozer bool isUndef() const { return !IsConst && ID == ValueIDNum::EmptyValue; } 371b5ba5d2aSStephen Tozer 372b5ba5d2aSStephen Tozer #ifndef NDEBUG 373b5ba5d2aSStephen Tozer void dump(const MLocTracker *MTrack) const; 374b5ba5d2aSStephen Tozer #endif 375b5ba5d2aSStephen Tozer }; 376b5ba5d2aSStephen Tozer 377b5ba5d2aSStephen Tozer /// A DbgOp whose ID (if any) has resolved to an actual location, LocIdx. Used 378b5ba5d2aSStephen Tozer /// when working with concrete debug values, i.e. when joining MLocs and VLocs 379b5ba5d2aSStephen Tozer /// in the TransferTracker or emitting DBG_VALUE/DBG_VALUE_LIST instructions in 380b5ba5d2aSStephen Tozer /// the MLocTracker. 381b5ba5d2aSStephen Tozer struct ResolvedDbgOp { 382b5ba5d2aSStephen Tozer union { 383b5ba5d2aSStephen Tozer LocIdx Loc; 384b5ba5d2aSStephen Tozer MachineOperand MO; 385b5ba5d2aSStephen Tozer }; 386b5ba5d2aSStephen Tozer bool IsConst; 387b5ba5d2aSStephen Tozer 388b5ba5d2aSStephen Tozer ResolvedDbgOp(LocIdx Loc) : Loc(Loc), IsConst(false) {} 389b5ba5d2aSStephen Tozer ResolvedDbgOp(MachineOperand MO) : MO(MO), IsConst(true) {} 390b5ba5d2aSStephen Tozer 391b5ba5d2aSStephen Tozer bool operator==(const ResolvedDbgOp &Other) const { 392b5ba5d2aSStephen Tozer if (IsConst != Other.IsConst) 393b5ba5d2aSStephen Tozer return false; 394b5ba5d2aSStephen Tozer if (IsConst) 395b5ba5d2aSStephen Tozer return MO.isIdenticalTo(Other.MO); 396b5ba5d2aSStephen Tozer return Loc == Other.Loc; 397b5ba5d2aSStephen Tozer } 398b5ba5d2aSStephen Tozer 399b5ba5d2aSStephen Tozer #ifndef NDEBUG 400b5ba5d2aSStephen Tozer void dump(const MLocTracker *MTrack) const; 401b5ba5d2aSStephen Tozer #endif 402b5ba5d2aSStephen Tozer }; 403b5ba5d2aSStephen Tozer 404b5ba5d2aSStephen Tozer /// An ID used in the DbgOpIDMap (below) to lookup a stored DbgOp. This is used 405b5ba5d2aSStephen Tozer /// in place of actual DbgOps inside of a DbgValue to reduce its size, as 406b5ba5d2aSStephen Tozer /// DbgValue is very frequently used and passed around, and the actual DbgOp is 407b5ba5d2aSStephen Tozer /// over 8x larger than this class, due to storing a MachineOperand. This ID 408b5ba5d2aSStephen Tozer /// should be equal for all equal DbgOps, and also encodes whether the mapped 409b5ba5d2aSStephen Tozer /// DbgOp is a constant, meaning that for simple equality or const-ness checks 410b5ba5d2aSStephen Tozer /// it is not necessary to lookup this ID. 411b5ba5d2aSStephen Tozer struct DbgOpID { 41236ec4decSKazu Hirata struct IsConstIndexPair { 413b5ba5d2aSStephen Tozer uint32_t IsConst : 1; 414b5ba5d2aSStephen Tozer uint32_t Index : 31; 41536ec4decSKazu Hirata }; 41636ec4decSKazu Hirata 41736ec4decSKazu Hirata union { 41836ec4decSKazu Hirata struct IsConstIndexPair ID; 419b5ba5d2aSStephen Tozer uint32_t RawID; 420b5ba5d2aSStephen Tozer }; 421b5ba5d2aSStephen Tozer 422b5ba5d2aSStephen Tozer DbgOpID() : RawID(UndefID.RawID) { 423b5ba5d2aSStephen Tozer static_assert(sizeof(DbgOpID) == 4, "DbgOpID should fit within 4 bytes."); 424b5ba5d2aSStephen Tozer } 425b5ba5d2aSStephen Tozer DbgOpID(uint32_t RawID) : RawID(RawID) {} 426b5ba5d2aSStephen Tozer DbgOpID(bool IsConst, uint32_t Index) : ID({IsConst, Index}) {} 427b5ba5d2aSStephen Tozer 428b5ba5d2aSStephen Tozer static DbgOpID UndefID; 429b5ba5d2aSStephen Tozer 430b5ba5d2aSStephen Tozer bool operator==(const DbgOpID &Other) const { return RawID == Other.RawID; } 431b5ba5d2aSStephen Tozer bool operator!=(const DbgOpID &Other) const { return !(*this == Other); } 432b5ba5d2aSStephen Tozer 433b5ba5d2aSStephen Tozer uint32_t asU32() const { return RawID; } 434b5ba5d2aSStephen Tozer 435b5ba5d2aSStephen Tozer bool isUndef() const { return *this == UndefID; } 436b5ba5d2aSStephen Tozer bool isConst() const { return ID.IsConst && !isUndef(); } 437b5ba5d2aSStephen Tozer uint32_t getIndex() const { return ID.Index; } 438b5ba5d2aSStephen Tozer 439b5ba5d2aSStephen Tozer #ifndef NDEBUG 440b5ba5d2aSStephen Tozer void dump(const MLocTracker *MTrack, const DbgOpIDMap *OpStore) const; 441b5ba5d2aSStephen Tozer #endif 442b5ba5d2aSStephen Tozer }; 443b5ba5d2aSStephen Tozer 444b5ba5d2aSStephen Tozer /// Class storing the complete set of values that are observed by DbgValues 445b5ba5d2aSStephen Tozer /// within the current function. Allows 2-way lookup, with `find` returning the 446b5ba5d2aSStephen Tozer /// Op for a given ID and `insert` returning the ID for a given Op (creating one 447b5ba5d2aSStephen Tozer /// if none exists). 448b5ba5d2aSStephen Tozer class DbgOpIDMap { 449b5ba5d2aSStephen Tozer 450b5ba5d2aSStephen Tozer SmallVector<ValueIDNum, 0> ValueOps; 451b5ba5d2aSStephen Tozer SmallVector<MachineOperand, 0> ConstOps; 452b5ba5d2aSStephen Tozer 453b5ba5d2aSStephen Tozer DenseMap<ValueIDNum, DbgOpID> ValueOpToID; 454b5ba5d2aSStephen Tozer DenseMap<MachineOperand, DbgOpID> ConstOpToID; 455b5ba5d2aSStephen Tozer 456b5ba5d2aSStephen Tozer public: 457b5ba5d2aSStephen Tozer /// If \p Op does not already exist in this map, it is inserted and the 458b5ba5d2aSStephen Tozer /// corresponding DbgOpID is returned. If Op already exists in this map, then 459b5ba5d2aSStephen Tozer /// no change is made and the existing ID for Op is returned. 460b5ba5d2aSStephen Tozer /// Calling this with the undef DbgOp will always return DbgOpID::UndefID. 461b5ba5d2aSStephen Tozer DbgOpID insert(DbgOp Op) { 462b5ba5d2aSStephen Tozer if (Op.isUndef()) 463b5ba5d2aSStephen Tozer return DbgOpID::UndefID; 464b5ba5d2aSStephen Tozer if (Op.IsConst) 465b5ba5d2aSStephen Tozer return insertConstOp(Op.MO); 466b5ba5d2aSStephen Tozer return insertValueOp(Op.ID); 467b5ba5d2aSStephen Tozer } 468b5ba5d2aSStephen Tozer /// Returns the DbgOp associated with \p ID. Should only be used for IDs 469b5ba5d2aSStephen Tozer /// returned from calling `insert` from this map or DbgOpID::UndefID. 470b5ba5d2aSStephen Tozer DbgOp find(DbgOpID ID) const { 471b5ba5d2aSStephen Tozer if (ID == DbgOpID::UndefID) 472b5ba5d2aSStephen Tozer return DbgOp(); 473b5ba5d2aSStephen Tozer if (ID.isConst()) 474b5ba5d2aSStephen Tozer return DbgOp(ConstOps[ID.getIndex()]); 475b5ba5d2aSStephen Tozer return DbgOp(ValueOps[ID.getIndex()]); 476b5ba5d2aSStephen Tozer } 477b5ba5d2aSStephen Tozer 478b5ba5d2aSStephen Tozer void clear() { 479b5ba5d2aSStephen Tozer ValueOps.clear(); 480b5ba5d2aSStephen Tozer ConstOps.clear(); 481b5ba5d2aSStephen Tozer ValueOpToID.clear(); 482b5ba5d2aSStephen Tozer ConstOpToID.clear(); 483b5ba5d2aSStephen Tozer } 484b5ba5d2aSStephen Tozer 485b5ba5d2aSStephen Tozer private: 486b5ba5d2aSStephen Tozer DbgOpID insertConstOp(MachineOperand &MO) { 4872d7d74d9SKazu Hirata auto [It, Inserted] = ConstOpToID.try_emplace(MO, true, ConstOps.size()); 4882d7d74d9SKazu Hirata if (Inserted) 489b5ba5d2aSStephen Tozer ConstOps.push_back(MO); 4902d7d74d9SKazu Hirata return It->second; 491b5ba5d2aSStephen Tozer } 492b5ba5d2aSStephen Tozer DbgOpID insertValueOp(ValueIDNum VID) { 4932d7d74d9SKazu Hirata auto [It, Inserted] = ValueOpToID.try_emplace(VID, false, ValueOps.size()); 4942d7d74d9SKazu Hirata if (Inserted) 495b5ba5d2aSStephen Tozer ValueOps.push_back(VID); 4962d7d74d9SKazu Hirata return It->second; 497b5ba5d2aSStephen Tozer } 498b5ba5d2aSStephen Tozer }; 499b5ba5d2aSStephen Tozer 500b5ba5d2aSStephen Tozer // We set the maximum number of operands that we will handle to keep DbgValue 501b5ba5d2aSStephen Tozer // within a reasonable size (64 bytes), as we store and pass a lot of them 502b5ba5d2aSStephen Tozer // around. 503b5ba5d2aSStephen Tozer #define MAX_DBG_OPS 8 504b5ba5d2aSStephen Tozer 505b5ba5d2aSStephen Tozer /// Class recording the (high level) _value_ of a variable. Identifies the value 506b5ba5d2aSStephen Tozer /// of the variable as a list of ValueIDNums and constant MachineOperands, or as 507b5ba5d2aSStephen Tozer /// an empty list for undef debug values or VPHI values which we have not found 508b5ba5d2aSStephen Tozer /// valid locations for. 509838b4a53SJeremy Morse /// This class also stores meta-information about how the value is qualified. 510838b4a53SJeremy Morse /// Used to reason about variable values when performing the second 511838b4a53SJeremy Morse /// (DebugVariable specific) dataflow analysis. 512838b4a53SJeremy Morse class DbgValue { 513b5ba5d2aSStephen Tozer private: 514b5ba5d2aSStephen Tozer /// If Kind is Def or VPHI, the set of IDs corresponding to the DbgOps that 515b5ba5d2aSStephen Tozer /// are used. VPHIs set every ID to EmptyID when we have not found a valid 516b5ba5d2aSStephen Tozer /// machine-value for every operand, and sets them to the corresponding 517b5ba5d2aSStephen Tozer /// machine-values when we have found all of them. 518b5ba5d2aSStephen Tozer DbgOpID DbgOps[MAX_DBG_OPS]; 519b5ba5d2aSStephen Tozer unsigned OpCount; 520b5ba5d2aSStephen Tozer 521838b4a53SJeremy Morse public: 522b5426cedSJeremy Morse /// For a NoVal or VPHI DbgValue, which block it was generated in. 523b5426cedSJeremy Morse int BlockNo; 524b5426cedSJeremy Morse 525838b4a53SJeremy Morse /// Qualifiers for the ValueIDNum above. 526838b4a53SJeremy Morse DbgValueProperties Properties; 527838b4a53SJeremy Morse 528838b4a53SJeremy Morse typedef enum { 529838b4a53SJeremy Morse Undef, // Represents a DBG_VALUE $noreg in the transfer function only. 530b5ba5d2aSStephen Tozer Def, // This value is defined by some combination of constants, 531b5ba5d2aSStephen Tozer // instructions, or PHI values. 532b5426cedSJeremy Morse VPHI, // Incoming values to BlockNo differ, those values must be joined by 533b5426cedSJeremy Morse // a PHI in this block. 534b5426cedSJeremy Morse NoVal, // Empty DbgValue indicating an unknown value. Used as initializer, 535b5426cedSJeremy Morse // before dominating blocks values are propagated in. 536838b4a53SJeremy Morse } KindT; 537838b4a53SJeremy Morse /// Discriminator for whether this is a constant or an in-program value. 538838b4a53SJeremy Morse KindT Kind; 539838b4a53SJeremy Morse 540b5ba5d2aSStephen Tozer DbgValue(ArrayRef<DbgOpID> DbgOps, const DbgValueProperties &Prop) 541b5ba5d2aSStephen Tozer : OpCount(DbgOps.size()), BlockNo(0), Properties(Prop), Kind(Def) { 542b5ba5d2aSStephen Tozer static_assert(sizeof(DbgValue) <= 64, 543b5ba5d2aSStephen Tozer "DbgValue should fit within 64 bytes."); 544b5ba5d2aSStephen Tozer assert(DbgOps.size() == Prop.getLocationOpCount()); 545b5ba5d2aSStephen Tozer if (DbgOps.size() > MAX_DBG_OPS || 546b5ba5d2aSStephen Tozer any_of(DbgOps, [](DbgOpID ID) { return ID.isUndef(); })) { 547b5ba5d2aSStephen Tozer Kind = Undef; 548b5ba5d2aSStephen Tozer OpCount = 0; 549b5ba5d2aSStephen Tozer #define DEBUG_TYPE "LiveDebugValues" 550b5ba5d2aSStephen Tozer if (DbgOps.size() > MAX_DBG_OPS) { 551b5ba5d2aSStephen Tozer LLVM_DEBUG(dbgs() << "Found DbgValue with more than maximum allowed " 552b5ba5d2aSStephen Tozer "operands.\n"); 553b5ba5d2aSStephen Tozer } 554b5ba5d2aSStephen Tozer #undef DEBUG_TYPE 555b5ba5d2aSStephen Tozer } else { 556b5ba5d2aSStephen Tozer for (unsigned Idx = 0; Idx < DbgOps.size(); ++Idx) 557b5ba5d2aSStephen Tozer this->DbgOps[Idx] = DbgOps[Idx]; 558b5ba5d2aSStephen Tozer } 559838b4a53SJeremy Morse } 560838b4a53SJeremy Morse 561838b4a53SJeremy Morse DbgValue(unsigned BlockNo, const DbgValueProperties &Prop, KindT Kind) 562b5ba5d2aSStephen Tozer : OpCount(0), BlockNo(BlockNo), Properties(Prop), Kind(Kind) { 563b5426cedSJeremy Morse assert(Kind == NoVal || Kind == VPHI); 564838b4a53SJeremy Morse } 565838b4a53SJeremy Morse 566838b4a53SJeremy Morse DbgValue(const DbgValueProperties &Prop, KindT Kind) 567b5ba5d2aSStephen Tozer : OpCount(0), BlockNo(0), Properties(Prop), Kind(Kind) { 568838b4a53SJeremy Morse assert(Kind == Undef && 569838b4a53SJeremy Morse "Empty DbgValue constructor must pass in Undef kind"); 570838b4a53SJeremy Morse } 571838b4a53SJeremy Morse 572d9fa186aSJeremy Morse #ifndef NDEBUG 573b5ba5d2aSStephen Tozer void dump(const MLocTracker *MTrack = nullptr, 574b5ba5d2aSStephen Tozer const DbgOpIDMap *OpStore = nullptr) const; 575d9fa186aSJeremy Morse #endif 576838b4a53SJeremy Morse 577838b4a53SJeremy Morse bool operator==(const DbgValue &Other) const { 578838b4a53SJeremy Morse if (std::tie(Kind, Properties) != std::tie(Other.Kind, Other.Properties)) 579838b4a53SJeremy Morse return false; 580b5ba5d2aSStephen Tozer else if (Kind == Def && !equal(getDbgOpIDs(), Other.getDbgOpIDs())) 581838b4a53SJeremy Morse return false; 582838b4a53SJeremy Morse else if (Kind == NoVal && BlockNo != Other.BlockNo) 583838b4a53SJeremy Morse return false; 584b5426cedSJeremy Morse else if (Kind == VPHI && BlockNo != Other.BlockNo) 585b5426cedSJeremy Morse return false; 586b5ba5d2aSStephen Tozer else if (Kind == VPHI && !equal(getDbgOpIDs(), Other.getDbgOpIDs())) 587b5426cedSJeremy Morse return false; 588838b4a53SJeremy Morse 589838b4a53SJeremy Morse return true; 590838b4a53SJeremy Morse } 591838b4a53SJeremy Morse 592838b4a53SJeremy Morse bool operator!=(const DbgValue &Other) const { return !(*this == Other); } 593b5ba5d2aSStephen Tozer 594b5ba5d2aSStephen Tozer // Returns an array of all the machine values used to calculate this variable 595b5ba5d2aSStephen Tozer // value, or an empty list for an Undef or unjoined VPHI. 596b5ba5d2aSStephen Tozer ArrayRef<DbgOpID> getDbgOpIDs() const { return {DbgOps, OpCount}; } 597b5ba5d2aSStephen Tozer 598b5ba5d2aSStephen Tozer // Returns either DbgOps[Index] if this DbgValue has Debug Operands, or 599b5ba5d2aSStephen Tozer // the ID for ValueIDNum::EmptyValue otherwise (i.e. if this is an Undef, 600b5ba5d2aSStephen Tozer // NoVal, or an unjoined VPHI). 601b5ba5d2aSStephen Tozer DbgOpID getDbgOpID(unsigned Index) const { 602b5ba5d2aSStephen Tozer if (!OpCount) 603b5ba5d2aSStephen Tozer return DbgOpID::UndefID; 604b5ba5d2aSStephen Tozer assert(Index < OpCount); 605b5ba5d2aSStephen Tozer return DbgOps[Index]; 606b5ba5d2aSStephen Tozer } 607b5ba5d2aSStephen Tozer // Replaces this DbgValue's existing DbgOpIDs (if any) with the contents of 608b5ba5d2aSStephen Tozer // \p NewIDs. The number of DbgOpIDs passed must be equal to the number of 609b5ba5d2aSStephen Tozer // arguments expected by this DbgValue's properties (the return value of 610b5ba5d2aSStephen Tozer // `getLocationOpCount()`). 611b5ba5d2aSStephen Tozer void setDbgOpIDs(ArrayRef<DbgOpID> NewIDs) { 612b5ba5d2aSStephen Tozer // We can go from no ops to some ops, but not from some ops to no ops. 613b5ba5d2aSStephen Tozer assert(NewIDs.size() == getLocationOpCount() && 614b5ba5d2aSStephen Tozer "Incorrect number of Debug Operands for this DbgValue."); 615b5ba5d2aSStephen Tozer OpCount = NewIDs.size(); 616b5ba5d2aSStephen Tozer for (unsigned Idx = 0; Idx < NewIDs.size(); ++Idx) 617b5ba5d2aSStephen Tozer DbgOps[Idx] = NewIDs[Idx]; 618b5ba5d2aSStephen Tozer } 619b5ba5d2aSStephen Tozer 620b5ba5d2aSStephen Tozer // The number of debug operands expected by this DbgValue's expression. 621b5ba5d2aSStephen Tozer // getDbgOpIDs() should return an array of this length, unless this is an 622b5ba5d2aSStephen Tozer // Undef or an unjoined VPHI. 623b5ba5d2aSStephen Tozer unsigned getLocationOpCount() const { 624b5ba5d2aSStephen Tozer return Properties.getLocationOpCount(); 625b5ba5d2aSStephen Tozer } 626b5ba5d2aSStephen Tozer 627b5ba5d2aSStephen Tozer // Returns true if this or Other are unjoined PHIs, which do not have defined 628b5ba5d2aSStephen Tozer // Loc Ops, or if the `n`th Loc Op for this has a different constness to the 629b5ba5d2aSStephen Tozer // `n`th Loc Op for Other. 630b5ba5d2aSStephen Tozer bool hasJoinableLocOps(const DbgValue &Other) const { 631b5ba5d2aSStephen Tozer if (isUnjoinedPHI() || Other.isUnjoinedPHI()) 632b5ba5d2aSStephen Tozer return true; 633b5ba5d2aSStephen Tozer for (unsigned Idx = 0; Idx < getLocationOpCount(); ++Idx) { 634b5ba5d2aSStephen Tozer if (getDbgOpID(Idx).isConst() != Other.getDbgOpID(Idx).isConst()) 635b5ba5d2aSStephen Tozer return false; 636b5ba5d2aSStephen Tozer } 637b5ba5d2aSStephen Tozer return true; 638b5ba5d2aSStephen Tozer } 639b5ba5d2aSStephen Tozer 640b5ba5d2aSStephen Tozer bool isUnjoinedPHI() const { return Kind == VPHI && OpCount == 0; } 641b5ba5d2aSStephen Tozer 642b5ba5d2aSStephen Tozer bool hasIdenticalValidLocOps(const DbgValue &Other) const { 643b5ba5d2aSStephen Tozer if (!OpCount) 644b5ba5d2aSStephen Tozer return false; 645b5ba5d2aSStephen Tozer return equal(getDbgOpIDs(), Other.getDbgOpIDs()); 646b5ba5d2aSStephen Tozer } 647838b4a53SJeremy Morse }; 648838b4a53SJeremy Morse 649838b4a53SJeremy Morse class LocIdxToIndexFunctor { 650838b4a53SJeremy Morse public: 651838b4a53SJeremy Morse using argument_type = LocIdx; 652838b4a53SJeremy Morse unsigned operator()(const LocIdx &L) const { return L.asU64(); } 653838b4a53SJeremy Morse }; 654838b4a53SJeremy Morse 655838b4a53SJeremy Morse /// Tracker for what values are in machine locations. Listens to the Things 656838b4a53SJeremy Morse /// being Done by various instructions, and maintains a table of what machine 657838b4a53SJeremy Morse /// locations have what values (as defined by a ValueIDNum). 658838b4a53SJeremy Morse /// 659838b4a53SJeremy Morse /// There are potentially a much larger number of machine locations on the 660838b4a53SJeremy Morse /// target machine than the actual working-set size of the function. On x86 for 661838b4a53SJeremy Morse /// example, we're extremely unlikely to want to track values through control 662838b4a53SJeremy Morse /// or debug registers. To avoid doing so, MLocTracker has several layers of 663e7084ceaSJeremy Morse /// indirection going on, described below, to avoid unnecessarily tracking 664e7084ceaSJeremy Morse /// any location. 665838b4a53SJeremy Morse /// 666e7084ceaSJeremy Morse /// Here's a sort of diagram of the indexes, read from the bottom up: 667e7084ceaSJeremy Morse /// 668e7084ceaSJeremy Morse /// Size on stack Offset on stack 669e7084ceaSJeremy Morse /// \ / 670e7084ceaSJeremy Morse /// Stack Idx (Where in slot is this?) 671e7084ceaSJeremy Morse /// / 672e7084ceaSJeremy Morse /// / 673e7084ceaSJeremy Morse /// Slot Num (%stack.0) / 674e7084ceaSJeremy Morse /// FrameIdx => SpillNum / 675e7084ceaSJeremy Morse /// \ / 676e7084ceaSJeremy Morse /// SpillID (int) Register number (int) 677e7084ceaSJeremy Morse /// \ / 678e7084ceaSJeremy Morse /// LocationID => LocIdx 679e7084ceaSJeremy Morse /// | 680e7084ceaSJeremy Morse /// LocIdx => ValueIDNum 681e7084ceaSJeremy Morse /// 682e7084ceaSJeremy Morse /// The aim here is that the LocIdx => ValueIDNum vector is just an array of 683e7084ceaSJeremy Morse /// values in numbered locations, so that later analyses can ignore whether the 684e7084ceaSJeremy Morse /// location is a register or otherwise. To map a register / spill location to 685e7084ceaSJeremy Morse /// a LocIdx, you have to use the (sparse) LocationID => LocIdx map. And to 686e7084ceaSJeremy Morse /// build a LocationID for a stack slot, you need to combine identifiers for 687e7084ceaSJeremy Morse /// which stack slot it is and where within that slot is being described. 688e7084ceaSJeremy Morse /// 689e7084ceaSJeremy Morse /// Register mask operands cause trouble by technically defining every register; 690e7084ceaSJeremy Morse /// various hacks are used to avoid tracking registers that are never read and 691e7084ceaSJeremy Morse /// only written by regmasks. 692838b4a53SJeremy Morse class MLocTracker { 693838b4a53SJeremy Morse public: 694838b4a53SJeremy Morse MachineFunction &MF; 695838b4a53SJeremy Morse const TargetInstrInfo &TII; 696838b4a53SJeremy Morse const TargetRegisterInfo &TRI; 697838b4a53SJeremy Morse const TargetLowering &TLI; 698838b4a53SJeremy Morse 699838b4a53SJeremy Morse /// IndexedMap type, mapping from LocIdx to ValueIDNum. 700838b4a53SJeremy Morse using LocToValueType = IndexedMap<ValueIDNum, LocIdxToIndexFunctor>; 701838b4a53SJeremy Morse 702838b4a53SJeremy Morse /// Map of LocIdxes to the ValueIDNums that they store. This is tightly 703838b4a53SJeremy Morse /// packed, entries only exist for locations that are being tracked. 704838b4a53SJeremy Morse LocToValueType LocIdxToIDNum; 705838b4a53SJeremy Morse 706838b4a53SJeremy Morse /// "Map" of machine location IDs (i.e., raw register or spill number) to the 707838b4a53SJeremy Morse /// LocIdx key / number for that location. There are always at least as many 708838b4a53SJeremy Morse /// as the number of registers on the target -- if the value in the register 709838b4a53SJeremy Morse /// is not being tracked, then the LocIdx value will be zero. New entries are 710838b4a53SJeremy Morse /// appended if a new spill slot begins being tracked. 711838b4a53SJeremy Morse /// This, and the corresponding reverse map persist for the analysis of the 712838b4a53SJeremy Morse /// whole function, and is necessarying for decoding various vectors of 713838b4a53SJeremy Morse /// values. 714838b4a53SJeremy Morse std::vector<LocIdx> LocIDToLocIdx; 715838b4a53SJeremy Morse 716838b4a53SJeremy Morse /// Inverse map of LocIDToLocIdx. 717838b4a53SJeremy Morse IndexedMap<unsigned, LocIdxToIndexFunctor> LocIdxToLocID; 718838b4a53SJeremy Morse 719fbf269c7SJeremy Morse /// When clobbering register masks, we chose to not believe the machine model 720fbf269c7SJeremy Morse /// and don't clobber SP. Do the same for SP aliases, and for efficiency, 721fbf269c7SJeremy Morse /// keep a set of them here. 722fbf269c7SJeremy Morse SmallSet<Register, 8> SPAliases; 723fbf269c7SJeremy Morse 724e7084ceaSJeremy Morse /// Unique-ification of spill. Used to number them -- their LocID number is 725e7084ceaSJeremy Morse /// the index in SpillLocs minus one plus NumRegs. 726838b4a53SJeremy Morse UniqueVector<SpillLoc> SpillLocs; 727838b4a53SJeremy Morse 728838b4a53SJeremy Morse // If we discover a new machine location, assign it an mphi with this 729838b4a53SJeremy Morse // block number. 730e06dac07SVitaly Buka unsigned CurBB = -1; 731838b4a53SJeremy Morse 732838b4a53SJeremy Morse /// Cached local copy of the number of registers the target has. 733838b4a53SJeremy Morse unsigned NumRegs; 734838b4a53SJeremy Morse 735e7084ceaSJeremy Morse /// Number of slot indexes the target has -- distinct segments of a stack 736e7084ceaSJeremy Morse /// slot that can take on the value of a subregister, when a super-register 737e7084ceaSJeremy Morse /// is written to the stack. 738e7084ceaSJeremy Morse unsigned NumSlotIdxes; 739e7084ceaSJeremy Morse 740838b4a53SJeremy Morse /// Collection of register mask operands that have been observed. Second part 741838b4a53SJeremy Morse /// of pair indicates the instruction that they happened in. Used to 742838b4a53SJeremy Morse /// reconstruct where defs happened if we start tracking a location later 743838b4a53SJeremy Morse /// on. 744838b4a53SJeremy Morse SmallVector<std::pair<const MachineOperand *, unsigned>, 32> Masks; 745838b4a53SJeremy Morse 746e7084ceaSJeremy Morse /// Pair for describing a position within a stack slot -- first the size in 747e7084ceaSJeremy Morse /// bits, then the offset. 748e7084ceaSJeremy Morse typedef std::pair<unsigned short, unsigned short> StackSlotPos; 749e7084ceaSJeremy Morse 750e7084ceaSJeremy Morse /// Map from a size/offset pair describing a position in a stack slot, to a 751e7084ceaSJeremy Morse /// numeric identifier for that position. Allows easier identification of 752e7084ceaSJeremy Morse /// individual positions. 753e7084ceaSJeremy Morse DenseMap<StackSlotPos, unsigned> StackSlotIdxes; 754e7084ceaSJeremy Morse 755e7084ceaSJeremy Morse /// Inverse of StackSlotIdxes. 756e7084ceaSJeremy Morse DenseMap<unsigned, StackSlotPos> StackIdxesToPos; 757e7084ceaSJeremy Morse 758838b4a53SJeremy Morse /// Iterator for locations and the values they contain. Dereferencing 759838b4a53SJeremy Morse /// produces a struct/pair containing the LocIdx key for this location, 760838b4a53SJeremy Morse /// and a reference to the value currently stored. Simplifies the process 761838b4a53SJeremy Morse /// of seeking a particular location. 762838b4a53SJeremy Morse class MLocIterator { 763838b4a53SJeremy Morse LocToValueType &ValueMap; 764838b4a53SJeremy Morse LocIdx Idx; 765838b4a53SJeremy Morse 766838b4a53SJeremy Morse public: 767838b4a53SJeremy Morse class value_type { 768838b4a53SJeremy Morse public: 769838b4a53SJeremy Morse value_type(LocIdx Idx, ValueIDNum &Value) : Idx(Idx), Value(Value) {} 770838b4a53SJeremy Morse const LocIdx Idx; /// Read-only index of this location. 771838b4a53SJeremy Morse ValueIDNum &Value; /// Reference to the stored value at this location. 772838b4a53SJeremy Morse }; 773838b4a53SJeremy Morse 774838b4a53SJeremy Morse MLocIterator(LocToValueType &ValueMap, LocIdx Idx) 775838b4a53SJeremy Morse : ValueMap(ValueMap), Idx(Idx) {} 776838b4a53SJeremy Morse 777838b4a53SJeremy Morse bool operator==(const MLocIterator &Other) const { 778838b4a53SJeremy Morse assert(&ValueMap == &Other.ValueMap); 779838b4a53SJeremy Morse return Idx == Other.Idx; 780838b4a53SJeremy Morse } 781838b4a53SJeremy Morse 782838b4a53SJeremy Morse bool operator!=(const MLocIterator &Other) const { 783838b4a53SJeremy Morse return !(*this == Other); 784838b4a53SJeremy Morse } 785838b4a53SJeremy Morse 786838b4a53SJeremy Morse void operator++() { Idx = LocIdx(Idx.asU64() + 1); } 787838b4a53SJeremy Morse 788838b4a53SJeremy Morse value_type operator*() { return value_type(Idx, ValueMap[LocIdx(Idx)]); } 789838b4a53SJeremy Morse }; 790838b4a53SJeremy Morse 791838b4a53SJeremy Morse MLocTracker(MachineFunction &MF, const TargetInstrInfo &TII, 792838b4a53SJeremy Morse const TargetRegisterInfo &TRI, const TargetLowering &TLI); 793838b4a53SJeremy Morse 794e7084ceaSJeremy Morse /// Produce location ID number for a Register. Provides some small amount of 795e7084ceaSJeremy Morse /// type safety. 796e7084ceaSJeremy Morse /// \param Reg The register we're looking up. 797e7084ceaSJeremy Morse unsigned getLocID(Register Reg) { return Reg.id(); } 798e7084ceaSJeremy Morse 799e7084ceaSJeremy Morse /// Produce location ID number for a spill position. 800e7084ceaSJeremy Morse /// \param Spill The number of the spill we're fetching the location for. 801e7084ceaSJeremy Morse /// \param SpillSubReg Subregister within the spill we're addressing. 802e7084ceaSJeremy Morse unsigned getLocID(SpillLocationNo Spill, unsigned SpillSubReg) { 803e7084ceaSJeremy Morse unsigned short Size = TRI.getSubRegIdxSize(SpillSubReg); 804e7084ceaSJeremy Morse unsigned short Offs = TRI.getSubRegIdxOffset(SpillSubReg); 805e7084ceaSJeremy Morse return getLocID(Spill, {Size, Offs}); 806e7084ceaSJeremy Morse } 807e7084ceaSJeremy Morse 808e7084ceaSJeremy Morse /// Produce location ID number for a spill position. 809e7084ceaSJeremy Morse /// \param Spill The number of the spill we're fetching the location for. 810e7084ceaSJeremy Morse /// \apram SpillIdx size/offset within the spill slot to be addressed. 811e7084ceaSJeremy Morse unsigned getLocID(SpillLocationNo Spill, StackSlotPos Idx) { 812e7084ceaSJeremy Morse unsigned SlotNo = Spill.id() - 1; 813e7084ceaSJeremy Morse SlotNo *= NumSlotIdxes; 814398af9b4SKazu Hirata assert(StackSlotIdxes.contains(Idx)); 815e7084ceaSJeremy Morse SlotNo += StackSlotIdxes[Idx]; 816e7084ceaSJeremy Morse SlotNo += NumRegs; 817e7084ceaSJeremy Morse return SlotNo; 818e7084ceaSJeremy Morse } 819e7084ceaSJeremy Morse 820e7084ceaSJeremy Morse /// Given a spill number, and a slot within the spill, calculate the ID number 821e7084ceaSJeremy Morse /// for that location. 822e7084ceaSJeremy Morse unsigned getSpillIDWithIdx(SpillLocationNo Spill, unsigned Idx) { 823e7084ceaSJeremy Morse unsigned SlotNo = Spill.id() - 1; 824e7084ceaSJeremy Morse SlotNo *= NumSlotIdxes; 825e7084ceaSJeremy Morse SlotNo += Idx; 826e7084ceaSJeremy Morse SlotNo += NumRegs; 827e7084ceaSJeremy Morse return SlotNo; 828e7084ceaSJeremy Morse } 829e7084ceaSJeremy Morse 830e7084ceaSJeremy Morse /// Return the spill number that a location ID corresponds to. 831e7084ceaSJeremy Morse SpillLocationNo locIDToSpill(unsigned ID) const { 832e7084ceaSJeremy Morse assert(ID >= NumRegs); 833e7084ceaSJeremy Morse ID -= NumRegs; 834e7084ceaSJeremy Morse // Truncate away the index part, leaving only the spill number. 835e7084ceaSJeremy Morse ID /= NumSlotIdxes; 836e7084ceaSJeremy Morse return SpillLocationNo(ID + 1); // The UniqueVector is one-based. 837e7084ceaSJeremy Morse } 838e7084ceaSJeremy Morse 839e7084ceaSJeremy Morse /// Returns the spill-slot size/offs that a location ID corresponds to. 840e7084ceaSJeremy Morse StackSlotPos locIDToSpillIdx(unsigned ID) const { 841e7084ceaSJeremy Morse assert(ID >= NumRegs); 842e7084ceaSJeremy Morse ID -= NumRegs; 843e7084ceaSJeremy Morse unsigned Idx = ID % NumSlotIdxes; 844e7084ceaSJeremy Morse return StackIdxesToPos.find(Idx)->second; 845838b4a53SJeremy Morse } 846838b4a53SJeremy Morse 8477e163afdSKazu Hirata unsigned getNumLocs() const { return LocIdxToIDNum.size(); } 848838b4a53SJeremy Morse 849838b4a53SJeremy Morse /// Reset all locations to contain a PHI value at the designated block. Used 850838b4a53SJeremy Morse /// sometimes for actual PHI values, othertimes to indicate the block entry 851838b4a53SJeremy Morse /// value (before any more information is known). 852838b4a53SJeremy Morse void setMPhis(unsigned NewCurBB) { 853838b4a53SJeremy Morse CurBB = NewCurBB; 854838b4a53SJeremy Morse for (auto Location : locations()) 855838b4a53SJeremy Morse Location.Value = {CurBB, 0, Location.Idx}; 856838b4a53SJeremy Morse } 857838b4a53SJeremy Morse 858838b4a53SJeremy Morse /// Load values for each location from array of ValueIDNums. Take current 859838b4a53SJeremy Morse /// bbnum just in case we read a value from a hitherto untouched register. 860ab49dce0SJeremy Morse void loadFromArray(ValueTable &Locs, unsigned NewCurBB) { 861838b4a53SJeremy Morse CurBB = NewCurBB; 862838b4a53SJeremy Morse // Iterate over all tracked locations, and load each locations live-in 863838b4a53SJeremy Morse // value into our local index. 864838b4a53SJeremy Morse for (auto Location : locations()) 865838b4a53SJeremy Morse Location.Value = Locs[Location.Idx.asU64()]; 866838b4a53SJeremy Morse } 867838b4a53SJeremy Morse 868838b4a53SJeremy Morse /// Wipe any un-necessary location records after traversing a block. 8697e163afdSKazu Hirata void reset() { 870838b4a53SJeremy Morse // We could reset all the location values too; however either loadFromArray 871838b4a53SJeremy Morse // or setMPhis should be called before this object is re-used. Just 872838b4a53SJeremy Morse // clear Masks, they're definitely not needed. 873838b4a53SJeremy Morse Masks.clear(); 874838b4a53SJeremy Morse } 875838b4a53SJeremy Morse 876838b4a53SJeremy Morse /// Clear all data. Destroys the LocID <=> LocIdx map, which makes most of 877838b4a53SJeremy Morse /// the information in this pass uninterpretable. 8787e163afdSKazu Hirata void clear() { 879838b4a53SJeremy Morse reset(); 880838b4a53SJeremy Morse LocIDToLocIdx.clear(); 881838b4a53SJeremy Morse LocIdxToLocID.clear(); 882838b4a53SJeremy Morse LocIdxToIDNum.clear(); 883838b4a53SJeremy Morse // SpillLocs.reset(); XXX UniqueVector::reset assumes a SpillLoc casts from 884838b4a53SJeremy Morse // 0 885838b4a53SJeremy Morse SpillLocs = decltype(SpillLocs)(); 886e7084ceaSJeremy Morse StackSlotIdxes.clear(); 887e7084ceaSJeremy Morse StackIdxesToPos.clear(); 888838b4a53SJeremy Morse 889838b4a53SJeremy Morse LocIDToLocIdx.resize(NumRegs, LocIdx::MakeIllegalLoc()); 890838b4a53SJeremy Morse } 891838b4a53SJeremy Morse 892838b4a53SJeremy Morse /// Set a locaiton to a certain value. 893838b4a53SJeremy Morse void setMLoc(LocIdx L, ValueIDNum Num) { 894838b4a53SJeremy Morse assert(L.asU64() < LocIdxToIDNum.size()); 895838b4a53SJeremy Morse LocIdxToIDNum[L] = Num; 896838b4a53SJeremy Morse } 897838b4a53SJeremy Morse 898d9eebe3cSJeremy Morse /// Read the value of a particular location 899d9eebe3cSJeremy Morse ValueIDNum readMLoc(LocIdx L) { 900d9eebe3cSJeremy Morse assert(L.asU64() < LocIdxToIDNum.size()); 901d9eebe3cSJeremy Morse return LocIdxToIDNum[L]; 902d9eebe3cSJeremy Morse } 903d9eebe3cSJeremy Morse 904838b4a53SJeremy Morse /// Create a LocIdx for an untracked register ID. Initialize it to either an 905838b4a53SJeremy Morse /// mphi value representing a live-in, or a recent register mask clobber. 906838b4a53SJeremy Morse LocIdx trackRegister(unsigned ID); 907838b4a53SJeremy Morse 908838b4a53SJeremy Morse LocIdx lookupOrTrackRegister(unsigned ID) { 909838b4a53SJeremy Morse LocIdx &Index = LocIDToLocIdx[ID]; 910838b4a53SJeremy Morse if (Index.isIllegal()) 911838b4a53SJeremy Morse Index = trackRegister(ID); 912838b4a53SJeremy Morse return Index; 913838b4a53SJeremy Morse } 914838b4a53SJeremy Morse 915fbf269c7SJeremy Morse /// Is register R currently tracked by MLocTracker? 916fbf269c7SJeremy Morse bool isRegisterTracked(Register R) { 917fbf269c7SJeremy Morse LocIdx &Index = LocIDToLocIdx[R]; 918fbf269c7SJeremy Morse return !Index.isIllegal(); 919fbf269c7SJeremy Morse } 920fbf269c7SJeremy Morse 921838b4a53SJeremy Morse /// Record a definition of the specified register at the given block / inst. 922838b4a53SJeremy Morse /// This doesn't take a ValueIDNum, because the definition and its location 923838b4a53SJeremy Morse /// are synonymous. 924838b4a53SJeremy Morse void defReg(Register R, unsigned BB, unsigned Inst) { 925e7084ceaSJeremy Morse unsigned ID = getLocID(R); 926838b4a53SJeremy Morse LocIdx Idx = lookupOrTrackRegister(ID); 927838b4a53SJeremy Morse ValueIDNum ValueID = {BB, Inst, Idx}; 928838b4a53SJeremy Morse LocIdxToIDNum[Idx] = ValueID; 929838b4a53SJeremy Morse } 930838b4a53SJeremy Morse 931838b4a53SJeremy Morse /// Set a register to a value number. To be used if the value number is 932838b4a53SJeremy Morse /// known in advance. 933838b4a53SJeremy Morse void setReg(Register R, ValueIDNum ValueID) { 934e7084ceaSJeremy Morse unsigned ID = getLocID(R); 935838b4a53SJeremy Morse LocIdx Idx = lookupOrTrackRegister(ID); 936838b4a53SJeremy Morse LocIdxToIDNum[Idx] = ValueID; 937838b4a53SJeremy Morse } 938838b4a53SJeremy Morse 939838b4a53SJeremy Morse ValueIDNum readReg(Register R) { 940e7084ceaSJeremy Morse unsigned ID = getLocID(R); 941838b4a53SJeremy Morse LocIdx Idx = lookupOrTrackRegister(ID); 942838b4a53SJeremy Morse return LocIdxToIDNum[Idx]; 943838b4a53SJeremy Morse } 944838b4a53SJeremy Morse 945838b4a53SJeremy Morse /// Reset a register value to zero / empty. Needed to replicate the 946838b4a53SJeremy Morse /// VarLoc implementation where a copy to/from a register effectively 947838b4a53SJeremy Morse /// clears the contents of the source register. (Values can only have one 948838b4a53SJeremy Morse /// machine location in VarLocBasedImpl). 949838b4a53SJeremy Morse void wipeRegister(Register R) { 950e7084ceaSJeremy Morse unsigned ID = getLocID(R); 951838b4a53SJeremy Morse LocIdx Idx = LocIDToLocIdx[ID]; 952838b4a53SJeremy Morse LocIdxToIDNum[Idx] = ValueIDNum::EmptyValue; 953838b4a53SJeremy Morse } 954838b4a53SJeremy Morse 955838b4a53SJeremy Morse /// Determine the LocIdx of an existing register. 956838b4a53SJeremy Morse LocIdx getRegMLoc(Register R) { 957e7084ceaSJeremy Morse unsigned ID = getLocID(R); 958e7084ceaSJeremy Morse assert(ID < LocIDToLocIdx.size()); 9597850c94bSDavid Green assert(LocIDToLocIdx[ID] != UINT_MAX); // Sentinel for IndexedMap. 960838b4a53SJeremy Morse return LocIDToLocIdx[ID]; 961838b4a53SJeremy Morse } 962838b4a53SJeremy Morse 963838b4a53SJeremy Morse /// Record a RegMask operand being executed. Defs any register we currently 964838b4a53SJeremy Morse /// track, stores a pointer to the mask in case we have to account for it 965838b4a53SJeremy Morse /// later. 966838b4a53SJeremy Morse void writeRegMask(const MachineOperand *MO, unsigned CurBB, unsigned InstID); 967838b4a53SJeremy Morse 968838b4a53SJeremy Morse /// Find LocIdx for SpillLoc \p L, creating a new one if it's not tracked. 9699f252e55SKazu Hirata /// Returns std::nullopt when in scenarios where a spill slot could be 9709f252e55SKazu Hirata /// tracked, but we would likely run into resource limitations. 97167819a72SFangrui Song std::optional<SpillLocationNo> getOrTrackSpillLoc(SpillLoc L); 972838b4a53SJeremy Morse 973e7084ceaSJeremy Morse // Get LocIdx of a spill ID. 974e7084ceaSJeremy Morse LocIdx getSpillMLoc(unsigned SpillID) { 9757850c94bSDavid Green assert(LocIDToLocIdx[SpillID] != UINT_MAX); // Sentinel for IndexedMap. 976e7084ceaSJeremy Morse return LocIDToLocIdx[SpillID]; 977838b4a53SJeremy Morse } 978838b4a53SJeremy Morse 979838b4a53SJeremy Morse /// Return true if Idx is a spill machine location. 980838b4a53SJeremy Morse bool isSpill(LocIdx Idx) const { return LocIdxToLocID[Idx] >= NumRegs; } 981838b4a53SJeremy Morse 982a975472fSJeremy Morse /// How large is this location (aka, how wide is a value defined there?). 983a975472fSJeremy Morse unsigned getLocSizeInBits(LocIdx L) const { 984a975472fSJeremy Morse unsigned ID = LocIdxToLocID[L]; 985a975472fSJeremy Morse if (!isSpill(L)) { 986a975472fSJeremy Morse return TRI.getRegSizeInBits(Register(ID), MF.getRegInfo()); 987a975472fSJeremy Morse } else { 988a975472fSJeremy Morse // The slot location on the stack is uninteresting, we care about the 989a975472fSJeremy Morse // position of the value within the slot (which comes with a size). 990a975472fSJeremy Morse StackSlotPos Pos = locIDToSpillIdx(ID); 991a975472fSJeremy Morse return Pos.first; 992a975472fSJeremy Morse } 993a975472fSJeremy Morse } 994a975472fSJeremy Morse 995838b4a53SJeremy Morse MLocIterator begin() { return MLocIterator(LocIdxToIDNum, 0); } 996838b4a53SJeremy Morse 997838b4a53SJeremy Morse MLocIterator end() { 998838b4a53SJeremy Morse return MLocIterator(LocIdxToIDNum, LocIdxToIDNum.size()); 999838b4a53SJeremy Morse } 1000838b4a53SJeremy Morse 1001838b4a53SJeremy Morse /// Return a range over all locations currently tracked. 1002838b4a53SJeremy Morse iterator_range<MLocIterator> locations() { 1003838b4a53SJeremy Morse return llvm::make_range(begin(), end()); 1004838b4a53SJeremy Morse } 1005838b4a53SJeremy Morse 1006838b4a53SJeremy Morse std::string LocIdxToName(LocIdx Idx) const; 1007838b4a53SJeremy Morse 1008838b4a53SJeremy Morse std::string IDAsString(const ValueIDNum &Num) const; 1009838b4a53SJeremy Morse 1010d9fa186aSJeremy Morse #ifndef NDEBUG 1011838b4a53SJeremy Morse LLVM_DUMP_METHOD void dump(); 1012838b4a53SJeremy Morse 1013838b4a53SJeremy Morse LLVM_DUMP_METHOD void dump_mloc_map(); 1014d9fa186aSJeremy Morse #endif 1015838b4a53SJeremy Morse 1016b12e5c88SStephen Tozer /// Create a DBG_VALUE based on debug operands \p DbgOps. Qualify it with the 1017838b4a53SJeremy Morse /// information in \pProperties, for variable Var. Don't insert it anywhere, 1018838b4a53SJeremy Morse /// just return the builder for it. 1019b12e5c88SStephen Tozer MachineInstrBuilder emitLoc(const SmallVectorImpl<ResolvedDbgOp> &DbgOps, 1020676efd0fSJeremy Morse const DebugVariable &Var, const DILocation *DILoc, 1021838b4a53SJeremy Morse const DbgValueProperties &Properties); 1022838b4a53SJeremy Morse }; 1023838b4a53SJeremy Morse 10240eee8445SJeremy Morse /// Types for recording sets of variable fragments that overlap. For a given 10250eee8445SJeremy Morse /// local variable, we record all other fragments of that variable that could 10260eee8445SJeremy Morse /// overlap it, to reduce search time. 10270eee8445SJeremy Morse using FragmentOfVar = 10280eee8445SJeremy Morse std::pair<const DILocalVariable *, DIExpression::FragmentInfo>; 10290eee8445SJeremy Morse using OverlapMap = 10300eee8445SJeremy Morse DenseMap<FragmentOfVar, SmallVector<DIExpression::FragmentInfo, 1>>; 10310eee8445SJeremy Morse 1032b5426cedSJeremy Morse /// Collection of DBG_VALUEs observed when traversing a block. Records each 1033b5426cedSJeremy Morse /// variable and the value the DBG_VALUE refers to. Requires the machine value 1034b5426cedSJeremy Morse /// location dataflow algorithm to have run already, so that values can be 1035b5426cedSJeremy Morse /// identified. 1036b5426cedSJeremy Morse class VLocTracker { 1037b5426cedSJeremy Morse public: 1038676efd0fSJeremy Morse /// Ref to function-wide map of DebugVariable <=> ID-numbers. 1039676efd0fSJeremy Morse DebugVariableMap &DVMap; 1040b5426cedSJeremy Morse /// Map DebugVariable to the latest Value it's defined to have. 1041b5426cedSJeremy Morse /// Needs to be a MapVector because we determine order-in-the-input-MIR from 1042676efd0fSJeremy Morse /// the order in this container. (FIXME: likely no longer true as the ordering 1043676efd0fSJeremy Morse /// is now provided by DebugVariableMap). 1044b5426cedSJeremy Morse /// We only retain the last DbgValue in each block for each variable, to 1045b5426cedSJeremy Morse /// determine the blocks live-out variable value. The Vars container forms the 1046b5426cedSJeremy Morse /// transfer function for this block, as part of the dataflow analysis. The 1047b5426cedSJeremy Morse /// movement of values between locations inside of a block is handled at a 1048b5426cedSJeremy Morse /// much later stage, in the TransferTracker class. 1049*96f37ae4SJeremy Morse SmallMapVector<DebugVariableID, DbgValue, 8> Vars; 1050676efd0fSJeremy Morse SmallDenseMap<DebugVariableID, const DILocation *, 8> Scopes; 1051cf033bb2SJeremy Morse MachineBasicBlock *MBB = nullptr; 10520eee8445SJeremy Morse const OverlapMap &OverlappingFragments; 10530eee8445SJeremy Morse DbgValueProperties EmptyProperties; 1054b5426cedSJeremy Morse 1055b5426cedSJeremy Morse public: 1056676efd0fSJeremy Morse VLocTracker(DebugVariableMap &DVMap, const OverlapMap &O, 1057676efd0fSJeremy Morse const DIExpression *EmptyExpr) 1058676efd0fSJeremy Morse : DVMap(DVMap), OverlappingFragments(O), 1059676efd0fSJeremy Morse EmptyProperties(EmptyExpr, false, false) {} 1060b5426cedSJeremy Morse 1061b5426cedSJeremy Morse void defVar(const MachineInstr &MI, const DbgValueProperties &Properties, 1062b5ba5d2aSStephen Tozer const SmallVectorImpl<DbgOpID> &DebugOps) { 1063e10e9363SStephen Tozer assert(MI.isDebugValueLike()); 1064b5426cedSJeremy Morse DebugVariable Var(MI.getDebugVariable(), MI.getDebugExpression(), 1065b5426cedSJeremy Morse MI.getDebugLoc()->getInlinedAt()); 1066676efd0fSJeremy Morse // Either insert or fetch an ID number for this variable. 1067676efd0fSJeremy Morse DebugVariableID VarID = DVMap.insertDVID(Var, MI.getDebugLoc().get()); 1068b5ba5d2aSStephen Tozer DbgValue Rec = (DebugOps.size() > 0) 1069b5ba5d2aSStephen Tozer ? DbgValue(DebugOps, Properties) 1070b5426cedSJeremy Morse : DbgValue(Properties, DbgValue::Undef); 1071b5426cedSJeremy Morse 1072b5426cedSJeremy Morse // Attempt insertion; overwrite if it's already mapped. 1073a341820fSKazu Hirata Vars.insert_or_assign(VarID, Rec); 1074676efd0fSJeremy Morse Scopes[VarID] = MI.getDebugLoc().get(); 10750eee8445SJeremy Morse 10760eee8445SJeremy Morse considerOverlaps(Var, MI.getDebugLoc().get()); 1077b5426cedSJeremy Morse } 1078b5426cedSJeremy Morse 10790eee8445SJeremy Morse void considerOverlaps(const DebugVariable &Var, const DILocation *Loc) { 10800eee8445SJeremy Morse auto Overlaps = OverlappingFragments.find( 10810eee8445SJeremy Morse {Var.getVariable(), Var.getFragmentOrDefault()}); 10820eee8445SJeremy Morse if (Overlaps == OverlappingFragments.end()) 10830eee8445SJeremy Morse return; 10840eee8445SJeremy Morse 10850eee8445SJeremy Morse // Otherwise: terminate any overlapped variable locations. 10860eee8445SJeremy Morse for (auto FragmentInfo : Overlaps->second) { 10870eee8445SJeremy Morse // The "empty" fragment is stored as DebugVariable::DefaultFragment, so 10880eee8445SJeremy Morse // that it overlaps with everything, however its cannonical representation 10890eee8445SJeremy Morse // in a DebugVariable is as "None". 10900ca43d44SKrzysztof Parzyszek std::optional<DIExpression::FragmentInfo> OptFragmentInfo = FragmentInfo; 10910eee8445SJeremy Morse if (DebugVariable::isDefaultFragment(FragmentInfo)) 1092998960eeSKazu Hirata OptFragmentInfo = std::nullopt; 10930eee8445SJeremy Morse 10940eee8445SJeremy Morse DebugVariable Overlapped(Var.getVariable(), OptFragmentInfo, 10950eee8445SJeremy Morse Var.getInlinedAt()); 1096676efd0fSJeremy Morse // Produce an ID number for this overlapping fragment of a variable. 1097676efd0fSJeremy Morse DebugVariableID OverlappedID = DVMap.insertDVID(Overlapped, Loc); 10980eee8445SJeremy Morse DbgValue Rec = DbgValue(EmptyProperties, DbgValue::Undef); 10990eee8445SJeremy Morse 11000eee8445SJeremy Morse // Attempt insertion; overwrite if it's already mapped. 1101a341820fSKazu Hirata Vars.insert_or_assign(OverlappedID, Rec); 1102676efd0fSJeremy Morse Scopes[OverlappedID] = Loc; 11030eee8445SJeremy Morse } 1104b5426cedSJeremy Morse } 1105a80181a8SJeremy Morse 1106a80181a8SJeremy Morse void clear() { 1107a80181a8SJeremy Morse Vars.clear(); 1108a80181a8SJeremy Morse Scopes.clear(); 1109a80181a8SJeremy Morse } 1110b5426cedSJeremy Morse }; 1111b5426cedSJeremy Morse 1112838b4a53SJeremy Morse // XXX XXX docs 1113838b4a53SJeremy Morse class InstrRefBasedLDV : public LDVImpl { 1114b5426cedSJeremy Morse public: 1115838b4a53SJeremy Morse friend class ::InstrRefLDVTest; 1116838b4a53SJeremy Morse 1117838b4a53SJeremy Morse using FragmentInfo = DIExpression::FragmentInfo; 11180ca43d44SKrzysztof Parzyszek using OptFragmentInfo = std::optional<DIExpression::FragmentInfo>; 1119838b4a53SJeremy Morse 1120838b4a53SJeremy Morse // Helper while building OverlapMap, a map of all fragments seen for a given 1121838b4a53SJeremy Morse // DILocalVariable. 1122838b4a53SJeremy Morse using VarToFragments = 1123838b4a53SJeremy Morse DenseMap<const DILocalVariable *, SmallSet<FragmentInfo, 4>>; 1124838b4a53SJeremy Morse 1125838b4a53SJeremy Morse /// Machine location/value transfer function, a mapping of which locations 1126838b4a53SJeremy Morse /// are assigned which new values. 11274136897bSJeremy Morse using MLocTransferMap = SmallDenseMap<LocIdx, ValueIDNum>; 1128838b4a53SJeremy Morse 1129838b4a53SJeremy Morse /// Live in/out structure for the variable values: a per-block map of 113089950adeSJeremy Morse /// variables to their values. 1131*96f37ae4SJeremy Morse using LiveIdxT = SmallDenseMap<const MachineBasicBlock *, DbgValue *, 16>; 1132838b4a53SJeremy Morse 1133676efd0fSJeremy Morse using VarAndLoc = std::pair<DebugVariableID, DbgValue>; 1134838b4a53SJeremy Morse 1135838b4a53SJeremy Morse /// Type for a live-in value: the predecessor block, and its value. 1136838b4a53SJeremy Morse using InValueT = std::pair<MachineBasicBlock *, DbgValue *>; 1137838b4a53SJeremy Morse 1138838b4a53SJeremy Morse /// Vector (per block) of a collection (inner smallvector) of live-ins. 1139838b4a53SJeremy Morse /// Used as the result type for the variable value dataflow problem. 1140838b4a53SJeremy Morse using LiveInsT = SmallVector<SmallVector<VarAndLoc, 8>, 8>; 1141838b4a53SJeremy Morse 11424a2cb013SJeremy Morse /// Mapping from lexical scopes to a DILocation in that scope. 11434a2cb013SJeremy Morse using ScopeToDILocT = DenseMap<const LexicalScope *, const DILocation *>; 11444a2cb013SJeremy Morse 11454a2cb013SJeremy Morse /// Mapping from lexical scopes to variables in that scope. 1146676efd0fSJeremy Morse using ScopeToVarsT = 1147676efd0fSJeremy Morse DenseMap<const LexicalScope *, SmallSet<DebugVariableID, 4>>; 11484a2cb013SJeremy Morse 11494a2cb013SJeremy Morse /// Mapping from lexical scopes to blocks where variables in that scope are 11504a2cb013SJeremy Morse /// assigned. Such blocks aren't necessarily "in" the lexical scope, it's 11514a2cb013SJeremy Morse /// just a block where an assignment happens. 11524a2cb013SJeremy Morse using ScopeToAssignBlocksT = DenseMap<const LexicalScope *, SmallPtrSet<MachineBasicBlock *, 4>>; 11534a2cb013SJeremy Morse 1154b5426cedSJeremy Morse private: 1155a3936a6cSJeremy Morse MachineDominatorTree *DomTree; 1156838b4a53SJeremy Morse const TargetRegisterInfo *TRI; 1157e7084ceaSJeremy Morse const MachineRegisterInfo *MRI; 1158838b4a53SJeremy Morse const TargetInstrInfo *TII; 1159838b4a53SJeremy Morse const TargetFrameLowering *TFI; 1160838b4a53SJeremy Morse const MachineFrameInfo *MFI; 1161838b4a53SJeremy Morse BitVector CalleeSavedRegs; 1162838b4a53SJeremy Morse LexicalScopes LS; 1163838b4a53SJeremy Morse TargetPassConfig *TPC; 1164838b4a53SJeremy Morse 1165b5426cedSJeremy Morse // An empty DIExpression. Used default / placeholder DbgValueProperties 1166b5426cedSJeremy Morse // objects, as we can't have null expressions. 1167b5426cedSJeremy Morse const DIExpression *EmptyExpr; 1168b5426cedSJeremy Morse 1169838b4a53SJeremy Morse /// Object to track machine locations as we step through a block. Could 1170838b4a53SJeremy Morse /// probably be a field rather than a pointer, as it's always used. 1171d9eebe3cSJeremy Morse MLocTracker *MTracker = nullptr; 1172838b4a53SJeremy Morse 1173838b4a53SJeremy Morse /// Number of the current block LiveDebugValues is stepping through. 1174e06dac07SVitaly Buka unsigned CurBB = -1; 1175838b4a53SJeremy Morse 1176838b4a53SJeremy Morse /// Number of the current instruction LiveDebugValues is evaluating. 1177838b4a53SJeremy Morse unsigned CurInst; 1178838b4a53SJeremy Morse 1179838b4a53SJeremy Morse /// Variable tracker -- listens to DBG_VALUEs occurring as InstrRefBasedImpl 1180838b4a53SJeremy Morse /// steps through a block. Reads the values at each location from the 1181838b4a53SJeremy Morse /// MLocTracker object. 1182d9eebe3cSJeremy Morse VLocTracker *VTracker = nullptr; 1183838b4a53SJeremy Morse 1184838b4a53SJeremy Morse /// Tracker for transfers, listens to DBG_VALUEs and transfers of values 1185838b4a53SJeremy Morse /// between locations during stepping, creates new DBG_VALUEs when values move 1186838b4a53SJeremy Morse /// location. 1187d9eebe3cSJeremy Morse TransferTracker *TTracker = nullptr; 1188838b4a53SJeremy Morse 1189838b4a53SJeremy Morse /// Blocks which are artificial, i.e. blocks which exclusively contain 1190838b4a53SJeremy Morse /// instructions without DebugLocs, or with line 0 locations. 11914a2cb013SJeremy Morse SmallPtrSet<MachineBasicBlock *, 16> ArtificialBlocks; 1192838b4a53SJeremy Morse 1193838b4a53SJeremy Morse // Mapping of blocks to and from their RPOT order. 11940b71d802SJeremy Morse SmallVector<MachineBasicBlock *> OrderToBB; 1195b5426cedSJeremy Morse DenseMap<const MachineBasicBlock *, unsigned int> BBToOrder; 1196838b4a53SJeremy Morse DenseMap<unsigned, unsigned> BBNumToRPO; 1197838b4a53SJeremy Morse 1198838b4a53SJeremy Morse /// Pair of MachineInstr, and its 1-based offset into the containing block. 1199838b4a53SJeremy Morse using InstAndNum = std::pair<const MachineInstr *, unsigned>; 1200838b4a53SJeremy Morse /// Map from debug instruction number to the MachineInstr labelled with that 1201838b4a53SJeremy Morse /// number, and its location within the function. Used to transform 1202838b4a53SJeremy Morse /// instruction numbers in DBG_INSTR_REFs into machine value numbers. 1203838b4a53SJeremy Morse std::map<uint64_t, InstAndNum> DebugInstrNumToInstr; 1204838b4a53SJeremy Morse 1205838b4a53SJeremy Morse /// Record of where we observed a DBG_PHI instruction. 1206838b4a53SJeremy Morse class DebugPHIRecord { 1207838b4a53SJeremy Morse public: 1208be5734ddSJeremy Morse /// Instruction number of this DBG_PHI. 1209be5734ddSJeremy Morse uint64_t InstrNum; 1210be5734ddSJeremy Morse /// Block where DBG_PHI occurred. 1211be5734ddSJeremy Morse MachineBasicBlock *MBB; 1212595f1a6aSKazu Hirata /// The value number read by the DBG_PHI -- or std::nullopt if it didn't 1213595f1a6aSKazu Hirata /// refer to a value. 121467819a72SFangrui Song std::optional<ValueIDNum> ValueRead; 1215595f1a6aSKazu Hirata /// Register/Stack location the DBG_PHI reads -- or std::nullopt if it 1216595f1a6aSKazu Hirata /// referred to something unexpected. 121767819a72SFangrui Song std::optional<LocIdx> ReadLoc; 1218838b4a53SJeremy Morse 1219838b4a53SJeremy Morse operator unsigned() const { return InstrNum; } 1220838b4a53SJeremy Morse }; 1221838b4a53SJeremy Morse 1222838b4a53SJeremy Morse /// Map from instruction numbers defined by DBG_PHIs to a record of what that 1223838b4a53SJeremy Morse /// DBG_PHI read and where. Populated and edited during the machine value 1224838b4a53SJeremy Morse /// location problem -- we use LLVMs SSA Updater to fix changes by 1225838b4a53SJeremy Morse /// optimizations that destroy PHI instructions. 1226838b4a53SJeremy Morse SmallVector<DebugPHIRecord, 32> DebugPHINumToValue; 1227838b4a53SJeremy Morse 1228838b4a53SJeremy Morse // Map of overlapping variable fragments. 1229838b4a53SJeremy Morse OverlapMap OverlapFragments; 1230838b4a53SJeremy Morse VarToFragments SeenFragments; 1231838b4a53SJeremy Morse 1232d556eb7eSJeremy Morse /// Mapping of DBG_INSTR_REF instructions to their values, for those 1233d556eb7eSJeremy Morse /// DBG_INSTR_REFs that call resolveDbgPHIs. These variable references solve 1234d556eb7eSJeremy Morse /// a mini SSA problem caused by DBG_PHIs being cloned, this collection caches 1235d556eb7eSJeremy Morse /// the result. 1236a344c907SStephen Tozer DenseMap<std::pair<MachineInstr *, unsigned>, std::optional<ValueIDNum>> 1237a344c907SStephen Tozer SeenDbgPHIs; 1238d556eb7eSJeremy Morse 1239b5ba5d2aSStephen Tozer DbgOpIDMap DbgOpStore; 1240b5ba5d2aSStephen Tozer 1241676efd0fSJeremy Morse /// Mapping between DebugVariables and unique ID numbers. This is a more 1242676efd0fSJeremy Morse /// efficient way to represent the identity of a variable, versus a plain 1243676efd0fSJeremy Morse /// DebugVariable. 1244676efd0fSJeremy Morse DebugVariableMap DVMap; 1245676efd0fSJeremy Morse 1246bfadc5dcSJeremy Morse /// True if we need to examine call instructions for stack clobbers. We 1247bfadc5dcSJeremy Morse /// normally assume that they don't clobber SP, but stack probes on Windows 1248bfadc5dcSJeremy Morse /// do. 1249bfadc5dcSJeremy Morse bool AdjustsStackInCalls = false; 1250bfadc5dcSJeremy Morse 1251bfadc5dcSJeremy Morse /// If AdjustsStackInCalls is true, this holds the name of the target's stack 1252bfadc5dcSJeremy Morse /// probe function, which is the function we expect will alter the stack 1253bfadc5dcSJeremy Morse /// pointer. 1254bfadc5dcSJeremy Morse StringRef StackProbeSymbolName; 1255bfadc5dcSJeremy Morse 1256838b4a53SJeremy Morse /// Tests whether this instruction is a spill to a stack slot. 125767819a72SFangrui Song std::optional<SpillLocationNo> isSpillInstruction(const MachineInstr &MI, 125814aaaa12SJeremy Morse MachineFunction *MF); 1259838b4a53SJeremy Morse 1260838b4a53SJeremy Morse /// Decide if @MI is a spill instruction and return true if it is. We use 2 1261838b4a53SJeremy Morse /// criteria to make this decision: 1262838b4a53SJeremy Morse /// - Is this instruction a store to a spill slot? 1263838b4a53SJeremy Morse /// - Is there a register operand that is both used and killed? 1264838b4a53SJeremy Morse /// TODO: Store optimization can fold spills into other stores (including 1265838b4a53SJeremy Morse /// other spills). We do not handle this yet (more than one memory operand). 1266838b4a53SJeremy Morse bool isLocationSpill(const MachineInstr &MI, MachineFunction *MF, 1267838b4a53SJeremy Morse unsigned &Reg); 1268838b4a53SJeremy Morse 1269838b4a53SJeremy Morse /// If a given instruction is identified as a spill, return the spill slot 1270838b4a53SJeremy Morse /// and set \p Reg to the spilled register. 127167819a72SFangrui Song std::optional<SpillLocationNo> isRestoreInstruction(const MachineInstr &MI, 127267819a72SFangrui Song MachineFunction *MF, 127367819a72SFangrui Song unsigned &Reg); 1274838b4a53SJeremy Morse 1275e7084ceaSJeremy Morse /// Given a spill instruction, extract the spill slot information, ensure it's 1276e7084ceaSJeremy Morse /// tracked, and return the spill number. 127767819a72SFangrui Song std::optional<SpillLocationNo> 127814aaaa12SJeremy Morse extractSpillBaseRegAndOffset(const MachineInstr &MI); 1279838b4a53SJeremy Morse 1280a344c907SStephen Tozer /// For an instruction reference given by \p InstNo and \p OpNo in instruction 1281a344c907SStephen Tozer /// \p MI returns the Value pointed to by that instruction reference if any 12821ca0cb71SKazu Hirata /// exists, otherwise returns std::nullopt. 1283a344c907SStephen Tozer std::optional<ValueIDNum> getValueForInstrRef(unsigned InstNo, unsigned OpNo, 1284a344c907SStephen Tozer MachineInstr &MI, 12851b531d54SFelipe de Azevedo Piovezan const FuncValueTable *MLiveOuts, 12861b531d54SFelipe de Azevedo Piovezan const FuncValueTable *MLiveIns); 1287a344c907SStephen Tozer 1288838b4a53SJeremy Morse /// Observe a single instruction while stepping through a block. 12891b531d54SFelipe de Azevedo Piovezan void process(MachineInstr &MI, const FuncValueTable *MLiveOuts, 12901b531d54SFelipe de Azevedo Piovezan const FuncValueTable *MLiveIns); 1291838b4a53SJeremy Morse 1292838b4a53SJeremy Morse /// Examines whether \p MI is a DBG_VALUE and notifies trackers. 1293838b4a53SJeremy Morse /// \returns true if MI was recognized and processed. 1294838b4a53SJeremy Morse bool transferDebugValue(const MachineInstr &MI); 1295838b4a53SJeremy Morse 1296838b4a53SJeremy Morse /// Examines whether \p MI is a DBG_INSTR_REF and notifies trackers. 1297838b4a53SJeremy Morse /// \returns true if MI was recognized and processed. 12981b531d54SFelipe de Azevedo Piovezan bool transferDebugInstrRef(MachineInstr &MI, const FuncValueTable *MLiveOuts, 12991b531d54SFelipe de Azevedo Piovezan const FuncValueTable *MLiveIns); 1300838b4a53SJeremy Morse 1301838b4a53SJeremy Morse /// Stores value-information about where this PHI occurred, and what 1302838b4a53SJeremy Morse /// instruction number is associated with it. 1303838b4a53SJeremy Morse /// \returns true if MI was recognized and processed. 1304838b4a53SJeremy Morse bool transferDebugPHI(MachineInstr &MI); 1305838b4a53SJeremy Morse 1306838b4a53SJeremy Morse /// Examines whether \p MI is copy instruction, and notifies trackers. 1307838b4a53SJeremy Morse /// \returns true if MI was recognized and processed. 1308838b4a53SJeremy Morse bool transferRegisterCopy(MachineInstr &MI); 1309838b4a53SJeremy Morse 1310838b4a53SJeremy Morse /// Examines whether \p MI is stack spill or restore instruction, and 1311838b4a53SJeremy Morse /// notifies trackers. \returns true if MI was recognized and processed. 1312838b4a53SJeremy Morse bool transferSpillOrRestoreInst(MachineInstr &MI); 1313838b4a53SJeremy Morse 1314838b4a53SJeremy Morse /// Examines \p MI for any registers that it defines, and notifies trackers. 1315838b4a53SJeremy Morse void transferRegisterDef(MachineInstr &MI); 1316838b4a53SJeremy Morse 1317838b4a53SJeremy Morse /// Copy one location to the other, accounting for movement of subregisters 1318838b4a53SJeremy Morse /// too. 1319838b4a53SJeremy Morse void performCopy(Register Src, Register Dst); 1320838b4a53SJeremy Morse 1321838b4a53SJeremy Morse void accumulateFragmentMap(MachineInstr &MI); 1322838b4a53SJeremy Morse 1323838b4a53SJeremy Morse /// Determine the machine value number referred to by (potentially several) 1324838b4a53SJeremy Morse /// DBG_PHI instructions. Block duplication and tail folding can duplicate 1325838b4a53SJeremy Morse /// DBG_PHIs, shifting the position where values in registers merge, and 1326838b4a53SJeremy Morse /// forming another mini-ssa problem to solve. 1327838b4a53SJeremy Morse /// \p Here the position of a DBG_INSTR_REF seeking a machine value number 1328838b4a53SJeremy Morse /// \p InstrNum Debug instruction number defined by DBG_PHI instructions. 1329595f1a6aSKazu Hirata /// \returns The machine value number at position Here, or std::nullopt. 133067819a72SFangrui Song std::optional<ValueIDNum> resolveDbgPHIs(MachineFunction &MF, 13311b531d54SFelipe de Azevedo Piovezan const FuncValueTable &MLiveOuts, 13321b531d54SFelipe de Azevedo Piovezan const FuncValueTable &MLiveIns, 133367819a72SFangrui Song MachineInstr &Here, 133467819a72SFangrui Song uint64_t InstrNum); 1335838b4a53SJeremy Morse 133667819a72SFangrui Song std::optional<ValueIDNum> resolveDbgPHIsImpl(MachineFunction &MF, 13371b531d54SFelipe de Azevedo Piovezan const FuncValueTable &MLiveOuts, 13381b531d54SFelipe de Azevedo Piovezan const FuncValueTable &MLiveIns, 1339d556eb7eSJeremy Morse MachineInstr &Here, 1340d556eb7eSJeremy Morse uint64_t InstrNum); 1341d556eb7eSJeremy Morse 1342838b4a53SJeremy Morse /// Step through the function, recording register definitions and movements 1343838b4a53SJeremy Morse /// in an MLocTracker. Convert the observations into a per-block transfer 1344838b4a53SJeremy Morse /// function in \p MLocTransfer, suitable for using with the machine value 1345838b4a53SJeremy Morse /// location dataflow problem. 1346838b4a53SJeremy Morse void 1347838b4a53SJeremy Morse produceMLocTransferFunction(MachineFunction &MF, 1348838b4a53SJeremy Morse SmallVectorImpl<MLocTransferMap> &MLocTransfer, 1349838b4a53SJeremy Morse unsigned MaxNumBlocks); 1350838b4a53SJeremy Morse 1351838b4a53SJeremy Morse /// Solve the machine value location dataflow problem. Takes as input the 1352838b4a53SJeremy Morse /// transfer functions in \p MLocTransfer. Writes the output live-in and 1353838b4a53SJeremy Morse /// live-out arrays to the (initialized to zero) multidimensional arrays in 1354838b4a53SJeremy Morse /// \p MInLocs and \p MOutLocs. The outer dimension is indexed by block 1355838b4a53SJeremy Morse /// number, the inner by LocIdx. 1356ab49dce0SJeremy Morse void buildMLocValueMap(MachineFunction &MF, FuncValueTable &MInLocs, 1357ab49dce0SJeremy Morse FuncValueTable &MOutLocs, 1358838b4a53SJeremy Morse SmallVectorImpl<MLocTransferMap> &MLocTransfer); 1359838b4a53SJeremy Morse 136097ddf49eSJeremy Morse /// Examine the stack indexes (i.e. offsets within the stack) to find the 136197ddf49eSJeremy Morse /// basic units of interference -- like reg units, but for the stack. 136297ddf49eSJeremy Morse void findStackIndexInterference(SmallVectorImpl<unsigned> &Slots); 136397ddf49eSJeremy Morse 1364fbf269c7SJeremy Morse /// Install PHI values into the live-in array for each block, according to 1365fbf269c7SJeremy Morse /// the IDF of each register. 1366fbf269c7SJeremy Morse void placeMLocPHIs(MachineFunction &MF, 1367fbf269c7SJeremy Morse SmallPtrSetImpl<MachineBasicBlock *> &AllBlocks, 1368ab49dce0SJeremy Morse FuncValueTable &MInLocs, 1369fbf269c7SJeremy Morse SmallVectorImpl<MLocTransferMap> &MLocTransfer); 1370fbf269c7SJeremy Morse 1371c703d77aSJeremy Morse /// Propagate variable values to blocks in the common case where there's 1372c703d77aSJeremy Morse /// only one value assigned to the variable. This function has better 1373c703d77aSJeremy Morse /// performance as it doesn't have to find the dominance frontier between 1374c703d77aSJeremy Morse /// different assignments. 1375c703d77aSJeremy Morse void placePHIsForSingleVarDefinition( 1376c703d77aSJeremy Morse const SmallPtrSetImpl<MachineBasicBlock *> &InScopeBlocks, 1377c703d77aSJeremy Morse MachineBasicBlock *MBB, SmallVectorImpl<VLocTracker> &AllTheVLocs, 1378676efd0fSJeremy Morse DebugVariableID Var, LiveInsT &Output); 1379c703d77aSJeremy Morse 1380a3936a6cSJeremy Morse /// Calculate the iterated-dominance-frontier for a set of defs, using the 1381a3936a6cSJeremy Morse /// existing LLVM facilities for this. Works for a single "value" or 1382a3936a6cSJeremy Morse /// machine/variable location. 1383a3936a6cSJeremy Morse /// \p AllBlocks Set of blocks where we might consume the value. 1384a3936a6cSJeremy Morse /// \p DefBlocks Set of blocks where the value/location is defined. 1385a3936a6cSJeremy Morse /// \p PHIBlocks Output set of blocks where PHIs must be placed. 1386a3936a6cSJeremy Morse void BlockPHIPlacement(const SmallPtrSetImpl<MachineBasicBlock *> &AllBlocks, 1387a3936a6cSJeremy Morse const SmallPtrSetImpl<MachineBasicBlock *> &DefBlocks, 1388a3936a6cSJeremy Morse SmallVectorImpl<MachineBasicBlock *> &PHIBlocks); 1389a3936a6cSJeremy Morse 1390838b4a53SJeremy Morse /// Perform a control flow join (lattice value meet) of the values in machine 1391838b4a53SJeremy Morse /// locations at \p MBB. Follows the algorithm described in the file-comment, 1392838b4a53SJeremy Morse /// reading live-outs of predecessors from \p OutLocs, the current live ins 1393838b4a53SJeremy Morse /// from \p InLocs, and assigning the newly computed live ins back into 1394838b4a53SJeremy Morse /// \p InLocs. \returns two bools -- the first indicates whether a change 1395838b4a53SJeremy Morse /// was made, the second whether a lattice downgrade occurred. If the latter 1396838b4a53SJeremy Morse /// is true, revisiting this block is necessary. 1397a3936a6cSJeremy Morse bool mlocJoin(MachineBasicBlock &MBB, 1398838b4a53SJeremy Morse SmallPtrSet<const MachineBasicBlock *, 16> &Visited, 1399ab49dce0SJeremy Morse FuncValueTable &OutLocs, ValueTable &InLocs); 1400838b4a53SJeremy Morse 14014a2cb013SJeremy Morse /// Produce a set of blocks that are in the current lexical scope. This means 14024a2cb013SJeremy Morse /// those blocks that contain instructions "in" the scope, blocks where 14034a2cb013SJeremy Morse /// assignments to variables in scope occur, and artificial blocks that are 14044a2cb013SJeremy Morse /// successors to any of the earlier blocks. See https://llvm.org/PR48091 for 14054a2cb013SJeremy Morse /// more commentry on what "in scope" means. 14064a2cb013SJeremy Morse /// \p DILoc A location in the scope that we're fetching blocks for. 14074a2cb013SJeremy Morse /// \p Output Set to put in-scope-blocks into. 14084a2cb013SJeremy Morse /// \p AssignBlocks Blocks known to contain assignments of variables in scope. 14094a2cb013SJeremy Morse void 14104a2cb013SJeremy Morse getBlocksForScope(const DILocation *DILoc, 14114a2cb013SJeremy Morse SmallPtrSetImpl<const MachineBasicBlock *> &Output, 14124a2cb013SJeremy Morse const SmallPtrSetImpl<MachineBasicBlock *> &AssignBlocks); 14134a2cb013SJeremy Morse 1414838b4a53SJeremy Morse /// Solve the variable value dataflow problem, for a single lexical scope. 1415b5426cedSJeremy Morse /// Uses the algorithm from the file comment to resolve control flow joins 1416b5426cedSJeremy Morse /// using PHI placement and value propagation. Reads the locations of machine 1417b5426cedSJeremy Morse /// values from the \p MInLocs and \p MOutLocs arrays (see buildMLocValueMap) 1418b5426cedSJeremy Morse /// and reads the variable values transfer function from \p AllTheVlocs. 1419b5426cedSJeremy Morse /// Live-in and Live-out variable values are stored locally, with the live-ins 1420b5426cedSJeremy Morse /// permanently stored to \p Output once a fixedpoint is reached. 1421838b4a53SJeremy Morse /// \p VarsWeCareAbout contains a collection of the variables in \p Scope 1422838b4a53SJeremy Morse /// that we should be tracking. 1423b5426cedSJeremy Morse /// \p AssignBlocks contains the set of blocks that aren't in \p DILoc's 1424b5426cedSJeremy Morse /// scope, but which do contain DBG_VALUEs, which VarLocBasedImpl tracks 1425b5426cedSJeremy Morse /// locations through. 1426b5426cedSJeremy Morse void buildVLocValueMap(const DILocation *DILoc, 1427676efd0fSJeremy Morse const SmallSet<DebugVariableID, 4> &VarsWeCareAbout, 1428838b4a53SJeremy Morse SmallPtrSetImpl<MachineBasicBlock *> &AssignBlocks, 1429ab49dce0SJeremy Morse LiveInsT &Output, FuncValueTable &MOutLocs, 1430ab49dce0SJeremy Morse FuncValueTable &MInLocs, 1431838b4a53SJeremy Morse SmallVectorImpl<VLocTracker> &AllTheVLocs); 1432838b4a53SJeremy Morse 1433b5426cedSJeremy Morse /// Attempt to eliminate un-necessary PHIs on entry to a block. Examines the 1434b5426cedSJeremy Morse /// live-in values coming from predecessors live-outs, and replaces any PHIs 1435b5426cedSJeremy Morse /// already present in this blocks live-ins with a live-through value if the 143689950adeSJeremy Morse /// PHI isn't needed. 143789950adeSJeremy Morse /// \p LiveIn Old live-in value, overwritten with new one if live-in changes. 1438b5426cedSJeremy Morse /// \returns true if any live-ins change value, either from value propagation 1439b5426cedSJeremy Morse /// or PHI elimination. 1440b5426cedSJeremy Morse bool vlocJoin(MachineBasicBlock &MBB, LiveIdxT &VLOCOutLocs, 1441838b4a53SJeremy Morse SmallPtrSet<const MachineBasicBlock *, 8> &BlocksToExplore, 144289950adeSJeremy Morse DbgValue &LiveIn); 1443838b4a53SJeremy Morse 144453fd5af6SStephen Tozer /// For the given block and live-outs feeding into it, try to find 144553fd5af6SStephen Tozer /// machine locations for each debug operand where all the values feeding 144653fd5af6SStephen Tozer /// into that operand join together. 144753fd5af6SStephen Tozer /// \returns true if a joined location was found for every value that needed 144853fd5af6SStephen Tozer /// to be joined. 144953fd5af6SStephen Tozer bool 145053fd5af6SStephen Tozer pickVPHILoc(SmallVectorImpl<DbgOpID> &OutValues, const MachineBasicBlock &MBB, 1451ab49dce0SJeremy Morse const LiveIdxT &LiveOuts, FuncValueTable &MOutLocs, 1452b5426cedSJeremy Morse const SmallVectorImpl<const MachineBasicBlock *> &BlockOrders); 1453838b4a53SJeremy Morse 145467819a72SFangrui Song std::optional<ValueIDNum> pickOperandPHILoc( 145553fd5af6SStephen Tozer unsigned DbgOpIdx, const MachineBasicBlock &MBB, const LiveIdxT &LiveOuts, 145653fd5af6SStephen Tozer FuncValueTable &MOutLocs, 145753fd5af6SStephen Tozer const SmallVectorImpl<const MachineBasicBlock *> &BlockOrders); 145853fd5af6SStephen Tozer 14594a2cb013SJeremy Morse /// Take collections of DBG_VALUE instructions stored in TTracker, and 1460676efd0fSJeremy Morse /// install them into their output blocks. 1461676efd0fSJeremy Morse bool emitTransfers(); 14624a2cb013SJeremy Morse 1463838b4a53SJeremy Morse /// Boilerplate computation of some initial sets, artifical blocks and 1464838b4a53SJeremy Morse /// RPOT block ordering. 1465838b4a53SJeremy Morse void initialSetup(MachineFunction &MF); 1466838b4a53SJeremy Morse 14679fd9d56dSJeremy Morse /// Produce a map of the last lexical scope that uses a block, using the 14689fd9d56dSJeremy Morse /// scopes DFSOut number. Mapping is block-number to DFSOut. 14699fd9d56dSJeremy Morse /// \p EjectionMap Pre-allocated vector in which to install the built ma. 14709fd9d56dSJeremy Morse /// \p ScopeToDILocation Mapping of LexicalScopes to their DILocations. 14719fd9d56dSJeremy Morse /// \p AssignBlocks Map of blocks where assignments happen for a scope. 14729fd9d56dSJeremy Morse void makeDepthFirstEjectionMap(SmallVectorImpl<unsigned> &EjectionMap, 14739fd9d56dSJeremy Morse const ScopeToDILocT &ScopeToDILocation, 14749fd9d56dSJeremy Morse ScopeToAssignBlocksT &AssignBlocks); 14759fd9d56dSJeremy Morse 14769fd9d56dSJeremy Morse /// When determining per-block variable values and emitting to DBG_VALUEs, 14779fd9d56dSJeremy Morse /// this function explores by lexical scope depth. Doing so means that per 14789fd9d56dSJeremy Morse /// block information can be fully computed before exploration finishes, 14799fd9d56dSJeremy Morse /// allowing us to emit it and free data structures earlier than otherwise. 14809fd9d56dSJeremy Morse /// It's also good for locality. 1481676efd0fSJeremy Morse bool depthFirstVLocAndEmit(unsigned MaxNumBlocks, 1482676efd0fSJeremy Morse const ScopeToDILocT &ScopeToDILocation, 1483676efd0fSJeremy Morse const ScopeToVarsT &ScopeToVars, 1484676efd0fSJeremy Morse ScopeToAssignBlocksT &ScopeToBlocks, 1485676efd0fSJeremy Morse LiveInsT &Output, FuncValueTable &MOutLocs, 1486676efd0fSJeremy Morse FuncValueTable &MInLocs, 1487676efd0fSJeremy Morse SmallVectorImpl<VLocTracker> &AllTheVLocs, 1488676efd0fSJeremy Morse MachineFunction &MF, const TargetPassConfig &TPC); 14899fd9d56dSJeremy Morse 1490a3936a6cSJeremy Morse bool ExtendRanges(MachineFunction &MF, MachineDominatorTree *DomTree, 1491a3936a6cSJeremy Morse TargetPassConfig *TPC, unsigned InputBBLimit, 1492a3936a6cSJeremy Morse unsigned InputDbgValLimit) override; 1493838b4a53SJeremy Morse 1494838b4a53SJeremy Morse public: 1495838b4a53SJeremy Morse /// Default construct and initialize the pass. 1496838b4a53SJeremy Morse InstrRefBasedLDV(); 1497838b4a53SJeremy Morse 1498838b4a53SJeremy Morse LLVM_DUMP_METHOD 1499838b4a53SJeremy Morse void dump_mloc_transfer(const MLocTransferMap &mloc_transfer) const; 1500838b4a53SJeremy Morse 1501838b4a53SJeremy Morse bool isCalleeSaved(LocIdx L) const; 150289d0cc99SStephen Tozer bool isCalleeSavedReg(Register R) const; 1503ee3eee71SJeremy Morse 1504ee3eee71SJeremy Morse bool hasFoldedStackStore(const MachineInstr &MI) { 1505ee3eee71SJeremy Morse // Instruction must have a memory operand that's a stack slot, and isn't 1506ee3eee71SJeremy Morse // aliased, meaning it's a spill from regalloc instead of a variable. 1507ee3eee71SJeremy Morse // If it's aliased, we can't guarantee its value. 1508ee3eee71SJeremy Morse if (!MI.hasOneMemOperand()) 1509ee3eee71SJeremy Morse return false; 1510ee3eee71SJeremy Morse auto *MemOperand = *MI.memoperands_begin(); 1511ee3eee71SJeremy Morse return MemOperand->isStore() && 1512ee3eee71SJeremy Morse MemOperand->getPseudoValue() && 1513ee3eee71SJeremy Morse MemOperand->getPseudoValue()->kind() == PseudoSourceValue::FixedStack 1514ee3eee71SJeremy Morse && !MemOperand->getPseudoValue()->isAliased(MFI); 1515ee3eee71SJeremy Morse } 1516ee3eee71SJeremy Morse 151767819a72SFangrui Song std::optional<LocIdx> findLocationForMemOperand(const MachineInstr &MI); 1518676efd0fSJeremy Morse 1519676efd0fSJeremy Morse // Utility for unit testing, don't use directly. 1520676efd0fSJeremy Morse DebugVariableMap &getDVMap() { 1521676efd0fSJeremy Morse return DVMap; 1522676efd0fSJeremy Morse } 1523838b4a53SJeremy Morse }; 1524838b4a53SJeremy Morse 1525838b4a53SJeremy Morse } // namespace LiveDebugValues 1526838b4a53SJeremy Morse 1527838b4a53SJeremy Morse #endif /* LLVM_LIB_CODEGEN_LIVEDEBUGVALUES_INSTRREFBASEDLDV_H */ 1528