Skip to content

Commit d25a8ae

Browse files
committed
Add explicit lowering for value packs and pack expansions.
- SILPackType carries whether the elements are stored directly in the pack, which we're not currently using in the lowering, but it's probably something we'll want in the final ABI. Having this also makes it clear that we're doing the right thing with substitution and element lowering. I also toyed with making this a scalar type, which made it necessary in various places, although eventually I pulled back to the design where we always use packs as addresses. - Pack boundaries are a core ABI concept, so the lowering has to wrap parameter pack expansions up as packs. There are huge unimplemented holes here where the abstraction pattern will need to tell us how many elements to gather into the pack, but a naive approach is good enough to get things off the ground. - Pack conventions are related to the existing parameter and result conventions, but they're different on enough grounds that they deserve to be separated.
1 parent 547d85e commit d25a8ae

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)