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