Skip to content

Commit d060f01

Browse files
authored
Merge pull request #78837 from gottesmm/rdar-142661388
[rbi] Change Region Based Isolation for closures to not use the AST and instead just use SIL.
2 parents 0558d3f + 05511c9 commit d060f01

File tree

59 files changed

+710
-220
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

59 files changed

+710
-220
lines changed

SwiftCompilerSources/Sources/SIL/Instruction.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1736,3 +1736,6 @@ final public class ThunkInst : Instruction {
17361736

17371737
final public class MergeIsolationRegionInst : Instruction {
17381738
}
1739+
1740+
final public class IgnoredUseInst : Instruction, UnaryInstruction {
1741+
}

SwiftCompilerSources/Sources/SIL/Registration.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -258,4 +258,5 @@ public func registerSILClasses() {
258258
register(CheckedCastAddrBranchInst.self)
259259
register(ThunkInst.self)
260260
register(MergeIsolationRegionInst.self)
261+
register(IgnoredUseInst.self)
261262
}

docs/SIL/Instructions.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5551,3 +5551,21 @@ sil-instruction ::= 'has_symbol' sil-decl-ref
55515551
Returns true if each of the underlying symbol addresses associated with
55525552
the given declaration are non-null. This can be used to determine
55535553
whether a weakly-imported declaration is available at runtime.
5554+
5555+
## Miscellaneous instructions
5556+
5557+
### ignored_use
5558+
5559+
```none
5560+
sil-instruction ::= 'ignored_use'
5561+
```
5562+
5563+
This instruction acts as a synthetic use instruction that suppresses unused
5564+
variable warnings. In Swift the equivalent operation is '_ = x'. This
5565+
importantly also provides a way to find the source location for '_ = x' when
5566+
emitting SIL diagnostics. It is only legal in Raw SIL and is removed as dead
5567+
code when we convert to Canonical SIL.
5568+
5569+
DISCUSSION: Before the introduction of this instruction, in certain cases,
5570+
SILGen would just not emit anything for '_ = x'... so one could not emit
5571+
diagnostics upon this case.

include/swift/AST/DiagnosticsSIL.def

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1056,6 +1056,12 @@ NOTE(regionbasedisolation_typed_tns_passed_to_sending_closure_helper_have_value_
10561056
NOTE(regionbasedisolation_typed_tns_passed_to_sending_closure_helper_multiple_value, none,
10571057
"closure captures non-Sendable %0",
10581058
(DeclName))
1059+
NOTE(regionbasedisolation_closure_captures, none,
1060+
"closure captures %0",
1061+
(DeclName))
1062+
NOTE(regionbasedisolation_closure_captures_actor, none,
1063+
"closure captures %0 allowing access to %1 state within the closure",
1064+
(DeclName, StringRef))
10591065

10601066
NOTE(regionbasedisolation_typed_tns_passed_to_sending_callee, none,
10611067
"Passing %0 value of non-Sendable type %1 as a 'sending' parameter to %2 %3 risks causing races inbetween %0 uses and uses reachable from %3",

include/swift/SIL/InstructionUtils.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,11 @@ bool isEndOfScopeMarker(SILInstruction *user);
129129
/// only used in recognizable patterns without otherwise "escaping".
130130
bool isIncidentalUse(SILInstruction *user);
131131

132+
/// Returns true if this is a move only wrapper use.
133+
///
134+
/// E.x.: moveonlywrapper_to_copyable_addr, copyable_to_moveonlywrapper_value
135+
bool isMoveOnlyWrapperUse(SILInstruction *user);
136+
132137
/// Return true if the given `user` instruction modifies the value's refcount
133138
/// without propagating the value or having any other effect aside from
134139
/// potentially destroying the value itself (and executing associated cleanups).

include/swift/SIL/SILBuilder.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3089,6 +3089,15 @@ class SILBuilder {
30893089
getModule(), getSILDebugLocation(Loc), Decl));
30903090
}
30913091

3092+
//===--------------------------------------------------------------------===//
3093+
// Misc Uses
3094+
//===--------------------------------------------------------------------===//
3095+
3096+
IgnoredUseInst *createIgnoredUse(SILLocation loc, SILValue value) {
3097+
return insert(new (getModule())
3098+
IgnoredUseInst(getSILDebugLocation(loc), value));
3099+
}
3100+
30923101
//===--------------------------------------------------------------------===//
30933102
// Private Helper Methods
30943103
//===--------------------------------------------------------------------===//

include/swift/SIL/SILCloner.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3796,6 +3796,14 @@ void SILCloner<ImplClass>::visitHasSymbolInst(HasSymbolInst *Inst) {
37963796
Inst->getDecl()));
37973797
}
37983798

