/* * il_values.h - Primitive value types for the IL interpreter. * * Copyright (C) 2001 Southern Storm Software, Pty Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef _IL_VALUES_H #define _IL_VALUES_H /* * Determine what kind of Win32 system we are running on. */ #if defined(__CYGWIN__) || defined(__CYGWIN32__) #define IL_WIN32_CYGWIN 1 #define IL_WIN32_PLATFORM 1 #elif defined(_WIN32) || defined(WIN32) #define IL_WIN32_NATIVE 1 #define IL_WIN32_PLATFORM 1 #endif #include "il_config.h" #include "il_profile.h" #ifdef __cplusplus extern "C" { #endif /* * Define the 8-bit and 16-bit numeric types. */ typedef signed char ILInt8; typedef unsigned char ILUInt8; typedef short ILInt16; typedef unsigned short ILUInt16; typedef ILInt8 ILBool; /* * Determine which types should be used for 32-bit numeric values. */ #ifdef SIZEOF_INT #if SIZEOF_INT == 4 typedef int ILInt32; typedef unsigned int ILUInt32; #define IL_HAVE_INT32 #endif #endif #ifndef IL_HAVE_INT32 typedef long ILInt32; typedef unsigned long ILUInt32; #endif /* * Determine which types should be used for 64-bit numeric values. */ #if defined(IL_WIN32_NATIVE) && defined(_MSC_VER) typedef __int64 ILInt64; typedef unsigned __int64 ILUInt64; #define IL_HAVE_INT64 #endif #if (!defined(IL_HAVE_INT64)) && defined(SIZEOF_LONG_LONG) #if SIZEOF_LONG_LONG == 8 typedef long long ILInt64; typedef unsigned long long ILUInt64; #define IL_HAVE_INT64 #endif #endif #if (!defined(IL_HAVE_INT64)) && defined(SIZEOF_LONG) #if SIZEOF_LONG == 8 typedef long ILInt64; typedef unsigned long ILUInt64; #define IL_HAVE_INT64 #endif #endif #if (!defined(IL_HAVE_INT64)) && defined(IL_WIN32_NATIVE) typedef __int64 ILInt64; typedef unsigned __int64 ILUInt64; #define IL_HAVE_INT64 #endif #ifndef IL_HAVE_INT64 #error "Could not detect the 64-bit integer type on this compiler" #endif /* * Native integers are the same size as native pointers. */ #ifdef SIZEOF_VOID_P #if SIZEOF_VOID_P == 8 typedef ILInt64 ILNativeInt; typedef ILUInt64 ILNativeUInt; #define IL_NATIVE_INT64 #endif #endif #ifndef IL_NATIVE_INT64 typedef ILInt32 ILNativeInt; typedef ILUInt32 ILNativeUInt; #define IL_NATIVE_INT32 #endif /* * Determine which type should be used for 32-bit floating point values. */ #ifdef SIZEOF_FLOAT #if SIZEOF_FLOAT == 4 typedef float ILFloat; #define IL_HAVE_FLOAT #else #error "Compiler's float is not 32 bits!" #endif #endif #ifndef IL_HAVE_FLOAT typedef float ILFloat; #endif /* * Determine which type should be used for 64-bit floating point values. */ #ifdef SIZEOF_DOUBLE #if SIZEOF_DOUBLE == 8 typedef double ILDouble; #define IL_HAVE_DOUBLE #else #error "Compiler's double is not 64 bits!" #endif #endif #ifndef IL_HAVE_DOUBLE typedef double ILDouble; #endif /* * Determine the best native floating point format. * * Note: we check that sizeof(long double) is different from * sizeof(double) because some versions of gcc complain about * "long double" if the underlying CPU doesn't really have it. */ #ifdef SIZEOF_LONG_DOUBLE #if SIZEOF_LONG_DOUBLE != 0 #if SIZEOF_LONG_DOUBLE != SIZEOF_DOUBLE typedef long double ILNativeFloat; #define IL_NATIVE_FLOAT #endif #endif #endif #ifndef IL_NATIVE_FLOAT typedef ILDouble ILNativeFloat; #endif /* * Useful min/max constants for the above types. */ #define IL_MIN_INT32 ((ILInt32)0x80000000L) #define IL_MAX_INT32 ((ILInt32)0x7FFFFFFFL) #define IL_MAX_UINT32 ((ILUInt32)0xFFFFFFFFL) #if defined(IL_WIN32_NATIVE) && defined(_MSC_VER) #define IL_MIN_INT64 ((ILInt64)0x8000000000000000L) #define IL_MAX_INT64 ((ILInt64)0x7FFFFFFFFFFFFFFFL) #define IL_MAX_UINT64 ((ILUInt64)0xFFFFFFFFFFFFFFFFUL) #else #define IL_MIN_INT64 ((ILInt64)0x8000000000000000LL) #define IL_MAX_INT64 ((ILInt64)0x7FFFFFFFFFFFFFFFLL) #define IL_MAX_UINT64 ((ILUInt64)0xFFFFFFFFFFFFFFFFLL) #endif #ifdef IL_NATIVE_INT32 #define IL_MIN_NATIVE_INT IL_MIN_INT32 #define IL_MAX_NATIVE_INT IL_MAX_INT32 #define IL_MAX_NATIVE_UINT IL_MAX_UINT32 #else #define IL_MIN_NATIVE_INT IL_MIN_INT64 #define IL_MAX_NATIVE_INT IL_MAX_INT64 #define IL_MAX_NATIVE_UINT IL_MAX_UINT64 #endif /* * Read little-endian values of various sizes from memory buffers. */ #define _IL_READ_BYTE(buf,offset) \ ((ILUInt32)(ILUInt8)(((ILUInt8 *)(buf))[(offset)])) #define _IL_READ_BYTE_SHIFT(buf,offset,shift) \ (((ILUInt32)(ILUInt8)(((ILUInt8 *)(buf))[(offset)])) << (shift)) #if defined(__i386) || defined(__i386__) /* The i386 family of CPU's can read little-endian values on any byte boundary, so we can implement the macros more simply */ #define IL_READ_INT16(buf) (*((ILInt16 *)(buf))) #define IL_READ_UINT16(buf) (*((ILUInt16 *)(buf))) #define IL_READ_INT32(buf) (*((ILInt32 *)(buf))) #define IL_READ_UINT32(buf) (*((ILUInt32 *)(buf))) #define IL_READ_INT64(buf) (*((ILInt64 *)(buf))) #define IL_READ_UINT64(buf) (*((ILUInt64 *)(buf))) #else #define IL_READ_INT16(buf) ((ILInt16)(_IL_READ_BYTE((buf), 0) | \ _IL_READ_BYTE_SHIFT((buf), 1, 8))) #define IL_READ_UINT16(buf) ((ILUInt16)(_IL_READ_BYTE((buf), 0) | \ _IL_READ_BYTE_SHIFT((buf), 1, 8))) #define IL_READ_INT32(buf) ((ILInt32)(_IL_READ_BYTE((buf), 0) | \ _IL_READ_BYTE_SHIFT((buf), 1, 8) | \ _IL_READ_BYTE_SHIFT((buf), 2, 16) | \ _IL_READ_BYTE_SHIFT((buf), 3, 24))) #define IL_READ_UINT32(buf) ((ILUInt32)(_IL_READ_BYTE((buf), 0) | \ _IL_READ_BYTE_SHIFT((buf), 1, 8) | \ _IL_READ_BYTE_SHIFT((buf), 2, 16) | \ _IL_READ_BYTE_SHIFT((buf), 3, 24))) #define IL_READ_INT64(buf) \ (((ILInt64)(IL_READ_UINT32((buf)))) | \ (((ILInt64)(IL_READ_INT32(((ILUInt8 *)(buf)) + 4))) << 32)) #define IL_READ_UINT64(buf) \ (((ILUInt64)(IL_READ_UINT32((buf)))) | \ (((ILUInt64)(IL_READ_UINT32(((ILUInt8 *)(buf)) + 4))) << 32)) #endif ILNativeFloat _ILReadFloat(const unsigned char *buf); #define IL_READ_FLOAT(buf) (_ILReadFloat((buf))) ILNativeFloat _ILReadDouble(const unsigned char *buf); #define IL_READ_DOUBLE(buf) (_ILReadDouble((buf))) /* * Write little-endian values of various sizes to memory buffers. */ #if defined(__i386) || defined(__i386__) /* The i386 family of CPU's can write little-endian values on any byte boundary, so we can implement the macros more simply */ #define IL_WRITE_UINT16(buf, value) (*((ILUInt16 *)(buf)) = (ILUInt16)(value)) #define IL_WRITE_INT16(buf, value) (*((ILInt16 *)(buf)) = (ILInt16)(value)) #define IL_WRITE_UINT32(buf, value) (*((ILUInt32 *)(buf)) = (ILUInt32)(value)) #define IL_WRITE_INT32(buf, value) (*((ILInt32 *)(buf)) = (ILInt32)(value)) #define IL_WRITE_UINT64(buf, value) (*((ILUInt64 *)(buf)) = (ILUInt64)(value)) #define IL_WRITE_INT64(buf, value) (*((ILInt64 *)(buf)) = (ILInt64)(value)) #else #define IL_WRITE_UINT16(buf, value) \ do { \ (buf)[0] = (unsigned char)(value); \ (buf)[1] = (unsigned char)((value) >> 8); \ } while (0) #define IL_WRITE_INT16(buf, value) IL_WRITE_UINT16((buf), (ILUInt16)(value)) #define IL_WRITE_UINT32(buf, value) \ do { \ (buf)[0] = (unsigned char)(value); \ (buf)[1] = (unsigned char)((value) >> 8); \ (buf)[2] = (unsigned char)((value) >> 16); \ (buf)[3] = (unsigned char)((value) >> 24); \ } while (0) #define IL_WRITE_INT32(buf, value) IL_WRITE_UINT32((buf), (ILUInt32)(value)) #define IL_WRITE_UINT64(buf, value) \ do { \ (buf)[0] = (unsigned char)(value); \ (buf)[1] = (unsigned char)((value) >> 8); \ (buf)[2] = (unsigned char)((value) >> 16); \ (buf)[3] = (unsigned char)((value) >> 24); \ (buf)[4] = (unsigned char)((value) >> 32); \ (buf)[5] = (unsigned char)((value) >> 40); \ (buf)[6] = (unsigned char)((value) >> 48); \ (buf)[7] = (unsigned char)((value) >> 56); \ } while (0) #define IL_WRITE_INT64(buf, value) IL_WRITE_UINT64((buf), (ILUInt64)(value)) #endif void _ILWriteFloat(unsigned char *buf, ILFloat value); #define IL_WRITE_FLOAT(buf,value) (_ILWriteFloat((buf), (value))) void _ILWriteDouble(unsigned char *buf, ILDouble value); #define IL_WRITE_DOUBLE(buf,value) (_ILWriteDouble((buf), (value))) /* * Multiply 64-bit values with overflow testing. * Returns zero on overflow. */ int ILInt64MulOvf(ILInt64 *product, ILInt64 value1, ILInt64 value2); int ILUInt64MulOvf(ILUInt64 *product, ILUInt64 value1, ILUInt64 value2); /* * Compute the floating-point remainder of two values. */ ILNativeFloat ILNativeFloatRem(ILNativeFloat value1, ILNativeFloat value2); /* * Value testing for floating-point values. */ int ILNativeFloatIsNaN(ILNativeFloat value); int ILNativeFloatIsFinite(ILNativeFloat value); int ILNativeFloatIsInf(ILNativeFloat value); /* * Perform difficult numeric conversions. */ ILNativeFloat ILUInt64ToFloat(ILUInt64 value); ILUInt64 ILFloatToUInt64(ILNativeFloat value); int ILFloatToInt64Ovf(ILInt64 *result, ILNativeFloat value); int ILFloatToUInt64Ovf(ILUInt64 *result, ILNativeFloat value); #ifdef __cplusplus }; #endif #endif /* _IL_VALUES_H */