Skip to content

Commit ea2c6a7

Browse files
committed
Explicitly lower value pack and parameter expansion types in SIL
Introduce a new SILPackType which captures whether the element types are stored inline in the pack array. Add ParameterConventions and SILArgumentConventions for passing packs. Make a bunch of changes, some of which might be correct.
1 parent 547d85e commit ea2c6a7

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

+950
-83
lines changed

docs/ABI/Mangling.rst

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -665,6 +665,7 @@ Types
665665
666666
type ::= pattern-type count-type 'Qp' // pack expansion type
667667
type ::= pack-element-list 'QP' // pack type
668+
type ::= pack-element-list 'QS' DIRECTNESS // SIL pack type
668669

669670
pack-element-list ::= type '_' type*
670671
pack-element-list ::= empty-list
@@ -746,6 +747,9 @@ mangled in to disambiguate.
746747
PARAM-CONVENTION ::= 'y' // direct unowned
747748
PARAM-CONVENTION ::= 'g' // direct guaranteed
748749
PARAM-CONVENTION ::= 'e' // direct deallocating
750+
PARAM-CONVENTION ::= 'v' // pack owned
751+
PARAM-CONVENTION ::= 'p' // pack guaranteed
752+
PARAM-CONVENTION ::= 'm' // pack inout
749753

750754
PARAM-DIFFERENTIABILITY ::= 'w' // @noDerivative
751755

@@ -757,6 +761,9 @@ mangled in to disambiguate.
757761

758762
RESULT-DIFFERENTIABILITY ::= 'w' // @noDerivative
759763

764+
DIRECTNESS ::= 'i' // indirect
765+
DIRECTNESS ::= 'd' // direct
766+
760767
For the most part, manglings follow the structure of formal language
761768
types. However, in some cases it is more useful to encode the exact
762769
implementation details of a function type.

include/swift/AST/Attr.def.gyb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,11 +66,15 @@ TYPE_ATTR(dynamic_self)
6666
#include "swift/AST/ReferenceStorage.def"
6767
TYPE_ATTR(error)
6868
TYPE_ATTR(out)
69+
TYPE_ATTR(direct)
6970
TYPE_ATTR(in)
7071
TYPE_ATTR(inout)
7172
TYPE_ATTR(inout_aliasable)
7273
TYPE_ATTR(in_guaranteed)
7374
TYPE_ATTR(in_constant)
75+
TYPE_ATTR(pack_owned)
76+
TYPE_ATTR(pack_guaranteed)
77+
TYPE_ATTR(pack_inout)
7478
TYPE_ATTR(owned)
7579
TYPE_ATTR(unowned_inner_pointer)
7680
TYPE_ATTR(guaranteed)

include/swift/AST/TypeDifferenceVisitor.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,14 @@ class CanTypeDifferenceVisitor : public CanTypePairVisitor<Impl, bool> {
136136
type2->getElementTypes());
137137
}
138138

