Skip to content

Commit 6f3e880

Browse files
committed
[sil-combine] Update unchecked_ref_cast_addr -> unchecked_ref_cast given loadable types for OSSA.
This involves just performing a load [take] + unchecked_ref_cast + store [init]. The test is ported from sil_combine_cast_foldings.sil
1 parent 698a0a3 commit 6f3e880

File tree

2 files changed

+197
-22
lines changed

2 files changed

+197
-22
lines changed

lib/SILOptimizer/SILCombiner/SILCombinerCastVisitors.cpp

Lines changed: 22 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -298,43 +298,43 @@ SILCombiner::visitBridgeObjectToRefInst(BridgeObjectToRefInst *BORI) {
298298
return nullptr;
299299
}
300300

301-
302-
303301
SILInstruction *
304-
SILCombiner::visitUncheckedRefCastAddrInst(UncheckedRefCastAddrInst *URCI) {
305-
if (URCI->getFunction()->hasOwnership())
306-
return nullptr;
307-
308-
SILType SrcTy = URCI->getSrc()->getType();
309-
if (!SrcTy.isLoadable(*URCI->getFunction()))
302+
SILCombiner::visitUncheckedRefCastAddrInst(UncheckedRefCastAddrInst *urci) {
303+
// Promote unchecked_ref_cast_addr in between two loadable values to
304+
// unchecked_ref_cast upon objects.
305+
//
306+
// NOTE: unchecked_ref_cast_addr is a taking operation, so we simulate that
307+
// with objects.
308+
SILType srcTy = urci->getSrc()->getType();
309+
if (!srcTy.isLoadable(*urci->getFunction()))
310310
return nullptr;
311311

312-
SILType DestTy = URCI->getDest()->getType();
313-
if (!DestTy.isLoadable(*URCI->getFunction()))
312+
SILType destTy = urci->getDest()->getType();
313+
if (!destTy.isLoadable(*urci->getFunction()))
314314
return nullptr;
315315

316316
// After promoting unchecked_ref_cast_addr to unchecked_ref_cast, the SIL
317317
// verifier will assert that the loadable source and dest type of reference
318318
// castable. If the static types are invalid, simply avoid promotion, that way
319319
// the runtime will then report a failure if this cast is ever executed.
320-
if (!SILType::canRefCast(SrcTy.getObjectType(), DestTy.getObjectType(),
321-
URCI->getModule()))
320+
if (!SILType::canRefCast(srcTy.getObjectType(), destTy.getObjectType(),
321+
urci->getModule()))
322322
return nullptr;
323323

324-
SILLocation Loc = URCI->getLoc();
325-
Builder.setCurrentDebugScope(URCI->getDebugScope());
326-
LoadInst *load = Builder.createLoad(Loc, URCI->getSrc(),
327-
LoadOwnershipQualifier::Unqualified);
324+
SILLocation loc = urci->getLoc();
325+
Builder.setCurrentDebugScope(urci->getDebugScope());
326+
SILValue load = Builder.emitLoadValueOperation(loc, urci->getSrc(),
327+
LoadOwnershipQualifier::Take);
328328

329-
assert(SILType::canRefCast(load->getType(), DestTy.getObjectType(),
329+
assert(SILType::canRefCast(load->getType(), destTy.getObjectType(),
330330
Builder.getModule()) &&
331331
"SILBuilder cannot handle reference-castable types");
332-
auto *cast = Builder.createUncheckedRefCast(Loc, load,
333-
DestTy.getObjectType());
334-
Builder.createStore(Loc, cast, URCI->getDest(),
335-
StoreOwnershipQualifier::Unqualified);
332+
auto *cast = Builder.createUncheckedRefCast(loc, load,
333+
destTy.getObjectType());
334+
Builder.emitStoreValueOperation(loc, cast, urci->getDest(),
335+
StoreOwnershipQualifier::Init);
336336

337-
return eraseInstFromFunction(*URCI);
337+
return eraseInstFromFunction(*urci);
338338
}
339339

340340
template <class CastInst>
Lines changed: 175 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,175 @@
1+
// RUN: %target-sil-opt -enable-objc-interop -enable-sil-verify-all -sil-combine %s | %FileCheck %s
2+
3+
import Swift
4+
5+
class AClass {
6+
deinit
7+
init()
8+
}
9+
10+
struct S {}
11+
12+
@objc class NSCloud {}
13+
14+
// CHECK-LABEL: sil [ossa] @dont_fold_unconditional_checked_cast_to_existentials :
15+
// CHECK: unconditional_checked_cast {{%.*}} : $NSCloud to AnyObject
16+
// CHECK: } // end sil function 'dont_fold_unconditional_checked_cast_to_existentials'
17+
sil [ossa] @dont_fold_unconditional_checked_cast_to_existentials : $@convention(thin) (@owned NSCloud) -> @owned AnyObject {
18+
entry(%arg : @owned $NSCloud):
19+
%0 = alloc_stack $NSCloud
20+
store %arg to [init] %0 : $*NSCloud
21+
%1 = load [take] %0 : $*NSCloud
22+
%2 = unconditional_checked_cast %1 : $NSCloud to AnyObject
23+
dealloc_stack %0 : $*NSCloud
24+
return %2 : $AnyObject
25+
}
26+
27+
// CHECK-LABEL: sil [ossa] @dont_fold_unconditional_checked_cast_from_existentials :
28+
// CHECK: unconditional_checked_cast %0 : $AnyObject to NSCloud
29+
// CHECK: } // end sil function 'dont_fold_unconditional_checked_cast_from_existentials'
30+
sil [ossa] @dont_fold_unconditional_checked_cast_from_existentials : $@convention(thin) (@owned AnyObject) -> @owned NSCloud {
31+
entry(%0 : @owned $AnyObject):
32+
%1 = unconditional_checked_cast %0 : $AnyObject to NSCloud
33+
return %1 : $NSCloud
34+
}
35+
36+
// We will handle this in a future commit.
37+
//
38+
// CHECK-LABEL: sil [ossa] @function_cast_nothrow_to_nothrow :
39+
// XHECK: load
40+
// XHECK: store
41+
// CHECK: } // end sil function 'function_cast_nothrow_to_nothrow'
42+
sil [ossa] @function_cast_nothrow_to_nothrow : $@convention(thin) <T> () -> () {
43+
entry:
44+
unconditional_checked_cast_addr () -> () in undef : $*(@in ()) -> @out () to () -> () in undef : $*(@in ()) -> @out ()
45+
return undef : $()
46+
}
47+
48+
// CHECK-LABEL: sil [ossa] @function_cast_nothrow_to_nothrow_substitutable :
49+
// CHECK: unconditional_checked_cast_addr
50+
// CHECK: } // end sil function 'function_cast_nothrow_to_nothrow_substitutable'
51+
sil [ossa] @function_cast_nothrow_to_nothrow_substitutable : $@convention(thin) <T> () -> () {
52+
entry:
53+
unconditional_checked_cast_addr () -> () in undef : $*(@in ()) -> @out () to (T) -> T in undef : $*(@in T) -> @out T
54+
return undef : $()
55+
}
56+
57+
// CHECK-LABEL: sil [ossa] @function_cast_nothrow_substitutable_to_nothrow :
58+
// CHECK: unconditional_checked_cast_addr
59+
// CHECK: } // end sil function 'function_cast_nothrow_substitutable_to_nothrow'
60+
sil [ossa] @function_cast_nothrow_substitutable_to_nothrow : $@convention(thin) <T> () -> () {
61+
entry:
62+
unconditional_checked_cast_addr (T) -> T in undef : $*(@in T) -> @out T to () -> () in undef : $*(@in ()) -> @out ()
63+
return undef : $()
64+
}
65+
66+
// We will handle this in a future commit.
67+
//
68+
// CHECK-LABEL: sil [ossa] @function_cast_throw_to_nothrow :
69+
// XHECK: builtin "int_trap"
70+
// CHECK: } // end sil function 'function_cast_throw_to_nothrow'
71+
sil [ossa] @function_cast_throw_to_nothrow : $@convention(thin) <T> () -> () {
72+
entry:
73+
unconditional_checked_cast_addr () throws -> () in undef : $*(@in ()) -> (@out (), @error Error) to () -> () in undef : $*(@in ()) -> @out ()
74+
return undef : $()
75+
}
76+
77+
// TODO: Do a function_conversion?
78+
// CHECK-LABEL: sil [ossa] @function_cast_nothrow_to_throw :
79+
// CHECK: unconditional_checked_cast_addr
80+
// CHECK: } // end sil function 'function_cast_nothrow_to_throw'
81+
sil [ossa] @function_cast_nothrow_to_throw : $@convention(thin) <T> () -> () {
82+
entry:
83+
unconditional_checked_cast_addr () -> () in undef : $*(@in ()) -> @out () to () throws -> () in undef : $*(@in ()) -> (@out (), @error Error)
84+
return undef : $()
85+
}
86+
87+
// We will handle this in a future commit.
88+
//
89+
// CHECK-LABEL: sil [ossa] @function_cast_throw_to_throw :
90+
// XHECK: load
91+
// XHECK: store
92+
// CHECK: } // end sil function 'function_cast_throw_to_throw'
93+
sil [ossa] @function_cast_throw_to_throw : $@convention(thin) <T> () -> () {
94+
entry:
95+
unconditional_checked_cast_addr () throws -> () in undef : $*(@in ()) -> (@out (), @error Error) to () throws -> () in undef : $*(@in ()) -> (@out (), @error Error)
96+
return undef : $()
97+
}
98+
99+
// CHECK-LABEL: sil [ossa] @function_ref_cast_promote
100+
// CHECK: [[LD:%.*]] = load [take] %1 : $*AnyObject
101+
// CHECK-NEXT: unchecked_ref_cast [[LD]] : $AnyObject to $AClass
102+
// CHECK-NEXT: store %{{.*}} to [init] %0 : $*AClass
103+
sil [ossa] @function_ref_cast_promote : $@convention(thin) (@in AnyObject) -> @out AClass {
104+
bb0(%0 : $*AClass, %1 : $*AnyObject):
105+
unchecked_ref_cast_addr AnyObject in %1 : $*AnyObject to AClass in %0 : $*AClass
106+
%4 = tuple ()
107+
return %4 : $()
108+
}
109+
110+
// Do not promote a ref cast for invalid types. It's a runtime error.
111+
// CHECK-LABEL: sil [ossa] @function_ref_cast_struct
112+
// CHECK: unchecked_ref_cast_addr
113+
sil [ossa] @function_ref_cast_struct : $@convention(thin) () -> @owned AnyObject {
114+
bb0:
115+
%0 = struct $S ()
116+
%1 = alloc_stack $S
117+
store %0 to [trivial] %1 : $*S
118+
%4 = alloc_stack $AnyObject
119+
unchecked_ref_cast_addr S in %1 : $*S to AnyObject in %4 : $*AnyObject
120+
%6 = load [take] %4 : $*AnyObject
121+
dealloc_stack %4 : $*AnyObject
122+
dealloc_stack %1 : $*S
123+
return %6 : $AnyObject
124+
}
125+
126+
// We will handle this in a future commit.
127+
//
128+
// CHECK-LABEL: sil [ossa] @destroy_source_of_removed_cast :
129+
// XHECK: destroy_addr %0
130+
// CHECK: } // end sil function 'destroy_source_of_removed_cast'
131+
sil [ossa] @destroy_source_of_removed_cast : $@convention(thin) (@in AnyObject) -> () {
132+
bb0(%0 : $*AnyObject):
133+
%2 = alloc_stack $Int
134+
unconditional_checked_cast_addr AnyObject in %0 : $*AnyObject to Int in %2 : $*Int
135+
%3 = load [trivial] %2 : $*Int
136+
dealloc_stack %2 : $*Int
137+
%r = tuple ()
138+
return %r : $()
139+
}
140+
141+
protocol P {}
142+
143+
// We will handle this in a future commit.
144+
//
145+
// CHECK-LABEL: sil [ossa] @remove_dead_checked_cast :
146+
// CHECK: bb0(%0 : $*AnyObject):
147+
// XHECK-NEXT: alloc_stack
148+
// XHECK-NEXT: destroy_addr %0
149+
// XHECK-NEXT: dealloc_stack
150+
// XHECK-NEXT: tuple
151+
// XHECK-NEXT: return
152+
// CHECK: } // end sil function 'remove_dead_checked_cast'
153+
sil [ossa] @remove_dead_checked_cast : $@convention(thin) (@in AnyObject) -> () {
154+
bb0(%0 : $*AnyObject):
155+
%5 = alloc_stack $P
156+
unconditional_checked_cast_addr AnyObject in %0 : $*AnyObject to P in %5 : $*P
157+
destroy_addr %5 : $*P
158+
dealloc_stack %5 : $*P
159+
%r = tuple ()
160+
return %r : $()
161+
}
162+
163+
// We will handle this in a future commit.
164+
//
165+
// CHECK-LABEL: sil [ossa] @testIOU :
166+
// CHECK: bb0(%0 : $*Optional<AnyObject>, %1 : $*Optional<AnyObject>):
167+
// XHECK: [[TMP:%.*]] = load [take] %1 : $*Optional<AnyObject>
168+
// XHECK: store [[TMP]] to [init] %0 : $*Optional<AnyObject>
169+
// CHECK: } // end sil function 'testIOU'
170+
sil [ossa] @testIOU : $@convention(thin) (@in Optional<AnyObject>) -> (@out Optional<AnyObject>) {
171+
bb0(%0 : $*Optional<AnyObject>, %1: $*Optional<AnyObject>):
172+
unconditional_checked_cast_addr ImplicitlyUnwrappedOptional<AnyObject> in %1 : $*Optional<AnyObject> to Optional<AnyObject> in %0 : $*Optional<AnyObject>
173+
%2 = tuple ()
174+
return %2 : $()
175+
}

0 commit comments

Comments
 (0)