Skip to content

Commit 467c8af

Browse files
authored
Merge pull request #7994 from swiftix/generic-specialization-fixes
[sil-generic-specializer] Don't specialize types which are too wide or too deep
2 parents 1eebdc1 + f07743b commit 467c8af

File tree

2 files changed

+153
-16
lines changed

2 files changed

+153
-16
lines changed

lib/SILOptimizer/Utils/Generics.cpp

Lines changed: 121 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -34,27 +34,134 @@ llvm::cl::opt<bool> SpecializeGenericSubstitutions(
3434
llvm::cl::init(false),
3535
llvm::cl::desc("Enable partial specialization with generic substitutions"));
3636

37-
// Max depth of a bound generic which can be processed by the generic
37+
// Max depth of a type which can be processed by the generic
3838
// specializer.
3939
// E.g. the depth of Array<Array<Array<T>>> is 3.
4040
// No specializations will be produced, if any of generic parameters contains
41-
// a bound generic type with the depth higher than this threshold
42-
static const unsigned BoundGenericDepthThreshold = 50;
43-
44-
static unsigned getBoundGenericDepth(Type t) {
41+
// a bound generic type with the depth higher than this threshold
42+
static const unsigned TypeDepthThreshold = 50;
43+
// Set the width threshold rather high, because some projects uses very wide
44+
// tuples to model fixed size arrays.
45+
static const unsigned TypeWidthThreshold = 2000;
46+
47+
// Compute the width and the depth of a type.
48+
// We compute both, because some pathological test-cases result in very
49+
// wide types and some others result in very deep types. It is important
50+
// to bail as soon as we hit the threshold on any of both dimentions to
51+
// prevent compiler hangs and crashes.
52+
static std::pair<unsigned, unsigned> getTypeDepthAndWidth(Type t) {
4553
unsigned Depth = 0;
46-
if (auto BGT = t->getAs<BoundGenericType>()) {
54+
unsigned Width = 0;
55+
if (auto *BGT = t->getAs<BoundGenericType>()) {
56+
auto *NTD = BGT->getNominalOrBoundGenericNominal();
57+
if (NTD) {
58+
auto StoredProperties = NTD->getStoredProperties();
59+
Width += std::distance(StoredProperties.begin(), StoredProperties.end());
60+
}
4761
Depth++;
62+
unsigned MaxTypeDepth = 0;
4863
auto GenericArgs = BGT->getGenericArgs();
49-
unsigned MaxGenericArgDepth = 0;
50-
for (auto GenericArg : GenericArgs) {
51-
auto ArgDepth = getBoundGenericDepth(GenericArg);
52-
if (ArgDepth > MaxGenericArgDepth)
53-
MaxGenericArgDepth = ArgDepth;
64+
for (auto Ty : GenericArgs) {
65+
unsigned TypeWidth;
66+
unsigned TypeDepth;
67+
std::tie(TypeDepth, TypeWidth) = getTypeDepthAndWidth(Ty);
68+
if (TypeDepth > MaxTypeDepth)
69+
MaxTypeDepth = TypeDepth;
70+
Width += TypeWidth;
71+
}
72+
Depth += MaxTypeDepth;
73+
return std::make_pair(Depth, Width);
74+
}
75+
76+
if (auto *TupleTy = t->getAs<TupleType>()) {
77+
Width += TupleTy->getNumElements();
78+
Depth++;
79+
unsigned MaxTypeDepth = 0;
80+
auto ElementTypes = TupleTy->getElementTypes();
81+
for (auto Ty : ElementTypes) {
82+
unsigned TypeWidth;
83+
unsigned TypeDepth;
84+
std::tie(TypeDepth, TypeWidth) = getTypeDepthAndWidth(Ty);
85+
if (TypeDepth > MaxTypeDepth)
86+
MaxTypeDepth = TypeDepth;
87+
Width += TypeWidth;
88+
}
89+
Depth += MaxTypeDepth;
90+
return std::make_pair(Depth, Width);
91+
}
92+
93+
if (auto *FnTy = t->getAs<SILFunctionType>()) {
94+
Depth++;
95+
unsigned MaxTypeDepth = 0;
96+
auto Params = FnTy->getParameters();
97+
Width += Params.size();
98+
for (auto Param : Params) {
99+
unsigned TypeWidth;
100+
unsigned TypeDepth;
101+
std::tie(TypeDepth, TypeWidth) = getTypeDepthAndWidth(Param.getType());
102+
if (TypeDepth > MaxTypeDepth)
103+
MaxTypeDepth = TypeDepth;
104+
Width += TypeWidth;
54105
}
55-
Depth += MaxGenericArgDepth;
106+
auto Results = FnTy->getResults();
107+
Width += Results.size();
108+
for (auto Result : Results) {
109+
unsigned TypeWidth;
110+
unsigned TypeDepth;
111+
std::tie(TypeDepth, TypeWidth) = getTypeDepthAndWidth(Result.getType());
112+
if (TypeDepth > MaxTypeDepth)
113+
MaxTypeDepth = TypeDepth;
114+
Width += TypeWidth;
115+
}
116+
if (FnTy->hasErrorResult()) {
117+
Width += 1;
118+
unsigned TypeWidth;
119+
unsigned TypeDepth;
120+
std::tie(TypeDepth, TypeWidth) =
121+
getTypeDepthAndWidth(FnTy->getErrorResult().getType());
122+
if (TypeDepth > MaxTypeDepth)
123+
MaxTypeDepth = TypeDepth;
124+
Width += TypeWidth;
125+
}
126+
Depth += MaxTypeDepth;
127+
return std::make_pair(Depth, Width);
128+
}
129+
130+
if (auto *FnTy = t->getAs<FunctionType>()) {
131+
Depth++;
132+
unsigned MaxTypeDepth = 0;
133+
unsigned TypeWidth;
134+
unsigned TypeDepth;
135+
std::tie(TypeDepth, TypeWidth) = getTypeDepthAndWidth(FnTy->getInput());
136+
if (TypeDepth > MaxTypeDepth)
137+
MaxTypeDepth = TypeDepth;
138+
Width += TypeWidth;
139+
std::tie(TypeDepth, TypeWidth) = getTypeDepthAndWidth(FnTy->getResult());
140+
if (TypeDepth > MaxTypeDepth)
141+
MaxTypeDepth = TypeDepth;
142+
Width += TypeWidth;
143+
Depth += MaxTypeDepth;
144+
return std::make_pair(Depth, Width);
56145
}
57-
return Depth;
146+
147+
if (auto *MT = t->getAs<MetatypeType>()) {
148+
Depth += 1;
149+
unsigned TypeWidth;
150+
unsigned TypeDepth;
151+
std::tie(TypeDepth, TypeWidth) = getTypeDepthAndWidth(MT->getInstanceType());
152+
Width += TypeWidth;
153+
Depth += TypeDepth;
154+
return std::make_pair(Depth, Width);
155+
}
156+
157+
return std::make_pair(Depth, Width);
158+
}
159+
160+
static bool isTypeTooComplex(Type t) {
161+
unsigned TypeWidth;
162+
unsigned TypeDepth;
163+
std::tie(TypeDepth, TypeWidth) = getTypeDepthAndWidth(t);
164+
return TypeWidth >= TypeWidthThreshold || TypeDepth >= TypeDepthThreshold;
58165
}
59166

60167
// =============================================================================
@@ -116,9 +223,7 @@ bool ReabstractionInfo::prepareAndCheck(ApplySite Apply, SILFunction *Callee,
116223
// generated specializations.
117224
for (auto Sub : ParamSubs) {
118225
auto Replacement = Sub.getReplacement();
119-
if (Replacement.findIf([](Type ty) -> bool {
120-
return getBoundGenericDepth(ty) >= BoundGenericDepthThreshold;
121-
})) {
226+
if (isTypeTooComplex(Replacement)) {
122227
DEBUG(llvm::dbgs()
123228
<< " Cannot specialize because the generic type is too deep.\n");
124229
return false;

test/SILOptimizer/specialize_deep_generics.swift

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,3 +32,35 @@ public func testComputeNat() -> Int32 {
3232
return computeNat(8, Zero())
3333
}
3434

35+
// Check that compiler does not hang producing very wide tuples during
36+
// specialization.
37+
@inline(never)
38+
func computeTuple<T>(t: T) {
39+
computeTuple(t: (t, t))
40+
}
41+
42+
// CHECK-LABEL: sil @_T024specialize_deep_generics16testComputeTupleyyF
43+
public func testComputeTuple() {
44+
computeTuple(t: 0)
45+
}
46+
47+
// Check that compiler does not hang producing very deep metatypes.
48+
@inline(never)
49+
public func computeMetatype<T>(t: T) {
50+
computeMetatype(t: T.self)
51+
}
52+
53+
// CHECK-LABEL: sil @_T024specialize_deep_generics19testComputeMetatypeyyF
54+
public func testComputeMetatype() {
55+
computeMetatype(t: 0)
56+
}
57+
58+
// Check that compiler does not hang producing very deep function types.
59+
@inline(never)
60+
public func computeFunctionType<T>(t: [T]) {
61+
computeFunctionType(t: [{ t[0] }])
62+
}
63+
64+
public func testComputeFunctionType() {
65+
computeFunctionType(t: [0])
66+
}

0 commit comments

Comments
 (0)