1*795d594fSAndroid Build Coastguard Worker /*
2*795d594fSAndroid Build Coastguard Worker * Copyright (C) 2015 The Android Open Source Project
3*795d594fSAndroid Build Coastguard Worker *
4*795d594fSAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
5*795d594fSAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
6*795d594fSAndroid Build Coastguard Worker * You may obtain a copy of the License at
7*795d594fSAndroid Build Coastguard Worker *
8*795d594fSAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
9*795d594fSAndroid Build Coastguard Worker *
10*795d594fSAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
11*795d594fSAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
12*795d594fSAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*795d594fSAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
14*795d594fSAndroid Build Coastguard Worker * limitations under the License.
15*795d594fSAndroid Build Coastguard Worker */
16*795d594fSAndroid Build Coastguard Worker
17*795d594fSAndroid Build Coastguard Worker #include "instruction_simplifier_arm.h"
18*795d594fSAndroid Build Coastguard Worker
19*795d594fSAndroid Build Coastguard Worker #include "code_generator.h"
20*795d594fSAndroid Build Coastguard Worker #include "common_arm.h"
21*795d594fSAndroid Build Coastguard Worker #include "instruction_simplifier.h"
22*795d594fSAndroid Build Coastguard Worker #include "instruction_simplifier_shared.h"
23*795d594fSAndroid Build Coastguard Worker #include "mirror/array-inl.h"
24*795d594fSAndroid Build Coastguard Worker #include "mirror/string.h"
25*795d594fSAndroid Build Coastguard Worker #include "nodes.h"
26*795d594fSAndroid Build Coastguard Worker
27*795d594fSAndroid Build Coastguard Worker namespace art HIDDEN {
28*795d594fSAndroid Build Coastguard Worker
29*795d594fSAndroid Build Coastguard Worker using helpers::CanFitInShifterOperand;
30*795d594fSAndroid Build Coastguard Worker using helpers::HasShifterOperand;
31*795d594fSAndroid Build Coastguard Worker using helpers::IsSubRightSubLeftShl;
32*795d594fSAndroid Build Coastguard Worker
33*795d594fSAndroid Build Coastguard Worker namespace arm {
34*795d594fSAndroid Build Coastguard Worker
35*795d594fSAndroid Build Coastguard Worker class InstructionSimplifierArmVisitor final : public HGraphVisitor {
36*795d594fSAndroid Build Coastguard Worker public:
InstructionSimplifierArmVisitor(HGraph * graph,CodeGenerator * codegen,OptimizingCompilerStats * stats)37*795d594fSAndroid Build Coastguard Worker InstructionSimplifierArmVisitor(
38*795d594fSAndroid Build Coastguard Worker HGraph* graph, CodeGenerator* codegen, OptimizingCompilerStats* stats)
39*795d594fSAndroid Build Coastguard Worker : HGraphVisitor(graph), codegen_(codegen), stats_(stats) {}
40*795d594fSAndroid Build Coastguard Worker
41*795d594fSAndroid Build Coastguard Worker private:
RecordSimplification()42*795d594fSAndroid Build Coastguard Worker void RecordSimplification() {
43*795d594fSAndroid Build Coastguard Worker MaybeRecordStat(stats_, MethodCompilationStat::kInstructionSimplificationsArch);
44*795d594fSAndroid Build Coastguard Worker }
45*795d594fSAndroid Build Coastguard Worker
46*795d594fSAndroid Build Coastguard Worker bool TryMergeIntoUsersShifterOperand(HInstruction* instruction);
47*795d594fSAndroid Build Coastguard Worker bool TryMergeIntoShifterOperand(HInstruction* use, HInstruction* bitfield_op, bool do_merge);
CanMergeIntoShifterOperand(HInstruction * use,HInstruction * bitfield_op)48*795d594fSAndroid Build Coastguard Worker bool CanMergeIntoShifterOperand(HInstruction* use, HInstruction* bitfield_op) {
49*795d594fSAndroid Build Coastguard Worker return TryMergeIntoShifterOperand(use, bitfield_op, /* do_merge= */ false);
50*795d594fSAndroid Build Coastguard Worker }
MergeIntoShifterOperand(HInstruction * use,HInstruction * bitfield_op)51*795d594fSAndroid Build Coastguard Worker bool MergeIntoShifterOperand(HInstruction* use, HInstruction* bitfield_op) {
52*795d594fSAndroid Build Coastguard Worker DCHECK(CanMergeIntoShifterOperand(use, bitfield_op));
53*795d594fSAndroid Build Coastguard Worker return TryMergeIntoShifterOperand(use, bitfield_op, /* do_merge= */ true);
54*795d594fSAndroid Build Coastguard Worker }
55*795d594fSAndroid Build Coastguard Worker
56*795d594fSAndroid Build Coastguard Worker /**
57*795d594fSAndroid Build Coastguard Worker * This simplifier uses a special-purpose BB visitor.
58*795d594fSAndroid Build Coastguard Worker * (1) No need to visit Phi nodes.
59*795d594fSAndroid Build Coastguard Worker * (2) Since statements can be removed in a "forward" fashion,
60*795d594fSAndroid Build Coastguard Worker * the visitor should test if each statement is still there.
61*795d594fSAndroid Build Coastguard Worker */
VisitBasicBlock(HBasicBlock * block)62*795d594fSAndroid Build Coastguard Worker void VisitBasicBlock(HBasicBlock* block) override {
63*795d594fSAndroid Build Coastguard Worker // TODO: fragile iteration, provide more robust iterators?
64*795d594fSAndroid Build Coastguard Worker for (HInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) {
65*795d594fSAndroid Build Coastguard Worker HInstruction* instruction = it.Current();
66*795d594fSAndroid Build Coastguard Worker if (instruction->IsInBlock()) {
67*795d594fSAndroid Build Coastguard Worker instruction->Accept(this);
68*795d594fSAndroid Build Coastguard Worker }
69*795d594fSAndroid Build Coastguard Worker }
70*795d594fSAndroid Build Coastguard Worker }
71*795d594fSAndroid Build Coastguard Worker
72*795d594fSAndroid Build Coastguard Worker void VisitAnd(HAnd* instruction) override;
73*795d594fSAndroid Build Coastguard Worker void VisitArrayGet(HArrayGet* instruction) override;
74*795d594fSAndroid Build Coastguard Worker void VisitArraySet(HArraySet* instruction) override;
75*795d594fSAndroid Build Coastguard Worker void VisitMul(HMul* instruction) override;
76*795d594fSAndroid Build Coastguard Worker void VisitOr(HOr* instruction) override;
77*795d594fSAndroid Build Coastguard Worker void VisitRol(HRol* instruction) override;
78*795d594fSAndroid Build Coastguard Worker void VisitShl(HShl* instruction) override;
79*795d594fSAndroid Build Coastguard Worker void VisitShr(HShr* instruction) override;
80*795d594fSAndroid Build Coastguard Worker void VisitSub(HSub* instruction) override;
81*795d594fSAndroid Build Coastguard Worker void VisitTypeConversion(HTypeConversion* instruction) override;
82*795d594fSAndroid Build Coastguard Worker void VisitUShr(HUShr* instruction) override;
83*795d594fSAndroid Build Coastguard Worker
84*795d594fSAndroid Build Coastguard Worker CodeGenerator* codegen_;
85*795d594fSAndroid Build Coastguard Worker OptimizingCompilerStats* stats_;
86*795d594fSAndroid Build Coastguard Worker };
87*795d594fSAndroid Build Coastguard Worker
TryMergeIntoShifterOperand(HInstruction * use,HInstruction * bitfield_op,bool do_merge)88*795d594fSAndroid Build Coastguard Worker bool InstructionSimplifierArmVisitor::TryMergeIntoShifterOperand(HInstruction* use,
89*795d594fSAndroid Build Coastguard Worker HInstruction* bitfield_op,
90*795d594fSAndroid Build Coastguard Worker bool do_merge) {
91*795d594fSAndroid Build Coastguard Worker DCHECK(HasShifterOperand(use, InstructionSet::kArm));
92*795d594fSAndroid Build Coastguard Worker DCHECK(use->IsBinaryOperation());
93*795d594fSAndroid Build Coastguard Worker DCHECK(CanFitInShifterOperand(bitfield_op));
94*795d594fSAndroid Build Coastguard Worker DCHECK(!bitfield_op->HasEnvironmentUses());
95*795d594fSAndroid Build Coastguard Worker
96*795d594fSAndroid Build Coastguard Worker DataType::Type type = use->GetType();
97*795d594fSAndroid Build Coastguard Worker if (type != DataType::Type::kInt32 && type != DataType::Type::kInt64) {
98*795d594fSAndroid Build Coastguard Worker return false;
99*795d594fSAndroid Build Coastguard Worker }
100*795d594fSAndroid Build Coastguard Worker
101*795d594fSAndroid Build Coastguard Worker HInstruction* left = use->InputAt(0);
102*795d594fSAndroid Build Coastguard Worker HInstruction* right = use->InputAt(1);
103*795d594fSAndroid Build Coastguard Worker DCHECK(left == bitfield_op || right == bitfield_op);
104*795d594fSAndroid Build Coastguard Worker
105*795d594fSAndroid Build Coastguard Worker if (left == right) {
106*795d594fSAndroid Build Coastguard Worker // TODO: Handle special transformations in this situation?
107*795d594fSAndroid Build Coastguard Worker // For example should we transform `(x << 1) + (x << 1)` into `(x << 2)`?
108*795d594fSAndroid Build Coastguard Worker // Or should this be part of a separate transformation logic?
109*795d594fSAndroid Build Coastguard Worker return false;
110*795d594fSAndroid Build Coastguard Worker }
111*795d594fSAndroid Build Coastguard Worker
112*795d594fSAndroid Build Coastguard Worker bool is_commutative = use->AsBinaryOperation()->IsCommutative();
113*795d594fSAndroid Build Coastguard Worker HInstruction* other_input;
114*795d594fSAndroid Build Coastguard Worker if (bitfield_op == right) {
115*795d594fSAndroid Build Coastguard Worker other_input = left;
116*795d594fSAndroid Build Coastguard Worker } else {
117*795d594fSAndroid Build Coastguard Worker if (is_commutative) {
118*795d594fSAndroid Build Coastguard Worker other_input = right;
119*795d594fSAndroid Build Coastguard Worker } else {
120*795d594fSAndroid Build Coastguard Worker return false;
121*795d594fSAndroid Build Coastguard Worker }
122*795d594fSAndroid Build Coastguard Worker }
123*795d594fSAndroid Build Coastguard Worker
124*795d594fSAndroid Build Coastguard Worker HDataProcWithShifterOp::OpKind op_kind;
125*795d594fSAndroid Build Coastguard Worker int shift_amount = 0;
126*795d594fSAndroid Build Coastguard Worker
127*795d594fSAndroid Build Coastguard Worker HDataProcWithShifterOp::GetOpInfoFromInstruction(bitfield_op, &op_kind, &shift_amount);
128*795d594fSAndroid Build Coastguard Worker shift_amount &= use->GetType() == DataType::Type::kInt32
129*795d594fSAndroid Build Coastguard Worker ? kMaxIntShiftDistance
130*795d594fSAndroid Build Coastguard Worker : kMaxLongShiftDistance;
131*795d594fSAndroid Build Coastguard Worker
132*795d594fSAndroid Build Coastguard Worker if (HDataProcWithShifterOp::IsExtensionOp(op_kind)) {
133*795d594fSAndroid Build Coastguard Worker if (!use->IsAdd() && (!use->IsSub() || use->GetType() != DataType::Type::kInt64)) {
134*795d594fSAndroid Build Coastguard Worker return false;
135*795d594fSAndroid Build Coastguard Worker }
136*795d594fSAndroid Build Coastguard Worker // Shift by 1 is a special case that results in the same number and type of instructions
137*795d594fSAndroid Build Coastguard Worker // as this simplification, but potentially shorter code.
138*795d594fSAndroid Build Coastguard Worker } else if (type == DataType::Type::kInt64 && shift_amount == 1) {
139*795d594fSAndroid Build Coastguard Worker return false;
140*795d594fSAndroid Build Coastguard Worker }
141*795d594fSAndroid Build Coastguard Worker
142*795d594fSAndroid Build Coastguard Worker if (do_merge) {
143*795d594fSAndroid Build Coastguard Worker HDataProcWithShifterOp* alu_with_op =
144*795d594fSAndroid Build Coastguard Worker new (GetGraph()->GetAllocator()) HDataProcWithShifterOp(use,
145*795d594fSAndroid Build Coastguard Worker other_input,
146*795d594fSAndroid Build Coastguard Worker bitfield_op->InputAt(0),
147*795d594fSAndroid Build Coastguard Worker op_kind,
148*795d594fSAndroid Build Coastguard Worker shift_amount,
149*795d594fSAndroid Build Coastguard Worker use->GetDexPc());
150*795d594fSAndroid Build Coastguard Worker use->GetBlock()->ReplaceAndRemoveInstructionWith(use, alu_with_op);
151*795d594fSAndroid Build Coastguard Worker if (bitfield_op->GetUses().empty()) {
152*795d594fSAndroid Build Coastguard Worker bitfield_op->GetBlock()->RemoveInstruction(bitfield_op);
153*795d594fSAndroid Build Coastguard Worker }
154*795d594fSAndroid Build Coastguard Worker RecordSimplification();
155*795d594fSAndroid Build Coastguard Worker }
156*795d594fSAndroid Build Coastguard Worker
157*795d594fSAndroid Build Coastguard Worker return true;
158*795d594fSAndroid Build Coastguard Worker }
159*795d594fSAndroid Build Coastguard Worker
160*795d594fSAndroid Build Coastguard Worker // Merge a bitfield move instruction into its uses if it can be merged in all of them.
TryMergeIntoUsersShifterOperand(HInstruction * bitfield_op)161*795d594fSAndroid Build Coastguard Worker bool InstructionSimplifierArmVisitor::TryMergeIntoUsersShifterOperand(HInstruction* bitfield_op) {
162*795d594fSAndroid Build Coastguard Worker DCHECK(CanFitInShifterOperand(bitfield_op));
163*795d594fSAndroid Build Coastguard Worker
164*795d594fSAndroid Build Coastguard Worker if (bitfield_op->HasEnvironmentUses()) {
165*795d594fSAndroid Build Coastguard Worker return false;
166*795d594fSAndroid Build Coastguard Worker }
167*795d594fSAndroid Build Coastguard Worker
168*795d594fSAndroid Build Coastguard Worker const HUseList<HInstruction*>& uses = bitfield_op->GetUses();
169*795d594fSAndroid Build Coastguard Worker
170*795d594fSAndroid Build Coastguard Worker // Check whether we can merge the instruction in all its users' shifter operand.
171*795d594fSAndroid Build Coastguard Worker for (const HUseListNode<HInstruction*>& use : uses) {
172*795d594fSAndroid Build Coastguard Worker HInstruction* user = use.GetUser();
173*795d594fSAndroid Build Coastguard Worker if (!HasShifterOperand(user, InstructionSet::kArm)) {
174*795d594fSAndroid Build Coastguard Worker return false;
175*795d594fSAndroid Build Coastguard Worker }
176*795d594fSAndroid Build Coastguard Worker if (!CanMergeIntoShifterOperand(user, bitfield_op)) {
177*795d594fSAndroid Build Coastguard Worker return false;
178*795d594fSAndroid Build Coastguard Worker }
179*795d594fSAndroid Build Coastguard Worker }
180*795d594fSAndroid Build Coastguard Worker
181*795d594fSAndroid Build Coastguard Worker // Merge the instruction into its uses.
182*795d594fSAndroid Build Coastguard Worker for (auto it = uses.begin(), end = uses.end(); it != end; /* ++it below */) {
183*795d594fSAndroid Build Coastguard Worker HInstruction* user = it->GetUser();
184*795d594fSAndroid Build Coastguard Worker // Increment `it` now because `*it` will disappear thanks to MergeIntoShifterOperand().
185*795d594fSAndroid Build Coastguard Worker ++it;
186*795d594fSAndroid Build Coastguard Worker bool merged = MergeIntoShifterOperand(user, bitfield_op);
187*795d594fSAndroid Build Coastguard Worker DCHECK(merged);
188*795d594fSAndroid Build Coastguard Worker }
189*795d594fSAndroid Build Coastguard Worker
190*795d594fSAndroid Build Coastguard Worker return true;
191*795d594fSAndroid Build Coastguard Worker }
192*795d594fSAndroid Build Coastguard Worker
VisitAnd(HAnd * instruction)193*795d594fSAndroid Build Coastguard Worker void InstructionSimplifierArmVisitor::VisitAnd(HAnd* instruction) {
194*795d594fSAndroid Build Coastguard Worker if (TryMergeNegatedInput(instruction)) {
195*795d594fSAndroid Build Coastguard Worker RecordSimplification();
196*795d594fSAndroid Build Coastguard Worker }
197*795d594fSAndroid Build Coastguard Worker }
198*795d594fSAndroid Build Coastguard Worker
VisitArrayGet(HArrayGet * instruction)199*795d594fSAndroid Build Coastguard Worker void InstructionSimplifierArmVisitor::VisitArrayGet(HArrayGet* instruction) {
200*795d594fSAndroid Build Coastguard Worker size_t data_offset = CodeGenerator::GetArrayDataOffset(instruction);
201*795d594fSAndroid Build Coastguard Worker DataType::Type type = instruction->GetType();
202*795d594fSAndroid Build Coastguard Worker
203*795d594fSAndroid Build Coastguard Worker // TODO: Implement reading (length + compression) for String compression feature from
204*795d594fSAndroid Build Coastguard Worker // negative offset (count_offset - data_offset). Thumb2Assembler (now removed) did
205*795d594fSAndroid Build Coastguard Worker // not support T4 encoding of "LDR (immediate)", but ArmVIXLMacroAssembler might.
206*795d594fSAndroid Build Coastguard Worker // Don't move array pointer if it is charAt because we need to take the count first.
207*795d594fSAndroid Build Coastguard Worker if (mirror::kUseStringCompression && instruction->IsStringCharAt()) {
208*795d594fSAndroid Build Coastguard Worker return;
209*795d594fSAndroid Build Coastguard Worker }
210*795d594fSAndroid Build Coastguard Worker
211*795d594fSAndroid Build Coastguard Worker // TODO: Support intermediate address for object arrays on arm.
212*795d594fSAndroid Build Coastguard Worker if (type == DataType::Type::kReference) {
213*795d594fSAndroid Build Coastguard Worker return;
214*795d594fSAndroid Build Coastguard Worker }
215*795d594fSAndroid Build Coastguard Worker
216*795d594fSAndroid Build Coastguard Worker if (type == DataType::Type::kInt64
217*795d594fSAndroid Build Coastguard Worker || type == DataType::Type::kFloat32
218*795d594fSAndroid Build Coastguard Worker || type == DataType::Type::kFloat64) {
219*795d594fSAndroid Build Coastguard Worker // T32 doesn't support ShiftedRegOffset mem address mode for these types
220*795d594fSAndroid Build Coastguard Worker // to enable optimization.
221*795d594fSAndroid Build Coastguard Worker return;
222*795d594fSAndroid Build Coastguard Worker }
223*795d594fSAndroid Build Coastguard Worker
224*795d594fSAndroid Build Coastguard Worker if (TryExtractArrayAccessAddress(codegen_,
225*795d594fSAndroid Build Coastguard Worker instruction,
226*795d594fSAndroid Build Coastguard Worker instruction->GetArray(),
227*795d594fSAndroid Build Coastguard Worker instruction->GetIndex(),
228*795d594fSAndroid Build Coastguard Worker data_offset)) {
229*795d594fSAndroid Build Coastguard Worker RecordSimplification();
230*795d594fSAndroid Build Coastguard Worker }
231*795d594fSAndroid Build Coastguard Worker }
232*795d594fSAndroid Build Coastguard Worker
VisitArraySet(HArraySet * instruction)233*795d594fSAndroid Build Coastguard Worker void InstructionSimplifierArmVisitor::VisitArraySet(HArraySet* instruction) {
234*795d594fSAndroid Build Coastguard Worker size_t access_size = DataType::Size(instruction->GetComponentType());
235*795d594fSAndroid Build Coastguard Worker size_t data_offset = mirror::Array::DataOffset(access_size).Uint32Value();
236*795d594fSAndroid Build Coastguard Worker DataType::Type type = instruction->GetComponentType();
237*795d594fSAndroid Build Coastguard Worker
238*795d594fSAndroid Build Coastguard Worker if (type == DataType::Type::kInt64
239*795d594fSAndroid Build Coastguard Worker || type == DataType::Type::kFloat32
240*795d594fSAndroid Build Coastguard Worker || type == DataType::Type::kFloat64) {
241*795d594fSAndroid Build Coastguard Worker // T32 doesn't support ShiftedRegOffset mem address mode for these types
242*795d594fSAndroid Build Coastguard Worker // to enable optimization.
243*795d594fSAndroid Build Coastguard Worker return;
244*795d594fSAndroid Build Coastguard Worker }
245*795d594fSAndroid Build Coastguard Worker
246*795d594fSAndroid Build Coastguard Worker if (TryExtractArrayAccessAddress(codegen_,
247*795d594fSAndroid Build Coastguard Worker instruction,
248*795d594fSAndroid Build Coastguard Worker instruction->GetArray(),
249*795d594fSAndroid Build Coastguard Worker instruction->GetIndex(),
250*795d594fSAndroid Build Coastguard Worker data_offset)) {
251*795d594fSAndroid Build Coastguard Worker RecordSimplification();
252*795d594fSAndroid Build Coastguard Worker }
253*795d594fSAndroid Build Coastguard Worker }
254*795d594fSAndroid Build Coastguard Worker
VisitMul(HMul * instruction)255*795d594fSAndroid Build Coastguard Worker void InstructionSimplifierArmVisitor::VisitMul(HMul* instruction) {
256*795d594fSAndroid Build Coastguard Worker if (TryCombineMultiplyAccumulate(instruction, InstructionSet::kArm)) {
257*795d594fSAndroid Build Coastguard Worker RecordSimplification();
258*795d594fSAndroid Build Coastguard Worker }
259*795d594fSAndroid Build Coastguard Worker }
260*795d594fSAndroid Build Coastguard Worker
VisitOr(HOr * instruction)261*795d594fSAndroid Build Coastguard Worker void InstructionSimplifierArmVisitor::VisitOr(HOr* instruction) {
262*795d594fSAndroid Build Coastguard Worker if (TryMergeNegatedInput(instruction)) {
263*795d594fSAndroid Build Coastguard Worker RecordSimplification();
264*795d594fSAndroid Build Coastguard Worker }
265*795d594fSAndroid Build Coastguard Worker }
266*795d594fSAndroid Build Coastguard Worker
VisitRol(HRol * instruction)267*795d594fSAndroid Build Coastguard Worker void InstructionSimplifierArmVisitor::VisitRol(HRol* instruction) {
268*795d594fSAndroid Build Coastguard Worker UnfoldRotateLeft(instruction);
269*795d594fSAndroid Build Coastguard Worker RecordSimplification();
270*795d594fSAndroid Build Coastguard Worker }
271*795d594fSAndroid Build Coastguard Worker
VisitShl(HShl * instruction)272*795d594fSAndroid Build Coastguard Worker void InstructionSimplifierArmVisitor::VisitShl(HShl* instruction) {
273*795d594fSAndroid Build Coastguard Worker if (instruction->InputAt(1)->IsConstant()) {
274*795d594fSAndroid Build Coastguard Worker TryMergeIntoUsersShifterOperand(instruction);
275*795d594fSAndroid Build Coastguard Worker }
276*795d594fSAndroid Build Coastguard Worker }
277*795d594fSAndroid Build Coastguard Worker
VisitShr(HShr * instruction)278*795d594fSAndroid Build Coastguard Worker void InstructionSimplifierArmVisitor::VisitShr(HShr* instruction) {
279*795d594fSAndroid Build Coastguard Worker if (instruction->InputAt(1)->IsConstant()) {
280*795d594fSAndroid Build Coastguard Worker TryMergeIntoUsersShifterOperand(instruction);
281*795d594fSAndroid Build Coastguard Worker }
282*795d594fSAndroid Build Coastguard Worker }
283*795d594fSAndroid Build Coastguard Worker
VisitSub(HSub * instruction)284*795d594fSAndroid Build Coastguard Worker void InstructionSimplifierArmVisitor::VisitSub(HSub* instruction) {
285*795d594fSAndroid Build Coastguard Worker if (IsSubRightSubLeftShl(instruction)) {
286*795d594fSAndroid Build Coastguard Worker HInstruction* shl = instruction->GetRight()->InputAt(0);
287*795d594fSAndroid Build Coastguard Worker if (shl->InputAt(1)->IsConstant() && TryReplaceSubSubWithSubAdd(instruction)) {
288*795d594fSAndroid Build Coastguard Worker if (TryMergeIntoUsersShifterOperand(shl)) {
289*795d594fSAndroid Build Coastguard Worker return;
290*795d594fSAndroid Build Coastguard Worker }
291*795d594fSAndroid Build Coastguard Worker }
292*795d594fSAndroid Build Coastguard Worker }
293*795d594fSAndroid Build Coastguard Worker
294*795d594fSAndroid Build Coastguard Worker if (TryMergeWithAnd(instruction)) {
295*795d594fSAndroid Build Coastguard Worker return;
296*795d594fSAndroid Build Coastguard Worker }
297*795d594fSAndroid Build Coastguard Worker }
298*795d594fSAndroid Build Coastguard Worker
VisitTypeConversion(HTypeConversion * instruction)299*795d594fSAndroid Build Coastguard Worker void InstructionSimplifierArmVisitor::VisitTypeConversion(HTypeConversion* instruction) {
300*795d594fSAndroid Build Coastguard Worker DataType::Type result_type = instruction->GetResultType();
301*795d594fSAndroid Build Coastguard Worker DataType::Type input_type = instruction->GetInputType();
302*795d594fSAndroid Build Coastguard Worker
303*795d594fSAndroid Build Coastguard Worker if (input_type == result_type) {
304*795d594fSAndroid Build Coastguard Worker // We let the arch-independent code handle this.
305*795d594fSAndroid Build Coastguard Worker return;
306*795d594fSAndroid Build Coastguard Worker }
307*795d594fSAndroid Build Coastguard Worker
308*795d594fSAndroid Build Coastguard Worker if (DataType::IsIntegralType(result_type) && DataType::IsIntegralType(input_type)) {
309*795d594fSAndroid Build Coastguard Worker TryMergeIntoUsersShifterOperand(instruction);
310*795d594fSAndroid Build Coastguard Worker }
311*795d594fSAndroid Build Coastguard Worker }
312*795d594fSAndroid Build Coastguard Worker
VisitUShr(HUShr * instruction)313*795d594fSAndroid Build Coastguard Worker void InstructionSimplifierArmVisitor::VisitUShr(HUShr* instruction) {
314*795d594fSAndroid Build Coastguard Worker if (instruction->InputAt(1)->IsConstant()) {
315*795d594fSAndroid Build Coastguard Worker TryMergeIntoUsersShifterOperand(instruction);
316*795d594fSAndroid Build Coastguard Worker }
317*795d594fSAndroid Build Coastguard Worker }
318*795d594fSAndroid Build Coastguard Worker
Run()319*795d594fSAndroid Build Coastguard Worker bool InstructionSimplifierArm::Run() {
320*795d594fSAndroid Build Coastguard Worker InstructionSimplifierArmVisitor visitor(graph_, codegen_, stats_);
321*795d594fSAndroid Build Coastguard Worker visitor.VisitReversePostOrder();
322*795d594fSAndroid Build Coastguard Worker return true;
323*795d594fSAndroid Build Coastguard Worker }
324*795d594fSAndroid Build Coastguard Worker
325*795d594fSAndroid Build Coastguard Worker } // namespace arm
326*795d594fSAndroid Build Coastguard Worker } // namespace art
327