From 92f7f3ce3b01f7c7df1c15b81c900e087248093f Mon Sep 17 00:00:00 2001 From: Vladimir Marko Date: Tue, 31 Oct 2017 11:38:30 +0000 Subject: Use intrinsic codegen for compiling intrinsic methods. When compiling an intrinsic method, generate a graph that invokes the same method and try to compile it. If the call is actually intrinsified (or simplified to other HIR) and yields a leaf method, use the result of this compilation attempt, otherwise compile the actual code or JNI stub. Note that CodeGenerator::CreateThrowingSlowPathLocations() actually marks the locations as kNoCall if the throw is not in a catch block, thus considering some throwing methods (for example, String.charAt()) as leaf methods. We would ideally want to use the intrinsic codegen for all intrinsics that do not generate a slow-path call to the default implementation. Relying on the leaf method is suboptimal as we're missing out on methods that do other types of calls, for example runtime calls. This shall be fixed in a subsequent CL. Test: m test-art-host-gtest Test: testrunner.py --host --optimizing Bug: 67717501 Change-Id: I640fda7c22d4ff494b5ff77ebec3b7f5f75af652 --- compiler/optimizing/builder.cc | 84 +++++++++++++++++++++++++++++++++++------- 1 file changed, 71 insertions(+), 13 deletions(-) (limited to 'compiler/optimizing/builder.cc') diff --git a/compiler/optimizing/builder.cc b/compiler/optimizing/builder.cc index 4ed1612220..d73ef1f3a1 100644 --- a/compiler/optimizing/builder.cc +++ b/compiler/optimizing/builder.cc @@ -24,6 +24,7 @@ #include "data_type-inl.h" #include "dex/verified_method.h" #include "driver/compiler_options.h" +#include "driver/dex_compilation_unit.h" #include "instruction_builder.h" #include "mirror/class_loader.h" #include "mirror/dex_cache.h" @@ -36,6 +37,7 @@ namespace art { HGraphBuilder::HGraphBuilder(HGraph* graph, + const DexFile::CodeItem* code_item, const DexCompilationUnit* dex_compilation_unit, const DexCompilationUnit* outer_compilation_unit, CompilerDriver* driver, @@ -45,7 +47,7 @@ HGraphBuilder::HGraphBuilder(HGraph* graph, VariableSizedHandleScope* handles) : graph_(graph), dex_file_(&graph->GetDexFile()), - code_item_(*dex_compilation_unit->GetCodeItem()), + code_item_(code_item), dex_compilation_unit_(dex_compilation_unit), outer_compilation_unit_(outer_compilation_unit), compiler_driver_(driver), @@ -67,23 +69,21 @@ bool HGraphBuilder::SkipCompilation(size_t number_of_branches) { return false; } - if (compiler_options.IsHugeMethod(code_item_.insns_size_in_code_units_)) { + if (compiler_options.IsHugeMethod(code_item_->insns_size_in_code_units_)) { VLOG(compiler) << "Skip compilation of huge method " << dex_file_->PrettyMethod(dex_compilation_unit_->GetDexMethodIndex()) - << ": " << code_item_.insns_size_in_code_units_ << " code units"; - MaybeRecordStat(compilation_stats_, - MethodCompilationStat::kNotCompiledHugeMethod); + << ": " << code_item_->insns_size_in_code_units_ << " code units"; + MaybeRecordStat(compilation_stats_, MethodCompilationStat::kNotCompiledHugeMethod); return true; } // If it's large and contains no branches, it's likely to be machine generated initialization. - if (compiler_options.IsLargeMethod(code_item_.insns_size_in_code_units_) + if (compiler_options.IsLargeMethod(code_item_->insns_size_in_code_units_) && (number_of_branches == 0)) { VLOG(compiler) << "Skip compilation of large method with no branch " << dex_file_->PrettyMethod(dex_compilation_unit_->GetDexMethodIndex()) - << ": " << code_item_.insns_size_in_code_units_ << " code units"; - MaybeRecordStat(compilation_stats_, - MethodCompilationStat::kNotCompiledLargeMethodNoBranches); + << ": " << code_item_->insns_size_in_code_units_ << " code units"; + MaybeRecordStat(compilation_stats_, MethodCompilationStat::kNotCompiledLargeMethodNoBranches); return true; } @@ -91,12 +91,13 @@ bool HGraphBuilder::SkipCompilation(size_t number_of_branches) { } GraphAnalysisResult HGraphBuilder::BuildGraph() { + DCHECK(code_item_ != nullptr); DCHECK(graph_->GetBlocks().empty()); - graph_->SetNumberOfVRegs(code_item_.registers_size_); - graph_->SetNumberOfInVRegs(code_item_.ins_size_); - graph_->SetMaximumNumberOfOutVRegs(code_item_.outs_size_); - graph_->SetHasTryCatch(code_item_.tries_size_ != 0); + graph_->SetNumberOfVRegs(code_item_->registers_size_); + graph_->SetNumberOfInVRegs(code_item_->ins_size_); + graph_->SetMaximumNumberOfOutVRegs(code_item_->outs_size_); + graph_->SetHasTryCatch(code_item_->tries_size_ != 0); // Use ScopedArenaAllocator for all local allocations. ScopedArenaAllocator local_allocator(graph_->GetArenaStack()); @@ -148,4 +149,61 @@ GraphAnalysisResult HGraphBuilder::BuildGraph() { return ssa_builder.BuildSsa(); } +void HGraphBuilder::BuildIntrinsicGraph(ArtMethod* method) { + DCHECK(code_item_ == nullptr); + DCHECK(graph_->GetBlocks().empty()); + + // Determine the number of arguments and associated vregs. + uint32_t method_idx = dex_compilation_unit_->GetDexMethodIndex(); + const char* shorty = dex_file_->GetMethodShorty(dex_file_->GetMethodId(method_idx)); + size_t num_args = strlen(shorty + 1); + size_t num_wide_args = std::count(shorty + 1, shorty + 1 + num_args, 'J') + + std::count(shorty + 1, shorty + 1 + num_args, 'D'); + size_t num_arg_vregs = num_args + num_wide_args + (dex_compilation_unit_->IsStatic() ? 0u : 1u); + + // For simplicity, reserve 2 vregs (the maximum) for return value regardless of the return type. + size_t return_vregs = 2u; + graph_->SetNumberOfVRegs(return_vregs + num_arg_vregs); + graph_->SetNumberOfInVRegs(num_arg_vregs); + graph_->SetMaximumNumberOfOutVRegs(num_arg_vregs); + graph_->SetHasTryCatch(false); + + // Use ScopedArenaAllocator for all local allocations. + ScopedArenaAllocator local_allocator(graph_->GetArenaStack()); + HBasicBlockBuilder block_builder(graph_, dex_file_, /* code_item */ nullptr, &local_allocator); + SsaBuilder ssa_builder(graph_, + dex_compilation_unit_->GetClassLoader(), + dex_compilation_unit_->GetDexCache(), + handles_, + &local_allocator); + HInstructionBuilder instruction_builder(graph_, + &block_builder, + &ssa_builder, + dex_file_, + /* code_item */ nullptr, + return_type_, + dex_compilation_unit_, + outer_compilation_unit_, + compiler_driver_, + code_generator_, + interpreter_metadata_, + compilation_stats_, + handles_, + &local_allocator); + + // 1) Create basic blocks for the intrinsic and link them together. + block_builder.BuildIntrinsic(); + + // 2) Build the trivial dominator tree. + GraphAnalysisResult bdt_result = graph_->BuildDominatorTree(); + DCHECK_EQ(bdt_result, kAnalysisSuccess); + + // 3) Populate basic blocks with instructions for the intrinsic. + instruction_builder.BuildIntrinsic(method); + + // 4) Type the graph (no dead/redundant phis to eliminate). + GraphAnalysisResult build_ssa_result = ssa_builder.BuildSsa(); + DCHECK_EQ(build_ssa_result, kAnalysisSuccess); +} + } // namespace art -- cgit v1.2.3-59-g8ed1b