Skip to content

Commit 5004e93

Browse files
committed
[OnoneSimplify] Handle tuple(destructure_tuple()).
1 parent cbf9cb2 commit 5004e93

File tree

3 files changed

+155
-0
lines changed

3 files changed

+155
-0
lines changed

SwiftCompilerSources/Sources/Optimizer/InstructionSimplification/CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ swift_compiler_sources(Optimizer
3131
SimplifyStrongRetainRelease.swift
3232
SimplifyStructExtract.swift
3333
SimplifySwitchEnum.swift
34+
SimplifyTuple.swift
3435
SimplifyTupleExtract.swift
3536
SimplifyUncheckedEnumData.swift
3637
SimplifyValueToBridgeObject.swift)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
//===--- SimplifyTuple.swift ---------------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2024 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
import SIL
14+
15+
extension TupleInst : OnoneSimplifyable {
16+
func simplify(_ context: SimplifyContext) {
17+
18+
// Eliminate the redundant instruction pair
19+
// ```
20+
// (%3, %4, %5) = destructure_tuple %input
21+
// %output = tuple (%3, %4, %5)
22+
// ```
23+
// and replace the result %output with %input
24+
//
25+
var destructure: DestructureTupleInst?
26+
for operand in operands {
27+
guard let def = operand.value.definingInstruction as? DestructureTupleInst else {
28+
return
29+
}
30+
guard let destructure else {
31+
destructure = def
32+
continue
33+
}
34+
if destructure != def {
35+
return
36+
}
37+
}
38+
guard let destructure else {
39+
return
40+
}
41+
guard destructure.operand.value.type == type else {
42+
return
43+
}
44+
// The destructure's operand having the same type as the tuple ensures that
45+
// the count of results of the destructure is equal to the count of operands
46+
// of the tuple.
47+
assert(destructure.results.count == operands.count)
48+
for (result, operand) in zip(destructure.results, operands) {
49+
if result != operand.value {
50+
return
51+
}
52+
}
53+
tryReplaceDestructConstructPair(destruct: destructure, construct: self, context)
54+
}
55+
}
56+
57+
private func tryReplaceDestructConstructPair(destruct: MultipleValueInstruction & UnaryInstruction,
58+
construct: SingleValueInstruction,
59+
_ context: SimplifyContext) {
60+
let everyResultUsedOnce = context.preserveDebugInfo
61+
? destruct.results.allSatisfy { $0.uses.singleUse != nil }
62+
: destruct.results.allSatisfy { $0.uses.ignoreDebugUses.singleUse != nil }
63+
let anyOwned = destruct.results.contains { $0.ownership == .owned }
64+
65+
if !everyResultUsedOnce && construct.parentFunction.hasOwnership && anyOwned {
66+
// We cannot add more uses to this destructure without inserting a copy.
67+
return
68+
}
69+
70+
construct.uses.replaceAll(with: destruct.operand.value, context)
71+
72+
if everyResultUsedOnce {
73+
context.erase(instructionIncludingDebugUses: construct)
74+
}
75+
}

test/SILOptimizer/simplify_tuple.sil

+79
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
// RUN: %target-sil-opt -enable-sil-verify-all %s -onone-simplification -simplify-instruction=tuple | %FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-ONONE
2+
// RUN: %target-sil-opt -enable-sil-verify-all %s -simplification -simplify-instruction=tuple | %FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-O
3+
4+
// REQUIRES: swift_in_compiler
5+
6+
import Swift
7+
import Builtin
8+
9+
// CHECK-LABEL: sil [ossa] @forward_owned :
10+
// CHECK-NOT: tuple
11+
// CHECK: return %0
12+
// CHECK: } // end sil function 'forward_owned'
13+
sil [ossa] @forward_owned : $@convention(thin) (@owned (String, Int)) -> @owned (String, Int) {
14+
bb0(%0 : @owned $(String, Int)):
15+
(%3, %4) = destructure_tuple %0 : $(String, Int)
16+
%2 = tuple (%3 : $String, %4 : $Int)
17+
return %2 : $(String, Int)
18+
}
19+
20+
// CHECK-LABEL: sil [ossa] @forward_borrowed :
21+
// CHECK-NOT: tuple
22+
// CHECK: fix_lifetime %0
23+
// CHECK: } // end sil function 'forward_borrowed'
24+
sil [ossa] @forward_borrowed : $@convention(thin) (@guaranteed (String, Int)) -> () {
25+
bb0(%0 : @guaranteed $(String, Int)):
26+
(%3, %4) = destructure_tuple %0 : $(String, Int)
27+
%2 = tuple (%3 : $String, %4 : $Int)
28+
fix_lifetime %2 : $(String, Int)
29+
%7 = tuple ()
30+
return %7 : $()
31+
}
32+
33+
// CHECK-LABEL: sil [ossa] @dont_forward_owned_with_uses :
34+
// CHECK: destructure_tuple
35+
// CHECK: tuple
36+
// CHECK: } // end sil function 'dont_forward_owned_with_uses'
37+
sil [ossa] @dont_forward_owned_with_uses : $@convention(thin) (@owned (String, Int)) -> @owned (String, Int) {
38+
bb0(%0 : @owned $(String, Int)):
39+
(%5, %6) = destructure_tuple %0 : $(String, Int)
40+
%3 = begin_borrow %5 : $String
41+
end_borrow %3 : $String
42+
%2 = tuple (%5 : $String, %6 : $Int)
43+
return %2 : $(String, Int)
44+
}
45+
46+
// CHECK-LABEL: sil [ossa] @forward_owned_with_debug_use :
47+
// CHECK-ONONE: destructure_tuple
48+
// CHECK-ONONE: tuple
49+
// CHECK-O: return %0
50+
// CHECK: } // end sil function 'forward_owned_with_debug_use'
51+
sil [ossa] @forward_owned_with_debug_use : $@convention(thin) (@owned (String, Int)) -> @owned (String, Int) {
52+
bb0(%0 : @owned $(String, Int)):
53+
(%4, %5) = destructure_tuple %0 : $(String, Int)
54+
debug_value %4 : $String, let, name "t"
55+
%2 = tuple (%4 : $String, %5 : $Int)
56+
return %2 : $(String, Int)
57+
}
58+
59+
// CHECK-LABEL: sil [ossa] @dont_forward_label_change :
60+
// CHECK: destructure_tuple
61+
// CHECK: tuple
62+
// CHECK-LABEL: } // end sil function 'dont_forward_label_change'
63+
sil [ossa] @dont_forward_label_change : $@convention(thin) (@owned (s: String, i: Int)) -> @owned (String, Int) {
64+
bb0(%0 : @owned $(s: String, i: Int)):
65+
(%4, %5) = destructure_tuple %0 : $(s: String, i: Int)
66+
%2 = tuple (%4 : $String, %5 : $Int)
67+
return %2 : $(String, Int)
68+
}
69+
70+
// CHECK-LABEL: sil [ossa] @dont_forward_flipped_arguments :
71+
// CHECK: destructure_tuple
72+
// CHECK: tuple
73+
// CHECK-LABEL: } // end sil function 'dont_forward_flipped_arguments'
74+
sil [ossa] @dont_forward_flipped_arguments : $@convention(thin) (@owned (String, String)) -> @owned (String, String) {
75+
bb0(%0 : @owned $(String, String)):
76+
(%4, %5) = destructure_tuple %0 : $(String, String)
77+
%2 = tuple (%5 : $String, %4 : $String)
78+
return %2 : $(String, String)
79+
}

0 commit comments

Comments
 (0)