[llvm] c727056 - Partial Reapply "[DebugInfo] Use variadic debug values to salvage BinOps and GEP instrs with non-const operands"

Stephen Tozer via llvm-commits llvm-commits at lists.llvm.org
Thu Jun 24 01:49:28 PDT 2021


Author: Stephen Tozer
Date: 2021-06-24T09:46:38+01:00
New Revision: c72705678c4733c83233b71b66a904cc8a0910e5

URL: https://github.com/llvm/llvm-project/commit/c72705678c4733c83233b71b66a904cc8a0910e5
DIFF: https://github.com/llvm/llvm-project/commit/c72705678c4733c83233b71b66a904cc8a0910e5.diff

LOG: Partial Reapply "[DebugInfo] Use variadic debug values to salvage BinOps and GEP instrs with non-const operands"

This is a partial reapply of the original commit and the followup commit
that were previously reverted; this reapply also includes a small fix
for a potential source of non-determinism, but also has a small change
to turn off variadic debug value salvaging, to ensure that any future
revert/reapply steps to disable and renable this feature do not risk
causing conflicts.

Differential Revision: https://reviews.llvm.org/D91722

This reverts commit 386b66b2fc297cda121a3cc8a36887a6ecbcfc68.

Added: 
    llvm/test/DebugInfo/limit-arglist-size.ll
    llvm/test/DebugInfo/salvage-gep.ll
    llvm/test/DebugInfo/salvage-nonconst-binop.ll

Modified: 
    llvm/include/llvm/IR/DebugInfoMetadata.h
    llvm/include/llvm/IR/Instructions.h
    llvm/include/llvm/IR/IntrinsicInst.h
    llvm/include/llvm/IR/Operator.h
    llvm/include/llvm/Transforms/Utils/Local.h
    llvm/lib/CodeGen/AsmPrinter/DebugLocEntry.h
    llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
    llvm/lib/IR/DebugInfoMetadata.cpp
    llvm/lib/IR/Instructions.cpp
    llvm/lib/IR/IntrinsicInst.cpp
    llvm/lib/IR/Operator.cpp
    llvm/lib/Transforms/Coroutines/CoroFrame.cpp
    llvm/lib/Transforms/Utils/Local.cpp
    llvm/test/Transforms/InstCombine/debuginfo-sink.ll
    llvm/test/Transforms/Reassociate/undef_intrinsics_when_deleting_instructions.ll

Removed: 
    


