Skip to content

Commit 9cb0113

Browse files
committed
SILOptimizer: add a utility to check if a generic nominal type's layout is dependent on its generic parameters
This is usually the case. Some examples, where they layout is _not_ dependent: ``` struct S<T> { var x: Int // no members which depend on T } struct S<T> { var c: SomeClass<T> // a class reference does not depend on the layout of the class } ```
1 parent a079c5c commit 9cb0113

File tree

2 files changed

+111
-0
lines changed

2 files changed

+111
-0
lines changed

include/swift/SILOptimizer/Utils/InstOptUtils.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,20 @@ castValueToABICompatibleType(SILBuilder *builder, SILPassManager *pm,
198198
SILLocation Loc,
199199
SILValue value, SILType srcTy, SILType destTy,
200200
ArrayRef<SILInstruction *> usePoints);
201+
202+
/// Returns true if the layout of a generic nominal type is dependent on its generic parameters.
203+
/// This is usually the case. Some examples, where they layout is _not_ dependent:
204+
/// ```
205+
/// struct S<T> {
206+
/// var x: Int // no members which depend on T
207+
/// }
208+
///
209+
/// struct S<T> {
210+
/// var c: SomeClass<T> // a class reference does not depend on the layout of the class
211+
/// }
212+
/// ```
213+
bool layoutIsTypeDependent(NominalTypeDecl *decl);
214+
201215
/// Peek through trivial Enum initialization, typically for pointless
202216
/// Optionals.
203217
///

lib/SILOptimizer/Utils/InstOptUtils.cpp

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -751,6 +751,103 @@ swift::castValueToABICompatibleType(SILBuilder *builder, SILPassManager *pm,
751751
llvm_unreachable("Unknown combination of types for casting");
752752
}
753753

754+
namespace {
755+
class TypeDependentVisitor : public CanTypeVisitor<TypeDependentVisitor, bool> {
756+
public:
757+
// If the type isn't actually dependent, we're okay.
758+
bool visit(CanType type) {
759+
if (!type->hasArchetype() && !type->hasTypeParameter())
760+
return false;
761+
return CanTypeVisitor::visit(type);
762+
}
763+
764+
bool visitStructType(CanStructType type) {
765+
return visitStructDecl(type->getDecl());
766+
}
767+
bool visitBoundGenericStructType(CanBoundGenericStructType type) {
768+
return visitStructDecl(type->getDecl());
769+
}
770+
bool visitStructDecl(StructDecl *decl) {
771+
auto rawLayout = decl->getAttrs().getAttribute<RawLayoutAttr>();
772+
if (rawLayout) {
773+
if (auto likeType = rawLayout->getResolvedScalarLikeType(decl)) {
774+
return visit((*likeType)->getCanonicalType());
775+
} else if (auto likeArray = rawLayout->getResolvedArrayLikeTypeAndCount(decl)) {
776+
return visit(likeArray->first->getCanonicalType());
777+
}
778+
}
779+
780+
for (auto field : decl->getStoredProperties()) {
781+
if (visit(field->getInterfaceType()->getCanonicalType()))
782+
return true;
783+
}
784+
return false;
785+
}
786+
787+
bool visitEnumType(CanEnumType type) {
788+
return visitEnumDecl(type->getDecl());
789+
}
790+
bool visitBoundGenericEnumType(CanBoundGenericEnumType type) {
791+
return visitEnumDecl(type->getDecl());
792+
}
793+
bool visitEnumDecl(EnumDecl *decl) {
794+
if (decl->isIndirect())
795+
return false;
796+
797+
for (auto elt : decl->getAllElements()) {
798+
if (!elt->hasAssociatedValues() || elt->isIndirect())
799+
continue;
800+
801+
if (visit(elt->getArgumentInterfaceType()->getCanonicalType()))
802+
return true;
803+
}
804+
return false;
805+
}
806+
807+
bool visitTupleType(CanTupleType type) {
808+
for (auto eltTy : type.getElementTypes()) {
809+
if (visit(eltTy->getCanonicalType()))
810+
return true;
811+
}
812+
return false;
813+
}
814+
815+
// A class reference does not depend on the layout of the class.
816+
bool visitClassType(CanClassType type) {
817+
return false;
818+
}
819+
bool visitBoundGenericClassType(CanBoundGenericClassType type) {
820+
return false;
821+
}
822+
823+
// The same for non-strong references.
824+
bool visitReferenceStorageType(CanReferenceStorageType type) {
825+
return false;
826+
}
827+
828+
// All function types have the same layout.
829+
bool visitAnyFunctionType(CanAnyFunctionType type) {
830+
return false;
831+
}
832+
833+
// The safe default for types we didn't handle above.
834+
bool visitType(CanType type) {
835+
return true;
836+
}
837+
};
838+
} // end anonymous namespace
839+
840+
bool swift::layoutIsTypeDependent(NominalTypeDecl *decl) {
841+
if (auto *classDecl = dyn_cast<ClassDecl>(decl)) {
842+
return false;
843+
} else if (auto *structDecl = dyn_cast<StructDecl>(decl)) {
844+
return TypeDependentVisitor().visitStructDecl(structDecl);
845+
} else {
846+
auto *enumDecl = cast<EnumDecl>(decl);
847+
return TypeDependentVisitor().visitEnumDecl(enumDecl);
848+
}
849+
}
850+
754851
ProjectBoxInst *swift::getOrCreateProjectBox(AllocBoxInst *abi,
755852
unsigned index) {
756853
SILBasicBlock::iterator iter(abi);

0 commit comments

Comments
 (0)