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_shared.h"
18*795d594fSAndroid Build Coastguard Worker
19*795d594fSAndroid Build Coastguard Worker #include "code_generator.h"
20*795d594fSAndroid Build Coastguard Worker #include "mirror/array-inl.h"
21*795d594fSAndroid Build Coastguard Worker #include "nodes.h"
22*795d594fSAndroid Build Coastguard Worker
23*795d594fSAndroid Build Coastguard Worker namespace art HIDDEN {
24*795d594fSAndroid Build Coastguard Worker
25*795d594fSAndroid Build Coastguard Worker namespace {
26*795d594fSAndroid Build Coastguard Worker
TrySimpleMultiplyAccumulatePatterns(HMul * mul,HBinaryOperation * input_binop,HInstruction * input_other)27*795d594fSAndroid Build Coastguard Worker bool TrySimpleMultiplyAccumulatePatterns(HMul* mul,
28*795d594fSAndroid Build Coastguard Worker HBinaryOperation* input_binop,
29*795d594fSAndroid Build Coastguard Worker HInstruction* input_other) {
30*795d594fSAndroid Build Coastguard Worker DCHECK(DataType::IsIntOrLongType(mul->GetType()));
31*795d594fSAndroid Build Coastguard Worker DCHECK(input_binop->IsAdd() || input_binop->IsSub());
32*795d594fSAndroid Build Coastguard Worker DCHECK_NE(input_binop, input_other);
33*795d594fSAndroid Build Coastguard Worker if (!input_binop->HasOnlyOneNonEnvironmentUse()) {
34*795d594fSAndroid Build Coastguard Worker return false;
35*795d594fSAndroid Build Coastguard Worker }
36*795d594fSAndroid Build Coastguard Worker
37*795d594fSAndroid Build Coastguard Worker // Try to interpret patterns like
38*795d594fSAndroid Build Coastguard Worker // a * (b <+/-> 1)
39*795d594fSAndroid Build Coastguard Worker // as
40*795d594fSAndroid Build Coastguard Worker // (a * b) <+/-> a
41*795d594fSAndroid Build Coastguard Worker HInstruction* input_a = input_other;
42*795d594fSAndroid Build Coastguard Worker HInstruction* input_b = nullptr; // Set to a non-null value if we found a pattern to optimize.
43*795d594fSAndroid Build Coastguard Worker HInstruction::InstructionKind op_kind;
44*795d594fSAndroid Build Coastguard Worker
45*795d594fSAndroid Build Coastguard Worker if (input_binop->IsAdd()) {
46*795d594fSAndroid Build Coastguard Worker if ((input_binop->GetConstantRight() != nullptr) && input_binop->GetConstantRight()->IsOne()) {
47*795d594fSAndroid Build Coastguard Worker // Interpret
48*795d594fSAndroid Build Coastguard Worker // a * (b + 1)
49*795d594fSAndroid Build Coastguard Worker // as
50*795d594fSAndroid Build Coastguard Worker // (a * b) + a
51*795d594fSAndroid Build Coastguard Worker input_b = input_binop->GetLeastConstantLeft();
52*795d594fSAndroid Build Coastguard Worker op_kind = HInstruction::kAdd;
53*795d594fSAndroid Build Coastguard Worker }
54*795d594fSAndroid Build Coastguard Worker } else {
55*795d594fSAndroid Build Coastguard Worker DCHECK(input_binop->IsSub());
56*795d594fSAndroid Build Coastguard Worker if (input_binop->GetRight()->IsConstant() &&
57*795d594fSAndroid Build Coastguard Worker input_binop->GetRight()->AsConstant()->IsMinusOne()) {
58*795d594fSAndroid Build Coastguard Worker // Interpret
59*795d594fSAndroid Build Coastguard Worker // a * (b - (-1))
60*795d594fSAndroid Build Coastguard Worker // as
61*795d594fSAndroid Build Coastguard Worker // a + (a * b)
62*795d594fSAndroid Build Coastguard Worker input_b = input_binop->GetLeft();
63*795d594fSAndroid Build Coastguard Worker op_kind = HInstruction::kAdd;
64*795d594fSAndroid Build Coastguard Worker } else if (input_binop->GetLeft()->IsConstant() &&
65*795d594fSAndroid Build Coastguard Worker input_binop->GetLeft()->AsConstant()->IsOne()) {
66*795d594fSAndroid Build Coastguard Worker // Interpret
67*795d594fSAndroid Build Coastguard Worker // a * (1 - b)
68*795d594fSAndroid Build Coastguard Worker // as
69*795d594fSAndroid Build Coastguard Worker // a - (a * b)
70*795d594fSAndroid Build Coastguard Worker input_b = input_binop->GetRight();
71*795d594fSAndroid Build Coastguard Worker op_kind = HInstruction::kSub;
72*795d594fSAndroid Build Coastguard Worker }
73*795d594fSAndroid Build Coastguard Worker }
74*795d594fSAndroid Build Coastguard Worker
75*795d594fSAndroid Build Coastguard Worker if (input_b == nullptr) {
76*795d594fSAndroid Build Coastguard Worker // We did not find a pattern we can optimize.
77*795d594fSAndroid Build Coastguard Worker return false;
78*795d594fSAndroid Build Coastguard Worker }
79*795d594fSAndroid Build Coastguard Worker
80*795d594fSAndroid Build Coastguard Worker ArenaAllocator* allocator = mul->GetBlock()->GetGraph()->GetAllocator();
81*795d594fSAndroid Build Coastguard Worker HMultiplyAccumulate* mulacc = new (allocator) HMultiplyAccumulate(
82*795d594fSAndroid Build Coastguard Worker mul->GetType(), op_kind, input_a, input_a, input_b, mul->GetDexPc());
83*795d594fSAndroid Build Coastguard Worker
84*795d594fSAndroid Build Coastguard Worker mul->GetBlock()->ReplaceAndRemoveInstructionWith(mul, mulacc);
85*795d594fSAndroid Build Coastguard Worker input_binop->GetBlock()->RemoveInstruction(input_binop);
86*795d594fSAndroid Build Coastguard Worker
87*795d594fSAndroid Build Coastguard Worker return true;
88*795d594fSAndroid Build Coastguard Worker }
89*795d594fSAndroid Build Coastguard Worker
90*795d594fSAndroid Build Coastguard Worker } // namespace
91*795d594fSAndroid Build Coastguard Worker
TryCombineMultiplyAccumulate(HMul * mul,InstructionSet isa)92*795d594fSAndroid Build Coastguard Worker bool TryCombineMultiplyAccumulate(HMul* mul, InstructionSet isa) {
93*795d594fSAndroid Build Coastguard Worker DataType::Type type = mul->GetType();
94*795d594fSAndroid Build Coastguard Worker switch (isa) {
95*795d594fSAndroid Build Coastguard Worker case InstructionSet::kArm:
96*795d594fSAndroid Build Coastguard Worker case InstructionSet::kThumb2:
97*795d594fSAndroid Build Coastguard Worker if (type != DataType::Type::kInt32) {
98*795d594fSAndroid Build Coastguard Worker return false;
99*795d594fSAndroid Build Coastguard Worker }
100*795d594fSAndroid Build Coastguard Worker break;
101*795d594fSAndroid Build Coastguard Worker case InstructionSet::kArm64:
102*795d594fSAndroid Build Coastguard Worker if (!DataType::IsIntOrLongType(type)) {
103*795d594fSAndroid Build Coastguard Worker return false;
104*795d594fSAndroid Build Coastguard Worker }
105*795d594fSAndroid Build Coastguard Worker break;
106*795d594fSAndroid Build Coastguard Worker default:
107*795d594fSAndroid Build Coastguard Worker return false;
108*795d594fSAndroid Build Coastguard Worker }
109*795d594fSAndroid Build Coastguard Worker
110*795d594fSAndroid Build Coastguard Worker ArenaAllocator* allocator = mul->GetBlock()->GetGraph()->GetAllocator();
111*795d594fSAndroid Build Coastguard Worker
112*795d594fSAndroid Build Coastguard Worker if (mul->HasOnlyOneNonEnvironmentUse()) {
113*795d594fSAndroid Build Coastguard Worker HInstruction* use = mul->GetUses().front().GetUser();
114*795d594fSAndroid Build Coastguard Worker if (use->IsAdd() || use->IsSub()) {
115*795d594fSAndroid Build Coastguard Worker // Replace code looking like
116*795d594fSAndroid Build Coastguard Worker // MUL tmp, x, y
117*795d594fSAndroid Build Coastguard Worker // SUB dst, acc, tmp
118*795d594fSAndroid Build Coastguard Worker // with
119*795d594fSAndroid Build Coastguard Worker // MULSUB dst, acc, x, y
120*795d594fSAndroid Build Coastguard Worker // Note that we do not want to (unconditionally) perform the merge when the
121*795d594fSAndroid Build Coastguard Worker // multiplication has multiple uses and it can be merged in all of them.
122*795d594fSAndroid Build Coastguard Worker // Multiple uses could happen on the same control-flow path, and we would
123*795d594fSAndroid Build Coastguard Worker // then increase the amount of work. In the future we could try to evaluate
124*795d594fSAndroid Build Coastguard Worker // whether all uses are on different control-flow paths (using dominance and
125*795d594fSAndroid Build Coastguard Worker // reverse-dominance information) and only perform the merge when they are.
126*795d594fSAndroid Build Coastguard Worker HInstruction* accumulator = nullptr;
127*795d594fSAndroid Build Coastguard Worker HBinaryOperation* binop = use->AsBinaryOperation();
128*795d594fSAndroid Build Coastguard Worker HInstruction* binop_left = binop->GetLeft();
129*795d594fSAndroid Build Coastguard Worker HInstruction* binop_right = binop->GetRight();
130*795d594fSAndroid Build Coastguard Worker // Be careful after GVN. This should not happen since the `HMul` has only
131*795d594fSAndroid Build Coastguard Worker // one use.
132*795d594fSAndroid Build Coastguard Worker DCHECK_NE(binop_left, binop_right);
133*795d594fSAndroid Build Coastguard Worker if (binop_right == mul) {
134*795d594fSAndroid Build Coastguard Worker accumulator = binop_left;
135*795d594fSAndroid Build Coastguard Worker } else if (use->IsAdd()) {
136*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(binop_left, mul);
137*795d594fSAndroid Build Coastguard Worker accumulator = binop_right;
138*795d594fSAndroid Build Coastguard Worker }
139*795d594fSAndroid Build Coastguard Worker
140*795d594fSAndroid Build Coastguard Worker if (accumulator != nullptr) {
141*795d594fSAndroid Build Coastguard Worker HMultiplyAccumulate* mulacc =
142*795d594fSAndroid Build Coastguard Worker new (allocator) HMultiplyAccumulate(type,
143*795d594fSAndroid Build Coastguard Worker binop->GetKind(),
144*795d594fSAndroid Build Coastguard Worker accumulator,
145*795d594fSAndroid Build Coastguard Worker mul->GetLeft(),
146*795d594fSAndroid Build Coastguard Worker mul->GetRight());
147*795d594fSAndroid Build Coastguard Worker
148*795d594fSAndroid Build Coastguard Worker binop->GetBlock()->ReplaceAndRemoveInstructionWith(binop, mulacc);
149*795d594fSAndroid Build Coastguard Worker DCHECK(!mul->HasUses());
150*795d594fSAndroid Build Coastguard Worker mul->GetBlock()->RemoveInstruction(mul);
151*795d594fSAndroid Build Coastguard Worker return true;
152*795d594fSAndroid Build Coastguard Worker }
153*795d594fSAndroid Build Coastguard Worker } else if (use->IsNeg() && isa != InstructionSet::kArm) {
154*795d594fSAndroid Build Coastguard Worker HMultiplyAccumulate* mulacc =
155*795d594fSAndroid Build Coastguard Worker new (allocator) HMultiplyAccumulate(type,
156*795d594fSAndroid Build Coastguard Worker HInstruction::kSub,
157*795d594fSAndroid Build Coastguard Worker mul->GetBlock()->GetGraph()->GetConstant(type, 0),
158*795d594fSAndroid Build Coastguard Worker mul->GetLeft(),
159*795d594fSAndroid Build Coastguard Worker mul->GetRight());
160*795d594fSAndroid Build Coastguard Worker
161*795d594fSAndroid Build Coastguard Worker use->GetBlock()->ReplaceAndRemoveInstructionWith(use, mulacc);
162*795d594fSAndroid Build Coastguard Worker DCHECK(!mul->HasUses());
163*795d594fSAndroid Build Coastguard Worker mul->GetBlock()->RemoveInstruction(mul);
164*795d594fSAndroid Build Coastguard Worker return true;
165*795d594fSAndroid Build Coastguard Worker }
166*795d594fSAndroid Build Coastguard Worker }
167*795d594fSAndroid Build Coastguard Worker
168*795d594fSAndroid Build Coastguard Worker // Use multiply accumulate instruction for a few simple patterns.
169*795d594fSAndroid Build Coastguard Worker // We prefer not applying the following transformations if the left and
170*795d594fSAndroid Build Coastguard Worker // right inputs perform the same operation.
171*795d594fSAndroid Build Coastguard Worker // We rely on GVN having squashed the inputs if appropriate. However the
172*795d594fSAndroid Build Coastguard Worker // results are still correct even if that did not happen.
173*795d594fSAndroid Build Coastguard Worker if (mul->GetLeft() == mul->GetRight()) {
174*795d594fSAndroid Build Coastguard Worker return false;
175*795d594fSAndroid Build Coastguard Worker }
176*795d594fSAndroid Build Coastguard Worker
177*795d594fSAndroid Build Coastguard Worker HInstruction* left = mul->GetLeft();
178*795d594fSAndroid Build Coastguard Worker HInstruction* right = mul->GetRight();
179*795d594fSAndroid Build Coastguard Worker if ((right->IsAdd() || right->IsSub()) &&
180*795d594fSAndroid Build Coastguard Worker TrySimpleMultiplyAccumulatePatterns(mul, right->AsBinaryOperation(), left)) {
181*795d594fSAndroid Build Coastguard Worker return true;
182*795d594fSAndroid Build Coastguard Worker }
183*795d594fSAndroid Build Coastguard Worker if ((left->IsAdd() || left->IsSub()) &&
184*795d594fSAndroid Build Coastguard Worker TrySimpleMultiplyAccumulatePatterns(mul, left->AsBinaryOperation(), right)) {
185*795d594fSAndroid Build Coastguard Worker return true;
186*795d594fSAndroid Build Coastguard Worker }
187*795d594fSAndroid Build Coastguard Worker return false;
188*795d594fSAndroid Build Coastguard Worker }
189*795d594fSAndroid Build Coastguard Worker
TryExtractArrayAccessAddress(CodeGenerator * codegen,HInstruction * access,HInstruction * array,HInstruction * index,size_t data_offset)190*795d594fSAndroid Build Coastguard Worker bool TryExtractArrayAccessAddress(CodeGenerator* codegen,
191*795d594fSAndroid Build Coastguard Worker HInstruction* access,
192*795d594fSAndroid Build Coastguard Worker HInstruction* array,
193*795d594fSAndroid Build Coastguard Worker HInstruction* index,
194*795d594fSAndroid Build Coastguard Worker size_t data_offset) {
195*795d594fSAndroid Build Coastguard Worker if (index->IsConstant() ||
196*795d594fSAndroid Build Coastguard Worker (index->IsBoundsCheck() && index->AsBoundsCheck()->GetIndex()->IsConstant())) {
197*795d594fSAndroid Build Coastguard Worker // When the index is a constant all the addressing can be fitted in the
198*795d594fSAndroid Build Coastguard Worker // memory access instruction, so do not split the access.
199*795d594fSAndroid Build Coastguard Worker return false;
200*795d594fSAndroid Build Coastguard Worker }
201*795d594fSAndroid Build Coastguard Worker if (access->IsArraySet() &&
202*795d594fSAndroid Build Coastguard Worker access->AsArraySet()->GetValue()->GetType() == DataType::Type::kReference) {
203*795d594fSAndroid Build Coastguard Worker // The access may require a runtime call or the original array pointer.
204*795d594fSAndroid Build Coastguard Worker return false;
205*795d594fSAndroid Build Coastguard Worker }
206*795d594fSAndroid Build Coastguard Worker if (codegen->EmitNonBakerReadBarrier() &&
207*795d594fSAndroid Build Coastguard Worker access->IsArrayGet() &&
208*795d594fSAndroid Build Coastguard Worker access->GetType() == DataType::Type::kReference) {
209*795d594fSAndroid Build Coastguard Worker // For object arrays, the non-Baker read barrier instrumentation requires
210*795d594fSAndroid Build Coastguard Worker // the original array pointer.
211*795d594fSAndroid Build Coastguard Worker return false;
212*795d594fSAndroid Build Coastguard Worker }
213*795d594fSAndroid Build Coastguard Worker
214*795d594fSAndroid Build Coastguard Worker // Proceed to extract the base address computation.
215*795d594fSAndroid Build Coastguard Worker HGraph* graph = access->GetBlock()->GetGraph();
216*795d594fSAndroid Build Coastguard Worker ArenaAllocator* allocator = graph->GetAllocator();
217*795d594fSAndroid Build Coastguard Worker
218*795d594fSAndroid Build Coastguard Worker HIntConstant* offset = graph->GetIntConstant(data_offset);
219*795d594fSAndroid Build Coastguard Worker HIntermediateAddress* address = new (allocator) HIntermediateAddress(array, offset, kNoDexPc);
220*795d594fSAndroid Build Coastguard Worker // TODO: Is it ok to not have this on the intermediate address?
221*795d594fSAndroid Build Coastguard Worker // address->SetReferenceTypeInfo(array->GetReferenceTypeInfo());
222*795d594fSAndroid Build Coastguard Worker access->GetBlock()->InsertInstructionBefore(address, access);
223*795d594fSAndroid Build Coastguard Worker access->ReplaceInput(address, 0);
224*795d594fSAndroid Build Coastguard Worker // Both instructions must depend on GC to prevent any instruction that can
225*795d594fSAndroid Build Coastguard Worker // trigger GC to be inserted between the two.
226*795d594fSAndroid Build Coastguard Worker access->AddSideEffects(SideEffects::DependsOnGC());
227*795d594fSAndroid Build Coastguard Worker DCHECK(address->GetSideEffects().Includes(SideEffects::DependsOnGC()));
228*795d594fSAndroid Build Coastguard Worker DCHECK(access->GetSideEffects().Includes(SideEffects::DependsOnGC()));
229*795d594fSAndroid Build Coastguard Worker // TODO: Code generation for HArrayGet and HArraySet will check whether the input address
230*795d594fSAndroid Build Coastguard Worker // is an HIntermediateAddress and generate appropriate code.
231*795d594fSAndroid Build Coastguard Worker // We would like to replace the `HArrayGet` and `HArraySet` with custom instructions (maybe
232*795d594fSAndroid Build Coastguard Worker // `HArm64Load` and `HArm64Store`,`HArmLoad` and `HArmStore`). We defer these changes
233*795d594fSAndroid Build Coastguard Worker // because these new instructions would not bring any advantages yet.
234*795d594fSAndroid Build Coastguard Worker // Also see the comments in
235*795d594fSAndroid Build Coastguard Worker // `InstructionCodeGeneratorARMVIXL::VisitArrayGet()`
236*795d594fSAndroid Build Coastguard Worker // `InstructionCodeGeneratorARMVIXL::VisitArraySet()`
237*795d594fSAndroid Build Coastguard Worker // `InstructionCodeGeneratorARM64::VisitArrayGet()`
238*795d594fSAndroid Build Coastguard Worker // `InstructionCodeGeneratorARM64::VisitArraySet()`.
239*795d594fSAndroid Build Coastguard Worker return true;
240*795d594fSAndroid Build Coastguard Worker }
241*795d594fSAndroid Build Coastguard Worker
TryExtractVecArrayAccessAddress(HVecMemoryOperation * access,HInstruction * index)242*795d594fSAndroid Build Coastguard Worker bool TryExtractVecArrayAccessAddress(HVecMemoryOperation* access, HInstruction* index) {
243*795d594fSAndroid Build Coastguard Worker if (index->IsConstant()) {
244*795d594fSAndroid Build Coastguard Worker // If index is constant the whole address calculation often can be done by LDR/STR themselves.
245*795d594fSAndroid Build Coastguard Worker // TODO: Treat the case with not-embedable constant.
246*795d594fSAndroid Build Coastguard Worker return false;
247*795d594fSAndroid Build Coastguard Worker }
248*795d594fSAndroid Build Coastguard Worker
249*795d594fSAndroid Build Coastguard Worker HGraph* graph = access->GetBlock()->GetGraph();
250*795d594fSAndroid Build Coastguard Worker ArenaAllocator* allocator = graph->GetAllocator();
251*795d594fSAndroid Build Coastguard Worker DataType::Type packed_type = access->GetPackedType();
252*795d594fSAndroid Build Coastguard Worker uint32_t data_offset = mirror::Array::DataOffset(
253*795d594fSAndroid Build Coastguard Worker DataType::Size(packed_type)).Uint32Value();
254*795d594fSAndroid Build Coastguard Worker size_t component_shift = DataType::SizeShift(packed_type);
255*795d594fSAndroid Build Coastguard Worker
256*795d594fSAndroid Build Coastguard Worker bool is_extracting_beneficial = false;
257*795d594fSAndroid Build Coastguard Worker // It is beneficial to extract index intermediate address only if there are at least 2 users.
258*795d594fSAndroid Build Coastguard Worker for (const HUseListNode<HInstruction*>& use : index->GetUses()) {
259*795d594fSAndroid Build Coastguard Worker HInstruction* user = use.GetUser();
260*795d594fSAndroid Build Coastguard Worker if (user->IsVecMemoryOperation() && user != access) {
261*795d594fSAndroid Build Coastguard Worker HVecMemoryOperation* another_access = user->AsVecMemoryOperation();
262*795d594fSAndroid Build Coastguard Worker DataType::Type another_packed_type = another_access->GetPackedType();
263*795d594fSAndroid Build Coastguard Worker uint32_t another_data_offset = mirror::Array::DataOffset(
264*795d594fSAndroid Build Coastguard Worker DataType::Size(another_packed_type)).Uint32Value();
265*795d594fSAndroid Build Coastguard Worker size_t another_component_shift = DataType::SizeShift(another_packed_type);
266*795d594fSAndroid Build Coastguard Worker if (another_data_offset == data_offset && another_component_shift == component_shift) {
267*795d594fSAndroid Build Coastguard Worker is_extracting_beneficial = true;
268*795d594fSAndroid Build Coastguard Worker break;
269*795d594fSAndroid Build Coastguard Worker }
270*795d594fSAndroid Build Coastguard Worker } else if (user->IsIntermediateAddressIndex()) {
271*795d594fSAndroid Build Coastguard Worker HIntermediateAddressIndex* another_access = user->AsIntermediateAddressIndex();
272*795d594fSAndroid Build Coastguard Worker uint32_t another_data_offset = another_access->GetOffset()->AsIntConstant()->GetValue();
273*795d594fSAndroid Build Coastguard Worker size_t another_component_shift = another_access->GetShift()->AsIntConstant()->GetValue();
274*795d594fSAndroid Build Coastguard Worker if (another_data_offset == data_offset && another_component_shift == component_shift) {
275*795d594fSAndroid Build Coastguard Worker is_extracting_beneficial = true;
276*795d594fSAndroid Build Coastguard Worker break;
277*795d594fSAndroid Build Coastguard Worker }
278*795d594fSAndroid Build Coastguard Worker }
279*795d594fSAndroid Build Coastguard Worker }
280*795d594fSAndroid Build Coastguard Worker
281*795d594fSAndroid Build Coastguard Worker if (!is_extracting_beneficial) {
282*795d594fSAndroid Build Coastguard Worker return false;
283*795d594fSAndroid Build Coastguard Worker }
284*795d594fSAndroid Build Coastguard Worker
285*795d594fSAndroid Build Coastguard Worker // Proceed to extract the index + data_offset address computation.
286*795d594fSAndroid Build Coastguard Worker HIntConstant* offset = graph->GetIntConstant(data_offset);
287*795d594fSAndroid Build Coastguard Worker HIntConstant* shift = graph->GetIntConstant(component_shift);
288*795d594fSAndroid Build Coastguard Worker HIntermediateAddressIndex* address =
289*795d594fSAndroid Build Coastguard Worker new (allocator) HIntermediateAddressIndex(index, offset, shift, kNoDexPc);
290*795d594fSAndroid Build Coastguard Worker
291*795d594fSAndroid Build Coastguard Worker access->GetBlock()->InsertInstructionBefore(address, access);
292*795d594fSAndroid Build Coastguard Worker access->ReplaceInput(address, 1);
293*795d594fSAndroid Build Coastguard Worker
294*795d594fSAndroid Build Coastguard Worker return true;
295*795d594fSAndroid Build Coastguard Worker }
296*795d594fSAndroid Build Coastguard Worker
TryReplaceSubSubWithSubAdd(HSub * last_sub)297*795d594fSAndroid Build Coastguard Worker bool TryReplaceSubSubWithSubAdd(HSub* last_sub) {
298*795d594fSAndroid Build Coastguard Worker DCHECK(last_sub->GetRight()->IsSub());
299*795d594fSAndroid Build Coastguard Worker HBasicBlock* basic_block = last_sub->GetBlock();
300*795d594fSAndroid Build Coastguard Worker ArenaAllocator* allocator = basic_block->GetGraph()->GetAllocator();
301*795d594fSAndroid Build Coastguard Worker HInstruction* last_sub_right = last_sub->GetRight();
302*795d594fSAndroid Build Coastguard Worker HInstruction* last_sub_left = last_sub->GetLeft();
303*795d594fSAndroid Build Coastguard Worker if (last_sub_right->GetUses().HasExactlyOneElement()) {
304*795d594fSAndroid Build Coastguard Worker // Reorder operands of last_sub_right: Sub(a, b) -> Sub(b, a).
305*795d594fSAndroid Build Coastguard Worker HInstruction* a = last_sub_right->InputAt(0);
306*795d594fSAndroid Build Coastguard Worker HInstruction* b = last_sub_right->InputAt(1);
307*795d594fSAndroid Build Coastguard Worker last_sub_right->ReplaceInput(b, 0);
308*795d594fSAndroid Build Coastguard Worker last_sub_right->ReplaceInput(a, 1);
309*795d594fSAndroid Build Coastguard Worker
310*795d594fSAndroid Build Coastguard Worker // Replace Sub(c, Sub(a, b)) with Add(c, Sub(b, a).
311*795d594fSAndroid Build Coastguard Worker HAdd* add = new (allocator) HAdd(last_sub->GetType(), last_sub_left, last_sub_right);
312*795d594fSAndroid Build Coastguard Worker basic_block->ReplaceAndRemoveInstructionWith(last_sub, add);
313*795d594fSAndroid Build Coastguard Worker return true;
314*795d594fSAndroid Build Coastguard Worker } else {
315*795d594fSAndroid Build Coastguard Worker return false;
316*795d594fSAndroid Build Coastguard Worker }
317*795d594fSAndroid Build Coastguard Worker }
318*795d594fSAndroid Build Coastguard Worker
UnfoldRotateLeft(HRol * rol)319*795d594fSAndroid Build Coastguard Worker void UnfoldRotateLeft(HRol* rol) {
320*795d594fSAndroid Build Coastguard Worker HBasicBlock* block = rol->GetBlock();
321*795d594fSAndroid Build Coastguard Worker HGraph* graph = block->GetGraph();
322*795d594fSAndroid Build Coastguard Worker ArenaAllocator* allocator = graph->GetAllocator();
323*795d594fSAndroid Build Coastguard Worker HInstruction* neg;
324*795d594fSAndroid Build Coastguard Worker if (rol->GetRight()->IsConstant()) {
325*795d594fSAndroid Build Coastguard Worker int32_t value = rol->GetRight()->AsIntConstant()->GetValue();
326*795d594fSAndroid Build Coastguard Worker neg = graph->GetIntConstant(-value);
327*795d594fSAndroid Build Coastguard Worker } else {
328*795d594fSAndroid Build Coastguard Worker neg = new (allocator) HNeg(DataType::Type::kInt32, rol->GetRight());
329*795d594fSAndroid Build Coastguard Worker block->InsertInstructionBefore(neg, rol);
330*795d594fSAndroid Build Coastguard Worker }
331*795d594fSAndroid Build Coastguard Worker HInstruction* ror = new (allocator) HRor(rol->GetType(), rol->GetLeft(), neg);
332*795d594fSAndroid Build Coastguard Worker block->ReplaceAndRemoveInstructionWith(rol, ror);
333*795d594fSAndroid Build Coastguard Worker }
334*795d594fSAndroid Build Coastguard Worker
335*795d594fSAndroid Build Coastguard Worker } // namespace art
336