1 // Copyright 2025 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 // Divisibility checks (x%c == 0 or x%c != 0) convert to multiply, rotate, compare.
6 // The opt pass rewrote x%c to x-(x/c)*c
7 // and then also rewrote x-(x/c)*c == 0 to x == (x/c)*c.
8 // If x/c is being used for a division already (div.Uses != 1)
9 // then we leave the expression alone.
10 //
11 // See ../magic.go for a detailed description of these algorithms.
12 // See test/codegen/divmod.go for tests.
13 // See divmod.rules for other division rules that run after these.
14
15 // Divisiblity by unsigned or signed power of two.
16 (Eq(8|16|32|64) x (Mul(8|16|32|64) <t> (Div(8|16|32|64)u x (Const(8|16|32|64) [c])) (Const(8|16|32|64) [c])))
17 && x.Op != OpConst64 && isPowerOfTwo(c) =>
18 (Eq(8|16|32|64) (And(8|16|32|64) <t> x (Const(8|16|32|64) <t> [c-1])) (Const(8|16|32|64) <t> [0]))
19 (Eq(8|16|32|64) x (Mul(8|16|32|64) <t> (Div(8|16|32|64) x (Const(8|16|32|64) [c])) (Const(8|16|32|64) [c])))
20 && x.Op != OpConst64 && isPowerOfTwo(c) =>
21 (Eq(8|16|32|64) (And(8|16|32|64) <t> x (Const(8|16|32|64) <t> [c-1])) (Const(8|16|32|64) <t> [0]))
22 (Neq(8|16|32|64) x (Mul(8|16|32|64) <t> (Div(8|16|32|64)u x (Const(8|16|32|64) [c])) (Const(8|16|32|64) [c])))
23 && x.Op != OpConst64 && isPowerOfTwo(c) =>
24 (Neq(8|16|32|64) (And(8|16|32|64) <t> x (Const(8|16|32|64) <t> [c-1])) (Const(8|16|32|64) <t> [0]))
25 (Neq(8|16|32|64) x (Mul(8|16|32|64) <t> (Div(8|16|32|64) x (Const(8|16|32|64) [c])) (Const(8|16|32|64) [c])))
26 && x.Op != OpConst64 && isPowerOfTwo(c) =>
27 (Neq(8|16|32|64) (And(8|16|32|64) <t> x (Const(8|16|32|64) <t> [c-1])) (Const(8|16|32|64) <t> [0]))
28
29 // Divisiblity by unsigned.
30 (Eq8 x (Mul8 <t> div:(Div8u x (Const8 [c])) (Const8 [c])))
31 && div.Uses == 1
32 && x.Op != OpConst8 && udivisibleOK8(c) =>
33 (Leq8U
34 (RotateLeft8 <t>
35 (Mul8 <t> x (Const8 <t> [int8(udivisible8(c).m)]))
36 (Const8 <t> [int8(8 - udivisible8(c).k)]))
37 (Const8 <t> [int8(udivisible8(c).max)]))
38 (Neq8 x (Mul8 <t> div:(Div8u x (Const8 [c])) (Const8 [c])))
39 && div.Uses == 1
40 && x.Op != OpConst8 && udivisibleOK8(c) =>
41 (Less8U
42 (Const8 <t> [int8(udivisible8(c).max)])
43 (RotateLeft8 <t>
44 (Mul8 <t> x (Const8 <t> [int8(udivisible8(c).m)]))
45 (Const8 <t> [int8(8 - udivisible8(c).k)])))
46 (Eq16 x (Mul16 <t> div:(Div16u x (Const16 [c])) (Const16 [c])))
47 && div.Uses == 1
48 && x.Op != OpConst16 && udivisibleOK16(c) =>
49 (Leq16U
50 (RotateLeft16 <t>
51 (Mul16 <t> x (Const16 <t> [int16(udivisible16(c).m)]))
52 (Const16 <t> [int16(16 - udivisible16(c).k)]))
53 (Const16 <t> [int16(udivisible16(c).max)]))
54 (Neq16 x (Mul16 <t> div:(Div16u x (Const16 [c])) (Const16 [c])))
55 && div.Uses == 1
56 && x.Op != OpConst16 && udivisibleOK16(c) =>
57 (Less16U
58 (Const16 <t> [int16(udivisible16(c).max)])
59 (RotateLeft16 <t>
60 (Mul16 <t> x (Const16 <t> [int16(udivisible16(c).m)]))
61 (Const16 <t> [int16(16 - udivisible16(c).k)])))
62 (Eq32 x (Mul32 <t> div:(Div32u x (Const32 [c])) (Const32 [c])))
63 && div.Uses == 1
64 && x.Op != OpConst32 && udivisibleOK32(c) =>
65 (Leq32U
66 (RotateLeft32 <t>
67 (Mul32 <t> x (Const32 <t> [int32(udivisible32(c).m)]))
68 (Const32 <t> [int32(32 - udivisible32(c).k)]))
69 (Const32 <t> [int32(udivisible32(c).max)]))
70 (Neq32 x (Mul32 <t> div:(Div32u x (Const32 [c])) (Const32 [c])))
71 && div.Uses == 1
72 && x.Op != OpConst32 && udivisibleOK32(c) =>
73 (Less32U
74 (Const32 <t> [int32(udivisible32(c).max)])
75 (RotateLeft32 <t>
76 (Mul32 <t> x (Const32 <t> [int32(udivisible32(c).m)]))
77 (Const32 <t> [int32(32 - udivisible32(c).k)])))
78 (Eq64 x (Mul64 <t> div:(Div64u x (Const64 [c])) (Const64 [c])))
79 && div.Uses == 1
80 && x.Op != OpConst64 && udivisibleOK64(c) =>
81 (Leq64U
82 (RotateLeft64 <t>
83 (Mul64 <t> x (Const64 <t> [int64(udivisible64(c).m)]))
84 (Const64 <t> [int64(64 - udivisible64(c).k)]))
85 (Const64 <t> [int64(udivisible64(c).max)]))
86 (Neq64 x (Mul64 <t> div:(Div64u x (Const64 [c])) (Const64 [c])))
87 && div.Uses == 1
88 && x.Op != OpConst64 && udivisibleOK64(c) =>
89 (Less64U
90 (Const64 <t> [int64(udivisible64(c).max)])
91 (RotateLeft64 <t>
92 (Mul64 <t> x (Const64 <t> [int64(udivisible64(c).m)]))
93 (Const64 <t> [int64(64 - udivisible64(c).k)])))
94
95 // Divisiblity by signed.
96 (Eq8 x (Mul8 <t> div:(Div8 x (Const8 [c])) (Const8 [c])))
97 && div.Uses == 1
98 && x.Op != OpConst8 && sdivisibleOK8(c) =>
99 (Leq8U
100 (RotateLeft8 <t>
101 (Add8 <t> (Mul8 <t> x (Const8 <t> [int8(sdivisible8(c).m)]))
102 (Const8 <t> [int8(sdivisible8(c).a)]))
103 (Const8 <t> [int8(8 - sdivisible8(c).k)]))
104 (Const8 <t> [int8(sdivisible8(c).max)]))
105 (Neq8 x (Mul8 <t> div:(Div8 x (Const8 [c])) (Const8 [c])))
106 && div.Uses == 1
107 && x.Op != OpConst8 && sdivisibleOK8(c) =>
108 (Less8U
109 (Const8 <t> [int8(sdivisible8(c).max)])
110 (RotateLeft8 <t>
111 (Add8 <t> (Mul8 <t> x (Const8 <t> [int8(sdivisible8(c).m)]))
112 (Const8 <t> [int8(sdivisible8(c).a)]))
113 (Const8 <t> [int8(8 - sdivisible8(c).k)])))
114 (Eq16 x (Mul16 <t> div:(Div16 x (Const16 [c])) (Const16 [c])))
115 && div.Uses == 1
116 && x.Op != OpConst16 && sdivisibleOK16(c) =>
117 (Leq16U
118 (RotateLeft16 <t>
119 (Add16 <t> (Mul16 <t> x (Const16 <t> [int16(sdivisible16(c).m)]))
120 (Const16 <t> [int16(sdivisible16(c).a)]))
121 (Const16 <t> [int16(16 - sdivisible16(c).k)]))
122 (Const16 <t> [int16(sdivisible16(c).max)]))
123 (Neq16 x (Mul16 <t> div:(Div16 x (Const16 [c])) (Const16 [c])))
124 && div.Uses == 1
125 && x.Op != OpConst16 && sdivisibleOK16(c) =>
126 (Less16U
127 (Const16 <t> [int16(sdivisible16(c).max)])
128 (RotateLeft16 <t>
129 (Add16 <t> (Mul16 <t> x (Const16 <t> [int16(sdivisible16(c).m)]))
130 (Const16 <t> [int16(sdivisible16(c).a)]))
131 (Const16 <t> [int16(16 - sdivisible16(c).k)])))
132 (Eq32 x (Mul32 <t> div:(Div32 x (Const32 [c])) (Const32 [c])))
133 && div.Uses == 1
134 && x.Op != OpConst32 && sdivisibleOK32(c) =>
135 (Leq32U
136 (RotateLeft32 <t>
137 (Add32 <t> (Mul32 <t> x (Const32 <t> [int32(sdivisible32(c).m)]))
138 (Const32 <t> [int32(sdivisible32(c).a)]))
139 (Const32 <t> [int32(32 - sdivisible32(c).k)]))
140 (Const32 <t> [int32(sdivisible32(c).max)]))
141 (Neq32 x (Mul32 <t> div:(Div32 x (Const32 [c])) (Const32 [c])))
142 && div.Uses == 1
143 && x.Op != OpConst32 && sdivisibleOK32(c) =>
144 (Less32U
145 (Const32 <t> [int32(sdivisible32(c).max)])
146 (RotateLeft32 <t>
147 (Add32 <t> (Mul32 <t> x (Const32 <t> [int32(sdivisible32(c).m)]))
148 (Const32 <t> [int32(sdivisible32(c).a)]))
149 (Const32 <t> [int32(32 - sdivisible32(c).k)])))
150 (Eq64 x (Mul64 <t> div:(Div64 x (Const64 [c])) (Const64 [c])))
151 && div.Uses == 1
152 && x.Op != OpConst64 && sdivisibleOK64(c) =>
153 (Leq64U
154 (RotateLeft64 <t>
155 (Add64 <t> (Mul64 <t> x (Const64 <t> [int64(sdivisible64(c).m)]))
156 (Const64 <t> [int64(sdivisible64(c).a)]))
157 (Const64 <t> [int64(64 - sdivisible64(c).k)]))
158 (Const64 <t> [int64(sdivisible64(c).max)]))
159 (Neq64 x (Mul64 <t> div:(Div64 x (Const64 [c])) (Const64 [c])))
160 && div.Uses == 1
161 && x.Op != OpConst64 && sdivisibleOK64(c) =>
162 (Less64U
163 (Const64 <t> [int64(sdivisible64(c).max)])
164 (RotateLeft64 <t>
165 (Add64 <t> (Mul64 <t> x (Const64 <t> [int64(sdivisible64(c).m)]))
166 (Const64 <t> [int64(sdivisible64(c).a)]))
167 (Const64 <t> [int64(64 - sdivisible64(c).k)])))
168
View as plain text