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/bits.h" 6 #include "src/compiler/instruction-selector-impl.h" 7 #include "src/compiler/node-matchers.h" 8 9 namespace v8 { 10 namespace internal { 11 namespace compiler { 12 13 // Adds Arm-specific methods for generating InstructionOperands. 14 class ArmOperandGenerator FINAL : public OperandGenerator { 15 public: 16 explicit ArmOperandGenerator(InstructionSelector* selector) 17 : OperandGenerator(selector) {} 18 19 InstructionOperand* UseOperand(Node* node, InstructionCode opcode) { 20 if (CanBeImmediate(node, opcode)) { 21 return UseImmediate(node); 22 } 23 return UseRegister(node); 24 } 25 26 bool CanBeImmediate(Node* node, InstructionCode opcode) { 27 Int32Matcher m(node); 28 if (!m.HasValue()) return false; 29 int32_t value = m.Value(); 30 switch (ArchOpcodeField::decode(opcode)) { 31 case kArmAnd: 32 case kArmMov: 33 case kArmMvn: 34 case kArmBic: 35 return ImmediateFitsAddrMode1Instruction(value) || 36 ImmediateFitsAddrMode1Instruction(~value); 37 38 case kArmAdd: 39 case kArmSub: 40 case kArmCmp: 41 case kArmCmn: 42 return ImmediateFitsAddrMode1Instruction(value) || 43 ImmediateFitsAddrMode1Instruction(-value); 44 45 case kArmTst: 46 case kArmTeq: 47 case kArmOrr: 48 case kArmEor: 49 case kArmRsb: 50 return ImmediateFitsAddrMode1Instruction(value); 51 52 case kArmVldr32: 53 case kArmVstr32: 54 case kArmVldr64: 55 case kArmVstr64: 56 return value >= -1020 && value <= 1020 && (value % 4) == 0; 57 58 case kArmLdrb: 59 case kArmLdrsb: 60 case kArmStrb: 61 case kArmLdr: 62 case kArmStr: 63 case kArmStoreWriteBarrier: 64 return value >= -4095 && value <= 4095; 65 66 case kArmLdrh: 67 case kArmLdrsh: 68 case kArmStrh: 69 return value >= -255 && value <= 255; 70 71 case kArchCallCodeObject: 72 case kArchCallJSFunction: 73 case kArchJmp: 74 case kArchNop: 75 case kArchRet: 76 case kArchTruncateDoubleToI: 77 case kArmMul: 78 case kArmMla: 79 case kArmMls: 80 case kArmSdiv: 81 case kArmUdiv: 82 case kArmBfc: 83 case kArmUbfx: 84 case kArmVcmpF64: 85 case kArmVaddF64: 86 case kArmVsubF64: 87 case kArmVmulF64: 88 case kArmVmlaF64: 89 case kArmVmlsF64: 90 case kArmVdivF64: 91 case kArmVmodF64: 92 case kArmVnegF64: 93 case kArmVsqrtF64: 94 case kArmVcvtF64S32: 95 case kArmVcvtF64U32: 96 case kArmVcvtS32F64: 97 case kArmVcvtU32F64: 98 case kArmPush: 99 return false; 100 } 101 UNREACHABLE(); 102 return false; 103 } 104 105 private: 106 bool ImmediateFitsAddrMode1Instruction(int32_t imm) const { 107 return Assembler::ImmediateFitsAddrMode1Instruction(imm); 108 } 109 }; 110 111 112 static void VisitRRRFloat64(InstructionSelector* selector, ArchOpcode opcode, 113 Node* node) { 114 ArmOperandGenerator g(selector); 115 selector->Emit(opcode, g.DefineAsRegister(node), 116 g.UseRegister(node->InputAt(0)), 117 g.UseRegister(node->InputAt(1))); 118 } 119 120 121 static bool TryMatchROR(InstructionSelector* selector, 122 InstructionCode* opcode_return, Node* node, 123 InstructionOperand** value_return, 124 InstructionOperand** shift_return) { 125 ArmOperandGenerator g(selector); 126 if (node->opcode() != IrOpcode::kWord32Ror) return false; 127 Int32BinopMatcher m(node); 128 *value_return = g.UseRegister(m.left().node()); 129 if (m.right().IsInRange(1, 31)) { 130 *opcode_return |= AddressingModeField::encode(kMode_Operand2_R_ROR_I); 131 *shift_return = g.UseImmediate(m.right().node()); 132 } else { 133 *opcode_return |= AddressingModeField::encode(kMode_Operand2_R_ROR_R); 134 *shift_return = g.UseRegister(m.right().node()); 135 } 136 return true; 137 } 138 139 140 static inline bool TryMatchASR(InstructionSelector* selector, 141 InstructionCode* opcode_return, Node* node, 142 InstructionOperand** value_return, 143 InstructionOperand** shift_return) { 144 ArmOperandGenerator g(selector); 145 if (node->opcode() != IrOpcode::kWord32Sar) return false; 146 Int32BinopMatcher m(node); 147 *value_return = g.UseRegister(m.left().node()); 148 if (m.right().IsInRange(1, 32)) { 149 *opcode_return |= AddressingModeField::encode(kMode_Operand2_R_ASR_I); 150 *shift_return = g.UseImmediate(m.right().node()); 151 } else { 152 *opcode_return |= AddressingModeField::encode(kMode_Operand2_R_ASR_R); 153 *shift_return = g.UseRegister(m.right().node()); 154 } 155 return true; 156 } 157 158 159 static inline bool TryMatchLSL(InstructionSelector* selector, 160 InstructionCode* opcode_return, Node* node, 161 InstructionOperand** value_return, 162 InstructionOperand** shift_return) { 163 ArmOperandGenerator g(selector); 164 if (node->opcode() != IrOpcode::kWord32Shl) return false; 165 Int32BinopMatcher m(node); 166 *value_return = g.UseRegister(m.left().node()); 167 if (m.right().IsInRange(0, 31)) { 168 *opcode_return |= AddressingModeField::encode(kMode_Operand2_R_LSL_I); 169 *shift_return = g.UseImmediate(m.right().node()); 170 } else { 171 *opcode_return |= AddressingModeField::encode(kMode_Operand2_R_LSL_R); 172 *shift_return = g.UseRegister(m.right().node()); 173 } 174 return true; 175 } 176 177 178 static inline bool TryMatchLSR(InstructionSelector* selector, 179 InstructionCode* opcode_return, Node* node, 180 InstructionOperand** value_return, 181 InstructionOperand** shift_return) { 182 ArmOperandGenerator g(selector); 183 if (node->opcode() != IrOpcode::kWord32Shr) return false; 184 Int32BinopMatcher m(node); 185 *value_return = g.UseRegister(m.left().node()); 186 if (m.right().IsInRange(1, 32)) { 187 *opcode_return |= AddressingModeField::encode(kMode_Operand2_R_LSR_I); 188 *shift_return = g.UseImmediate(m.right().node()); 189 } else { 190 *opcode_return |= AddressingModeField::encode(kMode_Operand2_R_LSR_R); 191 *shift_return = g.UseRegister(m.right().node()); 192 } 193 return true; 194 } 195 196 197 static inline bool TryMatchShift(InstructionSelector* selector, 198 InstructionCode* opcode_return, Node* node, 199 InstructionOperand** value_return, 200 InstructionOperand** shift_return) { 201 return ( 202 TryMatchASR(selector, opcode_return, node, value_return, shift_return) || 203 TryMatchLSL(selector, opcode_return, node, value_return, shift_return) || 204 TryMatchLSR(selector, opcode_return, node, value_return, shift_return) || 205 TryMatchROR(selector, opcode_return, node, value_return, shift_return)); 206 } 207 208 209 static inline bool TryMatchImmediateOrShift(InstructionSelector* selector, 210 InstructionCode* opcode_return, 211 Node* node, 212 size_t* input_count_return, 213 InstructionOperand** inputs) { 214 ArmOperandGenerator g(selector); 215 if (g.CanBeImmediate(node, *opcode_return)) { 216 *opcode_return |= AddressingModeField::encode(kMode_Operand2_I); 217 inputs[0] = g.UseImmediate(node); 218 *input_count_return = 1; 219 return true; 220 } 221 if (TryMatchShift(selector, opcode_return, node, &inputs[0], &inputs[1])) { 222 *input_count_return = 2; 223 return true; 224 } 225 return false; 226 } 227 228 229 static void VisitBinop(InstructionSelector* selector, Node* node, 230 InstructionCode opcode, InstructionCode reverse_opcode, 231 FlagsContinuation* cont) { 232 ArmOperandGenerator g(selector); 233 Int32BinopMatcher m(node); 234 InstructionOperand* inputs[5]; 235 size_t input_count = 0; 236 InstructionOperand* outputs[2]; 237 size_t output_count = 0; 238 239 if (TryMatchImmediateOrShift(selector, &opcode, m.right().node(), 240 &input_count, &inputs[1])) { 241 inputs[0] = g.UseRegister(m.left().node()); 242 input_count++; 243 } else if (TryMatchImmediateOrShift(selector, &reverse_opcode, 244 m.left().node(), &input_count, 245 &inputs[1])) { 246 inputs[0] = g.UseRegister(m.right().node()); 247 opcode = reverse_opcode; 248 input_count++; 249 } else { 250 opcode |= AddressingModeField::encode(kMode_Operand2_R); 251 inputs[input_count++] = g.UseRegister(m.left().node()); 252 inputs[input_count++] = g.UseRegister(m.right().node()); 253 } 254 255 if (cont->IsBranch()) { 256 inputs[input_count++] = g.Label(cont->true_block()); 257 inputs[input_count++] = g.Label(cont->false_block()); 258 } 259 260 outputs[output_count++] = g.DefineAsRegister(node); 261 if (cont->IsSet()) { 262 outputs[output_count++] = g.DefineAsRegister(cont->result()); 263 } 264 265 DCHECK_NE(0, input_count); 266 DCHECK_NE(0, output_count); 267 DCHECK_GE(arraysize(inputs), input_count); 268 DCHECK_GE(arraysize(outputs), output_count); 269 DCHECK_NE(kMode_None, AddressingModeField::decode(opcode)); 270 271 Instruction* instr = selector->Emit(cont->Encode(opcode), output_count, 272 outputs, input_count, inputs); 273 if (cont->IsBranch()) instr->MarkAsControl(); 274 } 275 276 277 static void VisitBinop(InstructionSelector* selector, Node* node, 278 InstructionCode opcode, InstructionCode reverse_opcode) { 279 FlagsContinuation cont; 280 VisitBinop(selector, node, opcode, reverse_opcode, &cont); 281 } 282 283 284 void InstructionSelector::VisitLoad(Node* node) { 285 MachineType rep = RepresentationOf(OpParameter<LoadRepresentation>(node)); 286 MachineType typ = TypeOf(OpParameter<LoadRepresentation>(node)); 287 ArmOperandGenerator g(this); 288 Node* base = node->InputAt(0); 289 Node* index = node->InputAt(1); 290 291 ArchOpcode opcode; 292 switch (rep) { 293 case kRepFloat32: 294 opcode = kArmVldr32; 295 break; 296 case kRepFloat64: 297 opcode = kArmVldr64; 298 break; 299 case kRepBit: // Fall through. 300 case kRepWord8: 301 opcode = typ == kTypeUint32 ? kArmLdrb : kArmLdrsb; 302 break; 303 case kRepWord16: 304 opcode = typ == kTypeUint32 ? kArmLdrh : kArmLdrsh; 305 break; 306 case kRepTagged: // Fall through. 307 case kRepWord32: 308 opcode = kArmLdr; 309 break; 310 default: 311 UNREACHABLE(); 312 return; 313 } 314 315 if (g.CanBeImmediate(index, opcode)) { 316 Emit(opcode | AddressingModeField::encode(kMode_Offset_RI), 317 g.DefineAsRegister(node), g.UseRegister(base), g.UseImmediate(index)); 318 } else { 319 Emit(opcode | AddressingModeField::encode(kMode_Offset_RR), 320 g.DefineAsRegister(node), g.UseRegister(base), g.UseRegister(index)); 321 } 322 } 323 324 325 void InstructionSelector::VisitStore(Node* node) { 326 ArmOperandGenerator g(this); 327 Node* base = node->InputAt(0); 328 Node* index = node->InputAt(1); 329 Node* value = node->InputAt(2); 330 331 StoreRepresentation store_rep = OpParameter<StoreRepresentation>(node); 332 MachineType rep = RepresentationOf(store_rep.machine_type()); 333 if (store_rep.write_barrier_kind() == kFullWriteBarrier) { 334 DCHECK(rep == kRepTagged); 335 // TODO(dcarney): refactor RecordWrite function to take temp registers 336 // and pass them here instead of using fixed regs 337 // TODO(dcarney): handle immediate indices. 338 InstructionOperand* temps[] = {g.TempRegister(r5), g.TempRegister(r6)}; 339 Emit(kArmStoreWriteBarrier, NULL, g.UseFixed(base, r4), 340 g.UseFixed(index, r5), g.UseFixed(value, r6), arraysize(temps), 341 temps); 342 return; 343 } 344 DCHECK_EQ(kNoWriteBarrier, store_rep.write_barrier_kind()); 345 346 ArchOpcode opcode; 347 switch (rep) { 348 case kRepFloat32: 349 opcode = kArmVstr32; 350 break; 351 case kRepFloat64: 352 opcode = kArmVstr64; 353 break; 354 case kRepBit: // Fall through. 355 case kRepWord8: 356 opcode = kArmStrb; 357 break; 358 case kRepWord16: 359 opcode = kArmStrh; 360 break; 361 case kRepTagged: // Fall through. 362 case kRepWord32: 363 opcode = kArmStr; 364 break; 365 default: 366 UNREACHABLE(); 367 return; 368 } 369 370 if (g.CanBeImmediate(index, opcode)) { 371 Emit(opcode | AddressingModeField::encode(kMode_Offset_RI), NULL, 372 g.UseRegister(base), g.UseImmediate(index), g.UseRegister(value)); 373 } else { 374 Emit(opcode | AddressingModeField::encode(kMode_Offset_RR), NULL, 375 g.UseRegister(base), g.UseRegister(index), g.UseRegister(value)); 376 } 377 } 378 379 380 static inline void EmitBic(InstructionSelector* selector, Node* node, 381 Node* left, Node* right) { 382 ArmOperandGenerator g(selector); 383 InstructionCode opcode = kArmBic; 384 InstructionOperand* value_operand; 385 InstructionOperand* shift_operand; 386 if (TryMatchShift(selector, &opcode, right, &value_operand, &shift_operand)) { 387 selector->Emit(opcode, g.DefineAsRegister(node), g.UseRegister(left), 388 value_operand, shift_operand); 389 return; 390 } 391 selector->Emit(opcode | AddressingModeField::encode(kMode_Operand2_R), 392 g.DefineAsRegister(node), g.UseRegister(left), 393 g.UseRegister(right)); 394 } 395 396 397 void InstructionSelector::VisitWord32And(Node* node) { 398 ArmOperandGenerator g(this); 399 Int32BinopMatcher m(node); 400 if (m.left().IsWord32Xor() && CanCover(node, m.left().node())) { 401 Int32BinopMatcher mleft(m.left().node()); 402 if (mleft.right().Is(-1)) { 403 EmitBic(this, node, m.right().node(), mleft.left().node()); 404 return; 405 } 406 } 407 if (m.right().IsWord32Xor() && CanCover(node, m.right().node())) { 408 Int32BinopMatcher mright(m.right().node()); 409 if (mright.right().Is(-1)) { 410 EmitBic(this, node, m.left().node(), mright.left().node()); 411 return; 412 } 413 } 414 if (IsSupported(ARMv7) && m.right().HasValue()) { 415 uint32_t value = m.right().Value(); 416 uint32_t width = base::bits::CountPopulation32(value); 417 uint32_t msb = base::bits::CountLeadingZeros32(value); 418 if (width != 0 && msb + width == 32) { 419 DCHECK_EQ(0, base::bits::CountTrailingZeros32(value)); 420 if (m.left().IsWord32Shr()) { 421 Int32BinopMatcher mleft(m.left().node()); 422 if (mleft.right().IsInRange(0, 31)) { 423 Emit(kArmUbfx, g.DefineAsRegister(node), 424 g.UseRegister(mleft.left().node()), 425 g.UseImmediate(mleft.right().node()), g.TempImmediate(width)); 426 return; 427 } 428 } 429 Emit(kArmUbfx, g.DefineAsRegister(node), g.UseRegister(m.left().node()), 430 g.TempImmediate(0), g.TempImmediate(width)); 431 return; 432 } 433 // Try to interpret this AND as BFC. 434 width = 32 - width; 435 msb = base::bits::CountLeadingZeros32(~value); 436 uint32_t lsb = base::bits::CountTrailingZeros32(~value); 437 if (msb + width + lsb == 32) { 438 Emit(kArmBfc, g.DefineSameAsFirst(node), g.UseRegister(m.left().node()), 439 g.TempImmediate(lsb), g.TempImmediate(width)); 440 return; 441 } 442 } 443 VisitBinop(this, node, kArmAnd, kArmAnd); 444 } 445 446 447 void InstructionSelector::VisitWord32Or(Node* node) { 448 VisitBinop(this, node, kArmOrr, kArmOrr); 449 } 450 451 452 void InstructionSelector::VisitWord32Xor(Node* node) { 453 ArmOperandGenerator g(this); 454 Int32BinopMatcher m(node); 455 if (m.right().Is(-1)) { 456 InstructionCode opcode = kArmMvn; 457 InstructionOperand* value_operand; 458 InstructionOperand* shift_operand; 459 if (TryMatchShift(this, &opcode, m.left().node(), &value_operand, 460 &shift_operand)) { 461 Emit(opcode, g.DefineAsRegister(node), value_operand, shift_operand); 462 return; 463 } 464 Emit(opcode | AddressingModeField::encode(kMode_Operand2_R), 465 g.DefineAsRegister(node), g.UseRegister(m.left().node())); 466 return; 467 } 468 VisitBinop(this, node, kArmEor, kArmEor); 469 } 470 471 472 template <typename TryMatchShift> 473 static inline void VisitShift(InstructionSelector* selector, Node* node, 474 TryMatchShift try_match_shift, 475 FlagsContinuation* cont) { 476 ArmOperandGenerator g(selector); 477 InstructionCode opcode = kArmMov; 478 InstructionOperand* inputs[4]; 479 size_t input_count = 2; 480 InstructionOperand* outputs[2]; 481 size_t output_count = 0; 482 483 CHECK(try_match_shift(selector, &opcode, node, &inputs[0], &inputs[1])); 484 485 if (cont->IsBranch()) { 486 inputs[input_count++] = g.Label(cont->true_block()); 487 inputs[input_count++] = g.Label(cont->false_block()); 488 } 489 490 outputs[output_count++] = g.DefineAsRegister(node); 491 if (cont->IsSet()) { 492 outputs[output_count++] = g.DefineAsRegister(cont->result()); 493 } 494 495 DCHECK_NE(0, input_count); 496 DCHECK_NE(0, output_count); 497 DCHECK_GE(arraysize(inputs), input_count); 498 DCHECK_GE(arraysize(outputs), output_count); 499 DCHECK_NE(kMode_None, AddressingModeField::decode(opcode)); 500 501 Instruction* instr = selector->Emit(cont->Encode(opcode), output_count, 502 outputs, input_count, inputs); 503 if (cont->IsBranch()) instr->MarkAsControl(); 504 } 505 506 507 template <typename TryMatchShift> 508 static inline void VisitShift(InstructionSelector* selector, Node* node, 509 TryMatchShift try_match_shift) { 510 FlagsContinuation cont; 511 VisitShift(selector, node, try_match_shift, &cont); 512 } 513 514 515 void InstructionSelector::VisitWord32Shl(Node* node) { 516 VisitShift(this, node, TryMatchLSL); 517 } 518 519 520 void InstructionSelector::VisitWord32Shr(Node* node) { 521 ArmOperandGenerator g(this); 522 Int32BinopMatcher m(node); 523 if (IsSupported(ARMv7) && m.left().IsWord32And() && 524 m.right().IsInRange(0, 31)) { 525 int32_t lsb = m.right().Value(); 526 Int32BinopMatcher mleft(m.left().node()); 527 if (mleft.right().HasValue()) { 528 uint32_t value = (mleft.right().Value() >> lsb) << lsb; 529 uint32_t width = base::bits::CountPopulation32(value); 530 uint32_t msb = base::bits::CountLeadingZeros32(value); 531 if (msb + width + lsb == 32) { 532 DCHECK_EQ(lsb, base::bits::CountTrailingZeros32(value)); 533 Emit(kArmUbfx, g.DefineAsRegister(node), 534 g.UseRegister(mleft.left().node()), g.TempImmediate(lsb), 535 g.TempImmediate(width)); 536 return; 537 } 538 } 539 } 540 VisitShift(this, node, TryMatchLSR); 541 } 542 543 544 void InstructionSelector::VisitWord32Sar(Node* node) { 545 VisitShift(this, node, TryMatchASR); 546 } 547 548 549 void InstructionSelector::VisitWord32Ror(Node* node) { 550 VisitShift(this, node, TryMatchROR); 551 } 552 553 554 void InstructionSelector::VisitInt32Add(Node* node) { 555 ArmOperandGenerator g(this); 556 Int32BinopMatcher m(node); 557 if (m.left().IsInt32Mul() && CanCover(node, m.left().node())) { 558 Int32BinopMatcher mleft(m.left().node()); 559 Emit(kArmMla, g.DefineAsRegister(node), g.UseRegister(mleft.left().node()), 560 g.UseRegister(mleft.right().node()), g.UseRegister(m.right().node())); 561 return; 562 } 563 if (m.right().IsInt32Mul() && CanCover(node, m.right().node())) { 564 Int32BinopMatcher mright(m.right().node()); 565 Emit(kArmMla, g.DefineAsRegister(node), g.UseRegister(mright.left().node()), 566 g.UseRegister(mright.right().node()), g.UseRegister(m.left().node())); 567 return; 568 } 569 VisitBinop(this, node, kArmAdd, kArmAdd); 570 } 571 572 573 void InstructionSelector::VisitInt32Sub(Node* node) { 574 ArmOperandGenerator g(this); 575 Int32BinopMatcher m(node); 576 if (IsSupported(MLS) && m.right().IsInt32Mul() && 577 CanCover(node, m.right().node())) { 578 Int32BinopMatcher mright(m.right().node()); 579 Emit(kArmMls, g.DefineAsRegister(node), g.UseRegister(mright.left().node()), 580 g.UseRegister(mright.right().node()), g.UseRegister(m.left().node())); 581 return; 582 } 583 VisitBinop(this, node, kArmSub, kArmRsb); 584 } 585 586 587 void InstructionSelector::VisitInt32Mul(Node* node) { 588 ArmOperandGenerator g(this); 589 Int32BinopMatcher m(node); 590 if (m.right().HasValue() && m.right().Value() > 0) { 591 int32_t value = m.right().Value(); 592 if (base::bits::IsPowerOfTwo32(value - 1)) { 593 Emit(kArmAdd | AddressingModeField::encode(kMode_Operand2_R_LSL_I), 594 g.DefineAsRegister(node), g.UseRegister(m.left().node()), 595 g.UseRegister(m.left().node()), 596 g.TempImmediate(WhichPowerOf2(value - 1))); 597 return; 598 } 599 if (value < kMaxInt && base::bits::IsPowerOfTwo32(value + 1)) { 600 Emit(kArmRsb | AddressingModeField::encode(kMode_Operand2_R_LSL_I), 601 g.DefineAsRegister(node), g.UseRegister(m.left().node()), 602 g.UseRegister(m.left().node()), 603 g.TempImmediate(WhichPowerOf2(value + 1))); 604 return; 605 } 606 } 607 Emit(kArmMul, g.DefineAsRegister(node), g.UseRegister(m.left().node()), 608 g.UseRegister(m.right().node())); 609 } 610 611 612 static void EmitDiv(InstructionSelector* selector, ArchOpcode div_opcode, 613 ArchOpcode f64i32_opcode, ArchOpcode i32f64_opcode, 614 InstructionOperand* result_operand, 615 InstructionOperand* left_operand, 616 InstructionOperand* right_operand) { 617 ArmOperandGenerator g(selector); 618 if (selector->IsSupported(SUDIV)) { 619 selector->Emit(div_opcode, result_operand, left_operand, right_operand); 620 return; 621 } 622 InstructionOperand* left_double_operand = g.TempDoubleRegister(); 623 InstructionOperand* right_double_operand = g.TempDoubleRegister(); 624 InstructionOperand* result_double_operand = g.TempDoubleRegister(); 625 selector->Emit(f64i32_opcode, left_double_operand, left_operand); 626 selector->Emit(f64i32_opcode, right_double_operand, right_operand); 627 selector->Emit(kArmVdivF64, result_double_operand, left_double_operand, 628 right_double_operand); 629 selector->Emit(i32f64_opcode, result_operand, result_double_operand); 630 } 631 632 633 static void VisitDiv(InstructionSelector* selector, Node* node, 634 ArchOpcode div_opcode, ArchOpcode f64i32_opcode, 635 ArchOpcode i32f64_opcode) { 636 ArmOperandGenerator g(selector); 637 Int32BinopMatcher m(node); 638 EmitDiv(selector, div_opcode, f64i32_opcode, i32f64_opcode, 639 g.DefineAsRegister(node), g.UseRegister(m.left().node()), 640 g.UseRegister(m.right().node())); 641 } 642 643 644 void InstructionSelector::VisitInt32Div(Node* node) { 645 VisitDiv(this, node, kArmSdiv, kArmVcvtF64S32, kArmVcvtS32F64); 646 } 647 648 649 void InstructionSelector::VisitInt32UDiv(Node* node) { 650 VisitDiv(this, node, kArmUdiv, kArmVcvtF64U32, kArmVcvtU32F64); 651 } 652 653 654 static void VisitMod(InstructionSelector* selector, Node* node, 655 ArchOpcode div_opcode, ArchOpcode f64i32_opcode, 656 ArchOpcode i32f64_opcode) { 657 ArmOperandGenerator g(selector); 658 Int32BinopMatcher m(node); 659 InstructionOperand* div_operand = g.TempRegister(); 660 InstructionOperand* result_operand = g.DefineAsRegister(node); 661 InstructionOperand* left_operand = g.UseRegister(m.left().node()); 662 InstructionOperand* right_operand = g.UseRegister(m.right().node()); 663 EmitDiv(selector, div_opcode, f64i32_opcode, i32f64_opcode, div_operand, 664 left_operand, right_operand); 665 if (selector->IsSupported(MLS)) { 666 selector->Emit(kArmMls, result_operand, div_operand, right_operand, 667 left_operand); 668 return; 669 } 670 InstructionOperand* mul_operand = g.TempRegister(); 671 selector->Emit(kArmMul, mul_operand, div_operand, right_operand); 672 selector->Emit(kArmSub, result_operand, left_operand, mul_operand); 673 } 674 675 676 void InstructionSelector::VisitInt32Mod(Node* node) { 677 VisitMod(this, node, kArmSdiv, kArmVcvtF64S32, kArmVcvtS32F64); 678 } 679 680 681 void InstructionSelector::VisitInt32UMod(Node* node) { 682 VisitMod(this, node, kArmUdiv, kArmVcvtF64U32, kArmVcvtU32F64); 683 } 684 685 686 void InstructionSelector::VisitChangeInt32ToFloat64(Node* node) { 687 ArmOperandGenerator g(this); 688 Emit(kArmVcvtF64S32, g.DefineAsRegister(node), 689 g.UseRegister(node->InputAt(0))); 690 } 691 692 693 void InstructionSelector::VisitChangeUint32ToFloat64(Node* node) { 694 ArmOperandGenerator g(this); 695 Emit(kArmVcvtF64U32, g.DefineAsRegister(node), 696 g.UseRegister(node->InputAt(0))); 697 } 698 699 700 void InstructionSelector::VisitChangeFloat64ToInt32(Node* node) { 701 ArmOperandGenerator g(this); 702 Emit(kArmVcvtS32F64, g.DefineAsRegister(node), 703 g.UseRegister(node->InputAt(0))); 704 } 705 706 707 void InstructionSelector::VisitChangeFloat64ToUint32(Node* node) { 708 ArmOperandGenerator g(this); 709 Emit(kArmVcvtU32F64, g.DefineAsRegister(node), 710 g.UseRegister(node->InputAt(0))); 711 } 712 713 714 void InstructionSelector::VisitFloat64Add(Node* node) { 715 ArmOperandGenerator g(this); 716 Int32BinopMatcher m(node); 717 if (m.left().IsFloat64Mul() && CanCover(node, m.left().node())) { 718 Int32BinopMatcher mleft(m.left().node()); 719 Emit(kArmVmlaF64, g.DefineSameAsFirst(node), 720 g.UseRegister(m.right().node()), g.UseRegister(mleft.left().node()), 721 g.UseRegister(mleft.right().node())); 722 return; 723 } 724 if (m.right().IsFloat64Mul() && CanCover(node, m.right().node())) { 725 Int32BinopMatcher mright(m.right().node()); 726 Emit(kArmVmlaF64, g.DefineSameAsFirst(node), g.UseRegister(m.left().node()), 727 g.UseRegister(mright.left().node()), 728 g.UseRegister(mright.right().node())); 729 return; 730 } 731 VisitRRRFloat64(this, kArmVaddF64, node); 732 } 733 734 735 void InstructionSelector::VisitFloat64Sub(Node* node) { 736 ArmOperandGenerator g(this); 737 Int32BinopMatcher m(node); 738 if (m.right().IsFloat64Mul() && CanCover(node, m.right().node())) { 739 Int32BinopMatcher mright(m.right().node()); 740 Emit(kArmVmlsF64, g.DefineSameAsFirst(node), g.UseRegister(m.left().node()), 741 g.UseRegister(mright.left().node()), 742 g.UseRegister(mright.right().node())); 743 return; 744 } 745 VisitRRRFloat64(this, kArmVsubF64, node); 746 } 747 748 749 void InstructionSelector::VisitFloat64Mul(Node* node) { 750 ArmOperandGenerator g(this); 751 Float64BinopMatcher m(node); 752 if (m.right().Is(-1.0)) { 753 Emit(kArmVnegF64, g.DefineAsRegister(node), g.UseRegister(m.left().node())); 754 } else { 755 VisitRRRFloat64(this, kArmVmulF64, node); 756 } 757 } 758 759 760 void InstructionSelector::VisitFloat64Div(Node* node) { 761 VisitRRRFloat64(this, kArmVdivF64, node); 762 } 763 764 765 void InstructionSelector::VisitFloat64Mod(Node* node) { 766 ArmOperandGenerator g(this); 767 Emit(kArmVmodF64, g.DefineAsFixed(node, d0), g.UseFixed(node->InputAt(0), d0), 768 g.UseFixed(node->InputAt(1), d1))->MarkAsCall(); 769 } 770 771 772 void InstructionSelector::VisitFloat64Sqrt(Node* node) { 773 ArmOperandGenerator g(this); 774 Emit(kArmVsqrtF64, g.DefineAsRegister(node), g.UseRegister(node->InputAt(0))); 775 } 776 777 778 void InstructionSelector::VisitCall(Node* call, BasicBlock* continuation, 779 BasicBlock* deoptimization) { 780 ArmOperandGenerator g(this); 781 CallDescriptor* descriptor = OpParameter<CallDescriptor*>(call); 782 783 FrameStateDescriptor* frame_state_descriptor = NULL; 784 if (descriptor->NeedsFrameState()) { 785 frame_state_descriptor = 786 GetFrameStateDescriptor(call->InputAt(descriptor->InputCount())); 787 } 788 789 CallBuffer buffer(zone(), descriptor, frame_state_descriptor); 790 791 // Compute InstructionOperands for inputs and outputs. 792 // TODO(turbofan): on ARM64 it's probably better to use the code object in a 793 // register if there are multiple uses of it. Improve constant pool and the 794 // heuristics in the register allocator for where to emit constants. 795 InitializeCallBuffer(call, &buffer, true, false); 796 797 // TODO(dcarney): might be possible to use claim/poke instead 798 // Push any stack arguments. 799 for (NodeVectorRIter input = buffer.pushed_nodes.rbegin(); 800 input != buffer.pushed_nodes.rend(); input++) { 801 Emit(kArmPush, NULL, g.UseRegister(*input)); 802 } 803 804 // Select the appropriate opcode based on the call type. 805 InstructionCode opcode; 806 switch (descriptor->kind()) { 807 case CallDescriptor::kCallCodeObject: { 808 opcode = kArchCallCodeObject; 809 break; 810 } 811 case CallDescriptor::kCallJSFunction: 812 opcode = kArchCallJSFunction; 813 break; 814 default: 815 UNREACHABLE(); 816 return; 817 } 818 opcode |= MiscField::encode(descriptor->flags()); 819 820 // Emit the call instruction. 821 Instruction* call_instr = 822 Emit(opcode, buffer.outputs.size(), &buffer.outputs.front(), 823 buffer.instruction_args.size(), &buffer.instruction_args.front()); 824 825 call_instr->MarkAsCall(); 826 if (deoptimization != NULL) { 827 DCHECK(continuation != NULL); 828 call_instr->MarkAsControl(); 829 } 830 } 831 832 833 void InstructionSelector::VisitInt32AddWithOverflow(Node* node, 834 FlagsContinuation* cont) { 835 VisitBinop(this, node, kArmAdd, kArmAdd, cont); 836 } 837 838 839 void InstructionSelector::VisitInt32SubWithOverflow(Node* node, 840 FlagsContinuation* cont) { 841 VisitBinop(this, node, kArmSub, kArmRsb, cont); 842 } 843 844 845 // Shared routine for multiple compare operations. 846 static void VisitWordCompare(InstructionSelector* selector, Node* node, 847 InstructionCode opcode, FlagsContinuation* cont, 848 bool commutative) { 849 ArmOperandGenerator g(selector); 850 Int32BinopMatcher m(node); 851 InstructionOperand* inputs[5]; 852 size_t input_count = 0; 853 InstructionOperand* outputs[1]; 854 size_t output_count = 0; 855 856 if (TryMatchImmediateOrShift(selector, &opcode, m.right().node(), 857 &input_count, &inputs[1])) { 858 inputs[0] = g.UseRegister(m.left().node()); 859 input_count++; 860 } else if (TryMatchImmediateOrShift(selector, &opcode, m.left().node(), 861 &input_count, &inputs[1])) { 862 if (!commutative) cont->Commute(); 863 inputs[0] = g.UseRegister(m.right().node()); 864 input_count++; 865 } else { 866 opcode |= AddressingModeField::encode(kMode_Operand2_R); 867 inputs[input_count++] = g.UseRegister(m.left().node()); 868 inputs[input_count++] = g.UseRegister(m.right().node()); 869 } 870 871 if (cont->IsBranch()) { 872 inputs[input_count++] = g.Label(cont->true_block()); 873 inputs[input_count++] = g.Label(cont->false_block()); 874 } else { 875 DCHECK(cont->IsSet()); 876 outputs[output_count++] = g.DefineAsRegister(cont->result()); 877 } 878 879 DCHECK_NE(0, input_count); 880 DCHECK_GE(arraysize(inputs), input_count); 881 DCHECK_GE(arraysize(outputs), output_count); 882 883 Instruction* instr = selector->Emit(cont->Encode(opcode), output_count, 884 outputs, input_count, inputs); 885 if (cont->IsBranch()) instr->MarkAsControl(); 886 } 887 888 889 void InstructionSelector::VisitWord32Test(Node* node, FlagsContinuation* cont) { 890 switch (node->opcode()) { 891 case IrOpcode::kInt32Add: 892 return VisitWordCompare(this, node, kArmCmn, cont, true); 893 case IrOpcode::kInt32Sub: 894 return VisitWordCompare(this, node, kArmCmp, cont, false); 895 case IrOpcode::kWord32And: 896 return VisitWordCompare(this, node, kArmTst, cont, true); 897 case IrOpcode::kWord32Or: 898 return VisitBinop(this, node, kArmOrr, kArmOrr, cont); 899 case IrOpcode::kWord32Xor: 900 return VisitWordCompare(this, node, kArmTeq, cont, true); 901 case IrOpcode::kWord32Sar: 902 return VisitShift(this, node, TryMatchASR, cont); 903 case IrOpcode::kWord32Shl: 904 return VisitShift(this, node, TryMatchLSL, cont); 905 case IrOpcode::kWord32Shr: 906 return VisitShift(this, node, TryMatchLSR, cont); 907 case IrOpcode::kWord32Ror: 908 return VisitShift(this, node, TryMatchROR, cont); 909 default: 910 break; 911 } 912 913 ArmOperandGenerator g(this); 914 InstructionCode opcode = 915 cont->Encode(kArmTst) | AddressingModeField::encode(kMode_Operand2_R); 916 if (cont->IsBranch()) { 917 Emit(opcode, NULL, g.UseRegister(node), g.UseRegister(node), 918 g.Label(cont->true_block()), 919 g.Label(cont->false_block()))->MarkAsControl(); 920 } else { 921 Emit(opcode, g.DefineAsRegister(cont->result()), g.UseRegister(node), 922 g.UseRegister(node)); 923 } 924 } 925 926 927 void InstructionSelector::VisitWord32Compare(Node* node, 928 FlagsContinuation* cont) { 929 VisitWordCompare(this, node, kArmCmp, cont, false); 930 } 931 932 933 void InstructionSelector::VisitFloat64Compare(Node* node, 934 FlagsContinuation* cont) { 935 ArmOperandGenerator g(this); 936 Float64BinopMatcher m(node); 937 if (cont->IsBranch()) { 938 Emit(cont->Encode(kArmVcmpF64), NULL, g.UseRegister(m.left().node()), 939 g.UseRegister(m.right().node()), g.Label(cont->true_block()), 940 g.Label(cont->false_block()))->MarkAsControl(); 941 } else { 942 DCHECK(cont->IsSet()); 943 Emit(cont->Encode(kArmVcmpF64), g.DefineAsRegister(cont->result()), 944 g.UseRegister(m.left().node()), g.UseRegister(m.right().node())); 945 } 946 } 947 948 } // namespace compiler 949 } // namespace internal 950 } // namespace v8 951