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