28
28
#include " swift/SILOptimizer/PassManager/Transforms.h"
29
29
#include " swift/SILOptimizer/Utils/InstOptUtils.h"
30
30
#include " llvm/ADT/Statistic.h"
31
+ #include " llvm/Support/CommandLine.h"
31
32
#include " llvm/Support/Debug.h"
32
33
33
34
using namespace swift ;
34
35
using namespace swift ::Lowering;
35
36
36
37
STATISTIC (NumExpand, " Number of instructions expanded" );
37
38
39
+ static llvm::cl::opt<bool > EnableExpandAll (" sil-lower-agg-instrs-expand-all" ,
40
+ llvm::cl::init (false ));
41
+
42
+ // ===----------------------------------------------------------------------===//
43
+ // Utility
44
+ // ===----------------------------------------------------------------------===//
45
+
46
+ // / We only expand if we are not in ownership and shouldExpand is true. The
47
+ // / reason why is that this was originally done to help the low level ARC
48
+ // / optimizer. To the high level ARC optimizer, this is just noise and
49
+ // / unnecessary IR. At the same time for testing purposes, we want to provide a
50
+ // / way even with ownership enabled to expand so we can check correctness.
51
+ static bool shouldExpandShim (SILFunction *fn, SILType type) {
52
+ return EnableExpandAll ||
53
+ (!fn->hasOwnership () && shouldExpand (fn->getModule (), type));
54
+ }
55
+
38
56
// ===----------------------------------------------------------------------===//
39
57
// Higher Level Operation Expansion
40
58
// ===----------------------------------------------------------------------===//
@@ -43,106 +61,110 @@ STATISTIC(NumExpand, "Number of instructions expanded");
43
61
// / non-address only type. We do this here so we can process the resulting
44
62
// / loads/stores.
45
63
// /
46
- // / This peephole implements the following optimizations:
64
+ // / This peephole implements the following optimizations with the ossa version
65
+ // / of the optimization first.
47
66
// /
48
67
// / copy_addr %0 to %1 : $*T
49
68
// / ->
69
+ // / %new = load [copy] %0 : $*T
70
+ // / store %new to [assign] %1 : $*T
71
+ // / ->
50
72
// / %new = load %0 : $*T // Load the new value from the source
51
- // / %old = load %1 : $*T // Load the old value from the destination
52
73
// / strong_retain %new : $T // Retain the new value
74
+ // / %old = load %1 : $*T // Load the old value from the destination
53
75
// / strong_release %old : $T // Release the old
54
76
// / store %new to %1 : $*T // Store the new value to the destination
55
77
// /
56
78
// / copy_addr [take] %0 to %1 : $*T
57
79
// / ->
80
+ // / // load [take], not load [copy]!
81
+ // / %new = load [take] %0 : $*T
82
+ // / store %new to [assign] %1 : $*T
83
+ // / ->
58
84
// / %new = load %0 : $*T
59
- // / %old = load %1 : $*T
60
85
// / // no retain of %new!
86
+ // / %old = load %1 : $*T
61
87
// / strong_release %old : $T
62
88
// / store %new to %1 : $*T
63
89
// /
64
90
// / copy_addr %0 to [initialization] %1 : $*T
65
91
// / ->
92
+ // / %new = load [copy] %0 : $*T
93
+ // / store %new to [init] %1 : $*T
94
+ // / ->
66
95
// / %new = load %0 : $*T
67
96
// / strong_retain %new : $T
68
97
// / // no load/release of %old!
69
98
// / store %new to %1 : $*T
70
99
// /
71
100
// / copy_addr [take] %0 to [initialization] %1 : $*T
72
101
// / ->
102
+ // / %new = load [take] %0 : $*T
103
+ // / store %new to [init] %1 : $*T
104
+ // / ->
73
105
// / %new = load %0 : $*T
74
106
// / // no retain of %new!
75
107
// / // no load/release of %old!
76
108
// / store %new to %1 : $*T
77
109
static bool expandCopyAddr (CopyAddrInst *cai) {
78
110
SILFunction *fn = cai->getFunction ();
79
- SILModule &module = cai->getModule ();
80
111
SILValue source = cai->getSrc ();
81
112
82
113
// If we have an address only type don't do anything.
83
114
SILType srcType = source->getType ();
84
115
if (srcType.isAddressOnly (*fn))
85
116
return false ;
86
117
87
- bool expand = shouldExpand ( module , srcType.getObjectType ());
118
+ bool expand = shouldExpandShim (fn , srcType.getObjectType ());
88
119
using TypeExpansionKind = Lowering::TypeLowering::TypeExpansionKind;
89
120
auto expansionKind = expand ? TypeExpansionKind::MostDerivedDescendents
90
121
: TypeExpansionKind::None;
91
122
92
123
SILBuilderWithScope builder (cai);
93
124
94
- // %new = load %0 : $*T
95
- LoadInst *newValue = builder.createLoad (cai->getLoc (), source,
96
- LoadOwnershipQualifier::Unqualified);
125
+ // If our object type is not trivial, we may need to destroy the old value and
126
+ // copy the new one. Handle the trivial case quickly and return.
127
+ if (srcType.isTrivial (*fn)) {
128
+ SILValue newValue = builder.emitLoadValueOperation (
129
+ cai->getLoc (), source, LoadOwnershipQualifier::Trivial);
130
+ SILValue destAddr = cai->getDest ();
131
+ // Create the store.
132
+ builder.emitStoreValueOperation (cai->getLoc (), newValue, destAddr,
133
+ StoreOwnershipQualifier::Trivial);
134
+ ++NumExpand;
135
+ return true ;
136
+ }
97
137
138
+ // %new = load [copy|take] %0 : $*T
139
+ auto loadQual = [&]() -> LoadOwnershipQualifier {
140
+ if (IsTake_t::IsTake == cai->isTakeOfSrc ())
141
+ return LoadOwnershipQualifier::Take;
142
+ return LoadOwnershipQualifier::Copy;
143
+ }();
144
+ SILValue newValue = builder.emitLoweredLoadValueOperation (
145
+ cai->getLoc (), source, loadQual, expansionKind);
98
146
SILValue destAddr = cai->getDest ();
99
147
100
- // If our object type is not trivial, we may need to release the old value and
101
- // retain the new one.
102
-
103
- auto &typeLowering = fn->getTypeLowering (srcType);
104
-
105
- // If we have a non-trivial type...
106
- if (!typeLowering.isTrivial ()) {
107
- // If we are not initializing:
108
- // %old = load %1 : $*T
109
- auto isInit = cai->isInitializationOfDest ();
110
- LoadInst *oldValue = nullptr ;
111
- if (IsInitialization_t::IsNotInitialization == isInit) {
112
- oldValue = builder.createLoad (cai->getLoc (), destAddr,
113
- LoadOwnershipQualifier::Unqualified);
114
- }
115
-
116
- // If we are not taking and have a reference type:
117
- // strong_retain %new : $*T
118
- // or if we have a non-trivial non-reference type.
119
- // retain_value %new : $*T
120
- if (IsTake_t::IsNotTake == cai->isTakeOfSrc ()) {
121
- typeLowering.emitLoweredCopyValue (builder, cai->getLoc (), newValue,
122
- expansionKind);
123
- }
124
-
125
- // If we are not initializing:
126
- // strong_release %old : $*T
127
- // *or*
128
- // release_value %old : $*T
129
- if (oldValue) {
130
- typeLowering.emitLoweredDestroyValue (builder, cai->getLoc (), oldValue,
131
- expansionKind);
132
- }
133
- }
134
-
135
- // Create the store.
136
- builder.createStore (cai->getLoc (), newValue, destAddr,
137
- StoreOwnershipQualifier::Unqualified);
148
+ // Create the store in the guaranteed uninitialized memory.
149
+ //
150
+ // store %new to [init|assign] %1
151
+ //
152
+ // If we are not initializing the destination, we need to destroy what is
153
+ // currently there before we re-initialize the memory.
154
+ auto storeQualifier = [&]() -> StoreOwnershipQualifier {
155
+ if (IsInitialization_t::IsInitialization != cai->isInitializationOfDest ())
156
+ return StoreOwnershipQualifier::Assign;
157
+ return StoreOwnershipQualifier::Init;
158
+ }();
159
+ builder.emitLoweredStoreValueOperation (cai->getLoc (), newValue, destAddr,
160
+ storeQualifier, expansionKind);
138
161
139
162
++NumExpand;
140
163
return true ;
141
164
}
142
165
143
166
static bool expandDestroyAddr (DestroyAddrInst *dai) {
144
167
SILFunction *fn = dai->getFunction ();
145
- SILModule &module = dai->getModule ();
146
168
SILBuilderWithScope builder (dai);
147
169
148
170
// Strength reduce destroy_addr inst into release/store if
@@ -154,13 +176,16 @@ static bool expandDestroyAddr(DestroyAddrInst *dai) {
154
176
if (type.isAddressOnly (*fn))
155
177
return false ;
156
178
157
- bool expand = shouldExpand (module , type.getObjectType ());
179
+ // We only expand if ownership is not enabled and we do not have a large
180
+ // type. This was something that was only really beneficial for the low level
181
+ // ARC optimizer which runs without ownership enabled.
182
+ bool expand = shouldExpandShim (fn, type.getObjectType ());
158
183
159
184
// If we have a non-trivial type...
160
185
if (!type.isTrivial (*fn)) {
161
- // If we have a type with reference semantics, emit a load/strong release .
162
- LoadInst * li = builder.createLoad (dai->getLoc (), addr,
163
- LoadOwnershipQualifier::Unqualified );
186
+ // If we have a type with reference semantics, emit a load/destroy .
187
+ SILValue li = builder.emitLoadValueOperation (dai->getLoc (), addr,
188
+ LoadOwnershipQualifier::Take );
164
189
auto &typeLowering = fn->getTypeLowering (type);
165
190
using TypeExpansionKind = Lowering::TypeLowering::TypeExpansionKind;
166
191
auto expansionKind = expand ? TypeExpansionKind::MostDerivedDescendents
@@ -175,7 +200,6 @@ static bool expandDestroyAddr(DestroyAddrInst *dai) {
175
200
176
201
static bool expandReleaseValue (ReleaseValueInst *rvi) {
177
202
SILFunction *fn = rvi->getFunction ();
178
- SILModule &module = rvi->getModule ();
179
203
SILBuilderWithScope builder (rvi);
180
204
181
205
// Strength reduce destroy_addr inst into release/store if
@@ -184,11 +208,11 @@ static bool expandReleaseValue(ReleaseValueInst *rvi) {
184
208
185
209
// If we have an address only type, do nothing.
186
210
SILType type = value->getType ();
187
- assert (!SILModuleConventions (module ).useLoweredAddresses () ||
211
+ assert (!SILModuleConventions (fn-> getModule () ).useLoweredAddresses () ||
188
212
type.isLoadable (*fn) &&
189
213
" release_value should never be called on a non-loadable type." );
190
214
191
- if (!shouldExpand ( module , type.getObjectType ()))
215
+ if (!shouldExpandShim (fn , type.getObjectType ()))
192
216
return false ;
193
217
194
218
auto &TL = fn->getTypeLowering (type);
@@ -203,7 +227,6 @@ static bool expandReleaseValue(ReleaseValueInst *rvi) {
203
227
204
228
static bool expandRetainValue (RetainValueInst *rvi) {
205
229
SILFunction *fn = rvi->getFunction ();
206
- SILModule &module = rvi->getModule ();
207
230
SILBuilderWithScope builder (rvi);
208
231
209
232
// Strength reduce destroy_addr inst into release/store if
@@ -212,11 +235,11 @@ static bool expandRetainValue(RetainValueInst *rvi) {
212
235
213
236
// If we have an address only type, do nothing.
214
237
SILType type = value->getType ();
215
- assert (!SILModuleConventions (module ).useLoweredAddresses () ||
238
+ assert (!SILModuleConventions (fn-> getModule () ).useLoweredAddresses () ||
216
239
type.isLoadable (*fn) &&
217
240
" Copy Value can only be called on loadable types." );
218
241
219
- if (!shouldExpand ( module , type.getObjectType ()))
242
+ if (!shouldExpandShim (fn , type.getObjectType ()))
220
243
return false ;
221
244
222
245
auto &typeLowering = fn->getTypeLowering (type);
@@ -291,9 +314,6 @@ class SILLowerAggregate : public SILFunctionTransform {
291
314
// / The entry point to the transformation.
292
315
void run () override {
293
316
SILFunction *f = getFunction ();
294
- // FIXME: Can we support ownership?
295
- if (f->hasOwnership ())
296
- return ;
297
317
LLVM_DEBUG (llvm::dbgs () << " ***** LowerAggregate on function: "
298
318
<< f->getName () << " *****\n " );
299
319
bool changed = processFunction (*f);
0 commit comments