ATLAS Offline Software
Loading...
Searching...
No Matches
crc64.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2026 CERN for the benefit of the ATLAS collaboration
3*/
4/*
5 */
193
194
195#include "CxxUtils/crc64.h"
196#include <stdio.h>
197
198
199#if ATH_CRC64_VEC
201
202// Two 64-bit integers.
203typedef long long int v2di __attribute__ ((vector_size (16)));
204
205
206// Two unsigned 64-bit integers.
207typedef uint64_t v2du __attribute__ ((vector_size (16)));
208
209
210// 16 signed characters.
211typedef char v16qi __attribute__ ((vector_size (16)));
212
213
214#endif
215
216
217namespace {
218
219
220//***************************************************************************
221// Primitive functions and utilities.
222//
223
224
225#if ATH_CRC64_VEC
231inline
232v2di load_unaligned (const char* x)
233{
234 return (v2di)__builtin_ia32_loaddqu (x);
235}
236
237
243inline
244v2di load_aligned (const char* x)
245{
246 return *(v2di*)x;
247}
248
249
255// A macro, not a function, because the second argument is constrained
256// to be an 8-bit constant. If this were a function, compilation might fail
257// if it is not inlined.
258#define byteshift_l(X, N) (__builtin_ia32_pslldqi128 ((X), (N)*8))
259
260
266// A macro, not a function; see above.
267#define byteshift_r(X, N) (__builtin_ia32_psrldqi128 ((X), (N)*8))
268
269
280// A macro, not a function; see above.
281#define clmul(A, B, WHICH) (__builtin_ia32_pclmulqdq128 ((A), (B), (WHICH)))
282
283
296__attribute__ ((target ("sse4")))
297inline
298void byteshift_l256 (v2di in, size_t n, v2di& outHigh, v2di& outLow)
299{
300 static const uint8_t shuffleMasks[] = {
301 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
302 0x8f, 0x8e, 0x8d, 0x8c, 0x8b, 0x8a, 0x89, 0x88, 0x87, 0x86, 0x85, 0x84, 0x83, 0x82, 0x81, 0x80,
303 };
304
305 const v16qi mask = (v16qi)load_unaligned ((const char*)shuffleMasks + (16-n));
306 outLow = (v2di)__builtin_ia32_pshufb128 ((v16qi)in, ~mask);
307 outHigh = (v2di)__builtin_ia32_pshufb128 ((v16qi)in, mask);
308}
309
310
318inline
319uint64_t hightest (uint64_t x, uint64_t y)
320{
321 // Relies on sign-extension of right-shift of a signed int.
322 // This is strictly speaking implementation-defined behavior.
323 // Since this code is anyway enabled only on x86_64, that's ok.
324 // cppcheck-suppress shiftTooManyBitsSigned
325 return y & (static_cast<int64_t>(x)>>63);
326}
327
328
338uint64_t exp_mod (unsigned exp, uint64_t p)
339{
340 // This is basically just doing binary long division without carry
341 // (so subtraction becomes xor).
342 uint64_t d = p;
343 for (unsigned i=0; i < exp-64; i++) {
344 d = (d<<1) ^ hightest (d, p);
345 }
346 return d;
347}
348
349
358uint64_t exp129_div (uint64_t p)
359{
360 // Again, just binary long division without carry.
361 uint64_t q = 0;
362 uint64_t h = p;
363 for (unsigned i=0; i < 64; i++) {
364 q |= (h & (1ull << 63)) >> i;
365 h = (h << 1) ^ hightest (h, p);
366 }
367 return q;
368}
369
370
371#endif // ATH_CRC64_VEC
372
373
374/*
375 * @brief Reflect the bits in a 64-bit word around the center.
376 * @param v Value to reflect.
377 *
378 * So, for example, 0x0120034005600780 becomes
379 * 0x01e006a002c00480
380 *
381 * Reference: https://graphics.stanford.edu/~seander/bithacks.html#ReverseParallel
382 * Originally credited to E. Freed, Dr. Dobbs's Journal 8 no. 4, p. 24 (1983).
383 */
384uint64_t bit_reflect (uint64_t v)
385{
386 v = ((v >> 1) & 0x5555555555555555) | ((v & 0x5555555555555555) << 1);
387 v = ((v >> 2) & 0x3333333333333333) | ((v & 0x3333333333333333) << 2);
388 v = ((v >> 4) & 0x0F0F0F0F0F0F0F0F) | ((v & 0x0F0F0F0F0F0F0F0F) << 4);
389 v = ((v >> 8) & 0x00FF00FF00FF00FF) | ((v & 0x00FF00FF00FF00FF) << 8);
390 v = ((v >> 16) & 0x0000FFFF0000FFFF) | ((v & 0x0000FFFF0000FFFF) << 16);
391 v = (v >> 32) | (v << 32);
392 return v;
393}
394
395
396//****************************************************************************
397// CRC helpers.
398//
399
400
401#if ATH_CRC64_VEC
410__attribute__ ((target ("pclmul")))
411inline
412v2di folding_round (v2di fold, v2di data, v2di k)
413{
414 return data
415 ^ clmul (fold, k, 0x00)
416 ^ clmul (fold, k, 0x11);
417}
418
419
425__attribute__ ((target ("pclmul")))
426inline
427v2di fold_trailing_zeros (v2di data, v2di k)
428{
429 return clmul (data, k, 0x10) ^ byteshift_r (data, 8);
430}
431
432
438__attribute__ ((target ("pclmul")))
439inline
440v2di barrett_reduce (v2di R, v2di k)
441{
442 v2di T1 = clmul (R, k, 0x00);
443 return R
444 ^ clmul (T1, k, 0x10)
445 ^ byteshift_l (T1, 8);
446}
447#endif
448
449
450} // anonymous namespace
451
452
453namespace CxxUtils {
454
455
456//***************************************************************************
457// Public entry points.
458//
459
464{
465public:
471 CRCTable (uint64_t p, uint64_t initial = 0xffffffffffffffff);
472
474 uint64_t m_initial;
475
477 uint64_t m_table[256];
478
479#if ATH_CRC64_VEC
481 v2di m_fold_constants;
482
484 v2di m_barrett_constants;
485#endif
486};
487
488
494CRCTable::CRCTable (uint64_t p, uint64_t initial /* = 0xffffffffffffffff*/)
495{
496 m_initial = initial;
497
498 uint64_t prev = bit_reflect (p);
499 for (int i = 0; i < 256; i++)
500 {
501 uint64_t r = i;
502 for (int j = 0; j < 8; j++)
503 {
504 if (r & 1)
505 r = (r >> 1) ^ prev;
506 else
507 r >>= 1;
508 }
509 m_table[i] = r;
510 }
511
512#if ATH_CRC64_VEC
513 const uint64_t k1 = bit_reflect (exp_mod (128+64, p)) << 1;
514 const uint64_t k2 = bit_reflect (exp_mod (128, p)) << 1;
515 const uint64_t mu = (bit_reflect (exp129_div (p)) << 1) | 1;
516 const uint64_t prev65 = (bit_reflect (p) << 1) | 1;
517 v2du a = {k1, k2};
518 m_fold_constants = reinterpret_cast<v2di>(a);
519 v2du b = { mu, prev65 };
520 m_barrett_constants = reinterpret_cast<v2di>(b);
521#endif
522}
523
524
525// Polynomial taken from code from David T. Jones (dtj@cs.ucl.ac.uk).
526// (The form given here is reversed.)
527// http://www0.cs.ucl.ac.uk/staff/D.Jones/crcnote.pdf
528const CRCTable defaultCRCTable (0xad93d23594c935a9);
529
530
535{
536 delete table;
537}
538
539
546std::unique_ptr<CRCTable> makeCRCTable (uint64_t p,
547 uint64_t initial /*= 0xffffffffffffffff*/)
548{
549 return std::make_unique<CRCTable> (p, initial);
550}
551
552
559uint64_t crc64_bytewise (const CRCTable& table,
560 const char* data,
561 size_t data_len)
562{
563 uint64_t crc = table.m_initial;
564 const char* seq = data;
565 const char* end = seq + data_len;
566 while (seq < end)
567 crc = table.m_table[(crc ^ *seq++) & 0xff] ^ (crc >> 8);
568 return crc;
569}
570
571
579uint64_t crc64_bytewise (const char* data,
580 size_t data_len)
581{
582 return crc64_bytewise (defaultCRCTable, data, data_len);
583}
584
585
592uint64_t crc64_bytewise (const std::string& s)
593{
594 return crc64_bytewise (defaultCRCTable, s.data(), s.size());
595}
596
597
598#if ATH_CRC64_VEC
605__attribute__ ((target ("pclmul")))
606uint64_t crc64 (const CRCTable& table,
607 const char* data,
608 size_t data_len)
609{
610 uint64_t crc = table.m_initial;
611
612 // Early exit if the string is null.
613 if (!data_len) [[unlikely]] return crc;
614
615 // The main body assumes that the data are aligned to 128 bits.
616 // This should almost always be the case. But just in case the input
617 // string is not, consume the initial unaligned portion byte-by-byte
618 // until it is.
619 if (reinterpret_cast<unsigned long>(data) & 15) [[unlikely]] {
620 // Number of unaligned bytes we need to read from the start of the string.
621 size_t leadin = std::min (16 - (reinterpret_cast<unsigned long>(data) & 15), data_len);
622 crc = crc64_bytewise (table, data, leadin);
623 data += leadin;
624 data_len -= leadin;
625
626 if (!data_len) [[unlikely]] return crc;
627 }
628
629 // Accumulator for CRC value.
630 v2di fold = {static_cast<int64_t>(crc), 0};
631
632 // Constants for the folding step.
633 v2di k = table.m_fold_constants;
634
635 if (data_len < 16) [[unlikely]] {
636 // Special case for less than 128 bits.
637 v2di temp2 = load_aligned (data);
638 v2di crc0, crc1;
639 byteshift_l256 (fold, 16-data_len, crc1, crc0);
640 v2di A, B;
641 byteshift_l256 (temp2, 16-data_len, B, A);
642
643 fold = A ^ crc0;
644 fold = fold_trailing_zeros (fold, k);
645 fold ^= byteshift_l (crc1, 8);
646 }
647 else {
648 // We have 128 bits or more.
649
650 // Load the first 128 bits.
651 fold ^= load_aligned (data);
652
653 // Main folding loop. Fold in 128 bits at a time until there
654 // are fewer than 128 left.
655 size_t n = 16;
656 for (; n+16 <= data_len; n += 16) {
657 v2di temp2 = load_aligned (data + n);
658 fold = folding_round (fold, temp2, k);
659 }
660
661 // Handle a partial block at the end of less than 128 bits.
662 if (n < data_len) [[likely]] {
663 v2di remainder = load_aligned (data + n);
664 // Number of remaining bytes.
665 size_t nrem = data_len - n;
666 v2di A, B, C, D;
667 byteshift_l256 (fold, 16-nrem, B, A);
668 byteshift_l256 (remainder, 16-nrem, D, C);
669 fold = folding_round (A, B|C, k);
670 }
671 fold = fold_trailing_zeros (fold, k);
672 }
673
675 fold = barrett_reduce (fold, table.m_barrett_constants);
676
677 return fold[1];
678}
679
680
681#endif // ATH_CRC64_VEC
682
683
692#if ATH_CRC64_VEC
693__attribute__ ((target ("default")))
694#endif
695uint64_t crc64 (const CRCTable& table,
696 const char* data,
697 size_t data_len)
698{
699 return crc64_bytewise (table, data, data_len);
700}
701
702
708uint64_t crc64 (const char* data,
709 size_t data_len)
710{
711 return crc64 (defaultCRCTable, data, data_len);
712}
713
714
719uint64_t crc64 (const std::string& s)
720{
721 return crc64 (defaultCRCTable, s.data(), s.size());
722}
723
724
731uint64_t crc64addint (uint64_t crc, uint64_t x)
732{
733 while (x > 0) {
734 crc = defaultCRCTable.m_table[(crc ^ x) & 0xff] ^ (crc >> 8);
735 x >>= 8;
736 }
737 return crc;
738}
739
740
745std::string crc64format (uint64_t crc)
746{
747 char buf[64];
748 sprintf (buf, "%08X%08X",
749 (unsigned)((crc>>32)&0xffffffff), (unsigned)(crc&0xffffffff));
750 return buf;
751}
752
753
760std::string crc64digest (const std::string& str)
761{
762 return crc64format (crc64 (str));
763}
764
765
766} // namespace CxxUtils
767
768
static Double_t a
__attribute__((always_inline)) inline uint16_t TileCalibDrawerBase
#define y
#define x
Header file for AthHistogramAlgorithm.
Precomputed tables and constants for the CRC calculation.
Definition crc64.cxx:464
uint64_t m_initial
Initial CRC value.
Definition crc64.cxx:474
uint64_t m_table[256]
Lookup table for bytewise CRC calculation.
Definition crc64.cxx:477
CRCTable(uint64_t p, uint64_t initial=0xffffffffffffffff)
Initialize the CRC tables and constants.
Definition crc64.cxx:494
std::vector< std::string > remainder(const std::vector< std::string > &v1, const std::vector< std::string > &v2)
uint64_t bit_reflect(uint64_t v)
Definition crc64.cxx:384
A crc-64 implementation, using pclmul where possible.
int r
Definition globals.cxx:22
struct color C
double R(const INavigable4Momentum *p1, const double v_eta, const double v_phi)
uint64_t crc64(const CRCTable &table, const char *data, size_t data_len)
Find the CRC-64 of a string,.
Definition crc64.cxx:695
uint64_t crc64_bytewise(const CRCTable &table, const char *data, size_t data_len)
Find the CRC-64 of a string, using a byte-by-byte algorithm.
Definition crc64.cxx:559
std::unique_ptr< CRCTable > makeCRCTable(uint64_t p, uint64_t initial=0xffffffffffffffff)
Initialize CRC tables and constants.
Definition crc64.cxx:546
const CRCTable defaultCRCTable(0xad93d23594c935a9)
std::string crc64digest(const std::string &str)
Return a CRC-64 digest of a string.
Definition crc64.cxx:760
const_iterator end() const
Return an end iterator.
std::string crc64format(uint64_t crc)
Format a CRC-64 as a string.
Definition crc64.cxx:745
void deleteCRCTable(CxxUtils::CRCTable *table)
Delete a CRCTable object.
Definition crc64.cxx:534
uint64_t crc64addint(uint64_t crc, uint64_t x)
Extend a previously-calculated CRC to include an int.
Definition crc64.cxx:731
#define likely(x)
#define unlikely(x)