Skip to content

Commit 8438e16

Browse files
committed
Fix TempLValueOpt for init_enum_data_addr
TempLValueOpt eliminates copies from a temporary to destination and supports hoisting projections of the destination. An enum is fully initialized with the pair init_enum_data_addr and inject_enum_addr. Calling destroy_addr only before inject_enum_addr can cause a runtime crash. This optimization can eliminate copy_addr and hoist init_enum_data_addr such that enum is not fully initialized before it's use. Disable this case for now. Fixes rdar://145941433 To correctly do this optimization we have to find the corresponding inject_enum_addr and hoist it as well or ensure the source is not used until fully initialized by inject_enum_addr.
1 parent f6924ee commit 8438e16

File tree

3 files changed

+64
-34
lines changed

3 files changed

+64
-34
lines changed

lib/SILOptimizer/Transforms/TempLValueOpt.cpp

-2
Original file line numberDiff line numberDiff line change
@@ -113,8 +113,6 @@ void TempLValueOptPass::run() {
113113
}
114114

115115
static SingleValueInstruction *isMovableProjection(SILValue addr) {
116-
if (auto *enumData = dyn_cast<InitEnumDataAddrInst>(addr))
117-
return enumData;
118116
if (auto *existentialAddr = dyn_cast<InitExistentialAddrInst>(addr))
119117
return existentialAddr;
120118

test/SILOptimizer/templvalueopt.sil

+48-16
Original file line numberDiff line numberDiff line change
@@ -84,14 +84,14 @@ struct AddressOnlyPayload {
8484
//
8585
// CHECK-LABEL: sil @test_initialize_struct :
8686
// CHECK: bb0(%0 : $*TestStruct, %1 : $*Any, %2 : $Int):
87-
// CHECK-NEXT: [[E:%[0-9]+]] = struct_element_addr %0
88-
// CHECK-NEXT: [[LEFT:%[0-9]+]] = init_enum_data_addr [[E]]
89-
// CHECK-NEXT: [[A:%[0-9]+]] = struct_element_addr [[LEFT]]
90-
// CHECK-NEXT: copy_addr %1 to [init] [[A]]
91-
// CHECK-NEXT: [[I:%[0-9]+]] = struct_element_addr [[LEFT]]
92-
// CHECK-NEXT: store %2 to [[I]]
93-
// CHECK-NEXT: inject_enum_addr [[E]]
94-
// CHECK-NOT: copy_addr
87+
// HECK-NEXT: [[E:%[0-9]+]] = struct_element_addr %0
88+
// HECK-NEXT: [[LEFT:%[0-9]+]] = init_enum_data_addr [[E]]
89+
// HECK-NEXT: [[A:%[0-9]+]] = struct_element_addr [[LEFT]]
90+
// HECK-NEXT: copy_addr %1 to [init] [[A]]
91+
// HECK-NEXT: [[I:%[0-9]+]] = struct_element_addr [[LEFT]]
92+
// HECK-NEXT: store %2 to [[I]]
93+
// HECK-NEXT: inject_enum_addr [[E]]
94+
// HECK-NOT: copy_addr
9595
// CHECK: } // end sil function 'test_initialize_struct'
9696
sil @test_initialize_struct : $@convention(method) (@in Any, Int) -> @out TestStruct {
9797
bb0(%0 : $*TestStruct, %1 : $*Any, %2 : $Int):
@@ -165,14 +165,14 @@ struct StructWithEnum : Proto {
165165

166166
// CHECK-LABEL: sil @move_projections :
167167
// CHECK: bb0(%0 : $*any Proto, %1 : $*Any):
168-
// CHECK-NEXT: [[S:%[0-9]+]] = init_existential_addr %0 : $*any Proto, $StructWithEnum
169-
// CHECK-NEXT: [[E:%[0-9]+]] = struct_element_addr [[S]] : $*StructWithEnum, #StructWithEnum.e
170-
// CHECK-NEXT: [[ENUMA:%[0-9]+]] = init_enum_data_addr [[E]] : $*Enum, #Enum.A!enumelt
171-
// CHECK-NEXT: [[OPTIONAL:%[0-9]+]] = init_enum_data_addr [[ENUMA]] : $*Optional<Any>, #Optional.some!enumelt
172-
// CHECK-NEXT: copy_addr [take] %1 to [init] [[OPTIONAL]] : $*Any
173-
// CHECK-NEXT: inject_enum_addr [[ENUMA]] : $*Optional<Any>, #Optional.some!enumelt
174-
// CHECK-NEXT: inject_enum_addr [[E]] : $*Enum, #Enum.A!enumelt
175-
// CHECK-NOT: copy_addr
168+
// HECK-NEXT: [[S:%[0-9]+]] = init_existential_addr %0 : $*any Proto, $StructWithEnum
169+
// HECK-NEXT: [[E:%[0-9]+]] = struct_element_addr [[S]] : $*StructWithEnum, #StructWithEnum.e
170+
// HECK-NEXT: [[ENUMA:%[0-9]+]] = init_enum_data_addr [[E]] : $*Enum, #Enum.A!enumelt
171+
// HECK-NEXT: [[OPTIONAL:%[0-9]+]] = init_enum_data_addr [[ENUMA]] : $*Optional<Any>, #Optional.some!enumelt
172+
// HECK-NEXT: copy_addr [take] %1 to [init] [[OPTIONAL]] : $*Any
173+
// HECK-NEXT: inject_enum_addr [[ENUMA]] : $*Optional<Any>, #Optional.some!enumelt
174+
// HECK-NEXT: inject_enum_addr [[E]] : $*Enum, #Enum.A!enumelt
175+
// HECK-NOT: copy_addr
176176
// CHECK: } // end sil function 'move_projections'
177177
sil @move_projections : $@convention(thin) (@in Any) -> @out Proto {
178178
bb0(%0 : $*Proto, %1 : $*Any):
@@ -278,3 +278,35 @@ bb0(%ret_addr : $*T):
278278
return %15 : $()
279279
}
280280

281+
class Klass {
282+
init()
283+
}
284+
285+
enum FakeOptional {
286+
case none
287+
case some(Klass)
288+
}
289+
290+
sil @initfn : $@convention(thin) () -> @out Klass
291+
292+
// CHECK-LABEL: sil @test_enum
293+
// CHECK: alloc_stack
294+
// CHECK: alloc_stack
295+
// CHECK-LABEL: } // end sil function 'test_enum'
296+
sil @test_enum : $@convention(thin) () -> @out FakeOptional {
297+
bb0(%0 : $*FakeOptional):
298+
%1 = alloc_stack [lexical] [var_decl] $Klass
299+
%2 = function_ref @initfn : $@convention(thin) () -> @out Klass
300+
%3 = apply %2(%1) : $@convention(thin) () -> @out Klass
301+
%4 = alloc_stack $Klass
302+
%5 = apply %2(%4) : $@convention(thin) () -> @out Klass
303+
destroy_addr %1
304+
copy_addr [take] %4 to [init] %1
305+
dealloc_stack %4
306+
%9 = init_enum_data_addr %0, #FakeOptional.some!enumelt
307+
copy_addr [take] %1 to [init] %9
308+
inject_enum_addr %0, #FakeOptional.some!enumelt
309+
dealloc_stack %1
310+
%13 = tuple ()
311+
return %13
312+
}

test/SILOptimizer/templvalueopt_ossa.sil

+16-16
Original file line numberDiff line numberDiff line change
@@ -84,14 +84,14 @@ struct AddressOnlyPayload {
8484
//
8585
// CHECK-LABEL: sil [ossa] @test_initialize_struct :
8686
// CHECK: bb0(%0 : $*TestStruct, %1 : $*Any, %2 : $Int):
87-
// CHECK-NEXT: [[E:%[0-9]+]] = struct_element_addr %0
88-
// CHECK-NEXT: [[LEFT:%[0-9]+]] = init_enum_data_addr [[E]]
89-
// CHECK-NEXT: [[A:%[0-9]+]] = struct_element_addr [[LEFT]]
90-
// CHECK-NEXT: copy_addr [take] %1 to [init] [[A]]
91-
// CHECK-NEXT: [[I:%[0-9]+]] = struct_element_addr [[LEFT]]
92-
// CHECK-NEXT: store %2 to [trivial] [[I]]
93-
// CHECK-NEXT: inject_enum_addr [[E]]
94-
// CHECK-NOT: copy_addr
87+
// HECK-NEXT: [[E:%[0-9]+]] = struct_element_addr %0
88+
// HECK-NEXT: [[LEFT:%[0-9]+]] = init_enum_data_addr [[E]]
89+
// HECK-NEXT: [[A:%[0-9]+]] = struct_element_addr [[LEFT]]
90+
// HECK-NEXT: copy_addr [take] %1 to [init] [[A]]
91+
// HECK-NEXT: [[I:%[0-9]+]] = struct_element_addr [[LEFT]]
92+
// HECK-NEXT: store %2 to [trivial] [[I]]
93+
// HECK-NEXT: inject_enum_addr [[E]]
94+
// HECK-NOT: copy_addr
9595
// CHECK: } // end sil function 'test_initialize_struct'
9696
sil [ossa] @test_initialize_struct : $@convention(method) (@in Any, Int) -> @out TestStruct {
9797
bb0(%0 : $*TestStruct, %1 : $*Any, %2 : $Int):
@@ -165,14 +165,14 @@ struct StructWithEnum : Proto {
165165

166166
// CHECK-LABEL: sil [ossa] @move_projections :
167167
// CHECK: bb0(%0 : $*any Proto, %1 : $*Any):
168-
// CHECK-NEXT: [[S:%[0-9]+]] = init_existential_addr %0 : $*any Proto, $StructWithEnum
169-
// CHECK-NEXT: [[E:%[0-9]+]] = struct_element_addr [[S]] : $*StructWithEnum, #StructWithEnum.e
170-
// CHECK-NEXT: [[ENUMA:%[0-9]+]] = init_enum_data_addr [[E]] : $*Enum, #Enum.A!enumelt
171-
// CHECK-NEXT: [[OPTIONAL:%[0-9]+]] = init_enum_data_addr [[ENUMA]] : $*Optional<Any>, #Optional.some!enumelt
172-
// CHECK-NEXT: copy_addr [take] %1 to [init] [[OPTIONAL]] : $*Any
173-
// CHECK-NEXT: inject_enum_addr [[ENUMA]] : $*Optional<Any>, #Optional.some!enumelt
174-
// CHECK-NEXT: inject_enum_addr [[E]] : $*Enum, #Enum.A!enumelt
175-
// CHECK-NOT: copy_addr
168+
// HECK-NEXT: [[S:%[0-9]+]] = init_existential_addr %0 : $*any Proto, $StructWithEnum
169+
// HECK-NEXT: [[E:%[0-9]+]] = struct_element_addr [[S]] : $*StructWithEnum, #StructWithEnum.e
170+
// HECK-NEXT: [[ENUMA:%[0-9]+]] = init_enum_data_addr [[E]] : $*Enum, #Enum.A!enumelt
171+
// HECK-NEXT: [[OPTIONAL:%[0-9]+]] = init_enum_data_addr [[ENUMA]] : $*Optional<Any>, #Optional.some!enumelt
172+
// HECK-NEXT: copy_addr [take] %1 to [init] [[OPTIONAL]] : $*Any
173+
// HECK-NEXT: inject_enum_addr [[ENUMA]] : $*Optional<Any>, #Optional.some!enumelt
174+
// HECK-NEXT: inject_enum_addr [[E]] : $*Enum, #Enum.A!enumelt
175+
// HECK-NOT: copy_addr
176176
// CHECK: } // end sil function 'move_projections'
177177
sil [ossa] @move_projections : $@convention(thin) (@in Any) -> @out Proto {
178178
bb0(%0 : $*Proto, %1 : $*Any):

0 commit comments

Comments
 (0)