Skip to content

Commit a8cc3bf

Browse files
committed
[SIL] Add dead_end flag to destroy_value.
1 parent 91fe12a commit a8cc3bf

File tree

15 files changed

+200
-21
lines changed

15 files changed

+200
-21
lines changed

docs/SIL.rst

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6664,7 +6664,7 @@ destroy_value
66646664

66656665
::
66666666

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

66696669
destroy_value %0 : $A
66706670

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

6685+
The optional ``dead_end`` attribute specifies that this instruction was created
6686+
during lifetime completion and is eligible for deletion during OSSA lowering.
6687+
66856688
autorelease_value
66866689
`````````````````
66876690

include/swift/SIL/SILBuilder.h

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1442,16 +1442,16 @@ class SILBuilder {
14421442
ExplicitCopyValueInst(getSILDebugLocation(Loc), operand));
14431443
}
14441444

1445-
DestroyValueInst *
1446-
createDestroyValue(SILLocation Loc, SILValue operand,
1447-
PoisonRefs_t poisonRefs = DontPoisonRefs) {
1445+
DestroyValueInst *createDestroyValue(SILLocation Loc, SILValue operand,
1446+
PoisonRefs_t poisonRefs = DontPoisonRefs,
1447+
IsDeadEnd_t isDeadEnd = IsntDeadEnd) {
14481448
assert(getFunction().hasOwnership());
14491449
assert(isLoadableOrOpaque(operand->getType()));
14501450
assert(!operand->getType().isTrivial(getFunction()) &&
14511451
"Should not be passing trivial values to this api. Use instead "
14521452
"emitDestroyValueOperation");
1453-
return insert(new (getModule()) DestroyValueInst(getSILDebugLocation(Loc),
1454-
operand, poisonRefs));
1453+
return insert(new (getModule()) DestroyValueInst(
1454+
getSILDebugLocation(Loc), operand, poisonRefs, isDeadEnd));
14551455
}
14561456

14571457
MoveValueInst *createMoveValue(

include/swift/SIL/SILCloner.h

Lines changed: 4 additions & 4 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>

include/swift/SIL/SILInstruction.h

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8806,16 +8806,22 @@ class UnownedCopyValueInst
88068806
};
88078807
#include "swift/AST/ReferenceStorage.def"
88088808

8809+
enum IsDeadEnd_t : bool {
8810+
IsntDeadEnd = false,
8811+
IsDeadEnd = true,
8812+
};
8813+
88098814
class DestroyValueInst
88108815
: public UnaryInstructionBase<SILInstructionKind::DestroyValueInst,
88118816
NonValueInstruction> {
88128817
friend class SILBuilder;
88138818
USE_SHARED_UINT8;
88148819

88158820
DestroyValueInst(SILDebugLocation DebugLoc, SILValue operand,
8816-
PoisonRefs_t poisonRefs)
8821+
PoisonRefs_t poisonRefs, IsDeadEnd_t isDeadEnd)
88178822
: UnaryInstructionBase(DebugLoc, operand) {
8818-
setPoisonRefs(poisonRefs);
8823+
sharedUInt8().DestroyValueInst.poisonRefs = poisonRefs;
8824+
sharedUInt8().DestroyValueInst.deadEnd = isDeadEnd;
88198825
}
88208826

88218827
public:
@@ -8843,6 +8849,10 @@ class DestroyValueInst
88438849
/// If the value being destroyed is a stack allocation of a nonescaping
88448850
/// closure, then return the PartialApplyInst that allocated the closure.
88458851
PartialApplyInst *getNonescapingClosureAllocation() const;
8852+
8853+
IsDeadEnd_t isDeadEnd() const {
8854+
return IsDeadEnd_t(sharedUInt8().DestroyValueInst.deadEnd);
8855+
}
88468856
};
88478857

88488858
class MoveValueInst

include/swift/SIL/SILNode.h

Lines changed: 3 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);

lib/SIL/IR/SILPrinter.cpp

Lines changed: 2 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

lib/SIL/Parser/ParseSIL.cpp

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3352,11 +3352,24 @@ bool SILParser::parseSpecificSILInstruction(SILBuilder &B,
33523352
break;
33533353
}
33543354
case SILInstructionKind::DestroyValueInst: {
3355-
bool poisonRefs = false;
3356-
if (parseSILOptional(poisonRefs, *this, "poison")
3357-
|| parseTypedValueRef(Val, B) || parseSILDebugLocation(InstLoc, B))
3355+
PoisonRefs_t poisonRefs = DontPoisonRefs;
3356+
IsDeadEnd_t isDeadEnd = IsntDeadEnd;
3357+
StringRef attributeName;
3358+
SourceLoc attributeLoc;
3359+
while (parseSILOptional(attributeName, attributeLoc, *this)) {
3360+
if (attributeName == "poison")
3361+
poisonRefs = PoisonRefs;
3362+
else if (attributeName == "dead_end")
3363+
isDeadEnd = IsDeadEnd;
3364+
else {
3365+
P.diagnose(attributeLoc, diag::sil_invalid_attribute_for_instruction,
3366+
attributeName, "destroy_value");
3367+
return true;
3368+
}
3369+
}
3370+
if (parseTypedValueRef(Val, B) || parseSILDebugLocation(InstLoc, B))
33583371
return true;
3359-
ResultVal = B.createDestroyValue(InstLoc, Val, PoisonRefs_t(poisonRefs));
3372+
ResultVal = B.createDestroyValue(InstLoc, Val, poisonRefs, isDeadEnd);
33603373
break;
33613374
}
33623375
case SILInstructionKind::BeginCOWMutationInst: {

lib/SIL/Verifier/SILVerifier.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3405,6 +3405,10 @@ class SILVerifier : public SILVerifierBase<SILVerifier> {
34053405
require(!fnConv.useLoweredAddresses() || F.hasOwnership(),
34063406
"destroy_value is only valid in functions with qualified "
34073407
"ownership");
3408+
if (I->isDeadEnd()) {
3409+
require(getDeadEndBlocks().isDeadEnd(I->getParentBlock()),
3410+
"a dead_end destroy_value must be in a dead-end block");
3411+
}
34083412
}
34093413

34103414
void checkReleaseValueInst(ReleaseValueInst *I) {

lib/Serialization/DeserializeSIL.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2323,12 +2323,13 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn,
23232323
case SILInstructionKind::DestroyValueInst: {
23242324
assert(RecordKind == SIL_ONE_OPERAND && "Layout should be OneOperand.");
23252325
PoisonRefs_t poisonRefs = PoisonRefs_t(Attr & 0x1);
2326+
IsDeadEnd_t isDeadEnd = IsDeadEnd_t((Attr >> 1) & 0x1);
23262327
ResultInst = Builder.createDestroyValue(
23272328
Loc,
23282329
getLocalValue(
23292330
Builder.maybeGetFunction(), ValID,
23302331
getSILType(MF->getType(TyID), (SILValueCategory)TyCategory, Fn)),
2331-
poisonRefs);
2332+
poisonRefs, isDeadEnd);
23322333
break;
23332334
}
23342335

lib/Serialization/ModuleFormat.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,8 +58,7 @@ const uint16_t SWIFTMODULE_VERSION_MAJOR = 0;
5858
/// describe what change you made. The content of this comment isn't important;
5959
/// it just ensures a conflict if two people change the module format.
6060
/// Don't worry about adhering to the 80-column limit for this line.
61-
const uint16_t SWIFTMODULE_VERSION_MINOR =
62-
878; // immortal bit in LifetimeDependence
61+
const uint16_t SWIFTMODULE_VERSION_MINOR = 879; // dead_end flag on destroy_value
6362

6463
/// A standard hash seed used for all string hashes in a serialized module.
6564
///

0 commit comments

Comments
 (0)