1 /*
2  * Copyright (C) 2015 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 public class Main {
18 
19   // A dummy value to defeat inlining of these routines.
20   static boolean doThrow = false;
21 
assertIntEquals(int expected, int result)22   public static void assertIntEquals(int expected, int result) {
23     if (expected != result) {
24       throw new Error("Expected: " + expected + ", found: " + result);
25     }
26   }
27 
assertLongEquals(long expected, long result)28   public static void assertLongEquals(long expected, long result) {
29     if (expected != result) {
30       throw new Error("Expected: " + expected + ", found: " + result);
31     }
32   }
33 
34   /**
35    * Test basic merging of `MUL+ADD` into `MULADD`.
36    */
37 
38   /// CHECK-START-ARM64: int Main.$opt$noinline$mulAdd(int, int, int) instruction_simplifier_arm64 (before)
39   /// CHECK:       <<Acc:i\d+>>         ParameterValue
40   /// CHECK:       <<Left:i\d+>>        ParameterValue
41   /// CHECK:       <<Right:i\d+>>       ParameterValue
42   /// CHECK:       <<Mul:i\d+>>         Mul [<<Left>>,<<Right>>]
43   /// CHECK:       <<Add:i\d+>>         Add [<<Acc>>,<<Mul>>]
44   /// CHECK:                            Return [<<Add>>]
45 
46   /// CHECK-START-ARM64: int Main.$opt$noinline$mulAdd(int, int, int) instruction_simplifier_arm64 (after)
47   /// CHECK:       <<Acc:i\d+>>         ParameterValue
48   /// CHECK:       <<Left:i\d+>>        ParameterValue
49   /// CHECK:       <<Right:i\d+>>       ParameterValue
50   /// CHECK:       <<MulAdd:i\d+>>      MultiplyAccumulate [<<Acc>>,<<Left>>,<<Right>>] kind:Add
51   /// CHECK:                            Return [<<MulAdd>>]
52 
53   /// CHECK-START-ARM64: int Main.$opt$noinline$mulAdd(int, int, int) instruction_simplifier_arm64 (after)
54   /// CHECK-NOT:                        Mul
55   /// CHECK-NOT:                        Add
56 
57   /// CHECK-START-ARM64: int Main.$opt$noinline$mulAdd(int, int, int) disassembly (after)
58   /// CHECK:                            madd w{{\d+}}, w{{\d+}}, w{{\d+}}, w{{\d+}}
59 
60   /// CHECK-START-ARM: int Main.$opt$noinline$mulAdd(int, int, int) instruction_simplifier_arm (before)
61   /// CHECK:       <<Acc:i\d+>>         ParameterValue
62   /// CHECK:       <<Left:i\d+>>        ParameterValue
63   /// CHECK:       <<Right:i\d+>>       ParameterValue
64   /// CHECK:       <<Mul:i\d+>>         Mul [<<Left>>,<<Right>>]
65   /// CHECK:       <<Add:i\d+>>         Add [<<Acc>>,<<Mul>>]
66   /// CHECK:                            Return [<<Add>>]
67 
68   /// CHECK-START-ARM: int Main.$opt$noinline$mulAdd(int, int, int) instruction_simplifier_arm (after)
69   /// CHECK:       <<Acc:i\d+>>         ParameterValue
70   /// CHECK:       <<Left:i\d+>>        ParameterValue
71   /// CHECK:       <<Right:i\d+>>       ParameterValue
72   /// CHECK:       <<MulAdd:i\d+>>      MultiplyAccumulate [<<Acc>>,<<Left>>,<<Right>>] kind:Add
73   /// CHECK:                            Return [<<MulAdd>>]
74 
75   /// CHECK-START-ARM: int Main.$opt$noinline$mulAdd(int, int, int) instruction_simplifier_arm (after)
76   /// CHECK-NOT:                        Mul
77   /// CHECK-NOT:                        Add
78 
79   /// CHECK-START-ARM: int Main.$opt$noinline$mulAdd(int, int, int) disassembly (after)
80   /// CHECK:                            mla r{{\d+}}, r{{\d+}}, r{{\d+}}, r{{\d+}}
81 
$opt$noinline$mulAdd(int acc, int left, int right)82   public static int $opt$noinline$mulAdd(int acc, int left, int right) {
83     if (doThrow) throw new Error();
84     return acc + left * right;
85   }
86 
87   /**
88    * Test basic merging of `MUL+SUB` into `MULSUB`.
89    */
90 
91   /// CHECK-START-ARM64: long Main.$opt$noinline$mulSub(long, long, long) instruction_simplifier_arm64 (before)
92   /// CHECK:       <<Acc:j\d+>>         ParameterValue
93   /// CHECK:       <<Left:j\d+>>        ParameterValue
94   /// CHECK:       <<Right:j\d+>>       ParameterValue
95   /// CHECK:       <<Mul:j\d+>>         Mul [<<Left>>,<<Right>>]
96   /// CHECK:       <<Sub:j\d+>>         Sub [<<Acc>>,<<Mul>>]
97   /// CHECK:                            Return [<<Sub>>]
98 
99   /// CHECK-START-ARM64: long Main.$opt$noinline$mulSub(long, long, long) instruction_simplifier_arm64 (after)
100   /// CHECK:       <<Acc:j\d+>>         ParameterValue
101   /// CHECK:       <<Left:j\d+>>        ParameterValue
102   /// CHECK:       <<Right:j\d+>>       ParameterValue
103   /// CHECK:       <<MulSub:j\d+>>      MultiplyAccumulate [<<Acc>>,<<Left>>,<<Right>>] kind:Sub
104   /// CHECK:                            Return [<<MulSub>>]
105 
106   /// CHECK-START-ARM64: long Main.$opt$noinline$mulSub(long, long, long) instruction_simplifier_arm64 (after)
107   /// CHECK-NOT:                        Mul
108   /// CHECK-NOT:                        Sub
109 
110   /// CHECK-START-ARM64: long Main.$opt$noinline$mulSub(long, long, long) disassembly (after)
111   /// CHECK:                            msub x{{\d+}}, x{{\d+}}, x{{\d+}}, x{{\d+}}
112 
113   /// CHECK-START-ARM: long Main.$opt$noinline$mulSub(long, long, long) instruction_simplifier_arm (before)
114   /// CHECK:       <<Acc:j\d+>>         ParameterValue
115   /// CHECK:       <<Left:j\d+>>        ParameterValue
116   /// CHECK:       <<Right:j\d+>>       ParameterValue
117   /// CHECK:       <<Mul:j\d+>>         Mul [<<Left>>,<<Right>>]
118   /// CHECK:       <<Sub:j\d+>>         Sub [<<Acc>>,<<Mul>>]
119   /// CHECK:                            Return [<<Sub>>]
120 
121   /// CHECK-START-ARM: long Main.$opt$noinline$mulSub(long, long, long) instruction_simplifier_arm (after)
122   /// CHECK-NOT:                        MultiplyAccumulate
123 
$opt$noinline$mulSub(long acc, long left, long right)124   public static long $opt$noinline$mulSub(long acc, long left, long right) {
125     if (doThrow) throw new Error();
126     return acc - left * right;
127   }
128 
129   /**
130    * Test that we do not create a multiply-accumulate instruction when there
131    * are other uses of the multiplication that cannot merge it.
132    */
133 
134   /// CHECK-START-ARM64: int Main.$opt$noinline$multipleUses1(int, int, int) instruction_simplifier_arm64 (before)
135   /// CHECK:       <<Acc:i\d+>>         ParameterValue
136   /// CHECK:       <<Left:i\d+>>        ParameterValue
137   /// CHECK:       <<Right:i\d+>>       ParameterValue
138   /// CHECK:       <<Mul:i\d+>>         Mul [<<Left>>,<<Right>>]
139   /// CHECK:       <<Add:i\d+>>         Add [<<Acc>>,<<Mul>>]
140   /// CHECK:       <<Or:i\d+>>          Or [<<Mul>>,<<Add>>]
141   /// CHECK:                            Return [<<Or>>]
142 
143   /// CHECK-START-ARM64: int Main.$opt$noinline$multipleUses1(int, int, int) instruction_simplifier_arm64 (after)
144   /// CHECK:       <<Acc:i\d+>>         ParameterValue
145   /// CHECK:       <<Left:i\d+>>        ParameterValue
146   /// CHECK:       <<Right:i\d+>>       ParameterValue
147   /// CHECK:       <<Mul:i\d+>>         Mul [<<Left>>,<<Right>>]
148   /// CHECK:       <<Add:i\d+>>         Add [<<Acc>>,<<Mul>>]
149   /// CHECK:       <<Or:i\d+>>          Or [<<Mul>>,<<Add>>]
150   /// CHECK:                            Return [<<Or>>]
151 
152   /// CHECK-START-ARM64: int Main.$opt$noinline$multipleUses1(int, int, int) instruction_simplifier_arm64 (after)
153   /// CHECK-NOT:                        MultiplyAccumulate
154 
155   /// CHECK-START-ARM: int Main.$opt$noinline$multipleUses1(int, int, int) instruction_simplifier_arm (before)
156   /// CHECK:       <<Acc:i\d+>>         ParameterValue
157   /// CHECK:       <<Left:i\d+>>        ParameterValue
158   /// CHECK:       <<Right:i\d+>>       ParameterValue
159   /// CHECK:       <<Mul:i\d+>>         Mul [<<Left>>,<<Right>>]
160   /// CHECK:       <<Add:i\d+>>         Add [<<Acc>>,<<Mul>>]
161   /// CHECK:       <<Or:i\d+>>          Or [<<Mul>>,<<Add>>]
162   /// CHECK:                            Return [<<Or>>]
163 
164   /// CHECK-START-ARM: int Main.$opt$noinline$multipleUses1(int, int, int) instruction_simplifier_arm (after)
165   /// CHECK:       <<Acc:i\d+>>         ParameterValue
166   /// CHECK:       <<Left:i\d+>>        ParameterValue
167   /// CHECK:       <<Right:i\d+>>       ParameterValue
168   /// CHECK:       <<Mul:i\d+>>         Mul [<<Left>>,<<Right>>]
169   /// CHECK:       <<Add:i\d+>>         Add [<<Acc>>,<<Mul>>]
170   /// CHECK:       <<Or:i\d+>>          Or [<<Mul>>,<<Add>>]
171   /// CHECK:                            Return [<<Or>>]
172 
173   /// CHECK-START-ARM: int Main.$opt$noinline$multipleUses1(int, int, int) instruction_simplifier_arm (after)
174   /// CHECK-NOT:                        MultiplyAccumulate
175 
$opt$noinline$multipleUses1(int acc, int left, int right)176   public static int $opt$noinline$multipleUses1(int acc, int left, int right) {
177     if (doThrow) throw new Error();
178     int temp = left * right;
179     return temp | (acc + temp);
180   }
181 
182   /**
183    * Test that we do not create a multiply-accumulate instruction even when all
184    * uses of the multiplication can merge it.
185    */
186 
187   /// CHECK-START-ARM64: long Main.$opt$noinline$multipleUses2(long, long, long) instruction_simplifier_arm64 (before)
188   /// CHECK:       <<Acc:j\d+>>         ParameterValue
189   /// CHECK:       <<Left:j\d+>>        ParameterValue
190   /// CHECK:       <<Right:j\d+>>       ParameterValue
191   /// CHECK:       <<Mul:j\d+>>         Mul [<<Left>>,<<Right>>]
192   /// CHECK:       <<Add:j\d+>>         Add [<<Acc>>,<<Mul>>]
193   /// CHECK:       <<Sub:j\d+>>         Sub [<<Acc>>,<<Mul>>]
194   /// CHECK:       <<Res:j\d+>>         Add [<<Add>>,<<Sub>>]
195   /// CHECK:                            Return [<<Res>>]
196 
197   /// CHECK-START-ARM64: long Main.$opt$noinline$multipleUses2(long, long, long) instruction_simplifier_arm64 (after)
198   /// CHECK:       <<Acc:j\d+>>         ParameterValue
199   /// CHECK:       <<Left:j\d+>>        ParameterValue
200   /// CHECK:       <<Right:j\d+>>       ParameterValue
201   /// CHECK:       <<Mul:j\d+>>         Mul [<<Left>>,<<Right>>]
202   /// CHECK:       <<Add:j\d+>>         Add [<<Acc>>,<<Mul>>]
203   /// CHECK:       <<Sub:j\d+>>         Sub [<<Acc>>,<<Mul>>]
204   /// CHECK:       <<Res:j\d+>>         Add [<<Add>>,<<Sub>>]
205   /// CHECK:                            Return [<<Res>>]
206 
207   /// CHECK-START-ARM64: long Main.$opt$noinline$multipleUses2(long, long, long) instruction_simplifier_arm64 (after)
208   /// CHECK-NOT:                        MultiplyAccumulate
209 
210   /// CHECK-START-ARM: long Main.$opt$noinline$multipleUses2(long, long, long) instruction_simplifier_arm (before)
211   /// CHECK:       <<Acc:j\d+>>         ParameterValue
212   /// CHECK:       <<Left:j\d+>>        ParameterValue
213   /// CHECK:       <<Right:j\d+>>       ParameterValue
214   /// CHECK:       <<Mul:j\d+>>         Mul [<<Left>>,<<Right>>]
215   /// CHECK:       <<Add:j\d+>>         Add [<<Acc>>,<<Mul>>]
216   /// CHECK:       <<Sub:j\d+>>         Sub [<<Acc>>,<<Mul>>]
217   /// CHECK:       <<Res:j\d+>>         Add [<<Add>>,<<Sub>>]
218   /// CHECK:                            Return [<<Res>>]
219 
220   /// CHECK-START-ARM: long Main.$opt$noinline$multipleUses2(long, long, long) instruction_simplifier_arm (after)
221   /// CHECK:       <<Acc:j\d+>>         ParameterValue
222   /// CHECK:       <<Left:j\d+>>        ParameterValue
223   /// CHECK:       <<Right:j\d+>>       ParameterValue
224   /// CHECK:       <<Mul:j\d+>>         Mul [<<Left>>,<<Right>>]
225   /// CHECK:       <<Add:j\d+>>         Add [<<Acc>>,<<Mul>>]
226   /// CHECK:       <<Sub:j\d+>>         Sub [<<Acc>>,<<Mul>>]
227   /// CHECK:       <<Res:j\d+>>         Add [<<Add>>,<<Sub>>]
228   /// CHECK:                            Return [<<Res>>]
229 
230   /// CHECK-START-ARM: long Main.$opt$noinline$multipleUses2(long, long, long) instruction_simplifier_arm (after)
231   /// CHECK-NOT:                        MultiplyAccumulate
232 
233 
$opt$noinline$multipleUses2(long acc, long left, long right)234   public static long $opt$noinline$multipleUses2(long acc, long left, long right) {
235     if (doThrow) throw new Error();
236     long temp = left * right;
237     return (acc + temp) + (acc - temp);
238   }
239 
240 
241   /**
242    * Test the interpretation of `a * (b + 1)` as `a + (a * b)`.
243    */
244 
245   /// CHECK-START-ARM64: int Main.$opt$noinline$mulPlusOne(int, int) instruction_simplifier_arm64 (before)
246   /// CHECK:       <<Acc:i\d+>>         ParameterValue
247   /// CHECK:       <<Var:i\d+>>         ParameterValue
248   /// CHECK:       <<Const1:i\d+>>      IntConstant 1
249   /// CHECK:       <<Add:i\d+>>         Add [<<Var>>,<<Const1>>]
250   /// CHECK:       <<Mul:i\d+>>         Mul [<<Acc>>,<<Add>>]
251   /// CHECK:                            Return [<<Mul>>]
252 
253   /// CHECK-START-ARM64: int Main.$opt$noinline$mulPlusOne(int, int) instruction_simplifier_arm64 (after)
254   /// CHECK:       <<Acc:i\d+>>         ParameterValue
255   /// CHECK:       <<Var:i\d+>>         ParameterValue
256   /// CHECK:       <<MulAdd:i\d+>>      MultiplyAccumulate [<<Acc>>,<<Acc>>,<<Var>>] kind:Add
257   /// CHECK:                            Return [<<MulAdd>>]
258 
259   /// CHECK-START-ARM64: int Main.$opt$noinline$mulPlusOne(int, int) instruction_simplifier_arm64 (after)
260   /// CHECK-NOT:                        Mul
261   /// CHECK-NOT:                        Add
262 
263   /// CHECK-START-ARM64: int Main.$opt$noinline$mulPlusOne(int, int) disassembly (after)
264   /// CHECK:                            madd w{{\d+}}, w{{\d+}}, w{{\d+}}, w{{\d+}}
265 
266   /// CHECK-START-ARM: int Main.$opt$noinline$mulPlusOne(int, int) instruction_simplifier_arm (before)
267   /// CHECK:       <<Acc:i\d+>>         ParameterValue
268   /// CHECK:       <<Var:i\d+>>         ParameterValue
269   /// CHECK:       <<Const1:i\d+>>      IntConstant 1
270   /// CHECK:       <<Add:i\d+>>         Add [<<Var>>,<<Const1>>]
271   /// CHECK:       <<Mul:i\d+>>         Mul [<<Acc>>,<<Add>>]
272   /// CHECK:                            Return [<<Mul>>]
273 
274   /// CHECK-START-ARM: int Main.$opt$noinline$mulPlusOne(int, int) instruction_simplifier_arm (after)
275   /// CHECK:       <<Acc:i\d+>>         ParameterValue
276   /// CHECK:       <<Var:i\d+>>         ParameterValue
277   /// CHECK:       <<MulAdd:i\d+>>      MultiplyAccumulate [<<Acc>>,<<Acc>>,<<Var>>] kind:Add
278   /// CHECK:                            Return [<<MulAdd>>]
279 
280   /// CHECK-START-ARM: int Main.$opt$noinline$mulPlusOne(int, int) instruction_simplifier_arm (after)
281   /// CHECK-NOT:                        Mul
282   /// CHECK-NOT:                        Add
283 
284   /// CHECK-START-ARM: int Main.$opt$noinline$mulPlusOne(int, int) disassembly (after)
285   /// CHECK:                            mla r{{\d+}}, r{{\d+}}, r{{\d+}}, r{{\d+}}
286 
$opt$noinline$mulPlusOne(int acc, int var)287   public static int $opt$noinline$mulPlusOne(int acc, int var) {
288     if (doThrow) throw new Error();
289     return acc * (var + 1);
290   }
291 
292 
293   /**
294    * Test the interpretation of `a * (1 - b)` as `a - (a * b)`.
295    */
296 
297   /// CHECK-START-ARM64: long Main.$opt$noinline$mulMinusOne(long, long) instruction_simplifier_arm64 (before)
298   /// CHECK:       <<Acc:j\d+>>         ParameterValue
299   /// CHECK:       <<Var:j\d+>>         ParameterValue
300   /// CHECK:       <<Const1:j\d+>>      LongConstant 1
301   /// CHECK:       <<Sub:j\d+>>         Sub [<<Const1>>,<<Var>>]
302   /// CHECK:       <<Mul:j\d+>>         Mul [<<Acc>>,<<Sub>>]
303   /// CHECK:                            Return [<<Mul>>]
304 
305   /// CHECK-START-ARM64: long Main.$opt$noinline$mulMinusOne(long, long) instruction_simplifier_arm64 (after)
306   /// CHECK:       <<Acc:j\d+>>         ParameterValue
307   /// CHECK:       <<Var:j\d+>>         ParameterValue
308   /// CHECK:       <<MulSub:j\d+>>      MultiplyAccumulate [<<Acc>>,<<Acc>>,<<Var>>] kind:Sub
309   /// CHECK:                            Return [<<MulSub>>]
310 
311   /// CHECK-START-ARM64: long Main.$opt$noinline$mulMinusOne(long, long) instruction_simplifier_arm64 (after)
312   /// CHECK-NOT:                        Mul
313   /// CHECK-NOT:                        Sub
314 
315   /// CHECK-START-ARM64: long Main.$opt$noinline$mulMinusOne(long, long) disassembly (after)
316   /// CHECK:                            msub x{{\d+}}, x{{\d+}}, x{{\d+}}, x{{\d+}}
317 
318   /// CHECK-START-ARM: long Main.$opt$noinline$mulMinusOne(long, long) instruction_simplifier_arm (before)
319   /// CHECK:       <<Acc:j\d+>>         ParameterValue
320   /// CHECK:       <<Var:j\d+>>         ParameterValue
321   /// CHECK:       <<Const1:j\d+>>      LongConstant 1
322   /// CHECK:       <<Sub:j\d+>>         Sub [<<Const1>>,<<Var>>]
323   /// CHECK:       <<Mul:j\d+>>         Mul [<<Acc>>,<<Sub>>]
324   /// CHECK:                            Return [<<Mul>>]
325 
326   /// CHECK-START-ARM: long Main.$opt$noinline$mulMinusOne(long, long) instruction_simplifier_arm (after)
327   /// CHECK-NOT:                        MultiplyAccumulate
$opt$noinline$mulMinusOne(long acc, long var)328   public static long $opt$noinline$mulMinusOne(long acc, long var) {
329     if (doThrow) throw new Error();
330     return acc * (1 - var);
331   }
332 
333   /**
334    * Test basic merging of `MUL+NEG` into `MULNEG`.
335    */
336 
337   /// CHECK-START-ARM64: int Main.$opt$noinline$mulNeg(int, int) instruction_simplifier_arm64 (before)
338   /// CHECK:       <<Left:i\d+>>        ParameterValue
339   /// CHECK:       <<Right:i\d+>>       ParameterValue
340   /// CHECK:       <<Mul:i\d+>>         Mul [<<Left>>,<<Right>>]
341   /// CHECK:       <<Neg:i\d+>>         Neg [<<Mul>>]
342   /// CHECK:                            Return [<<Neg>>]
343 
344   /// CHECK-START-ARM64: int Main.$opt$noinline$mulNeg(int, int) instruction_simplifier_arm64 (after)
345   /// CHECK:       <<Left:i\d+>>        ParameterValue
346   /// CHECK:       <<Right:i\d+>>       ParameterValue
347   /// CHECK:       <<Const0:i\d+>>      IntConstant 0
348   /// CHECK:       <<MulNeg:i\d+>>      MultiplyAccumulate [<<Const0>>,<<Left>>,<<Right>>] kind:Sub
349   /// CHECK:                            Return [<<MulNeg>>]
350 
351   /// CHECK-START-ARM64: int Main.$opt$noinline$mulNeg(int, int) instruction_simplifier_arm64 (after)
352   /// CHECK-NOT:                        Mul
353   /// CHECK-NOT:                        Neg
354 
355   /// CHECK-START-ARM64: int Main.$opt$noinline$mulNeg(int, int) disassembly (after)
356   /// CHECK:                            mneg w{{\d+}}, w{{\d+}}, w{{\d+}}
357 
358   /// CHECK-START-ARM: int Main.$opt$noinline$mulNeg(int, int) instruction_simplifier_arm (before)
359   /// CHECK:       <<Left:i\d+>>        ParameterValue
360   /// CHECK:       <<Right:i\d+>>       ParameterValue
361   /// CHECK:       <<Mul:i\d+>>         Mul [<<Left>>,<<Right>>]
362   /// CHECK:       <<Neg:i\d+>>         Neg [<<Mul>>]
363   /// CHECK:                            Return [<<Neg>>]
364 
365   /// CHECK-START-ARM: int Main.$opt$noinline$mulNeg(int, int) instruction_simplifier_arm (after)
366   /// CHECK:       <<Left:i\d+>>        ParameterValue
367   /// CHECK:       <<Right:i\d+>>       ParameterValue
368   /// CHECK:       <<Mul:i\d+>>         Mul [<<Left>>,<<Right>>]
369   /// CHECK:       <<Neg:i\d+>>         Neg [<<Mul>>]
370   /// CHECK:                            Return [<<Neg>>]
371 
372   /// CHECK-START-ARM: int Main.$opt$noinline$mulNeg(int, int) instruction_simplifier_arm (after)
373   /// CHECK-NOT:                        MultiplyAccumulate
374 
$opt$noinline$mulNeg(int left, int right)375   public static int $opt$noinline$mulNeg(int left, int right) {
376     if (doThrow) throw new Error();
377     return - (left * right);
378   }
379 
380   /**
381    * Test basic merging of `MUL+NEG` into `MULNEG`.
382    */
383 
384   /// CHECK-START-ARM64: long Main.$opt$noinline$mulNeg(long, long) instruction_simplifier_arm64 (before)
385   /// CHECK:       <<Left:j\d+>>        ParameterValue
386   /// CHECK:       <<Right:j\d+>>       ParameterValue
387   /// CHECK:       <<Mul:j\d+>>         Mul [<<Left>>,<<Right>>]
388   /// CHECK:       <<Neg:j\d+>>         Neg [<<Mul>>]
389   /// CHECK:                            Return [<<Neg>>]
390 
391   /// CHECK-START-ARM64: long Main.$opt$noinline$mulNeg(long, long) instruction_simplifier_arm64 (after)
392   /// CHECK:       <<Left:j\d+>>        ParameterValue
393   /// CHECK:       <<Right:j\d+>>       ParameterValue
394   /// CHECK:       <<Const0:j\d+>>      LongConstant 0
395   /// CHECK:       <<MulNeg:j\d+>>      MultiplyAccumulate [<<Const0>>,<<Left>>,<<Right>>] kind:Sub
396   /// CHECK:                            Return [<<MulNeg>>]
397 
398   /// CHECK-START-ARM64: long Main.$opt$noinline$mulNeg(long, long) instruction_simplifier_arm64 (after)
399   /// CHECK-NOT:                        Mul
400   /// CHECK-NOT:                        Neg
401 
402   /// CHECK-START-ARM64: long Main.$opt$noinline$mulNeg(long, long) disassembly (after)
403   /// CHECK:                            mneg x{{\d+}}, x{{\d+}}, x{{\d+}}
404 
405   /// CHECK-START-ARM: long Main.$opt$noinline$mulNeg(long, long) instruction_simplifier_arm (before)
406   /// CHECK:       <<Left:j\d+>>        ParameterValue
407   /// CHECK:       <<Right:j\d+>>       ParameterValue
408   /// CHECK:       <<Mul:j\d+>>         Mul [<<Left>>,<<Right>>]
409   /// CHECK:       <<Neg:j\d+>>         Neg [<<Mul>>]
410   /// CHECK:                            Return [<<Neg>>]
411 
412   /// CHECK-START-ARM: long Main.$opt$noinline$mulNeg(long, long) instruction_simplifier_arm (after)
413   /// CHECK:       <<Left:j\d+>>        ParameterValue
414   /// CHECK:       <<Right:j\d+>>       ParameterValue
415   /// CHECK:       <<Mul:j\d+>>         Mul [<<Left>>,<<Right>>]
416   /// CHECK:       <<Neg:j\d+>>         Neg [<<Mul>>]
417   /// CHECK:                            Return [<<Neg>>]
418 
419   /// CHECK-START-ARM: long Main.$opt$noinline$mulNeg(long, long) instruction_simplifier_arm (after)
420   /// CHECK-NOT:                        MultiplyAccumulate
421 
$opt$noinline$mulNeg(long left, long right)422   public static long $opt$noinline$mulNeg(long left, long right) {
423     if (doThrow) throw new Error();
424     return - (left * right);
425   }
426 
427   /// CHECK-START-ARM64: void Main.SimdMulAdd(int[], int[]) instruction_simplifier$after_bce (before)
428   /// CHECK-DAG:     Phi                            loop:<<Loop:B\d+>> outer_loop:none
429   /// CHECK-DAG:     VecMul                         loop:<<Loop>>      outer_loop:none
430   /// CHECK-DAG:     VecAdd                         loop:<<Loop>>      outer_loop:none
431 
432   /// CHECK-START-ARM64: void Main.SimdMulAdd(int[], int[]) instruction_simplifier$after_bce (after)
433   /// CHECK-DAG:     Phi                            loop:<<Loop:B\d+>> outer_loop:none
434   /// CHECK-DAG:     VecMultiplyAccumulate kind:Add loop:<<Loop>>      outer_loop:none
435 
436   /// CHECK-START-ARM64: void Main.SimdMulAdd(int[], int[]) instruction_simplifier$after_bce (after)
437   /// CHECK-NOT:     VecMul
438   /// CHECK-NOT:     VecAdd
439 
SimdMulAdd(int[] array1, int[] array2)440   public static void SimdMulAdd(int[] array1, int[] array2) {
441     for (int j = 0; j < 100; j++) {
442       array2[j] += 12345 * array1[j];
443     }
444   }
445 
SimdMulAddLong(long[] array1, long[] array2)446   public static void SimdMulAddLong(long[] array1, long[] array2) {
447     for (int j = 0; j < 100; j++) {
448       array2[j] += 12345 * array1[j];
449     }
450   }
451 
452   /// CHECK-START-ARM64: void Main.SimdMulSub(int[], int[]) instruction_simplifier$after_bce (before)
453   /// CHECK-DAG:     Phi                            loop:<<Loop:B\d+>> outer_loop:none
454   /// CHECK-DAG:     VecMul                         loop:<<Loop>>      outer_loop:none
455   /// CHECK-DAG:     VecSub                         loop:<<Loop>>      outer_loop:none
456 
457   /// CHECK-START-ARM64: void Main.SimdMulSub(int[], int[]) instruction_simplifier$after_bce (after)
458   /// CHECK-DAG:     Phi                            loop:<<Loop:B\d+>> outer_loop:none
459   /// CHECK-DAG:     VecMultiplyAccumulate kind:Sub loop:<<Loop>>      outer_loop:none
460 
461   /// CHECK-START-ARM64: void Main.SimdMulSub(int[], int[]) instruction_simplifier$after_bce (after)
462   /// CHECK-NOT:     VecMul
463   /// CHECK-NOT:     VecSub
464 
SimdMulSub(int[] array1, int[] array2)465   public static void SimdMulSub(int[] array1, int[] array2) {
466     for (int j = 0; j < 100; j++) {
467       array2[j] -= 12345 * array1[j];
468     }
469   }
470 
SimdMulSubLong(long[] array1, long[] array2)471   public static void SimdMulSubLong(long[] array1, long[] array2) {
472     for (int j = 0; j < 100; j++) {
473       array2[j] -= 12345 * array1[j];
474     }
475   }
476 
477   /// CHECK-START-ARM64: void Main.SimdMulMultipleUses(int[], int[]) instruction_simplifier$after_bce (before)
478   /// CHECK-DAG:     Phi                            loop:<<Loop:B\d+>> outer_loop:none
479   /// CHECK-DAG:     VecMul                         loop:<<Loop>>      outer_loop:none
480   /// CHECK-DAG:     VecSub                         loop:<<Loop>>      outer_loop:none
481 
482   /// CHECK-START-ARM64: void Main.SimdMulMultipleUses(int[], int[]) instruction_simplifier$after_bce (after)
483   /// CHECK-NOT: VecMultiplyAccumulate
484 
SimdMulMultipleUses(int[] array1, int[] array2)485   public static void SimdMulMultipleUses(int[] array1, int[] array2) {
486     for (int j = 0; j < 100; j++) {
487        int temp = 12345 * array1[j];
488        array2[j] -= temp;
489        array1[j] = temp;
490     }
491   }
492 
SimdMulMultipleUsesLong(long[] array1, long[] array2)493   public static void SimdMulMultipleUsesLong(long[] array1, long[] array2) {
494     for (int j = 0; j < 100; j++) {
495        long temp = 12345 * array1[j];
496        array2[j] -= temp;
497        array1[j] = temp;
498     }
499   }
500 
501   public static final int ARRAY_SIZE = 1000;
502 
initArray(int[] array)503   public static void initArray(int[] array) {
504     for (int i = 0; i < ARRAY_SIZE; i++) {
505       array[i] = i;
506     }
507   }
508 
initArrayLong(long[] array)509   public static void initArrayLong(long[] array) {
510     for (int i = 0; i < ARRAY_SIZE; i++) {
511       array[i] = i;
512     }
513   }
514 
calcArraySum(int[] array)515   public static int calcArraySum(int[] array) {
516     int sum = 0;
517     for (int i = 0; i < ARRAY_SIZE; i++) {
518       sum += array[i];
519     }
520     return sum;
521   }
522 
calcArraySumLong(long[] array)523   public static long calcArraySumLong(long[] array) {
524     long sum = 0;
525     for (int i = 0; i < ARRAY_SIZE; i++) {
526       sum += array[i];
527     }
528     return sum;
529   }
530 
testSimdMultiplyAccumulate()531   public static void testSimdMultiplyAccumulate() {
532     int[] array1 = new int[ARRAY_SIZE];
533     int[] array2 = new int[ARRAY_SIZE];
534     long[] array3 = new long[ARRAY_SIZE];
535     long[] array4 = new long[ARRAY_SIZE];
536 
537     initArray(array1);
538     initArray(array2);
539     SimdMulSub(array1, array2);
540     assertIntEquals(-60608250, calcArraySum(array2));
541 
542     initArrayLong(array3);
543     initArrayLong(array4);
544     SimdMulSubLong(array3, array4);
545     assertLongEquals(-60608250, calcArraySumLong(array4));
546 
547     initArray(array1);
548     initArray(array2);
549     SimdMulAdd(array1, array2);
550     assertIntEquals(61607250, calcArraySum(array2));
551 
552     initArrayLong(array3);
553     initArrayLong(array4);
554     SimdMulAddLong(array3, array4);
555     assertLongEquals(61607250, calcArraySumLong(array4));
556   }
557 
main(String[] args)558   public static void main(String[] args) {
559     assertIntEquals(7, $opt$noinline$mulAdd(1, 2, 3));
560     assertLongEquals(-26, $opt$noinline$mulSub(4, 5, 6));
561     assertIntEquals(79, $opt$noinline$multipleUses1(7, 8, 9));
562     assertLongEquals(20, $opt$noinline$multipleUses2(10, 11, 12));
563     assertIntEquals(195, $opt$noinline$mulPlusOne(13, 14));
564     assertLongEquals(-225, $opt$noinline$mulMinusOne(15, 16));
565     assertIntEquals(-306, $opt$noinline$mulNeg(17, 18));
566     assertLongEquals(-380, $opt$noinline$mulNeg(19, 20));
567 
568     testSimdMultiplyAccumulate();
569   }
570 }
571