// // Copyright (c) 2017 The Khronos Group Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // #include "conversions.h" #include #include #include #include "mt19937.h" #include "compat.h" #if defined(__SSE__) || defined(_MSC_VER) #include #endif #if defined(__SSE2__) || defined(_MSC_VER) #include #endif void print_type_to_string(ExplicitType type, void *data, char *string) { switch (type) { case kBool: if (*(char *)data) sprintf(string, "true"); else sprintf(string, "false"); return; case kChar: sprintf(string, "%d", (int)*((cl_char *)data)); return; case kUChar: case kUnsignedChar: sprintf(string, "%u", (int)*((cl_uchar *)data)); return; case kShort: sprintf(string, "%d", (int)*((cl_short *)data)); return; case kUShort: case kUnsignedShort: sprintf(string, "%u", (int)*((cl_ushort *)data)); return; case kInt: sprintf(string, "%d", *((cl_int *)data)); return; case kUInt: case kUnsignedInt: sprintf(string, "%u", *((cl_uint *)data)); return; case kLong: sprintf(string, "%lld", *((cl_long *)data)); return; case kULong: case kUnsignedLong: sprintf(string, "%llu", *((cl_ulong *)data)); return; case kFloat: sprintf(string, "%f", *((cl_float *)data)); return; case kHalf: sprintf(string, "half"); return; case kDouble: sprintf(string, "%g", *((cl_double *)data)); return; default: sprintf(string, "INVALID"); return; } } size_t get_explicit_type_size(ExplicitType type) { /* Quick method to avoid branching: make sure the following array matches * the Enum order */ static size_t sExplicitTypeSizes[] = { sizeof(cl_bool), sizeof(cl_char), sizeof(cl_uchar), sizeof(cl_uchar), sizeof(cl_short), sizeof(cl_ushort), sizeof(cl_ushort), sizeof(cl_int), sizeof(cl_uint), sizeof(cl_uint), sizeof(cl_long), sizeof(cl_ulong), sizeof(cl_ulong), sizeof(cl_float), sizeof(cl_half), sizeof(cl_double) }; return sExplicitTypeSizes[type]; } const char *get_explicit_type_name(ExplicitType type) { /* Quick method to avoid branching: make sure the following array matches * the Enum order */ static const char *sExplicitTypeNames[] = { "bool", "char", "uchar", "unsigned char", "short", "ushort", "unsigned short", "int", "uint", "unsigned int", "long", "ulong", "unsigned long", "float", "half", "double" }; return sExplicitTypeNames[type]; } static long lrintf_clamped(float f); static long lrintf_clamped(float f) { static const float magic[2] = { MAKE_HEX_FLOAT(0x1.0p23f, 0x1, 23), -MAKE_HEX_FLOAT(0x1.0p23f, 0x1, 23) }; if (f >= -(float)LONG_MIN) return LONG_MAX; if (f <= (float)LONG_MIN) return LONG_MIN; // Round fractional values to integer in round towards nearest mode if (fabsf(f) < MAKE_HEX_FLOAT(0x1.0p23f, 0x1, 23)) { volatile float x = f; float magicVal = magic[f < 0]; #if defined(__SSE__) || defined(_WIN32) // Defeat x87 based arithmetic, which cant do FTZ, and will round this // incorrectly __m128 v = _mm_set_ss(x); __m128 m = _mm_set_ss(magicVal); v = _mm_add_ss(v, m); v = _mm_sub_ss(v, m); _mm_store_ss((float *)&x, v); #else x += magicVal; x -= magicVal; #endif f = x; } return (long)f; } static long lrint_clamped(double f); static long lrint_clamped(double f) { static const double magic[2] = { MAKE_HEX_DOUBLE(0x1.0p52, 0x1LL, 52), MAKE_HEX_DOUBLE(-0x1.0p52, -0x1LL, 52) }; if (sizeof(long) > 4) { if (f >= -(double)LONG_MIN) return LONG_MAX; } else { if (f >= LONG_MAX) return LONG_MAX; } if (f <= (double)LONG_MIN) return LONG_MIN; // Round fractional values to integer in round towards nearest mode if (fabs(f) < MAKE_HEX_DOUBLE(0x1.0p52, 0x1LL, 52)) { volatile double x = f; double magicVal = magic[f < 0]; #if defined(__SSE2__) || (defined(_MSC_VER)) // Defeat x87 based arithmetic, which cant do FTZ, and will round this // incorrectly __m128d v = _mm_set_sd(x); __m128d m = _mm_set_sd(magicVal); v = _mm_add_sd(v, m); v = _mm_sub_sd(v, m); _mm_store_sd((double *)&x, v); #else x += magicVal; x -= magicVal; #endif f = x; } return (long)f; } typedef cl_long Long; typedef cl_ulong ULong; static ULong sUpperLimits[kNumExplicitTypes] = { 0, 127, 255, 255, 32767, 65535, 65535, 0x7fffffffLL, 0xffffffffLL, 0xffffffffLL, 0x7fffffffffffffffLL, 0xffffffffffffffffLL, 0xffffffffffffffffLL, 0, 0 }; // Last two values aren't stored here static Long sLowerLimits[kNumExplicitTypes] = { -1, -128, 0, 0, -32768, 0, 0, (Long)0xffffffff80000000LL, 0, 0, (Long)0x8000000000000000LL, 0, 0, 0, 0 }; // Last two values aren't stored here #define BOOL_CASE(inType) \ case kBool: \ boolPtr = (bool *)outRaw; \ *boolPtr = (*inType##Ptr) != 0 ? true : false; \ break; #define SIMPLE_CAST_CASE(inType, outEnum, outType) \ case outEnum: \ outType##Ptr = (outType *)outRaw; \ *outType##Ptr = (outType)(*inType##Ptr); \ break; // Sadly, the ULong downcasting cases need a separate #define to get rid of // signed/unsigned comparison warnings #define DOWN_CAST_CASE(inType, outEnum, outType, sat) \ case outEnum: \ outType##Ptr = (outType *)outRaw; \ if (sat) \ { \ if ((sLowerLimits[outEnum] < 0 \ && *inType##Ptr > (Long)sUpperLimits[outEnum]) \ || (sLowerLimits[outEnum] == 0 \ && (ULong)*inType##Ptr > sUpperLimits[outEnum])) \ *outType##Ptr = (outType)sUpperLimits[outEnum]; \ else if (*inType##Ptr < sLowerLimits[outEnum]) \ *outType##Ptr = (outType)sLowerLimits[outEnum]; \ else \ *outType##Ptr = (outType)*inType##Ptr; \ } \ else \ { \ *outType##Ptr = (outType)( \ *inType##Ptr \ & (0xffffffffffffffffLL >> (64 - (sizeof(outType) * 8)))); \ } \ break; #define U_DOWN_CAST_CASE(inType, outEnum, outType, sat) \ case outEnum: \ outType##Ptr = (outType *)outRaw; \ if (sat) \ { \ if ((ULong)*inType##Ptr > sUpperLimits[outEnum]) \ *outType##Ptr = (outType)sUpperLimits[outEnum]; \ else \ *outType##Ptr = (outType)*inType##Ptr; \ } \ else \ { \ *outType##Ptr = (outType)( \ *inType##Ptr \ & (0xffffffffffffffffLL >> (64 - (sizeof(outType) * 8)))); \ } \ break; #define TO_FLOAT_CASE(inType) \ case kFloat: \ floatPtr = (float *)outRaw; \ *floatPtr = (float)(*inType##Ptr); \ break; #define TO_DOUBLE_CASE(inType) \ case kDouble: \ doublePtr = (double *)outRaw; \ *doublePtr = (double)(*inType##Ptr); \ break; /* Note: we use lrintf here to force the rounding instead of whatever the * processor's current rounding mode is */ #define FLOAT_ROUND_TO_NEAREST_CASE(outEnum, outType) \ case outEnum: \ outType##Ptr = (outType *)outRaw; \ *outType##Ptr = (outType)lrintf_clamped(*floatPtr); \ break; #define FLOAT_ROUND_CASE(outEnum, outType, rounding, sat) \ case outEnum: { \ outType##Ptr = (outType *)outRaw; \ /* Get the tens digit */ \ Long wholeValue = (Long)*floatPtr; \ float largeRemainder = (*floatPtr - (float)wholeValue) * 10.f; \ /* What do we do based on that? */ \ if (rounding == kRoundToEven) \ { \ if (wholeValue & 1LL) /*between 1 and 1.99 */ \ wholeValue += 1LL; /* round up to even */ \ } \ else if (rounding == kRoundToZero) \ { \ /* Nothing to do, round-to-zero is what C casting does */ \ } \ else if (rounding == kRoundToPosInf) \ { \ /* Only positive numbers are wrong */ \ if (largeRemainder != 0.f && wholeValue >= 0) wholeValue++; \ } \ else if (rounding == kRoundToNegInf) \ { \ /* Only negative numbers are off */ \ if (largeRemainder != 0.f && wholeValue < 0) wholeValue--; \ } \ else \ { /* Default is round-to-nearest */ \ wholeValue = (Long)lrintf_clamped(*floatPtr); \ } \ /* Now apply saturation rules */ \ if (sat) \ { \ if ((sLowerLimits[outEnum] < 0 \ && wholeValue > (Long)sUpperLimits[outEnum]) \ || (sLowerLimits[outEnum] == 0 \ && (ULong)wholeValue > sUpperLimits[outEnum])) \ *outType##Ptr = (outType)sUpperLimits[outEnum]; \ else if (wholeValue < sLowerLimits[outEnum]) \ *outType##Ptr = (outType)sLowerLimits[outEnum]; \ else \ *outType##Ptr = (outType)wholeValue; \ } \ else \ { \ *outType##Ptr = (outType)( \ wholeValue \ & (0xffffffffffffffffLL >> (64 - (sizeof(outType) * 8)))); \ } \ } \ break; #define DOUBLE_ROUND_CASE(outEnum, outType, rounding, sat) \ case outEnum: { \ outType##Ptr = (outType *)outRaw; \ /* Get the tens digit */ \ Long wholeValue = (Long)*doublePtr; \ double largeRemainder = (*doublePtr - (double)wholeValue) * 10.0; \ /* What do we do based on that? */ \ if (rounding == kRoundToEven) \ { \ if (wholeValue & 1LL) /*between 1 and 1.99 */ \ wholeValue += 1LL; /* round up to even */ \ } \ else if (rounding == kRoundToZero) \ { \ /* Nothing to do, round-to-zero is what C casting does */ \ } \ else if (rounding == kRoundToPosInf) \ { \ /* Only positive numbers are wrong */ \ if (largeRemainder != 0.0 && wholeValue >= 0) wholeValue++; \ } \ else if (rounding == kRoundToNegInf) \ { \ /* Only negative numbers are off */ \ if (largeRemainder != 0.0 && wholeValue < 0) wholeValue--; \ } \ else \ { /* Default is round-to-nearest */ \ wholeValue = (Long)lrint_clamped(*doublePtr); \ } \ /* Now apply saturation rules */ \ if (sat) \ { \ if ((sLowerLimits[outEnum] < 0 \ && wholeValue > (Long)sUpperLimits[outEnum]) \ || (sLowerLimits[outEnum] == 0 \ && (ULong)wholeValue > sUpperLimits[outEnum])) \ *outType##Ptr = (outType)sUpperLimits[outEnum]; \ else if (wholeValue < sLowerLimits[outEnum]) \ *outType##Ptr = (outType)sLowerLimits[outEnum]; \ else \ *outType##Ptr = (outType)wholeValue; \ } \ else \ { \ *outType##Ptr = (outType)( \ wholeValue \ & (0xffffffffffffffffLL >> (64 - (sizeof(outType) * 8)))); \ } \ } \ break; typedef unsigned char uchar; typedef unsigned short ushort; typedef unsigned int uint; typedef unsigned long ulong; void convert_explicit_value(void *inRaw, void *outRaw, ExplicitType inType, bool saturate, RoundingType roundType, ExplicitType outType) { bool *boolPtr; char *charPtr; uchar *ucharPtr; short *shortPtr; ushort *ushortPtr; int *intPtr; uint *uintPtr; Long *LongPtr; ULong *ULongPtr; float *floatPtr; double *doublePtr; switch (inType) { case kBool: boolPtr = (bool *)inRaw; switch (outType) { case kBool: memcpy(outRaw, inRaw, get_explicit_type_size(inType)); break; case kChar: case kUChar: case kUnsignedChar: case kShort: case kUShort: case kUnsignedShort: case kInt: case kUInt: case kUnsignedInt: case kLong: case kULong: case kUnsignedLong: memset(outRaw, *boolPtr ? 0xff : 0, get_explicit_type_size(outType)); break; case kFloat: floatPtr = (float *)outRaw; *floatPtr = (*boolPtr) ? -1.f : 0.f; break; case kDouble: doublePtr = (double *)outRaw; *doublePtr = (*boolPtr) ? -1.0 : 0.0; break; default: log_error("ERROR: Invalid type given to " "convert_explicit_value!!\n"); break; } break; case kChar: charPtr = (char *)inRaw; switch (outType) { BOOL_CASE(char) case kChar: memcpy(outRaw, inRaw, get_explicit_type_size(inType)); break; DOWN_CAST_CASE(char, kUChar, uchar, saturate) SIMPLE_CAST_CASE(char, kUnsignedChar, uchar) SIMPLE_CAST_CASE(char, kShort, short) SIMPLE_CAST_CASE(char, kUShort, ushort) SIMPLE_CAST_CASE(char, kUnsignedShort, ushort) SIMPLE_CAST_CASE(char, kInt, int) SIMPLE_CAST_CASE(char, kUInt, uint) SIMPLE_CAST_CASE(char, kUnsignedInt, uint) SIMPLE_CAST_CASE(char, kLong, Long) SIMPLE_CAST_CASE(char, kULong, ULong) SIMPLE_CAST_CASE(char, kUnsignedLong, ULong) TO_FLOAT_CASE(char) TO_DOUBLE_CASE(char) default: log_error("ERROR: Invalid type given to " "convert_explicit_value!!\n"); break; } break; case kUChar: ucharPtr = (uchar *)inRaw; switch (outType) { BOOL_CASE(uchar) case kUChar: case kUnsignedChar: memcpy(outRaw, inRaw, get_explicit_type_size(inType)); break; DOWN_CAST_CASE(uchar, kChar, char, saturate) SIMPLE_CAST_CASE(uchar, kShort, short) SIMPLE_CAST_CASE(uchar, kUShort, ushort) SIMPLE_CAST_CASE(uchar, kUnsignedShort, ushort) SIMPLE_CAST_CASE(uchar, kInt, int) SIMPLE_CAST_CASE(uchar, kUInt, uint) SIMPLE_CAST_CASE(uchar, kUnsignedInt, uint) SIMPLE_CAST_CASE(uchar, kLong, Long) SIMPLE_CAST_CASE(uchar, kULong, ULong) SIMPLE_CAST_CASE(uchar, kUnsignedLong, ULong) TO_FLOAT_CASE(uchar) TO_DOUBLE_CASE(uchar) default: log_error("ERROR: Invalid type given to " "convert_explicit_value!!\n"); break; } break; case kUnsignedChar: ucharPtr = (uchar *)inRaw; switch (outType) { BOOL_CASE(uchar) case kUChar: case kUnsignedChar: memcpy(outRaw, inRaw, get_explicit_type_size(inType)); break; DOWN_CAST_CASE(uchar, kChar, char, saturate) SIMPLE_CAST_CASE(uchar, kShort, short) SIMPLE_CAST_CASE(uchar, kUShort, ushort) SIMPLE_CAST_CASE(uchar, kUnsignedShort, ushort) SIMPLE_CAST_CASE(uchar, kInt, int) SIMPLE_CAST_CASE(uchar, kUInt, uint) SIMPLE_CAST_CASE(uchar, kUnsignedInt, uint) SIMPLE_CAST_CASE(uchar, kLong, Long) SIMPLE_CAST_CASE(uchar, kULong, ULong) SIMPLE_CAST_CASE(uchar, kUnsignedLong, ULong) TO_FLOAT_CASE(uchar) TO_DOUBLE_CASE(uchar) default: log_error("ERROR: Invalid type given to " "convert_explicit_value!!\n"); break; } break; case kShort: shortPtr = (short *)inRaw; switch (outType) { BOOL_CASE(short) case kShort: memcpy(outRaw, inRaw, get_explicit_type_size(inType)); break; DOWN_CAST_CASE(short, kChar, char, saturate) DOWN_CAST_CASE(short, kUChar, uchar, saturate) DOWN_CAST_CASE(short, kUnsignedChar, uchar, saturate) DOWN_CAST_CASE(short, kUShort, ushort, saturate) DOWN_CAST_CASE(short, kUnsignedShort, ushort, saturate) SIMPLE_CAST_CASE(short, kInt, int) SIMPLE_CAST_CASE(short, kUInt, uint) SIMPLE_CAST_CASE(short, kUnsignedInt, uint) SIMPLE_CAST_CASE(short, kLong, Long) SIMPLE_CAST_CASE(short, kULong, ULong) SIMPLE_CAST_CASE(short, kUnsignedLong, ULong) TO_FLOAT_CASE(short) TO_DOUBLE_CASE(short) default: log_error("ERROR: Invalid type given to " "convert_explicit_value!!\n"); break; } break; case kUShort: ushortPtr = (ushort *)inRaw; switch (outType) { BOOL_CASE(ushort) case kUShort: case kUnsignedShort: memcpy(outRaw, inRaw, get_explicit_type_size(inType)); break; DOWN_CAST_CASE(ushort, kChar, char, saturate) DOWN_CAST_CASE(ushort, kUChar, uchar, saturate) DOWN_CAST_CASE(ushort, kUnsignedChar, uchar, saturate) DOWN_CAST_CASE(ushort, kShort, short, saturate) SIMPLE_CAST_CASE(ushort, kInt, int) SIMPLE_CAST_CASE(ushort, kUInt, uint) SIMPLE_CAST_CASE(ushort, kUnsignedInt, uint) SIMPLE_CAST_CASE(ushort, kLong, Long) SIMPLE_CAST_CASE(ushort, kULong, ULong) SIMPLE_CAST_CASE(ushort, kUnsignedLong, ULong) TO_FLOAT_CASE(ushort) TO_DOUBLE_CASE(ushort) default: log_error("ERROR: Invalid type given to " "convert_explicit_value!!\n"); break; } break; case kUnsignedShort: ushortPtr = (ushort *)inRaw; switch (outType) { BOOL_CASE(ushort) case kUShort: case kUnsignedShort: memcpy(outRaw, inRaw, get_explicit_type_size(inType)); break; DOWN_CAST_CASE(ushort, kChar, char, saturate) DOWN_CAST_CASE(ushort, kUChar, uchar, saturate) DOWN_CAST_CASE(ushort, kUnsignedChar, uchar, saturate) DOWN_CAST_CASE(ushort, kShort, short, saturate) SIMPLE_CAST_CASE(ushort, kInt, int) SIMPLE_CAST_CASE(ushort, kUInt, uint) SIMPLE_CAST_CASE(ushort, kUnsignedInt, uint) SIMPLE_CAST_CASE(ushort, kLong, Long) SIMPLE_CAST_CASE(ushort, kULong, ULong) SIMPLE_CAST_CASE(ushort, kUnsignedLong, ULong) TO_FLOAT_CASE(ushort) TO_DOUBLE_CASE(ushort) default: log_error("ERROR: Invalid type given to " "convert_explicit_value!!\n"); break; } break; case kInt: intPtr = (int *)inRaw; switch (outType) { BOOL_CASE(int) case kInt: memcpy(outRaw, inRaw, get_explicit_type_size(inType)); break; DOWN_CAST_CASE(int, kChar, char, saturate) DOWN_CAST_CASE(int, kUChar, uchar, saturate) DOWN_CAST_CASE(int, kUnsignedChar, uchar, saturate) DOWN_CAST_CASE(int, kShort, short, saturate) DOWN_CAST_CASE(int, kUShort, ushort, saturate) DOWN_CAST_CASE(int, kUnsignedShort, ushort, saturate) DOWN_CAST_CASE(int, kUInt, uint, saturate) DOWN_CAST_CASE(int, kUnsignedInt, uint, saturate) SIMPLE_CAST_CASE(int, kLong, Long) SIMPLE_CAST_CASE(int, kULong, ULong) SIMPLE_CAST_CASE(int, kUnsignedLong, ULong) TO_FLOAT_CASE(int) TO_DOUBLE_CASE(int) default: log_error("ERROR: Invalid type given to " "convert_explicit_value!!\n"); break; } break; case kUInt: uintPtr = (uint *)inRaw; switch (outType) { BOOL_CASE(uint) case kUInt: case kUnsignedInt: memcpy(outRaw, inRaw, get_explicit_type_size(inType)); break; DOWN_CAST_CASE(uint, kChar, char, saturate) DOWN_CAST_CASE(uint, kUChar, uchar, saturate) DOWN_CAST_CASE(uint, kUnsignedChar, uchar, saturate) DOWN_CAST_CASE(uint, kShort, short, saturate) DOWN_CAST_CASE(uint, kUShort, ushort, saturate) DOWN_CAST_CASE(uint, kUnsignedShort, ushort, saturate) DOWN_CAST_CASE(uint, kInt, int, saturate) SIMPLE_CAST_CASE(uint, kLong, Long) SIMPLE_CAST_CASE(uint, kULong, ULong) SIMPLE_CAST_CASE(uint, kUnsignedLong, ULong) TO_FLOAT_CASE(uint) TO_DOUBLE_CASE(uint) default: log_error("ERROR: Invalid type given to " "convert_explicit_value!!\n"); break; } break; case kUnsignedInt: uintPtr = (uint *)inRaw; switch (outType) { BOOL_CASE(uint) case kUInt: case kUnsignedInt: memcpy(outRaw, inRaw, get_explicit_type_size(inType)); break; DOWN_CAST_CASE(uint, kChar, char, saturate) DOWN_CAST_CASE(uint, kUChar, uchar, saturate) DOWN_CAST_CASE(uint, kUnsignedChar, uchar, saturate) DOWN_CAST_CASE(uint, kShort, short, saturate) DOWN_CAST_CASE(uint, kUShort, ushort, saturate) DOWN_CAST_CASE(uint, kUnsignedShort, ushort, saturate) DOWN_CAST_CASE(uint, kInt, int, saturate) SIMPLE_CAST_CASE(uint, kLong, Long) SIMPLE_CAST_CASE(uint, kULong, ULong) SIMPLE_CAST_CASE(uint, kUnsignedLong, ULong) TO_FLOAT_CASE(uint) TO_DOUBLE_CASE(uint) default: log_error("ERROR: Invalid type given to " "convert_explicit_value!!\n"); break; } break; case kLong: LongPtr = (Long *)inRaw; switch (outType) { BOOL_CASE(Long) case kLong: memcpy(outRaw, inRaw, get_explicit_type_size(inType)); break; DOWN_CAST_CASE(Long, kChar, char, saturate) DOWN_CAST_CASE(Long, kUChar, uchar, saturate) DOWN_CAST_CASE(Long, kUnsignedChar, uchar, saturate) DOWN_CAST_CASE(Long, kShort, short, saturate) DOWN_CAST_CASE(Long, kUShort, ushort, saturate) DOWN_CAST_CASE(Long, kUnsignedShort, ushort, saturate) DOWN_CAST_CASE(Long, kInt, int, saturate) DOWN_CAST_CASE(Long, kUInt, uint, saturate) DOWN_CAST_CASE(Long, kUnsignedInt, uint, saturate) DOWN_CAST_CASE(Long, kULong, ULong, saturate) DOWN_CAST_CASE(Long, kUnsignedLong, ULong, saturate) TO_FLOAT_CASE(Long) TO_DOUBLE_CASE(Long) default: log_error("ERROR: Invalid type given to " "convert_explicit_value!!\n"); break; } break; case kULong: ULongPtr = (ULong *)inRaw; switch (outType) { BOOL_CASE(ULong) case kUnsignedLong: case kULong: memcpy(outRaw, inRaw, get_explicit_type_size(inType)); break; U_DOWN_CAST_CASE(ULong, kChar, char, saturate) U_DOWN_CAST_CASE(ULong, kUChar, uchar, saturate) U_DOWN_CAST_CASE(ULong, kUnsignedChar, uchar, saturate) U_DOWN_CAST_CASE(ULong, kShort, short, saturate) U_DOWN_CAST_CASE(ULong, kUShort, ushort, saturate) U_DOWN_CAST_CASE(ULong, kUnsignedShort, ushort, saturate) U_DOWN_CAST_CASE(ULong, kInt, int, saturate) U_DOWN_CAST_CASE(ULong, kUInt, uint, saturate) U_DOWN_CAST_CASE(ULong, kUnsignedInt, uint, saturate) U_DOWN_CAST_CASE(ULong, kLong, Long, saturate) TO_FLOAT_CASE(ULong) TO_DOUBLE_CASE(ULong) default: log_error("ERROR: Invalid type given to " "convert_explicit_value!!\n"); break; } break; case kUnsignedLong: ULongPtr = (ULong *)inRaw; switch (outType) { BOOL_CASE(ULong) case kULong: case kUnsignedLong: memcpy(outRaw, inRaw, get_explicit_type_size(inType)); break; U_DOWN_CAST_CASE(ULong, kChar, char, saturate) U_DOWN_CAST_CASE(ULong, kUChar, uchar, saturate) U_DOWN_CAST_CASE(ULong, kUnsignedChar, uchar, saturate) U_DOWN_CAST_CASE(ULong, kShort, short, saturate) U_DOWN_CAST_CASE(ULong, kUShort, ushort, saturate) U_DOWN_CAST_CASE(ULong, kUnsignedShort, ushort, saturate) U_DOWN_CAST_CASE(ULong, kInt, int, saturate) U_DOWN_CAST_CASE(ULong, kUInt, uint, saturate) U_DOWN_CAST_CASE(ULong, kUnsignedInt, uint, saturate) U_DOWN_CAST_CASE(ULong, kLong, Long, saturate) TO_FLOAT_CASE(ULong) TO_DOUBLE_CASE(ULong) default: log_error("ERROR: Invalid type given to " "convert_explicit_value!!\n"); break; } break; case kFloat: floatPtr = (float *)inRaw; switch (outType) { BOOL_CASE(float) FLOAT_ROUND_CASE(kChar, char, roundType, saturate) FLOAT_ROUND_CASE(kUChar, uchar, roundType, saturate) FLOAT_ROUND_CASE(kUnsignedChar, uchar, roundType, saturate) FLOAT_ROUND_CASE(kShort, short, roundType, saturate) FLOAT_ROUND_CASE(kUShort, ushort, roundType, saturate) FLOAT_ROUND_CASE(kUnsignedShort, ushort, roundType, saturate) FLOAT_ROUND_CASE(kInt, int, roundType, saturate) FLOAT_ROUND_CASE(kUInt, uint, roundType, saturate) FLOAT_ROUND_CASE(kUnsignedInt, uint, roundType, saturate) FLOAT_ROUND_CASE(kLong, Long, roundType, saturate) FLOAT_ROUND_CASE(kULong, ULong, roundType, saturate) FLOAT_ROUND_CASE(kUnsignedLong, ULong, roundType, saturate) case kFloat: memcpy(outRaw, inRaw, get_explicit_type_size(inType)); break; TO_DOUBLE_CASE(float); default: log_error("ERROR: Invalid type given to " "convert_explicit_value!!\n"); break; } break; case kDouble: doublePtr = (double *)inRaw; switch (outType) { BOOL_CASE(double) DOUBLE_ROUND_CASE(kChar, char, roundType, saturate) DOUBLE_ROUND_CASE(kUChar, uchar, roundType, saturate) DOUBLE_ROUND_CASE(kUnsignedChar, uchar, roundType, saturate) DOUBLE_ROUND_CASE(kShort, short, roundType, saturate) DOUBLE_ROUND_CASE(kUShort, ushort, roundType, saturate) DOUBLE_ROUND_CASE(kUnsignedShort, ushort, roundType, saturate) DOUBLE_ROUND_CASE(kInt, int, roundType, saturate) DOUBLE_ROUND_CASE(kUInt, uint, roundType, saturate) DOUBLE_ROUND_CASE(kUnsignedInt, uint, roundType, saturate) DOUBLE_ROUND_CASE(kLong, Long, roundType, saturate) DOUBLE_ROUND_CASE(kULong, ULong, roundType, saturate) DOUBLE_ROUND_CASE(kUnsignedLong, ULong, roundType, saturate) TO_FLOAT_CASE(double); case kDouble: memcpy(outRaw, inRaw, get_explicit_type_size(inType)); break; default: log_error("ERROR: Invalid type given to " "convert_explicit_value!!\n"); break; } break; default: log_error( "ERROR: Invalid type given to convert_explicit_value!!\n"); break; } } void generate_random_data(ExplicitType type, size_t count, MTdata d, void *outData) { bool *boolPtr; cl_char *charPtr; cl_uchar *ucharPtr; cl_short *shortPtr; cl_ushort *ushortPtr; cl_int *intPtr; cl_uint *uintPtr; cl_long *longPtr; cl_ulong *ulongPtr; cl_float *floatPtr; cl_double *doublePtr; cl_half *halfPtr; size_t i; cl_uint bits = genrand_int32(d); cl_uint bitsLeft = 32; switch (type) { case kBool: boolPtr = (bool *)outData; for (i = 0; i < count; i++) { if (0 == bitsLeft) { bits = genrand_int32(d); bitsLeft = 32; } boolPtr[i] = (bits & 1) ? true : false; bits >>= 1; bitsLeft -= 1; } break; case kChar: charPtr = (cl_char *)outData; for (i = 0; i < count; i++) { if (0 == bitsLeft) { bits = genrand_int32(d); bitsLeft = 32; } charPtr[i] = (cl_char)((cl_int)(bits & 255) - 127); bits >>= 8; bitsLeft -= 8; } break; case kUChar: case kUnsignedChar: ucharPtr = (cl_uchar *)outData; for (i = 0; i < count; i++) { if (0 == bitsLeft) { bits = genrand_int32(d); bitsLeft = 32; } ucharPtr[i] = (cl_uchar)(bits & 255); bits >>= 8; bitsLeft -= 8; } break; case kShort: shortPtr = (cl_short *)outData; for (i = 0; i < count; i++) { if (0 == bitsLeft) { bits = genrand_int32(d); bitsLeft = 32; } shortPtr[i] = (cl_short)((cl_int)(bits & 65535) - 32767); bits >>= 16; bitsLeft -= 16; } break; case kUShort: case kUnsignedShort: ushortPtr = (cl_ushort *)outData; for (i = 0; i < count; i++) { if (0 == bitsLeft) { bits = genrand_int32(d); bitsLeft = 32; } ushortPtr[i] = (cl_ushort)((cl_int)(bits & 65535)); bits >>= 16; bitsLeft -= 16; } break; case kInt: intPtr = (cl_int *)outData; for (i = 0; i < count; i++) { intPtr[i] = (cl_int)genrand_int32(d); } break; case kUInt: case kUnsignedInt: uintPtr = (cl_uint *)outData; for (i = 0; i < count; i++) { uintPtr[i] = (unsigned int)genrand_int32(d); } break; case kLong: longPtr = (cl_long *)outData; for (i = 0; i < count; i++) { longPtr[i] = (cl_long)genrand_int32(d) | ((cl_long)genrand_int32(d) << 32); } break; case kULong: case kUnsignedLong: ulongPtr = (cl_ulong *)outData; for (i = 0; i < count; i++) { ulongPtr[i] = (cl_ulong)genrand_int32(d) | ((cl_ulong)genrand_int32(d) << 32); } break; case kFloat: floatPtr = (cl_float *)outData; for (i = 0; i < count; i++) { // [ -(double) 0x7fffffff, (double) 0x7fffffff ] double t = genrand_real1(d); floatPtr[i] = (float)((1.0 - t) * -(double)0x7fffffff + t * (double)0x7fffffff); } break; case kDouble: doublePtr = (cl_double *)outData; for (i = 0; i < count; i++) { cl_long u = (cl_long)genrand_int32(d) | ((cl_long)genrand_int32(d) << 32); double t = (double)u; // scale [-2**63, 2**63] to [-2**31, 2**31] t *= MAKE_HEX_DOUBLE(0x1.0p-32, 0x1, -32); doublePtr[i] = t; } break; case kHalf: halfPtr = (ushort *)outData; for (i = 0; i < count; i++) { if (0 == bitsLeft) { bits = genrand_int32(d); bitsLeft = 32; } halfPtr[i] = bits & 65535; /* Kindly generates random bits for us */ bits >>= 16; bitsLeft -= 16; } break; default: log_error( "ERROR: Invalid type passed in to generate_random_data!\n"); break; } } void *create_random_data(ExplicitType type, MTdata d, size_t count) { void *data = malloc(get_explicit_type_size(type) * count); generate_random_data(type, count, d, data); return data; } cl_long read_upscale_signed(void *inRaw, ExplicitType inType) { switch (inType) { case kChar: return (cl_long)(*((cl_char *)inRaw)); case kUChar: case kUnsignedChar: return (cl_long)(*((cl_uchar *)inRaw)); case kShort: return (cl_long)(*((cl_short *)inRaw)); case kUShort: case kUnsignedShort: return (cl_long)(*((cl_ushort *)inRaw)); case kInt: return (cl_long)(*((cl_int *)inRaw)); case kUInt: case kUnsignedInt: return (cl_long)(*((cl_uint *)inRaw)); case kLong: return (cl_long)(*((cl_long *)inRaw)); case kULong: case kUnsignedLong: return (cl_long)(*((cl_ulong *)inRaw)); default: return 0; } } cl_ulong read_upscale_unsigned(void *inRaw, ExplicitType inType) { switch (inType) { case kChar: return (cl_ulong)(*((cl_char *)inRaw)); case kUChar: case kUnsignedChar: return (cl_ulong)(*((cl_uchar *)inRaw)); case kShort: return (cl_ulong)(*((cl_short *)inRaw)); case kUShort: case kUnsignedShort: return (cl_ulong)(*((cl_ushort *)inRaw)); case kInt: return (cl_ulong)(*((cl_int *)inRaw)); case kUInt: case kUnsignedInt: return (cl_ulong)(*((cl_uint *)inRaw)); case kLong: return (cl_ulong)(*((cl_long *)inRaw)); case kULong: case kUnsignedLong: return (cl_ulong)(*((cl_ulong *)inRaw)); default: return 0; } } float read_as_float(void *inRaw, ExplicitType inType) { switch (inType) { case kChar: return (float)(*((cl_char *)inRaw)); case kUChar: case kUnsignedChar: return (float)(*((cl_char *)inRaw)); case kShort: return (float)(*((cl_short *)inRaw)); case kUShort: case kUnsignedShort: return (float)(*((cl_ushort *)inRaw)); case kInt: return (float)(*((cl_int *)inRaw)); case kUInt: case kUnsignedInt: return (float)(*((cl_uint *)inRaw)); case kLong: return (float)(*((cl_long *)inRaw)); case kULong: case kUnsignedLong: return (float)(*((cl_ulong *)inRaw)); case kFloat: return *((float *)inRaw); case kDouble: return (float)*((double *)inRaw); default: return 0; } } float get_random_float(float low, float high, MTdata d) { float t = (float)((double)genrand_int32(d) / (double)0xFFFFFFFF); return (1.0f - t) * low + t * high; } double get_random_double(double low, double high, MTdata d) { cl_ulong u = (cl_ulong)genrand_int32(d) | ((cl_ulong)genrand_int32(d) << 32); double t = (double)u * MAKE_HEX_DOUBLE(0x1.0p-64, 0x1, -64); return (1.0f - t) * low + t * high; } float any_float(MTdata d) { union { float f; cl_uint u; } u; u.u = genrand_int32(d); return u.f; } double any_double(MTdata d) { union { double f; cl_ulong u; } u; u.u = (cl_ulong)genrand_int32(d) | ((cl_ulong)genrand_int32(d) << 32); return u.f; } int random_in_range(int minV, int maxV, MTdata d) { cl_ulong r = ((cl_ulong)genrand_int32(d)) * (maxV - minV + 1); return (cl_uint)(r >> 32) + minV; } size_t get_random_size_t(size_t low, size_t high, MTdata d) { enum { N = sizeof(size_t) / sizeof(int) }; union { int word[N]; size_t size; } u; for (unsigned i = 0; i != N; ++i) { u.word[i] = genrand_int32(d); } assert(low <= high && "Invalid random number range specified"); size_t range = high - low; return (range) ? low + ((u.size - low) % range) : low; }