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