Skip to content

Commit c3e7626

Browse files
Merge pull request #39291 from nate-chandler/lexical_lifetimes/alloc_stack/lexical_flag
[SIL] Added lexical flag to alloc_stack.
2 parents e68b6a7 + b57b222 commit c3e7626

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
@@ -4142,34 +4142,60 @@ bool SILParser::parseSpecificSILInstruction(SILBuilder &B,
41424142

41434143
break;
41444144
}
4145-
case SILInstructionKind::AllocStackInst:
4146-
case SILInstructionKind::MetatypeInst: {
4147-
4145+
case SILInstructionKind::AllocStackInst: {
41484146
bool hasDynamicLifetime = false;
4149-
if (Opcode == SILInstructionKind::AllocStackInst &&
4150-
parseSILOptional(hasDynamicLifetime, *this, "dynamic_lifetime"))
4147+
bool isLexical = false;
4148+
4149+
while (P.consumeIf(tok::l_square)) {
4150+
Identifier ident;
4151+
SourceLoc identLoc;
4152+
if (parseSILIdentifier(ident, identLoc,
4153+
diag::expected_in_attribute_list)) {
4154+
if (P.consumeIf(tok::r_square)) {
4155+
continue;
4156+
} else {
4157+
return true;
4158+
}
4159+
}
4160+
StringRef attr = ident.str();
4161+
4162+
if (attr == "dynamic_lifetime") {
4163+
hasDynamicLifetime = true;
4164+
} else if (attr == "lexical") {
4165+
isLexical = true;
4166+
} else {
4167+
return true;
4168+
}
4169+
4170+
if (!P.consumeIf(tok::r_square))
4171+
return true;
4172+
}
4173+
4174+
SILType Ty;
4175+
if (parseSILType(Ty))
41514176
return true;
41524177

4178+
SILDebugVariable VarInfo;
4179+
if (parseSILDebugVar(VarInfo) || parseSILDebugLocation(InstLoc, B))
4180+
return true;
4181+
// It doesn't make sense to attach a debug var info if the name is empty
4182+
if (VarInfo.Name.size())
4183+
ResultVal = B.createAllocStack(InstLoc, Ty, VarInfo, hasDynamicLifetime,
4184+
isLexical);
4185+
else
4186+
ResultVal =
4187+
B.createAllocStack(InstLoc, Ty, {}, hasDynamicLifetime, isLexical);
4188+
break;
4189+
}
4190+
case SILInstructionKind::MetatypeInst: {
41534191
SILType Ty;
41544192
if (parseSILType(Ty))
41554193
return true;
41564194

4157-
if (Opcode == SILInstructionKind::AllocStackInst) {
4158-
SILDebugVariable VarInfo;
4159-
if (parseSILDebugVar(VarInfo) || parseSILDebugLocation(InstLoc, B))
4160-
return true;
4161-
// It doesn't make sense to attach a debug var info if the name is empty
4162-
if (VarInfo.Name.size())
4163-
ResultVal =
4164-
B.createAllocStack(InstLoc, Ty, VarInfo, hasDynamicLifetime);
4165-
else
4166-
ResultVal = B.createAllocStack(InstLoc, Ty, {}, hasDynamicLifetime);
4167-
} else {
4168-
assert(Opcode == SILInstructionKind::MetatypeInst);
4169-
if (parseSILDebugLocation(InstLoc, B))
4170-
return true;
4171-
ResultVal = B.createMetatype(InstLoc, Ty);
4172-
}
4195+
assert(Opcode == SILInstructionKind::MetatypeInst);
4196+
if (parseSILDebugLocation(InstLoc, B))
4197+
return true;
4198+
ResultVal = B.createMetatype(InstLoc, Ty);
41734199
break;
41744200
}
41754201
case SILInstructionKind::AllocRefInst:

lib/Serialization/DeserializeSIL.cpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1223,12 +1223,15 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn,
12231223
Loc, cast<SILBoxType>(MF->getType(TyID)->getCanonicalType()), None,
12241224
/*bool hasDynamicLifetime*/ Attr != 0);
12251225
break;
1226-
case SILInstructionKind::AllocStackInst:
1226+
case SILInstructionKind::AllocStackInst: {
12271227
assert(RecordKind == SIL_ONE_TYPE && "Layout should be OneType.");
1228+
bool hasDynamicLifetime = Attr & 0x1;
1229+
bool isLexical = (Attr >> 1) & 0x1;
12281230
ResultInst = Builder.createAllocStack(
12291231
Loc, getSILType(MF->getType(TyID), (SILValueCategory)TyCategory, Fn),
1230-
None, /*bool hasDynamicLifetime*/ Attr != 0);
1232+
None, hasDynamicLifetime, isLexical);
12311233
break;
1234+
}
12321235
case SILInstructionKind::MetatypeInst:
12331236
assert(RecordKind == SIL_ONE_TYPE && "Layout should be OneType.");
12341237
ResultInst = Builder.createMetatype(

lib/Serialization/SerializeSIL.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1014,8 +1014,9 @@ void SILSerializer::writeSILInstruction(const SILInstruction &SI) {
10141014
}
10151015
case SILInstructionKind::AllocStackInst: {
10161016
const AllocStackInst *ASI = cast<AllocStackInst>(&SI);
1017-
writeOneTypeLayout(ASI->getKind(), ASI->hasDynamicLifetime() ? 1 : 0,
1018-
ASI->getElementType());
1017+
unsigned attr =
1018+
unsigned(ASI->hasDynamicLifetime()) + unsigned(ASI->isLexical() << 1);
1019+
writeOneTypeLayout(ASI->getKind(), attr, ASI->getElementType());
10191020
break;
10201021
}
10211022
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) () -> () {

test/SIL/Serialization/borrow.sil

Lines changed: 34 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,40 @@ sil_stage canonical
88

99
import Builtin
1010

11+
// CHECK-LABEL: sil [serialized] [ossa] @begin_borrow_test
12+
// CHECK: begin_borrow [defined] {{%[^,]+}}
13+
// CHECK: begin_borrow {{%[^,]+}}
14+
// CHECK: } // end sil function 'begin_borrow_test'
15+
sil [serialized] [ossa] @begin_borrow_test : $@convention(thin) () -> () {
16+
%instance = alloc_ref $C
17+
%guaranteed_c = begin_borrow [defined] %instance : $C
18+
end_borrow %guaranteed_c : $C
19+
%guaranteed_c2 = begin_borrow %instance : $C
20+
end_borrow %guaranteed_c2 : $C
21+
destroy_value %instance : $C
22+
%res = tuple ()
23+
return %res : $()
24+
}
25+
26+
// CHECK-LABEL: sil [serialized] [ossa] @alloc_stack_test
27+
// CHECK: alloc_stack $Builtin.NativeObject
28+
// CHECK: alloc_stack [dynamic_lifetime]
29+
// CHECK: alloc_stack [lexical]
30+
// CHECK: alloc_stack [dynamic_lifetime] [lexical]
31+
// CHECK: } // end sil function 'alloc_stack_test'
32+
sil [serialized] [ossa] @alloc_stack_test : $@convention(thin) () -> () {
33+
%instance = alloc_stack $Builtin.NativeObject
34+
dealloc_stack %instance : $*Builtin.NativeObject
35+
%instance2 = alloc_stack [dynamic_lifetime] $Builtin.NativeObject
36+
dealloc_stack %instance2 : $*Builtin.NativeObject
37+
%instance3 = alloc_stack [lexical] $Builtin.NativeObject
38+
dealloc_stack %instance3 : $*Builtin.NativeObject
39+
%instance4 = alloc_stack [lexical] [dynamic_lifetime] $Builtin.NativeObject
40+
dealloc_stack %instance4 : $*Builtin.NativeObject
41+
%res = tuple ()
42+
return %res : $()
43+
}
44+
1145
// We do not verify here, but just make sure that all of the combinations parse and print correctly.
1246
// CHECK-LABEL: sil [serialized] [ossa] @borrow_test : $@convention(thin) (@in Builtin.NativeObject, @guaranteed Builtin.NativeObject) -> () {
1347
// CHECK: bb0([[ARG1:%[0-9]+]] : $*Builtin.NativeObject, [[ARG2:%[0-9]+]] : @guaranteed $Builtin.NativeObject):
@@ -31,15 +65,3 @@ bb0(%0 : $*Builtin.NativeObject, %1 : @guaranteed $Builtin.NativeObject):
3165
}
3266

