Skip to content

Commit 62ec31a

Browse files
Merge pull request #41338 from aschwaighofer/reuse_contiguous_array_storage_metadata
Reuse `_ContiguousArrayStorage<AnyObject>` metadata for any class or objc generic type
2 parents e675b31 + cc8a86b commit 62ec31a

34 files changed

+269
-51
lines changed

SwiftCompilerSources/Sources/SIL/Instruction.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -220,7 +220,7 @@ final public class DeallocStackInst : Instruction, UnaryInstruction {
220220
}
221221

222222
final public class DeallocStackRefInst : Instruction, UnaryInstruction {
223-
public var allocRef: AllocRefInst { operand as! AllocRefInst }
223+
public var allocRef: AllocRefInstBase { operand as! AllocRefInstBase }
224224
}
225225

226226
final public class CondFailInst : Instruction, UnaryInstruction {

include/swift/AST/KnownStdlibTypes.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ KNOWN_STDLIB_TYPE_DECL(String, NominalTypeDecl, 0)
4949
KNOWN_STDLIB_TYPE_DECL(StaticString, NominalTypeDecl, 0)
5050
KNOWN_STDLIB_TYPE_DECL(Substring, NominalTypeDecl, 0)
5151
KNOWN_STDLIB_TYPE_DECL(Array, NominalTypeDecl, 1)
52+
KNOWN_STDLIB_TYPE_DECL(_ContiguousArrayStorage, NominalTypeDecl, 1)
5253
KNOWN_STDLIB_TYPE_DECL(Set, NominalTypeDecl, 1)
5354
KNOWN_STDLIB_TYPE_DECL(Sequence, NominalTypeDecl, 1)
5455
KNOWN_STDLIB_TYPE_DECL(Dictionary, NominalTypeDecl, 2)

include/swift/AST/SemanticAttrs.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ SEMANTICS_ATTR(ARRAY_COUNT, "array.count")
6363
SEMANTICS_ATTR(ARRAY_DEALLOC_UNINITIALIZED, "array.dealloc_uninitialized")
6464
SEMANTICS_ATTR(ARRAY_UNINITIALIZED_INTRINSIC, "array.uninitialized_intrinsic")
6565
SEMANTICS_ATTR(ARRAY_FINALIZE_INTRINSIC, "array.finalize_intrinsic")
66+
SEMANTICS_ATTR(ARRAY_GET_CONTIGUOUSARRAYSTORAGETYPE, "array.getContiguousArrayStorageType")
6667

6768
SEMANTICS_ATTR(SEQUENCE_FOR_EACH, "sequence.forEach")
6869
SEMANTICS_ATTR(TYPENAME, "typeName")

include/swift/SIL/SILBuilder.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -408,14 +408,15 @@ class SILBuilder {
408408

409409
AllocRefDynamicInst *createAllocRefDynamic(SILLocation Loc, SILValue operand,
410410
SILType type, bool objc,
411+
bool canAllocOnStack,
411412
ArrayRef<SILType> ElementTypes,
412413
ArrayRef<SILValue> ElementCountOperands) {
413414
// AllocRefDynamicInsts expand to function calls and can therefore
414415
// not be counted towards the function prologue.
415416
assert(!Loc.isInPrologue());
416417
return insert(AllocRefDynamicInst::create(
417-
getSILDebugLocation(Loc), *F, operand, type, objc, ElementTypes,
418-
ElementCountOperands));
418+
getSILDebugLocation(Loc), *F, operand, type, objc, canAllocOnStack,
419+
ElementTypes, ElementCountOperands));
419420
}
420421

421422
AllocBoxInst *createAllocBox(SILLocation Loc, CanSILBoxType BoxType,

include/swift/SIL/SILCloner.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -839,6 +839,7 @@ SILCloner<ImplClass>::visitAllocRefDynamicInst(AllocRefDynamicInst *Inst) {
839839
getOpValue(Inst->getMetatypeOperand()),
840840
getOpType(Inst->getType()),
841841
Inst->isObjC(),
842+
Inst->canAllocOnStack(),
842843
ElemTypes, CountArgs);
843844
recordClonedInstruction(Inst, NewInst);
844845
}

include/swift/SIL/SILInstruction.h

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2145,6 +2145,26 @@ class AllocRefInstBase : public AllocationInst {
21452145
bool isObjC() const {
21462146
return SILNode::Bits.AllocRefInstBase.ObjC;
21472147
}
2148+
2149+
static bool classof(SILNodePointer node) {
2150+
if (auto *i = dyn_cast<SILInstruction>(node.get()))
2151+
return classof(i);
2152+
return false;
2153+
}
2154+
2155+
static bool classof(const SILInstruction *inst) {
2156+
return classof(inst->getKind());
2157+
}
2158+
2159+
static bool classof(SILInstructionKind kind) {
2160+
switch (kind) {
2161+
case SILInstructionKind::AllocRefInst:
2162+
case SILInstructionKind::AllocRefDynamicInst:
2163+
return true;
2164+
default:
2165+
return false;
2166+
}
2167+
}
21482168
};
21492169

