Skip to content

[DebugInfo][SIL] Introduce the 'implicit' attribute for debug variable #38735

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Aug 6, 2021
Merged
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
14 changes: 8 additions & 6 deletions docs/SIL.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3505,6 +3505,7 @@ The operand must have loadable type.
debug-var-attr ::= 'let'
debug-var-attr ::= 'name' string-literal
debug-var-attr ::= 'argno' integer-literal
debug-var-attr ::= 'implicit'

::

Expand All @@ -3520,12 +3521,13 @@ The operand must have loadable type.
There are a number of attributes that provide details about the source
variable that is being described, including the name of the
variable. For function and closure arguments ``argno`` is the number
of the function argument starting with 1. The advanced debug variable
attributes represent source locations and type of the source variable
when it was originally declared. It is useful when we're indirectly
associating the SSA value with the source variable (via di-expression,
for example) in which case SSA value's type is different from that of
source variable.
of the function argument starting with 1. A compiler-generated source
variable will be marked ``implicit`` and optimizers are free to remove
it even in -Onone. The advanced debug variable attributes represent source
locations and type of the source variable when it was originally declared.
It is useful when we're indirectly associating the SSA value with the
source variable (via di-expression, for example) in which case SSA value's
type is different from that of source variable.

If the '[poison]' flag is set, then all references within this debug
value will be overwritten with a sentinel at this point in the
Expand Down
164 changes: 90 additions & 74 deletions include/swift/SIL/SILInstruction.h
Original file line number Diff line number Diff line change
Expand Up @@ -1726,27 +1726,31 @@ struct SILDebugVariable {
StringRef Name;
unsigned ArgNo : 16;
unsigned Constant : 1;
unsigned Implicit : 1;
Optional<SILType> Type;
Optional<SILLocation> Loc;
const SILDebugScope *Scope;
SILDebugInfoExpression DIExpr;

SILDebugVariable() : ArgNo(0), Constant(false), Scope(nullptr) {}
SILDebugVariable()
: ArgNo(0), Constant(false), Implicit(false), Scope(nullptr) {}
SILDebugVariable(bool Constant, uint16_t ArgNo)
: ArgNo(ArgNo), Constant(Constant), Scope(nullptr) {}
: ArgNo(ArgNo), Constant(Constant), Implicit(false), Scope(nullptr) {}
SILDebugVariable(StringRef Name, bool Constant, unsigned ArgNo,
Optional<SILType> AuxType = {},
bool IsImplicit = false, Optional<SILType> AuxType = {},
Optional<SILLocation> DeclLoc = {},
const SILDebugScope *DeclScope = nullptr,
llvm::ArrayRef<SILDIExprElement> ExprElements = {})
: Name(Name), ArgNo(ArgNo), Constant(Constant), Type(AuxType),
Loc(DeclLoc), Scope(DeclScope), DIExpr(ExprElements) {}
: Name(Name), ArgNo(ArgNo), Constant(Constant), Implicit(IsImplicit),
Type(AuxType), Loc(DeclLoc), Scope(DeclScope), DIExpr(ExprElements) {}

// We're not comparing DIExpr here because strictly speaking,
// DIExpr is not part of the debug variable. We simply piggyback
// it in this class so that's it's easier to carry DIExpr around.
bool operator==(const SILDebugVariable &V) {
return ArgNo == V.ArgNo && Constant == V.Constant && Name == V.Name &&
Type == V.Type && Loc == V.Loc && Scope == V.Scope;
Implicit == V.Implicit && Type == V.Type && Loc == V.Loc &&
Scope == V.Scope;
}
};

