Files
swift-mirror/test/SILOptimizer/simplify_alloc_stack.sil
Adrian Prantl 99cf35cdce [SILOptimzer] Fix a crash caused by SILCombine mishandling inlined variables
This showed up on and off again on the source-compatibility testsuite project hummingbird.

The gist of the problem is that transformations may not rewrite the
type of an inlined instance of a variable without also createing a
deep copy of the inlined function with a different name (and e.g., a
specialization suffix). Otherwise the modified inlined variable will
cause an inconsistency when later compiler passes try to create the
abstract declaration of that inlined function as there would be
conflicting declarations for that variable.

Since SILDebugScope isn't yet available in the SwiftCompilerSources
this fix just drop these variables, but it would be absolutely
possible to preserve them by using the same mechanism that SILCloner
uses to create a deep copy of the inlined function scopes.

rdar://163167975
2025-11-07 17:06:33 -08:00

440 lines
14 KiB
Plaintext

// RUN: %target-sil-opt %s -simplification -simplify-instruction=alloc_stack | %FileCheck %s
import Swift
import Builtin
public class C {}
public struct S {}
protocol P {
}
protocol Q {
associatedtype A
}
public class C2: P {}
public struct T: P {
let c: C
let s: S
struct A {
var y: String
}
}
public struct U: Q {
let s: String
struct A {
var y: String
}
}
public struct T1: P {
let x: Int
}
public struct T2: P {
let x: Int
}
enum MP {
case A(S)
case B(S)
}
public enum X {
case none
case some(T)
}
sil [ossa] @take_s : $@convention(thin) (@in S) -> ()
sil [ossa] @take_t : $@convention(thin) (@in T) -> ()
sil [ossa] @use_mp : $@convention(thin) (@in_guaranteed MP) -> ()
sil [ossa] @use_c2 : $@convention(thin) (@in_guaranteed C2) -> ()
// CHECK-LABEL: sil [ossa] @expand_alloc_stack_of_enum1 :
// CHECK: [[A:%[0-9]+]] = alloc_stack [lexical] $S
// CHECK: bb1:
// CHECK-NEXT: store %0 to [trivial] [[A]]
// CHECK: bb2:
// CHECK-NEXT: store %0 to [trivial] [[A]]
// CHECK: bb3:
// CHECK: apply {{%[0-9]+}}([[A]])
// CHECK: } // end sil function 'expand_alloc_stack_of_enum1'
sil [ossa] @expand_alloc_stack_of_enum1 : $@convention(method) (S) -> () {
bb0(%0 : $S):
%1 = alloc_stack [lexical] $MP
cond_br undef, bb1, bb2
bb1:
%2 = init_enum_data_addr %1 : $*MP, #MP.A!enumelt
store %0 to [trivial] %2 : $*S
inject_enum_addr %1 : $*MP, #MP.A!enumelt
br bb3
bb2:
%3 = init_enum_data_addr %1 : $*MP, #MP.A!enumelt
store %0 to [trivial] %3 : $*S
inject_enum_addr %1 : $*MP, #MP.A!enumelt
br bb3
bb3:
%7 = unchecked_take_enum_data_addr %1 : $*MP, #MP.A!enumelt
%8 = function_ref @take_s : $@convention(thin) (@in S) -> ()
%9 = apply %8(%7) : $@convention(thin) (@in S) -> ()
dealloc_stack %1 : $*MP
%11 = tuple ()
return %11 : $()
}
// CHECK-LABEL: sil [ossa] @expand_alloc_stack_of_enum_without_take :
// CHECK: [[A:%[0-9]+]] = alloc_stack $S
// CHECK: bb1:
// CHECK-NEXT: store %0 to [trivial] [[A]]
// CHECK: bb2:
// CHECK-NEXT: store %0 to [trivial] [[A]]
// CHECK: bb3:
// CHECK: destroy_addr [[A]]
// CHECK: } // end sil function 'expand_alloc_stack_of_enum_without_take'
sil [ossa] @expand_alloc_stack_of_enum_without_take : $@convention(method) (S) -> () {
bb0(%0 : $S):
%1 = alloc_stack $MP
cond_br undef, bb1, bb2
bb1:
%2 = init_enum_data_addr %1 : $*MP, #MP.A!enumelt
store %0 to [trivial] %2 : $*S
inject_enum_addr %1 : $*MP, #MP.A!enumelt
br bb3
bb2:
%3 = init_enum_data_addr %1 : $*MP, #MP.A!enumelt
store %0 to [trivial] %3 : $*S
inject_enum_addr %1 : $*MP, #MP.A!enumelt
br bb3
bb3:
destroy_addr %1 : $*MP
dealloc_stack %1 : $*MP
%11 = tuple ()
return %11 : $()
}
// CHECK-LABEL: sil [ossa] @expand_alloc_stack_of_enum_multiple_cases :
// CHECK: [[A:%[0-9]+]] = alloc_stack $T
// CHECK: bb1:
// CHECK-NEXT: [[COPY_ARG:%.*]] = copy_value %0
// CHECK-NEXT: store [[COPY_ARG]] to [init] [[A]]
// CHECK: apply {{%[0-9]+}}([[A]])
// CHECK: bb2:
// CHECK-NEXT: br bb3
// CHECK: bb3:
// CHECK: } // end sil function 'expand_alloc_stack_of_enum_multiple_cases'
sil [ossa] @expand_alloc_stack_of_enum_multiple_cases : $@convention(method) (@guaranteed T) -> () {
bb0(%0 : @guaranteed $T):
%1 = alloc_stack $X
cond_br undef, bb1, bb2
bb1:
%2 = init_enum_data_addr %1 : $*X, #X.some!enumelt
%0a = copy_value %0 : $T
store %0a to [init] %2 : $*T
inject_enum_addr %1 : $*X, #X.some!enumelt
%7 = unchecked_take_enum_data_addr %1 : $*X, #X.some!enumelt
%8 = function_ref @take_t : $@convention(thin) (@in T) -> ()
%9 = apply %8(%7) : $@convention(thin) (@in T) -> ()
br bb3
bb2:
inject_enum_addr %1 : $*X, #X.none!enumelt
destroy_addr %1 : $*X
br bb3
bb3:
dealloc_stack %1 : $*X
%11 = tuple ()
return %11 : $()
}
// CHECK-LABEL: sil [ossa] @dont_expand_alloc_stack_of_enum_multiple_cases :
// CHECK: alloc_stack $MP
// CHECK: } // end sil function 'dont_expand_alloc_stack_of_enum_multiple_cases'
sil [ossa] @dont_expand_alloc_stack_of_enum_multiple_cases : $@convention(method) (S) -> () {
bb0(%0 : $S):
%1 = alloc_stack $MP
cond_br undef, bb1, bb2
bb1:
%2 = init_enum_data_addr %1 : $*MP, #MP.A!enumelt
store %0 to [trivial] %2 : $*S
inject_enum_addr %1 : $*MP, #MP.A!enumelt
br bb3
bb2:
%3 = init_enum_data_addr %1 : $*MP, #MP.B!enumelt
store %0 to [trivial] %3 : $*S
inject_enum_addr %1 : $*MP, #MP.B!enumelt
br bb3
bb3:
destroy_addr %1 : $*MP
dealloc_stack %1 : $*MP
%11 = tuple ()
return %11 : $()
}
// CHECK-LABEL: sil [ossa] @dont_expand_alloc_stack_of_enum_multiple_cases2 :
// CHECK: alloc_stack $X
// CHECK: } // end sil function 'dont_expand_alloc_stack_of_enum_multiple_cases2'
sil [ossa] @dont_expand_alloc_stack_of_enum_multiple_cases2 : $@convention(method) (@guaranteed T) -> () {
bb0(%0 : @guaranteed $T):
%1 = alloc_stack $X
cond_br undef, bb1, bb2
bb1:
%2 = init_enum_data_addr %1 : $*X, #X.some!enumelt
%0a = copy_value %0 : $T
store %0a to [init] %2 : $*T
inject_enum_addr %1 : $*X, #X.some!enumelt
br bb3
bb2:
inject_enum_addr %1 : $*X, #X.none!enumelt
br bb3
bb3:
destroy_addr %1 : $*X
dealloc_stack %1 : $*X
%11 = tuple ()
return %11 : $()
}
// CHECK-LABEL: sil [ossa] @dont_expand_alloc_stack_of_enum_unknown_use :
// CHECK: alloc_stack $MP
// CHECK: } // end sil function 'dont_expand_alloc_stack_of_enum_unknown_use'
sil [ossa] @dont_expand_alloc_stack_of_enum_unknown_use : $@convention(method) (S) -> () {
bb0(%0 : $S):
%1 = alloc_stack $MP
%2 = init_enum_data_addr %1 : $*MP, #MP.A!enumelt
store %0 to [trivial] %2 : $*S
inject_enum_addr %1 : $*MP, #MP.A!enumelt
%8 = function_ref @use_mp : $@convention(thin) (@in_guaranteed MP) -> ()
%9 = apply %8(%1) : $@convention(thin) (@in_guaranteed MP) -> ()
destroy_addr %1 : $*MP
dealloc_stack %1 : $*MP
%11 = tuple ()
return %11 : $()
}
// CHECK-LABEL: sil [ossa] @replace_archetype :
// CHECK: [[S:%.*]] = alloc_stack [lexical] $T
// CHECK: debug_value [[S]]
// CHECK: unchecked_addr_cast [[S]]
// CHECK: destroy_addr [[S]]
// CHECK: } // end sil function 'replace_archetype'
sil [ossa] @replace_archetype : $@convention(thin) (@owned T) -> () {
bb0(%0 : @owned $T):
%1 = metatype $@thick T.Type
%2 = init_existential_metatype %1, $@thick P.Type
%3 = open_existential_metatype %2 to $@thick (@opened("82105EE0-DCB0-11E5-865D-C8E0EB309913", P) Self).Type
%4 = alloc_stack [lexical] $@opened("82105EE0-DCB0-11E5-865D-C8E0EB309913", P) Self
debug_value %4, var, name "x"
%5 = unchecked_addr_cast %4 to $*T
store %0 to [init] %5
destroy_addr %4
dealloc_stack %4
%r = tuple ()
return %r
}
// TODO: we don't support dependent existential archetypes, yet. Once we do, change this test case.
// CHECK-LABEL: sil [ossa] @dont_replace_dependent_archetype :
// CHECK: alloc_stack {{.*}}@opened
// CHECK: } // end sil function 'dont_replace_dependent_archetype'
sil [ossa] @dont_replace_dependent_archetype : $@convention(thin) (@owned U.A) -> () {
bb0(%0 : @owned $U.A):
%1 = metatype $@thick U.Type
%2 = init_existential_metatype %1, $@thick Q.Type
%3 = open_existential_metatype %2 to $@thick (@opened("82105EE0-DCB0-11E5-865D-C8E0EB309914", Q) Self).Type
%4 = alloc_stack $(@opened("82105EE0-DCB0-11E5-865D-C8E0EB309914", Q) Self).A
%5 = unchecked_addr_cast %4 to $*U.A
store %0 to [init] %5
destroy_addr %4
dealloc_stack %4
%r = tuple ()
return %r
}
// CHECK-LABEL: sil [ossa] @replace_existential_with_concrete_type1 :
// CHECK: [[S:%.*]] = alloc_stack $T
// CHECK-NOT: init_existential_addr
// CHECK-NOT: open_existential_addr
// CHECK: destroy_addr [[S]]
// CHECK: } // end sil function 'replace_existential_with_concrete_type1'
sil [ossa] @replace_existential_with_concrete_type1 : $@convention(thin) (@owned T) -> () {
bb0(%0 : @owned $T):
%5 = alloc_stack $any P
%6 = init_existential_addr %5, $T
store %0 to [init] %6
%8 = open_existential_addr mutable_access %5 to $*@opened("83DE9694-7315-11E8-955C-ACDE48001122", P) Self
destroy_addr %8
dealloc_stack %5
%r = tuple ()
return %r
}
// CHECK-LABEL: sil [ossa] @replace_existential_with_concrete_type2 :
// CHECK: [[S:%.*]] = alloc_stack $T
// CHECK-NOT: init_existential_addr
// CHECK-NOT: open_existential_addr
// CHECK: store
// CHECK: unconditional_checked_cast_addr T in [[S]] to T in %0
// CHECK: destroy_addr [[S]]
// CHECK: } // end sil function 'replace_existential_with_concrete_type2'
sil [ossa] @replace_existential_with_concrete_type2 : $@convention(thin) (@owned T) -> @out T {
bb0(%0 : $*T, %1 : @owned $T):
%2 = metatype $@thick T.Type
%3 = init_existential_metatype %2, $@thick P.Type
%4 = open_existential_metatype %3 to $@thick (@opened("82105EE0-DCB0-11E5-865D-C8E0EB309913", P) Self).Type
%5 = alloc_stack $any P
%6 = init_existential_addr %5, $(@opened("82105EE0-DCB0-11E5-865D-C8E0EB309913", P) Self)
%7 = unchecked_addr_cast %6 to $*T
store %1 to [init] %7
unconditional_checked_cast_addr any P in %5 to T in %0
%8 = open_existential_addr mutable_access %5 to $*@opened("83DE9694-7315-11E8-955C-ACDE48001122", P) Self
destroy_addr %8
dealloc_stack %5
%r = tuple ()
return %r
}
// CHECK-LABEL: sil [ossa] @replace_existential_with_concrete_type3 :
// CHECK: [[S:%.*]] = alloc_stack $T
// CHECK-NOT: init_existential_addr
// CHECK-NOT: open_existential_addr
// CHECK: debug_value undef : $*any P, let, name "value1"
// CHECK: destroy_addr [[S]]
// CHECK: } // end sil function 'replace_existential_with_concrete_type3'
sil_scope 1 { loc "a.swift":1:1 parent @replace_existential_with_concrete_type3 : $@convention(thin) (@owned T) -> () }
sil_scope 2 { loc "inlined.swift":1:1 parent @$inlined : $@convention(thin) <τ_0_0> (@in_guaranteed τ_0_0) -> () inlined_at 1 }
sil [ossa] @replace_existential_with_concrete_type3 : $@convention(thin) (@owned T) -> () {
bb0(%0 : @owned $T):
%5 = alloc_stack $any P
debug_value %5, let, name "value1", loc "inlined.swift":1:1, scope 2
%6 = init_existential_addr %5, $T
store %0 to [init] %6
%8 = open_existential_addr mutable_access %5 to $*@opened("83DE9694-7315-11E8-955C-ACDE48001122", P) Self
destroy_addr %8
dealloc_stack %5
%r = tuple ()
return %r
}
// CHECK-LABEL: sil [ossa] @replace_existential_with_archetype :
// CHECK: [[S:%.*]] = alloc_stack $@opened("82105EE0-DCB0-11E5-865D-C8E0EB309913", any P) Self
// CHECK-NOT: init_existential_addr
// CHECK-NOT: open_existential_addr
// CHECK: checked_cast_addr_br take_always @opened("82105EE0-DCB0-11E5-865D-C8E0EB309913", any P) Self in [[S]] to T in %0, bb1, bb2
// CHECK: } // end sil function 'replace_existential_with_archetype'
sil [ossa] @replace_existential_with_archetype : $@convention(thin) (@owned T, @thick P.Type) -> @out T {
bb0(%0 : $*T, %1 : @owned $T, %2 : $@thick P.Type):
%3 = open_existential_metatype %2 to $@thick (@opened("82105EE0-DCB0-11E5-865D-C8E0EB309913", P) Self).Type
%4 = alloc_stack $any P
%5 = init_existential_addr %4, $(@opened("82105EE0-DCB0-11E5-865D-C8E0EB309913", P) Self)
%6 = unchecked_addr_cast %5 to $*T
store %1 to [init] %6
checked_cast_addr_br take_always any P in %4 to T in %0, bb1, bb2
bb1:
dealloc_stack %4
%r = tuple ()
return %r
bb2:
dealloc_stack %4
unreachable
}
// CHECK-LABEL: sil [ossa] @dont_replace_archetype_not_dominating :
// CHECK: alloc_stack $any P
// CHECK: init_existential_addr
// CHECK: open_existential_addr
// CHECK: } // end sil function 'dont_replace_archetype_not_dominating'
sil [ossa] @dont_replace_archetype_not_dominating : $@convention(thin) (@owned T, @thick P.Type) -> () {
bb0(%0 : @owned $T, %1 : $@thick P.Type):
%4 = alloc_stack $any P
%3 = open_existential_metatype %1 to $@thick (@opened("82105EE0-DCB0-11E5-865D-C8E0EB309913", P) Self).Type
%5 = init_existential_addr %4, $(@opened("82105EE0-DCB0-11E5-865D-C8E0EB309913", P) Self)
%6 = unchecked_addr_cast %5 to $*T
store %0 to [init] %6
%8 = open_existential_addr mutable_access %4 to $*@opened("83DE9694-7315-11E8-955C-ACDE48001122", P) Self
destroy_addr %8
dealloc_stack %4
%r = tuple ()
return %r
}
// CHECK-LABEL: sil [ossa] @dont_replace_multiple_inits :
// CHECK: [[S:%.*]] = alloc_stack $any P
// CHECK: init_existential_addr [[S]], $T1
// CHECK: init_existential_addr [[S]], $T2
// CHECK: open_existential_addr
// CHECK: } // end sil function 'dont_replace_multiple_inits'
sil [ossa] @dont_replace_multiple_inits : $@convention(thin) (T1, T2) -> () {
bb0(%0 : $T1, %1 : $T2):
%5 = alloc_stack $any P
cond_br undef, bb1, bb2
bb1:
%6 = init_existential_addr %5, $T1
store %0 to [trivial] %6
br bb3
bb2:
%9 = init_existential_addr %5, $T2
store %1 to [trivial] %9
br bb3
bb3:
%8 = open_existential_addr mutable_access %5 to $*@opened("83DE9694-7315-11E8-955C-ACDE48001122", P) Self
destroy_addr %8
dealloc_stack %5
%r = tuple ()
return %r
}
// CHECK-LABEL: sil [ossa] @init_existential_with_dynamic_self :
// CHECK: [[S:%.*]] = alloc_stack $C2
// CHECK: store %0 to [init] [[S]]
// CHECK: apply %{{[0-9]+}}([[S]])
// CHECK: } // end sil function 'init_existential_with_dynamic_self'
sil [ossa] @init_existential_with_dynamic_self : $@convention(method) (@owned C2) -> () {
bb0(%0 : @owned $C2):
%1 = alloc_stack $P
%2 = init_existential_addr %1, $@dynamic_self C2
store %0 to [init] %2
%4 = function_ref @use_c2 : $@convention(thin) (@in_guaranteed C2) -> ()
%5 = apply %4(%2) : $@convention(thin) (@in_guaranteed C2) -> ()
destroy_addr %1
dealloc_stack %1
return %5
}
// CHECK-LABEL: sil [ossa] @dont_replace_existential_with_escaping_addr :
// CHECK: alloc_stack $any P
// CHECK: } // end sil function 'dont_replace_existential_with_escaping_addr'
sil [ossa] @dont_replace_existential_with_escaping_addr : $@convention(thin) <V> (@thick V.Type, @owned C2) -> @out V {
bb0(%0 : $*V, %1 : $@thick V.Type, %2 : @owned $C2):
%114 = alloc_stack $any P
%117 = init_existential_addr %114, $C2
store %2 to [init] %117
%129 = unchecked_addr_cast %114 to $*V
copy_addr %129 to [init] %0
destroy_addr %114
dealloc_stack %114
%137 = tuple ()
return %137
}