alok created this revision.
alok added reviewers: aprantl, probinson, dblaikie, jmorse, jini.susan.george, 
SouraVX, awpandey.
alok added projects: LLVM, debug-info.
Herald added a reviewer: bollu.
Herald added subscribers: llvm-commits, lldb-commits, jdoerfert, asbirlea, 
george.burgess.iv, hiraditya.
Herald added a project: LLDB.
alok added a child revision: D69999: [DebugInfo] Support for 
DW_OP_implicit_pointer (IR Verifier and Bitcode).
alok added a parent revision: D70643: [DebugInfo] Support for 
DW_OP_implicit_pointer (DW_OP_LLVM_implicit_pointer).

    This patch (3/N) stems from D69787 as suggested by
    This is suggested by @jmorse.
  
    New intrinsic llvm.dbg.derefval is introduced.
  
  Summary:
    Since dbg.value currently represents (VAR=VALUE), the new intrinsic 
dbg.derefval will represent de-referenced value (*VAR = VAL)
      - Below represents ptr=null
        call void @llvm.dbg.value(metadata i32* null, metadata !21, metadata 
!DIExpression())
      - And below represents *ptr=var
        call void @llvm.dbg.derefval(metadata !16, metadata !21, metadata 
!DIExpression(DW_OP_LLVM_implicit_pointer, DW_OP_LLVM_arg0, 0))
      - And below represents *ptr=arr[1]
        call void @llvm.dbg.derefval(metadata !16, metadata !21, metadata 
!DIExpression(DW_OP_LLVM_implicit_pointer, DW_OP_LLVM_arg0, 4))
      - We should be able to represent the case when a variable points to 
temporary (initialized by constant) and temporary is optimized out.
        tmp=[CONST]; ptr=&tmp;
        call void @llvm.dbg.derefval(metadata [CONST], metadata !21, metadata 
!DIExpression(DW_OP_LLVM_arg0))


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D70644

Files:
  lldb/source/Expression/IRInterpreter.cpp
  llvm/docs/SourceLevelDebugging.rst
  llvm/include/llvm/Analysis/TargetTransformInfoImpl.h
  llvm/include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h
  llvm/include/llvm/CodeGen/MachineInstrBuilder.h
  llvm/include/llvm/IR/DIBuilder.h
  llvm/include/llvm/IR/InstVisitor.h
  llvm/include/llvm/IR/IntrinsicInst.h
  llvm/include/llvm/IR/Intrinsics.td
  llvm/lib/Analysis/MemorySSA.cpp
  llvm/lib/Analysis/ObjCARCInstKind.cpp
  llvm/lib/Analysis/ValueTracking.cpp
  llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
  llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp
  llvm/lib/CodeGen/GlobalISel/MachineIRBuilder.cpp
  llvm/lib/CodeGen/LiveDebugValues.cpp
  llvm/lib/CodeGen/SelectionDAG/FastISel.cpp
  llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
  llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.h
  llvm/lib/IR/DIBuilder.cpp
  llvm/lib/IR/IntrinsicInst.cpp
  llvm/lib/IR/Verifier.cpp
  llvm/lib/Transforms/Utils/Local.cpp
  llvm/lib/Transforms/Utils/SimplifyCFG.cpp
  polly/lib/Support/ScopHelper.cpp

Index: polly/lib/Support/ScopHelper.cpp
===================================================================
--- polly/lib/Support/ScopHelper.cpp
+++ polly/lib/Support/ScopHelper.cpp
@@ -624,6 +624,7 @@
     case llvm::Intrinsic::assume:
     // Some debug info intrinsics are supported/ignored.
     case llvm::Intrinsic::dbg_value:
+    case llvm::Intrinsic::dbg_derefval:
     case llvm::Intrinsic::dbg_declare:
       return true;
     default:
Index: llvm/lib/Transforms/Utils/SimplifyCFG.cpp
===================================================================
--- llvm/lib/Transforms/Utils/SimplifyCFG.cpp
+++ llvm/lib/Transforms/Utils/SimplifyCFG.cpp
@@ -4010,6 +4010,7 @@
     switch (IntrinsicID) {
     case Intrinsic::dbg_declare:
     case Intrinsic::dbg_value:
+    case Intrinsic::dbg_derefval:
     case Intrinsic::dbg_label:
     case Intrinsic::lifetime_end:
       break;
Index: llvm/lib/Transforms/Utils/Local.cpp
===================================================================
--- llvm/lib/Transforms/Utils/Local.cpp
+++ llvm/lib/Transforms/Utils/Local.cpp
@@ -385,6 +385,11 @@
       return false;
     return true;
   }
