Skip to content

Commit 46be958

Browse files
committed
Extract TypeLowering's recursive type properties into a header, add
functions to compute them directly without a TypeLowering object, and change a lot of getTypeLowering call sites to just use that. There is one subtle change here that I think is okay: SILBuilder used to use different TypeExpansionContexts when inserting into a global: - getTypeLowering() always used a minimal context when inserting into a global - getTypeExpansionContext() always returned a maximal context for the module scope The latter seems more correct, as AFAIK global initializers are never inlinable. If they are, we probably need to configure the builder with an actual context properly rather than making global assumptions. This is incremental progress towards computing this for most types without a TypeLowering, and hopefully eventually removing TL entirely.
1 parent d8cfe92 commit 46be958

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)