futhark-0.25.27: rts/c/scalar_f16.h
// Start of scalar_f16.h.
// Half-precision is emulated if needed (e.g. in straight C) with the
// native type used if possible. The emulation works by typedef'ing
// 'float' to 'f16', and then implementing all operations on single
// precision. To cut down on duplication, we use the same code for
// those Futhark functions that require just operators or casts. The
// in-memory representation for arrays will still be 16 bits even
// under emulation, so the compiler will have to be careful when
// generating reads or writes.
#if !defined(cl_khr_fp16) && !(defined(__CUDA_ARCH__) && __CUDA_ARCH__ >= 600) && !(defined(ISPC))
#define EMULATE_F16
#endif
#if !defined(EMULATE_F16) && defined(__OPENCL_VERSION__)
#pragma OPENCL EXTENSION cl_khr_fp16 : enable
#endif
#ifdef EMULATE_F16
// Note that the half-precision storage format is still 16 bits - the
// compiler will have to be real careful!
typedef float f16;
#elif defined(ISPC)
typedef float16 f16;
#else
#ifdef __CUDA_ARCH__
#include <cuda_fp16.h>
#endif
typedef half f16;
#endif
// Some of these functions convert to single precision because half
// precision versions are not available.
SCALAR_FUN_ATTR f16 fadd16(f16 x, f16 y) {
return x + y;
}
SCALAR_FUN_ATTR f16 fsub16(f16 x, f16 y) {
return x - y;
}
SCALAR_FUN_ATTR f16 fmul16(f16 x, f16 y) {
return x * y;
}
SCALAR_FUN_ATTR bool cmplt16(f16 x, f16 y) {
return x < y;
}
SCALAR_FUN_ATTR bool cmple16(f16 x, f16 y) {
return x <= y;
}
SCALAR_FUN_ATTR f16 sitofp_i8_f16(int8_t x) {
return (f16) x;
}
SCALAR_FUN_ATTR f16 sitofp_i16_f16(int16_t x) {
return (f16) x;
}
SCALAR_FUN_ATTR f16 sitofp_i32_f16(int32_t x) {
return (f16) x;
}
SCALAR_FUN_ATTR f16 sitofp_i64_f16(int64_t x) {
return (f16) x;
}
SCALAR_FUN_ATTR f16 uitofp_i8_f16(uint8_t x) {
return (f16) x;
}
SCALAR_FUN_ATTR f16 uitofp_i16_f16(uint16_t x) {
return (f16) x;
}
SCALAR_FUN_ATTR f16 uitofp_i32_f16(uint32_t x) {
return (f16) x;
}
SCALAR_FUN_ATTR f16 uitofp_i64_f16(uint64_t x) {
return (f16) x;
}
SCALAR_FUN_ATTR int8_t fptosi_f16_i8(f16 x) {
return (int8_t) (float) x;
}
SCALAR_FUN_ATTR int16_t fptosi_f16_i16(f16 x) {
return (int16_t) x;
}
SCALAR_FUN_ATTR int32_t fptosi_f16_i32(f16 x) {
return (int32_t) x;
}
SCALAR_FUN_ATTR int64_t fptosi_f16_i64(f16 x) {
return (int64_t) x;
}
SCALAR_FUN_ATTR uint8_t fptoui_f16_i8(f16 x) {
return (uint8_t) (float) x;
}
SCALAR_FUN_ATTR uint16_t fptoui_f16_i16(f16 x) {
return (uint16_t) x;
}
SCALAR_FUN_ATTR uint32_t fptoui_f16_i32(f16 x) {
return (uint32_t) x;
}
SCALAR_FUN_ATTR uint64_t fptoui_f16_i64(f16 x) {
return (uint64_t) x;
}
SCALAR_FUN_ATTR bool ftob_f16_bool(f16 x) {
return x != (f16)0;
}
SCALAR_FUN_ATTR f16 btof_bool_f16(bool x) {
return x ? 1 : 0;
}
#ifndef EMULATE_F16
SCALAR_FUN_ATTR bool futrts_isnan16(f16 x) {
return isnan((float)x);
}
#ifdef __OPENCL_VERSION__
SCALAR_FUN_ATTR f16 fabs16(f16 x) {
return fabs(x);
}
SCALAR_FUN_ATTR f16 fmax16(f16 x, f16 y) {
return fmax(x, y);
}
SCALAR_FUN_ATTR f16 fmin16(f16 x, f16 y) {
return fmin(x, y);
}
SCALAR_FUN_ATTR f16 fpow16(f16 x, f16 y) {
return pow(x, y);
}
#elif defined(ISPC)
SCALAR_FUN_ATTR f16 fabs16(f16 x) {
return abs(x);
}
SCALAR_FUN_ATTR f16 fmax16(f16 x, f16 y) {
return futrts_isnan16(x) ? y : futrts_isnan16(y) ? x : max(x, y);
}
SCALAR_FUN_ATTR f16 fmin16(f16 x, f16 y) {
return futrts_isnan16(x) ? y : futrts_isnan16(y) ? x : min(x, y);
}
SCALAR_FUN_ATTR f16 fpow16(f16 x, f16 y) {
return pow(x, y);
}
#else // Assuming CUDA.
SCALAR_FUN_ATTR f16 fabs16(f16 x) {
return fabsf(x);
}
SCALAR_FUN_ATTR f16 fmax16(f16 x, f16 y) {
return fmaxf(x, y);
}
SCALAR_FUN_ATTR f16 fmin16(f16 x, f16 y) {
return fminf(x, y);
}
SCALAR_FUN_ATTR f16 fpow16(f16 x, f16 y) {
return powf(x, y);
}
#endif
#if defined(ISPC)
SCALAR_FUN_ATTR bool futrts_isinf16(float x) {
return !futrts_isnan16(x) && futrts_isnan16(x - x);
}
SCALAR_FUN_ATTR bool futrts_isfinite16(float x) {
return !futrts_isnan16(x) && !futrts_isinf16(x);
}
#else
SCALAR_FUN_ATTR bool futrts_isinf16(f16 x) {
return isinf((float)x);
}
#endif
#ifdef __OPENCL_VERSION__
SCALAR_FUN_ATTR f16 futrts_log16(f16 x) {
return log(x);
}
SCALAR_FUN_ATTR f16 futrts_log2_16(f16 x) {
return log2(x);
}
SCALAR_FUN_ATTR f16 futrts_log10_16(f16 x) {
return log10(x);
}
SCALAR_FUN_ATTR f16 futrts_log1p_16(f16 x) {
return log1p(x);
}
SCALAR_FUN_ATTR f16 futrts_sqrt16(f16 x) {
return sqrt(x);
}
SCALAR_FUN_ATTR f16 futrts_cbrt16(f16 x) {
return cbrt(x);
}
SCALAR_FUN_ATTR f16 futrts_exp16(f16 x) {
return exp(x);
}
SCALAR_FUN_ATTR f16 futrts_cos16(f16 x) {
return cos(x);
}
SCALAR_FUN_ATTR f16 futrts_sin16(f16 x) {
return sin(x);
}
SCALAR_FUN_ATTR f16 futrts_tan16(f16 x) {
return tan(x);
}
SCALAR_FUN_ATTR f16 futrts_acos16(f16 x) {
return acos(x);
}
SCALAR_FUN_ATTR f16 futrts_asin16(f16 x) {
return asin(x);
}
SCALAR_FUN_ATTR f16 futrts_atan16(f16 x) {
return atan(x);
}
SCALAR_FUN_ATTR f16 futrts_cosh16(f16 x) {
return cosh(x);
}
SCALAR_FUN_ATTR f16 futrts_sinh16(f16 x) {
return sinh(x);
}
SCALAR_FUN_ATTR f16 futrts_tanh16(f16 x) {
return tanh(x);
}
SCALAR_FUN_ATTR f16 futrts_acosh16(f16 x) {
return acosh(x);
}
SCALAR_FUN_ATTR f16 futrts_asinh16(f16 x) {
return asinh(x);
}
SCALAR_FUN_ATTR f16 futrts_atanh16(f16 x) {
return atanh(x);
}
SCALAR_FUN_ATTR f16 futrts_atan2_16(f16 x, f16 y) {
return atan2(x, y);
}
SCALAR_FUN_ATTR f16 futrts_hypot16(f16 x, f16 y) {
return hypot(x, y);
}
SCALAR_FUN_ATTR f16 futrts_gamma16(f16 x) {
return tgamma(x);
}
SCALAR_FUN_ATTR f16 futrts_lgamma16(f16 x) {
return lgamma(x);
}
SCALAR_FUN_ATTR f16 futrts_erf16(f16 x) {
return erf(x);
}
SCALAR_FUN_ATTR f16 futrts_erfc16(f16 x) {
return erfc(x);
}
SCALAR_FUN_ATTR f16 fmod16(f16 x, f16 y) {
return fmod(x, y);
}
SCALAR_FUN_ATTR f16 futrts_round16(f16 x) {
return rint(x);
}
SCALAR_FUN_ATTR f16 futrts_floor16(f16 x) {
return floor(x);
}
SCALAR_FUN_ATTR f16 futrts_ceil16(f16 x) {
return ceil(x);
}
SCALAR_FUN_ATTR f16 futrts_nextafter16(f16 x, f16 y) {
return nextafter(x, y);
}
SCALAR_FUN_ATTR f16 futrts_lerp16(f16 v0, f16 v1, f16 t) {
return mix(v0, v1, t);
}
SCALAR_FUN_ATTR f16 futrts_ldexp16(f16 x, int32_t y) {
return ldexp(x, y);
}
SCALAR_FUN_ATTR f16 futrts_copysign16(f16 x, f16 y) {
return copysign(x, y);
}
SCALAR_FUN_ATTR f16 futrts_mad16(f16 a, f16 b, f16 c) {
return mad(a, b, c);
}
SCALAR_FUN_ATTR f16 futrts_fma16(f16 a, f16 b, f16 c) {
return fma(a, b, c);
}
#elif defined(ISPC)
SCALAR_FUN_ATTR f16 futrts_log16(f16 x) {
return futrts_isfinite16(x) || (futrts_isinf16(x) && x < 0) ? log(x) : x;
}
SCALAR_FUN_ATTR f16 futrts_log2_16(f16 x) {
return futrts_log16(x) / log(2.0f16);
}
SCALAR_FUN_ATTR f16 futrts_log10_16(f16 x) {
return futrts_log16(x) / log(10.0f16);
}
SCALAR_FUN_ATTR f16 futrts_log1p_16(f16 x) {
if(x == -1.0f16 || (futrts_isinf16(x) && x > 0.0f16)) return x / 0.0f16;
f16 y = 1.0f16 + x;
f16 z = y - 1.0f16;
return log(y) - (z-x)/y;
}
SCALAR_FUN_ATTR f16 futrts_sqrt16(f16 x) {
return (float16)sqrt((float)x);
}
SCALAR_FUN_ATTR f16 futrts_exp16(f16 x) {
return exp(x);
}
SCALAR_FUN_ATTR f16 futrts_cos16(f16 x) {
return (float16)cos((float)x);
}
SCALAR_FUN_ATTR f16 futrts_sin16(f16 x) {
return (float16)sin((float)x);
}
SCALAR_FUN_ATTR f16 futrts_tan16(f16 x) {
return (float16)tan((float)x);
}
SCALAR_FUN_ATTR f16 futrts_acos16(f16 x) {
return (float16)acos((float)x);
}
SCALAR_FUN_ATTR f16 futrts_asin16(f16 x) {
return (float16)asin((float)x);
}
SCALAR_FUN_ATTR f16 futrts_atan16(f16 x) {
return (float16)atan((float)x);
}
SCALAR_FUN_ATTR f16 futrts_cosh16(f16 x) {
return (exp(x)+exp(-x)) / 2.0f16;
}
SCALAR_FUN_ATTR f16 futrts_sinh16(f16 x) {
return (exp(x)-exp(-x)) / 2.0f16;
}
SCALAR_FUN_ATTR f16 futrts_tanh16(f16 x) {
return futrts_sinh16(x)/futrts_cosh16(x);
}
SCALAR_FUN_ATTR f16 futrts_acosh16(f16 x) {
float16 f = x+(float16)sqrt((float)(x*x-1));
if(futrts_isfinite16(f)) return log(f);
return f;
}
SCALAR_FUN_ATTR f16 futrts_asinh16(f16 x) {
float16 f = x+(float16)sqrt((float)(x*x+1));
if(futrts_isfinite16(f)) return log(f);
return f;
}
SCALAR_FUN_ATTR f16 futrts_atanh16(f16 x) {
float16 f = (1+x)/(1-x);
if(futrts_isfinite16(f)) return log(f)/2.0f16;
return f;
}
SCALAR_FUN_ATTR f16 futrts_atan2_16(f16 x, f16 y) {
return (float16)atan2((float)x, (float)y);
}
SCALAR_FUN_ATTR f16 futrts_hypot16(f16 x, f16 y) {
return (float16)futrts_hypot32((float)x, (float)y);
}
extern "C" unmasked uniform float tgammaf(uniform float x);
SCALAR_FUN_ATTR f16 futrts_gamma16(f16 x) {
f16 res;
foreach_active (i) {
uniform f16 r = (f16)tgammaf(extract((float)x, i));
res = insert(res, i, r);
}
return res;
}
extern "C" unmasked uniform float lgammaf(uniform float x);
SCALAR_FUN_ATTR f16 futrts_lgamma16(f16 x) {
f16 res;
foreach_active (i) {
uniform f16 r = (f16)lgammaf(extract((float)x, i));
res = insert(res, i, r);
}
return res;
}
SCALAR_FUN_ATTR f16 futrts_cbrt16(f16 x) {
f16 res = (f16)futrts_cbrt32((float)x);
return res;
}
SCALAR_FUN_ATTR f16 futrts_erf16(f16 x) {
f16 res = (f16)futrts_erf32((float)x);
return res;
}
SCALAR_FUN_ATTR f16 futrts_erfc16(f16 x) {
f16 res = (f16)futrts_erfc32((float)x);
return res;
}
SCALAR_FUN_ATTR f16 fmod16(f16 x, f16 y) {
return x - y * (float16)trunc((float) (x/y));
}
SCALAR_FUN_ATTR f16 futrts_round16(f16 x) {
return (float16)round((float)x);
}
SCALAR_FUN_ATTR f16 futrts_floor16(f16 x) {
return (float16)floor((float)x);
}
SCALAR_FUN_ATTR f16 futrts_ceil16(f16 x) {
return (float16)ceil((float)x);
}
SCALAR_FUN_ATTR f16 futrts_nextafter16(f16 x, f16 y) {
return (float16)futrts_nextafter32((float)x, (float) y);
}
SCALAR_FUN_ATTR f16 futrts_lerp16(f16 v0, f16 v1, f16 t) {
return v0 + (v1 - v0) * t;
}
SCALAR_FUN_ATTR f16 futrts_ldexp16(f16 x, int32_t y) {
return futrts_ldexp32((float)x, y);
}
SCALAR_FUN_ATTR f16 futrts_copysign16(f16 x, f16 y) {
return futrts_copysign32((float)x, y);
}
SCALAR_FUN_ATTR f16 futrts_mad16(f16 a, f16 b, f16 c) {
return a * b + c;
}
SCALAR_FUN_ATTR f16 futrts_fma16(f16 a, f16 b, f16 c) {
return a * b + c;
}
#else // Assume CUDA.
SCALAR_FUN_ATTR f16 futrts_log16(f16 x) {
return hlog(x);
}
SCALAR_FUN_ATTR f16 futrts_log2_16(f16 x) {
return hlog2(x);
}
SCALAR_FUN_ATTR f16 futrts_log10_16(f16 x) {
return hlog10(x);
}
SCALAR_FUN_ATTR f16 futrts_log1p_16(f16 x) {
return (f16)log1pf((float)x);
}
SCALAR_FUN_ATTR f16 futrts_sqrt16(f16 x) {
return hsqrt(x);
}
SCALAR_FUN_ATTR f16 futrts_cbrt16(f16 x) {
return cbrtf(x);
}
SCALAR_FUN_ATTR f16 futrts_exp16(f16 x) {
return hexp(x);
}
SCALAR_FUN_ATTR f16 futrts_cos16(f16 x) {
return hcos(x);
}
SCALAR_FUN_ATTR f16 futrts_sin16(f16 x) {
return hsin(x);
}
SCALAR_FUN_ATTR f16 futrts_tan16(f16 x) {
return tanf(x);
}
SCALAR_FUN_ATTR f16 futrts_acos16(f16 x) {
return acosf(x);
}
SCALAR_FUN_ATTR f16 futrts_asin16(f16 x) {
return asinf(x);
}
SCALAR_FUN_ATTR f16 futrts_atan16(f16 x) {
return atanf(x);
}
SCALAR_FUN_ATTR f16 futrts_cosh16(f16 x) {
return coshf(x);
}
SCALAR_FUN_ATTR f16 futrts_sinh16(f16 x) {
return sinhf(x);
}
SCALAR_FUN_ATTR f16 futrts_tanh16(f16 x) {
return tanhf(x);
}
SCALAR_FUN_ATTR f16 futrts_acosh16(f16 x) {
return acoshf(x);
}
SCALAR_FUN_ATTR f16 futrts_asinh16(f16 x) {
return asinhf(x);
}
SCALAR_FUN_ATTR f16 futrts_atanh16(f16 x) {
return atanhf(x);
}
SCALAR_FUN_ATTR f16 futrts_atan2_16(f16 x, f16 y) {
return atan2f(x, y);
}
SCALAR_FUN_ATTR f16 futrts_hypot16(f16 x, f16 y) {
return hypotf(x, y);
}
SCALAR_FUN_ATTR f16 futrts_gamma16(f16 x) {
return tgammaf(x);
}
SCALAR_FUN_ATTR f16 futrts_lgamma16(f16 x) {
return lgammaf(x);
}
SCALAR_FUN_ATTR f16 futrts_erf16(f16 x) {
return erff(x);
}
SCALAR_FUN_ATTR f16 futrts_erfc16(f16 x) {
return erfcf(x);
}
SCALAR_FUN_ATTR f16 fmod16(f16 x, f16 y) {
return fmodf(x, y);
}
SCALAR_FUN_ATTR f16 futrts_round16(f16 x) {
return rintf(x);
}
SCALAR_FUN_ATTR f16 futrts_floor16(f16 x) {
return hfloor(x);
}
SCALAR_FUN_ATTR f16 futrts_ceil16(f16 x) {
return hceil(x);
}
SCALAR_FUN_ATTR f16 futrts_nextafter16(f16 x, f16 y) {
return __ushort_as_half(halfbitsnextafter(__half_as_ushort(x), __half_as_ushort(y)));
}
SCALAR_FUN_ATTR f16 futrts_lerp16(f16 v0, f16 v1, f16 t) {
return v0 + (v1 - v0) * t;
}
SCALAR_FUN_ATTR f16 futrts_ldexp16(f16 x, int32_t y) {
return futrts_ldexp32((float)x, y);
}
SCALAR_FUN_ATTR f16 futrts_copysign16(f16 x, f16 y) {
return futrts_copysign32((float)x, y);
}
SCALAR_FUN_ATTR f16 futrts_mad16(f16 a, f16 b, f16 c) {
return a * b + c;
}
SCALAR_FUN_ATTR f16 futrts_fma16(f16 a, f16 b, f16 c) {
return fmaf(a, b, c);
}
#endif
// The CUDA __half type cannot be put in unions for some reason, so we
// use bespoke conversion functions instead.
#ifdef __CUDA_ARCH__
SCALAR_FUN_ATTR int16_t futrts_to_bits16(f16 x) {
return __half_as_ushort(x);
}
SCALAR_FUN_ATTR f16 futrts_from_bits16(int16_t x) {
return __ushort_as_half(x);
}
#elif defined(ISPC)
SCALAR_FUN_ATTR int16_t futrts_to_bits16(f16 x) {
varying int16_t y = *((varying int16_t * uniform)&x);
return y;
}
SCALAR_FUN_ATTR f16 futrts_from_bits16(int16_t x) {
varying f16 y = *((varying f16 * uniform)&x);
return y;
}
#else
SCALAR_FUN_ATTR int16_t futrts_to_bits16(f16 x) {
union {
f16 f;
int16_t t;
} p;
p.f = x;
return p.t;
}
SCALAR_FUN_ATTR f16 futrts_from_bits16(int16_t x) {
union {
int16_t f;
f16 t;
} p;
p.f = x;
return p.t;
}
#endif
#else // No native f16 - emulate.
SCALAR_FUN_ATTR f16 fabs16(f16 x) {
return fabs32(x);
}
SCALAR_FUN_ATTR f16 fmax16(f16 x, f16 y) {
return fmax32(x, y);
}
SCALAR_FUN_ATTR f16 fmin16(f16 x, f16 y) {
return fmin32(x, y);
}
SCALAR_FUN_ATTR f16 fpow16(f16 x, f16 y) {
return fpow32(x, y);
}
SCALAR_FUN_ATTR bool futrts_isnan16(f16 x) {
return futrts_isnan32(x);
}
SCALAR_FUN_ATTR bool futrts_isinf16(f16 x) {
return futrts_isinf32(x);
}
SCALAR_FUN_ATTR f16 futrts_log16(f16 x) {
return futrts_log32(x);
}
SCALAR_FUN_ATTR f16 futrts_log2_16(f16 x) {
return futrts_log2_32(x);
}
SCALAR_FUN_ATTR f16 futrts_log10_16(f16 x) {
return futrts_log10_32(x);
}
SCALAR_FUN_ATTR f16 futrts_log1p_16(f16 x) {
return futrts_log1p_32(x);
}
SCALAR_FUN_ATTR f16 futrts_sqrt16(f16 x) {
return futrts_sqrt32(x);
}
SCALAR_FUN_ATTR f16 futrts_cbrt16(f16 x) {
return futrts_cbrt32(x);
}
SCALAR_FUN_ATTR f16 futrts_exp16(f16 x) {
return futrts_exp32(x);
}
SCALAR_FUN_ATTR f16 futrts_cos16(f16 x) {
return futrts_cos32(x);
}
SCALAR_FUN_ATTR f16 futrts_sin16(f16 x) {
return futrts_sin32(x);
}
SCALAR_FUN_ATTR f16 futrts_tan16(f16 x) {
return futrts_tan32(x);
}
SCALAR_FUN_ATTR f16 futrts_acos16(f16 x) {
return futrts_acos32(x);
}
SCALAR_FUN_ATTR f16 futrts_asin16(f16 x) {
return futrts_asin32(x);
}
SCALAR_FUN_ATTR f16 futrts_atan16(f16 x) {
return futrts_atan32(x);
}
SCALAR_FUN_ATTR f16 futrts_cosh16(f16 x) {
return futrts_cosh32(x);
}
SCALAR_FUN_ATTR f16 futrts_sinh16(f16 x) {
return futrts_sinh32(x);
}
SCALAR_FUN_ATTR f16 futrts_tanh16(f16 x) {
return futrts_tanh32(x);
}
SCALAR_FUN_ATTR f16 futrts_acosh16(f16 x) {
return futrts_acosh32(x);
}
SCALAR_FUN_ATTR f16 futrts_asinh16(f16 x) {
return futrts_asinh32(x);
}
SCALAR_FUN_ATTR f16 futrts_atanh16(f16 x) {
return futrts_atanh32(x);
}
SCALAR_FUN_ATTR f16 futrts_atan2_16(f16 x, f16 y) {
return futrts_atan2_32(x, y);
}
SCALAR_FUN_ATTR f16 futrts_hypot16(f16 x, f16 y) {
return futrts_hypot32(x, y);
}
SCALAR_FUN_ATTR f16 futrts_gamma16(f16 x) {
return futrts_gamma32(x);
}
SCALAR_FUN_ATTR f16 futrts_lgamma16(f16 x) {
return futrts_lgamma32(x);
}
SCALAR_FUN_ATTR f16 futrts_erf16(f16 x) {
return futrts_erf32(x);
}
SCALAR_FUN_ATTR f16 futrts_erfc16(f16 x) {
return futrts_erfc32(x);
}
SCALAR_FUN_ATTR f16 fmod16(f16 x, f16 y) {
return fmod32(x, y);
}
SCALAR_FUN_ATTR f16 futrts_round16(f16 x) {
return futrts_round32(x);
}
SCALAR_FUN_ATTR f16 futrts_floor16(f16 x) {
return futrts_floor32(x);
}
SCALAR_FUN_ATTR f16 futrts_ceil16(f16 x) {
return futrts_ceil32(x);
}
SCALAR_FUN_ATTR f16 futrts_nextafter16(f16 x, f16 y) {
return halfbits2float(halfbitsnextafter(float2halfbits(x), float2halfbits(y)));
}
SCALAR_FUN_ATTR f16 futrts_lerp16(f16 v0, f16 v1, f16 t) {
return futrts_lerp32(v0, v1, t);
}
SCALAR_FUN_ATTR f16 futrts_ldexp16(f16 x, int32_t y) {
return futrts_ldexp32(x, y);
}
SCALAR_FUN_ATTR f16 futrts_copysign16(f16 x, f16 y) {
return futrts_copysign32((float)x, y);
}
SCALAR_FUN_ATTR f16 futrts_mad16(f16 a, f16 b, f16 c) {
return futrts_mad32(a, b, c);
}
SCALAR_FUN_ATTR f16 futrts_fma16(f16 a, f16 b, f16 c) {
return futrts_fma32(a, b, c);
}
// Even when we are using an OpenCL that does not support cl_khr_fp16,
// it must still support vload_half for actually creating a
// half-precision number, which can then be efficiently converted to a
// float. Similarly for vstore_half.
#ifdef __OPENCL_VERSION__
SCALAR_FUN_ATTR int16_t futrts_to_bits16(f16 x) {
int16_t y;
// Violating strict aliasing here.
vstore_half((float)x, 0, (half*)&y);
return y;
}
SCALAR_FUN_ATTR f16 futrts_from_bits16(int16_t x) {
return (f16)vload_half(0, (half*)&x);
}
#else
SCALAR_FUN_ATTR int16_t futrts_to_bits16(f16 x) {
return (int16_t)float2halfbits(x);
}
SCALAR_FUN_ATTR f16 futrts_from_bits16(int16_t x) {
return halfbits2float((uint16_t)x);
}
SCALAR_FUN_ATTR f16 fsignum16(f16 x) {
return futrts_isnan16(x) ? x : (x > 0 ? 1 : 0) - (x < 0 ? 1 : 0);
}
#endif
#endif
SCALAR_FUN_ATTR float fpconv_f16_f16(f16 x) {
return x;
}
SCALAR_FUN_ATTR float fpconv_f16_f32(f16 x) {
return x;
}
SCALAR_FUN_ATTR f16 fpconv_f32_f16(float x) {
return (f16) x;
}
#ifdef FUTHARK_F64_ENABLED
SCALAR_FUN_ATTR double fpconv_f16_f64(f16 x) {
return (double) x;
}
#if defined(ISPC)
SCALAR_FUN_ATTR f16 fpconv_f64_f16(double x) {
return (f16) ((float)x);
}
#else
SCALAR_FUN_ATTR f16 fpconv_f64_f16(double x) {
return (f16) x;
}
#endif
#endif
// End of scalar_f16.h.