summaryrefslogtreecommitdiffstats
path: root/compiler/dex/quick
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/dex/quick')
-rw-r--r--compiler/dex/quick/arm/codegen_arm.h2
-rw-r--r--compiler/dex/quick/arm/utility_arm.cc10
-rw-r--r--compiler/dex/quick/gen_invoke.cc163
-rw-r--r--compiler/dex/quick/mips/codegen_mips.h2
-rw-r--r--compiler/dex/quick/mips/utility_mips.cc10
-rw-r--r--compiler/dex/quick/mir_to_lir.h21
-rw-r--r--compiler/dex/quick/x86/assemble_x86.cc18
-rw-r--r--compiler/dex/quick/x86/codegen_x86.h2
-rw-r--r--compiler/dex/quick/x86/utility_x86.cc104
-rw-r--r--compiler/dex/quick/x86/x86_lir.h8
10 files changed, 310 insertions, 30 deletions
diff --git a/compiler/dex/quick/arm/codegen_arm.h b/compiler/dex/quick/arm/codegen_arm.h
index 32673db41e..0ed4576e80 100644
--- a/compiler/dex/quick/arm/codegen_arm.h
+++ b/compiler/dex/quick/arm/codegen_arm.h
@@ -154,6 +154,8 @@ class ArmMir2Lir : public Mir2Lir {
LIR* OpRegImm(OpKind op, int r_dest_src1, int value);
LIR* OpRegMem(OpKind op, int r_dest, int rBase, int offset);
LIR* OpRegReg(OpKind op, int r_dest_src1, int r_src2);
+ LIR* OpMovRegMem(int r_dest, int r_base, int offset, MoveType move_type);
+ LIR* OpMovMemReg(int r_base, int offset, int r_src, MoveType move_type);
LIR* OpCondRegReg(OpKind op, ConditionCode cc, int r_dest, int r_src);
LIR* OpRegRegImm(OpKind op, int r_dest, int r_src1, int value);
LIR* OpRegRegReg(OpKind op, int r_dest, int r_src1, int r_src2);
diff --git a/compiler/dex/quick/arm/utility_arm.cc b/compiler/dex/quick/arm/utility_arm.cc
index 07fc6c790d..9d3968bff2 100644
--- a/compiler/dex/quick/arm/utility_arm.cc
+++ b/compiler/dex/quick/arm/utility_arm.cc
@@ -367,6 +367,16 @@ LIR* ArmMir2Lir::OpRegReg(OpKind op, int r_dest_src1, int r_src2) {
return OpRegRegShift(op, r_dest_src1, r_src2, 0);
}
+LIR* ArmMir2Lir::OpMovRegMem(int r_dest, int r_base, int offset, MoveType move_type) {
+ UNIMPLEMENTED(FATAL);
+ return nullptr;
+}
+
+LIR* ArmMir2Lir::OpMovMemReg(int r_base, int offset, int r_src, MoveType move_type) {
+ UNIMPLEMENTED(FATAL);
+ return nullptr;
+}
+
LIR* ArmMir2Lir::OpCondRegReg(OpKind op, ConditionCode cc, int r_dest, int r_src) {
LOG(FATAL) << "Unexpected use of OpCondRegReg for Arm";
return NULL;
diff --git a/compiler/dex/quick/gen_invoke.cc b/compiler/dex/quick/gen_invoke.cc
index 3823fb31d4..6382dd6608 100644
--- a/compiler/dex/quick/gen_invoke.cc
+++ b/compiler/dex/quick/gen_invoke.cc
@@ -811,42 +811,145 @@ int Mir2Lir::GenDalvikArgsRange(CallInfo* info, int call_state,
}
}
+ // Logic below assumes that Method pointer is at offset zero from SP.
+ DCHECK_EQ(VRegOffset(static_cast<int>(kVRegMethodPtrBaseReg)), 0);
+
+ // The first 3 arguments are passed via registers.
+ // TODO: For 64-bit, instead of hardcoding 4 for Method* size, we should either
+ // get size of uintptr_t or size of object reference according to model being used.
+ int outs_offset = 4 /* Method* */ + (3 * sizeof(uint32_t));
int start_offset = SRegOffset(info->args[3].s_reg_low);
- int outs_offset = 4 /* Method* */ + (3 * 4);
- if (cu_->instruction_set != kThumb2) {
+ int regs_left_to_pass_via_stack = info->num_arg_words - 3;
+ DCHECK_GT(regs_left_to_pass_via_stack, 0);
+
+ if (cu_->instruction_set == kThumb2 && regs_left_to_pass_via_stack <= 16) {
+ // Use vldm/vstm pair using kArg3 as a temp
+ call_state = next_call_insn(cu_, info, call_state, target_method, vtable_idx,
+ direct_code, direct_method, type);
+ OpRegRegImm(kOpAdd, TargetReg(kArg3), TargetReg(kSp), start_offset);
+ LIR* ld = OpVldm(TargetReg(kArg3), regs_left_to_pass_via_stack);
+ // TUNING: loosen barrier
+ ld->u.m.def_mask = ENCODE_ALL;
+ SetMemRefType(ld, true /* is_load */, kDalvikReg);
+ call_state = next_call_insn(cu_, info, call_state, target_method, vtable_idx,
+ direct_code, direct_method, type);
+ OpRegRegImm(kOpAdd, TargetReg(kArg3), TargetReg(kSp), 4 /* Method* */ + (3 * 4));
+ call_state = next_call_insn(cu_, info, call_state, target_method, vtable_idx,
+ direct_code, direct_method, type);
+ LIR* st = OpVstm(TargetReg(kArg3), regs_left_to_pass_via_stack);
+ SetMemRefType(st, false /* is_load */, kDalvikReg);
+ st->u.m.def_mask = ENCODE_ALL;
+ call_state = next_call_insn(cu_, info, call_state, target_method, vtable_idx,
+ direct_code, direct_method, type);
+ } else if (cu_->instruction_set == kX86) {
+ int current_src_offset = start_offset;
+ int current_dest_offset = outs_offset;
+
+ while (regs_left_to_pass_via_stack > 0) {
+ // This is based on the knowledge that the stack itself is 16-byte aligned.
+ bool src_is_16b_aligned = (current_src_offset & 0xF) == 0;
+ bool dest_is_16b_aligned = (current_dest_offset & 0xF) == 0;
+ size_t bytes_to_move;
+
+ /*
+ * The amount to move defaults to 32-bit. If there are 4 registers left to move, then do a
+ * a 128-bit move because we won't get the chance to try to aligned. If there are more than
+ * 4 registers left to move, consider doing a 128-bit only if either src or dest are aligned.
+ * We do this because we could potentially do a smaller move to align.
+ */
+ if (regs_left_to_pass_via_stack == 4 ||
+ (regs_left_to_pass_via_stack > 4 && (src_is_16b_aligned || dest_is_16b_aligned))) {
+ // Moving 128-bits via xmm register.
+ bytes_to_move = sizeof(uint32_t) * 4;
+
+ // Allocate a free xmm temp. Since we are working through the calling sequence,
+ // we expect to have an xmm temporary available.
+ int temp = AllocTempDouble();
+ CHECK_GT(temp, 0);
+
+ LIR* ld1 = nullptr;
+ LIR* ld2 = nullptr;
+ LIR* st1 = nullptr;
+ LIR* st2 = nullptr;
+
+ /*
+ * The logic is similar for both loads and stores. If we have 16-byte alignment,
+ * do an aligned move. If we have 8-byte alignment, then do the move in two
+ * parts. This approach prevents possible cache line splits. Finally, fall back
+ * to doing an unaligned move. In most cases we likely won't split the cache
+ * line but we cannot prove it and thus take a conservative approach.
+ */
+ bool src_is_8b_aligned = (current_src_offset & 0x7) == 0;
+ bool dest_is_8b_aligned = (current_dest_offset & 0x7) == 0;
+
+ if (src_is_16b_aligned) {
+ ld1 = OpMovRegMem(temp, TargetReg(kSp), current_src_offset, kMovA128FP);
+ } else if (src_is_8b_aligned) {
+ ld1 = OpMovRegMem(temp, TargetReg(kSp), current_src_offset, kMovLo128FP);
+ ld2 = OpMovRegMem(temp, TargetReg(kSp), current_src_offset + (bytes_to_move >> 1), kMovHi128FP);
+ } else {
+ ld1 = OpMovRegMem(temp, TargetReg(kSp), current_src_offset, kMovU128FP);
+ }
+
+ if (dest_is_16b_aligned) {
+ st1 = OpMovMemReg(TargetReg(kSp), current_dest_offset, temp, kMovA128FP);
+ } else if (dest_is_8b_aligned) {
+ st1 = OpMovMemReg(TargetReg(kSp), current_dest_offset, temp, kMovLo128FP);
+ st2 = OpMovMemReg(TargetReg(kSp), current_dest_offset + (bytes_to_move >> 1), temp, kMovHi128FP);
+ } else {
+ st1 = OpMovMemReg(TargetReg(kSp), current_dest_offset, temp, kMovU128FP);
+ }
+
+ // TODO If we could keep track of aliasing information for memory accesses that are wider
+ // than 64-bit, we wouldn't need to set up a barrier.
+ if (ld1 != nullptr) {
+ if (ld2 != nullptr) {
+ // For 64-bit load we can actually set up the aliasing information.
+ AnnotateDalvikRegAccess(ld1, current_src_offset >> 2, true, true);
+ AnnotateDalvikRegAccess(ld2, (current_src_offset + (bytes_to_move >> 1)) >> 2, true, true);
+ } else {
+ // Set barrier for 128-bit load.
+ SetMemRefType(ld1, true /* is_load */, kDalvikReg);
+ ld1->u.m.def_mask = ENCODE_ALL;
+ }
+ }
+ if (st1 != nullptr) {
+ if (st2 != nullptr) {
+ // For 64-bit store we can actually set up the aliasing information.
+ AnnotateDalvikRegAccess(st1, current_dest_offset >> 2, false, true);
+ AnnotateDalvikRegAccess(st2, (current_dest_offset + (bytes_to_move >> 1)) >> 2, false, true);
+ } else {
+ // Set barrier for 128-bit store.
+ SetMemRefType(st1, false /* is_load */, kDalvikReg);
+ st1->u.m.def_mask = ENCODE_ALL;
+ }
+ }
+
+ // Free the temporary used for the data movement.
+ FreeTemp(temp);
+ } else {
+ // Moving 32-bits via general purpose register.
+ bytes_to_move = sizeof(uint32_t);
+
+ // Instead of allocating a new temp, simply reuse one of the registers being used
+ // for argument passing.
+ int temp = TargetReg(kArg3);
+
+ // Now load the argument VR and store to the outs.
+ LoadWordDisp(TargetReg(kSp), current_src_offset, temp);
+ StoreWordDisp(TargetReg(kSp), current_dest_offset, temp);
+ }
+
+ current_src_offset += bytes_to_move;
+ current_dest_offset += bytes_to_move;
+ regs_left_to_pass_via_stack -= (bytes_to_move >> 2);
+ }
+ } else {
// Generate memcpy
OpRegRegImm(kOpAdd, TargetReg(kArg0), TargetReg(kSp), outs_offset);
OpRegRegImm(kOpAdd, TargetReg(kArg1), TargetReg(kSp), start_offset);
CallRuntimeHelperRegRegImm(QUICK_ENTRYPOINT_OFFSET(pMemcpy), TargetReg(kArg0),
TargetReg(kArg1), (info->num_arg_words - 3) * 4, false);
- } else {
- if (info->num_arg_words >= 20) {
- // Generate memcpy
- OpRegRegImm(kOpAdd, TargetReg(kArg0), TargetReg(kSp), outs_offset);
- OpRegRegImm(kOpAdd, TargetReg(kArg1), TargetReg(kSp), start_offset);
- CallRuntimeHelperRegRegImm(QUICK_ENTRYPOINT_OFFSET(pMemcpy), TargetReg(kArg0),
- TargetReg(kArg1), (info->num_arg_words - 3) * 4, false);
- } else {
- // Use vldm/vstm pair using kArg3 as a temp
- int regs_left = std::min(info->num_arg_words - 3, 16);
- call_state = next_call_insn(cu_, info, call_state, target_method, vtable_idx,
- direct_code, direct_method, type);
- OpRegRegImm(kOpAdd, TargetReg(kArg3), TargetReg(kSp), start_offset);
- LIR* ld = OpVldm(TargetReg(kArg3), regs_left);
- // TUNING: loosen barrier
- ld->u.m.def_mask = ENCODE_ALL;
- SetMemRefType(ld, true /* is_load */, kDalvikReg);
- call_state = next_call_insn(cu_, info, call_state, target_method, vtable_idx,
- direct_code, direct_method, type);
- OpRegRegImm(kOpAdd, TargetReg(kArg3), TargetReg(kSp), 4 /* Method* */ + (3 * 4));
- call_state = next_call_insn(cu_, info, call_state, target_method, vtable_idx,
- direct_code, direct_method, type);
- LIR* st = OpVstm(TargetReg(kArg3), regs_left);
- SetMemRefType(st, false /* is_load */, kDalvikReg);
- st->u.m.def_mask = ENCODE_ALL;
- call_state = next_call_insn(cu_, info, call_state, target_method, vtable_idx,
- direct_code, direct_method, type);
- }
}
call_state = LoadArgRegs(info, call_state, next_call_insn,
diff --git a/compiler/dex/quick/mips/codegen_mips.h b/compiler/dex/quick/mips/codegen_mips.h
index aca93f51d3..11b8f83058 100644
--- a/compiler/dex/quick/mips/codegen_mips.h
+++ b/compiler/dex/quick/mips/codegen_mips.h
@@ -151,6 +151,8 @@ class MipsMir2Lir : public Mir2Lir {
LIR* OpRegImm(OpKind op, int r_dest_src1, int value);
LIR* OpRegMem(OpKind op, int r_dest, int rBase, int offset);
LIR* OpRegReg(OpKind op, int r_dest_src1, int r_src2);
+ LIR* OpMovRegMem(int r_dest, int r_base, int offset, MoveType move_type);
+ LIR* OpMovMemReg(int r_base, int offset, int r_src, MoveType move_type);
LIR* OpCondRegReg(OpKind op, ConditionCode cc, int r_dest, int r_src);
LIR* OpRegRegImm(OpKind op, int r_dest, int r_src1, int value);
LIR* OpRegRegReg(OpKind op, int r_dest, int r_src1, int r_src2);
diff --git a/compiler/dex/quick/mips/utility_mips.cc b/compiler/dex/quick/mips/utility_mips.cc
index c5e2b36ef2..21c971c327 100644
--- a/compiler/dex/quick/mips/utility_mips.cc
+++ b/compiler/dex/quick/mips/utility_mips.cc
@@ -325,6 +325,16 @@ LIR* MipsMir2Lir::OpRegReg(OpKind op, int r_dest_src1, int r_src2) {
return NewLIR2(opcode, r_dest_src1, r_src2);
}
+LIR* MipsMir2Lir::OpMovRegMem(int r_dest, int r_base, int offset, MoveType move_type) {
+ UNIMPLEMENTED(FATAL);
+ return nullptr;
+}
+
+LIR* MipsMir2Lir::OpMovMemReg(int r_base, int offset, int r_src, MoveType move_type) {
+ UNIMPLEMENTED(FATAL);
+ return nullptr;
+}
+
LIR* MipsMir2Lir::OpCondRegReg(OpKind op, ConditionCode cc, int r_dest, int r_src) {
LOG(FATAL) << "Unexpected use of OpCondRegReg for MIPS";
return NULL;
diff --git a/compiler/dex/quick/mir_to_lir.h b/compiler/dex/quick/mir_to_lir.h
index 09b501aba7..3a68044d51 100644
--- a/compiler/dex/quick/mir_to_lir.h
+++ b/compiler/dex/quick/mir_to_lir.h
@@ -946,6 +946,27 @@ class Mir2Lir : public Backend {
virtual LIR* OpRegReg(OpKind op, int r_dest_src1, int r_src2) = 0;
/**
+ * @brief Used to generate an LIR that does a load from mem to reg.
+ * @param r_dest The destination physical register.
+ * @param r_base The base physical register for memory operand.
+ * @param offset The displacement for memory operand.
+ * @param move_type Specification on the move desired (size, alignment, register kind).
+ * @return Returns the generate move LIR.
+ */
+ virtual LIR* OpMovRegMem(int r_dest, int r_base, int offset, MoveType move_type) = 0;
+
+ /**
+ * @brief Used to generate an LIR that does a store from reg to mem.
+ * @param r_base The base physical register for memory operand.
+ * @param offset The displacement for memory operand.
+ * @param r_src The destination physical register.
+ * @param bytes_to_move The number of bytes to move.
+ * @param is_aligned Whether the memory location is known to be aligned.
+ * @return Returns the generate move LIR.
+ */
+ virtual LIR* OpMovMemReg(int r_base, int offset, int r_src, MoveType move_type) = 0;
+
+ /**
* @brief Used for generating a conditional register to register operation.
* @param op The opcode kind.
* @param cc The condition code that when true will perform the opcode.
diff --git a/compiler/dex/quick/x86/assemble_x86.cc b/compiler/dex/quick/x86/assemble_x86.cc
index 3058b0c884..ae53ddbc9e 100644
--- a/compiler/dex/quick/x86/assemble_x86.cc
+++ b/compiler/dex/quick/x86/assemble_x86.cc
@@ -297,6 +297,24 @@ ENCODING_MAP(Cmp, IS_LOAD, 0, 0,
{ kX86SqrtsdRR, kRegReg, IS_BINARY_OP | REG_DEF0_USE1, { 0xF2, 0, 0x0F, 0x51, 0, 0, 0, 0 }, "SqrtsdRR", "!0r,!1r" },
{ kX86FstpdM, kMem, IS_STORE | IS_BINARY_OP | REG_USE0, { 0x0, 0, 0xDD, 0x00, 0, 3, 0, 0 }, "FstpdM", "[!0r,!1d]" },
+ EXT_0F_ENCODING_MAP(Movups, 0x0, 0x10, REG_DEF0),
+ { kX86MovupsMR, kMemReg, IS_STORE | IS_TERTIARY_OP | REG_USE02, { 0x0, 0, 0x0F, 0x11, 0, 0, 0, 0 }, "MovupsMR", "[!0r+!1d],!2r" },
+ { kX86MovupsAR, kArrayReg, IS_STORE | IS_QUIN_OP | REG_USE014, { 0x0, 0, 0x0F, 0x11, 0, 0, 0, 0 }, "MovupsAR", "[!0r+!1r<<!2d+!3d],!4r" },
+
+ EXT_0F_ENCODING_MAP(Movaps, 0x0, 0x28, REG_DEF0),
+ { kX86MovapsMR, kMemReg, IS_STORE | IS_TERTIARY_OP | REG_USE02, { 0x0, 0, 0x0F, 0x29, 0, 0, 0, 0 }, "MovapsMR", "[!0r+!1d],!2r" },
+ { kX86MovapsAR, kArrayReg, IS_STORE | IS_QUIN_OP | REG_USE014, { 0x0, 0, 0x0F, 0x29, 0, 0, 0, 0 }, "MovapsAR", "[!0r+!1r<<!2d+!3d],!4r" },
+
+ { kX86MovlpsRM, kRegMem, IS_LOAD | IS_TERTIARY_OP | REG_DEF0 | REG_USE01, { 0x0, 0, 0x0F, 0x12, 0, 0, 0, 0 }, "MovlpsRM", "!0r,[!1r+!2d]" },
+ { kX86MovlpsRA, kRegArray, IS_LOAD | IS_QUIN_OP | REG_DEF0 | REG_USE012, { 0x0, 0, 0x0F, 0x12, 0, 0, 0, 0 }, "MovlpsRA", "!0r,[!1r+!2r<<!3d+!4d]" },
+ { kX86MovlpsMR, kMemReg, IS_STORE | IS_TERTIARY_OP | REG_USE02, { 0x0, 0, 0x0F, 0x13, 0, 0, 0, 0 }, "MovlpsMR", "[!0r+!1d],!2r" },
+ { kX86MovlpsAR, kArrayReg, IS_STORE | IS_QUIN_OP | REG_USE014, { 0x0, 0, 0x0F, 0x13, 0, 0, 0, 0 }, "MovlpsAR", "[!0r+!1r<<!2d+!3d],!4r" },
+
+ { kX86MovhpsRM, kRegMem, IS_LOAD | IS_TERTIARY_OP | REG_DEF0 | REG_USE01, { 0x0, 0, 0x0F, 0x16, 0, 0, 0, 0 }, "MovhpsRM", "!0r,[!1r+!2d]" },
+ { kX86MovhpsRA, kRegArray, IS_LOAD | IS_QUIN_OP | REG_DEF0 | REG_USE012, { 0x0, 0, 0x0F, 0x16, 0, 0, 0, 0 }, "MovhpsRA", "!0r,[!1r+!2r<<!3d+!4d]" },
+ { kX86MovhpsMR, kMemReg, IS_STORE | IS_TERTIARY_OP | REG_USE02, { 0x0, 0, 0x0F, 0x17, 0, 0, 0, 0 }, "MovhpsMR", "[!0r+!1d],!2r" },
+ { kX86MovhpsAR, kArrayReg, IS_STORE | IS_QUIN_OP | REG_USE014, { 0x0, 0, 0x0F, 0x17, 0, 0, 0, 0 }, "MovhpsAR", "[!0r+!1r<<!2d+!3d],!4r" },
+
EXT_0F_ENCODING_MAP(Movdxr, 0x66, 0x6E, REG_DEF0),
{ kX86MovdrxRR, kRegRegStore, IS_BINARY_OP | REG_DEF0 | REG_USE01, { 0x66, 0, 0x0F, 0x7E, 0, 0, 0, 0 }, "MovdrxRR", "!0r,!1r" },
{ kX86MovdrxMR, kMemReg, IS_STORE | IS_TERTIARY_OP | REG_USE02, { 0x66, 0, 0x0F, 0x7E, 0, 0, 0, 0 }, "MovdrxMR", "[!0r+!1d],!2r" },
diff --git a/compiler/dex/quick/x86/codegen_x86.h b/compiler/dex/quick/x86/codegen_x86.h
index 6896504f52..4c1c1711c0 100644
--- a/compiler/dex/quick/x86/codegen_x86.h
+++ b/compiler/dex/quick/x86/codegen_x86.h
@@ -207,6 +207,8 @@ class X86Mir2Lir : public Mir2Lir {
LIR* OpMemReg(OpKind op, RegLocation rl_dest, int value);
LIR* OpRegMem(OpKind op, int r_dest, RegLocation value);
LIR* OpRegReg(OpKind op, int r_dest_src1, int r_src2);
+ LIR* OpMovRegMem(int r_dest, int r_base, int offset, MoveType move_type);
+ LIR* OpMovMemReg(int r_base, int offset, int r_src, MoveType move_type);
LIR* OpCondRegReg(OpKind op, ConditionCode cc, int r_dest, int r_src);
LIR* OpRegRegImm(OpKind op, int r_dest, int r_src1, int value);
LIR* OpRegRegReg(OpKind op, int r_dest, int r_src1, int r_src2);
diff --git a/compiler/dex/quick/x86/utility_x86.cc b/compiler/dex/quick/x86/utility_x86.cc
index 18c5ca801b..e2744d076d 100644
--- a/compiler/dex/quick/x86/utility_x86.cc
+++ b/compiler/dex/quick/x86/utility_x86.cc
@@ -211,6 +211,110 @@ LIR* X86Mir2Lir::OpRegReg(OpKind op, int r_dest_src1, int r_src2) {
return NewLIR2(opcode, r_dest_src1, r_src2);
}
+LIR* X86Mir2Lir::OpMovRegMem(int r_dest, int r_base, int offset, MoveType move_type) {
+ DCHECK(!(X86_FPREG(r_base)));
+
+ X86OpCode opcode = kX86Nop;
+ switch (move_type) {
+ case kMov8GP:
+ CHECK(!X86_FPREG(r_dest));
+ opcode = kX86Mov8RM;
+ break;
+ case kMov16GP:
+ CHECK(!X86_FPREG(r_dest));
+ opcode = kX86Mov16RM;
+ break;
+ case kMov32GP:
+ CHECK(!X86_FPREG(r_dest));
+ opcode = kX86Mov32RM;
+ break;
+ case kMov32FP:
+ CHECK(X86_FPREG(r_dest));
+ opcode = kX86MovssRM;
+ break;
+ case kMov64FP:
+ CHECK(X86_FPREG(r_dest));
+ opcode = kX86MovsdRM;
+ break;
+ case kMovU128FP:
+ CHECK(X86_FPREG(r_dest));
+ opcode = kX86MovupsRM;
+ break;
+ case kMovA128FP:
+ CHECK(X86_FPREG(r_dest));
+ opcode = kX86MovapsRM;
+ break;
+ case kMovLo128FP:
+ CHECK(X86_FPREG(r_dest));
+ opcode = kX86MovlpsRM;
+ break;
+ case kMovHi128FP:
+ CHECK(X86_FPREG(r_dest));
+ opcode = kX86MovhpsRM;
+ break;
+ case kMov64GP:
+ case kMovLo64FP:
+ case kMovHi64FP:
+ default:
+ LOG(FATAL) << "Bad case in OpMovRegMem";
+ break;
+ }
+
+ return NewLIR3(opcode, r_dest, r_base, offset);
+}
+
+LIR* X86Mir2Lir::OpMovMemReg(int r_base, int offset, int r_src, MoveType move_type) {
+ DCHECK(!(X86_FPREG(r_base)));
+
+ X86OpCode opcode = kX86Nop;
+ switch (move_type) {
+ case kMov8GP:
+ CHECK(!X86_FPREG(r_src));
+ opcode = kX86Mov8MR;
+ break;
+ case kMov16GP:
+ CHECK(!X86_FPREG(r_src));
+ opcode = kX86Mov16MR;
+ break;
+ case kMov32GP:
+ CHECK(!X86_FPREG(r_src));
+ opcode = kX86Mov32MR;
+ break;
+ case kMov32FP:
+ CHECK(X86_FPREG(r_src));
+ opcode = kX86MovssMR;
+ break;
+ case kMov64FP:
+ CHECK(X86_FPREG(r_src));
+ opcode = kX86MovsdMR;
+ break;
+ case kMovU128FP:
+ CHECK(X86_FPREG(r_src));
+ opcode = kX86MovupsMR;
+ break;
+ case kMovA128FP:
+ CHECK(X86_FPREG(r_src));
+ opcode = kX86MovapsMR;
+ break;
+ case kMovLo128FP:
+ CHECK(X86_FPREG(r_src));
+ opcode = kX86MovlpsMR;
+ break;
+ case kMovHi128FP:
+ CHECK(X86_FPREG(r_src));
+ opcode = kX86MovhpsMR;
+ break;
+ case kMov64GP:
+ case kMovLo64FP:
+ case kMovHi64FP:
+ default:
+ LOG(FATAL) << "Bad case in OpMovMemReg";
+ break;
+ }
+
+ return NewLIR3(opcode, r_base, offset, r_src);
+}
+
LIR* X86Mir2Lir::OpCondRegReg(OpKind op, ConditionCode cc, int r_dest, int r_src) {
// The only conditional reg to reg operation supported is Cmov
DCHECK_EQ(op, kOpCmov);
diff --git a/compiler/dex/quick/x86/x86_lir.h b/compiler/dex/quick/x86/x86_lir.h
index 7f35d061b5..6962ff7a49 100644
--- a/compiler/dex/quick/x86/x86_lir.h
+++ b/compiler/dex/quick/x86/x86_lir.h
@@ -357,6 +357,14 @@ enum X86OpCode {
kX86PsllqRI, // left shift of floating point registers
kX86SqrtsdRR, // sqrt of floating point register
kX86FstpdM, // Store and pop top x87 fp stack
+ Binary0fOpCode(kX86Movups), // load unaligned packed single FP values from xmm2/m128 to xmm1
+ kX86MovupsMR, kX86MovupsAR, // store unaligned packed single FP values from xmm1 to m128
+ Binary0fOpCode(kX86Movaps), // load aligned packed single FP values from xmm2/m128 to xmm1
+ kX86MovapsMR, kX86MovapsAR, // store aligned packed single FP values from xmm1 to m128
+ kX86MovlpsRM, kX86MovlpsRA, // load packed single FP values from m64 to low quadword of xmm
+ kX86MovlpsMR, kX86MovlpsAR, // store packed single FP values from low quadword of xmm to m64
+ kX86MovhpsRM, kX86MovhpsRA, // load packed single FP values from m64 to high quadword of xmm
+ kX86MovhpsMR, kX86MovhpsAR, // store packed single FP values from high quadword of xmm to m64
Binary0fOpCode(kX86Movdxr), // move into xmm from gpr
kX86MovdrxRR, kX86MovdrxMR, kX86MovdrxAR, // move into reg from xmm
kX86Set8R, kX86Set8M, kX86Set8A, // set byte depending on condition operand