+  if (DbgDerefValueInst *DVI = dyn_cast<DbgDerefValueInst>(I)) {
+    if (DVI->getDerefVariable())
+      return false;
+    return true;
+  }
   if (DbgLabelInst *DLI = dyn_cast<DbgLabelInst>(I)) {
     if (DLI->getLabel())
       return false;
Index: llvm/lib/IR/Verifier.cpp
===================================================================
--- llvm/lib/IR/Verifier.cpp
+++ llvm/lib/IR/Verifier.cpp
@@ -4314,6 +4314,9 @@
   case Intrinsic::dbg_value: // llvm.dbg.value
     visitDbgIntrinsic("value", cast<DbgVariableIntrinsic>(Call));
     break;
+  case Intrinsic::dbg_derefval: // llvm.dbg.derefval
+    visitDbgIntrinsic("derefval", cast<DbgVariableIntrinsic>(Call));
+    break;
   case Intrinsic::dbg_label: // llvm.dbg.label
     visitDbgLabelIntrinsic("label", cast<DbgLabelInst>(Call));
     break;
@@ -4836,8 +4839,9 @@
 void Verifier::visitDbgIntrinsic(StringRef Kind, DbgVariableIntrinsic &DII) {
   auto *MD = cast<MetadataAsValue>(DII.getArgOperand(0))->getMetadata();
   AssertDI(isa<ValueAsMetadata>(MD) ||
-             (isa<MDNode>(MD) && !cast<MDNode>(MD)->getNumOperands()),
-         "invalid llvm.dbg." + Kind + " intrinsic address/value", &DII, MD);
+               (isa<MDNode>(MD) && !cast<MDNode>(MD)->getNumOperands()) ||
+               isa<DbgDerefValueInst>(DII),
+           "invalid llvm.dbg." + Kind + " intrinsic address/value", &DII, MD);
   AssertDI(isa<DILocalVariable>(DII.getRawVariable()),
          "invalid llvm.dbg." + Kind + " intrinsic variable", &DII,
          DII.getRawVariable());
Index: llvm/lib/IR/IntrinsicInst.cpp
===================================================================
--- llvm/lib/IR/IntrinsicInst.cpp
+++ llvm/lib/IR/IntrinsicInst.cpp
@@ -50,6 +50,14 @@
   return nullptr;
 }
 
+Value *DbgVariableIntrinsic::getDerefVariable(bool AllowNullOp) const {
+  Value *Op = getArgOperand(0);
+  if (AllowNullOp && !Op)
+    return nullptr;
+
+  return Op;
+}
+
 Optional<uint64_t> DbgVariableIntrinsic::getFragmentSizeInBits() const {
   if (auto Fragment = getExpression()->getFragmentInfo())
     return Fragment->SizeInBits;
Index: llvm/lib/IR/DIBuilder.cpp
===================================================================
--- llvm/lib/IR/DIBuilder.cpp
+++ llvm/lib/IR/DIBuilder.cpp
@@ -885,6 +885,14 @@
       InsertBefore);
 }
 
+Instruction *DIBuilder::insertDbgDerefValueIntrinsic(
+    Value *V, DILocalVariable *VarInfo, DIExpression *Expr,
+    const DILocation *DL, Instruction *InsertBefore) {
+  return insertDbgDerefValueIntrinsic(
+      V, VarInfo, Expr, DL, InsertBefore ? InsertBefore->getParent() : nullptr,
+      InsertBefore);
+}
+
 Instruction *DIBuilder::insertDbgValueIntrinsic(Value *V,
                                                 DILocalVariable *VarInfo,
                                                 DIExpression *Expr,
@@ -960,6 +968,27 @@
   return B.CreateCall(ValueFn, Args);
 }
 