21502170
/// AllocRefInst - This represents the primitive allocation of an instance
@@ -2205,10 +2225,11 @@ class AllocRefDynamicInst final
22052225
AllocRefDynamicInst(SILDebugLocation DebugLoc,
22062226
SILType ty,
22072227
bool objc,
2228+
bool canBeOnStack,
22082229
ArrayRef<SILType> ElementTypes,
22092230
ArrayRef<SILValue> AllOperands)
22102231
: InstructionBaseWithTrailingOperands(AllOperands, DebugLoc, ty, objc,
2211-
false, ElementTypes) {
2232+
canBeOnStack, ElementTypes) {
22122233
assert(AllOperands.size() >= ElementTypes.size() + 1);
22132234
std::uninitialized_copy(ElementTypes.begin(), ElementTypes.end(),
22142235
getTrailingObjects<SILType>());
@@ -2217,6 +2238,7 @@ class AllocRefDynamicInst final
22172238
static AllocRefDynamicInst *
22182239
create(SILDebugLocation DebugLoc, SILFunction &F,
22192240
SILValue metatypeOperand, SILType ty, bool objc,
2241+
bool canBeOnStack,
22202242
ArrayRef<SILType> ElementTypes,
22212243
ArrayRef<SILValue> ElementCountOperands);
22222244

@@ -2232,6 +2254,9 @@ class AllocRefDynamicInst final
22322254
MutableArrayRef<Operand> getTypeDependentOperands() {
22332255
return getAllOperands().slice(getNumTailTypes() + 1);
22342256
}
2257+
// Is the deinit and the size of the dynamic type known to be equivalent to
2258+
// the the base type (i.e `this->getType()`).
2259+
bool isDynamicTypeDeinitAndSizeKnownEquivalentToBaseType() const;
22352260
};
22362261

22372262
/// This represents the allocation of a heap box for a Swift value of some type.
@@ -7692,7 +7717,9 @@ class DeallocStackRefInst
76927717
DeallocStackRefInst(SILDebugLocation DebugLoc, SILValue Operand)
76937718
: UnaryInstructionBase(DebugLoc, Operand) {}
76947719
public:
7695-
AllocRefInst *getAllocRef() { return cast<AllocRefInst>(getOperand()); }
7720+
AllocRefInstBase *getAllocRef() {
7721+
return cast<AllocRefInstBase>(getOperand());
7722+
}
76967723
};
76977724

76987725
/// Deallocate memory for a reference type instance from a destructor or

