| /* |
| * Copyright 2016 WebAssembly Community Group participants |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| #ifndef WABT_CONFIG_H_ |
| #define WABT_CONFIG_H_ |
| |
| /* TODO(binji): nice way to define these with WABT_ prefix? */ |
| |
| /* Whether <alloca.h> is available */ |
| #cmakedefine01 HAVE_ALLOCA_H |
| |
| /* Whether <unistd.h> is available */ |
| #cmakedefine01 HAVE_UNISTD_H |
| |
| /* Whether snprintf is defined by stdio.h */ |
| #cmakedefine01 HAVE_SNPRINTF |
| |
| /* Whether sysconf is defined by unistd.h */ |
| #cmakedefine01 HAVE_SYSCONF |
| |
| /* Whether ssize_t is defined by stddef.h */ |
| #cmakedefine01 HAVE_SSIZE_T |
| |
| /* Whether strcasecmp is defined by strings.h */ |
| #cmakedefine01 HAVE_STRCASECMP |
| |
| #cmakedefine01 COMPILER_IS_CLANG |
| #cmakedefine01 COMPILER_IS_GNU |
| #cmakedefine01 COMPILER_IS_MSVC |
| |
| #define SIZEOF_SIZE_T @SIZEOF_SIZE_T@ |
| #define SIZEOF_INT @SIZEOF_INT@ |
| #define SIZEOF_LONG @SIZEOF_LONG@ |
| #define SIZEOF_LONG_LONG @SIZEOF_LONG_LONG@ |
| |
| #if HAVE_ALLOCA_H |
| #include <alloca.h> |
| #elif COMPILER_IS_MSVC |
| #include <malloc.h> |
| #define alloca _alloca |
| #elif defined(__MINGW32__) |
| #include <malloc.h> |
| #elif defined(__FreeBSD__) |
| #include <stdlib.h> |
| #else |
| #error no alloca |
| #endif |
| |
| #if COMPILER_IS_CLANG || COMPILER_IS_GNU |
| |
| #define WABT_UNUSED __attribute__ ((unused)) |
| #define WABT_WARN_UNUSED __attribute__ ((warn_unused_result)) |
| #define WABT_INLINE inline |
| #define WABT_UNLIKELY(x) __builtin_expect(!!(x), 0) |
| #define WABT_LIKELY(x) __builtin_expect(!!(x), 1) |
| |
| #if __MINGW32__ |
| // mingw defaults to printf format specifier being ms_printf (which doesn't |
| // understand 'llu', etc.) We always want gnu_printf, and force mingw to always |
| // use mingw_printf, mingw_vprintf, etc. |
| #define WABT_PRINTF_FORMAT(format_arg, first_arg) \ |
| __attribute__((format(gnu_printf, (format_arg), (first_arg)))) |
| #else |
| #define WABT_PRINTF_FORMAT(format_arg, first_arg) \ |
| __attribute__((format(printf, (format_arg), (first_arg)))) |
| #endif |
| |
| #ifdef __cplusplus |
| #if __cplusplus >= 201103L |
| #define WABT_STATIC_ASSERT(x) static_assert((x), #x) |
| #else |
| #define WABT_STATIC_ASSERT__(x, c) \ |
| static int static_assert_##c[(x ? 0 : -1)] WABT_UNUSED |
| #define WABT_STATIC_ASSERT_(x, c) WABT_STATIC_ASSERT__(x, c) |
| #define WABT_STATIC_ASSERT(x) WABT_STATIC_ASSERT_(x, __COUNTER__) |
| #endif |
| #else |
| #define WABT_STATIC_ASSERT(x) _Static_assert((x), #x) |
| #endif |
| |
| #if SIZEOF_INT == 4 |
| #define wabt_clz_u32(x) __builtin_clz(x) |
| #define wabt_ctz_u32(x) __builtin_ctz(x) |
| #define wabt_popcount_u32(x) __builtin_popcount(x) |
| #elif SIZEOF_LONG == 4 |
| #define wabt_clz_u32(x) __builtin_clzl(x) |
| #define wabt_ctz_u32(x) __builtin_ctzl(x) |
| #define wabt_popcount_u32(x) __builtin_popcountl(x) |
| #else |
| #error "don't know how to define 32-bit builtins" |
| #endif |
| |
| #if SIZEOF_LONG == 8 |
| #define wabt_clz_u64(x) __builtin_clzl(x) |
| #define wabt_ctz_u64(x) __builtin_ctzl(x) |
| #define wabt_popcount_u64(x) __builtin_popcountl(x) |
| #elif SIZEOF_LONG_LONG == 8 |
| #define wabt_clz_u64(x) __builtin_clzll(x) |
| #define wabt_ctz_u64(x) __builtin_ctzll(x) |
| #define wabt_popcount_u64(x) __builtin_popcountll(x) |
| #else |
| #error "don't know how to define 64-bit builtins" |
| #endif |
| |
| #define WABT_UNREACHABLE __builtin_unreachable() |
| |
| #elif COMPILER_IS_MSVC |
| |
| #include <intrin.h> |
| #include <string.h> |
| |
| #define WABT_UNUSED |
| #define WABT_WARN_UNUSED _Check_return_ |
| #define WABT_INLINE __inline |
| #define WABT_STATIC_ASSERT(x) _STATIC_ASSERT(x) |
| #define WABT_UNLIKELY(x) (x) |
| #define WABT_LIKELY(x) (x) |
| #define WABT_PRINTF_FORMAT(format_arg, first_arg) |
| |
| #define WABT_UNREACHABLE __assume(0) |
| |
| __inline unsigned long wabt_clz_u32(unsigned long mask) { |
| unsigned long index; |
| _BitScanReverse(&index, mask); |
| return sizeof(unsigned long) * 8 - (index + 1); |
| } |
| |
| __inline unsigned long wabt_clz_u64(unsigned __int64 mask) { |
| #if _M_X64 |
| unsigned long index; |
| _BitScanReverse64(&index, mask); |
| return sizeof(unsigned __int64) * 8 - (index + 1); |
| #elif _M_IX86 |
| unsigned long index; |
| unsigned long high_mask; |
| memcpy(&high_mask, (unsigned char*)&mask + sizeof(unsigned long), |
| sizeof(unsigned long)); |
| if (_BitScanReverse(&index, high_mask)) { |
| return sizeof(unsigned long) * 8 - (index + 1); |
| } |
| |
| unsigned long low_mask; |
| memcpy(&low_mask, &mask, sizeof(unsigned long)); |
| _BitScanReverse(&index, low_mask); |
| return sizeof(unsigned __int64) * 8 - (index + 1); |
| #else |
| #error unexpected architecture |
| #endif |
| } |
| |
| __inline unsigned long wabt_ctz_u32(unsigned long mask) { |
| unsigned long index; |
| _BitScanForward(&index, mask); |
| return index; |
| } |
| |
| __inline unsigned long wabt_ctz_u64(unsigned __int64 mask) { |
| #if _M_X64 |
| unsigned long index; |
| _BitScanForward64(&index, mask); |
| return index; |
| #elif _M_IX86 |
| unsigned long low_mask = (unsigned long)mask; |
| if (low_mask) { |
| return wabt_ctz_u32(low_mask); |
| } |
| unsigned long high_mask; |
| memcpy(&high_mask, (unsigned char*)&mask + sizeof(unsigned long), |
| sizeof(unsigned long)); |
| return sizeof(unsigned long) * 8 + wabt_ctz_u32(high_mask); |
| #else |
| #error unexpected architecture |
| #endif |
| } |
| |
| |
| #define wabt_popcount_u32 __popcnt |
| #if _M_X64 |
| #elif _M_IX86 |
| __inline unsigned __int64 __popcnt64(unsigned __int64 value) { |
| unsigned long high_value; |
| unsigned long low_value; |
| memcpy(&high_value, (unsigned char*)&value + sizeof(unsigned long), |
| sizeof(unsigned long)); |
| memcpy(&low_value, &value, sizeof(unsigned long)); |
| return wabt_popcount_u32(high_value) + wabt_popcount_u32(low_value); |
| } |
| #else |
| #error unexpected architecture |
| #endif |
| #define wabt_popcount_u64 __popcnt64 |
| |
| #else |
| |
| #error unknown compiler |
| |
| #endif |
| |
| |
| #if COMPILER_IS_MSVC |
| |
| /* print format specifier for size_t */ |
| #if SIZEOF_SIZE_T == 4 |
| #define PRIzd "d" |
| #define PRIzx "x" |
| #elif SIZEOF_SIZE_T == 8 |
| #define PRIzd "I64d" |
| #define PRIzx "I64x" |
| #else |
| #error "weird sizeof size_t" |
| #endif |
| |
| #elif COMPILER_IS_CLANG || COMPILER_IS_GNU |
| |
| /* print format specifier for size_t */ |
| #define PRIzd "zd" |
| #define PRIzx "zx" |
| |
| #else |
| |
| #error unknown compiler |
| |
| #endif |
| |
| |
| #if HAVE_SNPRINTF |
| #define wabt_snprintf snprintf |
| #elif COMPILER_IS_MSVC |
| /* can't just use _snprintf because it doesn't always null terminate */ |
| #include <stdarg.h> |
| int wabt_snprintf(char* str, size_t size, const char* format, ...); |
| #else |
| #error no snprintf |
| #endif |
| |
| #if COMPILER_IS_MSVC |
| /* can't just use vsnprintf because it doesn't always null terminate */ |
| int wabt_vsnprintf(char* str, size_t size, const char* format, va_list ap); |
| #else |
| #define wabt_vsnprintf vsnprintf |
| #endif |
| |
| #if !HAVE_SSIZE_T |
| typedef int ssize_t; |
| #endif |
| |
| #if !HAVE_STRCASECMP |
| #if COMPILER_IS_MSVC |
| #define strcasecmp _stricmp |
| #else |
| #error no strcasecmp |
| #endif |
| #endif |
| |
| #if COMPILER_IS_MSVC && defined(_M_X64) |
| // MSVC on x64 generates uint64 -> float conversions but doesn't do |
| // round-to-nearest-ties-to-even, which is required by WebAssembly. |
| #include <emmintrin.h> |
| __inline double wabt_convert_uint64_to_double(unsigned __int64 x) { |
| __m128d result = _mm_setzero_pd(); |
| if (x & 0x8000000000000000ULL) { |
| result = _mm_cvtsi64_sd(result, (x >> 1) | (x & 1)); |
| result = _mm_add_sd(result, result); |
| } else { |
| result = _mm_cvtsi64_sd(result, x); |
| } |
| return _mm_cvtsd_f64(result); |
| } |
| |
| __inline float wabt_convert_uint64_to_float(unsigned __int64 x) { |
| __m128 result = _mm_setzero_ps(); |
| if (x & 0x8000000000000000ULL) { |
| result = _mm_cvtsi64_ss(result, (x >> 1) | (x & 1)); |
| result = _mm_add_ss(result, result); |
| } else { |
| result = _mm_cvtsi64_ss(result, x); |
| } |
| return _mm_cvtss_f32(result); |
| } |
| |
| #else |
| #define wabt_convert_uint64_to_double(x) static_cast<double>(x) |
| #define wabt_convert_uint64_to_float(x) static_cast<float>(x) |
| #endif |
| |
| #endif /* WABT_CONFIG_H_ */ |