@@ -34,27 +34,134 @@ llvm::cl::opt<bool> SpecializeGenericSubstitutions(
34
34
llvm::cl::init (false ),
35
35
llvm::cl::desc(" Enable partial specialization with generic substitutions" ));
36
36
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
38
38
// specializer.
39
39
// E.g. the depth of Array<Array<Array<T>>> is 3.
40
40
// 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) {
45
53
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
+ }
47
61
Depth++;
62
+ unsigned MaxTypeDepth = 0 ;
48
63
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;
54
105
}
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);
56
145
}
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;
58
165
}
59
166
60
167
// =============================================================================
@@ -116,9 +223,7 @@ bool ReabstractionInfo::prepareAndCheck(ApplySite Apply, SILFunction *Callee,
116
223
// generated specializations.
117
224
for (auto Sub : ParamSubs) {
118
225
auto Replacement = Sub.getReplacement ();
119
- if (Replacement.findIf ([](Type ty) -> bool {
120
- return getBoundGenericDepth (ty) >= BoundGenericDepthThreshold;
121
- })) {
226
+ if (isTypeTooComplex (Replacement)) {
122
227
DEBUG (llvm::dbgs ()
123
228
<< " Cannot specialize because the generic type is too deep.\n " );
124
229
return false ;
0 commit comments