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 "constant_folding.h"
18*795d594fSAndroid Build Coastguard Worker
19*795d594fSAndroid Build Coastguard Worker #include <algorithm>
20*795d594fSAndroid Build Coastguard Worker
21*795d594fSAndroid Build Coastguard Worker #include "base/bit_utils.h"
22*795d594fSAndroid Build Coastguard Worker #include "base/casts.h"
23*795d594fSAndroid Build Coastguard Worker #include "base/logging.h"
24*795d594fSAndroid Build Coastguard Worker #include "dex/dex_file-inl.h"
25*795d594fSAndroid Build Coastguard Worker #include "intrinsics_enum.h"
26*795d594fSAndroid Build Coastguard Worker #include "optimizing/data_type.h"
27*795d594fSAndroid Build Coastguard Worker #include "optimizing/nodes.h"
28*795d594fSAndroid Build Coastguard Worker
29*795d594fSAndroid Build Coastguard Worker namespace art HIDDEN {
30*795d594fSAndroid Build Coastguard Worker
31*795d594fSAndroid Build Coastguard Worker // This visitor tries to simplify instructions that can be evaluated
32*795d594fSAndroid Build Coastguard Worker // as constants.
33*795d594fSAndroid Build Coastguard Worker class HConstantFoldingVisitor final : public HGraphDelegateVisitor {
34*795d594fSAndroid Build Coastguard Worker public:
HConstantFoldingVisitor(HGraph * graph,OptimizingCompilerStats * stats)35*795d594fSAndroid Build Coastguard Worker explicit HConstantFoldingVisitor(HGraph* graph, OptimizingCompilerStats* stats)
36*795d594fSAndroid Build Coastguard Worker : HGraphDelegateVisitor(graph, stats) {}
37*795d594fSAndroid Build Coastguard Worker
38*795d594fSAndroid Build Coastguard Worker private:
39*795d594fSAndroid Build Coastguard Worker void VisitBasicBlock(HBasicBlock* block) override;
40*795d594fSAndroid Build Coastguard Worker
41*795d594fSAndroid Build Coastguard Worker void VisitUnaryOperation(HUnaryOperation* inst) override;
42*795d594fSAndroid Build Coastguard Worker void VisitBinaryOperation(HBinaryOperation* inst) override;
43*795d594fSAndroid Build Coastguard Worker
44*795d594fSAndroid Build Coastguard Worker // Tries to replace constants in binary operations like:
45*795d594fSAndroid Build Coastguard Worker // * BinaryOp(Select(false_constant, true_constant, condition), other_constant), or
46*795d594fSAndroid Build Coastguard Worker // * BinaryOp(other_constant, Select(false_constant, true_constant, condition))
47*795d594fSAndroid Build Coastguard Worker // with consolidated constants. For example, Add(Select(10, 20, condition), 5) can be replaced
48*795d594fSAndroid Build Coastguard Worker // with Select(15, 25, condition).
49*795d594fSAndroid Build Coastguard Worker bool TryRemoveBinaryOperationViaSelect(HBinaryOperation* inst);
50*795d594fSAndroid Build Coastguard Worker
51*795d594fSAndroid Build Coastguard Worker void VisitArrayLength(HArrayLength* inst) override;
52*795d594fSAndroid Build Coastguard Worker void VisitDivZeroCheck(HDivZeroCheck* inst) override;
53*795d594fSAndroid Build Coastguard Worker void VisitIf(HIf* inst) override;
54*795d594fSAndroid Build Coastguard Worker void VisitInvoke(HInvoke* inst) override;
55*795d594fSAndroid Build Coastguard Worker void VisitTypeConversion(HTypeConversion* inst) override;
56*795d594fSAndroid Build Coastguard Worker
57*795d594fSAndroid Build Coastguard Worker void PropagateValue(HBasicBlock* starting_block, HInstruction* variable, HConstant* constant);
58*795d594fSAndroid Build Coastguard Worker
59*795d594fSAndroid Build Coastguard Worker // Intrinsics foldings
60*795d594fSAndroid Build Coastguard Worker void FoldReverseIntrinsic(HInvoke* invoke);
61*795d594fSAndroid Build Coastguard Worker void FoldReverseBytesIntrinsic(HInvoke* invoke);
62*795d594fSAndroid Build Coastguard Worker void FoldBitCountIntrinsic(HInvoke* invoke);
63*795d594fSAndroid Build Coastguard Worker void FoldDivideUnsignedIntrinsic(HInvoke* invoke);
64*795d594fSAndroid Build Coastguard Worker void FoldHighestOneBitIntrinsic(HInvoke* invoke);
65*795d594fSAndroid Build Coastguard Worker void FoldLowestOneBitIntrinsic(HInvoke* invoke);
66*795d594fSAndroid Build Coastguard Worker void FoldNumberOfLeadingZerosIntrinsic(HInvoke* invoke);
67*795d594fSAndroid Build Coastguard Worker void FoldNumberOfTrailingZerosIntrinsic(HInvoke* invoke);
68*795d594fSAndroid Build Coastguard Worker
69*795d594fSAndroid Build Coastguard Worker DISALLOW_COPY_AND_ASSIGN(HConstantFoldingVisitor);
70*795d594fSAndroid Build Coastguard Worker };
71*795d594fSAndroid Build Coastguard Worker
72*795d594fSAndroid Build Coastguard Worker // This visitor tries to simplify operations with an absorbing input,
73*795d594fSAndroid Build Coastguard Worker // yielding a constant. For example `input * 0` is replaced by a
74*795d594fSAndroid Build Coastguard Worker // null constant.
75*795d594fSAndroid Build Coastguard Worker class InstructionWithAbsorbingInputSimplifier final : public HGraphVisitor {
76*795d594fSAndroid Build Coastguard Worker public:
InstructionWithAbsorbingInputSimplifier(HGraph * graph)77*795d594fSAndroid Build Coastguard Worker explicit InstructionWithAbsorbingInputSimplifier(HGraph* graph) : HGraphVisitor(graph) {}
78*795d594fSAndroid Build Coastguard Worker
79*795d594fSAndroid Build Coastguard Worker private:
80*795d594fSAndroid Build Coastguard Worker void VisitShift(HBinaryOperation* shift);
81*795d594fSAndroid Build Coastguard Worker
82*795d594fSAndroid Build Coastguard Worker void VisitEqual(HEqual* instruction) override;
83*795d594fSAndroid Build Coastguard Worker void VisitNotEqual(HNotEqual* instruction) override;
84*795d594fSAndroid Build Coastguard Worker
85*795d594fSAndroid Build Coastguard Worker void VisitAbove(HAbove* instruction) override;
86*795d594fSAndroid Build Coastguard Worker void VisitAboveOrEqual(HAboveOrEqual* instruction) override;
87*795d594fSAndroid Build Coastguard Worker void VisitBelow(HBelow* instruction) override;
88*795d594fSAndroid Build Coastguard Worker void VisitBelowOrEqual(HBelowOrEqual* instruction) override;
89*795d594fSAndroid Build Coastguard Worker
90*795d594fSAndroid Build Coastguard Worker void VisitGreaterThan(HGreaterThan* instruction) override;
91*795d594fSAndroid Build Coastguard Worker void VisitGreaterThanOrEqual(HGreaterThanOrEqual* instruction) override;
92*795d594fSAndroid Build Coastguard Worker void VisitLessThan(HLessThan* instruction) override;
93*795d594fSAndroid Build Coastguard Worker void VisitLessThanOrEqual(HLessThanOrEqual* instruction) override;
94*795d594fSAndroid Build Coastguard Worker
95*795d594fSAndroid Build Coastguard Worker void VisitAnd(HAnd* instruction) override;
96*795d594fSAndroid Build Coastguard Worker void VisitCompare(HCompare* instruction) override;
97*795d594fSAndroid Build Coastguard Worker void VisitMul(HMul* instruction) override;
98*795d594fSAndroid Build Coastguard Worker void VisitOr(HOr* instruction) override;
99*795d594fSAndroid Build Coastguard Worker void VisitRem(HRem* instruction) override;
100*795d594fSAndroid Build Coastguard Worker void VisitShl(HShl* instruction) override;
101*795d594fSAndroid Build Coastguard Worker void VisitShr(HShr* instruction) override;
102*795d594fSAndroid Build Coastguard Worker void VisitSub(HSub* instruction) override;
103*795d594fSAndroid Build Coastguard Worker void VisitUShr(HUShr* instruction) override;
104*795d594fSAndroid Build Coastguard Worker void VisitXor(HXor* instruction) override;
105*795d594fSAndroid Build Coastguard Worker };
106*795d594fSAndroid Build Coastguard Worker
107*795d594fSAndroid Build Coastguard Worker
Run()108*795d594fSAndroid Build Coastguard Worker bool HConstantFolding::Run() {
109*795d594fSAndroid Build Coastguard Worker HConstantFoldingVisitor visitor(graph_, stats_);
110*795d594fSAndroid Build Coastguard Worker // Process basic blocks in reverse post-order in the dominator tree,
111*795d594fSAndroid Build Coastguard Worker // so that an instruction turned into a constant, used as input of
112*795d594fSAndroid Build Coastguard Worker // another instruction, may possibly be used to turn that second
113*795d594fSAndroid Build Coastguard Worker // instruction into a constant as well.
114*795d594fSAndroid Build Coastguard Worker visitor.VisitReversePostOrder();
115*795d594fSAndroid Build Coastguard Worker return true;
116*795d594fSAndroid Build Coastguard Worker }
117*795d594fSAndroid Build Coastguard Worker
118*795d594fSAndroid Build Coastguard Worker
VisitBasicBlock(HBasicBlock * block)119*795d594fSAndroid Build Coastguard Worker void HConstantFoldingVisitor::VisitBasicBlock(HBasicBlock* block) {
120*795d594fSAndroid Build Coastguard Worker // Traverse this block's instructions (phis don't need to be processed) in (forward) order
121*795d594fSAndroid Build Coastguard Worker // and replace the ones that can be statically evaluated by a compile-time counterpart.
122*795d594fSAndroid Build Coastguard Worker VisitNonPhiInstructions(block);
123*795d594fSAndroid Build Coastguard Worker }
124*795d594fSAndroid Build Coastguard Worker
VisitUnaryOperation(HUnaryOperation * inst)125*795d594fSAndroid Build Coastguard Worker void HConstantFoldingVisitor::VisitUnaryOperation(HUnaryOperation* inst) {
126*795d594fSAndroid Build Coastguard Worker // Constant folding: replace `op(a)' with a constant at compile
127*795d594fSAndroid Build Coastguard Worker // time if `a' is a constant.
128*795d594fSAndroid Build Coastguard Worker HConstant* constant = inst->TryStaticEvaluation();
129*795d594fSAndroid Build Coastguard Worker if (constant != nullptr) {
130*795d594fSAndroid Build Coastguard Worker inst->ReplaceWith(constant);
131*795d594fSAndroid Build Coastguard Worker inst->GetBlock()->RemoveInstruction(inst);
132*795d594fSAndroid Build Coastguard Worker } else if (inst->InputAt(0)->IsSelect() && inst->InputAt(0)->HasOnlyOneNonEnvironmentUse()) {
133*795d594fSAndroid Build Coastguard Worker // Try to replace the select's inputs in Select+UnaryOperation cases. We can do this if both
134*795d594fSAndroid Build Coastguard Worker // inputs to the select are constants, and this is the only use of the select.
135*795d594fSAndroid Build Coastguard Worker HSelect* select = inst->InputAt(0)->AsSelect();
136*795d594fSAndroid Build Coastguard Worker HConstant* false_constant = inst->TryStaticEvaluation(select->GetFalseValue());
137*795d594fSAndroid Build Coastguard Worker if (false_constant == nullptr) {
138*795d594fSAndroid Build Coastguard Worker return;
139*795d594fSAndroid Build Coastguard Worker }
140*795d594fSAndroid Build Coastguard Worker HConstant* true_constant = inst->TryStaticEvaluation(select->GetTrueValue());
141*795d594fSAndroid Build Coastguard Worker if (true_constant == nullptr) {
142*795d594fSAndroid Build Coastguard Worker return;
143*795d594fSAndroid Build Coastguard Worker }
144*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(select->InputAt(0), select->GetFalseValue());
145*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(select->InputAt(1), select->GetTrueValue());
146*795d594fSAndroid Build Coastguard Worker select->ReplaceInput(false_constant, 0);
147*795d594fSAndroid Build Coastguard Worker select->ReplaceInput(true_constant, 1);
148*795d594fSAndroid Build Coastguard Worker select->UpdateType();
149*795d594fSAndroid Build Coastguard Worker inst->ReplaceWith(select);
150*795d594fSAndroid Build Coastguard Worker inst->GetBlock()->RemoveInstruction(inst);
151*795d594fSAndroid Build Coastguard Worker }
152*795d594fSAndroid Build Coastguard Worker }
153*795d594fSAndroid Build Coastguard Worker
TryRemoveBinaryOperationViaSelect(HBinaryOperation * inst)154*795d594fSAndroid Build Coastguard Worker bool HConstantFoldingVisitor::TryRemoveBinaryOperationViaSelect(HBinaryOperation* inst) {
155*795d594fSAndroid Build Coastguard Worker if (inst->GetLeft()->IsSelect() == inst->GetRight()->IsSelect()) {
156*795d594fSAndroid Build Coastguard Worker // If both of them are constants, VisitBinaryOperation already tried the static evaluation. If
157*795d594fSAndroid Build Coastguard Worker // both of them are selects, then we can't simplify.
158*795d594fSAndroid Build Coastguard Worker // TODO(solanes): Technically, if both of them are selects we could simplify iff both select's
159*795d594fSAndroid Build Coastguard Worker // conditions are equal e.g. Add(Select(1, 2, cond), Select(3, 4, cond)) could be replaced with
160*795d594fSAndroid Build Coastguard Worker // Select(4, 6, cond). This seems very unlikely to happen so we don't implement it.
161*795d594fSAndroid Build Coastguard Worker return false;
162*795d594fSAndroid Build Coastguard Worker }
163*795d594fSAndroid Build Coastguard Worker
164*795d594fSAndroid Build Coastguard Worker const bool left_is_select = inst->GetLeft()->IsSelect();
165*795d594fSAndroid Build Coastguard Worker HSelect* select = left_is_select ? inst->GetLeft()->AsSelect() : inst->GetRight()->AsSelect();
166*795d594fSAndroid Build Coastguard Worker HInstruction* maybe_constant = left_is_select ? inst->GetRight() : inst->GetLeft();
167*795d594fSAndroid Build Coastguard Worker
168*795d594fSAndroid Build Coastguard Worker if (select->HasOnlyOneNonEnvironmentUse()) {
169*795d594fSAndroid Build Coastguard Worker // Try to replace the select's inputs in Select+BinaryOperation. We can do this if both
170*795d594fSAndroid Build Coastguard Worker // inputs to the select are constants, and this is the only use of the select.
171*795d594fSAndroid Build Coastguard Worker HConstant* false_constant =
172*795d594fSAndroid Build Coastguard Worker inst->TryStaticEvaluation(left_is_select ? select->GetFalseValue() : maybe_constant,
173*795d594fSAndroid Build Coastguard Worker left_is_select ? maybe_constant : select->GetFalseValue());
174*795d594fSAndroid Build Coastguard Worker if (false_constant == nullptr) {
175*795d594fSAndroid Build Coastguard Worker return false;
176*795d594fSAndroid Build Coastguard Worker }
177*795d594fSAndroid Build Coastguard Worker HConstant* true_constant =
178*795d594fSAndroid Build Coastguard Worker inst->TryStaticEvaluation(left_is_select ? select->GetTrueValue() : maybe_constant,
179*795d594fSAndroid Build Coastguard Worker left_is_select ? maybe_constant : select->GetTrueValue());
180*795d594fSAndroid Build Coastguard Worker if (true_constant == nullptr) {
181*795d594fSAndroid Build Coastguard Worker return false;
182*795d594fSAndroid Build Coastguard Worker }
183*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(select->InputAt(0), select->GetFalseValue());
184*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(select->InputAt(1), select->GetTrueValue());
185*795d594fSAndroid Build Coastguard Worker select->ReplaceInput(false_constant, 0);
186*795d594fSAndroid Build Coastguard Worker select->ReplaceInput(true_constant, 1);
187*795d594fSAndroid Build Coastguard Worker select->UpdateType();
188*795d594fSAndroid Build Coastguard Worker inst->ReplaceWith(select);
189*795d594fSAndroid Build Coastguard Worker inst->GetBlock()->RemoveInstruction(inst);
190*795d594fSAndroid Build Coastguard Worker return true;
191*795d594fSAndroid Build Coastguard Worker }
192*795d594fSAndroid Build Coastguard Worker return false;
193*795d594fSAndroid Build Coastguard Worker }
194*795d594fSAndroid Build Coastguard Worker
VisitBinaryOperation(HBinaryOperation * inst)195*795d594fSAndroid Build Coastguard Worker void HConstantFoldingVisitor::VisitBinaryOperation(HBinaryOperation* inst) {
196*795d594fSAndroid Build Coastguard Worker // Constant folding: replace `op(a, b)' with a constant at
197*795d594fSAndroid Build Coastguard Worker // compile time if `a' and `b' are both constants.
198*795d594fSAndroid Build Coastguard Worker HConstant* constant = inst->TryStaticEvaluation();
199*795d594fSAndroid Build Coastguard Worker if (constant != nullptr) {
200*795d594fSAndroid Build Coastguard Worker inst->ReplaceWith(constant);
201*795d594fSAndroid Build Coastguard Worker inst->GetBlock()->RemoveInstruction(inst);
202*795d594fSAndroid Build Coastguard Worker } else if (TryRemoveBinaryOperationViaSelect(inst)) {
203*795d594fSAndroid Build Coastguard Worker // Already replaced inside TryRemoveBinaryOperationViaSelect.
204*795d594fSAndroid Build Coastguard Worker } else {
205*795d594fSAndroid Build Coastguard Worker InstructionWithAbsorbingInputSimplifier simplifier(GetGraph());
206*795d594fSAndroid Build Coastguard Worker inst->Accept(&simplifier);
207*795d594fSAndroid Build Coastguard Worker }
208*795d594fSAndroid Build Coastguard Worker }
209*795d594fSAndroid Build Coastguard Worker
VisitDivZeroCheck(HDivZeroCheck * inst)210*795d594fSAndroid Build Coastguard Worker void HConstantFoldingVisitor::VisitDivZeroCheck(HDivZeroCheck* inst) {
211*795d594fSAndroid Build Coastguard Worker // We can safely remove the check if the input is a non-null constant.
212*795d594fSAndroid Build Coastguard Worker HInstruction* check_input = inst->InputAt(0);
213*795d594fSAndroid Build Coastguard Worker if (check_input->IsConstant() && !check_input->AsConstant()->IsArithmeticZero()) {
214*795d594fSAndroid Build Coastguard Worker inst->ReplaceWith(check_input);
215*795d594fSAndroid Build Coastguard Worker inst->GetBlock()->RemoveInstruction(inst);
216*795d594fSAndroid Build Coastguard Worker }
217*795d594fSAndroid Build Coastguard Worker }
218*795d594fSAndroid Build Coastguard Worker
PropagateValue(HBasicBlock * starting_block,HInstruction * variable,HConstant * constant)219*795d594fSAndroid Build Coastguard Worker void HConstantFoldingVisitor::PropagateValue(HBasicBlock* starting_block,
220*795d594fSAndroid Build Coastguard Worker HInstruction* variable,
221*795d594fSAndroid Build Coastguard Worker HConstant* constant) {
222*795d594fSAndroid Build Coastguard Worker const bool recording_stats = stats_ != nullptr;
223*795d594fSAndroid Build Coastguard Worker size_t uses_before = 0;
224*795d594fSAndroid Build Coastguard Worker size_t uses_after = 0;
225*795d594fSAndroid Build Coastguard Worker if (recording_stats) {
226*795d594fSAndroid Build Coastguard Worker uses_before = variable->GetUses().SizeSlow();
227*795d594fSAndroid Build Coastguard Worker }
228*795d594fSAndroid Build Coastguard Worker
229*795d594fSAndroid Build Coastguard Worker if (!variable->GetUses().HasExactlyOneElement()) {
230*795d594fSAndroid Build Coastguard Worker variable->ReplaceUsesDominatedBy(
231*795d594fSAndroid Build Coastguard Worker starting_block->GetFirstInstruction(), constant, /* strictly_dominated= */ false);
232*795d594fSAndroid Build Coastguard Worker }
233*795d594fSAndroid Build Coastguard Worker
234*795d594fSAndroid Build Coastguard Worker if (recording_stats) {
235*795d594fSAndroid Build Coastguard Worker uses_after = variable->GetUses().SizeSlow();
236*795d594fSAndroid Build Coastguard Worker DCHECK_GE(uses_after, 1u) << "we must at least have the use in the if clause.";
237*795d594fSAndroid Build Coastguard Worker DCHECK_GE(uses_before, uses_after);
238*795d594fSAndroid Build Coastguard Worker MaybeRecordStat(stats_, MethodCompilationStat::kPropagatedIfValue, uses_before - uses_after);
239*795d594fSAndroid Build Coastguard Worker }
240*795d594fSAndroid Build Coastguard Worker }
241*795d594fSAndroid Build Coastguard Worker
VisitIf(HIf * inst)242*795d594fSAndroid Build Coastguard Worker void HConstantFoldingVisitor::VisitIf(HIf* inst) {
243*795d594fSAndroid Build Coastguard Worker // Consistency check: the true and false successors do not dominate each other.
244*795d594fSAndroid Build Coastguard Worker DCHECK(!inst->IfTrueSuccessor()->Dominates(inst->IfFalseSuccessor()) &&
245*795d594fSAndroid Build Coastguard Worker !inst->IfFalseSuccessor()->Dominates(inst->IfTrueSuccessor()));
246*795d594fSAndroid Build Coastguard Worker
247*795d594fSAndroid Build Coastguard Worker HInstruction* if_input = inst->InputAt(0);
248*795d594fSAndroid Build Coastguard Worker
249*795d594fSAndroid Build Coastguard Worker // Already a constant.
250*795d594fSAndroid Build Coastguard Worker if (if_input->IsConstant()) {
251*795d594fSAndroid Build Coastguard Worker return;
252*795d594fSAndroid Build Coastguard Worker }
253*795d594fSAndroid Build Coastguard Worker
254*795d594fSAndroid Build Coastguard Worker // if (variable) {
255*795d594fSAndroid Build Coastguard Worker // SSA `variable` guaranteed to be true
256*795d594fSAndroid Build Coastguard Worker // } else {
257*795d594fSAndroid Build Coastguard Worker // and here false
258*795d594fSAndroid Build Coastguard Worker // }
259*795d594fSAndroid Build Coastguard Worker PropagateValue(inst->IfTrueSuccessor(), if_input, GetGraph()->GetIntConstant(1));
260*795d594fSAndroid Build Coastguard Worker PropagateValue(inst->IfFalseSuccessor(), if_input, GetGraph()->GetIntConstant(0));
261*795d594fSAndroid Build Coastguard Worker
262*795d594fSAndroid Build Coastguard Worker // If the input is a condition, we can propagate the information of the condition itself.
263*795d594fSAndroid Build Coastguard Worker if (!if_input->IsCondition()) {
264*795d594fSAndroid Build Coastguard Worker return;
265*795d594fSAndroid Build Coastguard Worker }
266*795d594fSAndroid Build Coastguard Worker HCondition* condition = if_input->AsCondition();
267*795d594fSAndroid Build Coastguard Worker
268*795d594fSAndroid Build Coastguard Worker // We want either `==` or `!=`, since we cannot make assumptions for other conditions e.g. `>`
269*795d594fSAndroid Build Coastguard Worker if (!condition->IsEqual() && !condition->IsNotEqual()) {
270*795d594fSAndroid Build Coastguard Worker return;
271*795d594fSAndroid Build Coastguard Worker }
272*795d594fSAndroid Build Coastguard Worker
273*795d594fSAndroid Build Coastguard Worker HInstruction* left = condition->GetLeft();
274*795d594fSAndroid Build Coastguard Worker HInstruction* right = condition->GetRight();
275*795d594fSAndroid Build Coastguard Worker
276*795d594fSAndroid Build Coastguard Worker // We want one of them to be a constant and not the other.
277*795d594fSAndroid Build Coastguard Worker if (left->IsConstant() == right->IsConstant()) {
278*795d594fSAndroid Build Coastguard Worker return;
279*795d594fSAndroid Build Coastguard Worker }
280*795d594fSAndroid Build Coastguard Worker
281*795d594fSAndroid Build Coastguard Worker // At this point we have something like:
282*795d594fSAndroid Build Coastguard Worker // if (variable == constant) {
283*795d594fSAndroid Build Coastguard Worker // SSA `variable` guaranteed to be equal to constant here
284*795d594fSAndroid Build Coastguard Worker // } else {
285*795d594fSAndroid Build Coastguard Worker // No guarantees can be made here (usually, see boolean case below).
286*795d594fSAndroid Build Coastguard Worker // }
287*795d594fSAndroid Build Coastguard Worker // Similarly with variable != constant, except that we can make guarantees in the else case.
288*795d594fSAndroid Build Coastguard Worker
289*795d594fSAndroid Build Coastguard Worker HConstant* constant = left->IsConstant() ? left->AsConstant() : right->AsConstant();
290*795d594fSAndroid Build Coastguard Worker HInstruction* variable = left->IsConstant() ? right : left;
291*795d594fSAndroid Build Coastguard Worker
292*795d594fSAndroid Build Coastguard Worker // Don't deal with floats/doubles since they bring a lot of edge cases e.g.
293*795d594fSAndroid Build Coastguard Worker // if (f == 0.0f) {
294*795d594fSAndroid Build Coastguard Worker // // f is not really guaranteed to be 0.0f. It could be -0.0f, for example
295*795d594fSAndroid Build Coastguard Worker // }
296*795d594fSAndroid Build Coastguard Worker if (DataType::IsFloatingPointType(variable->GetType())) {
297*795d594fSAndroid Build Coastguard Worker return;
298*795d594fSAndroid Build Coastguard Worker }
299*795d594fSAndroid Build Coastguard Worker DCHECK(!DataType::IsFloatingPointType(constant->GetType()));
300*795d594fSAndroid Build Coastguard Worker
301*795d594fSAndroid Build Coastguard Worker // Sometimes we have an HCompare flowing into an Equals/NonEquals, which can act as a proxy. For
302*795d594fSAndroid Build Coastguard Worker // example: `Equals(Compare(var, constant), 0)`. This is common for long, float, and double.
303*795d594fSAndroid Build Coastguard Worker if (variable->IsCompare()) {
304*795d594fSAndroid Build Coastguard Worker // We only care about equality comparisons so we skip if it is a less or greater comparison.
305*795d594fSAndroid Build Coastguard Worker if (!constant->IsArithmeticZero()) {
306*795d594fSAndroid Build Coastguard Worker return;
307*795d594fSAndroid Build Coastguard Worker }
308*795d594fSAndroid Build Coastguard Worker
309*795d594fSAndroid Build Coastguard Worker // Update left and right to be the ones from the HCompare.
310*795d594fSAndroid Build Coastguard Worker left = variable->AsCompare()->GetLeft();
311*795d594fSAndroid Build Coastguard Worker right = variable->AsCompare()->GetRight();
312*795d594fSAndroid Build Coastguard Worker
313*795d594fSAndroid Build Coastguard Worker // Re-check that one of them to be a constant and not the other.
314*795d594fSAndroid Build Coastguard Worker if (left->IsConstant() == right->IsConstant()) {
315*795d594fSAndroid Build Coastguard Worker return;
316*795d594fSAndroid Build Coastguard Worker }
317*795d594fSAndroid Build Coastguard Worker
318*795d594fSAndroid Build Coastguard Worker constant = left->IsConstant() ? left->AsConstant() : right->AsConstant();
319*795d594fSAndroid Build Coastguard Worker variable = left->IsConstant() ? right : left;
320*795d594fSAndroid Build Coastguard Worker
321*795d594fSAndroid Build Coastguard Worker // Re-check floating point values.
322*795d594fSAndroid Build Coastguard Worker if (DataType::IsFloatingPointType(variable->GetType())) {
323*795d594fSAndroid Build Coastguard Worker return;
324*795d594fSAndroid Build Coastguard Worker }
325*795d594fSAndroid Build Coastguard Worker DCHECK(!DataType::IsFloatingPointType(constant->GetType()));
326*795d594fSAndroid Build Coastguard Worker }
327*795d594fSAndroid Build Coastguard Worker
328*795d594fSAndroid Build Coastguard Worker // From this block forward we want to replace the SSA value. We use `starting_block` and not the
329*795d594fSAndroid Build Coastguard Worker // `if` block as we want to update one of the branches but not the other.
330*795d594fSAndroid Build Coastguard Worker HBasicBlock* starting_block =
331*795d594fSAndroid Build Coastguard Worker condition->IsEqual() ? inst->IfTrueSuccessor() : inst->IfFalseSuccessor();
332*795d594fSAndroid Build Coastguard Worker
333*795d594fSAndroid Build Coastguard Worker PropagateValue(starting_block, variable, constant);
334*795d594fSAndroid Build Coastguard Worker
335*795d594fSAndroid Build Coastguard Worker // Special case for booleans since they have only two values so we know what to propagate in the
336*795d594fSAndroid Build Coastguard Worker // other branch. However, sometimes our boolean values are not compared to 0 or 1. In those cases
337*795d594fSAndroid Build Coastguard Worker // we cannot make an assumption for the `else` branch.
338*795d594fSAndroid Build Coastguard Worker if (variable->GetType() == DataType::Type::kBool &&
339*795d594fSAndroid Build Coastguard Worker constant->IsIntConstant() &&
340*795d594fSAndroid Build Coastguard Worker (constant->AsIntConstant()->IsTrue() || constant->AsIntConstant()->IsFalse())) {
341*795d594fSAndroid Build Coastguard Worker HBasicBlock* other_starting_block =
342*795d594fSAndroid Build Coastguard Worker condition->IsEqual() ? inst->IfFalseSuccessor() : inst->IfTrueSuccessor();
343*795d594fSAndroid Build Coastguard Worker DCHECK_NE(other_starting_block, starting_block);
344*795d594fSAndroid Build Coastguard Worker
345*795d594fSAndroid Build Coastguard Worker HConstant* other_constant = constant->AsIntConstant()->IsTrue() ?
346*795d594fSAndroid Build Coastguard Worker GetGraph()->GetIntConstant(0) :
347*795d594fSAndroid Build Coastguard Worker GetGraph()->GetIntConstant(1);
348*795d594fSAndroid Build Coastguard Worker DCHECK_NE(other_constant, constant);
349*795d594fSAndroid Build Coastguard Worker PropagateValue(other_starting_block, variable, other_constant);
350*795d594fSAndroid Build Coastguard Worker }
351*795d594fSAndroid Build Coastguard Worker }
352*795d594fSAndroid Build Coastguard Worker
VisitInvoke(HInvoke * inst)353*795d594fSAndroid Build Coastguard Worker void HConstantFoldingVisitor::VisitInvoke(HInvoke* inst) {
354*795d594fSAndroid Build Coastguard Worker switch (inst->GetIntrinsic()) {
355*795d594fSAndroid Build Coastguard Worker case Intrinsics::kIntegerReverse:
356*795d594fSAndroid Build Coastguard Worker case Intrinsics::kLongReverse:
357*795d594fSAndroid Build Coastguard Worker FoldReverseIntrinsic(inst);
358*795d594fSAndroid Build Coastguard Worker break;
359*795d594fSAndroid Build Coastguard Worker case Intrinsics::kIntegerReverseBytes:
360*795d594fSAndroid Build Coastguard Worker case Intrinsics::kLongReverseBytes:
361*795d594fSAndroid Build Coastguard Worker case Intrinsics::kShortReverseBytes:
362*795d594fSAndroid Build Coastguard Worker FoldReverseBytesIntrinsic(inst);
363*795d594fSAndroid Build Coastguard Worker break;
364*795d594fSAndroid Build Coastguard Worker case Intrinsics::kIntegerBitCount:
365*795d594fSAndroid Build Coastguard Worker case Intrinsics::kLongBitCount:
366*795d594fSAndroid Build Coastguard Worker FoldBitCountIntrinsic(inst);
367*795d594fSAndroid Build Coastguard Worker break;
368*795d594fSAndroid Build Coastguard Worker case Intrinsics::kIntegerDivideUnsigned:
369*795d594fSAndroid Build Coastguard Worker case Intrinsics::kLongDivideUnsigned:
370*795d594fSAndroid Build Coastguard Worker FoldDivideUnsignedIntrinsic(inst);
371*795d594fSAndroid Build Coastguard Worker break;
372*795d594fSAndroid Build Coastguard Worker case Intrinsics::kIntegerHighestOneBit:
373*795d594fSAndroid Build Coastguard Worker case Intrinsics::kLongHighestOneBit:
374*795d594fSAndroid Build Coastguard Worker FoldHighestOneBitIntrinsic(inst);
375*795d594fSAndroid Build Coastguard Worker break;
376*795d594fSAndroid Build Coastguard Worker case Intrinsics::kIntegerLowestOneBit:
377*795d594fSAndroid Build Coastguard Worker case Intrinsics::kLongLowestOneBit:
378*795d594fSAndroid Build Coastguard Worker FoldLowestOneBitIntrinsic(inst);
379*795d594fSAndroid Build Coastguard Worker break;
380*795d594fSAndroid Build Coastguard Worker case Intrinsics::kIntegerNumberOfLeadingZeros:
381*795d594fSAndroid Build Coastguard Worker case Intrinsics::kLongNumberOfLeadingZeros:
382*795d594fSAndroid Build Coastguard Worker FoldNumberOfLeadingZerosIntrinsic(inst);
383*795d594fSAndroid Build Coastguard Worker break;
384*795d594fSAndroid Build Coastguard Worker case Intrinsics::kIntegerNumberOfTrailingZeros:
385*795d594fSAndroid Build Coastguard Worker case Intrinsics::kLongNumberOfTrailingZeros:
386*795d594fSAndroid Build Coastguard Worker FoldNumberOfTrailingZerosIntrinsic(inst);
387*795d594fSAndroid Build Coastguard Worker break;
388*795d594fSAndroid Build Coastguard Worker default:
389*795d594fSAndroid Build Coastguard Worker break;
390*795d594fSAndroid Build Coastguard Worker }
391*795d594fSAndroid Build Coastguard Worker }
392*795d594fSAndroid Build Coastguard Worker
FoldReverseIntrinsic(HInvoke * inst)393*795d594fSAndroid Build Coastguard Worker void HConstantFoldingVisitor::FoldReverseIntrinsic(HInvoke* inst) {
394*795d594fSAndroid Build Coastguard Worker DCHECK(inst->GetIntrinsic() == Intrinsics::kIntegerReverse ||
395*795d594fSAndroid Build Coastguard Worker inst->GetIntrinsic() == Intrinsics::kLongReverse);
396*795d594fSAndroid Build Coastguard Worker
397*795d594fSAndroid Build Coastguard Worker HInstruction* input = inst->InputAt(0);
398*795d594fSAndroid Build Coastguard Worker if (!input->IsConstant()) {
399*795d594fSAndroid Build Coastguard Worker return;
400*795d594fSAndroid Build Coastguard Worker }
401*795d594fSAndroid Build Coastguard Worker
402*795d594fSAndroid Build Coastguard Worker // Integer and Long intrinsics have different return types.
403*795d594fSAndroid Build Coastguard Worker if (inst->GetIntrinsic() == Intrinsics::kIntegerReverse) {
404*795d594fSAndroid Build Coastguard Worker DCHECK(input->IsIntConstant());
405*795d594fSAndroid Build Coastguard Worker inst->ReplaceWith(
406*795d594fSAndroid Build Coastguard Worker GetGraph()->GetIntConstant(ReverseBits32(input->AsIntConstant()->GetValue())));
407*795d594fSAndroid Build Coastguard Worker } else {
408*795d594fSAndroid Build Coastguard Worker DCHECK(input->IsLongConstant());
409*795d594fSAndroid Build Coastguard Worker inst->ReplaceWith(
410*795d594fSAndroid Build Coastguard Worker GetGraph()->GetLongConstant(ReverseBits64(input->AsLongConstant()->GetValue())));
411*795d594fSAndroid Build Coastguard Worker }
412*795d594fSAndroid Build Coastguard Worker inst->GetBlock()->RemoveInstruction(inst);
413*795d594fSAndroid Build Coastguard Worker }
414*795d594fSAndroid Build Coastguard Worker
FoldReverseBytesIntrinsic(HInvoke * inst)415*795d594fSAndroid Build Coastguard Worker void HConstantFoldingVisitor::FoldReverseBytesIntrinsic(HInvoke* inst) {
416*795d594fSAndroid Build Coastguard Worker DCHECK(inst->GetIntrinsic() == Intrinsics::kIntegerReverseBytes ||
417*795d594fSAndroid Build Coastguard Worker inst->GetIntrinsic() == Intrinsics::kLongReverseBytes ||
418*795d594fSAndroid Build Coastguard Worker inst->GetIntrinsic() == Intrinsics::kShortReverseBytes);
419*795d594fSAndroid Build Coastguard Worker
420*795d594fSAndroid Build Coastguard Worker HInstruction* input = inst->InputAt(0);
421*795d594fSAndroid Build Coastguard Worker if (!input->IsConstant()) {
422*795d594fSAndroid Build Coastguard Worker return;
423*795d594fSAndroid Build Coastguard Worker }
424*795d594fSAndroid Build Coastguard Worker
425*795d594fSAndroid Build Coastguard Worker // Integer, Long, and Short intrinsics have different return types.
426*795d594fSAndroid Build Coastguard Worker if (inst->GetIntrinsic() == Intrinsics::kIntegerReverseBytes) {
427*795d594fSAndroid Build Coastguard Worker DCHECK(input->IsIntConstant());
428*795d594fSAndroid Build Coastguard Worker inst->ReplaceWith(GetGraph()->GetIntConstant(BSWAP(input->AsIntConstant()->GetValue())));
429*795d594fSAndroid Build Coastguard Worker } else if (inst->GetIntrinsic() == Intrinsics::kLongReverseBytes) {
430*795d594fSAndroid Build Coastguard Worker DCHECK(input->IsLongConstant());
431*795d594fSAndroid Build Coastguard Worker inst->ReplaceWith(GetGraph()->GetLongConstant(BSWAP(input->AsLongConstant()->GetValue())));
432*795d594fSAndroid Build Coastguard Worker } else {
433*795d594fSAndroid Build Coastguard Worker DCHECK(input->IsIntConstant());
434*795d594fSAndroid Build Coastguard Worker inst->ReplaceWith(GetGraph()->GetIntConstant(
435*795d594fSAndroid Build Coastguard Worker BSWAP(dchecked_integral_cast<int16_t>(input->AsIntConstant()->GetValue()))));
436*795d594fSAndroid Build Coastguard Worker }
437*795d594fSAndroid Build Coastguard Worker inst->GetBlock()->RemoveInstruction(inst);
438*795d594fSAndroid Build Coastguard Worker }
439*795d594fSAndroid Build Coastguard Worker
FoldBitCountIntrinsic(HInvoke * inst)440*795d594fSAndroid Build Coastguard Worker void HConstantFoldingVisitor::FoldBitCountIntrinsic(HInvoke* inst) {
441*795d594fSAndroid Build Coastguard Worker DCHECK(inst->GetIntrinsic() == Intrinsics::kIntegerBitCount ||
442*795d594fSAndroid Build Coastguard Worker inst->GetIntrinsic() == Intrinsics::kLongBitCount);
443*795d594fSAndroid Build Coastguard Worker
444*795d594fSAndroid Build Coastguard Worker HInstruction* input = inst->InputAt(0);
445*795d594fSAndroid Build Coastguard Worker if (!input->IsConstant()) {
446*795d594fSAndroid Build Coastguard Worker return;
447*795d594fSAndroid Build Coastguard Worker }
448*795d594fSAndroid Build Coastguard Worker
449*795d594fSAndroid Build Coastguard Worker DCHECK_IMPLIES(inst->GetIntrinsic() == Intrinsics::kIntegerBitCount, input->IsIntConstant());
450*795d594fSAndroid Build Coastguard Worker DCHECK_IMPLIES(inst->GetIntrinsic() == Intrinsics::kLongBitCount, input->IsLongConstant());
451*795d594fSAndroid Build Coastguard Worker
452*795d594fSAndroid Build Coastguard Worker // Note that both the Integer and Long intrinsics return an int as a result.
453*795d594fSAndroid Build Coastguard Worker int result = inst->GetIntrinsic() == Intrinsics::kIntegerBitCount ?
454*795d594fSAndroid Build Coastguard Worker POPCOUNT(input->AsIntConstant()->GetValue()) :
455*795d594fSAndroid Build Coastguard Worker POPCOUNT(input->AsLongConstant()->GetValue());
456*795d594fSAndroid Build Coastguard Worker inst->ReplaceWith(GetGraph()->GetIntConstant(result));
457*795d594fSAndroid Build Coastguard Worker inst->GetBlock()->RemoveInstruction(inst);
458*795d594fSAndroid Build Coastguard Worker }
459*795d594fSAndroid Build Coastguard Worker
FoldDivideUnsignedIntrinsic(HInvoke * inst)460*795d594fSAndroid Build Coastguard Worker void HConstantFoldingVisitor::FoldDivideUnsignedIntrinsic(HInvoke* inst) {
461*795d594fSAndroid Build Coastguard Worker DCHECK(inst->GetIntrinsic() == Intrinsics::kIntegerDivideUnsigned ||
462*795d594fSAndroid Build Coastguard Worker inst->GetIntrinsic() == Intrinsics::kLongDivideUnsigned);
463*795d594fSAndroid Build Coastguard Worker
464*795d594fSAndroid Build Coastguard Worker HInstruction* divisor = inst->InputAt(1);
465*795d594fSAndroid Build Coastguard Worker if (!divisor->IsConstant()) {
466*795d594fSAndroid Build Coastguard Worker return;
467*795d594fSAndroid Build Coastguard Worker }
468*795d594fSAndroid Build Coastguard Worker DCHECK_IMPLIES(inst->GetIntrinsic() == Intrinsics::kIntegerDivideUnsigned,
469*795d594fSAndroid Build Coastguard Worker divisor->IsIntConstant());
470*795d594fSAndroid Build Coastguard Worker DCHECK_IMPLIES(inst->GetIntrinsic() == Intrinsics::kLongDivideUnsigned,
471*795d594fSAndroid Build Coastguard Worker divisor->IsLongConstant());
472*795d594fSAndroid Build Coastguard Worker const bool is_int_intrinsic = inst->GetIntrinsic() == Intrinsics::kIntegerDivideUnsigned;
473*795d594fSAndroid Build Coastguard Worker if ((is_int_intrinsic && divisor->AsIntConstant()->IsArithmeticZero()) ||
474*795d594fSAndroid Build Coastguard Worker (!is_int_intrinsic && divisor->AsLongConstant()->IsArithmeticZero())) {
475*795d594fSAndroid Build Coastguard Worker // We will be throwing, don't constant fold.
476*795d594fSAndroid Build Coastguard Worker inst->SetAlwaysThrows(true);
477*795d594fSAndroid Build Coastguard Worker GetGraph()->SetHasAlwaysThrowingInvokes(true);
478*795d594fSAndroid Build Coastguard Worker return;
479*795d594fSAndroid Build Coastguard Worker }
480*795d594fSAndroid Build Coastguard Worker
481*795d594fSAndroid Build Coastguard Worker HInstruction* dividend = inst->InputAt(0);
482*795d594fSAndroid Build Coastguard Worker if (!dividend->IsConstant()) {
483*795d594fSAndroid Build Coastguard Worker return;
484*795d594fSAndroid Build Coastguard Worker }
485*795d594fSAndroid Build Coastguard Worker DCHECK_IMPLIES(inst->GetIntrinsic() == Intrinsics::kIntegerDivideUnsigned,
486*795d594fSAndroid Build Coastguard Worker dividend->IsIntConstant());
487*795d594fSAndroid Build Coastguard Worker DCHECK_IMPLIES(inst->GetIntrinsic() == Intrinsics::kLongDivideUnsigned,
488*795d594fSAndroid Build Coastguard Worker dividend->IsLongConstant());
489*795d594fSAndroid Build Coastguard Worker
490*795d594fSAndroid Build Coastguard Worker if (is_int_intrinsic) {
491*795d594fSAndroid Build Coastguard Worker uint32_t dividend_val =
492*795d594fSAndroid Build Coastguard Worker dchecked_integral_cast<uint32_t>(dividend->AsIntConstant()->GetValueAsUint64());
493*795d594fSAndroid Build Coastguard Worker uint32_t divisor_val =
494*795d594fSAndroid Build Coastguard Worker dchecked_integral_cast<uint32_t>(divisor->AsIntConstant()->GetValueAsUint64());
495*795d594fSAndroid Build Coastguard Worker inst->ReplaceWith(GetGraph()->GetIntConstant(static_cast<int32_t>(dividend_val / divisor_val)));
496*795d594fSAndroid Build Coastguard Worker } else {
497*795d594fSAndroid Build Coastguard Worker uint64_t dividend_val = dividend->AsLongConstant()->GetValueAsUint64();
498*795d594fSAndroid Build Coastguard Worker uint64_t divisor_val = divisor->AsLongConstant()->GetValueAsUint64();
499*795d594fSAndroid Build Coastguard Worker inst->ReplaceWith(
500*795d594fSAndroid Build Coastguard Worker GetGraph()->GetLongConstant(static_cast<int64_t>(dividend_val / divisor_val)));
501*795d594fSAndroid Build Coastguard Worker }
502*795d594fSAndroid Build Coastguard Worker
503*795d594fSAndroid Build Coastguard Worker inst->GetBlock()->RemoveInstruction(inst);
504*795d594fSAndroid Build Coastguard Worker }
505*795d594fSAndroid Build Coastguard Worker
FoldHighestOneBitIntrinsic(HInvoke * inst)506*795d594fSAndroid Build Coastguard Worker void HConstantFoldingVisitor::FoldHighestOneBitIntrinsic(HInvoke* inst) {
507*795d594fSAndroid Build Coastguard Worker DCHECK(inst->GetIntrinsic() == Intrinsics::kIntegerHighestOneBit ||
508*795d594fSAndroid Build Coastguard Worker inst->GetIntrinsic() == Intrinsics::kLongHighestOneBit);
509*795d594fSAndroid Build Coastguard Worker
510*795d594fSAndroid Build Coastguard Worker HInstruction* input = inst->InputAt(0);
511*795d594fSAndroid Build Coastguard Worker if (!input->IsConstant()) {
512*795d594fSAndroid Build Coastguard Worker return;
513*795d594fSAndroid Build Coastguard Worker }
514*795d594fSAndroid Build Coastguard Worker
515*795d594fSAndroid Build Coastguard Worker // Integer and Long intrinsics have different return types.
516*795d594fSAndroid Build Coastguard Worker if (inst->GetIntrinsic() == Intrinsics::kIntegerHighestOneBit) {
517*795d594fSAndroid Build Coastguard Worker DCHECK(input->IsIntConstant());
518*795d594fSAndroid Build Coastguard Worker inst->ReplaceWith(
519*795d594fSAndroid Build Coastguard Worker GetGraph()->GetIntConstant(HighestOneBitValue(input->AsIntConstant()->GetValue())));
520*795d594fSAndroid Build Coastguard Worker } else {
521*795d594fSAndroid Build Coastguard Worker DCHECK(input->IsLongConstant());
522*795d594fSAndroid Build Coastguard Worker inst->ReplaceWith(
523*795d594fSAndroid Build Coastguard Worker GetGraph()->GetLongConstant(HighestOneBitValue(input->AsLongConstant()->GetValue())));
524*795d594fSAndroid Build Coastguard Worker }
525*795d594fSAndroid Build Coastguard Worker inst->GetBlock()->RemoveInstruction(inst);
526*795d594fSAndroid Build Coastguard Worker }
527*795d594fSAndroid Build Coastguard Worker
FoldLowestOneBitIntrinsic(HInvoke * inst)528*795d594fSAndroid Build Coastguard Worker void HConstantFoldingVisitor::FoldLowestOneBitIntrinsic(HInvoke* inst) {
529*795d594fSAndroid Build Coastguard Worker DCHECK(inst->GetIntrinsic() == Intrinsics::kIntegerLowestOneBit ||
530*795d594fSAndroid Build Coastguard Worker inst->GetIntrinsic() == Intrinsics::kLongLowestOneBit);
531*795d594fSAndroid Build Coastguard Worker
532*795d594fSAndroid Build Coastguard Worker HInstruction* input = inst->InputAt(0);
533*795d594fSAndroid Build Coastguard Worker if (!input->IsConstant()) {
534*795d594fSAndroid Build Coastguard Worker return;
535*795d594fSAndroid Build Coastguard Worker }
536*795d594fSAndroid Build Coastguard Worker
537*795d594fSAndroid Build Coastguard Worker // Integer and Long intrinsics have different return types.
538*795d594fSAndroid Build Coastguard Worker if (inst->GetIntrinsic() == Intrinsics::kIntegerLowestOneBit) {
539*795d594fSAndroid Build Coastguard Worker DCHECK(input->IsIntConstant());
540*795d594fSAndroid Build Coastguard Worker inst->ReplaceWith(
541*795d594fSAndroid Build Coastguard Worker GetGraph()->GetIntConstant(LowestOneBitValue(input->AsIntConstant()->GetValue())));
542*795d594fSAndroid Build Coastguard Worker } else {
543*795d594fSAndroid Build Coastguard Worker DCHECK(input->IsLongConstant());
544*795d594fSAndroid Build Coastguard Worker inst->ReplaceWith(
545*795d594fSAndroid Build Coastguard Worker GetGraph()->GetLongConstant(LowestOneBitValue(input->AsLongConstant()->GetValue())));
546*795d594fSAndroid Build Coastguard Worker }
547*795d594fSAndroid Build Coastguard Worker inst->GetBlock()->RemoveInstruction(inst);
548*795d594fSAndroid Build Coastguard Worker }
549*795d594fSAndroid Build Coastguard Worker
FoldNumberOfLeadingZerosIntrinsic(HInvoke * inst)550*795d594fSAndroid Build Coastguard Worker void HConstantFoldingVisitor::FoldNumberOfLeadingZerosIntrinsic(HInvoke* inst) {
551*795d594fSAndroid Build Coastguard Worker DCHECK(inst->GetIntrinsic() == Intrinsics::kIntegerNumberOfLeadingZeros ||
552*795d594fSAndroid Build Coastguard Worker inst->GetIntrinsic() == Intrinsics::kLongNumberOfLeadingZeros);
553*795d594fSAndroid Build Coastguard Worker
554*795d594fSAndroid Build Coastguard Worker HInstruction* input = inst->InputAt(0);
555*795d594fSAndroid Build Coastguard Worker if (!input->IsConstant()) {
556*795d594fSAndroid Build Coastguard Worker return;
557*795d594fSAndroid Build Coastguard Worker }
558*795d594fSAndroid Build Coastguard Worker
559*795d594fSAndroid Build Coastguard Worker DCHECK_IMPLIES(inst->GetIntrinsic() == Intrinsics::kIntegerNumberOfLeadingZeros,
560*795d594fSAndroid Build Coastguard Worker input->IsIntConstant());
561*795d594fSAndroid Build Coastguard Worker DCHECK_IMPLIES(inst->GetIntrinsic() == Intrinsics::kLongNumberOfLeadingZeros,
562*795d594fSAndroid Build Coastguard Worker input->IsLongConstant());
563*795d594fSAndroid Build Coastguard Worker
564*795d594fSAndroid Build Coastguard Worker // Note that both the Integer and Long intrinsics return an int as a result.
565*795d594fSAndroid Build Coastguard Worker int result = input->IsIntConstant() ? JAVASTYLE_CLZ(input->AsIntConstant()->GetValue()) :
566*795d594fSAndroid Build Coastguard Worker JAVASTYLE_CLZ(input->AsLongConstant()->GetValue());
567*795d594fSAndroid Build Coastguard Worker inst->ReplaceWith(GetGraph()->GetIntConstant(result));
568*795d594fSAndroid Build Coastguard Worker inst->GetBlock()->RemoveInstruction(inst);
569*795d594fSAndroid Build Coastguard Worker }
570*795d594fSAndroid Build Coastguard Worker
FoldNumberOfTrailingZerosIntrinsic(HInvoke * inst)571*795d594fSAndroid Build Coastguard Worker void HConstantFoldingVisitor::FoldNumberOfTrailingZerosIntrinsic(HInvoke* inst) {
572*795d594fSAndroid Build Coastguard Worker DCHECK(inst->GetIntrinsic() == Intrinsics::kIntegerNumberOfTrailingZeros ||
573*795d594fSAndroid Build Coastguard Worker inst->GetIntrinsic() == Intrinsics::kLongNumberOfTrailingZeros);
574*795d594fSAndroid Build Coastguard Worker
575*795d594fSAndroid Build Coastguard Worker HInstruction* input = inst->InputAt(0);
576*795d594fSAndroid Build Coastguard Worker if (!input->IsConstant()) {
577*795d594fSAndroid Build Coastguard Worker return;
578*795d594fSAndroid Build Coastguard Worker }
579*795d594fSAndroid Build Coastguard Worker
580*795d594fSAndroid Build Coastguard Worker DCHECK_IMPLIES(inst->GetIntrinsic() == Intrinsics::kIntegerNumberOfTrailingZeros,
581*795d594fSAndroid Build Coastguard Worker input->IsIntConstant());
582*795d594fSAndroid Build Coastguard Worker DCHECK_IMPLIES(inst->GetIntrinsic() == Intrinsics::kLongNumberOfTrailingZeros,
583*795d594fSAndroid Build Coastguard Worker input->IsLongConstant());
584*795d594fSAndroid Build Coastguard Worker
585*795d594fSAndroid Build Coastguard Worker // Note that both the Integer and Long intrinsics return an int as a result.
586*795d594fSAndroid Build Coastguard Worker int result = input->IsIntConstant() ? JAVASTYLE_CTZ(input->AsIntConstant()->GetValue()) :
587*795d594fSAndroid Build Coastguard Worker JAVASTYLE_CTZ(input->AsLongConstant()->GetValue());
588*795d594fSAndroid Build Coastguard Worker inst->ReplaceWith(GetGraph()->GetIntConstant(result));
589*795d594fSAndroid Build Coastguard Worker inst->GetBlock()->RemoveInstruction(inst);
590*795d594fSAndroid Build Coastguard Worker }
591*795d594fSAndroid Build Coastguard Worker
VisitArrayLength(HArrayLength * inst)592*795d594fSAndroid Build Coastguard Worker void HConstantFoldingVisitor::VisitArrayLength(HArrayLength* inst) {
593*795d594fSAndroid Build Coastguard Worker HInstruction* input = inst->InputAt(0);
594*795d594fSAndroid Build Coastguard Worker if (input->IsLoadString()) {
595*795d594fSAndroid Build Coastguard Worker DCHECK(inst->IsStringLength());
596*795d594fSAndroid Build Coastguard Worker HLoadString* load_string = input->AsLoadString();
597*795d594fSAndroid Build Coastguard Worker const DexFile& dex_file = load_string->GetDexFile();
598*795d594fSAndroid Build Coastguard Worker const dex::StringId& string_id = dex_file.GetStringId(load_string->GetStringIndex());
599*795d594fSAndroid Build Coastguard Worker inst->ReplaceWith(GetGraph()->GetIntConstant(
600*795d594fSAndroid Build Coastguard Worker dchecked_integral_cast<int32_t>(dex_file.GetStringUtf16Length(string_id))));
601*795d594fSAndroid Build Coastguard Worker }
602*795d594fSAndroid Build Coastguard Worker }
603*795d594fSAndroid Build Coastguard Worker
VisitTypeConversion(HTypeConversion * inst)604*795d594fSAndroid Build Coastguard Worker void HConstantFoldingVisitor::VisitTypeConversion(HTypeConversion* inst) {
605*795d594fSAndroid Build Coastguard Worker // Constant folding: replace `TypeConversion(a)' with a constant at
606*795d594fSAndroid Build Coastguard Worker // compile time if `a' is a constant.
607*795d594fSAndroid Build Coastguard Worker HConstant* constant = inst->TryStaticEvaluation();
608*795d594fSAndroid Build Coastguard Worker if (constant != nullptr) {
609*795d594fSAndroid Build Coastguard Worker inst->ReplaceWith(constant);
610*795d594fSAndroid Build Coastguard Worker inst->GetBlock()->RemoveInstruction(inst);
611*795d594fSAndroid Build Coastguard Worker } else if (inst->InputAt(0)->IsSelect() && inst->InputAt(0)->HasOnlyOneNonEnvironmentUse()) {
612*795d594fSAndroid Build Coastguard Worker // Try to replace the select's inputs in Select+TypeConversion. We can do this if both
613*795d594fSAndroid Build Coastguard Worker // inputs to the select are constants, and this is the only use of the select.
614*795d594fSAndroid Build Coastguard Worker HSelect* select = inst->InputAt(0)->AsSelect();
615*795d594fSAndroid Build Coastguard Worker HConstant* false_constant = inst->TryStaticEvaluation(select->GetFalseValue());
616*795d594fSAndroid Build Coastguard Worker if (false_constant == nullptr) {
617*795d594fSAndroid Build Coastguard Worker return;
618*795d594fSAndroid Build Coastguard Worker }
619*795d594fSAndroid Build Coastguard Worker HConstant* true_constant = inst->TryStaticEvaluation(select->GetTrueValue());
620*795d594fSAndroid Build Coastguard Worker if (true_constant == nullptr) {
621*795d594fSAndroid Build Coastguard Worker return;
622*795d594fSAndroid Build Coastguard Worker }
623*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(select->InputAt(0), select->GetFalseValue());
624*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(select->InputAt(1), select->GetTrueValue());
625*795d594fSAndroid Build Coastguard Worker select->ReplaceInput(false_constant, 0);
626*795d594fSAndroid Build Coastguard Worker select->ReplaceInput(true_constant, 1);
627*795d594fSAndroid Build Coastguard Worker select->UpdateType();
628*795d594fSAndroid Build Coastguard Worker inst->ReplaceWith(select);
629*795d594fSAndroid Build Coastguard Worker inst->GetBlock()->RemoveInstruction(inst);
630*795d594fSAndroid Build Coastguard Worker }
631*795d594fSAndroid Build Coastguard Worker }
632*795d594fSAndroid Build Coastguard Worker
VisitShift(HBinaryOperation * instruction)633*795d594fSAndroid Build Coastguard Worker void InstructionWithAbsorbingInputSimplifier::VisitShift(HBinaryOperation* instruction) {
634*795d594fSAndroid Build Coastguard Worker DCHECK(instruction->IsShl() || instruction->IsShr() || instruction->IsUShr());
635*795d594fSAndroid Build Coastguard Worker HInstruction* left = instruction->GetLeft();
636*795d594fSAndroid Build Coastguard Worker if (left->IsConstant() && left->AsConstant()->IsArithmeticZero()) {
637*795d594fSAndroid Build Coastguard Worker // Replace code looking like
638*795d594fSAndroid Build Coastguard Worker // SHL dst, 0, shift_amount
639*795d594fSAndroid Build Coastguard Worker // with
640*795d594fSAndroid Build Coastguard Worker // CONSTANT 0
641*795d594fSAndroid Build Coastguard Worker instruction->ReplaceWith(left);
642*795d594fSAndroid Build Coastguard Worker instruction->GetBlock()->RemoveInstruction(instruction);
643*795d594fSAndroid Build Coastguard Worker }
644*795d594fSAndroid Build Coastguard Worker }
645*795d594fSAndroid Build Coastguard Worker
VisitEqual(HEqual * instruction)646*795d594fSAndroid Build Coastguard Worker void InstructionWithAbsorbingInputSimplifier::VisitEqual(HEqual* instruction) {
647*795d594fSAndroid Build Coastguard Worker if (instruction->GetLeft() == instruction->GetRight() &&
648*795d594fSAndroid Build Coastguard Worker !DataType::IsFloatingPointType(instruction->GetLeft()->GetType())) {
649*795d594fSAndroid Build Coastguard Worker // Replace code looking like
650*795d594fSAndroid Build Coastguard Worker // EQUAL lhs, lhs
651*795d594fSAndroid Build Coastguard Worker // CONSTANT true
652*795d594fSAndroid Build Coastguard Worker // We don't perform this optimizations for FP types since Double.NaN != Double.NaN, which is the
653*795d594fSAndroid Build Coastguard Worker // opposite value.
654*795d594fSAndroid Build Coastguard Worker instruction->ReplaceWith(GetGraph()->GetConstant(DataType::Type::kBool, 1));
655*795d594fSAndroid Build Coastguard Worker instruction->GetBlock()->RemoveInstruction(instruction);
656*795d594fSAndroid Build Coastguard Worker } else if ((instruction->GetLeft()->IsNullConstant() && !instruction->GetRight()->CanBeNull()) ||
657*795d594fSAndroid Build Coastguard Worker (instruction->GetRight()->IsNullConstant() && !instruction->GetLeft()->CanBeNull())) {
658*795d594fSAndroid Build Coastguard Worker // Replace code looking like
659*795d594fSAndroid Build Coastguard Worker // EQUAL lhs, null
660*795d594fSAndroid Build Coastguard Worker // where lhs cannot be null with
661*795d594fSAndroid Build Coastguard Worker // CONSTANT false
662*795d594fSAndroid Build Coastguard Worker instruction->ReplaceWith(GetGraph()->GetConstant(DataType::Type::kBool, 0));
663*795d594fSAndroid Build Coastguard Worker instruction->GetBlock()->RemoveInstruction(instruction);
664*795d594fSAndroid Build Coastguard Worker }
665*795d594fSAndroid Build Coastguard Worker }
666*795d594fSAndroid Build Coastguard Worker
VisitNotEqual(HNotEqual * instruction)667*795d594fSAndroid Build Coastguard Worker void InstructionWithAbsorbingInputSimplifier::VisitNotEqual(HNotEqual* instruction) {
668*795d594fSAndroid Build Coastguard Worker if (instruction->GetLeft() == instruction->GetRight() &&
669*795d594fSAndroid Build Coastguard Worker !DataType::IsFloatingPointType(instruction->GetLeft()->GetType())) {
670*795d594fSAndroid Build Coastguard Worker // Replace code looking like
671*795d594fSAndroid Build Coastguard Worker // NOT_EQUAL lhs, lhs
672*795d594fSAndroid Build Coastguard Worker // CONSTANT false
673*795d594fSAndroid Build Coastguard Worker // We don't perform this optimizations for FP types since Double.NaN != Double.NaN, which is the
674*795d594fSAndroid Build Coastguard Worker // opposite value.
675*795d594fSAndroid Build Coastguard Worker instruction->ReplaceWith(GetGraph()->GetConstant(DataType::Type::kBool, 0));
676*795d594fSAndroid Build Coastguard Worker instruction->GetBlock()->RemoveInstruction(instruction);
677*795d594fSAndroid Build Coastguard Worker } else if ((instruction->GetLeft()->IsNullConstant() && !instruction->GetRight()->CanBeNull()) ||
678*795d594fSAndroid Build Coastguard Worker (instruction->GetRight()->IsNullConstant() && !instruction->GetLeft()->CanBeNull())) {
679*795d594fSAndroid Build Coastguard Worker // Replace code looking like
680*795d594fSAndroid Build Coastguard Worker // NOT_EQUAL lhs, null
681*795d594fSAndroid Build Coastguard Worker // where lhs cannot be null with
682*795d594fSAndroid Build Coastguard Worker // CONSTANT true
683*795d594fSAndroid Build Coastguard Worker instruction->ReplaceWith(GetGraph()->GetConstant(DataType::Type::kBool, 1));
684*795d594fSAndroid Build Coastguard Worker instruction->GetBlock()->RemoveInstruction(instruction);
685*795d594fSAndroid Build Coastguard Worker }
686*795d594fSAndroid Build Coastguard Worker }
687*795d594fSAndroid Build Coastguard Worker
VisitAbove(HAbove * instruction)688*795d594fSAndroid Build Coastguard Worker void InstructionWithAbsorbingInputSimplifier::VisitAbove(HAbove* instruction) {
689*795d594fSAndroid Build Coastguard Worker if (instruction->GetLeft() == instruction->GetRight()) {
690*795d594fSAndroid Build Coastguard Worker // Replace code looking like
691*795d594fSAndroid Build Coastguard Worker // ABOVE lhs, lhs
692*795d594fSAndroid Build Coastguard Worker // CONSTANT false
693*795d594fSAndroid Build Coastguard Worker instruction->ReplaceWith(GetGraph()->GetConstant(DataType::Type::kBool, 0));
694*795d594fSAndroid Build Coastguard Worker instruction->GetBlock()->RemoveInstruction(instruction);
695*795d594fSAndroid Build Coastguard Worker } else if (instruction->GetLeft()->IsConstant() &&
696*795d594fSAndroid Build Coastguard Worker instruction->GetLeft()->AsConstant()->IsArithmeticZero()) {
697*795d594fSAndroid Build Coastguard Worker // Replace code looking like
698*795d594fSAndroid Build Coastguard Worker // ABOVE dst, 0, src // unsigned 0 > src is always false
699*795d594fSAndroid Build Coastguard Worker // with
700*795d594fSAndroid Build Coastguard Worker // CONSTANT false
701*795d594fSAndroid Build Coastguard Worker instruction->ReplaceWith(GetGraph()->GetConstant(DataType::Type::kBool, 0));
702*795d594fSAndroid Build Coastguard Worker instruction->GetBlock()->RemoveInstruction(instruction);
703*795d594fSAndroid Build Coastguard Worker }
704*795d594fSAndroid Build Coastguard Worker }
705*795d594fSAndroid Build Coastguard Worker
VisitAboveOrEqual(HAboveOrEqual * instruction)706*795d594fSAndroid Build Coastguard Worker void InstructionWithAbsorbingInputSimplifier::VisitAboveOrEqual(HAboveOrEqual* instruction) {
707*795d594fSAndroid Build Coastguard Worker if (instruction->GetLeft() == instruction->GetRight()) {
708*795d594fSAndroid Build Coastguard Worker // Replace code looking like
709*795d594fSAndroid Build Coastguard Worker // ABOVE_OR_EQUAL lhs, lhs
710*795d594fSAndroid Build Coastguard Worker // CONSTANT true
711*795d594fSAndroid Build Coastguard Worker instruction->ReplaceWith(GetGraph()->GetConstant(DataType::Type::kBool, 1));
712*795d594fSAndroid Build Coastguard Worker instruction->GetBlock()->RemoveInstruction(instruction);
713*795d594fSAndroid Build Coastguard Worker } else if (instruction->GetRight()->IsConstant() &&
714*795d594fSAndroid Build Coastguard Worker instruction->GetRight()->AsConstant()->IsArithmeticZero()) {
715*795d594fSAndroid Build Coastguard Worker // Replace code looking like
716*795d594fSAndroid Build Coastguard Worker // ABOVE_OR_EQUAL dst, src, 0 // unsigned src >= 0 is always true
717*795d594fSAndroid Build Coastguard Worker // with
718*795d594fSAndroid Build Coastguard Worker // CONSTANT true
719*795d594fSAndroid Build Coastguard Worker instruction->ReplaceWith(GetGraph()->GetConstant(DataType::Type::kBool, 1));
720*795d594fSAndroid Build Coastguard Worker instruction->GetBlock()->RemoveInstruction(instruction);
721*795d594fSAndroid Build Coastguard Worker }
722*795d594fSAndroid Build Coastguard Worker }
723*795d594fSAndroid Build Coastguard Worker
VisitBelow(HBelow * instruction)724*795d594fSAndroid Build Coastguard Worker void InstructionWithAbsorbingInputSimplifier::VisitBelow(HBelow* instruction) {
725*795d594fSAndroid Build Coastguard Worker if (instruction->GetLeft() == instruction->GetRight()) {
726*795d594fSAndroid Build Coastguard Worker // Replace code looking like
727*795d594fSAndroid Build Coastguard Worker // BELOW lhs, lhs
728*795d594fSAndroid Build Coastguard Worker // CONSTANT false
729*795d594fSAndroid Build Coastguard Worker instruction->ReplaceWith(GetGraph()->GetConstant(DataType::Type::kBool, 0));
730*795d594fSAndroid Build Coastguard Worker instruction->GetBlock()->RemoveInstruction(instruction);
731*795d594fSAndroid Build Coastguard Worker } else if (instruction->GetRight()->IsConstant() &&
732*795d594fSAndroid Build Coastguard Worker instruction->GetRight()->AsConstant()->IsArithmeticZero()) {
733*795d594fSAndroid Build Coastguard Worker // Replace code looking like
734*795d594fSAndroid Build Coastguard Worker // BELOW dst, src, 0 // unsigned src < 0 is always false
735*795d594fSAndroid Build Coastguard Worker // with
736*795d594fSAndroid Build Coastguard Worker // CONSTANT false
737*795d594fSAndroid Build Coastguard Worker instruction->ReplaceWith(GetGraph()->GetConstant(DataType::Type::kBool, 0));
738*795d594fSAndroid Build Coastguard Worker instruction->GetBlock()->RemoveInstruction(instruction);
739*795d594fSAndroid Build Coastguard Worker }
740*795d594fSAndroid Build Coastguard Worker }
741*795d594fSAndroid Build Coastguard Worker
VisitBelowOrEqual(HBelowOrEqual * instruction)742*795d594fSAndroid Build Coastguard Worker void InstructionWithAbsorbingInputSimplifier::VisitBelowOrEqual(HBelowOrEqual* instruction) {
743*795d594fSAndroid Build Coastguard Worker if (instruction->GetLeft() == instruction->GetRight()) {
744*795d594fSAndroid Build Coastguard Worker // Replace code looking like
745*795d594fSAndroid Build Coastguard Worker // BELOW_OR_EQUAL lhs, lhs
746*795d594fSAndroid Build Coastguard Worker // CONSTANT true
747*795d594fSAndroid Build Coastguard Worker instruction->ReplaceWith(GetGraph()->GetConstant(DataType::Type::kBool, 1));
748*795d594fSAndroid Build Coastguard Worker instruction->GetBlock()->RemoveInstruction(instruction);
749*795d594fSAndroid Build Coastguard Worker } else if (instruction->GetLeft()->IsConstant() &&
750*795d594fSAndroid Build Coastguard Worker instruction->GetLeft()->AsConstant()->IsArithmeticZero()) {
751*795d594fSAndroid Build Coastguard Worker // Replace code looking like
752*795d594fSAndroid Build Coastguard Worker // BELOW_OR_EQUAL dst, 0, src // unsigned 0 <= src is always true
753*795d594fSAndroid Build Coastguard Worker // with
754*795d594fSAndroid Build Coastguard Worker // CONSTANT true
755*795d594fSAndroid Build Coastguard Worker instruction->ReplaceWith(GetGraph()->GetConstant(DataType::Type::kBool, 1));
756*795d594fSAndroid Build Coastguard Worker instruction->GetBlock()->RemoveInstruction(instruction);
757*795d594fSAndroid Build Coastguard Worker }
758*795d594fSAndroid Build Coastguard Worker }
759*795d594fSAndroid Build Coastguard Worker
VisitGreaterThan(HGreaterThan * instruction)760*795d594fSAndroid Build Coastguard Worker void InstructionWithAbsorbingInputSimplifier::VisitGreaterThan(HGreaterThan* instruction) {
761*795d594fSAndroid Build Coastguard Worker if (instruction->GetLeft() == instruction->GetRight() &&
762*795d594fSAndroid Build Coastguard Worker (!DataType::IsFloatingPointType(instruction->GetLeft()->GetType()) ||
763*795d594fSAndroid Build Coastguard Worker instruction->IsLtBias())) {
764*795d594fSAndroid Build Coastguard Worker // Replace code looking like
765*795d594fSAndroid Build Coastguard Worker // GREATER_THAN lhs, lhs
766*795d594fSAndroid Build Coastguard Worker // CONSTANT false
767*795d594fSAndroid Build Coastguard Worker instruction->ReplaceWith(GetGraph()->GetConstant(DataType::Type::kBool, 0));
768*795d594fSAndroid Build Coastguard Worker instruction->GetBlock()->RemoveInstruction(instruction);
769*795d594fSAndroid Build Coastguard Worker }
770*795d594fSAndroid Build Coastguard Worker }
771*795d594fSAndroid Build Coastguard Worker
VisitGreaterThanOrEqual(HGreaterThanOrEqual * instruction)772*795d594fSAndroid Build Coastguard Worker void InstructionWithAbsorbingInputSimplifier::VisitGreaterThanOrEqual(
773*795d594fSAndroid Build Coastguard Worker HGreaterThanOrEqual* instruction) {
774*795d594fSAndroid Build Coastguard Worker if (instruction->GetLeft() == instruction->GetRight() &&
775*795d594fSAndroid Build Coastguard Worker (!DataType::IsFloatingPointType(instruction->GetLeft()->GetType()) ||
776*795d594fSAndroid Build Coastguard Worker instruction->IsGtBias())) {
777*795d594fSAndroid Build Coastguard Worker // Replace code looking like
778*795d594fSAndroid Build Coastguard Worker // GREATER_THAN_OR_EQUAL lhs, lhs
779*795d594fSAndroid Build Coastguard Worker // CONSTANT true
780*795d594fSAndroid Build Coastguard Worker instruction->ReplaceWith(GetGraph()->GetConstant(DataType::Type::kBool, 1));
781*795d594fSAndroid Build Coastguard Worker instruction->GetBlock()->RemoveInstruction(instruction);
782*795d594fSAndroid Build Coastguard Worker }
783*795d594fSAndroid Build Coastguard Worker }
784*795d594fSAndroid Build Coastguard Worker
VisitLessThan(HLessThan * instruction)785*795d594fSAndroid Build Coastguard Worker void InstructionWithAbsorbingInputSimplifier::VisitLessThan(HLessThan* instruction) {
786*795d594fSAndroid Build Coastguard Worker if (instruction->GetLeft() == instruction->GetRight() &&
787*795d594fSAndroid Build Coastguard Worker (!DataType::IsFloatingPointType(instruction->GetLeft()->GetType()) ||
788*795d594fSAndroid Build Coastguard Worker instruction->IsGtBias())) {
789*795d594fSAndroid Build Coastguard Worker // Replace code looking like
790*795d594fSAndroid Build Coastguard Worker // LESS_THAN lhs, lhs
791*795d594fSAndroid Build Coastguard Worker // CONSTANT false
792*795d594fSAndroid Build Coastguard Worker instruction->ReplaceWith(GetGraph()->GetConstant(DataType::Type::kBool, 0));
793*795d594fSAndroid Build Coastguard Worker instruction->GetBlock()->RemoveInstruction(instruction);
794*795d594fSAndroid Build Coastguard Worker }
795*795d594fSAndroid Build Coastguard Worker }
796*795d594fSAndroid Build Coastguard Worker
VisitLessThanOrEqual(HLessThanOrEqual * instruction)797*795d594fSAndroid Build Coastguard Worker void InstructionWithAbsorbingInputSimplifier::VisitLessThanOrEqual(HLessThanOrEqual* instruction) {
798*795d594fSAndroid Build Coastguard Worker if (instruction->GetLeft() == instruction->GetRight() &&
799*795d594fSAndroid Build Coastguard Worker (!DataType::IsFloatingPointType(instruction->GetLeft()->GetType()) ||
800*795d594fSAndroid Build Coastguard Worker instruction->IsLtBias())) {
801*795d594fSAndroid Build Coastguard Worker // Replace code looking like
802*795d594fSAndroid Build Coastguard Worker // LESS_THAN_OR_EQUAL lhs, lhs
803*795d594fSAndroid Build Coastguard Worker // CONSTANT true
804*795d594fSAndroid Build Coastguard Worker instruction->ReplaceWith(GetGraph()->GetConstant(DataType::Type::kBool, 1));
805*795d594fSAndroid Build Coastguard Worker instruction->GetBlock()->RemoveInstruction(instruction);
806*795d594fSAndroid Build Coastguard Worker }
807*795d594fSAndroid Build Coastguard Worker }
808*795d594fSAndroid Build Coastguard Worker
VisitAnd(HAnd * instruction)809*795d594fSAndroid Build Coastguard Worker void InstructionWithAbsorbingInputSimplifier::VisitAnd(HAnd* instruction) {
810*795d594fSAndroid Build Coastguard Worker DataType::Type type = instruction->GetType();
811*795d594fSAndroid Build Coastguard Worker HConstant* input_cst = instruction->GetConstantRight();
812*795d594fSAndroid Build Coastguard Worker if ((input_cst != nullptr) && input_cst->IsZeroBitPattern()) {
813*795d594fSAndroid Build Coastguard Worker // Replace code looking like
814*795d594fSAndroid Build Coastguard Worker // AND dst, src, 0
815*795d594fSAndroid Build Coastguard Worker // with
816*795d594fSAndroid Build Coastguard Worker // CONSTANT 0
817*795d594fSAndroid Build Coastguard Worker instruction->ReplaceWith(input_cst);
818*795d594fSAndroid Build Coastguard Worker instruction->GetBlock()->RemoveInstruction(instruction);
819*795d594fSAndroid Build Coastguard Worker }
820*795d594fSAndroid Build Coastguard Worker
821*795d594fSAndroid Build Coastguard Worker HInstruction* left = instruction->GetLeft();
822*795d594fSAndroid Build Coastguard Worker HInstruction* right = instruction->GetRight();
823*795d594fSAndroid Build Coastguard Worker
824*795d594fSAndroid Build Coastguard Worker if (left->IsNot() ^ right->IsNot()) {
825*795d594fSAndroid Build Coastguard Worker // Replace code looking like
826*795d594fSAndroid Build Coastguard Worker // NOT notsrc, src
827*795d594fSAndroid Build Coastguard Worker // AND dst, notsrc, src
828*795d594fSAndroid Build Coastguard Worker // with
829*795d594fSAndroid Build Coastguard Worker // CONSTANT 0
830*795d594fSAndroid Build Coastguard Worker HInstruction* hnot = (left->IsNot() ? left : right);
831*795d594fSAndroid Build Coastguard Worker HInstruction* hother = (left->IsNot() ? right : left);
832*795d594fSAndroid Build Coastguard Worker HInstruction* src = hnot->AsNot()->GetInput();
833*795d594fSAndroid Build Coastguard Worker
834*795d594fSAndroid Build Coastguard Worker if (src == hother) {
835*795d594fSAndroid Build Coastguard Worker instruction->ReplaceWith(GetGraph()->GetConstant(type, 0));
836*795d594fSAndroid Build Coastguard Worker instruction->GetBlock()->RemoveInstruction(instruction);
837*795d594fSAndroid Build Coastguard Worker }
838*795d594fSAndroid Build Coastguard Worker }
839*795d594fSAndroid Build Coastguard Worker }
840*795d594fSAndroid Build Coastguard Worker
VisitCompare(HCompare * instruction)841*795d594fSAndroid Build Coastguard Worker void InstructionWithAbsorbingInputSimplifier::VisitCompare(HCompare* instruction) {
842*795d594fSAndroid Build Coastguard Worker HConstant* input_cst = instruction->GetConstantRight();
843*795d594fSAndroid Build Coastguard Worker if (input_cst != nullptr) {
844*795d594fSAndroid Build Coastguard Worker HInstruction* input_value = instruction->GetLeastConstantLeft();
845*795d594fSAndroid Build Coastguard Worker if (DataType::IsFloatingPointType(input_value->GetType()) &&
846*795d594fSAndroid Build Coastguard Worker ((input_cst->IsFloatConstant() && input_cst->AsFloatConstant()->IsNaN()) ||
847*795d594fSAndroid Build Coastguard Worker (input_cst->IsDoubleConstant() && input_cst->AsDoubleConstant()->IsNaN()))) {
848*795d594fSAndroid Build Coastguard Worker // Replace code looking like
849*795d594fSAndroid Build Coastguard Worker // CMP{G,L}-{FLOAT,DOUBLE} dst, src, NaN
850*795d594fSAndroid Build Coastguard Worker // with
851*795d594fSAndroid Build Coastguard Worker // CONSTANT +1 (gt bias)
852*795d594fSAndroid Build Coastguard Worker // or
853*795d594fSAndroid Build Coastguard Worker // CONSTANT -1 (lt bias)
854*795d594fSAndroid Build Coastguard Worker instruction->ReplaceWith(GetGraph()->GetConstant(DataType::Type::kInt32,
855*795d594fSAndroid Build Coastguard Worker (instruction->IsGtBias() ? 1 : -1)));
856*795d594fSAndroid Build Coastguard Worker instruction->GetBlock()->RemoveInstruction(instruction);
857*795d594fSAndroid Build Coastguard Worker }
858*795d594fSAndroid Build Coastguard Worker }
859*795d594fSAndroid Build Coastguard Worker }
860*795d594fSAndroid Build Coastguard Worker
VisitMul(HMul * instruction)861*795d594fSAndroid Build Coastguard Worker void InstructionWithAbsorbingInputSimplifier::VisitMul(HMul* instruction) {
862*795d594fSAndroid Build Coastguard Worker HConstant* input_cst = instruction->GetConstantRight();
863*795d594fSAndroid Build Coastguard Worker DataType::Type type = instruction->GetType();
864*795d594fSAndroid Build Coastguard Worker if (DataType::IsIntOrLongType(type) &&
865*795d594fSAndroid Build Coastguard Worker (input_cst != nullptr) && input_cst->IsArithmeticZero()) {
866*795d594fSAndroid Build Coastguard Worker // Replace code looking like
867*795d594fSAndroid Build Coastguard Worker // MUL dst, src, 0
868*795d594fSAndroid Build Coastguard Worker // with
869*795d594fSAndroid Build Coastguard Worker // CONSTANT 0
870*795d594fSAndroid Build Coastguard Worker // Integral multiplication by zero always yields zero, but floating-point
871*795d594fSAndroid Build Coastguard Worker // multiplication by zero does not always do. For example `Infinity * 0.0`
872*795d594fSAndroid Build Coastguard Worker // should yield a NaN.
873*795d594fSAndroid Build Coastguard Worker instruction->ReplaceWith(input_cst);
874*795d594fSAndroid Build Coastguard Worker instruction->GetBlock()->RemoveInstruction(instruction);
875*795d594fSAndroid Build Coastguard Worker }
876*795d594fSAndroid Build Coastguard Worker }
877*795d594fSAndroid Build Coastguard Worker
VisitOr(HOr * instruction)878*795d594fSAndroid Build Coastguard Worker void InstructionWithAbsorbingInputSimplifier::VisitOr(HOr* instruction) {
879*795d594fSAndroid Build Coastguard Worker HConstant* input_cst = instruction->GetConstantRight();
880*795d594fSAndroid Build Coastguard Worker if (input_cst != nullptr && Int64FromConstant(input_cst) == -1) {
881*795d594fSAndroid Build Coastguard Worker // Replace code looking like
882*795d594fSAndroid Build Coastguard Worker // OR dst, src, 0xFFF...FF
883*795d594fSAndroid Build Coastguard Worker // with
884*795d594fSAndroid Build Coastguard Worker // CONSTANT 0xFFF...FF
885*795d594fSAndroid Build Coastguard Worker instruction->ReplaceWith(input_cst);
886*795d594fSAndroid Build Coastguard Worker instruction->GetBlock()->RemoveInstruction(instruction);
887*795d594fSAndroid Build Coastguard Worker return;
888*795d594fSAndroid Build Coastguard Worker }
889*795d594fSAndroid Build Coastguard Worker
890*795d594fSAndroid Build Coastguard Worker HInstruction* left = instruction->GetLeft();
891*795d594fSAndroid Build Coastguard Worker HInstruction* right = instruction->GetRight();
892*795d594fSAndroid Build Coastguard Worker if (left->IsNot() ^ right->IsNot()) {
893*795d594fSAndroid Build Coastguard Worker // Replace code looking like
894*795d594fSAndroid Build Coastguard Worker // NOT notsrc, src
895*795d594fSAndroid Build Coastguard Worker // OR dst, notsrc, src
896*795d594fSAndroid Build Coastguard Worker // with
897*795d594fSAndroid Build Coastguard Worker // CONSTANT 0xFFF...FF
898*795d594fSAndroid Build Coastguard Worker HInstruction* hnot = (left->IsNot() ? left : right);
899*795d594fSAndroid Build Coastguard Worker HInstruction* hother = (left->IsNot() ? right : left);
900*795d594fSAndroid Build Coastguard Worker HInstruction* src = hnot->AsNot()->GetInput();
901*795d594fSAndroid Build Coastguard Worker
902*795d594fSAndroid Build Coastguard Worker if (src == hother) {
903*795d594fSAndroid Build Coastguard Worker DCHECK(instruction->GetType() == DataType::Type::kInt32 ||
904*795d594fSAndroid Build Coastguard Worker instruction->GetType() == DataType::Type::kInt64);
905*795d594fSAndroid Build Coastguard Worker instruction->ReplaceWith(GetGraph()->GetConstant(instruction->GetType(), -1));
906*795d594fSAndroid Build Coastguard Worker instruction->GetBlock()->RemoveInstruction(instruction);
907*795d594fSAndroid Build Coastguard Worker return;
908*795d594fSAndroid Build Coastguard Worker }
909*795d594fSAndroid Build Coastguard Worker }
910*795d594fSAndroid Build Coastguard Worker }
911*795d594fSAndroid Build Coastguard Worker
VisitRem(HRem * instruction)912*795d594fSAndroid Build Coastguard Worker void InstructionWithAbsorbingInputSimplifier::VisitRem(HRem* instruction) {
913*795d594fSAndroid Build Coastguard Worker DataType::Type type = instruction->GetType();
914*795d594fSAndroid Build Coastguard Worker
915*795d594fSAndroid Build Coastguard Worker if (!DataType::IsIntegralType(type)) {
916*795d594fSAndroid Build Coastguard Worker return;
917*795d594fSAndroid Build Coastguard Worker }
918*795d594fSAndroid Build Coastguard Worker
919*795d594fSAndroid Build Coastguard Worker HBasicBlock* block = instruction->GetBlock();
920*795d594fSAndroid Build Coastguard Worker
921*795d594fSAndroid Build Coastguard Worker if (instruction->GetLeft()->IsConstant() &&
922*795d594fSAndroid Build Coastguard Worker instruction->GetLeft()->AsConstant()->IsArithmeticZero()) {
923*795d594fSAndroid Build Coastguard Worker // Replace code looking like
924*795d594fSAndroid Build Coastguard Worker // REM dst, 0, src
925*795d594fSAndroid Build Coastguard Worker // with
926*795d594fSAndroid Build Coastguard Worker // CONSTANT 0
927*795d594fSAndroid Build Coastguard Worker instruction->ReplaceWith(instruction->GetLeft());
928*795d594fSAndroid Build Coastguard Worker block->RemoveInstruction(instruction);
929*795d594fSAndroid Build Coastguard Worker }
930*795d594fSAndroid Build Coastguard Worker
931*795d594fSAndroid Build Coastguard Worker HConstant* cst_right = instruction->GetRight()->AsConstantOrNull();
932*795d594fSAndroid Build Coastguard Worker if (((cst_right != nullptr) &&
933*795d594fSAndroid Build Coastguard Worker (cst_right->IsOne() || cst_right->IsMinusOne())) ||
934*795d594fSAndroid Build Coastguard Worker (instruction->GetLeft() == instruction->GetRight())) {
935*795d594fSAndroid Build Coastguard Worker // Replace code looking like
936*795d594fSAndroid Build Coastguard Worker // REM dst, src, 1
937*795d594fSAndroid Build Coastguard Worker // or
938*795d594fSAndroid Build Coastguard Worker // REM dst, src, -1
939*795d594fSAndroid Build Coastguard Worker // or
940*795d594fSAndroid Build Coastguard Worker // REM dst, src, src
941*795d594fSAndroid Build Coastguard Worker // with
942*795d594fSAndroid Build Coastguard Worker // CONSTANT 0
943*795d594fSAndroid Build Coastguard Worker instruction->ReplaceWith(GetGraph()->GetConstant(type, 0));
944*795d594fSAndroid Build Coastguard Worker block->RemoveInstruction(instruction);
945*795d594fSAndroid Build Coastguard Worker }
946*795d594fSAndroid Build Coastguard Worker }
947*795d594fSAndroid Build Coastguard Worker
VisitShl(HShl * instruction)948*795d594fSAndroid Build Coastguard Worker void InstructionWithAbsorbingInputSimplifier::VisitShl(HShl* instruction) {
949*795d594fSAndroid Build Coastguard Worker VisitShift(instruction);
950*795d594fSAndroid Build Coastguard Worker }
951*795d594fSAndroid Build Coastguard Worker
VisitShr(HShr * instruction)952*795d594fSAndroid Build Coastguard Worker void InstructionWithAbsorbingInputSimplifier::VisitShr(HShr* instruction) {
953*795d594fSAndroid Build Coastguard Worker VisitShift(instruction);
954*795d594fSAndroid Build Coastguard Worker }
955*795d594fSAndroid Build Coastguard Worker
VisitSub(HSub * instruction)956*795d594fSAndroid Build Coastguard Worker void InstructionWithAbsorbingInputSimplifier::VisitSub(HSub* instruction) {
957*795d594fSAndroid Build Coastguard Worker DataType::Type type = instruction->GetType();
958*795d594fSAndroid Build Coastguard Worker
959*795d594fSAndroid Build Coastguard Worker if (!DataType::IsIntegralType(type)) {
960*795d594fSAndroid Build Coastguard Worker return;
961*795d594fSAndroid Build Coastguard Worker }
962*795d594fSAndroid Build Coastguard Worker
963*795d594fSAndroid Build Coastguard Worker HBasicBlock* block = instruction->GetBlock();
964*795d594fSAndroid Build Coastguard Worker
965*795d594fSAndroid Build Coastguard Worker // We assume that GVN has run before, so we only perform a pointer
966*795d594fSAndroid Build Coastguard Worker // comparison. If for some reason the values are equal but the pointers are
967*795d594fSAndroid Build Coastguard Worker // different, we are still correct and only miss an optimization
968*795d594fSAndroid Build Coastguard Worker // opportunity.
969*795d594fSAndroid Build Coastguard Worker if (instruction->GetLeft() == instruction->GetRight()) {
970*795d594fSAndroid Build Coastguard Worker // Replace code looking like
971*795d594fSAndroid Build Coastguard Worker // SUB dst, src, src
972*795d594fSAndroid Build Coastguard Worker // with
973*795d594fSAndroid Build Coastguard Worker // CONSTANT 0
974*795d594fSAndroid Build Coastguard Worker // Note that we cannot optimize `x - x` to `0` for floating-point. It does
975*795d594fSAndroid Build Coastguard Worker // not work when `x` is an infinity.
976*795d594fSAndroid Build Coastguard Worker instruction->ReplaceWith(GetGraph()->GetConstant(type, 0));
977*795d594fSAndroid Build Coastguard Worker block->RemoveInstruction(instruction);
978*795d594fSAndroid Build Coastguard Worker }
979*795d594fSAndroid Build Coastguard Worker }
980*795d594fSAndroid Build Coastguard Worker
VisitUShr(HUShr * instruction)981*795d594fSAndroid Build Coastguard Worker void InstructionWithAbsorbingInputSimplifier::VisitUShr(HUShr* instruction) {
982*795d594fSAndroid Build Coastguard Worker VisitShift(instruction);
983*795d594fSAndroid Build Coastguard Worker }
984*795d594fSAndroid Build Coastguard Worker
VisitXor(HXor * instruction)985*795d594fSAndroid Build Coastguard Worker void InstructionWithAbsorbingInputSimplifier::VisitXor(HXor* instruction) {
986*795d594fSAndroid Build Coastguard Worker if (instruction->GetLeft() == instruction->GetRight()) {
987*795d594fSAndroid Build Coastguard Worker // Replace code looking like
988*795d594fSAndroid Build Coastguard Worker // XOR dst, src, src
989*795d594fSAndroid Build Coastguard Worker // with
990*795d594fSAndroid Build Coastguard Worker // CONSTANT 0
991*795d594fSAndroid Build Coastguard Worker DataType::Type type = instruction->GetType();
992*795d594fSAndroid Build Coastguard Worker HBasicBlock* block = instruction->GetBlock();
993*795d594fSAndroid Build Coastguard Worker instruction->ReplaceWith(GetGraph()->GetConstant(type, 0));
994*795d594fSAndroid Build Coastguard Worker block->RemoveInstruction(instruction);
995*795d594fSAndroid Build Coastguard Worker return;
996*795d594fSAndroid Build Coastguard Worker }
997*795d594fSAndroid Build Coastguard Worker
998*795d594fSAndroid Build Coastguard Worker HInstruction* left = instruction->GetLeft();
999*795d594fSAndroid Build Coastguard Worker HInstruction* right = instruction->GetRight();
1000*795d594fSAndroid Build Coastguard Worker if (left->IsNot() ^ right->IsNot()) {
1001*795d594fSAndroid Build Coastguard Worker // Replace code looking like
1002*795d594fSAndroid Build Coastguard Worker // NOT notsrc, src
1003*795d594fSAndroid Build Coastguard Worker // XOR dst, notsrc, src
1004*795d594fSAndroid Build Coastguard Worker // with
1005*795d594fSAndroid Build Coastguard Worker // CONSTANT 0xFFF...FF
1006*795d594fSAndroid Build Coastguard Worker HInstruction* hnot = (left->IsNot() ? left : right);
1007*795d594fSAndroid Build Coastguard Worker HInstruction* hother = (left->IsNot() ? right : left);
1008*795d594fSAndroid Build Coastguard Worker HInstruction* src = hnot->AsNot()->GetInput();
1009*795d594fSAndroid Build Coastguard Worker
1010*795d594fSAndroid Build Coastguard Worker if (src == hother) {
1011*795d594fSAndroid Build Coastguard Worker DCHECK(instruction->GetType() == DataType::Type::kInt32 ||
1012*795d594fSAndroid Build Coastguard Worker instruction->GetType() == DataType::Type::kInt64);
1013*795d594fSAndroid Build Coastguard Worker instruction->ReplaceWith(GetGraph()->GetConstant(instruction->GetType(), -1));
1014*795d594fSAndroid Build Coastguard Worker instruction->GetBlock()->RemoveInstruction(instruction);
1015*795d594fSAndroid Build Coastguard Worker return;
1016*795d594fSAndroid Build Coastguard Worker }
1017*795d594fSAndroid Build Coastguard Worker }
1018*795d594fSAndroid Build Coastguard Worker }
1019*795d594fSAndroid Build Coastguard Worker
1020*795d594fSAndroid Build Coastguard Worker } // namespace art
1021