Skip to content

Commit 04debd3

Browse files
Merge pull request #74922 from nate-chandler/lifetime-completion/20240701/1
[LifetimeCompletion] Flag ends synthesized in dead-ends.
2 parents e50beb0 + 02c28f5 commit 04debd3

Some content is hidden

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

41 files changed

+579
-139
lines changed

docs/SIL.rst

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4179,7 +4179,7 @@ dealloc_box
41794179
```````````
41804180
::
41814181

4182-
sil-instruction ::= 'dealloc_box' sil-operand
4182+
sil-instruction ::= 'dealloc_box' '[dead_end]'? sil-operand
41834183

41844184
dealloc_box %0 : $@box T
41854185

@@ -4192,6 +4192,9 @@ This does not destroy the boxed value. The contents of the
41924192
value must have been fully uninitialized or destroyed before
41934193
``dealloc_box`` is applied.
41944194

4195+
The optional ``dead_end`` attribute specifies that this instruction was created
4196+
during lifetime completion and is eligible for deletion during OSSA lowering.
4197+
41954198
project_box
41964199
```````````
41974200
::
@@ -6664,7 +6667,7 @@ destroy_value
66646667

66656668
::
66666669

6667-
sil-instruction ::= 'destroy_value' '[poison]'? sil-operand
6670+
sil-instruction ::= 'destroy_value' '[dead_end]'? '[poison]'? sil-operand
66686671

66696672
destroy_value %0 : $A
66706673

@@ -6682,6 +6685,9 @@ For aggregate types, especially enums, it is typically both easier
66826685
and more efficient to reason about aggregate destroys than it is to
66836686
reason about destroys of the subobjects.
66846687

