// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. /*****************************************************************************/ #ifndef _VARTYPE_H_ #define _VARTYPE_H_ /*****************************************************************************/ #include "error.h" enum var_types_classification { VTF_ANY = 0x0000, VTF_INT = 0x0001, VTF_UNS = 0x0002, // type is unsigned VTF_FLT = 0x0004, VTF_GCR = 0x0008, // type is GC ref VTF_BYR = 0x0010, // type is Byref VTF_I = 0x0020, // is machine sized VTF_S = 0x0040, // is a struct type }; enum var_types : BYTE { #define DEF_TP(tn, nm, jitType, verType, sz, sze, asze, st, al, tf, howUsed) TYP_##tn, #include "typelist.h" #undef DEF_TP TYP_COUNT, TYP_lastIntrins = TYP_DOUBLE }; /***************************************************************************** * C-style pointers are implemented as TYP_INT or TYP_LONG depending on the * platform */ #ifdef _TARGET_64BIT_ #define TYP_I_IMPL TYP_LONG #define TYP_U_IMPL TYP_ULONG #define TYPE_REF_IIM TYPE_REF_LNG #else #define TYP_I_IMPL TYP_INT #define TYP_U_IMPL TYP_UINT #define TYPE_REF_IIM TYPE_REF_INT #ifdef _PREFAST_ // We silence this in the 32-bit build because for portability, we like to have asserts like this: // assert(op2->gtType == TYP_INT || op2->gtType == TYP_I_IMPL); // This is obviously redundant for 32-bit builds, but we don't want to have ifdefs and different // asserts just for 64-bit builds, so for now just silence the assert #pragma warning(disable : 6287) // warning 6287: the left and right sub-expressions are identical #endif //_PREFAST_ #endif /*****************************************************************************/ const extern BYTE varTypeClassification[TYP_COUNT]; // make any class with a TypeGet member also have a function TypeGet() that does the same thing template inline var_types TypeGet(T* t) { return t->TypeGet(); } // make a TypeGet function which is the identity function for var_types // the point of this and the preceding template is now you can make template functions // that work on var_types as well as any object that exposes a TypeGet method. // such as all of these varTypeIs* functions inline var_types TypeGet(var_types v) { return v; } #ifdef FEATURE_SIMD template inline bool varTypeIsSIMD(T vt) { switch (TypeGet(vt)) { case TYP_SIMD8: case TYP_SIMD12: case TYP_SIMD16: case TYP_SIMD32: return true; default: return false; } } #else // FEATURE_SIMD // Always return false if FEATURE_SIMD is not enabled template inline bool varTypeIsSIMD(T vt) { return false; } #endif // !FEATURE_SIMD template inline bool varTypeIsIntegral(T vt) { return ((varTypeClassification[TypeGet(vt)] & (VTF_INT)) != 0); } template inline bool varTypeIsIntegralOrI(T vt) { return ((varTypeClassification[TypeGet(vt)] & (VTF_INT | VTF_I)) != 0); } template inline bool varTypeIsUnsigned(T vt) { return ((varTypeClassification[TypeGet(vt)] & (VTF_UNS)) != 0); } // If "vt" is an unsigned integral type, returns the corresponding signed integral type, otherwise // return "vt". inline var_types varTypeUnsignedToSigned(var_types vt) { if (varTypeIsUnsigned(vt)) { switch (vt) { case TYP_BOOL: case TYP_UBYTE: return TYP_BYTE; case TYP_USHORT: return TYP_SHORT; case TYP_UINT: return TYP_INT; case TYP_ULONG: return TYP_LONG; default: unreached(); } } else { return vt; } } template inline bool varTypeIsFloating(T vt) { return ((varTypeClassification[TypeGet(vt)] & (VTF_FLT)) != 0); } template inline bool varTypeIsArithmetic(T vt) { return ((varTypeClassification[TypeGet(vt)] & (VTF_INT | VTF_FLT)) != 0); } template inline unsigned varTypeGCtype(T vt) { return (unsigned)(varTypeClassification[TypeGet(vt)] & (VTF_GCR | VTF_BYR)); } template inline bool varTypeIsGC(T vt) { return (varTypeGCtype(vt) != 0); } template inline bool varTypeIsI(T vt) { return ((varTypeClassification[TypeGet(vt)] & VTF_I) != 0); } template inline bool varTypeIsEnregisterable(T vt) { return (TypeGet(vt) != TYP_STRUCT); } template inline bool varTypeIsByte(T vt) { return (TypeGet(vt) >= TYP_BOOL) && (TypeGet(vt) <= TYP_UBYTE); } template inline bool varTypeIsShort(T vt) { return (TypeGet(vt) == TYP_SHORT) || (TypeGet(vt) == TYP_USHORT); } template inline bool varTypeIsSmall(T vt) { return (TypeGet(vt) >= TYP_BOOL) && (TypeGet(vt) <= TYP_USHORT); } template inline bool varTypeIsSmallInt(T vt) { return (TypeGet(vt) >= TYP_BYTE) && (TypeGet(vt) <= TYP_USHORT); } template inline bool varTypeIsIntOrI(T vt) { return ((TypeGet(vt) == TYP_INT) #ifdef _TARGET_64BIT_ || (TypeGet(vt) == TYP_I_IMPL) #endif // _TARGET_64BIT_ ); } template inline bool genActualTypeIsIntOrI(T vt) { return ((TypeGet(vt) >= TYP_BOOL) && (TypeGet(vt) <= TYP_U_IMPL)); } template inline bool varTypeIsLong(T vt) { return (TypeGet(vt) >= TYP_LONG) && (TypeGet(vt) <= TYP_ULONG); } template inline bool varTypeIsMultiReg(T vt) { #ifdef _TARGET_64BIT_ return false; #else return (TypeGet(vt) == TYP_LONG); #endif } template inline bool varTypeIsSingleReg(T vt) { return !varTypeIsMultiReg(vt); } template inline bool varTypeIsComposite(T vt) { return (!varTypeIsArithmetic(TypeGet(vt)) && TypeGet(vt) != TYP_VOID); } // Is this type promotable? // In general only structs are promotable. // However, a SIMD type, e.g. TYP_SIMD may be handled as either a struct, OR a // fully-promoted register type. // On 32-bit systems longs are split into an upper and lower half, and they are // handled as if they are structs with two integer fields. template inline bool varTypeIsPromotable(T vt) { return (varTypeIsStruct(vt) || (TypeGet(vt) == TYP_BLK) #if !defined(_TARGET_64BIT_) || varTypeIsLong(vt) #endif // !defined(_TARGET_64BIT_) ); } template inline bool varTypeIsStruct(T vt) { return ((varTypeClassification[TypeGet(vt)] & VTF_S) != 0); } template inline bool varTypeUsesFloatReg(T vt) { // Note that not all targets support SIMD, but if they don't, varTypeIsSIMD will // always return false. return varTypeIsFloating(vt) || varTypeIsSIMD(vt); } template inline bool varTypeUsesFloatArgReg(T vt) { #ifdef _TARGET_ARM64_ // Arm64 passes SIMD types in floating point registers. return varTypeUsesFloatReg(vt); #else // Other targets pass them as regular structs - by reference or by value. return varTypeIsFloating(vt); #endif } //------------------------------------------------------------------------ // varTypeIsValidHfaType: Determine if the type is a valid HFA type // // Arguments: // vt - the type of interest // // Return Value: // Returns true iff the type is a valid HFA type. // // Notes: // This should only be called with the return value from GetHfaType(). // The only valid values are TYP_UNDEF, for which this returns false, // TYP_FLOAT, TYP_DOUBLE, or (ARM64-only) TYP_SIMD*. // template inline bool varTypeIsValidHfaType(T vt) { #ifdef FEATURE_HFA bool isValid = (TypeGet(vt) != TYP_UNDEF); if (isValid) { #ifdef _TARGET_ARM64_ assert(varTypeUsesFloatReg(vt)); #else // !_TARGET_ARM64_ assert(varTypeIsFloating(vt)); #endif // !_TARGET_ARM64_ } return isValid; #else // !FEATURE_HFA return false; #endif // !FEATURE_HFA } /*****************************************************************************/ #endif // _VARTYPE_H_ /*****************************************************************************/