Source file src/cmd/compile/internal/ssacompile/magic.go

     1  // Copyright 2016 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package ssacompile
     6  
     7  // So you want to compute x / c for some constant c?
     8  // Machine division instructions are slow, so we try to
     9  // compute this division with a multiplication + a few
    10  // other cheap instructions instead.
    11  // (We assume here that c != 0, +/- 1, or +/- 2^i.  Those
    12  // cases are easy to handle in different ways).
    13  
    14  // Technique from https://gmplib.org/~tege/divcnst-pldi94.pdf
    15  
    16  // First consider unsigned division.
    17  // Our strategy is to precompute 1/c then do
    18  //   ⎣x / c⎦ = ⎣x * (1/c)⎦.
    19  // 1/c is less than 1, so we can't compute it directly in
    20  // integer arithmetic.  Let's instead compute 2^e/c
    21  // for a value of e TBD (^ = exponentiation).  Then
    22  //   ⎣x / c⎦ = ⎣x * (2^e/c) / 2^e⎦.
    23  // Dividing by 2^e is easy.  2^e/c isn't an integer, unfortunately.
    24  // So we must approximate it.  Let's call its approximation m.
    25  // We'll then compute
    26  //   ⎣x * m / 2^e⎦
    27  // Which we want to be equal to ⎣x / c⎦ for 0 <= x < 2^n-1
    28  // where n is the word size.
    29  // Setting x = c gives us c * m >= 2^e.
    30  // We'll chose m = ⎡2^e/c⎤ to satisfy that equation.
    31  // What remains is to choose e.
    32  // Let m = 2^e/c + delta, 0 <= delta < 1
    33  //   ⎣x * (2^e/c + delta) / 2^e⎦
    34  //   ⎣x / c + x * delta / 2^e⎦
    35  // We must have x * delta / 2^e < 1/c so that this
    36  // additional term never rounds differently than ⎣x / c⎦ does.
    37  // Rearranging,
    38  //   2^e > x * delta * c
    39  // x can be at most 2^n-1 and delta can be at most 1.
    40  // So it is sufficient to have 2^e >= 2^n*c.
    41  // So we'll choose e = n + s, with s = ⎡log2(c)⎤.
    42  //
    43  // An additional complication arises because m has n+1 bits in it.
    44  // Hardware restricts us to n bit by n bit multiplies.
    45  // We divide into 3 cases:
    46  //
    47  // Case 1: m is even.
    48  //   ⎣x / c⎦ = ⎣x * m / 2^(n+s)⎦
    49  //   ⎣x / c⎦ = ⎣x * (m/2) / 2^(n+s-1)⎦
    50  //   ⎣x / c⎦ = ⎣x * (m/2) / 2^n / 2^(s-1)⎦
    51  //   ⎣x / c⎦ = ⎣⎣x * (m/2) / 2^n⎦ / 2^(s-1)⎦
    52  //   multiply + shift
    53  //
    54  // Case 2: c is even.
    55  //   ⎣x / c⎦ = ⎣(x/2) / (c/2)⎦
    56  //   ⎣x / c⎦ = ⎣⎣x/2⎦ / (c/2)⎦
    57  //     This is just the original problem, with x' = ⎣x/2⎦, c' = c/2, n' = n-1.
    58  //       s' = s-1
    59  //       m' = ⎡2^(n'+s')/c'⎤
    60  //          = ⎡2^(n+s-1)/c⎤
    61  //          = ⎡m/2⎤
    62  //   ⎣x / c⎦ = ⎣x' * m' / 2^(n'+s')⎦
    63  //   ⎣x / c⎦ = ⎣⎣x/2⎦ * ⎡m/2⎤ / 2^(n+s-2)⎦
    64  //   ⎣x / c⎦ = ⎣⎣⎣x/2⎦ * ⎡m/2⎤ / 2^n⎦ / 2^(s-2)⎦
    65  //   shift + multiply + shift
    66  //
    67  // Case 3: everything else
    68  //   let k = m - 2^n. k fits in n bits.
    69  //   ⎣x / c⎦ = ⎣x * m / 2^(n+s)⎦
    70  //   ⎣x / c⎦ = ⎣x * (2^n + k) / 2^(n+s)⎦
    71  //   ⎣x / c⎦ = ⎣(x + x * k / 2^n) / 2^s⎦
    72  //   ⎣x / c⎦ = ⎣(x + ⎣x * k / 2^n⎦) / 2^s⎦
    73  //   ⎣x / c⎦ = ⎣(x + ⎣x * k / 2^n⎦) / 2^s⎦
    74  //   ⎣x / c⎦ = ⎣⎣(x + ⎣x * k / 2^n⎦) / 2⎦ / 2^(s-1)⎦
    75  //   multiply + avg + shift
    76  //
    77  // These can be implemented in hardware using:
    78  //  ⎣a * b / 2^n⎦ - aka high n bits of an n-bit by n-bit multiply.
    79  //  ⎣(a+b) / 2⎦   - aka "average" of two n-bit numbers.
    80  //                  (Not just a regular add & shift because the intermediate result
    81  //                   a+b has n+1 bits in it.  Nevertheless, can be done
    82  //                   in 2 instructions on x86.)
    83  
    84  // umagicOK reports whether we should strength reduce a n-bit divide by c.
    85  func umagicOK(n uint, c int64) bool {
    86  	// Convert from ConstX auxint values to the real uint64 constant they represent.
    87  	d := uint64(c) << (64 - n) >> (64 - n)
    88  
    89  	// Doesn't work for 0.
    90  	// Don't use for powers of 2.
    91  	return d&(d-1) != 0
    92  }
    93  

View as plain text