17c71a09dSpaperchalice //===-- AssignmentTrackingAnalysis.cpp ------------------------------------===// 27c71a09dSpaperchalice // 37c71a09dSpaperchalice // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 47c71a09dSpaperchalice // See https://llvm.org/LICENSE.txt for license information. 57c71a09dSpaperchalice // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 67c71a09dSpaperchalice // 77c71a09dSpaperchalice //===----------------------------------------------------------------------===// 87c71a09dSpaperchalice 91d1de746SOCHyams #include "llvm/CodeGen/AssignmentTrackingAnalysis.h" 10d4879d76SOCHyams #include "LiveDebugValues/LiveDebugValues.h" 11d5b2c8e5SOCHyams #include "llvm/ADT/BitVector.h" 121d1de746SOCHyams #include "llvm/ADT/DenseMapInfo.h" 131d1de746SOCHyams #include "llvm/ADT/IntervalMap.h" 141d1de746SOCHyams #include "llvm/ADT/PostOrderIterator.h" 151d1de746SOCHyams #include "llvm/ADT/STLExtras.h" 161d1de746SOCHyams #include "llvm/ADT/Statistic.h" 171d1de746SOCHyams #include "llvm/ADT/UniqueVector.h" 181d1de746SOCHyams #include "llvm/BinaryFormat/Dwarf.h" 191d1de746SOCHyams #include "llvm/IR/BasicBlock.h" 201d1de746SOCHyams #include "llvm/IR/DataLayout.h" 211d1de746SOCHyams #include "llvm/IR/DebugInfo.h" 226aeb7a71SStephen Tozer #include "llvm/IR/DebugProgramInstruction.h" 231d1de746SOCHyams #include "llvm/IR/Function.h" 241d1de746SOCHyams #include "llvm/IR/Instruction.h" 251d1de746SOCHyams #include "llvm/IR/IntrinsicInst.h" 264169338eSNikita Popov #include "llvm/IR/Module.h" 271d1de746SOCHyams #include "llvm/IR/PassManager.h" 281d1de746SOCHyams #include "llvm/IR/PrintPasses.h" 291d1de746SOCHyams #include "llvm/InitializePasses.h" 301d1de746SOCHyams #include "llvm/Support/CommandLine.h" 311d1de746SOCHyams #include "llvm/Support/ErrorHandling.h" 321d1de746SOCHyams #include "llvm/Support/raw_ostream.h" 331d1de746SOCHyams #include "llvm/Transforms/Utils/BasicBlockUtils.h" 341d1de746SOCHyams #include <assert.h> 351d1de746SOCHyams #include <cstdint> 369c444f70SKazu Hirata #include <optional> 3703f05a4eSNikita Popov #include <queue> 381d1de746SOCHyams #include <sstream> 391d1de746SOCHyams #include <unordered_map> 401d1de746SOCHyams 411d1de746SOCHyams using namespace llvm; 421d1de746SOCHyams #define DEBUG_TYPE "debug-ata" 431d1de746SOCHyams 441d1de746SOCHyams STATISTIC(NumDefsScanned, "Number of dbg locs that get scanned for removal"); 451d1de746SOCHyams STATISTIC(NumDefsRemoved, "Number of dbg locs removed"); 461d1de746SOCHyams STATISTIC(NumWedgesScanned, "Number of dbg wedges scanned"); 471d1de746SOCHyams STATISTIC(NumWedgesChanged, "Number of dbg wedges changed"); 481d1de746SOCHyams 491d1de746SOCHyams static cl::opt<unsigned> 501d1de746SOCHyams MaxNumBlocks("debug-ata-max-blocks", cl::init(10000), 511d1de746SOCHyams cl::desc("Maximum num basic blocks before debug info dropped"), 521d1de746SOCHyams cl::Hidden); 531d1de746SOCHyams /// Option for debugging the pass, determines if the memory location fragment 541d1de746SOCHyams /// filling happens after generating the variable locations. 551d1de746SOCHyams static cl::opt<bool> EnableMemLocFragFill("mem-loc-frag-fill", cl::init(true), 561d1de746SOCHyams cl::Hidden); 571d1de746SOCHyams /// Print the results of the analysis. Respects -filter-print-funcs. 581d1de746SOCHyams static cl::opt<bool> PrintResults("print-debug-ata", cl::init(false), 591d1de746SOCHyams cl::Hidden); 601d1de746SOCHyams 61d4879d76SOCHyams /// Coalesce adjacent dbg locs describing memory locations that have contiguous 62d4879d76SOCHyams /// fragments. This reduces the cost of LiveDebugValues which does SSA 63d4879d76SOCHyams /// construction for each explicitly stated variable fragment. 64d4879d76SOCHyams static cl::opt<cl::boolOrDefault> 65d4879d76SOCHyams CoalesceAdjacentFragmentsOpt("debug-ata-coalesce-frags", cl::Hidden); 66d4879d76SOCHyams 671d1de746SOCHyams // Implicit conversions are disabled for enum class types, so unfortunately we 681d1de746SOCHyams // need to create a DenseMapInfo wrapper around the specified underlying type. 691d1de746SOCHyams template <> struct llvm::DenseMapInfo<VariableID> { 701d1de746SOCHyams using Wrapped = DenseMapInfo<unsigned>; 711d1de746SOCHyams static inline VariableID getEmptyKey() { 721d1de746SOCHyams return static_cast<VariableID>(Wrapped::getEmptyKey()); 731d1de746SOCHyams } 741d1de746SOCHyams static inline VariableID getTombstoneKey() { 751d1de746SOCHyams return static_cast<VariableID>(Wrapped::getTombstoneKey()); 761d1de746SOCHyams } 771d1de746SOCHyams static unsigned getHashValue(const VariableID &Val) { 781d1de746SOCHyams return Wrapped::getHashValue(static_cast<unsigned>(Val)); 791d1de746SOCHyams } 801d1de746SOCHyams static bool isEqual(const VariableID &LHS, const VariableID &RHS) { 811d1de746SOCHyams return LHS == RHS; 821d1de746SOCHyams } 831d1de746SOCHyams }; 841d1de746SOCHyams 85ababa964SOrlando Cazalet-Hyams using VarLocInsertPt = PointerUnion<const Instruction *, const DbgRecord *>; 866aeb7a71SStephen Tozer 876aeb7a71SStephen Tozer namespace std { 886aeb7a71SStephen Tozer template <> struct hash<VarLocInsertPt> { 896aeb7a71SStephen Tozer using argument_type = VarLocInsertPt; 906aeb7a71SStephen Tozer using result_type = std::size_t; 916aeb7a71SStephen Tozer 926aeb7a71SStephen Tozer result_type operator()(const argument_type &Arg) const { 936aeb7a71SStephen Tozer return std::hash<void *>()(Arg.getOpaqueValue()); 946aeb7a71SStephen Tozer } 956aeb7a71SStephen Tozer }; 966aeb7a71SStephen Tozer } // namespace std 976aeb7a71SStephen Tozer 981d1de746SOCHyams /// Helper class to build FunctionVarLocs, since that class isn't easy to 991d1de746SOCHyams /// modify. TODO: There's not a great deal of value in the split, it could be 1001d1de746SOCHyams /// worth merging the two classes. 1011d1de746SOCHyams class FunctionVarLocsBuilder { 1021d1de746SOCHyams friend FunctionVarLocs; 1031d1de746SOCHyams UniqueVector<DebugVariable> Variables; 1041d1de746SOCHyams // Use an unordered_map so we don't invalidate iterators after 1051d1de746SOCHyams // insert/modifications. 1066aeb7a71SStephen Tozer std::unordered_map<VarLocInsertPt, SmallVector<VarLocInfo>> VarLocsBeforeInst; 1071d1de746SOCHyams 1081d1de746SOCHyams SmallVector<VarLocInfo> SingleLocVars; 1091d1de746SOCHyams 1101d1de746SOCHyams public: 111d5b2c8e5SOCHyams unsigned getNumVariables() const { return Variables.size(); } 112d5b2c8e5SOCHyams 1131d1de746SOCHyams /// Find or insert \p V and return the ID. 1141d1de746SOCHyams VariableID insertVariable(DebugVariable V) { 1151d1de746SOCHyams return static_cast<VariableID>(Variables.insert(V)); 1161d1de746SOCHyams } 1171d1de746SOCHyams 1181d1de746SOCHyams /// Get a variable from its \p ID. 1191d1de746SOCHyams const DebugVariable &getVariable(VariableID ID) const { 1201d1de746SOCHyams return Variables[static_cast<unsigned>(ID)]; 1211d1de746SOCHyams } 1221d1de746SOCHyams 1231d1de746SOCHyams /// Return ptr to wedge of defs or nullptr if no defs come just before /p 1241d1de746SOCHyams /// Before. 1256aeb7a71SStephen Tozer const SmallVectorImpl<VarLocInfo> *getWedge(VarLocInsertPt Before) const { 1261d1de746SOCHyams auto R = VarLocsBeforeInst.find(Before); 1271d1de746SOCHyams if (R == VarLocsBeforeInst.end()) 1281d1de746SOCHyams return nullptr; 1291d1de746SOCHyams return &R->second; 1301d1de746SOCHyams } 1311d1de746SOCHyams 1321d1de746SOCHyams /// Replace the defs that come just before /p Before with /p Wedge. 1336aeb7a71SStephen Tozer void setWedge(VarLocInsertPt Before, SmallVector<VarLocInfo> &&Wedge) { 1341d1de746SOCHyams VarLocsBeforeInst[Before] = std::move(Wedge); 1351d1de746SOCHyams } 1361d1de746SOCHyams 1371d1de746SOCHyams /// Add a def for a variable that is valid for its lifetime. 1381d1de746SOCHyams void addSingleLocVar(DebugVariable Var, DIExpression *Expr, DebugLoc DL, 1397d894374SOCHyams RawLocationWrapper R) { 1401d1de746SOCHyams VarLocInfo VarLoc; 1411d1de746SOCHyams VarLoc.VariableID = insertVariable(Var); 1421d1de746SOCHyams VarLoc.Expr = Expr; 1431d1de746SOCHyams VarLoc.DL = DL; 1447d894374SOCHyams VarLoc.Values = R; 1451d1de746SOCHyams SingleLocVars.emplace_back(VarLoc); 1461d1de746SOCHyams } 1471d1de746SOCHyams 1481d1de746SOCHyams /// Add a def to the wedge of defs just before /p Before. 1496aeb7a71SStephen Tozer void addVarLoc(VarLocInsertPt Before, DebugVariable Var, DIExpression *Expr, 1507d894374SOCHyams DebugLoc DL, RawLocationWrapper R) { 1511d1de746SOCHyams VarLocInfo VarLoc; 1521d1de746SOCHyams VarLoc.VariableID = insertVariable(Var); 1531d1de746SOCHyams VarLoc.Expr = Expr; 1541d1de746SOCHyams VarLoc.DL = DL; 1557d894374SOCHyams VarLoc.Values = R; 1561d1de746SOCHyams VarLocsBeforeInst[Before].emplace_back(VarLoc); 1571d1de746SOCHyams } 1581d1de746SOCHyams }; 1591d1de746SOCHyams 1601d1de746SOCHyams void FunctionVarLocs::print(raw_ostream &OS, const Function &Fn) const { 1611d1de746SOCHyams // Print the variable table first. TODO: Sorting by variable could make the 1621d1de746SOCHyams // output more stable? 1631d1de746SOCHyams unsigned Counter = -1; 1641d1de746SOCHyams OS << "=== Variables ===\n"; 1651d1de746SOCHyams for (const DebugVariable &V : Variables) { 1661d1de746SOCHyams ++Counter; 1671d1de746SOCHyams // Skip first entry because it is a dummy entry. 1681d1de746SOCHyams if (Counter == 0) { 1691d1de746SOCHyams continue; 1701d1de746SOCHyams } 1711d1de746SOCHyams OS << "[" << Counter << "] " << V.getVariable()->getName(); 1721d1de746SOCHyams if (auto F = V.getFragment()) 1731d1de746SOCHyams OS << " bits [" << F->OffsetInBits << ", " 1741d1de746SOCHyams << F->OffsetInBits + F->SizeInBits << ")"; 1751d1de746SOCHyams if (const auto *IA = V.getInlinedAt()) 1761d1de746SOCHyams OS << " inlined-at " << *IA; 1771d1de746SOCHyams OS << "\n"; 1781d1de746SOCHyams } 1791d1de746SOCHyams 1801d1de746SOCHyams auto PrintLoc = [&OS](const VarLocInfo &Loc) { 1811d1de746SOCHyams OS << "DEF Var=[" << (unsigned)Loc.VariableID << "]" 1827d894374SOCHyams << " Expr=" << *Loc.Expr << " Values=("; 1837d894374SOCHyams for (auto *Op : Loc.Values.location_ops()) { 1847d894374SOCHyams errs() << Op->getName() << " "; 1857d894374SOCHyams } 1867d894374SOCHyams errs() << ")\n"; 1871d1de746SOCHyams }; 1881d1de746SOCHyams 1891d1de746SOCHyams // Print the single location variables. 1901d1de746SOCHyams OS << "=== Single location vars ===\n"; 1911d1de746SOCHyams for (auto It = single_locs_begin(), End = single_locs_end(); It != End; 1921d1de746SOCHyams ++It) { 1931d1de746SOCHyams PrintLoc(*It); 1941d1de746SOCHyams } 1951d1de746SOCHyams 1961d1de746SOCHyams // Print the non-single-location defs in line with IR. 1971d1de746SOCHyams OS << "=== In-line variable defs ==="; 1981d1de746SOCHyams for (const BasicBlock &BB : Fn) { 1991d1de746SOCHyams OS << "\n" << BB.getName() << ":\n"; 2001d1de746SOCHyams for (const Instruction &I : BB) { 2011d1de746SOCHyams for (auto It = locs_begin(&I), End = locs_end(&I); It != End; ++It) { 2021d1de746SOCHyams PrintLoc(*It); 2031d1de746SOCHyams } 2041d1de746SOCHyams OS << I << "\n"; 2051d1de746SOCHyams } 2061d1de746SOCHyams } 2071d1de746SOCHyams } 2081d1de746SOCHyams 2091d1de746SOCHyams void FunctionVarLocs::init(FunctionVarLocsBuilder &Builder) { 2101d1de746SOCHyams // Add the single-location variables first. 2111d1de746SOCHyams for (const auto &VarLoc : Builder.SingleLocVars) 2121d1de746SOCHyams VarLocRecords.emplace_back(VarLoc); 2131d1de746SOCHyams // Mark the end of the section. 2141d1de746SOCHyams SingleVarLocEnd = VarLocRecords.size(); 2151d1de746SOCHyams 2161d1de746SOCHyams // Insert a contiguous block of VarLocInfos for each instruction, mapping it 2176aeb7a71SStephen Tozer // to the start and end position in the vector with VarLocsBeforeInst. This 218ffd08c77SStephen Tozer // block includes VarLocs for any DbgVariableRecords attached to that 219ffd08c77SStephen Tozer // instruction. 2201d1de746SOCHyams for (auto &P : Builder.VarLocsBeforeInst) { 221360da838SStephen Tozer // Process VarLocs attached to a DbgRecord alongside their marker 222360da838SStephen Tozer // Instruction. 223ababa964SOrlando Cazalet-Hyams if (isa<const DbgRecord *>(P.first)) 2246aeb7a71SStephen Tozer continue; 2256aeb7a71SStephen Tozer const Instruction *I = cast<const Instruction *>(P.first); 2261d1de746SOCHyams unsigned BlockStart = VarLocRecords.size(); 227360da838SStephen Tozer // Any VarLocInfos attached to a DbgRecord should now be remapped to their 228360da838SStephen Tozer // marker Instruction, in order of DbgRecord appearance and prior to any 2296aeb7a71SStephen Tozer // VarLocInfos attached directly to that instruction. 230ffd08c77SStephen Tozer for (const DbgVariableRecord &DVR : filterDbgVars(I->getDbgRecordRange())) { 231ffd08c77SStephen Tozer // Even though DVR defines a variable location, VarLocsBeforeInst can 2326aeb7a71SStephen Tozer // still be empty if that VarLoc was redundant. 233*c5312553SKazu Hirata auto It = Builder.VarLocsBeforeInst.find(&DVR); 234*c5312553SKazu Hirata if (It == Builder.VarLocsBeforeInst.end()) 2356aeb7a71SStephen Tozer continue; 236*c5312553SKazu Hirata for (const VarLocInfo &VarLoc : It->second) 2376aeb7a71SStephen Tozer VarLocRecords.emplace_back(VarLoc); 2386aeb7a71SStephen Tozer } 2391d1de746SOCHyams for (const VarLocInfo &VarLoc : P.second) 2401d1de746SOCHyams VarLocRecords.emplace_back(VarLoc); 2411d1de746SOCHyams unsigned BlockEnd = VarLocRecords.size(); 2421d1de746SOCHyams // Record the start and end indices. 2431d1de746SOCHyams if (BlockEnd != BlockStart) 2446aeb7a71SStephen Tozer VarLocsBeforeInst[I] = {BlockStart, BlockEnd}; 2451d1de746SOCHyams } 2461d1de746SOCHyams 2471d1de746SOCHyams // Copy the Variables vector from the builder's UniqueVector. 2481d1de746SOCHyams assert(Variables.empty() && "Expect clear before init"); 2491d1de746SOCHyams // UniqueVectors IDs are one-based (which means the VarLocInfo VarID values 2501d1de746SOCHyams // are one-based) so reserve an extra and insert a dummy. 2511d1de746SOCHyams Variables.reserve(Builder.Variables.size() + 1); 2529c444f70SKazu Hirata Variables.push_back(DebugVariable(nullptr, std::nullopt, nullptr)); 2531d1de746SOCHyams Variables.append(Builder.Variables.begin(), Builder.Variables.end()); 2541d1de746SOCHyams } 2551d1de746SOCHyams 2561d1de746SOCHyams void FunctionVarLocs::clear() { 2571d1de746SOCHyams Variables.clear(); 2581d1de746SOCHyams VarLocRecords.clear(); 2591d1de746SOCHyams VarLocsBeforeInst.clear(); 2601d1de746SOCHyams SingleVarLocEnd = 0; 2611d1de746SOCHyams } 2621d1de746SOCHyams 2631d1de746SOCHyams /// Walk backwards along constant GEPs and bitcasts to the base storage from \p 2641d1de746SOCHyams /// Start as far as possible. Prepend \Expression with the offset and append it 2651d1de746SOCHyams /// with a DW_OP_deref that haes been implicit until now. Returns the walked-to 2661d1de746SOCHyams /// value and modified expression. 2671d1de746SOCHyams static std::pair<Value *, DIExpression *> 2681d1de746SOCHyams walkToAllocaAndPrependOffsetDeref(const DataLayout &DL, Value *Start, 2691d1de746SOCHyams DIExpression *Expression) { 2701d1de746SOCHyams APInt OffsetInBytes(DL.getTypeSizeInBits(Start->getType()), false); 2711d1de746SOCHyams Value *End = 2721d1de746SOCHyams Start->stripAndAccumulateInBoundsConstantOffsets(DL, OffsetInBytes); 2731d1de746SOCHyams SmallVector<uint64_t, 3> Ops; 2741d1de746SOCHyams if (OffsetInBytes.getBoolValue()) { 2751d1de746SOCHyams Ops = {dwarf::DW_OP_plus_uconst, OffsetInBytes.getZExtValue()}; 2761d1de746SOCHyams Expression = DIExpression::prependOpcodes( 2771d1de746SOCHyams Expression, Ops, /*StackValue=*/false, /*EntryValue=*/false); 2781d1de746SOCHyams } 2791d1de746SOCHyams Expression = DIExpression::append(Expression, {dwarf::DW_OP_deref}); 2801d1de746SOCHyams return {End, Expression}; 2811d1de746SOCHyams } 2821d1de746SOCHyams 2833eebbaf0SKazu Hirata /// Extract the offset used in \p DIExpr. Returns std::nullopt if the expression 2841d1de746SOCHyams /// doesn't explicitly describe a memory location with DW_OP_deref or if the 2851d1de746SOCHyams /// expression is too complex to interpret. 28667819a72SFangrui Song static std::optional<int64_t> 28767819a72SFangrui Song getDerefOffsetInBytes(const DIExpression *DIExpr) { 2881d1de746SOCHyams int64_t Offset = 0; 2891d1de746SOCHyams const unsigned NumElements = DIExpr->getNumElements(); 2901d1de746SOCHyams const auto Elements = DIExpr->getElements(); 29125d0f3c4SOCHyams unsigned ExpectedDerefIdx = 0; 2921d1de746SOCHyams // Extract the offset. 2931d1de746SOCHyams if (NumElements > 2 && Elements[0] == dwarf::DW_OP_plus_uconst) { 2941d1de746SOCHyams Offset = Elements[1]; 29525d0f3c4SOCHyams ExpectedDerefIdx = 2; 2961d1de746SOCHyams } else if (NumElements > 3 && Elements[0] == dwarf::DW_OP_constu) { 29725d0f3c4SOCHyams ExpectedDerefIdx = 3; 2981d1de746SOCHyams if (Elements[2] == dwarf::DW_OP_plus) 2991d1de746SOCHyams Offset = Elements[1]; 3001d1de746SOCHyams else if (Elements[2] == dwarf::DW_OP_minus) 3011d1de746SOCHyams Offset = -Elements[1]; 3021d1de746SOCHyams else 3039c444f70SKazu Hirata return std::nullopt; 3041d1de746SOCHyams } 3051d1de746SOCHyams 3061d1de746SOCHyams // If that's all there is it means there's no deref. 30725d0f3c4SOCHyams if (ExpectedDerefIdx >= NumElements) 3089c444f70SKazu Hirata return std::nullopt; 3091d1de746SOCHyams 3101d1de746SOCHyams // Check the next element is DW_OP_deref - otherwise this is too complex or 3111d1de746SOCHyams // isn't a deref expression. 31225d0f3c4SOCHyams if (Elements[ExpectedDerefIdx] != dwarf::DW_OP_deref) 3139c444f70SKazu Hirata return std::nullopt; 3141d1de746SOCHyams 3151d1de746SOCHyams // Check the final operation is either the DW_OP_deref or is a fragment. 31625d0f3c4SOCHyams if (NumElements == ExpectedDerefIdx + 1) 3171d1de746SOCHyams return Offset; // Ends with deref. 31825d0f3c4SOCHyams unsigned ExpectedFragFirstIdx = ExpectedDerefIdx + 1; 31925d0f3c4SOCHyams unsigned ExpectedFragFinalIdx = ExpectedFragFirstIdx + 2; 32025d0f3c4SOCHyams if (NumElements == ExpectedFragFinalIdx + 1 && 32125d0f3c4SOCHyams Elements[ExpectedFragFirstIdx] == dwarf::DW_OP_LLVM_fragment) 3221d1de746SOCHyams return Offset; // Ends with deref + fragment. 3231d1de746SOCHyams 3241d1de746SOCHyams // Don't bother trying to interpret anything more complex. 3259c444f70SKazu Hirata return std::nullopt; 3261d1de746SOCHyams } 3271d1de746SOCHyams 3281d1de746SOCHyams /// A whole (unfragmented) source variable. 3291d1de746SOCHyams using DebugAggregate = std::pair<const DILocalVariable *, const DILocation *>; 3301d1de746SOCHyams static DebugAggregate getAggregate(const DbgVariableIntrinsic *DII) { 3311d1de746SOCHyams return DebugAggregate(DII->getVariable(), DII->getDebugLoc().getInlinedAt()); 3321d1de746SOCHyams } 3331d1de746SOCHyams static DebugAggregate getAggregate(const DebugVariable &Var) { 3341d1de746SOCHyams return DebugAggregate(Var.getVariable(), Var.getInlinedAt()); 3351d1de746SOCHyams } 3361d1de746SOCHyams 337d4879d76SOCHyams static bool shouldCoalesceFragments(Function &F) { 338d4879d76SOCHyams // Enabling fragment coalescing reduces compiler run time when instruction 339d4879d76SOCHyams // referencing is enabled. However, it may cause LiveDebugVariables to create 340d4879d76SOCHyams // incorrect locations. Since instruction-referencing mode effectively 341d4879d76SOCHyams // bypasses LiveDebugVariables we only enable coalescing if the cl::opt flag 342d4879d76SOCHyams // has not been explicitly set and instruction-referencing is turned on. 343d4879d76SOCHyams switch (CoalesceAdjacentFragmentsOpt) { 344d4879d76SOCHyams case cl::boolOrDefault::BOU_UNSET: 345d4879d76SOCHyams return debuginfoShouldUseDebugInstrRef( 346d4879d76SOCHyams Triple(F.getParent()->getTargetTriple())); 347d4879d76SOCHyams case cl::boolOrDefault::BOU_TRUE: 348d4879d76SOCHyams return true; 349d4879d76SOCHyams case cl::boolOrDefault::BOU_FALSE: 350d4879d76SOCHyams return false; 351d4879d76SOCHyams } 352d4879d76SOCHyams llvm_unreachable("Unknown boolOrDefault value"); 353d4879d76SOCHyams } 354d4879d76SOCHyams 355b6942a28SBenjamin Kramer namespace { 3561d1de746SOCHyams /// In dwarf emission, the following sequence 3571d1de746SOCHyams /// 1. dbg.value ... Fragment(0, 64) 3581d1de746SOCHyams /// 2. dbg.value ... Fragment(0, 32) 3591d1de746SOCHyams /// effectively sets Fragment(32, 32) to undef (each def sets all bits not in 3601d1de746SOCHyams /// the intersection of the fragments to having "no location"). This makes 3611d1de746SOCHyams /// sense for implicit location values because splitting the computed values 3621d1de746SOCHyams /// could be troublesome, and is probably quite uncommon. When we convert 3631d1de746SOCHyams /// dbg.assigns to dbg.value+deref this kind of thing is common, and describing 3641d1de746SOCHyams /// a location (memory) rather than a value means we don't need to worry about 3651d1de746SOCHyams /// splitting any values, so we try to recover the rest of the fragment 3661d1de746SOCHyams /// location here. 3671d1de746SOCHyams /// This class performs a(nother) dataflow analysis over the function, adding 3681d1de746SOCHyams /// variable locations so that any bits of a variable with a memory location 3691d1de746SOCHyams /// have that location explicitly reinstated at each subsequent variable 3701d1de746SOCHyams /// location definition that that doesn't overwrite those bits. i.e. after a 3711d1de746SOCHyams /// variable location def, insert new defs for the memory location with 3721d1de746SOCHyams /// fragments for the difference of "all bits currently in memory" and "the 3731d1de746SOCHyams /// fragment of the second def". 3741d1de746SOCHyams class MemLocFragmentFill { 3751d1de746SOCHyams Function &Fn; 3761d1de746SOCHyams FunctionVarLocsBuilder *FnVarLocs; 3771d1de746SOCHyams const DenseSet<DebugAggregate> *VarsWithStackSlot; 378d4879d76SOCHyams bool CoalesceAdjacentFragments; 3791d1de746SOCHyams 3801d1de746SOCHyams // 0 = no memory location. 3811d1de746SOCHyams using BaseAddress = unsigned; 3821d1de746SOCHyams using OffsetInBitsTy = unsigned; 3831d1de746SOCHyams using FragTraits = IntervalMapHalfOpenInfo<OffsetInBitsTy>; 3841d1de746SOCHyams using FragsInMemMap = IntervalMap< 3851d1de746SOCHyams OffsetInBitsTy, BaseAddress, 3861d1de746SOCHyams IntervalMapImpl::NodeSizer<OffsetInBitsTy, BaseAddress>::LeafSize, 3871d1de746SOCHyams FragTraits>; 3881d1de746SOCHyams FragsInMemMap::Allocator IntervalMapAlloc; 3891d1de746SOCHyams using VarFragMap = DenseMap<unsigned, FragsInMemMap>; 3901d1de746SOCHyams 3911d1de746SOCHyams /// IDs for memory location base addresses in maps. Use 0 to indicate that 3921d1de746SOCHyams /// there's no memory location. 3937d894374SOCHyams UniqueVector<RawLocationWrapper> Bases; 3941d1de746SOCHyams UniqueVector<DebugAggregate> Aggregates; 3951d1de746SOCHyams DenseMap<const BasicBlock *, VarFragMap> LiveIn; 3961d1de746SOCHyams DenseMap<const BasicBlock *, VarFragMap> LiveOut; 3971d1de746SOCHyams 3981d1de746SOCHyams struct FragMemLoc { 3991d1de746SOCHyams unsigned Var; 4001d1de746SOCHyams unsigned Base; 4011d1de746SOCHyams unsigned OffsetInBits; 4021d1de746SOCHyams unsigned SizeInBits; 4031d1de746SOCHyams DebugLoc DL; 4041d1de746SOCHyams }; 4056aeb7a71SStephen Tozer using InsertMap = MapVector<VarLocInsertPt, SmallVector<FragMemLoc>>; 4061d1de746SOCHyams 4071d1de746SOCHyams /// BBInsertBeforeMap holds a description for the set of location defs to be 4081d1de746SOCHyams /// inserted after the analysis is complete. It is updated during the dataflow 4091d1de746SOCHyams /// and the entry for a block is CLEARED each time it is (re-)visited. After 4101d1de746SOCHyams /// the dataflow is complete, each block entry will contain the set of defs 4111d1de746SOCHyams /// calculated during the final (fixed-point) iteration. 4121d1de746SOCHyams DenseMap<const BasicBlock *, InsertMap> BBInsertBeforeMap; 4131d1de746SOCHyams 4141d1de746SOCHyams static bool intervalMapsAreEqual(const FragsInMemMap &A, 4151d1de746SOCHyams const FragsInMemMap &B) { 4161d1de746SOCHyams auto AIt = A.begin(), AEnd = A.end(); 4171d1de746SOCHyams auto BIt = B.begin(), BEnd = B.end(); 4181d1de746SOCHyams for (; AIt != AEnd; ++AIt, ++BIt) { 4191d1de746SOCHyams if (BIt == BEnd) 4201d1de746SOCHyams return false; // B has fewer elements than A. 4211d1de746SOCHyams if (AIt.start() != BIt.start() || AIt.stop() != BIt.stop()) 4221d1de746SOCHyams return false; // Interval is different. 42351b68573SFangrui Song if (*AIt != *BIt) 4241d1de746SOCHyams return false; // Value at interval is different. 4251d1de746SOCHyams } 4261d1de746SOCHyams // AIt == AEnd. Check BIt is also now at end. 4271d1de746SOCHyams return BIt == BEnd; 4281d1de746SOCHyams } 4291d1de746SOCHyams 4301d1de746SOCHyams static bool varFragMapsAreEqual(const VarFragMap &A, const VarFragMap &B) { 4311d1de746SOCHyams if (A.size() != B.size()) 4321d1de746SOCHyams return false; 4331d1de746SOCHyams for (const auto &APair : A) { 4341d1de746SOCHyams auto BIt = B.find(APair.first); 4351d1de746SOCHyams if (BIt == B.end()) 4361d1de746SOCHyams return false; 4371d1de746SOCHyams if (!intervalMapsAreEqual(APair.second, BIt->second)) 4381d1de746SOCHyams return false; 4391d1de746SOCHyams } 4401d1de746SOCHyams return true; 4411d1de746SOCHyams } 4421d1de746SOCHyams 4431d1de746SOCHyams /// Return a string for the value that \p BaseID represents. 4441d1de746SOCHyams std::string toString(unsigned BaseID) { 4451d1de746SOCHyams if (BaseID) 4467d894374SOCHyams return Bases[BaseID].getVariableLocationOp(0)->getName().str(); 4471d1de746SOCHyams else 4481d1de746SOCHyams return "None"; 4491d1de746SOCHyams } 4501d1de746SOCHyams 4511d1de746SOCHyams /// Format string describing an FragsInMemMap (IntervalMap) interval. 4521d1de746SOCHyams std::string toString(FragsInMemMap::const_iterator It, bool Newline = true) { 4531d1de746SOCHyams std::string String; 4541d1de746SOCHyams std::stringstream S(String); 4551d1de746SOCHyams if (It.valid()) { 4561d1de746SOCHyams S << "[" << It.start() << ", " << It.stop() 4571d1de746SOCHyams << "): " << toString(It.value()); 4581d1de746SOCHyams } else { 4591d1de746SOCHyams S << "invalid iterator (end)"; 4601d1de746SOCHyams } 4611d1de746SOCHyams if (Newline) 4621d1de746SOCHyams S << "\n"; 4631d1de746SOCHyams return S.str(); 4641d1de746SOCHyams }; 4651d1de746SOCHyams 4661d1de746SOCHyams FragsInMemMap meetFragments(const FragsInMemMap &A, const FragsInMemMap &B) { 4671d1de746SOCHyams FragsInMemMap Result(IntervalMapAlloc); 4681d1de746SOCHyams for (auto AIt = A.begin(), AEnd = A.end(); AIt != AEnd; ++AIt) { 4691d1de746SOCHyams LLVM_DEBUG(dbgs() << "a " << toString(AIt)); 4701d1de746SOCHyams // This is basically copied from process() and inverted (process is 4711d1de746SOCHyams // performing something like a union whereas this is more of an 4721d1de746SOCHyams // intersect). 4731d1de746SOCHyams 4741d1de746SOCHyams // There's no work to do if interval `a` overlaps no fragments in map `B`. 4751d1de746SOCHyams if (!B.overlaps(AIt.start(), AIt.stop())) 4761d1de746SOCHyams continue; 4771d1de746SOCHyams 4781d1de746SOCHyams // Does StartBit intersect an existing fragment? 4791d1de746SOCHyams auto FirstOverlap = B.find(AIt.start()); 4801d1de746SOCHyams assert(FirstOverlap != B.end()); 4811d1de746SOCHyams bool IntersectStart = FirstOverlap.start() < AIt.start(); 4821d1de746SOCHyams LLVM_DEBUG(dbgs() << "- FirstOverlap " << toString(FirstOverlap, false) 4831d1de746SOCHyams << ", IntersectStart: " << IntersectStart << "\n"); 4841d1de746SOCHyams 4851d1de746SOCHyams // Does EndBit intersect an existing fragment? 4861d1de746SOCHyams auto LastOverlap = B.find(AIt.stop()); 4871d1de746SOCHyams bool IntersectEnd = 4881d1de746SOCHyams LastOverlap != B.end() && LastOverlap.start() < AIt.stop(); 4891d1de746SOCHyams LLVM_DEBUG(dbgs() << "- LastOverlap " << toString(LastOverlap, false) 4901d1de746SOCHyams << ", IntersectEnd: " << IntersectEnd << "\n"); 4911d1de746SOCHyams 4921d1de746SOCHyams // Check if both ends of `a` intersect the same interval `b`. 4931d1de746SOCHyams if (IntersectStart && IntersectEnd && FirstOverlap == LastOverlap) { 4941d1de746SOCHyams // Insert `a` (`a` is contained in `b`) if the values match. 4951d1de746SOCHyams // [ a ] 4961d1de746SOCHyams // [ - b - ] 4971d1de746SOCHyams // - 4981d1de746SOCHyams // [ r ] 4991d1de746SOCHyams LLVM_DEBUG(dbgs() << "- a is contained within " 5001d1de746SOCHyams << toString(FirstOverlap)); 50151b68573SFangrui Song if (*AIt && *AIt == *FirstOverlap) 50251b68573SFangrui Song Result.insert(AIt.start(), AIt.stop(), *AIt); 5031d1de746SOCHyams } else { 5041d1de746SOCHyams // There's an overlap but `a` is not fully contained within 5051d1de746SOCHyams // `b`. Shorten any end-point intersections. 5061d1de746SOCHyams // [ - a - ] 5071d1de746SOCHyams // [ - b - ] 5081d1de746SOCHyams // - 5091d1de746SOCHyams // [ r ] 5101d1de746SOCHyams auto Next = FirstOverlap; 5111d1de746SOCHyams if (IntersectStart) { 5121d1de746SOCHyams LLVM_DEBUG(dbgs() << "- insert intersection of a and " 5131d1de746SOCHyams << toString(FirstOverlap)); 51451b68573SFangrui Song if (*AIt && *AIt == *FirstOverlap) 51551b68573SFangrui Song Result.insert(AIt.start(), FirstOverlap.stop(), *AIt); 5161d1de746SOCHyams ++Next; 5171d1de746SOCHyams } 5181d1de746SOCHyams // [ - a - ] 5191d1de746SOCHyams // [ - b - ] 5201d1de746SOCHyams // - 5211d1de746SOCHyams // [ r ] 5221d1de746SOCHyams if (IntersectEnd) { 5231d1de746SOCHyams LLVM_DEBUG(dbgs() << "- insert intersection of a and " 5241d1de746SOCHyams << toString(LastOverlap)); 52551b68573SFangrui Song if (*AIt && *AIt == *LastOverlap) 52651b68573SFangrui Song Result.insert(LastOverlap.start(), AIt.stop(), *AIt); 5271d1de746SOCHyams } 5281d1de746SOCHyams 5291d1de746SOCHyams // Insert all intervals in map `B` that are contained within interval 5301d1de746SOCHyams // `a` where the values match. 5311d1de746SOCHyams // [ - - a - - ] 5321d1de746SOCHyams // [ b1 ] [ b2 ] 5331d1de746SOCHyams // - 5341d1de746SOCHyams // [ r1 ] [ r2 ] 5351d1de746SOCHyams while (Next != B.end() && Next.start() < AIt.stop() && 5361d1de746SOCHyams Next.stop() <= AIt.stop()) { 5371d1de746SOCHyams LLVM_DEBUG(dbgs() 5381d1de746SOCHyams << "- insert intersection of a and " << toString(Next)); 53951b68573SFangrui Song if (*AIt && *AIt == *Next) 54051b68573SFangrui Song Result.insert(Next.start(), Next.stop(), *Next); 5411d1de746SOCHyams ++Next; 5421d1de746SOCHyams } 5431d1de746SOCHyams } 5441d1de746SOCHyams } 5451d1de746SOCHyams return Result; 5461d1de746SOCHyams } 5471d1de746SOCHyams 5481d1de746SOCHyams /// Meet \p A and \p B, storing the result in \p A. 5491d1de746SOCHyams void meetVars(VarFragMap &A, const VarFragMap &B) { 5501d1de746SOCHyams // Meet A and B. 5511d1de746SOCHyams // 5521d1de746SOCHyams // Result = meet(a, b) for a in A, b in B where Var(a) == Var(b) 5531d1de746SOCHyams for (auto It = A.begin(), End = A.end(); It != End; ++It) { 5541d1de746SOCHyams unsigned AVar = It->first; 5551d1de746SOCHyams FragsInMemMap &AFrags = It->second; 5561d1de746SOCHyams auto BIt = B.find(AVar); 5571d1de746SOCHyams if (BIt == B.end()) { 5581d1de746SOCHyams A.erase(It); 5591d1de746SOCHyams continue; // Var has no bits defined in B. 5601d1de746SOCHyams } 5611d1de746SOCHyams LLVM_DEBUG(dbgs() << "meet fragment maps for " 5621d1de746SOCHyams << Aggregates[AVar].first->getName() << "\n"); 5631d1de746SOCHyams AFrags = meetFragments(AFrags, BIt->second); 5641d1de746SOCHyams } 5651d1de746SOCHyams } 5661d1de746SOCHyams 5671d1de746SOCHyams bool meet(const BasicBlock &BB, 5681d1de746SOCHyams const SmallPtrSet<BasicBlock *, 16> &Visited) { 5691d1de746SOCHyams LLVM_DEBUG(dbgs() << "meet block info from preds of " << BB.getName() 5701d1de746SOCHyams << "\n"); 5711d1de746SOCHyams 5721d1de746SOCHyams VarFragMap BBLiveIn; 5731d1de746SOCHyams bool FirstMeet = true; 5741d1de746SOCHyams // LiveIn locs for BB is the meet of the already-processed preds' LiveOut 5751d1de746SOCHyams // locs. 5763641efcfSKazu Hirata for (const BasicBlock *Pred : predecessors(&BB)) { 5771d1de746SOCHyams // Ignore preds that haven't been processed yet. This is essentially the 5781d1de746SOCHyams // same as initialising all variables to implicit top value (⊤) which is 5791d1de746SOCHyams // the identity value for the meet operation. 5801d1de746SOCHyams if (!Visited.count(Pred)) 5811d1de746SOCHyams continue; 5821d1de746SOCHyams 5831d1de746SOCHyams auto PredLiveOut = LiveOut.find(Pred); 5841d1de746SOCHyams assert(PredLiveOut != LiveOut.end()); 5851d1de746SOCHyams 5861d1de746SOCHyams if (FirstMeet) { 5871d1de746SOCHyams LLVM_DEBUG(dbgs() << "BBLiveIn = " << Pred->getName() << "\n"); 5881d1de746SOCHyams BBLiveIn = PredLiveOut->second; 5891d1de746SOCHyams FirstMeet = false; 5901d1de746SOCHyams } else { 5911d1de746SOCHyams LLVM_DEBUG(dbgs() << "BBLiveIn = meet BBLiveIn, " << Pred->getName() 5921d1de746SOCHyams << "\n"); 5931d1de746SOCHyams meetVars(BBLiveIn, PredLiveOut->second); 5941d1de746SOCHyams } 5951d1de746SOCHyams 5961d1de746SOCHyams // An empty set is ⊥ for the intersect-like meet operation. If we've 5971d1de746SOCHyams // already got ⊥ there's no need to run the code - we know the result is 5981d1de746SOCHyams // ⊥ since `meet(a, ⊥) = ⊥`. 5991d1de746SOCHyams if (BBLiveIn.size() == 0) 6001d1de746SOCHyams break; 6011d1de746SOCHyams } 6021d1de746SOCHyams 6031d1de746SOCHyams auto CurrentLiveInEntry = LiveIn.find(&BB); 6041d1de746SOCHyams // If there's no LiveIn entry for the block yet, add it. 6051d1de746SOCHyams if (CurrentLiveInEntry == LiveIn.end()) { 6061d1de746SOCHyams LLVM_DEBUG(dbgs() << "change=true (first) on meet on " << BB.getName() 6071d1de746SOCHyams << "\n"); 6081d1de746SOCHyams LiveIn[&BB] = std::move(BBLiveIn); 6091d1de746SOCHyams return /*Changed=*/true; 6101d1de746SOCHyams } 6111d1de746SOCHyams 6121d1de746SOCHyams // If the LiveIn set has changed (expensive check) update it and return 6131d1de746SOCHyams // true. 6141d1de746SOCHyams if (!varFragMapsAreEqual(BBLiveIn, CurrentLiveInEntry->second)) { 6151d1de746SOCHyams LLVM_DEBUG(dbgs() << "change=true on meet on " << BB.getName() << "\n"); 6161d1de746SOCHyams CurrentLiveInEntry->second = std::move(BBLiveIn); 6171d1de746SOCHyams return /*Changed=*/true; 6181d1de746SOCHyams } 6191d1de746SOCHyams 6201d1de746SOCHyams LLVM_DEBUG(dbgs() << "change=false on meet on " << BB.getName() << "\n"); 6211d1de746SOCHyams return /*Changed=*/false; 6221d1de746SOCHyams } 6231d1de746SOCHyams 6246aeb7a71SStephen Tozer void insertMemLoc(BasicBlock &BB, VarLocInsertPt Before, unsigned Var, 6251d1de746SOCHyams unsigned StartBit, unsigned EndBit, unsigned Base, 6261d1de746SOCHyams DebugLoc DL) { 6271d1de746SOCHyams assert(StartBit < EndBit && "Cannot create fragment of size <= 0"); 6281d1de746SOCHyams if (!Base) 6291d1de746SOCHyams return; 6301d1de746SOCHyams FragMemLoc Loc; 6311d1de746SOCHyams Loc.Var = Var; 6321d1de746SOCHyams Loc.OffsetInBits = StartBit; 6331d1de746SOCHyams Loc.SizeInBits = EndBit - StartBit; 6341d1de746SOCHyams assert(Base && "Expected a non-zero ID for Base address"); 6351d1de746SOCHyams Loc.Base = Base; 6361d1de746SOCHyams Loc.DL = DL; 6376aeb7a71SStephen Tozer BBInsertBeforeMap[&BB][Before].push_back(Loc); 6381d1de746SOCHyams LLVM_DEBUG(dbgs() << "Add mem def for " << Aggregates[Var].first->getName() 6391d1de746SOCHyams << " bits [" << StartBit << ", " << EndBit << ")\n"); 6401d1de746SOCHyams } 6411d1de746SOCHyams 642d4879d76SOCHyams /// Inserts a new dbg def if the interval found when looking up \p StartBit 643d4879d76SOCHyams /// in \p FragMap starts before \p StartBit or ends after \p EndBit (which 644d4879d76SOCHyams /// indicates - assuming StartBit->EndBit has just been inserted - that the 645d4879d76SOCHyams /// slice has been coalesced in the map). 6466aeb7a71SStephen Tozer void coalesceFragments(BasicBlock &BB, VarLocInsertPt Before, unsigned Var, 647d4879d76SOCHyams unsigned StartBit, unsigned EndBit, unsigned Base, 648d4879d76SOCHyams DebugLoc DL, const FragsInMemMap &FragMap) { 649d4879d76SOCHyams if (!CoalesceAdjacentFragments) 650d4879d76SOCHyams return; 651d4879d76SOCHyams // We've inserted the location into the map. The map will have coalesced 652d4879d76SOCHyams // adjacent intervals (variable fragments) that describe the same memory 653d4879d76SOCHyams // location. Use this knowledge to insert a debug location that describes 654d4879d76SOCHyams // that coalesced fragment. This may eclipse other locs we've just 655d4879d76SOCHyams // inserted. This is okay as redundant locs will be cleaned up later. 656d4879d76SOCHyams auto CoalescedFrag = FragMap.find(StartBit); 657d4879d76SOCHyams // Bail if no coalescing has taken place. 658d4879d76SOCHyams if (CoalescedFrag.start() == StartBit && CoalescedFrag.stop() == EndBit) 659d4879d76SOCHyams return; 660d4879d76SOCHyams 661d4879d76SOCHyams LLVM_DEBUG(dbgs() << "- Insert loc for bits " << CoalescedFrag.start() 662d4879d76SOCHyams << " to " << CoalescedFrag.stop() << "\n"); 663d4879d76SOCHyams insertMemLoc(BB, Before, Var, CoalescedFrag.start(), CoalescedFrag.stop(), 664d4879d76SOCHyams Base, DL); 665d4879d76SOCHyams } 666d4879d76SOCHyams 6676aeb7a71SStephen Tozer void addDef(const VarLocInfo &VarLoc, VarLocInsertPt Before, BasicBlock &BB, 6681d1de746SOCHyams VarFragMap &LiveSet) { 6691d1de746SOCHyams DebugVariable DbgVar = FnVarLocs->getVariable(VarLoc.VariableID); 6701d1de746SOCHyams if (skipVariable(DbgVar.getVariable())) 6711d1de746SOCHyams return; 6721d1de746SOCHyams // Don't bother doing anything for this variables if we know it's fully 6731d1de746SOCHyams // promoted. We're only interested in variables that (sometimes) live on 6741d1de746SOCHyams // the stack here. 6751d1de746SOCHyams if (!VarsWithStackSlot->count(getAggregate(DbgVar))) 6761d1de746SOCHyams return; 6771d1de746SOCHyams unsigned Var = Aggregates.insert( 6781d1de746SOCHyams DebugAggregate(DbgVar.getVariable(), VarLoc.DL.getInlinedAt())); 6791d1de746SOCHyams 6801d1de746SOCHyams // [StartBit: EndBit) are the bits affected by this def. 6811d1de746SOCHyams const DIExpression *DIExpr = VarLoc.Expr; 6821d1de746SOCHyams unsigned StartBit; 6831d1de746SOCHyams unsigned EndBit; 6841d1de746SOCHyams if (auto Frag = DIExpr->getFragmentInfo()) { 6851d1de746SOCHyams StartBit = Frag->OffsetInBits; 6861d1de746SOCHyams EndBit = StartBit + Frag->SizeInBits; 6871d1de746SOCHyams } else { 6881d1de746SOCHyams assert(static_cast<bool>(DbgVar.getVariable()->getSizeInBits())); 6891d1de746SOCHyams StartBit = 0; 6901d1de746SOCHyams EndBit = *DbgVar.getVariable()->getSizeInBits(); 6911d1de746SOCHyams } 6921d1de746SOCHyams 6931d1de746SOCHyams // We will only fill fragments for simple memory-describing dbg.value 6941d1de746SOCHyams // intrinsics. If the fragment offset is the same as the offset from the 6951d1de746SOCHyams // base pointer, do The Thing, otherwise fall back to normal dbg.value 6961d1de746SOCHyams // behaviour. AssignmentTrackingLowering has generated DIExpressions 6971d1de746SOCHyams // written in terms of the base pointer. 6981d1de746SOCHyams // TODO: Remove this condition since the fragment offset doesn't always 6991d1de746SOCHyams // equal the offset from base pointer (e.g. for a SROA-split variable). 7001d1de746SOCHyams const auto DerefOffsetInBytes = getDerefOffsetInBytes(DIExpr); 7011d1de746SOCHyams const unsigned Base = 7021d1de746SOCHyams DerefOffsetInBytes && *DerefOffsetInBytes * 8 == StartBit 7037d894374SOCHyams ? Bases.insert(VarLoc.Values) 7041d1de746SOCHyams : 0; 7051d1de746SOCHyams LLVM_DEBUG(dbgs() << "DEF " << DbgVar.getVariable()->getName() << " [" 7061d1de746SOCHyams << StartBit << ", " << EndBit << "): " << toString(Base) 7071d1de746SOCHyams << "\n"); 7081d1de746SOCHyams 7091d1de746SOCHyams // First of all, any locs that use mem that are disrupted need reinstating. 7101d1de746SOCHyams // Unfortunately, IntervalMap doesn't let us insert intervals that overlap 7111d1de746SOCHyams // with existing intervals so this code involves a lot of fiddling around 7121d1de746SOCHyams // with intervals to do that manually. 7131d1de746SOCHyams auto FragIt = LiveSet.find(Var); 7141d1de746SOCHyams 7151d1de746SOCHyams // Check if the variable does not exist in the map. 7161d1de746SOCHyams if (FragIt == LiveSet.end()) { 7171d1de746SOCHyams // Add this variable to the BB map. 7181d1de746SOCHyams auto P = LiveSet.try_emplace(Var, FragsInMemMap(IntervalMapAlloc)); 7191d1de746SOCHyams assert(P.second && "Var already in map?"); 7201d1de746SOCHyams // Add the interval to the fragment map. 7211d1de746SOCHyams P.first->second.insert(StartBit, EndBit, Base); 7221d1de746SOCHyams return; 7231d1de746SOCHyams } 7241d1de746SOCHyams // The variable has an entry in the map. 7251d1de746SOCHyams 7261d1de746SOCHyams FragsInMemMap &FragMap = FragIt->second; 7271d1de746SOCHyams // First check the easy case: the new fragment `f` doesn't overlap with any 7281d1de746SOCHyams // intervals. 7291d1de746SOCHyams if (!FragMap.overlaps(StartBit, EndBit)) { 7301d1de746SOCHyams LLVM_DEBUG(dbgs() << "- No overlaps\n"); 7311d1de746SOCHyams FragMap.insert(StartBit, EndBit, Base); 732d4879d76SOCHyams coalesceFragments(BB, Before, Var, StartBit, EndBit, Base, VarLoc.DL, 733d4879d76SOCHyams FragMap); 7341d1de746SOCHyams return; 7351d1de746SOCHyams } 7361d1de746SOCHyams // There is at least one overlap. 7371d1de746SOCHyams 7381d1de746SOCHyams // Does StartBit intersect an existing fragment? 7391d1de746SOCHyams auto FirstOverlap = FragMap.find(StartBit); 7401d1de746SOCHyams assert(FirstOverlap != FragMap.end()); 7411d1de746SOCHyams bool IntersectStart = FirstOverlap.start() < StartBit; 7421d1de746SOCHyams 7431d1de746SOCHyams // Does EndBit intersect an existing fragment? 7441d1de746SOCHyams auto LastOverlap = FragMap.find(EndBit); 7451d1de746SOCHyams bool IntersectEnd = LastOverlap.valid() && LastOverlap.start() < EndBit; 7461d1de746SOCHyams 7471d1de746SOCHyams // Check if both ends of `f` intersect the same interval `i`. 7481d1de746SOCHyams if (IntersectStart && IntersectEnd && FirstOverlap == LastOverlap) { 7491d1de746SOCHyams LLVM_DEBUG(dbgs() << "- Intersect single interval @ both ends\n"); 7501d1de746SOCHyams // Shorten `i` so that there's space to insert `f`. 7511d1de746SOCHyams // [ f ] 7521d1de746SOCHyams // [ - i - ] 7531d1de746SOCHyams // + 7541d1de746SOCHyams // [ i ][ f ][ i ] 755e3a00d51SOCHyams 756e3a00d51SOCHyams // Save values for use after inserting a new interval. 7571d1de746SOCHyams auto EndBitOfOverlap = FirstOverlap.stop(); 758e3a00d51SOCHyams unsigned OverlapValue = FirstOverlap.value(); 759e3a00d51SOCHyams 760e3a00d51SOCHyams // Shorten the overlapping interval. 7611d1de746SOCHyams FirstOverlap.setStop(StartBit); 7621d1de746SOCHyams insertMemLoc(BB, Before, Var, FirstOverlap.start(), StartBit, 763e3a00d51SOCHyams OverlapValue, VarLoc.DL); 7641d1de746SOCHyams 7651d1de746SOCHyams // Insert a new interval to represent the end part. 766e3a00d51SOCHyams FragMap.insert(EndBit, EndBitOfOverlap, OverlapValue); 767e3a00d51SOCHyams insertMemLoc(BB, Before, Var, EndBit, EndBitOfOverlap, OverlapValue, 76851b68573SFangrui Song VarLoc.DL); 7691d1de746SOCHyams 7701d1de746SOCHyams // Insert the new (middle) fragment now there is space. 7711d1de746SOCHyams FragMap.insert(StartBit, EndBit, Base); 7721d1de746SOCHyams } else { 7731d1de746SOCHyams // There's an overlap but `f` may not be fully contained within 7741d1de746SOCHyams // `i`. Shorten any end-point intersections so that we can then 7751d1de746SOCHyams // insert `f`. 7761d1de746SOCHyams // [ - f - ] 7771d1de746SOCHyams // [ - i - ] 7781d1de746SOCHyams // | | 7791d1de746SOCHyams // [ i ] 7801d1de746SOCHyams // Shorten any end-point intersections. 7811d1de746SOCHyams if (IntersectStart) { 7821d1de746SOCHyams LLVM_DEBUG(dbgs() << "- Intersect interval at start\n"); 7831d1de746SOCHyams // Split off at the intersection. 7841d1de746SOCHyams FirstOverlap.setStop(StartBit); 7851d1de746SOCHyams insertMemLoc(BB, Before, Var, FirstOverlap.start(), StartBit, 78651b68573SFangrui Song *FirstOverlap, VarLoc.DL); 7871d1de746SOCHyams } 7881d1de746SOCHyams // [ - f - ] 7891d1de746SOCHyams // [ - i - ] 7901d1de746SOCHyams // | | 7911d1de746SOCHyams // [ i ] 7921d1de746SOCHyams if (IntersectEnd) { 7931d1de746SOCHyams LLVM_DEBUG(dbgs() << "- Intersect interval at end\n"); 7941d1de746SOCHyams // Split off at the intersection. 7951d1de746SOCHyams LastOverlap.setStart(EndBit); 79651b68573SFangrui Song insertMemLoc(BB, Before, Var, EndBit, LastOverlap.stop(), *LastOverlap, 79751b68573SFangrui Song VarLoc.DL); 7981d1de746SOCHyams } 7991d1de746SOCHyams 8001d1de746SOCHyams LLVM_DEBUG(dbgs() << "- Erase intervals contained within\n"); 8011d1de746SOCHyams // FirstOverlap and LastOverlap have been shortened such that they're 8021d1de746SOCHyams // no longer overlapping with [StartBit, EndBit). Delete any overlaps 8031d1de746SOCHyams // that remain (these will be fully contained within `f`). 8041d1de746SOCHyams // [ - f - ] } 8051d1de746SOCHyams // [ - i - ] } Intersection shortening that has happened above. 8061d1de746SOCHyams // | | } 8071d1de746SOCHyams // [ i ] } 8081d1de746SOCHyams // ----------------- 8091d1de746SOCHyams // [i2 ] } Intervals fully contained within `f` get erased. 8101d1de746SOCHyams // ----------------- 8111d1de746SOCHyams // [ - f - ][ i ] } Completed insertion. 8121d1de746SOCHyams auto It = FirstOverlap; 8131d1de746SOCHyams if (IntersectStart) 8141d1de746SOCHyams ++It; // IntersectStart: first overlap has been shortened. 8151d1de746SOCHyams while (It.valid() && It.start() >= StartBit && It.stop() <= EndBit) { 8161d1de746SOCHyams LLVM_DEBUG(dbgs() << "- Erase " << toString(It)); 8171d1de746SOCHyams It.erase(); // This increments It after removing the interval. 8181d1de746SOCHyams } 8191d1de746SOCHyams // We've dealt with all the overlaps now! 8201d1de746SOCHyams assert(!FragMap.overlaps(StartBit, EndBit)); 8211d1de746SOCHyams LLVM_DEBUG(dbgs() << "- Insert DEF into now-empty space\n"); 8221d1de746SOCHyams FragMap.insert(StartBit, EndBit, Base); 8231d1de746SOCHyams } 824d4879d76SOCHyams 825d4879d76SOCHyams coalesceFragments(BB, Before, Var, StartBit, EndBit, Base, VarLoc.DL, 826d4879d76SOCHyams FragMap); 8271d1de746SOCHyams } 8281d1de746SOCHyams 8291d1de746SOCHyams bool skipVariable(const DILocalVariable *V) { return !V->getSizeInBits(); } 8301d1de746SOCHyams 8311d1de746SOCHyams void process(BasicBlock &BB, VarFragMap &LiveSet) { 8321d1de746SOCHyams BBInsertBeforeMap[&BB].clear(); 8331d1de746SOCHyams for (auto &I : BB) { 834ffd08c77SStephen Tozer for (DbgVariableRecord &DVR : filterDbgVars(I.getDbgRecordRange())) { 835ffd08c77SStephen Tozer if (const auto *Locs = FnVarLocs->getWedge(&DVR)) { 83630845e8aSStephen Tozer for (const VarLocInfo &Loc : *Locs) { 837ffd08c77SStephen Tozer addDef(Loc, &DVR, *I.getParent(), LiveSet); 83830845e8aSStephen Tozer } 83930845e8aSStephen Tozer } 84030845e8aSStephen Tozer } 8411d1de746SOCHyams if (const auto *Locs = FnVarLocs->getWedge(&I)) { 8421d1de746SOCHyams for (const VarLocInfo &Loc : *Locs) { 8436aeb7a71SStephen Tozer addDef(Loc, &I, *I.getParent(), LiveSet); 8441d1de746SOCHyams } 8451d1de746SOCHyams } 8461d1de746SOCHyams } 8471d1de746SOCHyams } 8481d1de746SOCHyams 8491d1de746SOCHyams public: 8501d1de746SOCHyams MemLocFragmentFill(Function &Fn, 851d4879d76SOCHyams const DenseSet<DebugAggregate> *VarsWithStackSlot, 852d4879d76SOCHyams bool CoalesceAdjacentFragments) 853d4879d76SOCHyams : Fn(Fn), VarsWithStackSlot(VarsWithStackSlot), 854d4879d76SOCHyams CoalesceAdjacentFragments(CoalesceAdjacentFragments) {} 8551d1de746SOCHyams 8561d1de746SOCHyams /// Add variable locations to \p FnVarLocs so that any bits of a variable 8571d1de746SOCHyams /// with a memory location have that location explicitly reinstated at each 8581d1de746SOCHyams /// subsequent variable location definition that that doesn't overwrite those 8591d1de746SOCHyams /// bits. i.e. after a variable location def, insert new defs for the memory 8601d1de746SOCHyams /// location with fragments for the difference of "all bits currently in 8611d1de746SOCHyams /// memory" and "the fragment of the second def". e.g. 8621d1de746SOCHyams /// 8631d1de746SOCHyams /// Before: 8641d1de746SOCHyams /// 8651d1de746SOCHyams /// var x bits 0 to 63: value in memory 8661d1de746SOCHyams /// more instructions 8671d1de746SOCHyams /// var x bits 0 to 31: value is %0 8681d1de746SOCHyams /// 8691d1de746SOCHyams /// After: 8701d1de746SOCHyams /// 8711d1de746SOCHyams /// var x bits 0 to 63: value in memory 8721d1de746SOCHyams /// more instructions 8731d1de746SOCHyams /// var x bits 0 to 31: value is %0 8741d1de746SOCHyams /// var x bits 32 to 61: value in memory ; <-- new loc def 8751d1de746SOCHyams /// 8761d1de746SOCHyams void run(FunctionVarLocsBuilder *FnVarLocs) { 8771d1de746SOCHyams if (!EnableMemLocFragFill) 8781d1de746SOCHyams return; 8791d1de746SOCHyams 8801d1de746SOCHyams this->FnVarLocs = FnVarLocs; 8811d1de746SOCHyams 8821d1de746SOCHyams // Prepare for traversal. 8831d1de746SOCHyams // 8841d1de746SOCHyams ReversePostOrderTraversal<Function *> RPOT(&Fn); 8851d1de746SOCHyams std::priority_queue<unsigned int, std::vector<unsigned int>, 8861d1de746SOCHyams std::greater<unsigned int>> 8871d1de746SOCHyams Worklist; 8881d1de746SOCHyams std::priority_queue<unsigned int, std::vector<unsigned int>, 8891d1de746SOCHyams std::greater<unsigned int>> 8901d1de746SOCHyams Pending; 8911d1de746SOCHyams DenseMap<unsigned int, BasicBlock *> OrderToBB; 8921d1de746SOCHyams DenseMap<BasicBlock *, unsigned int> BBToOrder; 8931d1de746SOCHyams { // Init OrderToBB and BBToOrder. 8941d1de746SOCHyams unsigned int RPONumber = 0; 895dae061f1SKazu Hirata for (BasicBlock *BB : RPOT) { 896dae061f1SKazu Hirata OrderToBB[RPONumber] = BB; 897dae061f1SKazu Hirata BBToOrder[BB] = RPONumber; 8981d1de746SOCHyams Worklist.push(RPONumber); 8991d1de746SOCHyams ++RPONumber; 9001d1de746SOCHyams } 9011d1de746SOCHyams LiveIn.init(RPONumber); 9021d1de746SOCHyams LiveOut.init(RPONumber); 9031d1de746SOCHyams } 9041d1de746SOCHyams 9051d1de746SOCHyams // Perform the traversal. 9061d1de746SOCHyams // 9071d1de746SOCHyams // This is a standard "intersect of predecessor outs" dataflow problem. To 9081d1de746SOCHyams // solve it, we perform meet() and process() using the two worklist method 9091d1de746SOCHyams // until the LiveIn data for each block becomes unchanging. 9101d1de746SOCHyams // 9111d1de746SOCHyams // This dataflow is essentially working on maps of sets and at each meet we 9121d1de746SOCHyams // intersect the maps and the mapped sets. So, initialized live-in maps 9131d1de746SOCHyams // monotonically decrease in value throughout the dataflow. 9141d1de746SOCHyams SmallPtrSet<BasicBlock *, 16> Visited; 9151d1de746SOCHyams while (!Worklist.empty() || !Pending.empty()) { 9161d1de746SOCHyams // We track what is on the pending worklist to avoid inserting the same 9171d1de746SOCHyams // thing twice. We could avoid this with a custom priority queue, but 9181d1de746SOCHyams // this is probably not worth it. 9191d1de746SOCHyams SmallPtrSet<BasicBlock *, 16> OnPending; 9201d1de746SOCHyams LLVM_DEBUG(dbgs() << "Processing Worklist\n"); 9211d1de746SOCHyams while (!Worklist.empty()) { 9221d1de746SOCHyams BasicBlock *BB = OrderToBB[Worklist.top()]; 9231d1de746SOCHyams LLVM_DEBUG(dbgs() << "\nPop BB " << BB->getName() << "\n"); 9241d1de746SOCHyams Worklist.pop(); 9251d1de746SOCHyams bool InChanged = meet(*BB, Visited); 9261d1de746SOCHyams // Always consider LiveIn changed on the first visit. 9271d1de746SOCHyams InChanged |= Visited.insert(BB).second; 9281d1de746SOCHyams if (InChanged) { 9291d1de746SOCHyams LLVM_DEBUG(dbgs() 9301d1de746SOCHyams << BB->getName() << " has new InLocs, process it\n"); 9311d1de746SOCHyams // Mutate a copy of LiveIn while processing BB. Once we've processed 9321d1de746SOCHyams // the terminator LiveSet is the LiveOut set for BB. 9331d1de746SOCHyams // This is an expensive copy! 9341d1de746SOCHyams VarFragMap LiveSet = LiveIn[BB]; 9351d1de746SOCHyams 9361d1de746SOCHyams // Process the instructions in the block. 9371d1de746SOCHyams process(*BB, LiveSet); 9381d1de746SOCHyams 9391d1de746SOCHyams // Relatively expensive check: has anything changed in LiveOut for BB? 9401d1de746SOCHyams if (!varFragMapsAreEqual(LiveOut[BB], LiveSet)) { 9411d1de746SOCHyams LLVM_DEBUG(dbgs() << BB->getName() 9421d1de746SOCHyams << " has new OutLocs, add succs to worklist: [ "); 9431d1de746SOCHyams LiveOut[BB] = std::move(LiveSet); 9443641efcfSKazu Hirata for (BasicBlock *Succ : successors(BB)) { 9453641efcfSKazu Hirata if (OnPending.insert(Succ).second) { 9463641efcfSKazu Hirata LLVM_DEBUG(dbgs() << Succ->getName() << " "); 9473641efcfSKazu Hirata Pending.push(BBToOrder[Succ]); 9481d1de746SOCHyams } 9491d1de746SOCHyams } 9501d1de746SOCHyams LLVM_DEBUG(dbgs() << "]\n"); 9511d1de746SOCHyams } 9521d1de746SOCHyams } 9531d1de746SOCHyams } 9541d1de746SOCHyams Worklist.swap(Pending); 9551d1de746SOCHyams // At this point, pending must be empty, since it was just the empty 9561d1de746SOCHyams // worklist 9571d1de746SOCHyams assert(Pending.empty() && "Pending should be empty"); 9581d1de746SOCHyams } 9591d1de746SOCHyams 9601d1de746SOCHyams // Insert new location defs. 9610c36ab19SAkshay Khadse for (auto &Pair : BBInsertBeforeMap) { 9621d1de746SOCHyams InsertMap &Map = Pair.second; 9630c36ab19SAkshay Khadse for (auto &Pair : Map) { 9646aeb7a71SStephen Tozer auto InsertBefore = Pair.first; 9651d1de746SOCHyams assert(InsertBefore && "should never be null"); 9661d1de746SOCHyams auto FragMemLocs = Pair.second; 9671d1de746SOCHyams auto &Ctx = Fn.getContext(); 9681d1de746SOCHyams 9690c36ab19SAkshay Khadse for (auto &FragMemLoc : FragMemLocs) { 970e03f4271SJay Foad DIExpression *Expr = DIExpression::get(Ctx, {}); 971d4879d76SOCHyams if (FragMemLoc.SizeInBits != 972d4879d76SOCHyams *Aggregates[FragMemLoc.Var].first->getSizeInBits()) 9731d1de746SOCHyams Expr = *DIExpression::createFragmentExpression( 9741d1de746SOCHyams Expr, FragMemLoc.OffsetInBits, FragMemLoc.SizeInBits); 9751d1de746SOCHyams Expr = DIExpression::prepend(Expr, DIExpression::DerefAfter, 9761d1de746SOCHyams FragMemLoc.OffsetInBits / 8); 9771d1de746SOCHyams DebugVariable Var(Aggregates[FragMemLoc.Var].first, Expr, 9781d1de746SOCHyams FragMemLoc.DL.getInlinedAt()); 9791d1de746SOCHyams FnVarLocs->addVarLoc(InsertBefore, Var, Expr, FragMemLoc.DL, 9801d1de746SOCHyams Bases[FragMemLoc.Base]); 9811d1de746SOCHyams } 9821d1de746SOCHyams } 9831d1de746SOCHyams } 9841d1de746SOCHyams } 9851d1de746SOCHyams }; 9861d1de746SOCHyams 9871d1de746SOCHyams /// AssignmentTrackingLowering encapsulates a dataflow analysis over a function 9881d1de746SOCHyams /// that interprets assignment tracking debug info metadata and stores in IR to 9891d1de746SOCHyams /// create a map of variable locations. 9901d1de746SOCHyams class AssignmentTrackingLowering { 9911d1de746SOCHyams public: 9921d1de746SOCHyams /// The kind of location in use for a variable, where Mem is the stack home, 9931d1de746SOCHyams /// Val is an SSA value or const, and None means that there is not one single 9941d1de746SOCHyams /// kind (either because there are multiple or because there is none; it may 9951d1de746SOCHyams /// prove useful to split this into two values in the future). 9961d1de746SOCHyams /// 9971d1de746SOCHyams /// LocKind is a join-semilattice with the partial order: 9981d1de746SOCHyams /// None > Mem, Val 9991d1de746SOCHyams /// 10001d1de746SOCHyams /// i.e. 10011d1de746SOCHyams /// join(Mem, Mem) = Mem 10021d1de746SOCHyams /// join(Val, Val) = Val 10031d1de746SOCHyams /// join(Mem, Val) = None 10041d1de746SOCHyams /// join(None, Mem) = None 10051d1de746SOCHyams /// join(None, Val) = None 10061d1de746SOCHyams /// join(None, None) = None 10071d1de746SOCHyams /// 10081d1de746SOCHyams /// Note: the order is not `None > Val > Mem` because we're using DIAssignID 10091d1de746SOCHyams /// to name assignments and are not tracking the actual stored values. 10101d1de746SOCHyams /// Therefore currently there's no way to ensure that Mem values and Val 10111d1de746SOCHyams /// values are the same. This could be a future extension, though it's not 10121d1de746SOCHyams /// clear that many additional locations would be recovered that way in 10131d1de746SOCHyams /// practice as the likelihood of this sitation arising naturally seems 10141d1de746SOCHyams /// incredibly low. 10151d1de746SOCHyams enum class LocKind { Mem, Val, None }; 10161d1de746SOCHyams 10171d1de746SOCHyams /// An abstraction of the assignment of a value to a variable or memory 10181d1de746SOCHyams /// location. 10191d1de746SOCHyams /// 10201d1de746SOCHyams /// An Assignment is Known or NoneOrPhi. A Known Assignment means we have a 10211d1de746SOCHyams /// DIAssignID ptr that represents it. NoneOrPhi means that we don't (or 10221d1de746SOCHyams /// can't) know the ID of the last assignment that took place. 10231d1de746SOCHyams /// 10241d1de746SOCHyams /// The Status of the Assignment (Known or NoneOrPhi) is another 10251d1de746SOCHyams /// join-semilattice. The partial order is: 10261d1de746SOCHyams /// NoneOrPhi > Known {id_0, id_1, ...id_N} 10271d1de746SOCHyams /// 10281d1de746SOCHyams /// i.e. for all values x and y where x != y: 10291d1de746SOCHyams /// join(x, x) = x 10301d1de746SOCHyams /// join(x, y) = NoneOrPhi 1031ffd08c77SStephen Tozer using AssignRecord = PointerUnion<DbgAssignIntrinsic *, DbgVariableRecord *>; 10321d1de746SOCHyams struct Assignment { 10331d1de746SOCHyams enum S { Known, NoneOrPhi } Status; 10341d1de746SOCHyams /// ID of the assignment. nullptr if Status is not Known. 10351d1de746SOCHyams DIAssignID *ID; 10361d1de746SOCHyams /// The dbg.assign that marks this dbg-def. Mem-defs don't use this field. 10371d1de746SOCHyams /// May be nullptr. 103852665432SStephen Tozer AssignRecord Source; 10391d1de746SOCHyams 10401d1de746SOCHyams bool isSameSourceAssignment(const Assignment &Other) const { 10411d1de746SOCHyams // Don't include Source in the equality check. Assignments are 10421d1de746SOCHyams // defined by their ID, not debug intrinsic(s). 10431d1de746SOCHyams return std::tie(Status, ID) == std::tie(Other.Status, Other.ID); 10441d1de746SOCHyams } 10451d1de746SOCHyams void dump(raw_ostream &OS) { 10461d1de746SOCHyams static const char *LUT[] = {"Known", "NoneOrPhi"}; 10471d1de746SOCHyams OS << LUT[Status] << "(id="; 10481d1de746SOCHyams if (ID) 10491d1de746SOCHyams OS << ID; 10501d1de746SOCHyams else 10511d1de746SOCHyams OS << "null"; 10521d1de746SOCHyams OS << ", s="; 105352665432SStephen Tozer if (Source.isNull()) 10541d1de746SOCHyams OS << "null"; 10555b19ed8bSKazu Hirata else if (const auto *DAI = dyn_cast<DbgAssignIntrinsic *>(Source)) 10565b19ed8bSKazu Hirata OS << DAI; 105752665432SStephen Tozer else 10585b19ed8bSKazu Hirata OS << cast<DbgVariableRecord *>(Source); 10591d1de746SOCHyams OS << ")"; 10601d1de746SOCHyams } 10611d1de746SOCHyams 10621d1de746SOCHyams static Assignment make(DIAssignID *ID, DbgAssignIntrinsic *Source) { 10631d1de746SOCHyams return Assignment(Known, ID, Source); 10641d1de746SOCHyams } 1065ffd08c77SStephen Tozer static Assignment make(DIAssignID *ID, DbgVariableRecord *Source) { 106652665432SStephen Tozer assert(Source->isDbgAssign() && 1067ffd08c77SStephen Tozer "Cannot make an assignment from a non-assign DbgVariableRecord"); 106852665432SStephen Tozer return Assignment(Known, ID, Source); 106952665432SStephen Tozer } 107052665432SStephen Tozer static Assignment make(DIAssignID *ID, AssignRecord Source) { 107152665432SStephen Tozer return Assignment(Known, ID, Source); 107252665432SStephen Tozer } 10731d1de746SOCHyams static Assignment makeFromMemDef(DIAssignID *ID) { 107452665432SStephen Tozer return Assignment(Known, ID); 10751d1de746SOCHyams } 107652665432SStephen Tozer static Assignment makeNoneOrPhi() { return Assignment(NoneOrPhi, nullptr); } 10771d1de746SOCHyams // Again, need a Top value? 107852665432SStephen Tozer Assignment() : Status(NoneOrPhi), ID(nullptr) {} // Can we delete this? 107952665432SStephen Tozer Assignment(S Status, DIAssignID *ID) : Status(Status), ID(ID) { 108052665432SStephen Tozer // If the Status is Known then we expect there to be an assignment ID. 108152665432SStephen Tozer assert(Status == NoneOrPhi || ID); 108252665432SStephen Tozer } 10831d1de746SOCHyams Assignment(S Status, DIAssignID *ID, DbgAssignIntrinsic *Source) 10841d1de746SOCHyams : Status(Status), ID(ID), Source(Source) { 10851d1de746SOCHyams // If the Status is Known then we expect there to be an assignment ID. 10861d1de746SOCHyams assert(Status == NoneOrPhi || ID); 10871d1de746SOCHyams } 1088ffd08c77SStephen Tozer Assignment(S Status, DIAssignID *ID, DbgVariableRecord *Source) 108952665432SStephen Tozer : Status(Status), ID(ID), Source(Source) { 109052665432SStephen Tozer // If the Status is Known then we expect there to be an assignment ID. 109152665432SStephen Tozer assert(Status == NoneOrPhi || ID); 109252665432SStephen Tozer } 109352665432SStephen Tozer Assignment(S Status, DIAssignID *ID, AssignRecord Source) 109452665432SStephen Tozer : Status(Status), ID(ID), Source(Source) { 109552665432SStephen Tozer // If the Status is Known then we expect there to be an assignment ID. 109652665432SStephen Tozer assert(Status == NoneOrPhi || ID); 109752665432SStephen Tozer } 10981d1de746SOCHyams }; 10991d1de746SOCHyams 1100d5b2c8e5SOCHyams using AssignmentMap = SmallVector<Assignment>; 1101d5b2c8e5SOCHyams using LocMap = SmallVector<LocKind>; 1102d5b2c8e5SOCHyams using OverlapMap = DenseMap<VariableID, SmallVector<VariableID>>; 11031d1de746SOCHyams using UntaggedStoreAssignmentMap = 11041d1de746SOCHyams DenseMap<const Instruction *, 11051d1de746SOCHyams SmallVector<std::pair<VariableID, at::AssignmentInfo>>>; 11061d1de746SOCHyams 11071d1de746SOCHyams private: 1108d5b2c8e5SOCHyams /// The highest numbered VariableID for partially promoted variables plus 1, 1109d5b2c8e5SOCHyams /// the values for which start at 1. 1110d5b2c8e5SOCHyams unsigned TrackedVariablesVectorSize = 0; 11111d1de746SOCHyams /// Map a variable to the set of variables that it fully contains. 11121d1de746SOCHyams OverlapMap VarContains; 11131d1de746SOCHyams /// Map untagged stores to the variable fragments they assign to. Used by 11141d1de746SOCHyams /// processUntaggedInstruction. 11151d1de746SOCHyams UntaggedStoreAssignmentMap UntaggedStoreVars; 11161d1de746SOCHyams 11171d1de746SOCHyams // Machinery to defer inserting dbg.values. 11186aeb7a71SStephen Tozer using InstInsertMap = MapVector<VarLocInsertPt, SmallVector<VarLocInfo>>; 11196aeb7a71SStephen Tozer InstInsertMap InsertBeforeMap; 11201d1de746SOCHyams /// Clear the location definitions currently cached for insertion after /p 11211d1de746SOCHyams /// After. 11221d1de746SOCHyams void resetInsertionPoint(Instruction &After); 1123ffd08c77SStephen Tozer void resetInsertionPoint(DbgVariableRecord &After); 112452665432SStephen Tozer 112552665432SStephen Tozer // emitDbgValue can be called with: 1126ffd08c77SStephen Tozer // Source=[AssignRecord|DbgValueInst*|DbgAssignIntrinsic*|DbgVariableRecord*] 112752665432SStephen Tozer // Since AssignRecord can be cast to one of the latter two types, and all 112852665432SStephen Tozer // other types have a shared interface, we use a template to handle the latter 112952665432SStephen Tozer // three types, and an explicit overload for AssignRecord that forwards to 113052665432SStephen Tozer // the template version with the right type. 113152665432SStephen Tozer void emitDbgValue(LocKind Kind, AssignRecord Source, VarLocInsertPt After); 113252665432SStephen Tozer template <typename T> 113352665432SStephen Tozer void emitDbgValue(LocKind Kind, const T Source, VarLocInsertPt After); 11341d1de746SOCHyams 1135d5b2c8e5SOCHyams static bool mapsAreEqual(const BitVector &Mask, const AssignmentMap &A, 1136d5b2c8e5SOCHyams const AssignmentMap &B) { 1137d5b2c8e5SOCHyams return llvm::all_of(Mask.set_bits(), [&](unsigned VarID) { 1138d5b2c8e5SOCHyams return A[VarID].isSameSourceAssignment(B[VarID]); 1139d5b2c8e5SOCHyams }); 11401d1de746SOCHyams } 11411d1de746SOCHyams 11421d1de746SOCHyams /// Represents the stack and debug assignments in a block. Used to describe 11431d1de746SOCHyams /// the live-in and live-out values for blocks, as well as the "current" 11441d1de746SOCHyams /// value as we process each instruction in a block. 11451d1de746SOCHyams struct BlockInfo { 1146d5b2c8e5SOCHyams /// The set of variables (VariableID) being tracked in this block. 1147d5b2c8e5SOCHyams BitVector VariableIDsInBlock; 1148d5b2c8e5SOCHyams /// Dominating assignment to memory for each variable, indexed by 1149d5b2c8e5SOCHyams /// VariableID. 11501d1de746SOCHyams AssignmentMap StackHomeValue; 1151d5b2c8e5SOCHyams /// Dominating assignemnt to each variable, indexed by VariableID. 11521d1de746SOCHyams AssignmentMap DebugValue; 11531d1de746SOCHyams /// Location kind for each variable. LiveLoc indicates whether the 11541d1de746SOCHyams /// dominating assignment in StackHomeValue (LocKind::Mem), DebugValue 11551d1de746SOCHyams /// (LocKind::Val), or neither (LocKind::None) is valid, in that order of 11561d1de746SOCHyams /// preference. This cannot be derived by inspecting DebugValue and 11571d1de746SOCHyams /// StackHomeValue due to the fact that there's no distinction in 11581d1de746SOCHyams /// Assignment (the class) between whether an assignment is unknown or a 11591d1de746SOCHyams /// merge of multiple assignments (both are Status::NoneOrPhi). In other 11601d1de746SOCHyams /// words, the memory location may well be valid while both DebugValue and 11611d1de746SOCHyams /// StackHomeValue contain Assignments that have a Status of NoneOrPhi. 1162d5b2c8e5SOCHyams /// Indexed by VariableID. 11631d1de746SOCHyams LocMap LiveLoc; 11641d1de746SOCHyams 1165d5b2c8e5SOCHyams public: 1166d5b2c8e5SOCHyams enum AssignmentKind { Stack, Debug }; 1167d5b2c8e5SOCHyams const AssignmentMap &getAssignmentMap(AssignmentKind Kind) const { 1168d5b2c8e5SOCHyams switch (Kind) { 1169d5b2c8e5SOCHyams case Stack: 1170d5b2c8e5SOCHyams return StackHomeValue; 1171d5b2c8e5SOCHyams case Debug: 1172d5b2c8e5SOCHyams return DebugValue; 1173d5b2c8e5SOCHyams } 1174d5b2c8e5SOCHyams llvm_unreachable("Unknown AssignmentKind"); 1175d5b2c8e5SOCHyams } 1176d5b2c8e5SOCHyams AssignmentMap &getAssignmentMap(AssignmentKind Kind) { 1177d5b2c8e5SOCHyams return const_cast<AssignmentMap &>( 1178d5b2c8e5SOCHyams const_cast<const BlockInfo *>(this)->getAssignmentMap(Kind)); 1179d5b2c8e5SOCHyams } 1180d5b2c8e5SOCHyams 1181d5b2c8e5SOCHyams bool isVariableTracked(VariableID Var) const { 1182d5b2c8e5SOCHyams return VariableIDsInBlock[static_cast<unsigned>(Var)]; 1183d5b2c8e5SOCHyams } 1184d5b2c8e5SOCHyams 1185d5b2c8e5SOCHyams const Assignment &getAssignment(AssignmentKind Kind, VariableID Var) const { 1186d5b2c8e5SOCHyams assert(isVariableTracked(Var) && "Var not tracked in block"); 1187d5b2c8e5SOCHyams return getAssignmentMap(Kind)[static_cast<unsigned>(Var)]; 1188d5b2c8e5SOCHyams } 1189d5b2c8e5SOCHyams 1190d5b2c8e5SOCHyams LocKind getLocKind(VariableID Var) const { 1191d5b2c8e5SOCHyams assert(isVariableTracked(Var) && "Var not tracked in block"); 1192d5b2c8e5SOCHyams return LiveLoc[static_cast<unsigned>(Var)]; 1193d5b2c8e5SOCHyams } 1194d5b2c8e5SOCHyams 1195d5b2c8e5SOCHyams /// Set LocKind for \p Var only: does not set LocKind for VariableIDs of 1196d5b2c8e5SOCHyams /// fragments contained win \p Var. 1197d5b2c8e5SOCHyams void setLocKind(VariableID Var, LocKind K) { 1198d5b2c8e5SOCHyams VariableIDsInBlock.set(static_cast<unsigned>(Var)); 1199d5b2c8e5SOCHyams LiveLoc[static_cast<unsigned>(Var)] = K; 1200d5b2c8e5SOCHyams } 1201d5b2c8e5SOCHyams 1202d5b2c8e5SOCHyams /// Set the assignment in the \p Kind assignment map for \p Var only: does 1203d5b2c8e5SOCHyams /// not set the assignment for VariableIDs of fragments contained win \p 1204d5b2c8e5SOCHyams /// Var. 1205d5b2c8e5SOCHyams void setAssignment(AssignmentKind Kind, VariableID Var, 1206d5b2c8e5SOCHyams const Assignment &AV) { 1207d5b2c8e5SOCHyams VariableIDsInBlock.set(static_cast<unsigned>(Var)); 1208d5b2c8e5SOCHyams getAssignmentMap(Kind)[static_cast<unsigned>(Var)] = AV; 1209d5b2c8e5SOCHyams } 1210d5b2c8e5SOCHyams 1211d5b2c8e5SOCHyams /// Return true if there is an assignment matching \p AV in the \p Kind 1212d5b2c8e5SOCHyams /// assignment map. Does consider assignments for VariableIDs of fragments 1213d5b2c8e5SOCHyams /// contained win \p Var. 1214d5b2c8e5SOCHyams bool hasAssignment(AssignmentKind Kind, VariableID Var, 1215d5b2c8e5SOCHyams const Assignment &AV) const { 1216d5b2c8e5SOCHyams if (!isVariableTracked(Var)) 1217d5b2c8e5SOCHyams return false; 1218d5b2c8e5SOCHyams return AV.isSameSourceAssignment(getAssignment(Kind, Var)); 1219d5b2c8e5SOCHyams } 1220d5b2c8e5SOCHyams 12211d1de746SOCHyams /// Compare every element in each map to determine structural equality 12221d1de746SOCHyams /// (slow). 12231d1de746SOCHyams bool operator==(const BlockInfo &Other) const { 1224d5b2c8e5SOCHyams return VariableIDsInBlock == Other.VariableIDsInBlock && 1225d5b2c8e5SOCHyams LiveLoc == Other.LiveLoc && 1226d5b2c8e5SOCHyams mapsAreEqual(VariableIDsInBlock, StackHomeValue, 1227d5b2c8e5SOCHyams Other.StackHomeValue) && 1228d5b2c8e5SOCHyams mapsAreEqual(VariableIDsInBlock, DebugValue, Other.DebugValue); 12291d1de746SOCHyams } 12301d1de746SOCHyams bool operator!=(const BlockInfo &Other) const { return !(*this == Other); } 12311d1de746SOCHyams bool isValid() { 12321d1de746SOCHyams return LiveLoc.size() == DebugValue.size() && 12331d1de746SOCHyams LiveLoc.size() == StackHomeValue.size(); 12341d1de746SOCHyams } 1235d5b2c8e5SOCHyams 1236d5b2c8e5SOCHyams /// Clear everything and initialise with ⊤-values for all variables. 1237d5b2c8e5SOCHyams void init(int NumVars) { 1238d5b2c8e5SOCHyams StackHomeValue.clear(); 1239d5b2c8e5SOCHyams DebugValue.clear(); 1240d5b2c8e5SOCHyams LiveLoc.clear(); 1241d5b2c8e5SOCHyams VariableIDsInBlock = BitVector(NumVars); 1242d5b2c8e5SOCHyams StackHomeValue.insert(StackHomeValue.begin(), NumVars, 1243d5b2c8e5SOCHyams Assignment::makeNoneOrPhi()); 1244d5b2c8e5SOCHyams DebugValue.insert(DebugValue.begin(), NumVars, 1245d5b2c8e5SOCHyams Assignment::makeNoneOrPhi()); 1246d5b2c8e5SOCHyams LiveLoc.insert(LiveLoc.begin(), NumVars, LocKind::None); 1247d5b2c8e5SOCHyams } 1248d5b2c8e5SOCHyams 1249d5b2c8e5SOCHyams /// Helper for join. 1250d5b2c8e5SOCHyams template <typename ElmtType, typename FnInputType> 1251d5b2c8e5SOCHyams static void joinElmt(int Index, SmallVector<ElmtType> &Target, 1252d5b2c8e5SOCHyams const SmallVector<ElmtType> &A, 1253d5b2c8e5SOCHyams const SmallVector<ElmtType> &B, 1254d5b2c8e5SOCHyams ElmtType (*Fn)(FnInputType, FnInputType)) { 1255d5b2c8e5SOCHyams Target[Index] = Fn(A[Index], B[Index]); 1256d5b2c8e5SOCHyams } 1257d5b2c8e5SOCHyams 1258d5b2c8e5SOCHyams /// See comment for AssignmentTrackingLowering::joinBlockInfo. 1259d5b2c8e5SOCHyams static BlockInfo join(const BlockInfo &A, const BlockInfo &B, int NumVars) { 1260d5b2c8e5SOCHyams // Join A and B. 1261d5b2c8e5SOCHyams // 1262d5b2c8e5SOCHyams // Intersect = join(a, b) for a in A, b in B where Var(a) == Var(b) 1263d5b2c8e5SOCHyams // Difference = join(x, ⊤) for x where Var(x) is in A xor B 1264d5b2c8e5SOCHyams // Join = Intersect ∪ Difference 1265d5b2c8e5SOCHyams // 1266d5b2c8e5SOCHyams // This is achieved by performing a join on elements from A and B with 1267d5b2c8e5SOCHyams // variables common to both A and B (join elements indexed by var 1268d5b2c8e5SOCHyams // intersect), then adding ⊤-value elements for vars in A xor B. The 1269d5b2c8e5SOCHyams // latter part is equivalent to performing join on elements with variables 1270d5b2c8e5SOCHyams // in A xor B with the ⊤-value for the map element since join(x, ⊤) = ⊤. 1271d5b2c8e5SOCHyams // BlockInfo::init initializes all variable entries to the ⊤ value so we 1272d5b2c8e5SOCHyams // don't need to explicitly perform that step as Join.VariableIDsInBlock 1273d5b2c8e5SOCHyams // is set to the union of the variables in A and B at the end of this 1274d5b2c8e5SOCHyams // function. 1275d5b2c8e5SOCHyams BlockInfo Join; 1276d5b2c8e5SOCHyams Join.init(NumVars); 1277d5b2c8e5SOCHyams 1278d5b2c8e5SOCHyams BitVector Intersect = A.VariableIDsInBlock; 1279d5b2c8e5SOCHyams Intersect &= B.VariableIDsInBlock; 1280d5b2c8e5SOCHyams 1281d5b2c8e5SOCHyams for (auto VarID : Intersect.set_bits()) { 1282d5b2c8e5SOCHyams joinElmt(VarID, Join.LiveLoc, A.LiveLoc, B.LiveLoc, joinKind); 1283d5b2c8e5SOCHyams joinElmt(VarID, Join.DebugValue, A.DebugValue, B.DebugValue, 1284d5b2c8e5SOCHyams joinAssignment); 1285d5b2c8e5SOCHyams joinElmt(VarID, Join.StackHomeValue, A.StackHomeValue, B.StackHomeValue, 1286d5b2c8e5SOCHyams joinAssignment); 1287d5b2c8e5SOCHyams } 1288d5b2c8e5SOCHyams 1289d5b2c8e5SOCHyams Join.VariableIDsInBlock = A.VariableIDsInBlock; 1290d5b2c8e5SOCHyams Join.VariableIDsInBlock |= B.VariableIDsInBlock; 1291d5b2c8e5SOCHyams assert(Join.isValid()); 1292d5b2c8e5SOCHyams return Join; 1293d5b2c8e5SOCHyams } 12941d1de746SOCHyams }; 12951d1de746SOCHyams 12961d1de746SOCHyams Function &Fn; 12971d1de746SOCHyams const DataLayout &Layout; 12981d1de746SOCHyams const DenseSet<DebugAggregate> *VarsWithStackSlot; 12991d1de746SOCHyams FunctionVarLocsBuilder *FnVarLocs; 13001d1de746SOCHyams DenseMap<const BasicBlock *, BlockInfo> LiveIn; 13011d1de746SOCHyams DenseMap<const BasicBlock *, BlockInfo> LiveOut; 13021d1de746SOCHyams 13031d1de746SOCHyams /// Helper for process methods to track variables touched each frame. 13041d1de746SOCHyams DenseSet<VariableID> VarsTouchedThisFrame; 13051d1de746SOCHyams 13061d1de746SOCHyams /// The set of variables that sometimes are not located in their stack home. 13071d1de746SOCHyams DenseSet<DebugAggregate> NotAlwaysStackHomed; 13081d1de746SOCHyams 13091d1de746SOCHyams VariableID getVariableID(const DebugVariable &Var) { 13101d1de746SOCHyams return static_cast<VariableID>(FnVarLocs->insertVariable(Var)); 13111d1de746SOCHyams } 13121d1de746SOCHyams 13131d1de746SOCHyams /// Join the LiveOut values of preds that are contained in \p Visited into 13141d1de746SOCHyams /// LiveIn[BB]. Return True if LiveIn[BB] has changed as a result. LiveIn[BB] 13151d1de746SOCHyams /// values monotonically increase. See the @link joinMethods join methods 13161d1de746SOCHyams /// @endlink documentation for more info. 13171d1de746SOCHyams bool join(const BasicBlock &BB, const SmallPtrSet<BasicBlock *, 16> &Visited); 13181d1de746SOCHyams ///@name joinMethods 13191d1de746SOCHyams /// Functions that implement `join` (the least upper bound) for the 13201d1de746SOCHyams /// join-semilattice types used in the dataflow. There is an explicit bottom 13211d1de746SOCHyams /// value (⊥) for some types and and explicit top value (⊤) for all types. 13221d1de746SOCHyams /// By definition: 13231d1de746SOCHyams /// 13241d1de746SOCHyams /// Join(A, B) >= A && Join(A, B) >= B 13251d1de746SOCHyams /// Join(A, ⊥) = A 13261d1de746SOCHyams /// Join(A, ⊤) = ⊤ 13271d1de746SOCHyams /// 13281d1de746SOCHyams /// These invariants are important for monotonicity. 13291d1de746SOCHyams /// 13301d1de746SOCHyams /// For the map-type functions, all unmapped keys in an empty map are 13311d1de746SOCHyams /// associated with a bottom value (⊥). This represents their values being 13321d1de746SOCHyams /// unknown. Unmapped keys in non-empty maps (joining two maps with a key 13331d1de746SOCHyams /// only present in one) represents either a variable going out of scope or 13341d1de746SOCHyams /// dropped debug info. It is assumed the key is associated with a top value 13351d1de746SOCHyams /// (⊤) in this case (unknown location / assignment). 13361d1de746SOCHyams ///@{ 13371d1de746SOCHyams static LocKind joinKind(LocKind A, LocKind B); 13381d1de746SOCHyams static Assignment joinAssignment(const Assignment &A, const Assignment &B); 1339d5b2c8e5SOCHyams BlockInfo joinBlockInfo(const BlockInfo &A, const BlockInfo &B); 13401d1de746SOCHyams ///@} 13411d1de746SOCHyams 13421d1de746SOCHyams /// Process the instructions in \p BB updating \p LiveSet along the way. \p 13431d1de746SOCHyams /// LiveSet must be initialized with the current live-in locations before 13441d1de746SOCHyams /// calling this. 13451d1de746SOCHyams void process(BasicBlock &BB, BlockInfo *LiveSet); 13461d1de746SOCHyams ///@name processMethods 13471d1de746SOCHyams /// Methods to process instructions in order to update the LiveSet (current 13481d1de746SOCHyams /// location information). 13491d1de746SOCHyams ///@{ 13501d1de746SOCHyams void processNonDbgInstruction(Instruction &I, BlockInfo *LiveSet); 135193c194fcSOCHyams void processDbgInstruction(DbgInfoIntrinsic &I, BlockInfo *LiveSet); 13521d1de746SOCHyams /// Update \p LiveSet after encountering an instruction with a DIAssignID 13531d1de746SOCHyams /// attachment, \p I. 13541d1de746SOCHyams void processTaggedInstruction(Instruction &I, BlockInfo *LiveSet); 13551d1de746SOCHyams /// Update \p LiveSet after encountering an instruciton without a DIAssignID 13561d1de746SOCHyams /// attachment, \p I. 13571d1de746SOCHyams void processUntaggedInstruction(Instruction &I, BlockInfo *LiveSet); 135852665432SStephen Tozer void processDbgAssign(AssignRecord Assign, BlockInfo *LiveSet); 1359ffd08c77SStephen Tozer void processDbgVariableRecord(DbgVariableRecord &DVR, BlockInfo *LiveSet); 1360ffd08c77SStephen Tozer void processDbgValue( 1361ffd08c77SStephen Tozer PointerUnion<DbgValueInst *, DbgVariableRecord *> DbgValueRecord, 136252665432SStephen Tozer BlockInfo *LiveSet); 13631d1de746SOCHyams /// Add an assignment to memory for the variable /p Var. 13641d1de746SOCHyams void addMemDef(BlockInfo *LiveSet, VariableID Var, const Assignment &AV); 13651d1de746SOCHyams /// Add an assignment to the variable /p Var. 13661d1de746SOCHyams void addDbgDef(BlockInfo *LiveSet, VariableID Var, const Assignment &AV); 13671d1de746SOCHyams ///@} 13681d1de746SOCHyams 13691d1de746SOCHyams /// Set the LocKind for \p Var. 13701d1de746SOCHyams void setLocKind(BlockInfo *LiveSet, VariableID Var, LocKind K); 13711d1de746SOCHyams /// Get the live LocKind for a \p Var. Requires addMemDef or addDbgDef to 13721d1de746SOCHyams /// have been called for \p Var first. 13731d1de746SOCHyams LocKind getLocKind(BlockInfo *LiveSet, VariableID Var); 13741d1de746SOCHyams /// Return true if \p Var has an assignment in \p M matching \p AV. 1375d5b2c8e5SOCHyams bool hasVarWithAssignment(BlockInfo *LiveSet, BlockInfo::AssignmentKind Kind, 1376d5b2c8e5SOCHyams VariableID Var, const Assignment &AV); 1377d5b2c8e5SOCHyams /// Return the set of VariableIDs corresponding the fragments contained fully 1378d5b2c8e5SOCHyams /// within the variable/fragment \p Var. 1379d5b2c8e5SOCHyams ArrayRef<VariableID> getContainedFragments(VariableID Var) const; 1380d5b2c8e5SOCHyams 1381d5b2c8e5SOCHyams /// Mark \p Var as having been touched this frame. Note, this applies only 1382d5b2c8e5SOCHyams /// to the exact fragment \p Var and not to any fragments contained within. 1383d5b2c8e5SOCHyams void touchFragment(VariableID Var); 13841d1de746SOCHyams 13851d1de746SOCHyams /// Emit info for variables that are fully promoted. 13861d1de746SOCHyams bool emitPromotedVarLocs(FunctionVarLocsBuilder *FnVarLocs); 13871d1de746SOCHyams 13881d1de746SOCHyams public: 13891d1de746SOCHyams AssignmentTrackingLowering(Function &Fn, const DataLayout &Layout, 13901d1de746SOCHyams const DenseSet<DebugAggregate> *VarsWithStackSlot) 13911d1de746SOCHyams : Fn(Fn), Layout(Layout), VarsWithStackSlot(VarsWithStackSlot) {} 13921d1de746SOCHyams /// Run the analysis, adding variable location info to \p FnVarLocs. Returns 13931d1de746SOCHyams /// true if any variable locations have been added to FnVarLocs. 13941d1de746SOCHyams bool run(FunctionVarLocsBuilder *FnVarLocs); 13951d1de746SOCHyams }; 1396b6942a28SBenjamin Kramer } // namespace 13971d1de746SOCHyams 1398d5b2c8e5SOCHyams ArrayRef<VariableID> 1399d5b2c8e5SOCHyams AssignmentTrackingLowering::getContainedFragments(VariableID Var) const { 1400d5b2c8e5SOCHyams auto R = VarContains.find(Var); 1401d5b2c8e5SOCHyams if (R == VarContains.end()) 1402e03f4271SJay Foad return {}; 1403d5b2c8e5SOCHyams return R->second; 1404d5b2c8e5SOCHyams } 1405d5b2c8e5SOCHyams 1406d5b2c8e5SOCHyams void AssignmentTrackingLowering::touchFragment(VariableID Var) { 1407d5b2c8e5SOCHyams VarsTouchedThisFrame.insert(Var); 1408d5b2c8e5SOCHyams } 1409d5b2c8e5SOCHyams 14101d1de746SOCHyams void AssignmentTrackingLowering::setLocKind(BlockInfo *LiveSet, VariableID Var, 14111d1de746SOCHyams LocKind K) { 14121d1de746SOCHyams auto SetKind = [this](BlockInfo *LiveSet, VariableID Var, LocKind K) { 1413d5b2c8e5SOCHyams LiveSet->setLocKind(Var, K); 1414d5b2c8e5SOCHyams touchFragment(Var); 14151d1de746SOCHyams }; 14161d1de746SOCHyams SetKind(LiveSet, Var, K); 14171d1de746SOCHyams 14181d1de746SOCHyams // Update the LocKind for all fragments contained within Var. 1419d5b2c8e5SOCHyams for (VariableID Frag : getContainedFragments(Var)) 14201d1de746SOCHyams SetKind(LiveSet, Frag, K); 14211d1de746SOCHyams } 14221d1de746SOCHyams 14231d1de746SOCHyams AssignmentTrackingLowering::LocKind 14241d1de746SOCHyams AssignmentTrackingLowering::getLocKind(BlockInfo *LiveSet, VariableID Var) { 1425d5b2c8e5SOCHyams return LiveSet->getLocKind(Var); 14261d1de746SOCHyams } 14271d1de746SOCHyams 14281d1de746SOCHyams void AssignmentTrackingLowering::addMemDef(BlockInfo *LiveSet, VariableID Var, 14291d1de746SOCHyams const Assignment &AV) { 1430d5b2c8e5SOCHyams LiveSet->setAssignment(BlockInfo::Stack, Var, AV); 14311d1de746SOCHyams 14321d1de746SOCHyams // Use this assigment for all fragments contained within Var, but do not 14331d1de746SOCHyams // provide a Source because we cannot convert Var's value to a value for the 14341d1de746SOCHyams // fragment. 14351d1de746SOCHyams Assignment FragAV = AV; 14361d1de746SOCHyams FragAV.Source = nullptr; 1437d5b2c8e5SOCHyams for (VariableID Frag : getContainedFragments(Var)) 1438d5b2c8e5SOCHyams LiveSet->setAssignment(BlockInfo::Stack, Frag, FragAV); 14391d1de746SOCHyams } 14401d1de746SOCHyams 14411d1de746SOCHyams void AssignmentTrackingLowering::addDbgDef(BlockInfo *LiveSet, VariableID Var, 14421d1de746SOCHyams const Assignment &AV) { 1443d5b2c8e5SOCHyams LiveSet->setAssignment(BlockInfo::Debug, Var, AV); 14441d1de746SOCHyams 14451d1de746SOCHyams // Use this assigment for all fragments contained within Var, but do not 14461d1de746SOCHyams // provide a Source because we cannot convert Var's value to a value for the 14471d1de746SOCHyams // fragment. 14481d1de746SOCHyams Assignment FragAV = AV; 14491d1de746SOCHyams FragAV.Source = nullptr; 1450d5b2c8e5SOCHyams for (VariableID Frag : getContainedFragments(Var)) 1451d5b2c8e5SOCHyams LiveSet->setAssignment(BlockInfo::Debug, Frag, FragAV); 14521d1de746SOCHyams } 14531d1de746SOCHyams 14541d1de746SOCHyams static DIAssignID *getIDFromInst(const Instruction &I) { 14551d1de746SOCHyams return cast<DIAssignID>(I.getMetadata(LLVMContext::MD_DIAssignID)); 14561d1de746SOCHyams } 14571d1de746SOCHyams 14581d1de746SOCHyams static DIAssignID *getIDFromMarker(const DbgAssignIntrinsic &DAI) { 14591d1de746SOCHyams return cast<DIAssignID>(DAI.getAssignID()); 14601d1de746SOCHyams } 14611d1de746SOCHyams 1462ffd08c77SStephen Tozer static DIAssignID *getIDFromMarker(const DbgVariableRecord &DVR) { 1463ffd08c77SStephen Tozer assert(DVR.isDbgAssign() && 1464ffd08c77SStephen Tozer "Cannot get a DIAssignID from a non-assign DbgVariableRecord!"); 1465ffd08c77SStephen Tozer return DVR.getAssignID(); 146652665432SStephen Tozer } 146752665432SStephen Tozer 14681d1de746SOCHyams /// Return true if \p Var has an assignment in \p M matching \p AV. 1469d5b2c8e5SOCHyams bool AssignmentTrackingLowering::hasVarWithAssignment( 1470d5b2c8e5SOCHyams BlockInfo *LiveSet, BlockInfo::AssignmentKind Kind, VariableID Var, 1471d5b2c8e5SOCHyams const Assignment &AV) { 1472d5b2c8e5SOCHyams if (!LiveSet->hasAssignment(Kind, Var, AV)) 14731d1de746SOCHyams return false; 14741d1de746SOCHyams 14751d1de746SOCHyams // Check all the frags contained within Var as these will have all been 14761d1de746SOCHyams // mapped to AV at the last store to Var. 1477d5b2c8e5SOCHyams for (VariableID Frag : getContainedFragments(Var)) 1478d5b2c8e5SOCHyams if (!LiveSet->hasAssignment(Kind, Frag, AV)) 14791d1de746SOCHyams return false; 14801d1de746SOCHyams return true; 14811d1de746SOCHyams } 14821d1de746SOCHyams 1483e0e48187SKazu Hirata #ifndef NDEBUG 14841d1de746SOCHyams const char *locStr(AssignmentTrackingLowering::LocKind Loc) { 14851d1de746SOCHyams using LocKind = AssignmentTrackingLowering::LocKind; 14861d1de746SOCHyams switch (Loc) { 14871d1de746SOCHyams case LocKind::Val: 14881d1de746SOCHyams return "Val"; 14891d1de746SOCHyams case LocKind::Mem: 14901d1de746SOCHyams return "Mem"; 14911d1de746SOCHyams case LocKind::None: 14921d1de746SOCHyams return "None"; 14931d1de746SOCHyams }; 14941d1de746SOCHyams llvm_unreachable("unknown LocKind"); 14951d1de746SOCHyams } 1496e0e48187SKazu Hirata #endif 14971d1de746SOCHyams 1498ffd08c77SStephen Tozer VarLocInsertPt getNextNode(const DbgRecord *DVR) { 1499ffd08c77SStephen Tozer auto NextIt = ++(DVR->getIterator()); 1500ffd08c77SStephen Tozer if (NextIt == DVR->getMarker()->getDbgRecordRange().end()) 1501ffd08c77SStephen Tozer return DVR->getMarker()->MarkedInstr; 15026aeb7a71SStephen Tozer return &*NextIt; 15036aeb7a71SStephen Tozer } 15046aeb7a71SStephen Tozer VarLocInsertPt getNextNode(const Instruction *Inst) { 15056aeb7a71SStephen Tozer const Instruction *Next = Inst->getNextNode(); 150615f3f446SStephen Tozer if (!Next->hasDbgRecords()) 15076aeb7a71SStephen Tozer return Next; 150815f3f446SStephen Tozer return &*Next->getDbgRecordRange().begin(); 15096aeb7a71SStephen Tozer } 15106aeb7a71SStephen Tozer VarLocInsertPt getNextNode(VarLocInsertPt InsertPt) { 15116aeb7a71SStephen Tozer if (isa<const Instruction *>(InsertPt)) 15126aeb7a71SStephen Tozer return getNextNode(cast<const Instruction *>(InsertPt)); 1513ababa964SOrlando Cazalet-Hyams return getNextNode(cast<const DbgRecord *>(InsertPt)); 15146aeb7a71SStephen Tozer } 15156aeb7a71SStephen Tozer 151652665432SStephen Tozer DbgAssignIntrinsic *CastToDbgAssign(DbgVariableIntrinsic *DVI) { 151752665432SStephen Tozer return cast<DbgAssignIntrinsic>(DVI); 151852665432SStephen Tozer } 151952665432SStephen Tozer 1520ffd08c77SStephen Tozer DbgVariableRecord *CastToDbgAssign(DbgVariableRecord *DVR) { 1521ffd08c77SStephen Tozer assert(DVR->isDbgAssign() && 1522ffd08c77SStephen Tozer "Attempted to cast non-assign DbgVariableRecord to DVRAssign."); 1523ffd08c77SStephen Tozer return DVR; 152452665432SStephen Tozer } 152552665432SStephen Tozer 15261d1de746SOCHyams void AssignmentTrackingLowering::emitDbgValue( 15271d1de746SOCHyams AssignmentTrackingLowering::LocKind Kind, 152852665432SStephen Tozer AssignmentTrackingLowering::AssignRecord Source, VarLocInsertPt After) { 152952665432SStephen Tozer if (isa<DbgAssignIntrinsic *>(Source)) 153052665432SStephen Tozer emitDbgValue(Kind, cast<DbgAssignIntrinsic *>(Source), After); 153152665432SStephen Tozer else 1532ffd08c77SStephen Tozer emitDbgValue(Kind, cast<DbgVariableRecord *>(Source), After); 153352665432SStephen Tozer } 153452665432SStephen Tozer template <typename T> 153552665432SStephen Tozer void AssignmentTrackingLowering::emitDbgValue( 153652665432SStephen Tozer AssignmentTrackingLowering::LocKind Kind, const T Source, 153752665432SStephen Tozer VarLocInsertPt After) { 15381d1de746SOCHyams 15391d1de746SOCHyams DILocation *DL = Source->getDebugLoc(); 15407d894374SOCHyams auto Emit = [this, Source, After, DL](Metadata *Val, DIExpression *Expr) { 15411d1de746SOCHyams assert(Expr); 15421d1de746SOCHyams if (!Val) 15437d894374SOCHyams Val = ValueAsMetadata::get( 15447d894374SOCHyams PoisonValue::get(Type::getInt1Ty(Source->getContext()))); 15451d1de746SOCHyams 15461d1de746SOCHyams // Find a suitable insert point. 15476aeb7a71SStephen Tozer auto InsertBefore = getNextNode(After); 15481d1de746SOCHyams assert(InsertBefore && "Shouldn't be inserting after a terminator"); 15491d1de746SOCHyams 15501d1de746SOCHyams VariableID Var = getVariableID(DebugVariable(Source)); 15511d1de746SOCHyams VarLocInfo VarLoc; 15521d1de746SOCHyams VarLoc.VariableID = static_cast<VariableID>(Var); 15531d1de746SOCHyams VarLoc.Expr = Expr; 15547d894374SOCHyams VarLoc.Values = RawLocationWrapper(Val); 15551d1de746SOCHyams VarLoc.DL = DL; 15561d1de746SOCHyams // Insert it into the map for later. 15571d1de746SOCHyams InsertBeforeMap[InsertBefore].push_back(VarLoc); 15581d1de746SOCHyams }; 15591d1de746SOCHyams 15601d1de746SOCHyams // NOTE: This block can mutate Kind. 15611d1de746SOCHyams if (Kind == LocKind::Mem) { 156252665432SStephen Tozer const auto *Assign = CastToDbgAssign(Source); 15631d1de746SOCHyams // Check the address hasn't been dropped (e.g. the debug uses may not have 15641d1de746SOCHyams // been replaced before deleting a Value). 156552665432SStephen Tozer if (Assign->isKillAddress()) { 156683f7f86eSOCHyams // The address isn't valid so treat this as a non-memory def. 156783f7f86eSOCHyams Kind = LocKind::Val; 156883f7f86eSOCHyams } else { 156952665432SStephen Tozer Value *Val = Assign->getAddress(); 157052665432SStephen Tozer DIExpression *Expr = Assign->getAddressExpression(); 15711d1de746SOCHyams assert(!Expr->getFragmentInfo() && 15721d1de746SOCHyams "fragment info should be stored in value-expression only"); 15731d1de746SOCHyams // Copy the fragment info over from the value-expression to the new 15741d1de746SOCHyams // DIExpression. 15751d1de746SOCHyams if (auto OptFragInfo = Source->getExpression()->getFragmentInfo()) { 157651b68573SFangrui Song auto FragInfo = *OptFragInfo; 15771d1de746SOCHyams Expr = *DIExpression::createFragmentExpression( 15781d1de746SOCHyams Expr, FragInfo.OffsetInBits, FragInfo.SizeInBits); 15791d1de746SOCHyams } 15801d1de746SOCHyams // The address-expression has an implicit deref, add it now. 15811d1de746SOCHyams std::tie(Val, Expr) = 15821d1de746SOCHyams walkToAllocaAndPrependOffsetDeref(Layout, Val, Expr); 15837d894374SOCHyams Emit(ValueAsMetadata::get(Val), Expr); 15841d1de746SOCHyams return; 15851d1de746SOCHyams } 15861d1de746SOCHyams } 15871d1de746SOCHyams 15881d1de746SOCHyams if (Kind == LocKind::Val) { 158947b99b7fSOCHyams Emit(Source->getRawLocation(), Source->getExpression()); 15901d1de746SOCHyams return; 15911d1de746SOCHyams } 15921d1de746SOCHyams 15931d1de746SOCHyams if (Kind == LocKind::None) { 159412ece768SOCHyams Emit(nullptr, Source->getExpression()); 15951d1de746SOCHyams return; 15961d1de746SOCHyams } 15971d1de746SOCHyams } 15981d1de746SOCHyams 15991d1de746SOCHyams void AssignmentTrackingLowering::processNonDbgInstruction( 16001d1de746SOCHyams Instruction &I, AssignmentTrackingLowering::BlockInfo *LiveSet) { 16011d1de746SOCHyams if (I.hasMetadata(LLVMContext::MD_DIAssignID)) 16021d1de746SOCHyams processTaggedInstruction(I, LiveSet); 16031d1de746SOCHyams else 16041d1de746SOCHyams processUntaggedInstruction(I, LiveSet); 16051d1de746SOCHyams } 16061d1de746SOCHyams 16071d1de746SOCHyams void AssignmentTrackingLowering::processUntaggedInstruction( 16081d1de746SOCHyams Instruction &I, AssignmentTrackingLowering::BlockInfo *LiveSet) { 16091d1de746SOCHyams // Interpret stack stores that are not tagged as an assignment in memory for 16101d1de746SOCHyams // the variables associated with that address. These stores may not be tagged 16111d1de746SOCHyams // because a) the store cannot be represented using dbg.assigns (non-const 16121d1de746SOCHyams // length or offset) or b) the tag was accidentally dropped during 16131d1de746SOCHyams // optimisations. For these stores we fall back to assuming that the stack 16141d1de746SOCHyams // home is a valid location for the variables. The benefit is that this 16151d1de746SOCHyams // prevents us missing an assignment and therefore incorrectly maintaining 16161d1de746SOCHyams // earlier location definitions, and in many cases it should be a reasonable 16171d1de746SOCHyams // assumption. However, this will occasionally lead to slight 16181d1de746SOCHyams // inaccuracies. The value of a hoisted untagged store will be visible 16191d1de746SOCHyams // "early", for example. 16201d1de746SOCHyams assert(!I.hasMetadata(LLVMContext::MD_DIAssignID)); 16211d1de746SOCHyams auto It = UntaggedStoreVars.find(&I); 16221d1de746SOCHyams if (It == UntaggedStoreVars.end()) 16231d1de746SOCHyams return; // No variables associated with the store destination. 16241d1de746SOCHyams 16251d1de746SOCHyams LLVM_DEBUG(dbgs() << "processUntaggedInstruction on UNTAGGED INST " << I 16261d1de746SOCHyams << "\n"); 16271d1de746SOCHyams // Iterate over the variables that this store affects, add a NoneOrPhi dbg 16281d1de746SOCHyams // and mem def, set lockind to Mem, and emit a location def for each. 16291d1de746SOCHyams for (auto [Var, Info] : It->second) { 16301d1de746SOCHyams // This instruction is treated as both a debug and memory assignment, 16311d1de746SOCHyams // meaning the memory location should be used. We don't have an assignment 16321d1de746SOCHyams // ID though so use Assignment::makeNoneOrPhi() to create an imaginary one. 16331d1de746SOCHyams addMemDef(LiveSet, Var, Assignment::makeNoneOrPhi()); 16341d1de746SOCHyams addDbgDef(LiveSet, Var, Assignment::makeNoneOrPhi()); 16351d1de746SOCHyams setLocKind(LiveSet, Var, LocKind::Mem); 16361d1de746SOCHyams LLVM_DEBUG(dbgs() << " setting Stack LocKind to: " << locStr(LocKind::Mem) 16371d1de746SOCHyams << "\n"); 16381d1de746SOCHyams // Build the dbg location def to insert. 16391d1de746SOCHyams // 16401d1de746SOCHyams // DIExpression: Add fragment and offset. 16411d1de746SOCHyams DebugVariable V = FnVarLocs->getVariable(Var); 1642e03f4271SJay Foad DIExpression *DIE = DIExpression::get(I.getContext(), {}); 16431d1de746SOCHyams if (auto Frag = V.getFragment()) { 16441d1de746SOCHyams auto R = DIExpression::createFragmentExpression(DIE, Frag->OffsetInBits, 16451d1de746SOCHyams Frag->SizeInBits); 16461d1de746SOCHyams assert(R && "unexpected createFragmentExpression failure"); 164751b68573SFangrui Song DIE = *R; 16481d1de746SOCHyams } 16491d1de746SOCHyams SmallVector<uint64_t, 3> Ops; 16501d1de746SOCHyams if (Info.OffsetInBits) 16511d1de746SOCHyams Ops = {dwarf::DW_OP_plus_uconst, Info.OffsetInBits / 8}; 16521d1de746SOCHyams Ops.push_back(dwarf::DW_OP_deref); 16531d1de746SOCHyams DIE = DIExpression::prependOpcodes(DIE, Ops, /*StackValue=*/false, 16541d1de746SOCHyams /*EntryValue=*/false); 1655360da838SStephen Tozer // Find a suitable insert point, before the next instruction or DbgRecord 16566aeb7a71SStephen Tozer // after I. 16576aeb7a71SStephen Tozer auto InsertBefore = getNextNode(&I); 16581d1de746SOCHyams assert(InsertBefore && "Shouldn't be inserting after a terminator"); 16591d1de746SOCHyams 16601d1de746SOCHyams // Get DILocation for this unrecorded assignment. 16611d1de746SOCHyams DILocation *InlinedAt = const_cast<DILocation *>(V.getInlinedAt()); 16621d1de746SOCHyams const DILocation *DILoc = DILocation::get( 16631d1de746SOCHyams Fn.getContext(), 0, 0, V.getVariable()->getScope(), InlinedAt); 16641d1de746SOCHyams 16651d1de746SOCHyams VarLocInfo VarLoc; 16661d1de746SOCHyams VarLoc.VariableID = static_cast<VariableID>(Var); 16671d1de746SOCHyams VarLoc.Expr = DIE; 16687d894374SOCHyams VarLoc.Values = RawLocationWrapper( 16697d894374SOCHyams ValueAsMetadata::get(const_cast<AllocaInst *>(Info.Base))); 16701d1de746SOCHyams VarLoc.DL = DILoc; 16711d1de746SOCHyams // 3. Insert it into the map for later. 16721d1de746SOCHyams InsertBeforeMap[InsertBefore].push_back(VarLoc); 16731d1de746SOCHyams } 16741d1de746SOCHyams } 16751d1de746SOCHyams 16761d1de746SOCHyams void AssignmentTrackingLowering::processTaggedInstruction( 16771d1de746SOCHyams Instruction &I, AssignmentTrackingLowering::BlockInfo *LiveSet) { 16781d1de746SOCHyams auto Linked = at::getAssignmentMarkers(&I); 1679ffd08c77SStephen Tozer auto LinkedDPAssigns = at::getDVRAssignmentMarkers(&I); 16801d1de746SOCHyams // No dbg.assign intrinsics linked. 16811d1de746SOCHyams // FIXME: All vars that have a stack slot this store modifies that don't have 16821d1de746SOCHyams // a dbg.assign linked to it should probably treat this like an untagged 16831d1de746SOCHyams // store. 168452665432SStephen Tozer if (Linked.empty() && LinkedDPAssigns.empty()) 16851d1de746SOCHyams return; 16861d1de746SOCHyams 16871d1de746SOCHyams LLVM_DEBUG(dbgs() << "processTaggedInstruction on " << I << "\n"); 168852665432SStephen Tozer auto ProcessLinkedAssign = [&](auto *Assign) { 168952665432SStephen Tozer VariableID Var = getVariableID(DebugVariable(Assign)); 16901d1de746SOCHyams // Something has gone wrong if VarsWithStackSlot doesn't contain a variable 16911d1de746SOCHyams // that is linked to a store. 169252665432SStephen Tozer assert(VarsWithStackSlot->count(getAggregate(Assign)) && 169352665432SStephen Tozer "expected Assign's variable to have stack slot"); 16941d1de746SOCHyams 16951d1de746SOCHyams Assignment AV = Assignment::makeFromMemDef(getIDFromInst(I)); 16961d1de746SOCHyams addMemDef(LiveSet, Var, AV); 16971d1de746SOCHyams 169852665432SStephen Tozer LLVM_DEBUG(dbgs() << " linked to " << *Assign << "\n"); 16991d1de746SOCHyams LLVM_DEBUG(dbgs() << " LiveLoc " << locStr(getLocKind(LiveSet, Var)) 17001d1de746SOCHyams << " -> "); 17011d1de746SOCHyams 17021d1de746SOCHyams // The last assignment to the stack is now AV. Check if the last debug 17031d1de746SOCHyams // assignment has a matching Assignment. 1704d5b2c8e5SOCHyams if (hasVarWithAssignment(LiveSet, BlockInfo::Debug, Var, AV)) { 17051d1de746SOCHyams // The StackHomeValue and DebugValue for this variable match so we can 17061d1de746SOCHyams // emit a stack home location here. 17071d1de746SOCHyams LLVM_DEBUG(dbgs() << "Mem, Stack matches Debug program\n";); 17081d1de746SOCHyams LLVM_DEBUG(dbgs() << " Stack val: "; AV.dump(dbgs()); dbgs() << "\n"); 17091d1de746SOCHyams LLVM_DEBUG(dbgs() << " Debug val: "; 1710d5b2c8e5SOCHyams LiveSet->DebugValue[static_cast<unsigned>(Var)].dump(dbgs()); 1711d5b2c8e5SOCHyams dbgs() << "\n"); 17121d1de746SOCHyams setLocKind(LiveSet, Var, LocKind::Mem); 171352665432SStephen Tozer emitDbgValue(LocKind::Mem, Assign, &I); 171452665432SStephen Tozer return; 17151d1de746SOCHyams } 17161d1de746SOCHyams 17171d1de746SOCHyams // The StackHomeValue and DebugValue for this variable do not match. I.e. 17181d1de746SOCHyams // The value currently stored in the stack is not what we'd expect to 17191d1de746SOCHyams // see, so we cannot use emit a stack home location here. Now we will 17201d1de746SOCHyams // look at the live LocKind for the variable and determine an appropriate 17211d1de746SOCHyams // dbg.value to emit. 17221d1de746SOCHyams LocKind PrevLoc = getLocKind(LiveSet, Var); 17231d1de746SOCHyams switch (PrevLoc) { 17241d1de746SOCHyams case LocKind::Val: { 17251d1de746SOCHyams // The value in memory in memory has changed but we're not currently 17261d1de746SOCHyams // using the memory location. Do nothing. 17271d1de746SOCHyams LLVM_DEBUG(dbgs() << "Val, (unchanged)\n";); 17281d1de746SOCHyams setLocKind(LiveSet, Var, LocKind::Val); 17291d1de746SOCHyams } break; 17301d1de746SOCHyams case LocKind::Mem: { 17311d1de746SOCHyams // There's been an assignment to memory that we were using as a 17321d1de746SOCHyams // location for this variable, and the Assignment doesn't match what 17331d1de746SOCHyams // we'd expect to see in memory. 1734d5b2c8e5SOCHyams Assignment DbgAV = LiveSet->getAssignment(BlockInfo::Debug, Var); 1735d5b2c8e5SOCHyams if (DbgAV.Status == Assignment::NoneOrPhi) { 17361d1de746SOCHyams // We need to terminate any previously open location now. 17371d1de746SOCHyams LLVM_DEBUG(dbgs() << "None, No Debug value available\n";); 17381d1de746SOCHyams setLocKind(LiveSet, Var, LocKind::None); 173952665432SStephen Tozer emitDbgValue(LocKind::None, Assign, &I); 17401d1de746SOCHyams } else { 17411d1de746SOCHyams // The previous DebugValue Value can be used here. 17421d1de746SOCHyams LLVM_DEBUG(dbgs() << "Val, Debug value is Known\n";); 17431d1de746SOCHyams setLocKind(LiveSet, Var, LocKind::Val); 1744d5b2c8e5SOCHyams if (DbgAV.Source) { 1745d5b2c8e5SOCHyams emitDbgValue(LocKind::Val, DbgAV.Source, &I); 17461d1de746SOCHyams } else { 17471d1de746SOCHyams // PrevAV.Source is nullptr so we must emit undef here. 174852665432SStephen Tozer emitDbgValue(LocKind::None, Assign, &I); 17491d1de746SOCHyams } 17501d1de746SOCHyams } 17511d1de746SOCHyams } break; 17521d1de746SOCHyams case LocKind::None: { 17531d1de746SOCHyams // There's been an assignment to memory and we currently are 17541d1de746SOCHyams // not tracking a location for the variable. Do not emit anything. 17551d1de746SOCHyams LLVM_DEBUG(dbgs() << "None, (unchanged)\n";); 17561d1de746SOCHyams setLocKind(LiveSet, Var, LocKind::None); 17571d1de746SOCHyams } break; 17581d1de746SOCHyams } 175952665432SStephen Tozer }; 176052665432SStephen Tozer for (DbgAssignIntrinsic *DAI : Linked) 176152665432SStephen Tozer ProcessLinkedAssign(DAI); 1762ffd08c77SStephen Tozer for (DbgVariableRecord *DVR : LinkedDPAssigns) 1763ffd08c77SStephen Tozer ProcessLinkedAssign(DVR); 17641d1de746SOCHyams } 17651d1de746SOCHyams 176652665432SStephen Tozer void AssignmentTrackingLowering::processDbgAssign(AssignRecord Assign, 17671d1de746SOCHyams BlockInfo *LiveSet) { 176852665432SStephen Tozer auto ProcessDbgAssignImpl = [&](auto *DbgAssign) { 17691d1de746SOCHyams // Only bother tracking variables that are at some point stack homed. Other 17701d1de746SOCHyams // variables can be dealt with trivially later. 177152665432SStephen Tozer if (!VarsWithStackSlot->count(getAggregate(DbgAssign))) 17721d1de746SOCHyams return; 17731d1de746SOCHyams 177452665432SStephen Tozer VariableID Var = getVariableID(DebugVariable(DbgAssign)); 177552665432SStephen Tozer Assignment AV = Assignment::make(getIDFromMarker(*DbgAssign), DbgAssign); 17761d1de746SOCHyams addDbgDef(LiveSet, Var, AV); 17771d1de746SOCHyams 177852665432SStephen Tozer LLVM_DEBUG(dbgs() << "processDbgAssign on " << *DbgAssign << "\n";); 17791d1de746SOCHyams LLVM_DEBUG(dbgs() << " LiveLoc " << locStr(getLocKind(LiveSet, Var)) 17801d1de746SOCHyams << " -> "); 17811d1de746SOCHyams 17821d1de746SOCHyams // Check if the DebugValue and StackHomeValue both hold the same 17831d1de746SOCHyams // Assignment. 1784d5b2c8e5SOCHyams if (hasVarWithAssignment(LiveSet, BlockInfo::Stack, Var, AV)) { 178552665432SStephen Tozer // They match. We can use the stack home because the debug intrinsics 178652665432SStephen Tozer // state that an assignment happened here, and we know that specific 178752665432SStephen Tozer // assignment was the last one to take place in memory for this variable. 17881d1de746SOCHyams LocKind Kind; 178952665432SStephen Tozer if (DbgAssign->isKillAddress()) { 17901d1de746SOCHyams LLVM_DEBUG( 179183f7f86eSOCHyams dbgs() 179283f7f86eSOCHyams << "Val, Stack matches Debug program but address is killed\n";); 17931d1de746SOCHyams Kind = LocKind::Val; 17941d1de746SOCHyams } else { 17951d1de746SOCHyams LLVM_DEBUG(dbgs() << "Mem, Stack matches Debug program\n";); 17961d1de746SOCHyams Kind = LocKind::Mem; 17971d1de746SOCHyams }; 17981d1de746SOCHyams setLocKind(LiveSet, Var, Kind); 179952665432SStephen Tozer emitDbgValue(Kind, DbgAssign, DbgAssign); 18001d1de746SOCHyams } else { 180152665432SStephen Tozer // The last assignment to the memory location isn't the one that we want 180252665432SStephen Tozer // to show to the user so emit a dbg.value(Value). Value may be undef. 18031d1de746SOCHyams LLVM_DEBUG(dbgs() << "Val, Stack contents is unknown\n";); 18041d1de746SOCHyams setLocKind(LiveSet, Var, LocKind::Val); 180552665432SStephen Tozer emitDbgValue(LocKind::Val, DbgAssign, DbgAssign); 18061d1de746SOCHyams } 180752665432SStephen Tozer }; 1808ffd08c77SStephen Tozer if (isa<DbgVariableRecord *>(Assign)) 1809ffd08c77SStephen Tozer return ProcessDbgAssignImpl(cast<DbgVariableRecord *>(Assign)); 181052665432SStephen Tozer return ProcessDbgAssignImpl(cast<DbgAssignIntrinsic *>(Assign)); 18111d1de746SOCHyams } 18121d1de746SOCHyams 181352665432SStephen Tozer void AssignmentTrackingLowering::processDbgValue( 1814ffd08c77SStephen Tozer PointerUnion<DbgValueInst *, DbgVariableRecord *> DbgValueRecord, 18151d1de746SOCHyams BlockInfo *LiveSet) { 181652665432SStephen Tozer auto ProcessDbgValueImpl = [&](auto *DbgValue) { 18171d1de746SOCHyams // Only other tracking variables that are at some point stack homed. 18181d1de746SOCHyams // Other variables can be dealt with trivally later. 181952665432SStephen Tozer if (!VarsWithStackSlot->count(getAggregate(DbgValue))) 18201d1de746SOCHyams return; 18211d1de746SOCHyams 182252665432SStephen Tozer VariableID Var = getVariableID(DebugVariable(DbgValue)); 18231d1de746SOCHyams // We have no ID to create an Assignment with so we mark this assignment as 18241d1de746SOCHyams // NoneOrPhi. Note that the dbg.value still exists, we just cannot determine 18251d1de746SOCHyams // the assignment responsible for setting this value. 18261d1de746SOCHyams // This is fine; dbg.values are essentially interchangable with unlinked 18271d1de746SOCHyams // dbg.assigns, and some passes such as mem2reg and instcombine add them to 18281d1de746SOCHyams // PHIs for promoted variables. 18291d1de746SOCHyams Assignment AV = Assignment::makeNoneOrPhi(); 18301d1de746SOCHyams addDbgDef(LiveSet, Var, AV); 18311d1de746SOCHyams 183252665432SStephen Tozer LLVM_DEBUG(dbgs() << "processDbgValue on " << *DbgValue << "\n";); 18331d1de746SOCHyams LLVM_DEBUG(dbgs() << " LiveLoc " << locStr(getLocKind(LiveSet, Var)) 18341d1de746SOCHyams << " -> Val, dbg.value override"); 18351d1de746SOCHyams 18361d1de746SOCHyams setLocKind(LiveSet, Var, LocKind::Val); 183752665432SStephen Tozer emitDbgValue(LocKind::Val, DbgValue, DbgValue); 183852665432SStephen Tozer }; 1839ffd08c77SStephen Tozer if (isa<DbgVariableRecord *>(DbgValueRecord)) 1840ffd08c77SStephen Tozer return ProcessDbgValueImpl(cast<DbgVariableRecord *>(DbgValueRecord)); 184152665432SStephen Tozer return ProcessDbgValueImpl(cast<DbgValueInst *>(DbgValueRecord)); 18421d1de746SOCHyams } 18431d1de746SOCHyams 18446aeb7a71SStephen Tozer template <typename T> static bool hasZeroSizedFragment(T &DbgValue) { 18456aeb7a71SStephen Tozer if (auto F = DbgValue.getExpression()->getFragmentInfo()) 184693c194fcSOCHyams return F->SizeInBits == 0; 184793c194fcSOCHyams return false; 184893c194fcSOCHyams } 184993c194fcSOCHyams 18501d1de746SOCHyams void AssignmentTrackingLowering::processDbgInstruction( 185193c194fcSOCHyams DbgInfoIntrinsic &I, AssignmentTrackingLowering::BlockInfo *LiveSet) { 185293c194fcSOCHyams auto *DVI = dyn_cast<DbgVariableIntrinsic>(&I); 185393c194fcSOCHyams if (!DVI) 185493c194fcSOCHyams return; 185593c194fcSOCHyams 185693c194fcSOCHyams // Ignore assignments to zero bits of the variable. 185793c194fcSOCHyams if (hasZeroSizedFragment(*DVI)) 185893c194fcSOCHyams return; 185993c194fcSOCHyams 18601d1de746SOCHyams if (auto *DAI = dyn_cast<DbgAssignIntrinsic>(&I)) 186152665432SStephen Tozer processDbgAssign(DAI, LiveSet); 18621d1de746SOCHyams else if (auto *DVI = dyn_cast<DbgValueInst>(&I)) 186352665432SStephen Tozer processDbgValue(DVI, LiveSet); 186452665432SStephen Tozer } 1865ffd08c77SStephen Tozer void AssignmentTrackingLowering::processDbgVariableRecord( 1866ffd08c77SStephen Tozer DbgVariableRecord &DVR, AssignmentTrackingLowering::BlockInfo *LiveSet) { 186752665432SStephen Tozer // Ignore assignments to zero bits of the variable. 1868ffd08c77SStephen Tozer if (hasZeroSizedFragment(DVR)) 186952665432SStephen Tozer return; 187052665432SStephen Tozer 1871ffd08c77SStephen Tozer if (DVR.isDbgAssign()) 1872ffd08c77SStephen Tozer processDbgAssign(&DVR, LiveSet); 1873ffd08c77SStephen Tozer else if (DVR.isDbgValue()) 1874ffd08c77SStephen Tozer processDbgValue(&DVR, LiveSet); 18751d1de746SOCHyams } 18761d1de746SOCHyams 18771d1de746SOCHyams void AssignmentTrackingLowering::resetInsertionPoint(Instruction &After) { 18781d1de746SOCHyams assert(!After.isTerminator() && "Can't insert after a terminator"); 187952665432SStephen Tozer auto *R = InsertBeforeMap.find(getNextNode(&After)); 188052665432SStephen Tozer if (R == InsertBeforeMap.end()) 188152665432SStephen Tozer return; 188252665432SStephen Tozer R->second.clear(); 188352665432SStephen Tozer } 1884ffd08c77SStephen Tozer void AssignmentTrackingLowering::resetInsertionPoint(DbgVariableRecord &After) { 188552665432SStephen Tozer auto *R = InsertBeforeMap.find(getNextNode(&After)); 18861d1de746SOCHyams if (R == InsertBeforeMap.end()) 18871d1de746SOCHyams return; 18881d1de746SOCHyams R->second.clear(); 18891d1de746SOCHyams } 18901d1de746SOCHyams 18911d1de746SOCHyams void AssignmentTrackingLowering::process(BasicBlock &BB, BlockInfo *LiveSet) { 1892360da838SStephen Tozer // If the block starts with DbgRecords, we need to process those DbgRecords as 189352665432SStephen Tozer // their own frame without processing any instructions first. 1894360da838SStephen Tozer bool ProcessedLeadingDbgRecords = !BB.begin()->hasDbgRecords(); 18951d1de746SOCHyams for (auto II = BB.begin(), EI = BB.end(); II != EI;) { 18961d1de746SOCHyams assert(VarsTouchedThisFrame.empty()); 18971d1de746SOCHyams // Process the instructions in "frames". A "frame" includes a single 18981d1de746SOCHyams // non-debug instruction followed any debug instructions before the 18991d1de746SOCHyams // next non-debug instruction. 190052665432SStephen Tozer 1901360da838SStephen Tozer // Skip the current instruction if it has unprocessed DbgRecords attached 1902360da838SStephen Tozer // (see comment above `ProcessedLeadingDbgRecords`). 1903360da838SStephen Tozer if (ProcessedLeadingDbgRecords) { 190452665432SStephen Tozer // II is now either a debug intrinsic, a non-debug instruction with no 1905360da838SStephen Tozer // attached DbgRecords, or a non-debug instruction with attached processed 1906360da838SStephen Tozer // DbgRecords. 190752665432SStephen Tozer // II has not been processed. 19081d1de746SOCHyams if (!isa<DbgInfoIntrinsic>(&*II)) { 19091d1de746SOCHyams if (II->isTerminator()) 19101d1de746SOCHyams break; 19111d1de746SOCHyams resetInsertionPoint(*II); 19121d1de746SOCHyams processNonDbgInstruction(*II, LiveSet); 19131d1de746SOCHyams assert(LiveSet->isValid()); 19141d1de746SOCHyams ++II; 19151d1de746SOCHyams } 191652665432SStephen Tozer } 191752665432SStephen Tozer // II is now either a debug intrinsic, a non-debug instruction with no 1918360da838SStephen Tozer // attached DbgRecords, or a non-debug instruction with attached unprocessed 1919360da838SStephen Tozer // DbgRecords. 192015f3f446SStephen Tozer if (II != EI && II->hasDbgRecords()) { 19218a164220SOrlando Cazalet-Hyams // Skip over non-variable debug records (i.e., labels). They're going to 19228a164220SOrlando Cazalet-Hyams // be read from IR (possibly re-ordering them within the debug record 19238a164220SOrlando Cazalet-Hyams // range) rather than from the analysis results. 1924ffd08c77SStephen Tozer for (DbgVariableRecord &DVR : filterDbgVars(II->getDbgRecordRange())) { 1925ffd08c77SStephen Tozer resetInsertionPoint(DVR); 1926ffd08c77SStephen Tozer processDbgVariableRecord(DVR, LiveSet); 192752665432SStephen Tozer assert(LiveSet->isValid()); 192852665432SStephen Tozer } 192952665432SStephen Tozer } 1930360da838SStephen Tozer ProcessedLeadingDbgRecords = true; 19311d1de746SOCHyams while (II != EI) { 193293c194fcSOCHyams auto *Dbg = dyn_cast<DbgInfoIntrinsic>(&*II); 193393c194fcSOCHyams if (!Dbg) 19341d1de746SOCHyams break; 19351d1de746SOCHyams resetInsertionPoint(*II); 193693c194fcSOCHyams processDbgInstruction(*Dbg, LiveSet); 19371d1de746SOCHyams assert(LiveSet->isValid()); 19381d1de746SOCHyams ++II; 19391d1de746SOCHyams } 1940360da838SStephen Tozer // II is now a non-debug instruction either with no attached DbgRecords, or 1941360da838SStephen Tozer // with attached processed DbgRecords. II has not been processed, and all 1942360da838SStephen Tozer // debug instructions or DbgRecords in the frame preceding II have been 194352665432SStephen Tozer // processed. 19441d1de746SOCHyams 19451d1de746SOCHyams // We've processed everything in the "frame". Now determine which variables 19461d1de746SOCHyams // cannot be represented by a dbg.declare. 19471d1de746SOCHyams for (auto Var : VarsTouchedThisFrame) { 19481d1de746SOCHyams LocKind Loc = getLocKind(LiveSet, Var); 19491d1de746SOCHyams // If a variable's LocKind is anything other than LocKind::Mem then we 19501d1de746SOCHyams // must note that it cannot be represented with a dbg.declare. 19511d1de746SOCHyams // Note that this check is enough without having to check the result of 19521d1de746SOCHyams // joins() because for join to produce anything other than Mem after 19531d1de746SOCHyams // we've already seen a Mem we'd be joining None or Val with Mem. In that 19541d1de746SOCHyams // case, we've already hit this codepath when we set the LocKind to Val 19551d1de746SOCHyams // or None in that block. 19561d1de746SOCHyams if (Loc != LocKind::Mem) { 19571d1de746SOCHyams DebugVariable DbgVar = FnVarLocs->getVariable(Var); 19581d1de746SOCHyams DebugAggregate Aggr{DbgVar.getVariable(), DbgVar.getInlinedAt()}; 19591d1de746SOCHyams NotAlwaysStackHomed.insert(Aggr); 19601d1de746SOCHyams } 19611d1de746SOCHyams } 19621d1de746SOCHyams VarsTouchedThisFrame.clear(); 19631d1de746SOCHyams } 19641d1de746SOCHyams } 19651d1de746SOCHyams 19661d1de746SOCHyams AssignmentTrackingLowering::LocKind 19671d1de746SOCHyams AssignmentTrackingLowering::joinKind(LocKind A, LocKind B) { 19681d1de746SOCHyams // Partial order: 19691d1de746SOCHyams // None > Mem, Val 19701d1de746SOCHyams return A == B ? A : LocKind::None; 19711d1de746SOCHyams } 19721d1de746SOCHyams 19731d1de746SOCHyams AssignmentTrackingLowering::Assignment 19741d1de746SOCHyams AssignmentTrackingLowering::joinAssignment(const Assignment &A, 19751d1de746SOCHyams const Assignment &B) { 19761d1de746SOCHyams // Partial order: 19771d1de746SOCHyams // NoneOrPhi(null, null) > Known(v, ?s) 19781d1de746SOCHyams 19791d1de746SOCHyams // If either are NoneOrPhi the join is NoneOrPhi. 19801d1de746SOCHyams // If either value is different then the result is 19811d1de746SOCHyams // NoneOrPhi (joining two values is a Phi). 19821d1de746SOCHyams if (!A.isSameSourceAssignment(B)) 19831d1de746SOCHyams return Assignment::makeNoneOrPhi(); 19841d1de746SOCHyams if (A.Status == Assignment::NoneOrPhi) 19851d1de746SOCHyams return Assignment::makeNoneOrPhi(); 19861d1de746SOCHyams 19871d1de746SOCHyams // Source is used to lookup the value + expression in the debug program if 19881d1de746SOCHyams // the stack slot gets assigned a value earlier than expected. Because 19891d1de746SOCHyams // we're only tracking the one dbg.assign, we can't capture debug PHIs. 19901d1de746SOCHyams // It's unlikely that we're losing out on much coverage by avoiding that 19911d1de746SOCHyams // extra work. 19921d1de746SOCHyams // The Source may differ in this situation: 19931d1de746SOCHyams // Pred.1: 19941d1de746SOCHyams // dbg.assign i32 0, ..., !1, ... 19951d1de746SOCHyams // Pred.2: 19961d1de746SOCHyams // dbg.assign i32 1, ..., !1, ... 19971d1de746SOCHyams // Here the same assignment (!1) was performed in both preds in the source, 19981d1de746SOCHyams // but we can't use either one unless they are identical (e.g. .we don't 19991d1de746SOCHyams // want to arbitrarily pick between constant values). 200052665432SStephen Tozer auto JoinSource = [&]() -> AssignRecord { 20011d1de746SOCHyams if (A.Source == B.Source) 20021d1de746SOCHyams return A.Source; 200352665432SStephen Tozer if (!A.Source || !B.Source) 200452665432SStephen Tozer return AssignRecord(); 2005ffd08c77SStephen Tozer assert(isa<DbgVariableRecord *>(A.Source) == 2006ffd08c77SStephen Tozer isa<DbgVariableRecord *>(B.Source)); 2007ffd08c77SStephen Tozer if (isa<DbgVariableRecord *>(A.Source) && 2008ffd08c77SStephen Tozer cast<DbgVariableRecord *>(A.Source)->isEquivalentTo( 2009ffd08c77SStephen Tozer *cast<DbgVariableRecord *>(B.Source))) 20101d1de746SOCHyams return A.Source; 201152665432SStephen Tozer if (isa<DbgAssignIntrinsic *>(A.Source) && 201252665432SStephen Tozer cast<DbgAssignIntrinsic *>(A.Source)->isIdenticalTo( 201352665432SStephen Tozer cast<DbgAssignIntrinsic *>(B.Source))) 201452665432SStephen Tozer return A.Source; 201552665432SStephen Tozer return AssignRecord(); 20161d1de746SOCHyams }; 201752665432SStephen Tozer AssignRecord Source = JoinSource(); 20181d1de746SOCHyams assert(A.Status == B.Status && A.Status == Assignment::Known); 20191d1de746SOCHyams assert(A.ID == B.ID); 20201d1de746SOCHyams return Assignment::make(A.ID, Source); 20211d1de746SOCHyams } 20221d1de746SOCHyams 20231d1de746SOCHyams AssignmentTrackingLowering::BlockInfo 20241d1de746SOCHyams AssignmentTrackingLowering::joinBlockInfo(const BlockInfo &A, 20251d1de746SOCHyams const BlockInfo &B) { 2026d5b2c8e5SOCHyams return BlockInfo::join(A, B, TrackedVariablesVectorSize); 20271d1de746SOCHyams } 20281d1de746SOCHyams 20291d1de746SOCHyams bool AssignmentTrackingLowering::join( 20301d1de746SOCHyams const BasicBlock &BB, const SmallPtrSet<BasicBlock *, 16> &Visited) { 2031c4861e32SOCHyams 2032c4861e32SOCHyams SmallVector<const BasicBlock *> VisitedPreds; 20331d1de746SOCHyams // Ignore backedges if we have not visited the predecessor yet. As the 20341d1de746SOCHyams // predecessor hasn't yet had locations propagated into it, most locations 20351d1de746SOCHyams // will not yet be valid, so treat them as all being uninitialized and 20361d1de746SOCHyams // potentially valid. If a location guessed to be correct here is 20371d1de746SOCHyams // invalidated later, we will remove it when we revisit this block. This 20381d1de746SOCHyams // is essentially the same as initialising all LocKinds and Assignments to 20391d1de746SOCHyams // an implicit ⊥ value which is the identity value for the join operation. 204071ca5c54SKazu Hirata for (const BasicBlock *Pred : predecessors(&BB)) { 2041c4861e32SOCHyams if (Visited.count(Pred)) 2042c4861e32SOCHyams VisitedPreds.push_back(Pred); 20431d1de746SOCHyams } 20441d1de746SOCHyams 2045c4861e32SOCHyams // No preds visited yet. 2046c4861e32SOCHyams if (VisitedPreds.empty()) { 2047c4861e32SOCHyams auto It = LiveIn.try_emplace(&BB, BlockInfo()); 2048c4861e32SOCHyams bool DidInsert = It.second; 2049c4861e32SOCHyams if (DidInsert) 2050c4861e32SOCHyams It.first->second.init(TrackedVariablesVectorSize); 2051c4861e32SOCHyams return /*Changed*/ DidInsert; 2052c4861e32SOCHyams } 2053d5b2c8e5SOCHyams 2054c4861e32SOCHyams // Exactly one visited pred. Copy the LiveOut from that pred into BB LiveIn. 2055c4861e32SOCHyams if (VisitedPreds.size() == 1) { 2056c4861e32SOCHyams const BlockInfo &PredLiveOut = LiveOut.find(VisitedPreds[0])->second; 2057c4861e32SOCHyams auto CurrentLiveInEntry = LiveIn.find(&BB); 2058c4861e32SOCHyams 2059c4861e32SOCHyams // Check if there isn't an entry, or there is but the LiveIn set has 2060c4861e32SOCHyams // changed (expensive check). 2061c4861e32SOCHyams if (CurrentLiveInEntry == LiveIn.end()) 2062c4861e32SOCHyams LiveIn.insert(std::make_pair(&BB, PredLiveOut)); 2063c4861e32SOCHyams else if (PredLiveOut != CurrentLiveInEntry->second) 2064c4861e32SOCHyams CurrentLiveInEntry->second = PredLiveOut; 2065c4861e32SOCHyams else 2066c4861e32SOCHyams return /*Changed*/ false; 2067c4861e32SOCHyams return /*Changed*/ true; 2068c4861e32SOCHyams } 2069c4861e32SOCHyams 2070c4861e32SOCHyams // More than one pred. Join LiveOuts of blocks 1 and 2. 2071c4861e32SOCHyams assert(VisitedPreds.size() > 1); 2072c4861e32SOCHyams const BlockInfo &PredLiveOut0 = LiveOut.find(VisitedPreds[0])->second; 2073c4861e32SOCHyams const BlockInfo &PredLiveOut1 = LiveOut.find(VisitedPreds[1])->second; 2074c4861e32SOCHyams BlockInfo BBLiveIn = joinBlockInfo(PredLiveOut0, PredLiveOut1); 2075c4861e32SOCHyams 2076c4861e32SOCHyams // Join the LiveOuts of subsequent blocks. 2077c4861e32SOCHyams ArrayRef Tail = ArrayRef(VisitedPreds).drop_front(2); 2078c4861e32SOCHyams for (const BasicBlock *Pred : Tail) { 2079c4861e32SOCHyams const auto &PredLiveOut = LiveOut.find(Pred); 2080c4861e32SOCHyams assert(PredLiveOut != LiveOut.end() && 2081c4861e32SOCHyams "block should have been processed already"); 2082c4861e32SOCHyams BBLiveIn = joinBlockInfo(std::move(BBLiveIn), PredLiveOut->second); 2083c4861e32SOCHyams } 2084c4861e32SOCHyams 2085c4861e32SOCHyams // Save the joined result for BB. 20861d1de746SOCHyams auto CurrentLiveInEntry = LiveIn.find(&BB); 20871d1de746SOCHyams // Check if there isn't an entry, or there is but the LiveIn set has changed 20881d1de746SOCHyams // (expensive check). 2089c4861e32SOCHyams if (CurrentLiveInEntry == LiveIn.end()) 2090c4861e32SOCHyams LiveIn.try_emplace(&BB, std::move(BBLiveIn)); 2091c4861e32SOCHyams else if (BBLiveIn != CurrentLiveInEntry->second) 2092c4861e32SOCHyams CurrentLiveInEntry->second = std::move(BBLiveIn); 2093c4861e32SOCHyams else 2094c4861e32SOCHyams return /*Changed*/ false; 2095c4861e32SOCHyams return /*Changed*/ true; 20961d1de746SOCHyams } 20971d1de746SOCHyams 20981d1de746SOCHyams /// Return true if A fully contains B. 20991d1de746SOCHyams static bool fullyContains(DIExpression::FragmentInfo A, 21001d1de746SOCHyams DIExpression::FragmentInfo B) { 21011d1de746SOCHyams auto ALeft = A.OffsetInBits; 21021d1de746SOCHyams auto BLeft = B.OffsetInBits; 21031d1de746SOCHyams if (BLeft < ALeft) 21041d1de746SOCHyams return false; 21051d1de746SOCHyams 21061d1de746SOCHyams auto ARight = ALeft + A.SizeInBits; 21071d1de746SOCHyams auto BRight = BLeft + B.SizeInBits; 21081d1de746SOCHyams if (BRight > ARight) 21091d1de746SOCHyams return false; 21101d1de746SOCHyams return true; 21111d1de746SOCHyams } 21121d1de746SOCHyams 21131d1de746SOCHyams static std::optional<at::AssignmentInfo> 21141d1de746SOCHyams getUntaggedStoreAssignmentInfo(const Instruction &I, const DataLayout &Layout) { 21151d1de746SOCHyams // Don't bother checking if this is an AllocaInst. We know this 21161d1de746SOCHyams // instruction has no tag which means there are no variables associated 21171d1de746SOCHyams // with it. 21181d1de746SOCHyams if (const auto *SI = dyn_cast<StoreInst>(&I)) 21191d1de746SOCHyams return at::getAssignmentInfo(Layout, SI); 21201d1de746SOCHyams if (const auto *MI = dyn_cast<MemIntrinsic>(&I)) 21211d1de746SOCHyams return at::getAssignmentInfo(Layout, MI); 21221d1de746SOCHyams // Alloca or non-store-like inst. 21231d1de746SOCHyams return std::nullopt; 21241d1de746SOCHyams } 21251d1de746SOCHyams 212652665432SStephen Tozer DbgDeclareInst *DynCastToDbgDeclare(DbgVariableIntrinsic *DVI) { 212752665432SStephen Tozer return dyn_cast<DbgDeclareInst>(DVI); 212852665432SStephen Tozer } 212952665432SStephen Tozer 2130ffd08c77SStephen Tozer DbgVariableRecord *DynCastToDbgDeclare(DbgVariableRecord *DVR) { 2131ffd08c77SStephen Tozer return DVR->isDbgDeclare() ? DVR : nullptr; 213252665432SStephen Tozer } 213352665432SStephen Tozer 21341d1de746SOCHyams /// Build a map of {Variable x: Variables y} where all variable fragments 21351d1de746SOCHyams /// contained within the variable fragment x are in set y. This means that 21361d1de746SOCHyams /// y does not contain all overlaps because partial overlaps are excluded. 21371d1de746SOCHyams /// 21381d1de746SOCHyams /// While we're iterating over the function, add single location defs for 2139d5b2c8e5SOCHyams /// dbg.declares to \p FnVarLocs. 2140d5b2c8e5SOCHyams /// 2141d5b2c8e5SOCHyams /// Variables that are interesting to this pass in are added to 2142d5b2c8e5SOCHyams /// FnVarLocs->Variables first. TrackedVariablesVectorSize is set to the ID of 2143d5b2c8e5SOCHyams /// the last interesting variable plus 1, meaning variables with ID 1 2144d5b2c8e5SOCHyams /// (inclusive) to TrackedVariablesVectorSize (exclusive) are interesting. The 2145d5b2c8e5SOCHyams /// subsequent variables are either stack homed or fully promoted. 21461d1de746SOCHyams /// 21471d1de746SOCHyams /// Finally, populate UntaggedStoreVars with a mapping of untagged stores to 21481d1de746SOCHyams /// the stored-to variable fragments. 21491d1de746SOCHyams /// 21501d1de746SOCHyams /// These tasks are bundled together to reduce the number of times we need 21511d1de746SOCHyams /// to iterate over the function as they can be achieved together in one pass. 21521d1de746SOCHyams static AssignmentTrackingLowering::OverlapMap buildOverlapMapAndRecordDeclares( 21531d1de746SOCHyams Function &Fn, FunctionVarLocsBuilder *FnVarLocs, 2154cbfeec66SOCHyams const DenseSet<DebugAggregate> &VarsWithStackSlot, 2155d5b2c8e5SOCHyams AssignmentTrackingLowering::UntaggedStoreAssignmentMap &UntaggedStoreVars, 2156d5b2c8e5SOCHyams unsigned &TrackedVariablesVectorSize) { 21571d1de746SOCHyams DenseSet<DebugVariable> Seen; 21581d1de746SOCHyams // Map of Variable: [Fragments]. 21591d1de746SOCHyams DenseMap<DebugAggregate, SmallVector<DebugVariable, 8>> FragmentMap; 21601d1de746SOCHyams // Iterate over all instructions: 21611d1de746SOCHyams // - dbg.declare -> add single location variable record 21621d1de746SOCHyams // - dbg.* -> Add fragments to FragmentMap 21631d1de746SOCHyams // - untagged store -> Add fragments to FragmentMap and update 21641d1de746SOCHyams // UntaggedStoreVars. 21651d1de746SOCHyams // We need to add fragments for untagged stores too so that we can correctly 21661d1de746SOCHyams // clobber overlapped fragment locations later. 216752665432SStephen Tozer SmallVector<DbgDeclareInst *> InstDeclares; 2168ffd08c77SStephen Tozer SmallVector<DbgVariableRecord *> DPDeclares; 216952665432SStephen Tozer auto ProcessDbgRecord = [&](auto *Record, auto &DeclareList) { 217052665432SStephen Tozer if (auto *Declare = DynCastToDbgDeclare(Record)) { 217152665432SStephen Tozer DeclareList.push_back(Declare); 217252665432SStephen Tozer return; 217352665432SStephen Tozer } 217452665432SStephen Tozer DebugVariable DV = DebugVariable(Record); 21751d1de746SOCHyams DebugAggregate DA = {DV.getVariable(), DV.getInlinedAt()}; 2176cbfeec66SOCHyams if (!VarsWithStackSlot.contains(DA)) 217752665432SStephen Tozer return; 21781d1de746SOCHyams if (Seen.insert(DV).second) 21791d1de746SOCHyams FragmentMap[DA].push_back(DV); 218052665432SStephen Tozer }; 218152665432SStephen Tozer for (auto &BB : Fn) { 218252665432SStephen Tozer for (auto &I : BB) { 2183ffd08c77SStephen Tozer for (DbgVariableRecord &DVR : filterDbgVars(I.getDbgRecordRange())) 2184ffd08c77SStephen Tozer ProcessDbgRecord(&DVR, DPDeclares); 218552665432SStephen Tozer if (auto *DII = dyn_cast<DbgVariableIntrinsic>(&I)) { 218652665432SStephen Tozer ProcessDbgRecord(DII, InstDeclares); 21871d1de746SOCHyams } else if (auto Info = getUntaggedStoreAssignmentInfo( 21889df71d76SNikita Popov I, Fn.getDataLayout())) { 21891d1de746SOCHyams // Find markers linked to this alloca. 219052665432SStephen Tozer auto HandleDbgAssignForStore = [&](auto *Assign) { 21917afc7db7SOrlando Cazalet-Hyams std::optional<DIExpression::FragmentInfo> FragInfo; 21927afc7db7SOrlando Cazalet-Hyams 21937afc7db7SOrlando Cazalet-Hyams // Skip this assignment if the affected bits are outside of the 21947afc7db7SOrlando Cazalet-Hyams // variable fragment. 21957afc7db7SOrlando Cazalet-Hyams if (!at::calculateFragmentIntersect( 21962d209d96SNikita Popov I.getDataLayout(), Info->Base, 219752665432SStephen Tozer Info->OffsetInBits, Info->SizeInBits, Assign, FragInfo) || 21987afc7db7SOrlando Cazalet-Hyams (FragInfo && FragInfo->SizeInBits == 0)) 219952665432SStephen Tozer return; 22007afc7db7SOrlando Cazalet-Hyams 22017afc7db7SOrlando Cazalet-Hyams // FragInfo from calculateFragmentIntersect is nullopt if the 22027afc7db7SOrlando Cazalet-Hyams // resultant fragment matches DAI's fragment or entire variable - in 22037afc7db7SOrlando Cazalet-Hyams // which case copy the fragment info from DAI. If FragInfo is still 22047afc7db7SOrlando Cazalet-Hyams // nullopt after the copy it means "no fragment info" instead, which 22057afc7db7SOrlando Cazalet-Hyams // is how it is usually interpreted. 22067afc7db7SOrlando Cazalet-Hyams if (!FragInfo) 220752665432SStephen Tozer FragInfo = Assign->getExpression()->getFragmentInfo(); 22081d1de746SOCHyams 220952665432SStephen Tozer DebugVariable DV = 221052665432SStephen Tozer DebugVariable(Assign->getVariable(), FragInfo, 221152665432SStephen Tozer Assign->getDebugLoc().getInlinedAt()); 22121d1de746SOCHyams DebugAggregate DA = {DV.getVariable(), DV.getInlinedAt()}; 2213cbfeec66SOCHyams if (!VarsWithStackSlot.contains(DA)) 221452665432SStephen Tozer return; 22151d1de746SOCHyams 22161d1de746SOCHyams // Cache this info for later. 22171d1de746SOCHyams UntaggedStoreVars[&I].push_back( 22181d1de746SOCHyams {FnVarLocs->insertVariable(DV), *Info}); 22191d1de746SOCHyams 22201d1de746SOCHyams if (Seen.insert(DV).second) 22211d1de746SOCHyams FragmentMap[DA].push_back(DV); 222252665432SStephen Tozer }; 222352665432SStephen Tozer for (DbgAssignIntrinsic *DAI : at::getAssignmentMarkers(Info->Base)) 222452665432SStephen Tozer HandleDbgAssignForStore(DAI); 2225ffd08c77SStephen Tozer for (DbgVariableRecord *DVR : at::getDVRAssignmentMarkers(Info->Base)) 2226ffd08c77SStephen Tozer HandleDbgAssignForStore(DVR); 22271d1de746SOCHyams } 22281d1de746SOCHyams } 22291d1de746SOCHyams } 22301d1de746SOCHyams 2231b59d672eSOCHyams // Sort the fragment map for each DebugAggregate in ascending 2232b59d672eSOCHyams // order of fragment size - there should be no duplicates. 22331d1de746SOCHyams for (auto &Pair : FragmentMap) { 22341d1de746SOCHyams SmallVector<DebugVariable, 8> &Frags = Pair.second; 2235fef144ceSKazu Hirata std::sort(Frags.begin(), Frags.end(), 2236fef144ceSKazu Hirata [](const DebugVariable &Next, const DebugVariable &Elmt) { 22371d1de746SOCHyams return Elmt.getFragmentOrDefault().SizeInBits > 22381d1de746SOCHyams Next.getFragmentOrDefault().SizeInBits; 22391d1de746SOCHyams }); 2240b59d672eSOCHyams // Check for duplicates. 2241b59d672eSOCHyams assert(std::adjacent_find(Frags.begin(), Frags.end()) == Frags.end()); 22421d1de746SOCHyams } 22431d1de746SOCHyams 22441d1de746SOCHyams // Build the map. 22451d1de746SOCHyams AssignmentTrackingLowering::OverlapMap Map; 224666268c8eSWang, Xin10 for (auto &Pair : FragmentMap) { 22471d1de746SOCHyams auto &Frags = Pair.second; 22481d1de746SOCHyams for (auto It = Frags.begin(), IEnd = Frags.end(); It != IEnd; ++It) { 22491d1de746SOCHyams DIExpression::FragmentInfo Frag = It->getFragmentOrDefault(); 22501d1de746SOCHyams // Find the frags that this is contained within. 22511d1de746SOCHyams // 22521d1de746SOCHyams // Because Frags is sorted by size and none have the same offset and 22531d1de746SOCHyams // size, we know that this frag can only be contained by subsequent 22541d1de746SOCHyams // elements. 22551d1de746SOCHyams SmallVector<DebugVariable, 8>::iterator OtherIt = It; 22561d1de746SOCHyams ++OtherIt; 22571d1de746SOCHyams VariableID ThisVar = FnVarLocs->insertVariable(*It); 22581d1de746SOCHyams for (; OtherIt != IEnd; ++OtherIt) { 22591d1de746SOCHyams DIExpression::FragmentInfo OtherFrag = OtherIt->getFragmentOrDefault(); 22601d1de746SOCHyams VariableID OtherVar = FnVarLocs->insertVariable(*OtherIt); 22611d1de746SOCHyams if (fullyContains(OtherFrag, Frag)) 22621d1de746SOCHyams Map[OtherVar].push_back(ThisVar); 22631d1de746SOCHyams } 22641d1de746SOCHyams } 22651d1de746SOCHyams } 22661d1de746SOCHyams 2267d5b2c8e5SOCHyams // VariableIDs are 1-based so the variable-tracking bitvector needs 2268d5b2c8e5SOCHyams // NumVariables plus 1 bits. 2269d5b2c8e5SOCHyams TrackedVariablesVectorSize = FnVarLocs->getNumVariables() + 1; 2270d5b2c8e5SOCHyams 2271d5b2c8e5SOCHyams // Finally, insert the declares afterwards, so the first IDs are all 2272d5b2c8e5SOCHyams // partially stack homed vars. 227352665432SStephen Tozer for (auto *DDI : InstDeclares) 2274d5b2c8e5SOCHyams FnVarLocs->addSingleLocVar(DebugVariable(DDI), DDI->getExpression(), 2275d5b2c8e5SOCHyams DDI->getDebugLoc(), DDI->getWrappedLocation()); 2276ffd08c77SStephen Tozer for (auto *DVR : DPDeclares) 2277ffd08c77SStephen Tozer FnVarLocs->addSingleLocVar(DebugVariable(DVR), DVR->getExpression(), 2278ffd08c77SStephen Tozer DVR->getDebugLoc(), 2279ffd08c77SStephen Tozer RawLocationWrapper(DVR->getRawLocation())); 22801d1de746SOCHyams return Map; 22811d1de746SOCHyams } 22821d1de746SOCHyams 22831d1de746SOCHyams bool AssignmentTrackingLowering::run(FunctionVarLocsBuilder *FnVarLocsBuilder) { 22841d1de746SOCHyams if (Fn.size() > MaxNumBlocks) { 22851d1de746SOCHyams LLVM_DEBUG(dbgs() << "[AT] Dropping var locs in: " << Fn.getName() 22861d1de746SOCHyams << ": too many blocks (" << Fn.size() << ")\n"); 22871d1de746SOCHyams at::deleteAll(&Fn); 22881d1de746SOCHyams return false; 22891d1de746SOCHyams } 22901d1de746SOCHyams 22911d1de746SOCHyams FnVarLocs = FnVarLocsBuilder; 22921d1de746SOCHyams 22931d1de746SOCHyams // The general structure here is inspired by VarLocBasedImpl.cpp 22941d1de746SOCHyams // (LiveDebugValues). 22951d1de746SOCHyams 22961d1de746SOCHyams // Build the variable fragment overlap map. 22971d1de746SOCHyams // Note that this pass doesn't handle partial overlaps correctly (FWIW 22981d1de746SOCHyams // neither does LiveDebugVariables) because that is difficult to do and 22991d1de746SOCHyams // appears to be rare occurance. 2300d5b2c8e5SOCHyams VarContains = buildOverlapMapAndRecordDeclares( 2301cbfeec66SOCHyams Fn, FnVarLocs, *VarsWithStackSlot, UntaggedStoreVars, 2302cbfeec66SOCHyams TrackedVariablesVectorSize); 23031d1de746SOCHyams 23041d1de746SOCHyams // Prepare for traversal. 23051d1de746SOCHyams ReversePostOrderTraversal<Function *> RPOT(&Fn); 23061d1de746SOCHyams std::priority_queue<unsigned int, std::vector<unsigned int>, 23071d1de746SOCHyams std::greater<unsigned int>> 23081d1de746SOCHyams Worklist; 23091d1de746SOCHyams std::priority_queue<unsigned int, std::vector<unsigned int>, 23101d1de746SOCHyams std::greater<unsigned int>> 23111d1de746SOCHyams Pending; 23121d1de746SOCHyams DenseMap<unsigned int, BasicBlock *> OrderToBB; 23131d1de746SOCHyams DenseMap<BasicBlock *, unsigned int> BBToOrder; 23141d1de746SOCHyams { // Init OrderToBB and BBToOrder. 23151d1de746SOCHyams unsigned int RPONumber = 0; 2316dae061f1SKazu Hirata for (BasicBlock *BB : RPOT) { 2317dae061f1SKazu Hirata OrderToBB[RPONumber] = BB; 2318dae061f1SKazu Hirata BBToOrder[BB] = RPONumber; 23191d1de746SOCHyams Worklist.push(RPONumber); 23201d1de746SOCHyams ++RPONumber; 23211d1de746SOCHyams } 23221d1de746SOCHyams LiveIn.init(RPONumber); 23231d1de746SOCHyams LiveOut.init(RPONumber); 23241d1de746SOCHyams } 23251d1de746SOCHyams 23261d1de746SOCHyams // Perform the traversal. 23271d1de746SOCHyams // 23281d1de746SOCHyams // This is a standard "union of predecessor outs" dataflow problem. To solve 23291d1de746SOCHyams // it, we perform join() and process() using the two worklist method until 23301d1de746SOCHyams // the LiveIn data for each block becomes unchanging. The "proof" that this 23311d1de746SOCHyams // terminates can be put together by looking at the comments around LocKind, 23321d1de746SOCHyams // Assignment, and the various join methods, which show that all the elements 23331d1de746SOCHyams // involved are made up of join-semilattices; LiveIn(n) can only 23341d1de746SOCHyams // monotonically increase in value throughout the dataflow. 23351d1de746SOCHyams // 23361d1de746SOCHyams SmallPtrSet<BasicBlock *, 16> Visited; 23371d1de746SOCHyams while (!Worklist.empty()) { 23381d1de746SOCHyams // We track what is on the pending worklist to avoid inserting the same 23391d1de746SOCHyams // thing twice. 23401d1de746SOCHyams SmallPtrSet<BasicBlock *, 16> OnPending; 23411d1de746SOCHyams LLVM_DEBUG(dbgs() << "Processing Worklist\n"); 23421d1de746SOCHyams while (!Worklist.empty()) { 23431d1de746SOCHyams BasicBlock *BB = OrderToBB[Worklist.top()]; 23441d1de746SOCHyams LLVM_DEBUG(dbgs() << "\nPop BB " << BB->getName() << "\n"); 23451d1de746SOCHyams Worklist.pop(); 23461d1de746SOCHyams bool InChanged = join(*BB, Visited); 23471d1de746SOCHyams // Always consider LiveIn changed on the first visit. 23481d1de746SOCHyams InChanged |= Visited.insert(BB).second; 23491d1de746SOCHyams if (InChanged) { 23501d1de746SOCHyams LLVM_DEBUG(dbgs() << BB->getName() << " has new InLocs, process it\n"); 23511d1de746SOCHyams // Mutate a copy of LiveIn while processing BB. After calling process 23521d1de746SOCHyams // LiveSet is the LiveOut set for BB. 23531d1de746SOCHyams BlockInfo LiveSet = LiveIn[BB]; 23541d1de746SOCHyams 23551d1de746SOCHyams // Process the instructions in the block. 23561d1de746SOCHyams process(*BB, &LiveSet); 23571d1de746SOCHyams 23581d1de746SOCHyams // Relatively expensive check: has anything changed in LiveOut for BB? 23591d1de746SOCHyams if (LiveOut[BB] != LiveSet) { 23601d1de746SOCHyams LLVM_DEBUG(dbgs() << BB->getName() 23611d1de746SOCHyams << " has new OutLocs, add succs to worklist: [ "); 23621d1de746SOCHyams LiveOut[BB] = std::move(LiveSet); 23633641efcfSKazu Hirata for (BasicBlock *Succ : successors(BB)) { 23643641efcfSKazu Hirata if (OnPending.insert(Succ).second) { 23653641efcfSKazu Hirata LLVM_DEBUG(dbgs() << Succ->getName() << " "); 23663641efcfSKazu Hirata Pending.push(BBToOrder[Succ]); 23671d1de746SOCHyams } 23681d1de746SOCHyams } 23691d1de746SOCHyams LLVM_DEBUG(dbgs() << "]\n"); 23701d1de746SOCHyams } 23711d1de746SOCHyams } 23721d1de746SOCHyams } 23731d1de746SOCHyams Worklist.swap(Pending); 23741d1de746SOCHyams // At this point, pending must be empty, since it was just the empty 23751d1de746SOCHyams // worklist 23761d1de746SOCHyams assert(Pending.empty() && "Pending should be empty"); 23771d1de746SOCHyams } 23781d1de746SOCHyams 23791d1de746SOCHyams // That's the hard part over. Now we just have some admin to do. 23801d1de746SOCHyams 23811d1de746SOCHyams // Record whether we inserted any intrinsics. 23821d1de746SOCHyams bool InsertedAnyIntrinsics = false; 23831d1de746SOCHyams 23841d1de746SOCHyams // Identify and add defs for single location variables. 23851d1de746SOCHyams // 23861d1de746SOCHyams // Go through all of the defs that we plan to add. If the aggregate variable 23871d1de746SOCHyams // it's a part of is not in the NotAlwaysStackHomed set we can emit a single 23881d1de746SOCHyams // location def and omit the rest. Add an entry to AlwaysStackHomed so that 23891d1de746SOCHyams // we can identify those uneeded defs later. 23901d1de746SOCHyams DenseSet<DebugAggregate> AlwaysStackHomed; 23911d1de746SOCHyams for (const auto &Pair : InsertBeforeMap) { 239252665432SStephen Tozer auto &Vec = Pair.second; 23931d1de746SOCHyams for (VarLocInfo VarLoc : Vec) { 23941d1de746SOCHyams DebugVariable Var = FnVarLocs->getVariable(VarLoc.VariableID); 23951d1de746SOCHyams DebugAggregate Aggr{Var.getVariable(), Var.getInlinedAt()}; 23961d1de746SOCHyams 23971d1de746SOCHyams // Skip this Var if it's not always stack homed. 23981d1de746SOCHyams if (NotAlwaysStackHomed.contains(Aggr)) 23991d1de746SOCHyams continue; 24001d1de746SOCHyams 24011d1de746SOCHyams // Skip complex cases such as when different fragments of a variable have 24021d1de746SOCHyams // been split into different allocas. Skipping in this case means falling 24031d1de746SOCHyams // back to using a list of defs (which could reduce coverage, but is no 24041d1de746SOCHyams // less correct). 24051d1de746SOCHyams bool Simple = 24061d1de746SOCHyams VarLoc.Expr->getNumElements() == 1 && VarLoc.Expr->startsWithDeref(); 24071d1de746SOCHyams if (!Simple) { 24081d1de746SOCHyams NotAlwaysStackHomed.insert(Aggr); 24091d1de746SOCHyams continue; 24101d1de746SOCHyams } 24111d1de746SOCHyams 24121d1de746SOCHyams // All source assignments to this variable remain and all stores to any 24131d1de746SOCHyams // part of the variable store to the same address (with varying 24141d1de746SOCHyams // offsets). We can just emit a single location for the whole variable. 24151d1de746SOCHyams // 24161d1de746SOCHyams // Unless we've already done so, create the single location def now. 24171d1de746SOCHyams if (AlwaysStackHomed.insert(Aggr).second) { 2418ac6e177cSOCHyams assert(!VarLoc.Values.hasArgList()); 24191d1de746SOCHyams // TODO: When more complex cases are handled VarLoc.Expr should be 24201d1de746SOCHyams // built appropriately rather than always using an empty DIExpression. 24211d1de746SOCHyams // The assert below is a reminder. 24221d1de746SOCHyams assert(Simple); 2423e03f4271SJay Foad VarLoc.Expr = DIExpression::get(Fn.getContext(), {}); 24241d1de746SOCHyams DebugVariable Var = FnVarLocs->getVariable(VarLoc.VariableID); 24257d894374SOCHyams FnVarLocs->addSingleLocVar(Var, VarLoc.Expr, VarLoc.DL, VarLoc.Values); 24261d1de746SOCHyams InsertedAnyIntrinsics = true; 24271d1de746SOCHyams } 24281d1de746SOCHyams } 24291d1de746SOCHyams } 24301d1de746SOCHyams 24311d1de746SOCHyams // Insert the other DEFs. 24321d1de746SOCHyams for (const auto &[InsertBefore, Vec] : InsertBeforeMap) { 24331d1de746SOCHyams SmallVector<VarLocInfo> NewDefs; 24341d1de746SOCHyams for (const VarLocInfo &VarLoc : Vec) { 24351d1de746SOCHyams DebugVariable Var = FnVarLocs->getVariable(VarLoc.VariableID); 24361d1de746SOCHyams DebugAggregate Aggr{Var.getVariable(), Var.getInlinedAt()}; 24371d1de746SOCHyams // If this variable is always stack homed then we have already inserted a 24381d1de746SOCHyams // dbg.declare and deleted this dbg.value. 24391d1de746SOCHyams if (AlwaysStackHomed.contains(Aggr)) 24401d1de746SOCHyams continue; 24411d1de746SOCHyams NewDefs.push_back(VarLoc); 24421d1de746SOCHyams InsertedAnyIntrinsics = true; 24431d1de746SOCHyams } 24441d1de746SOCHyams 24451d1de746SOCHyams FnVarLocs->setWedge(InsertBefore, std::move(NewDefs)); 24461d1de746SOCHyams } 24471d1de746SOCHyams 24481d1de746SOCHyams InsertedAnyIntrinsics |= emitPromotedVarLocs(FnVarLocs); 24491d1de746SOCHyams 24501d1de746SOCHyams return InsertedAnyIntrinsics; 24511d1de746SOCHyams } 24521d1de746SOCHyams 24531d1de746SOCHyams bool AssignmentTrackingLowering::emitPromotedVarLocs( 24541d1de746SOCHyams FunctionVarLocsBuilder *FnVarLocs) { 24551d1de746SOCHyams bool InsertedAnyIntrinsics = false; 24561d1de746SOCHyams // Go through every block, translating debug intrinsics for fully promoted 24571d1de746SOCHyams // variables into FnVarLocs location defs. No analysis required for these. 245852665432SStephen Tozer auto TranslateDbgRecord = [&](auto *Record) { 245952665432SStephen Tozer // Skip variables that haven't been promoted - we've dealt with those 246052665432SStephen Tozer // already. 246152665432SStephen Tozer if (VarsWithStackSlot->contains(getAggregate(Record))) 246252665432SStephen Tozer return; 246352665432SStephen Tozer auto InsertBefore = getNextNode(Record); 246452665432SStephen Tozer assert(InsertBefore && "Unexpected: debug intrinsics after a terminator"); 246552665432SStephen Tozer FnVarLocs->addVarLoc(InsertBefore, DebugVariable(Record), 246652665432SStephen Tozer Record->getExpression(), Record->getDebugLoc(), 246752665432SStephen Tozer RawLocationWrapper(Record->getRawLocation())); 246852665432SStephen Tozer InsertedAnyIntrinsics = true; 246952665432SStephen Tozer }; 24701d1de746SOCHyams for (auto &BB : Fn) { 24711d1de746SOCHyams for (auto &I : BB) { 24721d1de746SOCHyams // Skip instructions other than dbg.values and dbg.assigns. 2473ffd08c77SStephen Tozer for (DbgVariableRecord &DVR : filterDbgVars(I.getDbgRecordRange())) 2474ffd08c77SStephen Tozer if (DVR.isDbgValue() || DVR.isDbgAssign()) 2475ffd08c77SStephen Tozer TranslateDbgRecord(&DVR); 24761d1de746SOCHyams auto *DVI = dyn_cast<DbgValueInst>(&I); 247752665432SStephen Tozer if (DVI) 247852665432SStephen Tozer TranslateDbgRecord(DVI); 24791d1de746SOCHyams } 24801d1de746SOCHyams } 24811d1de746SOCHyams return InsertedAnyIntrinsics; 24821d1de746SOCHyams } 24831d1de746SOCHyams 24841d1de746SOCHyams /// Remove redundant definitions within sequences of consecutive location defs. 24851d1de746SOCHyams /// This is done using a backward scan to keep the last def describing a 24861d1de746SOCHyams /// specific variable/fragment. 24871d1de746SOCHyams /// 24881d1de746SOCHyams /// This implements removeRedundantDbgInstrsUsingBackwardScan from 24891d1de746SOCHyams /// lib/Transforms/Utils/BasicBlockUtils.cpp for locations described with 24901d1de746SOCHyams /// FunctionVarLocsBuilder instead of with intrinsics. 24911d1de746SOCHyams static bool 24921d1de746SOCHyams removeRedundantDbgLocsUsingBackwardScan(const BasicBlock *BB, 24931d1de746SOCHyams FunctionVarLocsBuilder &FnVarLocs) { 24941d1de746SOCHyams bool Changed = false; 24955d558397SOrlando Cazalet-Hyams SmallDenseMap<DebugAggregate, BitVector> VariableDefinedBytes; 24961d1de746SOCHyams // Scan over the entire block, not just over the instructions mapped by 2497d4a01549SJay Foad // FnVarLocs, because wedges in FnVarLocs may only be separated by debug 24981d1de746SOCHyams // instructions. 24991d1de746SOCHyams for (const Instruction &I : reverse(*BB)) { 25001d1de746SOCHyams if (!isa<DbgVariableIntrinsic>(I)) { 25011d1de746SOCHyams // Sequence of consecutive defs ended. Clear map for the next one. 25025d558397SOrlando Cazalet-Hyams VariableDefinedBytes.clear(); 25031d1de746SOCHyams } 25041d1de746SOCHyams 250530845e8aSStephen Tozer auto HandleLocsForWedge = [&](auto *WedgePosition) { 25061d1de746SOCHyams // Get the location defs that start just before this instruction. 250730845e8aSStephen Tozer const auto *Locs = FnVarLocs.getWedge(WedgePosition); 25081d1de746SOCHyams if (!Locs) 250930845e8aSStephen Tozer return; 25101d1de746SOCHyams 25111d1de746SOCHyams NumWedgesScanned++; 25121d1de746SOCHyams bool ChangedThisWedge = false; 25131d1de746SOCHyams // The new pruned set of defs, reversed because we're scanning backwards. 25141d1de746SOCHyams SmallVector<VarLocInfo> NewDefsReversed; 25151d1de746SOCHyams 25161d1de746SOCHyams // Iterate over the existing defs in reverse. 25171d1de746SOCHyams for (auto RIt = Locs->rbegin(), REnd = Locs->rend(); RIt != REnd; ++RIt) { 25181d1de746SOCHyams NumDefsScanned++; 25198e56a196SOCHyams DebugAggregate Aggr = 25208e56a196SOCHyams getAggregate(FnVarLocs.getVariable(RIt->VariableID)); 25218e56a196SOCHyams uint64_t SizeInBits = Aggr.first->getSizeInBits().value_or(0); 25225d558397SOrlando Cazalet-Hyams uint64_t SizeInBytes = divideCeil(SizeInBits, 8); 25231d1de746SOCHyams 25245d558397SOrlando Cazalet-Hyams // Cutoff for large variables to prevent expensive bitvector operations. 25255d558397SOrlando Cazalet-Hyams const uint64_t MaxSizeBytes = 2048; 25265d558397SOrlando Cazalet-Hyams 25275d558397SOrlando Cazalet-Hyams if (SizeInBytes == 0 || SizeInBytes > MaxSizeBytes) { 25288e56a196SOCHyams // If the size is unknown (0) then keep this location def to be safe. 25295d558397SOrlando Cazalet-Hyams // Do the same for defs of large variables, which would be expensive 25305d558397SOrlando Cazalet-Hyams // to represent with a BitVector. 25311d1de746SOCHyams NewDefsReversed.push_back(*RIt); 25328e56a196SOCHyams continue; 25338e56a196SOCHyams } 25348e56a196SOCHyams 25358e56a196SOCHyams // Only keep this location definition if it is not fully eclipsed by 25368e56a196SOCHyams // other definitions in this wedge that come after it 25378e56a196SOCHyams 25385d558397SOrlando Cazalet-Hyams // Inert the bytes the location definition defines. 25398e56a196SOCHyams auto InsertResult = 25405d558397SOrlando Cazalet-Hyams VariableDefinedBytes.try_emplace(Aggr, BitVector(SizeInBytes)); 25418e56a196SOCHyams bool FirstDefinition = InsertResult.second; 25425d558397SOrlando Cazalet-Hyams BitVector &DefinedBytes = InsertResult.first->second; 25438e56a196SOCHyams 25448e56a196SOCHyams DIExpression::FragmentInfo Fragment = 25458e56a196SOCHyams RIt->Expr->getFragmentInfo().value_or( 25468e56a196SOCHyams DIExpression::FragmentInfo(SizeInBits, 0)); 25478e56a196SOCHyams bool InvalidFragment = Fragment.endInBits() > SizeInBits; 25485d558397SOrlando Cazalet-Hyams uint64_t StartInBytes = Fragment.startInBits() / 8; 25495d558397SOrlando Cazalet-Hyams uint64_t EndInBytes = divideCeil(Fragment.endInBits(), 8); 25508e56a196SOCHyams 25515d558397SOrlando Cazalet-Hyams // If this defines any previously undefined bytes, keep it. 25528e56a196SOCHyams if (FirstDefinition || InvalidFragment || 25535d558397SOrlando Cazalet-Hyams DefinedBytes.find_first_unset_in(StartInBytes, EndInBytes) != -1) { 25548e56a196SOCHyams if (!InvalidFragment) 25555d558397SOrlando Cazalet-Hyams DefinedBytes.set(StartInBytes, EndInBytes); 25568e56a196SOCHyams NewDefsReversed.push_back(*RIt); 25578e56a196SOCHyams continue; 25588e56a196SOCHyams } 25598e56a196SOCHyams 25601d1de746SOCHyams // Redundant def found: throw it away. Since the wedge of defs is being 25611d1de746SOCHyams // rebuilt, doing nothing is the same as deleting an entry. 25621d1de746SOCHyams ChangedThisWedge = true; 25631d1de746SOCHyams NumDefsRemoved++; 25641d1de746SOCHyams } 25651d1de746SOCHyams 25661d1de746SOCHyams // Un-reverse the defs and replace the wedge with the pruned version. 25671d1de746SOCHyams if (ChangedThisWedge) { 25681d1de746SOCHyams std::reverse(NewDefsReversed.begin(), NewDefsReversed.end()); 256930845e8aSStephen Tozer FnVarLocs.setWedge(WedgePosition, std::move(NewDefsReversed)); 25701d1de746SOCHyams NumWedgesChanged++; 25711d1de746SOCHyams Changed = true; 25721d1de746SOCHyams } 257330845e8aSStephen Tozer }; 257430845e8aSStephen Tozer HandleLocsForWedge(&I); 2575ffd08c77SStephen Tozer for (DbgVariableRecord &DVR : reverse(filterDbgVars(I.getDbgRecordRange()))) 2576ffd08c77SStephen Tozer HandleLocsForWedge(&DVR); 25771d1de746SOCHyams } 25781d1de746SOCHyams 25791d1de746SOCHyams return Changed; 25801d1de746SOCHyams } 25811d1de746SOCHyams 25821d1de746SOCHyams /// Remove redundant location defs using a forward scan. This can remove a 25831d1de746SOCHyams /// location definition that is redundant due to indicating that a variable has 25841d1de746SOCHyams /// the same value as is already being indicated by an earlier def. 25851d1de746SOCHyams /// 25861d1de746SOCHyams /// This implements removeRedundantDbgInstrsUsingForwardScan from 25871d1de746SOCHyams /// lib/Transforms/Utils/BasicBlockUtils.cpp for locations described with 25881d1de746SOCHyams /// FunctionVarLocsBuilder instead of with intrinsics 25891d1de746SOCHyams static bool 25901d1de746SOCHyams removeRedundantDbgLocsUsingForwardScan(const BasicBlock *BB, 25911d1de746SOCHyams FunctionVarLocsBuilder &FnVarLocs) { 25921d1de746SOCHyams bool Changed = false; 25937d894374SOCHyams DenseMap<DebugVariable, std::pair<RawLocationWrapper, DIExpression *>> 25947d894374SOCHyams VariableMap; 25951d1de746SOCHyams 25961d1de746SOCHyams // Scan over the entire block, not just over the instructions mapped by 2597d4a01549SJay Foad // FnVarLocs, because wedges in FnVarLocs may only be separated by debug 25981d1de746SOCHyams // instructions. 25991d1de746SOCHyams for (const Instruction &I : *BB) { 26001d1de746SOCHyams // Get the defs that come just before this instruction. 260130845e8aSStephen Tozer auto HandleLocsForWedge = [&](auto *WedgePosition) { 260230845e8aSStephen Tozer const auto *Locs = FnVarLocs.getWedge(WedgePosition); 26031d1de746SOCHyams if (!Locs) 260430845e8aSStephen Tozer return; 26051d1de746SOCHyams 26061d1de746SOCHyams NumWedgesScanned++; 26071d1de746SOCHyams bool ChangedThisWedge = false; 26081d1de746SOCHyams // The new pruned set of defs. 26091d1de746SOCHyams SmallVector<VarLocInfo> NewDefs; 26101d1de746SOCHyams 26111d1de746SOCHyams // Iterate over the existing defs. 26121d1de746SOCHyams for (const VarLocInfo &Loc : *Locs) { 26131d1de746SOCHyams NumDefsScanned++; 26141d1de746SOCHyams DebugVariable Key(FnVarLocs.getVariable(Loc.VariableID).getVariable(), 26151d1de746SOCHyams std::nullopt, Loc.DL.getInlinedAt()); 26161d1de746SOCHyams auto VMI = VariableMap.find(Key); 26171d1de746SOCHyams 26181d1de746SOCHyams // Update the map if we found a new value/expression describing the 26191d1de746SOCHyams // variable, or if the variable wasn't mapped already. 26207d894374SOCHyams if (VMI == VariableMap.end() || VMI->second.first != Loc.Values || 26211d1de746SOCHyams VMI->second.second != Loc.Expr) { 26227d894374SOCHyams VariableMap[Key] = {Loc.Values, Loc.Expr}; 26231d1de746SOCHyams NewDefs.push_back(Loc); 26241d1de746SOCHyams continue; 26251d1de746SOCHyams } 26261d1de746SOCHyams 26271d1de746SOCHyams // Did not insert this Loc, which is the same as removing it. 26281d1de746SOCHyams ChangedThisWedge = true; 26291d1de746SOCHyams NumDefsRemoved++; 26301d1de746SOCHyams } 26311d1de746SOCHyams 26321d1de746SOCHyams // Replace the existing wedge with the pruned version. 26331d1de746SOCHyams if (ChangedThisWedge) { 263430845e8aSStephen Tozer FnVarLocs.setWedge(WedgePosition, std::move(NewDefs)); 26351d1de746SOCHyams NumWedgesChanged++; 26361d1de746SOCHyams Changed = true; 26371d1de746SOCHyams } 263830845e8aSStephen Tozer }; 263930845e8aSStephen Tozer 2640ffd08c77SStephen Tozer for (DbgVariableRecord &DVR : filterDbgVars(I.getDbgRecordRange())) 2641ffd08c77SStephen Tozer HandleLocsForWedge(&DVR); 264230845e8aSStephen Tozer HandleLocsForWedge(&I); 26431d1de746SOCHyams } 26441d1de746SOCHyams 26451d1de746SOCHyams return Changed; 26461d1de746SOCHyams } 26471d1de746SOCHyams 26481d1de746SOCHyams static bool 26491d1de746SOCHyams removeUndefDbgLocsFromEntryBlock(const BasicBlock *BB, 26501d1de746SOCHyams FunctionVarLocsBuilder &FnVarLocs) { 26511d1de746SOCHyams assert(BB->isEntryBlock()); 26521d1de746SOCHyams // Do extra work to ensure that we remove semantically unimportant undefs. 26531d1de746SOCHyams // 26541d1de746SOCHyams // This is to work around the fact that SelectionDAG will hoist dbg.values 26551d1de746SOCHyams // using argument values to the top of the entry block. That can move arg 26561d1de746SOCHyams // dbg.values before undef and constant dbg.values which they previously 26571d1de746SOCHyams // followed. The easiest thing to do is to just try to feed SelectionDAG 26581d1de746SOCHyams // input it's happy with. 26591d1de746SOCHyams // 26601d1de746SOCHyams // Map of {Variable x: Fragments y} where the fragments y of variable x have 26611d1de746SOCHyams // have at least one non-undef location defined already. Don't use directly, 26621d1de746SOCHyams // instead call DefineBits and HasDefinedBits. 26631d1de746SOCHyams SmallDenseMap<DebugAggregate, SmallDenseSet<DIExpression::FragmentInfo>> 26641d1de746SOCHyams VarsWithDef; 26651d1de746SOCHyams // Specify that V (a fragment of A) has a non-undef location. 26661d1de746SOCHyams auto DefineBits = [&VarsWithDef](DebugAggregate A, DebugVariable V) { 26671d1de746SOCHyams VarsWithDef[A].insert(V.getFragmentOrDefault()); 26681d1de746SOCHyams }; 26691d1de746SOCHyams // Return true if a non-undef location has been defined for V (a fragment of 26701d1de746SOCHyams // A). Doesn't imply that the location is currently non-undef, just that a 26711d1de746SOCHyams // non-undef location has been seen previously. 26721d1de746SOCHyams auto HasDefinedBits = [&VarsWithDef](DebugAggregate A, DebugVariable V) { 26731d1de746SOCHyams auto FragsIt = VarsWithDef.find(A); 26741d1de746SOCHyams if (FragsIt == VarsWithDef.end()) 26751d1de746SOCHyams return false; 26761d1de746SOCHyams return llvm::any_of(FragsIt->second, [V](auto Frag) { 26771d1de746SOCHyams return DIExpression::fragmentsOverlap(Frag, V.getFragmentOrDefault()); 26781d1de746SOCHyams }); 26791d1de746SOCHyams }; 26801d1de746SOCHyams 26811d1de746SOCHyams bool Changed = false; 26821d1de746SOCHyams DenseMap<DebugVariable, std::pair<Value *, DIExpression *>> VariableMap; 26831d1de746SOCHyams 26841d1de746SOCHyams // Scan over the entire block, not just over the instructions mapped by 2685d4a01549SJay Foad // FnVarLocs, because wedges in FnVarLocs may only be separated by debug 26861d1de746SOCHyams // instructions. 26871d1de746SOCHyams for (const Instruction &I : *BB) { 26881d1de746SOCHyams // Get the defs that come just before this instruction. 268930845e8aSStephen Tozer auto HandleLocsForWedge = [&](auto *WedgePosition) { 269030845e8aSStephen Tozer const auto *Locs = FnVarLocs.getWedge(WedgePosition); 26911d1de746SOCHyams if (!Locs) 269230845e8aSStephen Tozer return; 26931d1de746SOCHyams 26941d1de746SOCHyams NumWedgesScanned++; 26951d1de746SOCHyams bool ChangedThisWedge = false; 26961d1de746SOCHyams // The new pruned set of defs. 26971d1de746SOCHyams SmallVector<VarLocInfo> NewDefs; 26981d1de746SOCHyams 26991d1de746SOCHyams // Iterate over the existing defs. 27001d1de746SOCHyams for (const VarLocInfo &Loc : *Locs) { 27011d1de746SOCHyams NumDefsScanned++; 27021d1de746SOCHyams DebugAggregate Aggr{FnVarLocs.getVariable(Loc.VariableID).getVariable(), 27031d1de746SOCHyams Loc.DL.getInlinedAt()}; 27041d1de746SOCHyams DebugVariable Var = FnVarLocs.getVariable(Loc.VariableID); 27051d1de746SOCHyams 27061d1de746SOCHyams // Remove undef entries that are encountered before any non-undef 27071d1de746SOCHyams // intrinsics from the entry block. 27087d894374SOCHyams if (Loc.Values.isKillLocation(Loc.Expr) && !HasDefinedBits(Aggr, Var)) { 27091d1de746SOCHyams // Did not insert this Loc, which is the same as removing it. 27101d1de746SOCHyams NumDefsRemoved++; 27111d1de746SOCHyams ChangedThisWedge = true; 27121d1de746SOCHyams continue; 27131d1de746SOCHyams } 27141d1de746SOCHyams 27151d1de746SOCHyams DefineBits(Aggr, Var); 27161d1de746SOCHyams NewDefs.push_back(Loc); 27171d1de746SOCHyams } 27181d1de746SOCHyams 27191d1de746SOCHyams // Replace the existing wedge with the pruned version. 27201d1de746SOCHyams if (ChangedThisWedge) { 272130845e8aSStephen Tozer FnVarLocs.setWedge(WedgePosition, std::move(NewDefs)); 27221d1de746SOCHyams NumWedgesChanged++; 27231d1de746SOCHyams Changed = true; 27241d1de746SOCHyams } 272530845e8aSStephen Tozer }; 2726ffd08c77SStephen Tozer for (DbgVariableRecord &DVR : filterDbgVars(I.getDbgRecordRange())) 2727ffd08c77SStephen Tozer HandleLocsForWedge(&DVR); 272830845e8aSStephen Tozer HandleLocsForWedge(&I); 27291d1de746SOCHyams } 27301d1de746SOCHyams 27311d1de746SOCHyams return Changed; 27321d1de746SOCHyams } 27331d1de746SOCHyams 27341d1de746SOCHyams static bool removeRedundantDbgLocs(const BasicBlock *BB, 27351d1de746SOCHyams FunctionVarLocsBuilder &FnVarLocs) { 27361d1de746SOCHyams bool MadeChanges = false; 27371d1de746SOCHyams MadeChanges |= removeRedundantDbgLocsUsingBackwardScan(BB, FnVarLocs); 27381d1de746SOCHyams if (BB->isEntryBlock()) 27391d1de746SOCHyams MadeChanges |= removeUndefDbgLocsFromEntryBlock(BB, FnVarLocs); 27401d1de746SOCHyams MadeChanges |= removeRedundantDbgLocsUsingForwardScan(BB, FnVarLocs); 27411d1de746SOCHyams 27421d1de746SOCHyams if (MadeChanges) 27431d1de746SOCHyams LLVM_DEBUG(dbgs() << "Removed redundant dbg locs from: " << BB->getName() 27441d1de746SOCHyams << "\n"); 27451d1de746SOCHyams return MadeChanges; 27461d1de746SOCHyams } 27471d1de746SOCHyams 27481d1de746SOCHyams static DenseSet<DebugAggregate> findVarsWithStackSlot(Function &Fn) { 27491d1de746SOCHyams DenseSet<DebugAggregate> Result; 27501d1de746SOCHyams for (auto &BB : Fn) { 27511d1de746SOCHyams for (auto &I : BB) { 27521d1de746SOCHyams // Any variable linked to an instruction is considered 27531d1de746SOCHyams // interesting. Ideally we only need to check Allocas, however, a 27541d1de746SOCHyams // DIAssignID might get dropped from an alloca but not stores. In that 27551d1de746SOCHyams // case, we need to consider the variable interesting for NFC behaviour 27561d1de746SOCHyams // with this change. TODO: Consider only looking at allocas. 27571d1de746SOCHyams for (DbgAssignIntrinsic *DAI : at::getAssignmentMarkers(&I)) { 27581d1de746SOCHyams Result.insert({DAI->getVariable(), DAI->getDebugLoc().getInlinedAt()}); 27591d1de746SOCHyams } 2760ffd08c77SStephen Tozer for (DbgVariableRecord *DVR : at::getDVRAssignmentMarkers(&I)) { 2761ffd08c77SStephen Tozer Result.insert({DVR->getVariable(), DVR->getDebugLoc().getInlinedAt()}); 276230845e8aSStephen Tozer } 27631d1de746SOCHyams } 27641d1de746SOCHyams } 27651d1de746SOCHyams return Result; 27661d1de746SOCHyams } 27671d1de746SOCHyams 27681d1de746SOCHyams static void analyzeFunction(Function &Fn, const DataLayout &Layout, 27691d1de746SOCHyams FunctionVarLocsBuilder *FnVarLocs) { 27701d1de746SOCHyams // The analysis will generate location definitions for all variables, but we 27711d1de746SOCHyams // only need to perform a dataflow on the set of variables which have a stack 27721d1de746SOCHyams // slot. Find those now. 27731d1de746SOCHyams DenseSet<DebugAggregate> VarsWithStackSlot = findVarsWithStackSlot(Fn); 27741d1de746SOCHyams 27751d1de746SOCHyams bool Changed = false; 27761d1de746SOCHyams 27771d1de746SOCHyams // Use a scope block to clean up AssignmentTrackingLowering before running 27781d1de746SOCHyams // MemLocFragmentFill to reduce peak memory consumption. 27791d1de746SOCHyams { 27801d1de746SOCHyams AssignmentTrackingLowering Pass(Fn, Layout, &VarsWithStackSlot); 27811d1de746SOCHyams Changed = Pass.run(FnVarLocs); 27821d1de746SOCHyams } 27831d1de746SOCHyams 27841d1de746SOCHyams if (Changed) { 2785d4879d76SOCHyams MemLocFragmentFill Pass(Fn, &VarsWithStackSlot, 2786d4879d76SOCHyams shouldCoalesceFragments(Fn)); 27871d1de746SOCHyams Pass.run(FnVarLocs); 27881d1de746SOCHyams 27891d1de746SOCHyams // Remove redundant entries. As well as reducing memory consumption and 27901d1de746SOCHyams // avoiding waiting cycles later by burning some now, this has another 27911d1de746SOCHyams // important job. That is to work around some SelectionDAG quirks. See 27921d1de746SOCHyams // removeRedundantDbgLocsUsingForwardScan comments for more info on that. 27931d1de746SOCHyams for (auto &BB : Fn) 27941d1de746SOCHyams removeRedundantDbgLocs(&BB, *FnVarLocs); 27951d1de746SOCHyams } 27961d1de746SOCHyams } 27971d1de746SOCHyams 27987c71a09dSpaperchalice FunctionVarLocs 27997c71a09dSpaperchalice DebugAssignmentTrackingAnalysis::run(Function &F, 28007c71a09dSpaperchalice FunctionAnalysisManager &FAM) { 28017c71a09dSpaperchalice if (!isAssignmentTrackingEnabled(*F.getParent())) 28027c71a09dSpaperchalice return FunctionVarLocs(); 28037c71a09dSpaperchalice 28049df71d76SNikita Popov auto &DL = F.getDataLayout(); 28057c71a09dSpaperchalice 28067c71a09dSpaperchalice FunctionVarLocsBuilder Builder; 28077c71a09dSpaperchalice analyzeFunction(F, DL, &Builder); 28087c71a09dSpaperchalice 28097c71a09dSpaperchalice // Save these results. 28107c71a09dSpaperchalice FunctionVarLocs Results; 28117c71a09dSpaperchalice Results.init(Builder); 28127c71a09dSpaperchalice return Results; 28137c71a09dSpaperchalice } 28147c71a09dSpaperchalice 28157c71a09dSpaperchalice AnalysisKey DebugAssignmentTrackingAnalysis::Key; 28167c71a09dSpaperchalice 28177c71a09dSpaperchalice PreservedAnalyses 28187c71a09dSpaperchalice DebugAssignmentTrackingPrinterPass::run(Function &F, 28197c71a09dSpaperchalice FunctionAnalysisManager &FAM) { 28207c71a09dSpaperchalice FAM.getResult<DebugAssignmentTrackingAnalysis>(F).print(OS, F); 28217c71a09dSpaperchalice return PreservedAnalyses::all(); 28227c71a09dSpaperchalice } 28237c71a09dSpaperchalice 28241d1de746SOCHyams bool AssignmentTrackingAnalysis::runOnFunction(Function &F) { 28254ece5073SOCHyams if (!isAssignmentTrackingEnabled(*F.getParent())) 28264ece5073SOCHyams return false; 28274ece5073SOCHyams 28281d1de746SOCHyams LLVM_DEBUG(dbgs() << "AssignmentTrackingAnalysis run on " << F.getName() 28291d1de746SOCHyams << "\n"); 28301d1de746SOCHyams 28311d1de746SOCHyams // Clear previous results. 28321d1de746SOCHyams Results->clear(); 28331d1de746SOCHyams 28341d1de746SOCHyams FunctionVarLocsBuilder Builder; 283575c7bca7SSergei Barannikov analyzeFunction(F, F.getDataLayout(), &Builder); 28361d1de746SOCHyams 28371d1de746SOCHyams // Save these results. 28381d1de746SOCHyams Results->init(Builder); 28391d1de746SOCHyams 28401d1de746SOCHyams if (PrintResults && isFunctionInPrintList(F.getName())) 28411d1de746SOCHyams Results->print(errs(), F); 28421d1de746SOCHyams 28431d1de746SOCHyams // Return false because this pass does not modify the function. 28441d1de746SOCHyams return false; 28451d1de746SOCHyams } 28461d1de746SOCHyams 28471d1de746SOCHyams AssignmentTrackingAnalysis::AssignmentTrackingAnalysis() 28481d1de746SOCHyams : FunctionPass(ID), Results(std::make_unique<FunctionVarLocs>()) {} 28491d1de746SOCHyams 28501d1de746SOCHyams char AssignmentTrackingAnalysis::ID = 0; 28511d1de746SOCHyams 28521d1de746SOCHyams INITIALIZE_PASS(AssignmentTrackingAnalysis, DEBUG_TYPE, 28531d1de746SOCHyams "Assignment Tracking Analysis", false, true) 2854