@@ -6566,6 +6566,99 @@ GenTree* Lowering::LowerSelCC(GenTreeOpCC* selcc)
65666566 GenTree* falseOp = selcc->gtGetOp1 ();
65676567 GenTree* trueOp = selcc->gtGetOp2 ();
65686568
6569+ if (falseOp->OperIs (GT_CNS_INT) && trueOp->OperIs (GT_CNS_INT))
6570+ {
6571+ //
6572+ // SELCC(c1, c2) can sometimes be replaced with SETCC which avoids the need for 2 registers
6573+ // to load the constants:
6574+ // - SELCC(0, 1) -> SETCC
6575+ // - SELCC(0, -1) -> NEG(SETCC)
6576+ // - SELCC(3, 4) -> SETCC + 3
6577+ // - SELCC(0, 2) -> RSH(SETCC, 1)
6578+ //
6579+
6580+ var_types type = genActualType (selcc->TypeGet ());
6581+ GenCondition condition = selcc->gtCondition ;
6582+ size_t falseValue = static_cast <size_t >(falseOp->AsIntCon ()->IconValue ());
6583+ size_t trueValue = static_cast <size_t >(trueOp->AsIntCon ()->IconValue ());
6584+
6585+ if (falseValue > trueValue)
6586+ {
6587+ std::swap (falseValue, trueValue);
6588+ condition.Reverse ();
6589+ }
6590+
6591+ LIR::Use use;
6592+ bool isUsed = BlockRange ().TryGetUse (selcc, &use);
6593+ GenTree* result = nullptr ;
6594+
6595+ if ((falseValue == 0 ) && (trueValue == SIZE_T_MAX))
6596+ {
6597+ result = comp->gtNewOperNode (GT_NEG, type, selcc);
6598+ BlockRange ().InsertAfter (selcc, result);
6599+ }
6600+ else
6601+ {
6602+ size_t zeroOffset = 0 ;
6603+
6604+ if (falseValue != 0 )
6605+ {
6606+ zeroOffset = falseValue;
6607+ falseValue = 0 ;
6608+ trueValue -= zeroOffset;
6609+ }
6610+
6611+ if (isPow2 (trueValue) && ((zeroOffset == 0 ) || (genLog2 (trueValue) <= 3 )))
6612+ {
6613+ if (zeroOffset > 0 )
6614+ {
6615+ if (trueValue == 1 )
6616+ {
6617+ GenTree* offset = comp->gtNewIconNode (zeroOffset, type);
6618+ result = comp->gtNewOperNode (GT_ADD, type, selcc, offset);
6619+ BlockRange ().InsertAfter (selcc, offset, result);
6620+ }
6621+ else
6622+ {
6623+ result =
6624+ new (comp, GT_LEA) GenTreeAddrMode (type, nullptr , selcc, static_cast <unsigned >(trueValue),
6625+ static_cast <unsigned >(zeroOffset));
6626+ BlockRange ().InsertAfter (selcc, result);
6627+ }
6628+ }
6629+ else if (trueValue > 1 )
6630+ {
6631+ GenTree* shiftBy = comp->gtNewIconNode (genLog2 (trueValue), type);
6632+ result = comp->gtNewOperNode (GT_LSH, type, selcc, shiftBy);
6633+ BlockRange ().InsertAfter (selcc, shiftBy, result);
6634+ }
6635+ else
6636+ {
6637+ result = selcc;
6638+ }
6639+ }
6640+ }
6641+
6642+ if (result != nullptr )
6643+ {
6644+ selcc->ChangeOper (GT_SETCC);
6645+
6646+ GenTreeCC* setcc = selcc->AsCC ();
6647+ setcc->gtType = type;
6648+ setcc->gtCondition = condition;
6649+
6650+ BlockRange ().Remove (falseOp);
6651+ BlockRange ().Remove (trueOp);
6652+
6653+ if (isUsed && (result != selcc))
6654+ {
6655+ use.ReplaceWith (comp, result);
6656+ }
6657+
6658+ return selcc->gtNext ;
6659+ }
6660+ }
6661+
65696662 // Put constants in the second operand, this appears to improve register allocation.
65706663
65716664 if (falseOp->IsIntegralConst () && !trueOp->IsIntegralConst ())
0 commit comments