Skip to content

Commit 9055e93

Browse files
committed
SIL: some improvements/fixes around assign_by_wrapper
* Refactoring: replace "Destination" and the ownership qualifier by a single "Mode". This represents much better the mode how the instruction is to be lowered. NFC * Make assign_by_wrapper printable and parseable. * Fix lowering of the assign modes for indirect results of the init-closure: The indirect result was initialized and not assigned to. The fix is to insert a destroy_addr before calling the init closure. This fixes a memory lifetime error and/or a memory leak. Found by inspection. * Fix an iterator-invalidation crash in RawSILInstLowering * Add tests for lowering assign_by_wrapper.
1 parent 2ee7a32 commit 9055e93

File tree

13 files changed

+301
-69
lines changed

13 files changed

+301
-69
lines changed

docs/SIL.rst

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3642,7 +3642,9 @@ assign_by_wrapper
36423642
``````````````````
36433643
::
36443644

3645-
sil-instruction ::= 'assign_by_wrapper' sil-operand 'to' sil-operand ',' 'init' sil-operand ',' 'set' sil-operand
3645+
sil-instruction ::= 'assign_by_wrapper' sil-operand 'to' mode? sil-operand ',' 'init' sil-operand ',' 'set' sil-operand
3646+
3647+
mode ::= '[initialization]' | '[assign]' | '[assign_wrapped_value]'
36463648

36473649
assign_by_wrapper %0 : $S to %1 : $*T, init %2 : $F, set %3 : $G
36483650
// $S can be a value or address type
@@ -3653,13 +3655,22 @@ assign_by_wrapper
36533655
Similar to the `assign`_ instruction, but the assignment is done via a
36543656
delegate.
36553657

3656-
In case of an initialization, the function ``%2`` is called with ``%0`` as
3657-
argument. The result is stored to ``%1``. In case ``%2`` is an address type,
3658-
it is simply passed as a first out-argument to ``%2``.
3658+
Initially the instruction is created with no mode. Once the mode is decided
3659+
(by the definitive initialization pass), the instruction is lowered as follows:
3660+
3661+
If the mode is ``initialization``, the function ``%2`` is called with ``%0`` as
3662+
argument. The result is stored to ``%1``. In case of an address type, ``%1`` is
3663+
simply passed as a first out-argument to ``%2``.
36593664

3660-
In case of a re-assignment, the function ``%3`` is called with ``%0`` as
3661-
argument. As ``%3`` is a setter (e.g. for the property in the containing
3662-
nominal type), the destination address ``%1`` is not used in this case.
3665+
The ``assign`` mode works similar to ``initialization``, except that the
3666+
destination is "assigned" rather than "initialized". This means that the
3667+
existing value in the destination is destroyed before the new value is
3668+
stored.
3669+
3670+
If the mode is ``assign_wrapped_value``, the function ``%3`` is called with
3671+
``%0`` as argument. As ``%3`` is a setter (e.g. for the property in the
3672+
containing nominal type), the destination address ``%1`` is not used in this
3673+
case.
36633674

36643675
This instruction is only valid in Raw SIL and is rewritten as appropriate
36653676
by the definitive initialization pass.

include/swift/SIL/SILBuilder.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -877,10 +877,10 @@ class SILBuilder {
877877
SILValue Src, SILValue Dest,
878878
SILValue Initializer,
879879
SILValue Setter,
880-
AssignOwnershipQualifier Qualifier) {
880+
AssignByWrapperInst::Mode mode) {
881881
return insert(new (getModule())
882882
AssignByWrapperInst(getSILDebugLocation(Loc), Src, Dest,
883-
Initializer, Setter, Qualifier));
883+
Initializer, Setter, mode));
884884
}
885885

886886
StoreBorrowInst *createStoreBorrow(SILLocation Loc, SILValue Src,

include/swift/SIL/SILCloner.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1243,7 +1243,7 @@ void SILCloner<ImplClass>::visitAssignByWrapperInst(AssignByWrapperInst *Inst) {
12431243
getOpValue(Inst->getDest()),
12441244
getOpValue(Inst->getInitializer()),
12451245
getOpValue(Inst->getSetter()),
1246-
Inst->getOwnershipQualifier()));
1246+
Inst->getMode()));
12471247
}
12481248

12491249
template<typename ImplClass>

include/swift/SIL/SILInstruction.h

Lines changed: 21 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -4370,39 +4370,38 @@ class AssignByWrapperInst
43704370
friend SILBuilder;
43714371

