llvm.org GIT mirror llvm / 5cd79bc
Perform partial SROA on the helper hashing structure. I really wish the optimizers could do this for us, but expecting partial SROA of classes with template methods through cloning is probably expecting too much heroics. With this change, the begin/end pointer pairs which indicate the status of each loop iteration are actually passed directly into each layer of the combine_data calls, and the inliner has a chance to see when most of the combine_data function could be deleted by inlining. Similarly for 'length'. We have to be careful to limit the places where in/out reference parameters are used as those will also defeat the inliner / optimizers from properly propagating constants. With this change, LLVM is able to fully inline and unroll the hash computation of small sets of values, such as two or three pointers. These now decompose into essentially straight-line code with no loops or function calls. There is still one code quality problem to be solved with the hashing -- LLVM is failing to nuke the alloca. It removes all loads from the alloca, leaving only lifetime intrinsics and dead(!!) stores to the alloca. =/ Very unfortunate. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@154264 91177308-0d34-0410-b5e6-96231b3b80d8 Chandler Carruth 8 years ago
1 changed file(s) with 49 addition(s) and 43 deletion(s). Raw diff Collapse all Expand all
504504 /// recursive combining of arguments used in hash_combine. It is particularly
505505 /// useful at minimizing the code in the recursive calls to ease the pain
506506 /// caused by a lack of variadic functions.
507 class hash_combine_recursive_helper {
507 struct hash_combine_recursive_helper {
508 char buffer[64];
509 hash_state state;
508510 const size_t seed;
509 char buffer[64];
510 char *const buffer_end;
511 char *buffer_ptr;
512 size_t length;
513 hash_state state;
514511
515512 public:
516513 /// \brief Construct a recursive hash combining helper.
518515 /// This sets up the state for a recursive hash combine, including getting
519516 /// the seed and buffer setup.
520517 hash_combine_recursive_helper()
521 : seed(get_execution_seed()),
522 buffer_end(buffer + array_lengthof(buffer)),
523 buffer_ptr(buffer),
524 length(0) {}
518 : seed(get_execution_seed()) {}
525519
526520 /// \brief Combine one chunk of data into the current in-flight hash.
527521 ///
529523 /// the data. If the buffer is full, it hashes the buffer into its
530524 /// hash_state, empties it, and then merges the new chunk in. This also
531525 /// handles cases where the data straddles the end of the buffer.
532 template void combine_data(T data) {
526 template
527 char *combine_data(size_t &length, char *buffer_ptr, char *buffer_end, T data) {
533528 if (!store_and_advance(buffer_ptr, buffer_end, data)) {
534529 // Check for skew which prevents the buffer from being packed, and do
535530 // a partial store into the buffer to fill it. This is only a concern
560555 partial_store_size))
561556 abort();
562557 }
558 return buffer_ptr;
563559 }
564560
565561 #if defined(__has_feature) && __has_feature(__cxx_variadic_templates__)
569565 /// This function recurses through each argument, combining that argument
570566 /// into a single hash.
571567 template
572 hash_code combine(const T &arg, const Ts &...args) {
573 combine_data( get_hashable_data(arg));
568 hash_code combine(size_t length, char *buffer_ptr, char *buffer_end,
569 const T &arg, const Ts &...args) {
570 buffer_ptr = combine_data(length, buffer_ptr, buffer_end, get_hashable_data(arg));
574571
575572 // Recurse to the next argument.
576 return combine(args...);
573 return combine(length, buffer_ptr, buffer_end, args...);
577574 }
578575
579576 #else
582579
583580 template
584581 typename T6>
585 hash_code combine(const T1 &arg1, const T2 &arg2, const T3 &arg3,
582 hash_code combine(size_t length, char *buffer_ptr, char *buffer_end,
583 const T1 &arg1, const T2 &arg2, const T3 &arg3,
586584 const T4 &arg4, const T5 &arg5, const T6 &arg6) {
587 combine_data(get_hashable_data(arg1));
588 return combine(arg2, arg3, arg4, arg5, arg6);
585 buffer_ptr = combine_data(length, buffer_ptr, buffer_end, get_hashable_data(arg1));
586 return combine(length, buffer_ptr, buffer_end, arg2, arg3, arg4, arg5, arg6);
589587 }
590588 template
591 hash_code combine(const T1 &arg1, const T2 &arg2, const T3 &arg3,
589 hash_code combine(size_t length, char *buffer_ptr, char *buffer_end,
590 const T1 &arg1, const T2 &arg2, const T3 &arg3,
592591 const T4 &arg4, const T5 &arg5) {
593 combine_data(get_hashable_data(arg1));
594 return combine(arg2, arg3, arg4, arg5);
592 buffer_ptr = combine_data(length, buffer_ptr, buffer_end, get_hashable_data(arg1));
593 return combine(length, buffer_ptr, buffer_end, arg2, arg3, arg4, arg5);
595594 }
596595 template
597 hash_code combine(const T1 &arg1, const T2 &arg2, const T3 &arg3,
596 hash_code combine(size_t length, char *buffer_ptr, char *buffer_end,
597 const T1 &arg1, const T2 &arg2, const T3 &arg3,
598598 const T4 &arg4) {
599 combine_data(get_hashable_data(arg1));
600 return combine(arg2, arg3, arg4);
599 buffer_ptr = combine_data(length, buffer_ptr, buffer_end, get_hashable_data(arg1));
600 return combine(length, buffer_ptr, buffer_end, arg2, arg3, arg4);
601601 }
602602 template
603 hash_code combine(const T1 &arg1, const T2 &arg2, const T3 &arg3) {
604 combine_data(get_hashable_data(arg1));
605 return combine(arg2, arg3);
603 hash_code combine(size_t length, char *buffer_ptr, char *buffer_end,
604 const T1 &arg1, const T2 &arg2, const T3 &arg3) {
605 buffer_ptr = combine_data(length, buffer_ptr, buffer_end, get_hashable_data(arg1));
606 return combine(length, buffer_ptr, buffer_end, arg2, arg3);
606607 }
607608 template
608 hash_code combine(const T1 &arg1, const T2 &arg2) {
609 combine_data(get_hashable_data(arg1));
610 return combine(arg2);
609 hash_code combine(size_t length, char *buffer_ptr, char *buffer_end,
610 const T1 &arg1, const T2 &arg2) {
611 buffer_ptr = combine_data(length, buffer_ptr, buffer_end, get_hashable_data(arg1));
612 return combine(length, buffer_ptr, buffer_end, arg2);
611613 }
612614 template
613 hash_code combine(const T1 &arg1) {
614 combine_data(get_hashable_data(arg1));
615 return combine();
615 hash_code combine(size_t length, char *buffer_ptr, char *buffer_end,
616 const T1 &arg1) {
617 buffer_ptr = combine_data(length, buffer_ptr, buffer_end, get_hashable_data(arg1));
618 return combine(length, buffer_ptr, buffer_end);
616619 }
617620
618621 #endif
622625 /// The base case when combining arguments recursively is reached when all
623626 /// arguments have been handled. It flushes the remaining buffer and
624627 /// constructs a hash_code.
625 hash_code combine() {
628 hash_code combine(size_t length, char *buffer_ptr, char *buffer_end) {
626629 // Check whether the entire set of values fit in the buffer. If so, we'll
627630 // use the optimized short hashing routine and skip state entirely.
628631 if (length == 0)
662665 template hash_code hash_combine(const Ts &...args) {
663666 // Recursively hash each argument using a helper class.
664667 ::llvm::hashing::detail::hash_combine_recursive_helper helper;
665 return helper.combine(args...);
668 return helper.combine(0, helper.buffer, helper.buffer + 64, args...);
666669 }
667670
668671 #else
673676 template
674677 typename T6>
675678 hash_code hash_combine(const T1 &arg1, const T2 &arg2, const T3 &arg3,
676 const T4 &arg4, const T5 &arg5, const T6 &arg6) {
679 const T4 &arg4, const T5 &arg5, const T6 &arg6) {
677680 ::llvm::hashing::detail::hash_combine_recursive_helper helper;
678 return helper.combine(arg1, arg2, arg3, arg4, arg5, arg6);
681 return helper.combine(0, helper.buffer, helper.buffer + 64,
682 arg1, arg2, arg3, arg4, arg5, arg6);
679683 }
680684 template
681685 hash_code hash_combine(const T1 &arg1, const T2 &arg2, const T3 &arg3,
682 const T4 &arg4, const T5 &arg5) {
686 const T4 &arg4, const T5 &arg5) {
683687 ::llvm::hashing::detail::hash_combine_recursive_helper helper;
684 return helper.combine(arg1, arg2, arg3, arg4, arg5);
688 return helper.combine(0, helper.buffer, helper.buffer + 64,
689 arg1, arg2, arg3, arg4, arg5);
685690 }
686691 template
687692 hash_code hash_combine(const T1 &arg1, const T2 &arg2, const T3 &arg3,
688 const T4 &arg4) {
693 const T4 &arg4) {
689694 ::llvm::hashing::detail::hash_combine_recursive_helper helper;
690 return helper.combine(arg1, arg2, arg3, arg4);
695 return helper.combine(0, helper.buffer, helper.buffer + 64,
696 arg1, arg2, arg3, arg4);
691697 }
692698 template
693699 hash_code hash_combine(const T1 &arg1, const T2 &arg2, const T3 &arg3) {
694700 ::llvm::hashing::detail::hash_combine_recursive_helper helper;
695 return helper.combine(arg1, arg2, arg3);
701 return helper.combine(0, helper.buffer, helper.buffer + 64, arg1, arg2, arg3);
696702 }
697703 template
698704 hash_code hash_combine(const T1 &arg1, const T2 &arg2) {
699705 ::llvm::hashing::detail::hash_combine_recursive_helper helper;
700 return helper.combine(arg1, arg2);
706 return helper.combine(0, helper.buffer, helper.buffer + 64, arg1, arg2);
701707 }
702708 template
703709 hash_code hash_combine(const T1 &arg1) {
704710 ::llvm::hashing::detail::hash_combine_recursive_helper helper;
705 return helper.combine(arg1);
711 return helper.combine(0, helper.buffer, helper.buffer + 64, arg1);
706712 }
707713
708714 #endif