101e04c3fSmrg/* 201e04c3fSmrg * Copyright © 2018 Advanced Micro Devices, Inc. 301e04c3fSmrg * 401e04c3fSmrg * Permission is hereby granted, free of charge, to any person obtaining a 501e04c3fSmrg * copy of this software and associated documentation files (the "Software"), 601e04c3fSmrg * to deal in the Software without restriction, including without limitation 701e04c3fSmrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 801e04c3fSmrg * and/or sell copies of the Software, and to permit persons to whom the 901e04c3fSmrg * Software is furnished to do so, subject to the following conditions: 1001e04c3fSmrg * 1101e04c3fSmrg * The above copyright notice and this permission notice (including the next 1201e04c3fSmrg * paragraph) shall be included in all copies or substantial portions of the 1301e04c3fSmrg * Software. 1401e04c3fSmrg * 1501e04c3fSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 1601e04c3fSmrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 1701e04c3fSmrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 1801e04c3fSmrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 1901e04c3fSmrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 2001e04c3fSmrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 2101e04c3fSmrg * IN THE SOFTWARE. 2201e04c3fSmrg */ 2301e04c3fSmrg 2401e04c3fSmrg/* Imported from: 2501e04c3fSmrg * https://raw.githubusercontent.com/ridiculousfish/libdivide/master/divide_by_constants_codegen_reference.c 2601e04c3fSmrg * Paper: 2701e04c3fSmrg * http://ridiculousfish.com/files/faster_unsigned_division_by_constants.pdf 2801e04c3fSmrg * 2901e04c3fSmrg * The author, ridiculous_fish, wrote: 3001e04c3fSmrg * 3101e04c3fSmrg * ''Reference implementations of computing and using the "magic number" 3201e04c3fSmrg * approach to dividing by constants, including codegen instructions. 3301e04c3fSmrg * The unsigned division incorporates the "round down" optimization per 3401e04c3fSmrg * ridiculous_fish. 3501e04c3fSmrg * 3601e04c3fSmrg * This is free and unencumbered software. Any copyright is dedicated 3701e04c3fSmrg * to the Public Domain.'' 3801e04c3fSmrg */ 3901e04c3fSmrg 4001e04c3fSmrg#include "fast_idiv_by_const.h" 4101e04c3fSmrg#include "u_math.h" 427ec681f3Smrg#include "util/macros.h" 4301e04c3fSmrg#include <limits.h> 4401e04c3fSmrg#include <assert.h> 4501e04c3fSmrg 4601e04c3fSmrgstruct util_fast_udiv_info 4701e04c3fSmrgutil_compute_fast_udiv_info(uint64_t D, unsigned num_bits, unsigned UINT_BITS) 4801e04c3fSmrg{ 4901e04c3fSmrg /* The numerator must fit in a uint64_t */ 5001e04c3fSmrg assert(num_bits > 0 && num_bits <= UINT_BITS); 5101e04c3fSmrg assert(D != 0); 5201e04c3fSmrg 5301e04c3fSmrg /* The eventual result */ 5401e04c3fSmrg struct util_fast_udiv_info result; 5501e04c3fSmrg 5601e04c3fSmrg if (util_is_power_of_two_or_zero64(D)) { 5701e04c3fSmrg unsigned div_shift = util_logbase2_64(D); 5801e04c3fSmrg 5901e04c3fSmrg if (div_shift) { 6001e04c3fSmrg /* Dividing by a power of two. */ 6101e04c3fSmrg result.multiplier = 1ull << (UINT_BITS - div_shift); 6201e04c3fSmrg result.pre_shift = 0; 6301e04c3fSmrg result.post_shift = 0; 6401e04c3fSmrg result.increment = 0; 6501e04c3fSmrg return result; 6601e04c3fSmrg } else { 6701e04c3fSmrg /* Dividing by 1. */ 6801e04c3fSmrg /* Assuming: floor((num + 1) * (2^32 - 1) / 2^32) = num */ 697ec681f3Smrg result.multiplier = u_uintN_max(UINT_BITS); 7001e04c3fSmrg result.pre_shift = 0; 7101e04c3fSmrg result.post_shift = 0; 7201e04c3fSmrg result.increment = 1; 7301e04c3fSmrg return result; 7401e04c3fSmrg } 7501e04c3fSmrg } 7601e04c3fSmrg 7701e04c3fSmrg /* The extra shift implicit in the difference between UINT_BITS and num_bits 7801e04c3fSmrg */ 7901e04c3fSmrg const unsigned extra_shift = UINT_BITS - num_bits; 8001e04c3fSmrg 8101e04c3fSmrg /* The initial power of 2 is one less than the first one that can possibly 8201e04c3fSmrg * work. 8301e04c3fSmrg */ 8401e04c3fSmrg const uint64_t initial_power_of_2 = (uint64_t)1 << (UINT_BITS-1); 8501e04c3fSmrg 8601e04c3fSmrg /* The remainder and quotient of our power of 2 divided by d */ 8701e04c3fSmrg uint64_t quotient = initial_power_of_2 / D; 8801e04c3fSmrg uint64_t remainder = initial_power_of_2 % D; 8901e04c3fSmrg 9001e04c3fSmrg /* ceil(log_2 D) */ 9101e04c3fSmrg unsigned ceil_log_2_D; 9201e04c3fSmrg 9301e04c3fSmrg /* The magic info for the variant "round down" algorithm */ 9401e04c3fSmrg uint64_t down_multiplier = 0; 9501e04c3fSmrg unsigned down_exponent = 0; 9601e04c3fSmrg int has_magic_down = 0; 9701e04c3fSmrg 9801e04c3fSmrg /* Compute ceil(log_2 D) */ 9901e04c3fSmrg ceil_log_2_D = 0; 10001e04c3fSmrg uint64_t tmp; 10101e04c3fSmrg for (tmp = D; tmp > 0; tmp >>= 1) 10201e04c3fSmrg ceil_log_2_D += 1; 10301e04c3fSmrg 10401e04c3fSmrg 10501e04c3fSmrg /* Begin a loop that increments the exponent, until we find a power of 2 10601e04c3fSmrg * that works. 10701e04c3fSmrg */ 10801e04c3fSmrg unsigned exponent; 10901e04c3fSmrg for (exponent = 0; ; exponent++) { 11001e04c3fSmrg /* Quotient and remainder is from previous exponent; compute it for this 11101e04c3fSmrg * exponent. 11201e04c3fSmrg */ 11301e04c3fSmrg if (remainder >= D - remainder) { 11401e04c3fSmrg /* Doubling remainder will wrap around D */ 11501e04c3fSmrg quotient = quotient * 2 + 1; 11601e04c3fSmrg remainder = remainder * 2 - D; 11701e04c3fSmrg } else { 11801e04c3fSmrg /* Remainder will not wrap */ 11901e04c3fSmrg quotient = quotient * 2; 12001e04c3fSmrg remainder = remainder * 2; 12101e04c3fSmrg } 12201e04c3fSmrg 12301e04c3fSmrg /* We're done if this exponent works for the round_up algorithm. 12401e04c3fSmrg * Note that exponent may be larger than the maximum shift supported, 12501e04c3fSmrg * so the check for >= ceil_log_2_D is critical. 12601e04c3fSmrg */ 12701e04c3fSmrg if ((exponent + extra_shift >= ceil_log_2_D) || 12801e04c3fSmrg (D - remainder) <= ((uint64_t)1 << (exponent + extra_shift))) 12901e04c3fSmrg break; 13001e04c3fSmrg 13101e04c3fSmrg /* Set magic_down if we have not set it yet and this exponent works for 13201e04c3fSmrg * the round_down algorithm 13301e04c3fSmrg */ 13401e04c3fSmrg if (!has_magic_down && 13501e04c3fSmrg remainder <= ((uint64_t)1 << (exponent + extra_shift))) { 13601e04c3fSmrg has_magic_down = 1; 13701e04c3fSmrg down_multiplier = quotient; 13801e04c3fSmrg down_exponent = exponent; 13901e04c3fSmrg } 14001e04c3fSmrg } 14101e04c3fSmrg 14201e04c3fSmrg if (exponent < ceil_log_2_D) { 14301e04c3fSmrg /* magic_up is efficient */ 14401e04c3fSmrg result.multiplier = quotient + 1; 14501e04c3fSmrg result.pre_shift = 0; 14601e04c3fSmrg result.post_shift = exponent; 14701e04c3fSmrg result.increment = 0; 14801e04c3fSmrg } else if (D & 1) { 14901e04c3fSmrg /* Odd divisor, so use magic_down, which must have been set */ 15001e04c3fSmrg assert(has_magic_down); 15101e04c3fSmrg result.multiplier = down_multiplier; 15201e04c3fSmrg result.pre_shift = 0; 15301e04c3fSmrg result.post_shift = down_exponent; 15401e04c3fSmrg result.increment = 1; 15501e04c3fSmrg } else { 15601e04c3fSmrg /* Even divisor, so use a prefix-shifted dividend */ 15701e04c3fSmrg unsigned pre_shift = 0; 15801e04c3fSmrg uint64_t shifted_D = D; 15901e04c3fSmrg while ((shifted_D & 1) == 0) { 16001e04c3fSmrg shifted_D >>= 1; 16101e04c3fSmrg pre_shift += 1; 16201e04c3fSmrg } 16301e04c3fSmrg result = util_compute_fast_udiv_info(shifted_D, num_bits - pre_shift, 16401e04c3fSmrg UINT_BITS); 16501e04c3fSmrg /* expect no increment or pre_shift in this path */ 16601e04c3fSmrg assert(result.increment == 0 && result.pre_shift == 0); 16701e04c3fSmrg result.pre_shift = pre_shift; 16801e04c3fSmrg } 16901e04c3fSmrg return result; 17001e04c3fSmrg} 17101e04c3fSmrg 17201e04c3fSmrgstatic inline int64_t 17301e04c3fSmrgsign_extend(int64_t x, unsigned SINT_BITS) 17401e04c3fSmrg{ 1757ec681f3Smrg return (int64_t)((uint64_t)x << (64 - SINT_BITS)) >> (64 - SINT_BITS); 17601e04c3fSmrg} 17701e04c3fSmrg 17801e04c3fSmrgstruct util_fast_sdiv_info 17901e04c3fSmrgutil_compute_fast_sdiv_info(int64_t D, unsigned SINT_BITS) 18001e04c3fSmrg{ 18101e04c3fSmrg /* D must not be zero. */ 18201e04c3fSmrg assert(D != 0); 18301e04c3fSmrg /* The result is not correct for these divisors. */ 18401e04c3fSmrg assert(D != 1 && D != -1); 18501e04c3fSmrg 18601e04c3fSmrg /* Our result */ 18701e04c3fSmrg struct util_fast_sdiv_info result; 18801e04c3fSmrg 18901e04c3fSmrg /* Absolute value of D (we know D is not the most negative value since 19001e04c3fSmrg * that's a power of 2) 19101e04c3fSmrg */ 19201e04c3fSmrg const uint64_t abs_d = (D < 0 ? -D : D); 19301e04c3fSmrg 19401e04c3fSmrg /* The initial power of 2 is one less than the first one that can possibly 19501e04c3fSmrg * work */ 19601e04c3fSmrg /* "two31" in Warren */ 19701e04c3fSmrg unsigned exponent = SINT_BITS - 1; 19801e04c3fSmrg const uint64_t initial_power_of_2 = (uint64_t)1 << exponent; 19901e04c3fSmrg 20001e04c3fSmrg /* Compute the absolute value of our "test numerator," 20101e04c3fSmrg * which is the largest dividend whose remainder with d is d-1. 20201e04c3fSmrg * This is called anc in Warren. 20301e04c3fSmrg */ 20401e04c3fSmrg const uint64_t tmp = initial_power_of_2 + (D < 0); 20501e04c3fSmrg const uint64_t abs_test_numer = tmp - 1 - tmp % abs_d; 20601e04c3fSmrg 20701e04c3fSmrg /* Initialize our quotients and remainders (q1, r1, q2, r2 in Warren) */ 20801e04c3fSmrg uint64_t quotient1 = initial_power_of_2 / abs_test_numer; 20901e04c3fSmrg uint64_t remainder1 = initial_power_of_2 % abs_test_numer; 21001e04c3fSmrg uint64_t quotient2 = initial_power_of_2 / abs_d; 21101e04c3fSmrg uint64_t remainder2 = initial_power_of_2 % abs_d; 21201e04c3fSmrg uint64_t delta; 21301e04c3fSmrg 21401e04c3fSmrg /* Begin our loop */ 21501e04c3fSmrg do { 21601e04c3fSmrg /* Update the exponent */ 21701e04c3fSmrg exponent++; 21801e04c3fSmrg 21901e04c3fSmrg /* Update quotient1 and remainder1 */ 22001e04c3fSmrg quotient1 *= 2; 22101e04c3fSmrg remainder1 *= 2; 22201e04c3fSmrg if (remainder1 >= abs_test_numer) { 22301e04c3fSmrg quotient1 += 1; 22401e04c3fSmrg remainder1 -= abs_test_numer; 22501e04c3fSmrg } 22601e04c3fSmrg 22701e04c3fSmrg /* Update quotient2 and remainder2 */ 22801e04c3fSmrg quotient2 *= 2; 22901e04c3fSmrg remainder2 *= 2; 23001e04c3fSmrg if (remainder2 >= abs_d) { 23101e04c3fSmrg quotient2 += 1; 23201e04c3fSmrg remainder2 -= abs_d; 23301e04c3fSmrg } 23401e04c3fSmrg 23501e04c3fSmrg /* Keep going as long as (2**exponent) / abs_d <= delta */ 23601e04c3fSmrg delta = abs_d - remainder2; 23701e04c3fSmrg } while (quotient1 < delta || (quotient1 == delta && remainder1 == 0)); 23801e04c3fSmrg 23901e04c3fSmrg result.multiplier = sign_extend(quotient2 + 1, SINT_BITS); 24001e04c3fSmrg if (D < 0) result.multiplier = -result.multiplier; 24101e04c3fSmrg result.shift = exponent - SINT_BITS; 24201e04c3fSmrg return result; 24301e04c3fSmrg} 244