Skip to content

Commit f75d0e7

Browse files
authored
Merge pull request #16615 from rjmccall/abi-accessibility
Perform value operations opaquely on ABI-inaccessible types
2 parents dedcfac + 2ed9077 commit f75d0e7

24 files changed

+889
-387
lines changed

include/swift/AST/Type.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -419,6 +419,12 @@ class CanType : public Type {
419419
});
420420
}
421421

422+
bool findIf(llvm::function_ref<bool (CanType)> fn) const {
423+
return Type::findIf([&fn](Type t) {
424+
return fn(CanType(t));
425+
});
426+
}
427+
422428
// Provide a few optimized accessors that are really type-class queries.
423429

424430
/// Do values of this type have reference semantics?

include/swift/SIL/SILModule.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -632,6 +632,14 @@ class SILModule {
632632
PGOReader = std::move(IPR);
633633
}
634634

635+
/// Can value operations (copies and destroys) on the given lowered type
636+
/// be performed in this module?
637+
bool isTypeABIAccessible(SILType type);
638+
639+
/// Can type metadata for the given formal type be fetched in
640+
/// the given module?
641+
bool isTypeMetadataAccessible(CanType type);
642+
635643
/// \brief Run the SIL verifier to make sure that all Functions follow
636644
/// invariants.
637645
void verify() const;

include/swift/SIL/TypeLowering.h

