1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134
|
/*========================== begin_copyright_notice ============================
Copyright (C) 2017-2021 Intel Corporation
SPDX-License-Identifier: MIT
============================= end_copyright_notice ===========================*/
#include "../include/BiF_Definitions.cl"
#include "../../Headers/spirv.h"
float SPIRV_OVERLOADABLE SPIRV_OCL_BUILTIN(nextafter, _f32_f32, )( float x, float y )
{
const int maxneg = FLOAT_SIGN_MASK;
// The way this algorithm works is as follows:
//
// - Treat the incoming float as an integer. Note that the integer
// representation of floats are ordered if the integer is interpreted
// as being sign-magnitude encoded.
// - Convert each incoming float from sign-magnitude to twos-complement
// encoded, so we can use usual comparison and math operations on them.
// - Based on the twos complement encoding of the integer representation
// of each float, either add or subtract one from the twos-complement
// encoding of the integer representation of x. This gives a twos-
// complement encoding of the result.
// - Convert from the twos-complement encoding of the result back
// to a sign-magnitude encoding of the result, and interpret as
// a float. We're done! Well, almost.
// - Handle two special-cases:
// - When the two floats are equal then there is no delta.
// - When either float is NaN the result is NaN.
//
// The code is written so it does not need flow control.
int smix = as_int(x);
int nx = maxneg - smix;
int tcix = ( smix < 0 ) ? nx : smix;
int smiy = as_int(y);
int ny = maxneg - smiy;
int tciy = ( smiy < 0 ) ? ny : smiy;
int delta = ( tcix < tciy ) ? 1 : -1;
int tcir = tcix + delta;
int nr = maxneg - tcir;
int smir = ( tcir < 0 ) ? nr : tcir;
float result = as_float(smir);
result = (tcix == tciy) ? y : result;
{
float n = SPIRV_OCL_BUILTIN(nan, _i32, )(0);
int test = __intel_relaxed_isnan(x) | __intel_relaxed_isnan(y);
result = test ? n : result;
}
return result;
}
GENERATE_SPIRV_OCL_VECTOR_FUNCTIONS_2ARGS( nextafter, float, float, f32 )
#if defined(cl_khr_fp64)
double SPIRV_OVERLOADABLE SPIRV_OCL_BUILTIN(nextafter, _f64_f64, )( double x, double y )
{
const long maxneg = DOUBLE_SIGN_MASK;
long smix = as_long(x);
long nx = maxneg - smix;
long tcix = ( smix < 0 ) ? nx : smix;
long smiy = as_long(y);
long ny = maxneg - smiy;
long tciy = ( smiy < 0 ) ? ny : smiy;
long delta = ( tcix < tciy ) ? 1 : -1;
long tcir = tcix + delta;
long nr = maxneg - tcir;
long smir = ( tcir < 0 ) ? nr : tcir;
double result = as_double(smir);
result = (tcix == tciy) ? y : result;
{
double n = SPIRV_OCL_BUILTIN(nan, _i64, )(0);
int test = SPIRV_BUILTIN(IsNan, _f64, )(x) | SPIRV_BUILTIN(IsNan, _f64, )(y);
result = test ? n : result;
}
return result;
}
GENERATE_SPIRV_OCL_VECTOR_FUNCTIONS_2ARGS( nextafter, double, double, f64 )
#endif // defined(cl_khr_fp64)
#if defined(cl_khr_fp16)
half SPIRV_OVERLOADABLE SPIRV_OCL_BUILTIN(nextafter, _f16_f16, )( half x, half y )
{
const short maxneg = HALF_SIGN_MASK;
short smix = as_short(x);
short nx = maxneg - smix;
short tcix = ( smix < 0 ) ? nx : smix;
short smiy = as_short(y);
short ny = maxneg - smiy;
short tciy = ( smiy < 0 ) ? ny : smiy;
short delta = ( tcix < tciy ) ? 1 : -1;
short tcir = tcix + delta;
short nr = maxneg - tcir;
short smir = ( tcir < 0 ) ? nr : tcir;
half result = as_half(smir);
result = (tcix == tciy) ? y : result;
{
half n = SPIRV_OCL_BUILTIN(nan, _i32, )(0);
int test = SPIRV_BUILTIN(IsNan, _f16, )(x) | SPIRV_BUILTIN(IsNan, _f16, )(y);
result = test ? n : result;
}
return result;
}
GENERATE_SPIRV_OCL_VECTOR_FUNCTIONS_2ARGS( nextafter, half, half, f16 )
#endif // defined(cl_khr_fp16)
|