Skip to content

Commit c4f6fc3

Browse files
authored
Merge pull request #36253 from eeckstein/fix-assign-by-wrapper
SIL: some improvements/fixes around assign_by_wrapper
2 parents 87b9e63 + 9055e93 commit c4f6fc3

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
@@ -3650,7 +3650,9 @@ assign_by_wrapper
36503650
``````````````````
36513651
::
36523652

3653-
sil-instruction ::= 'assign_by_wrapper' sil-operand 'to' sil-operand ',' 'init' sil-operand ',' 'set' sil-operand
3653+
sil-instruction ::= 'assign_by_wrapper' sil-operand 'to' mode? sil-operand ',' 'init' sil-operand ',' 'set' sil-operand
3654+
3655+
mode ::= '[initialization]' | '[assign]' | '[assign_wrapped_value]'
36543656

36553657
assign_by_wrapper %0 : $S to %1 : $*T, init %2 : $F, set %3 : $G
36563658
// $S can be a value or address type
@@ -3661,13 +3663,22 @@ assign_by_wrapper
36613663
Similar to the `assign`_ instruction, but the assignment is done via a
36623664
delegate.
36633665

3664-
In case of an initialization, the function ``%2`` is called with ``%0`` as
3665-
argument. The result is stored to ``%1``. In case ``%2`` is an address type,
3666-
it is simply passed as a first out-argument to ``%2``.
3666+
Initially the instruction is created with no mode. Once the mode is decided
3667+
(by the definitive initialization pass), the instruction is lowered as follows:
3668+
3669+
If the mode is ``initialization``, the function ``%2`` is called with ``%0`` as
3670+
argument. The result is stored to ``%1``. In case of an address type, ``%1`` is
3671+
simply passed as a first out-argument to ``%2``.
36673672

3668-
In case of a re-assignment, the function ``%3`` is called with ``%0`` as
3669-
argument. As ``%3`` is a setter (e.g. for the property in the containing
3670-
nominal type), the destination address ``%1`` is not used in this case.
3673+
The ``assign`` mode works similar to ``initialization``, except that the
3674+
destination is "assigned" rather than "initialized". This means that the
3675+
existing value in the destination is destroyed before the new value is
3676+
stored.
3677+
3678+
If the mode is ``assign_wrapped_value``, the function ``%3`` is called with
3679+
``%0`` as argument. As ``%3`` is a setter (e.g. for the property in the
3680+
containing nominal type), the destination address ``%1`` is not used in this
3681+
case.
36713682

