instruction_simplifier.cc revision 0d13fee6f4330cc9cb100c43135490a34c11d7a5
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 "instruction_simplifier.h"
18
19#include "mirror/class-inl.h"
20#include "scoped_thread_state_change.h"
21
22namespace art {
23
24class InstructionSimplifierVisitor : public HGraphVisitor {
25 public:
26  InstructionSimplifierVisitor(HGraph* graph, OptimizingCompilerStats* stats)
27      : HGraphVisitor(graph),
28        stats_(stats) {}
29
30  void Run();
31
32 private:
33  void RecordSimplification() {
34    simplification_occurred_ = true;
35    simplifications_at_current_position_++;
36    if (stats_) {
37      stats_->RecordStat(kInstructionSimplifications);
38    }
39  }
40
41  bool TryMoveNegOnInputsAfterBinop(HBinaryOperation* binop);
42  void VisitShift(HBinaryOperation* shift);
43
44  void VisitSuspendCheck(HSuspendCheck* check) OVERRIDE;
45  void VisitEqual(HEqual* equal) OVERRIDE;
46  void VisitNotEqual(HNotEqual* equal) OVERRIDE;
47  void VisitBooleanNot(HBooleanNot* bool_not) OVERRIDE;
48  void VisitArraySet(HArraySet* equal) OVERRIDE;
49  void VisitTypeConversion(HTypeConversion* instruction) OVERRIDE;
50  void VisitNullCheck(HNullCheck* instruction) OVERRIDE;
51  void VisitArrayLength(HArrayLength* instruction) OVERRIDE;
52  void VisitCheckCast(HCheckCast* instruction) OVERRIDE;
53  void VisitAdd(HAdd* instruction) OVERRIDE;
54  void VisitAnd(HAnd* instruction) OVERRIDE;
55  void VisitDiv(HDiv* instruction) OVERRIDE;
56  void VisitMul(HMul* instruction) OVERRIDE;
57  void VisitNeg(HNeg* instruction) OVERRIDE;
58  void VisitNot(HNot* instruction) OVERRIDE;
59  void VisitOr(HOr* instruction) OVERRIDE;
60  void VisitShl(HShl* instruction) OVERRIDE;
61  void VisitShr(HShr* instruction) OVERRIDE;
62  void VisitSub(HSub* instruction) OVERRIDE;
63  void VisitUShr(HUShr* instruction) OVERRIDE;
64  void VisitXor(HXor* instruction) OVERRIDE;
65
66  OptimizingCompilerStats* stats_;
67  bool simplification_occurred_ = false;
68  int simplifications_at_current_position_ = 0;
69  // We ensure we do not loop infinitely. The value is a finger in the air guess
70  // that should allow enough simplification.
71  static constexpr int kMaxSamePositionSimplifications = 10;
72};
73
74void InstructionSimplifier::Run() {
75  InstructionSimplifierVisitor visitor(graph_, stats_);
76  visitor.Run();
77}
78
79void InstructionSimplifierVisitor::Run() {
80  for (HReversePostOrderIterator it(*GetGraph()); !it.Done();) {
81    // The simplification of an instruction to another instruction may yield
82    // possibilities for other simplifications. So although we perform a reverse
83    // post order visit, we sometimes need to revisit an instruction index.
84    simplification_occurred_ = false;
85    VisitBasicBlock(it.Current());
86    if (simplification_occurred_ &&
87        (simplifications_at_current_position_ < kMaxSamePositionSimplifications)) {
88      // New simplifications may be applicable to the instruction at the
89      // current index, so don't advance the iterator.
90      continue;
91    }
92    if (simplifications_at_current_position_ >= kMaxSamePositionSimplifications) {
93      LOG(WARNING) << "Too many simplifications (" << simplifications_at_current_position_
94          << ") occurred at the current position.";
95    }
96    simplifications_at_current_position_ = 0;
97    it.Advance();
98  }
99}
100
101namespace {
102
103bool AreAllBitsSet(HConstant* constant) {
104  return Int64FromConstant(constant) == -1;
105}
106
107}  // namespace
108
109// Returns true if the code was simplified to use only one negation operation
110// after the binary operation instead of one on each of the inputs.
111bool InstructionSimplifierVisitor::TryMoveNegOnInputsAfterBinop(HBinaryOperation* binop) {
112  DCHECK(binop->IsAdd() || binop->IsSub());
113  DCHECK(binop->GetLeft()->IsNeg() && binop->GetRight()->IsNeg());
114  HNeg* left_neg = binop->GetLeft()->AsNeg();
115  HNeg* right_neg = binop->GetRight()->AsNeg();
116  if (!left_neg->HasOnlyOneNonEnvironmentUse() ||
117      !right_neg->HasOnlyOneNonEnvironmentUse()) {
118    return false;
119  }
120  // Replace code looking like
121  //    NEG tmp1, a
122  //    NEG tmp2, b
123  //    ADD dst, tmp1, tmp2
124  // with
125  //    ADD tmp, a, b
126  //    NEG dst, tmp
127  binop->ReplaceInput(left_neg->GetInput(), 0);
128  binop->ReplaceInput(right_neg->GetInput(), 1);
129  left_neg->GetBlock()->RemoveInstruction(left_neg);
130  right_neg->GetBlock()->RemoveInstruction(right_neg);
131  HNeg* neg = new (GetGraph()->GetArena()) HNeg(binop->GetType(), binop);
132  binop->GetBlock()->InsertInstructionBefore(neg, binop->GetNext());
133  binop->ReplaceWithExceptInReplacementAtIndex(neg, 0);
134  RecordSimplification();
135  return true;
136}
137
138void InstructionSimplifierVisitor::VisitShift(HBinaryOperation* instruction) {
139  DCHECK(instruction->IsShl() || instruction->IsShr() || instruction->IsUShr());
140  HConstant* input_cst = instruction->GetConstantRight();
141  HInstruction* input_other = instruction->GetLeastConstantLeft();
142
143  if ((input_cst != nullptr) && input_cst->IsZero()) {
144    // Replace code looking like
145    //    SHL dst, src, 0
146    // with
147    //    src
148    instruction->ReplaceWith(input_other);
149    instruction->GetBlock()->RemoveInstruction(instruction);
150  }
151}
152
153void InstructionSimplifierVisitor::VisitNullCheck(HNullCheck* null_check) {
154  HInstruction* obj = null_check->InputAt(0);
155  if (!obj->CanBeNull()) {
156    null_check->ReplaceWith(obj);
157    null_check->GetBlock()->RemoveInstruction(null_check);
158    if (stats_ != nullptr) {
159      stats_->RecordStat(MethodCompilationStat::kRemovedNullCheck);
160    }
161  }
162}
163
164void InstructionSimplifierVisitor::VisitCheckCast(HCheckCast* check_cast) {
165  HLoadClass* load_class = check_cast->InputAt(1)->AsLoadClass();
166  if (!load_class->IsResolved()) {
167    // If the class couldn't be resolve it's not safe to compare against it. It's
168    // default type would be Top which might be wider that the actual class type
169    // and thus producing wrong results.
170    return;
171  }
172  ReferenceTypeInfo obj_rti = check_cast->InputAt(0)->GetReferenceTypeInfo();
173  ReferenceTypeInfo class_rti = load_class->GetLoadedClassRTI();
174  ScopedObjectAccess soa(Thread::Current());
175  if (class_rti.IsSupertypeOf(obj_rti)) {
176    check_cast->GetBlock()->RemoveInstruction(check_cast);
177    if (stats_ != nullptr) {
178      stats_->RecordStat(MethodCompilationStat::kRemovedCheckedCast);
179    }
180  }
181}
182
183void InstructionSimplifierVisitor::VisitSuspendCheck(HSuspendCheck* check) {
184  HBasicBlock* block = check->GetBlock();
185  // Currently always keep the suspend check at entry.
186  if (block->IsEntryBlock()) return;
187
188  // Currently always keep suspend checks at loop entry.
189  if (block->IsLoopHeader() && block->GetFirstInstruction() == check) {
190    DCHECK(block->GetLoopInformation()->GetSuspendCheck() == check);
191    return;
192  }
193
194  // Remove the suspend check that was added at build time for the baseline
195  // compiler.
196  block->RemoveInstruction(check);
197}
198
199void InstructionSimplifierVisitor::VisitEqual(HEqual* equal) {
200  HInstruction* input_const = equal->GetConstantRight();
201  if (input_const != nullptr) {
202    HInstruction* input_value = equal->GetLeastConstantLeft();
203    if (input_value->GetType() == Primitive::kPrimBoolean && input_const->IsIntConstant()) {
204      HBasicBlock* block = equal->GetBlock();
205      if (input_const->AsIntConstant()->IsOne()) {
206        // Replace (bool_value == true) with bool_value
207        equal->ReplaceWith(input_value);
208        block->RemoveInstruction(equal);
209        RecordSimplification();
210      } else {
211        // Replace (bool_value == false) with !bool_value
212        DCHECK(input_const->AsIntConstant()->IsZero());
213        block->ReplaceAndRemoveInstructionWith(
214            equal, new (block->GetGraph()->GetArena()) HBooleanNot(input_value));
215        RecordSimplification();
216      }
217    }
218  }
219}
220
221void InstructionSimplifierVisitor::VisitNotEqual(HNotEqual* not_equal) {
222  HInstruction* input_const = not_equal->GetConstantRight();
223  if (input_const != nullptr) {
224    HInstruction* input_value = not_equal->GetLeastConstantLeft();
225    if (input_value->GetType() == Primitive::kPrimBoolean && input_const->IsIntConstant()) {
226      HBasicBlock* block = not_equal->GetBlock();
227      if (input_const->AsIntConstant()->IsOne()) {
228        // Replace (bool_value != true) with !bool_value
229        block->ReplaceAndRemoveInstructionWith(
230            not_equal, new (block->GetGraph()->GetArena()) HBooleanNot(input_value));
231        RecordSimplification();
232      } else {
233        // Replace (bool_value != false) with bool_value
234        DCHECK(input_const->AsIntConstant()->IsZero());
235        not_equal->ReplaceWith(input_value);
236        block->RemoveInstruction(not_equal);
237        RecordSimplification();
238      }
239    }
240  }
241}
242
243void InstructionSimplifierVisitor::VisitBooleanNot(HBooleanNot* bool_not) {
244  HInstruction* parent = bool_not->InputAt(0);
245  if (parent->IsBooleanNot()) {
246    HInstruction* value = parent->InputAt(0);
247    // Replace (!(!bool_value)) with bool_value
248    bool_not->ReplaceWith(value);
249    bool_not->GetBlock()->RemoveInstruction(bool_not);
250    // It is possible that `parent` is dead at this point but we leave
251    // its removal to DCE for simplicity.
252    RecordSimplification();
253  }
254}
255
256void InstructionSimplifierVisitor::VisitArrayLength(HArrayLength* instruction) {
257  HInstruction* input = instruction->InputAt(0);
258  // If the array is a NewArray with constant size, replace the array length
259  // with the constant instruction. This helps the bounds check elimination phase.
260  if (input->IsNewArray()) {
261    input = input->InputAt(0);
262    if (input->IsIntConstant()) {
263      instruction->ReplaceWith(input);
264    }
265  }
266}
267
268void InstructionSimplifierVisitor::VisitArraySet(HArraySet* instruction) {
269  HInstruction* value = instruction->GetValue();
270  if (value->GetType() != Primitive::kPrimNot) return;
271
272  if (value->IsArrayGet()) {
273    if (value->AsArrayGet()->GetArray() == instruction->GetArray()) {
274      // If the code is just swapping elements in the array, no need for a type check.
275      instruction->ClearNeedsTypeCheck();
276    }
277  }
278}
279
280void InstructionSimplifierVisitor::VisitTypeConversion(HTypeConversion* instruction) {
281  if (instruction->GetResultType() == instruction->GetInputType()) {
282    // Remove the instruction if it's converting to the same type.
283    instruction->ReplaceWith(instruction->GetInput());
284    instruction->GetBlock()->RemoveInstruction(instruction);
285  }
286}
287
288void InstructionSimplifierVisitor::VisitAdd(HAdd* instruction) {
289  HConstant* input_cst = instruction->GetConstantRight();
290  HInstruction* input_other = instruction->GetLeastConstantLeft();
291  if ((input_cst != nullptr) && input_cst->IsZero()) {
292    // Replace code looking like
293    //    ADD dst, src, 0
294    // with
295    //    src
296    instruction->ReplaceWith(input_other);
297    instruction->GetBlock()->RemoveInstruction(instruction);
298    return;
299  }
300
301  HInstruction* left = instruction->GetLeft();
302  HInstruction* right = instruction->GetRight();
303  bool left_is_neg = left->IsNeg();
304  bool right_is_neg = right->IsNeg();
305
306  if (left_is_neg && right_is_neg) {
307    if (TryMoveNegOnInputsAfterBinop(instruction)) {
308      return;
309    }
310  }
311
312  HNeg* neg = left_is_neg ? left->AsNeg() : right->AsNeg();
313  if ((left_is_neg ^ right_is_neg) && neg->HasOnlyOneNonEnvironmentUse()) {
314    // Replace code looking like
315    //    NEG tmp, b
316    //    ADD dst, a, tmp
317    // with
318    //    SUB dst, a, b
319    // We do not perform the optimization if the input negation has environment
320    // uses or multiple non-environment uses as it could lead to worse code. In
321    // particular, we do not want the live range of `b` to be extended if we are
322    // not sure the initial 'NEG' instruction can be removed.
323    HInstruction* other = left_is_neg ? right : left;
324    HSub* sub = new(GetGraph()->GetArena()) HSub(instruction->GetType(), other, neg->GetInput());
325    instruction->GetBlock()->ReplaceAndRemoveInstructionWith(instruction, sub);
326    RecordSimplification();
327    neg->GetBlock()->RemoveInstruction(neg);
328  }
329}
330
331void InstructionSimplifierVisitor::VisitAnd(HAnd* instruction) {
332  HConstant* input_cst = instruction->GetConstantRight();
333  HInstruction* input_other = instruction->GetLeastConstantLeft();
334
335  if ((input_cst != nullptr) && AreAllBitsSet(input_cst)) {
336    // Replace code looking like
337    //    AND dst, src, 0xFFF...FF
338    // with
339    //    src
340    instruction->ReplaceWith(input_other);
341    instruction->GetBlock()->RemoveInstruction(instruction);
342    return;
343  }
344
345  // We assume that GVN has run before, so we only perform a pointer comparison.
346  // If for some reason the values are equal but the pointers are different, we
347  // are still correct and only miss an optimization opportunity.
348  if (instruction->GetLeft() == instruction->GetRight()) {
349    // Replace code looking like
350    //    AND dst, src, src
351    // with
352    //    src
353    instruction->ReplaceWith(instruction->GetLeft());
354    instruction->GetBlock()->RemoveInstruction(instruction);
355  }
356}
357
358void InstructionSimplifierVisitor::VisitDiv(HDiv* instruction) {
359  HConstant* input_cst = instruction->GetConstantRight();
360  HInstruction* input_other = instruction->GetLeastConstantLeft();
361  Primitive::Type type = instruction->GetType();
362
363  if ((input_cst != nullptr) && input_cst->IsOne()) {
364    // Replace code looking like
365    //    DIV dst, src, 1
366    // with
367    //    src
368    instruction->ReplaceWith(input_other);
369    instruction->GetBlock()->RemoveInstruction(instruction);
370    return;
371  }
372
373  if ((input_cst != nullptr) && input_cst->IsMinusOne() &&
374      (Primitive::IsFloatingPointType(type) || Primitive::IsIntOrLongType(type))) {
375    // Replace code looking like
376    //    DIV dst, src, -1
377    // with
378    //    NEG dst, src
379    instruction->GetBlock()->ReplaceAndRemoveInstructionWith(
380        instruction, (new (GetGraph()->GetArena()) HNeg(type, input_other)));
381    RecordSimplification();
382  }
383}
384
385void InstructionSimplifierVisitor::VisitMul(HMul* instruction) {
386  HConstant* input_cst = instruction->GetConstantRight();
387  HInstruction* input_other = instruction->GetLeastConstantLeft();
388  Primitive::Type type = instruction->GetType();
389  HBasicBlock* block = instruction->GetBlock();
390  ArenaAllocator* allocator = GetGraph()->GetArena();
391
392  if (input_cst == nullptr) {
393    return;
394  }
395
396  if (input_cst->IsOne()) {
397    // Replace code looking like
398    //    MUL dst, src, 1
399    // with
400    //    src
401    instruction->ReplaceWith(input_other);
402    instruction->GetBlock()->RemoveInstruction(instruction);
403    return;
404  }
405
406  if (input_cst->IsMinusOne() &&
407      (Primitive::IsFloatingPointType(type) || Primitive::IsIntOrLongType(type))) {
408    // Replace code looking like
409    //    MUL dst, src, -1
410    // with
411    //    NEG dst, src
412    HNeg* neg = new (allocator) HNeg(type, input_other);
413    block->ReplaceAndRemoveInstructionWith(instruction, neg);
414    RecordSimplification();
415    return;
416  }
417
418  if (Primitive::IsFloatingPointType(type) &&
419      ((input_cst->IsFloatConstant() && input_cst->AsFloatConstant()->GetValue() == 2.0f) ||
420       (input_cst->IsDoubleConstant() && input_cst->AsDoubleConstant()->GetValue() == 2.0))) {
421    // Replace code looking like
422    //    FP_MUL dst, src, 2.0
423    // with
424    //    FP_ADD dst, src, src
425    // The 'int' and 'long' cases are handled below.
426    block->ReplaceAndRemoveInstructionWith(instruction,
427                                           new (allocator) HAdd(type, input_other, input_other));
428    RecordSimplification();
429    return;
430  }
431
432  if (Primitive::IsIntOrLongType(type)) {
433    int64_t factor = Int64FromConstant(input_cst);
434    // We expect the `0` case to have been handled in the constant folding pass.
435    DCHECK_NE(factor, 0);
436    if (IsPowerOfTwo(factor)) {
437      // Replace code looking like
438      //    MUL dst, src, pow_of_2
439      // with
440      //    SHL dst, src, log2(pow_of_2)
441      HIntConstant* shift = GetGraph()->GetIntConstant(WhichPowerOf2(factor));
442      HShl* shl = new(allocator) HShl(type, input_other, shift);
443      block->ReplaceAndRemoveInstructionWith(instruction, shl);
444      RecordSimplification();
445    }
446  }
447}
448
449void InstructionSimplifierVisitor::VisitNeg(HNeg* instruction) {
450  HInstruction* input = instruction->GetInput();
451  if (input->IsNeg()) {
452    // Replace code looking like
453    //    NEG tmp, src
454    //    NEG dst, tmp
455    // with
456    //    src
457    HNeg* previous_neg = input->AsNeg();
458    instruction->ReplaceWith(previous_neg->GetInput());
459    instruction->GetBlock()->RemoveInstruction(instruction);
460    // We perform the optimization even if the input negation has environment
461    // uses since it allows removing the current instruction. But we only delete
462    // the input negation only if it is does not have any uses left.
463    if (!previous_neg->HasUses()) {
464      previous_neg->GetBlock()->RemoveInstruction(previous_neg);
465    }
466    RecordSimplification();
467    return;
468  }
469
470  if (input->IsSub() && input->HasOnlyOneNonEnvironmentUse()) {
471    // Replace code looking like
472    //    SUB tmp, a, b
473    //    NEG dst, tmp
474    // with
475    //    SUB dst, b, a
476    // We do not perform the optimization if the input subtraction has
477    // environment uses or multiple non-environment uses as it could lead to
478    // worse code. In particular, we do not want the live ranges of `a` and `b`
479    // to be extended if we are not sure the initial 'SUB' instruction can be
480    // removed.
481    HSub* sub = input->AsSub();
482    HSub* new_sub =
483        new (GetGraph()->GetArena()) HSub(instruction->GetType(), sub->GetRight(), sub->GetLeft());
484    instruction->GetBlock()->ReplaceAndRemoveInstructionWith(instruction, new_sub);
485    if (!sub->HasUses()) {
486      sub->GetBlock()->RemoveInstruction(sub);
487    }
488    RecordSimplification();
489  }
490}
491
492void InstructionSimplifierVisitor::VisitNot(HNot* instruction) {
493  HInstruction* input = instruction->GetInput();
494  if (input->IsNot()) {
495    // Replace code looking like
496    //    NOT tmp, src
497    //    NOT dst, tmp
498    // with
499    //    src
500    // We perform the optimization even if the input negation has environment
501    // uses since it allows removing the current instruction. But we only delete
502    // the input negation only if it is does not have any uses left.
503    HNot* previous_not = input->AsNot();
504    instruction->ReplaceWith(previous_not->GetInput());
505    instruction->GetBlock()->RemoveInstruction(instruction);
506    if (!previous_not->HasUses()) {
507      previous_not->GetBlock()->RemoveInstruction(previous_not);
508    }
509    RecordSimplification();
510  }
511}
512
513void InstructionSimplifierVisitor::VisitOr(HOr* instruction) {
514  HConstant* input_cst = instruction->GetConstantRight();
515  HInstruction* input_other = instruction->GetLeastConstantLeft();
516
517  if ((input_cst != nullptr) && input_cst->IsZero()) {
518    // Replace code looking like
519    //    OR dst, src, 0
520    // with
521    //    src
522    instruction->ReplaceWith(input_other);
523    instruction->GetBlock()->RemoveInstruction(instruction);
524    return;
525  }
526
527  // We assume that GVN has run before, so we only perform a pointer comparison.
528  // If for some reason the values are equal but the pointers are different, we
529  // are still correct and only miss an optimization opportunity.
530  if (instruction->GetLeft() == instruction->GetRight()) {
531    // Replace code looking like
532    //    OR dst, src, src
533    // with
534    //    src
535    instruction->ReplaceWith(instruction->GetLeft());
536    instruction->GetBlock()->RemoveInstruction(instruction);
537  }
538}
539
540void InstructionSimplifierVisitor::VisitShl(HShl* instruction) {
541  VisitShift(instruction);
542}
543
544void InstructionSimplifierVisitor::VisitShr(HShr* instruction) {
545  VisitShift(instruction);
546}
547
548void InstructionSimplifierVisitor::VisitSub(HSub* instruction) {
549  HConstant* input_cst = instruction->GetConstantRight();
550  HInstruction* input_other = instruction->GetLeastConstantLeft();
551
552  if ((input_cst != nullptr) && input_cst->IsZero()) {
553    // Replace code looking like
554    //    SUB dst, src, 0
555    // with
556    //    src
557    instruction->ReplaceWith(input_other);
558    instruction->GetBlock()->RemoveInstruction(instruction);
559    return;
560  }
561
562  Primitive::Type type = instruction->GetType();
563  if (!Primitive::IsIntegralType(type)) {
564    return;
565  }
566
567  HBasicBlock* block = instruction->GetBlock();
568  ArenaAllocator* allocator = GetGraph()->GetArena();
569
570  HInstruction* left = instruction->GetLeft();
571  HInstruction* right = instruction->GetRight();
572  if (left->IsConstant()) {
573    if (Int64FromConstant(left->AsConstant()) == 0) {
574      // Replace code looking like
575      //    SUB dst, 0, src
576      // with
577      //    NEG dst, src
578      // Note that we cannot optimize `0.0 - x` to `-x` for floating-point. When
579      // `x` is `0.0`, the former expression yields `0.0`, while the later
580      // yields `-0.0`.
581      HNeg* neg = new (allocator) HNeg(type, right);
582      block->ReplaceAndRemoveInstructionWith(instruction, neg);
583      RecordSimplification();
584      return;
585    }
586  }
587
588  if (left->IsNeg() && right->IsNeg()) {
589    if (TryMoveNegOnInputsAfterBinop(instruction)) {
590      return;
591    }
592  }
593
594  if (right->IsNeg() && right->HasOnlyOneNonEnvironmentUse()) {
595    // Replace code looking like
596    //    NEG tmp, b
597    //    SUB dst, a, tmp
598    // with
599    //    ADD dst, a, b
600    HAdd* add = new(GetGraph()->GetArena()) HAdd(type, left, right->AsNeg()->GetInput());
601    instruction->GetBlock()->ReplaceAndRemoveInstructionWith(instruction, add);
602    RecordSimplification();
603    right->GetBlock()->RemoveInstruction(right);
604    return;
605  }
606
607  if (left->IsNeg() && left->HasOnlyOneNonEnvironmentUse()) {
608    // Replace code looking like
609    //    NEG tmp, a
610    //    SUB dst, tmp, b
611    // with
612    //    ADD tmp, a, b
613    //    NEG dst, tmp
614    // The second version is not intrinsically better, but enables more
615    // transformations.
616    HAdd* add = new(GetGraph()->GetArena()) HAdd(type, left->AsNeg()->GetInput(), right);
617    instruction->GetBlock()->InsertInstructionBefore(add, instruction);
618    HNeg* neg = new (GetGraph()->GetArena()) HNeg(instruction->GetType(), add);
619    instruction->GetBlock()->InsertInstructionBefore(neg, instruction);
620    instruction->ReplaceWith(neg);
621    instruction->GetBlock()->RemoveInstruction(instruction);
622    RecordSimplification();
623    left->GetBlock()->RemoveInstruction(left);
624  }
625}
626
627void InstructionSimplifierVisitor::VisitUShr(HUShr* instruction) {
628  VisitShift(instruction);
629}
630
631void InstructionSimplifierVisitor::VisitXor(HXor* instruction) {
632  HConstant* input_cst = instruction->GetConstantRight();
633  HInstruction* input_other = instruction->GetLeastConstantLeft();
634
635  if ((input_cst != nullptr) && input_cst->IsZero()) {
636    // Replace code looking like
637    //    XOR dst, src, 0
638    // with
639    //    src
640    instruction->ReplaceWith(input_other);
641    instruction->GetBlock()->RemoveInstruction(instruction);
642    return;
643  }
644
645  if ((input_cst != nullptr) && AreAllBitsSet(input_cst)) {
646    // Replace code looking like
647    //    XOR dst, src, 0xFFF...FF
648    // with
649    //    NOT dst, src
650    HNot* bitwise_not = new (GetGraph()->GetArena()) HNot(instruction->GetType(), input_other);
651    instruction->GetBlock()->ReplaceAndRemoveInstructionWith(instruction, bitwise_not);
652    RecordSimplification();
653    return;
654  }
655}
656
657}  // namespace art
658