lib/IRGen/GenClass.cpp

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -828,12 +828,32 @@ llvm::Value *irgen::emitClassAllocationDynamic(IRGenFunction &IGF,
828828
llvm::Value *metadata,
829829
SILType selfType,
830830
bool objc,
831+
int &StackAllocSize,
831832
TailArraysRef TailArrays) {
832833
// If we need to use Objective-C allocation, do so.
833834
if (objc) {
835+
StackAllocSize = -1;
834836
return emitObjCAllocObjectCall(IGF, metadata, selfType);
835837
}
836838

839+
llvm::Value *Promoted;
840+
auto &classTI = IGF.getTypeInfo(selfType).as<ClassTypeInfo>();
841+
auto &classLayout = classTI.getClassLayout(IGF.IGM, selfType,
842+
/*forBackwardDeployment=*/false);
843+
844+
// If we are allowed to allocate on the stack we are allowed to use
845+
// `selfType`'s size assumptions.
846+
if (StackAllocSize >= 0 &&
847+
(Promoted = stackPromote(IGF, classLayout, StackAllocSize,
848+
TailArrays))) {
849+
llvm::Value *val = IGF.Builder.CreateBitCast(Promoted,
850+
IGF.IGM.RefCountedPtrTy);
851+
val = IGF.emitInitStackObjectCall(metadata, val, "reference.new");
852+
853+
llvm::Type *destType = classLayout.getType()->getPointerTo();
854+
return IGF.Builder.CreateBitCast(val, destType);
855+
}
856+
837857
// Otherwise, allocate using Swift's routines.
838858
llvm::Value *size, *alignMask;
839859
std::tie(size, alignMask)
@@ -845,10 +865,8 @@ llvm::Value *irgen::emitClassAllocationDynamic(IRGenFunction &IGF,
845865

846866
llvm::Value *val = IGF.emitAllocObjectCall(metadata, size, alignMask,
847867
"reference.new");
848-
auto &classTI = IGF.getTypeInfo(selfType).as<ClassTypeInfo>();
849-
auto &layout = classTI.getClassLayout(IGF.IGM, selfType,
850-
/*forBackwardDeployment=*/false);
851-
llvm::Type *destType = layout.getType()->getPointerTo();
868+
StackAllocSize = -1;
869+
llvm::Type *destType = classLayout.getType()->getPointerTo();
852870
return IGF.Builder.CreateBitCast(val, destType);
853871
}
854872

lib/IRGen/GenClass.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -167,10 +167,12 @@ namespace irgen {
167167
bool objc, int &StackAllocSize, TailArraysRef TailArrays);
168168

169169
/// Emit an allocation of a class using a metadata value.
170-
llvm::Value *emitClassAllocationDynamic(IRGenFunction &IGF,
170+
llvm::Value *emitClassAllocationDynamic(IRGenFunction &IGF,
171171
llvm::Value *metadata,
172172
SILType selfType,
173-
bool objc, TailArraysRef TailArrays);
173+
bool objc,
174+
int &StackAllocSize,
175+
TailArraysRef TailArrays);
174176

175177
/// Emit class deallocation.
176178
void emitClassDeallocation(IRGenFunction &IGF, SILType selfType,

lib/IRGen/IRGenSIL.cpp

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5433,14 +5433,30 @@ void IRGenSILFunction::visitAllocRefInst(swift::AllocRefInst *i) {
54335433
}
54345434

54355435
void IRGenSILFunction::visitAllocRefDynamicInst(swift::AllocRefDynamicInst *i) {
5436+
int StackAllocSize = -1;
5437+
if (i->canAllocOnStack()) {
5438+
assert(i->isDynamicTypeDeinitAndSizeKnownEquivalentToBaseType());
5439+
estimateStackSize();
5440+
// Is there enough space for stack allocation?
5441+
StackAllocSize = IGM.IRGen.Opts.StackPromotionSizeLimit - EstimatedStackSize;
5442+
}
5443+
54365444
SmallVector<std::pair<SILType, llvm::Value *>, 4> TailArrays;
54375445
buildTailArrays(*this, TailArrays, i);
54385446

54395447
Explosion metadata = getLoweredExplosion(i->getMetatypeOperand());
54405448
auto metadataValue = metadata.claimNext();
54415449
llvm::Value *alloced = emitClassAllocationDynamic(*this, metadataValue,
54425450
i->getType(), i->isObjC(),
5451+
StackAllocSize,
54435452
TailArrays);
5453+
5454+
if (StackAllocSize >= 0) {
5455+
// Remember that this alloc_ref_dynamic allocates the object on the stack.
5456+
StackAllocs.insert(i);
5457+
EstimatedStackSize += StackAllocSize;
5458+
}
5459+
54445460
Explosion e;
54455461
e.add(alloced);
54465462
setLoweredExplosion(i, e);
@@ -5484,7 +5500,7 @@ void IRGenSILFunction::visitDeallocRefInst(swift::DeallocRefInst *i) {
54845500
// Lower the operand.
54855501
Explosion self = getLoweredExplosion(i->getOperand());
54865502
auto selfValue = self.claimNext();
5487-
auto *ARI = dyn_cast<AllocRefInst>(i->getOperand());
5503+
auto *ARI = dyn_cast<AllocRefInstBase>(i->getOperand());
54885504
if (ARI && StackAllocs.count(ARI)) {
54895505
// We can ignore dealloc_refs for stack allocated objects.
54905506
//

lib/SIL/IR/Linker.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -327,6 +327,20 @@ void SILLinkerVisitor::visitInitExistentialRefInst(
327327
visitProtocolConformance(C, Optional<SILDeclRef>());
328328
}
329329
}
330+
void SILLinkerVisitor::visitAllocRefDynamicInst(AllocRefDynamicInst *ARI) {
331+
if (!isLinkAll())
332+
return;
333+
334+
if (!ARI->isDynamicTypeDeinitAndSizeKnownEquivalentToBaseType())
335+
return;
336+
337+
// Grab the class decl from the alloc ref inst.
338+
ClassDecl *D = ARI->getType().getClassOrBoundGenericClass();
339+
if (!D)
340+
return;
341+
342+
linkInVTable(D);
343+
}
330344

331345
void SILLinkerVisitor::visitAllocRefInst(AllocRefInst *ARI) {
332346
if (!isLinkAll())

0 commit comments

Comments
 (0)