blob: 3fc7c50bb10d4fc53c86b8a63e9ccc09118e1568 [file] [log] [blame]
Artem Udovichenko4a0dad62016-01-26 12:28:31 +03001/*
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
Artem Serov328429f2016-07-06 16:23:04 +010017#include "code_generator.h"
Anton Kirilov74234da2017-01-13 14:42:47 +000018#include "common_arm.h"
Artem Udovichenko4a0dad62016-01-26 12:28:31 +030019#include "instruction_simplifier_arm.h"
20#include "instruction_simplifier_shared.h"
Artem Serov328429f2016-07-06 16:23:04 +010021#include "mirror/array-inl.h"
Andreas Gampec6ea7d02017-02-01 16:46:28 -080022#include "mirror/string.h"
Anton Kirilov74234da2017-01-13 14:42:47 +000023#include "nodes.h"
Artem Udovichenko4a0dad62016-01-26 12:28:31 +030024
25namespace art {
Anton Kirilov74234da2017-01-13 14:42:47 +000026
27using helpers::CanFitInShifterOperand;
28using helpers::HasShifterOperand;
29
Artem Udovichenko4a0dad62016-01-26 12:28:31 +030030namespace arm {
31
Anton Kirilov74234da2017-01-13 14:42:47 +000032using helpers::ShifterOperandSupportsExtension;
33
34bool InstructionSimplifierArmVisitor::TryMergeIntoShifterOperand(HInstruction* use,
35 HInstruction* bitfield_op,
36 bool do_merge) {
37 DCHECK(HasShifterOperand(use, kArm));
38 DCHECK(use->IsBinaryOperation());
39 DCHECK(CanFitInShifterOperand(bitfield_op));
40 DCHECK(!bitfield_op->HasEnvironmentUses());
41
42 Primitive::Type type = use->GetType();
43 if (type != Primitive::kPrimInt && type != Primitive::kPrimLong) {
44 return false;
45 }
46
47 HInstruction* left = use->InputAt(0);
48 HInstruction* right = use->InputAt(1);
49 DCHECK(left == bitfield_op || right == bitfield_op);
50
51 if (left == right) {
52 // TODO: Handle special transformations in this situation?
53 // For example should we transform `(x << 1) + (x << 1)` into `(x << 2)`?
54 // Or should this be part of a separate transformation logic?
55 return false;
56 }
57
58 bool is_commutative = use->AsBinaryOperation()->IsCommutative();
59 HInstruction* other_input;
60 if (bitfield_op == right) {
61 other_input = left;
62 } else {
63 if (is_commutative) {
64 other_input = right;
65 } else {
66 return false;
67 }
68 }
69
70 HDataProcWithShifterOp::OpKind op_kind;
71 int shift_amount = 0;
72
73 HDataProcWithShifterOp::GetOpInfoFromInstruction(bitfield_op, &op_kind, &shift_amount);
74 shift_amount &= use->GetType() == Primitive::kPrimInt
75 ? kMaxIntShiftDistance
76 : kMaxLongShiftDistance;
77
78 if (HDataProcWithShifterOp::IsExtensionOp(op_kind)) {
79 if (!ShifterOperandSupportsExtension(use)) {
80 return false;
81 }
82 // Shift by 1 is a special case that results in the same number and type of instructions
83 // as this simplification, but potentially shorter code.
84 } else if (type == Primitive::kPrimLong && shift_amount == 1) {
85 return false;
86 }
87
88 if (do_merge) {
89 HDataProcWithShifterOp* alu_with_op =
90 new (GetGraph()->GetArena()) HDataProcWithShifterOp(use,
91 other_input,
92 bitfield_op->InputAt(0),
93 op_kind,
94 shift_amount,
95 use->GetDexPc());
96 use->GetBlock()->ReplaceAndRemoveInstructionWith(use, alu_with_op);
97 if (bitfield_op->GetUses().empty()) {
98 bitfield_op->GetBlock()->RemoveInstruction(bitfield_op);
99 }
Artem Udovichenko4a0dad62016-01-26 12:28:31 +0300100 RecordSimplification();
101 }
Anton Kirilov74234da2017-01-13 14:42:47 +0000102
103 return true;
Artem Udovichenko4a0dad62016-01-26 12:28:31 +0300104}
105
Anton Kirilov74234da2017-01-13 14:42:47 +0000106// Merge a bitfield move instruction into its uses if it can be merged in all of them.
107bool InstructionSimplifierArmVisitor::TryMergeIntoUsersShifterOperand(HInstruction* bitfield_op) {
108 DCHECK(CanFitInShifterOperand(bitfield_op));
109
110 if (bitfield_op->HasEnvironmentUses()) {
111 return false;
Artem Serov7fc63502016-02-09 17:15:29 +0000112 }
Anton Kirilov74234da2017-01-13 14:42:47 +0000113
114 const HUseList<HInstruction*>& uses = bitfield_op->GetUses();
115
116 // Check whether we can merge the instruction in all its users' shifter operand.
117 for (const HUseListNode<HInstruction*>& use : uses) {
118 HInstruction* user = use.GetUser();
119 if (!HasShifterOperand(user, kArm)) {
120 return false;
121 }
122 if (!CanMergeIntoShifterOperand(user, bitfield_op)) {
123 return false;
124 }
125 }
126
127 // Merge the instruction into its uses.
128 for (auto it = uses.begin(), end = uses.end(); it != end; /* ++it below */) {
129 HInstruction* user = it->GetUser();
130 // Increment `it` now because `*it` will disappear thanks to MergeIntoShifterOperand().
131 ++it;
132 bool merged = MergeIntoShifterOperand(user, bitfield_op);
133 DCHECK(merged);
134 }
135
136 return true;
Artem Serov7fc63502016-02-09 17:15:29 +0000137}
138
139void InstructionSimplifierArmVisitor::VisitAnd(HAnd* instruction) {
140 if (TryMergeNegatedInput(instruction)) {
141 RecordSimplification();
142 }
143}
144
Artem Serov328429f2016-07-06 16:23:04 +0100145void InstructionSimplifierArmVisitor::VisitArrayGet(HArrayGet* instruction) {
146 size_t data_offset = CodeGenerator::GetArrayDataOffset(instruction);
147 Primitive::Type type = instruction->GetType();
148
jessicahandojo05765752016-09-09 19:01:32 -0700149 // TODO: Implement reading (length + compression) for String compression feature from
150 // negative offset (count_offset - data_offset). Thumb2Assembler does not support T4
151 // encoding of "LDR (immediate)" at the moment.
152 // Don't move array pointer if it is charAt because we need to take the count first.
153 if (mirror::kUseStringCompression && instruction->IsStringCharAt()) {
154 return;
155 }
156
Artem Serov328429f2016-07-06 16:23:04 +0100157 if (type == Primitive::kPrimLong
158 || type == Primitive::kPrimFloat
159 || type == Primitive::kPrimDouble) {
160 // T32 doesn't support ShiftedRegOffset mem address mode for these types
161 // to enable optimization.
162 return;
163 }
164
165 if (TryExtractArrayAccessAddress(instruction,
166 instruction->GetArray(),
167 instruction->GetIndex(),
168 data_offset)) {
169 RecordSimplification();
170 }
171}
172
173void InstructionSimplifierArmVisitor::VisitArraySet(HArraySet* instruction) {
174 size_t access_size = Primitive::ComponentSize(instruction->GetComponentType());
175 size_t data_offset = mirror::Array::DataOffset(access_size).Uint32Value();
176 Primitive::Type type = instruction->GetComponentType();
177
178 if (type == Primitive::kPrimLong
179 || type == Primitive::kPrimFloat
180 || type == Primitive::kPrimDouble) {
181 // T32 doesn't support ShiftedRegOffset mem address mode for these types
182 // to enable optimization.
183 return;
184 }
185
186 if (TryExtractArrayAccessAddress(instruction,
187 instruction->GetArray(),
188 instruction->GetIndex(),
189 data_offset)) {
190 RecordSimplification();
191 }
192}
Artem Serov7fc63502016-02-09 17:15:29 +0000193
Anton Kirilov74234da2017-01-13 14:42:47 +0000194void InstructionSimplifierArmVisitor::VisitMul(HMul* instruction) {
195 if (TryCombineMultiplyAccumulate(instruction, kArm)) {
196 RecordSimplification();
197 }
198}
199
200void InstructionSimplifierArmVisitor::VisitOr(HOr* instruction) {
201 if (TryMergeNegatedInput(instruction)) {
202 RecordSimplification();
203 }
204}
205
206void InstructionSimplifierArmVisitor::VisitShl(HShl* instruction) {
207 if (instruction->InputAt(1)->IsConstant()) {
208 TryMergeIntoUsersShifterOperand(instruction);
209 }
210}
211
212void InstructionSimplifierArmVisitor::VisitShr(HShr* instruction) {
213 if (instruction->InputAt(1)->IsConstant()) {
214 TryMergeIntoUsersShifterOperand(instruction);
215 }
216}
217
218void InstructionSimplifierArmVisitor::VisitTypeConversion(HTypeConversion* instruction) {
219 Primitive::Type result_type = instruction->GetResultType();
220 Primitive::Type input_type = instruction->GetInputType();
221
222 if (input_type == result_type) {
223 // We let the arch-independent code handle this.
224 return;
225 }
226
227 if (Primitive::IsIntegralType(result_type) && Primitive::IsIntegralType(input_type)) {
228 TryMergeIntoUsersShifterOperand(instruction);
229 }
230}
231
232void InstructionSimplifierArmVisitor::VisitUShr(HUShr* instruction) {
233 if (instruction->InputAt(1)->IsConstant()) {
234 TryMergeIntoUsersShifterOperand(instruction);
235 }
236}
237
Artem Udovichenko4a0dad62016-01-26 12:28:31 +0300238} // namespace arm
239} // namespace art