Skip to content

Commit 0844bbd

Browse files
authored
Merge pull request #40738 from eeckstein/rename-dealloc-ref-stack
Rename `dealloc_ref [stack]` and enable StackPromotion for OSSA
2 parents 835beda + 802d11a commit 0844bbd

File tree

62 files changed

+271
-227
lines changed

Some content is hidden

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

62 files changed

+271
-227
lines changed

SwiftCompilerSources/Sources/SIL/Instruction.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,10 @@ final public class DeallocStackInst : Instruction, UnaryInstruction {
208208
}
209209
}
210210

211+
final public class DeallocStackRefInst : Instruction, UnaryInstruction {
212+
public var allocRef: AllocRefInst { operand as! AllocRefInst }
213+
}
214+
211215
final public class CondFailInst : Instruction, UnaryInstruction {
212216
public override var mayTrap: Bool { true }
213217

SwiftCompilerSources/Sources/SIL/Registration.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ public func registerSILClasses() {
4242
register(EndAccessInst.self)
4343
register(EndBorrowInst.self)
4444
register(DeallocStackInst.self)
45+
register(DeallocStackRefInst.self)
4546
register(CondFailInst.self)
4647
register(FixLifetimeInst.self)
4748
register(DebugValueInst.self)

docs/SIL.rst

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3143,8 +3143,8 @@ optional ``objc`` attribute indicates that the object should be
31433143
allocated using Objective-C's allocation methods (``+allocWithZone:``).
31443144

31453145
The optional ``stack`` attribute indicates that the object can be allocated
3146-
on the stack instead on the heap. In this case the instruction must have
3147-
balanced with a ``dealloc_ref [stack]`` instruction to mark the end of the
3146+
on the stack instead on the heap. In this case the instruction must be
3147+
balanced with a ``dealloc_stack_ref`` instruction to mark the end of the
31483148
object's lifetime.
31493149
Note that the ``stack`` attribute only specifies that stack allocation is
31503150
possible. The final decision on stack allocation is done during llvm IR
@@ -3381,13 +3381,25 @@ project_box
33813381

33823382
Given a ``@box T`` reference, produces the address of the value inside the box.
33833383

3384+
dealloc_stack_ref
3385+
`````````````````
3386+
::
3387+
3388+
sil-instruction ::= 'dealloc_stack_ref' sil-operand
3389+
3390+
dealloc_stack_ref %0 : $T
3391+
// $T must be a class type
3392+
// %0 must be an 'alloc_ref [stack]' instruction
3393+
3394+
Marks the deallocation of the stack space for an ``alloc_ref [stack]``.
3395+
33843396
dealloc_ref
33853397
```````````
33863398
::
33873399

3388-
sil-instruction ::= 'dealloc_ref' ('[' 'stack' ']')? sil-operand
3400+
sil-instruction ::= 'dealloc_ref' sil-operand
33893401

3390-
dealloc_ref [stack] %0 : $T
3402+
dealloc_ref %0 : $T
33913403
// $T must be a class type
33923404

33933405
Deallocates an uninitialized class type instance, bypassing the reference

include/swift/SIL/SILBuilder.h

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2005,10 +2005,14 @@ class SILBuilder {
20052005
return insert(new (getModule())
20062006
DeallocStackInst(getSILDebugLocation(Loc), operand));
20072007
}
2008-
DeallocRefInst *createDeallocRef(SILLocation Loc, SILValue operand,
2009-
bool canBeOnStack) {
2008+
DeallocStackRefInst *createDeallocStackRef(SILLocation Loc,
2009+
SILValue operand) {
2010+
return insert(new (getModule())
2011+
DeallocStackRefInst(getSILDebugLocation(Loc), operand));
2012+
}
2013+
DeallocRefInst *createDeallocRef(SILLocation Loc, SILValue operand) {
20102014
return insert(new (getModule()) DeallocRefInst(
2011-
getSILDebugLocation(Loc), operand, canBeOnStack));
2015+
getSILDebugLocation(Loc), operand));
20122016
}
20132017
DeallocPartialRefInst *createDeallocPartialRef(SILLocation Loc,
20142018
SILValue operand,

include/swift/SIL/SILCloner.h

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2488,8 +2488,16 @@ SILCloner<ImplClass>::visitDeallocRefInst(DeallocRefInst *Inst) {
24882488
getBuilder().setCurrentDebugScope(getOpScope(Inst->getDebugScope()));
24892489
recordClonedInstruction(
24902490
Inst, getBuilder().createDeallocRef(getOpLocation(Inst->getLoc()),
2491-
getOpValue(Inst->getOperand()),
2492-
Inst->canAllocOnStack()));
2491+
getOpValue(Inst->getOperand())));
2492+
}
2493+
2494+
template<typename ImplClass>
2495+
void
2496+
SILCloner<ImplClass>::visitDeallocStackRefInst(DeallocStackRefInst *Inst) {
2497+
getBuilder().setCurrentDebugScope(getOpScope(Inst->getDebugScope()));
2498+
recordClonedInstruction(
2499+
Inst, getBuilder().createDeallocStackRef(getOpLocation(Inst->getLoc()),
2500+
getOpValue(Inst->getOperand())));
24932501
}
24942502

