Skip to content

Commit 0d2047a

Browse files
committed
[sil-combine] Update RefToRawPointer simplifications for ossa.
These are always safe in OSSA since what we are doing here is hoisting the ref_to_raw_pointer up the def-use chain without deleting any instructions unless we know that they do not have any uses (in a strict sense so destroy_value is considered a use). E.x.: ``` %0 = ... %1 = unchecked_ref_cast %0 %2 = ref_to_raw_pointer %1 ``` -> ``` %0 = ... %1 = unchecked_ref_cast %0 %2 = ref_to_raw_pointer %0 ``` Notice, how we are actually not changing %1 at all. Instead we are just moving an instantaneous use earlier. One thing that is important to realize is that this /does/ cause us to need to put the ref_to_raw_pointer at the insert location of %0 since %0's lifetime ends at the unchecked_ref_cast if the value is owned. NOTE: I also identified the tests from sil_combine.sil that had to do with these simplifications and extracted them into sil_combine_casts.sil and did the ossa/non-ossa tests side by side. I am trying to fix up the SILCombine tests as I update stuff, so if I find opportunities to move tests into a more descriptive sub-file, I am going to do so. As an aside, to make it easier to transition SILCombine away from using a central builder, I added a withBuilder method that creates a new SILBuilder at a requested insertPt and uses the same context as the main builder of SILCombine. It also through the usage of auto makes really concise pieces of code. Today to do this just using builder, we would do: ``` SILBuilderWithScope builder(insertPt, Builder); builder.createInst1(insertPt->getLoc(), ...); builder.createInst2(insertPt->getLoc(), ...); builder.createInst3(insertPt->getLoc(), ...); auto *finalValue = builder.createInst4(insertPt->getLoc(), ...); ``` Thats a lot of typing and wastes a really commonly used temp name (builder) in the local scope! Instead, using this API, one can write: auto *finalValue = withBuilder(insertPt, [&](auto &b, auto l) { b.createInst1(l, ...); b.createInst2(l, ...); b.createInst3(l, ...); return b.createInst4(l, ...); }); There is significantly less to type and auto handles the types for us. The withBuilder construct is just syntactic since we always inline it.
1 parent 698a0a3 commit 0d2047a

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)