mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
Use consecutive instruction numbers to check for overlapping instead of iterating over the instruction list. This fixes a compile time problem which shows up if there are many stack locations in a large basic block. rdar://113207176
323 lines
7.8 KiB
Plaintext
323 lines
7.8 KiB
Plaintext
// RUN: %target-sil-opt -enable-sil-verify-all %s -alloc-stack-hoisting | %FileCheck --check-prefix=CHECK --check-prefix=CHECK-MERGING %s
|
|
// RUN: %target-sil-opt -enable-sil-verify-all %s -alloc-stack-hoisting -sil-merge-stack-slots=false | %FileCheck %s
|
|
sil_stage canonical
|
|
|
|
import Builtin
|
|
import Swift
|
|
import SwiftShims
|
|
|
|
protocol P {
|
|
}
|
|
|
|
struct Generic<T> {
|
|
var x : T
|
|
}
|
|
|
|
struct FixedSize {
|
|
var x : Builtin.Int8
|
|
}
|
|
|
|
// CHECK-LABEL: sil @hoist_generic
|
|
// CHECK: bb0({{.*}}):
|
|
// CHECK: [[AS:%.*]] = alloc_stack $T
|
|
// CHECK: bb1:
|
|
// CHECK-NOT: alloc_stack
|
|
// CHECK-NOT: dealloc_stack
|
|
// CHECK: bb2
|
|
// CHECK: bb3:
|
|
// CHECK: dealloc_stack [[AS]]
|
|
// CHECK: return
|
|
|
|
sil @hoist_generic : $@convention(thin) <T> (@in T, Builtin.Int1) -> () {
|
|
bb0(%0 : $*T, %1: $Builtin.Int1):
|
|
cond_br %1, bb1, bb2
|
|
bb1:
|
|
%2 = alloc_stack $T
|
|
copy_addr [take] %0 to [init] %2 : $*T
|
|
destroy_addr %2 : $*T
|
|
dealloc_stack %2 : $*T
|
|
br bb3
|
|
bb2:
|
|
destroy_addr %0 : $*T
|
|
br bb3
|
|
bb3:
|
|
%3 = tuple ()
|
|
return %3 : $()
|
|
}
|
|
|
|
sil @throwing_fun : $@convention(thin) () -> @error any Error
|
|
|
|
// CHECK-LABEL: sil @hoist_generic
|
|
// CHECK: bb0({{.*}}):
|
|
// CHECK: [[AS:%.*]] = alloc_stack $T
|
|
// CHECK: bb1:
|
|
// CHECK-NOT: alloc_stack
|
|
// CHECK-NOT: dealloc_stack
|
|
// CHECK: bb2
|
|
// CHECK: bb3:
|
|
// CHECK: try_apply
|
|
// CHECK: bb4({{.*}}:
|
|
// CHECK: dealloc_stack [[AS]]
|
|
// CHECK: return
|
|
// CHECK: bb5({{.*}}):
|
|
// CHECK: dealloc_stack [[AS]]
|
|
// CHECK: throw
|
|
|
|
sil @hoist_generic_throwing : $@convention(thin) <T> (@in T, Builtin.Int1) -> @error any Error {
|
|
bb0(%0 : $*T, %1: $Builtin.Int1):
|
|
cond_br %1, bb1, bb2
|
|
bb1:
|
|
%2 = alloc_stack $T
|
|
copy_addr [take] %0 to [init] %2 : $*T
|
|
destroy_addr %2 : $*T
|
|
dealloc_stack %2 : $*T
|
|
br bb3
|
|
bb2:
|
|
destroy_addr %0 : $*T
|
|
br bb3
|
|
bb3:
|
|
%3 = function_ref @throwing_fun : $@convention(thin) () -> @error any Error
|
|
try_apply %3() : $@convention(thin) () -> @error any Error, normal bb4, error bb5
|
|
|
|
bb4(%6: $()):
|
|
%4 = tuple ()
|
|
return %4 : $()
|
|
|
|
bb5(%5: $Error):
|
|
throw %5: $Error
|
|
}
|
|
|
|
// CHECK-LABEL: sil @hoist_generic
|
|
// CHECK: bb0({{.*}}):
|
|
// CHECK: [[AS:%.*]] = alloc_stack $Generic<T>
|
|
// CHECK: bb1:
|
|
// CHECK-NOT: alloc_stack
|
|
// CHECK-NOT: dealloc_stack
|
|
// CHECK: bb2
|
|
// CHECK: bb3:
|
|
// CHECK: dealloc_stack [[AS]]
|
|
// CHECK: return
|
|
|
|
sil @hoist_generic_type : $@convention(thin) <T> (@in Generic<T>, Builtin.Int1) -> () {
|
|
bb0(%0 : $*Generic<T>, %1: $Builtin.Int1):
|
|
cond_br %1, bb1, bb2
|
|
bb1:
|
|
%2 = alloc_stack $Generic<T>
|
|
copy_addr [take] %0 to [init] %2 : $*Generic<T>
|
|
destroy_addr %2 : $*Generic<T>
|
|
dealloc_stack %2 : $*Generic<T>
|
|
br bb3
|
|
bb2:
|
|
destroy_addr %0 : $*Generic<T>
|
|
br bb3
|
|
bb3:
|
|
%3 = tuple ()
|
|
return %3 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil @hoist_generic_nesting
|
|
// CHECK: bb0({{.*}}):
|
|
// CHECK: [[AS:%.*]] = alloc_stack $T
|
|
// CHECK: [[AS2:%.*]] = alloc_stack $T
|
|
// CHECK: [[FIXED:%.*]] = alloc_stack $FixedSize
|
|
// CHECK: bb1:
|
|
// CHECK-NOT: alloc_stack
|
|
// CHECK-NOT: dealloc_stack
|
|
// CHECK: bb2
|
|
// CHECK: bb3:
|
|
// CHECK: dealloc_stack [[FIXED]]
|
|
// CHECK: dealloc_stack [[AS2]]
|
|
// CHECK: dealloc_stack [[AS]]
|
|
// CHECK: return
|
|
|
|
sil @hoist_generic_nesting : $@convention(thin) <T> (@in T, Builtin.Int1) -> () {
|
|
bb0(%0 : $*T, %1: $Builtin.Int1):
|
|
%2 = alloc_stack $FixedSize
|
|
cond_br %1, bb1, bb2
|
|
bb1:
|
|
%3 = alloc_stack $T
|
|
%4 = alloc_stack $T
|
|
copy_addr [take] %0 to [init] %3 : $*T
|
|
destroy_addr %3 : $*T
|
|
dealloc_stack %4: $*T
|
|
dealloc_stack %3 : $*T
|
|
br bb3
|
|
bb2:
|
|
destroy_addr %0 : $*T
|
|
br bb3
|
|
bb3:
|
|
dealloc_stack %2: $*FixedSize
|
|
%5 = tuple ()
|
|
return %5 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil @dont_hoist_opened_generic
|
|
// CHECK: bb0({{.*}}):
|
|
// CHECK-NOT: alloc_stack
|
|
// CHECK: bb1:
|
|
// CHECK: alloc_stack
|
|
// CHECK: bb2:
|
|
// CHECK: bb3:
|
|
// CHECK-NOT: dealloc_stack
|
|
// CHECK: return
|
|
|
|
sil @dont_hoist_opened_generic : $@convention(thin) (@in P, Builtin.Int1) -> () {
|
|
bb0(%0 : $*P, %1: $Builtin.Int1):
|
|
cond_br %1, bb1, bb2
|
|
bb1:
|
|
%2 = open_existential_addr mutable_access %0 : $*P to $*@opened("1B6851A6-4796-11E6-B7DF-B8E856428C60", P) Self
|
|
%3 = alloc_stack $@opened("1B6851A6-4796-11E6-B7DF-B8E856428C60", P) Self
|
|
copy_addr [take] %2 to [init] %3 : $*@opened("1B6851A6-4796-11E6-B7DF-B8E856428C60", P) Self
|
|
destroy_addr %3 : $*@opened("1B6851A6-4796-11E6-B7DF-B8E856428C60", P) Self
|
|
dealloc_stack %3 : $*@opened("1B6851A6-4796-11E6-B7DF-B8E856428C60", P) Self
|
|
br bb3
|
|
bb2:
|
|
destroy_addr %0 : $*P
|
|
br bb3
|
|
bb3:
|
|
%4 = tuple ()
|
|
return %4 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil @dont_hoist_protocol
|
|
// CHECK: bb0({{.*}}):
|
|
// CHECK-NOT: alloc_stack
|
|
// CHECK: bb1:
|
|
// CHECK: alloc_stack
|
|
// CHECK: bb2:
|
|
// CHECK: bb3:
|
|
// CHECK-NOT: dealloc_stack
|
|
// CHECK: return
|
|
|
|
sil @dont_hoist_protocol : $@convention(thin) (@in P, Builtin.Int1) -> () {
|
|
bb0(%0 : $*P, %1: $Builtin.Int1):
|
|
cond_br %1, bb1, bb2
|
|
bb1:
|
|
%2 = alloc_stack $P
|
|
copy_addr [take] %0 to [init] %2 : $*P
|
|
destroy_addr %2 : $*P
|
|
dealloc_stack %2 : $*P
|
|
br bb3
|
|
bb2:
|
|
destroy_addr %0 : $*P
|
|
br bb3
|
|
bb3:
|
|
%3 = tuple ()
|
|
return %3 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil @dont_crash_on_unreachable
|
|
// CHECK: bb0({{.*}}):
|
|
// CHECK: alloc_stack
|
|
// CHECK: bb1:
|
|
// CHECK-NOT: alloc_stack
|
|
// CHECK: bb2:
|
|
// CHECK: bb3:
|
|
// CHECK: unreachable
|
|
|
|
sil @dont_crash_on_unreachable : $@convention(thin) <T> (@in T, Builtin.Int1) -> Never {
|
|
bb0(%0 : $*T, %1: $Builtin.Int1):
|
|
cond_br %1, bb1, bb2
|
|
bb1:
|
|
%2 = alloc_stack $T
|
|
copy_addr [take] %0 to [init] %2 : $*T
|
|
destroy_addr %2 : $*T
|
|
br bb3
|
|
bb2:
|
|
destroy_addr %0 : $*T
|
|
br bb3
|
|
bb3:
|
|
%3 = builtin "int_trap"() : $()
|
|
unreachable
|
|
}
|
|
|
|
// CHECK-LABEL: sil @dont_hoist_with_availability_checks
|
|
// CHECK-NOT: alloc_stack
|
|
// CHECK: cond_br
|
|
// CHECK: bb1:
|
|
// CHECK: alloc_stack
|
|
// CHECK: } // end sil function 'dont_hoist_with_availability_checks'
|
|
sil @dont_hoist_with_availability_checks : $@convention(thin) <T> (@in T, Builtin.Int1) -> () {
|
|
bb0(%0 : $*T, %1: $Builtin.Int1):
|
|
%5 = integer_literal $Builtin.Int32, 15
|
|
%7 = builtin "targetOSVersionAtLeast"(%5 : $Builtin.Int32, %5 : $Builtin.Int32, %5 : $Builtin.Int32) : $Builtin.Int32
|
|
%8 = builtin "cmp_eq_Int32"(%7 : $Builtin.Int32, %5 : $Builtin.Int32) : $Builtin.Int1
|
|
cond_br %8, bb1, bb2
|
|
bb1:
|
|
%2 = alloc_stack $T
|
|
copy_addr [take] %0 to [init] %2 : $*T
|
|
destroy_addr %2 : $*T
|
|
dealloc_stack %2 : $*T
|
|
br bb3
|
|
bb2:
|
|
destroy_addr %0 : $*T
|
|
br bb3
|
|
bb3:
|
|
%3 = tuple ()
|
|
return %3 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil @dont_hoist_with_has_symbol_checks
|
|
// CHECK-NOT: alloc_stack
|
|
// CHECK: cond_br
|
|
// CHECK: bb1:
|
|
// CHECK: alloc_stack
|
|
// CHECK: } // end sil function 'dont_hoist_with_has_symbol_checks'
|
|
sil @dont_hoist_with_has_symbol_checks : $@convention(thin) <T> (@in T, Builtin.Int1) -> () {
|
|
bb0(%0 : $*T, %1: $Builtin.Int1):
|
|
%5 = has_symbol #FixedSize.init
|
|
cond_br %5, bb1, bb2
|
|
bb1:
|
|
%2 = alloc_stack $T
|
|
copy_addr [take] %0 to [init] %2 : $*T
|
|
destroy_addr %2 : $*T
|
|
dealloc_stack %2 : $*T
|
|
br bb3
|
|
bb2:
|
|
destroy_addr %0 : $*T
|
|
br bb3
|
|
bb3:
|
|
%3 = tuple ()
|
|
return %3 : $()
|
|
}
|
|
|
|
// CHECK-MERGING-LABEL: sil @merging
|
|
// CHECK-MERGING: %1 = alloc_stack $T
|
|
// CHECK-MERGING-NEXT: debug_value %1
|
|
// CHECK-MERGING-NEXT: debug_value %1
|
|
// CHECK-MERGING: dealloc_stack %1
|
|
// CHECK-MERGING-NOT: alloc_stack
|
|
// CHECK: } // end sil function 'merging'
|
|
sil @merging : $@convention(thin) <T> (@in T) -> () {
|
|
bb0(%0 : $*T):
|
|
%1 = alloc_stack $T
|
|
debug_value %1 : $*T, name "x"
|
|
dealloc_stack %1 : $*T
|
|
%2 = alloc_stack $T
|
|
debug_value %2 : $*T, name "y"
|
|
dealloc_stack %2 : $*T
|
|
%r = tuple ()
|
|
return %r : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil @dont_merge
|
|
// CHECK: %1 = alloc_stack $T
|
|
// CHECK-NEXT: %2 = alloc_stack $T
|
|
// CHECK-NEXT: debug_value %2
|
|
// CHECK-NEXT: debug_value %1
|
|
// CHECK: dealloc_stack %2
|
|
// CHECK-NEXT: dealloc_stack %1
|
|
// CHECK: } // end sil function 'dont_merge'
|
|
sil @dont_merge : $@convention(thin) <T> (@in T) -> () {
|
|
bb0(%0 : $*T):
|
|
%1 = alloc_stack $T
|
|
debug_value %1 : $*T, name "x"
|
|
%3 = alloc_stack $T
|
|
debug_value %3 : $*T, name "y"
|
|
dealloc_stack %3 : $*T
|
|
dealloc_stack %1 : $*T
|
|
%r = tuple ()
|
|
return %r : $()
|
|
}
|
|
|