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