blob: 3493f77e758b9dfc0032d799b157711759e49234 [file] [log] [blame]
Nicolas Geoffray2e92bc22015-08-20 19:52:26 +01001/*
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
17public class Main {
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
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
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
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
169 public static void $noinline$doCall() {
Nicolas Geoffray2e92bc22015-08-20 19:52:26 +0100170 }
171
172 public static void $noinline$doCall(long e) {
Nicolas Geoffray2e92bc22015-08-20 19:52:26 +0100173 }
174
Nicolas Geoffray2e92bc22015-08-20 19:52:26 +0100175 public static int myField1;
176 public static int myField2;
177 public static int myField3;
178 public static int myField4;
179 public static int myField5;
180 public static long myLongField1;
181 public static long myLongField2;
182}