24952503
template<typename ImplClass>

include/swift/SIL/SILInstruction.h

Lines changed: 14 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -7619,6 +7619,18 @@ class DeallocStackInst :
76197619
: UnaryInstructionBase(DebugLoc, operand) {}
76207620
};
76217621

7622+
/// Like DeallocStackInst, but for `alloc_ref [stack]`.
7623+
class DeallocStackRefInst
7624+
: public UnaryInstructionBase<SILInstructionKind::DeallocStackRefInst,
7625+
DeallocationInst> {
7626+
friend SILBuilder;
7627+
7628+
DeallocStackRefInst(SILDebugLocation DebugLoc, SILValue Operand)
7629+
: UnaryInstructionBase(DebugLoc, Operand) {}
7630+
public:
7631+
AllocRefInst *getAllocRef() { return cast<AllocRefInst>(getOperand()); }
7632+
};
7633+
76227634
/// Deallocate memory for a reference type instance from a destructor or
76237635
/// failure path of a constructor.
76247636
///
@@ -7632,21 +7644,8 @@ class DeallocRefInst :
76327644
DeallocationInst> {
76337645
friend SILBuilder;
76347646

7635-
private:
7636-
DeallocRefInst(SILDebugLocation DebugLoc, SILValue Operand,
7637-
bool canBeOnStack = false)
7638-
: UnaryInstructionBase(DebugLoc, Operand) {
7639-
SILNode::Bits.DeallocRefInst.OnStack = canBeOnStack;
7640-
}
7641-
7642-
public:
7643-
bool canAllocOnStack() const {
7644-
return SILNode::Bits.DeallocRefInst.OnStack;
7645-
}
7646-
7647-
void setStackAllocatable(bool OnStack) {
7648-
SILNode::Bits.DeallocRefInst.OnStack = OnStack;
7649-
}
7647+
DeallocRefInst(SILDebugLocation DebugLoc, SILValue Operand)
7648+
: UnaryInstructionBase(DebugLoc, Operand) { }
76507649
};
76517650

76527651
/// Deallocate memory for a reference type instance from a failure path of a

include/swift/SIL/SILNode.h

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -218,10 +218,6 @@ class alignas(8) SILNode :
218218
Length : 32
219219
);
220220

221-
SWIFT_INLINE_BITFIELD(DeallocRefInst, DeallocationInst, 1,
222-
OnStack : 1
223-
);
224-
225221
// Ensure that AllocBoxInst bitfield does not overflow.
226222
IBWTO_BITFIELD_EMPTY(AllocBoxInst, AllocationInst);
227223
// Ensure that AllocExistentialBoxInst bitfield does not overflow.

