From: Wolfgang Pieb Date: Mon, 4 Feb 2019 20:42:45 +0000 (+0000) Subject: [DEBUGINFO] Reposting r352642: Handle restore instructions in LiveDebugValues X-Git-Tag: llvmorg-10-init~12852 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=90d856cd5f4c4bfe415105f6bfc66f05457a334d;p=platform%2Fupstream%2Fllvm.git [DEBUGINFO] Reposting r352642: Handle restore instructions in LiveDebugValues The LiveDebugValues pass recognizes spills but not restores, which can cause large gaps in location information for some variables, depending on control flow. This patch make LiveDebugValues recognize restores and generate appropriate DBG_VALUE instructions. This patch was posted previously with r352642 and reverted in r352666 due to buildbot errors. A missing return statement was the cause for the failures. Reviewers: aprantl, NicolaPrica Differential Revision: https://reviews.llvm.org/D57271 llvm-svn: 353089 --- diff --git a/llvm/include/llvm/CodeGen/MachineInstr.h b/llvm/include/llvm/CodeGen/MachineInstr.h index 39432f9..352334d 100644 --- a/llvm/include/llvm/CodeGen/MachineInstr.h +++ b/llvm/include/llvm/CodeGen/MachineInstr.h @@ -1399,6 +1399,19 @@ public: /// Return true if all the defs of this instruction are dead. bool allDefsAreDead() const; + /// Return a valid size if the instruction is a spill instruction. + Optional getSpillSize(const TargetInstrInfo *TII) const; + + /// Return a valid size if the instruction is a folded spill instruction. + Optional getFoldedSpillSize(const TargetInstrInfo *TII) const; + + /// Return a valid size if the instruction is a restore instruction. + Optional getRestoreSize(const TargetInstrInfo *TII) const; + + /// Return a valid size if the instruction is a folded restore instruction. + Optional + getFoldedRestoreSize(const TargetInstrInfo *TII) const; + /// Copy implicit register operands from specified /// instruction to this instruction. void copyImplicitOps(MachineFunction &MF, const MachineInstr &MI); diff --git a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp index b8d4466..be666ad 100644 --- a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp @@ -746,41 +746,20 @@ static void emitComments(const MachineInstr &MI, raw_ostream &CommentOS) { const TargetInstrInfo *TII = MF->getSubtarget().getInstrInfo(); // Check for spills and reloads - int FI; - - const MachineFrameInfo &MFI = MF->getFrameInfo(); - - auto getSize = - [&MFI](const SmallVectorImpl &Accesses) { - unsigned Size = 0; - for (auto A : Accesses) - if (MFI.isSpillSlotObjectIndex( - cast(A->getPseudoValue()) - ->getFrameIndex())) - Size += A->getSize(); - return Size; - }; // We assume a single instruction only has a spill or reload, not // both. - const MachineMemOperand *MMO; - SmallVector Accesses; - if (TII->isLoadFromStackSlotPostFE(MI, FI)) { - if (MFI.isSpillSlotObjectIndex(FI)) { - MMO = *MI.memoperands_begin(); - CommentOS << MMO->getSize() << "-byte Reload\n"; - } - } else if (TII->hasLoadFromStackSlot(MI, Accesses)) { - if (auto Size = getSize(Accesses)) - CommentOS << Size << "-byte Folded Reload\n"; - } else if (TII->isStoreToStackSlotPostFE(MI, FI)) { - if (MFI.isSpillSlotObjectIndex(FI)) { - MMO = *MI.memoperands_begin(); - CommentOS << MMO->getSize() << "-byte Spill\n"; - } - } else if (TII->hasStoreToStackSlot(MI, Accesses)) { - if (auto Size = getSize(Accesses)) - CommentOS << Size << "-byte Folded Spill\n"; + Optional Size; + if ((Size = MI.getRestoreSize(TII))) { + CommentOS << *Size << "-byte Reload\n"; + } else if ((Size = MI.getFoldedRestoreSize(TII))) { + if (*Size) + CommentOS << *Size << "-byte Folded Reload\n"; + } else if ((Size = MI.getSpillSize(TII))) { + CommentOS << *Size << "-byte Spill\n"; + } else if ((Size = MI.getFoldedSpillSize(TII))) { + if (*Size) + CommentOS << *Size << "-byte Folded Spill\n"; } // Check for spill-induced copies diff --git a/llvm/lib/CodeGen/LiveDebugValues.cpp b/llvm/lib/CodeGen/LiveDebugValues.cpp index 21791a9..449f10c 100644 --- a/llvm/lib/CodeGen/LiveDebugValues.cpp +++ b/llvm/lib/CodeGen/LiveDebugValues.cpp @@ -34,13 +34,14 @@ #include "llvm/CodeGen/MachineMemOperand.h" #include "llvm/CodeGen/MachineOperand.h" #include "llvm/CodeGen/PseudoSourceValue.h" +#include "llvm/CodeGen/RegisterScavenging.h" #include "llvm/CodeGen/TargetFrameLowering.h" #include "llvm/CodeGen/TargetInstrInfo.h" #include "llvm/CodeGen/TargetLowering.h" #include "llvm/CodeGen/TargetRegisterInfo.h" #include "llvm/CodeGen/TargetSubtargetInfo.h" -#include "llvm/CodeGen/RegisterScavenging.h" #include "llvm/Config/llvm-config.h" +#include "llvm/IR/DIBuilder.h" #include "llvm/IR/DebugInfoMetadata.h" #include "llvm/IR/DebugLoc.h" #include "llvm/IR/Function.h" @@ -85,6 +86,8 @@ private: BitVector CalleeSavedRegs; LexicalScopes LS; + enum struct TransferKind { TransferCopy, TransferSpill, TransferRestore }; + /// Keeps track of lexical scopes associated with a user value's source /// location. class UserValueScopes { @@ -124,15 +127,30 @@ private: /// A pair of debug variable and value location. struct VarLoc { + // The location at which a spilled variable resides. It consists of a + // register and an offset. + struct SpillLoc { + unsigned SpillBase; + int SpillOffset; + bool operator==(const SpillLoc &Other) const { + return SpillBase == Other.SpillBase && SpillOffset == Other.SpillOffset; + } + }; + const DebugVariable Var; const MachineInstr &MI; ///< Only used for cloning a new DBG_VALUE. mutable UserValueScopes UVS; - enum { InvalidKind = 0, RegisterKind } Kind = InvalidKind; + enum VarLocKind { + InvalidKind = 0, + RegisterKind, + SpillLocKind + } Kind = InvalidKind; /// The value location. Stored separately to avoid repeatedly /// extracting it from MI. union { uint64_t RegNo; + SpillLoc SpillLocation; uint64_t Hash; } Loc; @@ -149,6 +167,17 @@ private: } } + /// The constructor for spill locations. + VarLoc(const MachineInstr &MI, unsigned SpillBase, int SpillOffset, + LexicalScopes &LS) + : Var(MI.getDebugVariable(), MI.getDebugLoc()->getInlinedAt()), MI(MI), + UVS(MI.getDebugLoc(), LS) { + assert(MI.isDebugValue() && "not a DBG_VALUE"); + assert(MI.getNumOperands() == 4 && "malformed DBG_VALUE"); + Kind = SpillLocKind; + Loc.SpillLocation = {SpillBase, SpillOffset}; + } + /// If this variable is described by a register, return it, /// otherwise return 0. unsigned isDescribedByReg() const { @@ -236,15 +265,23 @@ private: bool isSpillInstruction(const MachineInstr &MI, MachineFunction *MF, unsigned &Reg); - int extractSpillBaseRegAndOffset(const MachineInstr &MI, unsigned &Reg); + /// If a given instruction is identified as a spill, return the spill location + /// and set \p Reg to the spilled register. + Optional isRestoreInstruction(const MachineInstr &MI, + MachineFunction *MF, + unsigned &Reg); + /// Given a spill instruction, extract the register and offset used to + /// address the spill location in a target independent way. + VarLoc::SpillLoc extractSpillBaseRegAndOffset(const MachineInstr &MI); void insertTransferDebugPair(MachineInstr &MI, OpenRangesSet &OpenRanges, TransferMap &Transfers, VarLocMap &VarLocIDs, - unsigned OldVarID, unsigned NewReg = 0); + unsigned OldVarID, TransferKind Kind, + unsigned NewReg = 0); void transferDebugValue(const MachineInstr &MI, OpenRangesSet &OpenRanges, VarLocMap &VarLocIDs); - void transferSpillInst(MachineInstr &MI, OpenRangesSet &OpenRanges, - VarLocMap &VarLocIDs, TransferMap &Transfers); + void transferSpillOrRestoreInst(MachineInstr &MI, OpenRangesSet &OpenRanges, + VarLocMap &VarLocIDs, TransferMap &Transfers); void transferRegisterCopy(MachineInstr &MI, OpenRangesSet &OpenRanges, VarLocMap &VarLocIDs, TransferMap &Transfers); void transferRegisterDef(MachineInstr &MI, OpenRangesSet &OpenRanges, @@ -338,10 +375,8 @@ void LiveDebugValues::printVarLocInMBB(const MachineFunction &MF, } #endif -/// Given a spill instruction, extract the register and offset used to -/// address the spill location in a target independent way. -int LiveDebugValues::extractSpillBaseRegAndOffset(const MachineInstr &MI, - unsigned &Reg) { +LiveDebugValues::VarLoc::SpillLoc +LiveDebugValues::extractSpillBaseRegAndOffset(const MachineInstr &MI) { assert(MI.hasOneMemOperand() && "Spill instruction does not have exactly one memory operand?"); auto MMOI = MI.memoperands_begin(); @@ -350,7 +385,9 @@ int LiveDebugValues::extractSpillBaseRegAndOffset(const MachineInstr &MI, "Inconsistent memory operand in spill instruction"); int FI = cast(PVal)->getFrameIndex(); const MachineBasicBlock *MBB = MI.getParent(); - return TFI->getFrameIndexReference(*MBB->getParent(), FI, Reg); + unsigned Reg; + int Offset = TFI->getFrameIndexReference(*MBB->getParent(), FI, Reg); + return {Reg, Offset}; } /// End all previous ranges related to @MI and start a new range from @MI @@ -386,11 +423,28 @@ void LiveDebugValues::transferDebugValue(const MachineInstr &MI, /// otherwise it is variable's location on the stack. void LiveDebugValues::insertTransferDebugPair( MachineInstr &MI, OpenRangesSet &OpenRanges, TransferMap &Transfers, - VarLocMap &VarLocIDs, unsigned OldVarID, unsigned NewReg) { + VarLocMap &VarLocIDs, unsigned OldVarID, TransferKind Kind, + unsigned NewReg) { const MachineInstr *DMI = &VarLocIDs[OldVarID].MI; MachineFunction *MF = MI.getParent()->getParent(); MachineInstr *NewDMI; - if (NewReg) { + + auto ProcessVarLoc = [&MI, &OpenRanges, &Transfers, + &VarLocIDs](VarLoc &VL, MachineInstr *NewDMI) { + unsigned LocId = VarLocIDs.insert(VL); + OpenRanges.insert(LocId, VL.Var); + // The newly created DBG_VALUE instruction NewDMI must be inserted after + // MI. Keep track of the pairing. + TransferDebugPair MIP = {&MI, NewDMI}; + Transfers.push_back(MIP); + }; + + // End all previous ranges of Var. + OpenRanges.erase(VarLocIDs[OldVarID].Var); + switch (Kind) { + case TransferKind::TransferCopy: { + assert(NewReg && + "No register supplied when handling a copy of a debug value"); // Create a DBG_VALUE instruction to describe the Var in its new // register location. NewDMI = BuildMI(*MF, DMI->getDebugLoc(), DMI->getDesc(), @@ -398,33 +452,43 @@ void LiveDebugValues::insertTransferDebugPair( DMI->getDebugVariable(), DMI->getDebugExpression()); if (DMI->isIndirectDebugValue()) NewDMI->getOperand(1).setImm(DMI->getOperand(1).getImm()); + VarLoc VL(*NewDMI, LS); + ProcessVarLoc(VL, NewDMI); LLVM_DEBUG(dbgs() << "Creating DBG_VALUE inst for register copy: "; NewDMI->print(dbgs(), false, false, false, TII)); - } else { + return; + } + case TransferKind::TransferSpill: { // Create a DBG_VALUE instruction to describe the Var in its spilled // location. - unsigned SpillBase; - int SpillOffset = extractSpillBaseRegAndOffset(MI, SpillBase); - auto *SpillExpr = DIExpression::prepend(DMI->getDebugExpression(), - DIExpression::NoDeref, SpillOffset); - NewDMI = BuildMI(*MF, DMI->getDebugLoc(), DMI->getDesc(), true, SpillBase, - DMI->getDebugVariable(), SpillExpr); + VarLoc::SpillLoc SpillLocation = extractSpillBaseRegAndOffset(MI); + auto *SpillExpr = + DIExpression::prepend(DMI->getDebugExpression(), DIExpression::NoDeref, + SpillLocation.SpillOffset); + NewDMI = + BuildMI(*MF, DMI->getDebugLoc(), DMI->getDesc(), true, + SpillLocation.SpillBase, DMI->getDebugVariable(), SpillExpr); + VarLoc VL(*NewDMI, SpillLocation.SpillBase, SpillLocation.SpillOffset, LS); + ProcessVarLoc(VL, NewDMI); LLVM_DEBUG(dbgs() << "Creating DBG_VALUE inst for spill: "; NewDMI->print(dbgs(), false, false, false, TII)); + return; } - - // The newly created DBG_VALUE instruction NewDMI must be inserted after - // MI. Keep track of the pairing. - TransferDebugPair MIP = {&MI, NewDMI}; - Transfers.push_back(MIP); - - // End all previous ranges of Var. - OpenRanges.erase(VarLocIDs[OldVarID].Var); - - // Add the VarLoc to OpenRanges. - VarLoc VL(*NewDMI, LS); - unsigned LocID = VarLocIDs.insert(VL); - OpenRanges.insert(LocID, VL.Var); + case TransferKind::TransferRestore: { + assert(NewReg && + "No register supplied when handling a restore of a debug value"); + MachineFunction *MF = MI.getMF(); + DIBuilder DIB(*const_cast(MF->getFunction()).getParent()); + NewDMI = BuildMI(*MF, DMI->getDebugLoc(), DMI->getDesc(), false, NewReg, + DMI->getDebugVariable(), DIB.createExpression()); + VarLoc VL(*NewDMI, LS); + ProcessVarLoc(VL, NewDMI); + LLVM_DEBUG(dbgs() << "Creating DBG_VALUE inst for register restore: "; + NewDMI->print(dbgs(), false, false, false, TII)); + return; + } + } + llvm_unreachable("Invalid transfer kind"); } /// A definition of a register may mark the end of a range. @@ -470,24 +534,15 @@ void LiveDebugValues::transferRegisterDef(MachineInstr &MI, /// other spills). We do not handle this yet (more than one memory operand). bool LiveDebugValues::isSpillInstruction(const MachineInstr &MI, MachineFunction *MF, unsigned &Reg) { - const MachineFrameInfo &FrameInfo = MF->getFrameInfo(); - int FI; SmallVector Accesses; // TODO: Handle multiple stores folded into one. if (!MI.hasOneMemOperand()) return false; - // To identify a spill instruction, use the same criteria as in AsmPrinter. - if (!((TII->isStoreToStackSlotPostFE(MI, FI) && - FrameInfo.isSpillSlotObjectIndex(FI)) || - (TII->hasStoreToStackSlot(MI, Accesses) && - llvm::any_of(Accesses, [&FrameInfo](const MachineMemOperand *MMO) { - return FrameInfo.isSpillSlotObjectIndex( - cast(MMO->getPseudoValue()) - ->getFrameIndex()); - })))) - return false; + if (!MI.getSpillSize(TII) && !MI.getFoldedSpillSize(TII)) + return false; // This is not a spill instruction, since no valid size was + // returned from either function. auto isKilledReg = [&](const MachineOperand MO, unsigned &Reg) { if (!MO.isReg() || !MO.isUse()) { @@ -524,29 +579,67 @@ bool LiveDebugValues::isSpillInstruction(const MachineInstr &MI, return false; } +Optional +LiveDebugValues::isRestoreInstruction(const MachineInstr &MI, + MachineFunction *MF, unsigned &Reg) { + if (!MI.hasOneMemOperand()) + return None; + + // FIXME: Handle folded restore instructions with more than one memory + // operand. + if (MI.getRestoreSize(TII)) { + Reg = MI.getOperand(0).getReg(); + return extractSpillBaseRegAndOffset(MI); + } + return None; +} + /// A spilled register may indicate that we have to end the current range of /// a variable and create a new one for the spill location. +/// A restored register may indicate the reverse situation. /// We don't want to insert any instructions in process(), so we just create /// the DBG_VALUE without inserting it and keep track of it in \p Transfers. /// It will be inserted into the BB when we're done iterating over the /// instructions. -void LiveDebugValues::transferSpillInst(MachineInstr &MI, - OpenRangesSet &OpenRanges, - VarLocMap &VarLocIDs, - TransferMap &Transfers) { - unsigned Reg; +void LiveDebugValues::transferSpillOrRestoreInst(MachineInstr &MI, + OpenRangesSet &OpenRanges, + VarLocMap &VarLocIDs, + TransferMap &Transfers) { MachineFunction *MF = MI.getMF(); - if (!isSpillInstruction(MI, MF, Reg)) - return; + TransferKind TKind; + unsigned Reg; + Optional Loc; - // Check if the register is the location of a debug value. + LLVM_DEBUG(dbgs() << "Examining instruction: "; MI.dump();); + + if (isSpillInstruction(MI, MF, Reg)) { + TKind = TransferKind::TransferSpill; + LLVM_DEBUG(dbgs() << "Recognized as spill: "; MI.dump();); + LLVM_DEBUG(dbgs() << "Register: " << Reg << " " << printReg(Reg, TRI) + << "\n"); + } else { + if (!(Loc = isRestoreInstruction(MI, MF, Reg))) + return; + TKind = TransferKind::TransferRestore; + LLVM_DEBUG(dbgs() << "Recognized as restore: "; MI.dump();); + LLVM_DEBUG(dbgs() << "Register: " << Reg << " " << printReg(Reg, TRI) + << "\n"); + } + // Check if the register or spill location is the location of a debug value. for (unsigned ID : OpenRanges.getVarLocs()) { - if (VarLocIDs[ID].isDescribedByReg() == Reg) { + if (TKind == TransferKind::TransferSpill && + VarLocIDs[ID].isDescribedByReg() == Reg) { LLVM_DEBUG(dbgs() << "Spilling Register " << printReg(Reg, TRI) << '(' << VarLocIDs[ID].Var.getVar()->getName() << ")\n"); - insertTransferDebugPair(MI, OpenRanges, Transfers, VarLocIDs, ID); - return; - } + } else if (TKind == TransferKind::TransferRestore && + VarLocIDs[ID].Loc.SpillLocation == *Loc) { + LLVM_DEBUG(dbgs() << "Restoring Register " << printReg(Reg, TRI) << '(' + << VarLocIDs[ID].Var.getVar()->getName() << ")\n"); + } else + continue; + insertTransferDebugPair(MI, OpenRanges, Transfers, VarLocIDs, ID, TKind, + Reg); + return; } } @@ -584,7 +677,7 @@ void LiveDebugValues::transferRegisterCopy(MachineInstr &MI, for (unsigned ID : OpenRanges.getVarLocs()) { if (VarLocIDs[ID].isDescribedByReg() == SrcReg) { insertTransferDebugPair(MI, OpenRanges, Transfers, VarLocIDs, ID, - DestReg); + TransferKind::TransferCopy, DestReg); return; } } @@ -624,7 +717,7 @@ bool LiveDebugValues::process(MachineInstr &MI, OpenRangesSet &OpenRanges, transferRegisterDef(MI, OpenRanges, VarLocIDs); if (transferChanges) { transferRegisterCopy(MI, OpenRanges, VarLocIDs, Transfers); - transferSpillInst(MI, OpenRanges, VarLocIDs, Transfers); + transferSpillOrRestoreInst(MI, OpenRanges, VarLocIDs, Transfers); } Changed = transferTerminatorInst(MI, OpenRanges, OutLocs, VarLocIDs); return Changed; diff --git a/llvm/lib/CodeGen/MachineInstr.cpp b/llvm/lib/CodeGen/MachineInstr.cpp index ca43804..7ef931a 100644 --- a/llvm/lib/CodeGen/MachineInstr.cpp +++ b/llvm/lib/CodeGen/MachineInstr.cpp @@ -25,6 +25,7 @@ #include "llvm/Analysis/MemoryLocation.h" #include "llvm/CodeGen/GlobalISel/RegisterBank.h" #include "llvm/CodeGen/MachineBasicBlock.h" +#include "llvm/CodeGen/MachineFrameInfo.h" #include "llvm/CodeGen/MachineFunction.h" #include "llvm/CodeGen/MachineInstrBuilder.h" #include "llvm/CodeGen/MachineInstrBundle.h" @@ -49,9 +50,9 @@ #include "llvm/IR/Metadata.h" #include "llvm/IR/Module.h" #include "llvm/IR/ModuleSlotTracker.h" +#include "llvm/IR/Operator.h" #include "llvm/IR/Type.h" #include "llvm/IR/Value.h" -#include "llvm/IR/Operator.h" #include "llvm/MC/MCInstrDesc.h" #include "llvm/MC/MCRegisterInfo.h" #include "llvm/MC/MCSymbol.h" @@ -2102,3 +2103,54 @@ void MachineInstr::changeDebugValuesDefReg(unsigned Reg) { for (auto *DBI : DbgValues) DBI->getOperand(0).setReg(Reg); } + +using MMOList = SmallVector; + +static unsigned getSpillSlotSize(MMOList &Accesses, + const MachineFrameInfo &MFI) { + unsigned Size = 0; + for (auto A : Accesses) + if (MFI.isSpillSlotObjectIndex( + cast(A->getPseudoValue()) + ->getFrameIndex())) + Size += A->getSize(); + return Size; +} + +Optional +MachineInstr::getSpillSize(const TargetInstrInfo *TII) const { + int FI; + if (TII->isStoreToStackSlotPostFE(*this, FI)) { + const MachineFrameInfo &MFI = getMF()->getFrameInfo(); + if (MFI.isSpillSlotObjectIndex(FI)) + return (*memoperands_begin())->getSize(); + } + return None; +} + +Optional +MachineInstr::getFoldedSpillSize(const TargetInstrInfo *TII) const { + MMOList Accesses; + if (TII->hasStoreToStackSlot(*this, Accesses)) + return getSpillSlotSize(Accesses, getMF()->getFrameInfo()); + return None; +} + +Optional +MachineInstr::getRestoreSize(const TargetInstrInfo *TII) const { + int FI; + if (TII->isLoadFromStackSlotPostFE(*this, FI)) { + const MachineFrameInfo &MFI = getMF()->getFrameInfo(); + if (MFI.isSpillSlotObjectIndex(FI)) + return (*memoperands_begin())->getSize(); + } + return None; +} + +Optional +MachineInstr::getFoldedRestoreSize(const TargetInstrInfo *TII) const { + MMOList Accesses; + if (TII->hasLoadFromStackSlot(*this, Accesses)) + return getSpillSlotSize(Accesses, getMF()->getFrameInfo()); + return None; +} diff --git a/llvm/test/DebugInfo/MIR/X86/live-debug-values-restore.mir b/llvm/test/DebugInfo/MIR/X86/live-debug-values-restore.mir new file mode 100644 index 0000000..6263281 --- /dev/null +++ b/llvm/test/DebugInfo/MIR/X86/live-debug-values-restore.mir @@ -0,0 +1,189 @@ +# RUN: llc -run-pass livedebugvalues -march=x86-64 -o - %s | FileCheck %s + +# Generated from the following source with: +# clang -g -mllvm -stop-before=livedebugvalues -S -O2 test.c -o test.mir + +# #define FORCE_SPILL() \ +# __asm volatile("" : : : \ +# "rax", "rbx", "rcx", "rdx", "rsi", "rdi", "rbp", "r8", \ +# "r9", "r10", "r11", "r12", "r13", "r14", "r15") +# int f(int *p) { +# if (p) { +# FORCE_SPILL(); +# } +# return *(p + 1); +# } + +# Ascertain that the spill has been recognized and manifested in a DBG_VALUE. +# CHECK: MOV64mr $rsp,{{.*-8.*}}killed{{.*}}$rdi :: (store 8 into %stack.0) +# CHECK-NEXT: DBG_VALUE $rsp,{{.*}}![[MDIX:[0-9]+]],{{.*}}!DIExpression(DW_OP_constu, 8, DW_OP_minus) + +# Check for the restore. +# CHECK: $rdi = MOV64rm $rsp,{{.*-8.*}}:: (load 8 from %stack.0) +# CHECK-NEXT: DBG_VALUE $rdi,{{.*}}![[MDIX]], !DIExpression() + +--- | + define dso_local i32 @f(i32* readonly %p) local_unnamed_addr !dbg !7 { + entry: + call void @llvm.dbg.value(metadata i32* %p, metadata !13, metadata !DIExpression()), !dbg !14 + %tobool = icmp eq i32* %p, null, !dbg !15 + br i1 %tobool, label %if.end, label %if.then, !dbg !17 + + if.then: ; preds = %entry + tail call void asm sideeffect "", "~{rax},~{rbx},~{rcx},~{rdx},~{rsi},~{rdi},~{rbp},~{r8},~{r9},~{r10},~{r11},~{r12},~{r13},~{r14},~{r15},~{dirflag},~{fpsr},~{flags}"(), !dbg !18, !srcloc !20 + br label %if.end, !dbg !21 + + if.end: ; preds = %entry, %if.then + %add.ptr = getelementptr inbounds i32, i32* %p, i64 1, !dbg !22 + %0 = load i32, i32* %add.ptr, align 4, !dbg !23, !tbaa !24 + ret i32 %0, !dbg !28 + } + + declare void @llvm.dbg.value(metadata, metadata, metadata) + + !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 (https://git.llvm.org/git/clang.git/ 57a6ce7ac318de98e3e777e09cb9ed8282b5cc03) (https://git.llvm.org/git/llvm.git/ ff54a19e4912d7f15cb02798a7f2048441bff751)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: None) + !1 = !DIFile(filename: "test2.c", directory: "/home/test") + !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 (https://git.llvm.org/git/clang.git/ 57a6ce7ac318de98e3e777e09cb9ed8282b5cc03) (https://git.llvm.org/git/llvm.git/ ff54a19e4912d7f15cb02798a7f2048441bff751)"} + !7 = distinct !DISubprogram(name: "f", scope: !1, file: !1, line: 5, type: !8, scopeLine: 5, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !12) + !8 = !DISubroutineType(types: !9) + !9 = !{!10, !11} + !10 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) + !11 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !10, size: 64) + !12 = !{!13} + !13 = !DILocalVariable(name: "p", arg: 1, scope: !7, file: !1, line: 5, type: !11) + !14 = !DILocation(line: 5, column: 12, scope: !7) + !15 = !DILocation(line: 6, column: 7, scope: !16) + !16 = distinct !DILexicalBlock(scope: !7, file: !1, line: 6, column: 7) + !17 = !DILocation(line: 6, column: 7, scope: !7) + !18 = !DILocation(line: 7, column: 5, scope: !19) + !19 = distinct !DILexicalBlock(scope: !16, file: !1, line: 6, column: 10) + !20 = !{i32 -2147471544} + !21 = !DILocation(line: 8, column: 3, scope: !19) + !22 = !DILocation(line: 9, column: 14, scope: !7) + !23 = !DILocation(line: 9, column: 10, scope: !7) + !24 = !{!25, !25, i64 0} + !25 = !{!"int", !26, i64 0} + !26 = !{!"omnipotent char", !27, i64 0} + !27 = !{!"Simple C/C++ TBAA"} + !28 = !DILocation(line: 9, column: 3, scope: !7) + +... +--- +name: f +alignment: 4 +exposesReturnsTwice: false +legalized: false +regBankSelected: false +selected: false +failedISel: false +tracksRegLiveness: true +hasWinCFI: false +registers: [] +liveins: + - { reg: '$rdi', virtual-reg: '' } +frameInfo: + isFrameAddressTaken: false + isReturnAddressTaken: false + hasStackMap: false + hasPatchPoint: false + stackSize: 48 + offsetAdjustment: -48 + maxAlignment: 8 + adjustsStack: false + hasCalls: false + stackProtector: '' + maxCallFrameSize: 0 + cvBytesOfCalleeSavedRegisters: 48 + hasOpaqueSPAdjustment: false + hasVAStart: false + hasMustTailInVarArgFunc: false + localFrameSize: 0 + savePoint: '' + restorePoint: '' +fixedStack: + - { id: 0, type: spill-slot, offset: -56, size: 8, alignment: 8, stack-id: 0, + callee-saved-register: '$rbx', callee-saved-restored: true, debug-info-variable: '', + debug-info-expression: '', debug-info-location: '' } + - { id: 1, type: spill-slot, offset: -48, size: 8, alignment: 16, stack-id: 0, + callee-saved-register: '$r12', callee-saved-restored: true, debug-info-variable: '', + debug-info-expression: '', debug-info-location: '' } + - { id: 2, type: spill-slot, offset: -40, size: 8, alignment: 8, stack-id: 0, + callee-saved-register: '$r13', callee-saved-restored: true, debug-info-variable: '', + debug-info-expression: '', debug-info-location: '' } + - { id: 3, type: spill-slot, offset: -32, size: 8, alignment: 16, stack-id: 0, + callee-saved-register: '$r14', callee-saved-restored: true, debug-info-variable: '', + debug-info-expression: '', debug-info-location: '' } + - { id: 4, type: spill-slot, offset: -24, size: 8, alignment: 8, stack-id: 0, + callee-saved-register: '$r15', callee-saved-restored: true, debug-info-variable: '', + debug-info-expression: '', debug-info-location: '' } + - { id: 5, type: spill-slot, offset: -16, size: 8, alignment: 16, stack-id: 0, + callee-saved-register: '$rbp', callee-saved-restored: true, debug-info-variable: '', + debug-info-expression: '', debug-info-location: '' } +stack: + - { id: 0, name: '', type: spill-slot, offset: -64, size: 8, alignment: 8, + stack-id: 0, callee-saved-register: '', callee-saved-restored: true, + debug-info-variable: '', debug-info-expression: '', debug-info-location: '' } +constants: [] +body: | + bb.0.entry: + successors: %bb.2(0x30000000), %bb.1(0x50000000) + liveins: $rdi, $rbx, $r12, $r13, $r14, $r15, $rbp + + DBG_VALUE $rdi, $noreg, !13, !DIExpression(), debug-location !14 + DBG_VALUE $rdi, $noreg, !13, !DIExpression(), debug-location !14 + TEST64rr renamable $rdi, renamable $rdi, implicit-def $eflags, debug-location !15 + JE_1 %bb.2, implicit $eflags, debug-location !17 + + bb.1.if.then: + successors: %bb.2(0x80000000) + liveins: $rdi, $rbp, $r15, $r14, $r13, $r12, $rbx + + frame-setup PUSH64r killed $rbp, implicit-def $rsp, implicit $rsp + CFI_INSTRUCTION def_cfa_offset 16 + frame-setup PUSH64r killed $r15, implicit-def $rsp, implicit $rsp + CFI_INSTRUCTION def_cfa_offset 24 + frame-setup PUSH64r killed $r14, implicit-def $rsp, implicit $rsp + CFI_INSTRUCTION def_cfa_offset 32 + frame-setup PUSH64r killed $r13, implicit-def $rsp, implicit $rsp + CFI_INSTRUCTION def_cfa_offset 40 + frame-setup PUSH64r killed $r12, implicit-def $rsp, implicit $rsp + CFI_INSTRUCTION def_cfa_offset 48 + frame-setup PUSH64r killed $rbx, implicit-def $rsp, implicit $rsp + CFI_INSTRUCTION def_cfa_offset 56 + CFI_INSTRUCTION offset $rbx, -56 + CFI_INSTRUCTION offset $r12, -48 + CFI_INSTRUCTION offset $r13, -40 + CFI_INSTRUCTION offset $r14, -32 + CFI_INSTRUCTION offset $r15, -24 + CFI_INSTRUCTION offset $rbp, -16 + MOV64mr $rsp, 1, $noreg, -8, $noreg, killed renamable $rdi :: (store 8 into %stack.0) + INLINEASM &"", 1, 12, implicit-def dead early-clobber $rax, 12, implicit-def dead early-clobber $rbx, 12, implicit-def dead early-clobber $rcx, 12, implicit-def dead early-clobber $rdx, 12, implicit-def dead early-clobber $rsi, 12, implicit-def dead early-clobber $rdi, 12, implicit-def dead early-clobber $rbp, 12, implicit-def dead early-clobber $r8, 12, implicit-def dead early-clobber $r9, 12, implicit-def dead early-clobber $r10, 12, implicit-def dead early-clobber $r11, 12, implicit-def dead early-clobber $r12, 12, implicit-def dead early-clobber $r13, 12, implicit-def dead early-clobber $r14, 12, implicit-def dead early-clobber $r15, 12, implicit-def dead early-clobber $eflags, !20, debug-location !18 + renamable $rdi = MOV64rm $rsp, 1, $noreg, -8, $noreg :: (load 8 from %stack.0) + $rbx = frame-destroy POP64r implicit-def $rsp, implicit $rsp + CFI_INSTRUCTION def_cfa_offset 48 + $r12 = frame-destroy POP64r implicit-def $rsp, implicit $rsp + CFI_INSTRUCTION def_cfa_offset 40 + $r13 = frame-destroy POP64r implicit-def $rsp, implicit $rsp + CFI_INSTRUCTION def_cfa_offset 32 + $r14 = frame-destroy POP64r implicit-def $rsp, implicit $rsp + CFI_INSTRUCTION def_cfa_offset 24 + $r15 = frame-destroy POP64r implicit-def $rsp, implicit $rsp + CFI_INSTRUCTION def_cfa_offset 16 + $rbp = frame-destroy POP64r implicit-def $rsp, implicit $rsp + CFI_INSTRUCTION def_cfa_offset 8 + + bb.2.if.end: + liveins: $rdi, $rbx, $r12, $r13, $r14, $r15, $rbp + + renamable $eax = MOV32rm killed renamable $rdi, 1, $noreg, 4, $noreg, debug-location !23 :: (load 4 from %ir.add.ptr, !tbaa !24) + RETQ $eax, debug-location !28 + +...