blob: c6399535362f5c230dbf96c216f5a82c7eda099c [file] [log] [blame]
Alexandre Rames44b9cf92015-08-19 15:39:06 +01001/*
2 * Copyright (C) 2015 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_arm64.h"
18
Alexandre Rames8626b742015-11-25 16:28:08 +000019#include "common_arm64.h"
Artem Udovichenko4a0dad62016-01-26 12:28:31 +030020#include "instruction_simplifier_shared.h"
Alexandre Ramese6dbf482015-10-19 10:10:41 +010021#include "mirror/array-inl.h"
Vladimir Marko87f3fcb2016-04-28 15:52:11 +010022#include "mirror/string.h"
Alexandre Ramese6dbf482015-10-19 10:10:41 +010023
Alexandre Rames44b9cf92015-08-19 15:39:06 +010024namespace art {
Alexandre Rames44b9cf92015-08-19 15:39:06 +010025
Alexandre Rames8626b742015-11-25 16:28:08 +000026using helpers::CanFitInShifterOperand;
27using helpers::HasShifterOperand;
Anton Kirilov74234da2017-01-13 14:42:47 +000028
29namespace arm64 {
30
Alexandre Rames8626b742015-11-25 16:28:08 +000031using helpers::ShifterOperandSupportsExtension;
32
Vladimir Marko0f689e72017-10-02 12:38:21 +010033class InstructionSimplifierArm64Visitor : public HGraphVisitor {
34 public:
35 InstructionSimplifierArm64Visitor(HGraph* graph, OptimizingCompilerStats* stats)
36 : HGraphVisitor(graph), stats_(stats) {}
37
38 private:
39 void RecordSimplification() {
40 if (stats_ != nullptr) {
41 stats_->RecordStat(kInstructionSimplificationsArch);
42 }
43 }
44
45 bool TryMergeIntoUsersShifterOperand(HInstruction* instruction);
46 bool TryMergeIntoShifterOperand(HInstruction* use,
47 HInstruction* bitfield_op,
48 bool do_merge);
49 bool CanMergeIntoShifterOperand(HInstruction* use, HInstruction* bitfield_op) {
50 return TryMergeIntoShifterOperand(use, bitfield_op, /* do_merge */ false);
51 }
52 bool MergeIntoShifterOperand(HInstruction* use, HInstruction* bitfield_op) {
53 DCHECK(CanMergeIntoShifterOperand(use, bitfield_op));
54 return TryMergeIntoShifterOperand(use, bitfield_op, /* do_merge */ true);
55 }
56
57 /**
58 * This simplifier uses a special-purpose BB visitor.
59 * (1) No need to visit Phi nodes.
60 * (2) Since statements can be removed in a "forward" fashion,
61 * the visitor should test if each statement is still there.
62 */
63 void VisitBasicBlock(HBasicBlock* block) OVERRIDE {
64 // TODO: fragile iteration, provide more robust iterators?
65 for (HInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) {
66 HInstruction* instruction = it.Current();
67 if (instruction->IsInBlock()) {
68 instruction->Accept(this);
69 }
70 }
71 }
72
73 // HInstruction visitors, sorted alphabetically.
74 void VisitAnd(HAnd* instruction) OVERRIDE;
75 void VisitArrayGet(HArrayGet* instruction) OVERRIDE;
76 void VisitArraySet(HArraySet* instruction) OVERRIDE;
77 void VisitMul(HMul* instruction) OVERRIDE;
78 void VisitOr(HOr* instruction) OVERRIDE;
79 void VisitShl(HShl* instruction) OVERRIDE;
80 void VisitShr(HShr* instruction) OVERRIDE;
81 void VisitTypeConversion(HTypeConversion* instruction) OVERRIDE;
82 void VisitUShr(HUShr* instruction) OVERRIDE;
83 void VisitXor(HXor* instruction) OVERRIDE;
84 void VisitVecLoad(HVecLoad* instruction) OVERRIDE;
85 void VisitVecStore(HVecStore* instruction) OVERRIDE;
86
87 OptimizingCompilerStats* stats_;
88};
89
Alexandre Rames8626b742015-11-25 16:28:08 +000090bool InstructionSimplifierArm64Visitor::TryMergeIntoShifterOperand(HInstruction* use,
91 HInstruction* bitfield_op,
92 bool do_merge) {
Anton Kirilov74234da2017-01-13 14:42:47 +000093 DCHECK(HasShifterOperand(use, kArm64));
Alexandre Rames8626b742015-11-25 16:28:08 +000094 DCHECK(use->IsBinaryOperation() || use->IsNeg());
95 DCHECK(CanFitInShifterOperand(bitfield_op));
96 DCHECK(!bitfield_op->HasEnvironmentUses());
97
Vladimir Marko0ebe0d82017-09-21 22:50:39 +010098 DataType::Type type = use->GetType();
99 if (type != DataType::Type::kInt32 && type != DataType::Type::kInt64) {
Alexandre Rames8626b742015-11-25 16:28:08 +0000100 return false;
101 }
102
103 HInstruction* left;
104 HInstruction* right;
105 if (use->IsBinaryOperation()) {
106 left = use->InputAt(0);
107 right = use->InputAt(1);
108 } else {
109 DCHECK(use->IsNeg());
110 right = use->AsNeg()->InputAt(0);
111 left = GetGraph()->GetConstant(right->GetType(), 0);
112 }
113 DCHECK(left == bitfield_op || right == bitfield_op);
114
115 if (left == right) {
116 // TODO: Handle special transformations in this situation?
117 // For example should we transform `(x << 1) + (x << 1)` into `(x << 2)`?
118 // Or should this be part of a separate transformation logic?
119 return false;
120 }
121
122 bool is_commutative = use->IsBinaryOperation() && use->AsBinaryOperation()->IsCommutative();
123 HInstruction* other_input;
124 if (bitfield_op == right) {
125 other_input = left;
126 } else {
127 if (is_commutative) {
128 other_input = right;
129 } else {
130 return false;
131 }
132 }
133
Anton Kirilov74234da2017-01-13 14:42:47 +0000134 HDataProcWithShifterOp::OpKind op_kind;
Alexandre Rames8626b742015-11-25 16:28:08 +0000135 int shift_amount = 0;
Anton Kirilov74234da2017-01-13 14:42:47 +0000136 HDataProcWithShifterOp::GetOpInfoFromInstruction(bitfield_op, &op_kind, &shift_amount);
Alexandre Rames8626b742015-11-25 16:28:08 +0000137
Anton Kirilov74234da2017-01-13 14:42:47 +0000138 if (HDataProcWithShifterOp::IsExtensionOp(op_kind) && !ShifterOperandSupportsExtension(use)) {
Alexandre Rames8626b742015-11-25 16:28:08 +0000139 return false;
140 }
141
142 if (do_merge) {
Anton Kirilov74234da2017-01-13 14:42:47 +0000143 HDataProcWithShifterOp* alu_with_op =
144 new (GetGraph()->GetArena()) HDataProcWithShifterOp(use,
145 other_input,
146 bitfield_op->InputAt(0),
147 op_kind,
148 shift_amount,
149 use->GetDexPc());
Alexandre Rames8626b742015-11-25 16:28:08 +0000150 use->GetBlock()->ReplaceAndRemoveInstructionWith(use, alu_with_op);
Vladimir Marko46817b82016-03-29 12:21:58 +0100151 if (bitfield_op->GetUses().empty()) {
Alexandre Rames8626b742015-11-25 16:28:08 +0000152 bitfield_op->GetBlock()->RemoveInstruction(bitfield_op);
153 }
154 RecordSimplification();
155 }
156
157 return true;
158}
159
160// Merge a bitfield move instruction into its uses if it can be merged in all of them.
161bool InstructionSimplifierArm64Visitor::TryMergeIntoUsersShifterOperand(HInstruction* bitfield_op) {
162 DCHECK(CanFitInShifterOperand(bitfield_op));
163
164 if (bitfield_op->HasEnvironmentUses()) {
165 return false;
166 }
167
168 const HUseList<HInstruction*>& uses = bitfield_op->GetUses();
169
170 // Check whether we can merge the instruction in all its users' shifter operand.
Vladimir Marko46817b82016-03-29 12:21:58 +0100171 for (const HUseListNode<HInstruction*>& use : uses) {
172 HInstruction* user = use.GetUser();
Anton Kirilov74234da2017-01-13 14:42:47 +0000173 if (!HasShifterOperand(user, kArm64)) {
Alexandre Rames8626b742015-11-25 16:28:08 +0000174 return false;
175 }
Vladimir Marko46817b82016-03-29 12:21:58 +0100176 if (!CanMergeIntoShifterOperand(user, bitfield_op)) {
Alexandre Rames8626b742015-11-25 16:28:08 +0000177 return false;
178 }
179 }
180
181 // Merge the instruction into its uses.
Vladimir Marko46817b82016-03-29 12:21:58 +0100182 for (auto it = uses.begin(), end = uses.end(); it != end; /* ++it below */) {
183 HInstruction* user = it->GetUser();
184 // Increment `it` now because `*it` will disappear thanks to MergeIntoShifterOperand().
185 ++it;
186 bool merged = MergeIntoShifterOperand(user, bitfield_op);
Alexandre Rames8626b742015-11-25 16:28:08 +0000187 DCHECK(merged);
188 }
189
190 return true;
191}
192
Kevin Brodsky9ff0d202016-01-11 13:43:31 +0000193void InstructionSimplifierArm64Visitor::VisitAnd(HAnd* instruction) {
Artem Serov7fc63502016-02-09 17:15:29 +0000194 if (TryMergeNegatedInput(instruction)) {
195 RecordSimplification();
196 }
Kevin Brodsky9ff0d202016-01-11 13:43:31 +0000197}
198
Alexandre Ramese6dbf482015-10-19 10:10:41 +0100199void InstructionSimplifierArm64Visitor::VisitArrayGet(HArrayGet* instruction) {
Vladimir Marko87f3fcb2016-04-28 15:52:11 +0100200 size_t data_offset = CodeGenerator::GetArrayDataOffset(instruction);
Artem Serov328429f2016-07-06 16:23:04 +0100201 if (TryExtractArrayAccessAddress(instruction,
202 instruction->GetArray(),
203 instruction->GetIndex(),
204 data_offset)) {
205 RecordSimplification();
206 }
Alexandre Ramese6dbf482015-10-19 10:10:41 +0100207}
208
209void InstructionSimplifierArm64Visitor::VisitArraySet(HArraySet* instruction) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100210 size_t access_size = DataType::Size(instruction->GetComponentType());
Vladimir Marko87f3fcb2016-04-28 15:52:11 +0100211 size_t data_offset = mirror::Array::DataOffset(access_size).Uint32Value();
Artem Serov328429f2016-07-06 16:23:04 +0100212 if (TryExtractArrayAccessAddress(instruction,
213 instruction->GetArray(),
214 instruction->GetIndex(),
215 data_offset)) {
216 RecordSimplification();
217 }
Alexandre Ramese6dbf482015-10-19 10:10:41 +0100218}
219
Alexandre Rames418318f2015-11-20 15:55:47 +0000220void InstructionSimplifierArm64Visitor::VisitMul(HMul* instruction) {
Artem Udovichenko4a0dad62016-01-26 12:28:31 +0300221 if (TryCombineMultiplyAccumulate(instruction, kArm64)) {
222 RecordSimplification();
Alexandre Rames418318f2015-11-20 15:55:47 +0000223 }
224}
225
Kevin Brodsky9ff0d202016-01-11 13:43:31 +0000226void InstructionSimplifierArm64Visitor::VisitOr(HOr* instruction) {
Artem Serov7fc63502016-02-09 17:15:29 +0000227 if (TryMergeNegatedInput(instruction)) {
228 RecordSimplification();
229 }
Kevin Brodsky9ff0d202016-01-11 13:43:31 +0000230}
231
Alexandre Rames8626b742015-11-25 16:28:08 +0000232void InstructionSimplifierArm64Visitor::VisitShl(HShl* instruction) {
233 if (instruction->InputAt(1)->IsConstant()) {
234 TryMergeIntoUsersShifterOperand(instruction);
235 }
236}
237
238void InstructionSimplifierArm64Visitor::VisitShr(HShr* instruction) {
239 if (instruction->InputAt(1)->IsConstant()) {
240 TryMergeIntoUsersShifterOperand(instruction);
241 }
242}
243
244void InstructionSimplifierArm64Visitor::VisitTypeConversion(HTypeConversion* instruction) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100245 DataType::Type result_type = instruction->GetResultType();
246 DataType::Type input_type = instruction->GetInputType();
Alexandre Rames8626b742015-11-25 16:28:08 +0000247
248 if (input_type == result_type) {
249 // We let the arch-independent code handle this.
250 return;
251 }
252
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100253 if (DataType::IsIntegralType(result_type) && DataType::IsIntegralType(input_type)) {
Alexandre Rames8626b742015-11-25 16:28:08 +0000254 TryMergeIntoUsersShifterOperand(instruction);
255 }
256}
257
258void InstructionSimplifierArm64Visitor::VisitUShr(HUShr* instruction) {
259 if (instruction->InputAt(1)->IsConstant()) {
260 TryMergeIntoUsersShifterOperand(instruction);
261 }
262}
263
Kevin Brodsky9ff0d202016-01-11 13:43:31 +0000264void InstructionSimplifierArm64Visitor::VisitXor(HXor* instruction) {
Artem Serov7fc63502016-02-09 17:15:29 +0000265 if (TryMergeNegatedInput(instruction)) {
266 RecordSimplification();
267 }
Kevin Brodsky9ff0d202016-01-11 13:43:31 +0000268}
269
Artem Serove1811ed2017-04-27 16:50:47 +0100270void InstructionSimplifierArm64Visitor::VisitVecLoad(HVecLoad* instruction) {
271 if (!instruction->IsStringCharAt()
272 && TryExtractVecArrayAccessAddress(instruction, instruction->GetIndex())) {
273 RecordSimplification();
274 }
275}
276
277void InstructionSimplifierArm64Visitor::VisitVecStore(HVecStore* instruction) {
278 if (TryExtractVecArrayAccessAddress(instruction, instruction->GetIndex())) {
279 RecordSimplification();
280 }
281}
282
Vladimir Marko0f689e72017-10-02 12:38:21 +0100283void InstructionSimplifierArm64::Run() {
284 InstructionSimplifierArm64Visitor visitor(graph_, stats_);
285 visitor.VisitReversePostOrder();
286}
287
Alexandre Rames44b9cf92015-08-19 15:39:06 +0100288} // namespace arm64
289} // namespace art