Skip to content

Commit 4ef135c

Browse files
authored
Merge pull request #66201 from nate-chandler/dealloc-on-stack-packs
[IRGen] Dealloc on-stack metadata/wtable packs on the dominance frontier.
2 parents 44a4097 + c5699c9 commit 4ef135c

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

47 files changed

+1264
-107
lines changed

docs/SIL.rst

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3797,7 +3797,21 @@ address of the allocated memory.
37973797

37983798
``alloc_pack`` is a stack allocation instruction. See the section above
37993799
on stack discipline. The corresponding stack deallocation instruction is
3800-
``dealloc_stack``.
3800+
``dealloc_pack``.
3801+
3802+
alloc_pack_metadata
3803+
```````````````````
3804+
3805+
::
3806+
3807+
sil-instruction ::= 'alloc_pack_metadata' $()
3808+
3809+
Inserted as the last SIL lowering pass of IRGen, indicates that the next instruction
3810+
may have on-stack pack metadata allocated on its behalf.
3811+
3812+
Notionally, ``alloc_pack_metadata`` is a stack allocation instruction. See the
3813+
section above on stack discipline. The corresponding stack deallocation
3814+
instruction is ``dealloc_pack_metadata``.
38013815

38023816
alloc_ref
38033817
`````````
@@ -4056,6 +4070,23 @@ prior to being deallocated.
40564070
on Stack Discipline above. The operand must be an ``alloc_pack``
40574071
instruction.
40584072

4073+
dealloc_pack_metadata
4074+
`````````````````````
4075+
4076+
::
4077+
4078+
sil-instruction ::= 'dealloc_pack_metadata' sil-operand
4079+
4080+
dealloc_pack_metadata $0 : $*()
4081+
4082+
Inserted as the last SIL lowering pass of IRGen, indicates that the on-stack
4083+
pack metadata emitted on behalf of its operand (actually on behalf of the
4084+
instruction after its operand) must be cleaned up here.
4085+
4086+
``dealloc_pack_metadata`` is a stack deallocation instruction. See the section
4087+
on Stack Discipline above. The operand must be an ``alloc_pack_metadata``
4088+
instruction.
4089+
40594090
dealloc_box
40604091
```````````
40614092
::

