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