Skip to content

Commit 2519c34

Browse files
committed
Optimizer: fix simplification of unchecked_enum_data
When replacing an `enum` - `unchecked_enum_data` pair and the enum's operand is another non-trivial enum which is constructed with a trivial payload, and this happens in different basic blocks, we need to insert a compensating `destroy_value`. Fixes a verifier crash rdar://139787167
1 parent 91d8abb commit 2519c34

File tree

2 files changed

+49
-3
lines changed

2 files changed

+49
-3
lines changed

SwiftCompilerSources/Sources/Optimizer/Utilities/OptUtils.swift

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -576,9 +576,18 @@ extension SimplifyContext {
576576
let singleUse = preserveDebugInfo ? first.uses.singleUse : first.uses.ignoreDebugUses.singleUse
577577
let canEraseFirst = singleUse?.instruction == second
578578

579-
if !canEraseFirst && first.parentFunction.hasOwnership && replacement.ownership == .owned {
580-
// We cannot add more uses to `replacement` without inserting a copy.
581-
return
579+
if !canEraseFirst && first.parentFunction.hasOwnership {
580+
if replacement.ownership == .owned {
581+
// We cannot add more uses to `replacement` without inserting a copy.
582+
return
583+
}
584+
if first.ownership == .owned {
585+
// We have to insert a compensating destroy because we are deleting the second instruction but
586+
// not the first one. This can happen if the first instruction is an `enum` which constructs a
587+
// non-trivial enum from a trivial payload.
588+
let builder = Builder(before: second, self)
589+
builder.createDestroyValue(operand: first)
590+
}
582591
}
583592

584593
second.uses.replaceAll(with: replacement, self)

test/SILOptimizer/simplify_unchecked_enum_data.sil

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,13 @@ enum E {
1111
case B(String)
1212
}
1313

14+
enum E2 {
15+
case int(Int)
16+
case str(String)
17+
}
18+
19+
sil @useit : $@convention(thin) (@owned E2) -> ()
20+
1421
// CHECK-LABEL: sil @forward_enum_data
1522
// CHECK: return %0
1623
// CHECK: } // end sil function 'forward_enum_data'
@@ -84,3 +91,33 @@ bb0(%0 : @owned $String):
8491
return %3 : $String
8592
}
8693

94+
// CHECK-LABEL: sil [ossa] @trivial_replacement
95+
// CHECK: bb1({{.*}}:
96+
// CHECK-NEXT: end_borrow
97+
// CHECK-NEXT: destroy_value %2
98+
// CHECK: apply {{%[0-9]+}}(%1)
99+
// CHECK: } // end sil function 'trivial_replacement'
100+
sil [ossa] @trivial_replacement : $@convention(thin) (Int) -> () {
101+
bb0(%0 : $Int):
102+
%1 = enum $E2, #E2.int!enumelt, %0 : $Int
103+
%2 = enum $Optional<E2>, #Optional.some!enumelt, %1 : $E2, forwarding: @owned
104+
%3 = begin_borrow %2 : $Optional<E2>
105+
switch_enum %3 : $Optional<E2>, case #Optional.some!enumelt: bb1, case #Optional.none!enumelt: bb2
106+
107+
bb1(%5 : @guaranteed $E2):
108+
end_borrow %3 : $Optional<E2>
109+
%7 = unchecked_enum_data %2 : $Optional<E2>, #Optional.some!enumelt
110+
%8 = function_ref @useit : $@convention(thin) (@owned E2) -> ()
111+
%9 = apply %8(%7) : $@convention(thin) (@owned E2) -> ()
112+
br bb3
113+
114+
bb2:
115+
end_borrow %3 : $Optional<E2>
116+
destroy_value %2 : $Optional<E2>
117+
br bb3
118+
119+
bb3:
120+
%r = tuple ()
121+
return %r : $()
122+
}
123+

0 commit comments

Comments
 (0)