include/swift/AST/SILOptions.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,12 @@ class SILOptions {
173173
/// Require linear OSSA lifetimes after SILGen
174174
bool OSSACompleteLifetimes = false;
175175

176+
/// Enable pack metadata stack "promotion".
177+
///
178+
/// More accurately, enable skipping mandatory heapification of pack metadata
179+
/// when possible.
180+
bool EnablePackMetadataStackPromotion = true;
181+
176182
// The kind of function bodies to skip emitting.
177183
FunctionBodySkipping SkipFunctionBodies = FunctionBodySkipping::None;
178184

include/swift/AST/Types.h

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,10 @@ class RecursiveTypeProperties {
179179
/// they have a type variable originator.
180180
SolverAllocated = 0x8000,
181181

182-
Last_Property = SolverAllocated
182+
/// This type contains a concrete pack.
183+
HasConcretePack = 0x10000,
184+
185+
Last_Property = HasConcretePack
183186
};
184187
enum { BitWidth = countBitsUsed(Property::Last_Property) };
185188

@@ -255,6 +258,8 @@ class RecursiveTypeProperties {
255258

256259
bool hasParameterPack() const { return Bits & HasParameterPack; }
257260

261+
bool hasConcretePack() const { return Bits & HasConcretePack; }
262+
258263
/// Does a type with these properties structurally contain a
259264
/// parameterized existential type?
260265
bool hasParameterizedExistential() const {
@@ -412,12 +417,12 @@ class alignas(1 << TypeAlignInBits) TypeBase
412417
NumProtocols : 16
413418
);
414419

415-
SWIFT_INLINE_BITFIELD_FULL(TypeVariableType, TypeBase, 7+31,
420+
SWIFT_INLINE_BITFIELD_FULL(TypeVariableType, TypeBase, 7+30,
416421
/// Type variable options.
417422
Options : 7,
418423
: NumPadBits,
419424
/// The unique number assigned to this type variable.
420-
ID : 31
425+
ID : 30
421426
);
422427

423428
SWIFT_INLINE_BITFIELD(SILFunctionType, TypeBase, NumSILExtInfoBits+1+4+1+2+1+1,
@@ -684,6 +689,13 @@ class alignas(1 << TypeAlignInBits) TypeBase
684689
return getRecursiveProperties().hasParameterPack();
685690
}
686691

692+
bool hasConcretePack() const {
693+
return getRecursiveProperties().hasConcretePack();
694+
}
695+
696+
/// Whether the type has some flavor of pack.
697+
bool hasPack() const { return hasParameterPack() || hasConcretePack(); }
698+
687699
/// Determine whether the type involves a parameterized existential type.
688700
bool hasParameterizedExistential() const {
689701
return getRecursiveProperties().hasParameterizedExistential();

include/swift/IRGen/IRGenSILPasses.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ namespace irgen {
1919
/// Create a pass to hoist alloc_stack instructions with non-fixed size.
2020
SILTransform *createAllocStackHoisting();
2121
SILTransform *createLoadableByAddress();
22+
SILTransform *createPackMetadataMarkerInserter();
2223

2324
} // end namespace irgen
2425
} // end namespace swift

include/swift/Option/FrontendOptions.td

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1028,6 +1028,16 @@ def force_struct_type_layouts : Flag<["-"], "force-struct-type-layouts">,
10281028
def enable_layout_string_value_witnesses : Flag<["-"], "enable-layout-string-value-witnesses">,
10291029
HelpText<"Enable layout string based value witnesses">;
10301030

1031+
let Flags = [FrontendOption, NoDriverOption, HelpHidden, ModuleInterfaceOptionIgnorable] in {
1032+
def enable_pack_metadata_stack_promotion :
1033+
Joined<["-"], "enable-pack-metadata-stack-promotion=">,
1034+
HelpText<"Whether to skip heapifying stack metadata packs when possible.">,
1035+
MetaVarName<"true|false">;
1036+
def enable_pack_metadata_stack_promotion_noArg :
1037+
Flag<["-"], "enable-pack-metadata-stack-promotion">,
1038+
HelpText<"Skip heapifying stack metadata packs when possible.">;
1039+
}
1040+
10311041
def disable_layout_string_value_witnesses : Flag<["-"], "disable-layout-string-value-witnesses">,
10321042
HelpText<"Disable layout string based value witnesses">;
10331043

include/swift/SIL/Dominance.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ class DominanceInfo : public DominatorTreeBase {
9494

9595
/// Compute a single block's dominance frontier.
9696
///
97-
/// Precondition: no critical edges (OSSA)
97+
/// Precondition: no critical edges
9898
///
9999
/// Postcondition: each block in \p boundary is dominated by \p root and either
100100
/// exits the function or has a single successor which has a predecessor that is

include/swift/SIL/SILBuilder.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -436,6 +436,15 @@ class SILBuilder {
436436
return insert(AllocPackInst::create(getSILDebugLocation(loc), packType,
437437
getFunction()));
438438
}
439+
AllocPackMetadataInst *
440+
createAllocPackMetadata(SILLocation loc,
441+
Optional<SILType> elementType = llvm::None) {
442+
return insert(new (getModule()) AllocPackMetadataInst(
443+
getSILDebugLocation(loc),
444+
elementType.value_or(
445+
SILType::getEmptyTupleType(getModule().getASTContext())
446+
.getAddressType())));
447+
}
439448

440449
AllocRefInst *createAllocRef(SILLocation Loc, SILType ObjectType,
441450
bool objc, bool canAllocOnStack,
@@ -2226,6 +2235,11 @@ class SILBuilder {
22262235
return insert(new (getModule())
22272236
DeallocPackInst(getSILDebugLocation(loc), operand));
22282237
}
2238+
DeallocPackMetadataInst *createDeallocPackMetadata(SILLocation loc,
2239+
SILValue alloc) {
2240+
return insert(new (getModule())
2241+
DeallocPackMetadataInst(getSILDebugLocation(loc), alloc));
2242+
}
22292243
DeallocStackRefInst *createDeallocStackRef(SILLocation Loc,
22302244
SILValue operand) {
22312245
return insert(new (getModule())

include/swift/SIL/SILCloner.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -892,6 +892,14 @@ SILCloner<ImplClass>::visitAllocStackInst(AllocStackInst *Inst) {
892892
recordClonedInstruction(Inst, NewInst);
893893
}
894894

895+
template <typename ImplClass>
896+
void SILCloner<ImplClass>::visitAllocPackMetadataInst(
897+
AllocPackMetadataInst *Inst) {
898+
getBuilder().setCurrentDebugScope(getOpScope(Inst->getDebugScope()));
899+
recordClonedInstruction(Inst, getBuilder().createAllocPackMetadata(
900+
getOpLocation(Inst->getLoc())));
901+
}
902+
895903
template<typename ImplClass>
896904
void
897905
SILCloner<ImplClass>::visitAllocPackInst(AllocPackInst *Inst) {
@@ -2854,6 +2862,15 @@ SILCloner<ImplClass>::visitDeallocPackInst(DeallocPackInst *Inst) {
28542862
getOpValue(Inst->getOperand())));
28552863
}
28562864

2865+
template <typename ImplClass>
2866+
void SILCloner<ImplClass>::visitDeallocPackMetadataInst(
2867+
DeallocPackMetadataInst *Inst) {
2868+
getBuilder().setCurrentDebugScope(getOpScope(Inst->getDebugScope()));
2869+
recordClonedInstruction(
2870+
Inst, getBuilder().createDeallocPackMetadata(
2871+
getOpLocation(Inst->getLoc()), Inst->getOperand()));
2872+
}
2873+
28572874
template<typename ImplClass>
28582875
void
28592876
SILCloner<ImplClass>::visitDeallocRefInst(DeallocRefInst *Inst) {

include/swift/SIL/SILFunction.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,11 @@ enum ForceEnableLexicalLifetimes_t {
7676
DoForceEnableLexicalLifetimes
7777
};
7878

79+
enum UseStackForPackMetadata_t {
80+
DoNotUseStackForPackMetadata,
81+
DoUseStackForPackMetadata,
82+
};
83+
7984
enum class PerformanceConstraints : uint8_t {
8085
None = 0,
8186
NoAllocation = 1,
@@ -418,6 +423,10 @@ class SILFunction
418423
/// If true, the function has lexical lifetimes even if the module does not.
419424
unsigned ForceEnableLexicalLifetimes : 1;
420425

426+
/// If true, the function contains an instruction that prevents stack nesting
427+
/// from running with pack metadata markers in place.
428+
unsigned UseStackForPackMetadata : 1;
429+
421430
static void
422431
validateSubclassScope(SubclassScope scope, IsThunk_t isThunk,
423432
const GenericSpecializationInformation *genericInfo) {
@@ -693,6 +702,14 @@ class SILFunction
693702
ForceEnableLexicalLifetimes = value;
694703
}
695704

705+
UseStackForPackMetadata_t useStackForPackMetadata() const {
706+
return UseStackForPackMetadata_t(UseStackForPackMetadata);
707+
}
708+
709+
void setUseStackForPackMetadata(UseStackForPackMetadata_t value) {
710+
UseStackForPackMetadata = value;
711+
}
712+
696713
/// Returns true if this is a reabstraction thunk of escaping function type
697714
/// whose single argument is a potentially non-escaping closure. i.e. the
698715
/// thunks' function argument may itself have @inout_aliasable parameters.

include/swift/SIL/SILInstruction.h

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -821,6 +821,10 @@ class SILInstruction : public llvm::ilist_node<SILInstruction> {
821821
/// The first operand must be the allocating instruction.
822822
bool isDeallocatingStack() const;
823823

824+
/// Whether IRGen lowering of this instruction may result in emitting packs of
825+
/// metadata or witness tables.
826+
bool mayRequirePackMetadata() const;
827+
824828
/// Create a new copy of this instruction, which retains all of the operands
825829
/// and other information of this one. If an insertion point is specified,
826830
/// then the new instruction is inserted before the specified point, otherwise
@@ -2275,6 +2279,27 @@ class AllocPackInst final
22752279
}
22762280
};
22772281

2282+
/// AllocPackMetadataInst - Marker instruction indicating that the next
2283+
/// instruction might allocate on-stack pack metadata
2284+
/// during IRGen.
2285+
///
2286+
/// Only valid in lowered SIL.
2287+
class AllocPackMetadataInst final
2288+
: public NullaryInstructionWithTypeDependentOperandsBase<
2289+
SILInstructionKind::AllocPackMetadataInst, AllocPackMetadataInst,
2290+
AllocationInst> {
2291+
friend SILBuilder;
2292+
2293+
AllocPackMetadataInst(SILDebugLocation loc, SILType elementType)
2294+
: NullaryInstructionWithTypeDependentOperandsBase(
2295+
loc, {}, elementType.getAddressType()) {}
2296+
2297+
public:
2298+
/// The instruction which may trigger on-stack pack metadata when IRGen
2299+
/// lowering.
2300+
SILInstruction *getIntroducer() { return getNextInstruction(); }
2301+
};
2302+
22782303
/// The base class for AllocRefInst and AllocRefDynamicInst.
22792304
///
22802305
/// The first NumTailTypes operands are counts for the tail allocated
@@ -8685,6 +8710,27 @@ class DeallocPackInst :
86858710
: UnaryInstructionBase(debugLoc, operand) {}
86868711
};
86878712

8713+
/// DeallocPackMetadataInst - Deallocate stack memory allocated on behalf of the
8714+
/// operand by IRGen.
8715+
///
8716+
/// Only valid in lowered SIL.
8717+
class DeallocPackMetadataInst final
8718+
: public UnaryInstructionBase<SILInstructionKind::DeallocPackMetadataInst,
8719+
DeallocationInst> {
8720+
friend SILBuilder;
8721+
8722+
DeallocPackMetadataInst(SILDebugLocation debugLoc, SILValue alloc)
8723+
: UnaryInstructionBase(debugLoc, alloc) {}
8724+
8725+
public:
8726+
AllocPackMetadataInst *getAllocation() {
8727+
return cast<AllocPackMetadataInst>(getOperand().getDefiningInstruction());
8728+
}
8729+
/// The instruction which may trigger on-stack pack metadata when IRGen
8730+
/// lowering.
8731+
SILInstruction *getIntroducer() { return getAllocation()->getIntroducer(); }
8732+
};
8733+
86888734
/// Like DeallocStackInst, but for `alloc_ref [stack]`.
86898735
class DeallocStackRefInst
86908736
: public UnaryInstructionBase<SILInstructionKind::DeallocStackRefInst,

include/swift/SIL/SILNodes.def

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -310,6 +310,8 @@ ABSTRACT_VALUE_AND_INST(SingleValueInstruction, ValueBase, SILInstruction)
310310
AllocationInst, None, DoesNotRelease)
311311
SINGLE_VALUE_INST(AllocPackInst, alloc_pack,
312312
AllocationInst, None, DoesNotRelease)
313+
SINGLE_VALUE_INST(AllocPackMetadataInst, alloc_pack_metadata,
314+
AllocationInst, None, DoesNotRelease)
313315
SINGLE_VALUE_INST(AllocRefInst, alloc_ref,
314316
AllocationInst, None, DoesNotRelease)
315317
SINGLE_VALUE_INST(AllocRefDynamicInst, alloc_ref_dynamic,
@@ -727,6 +729,8 @@ ABSTRACT_INST(DeallocationInst, SILInstruction)
727729
DeallocationInst, MayHaveSideEffects, DoesNotRelease)
728730
NON_VALUE_INST(DeallocPackInst, dealloc_pack,
729731
DeallocationInst, MayHaveSideEffects, DoesNotRelease)
732+
NON_VALUE_INST(DeallocPackMetadataInst, dealloc_pack_metadata,
733+
DeallocationInst, MayHaveSideEffects, DoesNotRelease)
730734
NON_VALUE_INST(DeallocStackRefInst, dealloc_stack_ref,
731735
DeallocationInst, MayHaveSideEffects, DoesNotRelease)
732736
NON_VALUE_INST(DeallocRefInst, dealloc_ref,

include/swift/SIL/SILType.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -373,6 +373,16 @@ class SILType {
373373
/// An efficient implementation of `!isTrivial() && isOrContainsRawPointer()`.
374374
bool isNonTrivialOrContainsRawPointer(const SILFunction *f) const;
375375

376+
/// Whether the type contains a generic parameter declared as a parameter
377+
/// pack.
378+
bool hasParameterPack() const { return getASTType()->hasParameterPack(); }
379+
380+
/// Whether the type contains a concrete pack.
381+
bool hasConcretePack() const { return getASTType()->hasConcretePack(); }
382+
383+
/// Whether the type contains some flavor of pack.
384+
bool hasPack() const { return getASTType()->hasPack(); }
385+
376386
/// True if the type is an empty tuple or an empty struct or a tuple or
377387
/// struct containing only empty types.
378388
bool isEmpty(const SILFunction &F) const;

include/swift/SILOptimizer/PassManager/Passes.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -353,6 +353,8 @@ IRGEN_PASS(LoadableByAddress, "loadable-address",
353353
"SIL Large Loadable type by-address lowering.")
354354
PASS(MandatorySILLinker, "mandatory-linker",
355355
"Deserialize all referenced SIL functions that are shared or transparent")
356+
IRGEN_PASS(PackMetadataMarkerInserter, "pack-metadata-marker-inserter",
357+
"Insert markers where pack metadata might be de/allocated.")
356358
PASS(PerformanceSILLinker, "performance-linker",
357359
"Deserialize all referenced SIL functions")
358360
PASS(RawSILInstLowering, "raw-sil-inst-lowering",

include/swift/SILOptimizer/Utils/StackNesting.h

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -88,10 +88,10 @@ class StackNesting {
8888
///
8989
/// Each stack location is allocated by a single allocation instruction.
9090
struct StackLoc {
91-
StackLoc(SingleValueInstruction *Alloc) : Alloc(Alloc) { }
91+
StackLoc(SILInstruction *Alloc) : Alloc(Alloc) {}
9292

9393
/// Back-link to the allocation instruction.
94-
SingleValueInstruction *Alloc;
94+
SILInstruction *Alloc;
9595

9696
/// Bit-set which represents all alive locations at this allocation.
9797
/// It obviously includes this location itself. And it includes all "outer"
@@ -100,7 +100,7 @@ class StackNesting {
100100
};
101101

102102
/// Mapping from stack allocations (= locations) to bit numbers.
103-
llvm::DenseMap<SingleValueInstruction *, unsigned> StackLoc2BitNumbers;
103+
llvm::DenseMap<SILInstruction *, unsigned> StackLoc2BitNumbers;
104104

105105
/// The list of stack locations. The index into this array is also the bit
106106
/// number in the bit-sets.
@@ -147,16 +147,22 @@ class StackNesting {
147147
/// Returns the location bit number for a stack allocation instruction.
148148
int bitNumberForAlloc(SILInstruction *AllocInst) {
149149
assert(AllocInst->isAllocatingStack());
150-
return StackLoc2BitNumbers[cast<SingleValueInstruction>(AllocInst)];
150+
return StackLoc2BitNumbers[AllocInst];
151151
}
152152

153153
/// Returns the location bit number for a stack deallocation instruction.
154154
int bitNumberForDealloc(SILInstruction *DeallocInst) {
155155
assert(DeallocInst->isDeallocatingStack());
156-
auto *AllocInst = cast<SingleValueInstruction>(DeallocInst->getOperand(0));
156+
auto *AllocInst = getAllocForDealloc(DeallocInst);
157157
return bitNumberForAlloc(AllocInst);
158158
}
159159

160+
/// Returns the stack allocation instruction for a stack deallocation
161+
/// instruction.
162+
SILInstruction *getAllocForDealloc(SILInstruction *Dealloc) const {
163+
return Dealloc->getOperand(0)->getDefiningInstruction();
164+
}
165+
160166
/// Insert deallocations at block boundaries.
161167
Changes insertDeallocsAtBlockBoundaries();
162168

0 commit comments

Comments
 (0)