diff options
Diffstat (limited to 'llvm/lib')
| -rw-r--r-- | llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp | 108 | ||||
| -rw-r--r-- | llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.h | 29 | ||||
| -rw-r--r-- | llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp | 212 | ||||
| -rw-r--r-- | llvm/lib/CodeGen/AsmPrinter/DwarfDebug.h | 19 | ||||
| -rw-r--r-- | llvm/lib/CodeGen/AsmPrinter/DwarfExpression.cpp | 35 | ||||
| -rw-r--r-- | llvm/lib/CodeGen/AsmPrinter/DwarfExpression.h | 11 | ||||
| -rw-r--r-- | llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp | 4 | ||||
| -rw-r--r-- | llvm/lib/CodeGen/AsmPrinter/DwarfUnit.h | 2 | ||||
| -rw-r--r-- | llvm/lib/CodeGen/TargetInstrInfo.cpp | 31 | ||||
| -rw-r--r-- | llvm/lib/CodeGen/TargetRegisterInfo.cpp | 13 | ||||
| -rw-r--r-- | llvm/lib/DebugInfo/DWARF/DWARFDie.cpp | 1 | ||||
| -rw-r--r-- | llvm/lib/IR/DebugInfoMetadata.cpp | 19 | ||||
| -rw-r--r-- | llvm/lib/Target/X86/X86InstrInfo.cpp | 88 | ||||
| -rw-r--r-- | llvm/lib/Target/X86/X86InstrInfo.h | 3 | 
14 files changed, 529 insertions, 46 deletions
diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp index 9548ad9918c..053f10f05b7 100644 --- a/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp @@ -892,32 +892,106 @@ void DwarfCompileUnit::constructAbstractSubprogramScopeDIE(      ContextCU->addDIEEntry(*AbsDef, dwarf::DW_AT_object_pointer, *ObjectPointer);  } -DIE &DwarfCompileUnit::constructCallSiteEntryDIE(DIE &ScopeDIE, -                                                 const DISubprogram &CalleeSP, -                                                 bool IsTail, -                                                 const MCExpr *PCOffset) { -  // Insert a call site entry DIE within ScopeDIE. -  DIE &CallSiteDIE = -      createAndAddDIE(dwarf::DW_TAG_call_site, ScopeDIE, nullptr); +dwarf::Tag DwarfCompileUnit::getDwarf5OrGNUCallSiteTag(dwarf::Tag Tag) const { +  bool ApplyGNUExtensions = DD->getDwarfVersion() == 4 && DD->tuneForGDB(); +  if (!ApplyGNUExtensions) +    return Tag; +  switch (Tag) { +  case dwarf::DW_TAG_call_site: +    return dwarf::DW_TAG_GNU_call_site; +  case dwarf::DW_TAG_call_site_parameter: +    return dwarf::DW_TAG_GNU_call_site_parameter; +  default: +    llvm_unreachable("unhandled call site tag"); +  } +} -  // For the purposes of showing tail call frames in backtraces, a key piece of -  // information is DW_AT_call_origin, a pointer to the callee DIE. -  DIE *CalleeDIE = getOrCreateSubprogramDIE(&CalleeSP); -  assert(CalleeDIE && "Could not create DIE for call site entry origin"); -  addDIEEntry(CallSiteDIE, dwarf::DW_AT_call_origin, *CalleeDIE); +dwarf::Attribute +DwarfCompileUnit::getDwarf5OrGNUCallSiteAttr(dwarf::Attribute Attr) const { +  bool ApplyGNUExtensions = DD->getDwarfVersion() == 4 && DD->tuneForGDB(); +  if (!ApplyGNUExtensions) +    return Attr; +  switch (Attr) { +  case dwarf::DW_AT_call_all_calls: +    return dwarf::DW_AT_GNU_all_call_sites; +  case dwarf::DW_AT_call_target: +    return dwarf::DW_AT_GNU_call_site_target; +  case dwarf::DW_AT_call_origin: +    return dwarf::DW_AT_abstract_origin; +  case dwarf::DW_AT_call_pc: +    return dwarf::DW_AT_low_pc; +  case dwarf::DW_AT_call_value: +    return dwarf::DW_AT_GNU_call_site_value; +  case dwarf::DW_AT_call_tail_call: +    return dwarf::DW_AT_GNU_tail_call; +  default: +    llvm_unreachable("unhandled call site attribute"); +  } +} -  if (IsTail) { -    // Attach DW_AT_call_tail_call to tail calls for standards compliance. -    addFlag(CallSiteDIE, dwarf::DW_AT_call_tail_call); +DIE &DwarfCompileUnit::constructCallSiteEntryDIE( +    DIE &ScopeDIE, const DISubprogram *CalleeSP, bool IsTail, +    const MCSymbol *PCAddr, const MCExpr *PCOffset, unsigned CallReg) { +  // Insert a call site entry DIE within ScopeDIE. +  DIE &CallSiteDIE = createAndAddDIE( +      getDwarf5OrGNUCallSiteTag(dwarf::DW_TAG_call_site), ScopeDIE, nullptr); + +  if (CallReg) { +    // Indirect call. +    addAddress(CallSiteDIE, +               getDwarf5OrGNUCallSiteAttr(dwarf::DW_AT_call_target), +               MachineLocation(CallReg));    } else { -    // Attach the return PC to allow the debugger to disambiguate call paths -    // from one function to another. +    DIE *CalleeDIE = getOrCreateSubprogramDIE(CalleeSP); +    assert(CalleeDIE && "Could not create DIE for call site entry origin"); +    addDIEEntry(CallSiteDIE, +                getDwarf5OrGNUCallSiteAttr(dwarf::DW_AT_call_origin), +                *CalleeDIE); +  } + +  if (IsTail) +    // Attach DW_AT_call_tail_call to tail calls for standards compliance. +    addFlag(CallSiteDIE, +            getDwarf5OrGNUCallSiteAttr(dwarf::DW_AT_call_tail_call)); + +  // Attach the return PC to allow the debugger to disambiguate call paths +  // from one function to another. +  if (DD->getDwarfVersion() == 4 && DD->tuneForGDB()) { +    assert(PCAddr && "Missing PC information for a call"); +    addLabelAddress(CallSiteDIE, dwarf::DW_AT_low_pc, PCAddr); +  } else if (!IsTail || DD->tuneForGDB()) {      assert(PCOffset && "Missing return PC information for a call");      addAddressExpr(CallSiteDIE, dwarf::DW_AT_call_return_pc, PCOffset);    } +    return CallSiteDIE;  } +void DwarfCompileUnit::constructCallSiteParmEntryDIEs( +    DIE &CallSiteDIE, SmallVector<DbgCallSiteParam, 4> &Params) { +  for (const auto &Param : Params) { +    unsigned Register = Param.getRegister(); +    auto CallSiteDieParam = +        DIE::get(DIEValueAllocator, +                 getDwarf5OrGNUCallSiteTag(dwarf::DW_TAG_call_site_parameter)); +    insertDIE(CallSiteDieParam); +    addAddress(*CallSiteDieParam, dwarf::DW_AT_location, +               MachineLocation(Register)); + +    DIELoc *Loc = new (DIEValueAllocator) DIELoc; +    DIEDwarfExpression DwarfExpr(*Asm, *this, *Loc); +    DwarfExpr.setCallSiteParamValueFlag(); + +    DwarfDebug::emitDebugLocValue(*Asm, nullptr, Param.getValue(), DwarfExpr); + +    addBlock(*CallSiteDieParam, +             getDwarf5OrGNUCallSiteAttr(dwarf::DW_AT_call_value), +             DwarfExpr.finalize()); + +    CallSiteDIE.addChild(CallSiteDieParam); +  } +} +  DIE *DwarfCompileUnit::constructImportedEntityDIE(      const DIImportedEntity *Module) {    DIE *IMDie = DIE::get(DIEValueAllocator, (dwarf::Tag)Module->getTag()); diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.h b/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.h index ea980dfda17..bf643c01007 100644 --- a/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.h +++ b/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.h @@ -227,12 +227,33 @@ public:    void constructAbstractSubprogramScopeDIE(LexicalScope *Scope); +  /// This takes the official DWARF 5 tag and returns the appropriate +  /// GNU tag if needed. +  dwarf::Tag getDwarf5OrGNUCallSiteTag(dwarf::Tag Tag) const; +  /// This takes the official DWARF 5 attribute and returns the appropriate +  /// GNU attribute if needed. +  dwarf::Attribute getDwarf5OrGNUCallSiteAttr(dwarf::Attribute Attr) const; +    /// Construct a call site entry DIE describing a call within \p Scope to a -  /// callee described by \p CalleeSP. \p IsTail specifies whether the call is -  /// a tail call. \p PCOffset must be non-zero for non-tail calls or be the +  /// callee described by \p CalleeSP. +  /// \p IsTail specifies whether the call is a tail call. +  /// \p PCAddr (used for GDB + DWARF 4 tuning) points to the PC value after +  /// the call instruction. +  /// \p PCOffset (used for cases other than GDB + DWARF 4 tuning) must be +  /// non-zero for non-tail calls (in the case of non-gdb tuning, since for +  /// GDB + DWARF 5 tuning we still generate PC info for tail calls) or be the    /// function-local offset to PC value after the call instruction. -  DIE &constructCallSiteEntryDIE(DIE &ScopeDIE, const DISubprogram &CalleeSP, -                                 bool IsTail, const MCExpr *PCOffset); +  /// \p CallReg is a register location for an indirect call. For direct calls +  /// the \p CallReg is set to 0. +  DIE &constructCallSiteEntryDIE(DIE &ScopeDIE, const DISubprogram *CalleeSP, +                                 bool IsTail, const MCSymbol *PCAddr, +                                 const MCExpr *PCOffset, unsigned CallReg); +  /// Construct call site parameter DIEs for the \p CallSiteDIE. The \p Params +  /// were collected by the \ref collectCallSiteParameters. +  /// Note: The order of parameters does not matter, since debuggers recognize +  ///       call site parameters by the DW_AT_location attribute. +  void constructCallSiteParmEntryDIEs(DIE &CallSiteDIE, +                                      SmallVector<DbgCallSiteParam, 4> &Params);    /// Construct import_module DIE.    DIE *constructImportedEntityDIE(const DIImportedEntity *Module); diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp index 71bb2b0858c..72792c8b3d5 100644 --- a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp @@ -26,6 +26,7 @@  #include "llvm/ADT/STLExtras.h"  #include "llvm/ADT/SmallVector.h"  #include "llvm/ADT/StringRef.h" +#include "llvm/ADT/Statistic.h"  #include "llvm/ADT/Triple.h"  #include "llvm/ADT/Twine.h"  #include "llvm/BinaryFormat/Dwarf.h" @@ -39,6 +40,7 @@  #include "llvm/CodeGen/MachineModuleInfo.h"  #include "llvm/CodeGen/MachineOperand.h"  #include "llvm/CodeGen/TargetInstrInfo.h" +#include "llvm/CodeGen/TargetLowering.h"  #include "llvm/CodeGen/TargetRegisterInfo.h"  #include "llvm/CodeGen/TargetSubtargetInfo.h"  #include "llvm/DebugInfo/DWARF/DWARFExpression.h" @@ -83,6 +85,8 @@ using namespace llvm;  #define DEBUG_TYPE "dwarfdebug" +STATISTIC(NumCSParams, "Number of dbg call site params created"); +  static cl::opt<bool>  DisableDebugInfoPrinting("disable-debug-info-print", cl::Hidden,                           cl::desc("Disable debug info printing")); @@ -551,6 +555,146 @@ void DwarfDebug::constructAbstractSubprogramScopeDIE(DwarfCompileUnit &SrcCU,    }  } +/// Try to interpret values loaded into registers that forward parameters +/// for \p CallMI. Store parameters with interpreted value into \p Params. +static void collectCallSiteParameters(const MachineInstr *CallMI, +                                      ParamSet &Params) { +  auto *MF = CallMI->getMF(); +  auto CalleesMap = MF->getCallSitesInfo(); +  auto CallFwdRegsInfo = CalleesMap.find(CallMI); + +  // There is no information for the call instruction. +  if (CallFwdRegsInfo == CalleesMap.end()) +    return; + +  auto *MBB = CallMI->getParent(); +  const auto &TRI = MF->getSubtarget().getRegisterInfo(); +  const auto &TII = MF->getSubtarget().getInstrInfo(); +  const auto &TLI = MF->getSubtarget().getTargetLowering(); + +  // Skip the call instruction. +  auto I = std::next(CallMI->getReverseIterator()); + +  DenseSet<unsigned> ForwardedRegWorklist; +  // Add all the forwarding registers into the ForwardedRegWorklist. +  for (auto ArgReg : CallFwdRegsInfo->second) { +    bool InsertedReg = ForwardedRegWorklist.insert(ArgReg.Reg).second; +    assert(InsertedReg && "Single register used to forward two arguments?"); +  } + +  // We erase, from the ForwardedRegWorklist, those forwarding registers for +  // which we successfully describe a loaded value (by using +  // the describeLoadedValue()). For those remaining arguments in the working +  // list, for which we do not describe a loaded value by +  // the describeLoadedValue(), we try to generate an entry value expression +  // for their call site value desctipion, if the call is within the entry MBB. +  // The RegsForEntryValues maps a forwarding register into the register holding +  // the entry value. +  // TODO: Handle situations when call site parameter value can be described +  // as the entry value within basic blocks other then the first one. +  bool ShouldTryEmitEntryVals = MBB->getIterator() == MF->begin(); +  DenseMap<unsigned, unsigned> RegsForEntryValues; + +  // If the MI is an instruction defining a parameter's forwarding register, +  // add it into the Defs. If the MI clobbers more then one register, we use +  // the Defs in order to remove all the registers from +  // the ForwardedRegWorklist, since we do not support such situations now. +  auto getForwardingRegsDefinedByMI = [&](const MachineInstr &MI, +                                         SmallVectorImpl<unsigned> &Defs) { +    if (MI.isDebugInstr()) +      return; + +    for (const MachineOperand &MO : MI.operands()) { +      if (MO.isReg() && MO.isDef() && TRI->isPhysicalRegister(MO.getReg())) { +        for (auto FwdReg : ForwardedRegWorklist) { +          if (TRI->regsOverlap(FwdReg, MO.getReg())) { +            Defs.push_back(FwdReg); +            break; +          } +        } +      } +    } +  }; + +  auto finishCallSiteParam = [&](DbgValueLoc DbgLocVal, unsigned Reg) { +    unsigned FwdReg = Reg; +    if (ShouldTryEmitEntryVals) { +      auto EntryValReg = RegsForEntryValues.find(Reg); +      if (EntryValReg != RegsForEntryValues.end()) +        FwdReg = EntryValReg->second; +    } + +    DbgCallSiteParam CSParm(FwdReg, DbgLocVal); +    Params.push_back(CSParm); +    ++NumCSParams; +  }; + +  // Search for a loading value in forwaring registers. +  for (; I != MBB->rend(); ++I) { +    // If the next instruction is a call we can not interpret parameter's +    // forwarding registers or we finished the interpretation of all parameters. +    if (I->isCall()) +      return; + +    if (ForwardedRegWorklist.empty()) +      return; + +    SmallVector<unsigned, 4> Defs; +    getForwardingRegsDefinedByMI(*I, Defs); +    if (Defs.empty()) +      continue; + +    // If the MI clobbers more then one forwarding register we must remove +    // all of them from the working list. +    for (auto Reg : Defs) +      ForwardedRegWorklist.erase(Reg); +    if (I->getNumDefs() != 1) +      continue; +    unsigned Reg = Defs[0]; + +    if (auto ParamValue = TII->describeLoadedValue(*I)) { +      if (ParamValue->first->isImm()) { +        unsigned Val = ParamValue->first->getImm(); +        DbgValueLoc DbgLocVal(ParamValue->second, Val); +        finishCallSiteParam(DbgLocVal, Reg); +      } else if (ParamValue->first->isReg()) { +        unsigned RegLoc = ParamValue->first->getReg(); +        unsigned SP = TLI->getStackPointerRegisterToSaveRestore(); +        unsigned FP = TRI->getFrameRegister(*MF); +        bool IsSPorFP = (RegLoc == SP) || (RegLoc == FP); +        if (TRI->isCalleeSavedPhysReg(RegLoc, *MF) || IsSPorFP) { +          DbgValueLoc DbgLocVal(ParamValue->second, +                                MachineLocation(RegLoc, +                                                /*IsIndirect=*/IsSPorFP)); +          finishCallSiteParam(DbgLocVal, Reg); +        } else if (ShouldTryEmitEntryVals) { +          ForwardedRegWorklist.insert(RegLoc); +          RegsForEntryValues[RegLoc] = Reg; +        } +      } +    } +  } + +  // Emit the call site parameter's value as an entry value. +  if (ShouldTryEmitEntryVals) { +    // Create an entry value expression where the expression following +    // the 'DW_OP_entry_value' will be the size of 1 (a register operation). +    DIExpression *EntryExpr = DIExpression::get(MF->getFunction().getContext(), +                                                {dwarf::DW_OP_entry_value, 1}); +    for (auto RegEntry : ForwardedRegWorklist) { +      unsigned FwdReg = RegEntry; +      auto EntryValReg = RegsForEntryValues.find(RegEntry); +        if (EntryValReg != RegsForEntryValues.end()) +          FwdReg = EntryValReg->second; + +      DbgValueLoc DbgLocVal(EntryExpr, MachineLocation(RegEntry)); +      DbgCallSiteParam CSParm(FwdReg, DbgLocVal); +      Params.push_back(CSParm); +      ++NumCSParams; +    } +  } +} +  void DwarfDebug::constructCallSiteEntryDIEs(const DISubprogram &SP,                                              DwarfCompileUnit &CU, DIE &ScopeDIE,                                              const MachineFunction &MF) { @@ -563,10 +707,12 @@ void DwarfDebug::constructCallSiteEntryDIEs(const DISubprogram &SP,    // for both tail and non-tail calls. Don't use DW_AT_call_all_source_calls    // because one of its requirements is not met: call site entries for    // optimized-out calls are elided. -  CU.addFlag(ScopeDIE, dwarf::DW_AT_call_all_calls); +  CU.addFlag(ScopeDIE, +             CU.getDwarf5OrGNUCallSiteAttr(dwarf::DW_AT_call_all_calls));    const TargetInstrInfo *TII = MF.getSubtarget().getInstrInfo();    assert(TII && "TargetInstrInfo not found: cannot label tail calls"); +  bool ApplyGNUExtensions = getDwarfVersion() == 4 && tuneForGDB();    // Emit call site entries for each call or tail call in the function.    for (const MachineBasicBlock &MBB : MF) { @@ -581,30 +727,66 @@ void DwarfDebug::constructCallSiteEntryDIEs(const DISubprogram &SP,          return;        // If this is a direct call, find the callee's subprogram. +      // In the case of an indirect call find the register that holds +      // the callee.        const MachineOperand &CalleeOp = MI.getOperand(0); -      if (!CalleeOp.isGlobal()) -        continue; -      const Function *CalleeDecl = dyn_cast<Function>(CalleeOp.getGlobal()); -      if (!CalleeDecl || !CalleeDecl->getSubprogram()) +      if (!CalleeOp.isGlobal() && !CalleeOp.isReg())          continue; +      unsigned CallReg = 0; +      const DISubprogram *CalleeSP = nullptr; +      const Function *CalleeDecl = nullptr; +      if (CalleeOp.isReg()) { +        CallReg = CalleeOp.getReg(); +        if (!CallReg) +          continue; +      } else { +        CalleeDecl = dyn_cast<Function>(CalleeOp.getGlobal()); +        if (!CalleeDecl || !CalleeDecl->getSubprogram()) +          continue; +        CalleeSP = CalleeDecl->getSubprogram(); +      } +        // TODO: Omit call site entries for runtime calls (objc_msgSend, etc). -      // TODO: Add support for indirect calls.        bool IsTail = TII->isTailCall(MI); -      // For tail calls, no return PC information is needed. For regular calls, -      // the return PC is needed to disambiguate paths in the call graph which -      // could lead to some target function. +      // For tail calls, for non-gdb tuning, no return PC information is needed. +      // For regular calls (and tail calls in GDB tuning), the return PC +      // is needed to disambiguate paths in the call graph which could lead to +      // some target function.        const MCExpr *PCOffset = -          IsTail ? nullptr : getFunctionLocalOffsetAfterInsn(&MI); +          (IsTail && !tuneForGDB()) ? nullptr +                                    : getFunctionLocalOffsetAfterInsn(&MI); + +      // Address of a call-like instruction for a normal call or a jump-like +      // instruction for a tail call. This is needed for GDB + DWARF 4 tuning. +      const MCSymbol *PCAddr = +          ApplyGNUExtensions ? const_cast<MCSymbol*>(getLabelAfterInsn(&MI)) +                             : nullptr; + +      assert((IsTail || PCOffset || PCAddr) && +             "Call without return PC information"); -      assert((IsTail || PCOffset) && "Call without return PC information");        LLVM_DEBUG(dbgs() << "CallSiteEntry: " << MF.getName() << " -> " -                        << CalleeDecl->getName() << (IsTail ? " [tail]" : "") -                        << "\n"); -      CU.constructCallSiteEntryDIE(ScopeDIE, *CalleeDecl->getSubprogram(), -                                   IsTail, PCOffset); +                        << (CalleeDecl ? CalleeDecl->getName() +                                       : StringRef(MF.getSubtarget() +                                                       .getRegisterInfo() +                                                       ->getName(CallReg))) +                        << (IsTail ? " [IsTail]" : "") << "\n"); + +      DIE &CallSiteDIE = +            CU.constructCallSiteEntryDIE(ScopeDIE, CalleeSP, IsTail, PCAddr, +                                         PCOffset, CallReg); + +      // For now only GDB supports call site parameter debug info. +      if (Asm->TM.Options.EnableDebugEntryValues && +          tuneForGDB()) { +        ParamSet Params; +        // Try to interpret values of call site parameters. +        collectCallSiteParameters(&MI, Params); +        CU.constructCallSiteParmEntryDIEs(CallSiteDIE, Params); +      }      }    }  } diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.h b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.h index 3ac474e2bdd..4f3630f84c9 100644 --- a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.h +++ b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.h @@ -254,6 +254,25 @@ public:    }  }; +/// Used for tracking debug info about call site parameters. +class DbgCallSiteParam { +private: +  unsigned Register; ///< Parameter register at the callee entry point. +  DbgValueLoc Value; ///< Corresponding location for the parameter value at +                     ///< the call site. +public: +  DbgCallSiteParam(unsigned Reg, DbgValueLoc Val) +      : Register(Reg), Value(Val) { +    assert(Reg && "Parameter register cannot be undef"); +  } + +  unsigned getRegister() const { return Register; } +  DbgValueLoc getValue() const { return Value; } +}; + +/// Collection used for storing debug call site parameters. +using ParamSet = SmallVector<DbgCallSiteParam, 4>; +  /// Helper used to pair up a symbol and its DWARF compile unit.  struct SymbolCU {    SymbolCU(DwarfCompileUnit *CU, const MCSymbol *Sym) : Sym(Sym), CU(CU) {} diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfExpression.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfExpression.cpp index 2858afaa1cf..7cac286a43f 100644 --- a/llvm/lib/CodeGen/AsmPrinter/DwarfExpression.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/DwarfExpression.cpp @@ -241,15 +241,19 @@ bool DwarfExpression::addMachineRegExpression(const TargetRegisterInfo &TRI,      return false;    } -  // Handle simple register locations. -  if (!isMemoryLocation() && !HasComplexExpression) { +  // Handle simple register locations. If we are supposed to emit +  // a call site parameter expression and if that expression is just a register +  // location, emit it with addBReg and offset 0, because we should emit a DWARF +  // expression representing a value, rather than a location. +  if (!isMemoryLocation() && !HasComplexExpression && (!isParameterValue() || +                                                       isEntryValue())) {      for (auto &Reg : DwarfRegs) {        if (Reg.DwarfRegNo >= 0)          addReg(Reg.DwarfRegNo, Reg.Comment);        addOpPiece(Reg.Size);      } -    if (isEntryValue() && DwarfVersion >= 4) +    if (isEntryValue() && !isParameterValue() && DwarfVersion >= 4)        emitOp(dwarf::DW_OP_stack_value);      DwarfRegs.clear(); @@ -340,7 +344,17 @@ void DwarfExpression::addExpression(DIExpressionCursor &&ExprCursor,    while (ExprCursor) {      auto Op = ExprCursor.take(); -    switch (Op->getOp()) { +    uint64_t OpNum = Op->getOp(); + +    if (OpNum >= dwarf::DW_OP_reg0 && OpNum <= dwarf::DW_OP_reg31) { +      emitOp(OpNum); +      continue; +    } else if (OpNum >= dwarf::DW_OP_breg0 && OpNum <= dwarf::DW_OP_breg31) { +      addBReg(OpNum - dwarf::DW_OP_breg0, Op->getArg(0)); +      continue; +    } + +    switch (OpNum) {      case dwarf::DW_OP_LLVM_fragment: {        unsigned SizeInBits = Op->getArg(1);        unsigned FragmentOffset = Op->getArg(0); @@ -389,7 +403,7 @@ void DwarfExpression::addExpression(DIExpressionCursor &&ExprCursor,      case dwarf::DW_OP_lit0:      case dwarf::DW_OP_not:      case dwarf::DW_OP_dup: -      emitOp(Op->getOp()); +      emitOp(OpNum);        break;      case dwarf::DW_OP_deref:        assert(!isRegisterLocation()); @@ -458,12 +472,21 @@ void DwarfExpression::addExpression(DIExpressionCursor &&ExprCursor,      case dwarf::DW_OP_LLVM_tag_offset:        TagOffset = Op->getArg(0);        break; +    case dwarf::DW_OP_regx: +      emitOp(dwarf::DW_OP_regx); +      emitUnsigned(Op->getArg(0)); +      break; +    case dwarf::DW_OP_bregx: +      emitOp(dwarf::DW_OP_bregx); +      emitUnsigned(Op->getArg(0)); +      emitSigned(Op->getArg(1)); +      break;      default:        llvm_unreachable("unhandled opcode found in expression");      }    } -  if (isImplicitLocation()) +  if (isImplicitLocation() && !isParameterValue())      // Turn this into an implicit location description.      addStackValue();  } diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfExpression.h b/llvm/lib/CodeGen/AsmPrinter/DwarfExpression.h index ec2ef6e575f..9f9baf8c1a1 100644 --- a/llvm/lib/CodeGen/AsmPrinter/DwarfExpression.h +++ b/llvm/lib/CodeGen/AsmPrinter/DwarfExpression.h @@ -120,7 +120,7 @@ protected:    enum { Unknown = 0, Register, Memory, Implicit };    /// The flags of location description being produced. -  enum { EntryValue = 1 }; +  enum { EntryValue = 1, CallSiteParamValue };    unsigned LocationKind : 3;    unsigned LocationFlags : 2; @@ -147,6 +147,10 @@ public:      return LocationFlags & EntryValue;    } +  bool isParameterValue() { +    return LocationFlags & CallSiteParamValue; +  } +    Optional<uint8_t> TagOffset;  protected: @@ -264,6 +268,11 @@ public:      LocationFlags |= EntryValue;    } +  /// Lock this down to become a call site parameter location. +  void setCallSiteParamValueFlag() { +    LocationFlags |= CallSiteParamValue; +  } +    /// Emit a machine register location. As an optimization this may also consume    /// the prefix of a DwarfExpression if a more efficient representation for    /// combining the register location and the first operation exists. diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp index 991ab94b50a..4990ea66cc1 100644 --- a/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp @@ -205,6 +205,10 @@ void DwarfUnit::insertDIE(const DINode *Desc, DIE *D) {    MDNodeToDieMap.insert(std::make_pair(Desc, D));  } +void DwarfUnit::insertDIE(DIE *D) { +  MDNodeToDieMap.insert(std::make_pair(nullptr, D)); +} +  void DwarfUnit::addFlag(DIE &Die, dwarf::Attribute Attribute) {    if (DD->getDwarfVersion() >= 4)      Die.addValue(DIEValueAllocator, Attribute, dwarf::DW_FORM_flag_present, diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.h b/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.h index 56c934a35ae..a376d5e75f6 100644 --- a/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.h +++ b/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.h @@ -127,6 +127,8 @@ public:    /// the mappings are kept in DwarfDebug.    void insertDIE(const DINode *Desc, DIE *D); +  void insertDIE(DIE *D); +    /// Add a flag that is true to the DIE.    void addFlag(DIE &Die, dwarf::Attribute Attribute); diff --git a/llvm/lib/CodeGen/TargetInstrInfo.cpp b/llvm/lib/CodeGen/TargetInstrInfo.cpp index 868617ffe14..c33ae5f47c1 100644 --- a/llvm/lib/CodeGen/TargetInstrInfo.cpp +++ b/llvm/lib/CodeGen/TargetInstrInfo.cpp @@ -23,6 +23,7 @@  #include "llvm/CodeGen/TargetRegisterInfo.h"  #include "llvm/CodeGen/TargetSchedule.h"  #include "llvm/IR/DataLayout.h" +#include "llvm/IR/DebugInfoMetadata.h"  #include "llvm/MC/MCAsmInfo.h"  #include "llvm/MC/MCInstrItineraries.h"  #include "llvm/Support/CommandLine.h" @@ -1120,6 +1121,36 @@ bool TargetInstrInfo::hasLowDefLatency(const TargetSchedModel &SchedModel,    return (DefCycle != -1 && DefCycle <= 1);  } +Optional<ParamLoadedValue> +TargetInstrInfo::describeLoadedValue(const MachineInstr &MI) const { +  const MachineFunction *MF = MI.getMF(); +  const MachineOperand *Op = nullptr; +  DIExpression *Expr = DIExpression::get(MF->getFunction().getContext(), {});; +  const MachineOperand *SrcRegOp, *DestRegOp; + +  if (isCopyInstr(MI, SrcRegOp, DestRegOp)) { +    Op = SrcRegOp; +    return ParamLoadedValue(Op, Expr); +  } else if (MI.isMoveImmediate()) { +    Op = &MI.getOperand(1); +    return ParamLoadedValue(Op, Expr); +  } else if (MI.hasOneMemOperand()) { +    int64_t Offset; +    const auto &TRI = MF->getSubtarget().getRegisterInfo(); +    const auto &TII = MF->getSubtarget().getInstrInfo(); +    const MachineOperand *BaseOp; + +    if (!TII->getMemOperandWithOffset(MI, BaseOp, Offset, TRI)) +      return None; + +    Expr = DIExpression::prepend(Expr, DIExpression::DerefAfter, Offset); +    Op = BaseOp; +    return ParamLoadedValue(Op, Expr); +  } + +  return None; +} +  /// Both DefMI and UseMI must be valid.  By default, call directly to the  /// itinerary. This may be overriden by the target.  int TargetInstrInfo::getOperandLatency(const InstrItineraryData *ItinData, diff --git a/llvm/lib/CodeGen/TargetRegisterInfo.cpp b/llvm/lib/CodeGen/TargetRegisterInfo.cpp index f1b2ecf3243..f081b02df56 100644 --- a/llvm/lib/CodeGen/TargetRegisterInfo.cpp +++ b/llvm/lib/CodeGen/TargetRegisterInfo.cpp @@ -433,6 +433,19 @@ TargetRegisterInfo::getRegAllocationHints(unsigned VirtReg,    return false;  } +bool TargetRegisterInfo::isCalleeSavedPhysReg( +    unsigned PhysReg, const MachineFunction &MF) const { +  if (PhysReg == 0) +    return false; +  const uint32_t *callerPreservedRegs = +      getCallPreservedMask(MF, MF.getFunction().getCallingConv()); +  if (callerPreservedRegs) { +    assert(isPhysicalRegister(PhysReg) && "Expected physical register"); +    return (callerPreservedRegs[PhysReg / 32] >> PhysReg % 32) & 1; +  } +  return false; +} +  bool TargetRegisterInfo::canRealignStack(const MachineFunction &MF) const {    return !MF.getFunction().hasFnAttribute("no-realign-stack");  } diff --git a/llvm/lib/DebugInfo/DWARF/DWARFDie.cpp b/llvm/lib/DebugInfo/DWARF/DWARFDie.cpp index d638dc4239f..e95a0ffa8f8 100644 --- a/llvm/lib/DebugInfo/DWARF/DWARFDie.cpp +++ b/llvm/lib/DebugInfo/DWARF/DWARFDie.cpp @@ -733,6 +733,7 @@ bool DWARFAttribute::mayHaveLocationDescription(dwarf::Attribute Attr) {    case DW_AT_call_data_value:    // Extensions.    case DW_AT_GNU_call_site_value: +  case DW_AT_GNU_call_site_target:      return true;    default:      return false; diff --git a/llvm/lib/IR/DebugInfoMetadata.cpp b/llvm/lib/IR/DebugInfoMetadata.cpp index 900df27d1d3..3482b616853 100644 --- a/llvm/lib/IR/DebugInfoMetadata.cpp +++ b/llvm/lib/IR/DebugInfoMetadata.cpp @@ -828,15 +828,23 @@ DIExpression *DIExpression::getImpl(LLVMContext &Context,  }  unsigned DIExpression::ExprOperand::getSize() const { -  switch (getOp()) { +  uint64_t Op = getOp(); + +  if (Op >= dwarf::DW_OP_breg0 && Op <= dwarf::DW_OP_breg31) +    return 2; + +  switch (Op) {    case dwarf::DW_OP_LLVM_convert:    case dwarf::DW_OP_LLVM_fragment: +  case dwarf::DW_OP_bregx:      return 3;    case dwarf::DW_OP_constu: +  case dwarf::DW_OP_consts:    case dwarf::DW_OP_deref_size:    case dwarf::DW_OP_plus_uconst:    case dwarf::DW_OP_LLVM_tag_offset:    case dwarf::DW_OP_entry_value: +  case dwarf::DW_OP_regx:      return 2;    default:      return 1; @@ -849,8 +857,13 @@ bool DIExpression::isValid() const {      if (I->get() + I->getSize() > E->get())        return false; +    uint64_t Op = I->getOp(); +    if ((Op >= dwarf::DW_OP_reg0 && Op <= dwarf::DW_OP_reg31) || +        (Op >= dwarf::DW_OP_breg0 && Op <= dwarf::DW_OP_breg31)) +      return true; +      // Check that the operand is valid. -    switch (I->getOp()) { +    switch (Op) {      default:        return false;      case dwarf::DW_OP_LLVM_fragment: @@ -905,6 +918,8 @@ bool DIExpression::isValid() const {      case dwarf::DW_OP_lit0:      case dwarf::DW_OP_not:      case dwarf::DW_OP_dup: +    case dwarf::DW_OP_regx: +    case dwarf::DW_OP_bregx:        break;      }    } diff --git a/llvm/lib/Target/X86/X86InstrInfo.cpp b/llvm/lib/Target/X86/X86InstrInfo.cpp index dbe45356c42..93c669801a7 100644 --- a/llvm/lib/Target/X86/X86InstrInfo.cpp +++ b/llvm/lib/Target/X86/X86InstrInfo.cpp @@ -30,7 +30,7 @@  #include "llvm/CodeGen/StackMaps.h"  #include "llvm/IR/DerivedTypes.h"  #include "llvm/IR/Function.h" -#include "llvm/IR/LLVMContext.h" +#include "llvm/IR/DebugInfoMetadata.h"  #include "llvm/MC/MCAsmInfo.h"  #include "llvm/MC/MCExpr.h"  #include "llvm/MC/MCInst.h" @@ -7367,6 +7367,92 @@ bool X86InstrInfo::isAssociativeAndCommutative(const MachineInstr &Inst) const {    }  } +Optional<ParamLoadedValue> +X86InstrInfo::describeLoadedValue(const MachineInstr &MI) const { +  const MachineOperand *Op = nullptr; +  DIExpression *Expr = nullptr; + +  switch (MI.getOpcode()) { +  case X86::LEA32r: +  case X86::LEA64r: +  case X86::LEA64_32r: { +    // Operand 4 could be global address. For now we do not support +    // such situation. +    if (!MI.getOperand(4).isImm() || !MI.getOperand(2).isImm()) +      return None; + +    const MachineOperand &Op1 = MI.getOperand(1); +    const MachineOperand &Op2 = MI.getOperand(3); +    const TargetRegisterInfo *TRI = &getRegisterInfo(); +    assert(Op2.isReg() && +           (Op2.getReg() == X86::NoRegister || +            TargetRegisterInfo::isPhysicalRegister(Op2.getReg()))); + +    // Omit situations like: +    // %rsi = lea %rsi, 4, ... +    if ((Op1.isReg() && Op1.getReg() == MI.getOperand(0).getReg()) || +        Op2.getReg() == MI.getOperand(0).getReg()) +      return None; +    else if ((Op1.isReg() && Op1.getReg() != X86::NoRegister && +              TRI->regsOverlap(Op1.getReg(), MI.getOperand(0).getReg())) || +             (Op2.getReg() != X86::NoRegister && +              TRI->regsOverlap(Op2.getReg(), MI.getOperand(0).getReg()))) +      return None; + +    int64_t Coef = MI.getOperand(2).getImm(); +    int64_t Offset = MI.getOperand(4).getImm(); +    SmallVector<uint64_t, 8> Ops; + +    if ((Op1.isReg() && Op1.getReg() != X86::NoRegister)) { +      Op = &Op1; +    } else if (Op1.isFI()) +      Op = &Op1; + +    if (Op && Op->isReg() && Op->getReg() == Op2.getReg() && Coef > 0) { +      Ops.push_back(dwarf::DW_OP_constu); +      Ops.push_back(Coef + 1); +      Ops.push_back(dwarf::DW_OP_mul); +    } else { +      if (Op && Op2.getReg() != X86::NoRegister) { +        int dwarfReg = TRI->getDwarfRegNum(Op2.getReg(), false); +        if (dwarfReg < 0) +          return None; +        else if (dwarfReg < 32) { +          Ops.push_back(dwarf::DW_OP_breg0 + dwarfReg); +          Ops.push_back(0); +        } else { +          Ops.push_back(dwarf::DW_OP_bregx); +          Ops.push_back(dwarfReg); +          Ops.push_back(0); +        } +      } else if (!Op) { +        assert(Op2.getReg() != X86::NoRegister); +        Op = &Op2; +      } + +      if (Coef > 1) { +        assert(Op2.getReg() != X86::NoRegister); +        Ops.push_back(dwarf::DW_OP_constu); +        Ops.push_back(Coef); +        Ops.push_back(dwarf::DW_OP_mul); +      } + +      if (((Op1.isReg() && Op1.getReg() != X86::NoRegister) || Op1.isFI()) && +          Op2.getReg() != X86::NoRegister) { +        Ops.push_back(dwarf::DW_OP_plus); +      } +    } + +    DIExpression::appendOffset(Ops, Offset); +    Expr = DIExpression::get(MI.getMF()->getFunction().getContext(), Ops); + +    return ParamLoadedValue(Op, Expr);; +  } +  default: +    return TargetInstrInfo::describeLoadedValue(MI); +  } +} +  /// This is an architecture-specific helper function of reassociateOps.  /// Set special operand attributes for new instructions after reassociation.  void X86InstrInfo::setSpecialOperandAttr(MachineInstr &OldMI1, diff --git a/llvm/lib/Target/X86/X86InstrInfo.h b/llvm/lib/Target/X86/X86InstrInfo.h index 13ca1713949..b18c1da3c9f 100644 --- a/llvm/lib/Target/X86/X86InstrInfo.h +++ b/llvm/lib/Target/X86/X86InstrInfo.h @@ -527,6 +527,9 @@ public:  #define GET_INSTRINFO_HELPER_DECLS  #include "X86GenInstrInfo.inc" +  Optional<ParamLoadedValue> +  describeLoadedValue(const MachineInstr &MI) const override; +  protected:    /// Commutes the operands in the given instruction by changing the operands    /// order and/or changing the instruction's opcode and/or the immediate value  | 

