@@ -131,120 +131,21 @@ bool IsConstantTestCondBlock(const BasicBlock* block,
131
131
return false ;
132
132
}
133
133
134
- #if defined(TARGET_AMD64)
135
- // ------------------------------------------------------------------------------
136
- // optSwitchDetectLikely : Return true if it is likely this block chain
137
- // can be converted into a switch at a later optimization pass
138
- //
139
- // Arguments:
140
- // firstBlock - A block to start the search from
141
- //
142
- // Return Value:
143
- // True if the conversion was successful, false otherwise
144
- //
145
- bool Compiler::optSwitchDetectLikely (BasicBlock* firstBlock)
146
- {
147
- assert (firstBlock->KindIs (BBJ_COND));
148
-
149
- GenTree* variableNode = nullptr ;
150
- ssize_t cns = 0 ;
151
- BasicBlock* trueTarget = nullptr ;
152
- BasicBlock* falseTarget = nullptr ;
153
-
154
- // The algorithm is simple - we check that the given block is a constant test block
155
- // and then try to accumulate as many constant test blocks as possible. Once we hit
156
- // a block that doesn't match the pattern, we start processing the accumulated blocks.
157
- bool isReversed = false ;
158
- if (IsConstantTestCondBlock (firstBlock, true , &trueTarget, &falseTarget, &isReversed, &variableNode, &cns))
159
- {
160
- if (isReversed)
161
- {
162
- // First block uses NE - we don't support this yet. We currently expect all blocks to use EQ
163
- // and allow NE for the last one (because it's what Roslyn usually emits).
164
- // TODO: make it more flexible and support cases like "x != cns1 && x != cns2 && ..."
165
- return false ;
166
- }
167
-
168
- // No more than SWITCH_MAX_TABLE_SIZE blocks are allowed (arbitrary limit in this context)
169
- int testValueIndex = 0 ;
170
- ssize_t testValues[SWITCH_MAX_DISTANCE] = {};
171
- testValues[testValueIndex] = cns;
172
- testValueIndex++;
173
-
174
- // Track likelihood of reaching the false block
175
- //
176
- weight_t falseLikelihood = firstBlock->GetFalseEdge ()->getLikelihood ();
177
- const BasicBlock* prevBlock = firstBlock;
178
-
179
- // Follow the same algorithm as below but only peek to the next block
180
- const BasicBlock* currBb = firstBlock->Next ();
181
- if (currBb != nullptr )
182
- {
183
- GenTree* currVariableNode = nullptr ;
184
- ssize_t currCns = 0 ;
185
- BasicBlock* currTrueTarget = nullptr ;
186
- BasicBlock* currFalseTarget = nullptr ;
187
-
188
- if (!currBb->hasSingleStmt ())
189
- {
190
- // Only the first conditional block can have multiple statements.
191
- // Stop searching and process what we already have.
192
- return false ;
193
- }
194
-
195
- // Inspect secondary blocks
196
- if (IsConstantTestCondBlock (currBb, false , &currTrueTarget, &currFalseTarget, &isReversed,
197
- &currVariableNode, &currCns))
198
- {
199
- if (currTrueTarget != trueTarget)
200
- {
201
- // This blocks jumps to a different target, stop searching and process what we already have.
202
- return false ;
203
- }
204
-
205
- if (!GenTree::Compare (currVariableNode, variableNode->gtEffectiveVal ()))
206
- {
207
- // A different variable node is used, stop searching and process what we already have.
208
- return false ;
209
- }
210
-
211
- if (currBb->GetUniquePred (this ) != prevBlock)
212
- {
213
- return false ;
214
- }
215
-
216
- if (!BasicBlock::sameEHRegion (prevBlock, currBb))
217
- {
218
- // Current block is in a different EH region, stop searching and process what we already have.
219
- return false ;
220
- }
221
-
222
- return true ;
223
- }
224
- else
225
- {
226
- // Current block is not a suitable test, stop searching and process what we already have.
227
- return false ;
228
- }
229
- }
230
- }
231
-
232
- return false ;
233
- }
234
- #endif
235
-
236
134
// ------------------------------------------------------------------------------
237
135
// optSwitchDetectAndConvert : Try to detect a series of conditional blocks which
238
136
// can be converted into a switch (jump-table) construct. See optSwitchConvert
239
137
// for more details.
240
138
//
241
139
// Arguments:
242
140
// firstBlock - A block to start the search from
141
+ // testingForConversion - Test if its likely a switch conversion will happen.
142
+ // Used to prevent a pessimization when optimizing for conditional chaining.
143
+ // Done in this function to prevent maintaining the check in two places.
243
144
//
244
145
// Return Value:
245
146
// True if the conversion was successful, false otherwise
246
147
//
247
- bool Compiler::optSwitchDetectAndConvert (BasicBlock* firstBlock)
148
+ bool Compiler::optSwitchDetectAndConvert (BasicBlock* firstBlock, bool testingForConversion )
248
149
{
249
150
assert (firstBlock->KindIs (BBJ_COND));
250
151
@@ -289,7 +190,8 @@ bool Compiler::optSwitchDetectAndConvert(BasicBlock* firstBlock)
289
190
{
290
191
// Only the first conditional block can have multiple statements.
291
192
// Stop searching and process what we already have.
292
- return optSwitchConvert (firstBlock, testValueIndex, testValues, falseLikelihood, variableNode);
193
+ return !testingForConversion &&
194
+ optSwitchConvert (firstBlock, testValueIndex, testValues, falseLikelihood, variableNode);
293
195
}
294
196
295
197
// Inspect secondary blocks
@@ -299,25 +201,29 @@ bool Compiler::optSwitchDetectAndConvert(BasicBlock* firstBlock)
299
201
if (currTrueTarget != trueTarget)
300
202
{
301
203
// This blocks jumps to a different target, stop searching and process what we already have.
302
- return optSwitchConvert (firstBlock, testValueIndex, testValues, falseLikelihood, variableNode);
204
+ return !testingForConversion &&
205
+ optSwitchConvert (firstBlock, testValueIndex, testValues, falseLikelihood, variableNode);
303
206
}
304
207
305
208
if (!GenTree::Compare (currVariableNode, variableNode->gtEffectiveVal ()))
306
209
{
307
210
// A different variable node is used, stop searching and process what we already have.
308
- return optSwitchConvert (firstBlock, testValueIndex, testValues, falseLikelihood, variableNode);
211
+ return !testingForConversion &&
212
+ optSwitchConvert (firstBlock, testValueIndex, testValues, falseLikelihood, variableNode);
309
213
}
310
214
311
215
if (currBb->GetUniquePred (this ) != prevBlock)
312
216
{
313
217
// Multiple preds in a secondary block, stop searching and process what we already have.
314
- return optSwitchConvert (firstBlock, testValueIndex, testValues, falseLikelihood, variableNode);
218
+ return !testingForConversion &&
219
+ optSwitchConvert (firstBlock, testValueIndex, testValues, falseLikelihood, variableNode);
315
220
}
316
221
317
222
if (!BasicBlock::sameEHRegion (prevBlock, currBb))
318
223
{
319
224
// Current block is in a different EH region, stop searching and process what we already have.
320
- return optSwitchConvert (firstBlock, testValueIndex, testValues, falseLikelihood, variableNode);
225
+ return !testingForConversion &&
226
+ optSwitchConvert (firstBlock, testValueIndex, testValues, falseLikelihood, variableNode);
321
227
}
322
228
323
229
// Ok we can work with that, add the test value to the list
@@ -327,21 +233,27 @@ bool Compiler::optSwitchDetectAndConvert(BasicBlock* firstBlock)
327
233
if (testValueIndex == SWITCH_MAX_DISTANCE)
328
234
{
329
235
// Too many suitable tests found - stop and process what we already have.
330
- return optSwitchConvert (firstBlock, testValueIndex, testValues, falseLikelihood, variableNode);
236
+ return !testingForConversion &&
237
+ optSwitchConvert (firstBlock, testValueIndex, testValues, falseLikelihood, variableNode);
331
238
}
332
239
333
240
if (isReversed)
334
241
{
335
242
// We only support reversed test (GT_NE) for the last block.
336
- return optSwitchConvert (firstBlock, testValueIndex, testValues, falseLikelihood, variableNode);
243
+ return !testingForConversion &&
244
+ optSwitchConvert (firstBlock, testValueIndex, testValues, falseLikelihood, variableNode);
337
245
}
338
246
247
+ if (testingForConversion)
248
+ return true ;
249
+
339
250
prevBlock = currBb;
340
251
}
341
252
else
342
253
{
343
254
// Current block is not a suitable test, stop searching and process what we already have.
344
- return optSwitchConvert (firstBlock, testValueIndex, testValues, falseLikelihood, variableNode);
255
+ return !testingForConversion &&
256
+ optSwitchConvert (firstBlock, testValueIndex, testValues, falseLikelihood, variableNode);
345
257
}
346
258
}
347
259
}
0 commit comments