139+
bool visitSILPackType(CanSILPackType type1, CanSILPackType type2) {
140+
if (type1->isElementAddress() != type2->isElementAddress())
141+
return asImpl().visitDifferentTypeStructure(type1, type2);
142+
return visitComponentArray(type1, type2,
143+
type1->getElementTypes(),
144+
type2->getElementTypes());
145+
}
146+
139147
bool visitPackExpansionType(CanPackExpansionType type1,
140148
CanPackExpansionType type2) {
141149
return asImpl().visit(type1.getPatternType(), type2.getPatternType());

include/swift/AST/TypeMatcher.h

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,29 @@ class TypeMatcher {
143143
return mismatch(firstTuple.getPointer(), secondType, sugaredFirstType);
144144
}
145145

146+
bool visitSILPackType(CanSILPackType firstPack, Type secondType,
147+
Type sugaredFirstType) {
148+
if (auto secondPack = secondType->getAs<SILPackType>()) {
149+
if (firstPack->getNumElements() != secondPack->getNumElements())
150+
return mismatch(firstPack.getPointer(), secondPack,
151+
sugaredFirstType);
152+
153+
for (unsigned i = 0, n = firstPack->getNumElements(); i != n; ++i) {
154+
// Recurse on the pack elements. There's no need to preserve
155+
// sugar for SIL types.
156+
if (!this->visit(firstPack->getElementType(i),
157+
secondPack->getElementType(i),
158+
firstPack->getElementType(i)))
159+
return false;
160+
}
161+
162+
return true;
163+
}
164+
165+
// Pack/non-pack mismatch.
166+
return mismatch(firstPack.getPointer(), secondType, sugaredFirstType);
167+
}
168+
146169
bool visitPackType(CanPackType firstTuple, Type secondType,
147170
Type sugaredFirstType) {
148171
if (auto secondTuple = secondType->getAs<PackType>()) {

include/swift/AST/TypeNodes.def

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,17 @@
5353
/// This is only expanded if SINGLETON_TYPE is defined, and in this
5454
/// case no other macros are expanded.
5555

56+
#ifndef ALWAYS_CANONICAL_ARTIFICIAL_TYPE
57+
#ifdef ALWAYS_CANONICAL_TYPE
58+
#ifdef ARTIFICIAL_TYPE
59+
#error must define ALWAYS_CANONICAL_ARTIFICIAL_TYPE if also defining both ALWAYS_CANONICAL_TYPE and ARTIFICIAL_TYPE
60+
#endif
61+
#define ALWAYS_CANONICAL_ARTIFICIAL_TYPE(id, parent) ALWAYS_CANONICAL_TYPE(id, parent)
62+
#else
63+
#define ALWAYS_CANONICAL_ARTIFICIAL_TYPE(id, parent) ARTIFICIAL_TYPE(id, parent)
64+
#endif
65+
#endif
66+
5667
#ifndef ALWAYS_CANONICAL_TYPE
5768
#define ALWAYS_CANONICAL_TYPE(id, parent) TYPE(id, parent)
5869
#endif
@@ -165,6 +176,7 @@ ARTIFICIAL_TYPE(SILFunction, Type)
165176
ARTIFICIAL_TYPE(SILBlockStorage, Type)
166177
ARTIFICIAL_TYPE(SILBox, Type)
167178
ARTIFICIAL_TYPE(SILMoveOnlyWrapped, Type)
179+
ALWAYS_CANONICAL_ARTIFICIAL_TYPE(SILPack, Type)
168180
ARTIFICIAL_TYPE(SILToken, Type)
169181
TYPE(ProtocolComposition, Type)
170182
TYPE(ParameterizedProtocol, Type)
@@ -213,5 +225,6 @@ SINGLETON_TYPE(SILToken, SILToken)
213225
#undef SUGARED_TYPE
214226
#undef BUILTIN_TYPE
215227
#undef ALWAYS_CANONICAL_TYPE
228+
#undef ALWAYS_CANONICAL_ARTIFICIAL_TYPE
216229
#undef TYPE
217230
#undef LAST_TYPE

include/swift/AST/Types.h

Lines changed: 131 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -407,10 +407,10 @@ class alignas(1 << TypeAlignInBits) TypeBase
407407
ID : 32
408408
);
409409

410-
SWIFT_INLINE_BITFIELD(SILFunctionType, TypeBase, NumSILExtInfoBits+1+3+1+2+1+1,
410+
SWIFT_INLINE_BITFIELD(SILFunctionType, TypeBase, NumSILExtInfoBits+1+4+1+2+1+1,
411411
ExtInfoBits : NumSILExtInfoBits,
412412
HasClangTypeInfo : 1,
413-
CalleeConvention : 3,
413+
CalleeConvention : 4,
414414
HasErrorResult : 1,
415415
CoroutineKind : 2,
416416
HasInvocationSubs : 1,
@@ -451,7 +451,17 @@ class alignas(1 << TypeAlignInBits) TypeBase
451451
SWIFT_INLINE_BITFIELD_FULL(PackType, TypeBase, 32,
452452
: NumPadBits,
453453

454-
/// The number of elements of the tuple.
454+
/// The number of elements of the pack.
455+
Count : 32
456+
);
457+
458+
SWIFT_INLINE_BITFIELD_FULL(SILPackType, TypeBase, 1+32,
459+
/// Whether elements of the pack are addresses.
460+
ElementIsAddress : 1,
461+
462+
: NumPadBits,
463+
464+
/// The number of elements of the pack
455465
Count : 32
456466
);
457467

@@ -3777,9 +3787,24 @@ enum class ParameterConvention : uint8_t {
37773787
/// This argument is passed directly. Its type is non-trivial, and the caller
37783788
/// guarantees its validity for the entirety of the call.
37793789
Direct_Guaranteed,
3790+
3791+
/// This argument is a value pack of mutable references to storage,
3792+
/// which the function is being given exclusive access to. The elements
3793+
/// must be passed indirectly.
3794+
Pack_Inout,
3795+
3796+
/// This argument is a value pack, and ownership of the elements is being
3797+
/// transferred into this function. Whether the elements are passed
3798+
/// indirectly is recorded in the pack type.
3799+
Pack_Owned,
3800+
3801+
/// This argument is a value pack, and ownership of the elements is not
3802+
/// being transferred into this function. Whether the elements are passed
3803+
/// indirectly is recorded in the pack type.
3804+
Pack_Guaranteed,
37803805
};
37813806
// Check that the enum values fit inside Bits.SILFunctionType.
3782-
static_assert(unsigned(ParameterConvention::Direct_Guaranteed) < (1<<3),
3807+
static_assert(unsigned(ParameterConvention::Pack_Guaranteed) < (1<<4),
37833808
"fits in Bits.SILFunctionType");
37843809

37853810
// Does this parameter convention require indirect storage? This reflects a
@@ -3796,6 +3821,9 @@ inline bool isIndirectFormalParameter(ParameterConvention conv) {
37963821
case ParameterConvention::Direct_Unowned:
37973822
case ParameterConvention::Direct_Guaranteed:
37983823
case ParameterConvention::Direct_Owned:
3824+
case ParameterConvention::Pack_Inout:
3825+
case ParameterConvention::Pack_Owned:
3826+
case ParameterConvention::Pack_Guaranteed:
37993827
return false;
38003828
}
38013829
llvm_unreachable("covered switch isn't covered?!");
@@ -3804,13 +3832,16 @@ inline bool isConsumedParameter(ParameterConvention conv) {
38043832
switch (conv) {
38053833
case ParameterConvention::Indirect_In:
38063834
case ParameterConvention::Direct_Owned:
3835+
case ParameterConvention::Pack_Owned:
38073836
return true;
38083837

38093838
case ParameterConvention::Indirect_Inout:
38103839
case ParameterConvention::Indirect_InoutAliasable:
38113840
case ParameterConvention::Direct_Unowned:
38123841
case ParameterConvention::Direct_Guaranteed:
38133842
case ParameterConvention::Indirect_In_Guaranteed:
3843+
case ParameterConvention::Pack_Inout:
3844+
case ParameterConvention::Pack_Guaranteed:
38143845
return false;
38153846
}
38163847
llvm_unreachable("bad convention kind");
@@ -3823,13 +3854,16 @@ inline bool isGuaranteedParameter(ParameterConvention conv) {
38233854
switch (conv) {
38243855
case ParameterConvention::Direct_Guaranteed:
38253856
case ParameterConvention::Indirect_In_Guaranteed:
3857+
case ParameterConvention::Pack_Guaranteed:
38263858
return true;
38273859

38283860
case ParameterConvention::Indirect_Inout:
38293861
case ParameterConvention::Indirect_InoutAliasable:
38303862
case ParameterConvention::Indirect_In:
38313863
case ParameterConvention::Direct_Unowned:
38323864
case ParameterConvention::Direct_Owned:
3865+
case ParameterConvention::Pack_Inout:
3866+
case ParameterConvention::Pack_Owned:
38333867
return false;
38343868
}
38353869
llvm_unreachable("bad convention kind");
@@ -5138,6 +5172,97 @@ class SILTokenType final : public TypeBase {
51385172
};
51395173
DEFINE_EMPTY_CAN_TYPE_WRAPPER(SILTokenType, Type)
51405174

5175+
/// A lowered pack type which structurally carries lowered information
5176+
/// about the pack elements.
5177+
///
5178+
/// A value pack is basically treated as a unique-ownership, unmovable
5179+
/// reference-semantics aggregate in SIL: ownership of the pack as a whole
5180+
/// is communicated with normal borrows of the pack, and packs can only
5181+
/// be created locally and forwarded as arguments rather than being moved
5182+
/// in any more complex way.
5183+
class SILPackType final : public TypeBase, public llvm::FoldingSetNode,
5184+
private llvm::TrailingObjects<SILPackType, CanType> {
5185+
public:
5186+
/// Type structure not reflected in the pack element type list.
5187+
///
5188+
/// In the design of this, we considered storing ownership here,
5189+
/// but ended up just with the one bit.
5190+
struct ExtInfo {
5191+
bool ElementIsAddress;
5192+
5193+
ExtInfo(bool elementIsAddress) : ElementIsAddress(elementIsAddress) {}
5194+
};
5195+
5196+
private:
5197+
friend TrailingObjects;
5198+
friend class ASTContext;
5199+
SILPackType(const ASTContext &ctx, RecursiveTypeProperties properties,
5200+
ExtInfo info, ArrayRef<CanType> elements)
5201+
: TypeBase(TypeKind::SILPack, &ctx, properties) {
5202+
Bits.SILPackType.Count = elements.size();
5203+
Bits.SILPackType.ElementIsAddress = info.ElementIsAddress;
5204+
memcpy(getTrailingObjects<CanType>(), elements.data(),
5205+
elements.size() * sizeof(CanType));
5206+
}
5207+
5208+
public:
5209+
static CanTypeWrapper<SILPackType> get(const ASTContext &ctx,
5210+
ExtInfo info,
5211+
ArrayRef<CanType> elements);
5212+
5213+
ExtInfo getExtInfo() const {
5214+
return { isElementAddress() };
5215+
}
5216+
5217+
bool isElementAddress() const {
5218+
return Bits.SILPackType.ElementIsAddress;
5219+
}
5220+
5221+
/// Retrieves the number of elements in this pack.
5222+
unsigned getNumElements() const { return Bits.SILPackType.Count; }
5223+
5224+
/// Retrieves the type of the elements in the pack.
5225+
ArrayRef<CanType> getElementTypes() const {
5226+
return {getTrailingObjects<CanType>(), getNumElements()};
5227+
}
5228+
5229+
/// Returns the type of the element at the given \p index.
5230+
/// This is a lowered SIL type.
5231+
CanType getElementType(unsigned index) const {
5232+
return getTrailingObjects<CanType>()[index];
5233+
}
5234+
5235+
SILType getSILElementType(unsigned index) const; // in SILType.h
5236+
5237+
/// Return the reduced shape of this pack. For consistency with
5238+
/// general shape-handling routines, we produce an AST pack type
5239+
/// as the shape, not a SIL pack type.
5240+
CanTypeWrapper<PackType> getReducedShape() const;
5241+
5242+
bool containsPackExpansionType() const;
5243+
5244+
void Profile(llvm::FoldingSetNodeID &ID) const {
5245+
Profile(ID, getExtInfo(), getElementTypes());
5246+
}
5247+
static void Profile(llvm::FoldingSetNodeID &ID,
5248+
ExtInfo info,
5249+
ArrayRef<CanType> elements);
5250+
5251+
// Implement isa/cast/dyncast/etc.
5252+
static bool classof(const TypeBase *T) {
5253+
return T->getKind() == TypeKind::SILPack;
5254+
}
5255+
};
5256+
BEGIN_CAN_TYPE_WRAPPER(SILPackType, Type)
5257+
CanType getElementType(unsigned elementNo) const {
5258+
return getPointer()->getElementType(elementNo);
5259+
}
5260+
5261+
ArrayRef<CanType> getElementTypes() const {
5262+
return getPointer()->getElementTypes();
5263+
}
5264+
END_CAN_TYPE_WRAPPER(SILPackType, Type)
5265+
51415266
/// A type with a special syntax that is always sugar for a library type. The
51425267
/// library type may have multiple base types. For unary syntax sugar, see
51435268
/// UnarySyntaxSugarType.
@@ -6654,6 +6779,8 @@ class PackExpansionType : public TypeBase, public llvm::FoldingSetNode {
66546779
const ASTContext *ctx);
66556780
};
66566781
BEGIN_CAN_TYPE_WRAPPER(PackExpansionType, Type)
6782+
static CanPackExpansionType get(CanType pattern, CanType countType);
6783+
66576784
CanType getPatternType() const {
66586785
return CanType(getPointer()->getPatternType());
66596786
}

include/swift/SIL/ApplySite.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -379,6 +379,7 @@ class ApplySite {
379379
switch (conv) {
380380
case SILArgumentConvention::Indirect_Inout:
381381
case SILArgumentConvention::Indirect_InoutAliasable:
382+
case SILArgumentConvention::Pack_Inout:
382383
return conv;
383384
case SILArgumentConvention::Direct_Owned:
384385
case SILArgumentConvention::Direct_Unowned:
@@ -389,7 +390,12 @@ class ApplySite {
389390
case SILArgumentConvention::Indirect_In_Guaranteed:
390391
return pai->isOnStack() ? SILArgumentConvention::Indirect_In_Guaranteed
391392
: SILArgumentConvention::Indirect_In;
393+
case SILArgumentConvention::Pack_Guaranteed:
394+
case SILArgumentConvention::Pack_Owned:
395+
return pai->isOnStack() ? SILArgumentConvention::Pack_Guaranteed
396+
: SILArgumentConvention::Pack_Owned;
392397
case SILArgumentConvention::Indirect_Out:
398+
case SILArgumentConvention::Pack_Out:
393399
llvm_unreachable("partial_apply cannot have an @out operand");
394400
}
395401
llvm_unreachable("covered switch");

0 commit comments

Comments
 (0)