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 { main(String[] args)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 testOddLow1(long a )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 testNonFollowingHigh(int i)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 testOddLow2()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 $noinline$doCall()169 public static void $noinline$doCall() { 170 if (doThrow) throw new Error(); 171 } 172 $noinline$doCall(long e)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