inline XMVECTOR XM_CALLCONV XMVectorLogE()

in Inc/DirectXMathVector.inl [3901:4061]


inline XMVECTOR XM_CALLCONV XMVectorLogE(FXMVECTOR V) noexcept
{
#if defined(_XM_NO_INTRINSICS_)

    XMVECTORF32 Result = { { {
            logf(V.vector4_f32[0]),
            logf(V.vector4_f32[1]),
            logf(V.vector4_f32[2]),
            logf(V.vector4_f32[3])
        } } };
    return Result.v;

#elif defined(_XM_ARM_NEON_INTRINSICS_)
    int32x4_t rawBiased = vandq_s32(vreinterpretq_s32_f32(V), g_XMInfinity);
    int32x4_t trailing = vandq_s32(vreinterpretq_s32_f32(V), g_XMQNaNTest);
    uint32x4_t isExponentZero = vceqq_s32(g_XMZero, rawBiased);

    // Compute exponent and significand for normals.
    int32x4_t biased = vshrq_n_s32(rawBiased, 23);
    int32x4_t exponentNor = vsubq_s32(biased, g_XMExponentBias);
    int32x4_t trailingNor = trailing;

    // Compute exponent and significand for subnormals.
    int32x4_t leading = Internal::GetLeadingBit(trailing);
    int32x4_t shift = vsubq_s32(g_XMNumTrailing, leading);
    int32x4_t exponentSub = vsubq_s32(g_XMSubnormalExponent, shift);
    int32x4_t trailingSub = vshlq_s32(trailing, shift);
    trailingSub = vandq_s32(trailingSub, g_XMQNaNTest);
    int32x4_t e = vbslq_s32(isExponentZero, exponentSub, exponentNor);
    int32x4_t t = vbslq_s32(isExponentZero, trailingSub, trailingNor);

    // Compute the approximation.
    int32x4_t tmp = vorrq_s32(g_XMOne, t);
    float32x4_t y = vsubq_f32(vreinterpretq_f32_s32(tmp), g_XMOne);

    float32x4_t log2 = vmlaq_f32(g_XMLogEst6, g_XMLogEst7, y);
    log2 = vmlaq_f32(g_XMLogEst5, log2, y);
    log2 = vmlaq_f32(g_XMLogEst4, log2, y);
    log2 = vmlaq_f32(g_XMLogEst3, log2, y);
    log2 = vmlaq_f32(g_XMLogEst2, log2, y);
    log2 = vmlaq_f32(g_XMLogEst1, log2, y);
    log2 = vmlaq_f32(g_XMLogEst0, log2, y);
    log2 = vmlaq_f32(vcvtq_f32_s32(e), log2, y);

    log2 = vmulq_f32(g_XMInvLgE, log2);

    //  if (x is NaN) -> QNaN
    //  else if (V is positive)
    //      if (V is infinite) -> +inf
    //      else -> log2(V)
    //  else
    //      if (V is zero) -> -inf
    //      else -> -QNaN

    uint32x4_t isInfinite = vandq_u32(vreinterpretq_u32_f32(V), g_XMAbsMask);
    isInfinite = vceqq_u32(isInfinite, g_XMInfinity);

    uint32x4_t isGreaterZero = vcgtq_s32(vreinterpretq_s32_f32(V), g_XMZero);
    uint32x4_t isNotFinite = vcgtq_s32(vreinterpretq_s32_f32(V), g_XMInfinity);
    uint32x4_t isPositive = vbicq_u32(isGreaterZero, isNotFinite);

    uint32x4_t isZero = vandq_u32(vreinterpretq_u32_f32(V), g_XMAbsMask);
    isZero = vceqq_u32(isZero, g_XMZero);

    uint32x4_t t0 = vandq_u32(vreinterpretq_u32_f32(V), g_XMQNaNTest);
    uint32x4_t t1 = vandq_u32(vreinterpretq_u32_f32(V), g_XMInfinity);
    t0 = vceqq_u32(t0, g_XMZero);
    t1 = vceqq_u32(t1, g_XMInfinity);
    uint32x4_t isNaN = vbicq_u32(t1, t0);

    float32x4_t result = vbslq_f32(isInfinite, g_XMInfinity, log2);
    float32x4_t tmp2 = vbslq_f32(isZero, g_XMNegInfinity, g_XMNegQNaN);
    result = vbslq_f32(isPositive, result, tmp2);
    result = vbslq_f32(isNaN, g_XMQNaN, result);
    return result;
#elif defined(_XM_SVML_INTRINSICS_)
    XMVECTOR Result = _mm_log_ps(V);
    return Result;
#elif defined(_XM_SSE_INTRINSICS_)
    __m128i rawBiased = _mm_and_si128(_mm_castps_si128(V), g_XMInfinity);
    __m128i trailing = _mm_and_si128(_mm_castps_si128(V), g_XMQNaNTest);
    __m128i isExponentZero = _mm_cmpeq_epi32(g_XMZero, rawBiased);

    // Compute exponent and significand for normals.
    __m128i biased = _mm_srli_epi32(rawBiased, 23);
    __m128i exponentNor = _mm_sub_epi32(biased, g_XMExponentBias);
    __m128i trailingNor = trailing;

    // Compute exponent and significand for subnormals.
    __m128i leading = Internal::GetLeadingBit(trailing);
    __m128i shift = _mm_sub_epi32(g_XMNumTrailing, leading);
    __m128i exponentSub = _mm_sub_epi32(g_XMSubnormalExponent, shift);
    __m128i trailingSub = Internal::multi_sll_epi32(trailing, shift);
    trailingSub = _mm_and_si128(trailingSub, g_XMQNaNTest);

    __m128i select0 = _mm_and_si128(isExponentZero, exponentSub);
    __m128i select1 = _mm_andnot_si128(isExponentZero, exponentNor);
    __m128i e = _mm_or_si128(select0, select1);

    select0 = _mm_and_si128(isExponentZero, trailingSub);
    select1 = _mm_andnot_si128(isExponentZero, trailingNor);
    __m128i t = _mm_or_si128(select0, select1);

    // Compute the approximation.
    __m128i tmp = _mm_or_si128(g_XMOne, t);
    __m128 y = _mm_sub_ps(_mm_castsi128_ps(tmp), g_XMOne);

    __m128 log2 = XM_FMADD_PS(g_XMLogEst7, y, g_XMLogEst6);
    log2 = XM_FMADD_PS(log2, y, g_XMLogEst5);
    log2 = XM_FMADD_PS(log2, y, g_XMLogEst4);
    log2 = XM_FMADD_PS(log2, y, g_XMLogEst3);
    log2 = XM_FMADD_PS(log2, y, g_XMLogEst2);
    log2 = XM_FMADD_PS(log2, y, g_XMLogEst1);
    log2 = XM_FMADD_PS(log2, y, g_XMLogEst0);
    log2 = XM_FMADD_PS(log2, y, _mm_cvtepi32_ps(e));

    log2 = _mm_mul_ps(g_XMInvLgE, log2);

    //  if (x is NaN) -> QNaN
    //  else if (V is positive)
    //      if (V is infinite) -> +inf
    //      else -> log2(V)
    //  else
    //      if (V is zero) -> -inf
    //      else -> -QNaN

    __m128i isInfinite = _mm_and_si128(_mm_castps_si128(V), g_XMAbsMask);
    isInfinite = _mm_cmpeq_epi32(isInfinite, g_XMInfinity);

    __m128i isGreaterZero = _mm_cmpgt_epi32(_mm_castps_si128(V), g_XMZero);
    __m128i isNotFinite = _mm_cmpgt_epi32(_mm_castps_si128(V), g_XMInfinity);
    __m128i isPositive = _mm_andnot_si128(isNotFinite, isGreaterZero);

    __m128i isZero = _mm_and_si128(_mm_castps_si128(V), g_XMAbsMask);
    isZero = _mm_cmpeq_epi32(isZero, g_XMZero);

    __m128i t0 = _mm_and_si128(_mm_castps_si128(V), g_XMQNaNTest);
    __m128i t1 = _mm_and_si128(_mm_castps_si128(V), g_XMInfinity);
    t0 = _mm_cmpeq_epi32(t0, g_XMZero);
    t1 = _mm_cmpeq_epi32(t1, g_XMInfinity);
    __m128i isNaN = _mm_andnot_si128(t0, t1);

    select0 = _mm_and_si128(isInfinite, g_XMInfinity);
    select1 = _mm_andnot_si128(isInfinite, _mm_castps_si128(log2));
    __m128i result = _mm_or_si128(select0, select1);

    select0 = _mm_and_si128(isZero, g_XMNegInfinity);
    select1 = _mm_andnot_si128(isZero, g_XMNegQNaN);
    tmp = _mm_or_si128(select0, select1);

    select0 = _mm_and_si128(isPositive, result);
    select1 = _mm_andnot_si128(isPositive, tmp);
    result = _mm_or_si128(select0, select1);

    select0 = _mm_and_si128(isNaN, g_XMQNaN);
    select1 = _mm_andnot_si128(isNaN, result);
    result = _mm_or_si128(select0, select1);

    return _mm_castsi128_ps(result);
#endif
}