36723683
This instruction is only valid in Raw SIL and is rewritten as appropriate
36733684
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,
@@ -3725,9 +3751,9 @@ bool SILParser::parseSpecificSILInstruction(SILBuilder &B,
37253751
case SILInstructionKind::AssignByWrapperInst: {
37263752
SILValue Src, DestAddr, InitFn, SetFn;
37273753
SourceLoc DestLoc;
3728-
AssignOwnershipQualifier AssignQualifier;
3754+
AssignByWrapperInst::Mode mode;
37293755
if (parseTypedValueRef(Src, B) || parseVerbatim("to") ||
3730-
parseAssignOwnershipQualifier(AssignQualifier, *this) ||
3756+
parseAssignByWrapperMode(mode, *this) ||
37313757
parseTypedValueRef(DestAddr, DestLoc, B) ||
37323758
P.parseToken(tok::comma, diag::expected_tok_in_sil_instr, ",") ||
37333759
parseVerbatim("init") || parseTypedValueRef(InitFn, B) ||
@@ -3743,7 +3769,7 @@ bool SILParser::parseSpecificSILInstruction(SILBuilder &B,
37433769
}
37443770

37453771
ResultVal = B.createAssignByWrapper(InstLoc, Src, DestAddr, InitFn, SetFn,
3746-
AssignQualifier);
3772+
mode);
37473773
break;
37483774
}
37493775

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");

lib/SILOptimizer/Mandatory/RawSILInstLowering.cpp

Lines changed: 32 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -167,44 +167,52 @@ static void getAssignByWrapperArgs(SmallVectorImpl<SILValue> &args,
167167

168168
static void lowerAssignByWrapperInstruction(SILBuilderWithScope &b,
169169
AssignByWrapperInst *inst,
170-
SmallVectorImpl<BeginAccessInst *> &accessMarkers) {
171-
LLVM_DEBUG(llvm::dbgs() << " *** Lowering [isInit="
172-
<< unsigned(inst->getOwnershipQualifier())
173-
<< "]: " << *inst << "\n");
170+
SmallSetVector<SILValue, 8> &toDelete) {
171+
LLVM_DEBUG(llvm::dbgs() << " *** Lowering " << *inst << "\n");
174172

175173
++numAssignRewritten;
176174

177175
SILValue src = inst->getSrc();
178176
SILValue dest = inst->getDest();
179177
SILLocation loc = inst->getLoc();
180178
SILBuilderWithScope forCleanup(std::next(inst->getIterator()));
181-
SingleValueInstruction *closureToDelete = nullptr;
179+
180+
switch (inst->getMode()) {
181+
case AssignByWrapperInst::Unknown:
182+
llvm_unreachable("assign_by_wrapper must have a valid mode");
182183

183-
switch (inst->getAssignDestination()) {
184-
case AssignByWrapperInst::Destination::BackingWrapper: {
184+
case AssignByWrapperInst::Initialization:
185+
case AssignByWrapperInst::Assign: {
185186
SILValue initFn = inst->getInitializer();
186187
CanSILFunctionType fTy = initFn->getType().castTo<SILFunctionType>();
187188
SILFunctionConventions convention(fTy, inst->getModule());
188189
SmallVector<SILValue, 4> args;
189190
if (convention.hasIndirectSILResults()) {
191+
if (inst->getMode() == AssignByWrapperInst::Assign)
192+
b.createDestroyAddr(loc, dest);
193+
190194
args.push_back(dest);
191195
getAssignByWrapperArgs(args, src, convention, b, forCleanup);
192196
b.createApply(loc, initFn, SubstitutionMap(), args);
193197
} else {
194198
getAssignByWrapperArgs(args, src, convention, b, forCleanup);
195199
SILValue wrappedSrc = b.createApply(loc, initFn, SubstitutionMap(),
196200
args);
197-
if (inst->getOwnershipQualifier() == AssignOwnershipQualifier::Init ||
201+
if (inst->getMode() == AssignByWrapperInst::Initialization ||
198202
inst->getDest()->getType().isTrivial(*inst->getFunction())) {
199-
b.createTrivialStoreOr(loc, wrappedSrc, dest, StoreOwnershipQualifier::Init);
203+
b.createTrivialStoreOr(loc, wrappedSrc, dest,
204+
StoreOwnershipQualifier::Init);
200205
} else {
201206
b.createStore(loc, wrappedSrc, dest, StoreOwnershipQualifier::Assign);
202207
}
203208
}
204-
closureToDelete = dyn_cast<SingleValueInstruction>(inst->getSetter());
209+
// The unused partial_apply violates memory lifetime rules in case "self"
210+
// is an inout. Therefore we cannot keep it as a dead closure to be
211+
// cleaned up later. We have to delete it in this pass.
212+
toDelete.insert(inst->getSetter());
205213
break;
206214
}
207-
case AssignByWrapperInst::Destination::WrappedValue: {
215+
case AssignByWrapperInst::AssignWrappedValue: {
208216
SILValue setterFn = inst->getSetter();
209217
CanSILFunctionType fTy = setterFn->getType().castTo<SILFunctionType>();
210218
SILFunctionConventions convention(fTy, inst->getModule());
@@ -217,15 +225,15 @@ static void lowerAssignByWrapperInstruction(SILBuilderWithScope &b,
217225
// marker. This is important, because also the setter function contains
218226
// access marker. In case those markers are dynamic it would cause a
219227
// nested access violation.
220-
if (auto *BA = dyn_cast<BeginAccessInst>(dest))
221-
accessMarkers.push_back(BA);
222-
closureToDelete = dyn_cast<SingleValueInstruction>(inst->getInitializer());
228+
if (isa<BeginAccessInst>(dest))
229+
toDelete.insert(dest);
230+
231+
// Again, we have to delete the unused dead closure.
232+
toDelete.insert(inst->getInitializer());
223233
break;
224234
}
225235
}
226236
inst->eraseFromParent();
227-
if (closureToDelete)
228-
tryDeleteDeadClosure(closureToDelete);
229237
}
230238

231239
static void deleteDeadAccessMarker(BeginAccessInst *BA) {
@@ -250,7 +258,7 @@ static bool lowerRawSILOperations(SILFunction &fn) {
250258
bool changed = false;
251259

252260
for (auto &bb : fn) {
253-
SmallVector<BeginAccessInst *, 8> accessMarkers;
261+
SmallSetVector<SILValue, 8> toDelete;
254262

255263
auto i = bb.begin(), e = bb.end();
256264
while (i != e) {
@@ -280,7 +288,7 @@ static bool lowerRawSILOperations(SILFunction &fn) {
280288

281289
if (auto *ai = dyn_cast<AssignByWrapperInst>(inst)) {
282290
SILBuilderWithScope b(ai);
283-
lowerAssignByWrapperInstruction(b, ai, accessMarkers);
291+
lowerAssignByWrapperInstruction(b, ai, toDelete);
284292
changed = true;
285293
continue;
286294
}
@@ -300,8 +308,12 @@ static bool lowerRawSILOperations(SILFunction &fn) {
300308
continue;
301309
}
302310
}
303-
for (BeginAccessInst *BA : accessMarkers) {
304-
deleteDeadAccessMarker(BA);
311+
for (SILValue deadVal : toDelete) {
312+
if (auto *beginAccess = dyn_cast<BeginAccessInst>(deadVal)) {
313+
deleteDeadAccessMarker(beginAccess);
314+
} else if (auto *svi = dyn_cast<SingleValueInstruction>(deadVal)) {
315+
tryDeleteDeadClosure(svi);
316+
}
305317
}
306318
}
307319
return changed;

0 commit comments

Comments
 (0)