1 /* 2 * Copyright (C) 2017 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include "instruction_simplifier_mips.h" 18 19 #include "arch/mips/instruction_set_features_mips.h" 20 #include "mirror/array-inl.h" 21 22 namespace art { 23 namespace mips { 24 25 class InstructionSimplifierMipsVisitor : public HGraphVisitor { 26 public: 27 InstructionSimplifierMipsVisitor(HGraph* graph, 28 CodeGenerator* codegen, 29 OptimizingCompilerStats* stats) 30 : HGraphVisitor(graph), 31 stats_(stats), 32 codegen_(down_cast<CodeGeneratorMIPS*>(codegen)) {} 33 34 private: 35 void RecordSimplification() { 36 MaybeRecordStat(stats_, MethodCompilationStat::kInstructionSimplificationsArch); 37 } 38 39 bool TryExtractArrayAccessIndex(HInstruction* access, 40 HInstruction* index, 41 DataType::Type packed_type); 42 void VisitArrayGet(HArrayGet* instruction) OVERRIDE; 43 void VisitArraySet(HArraySet* instruction) OVERRIDE; 44 45 OptimizingCompilerStats* stats_; 46 CodeGeneratorMIPS* codegen_; 47 }; 48 49 bool InstructionSimplifierMipsVisitor::TryExtractArrayAccessIndex(HInstruction* access, 50 HInstruction* index, 51 DataType::Type packed_type) { 52 if (codegen_->GetInstructionSetFeatures().IsR6() || 53 codegen_->GetInstructionSetFeatures().HasMsa()) { 54 return false; 55 } 56 if (index->IsConstant() || 57 (index->IsBoundsCheck() && index->AsBoundsCheck()->GetIndex()->IsConstant())) { 58 // If index is constant the whole address calculation often can be done by load/store 59 // instructions themselves. 60 // TODO: Treat the case with non-embeddable constants. 61 return false; 62 } 63 64 if (packed_type != DataType::Type::kInt16 && packed_type != DataType::Type::kUint16 && 65 packed_type != DataType::Type::kInt32 && packed_type != DataType::Type::kInt64 && 66 packed_type != DataType::Type::kFloat32 && packed_type != DataType::Type::kFloat64) { 67 return false; 68 } 69 70 if (access->IsArrayGet() && access->AsArrayGet()->IsStringCharAt()) { 71 return false; 72 } 73 74 HGraph* graph = access->GetBlock()->GetGraph(); 75 ArenaAllocator* allocator = graph->GetAllocator(); 76 size_t component_shift = DataType::SizeShift(packed_type); 77 78 bool is_extracting_beneficial = false; 79 // It is beneficial to extract index intermediate address only if there are at least 2 users. 80 for (const HUseListNode<HInstruction*>& use : index->GetUses()) { 81 HInstruction* user = use.GetUser(); 82 if (user->IsArrayGet() && user != access && !user->AsArrayGet()->IsStringCharAt()) { 83 HArrayGet* another_access = user->AsArrayGet(); 84 DataType::Type another_packed_type = another_access->GetType(); 85 size_t another_component_shift = DataType::SizeShift(another_packed_type); 86 if (another_component_shift == component_shift) { 87 is_extracting_beneficial = true; 88 break; 89 } 90 } else if (user->IsArraySet() && user != access) { 91 HArraySet* another_access = user->AsArraySet(); 92 DataType::Type another_packed_type = another_access->GetType(); 93 size_t another_component_shift = DataType::SizeShift(another_packed_type); 94 if (another_component_shift == component_shift) { 95 is_extracting_beneficial = true; 96 break; 97 } 98 } else if (user->IsIntermediateArrayAddressIndex()) { 99 HIntermediateArrayAddressIndex* another_access = user->AsIntermediateArrayAddressIndex(); 100 size_t another_component_shift = another_access->GetShift()->AsIntConstant()->GetValue(); 101 if (another_component_shift == component_shift) { 102 is_extracting_beneficial = true; 103 break; 104 } 105 } 106 } 107 108 if (!is_extracting_beneficial) { 109 return false; 110 } 111 112 HIntConstant* shift = graph->GetIntConstant(component_shift); 113 HIntermediateArrayAddressIndex* address = 114 new (allocator) HIntermediateArrayAddressIndex(index, shift, kNoDexPc); 115 access->GetBlock()->InsertInstructionBefore(address, access); 116 access->ReplaceInput(address, 1); 117 return true; 118 } 119 120 void InstructionSimplifierMipsVisitor::VisitArrayGet(HArrayGet* instruction) { 121 DataType::Type packed_type = instruction->GetType(); 122 if (TryExtractArrayAccessIndex(instruction, instruction->GetIndex(), packed_type)) { 123 RecordSimplification(); 124 } 125 } 126 127 void InstructionSimplifierMipsVisitor::VisitArraySet(HArraySet* instruction) { 128 DataType::Type packed_type = instruction->GetComponentType(); 129 if (TryExtractArrayAccessIndex(instruction, instruction->GetIndex(), packed_type)) { 130 RecordSimplification(); 131 } 132 } 133 134 void InstructionSimplifierMips::Run() { 135 InstructionSimplifierMipsVisitor visitor(graph_, codegen_, stats_); 136 visitor.VisitReversePostOrder(); 137 } 138 139 } // namespace mips 140 } // namespace art 141