Skip to content

Commit 2f6f3aa

Browse files
authored
Merge pull request #83490 from rjmccall/sil-type-properties
Extract and use SILTypeProperties without a TypeLowering
2 parents 7e82e62 + 46be958 commit 2f6f3aa

27 files changed

+606
-516
lines changed

include/swift/SIL/Lifetime.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ namespace swift {
2626
/// aggressively its destroys may be hoisted.
2727
///
2828
/// By default, types have lifetimes inferred from their structure, see
29-
/// TypeLowering::RecursiveProperties::isLexical. It can be overridden both on
29+
/// SILTypeProperties::isLexical. It can be overridden both on
3030
/// the type level and the value level via attributes.
3131
struct Lifetime {
3232
enum Storage : uint8_t {

include/swift/SIL/SILBuilder.h

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -210,7 +210,8 @@ class SILBuilder {
210210

211211
TypeExpansionContext getTypeExpansionContext() const {
212212
if (!F)
213-
return TypeExpansionContext::minimal();
213+
return TypeExpansionContext::maximal(getModule().getSwiftModule(),
214+
getModule().isWholeModule());
214215
return TypeExpansionContext(getFunction());
215216
}
216217

@@ -223,15 +224,10 @@ class SILBuilder {
223224
}
224225
ASTContext &getASTContext() const { return getModule().getASTContext(); }
225226
const Lowering::TypeLowering &getTypeLowering(SILType T) const {
226-
227-
auto expansion = TypeExpansionContext::maximal(getModule().getSwiftModule(),
228-
getModule().isWholeModule());
229-
// If there's no current SILFunction, we're inserting into a global
230-
// variable initializer.
231-
if (F) {
232-
expansion = TypeExpansionContext(getFunction());
233-
}
234-
return getModule().Types.getTypeLowering(T, expansion);
227+
return getModule().Types.getTypeLowering(T, getTypeExpansionContext());
228+
}
229+
SILTypeProperties getTypeProperties(SILType T) const {
230+
return getModule().Types.getTypeProperties(T, getTypeExpansionContext());
235231
}
236232

237233
void setCurrentDebugScope(const SILDebugScope *DS) { CurDebugScope = DS; }
@@ -2346,7 +2342,7 @@ class SILBuilder {
23462342
FixLifetimeInst(getSILDebugLocation(Loc), Operand));
23472343
}
23482344
void emitFixLifetime(SILLocation Loc, SILValue Operand) {
2349-
if (getTypeLowering(Operand->getType()).isTrivial())
2345+
if (getTypeProperties(Operand->getType()).isTrivial())
23502346
return;
23512347
createFixLifetime(Loc, Operand);
23522348
}
@@ -3187,7 +3183,7 @@ class SILBuilder {
31873183
if (!SILModuleConventions(M).useLoweredAddresses())
31883184
return true;
31893185

3190-
return getTypeLowering(Ty).isLoadable();
3186+
return getTypeProperties(Ty).isLoadable();
31913187
}
31923188

31933189
void appendOperandTypeName(SILType OpdTy, llvm::SmallString<16> &Name) {

include/swift/SIL/SILFunction.h

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ class BasicBlockBitfield;
4242
class NodeBitfield;
4343
class OperandBitfield;
4444
class CalleeCache;
45+
class SILTypeProperties;
4546
class SILUndef;
4647

4748
namespace Lowering {
@@ -784,11 +785,18 @@ class SILFunction
784785
return TypeExpansionContext(*this);
785786
}
786787

788+
SILTypeProperties getTypeProperties(Lowering::AbstractionPattern orig,
789+
Type subst) const;
790+
SILTypeProperties getTypeProperties(Type subst) const;
791+
SILTypeProperties getTypeProperties(SILType type) const;
792+
787793
const Lowering::TypeLowering &
788-
getTypeLowering(Lowering::AbstractionPattern orig, Type subst);
794+
getTypeLowering(Lowering::AbstractionPattern orig, Type subst) const;
789795

790796
const Lowering::TypeLowering &getTypeLowering(Type t) const;
791797

798+
const Lowering::TypeLowering &getTypeLowering(SILType type) const;
799+
792800
SILType getLoweredType(Lowering::AbstractionPattern orig, Type subst) const;
793801

794802
SILType getLoweredType(Type t) const;
@@ -801,8 +809,6 @@ class SILFunction
801809

802810
SILType getLoweredType(SILType t) const;
803811

804-
const Lowering::TypeLowering &getTypeLowering(SILType type) const;
805-
806812
bool isTypeABIAccessible(SILType type) const;
807813

808814
/// Returns true if this function has a calling convention that has a self

include/swift/SIL/SILTypeProperties.h

Lines changed: 254 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,254 @@
1+
//===--- SILTypeProperties.h - Properties of SIL types ----------*- C++ -*-===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2025 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
#ifndef SWIFT_SIL_SILTYPEPROPERTIES_H
14+
#define SWIFT_SIL_SILTYPEPROPERTIES_H
15+
16+
namespace swift {
17+
18+
/// Is a lowered SIL type trivial? That is, are copies ultimately just
19+
/// bit-copies, and it takes no work to destroy a value?
20+
enum IsTrivial_t : bool {
21+
IsNotTrivial = false,
22+
IsTrivial = true
23+
};
24+
25+
/// Is a lowered SIL type the Builtin.RawPointer or a struct/tuple/enum which
26+
/// contains a Builtin.RawPointer?
27+
/// HasRawPointer is true only for types that are known to contain
28+
/// Builtin.RawPointer. It is not assumed true for generic or resilient types.
29+
enum HasRawPointer_t : bool {
30+
DoesNotHaveRawPointer = false,
31+
HasRawPointer = true
32+
};
33+
34+
/// Is a lowered SIL type fixed-ABI? That is, can the current context
35+
/// assign it a fixed size and alignment and perform value operations on it
36+
/// (such as copies, destroys, constructions, and projections) without
37+
/// metadata?
38+
///
39+
/// Note that a fully concrete type can be non-fixed-ABI without being
40+
/// itself resilient if it contains a subobject which is not fixed-ABI.
41+
///
42+
/// Also note that we're only concerned with the external value ABI here:
43+
/// resilient class types are still fixed-ABI, indirect enum cases do not
44+
/// affect the fixed-ABI-ness of the enum, and so on.
45+
enum IsFixedABI_t : bool {
46+
IsNotFixedABI = false,
47+
IsFixedABI = true
48+
};
49+
50+
/// Is a lowered SIL type address-only? That is, is the current context
51+
/// required to keep the value in memory for some reason?
52+
///
53+
/// A type might be address-only because:
54+
///
55+
/// - it is not fixed-size (e.g. because it is a resilient type) and
56+
/// therefore cannot be loaded into a statically-boundable set of
57+
/// registers; or
58+
///
59+
/// - it is semantically bound to memory, either because its storage
60+
/// address is used by the language runtime to implement its semantics
61+
/// (as with a weak reference) or because its representation is somehow
62+
/// address-dependent (as with something like a relative pointer).
63+
///
64+
/// An address-only type can be fixed-layout and/or trivial.
65+
/// A non-fixed-layout type is always address-only.
66+
enum IsAddressOnly_t : bool {
67+
IsNotAddressOnly = false,
68+
IsAddressOnly = true
69+
};
70+
71+
/// Is this type somewhat like a reference-counted type?
72+
enum IsReferenceCounted_t : bool {
73+
IsNotReferenceCounted = false,
74+
IsReferenceCounted = true
75+
};
76+
77+
/// Is this type address only because it's resilient?
78+
enum IsResilient_t : bool {
79+
IsNotResilient = false,
80+
IsResilient = true
81+
};
82+
83+
/// Does this type contain an opaque result type that affects type lowering?
84+
enum IsTypeExpansionSensitive_t : bool {
85+
IsNotTypeExpansionSensitive = false,
86+
IsTypeExpansionSensitive = true
87+
};
88+
89+
/// Is the type infinitely defined in terms of itself? (Such types can never
90+
/// be concretely instantiated, but may still arise from generic specialization.)
91+
enum IsInfiniteType_t : bool {
92+
IsNotInfiniteType = false,
93+
IsInfiniteType = true,
94+
};
95+
96+
/// Does this type contain any pack-like thing.
97+
enum HasPack_t : bool {
98+
HasNoPack = false,
99+
HasPack = true,
100+
};
101+
102+
/// Is the type addressable-for-dependencies?
103+
///
104+
/// Values of an addressable-for-dependency type are passed indirectly into
105+
/// functions that specify a return value lifetime dependency on the value.
106+
/// This allows the dependent value to safely contain pointers to the in-memory
107+
/// representation of the source of the dependency.
108+
enum IsAddressableForDependencies_t : bool {
109+
IsNotAddressableForDependencies = false,
110+
IsAddressableForDependencies = true,
111+
};
112+
113+
class SILTypeProperties {
114+
// These are chosen so that bitwise-or merges the flags properly.
115+
//
116+
// clang-format off
117+
enum : unsigned {
118+
NonTrivialFlag = 1 << 0,
119+
NonFixedABIFlag = 1 << 1,
120+
AddressOnlyFlag = 1 << 2,
121+
ResilientFlag = 1 << 3,
122+
TypeExpansionSensitiveFlag = 1 << 4,
123+
InfiniteFlag = 1 << 5,
124+
HasRawPointerFlag = 1 << 6,
125+
LexicalFlag = 1 << 7,
126+
HasPackFlag = 1 << 8,
127+
AddressableForDependenciesFlag = 1 << 9,
128+
};
129+
// clang-format on
130+
131+
uint16_t Flags;
132+
133+
public:
134+
/// Construct a default SILTypeProperties, which corresponds to
135+
/// a trivial, loadable, fixed-layout type.
136+
constexpr SILTypeProperties() : Flags(0) {}
137+
138+
constexpr SILTypeProperties(
139+
IsTrivial_t isTrivial, IsFixedABI_t isFixedABI,
140+
IsAddressOnly_t isAddressOnly, IsResilient_t isResilient,
141+
IsTypeExpansionSensitive_t isTypeExpansionSensitive =
142+
IsNotTypeExpansionSensitive,
143+
HasRawPointer_t hasRawPointer = DoesNotHaveRawPointer,
144+
IsLexical_t isLexical = IsNotLexical, HasPack_t hasPack = HasNoPack,
145+
IsAddressableForDependencies_t isAFD = IsNotAddressableForDependencies)
146+
: Flags((isTrivial ? 0U : NonTrivialFlag) |
147+
(isFixedABI ? 0U : NonFixedABIFlag) |
148+
(isAddressOnly ? AddressOnlyFlag : 0U) |
149+
(isResilient ? ResilientFlag : 0U) |
150+
(isTypeExpansionSensitive ? TypeExpansionSensitiveFlag : 0U) |
151+
(hasRawPointer ? HasRawPointerFlag : 0U) |
152+
(isLexical ? LexicalFlag : 0U) |
153+
(hasPack ? HasPackFlag : 0U) |
154+
(isAFD ? AddressableForDependenciesFlag : 0U)) {}
155+
156+
constexpr bool operator==(SILTypeProperties p) const {
157+
return Flags == p.Flags;
158+
}
159+
160+
static constexpr SILTypeProperties forTrivial() {
161+
return {IsTrivial, IsFixedABI, IsNotAddressOnly, IsNotResilient};
162+
}
163+
164+
static constexpr SILTypeProperties forTrivialOpaque() {
165+
return {IsTrivial, IsFixedABI, IsNotAddressOnly, IsNotResilient,
166+
IsNotTypeExpansionSensitive, HasRawPointer, IsNotLexical,
167+
HasNoPack, IsAddressableForDependencies};
168+
}
169+
170+
static constexpr SILTypeProperties forRawPointer() {
171+
return {IsTrivial, IsFixedABI, IsNotAddressOnly, IsNotResilient,
172+
IsNotTypeExpansionSensitive, HasRawPointer};
173+
}
174+
175+
static constexpr SILTypeProperties forReference() {
176+
return {IsNotTrivial, IsFixedABI, IsNotAddressOnly, IsNotResilient,
177+
IsNotTypeExpansionSensitive, DoesNotHaveRawPointer, IsLexical};
178+
}
179+
180+
static constexpr SILTypeProperties forOpaque() {
181+
return {IsNotTrivial, IsNotFixedABI, IsAddressOnly, IsNotResilient,
182+
IsNotTypeExpansionSensitive, HasRawPointer, IsLexical,
183+
HasNoPack, IsAddressableForDependencies};
184+
}
185+
186+
static constexpr SILTypeProperties forResilient() {
187+
return {IsTrivial, IsFixedABI, IsNotAddressOnly, IsResilient,
188+
IsNotTypeExpansionSensitive, HasRawPointer, IsNotLexical,
189+
HasNoPack, IsNotAddressableForDependencies};
190+
}
191+
192+
void addSubobject(SILTypeProperties other) {
193+
Flags |= other.Flags;
194+
}
195+
196+
IsTrivial_t isTrivial() const {
197+
return IsTrivial_t((Flags & NonTrivialFlag) == 0);
198+
}
199+
HasRawPointer_t isOrContainsRawPointer() const {
200+
return HasRawPointer_t((Flags & HasRawPointerFlag) != 0);
201+
}
202+
IsFixedABI_t isFixedABI() const {
203+
return IsFixedABI_t((Flags & NonFixedABIFlag) == 0);
204+
}
205+
IsAddressOnly_t isAddressOnly() const {
206+
return IsAddressOnly_t((Flags & AddressOnlyFlag) != 0);
207+
}
208+
bool isLoadable() const {
209+
return !isAddressOnly();
210+
}
211+
IsResilient_t isResilient() const {
212+
return IsResilient_t((Flags & ResilientFlag) != 0);
213+
}
214+
IsTypeExpansionSensitive_t isTypeExpansionSensitive() const {
215+
return IsTypeExpansionSensitive_t(
216+
(Flags & TypeExpansionSensitiveFlag) != 0);
217+
}
218+
IsInfiniteType_t isInfinite() const {
219+
return IsInfiniteType_t((Flags & InfiniteFlag) != 0);
220+
}
221+
IsLexical_t isLexical() const {
222+
return IsLexical_t((Flags & LexicalFlag) != 0);
223+
}
224+
HasPack_t isOrContainsPack() const {
225+
return HasPack_t((Flags & HasPackFlag) != 0);
226+
}
227+
IsAddressableForDependencies_t isAddressableForDependencies() const {
228+
return IsAddressableForDependencies_t(
229+
(Flags & AddressableForDependenciesFlag) != 0);
230+
}
231+
232+
void setNonTrivial() { Flags |= NonTrivialFlag; }
233+
void setIsOrContainsRawPointer() { Flags |= HasRawPointerFlag; }
234+
235+
void setNonFixedABI() { Flags |= NonFixedABIFlag; }
236+
void setAddressOnly() { Flags |= AddressOnlyFlag; }
237+
void setTypeExpansionSensitive(
238+
IsTypeExpansionSensitive_t isTypeExpansionSensitive) {
239+
Flags = (Flags & ~TypeExpansionSensitiveFlag) |
240+
(isTypeExpansionSensitive ? TypeExpansionSensitiveFlag : 0);
241+
}
242+
void setInfinite() { Flags |= InfiniteFlag; }
243+
void setLexical(IsLexical_t isLexical) {
244+
Flags = (Flags & ~LexicalFlag) | (isLexical ? LexicalFlag : 0);
245+
}
246+
void setHasPack() { Flags |= HasPackFlag; }
247+
void setAddressableForDependencies() {
248+
Flags |= AddressableForDependenciesFlag;
249+
}
250+
};
251+
252+
} // end namespace swift
253+
254+
#endif

0 commit comments

Comments
 (0)