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 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154
|
/*========================== begin_copyright_notice ============================
Copyright (C) 2021-2023 Intel Corporation
SPDX-License-Identifier: MIT
============================= end_copyright_notice ===========================*/
#include <cm-cl/math.h>
#include <cm-cl/vector.h>
#include "../helpers.h"
using namespace cm;
namespace {
template <bool IsSigned, int N>
CM_NODEBUG CM_INLINE vector<uint64_t, N> __impl_fptoi(vector<double, N> a) {
// vector of floats -> vector of ints
vector<uint32_t, 2 * N> LoHi = a.template format<uint32_t>();
const vector<uint32_t, N> MantissaMask((1u << 20) - 1);
const vector<uint32_t, N> ExpMask(0x7ff);
const vector<uint32_t, N> Zero(0);
const vector<uint32_t, N> Ones(0xffffffff);
const vector<uint32_t, N> One(1);
vector<uint32_t, N> Lo = LoHi.template select<N, 2>(0);
vector<uint32_t, N> Hi = LoHi.template select<N, 2>(1);
vector<uint32_t, N> Exp = (Hi >> 20) & ExpMask;
// mantissa without hidden bit
vector<uint32_t, N> LoMant = Lo;
vector<uint32_t, N> HiMant = Hi & MantissaMask;
// for normalized numbers (1 + mant/2^52) * 2 ^ (mant-1023)
vector<int32_t, N> MantShift = Exp - 1023 - 52;
vector<int32_t, N> OneShift = Exp - 1023;
auto IsNormalized = Exp == Zero;
// for denormalized numbers (0 + mant/2^52) * 2 ^ (1-1023)
MantShift.merge(One - 1023 + 1, IsNormalized);
OneShift.merge(Ones, IsNormalized);
// 64bit Shift - we rely on compiler emulation there
vector<uint64_t, N> ToShift = __impl_combineLoHi<N>(LoMant, HiMant);
vector<uint64_t, N> Shifted64 = ToShift << MantShift;
auto IsRightShift = MantShift < vector<int32_t, N>(0);
Shifted64.merge(ToShift >> -MantShift, IsRightShift);
auto IsShiftGT64 = (MantShift >= vector<int32_t, N>(64)) |
(MantShift <= vector<int32_t, N>(-64));
Shifted64.merge(vector<uint64_t, N>(0), IsShiftGT64);
vector<uint32_t, 2 * N> Shifted = Shifted64.template format<uint32_t>();
vector<uint32_t, N> LoRes = Shifted.template select<N, 2>(0);
vector<uint32_t, N> HiRes = Shifted.template select<N, 2>(1);
// add hidden One
vector<uint32_t, N> OneInLo = One << OneShift;
auto IsOneInLo =
(OneShift < vector<int32_t, N>(32)) & (OneShift >= vector<int32_t, N>(0));
LoRes.merge(LoRes + OneInLo, IsOneInLo);
vector<uint32_t, N> OneInHi = One << (OneShift - 32);
auto IsOneInHi = (OneShift >= vector<int32_t, N>(32)) &
(OneShift < vector<int32_t, N>(64));
HiRes.merge(HiRes + OneInHi, IsOneInHi);
vector<uint32_t, N> SignedBitMask(1u << 31);
vector<uint32_t, N> SignedBit = Hi & SignedBitMask;
auto FlagSignSet = (SignedBit != Zero);
auto FlagNoSignSet = (SignedBit == Zero);
// check for Exponent overflow (when sign bit set)
auto FlagExpO = (Exp > vector<uint32_t, N>(1089));
auto FlagExpUO = FlagNoSignSet & FlagExpO;
auto IsNaN = (Exp == ExpMask) & ((LoMant != Zero) | (HiMant != Zero));
if constexpr (IsSigned) {
// calculate (NOT[Lo, Hi] + 1) (integer sign negation)
vector<uint32_t, N> NegLo = ~LoRes;
vector<uint32_t, N> NegHi = ~HiRes;
auto AddC = cm::math::add_with_carry(NegLo, One);
auto AddcRes = AddC.first;
auto AddcResCB = AddC.second;
NegHi = NegHi + AddcResCB;
// if sign bit is set, alter the result with negated value
// if (FlagSignSet)
LoRes.merge(AddcRes, FlagSignSet);
HiRes.merge(NegHi, FlagSignSet);
// Here we process overflows
vector<uint32_t, N> LoOrHi = LoRes | HiRes;
auto NZ = (LoOrHi != Zero);
vector<uint32_t, N> HiHBit = HiRes & SignedBitMask;
auto NZ2 = SignedBit != HiHBit;
auto Ovrfl1 = NZ2 & NZ;
// In case of overflow, HW response is : 7fffffffffffffff
// if (Ovrfl1)
LoRes.merge(Ones, Ovrfl1);
HiRes.merge(vector<uint32_t, N>((1u << 31) - 1), Ovrfl1);
// if (FlagExpO)
LoRes.merge(Zero, FlagExpO);
HiRes.merge(vector<uint32_t, N>(1u << 31), FlagExpO);
// if (FlagExpUO)
LoRes.merge(Ones, FlagExpUO);
HiRes.merge(vector<uint32_t, N>((1u << 31) - 1), FlagExpUO);
// if (IsNaN)
LoRes.merge(Zero, IsNaN);
HiRes.merge(Zero, IsNaN);
} else {
// if (FlagSignSet)
LoRes.merge(Zero, FlagSignSet);
HiRes.merge(Zero, FlagSignSet);
// if (FlagExpUO)
LoRes.merge(Ones, FlagExpUO);
HiRes.merge(Ones, FlagExpUO);
// if (IsNaN)
LoRes.merge(Zero, IsNaN);
HiRes.merge(Zero, IsNaN);
}
return __impl_combineLoHi<N>(LoRes, HiRes);
}
} // namespace
CM_NODEBUG CM_NOINLINE extern "C" uint64_t __vc_builtin_fptosi_f64(double a) {
vector<double, 1> va = a;
return __impl_fptoi<true>(va)[0];
}
CM_NODEBUG CM_NOINLINE extern "C" uint64_t __vc_builtin_fptoui_f64(double a) {
vector<double, 1> va = a;
return __impl_fptoi<false>(va)[0];
}
#define FPTOI(WIDTH) \
CM_NODEBUG CM_NOINLINE extern "C" cl_vector<uint64_t, WIDTH> \
__vc_builtin_fptosi_v##WIDTH##f64(cl_vector<double, WIDTH> a) { \
vector<double, WIDTH> va{a}; \
return __impl_fptoi<true>(va).cl_vector(); \
} \
CM_NODEBUG CM_NOINLINE extern "C" cl_vector<uint64_t, WIDTH> \
__vc_builtin_fptoui_v##WIDTH##f64(cl_vector<double, WIDTH> a) { \
vector<double, WIDTH> va{a}; \
return __impl_fptoi<false>(va).cl_vector(); \
}
FPTOI(1)
FPTOI(2)
FPTOI(4)
FPTOI(8)
FPTOI(16)
|