43724372
public:
4373-
/// The assignment destination for the property wrapper
4374-
enum class Destination {
4375-
BackingWrapper,
4376-
WrappedValue,
4373+
enum Mode {
4374+
/// The mode is not decided yet (by DefiniteInitialization).
4375+
Unknown,
4376+
4377+
/// The initializer is called with Src as argument. The result is stored to
4378+
/// Dest.
4379+
Initialization,
4380+
4381+
// Like ``Initialization``, except that the destination is "assigned" rather
4382+
// than "initialized". This means that the existing value in the destination
4383+
// is destroyed before the new value is stored.
4384+
Assign,
4385+
4386+
/// The setter is called with Src as argument. The Dest is not used in this
4387+
/// case.
4388+
AssignWrappedValue
43774389
};
43784390

43794391
private:
4380-
Destination AssignDest = Destination::WrappedValue;
4381-
43824392
AssignByWrapperInst(SILDebugLocation DebugLoc, SILValue Src, SILValue Dest,
4383-
SILValue Initializer, SILValue Setter,
4384-
AssignOwnershipQualifier Qualifier =
4385-
AssignOwnershipQualifier::Unknown);
4393+
SILValue Initializer, SILValue Setter, Mode mode);
43864394

43874395
public:
4388-
43894396
SILValue getInitializer() { return Operands[2].get(); }
43904397
SILValue getSetter() { return Operands[3].get(); }
43914398

