Path: blob/main/contrib/llvm-project/llvm/lib/CodeGen/AssignmentTrackingAnalysis.cpp
35232 views
//===-- AssignmentTrackingAnalysis.cpp ------------------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#include "llvm/CodeGen/AssignmentTrackingAnalysis.h"9#include "LiveDebugValues/LiveDebugValues.h"10#include "llvm/ADT/BitVector.h"11#include "llvm/ADT/DenseMapInfo.h"12#include "llvm/ADT/IntervalMap.h"13#include "llvm/ADT/PostOrderIterator.h"14#include "llvm/ADT/STLExtras.h"15#include "llvm/ADT/Statistic.h"16#include "llvm/ADT/UniqueVector.h"17#include "llvm/BinaryFormat/Dwarf.h"18#include "llvm/IR/BasicBlock.h"19#include "llvm/IR/DataLayout.h"20#include "llvm/IR/DebugInfo.h"21#include "llvm/IR/DebugProgramInstruction.h"22#include "llvm/IR/Function.h"23#include "llvm/IR/Instruction.h"24#include "llvm/IR/IntrinsicInst.h"25#include "llvm/IR/Module.h"26#include "llvm/IR/PassManager.h"27#include "llvm/IR/PrintPasses.h"28#include "llvm/InitializePasses.h"29#include "llvm/Support/CommandLine.h"30#include "llvm/Support/ErrorHandling.h"31#include "llvm/Support/raw_ostream.h"32#include "llvm/Transforms/Utils/BasicBlockUtils.h"33#include <assert.h>34#include <cstdint>35#include <optional>36#include <queue>37#include <sstream>38#include <unordered_map>3940using namespace llvm;41#define DEBUG_TYPE "debug-ata"4243STATISTIC(NumDefsScanned, "Number of dbg locs that get scanned for removal");44STATISTIC(NumDefsRemoved, "Number of dbg locs removed");45STATISTIC(NumWedgesScanned, "Number of dbg wedges scanned");46STATISTIC(NumWedgesChanged, "Number of dbg wedges changed");4748static cl::opt<unsigned>49MaxNumBlocks("debug-ata-max-blocks", cl::init(10000),50cl::desc("Maximum num basic blocks before debug info dropped"),51cl::Hidden);52/// Option for debugging the pass, determines if the memory location fragment53/// filling happens after generating the variable locations.54static cl::opt<bool> EnableMemLocFragFill("mem-loc-frag-fill", cl::init(true),55cl::Hidden);56/// Print the results of the analysis. Respects -filter-print-funcs.57static cl::opt<bool> PrintResults("print-debug-ata", cl::init(false),58cl::Hidden);5960/// Coalesce adjacent dbg locs describing memory locations that have contiguous61/// fragments. This reduces the cost of LiveDebugValues which does SSA62/// construction for each explicitly stated variable fragment.63static cl::opt<cl::boolOrDefault>64CoalesceAdjacentFragmentsOpt("debug-ata-coalesce-frags", cl::Hidden);6566// Implicit conversions are disabled for enum class types, so unfortunately we67// need to create a DenseMapInfo wrapper around the specified underlying type.68template <> struct llvm::DenseMapInfo<VariableID> {69using Wrapped = DenseMapInfo<unsigned>;70static inline VariableID getEmptyKey() {71return static_cast<VariableID>(Wrapped::getEmptyKey());72}73static inline VariableID getTombstoneKey() {74return static_cast<VariableID>(Wrapped::getTombstoneKey());75}76static unsigned getHashValue(const VariableID &Val) {77return Wrapped::getHashValue(static_cast<unsigned>(Val));78}79static bool isEqual(const VariableID &LHS, const VariableID &RHS) {80return LHS == RHS;81}82};8384using VarLocInsertPt = PointerUnion<const Instruction *, const DbgRecord *>;8586namespace std {87template <> struct hash<VarLocInsertPt> {88using argument_type = VarLocInsertPt;89using result_type = std::size_t;9091result_type operator()(const argument_type &Arg) const {92return std::hash<void *>()(Arg.getOpaqueValue());93}94};95} // namespace std9697/// Helper class to build FunctionVarLocs, since that class isn't easy to98/// modify. TODO: There's not a great deal of value in the split, it could be99/// worth merging the two classes.100class FunctionVarLocsBuilder {101friend FunctionVarLocs;102UniqueVector<DebugVariable> Variables;103// Use an unordered_map so we don't invalidate iterators after104// insert/modifications.105std::unordered_map<VarLocInsertPt, SmallVector<VarLocInfo>> VarLocsBeforeInst;106107SmallVector<VarLocInfo> SingleLocVars;108109public:110unsigned getNumVariables() const { return Variables.size(); }111112/// Find or insert \p V and return the ID.113VariableID insertVariable(DebugVariable V) {114return static_cast<VariableID>(Variables.insert(V));115}116117/// Get a variable from its \p ID.118const DebugVariable &getVariable(VariableID ID) const {119return Variables[static_cast<unsigned>(ID)];120}121122/// Return ptr to wedge of defs or nullptr if no defs come just before /p123/// Before.124const SmallVectorImpl<VarLocInfo> *getWedge(VarLocInsertPt Before) const {125auto R = VarLocsBeforeInst.find(Before);126if (R == VarLocsBeforeInst.end())127return nullptr;128return &R->second;129}130131/// Replace the defs that come just before /p Before with /p Wedge.132void setWedge(VarLocInsertPt Before, SmallVector<VarLocInfo> &&Wedge) {133VarLocsBeforeInst[Before] = std::move(Wedge);134}135136/// Add a def for a variable that is valid for its lifetime.137void addSingleLocVar(DebugVariable Var, DIExpression *Expr, DebugLoc DL,138RawLocationWrapper R) {139VarLocInfo VarLoc;140VarLoc.VariableID = insertVariable(Var);141VarLoc.Expr = Expr;142VarLoc.DL = DL;143VarLoc.Values = R;144SingleLocVars.emplace_back(VarLoc);145}146147/// Add a def to the wedge of defs just before /p Before.148void addVarLoc(VarLocInsertPt Before, DebugVariable Var, DIExpression *Expr,149DebugLoc DL, RawLocationWrapper R) {150VarLocInfo VarLoc;151VarLoc.VariableID = insertVariable(Var);152VarLoc.Expr = Expr;153VarLoc.DL = DL;154VarLoc.Values = R;155VarLocsBeforeInst[Before].emplace_back(VarLoc);156}157};158159void FunctionVarLocs::print(raw_ostream &OS, const Function &Fn) const {160// Print the variable table first. TODO: Sorting by variable could make the161// output more stable?162unsigned Counter = -1;163OS << "=== Variables ===\n";164for (const DebugVariable &V : Variables) {165++Counter;166// Skip first entry because it is a dummy entry.167if (Counter == 0) {168continue;169}170OS << "[" << Counter << "] " << V.getVariable()->getName();171if (auto F = V.getFragment())172OS << " bits [" << F->OffsetInBits << ", "173<< F->OffsetInBits + F->SizeInBits << ")";174if (const auto *IA = V.getInlinedAt())175OS << " inlined-at " << *IA;176OS << "\n";177}178179auto PrintLoc = [&OS](const VarLocInfo &Loc) {180OS << "DEF Var=[" << (unsigned)Loc.VariableID << "]"181<< " Expr=" << *Loc.Expr << " Values=(";182for (auto *Op : Loc.Values.location_ops()) {183errs() << Op->getName() << " ";184}185errs() << ")\n";186};187188// Print the single location variables.189OS << "=== Single location vars ===\n";190for (auto It = single_locs_begin(), End = single_locs_end(); It != End;191++It) {192PrintLoc(*It);193}194195// Print the non-single-location defs in line with IR.196OS << "=== In-line variable defs ===";197for (const BasicBlock &BB : Fn) {198OS << "\n" << BB.getName() << ":\n";199for (const Instruction &I : BB) {200for (auto It = locs_begin(&I), End = locs_end(&I); It != End; ++It) {201PrintLoc(*It);202}203OS << I << "\n";204}205}206}207208void FunctionVarLocs::init(FunctionVarLocsBuilder &Builder) {209// Add the single-location variables first.210for (const auto &VarLoc : Builder.SingleLocVars)211VarLocRecords.emplace_back(VarLoc);212// Mark the end of the section.213SingleVarLocEnd = VarLocRecords.size();214215// Insert a contiguous block of VarLocInfos for each instruction, mapping it216// to the start and end position in the vector with VarLocsBeforeInst. This217// block includes VarLocs for any DbgVariableRecords attached to that218// instruction.219for (auto &P : Builder.VarLocsBeforeInst) {220// Process VarLocs attached to a DbgRecord alongside their marker221// Instruction.222if (isa<const DbgRecord *>(P.first))223continue;224const Instruction *I = cast<const Instruction *>(P.first);225unsigned BlockStart = VarLocRecords.size();226// Any VarLocInfos attached to a DbgRecord should now be remapped to their227// marker Instruction, in order of DbgRecord appearance and prior to any228// VarLocInfos attached directly to that instruction.229for (const DbgVariableRecord &DVR : filterDbgVars(I->getDbgRecordRange())) {230// Even though DVR defines a variable location, VarLocsBeforeInst can231// still be empty if that VarLoc was redundant.232if (!Builder.VarLocsBeforeInst.count(&DVR))233continue;234for (const VarLocInfo &VarLoc : Builder.VarLocsBeforeInst[&DVR])235VarLocRecords.emplace_back(VarLoc);236}237for (const VarLocInfo &VarLoc : P.second)238VarLocRecords.emplace_back(VarLoc);239unsigned BlockEnd = VarLocRecords.size();240// Record the start and end indices.241if (BlockEnd != BlockStart)242VarLocsBeforeInst[I] = {BlockStart, BlockEnd};243}244245// Copy the Variables vector from the builder's UniqueVector.246assert(Variables.empty() && "Expect clear before init");247// UniqueVectors IDs are one-based (which means the VarLocInfo VarID values248// are one-based) so reserve an extra and insert a dummy.249Variables.reserve(Builder.Variables.size() + 1);250Variables.push_back(DebugVariable(nullptr, std::nullopt, nullptr));251Variables.append(Builder.Variables.begin(), Builder.Variables.end());252}253254void FunctionVarLocs::clear() {255Variables.clear();256VarLocRecords.clear();257VarLocsBeforeInst.clear();258SingleVarLocEnd = 0;259}260261/// Walk backwards along constant GEPs and bitcasts to the base storage from \p262/// Start as far as possible. Prepend \Expression with the offset and append it263/// with a DW_OP_deref that haes been implicit until now. Returns the walked-to264/// value and modified expression.265static std::pair<Value *, DIExpression *>266walkToAllocaAndPrependOffsetDeref(const DataLayout &DL, Value *Start,267DIExpression *Expression) {268APInt OffsetInBytes(DL.getTypeSizeInBits(Start->getType()), false);269Value *End =270Start->stripAndAccumulateInBoundsConstantOffsets(DL, OffsetInBytes);271SmallVector<uint64_t, 3> Ops;272if (OffsetInBytes.getBoolValue()) {273Ops = {dwarf::DW_OP_plus_uconst, OffsetInBytes.getZExtValue()};274Expression = DIExpression::prependOpcodes(275Expression, Ops, /*StackValue=*/false, /*EntryValue=*/false);276}277Expression = DIExpression::append(Expression, {dwarf::DW_OP_deref});278return {End, Expression};279}280281/// Extract the offset used in \p DIExpr. Returns std::nullopt if the expression282/// doesn't explicitly describe a memory location with DW_OP_deref or if the283/// expression is too complex to interpret.284static std::optional<int64_t>285getDerefOffsetInBytes(const DIExpression *DIExpr) {286int64_t Offset = 0;287const unsigned NumElements = DIExpr->getNumElements();288const auto Elements = DIExpr->getElements();289unsigned ExpectedDerefIdx = 0;290// Extract the offset.291if (NumElements > 2 && Elements[0] == dwarf::DW_OP_plus_uconst) {292Offset = Elements[1];293ExpectedDerefIdx = 2;294} else if (NumElements > 3 && Elements[0] == dwarf::DW_OP_constu) {295ExpectedDerefIdx = 3;296if (Elements[2] == dwarf::DW_OP_plus)297Offset = Elements[1];298else if (Elements[2] == dwarf::DW_OP_minus)299Offset = -Elements[1];300else301return std::nullopt;302}303304// If that's all there is it means there's no deref.305if (ExpectedDerefIdx >= NumElements)306return std::nullopt;307308// Check the next element is DW_OP_deref - otherwise this is too complex or309// isn't a deref expression.310if (Elements[ExpectedDerefIdx] != dwarf::DW_OP_deref)311return std::nullopt;312313// Check the final operation is either the DW_OP_deref or is a fragment.314if (NumElements == ExpectedDerefIdx + 1)315return Offset; // Ends with deref.316unsigned ExpectedFragFirstIdx = ExpectedDerefIdx + 1;317unsigned ExpectedFragFinalIdx = ExpectedFragFirstIdx + 2;318if (NumElements == ExpectedFragFinalIdx + 1 &&319Elements[ExpectedFragFirstIdx] == dwarf::DW_OP_LLVM_fragment)320return Offset; // Ends with deref + fragment.321322// Don't bother trying to interpret anything more complex.323return std::nullopt;324}325326/// A whole (unfragmented) source variable.327using DebugAggregate = std::pair<const DILocalVariable *, const DILocation *>;328static DebugAggregate getAggregate(const DbgVariableIntrinsic *DII) {329return DebugAggregate(DII->getVariable(), DII->getDebugLoc().getInlinedAt());330}331static DebugAggregate getAggregate(const DebugVariable &Var) {332return DebugAggregate(Var.getVariable(), Var.getInlinedAt());333}334335static bool shouldCoalesceFragments(Function &F) {336// Enabling fragment coalescing reduces compiler run time when instruction337// referencing is enabled. However, it may cause LiveDebugVariables to create338// incorrect locations. Since instruction-referencing mode effectively339// bypasses LiveDebugVariables we only enable coalescing if the cl::opt flag340// has not been explicitly set and instruction-referencing is turned on.341switch (CoalesceAdjacentFragmentsOpt) {342case cl::boolOrDefault::BOU_UNSET:343return debuginfoShouldUseDebugInstrRef(344Triple(F.getParent()->getTargetTriple()));345case cl::boolOrDefault::BOU_TRUE:346return true;347case cl::boolOrDefault::BOU_FALSE:348return false;349}350llvm_unreachable("Unknown boolOrDefault value");351}352353namespace {354/// In dwarf emission, the following sequence355/// 1. dbg.value ... Fragment(0, 64)356/// 2. dbg.value ... Fragment(0, 32)357/// effectively sets Fragment(32, 32) to undef (each def sets all bits not in358/// the intersection of the fragments to having "no location"). This makes359/// sense for implicit location values because splitting the computed values360/// could be troublesome, and is probably quite uncommon. When we convert361/// dbg.assigns to dbg.value+deref this kind of thing is common, and describing362/// a location (memory) rather than a value means we don't need to worry about363/// splitting any values, so we try to recover the rest of the fragment364/// location here.365/// This class performs a(nother) dataflow analysis over the function, adding366/// variable locations so that any bits of a variable with a memory location367/// have that location explicitly reinstated at each subsequent variable368/// location definition that that doesn't overwrite those bits. i.e. after a369/// variable location def, insert new defs for the memory location with370/// fragments for the difference of "all bits currently in memory" and "the371/// fragment of the second def".372class MemLocFragmentFill {373Function &Fn;374FunctionVarLocsBuilder *FnVarLocs;375const DenseSet<DebugAggregate> *VarsWithStackSlot;376bool CoalesceAdjacentFragments;377378// 0 = no memory location.379using BaseAddress = unsigned;380using OffsetInBitsTy = unsigned;381using FragTraits = IntervalMapHalfOpenInfo<OffsetInBitsTy>;382using FragsInMemMap = IntervalMap<383OffsetInBitsTy, BaseAddress,384IntervalMapImpl::NodeSizer<OffsetInBitsTy, BaseAddress>::LeafSize,385FragTraits>;386FragsInMemMap::Allocator IntervalMapAlloc;387using VarFragMap = DenseMap<unsigned, FragsInMemMap>;388389/// IDs for memory location base addresses in maps. Use 0 to indicate that390/// there's no memory location.391UniqueVector<RawLocationWrapper> Bases;392UniqueVector<DebugAggregate> Aggregates;393DenseMap<const BasicBlock *, VarFragMap> LiveIn;394DenseMap<const BasicBlock *, VarFragMap> LiveOut;395396struct FragMemLoc {397unsigned Var;398unsigned Base;399unsigned OffsetInBits;400unsigned SizeInBits;401DebugLoc DL;402};403using InsertMap = MapVector<VarLocInsertPt, SmallVector<FragMemLoc>>;404405/// BBInsertBeforeMap holds a description for the set of location defs to be406/// inserted after the analysis is complete. It is updated during the dataflow407/// and the entry for a block is CLEARED each time it is (re-)visited. After408/// the dataflow is complete, each block entry will contain the set of defs409/// calculated during the final (fixed-point) iteration.410DenseMap<const BasicBlock *, InsertMap> BBInsertBeforeMap;411412static bool intervalMapsAreEqual(const FragsInMemMap &A,413const FragsInMemMap &B) {414auto AIt = A.begin(), AEnd = A.end();415auto BIt = B.begin(), BEnd = B.end();416for (; AIt != AEnd; ++AIt, ++BIt) {417if (BIt == BEnd)418return false; // B has fewer elements than A.419if (AIt.start() != BIt.start() || AIt.stop() != BIt.stop())420return false; // Interval is different.421if (*AIt != *BIt)422return false; // Value at interval is different.423}424// AIt == AEnd. Check BIt is also now at end.425return BIt == BEnd;426}427428static bool varFragMapsAreEqual(const VarFragMap &A, const VarFragMap &B) {429if (A.size() != B.size())430return false;431for (const auto &APair : A) {432auto BIt = B.find(APair.first);433if (BIt == B.end())434return false;435if (!intervalMapsAreEqual(APair.second, BIt->second))436return false;437}438return true;439}440441/// Return a string for the value that \p BaseID represents.442std::string toString(unsigned BaseID) {443if (BaseID)444return Bases[BaseID].getVariableLocationOp(0)->getName().str();445else446return "None";447}448449/// Format string describing an FragsInMemMap (IntervalMap) interval.450std::string toString(FragsInMemMap::const_iterator It, bool Newline = true) {451std::string String;452std::stringstream S(String);453if (It.valid()) {454S << "[" << It.start() << ", " << It.stop()455<< "): " << toString(It.value());456} else {457S << "invalid iterator (end)";458}459if (Newline)460S << "\n";461return S.str();462};463464FragsInMemMap meetFragments(const FragsInMemMap &A, const FragsInMemMap &B) {465FragsInMemMap Result(IntervalMapAlloc);466for (auto AIt = A.begin(), AEnd = A.end(); AIt != AEnd; ++AIt) {467LLVM_DEBUG(dbgs() << "a " << toString(AIt));468// This is basically copied from process() and inverted (process is469// performing something like a union whereas this is more of an470// intersect).471472// There's no work to do if interval `a` overlaps no fragments in map `B`.473if (!B.overlaps(AIt.start(), AIt.stop()))474continue;475476// Does StartBit intersect an existing fragment?477auto FirstOverlap = B.find(AIt.start());478assert(FirstOverlap != B.end());479bool IntersectStart = FirstOverlap.start() < AIt.start();480LLVM_DEBUG(dbgs() << "- FirstOverlap " << toString(FirstOverlap, false)481<< ", IntersectStart: " << IntersectStart << "\n");482483// Does EndBit intersect an existing fragment?484auto LastOverlap = B.find(AIt.stop());485bool IntersectEnd =486LastOverlap != B.end() && LastOverlap.start() < AIt.stop();487LLVM_DEBUG(dbgs() << "- LastOverlap " << toString(LastOverlap, false)488<< ", IntersectEnd: " << IntersectEnd << "\n");489490// Check if both ends of `a` intersect the same interval `b`.491if (IntersectStart && IntersectEnd && FirstOverlap == LastOverlap) {492// Insert `a` (`a` is contained in `b`) if the values match.493// [ a ]494// [ - b - ]495// -496// [ r ]497LLVM_DEBUG(dbgs() << "- a is contained within "498<< toString(FirstOverlap));499if (*AIt && *AIt == *FirstOverlap)500Result.insert(AIt.start(), AIt.stop(), *AIt);501} else {502// There's an overlap but `a` is not fully contained within503// `b`. Shorten any end-point intersections.504// [ - a - ]505// [ - b - ]506// -507// [ r ]508auto Next = FirstOverlap;509if (IntersectStart) {510LLVM_DEBUG(dbgs() << "- insert intersection of a and "511<< toString(FirstOverlap));512if (*AIt && *AIt == *FirstOverlap)513Result.insert(AIt.start(), FirstOverlap.stop(), *AIt);514++Next;515}516// [ - a - ]517// [ - b - ]518// -519// [ r ]520if (IntersectEnd) {521LLVM_DEBUG(dbgs() << "- insert intersection of a and "522<< toString(LastOverlap));523if (*AIt && *AIt == *LastOverlap)524Result.insert(LastOverlap.start(), AIt.stop(), *AIt);525}526527// Insert all intervals in map `B` that are contained within interval528// `a` where the values match.529// [ - - a - - ]530// [ b1 ] [ b2 ]531// -532// [ r1 ] [ r2 ]533while (Next != B.end() && Next.start() < AIt.stop() &&534Next.stop() <= AIt.stop()) {535LLVM_DEBUG(dbgs()536<< "- insert intersection of a and " << toString(Next));537if (*AIt && *AIt == *Next)538Result.insert(Next.start(), Next.stop(), *Next);539++Next;540}541}542}543return Result;544}545546/// Meet \p A and \p B, storing the result in \p A.547void meetVars(VarFragMap &A, const VarFragMap &B) {548// Meet A and B.549//550// Result = meet(a, b) for a in A, b in B where Var(a) == Var(b)551for (auto It = A.begin(), End = A.end(); It != End; ++It) {552unsigned AVar = It->first;553FragsInMemMap &AFrags = It->second;554auto BIt = B.find(AVar);555if (BIt == B.end()) {556A.erase(It);557continue; // Var has no bits defined in B.558}559LLVM_DEBUG(dbgs() << "meet fragment maps for "560<< Aggregates[AVar].first->getName() << "\n");561AFrags = meetFragments(AFrags, BIt->second);562}563}564565bool meet(const BasicBlock &BB,566const SmallPtrSet<BasicBlock *, 16> &Visited) {567LLVM_DEBUG(dbgs() << "meet block info from preds of " << BB.getName()568<< "\n");569570VarFragMap BBLiveIn;571bool FirstMeet = true;572// LiveIn locs for BB is the meet of the already-processed preds' LiveOut573// locs.574for (const BasicBlock *Pred : predecessors(&BB)) {575// Ignore preds that haven't been processed yet. This is essentially the576// same as initialising all variables to implicit top value (⊤) which is577// the identity value for the meet operation.578if (!Visited.count(Pred))579continue;580581auto PredLiveOut = LiveOut.find(Pred);582assert(PredLiveOut != LiveOut.end());583584if (FirstMeet) {585LLVM_DEBUG(dbgs() << "BBLiveIn = " << Pred->getName() << "\n");586BBLiveIn = PredLiveOut->second;587FirstMeet = false;588} else {589LLVM_DEBUG(dbgs() << "BBLiveIn = meet BBLiveIn, " << Pred->getName()590<< "\n");591meetVars(BBLiveIn, PredLiveOut->second);592}593594// An empty set is ⊥ for the intersect-like meet operation. If we've595// already got ⊥ there's no need to run the code - we know the result is596// ⊥ since `meet(a, ⊥) = ⊥`.597if (BBLiveIn.size() == 0)598break;599}600601auto CurrentLiveInEntry = LiveIn.find(&BB);602// If there's no LiveIn entry for the block yet, add it.603if (CurrentLiveInEntry == LiveIn.end()) {604LLVM_DEBUG(dbgs() << "change=true (first) on meet on " << BB.getName()605<< "\n");606LiveIn[&BB] = std::move(BBLiveIn);607return /*Changed=*/true;608}609610// If the LiveIn set has changed (expensive check) update it and return611// true.612if (!varFragMapsAreEqual(BBLiveIn, CurrentLiveInEntry->second)) {613LLVM_DEBUG(dbgs() << "change=true on meet on " << BB.getName() << "\n");614CurrentLiveInEntry->second = std::move(BBLiveIn);615return /*Changed=*/true;616}617618LLVM_DEBUG(dbgs() << "change=false on meet on " << BB.getName() << "\n");619return /*Changed=*/false;620}621622void insertMemLoc(BasicBlock &BB, VarLocInsertPt Before, unsigned Var,623unsigned StartBit, unsigned EndBit, unsigned Base,624DebugLoc DL) {625assert(StartBit < EndBit && "Cannot create fragment of size <= 0");626if (!Base)627return;628FragMemLoc Loc;629Loc.Var = Var;630Loc.OffsetInBits = StartBit;631Loc.SizeInBits = EndBit - StartBit;632assert(Base && "Expected a non-zero ID for Base address");633Loc.Base = Base;634Loc.DL = DL;635BBInsertBeforeMap[&BB][Before].push_back(Loc);636LLVM_DEBUG(dbgs() << "Add mem def for " << Aggregates[Var].first->getName()637<< " bits [" << StartBit << ", " << EndBit << ")\n");638}639640/// Inserts a new dbg def if the interval found when looking up \p StartBit641/// in \p FragMap starts before \p StartBit or ends after \p EndBit (which642/// indicates - assuming StartBit->EndBit has just been inserted - that the643/// slice has been coalesced in the map).644void coalesceFragments(BasicBlock &BB, VarLocInsertPt Before, unsigned Var,645unsigned StartBit, unsigned EndBit, unsigned Base,646DebugLoc DL, const FragsInMemMap &FragMap) {647if (!CoalesceAdjacentFragments)648return;649// We've inserted the location into the map. The map will have coalesced650// adjacent intervals (variable fragments) that describe the same memory651// location. Use this knowledge to insert a debug location that describes652// that coalesced fragment. This may eclipse other locs we've just653// inserted. This is okay as redundant locs will be cleaned up later.654auto CoalescedFrag = FragMap.find(StartBit);655// Bail if no coalescing has taken place.656if (CoalescedFrag.start() == StartBit && CoalescedFrag.stop() == EndBit)657return;658659LLVM_DEBUG(dbgs() << "- Insert loc for bits " << CoalescedFrag.start()660<< " to " << CoalescedFrag.stop() << "\n");661insertMemLoc(BB, Before, Var, CoalescedFrag.start(), CoalescedFrag.stop(),662Base, DL);663}664665void addDef(const VarLocInfo &VarLoc, VarLocInsertPt Before, BasicBlock &BB,666VarFragMap &LiveSet) {667DebugVariable DbgVar = FnVarLocs->getVariable(VarLoc.VariableID);668if (skipVariable(DbgVar.getVariable()))669return;670// Don't bother doing anything for this variables if we know it's fully671// promoted. We're only interested in variables that (sometimes) live on672// the stack here.673if (!VarsWithStackSlot->count(getAggregate(DbgVar)))674return;675unsigned Var = Aggregates.insert(676DebugAggregate(DbgVar.getVariable(), VarLoc.DL.getInlinedAt()));677678// [StartBit: EndBit) are the bits affected by this def.679const DIExpression *DIExpr = VarLoc.Expr;680unsigned StartBit;681unsigned EndBit;682if (auto Frag = DIExpr->getFragmentInfo()) {683StartBit = Frag->OffsetInBits;684EndBit = StartBit + Frag->SizeInBits;685} else {686assert(static_cast<bool>(DbgVar.getVariable()->getSizeInBits()));687StartBit = 0;688EndBit = *DbgVar.getVariable()->getSizeInBits();689}690691// We will only fill fragments for simple memory-describing dbg.value692// intrinsics. If the fragment offset is the same as the offset from the693// base pointer, do The Thing, otherwise fall back to normal dbg.value694// behaviour. AssignmentTrackingLowering has generated DIExpressions695// written in terms of the base pointer.696// TODO: Remove this condition since the fragment offset doesn't always697// equal the offset from base pointer (e.g. for a SROA-split variable).698const auto DerefOffsetInBytes = getDerefOffsetInBytes(DIExpr);699const unsigned Base =700DerefOffsetInBytes && *DerefOffsetInBytes * 8 == StartBit701? Bases.insert(VarLoc.Values)702: 0;703LLVM_DEBUG(dbgs() << "DEF " << DbgVar.getVariable()->getName() << " ["704<< StartBit << ", " << EndBit << "): " << toString(Base)705<< "\n");706707// First of all, any locs that use mem that are disrupted need reinstating.708// Unfortunately, IntervalMap doesn't let us insert intervals that overlap709// with existing intervals so this code involves a lot of fiddling around710// with intervals to do that manually.711auto FragIt = LiveSet.find(Var);712713// Check if the variable does not exist in the map.714if (FragIt == LiveSet.end()) {715// Add this variable to the BB map.716auto P = LiveSet.try_emplace(Var, FragsInMemMap(IntervalMapAlloc));717assert(P.second && "Var already in map?");718// Add the interval to the fragment map.719P.first->second.insert(StartBit, EndBit, Base);720return;721}722// The variable has an entry in the map.723724FragsInMemMap &FragMap = FragIt->second;725// First check the easy case: the new fragment `f` doesn't overlap with any726// intervals.727if (!FragMap.overlaps(StartBit, EndBit)) {728LLVM_DEBUG(dbgs() << "- No overlaps\n");729FragMap.insert(StartBit, EndBit, Base);730coalesceFragments(BB, Before, Var, StartBit, EndBit, Base, VarLoc.DL,731FragMap);732return;733}734// There is at least one overlap.735736// Does StartBit intersect an existing fragment?737auto FirstOverlap = FragMap.find(StartBit);738assert(FirstOverlap != FragMap.end());739bool IntersectStart = FirstOverlap.start() < StartBit;740741// Does EndBit intersect an existing fragment?742auto LastOverlap = FragMap.find(EndBit);743bool IntersectEnd = LastOverlap.valid() && LastOverlap.start() < EndBit;744745// Check if both ends of `f` intersect the same interval `i`.746if (IntersectStart && IntersectEnd && FirstOverlap == LastOverlap) {747LLVM_DEBUG(dbgs() << "- Intersect single interval @ both ends\n");748// Shorten `i` so that there's space to insert `f`.749// [ f ]750// [ - i - ]751// +752// [ i ][ f ][ i ]753754// Save values for use after inserting a new interval.755auto EndBitOfOverlap = FirstOverlap.stop();756unsigned OverlapValue = FirstOverlap.value();757758// Shorten the overlapping interval.759FirstOverlap.setStop(StartBit);760insertMemLoc(BB, Before, Var, FirstOverlap.start(), StartBit,761OverlapValue, VarLoc.DL);762763// Insert a new interval to represent the end part.764FragMap.insert(EndBit, EndBitOfOverlap, OverlapValue);765insertMemLoc(BB, Before, Var, EndBit, EndBitOfOverlap, OverlapValue,766VarLoc.DL);767768// Insert the new (middle) fragment now there is space.769FragMap.insert(StartBit, EndBit, Base);770} else {771// There's an overlap but `f` may not be fully contained within772// `i`. Shorten any end-point intersections so that we can then773// insert `f`.774// [ - f - ]775// [ - i - ]776// | |777// [ i ]778// Shorten any end-point intersections.779if (IntersectStart) {780LLVM_DEBUG(dbgs() << "- Intersect interval at start\n");781// Split off at the intersection.782FirstOverlap.setStop(StartBit);783insertMemLoc(BB, Before, Var, FirstOverlap.start(), StartBit,784*FirstOverlap, VarLoc.DL);785}786// [ - f - ]787// [ - i - ]788// | |789// [ i ]790if (IntersectEnd) {791LLVM_DEBUG(dbgs() << "- Intersect interval at end\n");792// Split off at the intersection.793LastOverlap.setStart(EndBit);794insertMemLoc(BB, Before, Var, EndBit, LastOverlap.stop(), *LastOverlap,795VarLoc.DL);796}797798LLVM_DEBUG(dbgs() << "- Erase intervals contained within\n");799// FirstOverlap and LastOverlap have been shortened such that they're800// no longer overlapping with [StartBit, EndBit). Delete any overlaps801// that remain (these will be fully contained within `f`).802// [ - f - ] }803// [ - i - ] } Intersection shortening that has happened above.804// | | }805// [ i ] }806// -----------------807// [i2 ] } Intervals fully contained within `f` get erased.808// -----------------809// [ - f - ][ i ] } Completed insertion.810auto It = FirstOverlap;811if (IntersectStart)812++It; // IntersectStart: first overlap has been shortened.813while (It.valid() && It.start() >= StartBit && It.stop() <= EndBit) {814LLVM_DEBUG(dbgs() << "- Erase " << toString(It));815It.erase(); // This increments It after removing the interval.816}817// We've dealt with all the overlaps now!818assert(!FragMap.overlaps(StartBit, EndBit));819LLVM_DEBUG(dbgs() << "- Insert DEF into now-empty space\n");820FragMap.insert(StartBit, EndBit, Base);821}822823coalesceFragments(BB, Before, Var, StartBit, EndBit, Base, VarLoc.DL,824FragMap);825}826827bool skipVariable(const DILocalVariable *V) { return !V->getSizeInBits(); }828829void process(BasicBlock &BB, VarFragMap &LiveSet) {830BBInsertBeforeMap[&BB].clear();831for (auto &I : BB) {832for (DbgVariableRecord &DVR : filterDbgVars(I.getDbgRecordRange())) {833if (const auto *Locs = FnVarLocs->getWedge(&DVR)) {834for (const VarLocInfo &Loc : *Locs) {835addDef(Loc, &DVR, *I.getParent(), LiveSet);836}837}838}839if (const auto *Locs = FnVarLocs->getWedge(&I)) {840for (const VarLocInfo &Loc : *Locs) {841addDef(Loc, &I, *I.getParent(), LiveSet);842}843}844}845}846847public:848MemLocFragmentFill(Function &Fn,849const DenseSet<DebugAggregate> *VarsWithStackSlot,850bool CoalesceAdjacentFragments)851: Fn(Fn), VarsWithStackSlot(VarsWithStackSlot),852CoalesceAdjacentFragments(CoalesceAdjacentFragments) {}853854/// Add variable locations to \p FnVarLocs so that any bits of a variable855/// with a memory location have that location explicitly reinstated at each856/// subsequent variable location definition that that doesn't overwrite those857/// bits. i.e. after a variable location def, insert new defs for the memory858/// location with fragments for the difference of "all bits currently in859/// memory" and "the fragment of the second def". e.g.860///861/// Before:862///863/// var x bits 0 to 63: value in memory864/// more instructions865/// var x bits 0 to 31: value is %0866///867/// After:868///869/// var x bits 0 to 63: value in memory870/// more instructions871/// var x bits 0 to 31: value is %0872/// var x bits 32 to 61: value in memory ; <-- new loc def873///874void run(FunctionVarLocsBuilder *FnVarLocs) {875if (!EnableMemLocFragFill)876return;877878this->FnVarLocs = FnVarLocs;879880// Prepare for traversal.881//882ReversePostOrderTraversal<Function *> RPOT(&Fn);883std::priority_queue<unsigned int, std::vector<unsigned int>,884std::greater<unsigned int>>885Worklist;886std::priority_queue<unsigned int, std::vector<unsigned int>,887std::greater<unsigned int>>888Pending;889DenseMap<unsigned int, BasicBlock *> OrderToBB;890DenseMap<BasicBlock *, unsigned int> BBToOrder;891{ // Init OrderToBB and BBToOrder.892unsigned int RPONumber = 0;893for (BasicBlock *BB : RPOT) {894OrderToBB[RPONumber] = BB;895BBToOrder[BB] = RPONumber;896Worklist.push(RPONumber);897++RPONumber;898}899LiveIn.init(RPONumber);900LiveOut.init(RPONumber);901}902903// Perform the traversal.904//905// This is a standard "intersect of predecessor outs" dataflow problem. To906// solve it, we perform meet() and process() using the two worklist method907// until the LiveIn data for each block becomes unchanging.908//909// This dataflow is essentially working on maps of sets and at each meet we910// intersect the maps and the mapped sets. So, initialized live-in maps911// monotonically decrease in value throughout the dataflow.912SmallPtrSet<BasicBlock *, 16> Visited;913while (!Worklist.empty() || !Pending.empty()) {914// We track what is on the pending worklist to avoid inserting the same915// thing twice. We could avoid this with a custom priority queue, but916// this is probably not worth it.917SmallPtrSet<BasicBlock *, 16> OnPending;918LLVM_DEBUG(dbgs() << "Processing Worklist\n");919while (!Worklist.empty()) {920BasicBlock *BB = OrderToBB[Worklist.top()];921LLVM_DEBUG(dbgs() << "\nPop BB " << BB->getName() << "\n");922Worklist.pop();923bool InChanged = meet(*BB, Visited);924// Always consider LiveIn changed on the first visit.925InChanged |= Visited.insert(BB).second;926if (InChanged) {927LLVM_DEBUG(dbgs()928<< BB->getName() << " has new InLocs, process it\n");929// Mutate a copy of LiveIn while processing BB. Once we've processed930// the terminator LiveSet is the LiveOut set for BB.931// This is an expensive copy!932VarFragMap LiveSet = LiveIn[BB];933934// Process the instructions in the block.935process(*BB, LiveSet);936937// Relatively expensive check: has anything changed in LiveOut for BB?938if (!varFragMapsAreEqual(LiveOut[BB], LiveSet)) {939LLVM_DEBUG(dbgs() << BB->getName()940<< " has new OutLocs, add succs to worklist: [ ");941LiveOut[BB] = std::move(LiveSet);942for (BasicBlock *Succ : successors(BB)) {943if (OnPending.insert(Succ).second) {944LLVM_DEBUG(dbgs() << Succ->getName() << " ");945Pending.push(BBToOrder[Succ]);946}947}948LLVM_DEBUG(dbgs() << "]\n");949}950}951}952Worklist.swap(Pending);953// At this point, pending must be empty, since it was just the empty954// worklist955assert(Pending.empty() && "Pending should be empty");956}957958// Insert new location defs.959for (auto &Pair : BBInsertBeforeMap) {960InsertMap &Map = Pair.second;961for (auto &Pair : Map) {962auto InsertBefore = Pair.first;963assert(InsertBefore && "should never be null");964auto FragMemLocs = Pair.second;965auto &Ctx = Fn.getContext();966967for (auto &FragMemLoc : FragMemLocs) {968DIExpression *Expr = DIExpression::get(Ctx, std::nullopt);969if (FragMemLoc.SizeInBits !=970*Aggregates[FragMemLoc.Var].first->getSizeInBits())971Expr = *DIExpression::createFragmentExpression(972Expr, FragMemLoc.OffsetInBits, FragMemLoc.SizeInBits);973Expr = DIExpression::prepend(Expr, DIExpression::DerefAfter,974FragMemLoc.OffsetInBits / 8);975DebugVariable Var(Aggregates[FragMemLoc.Var].first, Expr,976FragMemLoc.DL.getInlinedAt());977FnVarLocs->addVarLoc(InsertBefore, Var, Expr, FragMemLoc.DL,978Bases[FragMemLoc.Base]);979}980}981}982}983};984985/// AssignmentTrackingLowering encapsulates a dataflow analysis over a function986/// that interprets assignment tracking debug info metadata and stores in IR to987/// create a map of variable locations.988class AssignmentTrackingLowering {989public:990/// The kind of location in use for a variable, where Mem is the stack home,991/// Val is an SSA value or const, and None means that there is not one single992/// kind (either because there are multiple or because there is none; it may993/// prove useful to split this into two values in the future).994///995/// LocKind is a join-semilattice with the partial order:996/// None > Mem, Val997///998/// i.e.999/// join(Mem, Mem) = Mem1000/// join(Val, Val) = Val1001/// join(Mem, Val) = None1002/// join(None, Mem) = None1003/// join(None, Val) = None1004/// join(None, None) = None1005///1006/// Note: the order is not `None > Val > Mem` because we're using DIAssignID1007/// to name assignments and are not tracking the actual stored values.1008/// Therefore currently there's no way to ensure that Mem values and Val1009/// values are the same. This could be a future extension, though it's not1010/// clear that many additional locations would be recovered that way in1011/// practice as the likelihood of this sitation arising naturally seems1012/// incredibly low.1013enum class LocKind { Mem, Val, None };10141015/// An abstraction of the assignment of a value to a variable or memory1016/// location.1017///1018/// An Assignment is Known or NoneOrPhi. A Known Assignment means we have a1019/// DIAssignID ptr that represents it. NoneOrPhi means that we don't (or1020/// can't) know the ID of the last assignment that took place.1021///1022/// The Status of the Assignment (Known or NoneOrPhi) is another1023/// join-semilattice. The partial order is:1024/// NoneOrPhi > Known {id_0, id_1, ...id_N}1025///1026/// i.e. for all values x and y where x != y:1027/// join(x, x) = x1028/// join(x, y) = NoneOrPhi1029using AssignRecord = PointerUnion<DbgAssignIntrinsic *, DbgVariableRecord *>;1030struct Assignment {1031enum S { Known, NoneOrPhi } Status;1032/// ID of the assignment. nullptr if Status is not Known.1033DIAssignID *ID;1034/// The dbg.assign that marks this dbg-def. Mem-defs don't use this field.1035/// May be nullptr.1036AssignRecord Source;10371038bool isSameSourceAssignment(const Assignment &Other) const {1039// Don't include Source in the equality check. Assignments are1040// defined by their ID, not debug intrinsic(s).1041return std::tie(Status, ID) == std::tie(Other.Status, Other.ID);1042}1043void dump(raw_ostream &OS) {1044static const char *LUT[] = {"Known", "NoneOrPhi"};1045OS << LUT[Status] << "(id=";1046if (ID)1047OS << ID;1048else1049OS << "null";1050OS << ", s=";1051if (Source.isNull())1052OS << "null";1053else if (isa<DbgAssignIntrinsic *>(Source))1054OS << Source.get<DbgAssignIntrinsic *>();1055else1056OS << Source.get<DbgVariableRecord *>();1057OS << ")";1058}10591060static Assignment make(DIAssignID *ID, DbgAssignIntrinsic *Source) {1061return Assignment(Known, ID, Source);1062}1063static Assignment make(DIAssignID *ID, DbgVariableRecord *Source) {1064assert(Source->isDbgAssign() &&1065"Cannot make an assignment from a non-assign DbgVariableRecord");1066return Assignment(Known, ID, Source);1067}1068static Assignment make(DIAssignID *ID, AssignRecord Source) {1069return Assignment(Known, ID, Source);1070}1071static Assignment makeFromMemDef(DIAssignID *ID) {1072return Assignment(Known, ID);1073}1074static Assignment makeNoneOrPhi() { return Assignment(NoneOrPhi, nullptr); }1075// Again, need a Top value?1076Assignment() : Status(NoneOrPhi), ID(nullptr) {} // Can we delete this?1077Assignment(S Status, DIAssignID *ID) : Status(Status), ID(ID) {1078// If the Status is Known then we expect there to be an assignment ID.1079assert(Status == NoneOrPhi || ID);1080}1081Assignment(S Status, DIAssignID *ID, DbgAssignIntrinsic *Source)1082: Status(Status), ID(ID), Source(Source) {1083// If the Status is Known then we expect there to be an assignment ID.1084assert(Status == NoneOrPhi || ID);1085}1086Assignment(S Status, DIAssignID *ID, DbgVariableRecord *Source)1087: Status(Status), ID(ID), Source(Source) {1088// If the Status is Known then we expect there to be an assignment ID.1089assert(Status == NoneOrPhi || ID);1090}1091Assignment(S Status, DIAssignID *ID, AssignRecord Source)1092: Status(Status), ID(ID), Source(Source) {1093// If the Status is Known then we expect there to be an assignment ID.1094assert(Status == NoneOrPhi || ID);1095}1096};10971098using AssignmentMap = SmallVector<Assignment>;1099using LocMap = SmallVector<LocKind>;1100using OverlapMap = DenseMap<VariableID, SmallVector<VariableID>>;1101using UntaggedStoreAssignmentMap =1102DenseMap<const Instruction *,1103SmallVector<std::pair<VariableID, at::AssignmentInfo>>>;11041105private:1106/// The highest numbered VariableID for partially promoted variables plus 1,1107/// the values for which start at 1.1108unsigned TrackedVariablesVectorSize = 0;1109/// Map a variable to the set of variables that it fully contains.1110OverlapMap VarContains;1111/// Map untagged stores to the variable fragments they assign to. Used by1112/// processUntaggedInstruction.1113UntaggedStoreAssignmentMap UntaggedStoreVars;11141115// Machinery to defer inserting dbg.values.1116using InstInsertMap = MapVector<VarLocInsertPt, SmallVector<VarLocInfo>>;1117InstInsertMap InsertBeforeMap;1118/// Clear the location definitions currently cached for insertion after /p1119/// After.1120void resetInsertionPoint(Instruction &After);1121void resetInsertionPoint(DbgVariableRecord &After);11221123// emitDbgValue can be called with:1124// Source=[AssignRecord|DbgValueInst*|DbgAssignIntrinsic*|DbgVariableRecord*]1125// Since AssignRecord can be cast to one of the latter two types, and all1126// other types have a shared interface, we use a template to handle the latter1127// three types, and an explicit overload for AssignRecord that forwards to1128// the template version with the right type.1129void emitDbgValue(LocKind Kind, AssignRecord Source, VarLocInsertPt After);1130template <typename T>1131void emitDbgValue(LocKind Kind, const T Source, VarLocInsertPt After);11321133static bool mapsAreEqual(const BitVector &Mask, const AssignmentMap &A,1134const AssignmentMap &B) {1135return llvm::all_of(Mask.set_bits(), [&](unsigned VarID) {1136return A[VarID].isSameSourceAssignment(B[VarID]);1137});1138}11391140/// Represents the stack and debug assignments in a block. Used to describe1141/// the live-in and live-out values for blocks, as well as the "current"1142/// value as we process each instruction in a block.1143struct BlockInfo {1144/// The set of variables (VariableID) being tracked in this block.1145BitVector VariableIDsInBlock;1146/// Dominating assignment to memory for each variable, indexed by1147/// VariableID.1148AssignmentMap StackHomeValue;1149/// Dominating assignemnt to each variable, indexed by VariableID.1150AssignmentMap DebugValue;1151/// Location kind for each variable. LiveLoc indicates whether the1152/// dominating assignment in StackHomeValue (LocKind::Mem), DebugValue1153/// (LocKind::Val), or neither (LocKind::None) is valid, in that order of1154/// preference. This cannot be derived by inspecting DebugValue and1155/// StackHomeValue due to the fact that there's no distinction in1156/// Assignment (the class) between whether an assignment is unknown or a1157/// merge of multiple assignments (both are Status::NoneOrPhi). In other1158/// words, the memory location may well be valid while both DebugValue and1159/// StackHomeValue contain Assignments that have a Status of NoneOrPhi.1160/// Indexed by VariableID.1161LocMap LiveLoc;11621163public:1164enum AssignmentKind { Stack, Debug };1165const AssignmentMap &getAssignmentMap(AssignmentKind Kind) const {1166switch (Kind) {1167case Stack:1168return StackHomeValue;1169case Debug:1170return DebugValue;1171}1172llvm_unreachable("Unknown AssignmentKind");1173}1174AssignmentMap &getAssignmentMap(AssignmentKind Kind) {1175return const_cast<AssignmentMap &>(1176const_cast<const BlockInfo *>(this)->getAssignmentMap(Kind));1177}11781179bool isVariableTracked(VariableID Var) const {1180return VariableIDsInBlock[static_cast<unsigned>(Var)];1181}11821183const Assignment &getAssignment(AssignmentKind Kind, VariableID Var) const {1184assert(isVariableTracked(Var) && "Var not tracked in block");1185return getAssignmentMap(Kind)[static_cast<unsigned>(Var)];1186}11871188LocKind getLocKind(VariableID Var) const {1189assert(isVariableTracked(Var) && "Var not tracked in block");1190return LiveLoc[static_cast<unsigned>(Var)];1191}11921193/// Set LocKind for \p Var only: does not set LocKind for VariableIDs of1194/// fragments contained win \p Var.1195void setLocKind(VariableID Var, LocKind K) {1196VariableIDsInBlock.set(static_cast<unsigned>(Var));1197LiveLoc[static_cast<unsigned>(Var)] = K;1198}11991200/// Set the assignment in the \p Kind assignment map for \p Var only: does1201/// not set the assignment for VariableIDs of fragments contained win \p1202/// Var.1203void setAssignment(AssignmentKind Kind, VariableID Var,1204const Assignment &AV) {1205VariableIDsInBlock.set(static_cast<unsigned>(Var));1206getAssignmentMap(Kind)[static_cast<unsigned>(Var)] = AV;1207}12081209/// Return true if there is an assignment matching \p AV in the \p Kind1210/// assignment map. Does consider assignments for VariableIDs of fragments1211/// contained win \p Var.1212bool hasAssignment(AssignmentKind Kind, VariableID Var,1213const Assignment &AV) const {1214if (!isVariableTracked(Var))1215return false;1216return AV.isSameSourceAssignment(getAssignment(Kind, Var));1217}12181219/// Compare every element in each map to determine structural equality1220/// (slow).1221bool operator==(const BlockInfo &Other) const {1222return VariableIDsInBlock == Other.VariableIDsInBlock &&1223LiveLoc == Other.LiveLoc &&1224mapsAreEqual(VariableIDsInBlock, StackHomeValue,1225Other.StackHomeValue) &&1226mapsAreEqual(VariableIDsInBlock, DebugValue, Other.DebugValue);1227}1228bool operator!=(const BlockInfo &Other) const { return !(*this == Other); }1229bool isValid() {1230return LiveLoc.size() == DebugValue.size() &&1231LiveLoc.size() == StackHomeValue.size();1232}12331234/// Clear everything and initialise with ⊤-values for all variables.1235void init(int NumVars) {1236StackHomeValue.clear();1237DebugValue.clear();1238LiveLoc.clear();1239VariableIDsInBlock = BitVector(NumVars);1240StackHomeValue.insert(StackHomeValue.begin(), NumVars,1241Assignment::makeNoneOrPhi());1242DebugValue.insert(DebugValue.begin(), NumVars,1243Assignment::makeNoneOrPhi());1244LiveLoc.insert(LiveLoc.begin(), NumVars, LocKind::None);1245}12461247/// Helper for join.1248template <typename ElmtType, typename FnInputType>1249static void joinElmt(int Index, SmallVector<ElmtType> &Target,1250const SmallVector<ElmtType> &A,1251const SmallVector<ElmtType> &B,1252ElmtType (*Fn)(FnInputType, FnInputType)) {1253Target[Index] = Fn(A[Index], B[Index]);1254}12551256/// See comment for AssignmentTrackingLowering::joinBlockInfo.1257static BlockInfo join(const BlockInfo &A, const BlockInfo &B, int NumVars) {1258// Join A and B.1259//1260// Intersect = join(a, b) for a in A, b in B where Var(a) == Var(b)1261// Difference = join(x, ⊤) for x where Var(x) is in A xor B1262// Join = Intersect ∪ Difference1263//1264// This is achieved by performing a join on elements from A and B with1265// variables common to both A and B (join elements indexed by var1266// intersect), then adding ⊤-value elements for vars in A xor B. The1267// latter part is equivalent to performing join on elements with variables1268// in A xor B with the ⊤-value for the map element since join(x, ⊤) = ⊤.1269// BlockInfo::init initializes all variable entries to the ⊤ value so we1270// don't need to explicitly perform that step as Join.VariableIDsInBlock1271// is set to the union of the variables in A and B at the end of this1272// function.1273BlockInfo Join;1274Join.init(NumVars);12751276BitVector Intersect = A.VariableIDsInBlock;1277Intersect &= B.VariableIDsInBlock;12781279for (auto VarID : Intersect.set_bits()) {1280joinElmt(VarID, Join.LiveLoc, A.LiveLoc, B.LiveLoc, joinKind);1281joinElmt(VarID, Join.DebugValue, A.DebugValue, B.DebugValue,1282joinAssignment);1283joinElmt(VarID, Join.StackHomeValue, A.StackHomeValue, B.StackHomeValue,1284joinAssignment);1285}12861287Join.VariableIDsInBlock = A.VariableIDsInBlock;1288Join.VariableIDsInBlock |= B.VariableIDsInBlock;1289assert(Join.isValid());1290return Join;1291}1292};12931294Function &Fn;1295const DataLayout &Layout;1296const DenseSet<DebugAggregate> *VarsWithStackSlot;1297FunctionVarLocsBuilder *FnVarLocs;1298DenseMap<const BasicBlock *, BlockInfo> LiveIn;1299DenseMap<const BasicBlock *, BlockInfo> LiveOut;13001301/// Helper for process methods to track variables touched each frame.1302DenseSet<VariableID> VarsTouchedThisFrame;13031304/// The set of variables that sometimes are not located in their stack home.1305DenseSet<DebugAggregate> NotAlwaysStackHomed;13061307VariableID getVariableID(const DebugVariable &Var) {1308return static_cast<VariableID>(FnVarLocs->insertVariable(Var));1309}13101311/// Join the LiveOut values of preds that are contained in \p Visited into1312/// LiveIn[BB]. Return True if LiveIn[BB] has changed as a result. LiveIn[BB]1313/// values monotonically increase. See the @link joinMethods join methods1314/// @endlink documentation for more info.1315bool join(const BasicBlock &BB, const SmallPtrSet<BasicBlock *, 16> &Visited);1316///@name joinMethods1317/// Functions that implement `join` (the least upper bound) for the1318/// join-semilattice types used in the dataflow. There is an explicit bottom1319/// value (⊥) for some types and and explicit top value (⊤) for all types.1320/// By definition:1321///1322/// Join(A, B) >= A && Join(A, B) >= B1323/// Join(A, ⊥) = A1324/// Join(A, ⊤) = ⊤1325///1326/// These invariants are important for monotonicity.1327///1328/// For the map-type functions, all unmapped keys in an empty map are1329/// associated with a bottom value (⊥). This represents their values being1330/// unknown. Unmapped keys in non-empty maps (joining two maps with a key1331/// only present in one) represents either a variable going out of scope or1332/// dropped debug info. It is assumed the key is associated with a top value1333/// (⊤) in this case (unknown location / assignment).1334///@{1335static LocKind joinKind(LocKind A, LocKind B);1336static Assignment joinAssignment(const Assignment &A, const Assignment &B);1337BlockInfo joinBlockInfo(const BlockInfo &A, const BlockInfo &B);1338///@}13391340/// Process the instructions in \p BB updating \p LiveSet along the way. \p1341/// LiveSet must be initialized with the current live-in locations before1342/// calling this.1343void process(BasicBlock &BB, BlockInfo *LiveSet);1344///@name processMethods1345/// Methods to process instructions in order to update the LiveSet (current1346/// location information).1347///@{1348void processNonDbgInstruction(Instruction &I, BlockInfo *LiveSet);1349void processDbgInstruction(DbgInfoIntrinsic &I, BlockInfo *LiveSet);1350/// Update \p LiveSet after encountering an instruction with a DIAssignID1351/// attachment, \p I.1352void processTaggedInstruction(Instruction &I, BlockInfo *LiveSet);1353/// Update \p LiveSet after encountering an instruciton without a DIAssignID1354/// attachment, \p I.1355void processUntaggedInstruction(Instruction &I, BlockInfo *LiveSet);1356void processDbgAssign(AssignRecord Assign, BlockInfo *LiveSet);1357void processDbgVariableRecord(DbgVariableRecord &DVR, BlockInfo *LiveSet);1358void processDbgValue(1359PointerUnion<DbgValueInst *, DbgVariableRecord *> DbgValueRecord,1360BlockInfo *LiveSet);1361/// Add an assignment to memory for the variable /p Var.1362void addMemDef(BlockInfo *LiveSet, VariableID Var, const Assignment &AV);1363/// Add an assignment to the variable /p Var.1364void addDbgDef(BlockInfo *LiveSet, VariableID Var, const Assignment &AV);1365///@}13661367/// Set the LocKind for \p Var.1368void setLocKind(BlockInfo *LiveSet, VariableID Var, LocKind K);1369/// Get the live LocKind for a \p Var. Requires addMemDef or addDbgDef to1370/// have been called for \p Var first.1371LocKind getLocKind(BlockInfo *LiveSet, VariableID Var);1372/// Return true if \p Var has an assignment in \p M matching \p AV.1373bool hasVarWithAssignment(BlockInfo *LiveSet, BlockInfo::AssignmentKind Kind,1374VariableID Var, const Assignment &AV);1375/// Return the set of VariableIDs corresponding the fragments contained fully1376/// within the variable/fragment \p Var.1377ArrayRef<VariableID> getContainedFragments(VariableID Var) const;13781379/// Mark \p Var as having been touched this frame. Note, this applies only1380/// to the exact fragment \p Var and not to any fragments contained within.1381void touchFragment(VariableID Var);13821383/// Emit info for variables that are fully promoted.1384bool emitPromotedVarLocs(FunctionVarLocsBuilder *FnVarLocs);13851386public:1387AssignmentTrackingLowering(Function &Fn, const DataLayout &Layout,1388const DenseSet<DebugAggregate> *VarsWithStackSlot)1389: Fn(Fn), Layout(Layout), VarsWithStackSlot(VarsWithStackSlot) {}1390/// Run the analysis, adding variable location info to \p FnVarLocs. Returns1391/// true if any variable locations have been added to FnVarLocs.1392bool run(FunctionVarLocsBuilder *FnVarLocs);1393};1394} // namespace13951396ArrayRef<VariableID>1397AssignmentTrackingLowering::getContainedFragments(VariableID Var) const {1398auto R = VarContains.find(Var);1399if (R == VarContains.end())1400return std::nullopt;1401return R->second;1402}14031404void AssignmentTrackingLowering::touchFragment(VariableID Var) {1405VarsTouchedThisFrame.insert(Var);1406}14071408void AssignmentTrackingLowering::setLocKind(BlockInfo *LiveSet, VariableID Var,1409LocKind K) {1410auto SetKind = [this](BlockInfo *LiveSet, VariableID Var, LocKind K) {1411LiveSet->setLocKind(Var, K);1412touchFragment(Var);1413};1414SetKind(LiveSet, Var, K);14151416// Update the LocKind for all fragments contained within Var.1417for (VariableID Frag : getContainedFragments(Var))1418SetKind(LiveSet, Frag, K);1419}14201421AssignmentTrackingLowering::LocKind1422AssignmentTrackingLowering::getLocKind(BlockInfo *LiveSet, VariableID Var) {1423return LiveSet->getLocKind(Var);1424}14251426void AssignmentTrackingLowering::addMemDef(BlockInfo *LiveSet, VariableID Var,1427const Assignment &AV) {1428LiveSet->setAssignment(BlockInfo::Stack, Var, AV);14291430// Use this assigment for all fragments contained within Var, but do not1431// provide a Source because we cannot convert Var's value to a value for the1432// fragment.1433Assignment FragAV = AV;1434FragAV.Source = nullptr;1435for (VariableID Frag : getContainedFragments(Var))1436LiveSet->setAssignment(BlockInfo::Stack, Frag, FragAV);1437}14381439void AssignmentTrackingLowering::addDbgDef(BlockInfo *LiveSet, VariableID Var,1440const Assignment &AV) {1441LiveSet->setAssignment(BlockInfo::Debug, Var, AV);14421443// Use this assigment for all fragments contained within Var, but do not1444// provide a Source because we cannot convert Var's value to a value for the1445// fragment.1446Assignment FragAV = AV;1447FragAV.Source = nullptr;1448for (VariableID Frag : getContainedFragments(Var))1449LiveSet->setAssignment(BlockInfo::Debug, Frag, FragAV);1450}14511452static DIAssignID *getIDFromInst(const Instruction &I) {1453return cast<DIAssignID>(I.getMetadata(LLVMContext::MD_DIAssignID));1454}14551456static DIAssignID *getIDFromMarker(const DbgAssignIntrinsic &DAI) {1457return cast<DIAssignID>(DAI.getAssignID());1458}14591460static DIAssignID *getIDFromMarker(const DbgVariableRecord &DVR) {1461assert(DVR.isDbgAssign() &&1462"Cannot get a DIAssignID from a non-assign DbgVariableRecord!");1463return DVR.getAssignID();1464}14651466/// Return true if \p Var has an assignment in \p M matching \p AV.1467bool AssignmentTrackingLowering::hasVarWithAssignment(1468BlockInfo *LiveSet, BlockInfo::AssignmentKind Kind, VariableID Var,1469const Assignment &AV) {1470if (!LiveSet->hasAssignment(Kind, Var, AV))1471return false;14721473// Check all the frags contained within Var as these will have all been1474// mapped to AV at the last store to Var.1475for (VariableID Frag : getContainedFragments(Var))1476if (!LiveSet->hasAssignment(Kind, Frag, AV))1477return false;1478return true;1479}14801481#ifndef NDEBUG1482const char *locStr(AssignmentTrackingLowering::LocKind Loc) {1483using LocKind = AssignmentTrackingLowering::LocKind;1484switch (Loc) {1485case LocKind::Val:1486return "Val";1487case LocKind::Mem:1488return "Mem";1489case LocKind::None:1490return "None";1491};1492llvm_unreachable("unknown LocKind");1493}1494#endif14951496VarLocInsertPt getNextNode(const DbgRecord *DVR) {1497auto NextIt = ++(DVR->getIterator());1498if (NextIt == DVR->getMarker()->getDbgRecordRange().end())1499return DVR->getMarker()->MarkedInstr;1500return &*NextIt;1501}1502VarLocInsertPt getNextNode(const Instruction *Inst) {1503const Instruction *Next = Inst->getNextNode();1504if (!Next->hasDbgRecords())1505return Next;1506return &*Next->getDbgRecordRange().begin();1507}1508VarLocInsertPt getNextNode(VarLocInsertPt InsertPt) {1509if (isa<const Instruction *>(InsertPt))1510return getNextNode(cast<const Instruction *>(InsertPt));1511return getNextNode(cast<const DbgRecord *>(InsertPt));1512}15131514DbgAssignIntrinsic *CastToDbgAssign(DbgVariableIntrinsic *DVI) {1515return cast<DbgAssignIntrinsic>(DVI);1516}15171518DbgVariableRecord *CastToDbgAssign(DbgVariableRecord *DVR) {1519assert(DVR->isDbgAssign() &&1520"Attempted to cast non-assign DbgVariableRecord to DVRAssign.");1521return DVR;1522}15231524void AssignmentTrackingLowering::emitDbgValue(1525AssignmentTrackingLowering::LocKind Kind,1526AssignmentTrackingLowering::AssignRecord Source, VarLocInsertPt After) {1527if (isa<DbgAssignIntrinsic *>(Source))1528emitDbgValue(Kind, cast<DbgAssignIntrinsic *>(Source), After);1529else1530emitDbgValue(Kind, cast<DbgVariableRecord *>(Source), After);1531}1532template <typename T>1533void AssignmentTrackingLowering::emitDbgValue(1534AssignmentTrackingLowering::LocKind Kind, const T Source,1535VarLocInsertPt After) {15361537DILocation *DL = Source->getDebugLoc();1538auto Emit = [this, Source, After, DL](Metadata *Val, DIExpression *Expr) {1539assert(Expr);1540if (!Val)1541Val = ValueAsMetadata::get(1542PoisonValue::get(Type::getInt1Ty(Source->getContext())));15431544// Find a suitable insert point.1545auto InsertBefore = getNextNode(After);1546assert(InsertBefore && "Shouldn't be inserting after a terminator");15471548VariableID Var = getVariableID(DebugVariable(Source));1549VarLocInfo VarLoc;1550VarLoc.VariableID = static_cast<VariableID>(Var);1551VarLoc.Expr = Expr;1552VarLoc.Values = RawLocationWrapper(Val);1553VarLoc.DL = DL;1554// Insert it into the map for later.1555InsertBeforeMap[InsertBefore].push_back(VarLoc);1556};15571558// NOTE: This block can mutate Kind.1559if (Kind == LocKind::Mem) {1560const auto *Assign = CastToDbgAssign(Source);1561// Check the address hasn't been dropped (e.g. the debug uses may not have1562// been replaced before deleting a Value).1563if (Assign->isKillAddress()) {1564// The address isn't valid so treat this as a non-memory def.1565Kind = LocKind::Val;1566} else {1567Value *Val = Assign->getAddress();1568DIExpression *Expr = Assign->getAddressExpression();1569assert(!Expr->getFragmentInfo() &&1570"fragment info should be stored in value-expression only");1571// Copy the fragment info over from the value-expression to the new1572// DIExpression.1573if (auto OptFragInfo = Source->getExpression()->getFragmentInfo()) {1574auto FragInfo = *OptFragInfo;1575Expr = *DIExpression::createFragmentExpression(1576Expr, FragInfo.OffsetInBits, FragInfo.SizeInBits);1577}1578// The address-expression has an implicit deref, add it now.1579std::tie(Val, Expr) =1580walkToAllocaAndPrependOffsetDeref(Layout, Val, Expr);1581Emit(ValueAsMetadata::get(Val), Expr);1582return;1583}1584}15851586if (Kind == LocKind::Val) {1587Emit(Source->getRawLocation(), Source->getExpression());1588return;1589}15901591if (Kind == LocKind::None) {1592Emit(nullptr, Source->getExpression());1593return;1594}1595}15961597void AssignmentTrackingLowering::processNonDbgInstruction(1598Instruction &I, AssignmentTrackingLowering::BlockInfo *LiveSet) {1599if (I.hasMetadata(LLVMContext::MD_DIAssignID))1600processTaggedInstruction(I, LiveSet);1601else1602processUntaggedInstruction(I, LiveSet);1603}16041605void AssignmentTrackingLowering::processUntaggedInstruction(1606Instruction &I, AssignmentTrackingLowering::BlockInfo *LiveSet) {1607// Interpret stack stores that are not tagged as an assignment in memory for1608// the variables associated with that address. These stores may not be tagged1609// because a) the store cannot be represented using dbg.assigns (non-const1610// length or offset) or b) the tag was accidentally dropped during1611// optimisations. For these stores we fall back to assuming that the stack1612// home is a valid location for the variables. The benefit is that this1613// prevents us missing an assignment and therefore incorrectly maintaining1614// earlier location definitions, and in many cases it should be a reasonable1615// assumption. However, this will occasionally lead to slight1616// inaccuracies. The value of a hoisted untagged store will be visible1617// "early", for example.1618assert(!I.hasMetadata(LLVMContext::MD_DIAssignID));1619auto It = UntaggedStoreVars.find(&I);1620if (It == UntaggedStoreVars.end())1621return; // No variables associated with the store destination.16221623LLVM_DEBUG(dbgs() << "processUntaggedInstruction on UNTAGGED INST " << I1624<< "\n");1625// Iterate over the variables that this store affects, add a NoneOrPhi dbg1626// and mem def, set lockind to Mem, and emit a location def for each.1627for (auto [Var, Info] : It->second) {1628// This instruction is treated as both a debug and memory assignment,1629// meaning the memory location should be used. We don't have an assignment1630// ID though so use Assignment::makeNoneOrPhi() to create an imaginary one.1631addMemDef(LiveSet, Var, Assignment::makeNoneOrPhi());1632addDbgDef(LiveSet, Var, Assignment::makeNoneOrPhi());1633setLocKind(LiveSet, Var, LocKind::Mem);1634LLVM_DEBUG(dbgs() << " setting Stack LocKind to: " << locStr(LocKind::Mem)1635<< "\n");1636// Build the dbg location def to insert.1637//1638// DIExpression: Add fragment and offset.1639DebugVariable V = FnVarLocs->getVariable(Var);1640DIExpression *DIE = DIExpression::get(I.getContext(), std::nullopt);1641if (auto Frag = V.getFragment()) {1642auto R = DIExpression::createFragmentExpression(DIE, Frag->OffsetInBits,1643Frag->SizeInBits);1644assert(R && "unexpected createFragmentExpression failure");1645DIE = *R;1646}1647SmallVector<uint64_t, 3> Ops;1648if (Info.OffsetInBits)1649Ops = {dwarf::DW_OP_plus_uconst, Info.OffsetInBits / 8};1650Ops.push_back(dwarf::DW_OP_deref);1651DIE = DIExpression::prependOpcodes(DIE, Ops, /*StackValue=*/false,1652/*EntryValue=*/false);1653// Find a suitable insert point, before the next instruction or DbgRecord1654// after I.1655auto InsertBefore = getNextNode(&I);1656assert(InsertBefore && "Shouldn't be inserting after a terminator");16571658// Get DILocation for this unrecorded assignment.1659DILocation *InlinedAt = const_cast<DILocation *>(V.getInlinedAt());1660const DILocation *DILoc = DILocation::get(1661Fn.getContext(), 0, 0, V.getVariable()->getScope(), InlinedAt);16621663VarLocInfo VarLoc;1664VarLoc.VariableID = static_cast<VariableID>(Var);1665VarLoc.Expr = DIE;1666VarLoc.Values = RawLocationWrapper(1667ValueAsMetadata::get(const_cast<AllocaInst *>(Info.Base)));1668VarLoc.DL = DILoc;1669// 3. Insert it into the map for later.1670InsertBeforeMap[InsertBefore].push_back(VarLoc);1671}1672}16731674void AssignmentTrackingLowering::processTaggedInstruction(1675Instruction &I, AssignmentTrackingLowering::BlockInfo *LiveSet) {1676auto Linked = at::getAssignmentMarkers(&I);1677auto LinkedDPAssigns = at::getDVRAssignmentMarkers(&I);1678// No dbg.assign intrinsics linked.1679// FIXME: All vars that have a stack slot this store modifies that don't have1680// a dbg.assign linked to it should probably treat this like an untagged1681// store.1682if (Linked.empty() && LinkedDPAssigns.empty())1683return;16841685LLVM_DEBUG(dbgs() << "processTaggedInstruction on " << I << "\n");1686auto ProcessLinkedAssign = [&](auto *Assign) {1687VariableID Var = getVariableID(DebugVariable(Assign));1688// Something has gone wrong if VarsWithStackSlot doesn't contain a variable1689// that is linked to a store.1690assert(VarsWithStackSlot->count(getAggregate(Assign)) &&1691"expected Assign's variable to have stack slot");16921693Assignment AV = Assignment::makeFromMemDef(getIDFromInst(I));1694addMemDef(LiveSet, Var, AV);16951696LLVM_DEBUG(dbgs() << " linked to " << *Assign << "\n");1697LLVM_DEBUG(dbgs() << " LiveLoc " << locStr(getLocKind(LiveSet, Var))1698<< " -> ");16991700// The last assignment to the stack is now AV. Check if the last debug1701// assignment has a matching Assignment.1702if (hasVarWithAssignment(LiveSet, BlockInfo::Debug, Var, AV)) {1703// The StackHomeValue and DebugValue for this variable match so we can1704// emit a stack home location here.1705LLVM_DEBUG(dbgs() << "Mem, Stack matches Debug program\n";);1706LLVM_DEBUG(dbgs() << " Stack val: "; AV.dump(dbgs()); dbgs() << "\n");1707LLVM_DEBUG(dbgs() << " Debug val: ";1708LiveSet->DebugValue[static_cast<unsigned>(Var)].dump(dbgs());1709dbgs() << "\n");1710setLocKind(LiveSet, Var, LocKind::Mem);1711emitDbgValue(LocKind::Mem, Assign, &I);1712return;1713}17141715// The StackHomeValue and DebugValue for this variable do not match. I.e.1716// The value currently stored in the stack is not what we'd expect to1717// see, so we cannot use emit a stack home location here. Now we will1718// look at the live LocKind for the variable and determine an appropriate1719// dbg.value to emit.1720LocKind PrevLoc = getLocKind(LiveSet, Var);1721switch (PrevLoc) {1722case LocKind::Val: {1723// The value in memory in memory has changed but we're not currently1724// using the memory location. Do nothing.1725LLVM_DEBUG(dbgs() << "Val, (unchanged)\n";);1726setLocKind(LiveSet, Var, LocKind::Val);1727} break;1728case LocKind::Mem: {1729// There's been an assignment to memory that we were using as a1730// location for this variable, and the Assignment doesn't match what1731// we'd expect to see in memory.1732Assignment DbgAV = LiveSet->getAssignment(BlockInfo::Debug, Var);1733if (DbgAV.Status == Assignment::NoneOrPhi) {1734// We need to terminate any previously open location now.1735LLVM_DEBUG(dbgs() << "None, No Debug value available\n";);1736setLocKind(LiveSet, Var, LocKind::None);1737emitDbgValue(LocKind::None, Assign, &I);1738} else {1739// The previous DebugValue Value can be used here.1740LLVM_DEBUG(dbgs() << "Val, Debug value is Known\n";);1741setLocKind(LiveSet, Var, LocKind::Val);1742if (DbgAV.Source) {1743emitDbgValue(LocKind::Val, DbgAV.Source, &I);1744} else {1745// PrevAV.Source is nullptr so we must emit undef here.1746emitDbgValue(LocKind::None, Assign, &I);1747}1748}1749} break;1750case LocKind::None: {1751// There's been an assignment to memory and we currently are1752// not tracking a location for the variable. Do not emit anything.1753LLVM_DEBUG(dbgs() << "None, (unchanged)\n";);1754setLocKind(LiveSet, Var, LocKind::None);1755} break;1756}1757};1758for (DbgAssignIntrinsic *DAI : Linked)1759ProcessLinkedAssign(DAI);1760for (DbgVariableRecord *DVR : LinkedDPAssigns)1761ProcessLinkedAssign(DVR);1762}17631764void AssignmentTrackingLowering::processDbgAssign(AssignRecord Assign,1765BlockInfo *LiveSet) {1766auto ProcessDbgAssignImpl = [&](auto *DbgAssign) {1767// Only bother tracking variables that are at some point stack homed. Other1768// variables can be dealt with trivially later.1769if (!VarsWithStackSlot->count(getAggregate(DbgAssign)))1770return;17711772VariableID Var = getVariableID(DebugVariable(DbgAssign));1773Assignment AV = Assignment::make(getIDFromMarker(*DbgAssign), DbgAssign);1774addDbgDef(LiveSet, Var, AV);17751776LLVM_DEBUG(dbgs() << "processDbgAssign on " << *DbgAssign << "\n";);1777LLVM_DEBUG(dbgs() << " LiveLoc " << locStr(getLocKind(LiveSet, Var))1778<< " -> ");17791780// Check if the DebugValue and StackHomeValue both hold the same1781// Assignment.1782if (hasVarWithAssignment(LiveSet, BlockInfo::Stack, Var, AV)) {1783// They match. We can use the stack home because the debug intrinsics1784// state that an assignment happened here, and we know that specific1785// assignment was the last one to take place in memory for this variable.1786LocKind Kind;1787if (DbgAssign->isKillAddress()) {1788LLVM_DEBUG(1789dbgs()1790<< "Val, Stack matches Debug program but address is killed\n";);1791Kind = LocKind::Val;1792} else {1793LLVM_DEBUG(dbgs() << "Mem, Stack matches Debug program\n";);1794Kind = LocKind::Mem;1795};1796setLocKind(LiveSet, Var, Kind);1797emitDbgValue(Kind, DbgAssign, DbgAssign);1798} else {1799// The last assignment to the memory location isn't the one that we want1800// to show to the user so emit a dbg.value(Value). Value may be undef.1801LLVM_DEBUG(dbgs() << "Val, Stack contents is unknown\n";);1802setLocKind(LiveSet, Var, LocKind::Val);1803emitDbgValue(LocKind::Val, DbgAssign, DbgAssign);1804}1805};1806if (isa<DbgVariableRecord *>(Assign))1807return ProcessDbgAssignImpl(cast<DbgVariableRecord *>(Assign));1808return ProcessDbgAssignImpl(cast<DbgAssignIntrinsic *>(Assign));1809}18101811void AssignmentTrackingLowering::processDbgValue(1812PointerUnion<DbgValueInst *, DbgVariableRecord *> DbgValueRecord,1813BlockInfo *LiveSet) {1814auto ProcessDbgValueImpl = [&](auto *DbgValue) {1815// Only other tracking variables that are at some point stack homed.1816// Other variables can be dealt with trivally later.1817if (!VarsWithStackSlot->count(getAggregate(DbgValue)))1818return;18191820VariableID Var = getVariableID(DebugVariable(DbgValue));1821// We have no ID to create an Assignment with so we mark this assignment as1822// NoneOrPhi. Note that the dbg.value still exists, we just cannot determine1823// the assignment responsible for setting this value.1824// This is fine; dbg.values are essentially interchangable with unlinked1825// dbg.assigns, and some passes such as mem2reg and instcombine add them to1826// PHIs for promoted variables.1827Assignment AV = Assignment::makeNoneOrPhi();1828addDbgDef(LiveSet, Var, AV);18291830LLVM_DEBUG(dbgs() << "processDbgValue on " << *DbgValue << "\n";);1831LLVM_DEBUG(dbgs() << " LiveLoc " << locStr(getLocKind(LiveSet, Var))1832<< " -> Val, dbg.value override");18331834setLocKind(LiveSet, Var, LocKind::Val);1835emitDbgValue(LocKind::Val, DbgValue, DbgValue);1836};1837if (isa<DbgVariableRecord *>(DbgValueRecord))1838return ProcessDbgValueImpl(cast<DbgVariableRecord *>(DbgValueRecord));1839return ProcessDbgValueImpl(cast<DbgValueInst *>(DbgValueRecord));1840}18411842template <typename T> static bool hasZeroSizedFragment(T &DbgValue) {1843if (auto F = DbgValue.getExpression()->getFragmentInfo())1844return F->SizeInBits == 0;1845return false;1846}18471848void AssignmentTrackingLowering::processDbgInstruction(1849DbgInfoIntrinsic &I, AssignmentTrackingLowering::BlockInfo *LiveSet) {1850auto *DVI = dyn_cast<DbgVariableIntrinsic>(&I);1851if (!DVI)1852return;18531854// Ignore assignments to zero bits of the variable.1855if (hasZeroSizedFragment(*DVI))1856return;18571858if (auto *DAI = dyn_cast<DbgAssignIntrinsic>(&I))1859processDbgAssign(DAI, LiveSet);1860else if (auto *DVI = dyn_cast<DbgValueInst>(&I))1861processDbgValue(DVI, LiveSet);1862}1863void AssignmentTrackingLowering::processDbgVariableRecord(1864DbgVariableRecord &DVR, AssignmentTrackingLowering::BlockInfo *LiveSet) {1865// Ignore assignments to zero bits of the variable.1866if (hasZeroSizedFragment(DVR))1867return;18681869if (DVR.isDbgAssign())1870processDbgAssign(&DVR, LiveSet);1871else if (DVR.isDbgValue())1872processDbgValue(&DVR, LiveSet);1873}18741875void AssignmentTrackingLowering::resetInsertionPoint(Instruction &After) {1876assert(!After.isTerminator() && "Can't insert after a terminator");1877auto *R = InsertBeforeMap.find(getNextNode(&After));1878if (R == InsertBeforeMap.end())1879return;1880R->second.clear();1881}1882void AssignmentTrackingLowering::resetInsertionPoint(DbgVariableRecord &After) {1883auto *R = InsertBeforeMap.find(getNextNode(&After));1884if (R == InsertBeforeMap.end())1885return;1886R->second.clear();1887}18881889void AssignmentTrackingLowering::process(BasicBlock &BB, BlockInfo *LiveSet) {1890// If the block starts with DbgRecords, we need to process those DbgRecords as1891// their own frame without processing any instructions first.1892bool ProcessedLeadingDbgRecords = !BB.begin()->hasDbgRecords();1893for (auto II = BB.begin(), EI = BB.end(); II != EI;) {1894assert(VarsTouchedThisFrame.empty());1895// Process the instructions in "frames". A "frame" includes a single1896// non-debug instruction followed any debug instructions before the1897// next non-debug instruction.18981899// Skip the current instruction if it has unprocessed DbgRecords attached1900// (see comment above `ProcessedLeadingDbgRecords`).1901if (ProcessedLeadingDbgRecords) {1902// II is now either a debug intrinsic, a non-debug instruction with no1903// attached DbgRecords, or a non-debug instruction with attached processed1904// DbgRecords.1905// II has not been processed.1906if (!isa<DbgInfoIntrinsic>(&*II)) {1907if (II->isTerminator())1908break;1909resetInsertionPoint(*II);1910processNonDbgInstruction(*II, LiveSet);1911assert(LiveSet->isValid());1912++II;1913}1914}1915// II is now either a debug intrinsic, a non-debug instruction with no1916// attached DbgRecords, or a non-debug instruction with attached unprocessed1917// DbgRecords.1918if (II != EI && II->hasDbgRecords()) {1919// Skip over non-variable debug records (i.e., labels). They're going to1920// be read from IR (possibly re-ordering them within the debug record1921// range) rather than from the analysis results.1922for (DbgVariableRecord &DVR : filterDbgVars(II->getDbgRecordRange())) {1923resetInsertionPoint(DVR);1924processDbgVariableRecord(DVR, LiveSet);1925assert(LiveSet->isValid());1926}1927}1928ProcessedLeadingDbgRecords = true;1929while (II != EI) {1930auto *Dbg = dyn_cast<DbgInfoIntrinsic>(&*II);1931if (!Dbg)1932break;1933resetInsertionPoint(*II);1934processDbgInstruction(*Dbg, LiveSet);1935assert(LiveSet->isValid());1936++II;1937}1938// II is now a non-debug instruction either with no attached DbgRecords, or1939// with attached processed DbgRecords. II has not been processed, and all1940// debug instructions or DbgRecords in the frame preceding II have been1941// processed.19421943// We've processed everything in the "frame". Now determine which variables1944// cannot be represented by a dbg.declare.1945for (auto Var : VarsTouchedThisFrame) {1946LocKind Loc = getLocKind(LiveSet, Var);1947// If a variable's LocKind is anything other than LocKind::Mem then we1948// must note that it cannot be represented with a dbg.declare.1949// Note that this check is enough without having to check the result of1950// joins() because for join to produce anything other than Mem after1951// we've already seen a Mem we'd be joining None or Val with Mem. In that1952// case, we've already hit this codepath when we set the LocKind to Val1953// or None in that block.1954if (Loc != LocKind::Mem) {1955DebugVariable DbgVar = FnVarLocs->getVariable(Var);1956DebugAggregate Aggr{DbgVar.getVariable(), DbgVar.getInlinedAt()};1957NotAlwaysStackHomed.insert(Aggr);1958}1959}1960VarsTouchedThisFrame.clear();1961}1962}19631964AssignmentTrackingLowering::LocKind1965AssignmentTrackingLowering::joinKind(LocKind A, LocKind B) {1966// Partial order:1967// None > Mem, Val1968return A == B ? A : LocKind::None;1969}19701971AssignmentTrackingLowering::Assignment1972AssignmentTrackingLowering::joinAssignment(const Assignment &A,1973const Assignment &B) {1974// Partial order:1975// NoneOrPhi(null, null) > Known(v, ?s)19761977// If either are NoneOrPhi the join is NoneOrPhi.1978// If either value is different then the result is1979// NoneOrPhi (joining two values is a Phi).1980if (!A.isSameSourceAssignment(B))1981return Assignment::makeNoneOrPhi();1982if (A.Status == Assignment::NoneOrPhi)1983return Assignment::makeNoneOrPhi();19841985// Source is used to lookup the value + expression in the debug program if1986// the stack slot gets assigned a value earlier than expected. Because1987// we're only tracking the one dbg.assign, we can't capture debug PHIs.1988// It's unlikely that we're losing out on much coverage by avoiding that1989// extra work.1990// The Source may differ in this situation:1991// Pred.1:1992// dbg.assign i32 0, ..., !1, ...1993// Pred.2:1994// dbg.assign i32 1, ..., !1, ...1995// Here the same assignment (!1) was performed in both preds in the source,1996// but we can't use either one unless they are identical (e.g. .we don't1997// want to arbitrarily pick between constant values).1998auto JoinSource = [&]() -> AssignRecord {1999if (A.Source == B.Source)2000return A.Source;2001if (!A.Source || !B.Source)2002return AssignRecord();2003assert(isa<DbgVariableRecord *>(A.Source) ==2004isa<DbgVariableRecord *>(B.Source));2005if (isa<DbgVariableRecord *>(A.Source) &&2006cast<DbgVariableRecord *>(A.Source)->isEquivalentTo(2007*cast<DbgVariableRecord *>(B.Source)))2008return A.Source;2009if (isa<DbgAssignIntrinsic *>(A.Source) &&2010cast<DbgAssignIntrinsic *>(A.Source)->isIdenticalTo(2011cast<DbgAssignIntrinsic *>(B.Source)))2012return A.Source;2013return AssignRecord();2014};2015AssignRecord Source = JoinSource();2016assert(A.Status == B.Status && A.Status == Assignment::Known);2017assert(A.ID == B.ID);2018return Assignment::make(A.ID, Source);2019}20202021AssignmentTrackingLowering::BlockInfo2022AssignmentTrackingLowering::joinBlockInfo(const BlockInfo &A,2023const BlockInfo &B) {2024return BlockInfo::join(A, B, TrackedVariablesVectorSize);2025}20262027bool AssignmentTrackingLowering::join(2028const BasicBlock &BB, const SmallPtrSet<BasicBlock *, 16> &Visited) {20292030SmallVector<const BasicBlock *> VisitedPreds;2031// Ignore backedges if we have not visited the predecessor yet. As the2032// predecessor hasn't yet had locations propagated into it, most locations2033// will not yet be valid, so treat them as all being uninitialized and2034// potentially valid. If a location guessed to be correct here is2035// invalidated later, we will remove it when we revisit this block. This2036// is essentially the same as initialising all LocKinds and Assignments to2037// an implicit ⊥ value which is the identity value for the join operation.2038for (const BasicBlock *Pred : predecessors(&BB)) {2039if (Visited.count(Pred))2040VisitedPreds.push_back(Pred);2041}20422043// No preds visited yet.2044if (VisitedPreds.empty()) {2045auto It = LiveIn.try_emplace(&BB, BlockInfo());2046bool DidInsert = It.second;2047if (DidInsert)2048It.first->second.init(TrackedVariablesVectorSize);2049return /*Changed*/ DidInsert;2050}20512052// Exactly one visited pred. Copy the LiveOut from that pred into BB LiveIn.2053if (VisitedPreds.size() == 1) {2054const BlockInfo &PredLiveOut = LiveOut.find(VisitedPreds[0])->second;2055auto CurrentLiveInEntry = LiveIn.find(&BB);20562057// Check if there isn't an entry, or there is but the LiveIn set has2058// changed (expensive check).2059if (CurrentLiveInEntry == LiveIn.end())2060LiveIn.insert(std::make_pair(&BB, PredLiveOut));2061else if (PredLiveOut != CurrentLiveInEntry->second)2062CurrentLiveInEntry->second = PredLiveOut;2063else2064return /*Changed*/ false;2065return /*Changed*/ true;2066}20672068// More than one pred. Join LiveOuts of blocks 1 and 2.2069assert(VisitedPreds.size() > 1);2070const BlockInfo &PredLiveOut0 = LiveOut.find(VisitedPreds[0])->second;2071const BlockInfo &PredLiveOut1 = LiveOut.find(VisitedPreds[1])->second;2072BlockInfo BBLiveIn = joinBlockInfo(PredLiveOut0, PredLiveOut1);20732074// Join the LiveOuts of subsequent blocks.2075ArrayRef Tail = ArrayRef(VisitedPreds).drop_front(2);2076for (const BasicBlock *Pred : Tail) {2077const auto &PredLiveOut = LiveOut.find(Pred);2078assert(PredLiveOut != LiveOut.end() &&2079"block should have been processed already");2080BBLiveIn = joinBlockInfo(std::move(BBLiveIn), PredLiveOut->second);2081}20822083// Save the joined result for BB.2084auto CurrentLiveInEntry = LiveIn.find(&BB);2085// Check if there isn't an entry, or there is but the LiveIn set has changed2086// (expensive check).2087if (CurrentLiveInEntry == LiveIn.end())2088LiveIn.try_emplace(&BB, std::move(BBLiveIn));2089else if (BBLiveIn != CurrentLiveInEntry->second)2090CurrentLiveInEntry->second = std::move(BBLiveIn);2091else2092return /*Changed*/ false;2093return /*Changed*/ true;2094}20952096/// Return true if A fully contains B.2097static bool fullyContains(DIExpression::FragmentInfo A,2098DIExpression::FragmentInfo B) {2099auto ALeft = A.OffsetInBits;2100auto BLeft = B.OffsetInBits;2101if (BLeft < ALeft)2102return false;21032104auto ARight = ALeft + A.SizeInBits;2105auto BRight = BLeft + B.SizeInBits;2106if (BRight > ARight)2107return false;2108return true;2109}21102111static std::optional<at::AssignmentInfo>2112getUntaggedStoreAssignmentInfo(const Instruction &I, const DataLayout &Layout) {2113// Don't bother checking if this is an AllocaInst. We know this2114// instruction has no tag which means there are no variables associated2115// with it.2116if (const auto *SI = dyn_cast<StoreInst>(&I))2117return at::getAssignmentInfo(Layout, SI);2118if (const auto *MI = dyn_cast<MemIntrinsic>(&I))2119return at::getAssignmentInfo(Layout, MI);2120// Alloca or non-store-like inst.2121return std::nullopt;2122}21232124DbgDeclareInst *DynCastToDbgDeclare(DbgVariableIntrinsic *DVI) {2125return dyn_cast<DbgDeclareInst>(DVI);2126}21272128DbgVariableRecord *DynCastToDbgDeclare(DbgVariableRecord *DVR) {2129return DVR->isDbgDeclare() ? DVR : nullptr;2130}21312132/// Build a map of {Variable x: Variables y} where all variable fragments2133/// contained within the variable fragment x are in set y. This means that2134/// y does not contain all overlaps because partial overlaps are excluded.2135///2136/// While we're iterating over the function, add single location defs for2137/// dbg.declares to \p FnVarLocs.2138///2139/// Variables that are interesting to this pass in are added to2140/// FnVarLocs->Variables first. TrackedVariablesVectorSize is set to the ID of2141/// the last interesting variable plus 1, meaning variables with ID 12142/// (inclusive) to TrackedVariablesVectorSize (exclusive) are interesting. The2143/// subsequent variables are either stack homed or fully promoted.2144///2145/// Finally, populate UntaggedStoreVars with a mapping of untagged stores to2146/// the stored-to variable fragments.2147///2148/// These tasks are bundled together to reduce the number of times we need2149/// to iterate over the function as they can be achieved together in one pass.2150static AssignmentTrackingLowering::OverlapMap buildOverlapMapAndRecordDeclares(2151Function &Fn, FunctionVarLocsBuilder *FnVarLocs,2152const DenseSet<DebugAggregate> &VarsWithStackSlot,2153AssignmentTrackingLowering::UntaggedStoreAssignmentMap &UntaggedStoreVars,2154unsigned &TrackedVariablesVectorSize) {2155DenseSet<DebugVariable> Seen;2156// Map of Variable: [Fragments].2157DenseMap<DebugAggregate, SmallVector<DebugVariable, 8>> FragmentMap;2158// Iterate over all instructions:2159// - dbg.declare -> add single location variable record2160// - dbg.* -> Add fragments to FragmentMap2161// - untagged store -> Add fragments to FragmentMap and update2162// UntaggedStoreVars.2163// We need to add fragments for untagged stores too so that we can correctly2164// clobber overlapped fragment locations later.2165SmallVector<DbgDeclareInst *> InstDeclares;2166SmallVector<DbgVariableRecord *> DPDeclares;2167auto ProcessDbgRecord = [&](auto *Record, auto &DeclareList) {2168if (auto *Declare = DynCastToDbgDeclare(Record)) {2169DeclareList.push_back(Declare);2170return;2171}2172DebugVariable DV = DebugVariable(Record);2173DebugAggregate DA = {DV.getVariable(), DV.getInlinedAt()};2174if (!VarsWithStackSlot.contains(DA))2175return;2176if (Seen.insert(DV).second)2177FragmentMap[DA].push_back(DV);2178};2179for (auto &BB : Fn) {2180for (auto &I : BB) {2181for (DbgVariableRecord &DVR : filterDbgVars(I.getDbgRecordRange()))2182ProcessDbgRecord(&DVR, DPDeclares);2183if (auto *DII = dyn_cast<DbgVariableIntrinsic>(&I)) {2184ProcessDbgRecord(DII, InstDeclares);2185} else if (auto Info = getUntaggedStoreAssignmentInfo(2186I, Fn.getDataLayout())) {2187// Find markers linked to this alloca.2188auto HandleDbgAssignForStore = [&](auto *Assign) {2189std::optional<DIExpression::FragmentInfo> FragInfo;21902191// Skip this assignment if the affected bits are outside of the2192// variable fragment.2193if (!at::calculateFragmentIntersect(2194I.getDataLayout(), Info->Base,2195Info->OffsetInBits, Info->SizeInBits, Assign, FragInfo) ||2196(FragInfo && FragInfo->SizeInBits == 0))2197return;21982199// FragInfo from calculateFragmentIntersect is nullopt if the2200// resultant fragment matches DAI's fragment or entire variable - in2201// which case copy the fragment info from DAI. If FragInfo is still2202// nullopt after the copy it means "no fragment info" instead, which2203// is how it is usually interpreted.2204if (!FragInfo)2205FragInfo = Assign->getExpression()->getFragmentInfo();22062207DebugVariable DV =2208DebugVariable(Assign->getVariable(), FragInfo,2209Assign->getDebugLoc().getInlinedAt());2210DebugAggregate DA = {DV.getVariable(), DV.getInlinedAt()};2211if (!VarsWithStackSlot.contains(DA))2212return;22132214// Cache this info for later.2215UntaggedStoreVars[&I].push_back(2216{FnVarLocs->insertVariable(DV), *Info});22172218if (Seen.insert(DV).second)2219FragmentMap[DA].push_back(DV);2220};2221for (DbgAssignIntrinsic *DAI : at::getAssignmentMarkers(Info->Base))2222HandleDbgAssignForStore(DAI);2223for (DbgVariableRecord *DVR : at::getDVRAssignmentMarkers(Info->Base))2224HandleDbgAssignForStore(DVR);2225}2226}2227}22282229// Sort the fragment map for each DebugAggregate in ascending2230// order of fragment size - there should be no duplicates.2231for (auto &Pair : FragmentMap) {2232SmallVector<DebugVariable, 8> &Frags = Pair.second;2233std::sort(Frags.begin(), Frags.end(),2234[](const DebugVariable &Next, const DebugVariable &Elmt) {2235return Elmt.getFragmentOrDefault().SizeInBits >2236Next.getFragmentOrDefault().SizeInBits;2237});2238// Check for duplicates.2239assert(std::adjacent_find(Frags.begin(), Frags.end()) == Frags.end());2240}22412242// Build the map.2243AssignmentTrackingLowering::OverlapMap Map;2244for (auto &Pair : FragmentMap) {2245auto &Frags = Pair.second;2246for (auto It = Frags.begin(), IEnd = Frags.end(); It != IEnd; ++It) {2247DIExpression::FragmentInfo Frag = It->getFragmentOrDefault();2248// Find the frags that this is contained within.2249//2250// Because Frags is sorted by size and none have the same offset and2251// size, we know that this frag can only be contained by subsequent2252// elements.2253SmallVector<DebugVariable, 8>::iterator OtherIt = It;2254++OtherIt;2255VariableID ThisVar = FnVarLocs->insertVariable(*It);2256for (; OtherIt != IEnd; ++OtherIt) {2257DIExpression::FragmentInfo OtherFrag = OtherIt->getFragmentOrDefault();2258VariableID OtherVar = FnVarLocs->insertVariable(*OtherIt);2259if (fullyContains(OtherFrag, Frag))2260Map[OtherVar].push_back(ThisVar);2261}2262}2263}22642265// VariableIDs are 1-based so the variable-tracking bitvector needs2266// NumVariables plus 1 bits.2267TrackedVariablesVectorSize = FnVarLocs->getNumVariables() + 1;22682269// Finally, insert the declares afterwards, so the first IDs are all2270// partially stack homed vars.2271for (auto *DDI : InstDeclares)2272FnVarLocs->addSingleLocVar(DebugVariable(DDI), DDI->getExpression(),2273DDI->getDebugLoc(), DDI->getWrappedLocation());2274for (auto *DVR : DPDeclares)2275FnVarLocs->addSingleLocVar(DebugVariable(DVR), DVR->getExpression(),2276DVR->getDebugLoc(),2277RawLocationWrapper(DVR->getRawLocation()));2278return Map;2279}22802281bool AssignmentTrackingLowering::run(FunctionVarLocsBuilder *FnVarLocsBuilder) {2282if (Fn.size() > MaxNumBlocks) {2283LLVM_DEBUG(dbgs() << "[AT] Dropping var locs in: " << Fn.getName()2284<< ": too many blocks (" << Fn.size() << ")\n");2285at::deleteAll(&Fn);2286return false;2287}22882289FnVarLocs = FnVarLocsBuilder;22902291// The general structure here is inspired by VarLocBasedImpl.cpp2292// (LiveDebugValues).22932294// Build the variable fragment overlap map.2295// Note that this pass doesn't handle partial overlaps correctly (FWIW2296// neither does LiveDebugVariables) because that is difficult to do and2297// appears to be rare occurance.2298VarContains = buildOverlapMapAndRecordDeclares(2299Fn, FnVarLocs, *VarsWithStackSlot, UntaggedStoreVars,2300TrackedVariablesVectorSize);23012302// Prepare for traversal.2303ReversePostOrderTraversal<Function *> RPOT(&Fn);2304std::priority_queue<unsigned int, std::vector<unsigned int>,2305std::greater<unsigned int>>2306Worklist;2307std::priority_queue<unsigned int, std::vector<unsigned int>,2308std::greater<unsigned int>>2309Pending;2310DenseMap<unsigned int, BasicBlock *> OrderToBB;2311DenseMap<BasicBlock *, unsigned int> BBToOrder;2312{ // Init OrderToBB and BBToOrder.2313unsigned int RPONumber = 0;2314for (BasicBlock *BB : RPOT) {2315OrderToBB[RPONumber] = BB;2316BBToOrder[BB] = RPONumber;2317Worklist.push(RPONumber);2318++RPONumber;2319}2320LiveIn.init(RPONumber);2321LiveOut.init(RPONumber);2322}23232324// Perform the traversal.2325//2326// This is a standard "union of predecessor outs" dataflow problem. To solve2327// it, we perform join() and process() using the two worklist method until2328// the LiveIn data for each block becomes unchanging. The "proof" that this2329// terminates can be put together by looking at the comments around LocKind,2330// Assignment, and the various join methods, which show that all the elements2331// involved are made up of join-semilattices; LiveIn(n) can only2332// monotonically increase in value throughout the dataflow.2333//2334SmallPtrSet<BasicBlock *, 16> Visited;2335while (!Worklist.empty()) {2336// We track what is on the pending worklist to avoid inserting the same2337// thing twice.2338SmallPtrSet<BasicBlock *, 16> OnPending;2339LLVM_DEBUG(dbgs() << "Processing Worklist\n");2340while (!Worklist.empty()) {2341BasicBlock *BB = OrderToBB[Worklist.top()];2342LLVM_DEBUG(dbgs() << "\nPop BB " << BB->getName() << "\n");2343Worklist.pop();2344bool InChanged = join(*BB, Visited);2345// Always consider LiveIn changed on the first visit.2346InChanged |= Visited.insert(BB).second;2347if (InChanged) {2348LLVM_DEBUG(dbgs() << BB->getName() << " has new InLocs, process it\n");2349// Mutate a copy of LiveIn while processing BB. After calling process2350// LiveSet is the LiveOut set for BB.2351BlockInfo LiveSet = LiveIn[BB];23522353// Process the instructions in the block.2354process(*BB, &LiveSet);23552356// Relatively expensive check: has anything changed in LiveOut for BB?2357if (LiveOut[BB] != LiveSet) {2358LLVM_DEBUG(dbgs() << BB->getName()2359<< " has new OutLocs, add succs to worklist: [ ");2360LiveOut[BB] = std::move(LiveSet);2361for (BasicBlock *Succ : successors(BB)) {2362if (OnPending.insert(Succ).second) {2363LLVM_DEBUG(dbgs() << Succ->getName() << " ");2364Pending.push(BBToOrder[Succ]);2365}2366}2367LLVM_DEBUG(dbgs() << "]\n");2368}2369}2370}2371Worklist.swap(Pending);2372// At this point, pending must be empty, since it was just the empty2373// worklist2374assert(Pending.empty() && "Pending should be empty");2375}23762377// That's the hard part over. Now we just have some admin to do.23782379// Record whether we inserted any intrinsics.2380bool InsertedAnyIntrinsics = false;23812382// Identify and add defs for single location variables.2383//2384// Go through all of the defs that we plan to add. If the aggregate variable2385// it's a part of is not in the NotAlwaysStackHomed set we can emit a single2386// location def and omit the rest. Add an entry to AlwaysStackHomed so that2387// we can identify those uneeded defs later.2388DenseSet<DebugAggregate> AlwaysStackHomed;2389for (const auto &Pair : InsertBeforeMap) {2390auto &Vec = Pair.second;2391for (VarLocInfo VarLoc : Vec) {2392DebugVariable Var = FnVarLocs->getVariable(VarLoc.VariableID);2393DebugAggregate Aggr{Var.getVariable(), Var.getInlinedAt()};23942395// Skip this Var if it's not always stack homed.2396if (NotAlwaysStackHomed.contains(Aggr))2397continue;23982399// Skip complex cases such as when different fragments of a variable have2400// been split into different allocas. Skipping in this case means falling2401// back to using a list of defs (which could reduce coverage, but is no2402// less correct).2403bool Simple =2404VarLoc.Expr->getNumElements() == 1 && VarLoc.Expr->startsWithDeref();2405if (!Simple) {2406NotAlwaysStackHomed.insert(Aggr);2407continue;2408}24092410// All source assignments to this variable remain and all stores to any2411// part of the variable store to the same address (with varying2412// offsets). We can just emit a single location for the whole variable.2413//2414// Unless we've already done so, create the single location def now.2415if (AlwaysStackHomed.insert(Aggr).second) {2416assert(!VarLoc.Values.hasArgList());2417// TODO: When more complex cases are handled VarLoc.Expr should be2418// built appropriately rather than always using an empty DIExpression.2419// The assert below is a reminder.2420assert(Simple);2421VarLoc.Expr = DIExpression::get(Fn.getContext(), std::nullopt);2422DebugVariable Var = FnVarLocs->getVariable(VarLoc.VariableID);2423FnVarLocs->addSingleLocVar(Var, VarLoc.Expr, VarLoc.DL, VarLoc.Values);2424InsertedAnyIntrinsics = true;2425}2426}2427}24282429// Insert the other DEFs.2430for (const auto &[InsertBefore, Vec] : InsertBeforeMap) {2431SmallVector<VarLocInfo> NewDefs;2432for (const VarLocInfo &VarLoc : Vec) {2433DebugVariable Var = FnVarLocs->getVariable(VarLoc.VariableID);2434DebugAggregate Aggr{Var.getVariable(), Var.getInlinedAt()};2435// If this variable is always stack homed then we have already inserted a2436// dbg.declare and deleted this dbg.value.2437if (AlwaysStackHomed.contains(Aggr))2438continue;2439NewDefs.push_back(VarLoc);2440InsertedAnyIntrinsics = true;2441}24422443FnVarLocs->setWedge(InsertBefore, std::move(NewDefs));2444}24452446InsertedAnyIntrinsics |= emitPromotedVarLocs(FnVarLocs);24472448return InsertedAnyIntrinsics;2449}24502451bool AssignmentTrackingLowering::emitPromotedVarLocs(2452FunctionVarLocsBuilder *FnVarLocs) {2453bool InsertedAnyIntrinsics = false;2454// Go through every block, translating debug intrinsics for fully promoted2455// variables into FnVarLocs location defs. No analysis required for these.2456auto TranslateDbgRecord = [&](auto *Record) {2457// Skip variables that haven't been promoted - we've dealt with those2458// already.2459if (VarsWithStackSlot->contains(getAggregate(Record)))2460return;2461auto InsertBefore = getNextNode(Record);2462assert(InsertBefore && "Unexpected: debug intrinsics after a terminator");2463FnVarLocs->addVarLoc(InsertBefore, DebugVariable(Record),2464Record->getExpression(), Record->getDebugLoc(),2465RawLocationWrapper(Record->getRawLocation()));2466InsertedAnyIntrinsics = true;2467};2468for (auto &BB : Fn) {2469for (auto &I : BB) {2470// Skip instructions other than dbg.values and dbg.assigns.2471for (DbgVariableRecord &DVR : filterDbgVars(I.getDbgRecordRange()))2472if (DVR.isDbgValue() || DVR.isDbgAssign())2473TranslateDbgRecord(&DVR);2474auto *DVI = dyn_cast<DbgValueInst>(&I);2475if (DVI)2476TranslateDbgRecord(DVI);2477}2478}2479return InsertedAnyIntrinsics;2480}24812482/// Remove redundant definitions within sequences of consecutive location defs.2483/// This is done using a backward scan to keep the last def describing a2484/// specific variable/fragment.2485///2486/// This implements removeRedundantDbgInstrsUsingBackwardScan from2487/// lib/Transforms/Utils/BasicBlockUtils.cpp for locations described with2488/// FunctionVarLocsBuilder instead of with intrinsics.2489static bool2490removeRedundantDbgLocsUsingBackwardScan(const BasicBlock *BB,2491FunctionVarLocsBuilder &FnVarLocs) {2492bool Changed = false;2493SmallDenseMap<DebugAggregate, BitVector> VariableDefinedBytes;2494// Scan over the entire block, not just over the instructions mapped by2495// FnVarLocs, because wedges in FnVarLocs may only be separated by debug2496// instructions.2497for (const Instruction &I : reverse(*BB)) {2498if (!isa<DbgVariableIntrinsic>(I)) {2499// Sequence of consecutive defs ended. Clear map for the next one.2500VariableDefinedBytes.clear();2501}25022503auto HandleLocsForWedge = [&](auto *WedgePosition) {2504// Get the location defs that start just before this instruction.2505const auto *Locs = FnVarLocs.getWedge(WedgePosition);2506if (!Locs)2507return;25082509NumWedgesScanned++;2510bool ChangedThisWedge = false;2511// The new pruned set of defs, reversed because we're scanning backwards.2512SmallVector<VarLocInfo> NewDefsReversed;25132514// Iterate over the existing defs in reverse.2515for (auto RIt = Locs->rbegin(), REnd = Locs->rend(); RIt != REnd; ++RIt) {2516NumDefsScanned++;2517DebugAggregate Aggr =2518getAggregate(FnVarLocs.getVariable(RIt->VariableID));2519uint64_t SizeInBits = Aggr.first->getSizeInBits().value_or(0);2520uint64_t SizeInBytes = divideCeil(SizeInBits, 8);25212522// Cutoff for large variables to prevent expensive bitvector operations.2523const uint64_t MaxSizeBytes = 2048;25242525if (SizeInBytes == 0 || SizeInBytes > MaxSizeBytes) {2526// If the size is unknown (0) then keep this location def to be safe.2527// Do the same for defs of large variables, which would be expensive2528// to represent with a BitVector.2529NewDefsReversed.push_back(*RIt);2530continue;2531}25322533// Only keep this location definition if it is not fully eclipsed by2534// other definitions in this wedge that come after it25352536// Inert the bytes the location definition defines.2537auto InsertResult =2538VariableDefinedBytes.try_emplace(Aggr, BitVector(SizeInBytes));2539bool FirstDefinition = InsertResult.second;2540BitVector &DefinedBytes = InsertResult.first->second;25412542DIExpression::FragmentInfo Fragment =2543RIt->Expr->getFragmentInfo().value_or(2544DIExpression::FragmentInfo(SizeInBits, 0));2545bool InvalidFragment = Fragment.endInBits() > SizeInBits;2546uint64_t StartInBytes = Fragment.startInBits() / 8;2547uint64_t EndInBytes = divideCeil(Fragment.endInBits(), 8);25482549// If this defines any previously undefined bytes, keep it.2550if (FirstDefinition || InvalidFragment ||2551DefinedBytes.find_first_unset_in(StartInBytes, EndInBytes) != -1) {2552if (!InvalidFragment)2553DefinedBytes.set(StartInBytes, EndInBytes);2554NewDefsReversed.push_back(*RIt);2555continue;2556}25572558// Redundant def found: throw it away. Since the wedge of defs is being2559// rebuilt, doing nothing is the same as deleting an entry.2560ChangedThisWedge = true;2561NumDefsRemoved++;2562}25632564// Un-reverse the defs and replace the wedge with the pruned version.2565if (ChangedThisWedge) {2566std::reverse(NewDefsReversed.begin(), NewDefsReversed.end());2567FnVarLocs.setWedge(WedgePosition, std::move(NewDefsReversed));2568NumWedgesChanged++;2569Changed = true;2570}2571};2572HandleLocsForWedge(&I);2573for (DbgVariableRecord &DVR : reverse(filterDbgVars(I.getDbgRecordRange())))2574HandleLocsForWedge(&DVR);2575}25762577return Changed;2578}25792580/// Remove redundant location defs using a forward scan. This can remove a2581/// location definition that is redundant due to indicating that a variable has2582/// the same value as is already being indicated by an earlier def.2583///2584/// This implements removeRedundantDbgInstrsUsingForwardScan from2585/// lib/Transforms/Utils/BasicBlockUtils.cpp for locations described with2586/// FunctionVarLocsBuilder instead of with intrinsics2587static bool2588removeRedundantDbgLocsUsingForwardScan(const BasicBlock *BB,2589FunctionVarLocsBuilder &FnVarLocs) {2590bool Changed = false;2591DenseMap<DebugVariable, std::pair<RawLocationWrapper, DIExpression *>>2592VariableMap;25932594// Scan over the entire block, not just over the instructions mapped by2595// FnVarLocs, because wedges in FnVarLocs may only be separated by debug2596// instructions.2597for (const Instruction &I : *BB) {2598// Get the defs that come just before this instruction.2599auto HandleLocsForWedge = [&](auto *WedgePosition) {2600const auto *Locs = FnVarLocs.getWedge(WedgePosition);2601if (!Locs)2602return;26032604NumWedgesScanned++;2605bool ChangedThisWedge = false;2606// The new pruned set of defs.2607SmallVector<VarLocInfo> NewDefs;26082609// Iterate over the existing defs.2610for (const VarLocInfo &Loc : *Locs) {2611NumDefsScanned++;2612DebugVariable Key(FnVarLocs.getVariable(Loc.VariableID).getVariable(),2613std::nullopt, Loc.DL.getInlinedAt());2614auto VMI = VariableMap.find(Key);26152616// Update the map if we found a new value/expression describing the2617// variable, or if the variable wasn't mapped already.2618if (VMI == VariableMap.end() || VMI->second.first != Loc.Values ||2619VMI->second.second != Loc.Expr) {2620VariableMap[Key] = {Loc.Values, Loc.Expr};2621NewDefs.push_back(Loc);2622continue;2623}26242625// Did not insert this Loc, which is the same as removing it.2626ChangedThisWedge = true;2627NumDefsRemoved++;2628}26292630// Replace the existing wedge with the pruned version.2631if (ChangedThisWedge) {2632FnVarLocs.setWedge(WedgePosition, std::move(NewDefs));2633NumWedgesChanged++;2634Changed = true;2635}2636};26372638for (DbgVariableRecord &DVR : filterDbgVars(I.getDbgRecordRange()))2639HandleLocsForWedge(&DVR);2640HandleLocsForWedge(&I);2641}26422643return Changed;2644}26452646static bool2647removeUndefDbgLocsFromEntryBlock(const BasicBlock *BB,2648FunctionVarLocsBuilder &FnVarLocs) {2649assert(BB->isEntryBlock());2650// Do extra work to ensure that we remove semantically unimportant undefs.2651//2652// This is to work around the fact that SelectionDAG will hoist dbg.values2653// using argument values to the top of the entry block. That can move arg2654// dbg.values before undef and constant dbg.values which they previously2655// followed. The easiest thing to do is to just try to feed SelectionDAG2656// input it's happy with.2657//2658// Map of {Variable x: Fragments y} where the fragments y of variable x have2659// have at least one non-undef location defined already. Don't use directly,2660// instead call DefineBits and HasDefinedBits.2661SmallDenseMap<DebugAggregate, SmallDenseSet<DIExpression::FragmentInfo>>2662VarsWithDef;2663// Specify that V (a fragment of A) has a non-undef location.2664auto DefineBits = [&VarsWithDef](DebugAggregate A, DebugVariable V) {2665VarsWithDef[A].insert(V.getFragmentOrDefault());2666};2667// Return true if a non-undef location has been defined for V (a fragment of2668// A). Doesn't imply that the location is currently non-undef, just that a2669// non-undef location has been seen previously.2670auto HasDefinedBits = [&VarsWithDef](DebugAggregate A, DebugVariable V) {2671auto FragsIt = VarsWithDef.find(A);2672if (FragsIt == VarsWithDef.end())2673return false;2674return llvm::any_of(FragsIt->second, [V](auto Frag) {2675return DIExpression::fragmentsOverlap(Frag, V.getFragmentOrDefault());2676});2677};26782679bool Changed = false;2680DenseMap<DebugVariable, std::pair<Value *, DIExpression *>> VariableMap;26812682// Scan over the entire block, not just over the instructions mapped by2683// FnVarLocs, because wedges in FnVarLocs may only be separated by debug2684// instructions.2685for (const Instruction &I : *BB) {2686// Get the defs that come just before this instruction.2687auto HandleLocsForWedge = [&](auto *WedgePosition) {2688const auto *Locs = FnVarLocs.getWedge(WedgePosition);2689if (!Locs)2690return;26912692NumWedgesScanned++;2693bool ChangedThisWedge = false;2694// The new pruned set of defs.2695SmallVector<VarLocInfo> NewDefs;26962697// Iterate over the existing defs.2698for (const VarLocInfo &Loc : *Locs) {2699NumDefsScanned++;2700DebugAggregate Aggr{FnVarLocs.getVariable(Loc.VariableID).getVariable(),2701Loc.DL.getInlinedAt()};2702DebugVariable Var = FnVarLocs.getVariable(Loc.VariableID);27032704// Remove undef entries that are encountered before any non-undef2705// intrinsics from the entry block.2706if (Loc.Values.isKillLocation(Loc.Expr) && !HasDefinedBits(Aggr, Var)) {2707// Did not insert this Loc, which is the same as removing it.2708NumDefsRemoved++;2709ChangedThisWedge = true;2710continue;2711}27122713DefineBits(Aggr, Var);2714NewDefs.push_back(Loc);2715}27162717// Replace the existing wedge with the pruned version.2718if (ChangedThisWedge) {2719FnVarLocs.setWedge(WedgePosition, std::move(NewDefs));2720NumWedgesChanged++;2721Changed = true;2722}2723};2724for (DbgVariableRecord &DVR : filterDbgVars(I.getDbgRecordRange()))2725HandleLocsForWedge(&DVR);2726HandleLocsForWedge(&I);2727}27282729return Changed;2730}27312732static bool removeRedundantDbgLocs(const BasicBlock *BB,2733FunctionVarLocsBuilder &FnVarLocs) {2734bool MadeChanges = false;2735MadeChanges |= removeRedundantDbgLocsUsingBackwardScan(BB, FnVarLocs);2736if (BB->isEntryBlock())2737MadeChanges |= removeUndefDbgLocsFromEntryBlock(BB, FnVarLocs);2738MadeChanges |= removeRedundantDbgLocsUsingForwardScan(BB, FnVarLocs);27392740if (MadeChanges)2741LLVM_DEBUG(dbgs() << "Removed redundant dbg locs from: " << BB->getName()2742<< "\n");2743return MadeChanges;2744}27452746static DenseSet<DebugAggregate> findVarsWithStackSlot(Function &Fn) {2747DenseSet<DebugAggregate> Result;2748for (auto &BB : Fn) {2749for (auto &I : BB) {2750// Any variable linked to an instruction is considered2751// interesting. Ideally we only need to check Allocas, however, a2752// DIAssignID might get dropped from an alloca but not stores. In that2753// case, we need to consider the variable interesting for NFC behaviour2754// with this change. TODO: Consider only looking at allocas.2755for (DbgAssignIntrinsic *DAI : at::getAssignmentMarkers(&I)) {2756Result.insert({DAI->getVariable(), DAI->getDebugLoc().getInlinedAt()});2757}2758for (DbgVariableRecord *DVR : at::getDVRAssignmentMarkers(&I)) {2759Result.insert({DVR->getVariable(), DVR->getDebugLoc().getInlinedAt()});2760}2761}2762}2763return Result;2764}27652766static void analyzeFunction(Function &Fn, const DataLayout &Layout,2767FunctionVarLocsBuilder *FnVarLocs) {2768// The analysis will generate location definitions for all variables, but we2769// only need to perform a dataflow on the set of variables which have a stack2770// slot. Find those now.2771DenseSet<DebugAggregate> VarsWithStackSlot = findVarsWithStackSlot(Fn);27722773bool Changed = false;27742775// Use a scope block to clean up AssignmentTrackingLowering before running2776// MemLocFragmentFill to reduce peak memory consumption.2777{2778AssignmentTrackingLowering Pass(Fn, Layout, &VarsWithStackSlot);2779Changed = Pass.run(FnVarLocs);2780}27812782if (Changed) {2783MemLocFragmentFill Pass(Fn, &VarsWithStackSlot,2784shouldCoalesceFragments(Fn));2785Pass.run(FnVarLocs);27862787// Remove redundant entries. As well as reducing memory consumption and2788// avoiding waiting cycles later by burning some now, this has another2789// important job. That is to work around some SelectionDAG quirks. See2790// removeRedundantDbgLocsUsingForwardScan comments for more info on that.2791for (auto &BB : Fn)2792removeRedundantDbgLocs(&BB, *FnVarLocs);2793}2794}27952796FunctionVarLocs2797DebugAssignmentTrackingAnalysis::run(Function &F,2798FunctionAnalysisManager &FAM) {2799if (!isAssignmentTrackingEnabled(*F.getParent()))2800return FunctionVarLocs();28012802auto &DL = F.getDataLayout();28032804FunctionVarLocsBuilder Builder;2805analyzeFunction(F, DL, &Builder);28062807// Save these results.2808FunctionVarLocs Results;2809Results.init(Builder);2810return Results;2811}28122813AnalysisKey DebugAssignmentTrackingAnalysis::Key;28142815PreservedAnalyses2816DebugAssignmentTrackingPrinterPass::run(Function &F,2817FunctionAnalysisManager &FAM) {2818FAM.getResult<DebugAssignmentTrackingAnalysis>(F).print(OS, F);2819return PreservedAnalyses::all();2820}28212822bool AssignmentTrackingAnalysis::runOnFunction(Function &F) {2823if (!isAssignmentTrackingEnabled(*F.getParent()))2824return false;28252826LLVM_DEBUG(dbgs() << "AssignmentTrackingAnalysis run on " << F.getName()2827<< "\n");2828auto DL = std::make_unique<DataLayout>(F.getParent());28292830// Clear previous results.2831Results->clear();28322833FunctionVarLocsBuilder Builder;2834analyzeFunction(F, *DL.get(), &Builder);28352836// Save these results.2837Results->init(Builder);28382839if (PrintResults && isFunctionInPrintList(F.getName()))2840Results->print(errs(), F);28412842// Return false because this pass does not modify the function.2843return false;2844}28452846AssignmentTrackingAnalysis::AssignmentTrackingAnalysis()2847: FunctionPass(ID), Results(std::make_unique<FunctionVarLocs>()) {}28482849char AssignmentTrackingAnalysis::ID = 0;28502851INITIALIZE_PASS(AssignmentTrackingAnalysis, DEBUG_TYPE,2852"Assignment Tracking Analysis", false, true)285328542855