Skip to content

Commit 9c46b2a

Browse files
committed
Fix block merging after inlining to help avoid quadratic inlining.
A recent SILCloner rewrite removed a special case hack for single basic block callee functions: commit c6865c0 Merge: 76e6c41 9e440d1 Author: Andrew Trick <[email protected]> Date: Thu Oct 11 14:23:32 2018 Merge pull request #19786 from atrick/silcloner-cleanup SILCloner and SILInliner rewrite. Instead, the new inliner simply merges trivial unconditional branches after inlining the return block. This way, the CFG is always in canonical state after inlining. This is more robust, and avoids interfering with subsequent SIL passes when non-single-block callees are inlined. The problem is that inlining a series of calls within a large block could result in interleaved block splitting and merging operations, which is quadratic in the block size. This showed up when inlining the tens of thousands of array subscript calls emitted for a large array initialization. The first half of the fix is to simply defer block merging until all calls are inlined. We can't expect SimplifyCFG to run immediately after inlining, nor would we want to do that, *especially* for mandatory inlining. This fix instead exposes block merging as a trivial utility. Note: by eliminating some unconditional branches, this change could reduce the number of debug locations emitted. This does not fundamentally change any debug information guarantee, and I was unable to observe any behavior difference in the debugger.
1 parent 720153a commit 9c46b2a

File tree

12 files changed

+89
-204
lines changed

12 files changed

+89
-204
lines changed

include/swift/SILOptimizer/Utils/CFG.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,16 @@ bool splitAllCondBrCriticalEdgesWithNonTrivialArgs(SILFunction &Fn,
127127
bool mergeBasicBlockWithSuccessor(SILBasicBlock *BB, DominanceInfo *DT,
128128
SILLoopInfo *LI);
129129

130+
/// Merge basic blocks in the given function by eliminating all unconditional
131+
/// branches to single-predecessor branch targets.
132+
///
133+
/// During optimization, SimplifyCFG also handles this, but this is a basic
134+
/// canonicalization after any pass that splits blocks, such as inlining. This
135+
/// is not done on-the-fly after splitting blocks because merging is linear in
136+
/// the number of instructions, so interleaved merging and splitting is
137+
/// quadratic.
138+
bool mergeBasicBlocks(SILFunction *F);
139+
130140
/// Given a list of \p UserBlocks and a list of \p DefBlocks, find a set of
131141
/// blocks that together with \p UserBlocks joint-postdominate \p
132142
/// DefBlocks. This is in a sense finding a set of blocks that "complete" \p

lib/SILOptimizer/Mandatory/MandatoryInlining.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -680,6 +680,9 @@ class MandatoryInlining : public SILModuleTransform {
680680
runOnFunctionRecursively(FuncBuilder, &F,
681681
FullApplySite(), FullyInlinedSet, SetFactory,
682682
SetFactory.getEmptySet(), CHA);
683+
// The inliner splits blocks at call sites. Re-merge trivial branches
684+
// to reestablish a canonical CFG.
685+
mergeBasicBlocks(&F);
683686
}
684687

685688
if (!ShouldCleanup)

lib/SILOptimizer/Transforms/PerformanceInliner.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include "swift/SILOptimizer/Analysis/SideEffectAnalysis.h"
1818
#include "swift/SILOptimizer/PassManager/Passes.h"
1919
#include "swift/SILOptimizer/PassManager/Transforms.h"
20+
#include "swift/SILOptimizer/Utils/CFG.h"
2021
#include "swift/SILOptimizer/Utils/Devirtualize.h"
2122
#include "swift/SILOptimizer/Utils/Generics.h"
2223
#include "swift/SILOptimizer/Utils/PerformanceInlinerUtils.h"
@@ -903,6 +904,9 @@ bool SILPerformanceInliner::inlineCallsIntoFunction(SILFunction *Caller) {
903904
Inliner.inlineFunction(Callee, AI, Args);
904905
NumFunctionsInlined++;
905906
}
907+
// The inliner splits blocks at call sites. Re-merge trivial branches to
908+
// reestablish a canonical CFG.
909+
mergeBasicBlocks(Caller);
906910
return true;
907911
}
908912

