Skip to content

Commit 0bab84f

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 76d5dd4 commit 0bab84f

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
@@ -750,6 +750,103 @@ swift::castValueToABICompatibleType(SILBuilder *builder, SILPassManager *pm,
750750
llvm_unreachable("Unknown combination of types for casting");
751751
}
752752

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

0 commit comments

Comments
 (0)