| 710 | /////////// UINT64 |
| 711 | |
| 712 | static inline struct libdivide_u64_t libdivide_internal_u64_gen(uint64_t d, int branchfree) { |
| 713 | if (d == 0) { |
| 714 | LIBDIVIDE_ERROR("divider must be != 0"); |
| 715 | } |
| 716 | |
| 717 | struct libdivide_u64_t result; |
| 718 | uint32_t floor_log_2_d = 63 - libdivide_count_leading_zeros64(d); |
| 719 | |
| 720 | // Power of 2 |
| 721 | if ((d & (d - 1)) == 0) { |
| 722 | // We need to subtract 1 from the shift value in case of an unsigned |
| 723 | // branchfree divider because there is a hardcoded right shift by 1 |
| 724 | // in its division algorithm. Because of this we also need to add back |
| 725 | // 1 in its recovery algorithm. |
| 726 | result.magic = 0; |
| 727 | result.more = (uint8_t)(floor_log_2_d - (branchfree != 0)); |
| 728 | } else { |
| 729 | uint64_t proposed_m, rem; |
| 730 | uint8_t more; |
| 731 | // (1 << (64 + floor_log_2_d)) / d |
| 732 | proposed_m = libdivide_128_div_64_to_64(1ULL << floor_log_2_d, 0, d, &rem); |
| 733 | |
| 734 | LIBDIVIDE_ASSERT(rem > 0 && rem < d); |
| 735 | const uint64_t e = d - rem; |
| 736 | |
| 737 | // This power works if e < 2**floor_log_2_d. |
| 738 | if (!branchfree && e < (1ULL << floor_log_2_d)) { |
| 739 | // This power works |
| 740 | more = floor_log_2_d; |
| 741 | } else { |
| 742 | // We have to use the general 65-bit algorithm. We need to compute |
| 743 | // (2**power) / d. However, we already have (2**(power-1))/d and |
| 744 | // its remainder. By doubling both, and then correcting the |
| 745 | // remainder, we can compute the larger division. |
| 746 | // don't care about overflow here - in fact, we expect it |
| 747 | proposed_m += proposed_m; |
| 748 | const uint64_t twice_rem = rem + rem; |
| 749 | if (twice_rem >= d || twice_rem < rem) proposed_m += 1; |
| 750 | more = floor_log_2_d | LIBDIVIDE_ADD_MARKER; |
| 751 | } |
| 752 | result.magic = 1 + proposed_m; |
| 753 | result.more = more; |
| 754 | // result.more's shift should in general be ceil_log_2_d. But if we |
| 755 | // used the smaller power, we subtract one from the shift because we're |
| 756 | // using the smaller power. If we're using the larger power, we |
| 757 | // subtract one from the shift because it's taken care of by the add |
| 758 | // indicator. So floor_log_2_d happens to be correct in both cases, |
| 759 | // which is why we do it outside of the if statement. |
| 760 | } |
| 761 | return result; |
| 762 | } |
| 763 | |
| 764 | struct libdivide_u64_t libdivide_u64_gen(uint64_t d) { |
| 765 | return libdivide_internal_u64_gen(d, 0); |
no test coverage detected