Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions include/swift/SIL/DebugUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,27 @@ inline void deleteAllDebugUses(SILInstruction *inst) {
}
}

/// Drops all of the debug uses of \p value.
/// Unlike deleteAllDebugUses, this preserves the debug_value instruction
/// but replaces its operand with undef and strips non-fragment DIExpr parts.
/// Use this when salvage has NOT already created a replacement debug_value.
inline void killAllDebugUses(SILValue value) {
SmallVector<DebugValueInst *, 4> debugUsers;
for (auto *use : value->getUses()) {
if (auto *dvi = dyn_cast<DebugValueInst>(use->getUser()))
debugUsers.push_back(dvi);
}
for (auto *dvi : debugUsers)
dvi->killOperand();
}

/// Drops all of the debug uses of any result of \p inst.
inline void killAllDebugUses(SILInstruction *inst) {
for (SILValue v : inst->getResults()) {
killAllDebugUses(v);
}
}

/// This iterator filters out any debug (or non-debug) instructions from a range
/// of uses, provided by the underlying ValueBaseUseIterator.
/// If \p nonDebugInsts is true, then the iterator provides a view to all non-
Expand Down
18 changes: 16 additions & 2 deletions include/swift/SIL/SILInstruction.h
Original file line number Diff line number Diff line change
Expand Up @@ -5626,7 +5626,8 @@ class DebugValueInst final