################################################################################
diff  --git a/llvm/include/llvm/IR/DebugInfoMetadata.h b/llvm/include/llvm/IR/DebugInfoMetadata.h
index e5e41e288411a..20a032f049093 100644
--- a/llvm/include/llvm/IR/DebugInfoMetadata.h
+++ b/llvm/include/llvm/IR/DebugInfoMetadata.h
@@ -2592,6 +2592,16 @@ class DIExpression : public MDNode {
   // return it's sign information.
   llvm::Optional<SignedOrUnsignedConstant> isConstant() const;
 
+  /// Return the number of unique location operands referred to (via
+  /// DW_OP_LLVM_arg) in this expression; this is not necessarily the number of
+  /// instances of DW_OP_LLVM_arg within the expression.
+  /// For example, for the expression:
+  ///   (DW_OP_LLVM_arg 0, DW_OP_LLVM_arg 1, DW_OP_plus,
+  ///    DW_OP_LLVM_arg 0, DW_OP_mul)
+  /// This function would return 2, as there are two unique location operands
+  /// (0 and 1).
+  uint64_t getNumLocationOperands() const;
+
   using element_iterator = ArrayRef<uint64_t>::iterator;
 
   element_iterator elements_begin() const { return getElements().begin(); }
@@ -2739,6 +2749,10 @@ class DIExpression : public MDNode {
   /// return true with an offset of zero.
   bool extractIfOffset(int64_t &Offset) const;
 
+  /// Returns true iff this DIExpression contains at least one instance of
+  /// `DW_OP_LLVM_arg, n` for all n in [0, N).
+  bool hasAllLocationOps(unsigned N) const;
+
   /// Checks if the last 4 elements of the expression are DW_OP_constu <DWARF
   /// Address Space> DW_OP_swap DW_OP_xderef and extracts the <DWARF Address
   /// Space>.

diff  --git a/llvm/include/llvm/IR/Instructions.h b/llvm/include/llvm/IR/Instructions.h
index 5b334493eb413..b911c34523788 100644
--- a/llvm/include/llvm/IR/Instructions.h
+++ b/llvm/include/llvm/IR/Instructions.h
@@ -17,6 +17,7 @@
 
 #include "llvm/ADT/ArrayRef.h"
 #include "llvm/ADT/Bitfields.h"
+#include "llvm/ADT/MapVector.h"
 #include "llvm/ADT/None.h"
 #include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/SmallVector.h"
@@ -1152,7 +1153,9 @@ class GetElementPtrInst : public Instruction {
   /// must be at least as wide as the IntPtr type for the address space of
   /// the base GEP pointer.
   bool accumulateConstantOffset(const DataLayout &DL, APInt &Offset) const;
-
+  bool collectOffset(const DataLayout &DL, unsigned BitWidth,
+                     MapVector<Value *, APInt> &VariableOffsets,
+                     APInt &ConstantOffset) const;
   // Methods for support type inquiry through isa, cast, and dyn_cast:
   static bool classof(const Instruction *I) {
     return (I->getOpcode() == Instruction::GetElementPtr);

diff  --git a/llvm/include/llvm/IR/IntrinsicInst.h b/llvm/include/llvm/IR/IntrinsicInst.h
index e28544b6c0970..606c2b570c1b7 100644
--- a/llvm/include/llvm/IR/IntrinsicInst.h
+++ b/llvm/include/llvm/IR/IntrinsicInst.h
@@ -204,6 +204,11 @@ class DbgVariableIntrinsic : public DbgInfoIntrinsic {
 
   void replaceVariableLocationOp(Value *OldValue, Value *NewValue);
   void replaceVariableLocationOp(unsigned OpIdx, Value *NewValue);
+  /// Adding a new location operand will always result in this intrinsic using
+  /// an ArgList, and must always be accompanied by a new expression that uses
+  /// the new operand.
+  void addVariableLocationOps(ArrayRef<Value *> NewValues,
+                              DIExpression *NewExpr);
 
   void setVariable(DILocalVariable *NewVar) {
     setArgOperand(1, MetadataAsValue::get(NewVar->getContext(), NewVar));

diff  --git a/llvm/include/llvm/IR/Operator.h b/llvm/include/llvm/IR/Operator.h
index 03bcea3d91f62..46c1dfc3e7350 100644
--- a/llvm/include/llvm/IR/Operator.h
+++ b/llvm/include/llvm/IR/Operator.h
@@ -14,6 +14,7 @@
 #ifndef LLVM_IR_OPERATOR_H
 #define LLVM_IR_OPERATOR_H
 
+#include "llvm/ADT/MapVector.h"
 #include "llvm/ADT/None.h"
 #include "llvm/ADT/Optional.h"
 #include "llvm/IR/Constants.h"
@@ -576,6 +577,12 @@ class GEPOperator
       Type *SourceType, ArrayRef<const Value *> Index, const DataLayout &DL,
       APInt &Offset,
       function_ref<bool(Value &, APInt &)> ExternalAnalysis = nullptr);
+
+  /// Collect the offset of this GEP as a map of Values to their associated
+  /// APInt multipliers, as well as a total Constant Offset.
+  bool collectOffset(const DataLayout &DL, unsigned BitWidth,
+                     MapVector<Value *, APInt> &VariableOffsets,
+                     APInt &ConstantOffset) const;
 };
 
 class PtrToIntOperator

diff  --git a/llvm/include/llvm/Transforms/Utils/Local.h b/llvm/include/llvm/Transforms/Utils/Local.h
index 9208ae8f2ad59..56dac033990cc 100644
--- a/llvm/include/llvm/Transforms/Utils/Local.h
+++ b/llvm/include/llvm/Transforms/Utils/Local.h
@@ -298,7 +298,8 @@ void salvageDebugInfoForDbgValues(Instruction &I,
 /// appended to the expression. \p LocNo: the index of the location operand to
 /// which \p I applies, should be 0 for debug info without a DIArgList.
 DIExpression *salvageDebugInfoImpl(Instruction &I, DIExpression *DIExpr,
-                                   bool StackVal, unsigned LocNo);
+                                   bool StackVal, unsigned LocNo,
+                                   SmallVectorImpl<Value *> &AdditionalValues);
 
 /// Point debug users of \p From to \p To or salvage them. Use this function
 /// only when replacing all uses of \p From with \p To, with a guarantee that

diff  --git a/llvm/lib/CodeGen/AsmPrinter/DebugLocEntry.h b/llvm/lib/CodeGen/AsmPrinter/DebugLocEntry.h
index 525b839d67a0a..62ebadaf3cbeb 100644
--- a/llvm/lib/CodeGen/AsmPrinter/DebugLocEntry.h
+++ b/llvm/lib/CodeGen/AsmPrinter/DebugLocEntry.h
@@ -121,11 +121,6 @@ class DbgValueLoc {
     // Currently, DBG_VALUE_VAR expressions must use stack_value.
     assert(Expr && Expr->isValid() &&
            is_contained(Locs, dwarf::DW_OP_stack_value));
-    for (DbgValueLocEntry &Entry : ValueLocEntries) {
-      assert(!Entry.isConstantFP() && !Entry.isConstantInt() &&
-             "Constant values should only be present in non-variadic "
-             "DBG_VALUEs.");
-    }
 #endif
   }
 
@@ -142,11 +137,6 @@ class DbgValueLoc {
       // Currently, DBG_VALUE_VAR expressions must use stack_value.
       assert(Expr && Expr->isValid() &&
              is_contained(Expr->getElements(), dwarf::DW_OP_stack_value));
-      for (DbgValueLocEntry &Entry : ValueLocEntries) {
-        assert(!Entry.isConstantFP() && !Entry.isConstantInt() &&
-               "Constant values should only be present in non-variadic "
-               "DBG_VALUEs.");
-      }
     }
 #endif
   }

diff  --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
index fd576eaa76aae..b63246ac671b7 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
@@ -1248,6 +1248,10 @@ void SelectionDAGBuilder::resolveDanglingDebugInfo(const Value *V,
 }
 
 void SelectionDAGBuilder::salvageUnresolvedDbgValue(DanglingDebugInfo &DDI) {
+  // TODO: For the variadic implementation, instead of only checking the fail
+  // state of `handleDebugValue`, we need know specifically which values were
+  // invalid, so that we attempt to salvage only those values when processing
+  // a DIArgList.
   assert(!DDI.getDI()->hasArgList() &&
          "Not implemented for variadic dbg_values");
   Value *V = DDI.getDI()->getValue(0);
@@ -1271,16 +1275,21 @@ void SelectionDAGBuilder::salvageUnresolvedDbgValue(DanglingDebugInfo &DDI) {
   while (isa<Instruction>(V)) {
     Instruction &VAsInst = *cast<Instruction>(V);
     // Temporary "0", awaiting real implementation.
-    DIExpression *NewExpr = salvageDebugInfoImpl(VAsInst, Expr, StackValue, 0);
+    SmallVector<Value *, 4> AdditionalValues;
+    DIExpression *SalvagedExpr =
+        salvageDebugInfoImpl(VAsInst, Expr, StackValue, 0, AdditionalValues);
 
     // If we cannot salvage any further, and haven't yet found a suitable debug
     // expression, bail out.
-    if (!NewExpr)
+    // TODO: If AdditionalValues isn't empty, then the salvage can only be
+    // represented with a DBG_VALUE_LIST, so we give up. When we have support
+    // here for variadic dbg_values, remove that condition.
+    if (!SalvagedExpr || !AdditionalValues.empty())
       break;
 
     // New value and expr now represent this debuginfo.
     V = VAsInst.getOperand(0);
-    Expr = NewExpr;
+    Expr = SalvagedExpr;
 
     // Some kind of simplification occurred: check whether the operand of the
     // salvaged debug expression can be encoded in this DAG.

diff  --git a/llvm/lib/IR/DebugInfoMetadata.cpp b/llvm/lib/IR/DebugInfoMetadata.cpp
index 5e8eaacfbdc79..7b0dab799e1a9 100644
--- a/llvm/lib/IR/DebugInfoMetadata.cpp
+++ b/llvm/lib/IR/DebugInfoMetadata.cpp
@@ -1251,6 +1251,17 @@ bool DIExpression::extractIfOffset(int64_t &Offset) const {
   return false;
 }
 
+bool DIExpression::hasAllLocationOps(unsigned N) const {
+  SmallDenseSet<uint64_t, 4> SeenOps;
+  for (auto ExprOp : expr_ops())
+    if (ExprOp.getOp() == dwarf::DW_OP_LLVM_arg)
+      SeenOps.insert(ExprOp.getArg(0));
+  for (uint64_t Idx = 0; Idx < N; ++Idx)
+    if (!is_contained(SeenOps, Idx))
+      return false;
+  return true;
+}
+
 const DIExpression *DIExpression::extractAddressClass(const DIExpression *Expr,
                                                       unsigned &AddrClass) {
   // FIXME: This seems fragile. Nothing that verifies that these elements
@@ -1465,6 +1476,16 @@ Optional<DIExpression *> DIExpression::createFragmentExpression(
   return DIExpression::get(Expr->getContext(), Ops);
 }
 
+uint64_t DIExpression::getNumLocationOperands() const {
+  uint64_t Result = 0;
+  for (auto ExprOp : expr_ops())
+    if (ExprOp.getOp() == dwarf::DW_OP_LLVM_arg)
+      Result = std::max(Result, ExprOp.getArg(0) + 1);
+  assert(hasAllLocationOps(Result) &&
+         "Expression is missing one or more location operands.");
+  return Result;
+}
+
 llvm::Optional<DIExpression::SignedOrUnsignedConstant>
 DIExpression::isConstant() const {
 

diff  --git a/llvm/lib/IR/Instructions.cpp b/llvm/lib/IR/Instructions.cpp
index 73a505324f665..f02de8eed21b0 100644
--- a/llvm/lib/IR/Instructions.cpp
+++ b/llvm/lib/IR/Instructions.cpp
@@ -1804,6 +1804,15 @@ bool GetElementPtrInst::accumulateConstantOffset(const DataLayout &DL,
   return cast<GEPOperator>(this)->accumulateConstantOffset(DL, Offset);
 }
 
+bool GetElementPtrInst::collectOffset(
+    const DataLayout &DL, unsigned BitWidth,
+    MapVector<Value *, APInt> &VariableOffsets,
+    APInt &ConstantOffset) const {
+  // Delegate to the generic GEPOperator implementation.
+  return cast<GEPOperator>(this)->collectOffset(DL, BitWidth, VariableOffsets,
+                                                ConstantOffset);
+}
+
 //===----------------------------------------------------------------------===//
 //                           ExtractElementInst Implementation
 //===----------------------------------------------------------------------===//

diff  --git a/llvm/lib/IR/IntrinsicInst.cpp b/llvm/lib/IR/IntrinsicInst.cpp
index d025bc6df44ac..776590af9a32e 100644
--- a/llvm/lib/IR/IntrinsicInst.cpp
+++ b/llvm/lib/IR/IntrinsicInst.cpp
@@ -118,6 +118,23 @@ void DbgVariableIntrinsic::replaceVariableLocationOp(unsigned OpIdx,
       0, MetadataAsValue::get(getContext(), DIArgList::get(getContext(), MDs)));
 }
 
+void DbgVariableIntrinsic::addVariableLocationOps(ArrayRef<Value *> NewValues,
+                                                  DIExpression *NewExpr) {
+  assert(NewExpr->hasAllLocationOps(getNumVariableLocationOps() +
+                                    NewValues.size()) &&
+         "NewExpr for debug variable intrinsic does not reference every "
+         "location operand.");
+  assert(!is_contained(NewValues, nullptr) && "New values must be non-null");
+  setArgOperand(2, MetadataAsValue::get(getContext(), NewExpr));
+  SmallVector<ValueAsMetadata *, 4> MDs;
+  for (auto *VMD : location_ops())
+    MDs.push_back(getAsMetadata(VMD));
+  for (auto *VMD : NewValues)
+    MDs.push_back(getAsMetadata(VMD));
+  setArgOperand(
+      0, MetadataAsValue::get(getContext(), DIArgList::get(getContext(), MDs)));
+}
+
 Optional<uint64_t> DbgVariableIntrinsic::getFragmentSizeInBits() const {
   if (auto Fragment = getExpression()->getFragmentInfo())
     return Fragment->SizeInBits;

diff  --git a/llvm/lib/IR/Operator.cpp b/llvm/lib/IR/Operator.cpp
index 69181f35827bf..18a1c84933e0a 100644
--- a/llvm/lib/IR/Operator.cpp
+++ b/llvm/lib/IR/Operator.cpp
@@ -142,4 +142,61 @@ bool GEPOperator::accumulateConstantOffset(
   }
   return true;
 }
+
+bool GEPOperator::collectOffset(
+    const DataLayout &DL, unsigned BitWidth,
+    MapVector<Value *, APInt> &VariableOffsets,
+    APInt &ConstantOffset) const {
+  assert(BitWidth == DL.getIndexSizeInBits(getPointerAddressSpace()) &&
+         "The offset bit width does not match DL specification.");
+
+  auto CollectConstantOffset = [&](APInt Index, uint64_t Size) {
+    Index = Index.sextOrTrunc(BitWidth);
+    APInt IndexedSize = APInt(BitWidth, Size);
+    ConstantOffset += Index * IndexedSize;
+  };
+
+  for (gep_type_iterator GTI = gep_type_begin(this), GTE = gep_type_end(this);
+       GTI != GTE; ++GTI) {
+    // Scalable vectors are multiplied by a runtime constant.
+    bool ScalableType = isa<ScalableVectorType>(GTI.getIndexedType());
+
+    Value *V = GTI.getOperand();
+    StructType *STy = GTI.getStructTypeOrNull();
+    // Handle ConstantInt if possible.
+    if (auto ConstOffset = dyn_cast<ConstantInt>(V)) {
+      if (ConstOffset->isZero())
+        continue;
+      // If the type is scalable and the constant is not zero (vscale * n * 0 =
+      // 0) bailout.
+      // TODO: If the runtime value is accessible at any point before DWARF
+      // emission, then we could potentially keep a forward reference to it
+      // in the debug value to be filled in later.
+      if (ScalableType)
+        return false;
+      // Handle a struct index, which adds its field offset to the pointer.
+      if (STy) {
+        unsigned ElementIdx = ConstOffset->getZExtValue();
+        const StructLayout *SL = DL.getStructLayout(STy);
+        // Element offset is in bytes.
+        CollectConstantOffset(APInt(BitWidth, SL->getElementOffset(ElementIdx)),
+                              1);
+        continue;
+      }
+      CollectConstantOffset(ConstOffset->getValue(),
+                            DL.getTypeAllocSize(GTI.getIndexedType()));
+      continue;
+    }
+
+    if (STy || ScalableType)
+      return false;
+    // Insert an initial offset of 0 for V iff none exists already, then
+    // increment the offset by IndexedSize.
+    VariableOffsets.insert({V, APInt(BitWidth, 0)});
+    APInt IndexedSize =
+        APInt(BitWidth, DL.getTypeAllocSize(GTI.getIndexedType()));
+    VariableOffsets[V] += IndexedSize;
+  }
+  return true;
+}
 } // namespace llvm

diff  --git a/llvm/lib/Transforms/Coroutines/CoroFrame.cpp b/llvm/lib/Transforms/Coroutines/CoroFrame.cpp
index 5dcfc4525e7a6..a376b4d3d6351 100644
--- a/llvm/lib/Transforms/Coroutines/CoroFrame.cpp
+++ b/llvm/lib/Transforms/Coroutines/CoroFrame.cpp
@@ -2488,10 +2488,15 @@ void coro::salvageDebugInfo(
     } else if (auto *StInst = dyn_cast<StoreInst>(Storage)) {
       Storage = StInst->getOperand(0);
     } else if (auto *GEPInst = dyn_cast<GetElementPtrInst>(Storage)) {
-      Expr = llvm::salvageDebugInfoImpl(*GEPInst, Expr,
-                                        /*WithStackValue=*/false, 0);
-      if (!Expr)
-        return;
+      SmallVector<Value *> AdditionalValues;
+      DIExpression *SalvagedExpr = llvm::salvageDebugInfoImpl(
+          *GEPInst, Expr,
+          /*WithStackValue=*/false, 0, AdditionalValues);
+      // Debug declares cannot currently handle additional location
+      // operands.
+      if (!SalvagedExpr || !AdditionalValues.empty())
+        break;
+      Expr = SalvagedExpr;
       Storage = GEPInst->getOperand(0);
     } else if (auto *BCInst = dyn_cast<llvm::BitCastInst>(Storage))
       Storage = BCInst->getOperand(0);

diff  --git a/llvm/lib/Transforms/Utils/Local.cpp b/llvm/lib/Transforms/Utils/Local.cpp
index c228df2f94a7e..cfbc24c0001fa 100644
--- a/llvm/lib/Transforms/Utils/Local.cpp
+++ b/llvm/lib/Transforms/Utils/Local.cpp
@@ -1718,6 +1718,9 @@ void llvm::salvageDebugInfo(Instruction &I) {
 
 void llvm::salvageDebugInfoForDbgValues(
     Instruction &I, ArrayRef<DbgVariableIntrinsic *> DbgUsers) {
+  // This is an arbitrary chosen limit on the maximum number of values we can
+  // salvage up to in a DIArgList, used for performance reasons.
+  const unsigned MaxDebugArgs = 16;
   bool Salvaged = false;
 
   for (auto *DII : DbgUsers) {
@@ -1730,17 +1733,34 @@ void llvm::salvageDebugInfoForDbgValues(
         is_contained(DIILocation, &I) &&
         "DbgVariableIntrinsic must use salvaged instruction as its location");
     unsigned LocNo = std::distance(DIILocation.begin(), find(DIILocation, &I));
-
-    DIExpression *DIExpr =
-        salvageDebugInfoImpl(I, DII->getExpression(), StackValue, LocNo);
+    SmallVector<Value *, 4> AdditionalValues;
+    DIExpression *SalvagedExpr = salvageDebugInfoImpl(
+        I, DII->getExpression(), StackValue, LocNo, AdditionalValues);
 
     // salvageDebugInfoImpl should fail on examining the first element of
     // DbgUsers, or none of them.
-    if (!DIExpr)
+    if (!SalvagedExpr)
       break;
 
     DII->replaceVariableLocationOp(&I, I.getOperand(0));
-    DII->setExpression(DIExpr);
+    if (AdditionalValues.empty()) {
+      DII->setExpression(SalvagedExpr);
+    } else if (isa<DbgValueInst>(DII) &&
+               DII->getNumVariableLocationOps() + AdditionalValues.size() <=
+                   MaxDebugArgs) {
+      // TODO: Uncomment the line below and delete the two beneath it to enable
+      // salvaging of dbg.values with multiple location operands.
+      // DII->addVariableLocationOps(AdditionalValues, SalvagedExpr);
+      Value *Undef = UndefValue::get(I.getOperand(0)->getType());
+      DII->replaceVariableLocationOp(I.getOperand(0), Undef);
+    } else {
+      // Do not salvage using DIArgList for dbg.addr/dbg.declare, as it is
+      // currently only valid for stack value expressions.
+      // Also do not salvage if the resulting DIArgList would contain an
+      // unreasonably large number of values.
+      Value *Undef = UndefValue::get(I.getOperand(0)->getType());
+      DII->replaceVariableLocationOp(I.getOperand(0), Undef);
+    }
     LLVM_DEBUG(dbgs() << "SALVAGE: " << *DII << '\n');
     Salvaged = true;
   }
@@ -1755,12 +1775,27 @@ void llvm::salvageDebugInfoForDbgValues(
 }
 
 bool getSalvageOpsForGEP(GetElementPtrInst *GEP, const DataLayout &DL,
-                         SmallVectorImpl<uint64_t> &Opcodes) {
+                         uint64_t CurrentLocOps,
+                         SmallVectorImpl<uint64_t> &Opcodes,
+                         SmallVectorImpl<Value *> &AdditionalValues) {
   unsigned BitWidth = DL.getIndexSizeInBits(GEP->getPointerAddressSpace());
-  // Rewrite a constant GEP into a DIExpression.
+  // Rewrite a GEP into a DIExpression.
+  MapVector<Value *, APInt> VariableOffsets;
   APInt ConstantOffset(BitWidth, 0);
-  if (!GEP->accumulateConstantOffset(DL, ConstantOffset))
+  if (!GEP->collectOffset(DL, BitWidth, VariableOffsets, ConstantOffset))
     return false;
+  if (!VariableOffsets.empty() && !CurrentLocOps) {
+    Opcodes.insert(Opcodes.begin(), {dwarf::DW_OP_LLVM_arg, 0});
+    CurrentLocOps = 1;
+  }
+  for (auto Offset : VariableOffsets) {
+    AdditionalValues.push_back(Offset.first);
+    assert(Offset.second.isStrictlyPositive() &&
+           "Expected strictly positive multiplier for offset.");
+    Opcodes.append({dwarf::DW_OP_LLVM_arg, CurrentLocOps++, dwarf::DW_OP_constu,
+                    Offset.second.getZExtValue(), dwarf::DW_OP_mul,
+                    dwarf::DW_OP_plus});
+  }
   DIExpression::appendOffset(Opcodes, ConstantOffset.getSExtValue());
   return true;
 }
@@ -1795,23 +1830,35 @@ uint64_t getDwarfOpForBinOp(Instruction::BinaryOps Opcode) {
   }
 }
 
-bool getSalvageOpsForBinOp(BinaryOperator *BI,
-                           SmallVectorImpl<uint64_t> &Opcodes) {
-  // Rewrite binary operations with constant integer operands.
+bool getSalvageOpsForBinOp(BinaryOperator *BI, uint64_t CurrentLocOps,
+                           SmallVectorImpl<uint64_t> &Opcodes,
+                           SmallVectorImpl<Value *> &AdditionalValues) {
+  // Handle binary operations with constant integer operands as a special case.
   auto *ConstInt = dyn_cast<ConstantInt>(BI->getOperand(1));
-  if (!ConstInt || ConstInt->getBitWidth() > 64)
+  // Values wider than 64 bits cannot be represented within a DIExpression.
+  if (ConstInt && ConstInt->getBitWidth() > 64)
     return false;
-  uint64_t Val = ConstInt->getSExtValue();
+
   Instruction::BinaryOps BinOpcode = BI->getOpcode();
-  // Add or Sub Instructions with a constant operand can potentially be
-  // simplified.
-  if (BinOpcode == Instruction::Add || BinOpcode == Instruction::Sub) {
-    uint64_t Offset = BinOpcode == Instruction::Add ? Val : -int64_t(Val);
-    DIExpression::appendOffset(Opcodes, Offset);
-    return true;
+  // Push any Constant Int operand onto the expression stack.
+  if (ConstInt) {
+    uint64_t Val = ConstInt->getSExtValue();
+    // Add or Sub Instructions with a constant operand can potentially be
+    // simplified.
+    if (BinOpcode == Instruction::Add || BinOpcode == Instruction::Sub) {
+      uint64_t Offset = BinOpcode == Instruction::Add ? Val : -int64_t(Val);
+      DIExpression::appendOffset(Opcodes, Offset);
+      return true;
+    }
+    Opcodes.append({dwarf::DW_OP_constu, Val});
+  } else {
+    if (!CurrentLocOps) {
+      Opcodes.append({dwarf::DW_OP_LLVM_arg, 0});
+      CurrentLocOps = 1;
+    }
+    Opcodes.append({dwarf::DW_OP_LLVM_arg, CurrentLocOps});
+    AdditionalValues.push_back(BI->getOperand(1));
   }
-  // Add constant int operand to expression stack.
-  Opcodes.append({dwarf::DW_OP_constu, Val});
 
   // Add salvaged binary operator to expression stack, if it has a valid
   // representation in a DIExpression.
@@ -1823,9 +1870,11 @@ bool getSalvageOpsForBinOp(BinaryOperator *BI,
   return true;
 }
 
-DIExpression *llvm::salvageDebugInfoImpl(Instruction &I,
-                                         DIExpression *SrcDIExpr,
-                                         bool WithStackValue, unsigned LocNo) {
+DIExpression *
+llvm::salvageDebugInfoImpl(Instruction &I, DIExpression *SrcDIExpr,
+                           bool WithStackValue, unsigned LocNo,
+                           SmallVectorImpl<Value *> &AdditionalValues) {
+  uint64_t CurrentLocOps = SrcDIExpr->getNumLocationOperands();
   auto &M = *I.getModule();
   auto &DL = M.getDataLayout();
 
@@ -1839,7 +1888,7 @@ DIExpression *llvm::salvageDebugInfoImpl(Instruction &I,
   };
 
   // initializer-list helper for applying operators to the source DIExpression.
-  auto applyOps = [&](ArrayRef<uint64_t> Opcodes) -> DIExpression * {
+  auto applyOps = [&](ArrayRef<uint64_t> Opcodes) {
     SmallVector<uint64_t, 8> Ops(Opcodes.begin(), Opcodes.end());
     return doSalvage(Ops);
   };
@@ -1865,15 +1914,15 @@ DIExpression *llvm::salvageDebugInfoImpl(Instruction &I,
 
   SmallVector<uint64_t, 8> Ops;
   if (auto *GEP = dyn_cast<GetElementPtrInst>(&I)) {
-    if (getSalvageOpsForGEP(GEP, DL, Ops))
+    if (getSalvageOpsForGEP(GEP, DL, CurrentLocOps, Ops, AdditionalValues))
       return doSalvage(Ops);
   } else if (auto *BI = dyn_cast<BinaryOperator>(&I)) {
-    if (getSalvageOpsForBinOp(BI, Ops))
+    if (getSalvageOpsForBinOp(BI, CurrentLocOps, Ops, AdditionalValues))
       return doSalvage(Ops);
   }
-    // *Not* to do: we should not attempt to salvage load instructions,
-    // because the validity and lifetime of a dbg.value containing
-    // DW_OP_deref becomes 
diff icult to analyze. See PR40628 for examples.
+  // *Not* to do: we should not attempt to salvage load instructions,
+  // because the validity and lifetime of a dbg.value containing
+  // DW_OP_deref becomes 
diff icult to analyze. See PR40628 for examples.
   return nullptr;
 }
 

diff  --git a/llvm/test/DebugInfo/limit-arglist-size.ll b/llvm/test/DebugInfo/limit-arglist-size.ll
new file mode 100644
index 0000000000000..951cc0e1c3cc7
--- /dev/null
+++ b/llvm/test/DebugInfo/limit-arglist-size.ll
@@ -0,0 +1,63 @@
+; RUN: opt -S -instcombine %s -o - | FileCheck %s
+
+; For performance reasons, we currently limit the number of values that can be
+; referenced by a dbg.value to 16. This test checks that we do not exceed this
+; limit during salvaging.
+
+; CHECK: DIArgList(i32 undef
+; CHECK-NOT: DW_OP_LLVM_arg, 16
+
+target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+define i32 @_Z3foov() local_unnamed_addr !dbg !9 {
+entry:
+  %call = call i32 @_Z3barv(), !dbg !14
+  %call1 = call i32 @_Z3barv(), !dbg !14
+  %add = add nsw i32 %call, %call1, !dbg !14
+  %call2 = call i32 @_Z3barv(), !dbg !14
+  %call4 = call i32 @_Z3barv(), !dbg !14
+  %call6 = call i32 @_Z3barv(), !dbg !14
+  %call8 = call i32 @_Z3barv(), !dbg !14
+  %call10 = call i32 @_Z3barv(), !dbg !14
+  %call12 = call i32 @_Z3barv(), !dbg !14
+  %call14 = call i32 @_Z3barv(), !dbg !14
+  %call16 = call i32 @_Z3barv(), !dbg !14
+  %call18 = call i32 @_Z3barv(), !dbg !14
+  %call20 = call i32 @_Z3barv(), !dbg !14
+  %call22 = call i32 @_Z3barv(), !dbg !14
+  %call24 = call i32 @_Z3barv(), !dbg !14
+  %call26 = call i32 @_Z3barv(), !dbg !14
+  %call28 = call i32 @_Z3barv(), !dbg !14
+  %call30 = call i32 @_Z3barv(), !dbg !14
+  call void @llvm.dbg.value(metadata !DIArgList(i32 %add, i32 %call30, i32 %call28, i32 %call26, i32 %call24, i32 %call22, i32 %call20, i32 %call18, i32 %call16, i32 %call14, i32 %call12, i32 %call10, i32 %call8, i32 %call6, i32 %call4, i32 %call2), metadata !15, metadata !DIExpression(DW_OP_LLVM_arg, 0, DW_OP_LLVM_arg, 15, DW_OP_plus, DW_OP_LLVM_arg, 14, DW_OP_plus, DW_OP_LLVM_arg, 13, DW_OP_plus, DW_OP_LLVM_arg, 12, DW_OP_plus, DW_OP_LLVM_arg, 11, DW_OP_plus, DW_OP_LLVM_arg, 10, DW_OP_plus, DW_OP_LLVM_arg, 9, DW_OP_plus, DW_OP_LLVM_arg, 8, DW_OP_plus, DW_OP_LLVM_arg, 7, DW_OP_plus, DW_OP_LLVM_arg, 6, DW_OP_plus, DW_OP_LLVM_arg, 5, DW_OP_plus, DW_OP_LLVM_arg, 4, DW_OP_plus, DW_OP_LLVM_arg, 3, DW_OP_plus, DW_OP_LLVM_arg, 2, DW_OP_plus, DW_OP_LLVM_arg, 1, DW_OP_plus, DW_OP_stack_value)), !dbg !16
+  %call32 = call i32 @_Z3barv(), !dbg !17
+  ret i32 %call32, !dbg !17
+}
+
+declare dso_local i32 @_Z3barv() local_unnamed_addr
+
+declare void @llvm.dbg.value(metadata, metadata, metadata)
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!3, !4, !5, !6, !7}
+!llvm.ident = !{!8}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !1, producer: "clang version 13.0.0", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, splitDebugInlining: false, nameTableKind: None)
+!1 = !DIFile(filename: "limit-arglist-size.cpp", directory: "/")
+!2 = !{}
+!3 = !{i32 7, !"Dwarf Version", i32 4}
+!4 = !{i32 2, !"Debug Info Version", i32 3}
+!5 = !{i32 1, !"wchar_size", i32 4}
+!6 = !{i32 7, !"uwtable", i32 1}
+!7 = !{i32 7, !"frame-pointer", i32 2}
+!8 = !{!"clang version 13.0.0"}
+!9 = distinct !DISubprogram(name: "foo", linkageName: "_Z3foov", scope: !10, file: !10, line: 3, type: !11, scopeLine: 3, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2)
+!10 = !DIFile(filename: "./limit-arglist-size.cpp", directory: "/")
+!11 = !DISubroutineType(types: !12)
+!12 = !{!13}
+!13 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!14 = !DILocation(line: 4, scope: !9)
+!15 = !DILocalVariable(name: "v16", scope: !9, file: !10, line: 4, type: !13)
+!16 = !DILocation(line: 0, scope: !9)
+!17 = !DILocation(line: 5, scope: !9)

diff  --git a/llvm/test/DebugInfo/salvage-gep.ll b/llvm/test/DebugInfo/salvage-gep.ll
new file mode 100644
index 0000000000000..dfb3b5311083b
--- /dev/null
+++ b/llvm/test/DebugInfo/salvage-gep.ll
@@ -0,0 +1,57 @@
+; XFAIL: *
+; RUN: opt %s -dce -S | FileCheck %s
+
+; Tests the salvaging of GEP instructions, specifically struct indexing and
+; non-constant array indexing.
+
+%struct.S = type { i32, i32 }
+
+; CHECK: call void @llvm.dbg.value(metadata !DIArgList(%struct.S* %ptr, i64 %offset),
+; CHECK-SAME: ![[VAR_OFFSET_PTR:[0-9]+]],
+; CHECK-SAME: !DIExpression(DW_OP_LLVM_arg, 0, DW_OP_LLVM_arg, 1, DW_OP_constu, 8, DW_OP_mul, DW_OP_plus, DW_OP_plus_uconst, 4, DW_OP_stack_value))
+
+; CHECK: ![[VAR_OFFSET_PTR]] = !DILocalVariable(name: "offset_ptr"
+
+define void @"?foo@@YAXPEAUS@@_J at Z"(%struct.S* %ptr, i64 %offset) !dbg !8 {
+entry:
+  call void @llvm.dbg.value(metadata i64 %offset, metadata !20, metadata !DIExpression()), !dbg !24
+  call void @llvm.dbg.value(metadata %struct.S* %ptr, metadata !21, metadata !DIExpression()), !dbg !24
+  %arrayidx = getelementptr inbounds %struct.S, %struct.S* %ptr, i64 %offset, !dbg !25
+  %b = getelementptr inbounds %struct.S, %struct.S* %arrayidx, i32 0, i32 1, !dbg !25
+  call void @llvm.dbg.value(metadata i32* %b, metadata !22, metadata !DIExpression()), !dbg !24
+  ret void, !dbg !26
+}
+
+declare void @llvm.dbg.value(metadata, metadata, metadata)
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!3, !4, !5, !6}
+!llvm.ident = !{!7}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !1, producer: "clang version 11.0.0", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: None)
+!1 = !DIFile(filename: "salvage-gep.cpp", directory: "/")
+!2 = !{}
+!3 = !{i32 2, !"CodeView", i32 1}
+!4 = !{i32 2, !"Debug Info Version", i32 3}
+!5 = !{i32 1, !"wchar_size", i32 2}
+!6 = !{i32 7, !"PIC Level", i32 2}
+!7 = !{!"clang version 11.0.0"}
+!8 = distinct !DISubprogram(name: "foo", linkageName: "?foo@@YAXPEAUS@@_J at Z", scope: !9, file: !9, line: 7, type: !10, scopeLine: 7, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !19)
+!9 = !DIFile(filename: ".\\salvage-gep.cpp", directory: "/")
+!10 = !DISubroutineType(types: !11)
+!11 = !{null, !12, !18}
+!12 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !13, size: 64)
+!13 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "S", file: !9, line: 2, size: 64, flags: DIFlagTypePassByValue, elements: !14, identifier: ".?AUS@@")
+!14 = !{!15, !17}
+!15 = !DIDerivedType(tag: DW_TAG_member, name: "a", scope: !13, file: !9, line: 3, baseType: !16, size: 32)
+!16 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!17 = !DIDerivedType(tag: DW_TAG_member, name: "b", scope: !13, file: !9, line: 4, baseType: !16, size: 32, offset: 32)
+!18 = !DIBasicType(name: "long long int", size: 64, encoding: DW_ATE_signed)
+!19 = !{!20, !21, !22}
+!20 = !DILocalVariable(name: "offset", arg: 2, scope: !8, file: !9, line: 7, type: !18)
+!21 = !DILocalVariable(name: "ptr", arg: 1, scope: !8, file: !9, line: 7, type: !12)
+!22 = !DILocalVariable(name: "offset_ptr", scope: !8, file: !9, line: 8, type: !23)
+!23 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !16, size: 64)
+!24 = !DILocation(line: 0, scope: !8)
+!25 = !DILocation(line: 8, scope: !8)
+!26 = !DILocation(line: 9, scope: !8)

diff  --git a/llvm/test/DebugInfo/salvage-nonconst-binop.ll b/llvm/test/DebugInfo/salvage-nonconst-binop.ll
new file mode 100644
index 0000000000000..f9ee1a6e253c9
--- /dev/null
+++ b/llvm/test/DebugInfo/salvage-nonconst-binop.ll
@@ -0,0 +1,46 @@
+; XFAIL: *
+; RUN: opt %s -dce -S | FileCheck %s
+
+; Tests the salvaging of binary operators that use more than one non-constant
+; SSA value.
+
+; CHECK: call void @llvm.dbg.value(metadata !DIArgList(i32 %a, i32 %b),
+; CHECK-SAME: ![[VAR_C:[0-9]+]],
+; CHECK-SAME: !DIExpression(DW_OP_LLVM_arg, 0, DW_OP_LLVM_arg, 1, DW_OP_plus, DW_OP_stack_value))
+
+; CHECK: ![[VAR_C]] = !DILocalVariable(name: "c"
+
+define i32 @"?multiply@@YAHHH at Z"(i32 %a, i32 %b) !dbg !8 {
+entry:
+  call void @llvm.dbg.value(metadata i32 %b, metadata !12, metadata !DIExpression()), !dbg !13
+  call void @llvm.dbg.value(metadata i32 %a, metadata !14, metadata !DIExpression()), !dbg !13
+  %add = add nsw i32 %a, %b, !dbg !15
+  call void @llvm.dbg.value(metadata i32 %add, metadata !16, metadata !DIExpression()), !dbg !13
+  %mul = mul nsw i32 %a, %b, !dbg !17
+  ret i32 %mul, !dbg !17
+}
+
+declare void @llvm.dbg.value(metadata, metadata, metadata)
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!3, !4, !5, !6}
+!llvm.ident = !{!7}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !1, producer: "clang version 11.0.0", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: None)
+!1 = !DIFile(filename: "test.cpp", directory: "/")
+!2 = !{}
+!3 = !{i32 2, !"CodeView", i32 1}
+!4 = !{i32 2, !"Debug Info Version", i32 3}
+!5 = !{i32 1, !"wchar_size", i32 2}
+!6 = !{i32 7, !"PIC Level", i32 2}
+!7 = !{!"clang version 11.0.0"}
+!8 = distinct !DISubprogram(name: "multiply", linkageName: "?multiply@@YAHHH at Z", scope: !1, file: !1, line: 1, type: !9, scopeLine: 1, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2)
+!9 = !DISubroutineType(types: !10)
+!10 = !{!11, !11, !11}
+!11 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!12 = !DILocalVariable(name: "b", arg: 2, scope: !8, file: !1, line: 1, type: !11)
+!13 = !DILocation(line: 0, scope: !8)
+!14 = !DILocalVariable(name: "a", arg: 1, scope: !8, file: !1, line: 1, type: !11)
+!15 = !DILocation(line: 2, scope: !8)
+!16 = !DILocalVariable(name: "c", scope: !8, file: !1, line: 2, type: !11)
+!17 = !DILocation(line: 3, scope: !8)

diff  --git a/llvm/test/Transforms/InstCombine/debuginfo-sink.ll b/llvm/test/Transforms/InstCombine/debuginfo-sink.ll
index 5a8cc78b08c2d..3fb27637022ad 100644
--- a/llvm/test/Transforms/InstCombine/debuginfo-sink.ll
+++ b/llvm/test/Transforms/InstCombine/debuginfo-sink.ll
@@ -33,23 +33,25 @@ sink1:
 ; value range.
 
 ; CHECK-LABEL: define i32 @bar(
-; CHECK:       call void @llvm.dbg.value(metadata i32* undef,
+; CHECK:       call void @llvm.dbg.value(metadata <vscale x 4 x i32>* undef,
 ; CHECK-NEXT:  br label %sink2
 
-define i32 @bar(i32 *%a, i32 %b) !dbg !70 {
+define i32 @bar(<vscale x 4 x i32>* %a, i32 %b) !dbg !70 {
 entry:
-  %gep = getelementptr i32, i32 *%a, i32 %b
-  call void @llvm.dbg.value(metadata i32* %gep, metadata !73, metadata !12), !dbg !74
+  %gep = getelementptr <vscale x 4 x i32>, <vscale x 4 x i32>* %a, i32 %b
+  call void @llvm.dbg.value(metadata <vscale x 4 x i32>* %gep, metadata !73, metadata !12), !dbg !74
   br label %sink2
 
 sink2:
 ; CHECK-LABEL: sink2:
-; CHECK:       call void @llvm.dbg.value(metadata i32* %gep,
+; CHECK:       call void @llvm.dbg.value(metadata <vscale x 4 x i32>* %gep,
 ; CHECK-SAME:                    metadata !{{[0-9]+}}, metadata !DIExpression())
 ; CHECK-NEXT:  load
+; CHECK-NEXT:  extractelement
 ; CHECK-NEXT:  ret
-  %0 = load i32, i32* %gep
-  ret i32 %0
+  %0 = load <vscale x 4 x i32>, <vscale x 4 x i32>* %gep
+  %extract = extractelement <vscale x 4 x i32> %0, i32 1
+  ret i32 %extract
 }
 
 ; This GEP is sunk, and has multiple debug uses in the same block. Check that

diff  --git a/llvm/test/Transforms/Reassociate/undef_intrinsics_when_deleting_instructions.ll b/llvm/test/Transforms/Reassociate/undef_intrinsics_when_deleting_instructions.ll
index 98c51c5cf8bb3..349da85cc80f7 100644
--- a/llvm/test/Transforms/Reassociate/undef_intrinsics_when_deleting_instructions.ll
+++ b/llvm/test/Transforms/Reassociate/undef_intrinsics_when_deleting_instructions.ll
@@ -1,95 +1,73 @@
-; RUN: opt < %s -reassociate -S | FileCheck %s
+; RUN: opt < %s -reassociate -S | FileCheck %s
+
+; Check that reassociate pass now undefs debug intrinsics that reference a value
+; that gets dropped and cannot be salvaged.
+
+; CHECK-NOT: %add = fadd fast float %a, %b
+; CHECK: call void @llvm.dbg.value(metadata float undef, metadata [[VAR_X:![0-9]+]], metadata !DIExpression())
+
+; CHECK-LABEL: if.then:
+; CHECK-NOT: %add1 = fadd fast float %add, %c
+; CHECK: call void @llvm.dbg.value(metadata float undef, metadata [[VAR_Y:![0-9]+]], metadata !DIExpression())
+; CHECK-LABEL: !0 =
+; CHECK-DAG: [[VAR_Y]] = !DILocalVariable(name: "y"
+; CHECK-DAG: [[VAR_X]] = !DILocalVariable(name: "x"
+
+define float @"?foo@@YAMMMMM at Z"(float %a, float %b, float %c, float %d) !dbg !8 {
+entry:
+  call void @llvm.dbg.value(metadata float %d, metadata !12, metadata !DIExpression()), !dbg !13
+  call void @llvm.dbg.value(metadata float %c, metadata !14, metadata !DIExpression()), !dbg !13
+  call void @llvm.dbg.value(metadata float %b, metadata !15, metadata !DIExpression()), !dbg !13
+  call void @llvm.dbg.value(metadata float %a, metadata !16, metadata !DIExpression()), !dbg !13
+  %add = fadd fast float %a, %b, !dbg !17
+  call void @llvm.dbg.value(metadata float %add, metadata !18, metadata !DIExpression()), !dbg !13
+  %cmp = fcmp fast oeq float %d, 4.000000e+00, !dbg !19
+  br i1 %cmp, label %if.then, label %return, !dbg !19
 
-; Check that reassociate pass now undefs debug intrinsics that reference a value
-; that gets dropped and cannot be salvaged.
+if.then:                                          ; preds = %entry
+  %add1 = fadd fast float %add, %c, !dbg !20
+  call void @llvm.dbg.value(metadata float %add1, metadata !23, metadata !DIExpression()), !dbg !24
+  %sub = fsub fast float %add, 1.200000e+01, !dbg !25
+  %sub2 = fsub fast float %add1, %sub, !dbg !25
+  %mul = fmul fast float %sub2, 2.000000e+01, !dbg !25
+  %div = fdiv fast float %mul, 3.000000e+00, !dbg !25
+  br label %return, !dbg !25
 
-define hidden i32 @main() local_unnamed_addr {
-entry:
-  %foo = alloca i32, align 4, !dbg !20
-  %foo.0.foo.0..sroa_cast = bitcast i32* %foo to i8*, !dbg !20
-  call void @llvm.lifetime.start.p0i8(i64 4, i8* nonnull %foo.0.foo.0..sroa_cast), !dbg !20
-  store volatile i32 4, i32* %foo, align 4, !dbg !20, !tbaa !21
-  %foo.0.foo.0. = load volatile i32, i32* %foo, align 4, !dbg !25, !tbaa !21
-  %foo.0.foo.0.15 = load volatile i32, i32* %foo, align 4, !dbg !27, !tbaa !21
-  %foo.0.foo.0.16 = load volatile i32, i32* %foo, align 4, !dbg !28, !tbaa !21
-  ; CHECK-NOT: %add = add nsw i32 %foo.0.foo.0., %foo.0.foo.0.15
-  %add = add nsw i32 %foo.0.foo.0., %foo.0.foo.0.15, !dbg !29
-  ; CHECK: call void @llvm.dbg.value(metadata i32 undef, metadata [[VAR_A:![0-9]+]], metadata !DIExpression())
-  call void @llvm.dbg.value(metadata i32 %add, metadata !19, metadata !DIExpression()), !dbg !26
-  %foo.0.foo.0.17 = load volatile i32, i32* %foo, align 4, !dbg !30, !tbaa !21
-  %cmp = icmp eq i32 %foo.0.foo.0.17, 4, !dbg !30
-  br i1 %cmp, label %if.then, label %if.end, !dbg !32
-
-  ; CHECK-LABEL: if.then:
-if.then:
-  ; CHECK-NOT: %add1 = add nsw i32 %add, %foo.0.foo.0.16
-  %add1 = add nsw i32 %add, %foo.0.foo.0.16, !dbg !33
-  ; CHECK: call void @llvm.dbg.value(metadata i32 undef, metadata [[VAR_A]], metadata !DIExpression())
-  call void @llvm.dbg.value(metadata i32 %add1, metadata !19, metadata !DIExpression()), !dbg !26
-  ; CHECK: call void @llvm.dbg.value(metadata i32 undef, metadata [[VAR_CHEESE:![0-9]+]], metadata !DIExpression())
-  call void @llvm.dbg.value(metadata i32 %add, metadata !18, metadata !DIExpression()), !dbg !26
-  %sub = add nsw i32 %add, -12, !dbg !34
-  %sub3 = sub nsw i32 %add1, %sub, !dbg !34
-  %mul = mul nsw i32 %sub3, 20, !dbg !36
-  %div = sdiv i32 %mul, 3, !dbg !37
-  br label %if.end, !dbg !38
-
-if.end:
-  %a.0 = phi i32 [ %div, %if.then ], [ 0, %entry ], !dbg !39
-  call void @llvm.lifetime.end.p0i8(i64 4, i8* nonnull %foo.0.foo.0..sroa_cast), !dbg !40
-  ret i32 %a.0, !dbg !41
+return:                                           ; preds = %entry, %if.then
+  %retval.0 = phi float [ %div, %if.then ], [ 0.000000e+00, %entry ], !dbg !13
+  ret float %retval.0, !dbg !26
 }
 
-declare void @llvm.lifetime.start.p0i8(i64 immarg, i8* nocapture) #1
-declare void @llvm.dbg.declare(metadata, metadata, metadata) #2
-declare void @llvm.lifetime.end.p0i8(i64 immarg, i8* nocapture) #1
-declare void @llvm.dbg.value(metadata, metadata, metadata) #2
+declare void @llvm.dbg.value(metadata, metadata, metadata)
 
 !llvm.dbg.cu = !{!0}
 !llvm.module.flags = !{!3, !4, !5, !6}
 !llvm.ident = !{!7}
 
-!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !1, producer: "clang version 10.0.0", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, debugInfoForProfiling: true, nameTableKind: None)
-!1 = !DIFile(filename: "test.cpp", directory: "F:\")
+!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !1, producer: "clang version 11.0.0", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: None)
+!1 = !DIFile(filename: "undef_intrinsics_when_deleting_instructions.cpp", directory: "/")
 !2 = !{}
-!3 = !{i32 2, !"Dwarf Version", i32 4}
+!3 = !{i32 2, !"CodeView", i32 1}
 !4 = !{i32 2, !"Debug Info Version", i32 3}
 !5 = !{i32 1, !"wchar_size", i32 2}
 !6 = !{i32 7, !"PIC Level", i32 2}
-!7 = !{!"clang version 10.0.0"}
-!8 = distinct !DISubprogram(name: "main", scope: !9, file: !9, line: 1, type: !10, scopeLine: 1, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !13)
-!9 = !DIFile(filename: "./test.cpp", directory: "F:\")
-!10 = !DISubroutineType(types: !11)
-!11 = !{!12}
-!12 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
-!13 = !{!14, !16, !17, !18, !19}
-!14 = !DILocalVariable(name: "foo", scope: !8, file: !9, line: 2, type: !15)
-!15 = !DIDerivedType(tag: DW_TAG_volatile_type, baseType: !12)
-!16 = !DILocalVariable(name: "read1", scope: !8, file: !9, line: 3, type: !12)
-!17 = !DILocalVariable(name: "read2", scope: !8, file: !9, line: 4, type: !12)
-; CHECK: [[VAR_CHEESE]] = !DILocalVariable(name: "cheese"
-!18 = !DILocalVariable(name: "cheese", scope: !8, file: !9, line: 6, type: !12)
-; CHECK: [[VAR_A]] = !DILocalVariable(name: "a"
-!19 = !DILocalVariable(name: "a", scope: !8, file: !9, line: 7, type: !12)
-!20 = !DILocation(line: 2, scope: !8)
-!21 = !{!22, !22, i64 0}
-!22 = !{!"int", !23, i64 0}
-!23 = !{!"omnipotent char", !24, i64 0}
-!24 = !{!"Simple C++ TBAA"}
-!25 = !DILocation(line: 3, scope: !8)
-!26 = !DILocation(line: 0, scope: !8)
-!27 = !DILocation(line: 4, scope: !8)
-!28 = !DILocation(line: 6, scope: !8)
-!29 = !DILocation(line: 7, scope: !8)
-!30 = !DILocation(line: 10, scope: !31)
-!31 = distinct !DILexicalBlock(scope: !8, file: !9, line: 10)
-!32 = !DILocation(line: 10, scope: !8)
-!33 = !DILocation(line: 8, scope: !8)
-!34 = !DILocation(line: 12, scope: !35)
-!35 = distinct !DILexicalBlock(scope: !31, file: !9, line: 10)
-!36 = !DILocation(line: 13, scope: !35)
-!37 = !DILocation(line: 14, scope: !35)
-!38 = !DILocation(line: 15, scope: !35)
-!39 = !DILocation(line: 0, scope: !31)
-!40 = !DILocation(line: 20, scope: !8)
-!41 = !DILocation(line: 19, scope: !8)
+!7 = !{!"clang version 11.0.0"}
+!8 = distinct !DISubprogram(name: "foo", linkageName: "?foo@@YAMMMMM at Z", scope: !1, file: !1, line: 1, type: !9, scopeLine: 1, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2)
+!9 = !DISubroutineType(types: !10)
+!10 = !{!11, !11, !11, !11, !11}
+!11 = !DIBasicType(name: "float", size: 32, encoding: DW_ATE_float)
+!12 = !DILocalVariable(name: "d", arg: 4, scope: !8, file: !1, line: 1, type: !11)
+!13 = !DILocation(line: 0, scope: !8)
+!14 = !DILocalVariable(name: "c", arg: 3, scope: !8, file: !1, line: 1, type: !11)
+!15 = !DILocalVariable(name: "b", arg: 2, scope: !8, file: !1, line: 1, type: !11)
+!16 = !DILocalVariable(name: "a", arg: 1, scope: !8, file: !1, line: 1, type: !11)
+!17 = !DILocation(line: 2, scope: !8)
+!18 = !DILocalVariable(name: "x", scope: !8, file: !1, line: 2, type: !11)
+!19 = !DILocation(line: 3, scope: !8)
+!20 = !DILocation(line: 4, scope: !21)
+!21 = distinct !DILexicalBlock(scope: !22, file: !1, line: 3)
+!22 = distinct !DILexicalBlock(scope: !8, file: !1, line: 3)
+!23 = !DILocalVariable(name: "y", scope: !21, file: !1, line: 4, type: !11)
+!24 = !DILocation(line: 0, scope: !21)
+!25 = !DILocation(line: 5, scope: !21)
+!26 = !DILocation(line: 8, scope: !8)


        


More information about the llvm-commits mailing list