Fix unaligned Memory peek/poke intrinsics.
Change-Id: Id454464d0b28aa37f5239f1c6589ceb0b3bbbdea
diff --git a/compiler/dex/quick/arm/codegen_arm.h b/compiler/dex/quick/arm/codegen_arm.h
index 0a3bfc1..15355be 100644
--- a/compiler/dex/quick/arm/codegen_arm.h
+++ b/compiler/dex/quick/arm/codegen_arm.h
@@ -107,6 +107,8 @@
bool GenInlinedCas32(CallInfo* info, bool need_write_barrier);
bool GenInlinedMinMaxInt(CallInfo* info, bool is_min);
bool GenInlinedSqrt(CallInfo* info);
+ bool GenInlinedPeek(CallInfo* info, OpSize size);
+ bool GenInlinedPoke(CallInfo* info, OpSize size);
void GenNegLong(RegLocation rl_dest, RegLocation rl_src);
void GenOrLong(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
void GenSubLong(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
diff --git a/compiler/dex/quick/arm/int_arm.cc b/compiler/dex/quick/arm/int_arm.cc
index c3140a5..0a8cbf9 100644
--- a/compiler/dex/quick/arm/int_arm.cc
+++ b/compiler/dex/quick/arm/int_arm.cc
@@ -493,6 +493,50 @@
return true;
}
+bool ArmMir2Lir::GenInlinedPeek(CallInfo* info, OpSize size) {
+ RegLocation rl_src_address = info->args[0]; // long address
+ rl_src_address.wide = 0; // ignore high half in info->args[1]
+ RegLocation rl_dest = InlineTarget(info);
+ RegLocation rl_address = LoadValue(rl_src_address, kCoreReg);
+ RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
+ if (size == kLong) {
+ // Fake unaligned LDRD by two unaligned LDR instructions on ARMv7 with SCTLR.A set to 0.
+ if (rl_address.low_reg != rl_result.low_reg) {
+ LoadBaseDisp(rl_address.low_reg, 0, rl_result.low_reg, kWord, INVALID_SREG);
+ LoadBaseDisp(rl_address.low_reg, 4, rl_result.high_reg, kWord, INVALID_SREG);
+ } else {
+ LoadBaseDisp(rl_address.low_reg, 4, rl_result.high_reg, kWord, INVALID_SREG);
+ LoadBaseDisp(rl_address.low_reg, 0, rl_result.low_reg, kWord, INVALID_SREG);
+ }
+ StoreValueWide(rl_dest, rl_result);
+ } else {
+ DCHECK(size == kSignedByte || size == kSignedHalf || size == kWord);
+ // Unaligned load with LDR and LDRSH is allowed on ARMv7 with SCTLR.A set to 0.
+ LoadBaseDisp(rl_address.low_reg, 0, rl_result.low_reg, size, INVALID_SREG);
+ StoreValue(rl_dest, rl_result);
+ }
+ return true;
+}
+
+bool ArmMir2Lir::GenInlinedPoke(CallInfo* info, OpSize size) {
+ RegLocation rl_src_address = info->args[0]; // long address
+ rl_src_address.wide = 0; // ignore high half in info->args[1]
+ RegLocation rl_src_value = info->args[2]; // [size] value
+ RegLocation rl_address = LoadValue(rl_src_address, kCoreReg);
+ if (size == kLong) {
+ // Fake unaligned STRD by two unaligned STR instructions on ARMv7 with SCTLR.A set to 0.
+ RegLocation rl_value = LoadValueWide(rl_src_value, kCoreReg);
+ StoreBaseDisp(rl_address.low_reg, 0, rl_value.low_reg, kWord);
+ StoreBaseDisp(rl_address.low_reg, 4, rl_value.high_reg, kWord);
+ } else {
+ DCHECK(size == kSignedByte || size == kSignedHalf || size == kWord);
+ // Unaligned store with STR and STRSH is allowed on ARMv7 with SCTLR.A set to 0.
+ RegLocation rl_value = LoadValue(rl_src_value, kCoreReg);
+ StoreBaseDisp(rl_address.low_reg, 0, rl_value.low_reg, size);
+ }
+ return true;
+}
+
void ArmMir2Lir::OpLea(int rBase, int reg1, int reg2, int scale, int offset) {
LOG(FATAL) << "Unexpected use of OpLea for Arm";
}
diff --git a/compiler/dex/quick/gen_invoke.cc b/compiler/dex/quick/gen_invoke.cc
index e7bbb04..7225262 100644
--- a/compiler/dex/quick/gen_invoke.cc
+++ b/compiler/dex/quick/gen_invoke.cc
@@ -1161,39 +1161,6 @@
return true;
}
-bool Mir2Lir::GenInlinedPeek(CallInfo* info, OpSize size) {
- RegLocation rl_src_address = info->args[0]; // long address
- rl_src_address.wide = 0; // ignore high half in info->args[1]
- RegLocation rl_dest = InlineTarget(info);
- RegLocation rl_address = LoadValue(rl_src_address, kCoreReg);
- RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
- if (size == kLong) {
- LoadBaseDispWide(rl_address.low_reg, 0, rl_result.low_reg, rl_result.high_reg, INVALID_SREG);
- StoreValueWide(rl_dest, rl_result);
- } else {
- DCHECK(size == kSignedByte || size == kSignedHalf || size == kWord);
- LoadBaseDisp(rl_address.low_reg, 0, rl_result.low_reg, size, INVALID_SREG);
- StoreValue(rl_dest, rl_result);
- }
- return true;
-}
-
-bool Mir2Lir::GenInlinedPoke(CallInfo* info, OpSize size) {
- RegLocation rl_src_address = info->args[0]; // long address
- rl_src_address.wide = 0; // ignore high half in info->args[1]
- RegLocation rl_src_value = info->args[2]; // [size] value
- RegLocation rl_address = LoadValue(rl_src_address, kCoreReg);
- if (size == kLong) {
- RegLocation rl_value = LoadValueWide(rl_src_value, kCoreReg);
- StoreBaseDispWide(rl_address.low_reg, 0, rl_value.low_reg, rl_value.high_reg);
- } else {
- DCHECK(size == kSignedByte || size == kSignedHalf || size == kWord);
- RegLocation rl_value = LoadValue(rl_src_value, kCoreReg);
- StoreBaseDisp(rl_address.low_reg, 0, rl_value.low_reg, size);
- }
- return true;
-}
-
bool Mir2Lir::GenInlinedUnsafeGet(CallInfo* info,
bool is_long, bool is_volatile) {
if (cu_->instruction_set == kMips) {
diff --git a/compiler/dex/quick/mips/codegen_mips.h b/compiler/dex/quick/mips/codegen_mips.h
index 0be20e8..88b244b 100644
--- a/compiler/dex/quick/mips/codegen_mips.h
+++ b/compiler/dex/quick/mips/codegen_mips.h
@@ -107,6 +107,8 @@
bool GenInlinedCas32(CallInfo* info, bool need_write_barrier);
bool GenInlinedMinMaxInt(CallInfo* info, bool is_min);
bool GenInlinedSqrt(CallInfo* info);
+ bool GenInlinedPeek(CallInfo* info, OpSize size);
+ bool GenInlinedPoke(CallInfo* info, OpSize size);
void GenNegLong(RegLocation rl_dest, RegLocation rl_src);
void GenOrLong(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
void GenSubLong(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
diff --git a/compiler/dex/quick/mips/int_mips.cc b/compiler/dex/quick/mips/int_mips.cc
index 02ab04e..5229429 100644
--- a/compiler/dex/quick/mips/int_mips.cc
+++ b/compiler/dex/quick/mips/int_mips.cc
@@ -268,6 +268,37 @@
return false;
}
+bool MipsMir2Lir::GenInlinedPeek(CallInfo* info, OpSize size) {
+ if (size != kSignedByte) {
+ // MIPS supports only aligned access. Defer unaligned access to JNI implementation.
+ return false;
+ }
+ RegLocation rl_src_address = info->args[0]; // long address
+ rl_src_address.wide = 0; // ignore high half in info->args[1]
+ RegLocation rl_dest = InlineTarget(info);
+ RegLocation rl_address = LoadValue(rl_src_address, kCoreReg);
+ RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
+ DCHECK(size == kSignedByte);
+ LoadBaseDisp(rl_address.low_reg, 0, rl_result.low_reg, size, INVALID_SREG);
+ StoreValue(rl_dest, rl_result);
+ return true;
+}
+
+bool MipsMir2Lir::GenInlinedPoke(CallInfo* info, OpSize size) {
+ if (size != kSignedByte) {
+ // MIPS supports only aligned access. Defer unaligned access to JNI implementation.
+ return false;
+ }
+ RegLocation rl_src_address = info->args[0]; // long address
+ rl_src_address.wide = 0; // ignore high half in info->args[1]
+ RegLocation rl_src_value = info->args[2]; // [size] value
+ RegLocation rl_address = LoadValue(rl_src_address, kCoreReg);
+ DCHECK(size == kSignedByte);
+ RegLocation rl_value = LoadValue(rl_src_value, kCoreReg);
+ StoreBaseDisp(rl_address.low_reg, 0, rl_value.low_reg, size);
+ return true;
+}
+
LIR* MipsMir2Lir::OpPcRelLoad(int reg, LIR* target) {
LOG(FATAL) << "Unexpected use of OpPcRelLoad for Mips";
return NULL;
diff --git a/compiler/dex/quick/mir_to_lir.h b/compiler/dex/quick/mir_to_lir.h
index 0c2a70c..4c56b74 100644
--- a/compiler/dex/quick/mir_to_lir.h
+++ b/compiler/dex/quick/mir_to_lir.h
@@ -552,8 +552,6 @@
bool GenInlinedIndexOf(CallInfo* info, bool zero_based);
bool GenInlinedStringCompareTo(CallInfo* info);
bool GenInlinedCurrentThread(CallInfo* info);
- bool GenInlinedPeek(CallInfo* info, OpSize size);
- bool GenInlinedPoke(CallInfo* info, OpSize size);
bool GenInlinedUnsafeGet(CallInfo* info, bool is_long, bool is_volatile);
bool GenInlinedUnsafePut(CallInfo* info, bool is_long, bool is_object,
bool is_volatile, bool is_ordered);
@@ -666,6 +664,8 @@
virtual bool GenInlinedCas32(CallInfo* info, bool need_write_barrier) = 0;
virtual bool GenInlinedMinMaxInt(CallInfo* info, bool is_min) = 0;
virtual bool GenInlinedSqrt(CallInfo* info) = 0;
+ virtual bool GenInlinedPeek(CallInfo* info, OpSize size) = 0;
+ virtual bool GenInlinedPoke(CallInfo* info, OpSize size) = 0;
virtual void GenNegLong(RegLocation rl_dest, RegLocation rl_src) = 0;
virtual void GenOrLong(RegLocation rl_dest, RegLocation rl_src1,
RegLocation rl_src2) = 0;
diff --git a/compiler/dex/quick/x86/codegen_x86.h b/compiler/dex/quick/x86/codegen_x86.h
index b28d7ef..1d6509e 100644
--- a/compiler/dex/quick/x86/codegen_x86.h
+++ b/compiler/dex/quick/x86/codegen_x86.h
@@ -107,6 +107,8 @@
bool GenInlinedCas32(CallInfo* info, bool need_write_barrier);
bool GenInlinedMinMaxInt(CallInfo* info, bool is_min);
bool GenInlinedSqrt(CallInfo* info);
+ bool GenInlinedPeek(CallInfo* info, OpSize size);
+ bool GenInlinedPoke(CallInfo* info, OpSize size);
void GenNegLong(RegLocation rl_dest, RegLocation rl_src);
void GenOrLong(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
void GenSubLong(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
diff --git a/compiler/dex/quick/x86/int_x86.cc b/compiler/dex/quick/x86/int_x86.cc
index 3fbc763..499547b 100644
--- a/compiler/dex/quick/x86/int_x86.cc
+++ b/compiler/dex/quick/x86/int_x86.cc
@@ -236,6 +236,43 @@
return true;
}
+bool X86Mir2Lir::GenInlinedPeek(CallInfo* info, OpSize size) {
+ RegLocation rl_src_address = info->args[0]; // long address
+ rl_src_address.wide = 0; // ignore high half in info->args[1]
+ RegLocation rl_dest = InlineTarget(info);
+ RegLocation rl_address = LoadValue(rl_src_address, kCoreReg);
+ RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
+ if (size == kLong) {
+ // Unaligned access is allowed on x86.
+ LoadBaseDispWide(rl_address.low_reg, 0, rl_result.low_reg, rl_result.high_reg, INVALID_SREG);
+ StoreValueWide(rl_dest, rl_result);
+ } else {
+ DCHECK(size == kSignedByte || size == kSignedHalf || size == kWord);
+ // Unaligned access is allowed on x86.
+ LoadBaseDisp(rl_address.low_reg, 0, rl_result.low_reg, size, INVALID_SREG);
+ StoreValue(rl_dest, rl_result);
+ }
+ return true;
+}
+
+bool X86Mir2Lir::GenInlinedPoke(CallInfo* info, OpSize size) {
+ RegLocation rl_src_address = info->args[0]; // long address
+ rl_src_address.wide = 0; // ignore high half in info->args[1]
+ RegLocation rl_src_value = info->args[2]; // [size] value
+ RegLocation rl_address = LoadValue(rl_src_address, kCoreReg);
+ if (size == kLong) {
+ // Unaligned access is allowed on x86.
+ RegLocation rl_value = LoadValueWide(rl_src_value, kCoreReg);
+ StoreBaseDispWide(rl_address.low_reg, 0, rl_value.low_reg, rl_value.high_reg);
+ } else {
+ DCHECK(size == kSignedByte || size == kSignedHalf || size == kWord);
+ // Unaligned access is allowed on x86.
+ RegLocation rl_value = LoadValue(rl_src_value, kCoreReg);
+ StoreBaseDisp(rl_address.low_reg, 0, rl_value.low_reg, size);
+ }
+ return true;
+}
+
void X86Mir2Lir::OpLea(int rBase, int reg1, int reg2, int scale, int offset) {
NewLIR5(kX86Lea32RA, rBase, reg1, reg2, scale, offset);
}