Index: llvm/lib/CodeGen/LiveDebugVariables.cpp =================================================================== --- llvm/lib/CodeGen/LiveDebugVariables.cpp +++ llvm/lib/CodeGen/LiveDebugVariables.cpp @@ -96,12 +96,12 @@ enum : unsigned { UndefLocNo = ~0U }; /// Describes a location by number along with some flags about the original -/// usage of the location. +/// usage of the location. A DIExpression is used to help classify the +/// location usage. class DbgValueLocation { public: - DbgValueLocation(unsigned LocNo, bool WasIndirect) - : LocNo(LocNo), WasIndirect(WasIndirect) { - static_assert(sizeof(*this) == sizeof(unsigned), "bad bitfield packing"); + DbgValueLocation(unsigned LocNo, bool WasIndirect, const DIExpression &Expr) + : LocNo(LocNo), WasIndirect(WasIndirect), Expression(&Expr) { assert(locNo() == LocNo && "location truncation"); } @@ -113,14 +113,16 @@ } bool wasIndirect() const { return WasIndirect; } bool isUndef() const { return locNo() == UndefLocNo; } + const DIExpression *expression() const { return Expression; } DbgValueLocation changeLocNo(unsigned NewLocNo) const { - return DbgValueLocation(NewLocNo, WasIndirect); + return DbgValueLocation(NewLocNo, WasIndirect, *Expression); } friend inline bool operator==(const DbgValueLocation &LHS, const DbgValueLocation &RHS) { - return LHS.LocNo == RHS.LocNo && LHS.WasIndirect == RHS.WasIndirect; + return LHS.LocNo == RHS.LocNo && LHS.WasIndirect == RHS.WasIndirect && + LHS.Expression == RHS.Expression; } friend inline bool operator!=(const DbgValueLocation &LHS, @@ -129,12 +131,13 @@ } private: + const DIExpression *Expression = nullptr; unsigned LocNo : 31; unsigned WasIndirect : 1; }; /// Map of where a user value is live, and its location. -using LocMap = IntervalMap; +using LocMap = IntervalMap; /// Map of stack slot offsets for spilled locations. /// Non-spilled locations are not added to the map. @@ -155,7 +158,8 @@ /// closure of that relation. class UserValue { const DILocalVariable *Variable; ///< The debug info variable we are part of. - const DIExpression *Expression; ///< Any complex address expression. + /// Fragment of the source variable. + const Optional FragInfo; DebugLoc dl; ///< The debug location for the variable. This is ///< used by dwarf writer to find lexical scope. UserValue *leader; ///< Equivalence class leader. @@ -167,7 +171,7 @@ /// Map of slot indices where this value is live. LocMap locInts; - /// Insert a DBG_VALUE into MBB at Idx for LocNo. + /// Insert a DBG_VALUE into MBB at Idx for Loc.locNo(). void insertDebugValue(MachineBasicBlock *MBB, SlotIndex StartIdx, SlotIndex StopIdx, DbgValueLocation Loc, bool Spilled, unsigned SpillOffset, LiveIntervals &LIS, @@ -181,9 +185,10 @@ public: /// Create a new UserValue. - UserValue(const DILocalVariable *var, const DIExpression *expr, DebugLoc L, + UserValue(const DILocalVariable *var, + Optional frag, DebugLoc L, LocMap::Allocator &alloc) - : Variable(var), Expression(expr), dl(std::move(L)), leader(this), + : Variable(var), FragInfo(frag), dl(std::move(L)), leader(this), locInts(alloc) {} /// Get the leader of this value's equivalence class. @@ -198,11 +203,10 @@ UserValue *getNext() const { return next; } /// Does this UserValue match the parameters? - bool match(const DILocalVariable *Var, const DIExpression *Expr, + bool match(const DILocalVariable *Var, + Optional Frag, const DILocation *IA) const { - // FIXME: The fragment should be part of the equivalence class, but not - // other things in the expression like stack values. - return Var == Variable && Expr == Expression && dl->getInlinedAt() == IA; + return Var == Variable && Frag == FragInfo && dl->getInlinedAt() == IA; } /// Merge equivalence classes. @@ -261,8 +265,10 @@ void mapVirtRegs(LDVImpl *LDV); /// Add a definition point to this value. - void addDef(SlotIndex Idx, const MachineOperand &LocMO, bool IsIndirect) { - DbgValueLocation Loc(getLocationNo(LocMO), IsIndirect); + void addDef(SlotIndex Idx, const MachineOperand &LocMO, bool IsIndirect, + const DIExpression &Expr) { + DbgValueLocation Loc(getLocationNo(LocMO), IsIndirect, Expr); + // Add a singular (Idx,Idx) -> Loc mapping. LocMap::iterator I = locInts.find(Idx); if (!I.valid() || I.start() != Idx) @@ -296,12 +302,11 @@ /// possible. /// /// \param LI Scan for copies of the value in LI->reg. - /// \param LocNo Location number of LI->reg. - /// \param WasIndirect Indicates if the original use of LI->reg was indirect + /// \param Loc LI->reg location and usage debug info. /// \param Kills Points where the range of LocNo could be extended. /// \param [in,out] NewDefs Append (Idx, LocNo) of inserted defs here. void addDefsFromCopies( - LiveInterval *LI, unsigned LocNo, bool WasIndirect, + LiveInterval *LI, DbgValueLocation Loc, const SmallVectorImpl &Kills, SmallVectorImpl> &NewDefs, MachineRegisterInfo &MRI, LiveIntervals &LIS); @@ -396,7 +401,7 @@ UVMap userVarMap; /// Find or create a UserValue. - UserValue *getUserValue(const DILocalVariable *Var, const DIExpression *Expr, + UserValue *getUserValue(const DILocalVariable *Var, Optional Frag, const DebugLoc &DL); /// Find the EC leader for VirtReg or null. @@ -559,18 +564,17 @@ } UserValue *LDVImpl::getUserValue(const DILocalVariable *Var, - const DIExpression *Expr, const DebugLoc &DL) { + Optional Frag, const DebugLoc &DL) { UserValue *&Leader = userVarMap[Var]; if (Leader) { UserValue *UV = Leader->getLeader(); Leader = UV; for (; UV; UV = UV->getNext()) - if (UV->match(Var, Expr, DL->getInlinedAt())) + if (UV->match(Var, Frag, DL->getInlinedAt())) return UV; } - userValues.push_back( - std::make_unique(Var, Expr, DL, allocator)); + userValues.push_back(std::make_unique(Var, Frag, DL, allocator)); UserValue *UV = userValues.back().get(); Leader = UserValue::merge(Leader, UV); return UV; @@ -637,13 +641,13 @@ const DILocalVariable *Var = MI.getDebugVariable(); const DIExpression *Expr = MI.getDebugExpression(); UserValue *UV = - getUserValue(Var, Expr, MI.getDebugLoc()); + getUserValue(Var, Expr->getFragmentInfo(), MI.getDebugLoc()); if (!Discard) - UV->addDef(Idx, MI.getOperand(0), IsIndirect); + UV->addDef(Idx, MI.getOperand(0), IsIndirect, *Expr); else { MachineOperand MO = MachineOperand::CreateReg(0U, false); MO.setIsDebug(); - UV->addDef(Idx, MO, false); + UV->addDef(Idx, MO, false, *Expr); } return true; } @@ -751,7 +755,7 @@ } void UserValue::addDefsFromCopies( - LiveInterval *LI, unsigned LocNo, bool WasIndirect, + LiveInterval *LI, DbgValueLocation Loc, const SmallVectorImpl &Kills, SmallVectorImpl> &NewDefs, MachineRegisterInfo &MRI, LiveIntervals &LIS) { @@ -781,7 +785,7 @@ // it, or we are looking at a wrong value of LI. SlotIndex Idx = LIS.getInstructionIndex(*MI); LocMap::iterator I = locInts.find(Idx.getRegSlot(true)); - if (!I.valid() || I.value().locNo() != LocNo) + if (!I.valid() || I.value().locNo() != Loc.locNo()) continue; if (!LIS.hasInterval(DstReg)) @@ -815,7 +819,7 @@ MachineInstr *CopyMI = LIS.getInstructionFromIndex(DstVNI->def); assert(CopyMI && CopyMI->isCopy() && "Bad copy value"); unsigned LocNo = getLocationNo(CopyMI->getOperand(0)); - DbgValueLocation NewLoc(LocNo, WasIndirect); + DbgValueLocation NewLoc = Loc.changeLocNo(LocNo); I.insert(Idx, Idx.getNextSlot(), NewLoc); NewDefs.push_back(std::make_pair(Idx, NewLoc)); break; @@ -863,8 +867,7 @@ // sub-register in that regclass). For now, simply skip handling copies if // a sub-register is involved. if (LI && !LocMO.getSubReg()) - addDefsFromCopies(LI, Loc.locNo(), Loc.wasIndirect(), Kills, Defs, MRI, - LIS); + addDefsFromCopies(LI, Loc, Kills, Defs, MRI, LIS); continue; } @@ -1301,7 +1304,7 @@ // original DBG_VALUE was indirect, we need to add DW_OP_deref to indicate // that the original virtual register was a pointer. Also, add the stack slot // offset for the spilled register to the expression. - const DIExpression *Expr = Expression; + const DIExpression *Expr = Loc.expression(); uint8_t DIExprFlags = DIExpression::ApplyOffset; bool IsIndirect = Loc.wasIndirect(); if (Spilled) { Index: llvm/test/DebugInfo/pr41992.ll =================================================================== --- /dev/null +++ llvm/test/DebugInfo/pr41992.ll @@ -0,0 +1,45 @@ +; Test that two identical DBG_VALUEs are not coalesced when another used to describe +; the same source variable with a different DIExpression is found between them. + +; RUN: llc %s -stop-after=virtregrewriter -o - | FileCheck %s +; CHECK: DBG_VALUE %stack.0.x.addr, $noreg, ![[DBG_VAR:[0-9]+]], !DIExpression(DW_OP_deref) +; CHECK: DBG_VALUE 1, $noreg, ![[DBG_VAR]], !DIExpression() +; CHECK: DBG_VALUE %stack.0.x.addr, $noreg, ![[DBG_VAR]], !DIExpression(DW_OP_deref) + +declare void @llvm.dbg.addr(metadata, metadata, metadata) +declare void @llvm.dbg.value(metadata, metadata, metadata) +declare void @escape(i32*) + +@global = external global i32, align 4 + +define void @f(i32 %x) !dbg !8 { +entry: + %x.addr = alloca i32, align 4 + store i32 %x, i32* %x.addr, align 4 + call void @llvm.dbg.value(metadata i32* %x.addr, metadata !13, metadata !DIExpression(DW_OP_deref)), !dbg !18 + call void @escape(i32* %x.addr), !dbg !18 + call void @llvm.dbg.value(metadata i32 1, metadata !13, metadata !DIExpression()), !dbg !18 + store i32 1, i32* @global, align 4, !dbg !18 + call void @llvm.dbg.value(metadata i32* %x.addr, metadata !13, metadata !DIExpression(DW_OP_deref)), !dbg !18 + store i32 2, i32* %x.addr, align 4, !dbg !18 + call void @escape(i32* %x.addr), !dbg !18 + ret void, !dbg !18 +} + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!3, !4} +!llvm.ident = !{!7} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 6.0.0 ", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2) +!1 = !DIFile(filename: "dse.c", directory: "") +!2 = !{} +!3 = !{i32 2, !"Dwarf Version", i32 4} +!4 = !{i32 2, !"Debug Info Version", i32 3} +!7 = !{!"clang version 6.0.0 "} +!8 = distinct !DISubprogram(name: "f", scope: !1, file: !1, line: 3, type: !9, isLocal: false, isDefinition: true, scopeLine: 3, flags: DIFlagPrototyped, isOptimized: true, unit: !0, retainedNodes: !12) +!9 = !DISubroutineType(types: !10) +!10 = !{null, !11} +!11 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!12 = !{!13} +!13 = !DILocalVariable(name: "x", arg: 1, scope: !8, file: !1, line: 3, type: !11) +!18 = !DILocation(line: 3, column: 12, scope: !8)