From e50383288a75244255d3ecedcc79ffe9caf774cb Mon Sep 17 00:00:00 2001 From: Nicolas Geoffray Date: Fri, 4 Jul 2014 09:41:32 +0100 Subject: Support fields in optimizing compiler. - Required support for temporaries, to be only used by baseline compiler. - Also fixed a few invalid assumptions around locations and instructions that don't need materialization. These instructions should not have an Out. Change-Id: Idc4a30dd95dd18015137300d36bec55fc024cf62 --- compiler/optimizing/builder.cc | 114 ++++++++- compiler/optimizing/builder.h | 14 +- compiler/optimizing/code_generator.cc | 23 +- compiler/optimizing/code_generator.h | 31 ++- compiler/optimizing/code_generator_arm.cc | 228 +++++++++++++++-- compiler/optimizing/code_generator_arm.h | 1 + compiler/optimizing/code_generator_x86.cc | 231 ++++++++++++++++- compiler/optimizing/code_generator_x86.h | 1 + compiler/optimizing/code_generator_x86_64.cc | 184 +++++++++++++- compiler/optimizing/code_generator_x86_64.h | 1 + compiler/optimizing/live_ranges_test.cc | 4 +- compiler/optimizing/liveness_test.cc | 368 ++++++++++++++------------- compiler/optimizing/nodes.h | 107 ++++++++ compiler/optimizing/optimizing_compiler.cc | 2 +- compiler/optimizing/ssa_liveness_analysis.cc | 9 +- 15 files changed, 1075 insertions(+), 243 deletions(-) (limited to 'compiler/optimizing') diff --git a/compiler/optimizing/builder.cc b/compiler/optimizing/builder.cc index cc995f72a1..c96792c903 100644 --- a/compiler/optimizing/builder.cc +++ b/compiler/optimizing/builder.cc @@ -15,13 +15,22 @@ * limitations under the License. */ +#include "builder.h" + +#include "class_linker.h" #include "dex_file.h" #include "dex_file-inl.h" #include "dex_instruction.h" #include "dex_instruction-inl.h" -#include "builder.h" +#include "driver/compiler_driver-inl.h" +#include "mirror/art_field.h" +#include "mirror/art_field-inl.h" +#include "mirror/class_loader.h" +#include "mirror/dex_cache.h" #include "nodes.h" #include "primitive.h" +#include "scoped_thread_state_change.h" +#include "thread.h" namespace art { @@ -93,7 +102,7 @@ static bool CanHandleCodeItem(const DexFile::CodeItem& code_item) { } template -void HGraphBuilder::If_22t(const Instruction& instruction, int32_t dex_offset) { +void HGraphBuilder::If_22t(const Instruction& instruction, uint32_t dex_offset) { HInstruction* first = LoadLocal(instruction.VRegA(), Primitive::kPrimInt); HInstruction* second = LoadLocal(instruction.VRegB(), Primitive::kPrimInt); T* comparison = new (arena_) T(first, second); @@ -110,7 +119,7 @@ void HGraphBuilder::If_22t(const Instruction& instruction, int32_t dex_offset) { } template -void HGraphBuilder::If_21t(const Instruction& instruction, int32_t dex_offset) { +void HGraphBuilder::If_21t(const Instruction& instruction, uint32_t dex_offset) { HInstruction* value = LoadLocal(instruction.VRegA(), Primitive::kPrimInt); T* comparison = new (arena_) T(value, GetIntConstant(0)); current_block_->AddInstruction(comparison); @@ -335,6 +344,79 @@ bool HGraphBuilder::BuildInvoke(const Instruction& instruction, return true; } +/** + * Helper class to add HTemporary instructions. This class is used when + * converting a DEX instruction to multiple HInstruction, and where those + * instructions do not die at the following instruction, but instead spans + * multiple instructions. + */ +class Temporaries : public ValueObject { + public: + Temporaries(HGraph* graph, size_t count) : graph_(graph), count_(count), index_(0) { + graph_->UpdateNumberOfTemporaries(count_); + } + + void Add(HInstruction* instruction) { + // We currently only support vreg size temps. + DCHECK(instruction->GetType() != Primitive::kPrimLong + && instruction->GetType() != Primitive::kPrimDouble); + HInstruction* temp = new (graph_->GetArena()) HTemporary(index_++); + instruction->GetBlock()->AddInstruction(temp); + DCHECK(temp->GetPrevious() == instruction); + } + + private: + HGraph* const graph_; + + // The total number of temporaries that will be used. + const size_t count_; + + // Current index in the temporary stack, updated by `Add`. + size_t index_; +}; + +bool HGraphBuilder::BuildFieldAccess(const Instruction& instruction, + uint32_t dex_offset, + bool is_put) { + uint32_t source_or_dest_reg = instruction.VRegA_22c(); + uint32_t obj_reg = instruction.VRegB_22c(); + uint16_t field_index = instruction.VRegC_22c(); + + ScopedObjectAccess soa(Thread::Current()); + StackHandleScope<1> hs(soa.Self()); + Handle resolved_field(hs.NewHandle( + compiler_driver_->ComputeInstanceFieldInfo(field_index, dex_compilation_unit_, is_put, soa))); + + if (resolved_field.Get() == nullptr) { + return false; + } + if (resolved_field->IsVolatile()) { + return false; + } + + HInstruction* object = LoadLocal(obj_reg, Primitive::kPrimNot); + current_block_->AddInstruction(new (arena_) HNullCheck(object, dex_offset)); + if (is_put) { + Temporaries temps(graph_, 1); + HInstruction* null_check = current_block_->GetLastInstruction(); + // We need one temporary for the null check. + temps.Add(null_check); + HInstruction* value = LoadLocal(source_or_dest_reg, resolved_field->GetTypeAsPrimitiveType()); + current_block_->AddInstruction(new (arena_) HInstanceFieldSet( + null_check, + value, + resolved_field->GetOffset())); + } else { + current_block_->AddInstruction(new (arena_) HInstanceFieldGet( + current_block_->GetLastInstruction(), + resolved_field->GetTypeAsPrimitiveType(), + resolved_field->GetOffset())); + + UpdateLocal(source_or_dest_reg, current_block_->GetLastInstruction()); + } + return true; +} + bool HGraphBuilder::AnalyzeDexInstruction(const Instruction& instruction, int32_t dex_offset) { if (current_block_ == nullptr) { return true; // Dead code @@ -581,6 +663,32 @@ bool HGraphBuilder::AnalyzeDexInstruction(const Instruction& instruction, int32_ case Instruction::NOP: break; + case Instruction::IGET: + case Instruction::IGET_WIDE: + case Instruction::IGET_OBJECT: + case Instruction::IGET_BOOLEAN: + case Instruction::IGET_BYTE: + case Instruction::IGET_CHAR: + case Instruction::IGET_SHORT: { + if (!BuildFieldAccess(instruction, dex_offset, false)) { + return false; + } + break; + } + + case Instruction::IPUT: + case Instruction::IPUT_WIDE: + case Instruction::IPUT_OBJECT: + case Instruction::IPUT_BOOLEAN: + case Instruction::IPUT_BYTE: + case Instruction::IPUT_CHAR: + case Instruction::IPUT_SHORT: { + if (!BuildFieldAccess(instruction, dex_offset, true)) { + return false; + } + break; + } + default: return false; } diff --git a/compiler/optimizing/builder.h b/compiler/optimizing/builder.h index ee32ca80ac..f94b8e810a 100644 --- a/compiler/optimizing/builder.h +++ b/compiler/optimizing/builder.h @@ -18,6 +18,7 @@ #define ART_COMPILER_OPTIMIZING_BUILDER_H_ #include "dex_file.h" +#include "driver/compiler_driver.h" #include "driver/dex_compilation_unit.h" #include "primitive.h" #include "utils/allocation.h" @@ -32,7 +33,8 @@ class HGraphBuilder : public ValueObject { public: HGraphBuilder(ArenaAllocator* arena, DexCompilationUnit* dex_compilation_unit = nullptr, - const DexFile* dex_file = nullptr) + const DexFile* dex_file = nullptr, + CompilerDriver* driver = nullptr) : arena_(arena), branch_targets_(arena, 0), locals_(arena, 0), @@ -43,7 +45,8 @@ class HGraphBuilder : public ValueObject { constant0_(nullptr), constant1_(nullptr), dex_file_(dex_file), - dex_compilation_unit_(dex_compilation_unit) { } + dex_compilation_unit_(dex_compilation_unit), + compiler_driver_(driver) {} HGraph* BuildGraph(const DexFile::CodeItem& code); @@ -84,11 +87,13 @@ class HGraphBuilder : public ValueObject { template void Binop_22s(const Instruction& instruction, bool reverse); - template void If_21t(const Instruction& instruction, int32_t dex_offset); - template void If_22t(const Instruction& instruction, int32_t dex_offset); + template void If_21t(const Instruction& instruction, uint32_t dex_offset); + template void If_22t(const Instruction& instruction, uint32_t dex_offset); void BuildReturn(const Instruction& instruction, Primitive::Type type); + bool BuildFieldAccess(const Instruction& instruction, uint32_t dex_offset, bool is_get); + // Builds an invocation node and returns whether the instruction is supported. bool BuildInvoke(const Instruction& instruction, uint32_t dex_offset, @@ -117,6 +122,7 @@ class HGraphBuilder : public ValueObject { const DexFile* const dex_file_; DexCompilationUnit* const dex_compilation_unit_; + CompilerDriver* const compiler_driver_; DISALLOW_COPY_AND_ASSIGN(HGraphBuilder); }; diff --git a/compiler/optimizing/code_generator.cc b/compiler/optimizing/code_generator.cc index b8332ad2a3..b0e6a75b3d 100644 --- a/compiler/optimizing/code_generator.cc +++ b/compiler/optimizing/code_generator.cc @@ -39,6 +39,7 @@ void CodeGenerator::CompileBaseline(CodeAllocator* allocator) { DCHECK_EQ(frame_size_, kUninitializedFrameSize); ComputeFrameSize(GetGraph()->GetMaximumNumberOfOutVRegs() + GetGraph()->GetNumberOfVRegs() + + GetGraph()->GetNumberOfTemporaries() + 1 /* filler */); GenerateFrameEntry(); @@ -54,6 +55,7 @@ void CodeGenerator::CompileBaseline(CodeAllocator* allocator) { current->Accept(instruction_visitor); } } + GenerateSlowPaths(); size_t code_size = GetAssembler()->CodeSize(); uint8_t* buffer = allocator->Allocate(code_size); @@ -79,6 +81,7 @@ void CodeGenerator::CompileOptimized(CodeAllocator* allocator) { current->Accept(instruction_visitor); } } + GenerateSlowPaths(); size_t code_size = GetAssembler()->CodeSize(); uint8_t* buffer = allocator->Allocate(code_size); @@ -86,6 +89,12 @@ void CodeGenerator::CompileOptimized(CodeAllocator* allocator) { GetAssembler()->FinalizeInstructions(code); } +void CodeGenerator::GenerateSlowPaths() { + for (size_t i = 0, e = slow_paths_.Size(); i < e; ++i) { + slow_paths_.Get(i)->EmitNativeCode(this); + } +} + size_t CodeGenerator::AllocateFreeRegisterInternal( bool* blocked_registers, size_t number_of_registers) const { for (size_t regno = 0; regno < number_of_registers; regno++) { @@ -94,7 +103,6 @@ size_t CodeGenerator::AllocateFreeRegisterInternal( return regno; } } - LOG(FATAL) << "Unreachable"; return -1; } @@ -162,13 +170,6 @@ void CodeGenerator::AllocateRegistersLocally(HInstruction* instruction) const { locations->SetTempAt(i, loc); } } - - // Make all registers available for the return value. - for (size_t i = 0, e = GetNumberOfRegisters(); i < e; ++i) { - blocked_registers_[i] = false; - } - SetupBlockedRegisters(blocked_registers_); - Location result_location = locations->Out(); if (result_location.IsUnallocated()) { switch (result_location.GetPolicy()) { @@ -187,6 +188,12 @@ void CodeGenerator::AllocateRegistersLocally(HInstruction* instruction) const { void CodeGenerator::InitLocations(HInstruction* instruction) { if (instruction->GetLocations() == nullptr) { + if (instruction->IsTemporary()) { + HInstruction* previous = instruction->GetPrevious(); + Location temp_location = GetTemporaryLocation(instruction->AsTemporary()); + Move(previous, temp_location, instruction); + previous->GetLocations()->SetOut(temp_location); + } return; } AllocateRegistersLocally(instruction); diff --git a/compiler/optimizing/code_generator.h b/compiler/optimizing/code_generator.h index ae2f03080e..abfb790d8f 100644 --- a/compiler/optimizing/code_generator.h +++ b/compiler/optimizing/code_generator.h @@ -30,12 +30,13 @@ namespace art { static size_t constexpr kVRegSize = 4; static size_t constexpr kUninitializedFrameSize = 0; +class CodeGenerator; class DexCompilationUnit; class CodeAllocator { public: - CodeAllocator() { } - virtual ~CodeAllocator() { } + CodeAllocator() {} + virtual ~CodeAllocator() {} virtual uint8_t* Allocate(size_t size) = 0; @@ -48,6 +49,23 @@ struct PcInfo { uintptr_t native_pc; }; +class SlowPathCode : public ArenaObject { + public: + SlowPathCode() : entry_label_(), exit_label_() {} + virtual ~SlowPathCode() {} + + Label* GetEntryLabel() { return &entry_label_; } + Label* GetExitLabel() { return &exit_label_; } + + virtual void EmitNativeCode(CodeGenerator* codegen) = 0; + + private: + Label entry_label_; + Label exit_label_; + + DISALLOW_COPY_AND_ASSIGN(SlowPathCode); +}; + class CodeGenerator : public ArenaObject { public: // Compiles the graph to executable instructions. Returns whether the compilation @@ -99,6 +117,12 @@ class CodeGenerator : public ArenaObject { pc_infos_.Add(pc_info); } + void AddSlowPath(SlowPathCode* slow_path) { + slow_paths_.Add(slow_path); + } + + void GenerateSlowPaths(); + void BuildMappingTable(std::vector* vector) const; void BuildVMapTable(std::vector* vector) const; void BuildNativeGCMap( @@ -110,6 +134,7 @@ class CodeGenerator : public ArenaObject { graph_(graph), block_labels_(graph->GetArena(), 0), pc_infos_(graph->GetArena(), 32), + slow_paths_(graph->GetArena(), 8), blocked_registers_(graph->GetArena()->AllocArray(number_of_registers)) {} ~CodeGenerator() {} @@ -125,6 +150,7 @@ class CodeGenerator : public ArenaObject { size_t AllocateFreeRegisterInternal(bool* blocked_registers, size_t number_of_registers) const; virtual Location GetStackLocation(HLoadLocal* load) const = 0; + virtual Location GetTemporaryLocation(HTemporary* temp) const = 0; // Frame size required for this method. uint32_t frame_size_; @@ -138,6 +164,7 @@ class CodeGenerator : public ArenaObject { // Labels for each block that will be compiled. GrowableArray