Skip to content

Commit b57b222

Browse files
committed
[SIL] Added lexical flag to alloc_stack.
The new flag will be used to track whether a borrow scope corresponds to a source-level lexical scope. Here, the flag is just documented, added to the instruction, represented in textual and serialized SIL, and cloned.
1 parent 6738c3e commit b57b222

File tree

12 files changed

+166
-60
lines changed

12 files changed

+166
-60
lines changed

docs/SIL.rst

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3079,7 +3079,7 @@ alloc_stack
30793079
```````````
30803080
::
30813081

3082-
sil-instruction ::= 'alloc_stack' '[dynamic_lifetime]'? sil-type (',' debug-var-attr)*
3082+
sil-instruction ::= 'alloc_stack' '[dynamic_lifetime]'? '[lexical]'? sil-type (',' debug-var-attr)*
30833083

30843084
%1 = alloc_stack $T
30853085
// %1 has type $*T
@@ -3102,6 +3102,9 @@ The ``dynamic_lifetime`` attribute specifies that the initialization and
31023102
destruction of the stored value cannot be verified at compile time.
31033103
This is the case, e.g. for conditionally initialized objects.
31043104

3105+
The optional ``lexical`` attribute specifies that the operand corresponds to a
3106+
local variable in the Swift source.
3107+
31053108
The memory is not retainable. To allocate a retainable box for a value
31063109
type, use ``alloc_box``.
31073110

include/swift/SIL/SILBuilder.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -365,13 +365,14 @@ class SILBuilder {
365365

366366
AllocStackInst *createAllocStack(SILLocation Loc, SILType elementType,
367367
Optional<SILDebugVariable> Var = None,
368-
bool hasDynamicLifetime = false) {
368+
bool hasDynamicLifetime = false,
369+
bool isLexical = false) {
369370
Loc.markAsPrologue();
370371
assert((!dyn_cast_or_null<VarDecl>(Loc.getAsASTNode<Decl>()) || Var) &&
371372
"location is a VarDecl, but SILDebugVariable is empty");
372373
return insert(AllocStackInst::create(getSILDebugLocation(Loc), elementType,
373-
getFunction(),
374-
Var, hasDynamicLifetime));
374+
getFunction(), Var, hasDynamicLifetime,
375+
isLexical));
375376
}
376377

377378
AllocRefInst *createAllocRef(SILLocation Loc, SILType ObjectType,

include/swift/SIL/SILCloner.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -759,9 +759,9 @@ SILCloner<ImplClass>::visitAllocStackInst(AllocStackInst *Inst) {
759759
Loc = MandatoryInlinedLocation::getAutoGeneratedLocation();
760760
VarInfo = None;
761761
}
762-
auto *NewInst =
763-
getBuilder().createAllocStack(Loc, getOpType(Inst->getElementType()),
764-
VarInfo, Inst->hasDynamicLifetime());
762+
auto *NewInst = getBuilder().createAllocStack(
763+
Loc, getOpType(Inst->getElementType()), VarInfo,
764+
Inst->hasDynamicLifetime(), Inst->isLexical());
765765
remapDebugVarInfo(DebugVarCarryingInst(NewInst));
766766
recordClonedInstruction(Inst, NewInst);
767767
}

include/swift/SIL/SILInstruction.h

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1902,16 +1902,16 @@ class AllocStackInst final
19021902
friend SILBuilder;
19031903

19041904
bool dynamicLifetime = false;
1905+
bool lexical = false;
19051906

19061907
AllocStackInst(SILDebugLocation Loc, SILType elementType,
1907-
ArrayRef<SILValue> TypeDependentOperands,
1908-
SILFunction &F,
1909-
Optional<SILDebugVariable> Var, bool hasDynamicLifetime);
1908+
ArrayRef<SILValue> TypeDependentOperands, SILFunction &F,
1909+
Optional<SILDebugVariable> Var, bool hasDynamicLifetime,
1910+
bool isLexical);
19101911

19111912
static AllocStackInst *create(SILDebugLocation Loc, SILType elementType,
1912-
SILFunction &F,
1913-
Optional<SILDebugVariable> Var,
1914-
bool hasDynamicLifetime);
1913+
SILFunction &F, Optional<SILDebugVariable> Var,
1914+
bool hasDynamicLifetime, bool isLexical);
19151915

19161916
SIL_DEBUG_VAR_SUPPLEMENT_TRAILING_OBJS_IMPL()
19171917

@@ -1942,6 +1942,9 @@ class AllocStackInst final
19421942
/// is conditionally initialized.
19431943
bool hasDynamicLifetime() const { return dynamicLifetime; }
19441944

1945+
/// Whether the alloc_stack instruction corresponds to a source-level VarDecl.
1946+
bool isLexical() const { return lexical; }
1947+
19451948
/// Return the debug variable information attached to this instruction.
19461949
Optional<SILDebugVariable> getVarInfo() const {
19471950
Optional<SILType> AuxVarType;

lib/SIL/IR/SILInstructions.cpp

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -191,13 +191,13 @@ SILDebugVariable::createFromAllocation(const AllocationInst *AI) {
191191
AllocStackInst::AllocStackInst(SILDebugLocation Loc, SILType elementType,
192192
ArrayRef<SILValue> TypeDependentOperands,
193193
SILFunction &F, Optional<SILDebugVariable> Var,
194-
bool hasDynamicLifetime)
194+
bool hasDynamicLifetime, bool isLexical)
195195
: InstructionBase(Loc, elementType.getAddressType()),
196196
SILDebugVariableSupplement(Var ? Var->DIExpr.getNumElements() : 0,
197197
Var ? Var->Type.hasValue() : false,
198198
Var ? Var->Loc.hasValue() : false,
199199
Var ? Var->Scope != nullptr : false),
200-
dynamicLifetime(hasDynamicLifetime) {
200+
dynamicLifetime(hasDynamicLifetime), lexical(isLexical) {
201201
SILNode::Bits.AllocStackInst.NumOperands =
202202
TypeDependentOperands.size();
203203
assert(SILNode::Bits.AllocStackInst.NumOperands ==
@@ -218,19 +218,18 @@ AllocStackInst::AllocStackInst(SILDebugLocation Loc, SILType elementType,
218218
TypeDependentOperands);
219219
}
220220

221-
AllocStackInst *
222-
AllocStackInst::create(SILDebugLocation Loc,
223-
SILType elementType, SILFunction &F,
224-
Optional<SILDebugVariable> Var,
225-
bool hasDynamicLifetime) {
221+
AllocStackInst *AllocStackInst::create(SILDebugLocation Loc,
222+
SILType elementType, SILFunction &F,
223+
Optional<SILDebugVariable> Var,
224+
bool hasDynamicLifetime,
225+
bool isLexical) {
226226
SmallVector<SILValue, 8> TypeDependentOperands;
227227
collectTypeDependentOperands(TypeDependentOperands, F,
228228
elementType.getASTType());
229229
void *Buffer = allocateDebugVarCarryingInst<AllocStackInst>(
230230
F.getModule(), Var, TypeDependentOperands);
231-
return ::new (Buffer)
232-
AllocStackInst(Loc, elementType, TypeDependentOperands, F, Var,
233-
hasDynamicLifetime);
231+
return ::new (Buffer) AllocStackInst(Loc, elementType, TypeDependentOperands,
232+
F, Var, hasDynamicLifetime, isLexical);
234233
}
235234

236235
VarDecl *AllocationInst::getDecl() const {

lib/SIL/IR/SILPrinter.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1260,6 +1260,8 @@ class SILPrinter : public SILInstructionVisitor<SILPrinter> {
12601260
void visitAllocStackInst(AllocStackInst *AVI) {
12611261
if (AVI->hasDynamicLifetime())
12621262
*this << "[dynamic_lifetime] ";
1263+
if (AVI->isLexical())
1264+
*this << "[lexical] ";
12631265
*this << AVI->getElementType();
12641266
printDebugVar(AVI->getVarInfo(),
12651267
&AVI->getModule().getASTContext().SourceMgr);

lib/SIL/Parser/ParseSIL.cpp

Lines changed: 47 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -4108,34 +4108,60 @@ bool SILParser::parseSpecificSILInstruction(SILBuilder &B,
41084108

41094109
break;
41104110
}
4111-
case SILInstructionKind::AllocStackInst:
4112-
case SILInstructionKind::MetatypeInst: {
4113-
4111+
case SILInstructionKind::AllocStackInst: {
41144112
bool hasDynamicLifetime = false;
4115-
if (Opcode == SILInstructionKind::AllocStackInst &&
4116-
parseSILOptional(hasDynamicLifetime, *this, "dynamic_lifetime"))
4113+
bool isLexical = false;
4114+
4115+
while (P.consumeIf(tok::l_square)) {
4116+
Identifier ident;
4117+
SourceLoc identLoc;
4118+
if (parseSILIdentifier(ident, identLoc,
4119+
diag::expected_in_attribute_list)) {
4120+
if (P.consumeIf(tok::r_square)) {
4121+
continue;
4122+
} else {
4123+
return true;
4124+
}
4125+
}
4126+
StringRef attr = ident.str();
4127+
4128+
if (attr == "dynamic_lifetime") {
4129+
hasDynamicLifetime = true;
4130+
} else if (attr == "lexical") {
4131+
isLexical = true;
4132+
} else {
4133+
return true;
4134+
}
4135+
4136+
if (!P.consumeIf(tok::r_square))
4137+
return true;
4138+
}
4139+
4140+
SILType Ty;
4141+
if (parseSILType(Ty))
41174142
return true;
41184143

4144+
SILDebugVariable VarInfo;
4145+
if (parseSILDebugVar(VarInfo) || parseSILDebugLocation(InstLoc, B))
4146+
return true;
4147+
// It doesn't make sense to attach a debug var info if the name is empty
4148+
if (VarInfo.Name.size())
4149+
ResultVal = B.createAllocStack(InstLoc, Ty, VarInfo, hasDynamicLifetime,
4150+
isLexical);
4151+
else
4152+
ResultVal =
4153+
B.createAllocStack(InstLoc, Ty, {}, hasDynamicLifetime, isLexical);
4154+
break;
4155+
}
4156+
case SILInstructionKind::MetatypeInst: {
41194157
SILType Ty;
41204158
if (parseSILType(Ty))
41214159
return true;
41224160

4123-
if (Opcode == SILInstructionKind::AllocStackInst) {
4124-
SILDebugVariable VarInfo;
4125-
if (parseSILDebugVar(VarInfo) || parseSILDebugLocation(InstLoc, B))
4126-
return true;
4127-
// It doesn't make sense to attach a debug var info if the name is empty
4128-
if (VarInfo.Name.size())
4129-
ResultVal =
4130-
B.createAllocStack(InstLoc, Ty, VarInfo, hasDynamicLifetime);
4131-
else
4132-
ResultVal = B.createAllocStack(InstLoc, Ty, {}, hasDynamicLifetime);
4133-
} else {
4134-
assert(Opcode == SILInstructionKind::MetatypeInst);
4135-
if (parseSILDebugLocation(InstLoc, B))
4136-
return true;
4137-
ResultVal = B.createMetatype(InstLoc, Ty);
4138-
}
4161+
assert(Opcode == SILInstructionKind::MetatypeInst);
4162+
if (parseSILDebugLocation(InstLoc, B))
4163+
return true;
4164+
ResultVal = B.createMetatype(InstLoc, Ty);
41394165
break;
41404166
}
41414167
case SILInstructionKind::AllocRefInst:

lib/Serialization/DeserializeSIL.cpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1217,12 +1217,15 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn,
12171217
Loc, cast<SILBoxType>(MF->getType(TyID)->getCanonicalType()), None,
12181218
/*bool hasDynamicLifetime*/ Attr != 0);
12191219
break;
1220-
case SILInstructionKind::AllocStackInst:
1220+
case SILInstructionKind::AllocStackInst: {
12211221
assert(RecordKind == SIL_ONE_TYPE && "Layout should be OneType.");
1222+
bool hasDynamicLifetime = Attr & 0x1;
1223+
bool isLexical = (Attr >> 1) & 0x1;
12221224
ResultInst = Builder.createAllocStack(
12231225
Loc, getSILType(MF->getType(TyID), (SILValueCategory)TyCategory, Fn),
1224-
None, /*bool hasDynamicLifetime*/ Attr != 0);
1226+
None, hasDynamicLifetime, isLexical);
12251227
break;
1228+
}
12261229
case SILInstructionKind::MetatypeInst:
12271230
assert(RecordKind == SIL_ONE_TYPE && "Layout should be OneType.");
12281231
ResultInst = Builder.createMetatype(

lib/Serialization/SerializeSIL.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -992,8 +992,9 @@ void SILSerializer::writeSILInstruction(const SILInstruction &SI) {
992992
}
993993
case SILInstructionKind::AllocStackInst: {
994994
const AllocStackInst *ASI = cast<AllocStackInst>(&SI);
995-
writeOneTypeLayout(ASI->getKind(), ASI->hasDynamicLifetime() ? 1 : 0,
996-
ASI->getElementType());
995+
unsigned attr =
996+
unsigned(ASI->hasDynamicLifetime()) + unsigned(ASI->isLexical() << 1);
997+
writeOneTypeLayout(ASI->getKind(), attr, ASI->getElementType());
997998
break;
998999
}
9991000
case SILInstructionKind::ProjectValueBufferInst: {

test/SIL/Parser/basic.sil

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1230,6 +1230,27 @@ bb0:
12301230
return %2 : $()
12311231
}
12321232

1233+
// CHECK-LABEL: sil @test_alloc_stack_flags
1234+
sil @test_alloc_stack_flags : $() -> () {
1235+
// CHECK: alloc_stack $Builtin.NativeObjec
1236+
%instance = alloc_stack $Builtin.NativeObject
1237+
dealloc_stack %instance : $*Builtin.NativeObject
1238+
// CHECK: alloc_stack [dynamic_lifetime]
1239+
%instance2 = alloc_stack [dynamic_lifetime] $Builtin.NativeObject
1240+
dealloc_stack %instance2 : $*Builtin.NativeObject
1241+
// CHECK: alloc_stack [lexical]
1242+
%instance3 = alloc_stack [lexical] $Builtin.NativeObject
1243+
dealloc_stack %instance3 : $*Builtin.NativeObject
1244+
// CHECK: alloc_stack [dynamic_lifetime] [lexical]
1245+
%instance4 = alloc_stack [dynamic_lifetime] [lexical] $Builtin.NativeObject
1246+
dealloc_stack %instance4 : $*Builtin.NativeObject
1247+
// CHECK: alloc_stack [dynamic_lifetime] [lexical]
1248+
%instance5 = alloc_stack [lexical] [dynamic_lifetime] $Builtin.NativeObject
1249+
dealloc_stack %instance5 : $*Builtin.NativeObject
1250+
%res = tuple ()
1251+
return %res : $()
1252+
}
1253+
12331254
sil_global @staticProp: $Int
12341255

12351256
// CHECK-LABEL: sil private @globalinit_func0 : $@convention(thin) () -> () {

0 commit comments

Comments
 (0)