Skip to content

Commit 1d40ef7

Browse files
committed
Reduce duplication from optSwitchDetectLikely.
1 parent dadfedb commit 1d40ef7

File tree

4 files changed

+30
-121
lines changed

4 files changed

+30
-121
lines changed

src/coreclr/jit/compiler.h

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7176,10 +7176,7 @@ class Compiler
71767176
PhaseStatus optOptimizeBools();
71777177
PhaseStatus optSwitchRecognition();
71787178
bool optSwitchConvert(BasicBlock* firstBlock, int testsCount, ssize_t* testValues, weight_t falseLikelihood, GenTree* nodeToTest);
7179-
bool optSwitchDetectAndConvert(BasicBlock* firstBlock);
7180-
#if defined(TARGET_AMD64)
7181-
bool optSwitchDetectLikely(BasicBlock* firstBlock);
7182-
#endif
7179+
bool optSwitchDetectAndConvert(BasicBlock* firstBlock, bool testingForConversion = false);
71837180

71847181
PhaseStatus optInvertLoops(); // Invert loops so they're entered at top and tested at bottom.
71857182
PhaseStatus optOptimizeFlow(); // Simplify flow graph and do tail duplication

src/coreclr/jit/emitxarch.cpp

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4451,7 +4451,8 @@ inline unsigned emitter::insEncodeRegSIB(const instrDesc* id, regNumber reg, cod
44514451
}
44524452
else if (hasEvexPrefix(*code))
44534453
{
4454-
// Note that APX-EVEX use EVEX.X4 as the MSB of the INDEX register to address GPRs, and the original EVEX.V4 is used for VSIB addressing.
4454+
// Note that APX-EVEX use EVEX.X4 as the MSB of the INDEX register to address GPRs, and the original
4455+
// EVEX.V4 is used for VSIB addressing.
44554456
*code &= 0xFFFFFBFFFFFFFFFFULL; // EVEX.X4
44564457
}
44574458
else
@@ -15407,7 +15408,7 @@ BYTE* emitter::emitOutputSV(BYTE* dst, instrDesc* id, code_t code, CnsVal* addc)
1540715408
{
1540815409
code |= EXTENDED_EVEX_PP_BITS;
1540915410
}
15410-
#endif // TARGET_AMD64
15411+
#endif // TARGET_AMD64
1541115412
}
1541215413
FALLTHROUGH;
1541315414

@@ -17034,15 +17035,14 @@ BYTE* emitter::emitOutputRI(BYTE* dst, instrDesc* id)
1703417035
code = insCodeACC(ins);
1703517036
assert(code < 0x100);
1703617037

17037-
1703817038
// This is INS_mov and will not take VEX prefix
1703917039
assert(!TakesVexPrefix(ins));
17040-
17040+
1704117041
code = AddX86PrefixIfNeededAndNotPresent(id, code, size);
1704217042
code |= 0x08; // Set the 'w' bit
1704317043
unsigned regcode = insEncodeReg012(id, reg, size, &code);
1704417044
code |= regcode;
17045-
17045+
1704617046
if (TakesRexWPrefix(id))
1704717047
{
1704817048
code = AddRexWPrefix(id, code);

src/coreclr/jit/optimizebools.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1991,7 +1991,7 @@ PhaseStatus Compiler::optOptimizeBools()
19911991
// trigger or not
19921992
// else if ((compOpportunisticallyDependsOn(InstructionSet_APX) || JitConfig.JitEnableApxIfConv()) &&
19931993
// optBoolsDsc.optOptimizeCompareChainCondBlock())
1994-
else if (JitConfig.EnableApxConditionalChaining() && !optSwitchDetectLikely(b1) &&
1994+
else if (JitConfig.EnableApxConditionalChaining() && !optSwitchDetectAndConvert(b1, true) &&
19951995
optBoolsDsc.optOptimizeCompareChainCondBlock())
19961996
{
19971997
// The optimization will have merged b1 and b2. Retry the loop so that

src/coreclr/jit/switchrecognition.cpp

Lines changed: 23 additions & 111 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)