@@ -110,193 +110,6 @@ bool SILType::isPointerSizeAndAligned() {
110
110
return false ;
111
111
}
112
112
113
- // Allow casting a struct by value when all elements in toType correspond to
114
- // an element of the same size or larger laid out in the same order in
115
- // fromType. The assumption is that if fromType has larger elements, or
116
- // additional elements, their presence cannot induce a more compact layout of
117
- // the overlapping elements.
118
- //
119
- // struct {A, B} -> A is castable
120
- // struct {A, B, C} -> struct {A, B} is castable
121
- // struct { struct {A, B}, C} -> struct {A, B} is castable
122
- // struct { A, B, C} -> struct { struct {A, B}, C} is NOT castable
123
- //
124
- // FIXME: This is unnecessarily conservative given the current ABI
125
- // (TypeLayout.rst). It would be simpler to flatten both `from` and `to` types,
126
- // exploding all structs and tuples, then trivially check if `to` is a prefix.
127
- static bool canUnsafeCastStruct (SILType fromType, StructDecl *fromStruct,
128
- SILType toType, SILModule &M) {
129
- auto fromRange = fromStruct->getStoredProperties ();
130
- if (fromRange.begin () == fromRange.end ())
131
- return false ;
132
-
133
- // Can the first element of fromStruct be cast by value into toType?
134
- SILType fromEltTy = fromType.getFieldType (*fromRange.begin (), M);
135
- if (SILType::canPerformABICompatibleUnsafeCastValue (fromEltTy, toType, M))
136
- return true ;
137
-
138
- // Otherwise, flatten one level of struct elements on each side.
139
- StructDecl *toStruct = toType.getStructOrBoundGenericStruct ();
140
- if (!toStruct)
141
- return false ;
142
-
143
- auto toRange = toStruct->getStoredProperties ();
144
- for (auto toI = toRange.begin (), toE = toRange.end (),
145
- fromI = fromRange.begin (), fromE = fromRange.end ();
146
- toI != toE; ++toI, ++fromI) {
147
-
148
- if (fromI == fromE)
149
- return false ; // fromType is a struct with fewer elements.
150
-
151
- SILType fromEltTy = fromType.getFieldType (*fromI, M);
152
- SILType toEltTy = toType.getFieldType (*toI, M);
153
- if (!SILType::canPerformABICompatibleUnsafeCastValue (fromEltTy, toEltTy, M))
154
- return false ;
155
- }
156
- // fromType's overlapping elements are compatible.
157
- return true ;
158
- }
159
-
160
- // Allow casting a tuple by value when all elements in toType correspond to an
161
- // element of the same size or larger in fromType in the same order.
162
- static bool canUnsafeCastTuple (SILType fromType, CanTupleType fromTupleTy,
163
- SILType toType, SILModule &M) {
164
- unsigned numFromElts = fromTupleTy->getNumElements ();
165
- // Can the first element of fromTupleTy be cast by value into toType?
166
- if (numFromElts != 0
167
- && SILType::canPerformABICompatibleUnsafeCastValue (
168
- fromType.getTupleElementType (0 ), toType, M)) {
169
- return true ;
170
- }
171
- // Otherwise, flatten one level of tuple elements on each side.
172
- auto toTupleTy = dyn_cast<TupleType>(toType.getASTType ());
173
- if (!toTupleTy)
174
- return false ;
175
-
176
- unsigned numToElts = toTupleTy->getNumElements ();
177
- if (numFromElts < numToElts)
178
- return false ;
179
-
180
- for (unsigned i = 0 ; i != numToElts; ++i) {
181
- if (!SILType::canPerformABICompatibleUnsafeCastValue (
182
- fromType.getTupleElementType (i), toType.getTupleElementType (i),
183
- M)) {
184
- return false ;
185
- }
186
- }
187
- return true ;
188
- }
189
-
190
- // Allow casting an enum by value when toType is an enum and each elements is
191
- // individually castable to toType. An enum cannot be smaller than its payload.
192
- static bool canUnsafeCastEnum (SILType fromType, EnumDecl *fromEnum,
193
- SILType toType, SILModule &M) {
194
- unsigned numToElements = 0 ;
195
- SILType toElementTy;
196
- if (EnumDecl *toEnum = toType.getEnumOrBoundGenericEnum ()) {
197
- for (auto toElement : toEnum->getAllElements ()) {
198
- ++numToElements;
199
- if (!toElement->hasAssociatedValues ())
200
- continue ;
201
- // Bail on multiple payloads.
202
- if (!toElementTy.isNull ())
203
- return false ;
204
- toElementTy = toType.getEnumElementType (toElement, M);
205
- }
206
- } else {
207
- // If toType is not an enum, handle it like a singleton
208
- numToElements = 1 ;
209
- toElementTy = toType;
210
- }
211
- // If toType has more elements, it may be larger.
212
- auto fromElements = fromEnum->getAllElements ();
213
- if (static_cast <ptrdiff_t >(numToElements) >
214
- std::distance (fromElements.begin (), fromElements.end ()))
215
- return false ;
216
-
217
- if (toElementTy.isNull ())
218
- return true ;
219
-
220
- // If any of the fromElements can be cast by value to the singleton toElement,
221
- // then the overall enum can be cast by value.
222
- for (auto fromElement : fromElements) {
223
- if (!fromElement->hasAssociatedValues ())
224
- continue ;
225
-
226
- auto fromElementTy = fromType.getEnumElementType (fromElement, M);
227
- if (SILType::canPerformABICompatibleUnsafeCastValue (fromElementTy,
228
- toElementTy, M))
229
- return true ;
230
- }
231
- return false ;
232
- }
233
-
234
- static bool canUnsafeCastScalars (SILType fromType, SILType toType,
235
- SILModule &M) {
236
- CanType fromCanTy = fromType.getASTType ();
237
- bool isToPointer = toType.isPointerSizeAndAligned ();
238
-
239
- unsigned LeastFromWidth = 0 ;
240
- // Like UnsafeRefBitCast, allow class existentials to be truncated to
241
- // single-pointer references. Unlike UnsafeRefBitCast, this also supports raw
242
- // pointers and words.
243
- if (fromType.isPointerSizeAndAligned ()
244
- || fromCanTy.isAnyClassReferenceType ()) {
245
-
246
- // Allow casting from a value that contains an aligned pointer into another
247
- // pointer value regardless of the fixed width.
248
- if (isToPointer)
249
- return true ;
250
-
251
- LeastFromWidth = BuiltinIntegerWidth::pointer ().getLeastWidth ();
252
-
253
- } else if (auto fromIntTy = dyn_cast<BuiltinIntegerType>(fromCanTy)) {
254
- if (fromIntTy->isFixedWidth ())
255
- LeastFromWidth = fromIntTy->getFixedWidth ();
256
- }
257
-
258
- unsigned GreatestToWidth = UINT_MAX;
259
- if (isToPointer) {
260
- GreatestToWidth = BuiltinIntegerWidth::pointer ().getGreatestWidth ();
261
-
262
- } else if (auto toIntTy = dyn_cast<BuiltinIntegerType>(
263
- toType.getASTType ())) {
264
- if (toIntTy->isFixedWidth ())
265
- GreatestToWidth = toIntTy->getFixedWidth ();
266
- }
267
- return LeastFromWidth >= GreatestToWidth;
268
- }
269
-
270
- bool SILType::canPerformABICompatibleUnsafeCastValue (SILType fromType,
271
- SILType toType,
272
- SILModule &M) {
273
- if (fromType == toType)
274
- return true ;
275
-
276
- // Unwrap single element structs.
277
- if (StructDecl *toStruct = toType.getStructOrBoundGenericStruct ()) {
278
- auto toRange = toStruct->getStoredProperties ();
279
- if (toRange.begin () != toRange.end ()
280
- && std::next (toRange.begin ()) == toRange.end ()) {
281
- toType = toType.getFieldType (*toRange.begin (), M);
282
- }
283
- }
284
- if (canUnsafeCastScalars (fromType, toType, M))
285
- return true ;
286
-
287
- if (StructDecl *fromStruct = fromType.getStructOrBoundGenericStruct ())
288
- return canUnsafeCastStruct (fromType, fromStruct, toType, M);
289
-
290
- if (CanTupleType fromTupleTy =
291
- dyn_cast<TupleType>(fromType.getASTType ())) {
292
- return canUnsafeCastTuple (fromType, fromTupleTy, toType, M);
293
- }
294
- if (EnumDecl *fromEnum = fromType.getEnumOrBoundGenericEnum ())
295
- return canUnsafeCastEnum (fromType, fromEnum, toType, M);
296
-
297
- return false ;
298
- }
299
-
300
113
// Reference cast from representations with single pointer low bits.
301
114
// Only reference cast to simple single pointer representations.
302
115
//
0 commit comments