Index: lib/CodeGen/LiveDebugVariables.cpp =================================================================== --- lib/CodeGen/LiveDebugVariables.cpp +++ lib/CodeGen/LiveDebugVariables.cpp @@ -71,6 +71,7 @@ cl::desc("Enable the live debug variables pass"), cl::Hidden); STATISTIC(NumInsertedDebugValues, "Number of DBG_VALUEs inserted"); +STATISTIC(NumInsertedDebugLabels, "Number of DBG_LABELs inserted"); char LiveDebugVariables::ID = 0; @@ -339,6 +340,37 @@ void print(raw_ostream &, const TargetRegisterInfo *); }; +/// A user label is a part of a debug info user label. +class UserLabel { + const DILabel *Label; ///< The debug info label we are part of. + DebugLoc dl; ///< The debug location for the label. This is + ///< used by dwarf writer to find lexical scope. + SlotIndex loc; ///< Slot used by the debug label. + + /// Insert a DBG_LABEL into MBB at Idx. + void insertDebugLabel(MachineBasicBlock *MBB, SlotIndex Idx, + LiveIntervals &LIS, const TargetInstrInfo &TII); + +public: + /// Create a new UserLabel. + UserLabel(const DILabel *label, DebugLoc L, SlotIndex Idx) + : Label(label), dl(std::move(L)), loc(Idx) {} + + /// Does this UserLabel match the parameters? + bool match(const DILabel *L, const DILocation *IA, + const SlotIndex Index) const { + return Label == L && dl->getInlinedAt() == IA && loc == Index; + } + + /// Recreate DBG_LABEL instruction from data structures. + void emitDebugLabels(LiveIntervals &LIS, const TargetInstrInfo &TII); + + /// Return DebugLoc of this UserLabel. + DebugLoc getDebugLoc() { return dl; } + + void print(raw_ostream &, const TargetRegisterInfo *); +}; + /// Implementation of the LiveDebugVariables pass. class LDVImpl { LiveDebugVariables &pass; @@ -356,6 +388,9 @@ /// All allocated UserValue instances. SmallVector, 8> userValues; + /// All allocated UserLabel instances. + SmallVector, 2> userLabels; + /// Map virtual register to eq class leader. using VRMap = DenseMap; VRMap virtRegToEqClass; @@ -368,6 +403,10 @@ UserValue *getUserValue(const DILocalVariable *Var, const DIExpression *Expr, const DebugLoc &DL); + /// Find or create a UserLabel. + void addUserLabel(const DILabel *Label, const DebugLoc &DL, + const SlotIndex Idx); + /// Find the EC leader for VirtReg or null. UserValue *lookupVirtReg(unsigned VirtReg); @@ -379,6 +418,14 @@ /// \returns True if the DBG_VALUE instruction should be deleted. bool handleDebugValue(MachineInstr &MI, SlotIndex Idx); + /// Add DBG_LABEL instruction to UserLabel. + /// + /// \param MI DBG_LABEL instruction + /// \param Idx Last valid SlotIndex before instruction. + /// + /// \returns True if the DBG_LABEL instruction should be deleted. + bool handleDebugLabel(MachineInstr &MI, SlotIndex Idx); + /// Collect and erase all DBG_VALUE instructions, adding a UserValue def /// for each instruction. /// @@ -400,6 +447,7 @@ void clear() { MF = nullptr; userValues.clear(); + userLabels.clear(); virtRegToEqClass.clear(); userVarMap.clear(); // Make sure we call emitDebugValues if the machine function was modified. @@ -445,12 +493,21 @@ CommentOS << " ]"; } -static void printExtendedName(raw_ostream &OS, const DILocalVariable *V, +static void printExtendedName(raw_ostream &OS, const DINode *Node, const DILocation *DL) { - const LLVMContext &Ctx = V->getContext(); - StringRef Res = V->getName(); + const LLVMContext &Ctx = Node->getContext(); + StringRef Res; + unsigned Line; + if (const auto *V = dyn_cast(Node)) { + Res = V->getName(); + Line = V->getLine(); + } else if (const auto *L = dyn_cast(Node)) { + Res = L->getName(); + Line = L->getLine(); + } + if (!Res.empty()) - OS << Res << "," << V->getLine(); + OS << Res << "," << Line; if (auto *InlinedAt = DL->getInlinedAt()) { if (DebugLoc InlinedAtDL = InlinedAt) { OS << " @["; @@ -461,9 +518,8 @@ } void UserValue::print(raw_ostream &OS, const TargetRegisterInfo *TRI) { - auto *DV = cast(Variable); OS << "!\""; - printExtendedName(OS, DV, dl); + printExtendedName(OS, Variable, dl); OS << "\"\t"; for (LocMap::const_iterator I = locInts.begin(); I.valid(); ++I) { @@ -483,10 +539,22 @@ OS << '\n'; } +void UserLabel::print(raw_ostream &OS, const TargetRegisterInfo *TRI) { + OS << "!\""; + printExtendedName(OS, Label, dl); + + OS << "\"\t"; + OS << loc; + OS << '\n'; +} + void LDVImpl::print(raw_ostream &OS) { OS << "********** DEBUG VARIABLES **********\n"; - for (unsigned i = 0, e = userValues.size(); i != e; ++i) - userValues[i]->print(OS, TRI); + for (auto &userValue : userValues) + userValue->print(OS, TRI); + OS << "********** DEBUG LABELS **********\n"; + for (auto &userLabel : userLabels) + userLabel->print(OS, TRI); } #endif @@ -515,6 +583,17 @@ return UV; } +void LDVImpl::addUserLabel(const DILabel *Label, const DebugLoc &DL, + const SlotIndex Idx) { + for (auto const &L : userLabels) { + // The Label has existed in userLabels. + if (L->match(Label, DL->getInlinedAt(), Idx)) + return; + } + + userLabels.push_back(llvm::make_unique(Label, DL, Idx)); +} + void LDVImpl::mapVirtReg(unsigned VirtReg, UserValue *EC) { assert(TargetRegisterInfo::isVirtualRegister(VirtReg) && "Only map VirtRegs"); UserValue *&Leader = virtRegToEqClass[VirtReg]; @@ -587,6 +666,19 @@ return true; } +bool LDVImpl::handleDebugLabel(MachineInstr &MI, SlotIndex Idx) { + // DBG_LABEL label + if (MI.getNumOperands() != 1 || !MI.getOperand(0).isMetadata()) { + LLVM_DEBUG(dbgs() << "Can't handle " << MI); + return false; + } + + // Get or create the UserLabel for label here. + const DILabel *Label = MI.getDebugLabel(); + addUserLabel(Label, MI.getDebugLoc(), Idx); + return true; +} + bool LDVImpl::collectDebugValues(MachineFunction &mf) { bool Changed = false; for (MachineFunction::iterator MFI = mf.begin(), MFE = mf.end(); MFI != MFE; @@ -610,7 +702,8 @@ do { // Only handle DBG_VALUE in handleDebugValue(). Skip all other // kinds of debug instructions. - if (MBBI->isDebugValue() && handleDebugValue(*MBBI, Idx)) { + if ((MBBI->isDebugValue() && handleDebugValue(*MBBI, Idx)) || + (MBBI->isDebugLabel() && handleDebugLabel(*MBBI, Idx))) { MBBI = MBB->erase(MBBI); Changed = true; } else @@ -1247,6 +1340,15 @@ } while (I != MBB->end()); } +void UserLabel::insertDebugLabel(MachineBasicBlock *MBB, SlotIndex Idx, + LiveIntervals &LIS, + const TargetInstrInfo &TII) { + MachineBasicBlock::iterator I = findInsertLocation(MBB, Idx, LIS); + ++NumInsertedDebugLabels; + BuildMI(*MBB, I, getDebugLoc(), TII.get(TargetOpcode::DBG_LABEL)) + .addMetadata(Label); +} + void UserValue::emitDebugValues(VirtRegMap *VRM, LiveIntervals &LIS, const TargetInstrInfo &TII, const TargetRegisterInfo &TRI, @@ -1295,16 +1397,32 @@ } } +void UserLabel::emitDebugLabels(LiveIntervals &LIS, + const TargetInstrInfo &TII) { + LLVM_DEBUG(dbgs() << "\t" << loc); + MachineFunction::iterator MBB = LIS.getMBBFromIndex(loc)->getIterator(); + + LLVM_DEBUG(dbgs() << ' ' << printMBBReference(*MBB)); + insertDebugLabel(&*MBB, loc, LIS, TII); + + LLVM_DEBUG(dbgs() << '\n'); +} + void LDVImpl::emitDebugValues(VirtRegMap *VRM) { LLVM_DEBUG(dbgs() << "********** EMITTING LIVE DEBUG VARIABLES **********\n"); if (!MF) return; const TargetInstrInfo *TII = MF->getSubtarget().getInstrInfo(); SpillOffsetMap SpillOffsets; - for (unsigned i = 0, e = userValues.size(); i != e; ++i) { - LLVM_DEBUG(userValues[i]->print(dbgs(), TRI)); - userValues[i]->rewriteLocations(*VRM, *MF, *TII, *TRI, SpillOffsets); - userValues[i]->emitDebugValues(VRM, *LIS, *TII, *TRI, SpillOffsets); + for (auto &userValue : userValues) { + LLVM_DEBUG(userValue->print(dbgs(), TRI)); + userValue->rewriteLocations(*VRM, *MF, *TII, *TRI, SpillOffsets); + userValue->emitDebugValues(VRM, *LIS, *TII, *TRI, SpillOffsets); + } + LLVM_DEBUG(dbgs() << "********** EMITTING LIVE DEBUG LABELS **********\n"); + for (auto &userLabel : userLabels) { + LLVM_DEBUG(userLabel->print(dbgs(), TRI)); + userLabel->emitDebugLabels(*LIS, *TII); } EmitDone = true; } Index: test/CodeGen/Generic/live-debug-label.ll =================================================================== --- /dev/null +++ test/CodeGen/Generic/live-debug-label.ll @@ -0,0 +1,141 @@ +; Generated with "clang++ -g -O1 -S -emit-llvm" +; +; inline bool bar(char c) { +; return c >= '0' && c <= '9'; +; } +; +; unsigned foo(const char* data, +; int length, +; int* parsing_result) { +; unsigned value = 0; +; int result = 1; +; bool overflow = 0; +; +; while (bar(*data)) { +; if (value > 1) { +; result = 2; +; overflow = 1; +; } +; +; if (!overflow) +; value = value + 1; +; } +; +; if (length == 0 || value) { +; if (!overflow) +; result = 0; +; } else { +; result = 1; +; } +; bye: +; *parsing_result = result; +; return result == 0 ? value : 0; +; } +; +; RUN: llc < %s -stop-after=virtregrewriter -o - | FileCheck %s +; +; CHECK-LABEL: {{^body:}} +; CHECK-LABEL: bye.thread21: +; CHECK: DBG_LABEL !14 +; CHECK-LABEL: if.then5: +; CHECK: DBG_LABEL !14 +; CHECK-NOT: DBG_LABEL !14 + +$_Z3barc = comdat any + +; Function Attrs: nounwind uwtable +define dso_local i32 @_Z3fooPKciPi(i8* nocapture readonly %data, i32 %length, i32* nocapture %parsing_result) local_unnamed_addr !dbg !4 { +entry: + %0 = load i8, i8* %data, align 1 + %call23 = tail call zeroext i1 @_Z3barc(i8 signext %0), !dbg !15 + br i1 %call23, label %while.body, label %while.end + +while.body: ; preds = %entry, %while.body + %overflow.026 = phi i8 [ %spec.select18, %while.body ], [ 0, %entry ] + %result.025 = phi i32 [ %spec.select, %while.body ], [ 1, %entry ] + %value.024 = phi i32 [ %value.1, %while.body ], [ 0, %entry ] + %cmp = icmp ugt i32 %value.024, 1 + %spec.select = select i1 %cmp, i32 2, i32 %result.025 + %spec.select18 = select i1 %cmp, i8 1, i8 %overflow.026 + %1 = and i8 %spec.select18, 1 + %2 = xor i8 %1, 1 + %3 = zext i8 %2 to i32 + %value.1 = add i32 %value.024, %3 + %4 = load i8, i8* %data, align 1 + %call = tail call zeroext i1 @_Z3barc(i8 signext %4), !dbg !15 + br i1 %call, label %while.body, label %while.end.loopexit + +while.end.loopexit: ; preds = %while.body + %phitmp = and i8 %spec.select18, 1 + br label %while.end + +while.end: ; preds = %while.end.loopexit, %entry + %value.0.lcssa = phi i32 [ 0, %entry ], [ %value.1, %while.end.loopexit ] + %result.0.lcssa = phi i32 [ 1, %entry ], [ %spec.select, %while.end.loopexit ] + %overflow.0.lcssa = phi i8 [ 0, %entry ], [ %phitmp, %while.end.loopexit ] + %cmp3 = icmp eq i32 %length, 0 + %tobool4 = icmp ne i32 %value.0.lcssa, 0 + %or.cond = or i1 %cmp3, %tobool4 + br i1 %or.cond, label %if.then5, label %bye.thread21 + +bye.thread21: ; preds = %while.end + call void @llvm.dbg.label(metadata !14), !dbg !16 + store i32 1, i32* %parsing_result, align 4 + br label %6 + +if.then5: ; preds = %while.end + %tobool6 = icmp eq i8 %overflow.0.lcssa, 0 + call void @llvm.dbg.label(metadata !14), !dbg !16 + call void @llvm.dbg.label(metadata !14), !dbg !16 + br i1 %tobool6, label %bye.thread, label %bye + +bye.thread: ; preds = %if.then5 + store i32 0, i32* %parsing_result, align 4 + br label %5 + +bye: ; preds = %if.then5 + store i32 %result.0.lcssa, i32* %parsing_result, align 4 + %cmp10 = icmp eq i32 %result.0.lcssa, 0 + br i1 %cmp10, label %5, label %6 + +;