4392-
AssignOwnershipQualifier getOwnershipQualifier() const {
4393-
return AssignOwnershipQualifier(
4394-
SILNode::Bits.AssignByWrapperInst.OwnershipQualifier);
4399+
Mode getMode() const {
4400+
return Mode(SILNode::Bits.AssignByWrapperInst.Mode);
43954401
}
43964402

4397-
Destination getAssignDestination() const { return AssignDest; }
4398-
4399-
void setAssignInfo(AssignOwnershipQualifier qualifier, Destination dest) {
4400-
assert(qualifier == AssignOwnershipQualifier::Init && dest == Destination::BackingWrapper ||
4401-
qualifier == AssignOwnershipQualifier::Reassign && dest == Destination::BackingWrapper ||
4402-
qualifier == AssignOwnershipQualifier::Reassign && dest == Destination::WrappedValue);
4403-
4404-
SILNode::Bits.AssignByWrapperInst.OwnershipQualifier = unsigned(qualifier);
4405-
AssignDest = dest;
4403+
void setMode(Mode mode) {
4404+
SILNode::Bits.AssignByWrapperInst.Mode = unsigned(mode);
44064405
}
44074406
};
44084407

include/swift/SIL/SILNode.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,7 @@ class alignas(8) SILNode {
120120
enum { NumStoreOwnershipQualifierBits = 2 };
121121
enum { NumLoadOwnershipQualifierBits = 2 };
122122
enum { NumAssignOwnershipQualifierBits = 2 };
123+
enum { NumAssignByWrapperModeBits = 2 };
123124
enum { NumSILAccessKindBits = 2 };
124125
enum { NumSILAccessEnforcementBits = 2 };
125126

@@ -311,8 +312,8 @@ class alignas(8) SILNode {
311312
OwnershipQualifier : NumAssignOwnershipQualifierBits
312313
);
313314
SWIFT_INLINE_BITFIELD(AssignByWrapperInst, NonValueInstruction,
314-
NumAssignOwnershipQualifierBits,
315-
OwnershipQualifier : NumAssignOwnershipQualifierBits
315+
NumAssignByWrapperModeBits,
316+
Mode : NumAssignByWrapperModeBits
316317
);
317318

318319
SWIFT_INLINE_BITFIELD(UncheckedOwnershipConversionInst,SingleValueInstruction,

lib/SIL/IR/SILInstructions.cpp

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1080,11 +1080,10 @@ AssignByWrapperInst::AssignByWrapperInst(SILDebugLocation Loc,
10801080
SILValue Src, SILValue Dest,
10811081
SILValue Initializer,
10821082
SILValue Setter,
1083-
AssignOwnershipQualifier Qualifier) :
1083+
AssignByWrapperInst::Mode mode) :
10841084
AssignInstBase(Loc, Src, Dest, Initializer, Setter) {
10851085
assert(Initializer->getType().is<SILFunctionType>());
1086-
SILNode::Bits.AssignByWrapperInst.OwnershipQualifier =
1087-
unsigned(Qualifier);
1086+
SILNode::Bits.AssignByWrapperInst.Mode = unsigned(mode);
10881087
}
10891088

10901089
MarkFunctionEscapeInst *

lib/SIL/IR/SILPrinter.cpp

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1453,7 +1453,19 @@ class SILPrinter : public SILInstructionVisitor<SILPrinter> {
14531453

14541454
void visitAssignByWrapperInst(AssignByWrapperInst *AI) {
14551455
*this << getIDAndType(AI->getSrc()) << " to ";
1456-
printAssignOwnershipQualifier(AI->getOwnershipQualifier());
1456+
switch (AI->getMode()) {
1457+
case AssignByWrapperInst::Unknown:
1458+
break;
1459+
case AssignByWrapperInst::Initialization:
1460+
*this << "[initialization] ";
1461+
break;
1462+
case AssignByWrapperInst::Assign:
1463+
*this << "[assign] ";
1464+
break;
1465+
case AssignByWrapperInst::AssignWrappedValue:
1466+
*this << "[assign_wrapped_value] ";
1467+
break;
1468+
}
14571469
*this << getIDAndType(AI->getDest())
14581470
<< ", init " << getIDAndType(AI->getInitializer())
14591471
<< ", set " << getIDAndType(AI->getSetter());

lib/SIL/Parser/ParseSIL.cpp

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1981,6 +1981,32 @@ static bool parseAssignOwnershipQualifier(AssignOwnershipQualifier &Result,
19811981
return false;
19821982
}
19831983

1984+
static bool parseAssignByWrapperMode(AssignByWrapperInst::Mode &Result,
1985+
SILParser &P) {
1986+
StringRef Str;
1987+
// If we do not parse '[' ... ']', we have unknown. Set value and return.
1988+
if (!parseSILOptional(Str, P)) {
1989+
Result = AssignByWrapperInst::Unknown;
1990+
return false;
1991+
}
1992+
1993+
// Then try to parse one of our other initialization kinds. We do not support
1994+
// parsing unknown here so we use that as our fail value.
1995+
auto Tmp = llvm::StringSwitch<AssignByWrapperInst::Mode>(Str)
1996+
.Case("initialization", AssignByWrapperInst::Initialization)
1997+
.Case("assign", AssignByWrapperInst::Assign)
1998+
.Case("assign_wrapped_value", AssignByWrapperInst::AssignWrappedValue)
1999+
.Default(AssignByWrapperInst::Unknown);
2000+
2001+
// Thus return true (following the conventions in this file) if we fail.
2002+
if (Tmp == AssignByWrapperInst::Unknown)
2003+
return true;
2004+
2005+
// Otherwise, assign Result and return false.
2006+
Result = Tmp;
2007+
return false;
2008+
}
2009+
19842010
// Parse a list of integer indices, prefaced with the given string label.
19852011
// Returns true on error.
19862012
static bool parseIndexList(Parser &P, StringRef label,
@@ -3659,9 +3685,9 @@ bool SILParser::parseSpecificSILInstruction(SILBuilder &B,
36593685
case SILInstructionKind::AssignByWrapperInst: {
36603686
SILValue Src, DestAddr, InitFn, SetFn;
36613687
SourceLoc DestLoc;
3662-
AssignOwnershipQualifier AssignQualifier;
3688+
AssignByWrapperInst::Mode mode;
36633689
if (parseTypedValueRef(Src, B) || parseVerbatim("to") ||
3664-
parseAssignOwnershipQualifier(AssignQualifier, *this) ||
3690+
parseAssignByWrapperMode(mode, *this) ||
36653691
parseTypedValueRef(DestAddr, DestLoc, B) ||
36663692
P.parseToken(tok::comma, diag::expected_tok_in_sil_instr, ",") ||
36673693
parseVerbatim("init") || parseTypedValueRef(InitFn, B) ||
@@ -3677,7 +3703,7 @@ bool SILParser::parseSpecificSILInstruction(SILBuilder &B,
36773703
}
36783704

36793705
ResultVal = B.createAssignByWrapper(InstLoc, Src, DestAddr, InitFn, SetFn,
3680-
AssignQualifier);
3706+
mode);
36813707
break;
36823708
}
36833709

lib/SILGen/SILGenLValue.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1549,7 +1549,7 @@ namespace {
15491549

15501550
SGF.B.createAssignByWrapper(loc, Mval.forward(SGF), proj.forward(SGF),
15511551
initFn.getValue(), setterFn.getValue(),
1552-
AssignOwnershipQualifier::Unknown);
1552+
AssignByWrapperInst::Unknown);
15531553

15541554
return;
15551555
}

lib/SILOptimizer/Mandatory/DefiniteInitialization.cpp

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2012,16 +2012,13 @@ void LifetimeChecker::updateInstructionForInitState(unsigned UseID) {
20122012

20132013
switch (Use.Kind) {
20142014
case DIUseKind::Initialization:
2015-
AI->setAssignInfo(AssignOwnershipQualifier::Init,
2016-
AssignByWrapperInst::Destination::BackingWrapper);
2015+
AI->setMode(AssignByWrapperInst::Initialization);
20172016
break;
20182017
case DIUseKind::Assign:
2019-
AI->setAssignInfo(AssignOwnershipQualifier::Reassign,
2020-
AssignByWrapperInst::Destination::BackingWrapper);
2018+
AI->setMode(AssignByWrapperInst::Assign);
20212019
break;
20222020
case DIUseKind::AssignWrappedValue:
2023-
AI->setAssignInfo(AssignOwnershipQualifier::Reassign,
2024-
AssignByWrapperInst::Destination::WrappedValue);
2021+
AI->setMode(AssignByWrapperInst::AssignWrappedValue);
20252022
break;
20262023
default:
20272024
llvm_unreachable("Wrong use kind for assign_by_wrapper");

0 commit comments

Comments
 (0)