lib/SILOptimizer/Utils/CFG.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -493,6 +493,19 @@ bool swift::mergeBasicBlockWithSuccessor(SILBasicBlock *BB, DominanceInfo *DT,
493493
return true;
494494
}
495495

496+
bool swift::mergeBasicBlocks(SILFunction *F) {
497+
bool merged = false;
498+
for (auto BBIter = F->begin(); BBIter != F->end();) {
499+
if (mergeBasicBlockWithSuccessor(&*BBIter, /*DT*/ nullptr, /*LI*/ nullptr)) {
500+
merged = true;
501+
// Continue to merge the current block without advancing.
502+
continue;
503+
}
504+
++BBIter;
505+
}
506+
return merged;
507+
}
508+
496509
/// Splits the critical edges between from and to. This code assumes there is
497510
/// only one edge between the two basic blocks.
498511
SILBasicBlock *swift::splitIfCriticalEdge(SILBasicBlock *From,

lib/SILOptimizer/Utils/SILInliner.cpp

Lines changed: 6 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -512,23 +512,12 @@ SILInlineCloner::cloneInline(ArrayRef<SILValue> AppliedArgs) {
512512
// NextIter is initialized during `fixUp`.
513513
cloneFunctionBody(getCalleeFunction(), callerBB, entryArgs);
514514

515-
// As a trivial optimization, if the apply block falls through, merge it. The
516-
// fall through is likely the ReturnToBB, but that is not guaranteed.
517-
if (auto *BI = dyn_cast<BranchInst>(callerBB->getTerminator())) {
518-
// FIXME: should be an assert once critical edges are fixed.
519-
// assert(BI->getDestBB()->getSinglePredecessorBlock() &&
520-
// "the return block cannot have other predecessors.");
521-
if (BI->getDestBB()->getSinglePredecessorBlock()) {
522-
SILInstruction *firstInlinedInst = &*NextIter;
523-
if (firstInlinedInst == BI)
524-
firstInlinedInst = &BI->getDestBB()->front();
525-
526-
mergeBasicBlockWithSuccessor(BI->getParent(), /*DT*/ nullptr,
527-
/*LI*/ nullptr);
528-
NextIter = firstInlinedInst->getIterator();
529-
ReturnToBB = nullptr;
530-
}
531-
}
515+
// For non-throwing applies, the inlined body now unconditionally branches to
516+
// the returned-to-code, which was previously part of the call site's basic
517+
// block. We could trivially merge these blocks now, however, this would be
518+
// quadratic: O(num-calls-in-block * num-instructions-in-block). On the other
519+
// hand, leaving the block's unmerged is non-canonical. Instead, wait until
520+
// all calls within a block are inlined, then merge blocks.
532521
return NextIter;
533522
}
534523

test/DebugInfo/returnlocation.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -184,10 +184,10 @@ public class Class1 {
184184
public required init?() {
185185
print("hello")
186186
// CHECK_INIT: call {{.*}}@"$ss5print_9separator10terminatoryypd_S2StF"{{.*}}, !dbg [[printLoc:![0-9]+]]
187-
// CHECK_INIT: br label {{.*}}, !dbg [[retnLoc:![0-9]+]]
187+
// CHECK_INIT: ret i64 0, !dbg [[retnLoc:![0-9]+]]
188188

189-
// CHECK_INIT: [[printLoc]] = !DILocation(line: [[@LINE-4]]
190-
// CHECK_INIT: [[retnLoc]] = !DILocation(line: [[@LINE+1]]
189+
// CHECK_INIT: [[retnLoc]] = !DILocation(line: 0
190+
// CHECK_INIT: [[printLoc]] = !DILocation(line: [[@LINE-5]]
191191
return nil
192192
}
193193
}

test/IRGen/nondominant.sil

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,9 @@ bb1:
1616
br bb2
1717
}
1818
// CHECK: define{{( dllexport)?}}{{( protected)?}} swiftcc i8 @test0()
19-
// CHECK: br
2019
// CHECK-NOT: }
2120
// CHECK: ret i8 7
2221
// CHECK-NOT: }
23-
// CHECK: br
2422
// CHECK: }
2523

