ART: Change x86 long param ABI (Quick/JNI/Opt)
Ensure that we don't pass a long parameter across the last register
and the stack: skip the register and allocate it only on the stack.
This was requested to simplify the optimizing compiler code
generation for x86.
Optimizing (Baseline) compiler support for x86 longs:
- Remove QuickParameter from Location, as there are no longer any uses
of it.
Bump oat.h version because we changed an ABI again.
I changed IsParamALong() to return false for argument 0 (this argument).
I am not sure why it differed from all other tests.
I have not tested on ARM. I followed Nicolas's suggestions for setting
the value of kSplitPairAcrossRegisterAndStack for different
architectures.
Change-Id: I2f16b33c1dac58dd4f4f503e9c2309d845f5fb7a
Signed-off-by: Mark Mendell <mark.p.mendell@intel.com>
diff --git a/compiler/jni/quick/calling_convention.h b/compiler/jni/quick/calling_convention.h
index 6db0c3b..0c64a36 100644
--- a/compiler/jni/quick/calling_convention.h
+++ b/compiler/jni/quick/calling_convention.h
@@ -141,7 +141,7 @@
if (IsStatic()) {
param++; // 0th argument must skip return value at start of the shorty
} else if (param == 0) {
- return true; // this argument
+ return false; // this argument
}
return shorty_[param] == 'J';
}
diff --git a/compiler/jni/quick/x86/calling_convention_x86.cc b/compiler/jni/quick/x86/calling_convention_x86.cc
index fc72e88..8a45f0c 100644
--- a/compiler/jni/quick/x86/calling_convention_x86.cc
+++ b/compiler/jni/quick/x86/calling_convention_x86.cc
@@ -85,9 +85,19 @@
ManagedRegister res = ManagedRegister::NoRegister();
if (!IsCurrentParamAFloatOrDouble()) {
switch (gpr_arg_count_) {
- case 0: res = X86ManagedRegister::FromCpuRegister(ECX); break;
- case 1: res = X86ManagedRegister::FromCpuRegister(EDX); break;
- case 2: res = X86ManagedRegister::FromCpuRegister(EBX); break;
+ case 0:
+ res = X86ManagedRegister::FromCpuRegister(ECX);
+ break;
+ case 1:
+ res = X86ManagedRegister::FromCpuRegister(EDX);
+ break;
+ case 2:
+ // Don't split a long between the last register and the stack.
+ if (IsCurrentParamALong()) {
+ return ManagedRegister::NoRegister();
+ }
+ res = X86ManagedRegister::FromCpuRegister(EBX);
+ break;
}
} else if (itr_float_and_doubles_ < 4) {
// First four float parameters are passed via XMM0..XMM3
@@ -120,27 +130,34 @@
ResetIterator(FrameOffset(0));
while (HasNext()) {
ManagedRegister in_reg = CurrentParamRegister();
+ bool is_long = IsCurrentParamALong();
if (!in_reg.IsNoRegister()) {
int32_t size = IsParamADouble(itr_args_) ? 8 : 4;
int32_t spill_offset = CurrentParamStackOffset().Uint32Value();
ManagedRegisterSpill spill(in_reg, size, spill_offset);
entry_spills_.push_back(spill);
- if (IsCurrentParamALong() && !IsCurrentParamAReference()) { // Long.
- // special case, as we may need a second register here.
+ if (is_long) {
+ // special case, as we need a second register here.
in_reg = CurrentParamHighLongRegister();
- if (!in_reg.IsNoRegister()) {
- // We have to spill the second half of the long.
- ManagedRegisterSpill spill2(in_reg, size, spill_offset + 4);
- entry_spills_.push_back(spill2);
- // Long was allocated in 2 registers.
- gpr_arg_count_++;
- }
+ DCHECK(!in_reg.IsNoRegister());
+ // We have to spill the second half of the long.
+ ManagedRegisterSpill spill2(in_reg, size, spill_offset + 4);
+ entry_spills_.push_back(spill2);
}
// Keep track of the number of GPRs allocated.
if (!IsCurrentParamAFloatOrDouble()) {
- gpr_arg_count_++;
+ if (is_long) {
+ // Long was allocated in 2 registers.
+ gpr_arg_count_ += 2;
+ } else {
+ gpr_arg_count_++;
+ }
}
+ } else if (is_long) {
+ // We need to skip the unused last register, which is empty.
+ // If we are already out of registers, this is harmless.
+ gpr_arg_count_ += 2;
}
Next();
}