content: /*
   * Copyright (C) 2015 The Android Open Source Project
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *
   *      http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  
  public class Main  {
    public static void main(String[] args) throws Exception {
      if (testOddLow1(5L)) {
        throw new Error();
      }
  
      if (testNonFollowingHigh(5)) {
        throw new Error();
      }
  
      if (testOddLow2()) {
        throw new Error();
      }
    }
  
    public static boolean testOddLow1(long a /* ECX-EDX */) {
      // class instance is in EBP
      long b = myLongField1; // ESI-EDI
      int f = myField1; // EBX
      int e = myField2; // EAX
      int g = myField3; // ESI (by spilling ESI-EDI, see below)
      int h = myField4; // EDI
      myLongField2 = a; // Make sure ESI-EDI gets spilled and not ECX-EDX
      myField2 = f; // use of EBX
      myField1 = e; // use of EAX
      myField3 = h; // use of ESI
      myField4 = g; // use if EDI
  
      // At this point `b` has been spilled and needs to have a pair. The ordering
      // in the register allocator triggers the allocation of `res` before `b`.
      // `res` being used after the `doCall`, we want a callee saved register.
      //
      // EBP is taken by the class instance and EDI is taken by `g` (both used in the `myField4`
      // assignment below). So we end up allocating ESI for `res`.
      //
      // When we try to allocate a pair for `b` we're in the following situation:
      // EAX is free
      // ECX is taken
      // EDX is taken
      // EBX is free
      // ESP is blocked
      // EBP could be spilled
      // ESI is taken
      // EDI could be spilled
      //
      // So there is no consecutive registers available to please the register allocator.
      // The compiler used to trip then because of a bogus implementation of trying to split
      // an unaligned register pair (here ECX and EDX). The implementation would not find
      // a register and the register allocator would then complain about not having
      // enough registers for the operation.
      boolean res = a == b;
      $noinline$doCall();
      myField4 = g;
      return res;
    }
  
    public static boolean testNonFollowingHigh(int i) {
      // class instance is in EBP
      long b = myLongField1; // ESI-EDI
      long a = (long)i; // EAX-EDX
      int f = myField1; // EBX
      int e = myField2; // ECX
      int g = myField3; // ESI (by spilling ESI-EDI, see below)
      int h = myField4; // EDI
      myLongField2 = a; // Make sure ESI-EDI gets spilled and not ECX-EDX
      myField2 = f; // use of EBX
      myField1 = e; // use of ECX
      myField3 = h; // use of EDI
      myField4 = g; // use of ESI
  
      // At this point `b` has been spilled and needs to have a pair. The ordering
      // in the register allocator triggers the allocation of `res` before `b`.
      // `res` being used after the `doCall`, we want a callee saved register.
      //
      // EBP is taken by the class instance and ESI is taken by `g` (both used in the `myField4`
      // assignment below). So we end up allocating EDI for `res`.
      //
      // When we try to allocate a pair for `b` we're in the following situation:
      // EAX is taken
      // ECX is free
      // EDX is taken
      // EBX is free
      // ESP is blocked
      // EBP could be spilled
      // ESI is taken
      // EDI could be spilled
      //
      // So there is no consecutive registers available to please the register allocator.
      // The compiler used to be in a bad state because of a bogus implementation of trying
      // to split an unaligned register pair (here EAX and EDX).
      boolean res = a == b;
      $noinline$doCall();
      myField4 = g;
      return res;
    }
  
    public static boolean testOddLow2() {
      // class instance is in EBP
      long b = myLongField1; // ECX-EDX (hint due to call below).
      long a = myLongField2; // ESI-EDI
      int f = myField1; // EBX
      int e = myField2; // EAX
      int g = myField3; // ECX
      int h = myField4; // EDX
      int i = myField5; // ESI - callee saved due to assignment after call to $noinline$doCall.
      myField2 = f; // use of EBX
      myField1 = e; // use of EAX
      myField3 = h; // use of EDX
      myField4 = i; // use of ESI
      myField5 = g; // use of ECX
  
      // At this point `a` and `b` have been spilled and need to have a pairs. The ordering
      // in the register allocator triggers the allocation of `res` before `a` and `b`.
      // `res` being used after the `doCall`, we want a callee saved register.
      //
      // EBP is taken by the class instance and ESI is taken by `i` (both used in the `myField4`
      // assignment below). So we end up allocating EDI for `res`.
      //
      // We first try to allocator a pair for `b`. We're in the following situation:
      // EAX is free
      // ECX is free
      // EDX is free
      // EBX is free
      // ESP is blocked
      // EBP could be spilled
      // ESI could be spilled
      // EDI is taken
      //
      // Because `b` is used as a first argument to a call, we take its hint and allocate
      // ECX-EDX to it.
      //
      // We then try to allocate a pair for `a`. We're in the following situation:
      // EAX is free
      // ECX could be spilled
      // EDX could be spilled
      // EBX is free
      // ESP is blocked
      // EBP could be spilled
      // ESI could be spilled
      // EDI is taken
      //
      // So no consecutive two free registers are available. When trying to find a slot, we pick
      // the first unaligned or non-pair interval. In this case, this is the unaligned ECX-EDX.
      // The compiler used to then trip because it forgot to remove the high interval containing
      // the pair from the active list.
  
      boolean res = a == b;
      $noinline$doCall(b);
      myField4 = i; // use of ESI
      return res;
    }
  
    public static void $noinline$doCall() {
      if (doThrow) throw new Error();
    }
  
    public static void $noinline$doCall(long e) {
      if (doThrow) throw new Error();
    }
  
    public static boolean doThrow;
    public static int myField1;
    public static int myField2;
    public static int myField3;
    public static int myField4;
    public static int myField5;
    public static long myLongField1;
    public static long myLongField2;
  }
  