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