Skip to content

[move-only] Initial commit of debug info for noncopyable types #64475

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 6 commits into from
Mar 20, 2023
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
5 changes: 3 additions & 2 deletions SwiftCompilerSources/Sources/SIL/Builder.swift
Original file line number Diff line number Diff line change
Expand Up @@ -84,9 +84,10 @@ public struct Builder {
}

public func createAllocStack(_ type: Type, hasDynamicLifetime: Bool = false,
isLexical: Bool = false, wasMoved: Bool = false) -> AllocStackInst {
isLexical: Bool = false,
usesMoveableValueDebugInfo: Bool = false) -> AllocStackInst {
let dr = SILBuilder_createAllocStack(bridged, type.bridged, hasDynamicLifetime ? 1 : 0,
isLexical ? 1 : 0, wasMoved ? 1 : 0)
isLexical ? 1 : 0, usesMoveableValueDebugInfo ? 1 : 0)
return notifyNew(dr.getAs(AllocStackInst.self))
}

Expand Down
39 changes: 27 additions & 12 deletions docs/SIL.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3745,7 +3745,10 @@ alloc_stack
```````````
::

sil-instruction ::= 'alloc_stack' '[dynamic_lifetime]'? '[lexical]'? '[moved]'? sil-type (',' debug-var-attr)*
sil-instruction ::= 'alloc_stack' alloc-stack-option* sil-type (',' debug-var-attr)*
alloc-stack-option ::= '[dynamic_lifetime]'
alloc-stack-option ::= '[lexical]'
alloc-stack-option ::= '[moveable_value_debuginfo]'

%1 = alloc_stack $T
// %1 has type $*T
Expand All @@ -3767,11 +3770,11 @@ This is the case, e.g. for conditionally initialized objects.
The optional ``lexical`` attribute specifies that the storage corresponds to a
local variable in the Swift source.

The optional ``moved`` attribute specifies that at the source level, the
variable associated with this alloc_stack was moved and furthermore that at the
SIL level it passed move operator checking. This means that one can not assume
that the value in the alloc_stack can be semantically valid over the entire
function frame when emitting debug info.
The optional ``moveable_value_debuginfo`` attribute specifies that when emitting
debug info, the code generator can not assume that the value in the alloc_stack
can be semantically valid over the entire function frame when emitting debug
info. NOTE: This is implicitly set to true if the alloc_stack's type is
noncopyable. This is just done to make SIL less verbose.

The memory is not retainable. To allocate a retainable box for a value
type, use ``alloc_box``.
Expand Down Expand Up @@ -3865,7 +3868,8 @@ alloc_box
`````````
::

sil-instruction ::= 'alloc_box' sil-type (',' debug-var-attr)*
sil-instruction ::= 'alloc_box' alloc-box-option* sil-type (',' debug-var-attr)*
alloc-box-option ::= moveable_value_debuginfo

%1 = alloc_box $T
// %1 has type $@box T
Expand All @@ -3883,6 +3887,12 @@ Releasing a box is undefined behavior if the box's value is uninitialized.
To deallocate a box whose value has not been initialized, ``dealloc_box``
should be used.

The optional ``moveable_value_debuginfo`` attribute specifies that when emitting
debug info, the code generator can not assume that the value in the alloc_stack
can be semantically valid over the entire function frame when emitting debug
info. NOTE: This is implicitly set to true if the alloc_stack's type is
noncopyable. This is just done to make SIL less verbose.

alloc_global
````````````

Expand Down Expand Up @@ -4155,7 +4165,10 @@ debug_value

::

sil-instruction ::= debug_value '[poison]'? '[moved]'? '[trace]'? sil-operand (',' debug-var-attr)* advanced-debug-var-attr* (',' 'expr' debug-info-expr)?
sil-instruction ::= debug_value sil-debug-value-option* sil-operand (',' debug-var-attr)* advanced-debug-var-attr* (',' 'expr' debug-info-expr)?
sil-debug-value-option ::= [poison]
sil-debug-value-option ::= [moveable_value_debuginfo]
sil-debug-value-option ::= [trace]

debug_value %1 : $Int

Expand All @@ -4164,10 +4177,12 @@ specified operand. The declaration in question is identified by either the
SILLocation attached to the debug_value instruction or the SILLocation specified
in the advanced debug variable attributes.

