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/compiler/code-generator.h" 6 7 #include "src/arm/macro-assembler-arm.h" 8 #include "src/compilation-info.h" 9 #include "src/compiler/code-generator-impl.h" 10 #include "src/compiler/gap-resolver.h" 11 #include "src/compiler/node-matchers.h" 12 #include "src/compiler/osr.h" 13 14 namespace v8 { 15 namespace internal { 16 namespace compiler { 17 18 #define __ masm()-> 19 20 21 #define kScratchReg r9 22 23 24 // Adds Arm-specific methods to convert InstructionOperands. 25 class ArmOperandConverter final : public InstructionOperandConverter { 26 public: 27 ArmOperandConverter(CodeGenerator* gen, Instruction* instr) 28 : InstructionOperandConverter(gen, instr) {} 29 30 SBit OutputSBit() const { 31 switch (instr_->flags_mode()) { 32 case kFlags_branch: 33 case kFlags_deoptimize: 34 case kFlags_set: 35 case kFlags_trap: 36 return SetCC; 37 case kFlags_none: 38 return LeaveCC; 39 } 40 UNREACHABLE(); 41 return LeaveCC; 42 } 43 44 Operand InputImmediate(size_t index) { 45 Constant constant = ToConstant(instr_->InputAt(index)); 46 switch (constant.type()) { 47 case Constant::kInt32: 48 return Operand(constant.ToInt32()); 49 case Constant::kFloat32: 50 return Operand( 51 isolate()->factory()->NewNumber(constant.ToFloat32(), TENURED)); 52 case Constant::kFloat64: 53 return Operand( 54 isolate()->factory()->NewNumber(constant.ToFloat64(), TENURED)); 55 case Constant::kInt64: 56 case Constant::kExternalReference: 57 case Constant::kHeapObject: 58 case Constant::kRpoNumber: 59 break; 60 } 61 UNREACHABLE(); 62 return Operand::Zero(); 63 } 64 65 Operand InputOperand2(size_t first_index) { 66 const size_t index = first_index; 67 switch (AddressingModeField::decode(instr_->opcode())) { 68 case kMode_None: 69 case kMode_Offset_RI: 70 case kMode_Offset_RR: 71 break; 72 case kMode_Operand2_I: 73 return InputImmediate(index + 0); 74 case kMode_Operand2_R: 75 return Operand(InputRegister(index + 0)); 76 case kMode_Operand2_R_ASR_I: 77 return Operand(InputRegister(index + 0), ASR, InputInt5(index + 1)); 78 case kMode_Operand2_R_ASR_R: 79 return Operand(InputRegister(index + 0), ASR, InputRegister(index + 1)); 80 case kMode_Operand2_R_LSL_I: 81 return Operand(InputRegister(index + 0), LSL, InputInt5(index + 1)); 82 case kMode_Operand2_R_LSL_R: 83 return Operand(InputRegister(index + 0), LSL, InputRegister(index + 1)); 84 case kMode_Operand2_R_LSR_I: 85 return Operand(InputRegister(index + 0), LSR, InputInt5(index + 1)); 86 case kMode_Operand2_R_LSR_R: 87 return Operand(InputRegister(index + 0), LSR, InputRegister(index + 1)); 88 case kMode_Operand2_R_ROR_I: 89 return Operand(InputRegister(index + 0), ROR, InputInt5(index + 1)); 90 case kMode_Operand2_R_ROR_R: 91 return Operand(InputRegister(index + 0), ROR, InputRegister(index + 1)); 92 } 93 UNREACHABLE(); 94 return Operand::Zero(); 95 } 96 97 MemOperand InputOffset(size_t* first_index) { 98 const size_t index = *first_index; 99 switch (AddressingModeField::decode(instr_->opcode())) { 100 case kMode_None: 101 case kMode_Operand2_I: 102 case kMode_Operand2_R: 103 case kMode_Operand2_R_ASR_I: 104 case kMode_Operand2_R_ASR_R: 105 case kMode_Operand2_R_LSL_R: 106 case kMode_Operand2_R_LSR_I: 107 case kMode_Operand2_R_LSR_R: 108 case kMode_Operand2_R_ROR_I: 109 case kMode_Operand2_R_ROR_R: 110 break; 111 case kMode_Operand2_R_LSL_I: 112 *first_index += 3; 113 return MemOperand(InputRegister(index + 0), InputRegister(index + 1), 114 LSL, InputInt32(index + 2)); 115 case kMode_Offset_RI: 116 *first_index += 2; 117 return MemOperand(InputRegister(index + 0), InputInt32(index + 1)); 118 case kMode_Offset_RR: 119 *first_index += 2; 120 return MemOperand(InputRegister(index + 0), InputRegister(index + 1)); 121 } 122 UNREACHABLE(); 123 return MemOperand(r0); 124 } 125 126 MemOperand InputOffset(size_t first_index = 0) { 127 return InputOffset(&first_index); 128 } 129 130 MemOperand ToMemOperand(InstructionOperand* op) const { 131 DCHECK_NOT_NULL(op); 132 DCHECK(op->IsStackSlot() || op->IsFPStackSlot()); 133 return SlotToMemOperand(AllocatedOperand::cast(op)->index()); 134 } 135 136 MemOperand SlotToMemOperand(int slot) const { 137 FrameOffset offset = frame_access_state()->GetFrameOffset(slot); 138 return MemOperand(offset.from_stack_pointer() ? sp : fp, offset.offset()); 139 } 140 }; 141 142 namespace { 143 144 class OutOfLineLoadFloat final : public OutOfLineCode { 145 public: 146 OutOfLineLoadFloat(CodeGenerator* gen, SwVfpRegister result) 147 : OutOfLineCode(gen), result_(result) {} 148 149 void Generate() final { 150 // Compute sqrtf(-1.0f), which results in a quiet single-precision NaN. 151 __ vmov(result_, -1.0f); 152 __ vsqrt(result_, result_); 153 } 154 155 private: 156 SwVfpRegister const result_; 157 }; 158 159 class OutOfLineLoadDouble final : public OutOfLineCode { 160 public: 161 OutOfLineLoadDouble(CodeGenerator* gen, DwVfpRegister result) 162 : OutOfLineCode(gen), result_(result) {} 163 164 void Generate() final { 165 // Compute sqrt(-1.0), which results in a quiet double-precision NaN. 166 __ vmov(result_, -1.0); 167 __ vsqrt(result_, result_); 168 } 169 170 private: 171 DwVfpRegister const result_; 172 }; 173 174 175 class OutOfLineLoadInteger final : public OutOfLineCode { 176 public: 177 OutOfLineLoadInteger(CodeGenerator* gen, Register result) 178 : OutOfLineCode(gen), result_(result) {} 179 180 void Generate() final { __ mov(result_, Operand::Zero()); } 181 182 private: 183 Register const result_; 184 }; 185 186 187 class OutOfLineRecordWrite final : public OutOfLineCode { 188 public: 189 OutOfLineRecordWrite(CodeGenerator* gen, Register object, Register index, 190 Register value, Register scratch0, Register scratch1, 191 RecordWriteMode mode, 192 UnwindingInfoWriter* unwinding_info_writer) 193 : OutOfLineCode(gen), 194 object_(object), 195 index_(index), 196 index_immediate_(0), 197 value_(value), 198 scratch0_(scratch0), 199 scratch1_(scratch1), 200 mode_(mode), 201 must_save_lr_(!gen->frame_access_state()->has_frame()), 202 unwinding_info_writer_(unwinding_info_writer) {} 203 204 OutOfLineRecordWrite(CodeGenerator* gen, Register object, int32_t index, 205 Register value, Register scratch0, Register scratch1, 206 RecordWriteMode mode, 207 UnwindingInfoWriter* unwinding_info_writer) 208 : OutOfLineCode(gen), 209 object_(object), 210 index_(no_reg), 211 index_immediate_(index), 212 value_(value), 213 scratch0_(scratch0), 214 scratch1_(scratch1), 215 mode_(mode), 216 must_save_lr_(!gen->frame_access_state()->has_frame()), 217 unwinding_info_writer_(unwinding_info_writer) {} 218 219 void Generate() final { 220 if (mode_ > RecordWriteMode::kValueIsPointer) { 221 __ JumpIfSmi(value_, exit()); 222 } 223 __ CheckPageFlag(value_, scratch0_, 224 MemoryChunk::kPointersToHereAreInterestingMask, eq, 225 exit()); 226 RememberedSetAction const remembered_set_action = 227 mode_ > RecordWriteMode::kValueIsMap ? EMIT_REMEMBERED_SET 228 : OMIT_REMEMBERED_SET; 229 SaveFPRegsMode const save_fp_mode = 230 frame()->DidAllocateDoubleRegisters() ? kSaveFPRegs : kDontSaveFPRegs; 231 if (must_save_lr_) { 232 // We need to save and restore lr if the frame was elided. 233 __ Push(lr); 234 unwinding_info_writer_->MarkLinkRegisterOnTopOfStack(__ pc_offset()); 235 } 236 RecordWriteStub stub(isolate(), object_, scratch0_, scratch1_, 237 remembered_set_action, save_fp_mode); 238 if (index_.is(no_reg)) { 239 __ add(scratch1_, object_, Operand(index_immediate_)); 240 } else { 241 DCHECK_EQ(0, index_immediate_); 242 __ add(scratch1_, object_, Operand(index_)); 243 } 244 __ CallStub(&stub); 245 if (must_save_lr_) { 246 __ Pop(lr); 247 unwinding_info_writer_->MarkPopLinkRegisterFromTopOfStack(__ pc_offset()); 248 } 249 } 250 251 private: 252 Register const object_; 253 Register const index_; 254 int32_t const index_immediate_; // Valid if index_.is(no_reg). 255 Register const value_; 256 Register const scratch0_; 257 Register const scratch1_; 258 RecordWriteMode const mode_; 259 bool must_save_lr_; 260 UnwindingInfoWriter* const unwinding_info_writer_; 261 }; 262 263 template <typename T> 264 class OutOfLineFloatMin final : public OutOfLineCode { 265 public: 266 OutOfLineFloatMin(CodeGenerator* gen, T result, T left, T right) 267 : OutOfLineCode(gen), result_(result), left_(left), right_(right) {} 268 269 void Generate() final { __ FloatMinOutOfLine(result_, left_, right_); } 270 271 private: 272 T const result_; 273 T const left_; 274 T const right_; 275 }; 276 typedef OutOfLineFloatMin<SwVfpRegister> OutOfLineFloat32Min; 277 typedef OutOfLineFloatMin<DwVfpRegister> OutOfLineFloat64Min; 278 279 template <typename T> 280 class OutOfLineFloatMax final : public OutOfLineCode { 281 public: 282 OutOfLineFloatMax(CodeGenerator* gen, T result, T left, T right) 283 : OutOfLineCode(gen), result_(result), left_(left), right_(right) {} 284 285 void Generate() final { __ FloatMaxOutOfLine(result_, left_, right_); } 286 287 private: 288 T const result_; 289 T const left_; 290 T const right_; 291 }; 292 typedef OutOfLineFloatMax<SwVfpRegister> OutOfLineFloat32Max; 293 typedef OutOfLineFloatMax<DwVfpRegister> OutOfLineFloat64Max; 294 295 Condition FlagsConditionToCondition(FlagsCondition condition) { 296 switch (condition) { 297 case kEqual: 298 return eq; 299 case kNotEqual: 300 return ne; 301 case kSignedLessThan: 302 return lt; 303 case kSignedGreaterThanOrEqual: 304 return ge; 305 case kSignedLessThanOrEqual: 306 return le; 307 case kSignedGreaterThan: 308 return gt; 309 case kUnsignedLessThan: 310 return lo; 311 case kUnsignedGreaterThanOrEqual: 312 return hs; 313 case kUnsignedLessThanOrEqual: 314 return ls; 315 case kUnsignedGreaterThan: 316 return hi; 317 case kFloatLessThanOrUnordered: 318 return lt; 319 case kFloatGreaterThanOrEqual: 320 return ge; 321 case kFloatLessThanOrEqual: 322 return ls; 323 case kFloatGreaterThanOrUnordered: 324 return hi; 325 case kFloatLessThan: 326 return lo; 327 case kFloatGreaterThanOrEqualOrUnordered: 328 return hs; 329 case kFloatLessThanOrEqualOrUnordered: 330 return le; 331 case kFloatGreaterThan: 332 return gt; 333 case kOverflow: 334 return vs; 335 case kNotOverflow: 336 return vc; 337 case kPositiveOrZero: 338 return pl; 339 case kNegative: 340 return mi; 341 default: 342 break; 343 } 344 UNREACHABLE(); 345 return kNoCondition; 346 } 347 348 } // namespace 349 350 #define ASSEMBLE_CHECKED_LOAD_FP(Type) \ 351 do { \ 352 auto result = i.Output##Type##Register(); \ 353 auto offset = i.InputRegister(0); \ 354 if (instr->InputAt(1)->IsRegister()) { \ 355 __ cmp(offset, i.InputRegister(1)); \ 356 } else { \ 357 __ cmp(offset, i.InputImmediate(1)); \ 358 } \ 359 auto ool = new (zone()) OutOfLineLoad##Type(this, result); \ 360 __ b(hs, ool->entry()); \ 361 __ vldr(result, i.InputOffset(2)); \ 362 __ bind(ool->exit()); \ 363 DCHECK_EQ(LeaveCC, i.OutputSBit()); \ 364 } while (0) 365 366 #define ASSEMBLE_CHECKED_LOAD_INTEGER(asm_instr) \ 367 do { \ 368 auto result = i.OutputRegister(); \ 369 auto offset = i.InputRegister(0); \ 370 if (instr->InputAt(1)->IsRegister()) { \ 371 __ cmp(offset, i.InputRegister(1)); \ 372 } else { \ 373 __ cmp(offset, i.InputImmediate(1)); \ 374 } \ 375 auto ool = new (zone()) OutOfLineLoadInteger(this, result); \ 376 __ b(hs, ool->entry()); \ 377 __ asm_instr(result, i.InputOffset(2)); \ 378 __ bind(ool->exit()); \ 379 DCHECK_EQ(LeaveCC, i.OutputSBit()); \ 380 } while (0) 381 382 #define ASSEMBLE_CHECKED_STORE_FP(Type) \ 383 do { \ 384 auto offset = i.InputRegister(0); \ 385 if (instr->InputAt(1)->IsRegister()) { \ 386 __ cmp(offset, i.InputRegister(1)); \ 387 } else { \ 388 __ cmp(offset, i.InputImmediate(1)); \ 389 } \ 390 auto value = i.Input##Type##Register(2); \ 391 __ vstr(value, i.InputOffset(3), lo); \ 392 DCHECK_EQ(LeaveCC, i.OutputSBit()); \ 393 } while (0) 394 395 #define ASSEMBLE_CHECKED_STORE_INTEGER(asm_instr) \ 396 do { \ 397 auto offset = i.InputRegister(0); \ 398 if (instr->InputAt(1)->IsRegister()) { \ 399 __ cmp(offset, i.InputRegister(1)); \ 400 } else { \ 401 __ cmp(offset, i.InputImmediate(1)); \ 402 } \ 403 auto value = i.InputRegister(2); \ 404 __ asm_instr(value, i.InputOffset(3), lo); \ 405 DCHECK_EQ(LeaveCC, i.OutputSBit()); \ 406 } while (0) 407 408 #define ASSEMBLE_ATOMIC_LOAD_INTEGER(asm_instr) \ 409 do { \ 410 __ asm_instr(i.OutputRegister(), \ 411 MemOperand(i.InputRegister(0), i.InputRegister(1))); \ 412 __ dmb(ISH); \ 413 } while (0) 414 415 #define ASSEMBLE_ATOMIC_STORE_INTEGER(asm_instr) \ 416 do { \ 417 __ dmb(ISH); \ 418 __ asm_instr(i.InputRegister(2), \ 419 MemOperand(i.InputRegister(0), i.InputRegister(1))); \ 420 __ dmb(ISH); \ 421 } while (0) 422 423 #define ASSEMBLE_IEEE754_BINOP(name) \ 424 do { \ 425 /* TODO(bmeurer): We should really get rid of this special instruction, */ \ 426 /* and generate a CallAddress instruction instead. */ \ 427 FrameScope scope(masm(), StackFrame::MANUAL); \ 428 __ PrepareCallCFunction(0, 2, kScratchReg); \ 429 __ MovToFloatParameters(i.InputDoubleRegister(0), \ 430 i.InputDoubleRegister(1)); \ 431 __ CallCFunction(ExternalReference::ieee754_##name##_function(isolate()), \ 432 0, 2); \ 433 /* Move the result in the double result register. */ \ 434 __ MovFromFloatResult(i.OutputDoubleRegister()); \ 435 DCHECK_EQ(LeaveCC, i.OutputSBit()); \ 436 } while (0) 437 438 #define ASSEMBLE_IEEE754_UNOP(name) \ 439 do { \ 440 /* TODO(bmeurer): We should really get rid of this special instruction, */ \ 441 /* and generate a CallAddress instruction instead. */ \ 442 FrameScope scope(masm(), StackFrame::MANUAL); \ 443 __ PrepareCallCFunction(0, 1, kScratchReg); \ 444 __ MovToFloatParameter(i.InputDoubleRegister(0)); \ 445 __ CallCFunction(ExternalReference::ieee754_##name##_function(isolate()), \ 446 0, 1); \ 447 /* Move the result in the double result register. */ \ 448 __ MovFromFloatResult(i.OutputDoubleRegister()); \ 449 DCHECK_EQ(LeaveCC, i.OutputSBit()); \ 450 } while (0) 451 452 void CodeGenerator::AssembleDeconstructFrame() { 453 __ LeaveFrame(StackFrame::MANUAL); 454 unwinding_info_writer_.MarkFrameDeconstructed(__ pc_offset()); 455 } 456 457 void CodeGenerator::AssemblePrepareTailCall() { 458 if (frame_access_state()->has_frame()) { 459 if (FLAG_enable_embedded_constant_pool) { 460 __ ldr(cp, MemOperand(fp, StandardFrameConstants::kConstantPoolOffset)); 461 } 462 __ ldr(lr, MemOperand(fp, StandardFrameConstants::kCallerPCOffset)); 463 __ ldr(fp, MemOperand(fp, StandardFrameConstants::kCallerFPOffset)); 464 } 465 frame_access_state()->SetFrameAccessToSP(); 466 } 467 468 void CodeGenerator::AssemblePopArgumentsAdaptorFrame(Register args_reg, 469 Register scratch1, 470 Register scratch2, 471 Register scratch3) { 472 DCHECK(!AreAliased(args_reg, scratch1, scratch2, scratch3)); 473 Label done; 474 475 // Check if current frame is an arguments adaptor frame. 476 __ ldr(scratch1, MemOperand(fp, StandardFrameConstants::kContextOffset)); 477 __ cmp(scratch1, 478 Operand(StackFrame::TypeToMarker(StackFrame::ARGUMENTS_ADAPTOR))); 479 __ b(ne, &done); 480 481 // Load arguments count from current arguments adaptor frame (note, it 482 // does not include receiver). 483 Register caller_args_count_reg = scratch1; 484 __ ldr(caller_args_count_reg, 485 MemOperand(fp, ArgumentsAdaptorFrameConstants::kLengthOffset)); 486 __ SmiUntag(caller_args_count_reg); 487 488 ParameterCount callee_args_count(args_reg); 489 __ PrepareForTailCall(callee_args_count, caller_args_count_reg, scratch2, 490 scratch3); 491 __ bind(&done); 492 } 493 494 namespace { 495 496 void FlushPendingPushRegisters(MacroAssembler* masm, 497 FrameAccessState* frame_access_state, 498 ZoneVector<Register>* pending_pushes) { 499 switch (pending_pushes->size()) { 500 case 0: 501 break; 502 case 1: 503 masm->push((*pending_pushes)[0]); 504 break; 505 case 2: 506 masm->Push((*pending_pushes)[0], (*pending_pushes)[1]); 507 break; 508 case 3: 509 masm->Push((*pending_pushes)[0], (*pending_pushes)[1], 510 (*pending_pushes)[2]); 511 break; 512 default: 513 UNREACHABLE(); 514 break; 515 } 516 frame_access_state->IncreaseSPDelta(pending_pushes->size()); 517 pending_pushes->resize(0); 518 } 519 520 void AddPendingPushRegister(MacroAssembler* masm, 521 FrameAccessState* frame_access_state, 522 ZoneVector<Register>* pending_pushes, 523 Register reg) { 524 pending_pushes->push_back(reg); 525 if (pending_pushes->size() == 3 || reg.is(ip)) { 526 FlushPendingPushRegisters(masm, frame_access_state, pending_pushes); 527 } 528 } 529 530 void AdjustStackPointerForTailCall( 531 MacroAssembler* masm, FrameAccessState* state, int new_slot_above_sp, 532 ZoneVector<Register>* pending_pushes = nullptr, 533 bool allow_shrinkage = true) { 534 int current_sp_offset = state->GetSPToFPSlotCount() + 535 StandardFrameConstants::kFixedSlotCountAboveFp; 536 int stack_slot_delta = new_slot_above_sp - current_sp_offset; 537 if (stack_slot_delta > 0) { 538 if (pending_pushes != nullptr) { 539 FlushPendingPushRegisters(masm, state, pending_pushes); 540 } 541 masm->sub(sp, sp, Operand(stack_slot_delta * kPointerSize)); 542 state->IncreaseSPDelta(stack_slot_delta); 543 } else if (allow_shrinkage && stack_slot_delta < 0) { 544 if (pending_pushes != nullptr) { 545 FlushPendingPushRegisters(masm, state, pending_pushes); 546 } 547 masm->add(sp, sp, Operand(-stack_slot_delta * kPointerSize)); 548 state->IncreaseSPDelta(stack_slot_delta); 549 } 550 } 551 552 } // namespace 553 554 void CodeGenerator::AssembleTailCallBeforeGap(Instruction* instr, 555 int first_unused_stack_slot) { 556 CodeGenerator::PushTypeFlags flags(kImmediatePush | kScalarPush); 557 ZoneVector<MoveOperands*> pushes(zone()); 558 GetPushCompatibleMoves(instr, flags, &pushes); 559 560 if (!pushes.empty() && 561 (LocationOperand::cast(pushes.back()->destination()).index() + 1 == 562 first_unused_stack_slot)) { 563 ArmOperandConverter g(this, instr); 564 ZoneVector<Register> pending_pushes(zone()); 565 for (auto move : pushes) { 566 LocationOperand destination_location( 567 LocationOperand::cast(move->destination())); 568 InstructionOperand source(move->source()); 569 AdjustStackPointerForTailCall( 570 masm(), frame_access_state(), 571 destination_location.index() - pending_pushes.size(), 572 &pending_pushes); 573 if (source.IsStackSlot()) { 574 LocationOperand source_location(LocationOperand::cast(source)); 575 __ ldr(ip, g.SlotToMemOperand(source_location.index())); 576 AddPendingPushRegister(masm(), frame_access_state(), &pending_pushes, 577 ip); 578 } else if (source.IsRegister()) { 579 LocationOperand source_location(LocationOperand::cast(source)); 580 AddPendingPushRegister(masm(), frame_access_state(), &pending_pushes, 581 source_location.GetRegister()); 582 } else if (source.IsImmediate()) { 583 AddPendingPushRegister(masm(), frame_access_state(), &pending_pushes, 584 ip); 585 } else { 586 // Pushes of non-scalar data types is not supported. 587 UNIMPLEMENTED(); 588 } 589 move->Eliminate(); 590 } 591 FlushPendingPushRegisters(masm(), frame_access_state(), &pending_pushes); 592 } 593 AdjustStackPointerForTailCall(masm(), frame_access_state(), 594 first_unused_stack_slot, nullptr, false); 595 } 596 597 void CodeGenerator::AssembleTailCallAfterGap(Instruction* instr, 598 int first_unused_stack_slot) { 599 AdjustStackPointerForTailCall(masm(), frame_access_state(), 600 first_unused_stack_slot); 601 } 602 603 // Assembles an instruction after register allocation, producing machine code. 604 CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction( 605 Instruction* instr) { 606 ArmOperandConverter i(this, instr); 607 608 __ MaybeCheckConstPool(); 609 InstructionCode opcode = instr->opcode(); 610 ArchOpcode arch_opcode = ArchOpcodeField::decode(opcode); 611 switch (arch_opcode) { 612 case kArchCallCodeObject: { 613 EnsureSpaceForLazyDeopt(); 614 if (instr->InputAt(0)->IsImmediate()) { 615 __ Call(Handle<Code>::cast(i.InputHeapObject(0)), 616 RelocInfo::CODE_TARGET); 617 } else { 618 __ add(ip, i.InputRegister(0), 619 Operand(Code::kHeaderSize - kHeapObjectTag)); 620 __ Call(ip); 621 } 622 RecordCallPosition(instr); 623 DCHECK_EQ(LeaveCC, i.OutputSBit()); 624 frame_access_state()->ClearSPDelta(); 625 break; 626 } 627 case kArchTailCallCodeObjectFromJSFunction: 628 case kArchTailCallCodeObject: { 629 if (arch_opcode == kArchTailCallCodeObjectFromJSFunction) { 630 AssemblePopArgumentsAdaptorFrame(kJavaScriptCallArgCountRegister, 631 i.TempRegister(0), i.TempRegister(1), 632 i.TempRegister(2)); 633 } 634 if (instr->InputAt(0)->IsImmediate()) { 635 __ Jump(Handle<Code>::cast(i.InputHeapObject(0)), 636 RelocInfo::CODE_TARGET); 637 } else { 638 __ add(ip, i.InputRegister(0), 639 Operand(Code::kHeaderSize - kHeapObjectTag)); 640 __ Jump(ip); 641 } 642 DCHECK_EQ(LeaveCC, i.OutputSBit()); 643 unwinding_info_writer_.MarkBlockWillExit(); 644 frame_access_state()->ClearSPDelta(); 645 frame_access_state()->SetFrameAccessToDefault(); 646 break; 647 } 648 case kArchTailCallAddress: { 649 CHECK(!instr->InputAt(0)->IsImmediate()); 650 __ Jump(i.InputRegister(0)); 651 unwinding_info_writer_.MarkBlockWillExit(); 652 frame_access_state()->ClearSPDelta(); 653 frame_access_state()->SetFrameAccessToDefault(); 654 break; 655 } 656 case kArchCallJSFunction: { 657 EnsureSpaceForLazyDeopt(); 658 Register func = i.InputRegister(0); 659 if (FLAG_debug_code) { 660 // Check the function's context matches the context argument. 661 __ ldr(kScratchReg, FieldMemOperand(func, JSFunction::kContextOffset)); 662 __ cmp(cp, kScratchReg); 663 __ Assert(eq, kWrongFunctionContext); 664 } 665 __ ldr(ip, FieldMemOperand(func, JSFunction::kCodeEntryOffset)); 666 __ Call(ip); 667 RecordCallPosition(instr); 668 DCHECK_EQ(LeaveCC, i.OutputSBit()); 669 frame_access_state()->ClearSPDelta(); 670 break; 671 } 672 case kArchTailCallJSFunctionFromJSFunction: { 673 Register func = i.InputRegister(0); 674 if (FLAG_debug_code) { 675 // Check the function's context matches the context argument. 676 __ ldr(kScratchReg, FieldMemOperand(func, JSFunction::kContextOffset)); 677 __ cmp(cp, kScratchReg); 678 __ Assert(eq, kWrongFunctionContext); 679 } 680 AssemblePopArgumentsAdaptorFrame(kJavaScriptCallArgCountRegister, 681 i.TempRegister(0), i.TempRegister(1), 682 i.TempRegister(2)); 683 __ ldr(ip, FieldMemOperand(func, JSFunction::kCodeEntryOffset)); 684 __ Jump(ip); 685 DCHECK_EQ(LeaveCC, i.OutputSBit()); 686 frame_access_state()->ClearSPDelta(); 687 frame_access_state()->SetFrameAccessToDefault(); 688 break; 689 } 690 case kArchPrepareCallCFunction: { 691 int const num_parameters = MiscField::decode(instr->opcode()); 692 __ PrepareCallCFunction(num_parameters, kScratchReg); 693 // Frame alignment requires using FP-relative frame addressing. 694 frame_access_state()->SetFrameAccessToFP(); 695 break; 696 } 697 case kArchPrepareTailCall: 698 AssemblePrepareTailCall(); 699 break; 700 case kArchCallCFunction: { 701 int const num_parameters = MiscField::decode(instr->opcode()); 702 if (instr->InputAt(0)->IsImmediate()) { 703 ExternalReference ref = i.InputExternalReference(0); 704 __ CallCFunction(ref, num_parameters); 705 } else { 706 Register func = i.InputRegister(0); 707 __ CallCFunction(func, num_parameters); 708 } 709 frame_access_state()->SetFrameAccessToDefault(); 710 frame_access_state()->ClearSPDelta(); 711 break; 712 } 713 case kArchJmp: 714 AssembleArchJump(i.InputRpo(0)); 715 DCHECK_EQ(LeaveCC, i.OutputSBit()); 716 break; 717 case kArchLookupSwitch: 718 AssembleArchLookupSwitch(instr); 719 DCHECK_EQ(LeaveCC, i.OutputSBit()); 720 break; 721 case kArchTableSwitch: 722 AssembleArchTableSwitch(instr); 723 DCHECK_EQ(LeaveCC, i.OutputSBit()); 724 break; 725 case kArchDebugBreak: 726 __ stop("kArchDebugBreak"); 727 break; 728 case kArchComment: { 729 Address comment_string = i.InputExternalReference(0).address(); 730 __ RecordComment(reinterpret_cast<const char*>(comment_string)); 731 break; 732 } 733 case kArchNop: 734 case kArchThrowTerminator: 735 // don't emit code for nops. 736 DCHECK_EQ(LeaveCC, i.OutputSBit()); 737 break; 738 case kArchDeoptimize: { 739 int deopt_state_id = 740 BuildTranslation(instr, -1, 0, OutputFrameStateCombine::Ignore()); 741 CodeGenResult result = 742 AssembleDeoptimizerCall(deopt_state_id, current_source_position_); 743 if (result != kSuccess) return result; 744 break; 745 } 746 case kArchRet: 747 AssembleReturn(instr->InputAt(0)); 748 DCHECK_EQ(LeaveCC, i.OutputSBit()); 749 break; 750 case kArchStackPointer: 751 __ mov(i.OutputRegister(), sp); 752 DCHECK_EQ(LeaveCC, i.OutputSBit()); 753 break; 754 case kArchFramePointer: 755 __ mov(i.OutputRegister(), fp); 756 DCHECK_EQ(LeaveCC, i.OutputSBit()); 757 break; 758 case kArchParentFramePointer: 759 if (frame_access_state()->has_frame()) { 760 __ ldr(i.OutputRegister(), MemOperand(fp, 0)); 761 } else { 762 __ mov(i.OutputRegister(), fp); 763 } 764 break; 765 case kArchTruncateDoubleToI: 766 __ TruncateDoubleToI(i.OutputRegister(), i.InputDoubleRegister(0)); 767 DCHECK_EQ(LeaveCC, i.OutputSBit()); 768 break; 769 case kArchStoreWithWriteBarrier: { 770 RecordWriteMode mode = 771 static_cast<RecordWriteMode>(MiscField::decode(instr->opcode())); 772 Register object = i.InputRegister(0); 773 Register value = i.InputRegister(2); 774 Register scratch0 = i.TempRegister(0); 775 Register scratch1 = i.TempRegister(1); 776 OutOfLineRecordWrite* ool; 777 778 AddressingMode addressing_mode = 779 AddressingModeField::decode(instr->opcode()); 780 if (addressing_mode == kMode_Offset_RI) { 781 int32_t index = i.InputInt32(1); 782 ool = new (zone()) 783 OutOfLineRecordWrite(this, object, index, value, scratch0, scratch1, 784 mode, &unwinding_info_writer_); 785 __ str(value, MemOperand(object, index)); 786 } else { 787 DCHECK_EQ(kMode_Offset_RR, addressing_mode); 788 Register index(i.InputRegister(1)); 789 ool = new (zone()) 790 OutOfLineRecordWrite(this, object, index, value, scratch0, scratch1, 791 mode, &unwinding_info_writer_); 792 __ str(value, MemOperand(object, index)); 793 } 794 __ CheckPageFlag(object, scratch0, 795 MemoryChunk::kPointersFromHereAreInterestingMask, ne, 796 ool->entry()); 797 __ bind(ool->exit()); 798 break; 799 } 800 case kArchStackSlot: { 801 FrameOffset offset = 802 frame_access_state()->GetFrameOffset(i.InputInt32(0)); 803 Register base; 804 if (offset.from_stack_pointer()) { 805 base = sp; 806 } else { 807 base = fp; 808 } 809 __ add(i.OutputRegister(0), base, Operand(offset.offset())); 810 break; 811 } 812 case kIeee754Float64Acos: 813 ASSEMBLE_IEEE754_UNOP(acos); 814 break; 815 case kIeee754Float64Acosh: 816 ASSEMBLE_IEEE754_UNOP(acosh); 817 break; 818 case kIeee754Float64Asin: 819 ASSEMBLE_IEEE754_UNOP(asin); 820 break; 821 case kIeee754Float64Asinh: 822 ASSEMBLE_IEEE754_UNOP(asinh); 823 break; 824 case kIeee754Float64Atan: 825 ASSEMBLE_IEEE754_UNOP(atan); 826 break; 827 case kIeee754Float64Atanh: 828 ASSEMBLE_IEEE754_UNOP(atanh); 829 break; 830 case kIeee754Float64Atan2: 831 ASSEMBLE_IEEE754_BINOP(atan2); 832 break; 833 case kIeee754Float64Cbrt: 834 ASSEMBLE_IEEE754_UNOP(cbrt); 835 break; 836 case kIeee754Float64Cos: 837 ASSEMBLE_IEEE754_UNOP(cos); 838 break; 839 case kIeee754Float64Cosh: 840 ASSEMBLE_IEEE754_UNOP(cosh); 841 break; 842 case kIeee754Float64Exp: 843 ASSEMBLE_IEEE754_UNOP(exp); 844 break; 845 case kIeee754Float64Expm1: 846 ASSEMBLE_IEEE754_UNOP(expm1); 847 break; 848 case kIeee754Float64Log: 849 ASSEMBLE_IEEE754_UNOP(log); 850 break; 851 case kIeee754Float64Log1p: 852 ASSEMBLE_IEEE754_UNOP(log1p); 853 break; 854 case kIeee754Float64Log2: 855 ASSEMBLE_IEEE754_UNOP(log2); 856 break; 857 case kIeee754Float64Log10: 858 ASSEMBLE_IEEE754_UNOP(log10); 859 break; 860 case kIeee754Float64Pow: { 861 MathPowStub stub(isolate(), MathPowStub::DOUBLE); 862 __ CallStub(&stub); 863 __ vmov(d0, d2); 864 break; 865 } 866 case kIeee754Float64Sin: 867 ASSEMBLE_IEEE754_UNOP(sin); 868 break; 869 case kIeee754Float64Sinh: 870 ASSEMBLE_IEEE754_UNOP(sinh); 871 break; 872 case kIeee754Float64Tan: 873 ASSEMBLE_IEEE754_UNOP(tan); 874 break; 875 case kIeee754Float64Tanh: 876 ASSEMBLE_IEEE754_UNOP(tanh); 877 break; 878 case kArmAdd: 879 __ add(i.OutputRegister(), i.InputRegister(0), i.InputOperand2(1), 880 i.OutputSBit()); 881 break; 882 case kArmAnd: 883 __ and_(i.OutputRegister(), i.InputRegister(0), i.InputOperand2(1), 884 i.OutputSBit()); 885 break; 886 case kArmBic: 887 __ bic(i.OutputRegister(), i.InputRegister(0), i.InputOperand2(1), 888 i.OutputSBit()); 889 break; 890 case kArmMul: 891 __ mul(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1), 892 i.OutputSBit()); 893 break; 894 case kArmMla: 895 __ mla(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1), 896 i.InputRegister(2), i.OutputSBit()); 897 break; 898 case kArmMls: { 899 CpuFeatureScope scope(masm(), ARMv7); 900 __ mls(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1), 901 i.InputRegister(2)); 902 DCHECK_EQ(LeaveCC, i.OutputSBit()); 903 break; 904 } 905 case kArmSmull: 906 __ smull(i.OutputRegister(0), i.OutputRegister(1), i.InputRegister(0), 907 i.InputRegister(1)); 908 break; 909 case kArmSmmul: 910 __ smmul(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1)); 911 DCHECK_EQ(LeaveCC, i.OutputSBit()); 912 break; 913 case kArmSmmla: 914 __ smmla(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1), 915 i.InputRegister(2)); 916 DCHECK_EQ(LeaveCC, i.OutputSBit()); 917 break; 918 case kArmUmull: 919 __ umull(i.OutputRegister(0), i.OutputRegister(1), i.InputRegister(0), 920 i.InputRegister(1), i.OutputSBit()); 921 break; 922 case kArmSdiv: { 923 CpuFeatureScope scope(masm(), SUDIV); 924 __ sdiv(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1)); 925 DCHECK_EQ(LeaveCC, i.OutputSBit()); 926 break; 927 } 928 case kArmUdiv: { 929 CpuFeatureScope scope(masm(), SUDIV); 930 __ udiv(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1)); 931 DCHECK_EQ(LeaveCC, i.OutputSBit()); 932 break; 933 } 934 case kArmMov: 935 __ Move(i.OutputRegister(), i.InputOperand2(0), i.OutputSBit()); 936 break; 937 case kArmMvn: 938 __ mvn(i.OutputRegister(), i.InputOperand2(0), i.OutputSBit()); 939 break; 940 case kArmOrr: 941 __ orr(i.OutputRegister(), i.InputRegister(0), i.InputOperand2(1), 942 i.OutputSBit()); 943 break; 944 case kArmEor: 945 __ eor(i.OutputRegister(), i.InputRegister(0), i.InputOperand2(1), 946 i.OutputSBit()); 947 break; 948 case kArmSub: 949 __ sub(i.OutputRegister(), i.InputRegister(0), i.InputOperand2(1), 950 i.OutputSBit()); 951 break; 952 case kArmRsb: 953 __ rsb(i.OutputRegister(), i.InputRegister(0), i.InputOperand2(1), 954 i.OutputSBit()); 955 break; 956 case kArmBfc: { 957 CpuFeatureScope scope(masm(), ARMv7); 958 __ bfc(i.OutputRegister(), i.InputInt8(1), i.InputInt8(2)); 959 DCHECK_EQ(LeaveCC, i.OutputSBit()); 960 break; 961 } 962 case kArmUbfx: { 963 CpuFeatureScope scope(masm(), ARMv7); 964 __ ubfx(i.OutputRegister(), i.InputRegister(0), i.InputInt8(1), 965 i.InputInt8(2)); 966 DCHECK_EQ(LeaveCC, i.OutputSBit()); 967 break; 968 } 969 case kArmSbfx: { 970 CpuFeatureScope scope(masm(), ARMv7); 971 __ sbfx(i.OutputRegister(), i.InputRegister(0), i.InputInt8(1), 972 i.InputInt8(2)); 973 DCHECK_EQ(LeaveCC, i.OutputSBit()); 974 break; 975 } 976 case kArmSxtb: 977 __ sxtb(i.OutputRegister(), i.InputRegister(0), i.InputInt32(1)); 978 DCHECK_EQ(LeaveCC, i.OutputSBit()); 979 break; 980 case kArmSxth: 981 __ sxth(i.OutputRegister(), i.InputRegister(0), i.InputInt32(1)); 982 DCHECK_EQ(LeaveCC, i.OutputSBit()); 983 break; 984 case kArmSxtab: 985 __ sxtab(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1), 986 i.InputInt32(2)); 987 DCHECK_EQ(LeaveCC, i.OutputSBit()); 988 break; 989 case kArmSxtah: 990 __ sxtah(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1), 991 i.InputInt32(2)); 992 DCHECK_EQ(LeaveCC, i.OutputSBit()); 993 break; 994 case kArmUxtb: 995 __ uxtb(i.OutputRegister(), i.InputRegister(0), i.InputInt32(1)); 996 DCHECK_EQ(LeaveCC, i.OutputSBit()); 997 break; 998 case kArmUxth: 999 __ uxth(i.OutputRegister(), i.InputRegister(0), i.InputInt32(1)); 1000 DCHECK_EQ(LeaveCC, i.OutputSBit()); 1001 break; 1002 case kArmUxtab: 1003 __ uxtab(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1), 1004 i.InputInt32(2)); 1005 DCHECK_EQ(LeaveCC, i.OutputSBit()); 1006 break; 1007 case kArmUxtah: 1008 __ uxtah(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1), 1009 i.InputInt32(2)); 1010 DCHECK_EQ(LeaveCC, i.OutputSBit()); 1011 break; 1012 case kArmRbit: { 1013 CpuFeatureScope scope(masm(), ARMv7); 1014 __ rbit(i.OutputRegister(), i.InputRegister(0)); 1015 DCHECK_EQ(LeaveCC, i.OutputSBit()); 1016 break; 1017 } 1018 case kArmClz: 1019 __ clz(i.OutputRegister(), i.InputRegister(0)); 1020 DCHECK_EQ(LeaveCC, i.OutputSBit()); 1021 break; 1022 case kArmCmp: 1023 __ cmp(i.InputRegister(0), i.InputOperand2(1)); 1024 DCHECK_EQ(SetCC, i.OutputSBit()); 1025 break; 1026 case kArmCmn: 1027 __ cmn(i.InputRegister(0), i.InputOperand2(1)); 1028 DCHECK_EQ(SetCC, i.OutputSBit()); 1029 break; 1030 case kArmTst: 1031 __ tst(i.InputRegister(0), i.InputOperand2(1)); 1032 DCHECK_EQ(SetCC, i.OutputSBit()); 1033 break; 1034 case kArmTeq: 1035 __ teq(i.InputRegister(0), i.InputOperand2(1)); 1036 DCHECK_EQ(SetCC, i.OutputSBit()); 1037 break; 1038 case kArmAddPair: 1039 // i.InputRegister(0) ... left low word. 1040 // i.InputRegister(1) ... left high word. 1041 // i.InputRegister(2) ... right low word. 1042 // i.InputRegister(3) ... right high word. 1043 __ add(i.OutputRegister(0), i.InputRegister(0), i.InputRegister(2), 1044 SBit::SetCC); 1045 __ adc(i.OutputRegister(1), i.InputRegister(1), 1046 Operand(i.InputRegister(3))); 1047 DCHECK_EQ(LeaveCC, i.OutputSBit()); 1048 break; 1049 case kArmSubPair: 1050 // i.InputRegister(0) ... left low word. 1051 // i.InputRegister(1) ... left high word. 1052 // i.InputRegister(2) ... right low word. 1053 // i.InputRegister(3) ... right high word. 1054 __ sub(i.OutputRegister(0), i.InputRegister(0), i.InputRegister(2), 1055 SBit::SetCC); 1056 __ sbc(i.OutputRegister(1), i.InputRegister(1), 1057 Operand(i.InputRegister(3))); 1058 DCHECK_EQ(LeaveCC, i.OutputSBit()); 1059 break; 1060 case kArmMulPair: 1061 // i.InputRegister(0) ... left low word. 1062 // i.InputRegister(1) ... left high word. 1063 // i.InputRegister(2) ... right low word. 1064 // i.InputRegister(3) ... right high word. 1065 __ umull(i.OutputRegister(0), i.OutputRegister(1), i.InputRegister(0), 1066 i.InputRegister(2)); 1067 __ mla(i.OutputRegister(1), i.InputRegister(0), i.InputRegister(3), 1068 i.OutputRegister(1)); 1069 __ mla(i.OutputRegister(1), i.InputRegister(2), i.InputRegister(1), 1070 i.OutputRegister(1)); 1071 break; 1072 case kArmLslPair: { 1073 Register second_output = 1074 instr->OutputCount() >= 2 ? i.OutputRegister(1) : i.TempRegister(0); 1075 if (instr->InputAt(2)->IsImmediate()) { 1076 __ LslPair(i.OutputRegister(0), second_output, i.InputRegister(0), 1077 i.InputRegister(1), i.InputInt32(2)); 1078 } else { 1079 __ LslPair(i.OutputRegister(0), second_output, i.InputRegister(0), 1080 i.InputRegister(1), kScratchReg, i.InputRegister(2)); 1081 } 1082 break; 1083 } 1084 case kArmLsrPair: { 1085 Register second_output = 1086 instr->OutputCount() >= 2 ? i.OutputRegister(1) : i.TempRegister(0); 1087 if (instr->InputAt(2)->IsImmediate()) { 1088 __ LsrPair(i.OutputRegister(0), second_output, i.InputRegister(0), 1089 i.InputRegister(1), i.InputInt32(2)); 1090 } else { 1091 __ LsrPair(i.OutputRegister(0), second_output, i.InputRegister(0), 1092 i.InputRegister(1), kScratchReg, i.InputRegister(2)); 1093 } 1094 break; 1095 } 1096 case kArmAsrPair: { 1097 Register second_output = 1098 instr->OutputCount() >= 2 ? i.OutputRegister(1) : i.TempRegister(0); 1099 if (instr->InputAt(2)->IsImmediate()) { 1100 __ AsrPair(i.OutputRegister(0), second_output, i.InputRegister(0), 1101 i.InputRegister(1), i.InputInt32(2)); 1102 } else { 1103 __ AsrPair(i.OutputRegister(0), second_output, i.InputRegister(0), 1104 i.InputRegister(1), kScratchReg, i.InputRegister(2)); 1105 } 1106 break; 1107 } 1108 case kArmVcmpF32: 1109 if (instr->InputAt(1)->IsFPRegister()) { 1110 __ VFPCompareAndSetFlags(i.InputFloatRegister(0), 1111 i.InputFloatRegister(1)); 1112 } else { 1113 DCHECK(instr->InputAt(1)->IsImmediate()); 1114 // 0.0 is the only immediate supported by vcmp instructions. 1115 DCHECK(i.InputFloat32(1) == 0.0f); 1116 __ VFPCompareAndSetFlags(i.InputFloatRegister(0), i.InputFloat32(1)); 1117 } 1118 DCHECK_EQ(SetCC, i.OutputSBit()); 1119 break; 1120 case kArmVaddF32: 1121 __ vadd(i.OutputFloatRegister(), i.InputFloatRegister(0), 1122 i.InputFloatRegister(1)); 1123 DCHECK_EQ(LeaveCC, i.OutputSBit()); 1124 break; 1125 case kArmVsubF32: 1126 __ vsub(i.OutputFloatRegister(), i.InputFloatRegister(0), 1127 i.InputFloatRegister(1)); 1128 DCHECK_EQ(LeaveCC, i.OutputSBit()); 1129 break; 1130 case kArmVmulF32: 1131 __ vmul(i.OutputFloatRegister(), i.InputFloatRegister(0), 1132 i.InputFloatRegister(1)); 1133 DCHECK_EQ(LeaveCC, i.OutputSBit()); 1134 break; 1135 case kArmVmlaF32: 1136 __ vmla(i.OutputFloatRegister(), i.InputFloatRegister(1), 1137 i.InputFloatRegister(2)); 1138 DCHECK_EQ(LeaveCC, i.OutputSBit()); 1139 break; 1140 case kArmVmlsF32: 1141 __ vmls(i.OutputFloatRegister(), i.InputFloatRegister(1), 1142 i.InputFloatRegister(2)); 1143 DCHECK_EQ(LeaveCC, i.OutputSBit()); 1144 break; 1145 case kArmVdivF32: 1146 __ vdiv(i.OutputFloatRegister(), i.InputFloatRegister(0), 1147 i.InputFloatRegister(1)); 1148 DCHECK_EQ(LeaveCC, i.OutputSBit()); 1149 break; 1150 case kArmVsqrtF32: 1151 __ vsqrt(i.OutputFloatRegister(), i.InputFloatRegister(0)); 1152 break; 1153 case kArmVabsF32: 1154 __ vabs(i.OutputFloatRegister(), i.InputFloatRegister(0)); 1155 break; 1156 case kArmVnegF32: 1157 __ vneg(i.OutputFloatRegister(), i.InputFloatRegister(0)); 1158 break; 1159 case kArmVcmpF64: 1160 if (instr->InputAt(1)->IsFPRegister()) { 1161 __ VFPCompareAndSetFlags(i.InputDoubleRegister(0), 1162 i.InputDoubleRegister(1)); 1163 } else { 1164 DCHECK(instr->InputAt(1)->IsImmediate()); 1165 // 0.0 is the only immediate supported by vcmp instructions. 1166 DCHECK(i.InputDouble(1) == 0.0); 1167 __ VFPCompareAndSetFlags(i.InputDoubleRegister(0), i.InputDouble(1)); 1168 } 1169 DCHECK_EQ(SetCC, i.OutputSBit()); 1170 break; 1171 case kArmVaddF64: 1172 __ vadd(i.OutputDoubleRegister(), i.InputDoubleRegister(0), 1173 i.InputDoubleRegister(1)); 1174 DCHECK_EQ(LeaveCC, i.OutputSBit()); 1175 break; 1176 case kArmVsubF64: 1177 __ vsub(i.OutputDoubleRegister(), i.InputDoubleRegister(0), 1178 i.InputDoubleRegister(1)); 1179 DCHECK_EQ(LeaveCC, i.OutputSBit()); 1180 break; 1181 case kArmVmulF64: 1182 __ vmul(i.OutputDoubleRegister(), i.InputDoubleRegister(0), 1183 i.InputDoubleRegister(1)); 1184 DCHECK_EQ(LeaveCC, i.OutputSBit()); 1185 break; 1186 case kArmVmlaF64: 1187 __ vmla(i.OutputDoubleRegister(), i.InputDoubleRegister(1), 1188 i.InputDoubleRegister(2)); 1189 DCHECK_EQ(LeaveCC, i.OutputSBit()); 1190 break; 1191 case kArmVmlsF64: 1192 __ vmls(i.OutputDoubleRegister(), i.InputDoubleRegister(1), 1193 i.InputDoubleRegister(2)); 1194 DCHECK_EQ(LeaveCC, i.OutputSBit()); 1195 break; 1196 case kArmVdivF64: 1197 __ vdiv(i.OutputDoubleRegister(), i.InputDoubleRegister(0), 1198 i.InputDoubleRegister(1)); 1199 DCHECK_EQ(LeaveCC, i.OutputSBit()); 1200 break; 1201 case kArmVmodF64: { 1202 // TODO(bmeurer): We should really get rid of this special instruction, 1203 // and generate a CallAddress instruction instead. 1204 FrameScope scope(masm(), StackFrame::MANUAL); 1205 __ PrepareCallCFunction(0, 2, kScratchReg); 1206 __ MovToFloatParameters(i.InputDoubleRegister(0), 1207 i.InputDoubleRegister(1)); 1208 __ CallCFunction(ExternalReference::mod_two_doubles_operation(isolate()), 1209 0, 2); 1210 // Move the result in the double result register. 1211 __ MovFromFloatResult(i.OutputDoubleRegister()); 1212 DCHECK_EQ(LeaveCC, i.OutputSBit()); 1213 break; 1214 } 1215 case kArmVsqrtF64: 1216 __ vsqrt(i.OutputDoubleRegister(), i.InputDoubleRegister(0)); 1217 break; 1218 case kArmVabsF64: 1219 __ vabs(i.OutputDoubleRegister(), i.InputDoubleRegister(0)); 1220 break; 1221 case kArmVnegF64: 1222 __ vneg(i.OutputDoubleRegister(), i.InputDoubleRegister(0)); 1223 break; 1224 case kArmVrintmF32: { 1225 CpuFeatureScope scope(masm(), ARMv8); 1226 __ vrintm(i.OutputFloatRegister(), i.InputFloatRegister(0)); 1227 break; 1228 } 1229 case kArmVrintmF64: { 1230 CpuFeatureScope scope(masm(), ARMv8); 1231 __ vrintm(i.OutputDoubleRegister(), i.InputDoubleRegister(0)); 1232 break; 1233 } 1234 case kArmVrintpF32: { 1235 CpuFeatureScope scope(masm(), ARMv8); 1236 __ vrintp(i.OutputFloatRegister(), i.InputFloatRegister(0)); 1237 break; 1238 } 1239 case kArmVrintpF64: { 1240 CpuFeatureScope scope(masm(), ARMv8); 1241 __ vrintp(i.OutputDoubleRegister(), i.InputDoubleRegister(0)); 1242 break; 1243 } 1244 case kArmVrintzF32: { 1245 CpuFeatureScope scope(masm(), ARMv8); 1246 __ vrintz(i.OutputFloatRegister(), i.InputFloatRegister(0)); 1247 break; 1248 } 1249 case kArmVrintzF64: { 1250 CpuFeatureScope scope(masm(), ARMv8); 1251 __ vrintz(i.OutputDoubleRegister(), i.InputDoubleRegister(0)); 1252 break; 1253 } 1254 case kArmVrintaF64: { 1255 CpuFeatureScope scope(masm(), ARMv8); 1256 __ vrinta(i.OutputDoubleRegister(), i.InputDoubleRegister(0)); 1257 break; 1258 } 1259 case kArmVrintnF32: { 1260 CpuFeatureScope scope(masm(), ARMv8); 1261 __ vrintn(i.OutputFloatRegister(), i.InputFloatRegister(0)); 1262 break; 1263 } 1264 case kArmVrintnF64: { 1265 CpuFeatureScope scope(masm(), ARMv8); 1266 __ vrintn(i.OutputDoubleRegister(), i.InputDoubleRegister(0)); 1267 break; 1268 } 1269 case kArmVcvtF32F64: { 1270 __ vcvt_f32_f64(i.OutputFloatRegister(), i.InputDoubleRegister(0)); 1271 DCHECK_EQ(LeaveCC, i.OutputSBit()); 1272 break; 1273 } 1274 case kArmVcvtF64F32: { 1275 __ vcvt_f64_f32(i.OutputDoubleRegister(), i.InputFloatRegister(0)); 1276 DCHECK_EQ(LeaveCC, i.OutputSBit()); 1277 break; 1278 } 1279 case kArmVcvtF32S32: { 1280 SwVfpRegister scratch = kScratchDoubleReg.low(); 1281 __ vmov(scratch, i.InputRegister(0)); 1282 __ vcvt_f32_s32(i.OutputFloatRegister(), scratch); 1283 DCHECK_EQ(LeaveCC, i.OutputSBit()); 1284 break; 1285 } 1286 case kArmVcvtF32U32: { 1287 SwVfpRegister scratch = kScratchDoubleReg.low(); 1288 __ vmov(scratch, i.InputRegister(0)); 1289 __ vcvt_f32_u32(i.OutputFloatRegister(), scratch); 1290 DCHECK_EQ(LeaveCC, i.OutputSBit()); 1291 break; 1292 } 1293 case kArmVcvtF64S32: { 1294 SwVfpRegister scratch = kScratchDoubleReg.low(); 1295 __ vmov(scratch, i.InputRegister(0)); 1296 __ vcvt_f64_s32(i.OutputDoubleRegister(), scratch); 1297 DCHECK_EQ(LeaveCC, i.OutputSBit()); 1298 break; 1299 } 1300 case kArmVcvtF64U32: { 1301 SwVfpRegister scratch = kScratchDoubleReg.low(); 1302 __ vmov(scratch, i.InputRegister(0)); 1303 __ vcvt_f64_u32(i.OutputDoubleRegister(), scratch); 1304 DCHECK_EQ(LeaveCC, i.OutputSBit()); 1305 break; 1306 } 1307 case kArmVcvtS32F32: { 1308 SwVfpRegister scratch = kScratchDoubleReg.low(); 1309 __ vcvt_s32_f32(scratch, i.InputFloatRegister(0)); 1310 __ vmov(i.OutputRegister(), scratch); 1311 // Avoid INT32_MAX as an overflow indicator and use INT32_MIN instead, 1312 // because INT32_MIN allows easier out-of-bounds detection. 1313 __ cmn(i.OutputRegister(), Operand(1)); 1314 __ mov(i.OutputRegister(), Operand(INT32_MIN), SBit::LeaveCC, vs); 1315 DCHECK_EQ(LeaveCC, i.OutputSBit()); 1316 break; 1317 } 1318 case kArmVcvtU32F32: { 1319 SwVfpRegister scratch = kScratchDoubleReg.low(); 1320 __ vcvt_u32_f32(scratch, i.InputFloatRegister(0)); 1321 __ vmov(i.OutputRegister(), scratch); 1322 // Avoid UINT32_MAX as an overflow indicator and use 0 instead, 1323 // because 0 allows easier out-of-bounds detection. 1324 __ cmn(i.OutputRegister(), Operand(1)); 1325 __ adc(i.OutputRegister(), i.OutputRegister(), Operand::Zero()); 1326 DCHECK_EQ(LeaveCC, i.OutputSBit()); 1327 break; 1328 } 1329 case kArmVcvtS32F64: { 1330 SwVfpRegister scratch = kScratchDoubleReg.low(); 1331 __ vcvt_s32_f64(scratch, i.InputDoubleRegister(0)); 1332 __ vmov(i.OutputRegister(), scratch); 1333 DCHECK_EQ(LeaveCC, i.OutputSBit()); 1334 break; 1335 } 1336 case kArmVcvtU32F64: { 1337 SwVfpRegister scratch = kScratchDoubleReg.low(); 1338 __ vcvt_u32_f64(scratch, i.InputDoubleRegister(0)); 1339 __ vmov(i.OutputRegister(), scratch); 1340 DCHECK_EQ(LeaveCC, i.OutputSBit()); 1341 break; 1342 } 1343 case kArmVmovU32F32: 1344 __ vmov(i.OutputRegister(), i.InputFloatRegister(0)); 1345 DCHECK_EQ(LeaveCC, i.OutputSBit()); 1346 break; 1347 case kArmVmovF32U32: 1348 __ vmov(i.OutputFloatRegister(), i.InputRegister(0)); 1349 DCHECK_EQ(LeaveCC, i.OutputSBit()); 1350 break; 1351 case kArmVmovLowU32F64: 1352 __ VmovLow(i.OutputRegister(), i.InputDoubleRegister(0)); 1353 DCHECK_EQ(LeaveCC, i.OutputSBit()); 1354 break; 1355 case kArmVmovLowF64U32: 1356 __ VmovLow(i.OutputDoubleRegister(), i.InputRegister(1)); 1357 DCHECK_EQ(LeaveCC, i.OutputSBit()); 1358 break; 1359 case kArmVmovHighU32F64: 1360 __ VmovHigh(i.OutputRegister(), i.InputDoubleRegister(0)); 1361 DCHECK_EQ(LeaveCC, i.OutputSBit()); 1362 break; 1363 case kArmVmovHighF64U32: 1364 __ VmovHigh(i.OutputDoubleRegister(), i.InputRegister(1)); 1365 DCHECK_EQ(LeaveCC, i.OutputSBit()); 1366 break; 1367 case kArmVmovF64U32U32: 1368 __ vmov(i.OutputDoubleRegister(), i.InputRegister(0), i.InputRegister(1)); 1369 DCHECK_EQ(LeaveCC, i.OutputSBit()); 1370 break; 1371 case kArmVmovU32U32F64: 1372 __ vmov(i.OutputRegister(0), i.OutputRegister(1), 1373 i.InputDoubleRegister(0)); 1374 DCHECK_EQ(LeaveCC, i.OutputSBit()); 1375 break; 1376 case kArmLdrb: 1377 __ ldrb(i.OutputRegister(), i.InputOffset()); 1378 DCHECK_EQ(LeaveCC, i.OutputSBit()); 1379 break; 1380 case kArmLdrsb: 1381 __ ldrsb(i.OutputRegister(), i.InputOffset()); 1382 DCHECK_EQ(LeaveCC, i.OutputSBit()); 1383 break; 1384 case kArmStrb: 1385 __ strb(i.InputRegister(0), i.InputOffset(1)); 1386 DCHECK_EQ(LeaveCC, i.OutputSBit()); 1387 break; 1388 case kArmLdrh: 1389 __ ldrh(i.OutputRegister(), i.InputOffset()); 1390 break; 1391 case kArmLdrsh: 1392 __ ldrsh(i.OutputRegister(), i.InputOffset()); 1393 break; 1394 case kArmStrh: 1395 __ strh(i.InputRegister(0), i.InputOffset(1)); 1396 DCHECK_EQ(LeaveCC, i.OutputSBit()); 1397 break; 1398 case kArmLdr: 1399 __ ldr(i.OutputRegister(), i.InputOffset()); 1400 break; 1401 case kArmStr: 1402 __ str(i.InputRegister(0), i.InputOffset(1)); 1403 DCHECK_EQ(LeaveCC, i.OutputSBit()); 1404 break; 1405 case kArmVldrF32: { 1406 __ vldr(i.OutputFloatRegister(), i.InputOffset()); 1407 DCHECK_EQ(LeaveCC, i.OutputSBit()); 1408 break; 1409 } 1410 case kArmVstrF32: 1411 __ vstr(i.InputFloatRegister(0), i.InputOffset(1)); 1412 DCHECK_EQ(LeaveCC, i.OutputSBit()); 1413 break; 1414 case kArmVldrF64: 1415 __ vldr(i.OutputDoubleRegister(), i.InputOffset()); 1416 DCHECK_EQ(LeaveCC, i.OutputSBit()); 1417 break; 1418 case kArmVstrF64: 1419 __ vstr(i.InputDoubleRegister(0), i.InputOffset(1)); 1420 DCHECK_EQ(LeaveCC, i.OutputSBit()); 1421 break; 1422 case kArmFloat32Max: { 1423 SwVfpRegister result = i.OutputFloatRegister(); 1424 SwVfpRegister left = i.InputFloatRegister(0); 1425 SwVfpRegister right = i.InputFloatRegister(1); 1426 if (left.is(right)) { 1427 __ Move(result, left); 1428 } else { 1429 auto ool = new (zone()) OutOfLineFloat32Max(this, result, left, right); 1430 __ FloatMax(result, left, right, ool->entry()); 1431 __ bind(ool->exit()); 1432 } 1433 DCHECK_EQ(LeaveCC, i.OutputSBit()); 1434 break; 1435 } 1436 case kArmFloat64Max: { 1437 DwVfpRegister result = i.OutputDoubleRegister(); 1438 DwVfpRegister left = i.InputDoubleRegister(0); 1439 DwVfpRegister right = i.InputDoubleRegister(1); 1440 if (left.is(right)) { 1441 __ Move(result, left); 1442 } else { 1443 auto ool = new (zone()) OutOfLineFloat64Max(this, result, left, right); 1444 __ FloatMax(result, left, right, ool->entry()); 1445 __ bind(ool->exit()); 1446 } 1447 DCHECK_EQ(LeaveCC, i.OutputSBit()); 1448 break; 1449 } 1450 case kArmFloat32Min: { 1451 SwVfpRegister result = i.OutputFloatRegister(); 1452 SwVfpRegister left = i.InputFloatRegister(0); 1453 SwVfpRegister right = i.InputFloatRegister(1); 1454 if (left.is(right)) { 1455 __ Move(result, left); 1456 } else { 1457 auto ool = new (zone()) OutOfLineFloat32Min(this, result, left, right); 1458 __ FloatMin(result, left, right, ool->entry()); 1459 __ bind(ool->exit()); 1460 } 1461 DCHECK_EQ(LeaveCC, i.OutputSBit()); 1462 break; 1463 } 1464 case kArmFloat64Min: { 1465 DwVfpRegister result = i.OutputDoubleRegister(); 1466 DwVfpRegister left = i.InputDoubleRegister(0); 1467 DwVfpRegister right = i.InputDoubleRegister(1); 1468 if (left.is(right)) { 1469 __ Move(result, left); 1470 } else { 1471 auto ool = new (zone()) OutOfLineFloat64Min(this, result, left, right); 1472 __ FloatMin(result, left, right, ool->entry()); 1473 __ bind(ool->exit()); 1474 } 1475 DCHECK_EQ(LeaveCC, i.OutputSBit()); 1476 break; 1477 } 1478 case kArmFloat64SilenceNaN: { 1479 DwVfpRegister value = i.InputDoubleRegister(0); 1480 DwVfpRegister result = i.OutputDoubleRegister(); 1481 __ VFPCanonicalizeNaN(result, value); 1482 break; 1483 } 1484 case kArmPush: 1485 if (instr->InputAt(0)->IsFPRegister()) { 1486 LocationOperand* op = LocationOperand::cast(instr->InputAt(0)); 1487 if (op->representation() == MachineRepresentation::kFloat64) { 1488 __ vpush(i.InputDoubleRegister(0)); 1489 frame_access_state()->IncreaseSPDelta(kDoubleSize / kPointerSize); 1490 } else { 1491 DCHECK_EQ(MachineRepresentation::kFloat32, op->representation()); 1492 __ vpush(i.InputFloatRegister(0)); 1493 frame_access_state()->IncreaseSPDelta(1); 1494 } 1495 } else { 1496 __ push(i.InputRegister(0)); 1497 frame_access_state()->IncreaseSPDelta(1); 1498 } 1499 DCHECK_EQ(LeaveCC, i.OutputSBit()); 1500 break; 1501 case kArmPoke: { 1502 int const slot = MiscField::decode(instr->opcode()); 1503 __ str(i.InputRegister(0), MemOperand(sp, slot * kPointerSize)); 1504 DCHECK_EQ(LeaveCC, i.OutputSBit()); 1505 break; 1506 } 1507 case kArmFloat32x4Splat: { 1508 __ vdup(i.OutputSimd128Register(), i.InputFloatRegister(0)); 1509 break; 1510 } 1511 case kArmFloat32x4ExtractLane: { 1512 __ ExtractLane(i.OutputFloatRegister(), i.InputSimd128Register(0), 1513 kScratchReg, i.InputInt8(1)); 1514 break; 1515 } 1516 case kArmFloat32x4ReplaceLane: { 1517 __ ReplaceLane(i.OutputSimd128Register(), i.InputSimd128Register(0), 1518 i.InputFloatRegister(2), kScratchReg, i.InputInt8(1)); 1519 break; 1520 } 1521 case kArmFloat32x4FromInt32x4: { 1522 __ vcvt_f32_s32(i.OutputSimd128Register(), i.InputSimd128Register(0)); 1523 break; 1524 } 1525 case kArmFloat32x4FromUint32x4: { 1526 __ vcvt_f32_u32(i.OutputSimd128Register(), i.InputSimd128Register(0)); 1527 break; 1528 } 1529 case kArmFloat32x4Abs: { 1530 __ vabs(i.OutputSimd128Register(), i.InputSimd128Register(0)); 1531 break; 1532 } 1533 case kArmFloat32x4Neg: { 1534 __ vneg(i.OutputSimd128Register(), i.InputSimd128Register(0)); 1535 break; 1536 } 1537 case kArmFloat32x4Add: { 1538 __ vadd(i.OutputSimd128Register(), i.InputSimd128Register(0), 1539 i.InputSimd128Register(1)); 1540 break; 1541 } 1542 case kArmFloat32x4Sub: { 1543 __ vsub(i.OutputSimd128Register(), i.InputSimd128Register(0), 1544 i.InputSimd128Register(1)); 1545 break; 1546 } 1547 case kArmFloat32x4Equal: { 1548 __ vceq(i.OutputSimd128Register(), i.InputSimd128Register(0), 1549 i.InputSimd128Register(1)); 1550 break; 1551 } 1552 case kArmFloat32x4NotEqual: { 1553 Simd128Register dst = i.OutputSimd128Register(); 1554 __ vceq(dst, i.InputSimd128Register(0), i.InputSimd128Register(1)); 1555 __ vmvn(dst, dst); 1556 break; 1557 } 1558 case kArmInt32x4Splat: { 1559 __ vdup(Neon32, i.OutputSimd128Register(), i.InputRegister(0)); 1560 break; 1561 } 1562 case kArmInt32x4ExtractLane: { 1563 __ ExtractLane(i.OutputRegister(), i.InputSimd128Register(0), NeonS32, 1564 i.InputInt8(1)); 1565 break; 1566 } 1567 case kArmInt32x4ReplaceLane: { 1568 __ ReplaceLane(i.OutputSimd128Register(), i.InputSimd128Register(0), 1569 i.InputRegister(2), NeonS32, i.InputInt8(1)); 1570 break; 1571 } 1572 case kArmInt32x4FromFloat32x4: { 1573 __ vcvt_s32_f32(i.OutputSimd128Register(), i.InputSimd128Register(0)); 1574 break; 1575 } 1576 case kArmUint32x4FromFloat32x4: { 1577 __ vcvt_u32_f32(i.OutputSimd128Register(), i.InputSimd128Register(0)); 1578 break; 1579 } 1580 case kArmInt32x4Neg: { 1581 __ vneg(Neon32, i.OutputSimd128Register(), i.InputSimd128Register(0)); 1582 break; 1583 } 1584 case kArmInt32x4ShiftLeftByScalar: { 1585 __ vshl(NeonS32, i.OutputSimd128Register(), i.InputSimd128Register(0), 1586 i.InputInt5(1)); 1587 break; 1588 } 1589 case kArmInt32x4ShiftRightByScalar: { 1590 __ vshr(NeonS32, i.OutputSimd128Register(), i.InputSimd128Register(0), 1591 i.InputInt5(1)); 1592 break; 1593 } 1594 case kArmInt32x4Add: { 1595 __ vadd(Neon32, i.OutputSimd128Register(), i.InputSimd128Register(0), 1596 i.InputSimd128Register(1)); 1597 break; 1598 } 1599 case kArmInt32x4Sub: { 1600 __ vsub(Neon32, i.OutputSimd128Register(), i.InputSimd128Register(0), 1601 i.InputSimd128Register(1)); 1602 break; 1603 } 1604 case kArmInt32x4Mul: { 1605 __ vmul(Neon32, i.OutputSimd128Register(), i.InputSimd128Register(0), 1606 i.InputSimd128Register(1)); 1607 break; 1608 } 1609 case kArmInt32x4Min: { 1610 __ vmin(NeonS32, i.OutputSimd128Register(), i.InputSimd128Register(0), 1611 i.InputSimd128Register(1)); 1612 break; 1613 } 1614 case kArmInt32x4Max: { 1615 __ vmax(NeonS32, i.OutputSimd128Register(), i.InputSimd128Register(0), 1616 i.InputSimd128Register(1)); 1617 break; 1618 } 1619 case kArmInt32x4Equal: { 1620 __ vceq(Neon32, i.OutputSimd128Register(), i.InputSimd128Register(0), 1621 i.InputSimd128Register(1)); 1622 break; 1623 } 1624 case kArmInt32x4NotEqual: { 1625 Simd128Register dst = i.OutputSimd128Register(); 1626 __ vceq(Neon32, dst, i.InputSimd128Register(0), 1627 i.InputSimd128Register(1)); 1628 __ vmvn(dst, dst); 1629 break; 1630 } 1631 case kArmInt32x4GreaterThan: { 1632 __ vcgt(NeonS32, i.OutputSimd128Register(), i.InputSimd128Register(0), 1633 i.InputSimd128Register(1)); 1634 break; 1635 } 1636 case kArmInt32x4GreaterThanOrEqual: { 1637 Simd128Register dst = i.OutputSimd128Register(); 1638 __ vcge(NeonS32, dst, i.InputSimd128Register(0), 1639 i.InputSimd128Register(1)); 1640 break; 1641 } 1642 case kArmUint32x4ShiftRightByScalar: { 1643 __ vshr(NeonU32, i.OutputSimd128Register(), i.InputSimd128Register(0), 1644 i.InputInt5(1)); 1645 break; 1646 } 1647 case kArmUint32x4Min: { 1648 __ vmin(NeonU32, i.OutputSimd128Register(), i.InputSimd128Register(0), 1649 i.InputSimd128Register(1)); 1650 break; 1651 } 1652 case kArmUint32x4Max: { 1653 __ vmax(NeonU32, i.OutputSimd128Register(), i.InputSimd128Register(0), 1654 i.InputSimd128Register(1)); 1655 break; 1656 } 1657 case kArmUint32x4GreaterThan: { 1658 __ vcgt(NeonU32, i.OutputSimd128Register(), i.InputSimd128Register(0), 1659 i.InputSimd128Register(1)); 1660 break; 1661 } 1662 case kArmUint32x4GreaterThanOrEqual: { 1663 Simd128Register dst = i.OutputSimd128Register(); 1664 __ vcge(NeonU32, dst, i.InputSimd128Register(0), 1665 i.InputSimd128Register(1)); 1666 break; 1667 } 1668 case kArmInt16x8Splat: { 1669 __ vdup(Neon16, i.OutputSimd128Register(), i.InputRegister(0)); 1670 break; 1671 } 1672 case kArmInt16x8ExtractLane: { 1673 __ ExtractLane(i.OutputRegister(), i.InputSimd128Register(0), NeonS16, 1674 i.InputInt8(1)); 1675 break; 1676 } 1677 case kArmInt16x8ReplaceLane: { 1678 __ ReplaceLane(i.OutputSimd128Register(), i.InputSimd128Register(0), 1679 i.InputRegister(2), NeonS16, i.InputInt8(1)); 1680 break; 1681 } 1682 case kArmInt16x8Neg: { 1683 __ vneg(Neon16, i.OutputSimd128Register(), i.InputSimd128Register(0)); 1684 break; 1685 } 1686 case kArmInt16x8ShiftLeftByScalar: { 1687 __ vshl(NeonS16, i.OutputSimd128Register(), i.InputSimd128Register(0), 1688 i.InputInt4(1)); 1689 break; 1690 } 1691 case kArmInt16x8ShiftRightByScalar: { 1692 __ vshr(NeonS16, i.OutputSimd128Register(), i.InputSimd128Register(0), 1693 i.InputInt4(1)); 1694 break; 1695 } 1696 case kArmInt16x8Add: { 1697 __ vadd(Neon16, i.OutputSimd128Register(), i.InputSimd128Register(0), 1698 i.InputSimd128Register(1)); 1699 break; 1700 } 1701 case kArmInt16x8AddSaturate: { 1702 __ vqadd(NeonS16, i.OutputSimd128Register(), i.InputSimd128Register(0), 1703 i.InputSimd128Register(1)); 1704 break; 1705 } 1706 case kArmInt16x8Sub: { 1707 __ vsub(Neon16, i.OutputSimd128Register(), i.InputSimd128Register(0), 1708 i.InputSimd128Register(1)); 1709 break; 1710 } 1711 case kArmInt16x8SubSaturate: { 1712 __ vqsub(NeonS16, i.OutputSimd128Register(), i.InputSimd128Register(0), 1713 i.InputSimd128Register(1)); 1714 break; 1715 } 1716 case kArmInt16x8Mul: { 1717 __ vmul(Neon16, i.OutputSimd128Register(), i.InputSimd128Register(0), 1718 i.InputSimd128Register(1)); 1719 break; 1720 } 1721 case kArmInt16x8Min: { 1722 __ vmin(NeonS16, i.OutputSimd128Register(), i.InputSimd128Register(0), 1723 i.InputSimd128Register(1)); 1724 break; 1725 } 1726 case kArmInt16x8Max: { 1727 __ vmax(NeonS16, i.OutputSimd128Register(), i.InputSimd128Register(0), 1728 i.InputSimd128Register(1)); 1729 break; 1730 } 1731 case kArmInt16x8Equal: { 1732 __ vceq(Neon16, i.OutputSimd128Register(), i.InputSimd128Register(0), 1733 i.InputSimd128Register(1)); 1734 break; 1735 } 1736 case kArmInt16x8NotEqual: { 1737 Simd128Register dst = i.OutputSimd128Register(); 1738 __ vceq(Neon16, dst, i.InputSimd128Register(0), 1739 i.InputSimd128Register(1)); 1740 __ vmvn(dst, dst); 1741 break; 1742 } 1743 case kArmInt16x8GreaterThan: { 1744 __ vcgt(NeonS16, i.OutputSimd128Register(), i.InputSimd128Register(0), 1745 i.InputSimd128Register(1)); 1746 break; 1747 } 1748 case kArmInt16x8GreaterThanOrEqual: { 1749 Simd128Register dst = i.OutputSimd128Register(); 1750 __ vcge(NeonS16, dst, i.InputSimd128Register(0), 1751 i.InputSimd128Register(1)); 1752 break; 1753 } 1754 case kArmUint16x8ShiftRightByScalar: { 1755 __ vshr(NeonU16, i.OutputSimd128Register(), i.InputSimd128Register(0), 1756 i.InputInt4(1)); 1757 break; 1758 } 1759 case kArmUint16x8AddSaturate: { 1760 __ vqadd(NeonU16, i.OutputSimd128Register(), i.InputSimd128Register(0), 1761 i.InputSimd128Register(1)); 1762 break; 1763 } 1764 case kArmUint16x8SubSaturate: { 1765 __ vqsub(NeonU16, i.OutputSimd128Register(), i.InputSimd128Register(0), 1766 i.InputSimd128Register(1)); 1767 break; 1768 } 1769 case kArmUint16x8Min: { 1770 __ vmin(NeonU16, i.OutputSimd128Register(), i.InputSimd128Register(0), 1771 i.InputSimd128Register(1)); 1772 break; 1773 } 1774 case kArmUint16x8Max: { 1775 __ vmax(NeonU16, i.OutputSimd128Register(), i.InputSimd128Register(0), 1776 i.InputSimd128Register(1)); 1777 break; 1778 } 1779 case kArmUint16x8GreaterThan: { 1780 __ vcgt(NeonU16, i.OutputSimd128Register(), i.InputSimd128Register(0), 1781 i.InputSimd128Register(1)); 1782 break; 1783 } 1784 case kArmUint16x8GreaterThanOrEqual: { 1785 Simd128Register dst = i.OutputSimd128Register(); 1786 __ vcge(NeonU16, dst, i.InputSimd128Register(0), 1787 i.InputSimd128Register(1)); 1788 break; 1789 } 1790 case kArmInt8x16Splat: { 1791 __ vdup(Neon8, i.OutputSimd128Register(), i.InputRegister(0)); 1792 break; 1793 } 1794 case kArmInt8x16ExtractLane: { 1795 __ ExtractLane(i.OutputRegister(), i.InputSimd128Register(0), NeonS8, 1796 i.InputInt8(1)); 1797 break; 1798 } 1799 case kArmInt8x16ReplaceLane: { 1800 __ ReplaceLane(i.OutputSimd128Register(), i.InputSimd128Register(0), 1801 i.InputRegister(2), NeonS8, i.InputInt8(1)); 1802 break; 1803 } 1804 case kArmInt8x16Neg: { 1805 __ vneg(Neon8, i.OutputSimd128Register(), i.InputSimd128Register(0)); 1806 break; 1807 } 1808 case kArmInt8x16ShiftLeftByScalar: { 1809 __ vshl(NeonS8, i.OutputSimd128Register(), i.InputSimd128Register(0), 1810 i.InputInt3(1)); 1811 break; 1812 } 1813 case kArmInt8x16ShiftRightByScalar: { 1814 __ vshr(NeonS8, i.OutputSimd128Register(), i.InputSimd128Register(0), 1815 i.InputInt3(1)); 1816 break; 1817 } 1818 case kArmInt8x16Add: { 1819 __ vadd(Neon8, i.OutputSimd128Register(), i.InputSimd128Register(0), 1820 i.InputSimd128Register(1)); 1821 break; 1822 } 1823 case kArmInt8x16AddSaturate: { 1824 __ vqadd(NeonS8, i.OutputSimd128Register(), i.InputSimd128Register(0), 1825 i.InputSimd128Register(1)); 1826 break; 1827 } 1828 case kArmInt8x16Sub: { 1829 __ vsub(Neon8, i.OutputSimd128Register(), i.InputSimd128Register(0), 1830 i.InputSimd128Register(1)); 1831 break; 1832 } 1833 case kArmInt8x16SubSaturate: { 1834 __ vqsub(NeonS8, i.OutputSimd128Register(), i.InputSimd128Register(0), 1835 i.InputSimd128Register(1)); 1836 break; 1837 } 1838 case kArmInt8x16Mul: { 1839 __ vmul(Neon8, i.OutputSimd128Register(), i.InputSimd128Register(0), 1840 i.InputSimd128Register(1)); 1841 break; 1842 } 1843 case kArmInt8x16Min: { 1844 __ vmin(NeonS8, i.OutputSimd128Register(), i.InputSimd128Register(0), 1845 i.InputSimd128Register(1)); 1846 break; 1847 } 1848 case kArmInt8x16Max: { 1849 __ vmax(NeonS8, i.OutputSimd128Register(), i.InputSimd128Register(0), 1850 i.InputSimd128Register(1)); 1851 break; 1852 } 1853 case kArmInt8x16Equal: { 1854 __ vceq(Neon8, i.OutputSimd128Register(), i.InputSimd128Register(0), 1855 i.InputSimd128Register(1)); 1856 break; 1857 } 1858 case kArmInt8x16NotEqual: { 1859 Simd128Register dst = i.OutputSimd128Register(); 1860 __ vceq(Neon8, dst, i.InputSimd128Register(0), i.InputSimd128Register(1)); 1861 __ vmvn(dst, dst); 1862 break; 1863 } 1864 case kArmInt8x16GreaterThan: { 1865 __ vcgt(NeonS8, i.OutputSimd128Register(), i.InputSimd128Register(0), 1866 i.InputSimd128Register(1)); 1867 break; 1868 } 1869 case kArmInt8x16GreaterThanOrEqual: { 1870 Simd128Register dst = i.OutputSimd128Register(); 1871 __ vcge(NeonS8, dst, i.InputSimd128Register(0), 1872 i.InputSimd128Register(1)); 1873 break; 1874 } 1875 case kArmUint8x16ShiftRightByScalar: { 1876 __ vshr(NeonU8, i.OutputSimd128Register(), i.InputSimd128Register(0), 1877 i.InputInt3(1)); 1878 break; 1879 } 1880 case kArmUint8x16AddSaturate: { 1881 __ vqadd(NeonU8, i.OutputSimd128Register(), i.InputSimd128Register(0), 1882 i.InputSimd128Register(1)); 1883 break; 1884 } 1885 case kArmUint8x16SubSaturate: { 1886 __ vqsub(NeonU8, i.OutputSimd128Register(), i.InputSimd128Register(0), 1887 i.InputSimd128Register(1)); 1888 break; 1889 } 1890 case kArmUint8x16Min: { 1891 __ vmin(NeonU8, i.OutputSimd128Register(), i.InputSimd128Register(0), 1892 i.InputSimd128Register(1)); 1893 break; 1894 } 1895 case kArmUint8x16Max: { 1896 __ vmax(NeonU8, i.OutputSimd128Register(), i.InputSimd128Register(0), 1897 i.InputSimd128Register(1)); 1898 break; 1899 } 1900 case kArmUint8x16GreaterThan: { 1901 __ vcgt(NeonU8, i.OutputSimd128Register(), i.InputSimd128Register(0), 1902 i.InputSimd128Register(1)); 1903 break; 1904 } 1905 case kArmUint8x16GreaterThanOrEqual: { 1906 Simd128Register dst = i.OutputSimd128Register(); 1907 __ vcge(NeonU8, dst, i.InputSimd128Register(0), 1908 i.InputSimd128Register(1)); 1909 break; 1910 } 1911 case kArmSimd128And: { 1912 __ vand(i.OutputSimd128Register(), i.InputSimd128Register(0), 1913 i.InputSimd128Register(1)); 1914 break; 1915 } 1916 case kArmSimd128Or: { 1917 __ vorr(i.OutputSimd128Register(), i.InputSimd128Register(0), 1918 i.InputSimd128Register(1)); 1919 break; 1920 } 1921 case kArmSimd128Xor: { 1922 __ veor(i.OutputSimd128Register(), i.InputSimd128Register(0), 1923 i.InputSimd128Register(1)); 1924 break; 1925 } 1926 case kArmSimd128Not: { 1927 __ vmvn(i.OutputSimd128Register(), i.InputSimd128Register(0)); 1928 break; 1929 } 1930 case kArmSimd32x4Select: 1931 case kArmSimd16x8Select: 1932 case kArmSimd8x16Select: { 1933 // vbsl clobbers the mask input so make sure it was DefineSameAsFirst. 1934 DCHECK(i.OutputSimd128Register().is(i.InputSimd128Register(0))); 1935 __ vbsl(i.OutputSimd128Register(), i.InputSimd128Register(1), 1936 i.InputSimd128Register(2)); 1937 break; 1938 } 1939 case kCheckedLoadInt8: 1940 ASSEMBLE_CHECKED_LOAD_INTEGER(ldrsb); 1941 break; 1942 case kCheckedLoadUint8: 1943 ASSEMBLE_CHECKED_LOAD_INTEGER(ldrb); 1944 break; 1945 case kCheckedLoadInt16: 1946 ASSEMBLE_CHECKED_LOAD_INTEGER(ldrsh); 1947 break; 1948 case kCheckedLoadUint16: 1949 ASSEMBLE_CHECKED_LOAD_INTEGER(ldrh); 1950 break; 1951 case kCheckedLoadWord32: 1952 ASSEMBLE_CHECKED_LOAD_INTEGER(ldr); 1953 break; 1954 case kCheckedLoadFloat32: 1955 ASSEMBLE_CHECKED_LOAD_FP(Float); 1956 break; 1957 case kCheckedLoadFloat64: 1958 ASSEMBLE_CHECKED_LOAD_FP(Double); 1959 break; 1960 case kCheckedStoreWord8: 1961 ASSEMBLE_CHECKED_STORE_INTEGER(strb); 1962 break; 1963 case kCheckedStoreWord16: 1964 ASSEMBLE_CHECKED_STORE_INTEGER(strh); 1965 break; 1966 case kCheckedStoreWord32: 1967 ASSEMBLE_CHECKED_STORE_INTEGER(str); 1968 break; 1969 case kCheckedStoreFloat32: 1970 ASSEMBLE_CHECKED_STORE_FP(Float); 1971 break; 1972 case kCheckedStoreFloat64: 1973 ASSEMBLE_CHECKED_STORE_FP(Double); 1974 break; 1975 case kCheckedLoadWord64: 1976 case kCheckedStoreWord64: 1977 UNREACHABLE(); // currently unsupported checked int64 load/store. 1978 break; 1979 1980 case kAtomicLoadInt8: 1981 ASSEMBLE_ATOMIC_LOAD_INTEGER(ldrsb); 1982 break; 1983 case kAtomicLoadUint8: 1984 ASSEMBLE_ATOMIC_LOAD_INTEGER(ldrb); 1985 break; 1986 case kAtomicLoadInt16: 1987 ASSEMBLE_ATOMIC_LOAD_INTEGER(ldrsh); 1988 break; 1989 case kAtomicLoadUint16: 1990 ASSEMBLE_ATOMIC_LOAD_INTEGER(ldrh); 1991 break; 1992 case kAtomicLoadWord32: 1993 ASSEMBLE_ATOMIC_LOAD_INTEGER(ldr); 1994 break; 1995 1996 case kAtomicStoreWord8: 1997 ASSEMBLE_ATOMIC_STORE_INTEGER(strb); 1998 break; 1999 case kAtomicStoreWord16: 2000 ASSEMBLE_ATOMIC_STORE_INTEGER(strh); 2001 break; 2002 case kAtomicStoreWord32: 2003 ASSEMBLE_ATOMIC_STORE_INTEGER(str); 2004 break; 2005 } 2006 return kSuccess; 2007 } // NOLINT(readability/fn_size) 2008 2009 2010 // Assembles branches after an instruction. 2011 void CodeGenerator::AssembleArchBranch(Instruction* instr, BranchInfo* branch) { 2012 ArmOperandConverter i(this, instr); 2013 Label* tlabel = branch->true_label; 2014 Label* flabel = branch->false_label; 2015 Condition cc = FlagsConditionToCondition(branch->condition); 2016 __ b(cc, tlabel); 2017 if (!branch->fallthru) __ b(flabel); // no fallthru to flabel. 2018 } 2019 2020 2021 void CodeGenerator::AssembleArchJump(RpoNumber target) { 2022 if (!IsNextInAssemblyOrder(target)) __ b(GetLabel(target)); 2023 } 2024 2025 void CodeGenerator::AssembleArchTrap(Instruction* instr, 2026 FlagsCondition condition) { 2027 class OutOfLineTrap final : public OutOfLineCode { 2028 public: 2029 OutOfLineTrap(CodeGenerator* gen, bool frame_elided, Instruction* instr) 2030 : OutOfLineCode(gen), 2031 frame_elided_(frame_elided), 2032 instr_(instr), 2033 gen_(gen) {} 2034 2035 void Generate() final { 2036 ArmOperandConverter i(gen_, instr_); 2037 2038 Builtins::Name trap_id = 2039 static_cast<Builtins::Name>(i.InputInt32(instr_->InputCount() - 1)); 2040 bool old_has_frame = __ has_frame(); 2041 if (frame_elided_) { 2042 __ set_has_frame(true); 2043 __ EnterFrame(StackFrame::WASM_COMPILED); 2044 } 2045 GenerateCallToTrap(trap_id); 2046 if (frame_elided_) { 2047 __ set_has_frame(old_has_frame); 2048 } 2049 } 2050 2051 private: 2052 void GenerateCallToTrap(Builtins::Name trap_id) { 2053 if (trap_id == Builtins::builtin_count) { 2054 // We cannot test calls to the runtime in cctest/test-run-wasm. 2055 // Therefore we emit a call to C here instead of a call to the runtime. 2056 // We use the context register as the scratch register, because we do 2057 // not have a context here. 2058 __ PrepareCallCFunction(0, 0, cp); 2059 __ CallCFunction( 2060 ExternalReference::wasm_call_trap_callback_for_testing(isolate()), 2061 0); 2062 __ LeaveFrame(StackFrame::WASM_COMPILED); 2063 __ Ret(); 2064 } else { 2065 gen_->AssembleSourcePosition(instr_); 2066 __ Call(handle(isolate()->builtins()->builtin(trap_id), isolate()), 2067 RelocInfo::CODE_TARGET); 2068 ReferenceMap* reference_map = 2069 new (gen_->zone()) ReferenceMap(gen_->zone()); 2070 gen_->RecordSafepoint(reference_map, Safepoint::kSimple, 0, 2071 Safepoint::kNoLazyDeopt); 2072 if (FLAG_debug_code) { 2073 __ stop(GetBailoutReason(kUnexpectedReturnFromWasmTrap)); 2074 } 2075 } 2076 } 2077 2078 bool frame_elided_; 2079 Instruction* instr_; 2080 CodeGenerator* gen_; 2081 }; 2082 bool frame_elided = !frame_access_state()->has_frame(); 2083 auto ool = new (zone()) OutOfLineTrap(this, frame_elided, instr); 2084 Label* tlabel = ool->entry(); 2085 Condition cc = FlagsConditionToCondition(condition); 2086 __ b(cc, tlabel); 2087 } 2088 2089 // Assembles boolean materializations after an instruction. 2090 void CodeGenerator::AssembleArchBoolean(Instruction* instr, 2091 FlagsCondition condition) { 2092 ArmOperandConverter i(this, instr); 2093 2094 // Materialize a full 32-bit 1 or 0 value. The result register is always the 2095 // last output of the instruction. 2096 DCHECK_NE(0u, instr->OutputCount()); 2097 Register reg = i.OutputRegister(instr->OutputCount() - 1); 2098 Condition cc = FlagsConditionToCondition(condition); 2099 __ mov(reg, Operand(0)); 2100 __ mov(reg, Operand(1), LeaveCC, cc); 2101 } 2102 2103 2104 void CodeGenerator::AssembleArchLookupSwitch(Instruction* instr) { 2105 ArmOperandConverter i(this, instr); 2106 Register input = i.InputRegister(0); 2107 for (size_t index = 2; index < instr->InputCount(); index += 2) { 2108 __ cmp(input, Operand(i.InputInt32(index + 0))); 2109 __ b(eq, GetLabel(i.InputRpo(index + 1))); 2110 } 2111 AssembleArchJump(i.InputRpo(1)); 2112 } 2113 2114 2115 void CodeGenerator::AssembleArchTableSwitch(Instruction* instr) { 2116 ArmOperandConverter i(this, instr); 2117 Register input = i.InputRegister(0); 2118 size_t const case_count = instr->InputCount() - 2; 2119 // Ensure to emit the constant pool first if necessary. 2120 __ CheckConstPool(true, true); 2121 __ cmp(input, Operand(case_count)); 2122 __ BlockConstPoolFor(case_count + 2); 2123 __ add(pc, pc, Operand(input, LSL, 2), LeaveCC, lo); 2124 __ b(GetLabel(i.InputRpo(1))); 2125 for (size_t index = 0; index < case_count; ++index) { 2126 __ b(GetLabel(i.InputRpo(index + 2))); 2127 } 2128 } 2129 2130 CodeGenerator::CodeGenResult CodeGenerator::AssembleDeoptimizerCall( 2131 int deoptimization_id, SourcePosition pos) { 2132 DeoptimizeKind deoptimization_kind = GetDeoptimizationKind(deoptimization_id); 2133 DeoptimizeReason deoptimization_reason = 2134 GetDeoptimizationReason(deoptimization_id); 2135 Deoptimizer::BailoutType bailout_type = 2136 deoptimization_kind == DeoptimizeKind::kSoft ? Deoptimizer::SOFT 2137 : Deoptimizer::EAGER; 2138 Address deopt_entry = Deoptimizer::GetDeoptimizationEntry( 2139 isolate(), deoptimization_id, bailout_type); 2140 // TODO(turbofan): We should be able to generate better code by sharing the 2141 // actual final call site and just bl'ing to it here, similar to what we do 2142 // in the lithium backend. 2143 if (deopt_entry == nullptr) return kTooManyDeoptimizationBailouts; 2144 __ RecordDeoptReason(deoptimization_reason, pos, deoptimization_id); 2145 __ Call(deopt_entry, RelocInfo::RUNTIME_ENTRY); 2146 __ CheckConstPool(false, false); 2147 return kSuccess; 2148 } 2149 2150 void CodeGenerator::FinishFrame(Frame* frame) { 2151 CallDescriptor* descriptor = linkage()->GetIncomingDescriptor(); 2152 2153 const RegList saves_fp = descriptor->CalleeSavedFPRegisters(); 2154 if (saves_fp != 0) { 2155 frame->AlignSavedCalleeRegisterSlots(); 2156 } 2157 2158 if (saves_fp != 0) { 2159 // Save callee-saved FP registers. 2160 STATIC_ASSERT(DwVfpRegister::kMaxNumRegisters == 32); 2161 uint32_t last = base::bits::CountLeadingZeros32(saves_fp) - 1; 2162 uint32_t first = base::bits::CountTrailingZeros32(saves_fp); 2163 DCHECK_EQ((last - first + 1), base::bits::CountPopulation32(saves_fp)); 2164 frame->AllocateSavedCalleeRegisterSlots((last - first + 1) * 2165 (kDoubleSize / kPointerSize)); 2166 } 2167 const RegList saves = FLAG_enable_embedded_constant_pool 2168 ? (descriptor->CalleeSavedRegisters() & ~pp.bit()) 2169 : descriptor->CalleeSavedRegisters(); 2170 if (saves != 0) { 2171 // Save callee-saved registers. 2172 frame->AllocateSavedCalleeRegisterSlots( 2173 base::bits::CountPopulation32(saves)); 2174 } 2175 } 2176 2177 void CodeGenerator::AssembleConstructFrame() { 2178 CallDescriptor* descriptor = linkage()->GetIncomingDescriptor(); 2179 if (frame_access_state()->has_frame()) { 2180 if (descriptor->IsCFunctionCall()) { 2181 if (FLAG_enable_embedded_constant_pool) { 2182 __ Push(lr, fp, pp); 2183 // Adjust FP to point to saved FP. 2184 __ sub(fp, sp, Operand(StandardFrameConstants::kConstantPoolOffset)); 2185 } else { 2186 __ Push(lr, fp); 2187 __ mov(fp, sp); 2188 } 2189 } else if (descriptor->IsJSFunctionCall()) { 2190 __ Prologue(this->info()->GeneratePreagedPrologue()); 2191 if (descriptor->PushArgumentCount()) { 2192 __ Push(kJavaScriptCallArgCountRegister); 2193 } 2194 } else { 2195 __ StubPrologue(info()->GetOutputStackFrameType()); 2196 } 2197 2198 if (!info()->GeneratePreagedPrologue()) { 2199 unwinding_info_writer_.MarkFrameConstructed(__ pc_offset()); 2200 } 2201 } 2202 2203 int shrink_slots = 2204 frame()->GetTotalFrameSlotCount() - descriptor->CalculateFixedFrameSize(); 2205 2206 if (info()->is_osr()) { 2207 // TurboFan OSR-compiled functions cannot be entered directly. 2208 __ Abort(kShouldNotDirectlyEnterOsrFunction); 2209 2210 // Unoptimized code jumps directly to this entrypoint while the unoptimized 2211 // frame is still on the stack. Optimized code uses OSR values directly from 2212 // the unoptimized frame. Thus, all that needs to be done is to allocate the 2213 // remaining stack slots. 2214 if (FLAG_code_comments) __ RecordComment("-- OSR entrypoint --"); 2215 osr_pc_offset_ = __ pc_offset(); 2216 shrink_slots -= OsrHelper(info()).UnoptimizedFrameSlots(); 2217 } 2218 2219 const RegList saves_fp = descriptor->CalleeSavedFPRegisters(); 2220 if (shrink_slots > 0) { 2221 __ sub(sp, sp, Operand(shrink_slots * kPointerSize)); 2222 } 2223 2224 if (saves_fp != 0) { 2225 // Save callee-saved FP registers. 2226 STATIC_ASSERT(DwVfpRegister::kMaxNumRegisters == 32); 2227 uint32_t last = base::bits::CountLeadingZeros32(saves_fp) - 1; 2228 uint32_t first = base::bits::CountTrailingZeros32(saves_fp); 2229 DCHECK_EQ((last - first + 1), base::bits::CountPopulation32(saves_fp)); 2230 __ vstm(db_w, sp, DwVfpRegister::from_code(first), 2231 DwVfpRegister::from_code(last)); 2232 } 2233 const RegList saves = FLAG_enable_embedded_constant_pool 2234 ? (descriptor->CalleeSavedRegisters() & ~pp.bit()) 2235 : descriptor->CalleeSavedRegisters(); 2236 if (saves != 0) { 2237 // Save callee-saved registers. 2238 __ stm(db_w, sp, saves); 2239 } 2240 } 2241 2242 void CodeGenerator::AssembleReturn(InstructionOperand* pop) { 2243 CallDescriptor* descriptor = linkage()->GetIncomingDescriptor(); 2244 int pop_count = static_cast<int>(descriptor->StackParameterCount()); 2245 2246 // Restore registers. 2247 const RegList saves = FLAG_enable_embedded_constant_pool 2248 ? (descriptor->CalleeSavedRegisters() & ~pp.bit()) 2249 : descriptor->CalleeSavedRegisters(); 2250 if (saves != 0) { 2251 __ ldm(ia_w, sp, saves); 2252 } 2253 2254 // Restore FP registers. 2255 const RegList saves_fp = descriptor->CalleeSavedFPRegisters(); 2256 if (saves_fp != 0) { 2257 STATIC_ASSERT(DwVfpRegister::kMaxNumRegisters == 32); 2258 uint32_t last = base::bits::CountLeadingZeros32(saves_fp) - 1; 2259 uint32_t first = base::bits::CountTrailingZeros32(saves_fp); 2260 __ vldm(ia_w, sp, DwVfpRegister::from_code(first), 2261 DwVfpRegister::from_code(last)); 2262 } 2263 2264 unwinding_info_writer_.MarkBlockWillExit(); 2265 2266 ArmOperandConverter g(this, nullptr); 2267 if (descriptor->IsCFunctionCall()) { 2268 AssembleDeconstructFrame(); 2269 } else if (frame_access_state()->has_frame()) { 2270 // Canonicalize JSFunction return sites for now unless they have an variable 2271 // number of stack slot pops. 2272 if (pop->IsImmediate() && g.ToConstant(pop).ToInt32() == 0) { 2273 if (return_label_.is_bound()) { 2274 __ b(&return_label_); 2275 return; 2276 } else { 2277 __ bind(&return_label_); 2278 AssembleDeconstructFrame(); 2279 } 2280 } else { 2281 AssembleDeconstructFrame(); 2282 } 2283 } 2284 2285 if (pop->IsImmediate()) { 2286 DCHECK_EQ(Constant::kInt32, g.ToConstant(pop).type()); 2287 pop_count += g.ToConstant(pop).ToInt32(); 2288 } else { 2289 __ Drop(g.ToRegister(pop)); 2290 } 2291 __ Drop(pop_count); 2292 __ Ret(); 2293 } 2294 2295 void CodeGenerator::AssembleMove(InstructionOperand* source, 2296 InstructionOperand* destination) { 2297 ArmOperandConverter g(this, nullptr); 2298 // Dispatch on the source and destination operand kinds. Not all 2299 // combinations are possible. 2300 if (source->IsRegister()) { 2301 DCHECK(destination->IsRegister() || destination->IsStackSlot()); 2302 Register src = g.ToRegister(source); 2303 if (destination->IsRegister()) { 2304 __ mov(g.ToRegister(destination), src); 2305 } else { 2306 __ str(src, g.ToMemOperand(destination)); 2307 } 2308 } else if (source->IsStackSlot()) { 2309 DCHECK(destination->IsRegister() || destination->IsStackSlot()); 2310 MemOperand src = g.ToMemOperand(source); 2311 if (destination->IsRegister()) { 2312 __ ldr(g.ToRegister(destination), src); 2313 } else { 2314 Register temp = kScratchReg; 2315 __ ldr(temp, src); 2316 __ str(temp, g.ToMemOperand(destination)); 2317 } 2318 } else if (source->IsConstant()) { 2319 Constant src = g.ToConstant(source); 2320 if (destination->IsRegister() || destination->IsStackSlot()) { 2321 Register dst = 2322 destination->IsRegister() ? g.ToRegister(destination) : kScratchReg; 2323 switch (src.type()) { 2324 case Constant::kInt32: 2325 if (RelocInfo::IsWasmReference(src.rmode())) { 2326 __ mov(dst, Operand(src.ToInt32(), src.rmode())); 2327 } else { 2328 __ mov(dst, Operand(src.ToInt32())); 2329 } 2330 break; 2331 case Constant::kInt64: 2332 UNREACHABLE(); 2333 break; 2334 case Constant::kFloat32: 2335 __ Move(dst, 2336 isolate()->factory()->NewNumber(src.ToFloat32(), TENURED)); 2337 break; 2338 case Constant::kFloat64: 2339 __ Move(dst, 2340 isolate()->factory()->NewNumber(src.ToFloat64(), TENURED)); 2341 break; 2342 case Constant::kExternalReference: 2343 __ mov(dst, Operand(src.ToExternalReference())); 2344 break; 2345 case Constant::kHeapObject: { 2346 Handle<HeapObject> src_object = src.ToHeapObject(); 2347 Heap::RootListIndex index; 2348 if (IsMaterializableFromRoot(src_object, &index)) { 2349 __ LoadRoot(dst, index); 2350 } else { 2351 __ Move(dst, src_object); 2352 } 2353 break; 2354 } 2355 case Constant::kRpoNumber: 2356 UNREACHABLE(); // TODO(dcarney): loading RPO constants on arm. 2357 break; 2358 } 2359 if (destination->IsStackSlot()) __ str(dst, g.ToMemOperand(destination)); 2360 } else if (src.type() == Constant::kFloat32) { 2361 if (destination->IsFloatStackSlot()) { 2362 MemOperand dst = g.ToMemOperand(destination); 2363 __ mov(ip, Operand(bit_cast<int32_t>(src.ToFloat32()))); 2364 __ str(ip, dst); 2365 } else { 2366 SwVfpRegister dst = g.ToFloatRegister(destination); 2367 __ vmov(dst, src.ToFloat32()); 2368 } 2369 } else { 2370 DCHECK_EQ(Constant::kFloat64, src.type()); 2371 DwVfpRegister dst = destination->IsFPRegister() 2372 ? g.ToDoubleRegister(destination) 2373 : kScratchDoubleReg; 2374 __ vmov(dst, src.ToFloat64(), kScratchReg); 2375 if (destination->IsDoubleStackSlot()) { 2376 __ vstr(dst, g.ToMemOperand(destination)); 2377 } 2378 } 2379 } else if (source->IsFPRegister()) { 2380 MachineRepresentation rep = LocationOperand::cast(source)->representation(); 2381 if (rep == MachineRepresentation::kFloat64) { 2382 DwVfpRegister src = g.ToDoubleRegister(source); 2383 if (destination->IsDoubleRegister()) { 2384 DwVfpRegister dst = g.ToDoubleRegister(destination); 2385 __ Move(dst, src); 2386 } else { 2387 DCHECK(destination->IsDoubleStackSlot()); 2388 __ vstr(src, g.ToMemOperand(destination)); 2389 } 2390 } else if (rep == MachineRepresentation::kFloat32) { 2391 // GapResolver may give us reg codes that don't map to actual s-registers. 2392 // Generate code to work around those cases. 2393 int src_code = LocationOperand::cast(source)->register_code(); 2394 if (destination->IsFloatRegister()) { 2395 int dst_code = LocationOperand::cast(destination)->register_code(); 2396 __ VmovExtended(dst_code, src_code, kScratchReg); 2397 } else { 2398 DCHECK(destination->IsFloatStackSlot()); 2399 __ VmovExtended(g.ToMemOperand(destination), src_code, kScratchReg); 2400 } 2401 } else { 2402 DCHECK_EQ(MachineRepresentation::kSimd128, rep); 2403 QwNeonRegister src = g.ToSimd128Register(source); 2404 if (destination->IsSimd128Register()) { 2405 QwNeonRegister dst = g.ToSimd128Register(destination); 2406 __ Move(dst, src); 2407 } else { 2408 DCHECK(destination->IsSimd128StackSlot()); 2409 MemOperand dst = g.ToMemOperand(destination); 2410 __ add(kScratchReg, dst.rn(), Operand(dst.offset())); 2411 __ vst1(Neon8, NeonListOperand(src.low(), 2), 2412 NeonMemOperand(kScratchReg)); 2413 } 2414 } 2415 } else if (source->IsFPStackSlot()) { 2416 MemOperand src = g.ToMemOperand(source); 2417 MachineRepresentation rep = 2418 LocationOperand::cast(destination)->representation(); 2419 if (destination->IsFPRegister()) { 2420 if (rep == MachineRepresentation::kFloat64) { 2421 __ vldr(g.ToDoubleRegister(destination), src); 2422 } else if (rep == MachineRepresentation::kFloat32) { 2423 // GapResolver may give us reg codes that don't map to actual 2424 // s-registers. Generate code to work around those cases. 2425 int dst_code = LocationOperand::cast(destination)->register_code(); 2426 __ VmovExtended(dst_code, src, kScratchReg); 2427 } else { 2428 DCHECK_EQ(MachineRepresentation::kSimd128, rep); 2429 QwNeonRegister dst = g.ToSimd128Register(destination); 2430 __ add(kScratchReg, src.rn(), Operand(src.offset())); 2431 __ vld1(Neon8, NeonListOperand(dst.low(), 2), 2432 NeonMemOperand(kScratchReg)); 2433 } 2434 } else if (rep == MachineRepresentation::kFloat64) { 2435 DCHECK(destination->IsFPStackSlot()); 2436 if (rep == MachineRepresentation::kFloat64) { 2437 DwVfpRegister temp = kScratchDoubleReg; 2438 __ vldr(temp, src); 2439 __ vstr(temp, g.ToMemOperand(destination)); 2440 } else if (rep == MachineRepresentation::kFloat32) { 2441 SwVfpRegister temp = kScratchDoubleReg.low(); 2442 __ vldr(temp, src); 2443 __ vstr(temp, g.ToMemOperand(destination)); 2444 } else { 2445 DCHECK_EQ(MachineRepresentation::kSimd128, rep); 2446 MemOperand dst = g.ToMemOperand(destination); 2447 __ add(kScratchReg, src.rn(), Operand(src.offset())); 2448 __ vld1(Neon8, NeonListOperand(kScratchQuadReg.low(), 2), 2449 NeonMemOperand(kScratchReg)); 2450 __ add(kScratchReg, dst.rn(), Operand(dst.offset())); 2451 __ vst1(Neon8, NeonListOperand(kScratchQuadReg.low(), 2), 2452 NeonMemOperand(kScratchReg)); 2453 __ veor(kDoubleRegZero, kDoubleRegZero, kDoubleRegZero); 2454 } 2455 } 2456 } else { 2457 UNREACHABLE(); 2458 } 2459 } 2460 2461 void CodeGenerator::AssembleSwap(InstructionOperand* source, 2462 InstructionOperand* destination) { 2463 ArmOperandConverter g(this, nullptr); 2464 // Dispatch on the source and destination operand kinds. Not all 2465 // combinations are possible. 2466 if (source->IsRegister()) { 2467 // Register-register. 2468 Register temp = kScratchReg; 2469 Register src = g.ToRegister(source); 2470 if (destination->IsRegister()) { 2471 Register dst = g.ToRegister(destination); 2472 __ Move(temp, src); 2473 __ Move(src, dst); 2474 __ Move(dst, temp); 2475 } else { 2476 DCHECK(destination->IsStackSlot()); 2477 MemOperand dst = g.ToMemOperand(destination); 2478 __ mov(temp, src); 2479 __ ldr(src, dst); 2480 __ str(temp, dst); 2481 } 2482 } else if (source->IsStackSlot()) { 2483 DCHECK(destination->IsStackSlot()); 2484 Register temp_0 = kScratchReg; 2485 SwVfpRegister temp_1 = kScratchDoubleReg.low(); 2486 MemOperand src = g.ToMemOperand(source); 2487 MemOperand dst = g.ToMemOperand(destination); 2488 __ ldr(temp_0, src); 2489 __ vldr(temp_1, dst); 2490 __ str(temp_0, dst); 2491 __ vstr(temp_1, src); 2492 } else if (source->IsFPRegister()) { 2493 MachineRepresentation rep = LocationOperand::cast(source)->representation(); 2494 LowDwVfpRegister temp = kScratchDoubleReg; 2495 if (rep == MachineRepresentation::kFloat64) { 2496 DwVfpRegister src = g.ToDoubleRegister(source); 2497 if (destination->IsFPRegister()) { 2498 DwVfpRegister dst = g.ToDoubleRegister(destination); 2499 __ Swap(src, dst); 2500 } else { 2501 DCHECK(destination->IsFPStackSlot()); 2502 MemOperand dst = g.ToMemOperand(destination); 2503 __ Move(temp, src); 2504 __ vldr(src, dst); 2505 __ vstr(temp, dst); 2506 } 2507 } else if (rep == MachineRepresentation::kFloat32) { 2508 int src_code = LocationOperand::cast(source)->register_code(); 2509 if (destination->IsFPRegister()) { 2510 int dst_code = LocationOperand::cast(destination)->register_code(); 2511 __ VmovExtended(temp.low().code(), src_code, kScratchReg); 2512 __ VmovExtended(src_code, dst_code, kScratchReg); 2513 __ VmovExtended(dst_code, temp.low().code(), kScratchReg); 2514 } else { 2515 DCHECK(destination->IsFPStackSlot()); 2516 MemOperand dst = g.ToMemOperand(destination); 2517 __ VmovExtended(temp.low().code(), src_code, kScratchReg); 2518 __ VmovExtended(src_code, dst, kScratchReg); 2519 __ vstr(temp.low(), dst); 2520 } 2521 } else { 2522 DCHECK_EQ(MachineRepresentation::kSimd128, rep); 2523 QwNeonRegister src = g.ToSimd128Register(source); 2524 if (destination->IsFPRegister()) { 2525 QwNeonRegister dst = g.ToSimd128Register(destination); 2526 __ Swap(src, dst); 2527 } else { 2528 DCHECK(destination->IsFPStackSlot()); 2529 MemOperand dst = g.ToMemOperand(destination); 2530 __ Move(kScratchQuadReg, src); 2531 __ add(kScratchReg, dst.rn(), Operand(dst.offset())); 2532 __ vld1(Neon8, NeonListOperand(src.low(), 2), 2533 NeonMemOperand(kScratchReg)); 2534 __ vst1(Neon8, NeonListOperand(kScratchQuadReg.low(), 2), 2535 NeonMemOperand(kScratchReg)); 2536 __ veor(kDoubleRegZero, kDoubleRegZero, kDoubleRegZero); 2537 } 2538 } 2539 } else if (source->IsFPStackSlot()) { 2540 DCHECK(destination->IsFPStackSlot()); 2541 MemOperand src = g.ToMemOperand(source); 2542 MemOperand dst = g.ToMemOperand(destination); 2543 MachineRepresentation rep = LocationOperand::cast(source)->representation(); 2544 if (rep == MachineRepresentation::kFloat64) { 2545 __ vldr(kScratchDoubleReg, dst); 2546 __ vldr(kDoubleRegZero, src); 2547 __ vstr(kScratchDoubleReg, src); 2548 __ vstr(kDoubleRegZero, dst); 2549 // Restore the 0 register. 2550 __ veor(kDoubleRegZero, kDoubleRegZero, kDoubleRegZero); 2551 } else if (rep == MachineRepresentation::kFloat32) { 2552 __ vldr(kScratchDoubleReg.low(), dst); 2553 __ vldr(kScratchDoubleReg.high(), src); 2554 __ vstr(kScratchDoubleReg.low(), src); 2555 __ vstr(kScratchDoubleReg.high(), dst); 2556 } else { 2557 DCHECK_EQ(MachineRepresentation::kSimd128, rep); 2558 __ vldr(kScratchDoubleReg, dst); 2559 __ vldr(kDoubleRegZero, src); 2560 __ vstr(kScratchDoubleReg, src); 2561 __ vstr(kDoubleRegZero, dst); 2562 src.set_offset(src.offset() + kDoubleSize); 2563 dst.set_offset(dst.offset() + kDoubleSize); 2564 __ vldr(kScratchDoubleReg, dst); 2565 __ vldr(kDoubleRegZero, src); 2566 __ vstr(kScratchDoubleReg, src); 2567 __ vstr(kDoubleRegZero, dst); 2568 // Restore the 0 register. 2569 __ veor(kDoubleRegZero, kDoubleRegZero, kDoubleRegZero); 2570 } 2571 } else { 2572 // No other combinations are possible. 2573 UNREACHABLE(); 2574 } 2575 } 2576 2577 void CodeGenerator::AssembleJumpTable(Label** targets, size_t target_count) { 2578 // On 32-bit ARM we emit the jump tables inline. 2579 UNREACHABLE(); 2580 } 2581 2582 2583 void CodeGenerator::EnsureSpaceForLazyDeopt() { 2584 if (!info()->ShouldEnsureSpaceForLazyDeopt()) { 2585 return; 2586 } 2587 2588 int space_needed = Deoptimizer::patch_size(); 2589 // Ensure that we have enough space after the previous lazy-bailout 2590 // instruction for patching the code here. 2591 int current_pc = masm()->pc_offset(); 2592 if (current_pc < last_lazy_deopt_pc_ + space_needed) { 2593 // Block literal pool emission for duration of padding. 2594 v8::internal::Assembler::BlockConstPoolScope block_const_pool(masm()); 2595 int padding_size = last_lazy_deopt_pc_ + space_needed - current_pc; 2596 DCHECK_EQ(0, padding_size % v8::internal::Assembler::kInstrSize); 2597 while (padding_size > 0) { 2598 __ nop(); 2599 padding_size -= v8::internal::Assembler::kInstrSize; 2600 } 2601 } 2602 } 2603 2604 #undef __ 2605 2606 } // namespace compiler 2607 } // namespace internal 2608 } // namespace v8 2609