diff --git a/src/coreclr/jit/switchrecognition.cpp b/src/coreclr/jit/switchrecognition.cpp index dcfb57cabf4e2..b0d2fe9455230 100644 --- a/src/coreclr/jit/switchrecognition.cpp +++ b/src/coreclr/jit/switchrecognition.cpp @@ -50,17 +50,19 @@ PhaseStatus Compiler::optSwitchRecognition() // constant test? e.g. JTRUE(EQ/NE(X, CNS)). // // Arguments: -// block - The block to check -// trueEdge - [out] The successor edge taken if X == CNS -// falseEdge - [out] The successor edge taken if X != CNS -// isReversed - [out] True if the condition is reversed (GT_NE) -// variableNode - [out] The variable node (X in the example above) -// cns - [out] The constant value (CNS in the example above) +// block - The block to check +// allowSideEffects - is variableNode allowed to have side-effects (COMMA)? +// trueEdge - [out] The successor edge taken if X == CNS +// falseEdge - [out] The successor edge taken if X != CNS +// isReversed - [out] True if the condition is reversed (GT_NE) +// variableNode - [out] The variable node (X in the example above) +// cns - [out] The constant value (CNS in the example above) // // Return Value: // True if the block represents a constant test, false otherwise // bool IsConstantTestCondBlock(const BasicBlock* block, + bool allowSideEffects, BasicBlock** trueTarget, BasicBlock** falseTarget, bool* isReversed, @@ -88,8 +90,14 @@ bool IsConstantTestCondBlock(const BasicBlock* block, // We're looking for "X EQ/NE CNS" or "CNS EQ/NE X" pattern if ((op1->IsCnsIntOrI() && !op1->IsIconHandle()) ^ (op2->IsCnsIntOrI() && !op2->IsIconHandle())) { - // TODO: relax this to support any side-effect free expression - if (!op1->OperIs(GT_LCL_VAR) && !op2->OperIs(GT_LCL_VAR)) + if (allowSideEffects) + { + if (!op1->gtEffectiveVal()->OperIs(GT_LCL_VAR) && !op2->gtEffectiveVal()->OperIs(GT_LCL_VAR)) + { + return false; + } + } + else if (!op1->OperIs(GT_LCL_VAR) && !op2->OperIs(GT_LCL_VAR)) { return false; } @@ -148,7 +156,7 @@ bool Compiler::optSwitchDetectAndConvert(BasicBlock* firstBlock) // and then try to accumulate as many constant test blocks as possible. Once we hit // a block that doesn't match the pattern, we start processing the accumulated blocks. bool isReversed = false; - if (IsConstantTestCondBlock(firstBlock, &trueTarget, &falseTarget, &isReversed, &variableNode, &cns)) + if (IsConstantTestCondBlock(firstBlock, true, &trueTarget, &falseTarget, &isReversed, &variableNode, &cns)) { if (isReversed) { @@ -185,8 +193,8 @@ bool Compiler::optSwitchDetectAndConvert(BasicBlock* firstBlock) } // Inspect secondary blocks - if (IsConstantTestCondBlock(currBb, &currTrueTarget, &currFalseTarget, &isReversed, &currVariableNode, - &currCns)) + if (IsConstantTestCondBlock(currBb, false, &currTrueTarget, &currFalseTarget, &isReversed, + &currVariableNode, &currCns)) { if (currTrueTarget != trueTarget) { @@ -194,7 +202,7 @@ bool Compiler::optSwitchDetectAndConvert(BasicBlock* firstBlock) return optSwitchConvert(firstBlock, testValueIndex, testValues, falseLikelihood, variableNode); } - if (!GenTree::Compare(currVariableNode, variableNode)) + if (!GenTree::Compare(currVariableNode, variableNode->gtEffectiveVal())) { // A different variable node is used, stop searching and process what we already have. return optSwitchConvert(firstBlock, testValueIndex, testValues, falseLikelihood, variableNode); @@ -324,7 +332,7 @@ bool Compiler::optSwitchConvert( BasicBlock* blockIfTrue = nullptr; BasicBlock* blockIfFalse = nullptr; bool isReversed = false; - const bool isTest = IsConstantTestCondBlock(lastBlock, &blockIfTrue, &blockIfFalse, &isReversed); + const bool isTest = IsConstantTestCondBlock(lastBlock, false, &blockIfTrue, &blockIfFalse, &isReversed); assert(isTest); assert(firstBlock->TrueTargetIs(blockIfTrue)); @@ -337,7 +345,7 @@ bool Compiler::optSwitchConvert( firstBlock->lastStmt()->GetRootNode()->ChangeOper(GT_SWITCH); // The root node is now SUB(nodeToTest, minValue) if minValue != 0 - GenTree* switchValue = gtCloneExpr(nodeToTest); + GenTree* switchValue = nodeToTest; if (minValue != 0) { switchValue =