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   public static void assertIntEquals(int expected, int result) {
     20     if (expected != result) {
     21       throw new Error("Expected: " + expected + ", found: " + result);
     22     }
     23   }
     24 
     25   /**
     26    * Test that HArrayGet with a constant index is not split.
     27    */
     28 
     29   /// CHECK-START-ARM64: int Main.constantIndexGet(int[]) instruction_simplifier_arm64 (before)
     30   /// CHECK:             <<Array:l\d+>>         NullCheck
     31   /// CHECK:             <<Index:i\d+>>         BoundsCheck
     32   /// CHECK:                                    ArrayGet [<<Array>>,<<Index>>]
     33 
     34   /// CHECK-START-ARM64: int Main.constantIndexGet(int[]) instruction_simplifier_arm64 (after)
     35   /// CHECK:             <<Array:l\d+>>         NullCheck
     36   /// CHECK:             <<Index:i\d+>>         BoundsCheck
     37   /// CHECK-NOT:                                Arm64IntermediateAddress
     38   /// CHECK:                                    ArrayGet [<<Array>>,<<Index>>]
     39 
     40   public static int constantIndexGet(int array[]) {
     41     return array[1];
     42   }
     43 
     44   /**
     45    * Test that HArraySet with a constant index is not split.
     46    */
     47 
     48   /// CHECK-START-ARM64: void Main.constantIndexSet(int[]) instruction_simplifier_arm64 (before)
     49   /// CHECK:             <<Const2:i\d+>>        IntConstant 2
     50   /// CHECK:             <<Array:l\d+>>         NullCheck
     51   /// CHECK:             <<Index:i\d+>>         BoundsCheck
     52   /// CHECK:                                    ArraySet [<<Array>>,<<Index>>,<<Const2>>]
     53 
     54   /// CHECK-START-ARM64: void Main.constantIndexSet(int[]) instruction_simplifier_arm64 (after)
     55   /// CHECK:             <<Const2:i\d+>>        IntConstant 2
     56   /// CHECK:             <<Array:l\d+>>         NullCheck
     57   /// CHECK:             <<Index:i\d+>>         BoundsCheck
     58   /// CHECK-NOT:                                Arm64IntermediateAddress
     59   /// CHECK:                                    ArraySet [<<Array>>,<<Index>>,<<Const2>>]
     60 
     61 
     62   public static void constantIndexSet(int array[]) {
     63     array[1] = 2;
     64   }
     65 
     66   /**
     67    * Test basic splitting of HArrayGet.
     68    */
     69 
     70   /// CHECK-START-ARM64: int Main.get(int[], int) instruction_simplifier_arm64 (before)
     71   /// CHECK:             <<Array:l\d+>>         NullCheck
     72   /// CHECK:             <<Index:i\d+>>         BoundsCheck
     73   /// CHECK:                                    ArrayGet [<<Array>>,<<Index>>]
     74 
     75   /// CHECK-START-ARM64: int Main.get(int[], int) instruction_simplifier_arm64 (after)
     76   /// CHECK:             <<DataOffset:i\d+>>    IntConstant
     77   /// CHECK:             <<Array:l\d+>>         NullCheck
     78   /// CHECK:             <<Index:i\d+>>         BoundsCheck
     79   /// CHECK:             <<Address:l\d+>>       Arm64IntermediateAddress [<<Array>>,<<DataOffset>>]
     80   /// CHECK-NEXT:                               ArrayGet [<<Address>>,<<Index>>]
     81 
     82   public static int get(int array[], int index) {
     83     return array[index];
     84   }
     85 
     86   /**
     87    * Test basic splitting of HArraySet.
     88    */
     89 
     90   /// CHECK-START-ARM64: void Main.set(int[], int, int) instruction_simplifier_arm64 (before)
     91   /// CHECK:                                    ParameterValue
     92   /// CHECK:                                    ParameterValue
     93   /// CHECK:             <<Arg:i\d+>>           ParameterValue
     94   /// CHECK:             <<Array:l\d+>>         NullCheck
     95   /// CHECK:             <<Index:i\d+>>         BoundsCheck
     96   /// CHECK:                                    ArraySet [<<Array>>,<<Index>>,<<Arg>>]
     97 
     98   /// CHECK-START-ARM64: void Main.set(int[], int, int) instruction_simplifier_arm64 (after)
     99   /// CHECK:                                    ParameterValue
    100   /// CHECK:                                    ParameterValue
    101   /// CHECK:             <<Arg:i\d+>>           ParameterValue
    102   /// CHECK:             <<DataOffset:i\d+>>    IntConstant
    103   /// CHECK:             <<Array:l\d+>>         NullCheck
    104   /// CHECK:             <<Index:i\d+>>         BoundsCheck
    105   /// CHECK:             <<Address:l\d+>>       Arm64IntermediateAddress [<<Array>>,<<DataOffset>>]
    106   /// CHECK-NEXT:                               ArraySet [<<Address>>,<<Index>>,<<Arg>>]
    107 
    108   public static void set(int array[], int index, int value) {
    109     array[index] = value;
    110   }
    111 
    112   /**
    113    * Check that the intermediate address can be shared after GVN.
    114    */
    115 
    116   /// CHECK-START-ARM64: void Main.getSet(int[], int) instruction_simplifier_arm64 (before)
    117   /// CHECK:             <<Const1:i\d+>>        IntConstant 1
    118   /// CHECK:             <<Array:l\d+>>         NullCheck
    119   /// CHECK:             <<Index:i\d+>>         BoundsCheck
    120   /// CHECK:             <<ArrayGet:i\d+>>      ArrayGet [<<Array>>,<<Index>>]
    121   /// CHECK:             <<Add:i\d+>>           Add [<<ArrayGet>>,<<Const1>>]
    122   /// CHECK:                                    ArraySet [<<Array>>,<<Index>>,<<Add>>]
    123 
    124   /// CHECK-START-ARM64: void Main.getSet(int[], int) instruction_simplifier_arm64 (after)
    125   /// CHECK-DAG:         <<Const1:i\d+>>        IntConstant 1
    126   /// CHECK-DAG:         <<DataOffset:i\d+>>    IntConstant
    127   /// CHECK:             <<Array:l\d+>>         NullCheck
    128   /// CHECK:             <<Index:i\d+>>         BoundsCheck
    129   /// CHECK:             <<Address1:l\d+>>      Arm64IntermediateAddress [<<Array>>,<<DataOffset>>]
    130   /// CHECK-NEXT:        <<ArrayGet:i\d+>>      ArrayGet [<<Address1>>,<<Index>>]
    131   /// CHECK:             <<Add:i\d+>>           Add [<<ArrayGet>>,<<Const1>>]
    132   /// CHECK:             <<Address2:l\d+>>      Arm64IntermediateAddress [<<Array>>,<<DataOffset>>]
    133   /// CHECK-NEXT:                               ArraySet [<<Address2>>,<<Index>>,<<Add>>]
    134 
    135   /// CHECK-START-ARM64: void Main.getSet(int[], int) GVN_after_arch (after)
    136   /// CHECK-DAG:         <<Const1:i\d+>>        IntConstant 1
    137   /// CHECK-DAG:         <<DataOffset:i\d+>>    IntConstant
    138   /// CHECK:             <<Array:l\d+>>         NullCheck
    139   /// CHECK:             <<Index:i\d+>>         BoundsCheck
    140   /// CHECK:             <<Address:l\d+>>       Arm64IntermediateAddress [<<Array>>,<<DataOffset>>]
    141   /// CHECK:             <<ArrayGet:i\d+>>      ArrayGet [<<Address>>,<<Index>>]
    142   /// CHECK:             <<Add:i\d+>>           Add [<<ArrayGet>>,<<Const1>>]
    143   /// CHECK-NOT:                                Arm64IntermediateAddress
    144   /// CHECK:                                    ArraySet [<<Address>>,<<Index>>,<<Add>>]
    145 
    146   public static void getSet(int array[], int index) {
    147     array[index] = array[index] + 1;
    148   }
    149 
    150   /**
    151    * Check that the intermediate address computation is not reordered or merged
    152    * across IRs that can trigger GC.
    153    */
    154 
    155   /// CHECK-START-ARM64: int[] Main.accrossGC(int[], int) instruction_simplifier_arm64 (before)
    156   /// CHECK:             <<Const1:i\d+>>        IntConstant 1
    157   /// CHECK:             <<Array:l\d+>>         NullCheck
    158   /// CHECK:             <<Index:i\d+>>         BoundsCheck
    159   /// CHECK:             <<ArrayGet:i\d+>>      ArrayGet [<<Array>>,<<Index>>]
    160   /// CHECK:             <<Add:i\d+>>           Add [<<ArrayGet>>,<<Const1>>]
    161   /// CHECK:                                    NewArray
    162   /// CHECK:                                    ArraySet [<<Array>>,<<Index>>,<<Add>>]
    163 
    164   /// CHECK-START-ARM64: int[] Main.accrossGC(int[], int) instruction_simplifier_arm64 (after)
    165   /// CHECK-DAG:         <<Const1:i\d+>>        IntConstant 1
    166   /// CHECK-DAG:         <<DataOffset:i\d+>>    IntConstant
    167   /// CHECK:             <<Array:l\d+>>         NullCheck
    168   /// CHECK:             <<Index:i\d+>>         BoundsCheck
    169   /// CHECK:             <<Address1:l\d+>>      Arm64IntermediateAddress [<<Array>>,<<DataOffset>>]
    170   /// CHECK-NEXT:        <<ArrayGet:i\d+>>      ArrayGet [<<Address1>>,<<Index>>]
    171   /// CHECK:             <<Add:i\d+>>           Add [<<ArrayGet>>,<<Const1>>]
    172   /// CHECK:                                    NewArray
    173   /// CHECK:             <<Address2:l\d+>>      Arm64IntermediateAddress [<<Array>>,<<DataOffset>>]
    174   /// CHECK-NEXT:                               ArraySet [<<Address2>>,<<Index>>,<<Add>>]
    175 
    176   /// CHECK-START-ARM64: int[] Main.accrossGC(int[], int) GVN_after_arch (after)
    177   /// CHECK-DAG:         <<Const1:i\d+>>        IntConstant 1
    178   /// CHECK-DAG:         <<DataOffset:i\d+>>    IntConstant
    179   /// CHECK:             <<Array:l\d+>>         NullCheck
    180   /// CHECK:             <<Index:i\d+>>         BoundsCheck
    181   /// CHECK:             <<Address1:l\d+>>      Arm64IntermediateAddress [<<Array>>,<<DataOffset>>]
    182   /// CHECK:             <<ArrayGet:i\d+>>      ArrayGet [<<Address1>>,<<Index>>]
    183   /// CHECK:             <<Add:i\d+>>           Add [<<ArrayGet>>,<<Const1>>]
    184   /// CHECK:                                    NewArray
    185   /// CHECK:             <<Address2:l\d+>>      Arm64IntermediateAddress [<<Array>>,<<DataOffset>>]
    186   /// CHECK:                                    ArraySet [<<Address2>>,<<Index>>,<<Add>>]
    187 
    188   public static int[] accrossGC(int array[], int index) {
    189     int tmp = array[index] + 1;
    190     int[] new_array = new int[1];
    191     array[index] = tmp;
    192     return new_array;
    193   }
    194 
    195   /**
    196    * Test that the intermediate address is shared between array accesses after
    197    * the bounds check have been removed by BCE.
    198    */
    199 
    200   /// CHECK-START-ARM64: int Main.canMergeAfterBCE1() instruction_simplifier_arm64 (before)
    201   /// CHECK:             <<Const1:i\d+>>        IntConstant 1
    202   /// CHECK:             <<Array:l\d+>>         NewArray
    203   /// CHECK:             <<Index:i\d+>>         Phi
    204   /// CHECK:                                    If
    205   //  -------------- Loop
    206   /// CHECK:             <<ArrayGet:i\d+>>      ArrayGet [<<Array>>,<<Index>>]
    207   /// CHECK:             <<Add:i\d+>>           Add [<<ArrayGet>>,<<Const1>>]
    208   /// CHECK:                                    ArraySet [<<Array>>,<<Index>>,<<Add>>]
    209 
    210   // By the time we reach the architecture-specific instruction simplifier, BCE
    211   // has removed the bounds checks in the loop.
    212 
    213   // Note that we do not care that the `DataOffset` is `12`. But if we do not
    214   // specify it and any other `IntConstant` appears before that instruction,
    215   // checker will match the previous `IntConstant`, and we will thus fail the
    216   // check.
    217 
    218   /// CHECK-START-ARM64: int Main.canMergeAfterBCE1() instruction_simplifier_arm64 (after)
    219   /// CHECK-DAG:         <<Const1:i\d+>>        IntConstant 1
    220   /// CHECK-DAG:         <<DataOffset:i\d+>>    IntConstant 12
    221   /// CHECK:             <<Array:l\d+>>         NewArray
    222   /// CHECK:             <<Index:i\d+>>         Phi
    223   /// CHECK:                                    If
    224   //  -------------- Loop
    225   /// CHECK:             <<Address1:l\d+>>      Arm64IntermediateAddress [<<Array>>,<<DataOffset>>]
    226   /// CHECK-NEXT:        <<ArrayGet:i\d+>>      ArrayGet [<<Address1>>,<<Index>>]
    227   /// CHECK:             <<Add:i\d+>>           Add [<<ArrayGet>>,<<Const1>>]
    228   /// CHECK:             <<Address2:l\d+>>      Arm64IntermediateAddress [<<Array>>,<<DataOffset>>]
    229   /// CHECK-NEXT:                               ArraySet [<<Address2>>,<<Index>>,<<Add>>]
    230 
    231   /// CHECK-START-ARM64: int Main.canMergeAfterBCE1() GVN_after_arch (after)
    232   /// CHECK-DAG:         <<Const1:i\d+>>        IntConstant 1
    233   /// CHECK-DAG:         <<DataOffset:i\d+>>    IntConstant 12
    234   /// CHECK:             <<Array:l\d+>>         NewArray
    235   /// CHECK:             <<Index:i\d+>>         Phi
    236   /// CHECK:                                    If
    237   //  -------------- Loop
    238   /// CHECK:             <<Address:l\d+>>       Arm64IntermediateAddress [<<Array>>,<<DataOffset>>]
    239   /// CHECK:             <<ArrayGet:i\d+>>      ArrayGet [<<Address>>,<<Index>>]
    240   /// CHECK:             <<Add:i\d+>>           Add [<<ArrayGet>>,<<Const1>>]
    241   /// CHECK-NOT:                                Arm64IntermediateAddress
    242   /// CHECK:                                    ArraySet [<<Address>>,<<Index>>,<<Add>>]
    243 
    244   public static int canMergeAfterBCE1() {
    245     int[] array = {0, 1, 2, 3};
    246     for (int i = 0; i < array.length; i++) {
    247       array[i] = array[i] + 1;
    248     }
    249     return array[array.length - 1];
    250   }
    251 
    252   /**
    253    * This test case is similar to `canMergeAfterBCE1`, but with different
    254    * indexes for the accesses.
    255    */
    256 
    257   /// CHECK-START-ARM64: int Main.canMergeAfterBCE2() instruction_simplifier_arm64 (before)
    258   /// CHECK:             <<Const1:i\d+>>        IntConstant 1
    259   /// CHECK:             <<Array:l\d+>>         NewArray
    260   /// CHECK:             <<Index:i\d+>>         Phi
    261   /// CHECK:                                    If
    262   //  -------------- Loop
    263   /// CHECK-DAG:         <<Index1:i\d+>>        Add [<<Index>>,<<Const1>>]
    264   /// CHECK-DAG:         <<ArrayGetI:i\d+>>     ArrayGet [<<Array>>,<<Index>>]
    265   /// CHECK-DAG:         <<ArrayGetI1:i\d+>>    ArrayGet [<<Array>>,<<Index1>>]
    266   /// CHECK:             <<Add:i\d+>>           Add [<<ArrayGetI>>,<<ArrayGetI1>>]
    267   /// CHECK:                                    ArraySet [<<Array>>,<<Index1>>,<<Add>>]
    268 
    269   // Note that we do not care that the `DataOffset` is `12`. But if we do not
    270   // specify it and any other `IntConstant` appears before that instruction,
    271   // checker will match the previous `IntConstant`, and we will thus fail the
    272   // check.
    273 
    274   /// CHECK-START-ARM64: int Main.canMergeAfterBCE2() instruction_simplifier_arm64 (after)
    275   /// CHECK-DAG:         <<Const1:i\d+>>        IntConstant 1
    276   /// CHECK-DAG:         <<DataOffset:i\d+>>    IntConstant 12
    277   /// CHECK:             <<Array:l\d+>>         NewArray
    278   /// CHECK:             <<Index:i\d+>>         Phi
    279   /// CHECK:                                    If
    280   //  -------------- Loop
    281   /// CHECK-DAG:         <<Index1:i\d+>>        Add [<<Index>>,<<Const1>>]
    282   /// CHECK-DAG:         <<Address1:l\d+>>      Arm64IntermediateAddress [<<Array>>,<<DataOffset>>]
    283   /// CHECK-DAG:         <<ArrayGetI:i\d+>>     ArrayGet [<<Address1>>,<<Index>>]
    284   /// CHECK-DAG:         <<Address2:l\d+>>      Arm64IntermediateAddress [<<Array>>,<<DataOffset>>]
    285   /// CHECK-DAG:         <<ArrayGetI1:i\d+>>    ArrayGet [<<Address2>>,<<Index1>>]
    286   /// CHECK:             <<Add:i\d+>>           Add [<<ArrayGetI>>,<<ArrayGetI1>>]
    287   /// CHECK:             <<Address3:l\d+>>      Arm64IntermediateAddress [<<Array>>,<<DataOffset>>]
    288   /// CHECK:                                    ArraySet [<<Address3>>,<<Index1>>,<<Add>>]
    289 
    290   /// CHECK-START-ARM64: int Main.canMergeAfterBCE2() GVN_after_arch (after)
    291   /// CHECK-DAG:         <<Const1:i\d+>>        IntConstant 1
    292   /// CHECK-DAG:         <<DataOffset:i\d+>>    IntConstant 12
    293   /// CHECK:             <<Array:l\d+>>         NewArray
    294   /// CHECK:             <<Index:i\d+>>         Phi
    295   /// CHECK:                                    If
    296   //  -------------- Loop
    297   /// CHECK-DAG:         <<Index1:i\d+>>        Add [<<Index>>,<<Const1>>]
    298   /// CHECK-DAG:         <<Address:l\d+>>       Arm64IntermediateAddress [<<Array>>,<<DataOffset>>]
    299   /// CHECK-DAG:         <<ArrayGetI:i\d+>>     ArrayGet [<<Address>>,<<Index>>]
    300   /// CHECK-DAG:         <<ArrayGetI1:i\d+>>    ArrayGet [<<Address>>,<<Index1>>]
    301   /// CHECK:             <<Add:i\d+>>           Add [<<ArrayGetI>>,<<ArrayGetI1>>]
    302   /// CHECK:                                    ArraySet [<<Address>>,<<Index1>>,<<Add>>]
    303 
    304   // There should be only one intermediate address computation in the loop.
    305 
    306   /// CHECK-START-ARM64: int Main.canMergeAfterBCE2() GVN_after_arch (after)
    307   /// CHECK:                                    Arm64IntermediateAddress
    308   /// CHECK-NOT:                                Arm64IntermediateAddress
    309 
    310   public static int canMergeAfterBCE2() {
    311     int[] array = {0, 1, 2, 3};
    312     for (int i = 0; i < array.length - 1; i++) {
    313       array[i + 1] = array[i] + array[i + 1];
    314     }
    315     return array[array.length - 1];
    316   }
    317 
    318 
    319   public static void main(String[] args) {
    320     int[] array = {123, 456, 789};
    321 
    322     assertIntEquals(456, constantIndexGet(array));
    323 
    324     constantIndexSet(array);
    325     assertIntEquals(2, array[1]);
    326 
    327     assertIntEquals(789, get(array, 2));
    328 
    329     set(array, 1, 456);
    330     assertIntEquals(456, array[1]);
    331 
    332     getSet(array, 0);
    333     assertIntEquals(124, array[0]);
    334 
    335     accrossGC(array, 0);
    336     assertIntEquals(125, array[0]);
    337 
    338     assertIntEquals(4, canMergeAfterBCE1());
    339     assertIntEquals(6, canMergeAfterBCE2());
    340   }
    341 }
    342