blob: 1c44e5ac49af0005b67ca4e60685df74415c2b94 [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() {
Vladimir Markocd09e1f2017-11-24 15:02:40 +000040 MaybeRecordStat(stats_, MethodCompilationStat::kInstructionSimplificationsArch);
Vladimir Marko0f689e72017-10-02 12:38:21 +010041 }
42
43 bool TryMergeIntoUsersShifterOperand(HInstruction* instruction);
44 bool TryMergeIntoShifterOperand(HInstruction* use,
45 HInstruction* bitfield_op,
46 bool do_merge);
47 bool CanMergeIntoShifterOperand(HInstruction* use, HInstruction* bitfield_op) {
48 return TryMergeIntoShifterOperand(use, bitfield_op, /* do_merge */ false);
49 }
50 bool MergeIntoShifterOperand(HInstruction* use, HInstruction* bitfield_op) {
51 DCHECK(CanMergeIntoShifterOperand(use, bitfield_op));
52 return TryMergeIntoShifterOperand(use, bitfield_op, /* do_merge */ true);
53 }
54
55 /**
56 * This simplifier uses a special-purpose BB visitor.
57 * (1) No need to visit Phi nodes.
58 * (2) Since statements can be removed in a "forward" fashion,
59 * the visitor should test if each statement is still there.
60 */
61 void VisitBasicBlock(HBasicBlock* block) OVERRIDE {
62 // TODO: fragile iteration, provide more robust iterators?
63 for (HInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) {
64 HInstruction* instruction = it.Current();
65 if (instruction->IsInBlock()) {
66 instruction->Accept(this);
67 }
68 }
69 }
70
71 // HInstruction visitors, sorted alphabetically.
72 void VisitAnd(HAnd* instruction) OVERRIDE;
73 void VisitArrayGet(HArrayGet* instruction) OVERRIDE;
74 void VisitArraySet(HArraySet* instruction) OVERRIDE;
75 void VisitMul(HMul* instruction) OVERRIDE;
76 void VisitOr(HOr* instruction) OVERRIDE;
77 void VisitShl(HShl* instruction) OVERRIDE;
78 void VisitShr(HShr* instruction) OVERRIDE;
79 void VisitTypeConversion(HTypeConversion* instruction) OVERRIDE;
80 void VisitUShr(HUShr* instruction) OVERRIDE;
81 void VisitXor(HXor* instruction) OVERRIDE;
82 void VisitVecLoad(HVecLoad* instruction) OVERRIDE;
83 void VisitVecStore(HVecStore* instruction) OVERRIDE;
84
85 OptimizingCompilerStats* stats_;
86};
87
Alexandre Rames8626b742015-11-25 16:28:08 +000088bool InstructionSimplifierArm64Visitor::TryMergeIntoShifterOperand(HInstruction* use,
89 HInstruction* bitfield_op,
90 bool do_merge) {
Vladimir Marko33bff252017-11-01 14:35:42 +000091 DCHECK(HasShifterOperand(use, InstructionSet::kArm64));
Alexandre Rames8626b742015-11-25 16:28:08 +000092 DCHECK(use->IsBinaryOperation() || use->IsNeg());
93 DCHECK(CanFitInShifterOperand(bitfield_op));
94 DCHECK(!bitfield_op->HasEnvironmentUses());
95
Vladimir Marko0ebe0d82017-09-21 22:50:39 +010096 DataType::Type type = use->GetType();
97 if (type != DataType::Type::kInt32 && type != DataType::Type::kInt64) {
Alexandre Rames8626b742015-11-25 16:28:08 +000098 return false;
99 }
100
101 HInstruction* left;
102 HInstruction* right;
103 if (use->IsBinaryOperation()) {
104 left = use->InputAt(0);
105 right = use->InputAt(1);
106 } else {
107 DCHECK(use->IsNeg());
108 right = use->AsNeg()->InputAt(0);
109 left = GetGraph()->GetConstant(right->GetType(), 0);
110 }
111 DCHECK(left == bitfield_op || right == bitfield_op);
112
113 if (left == right) {
114 // TODO: Handle special transformations in this situation?
115 // For example should we transform `(x << 1) + (x << 1)` into `(x << 2)`?
116 // Or should this be part of a separate transformation logic?
117 return false;
118 }
119
120 bool is_commutative = use->IsBinaryOperation() && use->AsBinaryOperation()->IsCommutative();
121 HInstruction* other_input;
122 if (bitfield_op == right) {
123 other_input = left;
124 } else {
125 if (is_commutative) {
126 other_input = right;
127 } else {
128 return false;
129 }
130 }
131
Anton Kirilov74234da2017-01-13 14:42:47 +0000132 HDataProcWithShifterOp::OpKind op_kind;
Alexandre Rames8626b742015-11-25 16:28:08 +0000133 int shift_amount = 0;
Anton Kirilov74234da2017-01-13 14:42:47 +0000134 HDataProcWithShifterOp::GetOpInfoFromInstruction(bitfield_op, &op_kind, &shift_amount);
Alexandre Rames8626b742015-11-25 16:28:08 +0000135
Anton Kirilov74234da2017-01-13 14:42:47 +0000136 if (HDataProcWithShifterOp::IsExtensionOp(op_kind) && !ShifterOperandSupportsExtension(use)) {
Alexandre Rames8626b742015-11-25 16:28:08 +0000137 return false;
138 }
139
140 if (do_merge) {
Anton Kirilov74234da2017-01-13 14:42:47 +0000141 HDataProcWithShifterOp* alu_with_op =
Vladimir Markoca6fff82017-10-03 14:49:14 +0100142 new (GetGraph()->GetAllocator()) HDataProcWithShifterOp(use,
143 other_input,
144 bitfield_op->InputAt(0),
145 op_kind,
146 shift_amount,
147 use->GetDexPc());
Alexandre Rames8626b742015-11-25 16:28:08 +0000148 use->GetBlock()->ReplaceAndRemoveInstructionWith(use, alu_with_op);
Vladimir Marko46817b82016-03-29 12:21:58 +0100149 if (bitfield_op->GetUses().empty()) {
Alexandre Rames8626b742015-11-25 16:28:08 +0000150 bitfield_op->GetBlock()->RemoveInstruction(bitfield_op);
151 }
152 RecordSimplification();
153 }
154
155 return true;
156}
157
158// Merge a bitfield move instruction into its uses if it can be merged in all of them.
159bool InstructionSimplifierArm64Visitor::TryMergeIntoUsersShifterOperand(HInstruction* bitfield_op) {
160 DCHECK(CanFitInShifterOperand(bitfield_op));
161
162 if (bitfield_op->HasEnvironmentUses()) {
163 return false;
164 }
165
166 const HUseList<HInstruction*>& uses = bitfield_op->GetUses();
167
168 // Check whether we can merge the instruction in all its users' shifter operand.
Vladimir Marko46817b82016-03-29 12:21:58 +0100169 for (const HUseListNode<HInstruction*>& use : uses) {
170 HInstruction* user = use.GetUser();
Vladimir Marko33bff252017-11-01 14:35:42 +0000171 if (!HasShifterOperand(user, InstructionSet::kArm64)) {
Alexandre Rames8626b742015-11-25 16:28:08 +0000172 return false;
173 }
Vladimir Marko46817b82016-03-29 12:21:58 +0100174 if (!CanMergeIntoShifterOperand(user, bitfield_op)) {
Alexandre Rames8626b742015-11-25 16:28:08 +0000175 return false;
176 }
177 }
178
179 // Merge the instruction into its uses.
Vladimir Marko46817b82016-03-29 12:21:58 +0100180 for (auto it = uses.begin(), end = uses.end(); it != end; /* ++it below */) {
181 HInstruction* user = it->GetUser();
182 // Increment `it` now because `*it` will disappear thanks to MergeIntoShifterOperand().
183 ++it;
184 bool merged = MergeIntoShifterOperand(user, bitfield_op);
Alexandre Rames8626b742015-11-25 16:28:08 +0000185 DCHECK(merged);
186 }
187
188 return true;
189}
190
Kevin Brodsky9ff0d202016-01-11 13:43:31 +0000191void InstructionSimplifierArm64Visitor::VisitAnd(HAnd* instruction) {
Artem Serov7fc63502016-02-09 17:15:29 +0000192 if (TryMergeNegatedInput(instruction)) {
193 RecordSimplification();
194 }
Kevin Brodsky9ff0d202016-01-11 13:43:31 +0000195}
196
Alexandre Ramese6dbf482015-10-19 10:10:41 +0100197void InstructionSimplifierArm64Visitor::VisitArrayGet(HArrayGet* instruction) {
Vladimir Marko87f3fcb2016-04-28 15:52:11 +0100198 size_t data_offset = CodeGenerator::GetArrayDataOffset(instruction);
Artem Serov328429f2016-07-06 16:23:04 +0100199 if (TryExtractArrayAccessAddress(instruction,
200 instruction->GetArray(),
201 instruction->GetIndex(),
202 data_offset)) {
203 RecordSimplification();
204 }
Alexandre Ramese6dbf482015-10-19 10:10:41 +0100205}
206
207void InstructionSimplifierArm64Visitor::VisitArraySet(HArraySet* instruction) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100208 size_t access_size = DataType::Size(instruction->GetComponentType());
Vladimir Marko87f3fcb2016-04-28 15:52:11 +0100209 size_t data_offset = mirror::Array::DataOffset(access_size).Uint32Value();
Artem Serov328429f2016-07-06 16:23:04 +0100210 if (TryExtractArrayAccessAddress(instruction,
211 instruction->GetArray(),
212 instruction->GetIndex(),
213 data_offset)) {
214 RecordSimplification();
215 }
Alexandre Ramese6dbf482015-10-19 10:10:41 +0100216}
217
Alexandre Rames418318f2015-11-20 15:55:47 +0000218void InstructionSimplifierArm64Visitor::VisitMul(HMul* instruction) {
Vladimir Marko33bff252017-11-01 14:35:42 +0000219 if (TryCombineMultiplyAccumulate(instruction, InstructionSet::kArm64)) {
Artem Udovichenko4a0dad62016-01-26 12:28:31 +0300220 RecordSimplification();
Alexandre Rames418318f2015-11-20 15:55:47 +0000221 }
222}
223
Kevin Brodsky9ff0d202016-01-11 13:43:31 +0000224void InstructionSimplifierArm64Visitor::VisitOr(HOr* instruction) {
Artem Serov7fc63502016-02-09 17:15:29 +0000225 if (TryMergeNegatedInput(instruction)) {
226 RecordSimplification();
227 }
Kevin Brodsky9ff0d202016-01-11 13:43:31 +0000228}
229
Alexandre Rames8626b742015-11-25 16:28:08 +0000230void InstructionSimplifierArm64Visitor::VisitShl(HShl* instruction) {
231 if (instruction->InputAt(1)->IsConstant()) {
232 TryMergeIntoUsersShifterOperand(instruction);
233 }
234}
235
236void InstructionSimplifierArm64Visitor::VisitShr(HShr* instruction) {
237 if (instruction->InputAt(1)->IsConstant()) {
238 TryMergeIntoUsersShifterOperand(instruction);
239 }
240}
241
242void InstructionSimplifierArm64Visitor::VisitTypeConversion(HTypeConversion* instruction) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100243 DataType::Type result_type = instruction->GetResultType();
244 DataType::Type input_type = instruction->GetInputType();
Alexandre Rames8626b742015-11-25 16:28:08 +0000245
246 if (input_type == result_type) {
247 // We let the arch-independent code handle this.
248 return;
249 }
250
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100251 if (DataType::IsIntegralType(result_type) && DataType::IsIntegralType(input_type)) {
Alexandre Rames8626b742015-11-25 16:28:08 +0000252 TryMergeIntoUsersShifterOperand(instruction);
253 }
254}
255
256void InstructionSimplifierArm64Visitor::VisitUShr(HUShr* instruction) {
257 if (instruction->InputAt(1)->IsConstant()) {
258 TryMergeIntoUsersShifterOperand(instruction);
259 }
260}
261
Kevin Brodsky9ff0d202016-01-11 13:43:31 +0000262void InstructionSimplifierArm64Visitor::VisitXor(HXor* instruction) {
Artem Serov7fc63502016-02-09 17:15:29 +0000263 if (TryMergeNegatedInput(instruction)) {
264 RecordSimplification();
265 }
Kevin Brodsky9ff0d202016-01-11 13:43:31 +0000266}
267
Artem Serove1811ed2017-04-27 16:50:47 +0100268void InstructionSimplifierArm64Visitor::VisitVecLoad(HVecLoad* instruction) {
269 if (!instruction->IsStringCharAt()
270 && TryExtractVecArrayAccessAddress(instruction, instruction->GetIndex())) {
271 RecordSimplification();
272 }
273}
274
275void InstructionSimplifierArm64Visitor::VisitVecStore(HVecStore* instruction) {
276 if (TryExtractVecArrayAccessAddress(instruction, instruction->GetIndex())) {
277 RecordSimplification();
278 }
279}
280
Vladimir Marko0f689e72017-10-02 12:38:21 +0100281void InstructionSimplifierArm64::Run() {
282 InstructionSimplifierArm64Visitor visitor(graph_, stats_);
283 visitor.VisitReversePostOrder();
284}
285
Alexandre Rames44b9cf92015-08-19 15:39:06 +0100286} // namespace arm64
287} // namespace art