1*fe6060f1SDimitry Andric //===- endian.h - Endianness support ----------------------------*- C++ -*-===// 2*fe6060f1SDimitry Andric // 3*fe6060f1SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*fe6060f1SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*fe6060f1SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*fe6060f1SDimitry Andric // 7*fe6060f1SDimitry Andric //===----------------------------------------------------------------------===// 8*fe6060f1SDimitry Andric // 9*fe6060f1SDimitry Andric // This file declares generic and optimized functions to swap the byte order of 10*fe6060f1SDimitry Andric // an integral type. 11*fe6060f1SDimitry Andric // 12*fe6060f1SDimitry Andric //===----------------------------------------------------------------------===// 13*fe6060f1SDimitry Andric 14*fe6060f1SDimitry Andric #ifndef ORC_RT_ENDIAN_H 15*fe6060f1SDimitry Andric #define ORC_RT_ENDIAN_H 16*fe6060f1SDimitry Andric 17*fe6060f1SDimitry Andric #include <cstddef> 18*fe6060f1SDimitry Andric #include <cstdint> 19*fe6060f1SDimitry Andric #include <type_traits> 20*fe6060f1SDimitry Andric #if defined(_MSC_VER) && !defined(_DEBUG) 21*fe6060f1SDimitry Andric #include <stdlib.h> 22*fe6060f1SDimitry Andric #endif 23*fe6060f1SDimitry Andric 24*fe6060f1SDimitry Andric #if defined(__linux__) || defined(__GNU__) || defined(__HAIKU__) || \ 25*fe6060f1SDimitry Andric defined(__Fuchsia__) || defined(__EMSCRIPTEN__) 26*fe6060f1SDimitry Andric #include <endian.h> 27*fe6060f1SDimitry Andric #elif defined(_AIX) 28*fe6060f1SDimitry Andric #include <sys/machine.h> 29*fe6060f1SDimitry Andric #elif defined(__sun) 30*fe6060f1SDimitry Andric /* Solaris provides _BIG_ENDIAN/_LITTLE_ENDIAN selector in sys/types.h */ 31*fe6060f1SDimitry Andric #include <sys/types.h> 32*fe6060f1SDimitry Andric #define BIG_ENDIAN 4321 33*fe6060f1SDimitry Andric #define LITTLE_ENDIAN 1234 34*fe6060f1SDimitry Andric #if defined(_BIG_ENDIAN) 35*fe6060f1SDimitry Andric #define BYTE_ORDER BIG_ENDIAN 36*fe6060f1SDimitry Andric #else 37*fe6060f1SDimitry Andric #define BYTE_ORDER LITTLE_ENDIAN 38*fe6060f1SDimitry Andric #endif 39*fe6060f1SDimitry Andric #elif defined(__MVS__) 40*fe6060f1SDimitry Andric #define BIG_ENDIAN 4321 41*fe6060f1SDimitry Andric #define LITTLE_ENDIAN 1234 42*fe6060f1SDimitry Andric #define BYTE_ORDER BIG_ENDIAN 43*fe6060f1SDimitry Andric #else 44*fe6060f1SDimitry Andric #if !defined(BYTE_ORDER) && !defined(_WIN32) 45*fe6060f1SDimitry Andric #include <machine/endian.h> 46*fe6060f1SDimitry Andric #endif 47*fe6060f1SDimitry Andric #endif 48*fe6060f1SDimitry Andric 49*fe6060f1SDimitry Andric namespace __orc_rt { 50*fe6060f1SDimitry Andric 51*fe6060f1SDimitry Andric /// ByteSwap_16 - This function returns a byte-swapped representation of 52*fe6060f1SDimitry Andric /// the 16-bit argument. ByteSwap_16(uint16_t value)53*fe6060f1SDimitry Andricinline uint16_t ByteSwap_16(uint16_t value) { 54*fe6060f1SDimitry Andric #if defined(_MSC_VER) && !defined(_DEBUG) 55*fe6060f1SDimitry Andric // The DLL version of the runtime lacks these functions (bug!?), but in a 56*fe6060f1SDimitry Andric // release build they're replaced with BSWAP instructions anyway. 57*fe6060f1SDimitry Andric return _byteswap_ushort(value); 58*fe6060f1SDimitry Andric #else 59*fe6060f1SDimitry Andric uint16_t Hi = value << 8; 60*fe6060f1SDimitry Andric uint16_t Lo = value >> 8; 61*fe6060f1SDimitry Andric return Hi | Lo; 62*fe6060f1SDimitry Andric #endif 63*fe6060f1SDimitry Andric } 64*fe6060f1SDimitry Andric 65*fe6060f1SDimitry Andric /// This function returns a byte-swapped representation of the 32-bit argument. ByteSwap_32(uint32_t value)66*fe6060f1SDimitry Andricinline uint32_t ByteSwap_32(uint32_t value) { 67*fe6060f1SDimitry Andric #if defined(__llvm__) || (defined(__GNUC__) && !defined(__ICC)) 68*fe6060f1SDimitry Andric return __builtin_bswap32(value); 69*fe6060f1SDimitry Andric #elif defined(_MSC_VER) && !defined(_DEBUG) 70*fe6060f1SDimitry Andric return _byteswap_ulong(value); 71*fe6060f1SDimitry Andric #else 72*fe6060f1SDimitry Andric uint32_t Byte0 = value & 0x000000FF; 73*fe6060f1SDimitry Andric uint32_t Byte1 = value & 0x0000FF00; 74*fe6060f1SDimitry Andric uint32_t Byte2 = value & 0x00FF0000; 75*fe6060f1SDimitry Andric uint32_t Byte3 = value & 0xFF000000; 76*fe6060f1SDimitry Andric return (Byte0 << 24) | (Byte1 << 8) | (Byte2 >> 8) | (Byte3 >> 24); 77*fe6060f1SDimitry Andric #endif 78*fe6060f1SDimitry Andric } 79*fe6060f1SDimitry Andric 80*fe6060f1SDimitry Andric /// This function returns a byte-swapped representation of the 64-bit argument. ByteSwap_64(uint64_t value)81*fe6060f1SDimitry Andricinline uint64_t ByteSwap_64(uint64_t value) { 82*fe6060f1SDimitry Andric #if defined(__llvm__) || (defined(__GNUC__) && !defined(__ICC)) 83*fe6060f1SDimitry Andric return __builtin_bswap64(value); 84*fe6060f1SDimitry Andric #elif defined(_MSC_VER) && !defined(_DEBUG) 85*fe6060f1SDimitry Andric return _byteswap_uint64(value); 86*fe6060f1SDimitry Andric #else 87*fe6060f1SDimitry Andric uint64_t Hi = ByteSwap_32(uint32_t(value)); 88*fe6060f1SDimitry Andric uint32_t Lo = ByteSwap_32(uint32_t(value >> 32)); 89*fe6060f1SDimitry Andric return (Hi << 32) | Lo; 90*fe6060f1SDimitry Andric #endif 91*fe6060f1SDimitry Andric } 92*fe6060f1SDimitry Andric 93*fe6060f1SDimitry Andric #if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && BYTE_ORDER == BIG_ENDIAN 94*fe6060f1SDimitry Andric constexpr bool IsBigEndianHost = true; 95*fe6060f1SDimitry Andric #else 96*fe6060f1SDimitry Andric constexpr bool IsBigEndianHost = false; 97*fe6060f1SDimitry Andric #endif 98*fe6060f1SDimitry Andric 99*fe6060f1SDimitry Andric static const bool IsLittleEndianHost = !IsBigEndianHost; 100*fe6060f1SDimitry Andric getSwappedBytes(unsigned char C)101*fe6060f1SDimitry Andricinline unsigned char getSwappedBytes(unsigned char C) { return C; } getSwappedBytes(signed char C)102*fe6060f1SDimitry Andricinline signed char getSwappedBytes(signed char C) { return C; } getSwappedBytes(char C)103*fe6060f1SDimitry Andricinline char getSwappedBytes(char C) { return C; } 104*fe6060f1SDimitry Andric getSwappedBytes(unsigned short C)105*fe6060f1SDimitry Andricinline unsigned short getSwappedBytes(unsigned short C) { 106*fe6060f1SDimitry Andric return ByteSwap_16(C); 107*fe6060f1SDimitry Andric } getSwappedBytes(signed short C)108*fe6060f1SDimitry Andricinline signed short getSwappedBytes(signed short C) { return ByteSwap_16(C); } 109*fe6060f1SDimitry Andric getSwappedBytes(unsigned int C)110*fe6060f1SDimitry Andricinline unsigned int getSwappedBytes(unsigned int C) { return ByteSwap_32(C); } getSwappedBytes(signed int C)111*fe6060f1SDimitry Andricinline signed int getSwappedBytes(signed int C) { return ByteSwap_32(C); } 112*fe6060f1SDimitry Andric getSwappedBytes(unsigned long C)113*fe6060f1SDimitry Andricinline unsigned long getSwappedBytes(unsigned long C) { 114*fe6060f1SDimitry Andric // Handle LLP64 and LP64 platforms. 115*fe6060f1SDimitry Andric return sizeof(long) == sizeof(int) ? ByteSwap_32((uint32_t)C) 116*fe6060f1SDimitry Andric : ByteSwap_64((uint64_t)C); 117*fe6060f1SDimitry Andric } getSwappedBytes(signed long C)118*fe6060f1SDimitry Andricinline signed long getSwappedBytes(signed long C) { 119*fe6060f1SDimitry Andric // Handle LLP64 and LP64 platforms. 120*fe6060f1SDimitry Andric return sizeof(long) == sizeof(int) ? ByteSwap_32((uint32_t)C) 121*fe6060f1SDimitry Andric : ByteSwap_64((uint64_t)C); 122*fe6060f1SDimitry Andric } 123*fe6060f1SDimitry Andric getSwappedBytes(unsigned long long C)124*fe6060f1SDimitry Andricinline unsigned long long getSwappedBytes(unsigned long long C) { 125*fe6060f1SDimitry Andric return ByteSwap_64(C); 126*fe6060f1SDimitry Andric } getSwappedBytes(signed long long C)127*fe6060f1SDimitry Andricinline signed long long getSwappedBytes(signed long long C) { 128*fe6060f1SDimitry Andric return ByteSwap_64(C); 129*fe6060f1SDimitry Andric } 130*fe6060f1SDimitry Andric 131*fe6060f1SDimitry Andric template <typename T> getSwappedBytes(T C)132*fe6060f1SDimitry Andricinline std::enable_if_t<std::is_enum<T>::value, T> getSwappedBytes(T C) { 133*fe6060f1SDimitry Andric return static_cast<T>( 134*fe6060f1SDimitry Andric getSwappedBytes(static_cast<std::underlying_type_t<T>>(C))); 135*fe6060f1SDimitry Andric } 136*fe6060f1SDimitry Andric swapByteOrder(T & Value)137*fe6060f1SDimitry Andrictemplate <typename T> inline void swapByteOrder(T &Value) { 138*fe6060f1SDimitry Andric Value = getSwappedBytes(Value); 139*fe6060f1SDimitry Andric } 140*fe6060f1SDimitry Andric 141*fe6060f1SDimitry Andric } // end namespace __orc_rt 142*fe6060f1SDimitry Andric 143*fe6060f1SDimitry Andric #endif // ORC_RT_ENDIAN_H 144