diff --git a/llvm/include/llvm/IR/DebugInfoMetadata.h b/llvm/include/llvm/IR/DebugInfoMetadata.h --- a/llvm/include/llvm/IR/DebugInfoMetadata.h +++ b/llvm/include/llvm/IR/DebugInfoMetadata.h @@ -2597,6 +2597,14 @@ static DIExpression *appendOpsToArg(const DIExpression *Expr, ArrayRef Ops, uint64_t ArgNo); + /// Modify \p Expr by replacing each instance of `DW_OP_LLVM_arg, \p OldArg` + /// with `DW_OP_LLVM_arg, \p NewArg`, and then each `DW_OP_LLVM_arg, Arg` + /// with `DW_OP_LLVM_arg, Arg - 1` for all Arg > \p OldArg. + /// This is used when replacing one of the operands of a debug value list + /// with another operand in the same list and deleting the old operand. + static DIExpression *replaceArg(const DIExpression *Expr, uint64_t OldArg, + uint64_t NewArg); + /// Create a DIExpression to describe one part of an aggregate variable that /// is fragmented across multiple Values. The DW_OP_LLVM_fragment operation /// will be appended to the elements of \c Expr. If \c Expr already contains diff --git a/llvm/lib/IR/DebugInfoMetadata.cpp b/llvm/lib/IR/DebugInfoMetadata.cpp --- a/llvm/lib/IR/DebugInfoMetadata.cpp +++ b/llvm/lib/IR/DebugInfoMetadata.cpp @@ -1188,6 +1188,28 @@ return DIExpression::get(Expr->getContext(), NewOps); } +DIExpression *DIExpression::replaceArg(const DIExpression *Expr, + uint64_t OldArg, uint64_t NewArg) { + assert(Expr && "Can't replace args in this expression"); + + SmallVector NewOps; + + for (auto Op : Expr->expr_ops()) { + if (Op.getOp() != dwarf::DW_OP_LLVM_arg || Op.getArg(0) < OldArg) { + Op.appendToVector(NewOps); + continue; + } + NewOps.push_back(dwarf::DW_OP_LLVM_arg); + uint64_t Arg = Op.getArg(0) == OldArg ? NewArg : Op.getArg(0); + // OldArg has been deleted from the Op list, so decrement all indices + // greater than it. + if (Arg > OldArg) + --Arg; + NewOps.push_back(Arg); + } + return DIExpression::get(Expr->getContext(), NewOps); +} + DIExpression *DIExpression::prependOpcodes(const DIExpression *Expr, SmallVectorImpl &Ops, bool StackValue,