Merge remote-tracking branches 'asoc/topic/ac97', 'asoc/topic/ac97-mfd', 'asoc/topic...
[sfrench/cifs-2.6.git] / include / linux / reciprocal_div.h
1 /* SPDX-License-Identifier: GPL-2.0 */
2 #ifndef _LINUX_RECIPROCAL_DIV_H
3 #define _LINUX_RECIPROCAL_DIV_H
4
5 #include <linux/types.h>
6
7 /*
8  * This algorithm is based on the paper "Division by Invariant
9  * Integers Using Multiplication" by Torbjörn Granlund and Peter
10  * L. Montgomery.
11  *
12  * The assembler implementation from Agner Fog, which this code is
13  * based on, can be found here:
14  * http://www.agner.org/optimize/asmlib.zip
15  *
16  * This optimization for A/B is helpful if the divisor B is mostly
17  * runtime invariant. The reciprocal of B is calculated in the
18  * slow-path with reciprocal_value(). The fast-path can then just use
19  * a much faster multiplication operation with a variable dividend A
20  * to calculate the division A/B.
21  */
22
23 struct reciprocal_value {
24         u32 m;
25         u8 sh1, sh2;
26 };
27
28 struct reciprocal_value reciprocal_value(u32 d);
29
30 static inline u32 reciprocal_divide(u32 a, struct reciprocal_value R)
31 {
32         u32 t = (u32)(((u64)a * R.m) >> 32);
33         return (t + ((a - t) >> R.sh1)) >> R.sh2;
34 }
35
36 #endif /* _LINUX_RECIPROCAL_DIV_H */