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   public static void main(String[] args) throws Exception {
     19     if (testOddLow1(5L)) {
     20       throw new Error();
     21     }
     22 
     23     if (testNonFollowingHigh(5)) {
     24       throw new Error();
     25     }
     26 
     27     if (testOddLow2()) {
     28       throw new Error();
     29     }
     30   }
     31 
     32   public static boolean testOddLow1(long a /* ECX-EDX */) {
     33     // class instance is in EBP
     34     long b = myLongField1; // ESI-EDI
     35     int f = myField1; // EBX
     36     int e = myField2; // EAX
     37     int g = myField3; // ESI (by spilling ESI-EDI, see below)
     38     int h = myField4; // EDI
     39     myLongField2 = a; // Make sure ESI-EDI gets spilled and not ECX-EDX
     40     myField2 = f; // use of EBX
     41     myField1 = e; // use of EAX
     42     myField3 = h; // use of ESI
     43     myField4 = g; // use if EDI
     44 
     45     // At this point `b` has been spilled and needs to have a pair. The ordering
     46     // in the register allocator triggers the allocation of `res` before `b`.
     47     // `res` being used after the `doCall`, we want a callee saved register.
     48     //
     49     // EBP is taken by the class instance and EDI is taken by `g` (both used in the `myField4`
     50     // assignment below). So we end up allocating ESI for `res`.
     51     //
     52     // When we try to allocate a pair for `b` we're in the following situation:
     53     // EAX is free
     54     // ECX is taken
     55     // EDX is taken
     56     // EBX is free
     57     // ESP is blocked
     58     // EBP could be spilled
     59     // ESI is taken
     60     // EDI could be spilled
     61     //
     62     // So there is no consecutive registers available to please the register allocator.
     63     // The compiler used to trip then because of a bogus implementation of trying to split
     64     // an unaligned register pair (here ECX and EDX). The implementation would not find
     65     // a register and the register allocator would then complain about not having
     66     // enough registers for the operation.
     67     boolean res = a == b;
     68     $noinline$doCall();
     69     myField4 = g;
     70     return res;
     71   }
     72 
     73   public static boolean testNonFollowingHigh(int i) {
     74     // class instance is in EBP
     75     long b = myLongField1; // ESI-EDI
     76     long a = (long)i; // EAX-EDX
     77     int f = myField1; // EBX
     78     int e = myField2; // ECX
     79     int g = myField3; // ESI (by spilling ESI-EDI, see below)
     80     int h = myField4; // EDI
     81     myLongField2 = a; // Make sure ESI-EDI gets spilled and not ECX-EDX
     82     myField2 = f; // use of EBX
     83     myField1 = e; // use of ECX
     84     myField3 = h; // use of EDI
     85     myField4 = g; // use of ESI
     86 
     87     // At this point `b` has been spilled and needs to have a pair. The ordering
     88     // in the register allocator triggers the allocation of `res` before `b`.
     89     // `res` being used after the `doCall`, we want a callee saved register.
     90     //
     91     // EBP is taken by the class instance and ESI is taken by `g` (both used in the `myField4`
     92     // assignment below). So we end up allocating EDI for `res`.
     93     //
     94     // When we try to allocate a pair for `b` we're in the following situation:
     95     // EAX is taken
     96     // ECX is free
     97     // EDX is taken
     98     // EBX is free
     99     // ESP is blocked
    100     // EBP could be spilled
    101     // ESI is taken
    102     // EDI could be spilled
    103     //
    104     // So there is no consecutive registers available to please the register allocator.
    105     // The compiler used to be in a bad state because of a bogus implementation of trying
    106     // to split an unaligned register pair (here EAX and EDX).
    107     boolean res = a == b;
    108     $noinline$doCall();
    109     myField4 = g;
    110     return res;
    111   }
    112 
    113   public static boolean testOddLow2() {
    114     // class instance is in EBP
    115     long b = myLongField1; // ECX-EDX (hint due to call below).
    116     long a = myLongField2; // ESI-EDI
    117     int f = myField1; // EBX
    118     int e = myField2; // EAX
    119     int g = myField3; // ECX
    120     int h = myField4; // EDX
    121     int i = myField5; // ESI - callee saved due to assignment after call to $noinline$doCall.
    122     myField2 = f; // use of EBX
    123     myField1 = e; // use of EAX
    124     myField3 = h; // use of EDX
    125     myField4 = i; // use of ESI
    126     myField5 = g; // use of ECX
    127 
    128     // At this point `a` and `b` have been spilled and need to have a pairs. The ordering
    129     // in the register allocator triggers the allocation of `res` before `a` and `b`.
    130     // `res` being used after the `doCall`, we want a callee saved register.
    131     //
    132     // EBP is taken by the class instance and ESI is taken by `i` (both used in the `myField4`
    133     // assignment below). So we end up allocating EDI for `res`.
    134     //
    135     // We first try to allocator a pair for `b`. We're in the following situation:
    136     // EAX is free
    137     // ECX is free
    138     // EDX is free
    139     // EBX is free
    140     // ESP is blocked
    141     // EBP could be spilled
    142     // ESI could be spilled
    143     // EDI is taken
    144     //
    145     // Because `b` is used as a first argument to a call, we take its hint and allocate
    146     // ECX-EDX to it.
    147     //
    148     // We then try to allocate a pair for `a`. We're in the following situation:
    149     // EAX is free
    150     // ECX could be spilled
    151     // EDX could be spilled
    152     // EBX is free
    153     // ESP is blocked
    154     // EBP could be spilled
    155     // ESI could be spilled
    156     // EDI is taken
    157     //
    158     // So no consecutive two free registers are available. When trying to find a slot, we pick
    159     // the first unaligned or non-pair interval. In this case, this is the unaligned ECX-EDX.
    160     // The compiler used to then trip because it forgot to remove the high interval containing
    161     // the pair from the active list.
    162 
    163     boolean res = a == b;
    164     $noinline$doCall(b);
    165     myField4 = i; // use of ESI
    166     return res;
    167   }
    168 
    169   public static void $noinline$doCall() {
    170     if (doThrow) throw new Error();
    171   }
    172 
    173   public static void $noinline$doCall(long e) {
    174     if (doThrow) throw new Error();
    175   }
    176 
    177   public static boolean doThrow;
    178   public static int myField1;
    179   public static int myField2;
    180   public static int myField3;
    181   public static int myField4;
    182   public static int myField5;
    183   public static long myLongField1;
    184   public static long myLongField2;
    185 }
    186