1*795d594fSAndroid Build Coastguard Worker /*
2*795d594fSAndroid Build Coastguard Worker * Copyright (C) 2014 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.h"
18*795d594fSAndroid Build Coastguard Worker
19*795d594fSAndroid Build Coastguard Worker #include "art_method-inl.h"
20*795d594fSAndroid Build Coastguard Worker #include "class_linker-inl.h"
21*795d594fSAndroid Build Coastguard Worker #include "class_root-inl.h"
22*795d594fSAndroid Build Coastguard Worker #include "data_type-inl.h"
23*795d594fSAndroid Build Coastguard Worker #include "driver/compiler_options.h"
24*795d594fSAndroid Build Coastguard Worker #include "escape.h"
25*795d594fSAndroid Build Coastguard Worker #include "intrinsic_objects.h"
26*795d594fSAndroid Build Coastguard Worker #include "intrinsics.h"
27*795d594fSAndroid Build Coastguard Worker #include "intrinsics_utils.h"
28*795d594fSAndroid Build Coastguard Worker #include "mirror/class-inl.h"
29*795d594fSAndroid Build Coastguard Worker #include "optimizing/data_type.h"
30*795d594fSAndroid Build Coastguard Worker #include "optimizing/nodes.h"
31*795d594fSAndroid Build Coastguard Worker #include "scoped_thread_state_change-inl.h"
32*795d594fSAndroid Build Coastguard Worker #include "sharpening.h"
33*795d594fSAndroid Build Coastguard Worker #include "string_builder_append.h"
34*795d594fSAndroid Build Coastguard Worker #include "well_known_classes.h"
35*795d594fSAndroid Build Coastguard Worker
36*795d594fSAndroid Build Coastguard Worker namespace art HIDDEN {
37*795d594fSAndroid Build Coastguard Worker
38*795d594fSAndroid Build Coastguard Worker // Whether to run an exhaustive test of individual HInstructions cloning when each instruction
39*795d594fSAndroid Build Coastguard Worker // is replaced with its copy if it is clonable.
40*795d594fSAndroid Build Coastguard Worker static constexpr bool kTestInstructionClonerExhaustively = false;
41*795d594fSAndroid Build Coastguard Worker
42*795d594fSAndroid Build Coastguard Worker class InstructionSimplifierVisitor final : public HGraphDelegateVisitor {
43*795d594fSAndroid Build Coastguard Worker public:
InstructionSimplifierVisitor(HGraph * graph,CodeGenerator * codegen,OptimizingCompilerStats * stats,bool be_loop_friendly)44*795d594fSAndroid Build Coastguard Worker InstructionSimplifierVisitor(HGraph* graph,
45*795d594fSAndroid Build Coastguard Worker CodeGenerator* codegen,
46*795d594fSAndroid Build Coastguard Worker OptimizingCompilerStats* stats,
47*795d594fSAndroid Build Coastguard Worker bool be_loop_friendly)
48*795d594fSAndroid Build Coastguard Worker : HGraphDelegateVisitor(graph),
49*795d594fSAndroid Build Coastguard Worker codegen_(codegen),
50*795d594fSAndroid Build Coastguard Worker stats_(stats),
51*795d594fSAndroid Build Coastguard Worker be_loop_friendly_(be_loop_friendly) {}
52*795d594fSAndroid Build Coastguard Worker
53*795d594fSAndroid Build Coastguard Worker bool Run();
54*795d594fSAndroid Build Coastguard Worker
55*795d594fSAndroid Build Coastguard Worker private:
RecordSimplification()56*795d594fSAndroid Build Coastguard Worker void RecordSimplification() {
57*795d594fSAndroid Build Coastguard Worker simplification_occurred_ = true;
58*795d594fSAndroid Build Coastguard Worker simplifications_at_current_position_++;
59*795d594fSAndroid Build Coastguard Worker MaybeRecordStat(stats_, MethodCompilationStat::kInstructionSimplifications);
60*795d594fSAndroid Build Coastguard Worker }
61*795d594fSAndroid Build Coastguard Worker
62*795d594fSAndroid Build Coastguard Worker bool ReplaceRotateWithRor(HBinaryOperation* op, HUShr* ushr, HShl* shl);
63*795d594fSAndroid Build Coastguard Worker bool TryReplaceWithRotate(HBinaryOperation* instruction);
64*795d594fSAndroid Build Coastguard Worker bool TryReplaceWithRotateConstantPattern(HBinaryOperation* op, HUShr* ushr, HShl* shl);
65*795d594fSAndroid Build Coastguard Worker bool TryReplaceWithRotateRegisterNegPattern(HBinaryOperation* op, HUShr* ushr, HShl* shl);
66*795d594fSAndroid Build Coastguard Worker bool TryReplaceWithRotateRegisterSubPattern(HBinaryOperation* op, HUShr* ushr, HShl* shl);
67*795d594fSAndroid Build Coastguard Worker
68*795d594fSAndroid Build Coastguard Worker bool TryMoveNegOnInputsAfterBinop(HBinaryOperation* binop);
69*795d594fSAndroid Build Coastguard Worker // `op` should be either HOr or HAnd.
70*795d594fSAndroid Build Coastguard Worker // De Morgan's laws:
71*795d594fSAndroid Build Coastguard Worker // ~a & ~b = ~(a | b) and ~a | ~b = ~(a & b)
72*795d594fSAndroid Build Coastguard Worker bool TryDeMorganNegationFactoring(HBinaryOperation* op);
73*795d594fSAndroid Build Coastguard Worker bool TryHandleAssociativeAndCommutativeOperation(HBinaryOperation* instruction);
74*795d594fSAndroid Build Coastguard Worker bool TrySubtractionChainSimplification(HBinaryOperation* instruction);
75*795d594fSAndroid Build Coastguard Worker bool TryCombineVecMultiplyAccumulate(HVecMul* mul);
76*795d594fSAndroid Build Coastguard Worker void TryToReuseDiv(HRem* rem);
77*795d594fSAndroid Build Coastguard Worker
78*795d594fSAndroid Build Coastguard Worker void VisitShift(HBinaryOperation* shift);
79*795d594fSAndroid Build Coastguard Worker void VisitEqual(HEqual* equal) override;
80*795d594fSAndroid Build Coastguard Worker void VisitNotEqual(HNotEqual* equal) override;
81*795d594fSAndroid Build Coastguard Worker void VisitBooleanNot(HBooleanNot* bool_not) override;
82*795d594fSAndroid Build Coastguard Worker void VisitInstanceFieldSet(HInstanceFieldSet* equal) override;
83*795d594fSAndroid Build Coastguard Worker void VisitStaticFieldSet(HStaticFieldSet* equal) override;
84*795d594fSAndroid Build Coastguard Worker void VisitArraySet(HArraySet* equal) override;
85*795d594fSAndroid Build Coastguard Worker void VisitTypeConversion(HTypeConversion* instruction) override;
86*795d594fSAndroid Build Coastguard Worker void VisitNullCheck(HNullCheck* instruction) override;
87*795d594fSAndroid Build Coastguard Worker void VisitArrayLength(HArrayLength* instruction) override;
88*795d594fSAndroid Build Coastguard Worker void VisitCheckCast(HCheckCast* instruction) override;
89*795d594fSAndroid Build Coastguard Worker void VisitAbs(HAbs* instruction) override;
90*795d594fSAndroid Build Coastguard Worker void VisitAdd(HAdd* instruction) override;
91*795d594fSAndroid Build Coastguard Worker void VisitAnd(HAnd* instruction) override;
92*795d594fSAndroid Build Coastguard Worker void VisitCompare(HCompare* instruction) override;
93*795d594fSAndroid Build Coastguard Worker void VisitCondition(HCondition* instruction) override;
94*795d594fSAndroid Build Coastguard Worker void VisitGreaterThan(HGreaterThan* condition) override;
95*795d594fSAndroid Build Coastguard Worker void VisitGreaterThanOrEqual(HGreaterThanOrEqual* condition) override;
96*795d594fSAndroid Build Coastguard Worker void VisitLessThan(HLessThan* condition) override;
97*795d594fSAndroid Build Coastguard Worker void VisitLessThanOrEqual(HLessThanOrEqual* condition) override;
98*795d594fSAndroid Build Coastguard Worker void VisitBelow(HBelow* condition) override;
99*795d594fSAndroid Build Coastguard Worker void VisitBelowOrEqual(HBelowOrEqual* condition) override;
100*795d594fSAndroid Build Coastguard Worker void VisitAbove(HAbove* condition) override;
101*795d594fSAndroid Build Coastguard Worker void VisitAboveOrEqual(HAboveOrEqual* condition) override;
102*795d594fSAndroid Build Coastguard Worker void VisitDiv(HDiv* instruction) override;
103*795d594fSAndroid Build Coastguard Worker void VisitRem(HRem* instruction) override;
104*795d594fSAndroid Build Coastguard Worker void VisitMul(HMul* instruction) override;
105*795d594fSAndroid Build Coastguard Worker void VisitNeg(HNeg* instruction) override;
106*795d594fSAndroid Build Coastguard Worker void VisitNot(HNot* instruction) override;
107*795d594fSAndroid Build Coastguard Worker void VisitOr(HOr* instruction) override;
108*795d594fSAndroid Build Coastguard Worker void VisitShl(HShl* instruction) override;
109*795d594fSAndroid Build Coastguard Worker void VisitShr(HShr* instruction) override;
110*795d594fSAndroid Build Coastguard Worker void VisitSub(HSub* instruction) override;
111*795d594fSAndroid Build Coastguard Worker void VisitUShr(HUShr* instruction) override;
112*795d594fSAndroid Build Coastguard Worker void VisitXor(HXor* instruction) override;
113*795d594fSAndroid Build Coastguard Worker void VisitSelect(HSelect* select) override;
114*795d594fSAndroid Build Coastguard Worker void VisitIf(HIf* instruction) override;
115*795d594fSAndroid Build Coastguard Worker void VisitInstanceOf(HInstanceOf* instruction) override;
116*795d594fSAndroid Build Coastguard Worker void VisitInvoke(HInvoke* invoke) override;
117*795d594fSAndroid Build Coastguard Worker void VisitDeoptimize(HDeoptimize* deoptimize) override;
118*795d594fSAndroid Build Coastguard Worker void VisitVecMul(HVecMul* instruction) override;
119*795d594fSAndroid Build Coastguard Worker void SimplifyBoxUnbox(HInvoke* instruction, ArtField* field, DataType::Type type);
120*795d594fSAndroid Build Coastguard Worker void SimplifySystemArrayCopy(HInvoke* invoke);
121*795d594fSAndroid Build Coastguard Worker void SimplifyStringEquals(HInvoke* invoke);
122*795d594fSAndroid Build Coastguard Worker void SimplifyFP2Int(HInvoke* invoke);
123*795d594fSAndroid Build Coastguard Worker void SimplifyStringCharAt(HInvoke* invoke);
124*795d594fSAndroid Build Coastguard Worker void SimplifyStringLength(HInvoke* invoke);
125*795d594fSAndroid Build Coastguard Worker void SimplifyStringIndexOf(HInvoke* invoke);
126*795d594fSAndroid Build Coastguard Worker void SimplifyNPEOnArgN(HInvoke* invoke, size_t);
127*795d594fSAndroid Build Coastguard Worker void SimplifyReturnThis(HInvoke* invoke);
128*795d594fSAndroid Build Coastguard Worker void SimplifyAllocationIntrinsic(HInvoke* invoke);
129*795d594fSAndroid Build Coastguard Worker void SimplifyVarHandleIntrinsic(HInvoke* invoke);
130*795d594fSAndroid Build Coastguard Worker void SimplifyArrayBaseOffset(HInvoke* invoke);
131*795d594fSAndroid Build Coastguard Worker
132*795d594fSAndroid Build Coastguard Worker bool CanUseKnownImageVarHandle(HInvoke* invoke);
133*795d594fSAndroid Build Coastguard Worker static bool CanEnsureNotNullAt(HInstruction* input, HInstruction* at);
134*795d594fSAndroid Build Coastguard Worker
135*795d594fSAndroid Build Coastguard Worker // Returns an instruction with the opposite Boolean value from 'cond'.
136*795d594fSAndroid Build Coastguard Worker // The instruction is inserted into the graph, either in the entry block
137*795d594fSAndroid Build Coastguard Worker // (constant), or before the `cursor` (otherwise).
138*795d594fSAndroid Build Coastguard Worker HInstruction* InsertOppositeCondition(HInstruction* cond, HInstruction* cursor);
139*795d594fSAndroid Build Coastguard Worker
140*795d594fSAndroid Build Coastguard Worker CodeGenerator* codegen_;
141*795d594fSAndroid Build Coastguard Worker OptimizingCompilerStats* stats_;
142*795d594fSAndroid Build Coastguard Worker bool simplification_occurred_ = false;
143*795d594fSAndroid Build Coastguard Worker int simplifications_at_current_position_ = 0;
144*795d594fSAndroid Build Coastguard Worker // Prohibit optimizations which can affect HInductionVarAnalysis/HLoopOptimization
145*795d594fSAndroid Build Coastguard Worker // and prevent loop optimizations:
146*795d594fSAndroid Build Coastguard Worker // true - avoid such optimizations.
147*795d594fSAndroid Build Coastguard Worker // false - allow such optimizations.
148*795d594fSAndroid Build Coastguard Worker // Checked by the following optimizations:
149*795d594fSAndroid Build Coastguard Worker // - TryToReuseDiv: simplification of Div+Rem into Div+Mul+Sub.
150*795d594fSAndroid Build Coastguard Worker bool be_loop_friendly_;
151*795d594fSAndroid Build Coastguard Worker // We ensure we do not loop infinitely. The value should not be too high, since that
152*795d594fSAndroid Build Coastguard Worker // would allow looping around the same basic block too many times. The value should
153*795d594fSAndroid Build Coastguard Worker // not be too low either, however, since we want to allow revisiting a basic block
154*795d594fSAndroid Build Coastguard Worker // with many statements and simplifications at least once.
155*795d594fSAndroid Build Coastguard Worker static constexpr int kMaxSamePositionSimplifications = 50;
156*795d594fSAndroid Build Coastguard Worker };
157*795d594fSAndroid Build Coastguard Worker
Run()158*795d594fSAndroid Build Coastguard Worker bool InstructionSimplifier::Run() {
159*795d594fSAndroid Build Coastguard Worker if (kTestInstructionClonerExhaustively) {
160*795d594fSAndroid Build Coastguard Worker CloneAndReplaceInstructionVisitor visitor(graph_);
161*795d594fSAndroid Build Coastguard Worker visitor.VisitReversePostOrder();
162*795d594fSAndroid Build Coastguard Worker }
163*795d594fSAndroid Build Coastguard Worker
164*795d594fSAndroid Build Coastguard Worker bool be_loop_friendly = (use_all_optimizations_ == false);
165*795d594fSAndroid Build Coastguard Worker
166*795d594fSAndroid Build Coastguard Worker InstructionSimplifierVisitor visitor(graph_, codegen_, stats_, be_loop_friendly);
167*795d594fSAndroid Build Coastguard Worker return visitor.Run();
168*795d594fSAndroid Build Coastguard Worker }
169*795d594fSAndroid Build Coastguard Worker
Run()170*795d594fSAndroid Build Coastguard Worker bool InstructionSimplifierVisitor::Run() {
171*795d594fSAndroid Build Coastguard Worker bool didSimplify = false;
172*795d594fSAndroid Build Coastguard Worker // Iterate in reverse post order to open up more simplifications to users
173*795d594fSAndroid Build Coastguard Worker // of instructions that got simplified.
174*795d594fSAndroid Build Coastguard Worker for (HBasicBlock* block : GetGraph()->GetReversePostOrder()) {
175*795d594fSAndroid Build Coastguard Worker // The simplification of an instruction to another instruction may yield
176*795d594fSAndroid Build Coastguard Worker // possibilities for other simplifications. So although we perform a reverse
177*795d594fSAndroid Build Coastguard Worker // post order visit, we sometimes need to revisit an instruction index.
178*795d594fSAndroid Build Coastguard Worker do {
179*795d594fSAndroid Build Coastguard Worker simplification_occurred_ = false;
180*795d594fSAndroid Build Coastguard Worker VisitNonPhiInstructions(block);
181*795d594fSAndroid Build Coastguard Worker if (simplification_occurred_) {
182*795d594fSAndroid Build Coastguard Worker didSimplify = true;
183*795d594fSAndroid Build Coastguard Worker }
184*795d594fSAndroid Build Coastguard Worker } while (simplification_occurred_ &&
185*795d594fSAndroid Build Coastguard Worker (simplifications_at_current_position_ < kMaxSamePositionSimplifications));
186*795d594fSAndroid Build Coastguard Worker simplifications_at_current_position_ = 0;
187*795d594fSAndroid Build Coastguard Worker }
188*795d594fSAndroid Build Coastguard Worker return didSimplify;
189*795d594fSAndroid Build Coastguard Worker }
190*795d594fSAndroid Build Coastguard Worker
191*795d594fSAndroid Build Coastguard Worker namespace {
192*795d594fSAndroid Build Coastguard Worker
AreAllBitsSet(HConstant * constant)193*795d594fSAndroid Build Coastguard Worker bool AreAllBitsSet(HConstant* constant) {
194*795d594fSAndroid Build Coastguard Worker return Int64FromConstant(constant) == -1;
195*795d594fSAndroid Build Coastguard Worker }
196*795d594fSAndroid Build Coastguard Worker
197*795d594fSAndroid Build Coastguard Worker } // namespace
198*795d594fSAndroid Build Coastguard Worker
199*795d594fSAndroid Build Coastguard Worker // Returns true if the code was simplified to use only one negation operation
200*795d594fSAndroid Build Coastguard Worker // after the binary operation instead of one on each of the inputs.
TryMoveNegOnInputsAfterBinop(HBinaryOperation * binop)201*795d594fSAndroid Build Coastguard Worker bool InstructionSimplifierVisitor::TryMoveNegOnInputsAfterBinop(HBinaryOperation* binop) {
202*795d594fSAndroid Build Coastguard Worker DCHECK(binop->IsAdd() || binop->IsSub());
203*795d594fSAndroid Build Coastguard Worker DCHECK(binop->GetLeft()->IsNeg() && binop->GetRight()->IsNeg());
204*795d594fSAndroid Build Coastguard Worker HNeg* left_neg = binop->GetLeft()->AsNeg();
205*795d594fSAndroid Build Coastguard Worker HNeg* right_neg = binop->GetRight()->AsNeg();
206*795d594fSAndroid Build Coastguard Worker if (!left_neg->HasOnlyOneNonEnvironmentUse() ||
207*795d594fSAndroid Build Coastguard Worker !right_neg->HasOnlyOneNonEnvironmentUse()) {
208*795d594fSAndroid Build Coastguard Worker return false;
209*795d594fSAndroid Build Coastguard Worker }
210*795d594fSAndroid Build Coastguard Worker // Replace code looking like
211*795d594fSAndroid Build Coastguard Worker // NEG tmp1, a
212*795d594fSAndroid Build Coastguard Worker // NEG tmp2, b
213*795d594fSAndroid Build Coastguard Worker // ADD dst, tmp1, tmp2
214*795d594fSAndroid Build Coastguard Worker // with
215*795d594fSAndroid Build Coastguard Worker // ADD tmp, a, b
216*795d594fSAndroid Build Coastguard Worker // NEG dst, tmp
217*795d594fSAndroid Build Coastguard Worker // Note that we cannot optimize `(-a) + (-b)` to `-(a + b)` for floating-point.
218*795d594fSAndroid Build Coastguard Worker // When `a` is `-0.0` and `b` is `0.0`, the former expression yields `0.0`,
219*795d594fSAndroid Build Coastguard Worker // while the later yields `-0.0`.
220*795d594fSAndroid Build Coastguard Worker if (!DataType::IsIntegralType(binop->GetType())) {
221*795d594fSAndroid Build Coastguard Worker return false;
222*795d594fSAndroid Build Coastguard Worker }
223*795d594fSAndroid Build Coastguard Worker binop->ReplaceInput(left_neg->GetInput(), 0);
224*795d594fSAndroid Build Coastguard Worker binop->ReplaceInput(right_neg->GetInput(), 1);
225*795d594fSAndroid Build Coastguard Worker left_neg->GetBlock()->RemoveInstruction(left_neg);
226*795d594fSAndroid Build Coastguard Worker right_neg->GetBlock()->RemoveInstruction(right_neg);
227*795d594fSAndroid Build Coastguard Worker HNeg* neg = new (GetGraph()->GetAllocator()) HNeg(binop->GetType(), binop);
228*795d594fSAndroid Build Coastguard Worker binop->GetBlock()->InsertInstructionBefore(neg, binop->GetNext());
229*795d594fSAndroid Build Coastguard Worker binop->ReplaceWithExceptInReplacementAtIndex(neg, 0);
230*795d594fSAndroid Build Coastguard Worker RecordSimplification();
231*795d594fSAndroid Build Coastguard Worker return true;
232*795d594fSAndroid Build Coastguard Worker }
233*795d594fSAndroid Build Coastguard Worker
TryDeMorganNegationFactoring(HBinaryOperation * op)234*795d594fSAndroid Build Coastguard Worker bool InstructionSimplifierVisitor::TryDeMorganNegationFactoring(HBinaryOperation* op) {
235*795d594fSAndroid Build Coastguard Worker DCHECK(op->IsAnd() || op->IsOr()) << op->DebugName();
236*795d594fSAndroid Build Coastguard Worker DataType::Type type = op->GetType();
237*795d594fSAndroid Build Coastguard Worker HInstruction* left = op->GetLeft();
238*795d594fSAndroid Build Coastguard Worker HInstruction* right = op->GetRight();
239*795d594fSAndroid Build Coastguard Worker
240*795d594fSAndroid Build Coastguard Worker // We can apply De Morgan's laws if both inputs are Not's and are only used
241*795d594fSAndroid Build Coastguard Worker // by `op`.
242*795d594fSAndroid Build Coastguard Worker if (((left->IsNot() && right->IsNot()) ||
243*795d594fSAndroid Build Coastguard Worker (left->IsBooleanNot() && right->IsBooleanNot())) &&
244*795d594fSAndroid Build Coastguard Worker left->HasOnlyOneNonEnvironmentUse() &&
245*795d594fSAndroid Build Coastguard Worker right->HasOnlyOneNonEnvironmentUse()) {
246*795d594fSAndroid Build Coastguard Worker // Replace code looking like
247*795d594fSAndroid Build Coastguard Worker // NOT nota, a
248*795d594fSAndroid Build Coastguard Worker // NOT notb, b
249*795d594fSAndroid Build Coastguard Worker // AND dst, nota, notb (respectively OR)
250*795d594fSAndroid Build Coastguard Worker // with
251*795d594fSAndroid Build Coastguard Worker // OR or, a, b (respectively AND)
252*795d594fSAndroid Build Coastguard Worker // NOT dest, or
253*795d594fSAndroid Build Coastguard Worker HInstruction* src_left = left->InputAt(0);
254*795d594fSAndroid Build Coastguard Worker HInstruction* src_right = right->InputAt(0);
255*795d594fSAndroid Build Coastguard Worker uint32_t dex_pc = op->GetDexPc();
256*795d594fSAndroid Build Coastguard Worker
257*795d594fSAndroid Build Coastguard Worker // Remove the negations on the inputs.
258*795d594fSAndroid Build Coastguard Worker left->ReplaceWith(src_left);
259*795d594fSAndroid Build Coastguard Worker right->ReplaceWith(src_right);
260*795d594fSAndroid Build Coastguard Worker left->GetBlock()->RemoveInstruction(left);
261*795d594fSAndroid Build Coastguard Worker right->GetBlock()->RemoveInstruction(right);
262*795d594fSAndroid Build Coastguard Worker
263*795d594fSAndroid Build Coastguard Worker // Replace the `HAnd` or `HOr`.
264*795d594fSAndroid Build Coastguard Worker HBinaryOperation* hbin;
265*795d594fSAndroid Build Coastguard Worker if (op->IsAnd()) {
266*795d594fSAndroid Build Coastguard Worker hbin = new (GetGraph()->GetAllocator()) HOr(type, src_left, src_right, dex_pc);
267*795d594fSAndroid Build Coastguard Worker } else {
268*795d594fSAndroid Build Coastguard Worker hbin = new (GetGraph()->GetAllocator()) HAnd(type, src_left, src_right, dex_pc);
269*795d594fSAndroid Build Coastguard Worker }
270*795d594fSAndroid Build Coastguard Worker HInstruction* hnot;
271*795d594fSAndroid Build Coastguard Worker if (left->IsBooleanNot()) {
272*795d594fSAndroid Build Coastguard Worker hnot = new (GetGraph()->GetAllocator()) HBooleanNot(hbin, dex_pc);
273*795d594fSAndroid Build Coastguard Worker } else {
274*795d594fSAndroid Build Coastguard Worker hnot = new (GetGraph()->GetAllocator()) HNot(type, hbin, dex_pc);
275*795d594fSAndroid Build Coastguard Worker }
276*795d594fSAndroid Build Coastguard Worker
277*795d594fSAndroid Build Coastguard Worker op->GetBlock()->InsertInstructionBefore(hbin, op);
278*795d594fSAndroid Build Coastguard Worker op->GetBlock()->ReplaceAndRemoveInstructionWith(op, hnot);
279*795d594fSAndroid Build Coastguard Worker
280*795d594fSAndroid Build Coastguard Worker RecordSimplification();
281*795d594fSAndroid Build Coastguard Worker return true;
282*795d594fSAndroid Build Coastguard Worker }
283*795d594fSAndroid Build Coastguard Worker
284*795d594fSAndroid Build Coastguard Worker return false;
285*795d594fSAndroid Build Coastguard Worker }
286*795d594fSAndroid Build Coastguard Worker
TryCombineVecMultiplyAccumulate(HVecMul * mul)287*795d594fSAndroid Build Coastguard Worker bool InstructionSimplifierVisitor::TryCombineVecMultiplyAccumulate(HVecMul* mul) {
288*795d594fSAndroid Build Coastguard Worker DataType::Type type = mul->GetPackedType();
289*795d594fSAndroid Build Coastguard Worker InstructionSet isa = codegen_->GetInstructionSet();
290*795d594fSAndroid Build Coastguard Worker switch (isa) {
291*795d594fSAndroid Build Coastguard Worker case InstructionSet::kArm64:
292*795d594fSAndroid Build Coastguard Worker if (!(type == DataType::Type::kUint8 ||
293*795d594fSAndroid Build Coastguard Worker type == DataType::Type::kInt8 ||
294*795d594fSAndroid Build Coastguard Worker type == DataType::Type::kUint16 ||
295*795d594fSAndroid Build Coastguard Worker type == DataType::Type::kInt16 ||
296*795d594fSAndroid Build Coastguard Worker type == DataType::Type::kInt32)) {
297*795d594fSAndroid Build Coastguard Worker return false;
298*795d594fSAndroid Build Coastguard Worker }
299*795d594fSAndroid Build Coastguard Worker break;
300*795d594fSAndroid Build Coastguard Worker default:
301*795d594fSAndroid Build Coastguard Worker return false;
302*795d594fSAndroid Build Coastguard Worker }
303*795d594fSAndroid Build Coastguard Worker
304*795d594fSAndroid Build Coastguard Worker ArenaAllocator* allocator = mul->GetBlock()->GetGraph()->GetAllocator();
305*795d594fSAndroid Build Coastguard Worker if (!mul->HasOnlyOneNonEnvironmentUse()) {
306*795d594fSAndroid Build Coastguard Worker return false;
307*795d594fSAndroid Build Coastguard Worker }
308*795d594fSAndroid Build Coastguard Worker HInstruction* binop = mul->GetUses().front().GetUser();
309*795d594fSAndroid Build Coastguard Worker if (!binop->IsVecAdd() && !binop->IsVecSub()) {
310*795d594fSAndroid Build Coastguard Worker return false;
311*795d594fSAndroid Build Coastguard Worker }
312*795d594fSAndroid Build Coastguard Worker
313*795d594fSAndroid Build Coastguard Worker // Replace code looking like
314*795d594fSAndroid Build Coastguard Worker // VECMUL tmp, x, y
315*795d594fSAndroid Build Coastguard Worker // VECADD/SUB dst, acc, tmp
316*795d594fSAndroid Build Coastguard Worker // with
317*795d594fSAndroid Build Coastguard Worker // VECMULACC dst, acc, x, y
318*795d594fSAndroid Build Coastguard Worker // Note that we do not want to (unconditionally) perform the merge when the
319*795d594fSAndroid Build Coastguard Worker // multiplication has multiple uses and it can be merged in all of them.
320*795d594fSAndroid Build Coastguard Worker // Multiple uses could happen on the same control-flow path, and we would
321*795d594fSAndroid Build Coastguard Worker // then increase the amount of work. In the future we could try to evaluate
322*795d594fSAndroid Build Coastguard Worker // whether all uses are on different control-flow paths (using dominance and
323*795d594fSAndroid Build Coastguard Worker // reverse-dominance information) and only perform the merge when they are.
324*795d594fSAndroid Build Coastguard Worker HInstruction* accumulator = nullptr;
325*795d594fSAndroid Build Coastguard Worker HVecBinaryOperation* vec_binop = binop->AsVecBinaryOperation();
326*795d594fSAndroid Build Coastguard Worker HInstruction* binop_left = vec_binop->GetLeft();
327*795d594fSAndroid Build Coastguard Worker HInstruction* binop_right = vec_binop->GetRight();
328*795d594fSAndroid Build Coastguard Worker // This is always true since the `HVecMul` has only one use (which is checked above).
329*795d594fSAndroid Build Coastguard Worker DCHECK_NE(binop_left, binop_right);
330*795d594fSAndroid Build Coastguard Worker if (binop_right == mul) {
331*795d594fSAndroid Build Coastguard Worker accumulator = binop_left;
332*795d594fSAndroid Build Coastguard Worker } else {
333*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(binop_left, mul);
334*795d594fSAndroid Build Coastguard Worker // Only addition is commutative.
335*795d594fSAndroid Build Coastguard Worker if (!binop->IsVecAdd()) {
336*795d594fSAndroid Build Coastguard Worker return false;
337*795d594fSAndroid Build Coastguard Worker }
338*795d594fSAndroid Build Coastguard Worker accumulator = binop_right;
339*795d594fSAndroid Build Coastguard Worker }
340*795d594fSAndroid Build Coastguard Worker
341*795d594fSAndroid Build Coastguard Worker DCHECK(accumulator != nullptr);
342*795d594fSAndroid Build Coastguard Worker HInstruction::InstructionKind kind =
343*795d594fSAndroid Build Coastguard Worker binop->IsVecAdd() ? HInstruction::kAdd : HInstruction::kSub;
344*795d594fSAndroid Build Coastguard Worker
345*795d594fSAndroid Build Coastguard Worker bool predicated_simd = vec_binop->IsPredicated();
346*795d594fSAndroid Build Coastguard Worker if (predicated_simd && !HVecOperation::HaveSamePredicate(vec_binop, mul)) {
347*795d594fSAndroid Build Coastguard Worker return false;
348*795d594fSAndroid Build Coastguard Worker }
349*795d594fSAndroid Build Coastguard Worker
350*795d594fSAndroid Build Coastguard Worker HVecMultiplyAccumulate* mulacc =
351*795d594fSAndroid Build Coastguard Worker new (allocator) HVecMultiplyAccumulate(allocator,
352*795d594fSAndroid Build Coastguard Worker kind,
353*795d594fSAndroid Build Coastguard Worker accumulator,
354*795d594fSAndroid Build Coastguard Worker mul->GetLeft(),
355*795d594fSAndroid Build Coastguard Worker mul->GetRight(),
356*795d594fSAndroid Build Coastguard Worker vec_binop->GetPackedType(),
357*795d594fSAndroid Build Coastguard Worker vec_binop->GetVectorLength(),
358*795d594fSAndroid Build Coastguard Worker vec_binop->GetDexPc());
359*795d594fSAndroid Build Coastguard Worker
360*795d594fSAndroid Build Coastguard Worker
361*795d594fSAndroid Build Coastguard Worker
362*795d594fSAndroid Build Coastguard Worker vec_binop->GetBlock()->ReplaceAndRemoveInstructionWith(vec_binop, mulacc);
363*795d594fSAndroid Build Coastguard Worker if (predicated_simd) {
364*795d594fSAndroid Build Coastguard Worker mulacc->SetGoverningPredicate(vec_binop->GetGoverningPredicate(),
365*795d594fSAndroid Build Coastguard Worker vec_binop->GetPredicationKind());
366*795d594fSAndroid Build Coastguard Worker }
367*795d594fSAndroid Build Coastguard Worker
368*795d594fSAndroid Build Coastguard Worker DCHECK(!mul->HasUses());
369*795d594fSAndroid Build Coastguard Worker mul->GetBlock()->RemoveInstruction(mul);
370*795d594fSAndroid Build Coastguard Worker return true;
371*795d594fSAndroid Build Coastguard Worker }
372*795d594fSAndroid Build Coastguard Worker
373*795d594fSAndroid Build Coastguard Worker // Replace code looking like (x << N >>> N or x << N >> N):
374*795d594fSAndroid Build Coastguard Worker // SHL tmp, x, N
375*795d594fSAndroid Build Coastguard Worker // USHR/SHR dst, tmp, N
376*795d594fSAndroid Build Coastguard Worker // with the corresponding type conversion:
377*795d594fSAndroid Build Coastguard Worker // TypeConversion<Unsigned<T>/Signed<T>> dst, x
378*795d594fSAndroid Build Coastguard Worker // if
379*795d594fSAndroid Build Coastguard Worker // SHL has only one non environment use
380*795d594fSAndroid Build Coastguard Worker // TypeOf(tmp) is not 64-bit type (they are not supported yet)
381*795d594fSAndroid Build Coastguard Worker // N % kBitsPerByte = 0
382*795d594fSAndroid Build Coastguard Worker // where
383*795d594fSAndroid Build Coastguard Worker // T = SignedIntegralTypeFromSize(source_integral_size)
384*795d594fSAndroid Build Coastguard Worker // source_integral_size = ByteSize(tmp) - N / kBitsPerByte
385*795d594fSAndroid Build Coastguard Worker //
386*795d594fSAndroid Build Coastguard Worker // We calculate source_integral_size from shift amount instead of
387*795d594fSAndroid Build Coastguard Worker // assuming that it is equal to ByteSize(x) to be able to optimize
388*795d594fSAndroid Build Coastguard Worker // cases like this:
389*795d594fSAndroid Build Coastguard Worker // int x = ...
390*795d594fSAndroid Build Coastguard Worker // int y = x << 24 >>> 24
391*795d594fSAndroid Build Coastguard Worker // that is equavalent to
392*795d594fSAndroid Build Coastguard Worker // int y = (unsigned byte) x
393*795d594fSAndroid Build Coastguard Worker // in this case:
394*795d594fSAndroid Build Coastguard Worker // N = 24
395*795d594fSAndroid Build Coastguard Worker // tmp = x << 24
396*795d594fSAndroid Build Coastguard Worker // source_integral_size is 1 (= 4 - 24 / 8) that corresponds to unsigned byte.
TryReplaceShiftsByConstantWithTypeConversion(HBinaryOperation * instruction)397*795d594fSAndroid Build Coastguard Worker static bool TryReplaceShiftsByConstantWithTypeConversion(HBinaryOperation *instruction) {
398*795d594fSAndroid Build Coastguard Worker if (!instruction->IsUShr() && !instruction->IsShr()) {
399*795d594fSAndroid Build Coastguard Worker return false;
400*795d594fSAndroid Build Coastguard Worker }
401*795d594fSAndroid Build Coastguard Worker
402*795d594fSAndroid Build Coastguard Worker if (DataType::Is64BitType(instruction->GetResultType())) {
403*795d594fSAndroid Build Coastguard Worker return false;
404*795d594fSAndroid Build Coastguard Worker }
405*795d594fSAndroid Build Coastguard Worker
406*795d594fSAndroid Build Coastguard Worker HInstruction* shr_amount = instruction->GetRight();
407*795d594fSAndroid Build Coastguard Worker if (!shr_amount->IsIntConstant()) {
408*795d594fSAndroid Build Coastguard Worker return false;
409*795d594fSAndroid Build Coastguard Worker }
410*795d594fSAndroid Build Coastguard Worker
411*795d594fSAndroid Build Coastguard Worker int32_t shr_amount_cst = shr_amount->AsIntConstant()->GetValue();
412*795d594fSAndroid Build Coastguard Worker
413*795d594fSAndroid Build Coastguard Worker // We assume that shift amount simplification was applied first so it doesn't
414*795d594fSAndroid Build Coastguard Worker // exceed maximum distance that is kMaxIntShiftDistance as 64-bit shifts aren't
415*795d594fSAndroid Build Coastguard Worker // supported.
416*795d594fSAndroid Build Coastguard Worker DCHECK_LE(shr_amount_cst, kMaxIntShiftDistance);
417*795d594fSAndroid Build Coastguard Worker
418*795d594fSAndroid Build Coastguard Worker if ((shr_amount_cst % kBitsPerByte) != 0) {
419*795d594fSAndroid Build Coastguard Worker return false;
420*795d594fSAndroid Build Coastguard Worker }
421*795d594fSAndroid Build Coastguard Worker
422*795d594fSAndroid Build Coastguard Worker // Calculate size of the significant part of the input, e.g. a part that is not
423*795d594fSAndroid Build Coastguard Worker // discarded due to left shift.
424*795d594fSAndroid Build Coastguard Worker // Shift amount here should be less than size of right shift type.
425*795d594fSAndroid Build Coastguard Worker DCHECK_GT(DataType::Size(instruction->GetType()), shr_amount_cst / kBitsPerByte);
426*795d594fSAndroid Build Coastguard Worker size_t source_significant_part_size =
427*795d594fSAndroid Build Coastguard Worker DataType::Size(instruction->GetType()) - shr_amount_cst / kBitsPerByte;
428*795d594fSAndroid Build Coastguard Worker
429*795d594fSAndroid Build Coastguard Worker // Look for the smallest signed integer type that is suitable to store the
430*795d594fSAndroid Build Coastguard Worker // significant part of the input.
431*795d594fSAndroid Build Coastguard Worker DataType::Type source_integral_type =
432*795d594fSAndroid Build Coastguard Worker DataType::SignedIntegralTypeFromSize(source_significant_part_size);
433*795d594fSAndroid Build Coastguard Worker
434*795d594fSAndroid Build Coastguard Worker // If the size of the significant part of the input isn't equal to the size of the
435*795d594fSAndroid Build Coastguard Worker // found type, shifts cannot be replaced by type conversion.
436*795d594fSAndroid Build Coastguard Worker if (DataType::Size(source_integral_type) != source_significant_part_size) {
437*795d594fSAndroid Build Coastguard Worker return false;
438*795d594fSAndroid Build Coastguard Worker }
439*795d594fSAndroid Build Coastguard Worker
440*795d594fSAndroid Build Coastguard Worker HInstruction* shr_value = instruction->GetLeft();
441*795d594fSAndroid Build Coastguard Worker if (!shr_value->IsShl()) {
442*795d594fSAndroid Build Coastguard Worker return false;
443*795d594fSAndroid Build Coastguard Worker }
444*795d594fSAndroid Build Coastguard Worker
445*795d594fSAndroid Build Coastguard Worker HShl *shl = shr_value->AsShl();
446*795d594fSAndroid Build Coastguard Worker if (!shl->HasOnlyOneNonEnvironmentUse()) {
447*795d594fSAndroid Build Coastguard Worker return false;
448*795d594fSAndroid Build Coastguard Worker }
449*795d594fSAndroid Build Coastguard Worker
450*795d594fSAndroid Build Coastguard Worker // Constants are unique so we just compare pointer here.
451*795d594fSAndroid Build Coastguard Worker if (shl->GetRight() != shr_amount) {
452*795d594fSAndroid Build Coastguard Worker return false;
453*795d594fSAndroid Build Coastguard Worker }
454*795d594fSAndroid Build Coastguard Worker
455*795d594fSAndroid Build Coastguard Worker // Type of shift's value is always int so sign/zero extension only
456*795d594fSAndroid Build Coastguard Worker // depends on the type of the shift (shr/ushr).
457*795d594fSAndroid Build Coastguard Worker bool is_signed = instruction->IsShr();
458*795d594fSAndroid Build Coastguard Worker DataType::Type conv_type =
459*795d594fSAndroid Build Coastguard Worker is_signed ? source_integral_type : DataType::ToUnsigned(source_integral_type);
460*795d594fSAndroid Build Coastguard Worker
461*795d594fSAndroid Build Coastguard Worker DCHECK(DataType::IsTypeConversionImplicit(conv_type, instruction->GetResultType()));
462*795d594fSAndroid Build Coastguard Worker
463*795d594fSAndroid Build Coastguard Worker HInstruction* shl_value = shl->GetLeft();
464*795d594fSAndroid Build Coastguard Worker HBasicBlock *block = instruction->GetBlock();
465*795d594fSAndroid Build Coastguard Worker
466*795d594fSAndroid Build Coastguard Worker // We shouldn't introduce new implicit type conversions during simplification.
467*795d594fSAndroid Build Coastguard Worker if (DataType::IsTypeConversionImplicit(shl_value->GetType(), conv_type)) {
468*795d594fSAndroid Build Coastguard Worker instruction->ReplaceWith(shl_value);
469*795d594fSAndroid Build Coastguard Worker instruction->GetBlock()->RemoveInstruction(instruction);
470*795d594fSAndroid Build Coastguard Worker } else {
471*795d594fSAndroid Build Coastguard Worker HTypeConversion* new_conversion =
472*795d594fSAndroid Build Coastguard Worker new (block->GetGraph()->GetAllocator()) HTypeConversion(conv_type, shl_value);
473*795d594fSAndroid Build Coastguard Worker block->ReplaceAndRemoveInstructionWith(instruction, new_conversion);
474*795d594fSAndroid Build Coastguard Worker }
475*795d594fSAndroid Build Coastguard Worker
476*795d594fSAndroid Build Coastguard Worker shl->GetBlock()->RemoveInstruction(shl);
477*795d594fSAndroid Build Coastguard Worker
478*795d594fSAndroid Build Coastguard Worker return true;
479*795d594fSAndroid Build Coastguard Worker }
480*795d594fSAndroid Build Coastguard Worker
VisitShift(HBinaryOperation * instruction)481*795d594fSAndroid Build Coastguard Worker void InstructionSimplifierVisitor::VisitShift(HBinaryOperation* instruction) {
482*795d594fSAndroid Build Coastguard Worker DCHECK(instruction->IsShl() || instruction->IsShr() || instruction->IsUShr());
483*795d594fSAndroid Build Coastguard Worker HInstruction* shift_amount = instruction->GetRight();
484*795d594fSAndroid Build Coastguard Worker HInstruction* value = instruction->GetLeft();
485*795d594fSAndroid Build Coastguard Worker
486*795d594fSAndroid Build Coastguard Worker int64_t implicit_mask = (value->GetType() == DataType::Type::kInt64)
487*795d594fSAndroid Build Coastguard Worker ? kMaxLongShiftDistance
488*795d594fSAndroid Build Coastguard Worker : kMaxIntShiftDistance;
489*795d594fSAndroid Build Coastguard Worker
490*795d594fSAndroid Build Coastguard Worker if (shift_amount->IsConstant()) {
491*795d594fSAndroid Build Coastguard Worker int64_t cst = Int64FromConstant(shift_amount->AsConstant());
492*795d594fSAndroid Build Coastguard Worker int64_t masked_cst = cst & implicit_mask;
493*795d594fSAndroid Build Coastguard Worker if (masked_cst == 0) {
494*795d594fSAndroid Build Coastguard Worker // Replace code looking like
495*795d594fSAndroid Build Coastguard Worker // SHL dst, value, 0
496*795d594fSAndroid Build Coastguard Worker // with
497*795d594fSAndroid Build Coastguard Worker // value
498*795d594fSAndroid Build Coastguard Worker instruction->ReplaceWith(value);
499*795d594fSAndroid Build Coastguard Worker instruction->GetBlock()->RemoveInstruction(instruction);
500*795d594fSAndroid Build Coastguard Worker RecordSimplification();
501*795d594fSAndroid Build Coastguard Worker return;
502*795d594fSAndroid Build Coastguard Worker } else if (masked_cst != cst) {
503*795d594fSAndroid Build Coastguard Worker // Replace code looking like
504*795d594fSAndroid Build Coastguard Worker // SHL dst, value, cst
505*795d594fSAndroid Build Coastguard Worker // where cst exceeds maximum distance with the equivalent
506*795d594fSAndroid Build Coastguard Worker // SHL dst, value, cst & implicit_mask
507*795d594fSAndroid Build Coastguard Worker // (as defined by shift semantics). This ensures other
508*795d594fSAndroid Build Coastguard Worker // optimizations do not need to special case for such situations.
509*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(shift_amount->GetType(), DataType::Type::kInt32);
510*795d594fSAndroid Build Coastguard Worker instruction->ReplaceInput(GetGraph()->GetIntConstant(masked_cst), /* index= */ 1);
511*795d594fSAndroid Build Coastguard Worker RecordSimplification();
512*795d594fSAndroid Build Coastguard Worker return;
513*795d594fSAndroid Build Coastguard Worker }
514*795d594fSAndroid Build Coastguard Worker
515*795d594fSAndroid Build Coastguard Worker if (TryReplaceShiftsByConstantWithTypeConversion(instruction)) {
516*795d594fSAndroid Build Coastguard Worker RecordSimplification();
517*795d594fSAndroid Build Coastguard Worker return;
518*795d594fSAndroid Build Coastguard Worker }
519*795d594fSAndroid Build Coastguard Worker }
520*795d594fSAndroid Build Coastguard Worker
521*795d594fSAndroid Build Coastguard Worker // Shift operations implicitly mask the shift amount according to the type width. Get rid of
522*795d594fSAndroid Build Coastguard Worker // unnecessary And/Or/Xor/Add/Sub/TypeConversion operations on the shift amount that do not
523*795d594fSAndroid Build Coastguard Worker // affect the relevant bits.
524*795d594fSAndroid Build Coastguard Worker // Replace code looking like
525*795d594fSAndroid Build Coastguard Worker // AND adjusted_shift, shift, <superset of implicit mask>
526*795d594fSAndroid Build Coastguard Worker // [OR/XOR/ADD/SUB adjusted_shift, shift, <value not overlapping with implicit mask>]
527*795d594fSAndroid Build Coastguard Worker // [<conversion-from-integral-non-64-bit-type> adjusted_shift, shift]
528*795d594fSAndroid Build Coastguard Worker // SHL dst, value, adjusted_shift
529*795d594fSAndroid Build Coastguard Worker // with
530*795d594fSAndroid Build Coastguard Worker // SHL dst, value, shift
531*795d594fSAndroid Build Coastguard Worker if (shift_amount->IsAnd() ||
532*795d594fSAndroid Build Coastguard Worker shift_amount->IsOr() ||
533*795d594fSAndroid Build Coastguard Worker shift_amount->IsXor() ||
534*795d594fSAndroid Build Coastguard Worker shift_amount->IsAdd() ||
535*795d594fSAndroid Build Coastguard Worker shift_amount->IsSub()) {
536*795d594fSAndroid Build Coastguard Worker int64_t required_result = shift_amount->IsAnd() ? implicit_mask : 0;
537*795d594fSAndroid Build Coastguard Worker HBinaryOperation* bin_op = shift_amount->AsBinaryOperation();
538*795d594fSAndroid Build Coastguard Worker HConstant* mask = bin_op->GetConstantRight();
539*795d594fSAndroid Build Coastguard Worker if (mask != nullptr && (Int64FromConstant(mask) & implicit_mask) == required_result) {
540*795d594fSAndroid Build Coastguard Worker instruction->ReplaceInput(bin_op->GetLeastConstantLeft(), 1);
541*795d594fSAndroid Build Coastguard Worker RecordSimplification();
542*795d594fSAndroid Build Coastguard Worker return;
543*795d594fSAndroid Build Coastguard Worker }
544*795d594fSAndroid Build Coastguard Worker } else if (shift_amount->IsTypeConversion()) {
545*795d594fSAndroid Build Coastguard Worker DCHECK_NE(shift_amount->GetType(), DataType::Type::kBool); // We never convert to bool.
546*795d594fSAndroid Build Coastguard Worker DataType::Type source_type = shift_amount->InputAt(0)->GetType();
547*795d594fSAndroid Build Coastguard Worker // Non-integral and 64-bit source types require an explicit type conversion.
548*795d594fSAndroid Build Coastguard Worker if (DataType::IsIntegralType(source_type) && !DataType::Is64BitType(source_type)) {
549*795d594fSAndroid Build Coastguard Worker instruction->ReplaceInput(shift_amount->AsTypeConversion()->GetInput(), 1);
550*795d594fSAndroid Build Coastguard Worker RecordSimplification();
551*795d594fSAndroid Build Coastguard Worker return;
552*795d594fSAndroid Build Coastguard Worker }
553*795d594fSAndroid Build Coastguard Worker }
554*795d594fSAndroid Build Coastguard Worker }
555*795d594fSAndroid Build Coastguard Worker
IsSubRegBitsMinusOther(HSub * sub,size_t reg_bits,HInstruction * other)556*795d594fSAndroid Build Coastguard Worker static bool IsSubRegBitsMinusOther(HSub* sub, size_t reg_bits, HInstruction* other) {
557*795d594fSAndroid Build Coastguard Worker return (sub->GetRight() == other &&
558*795d594fSAndroid Build Coastguard Worker sub->GetLeft()->IsConstant() &&
559*795d594fSAndroid Build Coastguard Worker (Int64FromConstant(sub->GetLeft()->AsConstant()) & (reg_bits - 1)) == 0);
560*795d594fSAndroid Build Coastguard Worker }
561*795d594fSAndroid Build Coastguard Worker
ReplaceRotateWithRor(HBinaryOperation * op,HUShr * ushr,HShl * shl)562*795d594fSAndroid Build Coastguard Worker bool InstructionSimplifierVisitor::ReplaceRotateWithRor(HBinaryOperation* op,
563*795d594fSAndroid Build Coastguard Worker HUShr* ushr,
564*795d594fSAndroid Build Coastguard Worker HShl* shl) {
565*795d594fSAndroid Build Coastguard Worker DCHECK(op->IsAdd() || op->IsXor() || op->IsOr()) << op->DebugName();
566*795d594fSAndroid Build Coastguard Worker HRor* ror =
567*795d594fSAndroid Build Coastguard Worker new (GetGraph()->GetAllocator()) HRor(ushr->GetType(), ushr->GetLeft(), ushr->GetRight());
568*795d594fSAndroid Build Coastguard Worker op->GetBlock()->ReplaceAndRemoveInstructionWith(op, ror);
569*795d594fSAndroid Build Coastguard Worker if (!ushr->HasUses()) {
570*795d594fSAndroid Build Coastguard Worker ushr->GetBlock()->RemoveInstruction(ushr);
571*795d594fSAndroid Build Coastguard Worker }
572*795d594fSAndroid Build Coastguard Worker if (!ushr->GetRight()->HasUses()) {
573*795d594fSAndroid Build Coastguard Worker ushr->GetRight()->GetBlock()->RemoveInstruction(ushr->GetRight());
574*795d594fSAndroid Build Coastguard Worker }
575*795d594fSAndroid Build Coastguard Worker if (!shl->HasUses()) {
576*795d594fSAndroid Build Coastguard Worker shl->GetBlock()->RemoveInstruction(shl);
577*795d594fSAndroid Build Coastguard Worker }
578*795d594fSAndroid Build Coastguard Worker if (!shl->GetRight()->HasUses()) {
579*795d594fSAndroid Build Coastguard Worker shl->GetRight()->GetBlock()->RemoveInstruction(shl->GetRight());
580*795d594fSAndroid Build Coastguard Worker }
581*795d594fSAndroid Build Coastguard Worker RecordSimplification();
582*795d594fSAndroid Build Coastguard Worker return true;
583*795d594fSAndroid Build Coastguard Worker }
584*795d594fSAndroid Build Coastguard Worker
585*795d594fSAndroid Build Coastguard Worker // Try to replace a binary operation flanked by one UShr and one Shl with a bitfield rotation.
TryReplaceWithRotate(HBinaryOperation * op)586*795d594fSAndroid Build Coastguard Worker bool InstructionSimplifierVisitor::TryReplaceWithRotate(HBinaryOperation* op) {
587*795d594fSAndroid Build Coastguard Worker DCHECK(op->IsAdd() || op->IsXor() || op->IsOr());
588*795d594fSAndroid Build Coastguard Worker HInstruction* left = op->GetLeft();
589*795d594fSAndroid Build Coastguard Worker HInstruction* right = op->GetRight();
590*795d594fSAndroid Build Coastguard Worker // If we have an UShr and a Shl (in either order).
591*795d594fSAndroid Build Coastguard Worker if ((left->IsUShr() && right->IsShl()) || (left->IsShl() && right->IsUShr())) {
592*795d594fSAndroid Build Coastguard Worker HUShr* ushr = left->IsUShr() ? left->AsUShr() : right->AsUShr();
593*795d594fSAndroid Build Coastguard Worker HShl* shl = left->IsShl() ? left->AsShl() : right->AsShl();
594*795d594fSAndroid Build Coastguard Worker DCHECK(DataType::IsIntOrLongType(ushr->GetType()));
595*795d594fSAndroid Build Coastguard Worker if (ushr->GetType() == shl->GetType() &&
596*795d594fSAndroid Build Coastguard Worker ushr->GetLeft() == shl->GetLeft()) {
597*795d594fSAndroid Build Coastguard Worker if (ushr->GetRight()->IsConstant() && shl->GetRight()->IsConstant()) {
598*795d594fSAndroid Build Coastguard Worker // Shift distances are both constant, try replacing with Ror if they
599*795d594fSAndroid Build Coastguard Worker // add up to the register size.
600*795d594fSAndroid Build Coastguard Worker return TryReplaceWithRotateConstantPattern(op, ushr, shl);
601*795d594fSAndroid Build Coastguard Worker } else if (ushr->GetRight()->IsSub() || shl->GetRight()->IsSub()) {
602*795d594fSAndroid Build Coastguard Worker // Shift distances are potentially of the form x and (reg_size - x).
603*795d594fSAndroid Build Coastguard Worker return TryReplaceWithRotateRegisterSubPattern(op, ushr, shl);
604*795d594fSAndroid Build Coastguard Worker } else if (ushr->GetRight()->IsNeg() || shl->GetRight()->IsNeg()) {
605*795d594fSAndroid Build Coastguard Worker // Shift distances are potentially of the form d and -d.
606*795d594fSAndroid Build Coastguard Worker return TryReplaceWithRotateRegisterNegPattern(op, ushr, shl);
607*795d594fSAndroid Build Coastguard Worker }
608*795d594fSAndroid Build Coastguard Worker }
609*795d594fSAndroid Build Coastguard Worker }
610*795d594fSAndroid Build Coastguard Worker return false;
611*795d594fSAndroid Build Coastguard Worker }
612*795d594fSAndroid Build Coastguard Worker
613*795d594fSAndroid Build Coastguard Worker // Try replacing code looking like (x >>> #rdist OP x << #ldist):
614*795d594fSAndroid Build Coastguard Worker // UShr dst, x, #rdist
615*795d594fSAndroid Build Coastguard Worker // Shl tmp, x, #ldist
616*795d594fSAndroid Build Coastguard Worker // OP dst, dst, tmp
617*795d594fSAndroid Build Coastguard Worker // or like (x >>> #rdist OP x << #-ldist):
618*795d594fSAndroid Build Coastguard Worker // UShr dst, x, #rdist
619*795d594fSAndroid Build Coastguard Worker // Shl tmp, x, #-ldist
620*795d594fSAndroid Build Coastguard Worker // OP dst, dst, tmp
621*795d594fSAndroid Build Coastguard Worker // with
622*795d594fSAndroid Build Coastguard Worker // Ror dst, x, #rdist
TryReplaceWithRotateConstantPattern(HBinaryOperation * op,HUShr * ushr,HShl * shl)623*795d594fSAndroid Build Coastguard Worker bool InstructionSimplifierVisitor::TryReplaceWithRotateConstantPattern(HBinaryOperation* op,
624*795d594fSAndroid Build Coastguard Worker HUShr* ushr,
625*795d594fSAndroid Build Coastguard Worker HShl* shl) {
626*795d594fSAndroid Build Coastguard Worker DCHECK(op->IsAdd() || op->IsXor() || op->IsOr());
627*795d594fSAndroid Build Coastguard Worker size_t reg_bits = DataType::Size(ushr->GetType()) * kBitsPerByte;
628*795d594fSAndroid Build Coastguard Worker size_t rdist = Int64FromConstant(ushr->GetRight()->AsConstant());
629*795d594fSAndroid Build Coastguard Worker size_t ldist = Int64FromConstant(shl->GetRight()->AsConstant());
630*795d594fSAndroid Build Coastguard Worker if (((ldist + rdist) & (reg_bits - 1)) == 0) {
631*795d594fSAndroid Build Coastguard Worker return ReplaceRotateWithRor(op, ushr, shl);
632*795d594fSAndroid Build Coastguard Worker }
633*795d594fSAndroid Build Coastguard Worker return false;
634*795d594fSAndroid Build Coastguard Worker }
635*795d594fSAndroid Build Coastguard Worker
636*795d594fSAndroid Build Coastguard Worker // Replace code looking like (x >>> -d OP x << d):
637*795d594fSAndroid Build Coastguard Worker // Neg neg, d
638*795d594fSAndroid Build Coastguard Worker // UShr dst, x, neg
639*795d594fSAndroid Build Coastguard Worker // Shl tmp, x, d
640*795d594fSAndroid Build Coastguard Worker // OP dst, dst, tmp
641*795d594fSAndroid Build Coastguard Worker // with
642*795d594fSAndroid Build Coastguard Worker // Neg neg, d
643*795d594fSAndroid Build Coastguard Worker // Ror dst, x, neg
644*795d594fSAndroid Build Coastguard Worker // *** OR ***
645*795d594fSAndroid Build Coastguard Worker // Replace code looking like (x >>> d OP x << -d):
646*795d594fSAndroid Build Coastguard Worker // UShr dst, x, d
647*795d594fSAndroid Build Coastguard Worker // Neg neg, d
648*795d594fSAndroid Build Coastguard Worker // Shl tmp, x, neg
649*795d594fSAndroid Build Coastguard Worker // OP dst, dst, tmp
650*795d594fSAndroid Build Coastguard Worker // with
651*795d594fSAndroid Build Coastguard Worker // Ror dst, x, d
652*795d594fSAndroid Build Coastguard Worker //
653*795d594fSAndroid Build Coastguard Worker // Requires `d` to be non-zero for the HAdd and HXor case. If `d` is 0 the shifts and rotate are
654*795d594fSAndroid Build Coastguard Worker // no-ops and the `OP` is never executed. This is fine for HOr since the result is the same, but the
655*795d594fSAndroid Build Coastguard Worker // result is different for HAdd and HXor.
TryReplaceWithRotateRegisterNegPattern(HBinaryOperation * op,HUShr * ushr,HShl * shl)656*795d594fSAndroid Build Coastguard Worker bool InstructionSimplifierVisitor::TryReplaceWithRotateRegisterNegPattern(HBinaryOperation* op,
657*795d594fSAndroid Build Coastguard Worker HUShr* ushr,
658*795d594fSAndroid Build Coastguard Worker HShl* shl) {
659*795d594fSAndroid Build Coastguard Worker DCHECK(op->IsAdd() || op->IsXor() || op->IsOr());
660*795d594fSAndroid Build Coastguard Worker DCHECK(ushr->GetRight()->IsNeg() || shl->GetRight()->IsNeg());
661*795d594fSAndroid Build Coastguard Worker bool neg_is_left = shl->GetRight()->IsNeg();
662*795d594fSAndroid Build Coastguard Worker HNeg* neg = neg_is_left ? shl->GetRight()->AsNeg() : ushr->GetRight()->AsNeg();
663*795d594fSAndroid Build Coastguard Worker HInstruction* value = neg->InputAt(0);
664*795d594fSAndroid Build Coastguard Worker
665*795d594fSAndroid Build Coastguard Worker // The shift distance being negated is the distance being shifted the other way.
666*795d594fSAndroid Build Coastguard Worker if (value != (neg_is_left ? ushr->GetRight() : shl->GetRight())) {
667*795d594fSAndroid Build Coastguard Worker return false;
668*795d594fSAndroid Build Coastguard Worker }
669*795d594fSAndroid Build Coastguard Worker
670*795d594fSAndroid Build Coastguard Worker const bool needs_non_zero_value = !op->IsOr();
671*795d594fSAndroid Build Coastguard Worker if (needs_non_zero_value) {
672*795d594fSAndroid Build Coastguard Worker if (!value->IsConstant() || value->AsConstant()->IsArithmeticZero()) {
673*795d594fSAndroid Build Coastguard Worker return false;
674*795d594fSAndroid Build Coastguard Worker }
675*795d594fSAndroid Build Coastguard Worker }
676*795d594fSAndroid Build Coastguard Worker return ReplaceRotateWithRor(op, ushr, shl);
677*795d594fSAndroid Build Coastguard Worker }
678*795d594fSAndroid Build Coastguard Worker
679*795d594fSAndroid Build Coastguard Worker // Try replacing code looking like (x >>> d OP x << (#bits - d)):
680*795d594fSAndroid Build Coastguard Worker // UShr dst, x, d
681*795d594fSAndroid Build Coastguard Worker // Sub ld, #bits, d
682*795d594fSAndroid Build Coastguard Worker // Shl tmp, x, ld
683*795d594fSAndroid Build Coastguard Worker // OP dst, dst, tmp
684*795d594fSAndroid Build Coastguard Worker // with
685*795d594fSAndroid Build Coastguard Worker // Ror dst, x, d
686*795d594fSAndroid Build Coastguard Worker // *** OR ***
687*795d594fSAndroid Build Coastguard Worker // Replace code looking like (x >>> (#bits - d) OP x << d):
688*795d594fSAndroid Build Coastguard Worker // Sub rd, #bits, d
689*795d594fSAndroid Build Coastguard Worker // UShr dst, x, rd
690*795d594fSAndroid Build Coastguard Worker // Shl tmp, x, d
691*795d594fSAndroid Build Coastguard Worker // OP dst, dst, tmp
692*795d594fSAndroid Build Coastguard Worker // with
693*795d594fSAndroid Build Coastguard Worker // Neg neg, d
694*795d594fSAndroid Build Coastguard Worker // Ror dst, x, neg
TryReplaceWithRotateRegisterSubPattern(HBinaryOperation * op,HUShr * ushr,HShl * shl)695*795d594fSAndroid Build Coastguard Worker bool InstructionSimplifierVisitor::TryReplaceWithRotateRegisterSubPattern(HBinaryOperation* op,
696*795d594fSAndroid Build Coastguard Worker HUShr* ushr,
697*795d594fSAndroid Build Coastguard Worker HShl* shl) {
698*795d594fSAndroid Build Coastguard Worker DCHECK(op->IsAdd() || op->IsXor() || op->IsOr());
699*795d594fSAndroid Build Coastguard Worker DCHECK(ushr->GetRight()->IsSub() || shl->GetRight()->IsSub());
700*795d594fSAndroid Build Coastguard Worker size_t reg_bits = DataType::Size(ushr->GetType()) * kBitsPerByte;
701*795d594fSAndroid Build Coastguard Worker HInstruction* shl_shift = shl->GetRight();
702*795d594fSAndroid Build Coastguard Worker HInstruction* ushr_shift = ushr->GetRight();
703*795d594fSAndroid Build Coastguard Worker if ((shl_shift->IsSub() && IsSubRegBitsMinusOther(shl_shift->AsSub(), reg_bits, ushr_shift)) ||
704*795d594fSAndroid Build Coastguard Worker (ushr_shift->IsSub() && IsSubRegBitsMinusOther(ushr_shift->AsSub(), reg_bits, shl_shift))) {
705*795d594fSAndroid Build Coastguard Worker return ReplaceRotateWithRor(op, ushr, shl);
706*795d594fSAndroid Build Coastguard Worker }
707*795d594fSAndroid Build Coastguard Worker return false;
708*795d594fSAndroid Build Coastguard Worker }
709*795d594fSAndroid Build Coastguard Worker
VisitNullCheck(HNullCheck * null_check)710*795d594fSAndroid Build Coastguard Worker void InstructionSimplifierVisitor::VisitNullCheck(HNullCheck* null_check) {
711*795d594fSAndroid Build Coastguard Worker HInstruction* obj = null_check->InputAt(0);
712*795d594fSAndroid Build Coastguard Worker // Note we don't do `CanEnsureNotNullAt` here. If we do that, we may get rid of a NullCheck but
713*795d594fSAndroid Build Coastguard Worker // what we should do instead is coalesce them. This is what GVN does, and so InstructionSimplifier
714*795d594fSAndroid Build Coastguard Worker // doesn't do this.
715*795d594fSAndroid Build Coastguard Worker if (!obj->CanBeNull()) {
716*795d594fSAndroid Build Coastguard Worker null_check->ReplaceWith(obj);
717*795d594fSAndroid Build Coastguard Worker null_check->GetBlock()->RemoveInstruction(null_check);
718*795d594fSAndroid Build Coastguard Worker if (stats_ != nullptr) {
719*795d594fSAndroid Build Coastguard Worker stats_->RecordStat(MethodCompilationStat::kRemovedNullCheck);
720*795d594fSAndroid Build Coastguard Worker }
721*795d594fSAndroid Build Coastguard Worker }
722*795d594fSAndroid Build Coastguard Worker }
723*795d594fSAndroid Build Coastguard Worker
CanEnsureNotNullAt(HInstruction * input,HInstruction * at)724*795d594fSAndroid Build Coastguard Worker bool InstructionSimplifierVisitor::CanEnsureNotNullAt(HInstruction* input, HInstruction* at) {
725*795d594fSAndroid Build Coastguard Worker if (!input->CanBeNull()) {
726*795d594fSAndroid Build Coastguard Worker return true;
727*795d594fSAndroid Build Coastguard Worker }
728*795d594fSAndroid Build Coastguard Worker
729*795d594fSAndroid Build Coastguard Worker for (const HUseListNode<HInstruction*>& use : input->GetUses()) {
730*795d594fSAndroid Build Coastguard Worker HInstruction* user = use.GetUser();
731*795d594fSAndroid Build Coastguard Worker if (user->IsNullCheck() && user->StrictlyDominates(at)) {
732*795d594fSAndroid Build Coastguard Worker return true;
733*795d594fSAndroid Build Coastguard Worker }
734*795d594fSAndroid Build Coastguard Worker }
735*795d594fSAndroid Build Coastguard Worker
736*795d594fSAndroid Build Coastguard Worker return false;
737*795d594fSAndroid Build Coastguard Worker }
738*795d594fSAndroid Build Coastguard Worker
739*795d594fSAndroid Build Coastguard Worker // Returns whether doing a type test between the class of `object` against `klass` has
740*795d594fSAndroid Build Coastguard Worker // a statically known outcome. The result of the test is stored in `outcome`.
TypeCheckHasKnownOutcome(ReferenceTypeInfo class_rti,HInstruction * object,bool * outcome)741*795d594fSAndroid Build Coastguard Worker static bool TypeCheckHasKnownOutcome(ReferenceTypeInfo class_rti,
742*795d594fSAndroid Build Coastguard Worker HInstruction* object,
743*795d594fSAndroid Build Coastguard Worker /*out*/bool* outcome) {
744*795d594fSAndroid Build Coastguard Worker DCHECK(!object->IsNullConstant()) << "Null constants should be special cased";
745*795d594fSAndroid Build Coastguard Worker ReferenceTypeInfo obj_rti = object->GetReferenceTypeInfo();
746*795d594fSAndroid Build Coastguard Worker ScopedObjectAccess soa(Thread::Current());
747*795d594fSAndroid Build Coastguard Worker if (!obj_rti.IsValid()) {
748*795d594fSAndroid Build Coastguard Worker // We run the simplifier before the reference type propagation so type info might not be
749*795d594fSAndroid Build Coastguard Worker // available.
750*795d594fSAndroid Build Coastguard Worker return false;
751*795d594fSAndroid Build Coastguard Worker }
752*795d594fSAndroid Build Coastguard Worker
753*795d594fSAndroid Build Coastguard Worker if (!class_rti.IsValid()) {
754*795d594fSAndroid Build Coastguard Worker // Happens when the loaded class is unresolved.
755*795d594fSAndroid Build Coastguard Worker if (obj_rti.IsExact()) {
756*795d594fSAndroid Build Coastguard Worker // outcome == 'true' && obj_rti is valid implies that class_rti is valid.
757*795d594fSAndroid Build Coastguard Worker // Since that's a contradiction we must not pass this check.
758*795d594fSAndroid Build Coastguard Worker *outcome = false;
759*795d594fSAndroid Build Coastguard Worker return true;
760*795d594fSAndroid Build Coastguard Worker } else {
761*795d594fSAndroid Build Coastguard Worker // We aren't able to say anything in particular since we don't know the
762*795d594fSAndroid Build Coastguard Worker // exact type of the object.
763*795d594fSAndroid Build Coastguard Worker return false;
764*795d594fSAndroid Build Coastguard Worker }
765*795d594fSAndroid Build Coastguard Worker }
766*795d594fSAndroid Build Coastguard Worker DCHECK(class_rti.IsExact());
767*795d594fSAndroid Build Coastguard Worker if (class_rti.IsSupertypeOf(obj_rti)) {
768*795d594fSAndroid Build Coastguard Worker *outcome = true;
769*795d594fSAndroid Build Coastguard Worker return true;
770*795d594fSAndroid Build Coastguard Worker } else if (obj_rti.IsExact()) {
771*795d594fSAndroid Build Coastguard Worker // The test failed at compile time so will also fail at runtime.
772*795d594fSAndroid Build Coastguard Worker *outcome = false;
773*795d594fSAndroid Build Coastguard Worker return true;
774*795d594fSAndroid Build Coastguard Worker } else if (!class_rti.IsInterface()
775*795d594fSAndroid Build Coastguard Worker && !obj_rti.IsInterface()
776*795d594fSAndroid Build Coastguard Worker && !obj_rti.IsSupertypeOf(class_rti)) {
777*795d594fSAndroid Build Coastguard Worker // Different type hierarchy. The test will fail.
778*795d594fSAndroid Build Coastguard Worker *outcome = false;
779*795d594fSAndroid Build Coastguard Worker return true;
780*795d594fSAndroid Build Coastguard Worker }
781*795d594fSAndroid Build Coastguard Worker return false;
782*795d594fSAndroid Build Coastguard Worker }
783*795d594fSAndroid Build Coastguard Worker
VisitCheckCast(HCheckCast * check_cast)784*795d594fSAndroid Build Coastguard Worker void InstructionSimplifierVisitor::VisitCheckCast(HCheckCast* check_cast) {
785*795d594fSAndroid Build Coastguard Worker HInstruction* object = check_cast->InputAt(0);
786*795d594fSAndroid Build Coastguard Worker if (CanEnsureNotNullAt(object, check_cast)) {
787*795d594fSAndroid Build Coastguard Worker check_cast->ClearMustDoNullCheck();
788*795d594fSAndroid Build Coastguard Worker }
789*795d594fSAndroid Build Coastguard Worker
790*795d594fSAndroid Build Coastguard Worker if (object->IsNullConstant()) {
791*795d594fSAndroid Build Coastguard Worker check_cast->GetBlock()->RemoveInstruction(check_cast);
792*795d594fSAndroid Build Coastguard Worker MaybeRecordStat(stats_, MethodCompilationStat::kRemovedCheckedCast);
793*795d594fSAndroid Build Coastguard Worker return;
794*795d594fSAndroid Build Coastguard Worker }
795*795d594fSAndroid Build Coastguard Worker
796*795d594fSAndroid Build Coastguard Worker // Minor correctness check.
797*795d594fSAndroid Build Coastguard Worker DCHECK(check_cast->GetTargetClass()->StrictlyDominates(check_cast))
798*795d594fSAndroid Build Coastguard Worker << "Illegal graph!\n"
799*795d594fSAndroid Build Coastguard Worker << check_cast->DumpWithArgs();
800*795d594fSAndroid Build Coastguard Worker
801*795d594fSAndroid Build Coastguard Worker // Historical note: The `outcome` was initialized to please Valgrind - the compiler can reorder
802*795d594fSAndroid Build Coastguard Worker // the return value check with the `outcome` check, b/27651442.
803*795d594fSAndroid Build Coastguard Worker bool outcome = false;
804*795d594fSAndroid Build Coastguard Worker if (TypeCheckHasKnownOutcome(check_cast->GetTargetClassRTI(), object, &outcome)) {
805*795d594fSAndroid Build Coastguard Worker if (outcome) {
806*795d594fSAndroid Build Coastguard Worker check_cast->GetBlock()->RemoveInstruction(check_cast);
807*795d594fSAndroid Build Coastguard Worker MaybeRecordStat(stats_, MethodCompilationStat::kRemovedCheckedCast);
808*795d594fSAndroid Build Coastguard Worker if (check_cast->GetTypeCheckKind() != TypeCheckKind::kBitstringCheck) {
809*795d594fSAndroid Build Coastguard Worker HLoadClass* load_class = check_cast->GetTargetClass();
810*795d594fSAndroid Build Coastguard Worker if (!load_class->HasUses() && !load_class->NeedsAccessCheck()) {
811*795d594fSAndroid Build Coastguard Worker // We cannot rely on DCE to remove the class because the `HLoadClass` thinks it can throw.
812*795d594fSAndroid Build Coastguard Worker // However, here we know that it cannot because the checkcast was successful, hence
813*795d594fSAndroid Build Coastguard Worker // the class was already loaded.
814*795d594fSAndroid Build Coastguard Worker load_class->GetBlock()->RemoveInstruction(load_class);
815*795d594fSAndroid Build Coastguard Worker }
816*795d594fSAndroid Build Coastguard Worker }
817*795d594fSAndroid Build Coastguard Worker } else {
818*795d594fSAndroid Build Coastguard Worker // TODO Don't do anything for exceptional cases for now. Ideally we should
819*795d594fSAndroid Build Coastguard Worker // remove all instructions and blocks this instruction dominates and
820*795d594fSAndroid Build Coastguard Worker // replace it with a manual throw.
821*795d594fSAndroid Build Coastguard Worker }
822*795d594fSAndroid Build Coastguard Worker }
823*795d594fSAndroid Build Coastguard Worker }
824*795d594fSAndroid Build Coastguard Worker
VisitInstanceOf(HInstanceOf * instruction)825*795d594fSAndroid Build Coastguard Worker void InstructionSimplifierVisitor::VisitInstanceOf(HInstanceOf* instruction) {
826*795d594fSAndroid Build Coastguard Worker HInstruction* object = instruction->InputAt(0);
827*795d594fSAndroid Build Coastguard Worker
828*795d594fSAndroid Build Coastguard Worker bool can_be_null = true;
829*795d594fSAndroid Build Coastguard Worker if (CanEnsureNotNullAt(object, instruction)) {
830*795d594fSAndroid Build Coastguard Worker can_be_null = false;
831*795d594fSAndroid Build Coastguard Worker instruction->ClearMustDoNullCheck();
832*795d594fSAndroid Build Coastguard Worker }
833*795d594fSAndroid Build Coastguard Worker
834*795d594fSAndroid Build Coastguard Worker HGraph* graph = GetGraph();
835*795d594fSAndroid Build Coastguard Worker if (object->IsNullConstant()) {
836*795d594fSAndroid Build Coastguard Worker MaybeRecordStat(stats_, MethodCompilationStat::kRemovedInstanceOf);
837*795d594fSAndroid Build Coastguard Worker instruction->ReplaceWith(graph->GetIntConstant(0));
838*795d594fSAndroid Build Coastguard Worker instruction->GetBlock()->RemoveInstruction(instruction);
839*795d594fSAndroid Build Coastguard Worker RecordSimplification();
840*795d594fSAndroid Build Coastguard Worker return;
841*795d594fSAndroid Build Coastguard Worker }
842*795d594fSAndroid Build Coastguard Worker
843*795d594fSAndroid Build Coastguard Worker // Minor correctness check.
844*795d594fSAndroid Build Coastguard Worker DCHECK(instruction->GetTargetClass()->StrictlyDominates(instruction))
845*795d594fSAndroid Build Coastguard Worker << "Illegal graph!\n"
846*795d594fSAndroid Build Coastguard Worker << instruction->DumpWithArgs();
847*795d594fSAndroid Build Coastguard Worker
848*795d594fSAndroid Build Coastguard Worker // Historical note: The `outcome` was initialized to please Valgrind - the compiler can reorder
849*795d594fSAndroid Build Coastguard Worker // the return value check with the `outcome` check, b/27651442.
850*795d594fSAndroid Build Coastguard Worker bool outcome = false;
851*795d594fSAndroid Build Coastguard Worker if (TypeCheckHasKnownOutcome(instruction->GetTargetClassRTI(), object, &outcome)) {
852*795d594fSAndroid Build Coastguard Worker MaybeRecordStat(stats_, MethodCompilationStat::kRemovedInstanceOf);
853*795d594fSAndroid Build Coastguard Worker if (outcome && can_be_null) {
854*795d594fSAndroid Build Coastguard Worker // Type test will succeed, we just need a null test.
855*795d594fSAndroid Build Coastguard Worker HNotEqual* test = new (graph->GetAllocator()) HNotEqual(graph->GetNullConstant(), object);
856*795d594fSAndroid Build Coastguard Worker instruction->GetBlock()->InsertInstructionBefore(test, instruction);
857*795d594fSAndroid Build Coastguard Worker instruction->ReplaceWith(test);
858*795d594fSAndroid Build Coastguard Worker } else {
859*795d594fSAndroid Build Coastguard Worker // We've statically determined the result of the instanceof.
860*795d594fSAndroid Build Coastguard Worker instruction->ReplaceWith(graph->GetIntConstant(outcome));
861*795d594fSAndroid Build Coastguard Worker }
862*795d594fSAndroid Build Coastguard Worker RecordSimplification();
863*795d594fSAndroid Build Coastguard Worker instruction->GetBlock()->RemoveInstruction(instruction);
864*795d594fSAndroid Build Coastguard Worker if (outcome && instruction->GetTypeCheckKind() != TypeCheckKind::kBitstringCheck) {
865*795d594fSAndroid Build Coastguard Worker HLoadClass* load_class = instruction->GetTargetClass();
866*795d594fSAndroid Build Coastguard Worker if (!load_class->HasUses() && !load_class->NeedsAccessCheck()) {
867*795d594fSAndroid Build Coastguard Worker // We cannot rely on DCE to remove the class because the `HLoadClass`
868*795d594fSAndroid Build Coastguard Worker // thinks it can throw. However, here we know that it cannot because the
869*795d594fSAndroid Build Coastguard Worker // instanceof check was successful and we don't need to check the
870*795d594fSAndroid Build Coastguard Worker // access, hence the class was already loaded.
871*795d594fSAndroid Build Coastguard Worker load_class->GetBlock()->RemoveInstruction(load_class);
872*795d594fSAndroid Build Coastguard Worker }
873*795d594fSAndroid Build Coastguard Worker }
874*795d594fSAndroid Build Coastguard Worker }
875*795d594fSAndroid Build Coastguard Worker }
876*795d594fSAndroid Build Coastguard Worker
VisitInstanceFieldSet(HInstanceFieldSet * instruction)877*795d594fSAndroid Build Coastguard Worker void InstructionSimplifierVisitor::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
878*795d594fSAndroid Build Coastguard Worker if ((instruction->GetValue()->GetType() == DataType::Type::kReference)
879*795d594fSAndroid Build Coastguard Worker && CanEnsureNotNullAt(instruction->GetValue(), instruction)) {
880*795d594fSAndroid Build Coastguard Worker instruction->ClearValueCanBeNull();
881*795d594fSAndroid Build Coastguard Worker }
882*795d594fSAndroid Build Coastguard Worker }
883*795d594fSAndroid Build Coastguard Worker
VisitStaticFieldSet(HStaticFieldSet * instruction)884*795d594fSAndroid Build Coastguard Worker void InstructionSimplifierVisitor::VisitStaticFieldSet(HStaticFieldSet* instruction) {
885*795d594fSAndroid Build Coastguard Worker if ((instruction->GetValue()->GetType() == DataType::Type::kReference)
886*795d594fSAndroid Build Coastguard Worker && CanEnsureNotNullAt(instruction->GetValue(), instruction)) {
887*795d594fSAndroid Build Coastguard Worker instruction->ClearValueCanBeNull();
888*795d594fSAndroid Build Coastguard Worker }
889*795d594fSAndroid Build Coastguard Worker }
890*795d594fSAndroid Build Coastguard Worker
GetOppositeConditionForOperandSwap(IfCondition cond)891*795d594fSAndroid Build Coastguard Worker static IfCondition GetOppositeConditionForOperandSwap(IfCondition cond) {
892*795d594fSAndroid Build Coastguard Worker switch (cond) {
893*795d594fSAndroid Build Coastguard Worker case kCondEQ: return kCondEQ;
894*795d594fSAndroid Build Coastguard Worker case kCondNE: return kCondNE;
895*795d594fSAndroid Build Coastguard Worker case kCondLT: return kCondGT;
896*795d594fSAndroid Build Coastguard Worker case kCondLE: return kCondGE;
897*795d594fSAndroid Build Coastguard Worker case kCondGT: return kCondLT;
898*795d594fSAndroid Build Coastguard Worker case kCondGE: return kCondLE;
899*795d594fSAndroid Build Coastguard Worker case kCondB: return kCondA;
900*795d594fSAndroid Build Coastguard Worker case kCondBE: return kCondAE;
901*795d594fSAndroid Build Coastguard Worker case kCondA: return kCondB;
902*795d594fSAndroid Build Coastguard Worker case kCondAE: return kCondBE;
903*795d594fSAndroid Build Coastguard Worker default:
904*795d594fSAndroid Build Coastguard Worker LOG(FATAL) << "Unknown ConditionType " << cond;
905*795d594fSAndroid Build Coastguard Worker UNREACHABLE();
906*795d594fSAndroid Build Coastguard Worker }
907*795d594fSAndroid Build Coastguard Worker }
908*795d594fSAndroid Build Coastguard Worker
InsertOppositeCondition(HInstruction * cond,HInstruction * cursor)909*795d594fSAndroid Build Coastguard Worker HInstruction* InstructionSimplifierVisitor::InsertOppositeCondition(HInstruction* cond,
910*795d594fSAndroid Build Coastguard Worker HInstruction* cursor) {
911*795d594fSAndroid Build Coastguard Worker if (cond->IsCondition() &&
912*795d594fSAndroid Build Coastguard Worker !DataType::IsFloatingPointType(cond->InputAt(0)->GetType())) {
913*795d594fSAndroid Build Coastguard Worker // Can't reverse floating point conditions. We have to use `HBooleanNot` in that case.
914*795d594fSAndroid Build Coastguard Worker HInstruction* lhs = cond->InputAt(0);
915*795d594fSAndroid Build Coastguard Worker HInstruction* rhs = cond->InputAt(1);
916*795d594fSAndroid Build Coastguard Worker HInstruction* replacement =
917*795d594fSAndroid Build Coastguard Worker HCondition::Create(GetGraph(), cond->AsCondition()->GetOppositeCondition(), lhs, rhs);
918*795d594fSAndroid Build Coastguard Worker cursor->GetBlock()->InsertInstructionBefore(replacement, cursor);
919*795d594fSAndroid Build Coastguard Worker return replacement;
920*795d594fSAndroid Build Coastguard Worker } else if (cond->IsIntConstant()) {
921*795d594fSAndroid Build Coastguard Worker HIntConstant* int_const = cond->AsIntConstant();
922*795d594fSAndroid Build Coastguard Worker if (int_const->IsFalse()) {
923*795d594fSAndroid Build Coastguard Worker return GetGraph()->GetIntConstant(1);
924*795d594fSAndroid Build Coastguard Worker } else {
925*795d594fSAndroid Build Coastguard Worker DCHECK(int_const->IsTrue()) << int_const->GetValue();
926*795d594fSAndroid Build Coastguard Worker return GetGraph()->GetIntConstant(0);
927*795d594fSAndroid Build Coastguard Worker }
928*795d594fSAndroid Build Coastguard Worker } else {
929*795d594fSAndroid Build Coastguard Worker HInstruction* replacement = new (GetGraph()->GetAllocator()) HBooleanNot(cond);
930*795d594fSAndroid Build Coastguard Worker cursor->GetBlock()->InsertInstructionBefore(replacement, cursor);
931*795d594fSAndroid Build Coastguard Worker return replacement;
932*795d594fSAndroid Build Coastguard Worker }
933*795d594fSAndroid Build Coastguard Worker }
934*795d594fSAndroid Build Coastguard Worker
VisitEqual(HEqual * equal)935*795d594fSAndroid Build Coastguard Worker void InstructionSimplifierVisitor::VisitEqual(HEqual* equal) {
936*795d594fSAndroid Build Coastguard Worker HInstruction* input_const = equal->GetConstantRight();
937*795d594fSAndroid Build Coastguard Worker if (input_const != nullptr) {
938*795d594fSAndroid Build Coastguard Worker HInstruction* input_value = equal->GetLeastConstantLeft();
939*795d594fSAndroid Build Coastguard Worker if ((input_value->GetType() == DataType::Type::kBool) && input_const->IsIntConstant()) {
940*795d594fSAndroid Build Coastguard Worker HBasicBlock* block = equal->GetBlock();
941*795d594fSAndroid Build Coastguard Worker // We are comparing the boolean to a constant which is of type int and can
942*795d594fSAndroid Build Coastguard Worker // be any constant.
943*795d594fSAndroid Build Coastguard Worker if (input_const->AsIntConstant()->IsTrue()) {
944*795d594fSAndroid Build Coastguard Worker // Replace (bool_value == true) with bool_value
945*795d594fSAndroid Build Coastguard Worker equal->ReplaceWith(input_value);
946*795d594fSAndroid Build Coastguard Worker block->RemoveInstruction(equal);
947*795d594fSAndroid Build Coastguard Worker RecordSimplification();
948*795d594fSAndroid Build Coastguard Worker } else if (input_const->AsIntConstant()->IsFalse()) {
949*795d594fSAndroid Build Coastguard Worker // Replace (bool_value == false) with !bool_value
950*795d594fSAndroid Build Coastguard Worker equal->ReplaceWith(InsertOppositeCondition(input_value, equal));
951*795d594fSAndroid Build Coastguard Worker block->RemoveInstruction(equal);
952*795d594fSAndroid Build Coastguard Worker RecordSimplification();
953*795d594fSAndroid Build Coastguard Worker } else {
954*795d594fSAndroid Build Coastguard Worker // Replace (bool_value == integer_not_zero_nor_one_constant) with false
955*795d594fSAndroid Build Coastguard Worker equal->ReplaceWith(GetGraph()->GetIntConstant(0));
956*795d594fSAndroid Build Coastguard Worker block->RemoveInstruction(equal);
957*795d594fSAndroid Build Coastguard Worker RecordSimplification();
958*795d594fSAndroid Build Coastguard Worker }
959*795d594fSAndroid Build Coastguard Worker } else {
960*795d594fSAndroid Build Coastguard Worker VisitCondition(equal);
961*795d594fSAndroid Build Coastguard Worker }
962*795d594fSAndroid Build Coastguard Worker } else {
963*795d594fSAndroid Build Coastguard Worker VisitCondition(equal);
964*795d594fSAndroid Build Coastguard Worker }
965*795d594fSAndroid Build Coastguard Worker }
966*795d594fSAndroid Build Coastguard Worker
VisitNotEqual(HNotEqual * not_equal)967*795d594fSAndroid Build Coastguard Worker void InstructionSimplifierVisitor::VisitNotEqual(HNotEqual* not_equal) {
968*795d594fSAndroid Build Coastguard Worker HInstruction* input_const = not_equal->GetConstantRight();
969*795d594fSAndroid Build Coastguard Worker if (input_const != nullptr) {
970*795d594fSAndroid Build Coastguard Worker HInstruction* input_value = not_equal->GetLeastConstantLeft();
971*795d594fSAndroid Build Coastguard Worker if ((input_value->GetType() == DataType::Type::kBool) && input_const->IsIntConstant()) {
972*795d594fSAndroid Build Coastguard Worker HBasicBlock* block = not_equal->GetBlock();
973*795d594fSAndroid Build Coastguard Worker // We are comparing the boolean to a constant which is of type int and can
974*795d594fSAndroid Build Coastguard Worker // be any constant.
975*795d594fSAndroid Build Coastguard Worker if (input_const->AsIntConstant()->IsTrue()) {
976*795d594fSAndroid Build Coastguard Worker // Replace (bool_value != true) with !bool_value
977*795d594fSAndroid Build Coastguard Worker not_equal->ReplaceWith(InsertOppositeCondition(input_value, not_equal));
978*795d594fSAndroid Build Coastguard Worker block->RemoveInstruction(not_equal);
979*795d594fSAndroid Build Coastguard Worker RecordSimplification();
980*795d594fSAndroid Build Coastguard Worker } else if (input_const->AsIntConstant()->IsFalse()) {
981*795d594fSAndroid Build Coastguard Worker // Replace (bool_value != false) with bool_value
982*795d594fSAndroid Build Coastguard Worker not_equal->ReplaceWith(input_value);
983*795d594fSAndroid Build Coastguard Worker block->RemoveInstruction(not_equal);
984*795d594fSAndroid Build Coastguard Worker RecordSimplification();
985*795d594fSAndroid Build Coastguard Worker } else {
986*795d594fSAndroid Build Coastguard Worker // Replace (bool_value != integer_not_zero_nor_one_constant) with true
987*795d594fSAndroid Build Coastguard Worker not_equal->ReplaceWith(GetGraph()->GetIntConstant(1));
988*795d594fSAndroid Build Coastguard Worker block->RemoveInstruction(not_equal);
989*795d594fSAndroid Build Coastguard Worker RecordSimplification();
990*795d594fSAndroid Build Coastguard Worker }
991*795d594fSAndroid Build Coastguard Worker } else {
992*795d594fSAndroid Build Coastguard Worker VisitCondition(not_equal);
993*795d594fSAndroid Build Coastguard Worker }
994*795d594fSAndroid Build Coastguard Worker } else {
995*795d594fSAndroid Build Coastguard Worker VisitCondition(not_equal);
996*795d594fSAndroid Build Coastguard Worker }
997*795d594fSAndroid Build Coastguard Worker }
998*795d594fSAndroid Build Coastguard Worker
VisitBooleanNot(HBooleanNot * bool_not)999*795d594fSAndroid Build Coastguard Worker void InstructionSimplifierVisitor::VisitBooleanNot(HBooleanNot* bool_not) {
1000*795d594fSAndroid Build Coastguard Worker HInstruction* input = bool_not->InputAt(0);
1001*795d594fSAndroid Build Coastguard Worker HInstruction* replace_with = nullptr;
1002*795d594fSAndroid Build Coastguard Worker
1003*795d594fSAndroid Build Coastguard Worker if (input->IsIntConstant()) {
1004*795d594fSAndroid Build Coastguard Worker // Replace !(true/false) with false/true.
1005*795d594fSAndroid Build Coastguard Worker if (input->AsIntConstant()->IsTrue()) {
1006*795d594fSAndroid Build Coastguard Worker replace_with = GetGraph()->GetIntConstant(0);
1007*795d594fSAndroid Build Coastguard Worker } else {
1008*795d594fSAndroid Build Coastguard Worker DCHECK(input->AsIntConstant()->IsFalse()) << input->AsIntConstant()->GetValue();
1009*795d594fSAndroid Build Coastguard Worker replace_with = GetGraph()->GetIntConstant(1);
1010*795d594fSAndroid Build Coastguard Worker }
1011*795d594fSAndroid Build Coastguard Worker } else if (input->IsBooleanNot()) {
1012*795d594fSAndroid Build Coastguard Worker // Replace (!(!bool_value)) with bool_value.
1013*795d594fSAndroid Build Coastguard Worker replace_with = input->InputAt(0);
1014*795d594fSAndroid Build Coastguard Worker } else if (input->IsCondition() &&
1015*795d594fSAndroid Build Coastguard Worker // Don't change FP compares. The definition of compares involving
1016*795d594fSAndroid Build Coastguard Worker // NaNs forces the compares to be done as written by the user.
1017*795d594fSAndroid Build Coastguard Worker !DataType::IsFloatingPointType(input->InputAt(0)->GetType())) {
1018*795d594fSAndroid Build Coastguard Worker // Replace condition with its opposite.
1019*795d594fSAndroid Build Coastguard Worker replace_with = InsertOppositeCondition(input->AsCondition(), bool_not);
1020*795d594fSAndroid Build Coastguard Worker }
1021*795d594fSAndroid Build Coastguard Worker
1022*795d594fSAndroid Build Coastguard Worker if (replace_with != nullptr) {
1023*795d594fSAndroid Build Coastguard Worker bool_not->ReplaceWith(replace_with);
1024*795d594fSAndroid Build Coastguard Worker bool_not->GetBlock()->RemoveInstruction(bool_not);
1025*795d594fSAndroid Build Coastguard Worker RecordSimplification();
1026*795d594fSAndroid Build Coastguard Worker }
1027*795d594fSAndroid Build Coastguard Worker }
1028*795d594fSAndroid Build Coastguard Worker
1029*795d594fSAndroid Build Coastguard Worker // Constructs a new ABS(x) node in the HIR.
NewIntegralAbs(ArenaAllocator * allocator,HInstruction * x,HInstruction * cursor)1030*795d594fSAndroid Build Coastguard Worker static HInstruction* NewIntegralAbs(ArenaAllocator* allocator,
1031*795d594fSAndroid Build Coastguard Worker HInstruction* x,
1032*795d594fSAndroid Build Coastguard Worker HInstruction* cursor) {
1033*795d594fSAndroid Build Coastguard Worker DataType::Type type = DataType::Kind(x->GetType());
1034*795d594fSAndroid Build Coastguard Worker DCHECK(type == DataType::Type::kInt32 || type == DataType::Type::kInt64);
1035*795d594fSAndroid Build Coastguard Worker HAbs* abs = new (allocator) HAbs(type, x, cursor->GetDexPc());
1036*795d594fSAndroid Build Coastguard Worker cursor->GetBlock()->InsertInstructionBefore(abs, cursor);
1037*795d594fSAndroid Build Coastguard Worker return abs;
1038*795d594fSAndroid Build Coastguard Worker }
1039*795d594fSAndroid Build Coastguard Worker
1040*795d594fSAndroid Build Coastguard Worker // Constructs a new MIN/MAX(x, y) node in the HIR.
NewIntegralMinMax(ArenaAllocator * allocator,HInstruction * x,HInstruction * y,HInstruction * cursor,bool is_min)1041*795d594fSAndroid Build Coastguard Worker static HInstruction* NewIntegralMinMax(ArenaAllocator* allocator,
1042*795d594fSAndroid Build Coastguard Worker HInstruction* x,
1043*795d594fSAndroid Build Coastguard Worker HInstruction* y,
1044*795d594fSAndroid Build Coastguard Worker HInstruction* cursor,
1045*795d594fSAndroid Build Coastguard Worker bool is_min) {
1046*795d594fSAndroid Build Coastguard Worker DataType::Type type = DataType::Kind(x->GetType());
1047*795d594fSAndroid Build Coastguard Worker DCHECK(type == DataType::Type::kInt32 || type == DataType::Type::kInt64);
1048*795d594fSAndroid Build Coastguard Worker HBinaryOperation* minmax = nullptr;
1049*795d594fSAndroid Build Coastguard Worker if (is_min) {
1050*795d594fSAndroid Build Coastguard Worker minmax = new (allocator) HMin(type, x, y, cursor->GetDexPc());
1051*795d594fSAndroid Build Coastguard Worker } else {
1052*795d594fSAndroid Build Coastguard Worker minmax = new (allocator) HMax(type, x, y, cursor->GetDexPc());
1053*795d594fSAndroid Build Coastguard Worker }
1054*795d594fSAndroid Build Coastguard Worker cursor->GetBlock()->InsertInstructionBefore(minmax, cursor);
1055*795d594fSAndroid Build Coastguard Worker return minmax;
1056*795d594fSAndroid Build Coastguard Worker }
1057*795d594fSAndroid Build Coastguard Worker
1058*795d594fSAndroid Build Coastguard Worker // Returns true if operands a and b consists of widening type conversions
1059*795d594fSAndroid Build Coastguard Worker // (either explicit or implicit) to the given to_type.
AreLowerPrecisionArgs(DataType::Type to_type,HInstruction * a,HInstruction * b)1060*795d594fSAndroid Build Coastguard Worker static bool AreLowerPrecisionArgs(DataType::Type to_type, HInstruction* a, HInstruction* b) {
1061*795d594fSAndroid Build Coastguard Worker if (a->IsTypeConversion() && a->GetType() == to_type) {
1062*795d594fSAndroid Build Coastguard Worker a = a->InputAt(0);
1063*795d594fSAndroid Build Coastguard Worker }
1064*795d594fSAndroid Build Coastguard Worker if (b->IsTypeConversion() && b->GetType() == to_type) {
1065*795d594fSAndroid Build Coastguard Worker b = b->InputAt(0);
1066*795d594fSAndroid Build Coastguard Worker }
1067*795d594fSAndroid Build Coastguard Worker DataType::Type type1 = a->GetType();
1068*795d594fSAndroid Build Coastguard Worker DataType::Type type2 = b->GetType();
1069*795d594fSAndroid Build Coastguard Worker return (type1 == DataType::Type::kUint8 && type2 == DataType::Type::kUint8) ||
1070*795d594fSAndroid Build Coastguard Worker (type1 == DataType::Type::kInt8 && type2 == DataType::Type::kInt8) ||
1071*795d594fSAndroid Build Coastguard Worker (type1 == DataType::Type::kInt16 && type2 == DataType::Type::kInt16) ||
1072*795d594fSAndroid Build Coastguard Worker (type1 == DataType::Type::kUint16 && type2 == DataType::Type::kUint16) ||
1073*795d594fSAndroid Build Coastguard Worker (type1 == DataType::Type::kInt32 && type2 == DataType::Type::kInt32 &&
1074*795d594fSAndroid Build Coastguard Worker to_type == DataType::Type::kInt64);
1075*795d594fSAndroid Build Coastguard Worker }
1076*795d594fSAndroid Build Coastguard Worker
1077*795d594fSAndroid Build Coastguard Worker // Returns an acceptable substitution for "a" on the select
1078*795d594fSAndroid Build Coastguard Worker // construct "a <cmp> b ? c : .." during MIN/MAX recognition.
AllowInMinMax(IfCondition cmp,HInstruction * a,HInstruction * b,HInstruction * c)1079*795d594fSAndroid Build Coastguard Worker static HInstruction* AllowInMinMax(IfCondition cmp,
1080*795d594fSAndroid Build Coastguard Worker HInstruction* a,
1081*795d594fSAndroid Build Coastguard Worker HInstruction* b,
1082*795d594fSAndroid Build Coastguard Worker HInstruction* c) {
1083*795d594fSAndroid Build Coastguard Worker int64_t value = 0;
1084*795d594fSAndroid Build Coastguard Worker if (IsInt64AndGet(b, /*out*/ &value) &&
1085*795d594fSAndroid Build Coastguard Worker (((cmp == kCondLT || cmp == kCondLE) && c->IsMax()) ||
1086*795d594fSAndroid Build Coastguard Worker ((cmp == kCondGT || cmp == kCondGE) && c->IsMin()))) {
1087*795d594fSAndroid Build Coastguard Worker HConstant* other = c->AsBinaryOperation()->GetConstantRight();
1088*795d594fSAndroid Build Coastguard Worker if (other != nullptr && a == c->AsBinaryOperation()->GetLeastConstantLeft()) {
1089*795d594fSAndroid Build Coastguard Worker int64_t other_value = Int64FromConstant(other);
1090*795d594fSAndroid Build Coastguard Worker bool is_max = (cmp == kCondLT || cmp == kCondLE);
1091*795d594fSAndroid Build Coastguard Worker // Allow the max for a < 100 ? max(a, -100) : ..
1092*795d594fSAndroid Build Coastguard Worker // or the min for a > -100 ? min(a, 100) : ..
1093*795d594fSAndroid Build Coastguard Worker if (is_max ? (value >= other_value) : (value <= other_value)) {
1094*795d594fSAndroid Build Coastguard Worker return c;
1095*795d594fSAndroid Build Coastguard Worker }
1096*795d594fSAndroid Build Coastguard Worker }
1097*795d594fSAndroid Build Coastguard Worker }
1098*795d594fSAndroid Build Coastguard Worker return nullptr;
1099*795d594fSAndroid Build Coastguard Worker }
1100*795d594fSAndroid Build Coastguard Worker
VisitSelect(HSelect * select)1101*795d594fSAndroid Build Coastguard Worker void InstructionSimplifierVisitor::VisitSelect(HSelect* select) {
1102*795d594fSAndroid Build Coastguard Worker HInstruction* replace_with = nullptr;
1103*795d594fSAndroid Build Coastguard Worker HInstruction* condition = select->GetCondition();
1104*795d594fSAndroid Build Coastguard Worker HInstruction* true_value = select->GetTrueValue();
1105*795d594fSAndroid Build Coastguard Worker HInstruction* false_value = select->GetFalseValue();
1106*795d594fSAndroid Build Coastguard Worker
1107*795d594fSAndroid Build Coastguard Worker if (condition->IsBooleanNot()) {
1108*795d594fSAndroid Build Coastguard Worker // Change ((!cond) ? x : y) to (cond ? y : x).
1109*795d594fSAndroid Build Coastguard Worker condition = condition->InputAt(0);
1110*795d594fSAndroid Build Coastguard Worker std::swap(true_value, false_value);
1111*795d594fSAndroid Build Coastguard Worker select->ReplaceInput(false_value, 0);
1112*795d594fSAndroid Build Coastguard Worker select->ReplaceInput(true_value, 1);
1113*795d594fSAndroid Build Coastguard Worker select->ReplaceInput(condition, 2);
1114*795d594fSAndroid Build Coastguard Worker RecordSimplification();
1115*795d594fSAndroid Build Coastguard Worker }
1116*795d594fSAndroid Build Coastguard Worker
1117*795d594fSAndroid Build Coastguard Worker if (true_value == false_value) {
1118*795d594fSAndroid Build Coastguard Worker // Replace (cond ? x : x) with (x).
1119*795d594fSAndroid Build Coastguard Worker replace_with = true_value;
1120*795d594fSAndroid Build Coastguard Worker } else if (condition->IsIntConstant()) {
1121*795d594fSAndroid Build Coastguard Worker if (condition->AsIntConstant()->IsTrue()) {
1122*795d594fSAndroid Build Coastguard Worker // Replace (true ? x : y) with (x).
1123*795d594fSAndroid Build Coastguard Worker replace_with = true_value;
1124*795d594fSAndroid Build Coastguard Worker } else {
1125*795d594fSAndroid Build Coastguard Worker // Replace (false ? x : y) with (y).
1126*795d594fSAndroid Build Coastguard Worker DCHECK(condition->AsIntConstant()->IsFalse()) << condition->AsIntConstant()->GetValue();
1127*795d594fSAndroid Build Coastguard Worker replace_with = false_value;
1128*795d594fSAndroid Build Coastguard Worker }
1129*795d594fSAndroid Build Coastguard Worker } else if (true_value->IsIntConstant() && false_value->IsIntConstant()) {
1130*795d594fSAndroid Build Coastguard Worker if (true_value->AsIntConstant()->IsTrue() && false_value->AsIntConstant()->IsFalse()) {
1131*795d594fSAndroid Build Coastguard Worker // Replace (cond ? true : false) with (cond).
1132*795d594fSAndroid Build Coastguard Worker replace_with = condition;
1133*795d594fSAndroid Build Coastguard Worker } else if (true_value->AsIntConstant()->IsFalse() && false_value->AsIntConstant()->IsTrue()) {
1134*795d594fSAndroid Build Coastguard Worker // Replace (cond ? false : true) with (!cond).
1135*795d594fSAndroid Build Coastguard Worker replace_with = InsertOppositeCondition(condition, select);
1136*795d594fSAndroid Build Coastguard Worker }
1137*795d594fSAndroid Build Coastguard Worker } else if (condition->IsCondition()) {
1138*795d594fSAndroid Build Coastguard Worker IfCondition cmp = condition->AsCondition()->GetCondition();
1139*795d594fSAndroid Build Coastguard Worker HInstruction* a = condition->InputAt(0);
1140*795d594fSAndroid Build Coastguard Worker HInstruction* b = condition->InputAt(1);
1141*795d594fSAndroid Build Coastguard Worker DataType::Type t_type = true_value->GetType();
1142*795d594fSAndroid Build Coastguard Worker DataType::Type f_type = false_value->GetType();
1143*795d594fSAndroid Build Coastguard Worker if (DataType::IsIntegralType(t_type) && DataType::Kind(t_type) == DataType::Kind(f_type)) {
1144*795d594fSAndroid Build Coastguard Worker if (cmp == kCondEQ || cmp == kCondNE) {
1145*795d594fSAndroid Build Coastguard Worker // Turns
1146*795d594fSAndroid Build Coastguard Worker // * Select[a, b, EQ(a,b)] / Select[a, b, EQ(b,a)] into a
1147*795d594fSAndroid Build Coastguard Worker // * Select[a, b, NE(a,b)] / Select[a, b, NE(b,a)] into b
1148*795d594fSAndroid Build Coastguard Worker // Note that the order in EQ/NE is irrelevant.
1149*795d594fSAndroid Build Coastguard Worker if ((a == true_value && b == false_value) || (a == false_value && b == true_value)) {
1150*795d594fSAndroid Build Coastguard Worker replace_with = cmp == kCondEQ ? false_value : true_value;
1151*795d594fSAndroid Build Coastguard Worker }
1152*795d594fSAndroid Build Coastguard Worker } else {
1153*795d594fSAndroid Build Coastguard Worker // Test if both values are compatible integral types (resulting MIN/MAX/ABS
1154*795d594fSAndroid Build Coastguard Worker // type will be int or long, like the condition). Replacements are general,
1155*795d594fSAndroid Build Coastguard Worker // but assume conditions prefer constants on the right.
1156*795d594fSAndroid Build Coastguard Worker
1157*795d594fSAndroid Build Coastguard Worker // Allow a < 100 ? max(a, -100) : ..
1158*795d594fSAndroid Build Coastguard Worker // or a > -100 ? min(a, 100) : ..
1159*795d594fSAndroid Build Coastguard Worker // to use min/max instead of a to detect nested min/max expressions.
1160*795d594fSAndroid Build Coastguard Worker HInstruction* new_a = AllowInMinMax(cmp, a, b, true_value);
1161*795d594fSAndroid Build Coastguard Worker if (new_a != nullptr) {
1162*795d594fSAndroid Build Coastguard Worker a = new_a;
1163*795d594fSAndroid Build Coastguard Worker }
1164*795d594fSAndroid Build Coastguard Worker // Try to replace typical integral MIN/MAX/ABS constructs.
1165*795d594fSAndroid Build Coastguard Worker if ((cmp == kCondLT || cmp == kCondLE || cmp == kCondGT || cmp == kCondGE) &&
1166*795d594fSAndroid Build Coastguard Worker ((a == true_value && b == false_value) || (b == true_value && a == false_value))) {
1167*795d594fSAndroid Build Coastguard Worker // Found a < b ? a : b (MIN) or a < b ? b : a (MAX)
1168*795d594fSAndroid Build Coastguard Worker // or a > b ? a : b (MAX) or a > b ? b : a (MIN).
1169*795d594fSAndroid Build Coastguard Worker bool is_min = (cmp == kCondLT || cmp == kCondLE) == (a == true_value);
1170*795d594fSAndroid Build Coastguard Worker replace_with = NewIntegralMinMax(GetGraph()->GetAllocator(), a, b, select, is_min);
1171*795d594fSAndroid Build Coastguard Worker } else if (((cmp == kCondLT || cmp == kCondLE) && true_value->IsNeg()) ||
1172*795d594fSAndroid Build Coastguard Worker ((cmp == kCondGT || cmp == kCondGE) && false_value->IsNeg())) {
1173*795d594fSAndroid Build Coastguard Worker bool negLeft = (cmp == kCondLT || cmp == kCondLE);
1174*795d594fSAndroid Build Coastguard Worker HInstruction* the_negated = negLeft ? true_value->InputAt(0) : false_value->InputAt(0);
1175*795d594fSAndroid Build Coastguard Worker HInstruction* not_negated = negLeft ? false_value : true_value;
1176*795d594fSAndroid Build Coastguard Worker if (a == the_negated && a == not_negated && IsInt64Value(b, 0)) {
1177*795d594fSAndroid Build Coastguard Worker // Found a < 0 ? -a : a
1178*795d594fSAndroid Build Coastguard Worker // or a > 0 ? a : -a
1179*795d594fSAndroid Build Coastguard Worker // which can be replaced by ABS(a).
1180*795d594fSAndroid Build Coastguard Worker replace_with = NewIntegralAbs(GetGraph()->GetAllocator(), a, select);
1181*795d594fSAndroid Build Coastguard Worker }
1182*795d594fSAndroid Build Coastguard Worker } else if (true_value->IsSub() && false_value->IsSub()) {
1183*795d594fSAndroid Build Coastguard Worker HInstruction* true_sub1 = true_value->InputAt(0);
1184*795d594fSAndroid Build Coastguard Worker HInstruction* true_sub2 = true_value->InputAt(1);
1185*795d594fSAndroid Build Coastguard Worker HInstruction* false_sub1 = false_value->InputAt(0);
1186*795d594fSAndroid Build Coastguard Worker HInstruction* false_sub2 = false_value->InputAt(1);
1187*795d594fSAndroid Build Coastguard Worker if ((((cmp == kCondGT || cmp == kCondGE) &&
1188*795d594fSAndroid Build Coastguard Worker (a == true_sub1 && b == true_sub2 && a == false_sub2 && b == false_sub1)) ||
1189*795d594fSAndroid Build Coastguard Worker ((cmp == kCondLT || cmp == kCondLE) &&
1190*795d594fSAndroid Build Coastguard Worker (a == true_sub2 && b == true_sub1 && a == false_sub1 && b == false_sub2))) &&
1191*795d594fSAndroid Build Coastguard Worker AreLowerPrecisionArgs(t_type, a, b)) {
1192*795d594fSAndroid Build Coastguard Worker // Found a > b ? a - b : b - a
1193*795d594fSAndroid Build Coastguard Worker // or a < b ? b - a : a - b
1194*795d594fSAndroid Build Coastguard Worker // which can be replaced by ABS(a - b) for lower precision operands a, b.
1195*795d594fSAndroid Build Coastguard Worker replace_with = NewIntegralAbs(GetGraph()->GetAllocator(), true_value, select);
1196*795d594fSAndroid Build Coastguard Worker }
1197*795d594fSAndroid Build Coastguard Worker }
1198*795d594fSAndroid Build Coastguard Worker }
1199*795d594fSAndroid Build Coastguard Worker }
1200*795d594fSAndroid Build Coastguard Worker }
1201*795d594fSAndroid Build Coastguard Worker
1202*795d594fSAndroid Build Coastguard Worker if (replace_with != nullptr) {
1203*795d594fSAndroid Build Coastguard Worker select->ReplaceWith(replace_with);
1204*795d594fSAndroid Build Coastguard Worker select->GetBlock()->RemoveInstruction(select);
1205*795d594fSAndroid Build Coastguard Worker RecordSimplification();
1206*795d594fSAndroid Build Coastguard Worker }
1207*795d594fSAndroid Build Coastguard Worker }
1208*795d594fSAndroid Build Coastguard Worker
VisitIf(HIf * instruction)1209*795d594fSAndroid Build Coastguard Worker void InstructionSimplifierVisitor::VisitIf(HIf* instruction) {
1210*795d594fSAndroid Build Coastguard Worker HInstruction* condition = instruction->InputAt(0);
1211*795d594fSAndroid Build Coastguard Worker if (condition->IsBooleanNot()) {
1212*795d594fSAndroid Build Coastguard Worker // Swap successors if input is negated.
1213*795d594fSAndroid Build Coastguard Worker instruction->ReplaceInput(condition->InputAt(0), 0);
1214*795d594fSAndroid Build Coastguard Worker instruction->GetBlock()->SwapSuccessors();
1215*795d594fSAndroid Build Coastguard Worker RecordSimplification();
1216*795d594fSAndroid Build Coastguard Worker }
1217*795d594fSAndroid Build Coastguard Worker }
1218*795d594fSAndroid Build Coastguard Worker
1219*795d594fSAndroid Build Coastguard Worker // TODO(solanes): This optimization should be in ConstantFolding since we are folding to a constant.
1220*795d594fSAndroid Build Coastguard Worker // However, we get code size regressions when we do that since we sometimes have a NullCheck between
1221*795d594fSAndroid Build Coastguard Worker // HArrayLength and IsNewArray, and said NullCheck is eliminated in InstructionSimplifier. If we run
1222*795d594fSAndroid Build Coastguard Worker // ConstantFolding and InstructionSimplifier in lockstep this wouldn't be an issue.
VisitArrayLength(HArrayLength * instruction)1223*795d594fSAndroid Build Coastguard Worker void InstructionSimplifierVisitor::VisitArrayLength(HArrayLength* instruction) {
1224*795d594fSAndroid Build Coastguard Worker HInstruction* input = instruction->InputAt(0);
1225*795d594fSAndroid Build Coastguard Worker // If the array is a NewArray with constant size, replace the array length
1226*795d594fSAndroid Build Coastguard Worker // with the constant instruction. This helps the bounds check elimination phase.
1227*795d594fSAndroid Build Coastguard Worker if (input->IsNewArray()) {
1228*795d594fSAndroid Build Coastguard Worker input = input->AsNewArray()->GetLength();
1229*795d594fSAndroid Build Coastguard Worker if (input->IsIntConstant()) {
1230*795d594fSAndroid Build Coastguard Worker instruction->ReplaceWith(input);
1231*795d594fSAndroid Build Coastguard Worker }
1232*795d594fSAndroid Build Coastguard Worker }
1233*795d594fSAndroid Build Coastguard Worker }
1234*795d594fSAndroid Build Coastguard Worker
VisitArraySet(HArraySet * instruction)1235*795d594fSAndroid Build Coastguard Worker void InstructionSimplifierVisitor::VisitArraySet(HArraySet* instruction) {
1236*795d594fSAndroid Build Coastguard Worker HInstruction* value = instruction->GetValue();
1237*795d594fSAndroid Build Coastguard Worker if (value->GetType() != DataType::Type::kReference) {
1238*795d594fSAndroid Build Coastguard Worker return;
1239*795d594fSAndroid Build Coastguard Worker }
1240*795d594fSAndroid Build Coastguard Worker
1241*795d594fSAndroid Build Coastguard Worker if (CanEnsureNotNullAt(value, instruction)) {
1242*795d594fSAndroid Build Coastguard Worker instruction->ClearValueCanBeNull();
1243*795d594fSAndroid Build Coastguard Worker }
1244*795d594fSAndroid Build Coastguard Worker
1245*795d594fSAndroid Build Coastguard Worker if (value->IsArrayGet()) {
1246*795d594fSAndroid Build Coastguard Worker if (value->AsArrayGet()->GetArray() == instruction->GetArray()) {
1247*795d594fSAndroid Build Coastguard Worker // If the code is just swapping elements in the array, no need for a type check.
1248*795d594fSAndroid Build Coastguard Worker instruction->ClearTypeCheck();
1249*795d594fSAndroid Build Coastguard Worker return;
1250*795d594fSAndroid Build Coastguard Worker }
1251*795d594fSAndroid Build Coastguard Worker }
1252*795d594fSAndroid Build Coastguard Worker
1253*795d594fSAndroid Build Coastguard Worker if (value->IsNullConstant()) {
1254*795d594fSAndroid Build Coastguard Worker instruction->ClearTypeCheck();
1255*795d594fSAndroid Build Coastguard Worker return;
1256*795d594fSAndroid Build Coastguard Worker }
1257*795d594fSAndroid Build Coastguard Worker
1258*795d594fSAndroid Build Coastguard Worker ScopedObjectAccess soa(Thread::Current());
1259*795d594fSAndroid Build Coastguard Worker ReferenceTypeInfo array_rti = instruction->GetArray()->GetReferenceTypeInfo();
1260*795d594fSAndroid Build Coastguard Worker ReferenceTypeInfo value_rti = value->GetReferenceTypeInfo();
1261*795d594fSAndroid Build Coastguard Worker if (!array_rti.IsValid()) {
1262*795d594fSAndroid Build Coastguard Worker return;
1263*795d594fSAndroid Build Coastguard Worker }
1264*795d594fSAndroid Build Coastguard Worker
1265*795d594fSAndroid Build Coastguard Worker if (value_rti.IsValid() && array_rti.CanArrayHold(value_rti)) {
1266*795d594fSAndroid Build Coastguard Worker instruction->ClearTypeCheck();
1267*795d594fSAndroid Build Coastguard Worker return;
1268*795d594fSAndroid Build Coastguard Worker }
1269*795d594fSAndroid Build Coastguard Worker
1270*795d594fSAndroid Build Coastguard Worker if (array_rti.IsObjectArray()) {
1271*795d594fSAndroid Build Coastguard Worker if (array_rti.IsExact()) {
1272*795d594fSAndroid Build Coastguard Worker instruction->ClearTypeCheck();
1273*795d594fSAndroid Build Coastguard Worker return;
1274*795d594fSAndroid Build Coastguard Worker }
1275*795d594fSAndroid Build Coastguard Worker instruction->SetStaticTypeOfArrayIsObjectArray();
1276*795d594fSAndroid Build Coastguard Worker }
1277*795d594fSAndroid Build Coastguard Worker }
1278*795d594fSAndroid Build Coastguard Worker
IsTypeConversionLossless(DataType::Type input_type,DataType::Type result_type)1279*795d594fSAndroid Build Coastguard Worker static bool IsTypeConversionLossless(DataType::Type input_type, DataType::Type result_type) {
1280*795d594fSAndroid Build Coastguard Worker // Make sure all implicit conversions have been simplified and no new ones have been introduced.
1281*795d594fSAndroid Build Coastguard Worker DCHECK(!DataType::IsTypeConversionImplicit(input_type, result_type))
1282*795d594fSAndroid Build Coastguard Worker << input_type << "," << result_type;
1283*795d594fSAndroid Build Coastguard Worker // The conversion to a larger type is loss-less with the exception of two cases,
1284*795d594fSAndroid Build Coastguard Worker // - conversion to the unsigned type Uint16, where we may lose some bits, and
1285*795d594fSAndroid Build Coastguard Worker // - conversion from float to long, the only FP to integral conversion with smaller FP type.
1286*795d594fSAndroid Build Coastguard Worker // For integral to FP conversions this holds because the FP mantissa is large enough.
1287*795d594fSAndroid Build Coastguard Worker // Note: The size check excludes Uint8 as the result type.
1288*795d594fSAndroid Build Coastguard Worker return DataType::Size(result_type) > DataType::Size(input_type) &&
1289*795d594fSAndroid Build Coastguard Worker result_type != DataType::Type::kUint16 &&
1290*795d594fSAndroid Build Coastguard Worker !(result_type == DataType::Type::kInt64 && input_type == DataType::Type::kFloat32);
1291*795d594fSAndroid Build Coastguard Worker }
1292*795d594fSAndroid Build Coastguard Worker
CanRemoveRedundantAnd(HConstant * and_right,HConstant * shr_right,DataType::Type result_type)1293*795d594fSAndroid Build Coastguard Worker static bool CanRemoveRedundantAnd(HConstant* and_right,
1294*795d594fSAndroid Build Coastguard Worker HConstant* shr_right,
1295*795d594fSAndroid Build Coastguard Worker DataType::Type result_type) {
1296*795d594fSAndroid Build Coastguard Worker int64_t and_cst = Int64FromConstant(and_right);
1297*795d594fSAndroid Build Coastguard Worker int64_t shr_cst = Int64FromConstant(shr_right);
1298*795d594fSAndroid Build Coastguard Worker
1299*795d594fSAndroid Build Coastguard Worker // In the following sequence A is the input value, D is the result:
1300*795d594fSAndroid Build Coastguard Worker // B := A & x
1301*795d594fSAndroid Build Coastguard Worker // C := B >> r
1302*795d594fSAndroid Build Coastguard Worker // D := TypeConv(n-bit type) C
1303*795d594fSAndroid Build Coastguard Worker
1304*795d594fSAndroid Build Coastguard Worker // The value of D is entirely dependent on the bits [n-1:0] of C, which in turn are dependent
1305*795d594fSAndroid Build Coastguard Worker // on bits [r+n-1:r] of B.
1306*795d594fSAndroid Build Coastguard Worker // Therefore, if the AND does not change bits [r+n-1:r] of A then it will not affect D.
1307*795d594fSAndroid Build Coastguard Worker // This can be checked by ensuring that bits [r+n-1:r] of the AND Constant are 1.
1308*795d594fSAndroid Build Coastguard Worker
1309*795d594fSAndroid Build Coastguard Worker // For example: return (byte) ((value & 0xff00) >> 8)
1310*795d594fSAndroid Build Coastguard Worker // return (byte) ((value & 0xff000000) >> 31)
1311*795d594fSAndroid Build Coastguard Worker
1312*795d594fSAndroid Build Coastguard Worker // The mask sets bits [r+n-1:r] to 1, and all others to 0.
1313*795d594fSAndroid Build Coastguard Worker int64_t mask = DataType::MaxValueOfIntegralType(DataType::ToUnsigned(result_type)) << shr_cst;
1314*795d594fSAndroid Build Coastguard Worker
1315*795d594fSAndroid Build Coastguard Worker // If the result of a bitwise AND between the mask and the AND constant is the original mask, then
1316*795d594fSAndroid Build Coastguard Worker // the AND does not change bits [r+n-1:r], meaning that it is redundant and can be removed.
1317*795d594fSAndroid Build Coastguard Worker return ((and_cst & mask) == mask);
1318*795d594fSAndroid Build Coastguard Worker }
1319*795d594fSAndroid Build Coastguard Worker
TryReplaceFieldOrArrayGetType(HInstruction * maybe_get,DataType::Type new_type)1320*795d594fSAndroid Build Coastguard Worker static inline bool TryReplaceFieldOrArrayGetType(HInstruction* maybe_get, DataType::Type new_type) {
1321*795d594fSAndroid Build Coastguard Worker if (maybe_get->IsInstanceFieldGet()) {
1322*795d594fSAndroid Build Coastguard Worker maybe_get->AsInstanceFieldGet()->SetType(new_type);
1323*795d594fSAndroid Build Coastguard Worker return true;
1324*795d594fSAndroid Build Coastguard Worker } else if (maybe_get->IsStaticFieldGet()) {
1325*795d594fSAndroid Build Coastguard Worker maybe_get->AsStaticFieldGet()->SetType(new_type);
1326*795d594fSAndroid Build Coastguard Worker return true;
1327*795d594fSAndroid Build Coastguard Worker } else if (maybe_get->IsArrayGet() && !maybe_get->AsArrayGet()->IsStringCharAt()) {
1328*795d594fSAndroid Build Coastguard Worker maybe_get->AsArrayGet()->SetType(new_type);
1329*795d594fSAndroid Build Coastguard Worker return true;
1330*795d594fSAndroid Build Coastguard Worker } else {
1331*795d594fSAndroid Build Coastguard Worker return false;
1332*795d594fSAndroid Build Coastguard Worker }
1333*795d594fSAndroid Build Coastguard Worker }
1334*795d594fSAndroid Build Coastguard Worker
1335*795d594fSAndroid Build Coastguard Worker // The type conversion is only used for storing into a field/element of the
1336*795d594fSAndroid Build Coastguard Worker // same/narrower size.
IsTypeConversionForStoringIntoNoWiderFieldOnly(HTypeConversion * type_conversion)1337*795d594fSAndroid Build Coastguard Worker static bool IsTypeConversionForStoringIntoNoWiderFieldOnly(HTypeConversion* type_conversion) {
1338*795d594fSAndroid Build Coastguard Worker if (type_conversion->HasEnvironmentUses()) {
1339*795d594fSAndroid Build Coastguard Worker return false;
1340*795d594fSAndroid Build Coastguard Worker }
1341*795d594fSAndroid Build Coastguard Worker DataType::Type input_type = type_conversion->GetInputType();
1342*795d594fSAndroid Build Coastguard Worker DataType::Type result_type = type_conversion->GetResultType();
1343*795d594fSAndroid Build Coastguard Worker if (!DataType::IsIntegralType(input_type) ||
1344*795d594fSAndroid Build Coastguard Worker !DataType::IsIntegralType(result_type) ||
1345*795d594fSAndroid Build Coastguard Worker input_type == DataType::Type::kInt64 ||
1346*795d594fSAndroid Build Coastguard Worker result_type == DataType::Type::kInt64) {
1347*795d594fSAndroid Build Coastguard Worker // Type conversion is needed if non-integer types are involved, or 64-bit
1348*795d594fSAndroid Build Coastguard Worker // types are involved, which may use different number of registers.
1349*795d594fSAndroid Build Coastguard Worker return false;
1350*795d594fSAndroid Build Coastguard Worker }
1351*795d594fSAndroid Build Coastguard Worker if (DataType::Size(input_type) >= DataType::Size(result_type)) {
1352*795d594fSAndroid Build Coastguard Worker // Type conversion is not necessary when storing to a field/element of the
1353*795d594fSAndroid Build Coastguard Worker // same/smaller size.
1354*795d594fSAndroid Build Coastguard Worker } else {
1355*795d594fSAndroid Build Coastguard Worker // We do not handle this case here.
1356*795d594fSAndroid Build Coastguard Worker return false;
1357*795d594fSAndroid Build Coastguard Worker }
1358*795d594fSAndroid Build Coastguard Worker
1359*795d594fSAndroid Build Coastguard Worker // Check if the converted value is only used for storing into heap.
1360*795d594fSAndroid Build Coastguard Worker for (const HUseListNode<HInstruction*>& use : type_conversion->GetUses()) {
1361*795d594fSAndroid Build Coastguard Worker HInstruction* instruction = use.GetUser();
1362*795d594fSAndroid Build Coastguard Worker if (instruction->IsInstanceFieldSet() &&
1363*795d594fSAndroid Build Coastguard Worker instruction->AsInstanceFieldSet()->GetFieldType() == result_type) {
1364*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(instruction->AsInstanceFieldSet()->GetValue(), type_conversion);
1365*795d594fSAndroid Build Coastguard Worker continue;
1366*795d594fSAndroid Build Coastguard Worker }
1367*795d594fSAndroid Build Coastguard Worker if (instruction->IsStaticFieldSet() &&
1368*795d594fSAndroid Build Coastguard Worker instruction->AsStaticFieldSet()->GetFieldType() == result_type) {
1369*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(instruction->AsStaticFieldSet()->GetValue(), type_conversion);
1370*795d594fSAndroid Build Coastguard Worker continue;
1371*795d594fSAndroid Build Coastguard Worker }
1372*795d594fSAndroid Build Coastguard Worker if (instruction->IsArraySet() &&
1373*795d594fSAndroid Build Coastguard Worker instruction->AsArraySet()->GetComponentType() == result_type &&
1374*795d594fSAndroid Build Coastguard Worker // not index use.
1375*795d594fSAndroid Build Coastguard Worker instruction->AsArraySet()->GetIndex() != type_conversion) {
1376*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(instruction->AsArraySet()->GetValue(), type_conversion);
1377*795d594fSAndroid Build Coastguard Worker continue;
1378*795d594fSAndroid Build Coastguard Worker }
1379*795d594fSAndroid Build Coastguard Worker // The use is not as a store value, or the field/element type is not the
1380*795d594fSAndroid Build Coastguard Worker // same as the result_type, keep the type conversion.
1381*795d594fSAndroid Build Coastguard Worker return false;
1382*795d594fSAndroid Build Coastguard Worker }
1383*795d594fSAndroid Build Coastguard Worker // Codegen automatically handles the type conversion during the store.
1384*795d594fSAndroid Build Coastguard Worker return true;
1385*795d594fSAndroid Build Coastguard Worker }
1386*795d594fSAndroid Build Coastguard Worker
VisitTypeConversion(HTypeConversion * instruction)1387*795d594fSAndroid Build Coastguard Worker void InstructionSimplifierVisitor::VisitTypeConversion(HTypeConversion* instruction) {
1388*795d594fSAndroid Build Coastguard Worker HInstruction* input = instruction->GetInput();
1389*795d594fSAndroid Build Coastguard Worker DataType::Type input_type = input->GetType();
1390*795d594fSAndroid Build Coastguard Worker DataType::Type result_type = instruction->GetResultType();
1391*795d594fSAndroid Build Coastguard Worker if (instruction->IsImplicitConversion()) {
1392*795d594fSAndroid Build Coastguard Worker instruction->ReplaceWith(input);
1393*795d594fSAndroid Build Coastguard Worker instruction->GetBlock()->RemoveInstruction(instruction);
1394*795d594fSAndroid Build Coastguard Worker RecordSimplification();
1395*795d594fSAndroid Build Coastguard Worker return;
1396*795d594fSAndroid Build Coastguard Worker }
1397*795d594fSAndroid Build Coastguard Worker
1398*795d594fSAndroid Build Coastguard Worker if (input->IsTypeConversion()) {
1399*795d594fSAndroid Build Coastguard Worker HTypeConversion* input_conversion = input->AsTypeConversion();
1400*795d594fSAndroid Build Coastguard Worker HInstruction* original_input = input_conversion->GetInput();
1401*795d594fSAndroid Build Coastguard Worker DataType::Type original_type = original_input->GetType();
1402*795d594fSAndroid Build Coastguard Worker
1403*795d594fSAndroid Build Coastguard Worker // When the first conversion is lossless, a direct conversion from the original type
1404*795d594fSAndroid Build Coastguard Worker // to the final type yields the same result, even for a lossy second conversion, for
1405*795d594fSAndroid Build Coastguard Worker // example float->double->int or int->double->float.
1406*795d594fSAndroid Build Coastguard Worker bool is_first_conversion_lossless = IsTypeConversionLossless(original_type, input_type);
1407*795d594fSAndroid Build Coastguard Worker
1408*795d594fSAndroid Build Coastguard Worker // For integral conversions, see if the first conversion loses only bits that the second
1409*795d594fSAndroid Build Coastguard Worker // doesn't need, i.e. the final type is no wider than the intermediate. If so, direct
1410*795d594fSAndroid Build Coastguard Worker // conversion yields the same result, for example long->int->short or int->char->short.
1411*795d594fSAndroid Build Coastguard Worker bool integral_conversions_with_non_widening_second =
1412*795d594fSAndroid Build Coastguard Worker DataType::IsIntegralType(input_type) &&
1413*795d594fSAndroid Build Coastguard Worker DataType::IsIntegralType(original_type) &&
1414*795d594fSAndroid Build Coastguard Worker DataType::IsIntegralType(result_type) &&
1415*795d594fSAndroid Build Coastguard Worker DataType::Size(result_type) <= DataType::Size(input_type);
1416*795d594fSAndroid Build Coastguard Worker
1417*795d594fSAndroid Build Coastguard Worker if (is_first_conversion_lossless || integral_conversions_with_non_widening_second) {
1418*795d594fSAndroid Build Coastguard Worker // If the merged conversion is implicit, do the simplification unconditionally.
1419*795d594fSAndroid Build Coastguard Worker if (DataType::IsTypeConversionImplicit(original_type, result_type)) {
1420*795d594fSAndroid Build Coastguard Worker instruction->ReplaceWith(original_input);
1421*795d594fSAndroid Build Coastguard Worker instruction->GetBlock()->RemoveInstruction(instruction);
1422*795d594fSAndroid Build Coastguard Worker if (!input_conversion->HasUses()) {
1423*795d594fSAndroid Build Coastguard Worker // Don't wait for DCE.
1424*795d594fSAndroid Build Coastguard Worker input_conversion->GetBlock()->RemoveInstruction(input_conversion);
1425*795d594fSAndroid Build Coastguard Worker }
1426*795d594fSAndroid Build Coastguard Worker RecordSimplification();
1427*795d594fSAndroid Build Coastguard Worker return;
1428*795d594fSAndroid Build Coastguard Worker }
1429*795d594fSAndroid Build Coastguard Worker // Otherwise simplify only if the first conversion has no other use.
1430*795d594fSAndroid Build Coastguard Worker if (input_conversion->HasOnlyOneNonEnvironmentUse()) {
1431*795d594fSAndroid Build Coastguard Worker input_conversion->ReplaceWith(original_input);
1432*795d594fSAndroid Build Coastguard Worker input_conversion->GetBlock()->RemoveInstruction(input_conversion);
1433*795d594fSAndroid Build Coastguard Worker RecordSimplification();
1434*795d594fSAndroid Build Coastguard Worker return;
1435*795d594fSAndroid Build Coastguard Worker }
1436*795d594fSAndroid Build Coastguard Worker }
1437*795d594fSAndroid Build Coastguard Worker } else if (input->IsShr() && DataType::IsIntegralType(result_type) &&
1438*795d594fSAndroid Build Coastguard Worker // Optimization only applies to lossy Type Conversions.
1439*795d594fSAndroid Build Coastguard Worker !IsTypeConversionLossless(input_type, result_type)) {
1440*795d594fSAndroid Build Coastguard Worker DCHECK(DataType::IsIntegralType(input_type));
1441*795d594fSAndroid Build Coastguard Worker HShr* shr_op = input->AsShr();
1442*795d594fSAndroid Build Coastguard Worker HConstant* shr_right = shr_op->GetConstantRight();
1443*795d594fSAndroid Build Coastguard Worker HInstruction* shr_left = shr_op->GetLeastConstantLeft();
1444*795d594fSAndroid Build Coastguard Worker if (shr_right != nullptr && shr_left->IsAnd()) {
1445*795d594fSAndroid Build Coastguard Worker // Optimization needs AND -> SHR -> TypeConversion pattern.
1446*795d594fSAndroid Build Coastguard Worker HAnd* and_op = shr_left->AsAnd();
1447*795d594fSAndroid Build Coastguard Worker HConstant* and_right = and_op->GetConstantRight();
1448*795d594fSAndroid Build Coastguard Worker HInstruction* and_left = and_op->GetLeastConstantLeft();
1449*795d594fSAndroid Build Coastguard Worker if (and_right != nullptr &&
1450*795d594fSAndroid Build Coastguard Worker !DataType::IsUnsignedType(and_left->GetType()) &&
1451*795d594fSAndroid Build Coastguard Worker !DataType::IsUnsignedType(result_type) &&
1452*795d594fSAndroid Build Coastguard Worker !DataType::IsUnsignedType(and_right->GetType()) &&
1453*795d594fSAndroid Build Coastguard Worker (DataType::Size(and_left->GetType()) < 8) &&
1454*795d594fSAndroid Build Coastguard Worker (DataType::Size(result_type) == 1)) {
1455*795d594fSAndroid Build Coastguard Worker // TODO: Support Unsigned Types.
1456*795d594fSAndroid Build Coastguard Worker // TODO: Support Long Types.
1457*795d594fSAndroid Build Coastguard Worker // TODO: Support result types other than byte.
1458*795d594fSAndroid Build Coastguard Worker if (and_op->HasOnlyOneNonEnvironmentUse() &&
1459*795d594fSAndroid Build Coastguard Worker CanRemoveRedundantAnd(and_right, shr_right, result_type)) {
1460*795d594fSAndroid Build Coastguard Worker and_op->ReplaceWith(and_left);
1461*795d594fSAndroid Build Coastguard Worker and_op->GetBlock()->RemoveInstruction(and_op);
1462*795d594fSAndroid Build Coastguard Worker RecordSimplification();
1463*795d594fSAndroid Build Coastguard Worker return;
1464*795d594fSAndroid Build Coastguard Worker }
1465*795d594fSAndroid Build Coastguard Worker }
1466*795d594fSAndroid Build Coastguard Worker }
1467*795d594fSAndroid Build Coastguard Worker } else if (input->IsAnd() && DataType::IsIntegralType(result_type)) {
1468*795d594fSAndroid Build Coastguard Worker DCHECK(DataType::IsIntegralType(input_type));
1469*795d594fSAndroid Build Coastguard Worker HAnd* input_and = input->AsAnd();
1470*795d594fSAndroid Build Coastguard Worker HConstant* constant = input_and->GetConstantRight();
1471*795d594fSAndroid Build Coastguard Worker if (constant != nullptr) {
1472*795d594fSAndroid Build Coastguard Worker int64_t value = Int64FromConstant(constant);
1473*795d594fSAndroid Build Coastguard Worker DCHECK_NE(value, -1); // "& -1" would have been optimized away in VisitAnd().
1474*795d594fSAndroid Build Coastguard Worker size_t trailing_ones = CTZ(~static_cast<uint64_t>(value));
1475*795d594fSAndroid Build Coastguard Worker if (trailing_ones >= kBitsPerByte * DataType::Size(result_type)) {
1476*795d594fSAndroid Build Coastguard Worker // The `HAnd` is useless, for example in `(byte) (x & 0xff)`, get rid of it.
1477*795d594fSAndroid Build Coastguard Worker HInstruction* original_input = input_and->GetLeastConstantLeft();
1478*795d594fSAndroid Build Coastguard Worker if (DataType::IsTypeConversionImplicit(original_input->GetType(), result_type)) {
1479*795d594fSAndroid Build Coastguard Worker instruction->ReplaceWith(original_input);
1480*795d594fSAndroid Build Coastguard Worker instruction->GetBlock()->RemoveInstruction(instruction);
1481*795d594fSAndroid Build Coastguard Worker RecordSimplification();
1482*795d594fSAndroid Build Coastguard Worker return;
1483*795d594fSAndroid Build Coastguard Worker } else if (input->HasOnlyOneNonEnvironmentUse()) {
1484*795d594fSAndroid Build Coastguard Worker input_and->ReplaceWith(original_input);
1485*795d594fSAndroid Build Coastguard Worker input_and->GetBlock()->RemoveInstruction(input_and);
1486*795d594fSAndroid Build Coastguard Worker RecordSimplification();
1487*795d594fSAndroid Build Coastguard Worker return;
1488*795d594fSAndroid Build Coastguard Worker }
1489*795d594fSAndroid Build Coastguard Worker }
1490*795d594fSAndroid Build Coastguard Worker }
1491*795d594fSAndroid Build Coastguard Worker } else if (input->HasOnlyOneNonEnvironmentUse() &&
1492*795d594fSAndroid Build Coastguard Worker ((input_type == DataType::Type::kInt8 && result_type == DataType::Type::kUint8) ||
1493*795d594fSAndroid Build Coastguard Worker (input_type == DataType::Type::kUint8 && result_type == DataType::Type::kInt8) ||
1494*795d594fSAndroid Build Coastguard Worker (input_type == DataType::Type::kInt16 && result_type == DataType::Type::kUint16) ||
1495*795d594fSAndroid Build Coastguard Worker (input_type == DataType::Type::kUint16 && result_type == DataType::Type::kInt16))) {
1496*795d594fSAndroid Build Coastguard Worker // Try to modify the type of the load to `result_type` and remove the explicit type conversion.
1497*795d594fSAndroid Build Coastguard Worker if (TryReplaceFieldOrArrayGetType(input, result_type)) {
1498*795d594fSAndroid Build Coastguard Worker instruction->ReplaceWith(input);
1499*795d594fSAndroid Build Coastguard Worker instruction->GetBlock()->RemoveInstruction(instruction);
1500*795d594fSAndroid Build Coastguard Worker RecordSimplification();
1501*795d594fSAndroid Build Coastguard Worker return;
1502*795d594fSAndroid Build Coastguard Worker }
1503*795d594fSAndroid Build Coastguard Worker }
1504*795d594fSAndroid Build Coastguard Worker
1505*795d594fSAndroid Build Coastguard Worker if (IsTypeConversionForStoringIntoNoWiderFieldOnly(instruction)) {
1506*795d594fSAndroid Build Coastguard Worker instruction->ReplaceWith(input);
1507*795d594fSAndroid Build Coastguard Worker instruction->GetBlock()->RemoveInstruction(instruction);
1508*795d594fSAndroid Build Coastguard Worker RecordSimplification();
1509*795d594fSAndroid Build Coastguard Worker return;
1510*795d594fSAndroid Build Coastguard Worker }
1511*795d594fSAndroid Build Coastguard Worker }
1512*795d594fSAndroid Build Coastguard Worker
VisitAbs(HAbs * instruction)1513*795d594fSAndroid Build Coastguard Worker void InstructionSimplifierVisitor::VisitAbs(HAbs* instruction) {
1514*795d594fSAndroid Build Coastguard Worker HInstruction* input = instruction->GetInput();
1515*795d594fSAndroid Build Coastguard Worker if (DataType::IsZeroExtension(input->GetType(), instruction->GetResultType())) {
1516*795d594fSAndroid Build Coastguard Worker // Zero extension from narrow to wide can never set sign bit in the wider
1517*795d594fSAndroid Build Coastguard Worker // operand, making the subsequent Abs redundant (e.g., abs(b & 0xff) for byte b).
1518*795d594fSAndroid Build Coastguard Worker instruction->ReplaceWith(input);
1519*795d594fSAndroid Build Coastguard Worker instruction->GetBlock()->RemoveInstruction(instruction);
1520*795d594fSAndroid Build Coastguard Worker RecordSimplification();
1521*795d594fSAndroid Build Coastguard Worker }
1522*795d594fSAndroid Build Coastguard Worker }
1523*795d594fSAndroid Build Coastguard Worker
VisitAdd(HAdd * instruction)1524*795d594fSAndroid Build Coastguard Worker void InstructionSimplifierVisitor::VisitAdd(HAdd* instruction) {
1525*795d594fSAndroid Build Coastguard Worker HConstant* input_cst = instruction->GetConstantRight();
1526*795d594fSAndroid Build Coastguard Worker HInstruction* input_other = instruction->GetLeastConstantLeft();
1527*795d594fSAndroid Build Coastguard Worker bool integral_type = DataType::IsIntegralType(instruction->GetType());
1528*795d594fSAndroid Build Coastguard Worker if ((input_cst != nullptr) && input_cst->IsArithmeticZero()) {
1529*795d594fSAndroid Build Coastguard Worker // Replace code looking like
1530*795d594fSAndroid Build Coastguard Worker // ADD dst, src, 0
1531*795d594fSAndroid Build Coastguard Worker // with
1532*795d594fSAndroid Build Coastguard Worker // src
1533*795d594fSAndroid Build Coastguard Worker // Note that we cannot optimize `x + 0.0` to `x` for floating-point. When
1534*795d594fSAndroid Build Coastguard Worker // `x` is `-0.0`, the former expression yields `0.0`, while the later
1535*795d594fSAndroid Build Coastguard Worker // yields `-0.0`.
1536*795d594fSAndroid Build Coastguard Worker if (integral_type) {
1537*795d594fSAndroid Build Coastguard Worker instruction->ReplaceWith(input_other);
1538*795d594fSAndroid Build Coastguard Worker instruction->GetBlock()->RemoveInstruction(instruction);
1539*795d594fSAndroid Build Coastguard Worker RecordSimplification();
1540*795d594fSAndroid Build Coastguard Worker return;
1541*795d594fSAndroid Build Coastguard Worker }
1542*795d594fSAndroid Build Coastguard Worker }
1543*795d594fSAndroid Build Coastguard Worker
1544*795d594fSAndroid Build Coastguard Worker HInstruction* left = instruction->GetLeft();
1545*795d594fSAndroid Build Coastguard Worker HInstruction* right = instruction->GetRight();
1546*795d594fSAndroid Build Coastguard Worker bool left_is_neg = left->IsNeg();
1547*795d594fSAndroid Build Coastguard Worker bool right_is_neg = right->IsNeg();
1548*795d594fSAndroid Build Coastguard Worker
1549*795d594fSAndroid Build Coastguard Worker if (left_is_neg && right_is_neg) {
1550*795d594fSAndroid Build Coastguard Worker if (TryMoveNegOnInputsAfterBinop(instruction)) {
1551*795d594fSAndroid Build Coastguard Worker return;
1552*795d594fSAndroid Build Coastguard Worker }
1553*795d594fSAndroid Build Coastguard Worker }
1554*795d594fSAndroid Build Coastguard Worker
1555*795d594fSAndroid Build Coastguard Worker if (left_is_neg != right_is_neg) {
1556*795d594fSAndroid Build Coastguard Worker HNeg* neg = left_is_neg ? left->AsNeg() : right->AsNeg();
1557*795d594fSAndroid Build Coastguard Worker if (neg->HasOnlyOneNonEnvironmentUse()) {
1558*795d594fSAndroid Build Coastguard Worker // Replace code looking like
1559*795d594fSAndroid Build Coastguard Worker // NEG tmp, b
1560*795d594fSAndroid Build Coastguard Worker // ADD dst, a, tmp
1561*795d594fSAndroid Build Coastguard Worker // with
1562*795d594fSAndroid Build Coastguard Worker // SUB dst, a, b
1563*795d594fSAndroid Build Coastguard Worker // We do not perform the optimization if the input negation has environment
1564*795d594fSAndroid Build Coastguard Worker // uses or multiple non-environment uses as it could lead to worse code. In
1565*795d594fSAndroid Build Coastguard Worker // particular, we do not want the live range of `b` to be extended if we are
1566*795d594fSAndroid Build Coastguard Worker // not sure the initial 'NEG' instruction can be removed.
1567*795d594fSAndroid Build Coastguard Worker HInstruction* other = left_is_neg ? right : left;
1568*795d594fSAndroid Build Coastguard Worker HSub* sub =
1569*795d594fSAndroid Build Coastguard Worker new(GetGraph()->GetAllocator()) HSub(instruction->GetType(), other, neg->GetInput());
1570*795d594fSAndroid Build Coastguard Worker instruction->GetBlock()->ReplaceAndRemoveInstructionWith(instruction, sub);
1571*795d594fSAndroid Build Coastguard Worker RecordSimplification();
1572*795d594fSAndroid Build Coastguard Worker neg->GetBlock()->RemoveInstruction(neg);
1573*795d594fSAndroid Build Coastguard Worker return;
1574*795d594fSAndroid Build Coastguard Worker }
1575*795d594fSAndroid Build Coastguard Worker }
1576*795d594fSAndroid Build Coastguard Worker
1577*795d594fSAndroid Build Coastguard Worker if (TryReplaceWithRotate(instruction)) {
1578*795d594fSAndroid Build Coastguard Worker return;
1579*795d594fSAndroid Build Coastguard Worker }
1580*795d594fSAndroid Build Coastguard Worker
1581*795d594fSAndroid Build Coastguard Worker // TryHandleAssociativeAndCommutativeOperation() does not remove its input,
1582*795d594fSAndroid Build Coastguard Worker // so no need to return.
1583*795d594fSAndroid Build Coastguard Worker TryHandleAssociativeAndCommutativeOperation(instruction);
1584*795d594fSAndroid Build Coastguard Worker
1585*795d594fSAndroid Build Coastguard Worker if ((left->IsSub() || right->IsSub()) &&
1586*795d594fSAndroid Build Coastguard Worker TrySubtractionChainSimplification(instruction)) {
1587*795d594fSAndroid Build Coastguard Worker return;
1588*795d594fSAndroid Build Coastguard Worker }
1589*795d594fSAndroid Build Coastguard Worker
1590*795d594fSAndroid Build Coastguard Worker if (integral_type) {
1591*795d594fSAndroid Build Coastguard Worker // Replace code patterns looking like
1592*795d594fSAndroid Build Coastguard Worker // SUB dst1, x, y SUB dst1, x, y
1593*795d594fSAndroid Build Coastguard Worker // ADD dst2, dst1, y ADD dst2, y, dst1
1594*795d594fSAndroid Build Coastguard Worker // with
1595*795d594fSAndroid Build Coastguard Worker // SUB dst1, x, y
1596*795d594fSAndroid Build Coastguard Worker // ADD instruction is not needed in this case, we may use
1597*795d594fSAndroid Build Coastguard Worker // one of inputs of SUB instead.
1598*795d594fSAndroid Build Coastguard Worker if (left->IsSub() && left->InputAt(1) == right) {
1599*795d594fSAndroid Build Coastguard Worker instruction->ReplaceWith(left->InputAt(0));
1600*795d594fSAndroid Build Coastguard Worker RecordSimplification();
1601*795d594fSAndroid Build Coastguard Worker instruction->GetBlock()->RemoveInstruction(instruction);
1602*795d594fSAndroid Build Coastguard Worker return;
1603*795d594fSAndroid Build Coastguard Worker } else if (right->IsSub() && right->InputAt(1) == left) {
1604*795d594fSAndroid Build Coastguard Worker instruction->ReplaceWith(right->InputAt(0));
1605*795d594fSAndroid Build Coastguard Worker RecordSimplification();
1606*795d594fSAndroid Build Coastguard Worker instruction->GetBlock()->RemoveInstruction(instruction);
1607*795d594fSAndroid Build Coastguard Worker return;
1608*795d594fSAndroid Build Coastguard Worker }
1609*795d594fSAndroid Build Coastguard Worker }
1610*795d594fSAndroid Build Coastguard Worker }
1611*795d594fSAndroid Build Coastguard Worker
VisitAnd(HAnd * instruction)1612*795d594fSAndroid Build Coastguard Worker void InstructionSimplifierVisitor::VisitAnd(HAnd* instruction) {
1613*795d594fSAndroid Build Coastguard Worker DCHECK(DataType::IsIntegralType(instruction->GetType()));
1614*795d594fSAndroid Build Coastguard Worker HConstant* input_cst = instruction->GetConstantRight();
1615*795d594fSAndroid Build Coastguard Worker HInstruction* input_other = instruction->GetLeastConstantLeft();
1616*795d594fSAndroid Build Coastguard Worker
1617*795d594fSAndroid Build Coastguard Worker if (input_cst != nullptr) {
1618*795d594fSAndroid Build Coastguard Worker int64_t value = Int64FromConstant(input_cst);
1619*795d594fSAndroid Build Coastguard Worker if (value == -1 ||
1620*795d594fSAndroid Build Coastguard Worker // Similar cases under zero extension.
1621*795d594fSAndroid Build Coastguard Worker (DataType::IsUnsignedType(input_other->GetType()) &&
1622*795d594fSAndroid Build Coastguard Worker ((DataType::MaxValueOfIntegralType(input_other->GetType()) & ~value) == 0))) {
1623*795d594fSAndroid Build Coastguard Worker // Replace code looking like
1624*795d594fSAndroid Build Coastguard Worker // AND dst, src, 0xFFF...FF
1625*795d594fSAndroid Build Coastguard Worker // with
1626*795d594fSAndroid Build Coastguard Worker // src
1627*795d594fSAndroid Build Coastguard Worker instruction->ReplaceWith(input_other);
1628*795d594fSAndroid Build Coastguard Worker instruction->GetBlock()->RemoveInstruction(instruction);
1629*795d594fSAndroid Build Coastguard Worker RecordSimplification();
1630*795d594fSAndroid Build Coastguard Worker return;
1631*795d594fSAndroid Build Coastguard Worker }
1632*795d594fSAndroid Build Coastguard Worker if (input_other->IsTypeConversion() &&
1633*795d594fSAndroid Build Coastguard Worker input_other->GetType() == DataType::Type::kInt64 &&
1634*795d594fSAndroid Build Coastguard Worker DataType::IsIntegralType(input_other->InputAt(0)->GetType()) &&
1635*795d594fSAndroid Build Coastguard Worker IsInt<32>(value) &&
1636*795d594fSAndroid Build Coastguard Worker input_other->HasOnlyOneNonEnvironmentUse()) {
1637*795d594fSAndroid Build Coastguard Worker // The AND can be reordered before the TypeConversion. Replace
1638*795d594fSAndroid Build Coastguard Worker // LongConstant cst, <32-bit-constant-sign-extended-to-64-bits>
1639*795d594fSAndroid Build Coastguard Worker // TypeConversion<Int64> tmp, src
1640*795d594fSAndroid Build Coastguard Worker // AND dst, tmp, cst
1641*795d594fSAndroid Build Coastguard Worker // with
1642*795d594fSAndroid Build Coastguard Worker // IntConstant cst, <32-bit-constant>
1643*795d594fSAndroid Build Coastguard Worker // AND tmp, src, cst
1644*795d594fSAndroid Build Coastguard Worker // TypeConversion<Int64> dst, tmp
1645*795d594fSAndroid Build Coastguard Worker // This helps 32-bit targets and does not hurt 64-bit targets.
1646*795d594fSAndroid Build Coastguard Worker // This also simplifies detection of other patterns, such as Uint8 loads.
1647*795d594fSAndroid Build Coastguard Worker HInstruction* new_and_input = input_other->InputAt(0);
1648*795d594fSAndroid Build Coastguard Worker // Implicit conversion Int64->Int64 would have been removed previously.
1649*795d594fSAndroid Build Coastguard Worker DCHECK_NE(new_and_input->GetType(), DataType::Type::kInt64);
1650*795d594fSAndroid Build Coastguard Worker HConstant* new_const = GetGraph()->GetConstant(DataType::Type::kInt32, value);
1651*795d594fSAndroid Build Coastguard Worker HAnd* new_and =
1652*795d594fSAndroid Build Coastguard Worker new (GetGraph()->GetAllocator()) HAnd(DataType::Type::kInt32, new_and_input, new_const);
1653*795d594fSAndroid Build Coastguard Worker instruction->GetBlock()->InsertInstructionBefore(new_and, instruction);
1654*795d594fSAndroid Build Coastguard Worker HTypeConversion* new_conversion =
1655*795d594fSAndroid Build Coastguard Worker new (GetGraph()->GetAllocator()) HTypeConversion(DataType::Type::kInt64, new_and);
1656*795d594fSAndroid Build Coastguard Worker instruction->GetBlock()->ReplaceAndRemoveInstructionWith(instruction, new_conversion);
1657*795d594fSAndroid Build Coastguard Worker input_other->GetBlock()->RemoveInstruction(input_other);
1658*795d594fSAndroid Build Coastguard Worker RecordSimplification();
1659*795d594fSAndroid Build Coastguard Worker // Try to process the new And now, do not wait for the next round of simplifications.
1660*795d594fSAndroid Build Coastguard Worker instruction = new_and;
1661*795d594fSAndroid Build Coastguard Worker input_other = new_and_input;
1662*795d594fSAndroid Build Coastguard Worker }
1663*795d594fSAndroid Build Coastguard Worker // Eliminate And from UShr+And if the And-mask contains all the bits that
1664*795d594fSAndroid Build Coastguard Worker // can be non-zero after UShr. Transform Shr+And to UShr if the And-mask
1665*795d594fSAndroid Build Coastguard Worker // precisely clears the shifted-in sign bits.
1666*795d594fSAndroid Build Coastguard Worker if ((input_other->IsUShr() || input_other->IsShr()) && input_other->InputAt(1)->IsConstant()) {
1667*795d594fSAndroid Build Coastguard Worker size_t reg_bits = (instruction->GetResultType() == DataType::Type::kInt64) ? 64 : 32;
1668*795d594fSAndroid Build Coastguard Worker size_t shift = Int64FromConstant(input_other->InputAt(1)->AsConstant()) & (reg_bits - 1);
1669*795d594fSAndroid Build Coastguard Worker size_t num_tail_bits_set = CTZ(value + 1);
1670*795d594fSAndroid Build Coastguard Worker if ((num_tail_bits_set >= reg_bits - shift) && input_other->IsUShr()) {
1671*795d594fSAndroid Build Coastguard Worker // This AND clears only bits known to be clear, for example "(x >>> 24) & 0xff".
1672*795d594fSAndroid Build Coastguard Worker instruction->ReplaceWith(input_other);
1673*795d594fSAndroid Build Coastguard Worker instruction->GetBlock()->RemoveInstruction(instruction);
1674*795d594fSAndroid Build Coastguard Worker RecordSimplification();
1675*795d594fSAndroid Build Coastguard Worker return;
1676*795d594fSAndroid Build Coastguard Worker } else if ((num_tail_bits_set == reg_bits - shift) && IsPowerOfTwo(value + 1) &&
1677*795d594fSAndroid Build Coastguard Worker input_other->HasOnlyOneNonEnvironmentUse()) {
1678*795d594fSAndroid Build Coastguard Worker DCHECK(input_other->IsShr()); // For UShr, we would have taken the branch above.
1679*795d594fSAndroid Build Coastguard Worker // Replace SHR+AND with USHR, for example "(x >> 24) & 0xff" -> "x >>> 24".
1680*795d594fSAndroid Build Coastguard Worker HUShr* ushr = new (GetGraph()->GetAllocator()) HUShr(instruction->GetType(),
1681*795d594fSAndroid Build Coastguard Worker input_other->InputAt(0),
1682*795d594fSAndroid Build Coastguard Worker input_other->InputAt(1),
1683*795d594fSAndroid Build Coastguard Worker input_other->GetDexPc());
1684*795d594fSAndroid Build Coastguard Worker instruction->GetBlock()->ReplaceAndRemoveInstructionWith(instruction, ushr);
1685*795d594fSAndroid Build Coastguard Worker input_other->GetBlock()->RemoveInstruction(input_other);
1686*795d594fSAndroid Build Coastguard Worker RecordSimplification();
1687*795d594fSAndroid Build Coastguard Worker return;
1688*795d594fSAndroid Build Coastguard Worker }
1689*795d594fSAndroid Build Coastguard Worker }
1690*795d594fSAndroid Build Coastguard Worker if ((value == 0xff || value == 0xffff) && instruction->GetType() != DataType::Type::kInt64) {
1691*795d594fSAndroid Build Coastguard Worker // Transform AND to a type conversion to Uint8/Uint16. If `input_other` is a field
1692*795d594fSAndroid Build Coastguard Worker // or array Get with only a single use, short-circuit the subsequent simplification
1693*795d594fSAndroid Build Coastguard Worker // of the Get+TypeConversion and change the Get's type to `new_type` instead.
1694*795d594fSAndroid Build Coastguard Worker DataType::Type new_type = (value == 0xff) ? DataType::Type::kUint8 : DataType::Type::kUint16;
1695*795d594fSAndroid Build Coastguard Worker DataType::Type find_type = (value == 0xff) ? DataType::Type::kInt8 : DataType::Type::kInt16;
1696*795d594fSAndroid Build Coastguard Worker if (input_other->GetType() == find_type &&
1697*795d594fSAndroid Build Coastguard Worker input_other->HasOnlyOneNonEnvironmentUse() &&
1698*795d594fSAndroid Build Coastguard Worker TryReplaceFieldOrArrayGetType(input_other, new_type)) {
1699*795d594fSAndroid Build Coastguard Worker instruction->ReplaceWith(input_other);
1700*795d594fSAndroid Build Coastguard Worker instruction->GetBlock()->RemoveInstruction(instruction);
1701*795d594fSAndroid Build Coastguard Worker } else if (DataType::IsTypeConversionImplicit(input_other->GetType(), new_type)) {
1702*795d594fSAndroid Build Coastguard Worker instruction->ReplaceWith(input_other);
1703*795d594fSAndroid Build Coastguard Worker instruction->GetBlock()->RemoveInstruction(instruction);
1704*795d594fSAndroid Build Coastguard Worker } else {
1705*795d594fSAndroid Build Coastguard Worker HTypeConversion* type_conversion = new (GetGraph()->GetAllocator()) HTypeConversion(
1706*795d594fSAndroid Build Coastguard Worker new_type, input_other, instruction->GetDexPc());
1707*795d594fSAndroid Build Coastguard Worker instruction->GetBlock()->ReplaceAndRemoveInstructionWith(instruction, type_conversion);
1708*795d594fSAndroid Build Coastguard Worker }
1709*795d594fSAndroid Build Coastguard Worker RecordSimplification();
1710*795d594fSAndroid Build Coastguard Worker return;
1711*795d594fSAndroid Build Coastguard Worker }
1712*795d594fSAndroid Build Coastguard Worker }
1713*795d594fSAndroid Build Coastguard Worker
1714*795d594fSAndroid Build Coastguard Worker // We assume that GVN has run before, so we only perform a pointer comparison.
1715*795d594fSAndroid Build Coastguard Worker // If for some reason the values are equal but the pointers are different, we
1716*795d594fSAndroid Build Coastguard Worker // are still correct and only miss an optimization opportunity.
1717*795d594fSAndroid Build Coastguard Worker if (instruction->GetLeft() == instruction->GetRight()) {
1718*795d594fSAndroid Build Coastguard Worker // Replace code looking like
1719*795d594fSAndroid Build Coastguard Worker // AND dst, src, src
1720*795d594fSAndroid Build Coastguard Worker // with
1721*795d594fSAndroid Build Coastguard Worker // src
1722*795d594fSAndroid Build Coastguard Worker instruction->ReplaceWith(instruction->GetLeft());
1723*795d594fSAndroid Build Coastguard Worker instruction->GetBlock()->RemoveInstruction(instruction);
1724*795d594fSAndroid Build Coastguard Worker RecordSimplification();
1725*795d594fSAndroid Build Coastguard Worker return;
1726*795d594fSAndroid Build Coastguard Worker }
1727*795d594fSAndroid Build Coastguard Worker
1728*795d594fSAndroid Build Coastguard Worker if (TryDeMorganNegationFactoring(instruction)) {
1729*795d594fSAndroid Build Coastguard Worker return;
1730*795d594fSAndroid Build Coastguard Worker }
1731*795d594fSAndroid Build Coastguard Worker
1732*795d594fSAndroid Build Coastguard Worker // TryHandleAssociativeAndCommutativeOperation() does not remove its input,
1733*795d594fSAndroid Build Coastguard Worker // so no need to return.
1734*795d594fSAndroid Build Coastguard Worker TryHandleAssociativeAndCommutativeOperation(instruction);
1735*795d594fSAndroid Build Coastguard Worker }
1736*795d594fSAndroid Build Coastguard Worker
VisitGreaterThan(HGreaterThan * condition)1737*795d594fSAndroid Build Coastguard Worker void InstructionSimplifierVisitor::VisitGreaterThan(HGreaterThan* condition) {
1738*795d594fSAndroid Build Coastguard Worker VisitCondition(condition);
1739*795d594fSAndroid Build Coastguard Worker }
1740*795d594fSAndroid Build Coastguard Worker
VisitGreaterThanOrEqual(HGreaterThanOrEqual * condition)1741*795d594fSAndroid Build Coastguard Worker void InstructionSimplifierVisitor::VisitGreaterThanOrEqual(HGreaterThanOrEqual* condition) {
1742*795d594fSAndroid Build Coastguard Worker VisitCondition(condition);
1743*795d594fSAndroid Build Coastguard Worker }
1744*795d594fSAndroid Build Coastguard Worker
VisitLessThan(HLessThan * condition)1745*795d594fSAndroid Build Coastguard Worker void InstructionSimplifierVisitor::VisitLessThan(HLessThan* condition) {
1746*795d594fSAndroid Build Coastguard Worker VisitCondition(condition);
1747*795d594fSAndroid Build Coastguard Worker }
1748*795d594fSAndroid Build Coastguard Worker
VisitLessThanOrEqual(HLessThanOrEqual * condition)1749*795d594fSAndroid Build Coastguard Worker void InstructionSimplifierVisitor::VisitLessThanOrEqual(HLessThanOrEqual* condition) {
1750*795d594fSAndroid Build Coastguard Worker VisitCondition(condition);
1751*795d594fSAndroid Build Coastguard Worker }
1752*795d594fSAndroid Build Coastguard Worker
VisitBelow(HBelow * condition)1753*795d594fSAndroid Build Coastguard Worker void InstructionSimplifierVisitor::VisitBelow(HBelow* condition) {
1754*795d594fSAndroid Build Coastguard Worker VisitCondition(condition);
1755*795d594fSAndroid Build Coastguard Worker }
1756*795d594fSAndroid Build Coastguard Worker
VisitBelowOrEqual(HBelowOrEqual * condition)1757*795d594fSAndroid Build Coastguard Worker void InstructionSimplifierVisitor::VisitBelowOrEqual(HBelowOrEqual* condition) {
1758*795d594fSAndroid Build Coastguard Worker VisitCondition(condition);
1759*795d594fSAndroid Build Coastguard Worker }
1760*795d594fSAndroid Build Coastguard Worker
VisitAbove(HAbove * condition)1761*795d594fSAndroid Build Coastguard Worker void InstructionSimplifierVisitor::VisitAbove(HAbove* condition) {
1762*795d594fSAndroid Build Coastguard Worker VisitCondition(condition);
1763*795d594fSAndroid Build Coastguard Worker }
1764*795d594fSAndroid Build Coastguard Worker
VisitAboveOrEqual(HAboveOrEqual * condition)1765*795d594fSAndroid Build Coastguard Worker void InstructionSimplifierVisitor::VisitAboveOrEqual(HAboveOrEqual* condition) {
1766*795d594fSAndroid Build Coastguard Worker VisitCondition(condition);
1767*795d594fSAndroid Build Coastguard Worker }
1768*795d594fSAndroid Build Coastguard Worker
1769*795d594fSAndroid Build Coastguard Worker // Recognize the following pattern:
1770*795d594fSAndroid Build Coastguard Worker // obj.getClass() ==/!= Foo.class
1771*795d594fSAndroid Build Coastguard Worker // And replace it with a constant value if the type of `obj` is statically known.
RecognizeAndSimplifyClassCheck(HCondition * condition)1772*795d594fSAndroid Build Coastguard Worker static bool RecognizeAndSimplifyClassCheck(HCondition* condition) {
1773*795d594fSAndroid Build Coastguard Worker HInstruction* input_one = condition->InputAt(0);
1774*795d594fSAndroid Build Coastguard Worker HInstruction* input_two = condition->InputAt(1);
1775*795d594fSAndroid Build Coastguard Worker HLoadClass* load_class = input_one->IsLoadClass()
1776*795d594fSAndroid Build Coastguard Worker ? input_one->AsLoadClass()
1777*795d594fSAndroid Build Coastguard Worker : input_two->AsLoadClassOrNull();
1778*795d594fSAndroid Build Coastguard Worker if (load_class == nullptr) {
1779*795d594fSAndroid Build Coastguard Worker return false;
1780*795d594fSAndroid Build Coastguard Worker }
1781*795d594fSAndroid Build Coastguard Worker
1782*795d594fSAndroid Build Coastguard Worker ReferenceTypeInfo class_rti = load_class->GetLoadedClassRTI();
1783*795d594fSAndroid Build Coastguard Worker if (!class_rti.IsValid()) {
1784*795d594fSAndroid Build Coastguard Worker // Unresolved class.
1785*795d594fSAndroid Build Coastguard Worker return false;
1786*795d594fSAndroid Build Coastguard Worker }
1787*795d594fSAndroid Build Coastguard Worker
1788*795d594fSAndroid Build Coastguard Worker HInstanceFieldGet* field_get = (load_class == input_one)
1789*795d594fSAndroid Build Coastguard Worker ? input_two->AsInstanceFieldGetOrNull()
1790*795d594fSAndroid Build Coastguard Worker : input_one->AsInstanceFieldGetOrNull();
1791*795d594fSAndroid Build Coastguard Worker if (field_get == nullptr) {
1792*795d594fSAndroid Build Coastguard Worker return false;
1793*795d594fSAndroid Build Coastguard Worker }
1794*795d594fSAndroid Build Coastguard Worker
1795*795d594fSAndroid Build Coastguard Worker HInstruction* receiver = field_get->InputAt(0);
1796*795d594fSAndroid Build Coastguard Worker ReferenceTypeInfo receiver_type = receiver->GetReferenceTypeInfo();
1797*795d594fSAndroid Build Coastguard Worker if (!receiver_type.IsExact()) {
1798*795d594fSAndroid Build Coastguard Worker return false;
1799*795d594fSAndroid Build Coastguard Worker }
1800*795d594fSAndroid Build Coastguard Worker
1801*795d594fSAndroid Build Coastguard Worker {
1802*795d594fSAndroid Build Coastguard Worker ScopedObjectAccess soa(Thread::Current());
1803*795d594fSAndroid Build Coastguard Worker ArtField* field = GetClassRoot<mirror::Object>()->GetInstanceField(0);
1804*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(std::string(field->GetName()), "shadow$_klass_");
1805*795d594fSAndroid Build Coastguard Worker if (field_get->GetFieldInfo().GetField() != field) {
1806*795d594fSAndroid Build Coastguard Worker return false;
1807*795d594fSAndroid Build Coastguard Worker }
1808*795d594fSAndroid Build Coastguard Worker
1809*795d594fSAndroid Build Coastguard Worker // We can replace the compare.
1810*795d594fSAndroid Build Coastguard Worker int value = 0;
1811*795d594fSAndroid Build Coastguard Worker if (receiver_type.IsEqual(class_rti)) {
1812*795d594fSAndroid Build Coastguard Worker value = condition->IsEqual() ? 1 : 0;
1813*795d594fSAndroid Build Coastguard Worker } else {
1814*795d594fSAndroid Build Coastguard Worker value = condition->IsNotEqual() ? 1 : 0;
1815*795d594fSAndroid Build Coastguard Worker }
1816*795d594fSAndroid Build Coastguard Worker condition->ReplaceWith(condition->GetBlock()->GetGraph()->GetIntConstant(value));
1817*795d594fSAndroid Build Coastguard Worker return true;
1818*795d594fSAndroid Build Coastguard Worker }
1819*795d594fSAndroid Build Coastguard Worker }
1820*795d594fSAndroid Build Coastguard Worker
CreateUnsignedConditionReplacement(ArenaAllocator * allocator,HCondition * cond,HCompare * compare)1821*795d594fSAndroid Build Coastguard Worker static HInstruction* CreateUnsignedConditionReplacement(ArenaAllocator* allocator,
1822*795d594fSAndroid Build Coastguard Worker HCondition* cond,
1823*795d594fSAndroid Build Coastguard Worker HCompare* compare) {
1824*795d594fSAndroid Build Coastguard Worker DCHECK(cond->InputAt(1)->IsIntConstant());
1825*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(cond->InputAt(1)->AsIntConstant()->GetValue(), 0);
1826*795d594fSAndroid Build Coastguard Worker DCHECK(cond->InputAt(0) == compare);
1827*795d594fSAndroid Build Coastguard Worker
1828*795d594fSAndroid Build Coastguard Worker HBasicBlock* block = cond->GetBlock();
1829*795d594fSAndroid Build Coastguard Worker HInstruction* lhs = compare->InputAt(0);
1830*795d594fSAndroid Build Coastguard Worker HInstruction* rhs = compare->InputAt(1);
1831*795d594fSAndroid Build Coastguard Worker
1832*795d594fSAndroid Build Coastguard Worker switch (cond->GetKind()) {
1833*795d594fSAndroid Build Coastguard Worker case HInstruction::kLessThan:
1834*795d594fSAndroid Build Coastguard Worker return new (allocator) HBelow(lhs, rhs, cond->GetDexPc());
1835*795d594fSAndroid Build Coastguard Worker case HInstruction::kLessThanOrEqual:
1836*795d594fSAndroid Build Coastguard Worker return new (allocator) HBelowOrEqual(lhs, rhs, cond->GetDexPc());
1837*795d594fSAndroid Build Coastguard Worker case HInstruction::kGreaterThan:
1838*795d594fSAndroid Build Coastguard Worker return new (allocator) HAbove(lhs, rhs, cond->GetDexPc());
1839*795d594fSAndroid Build Coastguard Worker case HInstruction::kGreaterThanOrEqual:
1840*795d594fSAndroid Build Coastguard Worker return new (allocator) HAboveOrEqual(lhs, rhs, cond->GetDexPc());
1841*795d594fSAndroid Build Coastguard Worker case HInstruction::kBelow:
1842*795d594fSAndroid Build Coastguard Worker // Below(Compare(x, y), 0) always False since
1843*795d594fSAndroid Build Coastguard Worker // unsigned(-1) < 0 -> False
1844*795d594fSAndroid Build Coastguard Worker // 0 < 0 -> False
1845*795d594fSAndroid Build Coastguard Worker // 1 < 0 -> False
1846*795d594fSAndroid Build Coastguard Worker return block->GetGraph()->GetConstant(DataType::Type::kBool, 0);
1847*795d594fSAndroid Build Coastguard Worker case HInstruction::kBelowOrEqual:
1848*795d594fSAndroid Build Coastguard Worker // BelowOrEqual(Compare(x, y), 0) transforms into Equal(x, y)
1849*795d594fSAndroid Build Coastguard Worker // unsigned(-1) <= 0 -> False
1850*795d594fSAndroid Build Coastguard Worker // 0 <= 0 -> True
1851*795d594fSAndroid Build Coastguard Worker // 1 <= 0 -> False
1852*795d594fSAndroid Build Coastguard Worker return new (allocator) HEqual(lhs, rhs, cond->GetDexPc());
1853*795d594fSAndroid Build Coastguard Worker case HInstruction::kAbove:
1854*795d594fSAndroid Build Coastguard Worker // Above(Compare(x, y), 0) transforms into NotEqual(x, y)
1855*795d594fSAndroid Build Coastguard Worker // unsigned(-1) > 0 -> True
1856*795d594fSAndroid Build Coastguard Worker // 0 > 0 -> False
1857*795d594fSAndroid Build Coastguard Worker // 1 > 0 -> True
1858*795d594fSAndroid Build Coastguard Worker return new (allocator) HNotEqual(lhs, rhs, cond->GetDexPc());
1859*795d594fSAndroid Build Coastguard Worker case HInstruction::kAboveOrEqual:
1860*795d594fSAndroid Build Coastguard Worker // AboveOrEqual(Compare(x, y), 0) always True since
1861*795d594fSAndroid Build Coastguard Worker // unsigned(-1) >= 0 -> True
1862*795d594fSAndroid Build Coastguard Worker // 0 >= 0 -> True
1863*795d594fSAndroid Build Coastguard Worker // 1 >= 0 -> True
1864*795d594fSAndroid Build Coastguard Worker return block->GetGraph()->GetConstant(DataType::Type::kBool, 1);
1865*795d594fSAndroid Build Coastguard Worker default:
1866*795d594fSAndroid Build Coastguard Worker LOG(FATAL) << "Unknown ConditionType " << cond->GetKind();
1867*795d594fSAndroid Build Coastguard Worker UNREACHABLE();
1868*795d594fSAndroid Build Coastguard Worker }
1869*795d594fSAndroid Build Coastguard Worker }
1870*795d594fSAndroid Build Coastguard Worker
VisitCondition(HCondition * condition)1871*795d594fSAndroid Build Coastguard Worker void InstructionSimplifierVisitor::VisitCondition(HCondition* condition) {
1872*795d594fSAndroid Build Coastguard Worker if (condition->IsEqual() || condition->IsNotEqual()) {
1873*795d594fSAndroid Build Coastguard Worker if (RecognizeAndSimplifyClassCheck(condition)) {
1874*795d594fSAndroid Build Coastguard Worker return;
1875*795d594fSAndroid Build Coastguard Worker }
1876*795d594fSAndroid Build Coastguard Worker }
1877*795d594fSAndroid Build Coastguard Worker
1878*795d594fSAndroid Build Coastguard Worker // Reverse condition if left is constant. Our code generators prefer constant
1879*795d594fSAndroid Build Coastguard Worker // on the right hand side.
1880*795d594fSAndroid Build Coastguard Worker HBasicBlock* block = condition->GetBlock();
1881*795d594fSAndroid Build Coastguard Worker HInstruction* left = condition->GetLeft();
1882*795d594fSAndroid Build Coastguard Worker HInstruction* right = condition->GetRight();
1883*795d594fSAndroid Build Coastguard Worker if (left->IsConstant() && !right->IsConstant()) {
1884*795d594fSAndroid Build Coastguard Worker IfCondition new_cond = GetOppositeConditionForOperandSwap(condition->GetCondition());
1885*795d594fSAndroid Build Coastguard Worker HCondition* replacement = HCondition::Create(GetGraph(), new_cond, right, left);
1886*795d594fSAndroid Build Coastguard Worker block->ReplaceAndRemoveInstructionWith(condition, replacement);
1887*795d594fSAndroid Build Coastguard Worker // If it is a FP condition, we must set the opposite bias.
1888*795d594fSAndroid Build Coastguard Worker if (condition->IsLtBias()) {
1889*795d594fSAndroid Build Coastguard Worker replacement->SetBias(ComparisonBias::kGtBias);
1890*795d594fSAndroid Build Coastguard Worker } else if (condition->IsGtBias()) {
1891*795d594fSAndroid Build Coastguard Worker replacement->SetBias(ComparisonBias::kLtBias);
1892*795d594fSAndroid Build Coastguard Worker }
1893*795d594fSAndroid Build Coastguard Worker RecordSimplification();
1894*795d594fSAndroid Build Coastguard Worker condition = replacement;
1895*795d594fSAndroid Build Coastguard Worker std::swap(left, right);
1896*795d594fSAndroid Build Coastguard Worker }
1897*795d594fSAndroid Build Coastguard Worker
1898*795d594fSAndroid Build Coastguard Worker // Try to fold an HCompare into this HCondition.
1899*795d594fSAndroid Build Coastguard Worker
1900*795d594fSAndroid Build Coastguard Worker // We can only replace an HCondition which compares a Compare to 0.
1901*795d594fSAndroid Build Coastguard Worker // Both 'dx' and 'jack' generate a compare to 0 when compiling a
1902*795d594fSAndroid Build Coastguard Worker // condition with a long, float or double comparison as input.
1903*795d594fSAndroid Build Coastguard Worker if (!left->IsCompare() || !right->IsConstant() || right->AsIntConstant()->GetValue() != 0) {
1904*795d594fSAndroid Build Coastguard Worker // Conversion is not possible.
1905*795d594fSAndroid Build Coastguard Worker return;
1906*795d594fSAndroid Build Coastguard Worker }
1907*795d594fSAndroid Build Coastguard Worker
1908*795d594fSAndroid Build Coastguard Worker // Is the Compare only used for this purpose?
1909*795d594fSAndroid Build Coastguard Worker if (!left->GetUses().HasExactlyOneElement()) {
1910*795d594fSAndroid Build Coastguard Worker // Someone else also wants the result of the compare.
1911*795d594fSAndroid Build Coastguard Worker return;
1912*795d594fSAndroid Build Coastguard Worker }
1913*795d594fSAndroid Build Coastguard Worker
1914*795d594fSAndroid Build Coastguard Worker if (!left->GetEnvUses().empty()) {
1915*795d594fSAndroid Build Coastguard Worker // There is a reference to the compare result in an environment. Do we really need it?
1916*795d594fSAndroid Build Coastguard Worker if (GetGraph()->IsDebuggable()) {
1917*795d594fSAndroid Build Coastguard Worker return;
1918*795d594fSAndroid Build Coastguard Worker }
1919*795d594fSAndroid Build Coastguard Worker
1920*795d594fSAndroid Build Coastguard Worker // We have to ensure that there are no deopt points in the sequence.
1921*795d594fSAndroid Build Coastguard Worker if (left->HasAnyEnvironmentUseBefore(condition)) {
1922*795d594fSAndroid Build Coastguard Worker return;
1923*795d594fSAndroid Build Coastguard Worker }
1924*795d594fSAndroid Build Coastguard Worker }
1925*795d594fSAndroid Build Coastguard Worker
1926*795d594fSAndroid Build Coastguard Worker // Clean up any environment uses from the HCompare, if any.
1927*795d594fSAndroid Build Coastguard Worker left->RemoveEnvironmentUsers();
1928*795d594fSAndroid Build Coastguard Worker
1929*795d594fSAndroid Build Coastguard Worker // We have decided to fold the HCompare into the HCondition. Transfer the information.
1930*795d594fSAndroid Build Coastguard Worker if (DataType::IsUnsignedType(left->AsCompare()->GetComparisonType()) &&
1931*795d594fSAndroid Build Coastguard Worker !condition->IsEqual() &&
1932*795d594fSAndroid Build Coastguard Worker !condition->IsNotEqual()) {
1933*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(condition->GetBias(), ComparisonBias::kNoBias);
1934*795d594fSAndroid Build Coastguard Worker HInstruction* replacement = CreateUnsignedConditionReplacement(
1935*795d594fSAndroid Build Coastguard Worker block->GetGraph()->GetAllocator(), condition, left->AsCompare());
1936*795d594fSAndroid Build Coastguard Worker
1937*795d594fSAndroid Build Coastguard Worker if (replacement->IsConstant()) {
1938*795d594fSAndroid Build Coastguard Worker condition->ReplaceWith(replacement);
1939*795d594fSAndroid Build Coastguard Worker block->RemoveInstruction(condition);
1940*795d594fSAndroid Build Coastguard Worker } else {
1941*795d594fSAndroid Build Coastguard Worker block->ReplaceAndRemoveInstructionWith(condition, replacement);
1942*795d594fSAndroid Build Coastguard Worker }
1943*795d594fSAndroid Build Coastguard Worker } else {
1944*795d594fSAndroid Build Coastguard Worker condition->SetBias(left->AsCompare()->GetBias());
1945*795d594fSAndroid Build Coastguard Worker
1946*795d594fSAndroid Build Coastguard Worker // Replace the operands of the HCondition.
1947*795d594fSAndroid Build Coastguard Worker condition->ReplaceInput(left->InputAt(0), 0);
1948*795d594fSAndroid Build Coastguard Worker condition->ReplaceInput(left->InputAt(1), 1);
1949*795d594fSAndroid Build Coastguard Worker }
1950*795d594fSAndroid Build Coastguard Worker
1951*795d594fSAndroid Build Coastguard Worker // Remove the HCompare.
1952*795d594fSAndroid Build Coastguard Worker left->GetBlock()->RemoveInstruction(left);
1953*795d594fSAndroid Build Coastguard Worker
1954*795d594fSAndroid Build Coastguard Worker RecordSimplification();
1955*795d594fSAndroid Build Coastguard Worker }
1956*795d594fSAndroid Build Coastguard Worker
CheckSignedToUnsignedCompareConversion(HInstruction * operand,HCompare * compare)1957*795d594fSAndroid Build Coastguard Worker static HInstruction* CheckSignedToUnsignedCompareConversion(HInstruction* operand,
1958*795d594fSAndroid Build Coastguard Worker HCompare* compare) {
1959*795d594fSAndroid Build Coastguard Worker // Check if operand looks like `ADD op, MIN_INTEGRAL`
1960*795d594fSAndroid Build Coastguard Worker if (operand->IsConstant()) {
1961*795d594fSAndroid Build Coastguard Worker // CONSTANT #x -> CONSTANT #(x - MIN_INTEGRAL)
1962*795d594fSAndroid Build Coastguard Worker HConstant* constant = operand->AsConstant();
1963*795d594fSAndroid Build Coastguard Worker if (constant->IsIntConstant()) {
1964*795d594fSAndroid Build Coastguard Worker HIntConstant* int_constant = constant->AsIntConstant();
1965*795d594fSAndroid Build Coastguard Worker int32_t old_value = int_constant->GetValue();
1966*795d594fSAndroid Build Coastguard Worker int32_t new_value = old_value - std::numeric_limits<int32_t>::min();
1967*795d594fSAndroid Build Coastguard Worker return operand->GetBlock()->GetGraph()->GetIntConstant(new_value);
1968*795d594fSAndroid Build Coastguard Worker } else if (constant->IsLongConstant()) {
1969*795d594fSAndroid Build Coastguard Worker HLongConstant* long_constant = constant->AsLongConstant();
1970*795d594fSAndroid Build Coastguard Worker int64_t old_value = long_constant->GetValue();
1971*795d594fSAndroid Build Coastguard Worker int64_t new_value = old_value - std::numeric_limits<int64_t>::min();
1972*795d594fSAndroid Build Coastguard Worker return operand->GetBlock()->GetGraph()->GetLongConstant(new_value);
1973*795d594fSAndroid Build Coastguard Worker } else {
1974*795d594fSAndroid Build Coastguard Worker return nullptr;
1975*795d594fSAndroid Build Coastguard Worker }
1976*795d594fSAndroid Build Coastguard Worker }
1977*795d594fSAndroid Build Coastguard Worker
1978*795d594fSAndroid Build Coastguard Worker if (!operand->IsAdd() && !operand->IsXor()) {
1979*795d594fSAndroid Build Coastguard Worker return nullptr;
1980*795d594fSAndroid Build Coastguard Worker }
1981*795d594fSAndroid Build Coastguard Worker
1982*795d594fSAndroid Build Coastguard Worker if (!operand->GetEnvUses().empty()) {
1983*795d594fSAndroid Build Coastguard Worker // There is a reference to the compare result in an environment. Do we really need it?
1984*795d594fSAndroid Build Coastguard Worker if (operand->GetBlock()->GetGraph()->IsDebuggable()) {
1985*795d594fSAndroid Build Coastguard Worker return nullptr;
1986*795d594fSAndroid Build Coastguard Worker }
1987*795d594fSAndroid Build Coastguard Worker
1988*795d594fSAndroid Build Coastguard Worker // We have to ensure that there are no deopt points in the sequence.
1989*795d594fSAndroid Build Coastguard Worker if (operand->HasAnyEnvironmentUseBefore(compare)) {
1990*795d594fSAndroid Build Coastguard Worker return nullptr;
1991*795d594fSAndroid Build Coastguard Worker }
1992*795d594fSAndroid Build Coastguard Worker }
1993*795d594fSAndroid Build Coastguard Worker
1994*795d594fSAndroid Build Coastguard Worker HBinaryOperation* additive_operand = operand->AsBinaryOperation();
1995*795d594fSAndroid Build Coastguard Worker
1996*795d594fSAndroid Build Coastguard Worker HInstruction* left = additive_operand->GetLeft();
1997*795d594fSAndroid Build Coastguard Worker HInstruction* right = additive_operand->GetRight();
1998*795d594fSAndroid Build Coastguard Worker
1999*795d594fSAndroid Build Coastguard Worker HConstant* constant = nullptr;
2000*795d594fSAndroid Build Coastguard Worker HInstruction* value = nullptr;
2001*795d594fSAndroid Build Coastguard Worker
2002*795d594fSAndroid Build Coastguard Worker if (left->IsConstant() && !right->IsConstant()) {
2003*795d594fSAndroid Build Coastguard Worker constant = left->AsConstant();
2004*795d594fSAndroid Build Coastguard Worker value = right;
2005*795d594fSAndroid Build Coastguard Worker } else if (!left->IsConstant() && right->IsConstant()) {
2006*795d594fSAndroid Build Coastguard Worker value = left;
2007*795d594fSAndroid Build Coastguard Worker constant = right->AsConstant();
2008*795d594fSAndroid Build Coastguard Worker } else {
2009*795d594fSAndroid Build Coastguard Worker return nullptr;
2010*795d594fSAndroid Build Coastguard Worker }
2011*795d594fSAndroid Build Coastguard Worker
2012*795d594fSAndroid Build Coastguard Worker if (constant->IsIntConstant()) {
2013*795d594fSAndroid Build Coastguard Worker HIntConstant* int_constant = constant->AsIntConstant();
2014*795d594fSAndroid Build Coastguard Worker if (int_constant->GetValue() != std::numeric_limits<int32_t>::min()) {
2015*795d594fSAndroid Build Coastguard Worker return nullptr;
2016*795d594fSAndroid Build Coastguard Worker }
2017*795d594fSAndroid Build Coastguard Worker } else if (constant->IsLongConstant()) {
2018*795d594fSAndroid Build Coastguard Worker HLongConstant* long_constant = constant->AsLongConstant();
2019*795d594fSAndroid Build Coastguard Worker if (long_constant->GetValue() != std::numeric_limits<int64_t>::min()) {
2020*795d594fSAndroid Build Coastguard Worker return nullptr;
2021*795d594fSAndroid Build Coastguard Worker }
2022*795d594fSAndroid Build Coastguard Worker } else {
2023*795d594fSAndroid Build Coastguard Worker return nullptr;
2024*795d594fSAndroid Build Coastguard Worker }
2025*795d594fSAndroid Build Coastguard Worker
2026*795d594fSAndroid Build Coastguard Worker return value;
2027*795d594fSAndroid Build Coastguard Worker }
2028*795d594fSAndroid Build Coastguard Worker
GetOpositeSignType(DataType::Type type)2029*795d594fSAndroid Build Coastguard Worker static DataType::Type GetOpositeSignType(DataType::Type type) {
2030*795d594fSAndroid Build Coastguard Worker return DataType::IsUnsignedType(type) ? DataType::ToSigned(type) : DataType::ToUnsigned(type);
2031*795d594fSAndroid Build Coastguard Worker }
2032*795d594fSAndroid Build Coastguard Worker
VisitCompare(HCompare * compare)2033*795d594fSAndroid Build Coastguard Worker void InstructionSimplifierVisitor::VisitCompare(HCompare* compare) {
2034*795d594fSAndroid Build Coastguard Worker // Transform signed compare into unsigned if possible
2035*795d594fSAndroid Build Coastguard Worker // Replace code looking like
2036*795d594fSAndroid Build Coastguard Worker // ADD normalizedLeft, left, MIN_INTEGRAL
2037*795d594fSAndroid Build Coastguard Worker // ADD normalizedRight, right, MIN_INTEGRAL
2038*795d594fSAndroid Build Coastguard Worker // COMPARE normalizedLeft, normalizedRight, sign
2039*795d594fSAndroid Build Coastguard Worker // with
2040*795d594fSAndroid Build Coastguard Worker // COMPARE left, right, !sign
2041*795d594fSAndroid Build Coastguard Worker
2042*795d594fSAndroid Build Coastguard Worker if (!DataType::IsIntegralType(compare->GetComparisonType())) {
2043*795d594fSAndroid Build Coastguard Worker return;
2044*795d594fSAndroid Build Coastguard Worker }
2045*795d594fSAndroid Build Coastguard Worker
2046*795d594fSAndroid Build Coastguard Worker HInstruction* compare_left = compare->GetLeft();
2047*795d594fSAndroid Build Coastguard Worker HInstruction* compare_right = compare->GetRight();
2048*795d594fSAndroid Build Coastguard Worker
2049*795d594fSAndroid Build Coastguard Worker if (compare_left->IsConstant() && compare_right->IsConstant()) {
2050*795d594fSAndroid Build Coastguard Worker // Do not simplify, let it be folded.
2051*795d594fSAndroid Build Coastguard Worker return;
2052*795d594fSAndroid Build Coastguard Worker }
2053*795d594fSAndroid Build Coastguard Worker
2054*795d594fSAndroid Build Coastguard Worker HInstruction* left = CheckSignedToUnsignedCompareConversion(compare_left, compare);
2055*795d594fSAndroid Build Coastguard Worker if (left == nullptr) {
2056*795d594fSAndroid Build Coastguard Worker return;
2057*795d594fSAndroid Build Coastguard Worker }
2058*795d594fSAndroid Build Coastguard Worker
2059*795d594fSAndroid Build Coastguard Worker HInstruction* right = CheckSignedToUnsignedCompareConversion(compare_right, compare);
2060*795d594fSAndroid Build Coastguard Worker if (right == nullptr) {
2061*795d594fSAndroid Build Coastguard Worker return;
2062*795d594fSAndroid Build Coastguard Worker }
2063*795d594fSAndroid Build Coastguard Worker
2064*795d594fSAndroid Build Coastguard Worker compare->SetComparisonType(GetOpositeSignType(compare->GetComparisonType()));
2065*795d594fSAndroid Build Coastguard Worker compare->ReplaceInput(left, 0);
2066*795d594fSAndroid Build Coastguard Worker compare->ReplaceInput(right, 1);
2067*795d594fSAndroid Build Coastguard Worker
2068*795d594fSAndroid Build Coastguard Worker RecordSimplification();
2069*795d594fSAndroid Build Coastguard Worker
2070*795d594fSAndroid Build Coastguard Worker if (compare_left->GetUses().empty()) {
2071*795d594fSAndroid Build Coastguard Worker compare_left->RemoveEnvironmentUsers();
2072*795d594fSAndroid Build Coastguard Worker compare_left->GetBlock()->RemoveInstruction(compare_left);
2073*795d594fSAndroid Build Coastguard Worker }
2074*795d594fSAndroid Build Coastguard Worker
2075*795d594fSAndroid Build Coastguard Worker if (compare_right->GetUses().empty()) {
2076*795d594fSAndroid Build Coastguard Worker compare_right->RemoveEnvironmentUsers();
2077*795d594fSAndroid Build Coastguard Worker compare_right->GetBlock()->RemoveInstruction(compare_right);
2078*795d594fSAndroid Build Coastguard Worker }
2079*795d594fSAndroid Build Coastguard Worker }
2080*795d594fSAndroid Build Coastguard Worker
2081*795d594fSAndroid Build Coastguard Worker // Return whether x / divisor == x * (1.0f / divisor), for every float x.
CanDivideByReciprocalMultiplyFloat(int32_t divisor)2082*795d594fSAndroid Build Coastguard Worker static constexpr bool CanDivideByReciprocalMultiplyFloat(int32_t divisor) {
2083*795d594fSAndroid Build Coastguard Worker // True, if the most significant bits of divisor are 0.
2084*795d594fSAndroid Build Coastguard Worker return ((divisor & 0x7fffff) == 0);
2085*795d594fSAndroid Build Coastguard Worker }
2086*795d594fSAndroid Build Coastguard Worker
2087*795d594fSAndroid Build Coastguard Worker // Return whether x / divisor == x * (1.0 / divisor), for every double x.
CanDivideByReciprocalMultiplyDouble(int64_t divisor)2088*795d594fSAndroid Build Coastguard Worker static constexpr bool CanDivideByReciprocalMultiplyDouble(int64_t divisor) {
2089*795d594fSAndroid Build Coastguard Worker // True, if the most significant bits of divisor are 0.
2090*795d594fSAndroid Build Coastguard Worker return ((divisor & ((UINT64_C(1) << 52) - 1)) == 0);
2091*795d594fSAndroid Build Coastguard Worker }
2092*795d594fSAndroid Build Coastguard Worker
VisitDiv(HDiv * instruction)2093*795d594fSAndroid Build Coastguard Worker void InstructionSimplifierVisitor::VisitDiv(HDiv* instruction) {
2094*795d594fSAndroid Build Coastguard Worker HConstant* input_cst = instruction->GetConstantRight();
2095*795d594fSAndroid Build Coastguard Worker HInstruction* input_other = instruction->GetLeastConstantLeft();
2096*795d594fSAndroid Build Coastguard Worker DataType::Type type = instruction->GetType();
2097*795d594fSAndroid Build Coastguard Worker
2098*795d594fSAndroid Build Coastguard Worker if ((input_cst != nullptr) && input_cst->IsOne()) {
2099*795d594fSAndroid Build Coastguard Worker // Replace code looking like
2100*795d594fSAndroid Build Coastguard Worker // DIV dst, src, 1
2101*795d594fSAndroid Build Coastguard Worker // with
2102*795d594fSAndroid Build Coastguard Worker // src
2103*795d594fSAndroid Build Coastguard Worker instruction->ReplaceWith(input_other);
2104*795d594fSAndroid Build Coastguard Worker instruction->GetBlock()->RemoveInstruction(instruction);
2105*795d594fSAndroid Build Coastguard Worker RecordSimplification();
2106*795d594fSAndroid Build Coastguard Worker return;
2107*795d594fSAndroid Build Coastguard Worker }
2108*795d594fSAndroid Build Coastguard Worker
2109*795d594fSAndroid Build Coastguard Worker if ((input_cst != nullptr) && input_cst->IsMinusOne()) {
2110*795d594fSAndroid Build Coastguard Worker // Replace code looking like
2111*795d594fSAndroid Build Coastguard Worker // DIV dst, src, -1
2112*795d594fSAndroid Build Coastguard Worker // with
2113*795d594fSAndroid Build Coastguard Worker // NEG dst, src
2114*795d594fSAndroid Build Coastguard Worker instruction->GetBlock()->ReplaceAndRemoveInstructionWith(
2115*795d594fSAndroid Build Coastguard Worker instruction, new (GetGraph()->GetAllocator()) HNeg(type, input_other));
2116*795d594fSAndroid Build Coastguard Worker RecordSimplification();
2117*795d594fSAndroid Build Coastguard Worker return;
2118*795d594fSAndroid Build Coastguard Worker }
2119*795d594fSAndroid Build Coastguard Worker
2120*795d594fSAndroid Build Coastguard Worker if ((input_cst != nullptr) && DataType::IsFloatingPointType(type)) {
2121*795d594fSAndroid Build Coastguard Worker // Try replacing code looking like
2122*795d594fSAndroid Build Coastguard Worker // DIV dst, src, constant
2123*795d594fSAndroid Build Coastguard Worker // with
2124*795d594fSAndroid Build Coastguard Worker // MUL dst, src, 1 / constant
2125*795d594fSAndroid Build Coastguard Worker HConstant* reciprocal = nullptr;
2126*795d594fSAndroid Build Coastguard Worker if (type == DataType::Type::kFloat64) {
2127*795d594fSAndroid Build Coastguard Worker double value = input_cst->AsDoubleConstant()->GetValue();
2128*795d594fSAndroid Build Coastguard Worker if (CanDivideByReciprocalMultiplyDouble(bit_cast<int64_t, double>(value))) {
2129*795d594fSAndroid Build Coastguard Worker reciprocal = GetGraph()->GetDoubleConstant(1.0 / value);
2130*795d594fSAndroid Build Coastguard Worker }
2131*795d594fSAndroid Build Coastguard Worker } else {
2132*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(type, DataType::Type::kFloat32);
2133*795d594fSAndroid Build Coastguard Worker float value = input_cst->AsFloatConstant()->GetValue();
2134*795d594fSAndroid Build Coastguard Worker if (CanDivideByReciprocalMultiplyFloat(bit_cast<int32_t, float>(value))) {
2135*795d594fSAndroid Build Coastguard Worker reciprocal = GetGraph()->GetFloatConstant(1.0f / value);
2136*795d594fSAndroid Build Coastguard Worker }
2137*795d594fSAndroid Build Coastguard Worker }
2138*795d594fSAndroid Build Coastguard Worker
2139*795d594fSAndroid Build Coastguard Worker if (reciprocal != nullptr) {
2140*795d594fSAndroid Build Coastguard Worker instruction->GetBlock()->ReplaceAndRemoveInstructionWith(
2141*795d594fSAndroid Build Coastguard Worker instruction, new (GetGraph()->GetAllocator()) HMul(type, input_other, reciprocal));
2142*795d594fSAndroid Build Coastguard Worker RecordSimplification();
2143*795d594fSAndroid Build Coastguard Worker return;
2144*795d594fSAndroid Build Coastguard Worker }
2145*795d594fSAndroid Build Coastguard Worker }
2146*795d594fSAndroid Build Coastguard Worker }
2147*795d594fSAndroid Build Coastguard Worker
2148*795d594fSAndroid Build Coastguard Worker
2149*795d594fSAndroid Build Coastguard Worker // Search HDiv having the specified dividend and divisor which is in the specified basic block.
2150*795d594fSAndroid Build Coastguard Worker // Return nullptr if nothing has been found.
FindDivWithInputsInBasicBlock(HInstruction * dividend,HInstruction * divisor,HBasicBlock * basic_block)2151*795d594fSAndroid Build Coastguard Worker static HDiv* FindDivWithInputsInBasicBlock(HInstruction* dividend,
2152*795d594fSAndroid Build Coastguard Worker HInstruction* divisor,
2153*795d594fSAndroid Build Coastguard Worker HBasicBlock* basic_block) {
2154*795d594fSAndroid Build Coastguard Worker for (const HUseListNode<HInstruction*>& use : dividend->GetUses()) {
2155*795d594fSAndroid Build Coastguard Worker HInstruction* user = use.GetUser();
2156*795d594fSAndroid Build Coastguard Worker if (user->GetBlock() == basic_block &&
2157*795d594fSAndroid Build Coastguard Worker user->IsDiv() &&
2158*795d594fSAndroid Build Coastguard Worker user->InputAt(0) == dividend &&
2159*795d594fSAndroid Build Coastguard Worker user->InputAt(1) == divisor) {
2160*795d594fSAndroid Build Coastguard Worker return user->AsDiv();
2161*795d594fSAndroid Build Coastguard Worker }
2162*795d594fSAndroid Build Coastguard Worker }
2163*795d594fSAndroid Build Coastguard Worker return nullptr;
2164*795d594fSAndroid Build Coastguard Worker }
2165*795d594fSAndroid Build Coastguard Worker
2166*795d594fSAndroid Build Coastguard Worker // If there is Div with the same inputs as Rem and in the same basic block, it can be reused.
2167*795d594fSAndroid Build Coastguard Worker // Rem is replaced with Mul+Sub which use the found Div.
TryToReuseDiv(HRem * rem)2168*795d594fSAndroid Build Coastguard Worker void InstructionSimplifierVisitor::TryToReuseDiv(HRem* rem) {
2169*795d594fSAndroid Build Coastguard Worker // As the optimization replaces Rem with Mul+Sub they prevent some loop optimizations
2170*795d594fSAndroid Build Coastguard Worker // if the Rem is in a loop.
2171*795d594fSAndroid Build Coastguard Worker // Check if it is allowed to optimize such Rems.
2172*795d594fSAndroid Build Coastguard Worker if (rem->IsInLoop() && be_loop_friendly_) {
2173*795d594fSAndroid Build Coastguard Worker return;
2174*795d594fSAndroid Build Coastguard Worker }
2175*795d594fSAndroid Build Coastguard Worker DataType::Type type = rem->GetResultType();
2176*795d594fSAndroid Build Coastguard Worker if (!DataType::IsIntOrLongType(type)) {
2177*795d594fSAndroid Build Coastguard Worker return;
2178*795d594fSAndroid Build Coastguard Worker }
2179*795d594fSAndroid Build Coastguard Worker
2180*795d594fSAndroid Build Coastguard Worker HBasicBlock* basic_block = rem->GetBlock();
2181*795d594fSAndroid Build Coastguard Worker HInstruction* dividend = rem->GetLeft();
2182*795d594fSAndroid Build Coastguard Worker HInstruction* divisor = rem->GetRight();
2183*795d594fSAndroid Build Coastguard Worker
2184*795d594fSAndroid Build Coastguard Worker if (divisor->IsConstant()) {
2185*795d594fSAndroid Build Coastguard Worker HConstant* input_cst = rem->GetConstantRight();
2186*795d594fSAndroid Build Coastguard Worker DCHECK(input_cst->IsIntConstant() || input_cst->IsLongConstant());
2187*795d594fSAndroid Build Coastguard Worker int64_t cst_value = Int64FromConstant(input_cst);
2188*795d594fSAndroid Build Coastguard Worker if (cst_value == std::numeric_limits<int64_t>::min() || IsPowerOfTwo(std::abs(cst_value))) {
2189*795d594fSAndroid Build Coastguard Worker // Such cases are usually handled in the code generator because they don't need Div at all.
2190*795d594fSAndroid Build Coastguard Worker return;
2191*795d594fSAndroid Build Coastguard Worker }
2192*795d594fSAndroid Build Coastguard Worker }
2193*795d594fSAndroid Build Coastguard Worker
2194*795d594fSAndroid Build Coastguard Worker HDiv* quotient = FindDivWithInputsInBasicBlock(dividend, divisor, basic_block);
2195*795d594fSAndroid Build Coastguard Worker if (quotient == nullptr) {
2196*795d594fSAndroid Build Coastguard Worker return;
2197*795d594fSAndroid Build Coastguard Worker }
2198*795d594fSAndroid Build Coastguard Worker if (!quotient->StrictlyDominates(rem)) {
2199*795d594fSAndroid Build Coastguard Worker quotient->MoveBefore(rem);
2200*795d594fSAndroid Build Coastguard Worker }
2201*795d594fSAndroid Build Coastguard Worker
2202*795d594fSAndroid Build Coastguard Worker ArenaAllocator* allocator = GetGraph()->GetAllocator();
2203*795d594fSAndroid Build Coastguard Worker HInstruction* mul = new (allocator) HMul(type, quotient, divisor);
2204*795d594fSAndroid Build Coastguard Worker basic_block->InsertInstructionBefore(mul, rem);
2205*795d594fSAndroid Build Coastguard Worker HInstruction* sub = new (allocator) HSub(type, dividend, mul);
2206*795d594fSAndroid Build Coastguard Worker basic_block->InsertInstructionBefore(sub, rem);
2207*795d594fSAndroid Build Coastguard Worker rem->ReplaceWith(sub);
2208*795d594fSAndroid Build Coastguard Worker basic_block->RemoveInstruction(rem);
2209*795d594fSAndroid Build Coastguard Worker RecordSimplification();
2210*795d594fSAndroid Build Coastguard Worker }
2211*795d594fSAndroid Build Coastguard Worker
VisitRem(HRem * rem)2212*795d594fSAndroid Build Coastguard Worker void InstructionSimplifierVisitor::VisitRem(HRem* rem) {
2213*795d594fSAndroid Build Coastguard Worker TryToReuseDiv(rem);
2214*795d594fSAndroid Build Coastguard Worker }
2215*795d594fSAndroid Build Coastguard Worker
VisitMul(HMul * instruction)2216*795d594fSAndroid Build Coastguard Worker void InstructionSimplifierVisitor::VisitMul(HMul* instruction) {
2217*795d594fSAndroid Build Coastguard Worker HConstant* input_cst = instruction->GetConstantRight();
2218*795d594fSAndroid Build Coastguard Worker HInstruction* input_other = instruction->GetLeastConstantLeft();
2219*795d594fSAndroid Build Coastguard Worker DataType::Type type = instruction->GetType();
2220*795d594fSAndroid Build Coastguard Worker HBasicBlock* block = instruction->GetBlock();
2221*795d594fSAndroid Build Coastguard Worker ArenaAllocator* allocator = GetGraph()->GetAllocator();
2222*795d594fSAndroid Build Coastguard Worker
2223*795d594fSAndroid Build Coastguard Worker if (input_cst == nullptr) {
2224*795d594fSAndroid Build Coastguard Worker return;
2225*795d594fSAndroid Build Coastguard Worker }
2226*795d594fSAndroid Build Coastguard Worker
2227*795d594fSAndroid Build Coastguard Worker if (input_cst->IsOne()) {
2228*795d594fSAndroid Build Coastguard Worker // Replace code looking like
2229*795d594fSAndroid Build Coastguard Worker // MUL dst, src, 1
2230*795d594fSAndroid Build Coastguard Worker // with
2231*795d594fSAndroid Build Coastguard Worker // src
2232*795d594fSAndroid Build Coastguard Worker instruction->ReplaceWith(input_other);
2233*795d594fSAndroid Build Coastguard Worker instruction->GetBlock()->RemoveInstruction(instruction);
2234*795d594fSAndroid Build Coastguard Worker RecordSimplification();
2235*795d594fSAndroid Build Coastguard Worker return;
2236*795d594fSAndroid Build Coastguard Worker }
2237*795d594fSAndroid Build Coastguard Worker
2238*795d594fSAndroid Build Coastguard Worker if (input_cst->IsMinusOne() &&
2239*795d594fSAndroid Build Coastguard Worker (DataType::IsFloatingPointType(type) || DataType::IsIntOrLongType(type))) {
2240*795d594fSAndroid Build Coastguard Worker // Replace code looking like
2241*795d594fSAndroid Build Coastguard Worker // MUL dst, src, -1
2242*795d594fSAndroid Build Coastguard Worker // with
2243*795d594fSAndroid Build Coastguard Worker // NEG dst, src
2244*795d594fSAndroid Build Coastguard Worker HNeg* neg = new (allocator) HNeg(type, input_other);
2245*795d594fSAndroid Build Coastguard Worker block->ReplaceAndRemoveInstructionWith(instruction, neg);
2246*795d594fSAndroid Build Coastguard Worker RecordSimplification();
2247*795d594fSAndroid Build Coastguard Worker return;
2248*795d594fSAndroid Build Coastguard Worker }
2249*795d594fSAndroid Build Coastguard Worker
2250*795d594fSAndroid Build Coastguard Worker if (DataType::IsFloatingPointType(type) &&
2251*795d594fSAndroid Build Coastguard Worker ((input_cst->IsFloatConstant() && input_cst->AsFloatConstant()->GetValue() == 2.0f) ||
2252*795d594fSAndroid Build Coastguard Worker (input_cst->IsDoubleConstant() && input_cst->AsDoubleConstant()->GetValue() == 2.0))) {
2253*795d594fSAndroid Build Coastguard Worker // Replace code looking like
2254*795d594fSAndroid Build Coastguard Worker // FP_MUL dst, src, 2.0
2255*795d594fSAndroid Build Coastguard Worker // with
2256*795d594fSAndroid Build Coastguard Worker // FP_ADD dst, src, src
2257*795d594fSAndroid Build Coastguard Worker // The 'int' and 'long' cases are handled below.
2258*795d594fSAndroid Build Coastguard Worker block->ReplaceAndRemoveInstructionWith(instruction,
2259*795d594fSAndroid Build Coastguard Worker new (allocator) HAdd(type, input_other, input_other));
2260*795d594fSAndroid Build Coastguard Worker RecordSimplification();
2261*795d594fSAndroid Build Coastguard Worker return;
2262*795d594fSAndroid Build Coastguard Worker }
2263*795d594fSAndroid Build Coastguard Worker
2264*795d594fSAndroid Build Coastguard Worker if (DataType::IsIntOrLongType(type)) {
2265*795d594fSAndroid Build Coastguard Worker int64_t factor = Int64FromConstant(input_cst);
2266*795d594fSAndroid Build Coastguard Worker // Even though constant propagation also takes care of the zero case, other
2267*795d594fSAndroid Build Coastguard Worker // optimizations can lead to having a zero multiplication.
2268*795d594fSAndroid Build Coastguard Worker if (factor == 0) {
2269*795d594fSAndroid Build Coastguard Worker // Replace code looking like
2270*795d594fSAndroid Build Coastguard Worker // MUL dst, src, 0
2271*795d594fSAndroid Build Coastguard Worker // with
2272*795d594fSAndroid Build Coastguard Worker // 0
2273*795d594fSAndroid Build Coastguard Worker instruction->ReplaceWith(input_cst);
2274*795d594fSAndroid Build Coastguard Worker instruction->GetBlock()->RemoveInstruction(instruction);
2275*795d594fSAndroid Build Coastguard Worker RecordSimplification();
2276*795d594fSAndroid Build Coastguard Worker return;
2277*795d594fSAndroid Build Coastguard Worker } else if (IsPowerOfTwo(factor)) {
2278*795d594fSAndroid Build Coastguard Worker // Replace code looking like
2279*795d594fSAndroid Build Coastguard Worker // MUL dst, src, pow_of_2
2280*795d594fSAndroid Build Coastguard Worker // with
2281*795d594fSAndroid Build Coastguard Worker // SHL dst, src, log2(pow_of_2)
2282*795d594fSAndroid Build Coastguard Worker HIntConstant* shift = GetGraph()->GetIntConstant(WhichPowerOf2(factor));
2283*795d594fSAndroid Build Coastguard Worker HShl* shl = new (allocator) HShl(type, input_other, shift);
2284*795d594fSAndroid Build Coastguard Worker block->ReplaceAndRemoveInstructionWith(instruction, shl);
2285*795d594fSAndroid Build Coastguard Worker RecordSimplification();
2286*795d594fSAndroid Build Coastguard Worker return;
2287*795d594fSAndroid Build Coastguard Worker } else if (IsPowerOfTwo(factor - 1)) {
2288*795d594fSAndroid Build Coastguard Worker // Transform code looking like
2289*795d594fSAndroid Build Coastguard Worker // MUL dst, src, (2^n + 1)
2290*795d594fSAndroid Build Coastguard Worker // into
2291*795d594fSAndroid Build Coastguard Worker // SHL tmp, src, n
2292*795d594fSAndroid Build Coastguard Worker // ADD dst, src, tmp
2293*795d594fSAndroid Build Coastguard Worker HShl* shl = new (allocator) HShl(type,
2294*795d594fSAndroid Build Coastguard Worker input_other,
2295*795d594fSAndroid Build Coastguard Worker GetGraph()->GetIntConstant(WhichPowerOf2(factor - 1)));
2296*795d594fSAndroid Build Coastguard Worker HAdd* add = new (allocator) HAdd(type, input_other, shl);
2297*795d594fSAndroid Build Coastguard Worker
2298*795d594fSAndroid Build Coastguard Worker block->InsertInstructionBefore(shl, instruction);
2299*795d594fSAndroid Build Coastguard Worker block->ReplaceAndRemoveInstructionWith(instruction, add);
2300*795d594fSAndroid Build Coastguard Worker RecordSimplification();
2301*795d594fSAndroid Build Coastguard Worker return;
2302*795d594fSAndroid Build Coastguard Worker } else if (IsPowerOfTwo(factor + 1)) {
2303*795d594fSAndroid Build Coastguard Worker // Transform code looking like
2304*795d594fSAndroid Build Coastguard Worker // MUL dst, src, (2^n - 1)
2305*795d594fSAndroid Build Coastguard Worker // into
2306*795d594fSAndroid Build Coastguard Worker // SHL tmp, src, n
2307*795d594fSAndroid Build Coastguard Worker // SUB dst, tmp, src
2308*795d594fSAndroid Build Coastguard Worker HShl* shl = new (allocator) HShl(type,
2309*795d594fSAndroid Build Coastguard Worker input_other,
2310*795d594fSAndroid Build Coastguard Worker GetGraph()->GetIntConstant(WhichPowerOf2(factor + 1)));
2311*795d594fSAndroid Build Coastguard Worker HSub* sub = new (allocator) HSub(type, shl, input_other);
2312*795d594fSAndroid Build Coastguard Worker
2313*795d594fSAndroid Build Coastguard Worker block->InsertInstructionBefore(shl, instruction);
2314*795d594fSAndroid Build Coastguard Worker block->ReplaceAndRemoveInstructionWith(instruction, sub);
2315*795d594fSAndroid Build Coastguard Worker RecordSimplification();
2316*795d594fSAndroid Build Coastguard Worker return;
2317*795d594fSAndroid Build Coastguard Worker }
2318*795d594fSAndroid Build Coastguard Worker }
2319*795d594fSAndroid Build Coastguard Worker
2320*795d594fSAndroid Build Coastguard Worker // TryHandleAssociativeAndCommutativeOperation() does not remove its input,
2321*795d594fSAndroid Build Coastguard Worker // so no need to return.
2322*795d594fSAndroid Build Coastguard Worker TryHandleAssociativeAndCommutativeOperation(instruction);
2323*795d594fSAndroid Build Coastguard Worker }
2324*795d594fSAndroid Build Coastguard Worker
VisitNeg(HNeg * instruction)2325*795d594fSAndroid Build Coastguard Worker void InstructionSimplifierVisitor::VisitNeg(HNeg* instruction) {
2326*795d594fSAndroid Build Coastguard Worker HInstruction* input = instruction->GetInput();
2327*795d594fSAndroid Build Coastguard Worker if (input->IsNeg()) {
2328*795d594fSAndroid Build Coastguard Worker // Replace code looking like
2329*795d594fSAndroid Build Coastguard Worker // NEG tmp, src
2330*795d594fSAndroid Build Coastguard Worker // NEG dst, tmp
2331*795d594fSAndroid Build Coastguard Worker // with
2332*795d594fSAndroid Build Coastguard Worker // src
2333*795d594fSAndroid Build Coastguard Worker HNeg* previous_neg = input->AsNeg();
2334*795d594fSAndroid Build Coastguard Worker instruction->ReplaceWith(previous_neg->GetInput());
2335*795d594fSAndroid Build Coastguard Worker instruction->GetBlock()->RemoveInstruction(instruction);
2336*795d594fSAndroid Build Coastguard Worker // We perform the optimization even if the input negation has environment
2337*795d594fSAndroid Build Coastguard Worker // uses since it allows removing the current instruction. But we only delete
2338*795d594fSAndroid Build Coastguard Worker // the input negation only if it is does not have any uses left.
2339*795d594fSAndroid Build Coastguard Worker if (!previous_neg->HasUses()) {
2340*795d594fSAndroid Build Coastguard Worker previous_neg->GetBlock()->RemoveInstruction(previous_neg);
2341*795d594fSAndroid Build Coastguard Worker }
2342*795d594fSAndroid Build Coastguard Worker RecordSimplification();
2343*795d594fSAndroid Build Coastguard Worker return;
2344*795d594fSAndroid Build Coastguard Worker }
2345*795d594fSAndroid Build Coastguard Worker
2346*795d594fSAndroid Build Coastguard Worker if (input->IsSub() && input->HasOnlyOneNonEnvironmentUse() &&
2347*795d594fSAndroid Build Coastguard Worker !DataType::IsFloatingPointType(input->GetType())) {
2348*795d594fSAndroid Build Coastguard Worker // Replace code looking like
2349*795d594fSAndroid Build Coastguard Worker // SUB tmp, a, b
2350*795d594fSAndroid Build Coastguard Worker // NEG dst, tmp
2351*795d594fSAndroid Build Coastguard Worker // with
2352*795d594fSAndroid Build Coastguard Worker // SUB dst, b, a
2353*795d594fSAndroid Build Coastguard Worker // We do not perform the optimization if the input subtraction has
2354*795d594fSAndroid Build Coastguard Worker // environment uses or multiple non-environment uses as it could lead to
2355*795d594fSAndroid Build Coastguard Worker // worse code. In particular, we do not want the live ranges of `a` and `b`
2356*795d594fSAndroid Build Coastguard Worker // to be extended if we are not sure the initial 'SUB' instruction can be
2357*795d594fSAndroid Build Coastguard Worker // removed.
2358*795d594fSAndroid Build Coastguard Worker // We do not perform optimization for fp because we could lose the sign of zero.
2359*795d594fSAndroid Build Coastguard Worker HSub* sub = input->AsSub();
2360*795d594fSAndroid Build Coastguard Worker HSub* new_sub = new (GetGraph()->GetAllocator()) HSub(
2361*795d594fSAndroid Build Coastguard Worker instruction->GetType(), sub->GetRight(), sub->GetLeft());
2362*795d594fSAndroid Build Coastguard Worker instruction->GetBlock()->ReplaceAndRemoveInstructionWith(instruction, new_sub);
2363*795d594fSAndroid Build Coastguard Worker if (!sub->HasUses()) {
2364*795d594fSAndroid Build Coastguard Worker sub->GetBlock()->RemoveInstruction(sub);
2365*795d594fSAndroid Build Coastguard Worker }
2366*795d594fSAndroid Build Coastguard Worker RecordSimplification();
2367*795d594fSAndroid Build Coastguard Worker }
2368*795d594fSAndroid Build Coastguard Worker }
2369*795d594fSAndroid Build Coastguard Worker
VisitNot(HNot * instruction)2370*795d594fSAndroid Build Coastguard Worker void InstructionSimplifierVisitor::VisitNot(HNot* instruction) {
2371*795d594fSAndroid Build Coastguard Worker HInstruction* input = instruction->GetInput();
2372*795d594fSAndroid Build Coastguard Worker if (input->IsNot()) {
2373*795d594fSAndroid Build Coastguard Worker // Replace code looking like
2374*795d594fSAndroid Build Coastguard Worker // NOT tmp, src
2375*795d594fSAndroid Build Coastguard Worker // NOT dst, tmp
2376*795d594fSAndroid Build Coastguard Worker // with
2377*795d594fSAndroid Build Coastguard Worker // src
2378*795d594fSAndroid Build Coastguard Worker // We perform the optimization even if the input negation has environment
2379*795d594fSAndroid Build Coastguard Worker // uses since it allows removing the current instruction. But we only delete
2380*795d594fSAndroid Build Coastguard Worker // the input negation only if it is does not have any uses left.
2381*795d594fSAndroid Build Coastguard Worker HNot* previous_not = input->AsNot();
2382*795d594fSAndroid Build Coastguard Worker instruction->ReplaceWith(previous_not->GetInput());
2383*795d594fSAndroid Build Coastguard Worker instruction->GetBlock()->RemoveInstruction(instruction);
2384*795d594fSAndroid Build Coastguard Worker if (!previous_not->HasUses()) {
2385*795d594fSAndroid Build Coastguard Worker previous_not->GetBlock()->RemoveInstruction(previous_not);
2386*795d594fSAndroid Build Coastguard Worker }
2387*795d594fSAndroid Build Coastguard Worker RecordSimplification();
2388*795d594fSAndroid Build Coastguard Worker }
2389*795d594fSAndroid Build Coastguard Worker }
2390*795d594fSAndroid Build Coastguard Worker
VisitOr(HOr * instruction)2391*795d594fSAndroid Build Coastguard Worker void InstructionSimplifierVisitor::VisitOr(HOr* instruction) {
2392*795d594fSAndroid Build Coastguard Worker HConstant* input_cst = instruction->GetConstantRight();
2393*795d594fSAndroid Build Coastguard Worker HInstruction* input_other = instruction->GetLeastConstantLeft();
2394*795d594fSAndroid Build Coastguard Worker
2395*795d594fSAndroid Build Coastguard Worker if ((input_cst != nullptr) && input_cst->IsZeroBitPattern()) {
2396*795d594fSAndroid Build Coastguard Worker // Replace code looking like
2397*795d594fSAndroid Build Coastguard Worker // OR dst, src, 0
2398*795d594fSAndroid Build Coastguard Worker // with
2399*795d594fSAndroid Build Coastguard Worker // src
2400*795d594fSAndroid Build Coastguard Worker instruction->ReplaceWith(input_other);
2401*795d594fSAndroid Build Coastguard Worker instruction->GetBlock()->RemoveInstruction(instruction);
2402*795d594fSAndroid Build Coastguard Worker RecordSimplification();
2403*795d594fSAndroid Build Coastguard Worker return;
2404*795d594fSAndroid Build Coastguard Worker }
2405*795d594fSAndroid Build Coastguard Worker
2406*795d594fSAndroid Build Coastguard Worker // We assume that GVN has run before, so we only perform a pointer comparison.
2407*795d594fSAndroid Build Coastguard Worker // If for some reason the values are equal but the pointers are different, we
2408*795d594fSAndroid Build Coastguard Worker // are still correct and only miss an optimization opportunity.
2409*795d594fSAndroid Build Coastguard Worker if (instruction->GetLeft() == instruction->GetRight()) {
2410*795d594fSAndroid Build Coastguard Worker // Replace code looking like
2411*795d594fSAndroid Build Coastguard Worker // OR dst, src, src
2412*795d594fSAndroid Build Coastguard Worker // with
2413*795d594fSAndroid Build Coastguard Worker // src
2414*795d594fSAndroid Build Coastguard Worker instruction->ReplaceWith(instruction->GetLeft());
2415*795d594fSAndroid Build Coastguard Worker instruction->GetBlock()->RemoveInstruction(instruction);
2416*795d594fSAndroid Build Coastguard Worker RecordSimplification();
2417*795d594fSAndroid Build Coastguard Worker return;
2418*795d594fSAndroid Build Coastguard Worker }
2419*795d594fSAndroid Build Coastguard Worker
2420*795d594fSAndroid Build Coastguard Worker if (TryDeMorganNegationFactoring(instruction)) return;
2421*795d594fSAndroid Build Coastguard Worker
2422*795d594fSAndroid Build Coastguard Worker if (TryReplaceWithRotate(instruction)) {
2423*795d594fSAndroid Build Coastguard Worker return;
2424*795d594fSAndroid Build Coastguard Worker }
2425*795d594fSAndroid Build Coastguard Worker
2426*795d594fSAndroid Build Coastguard Worker // TryHandleAssociativeAndCommutativeOperation() does not remove its input,
2427*795d594fSAndroid Build Coastguard Worker // so no need to return.
2428*795d594fSAndroid Build Coastguard Worker TryHandleAssociativeAndCommutativeOperation(instruction);
2429*795d594fSAndroid Build Coastguard Worker }
2430*795d594fSAndroid Build Coastguard Worker
VisitShl(HShl * instruction)2431*795d594fSAndroid Build Coastguard Worker void InstructionSimplifierVisitor::VisitShl(HShl* instruction) {
2432*795d594fSAndroid Build Coastguard Worker VisitShift(instruction);
2433*795d594fSAndroid Build Coastguard Worker }
2434*795d594fSAndroid Build Coastguard Worker
VisitShr(HShr * instruction)2435*795d594fSAndroid Build Coastguard Worker void InstructionSimplifierVisitor::VisitShr(HShr* instruction) {
2436*795d594fSAndroid Build Coastguard Worker VisitShift(instruction);
2437*795d594fSAndroid Build Coastguard Worker }
2438*795d594fSAndroid Build Coastguard Worker
VisitSub(HSub * instruction)2439*795d594fSAndroid Build Coastguard Worker void InstructionSimplifierVisitor::VisitSub(HSub* instruction) {
2440*795d594fSAndroid Build Coastguard Worker HConstant* input_cst = instruction->GetConstantRight();
2441*795d594fSAndroid Build Coastguard Worker HInstruction* input_other = instruction->GetLeastConstantLeft();
2442*795d594fSAndroid Build Coastguard Worker
2443*795d594fSAndroid Build Coastguard Worker DataType::Type type = instruction->GetType();
2444*795d594fSAndroid Build Coastguard Worker if (DataType::IsFloatingPointType(type)) {
2445*795d594fSAndroid Build Coastguard Worker return;
2446*795d594fSAndroid Build Coastguard Worker }
2447*795d594fSAndroid Build Coastguard Worker
2448*795d594fSAndroid Build Coastguard Worker if ((input_cst != nullptr) && input_cst->IsArithmeticZero()) {
2449*795d594fSAndroid Build Coastguard Worker // Replace code looking like
2450*795d594fSAndroid Build Coastguard Worker // SUB dst, src, 0
2451*795d594fSAndroid Build Coastguard Worker // with
2452*795d594fSAndroid Build Coastguard Worker // src
2453*795d594fSAndroid Build Coastguard Worker // Note that we cannot optimize `x - 0.0` to `x` for floating-point. When
2454*795d594fSAndroid Build Coastguard Worker // `x` is `-0.0`, the former expression yields `0.0`, while the later
2455*795d594fSAndroid Build Coastguard Worker // yields `-0.0`.
2456*795d594fSAndroid Build Coastguard Worker instruction->ReplaceWith(input_other);
2457*795d594fSAndroid Build Coastguard Worker instruction->GetBlock()->RemoveInstruction(instruction);
2458*795d594fSAndroid Build Coastguard Worker RecordSimplification();
2459*795d594fSAndroid Build Coastguard Worker return;
2460*795d594fSAndroid Build Coastguard Worker }
2461*795d594fSAndroid Build Coastguard Worker
2462*795d594fSAndroid Build Coastguard Worker HBasicBlock* block = instruction->GetBlock();
2463*795d594fSAndroid Build Coastguard Worker ArenaAllocator* allocator = GetGraph()->GetAllocator();
2464*795d594fSAndroid Build Coastguard Worker
2465*795d594fSAndroid Build Coastguard Worker HInstruction* left = instruction->GetLeft();
2466*795d594fSAndroid Build Coastguard Worker HInstruction* right = instruction->GetRight();
2467*795d594fSAndroid Build Coastguard Worker if (left->IsConstant()) {
2468*795d594fSAndroid Build Coastguard Worker if (Int64FromConstant(left->AsConstant()) == 0) {
2469*795d594fSAndroid Build Coastguard Worker // Replace code looking like
2470*795d594fSAndroid Build Coastguard Worker // SUB dst, 0, src
2471*795d594fSAndroid Build Coastguard Worker // with
2472*795d594fSAndroid Build Coastguard Worker // NEG dst, src
2473*795d594fSAndroid Build Coastguard Worker // Note that we cannot optimize `0.0 - x` to `-x` for floating-point. When
2474*795d594fSAndroid Build Coastguard Worker // `x` is `0.0`, the former expression yields `0.0`, while the later
2475*795d594fSAndroid Build Coastguard Worker // yields `-0.0`.
2476*795d594fSAndroid Build Coastguard Worker HNeg* neg = new (allocator) HNeg(type, right);
2477*795d594fSAndroid Build Coastguard Worker block->ReplaceAndRemoveInstructionWith(instruction, neg);
2478*795d594fSAndroid Build Coastguard Worker RecordSimplification();
2479*795d594fSAndroid Build Coastguard Worker return;
2480*795d594fSAndroid Build Coastguard Worker }
2481*795d594fSAndroid Build Coastguard Worker }
2482*795d594fSAndroid Build Coastguard Worker
2483*795d594fSAndroid Build Coastguard Worker if (left->IsNeg() && right->IsNeg()) {
2484*795d594fSAndroid Build Coastguard Worker if (TryMoveNegOnInputsAfterBinop(instruction)) {
2485*795d594fSAndroid Build Coastguard Worker return;
2486*795d594fSAndroid Build Coastguard Worker }
2487*795d594fSAndroid Build Coastguard Worker }
2488*795d594fSAndroid Build Coastguard Worker
2489*795d594fSAndroid Build Coastguard Worker if (right->IsNeg() && right->HasOnlyOneNonEnvironmentUse()) {
2490*795d594fSAndroid Build Coastguard Worker // Replace code looking like
2491*795d594fSAndroid Build Coastguard Worker // NEG tmp, b
2492*795d594fSAndroid Build Coastguard Worker // SUB dst, a, tmp
2493*795d594fSAndroid Build Coastguard Worker // with
2494*795d594fSAndroid Build Coastguard Worker // ADD dst, a, b
2495*795d594fSAndroid Build Coastguard Worker HAdd* add = new(GetGraph()->GetAllocator()) HAdd(type, left, right->AsNeg()->GetInput());
2496*795d594fSAndroid Build Coastguard Worker instruction->GetBlock()->ReplaceAndRemoveInstructionWith(instruction, add);
2497*795d594fSAndroid Build Coastguard Worker RecordSimplification();
2498*795d594fSAndroid Build Coastguard Worker right->GetBlock()->RemoveInstruction(right);
2499*795d594fSAndroid Build Coastguard Worker return;
2500*795d594fSAndroid Build Coastguard Worker }
2501*795d594fSAndroid Build Coastguard Worker
2502*795d594fSAndroid Build Coastguard Worker if (left->IsNeg() && left->HasOnlyOneNonEnvironmentUse()) {
2503*795d594fSAndroid Build Coastguard Worker // Replace code looking like
2504*795d594fSAndroid Build Coastguard Worker // NEG tmp, a
2505*795d594fSAndroid Build Coastguard Worker // SUB dst, tmp, b
2506*795d594fSAndroid Build Coastguard Worker // with
2507*795d594fSAndroid Build Coastguard Worker // ADD tmp, a, b
2508*795d594fSAndroid Build Coastguard Worker // NEG dst, tmp
2509*795d594fSAndroid Build Coastguard Worker // The second version is not intrinsically better, but enables more
2510*795d594fSAndroid Build Coastguard Worker // transformations.
2511*795d594fSAndroid Build Coastguard Worker HAdd* add = new(GetGraph()->GetAllocator()) HAdd(type, left->AsNeg()->GetInput(), right);
2512*795d594fSAndroid Build Coastguard Worker instruction->GetBlock()->InsertInstructionBefore(add, instruction);
2513*795d594fSAndroid Build Coastguard Worker HNeg* neg = new (GetGraph()->GetAllocator()) HNeg(instruction->GetType(), add);
2514*795d594fSAndroid Build Coastguard Worker instruction->GetBlock()->InsertInstructionBefore(neg, instruction);
2515*795d594fSAndroid Build Coastguard Worker instruction->ReplaceWith(neg);
2516*795d594fSAndroid Build Coastguard Worker instruction->GetBlock()->RemoveInstruction(instruction);
2517*795d594fSAndroid Build Coastguard Worker RecordSimplification();
2518*795d594fSAndroid Build Coastguard Worker left->GetBlock()->RemoveInstruction(left);
2519*795d594fSAndroid Build Coastguard Worker return;
2520*795d594fSAndroid Build Coastguard Worker }
2521*795d594fSAndroid Build Coastguard Worker
2522*795d594fSAndroid Build Coastguard Worker if (TrySubtractionChainSimplification(instruction)) {
2523*795d594fSAndroid Build Coastguard Worker return;
2524*795d594fSAndroid Build Coastguard Worker }
2525*795d594fSAndroid Build Coastguard Worker
2526*795d594fSAndroid Build Coastguard Worker if (left->IsAdd()) {
2527*795d594fSAndroid Build Coastguard Worker // Cases (x + y) - y = x, and (x + y) - x = y.
2528*795d594fSAndroid Build Coastguard Worker // Replace code patterns looking like
2529*795d594fSAndroid Build Coastguard Worker // ADD dst1, x, y ADD dst1, x, y
2530*795d594fSAndroid Build Coastguard Worker // SUB dst2, dst1, y SUB dst2, dst1, x
2531*795d594fSAndroid Build Coastguard Worker // with
2532*795d594fSAndroid Build Coastguard Worker // ADD dst1, x, y
2533*795d594fSAndroid Build Coastguard Worker // SUB instruction is not needed in this case, we may use
2534*795d594fSAndroid Build Coastguard Worker // one of inputs of ADD instead.
2535*795d594fSAndroid Build Coastguard Worker // It is applicable to integral types only.
2536*795d594fSAndroid Build Coastguard Worker HAdd* add = left->AsAdd();
2537*795d594fSAndroid Build Coastguard Worker DCHECK(DataType::IsIntegralType(type));
2538*795d594fSAndroid Build Coastguard Worker if (add->GetRight() == right) {
2539*795d594fSAndroid Build Coastguard Worker instruction->ReplaceWith(add->GetLeft());
2540*795d594fSAndroid Build Coastguard Worker RecordSimplification();
2541*795d594fSAndroid Build Coastguard Worker instruction->GetBlock()->RemoveInstruction(instruction);
2542*795d594fSAndroid Build Coastguard Worker return;
2543*795d594fSAndroid Build Coastguard Worker } else if (add->GetLeft() == right) {
2544*795d594fSAndroid Build Coastguard Worker instruction->ReplaceWith(add->GetRight());
2545*795d594fSAndroid Build Coastguard Worker RecordSimplification();
2546*795d594fSAndroid Build Coastguard Worker instruction->GetBlock()->RemoveInstruction(instruction);
2547*795d594fSAndroid Build Coastguard Worker return;
2548*795d594fSAndroid Build Coastguard Worker }
2549*795d594fSAndroid Build Coastguard Worker } else if (right->IsAdd()) {
2550*795d594fSAndroid Build Coastguard Worker // Cases y - (x + y) = -x, and x - (x + y) = -y.
2551*795d594fSAndroid Build Coastguard Worker // Replace code patterns looking like
2552*795d594fSAndroid Build Coastguard Worker // ADD dst1, x, y ADD dst1, x, y
2553*795d594fSAndroid Build Coastguard Worker // SUB dst2, y, dst1 SUB dst2, x, dst1
2554*795d594fSAndroid Build Coastguard Worker // with
2555*795d594fSAndroid Build Coastguard Worker // ADD dst1, x, y ADD dst1, x, y
2556*795d594fSAndroid Build Coastguard Worker // NEG x NEG y
2557*795d594fSAndroid Build Coastguard Worker // SUB instruction is not needed in this case, we may use
2558*795d594fSAndroid Build Coastguard Worker // one of inputs of ADD instead with a NEG.
2559*795d594fSAndroid Build Coastguard Worker // It is applicable to integral types only.
2560*795d594fSAndroid Build Coastguard Worker HAdd* add = right->AsAdd();
2561*795d594fSAndroid Build Coastguard Worker DCHECK(DataType::IsIntegralType(type));
2562*795d594fSAndroid Build Coastguard Worker if (add->GetRight() == left) {
2563*795d594fSAndroid Build Coastguard Worker HNeg* neg = new (GetGraph()->GetAllocator()) HNeg(add->GetType(), add->GetLeft());
2564*795d594fSAndroid Build Coastguard Worker instruction->GetBlock()->ReplaceAndRemoveInstructionWith(instruction, neg);
2565*795d594fSAndroid Build Coastguard Worker RecordSimplification();
2566*795d594fSAndroid Build Coastguard Worker return;
2567*795d594fSAndroid Build Coastguard Worker } else if (add->GetLeft() == left) {
2568*795d594fSAndroid Build Coastguard Worker HNeg* neg = new (GetGraph()->GetAllocator()) HNeg(add->GetType(), add->GetRight());
2569*795d594fSAndroid Build Coastguard Worker instruction->GetBlock()->ReplaceAndRemoveInstructionWith(instruction, neg);
2570*795d594fSAndroid Build Coastguard Worker RecordSimplification();
2571*795d594fSAndroid Build Coastguard Worker return;
2572*795d594fSAndroid Build Coastguard Worker }
2573*795d594fSAndroid Build Coastguard Worker } else if (left->IsSub()) {
2574*795d594fSAndroid Build Coastguard Worker // Case (x - y) - x = -y.
2575*795d594fSAndroid Build Coastguard Worker // Replace code patterns looking like
2576*795d594fSAndroid Build Coastguard Worker // SUB dst1, x, y
2577*795d594fSAndroid Build Coastguard Worker // SUB dst2, dst1, x
2578*795d594fSAndroid Build Coastguard Worker // with
2579*795d594fSAndroid Build Coastguard Worker // SUB dst1, x, y
2580*795d594fSAndroid Build Coastguard Worker // NEG y
2581*795d594fSAndroid Build Coastguard Worker // The second SUB is not needed in this case, we may use the second input of the first SUB
2582*795d594fSAndroid Build Coastguard Worker // instead with a NEG.
2583*795d594fSAndroid Build Coastguard Worker // It is applicable to integral types only.
2584*795d594fSAndroid Build Coastguard Worker HSub* sub = left->AsSub();
2585*795d594fSAndroid Build Coastguard Worker DCHECK(DataType::IsIntegralType(type));
2586*795d594fSAndroid Build Coastguard Worker if (sub->GetLeft() == right) {
2587*795d594fSAndroid Build Coastguard Worker HNeg* neg = new (GetGraph()->GetAllocator()) HNeg(sub->GetType(), sub->GetRight());
2588*795d594fSAndroid Build Coastguard Worker instruction->GetBlock()->ReplaceAndRemoveInstructionWith(instruction, neg);
2589*795d594fSAndroid Build Coastguard Worker RecordSimplification();
2590*795d594fSAndroid Build Coastguard Worker return;
2591*795d594fSAndroid Build Coastguard Worker }
2592*795d594fSAndroid Build Coastguard Worker } else if (right->IsSub()) {
2593*795d594fSAndroid Build Coastguard Worker // Case x - (x - y) = y.
2594*795d594fSAndroid Build Coastguard Worker // Replace code patterns looking like
2595*795d594fSAndroid Build Coastguard Worker // SUB dst1, x, y
2596*795d594fSAndroid Build Coastguard Worker // SUB dst2, x, dst1
2597*795d594fSAndroid Build Coastguard Worker // with
2598*795d594fSAndroid Build Coastguard Worker // SUB dst1, x, y
2599*795d594fSAndroid Build Coastguard Worker // The second SUB is not needed in this case, we may use the second input of the first SUB.
2600*795d594fSAndroid Build Coastguard Worker // It is applicable to integral types only.
2601*795d594fSAndroid Build Coastguard Worker HSub* sub = right->AsSub();
2602*795d594fSAndroid Build Coastguard Worker DCHECK(DataType::IsIntegralType(type));
2603*795d594fSAndroid Build Coastguard Worker if (sub->GetLeft() == left) {
2604*795d594fSAndroid Build Coastguard Worker instruction->ReplaceWith(sub->GetRight());
2605*795d594fSAndroid Build Coastguard Worker RecordSimplification();
2606*795d594fSAndroid Build Coastguard Worker instruction->GetBlock()->RemoveInstruction(instruction);
2607*795d594fSAndroid Build Coastguard Worker return;
2608*795d594fSAndroid Build Coastguard Worker }
2609*795d594fSAndroid Build Coastguard Worker }
2610*795d594fSAndroid Build Coastguard Worker }
2611*795d594fSAndroid Build Coastguard Worker
VisitUShr(HUShr * instruction)2612*795d594fSAndroid Build Coastguard Worker void InstructionSimplifierVisitor::VisitUShr(HUShr* instruction) {
2613*795d594fSAndroid Build Coastguard Worker VisitShift(instruction);
2614*795d594fSAndroid Build Coastguard Worker }
2615*795d594fSAndroid Build Coastguard Worker
VisitXor(HXor * instruction)2616*795d594fSAndroid Build Coastguard Worker void InstructionSimplifierVisitor::VisitXor(HXor* instruction) {
2617*795d594fSAndroid Build Coastguard Worker HConstant* input_cst = instruction->GetConstantRight();
2618*795d594fSAndroid Build Coastguard Worker HInstruction* input_other = instruction->GetLeastConstantLeft();
2619*795d594fSAndroid Build Coastguard Worker
2620*795d594fSAndroid Build Coastguard Worker if ((input_cst != nullptr) && input_cst->IsZeroBitPattern()) {
2621*795d594fSAndroid Build Coastguard Worker // Replace code looking like
2622*795d594fSAndroid Build Coastguard Worker // XOR dst, src, 0
2623*795d594fSAndroid Build Coastguard Worker // with
2624*795d594fSAndroid Build Coastguard Worker // src
2625*795d594fSAndroid Build Coastguard Worker instruction->ReplaceWith(input_other);
2626*795d594fSAndroid Build Coastguard Worker instruction->GetBlock()->RemoveInstruction(instruction);
2627*795d594fSAndroid Build Coastguard Worker RecordSimplification();
2628*795d594fSAndroid Build Coastguard Worker return;
2629*795d594fSAndroid Build Coastguard Worker }
2630*795d594fSAndroid Build Coastguard Worker
2631*795d594fSAndroid Build Coastguard Worker if ((input_cst != nullptr) && input_cst->IsOne()
2632*795d594fSAndroid Build Coastguard Worker && input_other->GetType() == DataType::Type::kBool) {
2633*795d594fSAndroid Build Coastguard Worker // Replace code looking like
2634*795d594fSAndroid Build Coastguard Worker // XOR dst, src, 1
2635*795d594fSAndroid Build Coastguard Worker // with
2636*795d594fSAndroid Build Coastguard Worker // BOOLEAN_NOT dst, src
2637*795d594fSAndroid Build Coastguard Worker HBooleanNot* boolean_not = new (GetGraph()->GetAllocator()) HBooleanNot(input_other);
2638*795d594fSAndroid Build Coastguard Worker instruction->GetBlock()->ReplaceAndRemoveInstructionWith(instruction, boolean_not);
2639*795d594fSAndroid Build Coastguard Worker RecordSimplification();
2640*795d594fSAndroid Build Coastguard Worker return;
2641*795d594fSAndroid Build Coastguard Worker }
2642*795d594fSAndroid Build Coastguard Worker
2643*795d594fSAndroid Build Coastguard Worker if ((input_cst != nullptr) && AreAllBitsSet(input_cst)) {
2644*795d594fSAndroid Build Coastguard Worker // Replace code looking like
2645*795d594fSAndroid Build Coastguard Worker // XOR dst, src, 0xFFF...FF
2646*795d594fSAndroid Build Coastguard Worker // with
2647*795d594fSAndroid Build Coastguard Worker // NOT dst, src
2648*795d594fSAndroid Build Coastguard Worker HNot* bitwise_not = new (GetGraph()->GetAllocator()) HNot(instruction->GetType(), input_other);
2649*795d594fSAndroid Build Coastguard Worker instruction->GetBlock()->ReplaceAndRemoveInstructionWith(instruction, bitwise_not);
2650*795d594fSAndroid Build Coastguard Worker RecordSimplification();
2651*795d594fSAndroid Build Coastguard Worker return;
2652*795d594fSAndroid Build Coastguard Worker }
2653*795d594fSAndroid Build Coastguard Worker
2654*795d594fSAndroid Build Coastguard Worker HInstruction* left = instruction->GetLeft();
2655*795d594fSAndroid Build Coastguard Worker HInstruction* right = instruction->GetRight();
2656*795d594fSAndroid Build Coastguard Worker if (((left->IsNot() && right->IsNot()) ||
2657*795d594fSAndroid Build Coastguard Worker (left->IsBooleanNot() && right->IsBooleanNot())) &&
2658*795d594fSAndroid Build Coastguard Worker left->HasOnlyOneNonEnvironmentUse() &&
2659*795d594fSAndroid Build Coastguard Worker right->HasOnlyOneNonEnvironmentUse()) {
2660*795d594fSAndroid Build Coastguard Worker // Replace code looking like
2661*795d594fSAndroid Build Coastguard Worker // NOT nota, a
2662*795d594fSAndroid Build Coastguard Worker // NOT notb, b
2663*795d594fSAndroid Build Coastguard Worker // XOR dst, nota, notb
2664*795d594fSAndroid Build Coastguard Worker // with
2665*795d594fSAndroid Build Coastguard Worker // XOR dst, a, b
2666*795d594fSAndroid Build Coastguard Worker instruction->ReplaceInput(left->InputAt(0), 0);
2667*795d594fSAndroid Build Coastguard Worker instruction->ReplaceInput(right->InputAt(0), 1);
2668*795d594fSAndroid Build Coastguard Worker left->GetBlock()->RemoveInstruction(left);
2669*795d594fSAndroid Build Coastguard Worker right->GetBlock()->RemoveInstruction(right);
2670*795d594fSAndroid Build Coastguard Worker RecordSimplification();
2671*795d594fSAndroid Build Coastguard Worker return;
2672*795d594fSAndroid Build Coastguard Worker }
2673*795d594fSAndroid Build Coastguard Worker
2674*795d594fSAndroid Build Coastguard Worker if (TryReplaceWithRotate(instruction)) {
2675*795d594fSAndroid Build Coastguard Worker return;
2676*795d594fSAndroid Build Coastguard Worker }
2677*795d594fSAndroid Build Coastguard Worker
2678*795d594fSAndroid Build Coastguard Worker // TryHandleAssociativeAndCommutativeOperation() does not remove its input,
2679*795d594fSAndroid Build Coastguard Worker // so no need to return.
2680*795d594fSAndroid Build Coastguard Worker TryHandleAssociativeAndCommutativeOperation(instruction);
2681*795d594fSAndroid Build Coastguard Worker }
2682*795d594fSAndroid Build Coastguard Worker
SimplifyBoxUnbox(HInvoke * instruction,ArtField * field,DataType::Type type)2683*795d594fSAndroid Build Coastguard Worker void InstructionSimplifierVisitor::SimplifyBoxUnbox(
2684*795d594fSAndroid Build Coastguard Worker HInvoke* instruction, ArtField* field, DataType::Type type) {
2685*795d594fSAndroid Build Coastguard Worker DCHECK(instruction->GetIntrinsic() == Intrinsics::kByteValueOf ||
2686*795d594fSAndroid Build Coastguard Worker instruction->GetIntrinsic() == Intrinsics::kShortValueOf ||
2687*795d594fSAndroid Build Coastguard Worker instruction->GetIntrinsic() == Intrinsics::kCharacterValueOf ||
2688*795d594fSAndroid Build Coastguard Worker instruction->GetIntrinsic() == Intrinsics::kIntegerValueOf);
2689*795d594fSAndroid Build Coastguard Worker const HUseList<HInstruction*>& uses = instruction->GetUses();
2690*795d594fSAndroid Build Coastguard Worker for (auto it = uses.begin(), end = uses.end(); it != end;) {
2691*795d594fSAndroid Build Coastguard Worker HInstruction* user = it->GetUser();
2692*795d594fSAndroid Build Coastguard Worker ++it; // Increment the iterator before we potentially remove the node from the list.
2693*795d594fSAndroid Build Coastguard Worker if (user->IsInstanceFieldGet() &&
2694*795d594fSAndroid Build Coastguard Worker user->AsInstanceFieldGet()->GetFieldInfo().GetField() == field &&
2695*795d594fSAndroid Build Coastguard Worker // Note: Due to other simplifications, we may have an `HInstanceFieldGet` with
2696*795d594fSAndroid Build Coastguard Worker // a different type (Int8 vs. Uint8, Int16 vs. Uint16) for the same field.
2697*795d594fSAndroid Build Coastguard Worker // Do not optimize that case for now. (We would need to insert a `HTypeConversion`.)
2698*795d594fSAndroid Build Coastguard Worker user->GetType() == type) {
2699*795d594fSAndroid Build Coastguard Worker user->ReplaceWith(instruction->InputAt(0));
2700*795d594fSAndroid Build Coastguard Worker RecordSimplification();
2701*795d594fSAndroid Build Coastguard Worker // Do not remove `user` while we're iterating over the block's instructions. Let DCE do it.
2702*795d594fSAndroid Build Coastguard Worker }
2703*795d594fSAndroid Build Coastguard Worker }
2704*795d594fSAndroid Build Coastguard Worker }
2705*795d594fSAndroid Build Coastguard Worker
SimplifyStringEquals(HInvoke * instruction)2706*795d594fSAndroid Build Coastguard Worker void InstructionSimplifierVisitor::SimplifyStringEquals(HInvoke* instruction) {
2707*795d594fSAndroid Build Coastguard Worker HInstruction* argument = instruction->InputAt(1);
2708*795d594fSAndroid Build Coastguard Worker HInstruction* receiver = instruction->InputAt(0);
2709*795d594fSAndroid Build Coastguard Worker if (receiver == argument) {
2710*795d594fSAndroid Build Coastguard Worker // Because String.equals is an instance call, the receiver is
2711*795d594fSAndroid Build Coastguard Worker // a null check if we don't know it's null. The argument however, will
2712*795d594fSAndroid Build Coastguard Worker // be the actual object. So we cannot end up in a situation where both
2713*795d594fSAndroid Build Coastguard Worker // are equal but could be null.
2714*795d594fSAndroid Build Coastguard Worker DCHECK(CanEnsureNotNullAt(argument, instruction));
2715*795d594fSAndroid Build Coastguard Worker instruction->ReplaceWith(GetGraph()->GetIntConstant(1));
2716*795d594fSAndroid Build Coastguard Worker instruction->GetBlock()->RemoveInstruction(instruction);
2717*795d594fSAndroid Build Coastguard Worker } else {
2718*795d594fSAndroid Build Coastguard Worker StringEqualsOptimizations optimizations(instruction);
2719*795d594fSAndroid Build Coastguard Worker if (CanEnsureNotNullAt(argument, instruction)) {
2720*795d594fSAndroid Build Coastguard Worker optimizations.SetArgumentNotNull();
2721*795d594fSAndroid Build Coastguard Worker }
2722*795d594fSAndroid Build Coastguard Worker ScopedObjectAccess soa(Thread::Current());
2723*795d594fSAndroid Build Coastguard Worker ReferenceTypeInfo argument_rti = argument->GetReferenceTypeInfo();
2724*795d594fSAndroid Build Coastguard Worker if (argument_rti.IsValid() && argument_rti.IsStringClass()) {
2725*795d594fSAndroid Build Coastguard Worker optimizations.SetArgumentIsString();
2726*795d594fSAndroid Build Coastguard Worker }
2727*795d594fSAndroid Build Coastguard Worker }
2728*795d594fSAndroid Build Coastguard Worker }
2729*795d594fSAndroid Build Coastguard Worker
IsArrayLengthOf(HInstruction * potential_length,HInstruction * potential_array)2730*795d594fSAndroid Build Coastguard Worker static bool IsArrayLengthOf(HInstruction* potential_length, HInstruction* potential_array) {
2731*795d594fSAndroid Build Coastguard Worker if (potential_length->IsArrayLength()) {
2732*795d594fSAndroid Build Coastguard Worker return potential_length->InputAt(0) == potential_array;
2733*795d594fSAndroid Build Coastguard Worker }
2734*795d594fSAndroid Build Coastguard Worker
2735*795d594fSAndroid Build Coastguard Worker if (potential_array->IsNewArray()) {
2736*795d594fSAndroid Build Coastguard Worker return potential_array->AsNewArray()->GetLength() == potential_length;
2737*795d594fSAndroid Build Coastguard Worker }
2738*795d594fSAndroid Build Coastguard Worker
2739*795d594fSAndroid Build Coastguard Worker return false;
2740*795d594fSAndroid Build Coastguard Worker }
2741*795d594fSAndroid Build Coastguard Worker
SimplifySystemArrayCopy(HInvoke * instruction)2742*795d594fSAndroid Build Coastguard Worker void InstructionSimplifierVisitor::SimplifySystemArrayCopy(HInvoke* instruction) {
2743*795d594fSAndroid Build Coastguard Worker HInstruction* source = instruction->InputAt(0);
2744*795d594fSAndroid Build Coastguard Worker HInstruction* source_pos = instruction->InputAt(1);
2745*795d594fSAndroid Build Coastguard Worker HInstruction* destination = instruction->InputAt(2);
2746*795d594fSAndroid Build Coastguard Worker HInstruction* destination_pos = instruction->InputAt(3);
2747*795d594fSAndroid Build Coastguard Worker HInstruction* count = instruction->InputAt(4);
2748*795d594fSAndroid Build Coastguard Worker SystemArrayCopyOptimizations optimizations(instruction);
2749*795d594fSAndroid Build Coastguard Worker if (CanEnsureNotNullAt(source, instruction)) {
2750*795d594fSAndroid Build Coastguard Worker optimizations.SetSourceIsNotNull();
2751*795d594fSAndroid Build Coastguard Worker }
2752*795d594fSAndroid Build Coastguard Worker if (CanEnsureNotNullAt(destination, instruction)) {
2753*795d594fSAndroid Build Coastguard Worker optimizations.SetDestinationIsNotNull();
2754*795d594fSAndroid Build Coastguard Worker }
2755*795d594fSAndroid Build Coastguard Worker if (destination == source) {
2756*795d594fSAndroid Build Coastguard Worker optimizations.SetDestinationIsSource();
2757*795d594fSAndroid Build Coastguard Worker }
2758*795d594fSAndroid Build Coastguard Worker
2759*795d594fSAndroid Build Coastguard Worker if (source_pos == destination_pos) {
2760*795d594fSAndroid Build Coastguard Worker optimizations.SetSourcePositionIsDestinationPosition();
2761*795d594fSAndroid Build Coastguard Worker }
2762*795d594fSAndroid Build Coastguard Worker
2763*795d594fSAndroid Build Coastguard Worker if (IsArrayLengthOf(count, source)) {
2764*795d594fSAndroid Build Coastguard Worker optimizations.SetCountIsSourceLength();
2765*795d594fSAndroid Build Coastguard Worker }
2766*795d594fSAndroid Build Coastguard Worker
2767*795d594fSAndroid Build Coastguard Worker if (IsArrayLengthOf(count, destination)) {
2768*795d594fSAndroid Build Coastguard Worker optimizations.SetCountIsDestinationLength();
2769*795d594fSAndroid Build Coastguard Worker }
2770*795d594fSAndroid Build Coastguard Worker
2771*795d594fSAndroid Build Coastguard Worker {
2772*795d594fSAndroid Build Coastguard Worker ScopedObjectAccess soa(Thread::Current());
2773*795d594fSAndroid Build Coastguard Worker DataType::Type source_component_type = DataType::Type::kVoid;
2774*795d594fSAndroid Build Coastguard Worker DataType::Type destination_component_type = DataType::Type::kVoid;
2775*795d594fSAndroid Build Coastguard Worker ReferenceTypeInfo destination_rti = destination->GetReferenceTypeInfo();
2776*795d594fSAndroid Build Coastguard Worker if (destination_rti.IsValid()) {
2777*795d594fSAndroid Build Coastguard Worker if (destination_rti.IsObjectArray()) {
2778*795d594fSAndroid Build Coastguard Worker if (destination_rti.IsExact()) {
2779*795d594fSAndroid Build Coastguard Worker optimizations.SetDoesNotNeedTypeCheck();
2780*795d594fSAndroid Build Coastguard Worker }
2781*795d594fSAndroid Build Coastguard Worker optimizations.SetDestinationIsTypedObjectArray();
2782*795d594fSAndroid Build Coastguard Worker }
2783*795d594fSAndroid Build Coastguard Worker if (destination_rti.IsPrimitiveArrayClass()) {
2784*795d594fSAndroid Build Coastguard Worker destination_component_type = DataTypeFromPrimitive(
2785*795d594fSAndroid Build Coastguard Worker destination_rti.GetTypeHandle()->GetComponentType()->GetPrimitiveType());
2786*795d594fSAndroid Build Coastguard Worker optimizations.SetDestinationIsPrimitiveArray();
2787*795d594fSAndroid Build Coastguard Worker } else if (destination_rti.IsNonPrimitiveArrayClass()) {
2788*795d594fSAndroid Build Coastguard Worker optimizations.SetDestinationIsNonPrimitiveArray();
2789*795d594fSAndroid Build Coastguard Worker }
2790*795d594fSAndroid Build Coastguard Worker }
2791*795d594fSAndroid Build Coastguard Worker ReferenceTypeInfo source_rti = source->GetReferenceTypeInfo();
2792*795d594fSAndroid Build Coastguard Worker if (source_rti.IsValid()) {
2793*795d594fSAndroid Build Coastguard Worker if (destination_rti.IsValid() && destination_rti.CanArrayHoldValuesOf(source_rti)) {
2794*795d594fSAndroid Build Coastguard Worker optimizations.SetDoesNotNeedTypeCheck();
2795*795d594fSAndroid Build Coastguard Worker }
2796*795d594fSAndroid Build Coastguard Worker if (source_rti.IsPrimitiveArrayClass()) {
2797*795d594fSAndroid Build Coastguard Worker optimizations.SetSourceIsPrimitiveArray();
2798*795d594fSAndroid Build Coastguard Worker source_component_type = DataTypeFromPrimitive(
2799*795d594fSAndroid Build Coastguard Worker source_rti.GetTypeHandle()->GetComponentType()->GetPrimitiveType());
2800*795d594fSAndroid Build Coastguard Worker } else if (source_rti.IsNonPrimitiveArrayClass()) {
2801*795d594fSAndroid Build Coastguard Worker optimizations.SetSourceIsNonPrimitiveArray();
2802*795d594fSAndroid Build Coastguard Worker }
2803*795d594fSAndroid Build Coastguard Worker }
2804*795d594fSAndroid Build Coastguard Worker // For primitive arrays, use their optimized ArtMethod implementations.
2805*795d594fSAndroid Build Coastguard Worker if ((source_component_type != DataType::Type::kVoid) &&
2806*795d594fSAndroid Build Coastguard Worker (source_component_type == destination_component_type)) {
2807*795d594fSAndroid Build Coastguard Worker ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
2808*795d594fSAndroid Build Coastguard Worker PointerSize image_size = class_linker->GetImagePointerSize();
2809*795d594fSAndroid Build Coastguard Worker HInvokeStaticOrDirect* invoke = instruction->AsInvokeStaticOrDirect();
2810*795d594fSAndroid Build Coastguard Worker ObjPtr<mirror::Class> system = invoke->GetResolvedMethod()->GetDeclaringClass();
2811*795d594fSAndroid Build Coastguard Worker ArtMethod* method = nullptr;
2812*795d594fSAndroid Build Coastguard Worker switch (source_component_type) {
2813*795d594fSAndroid Build Coastguard Worker case DataType::Type::kBool:
2814*795d594fSAndroid Build Coastguard Worker method = system->FindClassMethod("arraycopy", "([ZI[ZII)V", image_size);
2815*795d594fSAndroid Build Coastguard Worker break;
2816*795d594fSAndroid Build Coastguard Worker case DataType::Type::kInt8:
2817*795d594fSAndroid Build Coastguard Worker method = system->FindClassMethod("arraycopy", "([BI[BII)V", image_size);
2818*795d594fSAndroid Build Coastguard Worker break;
2819*795d594fSAndroid Build Coastguard Worker case DataType::Type::kUint16:
2820*795d594fSAndroid Build Coastguard Worker method = system->FindClassMethod("arraycopy", "([CI[CII)V", image_size);
2821*795d594fSAndroid Build Coastguard Worker break;
2822*795d594fSAndroid Build Coastguard Worker case DataType::Type::kInt16:
2823*795d594fSAndroid Build Coastguard Worker method = system->FindClassMethod("arraycopy", "([SI[SII)V", image_size);
2824*795d594fSAndroid Build Coastguard Worker break;
2825*795d594fSAndroid Build Coastguard Worker case DataType::Type::kInt32:
2826*795d594fSAndroid Build Coastguard Worker method = system->FindClassMethod("arraycopy", "([II[III)V", image_size);
2827*795d594fSAndroid Build Coastguard Worker break;
2828*795d594fSAndroid Build Coastguard Worker case DataType::Type::kFloat32:
2829*795d594fSAndroid Build Coastguard Worker method = system->FindClassMethod("arraycopy", "([FI[FII)V", image_size);
2830*795d594fSAndroid Build Coastguard Worker break;
2831*795d594fSAndroid Build Coastguard Worker case DataType::Type::kInt64:
2832*795d594fSAndroid Build Coastguard Worker method = system->FindClassMethod("arraycopy", "([JI[JII)V", image_size);
2833*795d594fSAndroid Build Coastguard Worker break;
2834*795d594fSAndroid Build Coastguard Worker case DataType::Type::kFloat64:
2835*795d594fSAndroid Build Coastguard Worker method = system->FindClassMethod("arraycopy", "([DI[DII)V", image_size);
2836*795d594fSAndroid Build Coastguard Worker break;
2837*795d594fSAndroid Build Coastguard Worker default:
2838*795d594fSAndroid Build Coastguard Worker LOG(FATAL) << "Unreachable";
2839*795d594fSAndroid Build Coastguard Worker }
2840*795d594fSAndroid Build Coastguard Worker DCHECK(method != nullptr);
2841*795d594fSAndroid Build Coastguard Worker DCHECK(method->IsStatic());
2842*795d594fSAndroid Build Coastguard Worker DCHECK(method->GetDeclaringClass() == system);
2843*795d594fSAndroid Build Coastguard Worker invoke->SetResolvedMethod(method, !codegen_->GetGraph()->IsDebuggable());
2844*795d594fSAndroid Build Coastguard Worker // Sharpen the new invoke. Note that we do not update the dex method index of
2845*795d594fSAndroid Build Coastguard Worker // the invoke, as we would need to look it up in the current dex file, and it
2846*795d594fSAndroid Build Coastguard Worker // is unlikely that it exists. The most usual situation for such typed
2847*795d594fSAndroid Build Coastguard Worker // arraycopy methods is a direct pointer to the boot image.
2848*795d594fSAndroid Build Coastguard Worker invoke->SetDispatchInfo(HSharpening::SharpenLoadMethod(
2849*795d594fSAndroid Build Coastguard Worker method,
2850*795d594fSAndroid Build Coastguard Worker /* has_method_id= */ true,
2851*795d594fSAndroid Build Coastguard Worker /* for_interface_call= */ false,
2852*795d594fSAndroid Build Coastguard Worker codegen_));
2853*795d594fSAndroid Build Coastguard Worker }
2854*795d594fSAndroid Build Coastguard Worker }
2855*795d594fSAndroid Build Coastguard Worker }
2856*795d594fSAndroid Build Coastguard Worker
SimplifyFP2Int(HInvoke * invoke)2857*795d594fSAndroid Build Coastguard Worker void InstructionSimplifierVisitor::SimplifyFP2Int(HInvoke* invoke) {
2858*795d594fSAndroid Build Coastguard Worker DCHECK(invoke->IsInvokeStaticOrDirect());
2859*795d594fSAndroid Build Coastguard Worker uint32_t dex_pc = invoke->GetDexPc();
2860*795d594fSAndroid Build Coastguard Worker HInstruction* x = invoke->InputAt(0);
2861*795d594fSAndroid Build Coastguard Worker DataType::Type type = x->GetType();
2862*795d594fSAndroid Build Coastguard Worker // Set proper bit pattern for NaN and replace intrinsic with raw version.
2863*795d594fSAndroid Build Coastguard Worker HInstruction* nan;
2864*795d594fSAndroid Build Coastguard Worker if (type == DataType::Type::kFloat64) {
2865*795d594fSAndroid Build Coastguard Worker nan = GetGraph()->GetLongConstant(0x7ff8000000000000L);
2866*795d594fSAndroid Build Coastguard Worker invoke->SetIntrinsic(Intrinsics::kDoubleDoubleToRawLongBits,
2867*795d594fSAndroid Build Coastguard Worker kNeedsEnvironment,
2868*795d594fSAndroid Build Coastguard Worker kNoSideEffects,
2869*795d594fSAndroid Build Coastguard Worker kNoThrow);
2870*795d594fSAndroid Build Coastguard Worker } else {
2871*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(type, DataType::Type::kFloat32);
2872*795d594fSAndroid Build Coastguard Worker nan = GetGraph()->GetIntConstant(0x7fc00000);
2873*795d594fSAndroid Build Coastguard Worker invoke->SetIntrinsic(Intrinsics::kFloatFloatToRawIntBits,
2874*795d594fSAndroid Build Coastguard Worker kNeedsEnvironment,
2875*795d594fSAndroid Build Coastguard Worker kNoSideEffects,
2876*795d594fSAndroid Build Coastguard Worker kNoThrow);
2877*795d594fSAndroid Build Coastguard Worker }
2878*795d594fSAndroid Build Coastguard Worker // Test IsNaN(x), which is the same as x != x.
2879*795d594fSAndroid Build Coastguard Worker HCondition* condition = new (GetGraph()->GetAllocator()) HNotEqual(x, x, dex_pc);
2880*795d594fSAndroid Build Coastguard Worker condition->SetBias(ComparisonBias::kLtBias);
2881*795d594fSAndroid Build Coastguard Worker invoke->GetBlock()->InsertInstructionBefore(condition, invoke->GetNext());
2882*795d594fSAndroid Build Coastguard Worker // Select between the two.
2883*795d594fSAndroid Build Coastguard Worker HInstruction* select = new (GetGraph()->GetAllocator()) HSelect(condition, nan, invoke, dex_pc);
2884*795d594fSAndroid Build Coastguard Worker invoke->GetBlock()->InsertInstructionBefore(select, condition->GetNext());
2885*795d594fSAndroid Build Coastguard Worker invoke->ReplaceWithExceptInReplacementAtIndex(select, 0); // false at index 0
2886*795d594fSAndroid Build Coastguard Worker }
2887*795d594fSAndroid Build Coastguard Worker
SimplifyStringCharAt(HInvoke * invoke)2888*795d594fSAndroid Build Coastguard Worker void InstructionSimplifierVisitor::SimplifyStringCharAt(HInvoke* invoke) {
2889*795d594fSAndroid Build Coastguard Worker HInstruction* str = invoke->InputAt(0);
2890*795d594fSAndroid Build Coastguard Worker HInstruction* index = invoke->InputAt(1);
2891*795d594fSAndroid Build Coastguard Worker uint32_t dex_pc = invoke->GetDexPc();
2892*795d594fSAndroid Build Coastguard Worker ArenaAllocator* allocator = GetGraph()->GetAllocator();
2893*795d594fSAndroid Build Coastguard Worker // We treat String as an array to allow DCE and BCE to seamlessly work on strings,
2894*795d594fSAndroid Build Coastguard Worker // so create the HArrayLength, HBoundsCheck and HArrayGet.
2895*795d594fSAndroid Build Coastguard Worker HArrayLength* length = new (allocator) HArrayLength(str, dex_pc, /* is_string_length= */ true);
2896*795d594fSAndroid Build Coastguard Worker invoke->GetBlock()->InsertInstructionBefore(length, invoke);
2897*795d594fSAndroid Build Coastguard Worker HBoundsCheck* bounds_check = new (allocator) HBoundsCheck(
2898*795d594fSAndroid Build Coastguard Worker index, length, dex_pc, /* is_string_char_at= */ true);
2899*795d594fSAndroid Build Coastguard Worker invoke->GetBlock()->InsertInstructionBefore(bounds_check, invoke);
2900*795d594fSAndroid Build Coastguard Worker HArrayGet* array_get = new (allocator) HArrayGet(str,
2901*795d594fSAndroid Build Coastguard Worker bounds_check,
2902*795d594fSAndroid Build Coastguard Worker DataType::Type::kUint16,
2903*795d594fSAndroid Build Coastguard Worker SideEffects::None(), // Strings are immutable.
2904*795d594fSAndroid Build Coastguard Worker dex_pc,
2905*795d594fSAndroid Build Coastguard Worker /* is_string_char_at= */ true);
2906*795d594fSAndroid Build Coastguard Worker invoke->GetBlock()->ReplaceAndRemoveInstructionWith(invoke, array_get);
2907*795d594fSAndroid Build Coastguard Worker bounds_check->CopyEnvironmentFrom(invoke->GetEnvironment());
2908*795d594fSAndroid Build Coastguard Worker GetGraph()->SetHasBoundsChecks(true);
2909*795d594fSAndroid Build Coastguard Worker }
2910*795d594fSAndroid Build Coastguard Worker
SimplifyStringLength(HInvoke * invoke)2911*795d594fSAndroid Build Coastguard Worker void InstructionSimplifierVisitor::SimplifyStringLength(HInvoke* invoke) {
2912*795d594fSAndroid Build Coastguard Worker HInstruction* str = invoke->InputAt(0);
2913*795d594fSAndroid Build Coastguard Worker uint32_t dex_pc = invoke->GetDexPc();
2914*795d594fSAndroid Build Coastguard Worker // We treat String as an array to allow DCE and BCE to seamlessly work on strings,
2915*795d594fSAndroid Build Coastguard Worker // so create the HArrayLength.
2916*795d594fSAndroid Build Coastguard Worker HArrayLength* length =
2917*795d594fSAndroid Build Coastguard Worker new (GetGraph()->GetAllocator()) HArrayLength(str, dex_pc, /* is_string_length= */ true);
2918*795d594fSAndroid Build Coastguard Worker invoke->GetBlock()->ReplaceAndRemoveInstructionWith(invoke, length);
2919*795d594fSAndroid Build Coastguard Worker }
2920*795d594fSAndroid Build Coastguard Worker
SimplifyStringIndexOf(HInvoke * invoke)2921*795d594fSAndroid Build Coastguard Worker void InstructionSimplifierVisitor::SimplifyStringIndexOf(HInvoke* invoke) {
2922*795d594fSAndroid Build Coastguard Worker DCHECK(invoke->GetIntrinsic() == Intrinsics::kStringIndexOf ||
2923*795d594fSAndroid Build Coastguard Worker invoke->GetIntrinsic() == Intrinsics::kStringIndexOfAfter);
2924*795d594fSAndroid Build Coastguard Worker if (invoke->InputAt(0)->IsLoadString()) {
2925*795d594fSAndroid Build Coastguard Worker HLoadString* load_string = invoke->InputAt(0)->AsLoadString();
2926*795d594fSAndroid Build Coastguard Worker const DexFile& dex_file = load_string->GetDexFile();
2927*795d594fSAndroid Build Coastguard Worker uint32_t utf16_length;
2928*795d594fSAndroid Build Coastguard Worker const char* data =
2929*795d594fSAndroid Build Coastguard Worker dex_file.GetStringDataAndUtf16Length(load_string->GetStringIndex(), &utf16_length);
2930*795d594fSAndroid Build Coastguard Worker if (utf16_length == 0) {
2931*795d594fSAndroid Build Coastguard Worker invoke->ReplaceWith(GetGraph()->GetIntConstant(-1));
2932*795d594fSAndroid Build Coastguard Worker invoke->GetBlock()->RemoveInstruction(invoke);
2933*795d594fSAndroid Build Coastguard Worker RecordSimplification();
2934*795d594fSAndroid Build Coastguard Worker return;
2935*795d594fSAndroid Build Coastguard Worker }
2936*795d594fSAndroid Build Coastguard Worker if (utf16_length == 1 && invoke->GetIntrinsic() == Intrinsics::kStringIndexOf) {
2937*795d594fSAndroid Build Coastguard Worker // Simplify to HSelect(HEquals(., load_string.charAt(0)), 0, -1).
2938*795d594fSAndroid Build Coastguard Worker // If the sought character is supplementary, this gives the correct result, i.e. -1.
2939*795d594fSAndroid Build Coastguard Worker uint32_t c = GetUtf16FromUtf8(&data);
2940*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(GetTrailingUtf16Char(c), 0u);
2941*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(GetLeadingUtf16Char(c), c);
2942*795d594fSAndroid Build Coastguard Worker uint32_t dex_pc = invoke->GetDexPc();
2943*795d594fSAndroid Build Coastguard Worker ArenaAllocator* allocator = GetGraph()->GetAllocator();
2944*795d594fSAndroid Build Coastguard Worker HEqual* equal =
2945*795d594fSAndroid Build Coastguard Worker new (allocator) HEqual(invoke->InputAt(1), GetGraph()->GetIntConstant(c), dex_pc);
2946*795d594fSAndroid Build Coastguard Worker invoke->GetBlock()->InsertInstructionBefore(equal, invoke);
2947*795d594fSAndroid Build Coastguard Worker HSelect* result = new (allocator) HSelect(equal,
2948*795d594fSAndroid Build Coastguard Worker GetGraph()->GetIntConstant(0),
2949*795d594fSAndroid Build Coastguard Worker GetGraph()->GetIntConstant(-1),
2950*795d594fSAndroid Build Coastguard Worker dex_pc);
2951*795d594fSAndroid Build Coastguard Worker invoke->GetBlock()->ReplaceAndRemoveInstructionWith(invoke, result);
2952*795d594fSAndroid Build Coastguard Worker RecordSimplification();
2953*795d594fSAndroid Build Coastguard Worker return;
2954*795d594fSAndroid Build Coastguard Worker }
2955*795d594fSAndroid Build Coastguard Worker }
2956*795d594fSAndroid Build Coastguard Worker }
2957*795d594fSAndroid Build Coastguard Worker
2958*795d594fSAndroid Build Coastguard Worker // This method should only be used on intrinsics whose sole way of throwing an
2959*795d594fSAndroid Build Coastguard Worker // exception is raising a NPE when the nth argument is null. If that argument
2960*795d594fSAndroid Build Coastguard Worker // is provably non-null, we can clear the flag.
SimplifyNPEOnArgN(HInvoke * invoke,size_t n)2961*795d594fSAndroid Build Coastguard Worker void InstructionSimplifierVisitor::SimplifyNPEOnArgN(HInvoke* invoke, size_t n) {
2962*795d594fSAndroid Build Coastguard Worker HInstruction* arg = invoke->InputAt(n);
2963*795d594fSAndroid Build Coastguard Worker if (invoke->CanThrow() && !arg->CanBeNull()) {
2964*795d594fSAndroid Build Coastguard Worker invoke->SetCanThrow(false);
2965*795d594fSAndroid Build Coastguard Worker }
2966*795d594fSAndroid Build Coastguard Worker }
2967*795d594fSAndroid Build Coastguard Worker
2968*795d594fSAndroid Build Coastguard Worker // Methods that return "this" can replace the returned value with the receiver.
SimplifyReturnThis(HInvoke * invoke)2969*795d594fSAndroid Build Coastguard Worker void InstructionSimplifierVisitor::SimplifyReturnThis(HInvoke* invoke) {
2970*795d594fSAndroid Build Coastguard Worker if (invoke->HasUses()) {
2971*795d594fSAndroid Build Coastguard Worker HInstruction* receiver = invoke->InputAt(0);
2972*795d594fSAndroid Build Coastguard Worker invoke->ReplaceWith(receiver);
2973*795d594fSAndroid Build Coastguard Worker RecordSimplification();
2974*795d594fSAndroid Build Coastguard Worker }
2975*795d594fSAndroid Build Coastguard Worker }
2976*795d594fSAndroid Build Coastguard Worker
2977*795d594fSAndroid Build Coastguard Worker // Helper method for StringBuffer escape analysis.
NoEscapeForStringBufferReference(HInstruction * reference,HInstruction * user)2978*795d594fSAndroid Build Coastguard Worker static bool NoEscapeForStringBufferReference(HInstruction* reference, HInstruction* user) {
2979*795d594fSAndroid Build Coastguard Worker if (user->IsInvoke()) {
2980*795d594fSAndroid Build Coastguard Worker switch (user->AsInvoke()->GetIntrinsic()) {
2981*795d594fSAndroid Build Coastguard Worker case Intrinsics::kStringBufferLength:
2982*795d594fSAndroid Build Coastguard Worker case Intrinsics::kStringBufferToString:
2983*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(user->InputAt(0), reference);
2984*795d594fSAndroid Build Coastguard Worker return true;
2985*795d594fSAndroid Build Coastguard Worker case Intrinsics::kStringBufferAppend:
2986*795d594fSAndroid Build Coastguard Worker // Returns "this", so only okay if no further uses.
2987*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(user->InputAt(0), reference);
2988*795d594fSAndroid Build Coastguard Worker DCHECK_NE(user->InputAt(1), reference);
2989*795d594fSAndroid Build Coastguard Worker return !user->HasUses();
2990*795d594fSAndroid Build Coastguard Worker default:
2991*795d594fSAndroid Build Coastguard Worker break;
2992*795d594fSAndroid Build Coastguard Worker }
2993*795d594fSAndroid Build Coastguard Worker }
2994*795d594fSAndroid Build Coastguard Worker
2995*795d594fSAndroid Build Coastguard Worker if (user->IsInvokeStaticOrDirect()) {
2996*795d594fSAndroid Build Coastguard Worker // Any constructor on StringBuffer is okay.
2997*795d594fSAndroid Build Coastguard Worker return user->AsInvokeStaticOrDirect()->GetResolvedMethod() != nullptr &&
2998*795d594fSAndroid Build Coastguard Worker user->AsInvokeStaticOrDirect()->GetResolvedMethod()->IsConstructor() &&
2999*795d594fSAndroid Build Coastguard Worker user->InputAt(0) == reference;
3000*795d594fSAndroid Build Coastguard Worker }
3001*795d594fSAndroid Build Coastguard Worker
3002*795d594fSAndroid Build Coastguard Worker return false;
3003*795d594fSAndroid Build Coastguard Worker }
3004*795d594fSAndroid Build Coastguard Worker
TryReplaceStringBuilderAppend(CodeGenerator * codegen,HInvoke * invoke)3005*795d594fSAndroid Build Coastguard Worker static bool TryReplaceStringBuilderAppend(CodeGenerator* codegen, HInvoke* invoke) {
3006*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(invoke->GetIntrinsic(), Intrinsics::kStringBuilderToString);
3007*795d594fSAndroid Build Coastguard Worker if (invoke->CanThrowIntoCatchBlock()) {
3008*795d594fSAndroid Build Coastguard Worker return false;
3009*795d594fSAndroid Build Coastguard Worker }
3010*795d594fSAndroid Build Coastguard Worker
3011*795d594fSAndroid Build Coastguard Worker HBasicBlock* block = invoke->GetBlock();
3012*795d594fSAndroid Build Coastguard Worker HInstruction* sb = invoke->InputAt(0);
3013*795d594fSAndroid Build Coastguard Worker
3014*795d594fSAndroid Build Coastguard Worker // We support only a new StringBuilder, otherwise we cannot ensure that
3015*795d594fSAndroid Build Coastguard Worker // the StringBuilder data does not need to be populated for other users.
3016*795d594fSAndroid Build Coastguard Worker if (!sb->IsNewInstance()) {
3017*795d594fSAndroid Build Coastguard Worker return false;
3018*795d594fSAndroid Build Coastguard Worker }
3019*795d594fSAndroid Build Coastguard Worker
3020*795d594fSAndroid Build Coastguard Worker // For now, we support only single-block recognition.
3021*795d594fSAndroid Build Coastguard Worker // (Ternary operators feeding the append could be implemented.)
3022*795d594fSAndroid Build Coastguard Worker for (const HUseListNode<HInstruction*>& use : sb->GetUses()) {
3023*795d594fSAndroid Build Coastguard Worker if (use.GetUser()->GetBlock() != block) {
3024*795d594fSAndroid Build Coastguard Worker return false;
3025*795d594fSAndroid Build Coastguard Worker }
3026*795d594fSAndroid Build Coastguard Worker // The append pattern uses the StringBuilder only as the first argument.
3027*795d594fSAndroid Build Coastguard Worker if (use.GetIndex() != 0u) {
3028*795d594fSAndroid Build Coastguard Worker return false;
3029*795d594fSAndroid Build Coastguard Worker }
3030*795d594fSAndroid Build Coastguard Worker }
3031*795d594fSAndroid Build Coastguard Worker
3032*795d594fSAndroid Build Coastguard Worker // Collect args and check for unexpected uses.
3033*795d594fSAndroid Build Coastguard Worker // We expect one call to a constructor with no arguments, one constructor fence (unless
3034*795d594fSAndroid Build Coastguard Worker // eliminated), some number of append calls and one call to StringBuilder.toString().
3035*795d594fSAndroid Build Coastguard Worker bool seen_constructor = false;
3036*795d594fSAndroid Build Coastguard Worker bool seen_constructor_fence = false;
3037*795d594fSAndroid Build Coastguard Worker bool seen_to_string = false;
3038*795d594fSAndroid Build Coastguard Worker uint32_t format = 0u;
3039*795d594fSAndroid Build Coastguard Worker uint32_t num_args = 0u;
3040*795d594fSAndroid Build Coastguard Worker bool has_fp_args = false;
3041*795d594fSAndroid Build Coastguard Worker HInstruction* args[StringBuilderAppend::kMaxArgs]; // Added in reverse order.
3042*795d594fSAndroid Build Coastguard Worker for (HBackwardInstructionIterator iter(block->GetInstructions()); !iter.Done(); iter.Advance()) {
3043*795d594fSAndroid Build Coastguard Worker HInstruction* user = iter.Current();
3044*795d594fSAndroid Build Coastguard Worker // Instructions of interest apply to `sb`, skip those that do not involve `sb`.
3045*795d594fSAndroid Build Coastguard Worker if (user->InputCount() == 0u || user->InputAt(0u) != sb) {
3046*795d594fSAndroid Build Coastguard Worker continue;
3047*795d594fSAndroid Build Coastguard Worker }
3048*795d594fSAndroid Build Coastguard Worker // We visit the uses in reverse order, so the StringBuilder.toString() must come first.
3049*795d594fSAndroid Build Coastguard Worker if (!seen_to_string) {
3050*795d594fSAndroid Build Coastguard Worker if (user == invoke) {
3051*795d594fSAndroid Build Coastguard Worker seen_to_string = true;
3052*795d594fSAndroid Build Coastguard Worker continue;
3053*795d594fSAndroid Build Coastguard Worker } else {
3054*795d594fSAndroid Build Coastguard Worker return false;
3055*795d594fSAndroid Build Coastguard Worker }
3056*795d594fSAndroid Build Coastguard Worker }
3057*795d594fSAndroid Build Coastguard Worker
3058*795d594fSAndroid Build Coastguard Worker // Pattern match seeing arguments, then constructor, then constructor fence.
3059*795d594fSAndroid Build Coastguard Worker if (user->IsInvokeStaticOrDirect() &&
3060*795d594fSAndroid Build Coastguard Worker user->AsInvokeStaticOrDirect()->GetResolvedMethod() != nullptr &&
3061*795d594fSAndroid Build Coastguard Worker user->AsInvokeStaticOrDirect()->GetResolvedMethod()->IsConstructor() &&
3062*795d594fSAndroid Build Coastguard Worker user->AsInvokeStaticOrDirect()->GetNumberOfArguments() == 1u) {
3063*795d594fSAndroid Build Coastguard Worker // After arguments, we should see the constructor.
3064*795d594fSAndroid Build Coastguard Worker // We accept only the constructor with no extra arguments.
3065*795d594fSAndroid Build Coastguard Worker DCHECK(!seen_constructor);
3066*795d594fSAndroid Build Coastguard Worker DCHECK(!seen_constructor_fence);
3067*795d594fSAndroid Build Coastguard Worker seen_constructor = true;
3068*795d594fSAndroid Build Coastguard Worker } else if (user->IsInvoke()) {
3069*795d594fSAndroid Build Coastguard Worker // The arguments.
3070*795d594fSAndroid Build Coastguard Worker HInvoke* as_invoke = user->AsInvoke();
3071*795d594fSAndroid Build Coastguard Worker DCHECK(!seen_constructor);
3072*795d594fSAndroid Build Coastguard Worker DCHECK(!seen_constructor_fence);
3073*795d594fSAndroid Build Coastguard Worker StringBuilderAppend::Argument arg;
3074*795d594fSAndroid Build Coastguard Worker switch (as_invoke->GetIntrinsic()) {
3075*795d594fSAndroid Build Coastguard Worker case Intrinsics::kStringBuilderAppendObject:
3076*795d594fSAndroid Build Coastguard Worker // TODO: Unimplemented, needs to call String.valueOf().
3077*795d594fSAndroid Build Coastguard Worker return false;
3078*795d594fSAndroid Build Coastguard Worker case Intrinsics::kStringBuilderAppendString:
3079*795d594fSAndroid Build Coastguard Worker arg = StringBuilderAppend::Argument::kString;
3080*795d594fSAndroid Build Coastguard Worker break;
3081*795d594fSAndroid Build Coastguard Worker case Intrinsics::kStringBuilderAppendCharArray:
3082*795d594fSAndroid Build Coastguard Worker // TODO: Unimplemented, StringBuilder.append(char[]) can throw NPE and we would
3083*795d594fSAndroid Build Coastguard Worker // not have the correct stack trace for it.
3084*795d594fSAndroid Build Coastguard Worker return false;
3085*795d594fSAndroid Build Coastguard Worker case Intrinsics::kStringBuilderAppendBoolean:
3086*795d594fSAndroid Build Coastguard Worker arg = StringBuilderAppend::Argument::kBoolean;
3087*795d594fSAndroid Build Coastguard Worker break;
3088*795d594fSAndroid Build Coastguard Worker case Intrinsics::kStringBuilderAppendChar:
3089*795d594fSAndroid Build Coastguard Worker arg = StringBuilderAppend::Argument::kChar;
3090*795d594fSAndroid Build Coastguard Worker break;
3091*795d594fSAndroid Build Coastguard Worker case Intrinsics::kStringBuilderAppendInt:
3092*795d594fSAndroid Build Coastguard Worker arg = StringBuilderAppend::Argument::kInt;
3093*795d594fSAndroid Build Coastguard Worker break;
3094*795d594fSAndroid Build Coastguard Worker case Intrinsics::kStringBuilderAppendLong:
3095*795d594fSAndroid Build Coastguard Worker arg = StringBuilderAppend::Argument::kLong;
3096*795d594fSAndroid Build Coastguard Worker break;
3097*795d594fSAndroid Build Coastguard Worker case Intrinsics::kStringBuilderAppendFloat:
3098*795d594fSAndroid Build Coastguard Worker arg = StringBuilderAppend::Argument::kFloat;
3099*795d594fSAndroid Build Coastguard Worker has_fp_args = true;
3100*795d594fSAndroid Build Coastguard Worker break;
3101*795d594fSAndroid Build Coastguard Worker case Intrinsics::kStringBuilderAppendDouble:
3102*795d594fSAndroid Build Coastguard Worker arg = StringBuilderAppend::Argument::kDouble;
3103*795d594fSAndroid Build Coastguard Worker has_fp_args = true;
3104*795d594fSAndroid Build Coastguard Worker break;
3105*795d594fSAndroid Build Coastguard Worker case Intrinsics::kStringBuilderAppendCharSequence: {
3106*795d594fSAndroid Build Coastguard Worker ReferenceTypeInfo rti = as_invoke->InputAt(1)->GetReferenceTypeInfo();
3107*795d594fSAndroid Build Coastguard Worker if (!rti.IsValid()) {
3108*795d594fSAndroid Build Coastguard Worker return false;
3109*795d594fSAndroid Build Coastguard Worker }
3110*795d594fSAndroid Build Coastguard Worker ScopedObjectAccess soa(Thread::Current());
3111*795d594fSAndroid Build Coastguard Worker Handle<mirror::Class> input_type = rti.GetTypeHandle();
3112*795d594fSAndroid Build Coastguard Worker DCHECK(input_type != nullptr);
3113*795d594fSAndroid Build Coastguard Worker if (input_type.Get() == GetClassRoot<mirror::String>()) {
3114*795d594fSAndroid Build Coastguard Worker arg = StringBuilderAppend::Argument::kString;
3115*795d594fSAndroid Build Coastguard Worker } else {
3116*795d594fSAndroid Build Coastguard Worker // TODO: Check and implement for StringBuilder. We could find the StringBuilder's
3117*795d594fSAndroid Build Coastguard Worker // internal char[] inconsistent with the length, or the string compression
3118*795d594fSAndroid Build Coastguard Worker // of the result could be compromised with a concurrent modification, and
3119*795d594fSAndroid Build Coastguard Worker // we would need to throw appropriate exceptions.
3120*795d594fSAndroid Build Coastguard Worker return false;
3121*795d594fSAndroid Build Coastguard Worker }
3122*795d594fSAndroid Build Coastguard Worker break;
3123*795d594fSAndroid Build Coastguard Worker }
3124*795d594fSAndroid Build Coastguard Worker default: {
3125*795d594fSAndroid Build Coastguard Worker return false;
3126*795d594fSAndroid Build Coastguard Worker }
3127*795d594fSAndroid Build Coastguard Worker }
3128*795d594fSAndroid Build Coastguard Worker // Uses of the append return value should have been replaced with the first input.
3129*795d594fSAndroid Build Coastguard Worker DCHECK(!as_invoke->HasUses());
3130*795d594fSAndroid Build Coastguard Worker DCHECK(!as_invoke->HasEnvironmentUses());
3131*795d594fSAndroid Build Coastguard Worker if (num_args == StringBuilderAppend::kMaxArgs) {
3132*795d594fSAndroid Build Coastguard Worker return false;
3133*795d594fSAndroid Build Coastguard Worker }
3134*795d594fSAndroid Build Coastguard Worker format = (format << StringBuilderAppend::kBitsPerArg) | static_cast<uint32_t>(arg);
3135*795d594fSAndroid Build Coastguard Worker args[num_args] = as_invoke->InputAt(1u);
3136*795d594fSAndroid Build Coastguard Worker ++num_args;
3137*795d594fSAndroid Build Coastguard Worker } else if (user->IsConstructorFence()) {
3138*795d594fSAndroid Build Coastguard Worker // The last use we see is the constructor fence.
3139*795d594fSAndroid Build Coastguard Worker DCHECK(seen_constructor);
3140*795d594fSAndroid Build Coastguard Worker DCHECK(!seen_constructor_fence);
3141*795d594fSAndroid Build Coastguard Worker seen_constructor_fence = true;
3142*795d594fSAndroid Build Coastguard Worker } else {
3143*795d594fSAndroid Build Coastguard Worker return false;
3144*795d594fSAndroid Build Coastguard Worker }
3145*795d594fSAndroid Build Coastguard Worker }
3146*795d594fSAndroid Build Coastguard Worker
3147*795d594fSAndroid Build Coastguard Worker if (num_args == 0u) {
3148*795d594fSAndroid Build Coastguard Worker return false;
3149*795d594fSAndroid Build Coastguard Worker }
3150*795d594fSAndroid Build Coastguard Worker
3151*795d594fSAndroid Build Coastguard Worker // Check environment uses.
3152*795d594fSAndroid Build Coastguard Worker for (const HUseListNode<HEnvironment*>& use : sb->GetEnvUses()) {
3153*795d594fSAndroid Build Coastguard Worker HInstruction* holder = use.GetUser()->GetHolder();
3154*795d594fSAndroid Build Coastguard Worker if (holder->GetBlock() != block) {
3155*795d594fSAndroid Build Coastguard Worker return false;
3156*795d594fSAndroid Build Coastguard Worker }
3157*795d594fSAndroid Build Coastguard Worker // Accept only calls on the StringBuilder (which shall all be removed).
3158*795d594fSAndroid Build Coastguard Worker // TODO: Carve-out for const-string? Or rely on environment pruning (to be implemented)?
3159*795d594fSAndroid Build Coastguard Worker if (holder->InputCount() == 0 || holder->InputAt(0) != sb) {
3160*795d594fSAndroid Build Coastguard Worker return false;
3161*795d594fSAndroid Build Coastguard Worker }
3162*795d594fSAndroid Build Coastguard Worker }
3163*795d594fSAndroid Build Coastguard Worker
3164*795d594fSAndroid Build Coastguard Worker // Calculate outgoing vregs, including padding for 64-bit arg alignment.
3165*795d594fSAndroid Build Coastguard Worker const PointerSize pointer_size = InstructionSetPointerSize(codegen->GetInstructionSet());
3166*795d594fSAndroid Build Coastguard Worker const size_t method_vregs = static_cast<size_t>(pointer_size) / kVRegSize;
3167*795d594fSAndroid Build Coastguard Worker uint32_t number_of_out_vregs = method_vregs; // For correct alignment padding; subtracted below.
3168*795d594fSAndroid Build Coastguard Worker for (uint32_t f = format; f != 0u; f >>= StringBuilderAppend::kBitsPerArg) {
3169*795d594fSAndroid Build Coastguard Worker auto a = enum_cast<StringBuilderAppend::Argument>(f & StringBuilderAppend::kArgMask);
3170*795d594fSAndroid Build Coastguard Worker if (a == StringBuilderAppend::Argument::kLong || a == StringBuilderAppend::Argument::kDouble) {
3171*795d594fSAndroid Build Coastguard Worker number_of_out_vregs += /* alignment */ ((number_of_out_vregs) & 1u) + /* vregs */ 2u;
3172*795d594fSAndroid Build Coastguard Worker } else {
3173*795d594fSAndroid Build Coastguard Worker number_of_out_vregs += /* vregs */ 1u;
3174*795d594fSAndroid Build Coastguard Worker }
3175*795d594fSAndroid Build Coastguard Worker }
3176*795d594fSAndroid Build Coastguard Worker number_of_out_vregs -= method_vregs;
3177*795d594fSAndroid Build Coastguard Worker
3178*795d594fSAndroid Build Coastguard Worker // Create replacement instruction.
3179*795d594fSAndroid Build Coastguard Worker HIntConstant* fmt = block->GetGraph()->GetIntConstant(static_cast<int32_t>(format));
3180*795d594fSAndroid Build Coastguard Worker ArenaAllocator* allocator = block->GetGraph()->GetAllocator();
3181*795d594fSAndroid Build Coastguard Worker HStringBuilderAppend* append = new (allocator) HStringBuilderAppend(
3182*795d594fSAndroid Build Coastguard Worker fmt, num_args, number_of_out_vregs, has_fp_args, allocator, invoke->GetDexPc());
3183*795d594fSAndroid Build Coastguard Worker append->SetReferenceTypeInfoIfValid(invoke->GetReferenceTypeInfo());
3184*795d594fSAndroid Build Coastguard Worker for (size_t i = 0; i != num_args; ++i) {
3185*795d594fSAndroid Build Coastguard Worker append->SetArgumentAt(i, args[num_args - 1u - i]);
3186*795d594fSAndroid Build Coastguard Worker }
3187*795d594fSAndroid Build Coastguard Worker block->InsertInstructionBefore(append, invoke);
3188*795d594fSAndroid Build Coastguard Worker DCHECK(!invoke->CanBeNull());
3189*795d594fSAndroid Build Coastguard Worker DCHECK(!append->CanBeNull());
3190*795d594fSAndroid Build Coastguard Worker invoke->ReplaceWith(append);
3191*795d594fSAndroid Build Coastguard Worker // Copy environment, except for the StringBuilder uses.
3192*795d594fSAndroid Build Coastguard Worker for (HEnvironment* env = invoke->GetEnvironment(); env != nullptr; env = env->GetParent()) {
3193*795d594fSAndroid Build Coastguard Worker for (size_t i = 0, size = env->Size(); i != size; ++i) {
3194*795d594fSAndroid Build Coastguard Worker if (env->GetInstructionAt(i) == sb) {
3195*795d594fSAndroid Build Coastguard Worker env->RemoveAsUserOfInput(i);
3196*795d594fSAndroid Build Coastguard Worker env->SetRawEnvAt(i, /*instruction=*/ nullptr);
3197*795d594fSAndroid Build Coastguard Worker }
3198*795d594fSAndroid Build Coastguard Worker }
3199*795d594fSAndroid Build Coastguard Worker }
3200*795d594fSAndroid Build Coastguard Worker append->CopyEnvironmentFrom(invoke->GetEnvironment());
3201*795d594fSAndroid Build Coastguard Worker // Remove the old instruction.
3202*795d594fSAndroid Build Coastguard Worker block->RemoveInstruction(invoke);
3203*795d594fSAndroid Build Coastguard Worker // Remove the StringBuilder's uses and StringBuilder.
3204*795d594fSAndroid Build Coastguard Worker while (sb->HasNonEnvironmentUses()) {
3205*795d594fSAndroid Build Coastguard Worker block->RemoveInstruction(sb->GetUses().front().GetUser());
3206*795d594fSAndroid Build Coastguard Worker }
3207*795d594fSAndroid Build Coastguard Worker DCHECK(!sb->HasEnvironmentUses());
3208*795d594fSAndroid Build Coastguard Worker block->RemoveInstruction(sb);
3209*795d594fSAndroid Build Coastguard Worker return true;
3210*795d594fSAndroid Build Coastguard Worker }
3211*795d594fSAndroid Build Coastguard Worker
3212*795d594fSAndroid Build Coastguard Worker // Certain allocation intrinsics are not removed by dead code elimination
3213*795d594fSAndroid Build Coastguard Worker // because of potentially throwing an OOM exception or other side effects.
3214*795d594fSAndroid Build Coastguard Worker // This method removes such intrinsics when special circumstances allow.
SimplifyAllocationIntrinsic(HInvoke * invoke)3215*795d594fSAndroid Build Coastguard Worker void InstructionSimplifierVisitor::SimplifyAllocationIntrinsic(HInvoke* invoke) {
3216*795d594fSAndroid Build Coastguard Worker if (!invoke->HasUses()) {
3217*795d594fSAndroid Build Coastguard Worker // Instruction has no uses. If unsynchronized, we can remove right away, safely ignoring
3218*795d594fSAndroid Build Coastguard Worker // the potential OOM of course. Otherwise, we must ensure the receiver object of this
3219*795d594fSAndroid Build Coastguard Worker // call does not escape since only thread-local synchronization may be removed.
3220*795d594fSAndroid Build Coastguard Worker bool is_synchronized = invoke->GetIntrinsic() == Intrinsics::kStringBufferToString;
3221*795d594fSAndroid Build Coastguard Worker HInstruction* receiver = invoke->InputAt(0);
3222*795d594fSAndroid Build Coastguard Worker if (!is_synchronized || DoesNotEscape(receiver, NoEscapeForStringBufferReference)) {
3223*795d594fSAndroid Build Coastguard Worker invoke->GetBlock()->RemoveInstruction(invoke);
3224*795d594fSAndroid Build Coastguard Worker RecordSimplification();
3225*795d594fSAndroid Build Coastguard Worker }
3226*795d594fSAndroid Build Coastguard Worker } else if (invoke->GetIntrinsic() == Intrinsics::kStringBuilderToString &&
3227*795d594fSAndroid Build Coastguard Worker TryReplaceStringBuilderAppend(codegen_, invoke)) {
3228*795d594fSAndroid Build Coastguard Worker RecordSimplification();
3229*795d594fSAndroid Build Coastguard Worker }
3230*795d594fSAndroid Build Coastguard Worker }
3231*795d594fSAndroid Build Coastguard Worker
SimplifyVarHandleIntrinsic(HInvoke * invoke)3232*795d594fSAndroid Build Coastguard Worker void InstructionSimplifierVisitor::SimplifyVarHandleIntrinsic(HInvoke* invoke) {
3233*795d594fSAndroid Build Coastguard Worker DCHECK(invoke->IsInvokePolymorphic());
3234*795d594fSAndroid Build Coastguard Worker VarHandleOptimizations optimizations(invoke);
3235*795d594fSAndroid Build Coastguard Worker
3236*795d594fSAndroid Build Coastguard Worker if (optimizations.GetDoNotIntrinsify()) {
3237*795d594fSAndroid Build Coastguard Worker // Preceding static checks disabled intrinsic, so no need to analyze further.
3238*795d594fSAndroid Build Coastguard Worker return;
3239*795d594fSAndroid Build Coastguard Worker }
3240*795d594fSAndroid Build Coastguard Worker
3241*795d594fSAndroid Build Coastguard Worker size_t expected_coordinates_count = GetExpectedVarHandleCoordinatesCount(invoke);
3242*795d594fSAndroid Build Coastguard Worker if (expected_coordinates_count != 0u) {
3243*795d594fSAndroid Build Coastguard Worker HInstruction* object = invoke->InputAt(1);
3244*795d594fSAndroid Build Coastguard Worker // The following has been ensured by static checks in the instruction builder.
3245*795d594fSAndroid Build Coastguard Worker DCHECK(object->GetType() == DataType::Type::kReference);
3246*795d594fSAndroid Build Coastguard Worker // Re-check for null constant, as this might have changed after the inliner.
3247*795d594fSAndroid Build Coastguard Worker if (object->IsNullConstant()) {
3248*795d594fSAndroid Build Coastguard Worker optimizations.SetDoNotIntrinsify();
3249*795d594fSAndroid Build Coastguard Worker return;
3250*795d594fSAndroid Build Coastguard Worker }
3251*795d594fSAndroid Build Coastguard Worker // Test whether we can avoid the null check on the object.
3252*795d594fSAndroid Build Coastguard Worker if (CanEnsureNotNullAt(object, invoke)) {
3253*795d594fSAndroid Build Coastguard Worker optimizations.SetSkipObjectNullCheck();
3254*795d594fSAndroid Build Coastguard Worker }
3255*795d594fSAndroid Build Coastguard Worker }
3256*795d594fSAndroid Build Coastguard Worker
3257*795d594fSAndroid Build Coastguard Worker if (CanUseKnownImageVarHandle(invoke)) {
3258*795d594fSAndroid Build Coastguard Worker optimizations.SetUseKnownImageVarHandle();
3259*795d594fSAndroid Build Coastguard Worker }
3260*795d594fSAndroid Build Coastguard Worker }
3261*795d594fSAndroid Build Coastguard Worker
CanUseKnownImageVarHandle(HInvoke * invoke)3262*795d594fSAndroid Build Coastguard Worker bool InstructionSimplifierVisitor::CanUseKnownImageVarHandle(HInvoke* invoke) {
3263*795d594fSAndroid Build Coastguard Worker // If the `VarHandle` comes from a static final field of an initialized class in an image
3264*795d594fSAndroid Build Coastguard Worker // (boot image or app image), we can do the checks at compile time. We do this optimization
3265*795d594fSAndroid Build Coastguard Worker // only for AOT and only for field handles when we can avoid all checks. This avoids the
3266*795d594fSAndroid Build Coastguard Worker // possibility of the code concurrently messing with the `VarHandle` using reflection,
3267*795d594fSAndroid Build Coastguard Worker // we simply perform the operation with the `VarHandle` as seen at compile time.
3268*795d594fSAndroid Build Coastguard Worker // TODO: Extend this to arrays to support the `AtomicIntegerArray` class.
3269*795d594fSAndroid Build Coastguard Worker const CompilerOptions& compiler_options = codegen_->GetCompilerOptions();
3270*795d594fSAndroid Build Coastguard Worker if (!compiler_options.IsAotCompiler()) {
3271*795d594fSAndroid Build Coastguard Worker return false;
3272*795d594fSAndroid Build Coastguard Worker }
3273*795d594fSAndroid Build Coastguard Worker size_t expected_coordinates_count = GetExpectedVarHandleCoordinatesCount(invoke);
3274*795d594fSAndroid Build Coastguard Worker if (expected_coordinates_count == 2u) {
3275*795d594fSAndroid Build Coastguard Worker return false;
3276*795d594fSAndroid Build Coastguard Worker }
3277*795d594fSAndroid Build Coastguard Worker HInstruction* var_handle_instruction = invoke->InputAt(0);
3278*795d594fSAndroid Build Coastguard Worker if (var_handle_instruction->IsNullCheck()) {
3279*795d594fSAndroid Build Coastguard Worker var_handle_instruction = var_handle_instruction->InputAt(0);
3280*795d594fSAndroid Build Coastguard Worker }
3281*795d594fSAndroid Build Coastguard Worker if (!var_handle_instruction->IsStaticFieldGet()) {
3282*795d594fSAndroid Build Coastguard Worker return false;
3283*795d594fSAndroid Build Coastguard Worker }
3284*795d594fSAndroid Build Coastguard Worker ArtField* field = var_handle_instruction->AsStaticFieldGet()->GetFieldInfo().GetField();
3285*795d594fSAndroid Build Coastguard Worker DCHECK(field->IsStatic());
3286*795d594fSAndroid Build Coastguard Worker if (!field->IsFinal()) {
3287*795d594fSAndroid Build Coastguard Worker return false;
3288*795d594fSAndroid Build Coastguard Worker }
3289*795d594fSAndroid Build Coastguard Worker ScopedObjectAccess soa(Thread::Current());
3290*795d594fSAndroid Build Coastguard Worker ObjPtr<mirror::Class> declaring_class = field->GetDeclaringClass();
3291*795d594fSAndroid Build Coastguard Worker if (!declaring_class->IsVisiblyInitialized()) {
3292*795d594fSAndroid Build Coastguard Worker // During AOT compilation, dex2oat ensures that initialized classes are visibly initialized.
3293*795d594fSAndroid Build Coastguard Worker DCHECK(!declaring_class->IsInitialized());
3294*795d594fSAndroid Build Coastguard Worker return false;
3295*795d594fSAndroid Build Coastguard Worker }
3296*795d594fSAndroid Build Coastguard Worker HInstruction* load_class = var_handle_instruction->InputAt(0);
3297*795d594fSAndroid Build Coastguard Worker if (kIsDebugBuild) {
3298*795d594fSAndroid Build Coastguard Worker bool is_in_image = false;
3299*795d594fSAndroid Build Coastguard Worker if (Runtime::Current()->GetHeap()->ObjectIsInBootImageSpace(declaring_class)) {
3300*795d594fSAndroid Build Coastguard Worker is_in_image = true;
3301*795d594fSAndroid Build Coastguard Worker } else if (compiler_options.IsGeneratingImage()) {
3302*795d594fSAndroid Build Coastguard Worker std::string storage;
3303*795d594fSAndroid Build Coastguard Worker const char* descriptor = declaring_class->GetDescriptor(&storage);
3304*795d594fSAndroid Build Coastguard Worker is_in_image = compiler_options.IsImageClass(descriptor);
3305*795d594fSAndroid Build Coastguard Worker }
3306*795d594fSAndroid Build Coastguard Worker CHECK_EQ(is_in_image, load_class->IsLoadClass() && load_class->AsLoadClass()->IsInImage());
3307*795d594fSAndroid Build Coastguard Worker }
3308*795d594fSAndroid Build Coastguard Worker if (!load_class->IsLoadClass() || !load_class->AsLoadClass()->IsInImage()) {
3309*795d594fSAndroid Build Coastguard Worker return false;
3310*795d594fSAndroid Build Coastguard Worker }
3311*795d594fSAndroid Build Coastguard Worker
3312*795d594fSAndroid Build Coastguard Worker // Get the `VarHandle` object and check its class.
3313*795d594fSAndroid Build Coastguard Worker ObjPtr<mirror::Class> expected_var_handle_class;
3314*795d594fSAndroid Build Coastguard Worker switch (expected_coordinates_count) {
3315*795d594fSAndroid Build Coastguard Worker case 0:
3316*795d594fSAndroid Build Coastguard Worker expected_var_handle_class = GetClassRoot<mirror::StaticFieldVarHandle>();
3317*795d594fSAndroid Build Coastguard Worker break;
3318*795d594fSAndroid Build Coastguard Worker default:
3319*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(expected_coordinates_count, 1u);
3320*795d594fSAndroid Build Coastguard Worker expected_var_handle_class = GetClassRoot<mirror::FieldVarHandle>();
3321*795d594fSAndroid Build Coastguard Worker break;
3322*795d594fSAndroid Build Coastguard Worker }
3323*795d594fSAndroid Build Coastguard Worker ObjPtr<mirror::Object> var_handle_object = field->GetObject(declaring_class);
3324*795d594fSAndroid Build Coastguard Worker if (var_handle_object == nullptr || var_handle_object->GetClass() != expected_var_handle_class) {
3325*795d594fSAndroid Build Coastguard Worker return false;
3326*795d594fSAndroid Build Coastguard Worker }
3327*795d594fSAndroid Build Coastguard Worker ObjPtr<mirror::VarHandle> var_handle = ObjPtr<mirror::VarHandle>::DownCast(var_handle_object);
3328*795d594fSAndroid Build Coastguard Worker
3329*795d594fSAndroid Build Coastguard Worker // Check access mode.
3330*795d594fSAndroid Build Coastguard Worker mirror::VarHandle::AccessMode access_mode =
3331*795d594fSAndroid Build Coastguard Worker mirror::VarHandle::GetAccessModeByIntrinsic(invoke->GetIntrinsic());
3332*795d594fSAndroid Build Coastguard Worker if (!var_handle->IsAccessModeSupported(access_mode)) {
3333*795d594fSAndroid Build Coastguard Worker return false;
3334*795d594fSAndroid Build Coastguard Worker }
3335*795d594fSAndroid Build Coastguard Worker
3336*795d594fSAndroid Build Coastguard Worker // Check argument types.
3337*795d594fSAndroid Build Coastguard Worker ObjPtr<mirror::Class> var_type = var_handle->GetVarType();
3338*795d594fSAndroid Build Coastguard Worker mirror::VarHandle::AccessModeTemplate access_mode_template =
3339*795d594fSAndroid Build Coastguard Worker mirror::VarHandle::GetAccessModeTemplate(access_mode);
3340*795d594fSAndroid Build Coastguard Worker // Note: The data type of input arguments does not need to match the type from shorty
3341*795d594fSAndroid Build Coastguard Worker // due to implicit conversions or avoiding unnecessary conversions before narrow stores.
3342*795d594fSAndroid Build Coastguard Worker DataType::Type type = (access_mode_template == mirror::VarHandle::AccessModeTemplate::kGet)
3343*795d594fSAndroid Build Coastguard Worker ? invoke->GetType()
3344*795d594fSAndroid Build Coastguard Worker : GetDataTypeFromShorty(invoke, invoke->GetNumberOfArguments() - 1u);
3345*795d594fSAndroid Build Coastguard Worker if (type != DataTypeFromPrimitive(var_type->GetPrimitiveType())) {
3346*795d594fSAndroid Build Coastguard Worker return false;
3347*795d594fSAndroid Build Coastguard Worker }
3348*795d594fSAndroid Build Coastguard Worker if (type == DataType::Type::kReference) {
3349*795d594fSAndroid Build Coastguard Worker uint32_t arguments_start = /* VarHandle object */ 1u + expected_coordinates_count;
3350*795d594fSAndroid Build Coastguard Worker uint32_t number_of_arguments = invoke->GetNumberOfArguments();
3351*795d594fSAndroid Build Coastguard Worker for (size_t arg_index = arguments_start; arg_index != number_of_arguments; ++arg_index) {
3352*795d594fSAndroid Build Coastguard Worker HInstruction* arg = invoke->InputAt(arg_index);
3353*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(arg->GetType(), DataType::Type::kReference);
3354*795d594fSAndroid Build Coastguard Worker if (!arg->IsNullConstant()) {
3355*795d594fSAndroid Build Coastguard Worker ReferenceTypeInfo arg_type_info = arg->GetReferenceTypeInfo();
3356*795d594fSAndroid Build Coastguard Worker if (!arg_type_info.IsValid() ||
3357*795d594fSAndroid Build Coastguard Worker !var_type->IsAssignableFrom(arg_type_info.GetTypeHandle().Get())) {
3358*795d594fSAndroid Build Coastguard Worker return false;
3359*795d594fSAndroid Build Coastguard Worker }
3360*795d594fSAndroid Build Coastguard Worker }
3361*795d594fSAndroid Build Coastguard Worker }
3362*795d594fSAndroid Build Coastguard Worker }
3363*795d594fSAndroid Build Coastguard Worker
3364*795d594fSAndroid Build Coastguard Worker // Check the first coordinate.
3365*795d594fSAndroid Build Coastguard Worker if (expected_coordinates_count != 0u) {
3366*795d594fSAndroid Build Coastguard Worker ObjPtr<mirror::Class> coordinate0_type = var_handle->GetCoordinateType0();
3367*795d594fSAndroid Build Coastguard Worker DCHECK(coordinate0_type != nullptr);
3368*795d594fSAndroid Build Coastguard Worker ReferenceTypeInfo object_type_info = invoke->InputAt(1)->GetReferenceTypeInfo();
3369*795d594fSAndroid Build Coastguard Worker if (!object_type_info.IsValid() ||
3370*795d594fSAndroid Build Coastguard Worker !coordinate0_type->IsAssignableFrom(object_type_info.GetTypeHandle().Get())) {
3371*795d594fSAndroid Build Coastguard Worker return false;
3372*795d594fSAndroid Build Coastguard Worker }
3373*795d594fSAndroid Build Coastguard Worker }
3374*795d594fSAndroid Build Coastguard Worker
3375*795d594fSAndroid Build Coastguard Worker // All required checks passed.
3376*795d594fSAndroid Build Coastguard Worker return true;
3377*795d594fSAndroid Build Coastguard Worker }
3378*795d594fSAndroid Build Coastguard Worker
VisitInvoke(HInvoke * instruction)3379*795d594fSAndroid Build Coastguard Worker void InstructionSimplifierVisitor::VisitInvoke(HInvoke* instruction) {
3380*795d594fSAndroid Build Coastguard Worker switch (instruction->GetIntrinsic()) {
3381*795d594fSAndroid Build Coastguard Worker #define SIMPLIFY_BOX_UNBOX(name, low, high, type, start_index) \
3382*795d594fSAndroid Build Coastguard Worker case Intrinsics::k ## name ## ValueOf: \
3383*795d594fSAndroid Build Coastguard Worker SimplifyBoxUnbox(instruction, WellKnownClasses::java_lang_##name##_value, type); \
3384*795d594fSAndroid Build Coastguard Worker break;
3385*795d594fSAndroid Build Coastguard Worker BOXED_TYPES(SIMPLIFY_BOX_UNBOX)
3386*795d594fSAndroid Build Coastguard Worker #undef SIMPLIFY_BOX_UNBOX
3387*795d594fSAndroid Build Coastguard Worker case Intrinsics::kStringEquals:
3388*795d594fSAndroid Build Coastguard Worker SimplifyStringEquals(instruction);
3389*795d594fSAndroid Build Coastguard Worker break;
3390*795d594fSAndroid Build Coastguard Worker case Intrinsics::kSystemArrayCopy:
3391*795d594fSAndroid Build Coastguard Worker SimplifySystemArrayCopy(instruction);
3392*795d594fSAndroid Build Coastguard Worker break;
3393*795d594fSAndroid Build Coastguard Worker case Intrinsics::kFloatFloatToIntBits:
3394*795d594fSAndroid Build Coastguard Worker case Intrinsics::kDoubleDoubleToLongBits:
3395*795d594fSAndroid Build Coastguard Worker SimplifyFP2Int(instruction);
3396*795d594fSAndroid Build Coastguard Worker break;
3397*795d594fSAndroid Build Coastguard Worker case Intrinsics::kStringCharAt:
3398*795d594fSAndroid Build Coastguard Worker // Instruction builder creates intermediate representation directly
3399*795d594fSAndroid Build Coastguard Worker // but the inliner can sharpen CharSequence.charAt() to String.charAt().
3400*795d594fSAndroid Build Coastguard Worker SimplifyStringCharAt(instruction);
3401*795d594fSAndroid Build Coastguard Worker break;
3402*795d594fSAndroid Build Coastguard Worker case Intrinsics::kStringLength:
3403*795d594fSAndroid Build Coastguard Worker // Instruction builder creates intermediate representation directly
3404*795d594fSAndroid Build Coastguard Worker // but the inliner can sharpen CharSequence.length() to String.length().
3405*795d594fSAndroid Build Coastguard Worker SimplifyStringLength(instruction);
3406*795d594fSAndroid Build Coastguard Worker break;
3407*795d594fSAndroid Build Coastguard Worker case Intrinsics::kStringIndexOf:
3408*795d594fSAndroid Build Coastguard Worker case Intrinsics::kStringIndexOfAfter:
3409*795d594fSAndroid Build Coastguard Worker SimplifyStringIndexOf(instruction);
3410*795d594fSAndroid Build Coastguard Worker break;
3411*795d594fSAndroid Build Coastguard Worker case Intrinsics::kStringStringIndexOf:
3412*795d594fSAndroid Build Coastguard Worker case Intrinsics::kStringStringIndexOfAfter:
3413*795d594fSAndroid Build Coastguard Worker SimplifyNPEOnArgN(instruction, 1); // 0th has own NullCheck
3414*795d594fSAndroid Build Coastguard Worker break;
3415*795d594fSAndroid Build Coastguard Worker case Intrinsics::kStringBufferAppend:
3416*795d594fSAndroid Build Coastguard Worker case Intrinsics::kStringBuilderAppendObject:
3417*795d594fSAndroid Build Coastguard Worker case Intrinsics::kStringBuilderAppendString:
3418*795d594fSAndroid Build Coastguard Worker case Intrinsics::kStringBuilderAppendCharSequence:
3419*795d594fSAndroid Build Coastguard Worker case Intrinsics::kStringBuilderAppendCharArray:
3420*795d594fSAndroid Build Coastguard Worker case Intrinsics::kStringBuilderAppendBoolean:
3421*795d594fSAndroid Build Coastguard Worker case Intrinsics::kStringBuilderAppendChar:
3422*795d594fSAndroid Build Coastguard Worker case Intrinsics::kStringBuilderAppendInt:
3423*795d594fSAndroid Build Coastguard Worker case Intrinsics::kStringBuilderAppendLong:
3424*795d594fSAndroid Build Coastguard Worker case Intrinsics::kStringBuilderAppendFloat:
3425*795d594fSAndroid Build Coastguard Worker case Intrinsics::kStringBuilderAppendDouble:
3426*795d594fSAndroid Build Coastguard Worker SimplifyReturnThis(instruction);
3427*795d594fSAndroid Build Coastguard Worker break;
3428*795d594fSAndroid Build Coastguard Worker case Intrinsics::kStringBufferToString:
3429*795d594fSAndroid Build Coastguard Worker case Intrinsics::kStringBuilderToString:
3430*795d594fSAndroid Build Coastguard Worker SimplifyAllocationIntrinsic(instruction);
3431*795d594fSAndroid Build Coastguard Worker break;
3432*795d594fSAndroid Build Coastguard Worker case Intrinsics::kVarHandleCompareAndExchange:
3433*795d594fSAndroid Build Coastguard Worker case Intrinsics::kVarHandleCompareAndExchangeAcquire:
3434*795d594fSAndroid Build Coastguard Worker case Intrinsics::kVarHandleCompareAndExchangeRelease:
3435*795d594fSAndroid Build Coastguard Worker case Intrinsics::kVarHandleCompareAndSet:
3436*795d594fSAndroid Build Coastguard Worker case Intrinsics::kVarHandleGet:
3437*795d594fSAndroid Build Coastguard Worker case Intrinsics::kVarHandleGetAcquire:
3438*795d594fSAndroid Build Coastguard Worker case Intrinsics::kVarHandleGetAndAdd:
3439*795d594fSAndroid Build Coastguard Worker case Intrinsics::kVarHandleGetAndAddAcquire:
3440*795d594fSAndroid Build Coastguard Worker case Intrinsics::kVarHandleGetAndAddRelease:
3441*795d594fSAndroid Build Coastguard Worker case Intrinsics::kVarHandleGetAndBitwiseAnd:
3442*795d594fSAndroid Build Coastguard Worker case Intrinsics::kVarHandleGetAndBitwiseAndAcquire:
3443*795d594fSAndroid Build Coastguard Worker case Intrinsics::kVarHandleGetAndBitwiseAndRelease:
3444*795d594fSAndroid Build Coastguard Worker case Intrinsics::kVarHandleGetAndBitwiseOr:
3445*795d594fSAndroid Build Coastguard Worker case Intrinsics::kVarHandleGetAndBitwiseOrAcquire:
3446*795d594fSAndroid Build Coastguard Worker case Intrinsics::kVarHandleGetAndBitwiseOrRelease:
3447*795d594fSAndroid Build Coastguard Worker case Intrinsics::kVarHandleGetAndBitwiseXor:
3448*795d594fSAndroid Build Coastguard Worker case Intrinsics::kVarHandleGetAndBitwiseXorAcquire:
3449*795d594fSAndroid Build Coastguard Worker case Intrinsics::kVarHandleGetAndBitwiseXorRelease:
3450*795d594fSAndroid Build Coastguard Worker case Intrinsics::kVarHandleGetAndSet:
3451*795d594fSAndroid Build Coastguard Worker case Intrinsics::kVarHandleGetAndSetAcquire:
3452*795d594fSAndroid Build Coastguard Worker case Intrinsics::kVarHandleGetAndSetRelease:
3453*795d594fSAndroid Build Coastguard Worker case Intrinsics::kVarHandleGetOpaque:
3454*795d594fSAndroid Build Coastguard Worker case Intrinsics::kVarHandleGetVolatile:
3455*795d594fSAndroid Build Coastguard Worker case Intrinsics::kVarHandleSet:
3456*795d594fSAndroid Build Coastguard Worker case Intrinsics::kVarHandleSetOpaque:
3457*795d594fSAndroid Build Coastguard Worker case Intrinsics::kVarHandleSetRelease:
3458*795d594fSAndroid Build Coastguard Worker case Intrinsics::kVarHandleSetVolatile:
3459*795d594fSAndroid Build Coastguard Worker case Intrinsics::kVarHandleWeakCompareAndSet:
3460*795d594fSAndroid Build Coastguard Worker case Intrinsics::kVarHandleWeakCompareAndSetAcquire:
3461*795d594fSAndroid Build Coastguard Worker case Intrinsics::kVarHandleWeakCompareAndSetPlain:
3462*795d594fSAndroid Build Coastguard Worker case Intrinsics::kVarHandleWeakCompareAndSetRelease:
3463*795d594fSAndroid Build Coastguard Worker SimplifyVarHandleIntrinsic(instruction);
3464*795d594fSAndroid Build Coastguard Worker break;
3465*795d594fSAndroid Build Coastguard Worker case Intrinsics::kUnsafeArrayBaseOffset:
3466*795d594fSAndroid Build Coastguard Worker case Intrinsics::kJdkUnsafeArrayBaseOffset:
3467*795d594fSAndroid Build Coastguard Worker SimplifyArrayBaseOffset(instruction);
3468*795d594fSAndroid Build Coastguard Worker break;
3469*795d594fSAndroid Build Coastguard Worker default:
3470*795d594fSAndroid Build Coastguard Worker break;
3471*795d594fSAndroid Build Coastguard Worker }
3472*795d594fSAndroid Build Coastguard Worker }
3473*795d594fSAndroid Build Coastguard Worker
SimplifyArrayBaseOffset(HInvoke * invoke)3474*795d594fSAndroid Build Coastguard Worker void InstructionSimplifierVisitor::SimplifyArrayBaseOffset(HInvoke* invoke) {
3475*795d594fSAndroid Build Coastguard Worker if (!invoke->InputAt(1)->IsLoadClass()) {
3476*795d594fSAndroid Build Coastguard Worker return;
3477*795d594fSAndroid Build Coastguard Worker }
3478*795d594fSAndroid Build Coastguard Worker HLoadClass* load_class = invoke->InputAt(1)->AsLoadClass();
3479*795d594fSAndroid Build Coastguard Worker ReferenceTypeInfo info = load_class->GetLoadedClassRTI();
3480*795d594fSAndroid Build Coastguard Worker if (!info.IsValid()) {
3481*795d594fSAndroid Build Coastguard Worker return;
3482*795d594fSAndroid Build Coastguard Worker }
3483*795d594fSAndroid Build Coastguard Worker ScopedObjectAccess soa(Thread::Current());
3484*795d594fSAndroid Build Coastguard Worker ObjPtr<mirror::Class> cls = info.GetTypeHandle()->GetComponentType();
3485*795d594fSAndroid Build Coastguard Worker if (cls == nullptr) {
3486*795d594fSAndroid Build Coastguard Worker return;
3487*795d594fSAndroid Build Coastguard Worker }
3488*795d594fSAndroid Build Coastguard Worker uint32_t base_offset =
3489*795d594fSAndroid Build Coastguard Worker mirror::Array::DataOffset(Primitive::ComponentSize(cls->GetPrimitiveType())).Int32Value();
3490*795d594fSAndroid Build Coastguard Worker invoke->ReplaceWith(GetGraph()->GetIntConstant(base_offset));
3491*795d594fSAndroid Build Coastguard Worker RecordSimplification();
3492*795d594fSAndroid Build Coastguard Worker return;
3493*795d594fSAndroid Build Coastguard Worker }
3494*795d594fSAndroid Build Coastguard Worker
VisitDeoptimize(HDeoptimize * deoptimize)3495*795d594fSAndroid Build Coastguard Worker void InstructionSimplifierVisitor::VisitDeoptimize(HDeoptimize* deoptimize) {
3496*795d594fSAndroid Build Coastguard Worker HInstruction* cond = deoptimize->InputAt(0);
3497*795d594fSAndroid Build Coastguard Worker if (cond->IsConstant()) {
3498*795d594fSAndroid Build Coastguard Worker if (cond->AsIntConstant()->IsFalse()) {
3499*795d594fSAndroid Build Coastguard Worker // Never deopt: instruction can be removed.
3500*795d594fSAndroid Build Coastguard Worker if (deoptimize->GuardsAnInput()) {
3501*795d594fSAndroid Build Coastguard Worker deoptimize->ReplaceWith(deoptimize->GuardedInput());
3502*795d594fSAndroid Build Coastguard Worker }
3503*795d594fSAndroid Build Coastguard Worker deoptimize->GetBlock()->RemoveInstruction(deoptimize);
3504*795d594fSAndroid Build Coastguard Worker } else {
3505*795d594fSAndroid Build Coastguard Worker // Always deopt.
3506*795d594fSAndroid Build Coastguard Worker }
3507*795d594fSAndroid Build Coastguard Worker }
3508*795d594fSAndroid Build Coastguard Worker }
3509*795d594fSAndroid Build Coastguard Worker
3510*795d594fSAndroid Build Coastguard Worker // Replace code looking like
3511*795d594fSAndroid Build Coastguard Worker // OP y, x, const1
3512*795d594fSAndroid Build Coastguard Worker // OP z, y, const2
3513*795d594fSAndroid Build Coastguard Worker // with
3514*795d594fSAndroid Build Coastguard Worker // OP z, x, const3
3515*795d594fSAndroid Build Coastguard Worker // where OP is both an associative and a commutative operation.
TryHandleAssociativeAndCommutativeOperation(HBinaryOperation * instruction)3516*795d594fSAndroid Build Coastguard Worker bool InstructionSimplifierVisitor::TryHandleAssociativeAndCommutativeOperation(
3517*795d594fSAndroid Build Coastguard Worker HBinaryOperation* instruction) {
3518*795d594fSAndroid Build Coastguard Worker DCHECK(instruction->IsCommutative());
3519*795d594fSAndroid Build Coastguard Worker
3520*795d594fSAndroid Build Coastguard Worker if (!DataType::IsIntegralType(instruction->GetType())) {
3521*795d594fSAndroid Build Coastguard Worker return false;
3522*795d594fSAndroid Build Coastguard Worker }
3523*795d594fSAndroid Build Coastguard Worker
3524*795d594fSAndroid Build Coastguard Worker HInstruction* left = instruction->GetLeft();
3525*795d594fSAndroid Build Coastguard Worker HInstruction* right = instruction->GetRight();
3526*795d594fSAndroid Build Coastguard Worker // Variable names as described above.
3527*795d594fSAndroid Build Coastguard Worker HConstant* const2;
3528*795d594fSAndroid Build Coastguard Worker HBinaryOperation* y;
3529*795d594fSAndroid Build Coastguard Worker
3530*795d594fSAndroid Build Coastguard Worker if (instruction->GetKind() == left->GetKind() && right->IsConstant()) {
3531*795d594fSAndroid Build Coastguard Worker const2 = right->AsConstant();
3532*795d594fSAndroid Build Coastguard Worker y = left->AsBinaryOperation();
3533*795d594fSAndroid Build Coastguard Worker } else if (left->IsConstant() && instruction->GetKind() == right->GetKind()) {
3534*795d594fSAndroid Build Coastguard Worker const2 = left->AsConstant();
3535*795d594fSAndroid Build Coastguard Worker y = right->AsBinaryOperation();
3536*795d594fSAndroid Build Coastguard Worker } else {
3537*795d594fSAndroid Build Coastguard Worker // The node does not match the pattern.
3538*795d594fSAndroid Build Coastguard Worker return false;
3539*795d594fSAndroid Build Coastguard Worker }
3540*795d594fSAndroid Build Coastguard Worker
3541*795d594fSAndroid Build Coastguard Worker // If `y` has more than one use, we do not perform the optimization
3542*795d594fSAndroid Build Coastguard Worker // because it might increase code size (e.g. if the new constant is
3543*795d594fSAndroid Build Coastguard Worker // no longer encodable as an immediate operand in the target ISA).
3544*795d594fSAndroid Build Coastguard Worker if (!y->HasOnlyOneNonEnvironmentUse()) {
3545*795d594fSAndroid Build Coastguard Worker return false;
3546*795d594fSAndroid Build Coastguard Worker }
3547*795d594fSAndroid Build Coastguard Worker
3548*795d594fSAndroid Build Coastguard Worker // GetConstantRight() can return both left and right constants
3549*795d594fSAndroid Build Coastguard Worker // for commutative operations.
3550*795d594fSAndroid Build Coastguard Worker HConstant* const1 = y->GetConstantRight();
3551*795d594fSAndroid Build Coastguard Worker if (const1 == nullptr) {
3552*795d594fSAndroid Build Coastguard Worker return false;
3553*795d594fSAndroid Build Coastguard Worker }
3554*795d594fSAndroid Build Coastguard Worker
3555*795d594fSAndroid Build Coastguard Worker instruction->ReplaceInput(const1, 0);
3556*795d594fSAndroid Build Coastguard Worker instruction->ReplaceInput(const2, 1);
3557*795d594fSAndroid Build Coastguard Worker HConstant* const3 = instruction->TryStaticEvaluation();
3558*795d594fSAndroid Build Coastguard Worker DCHECK(const3 != nullptr);
3559*795d594fSAndroid Build Coastguard Worker instruction->ReplaceInput(y->GetLeastConstantLeft(), 0);
3560*795d594fSAndroid Build Coastguard Worker instruction->ReplaceInput(const3, 1);
3561*795d594fSAndroid Build Coastguard Worker RecordSimplification();
3562*795d594fSAndroid Build Coastguard Worker return true;
3563*795d594fSAndroid Build Coastguard Worker }
3564*795d594fSAndroid Build Coastguard Worker
AsAddOrSub(HInstruction * binop)3565*795d594fSAndroid Build Coastguard Worker static HBinaryOperation* AsAddOrSub(HInstruction* binop) {
3566*795d594fSAndroid Build Coastguard Worker return (binop->IsAdd() || binop->IsSub()) ? binop->AsBinaryOperation() : nullptr;
3567*795d594fSAndroid Build Coastguard Worker }
3568*795d594fSAndroid Build Coastguard Worker
3569*795d594fSAndroid Build Coastguard Worker // Helper function that performs addition statically, considering the result type.
ComputeAddition(DataType::Type type,int64_t x,int64_t y)3570*795d594fSAndroid Build Coastguard Worker static int64_t ComputeAddition(DataType::Type type, int64_t x, int64_t y) {
3571*795d594fSAndroid Build Coastguard Worker // Use the Compute() method for consistency with TryStaticEvaluation().
3572*795d594fSAndroid Build Coastguard Worker if (type == DataType::Type::kInt32) {
3573*795d594fSAndroid Build Coastguard Worker return HAdd::Compute<int32_t>(x, y);
3574*795d594fSAndroid Build Coastguard Worker } else {
3575*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(type, DataType::Type::kInt64);
3576*795d594fSAndroid Build Coastguard Worker return HAdd::Compute<int64_t>(x, y);
3577*795d594fSAndroid Build Coastguard Worker }
3578*795d594fSAndroid Build Coastguard Worker }
3579*795d594fSAndroid Build Coastguard Worker
3580*795d594fSAndroid Build Coastguard Worker // Helper function that handles the child classes of HConstant
3581*795d594fSAndroid Build Coastguard Worker // and returns an integer with the appropriate sign.
GetValue(HConstant * constant,bool is_negated)3582*795d594fSAndroid Build Coastguard Worker static int64_t GetValue(HConstant* constant, bool is_negated) {
3583*795d594fSAndroid Build Coastguard Worker int64_t ret = Int64FromConstant(constant);
3584*795d594fSAndroid Build Coastguard Worker return is_negated ? -ret : ret;
3585*795d594fSAndroid Build Coastguard Worker }
3586*795d594fSAndroid Build Coastguard Worker
3587*795d594fSAndroid Build Coastguard Worker // Replace code looking like
3588*795d594fSAndroid Build Coastguard Worker // OP1 y, x, const1
3589*795d594fSAndroid Build Coastguard Worker // OP2 z, y, const2
3590*795d594fSAndroid Build Coastguard Worker // with
3591*795d594fSAndroid Build Coastguard Worker // OP3 z, x, const3
3592*795d594fSAndroid Build Coastguard Worker // where OPx is either ADD or SUB, and at least one of OP{1,2} is SUB.
TrySubtractionChainSimplification(HBinaryOperation * instruction)3593*795d594fSAndroid Build Coastguard Worker bool InstructionSimplifierVisitor::TrySubtractionChainSimplification(
3594*795d594fSAndroid Build Coastguard Worker HBinaryOperation* instruction) {
3595*795d594fSAndroid Build Coastguard Worker DCHECK(instruction->IsAdd() || instruction->IsSub()) << instruction->DebugName();
3596*795d594fSAndroid Build Coastguard Worker
3597*795d594fSAndroid Build Coastguard Worker DataType::Type type = instruction->GetType();
3598*795d594fSAndroid Build Coastguard Worker if (!DataType::IsIntegralType(type)) {
3599*795d594fSAndroid Build Coastguard Worker return false;
3600*795d594fSAndroid Build Coastguard Worker }
3601*795d594fSAndroid Build Coastguard Worker
3602*795d594fSAndroid Build Coastguard Worker HInstruction* left = instruction->GetLeft();
3603*795d594fSAndroid Build Coastguard Worker HInstruction* right = instruction->GetRight();
3604*795d594fSAndroid Build Coastguard Worker // Variable names as described above.
3605*795d594fSAndroid Build Coastguard Worker HConstant* const2 = right->IsConstant() ? right->AsConstant() : left->AsConstantOrNull();
3606*795d594fSAndroid Build Coastguard Worker if (const2 == nullptr) {
3607*795d594fSAndroid Build Coastguard Worker return false;
3608*795d594fSAndroid Build Coastguard Worker }
3609*795d594fSAndroid Build Coastguard Worker
3610*795d594fSAndroid Build Coastguard Worker HBinaryOperation* y = (AsAddOrSub(left) != nullptr)
3611*795d594fSAndroid Build Coastguard Worker ? left->AsBinaryOperation()
3612*795d594fSAndroid Build Coastguard Worker : AsAddOrSub(right);
3613*795d594fSAndroid Build Coastguard Worker // If y has more than one use, we do not perform the optimization because
3614*795d594fSAndroid Build Coastguard Worker // it might increase code size (e.g. if the new constant is no longer
3615*795d594fSAndroid Build Coastguard Worker // encodable as an immediate operand in the target ISA).
3616*795d594fSAndroid Build Coastguard Worker if ((y == nullptr) || !y->HasOnlyOneNonEnvironmentUse()) {
3617*795d594fSAndroid Build Coastguard Worker return false;
3618*795d594fSAndroid Build Coastguard Worker }
3619*795d594fSAndroid Build Coastguard Worker
3620*795d594fSAndroid Build Coastguard Worker left = y->GetLeft();
3621*795d594fSAndroid Build Coastguard Worker HConstant* const1 = left->IsConstant() ? left->AsConstant() : y->GetRight()->AsConstantOrNull();
3622*795d594fSAndroid Build Coastguard Worker if (const1 == nullptr) {
3623*795d594fSAndroid Build Coastguard Worker return false;
3624*795d594fSAndroid Build Coastguard Worker }
3625*795d594fSAndroid Build Coastguard Worker
3626*795d594fSAndroid Build Coastguard Worker HInstruction* x = (const1 == left) ? y->GetRight() : left;
3627*795d594fSAndroid Build Coastguard Worker // If both inputs are constants, let the constant folding pass deal with it.
3628*795d594fSAndroid Build Coastguard Worker if (x->IsConstant()) {
3629*795d594fSAndroid Build Coastguard Worker return false;
3630*795d594fSAndroid Build Coastguard Worker }
3631*795d594fSAndroid Build Coastguard Worker
3632*795d594fSAndroid Build Coastguard Worker bool is_const2_negated = (const2 == right) && instruction->IsSub();
3633*795d594fSAndroid Build Coastguard Worker int64_t const2_val = GetValue(const2, is_const2_negated);
3634*795d594fSAndroid Build Coastguard Worker bool is_y_negated = (y == right) && instruction->IsSub();
3635*795d594fSAndroid Build Coastguard Worker right = y->GetRight();
3636*795d594fSAndroid Build Coastguard Worker bool is_const1_negated = is_y_negated ^ ((const1 == right) && y->IsSub());
3637*795d594fSAndroid Build Coastguard Worker int64_t const1_val = GetValue(const1, is_const1_negated);
3638*795d594fSAndroid Build Coastguard Worker bool is_x_negated = is_y_negated ^ ((x == right) && y->IsSub());
3639*795d594fSAndroid Build Coastguard Worker int64_t const3_val = ComputeAddition(type, const1_val, const2_val);
3640*795d594fSAndroid Build Coastguard Worker HBasicBlock* block = instruction->GetBlock();
3641*795d594fSAndroid Build Coastguard Worker HConstant* const3 = block->GetGraph()->GetConstant(type, const3_val);
3642*795d594fSAndroid Build Coastguard Worker ArenaAllocator* allocator = instruction->GetAllocator();
3643*795d594fSAndroid Build Coastguard Worker HInstruction* z;
3644*795d594fSAndroid Build Coastguard Worker
3645*795d594fSAndroid Build Coastguard Worker if (is_x_negated) {
3646*795d594fSAndroid Build Coastguard Worker z = new (allocator) HSub(type, const3, x, instruction->GetDexPc());
3647*795d594fSAndroid Build Coastguard Worker } else {
3648*795d594fSAndroid Build Coastguard Worker z = new (allocator) HAdd(type, x, const3, instruction->GetDexPc());
3649*795d594fSAndroid Build Coastguard Worker }
3650*795d594fSAndroid Build Coastguard Worker
3651*795d594fSAndroid Build Coastguard Worker block->ReplaceAndRemoveInstructionWith(instruction, z);
3652*795d594fSAndroid Build Coastguard Worker RecordSimplification();
3653*795d594fSAndroid Build Coastguard Worker return true;
3654*795d594fSAndroid Build Coastguard Worker }
3655*795d594fSAndroid Build Coastguard Worker
VisitVecMul(HVecMul * instruction)3656*795d594fSAndroid Build Coastguard Worker void InstructionSimplifierVisitor::VisitVecMul(HVecMul* instruction) {
3657*795d594fSAndroid Build Coastguard Worker if (TryCombineVecMultiplyAccumulate(instruction)) {
3658*795d594fSAndroid Build Coastguard Worker RecordSimplification();
3659*795d594fSAndroid Build Coastguard Worker }
3660*795d594fSAndroid Build Coastguard Worker }
3661*795d594fSAndroid Build Coastguard Worker
TryMergeNegatedInput(HBinaryOperation * op)3662*795d594fSAndroid Build Coastguard Worker bool TryMergeNegatedInput(HBinaryOperation* op) {
3663*795d594fSAndroid Build Coastguard Worker DCHECK(op->IsAnd() || op->IsOr() || op->IsXor()) << op->DebugName();
3664*795d594fSAndroid Build Coastguard Worker HInstruction* left = op->GetLeft();
3665*795d594fSAndroid Build Coastguard Worker HInstruction* right = op->GetRight();
3666*795d594fSAndroid Build Coastguard Worker
3667*795d594fSAndroid Build Coastguard Worker // Only consider the case where there is exactly one Not, with 2 Not's De
3668*795d594fSAndroid Build Coastguard Worker // Morgan's laws should be applied instead.
3669*795d594fSAndroid Build Coastguard Worker if (left->IsNot() ^ right->IsNot()) {
3670*795d594fSAndroid Build Coastguard Worker HInstruction* hnot = (left->IsNot() ? left : right);
3671*795d594fSAndroid Build Coastguard Worker HInstruction* hother = (left->IsNot() ? right : left);
3672*795d594fSAndroid Build Coastguard Worker
3673*795d594fSAndroid Build Coastguard Worker // Only do the simplification if the Not has only one use and can thus be
3674*795d594fSAndroid Build Coastguard Worker // safely removed. Even though ARM64 negated bitwise operations do not have
3675*795d594fSAndroid Build Coastguard Worker // an immediate variant (only register), we still do the simplification when
3676*795d594fSAndroid Build Coastguard Worker // `hother` is a constant, because it removes an instruction if the constant
3677*795d594fSAndroid Build Coastguard Worker // cannot be encoded as an immediate:
3678*795d594fSAndroid Build Coastguard Worker // mov r0, #large_constant
3679*795d594fSAndroid Build Coastguard Worker // neg r2, r1
3680*795d594fSAndroid Build Coastguard Worker // and r0, r0, r2
3681*795d594fSAndroid Build Coastguard Worker // becomes:
3682*795d594fSAndroid Build Coastguard Worker // mov r0, #large_constant
3683*795d594fSAndroid Build Coastguard Worker // bic r0, r0, r1
3684*795d594fSAndroid Build Coastguard Worker if (hnot->HasOnlyOneNonEnvironmentUse()) {
3685*795d594fSAndroid Build Coastguard Worker // Replace code looking like
3686*795d594fSAndroid Build Coastguard Worker // NOT tmp, mask
3687*795d594fSAndroid Build Coastguard Worker // AND dst, src, tmp (respectively ORR, EOR)
3688*795d594fSAndroid Build Coastguard Worker // with
3689*795d594fSAndroid Build Coastguard Worker // BIC dst, src, mask (respectively ORN, EON)
3690*795d594fSAndroid Build Coastguard Worker HInstruction* src = hnot->AsNot()->GetInput();
3691*795d594fSAndroid Build Coastguard Worker
3692*795d594fSAndroid Build Coastguard Worker HBitwiseNegatedRight* neg_op = new (hnot->GetBlock()->GetGraph()->GetAllocator())
3693*795d594fSAndroid Build Coastguard Worker HBitwiseNegatedRight(op->GetType(), op->GetKind(), hother, src, op->GetDexPc());
3694*795d594fSAndroid Build Coastguard Worker
3695*795d594fSAndroid Build Coastguard Worker op->GetBlock()->ReplaceAndRemoveInstructionWith(op, neg_op);
3696*795d594fSAndroid Build Coastguard Worker hnot->GetBlock()->RemoveInstruction(hnot);
3697*795d594fSAndroid Build Coastguard Worker return true;
3698*795d594fSAndroid Build Coastguard Worker }
3699*795d594fSAndroid Build Coastguard Worker }
3700*795d594fSAndroid Build Coastguard Worker
3701*795d594fSAndroid Build Coastguard Worker return false;
3702*795d594fSAndroid Build Coastguard Worker }
3703*795d594fSAndroid Build Coastguard Worker
TryMergeWithAnd(HSub * instruction)3704*795d594fSAndroid Build Coastguard Worker bool TryMergeWithAnd(HSub* instruction) {
3705*795d594fSAndroid Build Coastguard Worker HAnd* and_instr = instruction->GetRight()->AsAndOrNull();
3706*795d594fSAndroid Build Coastguard Worker if (and_instr == nullptr) {
3707*795d594fSAndroid Build Coastguard Worker return false;
3708*795d594fSAndroid Build Coastguard Worker }
3709*795d594fSAndroid Build Coastguard Worker
3710*795d594fSAndroid Build Coastguard Worker HInstruction* value = instruction->GetLeft();
3711*795d594fSAndroid Build Coastguard Worker
3712*795d594fSAndroid Build Coastguard Worker HInstruction* left = and_instr->GetLeft();
3713*795d594fSAndroid Build Coastguard Worker const bool left_is_equal = left == value;
3714*795d594fSAndroid Build Coastguard Worker HInstruction* right = and_instr->GetRight();
3715*795d594fSAndroid Build Coastguard Worker const bool right_is_equal = right == value;
3716*795d594fSAndroid Build Coastguard Worker if (!left_is_equal && !right_is_equal) {
3717*795d594fSAndroid Build Coastguard Worker return false;
3718*795d594fSAndroid Build Coastguard Worker }
3719*795d594fSAndroid Build Coastguard Worker
3720*795d594fSAndroid Build Coastguard Worker HBitwiseNegatedRight* bnr = new (instruction->GetBlock()->GetGraph()->GetAllocator())
3721*795d594fSAndroid Build Coastguard Worker HBitwiseNegatedRight(instruction->GetType(),
3722*795d594fSAndroid Build Coastguard Worker HInstruction::InstructionKind::kAnd,
3723*795d594fSAndroid Build Coastguard Worker value,
3724*795d594fSAndroid Build Coastguard Worker left_is_equal ? right : left,
3725*795d594fSAndroid Build Coastguard Worker instruction->GetDexPc());
3726*795d594fSAndroid Build Coastguard Worker instruction->GetBlock()->ReplaceAndRemoveInstructionWith(instruction, bnr);
3727*795d594fSAndroid Build Coastguard Worker // Since we don't run DCE after this phase, try to manually remove the And instruction.
3728*795d594fSAndroid Build Coastguard Worker if (!and_instr->HasUses()) {
3729*795d594fSAndroid Build Coastguard Worker and_instr->GetBlock()->RemoveInstruction(and_instr);
3730*795d594fSAndroid Build Coastguard Worker }
3731*795d594fSAndroid Build Coastguard Worker return true;
3732*795d594fSAndroid Build Coastguard Worker }
3733*795d594fSAndroid Build Coastguard Worker
3734*795d594fSAndroid Build Coastguard Worker } // namespace art
3735