Skip to content

Commit 9049d6e

Browse files
authored
Merge pull request #3504 from swiftix/generic-specialization-fixes
[sil-generic-specializer] Avoid unlimited generic specialization of very deeply nested bound generic types
2 parents 7f2ae6c + 4109f87 commit 9049d6e

File tree

2 files changed

+70
-0
lines changed

2 files changed

+70
-0
lines changed

lib/SILOptimizer/Utils/Generics.cpp

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,29 @@
1919

2020
using namespace swift;
2121

22+
// Max depth of a bound generic which can be processed by the generic
23+
// specializer.
24+
// E.g. the depth of Array<Array<Array<T>>> is 3.
25+
// No specializations will be produced, if any of generic parameters contains
26+
// a bound generic type with the depth higher than this threshold
27+
static const unsigned BoundGenericDepthThreshold = 50;
28+
29+
static unsigned getBoundGenericDepth(Type t) {
30+
unsigned Depth = 0;
31+
if (auto BGT = t->getAs<BoundGenericType>()) {
32+
Depth++;
33+
auto GenericArgs = BGT->getGenericArgs();
34+
unsigned MaxGenericArgDepth = 0;
35+
for (auto GenericArg : GenericArgs) {
36+
auto ArgDepth = getBoundGenericDepth(GenericArg);
37+
if (ArgDepth > MaxGenericArgDepth)
38+
MaxGenericArgDepth = ArgDepth;
39+
}
40+
Depth += MaxGenericArgDepth;
41+
}
42+
return Depth;
43+
}
44+
2245
// =============================================================================
2346
// ReabstractionInfo
2447
// =============================================================================
@@ -50,6 +73,19 @@ ReabstractionInfo::ReabstractionInfo(SILFunction *OrigF,
5073
DEBUG(llvm::dbgs() << " Cannot specialize with dynamic self.\n");
5174
return;
5275
}
76+
77+
// Check if the substitution contains any generic types that are too deep.
78+
// If this is the case, bail to avoid the explosion in the number of
79+
// generated specializations.
80+
for (auto Sub : ParamSubs) {
81+
auto Replacement = Sub.getReplacement();
82+
if (Replacement.findIf([](Type ty) -> bool {
83+
return getBoundGenericDepth(ty) >= BoundGenericDepthThreshold;
84+
})) {
85+
return;
86+
}
87+
}
88+
5389
SILModule &M = OrigF->getModule();
5490
Module *SM = M.getSwiftModule();
5591

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// RUN: %target-swift-frontend -O -emit-sil %s | FileCheck %s
2+
3+
// Check that this Church Numerals inspired example does not hang
4+
// a compiler in the generic specializer.
5+
//
6+
// rdar://problem/21260480
7+
8+
protocol Nat {
9+
init()
10+
// static stored properties are not supported in generic structs.
11+
var val : Int32 {get}
12+
}
13+
14+
struct Zero : Nat { var val : Int32 = 0 }
15+
16+
struct PlusOne<X : Nat> : Nat {
17+
var val : Int32 = X().val + 1
18+
}
19+
20+
// Compiler used to keep performing the generic specialization of
21+
// computeNat for increasingly deeply nested bound generic types
22+
// like PlusOne<PlusOne<....<PlusOne<Zero>>>
23+
func computeNat<T: Nat>(_ v : Int32, _ t: T) -> Int32 {
24+
if v == 0 {
25+
return t.val
26+
}
27+
return computeNat(v - 1, PlusOne<T>())
28+
}
29+
30+
// CHECK-LABEL: sil @_TF24specialize_deep_generics14testComputeNatFT_Vs5Int32
31+
public func testComputeNat() -> Int32 {
32+
return computeNat(8, Zero())
33+
}
34+

0 commit comments

Comments
 (0)