include/swift/SIL/SILNodes.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -808,6 +808,8 @@ ABSTRACT_INST(TermInst, SILInstruction)
808808
ABSTRACT_INST(DeallocationInst, SILInstruction)
809809
BRIDGED_NON_VALUE_INST(DeallocStackInst, dealloc_stack,
810810
DeallocationInst, MayHaveSideEffects, DoesNotRelease)
811+
BRIDGED_NON_VALUE_INST(DeallocStackRefInst, dealloc_stack_ref,
812+
DeallocationInst, MayHaveSideEffects, DoesNotRelease)
811813
BRIDGED_NON_VALUE_INST(DeallocRefInst, dealloc_ref,
812814
DeallocationInst, MayHaveSideEffects, DoesNotRelease)
813815
NON_VALUE_INST(DeallocPartialRefInst, dealloc_partial_ref,

include/swift/SILOptimizer/Utils/ValueLifetime.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,8 @@ class ValueLifetimeAnalysis {
197197
(hasUsersBeforeDef || bb != getDefValueParentBlock());
198198
}
199199

200-
/// Checks if there is a dealloc_ref inside the value's live range.
200+
/// Checks if there is a dealloc_ref or dealloc_stack_ref inside the
201+
/// value's live range.
201202
bool containsDeallocRef(const FrontierImpl &frontier);
202203

203204
/// For debug dumping.

lib/IRGen/IRGenSIL.cpp

Lines changed: 24 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1257,6 +1257,7 @@ class IRGenSILFunction :
12571257
void visitEndCOWMutationInst(EndCOWMutationInst *i);
12581258
void visitIsEscapingClosureInst(IsEscapingClosureInst *i);
12591259
void visitDeallocStackInst(DeallocStackInst *i);
1260+
void visitDeallocStackRefInst(DeallocStackRefInst *i);
12601261
void visitDeallocBoxInst(DeallocBoxInst *i);
12611262
void visitDeallocRefInst(DeallocRefInst *i);
12621263
void visitDeallocPartialRefInst(DeallocPartialRefInst *i);
@@ -4515,9 +4516,9 @@ void IRGenSILFunction::visitSetDeallocatingInst(SetDeallocatingInst *i) {
45154516
// ...
45164517
// set_deallocating %0 // not needed
45174518
// // code which does not depend on the RC_DEALLOCATING_FLAG flag.
4518-
// dealloc_ref %0 // not needed (stems from the inlined deallocator)
4519+
// dealloc_ref %0 // stems from the inlined deallocator
45194520
// ...
4520-
// dealloc_ref [stack] %0
4521+
// dealloc_stack_ref %0
45214522
SILBasicBlock::iterator Iter(i);
45224523
SILBasicBlock::iterator End = i->getParent()->end();
45234524
for (++Iter; Iter != End; ++Iter) {
@@ -5432,32 +5433,10 @@ void IRGenSILFunction::visitDeallocStackInst(swift::DeallocStackInst *i) {
54325433
allocatedTI.deallocateStack(*this, stackAddr, allocatedType);
54335434
}
54345435

5435-
void IRGenSILFunction::visitDeallocRefInst(swift::DeallocRefInst *i) {
5436-
// Lower the operand.
5436+
void IRGenSILFunction::visitDeallocStackRefInst(DeallocStackRefInst *i) {
54375437
Explosion self = getLoweredExplosion(i->getOperand());
54385438
auto selfValue = self.claimNext();
5439-
auto *ARI = dyn_cast<AllocRefInst>(i->getOperand());
5440-
if (!i->canAllocOnStack()) {
5441-
if (ARI && StackAllocs.count(ARI)) {
5442-
// We can ignore dealloc_refs (without [stack]) for stack allocated
5443-
// objects.
5444-
//
5445-
// %0 = alloc_ref [stack]
5446-
// ...
5447-
// dealloc_ref %0 // not needed (stems from the inlined deallocator)
5448-
// ...
5449-
// dealloc_ref [stack] %0
5450-
return;
5451-
}
5452-
5453-
auto classType = i->getOperand()->getType();
5454-
emitClassDeallocation(*this, classType, selfValue);
5455-
return;
5456-
}
5457-
// It's a dealloc_ref [stack]. Even if the alloc_ref did not allocate the
5458-
// object on the stack, we don't have to deallocate it, because it is
5459-
// deallocated in the final release.
5460-
assert(ARI->canAllocOnStack());
5439+
auto *ARI = i->getAllocRef();
54615440
if (StackAllocs.count(ARI)) {
54625441
if (IGM.IRGen.Opts.EmitStackPromotionChecks) {
54635442
selfValue = Builder.CreateBitCast(selfValue, IGM.RefCountedPtrTy);
@@ -5473,6 +5452,25 @@ void IRGenSILFunction::visitDeallocRefInst(swift::DeallocRefInst *i) {
54735452
}
54745453
}
54755454

5455+
void IRGenSILFunction::visitDeallocRefInst(swift::DeallocRefInst *i) {
5456+
// Lower the operand.
5457+
Explosion self = getLoweredExplosion(i->getOperand());
5458+
auto selfValue = self.claimNext();
5459+
auto *ARI = dyn_cast<AllocRefInst>(i->getOperand());
5460+
if (ARI && StackAllocs.count(ARI)) {
5461+
// We can ignore dealloc_refs for stack allocated objects.
5462+
//
5463+
// %0 = alloc_ref [stack]
5464+
// ...
5465+
// dealloc_ref %0 // not needed (stems from the inlined deallocator)
5466+
// ...
5467+
// dealloc_stack_ref %0
5468+
return;
5469+
}
5470+
auto classType = i->getOperand()->getType();
5471+
emitClassDeallocation(*this, classType, selfValue);
5472+
}
5473+
54765474
void IRGenSILFunction::visitDeallocPartialRefInst(swift::DeallocPartialRefInst *i) {
54775475
Explosion self = getLoweredExplosion(i->getInstance());
54785476
auto selfValue = self.claimNext();

lib/SIL/IR/OperandOwnership.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,10 @@ OPERAND_OWNERSHIP(TrivialUse, UncheckedRefCastAddr)
184184
OPERAND_OWNERSHIP(TrivialUse, UncheckedTakeEnumDataAddr)
185185
OPERAND_OWNERSHIP(TrivialUse, UnconditionalCheckedCastAddr)
186186

187+
// The dealloc_stack_ref operand needs to have NonUse ownership because
188+
// this use comes after the last consuming use (which is usually a dealloc_ref).
189+
OPERAND_OWNERSHIP(NonUse, DeallocStackRef)
190+
187191
// Use an owned or guaranteed value only for the duration of the operation.
188192
OPERAND_OWNERSHIP(InstantaneousUse, ExistentialMetatype)
189193
OPERAND_OWNERSHIP(InstantaneousUse, FixLifetime)

lib/SIL/IR/SILInstruction.cpp

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -371,6 +371,10 @@ namespace {
371371
return true;
372372
}
373373

374+
bool visitDeallocStackRefInst(const DeallocStackRefInst *RHS) {
375+
return true;
376+
}
377+
374378
bool visitAllocStackInst(const AllocStackInst *RHS) {
375379
return true;
376380
}
@@ -1285,14 +1289,9 @@ bool SILInstruction::isAllocatingStack() const {
12851289
}
12861290

12871291
bool SILInstruction::isDeallocatingStack() const {
1288-
if (isa<DeallocStackInst>(this))
1292+
if (isa<DeallocStackInst>(this) || isa<DeallocStackRefInst>(this))
12891293
return true;
12901294

1291-
if (auto *DRI = dyn_cast<DeallocRefInst>(this)) {
1292-
if (DRI->canAllocOnStack())
1293-
return true;
1294-
}
1295-
12961295
if (auto *BI = dyn_cast<BuiltinInst>(this)) {
12971296
if (BI->getBuiltinKind() == BuiltinValueKind::StackDealloc) {
12981297
return true;

lib/SIL/IR/SILPrinter.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2211,9 +2211,10 @@ class SILPrinter : public SILInstructionVisitor<SILPrinter> {
22112211
void visitDeallocStackInst(DeallocStackInst *DI) {
22122212
*this << getIDAndType(DI->getOperand());
22132213
}
2214+
void visitDeallocStackRefInst(DeallocStackRefInst *ESRL) {
2215+
*this << getIDAndType(ESRL->getOperand());
2216+
}
22142217
void visitDeallocRefInst(DeallocRefInst *DI) {
2215-
if (DI->canAllocOnStack())
2216-
*this << "[stack] ";
22172218
*this << getIDAndType(DI->getOperand());
22182219
}
22192220
void visitDeallocPartialRefInst(DeallocPartialRefInst *DPI) {

lib/SIL/Parser/ParseSIL.cpp

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4301,14 +4301,15 @@ bool SILParser::parseSpecificSILInstruction(SILBuilder &B,
43014301
return true;
43024302
ResultVal = B.createDeallocStack(InstLoc, Val);
43034303
break;
4304-
case SILInstructionKind::DeallocRefInst: {
4305-
bool OnStack = false;
4306-
if (parseSILOptional(OnStack, *this, "stack"))
4304+
case SILInstructionKind::DeallocStackRefInst:
4305+
if (parseTypedValueRef(Val, B) || parseSILDebugLocation(InstLoc, B))
43074306
return true;
4308-
4307+
ResultVal = B.createDeallocStackRef(InstLoc, Val);
4308+
break;
4309+
case SILInstructionKind::DeallocRefInst: {
43094310
if (parseTypedValueRef(Val, B) || parseSILDebugLocation(InstLoc, B))
43104311
return true;
4311-
ResultVal = B.createDeallocRef(InstLoc, Val, OnStack);
4312+
ResultVal = B.createDeallocRef(InstLoc, Val);
43124313
break;
43134314
}
43144315
case SILInstructionKind::DeallocPartialRefInst: {

lib/SIL/Utils/InstructionUtils.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -461,6 +461,7 @@ RuntimeEffect swift::getRuntimeEffect(SILInstruction *inst, SILType &impactType)
461461
case SILInstructionKind::SwitchValueInst:
462462
case SILInstructionKind::SwitchEnumInst:
463463
case SILInstructionKind::DeallocStackInst:
464+
case SILInstructionKind::DeallocStackRefInst:
464465
case SILInstructionKind::AutoreleaseValueInst:
465466
case SILInstructionKind::BindMemoryInst:
466467
case SILInstructionKind::RebindMemoryInst:

lib/SIL/Utils/LoopInfo.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,8 +54,8 @@ bool SILLoop::canDuplicate(SILInstruction *I) const {
5454
if (isa<AllocStackInst>(address) || isa<PartialApplyInst>(address))
5555
alloc = cast<SingleValueInstruction>(address);
5656
}
57-
if (auto *dealloc = dyn_cast<DeallocRefInst>(I))
58-
alloc = dyn_cast<AllocRefInst>(dealloc->getOperand());
57+
if (auto *dealloc = dyn_cast<DeallocStackRefInst>(I))
58+
alloc = dealloc->getAllocRef();
5959

6060
return alloc && contains(alloc);
6161
}

lib/SIL/Verifier/SILOwnershipVerifier.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -207,9 +207,9 @@ bool SILValueOwnershipChecker::gatherNonGuaranteedUsers(
207207
for (auto *op : value->getUses()) {
208208
auto *user = op->getUser();
209209

210-
// If this op is a type dependent operand, skip it. It is not interesting
210+
// For example, type dependent operands are non-use. It is not interesting
211211
// from an ownership perspective.
212-
if (user->isTypeDependentOperand(*op))
212+
if (op->getOperandOwnership() == OperandOwnership::NonUse)
213213
continue;
214214

215215
// First check if this recursive use is compatible with our values ownership

lib/SIL/Verifier/SILVerifier.cpp

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2992,11 +2992,9 @@ class SILVerifier : public SILVerifierBase<SILVerifier> {
29922992
auto *cd = DI->getOperand()->getType().getClassOrBoundGenericClass();
29932993
require(cd, "Operand of dealloc_ref must be of class type");
29942994

2995-
if (!DI->canAllocOnStack()) {
2996-
require(!checkResilience(cd, F.getModule().getSwiftModule(),
2997-
F.getResilienceExpansion()),
2998-
"cannot directly deallocate resilient class");
2999-
}
2995+
require(!checkResilience(cd, F.getModule().getSwiftModule(),
2996+
F.getResilienceExpansion()),
2997+
"cannot directly deallocate resilient class");
30002998
}
30012999
void checkDeallocPartialRefInst(DeallocPartialRefInst *DPRI) {
30023000
require(DPRI->getInstance()->getType().isObject(),

lib/SILGen/SILGenDestructor.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,7 @@ void SILGenFunction::emitDeallocatingDestructor(DestructorDecl *dd) {
166166

167167
// Deallocate the object.
168168
selfForDealloc = B.createUncheckedRefCast(loc, selfForDealloc, classTy);
169-
B.createDeallocRef(loc, selfForDealloc, false);
169+
B.createDeallocRef(loc, selfForDealloc);
170170

171171
emitProfilerIncrement(dd->getTypecheckedBody());
172172

lib/SILOptimizer/Analysis/EscapeAnalysis.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2163,6 +2163,7 @@ void EscapeAnalysis::analyzeInstruction(SILInstruction *I,
21632163
case SILInstructionKind::InitExistentialMetatypeInst:
21642164
case SILInstructionKind::OpenExistentialMetatypeInst:
21652165
case SILInstructionKind::ExistentialMetatypeInst:
2166+
case SILInstructionKind::DeallocStackRefInst:
21662167
case SILInstructionKind::DeallocRefInst:
21672168
case SILInstructionKind::SetDeallocatingInst:
21682169
case SILInstructionKind::FixLifetimeInst:

lib/SILOptimizer/SILCombiner/SILCombinerApplyVisitors.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -616,7 +616,8 @@ bool SILCombiner::eraseApply(FullApplySite FAS, const UserListTy &Users) {
616616
if (!VLA.computeFrontier(Frontier, ValueLifetimeAnalysis::DontModifyCFG))
617617
return false;
618618
// As we are extending the lifetimes of owned parameters, we have to make
619-
// sure that no dealloc_ref instructions are within this extended liferange.
619+
// sure that no dealloc_ref or dealloc_stack_ref instructions are
620+
// within this extended liferange.
620621
// It could be that the dealloc_ref is deallocating a parameter and then
621622
// we would have a release after the dealloc.
622623
if (VLA.containsDeallocRef(Frontier))

0 commit comments

Comments
 (0)