2624
// Just don't crash on this one.

test/SILOptimizer/definite_init_failable_initializers.swift

Lines changed: 16 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -38,12 +38,8 @@ struct FailableStruct {
3838
// CHECK-LABEL: sil hidden @$s35definite_init_failable_initializers14FailableStructV24failBeforeInitializationACSgyt_tcfC
3939
// CHECK: bb0(%0 : $@thin FailableStruct.Type):
4040
// CHECK: [[SELF_BOX:%.*]] = alloc_stack $FailableStruct
41-
// CHECK: br bb1
42-
// CHECK: bb1:
43-
// CHECK-NEXT: dealloc_stack [[SELF_BOX]]
41+
// CHECK: dealloc_stack [[SELF_BOX]]
4442
// CHECK-NEXT: [[SELF:%.*]] = enum $Optional<FailableStruct>, #Optional.none!enumelt
45-
// CHECK-NEXT: br bb2
46-
// CHECK: bb2:
4743
// CHECK-NEXT: return [[SELF]]
4844
init?(failBeforeInitialization: ()) {
4945
return nil
@@ -57,14 +53,10 @@ struct FailableStruct {
5753
// CHECK-NEXT: [[X_ADDR:%.*]] = struct_element_addr [[WRITE]]
5854
// CHECK-NEXT: store [[CANARY]] to [[X_ADDR]]
5955
// CHECK-NEXT: end_access [[WRITE]] : $*FailableStruct
60-
// CHECK-NEXT: br bb1
61-
// CHECK: bb1:
6256
// CHECK-NEXT: [[X_ADDR:%.*]] = struct_element_addr [[SELF_BOX]]
6357
// CHECK-NEXT: destroy_addr [[X_ADDR]]
6458
// CHECK-NEXT: dealloc_stack [[SELF_BOX]]
6559
// CHECK-NEXT: [[SELF:%.*]] = enum $Optional<FailableStruct>, #Optional.none!enumelt
66-
// CHECK-NEXT: br bb2
67-
// CHECK: bb2:
6860
// CHECK-NEXT: return [[SELF]]
6961
init?(failAfterPartialInitialization: ()) {
7062
x = Canary()
@@ -84,13 +76,9 @@ struct FailableStruct {
8476
// CHECK-NEXT: [[Y_ADDR:%.*]] = struct_element_addr [[WRITE]]
8577
// CHECK-NEXT: store [[CANARY2]] to [[Y_ADDR]]
8678
// CHECK-NEXT: end_access [[WRITE]] : $*FailableStruct
87-
// CHECK-NEXT: br bb1
88-
// CHECK: bb1:
8979
// CHECK-NEXT: destroy_addr [[SELF_BOX]]
9080
// CHECK-NEXT: dealloc_stack [[SELF_BOX]]
9181
// CHECK-NEXT: [[NEW_SELF:%.*]] = enum $Optional<FailableStruct>, #Optional.none!enumelt
92-
// CHECK-NEXT: br bb2
93-
// CHECK: bb2:
9482
// CHECK-NEXT: return [[NEW_SELF]]
9583
init?(failAfterFullInitialization: ()) {
9684
x = Canary()
@@ -105,13 +93,9 @@ struct FailableStruct {
10593
// CHECK-NEXT: [[WRITE:%.*]] = begin_access [modify] [static] [[SELF_BOX]] : $*FailableStruct
10694
// CHECK-NEXT: store [[CANARY]] to [[WRITE]]
10795
// CHECK-NEXT: end_access [[WRITE]] : $*FailableStruct
108-
// CHECK-NEXT: br bb1
109-
// CHECK: bb1:
11096
// CHECK-NEXT: destroy_addr [[SELF_BOX]]
11197
// CHECK-NEXT: dealloc_stack [[SELF_BOX]]
11298
// CHECK-NEXT: [[SELF_VALUE:%.*]] = enum $Optional<FailableStruct>, #Optional.none!enumelt
113-
// CHECK-NEXT: br bb2
114-
// CHECK: bb2:
11599
// CHECK-NEXT: return [[SELF_VALUE]]
116100
init?(failAfterWholeObjectInitializationByAssignment: ()) {
117101
self = FailableStruct(noFail: ())
@@ -124,13 +108,9 @@ struct FailableStruct {
124108
// CHECK: [[INIT_FN:%.*]] = function_ref @$s35definite_init_failable_initializers14FailableStructV6noFailACyt_tcfC
125109
// CHECK-NEXT: [[NEW_SELF:%.*]] = apply [[INIT_FN]](%0)
126110
// CHECK-NEXT: store [[NEW_SELF]] to [[SELF_BOX]]
127-
// CHECK-NEXT: br bb1
128-
// CHECK: bb1:
129111
// CHECK-NEXT: destroy_addr [[SELF_BOX]]
130112
// CHECK-NEXT: dealloc_stack [[SELF_BOX]]
131113
// CHECK-NEXT: [[NEW_SELF:%.*]] = enum $Optional<FailableStruct>, #Optional.none!enumelt
132-
// CHECK-NEXT: br bb2
133-
// CHECK: bb2:
134114
// CHECK-NEXT: return [[NEW_SELF]]
135115
init?(failAfterWholeObjectInitializationByDelegation: ()) {
136116
self.init(noFail: ())
@@ -147,7 +127,9 @@ struct FailableStruct {
147127
//
148128
// CHECK: [[FAIL_BB]]:
149129
// CHECK-NEXT: release_value [[SELF_OPTIONAL]]
150-
// CHECK-NEXT: br [[FAIL_EPILOG_BB:bb[0-9]+]]
130+
// CHECK-NEXT: dealloc_stack [[SELF_BOX]]
131+
// CHECK-NEXT: [[NEW_SELF:%.*]] = enum $Optional<FailableStruct>, #Optional.none!enumelt
132+
// CHECK-NEXT: br [[EPILOG_BB:bb[0-9]+]]([[NEW_SELF]] : $Optional<FailableStruct>)
151133
//
152134
// CHECK: [[SUCC_BB]]:
153135
// CHECK-NEXT: [[SELF_VALUE:%.*]] = unchecked_enum_data [[SELF_OPTIONAL]]
@@ -158,11 +140,6 @@ struct FailableStruct {
158140
// CHECK-NEXT: dealloc_stack [[SELF_BOX]]
159141
// CHECK-NEXT: br [[EPILOG_BB:bb[0-9]+]]([[NEW_SELF]] : $Optional<FailableStruct>)
160142
//
161-
// CHECK: [[FAIL_EPILOG_BB]]:
162-
// CHECK-NEXT: dealloc_stack [[SELF_BOX]]
163-
// CHECK-NEXT: [[NEW_SELF:%.*]] = enum $Optional<FailableStruct>, #Optional.none!enumelt
164-
// CHECK-NEXT: br [[EPILOG_BB]]([[NEW_SELF]] : $Optional<FailableStruct>)
165-
//
166143
// CHECK: [[EPILOG_BB]]([[NEW_SELF:%.*]] : $Optional<FailableStruct>)
167144
// CHECK-NEXT: return [[NEW_SELF]]
168145
// Optional to optional
@@ -212,12 +189,8 @@ struct FailableAddrOnlyStruct<T : Pachyderm> {
212189
// CHECK-LABEL: sil hidden @$s35definite_init_failable_initializers22FailableAddrOnlyStructV{{[_0-9a-zA-Z]*}}failBeforeInitialization{{.*}}tcfC
213190
// CHECK: bb0(%0 : $*Optional<FailableAddrOnlyStruct<T>>, %1 : $@thin FailableAddrOnlyStruct<T>.Type):
214191
// CHECK: [[SELF_BOX:%.*]] = alloc_stack $FailableAddrOnlyStruct<T>
215-
// CHECK: br bb1
216-
// CHECK: bb1:
217-
// CHECK-NEXT: dealloc_stack [[SELF_BOX]]
192+
// CHECK: dealloc_stack [[SELF_BOX]]
218193
// CHECK-NEXT: inject_enum_addr %0
219-
// CHECK-NEXT: br bb2
220-
// CHECK: bb2:
221194
// CHECK: return
222195
init?(failBeforeInitialization: ()) {
223196
return nil
@@ -235,14 +208,10 @@ struct FailableAddrOnlyStruct<T : Pachyderm> {
235208
// CHECK-NEXT: copy_addr [take] [[X_BOX]] to [initialization] [[X_ADDR]]
236209
// CHECK-NEXT: end_access [[WRITE]] : $*FailableAddrOnlyStruct<T>
237210
// CHECK-NEXT: dealloc_stack [[X_BOX]]
238-
// CHECK-NEXT: br bb1
239-
// CHECK: bb1:
240211
// CHECK-NEXT: [[X_ADDR:%.*]] = struct_element_addr [[SELF_BOX]]
241212
// CHECK-NEXT: destroy_addr [[X_ADDR]]
242213
// CHECK-NEXT: dealloc_stack [[SELF_BOX]]
243214
// CHECK-NEXT: inject_enum_addr %0
244-
// CHECK-NEXT: br bb2
245-
// CHECK: bb2:
246215
// CHECK: return
247216
init?(failAfterPartialInitialization: ()) {
248217
x = T()
@@ -270,13 +239,9 @@ struct FailableAddrOnlyStruct<T : Pachyderm> {
270239
// CHECK-NEXT: copy_addr [take] [[Y_BOX]] to [initialization] [[Y_ADDR]]
271240
// CHECK-NEXT: end_access [[WRITE]] : $*FailableAddrOnlyStruct<T>
272241
// CHECK-NEXT: dealloc_stack [[Y_BOX]]
273-
// CHECK-NEXT: br bb1
274-
// CHECK: bb1:
275242
// CHECK-NEXT: destroy_addr [[SELF_BOX]]
276243
// CHECK-NEXT: dealloc_stack [[SELF_BOX]]
277244
// CHECK-NEXT: inject_enum_addr %0
278-
// CHECK-NEXT: br bb2
279-
// CHECK: bb2:
280245
// CHECK: return
281246
init?(failAfterFullInitialization: ()) {
282247
x = T()
@@ -548,8 +513,10 @@ struct ThrowStruct {
548513
// CHECK-NEXT: cond_br [[COND]], [[SUCC_BB:bb[0-9]+]], [[FAIL_BB:bb[0-9]+]]
549514
//
550515
// CHECK: [[FAIL_BB]]:
551-
// CHECK-NEXT: release_value [[SELF_OPTIONAL]]
552-
// CHECK-NEXT: br [[FAIL_EPILOG_BB:bb[0-9]+]]
516+
// CHECK: release_value [[SELF_OPTIONAL]]
517+
// CHECK-NEXT: dealloc_stack [[SELF_BOX]]
518+
// CHECK-NEXT: [[NEW_SELF:%.*]] = enum $Optional<ThrowStruct>, #Optional.none!enumelt
519+
// CHECK-NEXT: br [[EPILOG_BB:bb[0-9]+]]([[NEW_SELF]] : $Optional<ThrowStruct>)
553520
//
554521
// CHECK: [[SUCC_BB]]:
555522
// CHECK-NEXT: [[SELF_VALUE:%.*]] = unchecked_enum_data [[SELF_OPTIONAL]]
@@ -560,21 +527,13 @@ struct ThrowStruct {
560527
// CHECK-NEXT: dealloc_stack [[SELF_BOX]]
561528
// CHECK-NEXT: br [[EPILOG_BB:bb[0-9]+]]([[NEW_SELF]] : $Optional<ThrowStruct>)
562529
//
563-
// CHECK: [[FAIL_EPILOG_BB]]:
564-
// CHECK-NEXT: dealloc_stack [[SELF_BOX]]
565-
// CHECK-NEXT: [[NEW_SELF:%.*]] = enum $Optional<ThrowStruct>, #Optional.none!enumelt
566-
// CHECK-NEXT: br [[EPILOG_BB]]([[NEW_SELF]] : $Optional<ThrowStruct>)
567-
//
568530
// CHECK: [[EPILOG_BB]]([[NEW_SELF:%.*]] : $Optional<ThrowStruct>):
569531
// CHECK-NEXT: return [[NEW_SELF]] : $Optional<ThrowStruct>
570532
//
571-
// CHECK: [[TRY_APPLY_FAIL_TRAMPOLINE_BB:bb[0-9]+]]:
533+
// CHECK: [[TRY_APPLY_FAIL_BB]]([[ERROR]] : $Error):
572534
// CHECK-NEXT: strong_release [[ERROR:%.*]] : $Error
573535
// CHECK-NEXT: [[NEW_SELF:%.*]] = enum $Optional<ThrowStruct>, #Optional.none!enumelt
574536
// CHECK-NEXT: br [[TRY_APPLY_CONT]]([[NEW_SELF]] : $Optional<ThrowStruct>)
575-
//
576-
// CHECK: [[TRY_APPLY_FAIL_BB]]([[ERROR]] : $Error):
577-
// CHECK-NEXT: br [[TRY_APPLY_FAIL_TRAMPOLINE_BB]]
578537
init?(throwsToOptional: Int) {
579538
try? self.init(failDuringDelegation: throwsToOptional)
580539
}
@@ -767,12 +726,8 @@ class FailableBaseClass {
767726
// CHECK-NEXT: [[WRITE:%.*]] = begin_access [modify] [dynamic] [[MEMBER_ADDR]] : $*Canary
768727
// CHECK-NEXT: store [[CANARY]] to [[WRITE]]
769728
// CHECK-NEXT: end_access [[WRITE]] : $*Canary
770-
// CHECK-NEXT: br bb1
771-
// CHECK: bb1:
772729
// CHECK-NEXT: strong_release %0
773730
// CHECK-NEXT: [[NEW_SELF:%.*]] = enum $Optional<FailableBaseClass>, #Optional.none!enumelt
774-
// CHECK-NEXT: br bb2
775-
// CHECK: bb2:
776731
// CHECK-NEXT: return [[NEW_SELF]]
777732
init?(failAfterFullInitialization: ()) {
778733
member = Canary()
@@ -782,12 +737,8 @@ class FailableBaseClass {
782737
// CHECK-LABEL: sil hidden @$s35definite_init_failable_initializers17FailableBaseClassC20failBeforeDelegationACSgyt_tcfC
783738
// CHECK: bb0(%0 : $@thick FailableBaseClass.Type):
784739
// CHECK-NEXT: [[SELF_BOX:%.*]] = alloc_stack $FailableBaseClass
785-
// CHECK: br bb1
786-
// CHECK: bb1:
787-
// CHECK-NEXT: dealloc_stack [[SELF_BOX]]
740+
// CHECK: dealloc_stack [[SELF_BOX]]
788741
// CHECK-NEXT: [[RESULT:%.*]] = enum $Optional<FailableBaseClass>, #Optional.none!enumelt
789-
// CHECK-NEXT: br bb2
790-
// CHECK: bb2:
791742
// CHECK-NEXT: return [[RESULT]]
792743
convenience init?(failBeforeDelegation: ()) {
793744
return nil
@@ -799,13 +750,9 @@ class FailableBaseClass {
799750
// CHECK: [[INIT_FN:%.*]] = class_method %0
800751
// CHECK-NEXT: [[NEW_SELF:%.*]] = apply [[INIT_FN]](%0)
801752
// CHECK-NEXT: store [[NEW_SELF]] to [[SELF_BOX]]
802-
// CHECK-NEXT: br bb1
803-
// CHECK: bb1:
804753
// CHECK-NEXT: destroy_addr [[SELF_BOX]]
805754
// CHECK-NEXT: dealloc_stack [[SELF_BOX]]
806755
// CHECK-NEXT: [[RESULT:%.*]] = enum $Optional<FailableBaseClass>, #Optional.none!enumelt
807-
// CHECK-NEXT: br bb2
808-
// CHECK: bb2:
809756
// CHECK-NEXT: return [[RESULT]]
810757
convenience init?(failAfterDelegation: ()) {
811758
self.init(noFail: ())
@@ -834,8 +781,8 @@ class FailableBaseClass {
834781
// CHECK-NEXT: br [[EPILOG_BB:bb[0-9]+]]([[NEW_SELF]] : $Optional<FailableBaseClass>)
835782
//
836783
// CHECK: [[FAIL_TRAMPOLINE_BB]]:
837-
// CHECK-NEXT: dealloc_stack [[SELF_BOX]]
838-
// CHECK-NEXT: [[NEW_SELF:%.*]] = enum $Optional<FailableBaseClass>, #Optional.none!enumelt
784+
// CHECK: dealloc_stack [[SELF_BOX]]
785+
// CHECK: [[NEW_SELF:%.*]] = enum $Optional<FailableBaseClass>, #Optional.none!enumelt
839786
// CHECK-NEXT: br [[EPILOG_BB]]([[NEW_SELF]] : $Optional<FailableBaseClass>)
840787
//
841788
// CHECK: [[EPILOG_BB]]([[NEW_SELF:%.*]] : $Optional<FailableBaseClass>):
@@ -875,14 +822,10 @@ class FailableDerivedClass : FailableBaseClass {
875822
// CHECK: bb0(%0 : $FailableDerivedClass):
876823
// CHECK: [[SELF_BOX:%.*]] = alloc_stack $FailableDerivedClass
877824
// CHECK: store %0 to [[SELF_BOX]]
878-
// CHECK-NEXT: br bb1
879-
// CHECK: bb1:
880825
// CHECK-NEXT: [[METATYPE:%.*]] = metatype $@thick FailableDerivedClass.Type
881826
// CHECK-NEXT: dealloc_partial_ref %0 : $FailableDerivedClass, [[METATYPE]] : $@thick FailableDerivedClass.Type
882827
// CHECK-NEXT: dealloc_stack [[SELF_BOX]]
883828
// CHECK-NEXT: [[RESULT:%.*]] = enum $Optional<FailableDerivedClass>, #Optional.none!enumelt
884-
// CHECK-NEXT: br bb2
885-
// CHECK: bb2:
886829
// CHECK-NEXT: return [[RESULT]]
887830
init?(derivedFailBeforeDelegation: ()) {
888831
return nil
@@ -905,7 +848,9 @@ class FailableDerivedClass : FailableBaseClass {
905848
//
906849
// CHECK: [[FAIL_BB]]:
907850
// CHECK-NEXT: release_value [[SELF_OPTIONAL]]
908-
// CHECK-NEXT: br [[FAIL_TRAMPOLINE_BB:bb[0-9]+]]
851+
// CHECK: dealloc_stack [[SELF_BOX]]
852+
// CHECK-NEXT: [[NEW_SELF:%.*]] = enum $Optional<FailableDerivedClass>, #Optional.none!enumelt
853+
// CHECK-NEXT: br [[EPILOG_BB]]([[NEW_SELF]] : $Optional<FailableDerivedClass>)
909854
//
910855
// CHECK: [[SUCC_BB]]:
911856
// CHECK-NEXT: [[BASE_SELF_VALUE:%.*]] = unchecked_enum_data [[SELF_OPTIONAL]]
@@ -917,11 +862,6 @@ class FailableDerivedClass : FailableBaseClass {
917862
// CHECK-NEXT: dealloc_stack [[SELF_BOX]]
918863
// CHECK-NEXT: br [[EPILOG_BB:bb[0-9]+]]([[NEW_SELF]] : $Optional<FailableDerivedClass>)
919864
//
920-
// CHECK: [[FAIL_TRAMPOLINE_BB]]:
921-
// CHECK-NEXT: dealloc_stack [[SELF_BOX]]
922-
// CHECK-NEXT: [[NEW_SELF:%.*]] = enum $Optional<FailableDerivedClass>, #Optional.none!enumelt
923-
// CHECK-NEXT: br [[EPILOG_BB]]([[NEW_SELF]] : $Optional<FailableDerivedClass>)
924-
//
925865
// CHECK: [[EPILOG_BB]]([[NEW_SELF:%.*]] : $Optional<FailableDerivedClass>):
926866
// CHECK-NEXT: return [[NEW_SELF]] : $Optional<FailableDerivedClass>
927867
init?(derivedFailDuringDelegation: ()) {

0 commit comments

Comments
 (0)