instruction_simplifier.cc revision 38db785600757a832423e076b3cf0af3bee942d8
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 "intrinsics.h" 20#include "mirror/class-inl.h" 21#include "scoped_thread_state_change.h" 22 23namespace art { 24 25class InstructionSimplifierVisitor : public HGraphDelegateVisitor { 26 public: 27 InstructionSimplifierVisitor(HGraph* graph, OptimizingCompilerStats* stats) 28 : HGraphDelegateVisitor(graph), 29 stats_(stats) {} 30 31 void Run(); 32 33 private: 34 void RecordSimplification() { 35 simplification_occurred_ = true; 36 simplifications_at_current_position_++; 37 if (stats_) { 38 stats_->RecordStat(kInstructionSimplifications); 39 } 40 } 41 42 bool TryMoveNegOnInputsAfterBinop(HBinaryOperation* binop); 43 void VisitShift(HBinaryOperation* shift); 44 45 void VisitSuspendCheck(HSuspendCheck* check) OVERRIDE; 46 void VisitEqual(HEqual* equal) OVERRIDE; 47 void VisitNotEqual(HNotEqual* equal) OVERRIDE; 48 void VisitBooleanNot(HBooleanNot* bool_not) OVERRIDE; 49 void VisitInstanceFieldSet(HInstanceFieldSet* equal) OVERRIDE; 50 void VisitStaticFieldSet(HStaticFieldSet* equal) OVERRIDE; 51 void VisitArraySet(HArraySet* equal) OVERRIDE; 52 void VisitTypeConversion(HTypeConversion* instruction) OVERRIDE; 53 void VisitNullCheck(HNullCheck* instruction) OVERRIDE; 54 void VisitArrayLength(HArrayLength* instruction) OVERRIDE; 55 void VisitCheckCast(HCheckCast* instruction) OVERRIDE; 56 void VisitAdd(HAdd* instruction) OVERRIDE; 57 void VisitAnd(HAnd* instruction) OVERRIDE; 58 void VisitCondition(HCondition* instruction) OVERRIDE; 59 void VisitGreaterThan(HGreaterThan* condition) OVERRIDE; 60 void VisitGreaterThanOrEqual(HGreaterThanOrEqual* condition) OVERRIDE; 61 void VisitLessThan(HLessThan* condition) OVERRIDE; 62 void VisitLessThanOrEqual(HLessThanOrEqual* condition) OVERRIDE; 63 void VisitDiv(HDiv* instruction) OVERRIDE; 64 void VisitMul(HMul* instruction) OVERRIDE; 65 void VisitNeg(HNeg* instruction) OVERRIDE; 66 void VisitNot(HNot* instruction) OVERRIDE; 67 void VisitOr(HOr* instruction) OVERRIDE; 68 void VisitShl(HShl* instruction) OVERRIDE; 69 void VisitShr(HShr* instruction) OVERRIDE; 70 void VisitSub(HSub* instruction) OVERRIDE; 71 void VisitUShr(HUShr* instruction) OVERRIDE; 72 void VisitXor(HXor* instruction) OVERRIDE; 73 void VisitInstanceOf(HInstanceOf* instruction) OVERRIDE; 74 void VisitFakeString(HFakeString* fake_string) OVERRIDE; 75 void VisitInvoke(HInvoke* invoke) OVERRIDE; 76 void VisitDeoptimize(HDeoptimize* deoptimize) OVERRIDE; 77 78 bool CanEnsureNotNullAt(HInstruction* instr, HInstruction* at) const; 79 80 void SimplifySystemArrayCopy(HInvoke* invoke); 81 void SimplifyStringEquals(HInvoke* invoke); 82 83 OptimizingCompilerStats* stats_; 84 bool simplification_occurred_ = false; 85 int simplifications_at_current_position_ = 0; 86 // We ensure we do not loop infinitely. The value is a finger in the air guess 87 // that should allow enough simplification. 88 static constexpr int kMaxSamePositionSimplifications = 10; 89}; 90 91void InstructionSimplifier::Run() { 92 InstructionSimplifierVisitor visitor(graph_, stats_); 93 visitor.Run(); 94} 95 96void InstructionSimplifierVisitor::Run() { 97 // Iterate in reverse post order to open up more simplifications to users 98 // of instructions that got simplified. 99 for (HReversePostOrderIterator it(*GetGraph()); !it.Done();) { 100 // The simplification of an instruction to another instruction may yield 101 // possibilities for other simplifications. So although we perform a reverse 102 // post order visit, we sometimes need to revisit an instruction index. 103 simplification_occurred_ = false; 104 VisitBasicBlock(it.Current()); 105 if (simplification_occurred_ && 106 (simplifications_at_current_position_ < kMaxSamePositionSimplifications)) { 107 // New simplifications may be applicable to the instruction at the 108 // current index, so don't advance the iterator. 109 continue; 110 } 111 simplifications_at_current_position_ = 0; 112 it.Advance(); 113 } 114} 115 116namespace { 117 118bool AreAllBitsSet(HConstant* constant) { 119 return Int64FromConstant(constant) == -1; 120} 121 122} // namespace 123 124// Returns true if the code was simplified to use only one negation operation 125// after the binary operation instead of one on each of the inputs. 126bool InstructionSimplifierVisitor::TryMoveNegOnInputsAfterBinop(HBinaryOperation* binop) { 127 DCHECK(binop->IsAdd() || binop->IsSub()); 128 DCHECK(binop->GetLeft()->IsNeg() && binop->GetRight()->IsNeg()); 129 HNeg* left_neg = binop->GetLeft()->AsNeg(); 130 HNeg* right_neg = binop->GetRight()->AsNeg(); 131 if (!left_neg->HasOnlyOneNonEnvironmentUse() || 132 !right_neg->HasOnlyOneNonEnvironmentUse()) { 133 return false; 134 } 135 // Replace code looking like 136 // NEG tmp1, a 137 // NEG tmp2, b 138 // ADD dst, tmp1, tmp2 139 // with 140 // ADD tmp, a, b 141 // NEG dst, tmp 142 // Note that we cannot optimize `(-a) + (-b)` to `-(a + b)` for floating-point. 143 // When `a` is `-0.0` and `b` is `0.0`, the former expression yields `0.0`, 144 // while the later yields `-0.0`. 145 if (!Primitive::IsIntegralType(binop->GetType())) { 146 return false; 147 } 148 binop->ReplaceInput(left_neg->GetInput(), 0); 149 binop->ReplaceInput(right_neg->GetInput(), 1); 150 left_neg->GetBlock()->RemoveInstruction(left_neg); 151 right_neg->GetBlock()->RemoveInstruction(right_neg); 152 HNeg* neg = new (GetGraph()->GetArena()) HNeg(binop->GetType(), binop); 153 binop->GetBlock()->InsertInstructionBefore(neg, binop->GetNext()); 154 binop->ReplaceWithExceptInReplacementAtIndex(neg, 0); 155 RecordSimplification(); 156 return true; 157} 158 159void InstructionSimplifierVisitor::VisitShift(HBinaryOperation* instruction) { 160 DCHECK(instruction->IsShl() || instruction->IsShr() || instruction->IsUShr()); 161 HConstant* input_cst = instruction->GetConstantRight(); 162 HInstruction* input_other = instruction->GetLeastConstantLeft(); 163 164 if (input_cst != nullptr) { 165 if (input_cst->IsZero()) { 166 // Replace code looking like 167 // SHL dst, src, 0 168 // with 169 // src 170 instruction->ReplaceWith(input_other); 171 instruction->GetBlock()->RemoveInstruction(instruction); 172 } else if (instruction->IsShl() && input_cst->IsOne()) { 173 // Replace Shl looking like 174 // SHL dst, src, 1 175 // with 176 // ADD dst, src, src 177 HAdd *add = new(GetGraph()->GetArena()) HAdd(instruction->GetType(), 178 input_other, 179 input_other); 180 instruction->GetBlock()->ReplaceAndRemoveInstructionWith(instruction, add); 181 RecordSimplification(); 182 } 183 } 184} 185 186void InstructionSimplifierVisitor::VisitNullCheck(HNullCheck* null_check) { 187 HInstruction* obj = null_check->InputAt(0); 188 if (!obj->CanBeNull()) { 189 null_check->ReplaceWith(obj); 190 null_check->GetBlock()->RemoveInstruction(null_check); 191 if (stats_ != nullptr) { 192 stats_->RecordStat(MethodCompilationStat::kRemovedNullCheck); 193 } 194 } 195} 196 197bool InstructionSimplifierVisitor::CanEnsureNotNullAt(HInstruction* input, HInstruction* at) const { 198 if (!input->CanBeNull()) { 199 return true; 200 } 201 202 for (HUseIterator<HInstruction*> it(input->GetUses()); !it.Done(); it.Advance()) { 203 HInstruction* use = it.Current()->GetUser(); 204 if (use->IsNullCheck() && use->StrictlyDominates(at)) { 205 return true; 206 } 207 } 208 209 return false; 210} 211 212// Returns whether doing a type test between the class of `object` against `klass` has 213// a statically known outcome. The result of the test is stored in `outcome`. 214static bool TypeCheckHasKnownOutcome(HLoadClass* klass, HInstruction* object, bool* outcome) { 215 DCHECK(!object->IsNullConstant()) << "Null constants should be special cased"; 216 ReferenceTypeInfo obj_rti = object->GetReferenceTypeInfo(); 217 ScopedObjectAccess soa(Thread::Current()); 218 if (!obj_rti.IsValid()) { 219 // We run the simplifier before the reference type propagation so type info might not be 220 // available. 221 return false; 222 } 223 224 ReferenceTypeInfo class_rti = klass->GetLoadedClassRTI(); 225 if (!class_rti.IsValid()) { 226 // Happens when the loaded class is unresolved. 227 return false; 228 } 229 DCHECK(class_rti.IsExact()); 230 if (class_rti.IsSupertypeOf(obj_rti)) { 231 *outcome = true; 232 return true; 233 } else if (obj_rti.IsExact()) { 234 // The test failed at compile time so will also fail at runtime. 235 *outcome = false; 236 return true; 237 } else if (!class_rti.IsInterface() 238 && !obj_rti.IsInterface() 239 && !obj_rti.IsSupertypeOf(class_rti)) { 240 // Different type hierarchy. The test will fail. 241 *outcome = false; 242 return true; 243 } 244 return false; 245} 246 247void InstructionSimplifierVisitor::VisitCheckCast(HCheckCast* check_cast) { 248 HInstruction* object = check_cast->InputAt(0); 249 HLoadClass* load_class = check_cast->InputAt(1)->AsLoadClass(); 250 if (load_class->NeedsAccessCheck()) { 251 // If we need to perform an access check we cannot remove the instruction. 252 return; 253 } 254 255 if (CanEnsureNotNullAt(object, check_cast)) { 256 check_cast->ClearMustDoNullCheck(); 257 } 258 259 if (object->IsNullConstant()) { 260 check_cast->GetBlock()->RemoveInstruction(check_cast); 261 if (stats_ != nullptr) { 262 stats_->RecordStat(MethodCompilationStat::kRemovedCheckedCast); 263 } 264 return; 265 } 266 267 bool outcome; 268 if (TypeCheckHasKnownOutcome(load_class, object, &outcome)) { 269 if (outcome) { 270 check_cast->GetBlock()->RemoveInstruction(check_cast); 271 if (stats_ != nullptr) { 272 stats_->RecordStat(MethodCompilationStat::kRemovedCheckedCast); 273 } 274 if (!load_class->HasUses()) { 275 // We cannot rely on DCE to remove the class because the `HLoadClass` thinks it can throw. 276 // However, here we know that it cannot because the checkcast was successfull, hence 277 // the class was already loaded. 278 load_class->GetBlock()->RemoveInstruction(load_class); 279 } 280 } else { 281 // Don't do anything for exceptional cases for now. Ideally we should remove 282 // all instructions and blocks this instruction dominates. 283 } 284 } 285} 286 287void InstructionSimplifierVisitor::VisitInstanceOf(HInstanceOf* instruction) { 288 HInstruction* object = instruction->InputAt(0); 289 HLoadClass* load_class = instruction->InputAt(1)->AsLoadClass(); 290 if (load_class->NeedsAccessCheck()) { 291 // If we need to perform an access check we cannot remove the instruction. 292 return; 293 } 294 295 bool can_be_null = true; 296 if (CanEnsureNotNullAt(object, instruction)) { 297 can_be_null = false; 298 instruction->ClearMustDoNullCheck(); 299 } 300 301 HGraph* graph = GetGraph(); 302 if (object->IsNullConstant()) { 303 instruction->ReplaceWith(graph->GetIntConstant(0)); 304 instruction->GetBlock()->RemoveInstruction(instruction); 305 RecordSimplification(); 306 return; 307 } 308 309 bool outcome; 310 if (TypeCheckHasKnownOutcome(load_class, object, &outcome)) { 311 if (outcome && can_be_null) { 312 // Type test will succeed, we just need a null test. 313 HNotEqual* test = new (graph->GetArena()) HNotEqual(graph->GetNullConstant(), object); 314 instruction->GetBlock()->InsertInstructionBefore(test, instruction); 315 instruction->ReplaceWith(test); 316 } else { 317 // We've statically determined the result of the instanceof. 318 instruction->ReplaceWith(graph->GetIntConstant(outcome)); 319 } 320 RecordSimplification(); 321 instruction->GetBlock()->RemoveInstruction(instruction); 322 if (outcome && !load_class->HasUses()) { 323 // We cannot rely on DCE to remove the class because the `HLoadClass` thinks it can throw. 324 // However, here we know that it cannot because the instanceof check was successfull, hence 325 // the class was already loaded. 326 load_class->GetBlock()->RemoveInstruction(load_class); 327 } 328 } 329} 330 331void InstructionSimplifierVisitor::VisitInstanceFieldSet(HInstanceFieldSet* instruction) { 332 if ((instruction->GetValue()->GetType() == Primitive::kPrimNot) 333 && CanEnsureNotNullAt(instruction->GetValue(), instruction)) { 334 instruction->ClearValueCanBeNull(); 335 } 336} 337 338void InstructionSimplifierVisitor::VisitStaticFieldSet(HStaticFieldSet* instruction) { 339 if ((instruction->GetValue()->GetType() == Primitive::kPrimNot) 340 && CanEnsureNotNullAt(instruction->GetValue(), instruction)) { 341 instruction->ClearValueCanBeNull(); 342 } 343} 344 345void InstructionSimplifierVisitor::VisitSuspendCheck(HSuspendCheck* check) { 346 HBasicBlock* block = check->GetBlock(); 347 // Currently always keep the suspend check at entry. 348 if (block->IsEntryBlock()) return; 349 350 // Currently always keep suspend checks at loop entry. 351 if (block->IsLoopHeader() && block->GetFirstInstruction() == check) { 352 DCHECK(block->GetLoopInformation()->GetSuspendCheck() == check); 353 return; 354 } 355 356 // Remove the suspend check that was added at build time for the baseline 357 // compiler. 358 block->RemoveInstruction(check); 359} 360 361void InstructionSimplifierVisitor::VisitEqual(HEqual* equal) { 362 HInstruction* input_const = equal->GetConstantRight(); 363 if (input_const != nullptr) { 364 HInstruction* input_value = equal->GetLeastConstantLeft(); 365 if (input_value->GetType() == Primitive::kPrimBoolean && input_const->IsIntConstant()) { 366 HBasicBlock* block = equal->GetBlock(); 367 // We are comparing the boolean to a constant which is of type int and can 368 // be any constant. 369 if (input_const->AsIntConstant()->IsOne()) { 370 // Replace (bool_value == true) with bool_value 371 equal->ReplaceWith(input_value); 372 block->RemoveInstruction(equal); 373 RecordSimplification(); 374 } else if (input_const->AsIntConstant()->IsZero()) { 375 // Replace (bool_value == false) with !bool_value 376 block->ReplaceAndRemoveInstructionWith( 377 equal, new (block->GetGraph()->GetArena()) HBooleanNot(input_value)); 378 RecordSimplification(); 379 } else { 380 // Replace (bool_value == integer_not_zero_nor_one_constant) with false 381 equal->ReplaceWith(GetGraph()->GetIntConstant(0)); 382 block->RemoveInstruction(equal); 383 RecordSimplification(); 384 } 385 } else { 386 VisitCondition(equal); 387 } 388 } else { 389 VisitCondition(equal); 390 } 391} 392 393void InstructionSimplifierVisitor::VisitNotEqual(HNotEqual* not_equal) { 394 HInstruction* input_const = not_equal->GetConstantRight(); 395 if (input_const != nullptr) { 396 HInstruction* input_value = not_equal->GetLeastConstantLeft(); 397 if (input_value->GetType() == Primitive::kPrimBoolean && input_const->IsIntConstant()) { 398 HBasicBlock* block = not_equal->GetBlock(); 399 // We are comparing the boolean to a constant which is of type int and can 400 // be any constant. 401 if (input_const->AsIntConstant()->IsOne()) { 402 // Replace (bool_value != true) with !bool_value 403 block->ReplaceAndRemoveInstructionWith( 404 not_equal, new (block->GetGraph()->GetArena()) HBooleanNot(input_value)); 405 RecordSimplification(); 406 } else if (input_const->AsIntConstant()->IsZero()) { 407 // Replace (bool_value != false) with bool_value 408 not_equal->ReplaceWith(input_value); 409 block->RemoveInstruction(not_equal); 410 RecordSimplification(); 411 } else { 412 // Replace (bool_value != integer_not_zero_nor_one_constant) with true 413 not_equal->ReplaceWith(GetGraph()->GetIntConstant(1)); 414 block->RemoveInstruction(not_equal); 415 RecordSimplification(); 416 } 417 } else { 418 VisitCondition(not_equal); 419 } 420 } else { 421 VisitCondition(not_equal); 422 } 423} 424 425void InstructionSimplifierVisitor::VisitBooleanNot(HBooleanNot* bool_not) { 426 HInstruction* parent = bool_not->InputAt(0); 427 if (parent->IsBooleanNot()) { 428 HInstruction* value = parent->InputAt(0); 429 // Replace (!(!bool_value)) with bool_value 430 bool_not->ReplaceWith(value); 431 bool_not->GetBlock()->RemoveInstruction(bool_not); 432 // It is possible that `parent` is dead at this point but we leave 433 // its removal to DCE for simplicity. 434 RecordSimplification(); 435 } 436} 437 438void InstructionSimplifierVisitor::VisitArrayLength(HArrayLength* instruction) { 439 HInstruction* input = instruction->InputAt(0); 440 // If the array is a NewArray with constant size, replace the array length 441 // with the constant instruction. This helps the bounds check elimination phase. 442 if (input->IsNewArray()) { 443 input = input->InputAt(0); 444 if (input->IsIntConstant()) { 445 instruction->ReplaceWith(input); 446 } 447 } 448} 449 450void InstructionSimplifierVisitor::VisitArraySet(HArraySet* instruction) { 451 HInstruction* value = instruction->GetValue(); 452 if (value->GetType() != Primitive::kPrimNot) return; 453 454 if (CanEnsureNotNullAt(value, instruction)) { 455 instruction->ClearValueCanBeNull(); 456 } 457 458 if (value->IsArrayGet()) { 459 if (value->AsArrayGet()->GetArray() == instruction->GetArray()) { 460 // If the code is just swapping elements in the array, no need for a type check. 461 instruction->ClearNeedsTypeCheck(); 462 return; 463 } 464 } 465 466 if (value->IsNullConstant()) { 467 instruction->ClearNeedsTypeCheck(); 468 return; 469 } 470 471 ScopedObjectAccess soa(Thread::Current()); 472 ReferenceTypeInfo array_rti = instruction->GetArray()->GetReferenceTypeInfo(); 473 ReferenceTypeInfo value_rti = value->GetReferenceTypeInfo(); 474 if (!array_rti.IsValid()) { 475 return; 476 } 477 478 if (value_rti.IsValid() && array_rti.CanArrayHold(value_rti)) { 479 instruction->ClearNeedsTypeCheck(); 480 return; 481 } 482 483 if (array_rti.IsObjectArray()) { 484 if (array_rti.IsExact()) { 485 instruction->ClearNeedsTypeCheck(); 486 return; 487 } 488 instruction->SetStaticTypeOfArrayIsObjectArray(); 489 } 490} 491 492void InstructionSimplifierVisitor::VisitTypeConversion(HTypeConversion* instruction) { 493 if (instruction->GetResultType() == instruction->GetInputType()) { 494 // Remove the instruction if it's converting to the same type. 495 instruction->ReplaceWith(instruction->GetInput()); 496 instruction->GetBlock()->RemoveInstruction(instruction); 497 } 498} 499 500void InstructionSimplifierVisitor::VisitAdd(HAdd* instruction) { 501 HConstant* input_cst = instruction->GetConstantRight(); 502 HInstruction* input_other = instruction->GetLeastConstantLeft(); 503 if ((input_cst != nullptr) && input_cst->IsZero()) { 504 // Replace code looking like 505 // ADD dst, src, 0 506 // with 507 // src 508 // Note that we cannot optimize `x + 0.0` to `x` for floating-point. When 509 // `x` is `-0.0`, the former expression yields `0.0`, while the later 510 // yields `-0.0`. 511 if (Primitive::IsIntegralType(instruction->GetType())) { 512 instruction->ReplaceWith(input_other); 513 instruction->GetBlock()->RemoveInstruction(instruction); 514 return; 515 } 516 } 517 518 HInstruction* left = instruction->GetLeft(); 519 HInstruction* right = instruction->GetRight(); 520 bool left_is_neg = left->IsNeg(); 521 bool right_is_neg = right->IsNeg(); 522 523 if (left_is_neg && right_is_neg) { 524 if (TryMoveNegOnInputsAfterBinop(instruction)) { 525 return; 526 } 527 } 528 529 HNeg* neg = left_is_neg ? left->AsNeg() : right->AsNeg(); 530 if ((left_is_neg ^ right_is_neg) && neg->HasOnlyOneNonEnvironmentUse()) { 531 // Replace code looking like 532 // NEG tmp, b 533 // ADD dst, a, tmp 534 // with 535 // SUB dst, a, b 536 // We do not perform the optimization if the input negation has environment 537 // uses or multiple non-environment uses as it could lead to worse code. In 538 // particular, we do not want the live range of `b` to be extended if we are 539 // not sure the initial 'NEG' instruction can be removed. 540 HInstruction* other = left_is_neg ? right : left; 541 HSub* sub = new(GetGraph()->GetArena()) HSub(instruction->GetType(), other, neg->GetInput()); 542 instruction->GetBlock()->ReplaceAndRemoveInstructionWith(instruction, sub); 543 RecordSimplification(); 544 neg->GetBlock()->RemoveInstruction(neg); 545 } 546} 547 548void InstructionSimplifierVisitor::VisitAnd(HAnd* instruction) { 549 HConstant* input_cst = instruction->GetConstantRight(); 550 HInstruction* input_other = instruction->GetLeastConstantLeft(); 551 552 if (input_cst != nullptr) { 553 int64_t value = Int64FromConstant(input_cst); 554 if (value == -1) { 555 // Replace code looking like 556 // AND dst, src, 0xFFF...FF 557 // with 558 // src 559 instruction->ReplaceWith(input_other); 560 instruction->GetBlock()->RemoveInstruction(instruction); 561 RecordSimplification(); 562 return; 563 } 564 // Eliminate And from UShr+And if the And-mask contains all the bits that 565 // can be non-zero after UShr. Transform Shr+And to UShr if the And-mask 566 // precisely clears the shifted-in sign bits. 567 if ((input_other->IsUShr() || input_other->IsShr()) && input_other->InputAt(1)->IsConstant()) { 568 size_t reg_bits = (instruction->GetResultType() == Primitive::kPrimLong) ? 64 : 32; 569 size_t shift = Int64FromConstant(input_other->InputAt(1)->AsConstant()) & (reg_bits - 1); 570 size_t num_tail_bits_set = CTZ(value + 1); 571 if ((num_tail_bits_set >= reg_bits - shift) && input_other->IsUShr()) { 572 // This AND clears only bits known to be clear, for example "(x >>> 24) & 0xff". 573 instruction->ReplaceWith(input_other); 574 instruction->GetBlock()->RemoveInstruction(instruction); 575 RecordSimplification(); 576 return; 577 } else if ((num_tail_bits_set == reg_bits - shift) && IsPowerOfTwo(value + 1) && 578 input_other->HasOnlyOneNonEnvironmentUse()) { 579 DCHECK(input_other->IsShr()); // For UShr, we would have taken the branch above. 580 // Replace SHR+AND with USHR, for example "(x >> 24) & 0xff" -> "x >>> 24". 581 HUShr* ushr = new (GetGraph()->GetArena()) HUShr(instruction->GetType(), 582 input_other->InputAt(0), 583 input_other->InputAt(1), 584 input_other->GetDexPc()); 585 instruction->GetBlock()->ReplaceAndRemoveInstructionWith(instruction, ushr); 586 input_other->GetBlock()->RemoveInstruction(input_other); 587 RecordSimplification(); 588 return; 589 } 590 } 591 } 592 593 // We assume that GVN has run before, so we only perform a pointer comparison. 594 // If for some reason the values are equal but the pointers are different, we 595 // are still correct and only miss an optimization opportunity. 596 if (instruction->GetLeft() == instruction->GetRight()) { 597 // Replace code looking like 598 // AND dst, src, src 599 // with 600 // src 601 instruction->ReplaceWith(instruction->GetLeft()); 602 instruction->GetBlock()->RemoveInstruction(instruction); 603 } 604} 605 606void InstructionSimplifierVisitor::VisitGreaterThan(HGreaterThan* condition) { 607 VisitCondition(condition); 608} 609 610void InstructionSimplifierVisitor::VisitGreaterThanOrEqual(HGreaterThanOrEqual* condition) { 611 VisitCondition(condition); 612} 613 614void InstructionSimplifierVisitor::VisitLessThan(HLessThan* condition) { 615 VisitCondition(condition); 616} 617 618void InstructionSimplifierVisitor::VisitLessThanOrEqual(HLessThanOrEqual* condition) { 619 VisitCondition(condition); 620} 621 622// TODO: unsigned comparisons too? 623 624void InstructionSimplifierVisitor::VisitCondition(HCondition* condition) { 625 // Try to fold an HCompare into this HCondition. 626 627 // This simplification is currently supported on x86, x86_64, ARM and ARM64. 628 // TODO: Implement it for MIPS and MIPS64. 629 InstructionSet instruction_set = GetGraph()->GetInstructionSet(); 630 if (instruction_set == kMips || instruction_set == kMips64) { 631 return; 632 } 633 634 HInstruction* left = condition->GetLeft(); 635 HInstruction* right = condition->GetRight(); 636 // We can only replace an HCondition which compares a Compare to 0. 637 // Both 'dx' and 'jack' generate a compare to 0 when compiling a 638 // condition with a long, float or double comparison as input. 639 if (!left->IsCompare() || !right->IsConstant() || right->AsIntConstant()->GetValue() != 0) { 640 // Conversion is not possible. 641 return; 642 } 643 644 // Is the Compare only used for this purpose? 645 if (!left->GetUses().HasOnlyOneUse()) { 646 // Someone else also wants the result of the compare. 647 return; 648 } 649 650 if (!left->GetEnvUses().IsEmpty()) { 651 // There is a reference to the compare result in an environment. Do we really need it? 652 if (GetGraph()->IsDebuggable()) { 653 return; 654 } 655 656 // We have to ensure that there are no deopt points in the sequence. 657 if (left->HasAnyEnvironmentUseBefore(condition)) { 658 return; 659 } 660 } 661 662 // Clean up any environment uses from the HCompare, if any. 663 left->RemoveEnvironmentUsers(); 664 665 // We have decided to fold the HCompare into the HCondition. Transfer the information. 666 condition->SetBias(left->AsCompare()->GetBias()); 667 668 // Replace the operands of the HCondition. 669 condition->ReplaceInput(left->InputAt(0), 0); 670 condition->ReplaceInput(left->InputAt(1), 1); 671 672 // Remove the HCompare. 673 left->GetBlock()->RemoveInstruction(left); 674 675 RecordSimplification(); 676} 677 678void InstructionSimplifierVisitor::VisitDiv(HDiv* instruction) { 679 HConstant* input_cst = instruction->GetConstantRight(); 680 HInstruction* input_other = instruction->GetLeastConstantLeft(); 681 Primitive::Type type = instruction->GetType(); 682 683 if ((input_cst != nullptr) && input_cst->IsOne()) { 684 // Replace code looking like 685 // DIV dst, src, 1 686 // with 687 // src 688 instruction->ReplaceWith(input_other); 689 instruction->GetBlock()->RemoveInstruction(instruction); 690 return; 691 } 692 693 if ((input_cst != nullptr) && input_cst->IsMinusOne()) { 694 // Replace code looking like 695 // DIV dst, src, -1 696 // with 697 // NEG dst, src 698 instruction->GetBlock()->ReplaceAndRemoveInstructionWith( 699 instruction, new (GetGraph()->GetArena()) HNeg(type, input_other)); 700 RecordSimplification(); 701 return; 702 } 703 704 if ((input_cst != nullptr) && Primitive::IsFloatingPointType(type)) { 705 // Try replacing code looking like 706 // DIV dst, src, constant 707 // with 708 // MUL dst, src, 1 / constant 709 HConstant* reciprocal = nullptr; 710 if (type == Primitive::Primitive::kPrimDouble) { 711 double value = input_cst->AsDoubleConstant()->GetValue(); 712 if (CanDivideByReciprocalMultiplyDouble(bit_cast<int64_t, double>(value))) { 713 reciprocal = GetGraph()->GetDoubleConstant(1.0 / value); 714 } 715 } else { 716 DCHECK_EQ(type, Primitive::kPrimFloat); 717 float value = input_cst->AsFloatConstant()->GetValue(); 718 if (CanDivideByReciprocalMultiplyFloat(bit_cast<int32_t, float>(value))) { 719 reciprocal = GetGraph()->GetFloatConstant(1.0f / value); 720 } 721 } 722 723 if (reciprocal != nullptr) { 724 instruction->GetBlock()->ReplaceAndRemoveInstructionWith( 725 instruction, new (GetGraph()->GetArena()) HMul(type, input_other, reciprocal)); 726 RecordSimplification(); 727 return; 728 } 729 } 730} 731 732void InstructionSimplifierVisitor::VisitMul(HMul* instruction) { 733 HConstant* input_cst = instruction->GetConstantRight(); 734 HInstruction* input_other = instruction->GetLeastConstantLeft(); 735 Primitive::Type type = instruction->GetType(); 736 HBasicBlock* block = instruction->GetBlock(); 737 ArenaAllocator* allocator = GetGraph()->GetArena(); 738 739 if (input_cst == nullptr) { 740 return; 741 } 742 743 if (input_cst->IsOne()) { 744 // Replace code looking like 745 // MUL dst, src, 1 746 // with 747 // src 748 instruction->ReplaceWith(input_other); 749 instruction->GetBlock()->RemoveInstruction(instruction); 750 return; 751 } 752 753 if (input_cst->IsMinusOne() && 754 (Primitive::IsFloatingPointType(type) || Primitive::IsIntOrLongType(type))) { 755 // Replace code looking like 756 // MUL dst, src, -1 757 // with 758 // NEG dst, src 759 HNeg* neg = new (allocator) HNeg(type, input_other); 760 block->ReplaceAndRemoveInstructionWith(instruction, neg); 761 RecordSimplification(); 762 return; 763 } 764 765 if (Primitive::IsFloatingPointType(type) && 766 ((input_cst->IsFloatConstant() && input_cst->AsFloatConstant()->GetValue() == 2.0f) || 767 (input_cst->IsDoubleConstant() && input_cst->AsDoubleConstant()->GetValue() == 2.0))) { 768 // Replace code looking like 769 // FP_MUL dst, src, 2.0 770 // with 771 // FP_ADD dst, src, src 772 // The 'int' and 'long' cases are handled below. 773 block->ReplaceAndRemoveInstructionWith(instruction, 774 new (allocator) HAdd(type, input_other, input_other)); 775 RecordSimplification(); 776 return; 777 } 778 779 if (Primitive::IsIntOrLongType(type)) { 780 int64_t factor = Int64FromConstant(input_cst); 781 // Even though constant propagation also takes care of the zero case, other 782 // optimizations can lead to having a zero multiplication. 783 if (factor == 0) { 784 // Replace code looking like 785 // MUL dst, src, 0 786 // with 787 // 0 788 instruction->ReplaceWith(input_cst); 789 instruction->GetBlock()->RemoveInstruction(instruction); 790 } else if (IsPowerOfTwo(factor)) { 791 // Replace code looking like 792 // MUL dst, src, pow_of_2 793 // with 794 // SHL dst, src, log2(pow_of_2) 795 HIntConstant* shift = GetGraph()->GetIntConstant(WhichPowerOf2(factor)); 796 HShl* shl = new(allocator) HShl(type, input_other, shift); 797 block->ReplaceAndRemoveInstructionWith(instruction, shl); 798 RecordSimplification(); 799 } else if (IsPowerOfTwo(factor - 1)) { 800 // Transform code looking like 801 // MUL dst, src, (2^n + 1) 802 // into 803 // SHL tmp, src, n 804 // ADD dst, src, tmp 805 HShl* shl = new (allocator) HShl(type, 806 input_other, 807 GetGraph()->GetIntConstant(WhichPowerOf2(factor - 1))); 808 HAdd* add = new (allocator) HAdd(type, input_other, shl); 809 810 block->InsertInstructionBefore(shl, instruction); 811 block->ReplaceAndRemoveInstructionWith(instruction, add); 812 RecordSimplification(); 813 } else if (IsPowerOfTwo(factor + 1)) { 814 // Transform code looking like 815 // MUL dst, src, (2^n - 1) 816 // into 817 // SHL tmp, src, n 818 // SUB dst, tmp, src 819 HShl* shl = new (allocator) HShl(type, 820 input_other, 821 GetGraph()->GetIntConstant(WhichPowerOf2(factor + 1))); 822 HSub* sub = new (allocator) HSub(type, shl, input_other); 823 824 block->InsertInstructionBefore(shl, instruction); 825 block->ReplaceAndRemoveInstructionWith(instruction, sub); 826 RecordSimplification(); 827 } 828 } 829} 830 831void InstructionSimplifierVisitor::VisitNeg(HNeg* instruction) { 832 HInstruction* input = instruction->GetInput(); 833 if (input->IsNeg()) { 834 // Replace code looking like 835 // NEG tmp, src 836 // NEG dst, tmp 837 // with 838 // src 839 HNeg* previous_neg = input->AsNeg(); 840 instruction->ReplaceWith(previous_neg->GetInput()); 841 instruction->GetBlock()->RemoveInstruction(instruction); 842 // We perform the optimization even if the input negation has environment 843 // uses since it allows removing the current instruction. But we only delete 844 // the input negation only if it is does not have any uses left. 845 if (!previous_neg->HasUses()) { 846 previous_neg->GetBlock()->RemoveInstruction(previous_neg); 847 } 848 RecordSimplification(); 849 return; 850 } 851 852 if (input->IsSub() && input->HasOnlyOneNonEnvironmentUse() && 853 !Primitive::IsFloatingPointType(input->GetType())) { 854 // Replace code looking like 855 // SUB tmp, a, b 856 // NEG dst, tmp 857 // with 858 // SUB dst, b, a 859 // We do not perform the optimization if the input subtraction has 860 // environment uses or multiple non-environment uses as it could lead to 861 // worse code. In particular, we do not want the live ranges of `a` and `b` 862 // to be extended if we are not sure the initial 'SUB' instruction can be 863 // removed. 864 // We do not perform optimization for fp because we could lose the sign of zero. 865 HSub* sub = input->AsSub(); 866 HSub* new_sub = 867 new (GetGraph()->GetArena()) HSub(instruction->GetType(), sub->GetRight(), sub->GetLeft()); 868 instruction->GetBlock()->ReplaceAndRemoveInstructionWith(instruction, new_sub); 869 if (!sub->HasUses()) { 870 sub->GetBlock()->RemoveInstruction(sub); 871 } 872 RecordSimplification(); 873 } 874} 875 876void InstructionSimplifierVisitor::VisitNot(HNot* instruction) { 877 HInstruction* input = instruction->GetInput(); 878 if (input->IsNot()) { 879 // Replace code looking like 880 // NOT tmp, src 881 // NOT dst, tmp 882 // with 883 // src 884 // We perform the optimization even if the input negation has environment 885 // uses since it allows removing the current instruction. But we only delete 886 // the input negation only if it is does not have any uses left. 887 HNot* previous_not = input->AsNot(); 888 instruction->ReplaceWith(previous_not->GetInput()); 889 instruction->GetBlock()->RemoveInstruction(instruction); 890 if (!previous_not->HasUses()) { 891 previous_not->GetBlock()->RemoveInstruction(previous_not); 892 } 893 RecordSimplification(); 894 } 895} 896 897void InstructionSimplifierVisitor::VisitOr(HOr* instruction) { 898 HConstant* input_cst = instruction->GetConstantRight(); 899 HInstruction* input_other = instruction->GetLeastConstantLeft(); 900 901 if ((input_cst != nullptr) && input_cst->IsZero()) { 902 // Replace code looking like 903 // OR dst, src, 0 904 // with 905 // src 906 instruction->ReplaceWith(input_other); 907 instruction->GetBlock()->RemoveInstruction(instruction); 908 return; 909 } 910 911 // We assume that GVN has run before, so we only perform a pointer comparison. 912 // If for some reason the values are equal but the pointers are different, we 913 // are still correct and only miss an optimization opportunity. 914 if (instruction->GetLeft() == instruction->GetRight()) { 915 // Replace code looking like 916 // OR dst, src, src 917 // with 918 // src 919 instruction->ReplaceWith(instruction->GetLeft()); 920 instruction->GetBlock()->RemoveInstruction(instruction); 921 } 922} 923 924void InstructionSimplifierVisitor::VisitShl(HShl* instruction) { 925 VisitShift(instruction); 926} 927 928void InstructionSimplifierVisitor::VisitShr(HShr* instruction) { 929 VisitShift(instruction); 930} 931 932void InstructionSimplifierVisitor::VisitSub(HSub* instruction) { 933 HConstant* input_cst = instruction->GetConstantRight(); 934 HInstruction* input_other = instruction->GetLeastConstantLeft(); 935 936 Primitive::Type type = instruction->GetType(); 937 if (Primitive::IsFloatingPointType(type)) { 938 return; 939 } 940 941 if ((input_cst != nullptr) && input_cst->IsZero()) { 942 // Replace code looking like 943 // SUB dst, src, 0 944 // with 945 // src 946 // Note that we cannot optimize `x - 0.0` to `x` for floating-point. When 947 // `x` is `-0.0`, the former expression yields `0.0`, while the later 948 // yields `-0.0`. 949 instruction->ReplaceWith(input_other); 950 instruction->GetBlock()->RemoveInstruction(instruction); 951 return; 952 } 953 954 HBasicBlock* block = instruction->GetBlock(); 955 ArenaAllocator* allocator = GetGraph()->GetArena(); 956 957 HInstruction* left = instruction->GetLeft(); 958 HInstruction* right = instruction->GetRight(); 959 if (left->IsConstant()) { 960 if (Int64FromConstant(left->AsConstant()) == 0) { 961 // Replace code looking like 962 // SUB dst, 0, src 963 // with 964 // NEG dst, src 965 // Note that we cannot optimize `0.0 - x` to `-x` for floating-point. When 966 // `x` is `0.0`, the former expression yields `0.0`, while the later 967 // yields `-0.0`. 968 HNeg* neg = new (allocator) HNeg(type, right); 969 block->ReplaceAndRemoveInstructionWith(instruction, neg); 970 RecordSimplification(); 971 return; 972 } 973 } 974 975 if (left->IsNeg() && right->IsNeg()) { 976 if (TryMoveNegOnInputsAfterBinop(instruction)) { 977 return; 978 } 979 } 980 981 if (right->IsNeg() && right->HasOnlyOneNonEnvironmentUse()) { 982 // Replace code looking like 983 // NEG tmp, b 984 // SUB dst, a, tmp 985 // with 986 // ADD dst, a, b 987 HAdd* add = new(GetGraph()->GetArena()) HAdd(type, left, right->AsNeg()->GetInput()); 988 instruction->GetBlock()->ReplaceAndRemoveInstructionWith(instruction, add); 989 RecordSimplification(); 990 right->GetBlock()->RemoveInstruction(right); 991 return; 992 } 993 994 if (left->IsNeg() && left->HasOnlyOneNonEnvironmentUse()) { 995 // Replace code looking like 996 // NEG tmp, a 997 // SUB dst, tmp, b 998 // with 999 // ADD tmp, a, b 1000 // NEG dst, tmp 1001 // The second version is not intrinsically better, but enables more 1002 // transformations. 1003 HAdd* add = new(GetGraph()->GetArena()) HAdd(type, left->AsNeg()->GetInput(), right); 1004 instruction->GetBlock()->InsertInstructionBefore(add, instruction); 1005 HNeg* neg = new (GetGraph()->GetArena()) HNeg(instruction->GetType(), add); 1006 instruction->GetBlock()->InsertInstructionBefore(neg, instruction); 1007 instruction->ReplaceWith(neg); 1008 instruction->GetBlock()->RemoveInstruction(instruction); 1009 RecordSimplification(); 1010 left->GetBlock()->RemoveInstruction(left); 1011 } 1012} 1013 1014void InstructionSimplifierVisitor::VisitUShr(HUShr* instruction) { 1015 VisitShift(instruction); 1016} 1017 1018void InstructionSimplifierVisitor::VisitXor(HXor* instruction) { 1019 HConstant* input_cst = instruction->GetConstantRight(); 1020 HInstruction* input_other = instruction->GetLeastConstantLeft(); 1021 1022 if ((input_cst != nullptr) && input_cst->IsZero()) { 1023 // Replace code looking like 1024 // XOR dst, src, 0 1025 // with 1026 // src 1027 instruction->ReplaceWith(input_other); 1028 instruction->GetBlock()->RemoveInstruction(instruction); 1029 return; 1030 } 1031 1032 if ((input_cst != nullptr) && AreAllBitsSet(input_cst)) { 1033 // Replace code looking like 1034 // XOR dst, src, 0xFFF...FF 1035 // with 1036 // NOT dst, src 1037 HNot* bitwise_not = new (GetGraph()->GetArena()) HNot(instruction->GetType(), input_other); 1038 instruction->GetBlock()->ReplaceAndRemoveInstructionWith(instruction, bitwise_not); 1039 RecordSimplification(); 1040 return; 1041 } 1042} 1043 1044void InstructionSimplifierVisitor::VisitFakeString(HFakeString* instruction) { 1045 HInstruction* actual_string = nullptr; 1046 1047 // Find the string we need to replace this instruction with. The actual string is 1048 // the return value of a StringFactory call. 1049 for (HUseIterator<HInstruction*> it(instruction->GetUses()); !it.Done(); it.Advance()) { 1050 HInstruction* use = it.Current()->GetUser(); 1051 if (use->IsInvokeStaticOrDirect() 1052 && use->AsInvokeStaticOrDirect()->IsStringFactoryFor(instruction)) { 1053 use->AsInvokeStaticOrDirect()->RemoveFakeStringArgumentAsLastInput(); 1054 actual_string = use; 1055 break; 1056 } 1057 } 1058 1059 // Check that there is no other instruction that thinks it is the factory for that string. 1060 if (kIsDebugBuild) { 1061 CHECK(actual_string != nullptr); 1062 for (HUseIterator<HInstruction*> it(instruction->GetUses()); !it.Done(); it.Advance()) { 1063 HInstruction* use = it.Current()->GetUser(); 1064 if (use->IsInvokeStaticOrDirect()) { 1065 CHECK(!use->AsInvokeStaticOrDirect()->IsStringFactoryFor(instruction)); 1066 } 1067 } 1068 } 1069 1070 // We need to remove any environment uses of the fake string that are not dominated by 1071 // `actual_string` to null. 1072 for (HUseIterator<HEnvironment*> it(instruction->GetEnvUses()); !it.Done(); it.Advance()) { 1073 HEnvironment* environment = it.Current()->GetUser(); 1074 if (!actual_string->StrictlyDominates(environment->GetHolder())) { 1075 environment->RemoveAsUserOfInput(it.Current()->GetIndex()); 1076 environment->SetRawEnvAt(it.Current()->GetIndex(), nullptr); 1077 } 1078 } 1079 1080 // Only uses dominated by `actual_string` must remain. We can safely replace and remove 1081 // `instruction`. 1082 instruction->ReplaceWith(actual_string); 1083 instruction->GetBlock()->RemoveInstruction(instruction); 1084} 1085 1086void InstructionSimplifierVisitor::SimplifyStringEquals(HInvoke* instruction) { 1087 HInstruction* argument = instruction->InputAt(1); 1088 HInstruction* receiver = instruction->InputAt(0); 1089 if (receiver == argument) { 1090 // Because String.equals is an instance call, the receiver is 1091 // a null check if we don't know it's null. The argument however, will 1092 // be the actual object. So we cannot end up in a situation where both 1093 // are equal but could be null. 1094 DCHECK(CanEnsureNotNullAt(argument, instruction)); 1095 instruction->ReplaceWith(GetGraph()->GetIntConstant(1)); 1096 instruction->GetBlock()->RemoveInstruction(instruction); 1097 } else { 1098 StringEqualsOptimizations optimizations(instruction); 1099 if (CanEnsureNotNullAt(argument, instruction)) { 1100 optimizations.SetArgumentNotNull(); 1101 } 1102 ScopedObjectAccess soa(Thread::Current()); 1103 ReferenceTypeInfo argument_rti = argument->GetReferenceTypeInfo(); 1104 if (argument_rti.IsValid() && argument_rti.IsStringClass()) { 1105 optimizations.SetArgumentIsString(); 1106 } 1107 } 1108} 1109 1110static bool IsArrayLengthOf(HInstruction* potential_length, HInstruction* potential_array) { 1111 if (potential_length->IsArrayLength()) { 1112 return potential_length->InputAt(0) == potential_array; 1113 } 1114 1115 if (potential_array->IsNewArray()) { 1116 return potential_array->InputAt(0) == potential_length; 1117 } 1118 1119 return false; 1120} 1121 1122void InstructionSimplifierVisitor::SimplifySystemArrayCopy(HInvoke* instruction) { 1123 HInstruction* source = instruction->InputAt(0); 1124 HInstruction* destination = instruction->InputAt(2); 1125 HInstruction* count = instruction->InputAt(4); 1126 SystemArrayCopyOptimizations optimizations(instruction); 1127 if (CanEnsureNotNullAt(source, instruction)) { 1128 optimizations.SetSourceIsNotNull(); 1129 } 1130 if (CanEnsureNotNullAt(destination, instruction)) { 1131 optimizations.SetDestinationIsNotNull(); 1132 } 1133 if (destination == source) { 1134 optimizations.SetDestinationIsSource(); 1135 } 1136 1137 if (IsArrayLengthOf(count, source)) { 1138 optimizations.SetCountIsSourceLength(); 1139 } 1140 1141 if (IsArrayLengthOf(count, destination)) { 1142 optimizations.SetCountIsDestinationLength(); 1143 } 1144 1145 { 1146 ScopedObjectAccess soa(Thread::Current()); 1147 ReferenceTypeInfo destination_rti = destination->GetReferenceTypeInfo(); 1148 if (destination_rti.IsValid()) { 1149 if (destination_rti.IsObjectArray()) { 1150 if (destination_rti.IsExact()) { 1151 optimizations.SetDoesNotNeedTypeCheck(); 1152 } 1153 optimizations.SetDestinationIsTypedObjectArray(); 1154 } 1155 if (destination_rti.IsPrimitiveArrayClass()) { 1156 optimizations.SetDestinationIsPrimitiveArray(); 1157 } else if (destination_rti.IsNonPrimitiveArrayClass()) { 1158 optimizations.SetDestinationIsNonPrimitiveArray(); 1159 } 1160 } 1161 ReferenceTypeInfo source_rti = source->GetReferenceTypeInfo(); 1162 if (source_rti.IsValid()) { 1163 if (destination_rti.IsValid() && destination_rti.CanArrayHoldValuesOf(source_rti)) { 1164 optimizations.SetDoesNotNeedTypeCheck(); 1165 } 1166 if (source_rti.IsPrimitiveArrayClass()) { 1167 optimizations.SetSourceIsPrimitiveArray(); 1168 } else if (source_rti.IsNonPrimitiveArrayClass()) { 1169 optimizations.SetSourceIsNonPrimitiveArray(); 1170 } 1171 } 1172 } 1173} 1174 1175void InstructionSimplifierVisitor::VisitInvoke(HInvoke* instruction) { 1176 if (instruction->GetIntrinsic() == Intrinsics::kStringEquals) { 1177 SimplifyStringEquals(instruction); 1178 } else if (instruction->GetIntrinsic() == Intrinsics::kSystemArrayCopy) { 1179 SimplifySystemArrayCopy(instruction); 1180 } 1181} 1182 1183void InstructionSimplifierVisitor::VisitDeoptimize(HDeoptimize* deoptimize) { 1184 HInstruction* cond = deoptimize->InputAt(0); 1185 if (cond->IsConstant()) { 1186 if (cond->AsIntConstant()->IsZero()) { 1187 // Never deopt: instruction can be removed. 1188 deoptimize->GetBlock()->RemoveInstruction(deoptimize); 1189 } else { 1190 // Always deopt. 1191 } 1192 } 1193} 1194 1195} // namespace art 1196