1bdd1243dSDimitry Andric #include "llvm/CodeGen/AssignmentTrackingAnalysis.h" 2*06c3fb27SDimitry Andric #include "LiveDebugValues/LiveDebugValues.h" 3*06c3fb27SDimitry Andric #include "llvm/ADT/BitVector.h" 4bdd1243dSDimitry Andric #include "llvm/ADT/DenseMapInfo.h" 5bdd1243dSDimitry Andric #include "llvm/ADT/IntervalMap.h" 6bdd1243dSDimitry Andric #include "llvm/ADT/PostOrderIterator.h" 7bdd1243dSDimitry Andric #include "llvm/ADT/STLExtras.h" 8bdd1243dSDimitry Andric #include "llvm/ADT/SmallSet.h" 9bdd1243dSDimitry Andric #include "llvm/ADT/Statistic.h" 10bdd1243dSDimitry Andric #include "llvm/ADT/UniqueVector.h" 11bdd1243dSDimitry Andric #include "llvm/Analysis/Interval.h" 12bdd1243dSDimitry Andric #include "llvm/BinaryFormat/Dwarf.h" 13bdd1243dSDimitry Andric #include "llvm/IR/BasicBlock.h" 14bdd1243dSDimitry Andric #include "llvm/IR/DataLayout.h" 15bdd1243dSDimitry Andric #include "llvm/IR/DebugInfo.h" 16bdd1243dSDimitry Andric #include "llvm/IR/Function.h" 17bdd1243dSDimitry Andric #include "llvm/IR/Instruction.h" 18bdd1243dSDimitry Andric #include "llvm/IR/IntrinsicInst.h" 19bdd1243dSDimitry Andric #include "llvm/IR/PassManager.h" 20bdd1243dSDimitry Andric #include "llvm/IR/PrintPasses.h" 21bdd1243dSDimitry Andric #include "llvm/InitializePasses.h" 22bdd1243dSDimitry Andric #include "llvm/Support/CommandLine.h" 23bdd1243dSDimitry Andric #include "llvm/Support/ErrorHandling.h" 24bdd1243dSDimitry Andric #include "llvm/Support/raw_ostream.h" 25bdd1243dSDimitry Andric #include "llvm/Transforms/Utils/BasicBlockUtils.h" 26bdd1243dSDimitry Andric #include <assert.h> 27bdd1243dSDimitry Andric #include <cstdint> 28bdd1243dSDimitry Andric #include <optional> 29bdd1243dSDimitry Andric #include <sstream> 30bdd1243dSDimitry Andric #include <unordered_map> 31bdd1243dSDimitry Andric 32bdd1243dSDimitry Andric using namespace llvm; 33bdd1243dSDimitry Andric #define DEBUG_TYPE "debug-ata" 34bdd1243dSDimitry Andric 35bdd1243dSDimitry Andric STATISTIC(NumDefsScanned, "Number of dbg locs that get scanned for removal"); 36bdd1243dSDimitry Andric STATISTIC(NumDefsRemoved, "Number of dbg locs removed"); 37bdd1243dSDimitry Andric STATISTIC(NumWedgesScanned, "Number of dbg wedges scanned"); 38bdd1243dSDimitry Andric STATISTIC(NumWedgesChanged, "Number of dbg wedges changed"); 39bdd1243dSDimitry Andric 40bdd1243dSDimitry Andric static cl::opt<unsigned> 41bdd1243dSDimitry Andric MaxNumBlocks("debug-ata-max-blocks", cl::init(10000), 42bdd1243dSDimitry Andric cl::desc("Maximum num basic blocks before debug info dropped"), 43bdd1243dSDimitry Andric cl::Hidden); 44bdd1243dSDimitry Andric /// Option for debugging the pass, determines if the memory location fragment 45bdd1243dSDimitry Andric /// filling happens after generating the variable locations. 46bdd1243dSDimitry Andric static cl::opt<bool> EnableMemLocFragFill("mem-loc-frag-fill", cl::init(true), 47bdd1243dSDimitry Andric cl::Hidden); 48bdd1243dSDimitry Andric /// Print the results of the analysis. Respects -filter-print-funcs. 49bdd1243dSDimitry Andric static cl::opt<bool> PrintResults("print-debug-ata", cl::init(false), 50bdd1243dSDimitry Andric cl::Hidden); 51bdd1243dSDimitry Andric 52*06c3fb27SDimitry Andric /// Coalesce adjacent dbg locs describing memory locations that have contiguous 53*06c3fb27SDimitry Andric /// fragments. This reduces the cost of LiveDebugValues which does SSA 54*06c3fb27SDimitry Andric /// construction for each explicitly stated variable fragment. 55*06c3fb27SDimitry Andric static cl::opt<cl::boolOrDefault> 56*06c3fb27SDimitry Andric CoalesceAdjacentFragmentsOpt("debug-ata-coalesce-frags", cl::Hidden); 57*06c3fb27SDimitry Andric 58bdd1243dSDimitry Andric // Implicit conversions are disabled for enum class types, so unfortunately we 59bdd1243dSDimitry Andric // need to create a DenseMapInfo wrapper around the specified underlying type. 60bdd1243dSDimitry Andric template <> struct llvm::DenseMapInfo<VariableID> { 61bdd1243dSDimitry Andric using Wrapped = DenseMapInfo<unsigned>; 62bdd1243dSDimitry Andric static inline VariableID getEmptyKey() { 63bdd1243dSDimitry Andric return static_cast<VariableID>(Wrapped::getEmptyKey()); 64bdd1243dSDimitry Andric } 65bdd1243dSDimitry Andric static inline VariableID getTombstoneKey() { 66bdd1243dSDimitry Andric return static_cast<VariableID>(Wrapped::getTombstoneKey()); 67bdd1243dSDimitry Andric } 68bdd1243dSDimitry Andric static unsigned getHashValue(const VariableID &Val) { 69bdd1243dSDimitry Andric return Wrapped::getHashValue(static_cast<unsigned>(Val)); 70bdd1243dSDimitry Andric } 71bdd1243dSDimitry Andric static bool isEqual(const VariableID &LHS, const VariableID &RHS) { 72bdd1243dSDimitry Andric return LHS == RHS; 73bdd1243dSDimitry Andric } 74bdd1243dSDimitry Andric }; 75bdd1243dSDimitry Andric 76bdd1243dSDimitry Andric /// Helper class to build FunctionVarLocs, since that class isn't easy to 77bdd1243dSDimitry Andric /// modify. TODO: There's not a great deal of value in the split, it could be 78bdd1243dSDimitry Andric /// worth merging the two classes. 79bdd1243dSDimitry Andric class FunctionVarLocsBuilder { 80bdd1243dSDimitry Andric friend FunctionVarLocs; 81bdd1243dSDimitry Andric UniqueVector<DebugVariable> Variables; 82bdd1243dSDimitry Andric // Use an unordered_map so we don't invalidate iterators after 83bdd1243dSDimitry Andric // insert/modifications. 84bdd1243dSDimitry Andric std::unordered_map<const Instruction *, SmallVector<VarLocInfo>> 85bdd1243dSDimitry Andric VarLocsBeforeInst; 86bdd1243dSDimitry Andric 87bdd1243dSDimitry Andric SmallVector<VarLocInfo> SingleLocVars; 88bdd1243dSDimitry Andric 89bdd1243dSDimitry Andric public: 90*06c3fb27SDimitry Andric unsigned getNumVariables() const { return Variables.size(); } 91*06c3fb27SDimitry Andric 92bdd1243dSDimitry Andric /// Find or insert \p V and return the ID. 93bdd1243dSDimitry Andric VariableID insertVariable(DebugVariable V) { 94bdd1243dSDimitry Andric return static_cast<VariableID>(Variables.insert(V)); 95bdd1243dSDimitry Andric } 96bdd1243dSDimitry Andric 97bdd1243dSDimitry Andric /// Get a variable from its \p ID. 98bdd1243dSDimitry Andric const DebugVariable &getVariable(VariableID ID) const { 99bdd1243dSDimitry Andric return Variables[static_cast<unsigned>(ID)]; 100bdd1243dSDimitry Andric } 101bdd1243dSDimitry Andric 102bdd1243dSDimitry Andric /// Return ptr to wedge of defs or nullptr if no defs come just before /p 103bdd1243dSDimitry Andric /// Before. 104bdd1243dSDimitry Andric const SmallVectorImpl<VarLocInfo> *getWedge(const Instruction *Before) const { 105bdd1243dSDimitry Andric auto R = VarLocsBeforeInst.find(Before); 106bdd1243dSDimitry Andric if (R == VarLocsBeforeInst.end()) 107bdd1243dSDimitry Andric return nullptr; 108bdd1243dSDimitry Andric return &R->second; 109bdd1243dSDimitry Andric } 110bdd1243dSDimitry Andric 111bdd1243dSDimitry Andric /// Replace the defs that come just before /p Before with /p Wedge. 112bdd1243dSDimitry Andric void setWedge(const Instruction *Before, SmallVector<VarLocInfo> &&Wedge) { 113bdd1243dSDimitry Andric VarLocsBeforeInst[Before] = std::move(Wedge); 114bdd1243dSDimitry Andric } 115bdd1243dSDimitry Andric 116bdd1243dSDimitry Andric /// Add a def for a variable that is valid for its lifetime. 117bdd1243dSDimitry Andric void addSingleLocVar(DebugVariable Var, DIExpression *Expr, DebugLoc DL, 118*06c3fb27SDimitry Andric RawLocationWrapper R) { 119bdd1243dSDimitry Andric VarLocInfo VarLoc; 120bdd1243dSDimitry Andric VarLoc.VariableID = insertVariable(Var); 121bdd1243dSDimitry Andric VarLoc.Expr = Expr; 122bdd1243dSDimitry Andric VarLoc.DL = DL; 123*06c3fb27SDimitry Andric VarLoc.Values = R; 124bdd1243dSDimitry Andric SingleLocVars.emplace_back(VarLoc); 125bdd1243dSDimitry Andric } 126bdd1243dSDimitry Andric 127bdd1243dSDimitry Andric /// Add a def to the wedge of defs just before /p Before. 128bdd1243dSDimitry Andric void addVarLoc(Instruction *Before, DebugVariable Var, DIExpression *Expr, 129*06c3fb27SDimitry Andric DebugLoc DL, RawLocationWrapper R) { 130bdd1243dSDimitry Andric VarLocInfo VarLoc; 131bdd1243dSDimitry Andric VarLoc.VariableID = insertVariable(Var); 132bdd1243dSDimitry Andric VarLoc.Expr = Expr; 133bdd1243dSDimitry Andric VarLoc.DL = DL; 134*06c3fb27SDimitry Andric VarLoc.Values = R; 135bdd1243dSDimitry Andric VarLocsBeforeInst[Before].emplace_back(VarLoc); 136bdd1243dSDimitry Andric } 137bdd1243dSDimitry Andric }; 138bdd1243dSDimitry Andric 139bdd1243dSDimitry Andric void FunctionVarLocs::print(raw_ostream &OS, const Function &Fn) const { 140bdd1243dSDimitry Andric // Print the variable table first. TODO: Sorting by variable could make the 141bdd1243dSDimitry Andric // output more stable? 142bdd1243dSDimitry Andric unsigned Counter = -1; 143bdd1243dSDimitry Andric OS << "=== Variables ===\n"; 144bdd1243dSDimitry Andric for (const DebugVariable &V : Variables) { 145bdd1243dSDimitry Andric ++Counter; 146bdd1243dSDimitry Andric // Skip first entry because it is a dummy entry. 147bdd1243dSDimitry Andric if (Counter == 0) { 148bdd1243dSDimitry Andric continue; 149bdd1243dSDimitry Andric } 150bdd1243dSDimitry Andric OS << "[" << Counter << "] " << V.getVariable()->getName(); 151bdd1243dSDimitry Andric if (auto F = V.getFragment()) 152bdd1243dSDimitry Andric OS << " bits [" << F->OffsetInBits << ", " 153bdd1243dSDimitry Andric << F->OffsetInBits + F->SizeInBits << ")"; 154bdd1243dSDimitry Andric if (const auto *IA = V.getInlinedAt()) 155bdd1243dSDimitry Andric OS << " inlined-at " << *IA; 156bdd1243dSDimitry Andric OS << "\n"; 157bdd1243dSDimitry Andric } 158bdd1243dSDimitry Andric 159bdd1243dSDimitry Andric auto PrintLoc = [&OS](const VarLocInfo &Loc) { 160bdd1243dSDimitry Andric OS << "DEF Var=[" << (unsigned)Loc.VariableID << "]" 161*06c3fb27SDimitry Andric << " Expr=" << *Loc.Expr << " Values=("; 162*06c3fb27SDimitry Andric for (auto *Op : Loc.Values.location_ops()) { 163*06c3fb27SDimitry Andric errs() << Op->getName() << " "; 164*06c3fb27SDimitry Andric } 165*06c3fb27SDimitry Andric errs() << ")\n"; 166bdd1243dSDimitry Andric }; 167bdd1243dSDimitry Andric 168bdd1243dSDimitry Andric // Print the single location variables. 169bdd1243dSDimitry Andric OS << "=== Single location vars ===\n"; 170bdd1243dSDimitry Andric for (auto It = single_locs_begin(), End = single_locs_end(); It != End; 171bdd1243dSDimitry Andric ++It) { 172bdd1243dSDimitry Andric PrintLoc(*It); 173bdd1243dSDimitry Andric } 174bdd1243dSDimitry Andric 175bdd1243dSDimitry Andric // Print the non-single-location defs in line with IR. 176bdd1243dSDimitry Andric OS << "=== In-line variable defs ==="; 177bdd1243dSDimitry Andric for (const BasicBlock &BB : Fn) { 178bdd1243dSDimitry Andric OS << "\n" << BB.getName() << ":\n"; 179bdd1243dSDimitry Andric for (const Instruction &I : BB) { 180bdd1243dSDimitry Andric for (auto It = locs_begin(&I), End = locs_end(&I); It != End; ++It) { 181bdd1243dSDimitry Andric PrintLoc(*It); 182bdd1243dSDimitry Andric } 183bdd1243dSDimitry Andric OS << I << "\n"; 184bdd1243dSDimitry Andric } 185bdd1243dSDimitry Andric } 186bdd1243dSDimitry Andric } 187bdd1243dSDimitry Andric 188bdd1243dSDimitry Andric void FunctionVarLocs::init(FunctionVarLocsBuilder &Builder) { 189bdd1243dSDimitry Andric // Add the single-location variables first. 190bdd1243dSDimitry Andric for (const auto &VarLoc : Builder.SingleLocVars) 191bdd1243dSDimitry Andric VarLocRecords.emplace_back(VarLoc); 192bdd1243dSDimitry Andric // Mark the end of the section. 193bdd1243dSDimitry Andric SingleVarLocEnd = VarLocRecords.size(); 194bdd1243dSDimitry Andric 195bdd1243dSDimitry Andric // Insert a contiguous block of VarLocInfos for each instruction, mapping it 196bdd1243dSDimitry Andric // to the start and end position in the vector with VarLocsBeforeInst. 197bdd1243dSDimitry Andric for (auto &P : Builder.VarLocsBeforeInst) { 198bdd1243dSDimitry Andric unsigned BlockStart = VarLocRecords.size(); 199bdd1243dSDimitry Andric for (const VarLocInfo &VarLoc : P.second) 200bdd1243dSDimitry Andric VarLocRecords.emplace_back(VarLoc); 201bdd1243dSDimitry Andric unsigned BlockEnd = VarLocRecords.size(); 202bdd1243dSDimitry Andric // Record the start and end indices. 203bdd1243dSDimitry Andric if (BlockEnd != BlockStart) 204bdd1243dSDimitry Andric VarLocsBeforeInst[P.first] = {BlockStart, BlockEnd}; 205bdd1243dSDimitry Andric } 206bdd1243dSDimitry Andric 207bdd1243dSDimitry Andric // Copy the Variables vector from the builder's UniqueVector. 208bdd1243dSDimitry Andric assert(Variables.empty() && "Expect clear before init"); 209bdd1243dSDimitry Andric // UniqueVectors IDs are one-based (which means the VarLocInfo VarID values 210bdd1243dSDimitry Andric // are one-based) so reserve an extra and insert a dummy. 211bdd1243dSDimitry Andric Variables.reserve(Builder.Variables.size() + 1); 212bdd1243dSDimitry Andric Variables.push_back(DebugVariable(nullptr, std::nullopt, nullptr)); 213bdd1243dSDimitry Andric Variables.append(Builder.Variables.begin(), Builder.Variables.end()); 214bdd1243dSDimitry Andric } 215bdd1243dSDimitry Andric 216bdd1243dSDimitry Andric void FunctionVarLocs::clear() { 217bdd1243dSDimitry Andric Variables.clear(); 218bdd1243dSDimitry Andric VarLocRecords.clear(); 219bdd1243dSDimitry Andric VarLocsBeforeInst.clear(); 220bdd1243dSDimitry Andric SingleVarLocEnd = 0; 221bdd1243dSDimitry Andric } 222bdd1243dSDimitry Andric 223bdd1243dSDimitry Andric /// Walk backwards along constant GEPs and bitcasts to the base storage from \p 224bdd1243dSDimitry Andric /// Start as far as possible. Prepend \Expression with the offset and append it 225bdd1243dSDimitry Andric /// with a DW_OP_deref that haes been implicit until now. Returns the walked-to 226bdd1243dSDimitry Andric /// value and modified expression. 227bdd1243dSDimitry Andric static std::pair<Value *, DIExpression *> 228bdd1243dSDimitry Andric walkToAllocaAndPrependOffsetDeref(const DataLayout &DL, Value *Start, 229bdd1243dSDimitry Andric DIExpression *Expression) { 230bdd1243dSDimitry Andric APInt OffsetInBytes(DL.getTypeSizeInBits(Start->getType()), false); 231bdd1243dSDimitry Andric Value *End = 232bdd1243dSDimitry Andric Start->stripAndAccumulateInBoundsConstantOffsets(DL, OffsetInBytes); 233bdd1243dSDimitry Andric SmallVector<uint64_t, 3> Ops; 234bdd1243dSDimitry Andric if (OffsetInBytes.getBoolValue()) { 235bdd1243dSDimitry Andric Ops = {dwarf::DW_OP_plus_uconst, OffsetInBytes.getZExtValue()}; 236bdd1243dSDimitry Andric Expression = DIExpression::prependOpcodes( 237bdd1243dSDimitry Andric Expression, Ops, /*StackValue=*/false, /*EntryValue=*/false); 238bdd1243dSDimitry Andric } 239bdd1243dSDimitry Andric Expression = DIExpression::append(Expression, {dwarf::DW_OP_deref}); 240bdd1243dSDimitry Andric return {End, Expression}; 241bdd1243dSDimitry Andric } 242bdd1243dSDimitry Andric 243bdd1243dSDimitry Andric /// Extract the offset used in \p DIExpr. Returns std::nullopt if the expression 244bdd1243dSDimitry Andric /// doesn't explicitly describe a memory location with DW_OP_deref or if the 245bdd1243dSDimitry Andric /// expression is too complex to interpret. 246bdd1243dSDimitry Andric static std::optional<int64_t> 247bdd1243dSDimitry Andric getDerefOffsetInBytes(const DIExpression *DIExpr) { 248bdd1243dSDimitry Andric int64_t Offset = 0; 249bdd1243dSDimitry Andric const unsigned NumElements = DIExpr->getNumElements(); 250bdd1243dSDimitry Andric const auto Elements = DIExpr->getElements(); 251*06c3fb27SDimitry Andric unsigned ExpectedDerefIdx = 0; 252bdd1243dSDimitry Andric // Extract the offset. 253bdd1243dSDimitry Andric if (NumElements > 2 && Elements[0] == dwarf::DW_OP_plus_uconst) { 254bdd1243dSDimitry Andric Offset = Elements[1]; 255*06c3fb27SDimitry Andric ExpectedDerefIdx = 2; 256bdd1243dSDimitry Andric } else if (NumElements > 3 && Elements[0] == dwarf::DW_OP_constu) { 257*06c3fb27SDimitry Andric ExpectedDerefIdx = 3; 258bdd1243dSDimitry Andric if (Elements[2] == dwarf::DW_OP_plus) 259bdd1243dSDimitry Andric Offset = Elements[1]; 260bdd1243dSDimitry Andric else if (Elements[2] == dwarf::DW_OP_minus) 261bdd1243dSDimitry Andric Offset = -Elements[1]; 262bdd1243dSDimitry Andric else 263bdd1243dSDimitry Andric return std::nullopt; 264bdd1243dSDimitry Andric } 265bdd1243dSDimitry Andric 266bdd1243dSDimitry Andric // If that's all there is it means there's no deref. 267*06c3fb27SDimitry Andric if (ExpectedDerefIdx >= NumElements) 268bdd1243dSDimitry Andric return std::nullopt; 269bdd1243dSDimitry Andric 270bdd1243dSDimitry Andric // Check the next element is DW_OP_deref - otherwise this is too complex or 271bdd1243dSDimitry Andric // isn't a deref expression. 272*06c3fb27SDimitry Andric if (Elements[ExpectedDerefIdx] != dwarf::DW_OP_deref) 273bdd1243dSDimitry Andric return std::nullopt; 274bdd1243dSDimitry Andric 275bdd1243dSDimitry Andric // Check the final operation is either the DW_OP_deref or is a fragment. 276*06c3fb27SDimitry Andric if (NumElements == ExpectedDerefIdx + 1) 277bdd1243dSDimitry Andric return Offset; // Ends with deref. 278*06c3fb27SDimitry Andric unsigned ExpectedFragFirstIdx = ExpectedDerefIdx + 1; 279*06c3fb27SDimitry Andric unsigned ExpectedFragFinalIdx = ExpectedFragFirstIdx + 2; 280*06c3fb27SDimitry Andric if (NumElements == ExpectedFragFinalIdx + 1 && 281*06c3fb27SDimitry Andric Elements[ExpectedFragFirstIdx] == dwarf::DW_OP_LLVM_fragment) 282bdd1243dSDimitry Andric return Offset; // Ends with deref + fragment. 283bdd1243dSDimitry Andric 284bdd1243dSDimitry Andric // Don't bother trying to interpret anything more complex. 285bdd1243dSDimitry Andric return std::nullopt; 286bdd1243dSDimitry Andric } 287bdd1243dSDimitry Andric 288bdd1243dSDimitry Andric /// A whole (unfragmented) source variable. 289bdd1243dSDimitry Andric using DebugAggregate = std::pair<const DILocalVariable *, const DILocation *>; 290bdd1243dSDimitry Andric static DebugAggregate getAggregate(const DbgVariableIntrinsic *DII) { 291bdd1243dSDimitry Andric return DebugAggregate(DII->getVariable(), DII->getDebugLoc().getInlinedAt()); 292bdd1243dSDimitry Andric } 293bdd1243dSDimitry Andric static DebugAggregate getAggregate(const DebugVariable &Var) { 294bdd1243dSDimitry Andric return DebugAggregate(Var.getVariable(), Var.getInlinedAt()); 295bdd1243dSDimitry Andric } 296bdd1243dSDimitry Andric 297*06c3fb27SDimitry Andric static bool shouldCoalesceFragments(Function &F) { 298*06c3fb27SDimitry Andric // Enabling fragment coalescing reduces compiler run time when instruction 299*06c3fb27SDimitry Andric // referencing is enabled. However, it may cause LiveDebugVariables to create 300*06c3fb27SDimitry Andric // incorrect locations. Since instruction-referencing mode effectively 301*06c3fb27SDimitry Andric // bypasses LiveDebugVariables we only enable coalescing if the cl::opt flag 302*06c3fb27SDimitry Andric // has not been explicitly set and instruction-referencing is turned on. 303*06c3fb27SDimitry Andric switch (CoalesceAdjacentFragmentsOpt) { 304*06c3fb27SDimitry Andric case cl::boolOrDefault::BOU_UNSET: 305*06c3fb27SDimitry Andric return debuginfoShouldUseDebugInstrRef( 306*06c3fb27SDimitry Andric Triple(F.getParent()->getTargetTriple())); 307*06c3fb27SDimitry Andric case cl::boolOrDefault::BOU_TRUE: 308*06c3fb27SDimitry Andric return true; 309*06c3fb27SDimitry Andric case cl::boolOrDefault::BOU_FALSE: 310*06c3fb27SDimitry Andric return false; 311*06c3fb27SDimitry Andric } 312*06c3fb27SDimitry Andric llvm_unreachable("Unknown boolOrDefault value"); 313*06c3fb27SDimitry Andric } 314*06c3fb27SDimitry Andric 315bdd1243dSDimitry Andric namespace { 316bdd1243dSDimitry Andric /// In dwarf emission, the following sequence 317bdd1243dSDimitry Andric /// 1. dbg.value ... Fragment(0, 64) 318bdd1243dSDimitry Andric /// 2. dbg.value ... Fragment(0, 32) 319bdd1243dSDimitry Andric /// effectively sets Fragment(32, 32) to undef (each def sets all bits not in 320bdd1243dSDimitry Andric /// the intersection of the fragments to having "no location"). This makes 321bdd1243dSDimitry Andric /// sense for implicit location values because splitting the computed values 322bdd1243dSDimitry Andric /// could be troublesome, and is probably quite uncommon. When we convert 323bdd1243dSDimitry Andric /// dbg.assigns to dbg.value+deref this kind of thing is common, and describing 324bdd1243dSDimitry Andric /// a location (memory) rather than a value means we don't need to worry about 325bdd1243dSDimitry Andric /// splitting any values, so we try to recover the rest of the fragment 326bdd1243dSDimitry Andric /// location here. 327bdd1243dSDimitry Andric /// This class performs a(nother) dataflow analysis over the function, adding 328bdd1243dSDimitry Andric /// variable locations so that any bits of a variable with a memory location 329bdd1243dSDimitry Andric /// have that location explicitly reinstated at each subsequent variable 330bdd1243dSDimitry Andric /// location definition that that doesn't overwrite those bits. i.e. after a 331bdd1243dSDimitry Andric /// variable location def, insert new defs for the memory location with 332bdd1243dSDimitry Andric /// fragments for the difference of "all bits currently in memory" and "the 333bdd1243dSDimitry Andric /// fragment of the second def". 334bdd1243dSDimitry Andric class MemLocFragmentFill { 335bdd1243dSDimitry Andric Function &Fn; 336bdd1243dSDimitry Andric FunctionVarLocsBuilder *FnVarLocs; 337bdd1243dSDimitry Andric const DenseSet<DebugAggregate> *VarsWithStackSlot; 338*06c3fb27SDimitry Andric bool CoalesceAdjacentFragments; 339bdd1243dSDimitry Andric 340bdd1243dSDimitry Andric // 0 = no memory location. 341bdd1243dSDimitry Andric using BaseAddress = unsigned; 342bdd1243dSDimitry Andric using OffsetInBitsTy = unsigned; 343bdd1243dSDimitry Andric using FragTraits = IntervalMapHalfOpenInfo<OffsetInBitsTy>; 344bdd1243dSDimitry Andric using FragsInMemMap = IntervalMap< 345bdd1243dSDimitry Andric OffsetInBitsTy, BaseAddress, 346bdd1243dSDimitry Andric IntervalMapImpl::NodeSizer<OffsetInBitsTy, BaseAddress>::LeafSize, 347bdd1243dSDimitry Andric FragTraits>; 348bdd1243dSDimitry Andric FragsInMemMap::Allocator IntervalMapAlloc; 349bdd1243dSDimitry Andric using VarFragMap = DenseMap<unsigned, FragsInMemMap>; 350bdd1243dSDimitry Andric 351bdd1243dSDimitry Andric /// IDs for memory location base addresses in maps. Use 0 to indicate that 352bdd1243dSDimitry Andric /// there's no memory location. 353*06c3fb27SDimitry Andric UniqueVector<RawLocationWrapper> Bases; 354bdd1243dSDimitry Andric UniqueVector<DebugAggregate> Aggregates; 355bdd1243dSDimitry Andric DenseMap<const BasicBlock *, VarFragMap> LiveIn; 356bdd1243dSDimitry Andric DenseMap<const BasicBlock *, VarFragMap> LiveOut; 357bdd1243dSDimitry Andric 358bdd1243dSDimitry Andric struct FragMemLoc { 359bdd1243dSDimitry Andric unsigned Var; 360bdd1243dSDimitry Andric unsigned Base; 361bdd1243dSDimitry Andric unsigned OffsetInBits; 362bdd1243dSDimitry Andric unsigned SizeInBits; 363bdd1243dSDimitry Andric DebugLoc DL; 364bdd1243dSDimitry Andric }; 365bdd1243dSDimitry Andric using InsertMap = MapVector<Instruction *, SmallVector<FragMemLoc>>; 366bdd1243dSDimitry Andric 367bdd1243dSDimitry Andric /// BBInsertBeforeMap holds a description for the set of location defs to be 368bdd1243dSDimitry Andric /// inserted after the analysis is complete. It is updated during the dataflow 369bdd1243dSDimitry Andric /// and the entry for a block is CLEARED each time it is (re-)visited. After 370bdd1243dSDimitry Andric /// the dataflow is complete, each block entry will contain the set of defs 371bdd1243dSDimitry Andric /// calculated during the final (fixed-point) iteration. 372bdd1243dSDimitry Andric DenseMap<const BasicBlock *, InsertMap> BBInsertBeforeMap; 373bdd1243dSDimitry Andric 374bdd1243dSDimitry Andric static bool intervalMapsAreEqual(const FragsInMemMap &A, 375bdd1243dSDimitry Andric const FragsInMemMap &B) { 376bdd1243dSDimitry Andric auto AIt = A.begin(), AEnd = A.end(); 377bdd1243dSDimitry Andric auto BIt = B.begin(), BEnd = B.end(); 378bdd1243dSDimitry Andric for (; AIt != AEnd; ++AIt, ++BIt) { 379bdd1243dSDimitry Andric if (BIt == BEnd) 380bdd1243dSDimitry Andric return false; // B has fewer elements than A. 381bdd1243dSDimitry Andric if (AIt.start() != BIt.start() || AIt.stop() != BIt.stop()) 382bdd1243dSDimitry Andric return false; // Interval is different. 383bdd1243dSDimitry Andric if (*AIt != *BIt) 384bdd1243dSDimitry Andric return false; // Value at interval is different. 385bdd1243dSDimitry Andric } 386bdd1243dSDimitry Andric // AIt == AEnd. Check BIt is also now at end. 387bdd1243dSDimitry Andric return BIt == BEnd; 388bdd1243dSDimitry Andric } 389bdd1243dSDimitry Andric 390bdd1243dSDimitry Andric static bool varFragMapsAreEqual(const VarFragMap &A, const VarFragMap &B) { 391bdd1243dSDimitry Andric if (A.size() != B.size()) 392bdd1243dSDimitry Andric return false; 393bdd1243dSDimitry Andric for (const auto &APair : A) { 394bdd1243dSDimitry Andric auto BIt = B.find(APair.first); 395bdd1243dSDimitry Andric if (BIt == B.end()) 396bdd1243dSDimitry Andric return false; 397bdd1243dSDimitry Andric if (!intervalMapsAreEqual(APair.second, BIt->second)) 398bdd1243dSDimitry Andric return false; 399bdd1243dSDimitry Andric } 400bdd1243dSDimitry Andric return true; 401bdd1243dSDimitry Andric } 402bdd1243dSDimitry Andric 403bdd1243dSDimitry Andric /// Return a string for the value that \p BaseID represents. 404bdd1243dSDimitry Andric std::string toString(unsigned BaseID) { 405bdd1243dSDimitry Andric if (BaseID) 406*06c3fb27SDimitry Andric return Bases[BaseID].getVariableLocationOp(0)->getName().str(); 407bdd1243dSDimitry Andric else 408bdd1243dSDimitry Andric return "None"; 409bdd1243dSDimitry Andric } 410bdd1243dSDimitry Andric 411bdd1243dSDimitry Andric /// Format string describing an FragsInMemMap (IntervalMap) interval. 412bdd1243dSDimitry Andric std::string toString(FragsInMemMap::const_iterator It, bool Newline = true) { 413bdd1243dSDimitry Andric std::string String; 414bdd1243dSDimitry Andric std::stringstream S(String); 415bdd1243dSDimitry Andric if (It.valid()) { 416bdd1243dSDimitry Andric S << "[" << It.start() << ", " << It.stop() 417bdd1243dSDimitry Andric << "): " << toString(It.value()); 418bdd1243dSDimitry Andric } else { 419bdd1243dSDimitry Andric S << "invalid iterator (end)"; 420bdd1243dSDimitry Andric } 421bdd1243dSDimitry Andric if (Newline) 422bdd1243dSDimitry Andric S << "\n"; 423bdd1243dSDimitry Andric return S.str(); 424bdd1243dSDimitry Andric }; 425bdd1243dSDimitry Andric 426bdd1243dSDimitry Andric FragsInMemMap meetFragments(const FragsInMemMap &A, const FragsInMemMap &B) { 427bdd1243dSDimitry Andric FragsInMemMap Result(IntervalMapAlloc); 428bdd1243dSDimitry Andric for (auto AIt = A.begin(), AEnd = A.end(); AIt != AEnd; ++AIt) { 429bdd1243dSDimitry Andric LLVM_DEBUG(dbgs() << "a " << toString(AIt)); 430bdd1243dSDimitry Andric // This is basically copied from process() and inverted (process is 431bdd1243dSDimitry Andric // performing something like a union whereas this is more of an 432bdd1243dSDimitry Andric // intersect). 433bdd1243dSDimitry Andric 434bdd1243dSDimitry Andric // There's no work to do if interval `a` overlaps no fragments in map `B`. 435bdd1243dSDimitry Andric if (!B.overlaps(AIt.start(), AIt.stop())) 436bdd1243dSDimitry Andric continue; 437bdd1243dSDimitry Andric 438bdd1243dSDimitry Andric // Does StartBit intersect an existing fragment? 439bdd1243dSDimitry Andric auto FirstOverlap = B.find(AIt.start()); 440bdd1243dSDimitry Andric assert(FirstOverlap != B.end()); 441bdd1243dSDimitry Andric bool IntersectStart = FirstOverlap.start() < AIt.start(); 442bdd1243dSDimitry Andric LLVM_DEBUG(dbgs() << "- FirstOverlap " << toString(FirstOverlap, false) 443bdd1243dSDimitry Andric << ", IntersectStart: " << IntersectStart << "\n"); 444bdd1243dSDimitry Andric 445bdd1243dSDimitry Andric // Does EndBit intersect an existing fragment? 446bdd1243dSDimitry Andric auto LastOverlap = B.find(AIt.stop()); 447bdd1243dSDimitry Andric bool IntersectEnd = 448bdd1243dSDimitry Andric LastOverlap != B.end() && LastOverlap.start() < AIt.stop(); 449bdd1243dSDimitry Andric LLVM_DEBUG(dbgs() << "- LastOverlap " << toString(LastOverlap, false) 450bdd1243dSDimitry Andric << ", IntersectEnd: " << IntersectEnd << "\n"); 451bdd1243dSDimitry Andric 452bdd1243dSDimitry Andric // Check if both ends of `a` intersect the same interval `b`. 453bdd1243dSDimitry Andric if (IntersectStart && IntersectEnd && FirstOverlap == LastOverlap) { 454bdd1243dSDimitry Andric // Insert `a` (`a` is contained in `b`) if the values match. 455bdd1243dSDimitry Andric // [ a ] 456bdd1243dSDimitry Andric // [ - b - ] 457bdd1243dSDimitry Andric // - 458bdd1243dSDimitry Andric // [ r ] 459bdd1243dSDimitry Andric LLVM_DEBUG(dbgs() << "- a is contained within " 460bdd1243dSDimitry Andric << toString(FirstOverlap)); 461bdd1243dSDimitry Andric if (*AIt && *AIt == *FirstOverlap) 462bdd1243dSDimitry Andric Result.insert(AIt.start(), AIt.stop(), *AIt); 463bdd1243dSDimitry Andric } else { 464bdd1243dSDimitry Andric // There's an overlap but `a` is not fully contained within 465bdd1243dSDimitry Andric // `b`. Shorten any end-point intersections. 466bdd1243dSDimitry Andric // [ - a - ] 467bdd1243dSDimitry Andric // [ - b - ] 468bdd1243dSDimitry Andric // - 469bdd1243dSDimitry Andric // [ r ] 470bdd1243dSDimitry Andric auto Next = FirstOverlap; 471bdd1243dSDimitry Andric if (IntersectStart) { 472bdd1243dSDimitry Andric LLVM_DEBUG(dbgs() << "- insert intersection of a and " 473bdd1243dSDimitry Andric << toString(FirstOverlap)); 474bdd1243dSDimitry Andric if (*AIt && *AIt == *FirstOverlap) 475bdd1243dSDimitry Andric Result.insert(AIt.start(), FirstOverlap.stop(), *AIt); 476bdd1243dSDimitry Andric ++Next; 477bdd1243dSDimitry Andric } 478bdd1243dSDimitry Andric // [ - a - ] 479bdd1243dSDimitry Andric // [ - b - ] 480bdd1243dSDimitry Andric // - 481bdd1243dSDimitry Andric // [ r ] 482bdd1243dSDimitry Andric if (IntersectEnd) { 483bdd1243dSDimitry Andric LLVM_DEBUG(dbgs() << "- insert intersection of a and " 484bdd1243dSDimitry Andric << toString(LastOverlap)); 485bdd1243dSDimitry Andric if (*AIt && *AIt == *LastOverlap) 486bdd1243dSDimitry Andric Result.insert(LastOverlap.start(), AIt.stop(), *AIt); 487bdd1243dSDimitry Andric } 488bdd1243dSDimitry Andric 489bdd1243dSDimitry Andric // Insert all intervals in map `B` that are contained within interval 490bdd1243dSDimitry Andric // `a` where the values match. 491bdd1243dSDimitry Andric // [ - - a - - ] 492bdd1243dSDimitry Andric // [ b1 ] [ b2 ] 493bdd1243dSDimitry Andric // - 494bdd1243dSDimitry Andric // [ r1 ] [ r2 ] 495bdd1243dSDimitry Andric while (Next != B.end() && Next.start() < AIt.stop() && 496bdd1243dSDimitry Andric Next.stop() <= AIt.stop()) { 497bdd1243dSDimitry Andric LLVM_DEBUG(dbgs() 498bdd1243dSDimitry Andric << "- insert intersection of a and " << toString(Next)); 499bdd1243dSDimitry Andric if (*AIt && *AIt == *Next) 500bdd1243dSDimitry Andric Result.insert(Next.start(), Next.stop(), *Next); 501bdd1243dSDimitry Andric ++Next; 502bdd1243dSDimitry Andric } 503bdd1243dSDimitry Andric } 504bdd1243dSDimitry Andric } 505bdd1243dSDimitry Andric return Result; 506bdd1243dSDimitry Andric } 507bdd1243dSDimitry Andric 508bdd1243dSDimitry Andric /// Meet \p A and \p B, storing the result in \p A. 509bdd1243dSDimitry Andric void meetVars(VarFragMap &A, const VarFragMap &B) { 510bdd1243dSDimitry Andric // Meet A and B. 511bdd1243dSDimitry Andric // 512bdd1243dSDimitry Andric // Result = meet(a, b) for a in A, b in B where Var(a) == Var(b) 513bdd1243dSDimitry Andric for (auto It = A.begin(), End = A.end(); It != End; ++It) { 514bdd1243dSDimitry Andric unsigned AVar = It->first; 515bdd1243dSDimitry Andric FragsInMemMap &AFrags = It->second; 516bdd1243dSDimitry Andric auto BIt = B.find(AVar); 517bdd1243dSDimitry Andric if (BIt == B.end()) { 518bdd1243dSDimitry Andric A.erase(It); 519bdd1243dSDimitry Andric continue; // Var has no bits defined in B. 520bdd1243dSDimitry Andric } 521bdd1243dSDimitry Andric LLVM_DEBUG(dbgs() << "meet fragment maps for " 522bdd1243dSDimitry Andric << Aggregates[AVar].first->getName() << "\n"); 523bdd1243dSDimitry Andric AFrags = meetFragments(AFrags, BIt->second); 524bdd1243dSDimitry Andric } 525bdd1243dSDimitry Andric } 526bdd1243dSDimitry Andric 527bdd1243dSDimitry Andric bool meet(const BasicBlock &BB, 528bdd1243dSDimitry Andric const SmallPtrSet<BasicBlock *, 16> &Visited) { 529bdd1243dSDimitry Andric LLVM_DEBUG(dbgs() << "meet block info from preds of " << BB.getName() 530bdd1243dSDimitry Andric << "\n"); 531bdd1243dSDimitry Andric 532bdd1243dSDimitry Andric VarFragMap BBLiveIn; 533bdd1243dSDimitry Andric bool FirstMeet = true; 534bdd1243dSDimitry Andric // LiveIn locs for BB is the meet of the already-processed preds' LiveOut 535bdd1243dSDimitry Andric // locs. 536bdd1243dSDimitry Andric for (auto I = pred_begin(&BB), E = pred_end(&BB); I != E; I++) { 537bdd1243dSDimitry Andric // Ignore preds that haven't been processed yet. This is essentially the 538bdd1243dSDimitry Andric // same as initialising all variables to implicit top value (⊤) which is 539bdd1243dSDimitry Andric // the identity value for the meet operation. 540bdd1243dSDimitry Andric const BasicBlock *Pred = *I; 541bdd1243dSDimitry Andric if (!Visited.count(Pred)) 542bdd1243dSDimitry Andric continue; 543bdd1243dSDimitry Andric 544bdd1243dSDimitry Andric auto PredLiveOut = LiveOut.find(Pred); 545bdd1243dSDimitry Andric assert(PredLiveOut != LiveOut.end()); 546bdd1243dSDimitry Andric 547bdd1243dSDimitry Andric if (FirstMeet) { 548bdd1243dSDimitry Andric LLVM_DEBUG(dbgs() << "BBLiveIn = " << Pred->getName() << "\n"); 549bdd1243dSDimitry Andric BBLiveIn = PredLiveOut->second; 550bdd1243dSDimitry Andric FirstMeet = false; 551bdd1243dSDimitry Andric } else { 552bdd1243dSDimitry Andric LLVM_DEBUG(dbgs() << "BBLiveIn = meet BBLiveIn, " << Pred->getName() 553bdd1243dSDimitry Andric << "\n"); 554bdd1243dSDimitry Andric meetVars(BBLiveIn, PredLiveOut->second); 555bdd1243dSDimitry Andric } 556bdd1243dSDimitry Andric 557bdd1243dSDimitry Andric // An empty set is ⊥ for the intersect-like meet operation. If we've 558bdd1243dSDimitry Andric // already got ⊥ there's no need to run the code - we know the result is 559bdd1243dSDimitry Andric // ⊥ since `meet(a, ⊥) = ⊥`. 560bdd1243dSDimitry Andric if (BBLiveIn.size() == 0) 561bdd1243dSDimitry Andric break; 562bdd1243dSDimitry Andric } 563bdd1243dSDimitry Andric 564bdd1243dSDimitry Andric auto CurrentLiveInEntry = LiveIn.find(&BB); 565bdd1243dSDimitry Andric // If there's no LiveIn entry for the block yet, add it. 566bdd1243dSDimitry Andric if (CurrentLiveInEntry == LiveIn.end()) { 567bdd1243dSDimitry Andric LLVM_DEBUG(dbgs() << "change=true (first) on meet on " << BB.getName() 568bdd1243dSDimitry Andric << "\n"); 569bdd1243dSDimitry Andric LiveIn[&BB] = std::move(BBLiveIn); 570bdd1243dSDimitry Andric return /*Changed=*/true; 571bdd1243dSDimitry Andric } 572bdd1243dSDimitry Andric 573bdd1243dSDimitry Andric // If the LiveIn set has changed (expensive check) update it and return 574bdd1243dSDimitry Andric // true. 575bdd1243dSDimitry Andric if (!varFragMapsAreEqual(BBLiveIn, CurrentLiveInEntry->second)) { 576bdd1243dSDimitry Andric LLVM_DEBUG(dbgs() << "change=true on meet on " << BB.getName() << "\n"); 577bdd1243dSDimitry Andric CurrentLiveInEntry->second = std::move(BBLiveIn); 578bdd1243dSDimitry Andric return /*Changed=*/true; 579bdd1243dSDimitry Andric } 580bdd1243dSDimitry Andric 581bdd1243dSDimitry Andric LLVM_DEBUG(dbgs() << "change=false on meet on " << BB.getName() << "\n"); 582bdd1243dSDimitry Andric return /*Changed=*/false; 583bdd1243dSDimitry Andric } 584bdd1243dSDimitry Andric 585bdd1243dSDimitry Andric void insertMemLoc(BasicBlock &BB, Instruction &Before, unsigned Var, 586bdd1243dSDimitry Andric unsigned StartBit, unsigned EndBit, unsigned Base, 587bdd1243dSDimitry Andric DebugLoc DL) { 588bdd1243dSDimitry Andric assert(StartBit < EndBit && "Cannot create fragment of size <= 0"); 589bdd1243dSDimitry Andric if (!Base) 590bdd1243dSDimitry Andric return; 591bdd1243dSDimitry Andric FragMemLoc Loc; 592bdd1243dSDimitry Andric Loc.Var = Var; 593bdd1243dSDimitry Andric Loc.OffsetInBits = StartBit; 594bdd1243dSDimitry Andric Loc.SizeInBits = EndBit - StartBit; 595bdd1243dSDimitry Andric assert(Base && "Expected a non-zero ID for Base address"); 596bdd1243dSDimitry Andric Loc.Base = Base; 597bdd1243dSDimitry Andric Loc.DL = DL; 598bdd1243dSDimitry Andric BBInsertBeforeMap[&BB][&Before].push_back(Loc); 599bdd1243dSDimitry Andric LLVM_DEBUG(dbgs() << "Add mem def for " << Aggregates[Var].first->getName() 600bdd1243dSDimitry Andric << " bits [" << StartBit << ", " << EndBit << ")\n"); 601bdd1243dSDimitry Andric } 602bdd1243dSDimitry Andric 603*06c3fb27SDimitry Andric /// Inserts a new dbg def if the interval found when looking up \p StartBit 604*06c3fb27SDimitry Andric /// in \p FragMap starts before \p StartBit or ends after \p EndBit (which 605*06c3fb27SDimitry Andric /// indicates - assuming StartBit->EndBit has just been inserted - that the 606*06c3fb27SDimitry Andric /// slice has been coalesced in the map). 607*06c3fb27SDimitry Andric void coalesceFragments(BasicBlock &BB, Instruction &Before, unsigned Var, 608*06c3fb27SDimitry Andric unsigned StartBit, unsigned EndBit, unsigned Base, 609*06c3fb27SDimitry Andric DebugLoc DL, const FragsInMemMap &FragMap) { 610*06c3fb27SDimitry Andric if (!CoalesceAdjacentFragments) 611*06c3fb27SDimitry Andric return; 612*06c3fb27SDimitry Andric // We've inserted the location into the map. The map will have coalesced 613*06c3fb27SDimitry Andric // adjacent intervals (variable fragments) that describe the same memory 614*06c3fb27SDimitry Andric // location. Use this knowledge to insert a debug location that describes 615*06c3fb27SDimitry Andric // that coalesced fragment. This may eclipse other locs we've just 616*06c3fb27SDimitry Andric // inserted. This is okay as redundant locs will be cleaned up later. 617*06c3fb27SDimitry Andric auto CoalescedFrag = FragMap.find(StartBit); 618*06c3fb27SDimitry Andric // Bail if no coalescing has taken place. 619*06c3fb27SDimitry Andric if (CoalescedFrag.start() == StartBit && CoalescedFrag.stop() == EndBit) 620*06c3fb27SDimitry Andric return; 621*06c3fb27SDimitry Andric 622*06c3fb27SDimitry Andric LLVM_DEBUG(dbgs() << "- Insert loc for bits " << CoalescedFrag.start() 623*06c3fb27SDimitry Andric << " to " << CoalescedFrag.stop() << "\n"); 624*06c3fb27SDimitry Andric insertMemLoc(BB, Before, Var, CoalescedFrag.start(), CoalescedFrag.stop(), 625*06c3fb27SDimitry Andric Base, DL); 626*06c3fb27SDimitry Andric } 627*06c3fb27SDimitry Andric 628bdd1243dSDimitry Andric void addDef(const VarLocInfo &VarLoc, Instruction &Before, BasicBlock &BB, 629bdd1243dSDimitry Andric VarFragMap &LiveSet) { 630bdd1243dSDimitry Andric DebugVariable DbgVar = FnVarLocs->getVariable(VarLoc.VariableID); 631bdd1243dSDimitry Andric if (skipVariable(DbgVar.getVariable())) 632bdd1243dSDimitry Andric return; 633bdd1243dSDimitry Andric // Don't bother doing anything for this variables if we know it's fully 634bdd1243dSDimitry Andric // promoted. We're only interested in variables that (sometimes) live on 635bdd1243dSDimitry Andric // the stack here. 636bdd1243dSDimitry Andric if (!VarsWithStackSlot->count(getAggregate(DbgVar))) 637bdd1243dSDimitry Andric return; 638bdd1243dSDimitry Andric unsigned Var = Aggregates.insert( 639bdd1243dSDimitry Andric DebugAggregate(DbgVar.getVariable(), VarLoc.DL.getInlinedAt())); 640bdd1243dSDimitry Andric 641bdd1243dSDimitry Andric // [StartBit: EndBit) are the bits affected by this def. 642bdd1243dSDimitry Andric const DIExpression *DIExpr = VarLoc.Expr; 643bdd1243dSDimitry Andric unsigned StartBit; 644bdd1243dSDimitry Andric unsigned EndBit; 645bdd1243dSDimitry Andric if (auto Frag = DIExpr->getFragmentInfo()) { 646bdd1243dSDimitry Andric StartBit = Frag->OffsetInBits; 647bdd1243dSDimitry Andric EndBit = StartBit + Frag->SizeInBits; 648bdd1243dSDimitry Andric } else { 649bdd1243dSDimitry Andric assert(static_cast<bool>(DbgVar.getVariable()->getSizeInBits())); 650bdd1243dSDimitry Andric StartBit = 0; 651bdd1243dSDimitry Andric EndBit = *DbgVar.getVariable()->getSizeInBits(); 652bdd1243dSDimitry Andric } 653bdd1243dSDimitry Andric 654bdd1243dSDimitry Andric // We will only fill fragments for simple memory-describing dbg.value 655bdd1243dSDimitry Andric // intrinsics. If the fragment offset is the same as the offset from the 656bdd1243dSDimitry Andric // base pointer, do The Thing, otherwise fall back to normal dbg.value 657bdd1243dSDimitry Andric // behaviour. AssignmentTrackingLowering has generated DIExpressions 658bdd1243dSDimitry Andric // written in terms of the base pointer. 659bdd1243dSDimitry Andric // TODO: Remove this condition since the fragment offset doesn't always 660bdd1243dSDimitry Andric // equal the offset from base pointer (e.g. for a SROA-split variable). 661bdd1243dSDimitry Andric const auto DerefOffsetInBytes = getDerefOffsetInBytes(DIExpr); 662bdd1243dSDimitry Andric const unsigned Base = 663bdd1243dSDimitry Andric DerefOffsetInBytes && *DerefOffsetInBytes * 8 == StartBit 664*06c3fb27SDimitry Andric ? Bases.insert(VarLoc.Values) 665bdd1243dSDimitry Andric : 0; 666bdd1243dSDimitry Andric LLVM_DEBUG(dbgs() << "DEF " << DbgVar.getVariable()->getName() << " [" 667bdd1243dSDimitry Andric << StartBit << ", " << EndBit << "): " << toString(Base) 668bdd1243dSDimitry Andric << "\n"); 669bdd1243dSDimitry Andric 670bdd1243dSDimitry Andric // First of all, any locs that use mem that are disrupted need reinstating. 671bdd1243dSDimitry Andric // Unfortunately, IntervalMap doesn't let us insert intervals that overlap 672bdd1243dSDimitry Andric // with existing intervals so this code involves a lot of fiddling around 673bdd1243dSDimitry Andric // with intervals to do that manually. 674bdd1243dSDimitry Andric auto FragIt = LiveSet.find(Var); 675bdd1243dSDimitry Andric 676bdd1243dSDimitry Andric // Check if the variable does not exist in the map. 677bdd1243dSDimitry Andric if (FragIt == LiveSet.end()) { 678bdd1243dSDimitry Andric // Add this variable to the BB map. 679bdd1243dSDimitry Andric auto P = LiveSet.try_emplace(Var, FragsInMemMap(IntervalMapAlloc)); 680bdd1243dSDimitry Andric assert(P.second && "Var already in map?"); 681bdd1243dSDimitry Andric // Add the interval to the fragment map. 682bdd1243dSDimitry Andric P.first->second.insert(StartBit, EndBit, Base); 683bdd1243dSDimitry Andric return; 684bdd1243dSDimitry Andric } 685bdd1243dSDimitry Andric // The variable has an entry in the map. 686bdd1243dSDimitry Andric 687bdd1243dSDimitry Andric FragsInMemMap &FragMap = FragIt->second; 688bdd1243dSDimitry Andric // First check the easy case: the new fragment `f` doesn't overlap with any 689bdd1243dSDimitry Andric // intervals. 690bdd1243dSDimitry Andric if (!FragMap.overlaps(StartBit, EndBit)) { 691bdd1243dSDimitry Andric LLVM_DEBUG(dbgs() << "- No overlaps\n"); 692bdd1243dSDimitry Andric FragMap.insert(StartBit, EndBit, Base); 693*06c3fb27SDimitry Andric coalesceFragments(BB, Before, Var, StartBit, EndBit, Base, VarLoc.DL, 694*06c3fb27SDimitry Andric FragMap); 695bdd1243dSDimitry Andric return; 696bdd1243dSDimitry Andric } 697bdd1243dSDimitry Andric // There is at least one overlap. 698bdd1243dSDimitry Andric 699bdd1243dSDimitry Andric // Does StartBit intersect an existing fragment? 700bdd1243dSDimitry Andric auto FirstOverlap = FragMap.find(StartBit); 701bdd1243dSDimitry Andric assert(FirstOverlap != FragMap.end()); 702bdd1243dSDimitry Andric bool IntersectStart = FirstOverlap.start() < StartBit; 703bdd1243dSDimitry Andric 704bdd1243dSDimitry Andric // Does EndBit intersect an existing fragment? 705bdd1243dSDimitry Andric auto LastOverlap = FragMap.find(EndBit); 706bdd1243dSDimitry Andric bool IntersectEnd = LastOverlap.valid() && LastOverlap.start() < EndBit; 707bdd1243dSDimitry Andric 708bdd1243dSDimitry Andric // Check if both ends of `f` intersect the same interval `i`. 709bdd1243dSDimitry Andric if (IntersectStart && IntersectEnd && FirstOverlap == LastOverlap) { 710bdd1243dSDimitry Andric LLVM_DEBUG(dbgs() << "- Intersect single interval @ both ends\n"); 711bdd1243dSDimitry Andric // Shorten `i` so that there's space to insert `f`. 712bdd1243dSDimitry Andric // [ f ] 713bdd1243dSDimitry Andric // [ - i - ] 714bdd1243dSDimitry Andric // + 715bdd1243dSDimitry Andric // [ i ][ f ][ i ] 716bdd1243dSDimitry Andric 717bdd1243dSDimitry Andric // Save values for use after inserting a new interval. 718bdd1243dSDimitry Andric auto EndBitOfOverlap = FirstOverlap.stop(); 719bdd1243dSDimitry Andric unsigned OverlapValue = FirstOverlap.value(); 720bdd1243dSDimitry Andric 721bdd1243dSDimitry Andric // Shorten the overlapping interval. 722bdd1243dSDimitry Andric FirstOverlap.setStop(StartBit); 723bdd1243dSDimitry Andric insertMemLoc(BB, Before, Var, FirstOverlap.start(), StartBit, 724bdd1243dSDimitry Andric OverlapValue, VarLoc.DL); 725bdd1243dSDimitry Andric 726bdd1243dSDimitry Andric // Insert a new interval to represent the end part. 727bdd1243dSDimitry Andric FragMap.insert(EndBit, EndBitOfOverlap, OverlapValue); 728bdd1243dSDimitry Andric insertMemLoc(BB, Before, Var, EndBit, EndBitOfOverlap, OverlapValue, 729bdd1243dSDimitry Andric VarLoc.DL); 730bdd1243dSDimitry Andric 731bdd1243dSDimitry Andric // Insert the new (middle) fragment now there is space. 732bdd1243dSDimitry Andric FragMap.insert(StartBit, EndBit, Base); 733bdd1243dSDimitry Andric } else { 734bdd1243dSDimitry Andric // There's an overlap but `f` may not be fully contained within 735bdd1243dSDimitry Andric // `i`. Shorten any end-point intersections so that we can then 736bdd1243dSDimitry Andric // insert `f`. 737bdd1243dSDimitry Andric // [ - f - ] 738bdd1243dSDimitry Andric // [ - i - ] 739bdd1243dSDimitry Andric // | | 740bdd1243dSDimitry Andric // [ i ] 741bdd1243dSDimitry Andric // Shorten any end-point intersections. 742bdd1243dSDimitry Andric if (IntersectStart) { 743bdd1243dSDimitry Andric LLVM_DEBUG(dbgs() << "- Intersect interval at start\n"); 744bdd1243dSDimitry Andric // Split off at the intersection. 745bdd1243dSDimitry Andric FirstOverlap.setStop(StartBit); 746bdd1243dSDimitry Andric insertMemLoc(BB, Before, Var, FirstOverlap.start(), StartBit, 747bdd1243dSDimitry Andric *FirstOverlap, VarLoc.DL); 748bdd1243dSDimitry Andric } 749bdd1243dSDimitry Andric // [ - f - ] 750bdd1243dSDimitry Andric // [ - i - ] 751bdd1243dSDimitry Andric // | | 752bdd1243dSDimitry Andric // [ i ] 753bdd1243dSDimitry Andric if (IntersectEnd) { 754bdd1243dSDimitry Andric LLVM_DEBUG(dbgs() << "- Intersect interval at end\n"); 755bdd1243dSDimitry Andric // Split off at the intersection. 756bdd1243dSDimitry Andric LastOverlap.setStart(EndBit); 757bdd1243dSDimitry Andric insertMemLoc(BB, Before, Var, EndBit, LastOverlap.stop(), *LastOverlap, 758bdd1243dSDimitry Andric VarLoc.DL); 759bdd1243dSDimitry Andric } 760bdd1243dSDimitry Andric 761bdd1243dSDimitry Andric LLVM_DEBUG(dbgs() << "- Erase intervals contained within\n"); 762bdd1243dSDimitry Andric // FirstOverlap and LastOverlap have been shortened such that they're 763bdd1243dSDimitry Andric // no longer overlapping with [StartBit, EndBit). Delete any overlaps 764bdd1243dSDimitry Andric // that remain (these will be fully contained within `f`). 765bdd1243dSDimitry Andric // [ - f - ] } 766bdd1243dSDimitry Andric // [ - i - ] } Intersection shortening that has happened above. 767bdd1243dSDimitry Andric // | | } 768bdd1243dSDimitry Andric // [ i ] } 769bdd1243dSDimitry Andric // ----------------- 770bdd1243dSDimitry Andric // [i2 ] } Intervals fully contained within `f` get erased. 771bdd1243dSDimitry Andric // ----------------- 772bdd1243dSDimitry Andric // [ - f - ][ i ] } Completed insertion. 773bdd1243dSDimitry Andric auto It = FirstOverlap; 774bdd1243dSDimitry Andric if (IntersectStart) 775bdd1243dSDimitry Andric ++It; // IntersectStart: first overlap has been shortened. 776bdd1243dSDimitry Andric while (It.valid() && It.start() >= StartBit && It.stop() <= EndBit) { 777bdd1243dSDimitry Andric LLVM_DEBUG(dbgs() << "- Erase " << toString(It)); 778bdd1243dSDimitry Andric It.erase(); // This increments It after removing the interval. 779bdd1243dSDimitry Andric } 780bdd1243dSDimitry Andric // We've dealt with all the overlaps now! 781bdd1243dSDimitry Andric assert(!FragMap.overlaps(StartBit, EndBit)); 782bdd1243dSDimitry Andric LLVM_DEBUG(dbgs() << "- Insert DEF into now-empty space\n"); 783bdd1243dSDimitry Andric FragMap.insert(StartBit, EndBit, Base); 784bdd1243dSDimitry Andric } 785*06c3fb27SDimitry Andric 786*06c3fb27SDimitry Andric coalesceFragments(BB, Before, Var, StartBit, EndBit, Base, VarLoc.DL, 787*06c3fb27SDimitry Andric FragMap); 788bdd1243dSDimitry Andric } 789bdd1243dSDimitry Andric 790bdd1243dSDimitry Andric bool skipVariable(const DILocalVariable *V) { return !V->getSizeInBits(); } 791bdd1243dSDimitry Andric 792bdd1243dSDimitry Andric void process(BasicBlock &BB, VarFragMap &LiveSet) { 793bdd1243dSDimitry Andric BBInsertBeforeMap[&BB].clear(); 794bdd1243dSDimitry Andric for (auto &I : BB) { 795bdd1243dSDimitry Andric if (const auto *Locs = FnVarLocs->getWedge(&I)) { 796bdd1243dSDimitry Andric for (const VarLocInfo &Loc : *Locs) { 797bdd1243dSDimitry Andric addDef(Loc, I, *I.getParent(), LiveSet); 798bdd1243dSDimitry Andric } 799bdd1243dSDimitry Andric } 800bdd1243dSDimitry Andric } 801bdd1243dSDimitry Andric } 802bdd1243dSDimitry Andric 803bdd1243dSDimitry Andric public: 804bdd1243dSDimitry Andric MemLocFragmentFill(Function &Fn, 805*06c3fb27SDimitry Andric const DenseSet<DebugAggregate> *VarsWithStackSlot, 806*06c3fb27SDimitry Andric bool CoalesceAdjacentFragments) 807*06c3fb27SDimitry Andric : Fn(Fn), VarsWithStackSlot(VarsWithStackSlot), 808*06c3fb27SDimitry Andric CoalesceAdjacentFragments(CoalesceAdjacentFragments) {} 809bdd1243dSDimitry Andric 810bdd1243dSDimitry Andric /// Add variable locations to \p FnVarLocs so that any bits of a variable 811bdd1243dSDimitry Andric /// with a memory location have that location explicitly reinstated at each 812bdd1243dSDimitry Andric /// subsequent variable location definition that that doesn't overwrite those 813bdd1243dSDimitry Andric /// bits. i.e. after a variable location def, insert new defs for the memory 814bdd1243dSDimitry Andric /// location with fragments for the difference of "all bits currently in 815bdd1243dSDimitry Andric /// memory" and "the fragment of the second def". e.g. 816bdd1243dSDimitry Andric /// 817bdd1243dSDimitry Andric /// Before: 818bdd1243dSDimitry Andric /// 819bdd1243dSDimitry Andric /// var x bits 0 to 63: value in memory 820bdd1243dSDimitry Andric /// more instructions 821bdd1243dSDimitry Andric /// var x bits 0 to 31: value is %0 822bdd1243dSDimitry Andric /// 823bdd1243dSDimitry Andric /// After: 824bdd1243dSDimitry Andric /// 825bdd1243dSDimitry Andric /// var x bits 0 to 63: value in memory 826bdd1243dSDimitry Andric /// more instructions 827bdd1243dSDimitry Andric /// var x bits 0 to 31: value is %0 828bdd1243dSDimitry Andric /// var x bits 32 to 61: value in memory ; <-- new loc def 829bdd1243dSDimitry Andric /// 830bdd1243dSDimitry Andric void run(FunctionVarLocsBuilder *FnVarLocs) { 831bdd1243dSDimitry Andric if (!EnableMemLocFragFill) 832bdd1243dSDimitry Andric return; 833bdd1243dSDimitry Andric 834bdd1243dSDimitry Andric this->FnVarLocs = FnVarLocs; 835bdd1243dSDimitry Andric 836bdd1243dSDimitry Andric // Prepare for traversal. 837bdd1243dSDimitry Andric // 838bdd1243dSDimitry Andric ReversePostOrderTraversal<Function *> RPOT(&Fn); 839bdd1243dSDimitry Andric std::priority_queue<unsigned int, std::vector<unsigned int>, 840bdd1243dSDimitry Andric std::greater<unsigned int>> 841bdd1243dSDimitry Andric Worklist; 842bdd1243dSDimitry Andric std::priority_queue<unsigned int, std::vector<unsigned int>, 843bdd1243dSDimitry Andric std::greater<unsigned int>> 844bdd1243dSDimitry Andric Pending; 845bdd1243dSDimitry Andric DenseMap<unsigned int, BasicBlock *> OrderToBB; 846bdd1243dSDimitry Andric DenseMap<BasicBlock *, unsigned int> BBToOrder; 847bdd1243dSDimitry Andric { // Init OrderToBB and BBToOrder. 848bdd1243dSDimitry Andric unsigned int RPONumber = 0; 849bdd1243dSDimitry Andric for (auto RI = RPOT.begin(), RE = RPOT.end(); RI != RE; ++RI) { 850bdd1243dSDimitry Andric OrderToBB[RPONumber] = *RI; 851bdd1243dSDimitry Andric BBToOrder[*RI] = RPONumber; 852bdd1243dSDimitry Andric Worklist.push(RPONumber); 853bdd1243dSDimitry Andric ++RPONumber; 854bdd1243dSDimitry Andric } 855bdd1243dSDimitry Andric LiveIn.init(RPONumber); 856bdd1243dSDimitry Andric LiveOut.init(RPONumber); 857bdd1243dSDimitry Andric } 858bdd1243dSDimitry Andric 859bdd1243dSDimitry Andric // Perform the traversal. 860bdd1243dSDimitry Andric // 861bdd1243dSDimitry Andric // This is a standard "intersect of predecessor outs" dataflow problem. To 862bdd1243dSDimitry Andric // solve it, we perform meet() and process() using the two worklist method 863bdd1243dSDimitry Andric // until the LiveIn data for each block becomes unchanging. 864bdd1243dSDimitry Andric // 865bdd1243dSDimitry Andric // This dataflow is essentially working on maps of sets and at each meet we 866bdd1243dSDimitry Andric // intersect the maps and the mapped sets. So, initialized live-in maps 867bdd1243dSDimitry Andric // monotonically decrease in value throughout the dataflow. 868bdd1243dSDimitry Andric SmallPtrSet<BasicBlock *, 16> Visited; 869bdd1243dSDimitry Andric while (!Worklist.empty() || !Pending.empty()) { 870bdd1243dSDimitry Andric // We track what is on the pending worklist to avoid inserting the same 871bdd1243dSDimitry Andric // thing twice. We could avoid this with a custom priority queue, but 872bdd1243dSDimitry Andric // this is probably not worth it. 873bdd1243dSDimitry Andric SmallPtrSet<BasicBlock *, 16> OnPending; 874bdd1243dSDimitry Andric LLVM_DEBUG(dbgs() << "Processing Worklist\n"); 875bdd1243dSDimitry Andric while (!Worklist.empty()) { 876bdd1243dSDimitry Andric BasicBlock *BB = OrderToBB[Worklist.top()]; 877bdd1243dSDimitry Andric LLVM_DEBUG(dbgs() << "\nPop BB " << BB->getName() << "\n"); 878bdd1243dSDimitry Andric Worklist.pop(); 879bdd1243dSDimitry Andric bool InChanged = meet(*BB, Visited); 880bdd1243dSDimitry Andric // Always consider LiveIn changed on the first visit. 881bdd1243dSDimitry Andric InChanged |= Visited.insert(BB).second; 882bdd1243dSDimitry Andric if (InChanged) { 883bdd1243dSDimitry Andric LLVM_DEBUG(dbgs() 884bdd1243dSDimitry Andric << BB->getName() << " has new InLocs, process it\n"); 885bdd1243dSDimitry Andric // Mutate a copy of LiveIn while processing BB. Once we've processed 886bdd1243dSDimitry Andric // the terminator LiveSet is the LiveOut set for BB. 887bdd1243dSDimitry Andric // This is an expensive copy! 888bdd1243dSDimitry Andric VarFragMap LiveSet = LiveIn[BB]; 889bdd1243dSDimitry Andric 890bdd1243dSDimitry Andric // Process the instructions in the block. 891bdd1243dSDimitry Andric process(*BB, LiveSet); 892bdd1243dSDimitry Andric 893bdd1243dSDimitry Andric // Relatively expensive check: has anything changed in LiveOut for BB? 894bdd1243dSDimitry Andric if (!varFragMapsAreEqual(LiveOut[BB], LiveSet)) { 895bdd1243dSDimitry Andric LLVM_DEBUG(dbgs() << BB->getName() 896bdd1243dSDimitry Andric << " has new OutLocs, add succs to worklist: [ "); 897bdd1243dSDimitry Andric LiveOut[BB] = std::move(LiveSet); 898bdd1243dSDimitry Andric for (auto I = succ_begin(BB), E = succ_end(BB); I != E; I++) { 899bdd1243dSDimitry Andric if (OnPending.insert(*I).second) { 900bdd1243dSDimitry Andric LLVM_DEBUG(dbgs() << I->getName() << " "); 901bdd1243dSDimitry Andric Pending.push(BBToOrder[*I]); 902bdd1243dSDimitry Andric } 903bdd1243dSDimitry Andric } 904bdd1243dSDimitry Andric LLVM_DEBUG(dbgs() << "]\n"); 905bdd1243dSDimitry Andric } 906bdd1243dSDimitry Andric } 907bdd1243dSDimitry Andric } 908bdd1243dSDimitry Andric Worklist.swap(Pending); 909bdd1243dSDimitry Andric // At this point, pending must be empty, since it was just the empty 910bdd1243dSDimitry Andric // worklist 911bdd1243dSDimitry Andric assert(Pending.empty() && "Pending should be empty"); 912bdd1243dSDimitry Andric } 913bdd1243dSDimitry Andric 914bdd1243dSDimitry Andric // Insert new location defs. 915*06c3fb27SDimitry Andric for (auto &Pair : BBInsertBeforeMap) { 916bdd1243dSDimitry Andric InsertMap &Map = Pair.second; 917*06c3fb27SDimitry Andric for (auto &Pair : Map) { 918bdd1243dSDimitry Andric Instruction *InsertBefore = Pair.first; 919bdd1243dSDimitry Andric assert(InsertBefore && "should never be null"); 920bdd1243dSDimitry Andric auto FragMemLocs = Pair.second; 921bdd1243dSDimitry Andric auto &Ctx = Fn.getContext(); 922bdd1243dSDimitry Andric 923*06c3fb27SDimitry Andric for (auto &FragMemLoc : FragMemLocs) { 924bdd1243dSDimitry Andric DIExpression *Expr = DIExpression::get(Ctx, std::nullopt); 925*06c3fb27SDimitry Andric if (FragMemLoc.SizeInBits != 926*06c3fb27SDimitry Andric *Aggregates[FragMemLoc.Var].first->getSizeInBits()) 927bdd1243dSDimitry Andric Expr = *DIExpression::createFragmentExpression( 928bdd1243dSDimitry Andric Expr, FragMemLoc.OffsetInBits, FragMemLoc.SizeInBits); 929bdd1243dSDimitry Andric Expr = DIExpression::prepend(Expr, DIExpression::DerefAfter, 930bdd1243dSDimitry Andric FragMemLoc.OffsetInBits / 8); 931bdd1243dSDimitry Andric DebugVariable Var(Aggregates[FragMemLoc.Var].first, Expr, 932bdd1243dSDimitry Andric FragMemLoc.DL.getInlinedAt()); 933bdd1243dSDimitry Andric FnVarLocs->addVarLoc(InsertBefore, Var, Expr, FragMemLoc.DL, 934bdd1243dSDimitry Andric Bases[FragMemLoc.Base]); 935bdd1243dSDimitry Andric } 936bdd1243dSDimitry Andric } 937bdd1243dSDimitry Andric } 938bdd1243dSDimitry Andric } 939bdd1243dSDimitry Andric }; 940bdd1243dSDimitry Andric 941bdd1243dSDimitry Andric /// AssignmentTrackingLowering encapsulates a dataflow analysis over a function 942bdd1243dSDimitry Andric /// that interprets assignment tracking debug info metadata and stores in IR to 943bdd1243dSDimitry Andric /// create a map of variable locations. 944bdd1243dSDimitry Andric class AssignmentTrackingLowering { 945bdd1243dSDimitry Andric public: 946bdd1243dSDimitry Andric /// The kind of location in use for a variable, where Mem is the stack home, 947bdd1243dSDimitry Andric /// Val is an SSA value or const, and None means that there is not one single 948bdd1243dSDimitry Andric /// kind (either because there are multiple or because there is none; it may 949bdd1243dSDimitry Andric /// prove useful to split this into two values in the future). 950bdd1243dSDimitry Andric /// 951bdd1243dSDimitry Andric /// LocKind is a join-semilattice with the partial order: 952bdd1243dSDimitry Andric /// None > Mem, Val 953bdd1243dSDimitry Andric /// 954bdd1243dSDimitry Andric /// i.e. 955bdd1243dSDimitry Andric /// join(Mem, Mem) = Mem 956bdd1243dSDimitry Andric /// join(Val, Val) = Val 957bdd1243dSDimitry Andric /// join(Mem, Val) = None 958bdd1243dSDimitry Andric /// join(None, Mem) = None 959bdd1243dSDimitry Andric /// join(None, Val) = None 960bdd1243dSDimitry Andric /// join(None, None) = None 961bdd1243dSDimitry Andric /// 962bdd1243dSDimitry Andric /// Note: the order is not `None > Val > Mem` because we're using DIAssignID 963bdd1243dSDimitry Andric /// to name assignments and are not tracking the actual stored values. 964bdd1243dSDimitry Andric /// Therefore currently there's no way to ensure that Mem values and Val 965bdd1243dSDimitry Andric /// values are the same. This could be a future extension, though it's not 966bdd1243dSDimitry Andric /// clear that many additional locations would be recovered that way in 967bdd1243dSDimitry Andric /// practice as the likelihood of this sitation arising naturally seems 968bdd1243dSDimitry Andric /// incredibly low. 969bdd1243dSDimitry Andric enum class LocKind { Mem, Val, None }; 970bdd1243dSDimitry Andric 971bdd1243dSDimitry Andric /// An abstraction of the assignment of a value to a variable or memory 972bdd1243dSDimitry Andric /// location. 973bdd1243dSDimitry Andric /// 974bdd1243dSDimitry Andric /// An Assignment is Known or NoneOrPhi. A Known Assignment means we have a 975bdd1243dSDimitry Andric /// DIAssignID ptr that represents it. NoneOrPhi means that we don't (or 976bdd1243dSDimitry Andric /// can't) know the ID of the last assignment that took place. 977bdd1243dSDimitry Andric /// 978bdd1243dSDimitry Andric /// The Status of the Assignment (Known or NoneOrPhi) is another 979bdd1243dSDimitry Andric /// join-semilattice. The partial order is: 980bdd1243dSDimitry Andric /// NoneOrPhi > Known {id_0, id_1, ...id_N} 981bdd1243dSDimitry Andric /// 982bdd1243dSDimitry Andric /// i.e. for all values x and y where x != y: 983bdd1243dSDimitry Andric /// join(x, x) = x 984bdd1243dSDimitry Andric /// join(x, y) = NoneOrPhi 985bdd1243dSDimitry Andric struct Assignment { 986bdd1243dSDimitry Andric enum S { Known, NoneOrPhi } Status; 987bdd1243dSDimitry Andric /// ID of the assignment. nullptr if Status is not Known. 988bdd1243dSDimitry Andric DIAssignID *ID; 989bdd1243dSDimitry Andric /// The dbg.assign that marks this dbg-def. Mem-defs don't use this field. 990bdd1243dSDimitry Andric /// May be nullptr. 991bdd1243dSDimitry Andric DbgAssignIntrinsic *Source; 992bdd1243dSDimitry Andric 993bdd1243dSDimitry Andric bool isSameSourceAssignment(const Assignment &Other) const { 994bdd1243dSDimitry Andric // Don't include Source in the equality check. Assignments are 995bdd1243dSDimitry Andric // defined by their ID, not debug intrinsic(s). 996bdd1243dSDimitry Andric return std::tie(Status, ID) == std::tie(Other.Status, Other.ID); 997bdd1243dSDimitry Andric } 998bdd1243dSDimitry Andric void dump(raw_ostream &OS) { 999bdd1243dSDimitry Andric static const char *LUT[] = {"Known", "NoneOrPhi"}; 1000bdd1243dSDimitry Andric OS << LUT[Status] << "(id="; 1001bdd1243dSDimitry Andric if (ID) 1002bdd1243dSDimitry Andric OS << ID; 1003bdd1243dSDimitry Andric else 1004bdd1243dSDimitry Andric OS << "null"; 1005bdd1243dSDimitry Andric OS << ", s="; 1006bdd1243dSDimitry Andric if (Source) 1007bdd1243dSDimitry Andric OS << *Source; 1008bdd1243dSDimitry Andric else 1009bdd1243dSDimitry Andric OS << "null"; 1010bdd1243dSDimitry Andric OS << ")"; 1011bdd1243dSDimitry Andric } 1012bdd1243dSDimitry Andric 1013bdd1243dSDimitry Andric static Assignment make(DIAssignID *ID, DbgAssignIntrinsic *Source) { 1014bdd1243dSDimitry Andric return Assignment(Known, ID, Source); 1015bdd1243dSDimitry Andric } 1016bdd1243dSDimitry Andric static Assignment makeFromMemDef(DIAssignID *ID) { 1017bdd1243dSDimitry Andric return Assignment(Known, ID, nullptr); 1018bdd1243dSDimitry Andric } 1019bdd1243dSDimitry Andric static Assignment makeNoneOrPhi() { 1020bdd1243dSDimitry Andric return Assignment(NoneOrPhi, nullptr, nullptr); 1021bdd1243dSDimitry Andric } 1022bdd1243dSDimitry Andric // Again, need a Top value? 1023bdd1243dSDimitry Andric Assignment() 1024bdd1243dSDimitry Andric : Status(NoneOrPhi), ID(nullptr), Source(nullptr) { 1025bdd1243dSDimitry Andric } // Can we delete this? 1026bdd1243dSDimitry Andric Assignment(S Status, DIAssignID *ID, DbgAssignIntrinsic *Source) 1027bdd1243dSDimitry Andric : Status(Status), ID(ID), Source(Source) { 1028bdd1243dSDimitry Andric // If the Status is Known then we expect there to be an assignment ID. 1029bdd1243dSDimitry Andric assert(Status == NoneOrPhi || ID); 1030bdd1243dSDimitry Andric } 1031bdd1243dSDimitry Andric }; 1032bdd1243dSDimitry Andric 1033*06c3fb27SDimitry Andric using AssignmentMap = SmallVector<Assignment>; 1034*06c3fb27SDimitry Andric using LocMap = SmallVector<LocKind>; 1035*06c3fb27SDimitry Andric using OverlapMap = DenseMap<VariableID, SmallVector<VariableID>>; 1036bdd1243dSDimitry Andric using UntaggedStoreAssignmentMap = 1037bdd1243dSDimitry Andric DenseMap<const Instruction *, 1038bdd1243dSDimitry Andric SmallVector<std::pair<VariableID, at::AssignmentInfo>>>; 1039bdd1243dSDimitry Andric 1040bdd1243dSDimitry Andric private: 1041*06c3fb27SDimitry Andric /// The highest numbered VariableID for partially promoted variables plus 1, 1042*06c3fb27SDimitry Andric /// the values for which start at 1. 1043*06c3fb27SDimitry Andric unsigned TrackedVariablesVectorSize = 0; 1044bdd1243dSDimitry Andric /// Map a variable to the set of variables that it fully contains. 1045bdd1243dSDimitry Andric OverlapMap VarContains; 1046bdd1243dSDimitry Andric /// Map untagged stores to the variable fragments they assign to. Used by 1047bdd1243dSDimitry Andric /// processUntaggedInstruction. 1048bdd1243dSDimitry Andric UntaggedStoreAssignmentMap UntaggedStoreVars; 1049bdd1243dSDimitry Andric 1050bdd1243dSDimitry Andric // Machinery to defer inserting dbg.values. 1051bdd1243dSDimitry Andric using InsertMap = MapVector<Instruction *, SmallVector<VarLocInfo>>; 1052bdd1243dSDimitry Andric InsertMap InsertBeforeMap; 1053bdd1243dSDimitry Andric /// Clear the location definitions currently cached for insertion after /p 1054bdd1243dSDimitry Andric /// After. 1055bdd1243dSDimitry Andric void resetInsertionPoint(Instruction &After); 1056bdd1243dSDimitry Andric void emitDbgValue(LocKind Kind, const DbgVariableIntrinsic *Source, 1057bdd1243dSDimitry Andric Instruction *After); 1058bdd1243dSDimitry Andric 1059*06c3fb27SDimitry Andric static bool mapsAreEqual(const BitVector &Mask, const AssignmentMap &A, 1060*06c3fb27SDimitry Andric const AssignmentMap &B) { 1061*06c3fb27SDimitry Andric return llvm::all_of(Mask.set_bits(), [&](unsigned VarID) { 1062*06c3fb27SDimitry Andric return A[VarID].isSameSourceAssignment(B[VarID]); 1063*06c3fb27SDimitry Andric }); 1064bdd1243dSDimitry Andric } 1065bdd1243dSDimitry Andric 1066bdd1243dSDimitry Andric /// Represents the stack and debug assignments in a block. Used to describe 1067bdd1243dSDimitry Andric /// the live-in and live-out values for blocks, as well as the "current" 1068bdd1243dSDimitry Andric /// value as we process each instruction in a block. 1069bdd1243dSDimitry Andric struct BlockInfo { 1070*06c3fb27SDimitry Andric /// The set of variables (VariableID) being tracked in this block. 1071*06c3fb27SDimitry Andric BitVector VariableIDsInBlock; 1072*06c3fb27SDimitry Andric /// Dominating assignment to memory for each variable, indexed by 1073*06c3fb27SDimitry Andric /// VariableID. 1074bdd1243dSDimitry Andric AssignmentMap StackHomeValue; 1075*06c3fb27SDimitry Andric /// Dominating assignemnt to each variable, indexed by VariableID. 1076bdd1243dSDimitry Andric AssignmentMap DebugValue; 1077bdd1243dSDimitry Andric /// Location kind for each variable. LiveLoc indicates whether the 1078bdd1243dSDimitry Andric /// dominating assignment in StackHomeValue (LocKind::Mem), DebugValue 1079bdd1243dSDimitry Andric /// (LocKind::Val), or neither (LocKind::None) is valid, in that order of 1080bdd1243dSDimitry Andric /// preference. This cannot be derived by inspecting DebugValue and 1081bdd1243dSDimitry Andric /// StackHomeValue due to the fact that there's no distinction in 1082bdd1243dSDimitry Andric /// Assignment (the class) between whether an assignment is unknown or a 1083bdd1243dSDimitry Andric /// merge of multiple assignments (both are Status::NoneOrPhi). In other 1084bdd1243dSDimitry Andric /// words, the memory location may well be valid while both DebugValue and 1085bdd1243dSDimitry Andric /// StackHomeValue contain Assignments that have a Status of NoneOrPhi. 1086*06c3fb27SDimitry Andric /// Indexed by VariableID. 1087bdd1243dSDimitry Andric LocMap LiveLoc; 1088bdd1243dSDimitry Andric 1089*06c3fb27SDimitry Andric public: 1090*06c3fb27SDimitry Andric enum AssignmentKind { Stack, Debug }; 1091*06c3fb27SDimitry Andric const AssignmentMap &getAssignmentMap(AssignmentKind Kind) const { 1092*06c3fb27SDimitry Andric switch (Kind) { 1093*06c3fb27SDimitry Andric case Stack: 1094*06c3fb27SDimitry Andric return StackHomeValue; 1095*06c3fb27SDimitry Andric case Debug: 1096*06c3fb27SDimitry Andric return DebugValue; 1097*06c3fb27SDimitry Andric } 1098*06c3fb27SDimitry Andric llvm_unreachable("Unknown AssignmentKind"); 1099*06c3fb27SDimitry Andric } 1100*06c3fb27SDimitry Andric AssignmentMap &getAssignmentMap(AssignmentKind Kind) { 1101*06c3fb27SDimitry Andric return const_cast<AssignmentMap &>( 1102*06c3fb27SDimitry Andric const_cast<const BlockInfo *>(this)->getAssignmentMap(Kind)); 1103*06c3fb27SDimitry Andric } 1104*06c3fb27SDimitry Andric 1105*06c3fb27SDimitry Andric bool isVariableTracked(VariableID Var) const { 1106*06c3fb27SDimitry Andric return VariableIDsInBlock[static_cast<unsigned>(Var)]; 1107*06c3fb27SDimitry Andric } 1108*06c3fb27SDimitry Andric 1109*06c3fb27SDimitry Andric const Assignment &getAssignment(AssignmentKind Kind, VariableID Var) const { 1110*06c3fb27SDimitry Andric assert(isVariableTracked(Var) && "Var not tracked in block"); 1111*06c3fb27SDimitry Andric return getAssignmentMap(Kind)[static_cast<unsigned>(Var)]; 1112*06c3fb27SDimitry Andric } 1113*06c3fb27SDimitry Andric 1114*06c3fb27SDimitry Andric LocKind getLocKind(VariableID Var) const { 1115*06c3fb27SDimitry Andric assert(isVariableTracked(Var) && "Var not tracked in block"); 1116*06c3fb27SDimitry Andric return LiveLoc[static_cast<unsigned>(Var)]; 1117*06c3fb27SDimitry Andric } 1118*06c3fb27SDimitry Andric 1119*06c3fb27SDimitry Andric /// Set LocKind for \p Var only: does not set LocKind for VariableIDs of 1120*06c3fb27SDimitry Andric /// fragments contained win \p Var. 1121*06c3fb27SDimitry Andric void setLocKind(VariableID Var, LocKind K) { 1122*06c3fb27SDimitry Andric VariableIDsInBlock.set(static_cast<unsigned>(Var)); 1123*06c3fb27SDimitry Andric LiveLoc[static_cast<unsigned>(Var)] = K; 1124*06c3fb27SDimitry Andric } 1125*06c3fb27SDimitry Andric 1126*06c3fb27SDimitry Andric /// Set the assignment in the \p Kind assignment map for \p Var only: does 1127*06c3fb27SDimitry Andric /// not set the assignment for VariableIDs of fragments contained win \p 1128*06c3fb27SDimitry Andric /// Var. 1129*06c3fb27SDimitry Andric void setAssignment(AssignmentKind Kind, VariableID Var, 1130*06c3fb27SDimitry Andric const Assignment &AV) { 1131*06c3fb27SDimitry Andric VariableIDsInBlock.set(static_cast<unsigned>(Var)); 1132*06c3fb27SDimitry Andric getAssignmentMap(Kind)[static_cast<unsigned>(Var)] = AV; 1133*06c3fb27SDimitry Andric } 1134*06c3fb27SDimitry Andric 1135*06c3fb27SDimitry Andric /// Return true if there is an assignment matching \p AV in the \p Kind 1136*06c3fb27SDimitry Andric /// assignment map. Does consider assignments for VariableIDs of fragments 1137*06c3fb27SDimitry Andric /// contained win \p Var. 1138*06c3fb27SDimitry Andric bool hasAssignment(AssignmentKind Kind, VariableID Var, 1139*06c3fb27SDimitry Andric const Assignment &AV) const { 1140*06c3fb27SDimitry Andric if (!isVariableTracked(Var)) 1141*06c3fb27SDimitry Andric return false; 1142*06c3fb27SDimitry Andric return AV.isSameSourceAssignment(getAssignment(Kind, Var)); 1143*06c3fb27SDimitry Andric } 1144*06c3fb27SDimitry Andric 1145bdd1243dSDimitry Andric /// Compare every element in each map to determine structural equality 1146bdd1243dSDimitry Andric /// (slow). 1147bdd1243dSDimitry Andric bool operator==(const BlockInfo &Other) const { 1148*06c3fb27SDimitry Andric return VariableIDsInBlock == Other.VariableIDsInBlock && 1149*06c3fb27SDimitry Andric LiveLoc == Other.LiveLoc && 1150*06c3fb27SDimitry Andric mapsAreEqual(VariableIDsInBlock, StackHomeValue, 1151*06c3fb27SDimitry Andric Other.StackHomeValue) && 1152*06c3fb27SDimitry Andric mapsAreEqual(VariableIDsInBlock, DebugValue, Other.DebugValue); 1153bdd1243dSDimitry Andric } 1154bdd1243dSDimitry Andric bool operator!=(const BlockInfo &Other) const { return !(*this == Other); } 1155bdd1243dSDimitry Andric bool isValid() { 1156bdd1243dSDimitry Andric return LiveLoc.size() == DebugValue.size() && 1157bdd1243dSDimitry Andric LiveLoc.size() == StackHomeValue.size(); 1158bdd1243dSDimitry Andric } 1159*06c3fb27SDimitry Andric 1160*06c3fb27SDimitry Andric /// Clear everything and initialise with ⊤-values for all variables. 1161*06c3fb27SDimitry Andric void init(int NumVars) { 1162*06c3fb27SDimitry Andric StackHomeValue.clear(); 1163*06c3fb27SDimitry Andric DebugValue.clear(); 1164*06c3fb27SDimitry Andric LiveLoc.clear(); 1165*06c3fb27SDimitry Andric VariableIDsInBlock = BitVector(NumVars); 1166*06c3fb27SDimitry Andric StackHomeValue.insert(StackHomeValue.begin(), NumVars, 1167*06c3fb27SDimitry Andric Assignment::makeNoneOrPhi()); 1168*06c3fb27SDimitry Andric DebugValue.insert(DebugValue.begin(), NumVars, 1169*06c3fb27SDimitry Andric Assignment::makeNoneOrPhi()); 1170*06c3fb27SDimitry Andric LiveLoc.insert(LiveLoc.begin(), NumVars, LocKind::None); 1171*06c3fb27SDimitry Andric } 1172*06c3fb27SDimitry Andric 1173*06c3fb27SDimitry Andric /// Helper for join. 1174*06c3fb27SDimitry Andric template <typename ElmtType, typename FnInputType> 1175*06c3fb27SDimitry Andric static void joinElmt(int Index, SmallVector<ElmtType> &Target, 1176*06c3fb27SDimitry Andric const SmallVector<ElmtType> &A, 1177*06c3fb27SDimitry Andric const SmallVector<ElmtType> &B, 1178*06c3fb27SDimitry Andric ElmtType (*Fn)(FnInputType, FnInputType)) { 1179*06c3fb27SDimitry Andric Target[Index] = Fn(A[Index], B[Index]); 1180*06c3fb27SDimitry Andric } 1181*06c3fb27SDimitry Andric 1182*06c3fb27SDimitry Andric /// See comment for AssignmentTrackingLowering::joinBlockInfo. 1183*06c3fb27SDimitry Andric static BlockInfo join(const BlockInfo &A, const BlockInfo &B, int NumVars) { 1184*06c3fb27SDimitry Andric // Join A and B. 1185*06c3fb27SDimitry Andric // 1186*06c3fb27SDimitry Andric // Intersect = join(a, b) for a in A, b in B where Var(a) == Var(b) 1187*06c3fb27SDimitry Andric // Difference = join(x, ⊤) for x where Var(x) is in A xor B 1188*06c3fb27SDimitry Andric // Join = Intersect ∪ Difference 1189*06c3fb27SDimitry Andric // 1190*06c3fb27SDimitry Andric // This is achieved by performing a join on elements from A and B with 1191*06c3fb27SDimitry Andric // variables common to both A and B (join elements indexed by var 1192*06c3fb27SDimitry Andric // intersect), then adding ⊤-value elements for vars in A xor B. The 1193*06c3fb27SDimitry Andric // latter part is equivalent to performing join on elements with variables 1194*06c3fb27SDimitry Andric // in A xor B with the ⊤-value for the map element since join(x, ⊤) = ⊤. 1195*06c3fb27SDimitry Andric // BlockInfo::init initializes all variable entries to the ⊤ value so we 1196*06c3fb27SDimitry Andric // don't need to explicitly perform that step as Join.VariableIDsInBlock 1197*06c3fb27SDimitry Andric // is set to the union of the variables in A and B at the end of this 1198*06c3fb27SDimitry Andric // function. 1199*06c3fb27SDimitry Andric BlockInfo Join; 1200*06c3fb27SDimitry Andric Join.init(NumVars); 1201*06c3fb27SDimitry Andric 1202*06c3fb27SDimitry Andric BitVector Intersect = A.VariableIDsInBlock; 1203*06c3fb27SDimitry Andric Intersect &= B.VariableIDsInBlock; 1204*06c3fb27SDimitry Andric 1205*06c3fb27SDimitry Andric for (auto VarID : Intersect.set_bits()) { 1206*06c3fb27SDimitry Andric joinElmt(VarID, Join.LiveLoc, A.LiveLoc, B.LiveLoc, joinKind); 1207*06c3fb27SDimitry Andric joinElmt(VarID, Join.DebugValue, A.DebugValue, B.DebugValue, 1208*06c3fb27SDimitry Andric joinAssignment); 1209*06c3fb27SDimitry Andric joinElmt(VarID, Join.StackHomeValue, A.StackHomeValue, B.StackHomeValue, 1210*06c3fb27SDimitry Andric joinAssignment); 1211*06c3fb27SDimitry Andric } 1212*06c3fb27SDimitry Andric 1213*06c3fb27SDimitry Andric Join.VariableIDsInBlock = A.VariableIDsInBlock; 1214*06c3fb27SDimitry Andric Join.VariableIDsInBlock |= B.VariableIDsInBlock; 1215*06c3fb27SDimitry Andric assert(Join.isValid()); 1216*06c3fb27SDimitry Andric return Join; 1217*06c3fb27SDimitry Andric } 1218bdd1243dSDimitry Andric }; 1219bdd1243dSDimitry Andric 1220bdd1243dSDimitry Andric Function &Fn; 1221bdd1243dSDimitry Andric const DataLayout &Layout; 1222bdd1243dSDimitry Andric const DenseSet<DebugAggregate> *VarsWithStackSlot; 1223bdd1243dSDimitry Andric FunctionVarLocsBuilder *FnVarLocs; 1224bdd1243dSDimitry Andric DenseMap<const BasicBlock *, BlockInfo> LiveIn; 1225bdd1243dSDimitry Andric DenseMap<const BasicBlock *, BlockInfo> LiveOut; 1226bdd1243dSDimitry Andric 1227bdd1243dSDimitry Andric /// Helper for process methods to track variables touched each frame. 1228bdd1243dSDimitry Andric DenseSet<VariableID> VarsTouchedThisFrame; 1229bdd1243dSDimitry Andric 1230bdd1243dSDimitry Andric /// The set of variables that sometimes are not located in their stack home. 1231bdd1243dSDimitry Andric DenseSet<DebugAggregate> NotAlwaysStackHomed; 1232bdd1243dSDimitry Andric 1233bdd1243dSDimitry Andric VariableID getVariableID(const DebugVariable &Var) { 1234bdd1243dSDimitry Andric return static_cast<VariableID>(FnVarLocs->insertVariable(Var)); 1235bdd1243dSDimitry Andric } 1236bdd1243dSDimitry Andric 1237bdd1243dSDimitry Andric /// Join the LiveOut values of preds that are contained in \p Visited into 1238bdd1243dSDimitry Andric /// LiveIn[BB]. Return True if LiveIn[BB] has changed as a result. LiveIn[BB] 1239bdd1243dSDimitry Andric /// values monotonically increase. See the @link joinMethods join methods 1240bdd1243dSDimitry Andric /// @endlink documentation for more info. 1241bdd1243dSDimitry Andric bool join(const BasicBlock &BB, const SmallPtrSet<BasicBlock *, 16> &Visited); 1242bdd1243dSDimitry Andric ///@name joinMethods 1243bdd1243dSDimitry Andric /// Functions that implement `join` (the least upper bound) for the 1244bdd1243dSDimitry Andric /// join-semilattice types used in the dataflow. There is an explicit bottom 1245bdd1243dSDimitry Andric /// value (⊥) for some types and and explicit top value (⊤) for all types. 1246bdd1243dSDimitry Andric /// By definition: 1247bdd1243dSDimitry Andric /// 1248bdd1243dSDimitry Andric /// Join(A, B) >= A && Join(A, B) >= B 1249bdd1243dSDimitry Andric /// Join(A, ⊥) = A 1250bdd1243dSDimitry Andric /// Join(A, ⊤) = ⊤ 1251bdd1243dSDimitry Andric /// 1252bdd1243dSDimitry Andric /// These invariants are important for monotonicity. 1253bdd1243dSDimitry Andric /// 1254bdd1243dSDimitry Andric /// For the map-type functions, all unmapped keys in an empty map are 1255bdd1243dSDimitry Andric /// associated with a bottom value (⊥). This represents their values being 1256bdd1243dSDimitry Andric /// unknown. Unmapped keys in non-empty maps (joining two maps with a key 1257bdd1243dSDimitry Andric /// only present in one) represents either a variable going out of scope or 1258bdd1243dSDimitry Andric /// dropped debug info. It is assumed the key is associated with a top value 1259bdd1243dSDimitry Andric /// (⊤) in this case (unknown location / assignment). 1260bdd1243dSDimitry Andric ///@{ 1261bdd1243dSDimitry Andric static LocKind joinKind(LocKind A, LocKind B); 1262bdd1243dSDimitry Andric static Assignment joinAssignment(const Assignment &A, const Assignment &B); 1263*06c3fb27SDimitry Andric BlockInfo joinBlockInfo(const BlockInfo &A, const BlockInfo &B); 1264bdd1243dSDimitry Andric ///@} 1265bdd1243dSDimitry Andric 1266bdd1243dSDimitry Andric /// Process the instructions in \p BB updating \p LiveSet along the way. \p 1267bdd1243dSDimitry Andric /// LiveSet must be initialized with the current live-in locations before 1268bdd1243dSDimitry Andric /// calling this. 1269bdd1243dSDimitry Andric void process(BasicBlock &BB, BlockInfo *LiveSet); 1270bdd1243dSDimitry Andric ///@name processMethods 1271bdd1243dSDimitry Andric /// Methods to process instructions in order to update the LiveSet (current 1272bdd1243dSDimitry Andric /// location information). 1273bdd1243dSDimitry Andric ///@{ 1274bdd1243dSDimitry Andric void processNonDbgInstruction(Instruction &I, BlockInfo *LiveSet); 1275*06c3fb27SDimitry Andric void processDbgInstruction(DbgInfoIntrinsic &I, BlockInfo *LiveSet); 1276bdd1243dSDimitry Andric /// Update \p LiveSet after encountering an instruction with a DIAssignID 1277bdd1243dSDimitry Andric /// attachment, \p I. 1278bdd1243dSDimitry Andric void processTaggedInstruction(Instruction &I, BlockInfo *LiveSet); 1279bdd1243dSDimitry Andric /// Update \p LiveSet after encountering an instruciton without a DIAssignID 1280bdd1243dSDimitry Andric /// attachment, \p I. 1281bdd1243dSDimitry Andric void processUntaggedInstruction(Instruction &I, BlockInfo *LiveSet); 1282bdd1243dSDimitry Andric void processDbgAssign(DbgAssignIntrinsic &DAI, BlockInfo *LiveSet); 1283bdd1243dSDimitry Andric void processDbgValue(DbgValueInst &DVI, BlockInfo *LiveSet); 1284bdd1243dSDimitry Andric /// Add an assignment to memory for the variable /p Var. 1285bdd1243dSDimitry Andric void addMemDef(BlockInfo *LiveSet, VariableID Var, const Assignment &AV); 1286bdd1243dSDimitry Andric /// Add an assignment to the variable /p Var. 1287bdd1243dSDimitry Andric void addDbgDef(BlockInfo *LiveSet, VariableID Var, const Assignment &AV); 1288bdd1243dSDimitry Andric ///@} 1289bdd1243dSDimitry Andric 1290bdd1243dSDimitry Andric /// Set the LocKind for \p Var. 1291bdd1243dSDimitry Andric void setLocKind(BlockInfo *LiveSet, VariableID Var, LocKind K); 1292bdd1243dSDimitry Andric /// Get the live LocKind for a \p Var. Requires addMemDef or addDbgDef to 1293bdd1243dSDimitry Andric /// have been called for \p Var first. 1294bdd1243dSDimitry Andric LocKind getLocKind(BlockInfo *LiveSet, VariableID Var); 1295bdd1243dSDimitry Andric /// Return true if \p Var has an assignment in \p M matching \p AV. 1296*06c3fb27SDimitry Andric bool hasVarWithAssignment(BlockInfo *LiveSet, BlockInfo::AssignmentKind Kind, 1297*06c3fb27SDimitry Andric VariableID Var, const Assignment &AV); 1298*06c3fb27SDimitry Andric /// Return the set of VariableIDs corresponding the fragments contained fully 1299*06c3fb27SDimitry Andric /// within the variable/fragment \p Var. 1300*06c3fb27SDimitry Andric ArrayRef<VariableID> getContainedFragments(VariableID Var) const; 1301*06c3fb27SDimitry Andric 1302*06c3fb27SDimitry Andric /// Mark \p Var as having been touched this frame. Note, this applies only 1303*06c3fb27SDimitry Andric /// to the exact fragment \p Var and not to any fragments contained within. 1304*06c3fb27SDimitry Andric void touchFragment(VariableID Var); 1305bdd1243dSDimitry Andric 1306bdd1243dSDimitry Andric /// Emit info for variables that are fully promoted. 1307bdd1243dSDimitry Andric bool emitPromotedVarLocs(FunctionVarLocsBuilder *FnVarLocs); 1308bdd1243dSDimitry Andric 1309bdd1243dSDimitry Andric public: 1310bdd1243dSDimitry Andric AssignmentTrackingLowering(Function &Fn, const DataLayout &Layout, 1311bdd1243dSDimitry Andric const DenseSet<DebugAggregate> *VarsWithStackSlot) 1312bdd1243dSDimitry Andric : Fn(Fn), Layout(Layout), VarsWithStackSlot(VarsWithStackSlot) {} 1313bdd1243dSDimitry Andric /// Run the analysis, adding variable location info to \p FnVarLocs. Returns 1314bdd1243dSDimitry Andric /// true if any variable locations have been added to FnVarLocs. 1315bdd1243dSDimitry Andric bool run(FunctionVarLocsBuilder *FnVarLocs); 1316bdd1243dSDimitry Andric }; 1317bdd1243dSDimitry Andric } // namespace 1318bdd1243dSDimitry Andric 1319*06c3fb27SDimitry Andric ArrayRef<VariableID> 1320*06c3fb27SDimitry Andric AssignmentTrackingLowering::getContainedFragments(VariableID Var) const { 1321*06c3fb27SDimitry Andric auto R = VarContains.find(Var); 1322*06c3fb27SDimitry Andric if (R == VarContains.end()) 1323*06c3fb27SDimitry Andric return std::nullopt; 1324*06c3fb27SDimitry Andric return R->second; 1325*06c3fb27SDimitry Andric } 1326*06c3fb27SDimitry Andric 1327*06c3fb27SDimitry Andric void AssignmentTrackingLowering::touchFragment(VariableID Var) { 1328*06c3fb27SDimitry Andric VarsTouchedThisFrame.insert(Var); 1329*06c3fb27SDimitry Andric } 1330*06c3fb27SDimitry Andric 1331bdd1243dSDimitry Andric void AssignmentTrackingLowering::setLocKind(BlockInfo *LiveSet, VariableID Var, 1332bdd1243dSDimitry Andric LocKind K) { 1333bdd1243dSDimitry Andric auto SetKind = [this](BlockInfo *LiveSet, VariableID Var, LocKind K) { 1334*06c3fb27SDimitry Andric LiveSet->setLocKind(Var, K); 1335*06c3fb27SDimitry Andric touchFragment(Var); 1336bdd1243dSDimitry Andric }; 1337bdd1243dSDimitry Andric SetKind(LiveSet, Var, K); 1338bdd1243dSDimitry Andric 1339bdd1243dSDimitry Andric // Update the LocKind for all fragments contained within Var. 1340*06c3fb27SDimitry Andric for (VariableID Frag : getContainedFragments(Var)) 1341bdd1243dSDimitry Andric SetKind(LiveSet, Frag, K); 1342bdd1243dSDimitry Andric } 1343bdd1243dSDimitry Andric 1344bdd1243dSDimitry Andric AssignmentTrackingLowering::LocKind 1345bdd1243dSDimitry Andric AssignmentTrackingLowering::getLocKind(BlockInfo *LiveSet, VariableID Var) { 1346*06c3fb27SDimitry Andric return LiveSet->getLocKind(Var); 1347bdd1243dSDimitry Andric } 1348bdd1243dSDimitry Andric 1349bdd1243dSDimitry Andric void AssignmentTrackingLowering::addMemDef(BlockInfo *LiveSet, VariableID Var, 1350bdd1243dSDimitry Andric const Assignment &AV) { 1351*06c3fb27SDimitry Andric LiveSet->setAssignment(BlockInfo::Stack, Var, AV); 1352bdd1243dSDimitry Andric 1353bdd1243dSDimitry Andric // Use this assigment for all fragments contained within Var, but do not 1354bdd1243dSDimitry Andric // provide a Source because we cannot convert Var's value to a value for the 1355bdd1243dSDimitry Andric // fragment. 1356bdd1243dSDimitry Andric Assignment FragAV = AV; 1357bdd1243dSDimitry Andric FragAV.Source = nullptr; 1358*06c3fb27SDimitry Andric for (VariableID Frag : getContainedFragments(Var)) 1359*06c3fb27SDimitry Andric LiveSet->setAssignment(BlockInfo::Stack, Frag, FragAV); 1360bdd1243dSDimitry Andric } 1361bdd1243dSDimitry Andric 1362bdd1243dSDimitry Andric void AssignmentTrackingLowering::addDbgDef(BlockInfo *LiveSet, VariableID Var, 1363bdd1243dSDimitry Andric const Assignment &AV) { 1364*06c3fb27SDimitry Andric LiveSet->setAssignment(BlockInfo::Debug, Var, AV); 1365bdd1243dSDimitry Andric 1366bdd1243dSDimitry Andric // Use this assigment for all fragments contained within Var, but do not 1367bdd1243dSDimitry Andric // provide a Source because we cannot convert Var's value to a value for the 1368bdd1243dSDimitry Andric // fragment. 1369bdd1243dSDimitry Andric Assignment FragAV = AV; 1370bdd1243dSDimitry Andric FragAV.Source = nullptr; 1371*06c3fb27SDimitry Andric for (VariableID Frag : getContainedFragments(Var)) 1372*06c3fb27SDimitry Andric LiveSet->setAssignment(BlockInfo::Debug, Frag, FragAV); 1373bdd1243dSDimitry Andric } 1374bdd1243dSDimitry Andric 1375bdd1243dSDimitry Andric static DIAssignID *getIDFromInst(const Instruction &I) { 1376bdd1243dSDimitry Andric return cast<DIAssignID>(I.getMetadata(LLVMContext::MD_DIAssignID)); 1377bdd1243dSDimitry Andric } 1378bdd1243dSDimitry Andric 1379bdd1243dSDimitry Andric static DIAssignID *getIDFromMarker(const DbgAssignIntrinsic &DAI) { 1380bdd1243dSDimitry Andric return cast<DIAssignID>(DAI.getAssignID()); 1381bdd1243dSDimitry Andric } 1382bdd1243dSDimitry Andric 1383bdd1243dSDimitry Andric /// Return true if \p Var has an assignment in \p M matching \p AV. 1384*06c3fb27SDimitry Andric bool AssignmentTrackingLowering::hasVarWithAssignment( 1385*06c3fb27SDimitry Andric BlockInfo *LiveSet, BlockInfo::AssignmentKind Kind, VariableID Var, 1386*06c3fb27SDimitry Andric const Assignment &AV) { 1387*06c3fb27SDimitry Andric if (!LiveSet->hasAssignment(Kind, Var, AV)) 1388bdd1243dSDimitry Andric return false; 1389bdd1243dSDimitry Andric 1390bdd1243dSDimitry Andric // Check all the frags contained within Var as these will have all been 1391bdd1243dSDimitry Andric // mapped to AV at the last store to Var. 1392*06c3fb27SDimitry Andric for (VariableID Frag : getContainedFragments(Var)) 1393*06c3fb27SDimitry Andric if (!LiveSet->hasAssignment(Kind, Frag, AV)) 1394bdd1243dSDimitry Andric return false; 1395bdd1243dSDimitry Andric return true; 1396bdd1243dSDimitry Andric } 1397bdd1243dSDimitry Andric 1398bdd1243dSDimitry Andric #ifndef NDEBUG 1399bdd1243dSDimitry Andric const char *locStr(AssignmentTrackingLowering::LocKind Loc) { 1400bdd1243dSDimitry Andric using LocKind = AssignmentTrackingLowering::LocKind; 1401bdd1243dSDimitry Andric switch (Loc) { 1402bdd1243dSDimitry Andric case LocKind::Val: 1403bdd1243dSDimitry Andric return "Val"; 1404bdd1243dSDimitry Andric case LocKind::Mem: 1405bdd1243dSDimitry Andric return "Mem"; 1406bdd1243dSDimitry Andric case LocKind::None: 1407bdd1243dSDimitry Andric return "None"; 1408bdd1243dSDimitry Andric }; 1409bdd1243dSDimitry Andric llvm_unreachable("unknown LocKind"); 1410bdd1243dSDimitry Andric } 1411bdd1243dSDimitry Andric #endif 1412bdd1243dSDimitry Andric 1413bdd1243dSDimitry Andric void AssignmentTrackingLowering::emitDbgValue( 1414bdd1243dSDimitry Andric AssignmentTrackingLowering::LocKind Kind, 1415bdd1243dSDimitry Andric const DbgVariableIntrinsic *Source, Instruction *After) { 1416bdd1243dSDimitry Andric 1417bdd1243dSDimitry Andric DILocation *DL = Source->getDebugLoc(); 1418*06c3fb27SDimitry Andric auto Emit = [this, Source, After, DL](Metadata *Val, DIExpression *Expr) { 1419bdd1243dSDimitry Andric assert(Expr); 1420bdd1243dSDimitry Andric if (!Val) 1421*06c3fb27SDimitry Andric Val = ValueAsMetadata::get( 1422*06c3fb27SDimitry Andric PoisonValue::get(Type::getInt1Ty(Source->getContext()))); 1423bdd1243dSDimitry Andric 1424bdd1243dSDimitry Andric // Find a suitable insert point. 1425bdd1243dSDimitry Andric Instruction *InsertBefore = After->getNextNode(); 1426bdd1243dSDimitry Andric assert(InsertBefore && "Shouldn't be inserting after a terminator"); 1427bdd1243dSDimitry Andric 1428bdd1243dSDimitry Andric VariableID Var = getVariableID(DebugVariable(Source)); 1429bdd1243dSDimitry Andric VarLocInfo VarLoc; 1430bdd1243dSDimitry Andric VarLoc.VariableID = static_cast<VariableID>(Var); 1431bdd1243dSDimitry Andric VarLoc.Expr = Expr; 1432*06c3fb27SDimitry Andric VarLoc.Values = RawLocationWrapper(Val); 1433bdd1243dSDimitry Andric VarLoc.DL = DL; 1434bdd1243dSDimitry Andric // Insert it into the map for later. 1435bdd1243dSDimitry Andric InsertBeforeMap[InsertBefore].push_back(VarLoc); 1436bdd1243dSDimitry Andric }; 1437bdd1243dSDimitry Andric 1438bdd1243dSDimitry Andric // NOTE: This block can mutate Kind. 1439bdd1243dSDimitry Andric if (Kind == LocKind::Mem) { 1440bdd1243dSDimitry Andric const auto *DAI = cast<DbgAssignIntrinsic>(Source); 1441bdd1243dSDimitry Andric // Check the address hasn't been dropped (e.g. the debug uses may not have 1442bdd1243dSDimitry Andric // been replaced before deleting a Value). 1443bdd1243dSDimitry Andric if (DAI->isKillAddress()) { 1444bdd1243dSDimitry Andric // The address isn't valid so treat this as a non-memory def. 1445bdd1243dSDimitry Andric Kind = LocKind::Val; 1446bdd1243dSDimitry Andric } else { 1447bdd1243dSDimitry Andric Value *Val = DAI->getAddress(); 1448bdd1243dSDimitry Andric DIExpression *Expr = DAI->getAddressExpression(); 1449bdd1243dSDimitry Andric assert(!Expr->getFragmentInfo() && 1450bdd1243dSDimitry Andric "fragment info should be stored in value-expression only"); 1451bdd1243dSDimitry Andric // Copy the fragment info over from the value-expression to the new 1452bdd1243dSDimitry Andric // DIExpression. 1453bdd1243dSDimitry Andric if (auto OptFragInfo = Source->getExpression()->getFragmentInfo()) { 1454bdd1243dSDimitry Andric auto FragInfo = *OptFragInfo; 1455bdd1243dSDimitry Andric Expr = *DIExpression::createFragmentExpression( 1456bdd1243dSDimitry Andric Expr, FragInfo.OffsetInBits, FragInfo.SizeInBits); 1457bdd1243dSDimitry Andric } 1458bdd1243dSDimitry Andric // The address-expression has an implicit deref, add it now. 1459bdd1243dSDimitry Andric std::tie(Val, Expr) = 1460bdd1243dSDimitry Andric walkToAllocaAndPrependOffsetDeref(Layout, Val, Expr); 1461*06c3fb27SDimitry Andric Emit(ValueAsMetadata::get(Val), Expr); 1462bdd1243dSDimitry Andric return; 1463bdd1243dSDimitry Andric } 1464bdd1243dSDimitry Andric } 1465bdd1243dSDimitry Andric 1466bdd1243dSDimitry Andric if (Kind == LocKind::Val) { 1467*06c3fb27SDimitry Andric Emit(Source->getRawLocation(), Source->getExpression()); 1468bdd1243dSDimitry Andric return; 1469bdd1243dSDimitry Andric } 1470bdd1243dSDimitry Andric 1471bdd1243dSDimitry Andric if (Kind == LocKind::None) { 1472bdd1243dSDimitry Andric Emit(nullptr, Source->getExpression()); 1473bdd1243dSDimitry Andric return; 1474bdd1243dSDimitry Andric } 1475bdd1243dSDimitry Andric } 1476bdd1243dSDimitry Andric 1477bdd1243dSDimitry Andric void AssignmentTrackingLowering::processNonDbgInstruction( 1478bdd1243dSDimitry Andric Instruction &I, AssignmentTrackingLowering::BlockInfo *LiveSet) { 1479bdd1243dSDimitry Andric if (I.hasMetadata(LLVMContext::MD_DIAssignID)) 1480bdd1243dSDimitry Andric processTaggedInstruction(I, LiveSet); 1481bdd1243dSDimitry Andric else 1482bdd1243dSDimitry Andric processUntaggedInstruction(I, LiveSet); 1483bdd1243dSDimitry Andric } 1484bdd1243dSDimitry Andric 1485bdd1243dSDimitry Andric void AssignmentTrackingLowering::processUntaggedInstruction( 1486bdd1243dSDimitry Andric Instruction &I, AssignmentTrackingLowering::BlockInfo *LiveSet) { 1487bdd1243dSDimitry Andric // Interpret stack stores that are not tagged as an assignment in memory for 1488bdd1243dSDimitry Andric // the variables associated with that address. These stores may not be tagged 1489bdd1243dSDimitry Andric // because a) the store cannot be represented using dbg.assigns (non-const 1490bdd1243dSDimitry Andric // length or offset) or b) the tag was accidentally dropped during 1491bdd1243dSDimitry Andric // optimisations. For these stores we fall back to assuming that the stack 1492bdd1243dSDimitry Andric // home is a valid location for the variables. The benefit is that this 1493bdd1243dSDimitry Andric // prevents us missing an assignment and therefore incorrectly maintaining 1494bdd1243dSDimitry Andric // earlier location definitions, and in many cases it should be a reasonable 1495bdd1243dSDimitry Andric // assumption. However, this will occasionally lead to slight 1496bdd1243dSDimitry Andric // inaccuracies. The value of a hoisted untagged store will be visible 1497bdd1243dSDimitry Andric // "early", for example. 1498bdd1243dSDimitry Andric assert(!I.hasMetadata(LLVMContext::MD_DIAssignID)); 1499bdd1243dSDimitry Andric auto It = UntaggedStoreVars.find(&I); 1500bdd1243dSDimitry Andric if (It == UntaggedStoreVars.end()) 1501bdd1243dSDimitry Andric return; // No variables associated with the store destination. 1502bdd1243dSDimitry Andric 1503bdd1243dSDimitry Andric LLVM_DEBUG(dbgs() << "processUntaggedInstruction on UNTAGGED INST " << I 1504bdd1243dSDimitry Andric << "\n"); 1505bdd1243dSDimitry Andric // Iterate over the variables that this store affects, add a NoneOrPhi dbg 1506bdd1243dSDimitry Andric // and mem def, set lockind to Mem, and emit a location def for each. 1507bdd1243dSDimitry Andric for (auto [Var, Info] : It->second) { 1508bdd1243dSDimitry Andric // This instruction is treated as both a debug and memory assignment, 1509bdd1243dSDimitry Andric // meaning the memory location should be used. We don't have an assignment 1510bdd1243dSDimitry Andric // ID though so use Assignment::makeNoneOrPhi() to create an imaginary one. 1511bdd1243dSDimitry Andric addMemDef(LiveSet, Var, Assignment::makeNoneOrPhi()); 1512bdd1243dSDimitry Andric addDbgDef(LiveSet, Var, Assignment::makeNoneOrPhi()); 1513bdd1243dSDimitry Andric setLocKind(LiveSet, Var, LocKind::Mem); 1514bdd1243dSDimitry Andric LLVM_DEBUG(dbgs() << " setting Stack LocKind to: " << locStr(LocKind::Mem) 1515bdd1243dSDimitry Andric << "\n"); 1516bdd1243dSDimitry Andric // Build the dbg location def to insert. 1517bdd1243dSDimitry Andric // 1518bdd1243dSDimitry Andric // DIExpression: Add fragment and offset. 1519bdd1243dSDimitry Andric DebugVariable V = FnVarLocs->getVariable(Var); 1520bdd1243dSDimitry Andric DIExpression *DIE = DIExpression::get(I.getContext(), std::nullopt); 1521bdd1243dSDimitry Andric if (auto Frag = V.getFragment()) { 1522bdd1243dSDimitry Andric auto R = DIExpression::createFragmentExpression(DIE, Frag->OffsetInBits, 1523bdd1243dSDimitry Andric Frag->SizeInBits); 1524bdd1243dSDimitry Andric assert(R && "unexpected createFragmentExpression failure"); 1525bdd1243dSDimitry Andric DIE = *R; 1526bdd1243dSDimitry Andric } 1527bdd1243dSDimitry Andric SmallVector<uint64_t, 3> Ops; 1528bdd1243dSDimitry Andric if (Info.OffsetInBits) 1529bdd1243dSDimitry Andric Ops = {dwarf::DW_OP_plus_uconst, Info.OffsetInBits / 8}; 1530bdd1243dSDimitry Andric Ops.push_back(dwarf::DW_OP_deref); 1531bdd1243dSDimitry Andric DIE = DIExpression::prependOpcodes(DIE, Ops, /*StackValue=*/false, 1532bdd1243dSDimitry Andric /*EntryValue=*/false); 1533bdd1243dSDimitry Andric // Find a suitable insert point. 1534bdd1243dSDimitry Andric Instruction *InsertBefore = I.getNextNode(); 1535bdd1243dSDimitry Andric assert(InsertBefore && "Shouldn't be inserting after a terminator"); 1536bdd1243dSDimitry Andric 1537bdd1243dSDimitry Andric // Get DILocation for this unrecorded assignment. 1538bdd1243dSDimitry Andric DILocation *InlinedAt = const_cast<DILocation *>(V.getInlinedAt()); 1539bdd1243dSDimitry Andric const DILocation *DILoc = DILocation::get( 1540bdd1243dSDimitry Andric Fn.getContext(), 0, 0, V.getVariable()->getScope(), InlinedAt); 1541bdd1243dSDimitry Andric 1542bdd1243dSDimitry Andric VarLocInfo VarLoc; 1543bdd1243dSDimitry Andric VarLoc.VariableID = static_cast<VariableID>(Var); 1544bdd1243dSDimitry Andric VarLoc.Expr = DIE; 1545*06c3fb27SDimitry Andric VarLoc.Values = RawLocationWrapper( 1546*06c3fb27SDimitry Andric ValueAsMetadata::get(const_cast<AllocaInst *>(Info.Base))); 1547bdd1243dSDimitry Andric VarLoc.DL = DILoc; 1548bdd1243dSDimitry Andric // 3. Insert it into the map for later. 1549bdd1243dSDimitry Andric InsertBeforeMap[InsertBefore].push_back(VarLoc); 1550bdd1243dSDimitry Andric } 1551bdd1243dSDimitry Andric } 1552bdd1243dSDimitry Andric 1553bdd1243dSDimitry Andric void AssignmentTrackingLowering::processTaggedInstruction( 1554bdd1243dSDimitry Andric Instruction &I, AssignmentTrackingLowering::BlockInfo *LiveSet) { 1555bdd1243dSDimitry Andric auto Linked = at::getAssignmentMarkers(&I); 1556bdd1243dSDimitry Andric // No dbg.assign intrinsics linked. 1557bdd1243dSDimitry Andric // FIXME: All vars that have a stack slot this store modifies that don't have 1558bdd1243dSDimitry Andric // a dbg.assign linked to it should probably treat this like an untagged 1559bdd1243dSDimitry Andric // store. 1560bdd1243dSDimitry Andric if (Linked.empty()) 1561bdd1243dSDimitry Andric return; 1562bdd1243dSDimitry Andric 1563bdd1243dSDimitry Andric LLVM_DEBUG(dbgs() << "processTaggedInstruction on " << I << "\n"); 1564bdd1243dSDimitry Andric for (DbgAssignIntrinsic *DAI : Linked) { 1565bdd1243dSDimitry Andric VariableID Var = getVariableID(DebugVariable(DAI)); 1566bdd1243dSDimitry Andric // Something has gone wrong if VarsWithStackSlot doesn't contain a variable 1567bdd1243dSDimitry Andric // that is linked to a store. 1568bdd1243dSDimitry Andric assert(VarsWithStackSlot->count(getAggregate(DAI)) && 1569bdd1243dSDimitry Andric "expected DAI's variable to have stack slot"); 1570bdd1243dSDimitry Andric 1571bdd1243dSDimitry Andric Assignment AV = Assignment::makeFromMemDef(getIDFromInst(I)); 1572bdd1243dSDimitry Andric addMemDef(LiveSet, Var, AV); 1573bdd1243dSDimitry Andric 1574bdd1243dSDimitry Andric LLVM_DEBUG(dbgs() << " linked to " << *DAI << "\n"); 1575bdd1243dSDimitry Andric LLVM_DEBUG(dbgs() << " LiveLoc " << locStr(getLocKind(LiveSet, Var)) 1576bdd1243dSDimitry Andric << " -> "); 1577bdd1243dSDimitry Andric 1578bdd1243dSDimitry Andric // The last assignment to the stack is now AV. Check if the last debug 1579bdd1243dSDimitry Andric // assignment has a matching Assignment. 1580*06c3fb27SDimitry Andric if (hasVarWithAssignment(LiveSet, BlockInfo::Debug, Var, AV)) { 1581bdd1243dSDimitry Andric // The StackHomeValue and DebugValue for this variable match so we can 1582bdd1243dSDimitry Andric // emit a stack home location here. 1583bdd1243dSDimitry Andric LLVM_DEBUG(dbgs() << "Mem, Stack matches Debug program\n";); 1584bdd1243dSDimitry Andric LLVM_DEBUG(dbgs() << " Stack val: "; AV.dump(dbgs()); dbgs() << "\n"); 1585bdd1243dSDimitry Andric LLVM_DEBUG(dbgs() << " Debug val: "; 1586*06c3fb27SDimitry Andric LiveSet->DebugValue[static_cast<unsigned>(Var)].dump(dbgs()); 1587*06c3fb27SDimitry Andric dbgs() << "\n"); 1588bdd1243dSDimitry Andric setLocKind(LiveSet, Var, LocKind::Mem); 1589bdd1243dSDimitry Andric emitDbgValue(LocKind::Mem, DAI, &I); 1590bdd1243dSDimitry Andric continue; 1591bdd1243dSDimitry Andric } 1592bdd1243dSDimitry Andric 1593bdd1243dSDimitry Andric // The StackHomeValue and DebugValue for this variable do not match. I.e. 1594bdd1243dSDimitry Andric // The value currently stored in the stack is not what we'd expect to 1595bdd1243dSDimitry Andric // see, so we cannot use emit a stack home location here. Now we will 1596bdd1243dSDimitry Andric // look at the live LocKind for the variable and determine an appropriate 1597bdd1243dSDimitry Andric // dbg.value to emit. 1598bdd1243dSDimitry Andric LocKind PrevLoc = getLocKind(LiveSet, Var); 1599bdd1243dSDimitry Andric switch (PrevLoc) { 1600bdd1243dSDimitry Andric case LocKind::Val: { 1601bdd1243dSDimitry Andric // The value in memory in memory has changed but we're not currently 1602bdd1243dSDimitry Andric // using the memory location. Do nothing. 1603bdd1243dSDimitry Andric LLVM_DEBUG(dbgs() << "Val, (unchanged)\n";); 1604bdd1243dSDimitry Andric setLocKind(LiveSet, Var, LocKind::Val); 1605bdd1243dSDimitry Andric } break; 1606bdd1243dSDimitry Andric case LocKind::Mem: { 1607bdd1243dSDimitry Andric // There's been an assignment to memory that we were using as a 1608bdd1243dSDimitry Andric // location for this variable, and the Assignment doesn't match what 1609bdd1243dSDimitry Andric // we'd expect to see in memory. 1610*06c3fb27SDimitry Andric Assignment DbgAV = LiveSet->getAssignment(BlockInfo::Debug, Var); 1611*06c3fb27SDimitry Andric if (DbgAV.Status == Assignment::NoneOrPhi) { 1612bdd1243dSDimitry Andric // We need to terminate any previously open location now. 1613bdd1243dSDimitry Andric LLVM_DEBUG(dbgs() << "None, No Debug value available\n";); 1614bdd1243dSDimitry Andric setLocKind(LiveSet, Var, LocKind::None); 1615bdd1243dSDimitry Andric emitDbgValue(LocKind::None, DAI, &I); 1616bdd1243dSDimitry Andric } else { 1617bdd1243dSDimitry Andric // The previous DebugValue Value can be used here. 1618bdd1243dSDimitry Andric LLVM_DEBUG(dbgs() << "Val, Debug value is Known\n";); 1619bdd1243dSDimitry Andric setLocKind(LiveSet, Var, LocKind::Val); 1620*06c3fb27SDimitry Andric if (DbgAV.Source) { 1621*06c3fb27SDimitry Andric emitDbgValue(LocKind::Val, DbgAV.Source, &I); 1622bdd1243dSDimitry Andric } else { 1623bdd1243dSDimitry Andric // PrevAV.Source is nullptr so we must emit undef here. 1624bdd1243dSDimitry Andric emitDbgValue(LocKind::None, DAI, &I); 1625bdd1243dSDimitry Andric } 1626bdd1243dSDimitry Andric } 1627bdd1243dSDimitry Andric } break; 1628bdd1243dSDimitry Andric case LocKind::None: { 1629bdd1243dSDimitry Andric // There's been an assignment to memory and we currently are 1630bdd1243dSDimitry Andric // not tracking a location for the variable. Do not emit anything. 1631bdd1243dSDimitry Andric LLVM_DEBUG(dbgs() << "None, (unchanged)\n";); 1632bdd1243dSDimitry Andric setLocKind(LiveSet, Var, LocKind::None); 1633bdd1243dSDimitry Andric } break; 1634bdd1243dSDimitry Andric } 1635bdd1243dSDimitry Andric } 1636bdd1243dSDimitry Andric } 1637bdd1243dSDimitry Andric 1638bdd1243dSDimitry Andric void AssignmentTrackingLowering::processDbgAssign(DbgAssignIntrinsic &DAI, 1639bdd1243dSDimitry Andric BlockInfo *LiveSet) { 1640bdd1243dSDimitry Andric // Only bother tracking variables that are at some point stack homed. Other 1641bdd1243dSDimitry Andric // variables can be dealt with trivially later. 1642bdd1243dSDimitry Andric if (!VarsWithStackSlot->count(getAggregate(&DAI))) 1643bdd1243dSDimitry Andric return; 1644bdd1243dSDimitry Andric 1645bdd1243dSDimitry Andric VariableID Var = getVariableID(DebugVariable(&DAI)); 1646bdd1243dSDimitry Andric Assignment AV = Assignment::make(getIDFromMarker(DAI), &DAI); 1647bdd1243dSDimitry Andric addDbgDef(LiveSet, Var, AV); 1648bdd1243dSDimitry Andric 1649bdd1243dSDimitry Andric LLVM_DEBUG(dbgs() << "processDbgAssign on " << DAI << "\n";); 1650bdd1243dSDimitry Andric LLVM_DEBUG(dbgs() << " LiveLoc " << locStr(getLocKind(LiveSet, Var)) 1651bdd1243dSDimitry Andric << " -> "); 1652bdd1243dSDimitry Andric 1653bdd1243dSDimitry Andric // Check if the DebugValue and StackHomeValue both hold the same 1654bdd1243dSDimitry Andric // Assignment. 1655*06c3fb27SDimitry Andric if (hasVarWithAssignment(LiveSet, BlockInfo::Stack, Var, AV)) { 1656bdd1243dSDimitry Andric // They match. We can use the stack home because the debug intrinsics state 1657bdd1243dSDimitry Andric // that an assignment happened here, and we know that specific assignment 1658bdd1243dSDimitry Andric // was the last one to take place in memory for this variable. 1659bdd1243dSDimitry Andric LocKind Kind; 1660bdd1243dSDimitry Andric if (DAI.isKillAddress()) { 1661bdd1243dSDimitry Andric LLVM_DEBUG( 1662bdd1243dSDimitry Andric dbgs() 1663bdd1243dSDimitry Andric << "Val, Stack matches Debug program but address is killed\n";); 1664bdd1243dSDimitry Andric Kind = LocKind::Val; 1665bdd1243dSDimitry Andric } else { 1666bdd1243dSDimitry Andric LLVM_DEBUG(dbgs() << "Mem, Stack matches Debug program\n";); 1667bdd1243dSDimitry Andric Kind = LocKind::Mem; 1668bdd1243dSDimitry Andric }; 1669bdd1243dSDimitry Andric setLocKind(LiveSet, Var, Kind); 1670bdd1243dSDimitry Andric emitDbgValue(Kind, &DAI, &DAI); 1671bdd1243dSDimitry Andric } else { 1672bdd1243dSDimitry Andric // The last assignment to the memory location isn't the one that we want to 1673bdd1243dSDimitry Andric // show to the user so emit a dbg.value(Value). Value may be undef. 1674bdd1243dSDimitry Andric LLVM_DEBUG(dbgs() << "Val, Stack contents is unknown\n";); 1675bdd1243dSDimitry Andric setLocKind(LiveSet, Var, LocKind::Val); 1676bdd1243dSDimitry Andric emitDbgValue(LocKind::Val, &DAI, &DAI); 1677bdd1243dSDimitry Andric } 1678bdd1243dSDimitry Andric } 1679bdd1243dSDimitry Andric 1680bdd1243dSDimitry Andric void AssignmentTrackingLowering::processDbgValue(DbgValueInst &DVI, 1681bdd1243dSDimitry Andric BlockInfo *LiveSet) { 1682bdd1243dSDimitry Andric // Only other tracking variables that are at some point stack homed. 1683bdd1243dSDimitry Andric // Other variables can be dealt with trivally later. 1684bdd1243dSDimitry Andric if (!VarsWithStackSlot->count(getAggregate(&DVI))) 1685bdd1243dSDimitry Andric return; 1686bdd1243dSDimitry Andric 1687bdd1243dSDimitry Andric VariableID Var = getVariableID(DebugVariable(&DVI)); 1688bdd1243dSDimitry Andric // We have no ID to create an Assignment with so we mark this assignment as 1689bdd1243dSDimitry Andric // NoneOrPhi. Note that the dbg.value still exists, we just cannot determine 1690bdd1243dSDimitry Andric // the assignment responsible for setting this value. 1691bdd1243dSDimitry Andric // This is fine; dbg.values are essentially interchangable with unlinked 1692bdd1243dSDimitry Andric // dbg.assigns, and some passes such as mem2reg and instcombine add them to 1693bdd1243dSDimitry Andric // PHIs for promoted variables. 1694bdd1243dSDimitry Andric Assignment AV = Assignment::makeNoneOrPhi(); 1695bdd1243dSDimitry Andric addDbgDef(LiveSet, Var, AV); 1696bdd1243dSDimitry Andric 1697bdd1243dSDimitry Andric LLVM_DEBUG(dbgs() << "processDbgValue on " << DVI << "\n";); 1698bdd1243dSDimitry Andric LLVM_DEBUG(dbgs() << " LiveLoc " << locStr(getLocKind(LiveSet, Var)) 1699bdd1243dSDimitry Andric << " -> Val, dbg.value override"); 1700bdd1243dSDimitry Andric 1701bdd1243dSDimitry Andric setLocKind(LiveSet, Var, LocKind::Val); 1702bdd1243dSDimitry Andric emitDbgValue(LocKind::Val, &DVI, &DVI); 1703bdd1243dSDimitry Andric } 1704bdd1243dSDimitry Andric 1705*06c3fb27SDimitry Andric static bool hasZeroSizedFragment(DbgVariableIntrinsic &DVI) { 1706*06c3fb27SDimitry Andric if (auto F = DVI.getExpression()->getFragmentInfo()) 1707*06c3fb27SDimitry Andric return F->SizeInBits == 0; 1708*06c3fb27SDimitry Andric return false; 1709*06c3fb27SDimitry Andric } 1710*06c3fb27SDimitry Andric 1711bdd1243dSDimitry Andric void AssignmentTrackingLowering::processDbgInstruction( 1712*06c3fb27SDimitry Andric DbgInfoIntrinsic &I, AssignmentTrackingLowering::BlockInfo *LiveSet) { 1713*06c3fb27SDimitry Andric auto *DVI = dyn_cast<DbgVariableIntrinsic>(&I); 1714*06c3fb27SDimitry Andric if (!DVI) 1715*06c3fb27SDimitry Andric return; 1716*06c3fb27SDimitry Andric 1717*06c3fb27SDimitry Andric // Ignore assignments to zero bits of the variable. 1718*06c3fb27SDimitry Andric if (hasZeroSizedFragment(*DVI)) 1719*06c3fb27SDimitry Andric return; 1720*06c3fb27SDimitry Andric 1721bdd1243dSDimitry Andric if (auto *DAI = dyn_cast<DbgAssignIntrinsic>(&I)) 1722bdd1243dSDimitry Andric processDbgAssign(*DAI, LiveSet); 1723bdd1243dSDimitry Andric else if (auto *DVI = dyn_cast<DbgValueInst>(&I)) 1724bdd1243dSDimitry Andric processDbgValue(*DVI, LiveSet); 1725bdd1243dSDimitry Andric } 1726bdd1243dSDimitry Andric 1727bdd1243dSDimitry Andric void AssignmentTrackingLowering::resetInsertionPoint(Instruction &After) { 1728bdd1243dSDimitry Andric assert(!After.isTerminator() && "Can't insert after a terminator"); 1729bdd1243dSDimitry Andric auto R = InsertBeforeMap.find(After.getNextNode()); 1730bdd1243dSDimitry Andric if (R == InsertBeforeMap.end()) 1731bdd1243dSDimitry Andric return; 1732bdd1243dSDimitry Andric R->second.clear(); 1733bdd1243dSDimitry Andric } 1734bdd1243dSDimitry Andric 1735bdd1243dSDimitry Andric void AssignmentTrackingLowering::process(BasicBlock &BB, BlockInfo *LiveSet) { 1736bdd1243dSDimitry Andric for (auto II = BB.begin(), EI = BB.end(); II != EI;) { 1737bdd1243dSDimitry Andric assert(VarsTouchedThisFrame.empty()); 1738bdd1243dSDimitry Andric // Process the instructions in "frames". A "frame" includes a single 1739bdd1243dSDimitry Andric // non-debug instruction followed any debug instructions before the 1740bdd1243dSDimitry Andric // next non-debug instruction. 1741bdd1243dSDimitry Andric if (!isa<DbgInfoIntrinsic>(&*II)) { 1742bdd1243dSDimitry Andric if (II->isTerminator()) 1743bdd1243dSDimitry Andric break; 1744bdd1243dSDimitry Andric resetInsertionPoint(*II); 1745bdd1243dSDimitry Andric processNonDbgInstruction(*II, LiveSet); 1746bdd1243dSDimitry Andric assert(LiveSet->isValid()); 1747bdd1243dSDimitry Andric ++II; 1748bdd1243dSDimitry Andric } 1749bdd1243dSDimitry Andric while (II != EI) { 1750*06c3fb27SDimitry Andric auto *Dbg = dyn_cast<DbgInfoIntrinsic>(&*II); 1751*06c3fb27SDimitry Andric if (!Dbg) 1752bdd1243dSDimitry Andric break; 1753bdd1243dSDimitry Andric resetInsertionPoint(*II); 1754*06c3fb27SDimitry Andric processDbgInstruction(*Dbg, LiveSet); 1755bdd1243dSDimitry Andric assert(LiveSet->isValid()); 1756bdd1243dSDimitry Andric ++II; 1757bdd1243dSDimitry Andric } 1758bdd1243dSDimitry Andric 1759bdd1243dSDimitry Andric // We've processed everything in the "frame". Now determine which variables 1760bdd1243dSDimitry Andric // cannot be represented by a dbg.declare. 1761bdd1243dSDimitry Andric for (auto Var : VarsTouchedThisFrame) { 1762bdd1243dSDimitry Andric LocKind Loc = getLocKind(LiveSet, Var); 1763bdd1243dSDimitry Andric // If a variable's LocKind is anything other than LocKind::Mem then we 1764bdd1243dSDimitry Andric // must note that it cannot be represented with a dbg.declare. 1765bdd1243dSDimitry Andric // Note that this check is enough without having to check the result of 1766bdd1243dSDimitry Andric // joins() because for join to produce anything other than Mem after 1767bdd1243dSDimitry Andric // we've already seen a Mem we'd be joining None or Val with Mem. In that 1768bdd1243dSDimitry Andric // case, we've already hit this codepath when we set the LocKind to Val 1769bdd1243dSDimitry Andric // or None in that block. 1770bdd1243dSDimitry Andric if (Loc != LocKind::Mem) { 1771bdd1243dSDimitry Andric DebugVariable DbgVar = FnVarLocs->getVariable(Var); 1772bdd1243dSDimitry Andric DebugAggregate Aggr{DbgVar.getVariable(), DbgVar.getInlinedAt()}; 1773bdd1243dSDimitry Andric NotAlwaysStackHomed.insert(Aggr); 1774bdd1243dSDimitry Andric } 1775bdd1243dSDimitry Andric } 1776bdd1243dSDimitry Andric VarsTouchedThisFrame.clear(); 1777bdd1243dSDimitry Andric } 1778bdd1243dSDimitry Andric } 1779bdd1243dSDimitry Andric 1780bdd1243dSDimitry Andric AssignmentTrackingLowering::LocKind 1781bdd1243dSDimitry Andric AssignmentTrackingLowering::joinKind(LocKind A, LocKind B) { 1782bdd1243dSDimitry Andric // Partial order: 1783bdd1243dSDimitry Andric // None > Mem, Val 1784bdd1243dSDimitry Andric return A == B ? A : LocKind::None; 1785bdd1243dSDimitry Andric } 1786bdd1243dSDimitry Andric 1787bdd1243dSDimitry Andric AssignmentTrackingLowering::Assignment 1788bdd1243dSDimitry Andric AssignmentTrackingLowering::joinAssignment(const Assignment &A, 1789bdd1243dSDimitry Andric const Assignment &B) { 1790bdd1243dSDimitry Andric // Partial order: 1791bdd1243dSDimitry Andric // NoneOrPhi(null, null) > Known(v, ?s) 1792bdd1243dSDimitry Andric 1793bdd1243dSDimitry Andric // If either are NoneOrPhi the join is NoneOrPhi. 1794bdd1243dSDimitry Andric // If either value is different then the result is 1795bdd1243dSDimitry Andric // NoneOrPhi (joining two values is a Phi). 1796bdd1243dSDimitry Andric if (!A.isSameSourceAssignment(B)) 1797bdd1243dSDimitry Andric return Assignment::makeNoneOrPhi(); 1798bdd1243dSDimitry Andric if (A.Status == Assignment::NoneOrPhi) 1799bdd1243dSDimitry Andric return Assignment::makeNoneOrPhi(); 1800bdd1243dSDimitry Andric 1801bdd1243dSDimitry Andric // Source is used to lookup the value + expression in the debug program if 1802bdd1243dSDimitry Andric // the stack slot gets assigned a value earlier than expected. Because 1803bdd1243dSDimitry Andric // we're only tracking the one dbg.assign, we can't capture debug PHIs. 1804bdd1243dSDimitry Andric // It's unlikely that we're losing out on much coverage by avoiding that 1805bdd1243dSDimitry Andric // extra work. 1806bdd1243dSDimitry Andric // The Source may differ in this situation: 1807bdd1243dSDimitry Andric // Pred.1: 1808bdd1243dSDimitry Andric // dbg.assign i32 0, ..., !1, ... 1809bdd1243dSDimitry Andric // Pred.2: 1810bdd1243dSDimitry Andric // dbg.assign i32 1, ..., !1, ... 1811bdd1243dSDimitry Andric // Here the same assignment (!1) was performed in both preds in the source, 1812bdd1243dSDimitry Andric // but we can't use either one unless they are identical (e.g. .we don't 1813bdd1243dSDimitry Andric // want to arbitrarily pick between constant values). 1814bdd1243dSDimitry Andric auto JoinSource = [&]() -> DbgAssignIntrinsic * { 1815bdd1243dSDimitry Andric if (A.Source == B.Source) 1816bdd1243dSDimitry Andric return A.Source; 1817bdd1243dSDimitry Andric if (A.Source == nullptr || B.Source == nullptr) 1818bdd1243dSDimitry Andric return nullptr; 1819bdd1243dSDimitry Andric if (A.Source->isIdenticalTo(B.Source)) 1820bdd1243dSDimitry Andric return A.Source; 1821bdd1243dSDimitry Andric return nullptr; 1822bdd1243dSDimitry Andric }; 1823bdd1243dSDimitry Andric DbgAssignIntrinsic *Source = JoinSource(); 1824bdd1243dSDimitry Andric assert(A.Status == B.Status && A.Status == Assignment::Known); 1825bdd1243dSDimitry Andric assert(A.ID == B.ID); 1826bdd1243dSDimitry Andric return Assignment::make(A.ID, Source); 1827bdd1243dSDimitry Andric } 1828bdd1243dSDimitry Andric 1829bdd1243dSDimitry Andric AssignmentTrackingLowering::BlockInfo 1830bdd1243dSDimitry Andric AssignmentTrackingLowering::joinBlockInfo(const BlockInfo &A, 1831bdd1243dSDimitry Andric const BlockInfo &B) { 1832*06c3fb27SDimitry Andric return BlockInfo::join(A, B, TrackedVariablesVectorSize); 1833bdd1243dSDimitry Andric } 1834bdd1243dSDimitry Andric 1835bdd1243dSDimitry Andric bool AssignmentTrackingLowering::join( 1836bdd1243dSDimitry Andric const BasicBlock &BB, const SmallPtrSet<BasicBlock *, 16> &Visited) { 1837*06c3fb27SDimitry Andric 1838*06c3fb27SDimitry Andric SmallVector<const BasicBlock *> VisitedPreds; 1839bdd1243dSDimitry Andric // Ignore backedges if we have not visited the predecessor yet. As the 1840bdd1243dSDimitry Andric // predecessor hasn't yet had locations propagated into it, most locations 1841bdd1243dSDimitry Andric // will not yet be valid, so treat them as all being uninitialized and 1842bdd1243dSDimitry Andric // potentially valid. If a location guessed to be correct here is 1843bdd1243dSDimitry Andric // invalidated later, we will remove it when we revisit this block. This 1844bdd1243dSDimitry Andric // is essentially the same as initialising all LocKinds and Assignments to 1845bdd1243dSDimitry Andric // an implicit ⊥ value which is the identity value for the join operation. 1846*06c3fb27SDimitry Andric for (auto I = pred_begin(&BB), E = pred_end(&BB); I != E; I++) { 1847bdd1243dSDimitry Andric const BasicBlock *Pred = *I; 1848*06c3fb27SDimitry Andric if (Visited.count(Pred)) 1849*06c3fb27SDimitry Andric VisitedPreds.push_back(Pred); 1850bdd1243dSDimitry Andric } 1851bdd1243dSDimitry Andric 1852*06c3fb27SDimitry Andric // No preds visited yet. 1853*06c3fb27SDimitry Andric if (VisitedPreds.empty()) { 1854*06c3fb27SDimitry Andric auto It = LiveIn.try_emplace(&BB, BlockInfo()); 1855*06c3fb27SDimitry Andric bool DidInsert = It.second; 1856*06c3fb27SDimitry Andric if (DidInsert) 1857*06c3fb27SDimitry Andric It.first->second.init(TrackedVariablesVectorSize); 1858*06c3fb27SDimitry Andric return /*Changed*/ DidInsert; 1859*06c3fb27SDimitry Andric } 1860*06c3fb27SDimitry Andric 1861*06c3fb27SDimitry Andric // Exactly one visited pred. Copy the LiveOut from that pred into BB LiveIn. 1862*06c3fb27SDimitry Andric if (VisitedPreds.size() == 1) { 1863*06c3fb27SDimitry Andric const BlockInfo &PredLiveOut = LiveOut.find(VisitedPreds[0])->second; 1864*06c3fb27SDimitry Andric auto CurrentLiveInEntry = LiveIn.find(&BB); 1865*06c3fb27SDimitry Andric 1866*06c3fb27SDimitry Andric // Check if there isn't an entry, or there is but the LiveIn set has 1867*06c3fb27SDimitry Andric // changed (expensive check). 1868*06c3fb27SDimitry Andric if (CurrentLiveInEntry == LiveIn.end()) 1869*06c3fb27SDimitry Andric LiveIn.insert(std::make_pair(&BB, PredLiveOut)); 1870*06c3fb27SDimitry Andric else if (PredLiveOut != CurrentLiveInEntry->second) 1871*06c3fb27SDimitry Andric CurrentLiveInEntry->second = PredLiveOut; 1872*06c3fb27SDimitry Andric else 1873*06c3fb27SDimitry Andric return /*Changed*/ false; 1874*06c3fb27SDimitry Andric return /*Changed*/ true; 1875*06c3fb27SDimitry Andric } 1876*06c3fb27SDimitry Andric 1877*06c3fb27SDimitry Andric // More than one pred. Join LiveOuts of blocks 1 and 2. 1878*06c3fb27SDimitry Andric assert(VisitedPreds.size() > 1); 1879*06c3fb27SDimitry Andric const BlockInfo &PredLiveOut0 = LiveOut.find(VisitedPreds[0])->second; 1880*06c3fb27SDimitry Andric const BlockInfo &PredLiveOut1 = LiveOut.find(VisitedPreds[1])->second; 1881*06c3fb27SDimitry Andric BlockInfo BBLiveIn = joinBlockInfo(PredLiveOut0, PredLiveOut1); 1882*06c3fb27SDimitry Andric 1883*06c3fb27SDimitry Andric // Join the LiveOuts of subsequent blocks. 1884*06c3fb27SDimitry Andric ArrayRef Tail = ArrayRef(VisitedPreds).drop_front(2); 1885*06c3fb27SDimitry Andric for (const BasicBlock *Pred : Tail) { 1886*06c3fb27SDimitry Andric const auto &PredLiveOut = LiveOut.find(Pred); 1887*06c3fb27SDimitry Andric assert(PredLiveOut != LiveOut.end() && 1888*06c3fb27SDimitry Andric "block should have been processed already"); 1889*06c3fb27SDimitry Andric BBLiveIn = joinBlockInfo(std::move(BBLiveIn), PredLiveOut->second); 1890*06c3fb27SDimitry Andric } 1891*06c3fb27SDimitry Andric 1892*06c3fb27SDimitry Andric // Save the joined result for BB. 1893bdd1243dSDimitry Andric auto CurrentLiveInEntry = LiveIn.find(&BB); 1894bdd1243dSDimitry Andric // Check if there isn't an entry, or there is but the LiveIn set has changed 1895bdd1243dSDimitry Andric // (expensive check). 1896*06c3fb27SDimitry Andric if (CurrentLiveInEntry == LiveIn.end()) 1897*06c3fb27SDimitry Andric LiveIn.try_emplace(&BB, std::move(BBLiveIn)); 1898*06c3fb27SDimitry Andric else if (BBLiveIn != CurrentLiveInEntry->second) 1899*06c3fb27SDimitry Andric CurrentLiveInEntry->second = std::move(BBLiveIn); 1900*06c3fb27SDimitry Andric else 1901*06c3fb27SDimitry Andric return /*Changed*/ false; 1902*06c3fb27SDimitry Andric return /*Changed*/ true; 1903bdd1243dSDimitry Andric } 1904bdd1243dSDimitry Andric 1905bdd1243dSDimitry Andric /// Return true if A fully contains B. 1906bdd1243dSDimitry Andric static bool fullyContains(DIExpression::FragmentInfo A, 1907bdd1243dSDimitry Andric DIExpression::FragmentInfo B) { 1908bdd1243dSDimitry Andric auto ALeft = A.OffsetInBits; 1909bdd1243dSDimitry Andric auto BLeft = B.OffsetInBits; 1910bdd1243dSDimitry Andric if (BLeft < ALeft) 1911bdd1243dSDimitry Andric return false; 1912bdd1243dSDimitry Andric 1913bdd1243dSDimitry Andric auto ARight = ALeft + A.SizeInBits; 1914bdd1243dSDimitry Andric auto BRight = BLeft + B.SizeInBits; 1915bdd1243dSDimitry Andric if (BRight > ARight) 1916bdd1243dSDimitry Andric return false; 1917bdd1243dSDimitry Andric return true; 1918bdd1243dSDimitry Andric } 1919bdd1243dSDimitry Andric 1920bdd1243dSDimitry Andric static std::optional<at::AssignmentInfo> 1921bdd1243dSDimitry Andric getUntaggedStoreAssignmentInfo(const Instruction &I, const DataLayout &Layout) { 1922bdd1243dSDimitry Andric // Don't bother checking if this is an AllocaInst. We know this 1923bdd1243dSDimitry Andric // instruction has no tag which means there are no variables associated 1924bdd1243dSDimitry Andric // with it. 1925bdd1243dSDimitry Andric if (const auto *SI = dyn_cast<StoreInst>(&I)) 1926bdd1243dSDimitry Andric return at::getAssignmentInfo(Layout, SI); 1927bdd1243dSDimitry Andric if (const auto *MI = dyn_cast<MemIntrinsic>(&I)) 1928bdd1243dSDimitry Andric return at::getAssignmentInfo(Layout, MI); 1929bdd1243dSDimitry Andric // Alloca or non-store-like inst. 1930bdd1243dSDimitry Andric return std::nullopt; 1931bdd1243dSDimitry Andric } 1932bdd1243dSDimitry Andric 1933bdd1243dSDimitry Andric /// Build a map of {Variable x: Variables y} where all variable fragments 1934bdd1243dSDimitry Andric /// contained within the variable fragment x are in set y. This means that 1935bdd1243dSDimitry Andric /// y does not contain all overlaps because partial overlaps are excluded. 1936bdd1243dSDimitry Andric /// 1937bdd1243dSDimitry Andric /// While we're iterating over the function, add single location defs for 1938*06c3fb27SDimitry Andric /// dbg.declares to \p FnVarLocs. 1939*06c3fb27SDimitry Andric /// 1940*06c3fb27SDimitry Andric /// Variables that are interesting to this pass in are added to 1941*06c3fb27SDimitry Andric /// FnVarLocs->Variables first. TrackedVariablesVectorSize is set to the ID of 1942*06c3fb27SDimitry Andric /// the last interesting variable plus 1, meaning variables with ID 1 1943*06c3fb27SDimitry Andric /// (inclusive) to TrackedVariablesVectorSize (exclusive) are interesting. The 1944*06c3fb27SDimitry Andric /// subsequent variables are either stack homed or fully promoted. 1945bdd1243dSDimitry Andric /// 1946bdd1243dSDimitry Andric /// Finally, populate UntaggedStoreVars with a mapping of untagged stores to 1947bdd1243dSDimitry Andric /// the stored-to variable fragments. 1948bdd1243dSDimitry Andric /// 1949bdd1243dSDimitry Andric /// These tasks are bundled together to reduce the number of times we need 1950bdd1243dSDimitry Andric /// to iterate over the function as they can be achieved together in one pass. 1951bdd1243dSDimitry Andric static AssignmentTrackingLowering::OverlapMap buildOverlapMapAndRecordDeclares( 1952bdd1243dSDimitry Andric Function &Fn, FunctionVarLocsBuilder *FnVarLocs, 1953*06c3fb27SDimitry Andric const DenseSet<DebugAggregate> &VarsWithStackSlot, 1954*06c3fb27SDimitry Andric AssignmentTrackingLowering::UntaggedStoreAssignmentMap &UntaggedStoreVars, 1955*06c3fb27SDimitry Andric unsigned &TrackedVariablesVectorSize) { 1956bdd1243dSDimitry Andric DenseSet<DebugVariable> Seen; 1957bdd1243dSDimitry Andric // Map of Variable: [Fragments]. 1958bdd1243dSDimitry Andric DenseMap<DebugAggregate, SmallVector<DebugVariable, 8>> FragmentMap; 1959bdd1243dSDimitry Andric // Iterate over all instructions: 1960bdd1243dSDimitry Andric // - dbg.declare -> add single location variable record 1961bdd1243dSDimitry Andric // - dbg.* -> Add fragments to FragmentMap 1962bdd1243dSDimitry Andric // - untagged store -> Add fragments to FragmentMap and update 1963bdd1243dSDimitry Andric // UntaggedStoreVars. 1964bdd1243dSDimitry Andric // We need to add fragments for untagged stores too so that we can correctly 1965bdd1243dSDimitry Andric // clobber overlapped fragment locations later. 1966*06c3fb27SDimitry Andric SmallVector<DbgDeclareInst *> Declares; 1967bdd1243dSDimitry Andric for (auto &BB : Fn) { 1968bdd1243dSDimitry Andric for (auto &I : BB) { 1969bdd1243dSDimitry Andric if (auto *DDI = dyn_cast<DbgDeclareInst>(&I)) { 1970*06c3fb27SDimitry Andric Declares.push_back(DDI); 1971bdd1243dSDimitry Andric } else if (auto *DII = dyn_cast<DbgVariableIntrinsic>(&I)) { 1972bdd1243dSDimitry Andric DebugVariable DV = DebugVariable(DII); 1973bdd1243dSDimitry Andric DebugAggregate DA = {DV.getVariable(), DV.getInlinedAt()}; 1974*06c3fb27SDimitry Andric if (!VarsWithStackSlot.contains(DA)) 1975*06c3fb27SDimitry Andric continue; 1976bdd1243dSDimitry Andric if (Seen.insert(DV).second) 1977bdd1243dSDimitry Andric FragmentMap[DA].push_back(DV); 1978bdd1243dSDimitry Andric } else if (auto Info = getUntaggedStoreAssignmentInfo( 1979bdd1243dSDimitry Andric I, Fn.getParent()->getDataLayout())) { 1980bdd1243dSDimitry Andric // Find markers linked to this alloca. 1981bdd1243dSDimitry Andric for (DbgAssignIntrinsic *DAI : at::getAssignmentMarkers(Info->Base)) { 1982bdd1243dSDimitry Andric // Discard the fragment if it covers the entire variable. 1983bdd1243dSDimitry Andric std::optional<DIExpression::FragmentInfo> FragInfo = 1984bdd1243dSDimitry Andric [&Info, DAI]() -> std::optional<DIExpression::FragmentInfo> { 1985bdd1243dSDimitry Andric DIExpression::FragmentInfo F; 1986bdd1243dSDimitry Andric F.OffsetInBits = Info->OffsetInBits; 1987bdd1243dSDimitry Andric F.SizeInBits = Info->SizeInBits; 1988bdd1243dSDimitry Andric if (auto ExistingFrag = DAI->getExpression()->getFragmentInfo()) 1989bdd1243dSDimitry Andric F.OffsetInBits += ExistingFrag->OffsetInBits; 1990bdd1243dSDimitry Andric if (auto Sz = DAI->getVariable()->getSizeInBits()) { 1991bdd1243dSDimitry Andric if (F.OffsetInBits == 0 && F.SizeInBits == *Sz) 1992bdd1243dSDimitry Andric return std::nullopt; 1993bdd1243dSDimitry Andric } 1994bdd1243dSDimitry Andric return F; 1995bdd1243dSDimitry Andric }(); 1996bdd1243dSDimitry Andric 1997bdd1243dSDimitry Andric DebugVariable DV = DebugVariable(DAI->getVariable(), FragInfo, 1998bdd1243dSDimitry Andric DAI->getDebugLoc().getInlinedAt()); 1999bdd1243dSDimitry Andric DebugAggregate DA = {DV.getVariable(), DV.getInlinedAt()}; 2000*06c3fb27SDimitry Andric if (!VarsWithStackSlot.contains(DA)) 2001*06c3fb27SDimitry Andric continue; 2002bdd1243dSDimitry Andric 2003bdd1243dSDimitry Andric // Cache this info for later. 2004bdd1243dSDimitry Andric UntaggedStoreVars[&I].push_back( 2005bdd1243dSDimitry Andric {FnVarLocs->insertVariable(DV), *Info}); 2006bdd1243dSDimitry Andric 2007bdd1243dSDimitry Andric if (Seen.insert(DV).second) 2008bdd1243dSDimitry Andric FragmentMap[DA].push_back(DV); 2009bdd1243dSDimitry Andric } 2010bdd1243dSDimitry Andric } 2011bdd1243dSDimitry Andric } 2012bdd1243dSDimitry Andric } 2013bdd1243dSDimitry Andric 2014*06c3fb27SDimitry Andric // Sort the fragment map for each DebugAggregate in ascending 2015*06c3fb27SDimitry Andric // order of fragment size - there should be no duplicates. 2016bdd1243dSDimitry Andric for (auto &Pair : FragmentMap) { 2017bdd1243dSDimitry Andric SmallVector<DebugVariable, 8> &Frags = Pair.second; 2018*06c3fb27SDimitry Andric std::sort(Frags.begin(), Frags.end(), 2019*06c3fb27SDimitry Andric [](const DebugVariable &Next, const DebugVariable &Elmt) { 2020bdd1243dSDimitry Andric return Elmt.getFragmentOrDefault().SizeInBits > 2021bdd1243dSDimitry Andric Next.getFragmentOrDefault().SizeInBits; 2022bdd1243dSDimitry Andric }); 2023*06c3fb27SDimitry Andric // Check for duplicates. 2024*06c3fb27SDimitry Andric assert(std::adjacent_find(Frags.begin(), Frags.end()) == Frags.end()); 2025bdd1243dSDimitry Andric } 2026bdd1243dSDimitry Andric 2027bdd1243dSDimitry Andric // Build the map. 2028bdd1243dSDimitry Andric AssignmentTrackingLowering::OverlapMap Map; 2029*06c3fb27SDimitry Andric for (auto &Pair : FragmentMap) { 2030bdd1243dSDimitry Andric auto &Frags = Pair.second; 2031bdd1243dSDimitry Andric for (auto It = Frags.begin(), IEnd = Frags.end(); It != IEnd; ++It) { 2032bdd1243dSDimitry Andric DIExpression::FragmentInfo Frag = It->getFragmentOrDefault(); 2033bdd1243dSDimitry Andric // Find the frags that this is contained within. 2034bdd1243dSDimitry Andric // 2035bdd1243dSDimitry Andric // Because Frags is sorted by size and none have the same offset and 2036bdd1243dSDimitry Andric // size, we know that this frag can only be contained by subsequent 2037bdd1243dSDimitry Andric // elements. 2038bdd1243dSDimitry Andric SmallVector<DebugVariable, 8>::iterator OtherIt = It; 2039bdd1243dSDimitry Andric ++OtherIt; 2040bdd1243dSDimitry Andric VariableID ThisVar = FnVarLocs->insertVariable(*It); 2041bdd1243dSDimitry Andric for (; OtherIt != IEnd; ++OtherIt) { 2042bdd1243dSDimitry Andric DIExpression::FragmentInfo OtherFrag = OtherIt->getFragmentOrDefault(); 2043bdd1243dSDimitry Andric VariableID OtherVar = FnVarLocs->insertVariable(*OtherIt); 2044bdd1243dSDimitry Andric if (fullyContains(OtherFrag, Frag)) 2045bdd1243dSDimitry Andric Map[OtherVar].push_back(ThisVar); 2046bdd1243dSDimitry Andric } 2047bdd1243dSDimitry Andric } 2048bdd1243dSDimitry Andric } 2049bdd1243dSDimitry Andric 2050*06c3fb27SDimitry Andric // VariableIDs are 1-based so the variable-tracking bitvector needs 2051*06c3fb27SDimitry Andric // NumVariables plus 1 bits. 2052*06c3fb27SDimitry Andric TrackedVariablesVectorSize = FnVarLocs->getNumVariables() + 1; 2053*06c3fb27SDimitry Andric 2054*06c3fb27SDimitry Andric // Finally, insert the declares afterwards, so the first IDs are all 2055*06c3fb27SDimitry Andric // partially stack homed vars. 2056*06c3fb27SDimitry Andric for (auto *DDI : Declares) 2057*06c3fb27SDimitry Andric FnVarLocs->addSingleLocVar(DebugVariable(DDI), DDI->getExpression(), 2058*06c3fb27SDimitry Andric DDI->getDebugLoc(), DDI->getWrappedLocation()); 2059bdd1243dSDimitry Andric return Map; 2060bdd1243dSDimitry Andric } 2061bdd1243dSDimitry Andric 2062bdd1243dSDimitry Andric bool AssignmentTrackingLowering::run(FunctionVarLocsBuilder *FnVarLocsBuilder) { 2063bdd1243dSDimitry Andric if (Fn.size() > MaxNumBlocks) { 2064bdd1243dSDimitry Andric LLVM_DEBUG(dbgs() << "[AT] Dropping var locs in: " << Fn.getName() 2065bdd1243dSDimitry Andric << ": too many blocks (" << Fn.size() << ")\n"); 2066bdd1243dSDimitry Andric at::deleteAll(&Fn); 2067bdd1243dSDimitry Andric return false; 2068bdd1243dSDimitry Andric } 2069bdd1243dSDimitry Andric 2070bdd1243dSDimitry Andric FnVarLocs = FnVarLocsBuilder; 2071bdd1243dSDimitry Andric 2072bdd1243dSDimitry Andric // The general structure here is inspired by VarLocBasedImpl.cpp 2073bdd1243dSDimitry Andric // (LiveDebugValues). 2074bdd1243dSDimitry Andric 2075bdd1243dSDimitry Andric // Build the variable fragment overlap map. 2076bdd1243dSDimitry Andric // Note that this pass doesn't handle partial overlaps correctly (FWIW 2077bdd1243dSDimitry Andric // neither does LiveDebugVariables) because that is difficult to do and 2078bdd1243dSDimitry Andric // appears to be rare occurance. 2079*06c3fb27SDimitry Andric VarContains = buildOverlapMapAndRecordDeclares( 2080*06c3fb27SDimitry Andric Fn, FnVarLocs, *VarsWithStackSlot, UntaggedStoreVars, 2081*06c3fb27SDimitry Andric TrackedVariablesVectorSize); 2082bdd1243dSDimitry Andric 2083bdd1243dSDimitry Andric // Prepare for traversal. 2084bdd1243dSDimitry Andric ReversePostOrderTraversal<Function *> RPOT(&Fn); 2085bdd1243dSDimitry Andric std::priority_queue<unsigned int, std::vector<unsigned int>, 2086bdd1243dSDimitry Andric std::greater<unsigned int>> 2087bdd1243dSDimitry Andric Worklist; 2088bdd1243dSDimitry Andric std::priority_queue<unsigned int, std::vector<unsigned int>, 2089bdd1243dSDimitry Andric std::greater<unsigned int>> 2090bdd1243dSDimitry Andric Pending; 2091bdd1243dSDimitry Andric DenseMap<unsigned int, BasicBlock *> OrderToBB; 2092bdd1243dSDimitry Andric DenseMap<BasicBlock *, unsigned int> BBToOrder; 2093bdd1243dSDimitry Andric { // Init OrderToBB and BBToOrder. 2094bdd1243dSDimitry Andric unsigned int RPONumber = 0; 2095bdd1243dSDimitry Andric for (auto RI = RPOT.begin(), RE = RPOT.end(); RI != RE; ++RI) { 2096bdd1243dSDimitry Andric OrderToBB[RPONumber] = *RI; 2097bdd1243dSDimitry Andric BBToOrder[*RI] = RPONumber; 2098bdd1243dSDimitry Andric Worklist.push(RPONumber); 2099bdd1243dSDimitry Andric ++RPONumber; 2100bdd1243dSDimitry Andric } 2101bdd1243dSDimitry Andric LiveIn.init(RPONumber); 2102bdd1243dSDimitry Andric LiveOut.init(RPONumber); 2103bdd1243dSDimitry Andric } 2104bdd1243dSDimitry Andric 2105bdd1243dSDimitry Andric // Perform the traversal. 2106bdd1243dSDimitry Andric // 2107bdd1243dSDimitry Andric // This is a standard "union of predecessor outs" dataflow problem. To solve 2108bdd1243dSDimitry Andric // it, we perform join() and process() using the two worklist method until 2109bdd1243dSDimitry Andric // the LiveIn data for each block becomes unchanging. The "proof" that this 2110bdd1243dSDimitry Andric // terminates can be put together by looking at the comments around LocKind, 2111bdd1243dSDimitry Andric // Assignment, and the various join methods, which show that all the elements 2112bdd1243dSDimitry Andric // involved are made up of join-semilattices; LiveIn(n) can only 2113bdd1243dSDimitry Andric // monotonically increase in value throughout the dataflow. 2114bdd1243dSDimitry Andric // 2115bdd1243dSDimitry Andric SmallPtrSet<BasicBlock *, 16> Visited; 2116bdd1243dSDimitry Andric while (!Worklist.empty()) { 2117bdd1243dSDimitry Andric // We track what is on the pending worklist to avoid inserting the same 2118bdd1243dSDimitry Andric // thing twice. 2119bdd1243dSDimitry Andric SmallPtrSet<BasicBlock *, 16> OnPending; 2120bdd1243dSDimitry Andric LLVM_DEBUG(dbgs() << "Processing Worklist\n"); 2121bdd1243dSDimitry Andric while (!Worklist.empty()) { 2122bdd1243dSDimitry Andric BasicBlock *BB = OrderToBB[Worklist.top()]; 2123bdd1243dSDimitry Andric LLVM_DEBUG(dbgs() << "\nPop BB " << BB->getName() << "\n"); 2124bdd1243dSDimitry Andric Worklist.pop(); 2125bdd1243dSDimitry Andric bool InChanged = join(*BB, Visited); 2126bdd1243dSDimitry Andric // Always consider LiveIn changed on the first visit. 2127bdd1243dSDimitry Andric InChanged |= Visited.insert(BB).second; 2128bdd1243dSDimitry Andric if (InChanged) { 2129bdd1243dSDimitry Andric LLVM_DEBUG(dbgs() << BB->getName() << " has new InLocs, process it\n"); 2130bdd1243dSDimitry Andric // Mutate a copy of LiveIn while processing BB. After calling process 2131bdd1243dSDimitry Andric // LiveSet is the LiveOut set for BB. 2132bdd1243dSDimitry Andric BlockInfo LiveSet = LiveIn[BB]; 2133bdd1243dSDimitry Andric 2134bdd1243dSDimitry Andric // Process the instructions in the block. 2135bdd1243dSDimitry Andric process(*BB, &LiveSet); 2136bdd1243dSDimitry Andric 2137bdd1243dSDimitry Andric // Relatively expensive check: has anything changed in LiveOut for BB? 2138bdd1243dSDimitry Andric if (LiveOut[BB] != LiveSet) { 2139bdd1243dSDimitry Andric LLVM_DEBUG(dbgs() << BB->getName() 2140bdd1243dSDimitry Andric << " has new OutLocs, add succs to worklist: [ "); 2141bdd1243dSDimitry Andric LiveOut[BB] = std::move(LiveSet); 2142bdd1243dSDimitry Andric for (auto I = succ_begin(BB), E = succ_end(BB); I != E; I++) { 2143bdd1243dSDimitry Andric if (OnPending.insert(*I).second) { 2144bdd1243dSDimitry Andric LLVM_DEBUG(dbgs() << I->getName() << " "); 2145bdd1243dSDimitry Andric Pending.push(BBToOrder[*I]); 2146bdd1243dSDimitry Andric } 2147bdd1243dSDimitry Andric } 2148bdd1243dSDimitry Andric LLVM_DEBUG(dbgs() << "]\n"); 2149bdd1243dSDimitry Andric } 2150bdd1243dSDimitry Andric } 2151bdd1243dSDimitry Andric } 2152bdd1243dSDimitry Andric Worklist.swap(Pending); 2153bdd1243dSDimitry Andric // At this point, pending must be empty, since it was just the empty 2154bdd1243dSDimitry Andric // worklist 2155bdd1243dSDimitry Andric assert(Pending.empty() && "Pending should be empty"); 2156bdd1243dSDimitry Andric } 2157bdd1243dSDimitry Andric 2158bdd1243dSDimitry Andric // That's the hard part over. Now we just have some admin to do. 2159bdd1243dSDimitry Andric 2160bdd1243dSDimitry Andric // Record whether we inserted any intrinsics. 2161bdd1243dSDimitry Andric bool InsertedAnyIntrinsics = false; 2162bdd1243dSDimitry Andric 2163bdd1243dSDimitry Andric // Identify and add defs for single location variables. 2164bdd1243dSDimitry Andric // 2165bdd1243dSDimitry Andric // Go through all of the defs that we plan to add. If the aggregate variable 2166bdd1243dSDimitry Andric // it's a part of is not in the NotAlwaysStackHomed set we can emit a single 2167bdd1243dSDimitry Andric // location def and omit the rest. Add an entry to AlwaysStackHomed so that 2168bdd1243dSDimitry Andric // we can identify those uneeded defs later. 2169bdd1243dSDimitry Andric DenseSet<DebugAggregate> AlwaysStackHomed; 2170bdd1243dSDimitry Andric for (const auto &Pair : InsertBeforeMap) { 2171bdd1243dSDimitry Andric const auto &Vec = Pair.second; 2172bdd1243dSDimitry Andric for (VarLocInfo VarLoc : Vec) { 2173bdd1243dSDimitry Andric DebugVariable Var = FnVarLocs->getVariable(VarLoc.VariableID); 2174bdd1243dSDimitry Andric DebugAggregate Aggr{Var.getVariable(), Var.getInlinedAt()}; 2175bdd1243dSDimitry Andric 2176bdd1243dSDimitry Andric // Skip this Var if it's not always stack homed. 2177bdd1243dSDimitry Andric if (NotAlwaysStackHomed.contains(Aggr)) 2178bdd1243dSDimitry Andric continue; 2179bdd1243dSDimitry Andric 2180bdd1243dSDimitry Andric // Skip complex cases such as when different fragments of a variable have 2181bdd1243dSDimitry Andric // been split into different allocas. Skipping in this case means falling 2182bdd1243dSDimitry Andric // back to using a list of defs (which could reduce coverage, but is no 2183bdd1243dSDimitry Andric // less correct). 2184bdd1243dSDimitry Andric bool Simple = 2185bdd1243dSDimitry Andric VarLoc.Expr->getNumElements() == 1 && VarLoc.Expr->startsWithDeref(); 2186bdd1243dSDimitry Andric if (!Simple) { 2187bdd1243dSDimitry Andric NotAlwaysStackHomed.insert(Aggr); 2188bdd1243dSDimitry Andric continue; 2189bdd1243dSDimitry Andric } 2190bdd1243dSDimitry Andric 2191bdd1243dSDimitry Andric // All source assignments to this variable remain and all stores to any 2192bdd1243dSDimitry Andric // part of the variable store to the same address (with varying 2193bdd1243dSDimitry Andric // offsets). We can just emit a single location for the whole variable. 2194bdd1243dSDimitry Andric // 2195bdd1243dSDimitry Andric // Unless we've already done so, create the single location def now. 2196bdd1243dSDimitry Andric if (AlwaysStackHomed.insert(Aggr).second) { 2197*06c3fb27SDimitry Andric assert(!VarLoc.Values.hasArgList()); 2198bdd1243dSDimitry Andric // TODO: When more complex cases are handled VarLoc.Expr should be 2199bdd1243dSDimitry Andric // built appropriately rather than always using an empty DIExpression. 2200bdd1243dSDimitry Andric // The assert below is a reminder. 2201bdd1243dSDimitry Andric assert(Simple); 2202bdd1243dSDimitry Andric VarLoc.Expr = DIExpression::get(Fn.getContext(), std::nullopt); 2203bdd1243dSDimitry Andric DebugVariable Var = FnVarLocs->getVariable(VarLoc.VariableID); 2204*06c3fb27SDimitry Andric FnVarLocs->addSingleLocVar(Var, VarLoc.Expr, VarLoc.DL, VarLoc.Values); 2205bdd1243dSDimitry Andric InsertedAnyIntrinsics = true; 2206bdd1243dSDimitry Andric } 2207bdd1243dSDimitry Andric } 2208bdd1243dSDimitry Andric } 2209bdd1243dSDimitry Andric 2210bdd1243dSDimitry Andric // Insert the other DEFs. 2211bdd1243dSDimitry Andric for (const auto &[InsertBefore, Vec] : InsertBeforeMap) { 2212bdd1243dSDimitry Andric SmallVector<VarLocInfo> NewDefs; 2213bdd1243dSDimitry Andric for (const VarLocInfo &VarLoc : Vec) { 2214bdd1243dSDimitry Andric DebugVariable Var = FnVarLocs->getVariable(VarLoc.VariableID); 2215bdd1243dSDimitry Andric DebugAggregate Aggr{Var.getVariable(), Var.getInlinedAt()}; 2216bdd1243dSDimitry Andric // If this variable is always stack homed then we have already inserted a 2217bdd1243dSDimitry Andric // dbg.declare and deleted this dbg.value. 2218bdd1243dSDimitry Andric if (AlwaysStackHomed.contains(Aggr)) 2219bdd1243dSDimitry Andric continue; 2220bdd1243dSDimitry Andric NewDefs.push_back(VarLoc); 2221bdd1243dSDimitry Andric InsertedAnyIntrinsics = true; 2222bdd1243dSDimitry Andric } 2223bdd1243dSDimitry Andric 2224bdd1243dSDimitry Andric FnVarLocs->setWedge(InsertBefore, std::move(NewDefs)); 2225bdd1243dSDimitry Andric } 2226bdd1243dSDimitry Andric 2227bdd1243dSDimitry Andric InsertedAnyIntrinsics |= emitPromotedVarLocs(FnVarLocs); 2228bdd1243dSDimitry Andric 2229bdd1243dSDimitry Andric return InsertedAnyIntrinsics; 2230bdd1243dSDimitry Andric } 2231bdd1243dSDimitry Andric 2232bdd1243dSDimitry Andric bool AssignmentTrackingLowering::emitPromotedVarLocs( 2233bdd1243dSDimitry Andric FunctionVarLocsBuilder *FnVarLocs) { 2234bdd1243dSDimitry Andric bool InsertedAnyIntrinsics = false; 2235bdd1243dSDimitry Andric // Go through every block, translating debug intrinsics for fully promoted 2236bdd1243dSDimitry Andric // variables into FnVarLocs location defs. No analysis required for these. 2237bdd1243dSDimitry Andric for (auto &BB : Fn) { 2238bdd1243dSDimitry Andric for (auto &I : BB) { 2239bdd1243dSDimitry Andric // Skip instructions other than dbg.values and dbg.assigns. 2240bdd1243dSDimitry Andric auto *DVI = dyn_cast<DbgValueInst>(&I); 2241bdd1243dSDimitry Andric if (!DVI) 2242bdd1243dSDimitry Andric continue; 2243bdd1243dSDimitry Andric // Skip variables that haven't been promoted - we've dealt with those 2244bdd1243dSDimitry Andric // already. 2245bdd1243dSDimitry Andric if (VarsWithStackSlot->contains(getAggregate(DVI))) 2246bdd1243dSDimitry Andric continue; 2247bdd1243dSDimitry Andric Instruction *InsertBefore = I.getNextNode(); 2248bdd1243dSDimitry Andric assert(InsertBefore && "Unexpected: debug intrinsics after a terminator"); 2249bdd1243dSDimitry Andric FnVarLocs->addVarLoc(InsertBefore, DebugVariable(DVI), 2250bdd1243dSDimitry Andric DVI->getExpression(), DVI->getDebugLoc(), 2251*06c3fb27SDimitry Andric DVI->getWrappedLocation()); 2252bdd1243dSDimitry Andric InsertedAnyIntrinsics = true; 2253bdd1243dSDimitry Andric } 2254bdd1243dSDimitry Andric } 2255bdd1243dSDimitry Andric return InsertedAnyIntrinsics; 2256bdd1243dSDimitry Andric } 2257bdd1243dSDimitry Andric 2258bdd1243dSDimitry Andric /// Remove redundant definitions within sequences of consecutive location defs. 2259bdd1243dSDimitry Andric /// This is done using a backward scan to keep the last def describing a 2260bdd1243dSDimitry Andric /// specific variable/fragment. 2261bdd1243dSDimitry Andric /// 2262bdd1243dSDimitry Andric /// This implements removeRedundantDbgInstrsUsingBackwardScan from 2263bdd1243dSDimitry Andric /// lib/Transforms/Utils/BasicBlockUtils.cpp for locations described with 2264bdd1243dSDimitry Andric /// FunctionVarLocsBuilder instead of with intrinsics. 2265bdd1243dSDimitry Andric static bool 2266bdd1243dSDimitry Andric removeRedundantDbgLocsUsingBackwardScan(const BasicBlock *BB, 2267bdd1243dSDimitry Andric FunctionVarLocsBuilder &FnVarLocs) { 2268bdd1243dSDimitry Andric bool Changed = false; 2269*06c3fb27SDimitry Andric SmallDenseMap<DebugAggregate, BitVector> VariableDefinedBits; 2270bdd1243dSDimitry Andric // Scan over the entire block, not just over the instructions mapped by 2271bdd1243dSDimitry Andric // FnVarLocs, because wedges in FnVarLocs may only be seperated by debug 2272bdd1243dSDimitry Andric // instructions. 2273bdd1243dSDimitry Andric for (const Instruction &I : reverse(*BB)) { 2274bdd1243dSDimitry Andric if (!isa<DbgVariableIntrinsic>(I)) { 2275bdd1243dSDimitry Andric // Sequence of consecutive defs ended. Clear map for the next one. 2276*06c3fb27SDimitry Andric VariableDefinedBits.clear(); 2277bdd1243dSDimitry Andric } 2278bdd1243dSDimitry Andric 2279bdd1243dSDimitry Andric // Get the location defs that start just before this instruction. 2280bdd1243dSDimitry Andric const auto *Locs = FnVarLocs.getWedge(&I); 2281bdd1243dSDimitry Andric if (!Locs) 2282bdd1243dSDimitry Andric continue; 2283bdd1243dSDimitry Andric 2284bdd1243dSDimitry Andric NumWedgesScanned++; 2285bdd1243dSDimitry Andric bool ChangedThisWedge = false; 2286bdd1243dSDimitry Andric // The new pruned set of defs, reversed because we're scanning backwards. 2287bdd1243dSDimitry Andric SmallVector<VarLocInfo> NewDefsReversed; 2288bdd1243dSDimitry Andric 2289bdd1243dSDimitry Andric // Iterate over the existing defs in reverse. 2290bdd1243dSDimitry Andric for (auto RIt = Locs->rbegin(), REnd = Locs->rend(); RIt != REnd; ++RIt) { 2291bdd1243dSDimitry Andric NumDefsScanned++; 2292*06c3fb27SDimitry Andric DebugAggregate Aggr = 2293*06c3fb27SDimitry Andric getAggregate(FnVarLocs.getVariable(RIt->VariableID)); 2294*06c3fb27SDimitry Andric uint64_t SizeInBits = Aggr.first->getSizeInBits().value_or(0); 2295bdd1243dSDimitry Andric 2296*06c3fb27SDimitry Andric if (SizeInBits == 0) { 2297*06c3fb27SDimitry Andric // If the size is unknown (0) then keep this location def to be safe. 2298bdd1243dSDimitry Andric NewDefsReversed.push_back(*RIt); 2299*06c3fb27SDimitry Andric continue; 2300*06c3fb27SDimitry Andric } 2301*06c3fb27SDimitry Andric 2302*06c3fb27SDimitry Andric // Only keep this location definition if it is not fully eclipsed by 2303*06c3fb27SDimitry Andric // other definitions in this wedge that come after it 2304*06c3fb27SDimitry Andric 2305*06c3fb27SDimitry Andric // Inert the bits the location definition defines. 2306*06c3fb27SDimitry Andric auto InsertResult = 2307*06c3fb27SDimitry Andric VariableDefinedBits.try_emplace(Aggr, BitVector(SizeInBits)); 2308*06c3fb27SDimitry Andric bool FirstDefinition = InsertResult.second; 2309*06c3fb27SDimitry Andric BitVector &DefinedBits = InsertResult.first->second; 2310*06c3fb27SDimitry Andric 2311*06c3fb27SDimitry Andric DIExpression::FragmentInfo Fragment = 2312*06c3fb27SDimitry Andric RIt->Expr->getFragmentInfo().value_or( 2313*06c3fb27SDimitry Andric DIExpression::FragmentInfo(SizeInBits, 0)); 2314*06c3fb27SDimitry Andric bool InvalidFragment = Fragment.endInBits() > SizeInBits; 2315*06c3fb27SDimitry Andric 2316*06c3fb27SDimitry Andric // If this defines any previously undefined bits, keep it. 2317*06c3fb27SDimitry Andric if (FirstDefinition || InvalidFragment || 2318*06c3fb27SDimitry Andric DefinedBits.find_first_unset_in(Fragment.startInBits(), 2319*06c3fb27SDimitry Andric Fragment.endInBits()) != -1) { 2320*06c3fb27SDimitry Andric if (!InvalidFragment) 2321*06c3fb27SDimitry Andric DefinedBits.set(Fragment.startInBits(), Fragment.endInBits()); 2322*06c3fb27SDimitry Andric NewDefsReversed.push_back(*RIt); 2323*06c3fb27SDimitry Andric continue; 2324*06c3fb27SDimitry Andric } 2325*06c3fb27SDimitry Andric 2326bdd1243dSDimitry Andric // Redundant def found: throw it away. Since the wedge of defs is being 2327bdd1243dSDimitry Andric // rebuilt, doing nothing is the same as deleting an entry. 2328bdd1243dSDimitry Andric ChangedThisWedge = true; 2329bdd1243dSDimitry Andric NumDefsRemoved++; 2330bdd1243dSDimitry Andric } 2331bdd1243dSDimitry Andric 2332bdd1243dSDimitry Andric // Un-reverse the defs and replace the wedge with the pruned version. 2333bdd1243dSDimitry Andric if (ChangedThisWedge) { 2334bdd1243dSDimitry Andric std::reverse(NewDefsReversed.begin(), NewDefsReversed.end()); 2335bdd1243dSDimitry Andric FnVarLocs.setWedge(&I, std::move(NewDefsReversed)); 2336bdd1243dSDimitry Andric NumWedgesChanged++; 2337bdd1243dSDimitry Andric Changed = true; 2338bdd1243dSDimitry Andric } 2339bdd1243dSDimitry Andric } 2340bdd1243dSDimitry Andric 2341bdd1243dSDimitry Andric return Changed; 2342bdd1243dSDimitry Andric } 2343bdd1243dSDimitry Andric 2344bdd1243dSDimitry Andric /// Remove redundant location defs using a forward scan. This can remove a 2345bdd1243dSDimitry Andric /// location definition that is redundant due to indicating that a variable has 2346bdd1243dSDimitry Andric /// the same value as is already being indicated by an earlier def. 2347bdd1243dSDimitry Andric /// 2348bdd1243dSDimitry Andric /// This implements removeRedundantDbgInstrsUsingForwardScan from 2349bdd1243dSDimitry Andric /// lib/Transforms/Utils/BasicBlockUtils.cpp for locations described with 2350bdd1243dSDimitry Andric /// FunctionVarLocsBuilder instead of with intrinsics 2351bdd1243dSDimitry Andric static bool 2352bdd1243dSDimitry Andric removeRedundantDbgLocsUsingForwardScan(const BasicBlock *BB, 2353bdd1243dSDimitry Andric FunctionVarLocsBuilder &FnVarLocs) { 2354bdd1243dSDimitry Andric bool Changed = false; 2355*06c3fb27SDimitry Andric DenseMap<DebugVariable, std::pair<RawLocationWrapper, DIExpression *>> 2356*06c3fb27SDimitry Andric VariableMap; 2357bdd1243dSDimitry Andric 2358bdd1243dSDimitry Andric // Scan over the entire block, not just over the instructions mapped by 2359bdd1243dSDimitry Andric // FnVarLocs, because wedges in FnVarLocs may only be seperated by debug 2360bdd1243dSDimitry Andric // instructions. 2361bdd1243dSDimitry Andric for (const Instruction &I : *BB) { 2362bdd1243dSDimitry Andric // Get the defs that come just before this instruction. 2363bdd1243dSDimitry Andric const auto *Locs = FnVarLocs.getWedge(&I); 2364bdd1243dSDimitry Andric if (!Locs) 2365bdd1243dSDimitry Andric continue; 2366bdd1243dSDimitry Andric 2367bdd1243dSDimitry Andric NumWedgesScanned++; 2368bdd1243dSDimitry Andric bool ChangedThisWedge = false; 2369bdd1243dSDimitry Andric // The new pruned set of defs. 2370bdd1243dSDimitry Andric SmallVector<VarLocInfo> NewDefs; 2371bdd1243dSDimitry Andric 2372bdd1243dSDimitry Andric // Iterate over the existing defs. 2373bdd1243dSDimitry Andric for (const VarLocInfo &Loc : *Locs) { 2374bdd1243dSDimitry Andric NumDefsScanned++; 2375bdd1243dSDimitry Andric DebugVariable Key(FnVarLocs.getVariable(Loc.VariableID).getVariable(), 2376bdd1243dSDimitry Andric std::nullopt, Loc.DL.getInlinedAt()); 2377bdd1243dSDimitry Andric auto VMI = VariableMap.find(Key); 2378bdd1243dSDimitry Andric 2379bdd1243dSDimitry Andric // Update the map if we found a new value/expression describing the 2380bdd1243dSDimitry Andric // variable, or if the variable wasn't mapped already. 2381*06c3fb27SDimitry Andric if (VMI == VariableMap.end() || VMI->second.first != Loc.Values || 2382bdd1243dSDimitry Andric VMI->second.second != Loc.Expr) { 2383*06c3fb27SDimitry Andric VariableMap[Key] = {Loc.Values, Loc.Expr}; 2384bdd1243dSDimitry Andric NewDefs.push_back(Loc); 2385bdd1243dSDimitry Andric continue; 2386bdd1243dSDimitry Andric } 2387bdd1243dSDimitry Andric 2388bdd1243dSDimitry Andric // Did not insert this Loc, which is the same as removing it. 2389bdd1243dSDimitry Andric ChangedThisWedge = true; 2390bdd1243dSDimitry Andric NumDefsRemoved++; 2391bdd1243dSDimitry Andric } 2392bdd1243dSDimitry Andric 2393bdd1243dSDimitry Andric // Replace the existing wedge with the pruned version. 2394bdd1243dSDimitry Andric if (ChangedThisWedge) { 2395bdd1243dSDimitry Andric FnVarLocs.setWedge(&I, std::move(NewDefs)); 2396bdd1243dSDimitry Andric NumWedgesChanged++; 2397bdd1243dSDimitry Andric Changed = true; 2398bdd1243dSDimitry Andric } 2399bdd1243dSDimitry Andric } 2400bdd1243dSDimitry Andric 2401bdd1243dSDimitry Andric return Changed; 2402bdd1243dSDimitry Andric } 2403bdd1243dSDimitry Andric 2404bdd1243dSDimitry Andric static bool 2405bdd1243dSDimitry Andric removeUndefDbgLocsFromEntryBlock(const BasicBlock *BB, 2406bdd1243dSDimitry Andric FunctionVarLocsBuilder &FnVarLocs) { 2407bdd1243dSDimitry Andric assert(BB->isEntryBlock()); 2408bdd1243dSDimitry Andric // Do extra work to ensure that we remove semantically unimportant undefs. 2409bdd1243dSDimitry Andric // 2410bdd1243dSDimitry Andric // This is to work around the fact that SelectionDAG will hoist dbg.values 2411bdd1243dSDimitry Andric // using argument values to the top of the entry block. That can move arg 2412bdd1243dSDimitry Andric // dbg.values before undef and constant dbg.values which they previously 2413bdd1243dSDimitry Andric // followed. The easiest thing to do is to just try to feed SelectionDAG 2414bdd1243dSDimitry Andric // input it's happy with. 2415bdd1243dSDimitry Andric // 2416bdd1243dSDimitry Andric // Map of {Variable x: Fragments y} where the fragments y of variable x have 2417bdd1243dSDimitry Andric // have at least one non-undef location defined already. Don't use directly, 2418bdd1243dSDimitry Andric // instead call DefineBits and HasDefinedBits. 2419bdd1243dSDimitry Andric SmallDenseMap<DebugAggregate, SmallDenseSet<DIExpression::FragmentInfo>> 2420bdd1243dSDimitry Andric VarsWithDef; 2421bdd1243dSDimitry Andric // Specify that V (a fragment of A) has a non-undef location. 2422bdd1243dSDimitry Andric auto DefineBits = [&VarsWithDef](DebugAggregate A, DebugVariable V) { 2423bdd1243dSDimitry Andric VarsWithDef[A].insert(V.getFragmentOrDefault()); 2424bdd1243dSDimitry Andric }; 2425bdd1243dSDimitry Andric // Return true if a non-undef location has been defined for V (a fragment of 2426bdd1243dSDimitry Andric // A). Doesn't imply that the location is currently non-undef, just that a 2427bdd1243dSDimitry Andric // non-undef location has been seen previously. 2428bdd1243dSDimitry Andric auto HasDefinedBits = [&VarsWithDef](DebugAggregate A, DebugVariable V) { 2429bdd1243dSDimitry Andric auto FragsIt = VarsWithDef.find(A); 2430bdd1243dSDimitry Andric if (FragsIt == VarsWithDef.end()) 2431bdd1243dSDimitry Andric return false; 2432bdd1243dSDimitry Andric return llvm::any_of(FragsIt->second, [V](auto Frag) { 2433bdd1243dSDimitry Andric return DIExpression::fragmentsOverlap(Frag, V.getFragmentOrDefault()); 2434bdd1243dSDimitry Andric }); 2435bdd1243dSDimitry Andric }; 2436bdd1243dSDimitry Andric 2437bdd1243dSDimitry Andric bool Changed = false; 2438bdd1243dSDimitry Andric DenseMap<DebugVariable, std::pair<Value *, DIExpression *>> VariableMap; 2439bdd1243dSDimitry Andric 2440bdd1243dSDimitry Andric // Scan over the entire block, not just over the instructions mapped by 2441bdd1243dSDimitry Andric // FnVarLocs, because wedges in FnVarLocs may only be seperated by debug 2442bdd1243dSDimitry Andric // instructions. 2443bdd1243dSDimitry Andric for (const Instruction &I : *BB) { 2444bdd1243dSDimitry Andric // Get the defs that come just before this instruction. 2445bdd1243dSDimitry Andric const auto *Locs = FnVarLocs.getWedge(&I); 2446bdd1243dSDimitry Andric if (!Locs) 2447bdd1243dSDimitry Andric continue; 2448bdd1243dSDimitry Andric 2449bdd1243dSDimitry Andric NumWedgesScanned++; 2450bdd1243dSDimitry Andric bool ChangedThisWedge = false; 2451bdd1243dSDimitry Andric // The new pruned set of defs. 2452bdd1243dSDimitry Andric SmallVector<VarLocInfo> NewDefs; 2453bdd1243dSDimitry Andric 2454bdd1243dSDimitry Andric // Iterate over the existing defs. 2455bdd1243dSDimitry Andric for (const VarLocInfo &Loc : *Locs) { 2456bdd1243dSDimitry Andric NumDefsScanned++; 2457bdd1243dSDimitry Andric DebugAggregate Aggr{FnVarLocs.getVariable(Loc.VariableID).getVariable(), 2458bdd1243dSDimitry Andric Loc.DL.getInlinedAt()}; 2459bdd1243dSDimitry Andric DebugVariable Var = FnVarLocs.getVariable(Loc.VariableID); 2460bdd1243dSDimitry Andric 2461bdd1243dSDimitry Andric // Remove undef entries that are encountered before any non-undef 2462bdd1243dSDimitry Andric // intrinsics from the entry block. 2463*06c3fb27SDimitry Andric if (Loc.Values.isKillLocation(Loc.Expr) && !HasDefinedBits(Aggr, Var)) { 2464bdd1243dSDimitry Andric // Did not insert this Loc, which is the same as removing it. 2465bdd1243dSDimitry Andric NumDefsRemoved++; 2466bdd1243dSDimitry Andric ChangedThisWedge = true; 2467bdd1243dSDimitry Andric continue; 2468bdd1243dSDimitry Andric } 2469bdd1243dSDimitry Andric 2470bdd1243dSDimitry Andric DefineBits(Aggr, Var); 2471bdd1243dSDimitry Andric NewDefs.push_back(Loc); 2472bdd1243dSDimitry Andric } 2473bdd1243dSDimitry Andric 2474bdd1243dSDimitry Andric // Replace the existing wedge with the pruned version. 2475bdd1243dSDimitry Andric if (ChangedThisWedge) { 2476bdd1243dSDimitry Andric FnVarLocs.setWedge(&I, std::move(NewDefs)); 2477bdd1243dSDimitry Andric NumWedgesChanged++; 2478bdd1243dSDimitry Andric Changed = true; 2479bdd1243dSDimitry Andric } 2480bdd1243dSDimitry Andric } 2481bdd1243dSDimitry Andric 2482bdd1243dSDimitry Andric return Changed; 2483bdd1243dSDimitry Andric } 2484bdd1243dSDimitry Andric 2485bdd1243dSDimitry Andric static bool removeRedundantDbgLocs(const BasicBlock *BB, 2486bdd1243dSDimitry Andric FunctionVarLocsBuilder &FnVarLocs) { 2487bdd1243dSDimitry Andric bool MadeChanges = false; 2488bdd1243dSDimitry Andric MadeChanges |= removeRedundantDbgLocsUsingBackwardScan(BB, FnVarLocs); 2489bdd1243dSDimitry Andric if (BB->isEntryBlock()) 2490bdd1243dSDimitry Andric MadeChanges |= removeUndefDbgLocsFromEntryBlock(BB, FnVarLocs); 2491bdd1243dSDimitry Andric MadeChanges |= removeRedundantDbgLocsUsingForwardScan(BB, FnVarLocs); 2492bdd1243dSDimitry Andric 2493bdd1243dSDimitry Andric if (MadeChanges) 2494bdd1243dSDimitry Andric LLVM_DEBUG(dbgs() << "Removed redundant dbg locs from: " << BB->getName() 2495bdd1243dSDimitry Andric << "\n"); 2496bdd1243dSDimitry Andric return MadeChanges; 2497bdd1243dSDimitry Andric } 2498bdd1243dSDimitry Andric 2499bdd1243dSDimitry Andric static DenseSet<DebugAggregate> findVarsWithStackSlot(Function &Fn) { 2500bdd1243dSDimitry Andric DenseSet<DebugAggregate> Result; 2501bdd1243dSDimitry Andric for (auto &BB : Fn) { 2502bdd1243dSDimitry Andric for (auto &I : BB) { 2503bdd1243dSDimitry Andric // Any variable linked to an instruction is considered 2504bdd1243dSDimitry Andric // interesting. Ideally we only need to check Allocas, however, a 2505bdd1243dSDimitry Andric // DIAssignID might get dropped from an alloca but not stores. In that 2506bdd1243dSDimitry Andric // case, we need to consider the variable interesting for NFC behaviour 2507bdd1243dSDimitry Andric // with this change. TODO: Consider only looking at allocas. 2508bdd1243dSDimitry Andric for (DbgAssignIntrinsic *DAI : at::getAssignmentMarkers(&I)) { 2509bdd1243dSDimitry Andric Result.insert({DAI->getVariable(), DAI->getDebugLoc().getInlinedAt()}); 2510bdd1243dSDimitry Andric } 2511bdd1243dSDimitry Andric } 2512bdd1243dSDimitry Andric } 2513bdd1243dSDimitry Andric return Result; 2514bdd1243dSDimitry Andric } 2515bdd1243dSDimitry Andric 2516bdd1243dSDimitry Andric static void analyzeFunction(Function &Fn, const DataLayout &Layout, 2517bdd1243dSDimitry Andric FunctionVarLocsBuilder *FnVarLocs) { 2518bdd1243dSDimitry Andric // The analysis will generate location definitions for all variables, but we 2519bdd1243dSDimitry Andric // only need to perform a dataflow on the set of variables which have a stack 2520bdd1243dSDimitry Andric // slot. Find those now. 2521bdd1243dSDimitry Andric DenseSet<DebugAggregate> VarsWithStackSlot = findVarsWithStackSlot(Fn); 2522bdd1243dSDimitry Andric 2523bdd1243dSDimitry Andric bool Changed = false; 2524bdd1243dSDimitry Andric 2525bdd1243dSDimitry Andric // Use a scope block to clean up AssignmentTrackingLowering before running 2526bdd1243dSDimitry Andric // MemLocFragmentFill to reduce peak memory consumption. 2527bdd1243dSDimitry Andric { 2528bdd1243dSDimitry Andric AssignmentTrackingLowering Pass(Fn, Layout, &VarsWithStackSlot); 2529bdd1243dSDimitry Andric Changed = Pass.run(FnVarLocs); 2530bdd1243dSDimitry Andric } 2531bdd1243dSDimitry Andric 2532bdd1243dSDimitry Andric if (Changed) { 2533*06c3fb27SDimitry Andric MemLocFragmentFill Pass(Fn, &VarsWithStackSlot, 2534*06c3fb27SDimitry Andric shouldCoalesceFragments(Fn)); 2535bdd1243dSDimitry Andric Pass.run(FnVarLocs); 2536bdd1243dSDimitry Andric 2537bdd1243dSDimitry Andric // Remove redundant entries. As well as reducing memory consumption and 2538bdd1243dSDimitry Andric // avoiding waiting cycles later by burning some now, this has another 2539bdd1243dSDimitry Andric // important job. That is to work around some SelectionDAG quirks. See 2540bdd1243dSDimitry Andric // removeRedundantDbgLocsUsingForwardScan comments for more info on that. 2541bdd1243dSDimitry Andric for (auto &BB : Fn) 2542bdd1243dSDimitry Andric removeRedundantDbgLocs(&BB, *FnVarLocs); 2543bdd1243dSDimitry Andric } 2544bdd1243dSDimitry Andric } 2545bdd1243dSDimitry Andric 2546bdd1243dSDimitry Andric bool AssignmentTrackingAnalysis::runOnFunction(Function &F) { 2547bdd1243dSDimitry Andric if (!isAssignmentTrackingEnabled(*F.getParent())) 2548bdd1243dSDimitry Andric return false; 2549bdd1243dSDimitry Andric 2550bdd1243dSDimitry Andric LLVM_DEBUG(dbgs() << "AssignmentTrackingAnalysis run on " << F.getName() 2551bdd1243dSDimitry Andric << "\n"); 2552bdd1243dSDimitry Andric auto DL = std::make_unique<DataLayout>(F.getParent()); 2553bdd1243dSDimitry Andric 2554bdd1243dSDimitry Andric // Clear previous results. 2555bdd1243dSDimitry Andric Results->clear(); 2556bdd1243dSDimitry Andric 2557bdd1243dSDimitry Andric FunctionVarLocsBuilder Builder; 2558bdd1243dSDimitry Andric analyzeFunction(F, *DL.get(), &Builder); 2559bdd1243dSDimitry Andric 2560bdd1243dSDimitry Andric // Save these results. 2561bdd1243dSDimitry Andric Results->init(Builder); 2562bdd1243dSDimitry Andric 2563bdd1243dSDimitry Andric if (PrintResults && isFunctionInPrintList(F.getName())) 2564bdd1243dSDimitry Andric Results->print(errs(), F); 2565bdd1243dSDimitry Andric 2566bdd1243dSDimitry Andric // Return false because this pass does not modify the function. 2567bdd1243dSDimitry Andric return false; 2568bdd1243dSDimitry Andric } 2569bdd1243dSDimitry Andric 2570bdd1243dSDimitry Andric AssignmentTrackingAnalysis::AssignmentTrackingAnalysis() 2571bdd1243dSDimitry Andric : FunctionPass(ID), Results(std::make_unique<FunctionVarLocs>()) {} 2572bdd1243dSDimitry Andric 2573bdd1243dSDimitry Andric char AssignmentTrackingAnalysis::ID = 0; 2574bdd1243dSDimitry Andric 2575bdd1243dSDimitry Andric INITIALIZE_PASS(AssignmentTrackingAnalysis, DEBUG_TYPE, 2576bdd1243dSDimitry Andric "Assignment Tracking Analysis", false, true) 2577