If the '[moved]' flag is set, then one knows that the debug_value's operand is
moved at some point of the program, so one can not model the debug_value using
constructs that assume that the value is live for the entire function (e.x.:
llvm.dbg.declare).
If the ``moveable_value_debuginfo`` flag is set, then one knows that the
debug_value's operand is moved at some point of the program, so one can not
model the debug_value using constructs that assume that the value is live for
the entire function (e.x.: llvm.dbg.declare). NOTE: This is implicitly set to
true if the alloc_stack's type is noncopyable. This is just done to make SIL
less verbose.

::

Expand Down
17 changes: 9 additions & 8 deletions include/swift/SIL/DebugUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
#define SWIFT_SIL_DEBUGUTILS_H

#include "swift/SIL/SILBasicBlock.h"
#include "swift/SIL/SILBuilder.h"
#include "swift/SIL/SILGlobalVariable.h"
#include "swift/SIL/SILInstruction.h"

Expand Down Expand Up @@ -460,13 +461,14 @@ struct DebugVarCarryingInst : VarDeclCarryingInst {
case Kind::Invalid:
llvm_unreachable("Invalid?!");
case Kind::DebugValue:
cast<DebugValueInst>(**this)->markAsMoved();
cast<DebugValueInst>(**this)->setUsesMoveableValueDebugInfo();
break;
case Kind::AllocStack:
cast<AllocStackInst>(**this)->markAsMoved();
cast<AllocStackInst>(**this)->markUsesMoveableValueDebugInfo();
break;
case Kind::AllocBox:
llvm_unreachable("Not implemented");
cast<AllocBoxInst>(**this)->setUsesMoveableValueDebugInfo();
break;
}
}

Expand All @@ -476,12 +478,11 @@ struct DebugVarCarryingInst : VarDeclCarryingInst {
case Kind::Invalid:
llvm_unreachable("Invalid?!");
case Kind::DebugValue:
return cast<DebugValueInst>(**this)->getWasMoved();
return cast<DebugValueInst>(**this)->getUsesMoveableValueDebugInfo();
case Kind::AllocStack:
return cast<AllocStackInst>(**this)->getWasMoved();
return cast<AllocStackInst>(**this)->getUsesMoveableValueDebugInfo();
case Kind::AllocBox:
// We do not support moving alloc box today, so we always return false.
return false;
return cast<AllocBoxInst>(**this)->getUsesMoveableValueDebugInfo();
}
}

Expand All @@ -500,7 +501,7 @@ struct DebugVarCarryingInst : VarDeclCarryingInst {
case Kind::AllocStack:
return cast<AllocStackInst>(**this);
case Kind::AllocBox:
llvm_unreachable("Not implemented");
return cast<AllocBoxInst>(**this);
}
}

Expand Down
12 changes: 8 additions & 4 deletions include/swift/SIL/SILBuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -444,22 +444,26 @@ class SILBuilder {
AllocBoxInst *createAllocBox(SILLocation loc, SILType fieldType,
Optional<SILDebugVariable> Var = None,
bool hasDynamicLifetime = false,
bool reflection = false) {
bool reflection = false,
bool usesMoveableValueDebugInfo = false) {
return createAllocBox(loc, SILBoxType::get(fieldType.getASTType()), Var,
hasDynamicLifetime, reflection);
hasDynamicLifetime, reflection,
usesMoveableValueDebugInfo);
}

AllocBoxInst *createAllocBox(SILLocation Loc, CanSILBoxType BoxType,
Optional<SILDebugVariable> Var = None,
bool hasDynamicLifetime = false,
bool reflection = false) {
bool reflection = false,
bool usesMoveableValueDebugInfo = false) {
llvm::SmallString<4> Name;
Loc.markAsPrologue();
assert((!dyn_cast_or_null<VarDecl>(Loc.getAsASTNode<Decl>()) || Var) &&
"location is a VarDecl, but SILDebugVariable is empty");
return insert(AllocBoxInst::create(getSILDebugLocation(Loc), BoxType, *F,
substituteAnonymousArgs(Name, Var, Loc),
hasDynamicLifetime, reflection));
hasDynamicLifetime, reflection,
usesMoveableValueDebugInfo));
}

