Skip to content

Commit db60cae

Browse files
authored
Merge pull request #71441 from slavapestov/specializer-loop-rdar121867690
SILOptimizer: Fancier 'too complex' check to prevent runaway specialization
2 parents 8bb6846 + f79b621 commit db60cae

File tree

2 files changed

+68
-120
lines changed

2 files changed

+68
-120
lines changed

lib/SILOptimizer/Utils/Generics.cpp

Lines changed: 46 additions & 120 deletions
Original file line numberDiff line numberDiff line change
@@ -82,133 +82,59 @@ static const unsigned TypeDepthThreshold = 50;
8282
/// Set the width threshold rather high, because some projects uses very wide
8383
/// tuples to model fixed size arrays.
8484
static const unsigned TypeWidthThreshold = 2000;
85+
/// Max length of an opaque archetype's type parameter.
86+
static const unsigned TypeLengthThreshold = 10;
8587

8688
/// Compute the width and the depth of a type.
8789
/// We compute both, because some pathological test-cases result in very
8890
/// wide types and some others result in very deep types. It is important
8991
/// to bail as soon as we hit the threshold on any of both dimensions to
9092
/// prevent compiler hangs and crashes.
91-
static std::pair<unsigned, unsigned> getTypeDepthAndWidth(Type t) {
92-
unsigned Depth = 0;
93-
unsigned Width = 0;
94-
if (auto *BGT = t->getAs<BoundGenericType>()) {
95-
auto *NTD = BGT->getNominalOrBoundGenericNominal();
96-
if (NTD) {
97-
auto StoredProperties = NTD->getStoredProperties();
98-
Width += StoredProperties.size();
99-
}
100-
++Depth;
101-
unsigned MaxTypeDepth = 0;
102-
auto GenericArgs = BGT->getGenericArgs();
103-
for (auto Ty : GenericArgs) {
104-
unsigned TypeWidth;
105-
unsigned TypeDepth;
106-
std::tie(TypeDepth, TypeWidth) = getTypeDepthAndWidth(Ty);
107-
if (TypeDepth > MaxTypeDepth)
108-
MaxTypeDepth = TypeDepth;
109-
Width += TypeWidth;
110-
}
111-
Depth += MaxTypeDepth;
112-
return std::make_pair(Depth, Width);
113-
}
114-
115-
if (auto *TupleTy = t->getAs<TupleType>()) {
116-
Width += TupleTy->getNumElements();
117-
++Depth;
118-
unsigned MaxTypeDepth = 0;
119-
auto ElementTypes = TupleTy->getElementTypes();
120-
for (auto Ty : ElementTypes) {
121-
unsigned TypeWidth;
122-
unsigned TypeDepth;
123-
std::tie(TypeDepth, TypeWidth) = getTypeDepthAndWidth(Ty);
124-
if (TypeDepth > MaxTypeDepth)
125-
MaxTypeDepth = TypeDepth;
126-
Width += TypeWidth;
127-
}
128-
Depth += MaxTypeDepth;
129-
return std::make_pair(Depth, Width);
130-
}
131-
132-
if (auto *FnTy = t->getAs<SILFunctionType>()) {
133-
++Depth;
134-
unsigned MaxTypeDepth = 0;
135-
auto Params = FnTy->getParameters();
136-
Width += Params.size();
137-
for (auto Param : Params) {
138-
unsigned TypeWidth;
139-
unsigned TypeDepth;
140-
std::tie(TypeDepth, TypeWidth) =
141-
getTypeDepthAndWidth(Param.getInterfaceType());
142-
if (TypeDepth > MaxTypeDepth)
143-
MaxTypeDepth = TypeDepth;
144-
Width += TypeWidth;
145-
}
146-
auto Results = FnTy->getResults();
147-
Width += Results.size();
148-
for (auto Result : Results) {
149-
unsigned TypeWidth;
150-
unsigned TypeDepth;
151-
std::tie(TypeDepth, TypeWidth) =
152-
getTypeDepthAndWidth(Result.getInterfaceType());
153-
if (TypeDepth > MaxTypeDepth)
154-
MaxTypeDepth = TypeDepth;
155-
Width += TypeWidth;
156-
}
157-
if (FnTy->hasErrorResult()) {
158-
Width += 1;
159-
unsigned TypeWidth;
160-
unsigned TypeDepth;
161-
std::tie(TypeDepth, TypeWidth) =
162-
getTypeDepthAndWidth(FnTy->getErrorResult().getInterfaceType());
163-
if (TypeDepth > MaxTypeDepth)
164-
MaxTypeDepth = TypeDepth;
165-
Width += TypeWidth;
166-
}
167-
Depth += MaxTypeDepth;
168-
return std::make_pair(Depth, Width);
169-
}
170-
171-
if (auto *FnTy = t->getAs<FunctionType>()) {
172-
++Depth;
173-
unsigned MaxTypeDepth = 0;
174-
auto Params = FnTy->getParams();
175-
Width += Params.size();
176-
for (auto &Param : Params) {
177-
unsigned TypeWidth;
178-
unsigned TypeDepth;
179-
std::tie(TypeDepth, TypeWidth) = getTypeDepthAndWidth(Param.getParameterType());
180-
if (TypeDepth > MaxTypeDepth)
181-
MaxTypeDepth = TypeDepth;
182-
Width += TypeWidth;
183-
}
184-
unsigned TypeWidth;
185-
unsigned TypeDepth;
186-
std::tie(TypeDepth, TypeWidth) = getTypeDepthAndWidth(FnTy->getResult());
187-
if (TypeDepth > MaxTypeDepth)
188-
MaxTypeDepth = TypeDepth;
189-
Width += TypeWidth;
190-
Depth += MaxTypeDepth;
191-
return std::make_pair(Depth, Width);
192-
}
193-
194-
if (auto *MT = t->getAs<MetatypeType>()) {
195-
Depth += 1;
196-
unsigned TypeWidth;
197-
unsigned TypeDepth;
198-
std::tie(TypeDepth, TypeWidth) = getTypeDepthAndWidth(MT->getInstanceType());
199-
Width += TypeWidth;
200-
Depth += TypeDepth;
201-
return std::make_pair(Depth, Width);
202-
}
203-
204-
return std::make_pair(Depth, Width);
205-
}
206-
20793
static bool isTypeTooComplex(Type t) {
208-
unsigned TypeWidth;
209-
unsigned TypeDepth;
210-
std::tie(TypeDepth, TypeWidth) = getTypeDepthAndWidth(t);
211-
return TypeWidth >= TypeWidthThreshold || TypeDepth >= TypeDepthThreshold;
94+
struct Walker : TypeWalker {
95+
unsigned Depth = 0;
96+
unsigned MaxDepth = 0;
97+
unsigned MaxWidth = 0;
98+
unsigned MaxLength = 0;
99+
100+
Action walkToTypePre(Type ty) override {
101+
// The TypeWalker won't visit the interface type encapsulated by the
102+
// archetype, so we do it directly to measure its length.
103+
if (auto *opaqueArchetypeTy = ty->getAs<OpaqueTypeArchetypeType>()) {
104+
auto interfaceTy = opaqueArchetypeTy->getInterfaceType();
105+
106+
unsigned length = 0;
107+
while (auto memberTy = interfaceTy->getAs<DependentMemberType>()) {
108+
++length;
109+
interfaceTy = memberTy->getBase();
110+
}
111+
assert(interfaceTy->is<GenericTypeParamType>());
112+
113+
if (length > MaxLength)
114+
MaxLength = length;
115+
}
116+
117+
++Depth;
118+
MaxDepth = std::max(Depth, MaxDepth);
119+
120+
++MaxWidth;
121+
122+
return Action::Continue;
123+
}
124+
125+
Action walkToTypePost(Type ty) override {
126+
--Depth;
127+
128+
return Action::Continue;
129+
}
130+
};
131+
132+
Walker walker;
133+
t.walk(walker);
134+
135+
return (walker.MaxWidth >= TypeWidthThreshold ||
136+
walker.MaxDepth >= TypeDepthThreshold ||
137+
walker.MaxLength >= TypeLengthThreshold);
212138
}
213139

214140
namespace {
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// RUN: %target-swift-frontend -emit-sil -O %s -disable-availability-checking
2+
3+
// This should not hang forever.
4+
5+
public func foo() -> some P {
6+
return S()
7+
}
8+
9+
public protocol P {
10+
associatedtype A: P
11+
func p() -> A
12+
}
13+
14+
public struct S: P {
15+
public func p() -> some P { return self }
16+
}
17+
18+
public func bar<T: P>(_ t: T, _ n: Int) {
19+
if n > 0 { bar(t.p(), n - 1) }
20+
}
21+
22+
bar(foo(), 1000)

0 commit comments

Comments
 (0)