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