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 "art_method-inl.h" 20 #include "class_linker-inl.h" 21 #include "data_type-inl.h" 22 #include "escape.h" 23 #include "intrinsics.h" 24 #include "mirror/class-inl.h" 25 #include "scoped_thread_state_change-inl.h" 26 #include "sharpening.h" 27 28 namespace art { 29 30 // Whether to run an exhaustive test of individual HInstructions cloning when each instruction 31 // is replaced with its copy if it is clonable. 32 static constexpr bool kTestInstructionClonerExhaustively = false; 33 34 class InstructionSimplifierVisitor : public HGraphDelegateVisitor { 35 public: 36 InstructionSimplifierVisitor(HGraph* graph, 37 CodeGenerator* codegen, 38 CompilerDriver* compiler_driver, 39 OptimizingCompilerStats* stats) 40 : HGraphDelegateVisitor(graph), 41 codegen_(codegen), 42 compiler_driver_(compiler_driver), 43 stats_(stats) {} 44 45 void Run(); 46 47 private: 48 void RecordSimplification() { 49 simplification_occurred_ = true; 50 simplifications_at_current_position_++; 51 MaybeRecordStat(stats_, MethodCompilationStat::kInstructionSimplifications); 52 } 53 54 bool ReplaceRotateWithRor(HBinaryOperation* op, HUShr* ushr, HShl* shl); 55 bool TryReplaceWithRotate(HBinaryOperation* instruction); 56 bool TryReplaceWithRotateConstantPattern(HBinaryOperation* op, HUShr* ushr, HShl* shl); 57 bool TryReplaceWithRotateRegisterNegPattern(HBinaryOperation* op, HUShr* ushr, HShl* shl); 58 bool TryReplaceWithRotateRegisterSubPattern(HBinaryOperation* op, HUShr* ushr, HShl* shl); 59 60 bool TryMoveNegOnInputsAfterBinop(HBinaryOperation* binop); 61 // `op` should be either HOr or HAnd. 62 // De Morgan's laws: 63 // ~a & ~b = ~(a | b) and ~a | ~b = ~(a & b) 64 bool TryDeMorganNegationFactoring(HBinaryOperation* op); 65 bool TryHandleAssociativeAndCommutativeOperation(HBinaryOperation* instruction); 66 bool TrySubtractionChainSimplification(HBinaryOperation* instruction); 67 bool TryCombineVecMultiplyAccumulate(HVecMul* mul); 68 69 void VisitShift(HBinaryOperation* shift); 70 71 void VisitEqual(HEqual* equal) OVERRIDE; 72 void VisitNotEqual(HNotEqual* equal) OVERRIDE; 73 void VisitBooleanNot(HBooleanNot* bool_not) OVERRIDE; 74 void VisitInstanceFieldSet(HInstanceFieldSet* equal) OVERRIDE; 75 void VisitStaticFieldSet(HStaticFieldSet* equal) OVERRIDE; 76 void VisitArraySet(HArraySet* equal) OVERRIDE; 77 void VisitTypeConversion(HTypeConversion* instruction) OVERRIDE; 78 void VisitNullCheck(HNullCheck* instruction) OVERRIDE; 79 void VisitArrayLength(HArrayLength* instruction) OVERRIDE; 80 void VisitCheckCast(HCheckCast* instruction) OVERRIDE; 81 void VisitAdd(HAdd* instruction) OVERRIDE; 82 void VisitAnd(HAnd* instruction) OVERRIDE; 83 void VisitCondition(HCondition* instruction) OVERRIDE; 84 void VisitGreaterThan(HGreaterThan* condition) OVERRIDE; 85 void VisitGreaterThanOrEqual(HGreaterThanOrEqual* condition) OVERRIDE; 86 void VisitLessThan(HLessThan* condition) OVERRIDE; 87 void VisitLessThanOrEqual(HLessThanOrEqual* condition) OVERRIDE; 88 void VisitBelow(HBelow* condition) OVERRIDE; 89 void VisitBelowOrEqual(HBelowOrEqual* condition) OVERRIDE; 90 void VisitAbove(HAbove* condition) OVERRIDE; 91 void VisitAboveOrEqual(HAboveOrEqual* condition) OVERRIDE; 92 void VisitDiv(HDiv* instruction) OVERRIDE; 93 void VisitMul(HMul* instruction) OVERRIDE; 94 void VisitNeg(HNeg* instruction) OVERRIDE; 95 void VisitNot(HNot* instruction) OVERRIDE; 96 void VisitOr(HOr* instruction) OVERRIDE; 97 void VisitShl(HShl* instruction) OVERRIDE; 98 void VisitShr(HShr* instruction) OVERRIDE; 99 void VisitSub(HSub* instruction) OVERRIDE; 100 void VisitUShr(HUShr* instruction) OVERRIDE; 101 void VisitXor(HXor* instruction) OVERRIDE; 102 void VisitSelect(HSelect* select) OVERRIDE; 103 void VisitIf(HIf* instruction) OVERRIDE; 104 void VisitInstanceOf(HInstanceOf* instruction) OVERRIDE; 105 void VisitInvoke(HInvoke* invoke) OVERRIDE; 106 void VisitDeoptimize(HDeoptimize* deoptimize) OVERRIDE; 107 void VisitVecMul(HVecMul* instruction) OVERRIDE; 108 109 bool CanEnsureNotNullAt(HInstruction* instr, HInstruction* at) const; 110 111 void SimplifyRotate(HInvoke* invoke, bool is_left, DataType::Type type); 112 void SimplifySystemArrayCopy(HInvoke* invoke); 113 void SimplifyStringEquals(HInvoke* invoke); 114 void SimplifyCompare(HInvoke* invoke, bool is_signum, DataType::Type type); 115 void SimplifyIsNaN(HInvoke* invoke); 116 void SimplifyFP2Int(HInvoke* invoke); 117 void SimplifyStringCharAt(HInvoke* invoke); 118 void SimplifyStringIsEmptyOrLength(HInvoke* invoke); 119 void SimplifyNPEOnArgN(HInvoke* invoke, size_t); 120 void SimplifyReturnThis(HInvoke* invoke); 121 void SimplifyAllocationIntrinsic(HInvoke* invoke); 122 void SimplifyMemBarrier(HInvoke* invoke, MemBarrierKind barrier_kind); 123 124 CodeGenerator* codegen_; 125 CompilerDriver* compiler_driver_; 126 OptimizingCompilerStats* stats_; 127 bool simplification_occurred_ = false; 128 int simplifications_at_current_position_ = 0; 129 // We ensure we do not loop infinitely. The value should not be too high, since that 130 // would allow looping around the same basic block too many times. The value should 131 // not be too low either, however, since we want to allow revisiting a basic block 132 // with many statements and simplifications at least once. 133 static constexpr int kMaxSamePositionSimplifications = 50; 134 }; 135 136 void InstructionSimplifier::Run() { 137 if (kTestInstructionClonerExhaustively) { 138 CloneAndReplaceInstructionVisitor visitor(graph_); 139 visitor.VisitReversePostOrder(); 140 } 141 142 InstructionSimplifierVisitor visitor(graph_, codegen_, compiler_driver_, stats_); 143 visitor.Run(); 144 } 145 146 void InstructionSimplifierVisitor::Run() { 147 // Iterate in reverse post order to open up more simplifications to users 148 // of instructions that got simplified. 149 for (HBasicBlock* block : GetGraph()->GetReversePostOrder()) { 150 // The simplification of an instruction to another instruction may yield 151 // possibilities for other simplifications. So although we perform a reverse 152 // post order visit, we sometimes need to revisit an instruction index. 153 do { 154 simplification_occurred_ = false; 155 VisitBasicBlock(block); 156 } while (simplification_occurred_ && 157 (simplifications_at_current_position_ < kMaxSamePositionSimplifications)); 158 simplifications_at_current_position_ = 0; 159 } 160 } 161 162 namespace { 163 164 bool AreAllBitsSet(HConstant* constant) { 165 return Int64FromConstant(constant) == -1; 166 } 167 168 } // namespace 169 170 // Returns true if the code was simplified to use only one negation operation 171 // after the binary operation instead of one on each of the inputs. 172 bool InstructionSimplifierVisitor::TryMoveNegOnInputsAfterBinop(HBinaryOperation* binop) { 173 DCHECK(binop->IsAdd() || binop->IsSub()); 174 DCHECK(binop->GetLeft()->IsNeg() && binop->GetRight()->IsNeg()); 175 HNeg* left_neg = binop->GetLeft()->AsNeg(); 176 HNeg* right_neg = binop->GetRight()->AsNeg(); 177 if (!left_neg->HasOnlyOneNonEnvironmentUse() || 178 !right_neg->HasOnlyOneNonEnvironmentUse()) { 179 return false; 180 } 181 // Replace code looking like 182 // NEG tmp1, a 183 // NEG tmp2, b 184 // ADD dst, tmp1, tmp2 185 // with 186 // ADD tmp, a, b 187 // NEG dst, tmp 188 // Note that we cannot optimize `(-a) + (-b)` to `-(a + b)` for floating-point. 189 // When `a` is `-0.0` and `b` is `0.0`, the former expression yields `0.0`, 190 // while the later yields `-0.0`. 191 if (!DataType::IsIntegralType(binop->GetType())) { 192 return false; 193 } 194 binop->ReplaceInput(left_neg->GetInput(), 0); 195 binop->ReplaceInput(right_neg->GetInput(), 1); 196 left_neg->GetBlock()->RemoveInstruction(left_neg); 197 right_neg->GetBlock()->RemoveInstruction(right_neg); 198 HNeg* neg = new (GetGraph()->GetAllocator()) HNeg(binop->GetType(), binop); 199 binop->GetBlock()->InsertInstructionBefore(neg, binop->GetNext()); 200 binop->ReplaceWithExceptInReplacementAtIndex(neg, 0); 201 RecordSimplification(); 202 return true; 203 } 204 205 bool InstructionSimplifierVisitor::TryDeMorganNegationFactoring(HBinaryOperation* op) { 206 DCHECK(op->IsAnd() || op->IsOr()) << op->DebugName(); 207 DataType::Type type = op->GetType(); 208 HInstruction* left = op->GetLeft(); 209 HInstruction* right = op->GetRight(); 210 211 // We can apply De Morgan's laws if both inputs are Not's and are only used 212 // by `op`. 213 if (((left->IsNot() && right->IsNot()) || 214 (left->IsBooleanNot() && right->IsBooleanNot())) && 215 left->HasOnlyOneNonEnvironmentUse() && 216 right->HasOnlyOneNonEnvironmentUse()) { 217 // Replace code looking like 218 // NOT nota, a 219 // NOT notb, b 220 // AND dst, nota, notb (respectively OR) 221 // with 222 // OR or, a, b (respectively AND) 223 // NOT dest, or 224 HInstruction* src_left = left->InputAt(0); 225 HInstruction* src_right = right->InputAt(0); 226 uint32_t dex_pc = op->GetDexPc(); 227 228 // Remove the negations on the inputs. 229 left->ReplaceWith(src_left); 230 right->ReplaceWith(src_right); 231 left->GetBlock()->RemoveInstruction(left); 232 right->GetBlock()->RemoveInstruction(right); 233 234 // Replace the `HAnd` or `HOr`. 235 HBinaryOperation* hbin; 236 if (op->IsAnd()) { 237 hbin = new (GetGraph()->GetAllocator()) HOr(type, src_left, src_right, dex_pc); 238 } else { 239 hbin = new (GetGraph()->GetAllocator()) HAnd(type, src_left, src_right, dex_pc); 240 } 241 HInstruction* hnot; 242 if (left->IsBooleanNot()) { 243 hnot = new (GetGraph()->GetAllocator()) HBooleanNot(hbin, dex_pc); 244 } else { 245 hnot = new (GetGraph()->GetAllocator()) HNot(type, hbin, dex_pc); 246 } 247 248 op->GetBlock()->InsertInstructionBefore(hbin, op); 249 op->GetBlock()->ReplaceAndRemoveInstructionWith(op, hnot); 250 251 RecordSimplification(); 252 return true; 253 } 254 255 return false; 256 } 257 258 bool InstructionSimplifierVisitor::TryCombineVecMultiplyAccumulate(HVecMul* mul) { 259 DataType::Type type = mul->GetPackedType(); 260 InstructionSet isa = codegen_->GetInstructionSet(); 261 switch (isa) { 262 case InstructionSet::kArm64: 263 if (!(type == DataType::Type::kUint8 || 264 type == DataType::Type::kInt8 || 265 type == DataType::Type::kUint16 || 266 type == DataType::Type::kInt16 || 267 type == DataType::Type::kInt32)) { 268 return false; 269 } 270 break; 271 case InstructionSet::kMips: 272 case InstructionSet::kMips64: 273 if (!(type == DataType::Type::kUint8 || 274 type == DataType::Type::kInt8 || 275 type == DataType::Type::kUint16 || 276 type == DataType::Type::kInt16 || 277 type == DataType::Type::kInt32 || 278 type == DataType::Type::kInt64)) { 279 return false; 280 } 281 break; 282 default: 283 return false; 284 } 285 286 ArenaAllocator* allocator = mul->GetBlock()->GetGraph()->GetAllocator(); 287 288 if (mul->HasOnlyOneNonEnvironmentUse()) { 289 HInstruction* use = mul->GetUses().front().GetUser(); 290 if (use->IsVecAdd() || use->IsVecSub()) { 291 // Replace code looking like 292 // VECMUL tmp, x, y 293 // VECADD/SUB dst, acc, tmp 294 // with 295 // VECMULACC dst, acc, x, y 296 // Note that we do not want to (unconditionally) perform the merge when the 297 // multiplication has multiple uses and it can be merged in all of them. 298 // Multiple uses could happen on the same control-flow path, and we would 299 // then increase the amount of work. In the future we could try to evaluate 300 // whether all uses are on different control-flow paths (using dominance and 301 // reverse-dominance information) and only perform the merge when they are. 302 HInstruction* accumulator = nullptr; 303 HVecBinaryOperation* binop = use->AsVecBinaryOperation(); 304 HInstruction* binop_left = binop->GetLeft(); 305 HInstruction* binop_right = binop->GetRight(); 306 // This is always true since the `HVecMul` has only one use (which is checked above). 307 DCHECK_NE(binop_left, binop_right); 308 if (binop_right == mul) { 309 accumulator = binop_left; 310 } else if (use->IsVecAdd()) { 311 DCHECK_EQ(binop_left, mul); 312 accumulator = binop_right; 313 } 314 315 HInstruction::InstructionKind kind = 316 use->IsVecAdd() ? HInstruction::kAdd : HInstruction::kSub; 317 if (accumulator != nullptr) { 318 HVecMultiplyAccumulate* mulacc = 319 new (allocator) HVecMultiplyAccumulate(allocator, 320 kind, 321 accumulator, 322 mul->GetLeft(), 323 mul->GetRight(), 324 binop->GetPackedType(), 325 binop->GetVectorLength(), 326 binop->GetDexPc()); 327 328 binop->GetBlock()->ReplaceAndRemoveInstructionWith(binop, mulacc); 329 DCHECK(!mul->HasUses()); 330 mul->GetBlock()->RemoveInstruction(mul); 331 return true; 332 } 333 } 334 } 335 336 return false; 337 } 338 339 void InstructionSimplifierVisitor::VisitShift(HBinaryOperation* instruction) { 340 DCHECK(instruction->IsShl() || instruction->IsShr() || instruction->IsUShr()); 341 HInstruction* shift_amount = instruction->GetRight(); 342 HInstruction* value = instruction->GetLeft(); 343 344 int64_t implicit_mask = (value->GetType() == DataType::Type::kInt64) 345 ? kMaxLongShiftDistance 346 : kMaxIntShiftDistance; 347 348 if (shift_amount->IsConstant()) { 349 int64_t cst = Int64FromConstant(shift_amount->AsConstant()); 350 int64_t masked_cst = cst & implicit_mask; 351 if (masked_cst == 0) { 352 // Replace code looking like 353 // SHL dst, value, 0 354 // with 355 // value 356 instruction->ReplaceWith(value); 357 instruction->GetBlock()->RemoveInstruction(instruction); 358 RecordSimplification(); 359 return; 360 } else if (masked_cst != cst) { 361 // Replace code looking like 362 // SHL dst, value, cst 363 // where cst exceeds maximum distance with the equivalent 364 // SHL dst, value, cst & implicit_mask 365 // (as defined by shift semantics). This ensures other 366 // optimizations do not need to special case for such situations. 367 DCHECK_EQ(shift_amount->GetType(), DataType::Type::kInt32); 368 instruction->ReplaceInput(GetGraph()->GetIntConstant(masked_cst), /* index */ 1); 369 RecordSimplification(); 370 return; 371 } 372 } 373 374 // Shift operations implicitly mask the shift amount according to the type width. Get rid of 375 // unnecessary And/Or/Xor/Add/Sub/TypeConversion operations on the shift amount that do not 376 // affect the relevant bits. 377 // Replace code looking like 378 // AND adjusted_shift, shift, <superset of implicit mask> 379 // [OR/XOR/ADD/SUB adjusted_shift, shift, <value not overlapping with implicit mask>] 380 // [<conversion-from-integral-non-64-bit-type> adjusted_shift, shift] 381 // SHL dst, value, adjusted_shift 382 // with 383 // SHL dst, value, shift 384 if (shift_amount->IsAnd() || 385 shift_amount->IsOr() || 386 shift_amount->IsXor() || 387 shift_amount->IsAdd() || 388 shift_amount->IsSub()) { 389 int64_t required_result = shift_amount->IsAnd() ? implicit_mask : 0; 390 HBinaryOperation* bin_op = shift_amount->AsBinaryOperation(); 391 HConstant* mask = bin_op->GetConstantRight(); 392 if (mask != nullptr && (Int64FromConstant(mask) & implicit_mask) == required_result) { 393 instruction->ReplaceInput(bin_op->GetLeastConstantLeft(), 1); 394 RecordSimplification(); 395 return; 396 } 397 } else if (shift_amount->IsTypeConversion()) { 398 DCHECK_NE(shift_amount->GetType(), DataType::Type::kBool); // We never convert to bool. 399 DataType::Type source_type = shift_amount->InputAt(0)->GetType(); 400 // Non-integral and 64-bit source types require an explicit type conversion. 401 if (DataType::IsIntegralType(source_type) && !DataType::Is64BitType(source_type)) { 402 instruction->ReplaceInput(shift_amount->AsTypeConversion()->GetInput(), 1); 403 RecordSimplification(); 404 return; 405 } 406 } 407 } 408 409 static bool IsSubRegBitsMinusOther(HSub* sub, size_t reg_bits, HInstruction* other) { 410 return (sub->GetRight() == other && 411 sub->GetLeft()->IsConstant() && 412 (Int64FromConstant(sub->GetLeft()->AsConstant()) & (reg_bits - 1)) == 0); 413 } 414 415 bool InstructionSimplifierVisitor::ReplaceRotateWithRor(HBinaryOperation* op, 416 HUShr* ushr, 417 HShl* shl) { 418 DCHECK(op->IsAdd() || op->IsXor() || op->IsOr()) << op->DebugName(); 419 HRor* ror = 420 new (GetGraph()->GetAllocator()) HRor(ushr->GetType(), ushr->GetLeft(), ushr->GetRight()); 421 op->GetBlock()->ReplaceAndRemoveInstructionWith(op, ror); 422 if (!ushr->HasUses()) { 423 ushr->GetBlock()->RemoveInstruction(ushr); 424 } 425 if (!ushr->GetRight()->HasUses()) { 426 ushr->GetRight()->GetBlock()->RemoveInstruction(ushr->GetRight()); 427 } 428 if (!shl->HasUses()) { 429 shl->GetBlock()->RemoveInstruction(shl); 430 } 431 if (!shl->GetRight()->HasUses()) { 432 shl->GetRight()->GetBlock()->RemoveInstruction(shl->GetRight()); 433 } 434 RecordSimplification(); 435 return true; 436 } 437 438 // Try to replace a binary operation flanked by one UShr and one Shl with a bitfield rotation. 439 bool InstructionSimplifierVisitor::TryReplaceWithRotate(HBinaryOperation* op) { 440 DCHECK(op->IsAdd() || op->IsXor() || op->IsOr()); 441 HInstruction* left = op->GetLeft(); 442 HInstruction* right = op->GetRight(); 443 // If we have an UShr and a Shl (in either order). 444 if ((left->IsUShr() && right->IsShl()) || (left->IsShl() && right->IsUShr())) { 445 HUShr* ushr = left->IsUShr() ? left->AsUShr() : right->AsUShr(); 446 HShl* shl = left->IsShl() ? left->AsShl() : right->AsShl(); 447 DCHECK(DataType::IsIntOrLongType(ushr->GetType())); 448 if (ushr->GetType() == shl->GetType() && 449 ushr->GetLeft() == shl->GetLeft()) { 450 if (ushr->GetRight()->IsConstant() && shl->GetRight()->IsConstant()) { 451 // Shift distances are both constant, try replacing with Ror if they 452 // add up to the register size. 453 return TryReplaceWithRotateConstantPattern(op, ushr, shl); 454 } else if (ushr->GetRight()->IsSub() || shl->GetRight()->IsSub()) { 455 // Shift distances are potentially of the form x and (reg_size - x). 456 return TryReplaceWithRotateRegisterSubPattern(op, ushr, shl); 457 } else if (ushr->GetRight()->IsNeg() || shl->GetRight()->IsNeg()) { 458 // Shift distances are potentially of the form d and -d. 459 return TryReplaceWithRotateRegisterNegPattern(op, ushr, shl); 460 } 461 } 462 } 463 return false; 464 } 465 466 // Try replacing code looking like (x >>> #rdist OP x << #ldist): 467 // UShr dst, x, #rdist 468 // Shl tmp, x, #ldist 469 // OP dst, dst, tmp 470 // or like (x >>> #rdist OP x << #-ldist): 471 // UShr dst, x, #rdist 472 // Shl tmp, x, #-ldist 473 // OP dst, dst, tmp 474 // with 475 // Ror dst, x, #rdist 476 bool InstructionSimplifierVisitor::TryReplaceWithRotateConstantPattern(HBinaryOperation* op, 477 HUShr* ushr, 478 HShl* shl) { 479 DCHECK(op->IsAdd() || op->IsXor() || op->IsOr()); 480 size_t reg_bits = DataType::Size(ushr->GetType()) * kBitsPerByte; 481 size_t rdist = Int64FromConstant(ushr->GetRight()->AsConstant()); 482 size_t ldist = Int64FromConstant(shl->GetRight()->AsConstant()); 483 if (((ldist + rdist) & (reg_bits - 1)) == 0) { 484 ReplaceRotateWithRor(op, ushr, shl); 485 return true; 486 } 487 return false; 488 } 489 490 // Replace code looking like (x >>> -d OP x << d): 491 // Neg neg, d 492 // UShr dst, x, neg 493 // Shl tmp, x, d 494 // OP dst, dst, tmp 495 // with 496 // Neg neg, d 497 // Ror dst, x, neg 498 // *** OR *** 499 // Replace code looking like (x >>> d OP x << -d): 500 // UShr dst, x, d 501 // Neg neg, d 502 // Shl tmp, x, neg 503 // OP dst, dst, tmp 504 // with 505 // Ror dst, x, d 506 bool InstructionSimplifierVisitor::TryReplaceWithRotateRegisterNegPattern(HBinaryOperation* op, 507 HUShr* ushr, 508 HShl* shl) { 509 DCHECK(op->IsAdd() || op->IsXor() || op->IsOr()); 510 DCHECK(ushr->GetRight()->IsNeg() || shl->GetRight()->IsNeg()); 511 bool neg_is_left = shl->GetRight()->IsNeg(); 512 HNeg* neg = neg_is_left ? shl->GetRight()->AsNeg() : ushr->GetRight()->AsNeg(); 513 // And the shift distance being negated is the distance being shifted the other way. 514 if (neg->InputAt(0) == (neg_is_left ? ushr->GetRight() : shl->GetRight())) { 515 ReplaceRotateWithRor(op, ushr, shl); 516 } 517 return false; 518 } 519 520 // Try replacing code looking like (x >>> d OP x << (#bits - d)): 521 // UShr dst, x, d 522 // Sub ld, #bits, d 523 // Shl tmp, x, ld 524 // OP dst, dst, tmp 525 // with 526 // Ror dst, x, d 527 // *** OR *** 528 // Replace code looking like (x >>> (#bits - d) OP x << d): 529 // Sub rd, #bits, d 530 // UShr dst, x, rd 531 // Shl tmp, x, d 532 // OP dst, dst, tmp 533 // with 534 // Neg neg, d 535 // Ror dst, x, neg 536 bool InstructionSimplifierVisitor::TryReplaceWithRotateRegisterSubPattern(HBinaryOperation* op, 537 HUShr* ushr, 538 HShl* shl) { 539 DCHECK(op->IsAdd() || op->IsXor() || op->IsOr()); 540 DCHECK(ushr->GetRight()->IsSub() || shl->GetRight()->IsSub()); 541 size_t reg_bits = DataType::Size(ushr->GetType()) * kBitsPerByte; 542 HInstruction* shl_shift = shl->GetRight(); 543 HInstruction* ushr_shift = ushr->GetRight(); 544 if ((shl_shift->IsSub() && IsSubRegBitsMinusOther(shl_shift->AsSub(), reg_bits, ushr_shift)) || 545 (ushr_shift->IsSub() && IsSubRegBitsMinusOther(ushr_shift->AsSub(), reg_bits, shl_shift))) { 546 return ReplaceRotateWithRor(op, ushr, shl); 547 } 548 return false; 549 } 550 551 void InstructionSimplifierVisitor::VisitNullCheck(HNullCheck* null_check) { 552 HInstruction* obj = null_check->InputAt(0); 553 if (!obj->CanBeNull()) { 554 null_check->ReplaceWith(obj); 555 null_check->GetBlock()->RemoveInstruction(null_check); 556 if (stats_ != nullptr) { 557 stats_->RecordStat(MethodCompilationStat::kRemovedNullCheck); 558 } 559 } 560 } 561 562 bool InstructionSimplifierVisitor::CanEnsureNotNullAt(HInstruction* input, HInstruction* at) const { 563 if (!input->CanBeNull()) { 564 return true; 565 } 566 567 for (const HUseListNode<HInstruction*>& use : input->GetUses()) { 568 HInstruction* user = use.GetUser(); 569 if (user->IsNullCheck() && user->StrictlyDominates(at)) { 570 return true; 571 } 572 } 573 574 return false; 575 } 576 577 // Returns whether doing a type test between the class of `object` against `klass` has 578 // a statically known outcome. The result of the test is stored in `outcome`. 579 static bool TypeCheckHasKnownOutcome(HLoadClass* klass, HInstruction* object, bool* outcome) { 580 DCHECK(!object->IsNullConstant()) << "Null constants should be special cased"; 581 ReferenceTypeInfo obj_rti = object->GetReferenceTypeInfo(); 582 ScopedObjectAccess soa(Thread::Current()); 583 if (!obj_rti.IsValid()) { 584 // We run the simplifier before the reference type propagation so type info might not be 585 // available. 586 return false; 587 } 588 589 ReferenceTypeInfo class_rti = klass->GetLoadedClassRTI(); 590 if (!class_rti.IsValid()) { 591 // Happens when the loaded class is unresolved. 592 return false; 593 } 594 DCHECK(class_rti.IsExact()); 595 if (class_rti.IsSupertypeOf(obj_rti)) { 596 *outcome = true; 597 return true; 598 } else if (obj_rti.IsExact()) { 599 // The test failed at compile time so will also fail at runtime. 600 *outcome = false; 601 return true; 602 } else if (!class_rti.IsInterface() 603 && !obj_rti.IsInterface() 604 && !obj_rti.IsSupertypeOf(class_rti)) { 605 // Different type hierarchy. The test will fail. 606 *outcome = false; 607 return true; 608 } 609 return false; 610 } 611 612 void InstructionSimplifierVisitor::VisitCheckCast(HCheckCast* check_cast) { 613 HInstruction* object = check_cast->InputAt(0); 614 HLoadClass* load_class = check_cast->InputAt(1)->AsLoadClass(); 615 if (load_class->NeedsAccessCheck()) { 616 // If we need to perform an access check we cannot remove the instruction. 617 return; 618 } 619 620 if (CanEnsureNotNullAt(object, check_cast)) { 621 check_cast->ClearMustDoNullCheck(); 622 } 623 624 if (object->IsNullConstant()) { 625 check_cast->GetBlock()->RemoveInstruction(check_cast); 626 MaybeRecordStat(stats_, MethodCompilationStat::kRemovedCheckedCast); 627 return; 628 } 629 630 // Note: The `outcome` is initialized to please valgrind - the compiler can reorder 631 // the return value check with the `outcome` check, b/27651442 . 632 bool outcome = false; 633 if (TypeCheckHasKnownOutcome(load_class, object, &outcome)) { 634 if (outcome) { 635 check_cast->GetBlock()->RemoveInstruction(check_cast); 636 MaybeRecordStat(stats_, MethodCompilationStat::kRemovedCheckedCast); 637 if (!load_class->HasUses()) { 638 // We cannot rely on DCE to remove the class because the `HLoadClass` thinks it can throw. 639 // However, here we know that it cannot because the checkcast was successfull, hence 640 // the class was already loaded. 641 load_class->GetBlock()->RemoveInstruction(load_class); 642 } 643 } else { 644 // Don't do anything for exceptional cases for now. Ideally we should remove 645 // all instructions and blocks this instruction dominates. 646 } 647 } 648 } 649 650 void InstructionSimplifierVisitor::VisitInstanceOf(HInstanceOf* instruction) { 651 HInstruction* object = instruction->InputAt(0); 652 HLoadClass* load_class = instruction->InputAt(1)->AsLoadClass(); 653 if (load_class->NeedsAccessCheck()) { 654 // If we need to perform an access check we cannot remove the instruction. 655 return; 656 } 657 658 bool can_be_null = true; 659 if (CanEnsureNotNullAt(object, instruction)) { 660 can_be_null = false; 661 instruction->ClearMustDoNullCheck(); 662 } 663 664 HGraph* graph = GetGraph(); 665 if (object->IsNullConstant()) { 666 MaybeRecordStat(stats_, MethodCompilationStat::kRemovedInstanceOf); 667 instruction->ReplaceWith(graph->GetIntConstant(0)); 668 instruction->GetBlock()->RemoveInstruction(instruction); 669 RecordSimplification(); 670 return; 671 } 672 673 // Note: The `outcome` is initialized to please valgrind - the compiler can reorder 674 // the return value check with the `outcome` check, b/27651442 . 675 bool outcome = false; 676 if (TypeCheckHasKnownOutcome(load_class, object, &outcome)) { 677 MaybeRecordStat(stats_, MethodCompilationStat::kRemovedInstanceOf); 678 if (outcome && can_be_null) { 679 // Type test will succeed, we just need a null test. 680 HNotEqual* test = new (graph->GetAllocator()) HNotEqual(graph->GetNullConstant(), object); 681 instruction->GetBlock()->InsertInstructionBefore(test, instruction); 682 instruction->ReplaceWith(test); 683 } else { 684 // We've statically determined the result of the instanceof. 685 instruction->ReplaceWith(graph->GetIntConstant(outcome)); 686 } 687 RecordSimplification(); 688 instruction->GetBlock()->RemoveInstruction(instruction); 689 if (outcome && !load_class->HasUses()) { 690 // We cannot rely on DCE to remove the class because the `HLoadClass` thinks it can throw. 691 // However, here we know that it cannot because the instanceof check was successfull, hence 692 // the class was already loaded. 693 load_class->GetBlock()->RemoveInstruction(load_class); 694 } 695 } 696 } 697 698 void InstructionSimplifierVisitor::VisitInstanceFieldSet(HInstanceFieldSet* instruction) { 699 if ((instruction->GetValue()->GetType() == DataType::Type::kReference) 700 && CanEnsureNotNullAt(instruction->GetValue(), instruction)) { 701 instruction->ClearValueCanBeNull(); 702 } 703 } 704 705 void InstructionSimplifierVisitor::VisitStaticFieldSet(HStaticFieldSet* instruction) { 706 if ((instruction->GetValue()->GetType() == DataType::Type::kReference) 707 && CanEnsureNotNullAt(instruction->GetValue(), instruction)) { 708 instruction->ClearValueCanBeNull(); 709 } 710 } 711 712 static HCondition* GetOppositeConditionSwapOps(ArenaAllocator* allocator, HInstruction* cond) { 713 HInstruction *lhs = cond->InputAt(0); 714 HInstruction *rhs = cond->InputAt(1); 715 switch (cond->GetKind()) { 716 case HInstruction::kEqual: 717 return new (allocator) HEqual(rhs, lhs); 718 case HInstruction::kNotEqual: 719 return new (allocator) HNotEqual(rhs, lhs); 720 case HInstruction::kLessThan: 721 return new (allocator) HGreaterThan(rhs, lhs); 722 case HInstruction::kLessThanOrEqual: 723 return new (allocator) HGreaterThanOrEqual(rhs, lhs); 724 case HInstruction::kGreaterThan: 725 return new (allocator) HLessThan(rhs, lhs); 726 case HInstruction::kGreaterThanOrEqual: 727 return new (allocator) HLessThanOrEqual(rhs, lhs); 728 case HInstruction::kBelow: 729 return new (allocator) HAbove(rhs, lhs); 730 case HInstruction::kBelowOrEqual: 731 return new (allocator) HAboveOrEqual(rhs, lhs); 732 case HInstruction::kAbove: 733 return new (allocator) HBelow(rhs, lhs); 734 case HInstruction::kAboveOrEqual: 735 return new (allocator) HBelowOrEqual(rhs, lhs); 736 default: 737 LOG(FATAL) << "Unknown ConditionType " << cond->GetKind(); 738 } 739 return nullptr; 740 } 741 742 static bool CmpHasBoolType(HInstruction* input, HInstruction* cmp) { 743 if (input->GetType() == DataType::Type::kBool) { 744 return true; // input has direct boolean type 745 } else if (cmp->GetUses().HasExactlyOneElement()) { 746 // Comparison also has boolean type if both its input and the instruction 747 // itself feed into the same phi node. 748 HInstruction* user = cmp->GetUses().front().GetUser(); 749 return user->IsPhi() && user->HasInput(input) && user->HasInput(cmp); 750 } 751 return false; 752 } 753 754 void InstructionSimplifierVisitor::VisitEqual(HEqual* equal) { 755 HInstruction* input_const = equal->GetConstantRight(); 756 if (input_const != nullptr) { 757 HInstruction* input_value = equal->GetLeastConstantLeft(); 758 if (CmpHasBoolType(input_value, equal) && input_const->IsIntConstant()) { 759 HBasicBlock* block = equal->GetBlock(); 760 // We are comparing the boolean to a constant which is of type int and can 761 // be any constant. 762 if (input_const->AsIntConstant()->IsTrue()) { 763 // Replace (bool_value == true) with bool_value 764 equal->ReplaceWith(input_value); 765 block->RemoveInstruction(equal); 766 RecordSimplification(); 767 } else if (input_const->AsIntConstant()->IsFalse()) { 768 // Replace (bool_value == false) with !bool_value 769 equal->ReplaceWith(GetGraph()->InsertOppositeCondition(input_value, equal)); 770 block->RemoveInstruction(equal); 771 RecordSimplification(); 772 } else { 773 // Replace (bool_value == integer_not_zero_nor_one_constant) with false 774 equal->ReplaceWith(GetGraph()->GetIntConstant(0)); 775 block->RemoveInstruction(equal); 776 RecordSimplification(); 777 } 778 } else { 779 VisitCondition(equal); 780 } 781 } else { 782 VisitCondition(equal); 783 } 784 } 785 786 void InstructionSimplifierVisitor::VisitNotEqual(HNotEqual* not_equal) { 787 HInstruction* input_const = not_equal->GetConstantRight(); 788 if (input_const != nullptr) { 789 HInstruction* input_value = not_equal->GetLeastConstantLeft(); 790 if (CmpHasBoolType(input_value, not_equal) && input_const->IsIntConstant()) { 791 HBasicBlock* block = not_equal->GetBlock(); 792 // We are comparing the boolean to a constant which is of type int and can 793 // be any constant. 794 if (input_const->AsIntConstant()->IsTrue()) { 795 // Replace (bool_value != true) with !bool_value 796 not_equal->ReplaceWith(GetGraph()->InsertOppositeCondition(input_value, not_equal)); 797 block->RemoveInstruction(not_equal); 798 RecordSimplification(); 799 } else if (input_const->AsIntConstant()->IsFalse()) { 800 // Replace (bool_value != false) with bool_value 801 not_equal->ReplaceWith(input_value); 802 block->RemoveInstruction(not_equal); 803 RecordSimplification(); 804 } else { 805 // Replace (bool_value != integer_not_zero_nor_one_constant) with true 806 not_equal->ReplaceWith(GetGraph()->GetIntConstant(1)); 807 block->RemoveInstruction(not_equal); 808 RecordSimplification(); 809 } 810 } else { 811 VisitCondition(not_equal); 812 } 813 } else { 814 VisitCondition(not_equal); 815 } 816 } 817 818 void InstructionSimplifierVisitor::VisitBooleanNot(HBooleanNot* bool_not) { 819 HInstruction* input = bool_not->InputAt(0); 820 HInstruction* replace_with = nullptr; 821 822 if (input->IsIntConstant()) { 823 // Replace !(true/false) with false/true. 824 if (input->AsIntConstant()->IsTrue()) { 825 replace_with = GetGraph()->GetIntConstant(0); 826 } else { 827 DCHECK(input->AsIntConstant()->IsFalse()) << input->AsIntConstant()->GetValue(); 828 replace_with = GetGraph()->GetIntConstant(1); 829 } 830 } else if (input->IsBooleanNot()) { 831 // Replace (!(!bool_value)) with bool_value. 832 replace_with = input->InputAt(0); 833 } else if (input->IsCondition() && 834 // Don't change FP compares. The definition of compares involving 835 // NaNs forces the compares to be done as written by the user. 836 !DataType::IsFloatingPointType(input->InputAt(0)->GetType())) { 837 // Replace condition with its opposite. 838 replace_with = GetGraph()->InsertOppositeCondition(input->AsCondition(), bool_not); 839 } 840 841 if (replace_with != nullptr) { 842 bool_not->ReplaceWith(replace_with); 843 bool_not->GetBlock()->RemoveInstruction(bool_not); 844 RecordSimplification(); 845 } 846 } 847 848 // Constructs a new ABS(x) node in the HIR. 849 static HInstruction* NewIntegralAbs(ArenaAllocator* allocator, 850 HInstruction* x, 851 HInstruction* cursor) { 852 DataType::Type type = x->GetType(); 853 DCHECK(type == DataType::Type::kInt32 || type == DataType::Type::kInt64); 854 // Construct a fake intrinsic with as much context as is needed to allocate one. 855 // The intrinsic will always be lowered into code later anyway. 856 // TODO: b/65164101 : moving towards a real HAbs node makes more sense. 857 HInvokeStaticOrDirect::DispatchInfo dispatch_info = { 858 HInvokeStaticOrDirect::MethodLoadKind::kDirectAddress, 859 HInvokeStaticOrDirect::CodePtrLocation::kCallArtMethod, 860 0u 861 }; 862 HInvokeStaticOrDirect* invoke = new (allocator) HInvokeStaticOrDirect( 863 allocator, 864 1, 865 type, 866 x->GetDexPc(), 867 /*method_idx*/ -1, 868 /*resolved_method*/ nullptr, 869 dispatch_info, 870 kStatic, 871 MethodReference(nullptr, dex::kDexNoIndex), 872 HInvokeStaticOrDirect::ClinitCheckRequirement::kNone); 873 invoke->SetArgumentAt(0, x); 874 invoke->SetIntrinsic(type == DataType::Type::kInt32 ? Intrinsics::kMathAbsInt 875 : Intrinsics::kMathAbsLong, 876 kNoEnvironmentOrCache, 877 kNoSideEffects, 878 kNoThrow); 879 cursor->GetBlock()->InsertInstructionBefore(invoke, cursor); 880 return invoke; 881 } 882 883 // Returns true if operands a and b consists of widening type conversions 884 // (either explicit or implicit) to the given to_type. 885 static bool AreLowerPrecisionArgs(DataType::Type to_type, HInstruction* a, HInstruction* b) { 886 if (a->IsTypeConversion() && a->GetType() == to_type) { 887 a = a->InputAt(0); 888 } 889 if (b->IsTypeConversion() && b->GetType() == to_type) { 890 b = b->InputAt(0); 891 } 892 DataType::Type type1 = a->GetType(); 893 DataType::Type type2 = b->GetType(); 894 return (type1 == DataType::Type::kUint8 && type2 == DataType::Type::kUint8) || 895 (type1 == DataType::Type::kInt8 && type2 == DataType::Type::kInt8) || 896 (type1 == DataType::Type::kInt16 && type2 == DataType::Type::kInt16) || 897 (type1 == DataType::Type::kUint16 && type2 == DataType::Type::kUint16) || 898 (type1 == DataType::Type::kInt32 && type2 == DataType::Type::kInt32 && 899 to_type == DataType::Type::kInt64); 900 } 901 902 void InstructionSimplifierVisitor::VisitSelect(HSelect* select) { 903 HInstruction* replace_with = nullptr; 904 HInstruction* condition = select->GetCondition(); 905 HInstruction* true_value = select->GetTrueValue(); 906 HInstruction* false_value = select->GetFalseValue(); 907 908 if (condition->IsBooleanNot()) { 909 // Change ((!cond) ? x : y) to (cond ? y : x). 910 condition = condition->InputAt(0); 911 std::swap(true_value, false_value); 912 select->ReplaceInput(false_value, 0); 913 select->ReplaceInput(true_value, 1); 914 select->ReplaceInput(condition, 2); 915 RecordSimplification(); 916 } 917 918 if (true_value == false_value) { 919 // Replace (cond ? x : x) with (x). 920 replace_with = true_value; 921 } else if (condition->IsIntConstant()) { 922 if (condition->AsIntConstant()->IsTrue()) { 923 // Replace (true ? x : y) with (x). 924 replace_with = true_value; 925 } else { 926 // Replace (false ? x : y) with (y). 927 DCHECK(condition->AsIntConstant()->IsFalse()) << condition->AsIntConstant()->GetValue(); 928 replace_with = false_value; 929 } 930 } else if (true_value->IsIntConstant() && false_value->IsIntConstant()) { 931 if (true_value->AsIntConstant()->IsTrue() && false_value->AsIntConstant()->IsFalse()) { 932 // Replace (cond ? true : false) with (cond). 933 replace_with = condition; 934 } else if (true_value->AsIntConstant()->IsFalse() && false_value->AsIntConstant()->IsTrue()) { 935 // Replace (cond ? false : true) with (!cond). 936 replace_with = GetGraph()->InsertOppositeCondition(condition, select); 937 } 938 } else if (condition->IsCondition()) { 939 IfCondition cmp = condition->AsCondition()->GetCondition(); 940 HInstruction* a = condition->InputAt(0); 941 HInstruction* b = condition->InputAt(1); 942 DataType::Type t_type = true_value->GetType(); 943 DataType::Type f_type = false_value->GetType(); 944 // Here we have a <cmp> b ? true_value : false_value. 945 // Test if both values are same-typed int or long. 946 if (t_type == f_type && 947 (t_type == DataType::Type::kInt32 || t_type == DataType::Type::kInt64)) { 948 // Try to replace typical integral ABS constructs. 949 if (true_value->IsNeg()) { 950 HInstruction* negated = true_value->InputAt(0); 951 if ((cmp == kCondLT || cmp == kCondLE) && 952 (a == negated && a == false_value && IsInt64Value(b, 0))) { 953 // Found a < 0 ? -a : a which can be replaced by ABS(a). 954 replace_with = NewIntegralAbs(GetGraph()->GetAllocator(), false_value, select); 955 } 956 } else if (false_value->IsNeg()) { 957 HInstruction* negated = false_value->InputAt(0); 958 if ((cmp == kCondGT || cmp == kCondGE) && 959 (a == true_value && a == negated && IsInt64Value(b, 0))) { 960 // Found a > 0 ? a : -a which can be replaced by ABS(a). 961 replace_with = NewIntegralAbs(GetGraph()->GetAllocator(), true_value, select); 962 } 963 } else if (true_value->IsSub() && false_value->IsSub()) { 964 HInstruction* true_sub1 = true_value->InputAt(0); 965 HInstruction* true_sub2 = true_value->InputAt(1); 966 HInstruction* false_sub1 = false_value->InputAt(0); 967 HInstruction* false_sub2 = false_value->InputAt(1); 968 if ((((cmp == kCondGT || cmp == kCondGE) && 969 (a == true_sub1 && b == true_sub2 && a == false_sub2 && b == false_sub1)) || 970 ((cmp == kCondLT || cmp == kCondLE) && 971 (a == true_sub2 && b == true_sub1 && a == false_sub1 && b == false_sub2))) && 972 AreLowerPrecisionArgs(t_type, a, b)) { 973 // Found a > b ? a - b : b - a or 974 // a < b ? b - a : a - b 975 // which can be replaced by ABS(a - b) for lower precision operands a, b. 976 replace_with = NewIntegralAbs(GetGraph()->GetAllocator(), true_value, select); 977 } 978 } 979 } 980 } 981 982 if (replace_with != nullptr) { 983 select->ReplaceWith(replace_with); 984 select->GetBlock()->RemoveInstruction(select); 985 RecordSimplification(); 986 } 987 } 988 989 void InstructionSimplifierVisitor::VisitIf(HIf* instruction) { 990 HInstruction* condition = instruction->InputAt(0); 991 if (condition->IsBooleanNot()) { 992 // Swap successors if input is negated. 993 instruction->ReplaceInput(condition->InputAt(0), 0); 994 instruction->GetBlock()->SwapSuccessors(); 995 RecordSimplification(); 996 } 997 } 998 999 void InstructionSimplifierVisitor::VisitArrayLength(HArrayLength* instruction) { 1000 HInstruction* input = instruction->InputAt(0); 1001 // If the array is a NewArray with constant size, replace the array length 1002 // with the constant instruction. This helps the bounds check elimination phase. 1003 if (input->IsNewArray()) { 1004 input = input->AsNewArray()->GetLength(); 1005 if (input->IsIntConstant()) { 1006 instruction->ReplaceWith(input); 1007 } 1008 } 1009 } 1010 1011 void InstructionSimplifierVisitor::VisitArraySet(HArraySet* instruction) { 1012 HInstruction* value = instruction->GetValue(); 1013 if (value->GetType() != DataType::Type::kReference) { 1014 return; 1015 } 1016 1017 if (CanEnsureNotNullAt(value, instruction)) { 1018 instruction->ClearValueCanBeNull(); 1019 } 1020 1021 if (value->IsArrayGet()) { 1022 if (value->AsArrayGet()->GetArray() == instruction->GetArray()) { 1023 // If the code is just swapping elements in the array, no need for a type check. 1024 instruction->ClearNeedsTypeCheck(); 1025 return; 1026 } 1027 } 1028 1029 if (value->IsNullConstant()) { 1030 instruction->ClearNeedsTypeCheck(); 1031 return; 1032 } 1033 1034 ScopedObjectAccess soa(Thread::Current()); 1035 ReferenceTypeInfo array_rti = instruction->GetArray()->GetReferenceTypeInfo(); 1036 ReferenceTypeInfo value_rti = value->GetReferenceTypeInfo(); 1037 if (!array_rti.IsValid()) { 1038 return; 1039 } 1040 1041 if (value_rti.IsValid() && array_rti.CanArrayHold(value_rti)) { 1042 instruction->ClearNeedsTypeCheck(); 1043 return; 1044 } 1045 1046 if (array_rti.IsObjectArray()) { 1047 if (array_rti.IsExact()) { 1048 instruction->ClearNeedsTypeCheck(); 1049 return; 1050 } 1051 instruction->SetStaticTypeOfArrayIsObjectArray(); 1052 } 1053 } 1054 1055 static bool IsTypeConversionLossless(DataType::Type input_type, DataType::Type result_type) { 1056 // Make sure all implicit conversions have been simplified and no new ones have been introduced. 1057 DCHECK(!DataType::IsTypeConversionImplicit(input_type, result_type)) 1058 << input_type << "," << result_type; 1059 // The conversion to a larger type is loss-less with the exception of two cases, 1060 // - conversion to the unsigned type Uint16, where we may lose some bits, and 1061 // - conversion from float to long, the only FP to integral conversion with smaller FP type. 1062 // For integral to FP conversions this holds because the FP mantissa is large enough. 1063 // Note: The size check excludes Uint8 as the result type. 1064 return DataType::Size(result_type) > DataType::Size(input_type) && 1065 result_type != DataType::Type::kUint16 && 1066 !(result_type == DataType::Type::kInt64 && input_type == DataType::Type::kFloat32); 1067 } 1068 1069 static inline bool TryReplaceFieldOrArrayGetType(HInstruction* maybe_get, DataType::Type new_type) { 1070 if (maybe_get->IsInstanceFieldGet()) { 1071 maybe_get->AsInstanceFieldGet()->SetType(new_type); 1072 return true; 1073 } else if (maybe_get->IsStaticFieldGet()) { 1074 maybe_get->AsStaticFieldGet()->SetType(new_type); 1075 return true; 1076 } else if (maybe_get->IsArrayGet() && !maybe_get->AsArrayGet()->IsStringCharAt()) { 1077 maybe_get->AsArrayGet()->SetType(new_type); 1078 return true; 1079 } else { 1080 return false; 1081 } 1082 } 1083 1084 // The type conversion is only used for storing into a field/element of the 1085 // same/narrower size. 1086 static bool IsTypeConversionForStoringIntoNoWiderFieldOnly(HTypeConversion* type_conversion) { 1087 if (type_conversion->HasEnvironmentUses()) { 1088 return false; 1089 } 1090 DataType::Type input_type = type_conversion->GetInputType(); 1091 DataType::Type result_type = type_conversion->GetResultType(); 1092 if (!DataType::IsIntegralType(input_type) || 1093 !DataType::IsIntegralType(result_type) || 1094 input_type == DataType::Type::kInt64 || 1095 result_type == DataType::Type::kInt64) { 1096 // Type conversion is needed if non-integer types are involved, or 64-bit 1097 // types are involved, which may use different number of registers. 1098 return false; 1099 } 1100 if (DataType::Size(input_type) >= DataType::Size(result_type)) { 1101 // Type conversion is not necessary when storing to a field/element of the 1102 // same/smaller size. 1103 } else { 1104 // We do not handle this case here. 1105 return false; 1106 } 1107 1108 // Check if the converted value is only used for storing into heap. 1109 for (const HUseListNode<HInstruction*>& use : type_conversion->GetUses()) { 1110 HInstruction* instruction = use.GetUser(); 1111 if (instruction->IsInstanceFieldSet() && 1112 instruction->AsInstanceFieldSet()->GetFieldType() == result_type) { 1113 DCHECK_EQ(instruction->AsInstanceFieldSet()->GetValue(), type_conversion); 1114 continue; 1115 } 1116 if (instruction->IsStaticFieldSet() && 1117 instruction->AsStaticFieldSet()->GetFieldType() == result_type) { 1118 DCHECK_EQ(instruction->AsStaticFieldSet()->GetValue(), type_conversion); 1119 continue; 1120 } 1121 if (instruction->IsArraySet() && 1122 instruction->AsArraySet()->GetComponentType() == result_type && 1123 // not index use. 1124 instruction->AsArraySet()->GetIndex() != type_conversion) { 1125 DCHECK_EQ(instruction->AsArraySet()->GetValue(), type_conversion); 1126 continue; 1127 } 1128 // The use is not as a store value, or the field/element type is not the 1129 // same as the result_type, keep the type conversion. 1130 return false; 1131 } 1132 // Codegen automatically handles the type conversion during the store. 1133 return true; 1134 } 1135 1136 void InstructionSimplifierVisitor::VisitTypeConversion(HTypeConversion* instruction) { 1137 HInstruction* input = instruction->GetInput(); 1138 DataType::Type input_type = input->GetType(); 1139 DataType::Type result_type = instruction->GetResultType(); 1140 if (DataType::IsTypeConversionImplicit(input_type, result_type)) { 1141 // Remove the implicit conversion; this includes conversion to the same type. 1142 instruction->ReplaceWith(input); 1143 instruction->GetBlock()->RemoveInstruction(instruction); 1144 RecordSimplification(); 1145 return; 1146 } 1147 1148 if (input->IsTypeConversion()) { 1149 HTypeConversion* input_conversion = input->AsTypeConversion(); 1150 HInstruction* original_input = input_conversion->GetInput(); 1151 DataType::Type original_type = original_input->GetType(); 1152 1153 // When the first conversion is lossless, a direct conversion from the original type 1154 // to the final type yields the same result, even for a lossy second conversion, for 1155 // example float->double->int or int->double->float. 1156 bool is_first_conversion_lossless = IsTypeConversionLossless(original_type, input_type); 1157 1158 // For integral conversions, see if the first conversion loses only bits that the second 1159 // doesn't need, i.e. the final type is no wider than the intermediate. If so, direct 1160 // conversion yields the same result, for example long->int->short or int->char->short. 1161 bool integral_conversions_with_non_widening_second = 1162 DataType::IsIntegralType(input_type) && 1163 DataType::IsIntegralType(original_type) && 1164 DataType::IsIntegralType(result_type) && 1165 DataType::Size(result_type) <= DataType::Size(input_type); 1166 1167 if (is_first_conversion_lossless || integral_conversions_with_non_widening_second) { 1168 // If the merged conversion is implicit, do the simplification unconditionally. 1169 if (DataType::IsTypeConversionImplicit(original_type, result_type)) { 1170 instruction->ReplaceWith(original_input); 1171 instruction->GetBlock()->RemoveInstruction(instruction); 1172 if (!input_conversion->HasUses()) { 1173 // Don't wait for DCE. 1174 input_conversion->GetBlock()->RemoveInstruction(input_conversion); 1175 } 1176 RecordSimplification(); 1177 return; 1178 } 1179 // Otherwise simplify only if the first conversion has no other use. 1180 if (input_conversion->HasOnlyOneNonEnvironmentUse()) { 1181 input_conversion->ReplaceWith(original_input); 1182 input_conversion->GetBlock()->RemoveInstruction(input_conversion); 1183 RecordSimplification(); 1184 return; 1185 } 1186 } 1187 } else if (input->IsAnd() && DataType::IsIntegralType(result_type)) { 1188 DCHECK(DataType::IsIntegralType(input_type)); 1189 HAnd* input_and = input->AsAnd(); 1190 HConstant* constant = input_and->GetConstantRight(); 1191 if (constant != nullptr) { 1192 int64_t value = Int64FromConstant(constant); 1193 DCHECK_NE(value, -1); // "& -1" would have been optimized away in VisitAnd(). 1194 size_t trailing_ones = CTZ(~static_cast<uint64_t>(value)); 1195 if (trailing_ones >= kBitsPerByte * DataType::Size(result_type)) { 1196 // The `HAnd` is useless, for example in `(byte) (x & 0xff)`, get rid of it. 1197 HInstruction* original_input = input_and->GetLeastConstantLeft(); 1198 if (DataType::IsTypeConversionImplicit(original_input->GetType(), result_type)) { 1199 instruction->ReplaceWith(original_input); 1200 instruction->GetBlock()->RemoveInstruction(instruction); 1201 RecordSimplification(); 1202 return; 1203 } else if (input->HasOnlyOneNonEnvironmentUse()) { 1204 input_and->ReplaceWith(original_input); 1205 input_and->GetBlock()->RemoveInstruction(input_and); 1206 RecordSimplification(); 1207 return; 1208 } 1209 } 1210 } 1211 } else if (input->HasOnlyOneNonEnvironmentUse() && 1212 ((input_type == DataType::Type::kInt8 && result_type == DataType::Type::kUint8) || 1213 (input_type == DataType::Type::kUint8 && result_type == DataType::Type::kInt8) || 1214 (input_type == DataType::Type::kInt16 && result_type == DataType::Type::kUint16) || 1215 (input_type == DataType::Type::kUint16 && result_type == DataType::Type::kInt16))) { 1216 // Try to modify the type of the load to `result_type` and remove the explicit type conversion. 1217 if (TryReplaceFieldOrArrayGetType(input, result_type)) { 1218 instruction->ReplaceWith(input); 1219 instruction->GetBlock()->RemoveInstruction(instruction); 1220 RecordSimplification(); 1221 return; 1222 } 1223 } 1224 1225 if (IsTypeConversionForStoringIntoNoWiderFieldOnly(instruction)) { 1226 instruction->ReplaceWith(input); 1227 instruction->GetBlock()->RemoveInstruction(instruction); 1228 RecordSimplification(); 1229 return; 1230 } 1231 } 1232 1233 void InstructionSimplifierVisitor::VisitAdd(HAdd* instruction) { 1234 HConstant* input_cst = instruction->GetConstantRight(); 1235 HInstruction* input_other = instruction->GetLeastConstantLeft(); 1236 bool integral_type = DataType::IsIntegralType(instruction->GetType()); 1237 if ((input_cst != nullptr) && input_cst->IsArithmeticZero()) { 1238 // Replace code looking like 1239 // ADD dst, src, 0 1240 // with 1241 // src 1242 // Note that we cannot optimize `x + 0.0` to `x` for floating-point. When 1243 // `x` is `-0.0`, the former expression yields `0.0`, while the later 1244 // yields `-0.0`. 1245 if (integral_type) { 1246 instruction->ReplaceWith(input_other); 1247 instruction->GetBlock()->RemoveInstruction(instruction); 1248 RecordSimplification(); 1249 return; 1250 } 1251 } 1252 1253 HInstruction* left = instruction->GetLeft(); 1254 HInstruction* right = instruction->GetRight(); 1255 bool left_is_neg = left->IsNeg(); 1256 bool right_is_neg = right->IsNeg(); 1257 1258 if (left_is_neg && right_is_neg) { 1259 if (TryMoveNegOnInputsAfterBinop(instruction)) { 1260 return; 1261 } 1262 } 1263 1264 HNeg* neg = left_is_neg ? left->AsNeg() : right->AsNeg(); 1265 if ((left_is_neg ^ right_is_neg) && neg->HasOnlyOneNonEnvironmentUse()) { 1266 // Replace code looking like 1267 // NEG tmp, b 1268 // ADD dst, a, tmp 1269 // with 1270 // SUB dst, a, b 1271 // We do not perform the optimization if the input negation has environment 1272 // uses or multiple non-environment uses as it could lead to worse code. In 1273 // particular, we do not want the live range of `b` to be extended if we are 1274 // not sure the initial 'NEG' instruction can be removed. 1275 HInstruction* other = left_is_neg ? right : left; 1276 HSub* sub = 1277 new(GetGraph()->GetAllocator()) HSub(instruction->GetType(), other, neg->GetInput()); 1278 instruction->GetBlock()->ReplaceAndRemoveInstructionWith(instruction, sub); 1279 RecordSimplification(); 1280 neg->GetBlock()->RemoveInstruction(neg); 1281 return; 1282 } 1283 1284 if (TryReplaceWithRotate(instruction)) { 1285 return; 1286 } 1287 1288 // TryHandleAssociativeAndCommutativeOperation() does not remove its input, 1289 // so no need to return. 1290 TryHandleAssociativeAndCommutativeOperation(instruction); 1291 1292 if ((left->IsSub() || right->IsSub()) && 1293 TrySubtractionChainSimplification(instruction)) { 1294 return; 1295 } 1296 1297 if (integral_type) { 1298 // Replace code patterns looking like 1299 // SUB dst1, x, y SUB dst1, x, y 1300 // ADD dst2, dst1, y ADD dst2, y, dst1 1301 // with 1302 // SUB dst1, x, y 1303 // ADD instruction is not needed in this case, we may use 1304 // one of inputs of SUB instead. 1305 if (left->IsSub() && left->InputAt(1) == right) { 1306 instruction->ReplaceWith(left->InputAt(0)); 1307 RecordSimplification(); 1308 instruction->GetBlock()->RemoveInstruction(instruction); 1309 return; 1310 } else if (right->IsSub() && right->InputAt(1) == left) { 1311 instruction->ReplaceWith(right->InputAt(0)); 1312 RecordSimplification(); 1313 instruction->GetBlock()->RemoveInstruction(instruction); 1314 return; 1315 } 1316 } 1317 } 1318 1319 void InstructionSimplifierVisitor::VisitAnd(HAnd* instruction) { 1320 DCHECK(DataType::IsIntegralType(instruction->GetType())); 1321 HConstant* input_cst = instruction->GetConstantRight(); 1322 HInstruction* input_other = instruction->GetLeastConstantLeft(); 1323 1324 if (input_cst != nullptr) { 1325 int64_t value = Int64FromConstant(input_cst); 1326 if (value == -1 || 1327 // Similar cases under zero extension. 1328 (DataType::IsUnsignedType(input_other->GetType()) && 1329 ((DataType::MaxValueOfIntegralType(input_other->GetType()) & ~value) == 0))) { 1330 // Replace code looking like 1331 // AND dst, src, 0xFFF...FF 1332 // with 1333 // src 1334 instruction->ReplaceWith(input_other); 1335 instruction->GetBlock()->RemoveInstruction(instruction); 1336 RecordSimplification(); 1337 return; 1338 } 1339 if (input_other->IsTypeConversion() && 1340 input_other->GetType() == DataType::Type::kInt64 && 1341 DataType::IsIntegralType(input_other->InputAt(0)->GetType()) && 1342 IsInt<32>(value) && 1343 input_other->HasOnlyOneNonEnvironmentUse()) { 1344 // The AND can be reordered before the TypeConversion. Replace 1345 // LongConstant cst, <32-bit-constant-sign-extended-to-64-bits> 1346 // TypeConversion<Int64> tmp, src 1347 // AND dst, tmp, cst 1348 // with 1349 // IntConstant cst, <32-bit-constant> 1350 // AND tmp, src, cst 1351 // TypeConversion<Int64> dst, tmp 1352 // This helps 32-bit targets and does not hurt 64-bit targets. 1353 // This also simplifies detection of other patterns, such as Uint8 loads. 1354 HInstruction* new_and_input = input_other->InputAt(0); 1355 // Implicit conversion Int64->Int64 would have been removed previously. 1356 DCHECK_NE(new_and_input->GetType(), DataType::Type::kInt64); 1357 HConstant* new_const = GetGraph()->GetConstant(DataType::Type::kInt32, value); 1358 HAnd* new_and = 1359 new (GetGraph()->GetAllocator()) HAnd(DataType::Type::kInt32, new_and_input, new_const); 1360 instruction->GetBlock()->InsertInstructionBefore(new_and, instruction); 1361 HTypeConversion* new_conversion = 1362 new (GetGraph()->GetAllocator()) HTypeConversion(DataType::Type::kInt64, new_and); 1363 instruction->GetBlock()->ReplaceAndRemoveInstructionWith(instruction, new_conversion); 1364 input_other->GetBlock()->RemoveInstruction(input_other); 1365 RecordSimplification(); 1366 // Try to process the new And now, do not wait for the next round of simplifications. 1367 instruction = new_and; 1368 input_other = new_and_input; 1369 } 1370 // Eliminate And from UShr+And if the And-mask contains all the bits that 1371 // can be non-zero after UShr. Transform Shr+And to UShr if the And-mask 1372 // precisely clears the shifted-in sign bits. 1373 if ((input_other->IsUShr() || input_other->IsShr()) && input_other->InputAt(1)->IsConstant()) { 1374 size_t reg_bits = (instruction->GetResultType() == DataType::Type::kInt64) ? 64 : 32; 1375 size_t shift = Int64FromConstant(input_other->InputAt(1)->AsConstant()) & (reg_bits - 1); 1376 size_t num_tail_bits_set = CTZ(value + 1); 1377 if ((num_tail_bits_set >= reg_bits - shift) && input_other->IsUShr()) { 1378 // This AND clears only bits known to be clear, for example "(x >>> 24) & 0xff". 1379 instruction->ReplaceWith(input_other); 1380 instruction->GetBlock()->RemoveInstruction(instruction); 1381 RecordSimplification(); 1382 return; 1383 } else if ((num_tail_bits_set == reg_bits - shift) && IsPowerOfTwo(value + 1) && 1384 input_other->HasOnlyOneNonEnvironmentUse()) { 1385 DCHECK(input_other->IsShr()); // For UShr, we would have taken the branch above. 1386 // Replace SHR+AND with USHR, for example "(x >> 24) & 0xff" -> "x >>> 24". 1387 HUShr* ushr = new (GetGraph()->GetAllocator()) HUShr(instruction->GetType(), 1388 input_other->InputAt(0), 1389 input_other->InputAt(1), 1390 input_other->GetDexPc()); 1391 instruction->GetBlock()->ReplaceAndRemoveInstructionWith(instruction, ushr); 1392 input_other->GetBlock()->RemoveInstruction(input_other); 1393 RecordSimplification(); 1394 return; 1395 } 1396 } 1397 if ((value == 0xff || value == 0xffff) && instruction->GetType() != DataType::Type::kInt64) { 1398 // Transform AND to a type conversion to Uint8/Uint16. If `input_other` is a field 1399 // or array Get with only a single use, short-circuit the subsequent simplification 1400 // of the Get+TypeConversion and change the Get's type to `new_type` instead. 1401 DataType::Type new_type = (value == 0xff) ? DataType::Type::kUint8 : DataType::Type::kUint16; 1402 DataType::Type find_type = (value == 0xff) ? DataType::Type::kInt8 : DataType::Type::kInt16; 1403 if (input_other->GetType() == find_type && 1404 input_other->HasOnlyOneNonEnvironmentUse() && 1405 TryReplaceFieldOrArrayGetType(input_other, new_type)) { 1406 instruction->ReplaceWith(input_other); 1407 instruction->GetBlock()->RemoveInstruction(instruction); 1408 } else if (DataType::IsTypeConversionImplicit(input_other->GetType(), new_type)) { 1409 instruction->ReplaceWith(input_other); 1410 instruction->GetBlock()->RemoveInstruction(instruction); 1411 } else { 1412 HTypeConversion* type_conversion = new (GetGraph()->GetAllocator()) HTypeConversion( 1413 new_type, input_other, instruction->GetDexPc()); 1414 instruction->GetBlock()->ReplaceAndRemoveInstructionWith(instruction, type_conversion); 1415 } 1416 RecordSimplification(); 1417 return; 1418 } 1419 } 1420 1421 // We assume that GVN has run before, so we only perform a pointer comparison. 1422 // If for some reason the values are equal but the pointers are different, we 1423 // are still correct and only miss an optimization opportunity. 1424 if (instruction->GetLeft() == instruction->GetRight()) { 1425 // Replace code looking like 1426 // AND dst, src, src 1427 // with 1428 // src 1429 instruction->ReplaceWith(instruction->GetLeft()); 1430 instruction->GetBlock()->RemoveInstruction(instruction); 1431 RecordSimplification(); 1432 return; 1433 } 1434 1435 if (TryDeMorganNegationFactoring(instruction)) { 1436 return; 1437 } 1438 1439 // TryHandleAssociativeAndCommutativeOperation() does not remove its input, 1440 // so no need to return. 1441 TryHandleAssociativeAndCommutativeOperation(instruction); 1442 } 1443 1444 void InstructionSimplifierVisitor::VisitGreaterThan(HGreaterThan* condition) { 1445 VisitCondition(condition); 1446 } 1447 1448 void InstructionSimplifierVisitor::VisitGreaterThanOrEqual(HGreaterThanOrEqual* condition) { 1449 VisitCondition(condition); 1450 } 1451 1452 void InstructionSimplifierVisitor::VisitLessThan(HLessThan* condition) { 1453 VisitCondition(condition); 1454 } 1455 1456 void InstructionSimplifierVisitor::VisitLessThanOrEqual(HLessThanOrEqual* condition) { 1457 VisitCondition(condition); 1458 } 1459 1460 void InstructionSimplifierVisitor::VisitBelow(HBelow* condition) { 1461 VisitCondition(condition); 1462 } 1463 1464 void InstructionSimplifierVisitor::VisitBelowOrEqual(HBelowOrEqual* condition) { 1465 VisitCondition(condition); 1466 } 1467 1468 void InstructionSimplifierVisitor::VisitAbove(HAbove* condition) { 1469 VisitCondition(condition); 1470 } 1471 1472 void InstructionSimplifierVisitor::VisitAboveOrEqual(HAboveOrEqual* condition) { 1473 VisitCondition(condition); 1474 } 1475 1476 // Recognize the following pattern: 1477 // obj.getClass() ==/!= Foo.class 1478 // And replace it with a constant value if the type of `obj` is statically known. 1479 static bool RecognizeAndSimplifyClassCheck(HCondition* condition) { 1480 HInstruction* input_one = condition->InputAt(0); 1481 HInstruction* input_two = condition->InputAt(1); 1482 HLoadClass* load_class = input_one->IsLoadClass() 1483 ? input_one->AsLoadClass() 1484 : input_two->AsLoadClass(); 1485 if (load_class == nullptr) { 1486 return false; 1487 } 1488 1489 ReferenceTypeInfo class_rti = load_class->GetLoadedClassRTI(); 1490 if (!class_rti.IsValid()) { 1491 // Unresolved class. 1492 return false; 1493 } 1494 1495 HInstanceFieldGet* field_get = (load_class == input_one) 1496 ? input_two->AsInstanceFieldGet() 1497 : input_one->AsInstanceFieldGet(); 1498 if (field_get == nullptr) { 1499 return false; 1500 } 1501 1502 HInstruction* receiver = field_get->InputAt(0); 1503 ReferenceTypeInfo receiver_type = receiver->GetReferenceTypeInfo(); 1504 if (!receiver_type.IsExact()) { 1505 return false; 1506 } 1507 1508 { 1509 ScopedObjectAccess soa(Thread::Current()); 1510 ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); 1511 ArtField* field = class_linker->GetClassRoot(ClassLinker::kJavaLangObject)->GetInstanceField(0); 1512 DCHECK_EQ(std::string(field->GetName()), "shadow$_klass_"); 1513 if (field_get->GetFieldInfo().GetField() != field) { 1514 return false; 1515 } 1516 1517 // We can replace the compare. 1518 int value = 0; 1519 if (receiver_type.IsEqual(class_rti)) { 1520 value = condition->IsEqual() ? 1 : 0; 1521 } else { 1522 value = condition->IsNotEqual() ? 1 : 0; 1523 } 1524 condition->ReplaceWith(condition->GetBlock()->GetGraph()->GetIntConstant(value)); 1525 return true; 1526 } 1527 } 1528 1529 void InstructionSimplifierVisitor::VisitCondition(HCondition* condition) { 1530 if (condition->IsEqual() || condition->IsNotEqual()) { 1531 if (RecognizeAndSimplifyClassCheck(condition)) { 1532 return; 1533 } 1534 } 1535 1536 // Reverse condition if left is constant. Our code generators prefer constant 1537 // on the right hand side. 1538 if (condition->GetLeft()->IsConstant() && !condition->GetRight()->IsConstant()) { 1539 HBasicBlock* block = condition->GetBlock(); 1540 HCondition* replacement = 1541 GetOppositeConditionSwapOps(block->GetGraph()->GetAllocator(), condition); 1542 // If it is a fp we must set the opposite bias. 1543 if (replacement != nullptr) { 1544 if (condition->IsLtBias()) { 1545 replacement->SetBias(ComparisonBias::kGtBias); 1546 } else if (condition->IsGtBias()) { 1547 replacement->SetBias(ComparisonBias::kLtBias); 1548 } 1549 block->ReplaceAndRemoveInstructionWith(condition, replacement); 1550 RecordSimplification(); 1551 1552 condition = replacement; 1553 } 1554 } 1555 1556 HInstruction* left = condition->GetLeft(); 1557 HInstruction* right = condition->GetRight(); 1558 1559 // Try to fold an HCompare into this HCondition. 1560 1561 // We can only replace an HCondition which compares a Compare to 0. 1562 // Both 'dx' and 'jack' generate a compare to 0 when compiling a 1563 // condition with a long, float or double comparison as input. 1564 if (!left->IsCompare() || !right->IsConstant() || right->AsIntConstant()->GetValue() != 0) { 1565 // Conversion is not possible. 1566 return; 1567 } 1568 1569 // Is the Compare only used for this purpose? 1570 if (!left->GetUses().HasExactlyOneElement()) { 1571 // Someone else also wants the result of the compare. 1572 return; 1573 } 1574 1575 if (!left->GetEnvUses().empty()) { 1576 // There is a reference to the compare result in an environment. Do we really need it? 1577 if (GetGraph()->IsDebuggable()) { 1578 return; 1579 } 1580 1581 // We have to ensure that there are no deopt points in the sequence. 1582 if (left->HasAnyEnvironmentUseBefore(condition)) { 1583 return; 1584 } 1585 } 1586 1587 // Clean up any environment uses from the HCompare, if any. 1588 left->RemoveEnvironmentUsers(); 1589 1590 // We have decided to fold the HCompare into the HCondition. Transfer the information. 1591 condition->SetBias(left->AsCompare()->GetBias()); 1592 1593 // Replace the operands of the HCondition. 1594 condition->ReplaceInput(left->InputAt(0), 0); 1595 condition->ReplaceInput(left->InputAt(1), 1); 1596 1597 // Remove the HCompare. 1598 left->GetBlock()->RemoveInstruction(left); 1599 1600 RecordSimplification(); 1601 } 1602 1603 // Return whether x / divisor == x * (1.0f / divisor), for every float x. 1604 static constexpr bool CanDivideByReciprocalMultiplyFloat(int32_t divisor) { 1605 // True, if the most significant bits of divisor are 0. 1606 return ((divisor & 0x7fffff) == 0); 1607 } 1608 1609 // Return whether x / divisor == x * (1.0 / divisor), for every double x. 1610 static constexpr bool CanDivideByReciprocalMultiplyDouble(int64_t divisor) { 1611 // True, if the most significant bits of divisor are 0. 1612 return ((divisor & ((UINT64_C(1) << 52) - 1)) == 0); 1613 } 1614 1615 void InstructionSimplifierVisitor::VisitDiv(HDiv* instruction) { 1616 HConstant* input_cst = instruction->GetConstantRight(); 1617 HInstruction* input_other = instruction->GetLeastConstantLeft(); 1618 DataType::Type type = instruction->GetType(); 1619 1620 if ((input_cst != nullptr) && input_cst->IsOne()) { 1621 // Replace code looking like 1622 // DIV dst, src, 1 1623 // with 1624 // src 1625 instruction->ReplaceWith(input_other); 1626 instruction->GetBlock()->RemoveInstruction(instruction); 1627 RecordSimplification(); 1628 return; 1629 } 1630 1631 if ((input_cst != nullptr) && input_cst->IsMinusOne()) { 1632 // Replace code looking like 1633 // DIV dst, src, -1 1634 // with 1635 // NEG dst, src 1636 instruction->GetBlock()->ReplaceAndRemoveInstructionWith( 1637 instruction, new (GetGraph()->GetAllocator()) HNeg(type, input_other)); 1638 RecordSimplification(); 1639 return; 1640 } 1641 1642 if ((input_cst != nullptr) && DataType::IsFloatingPointType(type)) { 1643 // Try replacing code looking like 1644 // DIV dst, src, constant 1645 // with 1646 // MUL dst, src, 1 / constant 1647 HConstant* reciprocal = nullptr; 1648 if (type == DataType::Type::kFloat64) { 1649 double value = input_cst->AsDoubleConstant()->GetValue(); 1650 if (CanDivideByReciprocalMultiplyDouble(bit_cast<int64_t, double>(value))) { 1651 reciprocal = GetGraph()->GetDoubleConstant(1.0 / value); 1652 } 1653 } else { 1654 DCHECK_EQ(type, DataType::Type::kFloat32); 1655 float value = input_cst->AsFloatConstant()->GetValue(); 1656 if (CanDivideByReciprocalMultiplyFloat(bit_cast<int32_t, float>(value))) { 1657 reciprocal = GetGraph()->GetFloatConstant(1.0f / value); 1658 } 1659 } 1660 1661 if (reciprocal != nullptr) { 1662 instruction->GetBlock()->ReplaceAndRemoveInstructionWith( 1663 instruction, new (GetGraph()->GetAllocator()) HMul(type, input_other, reciprocal)); 1664 RecordSimplification(); 1665 return; 1666 } 1667 } 1668 } 1669 1670 void InstructionSimplifierVisitor::VisitMul(HMul* instruction) { 1671 HConstant* input_cst = instruction->GetConstantRight(); 1672 HInstruction* input_other = instruction->GetLeastConstantLeft(); 1673 DataType::Type type = instruction->GetType(); 1674 HBasicBlock* block = instruction->GetBlock(); 1675 ArenaAllocator* allocator = GetGraph()->GetAllocator(); 1676 1677 if (input_cst == nullptr) { 1678 return; 1679 } 1680 1681 if (input_cst->IsOne()) { 1682 // Replace code looking like 1683 // MUL dst, src, 1 1684 // with 1685 // src 1686 instruction->ReplaceWith(input_other); 1687 instruction->GetBlock()->RemoveInstruction(instruction); 1688 RecordSimplification(); 1689 return; 1690 } 1691 1692 if (input_cst->IsMinusOne() && 1693 (DataType::IsFloatingPointType(type) || DataType::IsIntOrLongType(type))) { 1694 // Replace code looking like 1695 // MUL dst, src, -1 1696 // with 1697 // NEG dst, src 1698 HNeg* neg = new (allocator) HNeg(type, input_other); 1699 block->ReplaceAndRemoveInstructionWith(instruction, neg); 1700 RecordSimplification(); 1701 return; 1702 } 1703 1704 if (DataType::IsFloatingPointType(type) && 1705 ((input_cst->IsFloatConstant() && input_cst->AsFloatConstant()->GetValue() == 2.0f) || 1706 (input_cst->IsDoubleConstant() && input_cst->AsDoubleConstant()->GetValue() == 2.0))) { 1707 // Replace code looking like 1708 // FP_MUL dst, src, 2.0 1709 // with 1710 // FP_ADD dst, src, src 1711 // The 'int' and 'long' cases are handled below. 1712 block->ReplaceAndRemoveInstructionWith(instruction, 1713 new (allocator) HAdd(type, input_other, input_other)); 1714 RecordSimplification(); 1715 return; 1716 } 1717 1718 if (DataType::IsIntOrLongType(type)) { 1719 int64_t factor = Int64FromConstant(input_cst); 1720 // Even though constant propagation also takes care of the zero case, other 1721 // optimizations can lead to having a zero multiplication. 1722 if (factor == 0) { 1723 // Replace code looking like 1724 // MUL dst, src, 0 1725 // with 1726 // 0 1727 instruction->ReplaceWith(input_cst); 1728 instruction->GetBlock()->RemoveInstruction(instruction); 1729 RecordSimplification(); 1730 return; 1731 } else if (IsPowerOfTwo(factor)) { 1732 // Replace code looking like 1733 // MUL dst, src, pow_of_2 1734 // with 1735 // SHL dst, src, log2(pow_of_2) 1736 HIntConstant* shift = GetGraph()->GetIntConstant(WhichPowerOf2(factor)); 1737 HShl* shl = new (allocator) HShl(type, input_other, shift); 1738 block->ReplaceAndRemoveInstructionWith(instruction, shl); 1739 RecordSimplification(); 1740 return; 1741 } else if (IsPowerOfTwo(factor - 1)) { 1742 // Transform code looking like 1743 // MUL dst, src, (2^n + 1) 1744 // into 1745 // SHL tmp, src, n 1746 // ADD dst, src, tmp 1747 HShl* shl = new (allocator) HShl(type, 1748 input_other, 1749 GetGraph()->GetIntConstant(WhichPowerOf2(factor - 1))); 1750 HAdd* add = new (allocator) HAdd(type, input_other, shl); 1751 1752 block->InsertInstructionBefore(shl, instruction); 1753 block->ReplaceAndRemoveInstructionWith(instruction, add); 1754 RecordSimplification(); 1755 return; 1756 } else if (IsPowerOfTwo(factor + 1)) { 1757 // Transform code looking like 1758 // MUL dst, src, (2^n - 1) 1759 // into 1760 // SHL tmp, src, n 1761 // SUB dst, tmp, src 1762 HShl* shl = new (allocator) HShl(type, 1763 input_other, 1764 GetGraph()->GetIntConstant(WhichPowerOf2(factor + 1))); 1765 HSub* sub = new (allocator) HSub(type, shl, input_other); 1766 1767 block->InsertInstructionBefore(shl, instruction); 1768 block->ReplaceAndRemoveInstructionWith(instruction, sub); 1769 RecordSimplification(); 1770 return; 1771 } 1772 } 1773 1774 // TryHandleAssociativeAndCommutativeOperation() does not remove its input, 1775 // so no need to return. 1776 TryHandleAssociativeAndCommutativeOperation(instruction); 1777 } 1778 1779 void InstructionSimplifierVisitor::VisitNeg(HNeg* instruction) { 1780 HInstruction* input = instruction->GetInput(); 1781 if (input->IsNeg()) { 1782 // Replace code looking like 1783 // NEG tmp, src 1784 // NEG dst, tmp 1785 // with 1786 // src 1787 HNeg* previous_neg = input->AsNeg(); 1788 instruction->ReplaceWith(previous_neg->GetInput()); 1789 instruction->GetBlock()->RemoveInstruction(instruction); 1790 // We perform the optimization even if the input negation has environment 1791 // uses since it allows removing the current instruction. But we only delete 1792 // the input negation only if it is does not have any uses left. 1793 if (!previous_neg->HasUses()) { 1794 previous_neg->GetBlock()->RemoveInstruction(previous_neg); 1795 } 1796 RecordSimplification(); 1797 return; 1798 } 1799 1800 if (input->IsSub() && input->HasOnlyOneNonEnvironmentUse() && 1801 !DataType::IsFloatingPointType(input->GetType())) { 1802 // Replace code looking like 1803 // SUB tmp, a, b 1804 // NEG dst, tmp 1805 // with 1806 // SUB dst, b, a 1807 // We do not perform the optimization if the input subtraction has 1808 // environment uses or multiple non-environment uses as it could lead to 1809 // worse code. In particular, we do not want the live ranges of `a` and `b` 1810 // to be extended if we are not sure the initial 'SUB' instruction can be 1811 // removed. 1812 // We do not perform optimization for fp because we could lose the sign of zero. 1813 HSub* sub = input->AsSub(); 1814 HSub* new_sub = new (GetGraph()->GetAllocator()) HSub( 1815 instruction->GetType(), sub->GetRight(), sub->GetLeft()); 1816 instruction->GetBlock()->ReplaceAndRemoveInstructionWith(instruction, new_sub); 1817 if (!sub->HasUses()) { 1818 sub->GetBlock()->RemoveInstruction(sub); 1819 } 1820 RecordSimplification(); 1821 } 1822 } 1823 1824 void InstructionSimplifierVisitor::VisitNot(HNot* instruction) { 1825 HInstruction* input = instruction->GetInput(); 1826 if (input->IsNot()) { 1827 // Replace code looking like 1828 // NOT tmp, src 1829 // NOT dst, tmp 1830 // with 1831 // src 1832 // We perform the optimization even if the input negation has environment 1833 // uses since it allows removing the current instruction. But we only delete 1834 // the input negation only if it is does not have any uses left. 1835 HNot* previous_not = input->AsNot(); 1836 instruction->ReplaceWith(previous_not->GetInput()); 1837 instruction->GetBlock()->RemoveInstruction(instruction); 1838 if (!previous_not->HasUses()) { 1839 previous_not->GetBlock()->RemoveInstruction(previous_not); 1840 } 1841 RecordSimplification(); 1842 } 1843 } 1844 1845 void InstructionSimplifierVisitor::VisitOr(HOr* instruction) { 1846 HConstant* input_cst = instruction->GetConstantRight(); 1847 HInstruction* input_other = instruction->GetLeastConstantLeft(); 1848 1849 if ((input_cst != nullptr) && input_cst->IsZeroBitPattern()) { 1850 // Replace code looking like 1851 // OR dst, src, 0 1852 // with 1853 // src 1854 instruction->ReplaceWith(input_other); 1855 instruction->GetBlock()->RemoveInstruction(instruction); 1856 RecordSimplification(); 1857 return; 1858 } 1859 1860 // We assume that GVN has run before, so we only perform a pointer comparison. 1861 // If for some reason the values are equal but the pointers are different, we 1862 // are still correct and only miss an optimization opportunity. 1863 if (instruction->GetLeft() == instruction->GetRight()) { 1864 // Replace code looking like 1865 // OR dst, src, src 1866 // with 1867 // src 1868 instruction->ReplaceWith(instruction->GetLeft()); 1869 instruction->GetBlock()->RemoveInstruction(instruction); 1870 RecordSimplification(); 1871 return; 1872 } 1873 1874 if (TryDeMorganNegationFactoring(instruction)) return; 1875 1876 if (TryReplaceWithRotate(instruction)) { 1877 return; 1878 } 1879 1880 // TryHandleAssociativeAndCommutativeOperation() does not remove its input, 1881 // so no need to return. 1882 TryHandleAssociativeAndCommutativeOperation(instruction); 1883 } 1884 1885 void InstructionSimplifierVisitor::VisitShl(HShl* instruction) { 1886 VisitShift(instruction); 1887 } 1888 1889 void InstructionSimplifierVisitor::VisitShr(HShr* instruction) { 1890 VisitShift(instruction); 1891 } 1892 1893 void InstructionSimplifierVisitor::VisitSub(HSub* instruction) { 1894 HConstant* input_cst = instruction->GetConstantRight(); 1895 HInstruction* input_other = instruction->GetLeastConstantLeft(); 1896 1897 DataType::Type type = instruction->GetType(); 1898 if (DataType::IsFloatingPointType(type)) { 1899 return; 1900 } 1901 1902 if ((input_cst != nullptr) && input_cst->IsArithmeticZero()) { 1903 // Replace code looking like 1904 // SUB dst, src, 0 1905 // with 1906 // src 1907 // Note that we cannot optimize `x - 0.0` to `x` for floating-point. When 1908 // `x` is `-0.0`, the former expression yields `0.0`, while the later 1909 // yields `-0.0`. 1910 instruction->ReplaceWith(input_other); 1911 instruction->GetBlock()->RemoveInstruction(instruction); 1912 RecordSimplification(); 1913 return; 1914 } 1915 1916 HBasicBlock* block = instruction->GetBlock(); 1917 ArenaAllocator* allocator = GetGraph()->GetAllocator(); 1918 1919 HInstruction* left = instruction->GetLeft(); 1920 HInstruction* right = instruction->GetRight(); 1921 if (left->IsConstant()) { 1922 if (Int64FromConstant(left->AsConstant()) == 0) { 1923 // Replace code looking like 1924 // SUB dst, 0, src 1925 // with 1926 // NEG dst, src 1927 // Note that we cannot optimize `0.0 - x` to `-x` for floating-point. When 1928 // `x` is `0.0`, the former expression yields `0.0`, while the later 1929 // yields `-0.0`. 1930 HNeg* neg = new (allocator) HNeg(type, right); 1931 block->ReplaceAndRemoveInstructionWith(instruction, neg); 1932 RecordSimplification(); 1933 return; 1934 } 1935 } 1936 1937 if (left->IsNeg() && right->IsNeg()) { 1938 if (TryMoveNegOnInputsAfterBinop(instruction)) { 1939 return; 1940 } 1941 } 1942 1943 if (right->IsNeg() && right->HasOnlyOneNonEnvironmentUse()) { 1944 // Replace code looking like 1945 // NEG tmp, b 1946 // SUB dst, a, tmp 1947 // with 1948 // ADD dst, a, b 1949 HAdd* add = new(GetGraph()->GetAllocator()) HAdd(type, left, right->AsNeg()->GetInput()); 1950 instruction->GetBlock()->ReplaceAndRemoveInstructionWith(instruction, add); 1951 RecordSimplification(); 1952 right->GetBlock()->RemoveInstruction(right); 1953 return; 1954 } 1955 1956 if (left->IsNeg() && left->HasOnlyOneNonEnvironmentUse()) { 1957 // Replace code looking like 1958 // NEG tmp, a 1959 // SUB dst, tmp, b 1960 // with 1961 // ADD tmp, a, b 1962 // NEG dst, tmp 1963 // The second version is not intrinsically better, but enables more 1964 // transformations. 1965 HAdd* add = new(GetGraph()->GetAllocator()) HAdd(type, left->AsNeg()->GetInput(), right); 1966 instruction->GetBlock()->InsertInstructionBefore(add, instruction); 1967 HNeg* neg = new (GetGraph()->GetAllocator()) HNeg(instruction->GetType(), add); 1968 instruction->GetBlock()->InsertInstructionBefore(neg, instruction); 1969 instruction->ReplaceWith(neg); 1970 instruction->GetBlock()->RemoveInstruction(instruction); 1971 RecordSimplification(); 1972 left->GetBlock()->RemoveInstruction(left); 1973 return; 1974 } 1975 1976 if (TrySubtractionChainSimplification(instruction)) { 1977 return; 1978 } 1979 1980 if (left->IsAdd()) { 1981 // Replace code patterns looking like 1982 // ADD dst1, x, y ADD dst1, x, y 1983 // SUB dst2, dst1, y SUB dst2, dst1, x 1984 // with 1985 // ADD dst1, x, y 1986 // SUB instruction is not needed in this case, we may use 1987 // one of inputs of ADD instead. 1988 // It is applicable to integral types only. 1989 DCHECK(DataType::IsIntegralType(type)); 1990 if (left->InputAt(1) == right) { 1991 instruction->ReplaceWith(left->InputAt(0)); 1992 RecordSimplification(); 1993 instruction->GetBlock()->RemoveInstruction(instruction); 1994 return; 1995 } else if (left->InputAt(0) == right) { 1996 instruction->ReplaceWith(left->InputAt(1)); 1997 RecordSimplification(); 1998 instruction->GetBlock()->RemoveInstruction(instruction); 1999 return; 2000 } 2001 } 2002 } 2003 2004 void InstructionSimplifierVisitor::VisitUShr(HUShr* instruction) { 2005 VisitShift(instruction); 2006 } 2007 2008 void InstructionSimplifierVisitor::VisitXor(HXor* instruction) { 2009 HConstant* input_cst = instruction->GetConstantRight(); 2010 HInstruction* input_other = instruction->GetLeastConstantLeft(); 2011 2012 if ((input_cst != nullptr) && input_cst->IsZeroBitPattern()) { 2013 // Replace code looking like 2014 // XOR dst, src, 0 2015 // with 2016 // src 2017 instruction->ReplaceWith(input_other); 2018 instruction->GetBlock()->RemoveInstruction(instruction); 2019 RecordSimplification(); 2020 return; 2021 } 2022 2023 if ((input_cst != nullptr) && input_cst->IsOne() 2024 && input_other->GetType() == DataType::Type::kBool) { 2025 // Replace code looking like 2026 // XOR dst, src, 1 2027 // with 2028 // BOOLEAN_NOT dst, src 2029 HBooleanNot* boolean_not = new (GetGraph()->GetAllocator()) HBooleanNot(input_other); 2030 instruction->GetBlock()->ReplaceAndRemoveInstructionWith(instruction, boolean_not); 2031 RecordSimplification(); 2032 return; 2033 } 2034 2035 if ((input_cst != nullptr) && AreAllBitsSet(input_cst)) { 2036 // Replace code looking like 2037 // XOR dst, src, 0xFFF...FF 2038 // with 2039 // NOT dst, src 2040 HNot* bitwise_not = new (GetGraph()->GetAllocator()) HNot(instruction->GetType(), input_other); 2041 instruction->GetBlock()->ReplaceAndRemoveInstructionWith(instruction, bitwise_not); 2042 RecordSimplification(); 2043 return; 2044 } 2045 2046 HInstruction* left = instruction->GetLeft(); 2047 HInstruction* right = instruction->GetRight(); 2048 if (((left->IsNot() && right->IsNot()) || 2049 (left->IsBooleanNot() && right->IsBooleanNot())) && 2050 left->HasOnlyOneNonEnvironmentUse() && 2051 right->HasOnlyOneNonEnvironmentUse()) { 2052 // Replace code looking like 2053 // NOT nota, a 2054 // NOT notb, b 2055 // XOR dst, nota, notb 2056 // with 2057 // XOR dst, a, b 2058 instruction->ReplaceInput(left->InputAt(0), 0); 2059 instruction->ReplaceInput(right->InputAt(0), 1); 2060 left->GetBlock()->RemoveInstruction(left); 2061 right->GetBlock()->RemoveInstruction(right); 2062 RecordSimplification(); 2063 return; 2064 } 2065 2066 if (TryReplaceWithRotate(instruction)) { 2067 return; 2068 } 2069 2070 // TryHandleAssociativeAndCommutativeOperation() does not remove its input, 2071 // so no need to return. 2072 TryHandleAssociativeAndCommutativeOperation(instruction); 2073 } 2074 2075 void InstructionSimplifierVisitor::SimplifyStringEquals(HInvoke* instruction) { 2076 HInstruction* argument = instruction->InputAt(1); 2077 HInstruction* receiver = instruction->InputAt(0); 2078 if (receiver == argument) { 2079 // Because String.equals is an instance call, the receiver is 2080 // a null check if we don't know it's null. The argument however, will 2081 // be the actual object. So we cannot end up in a situation where both 2082 // are equal but could be null. 2083 DCHECK(CanEnsureNotNullAt(argument, instruction)); 2084 instruction->ReplaceWith(GetGraph()->GetIntConstant(1)); 2085 instruction->GetBlock()->RemoveInstruction(instruction); 2086 } else { 2087 StringEqualsOptimizations optimizations(instruction); 2088 if (CanEnsureNotNullAt(argument, instruction)) { 2089 optimizations.SetArgumentNotNull(); 2090 } 2091 ScopedObjectAccess soa(Thread::Current()); 2092 ReferenceTypeInfo argument_rti = argument->GetReferenceTypeInfo(); 2093 if (argument_rti.IsValid() && argument_rti.IsStringClass()) { 2094 optimizations.SetArgumentIsString(); 2095 } else if (kUseReadBarrier) { 2096 DCHECK(instruction->GetResolvedMethod() != nullptr); 2097 DCHECK(instruction->GetResolvedMethod()->GetDeclaringClass()->IsStringClass() || 2098 // Object.equals() can be devirtualized to String.equals(). 2099 instruction->GetResolvedMethod()->GetDeclaringClass()->IsObjectClass()); 2100 Runtime* runtime = Runtime::Current(); 2101 // For AOT, we always assume that the boot image shall contain the String.class and 2102 // we do not need a read barrier for boot image classes as they are non-moveable. 2103 // For JIT, check if we actually have a boot image; if we do, the String.class 2104 // should also be non-moveable. 2105 if (runtime->IsAotCompiler() || runtime->GetHeap()->HasBootImageSpace()) { 2106 DCHECK(runtime->IsAotCompiler() || 2107 !runtime->GetHeap()->IsMovableObject( 2108 instruction->GetResolvedMethod()->GetDeclaringClass())); 2109 optimizations.SetNoReadBarrierForStringClass(); 2110 } 2111 } 2112 } 2113 } 2114 2115 void InstructionSimplifierVisitor::SimplifyRotate(HInvoke* invoke, 2116 bool is_left, 2117 DataType::Type type) { 2118 DCHECK(invoke->IsInvokeStaticOrDirect()); 2119 DCHECK_EQ(invoke->GetInvokeType(), InvokeType::kStatic); 2120 HInstruction* value = invoke->InputAt(0); 2121 HInstruction* distance = invoke->InputAt(1); 2122 // Replace the invoke with an HRor. 2123 if (is_left) { 2124 // Unconditionally set the type of the negated distance to `int`, 2125 // as shift and rotate operations expect a 32-bit (or narrower) 2126 // value for their distance input. 2127 distance = new (GetGraph()->GetAllocator()) HNeg(DataType::Type::kInt32, distance); 2128 invoke->GetBlock()->InsertInstructionBefore(distance, invoke); 2129 } 2130 HRor* ror = new (GetGraph()->GetAllocator()) HRor(type, value, distance); 2131 invoke->GetBlock()->ReplaceAndRemoveInstructionWith(invoke, ror); 2132 // Remove ClinitCheck and LoadClass, if possible. 2133 HInstruction* clinit = invoke->GetInputs().back(); 2134 if (clinit->IsClinitCheck() && !clinit->HasUses()) { 2135 clinit->GetBlock()->RemoveInstruction(clinit); 2136 HInstruction* ldclass = clinit->InputAt(0); 2137 if (ldclass->IsLoadClass() && !ldclass->HasUses()) { 2138 ldclass->GetBlock()->RemoveInstruction(ldclass); 2139 } 2140 } 2141 } 2142 2143 static bool IsArrayLengthOf(HInstruction* potential_length, HInstruction* potential_array) { 2144 if (potential_length->IsArrayLength()) { 2145 return potential_length->InputAt(0) == potential_array; 2146 } 2147 2148 if (potential_array->IsNewArray()) { 2149 return potential_array->AsNewArray()->GetLength() == potential_length; 2150 } 2151 2152 return false; 2153 } 2154 2155 void InstructionSimplifierVisitor::SimplifySystemArrayCopy(HInvoke* instruction) { 2156 HInstruction* source = instruction->InputAt(0); 2157 HInstruction* destination = instruction->InputAt(2); 2158 HInstruction* count = instruction->InputAt(4); 2159 SystemArrayCopyOptimizations optimizations(instruction); 2160 if (CanEnsureNotNullAt(source, instruction)) { 2161 optimizations.SetSourceIsNotNull(); 2162 } 2163 if (CanEnsureNotNullAt(destination, instruction)) { 2164 optimizations.SetDestinationIsNotNull(); 2165 } 2166 if (destination == source) { 2167 optimizations.SetDestinationIsSource(); 2168 } 2169 2170 if (IsArrayLengthOf(count, source)) { 2171 optimizations.SetCountIsSourceLength(); 2172 } 2173 2174 if (IsArrayLengthOf(count, destination)) { 2175 optimizations.SetCountIsDestinationLength(); 2176 } 2177 2178 { 2179 ScopedObjectAccess soa(Thread::Current()); 2180 DataType::Type source_component_type = DataType::Type::kVoid; 2181 DataType::Type destination_component_type = DataType::Type::kVoid; 2182 ReferenceTypeInfo destination_rti = destination->GetReferenceTypeInfo(); 2183 if (destination_rti.IsValid()) { 2184 if (destination_rti.IsObjectArray()) { 2185 if (destination_rti.IsExact()) { 2186 optimizations.SetDoesNotNeedTypeCheck(); 2187 } 2188 optimizations.SetDestinationIsTypedObjectArray(); 2189 } 2190 if (destination_rti.IsPrimitiveArrayClass()) { 2191 destination_component_type = DataTypeFromPrimitive( 2192 destination_rti.GetTypeHandle()->GetComponentType()->GetPrimitiveType()); 2193 optimizations.SetDestinationIsPrimitiveArray(); 2194 } else if (destination_rti.IsNonPrimitiveArrayClass()) { 2195 optimizations.SetDestinationIsNonPrimitiveArray(); 2196 } 2197 } 2198 ReferenceTypeInfo source_rti = source->GetReferenceTypeInfo(); 2199 if (source_rti.IsValid()) { 2200 if (destination_rti.IsValid() && destination_rti.CanArrayHoldValuesOf(source_rti)) { 2201 optimizations.SetDoesNotNeedTypeCheck(); 2202 } 2203 if (source_rti.IsPrimitiveArrayClass()) { 2204 optimizations.SetSourceIsPrimitiveArray(); 2205 source_component_type = DataTypeFromPrimitive( 2206 source_rti.GetTypeHandle()->GetComponentType()->GetPrimitiveType()); 2207 } else if (source_rti.IsNonPrimitiveArrayClass()) { 2208 optimizations.SetSourceIsNonPrimitiveArray(); 2209 } 2210 } 2211 // For primitive arrays, use their optimized ArtMethod implementations. 2212 if ((source_component_type != DataType::Type::kVoid) && 2213 (source_component_type == destination_component_type)) { 2214 ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); 2215 PointerSize image_size = class_linker->GetImagePointerSize(); 2216 HInvokeStaticOrDirect* invoke = instruction->AsInvokeStaticOrDirect(); 2217 mirror::Class* system = invoke->GetResolvedMethod()->GetDeclaringClass(); 2218 ArtMethod* method = nullptr; 2219 switch (source_component_type) { 2220 case DataType::Type::kBool: 2221 method = system->FindClassMethod("arraycopy", "([ZI[ZII)V", image_size); 2222 break; 2223 case DataType::Type::kInt8: 2224 method = system->FindClassMethod("arraycopy", "([BI[BII)V", image_size); 2225 break; 2226 case DataType::Type::kUint16: 2227 method = system->FindClassMethod("arraycopy", "([CI[CII)V", image_size); 2228 break; 2229 case DataType::Type::kInt16: 2230 method = system->FindClassMethod("arraycopy", "([SI[SII)V", image_size); 2231 break; 2232 case DataType::Type::kInt32: 2233 method = system->FindClassMethod("arraycopy", "([II[III)V", image_size); 2234 break; 2235 case DataType::Type::kFloat32: 2236 method = system->FindClassMethod("arraycopy", "([FI[FII)V", image_size); 2237 break; 2238 case DataType::Type::kInt64: 2239 method = system->FindClassMethod("arraycopy", "([JI[JII)V", image_size); 2240 break; 2241 case DataType::Type::kFloat64: 2242 method = system->FindClassMethod("arraycopy", "([DI[DII)V", image_size); 2243 break; 2244 default: 2245 LOG(FATAL) << "Unreachable"; 2246 } 2247 DCHECK(method != nullptr); 2248 DCHECK(method->IsStatic()); 2249 DCHECK(method->GetDeclaringClass() == system); 2250 invoke->SetResolvedMethod(method); 2251 // Sharpen the new invoke. Note that we do not update the dex method index of 2252 // the invoke, as we would need to look it up in the current dex file, and it 2253 // is unlikely that it exists. The most usual situation for such typed 2254 // arraycopy methods is a direct pointer to the boot image. 2255 HSharpening::SharpenInvokeStaticOrDirect(invoke, codegen_, compiler_driver_); 2256 } 2257 } 2258 } 2259 2260 void InstructionSimplifierVisitor::SimplifyCompare(HInvoke* invoke, 2261 bool is_signum, 2262 DataType::Type type) { 2263 DCHECK(invoke->IsInvokeStaticOrDirect()); 2264 uint32_t dex_pc = invoke->GetDexPc(); 2265 HInstruction* left = invoke->InputAt(0); 2266 HInstruction* right; 2267 if (!is_signum) { 2268 right = invoke->InputAt(1); 2269 } else if (type == DataType::Type::kInt64) { 2270 right = GetGraph()->GetLongConstant(0); 2271 } else { 2272 right = GetGraph()->GetIntConstant(0); 2273 } 2274 HCompare* compare = new (GetGraph()->GetAllocator()) 2275 HCompare(type, left, right, ComparisonBias::kNoBias, dex_pc); 2276 invoke->GetBlock()->ReplaceAndRemoveInstructionWith(invoke, compare); 2277 } 2278 2279 void InstructionSimplifierVisitor::SimplifyIsNaN(HInvoke* invoke) { 2280 DCHECK(invoke->IsInvokeStaticOrDirect()); 2281 uint32_t dex_pc = invoke->GetDexPc(); 2282 // IsNaN(x) is the same as x != x. 2283 HInstruction* x = invoke->InputAt(0); 2284 HCondition* condition = new (GetGraph()->GetAllocator()) HNotEqual(x, x, dex_pc); 2285 condition->SetBias(ComparisonBias::kLtBias); 2286 invoke->GetBlock()->ReplaceAndRemoveInstructionWith(invoke, condition); 2287 } 2288 2289 void InstructionSimplifierVisitor::SimplifyFP2Int(HInvoke* invoke) { 2290 DCHECK(invoke->IsInvokeStaticOrDirect()); 2291 uint32_t dex_pc = invoke->GetDexPc(); 2292 HInstruction* x = invoke->InputAt(0); 2293 DataType::Type type = x->GetType(); 2294 // Set proper bit pattern for NaN and replace intrinsic with raw version. 2295 HInstruction* nan; 2296 if (type == DataType::Type::kFloat64) { 2297 nan = GetGraph()->GetLongConstant(0x7ff8000000000000L); 2298 invoke->SetIntrinsic(Intrinsics::kDoubleDoubleToRawLongBits, 2299 kNeedsEnvironmentOrCache, 2300 kNoSideEffects, 2301 kNoThrow); 2302 } else { 2303 DCHECK_EQ(type, DataType::Type::kFloat32); 2304 nan = GetGraph()->GetIntConstant(0x7fc00000); 2305 invoke->SetIntrinsic(Intrinsics::kFloatFloatToRawIntBits, 2306 kNeedsEnvironmentOrCache, 2307 kNoSideEffects, 2308 kNoThrow); 2309 } 2310 // Test IsNaN(x), which is the same as x != x. 2311 HCondition* condition = new (GetGraph()->GetAllocator()) HNotEqual(x, x, dex_pc); 2312 condition->SetBias(ComparisonBias::kLtBias); 2313 invoke->GetBlock()->InsertInstructionBefore(condition, invoke->GetNext()); 2314 // Select between the two. 2315 HInstruction* select = new (GetGraph()->GetAllocator()) HSelect(condition, nan, invoke, dex_pc); 2316 invoke->GetBlock()->InsertInstructionBefore(select, condition->GetNext()); 2317 invoke->ReplaceWithExceptInReplacementAtIndex(select, 0); // false at index 0 2318 } 2319 2320 void InstructionSimplifierVisitor::SimplifyStringCharAt(HInvoke* invoke) { 2321 HInstruction* str = invoke->InputAt(0); 2322 HInstruction* index = invoke->InputAt(1); 2323 uint32_t dex_pc = invoke->GetDexPc(); 2324 ArenaAllocator* allocator = GetGraph()->GetAllocator(); 2325 // We treat String as an array to allow DCE and BCE to seamlessly work on strings, 2326 // so create the HArrayLength, HBoundsCheck and HArrayGet. 2327 HArrayLength* length = new (allocator) HArrayLength(str, dex_pc, /* is_string_length */ true); 2328 invoke->GetBlock()->InsertInstructionBefore(length, invoke); 2329 HBoundsCheck* bounds_check = new (allocator) HBoundsCheck( 2330 index, length, dex_pc, /* is_string_char_at */ true); 2331 invoke->GetBlock()->InsertInstructionBefore(bounds_check, invoke); 2332 HArrayGet* array_get = new (allocator) HArrayGet(str, 2333 bounds_check, 2334 DataType::Type::kUint16, 2335 SideEffects::None(), // Strings are immutable. 2336 dex_pc, 2337 /* is_string_char_at */ true); 2338 invoke->GetBlock()->ReplaceAndRemoveInstructionWith(invoke, array_get); 2339 bounds_check->CopyEnvironmentFrom(invoke->GetEnvironment()); 2340 GetGraph()->SetHasBoundsChecks(true); 2341 } 2342 2343 void InstructionSimplifierVisitor::SimplifyStringIsEmptyOrLength(HInvoke* invoke) { 2344 HInstruction* str = invoke->InputAt(0); 2345 uint32_t dex_pc = invoke->GetDexPc(); 2346 // We treat String as an array to allow DCE and BCE to seamlessly work on strings, 2347 // so create the HArrayLength. 2348 HArrayLength* length = 2349 new (GetGraph()->GetAllocator()) HArrayLength(str, dex_pc, /* is_string_length */ true); 2350 HInstruction* replacement; 2351 if (invoke->GetIntrinsic() == Intrinsics::kStringIsEmpty) { 2352 // For String.isEmpty(), create the `HEqual` representing the `length == 0`. 2353 invoke->GetBlock()->InsertInstructionBefore(length, invoke); 2354 HIntConstant* zero = GetGraph()->GetIntConstant(0); 2355 HEqual* equal = new (GetGraph()->GetAllocator()) HEqual(length, zero, dex_pc); 2356 replacement = equal; 2357 } else { 2358 DCHECK_EQ(invoke->GetIntrinsic(), Intrinsics::kStringLength); 2359 replacement = length; 2360 } 2361 invoke->GetBlock()->ReplaceAndRemoveInstructionWith(invoke, replacement); 2362 } 2363 2364 // This method should only be used on intrinsics whose sole way of throwing an 2365 // exception is raising a NPE when the nth argument is null. If that argument 2366 // is provably non-null, we can clear the flag. 2367 void InstructionSimplifierVisitor::SimplifyNPEOnArgN(HInvoke* invoke, size_t n) { 2368 HInstruction* arg = invoke->InputAt(n); 2369 if (invoke->CanThrow() && !arg->CanBeNull()) { 2370 invoke->SetCanThrow(false); 2371 } 2372 } 2373 2374 // Methods that return "this" can replace the returned value with the receiver. 2375 void InstructionSimplifierVisitor::SimplifyReturnThis(HInvoke* invoke) { 2376 if (invoke->HasUses()) { 2377 HInstruction* receiver = invoke->InputAt(0); 2378 invoke->ReplaceWith(receiver); 2379 RecordSimplification(); 2380 } 2381 } 2382 2383 // Helper method for StringBuffer escape analysis. 2384 static bool NoEscapeForStringBufferReference(HInstruction* reference, HInstruction* user) { 2385 if (user->IsInvokeStaticOrDirect()) { 2386 // Any constructor on StringBuffer is okay. 2387 return user->AsInvokeStaticOrDirect()->GetResolvedMethod() != nullptr && 2388 user->AsInvokeStaticOrDirect()->GetResolvedMethod()->IsConstructor() && 2389 user->InputAt(0) == reference; 2390 } else if (user->IsInvokeVirtual()) { 2391 switch (user->AsInvokeVirtual()->GetIntrinsic()) { 2392 case Intrinsics::kStringBufferLength: 2393 case Intrinsics::kStringBufferToString: 2394 DCHECK_EQ(user->InputAt(0), reference); 2395 return true; 2396 case Intrinsics::kStringBufferAppend: 2397 // Returns "this", so only okay if no further uses. 2398 DCHECK_EQ(user->InputAt(0), reference); 2399 DCHECK_NE(user->InputAt(1), reference); 2400 return !user->HasUses(); 2401 default: 2402 break; 2403 } 2404 } 2405 return false; 2406 } 2407 2408 // Certain allocation intrinsics are not removed by dead code elimination 2409 // because of potentially throwing an OOM exception or other side effects. 2410 // This method removes such intrinsics when special circumstances allow. 2411 void InstructionSimplifierVisitor::SimplifyAllocationIntrinsic(HInvoke* invoke) { 2412 if (!invoke->HasUses()) { 2413 // Instruction has no uses. If unsynchronized, we can remove right away, safely ignoring 2414 // the potential OOM of course. Otherwise, we must ensure the receiver object of this 2415 // call does not escape since only thread-local synchronization may be removed. 2416 bool is_synchronized = invoke->GetIntrinsic() == Intrinsics::kStringBufferToString; 2417 HInstruction* receiver = invoke->InputAt(0); 2418 if (!is_synchronized || DoesNotEscape(receiver, NoEscapeForStringBufferReference)) { 2419 invoke->GetBlock()->RemoveInstruction(invoke); 2420 RecordSimplification(); 2421 } 2422 } 2423 } 2424 2425 void InstructionSimplifierVisitor::SimplifyMemBarrier(HInvoke* invoke, 2426 MemBarrierKind barrier_kind) { 2427 uint32_t dex_pc = invoke->GetDexPc(); 2428 HMemoryBarrier* mem_barrier = 2429 new (GetGraph()->GetAllocator()) HMemoryBarrier(barrier_kind, dex_pc); 2430 invoke->GetBlock()->ReplaceAndRemoveInstructionWith(invoke, mem_barrier); 2431 } 2432 2433 void InstructionSimplifierVisitor::VisitInvoke(HInvoke* instruction) { 2434 switch (instruction->GetIntrinsic()) { 2435 case Intrinsics::kStringEquals: 2436 SimplifyStringEquals(instruction); 2437 break; 2438 case Intrinsics::kSystemArrayCopy: 2439 SimplifySystemArrayCopy(instruction); 2440 break; 2441 case Intrinsics::kIntegerRotateRight: 2442 SimplifyRotate(instruction, /* is_left */ false, DataType::Type::kInt32); 2443 break; 2444 case Intrinsics::kLongRotateRight: 2445 SimplifyRotate(instruction, /* is_left */ false, DataType::Type::kInt64); 2446 break; 2447 case Intrinsics::kIntegerRotateLeft: 2448 SimplifyRotate(instruction, /* is_left */ true, DataType::Type::kInt32); 2449 break; 2450 case Intrinsics::kLongRotateLeft: 2451 SimplifyRotate(instruction, /* is_left */ true, DataType::Type::kInt64); 2452 break; 2453 case Intrinsics::kIntegerCompare: 2454 SimplifyCompare(instruction, /* is_signum */ false, DataType::Type::kInt32); 2455 break; 2456 case Intrinsics::kLongCompare: 2457 SimplifyCompare(instruction, /* is_signum */ false, DataType::Type::kInt64); 2458 break; 2459 case Intrinsics::kIntegerSignum: 2460 SimplifyCompare(instruction, /* is_signum */ true, DataType::Type::kInt32); 2461 break; 2462 case Intrinsics::kLongSignum: 2463 SimplifyCompare(instruction, /* is_signum */ true, DataType::Type::kInt64); 2464 break; 2465 case Intrinsics::kFloatIsNaN: 2466 case Intrinsics::kDoubleIsNaN: 2467 SimplifyIsNaN(instruction); 2468 break; 2469 case Intrinsics::kFloatFloatToIntBits: 2470 case Intrinsics::kDoubleDoubleToLongBits: 2471 SimplifyFP2Int(instruction); 2472 break; 2473 case Intrinsics::kStringCharAt: 2474 SimplifyStringCharAt(instruction); 2475 break; 2476 case Intrinsics::kStringIsEmpty: 2477 case Intrinsics::kStringLength: 2478 SimplifyStringIsEmptyOrLength(instruction); 2479 break; 2480 case Intrinsics::kStringStringIndexOf: 2481 case Intrinsics::kStringStringIndexOfAfter: 2482 SimplifyNPEOnArgN(instruction, 1); // 0th has own NullCheck 2483 break; 2484 case Intrinsics::kStringBufferAppend: 2485 case Intrinsics::kStringBuilderAppend: 2486 SimplifyReturnThis(instruction); 2487 break; 2488 case Intrinsics::kStringBufferToString: 2489 case Intrinsics::kStringBuilderToString: 2490 SimplifyAllocationIntrinsic(instruction); 2491 break; 2492 case Intrinsics::kUnsafeLoadFence: 2493 SimplifyMemBarrier(instruction, MemBarrierKind::kLoadAny); 2494 break; 2495 case Intrinsics::kUnsafeStoreFence: 2496 SimplifyMemBarrier(instruction, MemBarrierKind::kAnyStore); 2497 break; 2498 case Intrinsics::kUnsafeFullFence: 2499 SimplifyMemBarrier(instruction, MemBarrierKind::kAnyAny); 2500 break; 2501 case Intrinsics::kVarHandleFullFence: 2502 SimplifyMemBarrier(instruction, MemBarrierKind::kAnyAny); 2503 break; 2504 case Intrinsics::kVarHandleAcquireFence: 2505 SimplifyMemBarrier(instruction, MemBarrierKind::kLoadAny); 2506 break; 2507 case Intrinsics::kVarHandleReleaseFence: 2508 SimplifyMemBarrier(instruction, MemBarrierKind::kAnyStore); 2509 break; 2510 case Intrinsics::kVarHandleLoadLoadFence: 2511 SimplifyMemBarrier(instruction, MemBarrierKind::kLoadAny); 2512 break; 2513 case Intrinsics::kVarHandleStoreStoreFence: 2514 SimplifyMemBarrier(instruction, MemBarrierKind::kStoreStore); 2515 break; 2516 default: 2517 break; 2518 } 2519 } 2520 2521 void InstructionSimplifierVisitor::VisitDeoptimize(HDeoptimize* deoptimize) { 2522 HInstruction* cond = deoptimize->InputAt(0); 2523 if (cond->IsConstant()) { 2524 if (cond->AsIntConstant()->IsFalse()) { 2525 // Never deopt: instruction can be removed. 2526 if (deoptimize->GuardsAnInput()) { 2527 deoptimize->ReplaceWith(deoptimize->GuardedInput()); 2528 } 2529 deoptimize->GetBlock()->RemoveInstruction(deoptimize); 2530 } else { 2531 // Always deopt. 2532 } 2533 } 2534 } 2535 2536 // Replace code looking like 2537 // OP y, x, const1 2538 // OP z, y, const2 2539 // with 2540 // OP z, x, const3 2541 // where OP is both an associative and a commutative operation. 2542 bool InstructionSimplifierVisitor::TryHandleAssociativeAndCommutativeOperation( 2543 HBinaryOperation* instruction) { 2544 DCHECK(instruction->IsCommutative()); 2545 2546 if (!DataType::IsIntegralType(instruction->GetType())) { 2547 return false; 2548 } 2549 2550 HInstruction* left = instruction->GetLeft(); 2551 HInstruction* right = instruction->GetRight(); 2552 // Variable names as described above. 2553 HConstant* const2; 2554 HBinaryOperation* y; 2555 2556 if (instruction->InstructionTypeEquals(left) && right->IsConstant()) { 2557 const2 = right->AsConstant(); 2558 y = left->AsBinaryOperation(); 2559 } else if (left->IsConstant() && instruction->InstructionTypeEquals(right)) { 2560 const2 = left->AsConstant(); 2561 y = right->AsBinaryOperation(); 2562 } else { 2563 // The node does not match the pattern. 2564 return false; 2565 } 2566 2567 // If `y` has more than one use, we do not perform the optimization 2568 // because it might increase code size (e.g. if the new constant is 2569 // no longer encodable as an immediate operand in the target ISA). 2570 if (!y->HasOnlyOneNonEnvironmentUse()) { 2571 return false; 2572 } 2573 2574 // GetConstantRight() can return both left and right constants 2575 // for commutative operations. 2576 HConstant* const1 = y->GetConstantRight(); 2577 if (const1 == nullptr) { 2578 return false; 2579 } 2580 2581 instruction->ReplaceInput(const1, 0); 2582 instruction->ReplaceInput(const2, 1); 2583 HConstant* const3 = instruction->TryStaticEvaluation(); 2584 DCHECK(const3 != nullptr); 2585 instruction->ReplaceInput(y->GetLeastConstantLeft(), 0); 2586 instruction->ReplaceInput(const3, 1); 2587 RecordSimplification(); 2588 return true; 2589 } 2590 2591 static HBinaryOperation* AsAddOrSub(HInstruction* binop) { 2592 return (binop->IsAdd() || binop->IsSub()) ? binop->AsBinaryOperation() : nullptr; 2593 } 2594 2595 // Helper function that performs addition statically, considering the result type. 2596 static int64_t ComputeAddition(DataType::Type type, int64_t x, int64_t y) { 2597 // Use the Compute() method for consistency with TryStaticEvaluation(). 2598 if (type == DataType::Type::kInt32) { 2599 return HAdd::Compute<int32_t>(x, y); 2600 } else { 2601 DCHECK_EQ(type, DataType::Type::kInt64); 2602 return HAdd::Compute<int64_t>(x, y); 2603 } 2604 } 2605 2606 // Helper function that handles the child classes of HConstant 2607 // and returns an integer with the appropriate sign. 2608 static int64_t GetValue(HConstant* constant, bool is_negated) { 2609 int64_t ret = Int64FromConstant(constant); 2610 return is_negated ? -ret : ret; 2611 } 2612 2613 // Replace code looking like 2614 // OP1 y, x, const1 2615 // OP2 z, y, const2 2616 // with 2617 // OP3 z, x, const3 2618 // where OPx is either ADD or SUB, and at least one of OP{1,2} is SUB. 2619 bool InstructionSimplifierVisitor::TrySubtractionChainSimplification( 2620 HBinaryOperation* instruction) { 2621 DCHECK(instruction->IsAdd() || instruction->IsSub()) << instruction->DebugName(); 2622 2623 DataType::Type type = instruction->GetType(); 2624 if (!DataType::IsIntegralType(type)) { 2625 return false; 2626 } 2627 2628 HInstruction* left = instruction->GetLeft(); 2629 HInstruction* right = instruction->GetRight(); 2630 // Variable names as described above. 2631 HConstant* const2 = right->IsConstant() ? right->AsConstant() : left->AsConstant(); 2632 if (const2 == nullptr) { 2633 return false; 2634 } 2635 2636 HBinaryOperation* y = (AsAddOrSub(left) != nullptr) 2637 ? left->AsBinaryOperation() 2638 : AsAddOrSub(right); 2639 // If y has more than one use, we do not perform the optimization because 2640 // it might increase code size (e.g. if the new constant is no longer 2641 // encodable as an immediate operand in the target ISA). 2642 if ((y == nullptr) || !y->HasOnlyOneNonEnvironmentUse()) { 2643 return false; 2644 } 2645 2646 left = y->GetLeft(); 2647 HConstant* const1 = left->IsConstant() ? left->AsConstant() : y->GetRight()->AsConstant(); 2648 if (const1 == nullptr) { 2649 return false; 2650 } 2651 2652 HInstruction* x = (const1 == left) ? y->GetRight() : left; 2653 // If both inputs are constants, let the constant folding pass deal with it. 2654 if (x->IsConstant()) { 2655 return false; 2656 } 2657 2658 bool is_const2_negated = (const2 == right) && instruction->IsSub(); 2659 int64_t const2_val = GetValue(const2, is_const2_negated); 2660 bool is_y_negated = (y == right) && instruction->IsSub(); 2661 right = y->GetRight(); 2662 bool is_const1_negated = is_y_negated ^ ((const1 == right) && y->IsSub()); 2663 int64_t const1_val = GetValue(const1, is_const1_negated); 2664 bool is_x_negated = is_y_negated ^ ((x == right) && y->IsSub()); 2665 int64_t const3_val = ComputeAddition(type, const1_val, const2_val); 2666 HBasicBlock* block = instruction->GetBlock(); 2667 HConstant* const3 = block->GetGraph()->GetConstant(type, const3_val); 2668 ArenaAllocator* allocator = instruction->GetAllocator(); 2669 HInstruction* z; 2670 2671 if (is_x_negated) { 2672 z = new (allocator) HSub(type, const3, x, instruction->GetDexPc()); 2673 } else { 2674 z = new (allocator) HAdd(type, x, const3, instruction->GetDexPc()); 2675 } 2676 2677 block->ReplaceAndRemoveInstructionWith(instruction, z); 2678 RecordSimplification(); 2679 return true; 2680 } 2681 2682 void InstructionSimplifierVisitor::VisitVecMul(HVecMul* instruction) { 2683 if (TryCombineVecMultiplyAccumulate(instruction)) { 2684 RecordSimplification(); 2685 } 2686 } 2687 2688 } // namespace art 2689