Home | History | Annotate | Download | only in src
      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 
     22   public static void assertIntEquals(int expected, int result) {
     23     if (expected != result) {
     24       throw new Error("Expected: " + expected + ", found: " + result);
     25     }
     26   }
     27 
     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 
     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 
    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 
    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 
    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 
    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
    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 
    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 
    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_arm64 (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_arm64 (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_arm64 (after)
    437   /// CHECK-NOT:     VecMull
    438   /// CHECK-NOT:     VecAdd
    439   public static void SimdMulAdd(int[] array1, int[] array2) {
    440     for (int j = 0; j < 100; j++) {
    441       array2[j] += 12345 * array1[j];
    442     }
    443   }
    444 
    445   /// CHECK-START-ARM64: void Main.SimdMulSub(int[], int[]) instruction_simplifier_arm64 (before)
    446   /// CHECK-DAG:     Phi                            loop:<<Loop:B\d+>> outer_loop:none
    447   /// CHECK-DAG:     VecMul                         loop:<<Loop>>      outer_loop:none
    448   /// CHECK-DAG:     VecSub                         loop:<<Loop>>      outer_loop:none
    449 
    450   /// CHECK-START-ARM64: void Main.SimdMulSub(int[], int[]) instruction_simplifier_arm64 (after)
    451   /// CHECK-DAG:     Phi                            loop:<<Loop:B\d+>> outer_loop:none
    452   /// CHECK-DAG:     VecMultiplyAccumulate kind:Sub loop:<<Loop>>      outer_loop:none
    453 
    454   /// CHECK-START-ARM64: void Main.SimdMulSub(int[], int[]) instruction_simplifier_arm64 (after)
    455   /// CHECK-NOT:     VecMull
    456   /// CHECK-NOT:     VecSub
    457   public static void SimdMulSub(int[] array1, int[] array2) {
    458     for (int j = 0; j < 100; j++) {
    459       array2[j] -= 12345 * array1[j];
    460     }
    461   }
    462 
    463   /// CHECK-START-ARM64: void Main.SimdMulMultipleUses(int[], int[]) instruction_simplifier_arm64 (before)
    464   /// CHECK-DAG:     Phi                            loop:<<Loop:B\d+>> outer_loop:none
    465   /// CHECK-DAG:     VecMul                         loop:<<Loop>>      outer_loop:none
    466   /// CHECK-DAG:     VecSub                         loop:<<Loop>>      outer_loop:none
    467 
    468   /// CHECK-START-ARM64: void Main.SimdMulMultipleUses(int[], int[]) instruction_simplifier_arm64 (after)
    469   /// CHECK-NOT: VecMultiplyAccumulate
    470   public static void SimdMulMultipleUses(int[] array1, int[] array2) {
    471     for (int j = 0; j < 100; j++) {
    472        int temp = 12345 * array1[j];
    473        array2[j] -= temp;
    474        array1[j] = temp;
    475     }
    476   }
    477 
    478   public static final int ARRAY_SIZE = 1000;
    479 
    480   public static void initArray(int[] array) {
    481     for (int i = 0; i < ARRAY_SIZE; i++) {
    482       array[i] = i;
    483     }
    484   }
    485 
    486   public static int calcArraySum(int[] array) {
    487     int sum = 0;
    488     for (int i = 0; i < ARRAY_SIZE; i++) {
    489       sum += array[i];
    490     }
    491     return sum;
    492   }
    493 
    494   public static void testSimdMultiplyAccumulate() {
    495     int[] array1 = new int[ARRAY_SIZE];
    496     int[] array2 = new int[ARRAY_SIZE];
    497 
    498     initArray(array1);
    499     initArray(array2);
    500     SimdMulSub(array1, array2);
    501     assertIntEquals(-60608250, calcArraySum(array2));
    502 
    503     initArray(array1);
    504     initArray(array2);
    505     SimdMulAdd(array1, array2);
    506     assertIntEquals(61607250, calcArraySum(array2));
    507   }
    508 
    509   public static void main(String[] args) {
    510     assertIntEquals(7, $opt$noinline$mulAdd(1, 2, 3));
    511     assertLongEquals(-26, $opt$noinline$mulSub(4, 5, 6));
    512     assertIntEquals(79, $opt$noinline$multipleUses1(7, 8, 9));
    513     assertLongEquals(20, $opt$noinline$multipleUses2(10, 11, 12));
    514     assertIntEquals(195, $opt$noinline$mulPlusOne(13, 14));
    515     assertLongEquals(-225, $opt$noinline$mulMinusOne(15, 16));
    516     assertIntEquals(-306, $opt$noinline$mulNeg(17, 18));
    517     assertLongEquals(-380, $opt$noinline$mulNeg(19, 20));
    518 
    519     testSimdMultiplyAccumulate();
    520   }
    521 }
    522