Skip to content

Commit 98b7dd8

Browse files
committed
SILGen: Avoid useless bitcasts when IUO-to-Optional conversion happens.
In SIL, the distinction between IUO and Optional is now lowered away, so there's no reason to emit any SIL at all when an IUO is converted to Optional formally in the AST. (Eventually this distinction ought to go away at the type system level too…) Memory promotion didn't understand initializations through unchecked_*_casts and would incorrectly flag them as improper captures, causing rdar://problem/26899492.
1 parent bd97f38 commit 98b7dd8

File tree

5 files changed

+57
-47
lines changed

5 files changed

+57
-47
lines changed

lib/SILGen/SILGenExpr.cpp

Lines changed: 2 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2977,8 +2977,6 @@ static bool emitOptimizedOptionalEvaluation(OptionalEvaluationExpr *E,
29772977
->getSemanticsProvidingExpr());
29782978
if (!BO || BO->getDepth() != 0) return false;
29792979

2980-
auto &optTL = SGF.getTypeLowering(E->getType());
2981-
29822980
// If the subexpression type is exactly the same, then just peephole the
29832981
// whole thing away.
29842982
if (BO->getSubExpr()->getType()->isEqual(E->getType())) {
@@ -2997,17 +2995,7 @@ static bool emitOptimizedOptionalEvaluation(OptionalEvaluationExpr *E,
29972995
// address only or because we have a contextual memory location to
29982996
// initialize).
29992997
if (optInit == nullptr) {
3000-
auto subMV = SGF.emitRValueAsSingleValue(BO->getSubExpr());
3001-
SILValue result;
3002-
if (optTL.isTrivial())
3003-
result = SGF.B.createUncheckedTrivialBitCast(E, subMV.forward(SGF),
3004-
optTL.getLoweredType());
3005-
else
3006-
// The optional object type is the same, so we assume the optional types
3007-
// are layout identical, allowing the use of unchecked bit casts.
3008-
result = SGF.B.createUncheckedBitCast(E, subMV.forward(SGF),
3009-
optTL.getLoweredType());
3010-
LoadableResult = result;
2998+
LoadableResult = SGF.emitRValueAsSingleValue(BO->getSubExpr()).forward(SGF);
30112999
return true;
30123000
}
30133001

@@ -3017,11 +3005,7 @@ static bool emitOptimizedOptionalEvaluation(OptionalEvaluationExpr *E,
30173005
SILValue optAddr = getAddressForInPlaceInitialization(optInit);
30183006
assert(optAddr && "Caller should have provided a buffer");
30193007

3020-
auto &subTL = SGF.getTypeLowering(BO->getSubExpr()->getType());
3021-
SILValue subAddr = SGF.B.createUncheckedAddrCast(E, optAddr,
3022-
subTL.getLoweredType().getAddressType());
3023-
3024-
KnownAddressInitialization subInit(subAddr);
3008+
KnownAddressInitialization subInit(optAddr);
30253009
SGF.emitExprInto(BO->getSubExpr(), &subInit);
30263010
optInit->finishInitialization(SGF);
30273011
return true;

test/SILGen/lying_about_optional_return_objc.swift

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -53,34 +53,35 @@ func optionalChainingForeignFunctionTypeProperties(b: BlockProperty?) {
5353

5454
// CHECK: enum $Optional<()>, #Optional.some!enumelt.1, {{%.*}} : $()
5555
_ = dynamic?.voidReturning()
56-
// CHECK: unchecked_trivial_bit_cast
56+
// CHECK: unchecked_trivial_bit_cast {{.*}} $UnsafeMutableRawPointer to $Optional
5757
_ = dynamic?.voidPointerReturning()
58-
// CHECK: unchecked_trivial_bit_cast
58+
// CHECK: unchecked_trivial_bit_cast {{.*}} $OpaquePointer to $Optional
5959
_ = dynamic?.opaquePointerReturning()
60-
// CHECK: unchecked_trivial_bit_cast
60+
// CHECK: unchecked_trivial_bit_cast {{.*}} $UnsafeMutablePointer{{.*}} to $Optional
6161
_ = dynamic?.pointerReturning()
62-
// CHECK: unchecked_trivial_bit_cast
62+
// CHECK: unchecked_trivial_bit_cast {{.*}} $UnsafePointer{{.*}} to $Optional
6363
_ = dynamic?.constPointerReturning()
64-
// CHECK: unchecked_trivial_bit_cast
64+
// CHECK: unchecked_trivial_bit_cast {{.*}} $Selector to $Optional
6565
_ = dynamic?.selectorReturning()
66-
// CHECK: unchecked_ref_cast
66+
// CHECK: unchecked_ref_cast {{.*}} $BlockProperty to $Optional
6767
_ = dynamic?.objectReturning()
68-
// CHECK: unchecked_trivial_bit_cast
68+
// FIXME: Doesn't opaquely cast the selector result!
69+
// C/HECK: unchecked_trivial_bit_cast {{.*}} $Selector to $Optional
6970
_ = dynamic?.selector
7071

71-
// CHECK: unchecked_bitwise_cast {{%.*}} : $Optional<{{.*}} -> {{.*}}> to $Optional<{{.*}} -> {{.*}}>
72+
// CHECK: inject_enum_addr {{%.*}} : $*Optional<{{.*}} -> ()>, #Optional.some
7273
_ = dynamic?.voidReturning
73-
// CHECK: unchecked_bitwise_cast {{%.*}} : $Optional<{{.*}} -> {{.*}}> to $Optional<{{.*}} -> {{.*}}>
74+
// CHECK: inject_enum_addr {{%.*}} : $*Optional<{{.*}} -> UnsafeMutableRawPointer>, #Optional.some
7475
_ = dynamic?.voidPointerReturning
75-
// CHECK: unchecked_bitwise_cast {{%.*}} : $Optional<{{.*}} -> {{.*}}> to $Optional<{{.*}} -> {{.*}}>
76+
// CHECK: inject_enum_addr {{%.*}} : $*Optional<{{.*}} -> OpaquePointer>, #Optional.some
7677
_ = dynamic?.opaquePointerReturning
77-
// CHECK: unchecked_bitwise_cast {{%.*}} : $Optional<{{.*}} -> {{.*}}> to $Optional<{{.*}} -> {{.*}}>
78+
// CHECK: inject_enum_addr {{%.*}} : $*Optional<{{.*}} -> UnsafeMutablePointer{{.*}}>, #Optional.some
7879
_ = dynamic?.pointerReturning
79-
// CHECK: unchecked_bitwise_cast {{%.*}} : $Optional<{{.*}} -> {{.*}}> to $Optional<{{.*}} -> {{.*}}>
80+
// CHECK: inject_enum_addr {{%.*}} : $*Optional<{{.*}} -> UnsafePointer{{.*}}>, #Optional.some
8081
_ = dynamic?.constPointerReturning
81-
// CHECK: unchecked_bitwise_cast {{%.*}} : $Optional<{{.*}} -> {{.*}}> to $Optional<{{.*}} -> {{.*}}>
82+
// CHECK: inject_enum_addr {{%.*}} : $*Optional<{{.*}} -> Selector>, #Optional.some
8283
_ = dynamic?.selectorReturning
83-
// CHECK: unchecked_bitwise_cast {{%.*}} : $Optional<{{.*}} -> {{.*}}> to $Optional<{{.*}} -> {{.*}}>
84+
// CHECK: inject_enum_addr {{%.*}} : $*Optional<{{.*}} -> @owned BlockProperty>, #Optional.some
8485
_ = dynamic?.objectReturning
8586

8687
// CHECK: enum $Optional<()>, #Optional.some!enumelt.1, {{%.*}} : $()

test/SILGen/objc_extensions.swift

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,6 @@ extension Sub {
6363

6464
// CHECK: bb3([[OLD_NSSTRING_BRIDGED:%.*]] : $Optional<String>):
6565
// This next line is completely not needed. But we are emitting it now.
66-
// CHECK: [[OLD_NSSTRING_BRIDGED_CAST:%.*]] = unchecked_bitwise_cast [[OLD_NSSTRING_BRIDGED]]
6766
// CHECK: destroy_value [[SELF_COPY]]
6867
// CHECK: [[SELF_COPY:%.*]] = copy_value [[SELF]]
6968
// CHECK: [[UPCAST_SELF_COPY:%.*]] = upcast [[SELF_COPY]] : $Sub to $Base
@@ -74,11 +73,10 @@ extension Sub {
7473
// CHECK: destroy_value [[BRIDGED_NEW_STRING]]
7574
// CHECK: destroy_value [[SELF_COPY]]
7675
// CHECK: [[DIDSET_NOTIFIER:%.*]] = function_ref @_TFC15objc_extensions3SubW4propGSQSS_ : $@convention(method) (@owned Optional<String>, @guaranteed Sub) -> ()
77-
// CHECK: [[COPIED_OLD_NSSTRING_BRIDGED_CAST:%.*]] = copy_value [[OLD_NSSTRING_BRIDGED_CAST]]
76+
// CHECK: [[COPIED_OLD_NSSTRING_BRIDGED:%.*]] = copy_value [[OLD_NSSTRING_BRIDGED]]
7877
// This is an identity cast that should be eliminated by SILGen peepholes.
79-
// CHECK: [[COPIED_OLD_NSSTRING_BRIDGED_CAST2:%.*]] = unchecked_bitwise_cast [[COPIED_OLD_NSSTRING_BRIDGED_CAST]]
80-
// CHECK: apply [[DIDSET_NOTIFIER]]([[COPIED_OLD_NSSTRING_BRIDGED_CAST2]], [[SELF]])
81-
// CHECK: destroy_value [[OLD_NSSTRING_BRIDGED_CAST]]
78+
// CHECK: apply [[DIDSET_NOTIFIER]]([[COPIED_OLD_NSSTRING_BRIDGED]], [[SELF]])
79+
// CHECK: destroy_value [[OLD_NSSTRING_BRIDGED]]
8280
// CHECK: destroy_value [[NEW_VALUE]]
8381
// CHECK: } // end sil function '_TFC15objc_extensions3Subs4propGSQSS_'
8482

test/SILGen/optional-cast.swift

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -131,8 +131,7 @@ func baz(_ y : AnyObject?) {
131131
// CHECK-LABEL: sil hidden @_TF4main18opt_to_opt_trivialFGSqSi_GSQSi_
132132
// CHECK: bb0(%0 : $Optional<Int>):
133133
// CHECK-NEXT: debug_value %0 : $Optional<Int>, let, name "x"
134-
// CHECK-NEXT: %2 = unchecked_trivial_bit_cast %0 : $Optional<Int> to $Optional<Int>
135-
// CHECK-NEXT: return %2 : $Optional<Int>
134+
// CHECK-NEXT: return %0 : $Optional<Int>
136135
// CHECK-NEXT:}
137136
func opt_to_opt_trivial(_ x: Int?) -> Int! {
138137
return x
@@ -141,8 +140,7 @@ func opt_to_opt_trivial(_ x: Int?) -> Int! {
141140
// CHECK-LABEL: sil hidden @_TF4main20opt_to_opt_referenceFGSQCS_1C_GSqS0__ :
142141
// CHECK: bb0([[ARG:%.*]] : $Optional<C>):
143142
// CHECK: debug_value [[ARG]] : $Optional<C>, let, name "x"
144-
// CHECK: [[COPY_ARG:%.*]] = copy_value [[ARG]]
145-
// CHECK: [[RESULT:%.*]] = unchecked_ref_cast [[COPY_ARG]] : $Optional<C> to $Optional<C>
143+
// CHECK: [[RESULT:%.*]] = copy_value [[ARG]]
146144
// CHECK: destroy_value [[ARG]]
147145
// CHECK: return [[RESULT]] : $Optional<C>
148146
// CHECK: } // end sil function '_TF4main20opt_to_opt_referenceFGSQCS_1C_GSqS0__'
@@ -151,8 +149,7 @@ func opt_to_opt_reference(_ x : C!) -> C? { return x }
151149
// CHECK-LABEL: sil hidden @_TF4main22opt_to_opt_addressOnly
152150
// CHECK: bb0(%0 : $*Optional<T>, %1 : $*Optional<T>):
153151
// CHECK-NEXT: debug_value_addr %1 : $*Optional<T>, let, name "x"
154-
// CHECK-NEXT: %3 = unchecked_addr_cast %0 : $*Optional<T> to $*Optional<T>
155-
// CHECK-NEXT: copy_addr %1 to [initialization] %3
152+
// CHECK-NEXT: copy_addr %1 to [initialization] %0
156153
// CHECK-NEXT: destroy_addr %1
157154
func opt_to_opt_addressOnly<T>(_ x : T!) -> T? { return x }
158155

@@ -164,8 +161,7 @@ public struct TestAddressOnlyStruct<T> {
164161
// CHECK-LABEL: sil hidden @_TFV4main21TestAddressOnlyStruct8testCall
165162
// CHECK: bb0(%0 : $*Optional<T>, %1 : $TestAddressOnlyStruct<T>):
166163
// CHECK: [[TMPBUF:%.*]] = alloc_stack $Optional<T>
167-
// CHECK: [[TMPCAST:%.*]] = unchecked_addr_cast [[TMPBUF]]
168-
// CHECK-NEXT: copy_addr %0 to [initialization] [[TMPCAST]]
164+
// CHECK-NEXT: copy_addr %0 to [initialization] [[TMPBUF]]
169165
// CHECK-NEXT: apply {{.*}}<T>([[TMPBUF]], %1)
170166
func testCall(_ a : T!) {
171167
f(a)
@@ -177,8 +173,7 @@ public struct TestAddressOnlyStruct<T> {
177173
// CHECK-NEXT: debug_value %0 : $Optional<Int>, let, name "a"
178174
// CHECK-NEXT: [[X:%.*]] = alloc_box ${ var Optional<Int> }, var, name "x"
179175
// CHECK-NEXT: [[PB:%.*]] = project_box [[X]]
180-
// CHECK-NEXT: [[CAST:%.*]] = unchecked_addr_cast [[PB]] : $*Optional<Int> to $*Optional<Int>
181-
// CHECK-NEXT: store %0 to [trivial] [[CAST]] : $*Optional<Int>
176+
// CHECK-NEXT: store %0 to [trivial] [[PB]] : $*Optional<Int>
182177
// CHECK-NEXT: destroy_value [[X]] : ${ var Optional<Int> }
183178
func testContextualInitOfNonAddrOnlyType(_ a : Int?) {
184179
var x: Int! = a
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// RUN: %target-swift-frontend -emit-silgen %s | %FileCheck %s
2+
3+
protocol P {}
4+
5+
class Foo {
6+
var x: Foo!
7+
var p: P!
8+
9+
// CHECK-LABEL: {{.*3Foo.*3foo.*}}
10+
// CHECK-NOT: unchecked_{{.*}}cast {{.*}} Optional{{.*}} to Optional
11+
func foo() -> Foo? {
12+
return x
13+
}
14+
// CHECK-LABEL: {{.*3Foo.*3poo.*}}
15+
// CHECK-NOT: unchecked_{{.*}}cast {{.*}} Optional{{.*}} to Optional
16+
func poo() -> P? {
17+
return p
18+
}
19+
20+
// CHECK-LABEL: {{.*3Foo.*3bar.*}}
21+
// CHECK-NOT: unchecked_{{.*}}cast {{.*}} Optional{{.*}} to Optional
22+
func bar() -> Foo? {
23+
var x2 = x
24+
}
25+
// CHECK-LABEL: {{.*3Foo.*3par.*}}
26+
// CHECK-NOT: unchecked_{{.*}}cast {{.*}} Optional{{.*}} to Optional
27+
func par(p3: P) -> P? {
28+
var p2 = p
29+
p2! = p3
30+
p2? = p3
31+
}
32+
}

0 commit comments

Comments
 (0)