blob: b55323bd2fbe70aed65b9d6fc4e51980b0c530df [file]
//-------------------------------------------------------------------------------------------------------
// Copyright (C) Microsoft Corporation and contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
//-------------------------------------------------------------------------------------------------------
#pragma once
namespace Wasm
{
template<typename T>
inline T WasmMath::Shl( T aLeft, T aRight )
{
return aLeft << (aRight & (sizeof(T)*8-1));
}
template<typename T>
inline T WasmMath::Shr( T aLeft, T aRight )
{
return aLeft >> (aRight & (sizeof(T)*8-1));
}
template<typename T>
inline T WasmMath::ShrU( T aLeft, T aRight )
{
return aLeft >> (aRight & (sizeof(T)*8-1));
}
template<>
inline int WasmMath::Ctz(int value)
{
DWORD index;
if (_BitScanForward(&index, value))
{
return index;
}
return 32;
}
template<>
inline int64 WasmMath::Ctz(int64 value)
{
DWORD index;
#if TARGET_64
if (_BitScanForward64(&index, value))
{
return index;
}
#else
if (_BitScanForward(&index, (int32)value))
{
return index;
}
if (_BitScanForward(&index, (int32)(value >> 32)))
{
return index + 32;
}
#endif
return 64;
}
template<>
inline int64 WasmMath::Clz(int64 value)
{
DWORD index;
#if TARGET_64
if (_BitScanReverse64(&index, value))
{
return 63 - index;
}
#else
if (_BitScanReverse(&index, (int32)(value >> 32)))
{
return 31 - index;
}
if (_BitScanReverse(&index, (int32)value))
{
return 63 - index;
}
#endif
return 64;
}
template<>
inline int WasmMath::PopCnt(int value)
{
return ::Math::PopCnt32(value);
}
template<>
inline int64 WasmMath::PopCnt(int64 value)
{
uint64 v = (uint64)value;
// https://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetParallel
v = v - ((v >> 1) & 0x5555555555555555LL);
v = (v & 0x3333333333333333LL) + ((v >> 2) & 0x3333333333333333LL);
v = (v + (v >> 4)) & 0x0f0f0f0f0f0f0f0f;
v = (uint64)(v * 0x0101010101010101LL) >> (sizeof(uint64) - 1) * CHAR_BIT;
return (int64)v;
}
template<typename T>
inline int WasmMath::Eqz(T value)
{
return value == 0;
}
template<>
inline double WasmMath::Copysign(double aLeft, double aRight)
{
return _copysign(aLeft, aRight);
}
template<>
inline float WasmMath::Copysign(float aLeft, float aRight)
{
uint32 res = ((*(uint32*)(&aLeft) & 0x7fffffffu) | (*(uint32*)(&aRight) & 0x80000000u));
return *(float*)(&res);
}
template <typename T> bool WasmMath::LessThan(T aLeft, T aRight)
{
return aLeft < aRight;
}
template <typename T> bool WasmMath::LessOrEqual(T aLeft, T aRight)
{
return aLeft <= aRight;
}
template <typename STYPE,
typename UTYPE,
UTYPE MAX,
UTYPE NEG_ZERO,
UTYPE NEG_ONE,
WasmMath::CmpPtr<UTYPE> CMP1,
WasmMath::CmpPtr<UTYPE> CMP2>
bool WasmMath::isInRange(STYPE srcVal)
{
Assert(sizeof(STYPE) == sizeof(UTYPE));
UTYPE val = *reinterpret_cast<UTYPE*> (&srcVal);
return (CMP1(val, MAX)) || (val >= NEG_ZERO && CMP2(val, NEG_ONE));
}
template <typename STYPE> bool WasmMath::isNaN(STYPE src)
{
return src != src;
}
template<typename T>
inline T WasmMath::Trunc(T value)
{
if (value == 0.0)
{
return value;
}
else
{
T result;
if (value < 0.0)
{
result = ceil(value);
}
else
{
result = floor(value);
}
// TODO: Propagating NaN sign for now awaiting consensus on semantics
return result;
}
}
template<typename T>
inline T WasmMath::Nearest(T value)
{
if (value == 0.0)
{
return value;
}
else
{
T result;
T u = ceil(value);
T d = floor(value);
T um = fabs(value - u);
T dm = fabs(value - d);
if (um < dm || (um == dm && floor(u / 2) == u / 2))
{
result = u;
}
else
{
result = d;
}
// TODO: Propagating NaN sign for now awaiting consensus on semantics
return result;
}
}
template<>
inline int WasmMath::Rol(int aLeft, int aRight)
{
return _rotl(aLeft, aRight);
}
template<>
inline int64 WasmMath::Rol(int64 aLeft, int64 aRight)
{
return _rotl64(aLeft, (int)aRight);
}
template<>
inline int WasmMath::Ror(int aLeft, int aRight)
{
return _rotr(aLeft, aRight);
}
template<>
inline int64 WasmMath::Ror(int64 aLeft, int64 aRight)
{
return _rotr64(aLeft, (int)aRight);
}
}