3367
class C {}
34-
35-
// CHECK-LABEL: sil [ossa] @defined_borrow_test
36-
// CHECK: begin_borrow [defined] {{%[^,]+}}
37-
// CHECK-LABEL: } // end sil function 'defined_borrow_test'
38-
sil [ossa] @defined_borrow_test : $@convention(thin) () -> () {
39-
%instance = alloc_ref $C
40-
%guaranteed_c = begin_borrow [defined] %instance : $C
41-
end_borrow %guaranteed_c : $C
42-
destroy_value %instance : $C
43-
%res = tuple ()
44-
return %res : $()
45-
}

test/SIL/cloning.sil

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,3 +45,28 @@ sil [ossa] @caller_begin_borrow_defined : $@convention(thin) () -> () {
4545
%res = apply %callee_begin_borrow_defined() : $@convention(thin) () -> ()
4646
return %res : $()
4747
}
48+
49+
sil [ossa] @callee_alloc_stack : $@convention(thin) () -> () {
50+
%instance = alloc_stack $Builtin.NativeObject
51+
dealloc_stack %instance : $*Builtin.NativeObject
52+
%instance2 = alloc_stack [dynamic_lifetime] $Builtin.NativeObject
53+
dealloc_stack %instance2 : $*Builtin.NativeObject
54+
%instance3 = alloc_stack [lexical] $Builtin.NativeObject
55+
dealloc_stack %instance3 : $*Builtin.NativeObject
56+
%instance4 = alloc_stack [dynamic_lifetime] [lexical] $Builtin.NativeObject
57+
dealloc_stack %instance4 : $*Builtin.NativeObject
58+
%res = tuple ()
59+
return %res : $()
60+
}
61+
62+
// CHECK-LABEL: sil [ossa] @caller_alloc_stack_lexical
63+
// CHECK: alloc_stack
64+
// CHECK: alloc_stack [dynamic_lifetime]
65+
// CHECK: alloc_stack [lexical]
66+
// CHECK: alloc_stack [dynamic_lifetime] [lexical]
67+
// CHECK-LABEL: } // end sil function 'caller_alloc_stack_lexical'
68+
sil [ossa] @caller_alloc_stack_lexical : $@convention(thin) () -> () {
69+
%callee_alloc_stack = function_ref @callee_alloc_stack : $@convention(thin) () -> ()
70+
%res = apply %callee_alloc_stack() : $@convention(thin) () -> ()
71+
return %res : $()
72+
}

0 commit comments

Comments
 (0)