diff options
Diffstat (limited to 'compiler/optimizing')
-rw-r--r-- | compiler/optimizing/bounds_check_elimination_test.cc | 12 | ||||
-rw-r--r-- | compiler/optimizing/graph_checker.cc | 16 | ||||
-rw-r--r-- | compiler/optimizing/licm.cc | 3 | ||||
-rw-r--r-- | compiler/optimizing/nodes.cc | 76 | ||||
-rw-r--r-- | compiler/optimizing/nodes.h | 151 | ||||
-rw-r--r-- | compiler/optimizing/register_allocator.cc | 101 | ||||
-rw-r--r-- | compiler/optimizing/register_allocator.h | 15 | ||||
-rw-r--r-- | compiler/optimizing/ssa_phi_elimination.cc | 36 |
8 files changed, 264 insertions, 146 deletions
diff --git a/compiler/optimizing/bounds_check_elimination_test.cc b/compiler/optimizing/bounds_check_elimination_test.cc index 17cb8f35de..66c873e27e 100644 --- a/compiler/optimizing/bounds_check_elimination_test.cc +++ b/compiler/optimizing/bounds_check_elimination_test.cc @@ -400,7 +400,6 @@ static HGraph* BuildSSAGraph1(ArenaAllocator* allocator, loop_body->AddSuccessor(loop_header); HPhi* phi = new (allocator) HPhi(allocator, 0, 0, Primitive::kPrimInt); - phi->AddInput(constant_initial); HInstruction* null_check = new (allocator) HNullCheck(parameter, 0); HInstruction* array_length = new (allocator) HArrayLength(null_check); HInstruction* cmp = nullptr; @@ -416,6 +415,7 @@ static HGraph* BuildSSAGraph1(ArenaAllocator* allocator, loop_header->AddInstruction(array_length); loop_header->AddInstruction(cmp); loop_header->AddInstruction(if_inst); + phi->AddInput(constant_initial); null_check = new (allocator) HNullCheck(parameter, 0); array_length = new (allocator) HArrayLength(null_check); @@ -544,7 +544,6 @@ static HGraph* BuildSSAGraph2(ArenaAllocator* allocator, loop_body->AddSuccessor(loop_header); HPhi* phi = new (allocator) HPhi(allocator, 0, 0, Primitive::kPrimInt); - phi->AddInput(array_length); HInstruction* cmp = nullptr; if (cond == kCondLE) { cmp = new (allocator) HLessThanOrEqual(phi, constant_initial); @@ -556,6 +555,7 @@ static HGraph* BuildSSAGraph2(ArenaAllocator* allocator, loop_header->AddPhi(phi); loop_header->AddInstruction(cmp); loop_header->AddInstruction(if_inst); + phi->AddInput(array_length); HInstruction* add = new (allocator) HAdd(Primitive::kPrimInt, phi, constant_minus_1); null_check = new (allocator) HNullCheck(parameter, 0); @@ -672,7 +672,6 @@ static HGraph* BuildSSAGraph3(ArenaAllocator* allocator, loop_body->AddSuccessor(loop_header); HPhi* phi = new (allocator) HPhi(allocator, 0, 0, Primitive::kPrimInt); - phi->AddInput(constant_initial); HInstruction* cmp = nullptr; if (cond == kCondGE) { cmp = new (allocator) HGreaterThanOrEqual(phi, constant_10); @@ -684,6 +683,7 @@ static HGraph* BuildSSAGraph3(ArenaAllocator* allocator, loop_header->AddPhi(phi); loop_header->AddInstruction(cmp); loop_header->AddInstruction(if_inst); + phi->AddInput(constant_initial); HNullCheck* null_check = new (allocator) HNullCheck(new_array, 0); HArrayLength* array_length = new (allocator) HArrayLength(null_check); @@ -785,7 +785,6 @@ static HGraph* BuildSSAGraph4(ArenaAllocator* allocator, loop_body->AddSuccessor(loop_header); HPhi* phi = new (allocator) HPhi(allocator, 0, 0, Primitive::kPrimInt); - phi->AddInput(constant_initial); HInstruction* null_check = new (allocator) HNullCheck(parameter, 0); HInstruction* array_length = new (allocator) HArrayLength(null_check); HInstruction* cmp = nullptr; @@ -800,6 +799,7 @@ static HGraph* BuildSSAGraph4(ArenaAllocator* allocator, loop_header->AddInstruction(array_length); loop_header->AddInstruction(cmp); loop_header->AddInstruction(if_inst); + phi->AddInput(constant_initial); null_check = new (allocator) HNullCheck(parameter, 0); array_length = new (allocator) HArrayLength(null_check); @@ -904,7 +904,6 @@ TEST(BoundsCheckEliminationTest, BubbleSortArrayBoundsElimination) { HBasicBlock* outer_header = new (&allocator) HBasicBlock(graph); graph->AddBlock(outer_header); HPhi* phi_i = new (&allocator) HPhi(&allocator, 0, 0, Primitive::kPrimInt); - phi_i->AddInput(constant_0); HNullCheck* null_check = new (&allocator) HNullCheck(parameter, 0); HArrayLength* array_length = new (&allocator) HArrayLength(null_check); HAdd* add = new (&allocator) HAdd(Primitive::kPrimInt, array_length, constant_minus_1); @@ -916,11 +915,11 @@ TEST(BoundsCheckEliminationTest, BubbleSortArrayBoundsElimination) { outer_header->AddInstruction(add); outer_header->AddInstruction(cmp); outer_header->AddInstruction(if_inst); + phi_i->AddInput(constant_0); HBasicBlock* inner_header = new (&allocator) HBasicBlock(graph); graph->AddBlock(inner_header); HPhi* phi_j = new (&allocator) HPhi(&allocator, 0, 0, Primitive::kPrimInt); - phi_j->AddInput(constant_0); null_check = new (&allocator) HNullCheck(parameter, 0); array_length = new (&allocator) HArrayLength(null_check); HSub* sub = new (&allocator) HSub(Primitive::kPrimInt, array_length, phi_i); @@ -934,6 +933,7 @@ TEST(BoundsCheckEliminationTest, BubbleSortArrayBoundsElimination) { inner_header->AddInstruction(add); inner_header->AddInstruction(cmp); inner_header->AddInstruction(if_inst); + phi_j->AddInput(constant_0); HBasicBlock* inner_body_compare = new (&allocator) HBasicBlock(graph); graph->AddBlock(inner_body_compare); diff --git a/compiler/optimizing/graph_checker.cc b/compiler/optimizing/graph_checker.cc index ef10428c0f..a7f1f74e27 100644 --- a/compiler/optimizing/graph_checker.cc +++ b/compiler/optimizing/graph_checker.cc @@ -160,6 +160,22 @@ void GraphChecker::VisitInstruction(HInstruction* instruction) { instruction->GetId())); } } + + // Ensure 'instruction' has pointers to its inputs' use entries. + for (size_t i = 0, e = instruction->InputCount(); i < e; ++i) { + HUserRecord<HInstruction*> input_record = instruction->InputRecordAt(i); + HInstruction* input = input_record.GetInstruction(); + HUseListNode<HInstruction*>* use_node = input_record.GetUseNode(); + if (use_node == nullptr || !input->GetUses().Contains(use_node)) { + AddError(StringPrintf("Instruction %s:%d has an invalid pointer to use entry " + "at input %u (%s:%d).", + instruction->DebugName(), + instruction->GetId(), + static_cast<unsigned>(i), + input->DebugName(), + input->GetId())); + } + } } void SSAChecker::VisitBasicBlock(HBasicBlock* block) { diff --git a/compiler/optimizing/licm.cc b/compiler/optimizing/licm.cc index 10f24d8148..bf9b8e59c5 100644 --- a/compiler/optimizing/licm.cc +++ b/compiler/optimizing/licm.cc @@ -66,8 +66,7 @@ static void UpdateLoopPhisIn(HEnvironment* environment, HLoopInformation* info) for (size_t i = 0, e = environment->Size(); i < e; ++i) { HInstruction* input = environment->GetInstructionAt(i); if (input != nullptr && IsPhiOf(input, info->GetHeader())) { - HUseListNode<HEnvironment*>* env_use = environment->GetInstructionEnvUseAt(i); - input->RemoveEnvironmentUser(env_use); + environment->RemoveAsUserOfInput(i); HInstruction* incoming = input->InputAt(0); environment->SetRawEnvAt(i, incoming); incoming->AddEnvUseAt(environment, i); diff --git a/compiler/optimizing/nodes.cc b/compiler/optimizing/nodes.cc index 7a75d260fd..93787b8bfd 100644 --- a/compiler/optimizing/nodes.cc +++ b/compiler/optimizing/nodes.cc @@ -34,17 +34,14 @@ void HGraph::FindBackEdges(ArenaBitVector* visited) { static void RemoveAsUser(HInstruction* instruction) { for (size_t i = 0; i < instruction->InputCount(); i++) { - instruction->InputAt(i)->RemoveUser(instruction, i); + instruction->RemoveAsUserOfInput(i); } HEnvironment* environment = instruction->GetEnvironment(); if (environment != nullptr) { for (size_t i = 0, e = environment->Size(); i < e; ++i) { - HUseListNode<HEnvironment*>* vreg_env_use = environment->GetInstructionEnvUseAt(i); - if (vreg_env_use != nullptr) { - HInstruction* vreg = environment->GetInstructionAt(i); - DCHECK(vreg != nullptr); - vreg->RemoveEnvironmentUser(vreg_env_use); + if (environment->GetInstructionAt(i) != nullptr) { + environment->RemoveAsUserOfInput(i); } } } @@ -64,22 +61,19 @@ void HGraph::RemoveInstructionsAsUsersFromDeadBlocks(const ArenaBitVector& visit } } -void HGraph::RemoveBlock(HBasicBlock* block) const { - for (size_t j = 0; j < block->GetSuccessors().Size(); ++j) { - block->GetSuccessors().Get(j)->RemovePredecessor(block); - } - for (HInstructionIterator it(block->GetPhis()); !it.Done(); it.Advance()) { - block->RemovePhi(it.Current()->AsPhi()); - } - for (HInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) { - block->RemoveInstruction(it.Current()); - } -} - void HGraph::RemoveDeadBlocks(const ArenaBitVector& visited) const { for (size_t i = 0; i < blocks_.Size(); ++i) { if (!visited.IsBitSet(i)) { - RemoveBlock(blocks_.Get(i)); + HBasicBlock* block = blocks_.Get(i); + for (size_t j = 0; j < block->GetSuccessors().Size(); ++j) { + block->GetSuccessors().Get(j)->RemovePredecessor(block); + } + for (HInstructionIterator it(block->GetPhis()); !it.Done(); it.Advance()) { + block->RemovePhi(it.Current()->AsPhi(), /*ensure_safety=*/ false); + } + for (HInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) { + block->RemoveInstruction(it.Current(), /*ensure_safety=*/ false); + } } } } @@ -439,22 +433,24 @@ void HBasicBlock::InsertPhiAfter(HPhi* phi, HPhi* cursor) { static void Remove(HInstructionList* instruction_list, HBasicBlock* block, - HInstruction* instruction) { + HInstruction* instruction, + bool ensure_safety) { DCHECK_EQ(block, instruction->GetBlock()); - DCHECK(instruction->GetUses().IsEmpty()); - DCHECK(instruction->GetEnvUses().IsEmpty()); instruction->SetBlock(nullptr); instruction_list->RemoveInstruction(instruction); - - RemoveAsUser(instruction); + if (ensure_safety) { + DCHECK(instruction->GetUses().IsEmpty()); + DCHECK(instruction->GetEnvUses().IsEmpty()); + RemoveAsUser(instruction); + } } -void HBasicBlock::RemoveInstruction(HInstruction* instruction) { - Remove(&instructions_, this, instruction); +void HBasicBlock::RemoveInstruction(HInstruction* instruction, bool ensure_safety) { + Remove(&instructions_, this, instruction, ensure_safety); } -void HBasicBlock::RemovePhi(HPhi* phi) { - Remove(&phis_, this, phi); +void HBasicBlock::RemovePhi(HPhi* phi, bool ensure_safety) { + Remove(&phis_, this, phi, ensure_safety); } void HEnvironment::CopyFrom(HEnvironment* env) { @@ -467,15 +463,9 @@ void HEnvironment::CopyFrom(HEnvironment* env) { } } -template <typename T> -static void RemoveFromUseList(T user, size_t input_index, HUseList<T>* list) { - HUseListNode<T>* current; - for (HUseIterator<HInstruction*> use_it(*list); !use_it.Done(); use_it.Advance()) { - current = use_it.Current(); - if (current->GetUser() == user && current->GetIndex() == input_index) { - list->Remove(current); - } - } +void HEnvironment::RemoveAsUserOfInput(size_t index) const { + const HUserRecord<HEnvironment*> user_record = vregs_.Get(index); + user_record.GetInstruction()->RemoveEnvironmentUser(user_record.GetUseNode()); } HInstruction* HInstruction::GetNextDisregardingMoves() const { @@ -494,14 +484,6 @@ HInstruction* HInstruction::GetPreviousDisregardingMoves() const { return previous; } -void HInstruction::RemoveUser(HInstruction* user, size_t input_index) { - RemoveFromUseList(user, input_index, &uses_); -} - -void HInstruction::RemoveEnvironmentUser(HUseListNode<HEnvironment*>* use) { - env_uses_.Remove(use); -} - void HInstructionList::AddInstruction(HInstruction* instruction) { if (first_instruction_ == nullptr) { DCHECK(last_instruction_ == nullptr); @@ -612,7 +594,7 @@ void HInstruction::ReplaceWith(HInstruction* other) { } void HInstruction::ReplaceInput(HInstruction* replacement, size_t index) { - InputAt(index)->RemoveUser(this, index); + RemoveAsUserOfInput(index); SetRawInputAt(index, replacement); replacement->AddUseAt(this, index); } @@ -623,7 +605,7 @@ size_t HInstruction::EnvironmentSize() const { void HPhi::AddInput(HInstruction* input) { DCHECK(input->GetBlock() != nullptr); - inputs_.Add(input); + inputs_.Add(HUserRecord<HInstruction*>(input)); input->AddUseAt(this, inputs_.Size() - 1); } diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h index 352403d72c..de448cc483 100644 --- a/compiler/optimizing/nodes.h +++ b/compiler/optimizing/nodes.h @@ -31,6 +31,7 @@ namespace art { +class GraphChecker; class HBasicBlock; class HEnvironment; class HInstruction; @@ -211,7 +212,6 @@ class HGraph : public ArenaObject<kArenaAllocMisc> { ArenaBitVector* visiting); void RemoveInstructionsAsUsersFromDeadBlocks(const ArenaBitVector& visited) const; void RemoveDeadBlocks(const ArenaBitVector& visited) const; - void RemoveBlock(HBasicBlock* block) const; ArenaAllocator* const arena_; @@ -490,14 +490,17 @@ class HBasicBlock : public ArenaObject<kArenaAllocMisc> { void ReplaceWith(HBasicBlock* other); void AddInstruction(HInstruction* instruction); - void RemoveInstruction(HInstruction* instruction); void InsertInstructionBefore(HInstruction* instruction, HInstruction* cursor); // Replace instruction `initial` with `replacement` within this block. void ReplaceAndRemoveInstructionWith(HInstruction* initial, HInstruction* replacement); void AddPhi(HPhi* phi); void InsertPhiAfter(HPhi* instruction, HPhi* cursor); - void RemovePhi(HPhi* phi); + // RemoveInstruction and RemovePhi delete a given instruction from the respective + // instruction list. With 'ensure_safety' set to true, it verifies that the + // instruction is not in use and removes it from the use lists of its inputs. + void RemoveInstruction(HInstruction* instruction, bool ensure_safety = true); + void RemovePhi(HPhi* phi, bool ensure_safety = true); bool IsLoopHeader() const { return (loop_information_ != nullptr) && (loop_information_->GetHeader() == this); @@ -715,6 +718,9 @@ class HUseList : public ValueObject { } void Remove(HUseListNode<T>* node) { + DCHECK(node != nullptr); + DCHECK(Contains(node)); + if (node->prev_ != nullptr) { node->prev_->next_ = node->next_; } @@ -726,6 +732,18 @@ class HUseList : public ValueObject { } } + bool Contains(const HUseListNode<T>* node) const { + if (node == nullptr) { + return false; + } + for (HUseListNode<T>* current = first_; current != nullptr; current = current->GetNext()) { + if (current == node) { + return true; + } + } + return false; + } + bool IsEmpty() const { return first_ == nullptr; } @@ -761,6 +779,33 @@ class HUseIterator : public ValueObject { friend class HValue; }; +// This class is used by HEnvironment and HInstruction classes to record the +// instructions they use and pointers to the corresponding HUseListNodes kept +// by the used instructions. +template <typename T> +class HUserRecord : public ValueObject { + public: + HUserRecord() : instruction_(nullptr), use_node_(nullptr) {} + explicit HUserRecord(HInstruction* instruction) : instruction_(instruction), use_node_(nullptr) {} + + HUserRecord(const HUserRecord<T>& old_record, HUseListNode<T>* use_node) + : instruction_(old_record.instruction_), use_node_(use_node) { + DCHECK(instruction_ != nullptr); + DCHECK(use_node_ != nullptr); + DCHECK(old_record.use_node_ == nullptr); + } + + HInstruction* GetInstruction() const { return instruction_; } + HUseListNode<T>* GetUseNode() const { return use_node_; } + + private: + // Instruction used by the user. + HInstruction* instruction_; + + // Corresponding entry in the use list kept by 'instruction_'. + HUseListNode<T>* use_node_; +}; + // Represents the side effects an instruction may have. class SideEffects : public ValueObject { public: @@ -831,46 +876,36 @@ class HEnvironment : public ArenaObject<kArenaAllocMisc> { : vregs_(arena, number_of_vregs) { vregs_.SetSize(number_of_vregs); for (size_t i = 0; i < number_of_vregs; i++) { - vregs_.Put(i, VRegInfo(nullptr, nullptr)); + vregs_.Put(i, HUserRecord<HEnvironment*>()); } } void CopyFrom(HEnvironment* env); void SetRawEnvAt(size_t index, HInstruction* instruction) { - vregs_.Put(index, VRegInfo(instruction, nullptr)); - } - - // Record instructions' use entries of this environment for constant-time removal. - void RecordEnvUse(HUseListNode<HEnvironment*>* env_use) { - DCHECK(env_use->GetUser() == this); - size_t index = env_use->GetIndex(); - VRegInfo info = vregs_.Get(index); - DCHECK(info.vreg_ != nullptr); - DCHECK(info.node_ == nullptr); - vregs_.Put(index, VRegInfo(info.vreg_, env_use)); + vregs_.Put(index, HUserRecord<HEnvironment*>(instruction)); } HInstruction* GetInstructionAt(size_t index) const { - return vregs_.Get(index).vreg_; + return vregs_.Get(index).GetInstruction(); } - HUseListNode<HEnvironment*>* GetInstructionEnvUseAt(size_t index) const { - return vregs_.Get(index).node_; - } + void RemoveAsUserOfInput(size_t index) const; size_t Size() const { return vregs_.Size(); } private: - struct VRegInfo { - HInstruction* vreg_; - HUseListNode<HEnvironment*>* node_; + // Record instructions' use entries of this environment for constant-time removal. + // It should only be called by HInstruction when a new environment use is added. + void RecordEnvUse(HUseListNode<HEnvironment*>* env_use) { + DCHECK(env_use->GetUser() == this); + size_t index = env_use->GetIndex(); + vregs_.Put(index, HUserRecord<HEnvironment*>(vregs_.Get(index), env_use)); + } - VRegInfo(HInstruction* instruction, HUseListNode<HEnvironment*>* env_use) - : vreg_(instruction), node_(env_use) {} - }; + GrowableArray<HUserRecord<HEnvironment*> > vregs_; - GrowableArray<VRegInfo> vregs_; + friend HInstruction; DISALLOW_COPY_AND_ASSIGN(HEnvironment); }; @@ -989,13 +1024,15 @@ class HInstruction : public ArenaObject<kArenaAllocMisc> { bool IsLoopHeaderPhi() { return IsPhi() && block_->IsLoopHeader(); } virtual size_t InputCount() const = 0; - virtual HInstruction* InputAt(size_t i) const = 0; + HInstruction* InputAt(size_t i) const { return InputRecordAt(i).GetInstruction(); } virtual void Accept(HGraphVisitor* visitor) = 0; virtual const char* DebugName() const = 0; virtual Primitive::Type GetType() const { return Primitive::kPrimVoid; } - virtual void SetRawInputAt(size_t index, HInstruction* input) = 0; + void SetRawInputAt(size_t index, HInstruction* input) { + SetRawInputRecordAt(index, HUserRecord<HInstruction*>(input)); + } virtual bool NeedsEnvironment() const { return false; } virtual bool IsControlFlow() const { return false; } @@ -1018,7 +1055,10 @@ class HInstruction : public ArenaObject<kArenaAllocMisc> { ReferenceTypeInfo GetReferenceTypeInfo() const { return reference_type_info_; } void AddUseAt(HInstruction* user, size_t index) { - uses_.AddUse(user, index, GetBlock()->GetGraph()->GetArena()); + DCHECK(user != nullptr); + HUseListNode<HInstruction*>* use = + uses_.AddUse(user, index, GetBlock()->GetGraph()->GetArena()); + user->SetRawInputRecordAt(index, HUserRecord<HInstruction*>(user->InputRecordAt(index), use)); } void AddEnvUseAt(HEnvironment* user, size_t index) { @@ -1028,11 +1068,13 @@ class HInstruction : public ArenaObject<kArenaAllocMisc> { user->RecordEnvUse(env_use); } - void RemoveUser(HInstruction* user, size_t index); - void RemoveEnvironmentUser(HUseListNode<HEnvironment*>* use); + void RemoveAsUserOfInput(size_t input) { + HUserRecord<HInstruction*> input_use = InputRecordAt(input); + input_use.GetInstruction()->uses_.Remove(input_use.GetUseNode()); + } - const HUseList<HInstruction*>& GetUses() { return uses_; } - const HUseList<HEnvironment*>& GetEnvUses() { return env_uses_; } + const HUseList<HInstruction*>& GetUses() const { return uses_; } + const HUseList<HEnvironment*>& GetEnvUses() const { return env_uses_; } bool HasUses() const { return !uses_.IsEmpty() || !env_uses_.IsEmpty(); } bool HasEnvironmentUses() const { return !env_uses_.IsEmpty(); } @@ -1126,7 +1168,13 @@ class HInstruction : public ArenaObject<kArenaAllocMisc> { return NeedsEnvironment() || IsLoadClass() || IsLoadString(); } + protected: + virtual const HUserRecord<HInstruction*> InputRecordAt(size_t i) const = 0; + virtual void SetRawInputRecordAt(size_t index, const HUserRecord<HInstruction*>& input) = 0; + private: + void RemoveEnvironmentUser(HUseListNode<HEnvironment*>* use_node) { env_uses_.Remove(use_node); } + HInstruction* previous_; HInstruction* next_; HBasicBlock* block_; @@ -1164,7 +1212,9 @@ class HInstruction : public ArenaObject<kArenaAllocMisc> { // TODO: for primitive types this should be marked as invalid. ReferenceTypeInfo reference_type_info_; + friend class GraphChecker; friend class HBasicBlock; + friend class HEnvironment; friend class HGraph; friend class HInstructionList; @@ -1284,15 +1334,16 @@ class HTemplateInstruction: public HInstruction { virtual ~HTemplateInstruction() {} virtual size_t InputCount() const { return N; } - virtual HInstruction* InputAt(size_t i) const { return inputs_[i]; } protected: - virtual void SetRawInputAt(size_t i, HInstruction* instruction) { - inputs_[i] = instruction; + const HUserRecord<HInstruction*> InputRecordAt(size_t i) const OVERRIDE { return inputs_[i]; } + + void SetRawInputRecordAt(size_t i, const HUserRecord<HInstruction*>& input) OVERRIDE { + inputs_[i] = input; } private: - EmbeddedArray<HInstruction*, N> inputs_; + EmbeddedArray<HUserRecord<HInstruction*>, N> inputs_; friend class SsaBuilder; }; @@ -1848,7 +1899,6 @@ std::ostream& operator<<(std::ostream& os, const Intrinsics& intrinsic); class HInvoke : public HInstruction { public: virtual size_t InputCount() const { return inputs_.Size(); } - virtual HInstruction* InputAt(size_t i) const { return inputs_.Get(i); } // Runtime needs to walk the stack, so Dex -> Dex calls need to // know their environment. @@ -1858,10 +1908,6 @@ class HInvoke : public HInstruction { SetRawInputAt(index, argument); } - virtual void SetRawInputAt(size_t index, HInstruction* input) { - inputs_.Put(index, input); - } - virtual Primitive::Type GetType() const { return return_type_; } uint32_t GetDexPc() const { return dex_pc_; } @@ -1893,7 +1939,12 @@ class HInvoke : public HInstruction { inputs_.SetSize(number_of_arguments); } - GrowableArray<HInstruction*> inputs_; + const HUserRecord<HInstruction*> InputRecordAt(size_t i) const OVERRIDE { return inputs_.Get(i); } + void SetRawInputRecordAt(size_t index, const HUserRecord<HInstruction*>& input) OVERRIDE { + inputs_.Put(index, input); + } + + GrowableArray<HUserRecord<HInstruction*> > inputs_; const Primitive::Type return_type_; const uint32_t dex_pc_; const uint32_t dex_method_index_; @@ -2389,11 +2440,6 @@ class HPhi : public HInstruction { } size_t InputCount() const OVERRIDE { return inputs_.Size(); } - HInstruction* InputAt(size_t i) const OVERRIDE { return inputs_.Get(i); } - - void SetRawInputAt(size_t index, HInstruction* input) OVERRIDE { - inputs_.Put(index, input); - } void AddInput(HInstruction* input); @@ -2412,8 +2458,15 @@ class HPhi : public HInstruction { DECLARE_INSTRUCTION(Phi); + protected: + const HUserRecord<HInstruction*> InputRecordAt(size_t i) const OVERRIDE { return inputs_.Get(i); } + + void SetRawInputRecordAt(size_t index, const HUserRecord<HInstruction*>& input) OVERRIDE { + inputs_.Put(index, input); + } + private: - GrowableArray<HInstruction*> inputs_; + GrowableArray<HUserRecord<HInstruction*> > inputs_; const uint32_t reg_number_; Primitive::Type type_; bool is_live_; diff --git a/compiler/optimizing/register_allocator.cc b/compiler/optimizing/register_allocator.cc index bfbe63f6ce..54e62a5b2c 100644 --- a/compiler/optimizing/register_allocator.cc +++ b/compiler/optimizing/register_allocator.cc @@ -48,7 +48,10 @@ RegisterAllocator::RegisterAllocator(ArenaAllocator* allocator, physical_core_register_intervals_(allocator, codegen->GetNumberOfCoreRegisters()), physical_fp_register_intervals_(allocator, codegen->GetNumberOfFloatingPointRegisters()), temp_intervals_(allocator, 4), - spill_slots_(allocator, kDefaultNumberOfSpillSlots), + int_spill_slots_(allocator, kDefaultNumberOfSpillSlots), + long_spill_slots_(allocator, kDefaultNumberOfSpillSlots), + float_spill_slots_(allocator, kDefaultNumberOfSpillSlots), + double_spill_slots_(allocator, kDefaultNumberOfSpillSlots), safepoints_(allocator, 0), processing_core_registers_(false), number_of_registers_(-1), @@ -438,7 +441,7 @@ bool RegisterAllocator::ValidateInternal(bool log_fatal_on_failure) const { } } - return ValidateIntervals(intervals, spill_slots_.Size(), reserved_out_slots_, *codegen_, + return ValidateIntervals(intervals, GetNumberOfSpillSlots(), reserved_out_slots_, *codegen_, allocator_, processing_core_registers_, log_fatal_on_failure); } @@ -1133,41 +1136,62 @@ void RegisterAllocator::AllocateSpillSlotFor(LiveInterval* interval) { } size_t end = last_sibling->GetEnd(); + GrowableArray<size_t>* spill_slots = nullptr; + switch (interval->GetType()) { + case Primitive::kPrimDouble: + spill_slots = &double_spill_slots_; + break; + case Primitive::kPrimLong: + spill_slots = &long_spill_slots_; + break; + case Primitive::kPrimFloat: + spill_slots = &float_spill_slots_; + break; + case Primitive::kPrimNot: + case Primitive::kPrimInt: + case Primitive::kPrimChar: + case Primitive::kPrimByte: + case Primitive::kPrimBoolean: + case Primitive::kPrimShort: + spill_slots = &int_spill_slots_; + break; + case Primitive::kPrimVoid: + LOG(FATAL) << "Unexpected type for interval " << interval->GetType(); + } + // Find an available spill slot. size_t slot = 0; - for (size_t e = spill_slots_.Size(); slot < e; ++slot) { - // We check if it is less rather than less or equal because the parallel move - // resolver does not work when a single spill slot needs to be exchanged with - // a double spill slot. The strict comparison avoids needing to exchange these - // locations at the same lifetime position. - if (spill_slots_.Get(slot) < parent->GetStart() - && (slot == (e - 1) || spill_slots_.Get(slot + 1) < parent->GetStart())) { + for (size_t e = spill_slots->Size(); slot < e; ++slot) { + if (spill_slots->Get(slot) <= parent->GetStart() + && (slot == (e - 1) || spill_slots->Get(slot + 1) <= parent->GetStart())) { break; } } if (parent->NeedsTwoSpillSlots()) { - if (slot == spill_slots_.Size()) { + if (slot == spill_slots->Size()) { // We need a new spill slot. - spill_slots_.Add(end); - spill_slots_.Add(end); - } else if (slot == spill_slots_.Size() - 1) { - spill_slots_.Put(slot, end); - spill_slots_.Add(end); + spill_slots->Add(end); + spill_slots->Add(end); + } else if (slot == spill_slots->Size() - 1) { + spill_slots->Put(slot, end); + spill_slots->Add(end); } else { - spill_slots_.Put(slot, end); - spill_slots_.Put(slot + 1, end); + spill_slots->Put(slot, end); + spill_slots->Put(slot + 1, end); } } else { - if (slot == spill_slots_.Size()) { + if (slot == spill_slots->Size()) { // We need a new spill slot. - spill_slots_.Add(end); + spill_slots->Add(end); } else { - spill_slots_.Put(slot, end); + spill_slots->Put(slot, end); } } - parent->SetSpillSlot((slot + reserved_out_slots_) * kVRegSize); + // Note that the exact spill slot location will be computed when we resolve, + // that is when we know the number of spill slots for each type. + parent->SetSpillSlot(slot); } static bool IsValidDestination(Location destination) { @@ -1516,7 +1540,7 @@ void RegisterAllocator::ConnectSplitSiblings(LiveInterval* interval, } void RegisterAllocator::Resolve() { - codegen_->InitializeCodeGeneration(spill_slots_.Size(), + codegen_->InitializeCodeGeneration(GetNumberOfSpillSlots(), maximum_number_of_live_core_registers_, maximum_number_of_live_fp_registers_, reserved_out_slots_, @@ -1542,6 +1566,39 @@ void RegisterAllocator::Resolve() { } else if (current->HasSpillSlot()) { current->SetSpillSlot(current->GetSpillSlot() + codegen_->GetFrameSize()); } + } else if (current->HasSpillSlot()) { + // Adjust the stack slot, now that we know the number of them for each type. + // The way this implementation lays out the stack is the following: + // [parameter slots ] + // [double spill slots ] + // [long spill slots ] + // [float spill slots ] + // [int/ref values ] + // [maximum out values ] (number of arguments for calls) + // [art method ]. + uint32_t slot = current->GetSpillSlot(); + switch (current->GetType()) { + case Primitive::kPrimDouble: + slot += long_spill_slots_.Size(); + FALLTHROUGH_INTENDED; + case Primitive::kPrimLong: + slot += float_spill_slots_.Size(); + FALLTHROUGH_INTENDED; + case Primitive::kPrimFloat: + slot += int_spill_slots_.Size(); + FALLTHROUGH_INTENDED; + case Primitive::kPrimNot: + case Primitive::kPrimInt: + case Primitive::kPrimChar: + case Primitive::kPrimByte: + case Primitive::kPrimBoolean: + case Primitive::kPrimShort: + slot += reserved_out_slots_; + break; + case Primitive::kPrimVoid: + LOG(FATAL) << "Unexpected type for interval " << current->GetType(); + } + current->SetSpillSlot(slot * kVRegSize); } Location source = current->ToLocation(); diff --git a/compiler/optimizing/register_allocator.h b/compiler/optimizing/register_allocator.h index b8f70bdc18..ff2f106b74 100644 --- a/compiler/optimizing/register_allocator.h +++ b/compiler/optimizing/register_allocator.h @@ -75,7 +75,10 @@ class RegisterAllocator { } size_t GetNumberOfSpillSlots() const { - return spill_slots_.Size(); + return int_spill_slots_.Size() + + long_spill_slots_.Size() + + float_spill_slots_.Size() + + double_spill_slots_.Size(); } private: @@ -171,8 +174,14 @@ class RegisterAllocator { // where an instruction requires a temporary. GrowableArray<LiveInterval*> temp_intervals_; - // The spill slots allocated for live intervals. - GrowableArray<size_t> spill_slots_; + // The spill slots allocated for live intervals. We ensure spill slots + // are typed to avoid (1) doing moves and swaps between two different kinds + // of registers, and (2) swapping between a single stack slot and a double + // stack slot. This simplifies the parallel move resolver. + GrowableArray<size_t> int_spill_slots_; + GrowableArray<size_t> long_spill_slots_; + GrowableArray<size_t> float_spill_slots_; + GrowableArray<size_t> double_spill_slots_; // Instructions that need a safepoint. GrowableArray<HInstruction*> safepoints_; diff --git a/compiler/optimizing/ssa_phi_elimination.cc b/compiler/optimizing/ssa_phi_elimination.cc index f66a1c8de2..2f2e2d1fab 100644 --- a/compiler/optimizing/ssa_phi_elimination.cc +++ b/compiler/optimizing/ssa_phi_elimination.cc @@ -64,31 +64,33 @@ void SsaDeadPhiElimination::EliminateDeadPhis() { HBasicBlock* block = it.Current(); HInstruction* current = block->GetFirstPhi(); HInstruction* next = nullptr; + HPhi* phi; while (current != nullptr) { + phi = current->AsPhi(); next = current->GetNext(); - if (current->AsPhi()->IsDead()) { - if (current->HasUses()) { - for (HUseIterator<HInstruction*> use_it(current->GetUses()); !use_it.Done(); + if (phi->IsDead()) { + // Make sure the phi is only used by other dead phis. + if (kIsDebugBuild) { + for (HUseIterator<HInstruction*> use_it(phi->GetUses()); !use_it.Done(); use_it.Advance()) { - HUseListNode<HInstruction*>* user_node = use_it.Current(); - HInstruction* user = user_node->GetUser(); + HInstruction* user = use_it.Current()->GetUser(); DCHECK(user->IsLoopHeaderPhi()) << user->GetId(); DCHECK(user->AsPhi()->IsDead()) << user->GetId(); - // Just put itself as an input. The phi will be removed in this loop anyway. - user->SetRawInputAt(user_node->GetIndex(), user); - current->RemoveUser(user, user_node->GetIndex()); } } - if (current->HasEnvironmentUses()) { - for (HUseIterator<HEnvironment*> use_it(current->GetEnvUses()); !use_it.Done(); - use_it.Advance()) { - HUseListNode<HEnvironment*>* user_node = use_it.Current(); - HEnvironment* user = user_node->GetUser(); - user->SetRawEnvAt(user_node->GetIndex(), nullptr); - current->RemoveEnvironmentUser(user_node); - } + // Remove the phi from use lists of its inputs. + for (size_t i = 0, e = phi->InputCount(); i < e; ++i) { + phi->RemoveAsUserOfInput(i); + } + // Remove the phi from environments that use it. + for (HUseIterator<HEnvironment*> use_it(phi->GetEnvUses()); !use_it.Done(); + use_it.Advance()) { + HUseListNode<HEnvironment*>* user_node = use_it.Current(); + HEnvironment* user = user_node->GetUser(); + user->SetRawEnvAt(user_node->GetIndex(), nullptr); } - block->RemovePhi(current->AsPhi()); + // Delete it from the instruction list. + block->RemovePhi(phi, /*ensure_safety=*/ false); } current = next; } |