/* * 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; }