@@ -6610,6 +6610,99 @@ GenTree* Lowering::LowerSelCC(GenTreeOpCC* selcc)
66106610 GenTree* falseOp = selcc->gtGetOp1 ();
66116611 GenTree* trueOp = selcc->gtGetOp2 ();
66126612
6613+ if (falseOp->OperIs (GT_CNS_INT) && trueOp->OperIs (GT_CNS_INT))
6614+ {
6615+ //
6616+ // SELCC(c1, c2) can sometimes be replaced with SETCC which avoids the need for 2 registers
6617+ // to load the constants:
6618+ // - SELCC(0, 1) -> SETCC
6619+ // - SELCC(0, -1) -> NEG(SETCC)
6620+ // - SELCC(3, 4) -> SETCC + 3
6621+ // - SELCC(0, 2) -> RSH(SETCC, 1)
6622+ //
6623+
6624+ var_types type = genActualType (selcc->TypeGet ());
6625+ GenCondition condition = selcc->gtCondition ;
6626+ size_t falseValue = static_cast <size_t >(falseOp->AsIntCon ()->IconValue ());
6627+ size_t trueValue = static_cast <size_t >(trueOp->AsIntCon ()->IconValue ());
6628+
6629+ if (falseValue > trueValue)
6630+ {
6631+ std::swap (falseValue, trueValue);
6632+ condition.Reverse ();
6633+ }
6634+
6635+ LIR::Use use;
6636+ bool isUsed = BlockRange ().TryGetUse (selcc, &use);
6637+ GenTree* result = nullptr ;
6638+
6639+ if ((falseValue == 0 ) && (trueValue == SIZE_T_MAX))
6640+ {
6641+ result = comp->gtNewOperNode (GT_NEG, type, selcc);
6642+ BlockRange ().InsertAfter (selcc, result);
6643+ }
6644+ else
6645+ {
6646+ size_t zeroOffset = 0 ;
6647+
6648+ if (falseValue != 0 )
6649+ {
6650+ zeroOffset = falseValue;
6651+ falseValue = 0 ;
6652+ trueValue -= zeroOffset;
6653+ }
6654+
6655+ if (isPow2 (trueValue) && ((zeroOffset == 0 ) || (genLog2 (trueValue) <= 3 )))
6656+ {
6657+ if (zeroOffset > 0 )
6658+ {
6659+ if (trueValue == 1 )
6660+ {
6661+ GenTree* offset = comp->gtNewIconNode (zeroOffset, type);
6662+ result = comp->gtNewOperNode (GT_ADD, type, selcc, offset);
6663+ BlockRange ().InsertAfter (selcc, offset, result);
6664+ }
6665+ else
6666+ {
6667+ result =
6668+ new (comp, GT_LEA) GenTreeAddrMode (type, nullptr , selcc, static_cast <unsigned >(trueValue),
6669+ static_cast <unsigned >(zeroOffset));
6670+ BlockRange ().InsertAfter (selcc, result);
6671+ }
6672+ }
6673+ else if (trueValue > 1 )
6674+ {
6675+ GenTree* shiftBy = comp->gtNewIconNode (genLog2 (trueValue), type);
6676+ result = comp->gtNewOperNode (GT_LSH, type, selcc, shiftBy);
6677+ BlockRange ().InsertAfter (selcc, shiftBy, result);
6678+ }
6679+ else
6680+ {
6681+ result = selcc;
6682+ }
6683+ }
6684+ }
6685+
6686+ if (result != nullptr )
6687+ {
6688+ selcc->ChangeOper (GT_SETCC);
6689+
6690+ GenTreeCC* setcc = selcc->AsCC ();
6691+ setcc->gtType = type;
6692+ setcc->gtCondition = condition;
6693+
6694+ BlockRange ().Remove (falseOp);
6695+ BlockRange ().Remove (trueOp);
6696+
6697+ if (isUsed && (result != selcc))
6698+ {
6699+ use.ReplaceWith (comp, result);
6700+ }
6701+
6702+ return selcc->gtNext ;
6703+ }
6704+ }
6705+
66136706 // Put constants in the second operand, this appears to improve register allocation.
66146707
66156708 if (falseOp->IsIntegralConst () && !trueOp->IsIntegralConst ())
0 commit comments