diff options
-rw-r--r-- | compiler/dex/mir_graph.h | 2 | ||||
-rw-r--r-- | compiler/dex/quick/x86/assemble_x86.cc | 11 | ||||
-rw-r--r-- | compiler/dex/quick/x86/call_x86.cc | 30 | ||||
-rw-r--r-- | compiler/dex/quick/x86/codegen_x86.h | 55 | ||||
-rw-r--r-- | compiler/dex/quick/x86/target_x86.cc | 8 | ||||
-rw-r--r-- | compiler/dex/quick/x86/utility_x86.cc | 141 |
6 files changed, 241 insertions, 6 deletions
diff --git a/compiler/dex/mir_graph.h b/compiler/dex/mir_graph.h index debcb5c..f8706c4 100644 --- a/compiler/dex/mir_graph.h +++ b/compiler/dex/mir_graph.h @@ -647,7 +647,7 @@ class MIRGraph { } RegLocation GetRegLocation(int index) { - DCHECK((index >= 0) && (index > num_ssa_regs_)); + DCHECK((index >= 0) && (index < num_ssa_regs_)); return reg_location_[index]; } diff --git a/compiler/dex/quick/x86/assemble_x86.cc b/compiler/dex/quick/x86/assemble_x86.cc index 916bc7a..3058b0c 100644 --- a/compiler/dex/quick/x86/assemble_x86.cc +++ b/compiler/dex/quick/x86/assemble_x86.cc @@ -1154,6 +1154,17 @@ AssemblerStatus X86Mir2Lir::AssembleInstructions(CodeOffset start_addr) { break; } default: + if (lir->flags.fixup == kFixupLoad) { + LIR *target_lir = lir->target; + DCHECK(target_lir != NULL); + CodeOffset target = target_lir->offset; + lir->operands[2] = target; + int newSize = GetInsnSize(lir); + if (newSize != lir->flags.size) { + lir->flags.size = newSize; + res = kRetryAll; + } + } break; } } diff --git a/compiler/dex/quick/x86/call_x86.cc b/compiler/dex/quick/x86/call_x86.cc index 4267b5b..93875c9 100644 --- a/compiler/dex/quick/x86/call_x86.cc +++ b/compiler/dex/quick/x86/call_x86.cc @@ -84,10 +84,19 @@ void X86Mir2Lir::GenPackedSwitch(MIR* mir, DexOffset table_offset, // Get the switch value rl_src = LoadValue(rl_src, kCoreReg); - int start_of_method_reg = AllocTemp(); - // Materialize a pointer to the switch table // NewLIR0(kX86Bkpt); - NewLIR1(kX86StartOfMethod, start_of_method_reg); + + // Materialize a pointer to the switch table + int start_of_method_reg; + if (base_of_code_ != nullptr) { + // We can use the saved value. + RegLocation rl_method = mir_graph_->GetRegLocation(base_of_code_->s_reg_low); + rl_method = LoadValue(rl_method, kCoreReg); + start_of_method_reg = rl_method.low_reg; + } else { + start_of_method_reg = AllocTemp(); + NewLIR1(kX86StartOfMethod, start_of_method_reg); + } int low_key = s4FromSwitchData(&table[2]); int keyReg; // Remove the bias, if necessary @@ -142,7 +151,13 @@ void X86Mir2Lir::GenFillArrayData(DexOffset table_offset, RegLocation rl_src) { FlushAllRegs(); /* Everything to home location */ LoadValueDirectFixed(rl_src, rX86_ARG0); // Materialize a pointer to the fill data image - NewLIR1(kX86StartOfMethod, rX86_ARG2); + if (base_of_code_ != nullptr) { + // We can use the saved value. + RegLocation rl_method = mir_graph_->GetRegLocation(base_of_code_->s_reg_low); + LoadValueDirect(rl_method, rX86_ARG2); + } else { + NewLIR1(kX86StartOfMethod, rX86_ARG2); + } NewLIR2(kX86PcRelAdr, rX86_ARG1, WrapPointer(tab_rec)); NewLIR2(kX86Add32RR, rX86_ARG1, rX86_ARG2); CallRuntimeHelperRegReg(QUICK_ENTRYPOINT_OFFSET(pHandleFillArrayData), rX86_ARG0, @@ -211,6 +226,13 @@ void X86Mir2Lir::GenEntrySequence(RegLocation* ArgLocs, RegLocation rl_method) { FlushIns(ArgLocs, rl_method); + if (base_of_code_ != nullptr) { + // We have been asked to save the address of the method start for later use. + NewLIR1(kX86StartOfMethod, rX86_ARG0); + int displacement = SRegOffset(base_of_code_->s_reg_low); + StoreBaseDisp(rX86_SP, displacement, rX86_ARG0, kWord); + } + FreeTemp(rX86_ARG0); FreeTemp(rX86_ARG1); FreeTemp(rX86_ARG2); diff --git a/compiler/dex/quick/x86/codegen_x86.h b/compiler/dex/quick/x86/codegen_x86.h index a864117..6896504 100644 --- a/compiler/dex/quick/x86/codegen_x86.h +++ b/compiler/dex/quick/x86/codegen_x86.h @@ -407,6 +407,61 @@ class X86Mir2Lir : public Mir2Lir { * @returns 'true' if the operation can proceed without needing temporary regs. */ bool IsOperationSafeWithoutTemps(RegLocation rl_lhs, RegLocation rl_rhs); + + /* + * @brief Perform MIR analysis before compiling method. + * @note Invokes Mir2LiR::Materialize after analysis. + */ + void Materialize(); + + /* + * @brief Analyze MIR before generating code, to prepare for the code generation. + */ + void AnalyzeMIR(); + + /* + * @brief Analyze one basic block. + * @param bb Basic block to analyze. + */ + void AnalyzeBB(BasicBlock * bb); + + /* + * @brief Analyze one extended MIR instruction + * @param opcode MIR instruction opcode. + * @param bb Basic block containing instruction. + * @param mir Extended instruction to analyze. + */ + void AnalyzeExtendedMIR(int opcode, BasicBlock * bb, MIR *mir); + + /* + * @brief Analyze one MIR instruction + * @param opcode MIR instruction opcode. + * @param bb Basic block containing instruction. + * @param mir Instruction to analyze. + */ + void AnalyzeMIR(int opcode, BasicBlock * bb, MIR *mir); + + /* + * @brief Analyze one MIR float/double instruction + * @param opcode MIR instruction opcode. + * @param bb Basic block containing instruction. + * @param mir Instruction to analyze. + */ + void AnalyzeFPInstruction(int opcode, BasicBlock * bb, MIR *mir); + + /* + * @brief Analyze one use of a double operand. + * @param rl_use Double RegLocation for the operand. + */ + void AnalyzeDoubleUse(RegLocation rl_use); + + // Information derived from analysis of MIR + + // Have we decided to compute a ptr to code and store in temporary VR? + bool store_method_addr_; + + // The compiler temporary for the code address of the method. + CompilerTemp *base_of_code_; }; } // namespace art diff --git a/compiler/dex/quick/x86/target_x86.cc b/compiler/dex/quick/x86/target_x86.cc index f223548..a347d8b 100644 --- a/compiler/dex/quick/x86/target_x86.cc +++ b/compiler/dex/quick/x86/target_x86.cc @@ -808,4 +808,12 @@ void X86Mir2Lir::DumpRegLocation(RegLocation loc) { << ", orig: " << loc.orig_sreg; } +void X86Mir2Lir::Materialize() { + // A good place to put the analysis before starting. + AnalyzeMIR(); + + // Now continue with regular code generation. + Mir2Lir::Materialize(); +} + } // namespace art diff --git a/compiler/dex/quick/x86/utility_x86.cc b/compiler/dex/quick/x86/utility_x86.cc index a77e921..18c5ca8 100644 --- a/compiler/dex/quick/x86/utility_x86.cc +++ b/compiler/dex/quick/x86/utility_x86.cc @@ -16,6 +16,7 @@ #include "codegen_x86.h" #include "dex/quick/mir_to_lir-inl.h" +#include "dex/dataflow_iterator-inl.h" #include "x86_lir.h" namespace art { @@ -61,7 +62,7 @@ bool X86Mir2Lir::InexpensiveConstantLong(int64_t value) { } bool X86Mir2Lir::InexpensiveConstantDouble(int64_t value) { - return false; // TUNING + return value == 0; } /* @@ -394,6 +395,27 @@ LIR* X86Mir2Lir::LoadConstantWide(int r_dest_lo, int r_dest_hi, int64_t value) { DCHECK_EQ(r_dest_lo, r_dest_hi); if (value == 0) { return NewLIR2(kX86XorpsRR, r_dest_lo, r_dest_lo); + } else if (base_of_code_ != nullptr) { + // We will load the value from the literal area. + LIR* data_target = ScanLiteralPoolWide(literal_list_, val_lo, val_hi); + if (data_target == NULL) { + data_target = AddWideData(&literal_list_, val_lo, val_hi); + } + + // Address the start of the method + RegLocation rl_method = mir_graph_->GetRegLocation(base_of_code_->s_reg_low); + rl_method = LoadValue(rl_method, kCoreReg); + + // Load the proper value from the literal area. + // We don't know the proper offset for the value, so pick one that will force + // 4 byte offset. We will fix this up in the assembler later to have the right + // value. + res = LoadBaseDisp(rl_method.low_reg, 256 /* bogus */, r_dest_lo, kDouble, INVALID_SREG); + res->target = data_target; + res->flags.fixup = kFixupLoad; + SetMemRefType(res, true, kLiteral); + // Redo after we assign target to ensure size is correct. + SetupResourceMasks(res); } else { if (val_lo == 0) { res = NewLIR2(kX86XorpsRR, r_dest_lo, r_dest_lo); @@ -662,4 +684,121 @@ LIR* X86Mir2Lir::OpCmpMemImmBranch(ConditionCode cond, int temp_reg, int base_re return branch; } +void X86Mir2Lir::AnalyzeMIR() { + // Assume we don't need a pointer to the base of the code. + cu_->NewTimingSplit("X86 MIR Analysis"); + store_method_addr_ = false; + + // Walk the MIR looking for interesting items. + PreOrderDfsIterator iter(mir_graph_); + BasicBlock* curr_bb = iter.Next(); + while (curr_bb != NULL) { + AnalyzeBB(curr_bb); + curr_bb = iter.Next(); + } + + // Did we need a pointer to the method code? + if (store_method_addr_) { + base_of_code_ = mir_graph_->GetNewCompilerTemp(kCompilerTempVR, false); + } else { + base_of_code_ = nullptr; + } +} + +void X86Mir2Lir::AnalyzeBB(BasicBlock * bb) { + if (bb->block_type == kDead) { + // Ignore dead blocks + return; + } + + for (MIR *mir = bb->first_mir_insn; mir != NULL; mir = mir->next) { + int opcode = mir->dalvikInsn.opcode; + if (opcode >= kMirOpFirst) { + AnalyzeExtendedMIR(opcode, bb, mir); + } else { + AnalyzeMIR(opcode, bb, mir); + } + } +} + + +void X86Mir2Lir::AnalyzeExtendedMIR(int opcode, BasicBlock * bb, MIR *mir) { + switch (opcode) { + // Instructions referencing doubles. + case kMirOpFusedCmplDouble: + case kMirOpFusedCmpgDouble: + AnalyzeFPInstruction(opcode, bb, mir); + break; + default: + // Ignore the rest. + break; + } +} + +void X86Mir2Lir::AnalyzeMIR(int opcode, BasicBlock * bb, MIR *mir) { + // Looking for + // - Do we need a pointer to the code (used for packed switches and double lits)? + + switch (opcode) { + // Instructions referencing doubles. + case Instruction::CMPL_DOUBLE: + case Instruction::CMPG_DOUBLE: + case Instruction::NEG_DOUBLE: + case Instruction::ADD_DOUBLE: + case Instruction::SUB_DOUBLE: + case Instruction::MUL_DOUBLE: + case Instruction::DIV_DOUBLE: + case Instruction::REM_DOUBLE: + case Instruction::ADD_DOUBLE_2ADDR: + case Instruction::SUB_DOUBLE_2ADDR: + case Instruction::MUL_DOUBLE_2ADDR: + case Instruction::DIV_DOUBLE_2ADDR: + case Instruction::REM_DOUBLE_2ADDR: + AnalyzeFPInstruction(opcode, bb, mir); + break; + // Packed switches and array fills need a pointer to the base of the method. + case Instruction::FILL_ARRAY_DATA: + case Instruction::PACKED_SWITCH: + store_method_addr_ = true; + break; + default: + // Other instructions are not interesting yet. + break; + } +} + +void X86Mir2Lir::AnalyzeFPInstruction(int opcode, BasicBlock * bb, MIR *mir) { + // Look at all the uses, and see if they are double constants. + uint64_t attrs = mir_graph_->oat_data_flow_attributes_[opcode]; + int next_sreg = 0; + if (attrs & DF_UA) { + if (attrs & DF_A_WIDE) { + AnalyzeDoubleUse(mir_graph_->GetSrcWide(mir, next_sreg)); + next_sreg += 2; + } else { + next_sreg++; + } + } + if (attrs & DF_UB) { + if (attrs & DF_B_WIDE) { + AnalyzeDoubleUse(mir_graph_->GetSrcWide(mir, next_sreg)); + next_sreg += 2; + } else { + next_sreg++; + } + } + if (attrs & DF_UC) { + if (attrs & DF_C_WIDE) { + AnalyzeDoubleUse(mir_graph_->GetSrcWide(mir, next_sreg)); + } + } +} + +void X86Mir2Lir::AnalyzeDoubleUse(RegLocation use) { + // If this is a double literal, we will want it in the literal pool. + if (use.is_const) { + store_method_addr_ = true; + } +} + } // namespace art |