Expand All @@ -1761,10 +1765,12 @@ class TailAllocatedDebugVariable {
int_type HasValue : 1;
/// True if this is a let-binding.
int_type Constant : 1;
/// True if this variable is created by compiler
int_type Implicit : 1;
/// When this is nonzero there is a tail-allocated string storing
/// variable name present. This typically only happens for
/// instructions that were created from parsing SIL assembler.
int_type NameLength : 14;
int_type NameLength : 13;
/// The source function argument position from left to right
/// starting with 1 or 0 if this is a local variable.
int_type ArgNo : 16;
Expand All @@ -1786,6 +1792,9 @@ class TailAllocatedDebugVariable {
StringRef getName(const char *buf) const;
bool isLet() const { return Bits.Data.Constant; }

bool isImplicit() const { return Bits.Data.Implicit; }
void setImplicit(bool V = true) { Bits.Data.Implicit = V; }

Optional<SILDebugVariable>
get(VarDecl *VD, const char *buf, Optional<SILType> AuxVarType = {},
Optional<SILLocation> DeclLoc = {},
Expand All @@ -1796,16 +1805,60 @@ class TailAllocatedDebugVariable {

if (VD)
return SILDebugVariable(VD->getName().empty() ? "" : VD->getName().str(),
VD->isLet(), getArgNo(), AuxVarType, DeclLoc,
DeclScope, DIExprElements);
else
return SILDebugVariable(getName(buf), isLet(), getArgNo(), AuxVarType,
VD->isLet(), getArgNo(), isImplicit(), AuxVarType,
DeclLoc, DeclScope, DIExprElements);
else
return SILDebugVariable(getName(buf), isLet(), getArgNo(), isImplicit(),
AuxVarType, DeclLoc, DeclScope, DIExprElements);
}
};
static_assert(sizeof(TailAllocatedDebugVariable) == 4,
"SILNode inline bitfield needs updating");

/// Used for keeping track of advanced / supplement debug variable info
/// stored in trailing objects space inside debug instructions (e.g.
/// debug_value)
class SILDebugVariableSupplement {
protected:
enum SourceLocKind : unsigned { SLK_Loc = 0b01, SLK_Scope = 0b10 };

unsigned NumDIExprOperands : 8;

unsigned HasAuxDebugVariableType : 1;

unsigned AuxVariableSourceLoc : 2;

SILDebugVariableSupplement(unsigned NumDIExprOps, bool AuxType, bool AuxLoc,
bool AuxScope)
: NumDIExprOperands(NumDIExprOps), HasAuxDebugVariableType(AuxType),
AuxVariableSourceLoc((AuxLoc ? SLK_Loc : 0) |
(AuxScope ? SLK_Scope : 0)) {}
};

#define SIL_DEBUG_VAR_SUPPLEMENT_TRAILING_OBJS_IMPL() \
inline bool hasAuxDebugLocation() const { \
return AuxVariableSourceLoc & SLK_Loc; \
} \
inline bool hasAuxDebugScope() const { \
return AuxVariableSourceLoc & SLK_Scope; \
} \
\
size_t numTrailingObjects(OverloadToken<SILType>) const { \
return HasAuxDebugVariableType ? 1 : 0; \
} \
\
size_t numTrailingObjects(OverloadToken<SILLocation>) const { \
return hasAuxDebugLocation() ? 1 : 0; \
} \
\
size_t numTrailingObjects(OverloadToken<const SILDebugScope *>) const { \
return hasAuxDebugScope() ? 1 : 0; \
} \
\
size_t numTrailingObjects(OverloadToken<SILDIExprElement>) const { \
return NumDIExprOperands; \
}

//===----------------------------------------------------------------------===//
// Allocation Instructions
//===----------------------------------------------------------------------===//
Expand Down Expand Up @@ -1833,7 +1886,10 @@ class DeallocStackInst;
class AllocStackInst final
: public InstructionBase<SILInstructionKind::AllocStackInst,
AllocationInst>,
private llvm::TrailingObjects<AllocStackInst, Operand, char> {
private SILDebugVariableSupplement,
private llvm::TrailingObjects<AllocStackInst, SILType, SILLocation,
const SILDebugScope *, SILDIExprElement,
Operand, char> {
friend TrailingObjects;
friend SILBuilder;

Expand All @@ -1849,6 +1905,8 @@ class AllocStackInst final
Optional<SILDebugVariable> Var,
bool hasDynamicLifetime);

SIL_DEBUG_VAR_SUPPLEMENT_TRAILING_OBJS_IMPL()

size_t numTrailingObjects(OverloadToken<Operand>) const {
return SILNode::Bits.AllocStackInst.NumOperands;
}
Expand Down Expand Up @@ -1878,9 +1936,24 @@ class AllocStackInst final

/// Return the debug variable information attached to this instruction.
Optional<SILDebugVariable> getVarInfo() const {
Optional<SILType> AuxVarType;
Optional<SILLocation> VarDeclLoc;
const SILDebugScope *VarDeclScope = nullptr;
if (HasAuxDebugVariableType)
AuxVarType = *getTrailingObjects<SILType>();

if (hasAuxDebugLocation())
VarDeclLoc = *getTrailingObjects<SILLocation>();
if (hasAuxDebugScope())
VarDeclScope = *getTrailingObjects<const SILDebugScope *>();

llvm::ArrayRef<SILDIExprElement> DIExprElements(
getTrailingObjects<SILDIExprElement>(), NumDIExprOperands);

auto RawValue = SILNode::Bits.AllocStackInst.VarInfo;
auto VI = TailAllocatedDebugVariable(RawValue);
return VI.get(getDecl(), getTrailingObjects<char>());
return VI.get(getDecl(), getTrailingObjects<char>(), AuxVarType, VarDeclLoc,
VarDeclScope, DIExprElements);
};
void setArgNo(unsigned N) {
auto RawValue = SILNode::Bits.AllocStackInst.VarInfo;
Expand Down Expand Up @@ -4560,29 +4633,18 @@ class MarkFunctionEscapeInst final
}
};

/// Simple bitmasks that represent whether a SIL instruction
/// or debug variable has SILLocation, DebugScope, or both of them
/// attached.
struct SILSourceLocKind {
static constexpr unsigned Loc = 0b01;
static constexpr unsigned Scope = 0b10;
};

/// Define the start or update to a symbolic variable value (for loadable
/// types).
class DebugValueInst final
: public UnaryInstructionBase<SILInstructionKind::DebugValueInst,
NonValueInstruction>,
private SILDebugVariableSupplement,
private llvm::TrailingObjects<DebugValueInst, SILType, SILLocation,
const SILDebugScope *, SILDIExprElement,
char> {
friend TrailingObjects;
friend SILBuilder;

unsigned NumDIExprOperands;
bool HasAuxDebugVariableType;
unsigned AuxVariableSourceLoc : 2;

TailAllocatedDebugVariable VarInfo;

DebugValueInst(SILDebugLocation DebugLoc, SILValue Operand,
Expand All @@ -4591,28 +4653,7 @@ class DebugValueInst final
SILModule &M, SILDebugVariable Var,
bool poisonRefs);

inline bool hasAuxDebugLocation() const {
return AuxVariableSourceLoc & SILSourceLocKind::Loc;
}
inline bool hasAuxDebugScope() const {
return AuxVariableSourceLoc & SILSourceLocKind::Scope;
}

size_t numTrailingObjects(OverloadToken<SILType>) const {
return HasAuxDebugVariableType ? 1 : 0;
}

size_t numTrailingObjects(OverloadToken<SILLocation>) const {
return hasAuxDebugLocation() ? 1 : 0;
}

size_t numTrailingObjects(OverloadToken<const SILDebugScope *>) const {
return hasAuxDebugScope() ? 1 : 0;
}

size_t numTrailingObjects(OverloadToken<SILDIExprElement>) const {
return NumDIExprOperands;
}
SIL_DEBUG_VAR_SUPPLEMENT_TRAILING_OBJS_IMPL()

size_t numTrailingObjects(OverloadToken<char>) const { return 1; }

Expand All @@ -4622,7 +4663,6 @@ class DebugValueInst final
VarDecl *getDecl() const;
/// Return the debug variable information attached to this instruction.
Optional<SILDebugVariable> getVarInfo() const {
;
Optional<SILType> AuxVarType;
Optional<SILLocation> VarDeclLoc;
const SILDebugScope *VarDeclScope = nullptr;
Expand Down Expand Up @@ -4662,16 +4702,13 @@ class DebugValueInst final
class DebugValueAddrInst final
: public UnaryInstructionBase<SILInstructionKind::DebugValueAddrInst,
NonValueInstruction>,
private SILDebugVariableSupplement,
private llvm::TrailingObjects<DebugValueAddrInst, SILType, SILLocation,
const SILDebugScope *, SILDIExprElement,
char> {
friend TrailingObjects;
friend SILBuilder;

unsigned NumDIExprOperands;
bool HasAuxDebugVariableType;
unsigned AuxVariableSourceLoc : 2;

TailAllocatedDebugVariable VarInfo;

DebugValueAddrInst(SILDebugLocation DebugLoc, SILValue Operand,
Expand All @@ -4680,28 +4717,7 @@ class DebugValueAddrInst final
SILValue Operand, SILModule &M,
SILDebugVariable Var);

inline bool hasAuxDebugLocation() const {
return AuxVariableSourceLoc & SILSourceLocKind::Loc;
}
inline bool hasAuxDebugScope() const {
return AuxVariableSourceLoc & SILSourceLocKind::Scope;
}

size_t numTrailingObjects(OverloadToken<SILType>) const {
return HasAuxDebugVariableType ? 1 : 0;
}

size_t numTrailingObjects(OverloadToken<SILLocation>) const {
return hasAuxDebugLocation() ? 1 : 0;
}

size_t numTrailingObjects(OverloadToken<const SILDebugScope *>) const {
return hasAuxDebugScope() ? 1 : 0;
}

size_t numTrailingObjects(OverloadToken<SILDIExprElement>) const {
return NumDIExprOperands;
}
SIL_DEBUG_VAR_SUPPLEMENT_TRAILING_OBJS_IMPL()

public:
/// Return the underlying variable declaration that this denotes,
Expand Down
14 changes: 7 additions & 7 deletions lib/IRGen/IRGenDebugInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2493,13 +2493,13 @@ void IRGenDebugInfoImpl::emitVariableDeclaration(
Operands.push_back(SizeInBits);
}
llvm::DIExpression *DIExpr = DBuilder.createExpression(Operands);
emitDbgIntrinsic(
Builder, Piece, Var,
// DW_OP_LLVM_fragment must be the last part of an DIExpr
// so we can't append more if IsPiece is true.
Operands.empty() || IsPiece ? DIExpr : appendDIExpression(DIExpr),
DInstLine, DInstLoc.column, Scope, DS,
Indirection == CoroDirectValue || Indirection == CoroIndirectValue);
emitDbgIntrinsic(Builder, Piece, Var,
// DW_OP_LLVM_fragment must be the last part of an DIExpr
// so we can't append more if IsPiece is true.
IsPiece ? DIExpr : appendDIExpression(DIExpr), DInstLine,
DInstLoc.column, Scope, DS,
Indirection == CoroDirectValue ||
Indirection == CoroIndirectValue);
}

// Emit locationless intrinsic for variables that were optimized away.
Expand Down
7 changes: 6 additions & 1 deletion lib/IRGen/IRGenSIL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5160,7 +5160,12 @@ void IRGenSILFunction::emitDebugInfoForAllocStack(AllocStackInst *i,
}
}

SILType SILTy = i->getType();
SILType SILTy;
if (auto MaybeSILTy = VarInfo->Type)
// If there is auxiliary type info, use it
SILTy = *MaybeSILTy;
else
SILTy = i->getType();
auto RealType = SILTy.getASTType();
DebugTypeInfo DbgTy;
if (Decl) {
Expand Down
Loading