summaryrefslogtreecommitdiff
path: root/src/jit/codegenlinear.cpp
diff options
context:
space:
mode:
authorMike Danes <onemihaid@hotmail.com>2018-08-07 22:16:51 +0300
committerMike Danes <onemihaid@hotmail.com>2018-09-06 18:55:00 +0300
commit38a5f91a3e11ecf4d7441a5ce05bb94b6edaf9c3 (patch)
treef374c5173bf0ccee6499abfd850c69e19f55df10 /src/jit/codegenlinear.cpp
parent43c5f23bf1b3d697ebe7178c612717a194cffdfe (diff)
downloadcoreclr-38a5f91a3e11ecf4d7441a5ce05bb94b6edaf9c3.tar.gz
coreclr-38a5f91a3e11ecf4d7441a5ce05bb94b6edaf9c3.tar.bz2
coreclr-38a5f91a3e11ecf4d7441a5ce05bb94b6edaf9c3.zip
Make cast classification arch independent
Diffstat (limited to 'src/jit/codegenlinear.cpp')
-rw-r--r--src/jit/codegenlinear.cpp118
1 files changed, 118 insertions, 0 deletions
diff --git a/src/jit/codegenlinear.cpp b/src/jit/codegenlinear.cpp
index bf229305c6..4d9fe4eb55 100644
--- a/src/jit/codegenlinear.cpp
+++ b/src/jit/codegenlinear.cpp
@@ -1948,6 +1948,124 @@ void CodeGen::genCodeForCast(GenTreeOp* tree)
// The per-case functions call genProduceReg()
}
+CodeGen::GenIntCastDesc::GenIntCastDesc(GenTreeCast* cast)
+{
+ const var_types srcType = genActualType(cast->gtGetOp1()->TypeGet());
+ const bool srcUnsigned = cast->IsUnsigned();
+ const unsigned srcSize = genTypeSize(srcType);
+ const var_types castType = cast->gtCastType;
+ const bool castUnsigned = varTypeIsUnsigned(castType);
+ const unsigned castSize = genTypeSize(castType);
+ const var_types dstType = genActualType(cast->TypeGet());
+ const unsigned dstSize = genTypeSize(dstType);
+ const bool overflow = cast->gtOverflow();
+
+ assert((srcSize == 4) || (srcSize == genTypeSize(TYP_I_IMPL)));
+ assert((dstSize == 4) || (dstSize == genTypeSize(TYP_I_IMPL)));
+
+ assert(dstSize == genTypeSize(genActualType(castType)));
+
+ if (castSize < 4) // Cast to small int type
+ {
+ if (overflow)
+ {
+ m_checkKind = CHECK_SMALL_INT_RANGE;
+ m_checkSrcSize = srcSize;
+ // Since these are small int types we can compute the min and max
+ // values of the castType without risk of integer overflow.
+ const int castNumBits = (castSize * 8) - (castUnsigned ? 0 : 1);
+ m_checkSmallIntMax = (1 << castNumBits) - 1;
+ m_checkSmallIntMin = (castUnsigned | srcUnsigned) ? 0 : (-m_checkSmallIntMax - 1);
+
+ m_extendKind = COPY;
+ m_extendSrcSize = dstSize;
+ }
+ else
+ {
+ m_checkKind = CHECK_NONE;
+
+ // Casting to a small type really means widening from that small type to INT/LONG.
+ m_extendKind = castUnsigned ? ZERO_EXTEND_SMALL_INT : SIGN_EXTEND_SMALL_INT;
+ m_extendSrcSize = castSize;
+ }
+ }
+#ifdef _TARGET_64BIT_
+ // castType cannot be (U)LONG on 32 bit targets, such casts should have been decomposed.
+ // srcType cannot be a small int type since it's the "actual type" of the cast operand.
+ // This means that widening casts do not occur on 32 bit targets.
+ else if (castSize > srcSize) // (U)INT to (U)LONG widening cast
+ {
+ assert((srcSize == 4) && (castSize == 8));
+
+ if (overflow && !srcUnsigned && castUnsigned)
+ {
+ // Widening from INT to ULONG, check if the value is positive
+ m_checkKind = CHECK_POSITIVE;
+ m_checkSrcSize = 4;
+
+ // This is the only overflow checking cast that requires changing the
+ // source value (by zero extending), all others copy the value as is.
+ assert((srcType == TYP_INT) && (castType == TYP_ULONG));
+ m_extendKind = ZERO_EXTEND_INT;
+ m_extendSrcSize = 4;
+ }
+ else
+ {
+ m_checkKind = CHECK_NONE;
+
+ m_extendKind = srcUnsigned ? ZERO_EXTEND_INT : SIGN_EXTEND_INT;
+ m_extendSrcSize = 4;
+ }
+ }
+ else if (castSize < srcSize) // (U)LONG to (U)INT narrowing cast
+ {
+ assert((srcSize == 8) && (castSize == 4));
+
+ if (overflow)
+ {
+ if (castUnsigned) // (U)LONG to UINT cast
+ {
+ m_checkKind = CHECK_UINT_RANGE;
+ }
+ else if (srcUnsigned) // ULONG to INT cast
+ {
+ m_checkKind = CHECK_POSITIVE_INT_RANGE;
+ }
+ else // LONG to INT cast
+ {
+ m_checkKind = CHECK_INT_RANGE;
+ }
+
+ m_checkSrcSize = 8;
+ }
+ else
+ {
+ m_checkKind = CHECK_NONE;
+ }
+
+ m_extendKind = COPY;
+ m_extendSrcSize = 4;
+ }
+#endif
+ else // if (castSize == srcSize) // Sign changing or same type cast
+ {
+ assert(castSize == srcSize);
+
+ if (overflow && (srcUnsigned != castUnsigned))
+ {
+ m_checkKind = CHECK_POSITIVE;
+ m_checkSrcSize = srcSize;
+ }
+ else
+ {
+ m_checkKind = CHECK_NONE;
+ }
+
+ m_extendKind = COPY;
+ m_extendSrcSize = srcSize;
+ }
+}
+
#if !defined(_TARGET_64BIT_)
//------------------------------------------------------------------------
// genStoreLongLclVar: Generate code to store a non-enregistered long lclVar