1
2
3
4
5 package ssacompile
6
7 import (
8 "cmd/compile/internal/ssa"
9 "cmd/compile/internal/ssa/block"
10 "cmd/compile/internal/ssa/ssaop"
11 )
12
13
14
15
16 func fuseIntInRange(b *ssa.Block) bool {
17 return fuseComparisons(b, canOptIntInRange)
18 }
19
20
21
22
23
24 func fuseNanCheck(b *ssa.Block) bool {
25 return fuseComparisons(b, canOptNanCheck)
26 }
27
28
29
30
31
32 func fuseSingleBitDifference(b *ssa.Block) bool {
33 return fuseComparisons(b, canOptSingleBitDifference)
34 }
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63 func fuseComparisons(b *ssa.Block, canOptControls func(a, b *ssa.Value, op ssaop.Op) bool) bool {
64 if len(b.Preds) != 1 {
65 return false
66 }
67 p := b.Preds[0].Block()
68 if b.Kind != block.BlockIf || p.Kind != block.BlockIf {
69 return false
70 }
71
72
73 if p.Likely == ssa.BranchLikely && p.Succs[0].Block() != b {
74 return false
75 }
76 if p.Likely == ssa.BranchUnlikely && p.Succs[1].Block() != b {
77 return false
78 }
79
80
81
82 for i, op := range [2]ssaop.Op{ssaop.OpOrB, ssaop.OpAndB} {
83 if p.Succs[i].Block() != b.Succs[i].Block() {
84 continue
85 }
86
87
88 bc := b.Controls[0]
89 pc := p.Controls[0]
90 if !canOptControls(bc, pc, op) {
91 return false
92 }
93
94
95
96
97
98
99
100 if !canSpeculativelyExecute(b) {
101 return false
102 }
103
104
105
106
107 if hasDifferentiatedPhi(p.Succs[i], b.Succs[i]) {
108 continue
109 }
110
111
112 v := b.NewValue0(bc.Pos, op, bc.Type)
113 v.AddArg(pc)
114 v.AddArg(bc)
115
116
117 b.SetControl(v)
118
119
120 p.RemoveEdge(i)
121 p.Kind = block.BlockPlain
122 p.Likely = ssa.BranchUnknown
123 p.ResetControls()
124
125 return true
126 }
127
128
129 return false
130 }
131
132 func hasDifferentiatedPhi(x ssa.Edge, y ssa.Edge) bool {
133 b := x.Block()
134 if y.Block() != b {
135 panic("non matching edges")
136 }
137 xi := x.I
138 yi := y.I
139 for _, v := range b.Values {
140 if v.Op != ssaop.OpPhi {
141 continue
142 }
143 if v.Args[xi] != v.Args[yi] {
144 return true
145 }
146 }
147 return false
148 }
149
150
151
152 func getConstIntArgIndex(v *ssa.Value) int {
153 for i, a := range v.Args {
154 switch a.Op {
155 case ssaop.OpConst8, ssaop.OpConst16, ssaop.OpConst32, ssaop.OpConst64:
156 return i
157 }
158 }
159 return -1
160 }
161
162
163
164 func isSignedInequality(v *ssa.Value) bool {
165 switch v.Op {
166 case ssaop.OpLess64, ssaop.OpLess32, ssaop.OpLess16, ssaop.OpLess8,
167 ssaop.OpLeq64, ssaop.OpLeq32, ssaop.OpLeq16, ssaop.OpLeq8:
168 return true
169 }
170 return false
171 }
172
173
174
175
176 func isUnsignedInequality(v *ssa.Value) bool {
177 switch v.Op {
178 case ssaop.OpLess64U, ssaop.OpLess32U, ssaop.OpLess16U, ssaop.OpLess8U,
179 ssaop.OpLeq64U, ssaop.OpLeq32U, ssaop.OpLeq16U, ssaop.OpLeq8U:
180 return true
181 case ssaop.OpNeq64, ssaop.OpNeq32, ssaop.OpNeq16, ssaop.OpNeq8:
182
183
184 return ssa.IsConstZero(v.Args[0]) || ssa.IsConstZero(v.Args[1])
185 }
186 return false
187 }
188
189 func canOptIntInRange(x, y *ssa.Value, op ssaop.Op) bool {
190
191
192
193
194 inequalityChecks := [...]func(*ssa.Value) bool{
195 isSignedInequality,
196 isUnsignedInequality,
197 }
198 for _, f := range inequalityChecks {
199 if !f(x) || !f(y) {
200 continue
201 }
202
203
204 xi := getConstIntArgIndex(x)
205 if xi < 0 {
206 return false
207 }
208 yi := getConstIntArgIndex(y)
209 if yi < 0 {
210 return false
211 }
212
213
214
215 return x.Args[xi^1] == y.Args[yi^1]
216 }
217 return false
218 }
219
220
221
222
223
224
225
226
227
228
229 func canOptNanCheck(x, y *ssa.Value, op ssaop.Op) bool {
230 if op != ssaop.OpOrB {
231 return false
232 }
233
234 for i := 0; i <= 1; i, x, y = i+1, y, x {
235 if len(x.Args) != 2 || x.Args[0] != x.Args[1] {
236 continue
237 }
238 v := x.Args[0]
239 switch x.Op {
240 case ssaop.OpNeq64F:
241 if y.Op != ssaop.OpLess64F && y.Op != ssaop.OpLeq64F {
242 return false
243 }
244 for j := 0; j <= 1; j++ {
245 a, b := y.Args[j], y.Args[j^1]
246 if a.Op != ssaop.OpConst64F {
247 continue
248 }
249
250
251 if (b.Op == ssaop.OpAbs || b.Op == ssaop.OpNeg64F) && b.Args[0] == v {
252 return true
253 }
254 return b == v
255 }
256 case ssaop.OpNeq32F:
257 if y.Op != ssaop.OpLess32F && y.Op != ssaop.OpLeq32F {
258 return false
259 }
260 for j := 0; j <= 1; j++ {
261 a, b := y.Args[j], y.Args[j^1]
262 if a.Op != ssaop.OpConst32F {
263 continue
264 }
265
266
267 if b.Op == ssaop.OpNeg32F && b.Args[0] == v {
268 return true
269 }
270 return b == v
271 }
272 }
273 }
274 return false
275 }
276
277
278
279
280
281
282
283 func canOptSingleBitDifference(x, y *ssa.Value, op ssaop.Op) bool {
284 if x.Op != y.Op {
285 return false
286 }
287 switch x.Op {
288 case ssaop.OpEq64, ssaop.OpEq32, ssaop.OpEq16, ssaop.OpEq8:
289 if op != ssaop.OpOrB {
290 return false
291 }
292 case ssaop.OpNeq64, ssaop.OpNeq32, ssaop.OpNeq16, ssaop.OpNeq8:
293 if op != ssaop.OpAndB {
294 return false
295 }
296 default:
297 return false
298 }
299
300 xi := getConstIntArgIndex(x)
301 if xi < 0 {
302 return false
303 }
304 yi := getConstIntArgIndex(y)
305 if yi < 0 {
306 return false
307 }
308 if x.Args[xi^1] != y.Args[yi^1] {
309 return false
310 }
311 return ssa.OneBit(x.Args[xi].AuxInt ^ y.Args[yi].AuxInt)
312 }
313
View as plain text