Skip to content

Commit bb4d406

Browse files
author
ematejska
authored
Merge pull request #6914 from jckarter/iuo-bitcast-3.1
[3.1] SILGen: Avoid useless bitcasts when IUO-to-Optional conversion happens.
2 parents bd97f38 + 98b7dd8 commit bb4d406

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)