Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,29 @@

import SIL

private extension ArgumentConventions {
func isLifetimeSourceOrTarget(index argIndex: Int) -> Bool {
// Check if `argIndex` is a lifetime target
if self[parameterDependencies: argIndex] != nil {
return true
}

// Check if `argIndex` is a lifetime source in resultDependencies
if self[resultDependsOn: argIndex] != nil {
return true
}

// Check if `argIndex` is a lifetime source in parameterDependencies
for targetIndex in firstParameterIndex..<self.count {
if getDependence(target: targetIndex, source: argIndex) != nil {
return true
}
}

return false
}
}

/// Replace an apply with metatype arguments with an apply to a specialized function, where the
/// metatype values are not passed, but rematerialized in the entry block of the specialized function
///
Expand Down Expand Up @@ -52,6 +75,15 @@ func specializeByRemovingMetatypeArguments(apply: FullApplySite, _ context: Modu
return
}

// If a function has lifetime dependencies, bailout if dead arguments precede lifetime sources or targets
if callee.convention.hasLifetimeDependencies() {
for (argIndex, _) in callee.arguments.enumerated() where argIndex >= deadArgIndices.first! {
if callee.argumentConventions.isLifetimeSourceOrTarget(index: argIndex) {
return
}
}
}

let specializedFuncName = context.mangle(withDeadArguments: deadArgIndices, from: callee)

let specializedCallee: Function
Expand Down
75 changes: 74 additions & 1 deletion test/SILOptimizer/mandatory_performance_optimizations.sil
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// RUN: %target-sil-opt -sil-print-types -enable-sil-verify-all %s -mandatory-performance-optimizations | %FileCheck %s
// RUN: %target-sil-opt -sil-print-types -enable-sil-verify-all %s -mandatory-performance-optimizations -enable-experimental-feature Lifetimes | %FileCheck %s

// REQUIRES: swift_in_compiler
// REQUIRES: swift_feature_Lifetimes

sil_stage canonical

Expand Down Expand Up @@ -222,6 +223,78 @@ bb0(%0 : $Int, %1 : $@thick Int.Type, %2 : @owned $Builtin.NativeObject):
return %2 : $Builtin.NativeObject
}

sil [no_locks] [perf_constraint] [ossa] @dont_remove_metatype_arg_lifetime : $@convention(thin) (Int, UnsafeRawPointer) -> @lifetime(borrow 1) Span<Int> {
bb0(%0 : $Int, %1 : $UnsafeRawPointer):
%3 = metatype $@thick Int.Type
%7 = function_ref @metatype_arg_lifetime : $@convention(thin) (Int, @thick Int.Type, UnsafeRawPointer) -> @lifetime(borrow 2) Span<Int>
%8 = apply %7(%0, %3, %1) : $@convention(thin) (Int, @thick Int.Type, UnsafeRawPointer) -> @lifetime(borrow 2) Span<Int>
return %8
}

sil [ossa] @get_span : $@convention(thin) (UnsafeRawPointer) -> @lifetime(borrow 0) Span<Int>

// CHECK-NOT: sil [signature_optimized_thunk] [ossa] @metatype_arg_lifetime :
sil [ossa] @metatype_arg_lifetime : $@convention(thin) (Int, @thick Int.Type, UnsafeRawPointer) -> @lifetime(borrow 2) Span<Int> {
bb0(%0 : $Int, %1 : $@thick Int.Type, %2 : $UnsafeRawPointer):
fix_lifetime %1 : $@thick Int.Type
%3 = function_ref @get_span : $@convention(thin) (UnsafeRawPointer) -> @lifetime(borrow 0) Span<Int>
%4 = apply %3(%2) : $@convention(thin) (UnsafeRawPointer) -> @lifetime(borrow 0) Span<Int>
return %4
}

sil [no_locks] [perf_constraint] [ossa] @can_remove_metatype_arg_lifetime : $@convention(thin) (Int, UnsafeRawPointer) -> @lifetime(borrow 1) Span<Int> {
bb0(%0 : $Int, %1 : $UnsafeRawPointer):
%3 = metatype $@thick Int.Type
%7 = function_ref @metatype_arg_lifetime_opt : $@convention(thin) (UnsafeRawPointer, Int, @thick Int.Type) -> @lifetime(borrow 0) Span<Int>
%8 = apply %7(%1, %0, %3) : $@convention(thin) (UnsafeRawPointer, Int, @thick Int.Type) -> @lifetime(borrow 0) Span<Int>
return %8
}

