89
89
#include " swift/SIL/SILInstruction.h"
90
90
#include " swift/SIL/SILLocation.h"
91
91
#include " swift/SIL/SILModule.h"
92
+ #include " swift/SIL/TypeLowering.h"
92
93
#include " swift/SILOptimizer/PassManager/Passes.h"
93
94
#include " swift/SILOptimizer/PassManager/Transforms.h"
94
95
#include " swift/SILOptimizer/Utils/CFGOptUtils.h"
101
102
#include " llvm/ADT/MapVector.h"
102
103
103
104
using namespace swift ;
105
+ using namespace Lowering ;
104
106
105
107
template <typename ... T, typename ... U>
106
108
static void diagnose (ASTContext &Context, SourceLoc loc, Diag<T...> diag,
@@ -239,6 +241,12 @@ static bool isStringType(SILType silType, ASTContext &astContext) {
239
241
return nominalDecl && nominalDecl == astContext.getStringDecl ();
240
242
}
241
243
244
+ // / Return true if and only if the given SIL type represents an Array type.
245
+ static bool isArrayType (SILType silType, ASTContext &astContext) {
246
+ NominalTypeDecl *nominalDecl = silType.getNominalOrBoundGenericNominal ();
247
+ return nominalDecl && nominalDecl == astContext.getArrayDecl ();
248
+ }
249
+
242
250
// / Decide if the given instruction (which could possibly be a call) should
243
251
// / be constant evaluated.
244
252
// /
@@ -290,6 +298,28 @@ static bool isFoldableString(SILValue value, SILInstruction *definingInst,
290
298
!getStringMakeUTF8Init (definingInst);
291
299
}
292
300
301
+ // / Return true iff the given value is an array and is not an initialization
302
+ // / of an array from an array literal.
303
+ static bool isFoldableArray (SILValue value, SILInstruction *definingInst,
304
+ ASTContext &astContext) {
305
+ assert (definingInst);
306
+ if (!isArrayType (value->getType (), astContext))
307
+ return false ;
308
+
309
+ // Check if this is not an initialization of an array from a literal.
310
+ SILInstruction *constructorInst = definingInst;
311
+ if (isa<DestructureTupleInst>(definingInst) ||
312
+ isa<TupleExtractInst>(definingInst)) {
313
+ constructorInst = definingInst->getOperand (0 )->getDefiningInstruction ();
314
+ }
315
+ ApplyInst *apply = dyn_cast<ApplyInst>(definingInst);
316
+ if (!apply)
317
+ return true ;
318
+ SILFunction *callee = apply->getCalleeFunction ();
319
+ return !callee || !callee->hasSemanticsAttr (" array.init.empty" ) ||
320
+ !callee->hasSemanticsAttr (" array.uninitialized_intrinsic" );
321
+ }
322
+
293
323
// / Check whether a SILValue is foldable. String, integer, array and
294
324
// / function values are foldable with the following exceptions:
295
325
// / - Addresses cannot be folded.
@@ -308,7 +338,8 @@ static bool isSILValueFoldable(SILValue value) {
308
338
!isa<BeginBorrowInst>(definingInst) &&
309
339
!isa<CopyValueInst>(definingInst) &&
310
340
(isFoldableIntOrBool (value, definingInst, astContext) ||
311
- isFoldableString (value, definingInst, astContext)));
341
+ isFoldableString (value, definingInst, astContext) ||
342
+ isFoldableArray (value, definingInst, astContext)));
312
343
}
313
344
314
345
// / Diagnose failure during evaluation of a call to a constant-evaluable
@@ -450,6 +481,110 @@ static Optional<SymbolicValue> collectConstants(FoldState &foldState) {
450
481
return None; // No error.
451
482
}
452
483
484
+ // / Generate SIL code to create an array of constant size from the given
485
+ // / SILValues \p elements. This function creates the same sequence of SIL
486
+ // / instructions that would be generated for initializing an array from an array
487
+ // / literal of the form [element1, element2, ..., elementn].
488
+ // /
489
+ // / \param elements SILValues that the array should contain
490
+ // / \param arrayType the type of the array that must be created.
491
+ // / \param builder SILBuilder that provides the context for emitting the code
492
+ // / for the array.
493
+ // / \param loc SILLocation to use in the emitted instructions.
494
+ // / \return the SILValue of the array that is created with the given \c
495
+ // / elements.
496
+ static SILValue emitCodeForConstantArray (ArrayRef<SILValue> elements,
497
+ CanType arrayType, SILBuilder &builder,
498
+ SILLocation loc) {
499
+ ASTContext &astContext = builder.getASTContext ();
500
+ assert (astContext.getArrayDecl () ==
501
+ arrayType->getNominalOrBoundGenericNominal ());
502
+ SILModule &module = builder.getModule ();
503
+ SILFunction &fun = builder.getFunction ();
504
+
505
+ // Create a SILValue for the number of elements.
506
+ unsigned numElements = elements.size ();
507
+ SILValue numElementsSIL = builder.createIntegerLiteral (
508
+ loc, SILType::getBuiltinWordType (astContext), numElements);
509
+
510
+ // Find the SILFunction that corresponds to _allocateUninitializedArray.
511
+ FuncDecl *arrayAllocateDecl = astContext.getAllocateUninitializedArray ();
512
+ assert (arrayAllocateDecl);
513
+ std::string allocatorMangledName =
514
+ SILDeclRef (arrayAllocateDecl, SILDeclRef::Kind::Func).mangle ();
515
+ SILFunction *arrayAllocateFun =
516
+ module .findFunction (allocatorMangledName, SILLinkage::PublicExternal);
517
+ assert (arrayAllocateFun);
518
+
519
+ // Call the _allocateUninitializedArray function with numElementsSIL. The
520
+ // call returns a two-element tuple, where the first element is the newly
521
+ // created array and the second element is a pointer to the internal storage
522
+ // of the array.
523
+ SubstitutionMap subMap = arrayType->getContextSubstitutionMap (
524
+ module .getSwiftModule (), astContext.getArrayDecl ());
525
+ FunctionRefInst *arrayAllocateRef =
526
+ builder.createFunctionRef (loc, arrayAllocateFun);
527
+ ApplyInst *applyInst = builder.createApply (
528
+ loc, arrayAllocateRef, subMap, ArrayRef<SILValue>(numElementsSIL), false );
529
+
530
+ // Extract the elements of the tuple returned by the call to the allocator.
531
+ SILValue arraySIL;
532
+ SILValue storagePointerSIL;
533
+ if (fun.hasOwnership ()) {
534
+ DestructureTupleInst *destructureInst =
535
+ builder.createDestructureTuple (loc, applyInst);
536
+ arraySIL = destructureInst->getResults ()[0 ];
537
+ storagePointerSIL = destructureInst->getResults ()[1 ];
538
+ } else {
539
+ SILType arraySILType = SILType::getPrimitiveObjectType (arrayType);
540
+ arraySIL = builder.createTupleExtract (loc, applyInst, 0 , arraySILType);
541
+ storagePointerSIL = builder.createTupleExtract (
542
+ loc, applyInst, 1 , SILType::getRawPointerType (astContext));
543
+ }
544
+
545
+ if (elements.empty ()) {
546
+ // Nothing more to be done if we are creating an empty array.
547
+ return arraySIL;
548
+ }
549
+
550
+ // Convert the pointer to the storage to an address. The elements will be
551
+ // stored into offsets from this address.
552
+ SILType elementSILType = elements[0 ]->getType ();
553
+ PointerToAddressInst *storageAddr = builder.createPointerToAddress (
554
+ loc, storagePointerSIL, elementSILType.getAddressType (),
555
+ /* isStrict*/ true ,
556
+ /* isInvariant*/ false );
557
+
558
+ // Iterate over the elements and store them into the storage address
559
+ // after offsetting it appropriately.
560
+
561
+ // Create a TypeLowering for emitting stores. Note that TypeLowering
562
+ // provides a utility for emitting stores for storing trivial and
563
+ // non-trivial values, and also handles OSSA and non-OSSA.
564
+ const TypeLowering &elementTypeLowering =
565
+ builder.getTypeLowering (elementSILType);
566
+
567
+ unsigned elementIndex = 0 ;
568
+ for (SILValue elementSIL : elements) {
569
+ // Compute the address where the element must be stored.
570
+ SILValue currentStorageAddr;
571
+ if (elementIndex != 0 ) {
572
+ SILValue indexSIL = builder.createIntegerLiteral (
573
+ loc, SILType::getBuiltinWordType (astContext), elementIndex);
574
+ currentStorageAddr = builder.createIndexAddr (loc, storageAddr, indexSIL);
575
+ } else {
576
+ currentStorageAddr = storageAddr;
577
+ }
578
+ // Store the generated element into the currentStorageAddr. This is an
579
+ // initializing store and therefore there is no need to free any existing
580
+ // element.
581
+ elementTypeLowering.emitStore (builder, loc, elementSIL, currentStorageAddr,
582
+ StoreOwnershipQualifier::Init);
583
+ elementIndex++;
584
+ }
585
+ return arraySIL;
586
+ }
587
+
453
588
// / Generate SIL code that computes the constant given by the symbolic value
454
589
// / `symVal`. Note that strings and struct-typed constant values will require
455
590
// / multiple instructions to be emitted.
@@ -532,6 +667,23 @@ static SILValue emitCodeForSymbolicValue(SymbolicValue symVal,
532
667
loc, aggregateType, ArrayRef<SILValue>(newPropertySIL));
533
668
return newStructInst;
534
669
}
670
+ case SymbolicValue::Array: {
671
+ assert (expectedType->isEqual (symVal.getArrayType ()));
672
+ CanType elementType;
673
+ ArrayRef<SymbolicValue> arrayElements =
674
+ symVal.getStorageOfArray ().getStoredElements (elementType);
675
+
676
+ // Emit code for the symbolic values corresponding to the array elements.
677
+ SmallVector<SILValue, 8 > elementSILValues;
678
+ for (SymbolicValue elementSymVal : arrayElements) {
679
+ SILValue elementSIL = emitCodeForSymbolicValue (elementSymVal, elementType,
680
+ builder, loc, stringInfo);
681
+ elementSILValues.push_back (elementSIL);
682
+ }
683
+ SILValue arraySIL = emitCodeForConstantArray (
684
+ elementSILValues, expectedType->getCanonicalType (), builder, loc);
685
+ return arraySIL;
686
+ }
535
687
default : {
536
688
llvm_unreachable (" Symbolic value kind is not supported" );
537
689
}
0 commit comments