Lines changed: 116 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -96,35 +96,120 @@ enum IsDependent_t : unsigned {
9696
IsNotDependent = false,
9797
IsDependent = true
9898
};
99-
99+
100+
/// Is a lowered SIL type trivial? That is, are copies ultimately just
101+
/// bit-copies, and it takes no work to destroy a value?
102+
enum IsTrivial_t : bool {
103+
IsNotTrivial = false,
104+
IsTrivial = true
105+
};
106+
107+
/// Is a lowered SIL type fixed-ABI? That is, can the current context
108+
/// assign it a fixed size and alignment and perform value operations on it
109+
/// (such as copies, destroys, constructions, and projections) without
110+
/// metadata?
111+
///
112+
/// Note that a fully concrete type can be non-fixed-ABI without being
113+
/// itself resilient if it contains a subobject which is not fixed-ABI.
114+
///
115+
/// Also note that we're only concerned with the external value ABI here:
116+
/// resilient class types are still fixed-ABI, indirect enum cases do not
117+
/// affect the fixed-ABI-ness of the enum, and so on.
118+
enum IsFixedABI_t : bool {
119+
IsNotFixedABI = false,
120+
IsFixedABI = true
121+
};
122+
123+
/// Is a lowered SIL type address-only? That is, is the current context
124+
/// required to keep the value in memory for some reason?
125+
///
126+
/// A type might be address-only because:
127+
///
128+
/// - it is not fixed-size (e.g. because it is a resilient type) and
129+
/// therefore cannot be loaded into a statically-boundable set of
130+
/// registers; or
131+
///
132+
/// - it is semantically bound to memory, either because its storage
133+
/// address is used by the language runtime to implement its semantics
134+
/// (as with a weak reference) or because its representation is somehow
135+
/// address-dependent (as with something like a relative pointer).
136+
///
137+
/// An address-only type can be fixed-layout and/or trivial.
138+
/// A non-fixed-layout type is always address-only.
139+
enum IsAddressOnly_t : bool {
140+
IsNotAddressOnly = false,
141+
IsAddressOnly = true
142+
};
143+
144+
/// Is this type somewhat like a reference-counted type?
145+
enum IsReferenceCounted_t : bool {
146+
IsNotReferenceCounted = false,
147+
IsReferenceCounted = true
148+
};
149+
100150
/// Extended type information used by SIL.
101151
class TypeLowering {
102152
public:
103-
enum IsTrivial_t : bool { IsNotTrivial, IsTrivial };
104-
enum IsAddressOnly_t : bool { IsNotAddressOnly, IsAddressOnly };
105-
enum IsReferenceCounted_t : bool {
106-
IsNotReferenceCounted,
107-
IsReferenceCounted
153+
class RecursiveProperties {
154+
// These are chosen so that bitwise-or merges the flags properly.
155+
enum : unsigned {
156+
NonTrivialFlag = 1 << 0,
157+
NonFixedABIFlag = 1 << 1,
158+
AddressOnlyFlag = 1 << 2,
159+
};
160+
161+
uint8_t Flags;
162+
public:
163+
/// Construct a default RecursiveProperties, which corresponds to
164+
/// a trivial, loadable, fixed-layout type.
165+
constexpr RecursiveProperties() : Flags(0) {}
166+
167+
constexpr RecursiveProperties(IsTrivial_t isTrivial,
168+
IsFixedABI_t isFixedABI,
169+
IsAddressOnly_t isAddressOnly)
170+
: Flags((isTrivial ? 0U : NonTrivialFlag) |
171+
(isAddressOnly ? AddressOnlyFlag : 0U) |
172+
(isFixedABI ? 0U : NonFixedABIFlag)) {}
173+
174+
static constexpr RecursiveProperties forReference() {
175+
return {IsNotTrivial, IsFixedABI, IsNotAddressOnly};
176+
}
177+
178+
static constexpr RecursiveProperties forOpaque() {
179+
return {IsNotTrivial, IsNotFixedABI, IsAddressOnly};
180+
}
181+
182+
void addSubobject(RecursiveProperties other) {
183+
Flags |= other.Flags;
184+
}
185+
186+
IsTrivial_t isTrivial() const {
187+
return IsTrivial_t((Flags & NonTrivialFlag) == 0);
188+
}
189+
IsFixedABI_t isFixedABI() const {
190+
return IsFixedABI_t((Flags & NonFixedABIFlag) == 0);
191+
}
192+
IsAddressOnly_t isAddressOnly() const {
193+
return IsAddressOnly_t((Flags & AddressOnlyFlag) != 0);
194+
}
195+
196+
void setNonTrivial() { Flags |= NonTrivialFlag; }
197+
void setNonFixedABI() { Flags |= NonFixedABIFlag; }
198+
void setAddressOnly() { Flags |= AddressOnlyFlag; }
108199
};
109200

110201
private:
111202
/// The SIL type of values with this Swift type.
112203
SILType LoweredType;
113204

114-
enum : unsigned {
115-
IsTrivialFlag = 0x1,
116-
IsAddressOnlyFlag = 0x2,
117-
IsReferenceCountedFlag = 0x4,
118-
};
119-
unsigned Flags;
205+
RecursiveProperties Properties;
206+
unsigned ReferenceCounted : 1;
120207

121208
protected:
122-
TypeLowering(SILType type, IsTrivial_t isTrivial,
123-
IsAddressOnly_t isAddressOnly,
209+
TypeLowering(SILType type, RecursiveProperties properties,
124210
IsReferenceCounted_t isRefCounted)
125-
: LoweredType(type), Flags((isTrivial ? IsTrivialFlag : 0U) |
126-
(isAddressOnly ? IsAddressOnlyFlag : 0U) |
127-
(isRefCounted ? IsReferenceCountedFlag : 0U)) {}
211+
: LoweredType(type), Properties(properties),
212+
ReferenceCounted(isRefCounted) {}
128213

129214
public:
130215
TypeLowering(const TypeLowering &) = delete;
@@ -143,30 +228,41 @@ class TypeLowering {
143228
/// This is independent of whether the SIL result is address type.
144229
bool isFormallyReturnedIndirectly() const { return isAddressOnly(); }
145230

231+
RecursiveProperties getRecursiveProperties() const {
232+
return Properties;
233+
}
234+
146235
/// isAddressOnly - Returns true if the type is an address-only type. A type
147236
/// is address-only if it is a resilient value type, or if it is a fragile
148237
/// value type with a resilient member. In either case, the full layout of
149238
/// values of the type is unavailable to the compiler.
150239
bool isAddressOnly() const {
151-
return Flags & IsAddressOnlyFlag;
240+
return Properties.isAddressOnly();
152241
}
153242
/// isLoadable - Returns true if the type is loadable, in other words, its
154243
/// full layout is available to the compiler. This is the inverse of
155244
/// isAddressOnly.
156245
bool isLoadable() const {
157246
return !isAddressOnly();
158247
}
248+
249+
/// isFixedABI - Returns true if the type has a known fixed layout.
250+
/// If this is true, value operations on the type can be performed even if
251+
/// the type is inaccessible.
252+
bool isFixedABI() const {
253+
return Properties.isFixedABI();
254+
}
159255

160256
/// Returns true if the type is trivial, meaning it is a loadable
161257
/// value type with no reference type members that require releasing.
162258
bool isTrivial() const {
163-
return Flags & IsTrivialFlag;
259+
return Properties.isTrivial();
164260
}
165261

166262
/// Returns true if the type is a scalar reference-counted reference, which
167263
/// can be retained and released.
168264
bool isReferenceCounted() const {
169-
return Flags & IsReferenceCountedFlag;
265+
return ReferenceCounted;
170266
}
171267

172268
/// getLoweredType - Get the type used to represent values of the Swift type

lib/IRGen/FixedTypeInfo.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ class FixedTypeInfo : public TypeInfo {
4545
Alignment align, IsPOD_t pod, IsBitwiseTakable_t bt,
4646
IsFixedSize_t alwaysFixedSize,
4747
SpecialTypeInfoKind stik = SpecialTypeInfoKind::Fixed)
48-
: TypeInfo(type, align, pod, bt, alwaysFixedSize, stik),
48+
: TypeInfo(type, align, pod, bt, alwaysFixedSize, IsABIAccessible, stik),
4949
SpareBits(spareBits) {
5050
assert(SpareBits.size() == size.getValueInBits());
5151
assert(isFixedSize());
@@ -58,7 +58,7 @@ class FixedTypeInfo : public TypeInfo {
5858
Alignment align, IsPOD_t pod, IsBitwiseTakable_t bt,
5959
IsFixedSize_t alwaysFixedSize,
6060
SpecialTypeInfoKind stik = SpecialTypeInfoKind::Fixed)
61-
: TypeInfo(type, align, pod, bt, alwaysFixedSize, stik),
61+
: TypeInfo(type, align, pod, bt, alwaysFixedSize, IsABIAccessible, stik),
6262
SpareBits(std::move(spareBits)) {
6363
assert(SpareBits.size() == size.getValueInBits());
6464
assert(isFixedSize());
@@ -69,6 +69,7 @@ class FixedTypeInfo : public TypeInfo {
6969
public:
7070
// This is useful for metaprogramming.
7171
static bool isFixed() { return true; }
72+
static IsABIAccessible_t isABIAccessible() { return IsABIAccessible; }
7273

7374
/// Whether this type is known to be empty.
7475
bool isKnownEmpty(ResilienceExpansion expansion) const {

lib/IRGen/GenArchetype.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,8 @@ namespace {
8989
class OpaqueArchetypeTypeInfo
9090
: public ResilientTypeInfo<OpaqueArchetypeTypeInfo>
9191
{
92-
OpaqueArchetypeTypeInfo(llvm::Type *type) : ResilientTypeInfo(type) {}
92+
OpaqueArchetypeTypeInfo(llvm::Type *type)
93+
: ResilientTypeInfo(type, IsABIAccessible) {}
9394

9495
public:
9596
static const OpaqueArchetypeTypeInfo *create(llvm::Type *type) {

0 commit comments

Comments
 (0)