// CHECK: sil [signature_optimized_thunk] [ossa] @metatype_arg_lifetime_opt :
sil [ossa] @metatype_arg_lifetime_opt : $@convention(thin) (UnsafeRawPointer, Int, @thick Int.Type) -> @lifetime(borrow 0) Span<Int> {
bb0(%2 : $UnsafeRawPointer, %0 : $Int, %1 : $@thick Int.Type):
fix_lifetime %1 : $@thick Int.Type
%3 = function_ref @get_span : $@convention(thin) (UnsafeRawPointer) -> @lifetime(borrow 0) Span<Int>
%4 = apply %3(%2) : $@convention(thin) (UnsafeRawPointer) -> @lifetime(borrow 0) Span<Int>
return %4
}

sil [no_locks] [perf_constraint] [ossa] @dont_remove_metatype_arg_lifetime_inout : $@convention(thin) (Int, @lifetime(copy 2) @inout MutableSpan<Int>, @owned MutableSpan<Int>) -> () {
bb0(%0 : $Int, %1 : $*MutableSpan<Int>, %2 : @owned $MutableSpan<Int>):
%3 = metatype $@thick Int.Type
%7 = function_ref @metatype_arg_lifetime_inout : $@convention(thin) (Int, @thick Int.Type, @lifetime(copy 3) @inout MutableSpan<Int>, @owned MutableSpan<Int>) -> ()
%8 = apply %7(%0, %3, %1, %2) : $@convention(thin) (Int, @thick Int.Type, @lifetime(copy 3) @inout MutableSpan<Int>, @owned MutableSpan<Int>) -> ()
%r = tuple ()
return %r
}

// CHECK-NOT: sil [signature_optimized_thunk] [ossa] @metatype_arg_lifetime_inout :
sil [ossa] @metatype_arg_lifetime_inout : $@convention(thin) (Int, @thick Int.Type, @lifetime(copy 3) @inout MutableSpan<Int>, @owned MutableSpan<Int>) -> () {
bb0(%0 : $Int, %1 : $@thick Int.Type, %2 : $*MutableSpan<Int>, %3 : @owned $MutableSpan<Int>):
fix_lifetime %1 : $@thick Int.Type
destroy_value %3
%r = tuple ()
return %r
}

sil [no_locks] [perf_constraint] [ossa] @dont_remove_metatype_arg_lifetime_inout_source : $@convention(thin) (Int, @lifetime(copy 2) @inout MutableSpan<Int>, @owned MutableSpan<Int>) -> () {
bb0(%0 : $Int, %1 : $*MutableSpan<Int>, %2 : @owned $MutableSpan<Int>):
%3 = metatype $@thick Int.Type
%7 = function_ref @metatype_arg_lifetime_inout_source : $@convention(thin) (@lifetime(copy 3) @inout MutableSpan<Int>, Int, @thick Int.Type, @owned MutableSpan<Int>) -> ()
%8 = apply %7(%1, %0, %3, %2) : $@convention(thin) (@lifetime(copy 3) @inout MutableSpan<Int>, Int, @thick Int.Type, @owned MutableSpan<Int>) -> ()
%r = tuple ()
return %r
}

// CHECK-NOT: sil [signature_optimized_thunk] [ossa] @metatype_arg_lifetime_inout_source :
sil [ossa] @metatype_arg_lifetime_inout_source : $@convention(thin) (@lifetime(copy 3) @inout MutableSpan<Int>, Int, @thick Int.Type, @owned MutableSpan<Int>) -> () {
bb0(%2 : $*MutableSpan<Int>, %0 : $Int, %1 : $@thick Int.Type, %3 : @owned $MutableSpan<Int>):
fix_lifetime %1 : $@thick Int.Type
destroy_value %3
%r = tuple ()
return %r
}

// CHECK-LABEL: sil [no_locks] [perf_constraint] [ossa] @remove_metatype_arg_throws :
// CHECK: [[F:%.*]] = function_ref @$s19metatype_arg_throwsTf4ndn_n : $@convention(thin) (Int, @owned Builtin.NativeObject) -> (@owned Builtin.NativeObject, @error any Error)
// CHECK: try_apply [[F]](%0, %1) : $@convention(thin) (Int, @owned Builtin.NativeObject) -> (@owned Builtin.NativeObject, @error any Error), normal bb1, error bb2
Expand Down