op2->gtType = op1Type;
}
}
+ else if ((op1->OperGet() == GT_CAST) && !op1->gtOverflow())
+ {
+ GenTreeCast* cast = op1->AsCast();
+ var_types castToType = cast->CastToType();
+ GenTree* castOp = cast->gtGetOp1();
+
+ if (((castToType == TYP_BOOL) || (castToType == TYP_UBYTE)) && FitsIn<UINT8>(op2Value))
+ {
+ bool canNarrow = ((castOp->OperGet() == GT_CNS_INT) || (castOp->OperGet() == GT_CALL) ||
+ (castOp->OperGet() == GT_LCL_VAR) || castOp->OperIsLogical() || castOp->isMemoryOp());
+
+ if (canNarrow)
+ {
+ assert(!castOp->gtOverflowEx()); // Must not be an overflow checking operation
+
+ castOp->gtType = castToType;
+
+ if (castOp->IsIntegralConst())
+ {
+ castOp->AsIntCon()->SetIconValue(castOp->AsIntCon()->IconValue() & 255);
+ }
+
+ cmp->gtOp.gtOp1 = castOp;
+ cmp->gtFlags |= GTF_UNSIGNED;
+ op2->gtType = castToType;
+
+ BlockRange().Remove(cast);
+ }
+ }
+ }
}
#endif // _TARGET_XARCH_
}
}
}
- else if (op1->OperGet() == GT_CAST)
- {
- // If the op1 is a cast operation, and cast type is one byte sized unsigned type,
- // we can directly use the number in register, instead of doing an extra cast step.
- var_types dstType = op1->CastToType();
- bool isUnsignedDst = varTypeIsUnsigned(dstType);
- emitAttr castSize = EA_ATTR(genTypeSize(dstType));
- GenTreePtr castOp1 = op1->gtOp.gtOp1;
- genTreeOps castOp1Oper = castOp1->OperGet();
- bool safeOper = false;
-
- // It is not always safe to change the gtType of 'castOp1' to TYP_UBYTE.
- // For example when 'castOp1Oper' is a GT_RSZ or GT_RSH then we are shifting
- // bits from the left into the lower bits. If we change the type to a TYP_UBYTE
- // we will instead generate a byte sized shift operation: shr al, 24
- // For the following ALU operations is it safe to change the gtType to the
- // smaller type:
- //
- if ((castOp1Oper == GT_CNS_INT) || (castOp1Oper == GT_CALL) || // the return value from a Call
- (castOp1Oper == GT_LCL_VAR) || castOp1->OperIsLogical() || // GT_AND, GT_OR, GT_XOR
- castOp1->isMemoryOp()) // isIndir() || isLclField();
- {
- safeOper = true;
- }
-
- if ((castSize == EA_1BYTE) && isUnsignedDst && // Unsigned cast to TYP_UBYTE
- safeOper && // Must be a safe operation
- !op1->gtOverflow()) // Must not be an overflow checking cast
- {
- // Currently all of the Oper accepted as 'safeOper' are
- // non-overflow checking operations. If we were to add
- // an overflow checking operation then this assert needs
- // to be moved above to guard entry to this block.
- //
- assert(!castOp1->gtOverflowEx()); // Must not be an overflow checking operation
-
- // TODO-Cleanup: we're within "if (CheckImmedAndMakeContained(tree, op2))", so isn't
- // the following condition always true?
- if (op2->isContainedIntOrIImmed())
- {
- ssize_t val = (ssize_t)op2->AsIntConCommon()->IconValue();
- if (val >= 0 && val <= 255)
- {
- GenTreePtr removeTreeNode = op1;
- tree->gtOp.gtOp1 = castOp1;
- op1 = castOp1;
- castOp1->gtType = TYP_UBYTE;
-
- // trim down the value if castOp1 is an int constant since its type changed to UBYTE.
- if (castOp1Oper == GT_CNS_INT)
- {
- castOp1->gtIntCon.gtIconVal = (UINT8)castOp1->gtIntCon.gtIconVal;
- }
-
- op2->gtType = TYP_UBYTE;
- tree->gtFlags |= GTF_UNSIGNED;
-
- // right now the op1's type is the same as op2's type.
- // if op1 is MemoryOp, we should make the op1 as contained node.
- if (castOp1->isMemoryOp())
- {
- MakeSrcContained(tree, op1);
- op1IsMadeContained = true;
- }
-
- BlockRange().Remove(removeTreeNode);
-
- // We've changed the type on op1 to TYP_UBYTE, but we already processed that node.
- // We need to go back and mark it byteable.
- // TODO-Cleanup: it might be better to move this out of the TreeNodeInfoInit pass to
- // the earlier "lower" pass, in which case the byteable check would just fall out.
- // But that is quite complex!
- TreeNodeInfoInitCheckByteable(op1);
-
-#ifdef DEBUG
- if (comp->verbose)
- {
- printf("TreeNodeInfoInitCmp: Removing a GT_CAST to TYP_UBYTE and changing "
- "castOp1->gtType to TYP_UBYTE\n");
- comp->gtDispTreeRange(BlockRange(), tree);
- }
-#endif
- }
- }
- }
- }
// If not made contained, op1 can be marked as reg-optional.
if (!op1IsMadeContained)