@@ -110,193 +110,6 @@ bool SILType::isPointerSizeAndAligned() {
110110 return false ;
111111}
112112
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.getSwiftRValueType ());
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.getSwiftRValueType ();
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.getSwiftRValueType ())) {
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.getSwiftRValueType ())) {
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-
300113// Reference cast from representations with single pointer low bits.
301114// Only reference cast to simple single pointer representations.
302115//
0 commit comments