Skip to content

Commit b4e1e52

Browse files
authored
Merge pull request #63292 from rjmccall/lower-pack-types
Explicitly lower value pack and parameter expansion types in SIL
2 parents 2eab34a + d25a8ae commit b4e1e52

Some content is hidden

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

69 files changed

+1235
-114
lines changed

docs/ABI/Mangling.rst

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

@@ -754,9 +758,13 @@ mangled in to disambiguate.
754758
RESULT-CONVENTION ::= 'd' // unowned
755759
RESULT-CONVENTION ::= 'u' // unowned inner pointer
756760
RESULT-CONVENTION ::= 'a' // auto-released
761+
RESULT-CONVENTION ::= 'k' // pack
757762

758763
RESULT-DIFFERENTIABILITY ::= 'w' // @noDerivative
759764

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

include/swift/AST/Attr.def.gyb

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,11 +66,16 @@ 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)
78+
TYPE_ATTR(pack_out)
7479
TYPE_ATTR(owned)
7580
TYPE_ATTR(unowned_inner_pointer)
7681
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: 163 additions & 5 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,11 +3854,34 @@ inline bool isGuaranteedParameter(ParameterConvention conv) {
38233854
switch (conv) {
38243855
case ParameterConvention::Direct_Guaranteed:
38253856
case ParameterConvention::Indirect_In_Guaranteed:
3857+
case ParameterConvention::Pack_Guaranteed:
3858+
return true;
3859+
3860+
case ParameterConvention::Indirect_Inout:
3861+
case ParameterConvention::Indirect_InoutAliasable:
3862+
case ParameterConvention::Indirect_In:
3863+
case ParameterConvention::Direct_Unowned:
3864+
case ParameterConvention::Direct_Owned:
3865+
case ParameterConvention::Pack_Inout:
3866+
case ParameterConvention::Pack_Owned:
3867+
return false;
3868+
}
3869+
llvm_unreachable("bad convention kind");
3870+
}
3871+
3872+
/// Returns true if conv indicates a pack parameter.
3873+
inline bool isPackParameter(ParameterConvention conv) {
3874+
switch (conv) {
3875+
case ParameterConvention::Pack_Guaranteed:
3876+
case ParameterConvention::Pack_Inout:
3877+
case ParameterConvention::Pack_Owned:
38263878
return true;
38273879

3880+
case ParameterConvention::Indirect_In_Guaranteed:
38283881
case ParameterConvention::Indirect_Inout:
38293882
case ParameterConvention::Indirect_InoutAliasable:
38303883
case ParameterConvention::Indirect_In:
3884+
case ParameterConvention::Direct_Guaranteed:
38313885
case ParameterConvention::Direct_Unowned:
38323886
case ParameterConvention::Direct_Owned:
38333887
return false;
@@ -3906,6 +3960,10 @@ class SILParameterInfo {
39063960
|| getConvention() == ParameterConvention::Indirect_InoutAliasable;
39073961
}
39083962

3963+
bool isPack() const {
3964+
return isPackParameter(getConvention());
3965+
}
3966+
39093967
/// True if this parameter is consumed by the callee, either
39103968
/// indirectly or directly.
39113969
bool isConsumed() const {
@@ -4027,11 +4085,18 @@ enum class ResultConvention : uint8_t {
40274085
/// The type must be a class or class existential type, and this
40284086
/// must be the only return value.
40294087
Autoreleased,
4088+
4089+
/// This value is a pack that is returned indirectly by passing a
4090+
/// pack address (which may or may not be further indirected,
4091+
/// depending on the pact type). The callee is responsible for
4092+
/// leaving an initialized object in each element of the pack.
4093+
Pack,
40304094
};
40314095

40324096
// Does this result require indirect storage for the purpose of reabstraction?
40334097
inline bool isIndirectFormalResult(ResultConvention convention) {
4034-
return convention == ResultConvention::Indirect;
4098+
return convention == ResultConvention::Indirect ||
4099+
convention == ResultConvention::Pack;
40354100
}
40364101

40374102
/// The differentiability of a SIL function type result.
@@ -5138,6 +5203,97 @@ class SILTokenType final : public TypeBase {
51385203
};
51395204
DEFINE_EMPTY_CAN_TYPE_WRAPPER(SILTokenType, Type)
51405205

5206+
/// A lowered pack type which structurally carries lowered information
5207+
/// about the pack elements.
5208+
///
5209+
/// A value pack is basically treated as a unique-ownership, unmovable
5210+
/// reference-semantics aggregate in SIL: ownership of the pack as a whole
5211+
/// is communicated with normal borrows of the pack, and packs can only
5212+
/// be created locally and forwarded as arguments rather than being moved
5213+
/// in any more complex way.
5214+
class SILPackType final : public TypeBase, public llvm::FoldingSetNode,
5215+
private llvm::TrailingObjects<SILPackType, CanType> {
5216+
public:
5217+
/// Type structure not reflected in the pack element type list.
5218+
///
5219+
/// In the design of this, we considered storing ownership here,
5220+
/// but ended up just with the one bit.
5221+
struct ExtInfo {
5222+
bool ElementIsAddress;
5223+
5224+
ExtInfo(bool elementIsAddress) : ElementIsAddress(elementIsAddress) {}
5225+
};
5226+
5227+
private:
5228+
friend TrailingObjects;
5229+
friend class ASTContext;
5230+
SILPackType(const ASTContext &ctx, RecursiveTypeProperties properties,
5231+
ExtInfo info, ArrayRef<CanType> elements)
5232+
: TypeBase(TypeKind::SILPack, &ctx, properties) {
5233+
Bits.SILPackType.Count = elements.size();
5234+
Bits.SILPackType.ElementIsAddress = info.ElementIsAddress;
5235+
memcpy(getTrailingObjects<CanType>(), elements.data(),
5236+
elements.size() * sizeof(CanType));
5237+
}
5238+
5239+
public:
5240+
static CanTypeWrapper<SILPackType> get(const ASTContext &ctx,
5241+
ExtInfo info,
5242+
ArrayRef<CanType> elements);
5243+
5244+
ExtInfo getExtInfo() const {
5245+
return { isElementAddress() };
5246+
}
5247+
5248+
bool isElementAddress() const {
5249+
return Bits.SILPackType.ElementIsAddress;
5250+
}
5251+
5252+
/// Retrieves the number of elements in this pack.
5253+
unsigned getNumElements() const { return Bits.SILPackType.Count; }
5254+
5255+
/// Retrieves the type of the elements in the pack.
5256+
ArrayRef<CanType> getElementTypes() const {
5257+
return {getTrailingObjects<CanType>(), getNumElements()};
5258+
}
5259+
5260+
/// Returns the type of the element at the given \p index.
5261+
/// This is a lowered SIL type.
5262+
CanType getElementType(unsigned index) const {
5263+
return getTrailingObjects<CanType>()[index];
5264+
}
5265+
5266+
SILType getSILElementType(unsigned index) const; // in SILType.h
5267+
5268+
/// Return the reduced shape of this pack. For consistency with
5269+
/// general shape-handling routines, we produce an AST pack type
5270+
/// as the shape, not a SIL pack type.
5271+
CanTypeWrapper<PackType> getReducedShape() const;
5272+
5273+
bool containsPackExpansionType() const;
5274+
5275+
void Profile(llvm::FoldingSetNodeID &ID) const {
5276+
Profile(ID, getExtInfo(), getElementTypes());
5277+
}
5278+
static void Profile(llvm::FoldingSetNodeID &ID,
5279+
ExtInfo info,
5280+
ArrayRef<CanType> elements);
5281+
5282+
// Implement isa/cast/dyncast/etc.
5283+
static bool classof(const TypeBase *T) {
5284+
return T->getKind() == TypeKind::SILPack;
5285+
}
5286+
};
5287+
BEGIN_CAN_TYPE_WRAPPER(SILPackType, Type)
5288+
CanType getElementType(unsigned elementNo) const {
5289+
return getPointer()->getElementType(elementNo);
5290+
}
5291+
5292+
ArrayRef<CanType> getElementTypes() const {
5293+
return getPointer()->getElementTypes();
5294+
}
5295+
END_CAN_TYPE_WRAPPER(SILPackType, Type)
5296+
51415297
/// A type with a special syntax that is always sugar for a library type. The
51425298
/// library type may have multiple base types. For unary syntax sugar, see
51435299
/// UnarySyntaxSugarType.
@@ -6654,6 +6810,8 @@ class PackExpansionType : public TypeBase, public llvm::FoldingSetNode {
66546810
const ASTContext *ctx);
66556811
};
66566812
BEGIN_CAN_TYPE_WRAPPER(PackExpansionType, Type)
6813+
static CanPackExpansionType get(CanType pattern, CanType countType);
6814+
66576815
CanType getPatternType() const {
66586816
return CanType(getPointer()->getPatternType());
66596817
}

0 commit comments

Comments
 (0)