Merge pull request #85482 from meg-gupta/reduceendcowmutation

Avoid inserting end_cow_mutation_addr in some common cases
This commit is contained in:
Meghana Gupta
2025-11-13 19:07:45 -08:00
committed by GitHub
2 changed files with 55 additions and 1 deletions

View File

@@ -142,6 +142,10 @@ let lifetimeDependenceScopeFixupPass = FunctionPass(
private extension Type {
func mayHaveMutableSpan(in function: Function, _ context: FunctionPassContext) -> Bool {
// Escapable and Copyable types cannot have MutableSpan
if isEscapable || !isMoveOnly {
return false
}
if hasArchetype {
return true
}
@@ -176,6 +180,24 @@ private extension Type {
}
return false
}
// Returns true if a type maybe Array/ArraySlice/ContiguousArray which are optimized COW types.
// The standard library introduces builtins begin_cow_mutation/end_cow_mutation for such types which are then used to optimize uniqueness checks.
func mayHaveOptimizedCOWType(in function: Function) -> Bool {
// Trivial types cannot be Array/ArraySlice/ContiguousArray.
if isTrivial(in: function) {
return false
}
// Builtin types do not contain Array/ArraySlice/ContiguousArray.
if isBuiltinType {
return false
}
// ~Copyable types cannot contain Array/ArraySlice/ContiguousArray.
if isMoveOnly {
return false
}
return true
}
}
/// Insert end_cow_mutation_addr for lifetime dependent values that maybe of type MutableSpan and depend on a mutable address.
@@ -203,7 +225,8 @@ private func createEndCOWMutationIfNeeded(lifetimeDep: LifetimeDependence, _ con
return
}
guard lifetimeDep.dependentValue.type.mayHaveMutableSpan(in: lifetimeDep.dependentValue.parentFunction, context) else {
guard lifetimeDep.dependentValue.type.mayHaveMutableSpan(in: lifetimeDep.dependentValue.parentFunction, context) &&
lifetimeDep.parentValue.type.mayHaveOptimizedCOWType(in: lifetimeDep.dependentValue.parentFunction) else {
return
}

View File

@@ -0,0 +1,31 @@
// RUN: %target-swift-frontend -O -emit-sil %s -disable-availability-checking | %FileCheck %s --check-prefix=CHECK-SIL
public protocol P {
mutating func mutate(_ other: Self)
}
// CHECK-SIL-LABEL: sil @$s38mutable_span_stdlib_bounds_check_tests0a1_B7_doubleyys11MutableSpanVyxGzAA1PRzlF :
// CHECK-SIL: bb3({{.*}}):
// CHECK-SIL-NOT: end_cow_mutation
// CHECK-SIL-NOT: cond_fail "index out of bounds"
// CHECK-SIL-LABEL: } // end sil function '$s38mutable_span_stdlib_bounds_check_tests0a1_B7_doubleyys11MutableSpanVyxGzAA1PRzlF'
public func mutable_span_double<T: P>(_ ms: inout MutableSpan<T>) {
for i in ms.indices {
ms[i].mutate(ms[i])
}
}
extension Int : P {
public mutating func mutate(_ other: Int) {
self += other
}
}
// CHECK-SIL-LABEL: sil @$s38mutable_span_stdlib_bounds_check_tests17specializedCalleryySaySiGzF : $@convention(thin) (@inout Array<Int>) -> () {
// CHECK-SIL-NOT: cond_fail "index out of bounds"
// CHECK-SIL-LABEL: } // end sil function '$s38mutable_span_stdlib_bounds_check_tests17specializedCalleryySaySiGzF'
public func specializedCaller(_ array: inout Array<Int>) {
var mut = array.mutableSpan
mutable_span_double(&mut)
}