Skip to content

Commit a035a39

Browse files
committed
[region-isolation] Make load/load_borrow look through instructions.
This ensures that when we process, we consider load/load_borrow's result to be equivalent to its operand. This ensures that a load/load_borrow cannot act as a use of its operand preventing spurious diagnostics. (cherry picked from commit eed51e7)
1 parent 0a0ae14 commit a035a39

File tree

4 files changed

+97
-8
lines changed

4 files changed

+97
-8
lines changed

lib/SILOptimizer/Analysis/RegionAnalysis.cpp

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -371,14 +371,23 @@ static SILValue getUnderlyingTrackedObjectValue(SILValue value) {
371371

372372
static UnderlyingTrackedValueInfo getUnderlyingTrackedValue(SILValue value) {
373373
if (!value->getType().isAddress()) {
374-
return UnderlyingTrackedValueInfo(getUnderlyingTrackedObjectValue(value));
374+
SILValue underlyingValue = getUnderlyingTrackedObjectValue(value);
375+
376+
if (!isa<LoadInst, LoadBorrowInst>(underlyingValue)) {
377+
return UnderlyingTrackedValueInfo(underlyingValue);
378+
}
379+
380+
// If we got an address, lets see if we can do even better by looking at the
381+
// address.
382+
value = cast<SingleValueInstruction>(underlyingValue)->getOperand(0);
375383
}
384+
assert(value->getType().isAddress());
376385

377386
UseDefChainVisitor visitor;
378387
SILValue base = visitor.visitAll(value);
379388
assert(base);
380389
if (base->getType().isObject())
381-
return {getUnderlyingObject(base), visitor.actorIsolation};
390+
return {getUnderlyingTrackedValue(base).value, visitor.actorIsolation};
382391
return {base, visitor.actorIsolation};
383392
}
384393

@@ -2393,8 +2402,6 @@ CONSTANT_TRANSLATION(ObjCExistentialMetatypeToObjectInst, AssignFresh)
23932402
// example, a cast would be inappropriate here. This is implemented by
23942403
// propagating the operand's region into the result's region and by
23952404
// requiring all operands.
2396-
CONSTANT_TRANSLATION(LoadInst, Assign)
2397-
CONSTANT_TRANSLATION(LoadBorrowInst, Assign)
23982405
CONSTANT_TRANSLATION(LoadWeakInst, Assign)
23992406
CONSTANT_TRANSLATION(StrongCopyUnownedValueInst, Assign)
24002407
CONSTANT_TRANSLATION(ClassMethodInst, Assign)
@@ -2736,6 +2743,23 @@ PartitionOpTranslator::visitBeginBorrowInst(BeginBorrowInst *bbi) {
27362743
return TranslationSemantics::LookThrough;
27372744
}
27382745

2746+
/// LoadInst is technically a statically look through instruction, but we want
2747+
/// to handle it especially in the infrastructure, so we cannot mark it as
2748+
/// such. This makes marking it as a normal lookthrough instruction impossible
2749+
/// since the routine checks that invariant.
2750+
TranslationSemantics PartitionOpTranslator::visitLoadInst(LoadInst *limvi) {
2751+
return TranslationSemantics::Special;
2752+
}
2753+
2754+
/// LoadBorrowInst is technically a statically look through instruction, but we
2755+
/// want to handle it especially in the infrastructure, so we cannot mark it as
2756+
/// such. This makes marking it as a normal lookthrough instruction impossible
2757+
/// since the routine checks that invariant.
2758+
TranslationSemantics
2759+
PartitionOpTranslator::visitLoadBorrowInst(LoadBorrowInst *lbi) {
2760+
return TranslationSemantics::Special;
2761+
}
2762+
27392763
TranslationSemantics PartitionOpTranslator::visitReturnInst(ReturnInst *ri) {
27402764
if (ri->getFunction()->getLoweredFunctionType()->hasTransferringResult()) {
27412765
return TranslationSemantics::TransferringNoResult;

test/ClangImporter/transferring.swift

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,12 +27,14 @@ func funcTestTransferringResult() async {
2727
// Just to show that without the transferring param, we generate diagnostics.
2828
let x2 = NonSendableCStruct()
2929
let y2 = returnUserDefinedFromGlobalFunction(x2)
30-
await transferToMain(x2) // expected-error {{transferring value of non-Sendable type 'NonSendableCStruct' from nonisolated context to main actor-isolated context}}
30+
await transferToMain(x2) // expected-error {{transferring 'x2' may cause a data race}}
31+
// expected-note @-1 {{transferring disconnected 'x2' to main actor-isolated callee could cause races in between callee main actor-isolated and local nonisolated uses}}
3132
useValue(y2) // expected-note {{use here could race}}
3233
}
3334

3435
func funcTestTransferringArg() async {
3536
let x = NonSendableCStruct()
36-
transferUserDefinedIntoGlobalFunction(x) // expected-error {{value of non-Sendable type 'NonSendableCStruct' accessed after being transferred; later accesses could race}}
37+
transferUserDefinedIntoGlobalFunction(x) // expected-error {{transferring 'x' may cause a data race}}
38+
// expected-note @-1 {{'x' used after being passed as a transferring parameter}}
3739
useValue(x) // expected-note {{use here could race}}
3840
}

test/Concurrency/transfernonsendable_instruction_matching.sil

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ class NonSendableKlass {}
2424
sil @transferNonSendableKlass : $@convention(thin) @async (@guaranteed NonSendableKlass) -> ()
2525
sil @useNonSendableKlass : $@convention(thin) (@guaranteed NonSendableKlass) -> ()
2626
sil @constructNonSendableKlass : $@convention(thin) () -> @owned NonSendableKlass
27+
sil @constructNonSendableKlassIndirect : $@convention(thin) () -> @out NonSendableKlass
2728
sil @useUnmanagedNonSendableKlass : $@convention(thin) (@guaranteed @sil_unmanaged NonSendableKlass) -> ()
2829

2930
final class SendableKlass : Sendable {}
@@ -1678,6 +1679,47 @@ bb0(%arg : $Builtin.Word):
16781679
return %9999 : $()
16791680
}
16801681

1682+
sil [ossa] @load_is_lookthrough_test : $@convention(thin) @async () -> () {
1683+
bb0:
1684+
%0 = alloc_stack $NonSendableKlass
1685+
%indirectConstruct = function_ref @constructNonSendableKlassIndirect : $@convention(thin) () -> @out NonSendableKlass
1686+
apply %indirectConstruct(%0) : $@convention(thin) () -> @out NonSendableKlass
1687+
1688+
%1 = load_borrow %0 : $*NonSendableKlass
1689+
%transferNonSendableKlass = function_ref @transferNonSendableKlass : $@convention(thin) @async (@guaranteed NonSendableKlass) -> ()
1690+
apply [caller_isolation=nonisolated] [callee_isolation=global_actor] %transferNonSendableKlass(%1) : $@convention(thin) @async (@guaranteed NonSendableKlass) -> ()
1691+
end_borrow %1 : $NonSendableKlass
1692+
1693+
%2 = load [copy] %0 : $*NonSendableKlass
1694+
destroy_value %2 : $NonSendableKlass
1695+
%3 = load [take] %0 : $*NonSendableKlass
1696+
destroy_value %3 : $NonSendableKlass
1697+
dealloc_stack %0 : $*NonSendableKlass
1698+
1699+
%9999 = tuple ()
1700+
return %9999 : $()
1701+
}
1702+
1703+
sil [ossa] @loadborrow_is_lookthrough_test : $@convention(thin) @async () -> () {
1704+
bb0:
1705+
%0 = alloc_stack $NonSendableKlass
1706+
%indirectConstruct = function_ref @constructNonSendableKlassIndirect : $@convention(thin) () -> @out NonSendableKlass
1707+
apply %indirectConstruct(%0) : $@convention(thin) () -> @out NonSendableKlass
1708+
1709+
%1 = load_borrow %0 : $*NonSendableKlass
1710+
%transferNonSendableKlass = function_ref @transferNonSendableKlass : $@convention(thin) @async (@guaranteed NonSendableKlass) -> ()
1711+
apply [caller_isolation=nonisolated] [callee_isolation=global_actor] %transferNonSendableKlass(%1) : $@convention(thin) @async (@guaranteed NonSendableKlass) -> ()
1712+
end_borrow %1 : $NonSendableKlass
1713+
1714+
%2 = load_borrow %0 : $*NonSendableKlass
1715+
end_borrow %2 : $NonSendableKlass
1716+
destroy_addr %0 : $*NonSendableKlass
1717+
dealloc_stack %0 : $*NonSendableKlass
1718+
1719+
%9999 = tuple ()
1720+
return %9999 : $()
1721+
}
1722+
16811723
sil hidden [ossa] @test_unconditional_checked_cast : $@convention(method) (@guaranteed ChildClass) -> @owned ChildClass {
16821724
bb0(%0 : @guaranteed $ChildClass):
16831725
debug_value %0 : $ChildClass, let, name "self", argno 1

test/Concurrency/transfernonsendable_strong_transferring_params.swift

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -185,14 +185,35 @@ func canTransferAssigningIntoLocal(_ x: transferring Klass) async {
185185
}
186186

187187
func canTransferAssigningIntoLocal2(_ x: transferring Klass) async {
188+
let _ = x
189+
await transferToMain(x)
190+
// We do not error here since we just load the value and do not do anything
191+
// with it.
192+
//
193+
// TODO: We should change let _ = x so that it has a move_value '_' or
194+
// something like that. It will also help move checking as well.
195+
let _ = x
196+
}
188197

198+
func canTransferAssigningIntoLocal2a(_ x: transferring Klass) async {
199+
let _ = x
200+
await transferToMain(x)
201+
// We do not error here since we just load the value and do not do anything
202+
// with it.
203+
//
204+
// TODO: We should change let _ = x so that it has a move_value '_' or
205+
// something like that. It will also help move checking as well.
206+
_ = x
207+
}
208+
209+
func canTransferAssigningIntoLocal3(_ x: transferring Klass) async {
189210
let _ = x
190211
await transferToMain(x) // expected-warning {{transferring 'x' may cause a data race}}
191212
// expected-note @-1 {{transferring disconnected 'x' to main actor-isolated callee could cause races in between callee main actor-isolated and local nonisolated uses}}
192-
let _ = x // expected-note {{use here could race}}
213+
let y = x // expected-note {{use here could race}}
214+
_ = y
193215
}
194216

195-
196217
//////////////////////////////////////
197218
// MARK: Transferring is "var" like //
198219
//////////////////////////////////////

0 commit comments

Comments
 (0)