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