| /* |
| * Copyright (C) 2017 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| #include "instruction_simplifier_mips.h" |
| |
| #include "arch/mips/instruction_set_features_mips.h" |
| #include "mirror/array-inl.h" |
| |
| namespace art { |
| namespace mips { |
| |
| class InstructionSimplifierMipsVisitor : public HGraphVisitor { |
| public: |
| InstructionSimplifierMipsVisitor(HGraph* graph, |
| CodeGenerator* codegen, |
| OptimizingCompilerStats* stats) |
| : HGraphVisitor(graph), |
| stats_(stats), |
| codegen_(down_cast<CodeGeneratorMIPS*>(codegen)) {} |
| |
| private: |
| void RecordSimplification() { |
| MaybeRecordStat(stats_, MethodCompilationStat::kInstructionSimplificationsArch); |
| } |
| |
| bool TryExtractArrayAccessIndex(HInstruction* access, |
| HInstruction* index, |
| DataType::Type packed_type); |
| void VisitArrayGet(HArrayGet* instruction) override; |
| void VisitArraySet(HArraySet* instruction) override; |
| |
| OptimizingCompilerStats* stats_; |
| CodeGeneratorMIPS* codegen_; |
| }; |
| |
| bool InstructionSimplifierMipsVisitor::TryExtractArrayAccessIndex(HInstruction* access, |
| HInstruction* index, |
| DataType::Type packed_type) { |
| if (codegen_->GetInstructionSetFeatures().IsR6() || |
| codegen_->GetInstructionSetFeatures().HasMsa()) { |
| return false; |
| } |
| if (index->IsConstant() || |
| (index->IsBoundsCheck() && index->AsBoundsCheck()->GetIndex()->IsConstant())) { |
| // If index is constant the whole address calculation often can be done by load/store |
| // instructions themselves. |
| // TODO: Treat the case with non-embeddable constants. |
| return false; |
| } |
| |
| if (packed_type != DataType::Type::kInt16 && packed_type != DataType::Type::kUint16 && |
| packed_type != DataType::Type::kInt32 && packed_type != DataType::Type::kInt64 && |
| packed_type != DataType::Type::kFloat32 && packed_type != DataType::Type::kFloat64) { |
| return false; |
| } |
| |
| if (access->IsArrayGet() && access->AsArrayGet()->IsStringCharAt()) { |
| return false; |
| } |
| |
| HGraph* graph = access->GetBlock()->GetGraph(); |
| ArenaAllocator* allocator = graph->GetAllocator(); |
| size_t component_shift = DataType::SizeShift(packed_type); |
| |
| bool is_extracting_beneficial = false; |
| // It is beneficial to extract index intermediate address only if there are at least 2 users. |
| for (const HUseListNode<HInstruction*>& use : index->GetUses()) { |
| HInstruction* user = use.GetUser(); |
| if (user->IsArrayGet() && user != access && !user->AsArrayGet()->IsStringCharAt()) { |
| HArrayGet* another_access = user->AsArrayGet(); |
| DataType::Type another_packed_type = another_access->GetType(); |
| size_t another_component_shift = DataType::SizeShift(another_packed_type); |
| if (another_component_shift == component_shift) { |
| is_extracting_beneficial = true; |
| break; |
| } |
| } else if (user->IsArraySet() && user != access) { |
| HArraySet* another_access = user->AsArraySet(); |
| DataType::Type another_packed_type = another_access->GetType(); |
| size_t another_component_shift = DataType::SizeShift(another_packed_type); |
| if (another_component_shift == component_shift) { |
| is_extracting_beneficial = true; |
| break; |
| } |
| } else if (user->IsIntermediateArrayAddressIndex()) { |
| HIntermediateArrayAddressIndex* another_access = user->AsIntermediateArrayAddressIndex(); |
| size_t another_component_shift = another_access->GetShift()->AsIntConstant()->GetValue(); |
| if (another_component_shift == component_shift) { |
| is_extracting_beneficial = true; |
| break; |
| } |
| } |
| } |
| |
| if (!is_extracting_beneficial) { |
| return false; |
| } |
| |
| HIntConstant* shift = graph->GetIntConstant(component_shift); |
| HIntermediateArrayAddressIndex* address = |
| new (allocator) HIntermediateArrayAddressIndex(index, shift, kNoDexPc); |
| access->GetBlock()->InsertInstructionBefore(address, access); |
| access->ReplaceInput(address, 1); |
| return true; |
| } |
| |
| void InstructionSimplifierMipsVisitor::VisitArrayGet(HArrayGet* instruction) { |
| DataType::Type packed_type = instruction->GetType(); |
| if (TryExtractArrayAccessIndex(instruction, instruction->GetIndex(), packed_type)) { |
| RecordSimplification(); |
| } |
| } |
| |
| void InstructionSimplifierMipsVisitor::VisitArraySet(HArraySet* instruction) { |
| DataType::Type packed_type = instruction->GetComponentType(); |
| if (TryExtractArrayAccessIndex(instruction, instruction->GetIndex(), packed_type)) { |
| RecordSimplification(); |
| } |
| } |
| |
| bool InstructionSimplifierMips::Run() { |
| InstructionSimplifierMipsVisitor visitor(graph_, codegen_, stats_); |
| visitor.VisitReversePostOrder(); |
| return true; |
| } |
| |
| } // namespace mips |
| } // namespace art |