AllocExistentialBoxInst *
Expand Down
6 changes: 4 additions & 2 deletions include/swift/SIL/SILCloner.h
Original file line number Diff line number Diff line change
Expand Up @@ -893,7 +893,8 @@ SILCloner<ImplClass>::visitAllocStackInst(AllocStackInst *Inst) {
}
auto *NewInst = getBuilder().createAllocStack(
Loc, getOpType(Inst->getElementType()), VarInfo,
Inst->hasDynamicLifetime(), Inst->isLexical(), Inst->getWasMoved());
Inst->hasDynamicLifetime(), Inst->isLexical(),
Inst->getUsesMoveableValueDebugInfo());
remapDebugVarInfo(DebugVarCarryingInst(NewInst));
recordClonedInstruction(Inst, NewInst);
}
Expand Down Expand Up @@ -1380,7 +1381,8 @@ SILCloner<ImplClass>::visitDebugValueInst(DebugValueInst *Inst) {
getBuilder().setCurrentDebugScope(getOpScope(Inst->getDebugScope()));
auto *NewInst = getBuilder().createDebugValue(
Inst->getLoc(), getOpValue(Inst->getOperand()), VarInfo,
Inst->poisonRefs(), Inst->getWasMoved(), Inst->hasTrace());
Inst->poisonRefs(), Inst->getUsesMoveableValueDebugInfo(),
Inst->hasTrace());
remapDebugVarInfo(DebugVarCarryingInst(NewInst));
recordClonedInstruction(Inst, NewInst);
}
Expand Down
57 changes: 39 additions & 18 deletions include/swift/SIL/SILInstruction.h
Original file line number Diff line number Diff line change
Expand Up @@ -2094,12 +2094,12 @@ class AllocStackInst final
AllocStackInst(SILDebugLocation Loc, SILType elementType,
ArrayRef<SILValue> TypeDependentOperands, SILFunction &F,
Optional<SILDebugVariable> Var, bool hasDynamicLifetime,
bool isLexical, bool wasMoved);
bool isLexical, bool usesMoveableValueDebugInfo);

static AllocStackInst *create(SILDebugLocation Loc, SILType elementType,
SILFunction &F, Optional<SILDebugVariable> Var,
bool hasDynamicLifetime, bool isLexical,
bool wasMoved);
bool usesMoveableValueDebugInfo);

SIL_DEBUG_VAR_SUPPLEMENT_TRAILING_OBJS_IMPL()

Expand All @@ -2116,11 +2116,15 @@ class AllocStackInst final
}
}

void markAsMoved() { sharedUInt8().AllocStackInst.wasMoved = true; }
void markUsesMoveableValueDebugInfo() {
sharedUInt8().AllocStackInst.usesMoveableValueDebugInfo = true;
}

/// Set to true if this alloc_stack's memory location was passed to _move at
/// any point of the program.
bool getWasMoved() const { return sharedUInt8().AllocStackInst.wasMoved; }
bool getUsesMoveableValueDebugInfo() const {
return sharedUInt8().AllocStackInst.usesMoveableValueDebugInfo;
}

/// Set to true that this alloc_stack contains a value whose lifetime can not
/// be ascertained from uses.
Expand Down Expand Up @@ -2452,39 +2456,53 @@ class AllocBoxInst final

TailAllocatedDebugVariable VarInfo;

unsigned HasDynamicLifetime : 1;
unsigned Reflection : 1;
USE_SHARED_UINT8;

AllocBoxInst(SILDebugLocation DebugLoc, CanSILBoxType BoxType,
ArrayRef<SILValue> TypeDependentOperands, SILFunction &F,
Optional<SILDebugVariable> Var, bool hasDynamicLifetime,
bool reflection = false);
bool reflection = false,
bool usesMoveableValueDebugInfo = false);

static AllocBoxInst *create(SILDebugLocation Loc, CanSILBoxType boxType,
SILFunction &F,
Optional<SILDebugVariable> Var,
bool hasDynamicLifetime,
bool reflection = false);
SILFunction &F, Optional<SILDebugVariable> Var,
bool hasDynamicLifetime, bool reflection = false,
bool usesMoveableValueDebugInfo = false);

public:
CanSILBoxType getBoxType() const {
return getType().castTo<SILBoxType>();
}

