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