//
void CodeGen::genIntCastOverflowCheck(GenTreeCast* cast, regNumber reg)
{
+ assert(cast->IsOverflowCheckRequired());
+
const var_types srcType = genActualType(cast->gtGetOp1()->TypeGet());
const bool srcUnsigned = cast->IsUnsigned();
const unsigned srcSize = genTypeSize(srcType);
instruction ins = INS_none;
emitAttr insSize;
- Lowering::CastInfo castInfo;
- Lowering::getCastDescription(cast, &castInfo);
- if (castInfo.requiresOverflowCheck)
+ if (cast->IsOverflowCheckRequired())
{
genIntCastOverflowCheck(cast, srcReg);
//
void CodeGen::genIntCastOverflowCheck(GenTreeCast* cast, regNumber reg)
{
+ assert(cast->IsOverflowCheckRequired());
+
const var_types srcType = genActualType(cast->gtGetOp1()->TypeGet());
const bool srcUnsigned = cast->IsUnsigned();
const unsigned srcSize = genTypeSize(srcType);
// On x86 casts to (U)BYTE require that the source be in a byte register.
//
// TODO-XArch-CQ: Allow castOp to be a contained node without an assigned register.
-// TODO: refactor to use getCastDescription
//
void CodeGen::genIntToIntCast(GenTreeCast* cast)
{
instruction ins = INS_none;
emitAttr insSize;
- Lowering::CastInfo castInfo;
- Lowering::getCastDescription(cast, &castInfo);
- if (castInfo.requiresOverflowCheck)
+ if (cast->IsOverflowCheckRequired())
{
genIntCastOverflowCheck(cast, srcReg);
gtRsvdRegs &= ~tempRegMask;
return genRegNumFromMask(tempRegMask);
}
+
+//------------------------------------------------------------------------
+// IsOverflowCheckRequired: Check if this cast node requires an overflow check.
+//
+// Notes:
+// Unlike gtOverflow, this function returns true only for casts that actually
+// require an overflow check:
+// - narrowing casts (e.g. TYP_INT -> TYP_SHORT, TYP_LONG -> TYP_INT)
+// - sign changing casts (e.g. TYP_INT -> TYP_UINT, TYP_ULONG -> TYP_LONG)
+// - widening from signed to unsigned casts (only TYP_INT -> TYP_ULONG)
+//
+bool GenTreeCast::IsOverflowCheckRequired() const
+{
+ if (!gtOverflow())
+ {
+ return false;
+ }
+
+ const var_types srcType = genActualType(gtGetOp1()->TypeGet());
+ const bool srcUnsigned = IsUnsigned();
+ const unsigned srcSize = genTypeSize(srcType);
+ const var_types castType = gtCastType;
+ const bool castUnsigned = varTypeIsUnsigned(castType);
+ const unsigned castSize = genTypeSize(castType);
+
+ if (castSize > srcSize)
+ {
+ // Overflow check required for widening from signed to unsigned.
+ return !srcUnsigned && castUnsigned;
+ }
+
+ if (castSize == srcSize)
+ {
+ // Overflow check required for any sign changing cast.
+ return srcUnsigned != castUnsigned;
+ }
+
+ // Overflow check required for any narrowing cast.
+ return true;
+}
{
}
#endif
+
+ // Returns true for casts that require an overflow check.
+ bool IsOverflowCheckRequired() const;
};
// GT_BOX nodes are place markers for boxed values. The "real" tree
}
}
-/**
- * Get common information required to handle a cast instruction
- */
-void Lowering::getCastDescription(GenTree* treeNode, CastInfo* castInfo)
-{
- // Intialize castInfo
- memset(castInfo, 0, sizeof(*castInfo));
-
- GenTree* castOp = treeNode->gtCast.CastOp();
-
- var_types dstType = treeNode->CastToType();
- var_types srcType = genActualType(castOp->TypeGet());
-
- castInfo->unsignedDest = varTypeIsUnsigned(dstType);
- castInfo->unsignedSource = varTypeIsUnsigned(srcType);
-
- // If necessary, force the srcType to unsigned when the GT_UNSIGNED flag is set.
- if (!castInfo->unsignedSource && (treeNode->gtFlags & GTF_UNSIGNED) != 0)
- {
- srcType = genUnsignedType(srcType);
- castInfo->unsignedSource = true;
- }
-
- if (treeNode->gtOverflow() &&
- (genTypeSize(srcType) >= genTypeSize(dstType) || (srcType == TYP_INT && dstType == TYP_ULONG)))
- {
- castInfo->requiresOverflowCheck = true;
- }
-
- if (castInfo->requiresOverflowCheck)
- {
- ssize_t typeMin = 0;
- ssize_t typeMax = 0;
- ssize_t typeMask = 0;
- bool signCheckOnly = false;
-
- // Do we need to compare the value, or just check masks
- switch (dstType)
- {
- default:
- assert(!"unreachable: getCastDescription");
- break;
-
- case TYP_BYTE:
- typeMask = ssize_t((int)0xFFFFFF80);
- typeMin = SCHAR_MIN;
- typeMax = SCHAR_MAX;
- break;
-
- case TYP_UBYTE:
- typeMask = ssize_t((int)0xFFFFFF00L);
- break;
-
- case TYP_SHORT:
- typeMask = ssize_t((int)0xFFFF8000);
- typeMin = SHRT_MIN;
- typeMax = SHRT_MAX;
- break;
-
- case TYP_USHORT:
- typeMask = ssize_t((int)0xFFFF0000L);
- break;
-
- case TYP_INT:
- if (srcType == TYP_UINT)
- {
- signCheckOnly = true;
- }
- else
- {
-#ifdef _TARGET_64BIT_
- typeMask = 0xFFFFFFFF80000000LL;
-#else
- typeMask = 0x80000000;
-#endif
- typeMin = INT_MIN;
- typeMax = INT_MAX;
- }
- break;
-
- case TYP_UINT:
- if (srcType == TYP_INT)
- {
- signCheckOnly = true;
- }
- else
- {
-#ifdef _TARGET_64BIT_
- typeMask = 0xFFFFFFFF00000000LL;
-#else
- typeMask = 0x00000000;
-#endif
- }
- break;
-
- case TYP_LONG:
- signCheckOnly = true;
- break;
-
- case TYP_ULONG:
- signCheckOnly = true;
- break;
- }
-
- if (signCheckOnly)
- {
- castInfo->signCheckOnly = true;
- }
-
- castInfo->typeMax = typeMax;
- castInfo->typeMin = typeMin;
- castInfo->typeMask = typeMask;
- }
-}
-
//------------------------------------------------------------------------
// Containment Analysis
//------------------------------------------------------------------------
}
virtual void DoPhase() override;
- // If requiresOverflowCheck is false, all other values will be unset
- struct CastInfo
- {
- bool requiresOverflowCheck; // Will the cast require an overflow check
- bool unsignedSource; // Is the source unsigned
- bool unsignedDest; // is the dest unsigned
-
- // All other fields are only meaningful if requiresOverflowCheck is set.
-
- ssize_t typeMin; // Lowest storable value of the dest type
- ssize_t typeMax; // Highest storable value of the dest type
- ssize_t typeMask; // For converting from/to unsigned
- bool signCheckOnly; // For converting between unsigned/signed int
- };
-
- static void getCastDescription(GenTree* treeNode, CastInfo* castInfo);
-
// This variant of LowerRange is called from outside of the main Lowering pass,
// so it creates its own instance of Lowering to do so.
void LowerRange(BasicBlock* block, LIR::ReadOnlyRange& range)