1 // Copyright (c) 2015-2016 The Khronos Group Inc. 2 // 3 // Permission is hereby granted, free of charge, to any person obtaining a 4 // copy of this software and/or associated documentation files (the 5 // "Materials"), to deal in the Materials without restriction, including 6 // without limitation the rights to use, copy, modify, merge, publish, 7 // distribute, sublicense, and/or sell copies of the Materials, and to 8 // permit persons to whom the Materials are furnished to do so, subject to 9 // the following conditions: 10 // 11 // The above copyright notice and this permission notice shall be included 12 // in all copies or substantial portions of the Materials. 13 // 14 // MODIFICATIONS TO THIS FILE MAY MEAN IT NO LONGER ACCURATELY REFLECTS 15 // KHRONOS STANDARDS. THE UNMODIFIED, NORMATIVE VERSIONS OF KHRONOS 16 // SPECIFICATIONS AND HEADER INFORMATION ARE LOCATED AT 17 // https://www.khronos.org/registry/ 18 // 19 // THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 20 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 21 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 22 // IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 23 // CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 24 // TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 25 // MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. 26 27 #include "spirv_endian.h" 28 29 #include <cstring> 30 31 enum { 32 I32_ENDIAN_LITTLE = 0x03020100ul, 33 I32_ENDIAN_BIG = 0x00010203ul, 34 }; 35 36 // This constant value allows the detection of the host machine's endianness. 37 // Accessing it through the "value" member is valid due to C++11 section 3.10 38 // paragraph 10. 39 static const union { 40 unsigned char bytes[4]; 41 uint32_t value; 42 } o32_host_order = {{0, 1, 2, 3}}; 43 44 #define I32_ENDIAN_HOST (o32_host_order.value) 45 46 uint32_t spvFixWord(const uint32_t word, const spv_endianness_t endian) { 47 if ((SPV_ENDIANNESS_LITTLE == endian && I32_ENDIAN_HOST == I32_ENDIAN_BIG) || 48 (SPV_ENDIANNESS_BIG == endian && I32_ENDIAN_HOST == I32_ENDIAN_LITTLE)) { 49 return (word & 0x000000ff) << 24 | (word & 0x0000ff00) << 8 | 50 (word & 0x00ff0000) >> 8 | (word & 0xff000000) >> 24; 51 } 52 53 return word; 54 } 55 56 uint64_t spvFixDoubleWord(const uint32_t low, const uint32_t high, 57 const spv_endianness_t endian) { 58 return (uint64_t(spvFixWord(high, endian)) << 32) | spvFixWord(low, endian); 59 } 60 61 spv_result_t spvBinaryEndianness(spv_const_binary binary, 62 spv_endianness_t* pEndian) { 63 if (!binary->code || !binary->wordCount) return SPV_ERROR_INVALID_BINARY; 64 if (!pEndian) return SPV_ERROR_INVALID_POINTER; 65 66 uint8_t bytes[4]; 67 memcpy(bytes, binary->code, sizeof(uint32_t)); 68 69 if (0x03 == bytes[0] && 0x02 == bytes[1] && 0x23 == bytes[2] && 70 0x07 == bytes[3]) { 71 *pEndian = SPV_ENDIANNESS_LITTLE; 72 return SPV_SUCCESS; 73 } 74 75 if (0x07 == bytes[0] && 0x23 == bytes[1] && 0x02 == bytes[2] && 76 0x03 == bytes[3]) { 77 *pEndian = SPV_ENDIANNESS_BIG; 78 return SPV_SUCCESS; 79 } 80 81 return SPV_ERROR_INVALID_BINARY; 82 } 83 84 bool spvIsHostEndian(spv_endianness_t endian) { 85 return ((SPV_ENDIANNESS_LITTLE == endian) && 86 (I32_ENDIAN_LITTLE == I32_ENDIAN_HOST)) || 87 ((SPV_ENDIANNESS_BIG == endian) && 88 (I32_ENDIAN_BIG == I32_ENDIAN_HOST)); 89 } 90