1 // Copyright 2014 the V8 project authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "src/base/adapters.h" 6 #include "src/base/bits.h" 7 #include "src/compiler/instruction-selector-impl.h" 8 #include "src/compiler/node-matchers.h" 9 #include "src/compiler/node-properties.h" 10 11 namespace v8 { 12 namespace internal { 13 namespace compiler { 14 15 // Adds Arm-specific methods for generating InstructionOperands. 16 class ArmOperandGenerator : public OperandGenerator { 17 public: 18 explicit ArmOperandGenerator(InstructionSelector* selector) 19 : OperandGenerator(selector) {} 20 21 bool CanBeImmediate(int32_t value) const { 22 return Assembler::ImmediateFitsAddrMode1Instruction(value); 23 } 24 25 bool CanBeImmediate(uint32_t value) const { 26 return CanBeImmediate(bit_cast<int32_t>(value)); 27 } 28 29 bool CanBeImmediate(Node* node, InstructionCode opcode) { 30 Int32Matcher m(node); 31 if (!m.HasValue()) return false; 32 int32_t value = m.Value(); 33 switch (ArchOpcodeField::decode(opcode)) { 34 case kArmAnd: 35 case kArmMov: 36 case kArmMvn: 37 case kArmBic: 38 return CanBeImmediate(value) || CanBeImmediate(~value); 39 40 case kArmAdd: 41 case kArmSub: 42 case kArmCmp: 43 case kArmCmn: 44 return CanBeImmediate(value) || CanBeImmediate(-value); 45 46 case kArmTst: 47 case kArmTeq: 48 case kArmOrr: 49 case kArmEor: 50 case kArmRsb: 51 return CanBeImmediate(value); 52 53 case kArmVldrF32: 54 case kArmVstrF32: 55 case kArmVldrF64: 56 case kArmVstrF64: 57 return value >= -1020 && value <= 1020 && (value % 4) == 0; 58 59 case kArmLdrb: 60 case kArmLdrsb: 61 case kArmStrb: 62 case kArmLdr: 63 case kArmStr: 64 return value >= -4095 && value <= 4095; 65 66 case kArmLdrh: 67 case kArmLdrsh: 68 case kArmStrh: 69 return value >= -255 && value <= 255; 70 71 default: 72 break; 73 } 74 return false; 75 } 76 }; 77 78 79 namespace { 80 81 void VisitRR(InstructionSelector* selector, ArchOpcode opcode, Node* node) { 82 ArmOperandGenerator g(selector); 83 selector->Emit(opcode, g.DefineAsRegister(node), 84 g.UseRegister(node->InputAt(0))); 85 } 86 87 88 void VisitRRR(InstructionSelector* selector, ArchOpcode opcode, Node* node) { 89 ArmOperandGenerator g(selector); 90 selector->Emit(opcode, g.DefineAsRegister(node), 91 g.UseRegister(node->InputAt(0)), 92 g.UseRegister(node->InputAt(1))); 93 } 94 95 96 template <IrOpcode::Value kOpcode, int kImmMin, int kImmMax, 97 AddressingMode kImmMode, AddressingMode kRegMode> 98 bool TryMatchShift(InstructionSelector* selector, 99 InstructionCode* opcode_return, Node* node, 100 InstructionOperand* value_return, 101 InstructionOperand* shift_return) { 102 ArmOperandGenerator g(selector); 103 if (node->opcode() == kOpcode) { 104 Int32BinopMatcher m(node); 105 *value_return = g.UseRegister(m.left().node()); 106 if (m.right().IsInRange(kImmMin, kImmMax)) { 107 *opcode_return |= AddressingModeField::encode(kImmMode); 108 *shift_return = g.UseImmediate(m.right().node()); 109 } else { 110 *opcode_return |= AddressingModeField::encode(kRegMode); 111 *shift_return = g.UseRegister(m.right().node()); 112 } 113 return true; 114 } 115 return false; 116 } 117 118 119 bool TryMatchROR(InstructionSelector* selector, InstructionCode* opcode_return, 120 Node* node, InstructionOperand* value_return, 121 InstructionOperand* shift_return) { 122 return TryMatchShift<IrOpcode::kWord32Ror, 1, 31, kMode_Operand2_R_ROR_I, 123 kMode_Operand2_R_ROR_R>(selector, opcode_return, node, 124 value_return, shift_return); 125 } 126 127 128 bool TryMatchASR(InstructionSelector* selector, InstructionCode* opcode_return, 129 Node* node, InstructionOperand* value_return, 130 InstructionOperand* shift_return) { 131 return TryMatchShift<IrOpcode::kWord32Sar, 1, 32, kMode_Operand2_R_ASR_I, 132 kMode_Operand2_R_ASR_R>(selector, opcode_return, node, 133 value_return, shift_return); 134 } 135 136 137 bool TryMatchLSL(InstructionSelector* selector, InstructionCode* opcode_return, 138 Node* node, InstructionOperand* value_return, 139 InstructionOperand* shift_return) { 140 return TryMatchShift<IrOpcode::kWord32Shl, 0, 31, kMode_Operand2_R_LSL_I, 141 kMode_Operand2_R_LSL_R>(selector, opcode_return, node, 142 value_return, shift_return); 143 } 144 145 146 bool TryMatchLSR(InstructionSelector* selector, InstructionCode* opcode_return, 147 Node* node, InstructionOperand* value_return, 148 InstructionOperand* shift_return) { 149 return TryMatchShift<IrOpcode::kWord32Shr, 1, 32, kMode_Operand2_R_LSR_I, 150 kMode_Operand2_R_LSR_R>(selector, opcode_return, node, 151 value_return, shift_return); 152 } 153 154 155 bool TryMatchShift(InstructionSelector* selector, 156 InstructionCode* opcode_return, Node* node, 157 InstructionOperand* value_return, 158 InstructionOperand* shift_return) { 159 return ( 160 TryMatchASR(selector, opcode_return, node, value_return, shift_return) || 161 TryMatchLSL(selector, opcode_return, node, value_return, shift_return) || 162 TryMatchLSR(selector, opcode_return, node, value_return, shift_return) || 163 TryMatchROR(selector, opcode_return, node, value_return, shift_return)); 164 } 165 166 167 bool TryMatchImmediateOrShift(InstructionSelector* selector, 168 InstructionCode* opcode_return, Node* node, 169 size_t* input_count_return, 170 InstructionOperand* inputs) { 171 ArmOperandGenerator g(selector); 172 if (g.CanBeImmediate(node, *opcode_return)) { 173 *opcode_return |= AddressingModeField::encode(kMode_Operand2_I); 174 inputs[0] = g.UseImmediate(node); 175 *input_count_return = 1; 176 return true; 177 } 178 if (TryMatchShift(selector, opcode_return, node, &inputs[0], &inputs[1])) { 179 *input_count_return = 2; 180 return true; 181 } 182 return false; 183 } 184 185 186 void VisitBinop(InstructionSelector* selector, Node* node, 187 InstructionCode opcode, InstructionCode reverse_opcode, 188 FlagsContinuation* cont) { 189 ArmOperandGenerator g(selector); 190 Int32BinopMatcher m(node); 191 InstructionOperand inputs[5]; 192 size_t input_count = 0; 193 InstructionOperand outputs[2]; 194 size_t output_count = 0; 195 196 if (m.left().node() == m.right().node()) { 197 // If both inputs refer to the same operand, enforce allocating a register 198 // for both of them to ensure that we don't end up generating code like 199 // this: 200 // 201 // mov r0, r1, asr #16 202 // adds r0, r0, r1, asr #16 203 // bvs label 204 InstructionOperand const input = g.UseRegister(m.left().node()); 205 opcode |= AddressingModeField::encode(kMode_Operand2_R); 206 inputs[input_count++] = input; 207 inputs[input_count++] = input; 208 } else if (TryMatchImmediateOrShift(selector, &opcode, m.right().node(), 209 &input_count, &inputs[1])) { 210 inputs[0] = g.UseRegister(m.left().node()); 211 input_count++; 212 } else if (TryMatchImmediateOrShift(selector, &reverse_opcode, 213 m.left().node(), &input_count, 214 &inputs[1])) { 215 inputs[0] = g.UseRegister(m.right().node()); 216 opcode = reverse_opcode; 217 input_count++; 218 } else { 219 opcode |= AddressingModeField::encode(kMode_Operand2_R); 220 inputs[input_count++] = g.UseRegister(m.left().node()); 221 inputs[input_count++] = g.UseRegister(m.right().node()); 222 } 223 224 if (cont->IsBranch()) { 225 inputs[input_count++] = g.Label(cont->true_block()); 226 inputs[input_count++] = g.Label(cont->false_block()); 227 } 228 229 outputs[output_count++] = g.DefineAsRegister(node); 230 if (cont->IsSet()) { 231 outputs[output_count++] = g.DefineAsRegister(cont->result()); 232 } 233 234 DCHECK_NE(0u, input_count); 235 DCHECK_NE(0u, output_count); 236 DCHECK_GE(arraysize(inputs), input_count); 237 DCHECK_GE(arraysize(outputs), output_count); 238 DCHECK_NE(kMode_None, AddressingModeField::decode(opcode)); 239 240 selector->Emit(cont->Encode(opcode), output_count, outputs, input_count, 241 inputs); 242 } 243 244 245 void VisitBinop(InstructionSelector* selector, Node* node, 246 InstructionCode opcode, InstructionCode reverse_opcode) { 247 FlagsContinuation cont; 248 VisitBinop(selector, node, opcode, reverse_opcode, &cont); 249 } 250 251 252 void EmitDiv(InstructionSelector* selector, ArchOpcode div_opcode, 253 ArchOpcode f64i32_opcode, ArchOpcode i32f64_opcode, 254 InstructionOperand result_operand, InstructionOperand left_operand, 255 InstructionOperand right_operand) { 256 ArmOperandGenerator g(selector); 257 if (selector->IsSupported(SUDIV)) { 258 selector->Emit(div_opcode, result_operand, left_operand, right_operand); 259 return; 260 } 261 InstructionOperand left_double_operand = g.TempDoubleRegister(); 262 InstructionOperand right_double_operand = g.TempDoubleRegister(); 263 InstructionOperand result_double_operand = g.TempDoubleRegister(); 264 selector->Emit(f64i32_opcode, left_double_operand, left_operand); 265 selector->Emit(f64i32_opcode, right_double_operand, right_operand); 266 selector->Emit(kArmVdivF64, result_double_operand, left_double_operand, 267 right_double_operand); 268 selector->Emit(i32f64_opcode, result_operand, result_double_operand); 269 } 270 271 272 void VisitDiv(InstructionSelector* selector, Node* node, ArchOpcode div_opcode, 273 ArchOpcode f64i32_opcode, ArchOpcode i32f64_opcode) { 274 ArmOperandGenerator g(selector); 275 Int32BinopMatcher m(node); 276 EmitDiv(selector, div_opcode, f64i32_opcode, i32f64_opcode, 277 g.DefineAsRegister(node), g.UseRegister(m.left().node()), 278 g.UseRegister(m.right().node())); 279 } 280 281 282 void VisitMod(InstructionSelector* selector, Node* node, ArchOpcode div_opcode, 283 ArchOpcode f64i32_opcode, ArchOpcode i32f64_opcode) { 284 ArmOperandGenerator g(selector); 285 Int32BinopMatcher m(node); 286 InstructionOperand div_operand = g.TempRegister(); 287 InstructionOperand result_operand = g.DefineAsRegister(node); 288 InstructionOperand left_operand = g.UseRegister(m.left().node()); 289 InstructionOperand right_operand = g.UseRegister(m.right().node()); 290 EmitDiv(selector, div_opcode, f64i32_opcode, i32f64_opcode, div_operand, 291 left_operand, right_operand); 292 if (selector->IsSupported(MLS)) { 293 selector->Emit(kArmMls, result_operand, div_operand, right_operand, 294 left_operand); 295 } else { 296 InstructionOperand mul_operand = g.TempRegister(); 297 selector->Emit(kArmMul, mul_operand, div_operand, right_operand); 298 selector->Emit(kArmSub, result_operand, left_operand, mul_operand); 299 } 300 } 301 302 } // namespace 303 304 305 void InstructionSelector::VisitLoad(Node* node) { 306 LoadRepresentation load_rep = LoadRepresentationOf(node->op()); 307 ArmOperandGenerator g(this); 308 Node* base = node->InputAt(0); 309 Node* index = node->InputAt(1); 310 311 ArchOpcode opcode = kArchNop; 312 switch (load_rep.representation()) { 313 case MachineRepresentation::kFloat32: 314 opcode = kArmVldrF32; 315 break; 316 case MachineRepresentation::kFloat64: 317 opcode = kArmVldrF64; 318 break; 319 case MachineRepresentation::kBit: // Fall through. 320 case MachineRepresentation::kWord8: 321 opcode = load_rep.IsUnsigned() ? kArmLdrb : kArmLdrsb; 322 break; 323 case MachineRepresentation::kWord16: 324 opcode = load_rep.IsUnsigned() ? kArmLdrh : kArmLdrsh; 325 break; 326 case MachineRepresentation::kTagged: // Fall through. 327 case MachineRepresentation::kWord32: 328 opcode = kArmLdr; 329 break; 330 case MachineRepresentation::kNone: // Fall through. 331 case MachineRepresentation::kWord64: 332 UNREACHABLE(); 333 return; 334 } 335 336 if (g.CanBeImmediate(index, opcode)) { 337 Emit(opcode | AddressingModeField::encode(kMode_Offset_RI), 338 g.DefineAsRegister(node), g.UseRegister(base), g.UseImmediate(index)); 339 } else { 340 Emit(opcode | AddressingModeField::encode(kMode_Offset_RR), 341 g.DefineAsRegister(node), g.UseRegister(base), g.UseRegister(index)); 342 } 343 } 344 345 346 void InstructionSelector::VisitStore(Node* node) { 347 ArmOperandGenerator g(this); 348 Node* base = node->InputAt(0); 349 Node* index = node->InputAt(1); 350 Node* value = node->InputAt(2); 351 352 StoreRepresentation store_rep = StoreRepresentationOf(node->op()); 353 WriteBarrierKind write_barrier_kind = store_rep.write_barrier_kind(); 354 MachineRepresentation rep = store_rep.representation(); 355 356 if (write_barrier_kind != kNoWriteBarrier) { 357 DCHECK_EQ(MachineRepresentation::kTagged, rep); 358 InstructionOperand inputs[3]; 359 size_t input_count = 0; 360 inputs[input_count++] = g.UseUniqueRegister(base); 361 inputs[input_count++] = g.UseUniqueRegister(index); 362 inputs[input_count++] = (write_barrier_kind == kMapWriteBarrier) 363 ? g.UseRegister(value) 364 : g.UseUniqueRegister(value); 365 RecordWriteMode record_write_mode = RecordWriteMode::kValueIsAny; 366 switch (write_barrier_kind) { 367 case kNoWriteBarrier: 368 UNREACHABLE(); 369 break; 370 case kMapWriteBarrier: 371 record_write_mode = RecordWriteMode::kValueIsMap; 372 break; 373 case kPointerWriteBarrier: 374 record_write_mode = RecordWriteMode::kValueIsPointer; 375 break; 376 case kFullWriteBarrier: 377 record_write_mode = RecordWriteMode::kValueIsAny; 378 break; 379 } 380 InstructionOperand temps[] = {g.TempRegister(), g.TempRegister()}; 381 size_t const temp_count = arraysize(temps); 382 InstructionCode code = kArchStoreWithWriteBarrier; 383 code |= MiscField::encode(static_cast<int>(record_write_mode)); 384 Emit(code, 0, nullptr, input_count, inputs, temp_count, temps); 385 } else { 386 ArchOpcode opcode = kArchNop; 387 switch (rep) { 388 case MachineRepresentation::kFloat32: 389 opcode = kArmVstrF32; 390 break; 391 case MachineRepresentation::kFloat64: 392 opcode = kArmVstrF64; 393 break; 394 case MachineRepresentation::kBit: // Fall through. 395 case MachineRepresentation::kWord8: 396 opcode = kArmStrb; 397 break; 398 case MachineRepresentation::kWord16: 399 opcode = kArmStrh; 400 break; 401 case MachineRepresentation::kTagged: // Fall through. 402 case MachineRepresentation::kWord32: 403 opcode = kArmStr; 404 break; 405 case MachineRepresentation::kNone: // Fall through. 406 case MachineRepresentation::kWord64: 407 UNREACHABLE(); 408 return; 409 } 410 411 if (g.CanBeImmediate(index, opcode)) { 412 Emit(opcode | AddressingModeField::encode(kMode_Offset_RI), g.NoOutput(), 413 g.UseRegister(base), g.UseImmediate(index), g.UseRegister(value)); 414 } else { 415 Emit(opcode | AddressingModeField::encode(kMode_Offset_RR), g.NoOutput(), 416 g.UseRegister(base), g.UseRegister(index), g.UseRegister(value)); 417 } 418 } 419 } 420 421 422 void InstructionSelector::VisitCheckedLoad(Node* node) { 423 CheckedLoadRepresentation load_rep = CheckedLoadRepresentationOf(node->op()); 424 ArmOperandGenerator g(this); 425 Node* const buffer = node->InputAt(0); 426 Node* const offset = node->InputAt(1); 427 Node* const length = node->InputAt(2); 428 ArchOpcode opcode = kArchNop; 429 switch (load_rep.representation()) { 430 case MachineRepresentation::kWord8: 431 opcode = load_rep.IsSigned() ? kCheckedLoadInt8 : kCheckedLoadUint8; 432 break; 433 case MachineRepresentation::kWord16: 434 opcode = load_rep.IsSigned() ? kCheckedLoadInt16 : kCheckedLoadUint16; 435 break; 436 case MachineRepresentation::kWord32: 437 opcode = kCheckedLoadWord32; 438 break; 439 case MachineRepresentation::kFloat32: 440 opcode = kCheckedLoadFloat32; 441 break; 442 case MachineRepresentation::kFloat64: 443 opcode = kCheckedLoadFloat64; 444 break; 445 case MachineRepresentation::kBit: // Fall through. 446 case MachineRepresentation::kTagged: // Fall through. 447 case MachineRepresentation::kWord64: // Fall through. 448 case MachineRepresentation::kNone: 449 UNREACHABLE(); 450 return; 451 } 452 InstructionOperand offset_operand = g.UseRegister(offset); 453 InstructionOperand length_operand = g.CanBeImmediate(length, kArmCmp) 454 ? g.UseImmediate(length) 455 : g.UseRegister(length); 456 Emit(opcode | AddressingModeField::encode(kMode_Offset_RR), 457 g.DefineAsRegister(node), offset_operand, length_operand, 458 g.UseRegister(buffer), offset_operand); 459 } 460 461 462 void InstructionSelector::VisitCheckedStore(Node* node) { 463 MachineRepresentation rep = CheckedStoreRepresentationOf(node->op()); 464 ArmOperandGenerator g(this); 465 Node* const buffer = node->InputAt(0); 466 Node* const offset = node->InputAt(1); 467 Node* const length = node->InputAt(2); 468 Node* const value = node->InputAt(3); 469 ArchOpcode opcode = kArchNop; 470 switch (rep) { 471 case MachineRepresentation::kWord8: 472 opcode = kCheckedStoreWord8; 473 break; 474 case MachineRepresentation::kWord16: 475 opcode = kCheckedStoreWord16; 476 break; 477 case MachineRepresentation::kWord32: 478 opcode = kCheckedStoreWord32; 479 break; 480 case MachineRepresentation::kFloat32: 481 opcode = kCheckedStoreFloat32; 482 break; 483 case MachineRepresentation::kFloat64: 484 opcode = kCheckedStoreFloat64; 485 break; 486 case MachineRepresentation::kBit: // Fall through. 487 case MachineRepresentation::kTagged: // Fall through. 488 case MachineRepresentation::kWord64: // Fall through. 489 case MachineRepresentation::kNone: 490 UNREACHABLE(); 491 return; 492 } 493 InstructionOperand offset_operand = g.UseRegister(offset); 494 InstructionOperand length_operand = g.CanBeImmediate(length, kArmCmp) 495 ? g.UseImmediate(length) 496 : g.UseRegister(length); 497 Emit(opcode | AddressingModeField::encode(kMode_Offset_RR), g.NoOutput(), 498 offset_operand, length_operand, g.UseRegister(value), 499 g.UseRegister(buffer), offset_operand); 500 } 501 502 503 namespace { 504 505 void EmitBic(InstructionSelector* selector, Node* node, Node* left, 506 Node* right) { 507 ArmOperandGenerator g(selector); 508 InstructionCode opcode = kArmBic; 509 InstructionOperand value_operand; 510 InstructionOperand shift_operand; 511 if (TryMatchShift(selector, &opcode, right, &value_operand, &shift_operand)) { 512 selector->Emit(opcode, g.DefineAsRegister(node), g.UseRegister(left), 513 value_operand, shift_operand); 514 return; 515 } 516 selector->Emit(opcode | AddressingModeField::encode(kMode_Operand2_R), 517 g.DefineAsRegister(node), g.UseRegister(left), 518 g.UseRegister(right)); 519 } 520 521 522 void EmitUbfx(InstructionSelector* selector, Node* node, Node* left, 523 uint32_t lsb, uint32_t width) { 524 DCHECK_LE(1u, width); 525 DCHECK_LE(width, 32u - lsb); 526 ArmOperandGenerator g(selector); 527 selector->Emit(kArmUbfx, g.DefineAsRegister(node), g.UseRegister(left), 528 g.TempImmediate(lsb), g.TempImmediate(width)); 529 } 530 531 } // namespace 532 533 534 void InstructionSelector::VisitWord32And(Node* node) { 535 ArmOperandGenerator g(this); 536 Int32BinopMatcher m(node); 537 if (m.left().IsWord32Xor() && CanCover(node, m.left().node())) { 538 Int32BinopMatcher mleft(m.left().node()); 539 if (mleft.right().Is(-1)) { 540 EmitBic(this, node, m.right().node(), mleft.left().node()); 541 return; 542 } 543 } 544 if (m.right().IsWord32Xor() && CanCover(node, m.right().node())) { 545 Int32BinopMatcher mright(m.right().node()); 546 if (mright.right().Is(-1)) { 547 EmitBic(this, node, m.left().node(), mright.left().node()); 548 return; 549 } 550 } 551 if (m.right().HasValue()) { 552 uint32_t const value = m.right().Value(); 553 uint32_t width = base::bits::CountPopulation32(value); 554 uint32_t msb = base::bits::CountLeadingZeros32(value); 555 // Try to interpret this AND as UBFX. 556 if (IsSupported(ARMv7) && width != 0 && msb + width == 32) { 557 DCHECK_EQ(0u, base::bits::CountTrailingZeros32(value)); 558 if (m.left().IsWord32Shr()) { 559 Int32BinopMatcher mleft(m.left().node()); 560 if (mleft.right().IsInRange(0, 31)) { 561 // UBFX cannot extract bits past the register size, however since 562 // shifting the original value would have introduced some zeros we can 563 // still use UBFX with a smaller mask and the remaining bits will be 564 // zeros. 565 uint32_t const lsb = mleft.right().Value(); 566 return EmitUbfx(this, node, mleft.left().node(), lsb, 567 std::min(width, 32 - lsb)); 568 } 569 } 570 return EmitUbfx(this, node, m.left().node(), 0, width); 571 } 572 // Try to interpret this AND as BIC. 573 if (g.CanBeImmediate(~value)) { 574 Emit(kArmBic | AddressingModeField::encode(kMode_Operand2_I), 575 g.DefineAsRegister(node), g.UseRegister(m.left().node()), 576 g.TempImmediate(~value)); 577 return; 578 } 579 // Try to interpret this AND as UXTH. 580 if (value == 0xffff) { 581 Emit(kArmUxth, g.DefineAsRegister(m.node()), 582 g.UseRegister(m.left().node()), g.TempImmediate(0)); 583 return; 584 } 585 // Try to interpret this AND as BFC. 586 if (IsSupported(ARMv7)) { 587 width = 32 - width; 588 msb = base::bits::CountLeadingZeros32(~value); 589 uint32_t lsb = base::bits::CountTrailingZeros32(~value); 590 if (msb + width + lsb == 32) { 591 Emit(kArmBfc, g.DefineSameAsFirst(node), g.UseRegister(m.left().node()), 592 g.TempImmediate(lsb), g.TempImmediate(width)); 593 return; 594 } 595 } 596 } 597 VisitBinop(this, node, kArmAnd, kArmAnd); 598 } 599 600 601 void InstructionSelector::VisitWord32Or(Node* node) { 602 VisitBinop(this, node, kArmOrr, kArmOrr); 603 } 604 605 606 void InstructionSelector::VisitWord32Xor(Node* node) { 607 ArmOperandGenerator g(this); 608 Int32BinopMatcher m(node); 609 if (m.right().Is(-1)) { 610 InstructionCode opcode = kArmMvn; 611 InstructionOperand value_operand; 612 InstructionOperand shift_operand; 613 if (TryMatchShift(this, &opcode, m.left().node(), &value_operand, 614 &shift_operand)) { 615 Emit(opcode, g.DefineAsRegister(node), value_operand, shift_operand); 616 return; 617 } 618 Emit(opcode | AddressingModeField::encode(kMode_Operand2_R), 619 g.DefineAsRegister(node), g.UseRegister(m.left().node())); 620 return; 621 } 622 VisitBinop(this, node, kArmEor, kArmEor); 623 } 624 625 626 namespace { 627 628 template <typename TryMatchShift> 629 void VisitShift(InstructionSelector* selector, Node* node, 630 TryMatchShift try_match_shift, FlagsContinuation* cont) { 631 ArmOperandGenerator g(selector); 632 InstructionCode opcode = kArmMov; 633 InstructionOperand inputs[4]; 634 size_t input_count = 2; 635 InstructionOperand outputs[2]; 636 size_t output_count = 0; 637 638 CHECK(try_match_shift(selector, &opcode, node, &inputs[0], &inputs[1])); 639 640 if (cont->IsBranch()) { 641 inputs[input_count++] = g.Label(cont->true_block()); 642 inputs[input_count++] = g.Label(cont->false_block()); 643 } 644 645 outputs[output_count++] = g.DefineAsRegister(node); 646 if (cont->IsSet()) { 647 outputs[output_count++] = g.DefineAsRegister(cont->result()); 648 } 649 650 DCHECK_NE(0u, input_count); 651 DCHECK_NE(0u, output_count); 652 DCHECK_GE(arraysize(inputs), input_count); 653 DCHECK_GE(arraysize(outputs), output_count); 654 DCHECK_NE(kMode_None, AddressingModeField::decode(opcode)); 655 656 selector->Emit(cont->Encode(opcode), output_count, outputs, input_count, 657 inputs); 658 } 659 660 661 template <typename TryMatchShift> 662 void VisitShift(InstructionSelector* selector, Node* node, 663 TryMatchShift try_match_shift) { 664 FlagsContinuation cont; 665 VisitShift(selector, node, try_match_shift, &cont); 666 } 667 668 } // namespace 669 670 671 void InstructionSelector::VisitWord32Shl(Node* node) { 672 VisitShift(this, node, TryMatchLSL); 673 } 674 675 676 void InstructionSelector::VisitWord32Shr(Node* node) { 677 ArmOperandGenerator g(this); 678 Int32BinopMatcher m(node); 679 if (IsSupported(ARMv7) && m.left().IsWord32And() && 680 m.right().IsInRange(0, 31)) { 681 uint32_t lsb = m.right().Value(); 682 Int32BinopMatcher mleft(m.left().node()); 683 if (mleft.right().HasValue()) { 684 uint32_t value = (mleft.right().Value() >> lsb) << lsb; 685 uint32_t width = base::bits::CountPopulation32(value); 686 uint32_t msb = base::bits::CountLeadingZeros32(value); 687 if (msb + width + lsb == 32) { 688 DCHECK_EQ(lsb, base::bits::CountTrailingZeros32(value)); 689 return EmitUbfx(this, node, mleft.left().node(), lsb, width); 690 } 691 } 692 } 693 VisitShift(this, node, TryMatchLSR); 694 } 695 696 697 void InstructionSelector::VisitWord32Sar(Node* node) { 698 ArmOperandGenerator g(this); 699 Int32BinopMatcher m(node); 700 if (CanCover(m.node(), m.left().node()) && m.left().IsWord32Shl()) { 701 Int32BinopMatcher mleft(m.left().node()); 702 if (mleft.right().Is(16) && m.right().Is(16)) { 703 Emit(kArmSxth, g.DefineAsRegister(node), 704 g.UseRegister(mleft.left().node()), g.TempImmediate(0)); 705 return; 706 } else if (mleft.right().Is(24) && m.right().Is(24)) { 707 Emit(kArmSxtb, g.DefineAsRegister(node), 708 g.UseRegister(mleft.left().node()), g.TempImmediate(0)); 709 return; 710 } 711 } 712 VisitShift(this, node, TryMatchASR); 713 } 714 715 716 void InstructionSelector::VisitWord32Ror(Node* node) { 717 VisitShift(this, node, TryMatchROR); 718 } 719 720 721 void InstructionSelector::VisitWord32Clz(Node* node) { 722 VisitRR(this, kArmClz, node); 723 } 724 725 726 void InstructionSelector::VisitWord32Ctz(Node* node) { UNREACHABLE(); } 727 728 729 void InstructionSelector::VisitWord32Popcnt(Node* node) { UNREACHABLE(); } 730 731 732 void InstructionSelector::VisitInt32Add(Node* node) { 733 ArmOperandGenerator g(this); 734 Int32BinopMatcher m(node); 735 if (CanCover(node, m.left().node())) { 736 switch (m.left().opcode()) { 737 case IrOpcode::kInt32Mul: { 738 Int32BinopMatcher mleft(m.left().node()); 739 Emit(kArmMla, g.DefineAsRegister(node), 740 g.UseRegister(mleft.left().node()), 741 g.UseRegister(mleft.right().node()), 742 g.UseRegister(m.right().node())); 743 return; 744 } 745 case IrOpcode::kInt32MulHigh: { 746 Int32BinopMatcher mleft(m.left().node()); 747 Emit(kArmSmmla, g.DefineAsRegister(node), 748 g.UseRegister(mleft.left().node()), 749 g.UseRegister(mleft.right().node()), 750 g.UseRegister(m.right().node())); 751 return; 752 } 753 case IrOpcode::kWord32And: { 754 Int32BinopMatcher mleft(m.left().node()); 755 if (mleft.right().Is(0xff)) { 756 Emit(kArmUxtab, g.DefineAsRegister(node), 757 g.UseRegister(m.right().node()), 758 g.UseRegister(mleft.left().node()), g.TempImmediate(0)); 759 return; 760 } else if (mleft.right().Is(0xffff)) { 761 Emit(kArmUxtah, g.DefineAsRegister(node), 762 g.UseRegister(m.right().node()), 763 g.UseRegister(mleft.left().node()), g.TempImmediate(0)); 764 return; 765 } 766 } 767 case IrOpcode::kWord32Sar: { 768 Int32BinopMatcher mleft(m.left().node()); 769 if (CanCover(mleft.node(), mleft.left().node()) && 770 mleft.left().IsWord32Shl()) { 771 Int32BinopMatcher mleftleft(mleft.left().node()); 772 if (mleft.right().Is(24) && mleftleft.right().Is(24)) { 773 Emit(kArmSxtab, g.DefineAsRegister(node), 774 g.UseRegister(m.right().node()), 775 g.UseRegister(mleftleft.left().node()), g.TempImmediate(0)); 776 return; 777 } else if (mleft.right().Is(16) && mleftleft.right().Is(16)) { 778 Emit(kArmSxtah, g.DefineAsRegister(node), 779 g.UseRegister(m.right().node()), 780 g.UseRegister(mleftleft.left().node()), g.TempImmediate(0)); 781 return; 782 } 783 } 784 } 785 default: 786 break; 787 } 788 } 789 if (CanCover(node, m.right().node())) { 790 switch (m.right().opcode()) { 791 case IrOpcode::kInt32Mul: { 792 Int32BinopMatcher mright(m.right().node()); 793 Emit(kArmMla, g.DefineAsRegister(node), 794 g.UseRegister(mright.left().node()), 795 g.UseRegister(mright.right().node()), 796 g.UseRegister(m.left().node())); 797 return; 798 } 799 case IrOpcode::kInt32MulHigh: { 800 Int32BinopMatcher mright(m.right().node()); 801 Emit(kArmSmmla, g.DefineAsRegister(node), 802 g.UseRegister(mright.left().node()), 803 g.UseRegister(mright.right().node()), 804 g.UseRegister(m.left().node())); 805 return; 806 } 807 case IrOpcode::kWord32And: { 808 Int32BinopMatcher mright(m.right().node()); 809 if (mright.right().Is(0xff)) { 810 Emit(kArmUxtab, g.DefineAsRegister(node), 811 g.UseRegister(m.left().node()), 812 g.UseRegister(mright.left().node()), g.TempImmediate(0)); 813 return; 814 } else if (mright.right().Is(0xffff)) { 815 Emit(kArmUxtah, g.DefineAsRegister(node), 816 g.UseRegister(m.left().node()), 817 g.UseRegister(mright.left().node()), g.TempImmediate(0)); 818 return; 819 } 820 } 821 case IrOpcode::kWord32Sar: { 822 Int32BinopMatcher mright(m.right().node()); 823 if (CanCover(mright.node(), mright.left().node()) && 824 mright.left().IsWord32Shl()) { 825 Int32BinopMatcher mrightleft(mright.left().node()); 826 if (mright.right().Is(24) && mrightleft.right().Is(24)) { 827 Emit(kArmSxtab, g.DefineAsRegister(node), 828 g.UseRegister(m.left().node()), 829 g.UseRegister(mrightleft.left().node()), g.TempImmediate(0)); 830 return; 831 } else if (mright.right().Is(16) && mrightleft.right().Is(16)) { 832 Emit(kArmSxtah, g.DefineAsRegister(node), 833 g.UseRegister(m.left().node()), 834 g.UseRegister(mrightleft.left().node()), g.TempImmediate(0)); 835 return; 836 } 837 } 838 } 839 default: 840 break; 841 } 842 } 843 VisitBinop(this, node, kArmAdd, kArmAdd); 844 } 845 846 847 void InstructionSelector::VisitInt32Sub(Node* node) { 848 ArmOperandGenerator g(this); 849 Int32BinopMatcher m(node); 850 if (IsSupported(MLS) && m.right().IsInt32Mul() && 851 CanCover(node, m.right().node())) { 852 Int32BinopMatcher mright(m.right().node()); 853 Emit(kArmMls, g.DefineAsRegister(node), g.UseRegister(mright.left().node()), 854 g.UseRegister(mright.right().node()), g.UseRegister(m.left().node())); 855 return; 856 } 857 VisitBinop(this, node, kArmSub, kArmRsb); 858 } 859 860 861 void InstructionSelector::VisitInt32Mul(Node* node) { 862 ArmOperandGenerator g(this); 863 Int32BinopMatcher m(node); 864 if (m.right().HasValue() && m.right().Value() > 0) { 865 int32_t value = m.right().Value(); 866 if (base::bits::IsPowerOfTwo32(value - 1)) { 867 Emit(kArmAdd | AddressingModeField::encode(kMode_Operand2_R_LSL_I), 868 g.DefineAsRegister(node), g.UseRegister(m.left().node()), 869 g.UseRegister(m.left().node()), 870 g.TempImmediate(WhichPowerOf2(value - 1))); 871 return; 872 } 873 if (value < kMaxInt && base::bits::IsPowerOfTwo32(value + 1)) { 874 Emit(kArmRsb | AddressingModeField::encode(kMode_Operand2_R_LSL_I), 875 g.DefineAsRegister(node), g.UseRegister(m.left().node()), 876 g.UseRegister(m.left().node()), 877 g.TempImmediate(WhichPowerOf2(value + 1))); 878 return; 879 } 880 } 881 VisitRRR(this, kArmMul, node); 882 } 883 884 885 void InstructionSelector::VisitInt32MulHigh(Node* node) { 886 VisitRRR(this, kArmSmmul, node); 887 } 888 889 890 void InstructionSelector::VisitUint32MulHigh(Node* node) { 891 ArmOperandGenerator g(this); 892 InstructionOperand outputs[] = {g.TempRegister(), g.DefineAsRegister(node)}; 893 InstructionOperand inputs[] = {g.UseRegister(node->InputAt(0)), 894 g.UseRegister(node->InputAt(1))}; 895 Emit(kArmUmull, arraysize(outputs), outputs, arraysize(inputs), inputs); 896 } 897 898 899 void InstructionSelector::VisitInt32Div(Node* node) { 900 VisitDiv(this, node, kArmSdiv, kArmVcvtF64S32, kArmVcvtS32F64); 901 } 902 903 904 void InstructionSelector::VisitUint32Div(Node* node) { 905 VisitDiv(this, node, kArmUdiv, kArmVcvtF64U32, kArmVcvtU32F64); 906 } 907 908 909 void InstructionSelector::VisitInt32Mod(Node* node) { 910 VisitMod(this, node, kArmSdiv, kArmVcvtF64S32, kArmVcvtS32F64); 911 } 912 913 914 void InstructionSelector::VisitUint32Mod(Node* node) { 915 VisitMod(this, node, kArmUdiv, kArmVcvtF64U32, kArmVcvtU32F64); 916 } 917 918 919 void InstructionSelector::VisitChangeFloat32ToFloat64(Node* node) { 920 VisitRR(this, kArmVcvtF64F32, node); 921 } 922 923 924 void InstructionSelector::VisitChangeInt32ToFloat64(Node* node) { 925 VisitRR(this, kArmVcvtF64S32, node); 926 } 927 928 929 void InstructionSelector::VisitChangeUint32ToFloat64(Node* node) { 930 VisitRR(this, kArmVcvtF64U32, node); 931 } 932 933 934 void InstructionSelector::VisitChangeFloat64ToInt32(Node* node) { 935 VisitRR(this, kArmVcvtS32F64, node); 936 } 937 938 939 void InstructionSelector::VisitChangeFloat64ToUint32(Node* node) { 940 VisitRR(this, kArmVcvtU32F64, node); 941 } 942 943 944 void InstructionSelector::VisitTruncateFloat64ToFloat32(Node* node) { 945 VisitRR(this, kArmVcvtF32F64, node); 946 } 947 948 949 void InstructionSelector::VisitTruncateFloat64ToInt32(Node* node) { 950 switch (TruncationModeOf(node->op())) { 951 case TruncationMode::kJavaScript: 952 return VisitRR(this, kArchTruncateDoubleToI, node); 953 case TruncationMode::kRoundToZero: 954 return VisitRR(this, kArmVcvtS32F64, node); 955 } 956 UNREACHABLE(); 957 } 958 959 960 void InstructionSelector::VisitBitcastFloat32ToInt32(Node* node) { 961 VisitRR(this, kArmVmovLowU32F64, node); 962 } 963 964 965 void InstructionSelector::VisitBitcastInt32ToFloat32(Node* node) { 966 ArmOperandGenerator g(this); 967 Emit(kArmVmovLowF64U32, g.DefineAsRegister(node), 968 ImmediateOperand(ImmediateOperand::INLINE, 0), 969 g.UseRegister(node->InputAt(0))); 970 } 971 972 973 void InstructionSelector::VisitFloat32Add(Node* node) { 974 ArmOperandGenerator g(this); 975 Float32BinopMatcher m(node); 976 if (m.left().IsFloat32Mul() && CanCover(node, m.left().node())) { 977 Float32BinopMatcher mleft(m.left().node()); 978 Emit(kArmVmlaF32, g.DefineSameAsFirst(node), 979 g.UseRegister(m.right().node()), g.UseRegister(mleft.left().node()), 980 g.UseRegister(mleft.right().node())); 981 return; 982 } 983 if (m.right().IsFloat32Mul() && CanCover(node, m.right().node())) { 984 Float32BinopMatcher mright(m.right().node()); 985 Emit(kArmVmlaF32, g.DefineSameAsFirst(node), g.UseRegister(m.left().node()), 986 g.UseRegister(mright.left().node()), 987 g.UseRegister(mright.right().node())); 988 return; 989 } 990 VisitRRR(this, kArmVaddF32, node); 991 } 992 993 994 void InstructionSelector::VisitFloat64Add(Node* node) { 995 ArmOperandGenerator g(this); 996 Float64BinopMatcher m(node); 997 if (m.left().IsFloat64Mul() && CanCover(node, m.left().node())) { 998 Float64BinopMatcher mleft(m.left().node()); 999 Emit(kArmVmlaF64, g.DefineSameAsFirst(node), 1000 g.UseRegister(m.right().node()), g.UseRegister(mleft.left().node()), 1001 g.UseRegister(mleft.right().node())); 1002 return; 1003 } 1004 if (m.right().IsFloat64Mul() && CanCover(node, m.right().node())) { 1005 Float64BinopMatcher mright(m.right().node()); 1006 Emit(kArmVmlaF64, g.DefineSameAsFirst(node), g.UseRegister(m.left().node()), 1007 g.UseRegister(mright.left().node()), 1008 g.UseRegister(mright.right().node())); 1009 return; 1010 } 1011 VisitRRR(this, kArmVaddF64, node); 1012 } 1013 1014 1015 void InstructionSelector::VisitFloat32Sub(Node* node) { 1016 ArmOperandGenerator g(this); 1017 Float32BinopMatcher m(node); 1018 if (m.left().IsMinusZero()) { 1019 Emit(kArmVnegF32, g.DefineAsRegister(node), 1020 g.UseRegister(m.right().node())); 1021 return; 1022 } 1023 if (m.right().IsFloat32Mul() && CanCover(node, m.right().node())) { 1024 Float32BinopMatcher mright(m.right().node()); 1025 Emit(kArmVmlsF32, g.DefineSameAsFirst(node), g.UseRegister(m.left().node()), 1026 g.UseRegister(mright.left().node()), 1027 g.UseRegister(mright.right().node())); 1028 return; 1029 } 1030 VisitRRR(this, kArmVsubF32, node); 1031 } 1032 1033 1034 void InstructionSelector::VisitFloat64Sub(Node* node) { 1035 ArmOperandGenerator g(this); 1036 Float64BinopMatcher m(node); 1037 if (m.left().IsMinusZero()) { 1038 if (m.right().IsFloat64RoundDown() && 1039 CanCover(m.node(), m.right().node())) { 1040 if (m.right().InputAt(0)->opcode() == IrOpcode::kFloat64Sub && 1041 CanCover(m.right().node(), m.right().InputAt(0))) { 1042 Float64BinopMatcher mright0(m.right().InputAt(0)); 1043 if (mright0.left().IsMinusZero()) { 1044 Emit(kArmVrintpF64, g.DefineAsRegister(node), 1045 g.UseRegister(mright0.right().node())); 1046 return; 1047 } 1048 } 1049 } 1050 Emit(kArmVnegF64, g.DefineAsRegister(node), 1051 g.UseRegister(m.right().node())); 1052 return; 1053 } 1054 if (m.right().IsFloat64Mul() && CanCover(node, m.right().node())) { 1055 Float64BinopMatcher mright(m.right().node()); 1056 Emit(kArmVmlsF64, g.DefineSameAsFirst(node), g.UseRegister(m.left().node()), 1057 g.UseRegister(mright.left().node()), 1058 g.UseRegister(mright.right().node())); 1059 return; 1060 } 1061 VisitRRR(this, kArmVsubF64, node); 1062 } 1063 1064 1065 void InstructionSelector::VisitFloat32Mul(Node* node) { 1066 VisitRRR(this, kArmVmulF32, node); 1067 } 1068 1069 1070 void InstructionSelector::VisitFloat64Mul(Node* node) { 1071 VisitRRR(this, kArmVmulF64, node); 1072 } 1073 1074 1075 void InstructionSelector::VisitFloat32Div(Node* node) { 1076 VisitRRR(this, kArmVdivF32, node); 1077 } 1078 1079 1080 void InstructionSelector::VisitFloat64Div(Node* node) { 1081 VisitRRR(this, kArmVdivF64, node); 1082 } 1083 1084 1085 void InstructionSelector::VisitFloat64Mod(Node* node) { 1086 ArmOperandGenerator g(this); 1087 Emit(kArmVmodF64, g.DefineAsFixed(node, d0), g.UseFixed(node->InputAt(0), d0), 1088 g.UseFixed(node->InputAt(1), d1))->MarkAsCall(); 1089 } 1090 1091 1092 void InstructionSelector::VisitFloat32Max(Node* node) { UNREACHABLE(); } 1093 1094 1095 void InstructionSelector::VisitFloat64Max(Node* node) { UNREACHABLE(); } 1096 1097 1098 void InstructionSelector::VisitFloat32Min(Node* node) { UNREACHABLE(); } 1099 1100 1101 void InstructionSelector::VisitFloat64Min(Node* node) { UNREACHABLE(); } 1102 1103 1104 void InstructionSelector::VisitFloat32Abs(Node* node) { 1105 VisitRR(this, kArmVabsF32, node); 1106 } 1107 1108 1109 void InstructionSelector::VisitFloat64Abs(Node* node) { 1110 VisitRR(this, kArmVabsF64, node); 1111 } 1112 1113 1114 void InstructionSelector::VisitFloat32Sqrt(Node* node) { 1115 VisitRR(this, kArmVsqrtF32, node); 1116 } 1117 1118 1119 void InstructionSelector::VisitFloat64Sqrt(Node* node) { 1120 VisitRR(this, kArmVsqrtF64, node); 1121 } 1122 1123 1124 void InstructionSelector::VisitFloat32RoundDown(Node* node) { 1125 VisitRR(this, kArmVrintmF32, node); 1126 } 1127 1128 1129 void InstructionSelector::VisitFloat64RoundDown(Node* node) { 1130 VisitRR(this, kArmVrintmF64, node); 1131 } 1132 1133 1134 void InstructionSelector::VisitFloat32RoundUp(Node* node) { 1135 VisitRR(this, kArmVrintpF32, node); 1136 } 1137 1138 1139 void InstructionSelector::VisitFloat64RoundUp(Node* node) { 1140 VisitRR(this, kArmVrintpF64, node); 1141 } 1142 1143 1144 void InstructionSelector::VisitFloat32RoundTruncate(Node* node) { 1145 VisitRR(this, kArmVrintzF32, node); 1146 } 1147 1148 1149 void InstructionSelector::VisitFloat64RoundTruncate(Node* node) { 1150 VisitRR(this, kArmVrintzF64, node); 1151 } 1152 1153 1154 void InstructionSelector::VisitFloat64RoundTiesAway(Node* node) { 1155 VisitRR(this, kArmVrintaF64, node); 1156 } 1157 1158 1159 void InstructionSelector::VisitFloat32RoundTiesEven(Node* node) { 1160 VisitRR(this, kArmVrintnF32, node); 1161 } 1162 1163 1164 void InstructionSelector::VisitFloat64RoundTiesEven(Node* node) { 1165 VisitRR(this, kArmVrintnF64, node); 1166 } 1167 1168 1169 void InstructionSelector::EmitPrepareArguments( 1170 ZoneVector<PushParameter>* arguments, const CallDescriptor* descriptor, 1171 Node* node) { 1172 ArmOperandGenerator g(this); 1173 1174 // Prepare for C function call. 1175 if (descriptor->IsCFunctionCall()) { 1176 Emit(kArchPrepareCallCFunction | 1177 MiscField::encode(static_cast<int>(descriptor->CParameterCount())), 1178 0, nullptr, 0, nullptr); 1179 1180 // Poke any stack arguments. 1181 for (size_t n = 0; n < arguments->size(); ++n) { 1182 PushParameter input = (*arguments)[n]; 1183 if (input.node()) { 1184 int slot = static_cast<int>(n); 1185 Emit(kArmPoke | MiscField::encode(slot), g.NoOutput(), 1186 g.UseRegister(input.node())); 1187 } 1188 } 1189 } else { 1190 // Push any stack arguments. 1191 for (PushParameter input : base::Reversed(*arguments)) { 1192 // Skip any alignment holes in pushed nodes. 1193 if (input.node() == nullptr) continue; 1194 Emit(kArmPush, g.NoOutput(), g.UseRegister(input.node())); 1195 } 1196 } 1197 } 1198 1199 1200 bool InstructionSelector::IsTailCallAddressImmediate() { return false; } 1201 1202 1203 namespace { 1204 1205 // Shared routine for multiple compare operations. 1206 void VisitCompare(InstructionSelector* selector, InstructionCode opcode, 1207 InstructionOperand left, InstructionOperand right, 1208 FlagsContinuation* cont) { 1209 ArmOperandGenerator g(selector); 1210 opcode = cont->Encode(opcode); 1211 if (cont->IsBranch()) { 1212 selector->Emit(opcode, g.NoOutput(), left, right, 1213 g.Label(cont->true_block()), g.Label(cont->false_block())); 1214 } else { 1215 DCHECK(cont->IsSet()); 1216 selector->Emit(opcode, g.DefineAsRegister(cont->result()), left, right); 1217 } 1218 } 1219 1220 1221 // Shared routine for multiple float32 compare operations. 1222 void VisitFloat32Compare(InstructionSelector* selector, Node* node, 1223 FlagsContinuation* cont) { 1224 ArmOperandGenerator g(selector); 1225 Float32BinopMatcher m(node); 1226 if (m.right().Is(0.0f)) { 1227 VisitCompare(selector, kArmVcmpF32, g.UseRegister(m.left().node()), 1228 g.UseImmediate(m.right().node()), cont); 1229 } else if (m.left().Is(0.0f)) { 1230 cont->Commute(); 1231 VisitCompare(selector, kArmVcmpF32, g.UseRegister(m.right().node()), 1232 g.UseImmediate(m.left().node()), cont); 1233 } else { 1234 VisitCompare(selector, kArmVcmpF32, g.UseRegister(m.left().node()), 1235 g.UseRegister(m.right().node()), cont); 1236 } 1237 } 1238 1239 1240 // Shared routine for multiple float64 compare operations. 1241 void VisitFloat64Compare(InstructionSelector* selector, Node* node, 1242 FlagsContinuation* cont) { 1243 ArmOperandGenerator g(selector); 1244 Float64BinopMatcher m(node); 1245 if (m.right().Is(0.0)) { 1246 VisitCompare(selector, kArmVcmpF64, g.UseRegister(m.left().node()), 1247 g.UseImmediate(m.right().node()), cont); 1248 } else if (m.left().Is(0.0)) { 1249 cont->Commute(); 1250 VisitCompare(selector, kArmVcmpF64, g.UseRegister(m.right().node()), 1251 g.UseImmediate(m.left().node()), cont); 1252 } else { 1253 VisitCompare(selector, kArmVcmpF64, g.UseRegister(m.left().node()), 1254 g.UseRegister(m.right().node()), cont); 1255 } 1256 } 1257 1258 1259 // Shared routine for multiple word compare operations. 1260 void VisitWordCompare(InstructionSelector* selector, Node* node, 1261 InstructionCode opcode, FlagsContinuation* cont) { 1262 ArmOperandGenerator g(selector); 1263 Int32BinopMatcher m(node); 1264 InstructionOperand inputs[5]; 1265 size_t input_count = 0; 1266 InstructionOperand outputs[1]; 1267 size_t output_count = 0; 1268 1269 if (TryMatchImmediateOrShift(selector, &opcode, m.right().node(), 1270 &input_count, &inputs[1])) { 1271 inputs[0] = g.UseRegister(m.left().node()); 1272 input_count++; 1273 } else if (TryMatchImmediateOrShift(selector, &opcode, m.left().node(), 1274 &input_count, &inputs[1])) { 1275 if (!node->op()->HasProperty(Operator::kCommutative)) cont->Commute(); 1276 inputs[0] = g.UseRegister(m.right().node()); 1277 input_count++; 1278 } else { 1279 opcode |= AddressingModeField::encode(kMode_Operand2_R); 1280 inputs[input_count++] = g.UseRegister(m.left().node()); 1281 inputs[input_count++] = g.UseRegister(m.right().node()); 1282 } 1283 1284 if (cont->IsBranch()) { 1285 inputs[input_count++] = g.Label(cont->true_block()); 1286 inputs[input_count++] = g.Label(cont->false_block()); 1287 } else { 1288 DCHECK(cont->IsSet()); 1289 outputs[output_count++] = g.DefineAsRegister(cont->result()); 1290 } 1291 1292 DCHECK_NE(0u, input_count); 1293 DCHECK_GE(arraysize(inputs), input_count); 1294 DCHECK_GE(arraysize(outputs), output_count); 1295 1296 selector->Emit(cont->Encode(opcode), output_count, outputs, input_count, 1297 inputs); 1298 } 1299 1300 1301 void VisitWordCompare(InstructionSelector* selector, Node* node, 1302 FlagsContinuation* cont) { 1303 VisitWordCompare(selector, node, kArmCmp, cont); 1304 } 1305 1306 1307 // Shared routine for word comparisons against zero. 1308 void VisitWordCompareZero(InstructionSelector* selector, Node* user, 1309 Node* value, FlagsContinuation* cont) { 1310 while (selector->CanCover(user, value)) { 1311 switch (value->opcode()) { 1312 case IrOpcode::kWord32Equal: { 1313 // Combine with comparisons against 0 by simply inverting the 1314 // continuation. 1315 Int32BinopMatcher m(value); 1316 if (m.right().Is(0)) { 1317 user = value; 1318 value = m.left().node(); 1319 cont->Negate(); 1320 continue; 1321 } 1322 cont->OverwriteAndNegateIfEqual(kEqual); 1323 return VisitWordCompare(selector, value, cont); 1324 } 1325 case IrOpcode::kInt32LessThan: 1326 cont->OverwriteAndNegateIfEqual(kSignedLessThan); 1327 return VisitWordCompare(selector, value, cont); 1328 case IrOpcode::kInt32LessThanOrEqual: 1329 cont->OverwriteAndNegateIfEqual(kSignedLessThanOrEqual); 1330 return VisitWordCompare(selector, value, cont); 1331 case IrOpcode::kUint32LessThan: 1332 cont->OverwriteAndNegateIfEqual(kUnsignedLessThan); 1333 return VisitWordCompare(selector, value, cont); 1334 case IrOpcode::kUint32LessThanOrEqual: 1335 cont->OverwriteAndNegateIfEqual(kUnsignedLessThanOrEqual); 1336 return VisitWordCompare(selector, value, cont); 1337 case IrOpcode::kFloat32Equal: 1338 cont->OverwriteAndNegateIfEqual(kEqual); 1339 return VisitFloat32Compare(selector, value, cont); 1340 case IrOpcode::kFloat32LessThan: 1341 cont->OverwriteAndNegateIfEqual(kFloatLessThan); 1342 return VisitFloat32Compare(selector, value, cont); 1343 case IrOpcode::kFloat32LessThanOrEqual: 1344 cont->OverwriteAndNegateIfEqual(kFloatLessThanOrEqual); 1345 return VisitFloat32Compare(selector, value, cont); 1346 case IrOpcode::kFloat64Equal: 1347 cont->OverwriteAndNegateIfEqual(kEqual); 1348 return VisitFloat64Compare(selector, value, cont); 1349 case IrOpcode::kFloat64LessThan: 1350 cont->OverwriteAndNegateIfEqual(kFloatLessThan); 1351 return VisitFloat64Compare(selector, value, cont); 1352 case IrOpcode::kFloat64LessThanOrEqual: 1353 cont->OverwriteAndNegateIfEqual(kFloatLessThanOrEqual); 1354 return VisitFloat64Compare(selector, value, cont); 1355 case IrOpcode::kProjection: 1356 // Check if this is the overflow output projection of an 1357 // <Operation>WithOverflow node. 1358 if (ProjectionIndexOf(value->op()) == 1u) { 1359 // We cannot combine the <Operation>WithOverflow with this branch 1360 // unless the 0th projection (the use of the actual value of the 1361 // <Operation> is either nullptr, which means there's no use of the 1362 // actual value, or was already defined, which means it is scheduled 1363 // *AFTER* this branch). 1364 Node* const node = value->InputAt(0); 1365 Node* const result = NodeProperties::FindProjection(node, 0); 1366 if (!result || selector->IsDefined(result)) { 1367 switch (node->opcode()) { 1368 case IrOpcode::kInt32AddWithOverflow: 1369 cont->OverwriteAndNegateIfEqual(kOverflow); 1370 return VisitBinop(selector, node, kArmAdd, kArmAdd, cont); 1371 case IrOpcode::kInt32SubWithOverflow: 1372 cont->OverwriteAndNegateIfEqual(kOverflow); 1373 return VisitBinop(selector, node, kArmSub, kArmRsb, cont); 1374 default: 1375 break; 1376 } 1377 } 1378 } 1379 break; 1380 case IrOpcode::kInt32Add: 1381 return VisitWordCompare(selector, value, kArmCmn, cont); 1382 case IrOpcode::kInt32Sub: 1383 return VisitWordCompare(selector, value, kArmCmp, cont); 1384 case IrOpcode::kWord32And: 1385 return VisitWordCompare(selector, value, kArmTst, cont); 1386 case IrOpcode::kWord32Or: 1387 return VisitBinop(selector, value, kArmOrr, kArmOrr, cont); 1388 case IrOpcode::kWord32Xor: 1389 return VisitWordCompare(selector, value, kArmTeq, cont); 1390 case IrOpcode::kWord32Sar: 1391 return VisitShift(selector, value, TryMatchASR, cont); 1392 case IrOpcode::kWord32Shl: 1393 return VisitShift(selector, value, TryMatchLSL, cont); 1394 case IrOpcode::kWord32Shr: 1395 return VisitShift(selector, value, TryMatchLSR, cont); 1396 case IrOpcode::kWord32Ror: 1397 return VisitShift(selector, value, TryMatchROR, cont); 1398 default: 1399 break; 1400 } 1401 break; 1402 } 1403 1404 // Continuation could not be combined with a compare, emit compare against 0. 1405 ArmOperandGenerator g(selector); 1406 InstructionCode const opcode = 1407 cont->Encode(kArmTst) | AddressingModeField::encode(kMode_Operand2_R); 1408 InstructionOperand const value_operand = g.UseRegister(value); 1409 if (cont->IsBranch()) { 1410 selector->Emit(opcode, g.NoOutput(), value_operand, value_operand, 1411 g.Label(cont->true_block()), g.Label(cont->false_block())); 1412 } else { 1413 selector->Emit(opcode, g.DefineAsRegister(cont->result()), value_operand, 1414 value_operand); 1415 } 1416 } 1417 1418 } // namespace 1419 1420 1421 void InstructionSelector::VisitBranch(Node* branch, BasicBlock* tbranch, 1422 BasicBlock* fbranch) { 1423 FlagsContinuation cont(kNotEqual, tbranch, fbranch); 1424 VisitWordCompareZero(this, branch, branch->InputAt(0), &cont); 1425 } 1426 1427 1428 void InstructionSelector::VisitSwitch(Node* node, const SwitchInfo& sw) { 1429 ArmOperandGenerator g(this); 1430 InstructionOperand value_operand = g.UseRegister(node->InputAt(0)); 1431 1432 // Emit either ArchTableSwitch or ArchLookupSwitch. 1433 size_t table_space_cost = 4 + sw.value_range; 1434 size_t table_time_cost = 3; 1435 size_t lookup_space_cost = 3 + 2 * sw.case_count; 1436 size_t lookup_time_cost = sw.case_count; 1437 if (sw.case_count > 0 && 1438 table_space_cost + 3 * table_time_cost <= 1439 lookup_space_cost + 3 * lookup_time_cost && 1440 sw.min_value > std::numeric_limits<int32_t>::min()) { 1441 InstructionOperand index_operand = value_operand; 1442 if (sw.min_value) { 1443 index_operand = g.TempRegister(); 1444 Emit(kArmSub | AddressingModeField::encode(kMode_Operand2_I), 1445 index_operand, value_operand, g.TempImmediate(sw.min_value)); 1446 } 1447 // Generate a table lookup. 1448 return EmitTableSwitch(sw, index_operand); 1449 } 1450 1451 // Generate a sequence of conditional jumps. 1452 return EmitLookupSwitch(sw, value_operand); 1453 } 1454 1455 1456 void InstructionSelector::VisitWord32Equal(Node* const node) { 1457 FlagsContinuation cont(kEqual, node); 1458 Int32BinopMatcher m(node); 1459 if (m.right().Is(0)) { 1460 return VisitWordCompareZero(this, m.node(), m.left().node(), &cont); 1461 } 1462 VisitWordCompare(this, node, &cont); 1463 } 1464 1465 1466 void InstructionSelector::VisitInt32LessThan(Node* node) { 1467 FlagsContinuation cont(kSignedLessThan, node); 1468 VisitWordCompare(this, node, &cont); 1469 } 1470 1471 1472 void InstructionSelector::VisitInt32LessThanOrEqual(Node* node) { 1473 FlagsContinuation cont(kSignedLessThanOrEqual, node); 1474 VisitWordCompare(this, node, &cont); 1475 } 1476 1477 1478 void InstructionSelector::VisitUint32LessThan(Node* node) { 1479 FlagsContinuation cont(kUnsignedLessThan, node); 1480 VisitWordCompare(this, node, &cont); 1481 } 1482 1483 1484 void InstructionSelector::VisitUint32LessThanOrEqual(Node* node) { 1485 FlagsContinuation cont(kUnsignedLessThanOrEqual, node); 1486 VisitWordCompare(this, node, &cont); 1487 } 1488 1489 1490 void InstructionSelector::VisitInt32AddWithOverflow(Node* node) { 1491 if (Node* ovf = NodeProperties::FindProjection(node, 1)) { 1492 FlagsContinuation cont(kOverflow, ovf); 1493 return VisitBinop(this, node, kArmAdd, kArmAdd, &cont); 1494 } 1495 FlagsContinuation cont; 1496 VisitBinop(this, node, kArmAdd, kArmAdd, &cont); 1497 } 1498 1499 1500 void InstructionSelector::VisitInt32SubWithOverflow(Node* node) { 1501 if (Node* ovf = NodeProperties::FindProjection(node, 1)) { 1502 FlagsContinuation cont(kOverflow, ovf); 1503 return VisitBinop(this, node, kArmSub, kArmRsb, &cont); 1504 } 1505 FlagsContinuation cont; 1506 VisitBinop(this, node, kArmSub, kArmRsb, &cont); 1507 } 1508 1509 1510 void InstructionSelector::VisitFloat32Equal(Node* node) { 1511 FlagsContinuation cont(kEqual, node); 1512 VisitFloat32Compare(this, node, &cont); 1513 } 1514 1515 1516 void InstructionSelector::VisitFloat32LessThan(Node* node) { 1517 FlagsContinuation cont(kFloatLessThan, node); 1518 VisitFloat32Compare(this, node, &cont); 1519 } 1520 1521 1522 void InstructionSelector::VisitFloat32LessThanOrEqual(Node* node) { 1523 FlagsContinuation cont(kFloatLessThanOrEqual, node); 1524 VisitFloat32Compare(this, node, &cont); 1525 } 1526 1527 1528 void InstructionSelector::VisitFloat64Equal(Node* node) { 1529 FlagsContinuation cont(kEqual, node); 1530 VisitFloat64Compare(this, node, &cont); 1531 } 1532 1533 1534 void InstructionSelector::VisitFloat64LessThan(Node* node) { 1535 FlagsContinuation cont(kFloatLessThan, node); 1536 VisitFloat64Compare(this, node, &cont); 1537 } 1538 1539 1540 void InstructionSelector::VisitFloat64LessThanOrEqual(Node* node) { 1541 FlagsContinuation cont(kFloatLessThanOrEqual, node); 1542 VisitFloat64Compare(this, node, &cont); 1543 } 1544 1545 1546 void InstructionSelector::VisitFloat64ExtractLowWord32(Node* node) { 1547 VisitRR(this, kArmVmovLowU32F64, node); 1548 } 1549 1550 1551 void InstructionSelector::VisitFloat64ExtractHighWord32(Node* node) { 1552 VisitRR(this, kArmVmovHighU32F64, node); 1553 } 1554 1555 1556 void InstructionSelector::VisitFloat64InsertLowWord32(Node* node) { 1557 ArmOperandGenerator g(this); 1558 Node* left = node->InputAt(0); 1559 Node* right = node->InputAt(1); 1560 if (left->opcode() == IrOpcode::kFloat64InsertHighWord32 && 1561 CanCover(node, left)) { 1562 left = left->InputAt(1); 1563 Emit(kArmVmovF64U32U32, g.DefineAsRegister(node), g.UseRegister(right), 1564 g.UseRegister(left)); 1565 return; 1566 } 1567 Emit(kArmVmovLowF64U32, g.DefineSameAsFirst(node), g.UseRegister(left), 1568 g.UseRegister(right)); 1569 } 1570 1571 1572 void InstructionSelector::VisitFloat64InsertHighWord32(Node* node) { 1573 ArmOperandGenerator g(this); 1574 Node* left = node->InputAt(0); 1575 Node* right = node->InputAt(1); 1576 if (left->opcode() == IrOpcode::kFloat64InsertLowWord32 && 1577 CanCover(node, left)) { 1578 left = left->InputAt(1); 1579 Emit(kArmVmovF64U32U32, g.DefineAsRegister(node), g.UseRegister(left), 1580 g.UseRegister(right)); 1581 return; 1582 } 1583 Emit(kArmVmovHighF64U32, g.DefineSameAsFirst(node), g.UseRegister(left), 1584 g.UseRegister(right)); 1585 } 1586 1587 1588 // static 1589 MachineOperatorBuilder::Flags 1590 InstructionSelector::SupportedMachineOperatorFlags() { 1591 MachineOperatorBuilder::Flags flags = 1592 MachineOperatorBuilder::kInt32DivIsSafe | 1593 MachineOperatorBuilder::kUint32DivIsSafe; 1594 if (CpuFeatures::IsSupported(ARMv8)) { 1595 flags |= MachineOperatorBuilder::kFloat32RoundDown | 1596 MachineOperatorBuilder::kFloat64RoundDown | 1597 MachineOperatorBuilder::kFloat32RoundUp | 1598 MachineOperatorBuilder::kFloat64RoundUp | 1599 MachineOperatorBuilder::kFloat32RoundTruncate | 1600 MachineOperatorBuilder::kFloat64RoundTruncate | 1601 MachineOperatorBuilder::kFloat64RoundTiesAway | 1602 MachineOperatorBuilder::kFloat32RoundTiesEven | 1603 MachineOperatorBuilder::kFloat64RoundTiesEven; 1604 } 1605 return flags; 1606 } 1607 1608 } // namespace compiler 1609 } // namespace internal 1610 } // namespace v8 1611