//
void Lowering::LowerCompare(GenTree* cmp)
{
+#ifdef _TARGET_XARCH_
+ if (cmp->gtGetOp2()->IsIntegralConst())
+ {
+ GenTree* op1 = cmp->gtGetOp1();
+ var_types op1Type = op1->TypeGet();
+ GenTreeIntCon* op2 = cmp->gtGetOp2()->AsIntCon();
+ ssize_t op2Value = op2->IconValue();
+
+ if (op1->isMemoryOp() && varTypeIsSmallInt(op1Type))
+ {
+ //
+ // If op1's type is small then try to narrow op2 so it has the same type as op1.
+ // Small types are usually used by memory loads and if both compare operands have
+ // the same type then the memory load can be contained. In certain situations
+ // (e.g "cmp ubyte, 200") we also get a smaller instruction encoding.
+ //
+
+ if ((op1Type == TYP_UBYTE) && FitsIn<UINT8>(op2Value))
+ {
+ cmp->gtFlags |= GTF_UNSIGNED;
+ op2->gtType = op1Type;
+ }
+ else if ((op1Type == TYP_BYTE) && FitsIn<INT8>(op2Value))
+ {
+ op2->gtType = op1Type;
+ }
+ else if ((op1Type == TYP_CHAR) && FitsIn<UINT16>(op2Value))
+ {
+ cmp->gtFlags |= GTF_UNSIGNED;
+ op2->gtType = op1Type;
+ }
+ else if ((op1Type == TYP_SHORT) && FitsIn<INT16>(op2Value))
+ {
+ op2->gtType = op1Type;
+ }
+ }
+ }
+#endif // _TARGET_XARCH_
+
#ifndef _TARGET_64BIT_
if (cmp->gtGetOp1()->TypeGet() != TYP_LONG)
{
// we can treat the isMemoryOp as contained.
bool op1CanBeContained = (genTypeSize(op1Type) == genTypeSize(op2Type));
- // Do we have a short compare against a constant in op2
- //
- if (varTypeIsSmall(op1Type))
- {
- GenTreeIntCon* con = op2->AsIntCon();
- ssize_t ival = con->gtIconVal;
-
- bool isEqualityCompare = (tree->gtOper == GT_EQ || tree->gtOper == GT_NE);
- bool useTest = isEqualityCompare && (ival == 0);
-
- if (!useTest)
- {
- ssize_t lo = 0; // minimum imm value allowed for cmp reg,imm
- ssize_t hi = 0; // maximum imm value allowed for cmp reg,imm
- bool isUnsigned = false;
-
- switch (op1Type)
- {
- case TYP_BOOL:
- op1Type = TYP_UBYTE;
- __fallthrough;
- case TYP_UBYTE:
- lo = 0;
- hi = 0x7f;
- isUnsigned = true;
- break;
- case TYP_BYTE:
- lo = -0x80;
- hi = 0x7f;
- break;
- case TYP_CHAR:
- lo = 0;
- hi = 0x7fff;
- isUnsigned = true;
- break;
- case TYP_SHORT:
- lo = -0x8000;
- hi = 0x7fff;
- break;
- default:
- unreached();
- }
-
- if ((ival >= lo) && (ival <= hi))
- {
- // We can perform a small compare with the immediate 'ival'
- tree->gtFlags |= GTF_RELOP_SMALL;
- if (isUnsigned && !isEqualityCompare)
- {
- tree->gtFlags |= GTF_UNSIGNED;
- }
- // We can treat the isMemoryOp as "contained"
- op1CanBeContained = true;
- }
- }
- }
-
if (op1CanBeContained)
{
if (op1->isMemoryOp())