Skip to content

Commit 3747a28

Browse files
committed
Optimizer: add simplification for init_enum_data_addr
Optimize the sequence ``` %1 = init_enum_data_addr %enum_addr, #someCaseWithPayload store %payload to %1 inject_enum_addr %enum_addr, #someCaseWithPayload ``` to ``` %1 = enum $E, #someCaseWithPayload, %payload store %1 to %enum_addr ``` This sequence of three instructions must appear in consecutive order. But usually this is the case, because it's generated this way by SILGen.
1 parent d02765f commit 3747a28

File tree

3 files changed

+129
-0
lines changed

3 files changed

+129
-0
lines changed

SwiftCompilerSources/Sources/Optimizer/InstructionSimplification/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ swift_compiler_sources(Optimizer
1616
SimplifyDebugStep.swift
1717
SimplifyDestructure.swift
1818
SimplifyGlobalValue.swift
19+
SimplifyInitEnumDataAddr.swift
1920
SimplifyLoad.swift
2021
SimplifyPartialApply.swift
2122
SimplifyStrongRetainRelease.swift
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
//===--- SimplifyInitEnumDataAddr.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 InitEnumDataAddrInst : OnoneSimplifyable {
16+
func simplify(_ context: SimplifyContext) {
17+
18+
// Optimize the sequence
19+
// ```
20+
// %1 = init_enum_data_addr %enum_addr, #someCaseWithPayload
21+
// store %payload to %1
22+
// inject_enum_addr %enum_addr, #someCaseWithPayload
23+
// ```
24+
// to
25+
// ```
26+
// %1 = enum $E, #someCaseWithPayload, %payload
27+
// store %1 to %enum_addr
28+
// ```
29+
// This sequence of three instructions must appear in consecutive order.
30+
// But usually this is the case, because it's generated this way by SILGen.
31+
//
32+
if let nextInst = self.next,
33+
let store = nextInst as? StoreInst,
34+
store.destination == self,
35+
let singleUse = self.uses.singleUse,
36+
singleUse.instruction == store,
37+
let nextAfterStore = store.next,
38+
let inject = nextAfterStore as? InjectEnumAddrInst,
39+
inject.enum == self.enum,
40+
inject.enum.type.isLoadable(in: parentFunction) {
41+
42+
assert(self.caseIndex == inject.caseIndex, "mismatching case indices when creating an enum")
43+
44+
let builder = Builder(before: store, context)
45+
let enumInst = builder.createEnum(caseIndex: self.caseIndex, payload: store.source, enumType: self.enum.type.objectType)
46+
let storeOwnership = StoreInst.Ownership(for: self.enum.type, in: parentFunction, initialize: true)
47+
builder.createStore(source: enumInst, destination: self.enum, ownership: storeOwnership)
48+
context.erase(instruction: store)
49+
context.erase(instruction: inject)
50+
context.erase(instruction: self)
51+
}
52+
}
53+
}
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
// RUN: %target-sil-opt -enable-sil-verify-all %s -onone-simplification -simplify-instruction=init_enum_data_addr | %FileCheck %s
2+
3+
// REQUIRES: swift_in_compiler
4+
5+
import Swift
6+
import Builtin
7+
8+
enum E {
9+
case A(Int)
10+
case B(AnyObject)
11+
}
12+
13+
enum GenE<T> {
14+
case A(Int)
15+
case B(T)
16+
}
17+
// CHECK-LABEL: sil @optional_int
18+
// CHECK: %2 = enum $Optional<Int>, #Optional.some!enumelt, %1 : $Int
19+
// CHECK: store %2 to %0 : $*Optional<Int>
20+
// CHECK: %4 = tuple ()
21+
// CHECK: return %4
22+
// CHECK: } // end sil function 'optional_int'
23+
sil @optional_int : $@convention(thin) (Int) -> @out Optional<Int> {
24+
bb0(%0 : $*Optional<Int>, %1 : $Int):
25+
%2 = init_enum_data_addr %0 : $*Optional<Int>, #Optional.some!enumelt
26+
store %1 to %2 : $*Int
27+
inject_enum_addr %0 : $*Optional<Int>, #Optional.some!enumelt
28+
%5 = tuple ()
29+
return %5 : $()
30+
}
31+
32+
// CHECK-LABEL: sil [ossa] @ossa_trivial
33+
// CHECK: %2 = enum $Optional<Int>, #Optional.some!enumelt, %1 : $Int
34+
// CHECK: store %2 to [trivial] %0 : $*Optional<Int>
35+
// CHECK: %4 = tuple ()
36+
// CHECK: return %4
37+
// CHECK: } // end sil function 'ossa_trivial'
38+
sil [ossa] @ossa_trivial : $@convention(thin) (Int) -> @out Optional<Int> {
39+
bb0(%0 : $*Optional<Int>, %1 : $Int):
40+
%2 = init_enum_data_addr %0 : $*Optional<Int>, #Optional.some!enumelt
41+
store %1 to [trivial] %2 : $*Int
42+
inject_enum_addr %0 : $*Optional<Int>, #Optional.some!enumelt
43+
%5 = tuple ()
44+
return %5 : $()
45+
}
46+
47+
// CHECK-LABEL: sil [ossa] @ossa_nontrivial
48+
// CHECK: %2 = enum $E, #E.A!enumelt, %1 : $Int
49+
// CHECK: store %2 to [init] %0 : $*E
50+
// CHECK: %4 = tuple ()
51+
// CHECK: return %4
52+
// CHECK: } // end sil function 'ossa_nontrivial'
53+
sil [ossa] @ossa_nontrivial : $@convention(thin) (Int) -> @out E {
54+
bb0(%0 : $*E, %1 : $Int):
55+
%2 = init_enum_data_addr %0 : $*E, #E.A!enumelt
56+
store %1 to [trivial] %2 : $*Int
57+
inject_enum_addr %0 : $*E, #E.A!enumelt
58+
%5 = tuple ()
59+
return %5 : $()
60+
}
61+
62+
// CHECK-LABEL: sil [ossa] @not_loadable
63+
// CHECK: %2 = init_enum_data_addr
64+
// CHECK: store %1 to [trivial] %2
65+
// CHECK: inject_enum_addr
66+
// CHECK: } // end sil function 'not_loadable'
67+
sil [ossa] @not_loadable : $@convention(thin) <T> (Int) -> @out GenE<T> {
68+
bb0(%0 : $*GenE<T>, %1 : $Int):
69+
%2 = init_enum_data_addr %0 : $*GenE<T>, #GenE.A!enumelt
70+
store %1 to [trivial] %2 : $*Int
71+
inject_enum_addr %0 : $*GenE<T>, #GenE.A!enumelt
72+
%5 = tuple ()
73+
return %5 : $()
74+
}
75+

0 commit comments

Comments
 (0)