@@ -131,120 +131,21 @@ bool IsConstantTestCondBlock(const BasicBlock* block,
131131 return false ;
132132}
133133
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-
236134// ------------------------------------------------------------------------------
237135// optSwitchDetectAndConvert : Try to detect a series of conditional blocks which
238136// can be converted into a switch (jump-table) construct. See optSwitchConvert
239137// for more details.
240138//
241139// Arguments:
242140// 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.
243144//
244145// Return Value:
245146// True if the conversion was successful, false otherwise
246147//
247- bool Compiler::optSwitchDetectAndConvert (BasicBlock* firstBlock)
148+ bool Compiler::optSwitchDetectAndConvert (BasicBlock* firstBlock, bool testingForConversion )
248149{
249150 assert (firstBlock->KindIs (BBJ_COND));
250151
@@ -289,7 +190,8 @@ bool Compiler::optSwitchDetectAndConvert(BasicBlock* firstBlock)
289190 {
290191 // Only the first conditional block can have multiple statements.
291192 // 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);
293195 }
294196
295197 // Inspect secondary blocks
@@ -299,25 +201,29 @@ bool Compiler::optSwitchDetectAndConvert(BasicBlock* firstBlock)
299201 if (currTrueTarget != trueTarget)
300202 {
301203 // 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);
303206 }
304207
305208 if (!GenTree::Compare (currVariableNode, variableNode->gtEffectiveVal ()))
306209 {
307210 // 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);
309213 }
310214
311215 if (currBb->GetUniquePred (this ) != prevBlock)
312216 {
313217 // 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);
315220 }
316221
317222 if (!BasicBlock::sameEHRegion (prevBlock, currBb))
318223 {
319224 // 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);
321227 }
322228
323229 // Ok we can work with that, add the test value to the list
@@ -327,21 +233,27 @@ bool Compiler::optSwitchDetectAndConvert(BasicBlock* firstBlock)
327233 if (testValueIndex == SWITCH_MAX_DISTANCE)
328234 {
329235 // 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);
331238 }
332239
333240 if (isReversed)
334241 {
335242 // 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);
337245 }
338246
247+ if (testingForConversion)
248+ return true ;
249+
339250 prevBlock = currBb;
340251 }
341252 else
342253 {
343254 // 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);
345257 }
346258 }
347259 }
0 commit comments