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
9// This file contains codegen tests related to arithmetic
10// simplifications and optimizations on integer types.
11// For codegen tests on float types, see floats.go.
12
13// ----------------- //
14//    Addition       //
15// ----------------- //
16
17func AddLargeConst(a uint64, out []uint64) {
18	// ppc64x/power10:"ADD\t[$]4294967296,"
19	// ppc64x/power9:"MOVD\t[$]1", "SLD\t[$]32" "ADD\tR[0-9]*"
20	// ppc64x/power8:"MOVD\t[$]1", "SLD\t[$]32" "ADD\tR[0-9]*"
21	out[0] = a + 0x100000000
22	// ppc64x/power10:"ADD\t[$]-8589934592,"
23	// ppc64x/power9:"MOVD\t[$]-1", "SLD\t[$]33" "ADD\tR[0-9]*"
24	// ppc64x/power8:"MOVD\t[$]-1", "SLD\t[$]33" "ADD\tR[0-9]*"
25	out[1] = a + 0xFFFFFFFE00000000
26	// ppc64x/power10:"ADD\t[$]1234567,"
27	// ppc64x/power9:"ADDIS\t[$]19,", "ADD\t[$]-10617,"
28	// ppc64x/power8:"ADDIS\t[$]19,", "ADD\t[$]-10617,"
29	out[2] = a + 1234567
30	// ppc64x/power10:"ADD\t[$]-1234567,"
31	// ppc64x/power9:"ADDIS\t[$]-19,", "ADD\t[$]10617,"
32	// ppc64x/power8:"ADDIS\t[$]-19,", "ADD\t[$]10617,"
33	out[3] = a - 1234567
34	// ppc64x/power10:"ADD\t[$]2147450879,"
35	// ppc64x/power9:"ADDIS\t[$]32767,", "ADD\t[$]32767,"
36	// ppc64x/power8:"ADDIS\t[$]32767,", "ADD\t[$]32767,"
37	out[4] = a + 0x7FFF7FFF
38	// ppc64x/power10:"ADD\t[$]-2147483647,"
39	// ppc64x/power9:"ADDIS\t[$]-32768,", "ADD\t[$]1,"
40	// ppc64x/power8:"ADDIS\t[$]-32768,", "ADD\t[$]1,"
41	out[5] = a - 2147483647
42	// ppc64x:"ADDIS\t[$]-32768,", ^"ADD\t"
43	out[6] = a - 2147483648
44	// ppc64x:"ADD\t[$]2147450880,", ^"ADDIS\t"
45	out[7] = a + 0x7FFF8000
46	// ppc64x:"ADD\t[$]-32768,", ^"ADDIS\t"
47	out[8] = a - 32768
48	// ppc64x/power10:"ADD\t[$]-32769,"
49	// ppc64x/power9:"ADDIS\t[$]-1,", "ADD\t[$]32767,"
50	// ppc64x/power8:"ADDIS\t[$]-1,", "ADD\t[$]32767,"
51	out[9] = a - 32769
52}
53
54// ----------------- //
55//    Subtraction    //
56// ----------------- //
57
58var ef int
59
60func SubMem(arr []int, b, c, d int) int {
61	// 386:`SUBL\s[A-Z]+,\s8\([A-Z]+\)`
62	// amd64:`SUBQ\s[A-Z]+,\s16\([A-Z]+\)`
63	arr[2] -= b
64	// 386:`SUBL\s[A-Z]+,\s12\([A-Z]+\)`
65	// amd64:`SUBQ\s[A-Z]+,\s24\([A-Z]+\)`
66	arr[3] -= b
67	// 386:`DECL\s16\([A-Z]+\)`
68	arr[4]--
69	// 386:`ADDL\s[$]-20,\s20\([A-Z]+\)`
70	arr[5] -= 20
71	// 386:`SUBL\s\([A-Z]+\)\([A-Z]+\*4\),\s[A-Z]+`
72	ef -= arr[b]
73	// 386:`SUBL\s[A-Z]+,\s\([A-Z]+\)\([A-Z]+\*4\)`
74	arr[c] -= b
75	// 386:`ADDL\s[$]-15,\s\([A-Z]+\)\([A-Z]+\*4\)`
76	arr[d] -= 15
77	// 386:`DECL\s\([A-Z]+\)\([A-Z]+\*4\)`
78	arr[b]--
79	// amd64:`DECQ\s64\([A-Z]+\)`
80	arr[8]--
81	// 386:"SUBL\t4"
82	// amd64:"SUBQ\t8"
83	return arr[0] - arr[1]
84}
85
86func SubFromConst(a int) int {
87	// ppc64x: `SUBC\tR[0-9]+,\s[$]40,\sR`
88	b := 40 - a
89	return b
90}
91
92func SubFromConstNeg(a int) int {
93	// ppc64x: `ADD\t[$]40,\sR[0-9]+,\sR`
94	c := 40 - (-a)
95	return c
96}
97
98func SubSubFromConst(a int) int {
99	// ppc64x: `ADD\t[$]20,\sR[0-9]+,\sR`
100	c := 40 - (20 - a)
101	return c
102}
103
104func AddSubFromConst(a int) int {
105	// ppc64x: `SUBC\tR[0-9]+,\s[$]60,\sR`
106	c := 40 + (20 - a)
107	return c
108}
109
110func NegSubFromConst(a int) int {
111	// ppc64x: `ADD\t[$]-20,\sR[0-9]+,\sR`
112	c := -(20 - a)
113	return c
114}
115
116func NegAddFromConstNeg(a int) int {
117	// ppc64x: `SUBC\tR[0-9]+,\s[$]40,\sR`
118	c := -(-40 + a)
119	return c
120}
121
122func SubSubNegSimplify(a, b int) int {
123	// amd64:"NEGQ"
124	// ppc64x:"NEG"
125	r := (a - b) - a
126	return r
127}
128
129func SubAddSimplify(a, b int) int {
130	// amd64:-"SUBQ",-"ADDQ"
131	// ppc64x:-"SUB",-"ADD"
132	r := a + (b - a)
133	return r
134}
135
136func SubAddSimplify2(a, b, c int) (int, int, int, int, int, int) {
137	// amd64:-"ADDQ"
138	r := (a + b) - (a + c)
139	// amd64:-"ADDQ"
140	r1 := (a + b) - (c + a)
141	// amd64:-"ADDQ"
142	r2 := (b + a) - (a + c)
143	// amd64:-"ADDQ"
144	r3 := (b + a) - (c + a)
145	// amd64:-"SUBQ"
146	r4 := (a - c) + (c + b)
147	// amd64:-"SUBQ"
148	r5 := (a - c) + (b + c)
149	return r, r1, r2, r3, r4, r5
150}
151
152func SubAddNegSimplify(a, b int) int {
153	// amd64:"NEGQ",-"ADDQ",-"SUBQ"
154	// ppc64x:"NEG",-"ADD",-"SUB"
155	r := a - (b + a)
156	return r
157}
158
159func AddAddSubSimplify(a, b, c int) int {
160	// amd64:-"SUBQ"
161	// ppc64x:-"SUB"
162	r := a + (b + (c - a))
163	return r
164}
165
166// -------------------- //
167//    Multiplication    //
168// -------------------- //
169
170func Pow2Muls(n1, n2 int) (int, int) {
171	// amd64:"SHLQ\t[$]5",-"IMULQ"
172	// 386:"SHLL\t[$]5",-"IMULL"
173	// arm:"SLL\t[$]5",-"MUL"
174	// arm64:"LSL\t[$]5",-"MUL"
175	// ppc64x:"SLD\t[$]5",-"MUL"
176	a := n1 * 32
177
178	// amd64:"SHLQ\t[$]6",-"IMULQ"
179	// 386:"SHLL\t[$]6",-"IMULL"
180	// arm:"SLL\t[$]6",-"MUL"
181	// arm64:`NEG\sR[0-9]+<<6,\sR[0-9]+`,-`LSL`,-`MUL`
182	// ppc64x:"SLD\t[$]6","NEG\\sR[0-9]+,\\sR[0-9]+",-"MUL"
183	b := -64 * n2
184
185	return a, b
186}
187
188func Mul_96(n int) int {
189	// amd64:`SHLQ\t[$]5`,`LEAQ\t\(.*\)\(.*\*2\),`,-`IMULQ`
190	// 386:`SHLL\t[$]5`,`LEAL\t\(.*\)\(.*\*2\),`,-`IMULL`
191	// arm64:`LSL\t[$]5`,`ADD\sR[0-9]+<<1,\sR[0-9]+`,-`MUL`
192	// arm:`SLL\t[$]5`,`ADD\sR[0-9]+<<1,\sR[0-9]+`,-`MUL`
193	// s390x:`SLD\t[$]5`,`SLD\t[$]6`,-`MULLD`
194	return n * 96
195}
196
197func Mul_n120(n int) int {
198	// s390x:`SLD\t[$]3`,`SLD\t[$]7`,-`MULLD`
199	return n * -120
200}
201
202func MulMemSrc(a []uint32, b []float32) {
203	// 386:`IMULL\s4\([A-Z]+\),\s[A-Z]+`
204	a[0] *= a[1]
205	// 386/sse2:`MULSS\s4\([A-Z]+\),\sX[0-9]+`
206	// amd64:`MULSS\s4\([A-Z]+\),\sX[0-9]+`
207	b[0] *= b[1]
208}
209
210// Multiplications merging tests
211
212func MergeMuls1(n int) int {
213	// amd64:"IMUL3Q\t[$]46"
214	// 386:"IMUL3L\t[$]46"
215	// ppc64x:"MULLD\t[$]46"
216	return 15*n + 31*n // 46n
217}
218
219func MergeMuls2(n int) int {
220	// amd64:"IMUL3Q\t[$]23","(ADDQ\t[$]29)|(LEAQ\t29)"
221	// 386:"IMUL3L\t[$]23","ADDL\t[$]29"
222	// ppc64x/power9:"MADDLD",-"MULLD\t[$]23",-"ADD\t[$]29"
223	// ppc64x/power8:"MULLD\t[$]23","ADD\t[$]29"
224	return 5*n + 7*(n+1) + 11*(n+2) // 23n + 29
225}
226
227func MergeMuls3(a, n int) int {
228	// amd64:"ADDQ\t[$]19",-"IMULQ\t[$]19"
229	// 386:"ADDL\t[$]19",-"IMULL\t[$]19"
230	// ppc64x:"ADD\t[$]19",-"MULLD\t[$]19"
231	return a*n + 19*n // (a+19)n
232}
233
234func MergeMuls4(n int) int {
235	// amd64:"IMUL3Q\t[$]14"
236	// 386:"IMUL3L\t[$]14"
237	// ppc64x:"MULLD\t[$]14"
238	return 23*n - 9*n // 14n
239}
240
241func MergeMuls5(a, n int) int {
242	// amd64:"ADDQ\t[$]-19",-"IMULQ\t[$]19"
243	// 386:"ADDL\t[$]-19",-"IMULL\t[$]19"
244	// ppc64x:"ADD\t[$]-19",-"MULLD\t[$]19"
245	return a*n - 19*n // (a-19)n
246}
247
248// -------------- //
249//    Division    //
250// -------------- //
251
252func DivMemSrc(a []float64) {
253	// 386/sse2:`DIVSD\s8\([A-Z]+\),\sX[0-9]+`
254	// amd64:`DIVSD\s8\([A-Z]+\),\sX[0-9]+`
255	a[0] /= a[1]
256}
257
258func Pow2Divs(n1 uint, n2 int) (uint, int) {
259	// 386:"SHRL\t[$]5",-"DIVL"
260	// amd64:"SHRQ\t[$]5",-"DIVQ"
261	// arm:"SRL\t[$]5",-".*udiv"
262	// arm64:"LSR\t[$]5",-"UDIV"
263	// ppc64x:"SRD"
264	a := n1 / 32 // unsigned
265
266	// amd64:"SARQ\t[$]6",-"IDIVQ"
267	// 386:"SARL\t[$]6",-"IDIVL"
268	// arm:"SRA\t[$]6",-".*udiv"
269	// arm64:"ASR\t[$]6",-"SDIV"
270	// ppc64x:"SRAD"
271	b := n2 / 64 // signed
272
273	return a, b
274}
275
276// Check that constant divisions get turned into MULs
277func ConstDivs(n1 uint, n2 int) (uint, int) {
278	// amd64:"MOVQ\t[$]-1085102592571150095","MULQ",-"DIVQ"
279	// 386:"MOVL\t[$]-252645135","MULL",-"DIVL"
280	// arm64:`MOVD`,`UMULH`,-`DIV`
281	// arm:`MOVW`,`MUL`,-`.*udiv`
282	a := n1 / 17 // unsigned
283
284	// amd64:"MOVQ\t[$]-1085102592571150095","IMULQ",-"IDIVQ"
285	// 386:"MOVL\t[$]-252645135","IMULL",-"IDIVL"
286	// arm64:`SMULH`,-`DIV`
287	// arm:`MOVW`,`MUL`,-`.*udiv`
288	b := n2 / 17 // signed
289
290	return a, b
291}
292
293func FloatDivs(a []float32) float32 {
294	// amd64:`DIVSS\s8\([A-Z]+\),\sX[0-9]+`
295	// 386/sse2:`DIVSS\s8\([A-Z]+\),\sX[0-9]+`
296	return a[1] / a[2]
297}
298
299func Pow2Mods(n1 uint, n2 int) (uint, int) {
300	// 386:"ANDL\t[$]31",-"DIVL"
301	// amd64:"ANDL\t[$]31",-"DIVQ"
302	// arm:"AND\t[$]31",-".*udiv"
303	// arm64:"AND\t[$]31",-"UDIV"
304	// ppc64x:"RLDICL"
305	a := n1 % 32 // unsigned
306
307	// 386:"SHRL",-"IDIVL"
308	// amd64:"SHRQ",-"IDIVQ"
309	// arm:"SRA",-".*udiv"
310	// arm64:"ASR",-"REM"
311	// ppc64x:"SRAD"
312	b := n2 % 64 // signed
313
314	return a, b
315}
316
317// Check that signed divisibility checks get converted to AND on low bits
318func Pow2DivisibleSigned(n1, n2 int) (bool, bool) {
319	// 386:"TESTL\t[$]63",-"DIVL",-"SHRL"
320	// amd64:"TESTQ\t[$]63",-"DIVQ",-"SHRQ"
321	// arm:"AND\t[$]63",-".*udiv",-"SRA"
322	// arm64:"TST\t[$]63",-"UDIV",-"ASR",-"AND"
323	// ppc64x:"ANDCC",-"RLDICL",-"SRAD",-"CMP"
324	a := n1%64 == 0 // signed divisible
325
326	// 386:"TESTL\t[$]63",-"DIVL",-"SHRL"
327	// amd64:"TESTQ\t[$]63",-"DIVQ",-"SHRQ"
328	// arm:"AND\t[$]63",-".*udiv",-"SRA"
329	// arm64:"TST\t[$]63",-"UDIV",-"ASR",-"AND"
330	// ppc64x:"ANDCC",-"RLDICL",-"SRAD",-"CMP"
331	b := n2%64 != 0 // signed indivisible
332
333	return a, b
334}
335
336// Check that constant modulo divs get turned into MULs
337func ConstMods(n1 uint, n2 int) (uint, int) {
338	// amd64:"MOVQ\t[$]-1085102592571150095","MULQ",-"DIVQ"
339	// 386:"MOVL\t[$]-252645135","MULL",-"DIVL"
340	// arm64:`MOVD`,`UMULH`,-`DIV`
341	// arm:`MOVW`,`MUL`,-`.*udiv`
342	a := n1 % 17 // unsigned
343
344	// amd64:"MOVQ\t[$]-1085102592571150095","IMULQ",-"IDIVQ"
345	// 386:"MOVL\t[$]-252645135","IMULL",-"IDIVL"
346	// arm64:`SMULH`,-`DIV`
347	// arm:`MOVW`,`MUL`,-`.*udiv`
348	b := n2 % 17 // signed
349
350	return a, b
351}
352
353// Check that divisibility checks x%c==0 are converted to MULs and rotates
354func DivisibleU(n uint) (bool, bool) {
355	// amd64:"MOVQ\t[$]-6148914691236517205","IMULQ","ROLQ\t[$]63",-"DIVQ"
356	// 386:"IMUL3L\t[$]-1431655765","ROLL\t[$]31",-"DIVQ"
357	// arm64:"MOVD\t[$]-6148914691236517205","MOVD\t[$]3074457345618258602","MUL","ROR",-"DIV"
358	// arm:"MUL","CMP\t[$]715827882",-".*udiv"
359	// ppc64x:"MULLD","ROTL\t[$]63"
360	even := n%6 == 0
361
362	// amd64:"MOVQ\t[$]-8737931403336103397","IMULQ",-"ROLQ",-"DIVQ"
363	// 386:"IMUL3L\t[$]678152731",-"ROLL",-"DIVQ"
364	// arm64:"MOVD\t[$]-8737931403336103397","MUL",-"ROR",-"DIV"
365	// arm:"MUL","CMP\t[$]226050910",-".*udiv"
366	// ppc64x:"MULLD",-"ROTL"
367	odd := n%19 == 0
368
369	return even, odd
370}
371
372func Divisible(n int) (bool, bool) {
373	// amd64:"IMULQ","ADD","ROLQ\t[$]63",-"DIVQ"
374	// 386:"IMUL3L\t[$]-1431655765","ADDL\t[$]715827882","ROLL\t[$]31",-"DIVQ"
375	// arm64:"MOVD\t[$]-6148914691236517205","MOVD\t[$]3074457345618258602","MUL","ADD\tR","ROR",-"DIV"
376	// arm:"MUL","ADD\t[$]715827882",-".*udiv"
377	// ppc64x/power8:"MULLD","ADD","ROTL\t[$]63"
378	// ppc64x/power9:"MADDLD","ROTL\t[$]63"
379	even := n%6 == 0
380
381	// amd64:"IMULQ","ADD",-"ROLQ",-"DIVQ"
382	// 386:"IMUL3L\t[$]678152731","ADDL\t[$]113025455",-"ROLL",-"DIVQ"
383	// arm64:"MUL","MOVD\t[$]485440633518672410","ADD",-"ROR",-"DIV"
384	// arm:"MUL","ADD\t[$]113025455",-".*udiv"
385	// ppc64x/power8:"MULLD","ADD",-"ROTL"
386	// ppc64x/power9:"MADDLD",-"ROTL"
387	odd := n%19 == 0
388
389	return even, odd
390}
391
392// Check that fix-up code is not generated for divisions where it has been proven that
393// that the divisor is not -1 or that the dividend is > MinIntNN.
394func NoFix64A(divr int64) (int64, int64) {
395	var d int64 = 42
396	var e int64 = 84
397	if divr > 5 {
398		d /= divr // amd64:-"JMP"
399		e %= divr // amd64:-"JMP"
400		// The following statement is to avoid conflict between the above check
401		// and the normal JMP generated at the end of the block.
402		d += e
403	}
404	return d, e
405}
406
407func NoFix64B(divd int64) (int64, int64) {
408	var d int64
409	var e int64
410	var divr int64 = -1
411	if divd > -9223372036854775808 {
412		d = divd / divr // amd64:-"JMP"
413		e = divd % divr // amd64:-"JMP"
414		d += e
415	}
416	return d, e
417}
418
419func NoFix32A(divr int32) (int32, int32) {
420	var d int32 = 42
421	var e int32 = 84
422	if divr > 5 {
423		// amd64:-"JMP"
424		// 386:-"JMP"
425		d /= divr
426		// amd64:-"JMP"
427		// 386:-"JMP"
428		e %= divr
429		d += e
430	}
431	return d, e
432}
433
434func NoFix32B(divd int32) (int32, int32) {
435	var d int32
436	var e int32
437	var divr int32 = -1
438	if divd > -2147483648 {
439		// amd64:-"JMP"
440		// 386:-"JMP"
441		d = divd / divr
442		// amd64:-"JMP"
443		// 386:-"JMP"
444		e = divd % divr
445		d += e
446	}
447	return d, e
448}
449
450func NoFix16A(divr int16) (int16, int16) {
451	var d int16 = 42
452	var e int16 = 84
453	if divr > 5 {
454		// amd64:-"JMP"
455		// 386:-"JMP"
456		d /= divr
457		// amd64:-"JMP"
458		// 386:-"JMP"
459		e %= divr
460		d += e
461	}
462	return d, e
463}
464
465func NoFix16B(divd int16) (int16, int16) {
466	var d int16
467	var e int16
468	var divr int16 = -1
469	if divd > -32768 {
470		// amd64:-"JMP"
471		// 386:-"JMP"
472		d = divd / divr
473		// amd64:-"JMP"
474		// 386:-"JMP"
475		e = divd % divr
476		d += e
477	}
478	return d, e
479}
480
481// Check that len() and cap() calls divided by powers of two are
482// optimized into shifts and ands
483
484func LenDiv1(a []int) int {
485	// 386:"SHRL\t[$]10"
486	// amd64:"SHRQ\t[$]10"
487	// arm64:"LSR\t[$]10",-"SDIV"
488	// arm:"SRL\t[$]10",-".*udiv"
489	// ppc64x:"SRD"\t[$]10"
490	return len(a) / 1024
491}
492
493func LenDiv2(s string) int {
494	// 386:"SHRL\t[$]11"
495	// amd64:"SHRQ\t[$]11"
496	// arm64:"LSR\t[$]11",-"SDIV"
497	// arm:"SRL\t[$]11",-".*udiv"
498	// ppc64x:"SRD\t[$]11"
499	return len(s) / (4097 >> 1)
500}
501
502func LenMod1(a []int) int {
503	// 386:"ANDL\t[$]1023"
504	// amd64:"ANDL\t[$]1023"
505	// arm64:"AND\t[$]1023",-"SDIV"
506	// arm/6:"AND",-".*udiv"
507	// arm/7:"BFC",-".*udiv",-"AND"
508	// ppc64x:"RLDICL"
509	return len(a) % 1024
510}
511
512func LenMod2(s string) int {
513	// 386:"ANDL\t[$]2047"
514	// amd64:"ANDL\t[$]2047"
515	// arm64:"AND\t[$]2047",-"SDIV"
516	// arm/6:"AND",-".*udiv"
517	// arm/7:"BFC",-".*udiv",-"AND"
518	// ppc64x:"RLDICL"
519	return len(s) % (4097 >> 1)
520}
521
522func CapDiv(a []int) int {
523	// 386:"SHRL\t[$]12"
524	// amd64:"SHRQ\t[$]12"
525	// arm64:"LSR\t[$]12",-"SDIV"
526	// arm:"SRL\t[$]12",-".*udiv"
527	// ppc64x:"SRD\t[$]12"
528	return cap(a) / ((1 << 11) + 2048)
529}
530
531func CapMod(a []int) int {
532	// 386:"ANDL\t[$]4095"
533	// amd64:"ANDL\t[$]4095"
534	// arm64:"AND\t[$]4095",-"SDIV"
535	// arm/6:"AND",-".*udiv"
536	// arm/7:"BFC",-".*udiv",-"AND"
537	// ppc64x:"RLDICL"
538	return cap(a) % ((1 << 11) + 2048)
539}
540
541func AddMul(x int) int {
542	// amd64:"LEAQ\t1"
543	return 2*x + 1
544}
545
546func MULA(a, b, c uint32) (uint32, uint32, uint32) {
547	// arm:`MULA`,-`MUL\s`
548	// arm64:`MADDW`,-`MULW`
549	r0 := a*b + c
550	// arm:`MULA`,-`MUL\s`
551	// arm64:`MADDW`,-`MULW`
552	r1 := c*79 + a
553	// arm:`ADD`,-`MULA`,-`MUL\s`
554	// arm64:`ADD`,-`MADD`,-`MULW`
555	// ppc64x:`ADD`,-`MULLD`
556	r2 := b*64 + c
557	return r0, r1, r2
558}
559
560func MULS(a, b, c uint32) (uint32, uint32, uint32) {
561	// arm/7:`MULS`,-`MUL\s`
562	// arm/6:`SUB`,`MUL\s`,-`MULS`
563	// arm64:`MSUBW`,-`MULW`
564	r0 := c - a*b
565	// arm/7:`MULS`,-`MUL\s`
566	// arm/6:`SUB`,`MUL\s`,-`MULS`
567	// arm64:`MSUBW`,-`MULW`
568	r1 := a - c*79
569	// arm/7:`SUB`,-`MULS`,-`MUL\s`
570	// arm64:`SUB`,-`MSUBW`,-`MULW`
571	// ppc64x:`SUB`,-`MULLD`
572	r2 := c - b*64
573	return r0, r1, r2
574}
575
576func addSpecial(a, b, c uint32) (uint32, uint32, uint32) {
577	// amd64:`INCL`
578	a++
579	// amd64:`DECL`
580	b--
581	// amd64:`SUBL.*-128`
582	c += 128
583	return a, b, c
584}
585
586// Divide -> shift rules usually require fixup for negative inputs.
587// If the input is non-negative, make sure the fixup is eliminated.
588func divInt(v int64) int64 {
589	if v < 0 {
590		return 0
591	}
592	// amd64:-`.*SARQ.*63,`, -".*SHRQ", ".*SARQ.*[$]9,"
593	return v / 512
594}
595
596// The reassociate rules "x - (z + C) -> (x - z) - C" and
597// "(z + C) -x -> C + (z - x)" can optimize the following cases.
598func constantFold1(i0, j0, i1, j1, i2, j2, i3, j3 int) (int, int, int, int) {
599	// arm64:"SUB","ADD\t[$]2"
600	// ppc64x:"SUB","ADD\t[$]2"
601	r0 := (i0 + 3) - (j0 + 1)
602	// arm64:"SUB","SUB\t[$]4"
603	// ppc64x:"SUB","ADD\t[$]-4"
604	r1 := (i1 - 3) - (j1 + 1)
605	// arm64:"SUB","ADD\t[$]4"
606	// ppc64x:"SUB","ADD\t[$]4"
607	r2 := (i2 + 3) - (j2 - 1)
608	// arm64:"SUB","SUB\t[$]2"
609	// ppc64x:"SUB","ADD\t[$]-2"
610	r3 := (i3 - 3) - (j3 - 1)
611	return r0, r1, r2, r3
612}
613
614// The reassociate rules "x - (z + C) -> (x - z) - C" and
615// "(C - z) - x -> C - (z + x)" can optimize the following cases.
616func constantFold2(i0, j0, i1, j1 int) (int, int) {
617	// arm64:"ADD","MOVD\t[$]2","SUB"
618	// ppc64x: `SUBC\tR[0-9]+,\s[$]2,\sR`
619	r0 := (3 - i0) - (j0 + 1)
620	// arm64:"ADD","MOVD\t[$]4","SUB"
621	// ppc64x: `SUBC\tR[0-9]+,\s[$]4,\sR`
622	r1 := (3 - i1) - (j1 - 1)
623	return r0, r1
624}
625
626func constantFold3(i, j int) int {
627	// arm64: "MOVD\t[$]30","MUL",-"ADD",-"LSL"
628	// ppc64x:"MULLD\t[$]30","MULLD"
629	r := (5 * i) * (6 * j)
630	return r
631}
632