From 5004e931442f2a3e13d39d1185e60eb68ead967f Mon Sep 17 00:00:00 2001 From: Nate Chandler Date: Thu, 11 Apr 2024 14:58:03 -0700 Subject: [PATCH] [OnoneSimplify] Handle tuple(destructure_tuple()). --- .../InstructionSimplification/CMakeLists.txt | 1 + .../SimplifyTuple.swift | 75 ++++++++++++++++++ test/SILOptimizer/simplify_tuple.sil | 79 +++++++++++++++++++ 3 files changed, 155 insertions(+) create mode 100644 SwiftCompilerSources/Sources/Optimizer/InstructionSimplification/SimplifyTuple.swift create mode 100644 test/SILOptimizer/simplify_tuple.sil diff --git a/SwiftCompilerSources/Sources/Optimizer/InstructionSimplification/CMakeLists.txt b/SwiftCompilerSources/Sources/Optimizer/InstructionSimplification/CMakeLists.txt index 99a5e2cbb4dd1..4e45b885da638 100644 --- a/SwiftCompilerSources/Sources/Optimizer/InstructionSimplification/CMakeLists.txt +++ b/SwiftCompilerSources/Sources/Optimizer/InstructionSimplification/CMakeLists.txt @@ -31,6 +31,7 @@ swift_compiler_sources(Optimizer SimplifyStrongRetainRelease.swift SimplifyStructExtract.swift SimplifySwitchEnum.swift + SimplifyTuple.swift SimplifyTupleExtract.swift SimplifyUncheckedEnumData.swift SimplifyValueToBridgeObject.swift) diff --git a/SwiftCompilerSources/Sources/Optimizer/InstructionSimplification/SimplifyTuple.swift b/SwiftCompilerSources/Sources/Optimizer/InstructionSimplification/SimplifyTuple.swift new file mode 100644 index 0000000000000..3079684e0c4c9 --- /dev/null +++ b/SwiftCompilerSources/Sources/Optimizer/InstructionSimplification/SimplifyTuple.swift @@ -0,0 +1,75 @@ +//===--- SimplifyTuple.swift ---------------------------------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2024 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 + +extension TupleInst : OnoneSimplifyable { + func simplify(_ context: SimplifyContext) { + + // Eliminate the redundant instruction pair + // ``` + // (%3, %4, %5) = destructure_tuple %input + // %output = tuple (%3, %4, %5) + // ``` + // and replace the result %output with %input + // + var destructure: DestructureTupleInst? + for operand in operands { + guard let def = operand.value.definingInstruction as? DestructureTupleInst else { + return + } + guard let destructure else { + destructure = def + continue + } + if destructure != def { + return + } + } + guard let destructure else { + return + } + guard destructure.operand.value.type == type else { + return + } + // The destructure's operand having the same type as the tuple ensures that + // the count of results of the destructure is equal to the count of operands + // of the tuple. + assert(destructure.results.count == operands.count) + for (result, operand) in zip(destructure.results, operands) { + if result != operand.value { + return + } + } + tryReplaceDestructConstructPair(destruct: destructure, construct: self, context) + } +} + +private func tryReplaceDestructConstructPair(destruct: MultipleValueInstruction & UnaryInstruction, + construct: SingleValueInstruction, + _ context: SimplifyContext) { + let everyResultUsedOnce = context.preserveDebugInfo + ? destruct.results.allSatisfy { $0.uses.singleUse != nil } + : destruct.results.allSatisfy { $0.uses.ignoreDebugUses.singleUse != nil } + let anyOwned = destruct.results.contains { $0.ownership == .owned } + + if !everyResultUsedOnce && construct.parentFunction.hasOwnership && anyOwned { + // We cannot add more uses to this destructure without inserting a copy. + return + } + + construct.uses.replaceAll(with: destruct.operand.value, context) + + if everyResultUsedOnce { + context.erase(instructionIncludingDebugUses: construct) + } +} diff --git a/test/SILOptimizer/simplify_tuple.sil b/test/SILOptimizer/simplify_tuple.sil new file mode 100644 index 0000000000000..8abeab78f6bfe --- /dev/null +++ b/test/SILOptimizer/simplify_tuple.sil @@ -0,0 +1,79 @@ +// RUN: %target-sil-opt -enable-sil-verify-all %s -onone-simplification -simplify-instruction=tuple | %FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-ONONE +// RUN: %target-sil-opt -enable-sil-verify-all %s -simplification -simplify-instruction=tuple | %FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-O + +// REQUIRES: swift_in_compiler + +import Swift +import Builtin + +// CHECK-LABEL: sil [ossa] @forward_owned : +// CHECK-NOT: tuple +// CHECK: return %0 +// CHECK: } // end sil function 'forward_owned' +sil [ossa] @forward_owned : $@convention(thin) (@owned (String, Int)) -> @owned (String, Int) { +bb0(%0 : @owned $(String, Int)): + (%3, %4) = destructure_tuple %0 : $(String, Int) + %2 = tuple (%3 : $String, %4 : $Int) + return %2 : $(String, Int) +} + +// CHECK-LABEL: sil [ossa] @forward_borrowed : +// CHECK-NOT: tuple +// CHECK: fix_lifetime %0 +// CHECK: } // end sil function 'forward_borrowed' +sil [ossa] @forward_borrowed : $@convention(thin) (@guaranteed (String, Int)) -> () { +bb0(%0 : @guaranteed $(String, Int)): + (%3, %4) = destructure_tuple %0 : $(String, Int) + %2 = tuple (%3 : $String, %4 : $Int) + fix_lifetime %2 : $(String, Int) + %7 = tuple () + return %7 : $() +} + +// CHECK-LABEL: sil [ossa] @dont_forward_owned_with_uses : +// CHECK: destructure_tuple +// CHECK: tuple +// CHECK: } // end sil function 'dont_forward_owned_with_uses' +sil [ossa] @dont_forward_owned_with_uses : $@convention(thin) (@owned (String, Int)) -> @owned (String, Int) { +bb0(%0 : @owned $(String, Int)): + (%5, %6) = destructure_tuple %0 : $(String, Int) + %3 = begin_borrow %5 : $String + end_borrow %3 : $String + %2 = tuple (%5 : $String, %6 : $Int) + return %2 : $(String, Int) +} + +// CHECK-LABEL: sil [ossa] @forward_owned_with_debug_use : +// CHECK-ONONE: destructure_tuple +// CHECK-ONONE: tuple +// CHECK-O: return %0 +// CHECK: } // end sil function 'forward_owned_with_debug_use' +sil [ossa] @forward_owned_with_debug_use : $@convention(thin) (@owned (String, Int)) -> @owned (String, Int) { +bb0(%0 : @owned $(String, Int)): + (%4, %5) = destructure_tuple %0 : $(String, Int) + debug_value %4 : $String, let, name "t" + %2 = tuple (%4 : $String, %5 : $Int) + return %2 : $(String, Int) +} + +// CHECK-LABEL: sil [ossa] @dont_forward_label_change : +// CHECK: destructure_tuple +// CHECK: tuple +// CHECK-LABEL: } // end sil function 'dont_forward_label_change' +sil [ossa] @dont_forward_label_change : $@convention(thin) (@owned (s: String, i: Int)) -> @owned (String, Int) { +bb0(%0 : @owned $(s: String, i: Int)): + (%4, %5) = destructure_tuple %0 : $(s: String, i: Int) + %2 = tuple (%4 : $String, %5 : $Int) + return %2 : $(String, Int) +} + +// CHECK-LABEL: sil [ossa] @dont_forward_flipped_arguments : +// CHECK: destructure_tuple +// CHECK: tuple +// CHECK-LABEL: } // end sil function 'dont_forward_flipped_arguments' +sil [ossa] @dont_forward_flipped_arguments : $@convention(thin) (@owned (String, String)) -> @owned (String, String) { +bb0(%0 : @owned $(String, String)): + (%4, %5) = destructure_tuple %0 : $(String, String) + %2 = tuple (%5 : $String, %4 : $String) + return %2 : $(String, String) +}