Skip to content

Commit 5a3ab6e

Browse files
committed
Swift Optimizer: add simplifications for destructure_struct and destructure_tuple
Eliminate the redundant instruction pair ``` %t = tuple (%0, %1, %2) (%3, %4, %5) = destructure_tuple %t ``` and replace the results %3, %4, %5 with %0, %1, %2, respectively. The same for structs.
1 parent 0a05124 commit 5a3ab6e

File tree

4 files changed

+206
-0
lines changed

4 files changed

+206
-0
lines changed

SwiftCompilerSources/Sources/Optimizer/InstructionSimplification/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ swift_compiler_sources(Optimizer
1414
SimplifyCondBranch.swift
1515
SimplifyCondFail.swift
1616
SimplifyDebugStep.swift
17+
SimplifyDestructure.swift
1718
SimplifyGlobalValue.swift
1819
SimplifyStrongRetainRelease.swift
1920
SimplifyStructExtract.swift
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
//===--- SimplifyDestructure.swift ----------------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2023 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 DestructureTupleInst : OnoneSimplifyable {
16+
func simplify(_ context: SimplifyContext) {
17+
18+
// Eliminate the redundant instruction pair
19+
// ```
20+
// %t = tuple (%0, %1, %2)
21+
// (%3, %4, %5) = destructure_tuple %t
22+
// ```
23+
// and replace the results %3, %4, %5 with %0, %1, %2, respectively
24+
//
25+
if let tuple = self.tuple as? TupleInst {
26+
tryReplaceConstructDestructPair(construct: tuple, destruct: self, context)
27+
}
28+
}
29+
}
30+
31+
extension DestructureStructInst : OnoneSimplifyable {
32+
func simplify(_ context: SimplifyContext) {
33+
34+
// Eliminate the redundant instruction pair
35+
// ```
36+
// %s = struct (%0, %1, %2)
37+
// (%3, %4, %5) = destructure_struct %s
38+
// ```
39+
// and replace the results %3, %4, %5 with %0, %1, %2, respectively
40+
//
41+
if let str = self.struct as? StructInst {
42+
tryReplaceConstructDestructPair(construct: str, destruct: self, context)
43+
}
44+
}
45+
}
46+
47+
private func tryReplaceConstructDestructPair(construct: SingleValueInstruction,
48+
destruct: MultipleValueInstruction,
49+
_ context: SimplifyContext) {
50+
let singleUse = context.preserveDebugInfo ? construct.uses.singleUse : construct.uses.singleNonDebugUse
51+
let canEraseFirst = singleUse?.instruction == destruct
52+
53+
if !canEraseFirst && construct.parentFunction.hasOwnership && construct.ownership == .owned {
54+
// We cannot add more uses to this tuple without inserting a copy.
55+
return
56+
}
57+
58+
for (result, operand) in zip(destruct.results, construct.operands) {
59+
result.uses.replaceAll(with: operand.value, context)
60+
}
61+
62+
if canEraseFirst {
63+
context.erase(instructionIncludingDebugUses: destruct)
64+
}
65+
}
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
// RUN: %target-sil-opt -enable-sil-verify-all %s -onone-simplification -simplify-instruction=destructure_struct | %FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-ONONE
2+
// RUN: %target-sil-opt -enable-sil-verify-all %s -simplification -simplify-instruction=destructure_struct | %FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-O
3+
4+
// REQUIRES: swift_in_compiler
5+
6+
import Swift
7+
import Builtin
8+
9+
struct S {
10+
@_hasStorage let a: String
11+
@_hasStorage let b: Int
12+
}
13+
14+
// CHECK-LABEL: sil [ossa] @forward_owned :
15+
// CHECK-NOT: destructure_tuple
16+
// CHECK: fix_lifetime %1
17+
// CHECK: return %0
18+
// CHECK: } // end sil function 'forward_owned'
19+
sil [ossa] @forward_owned : $@convention(thin) (@owned String, Int) -> @owned String {
20+
bb0(%0 : @owned $String, %1 : $Int):
21+
%2 = struct $S (%0 : $String, %1 : $Int)
22+
(%3, %4) = destructure_struct %2 : $S
23+
fix_lifetime %4 : $Int
24+
return %3 : $String
25+
}
26+
27+
// CHECK-LABEL: sil [ossa] @forward_borrowed :
28+
// CHECK-NOT: destructure_struct
29+
// CHECK: fix_lifetime %0
30+
// CHECK: fix_lifetime %1
31+
// CHECK: } // end sil function 'forward_borrowed'
32+
sil [ossa] @forward_borrowed : $@convention(thin) (@guaranteed String, Int) -> () {
33+
bb0(%0 : @guaranteed $String, %1 : $Int):
34+
%2 = struct $S (%0 : $String, %1 : $Int)
35+
(%3, %4) = destructure_struct %2 : $S
36+
fix_lifetime %3 : $String
37+
fix_lifetime %4 : $Int
38+
%7 = tuple ()
39+
return %7 : $()
40+
}
41+
42+
// CHECK-LABEL: sil [ossa] @dont_forward_owned_with_uses :
43+
// CHECK: (%5, %6) = destructure_struct %2 : $S
44+
// CHECK: fix_lifetime %6
45+
// CHECK: return %5
46+
// CHECK: } // end sil function 'dont_forward_owned_with_uses'
47+
sil [ossa] @dont_forward_owned_with_uses : $@convention(thin) (@owned String, Int) -> @owned String {
48+
bb0(%0 : @owned $String, %1 : $Int):
49+
%2 = struct $S (%0 : $String, %1 : $Int)
50+
%3 = begin_borrow %2 : $S
51+
end_borrow %3 : $S
52+
(%5, %6) = destructure_struct %2 : $S
53+
fix_lifetime %6 : $Int
54+
return %5 : $String
55+
}
56+
57+
// CHECK-LABEL: sil [ossa] @forward_owned_with_debug_use :
58+
// CHECK-ONONE: (%4, %5) = destructure_struct %2 : $S
59+
// CHECK-ONONE: fix_lifetime %5
60+
// CHECK-ONONE: return %4
61+
// CHECK-O: fix_lifetime %1
62+
// CHECK-O: return %0
63+
// CHECK: } // end sil function 'forward_owned_with_debug_use'
64+
sil [ossa] @forward_owned_with_debug_use : $@convention(thin) (@owned String, Int) -> @owned String {
65+
bb0(%0 : @owned $String, %1 : $Int):
66+
%2 = struct $S (%0 : $String, %1 : $Int)
67+
debug_value %2 : $S, let, name "s"
68+
(%4, %5) = destructure_struct %2 : $S
69+
fix_lifetime %5 : $Int
70+
return %4 : $String
71+
}
72+
73+
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
// RUN: %target-sil-opt -enable-sil-verify-all %s -onone-simplification -simplify-instruction=destructure_tuple | %FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-ONONE
2+
// RUN: %target-sil-opt -enable-sil-verify-all %s -simplification -simplify-instruction=destructure_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: destructure_tuple
11+
// CHECK: fix_lifetime %1
12+
// CHECK: return %0
13+
// CHECK: } // end sil function 'forward_owned'
14+
sil [ossa] @forward_owned : $@convention(thin) (@owned String, Int) -> @owned String {
15+
bb0(%0 : @owned $String, %1 : $Int):
16+
%2 = tuple (%0 : $String, %1 : $Int)
17+
(%3, %4) = destructure_tuple %2 : $(String, Int)
18+
fix_lifetime %4 : $Int
19+
return %3 : $String
20+
}
21+
22+
// CHECK-LABEL: sil [ossa] @forward_borrowed :
23+
// CHECK-NOT: destructure_tuple
24+
// CHECK: fix_lifetime %0
25+
// CHECK: fix_lifetime %1
26+
// CHECK: } // end sil function 'forward_borrowed'
27+
sil [ossa] @forward_borrowed : $@convention(thin) (@guaranteed String, Int) -> () {
28+
bb0(%0 : @guaranteed $String, %1 : $Int):
29+
%2 = tuple (%0 : $String, %1 : $Int)
30+
(%3, %4) = destructure_tuple %2 : $(String, Int)
31+
fix_lifetime %3 : $String
32+
fix_lifetime %4 : $Int
33+
%7 = tuple ()
34+
return %7 : $()
35+
}
36+
37+
// CHECK-LABEL: sil [ossa] @dont_forward_owned_with_uses :
38+
// CHECK: (%5, %6) = destructure_tuple %2 : $(String, Int)
39+
// CHECK: fix_lifetime %6
40+
// CHECK: return %5
41+
// CHECK: } // end sil function 'dont_forward_owned_with_uses'
42+
sil [ossa] @dont_forward_owned_with_uses : $@convention(thin) (@owned String, Int) -> @owned String {
43+
bb0(%0 : @owned $String, %1 : $Int):
44+
%2 = tuple (%0 : $String, %1 : $Int)
45+
%3 = begin_borrow %2 : $(String, Int)
46+
end_borrow %3 : $(String, Int)
47+
(%5, %6) = destructure_tuple %2 : $(String, Int)
48+
fix_lifetime %6 : $Int
49+
return %5 : $String
50+
}
51+
52+
// CHECK-LABEL: sil [ossa] @forward_owned_with_debug_use :
53+
// CHECK-ONONE: (%4, %5) = destructure_tuple %2 : $(String, Int)
54+
// CHECK-ONONE: fix_lifetime %5
55+
// CHECK-ONONE: return %4
56+
// CHECK-O: fix_lifetime %1
57+
// CHECK-O: return %0
58+
// CHECK: } // end sil function 'forward_owned_with_debug_use'
59+
sil [ossa] @forward_owned_with_debug_use : $@convention(thin) (@owned String, Int) -> @owned String {
60+
bb0(%0 : @owned $String, %1 : $Int):
61+
%2 = tuple (%0 : $String, %1 : $Int)
62+
debug_value %2 : $(String, Int), let, name "t"
63+
(%4, %5) = destructure_tuple %2 : $(String, Int)
64+
fix_lifetime %5 : $Int
65+
return %4 : $String
66+
}
67+

0 commit comments

Comments
 (0)