Skip to content

Commit 9fa3895

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 54898ce commit 9fa3895

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
@@ -197,6 +197,20 @@ std::pair<SILValue, bool /* changedCFG */>
197197
castValueToABICompatibleType(SILBuilder *builder, SILLocation Loc,
198198
SILValue value, SILType srcTy, SILType destTy,
199199
ArrayRef<SILInstruction *> usePoints);
200+
201+
/// Returns true if the layout of a generic nominal type is dependent on its generic parameters.
202+
/// This is usually the case. Some examples, where they layout is _not_ dependent:
203+
/// ```
204+
/// struct S<T> {
205+
/// var x: Int // no members which depend on T
206+
/// }
207+
///
208+
/// struct S<T> {
209+
/// var c: SomeClass<T> // a class reference does not depend on the layout of the class
210+
/// }
211+
/// ```
212+
bool layoutIsTypeDependent(NominalTypeDecl *decl);
213+
200214
/// Peek through trivial Enum initialization, typically for pointless
201215
/// Optionals.
202216
///

lib/SILOptimizer/Utils/InstOptUtils.cpp

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -742,6 +742,103 @@ swift::castValueToABICompatibleType(SILBuilder *builder, SILLocation loc,
742742
llvm_unreachable("Unknown combination of types for casting");
743743
}
744744

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

0 commit comments

Comments
 (0)