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