Skip to content

Commit e1a616f

Browse files
authored
Merge pull request swiftlang#35198 from gottesmm/pr-0d922ed7f7078d21e2bbfc5273730703a61d7c08
[sil-combine] Update RefToRawPointer simplifications for ossa.
2 parents 890b202 + 0d2047a commit e1a616f

File tree

4 files changed

+255
-69
lines changed

4 files changed

+255
-69
lines changed

lib/SILOptimizer/SILCombiner/SILCombiner.h

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,41 @@ class SILCombiner :
113113
MadeChange = false;
114114
}
115115

116+
/// A "syntactic" high level function that combines our insertPt with the main
117+
/// builder's builder context.
118+
///
119+
/// Since this is syntactic and we assume that our caller is passing in a
120+
/// lambda that if we inline will be eliminated, we mark this function always
121+
/// inline.
122+
///
123+
/// What is nice about this formulation is it enables one to really concisely
124+
/// create a SILBuilder that uses the SILCombiner's builder context but at a
125+
/// different use point. Example:
126+
///
127+
/// SILBuilderWithScope builder(insertPt);
128+
/// builder.createInst1(insertPt->getLoc(), ...);
129+
/// builder.createInst2(insertPt->getLoc(), ...);
130+
/// builder.createInst3(insertPt->getLoc(), ...);
131+
/// auto *finalValue = builder.createInst4(insertPt->getLoc(), ...);
132+
///
133+
/// Thats a lot of typing! Instead, using this API, one can write:
134+
///
135+
/// auto *finalValue = withBuilder(insertPt, [&](auto &b, auto l) {
136+
/// b.createInst1(l, ...);
137+
/// b.createInst2(l, ...);
138+
/// b.createInst3(l, ...);
139+
/// return b.createInst4(l, ...);
140+
/// });
141+
///
142+
/// Since this is meant to be just be syntactic, we always inline this method.
143+
LLVM_ATTRIBUTE_ALWAYS_INLINE
144+
SingleValueInstruction *
145+
withBuilder(SILInstruction *insertPt,
146+
llvm::function_ref<SingleValueInstruction * (SILBuilder &, SILLocation)> visitor) {
147+
SILBuilderWithScope builder(insertPt, Builder);
148+
return visitor(builder, insertPt->getLoc());
149+
}
150+
116151
// Insert the instruction New before instruction Old in Old's parent BB. Add
117152
// New to the worklist.
118153
SILInstruction *insertNewInstBefore(SILInstruction *New,

lib/SILOptimizer/SILCombiner/SILCombinerCastVisitors.cpp

Lines changed: 54 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -30,31 +30,67 @@ using namespace swift;
3030
using namespace swift::PatternMatch;
3131

3232
SILInstruction *
33-
SILCombiner::visitRefToRawPointerInst(RefToRawPointerInst *RRPI) {
34-
if (RRPI->getFunction()->hasOwnership())
35-
return nullptr;
36-
37-
// Ref to raw pointer consumption of other ref casts.
38-
if (auto *URCI = dyn_cast<UncheckedRefCastInst>(RRPI->getOperand())) {
39-
// (ref_to_raw_pointer (unchecked_ref_cast x))
40-
// -> (ref_to_raw_pointer x)
41-
if (URCI->getOperand()->getType().isAnyClassReferenceType()) {
42-
RRPI->setOperand(URCI->getOperand());
43-
return URCI->use_empty() ? eraseInstFromFunction(*URCI) : nullptr;
33+
SILCombiner::visitRefToRawPointerInst(RefToRawPointerInst *rrpi) {
34+
if (auto *urci = dyn_cast<UncheckedRefCastInst>(rrpi->getOperand())) {
35+
// In this optimization, we try to move ref_to_raw_pointer up the def-use
36+
// graph. E.x.:
37+
//
38+
// ```
39+
// %0 = ...
40+
// %1 = unchecked_ref_cast %0
41+
// %2 = ref_to_raw_pointer %1
42+
// ```
43+
//
44+
// to:
45+
//
46+
// ```
47+
// %0 = ...
48+
// %2 = ref_to_raw_pointer %0
49+
// %1 = unchecked_ref_cast %0
50+
// ```
51+
//
52+
// If we find that the unchecked_ref_cast has no uses, we then eliminate
53+
// it.
54+
//
55+
// Naturally, this requires us to always hoist our new instruction (or
56+
// modified instruction) to before the unchecked_ref_cast.
57+
//
58+
// First we handle the case where we have a class type where we do not need
59+
// to insert a new instruction.
60+
if (urci->getOperand()->getType().isAnyClassReferenceType()) {
61+
rrpi->setOperand(urci->getOperand());
62+
rrpi->moveBefore(urci);
63+
return urci->use_empty() ? eraseInstFromFunction(*urci) : nullptr;
4464
}
65+
66+
// Otherwise, we ened to use an unchecked_trivial_bit_cast insert it at
67+
// urci.
68+
//
4569
// (ref_to_raw_pointer (unchecked_ref_cast x))
4670
// -> (unchecked_trivial_bit_cast x)
47-
return Builder.createUncheckedTrivialBitCast(RRPI->getLoc(),
48-
URCI->getOperand(),
49-
RRPI->getType());
71+
auto *utbi = withBuilder(urci, [&](auto &b, auto l) {
72+
return b.createUncheckedTrivialBitCast(l, urci->getOperand(),
73+
rrpi->getType());
74+
});
75+
rrpi->replaceAllUsesWith(utbi);
76+
eraseInstFromFunction(*rrpi);
77+
return urci->use_empty() ? eraseInstFromFunction(*urci) : nullptr;
5078
}
5179

5280
// (ref_to_raw_pointer (open_existential_ref (init_existential_ref x))) ->
5381
// (ref_to_raw_pointer x)
54-
if (auto *OER = dyn_cast<OpenExistentialRefInst>(RRPI->getOperand()))
55-
if (auto *IER = dyn_cast<InitExistentialRefInst>(OER->getOperand()))
56-
return Builder.createRefToRawPointer(RRPI->getLoc(), IER->getOperand(),
57-
RRPI->getType());
82+
//
83+
// In terms of ownership, we need to insert this at the init_existential to
84+
// ensure that x is live if we have an owned value.
85+
if (auto *oeri = dyn_cast<OpenExistentialRefInst>(rrpi->getOperand())) {
86+
if (auto *ieri = dyn_cast<InitExistentialRefInst>(oeri->getOperand())) {
87+
auto *utbi = withBuilder(ieri, [&](auto &b, auto l) {
88+
return b.createRefToRawPointer(l, ieri->getOperand(), rrpi->getType());
89+
});
90+
rrpi->replaceAllUsesWith(utbi);
91+
return eraseInstFromFunction(*rrpi);
92+
}
93+
}
5894

5995
return nullptr;
6096
}

test/SILOptimizer/sil_combine.sil

Lines changed: 2 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -544,21 +544,6 @@ bb0(%0 : $@thin U.Type, %1 : $C):
544544
return %6 : $(U, U, U)
545545
}
546546

547-
// RefToRawPointer pointer consumption.
548-
//
549-
// (ref_to_raw_pointer (unchecked_ref_cast x))
550-
// -> (ref_to_raw_pointer x)
551-
// CHECK-LABEL: sil @ref_to_raw_pointer_unchecked_ref_cast_composition : $@convention(thin) (C) -> Builtin.RawPointer
552-
// CHECK: bb0
553-
// CHECK-NEXT: ref_to_raw_pointer
554-
// CHECK-NEXT: return
555-
sil @ref_to_raw_pointer_unchecked_ref_cast_composition : $@convention(thin) (C) -> Builtin.RawPointer {
556-
bb0(%0 : $C):
557-
%1 = unchecked_ref_cast %0 : $C to $Builtin.NativeObject
558-
%2 = ref_to_raw_pointer %1 : $Builtin.NativeObject to $Builtin.RawPointer
559-
return %2 : $Builtin.RawPointer
560-
}
561-
562547
// CHECK-LABEL: sil @downcast_upcast_roundtrip
563548
// CHECK: bb0
564549
// CHECK-NEXT: return
@@ -2342,30 +2327,11 @@ bb0(%0: $MyClass):
23422327
return %3 : $Builtin.NativeObject
23432328
}
23442329

2345-
// CHECK-LABEL: sil @collapse_existential_pack_unpack_ref_to_raw_pointer
2346-
// CHECK: bb0([[Ref:%.*]]: $MyClass):
2347-
// CHECK-NOT: init_existential_ref
2348-
// CHECK-NOT: open_existential_ref
2349-
// CHECK: ref_to_raw_pointer [[Ref]]
2350-
2351-
sil @collapse_existential_pack_unpack_ref_to_raw_pointer : $@convention(thin) (MyClass) -> () {
2352-
bb0(%0: $MyClass):
2353-
%1 = init_existential_ref %0 : $MyClass : $MyClass, $AnyObject
2354-
%2 = open_existential_ref %1 : $AnyObject to $@opened("2CAE06CE-5F10-11E4-AF13-C82A1428F987") AnyObject
2355-
%3 = ref_to_raw_pointer %2 : $@opened("2CAE06CE-5F10-11E4-AF13-C82A1428F987") AnyObject to $Builtin.RawPointer
2356-
%4 = pointer_to_address %3 : $Builtin.RawPointer to [strict] $*Builtin.Word
2357-
%5 = integer_literal $Builtin.Word, 5
2358-
store %5 to %4: $*Builtin.Word
2359-
%6 = tuple ()
2360-
return %6 : $()
2361-
}
2362-
23632330
// CHECK-LABEL: sil @load_fixlifetime_address
23642331
// CHECK: [[Stck:%.*]] = alloc_stack
23652332
// CHECK-NOT: fix_lifetime [[Stck]]#1
23662333
// CHECK: [[StckVal:%.*]] = load [[Stck]]
23672334
// CHECK: fix_lifetime [[StckVal]]
2368-
23692335
sil @load_fixlifetime_address : $@convention(thin) (Builtin.NativeObject) -> () {
23702336
bb0(%0: $Builtin.NativeObject):
23712337
%1 = alloc_stack $Builtin.NativeObject
@@ -2376,20 +2342,6 @@ bb0(%0: $Builtin.NativeObject):
23762342
return %6 : $()
23772343
}
23782344

2379-
// CHECK-LABEL: sil @collapse_to_unchecked_trivial_bit_cast
2380-
// CHECK: bb0([[Ref:%.*]]: $Optional<MyClass>):
2381-
// CHECK: unchecked_trivial_bit_cast [[Ref]]
2382-
// CHECK-NOT: unchecked_ref_cast
2383-
// CHECK-NOT: ref_to_raw_pointer
2384-
// CHECK: return
2385-
// (ref_to_raw_pointer (unchecked_ref_cast x)) -> (unchecked_trivial_bit_cast x)
2386-
sil @collapse_to_unchecked_trivial_bit_cast : $@convention(thin) (Optional<MyClass>) -> (Builtin.RawPointer) {
2387-
bb0(%0 : $Optional<MyClass>):
2388-
%1 = unchecked_ref_cast %0 : $Optional<MyClass> to $Builtin.NativeObject
2389-
%2 = ref_to_raw_pointer %1 : $Builtin.NativeObject to $Builtin.RawPointer
2390-
return %2 : $Builtin.RawPointer
2391-
}
2392-
23932345
struct GenContainer<T> {
23942346
}
23952347

@@ -2398,12 +2350,11 @@ bb0(%0 : $Builtin.RawPointer, %1 : $*Builtin.UnsafeValueBuffer, %2 : $*GenContai
23982350
unreachable
23992351
}
24002352

2401-
2402-
// CHECK-LABEL: sil @remove_dead_code_after_cond_fail
2353+
// CHECK-LABEL: sil @remove_dead_code_after_cond_fail :
24032354
// CHECK: [[Ref:%.*]] = integer_literal $Builtin.Int1, -1
24042355
// CHECK-NEXT: cond_fail [[Ref]]
24052356
// CHECK-NEXT: unreachable
2406-
2357+
// CHECK: } // end sil function 'remove_dead_code_after_cond_fail'
24072358
sil @remove_dead_code_after_cond_fail : $@convention(thin) () -> (Int32) {
24082359
bb0:
24092360
%0 = integer_literal $Builtin.Int32, -2

test/SILOptimizer/sil_combine_casts.sil

Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,13 @@
33
sil_stage canonical
44

55
import Builtin
6+
import Swift
67

78
class Klass {}
89

910
sil @returnInt : $@convention(thin) () -> Builtin.Int32
11+
sil @use_anyobject : $@convention(thin) (@guaranteed AnyObject) -> ()
12+
sil @use_nativeobject : $@convention(thin) (@guaranteed Builtin.NativeObject) -> ()
1013

1114
// CHECK-LABEL: sil @optimize_convert_escape_to_noescape :
1215
// CHECK: [[FN:%.*]] = function_ref @returnInt
@@ -37,3 +40,164 @@ bb0:
3740
%4 = apply %2() : $@noescape @callee_guaranteed () -> Builtin.Int32
3841
return %4 : $Builtin.Int32
3942
}
43+
44+
//////////////////////////////
45+
// ref_to_raw_pointer tests //
46+
//////////////////////////////
47+
48+
// RefToRawPointer pointer consumption.
49+
//
50+
// (ref_to_raw_pointer (unchecked_ref_cast x))
51+
// -> (ref_to_raw_pointer x)
52+
//
53+
// CHECK-LABEL: sil @ref_to_raw_pointer_unchecked_ref_cast_composition : $@convention(thin) (@guaranteed Klass) -> Builtin.RawPointer
54+
// CHECK: bb0
55+
// CHECK-NEXT: ref_to_raw_pointer
56+
// CHECK-NEXT: return
57+
// CHECK: } // end sil function 'ref_to_raw_pointer_unchecked_ref_cast_composition'
58+
sil @ref_to_raw_pointer_unchecked_ref_cast_composition : $@convention(thin) (@guaranteed Klass) -> Builtin.RawPointer {
59+
bb0(%0 : $Klass):
60+
%1 = unchecked_ref_cast %0 : $Klass to $Builtin.NativeObject
61+
%2 = ref_to_raw_pointer %1 : $Builtin.NativeObject to $Builtin.RawPointer
62+
return %2 : $Builtin.RawPointer
63+
}
64+
65+
// CHECK-LABEL: sil [ossa] @ref_to_raw_pointer_unchecked_ref_cast_composition_ossa_guaranteed : $@convention(thin) (@guaranteed Klass) -> Builtin.RawPointer
66+
// CHECK: bb0
67+
// CHECK-NEXT: ref_to_raw_pointer
68+
// CHECK-NEXT: return
69+
// CHECK: } // end sil function 'ref_to_raw_pointer_unchecked_ref_cast_composition_ossa_guaranteed'
70+
sil [ossa] @ref_to_raw_pointer_unchecked_ref_cast_composition_ossa_guaranteed : $@convention(thin) (@guaranteed Klass) -> Builtin.RawPointer {
71+
bb0(%0 : @guaranteed $Klass):
72+
%1 = unchecked_ref_cast %0 : $Klass to $Builtin.NativeObject
73+
%2 = ref_to_raw_pointer %1 : $Builtin.NativeObject to $Builtin.RawPointer
74+
return %2 : $Builtin.RawPointer
75+
}
76+
77+
// CHECK-LABEL: sil [ossa] @ref_to_raw_pointer_unchecked_ref_cast_composition_ossa_owned : $@convention(thin) (@owned Klass) -> Builtin.RawPointer
78+
// CHECK: bb0([[ARG:%.*]] : @owned
79+
// CHECK-NEXT: [[RESULT:%.*]] = ref_to_raw_pointer [[ARG]]
80+
// CHECK-NEXT: [[CAST:%.*]] = unchecked_ref_cast [[ARG]]
81+
// CHECK-NEXT: destroy_value [[CAST]]
82+
// CHECK-NEXT: return [[RESULT]]
83+
// CHECK: } // end sil function 'ref_to_raw_pointer_unchecked_ref_cast_composition_ossa_owned'
84+
sil [ossa] @ref_to_raw_pointer_unchecked_ref_cast_composition_ossa_owned : $@convention(thin) (@owned Klass) -> Builtin.RawPointer {
85+
bb0(%0 : @owned $Klass):
86+
%1 = unchecked_ref_cast %0 : $Klass to $Builtin.NativeObject
87+
%2 = ref_to_raw_pointer %1 : $Builtin.NativeObject to $Builtin.RawPointer
88+
destroy_value %1 : $Builtin.NativeObject
89+
return %2 : $Builtin.RawPointer
90+
}
91+
92+
// CHECK-LABEL: sil @collapse_existential_pack_unpack_ref_to_raw_pointer :
93+
// CHECK: bb0([[Ref:%.*]] : $Klass):
94+
// CHECK-NOT: init_existential_ref
95+
// CHECK-NOT: open_existential_ref
96+
// CHECK: ref_to_raw_pointer [[Ref]]
97+
// CHECK: } // end sil function 'collapse_existential_pack_unpack_ref_to_raw_pointer'
98+
sil @collapse_existential_pack_unpack_ref_to_raw_pointer : $@convention(thin) (@guaranteed Klass) -> () {
99+
bb0(%0 : $Klass):
100+
%1 = init_existential_ref %0 : $Klass : $Klass, $AnyObject
101+
%2 = open_existential_ref %1 : $AnyObject to $@opened("2CAE06CE-5F10-11E4-AF13-C82A1428F987") AnyObject
102+
%3 = ref_to_raw_pointer %2 : $@opened("2CAE06CE-5F10-11E4-AF13-C82A1428F987") AnyObject to $Builtin.RawPointer
103+
%4 = pointer_to_address %3 : $Builtin.RawPointer to [strict] $*Builtin.Word
104+
%5 = integer_literal $Builtin.Word, 5
105+
store %5 to %4: $*Builtin.Word
106+
%6 = tuple ()
107+
return %6 : $()
108+
}
109+
110+
// CHECK-LABEL: sil [ossa] @collapse_existential_pack_unpack_ref_to_raw_pointer_ossa_guaranteed :
111+
// CHECK: bb0([[Ref:%.*]] : @guaranteed $Klass):
112+
// CHECK-NOT: init_existential_ref
113+
// CHECK-NOT: open_existential_ref
114+
// CHECK: ref_to_raw_pointer [[Ref]]
115+
// CHECK: } // end sil function 'collapse_existential_pack_unpack_ref_to_raw_pointer_ossa_guaranteed'
116+
sil [ossa] @collapse_existential_pack_unpack_ref_to_raw_pointer_ossa_guaranteed : $@convention(thin) (@guaranteed Klass) -> () {
117+
bb0(%0 : @guaranteed $Klass):
118+
%1 = init_existential_ref %0 : $Klass : $Klass, $AnyObject
119+
%2 = open_existential_ref %1 : $AnyObject to $@opened("2CAE06CE-5F10-11E4-AF13-C82A1428F987") AnyObject
120+
%3 = ref_to_raw_pointer %2 : $@opened("2CAE06CE-5F10-11E4-AF13-C82A1428F987") AnyObject to $Builtin.RawPointer
121+
%4 = pointer_to_address %3 : $Builtin.RawPointer to [strict] $*Builtin.Word
122+
%5 = integer_literal $Builtin.Word, 5
123+
store %5 to [trivial] %4: $*Builtin.Word
124+
%6 = tuple ()
125+
return %6 : $()
126+
}
127+
128+
// We need to hoist the ref_to_raw_pointer above the init_existential_ref since
129+
// that is where %0 is live.
130+
//
131+
// CHECK-LABEL: sil [ossa] @collapse_existential_pack_unpack_ref_to_raw_pointer_ossa_owned :
132+
// CHECK: bb0([[ARG:%.*]] : @owned $Klass):
133+
// CHECK-NOT: init_existential_ref
134+
// CHECK-NOT: open_existential_ref
135+
// CHECK: [[PTR:%.*]] = ref_to_raw_pointer [[ARG]]
136+
// CHECK: [[FORWARDED_ARG:%.*]] = init_existential_ref [[ARG]]
137+
// CHECK: destroy_value [[FORWARDED_ARG]]
138+
// CHECK: } // end sil function 'collapse_existential_pack_unpack_ref_to_raw_pointer_ossa_owned'
139+
sil [ossa] @collapse_existential_pack_unpack_ref_to_raw_pointer_ossa_owned : $@convention(thin) (@owned Klass) -> () {
140+
bb0(%0 : @owned $Klass):
141+
%1 = init_existential_ref %0 : $Klass : $Klass, $AnyObject
142+
%f = function_ref @use_anyobject : $@convention(thin) (@guaranteed AnyObject) -> ()
143+
apply %f(%1) : $@convention(thin) (@guaranteed AnyObject) -> ()
144+
%2 = open_existential_ref %1 : $AnyObject to $@opened("2CAE06CE-5F10-11E4-AF13-C82A1428F987") AnyObject
145+
%3 = ref_to_raw_pointer %2 : $@opened("2CAE06CE-5F10-11E4-AF13-C82A1428F987") AnyObject to $Builtin.RawPointer
146+
%4 = pointer_to_address %3 : $Builtin.RawPointer to [strict] $*Builtin.Word
147+
%5 = integer_literal $Builtin.Word, 5
148+
store %5 to [trivial] %4: $*Builtin.Word
149+
destroy_value %2 : $@opened("2CAE06CE-5F10-11E4-AF13-C82A1428F987") AnyObject
150+
%6 = tuple ()
151+
return %6 : $()
152+
}
153+
154+
155+
// (ref_to_raw_pointer (unchecked_ref_cast x)) -> (unchecked_trivial_bit_cast x)
156+
//
157+
// CHECK-LABEL: sil @collapse_to_unchecked_trivial_bit_cast :
158+
// CHECK: bb0([[Ref:%.*]] : $Optional<Klass>):
159+
// CHECK: unchecked_trivial_bit_cast [[Ref]]
160+
// CHECK-NOT: unchecked_ref_cast
161+
// CHECK-NOT: ref_to_raw_pointer
162+
// CHECK: } // end sil function 'collapse_to_unchecked_trivial_bit_cast'
163+
sil @collapse_to_unchecked_trivial_bit_cast : $@convention(thin) (Optional<Klass>) -> (Builtin.RawPointer) {
164+
bb0(%0 : $Optional<Klass>):
165+
%1 = unchecked_ref_cast %0 : $Optional<Klass> to $Builtin.NativeObject
166+
%2 = ref_to_raw_pointer %1 : $Builtin.NativeObject to $Builtin.RawPointer
167+
return %2 : $Builtin.RawPointer
168+
}
169+
170+
// CHECK-LABEL: sil [ossa] @collapse_to_unchecked_trivial_bit_cast_ossa_guaranteed :
171+
// CHECK: bb0([[Ref:%.*]] : @guaranteed $Optional<Klass>):
172+
// CHECK: unchecked_trivial_bit_cast [[Ref]]
173+
// CHECK-NOT: unchecked_ref_cast
174+
// CHECK-NOT: ref_to_raw_pointer
175+
// CHECK: } // end sil function 'collapse_to_unchecked_trivial_bit_cast_ossa_guaranteed'
176+
sil [ossa] @collapse_to_unchecked_trivial_bit_cast_ossa_guaranteed : $@convention(thin) (@guaranteed Optional<Klass>) -> (Builtin.RawPointer) {
177+
bb0(%0 : @guaranteed $Optional<Klass>):
178+
%1 = unchecked_ref_cast %0 : $Optional<Klass> to $Builtin.NativeObject
179+
%2 = ref_to_raw_pointer %1 : $Builtin.NativeObject to $Builtin.RawPointer
180+
return %2 : $Builtin.RawPointer
181+
}
182+
183+
// We need to make sure that we hoist unchecked_trivial_bit_cast above
184+
// unchecked_ref_cast since we are not eliminating it here due to an additional
185+
// user.
186+
//
187+
// CHECK-LABEL: sil [ossa] @collapse_to_unchecked_trivial_bit_cast_ossa_owned :
188+
// CHECK: bb0([[ARG:%.*]] : @owned $Optional<Klass>):
189+
// CHECK: [[RESULT:%.*]] = unchecked_trivial_bit_cast [[ARG]]
190+
// CHECK: [[FORWARDED_ARG:%.*]] = unchecked_ref_cast [[ARG]]
191+
// CHECK: destroy_value [[FORWARDED_ARG]]
192+
// CHECK: return [[RESULT]]
193+
// CHECK: } // end sil function 'collapse_to_unchecked_trivial_bit_cast_ossa_owned'
194+
sil [ossa] @collapse_to_unchecked_trivial_bit_cast_ossa_owned : $@convention(thin) (@owned Optional<Klass>) -> (Builtin.RawPointer) {
195+
bb0(%0 : @owned $Optional<Klass>):
196+
%1 = unchecked_ref_cast %0 : $Optional<Klass> to $Builtin.NativeObject
197+
%f = function_ref @use_nativeobject : $@convention(thin) (@guaranteed Builtin.NativeObject) -> ()
198+
apply %f(%1) : $@convention(thin) (@guaranteed Builtin.NativeObject) -> ()
199+
%2 = ref_to_raw_pointer %1 : $Builtin.NativeObject to $Builtin.RawPointer
200+
destroy_value %1 : $Builtin.NativeObject
201+
return %2 : $Builtin.RawPointer
202+
}
203+

0 commit comments

Comments
 (0)