Skip to content

Commit 3e12ecc

Browse files
committed
SIL: Fix miscompiles with @effects(readonly) functions that have indirect results
When resilience is enabled, some functions in the standard library that are marked @effects(readonly) now have indirect results. The SILCombiner pass doesn't handle @effects(readonly) with @out results correctly, so just disable the optimizations temporarily to avoid a mis-compile when resilience is enabled. The LLVM readonly attribute can never be applied to such functions, so don't set it either. Should not have an effect when resilience is disabled.
1 parent 4b304f7 commit 3e12ecc

File tree

4 files changed

+41
-24
lines changed

4 files changed

+41
-24
lines changed

include/swift/SIL/SILFunction.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -293,14 +293,19 @@ class SILFunction
293293

294294
/// Returns true if the function has parameters that are consumed by the
295295
// callee.
296-
bool hasOwnedParameters() {
296+
bool hasOwnedParameters() const {
297297
for (auto &ParamInfo : getLoweredFunctionType()->getParameters()) {
298298
if (ParamInfo.isConsumed())
299299
return true;
300300
}
301301
return false;
302302
}
303303

304+
// Returns true if the function has indirect out parameters.
305+
bool hasIndirectResults() const {
306+
return getLoweredFunctionType()->getNumIndirectResults() > 0;
307+
}
308+
304309
/// Returns true if this function either has a self metadata argument or
305310
/// object that Self metadata may be derived from.
306311
bool hasSelfMetadataParam() const;

lib/IRGen/GenDecl.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1652,7 +1652,7 @@ static bool isReadOnlyFunction(SILFunction *f) {
16521652
// Check if the function has any 'owned' parameters. Owned parameters may
16531653
// call the destructor of the object which could violate the readonly-ness
16541654
// of the function.
1655-
if (f->hasOwnedParameters())
1655+
if (f->hasOwnedParameters() || f->hasIndirectResults())
16561656
return false;
16571657

16581658
auto Eff = f->getEffectsKind();

lib/SILOptimizer/SILCombiner/SILCombinerApplyVisitors.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -482,6 +482,11 @@ SILCombiner::optimizeApplyOfConvertFunctionInst(FullApplySite AI,
482482

483483
bool
484484
SILCombiner::recursivelyCollectARCUsers(UserListTy &Uses, ValueBase *Value) {
485+
// FIXME: We could probably optimize this case too
486+
if (auto *AI = dyn_cast<ApplyInst>(Value))
487+
if (AI->hasIndirectResults())
488+
return false;
489+
485490
for (auto *Use : Value->getUses()) {
486491
SILInstruction *Inst = Use->getUser();
487492
if (isa<RefCountingInst>(Inst) ||

test/IRGen/readonly.sil

Lines changed: 29 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -7,38 +7,45 @@ import SwiftShims
77

88
private class XXX{}
99

10-
// This is the swift content of this file:
11-
//@effects(readonly) public func foo(x : Int) { }
12-
//@effects(readonly) public func bar(x : XXX) { }
10+
sil @XXX_dtor : $@convention(method) (@owned XXX) -> ()
11+
sil @XXX_ctor : $@convention(method) (@owned XXX) -> @owned XXX
1312

14-
sil @_TFC8readonly3XXXD : $@convention(method) (@owned XXX) -> ()
15-
sil @_TFC8readonly3XXXd : $@convention(method) (@guaranteed XXX) -> @owned Builtin.NativeObject
16-
sil @_TFC8readonly3XXXcfMS0_FT_S0_ : $@convention(method) (@owned XXX) -> @owned XXX
17-
sil @_TFC8readonly3XXXCfMS0_FT_S0_ : $@convention(thin) (@thick XXX.Type) -> @owned XXX
13+
// CHECK: target datalayout
1814

19-
//CHECK: target datalayout
15+
// No @owned or @out parameters -- function is read only at LLVM level
2016

21-
//CHECK: ; Function Attrs: readonly
22-
//CHECK-NEXT: define{{( protected)?}} void @function_foo(
17+
// CHECK: ; Function Attrs: readonly
18+
// CHECK-NEXT: define{{( protected)?}} void @function_foo(
2319
sil [readonly] @function_foo : $@convention(thin) (Int) -> () {
2420
bb0(%0 : $Int):
25-
%1 = tuple () // user: %2
26-
return %1 : $() // id: %2
21+
%1 = tuple ()
22+
return %1 : $()
2723
}
2824

29-
//CHECK-NOT: ; Function Attrs: readonly
30-
//CHECK: define{{( protected)?}} void @function_bar(
25+
// There's an @owned parameter, and destructors can call arbitrary code
26+
// -- function is not read only at LLVM level
27+
28+
// CHECK-NOT: ; Function Attrs: readonly
29+
// CHECK: define{{( protected)?}} void @function_bar(
3130
sil [readonly] @function_bar : $@convention(thin) (@owned XXX) -> () {
3231
bb0(%0 : $XXX):
33-
strong_release %0 : $XXX // id: %2
34-
%3 = tuple () // user: %4
35-
return %3 : $() // id: %4
36-
}
37-
38-
sil_vtable XXX {
39-
#XXX.deinit!deallocator: _TFC8readonly3XXXD // readonly.XXX.__deallocating_deinit
40-
#XXX.init!initializer.1: _TFC8readonly3XXXcfMS0_FT_S0_ // readonly.XXX.init (readonly.XXX.Type)() -> readonly.XXX
32+
strong_release %0 : $XXX
33+
%1 = tuple ()
34+
return %1 : $()
4135
}
4236

37+
// There's an @out parameter -- function is not read only at LLVM level
4338

39+
// CHECK-NOT: ; Function Attrs: readonly
40+
// CHECK: define{{( protected)?}} void @function_baz(
41+
sil [readonly] @function_baz : $@convention(thin) () -> (@out Any) {
42+
bb0(%0 : $*Any):
43+
init_existential_addr %0 : $*Any, $()
44+
%1 = tuple ()
45+
return %1 : $()
46+
}
4447

48+
sil_vtable XXX {
49+
#XXX.deinit!deallocator: XXX_dtor
50+
#XXX.init!initializer.1: XXX_ctor
51+
}

0 commit comments

Comments
 (0)