void setDynamicLifetime() { HasDynamicLifetime = true; }
bool hasDynamicLifetime() const { return HasDynamicLifetime; }
void setDynamicLifetime() {
sharedUInt8().AllocBoxInst.dynamicLifetime = true;
}

bool hasDynamicLifetime() const {
return sharedUInt8().AllocBoxInst.dynamicLifetime;
}

/// True if the box should be emitted with reflection metadata for its
/// contents.
bool emitReflectionMetadata() const { return Reflection; }

bool emitReflectionMetadata() const {
return sharedUInt8().AllocBoxInst.reflection;
}

// Return the type of the memory stored in the alloc_box.
SILType getAddressType() const;

/// Return the debug variable information attached to this instruction.
Optional<SILDebugVariable> getVarInfo() const {
return VarInfo.get(getDecl(), getTrailingObjects<char>());
};

void setUsesMoveableValueDebugInfo() {
sharedUInt8().AllocBoxInst.usesMoveableValueDebugInfo = true;
}

bool getUsesMoveableValueDebugInfo() const {
return sharedUInt8().AllocBoxInst.usesMoveableValueDebugInfo;
}
};

/// This represents the allocation of a heap box for an existential container.
Expand Down Expand Up @@ -5012,14 +5030,17 @@ class DebugValueInst final
size_t numTrailingObjects(OverloadToken<char>) const { return 1; }

public:
void markAsMoved() { sharedUInt8().DebugValueInst.operandWasMoved = true; }
/// Sets a bool that states this debug_value is supposed to use the
void setUsesMoveableValueDebugInfo() {
sharedUInt8().DebugValueInst.usesMoveableValueDebugInfo = true;
}

/// True if this debug_value is on an SSA value that was moved.
///
/// IRGen uses this information to determine if we should use llvm.dbg.addr or
/// llvm.dbg.declare.
bool getWasMoved() const {
return sharedUInt8().DebugValueInst.operandWasMoved;
bool getUsesMoveableValueDebugInfo() const {
return sharedUInt8().DebugValueInst.usesMoveableValueDebugInfo;
}

/// Return the underlying variable declaration that this denotes,
Expand Down
23 changes: 16 additions & 7 deletions include/swift/SIL/SILNode.h
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,7 @@ class alignas(8) SILNode :
#define SHARED_TEMPLATE4_FIELD(T1, T2, T3, T4, I, ...) \
class { template <T1, T2, T3, T4> friend class I; __VA_ARGS__; } I;

// clang-format off
union SharedUInt8Fields {
uint8_t opaque;

Expand Down Expand Up @@ -203,15 +204,20 @@ class alignas(8) SILNode :
SHARED_FIELD(BeginCOWMutationInst, bool native);

SHARED_FIELD(DebugValueInst, uint8_t
poisonRefs : 1,
operandWasMoved : 1,
trace : 1);
poisonRefs : 1,
usesMoveableValueDebugInfo : 1,
trace : 1);

SHARED_FIELD(AllocStackInst, uint8_t
dynamicLifetime : 1,
lexical : 1,
wasMoved : 1,
hasInvalidatedVarInfo : 1);
dynamicLifetime : 1,
lexical : 1,
usesMoveableValueDebugInfo : 1,
hasInvalidatedVarInfo : 1);

SHARED_FIELD(AllocBoxInst, uint8_t
dynamicLifetime : 1,
reflection : 1,
usesMoveableValueDebugInfo : 1);

SHARED_FIELD(AllocRefInstBase, uint8_t
objC : 1,
Expand Down Expand Up @@ -243,10 +249,12 @@ class alignas(8) SILNode :

// Do not use `_sharedUInt8_private` outside of SILNode.
} _sharedUInt8_private;
// clang-format on

static_assert(sizeof(SharedUInt8Fields) == sizeof(uint8_t),
"A SILNode's shared uint8 field is too large");

// clang-format off
union SharedUInt32Fields {
uint32_t opaque;

Expand All @@ -272,6 +280,7 @@ class alignas(8) SILNode :

// Do not use `_sharedUInt32_private` outside of SILNode.
} _sharedUInt32_private;
// clang-format on

static_assert(sizeof(SharedUInt32Fields) == sizeof(uint32_t),
"A SILNode's shared uint32 field is too large");
Expand Down
Loading