3799+
template <typename ImplClass>
3800+
void SILCloner<ImplClass>::visitIgnoredUseInst(IgnoredUseInst *Inst) {
3801+
getBuilder().setCurrentDebugScope(getOpScope(Inst->getDebugScope()));
3802+
recordClonedInstruction(
3803+
Inst, getBuilder().createIgnoredUse(getOpLocation(Inst->getLoc()),
3804+
getOpValue(Inst->getOperand())));
3805+
}
3806+
37993807
} // end namespace swift
38003808

38013809
#endif

include/swift/SIL/SILInstruction.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11725,6 +11725,17 @@ class MergeIsolationRegionInst final
1172511725
}
1172611726
};
1172711727

11728+
/// An instruction that represents a semantic-less use that is used to
11729+
/// suppresses unused value variable warnings. E.x.: _ = x.
11730+
class IgnoredUseInst final
11731+
: public UnaryInstructionBase<SILInstructionKind::IgnoredUseInst,
11732+
NonValueInstruction> {
11733+
friend SILBuilder;
11734+
11735+
IgnoredUseInst(SILDebugLocation loc, SILValue operand)
11736+
: UnaryInstructionBase(loc, operand) {}
11737+
};
11738+
1172811739
inline SILType *AllocRefInstBase::getTypeStorage() {
1172911740
// If the size of the subclasses are equal, then all of this compiles away.
1173011741
if (auto I = dyn_cast<AllocRefInst>(this))

include/swift/SIL/SILNodes.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -897,6 +897,9 @@ NON_VALUE_INST(MarkUnresolvedMoveAddrInst, mark_unresolved_move_addr,
897897
NON_VALUE_INST(MergeIsolationRegionInst, merge_isolation_region,
898898
SILInstruction, None, DoesNotRelease)
899899

900+
NON_VALUE_INST(IgnoredUseInst, ignored_use,
901+
SILInstruction, None, DoesNotRelease)
902+
900903
NON_VALUE_INST(IncrementProfilerCounterInst, increment_profiler_counter,
901904
SILInstruction, MayReadWrite, DoesNotRelease)
902905

include/swift/SILOptimizer/Utils/PartitionUtils.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1374,6 +1374,12 @@ struct PartitionOpEvaluator {
13741374
Region sentRegion = p.getRegion(sentElement);
13751375
bool isClosureCapturedElt = false;
13761376
SILDynamicMergedIsolationInfo sentRegionIsolation;
1377+
1378+
// TODO: Today we only return the first element in our region that has
1379+
// some form of isolation. This causes us to in the case of sending
1380+
// partial_applies to only emit a diagnostic for the first element in the
1381+
// capture list of the partial_apply. If we returned a list of potential
1382+
// errors... we could emit the error for each capture individually.
13771383
auto pairOpt = getIsolationRegionInfo(sentRegion, op.getSourceOp());
13781384
if (!pairOpt) {
13791385
return handleError(UnknownCodePatternError(op));

lib/IRGen/IRGenSIL.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1273,6 +1273,9 @@ class IRGenSILFunction :
12731273
visitMoveOnlyWrapperToCopyableBoxInst(MoveOnlyWrapperToCopyableBoxInst *i) {
12741274
llvm_unreachable("OSSA instruction");
12751275
}
1276+
1277+
void visitIgnoredUseInst(IgnoredUseInst *i) {}
1278+
12761279
void
12771280
visitMoveOnlyWrapperToCopyableAddrInst(MoveOnlyWrapperToCopyableAddrInst *i) {
12781281
auto e = getLoweredExplosion(i->getOperand());

lib/SIL/IR/OperandOwnership.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,7 @@ OPERAND_OWNERSHIP(TrivialUse, GlobalAddr)
214214
// The dealloc_stack_ref operand needs to have NonUse ownership because
215215
// this use comes after the last consuming use (which is usually a dealloc_ref).
216216
OPERAND_OWNERSHIP(NonUse, DeallocStackRef)
217+
OPERAND_OWNERSHIP(InstantaneousUse, IgnoredUse)
217218

218219
// Use an owned or guaranteed value only for the duration of the operation.
219220
OPERAND_OWNERSHIP(InstantaneousUse, ExistentialMetatype)

lib/SIL/IR/SILPrinter.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2873,6 +2873,10 @@ class SILPrinter : public SILInstructionVisitor<SILPrinter> {
28732873
*this << GI->getFormalResumeType();
28742874
}
28752875

2876+
void visitIgnoredUseInst(IgnoredUseInst *i) {
2877+
*this << getIDAndType(i->getOperand());
2878+
}
2879+
28762880
void visitGetAsyncContinuationAddrInst(GetAsyncContinuationAddrInst *GI) {
28772881
if (GI->throws())
28782882
*this << "[throws] ";

lib/SIL/Parser/ParseSIL.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5077,6 +5077,11 @@ bool SILParser::parseSpecificSILInstruction(SILBuilder &B,
50775077
}
50785078
break;
50795079
}
5080+
case SILInstructionKind::IgnoredUseInst:
5081+
if (parseTypedValueRef(Val, B) || parseSILDebugLocation(InstLoc, B))
5082+
return true;
5083+
ResultVal = B.createIgnoredUse(InstLoc, Val);
5084+
break;
50805085

50815086
case SILInstructionKind::DeallocStackInst:
50825087
if (parseTypedValueRef(Val, B) || parseSILDebugLocation(InstLoc, B))

lib/SIL/Utils/InstructionUtils.cpp

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -335,7 +335,21 @@ bool swift::isEndOfScopeMarker(SILInstruction *user) {
335335

336336
bool swift::isIncidentalUse(SILInstruction *user) {
337337
return isEndOfScopeMarker(user) || user->isDebugInstruction() ||
338-
isa<FixLifetimeInst>(user) || isa<EndLifetimeInst>(user);
338+
isa<FixLifetimeInst>(user) || isa<EndLifetimeInst>(user) ||
339+
isa<IgnoredUseInst>(user);
340+
}
341+
342+
bool swift::isMoveOnlyWrapperUse(SILInstruction *user) {
343+
switch (user->getKind()) {
344+
case SILInstructionKind::MoveOnlyWrapperToCopyableValueInst:
345+
case SILInstructionKind::MoveOnlyWrapperToCopyableBoxInst:
346+
case SILInstructionKind::MoveOnlyWrapperToCopyableAddrInst:
347+
case SILInstructionKind::CopyableToMoveOnlyWrapperValueInst:
348+
case SILInstructionKind::CopyableToMoveOnlyWrapperAddrInst:
349+
return true;
350+
default:
351+
return false;
352+
}
339353
}
340354

341355
bool swift::onlyAffectsRefCount(SILInstruction *user) {
@@ -623,6 +637,7 @@ RuntimeEffect swift::getRuntimeEffect(SILInstruction *inst, SILType &impactType)
623637
case SILInstructionKind::DebugStepInst:
624638
case SILInstructionKind::FunctionExtractIsolationInst:
625639
case SILInstructionKind::TypeValueInst:
640+
case SILInstructionKind::IgnoredUseInst:
626641
return RuntimeEffect::NoEffect;
627642

628643
case SILInstructionKind::OpenExistentialMetatypeInst:

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/Analysis/RegionAnalysis.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3103,6 +3103,7 @@ CONSTANT_TRANSLATION(DebugStepInst, Ignored)
31033103
CONSTANT_TRANSLATION(IncrementProfilerCounterInst, Ignored)
31043104
CONSTANT_TRANSLATION(SpecifyTestInst, Ignored)
31053105
CONSTANT_TRANSLATION(TypeValueInst, Ignored)
3106+
CONSTANT_TRANSLATION(IgnoredUseInst, Ignored)
31063107

31073108
//===---
31083109
// Require

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

0 commit comments

Comments
 (0)