blob: 6a0d8a60c4f2dfd395d22f6811fe89e3d2a3c408 [file] [log] [blame]
Lena Djokica2901602017-09-21 13:50:52 +02001/*
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
22namespace art {
23namespace mips {
24
25class 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 if (stats_ != nullptr) {
37 stats_->RecordStat(kInstructionSimplificationsArch);
38 }
39 }
40
41 bool TryExtractArrayAccessIndex(HInstruction* access,
42 HInstruction* index,
43 DataType::Type packed_type);
44 void VisitArrayGet(HArrayGet* instruction) OVERRIDE;
45 void VisitArraySet(HArraySet* instruction) OVERRIDE;
46
47 OptimizingCompilerStats* stats_;
48 CodeGeneratorMIPS* codegen_;
49};
50
51bool InstructionSimplifierMipsVisitor::TryExtractArrayAccessIndex(HInstruction* access,
52 HInstruction* index,
53 DataType::Type packed_type) {
54 if (codegen_->GetInstructionSetFeatures().IsR6() ||
55 codegen_->GetInstructionSetFeatures().HasMsa()) {
56 return false;
57 }
58 if (index->IsConstant() ||
59 (index->IsBoundsCheck() && index->AsBoundsCheck()->GetIndex()->IsConstant())) {
60 // If index is constant the whole address calculation often can be done by load/store
61 // instructions themselves.
62 // TODO: Treat the case with non-embeddable constants.
63 return false;
64 }
65
66 if (packed_type != DataType::Type::kInt16 && packed_type != DataType::Type::kUint16 &&
67 packed_type != DataType::Type::kInt32 && packed_type != DataType::Type::kInt64 &&
68 packed_type != DataType::Type::kFloat32 && packed_type != DataType::Type::kFloat64) {
69 return false;
70 }
71
72 if (access->IsArrayGet() && access->AsArrayGet()->IsStringCharAt()) {
73 return false;
74 }
75
76 HGraph* graph = access->GetBlock()->GetGraph();
Vladimir Markoca6fff82017-10-03 14:49:14 +010077 ArenaAllocator* allocator = graph->GetAllocator();
Lena Djokica2901602017-09-21 13:50:52 +020078 size_t component_shift = DataType::SizeShift(packed_type);
79
80 bool is_extracting_beneficial = false;
81 // It is beneficial to extract index intermediate address only if there are at least 2 users.
82 for (const HUseListNode<HInstruction*>& use : index->GetUses()) {
83 HInstruction* user = use.GetUser();
84 if (user->IsArrayGet() && user != access && !user->AsArrayGet()->IsStringCharAt()) {
85 HArrayGet* another_access = user->AsArrayGet();
86 DataType::Type another_packed_type = another_access->GetType();
87 size_t another_component_shift = DataType::SizeShift(another_packed_type);
88 if (another_component_shift == component_shift) {
89 is_extracting_beneficial = true;
90 break;
91 }
92 } else if (user->IsArraySet() && user != access) {
93 HArraySet* another_access = user->AsArraySet();
94 DataType::Type another_packed_type = another_access->GetType();
95 size_t another_component_shift = DataType::SizeShift(another_packed_type);
96 if (another_component_shift == component_shift) {
97 is_extracting_beneficial = true;
98 break;
99 }
100 } else if (user->IsIntermediateArrayAddressIndex()) {
101 HIntermediateArrayAddressIndex* another_access = user->AsIntermediateArrayAddressIndex();
102 size_t another_component_shift = another_access->GetShift()->AsIntConstant()->GetValue();
103 if (another_component_shift == component_shift) {
104 is_extracting_beneficial = true;
105 break;
106 }
107 }
108 }
109
110 if (!is_extracting_beneficial) {
111 return false;
112 }
113
114 HIntConstant* shift = graph->GetIntConstant(component_shift);
115 HIntermediateArrayAddressIndex* address =
Vladimir Markoca6fff82017-10-03 14:49:14 +0100116 new (allocator) HIntermediateArrayAddressIndex(index, shift, kNoDexPc);
Lena Djokica2901602017-09-21 13:50:52 +0200117 access->GetBlock()->InsertInstructionBefore(address, access);
118 access->ReplaceInput(address, 1);
119 return true;
120}
121
122void InstructionSimplifierMipsVisitor::VisitArrayGet(HArrayGet* instruction) {
123 DataType::Type packed_type = instruction->GetType();
124 if (TryExtractArrayAccessIndex(instruction, instruction->GetIndex(), packed_type)) {
125 RecordSimplification();
126 }
127}
128
129void InstructionSimplifierMipsVisitor::VisitArraySet(HArraySet* instruction) {
130 DataType::Type packed_type = instruction->GetComponentType();
131 if (TryExtractArrayAccessIndex(instruction, instruction->GetIndex(), packed_type)) {
132 RecordSimplification();
133 }
134}
135
136void InstructionSimplifierMips::Run() {
137 InstructionSimplifierMipsVisitor visitor(graph_, codegen_, stats_);
138 visitor.VisitReversePostOrder();
139}
140
141} // namespace mips
142} // namespace art