ART: aarch64 jni compiler needs to extend small return types
As aarch64 calling convention does not mandate extension on return
values anymore and leaves the upper bits undefined, the jni compiler
needs to sign- or zero-extend the returned values when necessary.
As three architectures need extension now, refactor this fact into a
flag into a virtual method.
Add tests to JniTest that exercise the required extension.
Change-Id: Idebb7c4dedebb852e58ade63e1c2b1eeced23104
diff --git a/compiler/jni/quick/arm/calling_convention_arm.h b/compiler/jni/quick/arm/calling_convention_arm.h
index 00a239b..604ce1c 100644
--- a/compiler/jni/quick/arm/calling_convention_arm.h
+++ b/compiler/jni/quick/arm/calling_convention_arm.h
@@ -71,6 +71,11 @@
ManagedRegister CurrentParamRegister() OVERRIDE;
FrameOffset CurrentParamStackOffset() OVERRIDE;
+ // AAPCS mandates return values are extended.
+ bool RequiresSmallResultTypeExtension() const OVERRIDE {
+ return false;
+ }
+
protected:
size_t NumberOfOutgoingStackArgs() OVERRIDE;
diff --git a/compiler/jni/quick/arm64/calling_convention_arm64.h b/compiler/jni/quick/arm64/calling_convention_arm64.h
index 92f547c..9fd3265 100644
--- a/compiler/jni/quick/arm64/calling_convention_arm64.h
+++ b/compiler/jni/quick/arm64/calling_convention_arm64.h
@@ -68,6 +68,11 @@
ManagedRegister CurrentParamRegister() OVERRIDE;
FrameOffset CurrentParamStackOffset() OVERRIDE;
+ // aarch64 calling convention leaves upper bits undefined.
+ bool RequiresSmallResultTypeExtension() const OVERRIDE {
+ return true;
+ }
+
protected:
size_t NumberOfOutgoingStackArgs() OVERRIDE;
diff --git a/compiler/jni/quick/calling_convention.h b/compiler/jni/quick/calling_convention.h
index 4d25d1c..18afd58 100644
--- a/compiler/jni/quick/calling_convention.h
+++ b/compiler/jni/quick/calling_convention.h
@@ -287,6 +287,8 @@
FrameOffset ReturnValueSaveLocation() const;
// Register that holds result if it is integer.
virtual ManagedRegister IntReturnRegister() = 0;
+ // Whether the compiler needs to ensure zero-/sign-extension of a small result type
+ virtual bool RequiresSmallResultTypeExtension() const = 0;
// Callee save registers to spill prior to native code (which may clobber)
virtual const std::vector<ManagedRegister>& CalleeSaveRegisters() const = 0;
diff --git a/compiler/jni/quick/jni_compiler.cc b/compiler/jni/quick/jni_compiler.cc
index 93b1b5a..9f439eb 100644
--- a/compiler/jni/quick/jni_compiler.cc
+++ b/compiler/jni/quick/jni_compiler.cc
@@ -314,7 +314,7 @@
mr_conv->InterproceduralScratchRegister());
// 10. Fix differences in result widths.
- if (instruction_set == kX86 || instruction_set == kX86_64) {
+ if (main_jni_conv->RequiresSmallResultTypeExtension()) {
if (main_jni_conv->GetReturnType() == Primitive::kPrimByte ||
main_jni_conv->GetReturnType() == Primitive::kPrimShort) {
__ SignExtend(main_jni_conv->ReturnRegister(),
diff --git a/compiler/jni/quick/mips/calling_convention_mips.h b/compiler/jni/quick/mips/calling_convention_mips.h
index e33fbad..8d82dce 100644
--- a/compiler/jni/quick/mips/calling_convention_mips.h
+++ b/compiler/jni/quick/mips/calling_convention_mips.h
@@ -71,6 +71,11 @@
ManagedRegister CurrentParamRegister() OVERRIDE;
FrameOffset CurrentParamStackOffset() OVERRIDE;
+ // Mips does not need to extend small return types.
+ bool RequiresSmallResultTypeExtension() const OVERRIDE {
+ return false;
+ }
+
protected:
size_t NumberOfOutgoingStackArgs() OVERRIDE;
diff --git a/compiler/jni/quick/x86/calling_convention_x86.h b/compiler/jni/quick/x86/calling_convention_x86.h
index 5b9069c..025eb6d 100644
--- a/compiler/jni/quick/x86/calling_convention_x86.h
+++ b/compiler/jni/quick/x86/calling_convention_x86.h
@@ -69,6 +69,11 @@
ManagedRegister CurrentParamRegister() OVERRIDE;
FrameOffset CurrentParamStackOffset() OVERRIDE;
+ // x86 needs to extend small return types.
+ bool RequiresSmallResultTypeExtension() const OVERRIDE {
+ return true;
+ }
+
protected:
size_t NumberOfOutgoingStackArgs() OVERRIDE;
diff --git a/compiler/jni/quick/x86_64/calling_convention_x86_64.h b/compiler/jni/quick/x86_64/calling_convention_x86_64.h
index d545774..1ba5353 100644
--- a/compiler/jni/quick/x86_64/calling_convention_x86_64.h
+++ b/compiler/jni/quick/x86_64/calling_convention_x86_64.h
@@ -69,6 +69,11 @@
ManagedRegister CurrentParamRegister() OVERRIDE;
FrameOffset CurrentParamStackOffset() OVERRIDE;
+ // x86-64 needs to extend small return types.
+ bool RequiresSmallResultTypeExtension() const OVERRIDE {
+ return true;
+ }
+
protected:
size_t NumberOfOutgoingStackArgs() OVERRIDE;
diff --git a/compiler/utils/arm64/assembler_arm64.cc b/compiler/utils/arm64/assembler_arm64.cc
index 1d87eaa..b4bb979 100644
--- a/compiler/utils/arm64/assembler_arm64.cc
+++ b/compiler/utils/arm64/assembler_arm64.cc
@@ -467,12 +467,26 @@
#endif
}
-void Arm64Assembler::SignExtend(ManagedRegister /*mreg*/, size_t /*size*/) {
- UNIMPLEMENTED(FATAL) << "no sign extension necessary for Arm64";
+void Arm64Assembler::SignExtend(ManagedRegister mreg, size_t size) {
+ Arm64ManagedRegister reg = mreg.AsArm64();
+ CHECK(size == 1 || size == 2) << size;
+ CHECK(reg.IsWRegister()) << reg;
+ if (size == 1) {
+ ___ sxtb(reg_w(reg.AsWRegister()), reg_w(reg.AsWRegister()));
+ } else {
+ ___ sxth(reg_w(reg.AsWRegister()), reg_w(reg.AsWRegister()));
+ }
}
-void Arm64Assembler::ZeroExtend(ManagedRegister /*mreg*/, size_t /*size*/) {
- UNIMPLEMENTED(FATAL) << "no zero extension necessary for Arm64";
+void Arm64Assembler::ZeroExtend(ManagedRegister mreg, size_t size) {
+ Arm64ManagedRegister reg = mreg.AsArm64();
+ CHECK(size == 1 || size == 2) << size;
+ CHECK(reg.IsWRegister()) << reg;
+ if (size == 1) {
+ ___ uxtb(reg_w(reg.AsWRegister()), reg_w(reg.AsWRegister()));
+ } else {
+ ___ uxth(reg_w(reg.AsWRegister()), reg_w(reg.AsWRegister()));
+ }
}
void Arm64Assembler::VerifyObject(ManagedRegister /*src*/, bool /*could_be_null*/) {