Skip to content

Commit efc01b8

Browse files
committed
Optimizer: run TempRValueElimination also at Onone
Introduce a new pass MandatoryTempRValueElimination, which works as the original TempRValueElimination, except that it does not remove any alloc_stack instruction which are associated with source variables. Running this pass at Onone helps to reduce copies of large structs, e.g. InlineArrays or structs containing InlineArrays. Copying large structs can be a performance problem, even at Onone. rdar://151629149
1 parent 0601198 commit efc01b8

File tree

16 files changed

+115
-64
lines changed

16 files changed

+115
-64
lines changed

SwiftCompilerSources/Sources/Optimizer/FunctionPasses/TempRValueElimination.swift

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,15 @@ import SIL
3636
///
3737
let tempRValueElimination = FunctionPass(name: "temp-rvalue-elimination") {
3838
(function: Function, context: FunctionPassContext) in
39+
removeTempRValues(in: function, keepDebugInfo: false, context)
40+
}
3941

42+
let mandatoryTempRValueElimination = FunctionPass(name: "mandatory-temp-rvalue-elimination") {
43+
(function: Function, context: FunctionPassContext) in
44+
removeTempRValues(in: function, keepDebugInfo: true, context)
45+
}
46+
47+
private func removeTempRValues(in function: Function, keepDebugInfo: Bool, _ context: FunctionPassContext) {
4048
for inst in function.instructions {
4149
switch inst {
4250
case let copy as CopyAddrInst:
@@ -45,12 +53,12 @@ let tempRValueElimination = FunctionPass(name: "temp-rvalue-elimination") {
4553
// copied the `alloc_stack` back to the source location.
4654
context.erase(instruction: copy)
4755
} else {
48-
tryEliminate(copy: copy, context)
56+
tryEliminate(copy: copy, keepDebugInfo: keepDebugInfo, context)
4957
}
5058
case let store as StoreInst:
5159
// Also handle `load`-`store` pairs which are basically the same thing as a `copy_addr`.
5260
if let load = store.source as? LoadInst, load.uses.isSingleUse, load.parentBlock == store.parentBlock {
53-
tryEliminate(copy: store, context)
61+
tryEliminate(copy: store, keepDebugInfo: keepDebugInfo, context)
5462
}
5563
default:
5664
break
@@ -82,9 +90,10 @@ extension StoreInst: CopyLikeInstruction {
8290
private var load: LoadInst { source as! LoadInst }
8391
}
8492

85-
private func tryEliminate(copy: CopyLikeInstruction, _ context: FunctionPassContext) {
93+
private func tryEliminate(copy: CopyLikeInstruction, keepDebugInfo: Bool, _ context: FunctionPassContext) {
8694

87-
guard let (allocStack, lastUseOfAllocStack) = getRemovableAllocStackDestination(of: copy, context) else {
95+
guard let (allocStack, lastUseOfAllocStack) =
96+
getRemovableAllocStackDestination(of: copy, keepDebugInfo: keepDebugInfo, context) else {
8897
return
8998
}
9099

@@ -138,18 +147,24 @@ private func tryEliminate(copy: CopyLikeInstruction, _ context: FunctionPassCont
138147
/// %lastUseOfAllocStack = load %allocStack
139148
/// ```
140149
private func getRemovableAllocStackDestination(
141-
of copy: CopyLikeInstruction, _ context: FunctionPassContext
150+
of copy: CopyLikeInstruction, keepDebugInfo: Bool, _ context: FunctionPassContext
142151
) -> (allocStack: AllocStackInst, lastUseOfAllocStack: Instruction)? {
143152
guard copy.isInitializationOfDestination,
144153
let allocStack = copy.destinationAddress as? AllocStackInst
145154
else {
146155
return nil
147156
}
148157

149-
// If the `allocStack` is lexical we can eliminate it if the source of the copy is lexical and
150-
// it is live for longer than the `allocStack`.
151-
if allocStack.isLexical && !copy.sourceAddress.accessBase.storageIsLexical {
152-
return nil
158+
if keepDebugInfo {
159+
if allocStack.isFromVarDecl || allocStack.isLexical {
160+
return nil
161+
}
162+
} else {
163+
// If the `allocStack` is lexical we can eliminate it if the source of the copy is lexical and
164+
// it is live for longer than the `allocStack`.
165+
if allocStack.isLexical && !copy.sourceAddress.accessBase.storageIsLexical {
166+
return nil
167+
}
153168
}
154169

155170
var allocStackUses = UseCollector(copy: copy, context)

SwiftCompilerSources/Sources/Optimizer/PassManager/PassRegistration.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,7 @@ private func registerSwiftPasses() {
101101
registerPass(lifetimeDependenceScopeFixupPass, { lifetimeDependenceScopeFixupPass.run($0) })
102102
registerPass(copyToBorrowOptimization, { copyToBorrowOptimization.run($0) })
103103
registerPass(tempRValueElimination, { tempRValueElimination.run($0) })
104+
registerPass(mandatoryTempRValueElimination, { mandatoryTempRValueElimination.run($0) })
104105
registerPass(generalClosureSpecialization, { generalClosureSpecialization.run($0) })
105106
registerPass(autodiffClosureSpecialization, { autodiffClosureSpecialization.run($0) })
106107

include/swift/SILOptimizer/PassManager/Passes.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,8 @@ PASS(StackPromotion, "stack-promotion",
140140
"Stack Promotion of Class Objects")
141141
PASS(UpdateBorrowedFrom, "update-borrowed-from",
142142
"Test pass for update borrowed-from instructions")
143+
PASS(MandatoryTempRValueElimination, "mandatory-temp-rvalue-elimination",
144+
"Mandatory remove short-lived immutable temporary copies")
143145
PASS(TempRValueElimination, "temp-rvalue-elimination",
144146
"Remove short-lived immutable temporary copies")
145147

lib/SILOptimizer/PassManager/PassPipeline.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1082,6 +1082,9 @@ SILPassPipelinePlan::getOnonePassPipeline(const SILOptions &Options) {
10821082
// Now that we have serialized, propagate debug info.
10831083
P.addMovedAsyncVarDebugInfoPropagator();
10841084

1085+
// Even at Onone it's important to remove copies of structs, especially if they are large.
1086+
P.addMandatoryTempRValueElimination();
1087+
10851088
// If we are asked to stop optimizing before lowering ownership, do so now.
10861089
if (P.Options.StopOptimizationBeforeLoweringOwnership)
10871090
return P;

test/AutoDiff/SILOptimizer/optional_pullback.swift

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,9 @@ import _Differentiation
1313
// CHECK: apply %[[ZERO1]]<τ_0_0.TangentVector>(%[[RET_TAN_BUF]], %{{.*}})
1414
// CHECK: %[[ADJ_IN_BB:.+]] = alloc_stack $τ_0_0.TangentVector
1515
//
16-
// CHECK: %[[TAN_VAL_COPY:.+]] = alloc_stack $Optional<τ_0_0.TangentVector>
17-
// CHECK: %[[TAN_BUF:.+]] = alloc_stack $Optional<τ_0_0>.TangentVector
18-
19-
// CHECK: copy_addr %[[OPT_TAN]] to [init] %[[TAN_BUF]] : $*Optional<τ_0_0>.TangentVector
20-
// CHECK: %[[TAN_VAL:.+]] = struct_element_addr %[[TAN_BUF]] : $*Optional<τ_0_0>.TangentVector, #Optional.TangentVector.value
21-
// CHECK: copy_addr %[[TAN_VAL]] to [init] %[[TAN_VAL_COPY]] : $*Optional<τ_0_0.TangentVector>
16+
// CHECK: %[[TAN_VAL:.+]] = struct_element_addr %[[OPT_TAN]] : $*Optional<τ_0_0>.TangentVector, #Optional.TangentVector.value
2217
//
23-
// CHECK: %[[TAN_DATA:.+]] = unchecked_take_enum_data_addr %[[TAN_VAL_COPY]] : $*Optional<τ_0_0.TangentVector>, #Optional.some!enumelt
18+
// CHECK: %[[TAN_DATA:.+]] = unchecked_take_enum_data_addr %[[TAN_VAL]] : $*Optional<τ_0_0.TangentVector>, #Optional.some!enumelt
2419
// CHECK: %[[PLUS_EQUAL:.+]] = witness_method $τ_0_0.TangentVector, #AdditiveArithmetic."+="
2520
// CHECK: apply %[[PLUS_EQUAL]]<τ_0_0.TangentVector>(%[[ADJ_IN_BB]], %[[TAN_DATA]], %{{.*}})
2621

@@ -29,9 +24,6 @@ import _Differentiation
2924
// CHECK: destroy_addr %[[ADJ_IN_BB]] : $*τ_0_0.TangentVector
3025

3126
// CHECK: copy_addr [take] %[[RET_TAN_BUF:.+]] to [init] %[[RET_TAN:.+]]
32-
// CHECK: destroy_addr %[[TAN_BUF]] : $*Optional<τ_0_0>.TangentVector
33-
// CHECK: dealloc_stack %[[TAN_BUF]] : $*Optional<τ_0_0>.TangentVector
34-
// CHECK: dealloc_stack %[[TAN_VAL_COPY]] : $*Optional<τ_0_0.TangentVector>
3527
// CHECK: dealloc_stack %[[RET_TAN_BUF]] : $*τ_0_0.TangentVector
3628

3729
@differentiable(reverse)

test/DebugInfo/move_function_dbginfo_async.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// RUN: %empty-directory(%t)
2-
// RUN: %target-swift-frontend -parse-as-library -target %target-swift-5.1-abi-triple -g -emit-sil -o - %s | %FileCheck -check-prefix=SIL %s
3-
// RUN: %target-swift-frontend -parse-as-library -target %target-swift-5.1-abi-triple -g -emit-ir -o - %s | %FileCheck %s
4-
// RUN: %target-swift-frontend -parse-as-library -target %target-swift-5.1-abi-triple -g -c %s -o %t/out.o
2+
// RUN: %target-swift-frontend -parse-as-library -target %target-swift-5.1-abi-triple -Xllvm -sil-disable-pass=mandatory-temp-rvalue-elimination -g -emit-sil -o - %s | %FileCheck -check-prefix=SIL %s
3+
// RUN: %target-swift-frontend -parse-as-library -target %target-swift-5.1-abi-triple -Xllvm -sil-disable-pass=mandatory-temp-rvalue-elimination -g -emit-ir -o - %s | %FileCheck %s
4+
// RUN: %target-swift-frontend -parse-as-library -target %target-swift-5.1-abi-triple -Xllvm -sil-disable-pass=mandatory-temp-rvalue-elimination -g -c %s -o %t/out.o
55

66
// This test checks that:
77
//

test/IRGen/lifetime.sil

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// RUN: %target-swift-frontend -disable-debugger-shadow-copies -gnone -emit-ir %s | %FileCheck --check-prefix=CHECK --check-prefix=CHECK-%target-cpu %s -DINT=i%target-ptrsize
1+
// RUN: %target-swift-frontend -disable-debugger-shadow-copies -Xllvm -sil-disable-pass=mandatory-temp-rvalue-elimination -gnone -emit-ir %s | %FileCheck --check-prefix=CHECK --check-prefix=CHECK-%target-cpu %s -DINT=i%target-ptrsize
22

33
sil_stage canonical
44

test/IRGen/typelayout_based_value_operation.sil

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
// RUN: %target-swift-frontend -enable-type-layout %s -emit-ir -sil-verify-all | %FileCheck %s
2-
// RUNx: %target-swift-frontend -disable-type-layout %s -emit-ir -sil-verify-all | %FileCheck %s --check-prefix=NOTYPELAYOUT
1+
// RUN: %target-swift-frontend -enable-type-layout %s -Xllvm -sil-disable-pass=mandatory-temp-rvalue-elimination -emit-ir -sil-verify-all | %FileCheck %s
2+
// RUNx: %target-swift-frontend -disable-type-layout %s -Xllvm -sil-disable-pass=mandatory-temp-rvalue-elimination -emit-ir -sil-verify-all | %FileCheck %s --check-prefix=NOTYPELAYOUT
33

44
sil_stage canonical
55
import Builtin

test/IRGen/variadic_generic_fulfillment.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// RUN: %target-swift-frontend -emit-ir %s -target %target-swift-5.9-abi-triple | %FileCheck %s -DINT=i%target-ptrsize
1+
// RUN: %target-swift-frontend -Xllvm -sil-disable-pass=mandatory-temp-rvalue-elimination -emit-ir %s -target %target-swift-5.9-abi-triple | %FileCheck %s -DINT=i%target-ptrsize
22

33
public struct G<T> {}
44

test/Interop/Cxx/class/closure-thunk-irgen.swift

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,7 @@ public func testClosureToBlock() {
2121
}
2222

2323
// CHECK: define internal void @"$s4main20testClosureToFuncPtryyFySo10NonTrivialVcfU_To"(ptr %[[V0:.*]])
24-
// CHECK: %[[V1:.*]] = alloca %{{.*}}, align 8
25-
// CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 8, ptr %[[V1]])
26-
// CHECK-NEXT: call {{void|ptr}} @_ZN10NonTrivialC{{1|2}}ERKS_(ptr %[[V1]], ptr %[[V0]])
27-
// CHECK-NEXT: call swiftcc void @"$s4main20testClosureToFuncPtryyFySo10NonTrivialVcfU_"(ptr noalias dereferenceable(8) %[[V1]])
28-
// CHECK-NEXT: call {{void|ptr}} @_ZN10NonTrivialD{{1|2}}Ev(ptr %[[V1]])
29-
// CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 8, ptr %[[V1]])
24+
// CHECK: call swiftcc void @"$s4main20testClosureToFuncPtryyFySo10NonTrivialVcfU_"(ptr noalias dereferenceable(8) %[[V0]])
3025
// CHECK-NEXT: ret void
3126

3227
public func testClosureToFuncPtr() {

0 commit comments

Comments
 (0)