1 /* 2 Borrowed XXH32 and XXH64 implementation from xxHash project 3 4 Added Copyright notice just above the function definition 5 6 TODO 1 : We might wanna implement our version of xxh for copyright reason 7 TODO 2 : We might wanna gather all copyright notice and create a single file. 8 */ 9 10 11 12 #include <stdint.h> 13 #include <netinet/in.h> 14 #include <arpa/inet.h> 15 #include <string.h> 16 #include <ctype.h> 17 #include <mtcp_util.h> 18 #include <limits.h> 19 #include <stdio.h> 20 #include <errno.h> 21 #include <stdlib.h> 22 23 /*-------------------------------------------------------------*/ 24 extern int 25 FetchEndianType(); 26 /*-------------------------------------------------------------*/ 27 static void 28 BuildKeyCache(uint32_t *cache, int cache_len) 29 { 30 #ifndef NBBY 31 #define NBBY 8 /* number of bits per byte */ 32 #endif 33 34 /* Both of DPDK and Netmap uses this key for hash calculation. 35 * Do not change any single bit of this key. */ 36 static const uint8_t key[] = { 37 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 38 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 39 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 40 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 41 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05 42 }; 43 44 uint32_t result = (((uint32_t)key[0]) << 24) | 45 (((uint32_t)key[1]) << 16) | 46 (((uint32_t)key[2]) << 8) | ((uint32_t)key[3]); 47 uint32_t idx = 32; 48 int i; 49 50 for (i = 0; i < cache_len; i++, idx++) { 51 uint8_t shift = (idx % NBBY); 52 uint32_t bit; 53 54 cache[i] = result; 55 bit = ((key[idx/NBBY] << shift) & 0x80) ? 1 : 0; 56 result = ((result << 1) | bit); 57 } 58 59 } 60 /*-------------------------------------------------------------*/ 61 uint32_t 62 GetRSSHash(in_addr_t sip, in_addr_t dip, in_port_t sp, in_port_t dp) 63 { 64 #define MSB32 0x80000000 65 #define MSB16 0x8000 66 #define KEY_CACHE_LEN 96 67 68 uint32_t res = 0; 69 int i; 70 static int first = 1; 71 static uint32_t key_cache[KEY_CACHE_LEN] = {0}; 72 73 if (first) { 74 BuildKeyCache(key_cache, KEY_CACHE_LEN); 75 first = 0; 76 } 77 78 for (i = 0; i < 32; i++) { 79 if (sip & MSB32) 80 res ^= key_cache[i]; 81 sip <<= 1; 82 } 83 for (i = 0; i < 32; i++) { 84 if (dip & MSB32) 85 res ^= key_cache[32+i]; 86 dip <<= 1; 87 } 88 for (i = 0; i < 16; i++) { 89 if (sp & MSB16) 90 res ^= key_cache[64+i]; 91 sp <<= 1; 92 } 93 for (i = 0; i < 16; i++) { 94 if (dp & MSB16) 95 res ^= key_cache[80+i]; 96 dp <<= 1; 97 } 98 return res; 99 } 100 /*-------------------------------------------------------------------*/ 101 /* RSS redirection table is in the little endian byte order (intel) */ 102 /* */ 103 /* idx: 0 1 2 3 | 4 5 6 7 | 8 9 10 11 | 12 13 14 15 | 16 17 18 19 ...*/ 104 /* val: 3 2 1 0 | 7 6 5 4 | 11 10 9 8 | 15 14 13 12 | 19 18 17 16 ...*/ 105 /* qid = val % num_queues */ 106 /*-------------------------------------------------------------------*/ 107 /* 108 * ixgbe (e.g., X520) : (Rx queue #) = (7 LS bits of RSS hash) mod N 109 * i40e (e.g., XL710) : (Rx queue #) = (9 LS bits of RSS hash) mod N 110 */ 111 /*-------------------------------------------------------------------*/ 112 #define RSS_BIT_MASK_IXGBE 0x0000007F 113 #define RSS_BIT_MASK_I40E 0x000001FF 114 int 115 GetRSSCPUCore(in_addr_t sip, in_addr_t dip, 116 in_port_t sp, in_port_t dp, int num_queues) 117 { 118 uint32_t masked; 119 int endian_type = FetchEndianType(); 120 121 if (endian_type) { 122 masked = GetRSSHash(sip, dip, sp, dp) & RSS_BIT_MASK_I40E; 123 static const uint32_t off[4] = {3, 1, -1, -3}; 124 masked += off[masked & 0x3]; 125 } 126 else 127 masked = GetRSSHash(sip, dip, sp, dp) & RSS_BIT_MASK_IXGBE; 128 129 return (masked % num_queues); 130 131 } 132 /*-------------------------------------------------------------*/ 133 int 134 mystrtol(const char *nptr, int base) 135 { 136 int rval; 137 char *endptr; 138 139 errno = 0; 140 rval = strtol(nptr, &endptr, 10); 141 /* check for strtol errors */ 142 if ((errno == ERANGE && (rval == LONG_MAX || 143 rval == LONG_MIN)) 144 || (errno != 0 && rval == 0)) { 145 perror("strtol"); 146 exit(EXIT_FAILURE); 147 } 148 if (endptr == nptr) { 149 fprintf(stderr, "Parsing strtol error!\n"); 150 exit(EXIT_FAILURE); 151 } 152 153 return rval; 154 } 155 /*---------------------------------------------------------------*/ 156 int 157 StrToArgs(char *str, int *argc, char **argv, int max_argc) 158 { 159 160 uint8_t single_quotes; 161 uint8_t double_quotes; 162 uint8_t delim; 163 164 single_quotes = 0; 165 double_quotes = 0; 166 delim = 1; 167 168 *argc = 0; 169 170 int i; 171 int len = strlen(str); 172 for (i = 0; i < len; i++) { 173 174 if (str[i] == '\'') { 175 if (single_quotes) 176 str[i] = '\0'; 177 else 178 i++; 179 single_quotes = !single_quotes; 180 goto __non_space; 181 } else if (str[i] == '\"') { 182 if (double_quotes) 183 str[i] = '\0'; 184 else 185 i++; 186 double_quotes = !double_quotes; 187 goto __non_space; 188 } 189 190 if (single_quotes || double_quotes) 191 continue; 192 193 if (isspace(str[i])) { 194 delim = 1; 195 str[i] = '\0'; 196 continue; 197 } 198 __non_space: 199 if (delim == 1) { 200 delim = 0; 201 argv[(*argc)++] = &str[i]; 202 if (*argc > max_argc) 203 break; 204 } 205 } 206 207 argv[*argc] = NULL; 208 209 return 0; 210 } 211 212 /* 213 xxHash - Fast Hash algorithm 214 Copyright (C) 2012-2015, Yann Collet 215 216 BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) 217 218 Redistribution and use in source and binary forms, with or without 219 modification, are permitted provided that the following conditions are 220 met: 221 222 * Redistributions of source code must retain the above copyright 223 notice, this list of conditions and the following disclaimer. 224 * Redistributions in binary form must reproduce the above 225 copyright notice, this list of conditions and the following disclaimer 226 in the documentation and/or other materials provided with the 227 distribution. 228 229 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 230 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 231 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 232 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 233 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 234 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 235 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 236 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 237 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 238 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 239 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 240 241 You can contact the author at : 242 - xxHash source repository : https://github.com/Cyan4973/xxHash 243 */ 244 245 246 247 248 /************************************** 249 * Tuning parameters 250 **************************************/ 251 /* Unaligned memory access is automatically enabled for "common" CPU, such as x86. 252 * For others CPU, the compiler will be more cautious, and insert extra code to ensure aligned access is respected. 253 * If you know your target CPU supports unaligned memory access, you want to force this option manually to improve performance. 254 * You can also enable this parameter if you know your input data will always be aligned (boundaries of 4, for U32). 255 */ 256 #if defined(__ARM_FEATURE_UNALIGNED) || defined(__i386) || defined(_M_IX86) || defined(__x86_64__) || defined(_M_X64) 257 # define XXH_USE_UNALIGNED_ACCESS 1 258 #endif 259 260 /* XXH_ACCEPT_NULL_INPUT_POINTER : 261 * If the input pointer is a null pointer, xxHash default behavior is to trigger a memory access error, since it is a bad pointer. 262 * When this option is enabled, xxHash output for null input pointers will be the same as a null-length input. 263 * By default, this option is disabled. To enable it, uncomment below define : 264 */ 265 /* #define XXH_ACCEPT_NULL_INPUT_POINTER 1 */ 266 267 /* XXH_FORCE_NATIVE_FORMAT : 268 * By default, xxHash library provides endian-independant Hash values, based on little-endian convention. 269 * Results are therefore identical for little-endian and big-endian CPU. 270 * This comes at a performance cost for big-endian CPU, since some swapping is required to emulate little-endian format. 271 * Should endian-independance be of no importance for your application, you may set the #define below to 1. 272 * It will improve speed for Big-endian CPU. 273 * This option has no impact on Little_Endian CPU. 274 */ 275 #define XXH_FORCE_NATIVE_FORMAT 0 276 277 278 /************************************** 279 * Compiler Specific Options 280 ***************************************/ 281 #ifdef _MSC_VER /* Visual Studio */ 282 # pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */ 283 # define FORCE_INLINE static __forceinline 284 #else 285 # if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L /* C99 */ 286 # ifdef __GNUC__ 287 # define FORCE_INLINE static inline __attribute__((always_inline)) 288 # else 289 # define FORCE_INLINE static inline 290 # endif 291 # else 292 # define FORCE_INLINE static 293 # endif /* __STDC_VERSION__ */ 294 #endif 295 296 297 /************************************** 298 * Basic Types 299 ***************************************/ 300 #if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L /* C99 */ 301 # include <stdint.h> 302 typedef uint8_t BYTE; 303 typedef uint16_t U16; 304 typedef uint32_t U32; 305 typedef int32_t S32; 306 typedef uint64_t U64; 307 #else 308 typedef unsigned char BYTE; 309 typedef unsigned short U16; 310 typedef unsigned int U32; 311 typedef signed int S32; 312 typedef unsigned long long U64; 313 #endif 314 315 static U32 XXH_read32(const void* memPtr) 316 { 317 U32 val32; 318 memcpy(&val32, memPtr, 4); 319 return val32; 320 } 321 322 static U64 XXH_read64(const void* memPtr) 323 { 324 U64 val64; 325 memcpy(&val64, memPtr, 8); 326 return val64; 327 } 328 329 330 331 /****************************************** 332 * Compiler-specific Functions and Macros 333 ******************************************/ 334 #define GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__) 335 336 /* Note : although _rotl exists for minGW (GCC under windows), performance seems poor */ 337 #if defined(_MSC_VER) 338 # define XXH_rotl32(x,r) _rotl(x,r) 339 # define XXH_rotl64(x,r) _rotl64(x,r) 340 #else 341 # define XXH_rotl32(x,r) ((x << r) | (x >> (32 - r))) 342 # define XXH_rotl64(x,r) ((x << r) | (x >> (64 - r))) 343 #endif 344 345 #if defined(_MSC_VER) /* Visual Studio */ 346 # define XXH_swap32 _byteswap_ulong 347 # define XXH_swap64 _byteswap_uint64 348 #elif GCC_VERSION >= 403 349 # define XXH_swap32 __builtin_bswap32 350 # define XXH_swap64 __builtin_bswap64 351 #else 352 static U32 XXH_swap32 (U32 x) 353 { 354 return ((x << 24) & 0xff000000 ) | 355 ((x << 8) & 0x00ff0000 ) | 356 ((x >> 8) & 0x0000ff00 ) | 357 ((x >> 24) & 0x000000ff ); 358 } 359 static U64 XXH_swap64 (U64 x) 360 { 361 return ((x << 56) & 0xff00000000000000ULL) | 362 ((x << 40) & 0x00ff000000000000ULL) | 363 ((x << 24) & 0x0000ff0000000000ULL) | 364 ((x << 8) & 0x000000ff00000000ULL) | 365 ((x >> 8) & 0x00000000ff000000ULL) | 366 ((x >> 24) & 0x0000000000ff0000ULL) | 367 ((x >> 40) & 0x000000000000ff00ULL) | 368 ((x >> 56) & 0x00000000000000ffULL); 369 } 370 #endif 371 372 373 /*************************************** 374 * Architecture Macros 375 ***************************************/ 376 typedef enum { XXH_bigEndian=0, XXH_littleEndian=1 } XXH_endianess; 377 #ifndef XXH_CPU_LITTLE_ENDIAN /* XXH_CPU_LITTLE_ENDIAN can be defined externally, for example using a compiler switch */ 378 static const int one = 1; 379 # define XXH_CPU_LITTLE_ENDIAN (*(const char*)(&one)) 380 #endif 381 382 383 /***************************** 384 * Memory reads 385 *****************************/ 386 typedef enum { XXH_aligned, XXH_unaligned } XXH_alignment; 387 388 FORCE_INLINE U32 XXH_readLE32_align(const void* ptr, XXH_endianess endian, XXH_alignment align) 389 { 390 if (align==XXH_unaligned) 391 return endian==XXH_littleEndian ? XXH_read32(ptr) : XXH_swap32(XXH_read32(ptr)); 392 else 393 return endian==XXH_littleEndian ? *(const U32*)ptr : XXH_swap32(*(const U32*)ptr); 394 } 395 396 FORCE_INLINE U64 XXH_readLE64_align(const void* ptr, XXH_endianess endian, XXH_alignment align) 397 { 398 if (align==XXH_unaligned) 399 return endian==XXH_littleEndian ? XXH_read64(ptr) : XXH_swap64(XXH_read64(ptr)); 400 else 401 return endian==XXH_littleEndian ? *(const U64*)ptr : XXH_swap64(*(const U64*)ptr); 402 } 403 404 /*************************************** 405 * Macros 406 ***************************************/ 407 #define XXH_STATIC_ASSERT(c) { enum { XXH_static_assert = 1/(!!(c)) }; } /* use only *after* variable declarations */ 408 409 410 /*************************************** 411 * Constants 412 ***************************************/ 413 #define PRIME32_1 2654435761U 414 #define PRIME32_2 2246822519U 415 #define PRIME32_3 3266489917U 416 #define PRIME32_4 668265263U 417 #define PRIME32_5 374761393U 418 419 #define PRIME64_1 11400714785074694791ULL 420 #define PRIME64_2 14029467366897019727ULL 421 #define PRIME64_3 1609587929392839161ULL 422 #define PRIME64_4 9650029242287828579ULL 423 #define PRIME64_5 2870177450012600261ULL 424 425 426 /***************************** 427 * Simple Hash Functions 428 *****************************/ 429 FORCE_INLINE U32 XXH32_endian_align(const void* input, size_t len, U32 seed, XXH_endianess endian, XXH_alignment align) 430 { 431 const BYTE* p = (const BYTE*)input; 432 const BYTE* bEnd = p + len; 433 U32 h32; 434 #define XXH_get32bits(p) XXH_readLE32_align(p, endian, align) 435 436 #ifdef XXH_ACCEPT_NULL_INPUT_POINTER 437 if (p==NULL) 438 { 439 len=0; 440 bEnd=p=(const BYTE*)(size_t)16; 441 } 442 #endif 443 444 if (len>=16) 445 { 446 const BYTE* const limit = bEnd - 16; 447 U32 v1 = seed + PRIME32_1 + PRIME32_2; 448 U32 v2 = seed + PRIME32_2; 449 U32 v3 = seed + 0; 450 U32 v4 = seed - PRIME32_1; 451 452 do 453 { 454 v1 += XXH_get32bits(p) * PRIME32_2; 455 v1 = XXH_rotl32(v1, 13); 456 v1 *= PRIME32_1; 457 p+=4; 458 v2 += XXH_get32bits(p) * PRIME32_2; 459 v2 = XXH_rotl32(v2, 13); 460 v2 *= PRIME32_1; 461 p+=4; 462 v3 += XXH_get32bits(p) * PRIME32_2; 463 v3 = XXH_rotl32(v3, 13); 464 v3 *= PRIME32_1; 465 p+=4; 466 v4 += XXH_get32bits(p) * PRIME32_2; 467 v4 = XXH_rotl32(v4, 13); 468 v4 *= PRIME32_1; 469 p+=4; 470 } 471 while (p<=limit); 472 473 h32 = XXH_rotl32(v1, 1) + XXH_rotl32(v2, 7) + XXH_rotl32(v3, 12) + XXH_rotl32(v4, 18); 474 } 475 else 476 { 477 h32 = seed + PRIME32_5; 478 } 479 480 h32 += (U32) len; 481 482 while (p+4<=bEnd) 483 { 484 h32 += XXH_get32bits(p) * PRIME32_3; 485 h32 = XXH_rotl32(h32, 17) * PRIME32_4 ; 486 p+=4; 487 } 488 489 while (p<bEnd) 490 { 491 h32 += (*p) * PRIME32_5; 492 h32 = XXH_rotl32(h32, 11) * PRIME32_1 ; 493 p++; 494 } 495 496 h32 ^= h32 >> 15; 497 h32 *= PRIME32_2; 498 h32 ^= h32 >> 13; 499 h32 *= PRIME32_3; 500 h32 ^= h32 >> 16; 501 502 return h32; 503 } 504 505 506 unsigned XXH32 (const void* input, size_t len, unsigned seed) 507 { 508 #if 0 509 /* Simple version, good for code maintenance, but unfortunately slow for small inputs */ 510 XXH32_state_t state; 511 XXH32_reset(&state, seed); 512 XXH32_update(&state, input, len); 513 return XXH32_digest(&state); 514 #else 515 XXH_endianess endian_detected = (XXH_endianess)XXH_CPU_LITTLE_ENDIAN; 516 517 # if !defined(XXH_USE_UNALIGNED_ACCESS) 518 if ((((size_t)input) & 3) == 0) /* Input is 4-bytes aligned, leverage the speed benefit */ 519 { 520 if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT) 521 return XXH32_endian_align(input, len, seed, XXH_littleEndian, XXH_aligned); 522 else 523 return XXH32_endian_align(input, len, seed, XXH_bigEndian, XXH_aligned); 524 } 525 # endif 526 527 if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT) 528 return XXH32_endian_align(input, len, seed, XXH_littleEndian, XXH_unaligned); 529 else 530 return XXH32_endian_align(input, len, seed, XXH_bigEndian, XXH_unaligned); 531 #endif 532 } 533 534 FORCE_INLINE U64 XXH64_endian_align(const void* input, size_t len, U64 seed, XXH_endianess endian, XXH_alignment align) 535 { 536 const BYTE* p = (const BYTE*)input; 537 const BYTE* bEnd = p + len; 538 U64 h64; 539 #define XXH_get64bits(p) XXH_readLE64_align(p, endian, align) 540 541 #ifdef XXH_ACCEPT_NULL_INPUT_POINTER 542 if (p==NULL) 543 { 544 len=0; 545 bEnd=p=(const BYTE*)(size_t)32; 546 } 547 #endif 548 549 if (len>=32) 550 { 551 const BYTE* const limit = bEnd - 32; 552 U64 v1 = seed + PRIME64_1 + PRIME64_2; 553 U64 v2 = seed + PRIME64_2; 554 U64 v3 = seed + 0; 555 U64 v4 = seed - PRIME64_1; 556 557 do 558 { 559 v1 += XXH_get64bits(p) * PRIME64_2; 560 p+=8; 561 v1 = XXH_rotl64(v1, 31); 562 v1 *= PRIME64_1; 563 v2 += XXH_get64bits(p) * PRIME64_2; 564 p+=8; 565 v2 = XXH_rotl64(v2, 31); 566 v2 *= PRIME64_1; 567 v3 += XXH_get64bits(p) * PRIME64_2; 568 p+=8; 569 v3 = XXH_rotl64(v3, 31); 570 v3 *= PRIME64_1; 571 v4 += XXH_get64bits(p) * PRIME64_2; 572 p+=8; 573 v4 = XXH_rotl64(v4, 31); 574 v4 *= PRIME64_1; 575 } 576 while (p<=limit); 577 578 h64 = XXH_rotl64(v1, 1) + XXH_rotl64(v2, 7) + XXH_rotl64(v3, 12) + XXH_rotl64(v4, 18); 579 580 v1 *= PRIME64_2; 581 v1 = XXH_rotl64(v1, 31); 582 v1 *= PRIME64_1; 583 h64 ^= v1; 584 h64 = h64 * PRIME64_1 + PRIME64_4; 585 586 v2 *= PRIME64_2; 587 v2 = XXH_rotl64(v2, 31); 588 v2 *= PRIME64_1; 589 h64 ^= v2; 590 h64 = h64 * PRIME64_1 + PRIME64_4; 591 592 v3 *= PRIME64_2; 593 v3 = XXH_rotl64(v3, 31); 594 v3 *= PRIME64_1; 595 h64 ^= v3; 596 h64 = h64 * PRIME64_1 + PRIME64_4; 597 598 v4 *= PRIME64_2; 599 v4 = XXH_rotl64(v4, 31); 600 v4 *= PRIME64_1; 601 h64 ^= v4; 602 h64 = h64 * PRIME64_1 + PRIME64_4; 603 } 604 else 605 { 606 h64 = seed + PRIME64_5; 607 } 608 609 h64 += (U64) len; 610 611 while (p+8<=bEnd) 612 { 613 U64 k1 = XXH_get64bits(p); 614 k1 *= PRIME64_2; 615 k1 = XXH_rotl64(k1,31); 616 k1 *= PRIME64_1; 617 h64 ^= k1; 618 h64 = XXH_rotl64(h64,27) * PRIME64_1 + PRIME64_4; 619 p+=8; 620 } 621 622 if (p+4<=bEnd) 623 { 624 h64 ^= (U64)(XXH_get32bits(p)) * PRIME64_1; 625 h64 = XXH_rotl64(h64, 23) * PRIME64_2 + PRIME64_3; 626 p+=4; 627 } 628 629 while (p<bEnd) 630 { 631 h64 ^= (*p) * PRIME64_5; 632 h64 = XXH_rotl64(h64, 11) * PRIME64_1; 633 p++; 634 } 635 636 h64 ^= h64 >> 33; 637 h64 *= PRIME64_2; 638 h64 ^= h64 >> 29; 639 h64 *= PRIME64_3; 640 h64 ^= h64 >> 32; 641 642 return h64; 643 } 644 645 646 unsigned long long XXH64 (const void* input, size_t len, unsigned long long seed) 647 { 648 #if 0 649 /* Simple version, good for code maintenance, but unfortunately slow for small inputs */ 650 XXH64_state_t state; 651 XXH64_reset(&state, seed); 652 XXH64_update(&state, input, len); 653 return XXH64_digest(&state); 654 #else 655 XXH_endianess endian_detected = (XXH_endianess)XXH_CPU_LITTLE_ENDIAN; 656 657 # if !defined(XXH_USE_UNALIGNED_ACCESS) 658 if ((((size_t)input) & 7)==0) /* Input is aligned, let's leverage the speed advantage */ 659 { 660 if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT) 661 return XXH64_endian_align(input, len, seed, XXH_littleEndian, XXH_aligned); 662 else 663 return XXH64_endian_align(input, len, seed, XXH_bigEndian, XXH_aligned); 664 } 665 # endif 666 667 if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT) 668 return XXH64_endian_align(input, len, seed, XXH_littleEndian, XXH_unaligned); 669 else 670 return XXH64_endian_align(input, len, seed, XXH_bigEndian, XXH_unaligned); 671 #endif 672 } 673 674