DebugValueInst(SILDebugLocation DebugLoc, SILValue Operand,
SILDebugVariable Var, PoisonRefs_t poisonRefs,
UsesMoveableValueDebugInfo_t operandWasMoved, bool trace);
UsesMoveableValueDebugInfo_t operandWasMoved, bool trace,
bool prependDeref);
static DebugValueInst *create(SILDebugLocation DebugLoc, SILValue Operand,
SILModule &M, SILDebugVariable Var,
PoisonRefs_t poisonRefs,
Expand Down Expand Up @@ -5704,7 +5705,7 @@ class DebugValueInst final
// Make a temporary copy to prepend a deref. This is safe as
// SILDebugVariable contains a copy of the expression.
llvm::SmallVector<SILDIExprElement, 4> DIExprCopy;
if (sharedUInt8().DebugValueInst.prependDeref) {
if (hasDeref()) {
DIExprCopy.push_back(SILDIExprElement::createOperator(
SILDIExprOperator::Dereference));
DIExprCopy.append(DIExprElements.begin(), DIExprElements.end());
Expand Down Expand Up @@ -5742,6 +5743,12 @@ class DebugValueInst final
return DVI && DVI->hasAddrVal()? DVI : nullptr;
}

/// Whether this debug value has a DIExpr with a deref. If this instruction
/// has a debug reconstruction block, this returns false.
bool hasDeref() const {
return sharedUInt8().DebugValueInst.prependDeref;
}

/// Prepends a deref operator to this debug_value in place.
/// This must be called when the operand is changed from an object type to
/// an address type (when moved to the stack, for example).
Expand Down Expand Up @@ -5781,6 +5788,13 @@ class DebugValueInst final
/// has no arguments and returns undef directly.
SILBasicBlock *getOrCreateDebugReconstructionBlock();

/// Drops the operand from this debug value.
/// This function must be called by passes whenever the operand of this debug
/// value is no longer valid and cannot be salvaged.
/// This will replace the operand with an undef, and clear any DIExpr or debug
/// reconstruction block.
void killOperand();

/// True if all references within this debug value will be overwritten with a
/// poison sentinel at this point in the program. This is used in debug builds
/// when shortening non-trivial value lifetimes to ensure the debugger cannot
Expand Down
51 changes: 45 additions & 6 deletions lib/SIL/IR/SILInstructions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -438,7 +438,7 @@ SILType AllocBoxInst::getAddressType() const {
DebugValueInst::DebugValueInst(
SILDebugLocation DebugLoc, SILValue Operand, SILDebugVariable Var,
PoisonRefs_t poisonRefs,
UsesMoveableValueDebugInfo_t usesMoveableValueDebugInfo, bool trace)
UsesMoveableValueDebugInfo_t usesMoveableValueDebugInfo, bool trace, bool prependDeref)
: UnaryInstructionBase(DebugLoc, Operand),
SILDebugVariableSupplement(Var.DIExpr.getNumElements(),
Var.Type.has_value(), Var.Loc.has_value(),
Expand All @@ -451,6 +451,8 @@ DebugValueInst::DebugValueInst(
if (usesMoveableValueDebugInfo || Operand->getType().isMoveOnly())
setUsesMoveableValueDebugInfo();
setTrace(trace);
if (prependDeref)
this->prependDeref();
}

DebugValueInst *DebugValueInst::create(SILDebugLocation DebugLoc,
Expand All @@ -466,14 +468,18 @@ DebugValueInst *DebugValueInst::create(SILDebugLocation DebugLoc,
Var.Scope = nullptr;
if (Var.Type == Operand->getType().getObjectType())
Var.Type = {};
// Use the prependDeref bit rather than storing it in the DIExpr.
bool prependDeref = Var.DIExpr.startsWithDeref();
if (prependDeref) {
Var.DIExpr.eraseElement(Var.DIExpr.element_begin());
}
void *buf = allocateDebugVarCarryingInst<DebugValueInst>(M, Var);
return ::new (buf)
DebugValueInst(DebugLoc, Operand, Var, poisonRefs, wasMoved, trace);
DebugValueInst(DebugLoc, Operand, Var, poisonRefs, wasMoved, trace, prependDeref);
}

void DebugValueInst::prependDeref() {
ASSERT(!sharedUInt8().DebugValueInst.prependDeref &&
"Debug value cannot have two derefs!");
ASSERT(!hasDeref() && "Debug value cannot have two derefs!");
if (!ReconstructionBlock) {
sharedUInt8().DebugValueInst.prependDeref = true;
return;
Expand Down Expand Up @@ -509,7 +515,7 @@ SILBasicBlock *DebugValueInst::getOrCreateDebugReconstructionBlock() {
if (isa<SILUndef>(operand)) {
// No arguments, return the same undef directly.
retVal = operand;
} else if (sharedUInt8().DebugValueInst.prependDeref) {
} else if (hasDeref()) {
// Convert the deref to a load.
SILArgument *arg = block->createPhiArgument(
operand->getType().getAddressType(), OwnershipKind::None);
Expand All @@ -527,6 +533,31 @@ SILBasicBlock *DebugValueInst::getOrCreateDebugReconstructionBlock() {
return block;
}

void DebugValueInst::killOperand() {
if (isa<SILUndef>(getOperand())) {
// Already undef: no operand to kill.
return;
}

// Use the object type because we may be stripping the deref.
SILValue undef =
SILUndef::get(getFunction(), getOperand()->getType().getObjectType());
setOperand(undef);

// Strip prependDeref.
// The stored DIExpr only contains fragments, which we want to keep.
sharedUInt8().DebugValueInst.prependDeref = false;

// Rather than completely removing the debug reconstruction block, remove its
// argument, as a part of the variable might be constant and recoverable.
if (auto bb = getDebugReconstructionBlock()) {
ASSERT(bb->getNumArguments() == 1);
auto argument = bb->getArgument(0);
argument->replaceAllUsesWithUndef();
bb->eraseArgument(0);
}
}

bool DebugValueInst::isExprTypeValid() const {
auto varInfo = getCompleteVarInfo();

Expand Down Expand Up @@ -556,6 +587,9 @@ bool DebugValueInst::isExprTypeValid() const {
if (debugBB->getArgument(0)->getType() != valueType)
return false;
}
// Cannot have both an op_deref and a debug reconstruction block.
if (hasDeref())
return false;
auto *terminator = cast<ReturnInst>(debugBB->getTerminator());
valueType = terminator->getOperand()->getType();
}
Expand All @@ -580,7 +614,8 @@ bool DebugValueInst::isExprTypeValid() const {
break;
}
default:
break;
// Invalid operator
return false;
}
}

Expand All @@ -589,6 +624,10 @@ bool DebugValueInst::isExprTypeValid() const {
if (derefCount != valueType.isAddress())
return false;

// The op_deref must be stored in the prependDeref bit.
if (derefCount != hasDeref())
return false;

return RunningType.removingMoveOnlyWrapper() ==
valueType.getObjectType().removingMoveOnlyWrapper();
}
Expand Down