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