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