Skip to content

Commit 6058b1d

Browse files
committed
[silgen] Change SILGen to emit ignored_user for emitIgnoredExpr and black hole initialization.
1 parent 7ae56aa commit 6058b1d

30 files changed

+168
-65
lines changed

lib/SIL/Verifier/SILVerifier.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -719,6 +719,7 @@ struct ImmutableAddressUseVerifier {
719719
case SILInstructionKind::KeyPathInst:
720720
case SILInstructionKind::SwitchEnumAddrInst:
721721
case SILInstructionKind::SelectEnumAddrInst:
722+
case SILInstructionKind::IgnoredUseInst:
722723
break;
723724
case SILInstructionKind::DebugValueInst:
724725
if (cast<DebugValueInst>(inst)->hasAddrVal())

lib/SILGen/SILGenDecl.cpp

Lines changed: 36 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1582,38 +1582,34 @@ void SILGenFunction::emitPatternBinding(PatternBindingDecl *PBD, unsigned idx,
15821582
return nullptr;
15831583
};
15841584

1585-
auto emitInitializer = [&](Expr *initExpr, VarDecl *var, bool forLocalContext,
1586-
InitializationPtr &initialization) {
1587-
// If an initial value expression was specified by the decl, emit it into
1588-
// the initialization.
1589-
FullExpr Scope(Cleanups, CleanupLocation(initExpr));
1590-
1591-
if (forLocalContext) {
1592-
if (auto *orig = var->getOriginalWrappedProperty()) {
1593-
if (auto *initExpr = getWrappedValueExpr(var)) {
1594-
auto value = emitRValue(initExpr);
1595-
emitApplyOfPropertyWrapperBackingInitializer(
1585+
auto *initExpr = PBD->getExecutableInit(idx);
1586+
1587+
// If we do not have an explicit initialization expression, just mark the
1588+
// initialization as unfinished for DI to resolve.
1589+
if (!initExpr) {
1590+
return initialization->finishUninitialized(*this);
1591+
}
1592+
1593+
// Otherwise, an initial value expression was specified by the decl... emit it
1594+
// into the initialization.
1595+
FullExpr Scope(Cleanups, CleanupLocation(initExpr));
1596+
1597+
auto *singleVar = PBD->getSingleVar();
1598+
bool isLocalSingleVar =
1599+
singleVar && singleVar->getDeclContext()->isLocalContext();
1600+
if (isLocalSingleVar) {
1601+
if (auto *orig = singleVar->getOriginalWrappedProperty()) {
1602+
if (auto *initExpr = getWrappedValueExpr(singleVar)) {
1603+
auto value = emitRValue(initExpr);
1604+
emitApplyOfPropertyWrapperBackingInitializer(
15961605
PBD, orig, getForwardingSubstitutionMap(), std::move(value))
15971606
.forwardInto(*this, SILLocation(PBD), initialization.get());
1598-
return;
1599-
}
1607+
return;
16001608
}
16011609
}
1602-
1603-
emitExprInto(initExpr, initialization.get());
1604-
};
1605-
1606-
auto *singleVar = PBD->getSingleVar();
1607-
if (auto *Init = PBD->getExecutableInit(idx)) {
1608-
// If an initial value expression was specified by the decl, emit it into
1609-
// the initialization.
1610-
bool isLocalVar =
1611-
singleVar && singleVar->getDeclContext()->isLocalContext();
1612-
emitInitializer(Init, singleVar, isLocalVar, initialization);
1613-
} else {
1614-
// Otherwise, mark it uninitialized for DI to resolve.
1615-
initialization->finishUninitialized(*this);
16161610
}
1611+
1612+
emitExprInto(initExpr, initialization.get());
16171613
}
16181614

16191615
void SILGenFunction::visitPatternBindingDecl(PatternBindingDecl *PBD,
@@ -2421,18 +2417,23 @@ void BlackHoleInitialization::performPackExpansionInitialization(
24212417

24222418
void BlackHoleInitialization::copyOrInitValueInto(SILGenFunction &SGF, SILLocation loc,
24232419
ManagedValue value, bool isInit) {
2424-
// Normally we do not do anything if we have a black hole
2425-
// initialization... but if we have a move only object, insert a move value.
2426-
if (!value.getType().isMoveOnly())
2420+
// If we do not have a noncopyable type, just insert an ignored use.
2421+
if (!value.getType().isMoveOnly()) {
2422+
SGF.B.createIgnoredUse(loc, value.getValue());
24272423
return;
2424+
}
24282425

2429-
// If we have an address, then this will create a new temporary allocation
2430-
// which will trigger the move checker. If we have an object though, we need
2431-
// to insert an extra move_value to make sure the object checker behaves
2432-
// correctly.
2426+
// If we have a noncopyable type, we need to do a little more work to satisfy
2427+
// the move checkers. If we have an address, then this will create a new
2428+
// temporary allocation which will trigger the move checker...
24332429
value = value.ensurePlusOne(SGF, loc);
2434-
if (value.getType().isAddress())
2430+
if (value.getType().isAddress()) {
2431+
SGF.B.createIgnoredUse(loc, value.getValue());
24352432
return;
2433+
}
24362434

2435+
// If we have an object though, we need to insert an extra move_value to make
2436+
// sure the object checker behaves correctly.
24372437
value = SGF.B.createMoveValue(loc, value);
2438+
SGF.B.createIgnoredUse(loc, value.getValue());
24382439
}

lib/SILGen/SILGenExpr.cpp

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5376,7 +5376,19 @@ static void emitSimpleAssignment(SILGenFunction &SGF, SILLocation loc,
53765376
value = value.ensurePlusOne(SGF, loc);
53775377
if (value.getType().isObject())
53785378
value = SGF.B.createMoveValue(loc, value);
5379+
SGF.B.createIgnoredUse(loc, value.getValue());
5380+
return;
5381+
}
5382+
5383+
// Emit the ignored use instruction like we would do in emitIgnoredExpr.
5384+
if (!rv.isNull()) {
5385+
SmallVector<ManagedValue, 16> values;
5386+
std::move(rv).getAll(values);
5387+
for (auto v : values) {
5388+
SGF.B.createIgnoredUse(loc, v.getValue());
5389+
}
53795390
}
5391+
53805392
return;
53815393
}
53825394

@@ -7027,7 +7039,24 @@ void SILGenFunction::emitIgnoredExpr(Expr *E) {
70277039

70287040
// Otherwise, emit the result (to get any side effects), but produce it at +0
70297041
// if that allows simplification.
7030-
emitRValue(E, SGFContext::AllowImmediatePlusZero);
7042+
RValue rv = emitRValue(E, SGFContext::AllowImmediatePlusZero);
7043+
7044+
// Return early if we do not have any result.
7045+
if (rv.isNull())
7046+
return;
7047+
7048+
// Then emit ignored use on all of the rvalue components. We purposely do not
7049+
// implode the tuple since if we have a tuple formation like:
7050+
//
7051+
// let _ = (x, y)
7052+
//
7053+
// we want the use to be on x and y and not on the imploded tuple. It also
7054+
// helps us avoid emitting unnecessary code.
7055+
SmallVector<ManagedValue, 16> values;
7056+
std::move(rv).getAll(values);
7057+
for (auto v : values) {
7058+
B.createIgnoredUse(E, v.getValue());
7059+
}
70317060
}
70327061

70337062
/// Emit the given expression as an r-value, then (if it is a tuple), combine

lib/SILOptimizer/Mandatory/DiagnoseUnreachable.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -775,6 +775,14 @@ static bool simplifyBlocksWithCallsToNoReturn(SILBasicBlock &BB,
775775
if (isa<EndBorrowInst>(currInst))
776776
return false;
777777

778+
// If we have an ignored use whose operand is our no return call, ignore it.
779+
if (auto *i = dyn_cast<IgnoredUseInst>(currInst)) {
780+
if (auto *svi = dyn_cast<SingleValueInstruction>(i->getOperand());
781+
svi && getAsCallToNoReturn(svi)) {
782+
return false;
783+
}
784+
}
785+
778786
// destroy_value [dead_end] instructions are inserted at the availability
779787
// boundary by lifetime completion. Such instructions correctly mark the
780788
// lifetime boundary of the destroyed value and never arise from dead user

lib/SILOptimizer/Mandatory/LowerTupleAddrConstructor.cpp

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -78,46 +78,53 @@ class LowerTupleAddrConstructorTransform : public SILFunctionTransform {
7878
bool deletedInst = false;
7979
for (auto &block : *function) {
8080
for (auto ii = block.begin(), ie = block.end(); ii != ie;) {
81-
auto *inst = dyn_cast<TupleAddrConstructorInst>(&*ii);
81+
auto *inst = &*ii;
8282
++ii;
8383

84-
if (!inst)
84+
if (auto *i = dyn_cast<IgnoredUseInst>(inst)) {
85+
i->eraseFromParent();
86+
deletedInst = true;
87+
continue;
88+
}
89+
90+
auto *t = dyn_cast<TupleAddrConstructorInst>(inst);
91+
if (!t)
8592
continue;
8693

8794
// (tuple_addr_constructor [assign/init] %addr,
8895
// (destructure_tuple %tuple))
8996
// ->
9097
// (store [assign/init] %tuple to %addr)
91-
if (peepholeTupleDestructorOperand(inst)) {
98+
if (peepholeTupleDestructorOperand(t)) {
9299
continue;
93100
}
94101

95102
SILBuilderWithScope builder(inst);
96103

97104
unsigned count = 0;
98105
visitExplodedTupleValue(
99-
inst->getDest(),
106+
t->getDest(),
100107
[&](SILValue value, std::optional<unsigned> index) -> SILValue {
101108
if (!index) {
102-
SILValue elt = inst->getElement(count);
109+
SILValue elt = t->getElement(count);
103110
if (elt->getType().isAddress()) {
104-
builder.createCopyAddr(inst->getLoc(), elt, value, IsTake,
105-
inst->isInitializationOfDest());
111+
builder.createCopyAddr(t->getLoc(), elt, value, IsTake,
112+
t->isInitializationOfDest());
106113
} else {
107114
builder.emitStoreValueOperation(
108-
inst->getLoc(), elt, value,
109-
bool(inst->isInitializationOfDest())
115+
t->getLoc(), elt, value,
116+
bool(t->isInitializationOfDest())
110117
? StoreOwnershipQualifier::Init
111118
: StoreOwnershipQualifier::Assign);
112119
}
113120
++count;
114121
return value;
115122
}
116123
auto *teai =
117-
builder.createTupleElementAddr(inst->getLoc(), value, *index);
124+
builder.createTupleElementAddr(t->getLoc(), value, *index);
118125
return teai;
119126
});
120-
inst->eraseFromParent();
127+
t->eraseFromParent();
121128
deletedInst = true;
122129
}
123130
}

lib/SILOptimizer/Mandatory/MoveOnlyWrappedTypeEliminator.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,7 @@ struct SILMoveOnlyWrappedTypeEliminatorVisitor
210210
NO_UPDATE_NEEDED(AddressToPointer)
211211
NO_UPDATE_NEEDED(ExistentialMetatype)
212212
NO_UPDATE_NEEDED(Builtin)
213+
NO_UPDATE_NEEDED(IgnoredUse)
213214
#undef NO_UPDATE_NEEDED
214215

215216
bool eliminateIdentityCast(SingleValueInstruction *svi) {

lib/SILOptimizer/Mandatory/OwnershipModelEliminator.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,11 @@ struct OwnershipModelEliminatorVisitor
139139
bool visitExplicitCopyAddrInst(ExplicitCopyAddrInst *cai);
140140
bool visitApplyInst(ApplyInst *ai);
141141

142+
bool visitIgnoredUseInst(IgnoredUseInst *iui) {
143+
eraseInstruction(iui);
144+
return true;
145+
}
146+
142147
void splitDestroy(DestroyValueInst *destroy);
143148
bool peepholeTupleConstructorUser(DestructureTupleInst *dti);
144149
bool visitDestroyValueInst(DestroyValueInst *dvi);

test/AutoDiff/SILOptimizer/activity_analysis.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,7 @@ func checked_cast_addr_nonactive_result<T: Differentiable>(_ x: T) -> T {
191191
// CHECK: bb5:
192192
// CHECK: [VARIED] %18 = argument of bb5 : $Float
193193
// CHECK: bb6:
194-
// CHECK: [NONE] %22 = tuple ()
194+
// CHECK: [NONE] %{{.*}} = tuple ()
195195

196196
// CHECK-LABEL: sil hidden [ossa] @${{.*}}checked_cast_addr_nonactive_result{{.*}} : $@convention(thin) <T where T : Differentiable> (@in_guaranteed T) -> @out T {
197197
// CHECK: checked_cast_addr_br take_always T in %3 : $*T to Float in %5 : $*Float, bb1, bb2

test/Concurrency/transfernonsendable.swift

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -887,8 +887,8 @@ func letSendableNonTrivialLetStructFieldTest() async {
887887
await transferToMain(test) // expected-tns-warning {{sending 'test' risks causing data races}}
888888
// expected-tns-note @-1 {{sending 'test' to main actor-isolated global function 'transferToMain' risks causing data races between main actor-isolated and local nonisolated uses}}
889889
// expected-complete-warning @-2 {{passing argument of non-sendable type 'StructFieldTests' into main actor-isolated context may introduce data races}}
890-
_ = test.letSendableNonTrivial
891-
useValue(test) // expected-tns-note {{access can happen concurrently}}
890+
_ = test.letSendableNonTrivial // expected-tns-note {{access can happen concurrently}}
891+
useValue(test)
892892
}
893893

894894
func letNonSendableNonTrivialLetStructFieldTest() async {
@@ -968,8 +968,8 @@ func varSendableNonTrivialLetStructFieldTest() async {
968968
await transferToMain(test) // expected-tns-warning {{sending 'test' risks causing data races}}
969969
// expected-tns-note @-1 {{sending 'test' to main actor-isolated global function 'transferToMain' risks causing data races between main actor-isolated and local nonisolated uses}}
970970
// expected-complete-warning @-2 {{passing argument of non-sendable type 'StructFieldTests' into main actor-isolated context may introduce data races}}
971-
_ = test.varSendableNonTrivial
972-
useValue(test) // expected-tns-note {{access can happen concurrently}}
971+
_ = test.varSendableNonTrivial // expected-tns-note {{access can happen concurrently}}
972+
useValue(test)
973973
}
974974

975975
func varNonSendableNonTrivialLetStructFieldTest() async {

test/SILGen/class_bound_protocols.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,7 @@ func takesInheritsMutatingMethod(x: inout InheritsMutatingMethod,
198198
// CHECK-NEXT: end_borrow
199199
// CHECK-NEXT: destroy_addr
200200
// CHECK-NEXT: end_access [[X_ADDR]] : $*any InheritsMutatingMethod
201+
// CHECK-NEXT: ignored_use [[RESULT_VALUE]]
201202
// CHECK-NEXT: dealloc_stack [[TEMPORARY]] : $*@opened("{{.*}}", any InheritsMutatingMethod) Self
202203
_ = x.mutatingCounter
203204

test/SILGen/do_expr.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ func test6() -> Int {
5656
// CHECK: try_apply [[THROWS_ERR_FN]]({{%[0-9]+}}) : $@convention(thin) (Int) -> (Int, @error any Error), normal [[BB_NORMAL:bb[0-9]+]], error [[BB_ERR:bb[0-9]+]]
5757
//
5858
// CHECK: [[BB_NORMAL]]
59+
// CHECK-NEXT: ignored_use
5960
// CHECK-NEXT: store [[MVY]] to [trivial] [[RESULT]] : $*Int
6061
// CHECK-NEXT: extend_lifetime [[MVY]] : $Int
6162
// CHECK-NEXT: br [[BB_EXIT:bb[0-9]+]]

test/SILGen/enum.swift

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ enum Boolish {
1010
func Boolish_cases() {
1111
// CHECK: [[BOOLISH:%[0-9]+]] = metatype $@thin Boolish.Type
1212
// CHECK-NEXT: [[FALSY:%[0-9]+]] = enum $Boolish, #Boolish.falsy!enumelt
13+
// CHECK-NEXT: ignored_use
1314
_ = Boolish.falsy
1415

1516
// CHECK-NEXT: [[BOOLISH:%[0-9]+]] = metatype $@thin Boolish.Type
@@ -52,12 +53,14 @@ func AddressOnly_cases(_ s: S) {
5253
// CHECK: [[METATYPE:%.*]] = metatype $@thin AddressOnly.Type
5354
// CHECK: [[FN:%.*]] = function_ref @$s4enum17AddressOnly_casesyyAA1SVFAA0bC0OAA1P_pcAFmcfu_
5455
// CHECK-NEXT: [[CTOR:%.*]] = apply [[FN]]([[METATYPE]])
56+
// CHECK-NEXT: ignored_use
5557
// CHECK-NEXT: destroy_value [[CTOR]]
5658
_ = AddressOnly.mere
5759

5860
// CHECK-NEXT: [[METATYPE:%.*]] = metatype $@thin AddressOnly.Type
5961
// CHECK-NEXT: [[NOUGHT:%.*]] = alloc_stack $AddressOnly
6062
// CHECK-NEXT: inject_enum_addr [[NOUGHT]]
63+
// CHECK-NEXT: ignored_use
6164
// CHECK-NEXT: destroy_addr [[NOUGHT]]
6265
// CHECK-NEXT: dealloc_stack [[NOUGHT]]
6366
_ = AddressOnly.nought
@@ -68,6 +71,7 @@ func AddressOnly_cases(_ s: S) {
6871
// CHECK-NEXT: [[PAYLOAD_ADDR:%.*]] = init_existential_addr [[PAYLOAD]]
6972
// CHECK-NEXT: store %0 to [trivial] [[PAYLOAD_ADDR]]
7073
// CHECK-NEXT: inject_enum_addr [[MERE]]
74+
// CHECK-NEXT: ignored_use
7175
// CHECK-NEXT: destroy_addr [[MERE]]
7276
// CHECK-NEXT: dealloc_stack [[MERE]]
7377
_ = AddressOnly.mere(s)
@@ -79,6 +83,7 @@ func AddressOnly_cases(_ s: S) {
7983
// CHECK-NEXT: [[PAYLOAD:%.*]] = init_enum_data_addr [[PHANTOM]] : $*AddressOnly, #AddressOnly.phantom!enumelt
8084
// CHECK-NEXT: store %0 to [trivial] [[PAYLOAD]]
8185
// CHECK-NEXT: inject_enum_addr [[PHANTOM]] : $*AddressOnly, #AddressOnly.phantom!enumelt
86+
// CHECK-NEXT: ignored_use
8287
// CHECK-NEXT: destroy_addr [[PHANTOM]]
8388
// CHECK-NEXT: dealloc_stack [[PHANTOM]]
8489

@@ -97,6 +102,7 @@ func PolyOptionable_cases<T>(_ t: T) {
97102
// CHECK: [[METATYPE:%.*]] = metatype $@thin PolyOptionable<T>.Type
98103
// CHECK-NEXT: [[NOUGHT:%.*]] = alloc_stack $PolyOptionable<T>
99104
// CHECK-NEXT: inject_enum_addr [[NOUGHT]]
105+
// CHECK-NEXT: ignored_use
100106
// CHECK-NEXT: destroy_addr [[NOUGHT]]
101107
// CHECK-NEXT: dealloc_stack [[NOUGHT]]
102108
_ = PolyOptionable<T>.nought
@@ -106,6 +112,7 @@ func PolyOptionable_cases<T>(_ t: T) {
106112
// CHECK-NEXT: [[PAYLOAD:%.*]] = init_enum_data_addr [[MERE]]
107113
// CHECK-NEXT: copy_addr %0 to [init] [[PAYLOAD]] : $*T
108114
// CHECK-NEXT: inject_enum_addr [[MERE]]
115+
// CHECK-NEXT: ignored_use
109116
// CHECK-NEXT: destroy_addr [[MERE]]
110117
// CHECK-NEXT: dealloc_stack [[MERE]]
111118
_ = PolyOptionable<T>.mere(t)
@@ -122,6 +129,7 @@ func PolyOptionable_specialized_cases(_ t: Int) {
122129

123130
// CHECK: [[METATYPE:%.*]] = metatype $@thin PolyOptionable<Int>.Type
124131
// CHECK-NEXT: [[NOUGHT:%.*]] = enum $PolyOptionable<Int>, #PolyOptionable.nought!enumelt
132+
// CHECK-NEXT: ignored_use
125133
_ = PolyOptionable<Int>.nought
126134

127135
// CHECK-NEXT: [[METATYPE:%.*]] = metatype $@thin PolyOptionable<Int>.Type

0 commit comments

Comments
 (0)