From 5e88f38152b7c4463b08a4f16fc347536306fa7e Mon Sep 17 00:00:00 2001 From: Meghana Gupta Date: Thu, 13 Nov 2025 02:24:48 -0800 Subject: [PATCH 1/3] Avoid inserting end_cow_mutation_addr in some common cases --- .../LifetimeDependenceScopeFixup.swift | 21 ++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/SwiftCompilerSources/Sources/Optimizer/FunctionPasses/LifetimeDependenceScopeFixup.swift b/SwiftCompilerSources/Sources/Optimizer/FunctionPasses/LifetimeDependenceScopeFixup.swift index f90815bbee2d9..cf0d20752caab 100644 --- a/SwiftCompilerSources/Sources/Optimizer/FunctionPasses/LifetimeDependenceScopeFixup.swift +++ b/SwiftCompilerSources/Sources/Optimizer/FunctionPasses/LifetimeDependenceScopeFixup.swift @@ -176,6 +176,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 +221,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 } From 1dc03fea2509e134756cd450372e0fc0b655aceb Mon Sep 17 00:00:00 2001 From: Meghana Gupta Date: Thu, 13 Nov 2025 10:26:57 -0800 Subject: [PATCH 2/3] Add early exit for Escapable and copyable types from mayHaveMutableSpan --- .../FunctionPasses/LifetimeDependenceScopeFixup.swift | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/SwiftCompilerSources/Sources/Optimizer/FunctionPasses/LifetimeDependenceScopeFixup.swift b/SwiftCompilerSources/Sources/Optimizer/FunctionPasses/LifetimeDependenceScopeFixup.swift index cf0d20752caab..3eea101ed0989 100644 --- a/SwiftCompilerSources/Sources/Optimizer/FunctionPasses/LifetimeDependenceScopeFixup.swift +++ b/SwiftCompilerSources/Sources/Optimizer/FunctionPasses/LifetimeDependenceScopeFixup.swift @@ -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 } From 404173de831393cdcad41ef359d463232392093d Mon Sep 17 00:00:00 2001 From: Meghana Gupta Date: Thu, 13 Nov 2025 10:39:08 -0800 Subject: [PATCH 3/3] [NFC] Add MutableSpan bounds check test --- ...table_span_stdlib_bounds_check_tests.swift | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 test/SILOptimizer/mutable_span_stdlib_bounds_check_tests.swift diff --git a/test/SILOptimizer/mutable_span_stdlib_bounds_check_tests.swift b/test/SILOptimizer/mutable_span_stdlib_bounds_check_tests.swift new file mode 100644 index 0000000000000..79d974787cf55 --- /dev/null +++ b/test/SILOptimizer/mutable_span_stdlib_bounds_check_tests.swift @@ -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(_ ms: inout MutableSpan) { + 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) -> () { +// 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) { + var mut = array.mutableSpan + mutable_span_double(&mut) +} +