You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1976 lines
65 KiB
1976 lines
65 KiB
/* $Id: sph_types.h 260 2011-07-21 01:02:38Z tp $ */ |
|
/** |
|
* Basic type definitions. |
|
* |
|
* This header file defines the generic integer types that will be used |
|
* for the implementation of hash functions; it also contains helper |
|
* functions which encode and decode multi-byte integer values, using |
|
* either little-endian or big-endian conventions. |
|
* |
|
* This file contains a compile-time test on the size of a byte |
|
* (the <code>unsigned char</code> C type). If bytes are not octets, |
|
* i.e. if they do not have a size of exactly 8 bits, then compilation |
|
* is aborted. Architectures where bytes are not octets are relatively |
|
* rare, even in the embedded devices market. We forbid non-octet bytes |
|
* because there is no clear convention on how octet streams are encoded |
|
* on such systems. |
|
* |
|
* ==========================(LICENSE BEGIN)============================ |
|
* |
|
* Copyright (c) 2007-2010 Projet RNRT SAPHIR |
|
* |
|
* Permission is hereby granted, free of charge, to any person obtaining |
|
* a copy of this software and associated documentation files (the |
|
* "Software"), to deal in the Software without restriction, including |
|
* without limitation the rights to use, copy, modify, merge, publish, |
|
* distribute, sublicense, and/or sell copies of the Software, and to |
|
* permit persons to whom the Software is furnished to do so, subject to |
|
* the following conditions: |
|
* |
|
* The above copyright notice and this permission notice shall be |
|
* included in all copies or substantial portions of the Software. |
|
* |
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. |
|
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY |
|
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, |
|
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE |
|
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
|
* |
|
* ===========================(LICENSE END)============================= |
|
* |
|
* @file sph_types.h |
|
* @author Thomas Pornin <thomas.pornin@cryptolog.com> |
|
*/ |
|
|
|
#ifndef SPH_TYPES_H__ |
|
#define SPH_TYPES_H__ |
|
|
|
#include <limits.h> |
|
|
|
/* |
|
* All our I/O functions are defined over octet streams. We do not know |
|
* how to handle input data if bytes are not octets. |
|
*/ |
|
#if CHAR_BIT != 8 |
|
#error This code requires 8-bit bytes |
|
#endif |
|
|
|
/* ============= BEGIN documentation block for Doxygen ============ */ |
|
|
|
#ifdef DOXYGEN_IGNORE |
|
|
|
/** @mainpage sphlib C code documentation |
|
* |
|
* @section overview Overview |
|
* |
|
* <code>sphlib</code> is a library which contains implementations of |
|
* various cryptographic hash functions. These pages have been generated |
|
* with <a href="http://www.doxygen.org/index.html">doxygen</a> and |
|
* document the API for the C implementations. |
|
* |
|
* The API is described in appropriate header files, which are available |
|
* in the "Files" section. Each hash function family has its own header, |
|
* whose name begins with <code>"sph_"</code> and contains the family |
|
* name. For instance, the API for the RIPEMD hash functions is available |
|
* in the header file <code>sph_ripemd.h</code>. |
|
* |
|
* @section principles API structure and conventions |
|
* |
|
* @subsection io Input/output conventions |
|
* |
|
* In all generality, hash functions operate over strings of bits. |
|
* Individual bits are rarely encountered in C programming or actual |
|
* communication protocols; most protocols converge on the ubiquitous |
|
* "octet" which is a group of eight bits. Data is thus expressed as a |
|
* stream of octets. The C programming language contains the notion of a |
|
* "byte", which is a data unit managed under the type <code>"unsigned |
|
* char"</code>. The C standard prescribes that a byte should hold at |
|
* least eight bits, but possibly more. Most modern architectures, even |
|
* in the embedded world, feature eight-bit bytes, i.e. map bytes to |
|
* octets. |
|
* |
|
* Nevertheless, for some of the implemented hash functions, an extra |
|
* API has been added, which allows the input of arbitrary sequences of |
|
* bits: when the computation is about to be closed, 1 to 7 extra bits |
|
* can be added. The functions for which this API is implemented include |
|
* the SHA-2 functions and all SHA-3 candidates. |
|
* |
|
* <code>sphlib</code> defines hash function which may hash octet streams, |
|
* i.e. streams of bits where the number of bits is a multiple of eight. |
|
* The data input functions in the <code>sphlib</code> API expect data |
|
* as anonymous pointers (<code>"const void *"</code>) with a length |
|
* (of type <code>"size_t"</code>) which gives the input data chunk length |
|
* in bytes. A byte is assumed to be an octet; the <code>sph_types.h</code> |
|
* header contains a compile-time test which prevents compilation on |
|
* architectures where this property is not met. |
|
* |
|
* The hash function output is also converted into bytes. All currently |
|
* implemented hash functions have an output width which is a multiple of |
|
* eight, and this is likely to remain true for new designs. |
|
* |
|
* Most hash functions internally convert input data into 32-bit of 64-bit |
|
* words, using either little-endian or big-endian conversion. The hash |
|
* output also often consists of such words, which are encoded into output |
|
* bytes with a similar endianness convention. Some hash functions have |
|
* been only loosely specified on that subject; when necessary, |
|
* <code>sphlib</code> has been tested against published "reference" |
|
* implementations in order to use the same conventions. |
|
* |
|
* @subsection shortname Function short name |
|
* |
|
* Each implemented hash function has a "short name" which is used |
|
* internally to derive the identifiers for the functions and context |
|
* structures which the function uses. For instance, MD5 has the short |
|
* name <code>"md5"</code>. Short names are listed in the next section, |
|
* for the implemented hash functions. In subsequent sections, the |
|
* short name will be assumed to be <code>"XXX"</code>: replace with the |
|
* actual hash function name to get the C identifier. |
|
* |
|
* Note: some functions within the same family share the same core |
|
* elements, such as update function or context structure. Correspondingly, |
|
* some of the defined types or functions may actually be macros which |
|
* transparently evaluate to another type or function name. |
|
* |
|
* @subsection context Context structure |
|
* |
|
* Each implemented hash fonction has its own context structure, available |
|
* under the type name <code>"sph_XXX_context"</code> for the hash function |
|
* with short name <code>"XXX"</code>. This structure holds all needed |
|
* state for a running hash computation. |
|
* |
|
* The contents of these structures are meant to be opaque, and private |
|
* to the implementation. However, these contents are specified in the |
|
* header files so that application code which uses <code>sphlib</code> |
|
* may access the size of those structures. |
|
* |
|
* The caller is responsible for allocating the context structure, |
|
* whether by dynamic allocation (<code>malloc()</code> or equivalent), |
|
* static allocation (a global permanent variable), as an automatic |
|
* variable ("on the stack"), or by any other mean which ensures proper |
|
* structure alignment. <code>sphlib</code> code performs no dynamic |
|
* allocation by itself. |
|
* |
|
* The context must be initialized before use, using the |
|
* <code>sph_XXX_init()</code> function. This function sets the context |
|
* state to proper initial values for hashing. |
|
* |
|
* Since all state data is contained within the context structure, |
|
* <code>sphlib</code> is thread-safe and reentrant: several hash |
|
* computations may be performed in parallel, provided that they do not |
|
* operate on the same context. Moreover, a running computation can be |
|
* cloned by copying the context (with a simple <code>memcpy()</code>): |
|
* the context and its clone are then independant and may be updated |
|
* with new data and/or closed without interfering with each other. |
|
* Similarly, a context structure can be moved in memory at will: |
|
* context structures contain no pointer, in particular no pointer to |
|
* themselves. |
|
* |
|
* @subsection dataio Data input |
|
* |
|
* Hashed data is input with the <code>sph_XXX()</code> fonction, which |
|
* takes as parameters a pointer to the context, a pointer to the data |
|
* to hash, and the number of data bytes to hash. The context is updated |
|
* with the new data. |
|
* |
|
* Data can be input in one or several calls, with arbitrary input lengths. |
|
* However, it is best, performance wise, to input data by relatively big |
|
* chunks (say a few kilobytes), because this allows <code>sphlib</code> to |
|
* optimize things and avoid internal copying. |
|
* |
|
* When all data has been input, the context can be closed with |
|
* <code>sph_XXX_close()</code>. The hash output is computed and written |
|
* into the provided buffer. The caller must take care to provide a |
|
* buffer of appropriate length; e.g., when using SHA-1, the output is |
|
* a 20-byte word, therefore the output buffer must be at least 20-byte |
|
* long. |
|
* |
|
* For some hash functions, the <code>sph_XXX_addbits_and_close()</code> |
|
* function can be used instead of <code>sph_XXX_close()</code>. This |
|
* function can take a few extra <strong>bits</strong> to be added at |
|
* the end of the input message. This allows hashing messages with a |
|
* bit length which is not a multiple of 8. The extra bits are provided |
|
* as an unsigned integer value, and a bit count. The bit count must be |
|
* between 0 and 7, inclusive. The extra bits are provided as bits 7 to |
|
* 0 (bits of numerical value 128, 64, 32... downto 0), in that order. |
|
* For instance, to add three bits of value 1, 1 and 0, the unsigned |
|
* integer will have value 192 (1*128 + 1*64 + 0*32) and the bit count |
|
* will be 3. |
|
* |
|
* The <code>SPH_SIZE_XXX</code> macro is defined for each hash function; |
|
* it evaluates to the function output size, expressed in bits. For instance, |
|
* <code>SPH_SIZE_sha1</code> evaluates to <code>160</code>. |
|
* |
|
* When closed, the context is automatically reinitialized and can be |
|
* immediately used for another computation. It is not necessary to call |
|
* <code>sph_XXX_init()</code> after a close. Note that |
|
* <code>sph_XXX_init()</code> can still be called to "reset" a context, |
|
* i.e. forget previously input data, and get back to the initial state. |
|
* |
|
* @subsection alignment Data alignment |
|
* |
|
* "Alignment" is a property of data, which is said to be "properly |
|
* aligned" when its emplacement in memory is such that the data can |
|
* be optimally read by full words. This depends on the type of access; |
|
* basically, some hash functions will read data by 32-bit or 64-bit |
|
* words. <code>sphlib</code> does not mandate such alignment for input |
|
* data, but using aligned data can substantially improve performance. |
|
* |
|
* As a rule, it is best to input data by chunks whose length (in bytes) |
|
* is a multiple of eight, and which begins at "generally aligned" |
|
* addresses, such as the base address returned by a call to |
|
* <code>malloc()</code>. |
|
* |
|
* @section functions Implemented functions |
|
* |
|
* We give here the list of implemented functions. They are grouped by |
|
* family; to each family corresponds a specific header file. Each |
|
* individual function has its associated "short name". Please refer to |
|
* the documentation for that header file to get details on the hash |
|
* function denomination and provenance. |
|
* |
|
* Note: the functions marked with a '(64)' in the list below are |
|
* available only if the C compiler provides an integer type of length |
|
* 64 bits or more. Such a type is mandatory in the latest C standard |
|
* (ISO 9899:1999, aka "C99") and is present in several older compilers |
|
* as well, so chances are that such a type is available. |
|
* |
|
* - HAVAL family: file <code>sph_haval.h</code> |
|
* - HAVAL-128/3 (128-bit, 3 passes): short name: <code>haval128_3</code> |
|
* - HAVAL-128/4 (128-bit, 4 passes): short name: <code>haval128_4</code> |
|
* - HAVAL-128/5 (128-bit, 5 passes): short name: <code>haval128_5</code> |
|
* - HAVAL-160/3 (160-bit, 3 passes): short name: <code>haval160_3</code> |
|
* - HAVAL-160/4 (160-bit, 4 passes): short name: <code>haval160_4</code> |
|
* - HAVAL-160/5 (160-bit, 5 passes): short name: <code>haval160_5</code> |
|
* - HAVAL-192/3 (192-bit, 3 passes): short name: <code>haval192_3</code> |
|
* - HAVAL-192/4 (192-bit, 4 passes): short name: <code>haval192_4</code> |
|
* - HAVAL-192/5 (192-bit, 5 passes): short name: <code>haval192_5</code> |
|
* - HAVAL-224/3 (224-bit, 3 passes): short name: <code>haval224_3</code> |
|
* - HAVAL-224/4 (224-bit, 4 passes): short name: <code>haval224_4</code> |
|
* - HAVAL-224/5 (224-bit, 5 passes): short name: <code>haval224_5</code> |
|
* - HAVAL-256/3 (256-bit, 3 passes): short name: <code>haval256_3</code> |
|
* - HAVAL-256/4 (256-bit, 4 passes): short name: <code>haval256_4</code> |
|
* - HAVAL-256/5 (256-bit, 5 passes): short name: <code>haval256_5</code> |
|
* - MD2: file <code>sph_md2.h</code>, short name: <code>md2</code> |
|
* - MD4: file <code>sph_md4.h</code>, short name: <code>md4</code> |
|
* - MD5: file <code>sph_md5.h</code>, short name: <code>md5</code> |
|
* - PANAMA: file <code>sph_panama.h</code>, short name: <code>panama</code> |
|
* - RadioGatun family: file <code>sph_radiogatun.h</code> |
|
* - RadioGatun[32]: short name: <code>radiogatun32</code> |
|
* - RadioGatun[64]: short name: <code>radiogatun64</code> (64) |
|
* - RIPEMD family: file <code>sph_ripemd.h</code> |
|
* - RIPEMD: short name: <code>ripemd</code> |
|
* - RIPEMD-128: short name: <code>ripemd128</code> |
|
* - RIPEMD-160: short name: <code>ripemd160</code> |
|
* - SHA-0: file <code>sph_sha0.h</code>, short name: <code>sha0</code> |
|
* - SHA-1: file <code>sph_sha1.h</code>, short name: <code>sha1</code> |
|
* - SHA-2 family, 32-bit hashes: file <code>sph_sha2.h</code> |
|
* - SHA-224: short name: <code>sha224</code> |
|
* - SHA-256: short name: <code>sha256</code> |
|
* - SHA-384: short name: <code>sha384</code> (64) |
|
* - SHA-512: short name: <code>sha512</code> (64) |
|
* - Tiger family: file <code>sph_tiger.h</code> |
|
* - Tiger: short name: <code>tiger</code> (64) |
|
* - Tiger2: short name: <code>tiger2</code> (64) |
|
* - WHIRLPOOL family: file <code>sph_whirlpool.h</code> |
|
* - WHIRLPOOL-0: short name: <code>whirlpool0</code> (64) |
|
* - WHIRLPOOL-1: short name: <code>whirlpool1</code> (64) |
|
* - WHIRLPOOL: short name: <code>whirlpool</code> (64) |
|
* |
|
* The fourteen second-round SHA-3 candidates are also implemented; |
|
* when applicable, the implementations follow the "final" specifications |
|
* as published for the third round of the SHA-3 competition (BLAKE, |
|
* Groestl, JH, Keccak and Skein have been tweaked for third round). |
|
* |
|
* - BLAKE family: file <code>sph_blake.h</code> |
|
* - BLAKE-224: short name: <code>blake224</code> |
|
* - BLAKE-256: short name: <code>blake256</code> |
|
* - BLAKE-384: short name: <code>blake384</code> |
|
* - BLAKE-512: short name: <code>blake512</code> |
|
* - BMW (Blue Midnight Wish) family: file <code>sph_bmw.h</code> |
|
* - BMW-224: short name: <code>bmw224</code> |
|
* - BMW-256: short name: <code>bmw256</code> |
|
* - BMW-384: short name: <code>bmw384</code> (64) |
|
* - BMW-512: short name: <code>bmw512</code> (64) |
|
* - CubeHash family: file <code>sph_cubehash.h</code> (specified as |
|
* CubeHash16/32 in the CubeHash specification) |
|
* - CubeHash-224: short name: <code>cubehash224</code> |
|
* - CubeHash-256: short name: <code>cubehash256</code> |
|
* - CubeHash-384: short name: <code>cubehash384</code> |
|
* - CubeHash-512: short name: <code>cubehash512</code> |
|
* - ECHO family: file <code>sph_echo.h</code> |
|
* - ECHO-224: short name: <code>echo224</code> |
|
* - ECHO-256: short name: <code>echo256</code> |
|
* - ECHO-384: short name: <code>echo384</code> |
|
* - ECHO-512: short name: <code>echo512</code> |
|
* - Fugue family: file <code>sph_fugue.h</code> |
|
* - Fugue-224: short name: <code>fugue224</code> |
|
* - Fugue-256: short name: <code>fugue256</code> |
|
* - Fugue-384: short name: <code>fugue384</code> |
|
* - Fugue-512: short name: <code>fugue512</code> |
|
* - Groestl family: file <code>sph_groestl.h</code> |
|
* - Groestl-224: short name: <code>groestl224</code> |
|
* - Groestl-256: short name: <code>groestl256</code> |
|
* - Groestl-384: short name: <code>groestl384</code> |
|
* - Groestl-512: short name: <code>groestl512</code> |
|
* - Hamsi family: file <code>sph_hamsi.h</code> |
|
* - Hamsi-224: short name: <code>hamsi224</code> |
|
* - Hamsi-256: short name: <code>hamsi256</code> |
|
* - Hamsi-384: short name: <code>hamsi384</code> |
|
* - Hamsi-512: short name: <code>hamsi512</code> |
|
* - JH family: file <code>sph_jh.h</code> |
|
* - JH-224: short name: <code>jh224</code> |
|
* - JH-256: short name: <code>jh256</code> |
|
* - JH-384: short name: <code>jh384</code> |
|
* - JH-512: short name: <code>jh512</code> |
|
* - Keccak family: file <code>sph_keccak.h</code> |
|
* - Keccak-224: short name: <code>keccak224</code> |
|
* - Keccak-256: short name: <code>keccak256</code> |
|
* - Keccak-384: short name: <code>keccak384</code> |
|
* - Keccak-512: short name: <code>keccak512</code> |
|
* - Luffa family: file <code>sph_luffa.h</code> |
|
* - Luffa-224: short name: <code>luffa224</code> |
|
* - Luffa-256: short name: <code>luffa256</code> |
|
* - Luffa-384: short name: <code>luffa384</code> |
|
* - Luffa-512: short name: <code>luffa512</code> |
|
* - Shabal family: file <code>sph_shabal.h</code> |
|
* - Shabal-192: short name: <code>shabal192</code> |
|
* - Shabal-224: short name: <code>shabal224</code> |
|
* - Shabal-256: short name: <code>shabal256</code> |
|
* - Shabal-384: short name: <code>shabal384</code> |
|
* - Shabal-512: short name: <code>shabal512</code> |
|
* - SHAvite-3 family: file <code>sph_shavite.h</code> |
|
* - SHAvite-224 (nominally "SHAvite-3 with 224-bit output"): |
|
* short name: <code>shabal224</code> |
|
* - SHAvite-256 (nominally "SHAvite-3 with 256-bit output"): |
|
* short name: <code>shabal256</code> |
|
* - SHAvite-384 (nominally "SHAvite-3 with 384-bit output"): |
|
* short name: <code>shabal384</code> |
|
* - SHAvite-512 (nominally "SHAvite-3 with 512-bit output"): |
|
* short name: <code>shabal512</code> |
|
* - SIMD family: file <code>sph_simd.h</code> |
|
* - SIMD-224: short name: <code>simd224</code> |
|
* - SIMD-256: short name: <code>simd256</code> |
|
* - SIMD-384: short name: <code>simd384</code> |
|
* - SIMD-512: short name: <code>simd512</code> |
|
* - Skein family: file <code>sph_skein.h</code> |
|
* - Skein-224 (nominally specified as Skein-512-224): short name: |
|
* <code>skein224</code> (64) |
|
* - Skein-256 (nominally specified as Skein-512-256): short name: |
|
* <code>skein256</code> (64) |
|
* - Skein-384 (nominally specified as Skein-512-384): short name: |
|
* <code>skein384</code> (64) |
|
* - Skein-512 (nominally specified as Skein-512-512): short name: |
|
* <code>skein512</code> (64) |
|
* |
|
* For the second-round SHA-3 candidates, the functions are as specified |
|
* for round 2, i.e. with the "tweaks" that some candidates added |
|
* between round 1 and round 2. Also, some of the submitted packages for |
|
* round 2 contained errors, in the specification, reference code, or |
|
* both. <code>sphlib</code> implements the corrected versions. |
|
*/ |
|
|
|
/** @hideinitializer |
|
* Unsigned integer type whose length is at least 32 bits; on most |
|
* architectures, it will have a width of exactly 32 bits. Unsigned C |
|
* types implement arithmetics modulo a power of 2; use the |
|
* <code>SPH_T32()</code> macro to ensure that the value is truncated |
|
* to exactly 32 bits. Unless otherwise specified, all macros and |
|
* functions which accept <code>sph_u32</code> values assume that these |
|
* values fit on 32 bits, i.e. do not exceed 2^32-1, even on architectures |
|
* where <code>sph_u32</code> is larger than that. |
|
*/ |
|
typedef __arch_dependant__ sph_u32; |
|
|
|
/** @hideinitializer |
|
* Signed integer type corresponding to <code>sph_u32</code>; it has |
|
* width 32 bits or more. |
|
*/ |
|
typedef __arch_dependant__ sph_s32; |
|
|
|
/** @hideinitializer |
|
* Unsigned integer type whose length is at least 64 bits; on most |
|
* architectures which feature such a type, it will have a width of |
|
* exactly 64 bits. C99-compliant platform will have this type; it |
|
* is also defined when the GNU compiler (gcc) is used, and on |
|
* platforms where <code>unsigned long</code> is large enough. If this |
|
* type is not available, then some hash functions which depends on |
|
* a 64-bit type will not be available (most notably SHA-384, SHA-512, |
|
* Tiger and WHIRLPOOL). |
|
*/ |
|
typedef __arch_dependant__ sph_u64; |
|
|
|
/** @hideinitializer |
|
* Signed integer type corresponding to <code>sph_u64</code>; it has |
|
* width 64 bits or more. |
|
*/ |
|
typedef __arch_dependant__ sph_s64; |
|
|
|
/** |
|
* This macro expands the token <code>x</code> into a suitable |
|
* constant expression of type <code>sph_u32</code>. Depending on |
|
* how this type is defined, a suffix such as <code>UL</code> may |
|
* be appended to the argument. |
|
* |
|
* @param x the token to expand into a suitable constant expression |
|
*/ |
|
#define SPH_C32(x) |
|
|
|
/** |
|
* Truncate a 32-bit value to exactly 32 bits. On most systems, this is |
|
* a no-op, recognized as such by the compiler. |
|
* |
|
* @param x the value to truncate (of type <code>sph_u32</code>) |
|
*/ |
|
#define SPH_T32(x) |
|
|
|
/** |
|
* Rotate a 32-bit value by a number of bits to the left. The rotate |
|
* count must reside between 1 and 31. This macro assumes that its |
|
* first argument fits in 32 bits (no extra bit allowed on machines where |
|
* <code>sph_u32</code> is wider); both arguments may be evaluated |
|
* several times. |
|
* |
|
* @param x the value to rotate (of type <code>sph_u32</code>) |
|
* @param n the rotation count (between 1 and 31, inclusive) |
|
*/ |
|
#define SPH_ROTL32(x, n) |
|
|
|
/** |
|
* Rotate a 32-bit value by a number of bits to the left. The rotate |
|
* count must reside between 1 and 31. This macro assumes that its |
|
* first argument fits in 32 bits (no extra bit allowed on machines where |
|
* <code>sph_u32</code> is wider); both arguments may be evaluated |
|
* several times. |
|
* |
|
* @param x the value to rotate (of type <code>sph_u32</code>) |
|
* @param n the rotation count (between 1 and 31, inclusive) |
|
*/ |
|
#define SPH_ROTR32(x, n) |
|
|
|
/** |
|
* This macro is defined on systems for which a 64-bit type has been |
|
* detected, and is used for <code>sph_u64</code>. |
|
*/ |
|
#define SPH_64 |
|
|
|
/** |
|
* This macro is defined on systems for the "native" integer size is |
|
* 64 bits (64-bit values fit in one register). |
|
*/ |
|
#define SPH_64_TRUE |
|
|
|
/** |
|
* This macro expands the token <code>x</code> into a suitable |
|
* constant expression of type <code>sph_u64</code>. Depending on |
|
* how this type is defined, a suffix such as <code>ULL</code> may |
|
* be appended to the argument. This macro is defined only if a |
|
* 64-bit type was detected and used for <code>sph_u64</code>. |
|
* |
|
* @param x the token to expand into a suitable constant expression |
|
*/ |
|
#define SPH_C64(x) |
|
|
|
/** |
|
* Truncate a 64-bit value to exactly 64 bits. On most systems, this is |
|
* a no-op, recognized as such by the compiler. This macro is defined only |
|
* if a 64-bit type was detected and used for <code>sph_u64</code>. |
|
* |
|
* @param x the value to truncate (of type <code>sph_u64</code>) |
|
*/ |
|
#define SPH_T64(x) |
|
|
|
/** |
|
* Rotate a 64-bit value by a number of bits to the left. The rotate |
|
* count must reside between 1 and 63. This macro assumes that its |
|
* first argument fits in 64 bits (no extra bit allowed on machines where |
|
* <code>sph_u64</code> is wider); both arguments may be evaluated |
|
* several times. This macro is defined only if a 64-bit type was detected |
|
* and used for <code>sph_u64</code>. |
|
* |
|
* @param x the value to rotate (of type <code>sph_u64</code>) |
|
* @param n the rotation count (between 1 and 63, inclusive) |
|
*/ |
|
#define SPH_ROTL64(x, n) |
|
|
|
/** |
|
* Rotate a 64-bit value by a number of bits to the left. The rotate |
|
* count must reside between 1 and 63. This macro assumes that its |
|
* first argument fits in 64 bits (no extra bit allowed on machines where |
|
* <code>sph_u64</code> is wider); both arguments may be evaluated |
|
* several times. This macro is defined only if a 64-bit type was detected |
|
* and used for <code>sph_u64</code>. |
|
* |
|
* @param x the value to rotate (of type <code>sph_u64</code>) |
|
* @param n the rotation count (between 1 and 63, inclusive) |
|
*/ |
|
#define SPH_ROTR64(x, n) |
|
|
|
/** |
|
* This macro evaluates to <code>inline</code> or an equivalent construction, |
|
* if available on the compilation platform, or to nothing otherwise. This |
|
* is used to declare inline functions, for which the compiler should |
|
* endeavour to include the code directly in the caller. Inline functions |
|
* are typically defined in header files as replacement for macros. |
|
*/ |
|
#define SPH_INLINE |
|
|
|
/** |
|
* This macro is defined if the platform has been detected as using |
|
* little-endian convention. This implies that the <code>sph_u32</code> |
|
* type (and the <code>sph_u64</code> type also, if it is defined) has |
|
* an exact width (i.e. exactly 32-bit, respectively 64-bit). |
|
*/ |
|
#define SPH_LITTLE_ENDIAN |
|
|
|
/** |
|
* This macro is defined if the platform has been detected as using |
|
* big-endian convention. This implies that the <code>sph_u32</code> |
|
* type (and the <code>sph_u64</code> type also, if it is defined) has |
|
* an exact width (i.e. exactly 32-bit, respectively 64-bit). |
|
*/ |
|
#define SPH_BIG_ENDIAN |
|
|
|
/** |
|
* This macro is defined if 32-bit words (and 64-bit words, if defined) |
|
* can be read from and written to memory efficiently in little-endian |
|
* convention. This is the case for little-endian platforms, and also |
|
* for the big-endian platforms which have special little-endian access |
|
* opcodes (e.g. Ultrasparc). |
|
*/ |
|
#define SPH_LITTLE_FAST |
|
|
|
/** |
|
* This macro is defined if 32-bit words (and 64-bit words, if defined) |
|
* can be read from and written to memory efficiently in big-endian |
|
* convention. This is the case for little-endian platforms, and also |
|
* for the little-endian platforms which have special big-endian access |
|
* opcodes. |
|
*/ |
|
#define SPH_BIG_FAST |
|
|
|
/** |
|
* On some platforms, this macro is defined to an unsigned integer type |
|
* into which pointer values may be cast. The resulting value can then |
|
* be tested for being a multiple of 2, 4 or 8, indicating an aligned |
|
* pointer for, respectively, 16-bit, 32-bit or 64-bit memory accesses. |
|
*/ |
|
#define SPH_UPTR |
|
|
|
/** |
|
* When defined, this macro indicates that unaligned memory accesses |
|
* are possible with only a minor penalty, and thus should be prefered |
|
* over strategies which first copy data to an aligned buffer. |
|
*/ |
|
#define SPH_UNALIGNED |
|
|
|
/** |
|
* Byte-swap a 32-bit word (i.e. <code>0x12345678</code> becomes |
|
* <code>0x78563412</code>). This is an inline function which resorts |
|
* to inline assembly on some platforms, for better performance. |
|
* |
|
* @param x the 32-bit value to byte-swap |
|
* @return the byte-swapped value |
|
*/ |
|
static inline sph_u32 sph_bswap32(sph_u32 x); |
|
|
|
/** |
|
* Byte-swap a 64-bit word. This is an inline function which resorts |
|
* to inline assembly on some platforms, for better performance. This |
|
* function is defined only if a suitable 64-bit type was found for |
|
* <code>sph_u64</code> |
|
* |
|
* @param x the 64-bit value to byte-swap |
|
* @return the byte-swapped value |
|
*/ |
|
static inline sph_u64 sph_bswap64(sph_u64 x); |
|
|
|
/** |
|
* Decode a 16-bit unsigned value from memory, in little-endian convention |
|
* (least significant byte comes first). |
|
* |
|
* @param src the source address |
|
* @return the decoded value |
|
*/ |
|
static inline unsigned sph_dec16le(const void *src); |
|
|
|
/** |
|
* Encode a 16-bit unsigned value into memory, in little-endian convention |
|
* (least significant byte comes first). |
|
* |
|
* @param dst the destination buffer |
|
* @param val the value to encode |
|
*/ |
|
static inline void sph_enc16le(void *dst, unsigned val); |
|
|
|
/** |
|
* Decode a 16-bit unsigned value from memory, in big-endian convention |
|
* (most significant byte comes first). |
|
* |
|
* @param src the source address |
|
* @return the decoded value |
|
*/ |
|
static inline unsigned sph_dec16be(const void *src); |
|
|
|
/** |
|
* Encode a 16-bit unsigned value into memory, in big-endian convention |
|
* (most significant byte comes first). |
|
* |
|
* @param dst the destination buffer |
|
* @param val the value to encode |
|
*/ |
|
static inline void sph_enc16be(void *dst, unsigned val); |
|
|
|
/** |
|
* Decode a 32-bit unsigned value from memory, in little-endian convention |
|
* (least significant byte comes first). |
|
* |
|
* @param src the source address |
|
* @return the decoded value |
|
*/ |
|
static inline sph_u32 sph_dec32le(const void *src); |
|
|
|
/** |
|
* Decode a 32-bit unsigned value from memory, in little-endian convention |
|
* (least significant byte comes first). This function assumes that the |
|
* source address is suitably aligned for a direct access, if the platform |
|
* supports such things; it can thus be marginally faster than the generic |
|
* <code>sph_dec32le()</code> function. |
|
* |
|
* @param src the source address |
|
* @return the decoded value |
|
*/ |
|
static inline sph_u32 sph_dec32le_aligned(const void *src); |
|
|
|
/** |
|
* Encode a 32-bit unsigned value into memory, in little-endian convention |
|
* (least significant byte comes first). |
|
* |
|
* @param dst the destination buffer |
|
* @param val the value to encode |
|
*/ |
|
static inline void sph_enc32le(void *dst, sph_u32 val); |
|
|
|
/** |
|
* Encode a 32-bit unsigned value into memory, in little-endian convention |
|
* (least significant byte comes first). This function assumes that the |
|
* destination address is suitably aligned for a direct access, if the |
|
* platform supports such things; it can thus be marginally faster than |
|
* the generic <code>sph_enc32le()</code> function. |
|
* |
|
* @param dst the destination buffer |
|
* @param val the value to encode |
|
*/ |
|
static inline void sph_enc32le_aligned(void *dst, sph_u32 val); |
|
|
|
/** |
|
* Decode a 32-bit unsigned value from memory, in big-endian convention |
|
* (most significant byte comes first). |
|
* |
|
* @param src the source address |
|
* @return the decoded value |
|
*/ |
|
static inline sph_u32 sph_dec32be(const void *src); |
|
|
|
/** |
|
* Decode a 32-bit unsigned value from memory, in big-endian convention |
|
* (most significant byte comes first). This function assumes that the |
|
* source address is suitably aligned for a direct access, if the platform |
|
* supports such things; it can thus be marginally faster than the generic |
|
* <code>sph_dec32be()</code> function. |
|
* |
|
* @param src the source address |
|
* @return the decoded value |
|
*/ |
|
static inline sph_u32 sph_dec32be_aligned(const void *src); |
|
|
|
/** |
|
* Encode a 32-bit unsigned value into memory, in big-endian convention |
|
* (most significant byte comes first). |
|
* |
|
* @param dst the destination buffer |
|
* @param val the value to encode |
|
*/ |
|
static inline void sph_enc32be(void *dst, sph_u32 val); |
|
|
|
/** |
|
* Encode a 32-bit unsigned value into memory, in big-endian convention |
|
* (most significant byte comes first). This function assumes that the |
|
* destination address is suitably aligned for a direct access, if the |
|
* platform supports such things; it can thus be marginally faster than |
|
* the generic <code>sph_enc32be()</code> function. |
|
* |
|
* @param dst the destination buffer |
|
* @param val the value to encode |
|
*/ |
|
static inline void sph_enc32be_aligned(void *dst, sph_u32 val); |
|
|
|
/** |
|
* Decode a 64-bit unsigned value from memory, in little-endian convention |
|
* (least significant byte comes first). This function is defined only |
|
* if a suitable 64-bit type was detected and used for <code>sph_u64</code>. |
|
* |
|
* @param src the source address |
|
* @return the decoded value |
|
*/ |
|
static inline sph_u64 sph_dec64le(const void *src); |
|
|
|
/** |
|
* Decode a 64-bit unsigned value from memory, in little-endian convention |
|
* (least significant byte comes first). This function assumes that the |
|
* source address is suitably aligned for a direct access, if the platform |
|
* supports such things; it can thus be marginally faster than the generic |
|
* <code>sph_dec64le()</code> function. This function is defined only |
|
* if a suitable 64-bit type was detected and used for <code>sph_u64</code>. |
|
* |
|
* @param src the source address |
|
* @return the decoded value |
|
*/ |
|
static inline sph_u64 sph_dec64le_aligned(const void *src); |
|
|
|
/** |
|
* Encode a 64-bit unsigned value into memory, in little-endian convention |
|
* (least significant byte comes first). This function is defined only |
|
* if a suitable 64-bit type was detected and used for <code>sph_u64</code>. |
|
* |
|
* @param dst the destination buffer |
|
* @param val the value to encode |
|
*/ |
|
static inline void sph_enc64le(void *dst, sph_u64 val); |
|
|
|
/** |
|
* Encode a 64-bit unsigned value into memory, in little-endian convention |
|
* (least significant byte comes first). This function assumes that the |
|
* destination address is suitably aligned for a direct access, if the |
|
* platform supports such things; it can thus be marginally faster than |
|
* the generic <code>sph_enc64le()</code> function. This function is defined |
|
* only if a suitable 64-bit type was detected and used for |
|
* <code>sph_u64</code>. |
|
* |
|
* @param dst the destination buffer |
|
* @param val the value to encode |
|
*/ |
|
static inline void sph_enc64le_aligned(void *dst, sph_u64 val); |
|
|
|
/** |
|
* Decode a 64-bit unsigned value from memory, in big-endian convention |
|
* (most significant byte comes first). This function is defined only |
|
* if a suitable 64-bit type was detected and used for <code>sph_u64</code>. |
|
* |
|
* @param src the source address |
|
* @return the decoded value |
|
*/ |
|
static inline sph_u64 sph_dec64be(const void *src); |
|
|
|
/** |
|
* Decode a 64-bit unsigned value from memory, in big-endian convention |
|
* (most significant byte comes first). This function assumes that the |
|
* source address is suitably aligned for a direct access, if the platform |
|
* supports such things; it can thus be marginally faster than the generic |
|
* <code>sph_dec64be()</code> function. This function is defined only |
|
* if a suitable 64-bit type was detected and used for <code>sph_u64</code>. |
|
* |
|
* @param src the source address |
|
* @return the decoded value |
|
*/ |
|
static inline sph_u64 sph_dec64be_aligned(const void *src); |
|
|
|
/** |
|
* Encode a 64-bit unsigned value into memory, in big-endian convention |
|
* (most significant byte comes first). This function is defined only |
|
* if a suitable 64-bit type was detected and used for <code>sph_u64</code>. |
|
* |
|
* @param dst the destination buffer |
|
* @param val the value to encode |
|
*/ |
|
static inline void sph_enc64be(void *dst, sph_u64 val); |
|
|
|
/** |
|
* Encode a 64-bit unsigned value into memory, in big-endian convention |
|
* (most significant byte comes first). This function assumes that the |
|
* destination address is suitably aligned for a direct access, if the |
|
* platform supports such things; it can thus be marginally faster than |
|
* the generic <code>sph_enc64be()</code> function. This function is defined |
|
* only if a suitable 64-bit type was detected and used for |
|
* <code>sph_u64</code>. |
|
* |
|
* @param dst the destination buffer |
|
* @param val the value to encode |
|
*/ |
|
static inline void sph_enc64be_aligned(void *dst, sph_u64 val); |
|
|
|
#endif |
|
|
|
/* ============== END documentation block for Doxygen ============= */ |
|
|
|
#ifndef DOXYGEN_IGNORE |
|
|
|
/* |
|
* We want to define the types "sph_u32" and "sph_u64" which hold |
|
* unsigned values of at least, respectively, 32 and 64 bits. These |
|
* tests should select appropriate types for most platforms. The |
|
* macro "SPH_64" is defined if the 64-bit is supported. |
|
*/ |
|
|
|
#undef SPH_64 |
|
#undef SPH_64_TRUE |
|
|
|
#if defined __STDC__ && __STDC_VERSION__ >= 199901L |
|
|
|
/* |
|
* On C99 implementations, we can use <stdint.h> to get an exact 64-bit |
|
* type, if any, or otherwise use a wider type (which must exist, for |
|
* C99 conformance). |
|
*/ |
|
|
|
#include <stdint.h> |
|
|
|
#ifdef UINT32_MAX |
|
typedef uint32_t sph_u32; |
|
typedef int32_t sph_s32; |
|
#else |
|
typedef uint_fast32_t sph_u32; |
|
typedef int_fast32_t sph_s32; |
|
#endif |
|
#if !SPH_NO_64 |
|
#ifdef UINT64_MAX |
|
typedef uint64_t sph_u64; |
|
typedef int64_t sph_s64; |
|
#else |
|
typedef uint_fast64_t sph_u64; |
|
typedef int_fast64_t sph_s64; |
|
#endif |
|
#endif |
|
|
|
#define SPH_C32(x) ((sph_u32)(x)) |
|
#if !SPH_NO_64 |
|
#define SPH_C64(x) ((sph_u64)(x)) |
|
#define SPH_64 1 |
|
#endif |
|
|
|
#else |
|
|
|
/* |
|
* On non-C99 systems, we use "unsigned int" if it is wide enough, |
|
* "unsigned long" otherwise. This supports all "reasonable" architectures. |
|
* We have to be cautious: pre-C99 preprocessors handle constants |
|
* differently in '#if' expressions. Hence the shifts to test UINT_MAX. |
|
*/ |
|
|
|
#if ((UINT_MAX >> 11) >> 11) >= 0x3FF |
|
|
|
typedef unsigned int sph_u32; |
|
typedef int sph_s32; |
|
|
|
#define SPH_C32(x) ((sph_u32)(x ## U)) |
|
|
|
#else |
|
|
|
typedef unsigned long sph_u32; |
|
typedef long sph_s32; |
|
|
|
#define SPH_C32(x) ((sph_u32)(x ## UL)) |
|
|
|
#endif |
|
|
|
#if !SPH_NO_64 |
|
|
|
/* |
|
* We want a 64-bit type. We use "unsigned long" if it is wide enough (as |
|
* is common on 64-bit architectures such as AMD64, Alpha or Sparcv9), |
|
* "unsigned long long" otherwise, if available. We use ULLONG_MAX to |
|
* test whether "unsigned long long" is available; we also know that |
|
* gcc features this type, even if the libc header do not know it. |
|
*/ |
|
|
|
#if ((ULONG_MAX >> 31) >> 31) >= 3 |
|
|
|
typedef unsigned long sph_u64; |
|
typedef long sph_s64; |
|
|
|
#define SPH_C64(x) ((sph_u64)(x ## UL)) |
|
|
|
#define SPH_64 1 |
|
|
|
#elif ((ULLONG_MAX >> 31) >> 31) >= 3 || defined __GNUC__ |
|
|
|
typedef unsigned long long sph_u64; |
|
typedef long long sph_s64; |
|
|
|
#define SPH_C64(x) ((sph_u64)(x ## ULL)) |
|
|
|
#define SPH_64 1 |
|
|
|
#else |
|
|
|
/* |
|
* No 64-bit type... |
|
*/ |
|
|
|
#endif |
|
|
|
#endif |
|
|
|
#endif |
|
|
|
/* |
|
* If the "unsigned long" type has length 64 bits or more, then this is |
|
* a "true" 64-bit architectures. This is also true with Visual C on |
|
* amd64, even though the "long" type is limited to 32 bits. |
|
*/ |
|
#if SPH_64 && (((ULONG_MAX >> 31) >> 31) >= 3 || defined _M_X64) |
|
#define SPH_64_TRUE 1 |
|
#endif |
|
|
|
/* |
|
* Implementation note: some processors have specific opcodes to perform |
|
* a rotation. Recent versions of gcc recognize the expression above and |
|
* use the relevant opcodes, when appropriate. |
|
*/ |
|
|
|
#define SPH_T32(x) ((x) & SPH_C32(0xFFFFFFFF)) |
|
#define SPH_ROTL32(x, n) SPH_T32(((x) << (n)) | ((x) >> (32 - (n)))) |
|
#define SPH_ROTR32(x, n) SPH_ROTL32(x, (32 - (n))) |
|
|
|
#if SPH_64 |
|
|
|
#define SPH_T64(x) ((x) & SPH_C64(0xFFFFFFFFFFFFFFFF)) |
|
#define SPH_ROTL64(x, n) SPH_T64(((x) << (n)) | ((x) >> (64 - (n)))) |
|
#define SPH_ROTR64(x, n) SPH_ROTL64(x, (64 - (n))) |
|
|
|
#endif |
|
|
|
#ifndef DOXYGEN_IGNORE |
|
/* |
|
* Define SPH_INLINE to be an "inline" qualifier, if available. We define |
|
* some small macro-like functions which benefit greatly from being inlined. |
|
*/ |
|
#if (defined __STDC__ && __STDC_VERSION__ >= 199901L) || defined __GNUC__ |
|
#define SPH_INLINE inline |
|
#elif defined _MSC_VER |
|
#define SPH_INLINE __inline |
|
#else |
|
#define SPH_INLINE |
|
#endif |
|
#endif |
|
|
|
/* |
|
* We define some macros which qualify the architecture. These macros |
|
* may be explicit set externally (e.g. as compiler parameters). The |
|
* code below sets those macros if they are not already defined. |
|
* |
|
* Most macros are boolean, thus evaluate to either zero or non-zero. |
|
* The SPH_UPTR macro is special, in that it evaluates to a C type, |
|
* or is not defined. |
|
* |
|
* SPH_UPTR if defined: unsigned type to cast pointers into |
|
* |
|
* SPH_UNALIGNED non-zero if unaligned accesses are efficient |
|
* SPH_LITTLE_ENDIAN non-zero if architecture is known to be little-endian |
|
* SPH_BIG_ENDIAN non-zero if architecture is known to be big-endian |
|
* SPH_LITTLE_FAST non-zero if little-endian decoding is fast |
|
* SPH_BIG_FAST non-zero if big-endian decoding is fast |
|
* |
|
* If SPH_UPTR is defined, then encoding and decoding of 32-bit and 64-bit |
|
* values will try to be "smart". Either SPH_LITTLE_ENDIAN or SPH_BIG_ENDIAN |
|
* _must_ be non-zero in those situations. The 32-bit and 64-bit types |
|
* _must_ also have an exact width. |
|
* |
|
* SPH_SPARCV9_GCC_32 UltraSPARC-compatible with gcc, 32-bit mode |
|
* SPH_SPARCV9_GCC_64 UltraSPARC-compatible with gcc, 64-bit mode |
|
* SPH_SPARCV9_GCC UltraSPARC-compatible with gcc |
|
* SPH_I386_GCC x86-compatible (32-bit) with gcc |
|
* SPH_I386_MSVC x86-compatible (32-bit) with Microsoft Visual C |
|
* SPH_AMD64_GCC x86-compatible (64-bit) with gcc |
|
* SPH_AMD64_MSVC x86-compatible (64-bit) with Microsoft Visual C |
|
* SPH_PPC32_GCC PowerPC, 32-bit, with gcc |
|
* SPH_PPC64_GCC PowerPC, 64-bit, with gcc |
|
* |
|
* TODO: enhance automatic detection, for more architectures and compilers. |
|
* Endianness is the most important. SPH_UNALIGNED and SPH_UPTR help with |
|
* some very fast functions (e.g. MD4) when using unaligned input data. |
|
* The CPU-specific-with-GCC macros are useful only for inline assembly, |
|
* normally restrained to this header file. |
|
*/ |
|
|
|
/* |
|
* 32-bit x86, aka "i386 compatible". |
|
*/ |
|
#if defined __i386__ || defined _M_IX86 |
|
|
|
#define SPH_DETECT_UNALIGNED 1 |
|
#define SPH_DETECT_LITTLE_ENDIAN 1 |
|
#define SPH_DETECT_UPTR sph_u32 |
|
#ifdef __GNUC__ |
|
#define SPH_DETECT_I386_GCC 1 |
|
#endif |
|
#ifdef _MSC_VER |
|
#define SPH_DETECT_I386_MSVC 1 |
|
#endif |
|
|
|
/* |
|
* 64-bit x86, hereafter known as "amd64". |
|
*/ |
|
#elif defined __x86_64 || defined _M_X64 |
|
|
|
#define SPH_DETECT_UNALIGNED 1 |
|
#define SPH_DETECT_LITTLE_ENDIAN 1 |
|
#define SPH_DETECT_UPTR sph_u64 |
|
#ifdef __GNUC__ |
|
#define SPH_DETECT_AMD64_GCC 1 |
|
#endif |
|
#ifdef _MSC_VER |
|
#define SPH_DETECT_AMD64_MSVC 1 |
|
#endif |
|
|
|
/* |
|
* 64-bit Sparc architecture (implies v9). |
|
*/ |
|
#elif ((defined __sparc__ || defined __sparc) && defined __arch64__) \ |
|
|| defined __sparcv9 |
|
|
|
#define SPH_DETECT_BIG_ENDIAN 1 |
|
#define SPH_DETECT_UPTR sph_u64 |
|
#ifdef __GNUC__ |
|
#define SPH_DETECT_SPARCV9_GCC_64 1 |
|
#define SPH_DETECT_LITTLE_FAST 1 |
|
#endif |
|
|
|
/* |
|
* 32-bit Sparc. |
|
*/ |
|
#elif (defined __sparc__ || defined __sparc) \ |
|
&& !(defined __sparcv9 || defined __arch64__) |
|
|
|
#define SPH_DETECT_BIG_ENDIAN 1 |
|
#define SPH_DETECT_UPTR sph_u32 |
|
#if defined __GNUC__ && defined __sparc_v9__ |
|
#define SPH_DETECT_SPARCV9_GCC_32 1 |
|
#define SPH_DETECT_LITTLE_FAST 1 |
|
#endif |
|
|
|
/* |
|
* ARM, little-endian. |
|
*/ |
|
#elif defined __arm__ && __ARMEL__ |
|
|
|
#define SPH_DETECT_LITTLE_ENDIAN 1 |
|
|
|
/* |
|
* MIPS, little-endian. |
|
*/ |
|
#elif MIPSEL || _MIPSEL || __MIPSEL || __MIPSEL__ |
|
|
|
#define SPH_DETECT_LITTLE_ENDIAN 1 |
|
|
|
/* |
|
* MIPS, big-endian. |
|
*/ |
|
#elif MIPSEB || _MIPSEB || __MIPSEB || __MIPSEB__ |
|
|
|
#define SPH_DETECT_BIG_ENDIAN 1 |
|
|
|
/* |
|
* PowerPC. |
|
*/ |
|
#elif defined __powerpc__ || defined __POWERPC__ || defined __ppc__ \ |
|
|| defined _ARCH_PPC |
|
|
|
/* |
|
* Note: we do not declare cross-endian access to be "fast": even if |
|
* using inline assembly, implementation should still assume that |
|
* keeping the decoded word in a temporary is faster than decoding |
|
* it again. |
|
*/ |
|
#if defined __GNUC__ |
|
#if SPH_64_TRUE |
|
#define SPH_DETECT_PPC64_GCC 1 |
|
#else |
|
#define SPH_DETECT_PPC32_GCC 1 |
|
#endif |
|
#endif |
|
|
|
#if defined __BIG_ENDIAN__ || defined _BIG_ENDIAN |
|
#define SPH_DETECT_BIG_ENDIAN 1 |
|
#elif defined __LITTLE_ENDIAN__ || defined _LITTLE_ENDIAN |
|
#define SPH_DETECT_LITTLE_ENDIAN 1 |
|
#endif |
|
|
|
/* |
|
* Itanium, 64-bit. |
|
*/ |
|
#elif defined __ia64 || defined __ia64__ \ |
|
|| defined __itanium__ || defined _M_IA64 |
|
|
|
#if defined __BIG_ENDIAN__ || defined _BIG_ENDIAN |
|
#define SPH_DETECT_BIG_ENDIAN 1 |
|
#else |
|
#define SPH_DETECT_LITTLE_ENDIAN 1 |
|
#endif |
|
#if defined __LP64__ || defined _LP64 |
|
#define SPH_DETECT_UPTR sph_u64 |
|
#else |
|
#define SPH_DETECT_UPTR sph_u32 |
|
#endif |
|
|
|
#endif |
|
|
|
#if defined SPH_DETECT_SPARCV9_GCC_32 || defined SPH_DETECT_SPARCV9_GCC_64 |
|
#define SPH_DETECT_SPARCV9_GCC 1 |
|
#endif |
|
|
|
#if defined SPH_DETECT_UNALIGNED && !defined SPH_UNALIGNED |
|
#define SPH_UNALIGNED SPH_DETECT_UNALIGNED |
|
#endif |
|
#if defined SPH_DETECT_UPTR && !defined SPH_UPTR |
|
#define SPH_UPTR SPH_DETECT_UPTR |
|
#endif |
|
#if defined SPH_DETECT_LITTLE_ENDIAN && !defined SPH_LITTLE_ENDIAN |
|
#define SPH_LITTLE_ENDIAN SPH_DETECT_LITTLE_ENDIAN |
|
#endif |
|
#if defined SPH_DETECT_BIG_ENDIAN && !defined SPH_BIG_ENDIAN |
|
#define SPH_BIG_ENDIAN SPH_DETECT_BIG_ENDIAN |
|
#endif |
|
#if defined SPH_DETECT_LITTLE_FAST && !defined SPH_LITTLE_FAST |
|
#define SPH_LITTLE_FAST SPH_DETECT_LITTLE_FAST |
|
#endif |
|
#if defined SPH_DETECT_BIG_FAST && !defined SPH_BIG_FAST |
|
#define SPH_BIG_FAST SPH_DETECT_BIG_FAST |
|
#endif |
|
#if defined SPH_DETECT_SPARCV9_GCC_32 && !defined SPH_SPARCV9_GCC_32 |
|
#define SPH_SPARCV9_GCC_32 SPH_DETECT_SPARCV9_GCC_32 |
|
#endif |
|
#if defined SPH_DETECT_SPARCV9_GCC_64 && !defined SPH_SPARCV9_GCC_64 |
|
#define SPH_SPARCV9_GCC_64 SPH_DETECT_SPARCV9_GCC_64 |
|
#endif |
|
#if defined SPH_DETECT_SPARCV9_GCC && !defined SPH_SPARCV9_GCC |
|
#define SPH_SPARCV9_GCC SPH_DETECT_SPARCV9_GCC |
|
#endif |
|
#if defined SPH_DETECT_I386_GCC && !defined SPH_I386_GCC |
|
#define SPH_I386_GCC SPH_DETECT_I386_GCC |
|
#endif |
|
#if defined SPH_DETECT_I386_MSVC && !defined SPH_I386_MSVC |
|
#define SPH_I386_MSVC SPH_DETECT_I386_MSVC |
|
#endif |
|
#if defined SPH_DETECT_AMD64_GCC && !defined SPH_AMD64_GCC |
|
#define SPH_AMD64_GCC SPH_DETECT_AMD64_GCC |
|
#endif |
|
#if defined SPH_DETECT_AMD64_MSVC && !defined SPH_AMD64_MSVC |
|
#define SPH_AMD64_MSVC SPH_DETECT_AMD64_MSVC |
|
#endif |
|
#if defined SPH_DETECT_PPC32_GCC && !defined SPH_PPC32_GCC |
|
#define SPH_PPC32_GCC SPH_DETECT_PPC32_GCC |
|
#endif |
|
#if defined SPH_DETECT_PPC64_GCC && !defined SPH_PPC64_GCC |
|
#define SPH_PPC64_GCC SPH_DETECT_PPC64_GCC |
|
#endif |
|
|
|
#if SPH_LITTLE_ENDIAN && !defined SPH_LITTLE_FAST |
|
#define SPH_LITTLE_FAST 1 |
|
#endif |
|
#if SPH_BIG_ENDIAN && !defined SPH_BIG_FAST |
|
#define SPH_BIG_FAST 1 |
|
#endif |
|
|
|
#if defined SPH_UPTR && !(SPH_LITTLE_ENDIAN || SPH_BIG_ENDIAN) |
|
#error SPH_UPTR defined, but endianness is not known. |
|
#endif |
|
|
|
#if SPH_I386_GCC && !SPH_NO_ASM |
|
|
|
/* |
|
* On x86 32-bit, with gcc, we use the bswapl opcode to byte-swap 32-bit |
|
* values. |
|
*/ |
|
|
|
static SPH_INLINE sph_u32 |
|
sph_bswap32(sph_u32 x) |
|
{ |
|
__asm__ __volatile__ ("bswapl %0" : "=r" (x) : "0" (x)); |
|
return x; |
|
} |
|
|
|
#if SPH_64 |
|
|
|
static SPH_INLINE sph_u64 |
|
sph_bswap64(sph_u64 x) |
|
{ |
|
return ((sph_u64)sph_bswap32((sph_u32)x) << 32) |
|
| (sph_u64)sph_bswap32((sph_u32)(x >> 32)); |
|
} |
|
|
|
#endif |
|
|
|
#elif SPH_AMD64_GCC && !SPH_NO_ASM |
|
|
|
/* |
|
* On x86 64-bit, with gcc, we use the bswapl opcode to byte-swap 32-bit |
|
* and 64-bit values. |
|
*/ |
|
|
|
static SPH_INLINE sph_u32 |
|
sph_bswap32(sph_u32 x) |
|
{ |
|
__asm__ __volatile__ ("bswapl %0" : "=r" (x) : "0" (x)); |
|
return x; |
|
} |
|
|
|
#if SPH_64 |
|
|
|
static SPH_INLINE sph_u64 |
|
sph_bswap64(sph_u64 x) |
|
{ |
|
__asm__ __volatile__ ("bswapq %0" : "=r" (x) : "0" (x)); |
|
return x; |
|
} |
|
|
|
#endif |
|
|
|
/* |
|
* Disabled code. Apparently, Microsoft Visual C 2005 is smart enough |
|
* to generate proper opcodes for endianness swapping with the pure C |
|
* implementation below. |
|
* |
|
|
|
#elif SPH_I386_MSVC && !SPH_NO_ASM |
|
|
|
static __inline sph_u32 __declspec(naked) __fastcall |
|
sph_bswap32(sph_u32 x) |
|
{ |
|
__asm { |
|
bswap ecx |
|
mov eax,ecx |
|
ret |
|
} |
|
} |
|
|
|
#if SPH_64 |
|
|
|
static SPH_INLINE sph_u64 |
|
sph_bswap64(sph_u64 x) |
|
{ |
|
return ((sph_u64)sph_bswap32((sph_u32)x) << 32) |
|
| (sph_u64)sph_bswap32((sph_u32)(x >> 32)); |
|
} |
|
|
|
#endif |
|
|
|
* |
|
* [end of disabled code] |
|
*/ |
|
|
|
#else |
|
|
|
static SPH_INLINE sph_u32 |
|
sph_bswap32(sph_u32 x) |
|
{ |
|
x = SPH_T32((x << 16) | (x >> 16)); |
|
x = ((x & SPH_C32(0xFF00FF00)) >> 8) |
|
| ((x & SPH_C32(0x00FF00FF)) << 8); |
|
return x; |
|
} |
|
|
|
#if SPH_64 |
|
|
|
/** |
|
* Byte-swap a 64-bit value. |
|
* |
|
* @param x the input value |
|
* @return the byte-swapped value |
|
*/ |
|
static SPH_INLINE sph_u64 |
|
sph_bswap64(sph_u64 x) |
|
{ |
|
x = SPH_T64((x << 32) | (x >> 32)); |
|
x = ((x & SPH_C64(0xFFFF0000FFFF0000)) >> 16) |
|
| ((x & SPH_C64(0x0000FFFF0000FFFF)) << 16); |
|
x = ((x & SPH_C64(0xFF00FF00FF00FF00)) >> 8) |
|
| ((x & SPH_C64(0x00FF00FF00FF00FF)) << 8); |
|
return x; |
|
} |
|
|
|
#endif |
|
|
|
#endif |
|
|
|
#if SPH_SPARCV9_GCC && !SPH_NO_ASM |
|
|
|
/* |
|
* On UltraSPARC systems, native ordering is big-endian, but it is |
|
* possible to perform little-endian read accesses by specifying the |
|
* address space 0x88 (ASI_PRIMARY_LITTLE). Basically, either we use |
|
* the opcode "lda [%reg]0x88,%dst", where %reg is the register which |
|
* contains the source address and %dst is the destination register, |
|
* or we use "lda [%reg+imm]%asi,%dst", which uses the %asi register |
|
* to get the address space name. The latter format is better since it |
|
* combines an addition and the actual access in a single opcode; but |
|
* it requires the setting (and subsequent resetting) of %asi, which is |
|
* slow. Some operations (i.e. MD5 compression function) combine many |
|
* successive little-endian read accesses, which may share the same |
|
* %asi setting. The macros below contain the appropriate inline |
|
* assembly. |
|
*/ |
|
|
|
#define SPH_SPARCV9_SET_ASI \ |
|
sph_u32 sph_sparcv9_asi; \ |
|
__asm__ __volatile__ ( \ |
|
"rd %%asi,%0\n\twr %%g0,0x88,%%asi" : "=r" (sph_sparcv9_asi)); |
|
|
|
#define SPH_SPARCV9_RESET_ASI \ |
|
__asm__ __volatile__ ("wr %%g0,%0,%%asi" : : "r" (sph_sparcv9_asi)); |
|
|
|
#define SPH_SPARCV9_DEC32LE(base, idx) ({ \ |
|
sph_u32 sph_sparcv9_tmp; \ |
|
__asm__ __volatile__ ("lda [%1+" #idx "*4]%%asi,%0" \ |
|
: "=r" (sph_sparcv9_tmp) : "r" (base)); \ |
|
sph_sparcv9_tmp; \ |
|
}) |
|
|
|
#endif |
|
|
|
static SPH_INLINE void |
|
sph_enc16be(void *dst, unsigned val) |
|
{ |
|
((unsigned char *)dst)[0] = (val >> 8); |
|
((unsigned char *)dst)[1] = val; |
|
} |
|
|
|
static SPH_INLINE unsigned |
|
sph_dec16be(const void *src) |
|
{ |
|
return ((unsigned)(((const unsigned char *)src)[0]) << 8) |
|
| (unsigned)(((const unsigned char *)src)[1]); |
|
} |
|
|
|
static SPH_INLINE void |
|
sph_enc16le(void *dst, unsigned val) |
|
{ |
|
((unsigned char *)dst)[0] = val; |
|
((unsigned char *)dst)[1] = val >> 8; |
|
} |
|
|
|
static SPH_INLINE unsigned |
|
sph_dec16le(const void *src) |
|
{ |
|
return (unsigned)(((const unsigned char *)src)[0]) |
|
| ((unsigned)(((const unsigned char *)src)[1]) << 8); |
|
} |
|
|
|
/** |
|
* Encode a 32-bit value into the provided buffer (big endian convention). |
|
* |
|
* @param dst the destination buffer |
|
* @param val the 32-bit value to encode |
|
*/ |
|
static SPH_INLINE void |
|
sph_enc32be(void *dst, sph_u32 val) |
|
{ |
|
#if defined SPH_UPTR |
|
#if SPH_UNALIGNED |
|
#if SPH_LITTLE_ENDIAN |
|
val = sph_bswap32(val); |
|
#endif |
|
*(sph_u32 *)dst = val; |
|
#else |
|
if (((SPH_UPTR)dst & 3) == 0) { |
|
#if SPH_LITTLE_ENDIAN |
|
val = sph_bswap32(val); |
|
#endif |
|
*(sph_u32 *)dst = val; |
|
} else { |
|
((unsigned char *)dst)[0] = (val >> 24); |
|
((unsigned char *)dst)[1] = (val >> 16); |
|
((unsigned char *)dst)[2] = (val >> 8); |
|
((unsigned char *)dst)[3] = val; |
|
} |
|
#endif |
|
#else |
|
((unsigned char *)dst)[0] = (val >> 24); |
|
((unsigned char *)dst)[1] = (val >> 16); |
|
((unsigned char *)dst)[2] = (val >> 8); |
|
((unsigned char *)dst)[3] = val; |
|
#endif |
|
} |
|
|
|
/** |
|
* Encode a 32-bit value into the provided buffer (big endian convention). |
|
* The destination buffer must be properly aligned. |
|
* |
|
* @param dst the destination buffer (32-bit aligned) |
|
* @param val the value to encode |
|
*/ |
|
static SPH_INLINE void |
|
sph_enc32be_aligned(void *dst, sph_u32 val) |
|
{ |
|
#if SPH_LITTLE_ENDIAN |
|
*(sph_u32 *)dst = sph_bswap32(val); |
|
#elif SPH_BIG_ENDIAN |
|
*(sph_u32 *)dst = val; |
|
#else |
|
((unsigned char *)dst)[0] = (val >> 24); |
|
((unsigned char *)dst)[1] = (val >> 16); |
|
((unsigned char *)dst)[2] = (val >> 8); |
|
((unsigned char *)dst)[3] = val; |
|
#endif |
|
} |
|
|
|
/** |
|
* Decode a 32-bit value from the provided buffer (big endian convention). |
|
* |
|
* @param src the source buffer |
|
* @return the decoded value |
|
*/ |
|
static SPH_INLINE sph_u32 |
|
sph_dec32be(const void *src) |
|
{ |
|
#if defined SPH_UPTR |
|
#if SPH_UNALIGNED |
|
#if SPH_LITTLE_ENDIAN |
|
return sph_bswap32(*(const sph_u32 *)src); |
|
#else |
|
return *(const sph_u32 *)src; |
|
#endif |
|
#else |
|
if (((SPH_UPTR)src & 3) == 0) { |
|
#if SPH_LITTLE_ENDIAN |
|
return sph_bswap32(*(const sph_u32 *)src); |
|
#else |
|
return *(const sph_u32 *)src; |
|
#endif |
|
} else { |
|
return ((sph_u32)(((const unsigned char *)src)[0]) << 24) |
|
| ((sph_u32)(((const unsigned char *)src)[1]) << 16) |
|
| ((sph_u32)(((const unsigned char *)src)[2]) << 8) |
|
| (sph_u32)(((const unsigned char *)src)[3]); |
|
} |
|
#endif |
|
#else |
|
return ((sph_u32)(((const unsigned char *)src)[0]) << 24) |
|
| ((sph_u32)(((const unsigned char *)src)[1]) << 16) |
|
| ((sph_u32)(((const unsigned char *)src)[2]) << 8) |
|
| (sph_u32)(((const unsigned char *)src)[3]); |
|
#endif |
|
} |
|
|
|
/** |
|
* Decode a 32-bit value from the provided buffer (big endian convention). |
|
* The source buffer must be properly aligned. |
|
* |
|
* @param src the source buffer (32-bit aligned) |
|
* @return the decoded value |
|
*/ |
|
static SPH_INLINE sph_u32 |
|
sph_dec32be_aligned(const void *src) |
|
{ |
|
#if SPH_LITTLE_ENDIAN |
|
return sph_bswap32(*(const sph_u32 *)src); |
|
#elif SPH_BIG_ENDIAN |
|
return *(const sph_u32 *)src; |
|
#else |
|
return ((sph_u32)(((const unsigned char *)src)[0]) << 24) |
|
| ((sph_u32)(((const unsigned char *)src)[1]) << 16) |
|
| ((sph_u32)(((const unsigned char *)src)[2]) << 8) |
|
| (sph_u32)(((const unsigned char *)src)[3]); |
|
#endif |
|
} |
|
|
|
/** |
|
* Encode a 32-bit value into the provided buffer (little endian convention). |
|
* |
|
* @param dst the destination buffer |
|
* @param val the 32-bit value to encode |
|
*/ |
|
static SPH_INLINE void |
|
sph_enc32le(void *dst, sph_u32 val) |
|
{ |
|
#if defined SPH_UPTR |
|
#if SPH_UNALIGNED |
|
#if SPH_BIG_ENDIAN |
|
val = sph_bswap32(val); |
|
#endif |
|
*(sph_u32 *)dst = val; |
|
#else |
|
if (((SPH_UPTR)dst & 3) == 0) { |
|
#if SPH_BIG_ENDIAN |
|
val = sph_bswap32(val); |
|
#endif |
|
*(sph_u32 *)dst = val; |
|
} else { |
|
((unsigned char *)dst)[0] = val; |
|
((unsigned char *)dst)[1] = (val >> 8); |
|
((unsigned char *)dst)[2] = (val >> 16); |
|
((unsigned char *)dst)[3] = (val >> 24); |
|
} |
|
#endif |
|
#else |
|
((unsigned char *)dst)[0] = val; |
|
((unsigned char *)dst)[1] = (val >> 8); |
|
((unsigned char *)dst)[2] = (val >> 16); |
|
((unsigned char *)dst)[3] = (val >> 24); |
|
#endif |
|
} |
|
|
|
/** |
|
* Encode a 32-bit value into the provided buffer (little endian convention). |
|
* The destination buffer must be properly aligned. |
|
* |
|
* @param dst the destination buffer (32-bit aligned) |
|
* @param val the value to encode |
|
*/ |
|
static SPH_INLINE void |
|
sph_enc32le_aligned(void *dst, sph_u32 val) |
|
{ |
|
#if SPH_LITTLE_ENDIAN |
|
*(sph_u32 *)dst = val; |
|
#elif SPH_BIG_ENDIAN |
|
*(sph_u32 *)dst = sph_bswap32(val); |
|
#else |
|
((unsigned char *)dst)[0] = val; |
|
((unsigned char *)dst)[1] = (val >> 8); |
|
((unsigned char *)dst)[2] = (val >> 16); |
|
((unsigned char *)dst)[3] = (val >> 24); |
|
#endif |
|
} |
|
|
|
/** |
|
* Decode a 32-bit value from the provided buffer (little endian convention). |
|
* |
|
* @param src the source buffer |
|
* @return the decoded value |
|
*/ |
|
static SPH_INLINE sph_u32 |
|
sph_dec32le(const void *src) |
|
{ |
|
#if defined SPH_UPTR |
|
#if SPH_UNALIGNED |
|
#if SPH_BIG_ENDIAN |
|
return sph_bswap32(*(const sph_u32 *)src); |
|
#else |
|
return *(const sph_u32 *)src; |
|
#endif |
|
#else |
|
if (((SPH_UPTR)src & 3) == 0) { |
|
#if SPH_BIG_ENDIAN |
|
#if SPH_SPARCV9_GCC && !SPH_NO_ASM |
|
sph_u32 tmp; |
|
|
|
/* |
|
* "__volatile__" is needed here because without it, |
|
* gcc-3.4.3 miscompiles the code and performs the |
|
* access before the test on the address, thus triggering |
|
* a bus error... |
|
*/ |
|
__asm__ __volatile__ ( |
|
"lda [%1]0x88,%0" : "=r" (tmp) : "r" (src)); |
|
return tmp; |
|
/* |
|
* On PowerPC, this turns out not to be worth the effort: the inline |
|
* assembly makes GCC optimizer uncomfortable, which tends to nullify |
|
* the decoding gains. |
|
* |
|
* For most hash functions, using this inline assembly trick changes |
|
* hashing speed by less than 5% and often _reduces_ it. The biggest |
|
* gains are for MD4 (+11%) and CubeHash (+30%). For all others, it is |
|
* less then 10%. The speed gain on CubeHash is probably due to the |
|
* chronic shortage of registers that CubeHash endures; for the other |
|
* functions, the generic code appears to be efficient enough already. |
|
* |
|
#elif (SPH_PPC32_GCC || SPH_PPC64_GCC) && !SPH_NO_ASM |
|
sph_u32 tmp; |
|
|
|
__asm__ __volatile__ ( |
|
"lwbrx %0,0,%1" : "=r" (tmp) : "r" (src)); |
|
return tmp; |
|
*/ |
|
#else |
|
return sph_bswap32(*(const sph_u32 *)src); |
|
#endif |
|
#else |
|
return *(const sph_u32 *)src; |
|
#endif |
|
} else { |
|
return (sph_u32)(((const unsigned char *)src)[0]) |
|
| ((sph_u32)(((const unsigned char *)src)[1]) << 8) |
|
| ((sph_u32)(((const unsigned char *)src)[2]) << 16) |
|
| ((sph_u32)(((const unsigned char *)src)[3]) << 24); |
|
} |
|
#endif |
|
#else |
|
return (sph_u32)(((const unsigned char *)src)[0]) |
|
| ((sph_u32)(((const unsigned char *)src)[1]) << 8) |
|
| ((sph_u32)(((const unsigned char *)src)[2]) << 16) |
|
| ((sph_u32)(((const unsigned char *)src)[3]) << 24); |
|
#endif |
|
} |
|
|
|
/** |
|
* Decode a 32-bit value from the provided buffer (little endian convention). |
|
* The source buffer must be properly aligned. |
|
* |
|
* @param src the source buffer (32-bit aligned) |
|
* @return the decoded value |
|
*/ |
|
static SPH_INLINE sph_u32 |
|
sph_dec32le_aligned(const void *src) |
|
{ |
|
#if SPH_LITTLE_ENDIAN |
|
return *(const sph_u32 *)src; |
|
#elif SPH_BIG_ENDIAN |
|
#if SPH_SPARCV9_GCC && !SPH_NO_ASM |
|
sph_u32 tmp; |
|
|
|
__asm__ __volatile__ ("lda [%1]0x88,%0" : "=r" (tmp) : "r" (src)); |
|
return tmp; |
|
/* |
|
* Not worth it generally. |
|
* |
|
#elif (SPH_PPC32_GCC || SPH_PPC64_GCC) && !SPH_NO_ASM |
|
sph_u32 tmp; |
|
|
|
__asm__ __volatile__ ("lwbrx %0,0,%1" : "=r" (tmp) : "r" (src)); |
|
return tmp; |
|
*/ |
|
#else |
|
return sph_bswap32(*(const sph_u32 *)src); |
|
#endif |
|
#else |
|
return (sph_u32)(((const unsigned char *)src)[0]) |
|
| ((sph_u32)(((const unsigned char *)src)[1]) << 8) |
|
| ((sph_u32)(((const unsigned char *)src)[2]) << 16) |
|
| ((sph_u32)(((const unsigned char *)src)[3]) << 24); |
|
#endif |
|
} |
|
|
|
#if SPH_64 |
|
|
|
/** |
|
* Encode a 64-bit value into the provided buffer (big endian convention). |
|
* |
|
* @param dst the destination buffer |
|
* @param val the 64-bit value to encode |
|
*/ |
|
static SPH_INLINE void |
|
sph_enc64be(void *dst, sph_u64 val) |
|
{ |
|
#if defined SPH_UPTR |
|
#if SPH_UNALIGNED |
|
#if SPH_LITTLE_ENDIAN |
|
val = sph_bswap64(val); |
|
#endif |
|
*(sph_u64 *)dst = val; |
|
#else |
|
if (((SPH_UPTR)dst & 7) == 0) { |
|
#if SPH_LITTLE_ENDIAN |
|
val = sph_bswap64(val); |
|
#endif |
|
*(sph_u64 *)dst = val; |
|
} else { |
|
((unsigned char *)dst)[0] = (val >> 56); |
|
((unsigned char *)dst)[1] = (val >> 48); |
|
((unsigned char *)dst)[2] = (val >> 40); |
|
((unsigned char *)dst)[3] = (val >> 32); |
|
((unsigned char *)dst)[4] = (val >> 24); |
|
((unsigned char *)dst)[5] = (val >> 16); |
|
((unsigned char *)dst)[6] = (val >> 8); |
|
((unsigned char *)dst)[7] = val; |
|
} |
|
#endif |
|
#else |
|
((unsigned char *)dst)[0] = (val >> 56); |
|
((unsigned char *)dst)[1] = (val >> 48); |
|
((unsigned char *)dst)[2] = (val >> 40); |
|
((unsigned char *)dst)[3] = (val >> 32); |
|
((unsigned char *)dst)[4] = (val >> 24); |
|
((unsigned char *)dst)[5] = (val >> 16); |
|
((unsigned char *)dst)[6] = (val >> 8); |
|
((unsigned char *)dst)[7] = val; |
|
#endif |
|
} |
|
|
|
/** |
|
* Encode a 64-bit value into the provided buffer (big endian convention). |
|
* The destination buffer must be properly aligned. |
|
* |
|
* @param dst the destination buffer (64-bit aligned) |
|
* @param val the value to encode |
|
*/ |
|
static SPH_INLINE void |
|
sph_enc64be_aligned(void *dst, sph_u64 val) |
|
{ |
|
#if SPH_LITTLE_ENDIAN |
|
*(sph_u64 *)dst = sph_bswap64(val); |
|
#elif SPH_BIG_ENDIAN |
|
*(sph_u64 *)dst = val; |
|
#else |
|
((unsigned char *)dst)[0] = (val >> 56); |
|
((unsigned char *)dst)[1] = (val >> 48); |
|
((unsigned char *)dst)[2] = (val >> 40); |
|
((unsigned char *)dst)[3] = (val >> 32); |
|
((unsigned char *)dst)[4] = (val >> 24); |
|
((unsigned char *)dst)[5] = (val >> 16); |
|
((unsigned char *)dst)[6] = (val >> 8); |
|
((unsigned char *)dst)[7] = val; |
|
#endif |
|
} |
|
|
|
/** |
|
* Decode a 64-bit value from the provided buffer (big endian convention). |
|
* |
|
* @param src the source buffer |
|
* @return the decoded value |
|
*/ |
|
static SPH_INLINE sph_u64 |
|
sph_dec64be(const void *src) |
|
{ |
|
#if defined SPH_UPTR |
|
#if SPH_UNALIGNED |
|
#if SPH_LITTLE_ENDIAN |
|
return sph_bswap64(*(const sph_u64 *)src); |
|
#else |
|
return *(const sph_u64 *)src; |
|
#endif |
|
#else |
|
if (((SPH_UPTR)src & 7) == 0) { |
|
#if SPH_LITTLE_ENDIAN |
|
return sph_bswap64(*(const sph_u64 *)src); |
|
#else |
|
return *(const sph_u64 *)src; |
|
#endif |
|
} else { |
|
return ((sph_u64)(((const unsigned char *)src)[0]) << 56) |
|
| ((sph_u64)(((const unsigned char *)src)[1]) << 48) |
|
| ((sph_u64)(((const unsigned char *)src)[2]) << 40) |
|
| ((sph_u64)(((const unsigned char *)src)[3]) << 32) |
|
| ((sph_u64)(((const unsigned char *)src)[4]) << 24) |
|
| ((sph_u64)(((const unsigned char *)src)[5]) << 16) |
|
| ((sph_u64)(((const unsigned char *)src)[6]) << 8) |
|
| (sph_u64)(((const unsigned char *)src)[7]); |
|
} |
|
#endif |
|
#else |
|
return ((sph_u64)(((const unsigned char *)src)[0]) << 56) |
|
| ((sph_u64)(((const unsigned char *)src)[1]) << 48) |
|
| ((sph_u64)(((const unsigned char *)src)[2]) << 40) |
|
| ((sph_u64)(((const unsigned char *)src)[3]) << 32) |
|
| ((sph_u64)(((const unsigned char *)src)[4]) << 24) |
|
| ((sph_u64)(((const unsigned char *)src)[5]) << 16) |
|
| ((sph_u64)(((const unsigned char *)src)[6]) << 8) |
|
| (sph_u64)(((const unsigned char *)src)[7]); |
|
#endif |
|
} |
|
|
|
/** |
|
* Decode a 64-bit value from the provided buffer (big endian convention). |
|
* The source buffer must be properly aligned. |
|
* |
|
* @param src the source buffer (64-bit aligned) |
|
* @return the decoded value |
|
*/ |
|
static SPH_INLINE sph_u64 |
|
sph_dec64be_aligned(const void *src) |
|
{ |
|
#if SPH_LITTLE_ENDIAN |
|
return sph_bswap64(*(const sph_u64 *)src); |
|
#elif SPH_BIG_ENDIAN |
|
return *(const sph_u64 *)src; |
|
#else |
|
return ((sph_u64)(((const unsigned char *)src)[0]) << 56) |
|
| ((sph_u64)(((const unsigned char *)src)[1]) << 48) |
|
| ((sph_u64)(((const unsigned char *)src)[2]) << 40) |
|
| ((sph_u64)(((const unsigned char *)src)[3]) << 32) |
|
| ((sph_u64)(((const unsigned char *)src)[4]) << 24) |
|
| ((sph_u64)(((const unsigned char *)src)[5]) << 16) |
|
| ((sph_u64)(((const unsigned char *)src)[6]) << 8) |
|
| (sph_u64)(((const unsigned char *)src)[7]); |
|
#endif |
|
} |
|
|
|
/** |
|
* Encode a 64-bit value into the provided buffer (little endian convention). |
|
* |
|
* @param dst the destination buffer |
|
* @param val the 64-bit value to encode |
|
*/ |
|
static SPH_INLINE void |
|
sph_enc64le(void *dst, sph_u64 val) |
|
{ |
|
#if defined SPH_UPTR |
|
#if SPH_UNALIGNED |
|
#if SPH_BIG_ENDIAN |
|
val = sph_bswap64(val); |
|
#endif |
|
*(sph_u64 *)dst = val; |
|
#else |
|
if (((SPH_UPTR)dst & 7) == 0) { |
|
#if SPH_BIG_ENDIAN |
|
val = sph_bswap64(val); |
|
#endif |
|
*(sph_u64 *)dst = val; |
|
} else { |
|
((unsigned char *)dst)[0] = val; |
|
((unsigned char *)dst)[1] = (val >> 8); |
|
((unsigned char *)dst)[2] = (val >> 16); |
|
((unsigned char *)dst)[3] = (val >> 24); |
|
((unsigned char *)dst)[4] = (val >> 32); |
|
((unsigned char *)dst)[5] = (val >> 40); |
|
((unsigned char *)dst)[6] = (val >> 48); |
|
((unsigned char *)dst)[7] = (val >> 56); |
|
} |
|
#endif |
|
#else |
|
((unsigned char *)dst)[0] = val; |
|
((unsigned char *)dst)[1] = (val >> 8); |
|
((unsigned char *)dst)[2] = (val >> 16); |
|
((unsigned char *)dst)[3] = (val >> 24); |
|
((unsigned char *)dst)[4] = (val >> 32); |
|
((unsigned char *)dst)[5] = (val >> 40); |
|
((unsigned char *)dst)[6] = (val >> 48); |
|
((unsigned char *)dst)[7] = (val >> 56); |
|
#endif |
|
} |
|
|
|
/** |
|
* Encode a 64-bit value into the provided buffer (little endian convention). |
|
* The destination buffer must be properly aligned. |
|
* |
|
* @param dst the destination buffer (64-bit aligned) |
|
* @param val the value to encode |
|
*/ |
|
static SPH_INLINE void |
|
sph_enc64le_aligned(void *dst, sph_u64 val) |
|
{ |
|
#if SPH_LITTLE_ENDIAN |
|
*(sph_u64 *)dst = val; |
|
#elif SPH_BIG_ENDIAN |
|
*(sph_u64 *)dst = sph_bswap64(val); |
|
#else |
|
((unsigned char *)dst)[0] = val; |
|
((unsigned char *)dst)[1] = (val >> 8); |
|
((unsigned char *)dst)[2] = (val >> 16); |
|
((unsigned char *)dst)[3] = (val >> 24); |
|
((unsigned char *)dst)[4] = (val >> 32); |
|
((unsigned char *)dst)[5] = (val >> 40); |
|
((unsigned char *)dst)[6] = (val >> 48); |
|
((unsigned char *)dst)[7] = (val >> 56); |
|
#endif |
|
} |
|
|
|
/** |
|
* Decode a 64-bit value from the provided buffer (little endian convention). |
|
* |
|
* @param src the source buffer |
|
* @return the decoded value |
|
*/ |
|
static SPH_INLINE sph_u64 |
|
sph_dec64le(const void *src) |
|
{ |
|
#if defined SPH_UPTR |
|
#if SPH_UNALIGNED |
|
#if SPH_BIG_ENDIAN |
|
return sph_bswap64(*(const sph_u64 *)src); |
|
#else |
|
return *(const sph_u64 *)src; |
|
#endif |
|
#else |
|
if (((SPH_UPTR)src & 7) == 0) { |
|
#if SPH_BIG_ENDIAN |
|
#if SPH_SPARCV9_GCC_64 && !SPH_NO_ASM |
|
sph_u64 tmp; |
|
|
|
__asm__ __volatile__ ( |
|
"ldxa [%1]0x88,%0" : "=r" (tmp) : "r" (src)); |
|
return tmp; |
|
/* |
|
* Not worth it generally. |
|
* |
|
#elif SPH_PPC32_GCC && !SPH_NO_ASM |
|
return (sph_u64)sph_dec32le_aligned(src) |
|
| ((sph_u64)sph_dec32le_aligned( |
|
(const char *)src + 4) << 32); |
|
#elif SPH_PPC64_GCC && !SPH_NO_ASM |
|
sph_u64 tmp; |
|
|
|
__asm__ __volatile__ ( |
|
"ldbrx %0,0,%1" : "=r" (tmp) : "r" (src)); |
|
return tmp; |
|
*/ |
|
#else |
|
return sph_bswap64(*(const sph_u64 *)src); |
|
#endif |
|
#else |
|
return *(const sph_u64 *)src; |
|
#endif |
|
} else { |
|
return (sph_u64)(((const unsigned char *)src)[0]) |
|
| ((sph_u64)(((const unsigned char *)src)[1]) << 8) |
|
| ((sph_u64)(((const unsigned char *)src)[2]) << 16) |
|
| ((sph_u64)(((const unsigned char *)src)[3]) << 24) |
|
| ((sph_u64)(((const unsigned char *)src)[4]) << 32) |
|
| ((sph_u64)(((const unsigned char *)src)[5]) << 40) |
|
| ((sph_u64)(((const unsigned char *)src)[6]) << 48) |
|
| ((sph_u64)(((const unsigned char *)src)[7]) << 56); |
|
} |
|
#endif |
|
#else |
|
return (sph_u64)(((const unsigned char *)src)[0]) |
|
| ((sph_u64)(((const unsigned char *)src)[1]) << 8) |
|
| ((sph_u64)(((const unsigned char *)src)[2]) << 16) |
|
| ((sph_u64)(((const unsigned char *)src)[3]) << 24) |
|
| ((sph_u64)(((const unsigned char *)src)[4]) << 32) |
|
| ((sph_u64)(((const unsigned char *)src)[5]) << 40) |
|
| ((sph_u64)(((const unsigned char *)src)[6]) << 48) |
|
| ((sph_u64)(((const unsigned char *)src)[7]) << 56); |
|
#endif |
|
} |
|
|
|
/** |
|
* Decode a 64-bit value from the provided buffer (little endian convention). |
|
* The source buffer must be properly aligned. |
|
* |
|
* @param src the source buffer (64-bit aligned) |
|
* @return the decoded value |
|
*/ |
|
static SPH_INLINE sph_u64 |
|
sph_dec64le_aligned(const void *src) |
|
{ |
|
#if SPH_LITTLE_ENDIAN |
|
return *(const sph_u64 *)src; |
|
#elif SPH_BIG_ENDIAN |
|
#if SPH_SPARCV9_GCC_64 && !SPH_NO_ASM |
|
sph_u64 tmp; |
|
|
|
__asm__ __volatile__ ("ldxa [%1]0x88,%0" : "=r" (tmp) : "r" (src)); |
|
return tmp; |
|
/* |
|
* Not worth it generally. |
|
* |
|
#elif SPH_PPC32_GCC && !SPH_NO_ASM |
|
return (sph_u64)sph_dec32le_aligned(src) |
|
| ((sph_u64)sph_dec32le_aligned((const char *)src + 4) << 32); |
|
#elif SPH_PPC64_GCC && !SPH_NO_ASM |
|
sph_u64 tmp; |
|
|
|
__asm__ __volatile__ ("ldbrx %0,0,%1" : "=r" (tmp) : "r" (src)); |
|
return tmp; |
|
*/ |
|
#else |
|
return sph_bswap64(*(const sph_u64 *)src); |
|
#endif |
|
#else |
|
return (sph_u64)(((const unsigned char *)src)[0]) |
|
| ((sph_u64)(((const unsigned char *)src)[1]) << 8) |
|
| ((sph_u64)(((const unsigned char *)src)[2]) << 16) |
|
| ((sph_u64)(((const unsigned char *)src)[3]) << 24) |
|
| ((sph_u64)(((const unsigned char *)src)[4]) << 32) |
|
| ((sph_u64)(((const unsigned char *)src)[5]) << 40) |
|
| ((sph_u64)(((const unsigned char *)src)[6]) << 48) |
|
| ((sph_u64)(((const unsigned char *)src)[7]) << 56); |
|
#endif |
|
} |
|
|
|
#endif |
|
|
|
#endif /* Doxygen excluded block */ |
|
|
|
#endif
|
|
|