+Instruction *DIBuilder::insertDbgDerefValueIntrinsic(
+    Value *V, DILocalVariable *VarInfo, DIExpression *Expr,
+    const DILocation *DL, BasicBlock *InsertBB, Instruction *InsertBefore) {
+  assert(V && "no value passed to dbg.value");
+  assert(VarInfo && "empty or invalid DILocalVariable* passed to dbg.value");
+  assert(DL && "Expected debug loc");
+  assert(DL->getScope()->getSubprogram() ==
+             VarInfo->getScope()->getSubprogram() &&
+         "Expected matching subprograms");
+  if (!ValueFn)
+    ValueFn = Intrinsic::getDeclaration(&M, Intrinsic::dbg_derefval);
+
+  trackIfUnresolved(VarInfo);
+  trackIfUnresolved(Expr);
+  Value *Args[] = {V, MetadataAsValue::get(VMContext, VarInfo),
+                   MetadataAsValue::get(VMContext, Expr)};
+
+  IRBuilder<> B = getIRBForDbgInsertion(DL, InsertBB, InsertBefore);
+  return B.CreateCall(ValueFn, Args);
+}
+
 Instruction *DIBuilder::insertLabel(
     DILabel *LabelInfo, const DILocation *DL,
     BasicBlock *InsertBB, Instruction *InsertBefore) {
Index: llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.h
===================================================================
--- llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.h
+++ llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.h
@@ -105,16 +105,17 @@
 
   /// Helper type for DanglingDebugInfoMap.
   class DanglingDebugInfo {
-    const DbgValueInst* DI = nullptr;
+    const DbgVariableIntrinsic *DI = nullptr;
     DebugLoc dl;
     unsigned SDNodeOrder = 0;
 
   public:
     DanglingDebugInfo() = default;
-    DanglingDebugInfo(const DbgValueInst *di, DebugLoc DL, unsigned SDNO)
+    DanglingDebugInfo(const DbgVariableIntrinsic *di, DebugLoc DL,
+                      unsigned SDNO)
         : DI(di), dl(std::move(DL)), SDNodeOrder(SDNO) {}
 
-    const DbgValueInst* getDI() { return DI; }
+    const DbgVariableIntrinsic *getDI() { return DI; }
     DebugLoc getdl() { return dl; }
     unsigned getSDNodeOrder() { return SDNodeOrder; }
   };
Index: llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
===================================================================
--- llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
+++ llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
@@ -1133,7 +1133,7 @@
 void SelectionDAGBuilder::dropDanglingDebugInfo(const DILocalVariable *Variable,
                                                 const DIExpression *Expr) {
   auto isMatchingDbgValue = [&](DanglingDebugInfo &DDI) {
-    const DbgValueInst *DI = DDI.getDI();
+    const DbgVariableIntrinsic *DI = DDI.getDI();
     DIVariable *DanglingVariable = DI->getVariable();
     DIExpression *DanglingExpr = DI->getExpression();
     if (DanglingVariable == Variable && Expr->fragmentsOverlap(DanglingExpr)) {
@@ -1166,7 +1166,7 @@
 
   DanglingDebugInfoVector &DDIV = DanglingDbgInfoIt->second;
   for (auto &DDI : DDIV) {
-    const DbgValueInst *DI = DDI.getDI();
+    const DbgVariableIntrinsic *DI = DDI.getDI();
     assert(DI && "Ill-formed DanglingDebugInfo");
     DebugLoc dl = DDI.getdl();
     unsigned ValSDNodeOrder = Val.getNode()->getIROrder();
@@ -1213,16 +1213,21 @@
 }
 
 void SelectionDAGBuilder::salvageUnresolvedDbgValue(DanglingDebugInfo &DDI) {
-  Value *V = DDI.getDI()->getValue();
+  const DbgVariableIntrinsic *DVI = DDI.getDI();
+
+  // Currently we consider only dbg.value intrinsics -- we tell the salvager
+  // that DW_OP_stack_value is desired.
+  assert(isa<DbgValueInst>(DVI) || isa<DbgDerefValueInst>(DVI));
+
+  Value *V = isa<DbgValueInst>(DVI) ? cast<DbgValueInst>(DVI)->getValue()
+                                    : cast<DbgDerefValueInst>(DVI)->getValue();
+
   DILocalVariable *Var = DDI.getDI()->getVariable();
   DIExpression *Expr = DDI.getDI()->getExpression();
   DebugLoc DL = DDI.getdl();
   DebugLoc InstDL = DDI.getDI()->getDebugLoc();
   unsigned SDOrder = DDI.getSDNodeOrder();
 
-  // Currently we consider only dbg.value intrinsics -- we tell the salvager
-  // that DW_OP_stack_value is desired.
-  assert(isa<DbgValueInst>(DDI.getDI()));
   bool StackValue = true;
 
   // Can this Value can be encoded without any further work?
@@ -5943,6 +5948,29 @@
     DanglingDebugInfoMap[V].emplace_back(&DI, dl, SDNodeOrder);
     return;
   }
+  case Intrinsic::dbg_derefval: {
+    const DbgDerefValueInst &DI = cast<DbgDerefValueInst>(I);
+    assert(DI.getVariable() && "Missing variable");
+
+    DILocalVariable *Variable = DI.getVariable();
+    DIExpression *Expression = DI.getExpression();
+    dropDanglingDebugInfo(Variable, Expression);
+    const Value *V = DI.getValue();
+    if (!V)
+      return;
+
+    if (handleDebugValue(V, Variable, Expression, dl, DI.getDebugLoc(),
+                         SDNodeOrder))
+      return;
+
+    // TODO: Dangling debug info will eventually either be resolved or produce
+    // an Undef DBG_VALUE. However in the resolution case, a gap may appear
+    // between the original dbg.value location and its resolved DBG_VALUE, which
+    // we should ideally fill with an extra Undef DBG_VALUE.
+
+    DanglingDebugInfoMap[V].emplace_back(&DI, dl, SDNodeOrder);
+    return;
+  }
 
   case Intrinsic::eh_typeid_for: {
     // Find the type id for the given typeinfo.
Index: llvm/lib/CodeGen/SelectionDAG/FastISel.cpp
===================================================================
--- llvm/lib/CodeGen/SelectionDAG/FastISel.cpp
+++ llvm/lib/CodeGen/SelectionDAG/FastISel.cpp
@@ -1444,6 +1444,52 @@
     }
     return true;
   }
+  case Intrinsic::dbg_derefval: {
+    // This form of DBG_VALUE is target-independent.
+    const DbgDerefValueInst *DI = cast<DbgDerefValueInst>(II);
+    const MCInstrDesc &II = TII.get(TargetOpcode::DBG_VALUE);
+    const Value *V = DI->getValue();
+    assert(DI->getVariable()->isValidLocationForIntrinsic(DbgLoc) &&
+           "Expected inlined-at fields to agree");
+    if (!V) {
+      // Currently the optimizer can produce this; insert an undef to
+      // help debugging.  Probably the optimizer should not do this.
+      BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, II, false, 0U,
+              DI->getVariable(), DI->getExpression());
+    } else if (const auto *MDV = dyn_cast<llvm::MetadataAsValue>(V)) {
+      if (const auto *LDV = dyn_cast<llvm::DIVariable>(MDV->getMetadata())) {
+        BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, II)
+            .addMetadata(LDV, true)
+            .addReg(0U)
+            .addMetadata(DI->getVariable())
+            .addMetadata(DI->getExpression());
+      }
+    } else if (const auto *CI = dyn_cast<ConstantInt>(V)) {
+      if (CI->getBitWidth() > 64)
+        BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, II)
+            .addCImm(CI)
+            .addReg(0U)
+            .addMetadata(DI->getVariable())
+            .addMetadata(DI->getExpression());
+      else
+        BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, II)
+            .addImm(CI->getZExtValue())
+            .addReg(0U)
+            .addMetadata(DI->getVariable())
+            .addMetadata(DI->getExpression());
+    } else if (const auto *CF = dyn_cast<ConstantFP>(V)) {
+      BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, II)
+          .addFPImm(CF)
+          .addReg(0U)
+          .addMetadata(DI->getVariable())
+          .addMetadata(DI->getExpression());
+    } else {
+      // We can't yet handle anything else here because it would require
+      // generating code, thus altering codegen because of debug info.
+      LLVM_DEBUG(dbgs() << "Dropping debug info for " << *DI << "\n");
+    }
+    return true;
+  }
   case Intrinsic::dbg_label: {
     const DbgLabelInst *DI = cast<DbgLabelInst>(II);
     assert(DI->getLabel() && "Missing label");
Index: llvm/lib/CodeGen/LiveDebugValues.cpp
===================================================================
--- llvm/lib/CodeGen/LiveDebugValues.cpp
+++ llvm/lib/CodeGen/LiveDebugValues.cpp
@@ -714,7 +714,8 @@
   // Add the VarLoc to OpenRanges from this DBG_VALUE.
   unsigned ID;
   if (isDbgValueDescribedByReg(MI) || MI.getOperand(0).isImm() ||
-      MI.getOperand(0).isFPImm() || MI.getOperand(0).isCImm()) {
+      MI.getOperand(0).isFPImm() || MI.getOperand(0).isCImm() ||
+      MI.getOperand(0).isMetadata()) {
     // Use normal VarLoc constructor for registers and immediates.
     VarLoc VL(MI, LS);
     ID = VarLocIDs.insert(VL);
Index: llvm/lib/CodeGen/GlobalISel/MachineIRBuilder.cpp
===================================================================
--- llvm/lib/CodeGen/GlobalISel/MachineIRBuilder.cpp
+++ llvm/lib/CodeGen/GlobalISel/MachineIRBuilder.cpp
@@ -159,6 +159,34 @@
   return MIB.addReg(0).addMetadata(Variable).addMetadata(Expr);
 }
 
+MachineInstrBuilder MachineIRBuilder::buildDerefDbgValue(const Value *Derefval,
+                                                         const MDNode *Variable,
+                                                         const MDNode *Expr) {
+  assert(isa<DILocalVariable>(Variable) && "not a variable");
+  assert(cast<DIExpression>(Expr)->isValid() && "not an expression");
+  assert(
+      cast<DILocalVariable>(Variable)->isValidLocationForIntrinsic(getDL()) &&
+      "Expected inlined-at fields to agree");
+  auto MIB = buildInstr(TargetOpcode::DBG_VALUE);
+  if (const auto *MDV = dyn_cast<llvm::MetadataAsValue>(Derefval)) {
+    if (const auto *LDV = dyn_cast<llvm::DIVariable>(MDV->getMetadata())) {
+      MIB.addMetadata(LDV, true);
+    }
+  } else if (auto *CI = dyn_cast<ConstantInt>(Derefval)) {
+    if (CI->getBitWidth() > 64)
+      MIB.addCImm(CI);
+    else
+      MIB.addImm(CI->getZExtValue());
+  } else if (auto *CFP = dyn_cast<ConstantFP>(Derefval)) {
+    MIB.addFPImm(CFP);
+  } else {
+    // Insert %noreg if we didn't find a usable constant and had to drop it.
+    MIB.addReg(0U);
+  }
+
+  return MIB.addReg(0).addMetadata(Variable).addMetadata(Expr);
+}
+
 MachineInstrBuilder MachineIRBuilder::buildDbgLabel(const MDNode *Label) {
   assert(isa<DILabel>(Label) && "not a label");
   assert(cast<DILabel>(Label)->isValidLocationForIntrinsic(State.DL) &&
Index: llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp
===================================================================
--- llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp
+++ llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp
@@ -1397,6 +1397,22 @@
     }
     return true;
   }
+  case Intrinsic::dbg_derefval: {
+    // This form of DBG_VALUE is target-independent.
+    const DbgDerefValueInst &DI = cast<DbgDerefValueInst>(CI);
+    const Value *V = DI.getValue();
+    assert(DI.getVariable()->isValidLocationForIntrinsic(
+               MIRBuilder.getDebugLoc()) &&
+           "Expected inlined-at fields to agree");
+    if (!V) {
+      // Currently the optimizer can produce this; insert an undef to
+      // help debugging.  Probably the optimizer should not do this.
+      MIRBuilder.buildDirectDbgValue(0, DI.getVariable(), DI.getExpression());
+    } else {
+      MIRBuilder.buildDerefDbgValue(V, DI.getVariable(), DI.getExpression());
+    }
+    return true;
+  }
   case Intrinsic::uadd_with_overflow:
     return translateOverflowIntrinsic(CI, TargetOpcode::G_UADDO, MIRBuilder);
   case Intrinsic::sadd_with_overflow:
Index: llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
===================================================================
--- llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
+++ llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
@@ -874,6 +874,8 @@
     OS << MI->getOperand(0).getImm();
   } else if (MI->getOperand(0).isCImm()) {
     MI->getOperand(0).getCImm()->getValue().print(OS, false /*isSigned*/);
+  } else if (MI->getOperand(0).isMetadata()) {
+    OS << MI->getOperand(0).getMetadata();
   } else {
     unsigned Reg;
     if (MI->getOperand(0).isReg()) {
Index: llvm/lib/Analysis/ValueTracking.cpp
===================================================================
--- llvm/lib/Analysis/ValueTracking.cpp
+++ llvm/lib/Analysis/ValueTracking.cpp
@@ -508,6 +508,7 @@
       case Intrinsic::sideeffect:
       case Intrinsic::dbg_declare:
       case Intrinsic::dbg_value:
+      case Intrinsic::dbg_derefval:
       case Intrinsic::dbg_label:
       case Intrinsic::invariant_start:
       case Intrinsic::invariant_end:
Index: llvm/lib/Analysis/ObjCARCInstKind.cpp
===================================================================
--- llvm/lib/Analysis/ObjCARCInstKind.cpp
+++ llvm/lib/Analysis/ObjCARCInstKind.cpp
@@ -184,6 +184,7 @@
   // Don't let dbg info affect our results.
   case Intrinsic::dbg_declare:
   case Intrinsic::dbg_value:
+  case Intrinsic::dbg_derefval:
   case Intrinsic::dbg_label:
     // Short cut: Some intrinsics obviously don't use ObjC pointers.
     return true;
Index: llvm/lib/Analysis/MemorySSA.cpp
===================================================================
--- llvm/lib/Analysis/MemorySSA.cpp
+++ llvm/lib/Analysis/MemorySSA.cpp
@@ -290,6 +290,7 @@
     case Intrinsic::dbg_declare:
     case Intrinsic::dbg_label:
     case Intrinsic::dbg_value:
+    case Intrinsic::dbg_derefval:
       llvm_unreachable("debuginfo shouldn't have associated defs!");
     default:
       break;
Index: llvm/include/llvm/IR/Intrinsics.td
===================================================================
--- llvm/include/llvm/IR/Intrinsics.td
+++ llvm/include/llvm/IR/Intrinsics.td
@@ -787,6 +787,10 @@
                                        [llvm_metadata_ty,
                                         llvm_metadata_ty,
                                         llvm_metadata_ty]>;
+  def int_dbg_derefval     : Intrinsic<[],
+                                       [llvm_metadata_ty,
+                                        llvm_metadata_ty,
+                                        llvm_metadata_ty]>;
   def int_dbg_addr         : Intrinsic<[],
                                        [llvm_metadata_ty,
                                         llvm_metadata_ty,
Index: llvm/include/llvm/IR/IntrinsicInst.h
===================================================================
--- llvm/include/llvm/IR/IntrinsicInst.h
+++ llvm/include/llvm/IR/IntrinsicInst.h
@@ -72,6 +72,7 @@
       switch (I->getIntrinsicID()) {
       case Intrinsic::dbg_declare:
       case Intrinsic::dbg_value:
+      case Intrinsic::dbg_derefval:
       case Intrinsic::dbg_addr:
       case Intrinsic::dbg_label:
         return true;
@@ -92,10 +93,13 @@
     /// variable's value or its address.
     Value *getVariableLocation(bool AllowNullOp = true) const;
 
+    Value *getDerefVariable(bool AllowNullOp = true) const;
+
     /// Does this describe the address of a local variable. True for dbg.addr
     /// and dbg.declare, but not dbg.value, which describes its value.
     bool isAddressOfVariable() const {
-      return getIntrinsicID() != Intrinsic::dbg_value;
+      return getIntrinsicID() == Intrinsic::dbg_declare ||
+             getIntrinsicID() == Intrinsic::dbg_addr;
     }
 
     DILocalVariable *getVariable() const {
@@ -124,6 +128,7 @@
       switch (I->getIntrinsicID()) {
       case Intrinsic::dbg_declare:
       case Intrinsic::dbg_value:
+      case Intrinsic::dbg_derefval:
       case Intrinsic::dbg_addr:
         return true;
       default: return false;
@@ -184,6 +189,24 @@
     /// @}
   };
 
+  /// This represents the llvm.dbg.deref.value instruction.
+  class DbgDerefValueInst : public DbgVariableIntrinsic {
+  public:
+    Value *getValue() const {
+      return getDerefVariable(/* AllowNullOp = */ false);
+    }
+
+    /// \name Casting methods
+    /// @{
+    static bool classof(const IntrinsicInst *I) {
+      return I->getIntrinsicID() == Intrinsic::dbg_derefval;
+    }
+    static bool classof(const Value *V) {
+      return isa<IntrinsicInst>(V) && classof(cast<IntrinsicInst>(V));
+    }
+    /// @}
+  };
+
   /// This represents the llvm.dbg.label instruction.
   class DbgLabelInst : public DbgInfoIntrinsic {
   public:
Index: llvm/include/llvm/IR/InstVisitor.h
===================================================================
--- llvm/include/llvm/IR/InstVisitor.h
+++ llvm/include/llvm/IR/InstVisitor.h
@@ -204,6 +204,9 @@
   // Handle the special instrinsic instruction classes.
   RetTy visitDbgDeclareInst(DbgDeclareInst &I)    { DELEGATE(DbgVariableIntrinsic);}
   RetTy visitDbgValueInst(DbgValueInst &I)        { DELEGATE(DbgVariableIntrinsic);}
+  RetTy visitDbgDerefValueInst(DbgDerefValueInst &I) {
+    DELEGATE(DbgVariableIntrinsic);
+  }
   RetTy visitDbgVariableIntrinsic(DbgVariableIntrinsic &I)
                                                   { DELEGATE(DbgInfoIntrinsic);}
   RetTy visitDbgLabelInst(DbgLabelInst &I)        { DELEGATE(DbgInfoIntrinsic);}
@@ -306,6 +309,8 @@
       default:                     DELEGATE(IntrinsicInst);
       case Intrinsic::dbg_declare: DELEGATE(DbgDeclareInst);
       case Intrinsic::dbg_value:   DELEGATE(DbgValueInst);
+      case Intrinsic::dbg_derefval:
+        DELEGATE(DbgDerefValueInst);
       case Intrinsic::dbg_label:   DELEGATE(DbgLabelInst);
       case Intrinsic::memcpy:      DELEGATE(MemCpyInst);
       case Intrinsic::memmove:     DELEGATE(MemMoveInst);
Index: llvm/include/llvm/IR/DIBuilder.h
===================================================================
--- llvm/include/llvm/IR/DIBuilder.h
+++ llvm/include/llvm/IR/DIBuilder.h
@@ -92,6 +92,11 @@
                             DIExpression *Expr, const DILocation *DL,
                             BasicBlock *InsertBB, Instruction *InsertBefore);
 
+    /// Internal helper for insertDbgDerefValueIntrinsic.
+    Instruction *insertDbgDerefValueIntrinsic(
+        llvm::Value *Val, DILocalVariable *VarInfo, DIExpression *Expr,
+        const DILocation *DL, BasicBlock *InsertBB, Instruction *InsertBefore);
+
   public:
     /// Construct a builder for a module.
     ///
@@ -849,6 +854,18 @@
                                          const DILocation *DL,
                                          Instruction *InsertBefore);
 
+    /// Insert a new llvm.dbg.derefval intrinsic call.
+    /// \param Val          dereferenced value of the variable
+    /// \param VarInfo      Variable's debug info descriptor.
+    /// \param Expr         A complex location expression.
+    /// \param DL           Debug info location.
+    /// \param InsertBefore Location for the new intrinsic.
+    Instruction *insertDbgDerefValueIntrinsic(llvm::Value *Val,
+                                              DILocalVariable *VarInfo,
+                                              DIExpression *Expr,
+                                              const DILocation *DL,
+                                              Instruction *InsertBefore);
+
     /// Replace the vtable holder in the given type.
     ///
     /// If this creates a self reference, it may orphan some unresolved cycles
Index: llvm/include/llvm/CodeGen/MachineInstrBuilder.h
===================================================================
--- llvm/include/llvm/CodeGen/MachineInstrBuilder.h
+++ llvm/include/llvm/CodeGen/MachineInstrBuilder.h
@@ -224,10 +224,12 @@
     return *this;
   }
 
-  const MachineInstrBuilder &addMetadata(const MDNode *MD) const {
+  const MachineInstrBuilder &addMetadata(const MDNode *MD,
+                                         bool IsImplicitPointer = false) const {
     MI->addOperand(*MF, MachineOperand::CreateMetadata(MD));
-    assert((MI->isDebugValue() ? static_cast<bool>(MI->getDebugVariable())
-                               : true) &&
+    assert(((MI->isDebugValue() && !IsImplicitPointer)
+                ? static_cast<bool>(MI->getDebugVariable())
+                : true) &&
            "first MDNode argument of a DBG_VALUE not a variable");
     assert((MI->isDebugLabel() ? static_cast<bool>(MI->getDebugLabel())
                                : true) &&
Index: llvm/include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h
===================================================================
--- llvm/include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h
+++ llvm/include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h
@@ -366,6 +366,11 @@
                                          const MDNode *Variable,
                                          const MDNode *Expr);
 
+  /// Build and insert a DBG_VALUE instructions specifying that dereferenced
+  /// value of \p Variable is given by \p V (suitably modified by \p Expr).
+  MachineInstrBuilder buildDerefDbgValue(const Value *V, const MDNode *Variable,
+                                         const MDNode *Expr);
+
   /// Build and insert a DBG_LABEL instructions specifying that \p Label is
   /// given. Convert "llvm.dbg.label Label" to "DBG_LABEL Label".
   MachineInstrBuilder buildDbgLabel(const MDNode *Label);
Index: llvm/include/llvm/Analysis/TargetTransformInfoImpl.h
===================================================================
--- llvm/include/llvm/Analysis/TargetTransformInfoImpl.h
+++ llvm/include/llvm/Analysis/TargetTransformInfoImpl.h
@@ -814,6 +814,7 @@
     case Intrinsic::sideeffect:
     case Intrinsic::dbg_declare:
     case Intrinsic::dbg_value:
+    case Intrinsic::dbg_derefval:
     case Intrinsic::dbg_label:
     case Intrinsic::invariant_start:
     case Intrinsic::invariant_end:
Index: llvm/docs/SourceLevelDebugging.rst
===================================================================
--- llvm/docs/SourceLevelDebugging.rst
+++ llvm/docs/SourceLevelDebugging.rst
@@ -250,6 +250,38 @@
 be indirect (i.e, a pointer to the source variable), provided that interpreting
 the complex expression derives the direct value.
 
+``llvm.dbg.derefval``
+^^^^^^^^^^^^^^^^^^^^^
+
+.. code-block:: llvm
+
+  void @llvm.dbg.derefval(metadata, metadata, metadata)
+
+This intrinsic is identical to `llvm.dbg.value`, except that it is used to
+describe dereferenced value of pointer variable. The first argument is metadata.
+The second argument is a `local variable <LangRef.html#dilocalvariable>`_
+containing a description of the variable.  The third argument is a
+`complex expression <LangRef.html#diexpression>`_. The first argument can be
+interpreted based on the third argument. If the third argument represents
+DW_OP_LLVM_implicit_pointer, the first argument is
+ `local variable <LangRef.html#dilocalvariable>`_ , otherwise it is the value
+(wrapped as metadata).
+
+An `llvm.dbg.derefval` intrinsic is usefull when location which the variable
+points to is optimized out, but the dereferenced value is known.
+
+.. code-block:: text
+
+    call void @llvm.dbg.derefval(metadata !1, metadata !2,
+          metadata !DIExpression(DW_OP_LLVM_implicit_pointer,
+                                 DW_OP_LLVM_arg0, 0))
+    !1 = !DILocalVariable(name: "arr", ...) ; int arr[5]
+    !2 = !DILocalVariable(name: "ptr", ...) ; int *ptr; ptr=arr;
+    ...
+    call void @llvm.dbg.derefval(metadata i32 1, metadata !1,
+                         metadata !DIExpression(DW_OP_LLVM_arg0))
+    !1 = !DILocalVariable(name: "ptr", ...) ; int *ptr;tmp=1;ptr=&tmp;
+
 Object lifetimes and scoping
 ============================
 
Index: lldb/source/Expression/IRInterpreter.cpp
===================================================================
--- lldb/source/Expression/IRInterpreter.cpp
+++ lldb/source/Expression/IRInterpreter.cpp
@@ -81,6 +81,7 @@
       break;
     case llvm::Intrinsic::dbg_declare:
     case llvm::Intrinsic::dbg_value:
+    case llvm::Intrinsic::dbg_derefval:
       return true;
     }
   }
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to