diff options
| author | 2013-11-26 20:14:20 +0000 | |
|---|---|---|
| committer | 2013-11-26 20:14:21 +0000 | |
| commit | 83a9962f4062cd91e823a2a948aba3887cbe32aa (patch) | |
| tree | 01ff0b0545450439200b81627bfc43ae60f414c2 /compiler | |
| parent | 21be5b21017823b3785f94349e2e2b57d82431e6 (diff) | |
| parent | 1da1e2fceb0030b4b76b43510b1710a9613e0c2e (diff) | |
Merge "More compile-time tuning"
Diffstat (limited to 'compiler')
| -rw-r--r-- | compiler/dex/dataflow_iterator-inl.h | 2 | ||||
| -rw-r--r-- | compiler/dex/dataflow_iterator.h | 4 | ||||
| -rw-r--r-- | compiler/dex/frontend.cc | 24 | ||||
| -rw-r--r-- | compiler/dex/mir_dataflow.cc | 112 | ||||
| -rw-r--r-- | compiler/dex/mir_graph.cc | 6 | ||||
| -rw-r--r-- | compiler/dex/mir_graph.h | 85 | ||||
| -rw-r--r-- | compiler/dex/mir_optimization.cc | 209 | ||||
| -rw-r--r-- | compiler/dex/portable/mir_to_gbc.cc | 2 | ||||
| -rw-r--r-- | compiler/dex/quick/arm/assemble_arm.cc | 1 | ||||
| -rw-r--r-- | compiler/dex/quick/local_optimizations.cc | 6 | ||||
| -rw-r--r-- | compiler/dex/quick/mips/assemble_mips.cc | 1 | ||||
| -rw-r--r-- | compiler/dex/quick/mir_to_lir.cc | 2 | ||||
| -rw-r--r-- | compiler/dex/quick/x86/assemble_x86.cc | 1 | ||||
| -rw-r--r-- | compiler/dex/vreg_analysis.cc | 490 |
14 files changed, 485 insertions, 460 deletions
diff --git a/compiler/dex/dataflow_iterator-inl.h b/compiler/dex/dataflow_iterator-inl.h index 74f36ddd81..64e5fa64e3 100644 --- a/compiler/dex/dataflow_iterator-inl.h +++ b/compiler/dex/dataflow_iterator-inl.h @@ -37,6 +37,7 @@ inline BasicBlock* DataflowIterator::ForwardRepeatNext(bool had_change) { BasicBlock* res = NULL; if ((idx_ >= end_idx_) && changed_) { idx_ = start_idx_; + repeats_++; changed_ = false; } if (idx_ < end_idx_) { @@ -62,6 +63,7 @@ inline BasicBlock* DataflowIterator::ReverseRepeatNext(bool had_change) { BasicBlock* res = NULL; if ((idx_ < 0) && changed_) { idx_ = start_idx_; + repeats_++; changed_ = false; } if (idx_ >= 0) { diff --git a/compiler/dex/dataflow_iterator.h b/compiler/dex/dataflow_iterator.h index 26e36653be..a0c1c123e7 100644 --- a/compiler/dex/dataflow_iterator.h +++ b/compiler/dex/dataflow_iterator.h @@ -37,6 +37,7 @@ namespace art { class DataflowIterator { public: virtual ~DataflowIterator() {} + int32_t GetRepeatCount() { return repeats_; } protected: DataflowIterator(MIRGraph* mir_graph, int32_t start_idx, int32_t end_idx) @@ -45,6 +46,7 @@ namespace art { end_idx_(end_idx), block_id_list_(NULL), idx_(0), + repeats_(0), changed_(false) {} virtual BasicBlock* ForwardSingleNext() ALWAYS_INLINE; @@ -52,11 +54,13 @@ namespace art { virtual BasicBlock* ForwardRepeatNext(bool had_change) ALWAYS_INLINE; virtual BasicBlock* ReverseRepeatNext(bool had_change) ALWAYS_INLINE; + MIRGraph* const mir_graph_; const int32_t start_idx_; const int32_t end_idx_; GrowableArray<BasicBlockId>* block_id_list_; int32_t idx_; + int32_t repeats_; bool changed_; }; // DataflowIterator diff --git a/compiler/dex/frontend.cc b/compiler/dex/frontend.cc index e53d63648b..197bba5a58 100644 --- a/compiler/dex/frontend.cc +++ b/compiler/dex/frontend.cc @@ -253,15 +253,15 @@ static CompiledMethod* CompileMethod(CompilerDriver& compiler, cu.mir_graph->InlineMethod(code_item, access_flags, invoke_type, class_def_idx, method_idx, class_loader, dex_file); + cu.NewTimingSplit("MIROpt:CheckFilters"); #if !defined(ART_USE_PORTABLE_COMPILER) if (cu.mir_graph->SkipCompilation(Runtime::Current()->GetCompilerFilter())) { return NULL; } #endif - cu.NewTimingSplit("MIROpt:CodeLayout"); - /* Do a code layout pass */ + cu.NewTimingSplit("MIROpt:CodeLayout"); cu.mir_graph->CodeLayout(); /* Perform SSA transformation for the whole method */ @@ -272,18 +272,23 @@ static CompiledMethod* CompileMethod(CompilerDriver& compiler, cu.NewTimingSplit("MIROpt:ConstantProp"); cu.mir_graph->PropagateConstants(); + cu.NewTimingSplit("MIROpt:InitRegLoc"); + cu.mir_graph->InitRegLocations(); + /* Count uses */ + cu.NewTimingSplit("MIROpt:UseCount"); cu.mir_graph->MethodUseCount(); - /* Perform null check elimination */ - cu.NewTimingSplit("MIROpt:NullCheckElimination"); - cu.mir_graph->NullCheckElimination(); + /* Perform null check elimination and type inference*/ + cu.NewTimingSplit("MIROpt:NCE_TypeInference"); + cu.mir_graph->NullCheckEliminationAndTypeInference(); /* Combine basic blocks where possible */ - cu.NewTimingSplit("MIROpt:BBOpt"); + cu.NewTimingSplit("MIROpt:BBCombine"); cu.mir_graph->BasicBlockCombine(); /* Do some basic block optimizations */ + cu.NewTimingSplit("MIROpt:BBOpt"); cu.mir_graph->BasicBlockOptimization(); if (cu.enable_debug & (1 << kDebugDumpCheckStats)) { @@ -294,8 +299,8 @@ static CompiledMethod* CompileMethod(CompilerDriver& compiler, cu.mir_graph->ShowOpcodeStats(); } - /* Set up regLocation[] array to describe values - one for each ssa_name. */ - cu.mir_graph->BuildRegLocations(); + /* Reassociate sreg names with original Dalvik vreg names. */ + cu.mir_graph->RemapRegLocations(); CompiledMethod* result = NULL; @@ -323,8 +328,9 @@ static CompiledMethod* CompileMethod(CompilerDriver& compiler, cu.cg->Materialize(); - cu.NewTimingSplit("Cleanup"); + cu.NewTimingSplit("Dedupe"); /* deduping takes up the vast majority of time in GetCompiledMethod(). */ result = cu.cg->GetCompiledMethod(); + cu.NewTimingSplit("Cleanup"); if (result) { VLOG(compiler) << "Compiled " << PrettyMethod(method_idx, dex_file); diff --git a/compiler/dex/mir_dataflow.cc b/compiler/dex/mir_dataflow.cc index d359ee2dfe..728d48ad70 100644 --- a/compiler/dex/mir_dataflow.cc +++ b/compiler/dex/mir_dataflow.cc @@ -29,7 +29,7 @@ namespace art { * TODO - many optimization flags are incomplete - they will only limit the * scope of optimizations but will not cause mis-optimizations. */ -const int MIRGraph::oat_data_flow_attributes_[kMirOpLast] = { +const uint64_t MIRGraph::oat_data_flow_attributes_[kMirOpLast] = { // 00 NOP DF_NOP, @@ -235,88 +235,88 @@ const int MIRGraph::oat_data_flow_attributes_[kMirOpLast] = { DF_NOP, // 44 AGET vAA, vBB, vCC - DF_DA | DF_UB | DF_UC | DF_NULL_CHK_0 | DF_RANGE_CHK_1 | DF_REF_B | DF_CORE_C, + DF_DA | DF_UB | DF_UC | DF_NULL_CHK_0 | DF_RANGE_CHK_1 | DF_REF_B | DF_CORE_C | DF_LVN, // 45 AGET_WIDE vAA, vBB, vCC - DF_DA | DF_A_WIDE | DF_UB | DF_UC | DF_NULL_CHK_0 | DF_RANGE_CHK_1 | DF_REF_B | DF_CORE_C, + DF_DA | DF_A_WIDE | DF_UB | DF_UC | DF_NULL_CHK_0 | DF_RANGE_CHK_1 | DF_REF_B | DF_CORE_C | DF_LVN, // 46 AGET_OBJECT vAA, vBB, vCC - DF_DA | DF_UB | DF_UC | DF_NULL_CHK_0 | DF_RANGE_CHK_1 | DF_REF_A | DF_REF_B | DF_CORE_C, + DF_DA | DF_UB | DF_UC | DF_NULL_CHK_0 | DF_RANGE_CHK_1 | DF_REF_A | DF_REF_B | DF_CORE_C | DF_LVN, // 47 AGET_BOOLEAN vAA, vBB, vCC - DF_DA | DF_UB | DF_UC | DF_NULL_CHK_0 | DF_RANGE_CHK_1 | DF_REF_B | DF_CORE_C, + DF_DA | DF_UB | DF_UC | DF_NULL_CHK_0 | DF_RANGE_CHK_1 | DF_REF_B | DF_CORE_C | DF_LVN, // 48 AGET_BYTE vAA, vBB, vCC - DF_DA | DF_UB | DF_UC | DF_NULL_CHK_0 | DF_RANGE_CHK_1 | DF_REF_B | DF_CORE_C, + DF_DA | DF_UB | DF_UC | DF_NULL_CHK_0 | DF_RANGE_CHK_1 | DF_REF_B | DF_CORE_C | DF_LVN, // 49 AGET_CHAR vAA, vBB, vCC - DF_DA | DF_UB | DF_UC | DF_NULL_CHK_0 | DF_RANGE_CHK_1 | DF_REF_B | DF_CORE_C, + DF_DA | DF_UB | DF_UC | DF_NULL_CHK_0 | DF_RANGE_CHK_1 | DF_REF_B | DF_CORE_C | DF_LVN, // 4A AGET_SHORT vAA, vBB, vCC - DF_DA | DF_UB | DF_UC | DF_NULL_CHK_0 | DF_RANGE_CHK_1 | DF_REF_B | DF_CORE_C, + DF_DA | DF_UB | DF_UC | DF_NULL_CHK_0 | DF_RANGE_CHK_1 | DF_REF_B | DF_CORE_C | DF_LVN, // 4B APUT vAA, vBB, vCC - DF_UA | DF_UB | DF_UC | DF_NULL_CHK_1 | DF_RANGE_CHK_2 | DF_REF_B | DF_CORE_C, + DF_UA | DF_UB | DF_UC | DF_NULL_CHK_1 | DF_RANGE_CHK_2 | DF_REF_B | DF_CORE_C | DF_LVN, // 4C APUT_WIDE vAA, vBB, vCC - DF_UA | DF_A_WIDE | DF_UB | DF_UC | DF_NULL_CHK_2 | DF_RANGE_CHK_3 | DF_REF_B | DF_CORE_C, + DF_UA | DF_A_WIDE | DF_UB | DF_UC | DF_NULL_CHK_2 | DF_RANGE_CHK_3 | DF_REF_B | DF_CORE_C | DF_LVN, // 4D APUT_OBJECT vAA, vBB, vCC - DF_UA | DF_UB | DF_UC | DF_NULL_CHK_1 | DF_RANGE_CHK_2 | DF_REF_A | DF_REF_B | DF_CORE_C, + DF_UA | DF_UB | DF_UC | DF_NULL_CHK_1 | DF_RANGE_CHK_2 | DF_REF_A | DF_REF_B | DF_CORE_C | DF_LVN, // 4E APUT_BOOLEAN vAA, vBB, vCC - DF_UA | DF_UB | DF_UC | DF_NULL_CHK_1 | DF_RANGE_CHK_2 | DF_REF_B | DF_CORE_C, + DF_UA | DF_UB | DF_UC | DF_NULL_CHK_1 | DF_RANGE_CHK_2 | DF_REF_B | DF_CORE_C | DF_LVN, // 4F APUT_BYTE vAA, vBB, vCC - DF_UA | DF_UB | DF_UC | DF_NULL_CHK_1 | DF_RANGE_CHK_2 | DF_REF_B | DF_CORE_C, + DF_UA | DF_UB | DF_UC | DF_NULL_CHK_1 | DF_RANGE_CHK_2 | DF_REF_B | DF_CORE_C | DF_LVN, // 50 APUT_CHAR vAA, vBB, vCC - DF_UA | DF_UB | DF_UC | DF_NULL_CHK_1 | DF_RANGE_CHK_2 | DF_REF_B | DF_CORE_C, + DF_UA | DF_UB | DF_UC | DF_NULL_CHK_1 | DF_RANGE_CHK_2 | DF_REF_B | DF_CORE_C | DF_LVN, // 51 APUT_SHORT vAA, vBB, vCC - DF_UA | DF_UB | DF_UC | DF_NULL_CHK_1 | DF_RANGE_CHK_2 | DF_REF_B | DF_CORE_C, + DF_UA | DF_UB | DF_UC | DF_NULL_CHK_1 | DF_RANGE_CHK_2 | DF_REF_B | DF_CORE_C | DF_LVN, // 52 IGET vA, vB, field@CCCC - DF_DA | DF_UB | DF_NULL_CHK_0 | DF_REF_B, + DF_DA | DF_UB | DF_NULL_CHK_0 | DF_REF_B | DF_LVN, // 53 IGET_WIDE vA, vB, field@CCCC - DF_DA | DF_A_WIDE | DF_UB | DF_NULL_CHK_0 | DF_REF_B, + DF_DA | DF_A_WIDE | DF_UB | DF_NULL_CHK_0 | DF_REF_B | DF_LVN, // 54 IGET_OBJECT vA, vB, field@CCCC - DF_DA | DF_UB | DF_NULL_CHK_0 | DF_REF_A | DF_REF_B, + DF_DA | DF_UB | DF_NULL_CHK_0 | DF_REF_A | DF_REF_B | DF_LVN, // 55 IGET_BOOLEAN vA, vB, field@CCCC - DF_DA | DF_UB | DF_NULL_CHK_0 | DF_REF_B, + DF_DA | DF_UB | DF_NULL_CHK_0 | DF_REF_B | DF_LVN, // 56 IGET_BYTE vA, vB, field@CCCC - DF_DA | DF_UB | DF_NULL_CHK_0 | DF_REF_B, + DF_DA | DF_UB | DF_NULL_CHK_0 | DF_REF_B | DF_LVN, // 57 IGET_CHAR vA, vB, field@CCCC - DF_DA | DF_UB | DF_NULL_CHK_0 | DF_REF_B, + DF_DA | DF_UB | DF_NULL_CHK_0 | DF_REF_B | DF_LVN, // 58 IGET_SHORT vA, vB, field@CCCC - DF_DA | DF_UB | DF_NULL_CHK_0 | DF_REF_B, + DF_DA | DF_UB | DF_NULL_CHK_0 | DF_REF_B | DF_LVN, // 59 IPUT vA, vB, field@CCCC - DF_UA | DF_UB | DF_NULL_CHK_1 | DF_REF_B, + DF_UA | DF_UB | DF_NULL_CHK_1 | DF_REF_B | DF_LVN, // 5A IPUT_WIDE vA, vB, field@CCCC - DF_UA | DF_A_WIDE | DF_UB | DF_NULL_CHK_2 | DF_REF_B, + DF_UA | DF_A_WIDE | DF_UB | DF_NULL_CHK_2 | DF_REF_B | DF_LVN, // 5B IPUT_OBJECT vA, vB, field@CCCC - DF_UA | DF_UB | DF_NULL_CHK_1 | DF_REF_A | DF_REF_B, + DF_UA | DF_UB | DF_NULL_CHK_1 | DF_REF_A | DF_REF_B | DF_LVN, // 5C IPUT_BOOLEAN vA, vB, field@CCCC - DF_UA | DF_UB | DF_NULL_CHK_1 | DF_REF_B, + DF_UA | DF_UB | DF_NULL_CHK_1 | DF_REF_B | DF_LVN, // 5D IPUT_BYTE vA, vB, field@CCCC - DF_UA | DF_UB | DF_NULL_CHK_1 | DF_REF_B, + DF_UA | DF_UB | DF_NULL_CHK_1 | DF_REF_B | DF_LVN, // 5E IPUT_CHAR vA, vB, field@CCCC - DF_UA | DF_UB | DF_NULL_CHK_1 | DF_REF_B, + DF_UA | DF_UB | DF_NULL_CHK_1 | DF_REF_B | DF_LVN, // 5F IPUT_SHORT vA, vB, field@CCCC - DF_UA | DF_UB | DF_NULL_CHK_1 | DF_REF_B, + DF_UA | DF_UB | DF_NULL_CHK_1 | DF_REF_B | DF_LVN, // 60 SGET vAA, field@BBBB DF_DA | DF_UMS, @@ -712,10 +712,10 @@ const int MIRGraph::oat_data_flow_attributes_[kMirOpLast] = { DF_DA | DF_UB | DF_CORE_A | DF_CORE_B, // E3 IGET_VOLATILE - DF_DA | DF_UB | DF_NULL_CHK_0 | DF_REF_B, + DF_DA | DF_UB | DF_NULL_CHK_0 | DF_REF_B | DF_LVN, // E4 IPUT_VOLATILE - DF_UA | DF_UB | DF_NULL_CHK_1 | DF_REF_B, + DF_UA | DF_UB | DF_NULL_CHK_1 | DF_REF_B | DF_LVN, // E5 SGET_VOLATILE DF_DA | DF_UMS, @@ -724,13 +724,13 @@ const int MIRGraph::oat_data_flow_attributes_[kMirOpLast] = { DF_UA | DF_UMS, // E7 IGET_OBJECT_VOLATILE - DF_DA | DF_UB | DF_NULL_CHK_0 | DF_REF_A | DF_REF_B, + DF_DA | DF_UB | DF_NULL_CHK_0 | DF_REF_A | DF_REF_B | DF_LVN, // E8 IGET_WIDE_VOLATILE - DF_DA | DF_A_WIDE | DF_UB | DF_NULL_CHK_0 | DF_REF_B, + DF_DA | DF_A_WIDE | DF_UB | DF_NULL_CHK_0 | DF_REF_B | DF_LVN, // E9 IPUT_WIDE_VOLATILE - DF_UA | DF_A_WIDE | DF_UB | DF_NULL_CHK_2 | DF_REF_B, + DF_UA | DF_A_WIDE | DF_UB | DF_NULL_CHK_2 | DF_REF_B | DF_LVN, // EA SGET_WIDE_VOLATILE DF_DA | DF_A_WIDE | DF_UMS, @@ -757,22 +757,22 @@ const int MIRGraph::oat_data_flow_attributes_[kMirOpLast] = { DF_NOP, // F2 IGET_QUICK - DF_DA | DF_UB | DF_NULL_CHK_0, + DF_DA | DF_UB | DF_NULL_CHK_0 | DF_LVN, // F3 IGET_WIDE_QUICK - DF_DA | DF_A_WIDE | DF_UB | DF_NULL_CHK_0, + DF_DA | DF_A_WIDE | DF_UB | DF_NULL_CHK_0 | DF_LVN, // F4 IGET_OBJECT_QUICK - DF_DA | DF_UB | DF_NULL_CHK_0, + DF_DA | DF_UB | DF_NULL_CHK_0 | DF_LVN, // F5 IPUT_QUICK - DF_UA | DF_UB | DF_NULL_CHK_1, + DF_UA | DF_UB | DF_NULL_CHK_1 | DF_LVN, // F6 IPUT_WIDE_QUICK - DF_UA | DF_A_WIDE | DF_UB | DF_NULL_CHK_2, + DF_UA | DF_A_WIDE | DF_UB | DF_NULL_CHK_2 | DF_LVN, // F7 IPUT_OBJECT_QUICK - DF_UA | DF_UB | DF_NULL_CHK_1, + DF_UA | DF_UB | DF_NULL_CHK_1 | DF_LVN, // F8 INVOKE_VIRTUAL_QUICK DF_FORMAT_35C | DF_NULL_CHK_OUT0 | DF_UMS, @@ -787,7 +787,7 @@ const int MIRGraph::oat_data_flow_attributes_[kMirOpLast] = { DF_FORMAT_3RC | DF_NULL_CHK_OUT0 | DF_UMS, // FC IPUT_OBJECT_VOLATILE - DF_UA | DF_UB | DF_NULL_CHK_1 | DF_REF_A | DF_REF_B, + DF_UA | DF_UB | DF_NULL_CHK_1 | DF_REF_A | DF_REF_B | DF_LVN, // FD SGET_OBJECT_VOLATILE DF_DA | DF_REF_A | DF_UMS, @@ -879,7 +879,7 @@ bool MIRGraph::FindLocalLiveIn(BasicBlock* bb) { new (arena_) ArenaBitVector(arena_, cu_->num_dalvik_registers, false, kBitMapLiveIn); for (mir = bb->first_mir_insn; mir != NULL; mir = mir->next) { - int df_attributes = oat_data_flow_attributes_[mir->dalvikInsn.opcode]; + uint64_t df_attributes = oat_data_flow_attributes_[mir->dalvikInsn.opcode]; DecodedInstruction *d_insn = &mir->dalvikInsn; if (df_attributes & DF_HAS_USES) { @@ -994,7 +994,7 @@ bool MIRGraph::DoSSAConversion(BasicBlock* bb) { static_cast<struct SSARepresentation *>(arena_->Alloc(sizeof(SSARepresentation), ArenaAllocator::kAllocDFInfo)); - int df_attributes = oat_data_flow_attributes_[mir->dalvikInsn.opcode]; + uint64_t df_attributes = oat_data_flow_attributes_[mir->dalvikInsn.opcode]; // If not a pseudo-op, note non-leaf or can throw if (static_cast<int>(mir->dalvikInsn.opcode) < @@ -1239,37 +1239,33 @@ bool MIRGraph::CountUses(struct BasicBlock* bb) { if (bb->block_type != kDalvikByteCode) { return false; } + // Each level of nesting adds *100 to count, up to 3 levels deep. + uint32_t depth = std::min(3U, static_cast<uint32_t>(bb->nesting_depth)); + uint32_t weight = std::max(1U, depth * 100); for (MIR* mir = bb->first_mir_insn; (mir != NULL); mir = mir->next) { if (mir->ssa_rep == NULL) { continue; } - // Each level of nesting adds *100 to count, up to 3 levels deep. - uint32_t depth = std::min(3U, static_cast<uint32_t>(bb->nesting_depth)); - uint32_t weight = std::max(1U, depth * 100); for (int i = 0; i < mir->ssa_rep->num_uses; i++) { int s_reg = mir->ssa_rep->uses[i]; raw_use_counts_.Increment(s_reg); use_counts_.Put(s_reg, use_counts_.Get(s_reg) + weight); } if (!(cu_->disable_opt & (1 << kPromoteCompilerTemps))) { - int df_attributes = oat_data_flow_attributes_[mir->dalvikInsn.opcode]; + uint64_t df_attributes = oat_data_flow_attributes_[mir->dalvikInsn.opcode]; // Implicit use of Method* ? */ if (df_attributes & DF_UMS) { /* * Some invokes will not use Method* - need to perform test similar * to that found in GenInvoke() to decide whether to count refs - * for Method* on invoke-class opcodes. - * TODO: refactor for common test here, save results for GenInvoke + * for Method* on invoke-class opcodes. This is a relatively expensive + * operation, so should only be done once. + * TODO: refactor InvokeUsesMethodStar() to perform check at parse time, + * and save results for both here and GenInvoke. For now, go ahead + * and assume all invokes use method*. */ - int uses_method_star = true; - if ((df_attributes & (DF_FORMAT_35C | DF_FORMAT_3RC)) && - !(df_attributes & DF_NON_NULL_RET)) { - uses_method_star &= InvokeUsesMethodStar(mir); - } - if (uses_method_star) { - raw_use_counts_.Increment(method_sreg_); - use_counts_.Put(method_sreg_, use_counts_.Get(method_sreg_) + weight); - } + raw_use_counts_.Increment(method_sreg_); + use_counts_.Put(method_sreg_, use_counts_.Get(method_sreg_) + weight); } } } diff --git a/compiler/dex/mir_graph.cc b/compiler/dex/mir_graph.cc index deaf2ffe80..2a18280133 100644 --- a/compiler/dex/mir_graph.cc +++ b/compiler/dex/mir_graph.cc @@ -650,12 +650,16 @@ void MIRGraph::InlineMethod(const DexFile::CodeItem* code_item, uint32_t access_ int flags = Instruction::FlagsOf(insn->dalvikInsn.opcode); - int df_flags = oat_data_flow_attributes_[insn->dalvikInsn.opcode]; + uint64_t df_flags = oat_data_flow_attributes_[insn->dalvikInsn.opcode]; if (df_flags & DF_HAS_DEFS) { def_count_ += (df_flags & DF_A_WIDE) ? 2 : 1; } + if (df_flags & DF_LVN) { + cur_block->use_lvn = true; // Run local value numbering on this basic block. + } + // Check for inline data block signatures if (opcode == Instruction::NOP) { // A simple NOP will have a width of 1 at this point, embedded data NOP > 1. diff --git a/compiler/dex/mir_graph.h b/compiler/dex/mir_graph.h index 8c20728a51..bffec394d6 100644 --- a/compiler/dex/mir_graph.h +++ b/compiler/dex/mir_graph.h @@ -92,41 +92,43 @@ enum DataFlowAttributePos { kRefB, kRefC, kUsesMethodStar, // Implicit use of Method*. + kDoLVN, // Worth computing local value numbers. }; -#define DF_NOP 0 -#define DF_UA (1 << kUA) -#define DF_UB (1 << kUB) -#define DF_UC (1 << kUC) -#define DF_A_WIDE (1 << kAWide) -#define DF_B_WIDE (1 << kBWide) -#define DF_C_WIDE (1 << kCWide) -#define DF_DA (1 << kDA) -#define DF_IS_MOVE (1 << kIsMove) -#define DF_SETS_CONST (1 << kSetsConst) -#define DF_FORMAT_35C (1 << kFormat35c) -#define DF_FORMAT_3RC (1 << kFormat3rc) -#define DF_NULL_CHK_0 (1 << kNullCheckSrc0) -#define DF_NULL_CHK_1 (1 << kNullCheckSrc1) -#define DF_NULL_CHK_2 (1 << kNullCheckSrc2) -#define DF_NULL_CHK_OUT0 (1 << kNullCheckOut0) -#define DF_NON_NULL_DST (1 << kDstNonNull) -#define DF_NON_NULL_RET (1 << kRetNonNull) -#define DF_NULL_TRANSFER_0 (1 << kNullTransferSrc0) -#define DF_NULL_TRANSFER_N (1 << kNullTransferSrcN) -#define DF_RANGE_CHK_1 (1 << kRangeCheckSrc1) -#define DF_RANGE_CHK_2 (1 << kRangeCheckSrc2) -#define DF_RANGE_CHK_3 (1 << kRangeCheckSrc3) -#define DF_FP_A (1 << kFPA) -#define DF_FP_B (1 << kFPB) -#define DF_FP_C (1 << kFPC) -#define DF_CORE_A (1 << kCoreA) -#define DF_CORE_B (1 << kCoreB) -#define DF_CORE_C (1 << kCoreC) -#define DF_REF_A (1 << kRefA) -#define DF_REF_B (1 << kRefB) -#define DF_REF_C (1 << kRefC) -#define DF_UMS (1 << kUsesMethodStar) +#define DF_NOP 0ULL +#define DF_UA (1ULL << kUA) +#define DF_UB (1ULL << kUB) +#define DF_UC (1ULL << kUC) +#define DF_A_WIDE (1ULL << kAWide) +#define DF_B_WIDE (1ULL << kBWide) +#define DF_C_WIDE (1ULL << kCWide) +#define DF_DA (1ULL << kDA) +#define DF_IS_MOVE (1ULL << kIsMove) +#define DF_SETS_CONST (1ULL << kSetsConst) +#define DF_FORMAT_35C (1ULL << kFormat35c) +#define DF_FORMAT_3RC (1ULL << kFormat3rc) +#define DF_NULL_CHK_0 (1ULL << kNullCheckSrc0) +#define DF_NULL_CHK_1 (1ULL << kNullCheckSrc1) +#define DF_NULL_CHK_2 (1ULL << kNullCheckSrc2) +#define DF_NULL_CHK_OUT0 (1ULL << kNullCheckOut0) +#define DF_NON_NULL_DST (1ULL << kDstNonNull) +#define DF_NON_NULL_RET (1ULL << kRetNonNull) +#define DF_NULL_TRANSFER_0 (1ULL << kNullTransferSrc0) +#define DF_NULL_TRANSFER_N (1ULL << kNullTransferSrcN) +#define DF_RANGE_CHK_1 (1ULL << kRangeCheckSrc1) +#define DF_RANGE_CHK_2 (1ULL << kRangeCheckSrc2) +#define DF_RANGE_CHK_3 (1ULL << kRangeCheckSrc3) +#define DF_FP_A (1ULL << kFPA) +#define DF_FP_B (1ULL << kFPB) +#define DF_FP_C (1ULL << kFPC) +#define DF_CORE_A (1ULL << kCoreA) +#define DF_CORE_B (1ULL << kCoreB) +#define DF_CORE_C (1ULL << kCoreC) +#define DF_REF_A (1ULL << kRefA) +#define DF_REF_B (1ULL << kRefB) +#define DF_REF_C (1ULL << kRefC) +#define DF_UMS (1ULL << kUsesMethodStar) +#define DF_LVN (1ULL << kDoLVN) #define DF_HAS_USES (DF_UA | DF_UB | DF_UC) @@ -273,8 +275,9 @@ struct BasicBlock { bool catch_entry:1; bool explicit_throw:1; bool conditional_branch:1; - bool terminated_by_return:1; // Block ends with a Dalvik return opcode. - bool dominates_return:1; // Is a member of return extended basic block. + bool terminated_by_return:1; // Block ends with a Dalvik return opcode. + bool dominates_return:1; // Is a member of return extended basic block. + bool use_lvn:1; // Run local value numbering on this block. MIR* first_mir_insn; MIR* last_mir_insn; BasicBlockDataFlow* data_flow_info; @@ -451,7 +454,9 @@ class MIRGraph { void DumpCFG(const char* dir_prefix, bool all_blocks); - void BuildRegLocations(); + void InitRegLocations(); + + void RemapRegLocations(); void DumpRegLocTable(RegLocation* table, int count); @@ -619,7 +624,7 @@ class MIRGraph { void MethodUseCount(); void SSATransformation(); void CheckForDominanceFrontier(BasicBlock* dom_bb, const BasicBlock* succ_bb); - void NullCheckElimination(); + void NullCheckEliminationAndTypeInference(); /* * Type inference handling helpers. Because Dalvik's bytecode is not fully typed, * we have to do some work to figure out the sreg type. For some operations it is @@ -675,7 +680,7 @@ class MIRGraph { GrowableArray<CompilerTemp*> compiler_temps_; SafeMap<unsigned int, unsigned int> block_id_map_; // Block collapse lookup cache. - static const int oat_data_flow_attributes_[kMirOpLast]; + static const uint64_t oat_data_flow_attributes_[kMirOpLast]; static const char* extended_mir_op_names_[kMirOpLast - kMirOpFirst]; static const uint32_t analysis_attributes_[kMirOpLast]; @@ -711,7 +716,7 @@ class MIRGraph { bool FindLocalLiveIn(BasicBlock* bb); void ClearAllVisitedFlags(); bool CountUses(struct BasicBlock* bb); - bool InferTypeAndSize(BasicBlock* bb); + bool InferTypeAndSize(BasicBlock* bb, MIR* mir, bool changed); bool VerifyPredInfo(BasicBlock* bb); BasicBlock* NeedsVisit(BasicBlock* bb); BasicBlock* NextUnvisitedSuccessor(BasicBlock* bb); @@ -727,7 +732,7 @@ class MIRGraph { void SetConstantWide(int ssa_reg, int64_t value); int GetSSAUseCount(int s_reg); bool BasicBlockOpt(BasicBlock* bb); - bool EliminateNullChecks(BasicBlock* bb); + bool EliminateNullChecksAndInferTypes(BasicBlock* bb); void NullCheckEliminationInit(BasicBlock* bb); bool BuildExtendedBBList(struct BasicBlock* bb); bool FillDefBlockMatrix(BasicBlock* bb); diff --git a/compiler/dex/mir_optimization.cc b/compiler/dex/mir_optimization.cc index f5913a5ad4..635393796a 100644 --- a/compiler/dex/mir_optimization.cc +++ b/compiler/dex/mir_optimization.cc @@ -40,7 +40,7 @@ void MIRGraph::DoConstantPropogation(BasicBlock* bb) { MIR* mir; for (mir = bb->first_mir_insn; mir != NULL; mir = mir->next) { - int df_attributes = oat_data_flow_attributes_[mir->dalvikInsn.opcode]; + uint64_t df_attributes = oat_data_flow_attributes_[mir->dalvikInsn.opcode]; DecodedInstruction *d_insn = &mir->dalvikInsn; @@ -155,7 +155,7 @@ BasicBlock* MIRGraph::NextDominatedBlock(BasicBlock* bb) { || (bb->block_type == kExitBlock)); BasicBlock* bb_taken = GetBasicBlock(bb->taken); BasicBlock* bb_fall_through = GetBasicBlock(bb->fall_through); - if (((bb_taken != NULL) && (bb_fall_through == NULL)) && + if (((bb_fall_through == NULL) && (bb_taken != NULL)) && ((bb_taken->block_type == kDalvikByteCode) || (bb_taken->block_type == kExitBlock))) { // Follow simple unconditional branches. bb = bb_taken; @@ -216,11 +216,17 @@ bool MIRGraph::BasicBlockOpt(BasicBlock* bb) { return true; } int num_temps = 0; - LocalValueNumbering local_valnum(cu_); + bool use_lvn = bb->use_lvn; + UniquePtr<LocalValueNumbering> local_valnum; + if (use_lvn) { + local_valnum.reset(new LocalValueNumbering(cu_)); + } while (bb != NULL) { for (MIR* mir = bb->first_mir_insn; mir != NULL; mir = mir->next) { // TUNING: use the returned value number for CSE. - local_valnum.GetValueNumber(mir); + if (use_lvn) { + local_valnum->GetValueNumber(mir); + } // Look for interesting opcodes, skip otherwise Instruction::Code opcode = mir->dalvikInsn.opcode; switch (opcode) { @@ -463,7 +469,7 @@ bool MIRGraph::BasicBlockOpt(BasicBlock* bb) { } } } - bb = NextDominatedBlock(bb); + bb = ((cu_->disable_opt & (1 << kSuppressExceptionEdges)) != 0) ? NextDominatedBlock(bb) : NULL; } if (num_temps > cu_->num_compiler_temps) { @@ -486,7 +492,7 @@ void MIRGraph::CountChecks(struct BasicBlock* bb) { if (mir->ssa_rep == NULL) { continue; } - int df_attributes = oat_data_flow_attributes_[mir->dalvikInsn.opcode]; + uint64_t df_attributes = oat_data_flow_attributes_[mir->dalvikInsn.opcode]; if (df_attributes & DF_HAS_NULL_CHKS) { checkstats_->null_checks++; if (mir->optimization_flags & MIR_IGNORE_NULL_CHECK) { @@ -571,7 +577,7 @@ bool MIRGraph::CombineBlocks(struct BasicBlock* bb) { MIR* mir = bb->last_mir_insn; // Grab the attributes from the paired opcode MIR* throw_insn = mir->meta.throw_insn; - int df_attributes = oat_data_flow_attributes_[throw_insn->dalvikInsn.opcode]; + uint64_t df_attributes = oat_data_flow_attributes_[throw_insn->dalvikInsn.opcode]; bool can_combine = true; if (df_attributes & DF_HAS_NULL_CHKS) { can_combine &= ((throw_insn->optimization_flags & MIR_IGNORE_NULL_CHECK) != 0); @@ -618,74 +624,87 @@ bool MIRGraph::CombineBlocks(struct BasicBlock* bb) { return false; } -/* Eliminate unnecessary null checks for a basic block. */ -bool MIRGraph::EliminateNullChecks(struct BasicBlock* bb) { +/* + * Eliminate unnecessary null checks for a basic block. Also, while we're doing + * an iterative walk go ahead and perform type and size inference. + */ +bool MIRGraph::EliminateNullChecksAndInferTypes(struct BasicBlock* bb) { if (bb->data_flow_info == NULL) return false; + bool infer_changed = false; + bool do_nce = ((cu_->disable_opt & (1 << kNullCheckElimination)) == 0); - /* - * Set initial state. Be conservative with catch - * blocks and start with no assumptions about null check - * status (except for "this"). - */ - if ((bb->block_type == kEntryBlock) | bb->catch_entry) { - temp_ssa_register_v_->ClearAllBits(); - // Assume all ins are objects. - for (uint16_t in_reg = cu_->num_dalvik_registers - cu_->num_ins; - in_reg < cu_->num_dalvik_registers; in_reg++) { - temp_ssa_register_v_->SetBit(in_reg); - } - if ((cu_->access_flags & kAccStatic) == 0) { - // If non-static method, mark "this" as non-null - int this_reg = cu_->num_dalvik_registers - cu_->num_ins; - temp_ssa_register_v_->ClearBit(this_reg); - } - } else if (bb->predecessors->Size() == 1) { - BasicBlock* pred_bb = GetBasicBlock(bb->predecessors->Get(0)); - temp_ssa_register_v_->Copy(pred_bb->data_flow_info->ending_null_check_v); - if (pred_bb->block_type == kDalvikByteCode) { - // Check to see if predecessor had an explicit null-check. - MIR* last_insn = pred_bb->last_mir_insn; - Instruction::Code last_opcode = last_insn->dalvikInsn.opcode; - if (last_opcode == Instruction::IF_EQZ) { - if (pred_bb->fall_through == bb->id) { - // The fall-through of a block following a IF_EQZ, set the vA of the IF_EQZ to show that - // it can't be null. - temp_ssa_register_v_->ClearBit(last_insn->ssa_rep->uses[0]); - } - } else if (last_opcode == Instruction::IF_NEZ) { - if (pred_bb->taken == bb->id) { - // The taken block following a IF_NEZ, set the vA of the IF_NEZ to show that it can't be - // null. - temp_ssa_register_v_->ClearBit(last_insn->ssa_rep->uses[0]); + if (do_nce) { + /* + * Set initial state. Be conservative with catch + * blocks and start with no assumptions about null check + * status (except for "this"). + */ + if ((bb->block_type == kEntryBlock) | bb->catch_entry) { + temp_ssa_register_v_->ClearAllBits(); + // Assume all ins are objects. + for (uint16_t in_reg = cu_->num_dalvik_registers - cu_->num_ins; + in_reg < cu_->num_dalvik_registers; in_reg++) { + temp_ssa_register_v_->SetBit(in_reg); + } + if ((cu_->access_flags & kAccStatic) == 0) { + // If non-static method, mark "this" as non-null + int this_reg = cu_->num_dalvik_registers - cu_->num_ins; + temp_ssa_register_v_->ClearBit(this_reg); + } + } else if (bb->predecessors->Size() == 1) { + BasicBlock* pred_bb = GetBasicBlock(bb->predecessors->Get(0)); + temp_ssa_register_v_->Copy(pred_bb->data_flow_info->ending_null_check_v); + if (pred_bb->block_type == kDalvikByteCode) { + // Check to see if predecessor had an explicit null-check. + MIR* last_insn = pred_bb->last_mir_insn; + Instruction::Code last_opcode = last_insn->dalvikInsn.opcode; + if (last_opcode == Instruction::IF_EQZ) { + if (pred_bb->fall_through == bb->id) { + // The fall-through of a block following a IF_EQZ, set the vA of the IF_EQZ to show that + // it can't be null. + temp_ssa_register_v_->ClearBit(last_insn->ssa_rep->uses[0]); + } + } else if (last_opcode == Instruction::IF_NEZ) { + if (pred_bb->taken == bb->id) { + // The taken block following a IF_NEZ, set the vA of the IF_NEZ to show that it can't be + // null. + temp_ssa_register_v_->ClearBit(last_insn->ssa_rep->uses[0]); + } } } - } - } else { - // Starting state is union of all incoming arcs - GrowableArray<BasicBlockId>::Iterator iter(bb->predecessors); - BasicBlock* pred_bb = GetBasicBlock(iter.Next()); - DCHECK(pred_bb != NULL); - temp_ssa_register_v_->Copy(pred_bb->data_flow_info->ending_null_check_v); - while (true) { - pred_bb = GetBasicBlock(iter.Next()); - if (!pred_bb) break; - if ((pred_bb->data_flow_info == NULL) || - (pred_bb->data_flow_info->ending_null_check_v == NULL)) { - continue; + } else { + // Starting state is union of all incoming arcs + GrowableArray<BasicBlockId>::Iterator iter(bb->predecessors); + BasicBlock* pred_bb = GetBasicBlock(iter.Next()); + DCHECK(pred_bb != NULL); + temp_ssa_register_v_->Copy(pred_bb->data_flow_info->ending_null_check_v); + while (true) { + pred_bb = GetBasicBlock(iter.Next()); + if (!pred_bb) break; + if ((pred_bb->data_flow_info == NULL) || + (pred_bb->data_flow_info->ending_null_check_v == NULL)) { + continue; + } + temp_ssa_register_v_->Union(pred_bb->data_flow_info->ending_null_check_v); } - temp_ssa_register_v_->Union(pred_bb->data_flow_info->ending_null_check_v); } + // At this point, temp_ssa_register_v_ shows which sregs have an object definition with + // no intervening uses. } - // At this point, temp_ssa_register_v_ shows which sregs have an object definition with - // no intervening uses. - // Walk through the instruction in the block, updating as necessary for (MIR* mir = bb->first_mir_insn; mir != NULL; mir = mir->next) { if (mir->ssa_rep == NULL) { continue; } - int df_attributes = oat_data_flow_attributes_[mir->dalvikInsn.opcode]; + + // Propagate type info. + infer_changed = InferTypeAndSize(bb, mir, infer_changed); + if (!do_nce) { + continue; + } + + uint64_t df_attributes = oat_data_flow_attributes_[mir->dalvikInsn.opcode]; // Might need a null check? if (df_attributes & DF_HAS_NULL_CHKS) { @@ -784,25 +803,25 @@ bool MIRGraph::EliminateNullChecks(struct BasicBlock* bb) { } // Did anything change? - bool changed = !temp_ssa_register_v_->Equal(bb->data_flow_info->ending_null_check_v); - if (changed) { + bool nce_changed = do_nce && !temp_ssa_register_v_->Equal(bb->data_flow_info->ending_null_check_v); + if (nce_changed) { bb->data_flow_info->ending_null_check_v->Copy(temp_ssa_register_v_); } - return changed; + return infer_changed | nce_changed; } -void MIRGraph::NullCheckElimination() { - if (!(cu_->disable_opt & (1 << kNullCheckElimination))) { - DCHECK(temp_ssa_register_v_ != NULL); +void MIRGraph::NullCheckEliminationAndTypeInference() { + DCHECK(temp_ssa_register_v_ != NULL); + if ((cu_->disable_opt & (1 << kNullCheckElimination)) == 0) { AllNodesIterator iter(this); for (BasicBlock* bb = iter.Next(); bb != NULL; bb = iter.Next()) { NullCheckEliminationInit(bb); } - RepeatingPreOrderDfsIterator iter2(this); - bool change = false; - for (BasicBlock* bb = iter2.Next(change); bb != NULL; bb = iter2.Next(change)) { - change = EliminateNullChecks(bb); - } + } + RepeatingPreOrderDfsIterator iter2(this); + bool change = false; + for (BasicBlock* bb = iter2.Next(change); bb != NULL; bb = iter2.Next(change)) { + change = EliminateNullChecksAndInferTypes(bb); } if (cu_->enable_debug & (1 << kDebugDumpCFG)) { DumpCFG("/sdcard/4_post_nce_cfg/", false); @@ -810,12 +829,14 @@ void MIRGraph::NullCheckElimination() { } void MIRGraph::BasicBlockCombine() { - PreOrderDfsIterator iter(this); - for (BasicBlock* bb = iter.Next(); bb != NULL; bb = iter.Next()) { - CombineBlocks(bb); - } - if (cu_->enable_debug & (1 << kDebugDumpCFG)) { - DumpCFG("/sdcard/5_post_bbcombine_cfg/", false); + if ((cu_->disable_opt & (1 << kSuppressExceptionEdges)) != 0) { + PreOrderDfsIterator iter(this); + for (BasicBlock* bb = iter.Next(); bb != NULL; bb = iter.Next()) { + CombineBlocks(bb); + } + if (cu_->enable_debug & (1 << kDebugDumpCFG)) { + DumpCFG("/sdcard/5_post_bbcombine_cfg/", false); + } } } @@ -868,17 +889,20 @@ bool MIRGraph::BuildExtendedBBList(struct BasicBlock* bb) { BasicBlock* start_bb = bb; extended_basic_blocks_.push_back(bb->id); bool terminated_by_return = false; + bool do_local_value_numbering = false; // Visit blocks strictly dominated by this head. while (bb != NULL) { bb->visited = true; terminated_by_return |= bb->terminated_by_return; + do_local_value_numbering |= bb->use_lvn; bb = NextDominatedBlock(bb); } - if (terminated_by_return) { - // This extended basic block contains a return, so mark all members. + if (terminated_by_return || do_local_value_numbering) { + // Do lvn for all blocks in this extended set. bb = start_bb; while (bb != NULL) { - bb->dominates_return = true; + bb->use_lvn = do_local_value_numbering; + bb->dominates_return = terminated_by_return; bb = NextDominatedBlock(bb); } } @@ -889,14 +913,21 @@ bool MIRGraph::BuildExtendedBBList(struct BasicBlock* bb) { void MIRGraph::BasicBlockOptimization() { if (!(cu_->disable_opt & (1 << kBBOpt))) { DCHECK_EQ(cu_->num_compiler_temps, 0); - ClearAllVisitedFlags(); - PreOrderDfsIterator iter2(this); - for (BasicBlock* bb = iter2.Next(); bb != NULL; bb = iter2.Next()) { - BuildExtendedBBList(bb); + if ((cu_->disable_opt & (1 << kSuppressExceptionEdges)) != 0) { + ClearAllVisitedFlags(); + PreOrderDfsIterator iter2(this); + for (BasicBlock* bb = iter2.Next(); bb != NULL; bb = iter2.Next()) { + BuildExtendedBBList(bb); + } + // Perform extended basic block optimizations. + for (unsigned int i = 0; i < extended_basic_blocks_.size(); i++) { + BasicBlockOpt(GetBasicBlock(extended_basic_blocks_[i])); + } } - // Perform extended basic block optimizations. - for (unsigned int i = 0; i < extended_basic_blocks_.size(); i++) { - BasicBlockOpt(GetBasicBlock(extended_basic_blocks_[i])); + } else { + PreOrderDfsIterator iter(this); + for (BasicBlock* bb = iter.Next(); bb != NULL; bb = iter.Next()) { + BasicBlockOpt(bb); } } if (cu_->enable_debug & (1 << kDebugDumpCFG)) { diff --git a/compiler/dex/portable/mir_to_gbc.cc b/compiler/dex/portable/mir_to_gbc.cc index 07bd2aa979..e5b4876f08 100644 --- a/compiler/dex/portable/mir_to_gbc.cc +++ b/compiler/dex/portable/mir_to_gbc.cc @@ -705,7 +705,7 @@ bool MirConverter::ConvertMIRNode(MIR* mir, BasicBlock* bb, /* Prep Src and Dest locations */ int next_sreg = 0; int next_loc = 0; - int attrs = mir_graph_->oat_data_flow_attributes_[opcode]; + uint64_t attrs = mir_graph_->oat_data_flow_attributes_[opcode]; rl_src[0] = rl_src[1] = rl_src[2] = mir_graph_->GetBadLoc(); if (attrs & DF_UA) { if (attrs & DF_A_WIDE) { diff --git a/compiler/dex/quick/arm/assemble_arm.cc b/compiler/dex/quick/arm/assemble_arm.cc index b3236ae23e..820b3aa24e 100644 --- a/compiler/dex/quick/arm/assemble_arm.cc +++ b/compiler/dex/quick/arm/assemble_arm.cc @@ -1615,7 +1615,6 @@ void ArmMir2Lir::AssembleLIR() { data_offset_ = (code_buffer_.size() + 0x3) & ~0x3; - cu_->NewTimingSplit("LiteralData"); // Install literals InstallLiteralPools(); diff --git a/compiler/dex/quick/local_optimizations.cc b/compiler/dex/quick/local_optimizations.cc index 0f29578c4e..7a2dce13dc 100644 --- a/compiler/dex/quick/local_optimizations.cc +++ b/compiler/dex/quick/local_optimizations.cc @@ -291,9 +291,9 @@ void Mir2Lir::ApplyLoadHoisting(LIR* head_lir, LIR* tail_lir) { uint64_t target_flags = GetTargetInstFlags(this_lir->opcode); /* Skip non-interesting instructions */ - if ((this_lir->flags.is_nop == true) || - ((target_flags & (REG_DEF0 | REG_DEF1)) == (REG_DEF0 | REG_DEF1)) || - !(target_flags & IS_LOAD)) { + if (!(target_flags & IS_LOAD) || + (this_lir->flags.is_nop == true) || + ((target_flags & (REG_DEF0 | REG_DEF1)) == (REG_DEF0 | REG_DEF1))) { continue; } diff --git a/compiler/dex/quick/mips/assemble_mips.cc b/compiler/dex/quick/mips/assemble_mips.cc index 5f5e5e44ac..bd3355f8da 100644 --- a/compiler/dex/quick/mips/assemble_mips.cc +++ b/compiler/dex/quick/mips/assemble_mips.cc @@ -793,7 +793,6 @@ void MipsMir2Lir::AssembleLIR() { } // Install literals - cu_->NewTimingSplit("LiteralData"); InstallLiteralPools(); // Install switch tables diff --git a/compiler/dex/quick/mir_to_lir.cc b/compiler/dex/quick/mir_to_lir.cc index fa9a3ad566..19d04be6df 100644 --- a/compiler/dex/quick/mir_to_lir.cc +++ b/compiler/dex/quick/mir_to_lir.cc @@ -39,7 +39,7 @@ void Mir2Lir::CompileDalvikInstruction(MIR* mir, BasicBlock* bb, LIR* label_list // Prep Src and Dest locations. int next_sreg = 0; int next_loc = 0; - int attrs = mir_graph_->oat_data_flow_attributes_[opcode]; + uint64_t attrs = mir_graph_->oat_data_flow_attributes_[opcode]; rl_src[0] = rl_src[1] = rl_src[2] = mir_graph_->GetBadLoc(); if (attrs & DF_UA) { if (attrs & DF_A_WIDE) { diff --git a/compiler/dex/quick/x86/assemble_x86.cc b/compiler/dex/quick/x86/assemble_x86.cc index 2047f30765..191c9c701b 100644 --- a/compiler/dex/quick/x86/assemble_x86.cc +++ b/compiler/dex/quick/x86/assemble_x86.cc @@ -1503,7 +1503,6 @@ void X86Mir2Lir::AssembleLIR() { } } - cu_->NewTimingSplit("LiteralData"); // Install literals InstallLiteralPools(); diff --git a/compiler/dex/vreg_analysis.cc b/compiler/dex/vreg_analysis.cc index 32fac0b393..bef966c8ff 100644 --- a/compiler/dex/vreg_analysis.cc +++ b/compiler/dex/vreg_analysis.cc @@ -121,260 +121,251 @@ bool MIRGraph::SetHigh(int index) { * as it doesn't propagate. We're guaranteed at least one pass through * the cfg. */ -bool MIRGraph::InferTypeAndSize(BasicBlock* bb) { - MIR *mir; - bool changed = false; // Did anything change? - - if (bb->data_flow_info == NULL) return false; - if (bb->block_type != kDalvikByteCode && bb->block_type != kEntryBlock) - return false; - - for (mir = bb->first_mir_insn; mir != NULL; mir = mir->next) { - SSARepresentation *ssa_rep = mir->ssa_rep; - if (ssa_rep) { - int attrs = oat_data_flow_attributes_[mir->dalvikInsn.opcode]; - const int* uses = ssa_rep->uses; - const int* defs = ssa_rep->defs; +bool MIRGraph::InferTypeAndSize(BasicBlock* bb, MIR* mir, bool changed) { + SSARepresentation *ssa_rep = mir->ssa_rep; + if (ssa_rep) { + uint64_t attrs = oat_data_flow_attributes_[mir->dalvikInsn.opcode]; + const int* uses = ssa_rep->uses; + const int* defs = ssa_rep->defs; + + // Handle defs + if (attrs & DF_DA) { + if (attrs & DF_CORE_A) { + changed |= SetCore(defs[0]); + } + if (attrs & DF_REF_A) { + changed |= SetRef(defs[0]); + } + if (attrs & DF_A_WIDE) { + reg_location_[defs[0]].wide = true; + reg_location_[defs[1]].wide = true; + reg_location_[defs[1]].high_word = true; + DCHECK_EQ(SRegToVReg(defs[0])+1, + SRegToVReg(defs[1])); + } + } - // Handle defs - if (attrs & DF_DA) { - if (attrs & DF_CORE_A) { - changed |= SetCore(defs[0]); - } - if (attrs & DF_REF_A) { - changed |= SetRef(defs[0]); - } - if (attrs & DF_A_WIDE) { - reg_location_[defs[0]].wide = true; - reg_location_[defs[1]].wide = true; - reg_location_[defs[1]].high_word = true; - DCHECK_EQ(SRegToVReg(defs[0])+1, - SRegToVReg(defs[1])); - } + // Handles uses + int next = 0; + if (attrs & DF_UA) { + if (attrs & DF_CORE_A) { + changed |= SetCore(uses[next]); + } + if (attrs & DF_REF_A) { + changed |= SetRef(uses[next]); + } + if (attrs & DF_A_WIDE) { + reg_location_[uses[next]].wide = true; + reg_location_[uses[next + 1]].wide = true; + reg_location_[uses[next + 1]].high_word = true; + DCHECK_EQ(SRegToVReg(uses[next])+1, + SRegToVReg(uses[next + 1])); + next += 2; + } else { + next++; + } + } + if (attrs & DF_UB) { + if (attrs & DF_CORE_B) { + changed |= SetCore(uses[next]); + } + if (attrs & DF_REF_B) { + changed |= SetRef(uses[next]); + } + if (attrs & DF_B_WIDE) { + reg_location_[uses[next]].wide = true; + reg_location_[uses[next + 1]].wide = true; + reg_location_[uses[next + 1]].high_word = true; + DCHECK_EQ(SRegToVReg(uses[next])+1, + SRegToVReg(uses[next + 1])); + next += 2; + } else { + next++; + } + } + if (attrs & DF_UC) { + if (attrs & DF_CORE_C) { + changed |= SetCore(uses[next]); + } + if (attrs & DF_REF_C) { + changed |= SetRef(uses[next]); } + if (attrs & DF_C_WIDE) { + reg_location_[uses[next]].wide = true; + reg_location_[uses[next + 1]].wide = true; + reg_location_[uses[next + 1]].high_word = true; + DCHECK_EQ(SRegToVReg(uses[next])+1, + SRegToVReg(uses[next + 1])); + } + } - // Handles uses - int next = 0; - if (attrs & DF_UA) { - if (attrs & DF_CORE_A) { - changed |= SetCore(uses[next]); - } - if (attrs & DF_REF_A) { - changed |= SetRef(uses[next]); - } - if (attrs & DF_A_WIDE) { - reg_location_[uses[next]].wide = true; - reg_location_[uses[next + 1]].wide = true; - reg_location_[uses[next + 1]].high_word = true; - DCHECK_EQ(SRegToVReg(uses[next])+1, - SRegToVReg(uses[next + 1])); - next += 2; - } else { - next++; - } + // Special-case return handling + if ((mir->dalvikInsn.opcode == Instruction::RETURN) || + (mir->dalvikInsn.opcode == Instruction::RETURN_WIDE) || + (mir->dalvikInsn.opcode == Instruction::RETURN_OBJECT)) { + switch (cu_->shorty[0]) { + case 'I': + changed |= SetCore(uses[0]); + break; + case 'J': + changed |= SetCore(uses[0]); + changed |= SetCore(uses[1]); + reg_location_[uses[0]].wide = true; + reg_location_[uses[1]].wide = true; + reg_location_[uses[1]].high_word = true; + break; + case 'F': + changed |= SetFp(uses[0]); + break; + case 'D': + changed |= SetFp(uses[0]); + changed |= SetFp(uses[1]); + reg_location_[uses[0]].wide = true; + reg_location_[uses[1]].wide = true; + reg_location_[uses[1]].high_word = true; + break; + case 'L': + changed |= SetRef(uses[0]); + break; + default: break; } - if (attrs & DF_UB) { - if (attrs & DF_CORE_B) { - changed |= SetCore(uses[next]); - } - if (attrs & DF_REF_B) { - changed |= SetRef(uses[next]); - } - if (attrs & DF_B_WIDE) { - reg_location_[uses[next]].wide = true; - reg_location_[uses[next + 1]].wide = true; - reg_location_[uses[next + 1]].high_word = true; - DCHECK_EQ(SRegToVReg(uses[next])+1, - SRegToVReg(uses[next + 1])); - next += 2; - } else { - next++; + } + + // Special-case handling for format 35c/3rc invokes + Instruction::Code opcode = mir->dalvikInsn.opcode; + int flags = (static_cast<int>(opcode) >= kNumPackedOpcodes) + ? 0 : Instruction::FlagsOf(mir->dalvikInsn.opcode); + if ((flags & Instruction::kInvoke) && + (attrs & (DF_FORMAT_35C | DF_FORMAT_3RC))) { + DCHECK_EQ(next, 0); + int target_idx = mir->dalvikInsn.vB; + const char* shorty = GetShortyFromTargetIdx(target_idx); + // Handle result type if floating point + if ((shorty[0] == 'F') || (shorty[0] == 'D')) { + MIR* move_result_mir = FindMoveResult(bb, mir); + // Result might not be used at all, so no move-result + if (move_result_mir && (move_result_mir->dalvikInsn.opcode != + Instruction::MOVE_RESULT_OBJECT)) { + SSARepresentation* tgt_rep = move_result_mir->ssa_rep; + DCHECK(tgt_rep != NULL); + tgt_rep->fp_def[0] = true; + changed |= SetFp(tgt_rep->defs[0]); + if (shorty[0] == 'D') { + tgt_rep->fp_def[1] = true; + changed |= SetFp(tgt_rep->defs[1]); + } } } - if (attrs & DF_UC) { - if (attrs & DF_CORE_C) { - changed |= SetCore(uses[next]); - } - if (attrs & DF_REF_C) { - changed |= SetRef(uses[next]); - } - if (attrs & DF_C_WIDE) { - reg_location_[uses[next]].wide = true; - reg_location_[uses[next + 1]].wide = true; - reg_location_[uses[next + 1]].high_word = true; - DCHECK_EQ(SRegToVReg(uses[next])+1, - SRegToVReg(uses[next + 1])); - } + int num_uses = mir->dalvikInsn.vA; + // If this is a non-static invoke, mark implicit "this" + if (((mir->dalvikInsn.opcode != Instruction::INVOKE_STATIC) && + (mir->dalvikInsn.opcode != Instruction::INVOKE_STATIC_RANGE))) { + reg_location_[uses[next]].defined = true; + reg_location_[uses[next]].ref = true; + next++; } - - // Special-case return handling - if ((mir->dalvikInsn.opcode == Instruction::RETURN) || - (mir->dalvikInsn.opcode == Instruction::RETURN_WIDE) || - (mir->dalvikInsn.opcode == Instruction::RETURN_OBJECT)) { - switch (cu_->shorty[0]) { - case 'I': - changed |= SetCore(uses[0]); + uint32_t cpos = 1; + if (strlen(shorty) > 1) { + for (int i = next; i < num_uses;) { + DCHECK_LT(cpos, strlen(shorty)); + switch (shorty[cpos++]) { + case 'D': + ssa_rep->fp_use[i] = true; + ssa_rep->fp_use[i+1] = true; + reg_location_[uses[i]].wide = true; + reg_location_[uses[i+1]].wide = true; + reg_location_[uses[i+1]].high_word = true; + DCHECK_EQ(SRegToVReg(uses[i])+1, SRegToVReg(uses[i+1])); + i++; break; case 'J': - changed |= SetCore(uses[0]); - changed |= SetCore(uses[1]); - reg_location_[uses[0]].wide = true; - reg_location_[uses[1]].wide = true; - reg_location_[uses[1]].high_word = true; + reg_location_[uses[i]].wide = true; + reg_location_[uses[i+1]].wide = true; + reg_location_[uses[i+1]].high_word = true; + DCHECK_EQ(SRegToVReg(uses[i])+1, SRegToVReg(uses[i+1])); + changed |= SetCore(uses[i]); + i++; break; case 'F': - changed |= SetFp(uses[0]); - break; - case 'D': - changed |= SetFp(uses[0]); - changed |= SetFp(uses[1]); - reg_location_[uses[0]].wide = true; - reg_location_[uses[1]].wide = true; - reg_location_[uses[1]].high_word = true; + ssa_rep->fp_use[i] = true; break; case 'L': - changed |= SetRef(uses[0]); + changed |= SetRef(uses[i]); + break; + default: + changed |= SetCore(uses[i]); break; - default: break; - } - } - - // Special-case handling for format 35c/3rc invokes - Instruction::Code opcode = mir->dalvikInsn.opcode; - int flags = (static_cast<int>(opcode) >= kNumPackedOpcodes) - ? 0 : Instruction::FlagsOf(mir->dalvikInsn.opcode); - if ((flags & Instruction::kInvoke) && - (attrs & (DF_FORMAT_35C | DF_FORMAT_3RC))) { - DCHECK_EQ(next, 0); - int target_idx = mir->dalvikInsn.vB; - const char* shorty = GetShortyFromTargetIdx(target_idx); - // Handle result type if floating point - if ((shorty[0] == 'F') || (shorty[0] == 'D')) { - MIR* move_result_mir = FindMoveResult(bb, mir); - // Result might not be used at all, so no move-result - if (move_result_mir && (move_result_mir->dalvikInsn.opcode != - Instruction::MOVE_RESULT_OBJECT)) { - SSARepresentation* tgt_rep = move_result_mir->ssa_rep; - DCHECK(tgt_rep != NULL); - tgt_rep->fp_def[0] = true; - changed |= SetFp(tgt_rep->defs[0]); - if (shorty[0] == 'D') { - tgt_rep->fp_def[1] = true; - changed |= SetFp(tgt_rep->defs[1]); - } - } - } - int num_uses = mir->dalvikInsn.vA; - // If this is a non-static invoke, mark implicit "this" - if (((mir->dalvikInsn.opcode != Instruction::INVOKE_STATIC) && - (mir->dalvikInsn.opcode != Instruction::INVOKE_STATIC_RANGE))) { - reg_location_[uses[next]].defined = true; - reg_location_[uses[next]].ref = true; - next++; - } - uint32_t cpos = 1; - if (strlen(shorty) > 1) { - for (int i = next; i < num_uses;) { - DCHECK_LT(cpos, strlen(shorty)); - switch (shorty[cpos++]) { - case 'D': - ssa_rep->fp_use[i] = true; - ssa_rep->fp_use[i+1] = true; - reg_location_[uses[i]].wide = true; - reg_location_[uses[i+1]].wide = true; - reg_location_[uses[i+1]].high_word = true; - DCHECK_EQ(SRegToVReg(uses[i])+1, SRegToVReg(uses[i+1])); - i++; - break; - case 'J': - reg_location_[uses[i]].wide = true; - reg_location_[uses[i+1]].wide = true; - reg_location_[uses[i+1]].high_word = true; - DCHECK_EQ(SRegToVReg(uses[i])+1, SRegToVReg(uses[i+1])); - changed |= SetCore(uses[i]); - i++; - break; - case 'F': - ssa_rep->fp_use[i] = true; - break; - case 'L': - changed |= SetRef(uses[i]); - break; - default: - changed |= SetCore(uses[i]); - break; - } - i++; } + i++; } } + } - for (int i = 0; ssa_rep->fp_use && i< ssa_rep->num_uses; i++) { - if (ssa_rep->fp_use[i]) - changed |= SetFp(uses[i]); - } - for (int i = 0; ssa_rep->fp_def && i< ssa_rep->num_defs; i++) { - if (ssa_rep->fp_def[i]) - changed |= SetFp(defs[i]); - } - // Special-case handling for moves & Phi - if (attrs & (DF_IS_MOVE | DF_NULL_TRANSFER_N)) { - /* - * If any of our inputs or outputs is defined, set all. - * Some ugliness related to Phi nodes and wide values. - * The Phi set will include all low words or all high - * words, so we have to treat them specially. - */ - bool is_phi = (static_cast<int>(mir->dalvikInsn.opcode) == - kMirOpPhi); - RegLocation rl_temp = reg_location_[defs[0]]; - bool defined_fp = rl_temp.defined && rl_temp.fp; - bool defined_core = rl_temp.defined && rl_temp.core; - bool defined_ref = rl_temp.defined && rl_temp.ref; - bool is_wide = rl_temp.wide || ((attrs & DF_A_WIDE) != 0); - bool is_high = is_phi && rl_temp.wide && rl_temp.high_word; - for (int i = 0; i < ssa_rep->num_uses; i++) { - rl_temp = reg_location_[uses[i]]; - defined_fp |= rl_temp.defined && rl_temp.fp; - defined_core |= rl_temp.defined && rl_temp.core; - defined_ref |= rl_temp.defined && rl_temp.ref; - is_wide |= rl_temp.wide; - is_high |= is_phi && rl_temp.wide && rl_temp.high_word; - } - /* - * We don't normally expect to see a Dalvik register definition used both as a - * floating point and core value, though technically it could happen with constants. - * Until we have proper typing, detect this situation and disable register promotion - * (which relies on the distinction between core a fp usages). - */ - if ((defined_fp && (defined_core | defined_ref)) && - ((cu_->disable_opt & (1 << kPromoteRegs)) == 0)) { - LOG(WARNING) << PrettyMethod(cu_->method_idx, *cu_->dex_file) - << " op at block " << bb->id - << " has both fp and core/ref uses for same def."; - cu_->disable_opt |= (1 << kPromoteRegs); - } - changed |= SetFp(defs[0], defined_fp); - changed |= SetCore(defs[0], defined_core); - changed |= SetRef(defs[0], defined_ref); - changed |= SetWide(defs[0], is_wide); - changed |= SetHigh(defs[0], is_high); - if (attrs & DF_A_WIDE) { - changed |= SetWide(defs[1]); - changed |= SetHigh(defs[1]); - } - for (int i = 0; i < ssa_rep->num_uses; i++) { - changed |= SetFp(uses[i], defined_fp); - changed |= SetCore(uses[i], defined_core); - changed |= SetRef(uses[i], defined_ref); - changed |= SetWide(uses[i], is_wide); - changed |= SetHigh(uses[i], is_high); - } - if (attrs & DF_A_WIDE) { - DCHECK_EQ(ssa_rep->num_uses, 2); - changed |= SetWide(uses[1]); - changed |= SetHigh(uses[1]); - } + for (int i = 0; ssa_rep->fp_use && i< ssa_rep->num_uses; i++) { + if (ssa_rep->fp_use[i]) + changed |= SetFp(uses[i]); + } + for (int i = 0; ssa_rep->fp_def && i< ssa_rep->num_defs; i++) { + if (ssa_rep->fp_def[i]) + changed |= SetFp(defs[i]); + } + // Special-case handling for moves & Phi + if (attrs & (DF_IS_MOVE | DF_NULL_TRANSFER_N)) { + /* + * If any of our inputs or outputs is defined, set all. + * Some ugliness related to Phi nodes and wide values. + * The Phi set will include all low words or all high + * words, so we have to treat them specially. + */ + bool is_phi = (static_cast<int>(mir->dalvikInsn.opcode) == + kMirOpPhi); + RegLocation rl_temp = reg_location_[defs[0]]; + bool defined_fp = rl_temp.defined && rl_temp.fp; + bool defined_core = rl_temp.defined && rl_temp.core; + bool defined_ref = rl_temp.defined && rl_temp.ref; + bool is_wide = rl_temp.wide || ((attrs & DF_A_WIDE) != 0); + bool is_high = is_phi && rl_temp.wide && rl_temp.high_word; + for (int i = 0; i < ssa_rep->num_uses; i++) { + rl_temp = reg_location_[uses[i]]; + defined_fp |= rl_temp.defined && rl_temp.fp; + defined_core |= rl_temp.defined && rl_temp.core; + defined_ref |= rl_temp.defined && rl_temp.ref; + is_wide |= rl_temp.wide; + is_high |= is_phi && rl_temp.wide && rl_temp.high_word; + } + /* + * We don't normally expect to see a Dalvik register definition used both as a + * floating point and core value, though technically it could happen with constants. + * Until we have proper typing, detect this situation and disable register promotion + * (which relies on the distinction between core a fp usages). + */ + if ((defined_fp && (defined_core | defined_ref)) && + ((cu_->disable_opt & (1 << kPromoteRegs)) == 0)) { + LOG(WARNING) << PrettyMethod(cu_->method_idx, *cu_->dex_file) + << " op at block " << bb->id + << " has both fp and core/ref uses for same def."; + cu_->disable_opt |= (1 << kPromoteRegs); + } + changed |= SetFp(defs[0], defined_fp); + changed |= SetCore(defs[0], defined_core); + changed |= SetRef(defs[0], defined_ref); + changed |= SetWide(defs[0], is_wide); + changed |= SetHigh(defs[0], is_high); + if (attrs & DF_A_WIDE) { + changed |= SetWide(defs[1]); + changed |= SetHigh(defs[1]); + } + for (int i = 0; i < ssa_rep->num_uses; i++) { + changed |= SetFp(uses[i], defined_fp); + changed |= SetCore(uses[i], defined_core); + changed |= SetRef(uses[i], defined_ref); + changed |= SetWide(uses[i], is_wide); + changed |= SetHigh(uses[i], is_high); + } + if (attrs & DF_A_WIDE) { + DCHECK_EQ(ssa_rep->num_uses, 2); + changed |= SetWide(uses[1]); + changed |= SetHigh(uses[1]); } } } @@ -417,13 +408,7 @@ static const RegLocation fresh_loc = {kLocDalvikFrame, 0, 0, 0, 0, 0, 0, 0, 0, INVALID_REG, INVALID_REG, INVALID_SREG, INVALID_SREG}; -/* - * Simple register allocation. Some Dalvik virtual registers may - * be promoted to physical registers. Most of the work for temp - * allocation is done on the fly. We also do some initialization and - * type inference here. - */ -void MIRGraph::BuildRegLocations() { +void MIRGraph::InitRegLocations() { /* Allocate the location map */ RegLocation* loc = static_cast<RegLocation*>(arena_->Alloc(GetNumSSARegs() * sizeof(*loc), ArenaAllocator::kAllocRegAlloc)); @@ -493,19 +478,14 @@ void MIRGraph::BuildRegLocations() { s_reg++; } } +} - /* Do type & size inference pass */ - RepeatingPreOrderDfsIterator iter(this); - bool change = false; - for (BasicBlock* bb = iter.Next(false); bb != NULL; bb = iter.Next(change)) { - change = InferTypeAndSize(bb); - } - - /* - * Set the s_reg_low field to refer to the pre-SSA name of the - * base Dalvik virtual register. Once we add a better register - * allocator, remove this remapping. - */ +/* + * Set the s_reg_low field to refer to the pre-SSA name of the + * base Dalvik virtual register. Once we add a better register + * allocator, remove this remapping. + */ +void MIRGraph::RemapRegLocations() { for (int i = 0; i < GetNumSSARegs(); i++) { if (reg_location_[i].location != kLocCompilerTemp) { int orig_sreg = reg_location_[i].s_reg_low; |