1// asmcheck
2
3// Copyright 2018 The Go Authors. All rights reserved.
4// Use of this source code is governed by a BSD-style
5// license that can be found in the LICENSE file.
6
7package codegen
8
9func cmovint(c int) int {
10	x := c + 4
11	if x < 0 {
12		x = 182
13	}
14	// amd64:"CMOVQLT"
15	// arm64:"CSEL\tLT"
16	// ppc64x:"ISEL\t[$]0"
17	// wasm:"Select"
18	return x
19}
20
21func cmovchan(x, y chan int) chan int {
22	if x != y {
23		x = y
24	}
25	// amd64:"CMOVQNE"
26	// arm64:"CSEL\tNE"
27	// ppc64x:"ISEL\t[$]2"
28	// wasm:"Select"
29	return x
30}
31
32func cmovuintptr(x, y uintptr) uintptr {
33	if x < y {
34		x = -y
35	}
36	// amd64:"CMOVQ(HI|CS)"
37	// arm64:"CSNEG\tLS"
38	// ppc64x:"ISEL\t[$]1"
39	// wasm:"Select"
40	return x
41}
42
43func cmov32bit(x, y uint32) uint32 {
44	if x < y {
45		x = -y
46	}
47	// amd64:"CMOVL(HI|CS)"
48	// arm64:"CSNEG\t(LS|HS)"
49	// ppc64x:"ISEL\t[$]1"
50	// wasm:"Select"
51	return x
52}
53
54func cmov16bit(x, y uint16) uint16 {
55	if x < y {
56		x = -y
57	}
58	// amd64:"CMOVW(HI|CS)"
59	// arm64:"CSNEG\t(LS|HS)"
60	// ppc64x:"ISEL\t[$][01]"
61	// wasm:"Select"
62	return x
63}
64
65// Floating point comparison. For EQ/NE, we must
66// generate special code to handle NaNs.
67func cmovfloateq(x, y float64) int {
68	a := 128
69	if x == y {
70		a = 256
71	}
72	// amd64:"CMOVQNE","CMOVQPC"
73	// arm64:"CSEL\tEQ"
74	// ppc64x:"ISEL\t[$]2"
75	// wasm:"Select"
76	return a
77}
78
79func cmovfloatne(x, y float64) int {
80	a := 128
81	if x != y {
82		a = 256
83	}
84	// amd64:"CMOVQNE","CMOVQPS"
85	// arm64:"CSEL\tNE"
86	// ppc64x:"ISEL\t[$]2"
87	// wasm:"Select"
88	return a
89}
90
91//go:noinline
92func frexp(f float64) (frac float64, exp int) {
93	return 1.0, 4
94}
95
96//go:noinline
97func ldexp(frac float64, exp int) float64 {
98	return 1.0
99}
100
101// Generate a CMOV with a floating comparison and integer move.
102func cmovfloatint2(x, y float64) float64 {
103	yfr, yexp := 4.0, 5
104
105	r := x
106	for r >= y {
107		rfr, rexp := frexp(r)
108		if rfr < yfr {
109			rexp = rexp - 1
110		}
111		// amd64:"CMOVQHI"
112		// arm64:"CSEL\tMI"
113		// ppc64x:"ISEL\t[$]0"
114		// wasm:"Select"
115		r = r - ldexp(y, rexp-yexp)
116	}
117	return r
118}
119
120func cmovloaded(x [4]int, y int) int {
121	if x[2] != 0 {
122		y = x[2]
123	} else {
124		y = y >> 2
125	}
126	// amd64:"CMOVQNE"
127	// arm64:"CSEL\tNE"
128	// ppc64x:"ISEL\t[$]2"
129	// wasm:"Select"
130	return y
131}
132
133func cmovuintptr2(x, y uintptr) uintptr {
134	a := x * 2
135	if a == 0 {
136		a = 256
137	}
138	// amd64:"CMOVQEQ"
139	// arm64:"CSEL\tEQ"
140	// ppc64x:"ISEL\t[$]2"
141	// wasm:"Select"
142	return a
143}
144
145// Floating point CMOVs are not supported by amd64/arm64/ppc64x
146func cmovfloatmove(x, y int) float64 {
147	a := 1.0
148	if x <= y {
149		a = 2.0
150	}
151	// amd64:-"CMOV"
152	// arm64:-"CSEL"
153	// ppc64x:-"ISEL"
154	// wasm:-"Select"
155	return a
156}
157
158// On amd64, the following patterns trigger comparison inversion.
159// Test that we correctly invert the CMOV condition
160var gsink int64
161var gusink uint64
162
163func cmovinvert1(x, y int64) int64 {
164	if x < gsink {
165		y = -y
166	}
167	// amd64:"CMOVQGT"
168	return y
169}
170func cmovinvert2(x, y int64) int64 {
171	if x <= gsink {
172		y = -y
173	}
174	// amd64:"CMOVQGE"
175	return y
176}
177func cmovinvert3(x, y int64) int64 {
178	if x == gsink {
179		y = -y
180	}
181	// amd64:"CMOVQEQ"
182	return y
183}
184func cmovinvert4(x, y int64) int64 {
185	if x != gsink {
186		y = -y
187	}
188	// amd64:"CMOVQNE"
189	return y
190}
191func cmovinvert5(x, y uint64) uint64 {
192	if x > gusink {
193		y = -y
194	}
195	// amd64:"CMOVQCS"
196	return y
197}
198func cmovinvert6(x, y uint64) uint64 {
199	if x >= gusink {
200		y = -y
201	}
202	// amd64:"CMOVQLS"
203	return y
204}
205
206func cmovload(a []int, i int, b bool) int {
207	if b {
208		i++
209	}
210	// See issue 26306
211	// amd64:-"CMOVQNE"
212	return a[i]
213}
214
215func cmovstore(a []int, i int, b bool) {
216	if b {
217		i++
218	}
219	// amd64:"CMOVQNE"
220	a[i] = 7
221}
222
223var r0, r1, r2, r3, r4, r5 int
224
225func cmovinc(cond bool, a, b, c int) {
226	var x0, x1 int
227
228	if cond {
229		x0 = a
230	} else {
231		x0 = b + 1
232	}
233	// arm64:"CSINC\tNE", -"CSEL"
234	r0 = x0
235
236	if cond {
237		x1 = b + 1
238	} else {
239		x1 = a
240	}
241	// arm64:"CSINC\tEQ", -"CSEL"
242	r1 = x1
243
244	if cond {
245		c++
246	}
247	// arm64:"CSINC\tEQ", -"CSEL"
248	r2 = c
249}
250
251func cmovinv(cond bool, a, b int) {
252	var x0, x1 int
253
254	if cond {
255		x0 = a
256	} else {
257		x0 = ^b
258	}
259	// arm64:"CSINV\tNE", -"CSEL"
260	r0 = x0
261
262	if cond {
263		x1 = ^b
264	} else {
265		x1 = a
266	}
267	// arm64:"CSINV\tEQ", -"CSEL"
268	r1 = x1
269}
270
271func cmovneg(cond bool, a, b, c int) {
272	var x0, x1 int
273
274	if cond {
275		x0 = a
276	} else {
277		x0 = -b
278	}
279	// arm64:"CSNEG\tNE", -"CSEL"
280	r0 = x0
281
282	if cond {
283		x1 = -b
284	} else {
285		x1 = a
286	}
287	// arm64:"CSNEG\tEQ", -"CSEL"
288	r1 = x1
289}
290
291func cmovsetm(cond bool, x int) {
292	var x0, x1 int
293
294	if cond {
295		x0 = -1
296	} else {
297		x0 = 0
298	}
299	// arm64:"CSETM\tNE", -"CSEL"
300	r0 = x0
301
302	if cond {
303		x1 = 0
304	} else {
305		x1 = -1
306	}
307	// arm64:"CSETM\tEQ", -"CSEL"
308	r1 = x1
309}
310
311func cmovFcmp0(s, t float64, a, b int) {
312	var x0, x1, x2, x3, x4, x5 int
313
314	if s < t {
315		x0 = a
316	} else {
317		x0 = b + 1
318	}
319	// arm64:"CSINC\tMI", -"CSEL"
320	r0 = x0
321
322	if s <= t {
323		x1 = a
324	} else {
325		x1 = ^b
326	}
327	// arm64:"CSINV\tLS", -"CSEL"
328	r1 = x1
329
330	if s > t {
331		x2 = a
332	} else {
333		x2 = -b
334	}
335	// arm64:"CSNEG\tMI", -"CSEL"
336	r2 = x2
337
338	if s >= t {
339		x3 = -1
340	} else {
341		x3 = 0
342	}
343	// arm64:"CSETM\tLS", -"CSEL"
344	r3 = x3
345
346	if s == t {
347		x4 = a
348	} else {
349		x4 = b + 1
350	}
351	// arm64:"CSINC\tEQ", -"CSEL"
352	r4 = x4
353
354	if s != t {
355		x5 = a
356	} else {
357		x5 = b + 1
358	}
359	// arm64:"CSINC\tNE", -"CSEL"
360	r5 = x5
361}
362
363func cmovFcmp1(s, t float64, a, b int) {
364	var x0, x1, x2, x3, x4, x5 int
365
366	if s < t {
367		x0 = b + 1
368	} else {
369		x0 = a
370	}
371	// arm64:"CSINC\tPL", -"CSEL"
372	r0 = x0
373
374	if s <= t {
375		x1 = ^b
376	} else {
377		x1 = a
378	}
379	// arm64:"CSINV\tHI", -"CSEL"
380	r1 = x1
381
382	if s > t {
383		x2 = -b
384	} else {
385		x2 = a
386	}
387	// arm64:"CSNEG\tPL", -"CSEL"
388	r2 = x2
389
390	if s >= t {
391		x3 = 0
392	} else {
393		x3 = -1
394	}
395	// arm64:"CSETM\tHI", -"CSEL"
396	r3 = x3
397
398	if s == t {
399		x4 = b + 1
400	} else {
401		x4 = a
402	}
403	// arm64:"CSINC\tNE", -"CSEL"
404	r4 = x4
405
406	if s != t {
407		x5 = b + 1
408	} else {
409		x5 = a
410	}
411	// arm64:"CSINC\tEQ", -"CSEL"
412	r5 = x5
413}
414
415func cmovzero1(c bool) int {
416	var x int
417	if c {
418		x = 182
419	}
420	// loong64:"MASKEQZ", -"MASKNEZ"
421	return x
422}
423
424func cmovzero2(c bool) int {
425	var x int
426	if !c {
427		x = 182
428	}
429	// loong64:"MASKNEZ", -"MASKEQZ"
430	return x
431}
432
433// Conditionally selecting between a value or 0 can be done without
434// an extra load of 0 to a register on PPC64 by using R0 (which always
435// holds the value $0) instead. Verify both cases where either arg1
436// or arg2 is zero.
437func cmovzeroreg0(a, b int) int {
438	x := 0
439	if a == b {
440		x = a
441	}
442	// ppc64x:"ISEL\t[$]2, R[0-9]+, R0, R[0-9]+"
443	return x
444}
445
446func cmovzeroreg1(a, b int) int {
447	x := a
448	if a == b {
449		x = 0
450	}
451	// ppc64x:"ISEL\t[$]2, R0, R[0-9]+, R[0-9]+"
452	return x
453}
454