6688+
The optional ``dead_end`` attribute specifies that this instruction was created
6689+
during lifetime completion and is eligible for deletion during OSSA lowering.
6690+
66856691
autorelease_value
66866692
`````````````````
66876693

include/swift/SIL/OSSALifetimeCompletion.h

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@
3434

3535
namespace swift {
3636

37+
class DeadEndBlocks;
38+
3739
enum class LifetimeCompletion { NoLifetime, AlreadyComplete, WasCompleted };
3840

3941
class OSSALifetimeCompletion {
@@ -42,13 +44,17 @@ class OSSALifetimeCompletion {
4244
// create a new phi would result in an immediately redundant phi.
4345
const DominanceInfo *domInfo = nullptr;
4446

47+
DeadEndBlocks &deadEndBlocks;
48+
4549
// Cache intructions already handled by the recursive algorithm to avoid
4650
// recomputing their lifetimes.
4751
ValueSet completedValues;
4852

4953
public:
50-
OSSALifetimeCompletion(SILFunction *function, const DominanceInfo *domInfo)
51-
: domInfo(domInfo), completedValues(function) {}
54+
OSSALifetimeCompletion(SILFunction *function, const DominanceInfo *domInfo,
55+
DeadEndBlocks &deadEndBlocks)
56+
: domInfo(domInfo), deadEndBlocks(deadEndBlocks),
57+
completedValues(function) {}
5258

5359
// The kind of boundary at which to complete the lifetime.
5460
//
@@ -139,16 +145,19 @@ class UnreachableLifetimeCompletion {
139145
// If domInfo is nullptr, lifetime completion may attempt to recreate
140146
// redundant phis, which should be immediately discarded.
141147
const DominanceInfo *domInfo = nullptr;
148+
DeadEndBlocks &deadEndBlocks;
142149

143150
BasicBlockSetVector unreachableBlocks;
144151
InstructionSet unreachableInsts; // not including those in unreachableBlocks
145152
ValueSetVector incompleteValues;
146153
bool updatingLifetimes = false;
147154

148155
public:
149-
UnreachableLifetimeCompletion(SILFunction *function, DominanceInfo *domInfo)
150-
: function(function), unreachableBlocks(function),
151-
unreachableInsts(function), incompleteValues(function) {}
156+
UnreachableLifetimeCompletion(SILFunction *function, DominanceInfo *domInfo,
157+
DeadEndBlocks &deadEndBlocks)
158+
: function(function), domInfo(domInfo), deadEndBlocks(deadEndBlocks),
159+
unreachableBlocks(function), unreachableInsts(function),
160+
incompleteValues(function) {}
152161

153162
/// Record information about this unreachable instruction and return true if
154163
/// ends any simple OSSA lifetimes.

include/swift/SIL/SILBuilder.h

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1072,7 +1072,7 @@ class SILBuilder {
10721072

10731073
DebugValueInst *createDebugValue(
10741074
SILLocation Loc, SILValue src, SILDebugVariable Var,
1075-
bool poisonRefs = false,
1075+
PoisonRefs_t poisonRefs = DontPoisonRefs,
10761076
UsesMoveableValueDebugInfo_t wasMoved = DoesNotUseMoveableValueDebugInfo,
10771077
bool trace = false);
10781078
DebugValueInst *createDebugValueAddr(
@@ -1443,14 +1443,15 @@ class SILBuilder {
14431443
}
14441444

14451445
DestroyValueInst *createDestroyValue(SILLocation Loc, SILValue operand,
1446-
bool poisonRefs = false) {
1446+
PoisonRefs_t poisonRefs = DontPoisonRefs,
1447+
IsDeadEnd_t isDeadEnd = IsntDeadEnd) {
14471448
assert(getFunction().hasOwnership());
14481449
assert(isLoadableOrOpaque(operand->getType()));
14491450
assert(!operand->getType().isTrivial(getFunction()) &&
14501451
"Should not be passing trivial values to this api. Use instead "
14511452
"emitDestroyValueOperation");
1452-
return insert(new (getModule()) DestroyValueInst(getSILDebugLocation(Loc),
1453-
operand, poisonRefs));
1453+
return insert(new (getModule()) DestroyValueInst(
1454+
getSILDebugLocation(Loc), operand, poisonRefs, isDeadEnd));
14541455
}
14551456

14561457
MoveValueInst *createMoveValue(
@@ -2386,10 +2387,10 @@ class SILBuilder {
23862387
return insert(new (getModule()) DeallocPartialRefInst(
23872388
getSILDebugLocation(Loc), operand, metatype));
23882389
}
2389-
DeallocBoxInst *createDeallocBox(SILLocation Loc,
2390-
SILValue operand) {
2391-
return insert(new (getModule()) DeallocBoxInst(
2392-
getSILDebugLocation(Loc), operand));
2390+
DeallocBoxInst *createDeallocBox(SILLocation Loc, SILValue operand,
2391+
IsDeadEnd_t isDeadEnd = IsntDeadEnd) {
2392+
return insert(new (getModule()) DeallocBoxInst(getSILDebugLocation(Loc),
2393+
operand, isDeadEnd));
23932394
}
23942395
DeallocExistentialBoxInst *createDeallocExistentialBox(SILLocation Loc,
23952396
CanType concreteType,

include/swift/SIL/SILCloner.h

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2208,10 +2208,10 @@ void SILCloner<ImplClass>::visitDestroyValueInst(DestroyValueInst *Inst) {
22082208
RefCountingInst::Atomicity::Atomic));
22092209
}
22102210

2211-
recordClonedInstruction(
2212-
Inst, getBuilder().createDestroyValue(getOpLocation(Inst->getLoc()),
2213-
getOpValue(Inst->getOperand()),
2214-
Inst->poisonRefs()));
2211+
recordClonedInstruction(Inst, getBuilder().createDestroyValue(
2212+
getOpLocation(Inst->getLoc()),
2213+
getOpValue(Inst->getOperand()),
2214+
Inst->poisonRefs(), Inst->isDeadEnd()));
22152215
}
22162216

22172217
template <typename ImplClass>
@@ -3175,7 +3175,8 @@ SILCloner<ImplClass>::visitDeallocBoxInst(DeallocBoxInst *Inst) {
31753175
getBuilder().setCurrentDebugScope(getOpScope(Inst->getDebugScope()));
31763176
recordClonedInstruction(
31773177
Inst, getBuilder().createDeallocBox(getOpLocation(Inst->getLoc()),
3178-
getOpValue(Inst->getOperand())));
3178+
getOpValue(Inst->getOperand()),
3179+
Inst->isDeadEnd()));
31793180
}
31803181

31813182
template<typename ImplClass>

include/swift/SIL/SILInstruction.h

Lines changed: 42 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5381,6 +5381,11 @@ class DebugStepInst final
53815381
MutableArrayRef<Operand> getAllOperands() { return {}; }
53825382
};
53835383

5384+
enum PoisonRefs_t : bool {
5385+
DontPoisonRefs = false,
5386+
PoisonRefs = true,
5387+
};
5388+
53845389
/// Define the start or update to a symbolic variable value (for loadable
53855390
/// types).
53865391
class DebugValueInst final
@@ -5397,11 +5402,11 @@ class DebugValueInst final
53975402
USE_SHARED_UINT8;
53985403

53995404
DebugValueInst(SILDebugLocation DebugLoc, SILValue Operand,
5400-
SILDebugVariable Var, bool poisonRefs,
5405+
SILDebugVariable Var, PoisonRefs_t poisonRefs,
54015406
UsesMoveableValueDebugInfo_t operandWasMoved, bool trace);
54025407
static DebugValueInst *create(SILDebugLocation DebugLoc, SILValue Operand,
54035408
SILModule &M, SILDebugVariable Var,
5404-
bool poisonRefs,
5409+
PoisonRefs_t poisonRefs,
54055410
UsesMoveableValueDebugInfo_t operandWasMoved,
54065411
bool trace);
54075412
static DebugValueInst *createAddr(SILDebugLocation DebugLoc, SILValue Operand,
@@ -5511,9 +5516,11 @@ class DebugValueInst final
55115516
/// OSSA lowering. It should not be necessary to model the poison operation as
55125517
/// a side effect, which would violate the rule that debug_values cannot
55135518
/// affect optimization.
5514-
bool poisonRefs() const { return sharedUInt8().DebugValueInst.poisonRefs; }
5519+
PoisonRefs_t poisonRefs() const {
5520+
return PoisonRefs_t(sharedUInt8().DebugValueInst.poisonRefs);
5521+
}
55155522

5516-
void setPoisonRefs(bool poisonRefs = true) {
5523+
void setPoisonRefs(PoisonRefs_t poisonRefs = PoisonRefs) {
55175524
sharedUInt8().DebugValueInst.poisonRefs = poisonRefs;
55185525
}
55195526

@@ -8799,15 +8806,22 @@ class UnownedCopyValueInst
87998806
};
88008807
#include "swift/AST/ReferenceStorage.def"
88018808

8809+
enum IsDeadEnd_t : bool {
8810+
IsntDeadEnd = false,
8811+
IsDeadEnd = true,
8812+
};
8813+
88028814
class DestroyValueInst
88038815
: public UnaryInstructionBase<SILInstructionKind::DestroyValueInst,
88048816
NonValueInstruction> {
88058817
friend class SILBuilder;
88068818
USE_SHARED_UINT8;
88078819

8808-
DestroyValueInst(SILDebugLocation DebugLoc, SILValue operand, bool poisonRefs)
8820+
DestroyValueInst(SILDebugLocation DebugLoc, SILValue operand,
8821+
PoisonRefs_t poisonRefs, IsDeadEnd_t isDeadEnd)
88098822
: UnaryInstructionBase(DebugLoc, operand) {
8810-
setPoisonRefs(poisonRefs);
8823+
sharedUInt8().DestroyValueInst.poisonRefs = poisonRefs;
8824+
sharedUInt8().DestroyValueInst.deadEnd = isDeadEnd;
88118825
}
88128826

88138827
public:
@@ -8824,15 +8838,21 @@ class DestroyValueInst
88248838
/// transformations keep the poison operation associated with the destroy
88258839
/// point. After OSSA, these are lowered to 'debug_values [poison]'
88268840
/// instructions, after which the Onone pipeline should avoid code motion.
8827-
bool poisonRefs() const { return sharedUInt8().DestroyValueInst.poisonRefs; }
8841+
PoisonRefs_t poisonRefs() const {
8842+
return PoisonRefs_t(sharedUInt8().DestroyValueInst.poisonRefs);
8843+
}
88288844

8829-
void setPoisonRefs(bool poisonRefs = true) {
8845+
void setPoisonRefs(PoisonRefs_t poisonRefs = PoisonRefs) {
88308846
sharedUInt8().DestroyValueInst.poisonRefs = poisonRefs;
88318847
}
8832-
8848+
88338849
/// If the value being destroyed is a stack allocation of a nonescaping
88348850
/// closure, then return the PartialApplyInst that allocated the closure.
88358851
PartialApplyInst *getNonescapingClosureAllocation() const;
8852+
8853+
IsDeadEnd_t isDeadEnd() const {
8854+
return IsDeadEnd_t(sharedUInt8().DestroyValueInst.deadEnd);
8855+
}
88368856
};
88378857

88388858
class MoveValueInst
@@ -9443,8 +9463,19 @@ class DeallocBoxInst
94439463
{
94449464
friend SILBuilder;
94459465

9446-
DeallocBoxInst(SILDebugLocation DebugLoc, SILValue operand)
9447-
: UnaryInstructionBase(DebugLoc, operand) {}
9466+
USE_SHARED_UINT8;
9467+
9468+
public:
9469+
IsDeadEnd_t isDeadEnd() const {
9470+
return IsDeadEnd_t(sharedUInt8().DeallocBoxInst.deadEnd);
9471+
}
9472+
9473+
private:
9474+
DeallocBoxInst(SILDebugLocation DebugLoc, SILValue operand,
9475+
IsDeadEnd_t isDeadEnd)
9476+
: UnaryInstructionBase(DebugLoc, operand) {
9477+
sharedUInt8().DeallocBoxInst.deadEnd = isDeadEnd;
9478+
}
94489479
};
94499480

94509481
/// Deallocate memory allocated for a boxed existential container created by

include/swift/SIL/SILNode.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,9 @@ class alignas(8) SILNode :
205205
SHARED_FIELD(AddressToPointerInst, bool needsStackProtection);
206206
SHARED_FIELD(IndexAddrInst, bool needsStackProtection);
207207
SHARED_FIELD(HopToExecutorInst, bool mandatory);
208-
SHARED_FIELD(DestroyValueInst, bool poisonRefs);
208+
SHARED_FIELD(DestroyValueInst, uint8_t
209+
poisonRefs : 1,
210+
deadEnd : 1);
209211
SHARED_FIELD(EndCOWMutationInst, bool keepUnique);
210212
SHARED_FIELD(ConvertFunctionInst, bool withoutActuallyEscaping);
211213
SHARED_FIELD(BeginCOWMutationInst, bool native);
@@ -246,6 +248,9 @@ class alignas(8) SILNode :
246248
fromVarDecl : 1,
247249
fixed : 1);
248250

251+
SHARED_FIELD(DeallocBoxInst, uint8_t
252+
deadEnd : 1);
253+
249254
SHARED_FIELD(CopyAddrInst, uint8_t
250255
isTakeOfSrc : 1,
251256
isInitializationOfDest : 1);

include/swift/SIL/Test.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,7 @@ class SILFunctionTransform;
108108
class SILPassManager;
109109
class DominanceAnalysis;
110110
class DominanceInfo;
111+
class DeadEndBlocks;
111112

112113
namespace test {
113114

@@ -162,6 +163,9 @@ class FunctionTest final {
162163
/// Computes and returns the function's dominance tree.
163164
DominanceInfo *getDominanceInfo();
164165

166+
/// The function's dead-end blocks.
167+
DeadEndBlocks *getDeadEndBlocks();
168+
165169
/// Returns the active pass manager.
166170
SILPassManager *getPassManager();
167171

@@ -254,6 +258,7 @@ class FunctionTest final {
254258
/// are visible: TestRunner::FunctionTestDependenciesImpl.
255259
struct Dependencies {
256260
virtual DominanceInfo *getDominanceInfo() = 0;
261+
virtual DeadEndBlocks *getDeadEndBlocks() = 0;
257262
virtual SILPassManager *getPassManager() = 0;
258263
virtual SwiftPassInvocation *getSwiftPassInvocation() = 0;
259264
virtual ~Dependencies(){};

lib/SIL/IR/SILBuilder.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -635,7 +635,7 @@ void SILBuilder::emitDestructureValueOperation(
635635

636636
DebugValueInst *SILBuilder::createDebugValue(SILLocation Loc, SILValue src,
637637
SILDebugVariable Var,
638-
bool poisonRefs,
638+
PoisonRefs_t poisonRefs,
639639
UsesMoveableValueDebugInfo_t moved,
640640
bool trace) {
641641
if (shouldDropVariable(Var, Loc))

lib/SIL/IR/SILInstructions.cpp

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -436,8 +436,8 @@ SILType AllocBoxInst::getAddressType() const {
436436

437437
DebugValueInst::DebugValueInst(
438438
SILDebugLocation DebugLoc, SILValue Operand, SILDebugVariable Var,
439-
bool poisonRefs, UsesMoveableValueDebugInfo_t usesMoveableValueDebugInfo,
440-
bool trace)
439+
PoisonRefs_t poisonRefs,
440+
UsesMoveableValueDebugInfo_t usesMoveableValueDebugInfo, bool trace)
441441
: UnaryInstructionBase(DebugLoc, Operand),
442442
SILDebugVariableSupplement(Var.DIExpr.getNumElements(),
443443
Var.Type.has_value(), Var.Loc.has_value(),
@@ -454,7 +454,8 @@ DebugValueInst::DebugValueInst(
454454

455455
DebugValueInst *DebugValueInst::create(SILDebugLocation DebugLoc,
456456
SILValue Operand, SILModule &M,
457-
SILDebugVariable Var, bool poisonRefs,
457+
SILDebugVariable Var,
458+
PoisonRefs_t poisonRefs,
458459
UsesMoveableValueDebugInfo_t wasMoved,
459460
bool trace) {
460461
// Don't store the same information twice.
@@ -478,8 +479,8 @@ DebugValueInst::createAddr(SILDebugLocation DebugLoc, SILValue Operand,
478479
if (!isa<AllocStackInst>(Operand))
479480
Var.DIExpr.prependElements(
480481
{SILDIExprElement::createOperator(SILDIExprOperator::Dereference)});
481-
return DebugValueInst::create(DebugLoc, Operand, M, Var,
482-
/*poisonRefs=*/false, wasMoved, trace);
482+
return DebugValueInst::create(DebugLoc, Operand, M, Var, DontPoisonRefs,
483+
wasMoved, trace);
483484
}
484485

485486
bool DebugValueInst::exprStartsWithDeref() const {

lib/SIL/IR/SILPrinter.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2231,6 +2231,8 @@ class SILPrinter : public SILInstructionVisitor<SILPrinter> {
22312231
void visitDestroyValueInst(DestroyValueInst *I) {
22322232
if (I->poisonRefs())
22332233
*this << "[poison] ";
2234+
if (I->isDeadEnd())
2235+
*this << "[dead_end] ";
22342236
*this << getIDAndType(I->getOperand());
22352237
}
22362238

@@ -2647,6 +2649,8 @@ class SILPrinter : public SILInstructionVisitor<SILPrinter> {
26472649
*this << getIDAndType(DPI->getMetatype());
26482650
}
26492651
void visitDeallocBoxInst(DeallocBoxInst *DI) {
2652+
if (DI->isDeadEnd())
2653+
*this << "[dead_end] ";
26502654
*this << getIDAndType(DI->getOperand());
26512655
}
26522656
void visitDestroyAddrInst(DestroyAddrInst *DI) {

0 commit comments

Comments
 (0)