diff options
| author | 2013-12-18 06:02:17 -0800 | |
|---|---|---|
| committer | 2013-12-18 09:54:32 -0800 | |
| commit | 343adb52d3f031b6b5e005ff51f9cb04df219b21 (patch) | |
| tree | 9d0ce59baf6dbeffe83623dced6cd8b28543164b | |
| parent | d87ebe99b8e6ba128963e31d3b3d3deca6ac9b89 (diff) | |
Enhance GenArrayGet, GenArrayPut for x86
As pointed out by Ian Rogers, the x86 versions didn't optimize
handling of constant index expressions. Added that support,
simplified checking of constant indices, and removed the use of
a temporary register for the 'wide' cases by using x86 scaled
addressing mode.
Change-Id: I82174e4e3674752d00d7c4730496f59d69f5f173
Signed-off-by: Mark Mendell <mark.p.mendell@intel.com>
| -rw-r--r-- | compiler/dex/quick/x86/assemble_x86.cc | 10 | ||||
| -rw-r--r-- | compiler/dex/quick/x86/codegen_x86.h | 3 | ||||
| -rw-r--r-- | compiler/dex/quick/x86/int_x86.cc | 75 |
3 files changed, 70 insertions, 18 deletions
diff --git a/compiler/dex/quick/x86/assemble_x86.cc b/compiler/dex/quick/x86/assemble_x86.cc index c9c4f55e62..c24f0e33f8 100644 --- a/compiler/dex/quick/x86/assemble_x86.cc +++ b/compiler/dex/quick/x86/assemble_x86.cc @@ -772,6 +772,13 @@ void X86Mir2Lir::EmitRegImm(const X86EncodingMap* entry, uint8_t reg, int imm) { EmitImm(entry, imm); } +void X86Mir2Lir::EmitMemImm(const X86EncodingMap* entry, uint8_t base, int disp, int32_t imm) { + EmitPrefixAndOpcode(entry); + EmitModrmDisp(entry->skeleton.modrm_opcode, base, disp); + DCHECK_EQ(0, entry->skeleton.ax_opcode); + EmitImm(entry, imm); +} + void X86Mir2Lir::EmitThreadImm(const X86EncodingMap* entry, int disp, int imm) { EmitPrefixAndOpcode(entry); uint8_t modrm = (0 << 6) | (entry->skeleton.modrm_opcode << 3) | rBP; @@ -1127,6 +1134,9 @@ AssemblerStatus X86Mir2Lir::AssembleInstructions(CodeOffset start_addr) { case kMemReg: // lir operands - 0: base, 1: disp, 2: reg EmitMemReg(entry, lir->operands[0], lir->operands[1], lir->operands[2]); break; + case kMemImm: // lir operands - 0: base, 1: disp, 2: immediate + EmitMemImm(entry, lir->operands[0], lir->operands[1], lir->operands[2]); + break; case kArrayReg: // lir operands - 0: base, 1: index, 2: scale, 3: disp, 4: reg EmitArrayReg(entry, lir->operands[0], lir->operands[1], lir->operands[2], lir->operands[3], lir->operands[4]); diff --git a/compiler/dex/quick/x86/codegen_x86.h b/compiler/dex/quick/x86/codegen_x86.h index 6552607d9e..62ec77a508 100644 --- a/compiler/dex/quick/x86/codegen_x86.h +++ b/compiler/dex/quick/x86/codegen_x86.h @@ -115,6 +115,8 @@ class X86Mir2Lir : public Mir2Lir { void GenXorLong(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2); LIR* GenRegMemCheck(ConditionCode c_code, int reg1, int base, int offset, ThrowKind kind); + LIR* GenMemImmedCheck(ConditionCode c_code, int base, int offset, int check_value, + ThrowKind kind); RegLocation GenDivRem(RegLocation rl_dest, int reg_lo, int reg_hi, bool is_div); RegLocation GenDivRemLit(RegLocation rl_dest, int reg_lo, int lit, bool is_div); void GenCmpLong(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2); @@ -184,6 +186,7 @@ class X86Mir2Lir : public Mir2Lir { void EmitOpArray(const X86EncodingMap* entry, uint8_t base, uint8_t index, int scale, int disp); void EmitMemReg(const X86EncodingMap* entry, uint8_t base, int disp, uint8_t reg); + void EmitMemImm(const X86EncodingMap* entry, uint8_t base, int disp, int32_t imm); void EmitRegMem(const X86EncodingMap* entry, uint8_t reg, uint8_t base, int disp); void EmitRegArray(const X86EncodingMap* entry, uint8_t reg, uint8_t base, uint8_t index, int scale, int disp); diff --git a/compiler/dex/quick/x86/int_x86.cc b/compiler/dex/quick/x86/int_x86.cc index 340c74ae14..8ff9ded457 100644 --- a/compiler/dex/quick/x86/int_x86.cc +++ b/compiler/dex/quick/x86/int_x86.cc @@ -38,6 +38,20 @@ LIR* X86Mir2Lir::GenRegMemCheck(ConditionCode c_code, } /* + * Perform a compare of memory to immediate value + */ +LIR* X86Mir2Lir::GenMemImmedCheck(ConditionCode c_code, + int base, int offset, int check_value, ThrowKind kind) { + LIR* tgt = RawLIR(0, kPseudoThrowTarget, kind, + current_dalvik_offset_, base, check_value, 0); + NewLIR3(IS_SIMM8(check_value) ? kX86Cmp32MI8 : kX86Cmp32MI, base, offset, check_value); + LIR* branch = OpCondBranch(c_code, tgt); + // Remember branch target - will process later + throw_launchpads_.Insert(tgt); + return branch; +} + +/* * Compare two 64-bit values * x = y return 0 * x < y return -1 @@ -521,41 +535,49 @@ void X86Mir2Lir::GenArrayGet(int opt_flags, OpSize size, RegLocation rl_array, RegLocation rl_index, RegLocation rl_dest, int scale) { RegisterClass reg_class = oat_reg_class_by_size(size); int len_offset = mirror::Array::LengthOffset().Int32Value(); - int data_offset; RegLocation rl_result; rl_array = LoadValue(rl_array, kCoreReg); - rl_index = LoadValue(rl_index, kCoreReg); + int data_offset; if (size == kLong || size == kDouble) { data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Int32Value(); } else { data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Int32Value(); } + bool constant_index = rl_index.is_const; + int32_t constant_index_value = 0; + if (!constant_index) { + rl_index = LoadValue(rl_index, kCoreReg); + } else { + constant_index_value = mir_graph_->ConstantValue(rl_index); + // If index is constant, just fold it into the data offset + data_offset += constant_index_value << scale; + // treat as non array below + rl_index.low_reg = INVALID_REG; + } + /* null object? */ GenNullCheck(rl_array.s_reg_low, rl_array.low_reg, opt_flags); if (!(opt_flags & MIR_IGNORE_RANGE_CHECK)) { - /* if (rl_index >= [rl_array + len_offset]) goto kThrowArrayBounds */ - GenRegMemCheck(kCondUge, rl_index.low_reg, rl_array.low_reg, - len_offset, kThrowArrayBounds); + if (constant_index) { + GenMemImmedCheck(kCondLs, rl_array.low_reg, len_offset, + constant_index_value, kThrowConstantArrayBounds); + } else { + GenRegMemCheck(kCondUge, rl_index.low_reg, rl_array.low_reg, + len_offset, kThrowArrayBounds); + } } + rl_result = EvalLoc(rl_dest, reg_class, true); if ((size == kLong) || (size == kDouble)) { - int reg_addr = AllocTemp(); - OpLea(reg_addr, rl_array.low_reg, rl_index.low_reg, scale, data_offset); - FreeTemp(rl_array.low_reg); - FreeTemp(rl_index.low_reg); - rl_result = EvalLoc(rl_dest, reg_class, true); - LoadBaseIndexedDisp(reg_addr, INVALID_REG, 0, 0, rl_result.low_reg, + LoadBaseIndexedDisp(rl_array.low_reg, rl_index.low_reg, scale, data_offset, rl_result.low_reg, rl_result.high_reg, size, INVALID_SREG); StoreValueWide(rl_dest, rl_result); } else { - rl_result = EvalLoc(rl_dest, reg_class, true); - LoadBaseIndexedDisp(rl_array.low_reg, rl_index.low_reg, scale, data_offset, rl_result.low_reg, INVALID_REG, size, INVALID_SREG); - StoreValue(rl_dest, rl_result); } } @@ -577,14 +599,29 @@ void X86Mir2Lir::GenArrayPut(int opt_flags, OpSize size, RegLocation rl_array, } rl_array = LoadValue(rl_array, kCoreReg); - rl_index = LoadValue(rl_index, kCoreReg); + bool constant_index = rl_index.is_const; + int32_t constant_index_value = 0; + if (!constant_index) { + rl_index = LoadValue(rl_index, kCoreReg); + } else { + // If index is constant, just fold it into the data offset + constant_index_value = mir_graph_->ConstantValue(rl_index); + data_offset += constant_index_value << scale; + // treat as non array below + rl_index.low_reg = INVALID_REG; + } /* null object? */ GenNullCheck(rl_array.s_reg_low, rl_array.low_reg, opt_flags); if (!(opt_flags & MIR_IGNORE_RANGE_CHECK)) { - /* if (rl_index >= [rl_array + len_offset]) goto kThrowArrayBounds */ - GenRegMemCheck(kCondUge, rl_index.low_reg, rl_array.low_reg, len_offset, kThrowArrayBounds); + if (constant_index) { + GenMemImmedCheck(kCondLs, rl_array.low_reg, len_offset, + constant_index_value, kThrowConstantArrayBounds); + } else { + GenRegMemCheck(kCondUge, rl_index.low_reg, rl_array.low_reg, + len_offset, kThrowArrayBounds); + } } if ((size == kLong) || (size == kDouble)) { rl_src = LoadValueWide(rl_src, reg_class); @@ -603,7 +640,9 @@ void X86Mir2Lir::GenArrayPut(int opt_flags, OpSize size, RegLocation rl_array, } if (card_mark) { // Free rl_index if its a temp. Ensures there are 2 free regs for card mark. - FreeTemp(rl_index.low_reg); + if (!constant_index) { + FreeTemp(rl_index.low_reg); + } MarkGCCard(rl_src.low_reg, rl_array.low_reg); } } |