From e317a603fcbc59adf80c3b55be857d63712e2366 Mon Sep 17 00:00:00 2001 From: Meghana Gupta Date: Tue, 8 Jul 2025 12:04:57 -0700 Subject: [PATCH] Add simplification for end_cow_mutation_addr We insert end_cow_mutation_addr for lifetime dependent values dependent on mutable addresses. end_cow_mutation_addr can be simplified to end_cow_mutation after other optimizations like inlining, specialization etc This PR adds an instruction simplification to transform end_cow_mutation_addr to end_cow_mutation. This can enable array optimizations which look for end_cow_mutation. --- .../InstructionSimplification/CMakeLists.txt | 1 + .../SimplifyEndCOWMutationAddr.swift | 32 +++++++++++++ .../SimplifyMisc.swift | 1 + .../PassManager/PassRegistration.swift | 1 + lib/IRGen/LoadableByAddress.cpp | 8 ++++ .../SILCombiner/Simplifications.def | 1 + .../simplify_end_cow_mutation_addr.sil | 45 +++++++++++++++++++ 7 files changed, 89 insertions(+) create mode 100644 SwiftCompilerSources/Sources/Optimizer/InstructionSimplification/SimplifyEndCOWMutationAddr.swift create mode 100644 test/SILOptimizer/simplify_end_cow_mutation_addr.sil diff --git a/SwiftCompilerSources/Sources/Optimizer/InstructionSimplification/CMakeLists.txt b/SwiftCompilerSources/Sources/Optimizer/InstructionSimplification/CMakeLists.txt index e49d4b8952e..be954153319 100644 --- a/SwiftCompilerSources/Sources/Optimizer/InstructionSimplification/CMakeLists.txt +++ b/SwiftCompilerSources/Sources/Optimizer/InstructionSimplification/CMakeLists.txt @@ -24,6 +24,7 @@ swift_compiler_sources(Optimizer SimplifyDebugStep.swift SimplifyDestroyValue.swift SimplifyDestructure.swift + SimplifyEndCOWMutationAddr.swift SimplifyFixLifetime.swift SimplifyGlobalValue.swift SimplifyInitEnumDataAddr.swift diff --git a/SwiftCompilerSources/Sources/Optimizer/InstructionSimplification/SimplifyEndCOWMutationAddr.swift b/SwiftCompilerSources/Sources/Optimizer/InstructionSimplification/SimplifyEndCOWMutationAddr.swift new file mode 100644 index 00000000000..b68aba70fc5 --- /dev/null +++ b/SwiftCompilerSources/Sources/Optimizer/InstructionSimplification/SimplifyEndCOWMutationAddr.swift @@ -0,0 +1,32 @@ +//===--- SimplifyEndCOWMutationAddr.swift ---------------------------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2025 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// + +import SIL + +// Simplify end_cow_mutation_addr to end_cow_mutation when it's operand is loadable +extension EndCOWMutationAddrInst: OnoneSimplifiable, SILCombineSimplifiable { + func simplify(_ context: SimplifyContext) { + let address = operand.value + if !address.type.isLoadable(in: parentFunction) { + return + } + if address.type.isTrivial(in: parentFunction) { + context.erase(instruction: self) + return + } + let builder = Builder(before: self, context) + let load = builder.createLoad(fromAddress: address, ownership: parentFunction.hasOwnership ? .take : .unqualified) + let endCOWMutation = builder.createEndCOWMutation(instance: load, keepUnique: false) + builder.createStore(source: endCOWMutation, destination: address, ownership: parentFunction.hasOwnership ? .initialize : .unqualified) + context.erase(instruction: self) + } +} diff --git a/SwiftCompilerSources/Sources/Optimizer/InstructionSimplification/SimplifyMisc.swift b/SwiftCompilerSources/Sources/Optimizer/InstructionSimplification/SimplifyMisc.swift index 2ad1e3c0e76..2f571a61768 100644 --- a/SwiftCompilerSources/Sources/Optimizer/InstructionSimplification/SimplifyMisc.swift +++ b/SwiftCompilerSources/Sources/Optimizer/InstructionSimplification/SimplifyMisc.swift @@ -30,3 +30,4 @@ extension TypeValueInst: OnoneSimplifiable, SILCombineSimplifiable { context.erase(instruction: self) } } + diff --git a/SwiftCompilerSources/Sources/Optimizer/PassManager/PassRegistration.swift b/SwiftCompilerSources/Sources/Optimizer/PassManager/PassRegistration.swift index 16cfe109e6b..ba709d6c689 100644 --- a/SwiftCompilerSources/Sources/Optimizer/PassManager/PassRegistration.swift +++ b/SwiftCompilerSources/Sources/Optimizer/PassManager/PassRegistration.swift @@ -136,6 +136,7 @@ private func registerSwiftPasses() { registerForSILCombine(AllocStackInst.self, { run(AllocStackInst.self, $0) }) registerForSILCombine(ApplyInst.self, { run(ApplyInst.self, $0) }) registerForSILCombine(TryApplyInst.self, { run(TryApplyInst.self, $0) }) + registerForSILCombine(EndCOWMutationAddrInst.self, { run(EndCOWMutationAddrInst.self, $0) }) // Test passes registerPass(aliasInfoDumper, { aliasInfoDumper.run($0) }) diff --git a/lib/IRGen/LoadableByAddress.cpp b/lib/IRGen/LoadableByAddress.cpp index f37f17f1b8f..349539a83e3 100644 --- a/lib/IRGen/LoadableByAddress.cpp +++ b/lib/IRGen/LoadableByAddress.cpp @@ -3984,6 +3984,14 @@ protected: singleValueInstructionFallback(kp); } + void visitEndCOWMutationInst(EndCOWMutationInst *endCOW) { + // This instruction is purely for semantic tracking in SIL. + // Simply forward the value and delete the instruction. + auto valAddr = assignment.getAddressForValue(endCOW->getOperand()); + assignment.mapValueToAddress(endCOW, valAddr); + assignment.markForDeletion(endCOW); + } + void visitMarkDependenceInst(MarkDependenceInst *mark) { // This instruction is purely for semantic tracking in SIL. // Simply forward the value and delete the instruction. diff --git a/lib/SILOptimizer/SILCombiner/Simplifications.def b/lib/SILOptimizer/SILCombiner/Simplifications.def index 6e8649bacd7..0ac82f02931 100644 --- a/lib/SILOptimizer/SILCombiner/Simplifications.def +++ b/lib/SILOptimizer/SILCombiner/Simplifications.def @@ -52,6 +52,7 @@ INSTRUCTION_SIMPLIFICATION(TypeValueInst) INSTRUCTION_SIMPLIFICATION(UncheckedAddrCastInst) INSTRUCTION_SIMPLIFICATION(UncheckedEnumDataInst) INSTRUCTION_SIMPLIFICATION(WitnessMethodInst) +INSTRUCTION_SIMPLIFICATION(EndCOWMutationAddrInst) INSTRUCTION_SIMPLIFICATION_WITH_LEGACY(AllocStackInst) INSTRUCTION_SIMPLIFICATION_WITH_LEGACY(UnconditionalCheckedCastInst) INSTRUCTION_SIMPLIFICATION_WITH_LEGACY(ApplyInst) diff --git a/test/SILOptimizer/simplify_end_cow_mutation_addr.sil b/test/SILOptimizer/simplify_end_cow_mutation_addr.sil new file mode 100644 index 00000000000..6b0f8a88a7e --- /dev/null +++ b/test/SILOptimizer/simplify_end_cow_mutation_addr.sil @@ -0,0 +1,45 @@ +// RUN: %target-sil-opt %s -onone-simplification -simplify-instruction=end_cow_mutation_addr -enable-experimental-feature Lifetimes | %FileCheck %s + +// REQUIRES: swift_feature_Lifetimes + +import Swift +import Builtin + +protocol P { + mutating func getMutableSpan() -> MutableSpan +} + +struct C : P { + @_hasStorage var array: [Int] { get set } + mutating func getMutableSpan() -> MutableSpan + init(array: [Int]) +} + +extension Array : P where Element == Int { + mutating func getMutableSpan() -> MutableSpan +} + +sil @getMutableSpan : $@convention(method) (@inout Array) -> @lifetime(borrow 0) @owned MutableSpan +sil @write : $@convention(thin) (@lifetime(copy 0) @inout MutableSpan) -> () + +// CHECK-LABEL: sil hidden @test_end_cow_mutation_addr : +// CHECK-NOT: end_cow_mutation_addr +// CHECK: end_cow_mutation +// CHECK: } // end sil function 'test_end_cow_mutation_addr' +sil hidden @test_end_cow_mutation_addr : $@convention(thin) (@inout C) -> () { +bb0(%0 : $*C): + %3 = alloc_stack [lexical] [var_decl] $MutableSpan, var, name "span" + %5 = struct_element_addr %0, #C.array + %6 = function_ref @getMutableSpan : $@convention(method) (@inout Array) -> @lifetime(borrow 0) @owned MutableSpan + %7 = apply %6(%5) : $@convention(method) (@inout Array) -> @lifetime(borrow 0) @owned MutableSpan + %8 = mark_dependence [nonescaping] %7 on %0 + %9 = mark_dependence [nonescaping] %8 on %0 + %10 = mark_dependence [nonescaping] %9 on %0 + store %10 to %3 + %12 = function_ref @write : $@convention(thin) (@lifetime(copy 0) @inout MutableSpan) -> () + %13 = apply %12(%3) : $@convention(thin) (@lifetime(copy 0) @inout MutableSpan) -> () + end_cow_mutation_addr %0 + dealloc_stack %3 + %17 = tuple () + return %17 +}