Skip to content

Commit 375ce35

Browse files
committed
[move-function] Add a flag to alloc_stack and debug_value that states that they describe an address/value that was moved at some point locally in the function.
The main effect of this will be that in IRGen we will use llvm.dbg.addr instead of llvm.dbg.declare. We must do this since llvm.dbg.declare implies that the given address is valid throughout the program. This just adds the instructions/printing/parsing/serialization/deserialization. rdar://85020571
1 parent 9cc5d12 commit 375ce35

File tree

14 files changed

+166
-46
lines changed

14 files changed

+166
-46
lines changed

docs/SIL.rst

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3178,7 +3178,7 @@ alloc_stack
31783178
```````````
31793179
::
31803180

3181-
sil-instruction ::= 'alloc_stack' '[dynamic_lifetime]'? '[lexical]'? sil-type (',' debug-var-attr)*
3181+
sil-instruction ::= 'alloc_stack' '[dynamic_lifetime]'? '[lexical]'? '[moved]'? sil-type (',' debug-var-attr)*
31823182

31833183
%1 = alloc_stack $T
31843184
// %1 has type $*T
@@ -3204,6 +3204,12 @@ This is the case, e.g. for conditionally initialized objects.
32043204
The optional ``lexical`` attribute specifies that the storage corresponds to a
32053205
local variable in the Swift source.
32063206

3207+
The optional ``moved`` attribute specifies that at the source level, the
3208+
variable associated with this alloc_stack was moved and furthermore that at the
3209+
SIL level it passed move operator checking. This means that one can not assume
3210+
that the value in the alloc_stack can be semantically valid over the entire
3211+
function frame when emitting debug info.
3212+
32073213
The memory is not retainable. To allocate a retainable box for a value
32083214
type, use ``alloc_box``.
32093215

@@ -3548,7 +3554,7 @@ debug_value
35483554

35493555
::
35503556

3551-
sil-instruction ::= debug_value '[poison]'? sil-operand (',' debug-var-attr)* advanced-debug-var-attr* (',' 'expr' debug-info-expr)?
3557+
sil-instruction ::= debug_value '[poison]'? '[moved]'? sil-operand (',' debug-var-attr)* advanced-debug-var-attr* (',' 'expr' debug-info-expr)?
35523558

35533559
debug_value %1 : $Int
35543560

@@ -3557,6 +3563,11 @@ specified operand. The declaration in question is identified by either the
35573563
SILLocation attached to the debug_value instruction or the SILLocation specified
35583564
in the advanced debug variable attributes.
35593565

3566+
If the '[moved]' flag is set, then one knows that the debug_value's operand is
3567+
moved at some point of the program, so one can not model the debug_value using
3568+
constructs that assume that the value is live for the entire function (e.x.:
3569+
llvm.dbg.declare).
3570+
35603571
::
35613572

35623573
debug-var-attr ::= 'var'

include/swift/SIL/SILBuilder.h

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -382,15 +382,16 @@ class SILBuilder {
382382
AllocStackInst *createAllocStack(SILLocation Loc, SILType elementType,
383383
Optional<SILDebugVariable> Var = None,
384384
bool hasDynamicLifetime = false,
385-
bool isLexical = false) {
385+
bool isLexical = false,
386+
bool wasMoved = false) {
386387
llvm::SmallString<4> Name;
387388
Loc.markAsPrologue();
388389
assert((!dyn_cast_or_null<VarDecl>(Loc.getAsASTNode<Decl>()) || Var) &&
389390
"location is a VarDecl, but SILDebugVariable is empty");
390391
return insert(AllocStackInst::create(
391392
getSILDebugLocation(Loc), elementType, getFunction(),
392-
substituteAnonymousArgs(Name, Var, Loc), hasDynamicLifetime,
393-
isLexical));
393+
substituteAnonymousArgs(Name, Var, Loc), hasDynamicLifetime, isLexical,
394+
wasMoved));
394395
}
395396

396397
AllocRefInst *createAllocRef(SILLocation Loc, SILType ObjectType,
@@ -941,9 +942,11 @@ class SILBuilder {
941942

942943
DebugValueInst *createDebugValue(SILLocation Loc, SILValue src,
943944
SILDebugVariable Var,
944-
bool poisonRefs = false);
945+
bool poisonRefs = false,
946+
bool wasMoved = false);
945947
DebugValueInst *createDebugValueAddr(SILLocation Loc, SILValue src,
946-
SILDebugVariable Var);
948+
SILDebugVariable Var,
949+
bool wasMoved = false);
947950

948951
/// Create a debug_value according to the type of \p src
949952
SILInstruction *emitDebugDescription(SILLocation Loc, SILValue src,

include/swift/SIL/SILCloner.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -800,7 +800,7 @@ SILCloner<ImplClass>::visitAllocStackInst(AllocStackInst *Inst) {
800800
}
801801
auto *NewInst = getBuilder().createAllocStack(
802802
Loc, getOpType(Inst->getElementType()), VarInfo,
803-
Inst->hasDynamicLifetime(), Inst->isLexical());
803+
Inst->hasDynamicLifetime(), Inst->isLexical(), Inst->getWasMoved());
804804
remapDebugVarInfo(DebugVarCarryingInst(NewInst));
805805
recordClonedInstruction(Inst, NewInst);
806806
}
@@ -1277,9 +1277,9 @@ SILCloner<ImplClass>::visitDebugValueInst(DebugValueInst *Inst) {
12771277
// Since we want the debug info to survive, we do not remap the location here.
12781278
SILDebugVariable VarInfo = *Inst->getVarInfo();
12791279
getBuilder().setCurrentDebugScope(getOpScope(Inst->getDebugScope()));
1280-
auto *NewInst = getBuilder().createDebugValue(Inst->getLoc(),
1281-
getOpValue(Inst->getOperand()),
1282-
VarInfo, Inst->poisonRefs());
1280+
auto *NewInst = getBuilder().createDebugValue(
1281+
Inst->getLoc(), getOpValue(Inst->getOperand()), VarInfo,
1282+
Inst->poisonRefs(), Inst->getWasMoved());
12831283
remapDebugVarInfo(DebugVarCarryingInst(NewInst));
12841284
recordClonedInstruction(Inst, NewInst);
12851285
}

include/swift/SIL/SILInstruction.h

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1916,14 +1916,19 @@ class AllocStackInst final
19161916
bool dynamicLifetime = false;
19171917
bool lexical = false;
19181918

1919+
/// Set to true if this alloc_stack's memory location was passed to _move at
1920+
/// any point of the program.
1921+
bool wasMoved = false;
1922+
19191923
AllocStackInst(SILDebugLocation Loc, SILType elementType,
19201924
ArrayRef<SILValue> TypeDependentOperands, SILFunction &F,
19211925
Optional<SILDebugVariable> Var, bool hasDynamicLifetime,
1922-
bool isLexical);
1926+
bool isLexical, bool wasMoved);
19231927

19241928
static AllocStackInst *create(SILDebugLocation Loc, SILType elementType,
19251929
SILFunction &F, Optional<SILDebugVariable> Var,
1926-
bool hasDynamicLifetime, bool isLexical);
1930+
bool hasDynamicLifetime, bool isLexical,
1931+
bool wasMoved);
19271932

19281933
SIL_DEBUG_VAR_SUPPLEMENT_TRAILING_OBJS_IMPL()
19291934

@@ -1940,6 +1945,10 @@ class AllocStackInst final
19401945
}
19411946
}
19421947

1948+
void markAsMoved() { wasMoved = true; }
1949+
1950+
bool getWasMoved() const { return wasMoved; }
1951+
19431952
/// Set to true that this alloc_stack contains a value whose lifetime can not
19441953
/// be ascertained from uses.
19451954
///
@@ -4696,22 +4705,34 @@ class DebugValueInst final
46964705

46974706
TailAllocatedDebugVariable VarInfo;
46984707

4708+
/// Set to true if this debug_value is on an SSA value that was moved.
4709+
///
4710+
/// IRGen uses this information to determine if we should use llvm.dbg.addr or
4711+
/// llvm.dbg.declare.
4712+
bool operandWasMoved = false;
4713+
46994714
DebugValueInst(SILDebugLocation DebugLoc, SILValue Operand,
4700-
SILDebugVariable Var, bool poisonRefs);
4715+
SILDebugVariable Var, bool poisonRefs, bool operandWasMoved);
47014716
static DebugValueInst *create(SILDebugLocation DebugLoc, SILValue Operand,
47024717
SILModule &M, SILDebugVariable Var,
4703-
bool poisonRefs);
4718+
bool poisonRefs, bool operandWasMoved);
47044719
static DebugValueInst *createAddr(SILDebugLocation DebugLoc, SILValue Operand,
4705-
SILModule &M, SILDebugVariable Var);
4720+
SILModule &M, SILDebugVariable Var,
4721+
bool operandWasMoved);
47064722

47074723
SIL_DEBUG_VAR_SUPPLEMENT_TRAILING_OBJS_IMPL()
47084724

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

47114727
public:
4728+
void markAsMoved() { operandWasMoved = true; }
4729+
4730+
bool getWasMoved() const { return operandWasMoved; }
4731+
47124732
/// Return the underlying variable declaration that this denotes,
47134733
/// or null if we don't have one.
47144734
VarDecl *getDecl() const;
4735+
47154736
/// Return the debug variable information attached to this instruction.
47164737
Optional<SILDebugVariable> getVarInfo() const {
47174738
Optional<SILType> AuxVarType;

lib/SIL/IR/SILBuilder.cpp

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -572,24 +572,25 @@ void SILBuilder::emitDestructureValueOperation(
572572

573573
DebugValueInst *SILBuilder::createDebugValue(SILLocation Loc, SILValue src,
574574
SILDebugVariable Var,
575-
bool poisonRefs) {
575+
bool poisonRefs,
576+
bool operandWasMoved) {
576577
llvm::SmallString<4> Name;
577578
// Debug location overrides cannot apply to debug value instructions.
578579
DebugLocOverrideRAII LocOverride{*this, None};
579580
return insert(DebugValueInst::create(
580581
getSILDebugLocation(Loc), src, getModule(),
581-
*substituteAnonymousArgs(Name, Var, Loc), poisonRefs));
582+
*substituteAnonymousArgs(Name, Var, Loc), poisonRefs, operandWasMoved));
582583
}
583584

584-
DebugValueInst *SILBuilder::createDebugValueAddr(SILLocation Loc,
585-
SILValue src,
586-
SILDebugVariable Var) {
585+
DebugValueInst *SILBuilder::createDebugValueAddr(SILLocation Loc, SILValue src,
586+
SILDebugVariable Var,
587+
bool wasMoved) {
587588
llvm::SmallString<4> Name;
588589
// Debug location overrides cannot apply to debug addr instructions.
589590
DebugLocOverrideRAII LocOverride{*this, None};
590-
return insert(
591-
DebugValueInst::createAddr(getSILDebugLocation(Loc), src, getModule(),
592-
*substituteAnonymousArgs(Name, Var, Loc)));
591+
return insert(DebugValueInst::createAddr(
592+
getSILDebugLocation(Loc), src, getModule(),
593+
*substituteAnonymousArgs(Name, Var, Loc), wasMoved));
593594
}
594595

595596
void SILBuilder::emitScopedBorrowOperation(SILLocation loc, SILValue original,

lib/SIL/IR/SILInstructions.cpp

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -190,13 +190,15 @@ SILDebugVariable::createFromAllocation(const AllocationInst *AI) {
190190
AllocStackInst::AllocStackInst(SILDebugLocation Loc, SILType elementType,
191191
ArrayRef<SILValue> TypeDependentOperands,
192192
SILFunction &F, Optional<SILDebugVariable> Var,
193-
bool hasDynamicLifetime, bool isLexical)
193+
bool hasDynamicLifetime, bool isLexical,
194+
bool wasMoved)
194195
: InstructionBase(Loc, elementType.getAddressType()),
195196
SILDebugVariableSupplement(Var ? Var->DIExpr.getNumElements() : 0,
196197
Var ? Var->Type.hasValue() : false,
197198
Var ? Var->Loc.hasValue() : false,
198199
Var ? Var->Scope != nullptr : false),
199-
dynamicLifetime(hasDynamicLifetime), lexical(isLexical) {
200+
dynamicLifetime(hasDynamicLifetime), lexical(isLexical),
201+
wasMoved(wasMoved) {
200202
SILNode::Bits.AllocStackInst.NumOperands =
201203
TypeDependentOperands.size();
202204
assert(SILNode::Bits.AllocStackInst.NumOperands ==
@@ -221,15 +223,16 @@ AllocStackInst::AllocStackInst(SILDebugLocation Loc, SILType elementType,
221223
AllocStackInst *AllocStackInst::create(SILDebugLocation Loc,
222224
SILType elementType, SILFunction &F,
223225
Optional<SILDebugVariable> Var,
224-
bool hasDynamicLifetime,
225-
bool isLexical) {
226+
bool hasDynamicLifetime, bool isLexical,
227+
bool wasMoved) {
226228
SmallVector<SILValue, 8> TypeDependentOperands;
227229
collectTypeDependentOperands(TypeDependentOperands, F,
228230
elementType.getASTType());
229231
void *Buffer = allocateDebugVarCarryingInst<AllocStackInst>(
230232
F.getModule(), Var, TypeDependentOperands);
231-
return ::new (Buffer) AllocStackInst(Loc, elementType, TypeDependentOperands,
232-
F, Var, hasDynamicLifetime, isLexical);
233+
return ::new (Buffer)
234+
AllocStackInst(Loc, elementType, TypeDependentOperands, F, Var,
235+
hasDynamicLifetime, isLexical, wasMoved);
233236
}
234237

235238
VarDecl *AllocationInst::getDecl() const {
@@ -334,7 +337,8 @@ SILType AllocBoxInst::getAddressType() const {
334337
}
335338

336339
DebugValueInst::DebugValueInst(SILDebugLocation DebugLoc, SILValue Operand,
337-
SILDebugVariable Var, bool poisonRefs)
340+
SILDebugVariable Var, bool poisonRefs,
341+
bool wasMoved)
338342
: UnaryInstructionBase(DebugLoc, Operand),
339343
SILDebugVariableSupplement(Var.DIExpr.getNumElements(),
340344
Var.Type.hasValue(), Var.Loc.hasValue(),
@@ -346,26 +350,31 @@ DebugValueInst::DebugValueInst(SILDebugLocation DebugLoc, SILValue Operand,
346350
if (auto *VD = DebugLoc.getLocation().getAsASTNode<VarDecl>())
347351
VarInfo.setImplicit(VD->isImplicit() || VarInfo.isImplicit());
348352
setPoisonRefs(poisonRefs);
353+
if (wasMoved)
354+
markAsMoved();
349355
}
350356

351357
DebugValueInst *DebugValueInst::create(SILDebugLocation DebugLoc,
352358
SILValue Operand, SILModule &M,
353-
SILDebugVariable Var, bool poisonRefs) {
359+
SILDebugVariable Var, bool poisonRefs,
360+
bool wasMoved) {
354361
void *buf = allocateDebugVarCarryingInst<DebugValueInst>(M, Var);
355-
return ::new (buf) DebugValueInst(DebugLoc, Operand, Var, poisonRefs);
362+
return ::new (buf)
363+
DebugValueInst(DebugLoc, Operand, Var, poisonRefs, wasMoved);
356364
}
357365

358366
DebugValueInst *DebugValueInst::createAddr(SILDebugLocation DebugLoc,
359367
SILValue Operand, SILModule &M,
360-
SILDebugVariable Var) {
368+
SILDebugVariable Var,
369+
bool wasMoved) {
361370
// For alloc_stack, debug_value is used to annotate the associated
362371
// memory location, so we shouldn't attach op_deref.
363372
if (!isa<AllocStackInst>(Operand))
364373
Var.DIExpr.prependElements(
365374
{SILDIExprElement::createOperator(SILDIExprOperator::Dereference)});
366375
void *buf = allocateDebugVarCarryingInst<DebugValueInst>(M, Var);
367376
return ::new (buf) DebugValueInst(DebugLoc, Operand, Var,
368-
/*poisonRefs=*/false);
377+
/*poisonRefs=*/false, wasMoved);
369378
}
370379

371380
bool DebugValueInst::exprStartsWithDeref() const {

lib/SIL/IR/SILPrinter.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1321,6 +1321,8 @@ class SILPrinter : public SILInstructionVisitor<SILPrinter> {
13211321
*this << "[dynamic_lifetime] ";
13221322
if (AVI->isLexical())
13231323
*this << "[lexical] ";
1324+
if (AVI->getWasMoved())
1325+
*this << "[moved] ";
13241326
*this << AVI->getElementType();
13251327
printDebugVar(AVI->getVarInfo(),
13261328
&AVI->getModule().getASTContext().SourceMgr);
@@ -1681,6 +1683,8 @@ class SILPrinter : public SILInstructionVisitor<SILPrinter> {
16811683
void visitDebugValueInst(DebugValueInst *DVI) {
16821684
if (DVI->poisonRefs())
16831685
*this << "[poison] ";
1686+
if (DVI->getWasMoved())
1687+
*this << "[moved] ";
16841688
*this << getIDAndType(DVI->getOperand());
16851689
printDebugVar(DVI->getVarInfo(),
16861690
&DVI->getModule().getASTContext().SourceMgr);

lib/SIL/Parser/ParseSIL.cpp

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3260,14 +3260,30 @@ bool SILParser::parseSpecificSILInstruction(SILBuilder &B,
32603260

32613261
case SILInstructionKind::DebugValueInst: {
32623262
bool poisonRefs = false;
3263+
bool wasMoved = false;
32633264
SILDebugVariable VarInfo;
3264-
if (parseSILOptional(poisonRefs, *this, "poison")
3265-
|| parseTypedValueRef(Val, B) || parseSILDebugVar(VarInfo) ||
3265+
3266+
// Allow for poison and moved to be in either order.
3267+
StringRef attributeName;
3268+
SourceLoc attributeLoc;
3269+
while (parseSILOptional(attributeName, attributeLoc, *this)) {
3270+
if (attributeName == "poison")
3271+
poisonRefs = true;
3272+
else if (attributeName == "moved")
3273+
wasMoved = true;
3274+
else {
3275+
P.diagnose(attributeLoc, diag::sil_invalid_attribute_for_instruction,
3276+
attributeName, "debug_value");
3277+
return true;
3278+
}
3279+
}
3280+
3281+
if (parseTypedValueRef(Val, B) || parseSILDebugVar(VarInfo) ||
32663282
parseSILDebugLocation(InstLoc, B))
32673283
return true;
32683284
if (Val->getType().isAddress())
32693285
assert(!poisonRefs && "debug_value w/ address value does not support poison");
3270-
ResultVal = B.createDebugValue(InstLoc, Val, VarInfo, poisonRefs);
3286+
ResultVal = B.createDebugValue(InstLoc, Val, VarInfo, poisonRefs, wasMoved);
32713287
break;
32723288
}
32733289

@@ -4247,6 +4263,7 @@ bool SILParser::parseSpecificSILInstruction(SILBuilder &B,
42474263
case SILInstructionKind::AllocStackInst: {
42484264
bool hasDynamicLifetime = false;
42494265
bool isLexical = false;
4266+
bool wasMoved = false;
42504267

42514268
StringRef attributeName;
42524269
SourceLoc attributeLoc;
@@ -4255,6 +4272,8 @@ bool SILParser::parseSpecificSILInstruction(SILBuilder &B,
42554272
hasDynamicLifetime = true;
42564273
else if (attributeName == "lexical")
42574274
isLexical = true;
4275+
else if (attributeName == "moved")
4276+
wasMoved = true;
42584277
else {
42594278
P.diagnose(attributeLoc, diag::sil_invalid_attribute_for_instruction,
42604279
attributeName, "alloc_stack");
@@ -4272,10 +4291,10 @@ bool SILParser::parseSpecificSILInstruction(SILBuilder &B,
42724291
// It doesn't make sense to attach a debug var info if the name is empty
42734292
if (VarInfo.Name.size())
42744293
ResultVal = B.createAllocStack(InstLoc, Ty, VarInfo, hasDynamicLifetime,
4275-
isLexical);
4294+
isLexical, wasMoved);
42764295
else
4277-
ResultVal =
4278-
B.createAllocStack(InstLoc, Ty, {}, hasDynamicLifetime, isLexical);
4296+
ResultVal = B.createAllocStack(InstLoc, Ty, {}, hasDynamicLifetime,
4297+
isLexical, wasMoved);
42794298
break;
42804299
}
42814300
case SILInstructionKind::MetatypeInst: {

lib/Serialization/DeserializeSIL.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1249,9 +1249,10 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn,
12491249
assert(RecordKind == SIL_ONE_TYPE && "Layout should be OneType.");
12501250
bool hasDynamicLifetime = Attr & 0x1;
12511251
bool isLexical = (Attr >> 1) & 0x1;
1252+
bool wasMoved = (Attr >> 2) & 0x1;
12521253
ResultInst = Builder.createAllocStack(
12531254
Loc, getSILType(MF->getType(TyID), (SILValueCategory)TyCategory, Fn),
1254-
None, hasDynamicLifetime, isLexical);
1255+
None, hasDynamicLifetime, isLexical, wasMoved);
12551256
break;
12561257
}
12571258
case SILInstructionKind::MetatypeInst:

lib/Serialization/ModuleFormat.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ const uint16_t SWIFTMODULE_VERSION_MAJOR = 0;
5656
/// describe what change you made. The content of this comment isn't important;
5757
/// it just ensures a conflict if two people change the module format.
5858
/// Don't worry about adhering to the 80-column limit for this line.
59-
const uint16_t SWIFTMODULE_VERSION_MINOR = 669; // RequirementMachine protocol typealiases
59+
const uint16_t SWIFTMODULE_VERSION_MINOR = 670; // alloc-stack was-moved
6060

6161
/// A standard hash seed used for all string hashes in a serialized module.
6262
///

0 commit comments

Comments
 (0)