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