Skip to content

Commit

Permalink
[Local] replaceAllDbgUsesWith: Update debug values before RAUW
Browse files Browse the repository at this point in the history
The replaceAllDbgUsesWith utility helps passes preserve debug info when
replacing one value with another.

This improves upon the existing insertReplacementDbgValues API by:

- Updating debug intrinsics in-place, while preventing use-before-def of
  the replacement value.
- Falling back to salvageDebugInfo when a replacement can't be made.
- Moving the responsibiliy for rewriting llvm.dbg.* DIExpressions into
  common utility code.

Along with the API change, this teaches replaceAllDbgUsesWith how to
create DIExpressions for three basic integer and pointer conversions:

- The no-op conversion. Applies when the values have the same width, or
  have bit-for-bit compatible pointer representations.
- Truncation. Applies when the new value is wider than the old one.
- Zero/sign extension. Applies when the new value is narrower than the
  old one.

Testing:

- check-llvm, check-clang, a stage2 `-g -O3` build of clang,
  regression/unit testing.
- This resolves a number of mis-sized dbg.value diagnostics from
  Debugify.

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

llvm-svn: 336451
  • Loading branch information
vedantk committed Jul 6, 2018
1 parent a212b0b commit 6379a62
Show file tree
Hide file tree
Showing 12 changed files with 544 additions and 69 deletions.
26 changes: 26 additions & 0 deletions llvm/include/llvm/IR/DebugInfoMetadata.h
Original file line number Diff line number Diff line change
Expand Up @@ -778,6 +778,12 @@ class DIBasicType : public DIType {

unsigned getEncoding() const { return Encoding; }

enum class Signedness { Signed, Unsigned };

/// Return the signedness of this type, or None if this type is neither
/// signed nor unsigned.
Optional<Signedness> getSignedness() const;

static bool classof(const Metadata *MD) {
return MD->getMetadataID() == DIBasicTypeKind;
}
Expand Down Expand Up @@ -2206,6 +2212,14 @@ class DIVariable : public DINode {
/// Determines the size of the variable's type.
Optional<uint64_t> getSizeInBits() const;

/// Return the signedness of this variable's type, or None if this type is
/// neither signed nor unsigned.
Optional<DIBasicType::Signedness> getSignedness() const {
if (auto *BT = dyn_cast<DIBasicType>(getType().resolve()))
return BT->getSignedness();
return None;
}

StringRef getFilename() const {
if (auto *F = getFile())
return F->getFilename();
Expand Down Expand Up @@ -2312,6 +2326,11 @@ class DIExpression : public MDNode {
///
/// Return the number of elements in the operand (1 + args).
unsigned getSize() const;

/// Append the elements of this operand to \p V.
void appendToVector(SmallVectorImpl<uint64_t> &V) const {
V.append(getSize(), *get());
}
};

/// An iterator for expression operands.
Expand Down Expand Up @@ -2425,6 +2444,13 @@ class DIExpression : public MDNode {
SmallVectorImpl<uint64_t> &Ops,
bool StackValue = false);

/// Convert \p DIExpr into a stack value if it isn't one already by appending
/// DW_OP_deref if needed, and applying \p Ops to the resulting expression.
/// If \p DIExpr is a fragment, the returned expression will contain the same
/// fragment.
static DIExpression *appendToStack(const DIExpression *DIExpr,
ArrayRef<uint64_t> Ops);

/// 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
Expand Down
3 changes: 3 additions & 0 deletions llvm/include/llvm/IR/Type.h
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,9 @@ class Type {
return getScalarType()->isIntegerTy(BitWidth);
}

/// Return true if this is an integer type or a pointer type.
bool isIntOrPtrTy() const { return isIntegerTy() || isPointerTy(); }

/// True if this is an instance of FunctionType.
bool isFunctionTy() const { return getTypeID() == FunctionTyID; }

Expand Down
42 changes: 21 additions & 21 deletions llvm/include/llvm/Transforms/Utils/Local.h
Original file line number Diff line number Diff line change
Expand Up @@ -329,27 +329,27 @@ bool replaceDbgDeclareForAlloca(AllocaInst *AI, Value *NewAllocaAddress,
void replaceDbgValueForAlloca(AllocaInst *AI, Value *NewAllocaAddress,
DIBuilder &Builder, int Offset = 0);

/// Assuming the instruction \p I is going to be deleted, attempt to salvage any
/// dbg.value intrinsics referring to \p I by rewriting its effect into a
/// DIExpression.
void salvageDebugInfo(Instruction &I);

/// Assuming the value \p From is going to be deleted, insert replacement
/// dbg.value intrinsics for each debug user of \p From. The newly-inserted
/// dbg.values refer to \p To instead of \p From. Each replacement dbg.value
/// has the same location and variable as the debug user it replaces, has a
/// DIExpression determined by the result of \p RewriteExpr applied to an old
/// debug user of \p From, and is placed before \p InsertBefore. If
/// \p RewriteExpr returns nullptr, no replacement for the specified debug
/// user is emitted.
void insertReplacementDbgValues(
Value &From, Value &To, Instruction &InsertBefore,
function_ref<DIExpression *(DbgInfoIntrinsic &OldDII)> RewriteExpr);

/// An overload of insertReplacementDbgValues() for the common case where
/// the replacement dbg.values have the same DIExpressions as the originals.
void insertReplacementDbgValues(Value &From, Value &To,
Instruction &InsertBefore);
/// Assuming the instruction \p I is going to be deleted, attempt to salvage
/// debug users of \p I by writing the effect of \p I in a DIExpression.
/// Returns true if any debug users were updated.
bool salvageDebugInfo(Instruction &I);

/// 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
/// \p From is going to be deleted.
///
/// Follow these rules to prevent use-before-def of \p To:
/// . If \p To is a linked Instruction, set \p DomPoint to \p To.
/// . If \p To is an unlinked Instruction, set \p DomPoint to the Instruction
/// \p To will be inserted after.
/// . If \p To is not an Instruction (e.g a Constant), the choice of
/// \p DomPoint is arbitrary. Pick \p From for simplicity.
///
/// If a debug user cannot be preserved without reordering variable updates or
/// introducing a use-before-def, it is either salvaged (\ref salvageDebugInfo)
/// or deleted. Returns true if any debug users were updated.
bool replaceAllDbgUsesWith(Instruction &From, Value &To, Instruction &DomPoint,
DominatorTree &DT);

/// Remove all instructions from a basic block other than it's terminator
/// and any present EH pad instructions.
Expand Down
3 changes: 3 additions & 0 deletions llvm/lib/CodeGen/AsmPrinter/DwarfExpression.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -357,6 +357,9 @@ void DwarfExpression::addExpression(DIExpressionCursor &&ExprCursor,
case dwarf::DW_OP_shl:
case dwarf::DW_OP_shr:
case dwarf::DW_OP_shra:
case dwarf::DW_OP_lit0:
case dwarf::DW_OP_not:
case dwarf::DW_OP_dup:
emitOp(Op->getOp());
break;
case dwarf::DW_OP_deref:
Expand Down
52 changes: 52 additions & 0 deletions llvm/lib/IR/DebugInfoMetadata.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -283,6 +283,19 @@ DIBasicType *DIBasicType::getImpl(LLVMContext &Context, unsigned Tag,
Ops);
}

Optional<DIBasicType::Signedness> DIBasicType::getSignedness() const {
switch (getEncoding()) {
case dwarf::DW_ATE_signed:
case dwarf::DW_ATE_signed_char:
return Signedness::Signed;
case dwarf::DW_ATE_unsigned:
case dwarf::DW_ATE_unsigned_char:
return Signedness::Unsigned;
default:
return None;
}
}

DIDerivedType *DIDerivedType::getImpl(
LLVMContext &Context, unsigned Tag, MDString *Name, Metadata *File,
unsigned Line, Metadata *Scope, Metadata *BaseType, uint64_t SizeInBits,
Expand Down Expand Up @@ -733,6 +746,9 @@ bool DIExpression::isValid() const {
case dwarf::DW_OP_shra:
case dwarf::DW_OP_deref:
case dwarf::DW_OP_xderef:
case dwarf::DW_OP_lit0:
case dwarf::DW_OP_not:
case dwarf::DW_OP_dup:
break;
}
}
Expand Down Expand Up @@ -826,6 +842,42 @@ DIExpression *DIExpression::prependOpcodes(const DIExpression *Expr,
return DIExpression::get(Expr->getContext(), Ops);
}

DIExpression *DIExpression::appendToStack(const DIExpression *Expr,
ArrayRef<uint64_t> Ops) {
assert(Expr && !Ops.empty() && "Can't append ops to this expression");

// Append a DW_OP_deref after Expr's current op list if it's non-empty and
// has no DW_OP_stack_value.
//
// Match .* DW_OP_stack_value (DW_OP_LLVM_fragment A B)?.
Optional<FragmentInfo> FI = Expr->getFragmentInfo();
unsigned DropUntilStackValue = FI.hasValue() ? 3 : 0;
bool NeedsDeref =
(Expr->getNumElements() > DropUntilStackValue) &&
(Expr->getElements().drop_back(DropUntilStackValue).back() !=
dwarf::DW_OP_stack_value);

// Copy Expr's current op list, add a DW_OP_deref if needed, and ensure that
// a DW_OP_stack_value is present.
SmallVector<uint64_t, 16> NewOps;
for (auto Op : Expr->expr_ops()) {
if (Op.getOp() == dwarf::DW_OP_stack_value ||
Op.getOp() == dwarf::DW_OP_LLVM_fragment)
break;
Op.appendToVector(NewOps);
}
if (NeedsDeref)
NewOps.push_back(dwarf::DW_OP_deref);
NewOps.append(Ops.begin(), Ops.end());
NewOps.push_back(dwarf::DW_OP_stack_value);

// If Expr is a fragment, make the new expression a fragment as well.
if (FI)
NewOps.append(
{dwarf::DW_OP_LLVM_fragment, FI->OffsetInBits, FI->SizeInBits});
return DIExpression::get(Expr->getContext(), NewOps);
}

Optional<DIExpression *> DIExpression::createFragmentExpression(
const DIExpression *Expr, unsigned OffsetInBits, unsigned SizeInBits) {
SmallVector<uint64_t, 8> Ops;
Expand Down
22 changes: 7 additions & 15 deletions llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -268,11 +268,9 @@ Instruction *InstCombiner::commonCastTransforms(CastInst &CI) {
// the second cast (CI). CSrc will then have a good chance of being dead.
auto *Ty = CI.getType();
auto *Res = CastInst::Create(NewOpc, CSrc->getOperand(0), Ty);
// Replace debug users of the eliminable cast by emitting debug values
// which refer to the new cast.
if (Ty->isIntegerTy() || Ty->isPointerTy())
// TODO: Support floats and vectors (see DW_OP_convert, fragment).
insertReplacementDbgValues(*CSrc, *Res, *std::next(CI.getIterator()));
// Point debug users of the dying cast to the new one.
if (CSrc->hasOneUse())
replaceAllDbgUsesWith(*CSrc, *Res, CI, DT);
return Res;
}
}
Expand Down Expand Up @@ -1079,16 +1077,10 @@ Instruction *InstCombiner::visitZExt(ZExtInst &CI) {
Value *Res = EvaluateInDifferentType(Src, DestTy, false);
assert(Res->getType() == DestTy);

// When DestTy is integer, try to preserve any debug values referring
// to the zext being replaced.
// TODO: This should work for vectors as well, possibly via the use
// of DWARF fragments.
if (DestTy->isIntegerTy()) {
insertReplacementDbgValues(
*Src, *Res, CI, [](DbgInfoIntrinsic &OldDII) -> DIExpression * {
return OldDII.getExpression();
});
}
// Preserve debug values referring to Src if the zext is its last use.
if (auto *SrcOp = dyn_cast<Instruction>(Src))
if (SrcOp->hasOneUse())
replaceAllDbgUsesWith(*SrcOp, *Res, CI, DT);

uint32_t SrcBitsKept = SrcTy->getScalarSizeInBits()-BitsToClear;
uint32_t DestBitSize = DestTy->getScalarSizeInBits();
Expand Down
Loading

0 comments on commit 6379a62

Please sign in to comment.