@@ -76,20 +76,6 @@ class ArrayAllocation {
76
76
77
77
public:
78
78
79
- // / Specifies the value with which a get-element call can be replaced.
80
- struct GetElementReplacement {
81
- ApplyInst *GetElementCall;
82
- SILValue Replacement;
83
- };
84
-
85
- // / Specifies the set of elements with which an append-contentof call can be
86
- // / replaced.
87
- struct AppendContentOfReplacement {
88
- ApplyInst *AppendContentOfCall;
89
- llvm::SmallVector<SILValue, 4 > ReplacementValues;
90
- SILValue Array;
91
- };
92
-
93
79
ArrayAllocation () {}
94
80
95
81
// / Analyzes an array allocation call.
@@ -99,14 +85,11 @@ class ArrayAllocation {
99
85
// / or append(contentof) calls.
100
86
bool analyze (ApplyInst *Alloc);
101
87
102
- // / Gets the list of get_element calls which can be replaced.
103
- void getGetElementReplacements (
104
- llvm::SmallVectorImpl<GetElementReplacement> &Replacements);
88
+ // / Replace getElement calls with the actual values.
89
+ bool replaceGetElements ();
105
90
106
- // / Gets the list of append(contentof) calls which can be replaced by a
107
- // / set of values.
108
- void getAppendContentOfReplacements (
109
- llvm::SmallVectorImpl<AppendContentOfReplacement> &Replacements);
91
+ // / Replace append(contentsOf:) with multiple append(element:)
92
+ bool replaceAppendContentOf ();
110
93
};
111
94
112
95
// / Map the indices of array element initialization stores to their values.
@@ -222,6 +205,10 @@ bool ArrayAllocation::recursivelyCollectUses(ValueBase *Def) {
222
205
}
223
206
224
207
bool ArrayAllocation::analyze (ApplyInst *Alloc) {
208
+ GetElementCalls.clear ();
209
+ AppendContentsOfCalls.clear ();
210
+ ElementValueMap.clear ();
211
+
225
212
ArraySemanticsCall Uninitialized (Alloc, " array.uninitialized" );
226
213
if (!Uninitialized)
227
214
return false ;
@@ -245,8 +232,16 @@ bool ArrayAllocation::analyze(ApplyInst *Alloc) {
245
232
return true ;
246
233
}
247
234
248
- void ArrayAllocation::getGetElementReplacements (
249
- llvm::SmallVectorImpl<GetElementReplacement> &Replacements) {
235
+ // / Replace getElement calls with the actual values.
236
+ // /
237
+ // / \code
238
+ // / store %x to %element_address
239
+ // / ...
240
+ // / %e = apply %getElement(%array, %constant_index)
241
+ // / \endcode
242
+ // / The value %e is replaced with %x.
243
+ bool ArrayAllocation::replaceGetElements () {
244
+ bool Changed = false ;
250
245
for (auto *GetElementCall : GetElementCalls) {
251
246
ArraySemanticsCall GetElement (GetElementCall);
252
247
assert (GetElement.getKind () == ArrayCallKind::kGetElement );
@@ -261,85 +256,107 @@ void ArrayAllocation::getGetElementReplacements(
261
256
if (EltValueIt == ElementValueMap.end ())
262
257
continue ;
263
258
264
- Replacements. push_back ({GetElementCall, EltValueIt->second } );
259
+ Changed |= GetElement. replaceByValue ( EltValueIt->second );
265
260
}
261
+ return Changed;
266
262
}
267
263
268
- void ArrayAllocation::getAppendContentOfReplacements (
269
- llvm::SmallVectorImpl<AppendContentOfReplacement> &Replacements) {
264
+ // / Replace append(contentsOf:) with multiple append(element:)
265
+ // /
266
+ // / \code
267
+ // / store %x to %source_array_element_address_0
268
+ // / store %y to %source_array_element_address_1
269
+ // / ...
270
+ // / apply %append_contentsOf(%dest_array, %source_array)
271
+ // / \endcode
272
+ // / is replaced by
273
+ // / \code
274
+ // / store %x to %source_array_element_address_0
275
+ // / store %y to %source_array_element_address_1
276
+ // / ...
277
+ // / apply %reserveCapacityForAppend(%dest_array, %number_of_values)
278
+ // / apply %append_element(%dest_array, %x)
279
+ // / apply %append_element(%dest_array, %y)
280
+ // / ...
281
+ // / \endcode
282
+ // / The source_array and its initialization code can then be deleted (if not
283
+ // / used otherwise).
284
+ bool ArrayAllocation::replaceAppendContentOf () {
270
285
if (AppendContentsOfCalls.empty ())
271
- return ;
286
+ return false ;
287
+ if (ElementValueMap.empty ())
288
+ return false ;
289
+
290
+ // Check if there is a store to each element.
272
291
if (!replacementsAreValid ())
273
- return ;
292
+ return false ;
274
293
275
294
llvm::SmallVector<SILValue, 4 > ElementValueVector;
276
- for (unsigned i = 0 ; i < ElementValueMap.size (); ++i)
277
- ElementValueVector.push_back (ElementValueMap[i]);
295
+ for (unsigned i = 0 ; i < ElementValueMap.size (); ++i) {
296
+ SILValue V = ElementValueMap[i];
297
+ ElementValueVector.push_back (V);
298
+ }
278
299
279
- for ( auto *Call : AppendContentsOfCalls)
280
- Replacements. push_back ({Call, ElementValueVector, ArrayValue} );
281
- }
300
+ SILFunction *Fn = AppendContentsOfCalls[ 0 ]-> getFunction ();
301
+ SILModule &M = Fn-> getModule ( );
302
+ ASTContext &Ctx = M. getASTContext ();
282
303
283
- // =============================================================================
284
- // Driver
285
- // =============================================================================
304
+ LLVM_DEBUG (llvm::dbgs () << " Array append contentsOf calls replaced in "
305
+ << Fn->getName () << " \n " );
286
306
287
- class ArrayElementPropagation : public SILFunctionTransform {
288
- public:
289
- ArrayElementPropagation () {}
307
+ // Get the needed Array helper functions.
308
+ FuncDecl *AppendFnDecl = Ctx.getArrayAppendElementDecl ();
309
+ if (!AppendFnDecl)
310
+ return false ;
290
311
291
- bool replaceAppendCalls (
292
- ArrayRef<ArrayAllocation::AppendContentOfReplacement> Repls) {
293
- auto &Fn = *getFunction ();
294
- auto &M = Fn.getModule ();
295
- auto &Ctx = M.getASTContext ();
312
+ FuncDecl *ReserveFnDecl = Ctx.getArrayReserveCapacityDecl ();
313
+ if (!ReserveFnDecl)
314
+ return false ;
296
315
297
- if (Repls.empty ())
298
- return false ;
316
+ auto Mangled = SILDeclRef (AppendFnDecl, SILDeclRef::Kind::Func).mangle ();
317
+ SILFunction *AppendFn = M.findFunction (Mangled, SILLinkage::PublicExternal);
318
+ if (!AppendFn)
319
+ return false ;
299
320
300
- LLVM_DEBUG (llvm::dbgs () << " Array append contentsOf calls replaced in "
301
- << Fn.getName () << " (" << Repls.size () << " )\n " );
321
+ Mangled = SILDeclRef (ReserveFnDecl, SILDeclRef::Kind::Func).mangle ();
322
+ SILFunction *ReserveFn = M.findFunction (Mangled, SILLinkage::PublicExternal);
323
+ if (!ReserveFn)
324
+ return false ;
302
325
303
- FuncDecl *AppendFnDecl = Ctx.getArrayAppendElementDecl ();
304
- if (!AppendFnDecl)
305
- return false ;
326
+ bool Changed = false ;
327
+ // Usually there is only a single append(contentsOf:) call. But there might
328
+ // be multiple - with the same source array to append.
329
+ for (ApplyInst *AppendContentOfCall : AppendContentsOfCalls) {
330
+ ArraySemanticsCall AppendContentsOf (AppendContentOfCall);
331
+ assert (AppendContentsOf && " Must be AppendContentsOf call" );
306
332
307
- FuncDecl *ReserveFnDecl = Ctx.getArrayReserveCapacityDecl ();
308
- if (!ReserveFnDecl)
309
- return false ;
333
+ NominalTypeDecl *AppendSelfArray = AppendContentsOf.getSelf ()->getType ().
334
+ getASTType ()->getAnyNominal ();
310
335
311
- auto Mangled = SILDeclRef (AppendFnDecl, SILDeclRef::Kind::Func).mangle ();
312
- SILFunction *AppendFn = M.findFunction (Mangled, SILLinkage::PublicExternal);
313
- if (!AppendFn)
314
- return false ;
315
-
316
- Mangled = SILDeclRef (ReserveFnDecl, SILDeclRef::Kind::Func).mangle ();
317
- SILFunction *ReserveFn = M.findFunction (Mangled, SILLinkage::PublicExternal);
318
- if (!ReserveFn)
319
- return false ;
336
+ // In case if it's not an Array, but e.g. an ContiguousArray
337
+ if (AppendSelfArray != Ctx.getArrayDecl ())
338
+ continue ;
320
339
321
- for (const ArrayAllocation::AppendContentOfReplacement &Repl : Repls) {
322
- ArraySemanticsCall AppendContentsOf (Repl.AppendContentOfCall );
323
- assert (AppendContentsOf && " Must be AppendContentsOf call" );
340
+ SILType ArrayType = ArrayValue->getType ();
341
+ auto *NTD = ArrayType.getASTType ()->getAnyNominal ();
342
+ SubstitutionMap ArraySubMap = ArrayType.getASTType ()
343
+ ->getContextSubstitutionMap (M.getSwiftModule (), NTD);
324
344
325
- NominalTypeDecl *AppendSelfArray = AppendContentsOf.getSelf ()->getType ().
326
- getASTType ()->getAnyNominal ();
345
+ AppendContentsOf.replaceByAppendingValues (M, AppendFn, ReserveFn,
346
+ ElementValueVector,
347
+ ArraySubMap);
348
+ Changed = true ;
349
+ }
350
+ return Changed;
351
+ }
327
352
328
- // In case if it's not an Array, but e.g. an ContiguousArray
329
- if (AppendSelfArray != Ctx. getArrayDecl ())
330
- continue ;
353
+ // =============================================================================
354
+ // Driver
355
+ // =============================================================================
331
356
332
- SILType ArrayType = Repl.Array ->getType ();
333
- auto *NTD = ArrayType.getASTType ()->getAnyNominal ();
334
- SubstitutionMap ArraySubMap = ArrayType.getASTType ()
335
- ->getContextSubstitutionMap (M.getSwiftModule (), NTD);
336
-
337
- AppendContentsOf.replaceByAppendingValues (M, AppendFn, ReserveFn,
338
- Repl.ReplacementValues ,
339
- ArraySubMap);
340
- }
341
- return true ;
342
- }
357
+ class ArrayElementPropagation : public SILFunctionTransform {
358
+ public:
359
+ ArrayElementPropagation () {}
343
360
344
361
void run () override {
345
362
auto &Fn = *getFunction ();
@@ -348,39 +365,28 @@ class ArrayElementPropagation : public SILFunctionTransform {
348
365
if (Fn.hasOwnership ())
349
366
return ;
350
367
351
- // Propagate the elements an of array value to its users.
352
- llvm::SmallVector<ArrayAllocation::GetElementReplacement, 16 >
353
- GetElementReplacements;
354
- llvm::SmallVector<ArrayAllocation::AppendContentOfReplacement, 4 >
355
- AppendContentsOfReplacements;
368
+ bool Changed = false ;
356
369
357
370
for (auto &BB :Fn) {
358
371
for (auto &Inst : BB) {
359
372
if (auto *Apply = dyn_cast<ApplyInst>(&Inst)) {
360
373
ArrayAllocation ALit;
361
- if (ALit.analyze (Apply)) {
362
- ALit.getGetElementReplacements (GetElementReplacements);
363
- ALit.getAppendContentOfReplacements (AppendContentsOfReplacements);
374
+ if (!ALit.analyze (Apply))
375
+ continue ;
376
+
377
+ // First optimization: replace getElemente calls.
378
+ if (ALit.replaceGetElements ()) {
379
+ Changed = true ;
380
+ // Re-do the analysis if the SIL changed.
381
+ if (!ALit.analyze (Apply))
382
+ continue ;
364
383
}
384
+ // Second optimization: replace append(contentsOf:) calls.
385
+ Changed |= ALit.replaceAppendContentOf ();
365
386
}
366
387
}
367
388
}
368
389
369
- LLVM_DEBUG (if (!GetElementReplacements.empty ()) {
370
- llvm::dbgs () << " Array elements replaced in " << Fn.getName () << " ("
371
- << GetElementReplacements.size () << " )\n " ;
372
- });
373
-
374
- bool Changed = false ;
375
-
376
- // Perform the actual replacement of the get_element call by its value.
377
- for (ArrayAllocation::GetElementReplacement &Repl : GetElementReplacements) {
378
- ArraySemanticsCall GetElement (Repl.GetElementCall );
379
- Changed |= GetElement.replaceByValue (Repl.Replacement );
380
- }
381
-
382
- Changed |= replaceAppendCalls (AppendContentsOfReplacements);
383
-
384
390
if (Changed) {
385
391
PM->invalidateAnalysis (
386
392
&Fn, SILAnalysis::InvalidationKind::CallsAndInstructions);
0 commit comments