• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "dex/dex_file-inl.h"
22 #include "optimizing/data_type.h"
23 #include "optimizing/nodes.h"
24 
25 namespace art HIDDEN {
26 
27 // This visitor tries to simplify instructions that can be evaluated
28 // as constants.
29 class HConstantFoldingVisitor final : public HGraphDelegateVisitor {
30  public:
HConstantFoldingVisitor(HGraph * graph,OptimizingCompilerStats * stats,bool use_all_optimizations)31   HConstantFoldingVisitor(HGraph* graph, OptimizingCompilerStats* stats, bool use_all_optimizations)
32       : HGraphDelegateVisitor(graph, stats), use_all_optimizations_(use_all_optimizations) {}
33 
34  private:
35   void VisitBasicBlock(HBasicBlock* block) override;
36 
37   void VisitUnaryOperation(HUnaryOperation* inst) override;
38   void VisitBinaryOperation(HBinaryOperation* inst) override;
39 
40   void VisitArrayLength(HArrayLength* inst) override;
41   void VisitDivZeroCheck(HDivZeroCheck* inst) override;
42   void VisitIf(HIf* inst) override;
43   void VisitTypeConversion(HTypeConversion* inst) override;
44 
45   void PropagateValue(HBasicBlock* starting_block, HInstruction* variable, HConstant* constant);
46 
47   // Use all optimizations without restrictions.
48   bool use_all_optimizations_;
49 
50   DISALLOW_COPY_AND_ASSIGN(HConstantFoldingVisitor);
51 };
52 
53 // This visitor tries to simplify operations with an absorbing input,
54 // yielding a constant. For example `input * 0` is replaced by a
55 // null constant.
56 class InstructionWithAbsorbingInputSimplifier : public HGraphVisitor {
57  public:
InstructionWithAbsorbingInputSimplifier(HGraph * graph)58   explicit InstructionWithAbsorbingInputSimplifier(HGraph* graph) : HGraphVisitor(graph) {}
59 
60  private:
61   void VisitShift(HBinaryOperation* shift);
62 
63   void VisitEqual(HEqual* instruction) override;
64   void VisitNotEqual(HNotEqual* instruction) override;
65 
66   void VisitAbove(HAbove* instruction) override;
67   void VisitAboveOrEqual(HAboveOrEqual* instruction) override;
68   void VisitBelow(HBelow* instruction) override;
69   void VisitBelowOrEqual(HBelowOrEqual* instruction) override;
70 
71   void VisitGreaterThan(HGreaterThan* instruction) override;
72   void VisitGreaterThanOrEqual(HGreaterThanOrEqual* instruction) override;
73   void VisitLessThan(HLessThan* instruction) override;
74   void VisitLessThanOrEqual(HLessThanOrEqual* instruction) override;
75 
76   void VisitAnd(HAnd* instruction) override;
77   void VisitCompare(HCompare* instruction) override;
78   void VisitMul(HMul* instruction) override;
79   void VisitOr(HOr* instruction) override;
80   void VisitRem(HRem* instruction) override;
81   void VisitShl(HShl* instruction) override;
82   void VisitShr(HShr* instruction) override;
83   void VisitSub(HSub* instruction) override;
84   void VisitUShr(HUShr* instruction) override;
85   void VisitXor(HXor* instruction) override;
86 };
87 
88 
Run()89 bool HConstantFolding::Run() {
90   HConstantFoldingVisitor visitor(graph_, stats_, use_all_optimizations_);
91   // Process basic blocks in reverse post-order in the dominator tree,
92   // so that an instruction turned into a constant, used as input of
93   // another instruction, may possibly be used to turn that second
94   // instruction into a constant as well.
95   visitor.VisitReversePostOrder();
96   return true;
97 }
98 
99 
VisitBasicBlock(HBasicBlock * block)100 void HConstantFoldingVisitor::VisitBasicBlock(HBasicBlock* block) {
101   // Traverse this block's instructions (phis don't need to be
102   // processed) in (forward) order and replace the ones that can be
103   // statically evaluated by a compile-time counterpart.
104   for (HInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) {
105     it.Current()->Accept(this);
106   }
107 }
108 
VisitUnaryOperation(HUnaryOperation * inst)109 void HConstantFoldingVisitor::VisitUnaryOperation(HUnaryOperation* inst) {
110   // Constant folding: replace `op(a)' with a constant at compile
111   // time if `a' is a constant.
112   HConstant* constant = inst->TryStaticEvaluation();
113   if (constant != nullptr) {
114     inst->ReplaceWith(constant);
115     inst->GetBlock()->RemoveInstruction(inst);
116   }
117 }
118 
VisitBinaryOperation(HBinaryOperation * inst)119 void HConstantFoldingVisitor::VisitBinaryOperation(HBinaryOperation* inst) {
120   // Constant folding: replace `op(a, b)' with a constant at
121   // compile time if `a' and `b' are both constants.
122   HConstant* constant = inst->TryStaticEvaluation();
123   if (constant != nullptr) {
124     inst->ReplaceWith(constant);
125     inst->GetBlock()->RemoveInstruction(inst);
126   } else {
127     InstructionWithAbsorbingInputSimplifier simplifier(GetGraph());
128     inst->Accept(&simplifier);
129   }
130 }
131 
VisitDivZeroCheck(HDivZeroCheck * inst)132 void HConstantFoldingVisitor::VisitDivZeroCheck(HDivZeroCheck* inst) {
133   // We can safely remove the check if the input is a non-null constant.
134   HInstruction* check_input = inst->InputAt(0);
135   if (check_input->IsConstant() && !check_input->AsConstant()->IsArithmeticZero()) {
136     inst->ReplaceWith(check_input);
137     inst->GetBlock()->RemoveInstruction(inst);
138   }
139 }
140 
PropagateValue(HBasicBlock * starting_block,HInstruction * variable,HConstant * constant)141 void HConstantFoldingVisitor::PropagateValue(HBasicBlock* starting_block,
142                                              HInstruction* variable,
143                                              HConstant* constant) {
144   const bool recording_stats = stats_ != nullptr;
145   size_t uses_before = 0;
146   size_t uses_after = 0;
147   if (recording_stats) {
148     uses_before = variable->GetUses().SizeSlow();
149   }
150 
151   if (variable->GetUses().HasExactlyOneElement()) {
152     // Nothing to do, since we only have the `if (variable)` use or the `condition` use.
153     return;
154   }
155 
156   variable->ReplaceUsesDominatedBy(
157       starting_block->GetFirstInstruction(), constant, /* strictly_dominated= */ false);
158 
159   if (recording_stats) {
160     uses_after = variable->GetUses().SizeSlow();
161     DCHECK_GE(uses_after, 1u) << "we must at least have the use in the if clause.";
162     DCHECK_GE(uses_before, uses_after);
163     MaybeRecordStat(stats_, MethodCompilationStat::kPropagatedIfValue, uses_before - uses_after);
164   }
165 }
166 
VisitIf(HIf * inst)167 void HConstantFoldingVisitor::VisitIf(HIf* inst) {
168   // This optimization can take a lot of compile time since we have a lot of If instructions in
169   // graphs.
170   if (!use_all_optimizations_) {
171     return;
172   }
173 
174   // Consistency check: the true and false successors do not dominate each other.
175   DCHECK(!inst->IfTrueSuccessor()->Dominates(inst->IfFalseSuccessor()) &&
176          !inst->IfFalseSuccessor()->Dominates(inst->IfTrueSuccessor()));
177 
178   HInstruction* if_input = inst->InputAt(0);
179 
180   // Already a constant.
181   if (if_input->IsConstant()) {
182     return;
183   }
184 
185   // if (variable) {
186   //   SSA `variable` guaranteed to be true
187   // } else {
188   //   and here false
189   // }
190   PropagateValue(inst->IfTrueSuccessor(), if_input, GetGraph()->GetIntConstant(1));
191   PropagateValue(inst->IfFalseSuccessor(), if_input, GetGraph()->GetIntConstant(0));
192 
193   // If the input is a condition, we can propagate the information of the condition itself.
194   if (!if_input->IsCondition()) {
195     return;
196   }
197   HCondition* condition = if_input->AsCondition();
198 
199   // We want either `==` or `!=`, since we cannot make assumptions for other conditions e.g. `>`
200   if (!condition->IsEqual() && !condition->IsNotEqual()) {
201     return;
202   }
203 
204   HInstruction* left = condition->GetLeft();
205   HInstruction* right = condition->GetRight();
206 
207   // We want one of them to be a constant and not the other.
208   if (left->IsConstant() == right->IsConstant()) {
209     return;
210   }
211 
212   // At this point we have something like:
213   // if (variable == constant) {
214   //   SSA `variable` guaranteed to be equal to constant here
215   // } else {
216   //   No guarantees can be made here (usually, see boolean case below).
217   // }
218   // Similarly with variable != constant, except that we can make guarantees in the else case.
219 
220   HConstant* constant = left->IsConstant() ? left->AsConstant() : right->AsConstant();
221   HInstruction* variable = left->IsConstant() ? right : left;
222 
223   // Don't deal with floats/doubles since they bring a lot of edge cases e.g.
224   // if (f == 0.0f) {
225   //   // f is not really guaranteed to be 0.0f. It could be -0.0f, for example
226   // }
227   if (DataType::IsFloatingPointType(variable->GetType())) {
228     return;
229   }
230   DCHECK(!DataType::IsFloatingPointType(constant->GetType()));
231 
232   // Sometimes we have an HCompare flowing into an Equals/NonEquals, which can act as a proxy. For
233   // example: `Equals(Compare(var, constant), 0)`. This is common for long, float, and double.
234   if (variable->IsCompare()) {
235     // We only care about equality comparisons so we skip if it is a less or greater comparison.
236     if (!constant->IsArithmeticZero()) {
237       return;
238     }
239 
240     // Update left and right to be the ones from the HCompare.
241     left = variable->AsCompare()->GetLeft();
242     right = variable->AsCompare()->GetRight();
243 
244     // Re-check that one of them to be a constant and not the other.
245     if (left->IsConstant() == right->IsConstant()) {
246       return;
247     }
248 
249     constant = left->IsConstant() ? left->AsConstant() : right->AsConstant();
250     variable = left->IsConstant() ? right : left;
251 
252     // Re-check floating point values.
253     if (DataType::IsFloatingPointType(variable->GetType())) {
254       return;
255     }
256     DCHECK(!DataType::IsFloatingPointType(constant->GetType()));
257   }
258 
259   // From this block forward we want to replace the SSA value. We use `starting_block` and not the
260   // `if` block as we want to update one of the branches but not the other.
261   HBasicBlock* starting_block =
262       condition->IsEqual() ? inst->IfTrueSuccessor() : inst->IfFalseSuccessor();
263 
264   PropagateValue(starting_block, variable, constant);
265 
266   // Special case for booleans since they have only two values so we know what to propagate in the
267   // other branch. However, sometimes our boolean values are not compared to 0 or 1. In those cases
268   // we cannot make an assumption for the `else` branch.
269   if (variable->GetType() == DataType::Type::kBool &&
270       constant->IsIntConstant() &&
271       (constant->AsIntConstant()->IsTrue() || constant->AsIntConstant()->IsFalse())) {
272     HBasicBlock* other_starting_block =
273         condition->IsEqual() ? inst->IfFalseSuccessor() : inst->IfTrueSuccessor();
274     DCHECK_NE(other_starting_block, starting_block);
275 
276     HConstant* other_constant = constant->AsIntConstant()->IsTrue() ?
277                                     GetGraph()->GetIntConstant(0) :
278                                     GetGraph()->GetIntConstant(1);
279     DCHECK_NE(other_constant, constant);
280     PropagateValue(other_starting_block, variable, other_constant);
281   }
282 }
283 
VisitArrayLength(HArrayLength * inst)284 void HConstantFoldingVisitor::VisitArrayLength(HArrayLength* inst) {
285   HInstruction* input = inst->InputAt(0);
286   if (input->IsLoadString()) {
287     DCHECK(inst->IsStringLength());
288     HLoadString* load_string = input->AsLoadString();
289     const DexFile& dex_file = load_string->GetDexFile();
290     const dex::StringId& string_id = dex_file.GetStringId(load_string->GetStringIndex());
291     inst->ReplaceWith(GetGraph()->GetIntConstant(dex_file.GetStringLength(string_id)));
292   }
293 }
294 
VisitTypeConversion(HTypeConversion * inst)295 void HConstantFoldingVisitor::VisitTypeConversion(HTypeConversion* inst) {
296   // Constant folding: replace `TypeConversion(a)' with a constant at
297   // compile time if `a' is a constant.
298   HConstant* constant = inst->TryStaticEvaluation();
299   if (constant != nullptr) {
300     inst->ReplaceWith(constant);
301     inst->GetBlock()->RemoveInstruction(inst);
302   }
303 }
304 
VisitShift(HBinaryOperation * instruction)305 void InstructionWithAbsorbingInputSimplifier::VisitShift(HBinaryOperation* instruction) {
306   DCHECK(instruction->IsShl() || instruction->IsShr() || instruction->IsUShr());
307   HInstruction* left = instruction->GetLeft();
308   if (left->IsConstant() && left->AsConstant()->IsArithmeticZero()) {
309     // Replace code looking like
310     //    SHL dst, 0, shift_amount
311     // with
312     //    CONSTANT 0
313     instruction->ReplaceWith(left);
314     instruction->GetBlock()->RemoveInstruction(instruction);
315   }
316 }
317 
VisitEqual(HEqual * instruction)318 void InstructionWithAbsorbingInputSimplifier::VisitEqual(HEqual* instruction) {
319   if (instruction->GetLeft() == instruction->GetRight() &&
320       !DataType::IsFloatingPointType(instruction->GetLeft()->GetType())) {
321     // Replace code looking like
322     //    EQUAL lhs, lhs
323     //    CONSTANT true
324     // We don't perform this optimizations for FP types since Double.NaN != Double.NaN, which is the
325     // opposite value.
326     instruction->ReplaceWith(GetGraph()->GetConstant(DataType::Type::kBool, 1));
327     instruction->GetBlock()->RemoveInstruction(instruction);
328   } else if ((instruction->GetLeft()->IsNullConstant() && !instruction->GetRight()->CanBeNull()) ||
329              (instruction->GetRight()->IsNullConstant() && !instruction->GetLeft()->CanBeNull())) {
330     // Replace code looking like
331     //    EQUAL lhs, null
332     // where lhs cannot be null with
333     //    CONSTANT false
334     instruction->ReplaceWith(GetGraph()->GetConstant(DataType::Type::kBool, 0));
335     instruction->GetBlock()->RemoveInstruction(instruction);
336   }
337 }
338 
VisitNotEqual(HNotEqual * instruction)339 void InstructionWithAbsorbingInputSimplifier::VisitNotEqual(HNotEqual* instruction) {
340   if (instruction->GetLeft() == instruction->GetRight() &&
341       !DataType::IsFloatingPointType(instruction->GetLeft()->GetType())) {
342     // Replace code looking like
343     //    NOT_EQUAL lhs, lhs
344     //    CONSTANT false
345     // We don't perform this optimizations for FP types since Double.NaN != Double.NaN, which is the
346     // opposite value.
347     instruction->ReplaceWith(GetGraph()->GetConstant(DataType::Type::kBool, 0));
348     instruction->GetBlock()->RemoveInstruction(instruction);
349   } else if ((instruction->GetLeft()->IsNullConstant() && !instruction->GetRight()->CanBeNull()) ||
350              (instruction->GetRight()->IsNullConstant() && !instruction->GetLeft()->CanBeNull())) {
351     // Replace code looking like
352     //    NOT_EQUAL lhs, null
353     // where lhs cannot be null with
354     //    CONSTANT true
355     instruction->ReplaceWith(GetGraph()->GetConstant(DataType::Type::kBool, 1));
356     instruction->GetBlock()->RemoveInstruction(instruction);
357   }
358 }
359 
VisitAbove(HAbove * instruction)360 void InstructionWithAbsorbingInputSimplifier::VisitAbove(HAbove* instruction) {
361   if (instruction->GetLeft() == instruction->GetRight()) {
362     // Replace code looking like
363     //    ABOVE lhs, lhs
364     //    CONSTANT false
365     instruction->ReplaceWith(GetGraph()->GetConstant(DataType::Type::kBool, 0));
366     instruction->GetBlock()->RemoveInstruction(instruction);
367   } else if (instruction->GetLeft()->IsConstant() &&
368              instruction->GetLeft()->AsConstant()->IsArithmeticZero()) {
369     // Replace code looking like
370     //    ABOVE dst, 0, src  // unsigned 0 > src is always false
371     // with
372     //    CONSTANT false
373     instruction->ReplaceWith(GetGraph()->GetConstant(DataType::Type::kBool, 0));
374     instruction->GetBlock()->RemoveInstruction(instruction);
375   }
376 }
377 
VisitAboveOrEqual(HAboveOrEqual * instruction)378 void InstructionWithAbsorbingInputSimplifier::VisitAboveOrEqual(HAboveOrEqual* instruction) {
379   if (instruction->GetLeft() == instruction->GetRight()) {
380     // Replace code looking like
381     //    ABOVE_OR_EQUAL lhs, lhs
382     //    CONSTANT true
383     instruction->ReplaceWith(GetGraph()->GetConstant(DataType::Type::kBool, 1));
384     instruction->GetBlock()->RemoveInstruction(instruction);
385   } else if (instruction->GetRight()->IsConstant() &&
386              instruction->GetRight()->AsConstant()->IsArithmeticZero()) {
387     // Replace code looking like
388     //    ABOVE_OR_EQUAL dst, src, 0  // unsigned src >= 0 is always true
389     // with
390     //    CONSTANT true
391     instruction->ReplaceWith(GetGraph()->GetConstant(DataType::Type::kBool, 1));
392     instruction->GetBlock()->RemoveInstruction(instruction);
393   }
394 }
395 
VisitBelow(HBelow * instruction)396 void InstructionWithAbsorbingInputSimplifier::VisitBelow(HBelow* instruction) {
397   if (instruction->GetLeft() == instruction->GetRight()) {
398     // Replace code looking like
399     //    BELOW lhs, lhs
400     //    CONSTANT false
401     instruction->ReplaceWith(GetGraph()->GetConstant(DataType::Type::kBool, 0));
402     instruction->GetBlock()->RemoveInstruction(instruction);
403   } else if (instruction->GetRight()->IsConstant() &&
404              instruction->GetRight()->AsConstant()->IsArithmeticZero()) {
405     // Replace code looking like
406     //    BELOW dst, src, 0  // unsigned src < 0 is always false
407     // with
408     //    CONSTANT false
409     instruction->ReplaceWith(GetGraph()->GetConstant(DataType::Type::kBool, 0));
410     instruction->GetBlock()->RemoveInstruction(instruction);
411   }
412 }
413 
VisitBelowOrEqual(HBelowOrEqual * instruction)414 void InstructionWithAbsorbingInputSimplifier::VisitBelowOrEqual(HBelowOrEqual* instruction) {
415   if (instruction->GetLeft() == instruction->GetRight()) {
416     // Replace code looking like
417     //    BELOW_OR_EQUAL lhs, lhs
418     //    CONSTANT true
419     instruction->ReplaceWith(GetGraph()->GetConstant(DataType::Type::kBool, 1));
420     instruction->GetBlock()->RemoveInstruction(instruction);
421   } else if (instruction->GetLeft()->IsConstant() &&
422              instruction->GetLeft()->AsConstant()->IsArithmeticZero()) {
423     // Replace code looking like
424     //    BELOW_OR_EQUAL dst, 0, src  // unsigned 0 <= src is always true
425     // with
426     //    CONSTANT true
427     instruction->ReplaceWith(GetGraph()->GetConstant(DataType::Type::kBool, 1));
428     instruction->GetBlock()->RemoveInstruction(instruction);
429   }
430 }
431 
VisitGreaterThan(HGreaterThan * instruction)432 void InstructionWithAbsorbingInputSimplifier::VisitGreaterThan(HGreaterThan* instruction) {
433   if (instruction->GetLeft() == instruction->GetRight() &&
434       (!DataType::IsFloatingPointType(instruction->GetLeft()->GetType()) ||
435        instruction->IsLtBias())) {
436     // Replace code looking like
437     //    GREATER_THAN lhs, lhs
438     //    CONSTANT false
439     instruction->ReplaceWith(GetGraph()->GetConstant(DataType::Type::kBool, 0));
440     instruction->GetBlock()->RemoveInstruction(instruction);
441   }
442 }
443 
VisitGreaterThanOrEqual(HGreaterThanOrEqual * instruction)444 void InstructionWithAbsorbingInputSimplifier::VisitGreaterThanOrEqual(
445     HGreaterThanOrEqual* instruction) {
446   if (instruction->GetLeft() == instruction->GetRight() &&
447       (!DataType::IsFloatingPointType(instruction->GetLeft()->GetType()) ||
448        instruction->IsGtBias())) {
449     // Replace code looking like
450     //    GREATER_THAN_OR_EQUAL lhs, lhs
451     //    CONSTANT true
452     instruction->ReplaceWith(GetGraph()->GetConstant(DataType::Type::kBool, 1));
453     instruction->GetBlock()->RemoveInstruction(instruction);
454   }
455 }
456 
VisitLessThan(HLessThan * instruction)457 void InstructionWithAbsorbingInputSimplifier::VisitLessThan(HLessThan* instruction) {
458   if (instruction->GetLeft() == instruction->GetRight() &&
459       (!DataType::IsFloatingPointType(instruction->GetLeft()->GetType()) ||
460        instruction->IsGtBias())) {
461     // Replace code looking like
462     //    LESS_THAN lhs, lhs
463     //    CONSTANT false
464     instruction->ReplaceWith(GetGraph()->GetConstant(DataType::Type::kBool, 0));
465     instruction->GetBlock()->RemoveInstruction(instruction);
466   }
467 }
468 
VisitLessThanOrEqual(HLessThanOrEqual * instruction)469 void InstructionWithAbsorbingInputSimplifier::VisitLessThanOrEqual(HLessThanOrEqual* instruction) {
470   if (instruction->GetLeft() == instruction->GetRight() &&
471       (!DataType::IsFloatingPointType(instruction->GetLeft()->GetType()) ||
472        instruction->IsLtBias())) {
473     // Replace code looking like
474     //    LESS_THAN_OR_EQUAL lhs, lhs
475     //    CONSTANT true
476     instruction->ReplaceWith(GetGraph()->GetConstant(DataType::Type::kBool, 1));
477     instruction->GetBlock()->RemoveInstruction(instruction);
478   }
479 }
480 
VisitAnd(HAnd * instruction)481 void InstructionWithAbsorbingInputSimplifier::VisitAnd(HAnd* instruction) {
482   DataType::Type type = instruction->GetType();
483   HConstant* input_cst = instruction->GetConstantRight();
484   if ((input_cst != nullptr) && input_cst->IsZeroBitPattern()) {
485     // Replace code looking like
486     //    AND dst, src, 0
487     // with
488     //    CONSTANT 0
489     instruction->ReplaceWith(input_cst);
490     instruction->GetBlock()->RemoveInstruction(instruction);
491   }
492 
493   HInstruction* left = instruction->GetLeft();
494   HInstruction* right = instruction->GetRight();
495 
496   if (left->IsNot() ^ right->IsNot()) {
497     // Replace code looking like
498     //    NOT notsrc, src
499     //    AND dst, notsrc, src
500     // with
501     //    CONSTANT 0
502     HInstruction* hnot = (left->IsNot() ? left : right);
503     HInstruction* hother = (left->IsNot() ? right : left);
504     HInstruction* src = hnot->AsNot()->GetInput();
505 
506     if (src == hother) {
507       instruction->ReplaceWith(GetGraph()->GetConstant(type, 0));
508       instruction->GetBlock()->RemoveInstruction(instruction);
509     }
510   }
511 }
512 
VisitCompare(HCompare * instruction)513 void InstructionWithAbsorbingInputSimplifier::VisitCompare(HCompare* instruction) {
514   HConstant* input_cst = instruction->GetConstantRight();
515   if (input_cst != nullptr) {
516     HInstruction* input_value = instruction->GetLeastConstantLeft();
517     if (DataType::IsFloatingPointType(input_value->GetType()) &&
518         ((input_cst->IsFloatConstant() && input_cst->AsFloatConstant()->IsNaN()) ||
519          (input_cst->IsDoubleConstant() && input_cst->AsDoubleConstant()->IsNaN()))) {
520       // Replace code looking like
521       //    CMP{G,L}-{FLOAT,DOUBLE} dst, src, NaN
522       // with
523       //    CONSTANT +1 (gt bias)
524       // or
525       //    CONSTANT -1 (lt bias)
526       instruction->ReplaceWith(GetGraph()->GetConstant(DataType::Type::kInt32,
527                                                        (instruction->IsGtBias() ? 1 : -1)));
528       instruction->GetBlock()->RemoveInstruction(instruction);
529     }
530   }
531 }
532 
VisitMul(HMul * instruction)533 void InstructionWithAbsorbingInputSimplifier::VisitMul(HMul* instruction) {
534   HConstant* input_cst = instruction->GetConstantRight();
535   DataType::Type type = instruction->GetType();
536   if (DataType::IsIntOrLongType(type) &&
537       (input_cst != nullptr) && input_cst->IsArithmeticZero()) {
538     // Replace code looking like
539     //    MUL dst, src, 0
540     // with
541     //    CONSTANT 0
542     // Integral multiplication by zero always yields zero, but floating-point
543     // multiplication by zero does not always do. For example `Infinity * 0.0`
544     // should yield a NaN.
545     instruction->ReplaceWith(input_cst);
546     instruction->GetBlock()->RemoveInstruction(instruction);
547   }
548 }
549 
VisitOr(HOr * instruction)550 void InstructionWithAbsorbingInputSimplifier::VisitOr(HOr* instruction) {
551   HConstant* input_cst = instruction->GetConstantRight();
552 
553   if (input_cst == nullptr) {
554     return;
555   }
556 
557   if (Int64FromConstant(input_cst) == -1) {
558     // Replace code looking like
559     //    OR dst, src, 0xFFF...FF
560     // with
561     //    CONSTANT 0xFFF...FF
562     instruction->ReplaceWith(input_cst);
563     instruction->GetBlock()->RemoveInstruction(instruction);
564   }
565 }
566 
VisitRem(HRem * instruction)567 void InstructionWithAbsorbingInputSimplifier::VisitRem(HRem* instruction) {
568   DataType::Type type = instruction->GetType();
569 
570   if (!DataType::IsIntegralType(type)) {
571     return;
572   }
573 
574   HBasicBlock* block = instruction->GetBlock();
575 
576   if (instruction->GetLeft()->IsConstant() &&
577       instruction->GetLeft()->AsConstant()->IsArithmeticZero()) {
578     // Replace code looking like
579     //    REM dst, 0, src
580     // with
581     //    CONSTANT 0
582     instruction->ReplaceWith(instruction->GetLeft());
583     block->RemoveInstruction(instruction);
584   }
585 
586   HConstant* cst_right = instruction->GetRight()->AsConstant();
587   if (((cst_right != nullptr) &&
588        (cst_right->IsOne() || cst_right->IsMinusOne())) ||
589       (instruction->GetLeft() == instruction->GetRight())) {
590     // Replace code looking like
591     //    REM dst, src, 1
592     // or
593     //    REM dst, src, -1
594     // or
595     //    REM dst, src, src
596     // with
597     //    CONSTANT 0
598     instruction->ReplaceWith(GetGraph()->GetConstant(type, 0));
599     block->RemoveInstruction(instruction);
600   }
601 }
602 
VisitShl(HShl * instruction)603 void InstructionWithAbsorbingInputSimplifier::VisitShl(HShl* instruction) {
604   VisitShift(instruction);
605 }
606 
VisitShr(HShr * instruction)607 void InstructionWithAbsorbingInputSimplifier::VisitShr(HShr* instruction) {
608   VisitShift(instruction);
609 }
610 
VisitSub(HSub * instruction)611 void InstructionWithAbsorbingInputSimplifier::VisitSub(HSub* instruction) {
612   DataType::Type type = instruction->GetType();
613 
614   if (!DataType::IsIntegralType(type)) {
615     return;
616   }
617 
618   HBasicBlock* block = instruction->GetBlock();
619 
620   // We assume that GVN has run before, so we only perform a pointer
621   // comparison.  If for some reason the values are equal but the pointers are
622   // different, we are still correct and only miss an optimization
623   // opportunity.
624   if (instruction->GetLeft() == instruction->GetRight()) {
625     // Replace code looking like
626     //    SUB dst, src, src
627     // with
628     //    CONSTANT 0
629     // Note that we cannot optimize `x - x` to `0` for floating-point. It does
630     // not work when `x` is an infinity.
631     instruction->ReplaceWith(GetGraph()->GetConstant(type, 0));
632     block->RemoveInstruction(instruction);
633   }
634 }
635 
VisitUShr(HUShr * instruction)636 void InstructionWithAbsorbingInputSimplifier::VisitUShr(HUShr* instruction) {
637   VisitShift(instruction);
638 }
639 
VisitXor(HXor * instruction)640 void InstructionWithAbsorbingInputSimplifier::VisitXor(HXor* instruction) {
641   if (instruction->GetLeft() == instruction->GetRight()) {
642     // Replace code looking like
643     //    XOR dst, src, src
644     // with
645     //    CONSTANT 0
646     DataType::Type type = instruction->GetType();
647     HBasicBlock* block = instruction->GetBlock();
648     instruction->ReplaceWith(GetGraph()->GetConstant(type, 0));
649     block->RemoveInstruction(instruction);
650   }
651 }
652 
653 }  // namespace art
654