Index: lib/CodeGen/AsmPrinter/DbgEntityHistoryCalculator.cpp =================================================================== --- lib/CodeGen/AsmPrinter/DbgEntityHistoryCalculator.cpp +++ lib/CodeGen/AsmPrinter/DbgEntityHistoryCalculator.cpp @@ -287,6 +287,7 @@ const TargetLowering *TLI = MF->getSubtarget().getTargetLowering(); unsigned SP = TLI->getStackPointerRegisterToSaveRestore(); + unsigned FrameReg = TRI->getFrameRegister(*MF); RegDescribedVarsMap RegVars; DbgValueEntriesMap LiveEntries; for (const auto &MBB : *MF) { @@ -359,7 +360,8 @@ for (auto I = RegVars.begin(), E = RegVars.end(); I != E;) { auto CurElem = I++; // CurElem can be erased below. if (TRI->isVirtualRegister(CurElem->first) || - ChangingRegs.test(CurElem->first)) + ChangingRegs.test(CurElem->first) || + FrameReg == CurElem->first) clobberRegisterUses(RegVars, CurElem, DbgValues, LiveEntries, MBB.back()); } Index: lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp =================================================================== --- lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp +++ lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp @@ -607,36 +607,27 @@ return VariableDie; } - // Check if variable is described by a DBG_VALUE instruction. - if (const MachineInstr *DVInsn = DV.getMInsn()) { - assert(DVInsn->getNumOperands() == 4); - if (DVInsn->getOperand(0).isReg()) { - auto RegOp = DVInsn->getOperand(0); - auto Op1 = DVInsn->getOperand(1); - // If the second operand is an immediate, this is an indirect value. - assert((!Op1.isImm() || (Op1.getImm() == 0)) && "unexpected offset"); - MachineLocation Location(RegOp.getReg(), Op1.isImm()); - addVariableAddress(DV, *VariableDie, Location); - } else if (DVInsn->getOperand(0).isImm()) { - // This variable is described by a single constant. - // Check whether it has a DIExpression. + // CHeck if variable has single location description. + if (auto *DVal = DV.getValueLoc()) { + if (DVal->isLocation()) + addVariableAddress(DV, *VariableDie, DVal->getLoc()); + else if (DVal->isInt()) { auto *Expr = DV.getSingleExpression(); if (Expr && Expr->getNumElements()) { DIELoc *Loc = new (DIEValueAllocator) DIELoc; DIEDwarfExpression DwarfExpr(*Asm, *this, *Loc); // If there is an expression, emit raw unsigned bytes. DwarfExpr.addFragmentOffset(Expr); - DwarfExpr.addUnsignedConstant(DVInsn->getOperand(0).getImm()); + DwarfExpr.addUnsignedConstant(DVal->getInt()); DwarfExpr.addExpression(Expr); addBlock(*VariableDie, dwarf::DW_AT_location, DwarfExpr.finalize()); } else - addConstantValue(*VariableDie, DVInsn->getOperand(0), DV.getType()); - } else if (DVInsn->getOperand(0).isFPImm()) - addConstantFPValue(*VariableDie, DVInsn->getOperand(0)); - else if (DVInsn->getOperand(0).isCImm()) - addConstantValue(*VariableDie, DVInsn->getOperand(0).getCImm(), - DV.getType()); - + addConstantValue(*VariableDie, DVal->getInt(), DV.getType()); + } else if (DVal->isConstantFP()) { + addConstantFPValue(*VariableDie, DVal->getConstantFP()); + } else if (DVal->isConstantInt()) { + addConstantValue(*VariableDie, DVal->getConstantInt(), DV.getType()); + } return VariableDie; } Index: lib/CodeGen/AsmPrinter/DwarfDebug.h =================================================================== --- lib/CodeGen/AsmPrinter/DwarfDebug.h +++ lib/CodeGen/AsmPrinter/DwarfDebug.h @@ -15,6 +15,7 @@ #include "AddressPool.h" #include "DebugLocStream.h" +#include "DebugLocEntry.h" #include "DwarfFile.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMap.h" @@ -110,12 +111,14 @@ /// /// Variables can be created from \c DBG_VALUE instructions. Those whose /// location changes over time use \a DebugLocListIndex, while those with a -/// single instruction use \a MInsn and (optionally) a single entry of \a Expr. +/// single instruction use \a ValueLoc and (optionally) a single entry of \a Expr. /// /// Variables that have been optimized out use none of these fields. class DbgVariable : public DbgEntity { - unsigned DebugLocListIndex = ~0u; /// Offset in DebugLocs. - const MachineInstr *MInsn = nullptr; /// DBG_VALUE instruction. + /// Offset in DebugLocs. + unsigned DebugLocListIndex = ~0u; + /// Single value location description. + std::unique_ptr ValueLoc = nullptr; struct FrameIndexExpr { int FI; @@ -135,7 +138,7 @@ /// Initialize from the MMI table. void initializeMMI(const DIExpression *E, int FI) { assert(FrameIndexExprs.empty() && "Already initialized?"); - assert(!MInsn && "Already initialized?"); + assert(!ValueLoc.get() && "Already initialized?"); assert((!E || E->isValid()) && "Expected valid expression"); assert(FI != std::numeric_limits::max() && "Expected valid index"); @@ -143,35 +146,35 @@ FrameIndexExprs.push_back({FI, E}); } - /// Initialize from a DBG_VALUE instruction. - void initializeDbgValue(const MachineInstr *DbgValue) { + // Initialize variable's location. + void initializeDbgValue(DebugLocEntry::Value Value) { assert(FrameIndexExprs.empty() && "Already initialized?"); - assert(!MInsn && "Already initialized?"); - - assert(getVariable() == DbgValue->getDebugVariable() && "Wrong variable"); - assert(getInlinedAt() == DbgValue->getDebugLoc()->getInlinedAt() && - "Wrong inlined-at"); + assert(!ValueLoc && "Already initialized?"); + assert(!Value.getExpression()->isFragment() && "Fragments not supported."); - MInsn = DbgValue; - if (auto *E = DbgValue->getDebugExpression()) + ValueLoc = llvm::make_unique(Value); + if (auto *E = ValueLoc->getExpression()) if (E->getNumElements()) FrameIndexExprs.push_back({0, E}); } + /// Initialize from a DBG_VALUE instruction. + void initializeDbgValue(const MachineInstr *DbgValue); + // Accessors. const DILocalVariable *getVariable() const { return cast(getEntity()); } const DIExpression *getSingleExpression() const { - assert(MInsn && FrameIndexExprs.size() <= 1); + assert(ValueLoc.get() && FrameIndexExprs.size() <= 1); return FrameIndexExprs.size() ? FrameIndexExprs[0].Expr : nullptr; } void setDebugLocListIndex(unsigned O) { DebugLocListIndex = O; } unsigned getDebugLocListIndex() const { return DebugLocListIndex; } StringRef getName() const { return getVariable()->getName(); } - const MachineInstr *getMInsn() const { return MInsn; } + const DebugLocEntry::Value *getValueLoc() const { return ValueLoc.get(); } /// Get the FI entries, sorted by fragment offset. ArrayRef getFrameIndexExprs() const; bool hasFrameIndexExprs() const { return !FrameIndexExprs.empty(); } @@ -204,7 +207,7 @@ } bool hasComplexAddress() const { - assert(MInsn && "Expected DBG_VALUE, not MMI variable"); + assert(ValueLoc.get() && "Expected DBG_VALUE, not MMI variable"); assert((FrameIndexExprs.empty() || (FrameIndexExprs.size() == 1 && FrameIndexExprs[0].Expr->getNumElements())) && @@ -547,8 +550,10 @@ DenseSet &ProcessedVars); /// Build the location list for all DBG_VALUEs in the - /// function that describe the same variable. - void buildLocationList(SmallVectorImpl &DebugLoc, + /// function that describe the same variable. If built list has + /// only one entry that is valid for entire variable's scope + /// return true. + bool buildLocationList(SmallVectorImpl &DebugLoc, const DbgValueHistoryMap::Entries &Entries); /// Collect variable information from the side table maintained by MF. Index: lib/CodeGen/AsmPrinter/DwarfDebug.cpp =================================================================== --- lib/CodeGen/AsmPrinter/DwarfDebug.cpp +++ lib/CodeGen/AsmPrinter/DwarfDebug.cpp @@ -244,6 +244,44 @@ return Ty; } +// Get .debug_loc entry for the instruction range starting at MI. +static DebugLocEntry::Value getDebugLocValue(const MachineInstr *MI) { + const DIExpression *Expr = MI->getDebugExpression(); + assert(MI->getNumOperands() == 4); + if (MI->getOperand(0).isReg()) { + auto RegOp = MI->getOperand(0); + auto Op1 = MI->getOperand(1); + // If the second operand is an immediate, this is a + // register-indirect address. + assert((!Op1.isImm() || (Op1.getImm() == 0)) && "unexpected offset"); + MachineLocation MLoc(RegOp.getReg(), Op1.isImm()); + return DebugLocEntry::Value(Expr, MLoc); + } + if (MI->getOperand(0).isImm()) + return DebugLocEntry::Value(Expr, MI->getOperand(0).getImm()); + if (MI->getOperand(0).isFPImm()) + return DebugLocEntry::Value(Expr, MI->getOperand(0).getFPImm()); + if (MI->getOperand(0).isCImm()) + return DebugLocEntry::Value(Expr, MI->getOperand(0).getCImm()); + + llvm_unreachable("Unexpected 4-operand DBG_VALUE instruction!"); +} + +/// Initialize from a DBG_VALUE instruction. +void DbgVariable::initializeDbgValue(const MachineInstr *DbgValue) { + assert(FrameIndexExprs.empty() && "Already initialized?"); + assert(!ValueLoc.get() && "Already initialized?"); + + assert(getVariable() == DbgValue->getDebugVariable() && "Wrong variable"); + assert(getInlinedAt() == DbgValue->getDebugLoc()->getInlinedAt() && + "Wrong inlined-at"); + + ValueLoc = llvm::make_unique(getDebugLocValue(DbgValue)); + if (auto *E = DbgValue->getDebugExpression()) + if (E->getNumElements()) + FrameIndexExprs.push_back({0, E}); +} + ArrayRef DbgVariable::getFrameIndexExprs() const { if (FrameIndexExprs.size() == 1) return FrameIndexExprs; @@ -263,8 +301,8 @@ } void DbgVariable::addMMIEntry(const DbgVariable &V) { - assert(DebugLocListIndex == ~0U && !MInsn && "not an MMI entry"); - assert(V.DebugLocListIndex == ~0U && !V.MInsn && "not an MMI entry"); + assert(DebugLocListIndex == ~0U && !ValueLoc.get() && "not an MMI entry"); + assert(V.DebugLocListIndex == ~0U && !V.ValueLoc.get() && "not an MMI entry"); assert(V.getVariable() == getVariable() && "conflicting variable"); assert(V.getInlinedAt() == getInlinedAt() && "conflicting inlined-at location"); @@ -1075,33 +1113,69 @@ } } -// Get .debug_loc entry for the instruction range starting at MI. -static DebugLocEntry::Value getDebugLocValue(const MachineInstr *MI) { - const DIExpression *Expr = MI->getDebugExpression(); - assert(MI->getNumOperands() == 4); - if (MI->getOperand(0).isReg()) { - auto RegOp = MI->getOperand(0); - auto Op1 = MI->getOperand(1); - // If the second operand is an immediate, this is a - // register-indirect address. - assert((!Op1.isImm() || (Op1.getImm() == 0)) && "unexpected offset"); - MachineLocation MLoc(RegOp.getReg(), Op1.isImm()); - return DebugLocEntry::Value(Expr, MLoc); +/// Determine whether a *singular* DBG_VALUE is valid for the entirety of its +/// enclosing lexical scope. The check ensures there are no other instructions +/// in the same lexical scope preceding the DBG_VALUE and that its range is +/// either open or otherwise rolls off the end of the scope. +static bool validThroughout(LexicalScopes &LScopes, + const MachineInstr *DbgValue, + const MachineInstr *RangeEnd) { + assert(DbgValue->getDebugLoc() && "DBG_VALUE without a debug location"); + auto MBB = DbgValue->getParent(); + auto DL = DbgValue->getDebugLoc(); + auto *LScope = LScopes.findLexicalScope(DL); + // Scope doesn't exist; this is a dead DBG_VALUE. + if (!LScope) + return false; + auto &LSRange = LScope->getRanges(); + if (LSRange.size() == 0) + return false; + + // Determine if the DBG_VALUE is valid at the beginning of its lexical block. + const MachineInstr *LScopeBegin = LSRange.front().first; + // Early exit if the lexical scope begins outside of the current block. + if (LScopeBegin->getParent() != MBB) + return false; + MachineBasicBlock::const_reverse_iterator Pred(DbgValue); + for (++Pred; Pred != MBB->rend(); ++Pred) { + if (Pred->getFlag(MachineInstr::FrameSetup)) + break; + auto PredDL = Pred->getDebugLoc(); + if (!PredDL || Pred->isMetaInstruction()) + continue; + // Check whether the instruction preceding the DBG_VALUE is in the same + // (sub)scope as the DBG_VALUE. + if (DL->getScope() == PredDL->getScope()) + return false; + auto *PredScope = LScopes.findLexicalScope(PredDL); + if (!PredScope || LScope->dominates(PredScope)) + return false; } - if (MI->getOperand(0).isImm()) - return DebugLocEntry::Value(Expr, MI->getOperand(0).getImm()); - if (MI->getOperand(0).isFPImm()) - return DebugLocEntry::Value(Expr, MI->getOperand(0).getFPImm()); - if (MI->getOperand(0).isCImm()) - return DebugLocEntry::Value(Expr, MI->getOperand(0).getCImm()); - llvm_unreachable("Unexpected 4-operand DBG_VALUE instruction!"); + // If the range of the DBG_VALUE is open-ended, report success. + if (!RangeEnd) + return true; + + // Fail if there are instructions belonging to our scope in another block. + const MachineInstr *LScopeEnd = LSRange.back().second; + if (LScopeEnd->getParent() != MBB) + return false; + + // Single, constant DBG_VALUEs in the prologue are promoted to be live + // throughout the function. This is a hack, presumably for DWARF v2 and not + // necessarily correct. It would be much better to use a dbg.declare instead + // if we know the constant is live throughout the scope. + if (DbgValue->getOperand(0).isImm() && MBB->pred_empty()) + return true; + + return false; } /// Build the location list for all DBG_VALUEs in the function that /// describe the same variable. The resulting DebugLocEntries will have /// strict monotonically increasing begin addresses and will never -/// overlap. +/// overlap. If built list has only one entry that is valid throughout +/// variable's scope return true. // // See the definition of DbgValueHistoryMap::Entry for an explanation of the // different kinds of history map entries. One thing to be aware of is that if @@ -1130,11 +1204,14 @@ // [1-3) [(reg0, fragment 0, 32), (reg1, fragment 32, 32)] // [3-4) [(reg1, fragment 32, 32), (123, fragment 64, 32)] // [4-) [(@g, fragment 0, 96)] -void DwarfDebug::buildLocationList(SmallVectorImpl &DebugLoc, +bool DwarfDebug::buildLocationList(SmallVectorImpl &DebugLoc, const DbgValueHistoryMap::Entries &Entries) { using OpenRange = std::pair; SmallVector OpenRanges; + bool isSafeForSingleLocation = true; + const MachineInstr *StartDebugMI = nullptr; + const MachineInstr *EndMI = nullptr; for (auto EB = Entries.begin(), EI = EB, EE = Entries.end(); EI != EE; ++EI) { const MachineInstr *Instr = EI->getInstr(); @@ -1142,10 +1219,16 @@ if (EI->isDbgValue()) { // Check if a variable is inaccessible in this range. // TODO: This should only truncate open ranges that are overlapping. - if (Instr->getNumOperands() > 1 && - Instr->getOperand(0).isReg() && !Instr->getOperand(0).getReg()) { + if (Instr->getNumOperands() > 1 && Instr->getOperand(0).isReg() && + !Instr->getOperand(0).getReg()) { OpenRanges.clear(); + isSafeForSingleLocation = false; continue; + } else if (Instr->getDebugExpression()->isFragment()) { + // TODO: Add support for single value fragment locations. + isSafeForSingleLocation = false; + } else if (!StartDebugMI) { + StartDebugMI = Instr; } } @@ -1163,8 +1246,11 @@ "Forgot label before/after instruction starting a range!"); const MCSymbol *EndLabel; - if (std::next(EI) == Entries.end()) + if (std::next(EI) == Entries.end()) { EndLabel = Asm->getFunctionEnd(); + if (EI->isClobber()) + EndMI = EI->getInstr(); + } else if (std::next(EI)->isClobber()) EndLabel = getLabelAfterInsn(std::next(EI)->getInstr()); else @@ -1211,6 +1297,9 @@ if (PrevEntry != DebugLoc.rend() && PrevEntry->MergeRanges(*CurEntry)) DebugLoc.pop_back(); } + + return DebugLoc.size() == 1 && isSafeForSingleLocation && + validThroughout(LScopes, StartDebugMI, EndMI); } DbgEntity *DwarfDebug::createConcreteEntity(DwarfCompileUnit &TheCU, @@ -1235,64 +1324,6 @@ return ConcreteEntities.back().get(); } -/// Determine whether a *singular* DBG_VALUE is valid for the entirety of its -/// enclosing lexical scope. The check ensures there are no other instructions -/// in the same lexical scope preceding the DBG_VALUE and that its range is -/// either open or otherwise rolls off the end of the scope. -static bool validThroughout(LexicalScopes &LScopes, - const MachineInstr *DbgValue, - const MachineInstr *RangeEnd) { - assert(DbgValue->getDebugLoc() && "DBG_VALUE without a debug location"); - auto MBB = DbgValue->getParent(); - auto DL = DbgValue->getDebugLoc(); - auto *LScope = LScopes.findLexicalScope(DL); - // Scope doesn't exist; this is a dead DBG_VALUE. - if (!LScope) - return false; - auto &LSRange = LScope->getRanges(); - if (LSRange.size() == 0) - return false; - - // Determine if the DBG_VALUE is valid at the beginning of its lexical block. - const MachineInstr *LScopeBegin = LSRange.front().first; - // Early exit if the lexical scope begins outside of the current block. - if (LScopeBegin->getParent() != MBB) - return false; - MachineBasicBlock::const_reverse_iterator Pred(DbgValue); - for (++Pred; Pred != MBB->rend(); ++Pred) { - if (Pred->getFlag(MachineInstr::FrameSetup)) - break; - auto PredDL = Pred->getDebugLoc(); - if (!PredDL || Pred->isMetaInstruction()) - continue; - // Check whether the instruction preceding the DBG_VALUE is in the same - // (sub)scope as the DBG_VALUE. - if (DL->getScope() == PredDL->getScope()) - return false; - auto *PredScope = LScopes.findLexicalScope(PredDL); - if (!PredScope || LScope->dominates(PredScope)) - return false; - } - - // If the range of the DBG_VALUE is open-ended, report success. - if (!RangeEnd) - return true; - - // Fail if there are instructions belonging to our scope in another block. - const MachineInstr *LScopeEnd = LSRange.back().second; - if (LScopeEnd->getParent() != MBB) - return false; - - // Single, constant DBG_VALUEs in the prologue are promoted to be live - // throughout the function. This is a hack, presumably for DWARF v2 and not - // necessarily correct. It would be much better to use a dbg.declare instead - // if we know the constant is live throughout the scope. - if (DbgValue->getOperand(0).isImm() && MBB->pred_empty()) - return true; - - return false; -} - // Find variables for each lexical scope. void DwarfDebug::collectEntityInfo(DwarfCompileUnit &TheCU, const DISubprogram *SP, @@ -1330,9 +1361,10 @@ // Check if there is a single DBG_VALUE, valid throughout the var's scope. // If the history map contains a single debug value, there may be an // additional entry which clobbers the debug value. + size_t HistSize = HistoryMapEntries.size(); bool SingleValueWithClobber = - HistoryMapEntries.size() == 2 && HistoryMapEntries[1].isClobber(); - if (HistoryMapEntries.size() == 1 || SingleValueWithClobber) { + HistSize == 2 && HistoryMapEntries[1].isClobber(); + if (HistSize == 1 || SingleValueWithClobber) { const auto *End = SingleValueWithClobber ? HistoryMapEntries[1].getInstr() : nullptr; if (validThroughout(LScopes, MInsn, End)) { @@ -1350,7 +1382,15 @@ // Build the location list for this variable. SmallVector Entries; - buildLocationList(Entries, HistoryMapEntries); + bool isValidSingleLocation = buildLocationList(Entries, HistoryMapEntries); + + // Check whether buildLocationList managed to merge all locations to one + // that is valid throughout the variable's scope. If so, produce single + // value location. + if (isValidSingleLocation) { + RegVar->initializeDbgValue(Entries[0].getValues()[0]); + continue; + } // If the variable has a DIBasicType, extract it. Basic types cannot have // unique identifiers, so don't bother resolving the type with the @@ -1902,8 +1942,8 @@ StringOffsetsSection, /* UseRelativeOffsets = */ true); } -void DwarfDebug::emitDebugLocEntry(ByteStreamer &Streamer, const - DebugLocStream::Entry &Entry, +void DwarfDebug::emitDebugLocEntry(ByteStreamer &Streamer, + const DebugLocStream::Entry &Entry, const DwarfCompileUnit *CU) { auto &&Comments = DebugLocs.getComments(Entry); auto Comment = Comments.begin(); Index: lib/CodeGen/AsmPrinter/DwarfUnit.h =================================================================== --- lib/CodeGen/AsmPrinter/DwarfUnit.h +++ lib/CodeGen/AsmPrinter/DwarfUnit.h @@ -198,6 +198,7 @@ void addConstantValue(DIE &Die, const ConstantInt *CI, const DIType *Ty); void addConstantValue(DIE &Die, const APInt &Val, const DIType *Ty); void addConstantValue(DIE &Die, const APInt &Val, bool Unsigned); + void addConstantValue(DIE &Die, uint64_t Val, const DIType *Ty); void addConstantValue(DIE &Die, bool Unsigned, uint64_t Val); /// Add constant value entry in variable DIE. Index: lib/CodeGen/AsmPrinter/DwarfUnit.cpp =================================================================== --- lib/CodeGen/AsmPrinter/DwarfUnit.cpp +++ lib/CodeGen/AsmPrinter/DwarfUnit.cpp @@ -531,6 +531,10 @@ addConstantValue(Die, isUnsignedDIType(DD, Ty), MO.getImm()); } +void DwarfUnit::addConstantValue(DIE &Die, uint64_t Val, const DIType *Ty) { + addConstantValue(Die, isUnsignedDIType(DD, Ty), Val); +} + void DwarfUnit::addConstantValue(DIE &Die, bool Unsigned, uint64_t Val) { // FIXME: This is a bit conservative/simple - it emits negative values always // sign extended to 64 bits rather than minimizing the number of bytes. Index: test/DebugInfo/MIR/X86/dbg-stack-value-range.mir =================================================================== --- /dev/null +++ test/DebugInfo/MIR/X86/dbg-stack-value-range.mir @@ -0,0 +1,184 @@ +# RUN: llc -start-before=livedebugvalues %s -filetype=asm -o -| FileCheck %s +# +# DbgEntityHistoryCalculator should close variable's range at the end of +# the basic block when variable is referenced through non-changing frame +# pointer register. Having BB1 that branches to BB2 and BB3, where +# BB2 falls through to BB3, variable can have different locations at BB1 and BB2. +# Since input locations at BB3 for same variable are different LiveDebugValues +# wont generate DBG_VALUE for BB3. If last variable location at BB2 is +# non-changing register, DbgEntityHistoryCalculator will extend range of +# DBG_VALUE from BB2 to whole BB3 and thus produce incorrect range for +# case when we took branch BB3 from BB1. +# +# Verifies that "local1" stack location is ended at the end of the block (.Ltmp6). +# +# CHECK: .Ltmp4: +# CHECK-NEXT: #DEBUG_VALUE: foo:local1 <- [DW_OP_constu 4, DW_OP_minus, DW_OP_deref] $rbp +# CHECK: jmp .LBB0_2 +# CHECK-NEXT: .Ltmp6: +# CHECK: .Lfunc_end0: +# +# CHECK: .Linfo_string7: +# CHECK-NEXT: .asciz "local1" +# +# CHECK: .Ldebug_loc2: +# CHECK-NEXT: .quad .Ltmp1-.Lfunc_begin0 +# CHECK-NEXT: .quad .Ltmp4-.Lfunc_begin0 +# CHECK-NEXT: .short 1 # Loc expr size +# CHECK-NEXT: .byte 94 # super-register DW_OP_reg14 +# CHECK-NEXT: .quad .Ltmp4-.Lfunc_begin0 +# CHECK-NEXT: .quad .Ltmp6-.Lfunc_begin0 +# CHECK-NEXT: .short 2 # Loc expr size +# CHECK-NEXT: .byte 118 # DW_OP_breg6 +# CHECK-NEXT: .byte 124 # -4 +# +# CHECK: .long .Ldebug_loc2 # DW_AT_location +# CHECK-NEXT: .long .Linfo_string7 # DW_AT_name + + +--- | + ; ModuleID = 'dbg-stack-value-range.ll' + source_filename = "dbg-stack-value-range.c" + target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" + target triple = "x86_64-unknown-linux-gnu" + + ; Function Attrs: nounwind uwtable + define dso_local i32 @foo(i32 %X) local_unnamed_addr #0 !dbg !7 { + entry: + %local1 = alloca i32, align 4 + call void @llvm.dbg.value(metadata i32 %X, metadata !12, metadata !DIExpression()), !dbg !15 + %0 = bitcast i32* %local1 to i8*, !dbg !15 + call void @llvm.lifetime.start.p0i8(i64 4, i8* nonnull %0), !dbg !15 + call void @llvm.dbg.value(metadata i32 5, metadata !14, metadata !DIExpression()), !dbg !15 + %call = tail call i32 (...) @check(), !dbg !15 + %tobool = icmp eq i32 %call, 0, !dbg !15 + br i1 %tobool, label %if.else, label %if.then, !dbg !15 + + if.then: ; preds = %entry + call void @llvm.dbg.value(metadata i32 4, metadata !13, metadata !DIExpression()), !dbg !15 + store i32 4, i32* %local1, align 4, !dbg !15, !tbaa !16 + call void @llvm.dbg.value(metadata i32* %local1, metadata !13, metadata !DIExpression(DW_OP_deref)), !dbg !15 + %call1 = call i32 @init(i32* nonnull %local1), !dbg !15 + call void @llvm.dbg.value(metadata i32 undef, metadata !14, metadata !DIExpression()), !dbg !15 + br label %if.end, !dbg !15 + + if.else: ; preds = %entry + call void @llvm.dbg.value(metadata i32 5, metadata !13, metadata !DIExpression()), !dbg !15 + store i32 5, i32* %local1, align 4, !dbg !15, !tbaa !16 + br label %if.end + + if.end: ; preds = %if.else, %if.then + %1 = bitcast i32* %local1 to i8*, !dbg !15 + call void @llvm.dbg.value(metadata i32 undef, metadata !14, metadata !DIExpression()), !dbg !15 + %call2 = call i32 (...) @init2(), !dbg !15 + call void @llvm.dbg.value(metadata i32 undef, metadata !14, metadata !DIExpression()), !dbg !15 + %2 = load i32, i32* %local1, align 4, !dbg !15, !tbaa !16 + call void @llvm.dbg.value(metadata i32 %2, metadata !13, metadata !DIExpression()), !dbg !15 + call void @llvm.lifetime.end.p0i8(i64 4, i8* nonnull %1), !dbg !15 + ret i32 %2, !dbg !15 + } + + ; Function Attrs: argmemonly nounwind + declare void @llvm.lifetime.start.p0i8(i64 immarg, i8* nocapture) + + declare dso_local i32 @check(...) local_unnamed_addr + + declare dso_local i32 @init(i32*) local_unnamed_addr + + declare dso_local i32 @init2(...) local_unnamed_addr + + ; Function Attrs: argmemonly nounwind + declare void @llvm.lifetime.end.p0i8(i64 immarg, i8* nocapture) + + ; Function Attrs: nounwind readnone speculatable + declare void @llvm.dbg.value(metadata, metadata, metadata) + + ; Function Attrs: nounwind + declare void @llvm.stackprotector(i8*, i8**) + + attributes #0 = { nounwind uwtable "no-frame-pointer-elim"="false" "no-frame-pointer-elim-non-leaf" } + + !llvm.dbg.cu = !{!0} + !llvm.module.flags = !{!3, !4, !5} + !llvm.ident = !{!6} + + !0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 9.0.0", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: None) + !1 = !DIFile(filename: "dbg-stack-value-range.c", directory: "/") + !2 = !{} + !3 = !{i32 2, !"Dwarf Version", i32 4} + !4 = !{i32 2, !"Debug Info Version", i32 3} + !5 = !{i32 1, !"wchar_size", i32 4} + !6 = !{!"clang version 9.0.0"} + !7 = distinct !DISubprogram(name: "foo", scope: !1, file: !1, line: 11, type: !8, scopeLine: 11, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !11) + !8 = !DISubroutineType(types: !9) + !9 = !{!10, !10} + !10 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) + !11 = !{!12, !13, !14} + !12 = !DILocalVariable(name: "X", arg: 1, scope: !7, file: !1, line: 11, type: !10) + !13 = !DILocalVariable(name: "local1", scope: !7, file: !1, line: 12, type: !10) + !14 = !DILocalVariable(name: "local2", scope: !7, file: !1, line: 12, type: !10) + !15 = !DILocation(line: 11, column: 13, scope: !7) + !16 = !{!17, !17, i64 0} + !17 = !{!"int", !18, i64 0} + !18 = !{!"omnipotent char", !19, i64 0} + !19 = !{!"Simple C/C++ TBAA"} + +... +--- +name: foo +alignment: 4 +frameInfo: + stackSize: 24 + offsetAdjustment: -24 + maxAlignment: 4 + adjustsStack: true + hasCalls: true +fixedStack: + - { id: 0, type: spill-slot, offset: -16, size: 8, alignment: 16, stack-id: 0, + callee-saved-register: '$r14d', callee-saved-restored: true, debug-info-variable: '', + debug-info-expression: '', debug-info-location: '' } +stack: + - { id: 0, name: local1, type: default, offset: -20, size: 4, alignment: 4, + stack-id: 0, callee-saved-register: '', callee-saved-restored: true, + debug-info-variable: '', debug-info-expression: '', debug-info-location: '' } +body: | + bb.0.entry: + successors: %bb.3(0x30000000), %bb.1(0x50000000) + + DBG_VALUE $edi, $noreg, !12, !DIExpression(), debug-location !15 + frame-setup PUSH64r killed $rbp, implicit-def $rsp, implicit $rsp + CFI_INSTRUCTION def_cfa_offset 16 + CFI_INSTRUCTION offset $rbp, -16 + $rbp = frame-setup MOV64rr $rsp + CFI_INSTRUCTION def_cfa_register $rbp + $rsp = frame-setup SUB64ri8 $rsp, 16, implicit-def dead $eflags + DBG_VALUE 5, $noreg, !14, !DIExpression(), debug-location !15 + $r14d = MOV32ri 4, implicit-def $r14 + DBG_VALUE $r14d, $noreg, !13, !DIExpression(), debug-location !15 + dead $eax = XOR32rr undef $eax, undef $eax, implicit-def dead $eflags, implicit-def $al, debug-location !15 + CALL64pcrel32 @check, csr_64, implicit $rsp, implicit $ssp, implicit $al, implicit-def $rsp, implicit-def $ssp, implicit-def $eax, debug-location !15 + TEST32rr killed renamable $eax, renamable $eax, implicit-def $eflags, debug-location !15 + JCC_1 %bb.3, 4, implicit killed $eflags, debug-location !15 + + bb.1.if.then: + successors: %bb.3(0x80000000) + + MOV32mr $rbp, 1, $noreg, -4, $noreg, $r14d, debug-location !15 :: (store 4 into %ir.local1, !tbaa !16) + DBG_VALUE $rbp, $noreg, !13, !DIExpression(DW_OP_constu, 4, DW_OP_minus, DW_OP_deref), debug-location !15 + renamable $rdi = LEA64r $rbp, 1, $noreg, -4, $noreg + CALL64pcrel32 @init, csr_64, implicit $rsp, implicit $ssp, implicit $rdi, implicit-def $rsp, implicit-def $ssp, implicit-def dead $eax, debug-location !15 + DBG_VALUE $noreg, $noreg, !14, !DIExpression(), debug-location !15 + JMP_1 %bb.3 + + bb.3.if.end: + DBG_VALUE $noreg, $noreg, !14, !DIExpression(), debug-location !15 + dead $eax = XOR32rr undef $eax, undef $eax, implicit-def dead $eflags, implicit-def $al, debug-location !15 + CALL64pcrel32 @init2, csr_64, implicit $rsp, implicit $ssp, implicit $al, implicit-def $rsp, implicit-def $ssp, implicit-def dead $eax, debug-location !15 + DBG_VALUE $noreg, $noreg, !14, !DIExpression(), debug-location !15 + renamable $eax = MOV32rm $rbp, 1, $noreg, -4, $noreg, debug-location !15 :: (dereferenceable load 4 from %ir.local1, !tbaa !16) + $rsp = frame-destroy ADD64ri8 $rsp, 16, implicit-def dead $eflags, debug-location !15 + $rbp = frame-destroy POP64r implicit-def $rsp, implicit $rsp, debug-location !15 + CFI_INSTRUCTION def_cfa $rsp, 8, debug-location !15 + RETQ $eax, debug-location !15 + +... Index: test/DebugInfo/X86/fission-ranges.ll =================================================================== --- test/DebugInfo/X86/fission-ranges.ll +++ test/DebugInfo/X86/fission-ranges.ll @@ -161,7 +161,7 @@ for.inc13: ; preds = %for.inc10 %inc14 = add i32 %d.06, 1, !dbg !37 - tail call void @llvm.dbg.value(metadata i32 %inc14, metadata !16, metadata !DIExpression()), !dbg !37 + tail call void @llvm.dbg.value(metadata i32 %inc14, metadata !16, metadata !DIExpression()), !dbg !42 %exitcond12 = icmp eq i32 %inc14, 30, !dbg !37 br i1 %exitcond12, label %for.inc16, label %for.cond4.preheader, !dbg !37