Skip to content

Commit a042112

Browse files
authored
Merge pull request #25041 from gottesmm/pr-d02a03999626f1d50a4bf0996dadb34e72d9f355
[cast-opt] Fix miscompile when we tried to optimize take_on_success t…
2 parents 381cf59 + ad67685 commit a042112

File tree

2 files changed

+226
-3
lines changed

2 files changed

+226
-3
lines changed

lib/SILOptimizer/Utils/CastOptimizer.cpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -323,11 +323,12 @@ CastOptimizer::optimizeBridgedObjCToSwiftCast(SILDynamicCastInst dynamicCast) {
323323
case CastConsumptionKind::TakeAlways:
324324
Builder.createReleaseValue(Loc, srcOp, Builder.getDefaultAtomicity());
325325
break;
326-
case CastConsumptionKind::TakeOnSuccess:
326+
case CastConsumptionKind::TakeOnSuccess: {
327327
// Insert a release in the success BB.
328-
Builder.setInsertionPoint(SuccessBB->begin());
329-
Builder.createReleaseValue(Loc, srcOp, Builder.getDefaultAtomicity());
328+
SILBuilderWithScope SuccessBuilder(SuccessBB->begin());
329+
SuccessBuilder.emitDestroyValueOperation(Loc, srcOp);
330330
break;
331+
}
331332
case CastConsumptionKind::BorrowAlways:
332333
llvm_unreachable("checked_cast_addr_br never has BorrowAlways");
333334
case CastConsumptionKind::CopyOnSuccess:
Lines changed: 222 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,222 @@
1+
// RUN: %target-sil-opt -enable-sil-verify-all %s -diagnostic-constant-propagation | %FileCheck %s
2+
// RUN: %target-sil-opt -enable-sil-verify-all %s -performance-constant-propagation | %FileCheck %s
3+
4+
// REQUIRES: objc_interop
5+
6+
sil_stage canonical
7+
8+
import Swift
9+
import Foundation
10+
import Builtin
11+
12+
sil @$ss11AnyHashableVyABxcSHRzlufC : $@convention(method) <τ_0_0 where τ_0_0 : Hashable> (@in τ_0_0, @thin AnyHashable.Type) -> @out AnyHashable
13+
14+
sil @guaranteed_swift_array_user : $@convention(thin) <τ_0_0> (@guaranteed Array<τ_0_0>) -> ()
15+
16+
// CHECK-LABEL: sil @array_downcast_copyonsuccess : $@convention(thin) (@guaranteed NSArray) -> () {
17+
// CHECK: bb0([[ARG:%.*]] : $NSArray):
18+
// CHECK: [[INPUT:%.*]] = alloc_stack $NSArray
19+
// CHECK: retain_value [[ARG]]
20+
// CHECK: store [[ARG]] to [[INPUT]]
21+
// CHECK: [[OUTPUT:%.*]] = alloc_stack $Array<String>
22+
// CHECK: [[INPUT_VALUE:%.*]] = load [[INPUT]]
23+
// CHECK: br [[BRIDGE_BB:bb[0-9]+]]([[INPUT_VALUE]] :
24+
//
25+
// CHECK: [[SUCCESS_BB:bb[0-9]+]]:
26+
// CHECK: [[SUCCESS_VAL:%.*]] = load [[OUTPUT]]
27+
// CHECK: [[CAST_RESULT:%.*]] = apply {{%.*}}<String>([[SUCCESS_VAL]])
28+
// CHECK-NEXT: release_value [[SUCCESS_VAL]]
29+
// CHECK-NEXT: dealloc_stack [[OUTPUT]]
30+
// CHECK-NEXT: destroy_addr [[INPUT]]
31+
// CHECK-NEXT: dealloc_stack [[INPUT]]
32+
// CHECK-NEXT: br [[EXIT_BB:bb[0-9]+]]
33+
//
34+
// CHECK: [[FAIL_BB:bb[0-9]+]]:
35+
// CHECK-NEXT: dealloc_stack [[CAST_TMP:%.*]]
36+
// CHECK-NEXT: dealloc_stack [[OUTPUT]]
37+
// CHECK-NEXT: destroy_addr [[INPUT]]
38+
// CHECK-NEXT: dealloc_stack [[INPUT]]
39+
// CHECK-NEXT: br [[EXIT_BB]]
40+
//
41+
// CHECK: [[EXIT_BB]]:
42+
// CHECK: return
43+
//
44+
// CHECK: [[BRIDGE_BB]]([[INPUT_VALUE:%.*]] : $NSArray):
45+
// CHECK: [[CAST_TMP:%.*]] = alloc_stack $Optional<Array<String>>
46+
// CHECK: strong_retain [[INPUT_VALUE]]
47+
// CHECK: apply {{%.*}}<Array<String>>([[CAST_TMP]], [[INPUT_VALUE]],
48+
// CHECK: strong_release [[INPUT_VALUE]]
49+
// CHECK: switch_enum_addr [[CAST_TMP]] : $*Optional<Array<String>>, case #Optional.none!enumelt: [[FAIL_BB]], default [[SUCCESS_TRAMPOLINE_BB:bb[0-9]+]]
50+
//
51+
// CHECK: [[SUCCESS_TRAMPOLINE_BB]]:
52+
// CHECK: [[PROJ_ENUM:%.*]] = unchecked_take_enum_data_addr [[CAST_TMP]]
53+
// CHECK: copy_addr [take] [[PROJ_ENUM]] to [initialization] [[OUTPUT]]
54+
// CHECK: dealloc_stack [[CAST_TMP]]
55+
// CHECK: br [[SUCCESS_BB]]
56+
// CHECK: } // end sil function 'array_downcast_copyonsuccess'
57+
sil @array_downcast_copyonsuccess : $@convention(thin) (@guaranteed NSArray) -> () {
58+
bb0(%0 : $NSArray):
59+
%4 = alloc_stack $NSArray
60+
retain_value %0 : $NSArray
61+
store %0 to %4 : $*NSArray
62+
%7 = alloc_stack $Array<String>
63+
checked_cast_addr_br copy_on_success NSArray in %4 : $*NSArray to Array<String> in %7 : $*Array<String>, bb2, bb3
64+
65+
bb2:
66+
%9 = load %7 : $*Array<String>
67+
%10 = function_ref @guaranteed_swift_array_user : $@convention(thin) <τ_0_0> (@guaranteed Array<τ_0_0>) -> ()
68+
apply %10<String>(%9) : $@convention(thin) <τ_0_0> (@guaranteed Array<τ_0_0>) -> ()
69+
release_value %9 : $Array<String>
70+
dealloc_stack %7 : $*Array<String>
71+
destroy_addr %4 : $*NSArray
72+
dealloc_stack %4 : $*NSArray
73+
br bb4
74+
75+
bb3:
76+
dealloc_stack %7 : $*Array<String>
77+
destroy_addr %4 : $*NSArray
78+
dealloc_stack %4 : $*NSArray
79+
br bb4
80+
81+
bb4:
82+
%9999 = tuple()
83+
return %9999 : $()
84+
}
85+
86+
// CHECK-LABEL: sil @array_downcast_takeonsuccess : $@convention(thin) (@guaranteed NSArray) -> () {
87+
// CHECK: bb0([[ARG:%.*]] : $NSArray):
88+
// CHECK: [[INPUT:%.*]] = alloc_stack $NSArray
89+
// CHECK: retain_value [[ARG]]
90+
// CHECK: store [[ARG]] to [[INPUT]]
91+
// CHECK: [[OUTPUT:%.*]] = alloc_stack $Array<String>
92+
// CHECK: [[INPUT_VALUE:%.*]] = load [[INPUT]]
93+
// CHECK: br [[BRIDGE_BB:bb[0-9]+]]([[INPUT_VALUE]] :
94+
//
95+
// CHECK: [[SUCCESS_BB:bb[0-9]+]]:
96+
// CHECK: strong_release [[INPUT_VALUE:%.*]] :
97+
// CHECK: [[SUCCESS_VAL:%.*]] = load [[OUTPUT]]
98+
// CHECK: [[CAST_RESULT:%.*]] = apply {{%.*}}<String>([[SUCCESS_VAL]])
99+
// CHECK-NEXT: release_value [[SUCCESS_VAL]]
100+
// CHECK-NEXT: dealloc_stack [[OUTPUT]]
101+
// CHECK-NEXT: dealloc_stack [[INPUT]]
102+
// CHECK-NEXT: br [[EXIT_BB:bb[0-9]+]]
103+
//
104+
// CHECK: [[FAIL_BB:bb[0-9]+]]:
105+
// CHECK-NEXT: dealloc_stack [[CAST_TMP:%.*]]
106+
// CHECK-NEXT: dealloc_stack [[OUTPUT]]
107+
// CHECK-NEXT: destroy_addr [[INPUT]]
108+
// CHECK-NEXT: dealloc_stack [[INPUT]]
109+
// CHECK-NEXT: br [[EXIT_BB]]
110+
//
111+
// CHECK: [[EXIT_BB]]:
112+
// CHECK: return
113+
//
114+
// CHECK: [[BRIDGE_BB]]([[INPUT_VALUE]] : $NSArray):
115+
// CHECK: [[CAST_TMP:%.*]] = alloc_stack $Optional<Array<String>>
116+
// CHECK: strong_retain [[INPUT_VALUE]]
117+
// CHECK: apply {{%.*}}<Array<String>>([[CAST_TMP]], [[INPUT_VALUE]],
118+
// CHECK: strong_release [[INPUT_VALUE]]
119+
// NOTE: In contrast to with take_always, the release_value is above in SUCCESS_BLOCK
120+
// CHECK: switch_enum_addr [[CAST_TMP]] : $*Optional<Array<String>>, case #Optional.none!enumelt: [[FAIL_BB]], default [[SUCCESS_TRAMPOLINE_BB:bb[0-9]+]]
121+
//
122+
// CHECK: [[SUCCESS_TRAMPOLINE_BB]]:
123+
// CHECK: [[PROJ_ENUM:%.*]] = unchecked_take_enum_data_addr [[CAST_TMP]]
124+
// CHECK: copy_addr [take] [[PROJ_ENUM]] to [initialization] [[OUTPUT]]
125+
// CHECK: dealloc_stack [[CAST_TMP]]
126+
// CHECK: br [[SUCCESS_BB]]
127+
// CHECK: } // end sil function 'array_downcast_takeonsuccess'
128+
sil @array_downcast_takeonsuccess : $@convention(thin) (@guaranteed NSArray) -> () {
129+
bb0(%0 : $NSArray):
130+
%4 = alloc_stack $NSArray
131+
retain_value %0 : $NSArray
132+
store %0 to %4 : $*NSArray
133+
%7 = alloc_stack $Array<String>
134+
checked_cast_addr_br take_on_success NSArray in %4 : $*NSArray to Array<String> in %7 : $*Array<String>, bb2, bb3
135+
136+
bb2:
137+
%9 = load %7 : $*Array<String>
138+
%10 = function_ref @guaranteed_swift_array_user : $@convention(thin) <τ_0_0> (@guaranteed Array<τ_0_0>) -> ()
139+
apply %10<String>(%9) : $@convention(thin) <τ_0_0> (@guaranteed Array<τ_0_0>) -> ()
140+
release_value %9 : $Array<String>
141+
dealloc_stack %7 : $*Array<String>
142+
dealloc_stack %4 : $*NSArray
143+
br bb4
144+
145+
bb3:
146+
dealloc_stack %7 : $*Array<String>
147+
destroy_addr %4 : $*NSArray
148+
dealloc_stack %4 : $*NSArray
149+
br bb4
150+
151+
bb4:
152+
%9999 = tuple()
153+
return %9999 : $()
154+
}
155+
156+
// CHECK-LABEL: sil @array_downcast_takealways : $@convention(thin) (@guaranteed NSArray) -> () {
157+
// CHECK: bb0([[ARG:%.*]] : $NSArray):
158+
// CHECK: [[INPUT:%.*]] = alloc_stack $NSArray
159+
// CHECK: retain_value [[ARG]]
160+
// CHECK: store [[ARG]] to [[INPUT]]
161+
// CHECK: [[OUTPUT:%.*]] = alloc_stack $Array<String>
162+
// CHECK: [[INPUT_VALUE:%.*]] = load [[INPUT]]
163+
// CHECK: br [[BRIDGE_BB:bb[0-9]+]]([[INPUT_VALUE]] :
164+
//
165+
// CHECK: [[SUCCESS_BB:bb[0-9]+]]:
166+
// CHECK: [[SUCCESS_VAL:%.*]] = load [[OUTPUT]]
167+
// CHECK: [[CAST_RESULT:%.*]] = apply {{%.*}}<String>([[SUCCESS_VAL]])
168+
// CHECK-NEXT: release_value [[SUCCESS_VAL]]
169+
// CHECK-NEXT: dealloc_stack [[OUTPUT]]
170+
// CHECK-NEXT: dealloc_stack [[INPUT]]
171+
// CHECK-NEXT: br [[EXIT_BB:bb[0-9]+]]
172+
//
173+
// CHECK: [[FAIL_BB:bb[0-9]+]]:
174+
// CHECK-NEXT: dealloc_stack [[CAST_TMP:%.*]]
175+
// CHECK-NEXT: dealloc_stack [[OUTPUT]]
176+
// CHECK-NEXT: dealloc_stack [[INPUT]]
177+
// CHECK-NEXT: br [[EXIT_BB]]
178+
//
179+
// CHECK: [[EXIT_BB]]:
180+
// CHECK: return
181+
//
182+
// CHECK: [[BRIDGE_BB]]([[INPUT_VALUE:%.*]] : $NSArray):
183+
// CHECK: [[CAST_TMP:%.*]] = alloc_stack $Optional<Array<String>>
184+
// CHECK: strong_retain [[INPUT_VALUE]]
185+
// CHECK: apply {{%.*}}<Array<String>>([[CAST_TMP]], [[INPUT_VALUE]],
186+
// CHECK: strong_release [[INPUT_VALUE]]
187+
// NOTE: When we perform take_always, this is the take of the cast.
188+
// CHECK: release_value [[INPUT_VALUE]]
189+
// CHECK: switch_enum_addr [[CAST_TMP]] : $*Optional<Array<String>>, case #Optional.none!enumelt: [[FAIL_BB]], default [[SUCCESS_TRAMPOLINE_BB:bb[0-9]+]]
190+
//
191+
// CHECK: [[SUCCESS_TRAMPOLINE_BB]]:
192+
// CHECK: [[PROJ_ENUM:%.*]] = unchecked_take_enum_data_addr [[CAST_TMP]]
193+
// CHECK: copy_addr [take] [[PROJ_ENUM]] to [initialization] [[OUTPUT]]
194+
// CHECK: dealloc_stack [[CAST_TMP]]
195+
// CHECK: br [[SUCCESS_BB]]
196+
// CHECK: } // end sil function 'array_downcast_takealways'
197+
sil @array_downcast_takealways : $@convention(thin) (@guaranteed NSArray) -> () {
198+
bb0(%0 : $NSArray):
199+
%4 = alloc_stack $NSArray
200+
retain_value %0 : $NSArray
201+
store %0 to %4 : $*NSArray
202+
%7 = alloc_stack $Array<String>
203+
checked_cast_addr_br take_always NSArray in %4 : $*NSArray to Array<String> in %7 : $*Array<String>, bb2, bb3
204+
205+
bb2:
206+
%9 = load %7 : $*Array<String>
207+
%10 = function_ref @guaranteed_swift_array_user : $@convention(thin) <τ_0_0> (@guaranteed Array<τ_0_0>) -> ()
208+
apply %10<String>(%9) : $@convention(thin) <τ_0_0> (@guaranteed Array<τ_0_0>) -> ()
209+
release_value %9 : $Array<String>
210+
dealloc_stack %7 : $*Array<String>
211+
dealloc_stack %4 : $*NSArray
212+
br bb4
213+
214+
bb3:
215+
dealloc_stack %7 : $*Array<String>
216+
dealloc_stack %4 : $*NSArray
217+
br bb4
218+
219+
bb4:
220+
%9999 = tuple()
221+
return %9999 : $()
222+
}

0 commit comments

Comments
 (0)