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 #include "src/compilation-info.h" 7 #include "src/compiler/code-generator-impl.h" 8 #include "src/compiler/gap-resolver.h" 9 #include "src/compiler/node-matchers.h" 10 #include "src/compiler/osr.h" 11 #include "src/mips/macro-assembler-mips.h" 12 13 namespace v8 { 14 namespace internal { 15 namespace compiler { 16 17 #define __ masm()-> 18 19 20 // TODO(plind): Possibly avoid using these lithium names. 21 #define kScratchReg kLithiumScratchReg 22 #define kScratchReg2 kLithiumScratchReg2 23 #define kScratchDoubleReg kLithiumScratchDouble 24 25 26 // TODO(plind): consider renaming these macros. 27 #define TRACE_MSG(msg) \ 28 PrintF("code_gen: \'%s\' in function %s at line %d\n", msg, __FUNCTION__, \ 29 __LINE__) 30 31 #define TRACE_UNIMPL() \ 32 PrintF("UNIMPLEMENTED code_generator_mips: %s at line %d\n", __FUNCTION__, \ 33 __LINE__) 34 35 36 // Adds Mips-specific methods to convert InstructionOperands. 37 class MipsOperandConverter final : public InstructionOperandConverter { 38 public: 39 MipsOperandConverter(CodeGenerator* gen, Instruction* instr) 40 : InstructionOperandConverter(gen, instr) {} 41 42 FloatRegister OutputSingleRegister(size_t index = 0) { 43 return ToSingleRegister(instr_->OutputAt(index)); 44 } 45 46 FloatRegister InputSingleRegister(size_t index) { 47 return ToSingleRegister(instr_->InputAt(index)); 48 } 49 50 FloatRegister ToSingleRegister(InstructionOperand* op) { 51 // Single (Float) and Double register namespace is same on MIPS, 52 // both are typedefs of FPURegister. 53 return ToDoubleRegister(op); 54 } 55 56 Register InputOrZeroRegister(size_t index) { 57 if (instr_->InputAt(index)->IsImmediate()) { 58 DCHECK((InputInt32(index) == 0)); 59 return zero_reg; 60 } 61 return InputRegister(index); 62 } 63 64 DoubleRegister InputOrZeroDoubleRegister(size_t index) { 65 if (instr_->InputAt(index)->IsImmediate()) return kDoubleRegZero; 66 67 return InputDoubleRegister(index); 68 } 69 70 DoubleRegister InputOrZeroSingleRegister(size_t index) { 71 if (instr_->InputAt(index)->IsImmediate()) return kDoubleRegZero; 72 73 return InputSingleRegister(index); 74 } 75 76 Operand InputImmediate(size_t index) { 77 Constant constant = ToConstant(instr_->InputAt(index)); 78 switch (constant.type()) { 79 case Constant::kInt32: 80 return Operand(constant.ToInt32()); 81 case Constant::kInt64: 82 return Operand(constant.ToInt64()); 83 case Constant::kFloat32: 84 return Operand( 85 isolate()->factory()->NewNumber(constant.ToFloat32(), TENURED)); 86 case Constant::kFloat64: 87 return Operand( 88 isolate()->factory()->NewNumber(constant.ToFloat64(), TENURED)); 89 case Constant::kExternalReference: 90 case Constant::kHeapObject: 91 // TODO(plind): Maybe we should handle ExtRef & HeapObj here? 92 // maybe not done on arm due to const pool ?? 93 break; 94 case Constant::kRpoNumber: 95 UNREACHABLE(); // TODO(titzer): RPO immediates on mips? 96 break; 97 } 98 UNREACHABLE(); 99 return Operand(zero_reg); 100 } 101 102 Operand InputOperand(size_t index) { 103 InstructionOperand* op = instr_->InputAt(index); 104 if (op->IsRegister()) { 105 return Operand(ToRegister(op)); 106 } 107 return InputImmediate(index); 108 } 109 110 MemOperand MemoryOperand(size_t* first_index) { 111 const size_t index = *first_index; 112 switch (AddressingModeField::decode(instr_->opcode())) { 113 case kMode_None: 114 break; 115 case kMode_MRI: 116 *first_index += 2; 117 return MemOperand(InputRegister(index + 0), InputInt32(index + 1)); 118 case kMode_MRR: 119 // TODO(plind): r6 address mode, to be implemented ... 120 UNREACHABLE(); 121 } 122 UNREACHABLE(); 123 return MemOperand(no_reg); 124 } 125 126 MemOperand MemoryOperand(size_t index = 0) { return MemoryOperand(&index); } 127 128 MemOperand ToMemOperand(InstructionOperand* op) const { 129 DCHECK_NOT_NULL(op); 130 DCHECK(op->IsStackSlot() || op->IsFPStackSlot()); 131 return SlotToMemOperand(AllocatedOperand::cast(op)->index()); 132 } 133 134 MemOperand SlotToMemOperand(int slot) const { 135 FrameOffset offset = frame_access_state()->GetFrameOffset(slot); 136 return MemOperand(offset.from_stack_pointer() ? sp : fp, offset.offset()); 137 } 138 }; 139 140 141 static inline bool HasRegisterInput(Instruction* instr, size_t index) { 142 return instr->InputAt(index)->IsRegister(); 143 } 144 145 146 namespace { 147 148 class OutOfLineLoadSingle final : public OutOfLineCode { 149 public: 150 OutOfLineLoadSingle(CodeGenerator* gen, FloatRegister result) 151 : OutOfLineCode(gen), result_(result) {} 152 153 void Generate() final { 154 __ Move(result_, std::numeric_limits<float>::quiet_NaN()); 155 } 156 157 private: 158 FloatRegister const result_; 159 }; 160 161 162 class OutOfLineLoadDouble final : public OutOfLineCode { 163 public: 164 OutOfLineLoadDouble(CodeGenerator* gen, DoubleRegister result) 165 : OutOfLineCode(gen), result_(result) {} 166 167 void Generate() final { 168 __ Move(result_, std::numeric_limits<double>::quiet_NaN()); 169 } 170 171 private: 172 DoubleRegister const result_; 173 }; 174 175 176 class OutOfLineLoadInteger final : public OutOfLineCode { 177 public: 178 OutOfLineLoadInteger(CodeGenerator* gen, Register result) 179 : OutOfLineCode(gen), result_(result) {} 180 181 void Generate() final { __ mov(result_, zero_reg); } 182 183 private: 184 Register const result_; 185 }; 186 187 188 class OutOfLineRound : public OutOfLineCode { 189 public: 190 OutOfLineRound(CodeGenerator* gen, DoubleRegister result) 191 : OutOfLineCode(gen), result_(result) {} 192 193 void Generate() final { 194 // Handle rounding to zero case where sign has to be preserved. 195 // High bits of double input already in kScratchReg. 196 __ dsrl(at, kScratchReg, 31); 197 __ dsll(at, at, 31); 198 __ mthc1(at, result_); 199 } 200 201 private: 202 DoubleRegister const result_; 203 }; 204 205 206 class OutOfLineRound32 : public OutOfLineCode { 207 public: 208 OutOfLineRound32(CodeGenerator* gen, DoubleRegister result) 209 : OutOfLineCode(gen), result_(result) {} 210 211 void Generate() final { 212 // Handle rounding to zero case where sign has to be preserved. 213 // High bits of float input already in kScratchReg. 214 __ srl(at, kScratchReg, 31); 215 __ sll(at, at, 31); 216 __ mtc1(at, result_); 217 } 218 219 private: 220 DoubleRegister const result_; 221 }; 222 223 224 class OutOfLineRecordWrite final : public OutOfLineCode { 225 public: 226 OutOfLineRecordWrite(CodeGenerator* gen, Register object, Register index, 227 Register value, Register scratch0, Register scratch1, 228 RecordWriteMode mode) 229 : OutOfLineCode(gen), 230 object_(object), 231 index_(index), 232 value_(value), 233 scratch0_(scratch0), 234 scratch1_(scratch1), 235 mode_(mode), 236 must_save_lr_(!gen->frame_access_state()->has_frame()) {} 237 238 void Generate() final { 239 if (mode_ > RecordWriteMode::kValueIsPointer) { 240 __ JumpIfSmi(value_, exit()); 241 } 242 __ CheckPageFlag(value_, scratch0_, 243 MemoryChunk::kPointersToHereAreInterestingMask, eq, 244 exit()); 245 RememberedSetAction const remembered_set_action = 246 mode_ > RecordWriteMode::kValueIsMap ? EMIT_REMEMBERED_SET 247 : OMIT_REMEMBERED_SET; 248 SaveFPRegsMode const save_fp_mode = 249 frame()->DidAllocateDoubleRegisters() ? kSaveFPRegs : kDontSaveFPRegs; 250 if (must_save_lr_) { 251 // We need to save and restore ra if the frame was elided. 252 __ Push(ra); 253 } 254 RecordWriteStub stub(isolate(), object_, scratch0_, scratch1_, 255 remembered_set_action, save_fp_mode); 256 __ Daddu(scratch1_, object_, index_); 257 __ CallStub(&stub); 258 if (must_save_lr_) { 259 __ Pop(ra); 260 } 261 } 262 263 private: 264 Register const object_; 265 Register const index_; 266 Register const value_; 267 Register const scratch0_; 268 Register const scratch1_; 269 RecordWriteMode const mode_; 270 bool must_save_lr_; 271 }; 272 273 274 Condition FlagsConditionToConditionCmp(FlagsCondition condition) { 275 switch (condition) { 276 case kEqual: 277 return eq; 278 case kNotEqual: 279 return ne; 280 case kSignedLessThan: 281 return lt; 282 case kSignedGreaterThanOrEqual: 283 return ge; 284 case kSignedLessThanOrEqual: 285 return le; 286 case kSignedGreaterThan: 287 return gt; 288 case kUnsignedLessThan: 289 return lo; 290 case kUnsignedGreaterThanOrEqual: 291 return hs; 292 case kUnsignedLessThanOrEqual: 293 return ls; 294 case kUnsignedGreaterThan: 295 return hi; 296 case kUnorderedEqual: 297 case kUnorderedNotEqual: 298 break; 299 default: 300 break; 301 } 302 UNREACHABLE(); 303 return kNoCondition; 304 } 305 306 307 Condition FlagsConditionToConditionTst(FlagsCondition condition) { 308 switch (condition) { 309 case kNotEqual: 310 return ne; 311 case kEqual: 312 return eq; 313 default: 314 break; 315 } 316 UNREACHABLE(); 317 return kNoCondition; 318 } 319 320 321 Condition FlagsConditionToConditionOvf(FlagsCondition condition) { 322 switch (condition) { 323 case kOverflow: 324 return ne; 325 case kNotOverflow: 326 return eq; 327 default: 328 break; 329 } 330 UNREACHABLE(); 331 return kNoCondition; 332 } 333 334 335 FPUCondition FlagsConditionToConditionCmpFPU(bool& predicate, 336 FlagsCondition condition) { 337 switch (condition) { 338 case kEqual: 339 predicate = true; 340 return EQ; 341 case kNotEqual: 342 predicate = false; 343 return EQ; 344 case kUnsignedLessThan: 345 predicate = true; 346 return OLT; 347 case kUnsignedGreaterThanOrEqual: 348 predicate = false; 349 return ULT; 350 case kUnsignedLessThanOrEqual: 351 predicate = true; 352 return OLE; 353 case kUnsignedGreaterThan: 354 predicate = false; 355 return ULE; 356 case kUnorderedEqual: 357 case kUnorderedNotEqual: 358 predicate = true; 359 break; 360 default: 361 predicate = true; 362 break; 363 } 364 UNREACHABLE(); 365 return kNoFPUCondition; 366 } 367 368 } // namespace 369 370 #define ASSEMBLE_CHECKED_LOAD_FLOAT(width, asm_instr) \ 371 do { \ 372 auto result = i.Output##width##Register(); \ 373 auto ool = new (zone()) OutOfLineLoad##width(this, result); \ 374 if (instr->InputAt(0)->IsRegister()) { \ 375 auto offset = i.InputRegister(0); \ 376 __ Branch(USE_DELAY_SLOT, ool->entry(), hs, offset, i.InputOperand(1)); \ 377 __ And(kScratchReg, offset, Operand(0xffffffff)); \ 378 __ Daddu(kScratchReg, i.InputRegister(2), kScratchReg); \ 379 __ asm_instr(result, MemOperand(kScratchReg, 0)); \ 380 } else { \ 381 int offset = static_cast<int>(i.InputOperand(0).immediate()); \ 382 __ Branch(ool->entry(), ls, i.InputRegister(1), Operand(offset)); \ 383 __ asm_instr(result, MemOperand(i.InputRegister(2), offset)); \ 384 } \ 385 __ bind(ool->exit()); \ 386 } while (0) 387 388 #define ASSEMBLE_CHECKED_LOAD_INTEGER(asm_instr) \ 389 do { \ 390 auto result = i.OutputRegister(); \ 391 auto ool = new (zone()) OutOfLineLoadInteger(this, result); \ 392 if (instr->InputAt(0)->IsRegister()) { \ 393 auto offset = i.InputRegister(0); \ 394 __ Branch(USE_DELAY_SLOT, ool->entry(), hs, offset, i.InputOperand(1)); \ 395 __ And(kScratchReg, offset, Operand(0xffffffff)); \ 396 __ Daddu(kScratchReg, i.InputRegister(2), kScratchReg); \ 397 __ asm_instr(result, MemOperand(kScratchReg, 0)); \ 398 } else { \ 399 int offset = static_cast<int>(i.InputOperand(0).immediate()); \ 400 __ Branch(ool->entry(), ls, i.InputRegister(1), Operand(offset)); \ 401 __ asm_instr(result, MemOperand(i.InputRegister(2), offset)); \ 402 } \ 403 __ bind(ool->exit()); \ 404 } while (0) 405 406 #define ASSEMBLE_CHECKED_STORE_FLOAT(width, asm_instr) \ 407 do { \ 408 Label done; \ 409 if (instr->InputAt(0)->IsRegister()) { \ 410 auto offset = i.InputRegister(0); \ 411 auto value = i.InputOrZero##width##Register(2); \ 412 if (value.is(kDoubleRegZero) && !__ IsDoubleZeroRegSet()) { \ 413 __ Move(kDoubleRegZero, 0.0); \ 414 } \ 415 __ Branch(USE_DELAY_SLOT, &done, hs, offset, i.InputOperand(1)); \ 416 __ And(kScratchReg, offset, Operand(0xffffffff)); \ 417 __ Daddu(kScratchReg, i.InputRegister(3), kScratchReg); \ 418 __ asm_instr(value, MemOperand(kScratchReg, 0)); \ 419 } else { \ 420 int offset = static_cast<int>(i.InputOperand(0).immediate()); \ 421 auto value = i.InputOrZero##width##Register(2); \ 422 if (value.is(kDoubleRegZero) && !__ IsDoubleZeroRegSet()) { \ 423 __ Move(kDoubleRegZero, 0.0); \ 424 } \ 425 __ Branch(&done, ls, i.InputRegister(1), Operand(offset)); \ 426 __ asm_instr(value, MemOperand(i.InputRegister(3), offset)); \ 427 } \ 428 __ bind(&done); \ 429 } while (0) 430 431 #define ASSEMBLE_CHECKED_STORE_INTEGER(asm_instr) \ 432 do { \ 433 Label done; \ 434 if (instr->InputAt(0)->IsRegister()) { \ 435 auto offset = i.InputRegister(0); \ 436 auto value = i.InputOrZeroRegister(2); \ 437 __ Branch(USE_DELAY_SLOT, &done, hs, offset, i.InputOperand(1)); \ 438 __ And(kScratchReg, offset, Operand(0xffffffff)); \ 439 __ Daddu(kScratchReg, i.InputRegister(3), kScratchReg); \ 440 __ asm_instr(value, MemOperand(kScratchReg, 0)); \ 441 } else { \ 442 int offset = static_cast<int>(i.InputOperand(0).immediate()); \ 443 auto value = i.InputOrZeroRegister(2); \ 444 __ Branch(&done, ls, i.InputRegister(1), Operand(offset)); \ 445 __ asm_instr(value, MemOperand(i.InputRegister(3), offset)); \ 446 } \ 447 __ bind(&done); \ 448 } while (0) 449 450 #define ASSEMBLE_ROUND_DOUBLE_TO_DOUBLE(mode) \ 451 if (kArchVariant == kMips64r6) { \ 452 __ cfc1(kScratchReg, FCSR); \ 453 __ li(at, Operand(mode_##mode)); \ 454 __ ctc1(at, FCSR); \ 455 __ rint_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0)); \ 456 __ ctc1(kScratchReg, FCSR); \ 457 } else { \ 458 auto ool = new (zone()) OutOfLineRound(this, i.OutputDoubleRegister()); \ 459 Label done; \ 460 __ mfhc1(kScratchReg, i.InputDoubleRegister(0)); \ 461 __ Ext(at, kScratchReg, HeapNumber::kExponentShift, \ 462 HeapNumber::kExponentBits); \ 463 __ Branch(USE_DELAY_SLOT, &done, hs, at, \ 464 Operand(HeapNumber::kExponentBias + HeapNumber::kMantissaBits)); \ 465 __ mov_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0)); \ 466 __ mode##_l_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0)); \ 467 __ dmfc1(at, i.OutputDoubleRegister()); \ 468 __ Branch(USE_DELAY_SLOT, ool->entry(), eq, at, Operand(zero_reg)); \ 469 __ cvt_d_l(i.OutputDoubleRegister(), i.OutputDoubleRegister()); \ 470 __ bind(ool->exit()); \ 471 __ bind(&done); \ 472 } 473 474 #define ASSEMBLE_ROUND_FLOAT_TO_FLOAT(mode) \ 475 if (kArchVariant == kMips64r6) { \ 476 __ cfc1(kScratchReg, FCSR); \ 477 __ li(at, Operand(mode_##mode)); \ 478 __ ctc1(at, FCSR); \ 479 __ rint_s(i.OutputDoubleRegister(), i.InputDoubleRegister(0)); \ 480 __ ctc1(kScratchReg, FCSR); \ 481 } else { \ 482 int32_t kFloat32ExponentBias = 127; \ 483 int32_t kFloat32MantissaBits = 23; \ 484 int32_t kFloat32ExponentBits = 8; \ 485 auto ool = new (zone()) OutOfLineRound32(this, i.OutputDoubleRegister()); \ 486 Label done; \ 487 __ mfc1(kScratchReg, i.InputDoubleRegister(0)); \ 488 __ Ext(at, kScratchReg, kFloat32MantissaBits, kFloat32ExponentBits); \ 489 __ Branch(USE_DELAY_SLOT, &done, hs, at, \ 490 Operand(kFloat32ExponentBias + kFloat32MantissaBits)); \ 491 __ mov_s(i.OutputDoubleRegister(), i.InputDoubleRegister(0)); \ 492 __ mode##_w_s(i.OutputDoubleRegister(), i.InputDoubleRegister(0)); \ 493 __ mfc1(at, i.OutputDoubleRegister()); \ 494 __ Branch(USE_DELAY_SLOT, ool->entry(), eq, at, Operand(zero_reg)); \ 495 __ cvt_s_w(i.OutputDoubleRegister(), i.OutputDoubleRegister()); \ 496 __ bind(ool->exit()); \ 497 __ bind(&done); \ 498 } 499 500 #define ASSEMBLE_ATOMIC_LOAD_INTEGER(asm_instr) \ 501 do { \ 502 __ asm_instr(i.OutputRegister(), i.MemoryOperand()); \ 503 __ sync(); \ 504 } while (0) 505 506 #define ASSEMBLE_ATOMIC_STORE_INTEGER(asm_instr) \ 507 do { \ 508 __ sync(); \ 509 __ asm_instr(i.InputOrZeroRegister(2), i.MemoryOperand()); \ 510 __ sync(); \ 511 } while (0) 512 513 #define ASSEMBLE_IEEE754_BINOP(name) \ 514 do { \ 515 FrameScope scope(masm(), StackFrame::MANUAL); \ 516 __ PrepareCallCFunction(0, 2, kScratchReg); \ 517 __ MovToFloatParameters(i.InputDoubleRegister(0), \ 518 i.InputDoubleRegister(1)); \ 519 __ CallCFunction(ExternalReference::ieee754_##name##_function(isolate()), \ 520 0, 2); \ 521 /* Move the result in the double result register. */ \ 522 __ MovFromFloatResult(i.OutputDoubleRegister()); \ 523 } while (0) 524 525 #define ASSEMBLE_IEEE754_UNOP(name) \ 526 do { \ 527 FrameScope scope(masm(), StackFrame::MANUAL); \ 528 __ PrepareCallCFunction(0, 1, kScratchReg); \ 529 __ MovToFloatParameter(i.InputDoubleRegister(0)); \ 530 __ CallCFunction(ExternalReference::ieee754_##name##_function(isolate()), \ 531 0, 1); \ 532 /* Move the result in the double result register. */ \ 533 __ MovFromFloatResult(i.OutputDoubleRegister()); \ 534 } while (0) 535 536 void CodeGenerator::AssembleDeconstructFrame() { 537 __ mov(sp, fp); 538 __ Pop(ra, fp); 539 } 540 541 void CodeGenerator::AssemblePrepareTailCall() { 542 if (frame_access_state()->has_frame()) { 543 __ ld(ra, MemOperand(fp, StandardFrameConstants::kCallerPCOffset)); 544 __ ld(fp, MemOperand(fp, StandardFrameConstants::kCallerFPOffset)); 545 } 546 frame_access_state()->SetFrameAccessToSP(); 547 } 548 549 void CodeGenerator::AssemblePopArgumentsAdaptorFrame(Register args_reg, 550 Register scratch1, 551 Register scratch2, 552 Register scratch3) { 553 DCHECK(!AreAliased(args_reg, scratch1, scratch2, scratch3)); 554 Label done; 555 556 // Check if current frame is an arguments adaptor frame. 557 __ ld(scratch3, MemOperand(fp, StandardFrameConstants::kContextOffset)); 558 __ Branch(&done, ne, scratch3, 559 Operand(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR))); 560 561 // Load arguments count from current arguments adaptor frame (note, it 562 // does not include receiver). 563 Register caller_args_count_reg = scratch1; 564 __ ld(caller_args_count_reg, 565 MemOperand(fp, ArgumentsAdaptorFrameConstants::kLengthOffset)); 566 __ SmiUntag(caller_args_count_reg); 567 568 ParameterCount callee_args_count(args_reg); 569 __ PrepareForTailCall(callee_args_count, caller_args_count_reg, scratch2, 570 scratch3); 571 __ bind(&done); 572 } 573 574 namespace { 575 576 void AdjustStackPointerForTailCall(MacroAssembler* masm, 577 FrameAccessState* state, 578 int new_slot_above_sp, 579 bool allow_shrinkage = true) { 580 int current_sp_offset = state->GetSPToFPSlotCount() + 581 StandardFrameConstants::kFixedSlotCountAboveFp; 582 int stack_slot_delta = new_slot_above_sp - current_sp_offset; 583 if (stack_slot_delta > 0) { 584 masm->Dsubu(sp, sp, stack_slot_delta * kPointerSize); 585 state->IncreaseSPDelta(stack_slot_delta); 586 } else if (allow_shrinkage && stack_slot_delta < 0) { 587 masm->Daddu(sp, sp, -stack_slot_delta * kPointerSize); 588 state->IncreaseSPDelta(stack_slot_delta); 589 } 590 } 591 592 } // namespace 593 594 void CodeGenerator::AssembleTailCallBeforeGap(Instruction* instr, 595 int first_unused_stack_slot) { 596 AdjustStackPointerForTailCall(masm(), frame_access_state(), 597 first_unused_stack_slot, false); 598 } 599 600 void CodeGenerator::AssembleTailCallAfterGap(Instruction* instr, 601 int first_unused_stack_slot) { 602 AdjustStackPointerForTailCall(masm(), frame_access_state(), 603 first_unused_stack_slot); 604 } 605 606 // Assembles an instruction after register allocation, producing machine code. 607 CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction( 608 Instruction* instr) { 609 MipsOperandConverter i(this, instr); 610 InstructionCode opcode = instr->opcode(); 611 ArchOpcode arch_opcode = ArchOpcodeField::decode(opcode); 612 switch (arch_opcode) { 613 case kArchCallCodeObject: { 614 EnsureSpaceForLazyDeopt(); 615 if (instr->InputAt(0)->IsImmediate()) { 616 __ Call(Handle<Code>::cast(i.InputHeapObject(0)), 617 RelocInfo::CODE_TARGET); 618 } else { 619 __ daddiu(at, i.InputRegister(0), Code::kHeaderSize - kHeapObjectTag); 620 __ Call(at); 621 } 622 RecordCallPosition(instr); 623 frame_access_state()->ClearSPDelta(); 624 break; 625 } 626 case kArchTailCallCodeObjectFromJSFunction: 627 case kArchTailCallCodeObject: { 628 if (arch_opcode == kArchTailCallCodeObjectFromJSFunction) { 629 AssemblePopArgumentsAdaptorFrame(kJavaScriptCallArgCountRegister, 630 i.TempRegister(0), i.TempRegister(1), 631 i.TempRegister(2)); 632 } 633 if (instr->InputAt(0)->IsImmediate()) { 634 __ Jump(Handle<Code>::cast(i.InputHeapObject(0)), 635 RelocInfo::CODE_TARGET); 636 } else { 637 __ daddiu(at, i.InputRegister(0), Code::kHeaderSize - kHeapObjectTag); 638 __ Jump(at); 639 } 640 frame_access_state()->ClearSPDelta(); 641 frame_access_state()->SetFrameAccessToDefault(); 642 break; 643 } 644 case kArchTailCallAddress: { 645 CHECK(!instr->InputAt(0)->IsImmediate()); 646 __ Jump(i.InputRegister(0)); 647 frame_access_state()->ClearSPDelta(); 648 frame_access_state()->SetFrameAccessToDefault(); 649 break; 650 } 651 case kArchCallJSFunction: { 652 EnsureSpaceForLazyDeopt(); 653 Register func = i.InputRegister(0); 654 if (FLAG_debug_code) { 655 // Check the function's context matches the context argument. 656 __ ld(kScratchReg, FieldMemOperand(func, JSFunction::kContextOffset)); 657 __ Assert(eq, kWrongFunctionContext, cp, Operand(kScratchReg)); 658 } 659 __ ld(at, FieldMemOperand(func, JSFunction::kCodeEntryOffset)); 660 __ Call(at); 661 RecordCallPosition(instr); 662 frame_access_state()->ClearSPDelta(); 663 break; 664 } 665 case kArchTailCallJSFunctionFromJSFunction: { 666 Register func = i.InputRegister(0); 667 if (FLAG_debug_code) { 668 // Check the function's context matches the context argument. 669 __ ld(kScratchReg, FieldMemOperand(func, JSFunction::kContextOffset)); 670 __ Assert(eq, kWrongFunctionContext, cp, Operand(kScratchReg)); 671 } 672 AssemblePopArgumentsAdaptorFrame(kJavaScriptCallArgCountRegister, 673 i.TempRegister(0), i.TempRegister(1), 674 i.TempRegister(2)); 675 __ ld(at, FieldMemOperand(func, JSFunction::kCodeEntryOffset)); 676 __ Jump(at); 677 frame_access_state()->ClearSPDelta(); 678 frame_access_state()->SetFrameAccessToDefault(); 679 break; 680 } 681 case kArchPrepareCallCFunction: { 682 int const num_parameters = MiscField::decode(instr->opcode()); 683 __ PrepareCallCFunction(num_parameters, kScratchReg); 684 // Frame alignment requires using FP-relative frame addressing. 685 frame_access_state()->SetFrameAccessToFP(); 686 break; 687 } 688 case kArchPrepareTailCall: 689 AssemblePrepareTailCall(); 690 break; 691 case kArchCallCFunction: { 692 int const num_parameters = MiscField::decode(instr->opcode()); 693 if (instr->InputAt(0)->IsImmediate()) { 694 ExternalReference ref = i.InputExternalReference(0); 695 __ CallCFunction(ref, num_parameters); 696 } else { 697 Register func = i.InputRegister(0); 698 __ CallCFunction(func, num_parameters); 699 } 700 frame_access_state()->SetFrameAccessToDefault(); 701 frame_access_state()->ClearSPDelta(); 702 break; 703 } 704 case kArchJmp: 705 AssembleArchJump(i.InputRpo(0)); 706 break; 707 case kArchLookupSwitch: 708 AssembleArchLookupSwitch(instr); 709 break; 710 case kArchTableSwitch: 711 AssembleArchTableSwitch(instr); 712 break; 713 case kArchDebugBreak: 714 __ stop("kArchDebugBreak"); 715 break; 716 case kArchComment: { 717 Address comment_string = i.InputExternalReference(0).address(); 718 __ RecordComment(reinterpret_cast<const char*>(comment_string)); 719 break; 720 } 721 case kArchNop: 722 case kArchThrowTerminator: 723 // don't emit code for nops. 724 break; 725 case kArchDeoptimize: { 726 int deopt_state_id = 727 BuildTranslation(instr, -1, 0, OutputFrameStateCombine::Ignore()); 728 Deoptimizer::BailoutType bailout_type = 729 Deoptimizer::BailoutType(MiscField::decode(instr->opcode())); 730 CodeGenResult result = AssembleDeoptimizerCall( 731 deopt_state_id, bailout_type, current_source_position_); 732 if (result != kSuccess) return result; 733 break; 734 } 735 case kArchRet: 736 AssembleReturn(instr->InputAt(0)); 737 break; 738 case kArchStackPointer: 739 __ mov(i.OutputRegister(), sp); 740 break; 741 case kArchFramePointer: 742 __ mov(i.OutputRegister(), fp); 743 break; 744 case kArchParentFramePointer: 745 if (frame_access_state()->has_frame()) { 746 __ ld(i.OutputRegister(), MemOperand(fp, 0)); 747 } else { 748 __ mov(i.OutputRegister(), fp); 749 } 750 break; 751 case kArchTruncateDoubleToI: 752 __ TruncateDoubleToI(i.OutputRegister(), i.InputDoubleRegister(0)); 753 break; 754 case kArchStoreWithWriteBarrier: { 755 RecordWriteMode mode = 756 static_cast<RecordWriteMode>(MiscField::decode(instr->opcode())); 757 Register object = i.InputRegister(0); 758 Register index = i.InputRegister(1); 759 Register value = i.InputRegister(2); 760 Register scratch0 = i.TempRegister(0); 761 Register scratch1 = i.TempRegister(1); 762 auto ool = new (zone()) OutOfLineRecordWrite(this, object, index, value, 763 scratch0, scratch1, mode); 764 __ Daddu(at, object, index); 765 __ sd(value, MemOperand(at)); 766 __ CheckPageFlag(object, scratch0, 767 MemoryChunk::kPointersFromHereAreInterestingMask, ne, 768 ool->entry()); 769 __ bind(ool->exit()); 770 break; 771 } 772 case kArchStackSlot: { 773 FrameOffset offset = 774 frame_access_state()->GetFrameOffset(i.InputInt32(0)); 775 __ Daddu(i.OutputRegister(), offset.from_stack_pointer() ? sp : fp, 776 Operand(offset.offset())); 777 break; 778 } 779 case kIeee754Float64Acos: 780 ASSEMBLE_IEEE754_UNOP(acos); 781 break; 782 case kIeee754Float64Acosh: 783 ASSEMBLE_IEEE754_UNOP(acosh); 784 break; 785 case kIeee754Float64Asin: 786 ASSEMBLE_IEEE754_UNOP(asin); 787 break; 788 case kIeee754Float64Asinh: 789 ASSEMBLE_IEEE754_UNOP(asinh); 790 break; 791 case kIeee754Float64Atan: 792 ASSEMBLE_IEEE754_UNOP(atan); 793 break; 794 case kIeee754Float64Atanh: 795 ASSEMBLE_IEEE754_UNOP(atanh); 796 break; 797 case kIeee754Float64Atan2: 798 ASSEMBLE_IEEE754_BINOP(atan2); 799 break; 800 case kIeee754Float64Cos: 801 ASSEMBLE_IEEE754_UNOP(cos); 802 break; 803 case kIeee754Float64Cosh: 804 ASSEMBLE_IEEE754_UNOP(cosh); 805 break; 806 case kIeee754Float64Cbrt: 807 ASSEMBLE_IEEE754_UNOP(cbrt); 808 break; 809 case kIeee754Float64Exp: 810 ASSEMBLE_IEEE754_UNOP(exp); 811 break; 812 case kIeee754Float64Expm1: 813 ASSEMBLE_IEEE754_UNOP(expm1); 814 break; 815 case kIeee754Float64Log: 816 ASSEMBLE_IEEE754_UNOP(log); 817 break; 818 case kIeee754Float64Log1p: 819 ASSEMBLE_IEEE754_UNOP(log1p); 820 break; 821 case kIeee754Float64Log2: 822 ASSEMBLE_IEEE754_UNOP(log2); 823 break; 824 case kIeee754Float64Log10: 825 ASSEMBLE_IEEE754_UNOP(log10); 826 break; 827 case kIeee754Float64Pow: { 828 MathPowStub stub(isolate(), MathPowStub::DOUBLE); 829 __ CallStub(&stub); 830 break; 831 } 832 case kIeee754Float64Sin: 833 ASSEMBLE_IEEE754_UNOP(sin); 834 break; 835 case kIeee754Float64Sinh: 836 ASSEMBLE_IEEE754_UNOP(sinh); 837 break; 838 case kIeee754Float64Tan: 839 ASSEMBLE_IEEE754_UNOP(tan); 840 break; 841 case kIeee754Float64Tanh: 842 ASSEMBLE_IEEE754_UNOP(tanh); 843 break; 844 case kMips64Add: 845 __ Addu(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1)); 846 break; 847 case kMips64Dadd: 848 __ Daddu(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1)); 849 break; 850 case kMips64DaddOvf: 851 // Pseudo-instruction used for overflow/branch. No opcode emitted here. 852 break; 853 case kMips64Sub: 854 __ Subu(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1)); 855 break; 856 case kMips64Dsub: 857 __ Dsubu(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1)); 858 break; 859 case kMips64DsubOvf: 860 // Pseudo-instruction used for overflow/branch. No opcode emitted here. 861 break; 862 case kMips64Mul: 863 __ Mul(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1)); 864 break; 865 case kMips64MulOvf: 866 // Pseudo-instruction used for overflow/branch. No opcode emitted here. 867 break; 868 case kMips64MulHigh: 869 __ Mulh(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1)); 870 break; 871 case kMips64MulHighU: 872 __ Mulhu(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1)); 873 break; 874 case kMips64DMulHigh: 875 __ Dmulh(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1)); 876 break; 877 case kMips64Div: 878 __ Div(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1)); 879 if (kArchVariant == kMips64r6) { 880 __ selnez(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1)); 881 } else { 882 __ Movz(i.OutputRegister(), i.InputRegister(1), i.InputRegister(1)); 883 } 884 break; 885 case kMips64DivU: 886 __ Divu(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1)); 887 if (kArchVariant == kMips64r6) { 888 __ selnez(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1)); 889 } else { 890 __ Movz(i.OutputRegister(), i.InputRegister(1), i.InputRegister(1)); 891 } 892 break; 893 case kMips64Mod: 894 __ Mod(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1)); 895 break; 896 case kMips64ModU: 897 __ Modu(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1)); 898 break; 899 case kMips64Dmul: 900 __ Dmul(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1)); 901 break; 902 case kMips64Ddiv: 903 __ Ddiv(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1)); 904 if (kArchVariant == kMips64r6) { 905 __ selnez(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1)); 906 } else { 907 __ Movz(i.OutputRegister(), i.InputRegister(1), i.InputRegister(1)); 908 } 909 break; 910 case kMips64DdivU: 911 __ Ddivu(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1)); 912 if (kArchVariant == kMips64r6) { 913 __ selnez(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1)); 914 } else { 915 __ Movz(i.OutputRegister(), i.InputRegister(1), i.InputRegister(1)); 916 } 917 break; 918 case kMips64Dmod: 919 __ Dmod(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1)); 920 break; 921 case kMips64DmodU: 922 __ Dmodu(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1)); 923 break; 924 case kMips64Dlsa: 925 DCHECK(instr->InputAt(2)->IsImmediate()); 926 __ Dlsa(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1), 927 i.InputInt8(2)); 928 break; 929 case kMips64Lsa: 930 DCHECK(instr->InputAt(2)->IsImmediate()); 931 __ Lsa(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1), 932 i.InputInt8(2)); 933 break; 934 case kMips64And: 935 __ And(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1)); 936 break; 937 case kMips64And32: 938 if (instr->InputAt(1)->IsRegister()) { 939 __ sll(i.InputRegister(0), i.InputRegister(0), 0x0); 940 __ sll(i.InputRegister(1), i.InputRegister(1), 0x0); 941 __ And(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1)); 942 } else { 943 __ sll(i.InputRegister(0), i.InputRegister(0), 0x0); 944 __ And(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1)); 945 } 946 break; 947 case kMips64Or: 948 __ Or(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1)); 949 break; 950 case kMips64Or32: 951 if (instr->InputAt(1)->IsRegister()) { 952 __ sll(i.InputRegister(0), i.InputRegister(0), 0x0); 953 __ sll(i.InputRegister(1), i.InputRegister(1), 0x0); 954 __ Or(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1)); 955 } else { 956 __ sll(i.InputRegister(0), i.InputRegister(0), 0x0); 957 __ Or(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1)); 958 } 959 break; 960 case kMips64Nor: 961 if (instr->InputAt(1)->IsRegister()) { 962 __ Nor(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1)); 963 } else { 964 DCHECK(i.InputOperand(1).immediate() == 0); 965 __ Nor(i.OutputRegister(), i.InputRegister(0), zero_reg); 966 } 967 break; 968 case kMips64Nor32: 969 if (instr->InputAt(1)->IsRegister()) { 970 __ sll(i.InputRegister(0), i.InputRegister(0), 0x0); 971 __ sll(i.InputRegister(1), i.InputRegister(1), 0x0); 972 __ Nor(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1)); 973 } else { 974 DCHECK(i.InputOperand(1).immediate() == 0); 975 __ sll(i.InputRegister(0), i.InputRegister(0), 0x0); 976 __ Nor(i.OutputRegister(), i.InputRegister(0), zero_reg); 977 } 978 break; 979 case kMips64Xor: 980 __ Xor(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1)); 981 break; 982 case kMips64Xor32: 983 if (instr->InputAt(1)->IsRegister()) { 984 __ sll(i.InputRegister(0), i.InputRegister(0), 0x0); 985 __ sll(i.InputRegister(1), i.InputRegister(1), 0x0); 986 __ Xor(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1)); 987 } else { 988 __ sll(i.InputRegister(0), i.InputRegister(0), 0x0); 989 __ Xor(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1)); 990 } 991 break; 992 case kMips64Clz: 993 __ Clz(i.OutputRegister(), i.InputRegister(0)); 994 break; 995 case kMips64Dclz: 996 __ dclz(i.OutputRegister(), i.InputRegister(0)); 997 break; 998 case kMips64Ctz: { 999 Register reg1 = kScratchReg; 1000 Register reg2 = kScratchReg2; 1001 Label skip_for_zero; 1002 Label end; 1003 // Branch if the operand is zero 1004 __ Branch(&skip_for_zero, eq, i.InputRegister(0), Operand(zero_reg)); 1005 // Find the number of bits before the last bit set to 1. 1006 __ Subu(reg2, zero_reg, i.InputRegister(0)); 1007 __ And(reg2, reg2, i.InputRegister(0)); 1008 __ clz(reg2, reg2); 1009 // Get the number of bits after the last bit set to 1. 1010 __ li(reg1, 0x1F); 1011 __ Subu(i.OutputRegister(), reg1, reg2); 1012 __ Branch(&end); 1013 __ bind(&skip_for_zero); 1014 // If the operand is zero, return word length as the result. 1015 __ li(i.OutputRegister(), 0x20); 1016 __ bind(&end); 1017 } break; 1018 case kMips64Dctz: { 1019 Register reg1 = kScratchReg; 1020 Register reg2 = kScratchReg2; 1021 Label skip_for_zero; 1022 Label end; 1023 // Branch if the operand is zero 1024 __ Branch(&skip_for_zero, eq, i.InputRegister(0), Operand(zero_reg)); 1025 // Find the number of bits before the last bit set to 1. 1026 __ Dsubu(reg2, zero_reg, i.InputRegister(0)); 1027 __ And(reg2, reg2, i.InputRegister(0)); 1028 __ dclz(reg2, reg2); 1029 // Get the number of bits after the last bit set to 1. 1030 __ li(reg1, 0x3F); 1031 __ Subu(i.OutputRegister(), reg1, reg2); 1032 __ Branch(&end); 1033 __ bind(&skip_for_zero); 1034 // If the operand is zero, return word length as the result. 1035 __ li(i.OutputRegister(), 0x40); 1036 __ bind(&end); 1037 } break; 1038 case kMips64Popcnt: { 1039 Register reg1 = kScratchReg; 1040 Register reg2 = kScratchReg2; 1041 uint32_t m1 = 0x55555555; 1042 uint32_t m2 = 0x33333333; 1043 uint32_t m4 = 0x0f0f0f0f; 1044 uint32_t m8 = 0x00ff00ff; 1045 uint32_t m16 = 0x0000ffff; 1046 1047 // Put count of ones in every 2 bits into those 2 bits. 1048 __ li(at, m1); 1049 __ dsrl(reg1, i.InputRegister(0), 1); 1050 __ And(reg2, i.InputRegister(0), at); 1051 __ And(reg1, reg1, at); 1052 __ Daddu(reg1, reg1, reg2); 1053 1054 // Put count of ones in every 4 bits into those 4 bits. 1055 __ li(at, m2); 1056 __ dsrl(reg2, reg1, 2); 1057 __ And(reg2, reg2, at); 1058 __ And(reg1, reg1, at); 1059 __ Daddu(reg1, reg1, reg2); 1060 1061 // Put count of ones in every 8 bits into those 8 bits. 1062 __ li(at, m4); 1063 __ dsrl(reg2, reg1, 4); 1064 __ And(reg2, reg2, at); 1065 __ And(reg1, reg1, at); 1066 __ Daddu(reg1, reg1, reg2); 1067 1068 // Put count of ones in every 16 bits into those 16 bits. 1069 __ li(at, m8); 1070 __ dsrl(reg2, reg1, 8); 1071 __ And(reg2, reg2, at); 1072 __ And(reg1, reg1, at); 1073 __ Daddu(reg1, reg1, reg2); 1074 1075 // Calculate total number of ones. 1076 __ li(at, m16); 1077 __ dsrl(reg2, reg1, 16); 1078 __ And(reg2, reg2, at); 1079 __ And(reg1, reg1, at); 1080 __ Daddu(i.OutputRegister(), reg1, reg2); 1081 } break; 1082 case kMips64Dpopcnt: { 1083 Register reg1 = kScratchReg; 1084 Register reg2 = kScratchReg2; 1085 uint64_t m1 = 0x5555555555555555; 1086 uint64_t m2 = 0x3333333333333333; 1087 uint64_t m4 = 0x0f0f0f0f0f0f0f0f; 1088 uint64_t m8 = 0x00ff00ff00ff00ff; 1089 uint64_t m16 = 0x0000ffff0000ffff; 1090 uint64_t m32 = 0x00000000ffffffff; 1091 1092 // Put count of ones in every 2 bits into those 2 bits. 1093 __ li(at, m1); 1094 __ dsrl(reg1, i.InputRegister(0), 1); 1095 __ and_(reg2, i.InputRegister(0), at); 1096 __ and_(reg1, reg1, at); 1097 __ Daddu(reg1, reg1, reg2); 1098 1099 // Put count of ones in every 4 bits into those 4 bits. 1100 __ li(at, m2); 1101 __ dsrl(reg2, reg1, 2); 1102 __ and_(reg2, reg2, at); 1103 __ and_(reg1, reg1, at); 1104 __ Daddu(reg1, reg1, reg2); 1105 1106 // Put count of ones in every 8 bits into those 8 bits. 1107 __ li(at, m4); 1108 __ dsrl(reg2, reg1, 4); 1109 __ and_(reg2, reg2, at); 1110 __ and_(reg1, reg1, at); 1111 __ Daddu(reg1, reg1, reg2); 1112 1113 // Put count of ones in every 16 bits into those 16 bits. 1114 __ li(at, m8); 1115 __ dsrl(reg2, reg1, 8); 1116 __ and_(reg2, reg2, at); 1117 __ and_(reg1, reg1, at); 1118 __ Daddu(reg1, reg1, reg2); 1119 1120 // Put count of ones in every 32 bits into those 32 bits. 1121 __ li(at, m16); 1122 __ dsrl(reg2, reg1, 16); 1123 __ and_(reg2, reg2, at); 1124 __ and_(reg1, reg1, at); 1125 __ Daddu(reg1, reg1, reg2); 1126 1127 // Calculate total number of ones. 1128 __ li(at, m32); 1129 __ dsrl32(reg2, reg1, 0); 1130 __ and_(reg2, reg2, at); 1131 __ and_(reg1, reg1, at); 1132 __ Daddu(i.OutputRegister(), reg1, reg2); 1133 } break; 1134 case kMips64Shl: 1135 if (instr->InputAt(1)->IsRegister()) { 1136 __ sllv(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1)); 1137 } else { 1138 int64_t imm = i.InputOperand(1).immediate(); 1139 __ sll(i.OutputRegister(), i.InputRegister(0), 1140 static_cast<uint16_t>(imm)); 1141 } 1142 break; 1143 case kMips64Shr: 1144 if (instr->InputAt(1)->IsRegister()) { 1145 __ sll(i.InputRegister(0), i.InputRegister(0), 0x0); 1146 __ srlv(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1)); 1147 } else { 1148 int64_t imm = i.InputOperand(1).immediate(); 1149 __ sll(i.InputRegister(0), i.InputRegister(0), 0x0); 1150 __ srl(i.OutputRegister(), i.InputRegister(0), 1151 static_cast<uint16_t>(imm)); 1152 } 1153 break; 1154 case kMips64Sar: 1155 if (instr->InputAt(1)->IsRegister()) { 1156 __ sll(i.InputRegister(0), i.InputRegister(0), 0x0); 1157 __ srav(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1)); 1158 } else { 1159 int64_t imm = i.InputOperand(1).immediate(); 1160 __ sll(i.InputRegister(0), i.InputRegister(0), 0x0); 1161 __ sra(i.OutputRegister(), i.InputRegister(0), 1162 static_cast<uint16_t>(imm)); 1163 } 1164 break; 1165 case kMips64Ext: 1166 __ Ext(i.OutputRegister(), i.InputRegister(0), i.InputInt8(1), 1167 i.InputInt8(2)); 1168 break; 1169 case kMips64Ins: 1170 if (instr->InputAt(1)->IsImmediate() && i.InputInt8(1) == 0) { 1171 __ Ins(i.OutputRegister(), zero_reg, i.InputInt8(1), i.InputInt8(2)); 1172 } else { 1173 __ Ins(i.OutputRegister(), i.InputRegister(0), i.InputInt8(1), 1174 i.InputInt8(2)); 1175 } 1176 break; 1177 case kMips64Dext: { 1178 int16_t pos = i.InputInt8(1); 1179 int16_t size = i.InputInt8(2); 1180 if (size > 0 && size <= 32 && pos >= 0 && pos < 32) { 1181 __ Dext(i.OutputRegister(), i.InputRegister(0), i.InputInt8(1), 1182 i.InputInt8(2)); 1183 } else if (size > 32 && size <= 64 && pos > 0 && pos < 32) { 1184 __ Dextm(i.OutputRegister(), i.InputRegister(0), i.InputInt8(1), 1185 i.InputInt8(2)); 1186 } else { 1187 DCHECK(size > 0 && size <= 32 && pos >= 32 && pos < 64); 1188 __ Dextu(i.OutputRegister(), i.InputRegister(0), i.InputInt8(1), 1189 i.InputInt8(2)); 1190 } 1191 break; 1192 } 1193 case kMips64Dins: 1194 if (instr->InputAt(1)->IsImmediate() && i.InputInt8(1) == 0) { 1195 __ Dins(i.OutputRegister(), zero_reg, i.InputInt8(1), i.InputInt8(2)); 1196 } else { 1197 __ Dins(i.OutputRegister(), i.InputRegister(0), i.InputInt8(1), 1198 i.InputInt8(2)); 1199 } 1200 break; 1201 case kMips64Dshl: 1202 if (instr->InputAt(1)->IsRegister()) { 1203 __ dsllv(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1)); 1204 } else { 1205 int64_t imm = i.InputOperand(1).immediate(); 1206 if (imm < 32) { 1207 __ dsll(i.OutputRegister(), i.InputRegister(0), 1208 static_cast<uint16_t>(imm)); 1209 } else { 1210 __ dsll32(i.OutputRegister(), i.InputRegister(0), 1211 static_cast<uint16_t>(imm - 32)); 1212 } 1213 } 1214 break; 1215 case kMips64Dshr: 1216 if (instr->InputAt(1)->IsRegister()) { 1217 __ dsrlv(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1)); 1218 } else { 1219 int64_t imm = i.InputOperand(1).immediate(); 1220 if (imm < 32) { 1221 __ dsrl(i.OutputRegister(), i.InputRegister(0), 1222 static_cast<uint16_t>(imm)); 1223 } else { 1224 __ dsrl32(i.OutputRegister(), i.InputRegister(0), 1225 static_cast<uint16_t>(imm - 32)); 1226 } 1227 } 1228 break; 1229 case kMips64Dsar: 1230 if (instr->InputAt(1)->IsRegister()) { 1231 __ dsrav(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1)); 1232 } else { 1233 int64_t imm = i.InputOperand(1).immediate(); 1234 if (imm < 32) { 1235 __ dsra(i.OutputRegister(), i.InputRegister(0), imm); 1236 } else { 1237 __ dsra32(i.OutputRegister(), i.InputRegister(0), imm - 32); 1238 } 1239 } 1240 break; 1241 case kMips64Ror: 1242 __ Ror(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1)); 1243 break; 1244 case kMips64Dror: 1245 __ Dror(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1)); 1246 break; 1247 case kMips64Tst: 1248 // Pseudo-instruction used for cmp/branch. No opcode emitted here. 1249 break; 1250 case kMips64Cmp: 1251 // Pseudo-instruction used for cmp/branch. No opcode emitted here. 1252 break; 1253 case kMips64Mov: 1254 // TODO(plind): Should we combine mov/li like this, or use separate instr? 1255 // - Also see x64 ASSEMBLE_BINOP & RegisterOrOperandType 1256 if (HasRegisterInput(instr, 0)) { 1257 __ mov(i.OutputRegister(), i.InputRegister(0)); 1258 } else { 1259 __ li(i.OutputRegister(), i.InputOperand(0)); 1260 } 1261 break; 1262 1263 case kMips64CmpS: 1264 // Psuedo-instruction used for FP cmp/branch. No opcode emitted here. 1265 break; 1266 case kMips64AddS: 1267 // TODO(plind): add special case: combine mult & add. 1268 __ add_s(i.OutputDoubleRegister(), i.InputDoubleRegister(0), 1269 i.InputDoubleRegister(1)); 1270 break; 1271 case kMips64SubS: 1272 __ sub_s(i.OutputDoubleRegister(), i.InputDoubleRegister(0), 1273 i.InputDoubleRegister(1)); 1274 break; 1275 case kMips64MulS: 1276 // TODO(plind): add special case: right op is -1.0, see arm port. 1277 __ mul_s(i.OutputDoubleRegister(), i.InputDoubleRegister(0), 1278 i.InputDoubleRegister(1)); 1279 break; 1280 case kMips64DivS: 1281 __ div_s(i.OutputDoubleRegister(), i.InputDoubleRegister(0), 1282 i.InputDoubleRegister(1)); 1283 break; 1284 case kMips64ModS: { 1285 // TODO(bmeurer): We should really get rid of this special instruction, 1286 // and generate a CallAddress instruction instead. 1287 FrameScope scope(masm(), StackFrame::MANUAL); 1288 __ PrepareCallCFunction(0, 2, kScratchReg); 1289 __ MovToFloatParameters(i.InputDoubleRegister(0), 1290 i.InputDoubleRegister(1)); 1291 // TODO(balazs.kilvady): implement mod_two_floats_operation(isolate()) 1292 __ CallCFunction(ExternalReference::mod_two_doubles_operation(isolate()), 1293 0, 2); 1294 // Move the result in the double result register. 1295 __ MovFromFloatResult(i.OutputSingleRegister()); 1296 break; 1297 } 1298 case kMips64AbsS: 1299 __ abs_s(i.OutputSingleRegister(), i.InputSingleRegister(0)); 1300 break; 1301 case kMips64NegS: 1302 __ Neg_s(i.OutputSingleRegister(), i.InputSingleRegister(0)); 1303 break; 1304 case kMips64SqrtS: { 1305 __ sqrt_s(i.OutputDoubleRegister(), i.InputDoubleRegister(0)); 1306 break; 1307 } 1308 case kMips64MaxS: 1309 __ max_s(i.OutputDoubleRegister(), i.InputDoubleRegister(0), 1310 i.InputDoubleRegister(1)); 1311 break; 1312 case kMips64MinS: 1313 __ min_s(i.OutputDoubleRegister(), i.InputDoubleRegister(0), 1314 i.InputDoubleRegister(1)); 1315 break; 1316 case kMips64CmpD: 1317 // Psuedo-instruction used for FP cmp/branch. No opcode emitted here. 1318 break; 1319 case kMips64AddD: 1320 // TODO(plind): add special case: combine mult & add. 1321 __ add_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0), 1322 i.InputDoubleRegister(1)); 1323 break; 1324 case kMips64SubD: 1325 __ sub_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0), 1326 i.InputDoubleRegister(1)); 1327 break; 1328 case kMips64MaddS: 1329 __ madd_s(i.OutputFloatRegister(), i.InputFloatRegister(0), 1330 i.InputFloatRegister(1), i.InputFloatRegister(2)); 1331 break; 1332 case kMips64MaddD: 1333 __ madd_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0), 1334 i.InputDoubleRegister(1), i.InputDoubleRegister(2)); 1335 break; 1336 case kMips64MaddfS: 1337 __ maddf_s(i.OutputFloatRegister(), i.InputFloatRegister(1), 1338 i.InputFloatRegister(2)); 1339 break; 1340 case kMips64MaddfD: 1341 __ maddf_d(i.OutputDoubleRegister(), i.InputDoubleRegister(1), 1342 i.InputDoubleRegister(2)); 1343 break; 1344 case kMips64MsubS: 1345 __ msub_s(i.OutputFloatRegister(), i.InputFloatRegister(0), 1346 i.InputFloatRegister(1), i.InputFloatRegister(2)); 1347 break; 1348 case kMips64MsubD: 1349 __ msub_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0), 1350 i.InputDoubleRegister(1), i.InputDoubleRegister(2)); 1351 break; 1352 case kMips64MsubfS: 1353 __ msubf_s(i.OutputFloatRegister(), i.InputFloatRegister(1), 1354 i.InputFloatRegister(2)); 1355 break; 1356 case kMips64MsubfD: 1357 __ msubf_d(i.OutputDoubleRegister(), i.InputDoubleRegister(1), 1358 i.InputDoubleRegister(2)); 1359 break; 1360 case kMips64MulD: 1361 // TODO(plind): add special case: right op is -1.0, see arm port. 1362 __ mul_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0), 1363 i.InputDoubleRegister(1)); 1364 break; 1365 case kMips64DivD: 1366 __ div_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0), 1367 i.InputDoubleRegister(1)); 1368 break; 1369 case kMips64ModD: { 1370 // TODO(bmeurer): We should really get rid of this special instruction, 1371 // and generate a CallAddress instruction instead. 1372 FrameScope scope(masm(), StackFrame::MANUAL); 1373 __ PrepareCallCFunction(0, 2, kScratchReg); 1374 __ MovToFloatParameters(i.InputDoubleRegister(0), 1375 i.InputDoubleRegister(1)); 1376 __ CallCFunction(ExternalReference::mod_two_doubles_operation(isolate()), 1377 0, 2); 1378 // Move the result in the double result register. 1379 __ MovFromFloatResult(i.OutputDoubleRegister()); 1380 break; 1381 } 1382 case kMips64AbsD: 1383 __ abs_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0)); 1384 break; 1385 case kMips64NegD: 1386 __ Neg_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0)); 1387 break; 1388 case kMips64SqrtD: { 1389 __ sqrt_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0)); 1390 break; 1391 } 1392 case kMips64MaxD: 1393 __ max_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0), 1394 i.InputDoubleRegister(1)); 1395 break; 1396 case kMips64MinD: 1397 __ min_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0), 1398 i.InputDoubleRegister(1)); 1399 break; 1400 case kMips64Float64RoundDown: { 1401 ASSEMBLE_ROUND_DOUBLE_TO_DOUBLE(floor); 1402 break; 1403 } 1404 case kMips64Float32RoundDown: { 1405 ASSEMBLE_ROUND_FLOAT_TO_FLOAT(floor); 1406 break; 1407 } 1408 case kMips64Float64RoundTruncate: { 1409 ASSEMBLE_ROUND_DOUBLE_TO_DOUBLE(trunc); 1410 break; 1411 } 1412 case kMips64Float32RoundTruncate: { 1413 ASSEMBLE_ROUND_FLOAT_TO_FLOAT(trunc); 1414 break; 1415 } 1416 case kMips64Float64RoundUp: { 1417 ASSEMBLE_ROUND_DOUBLE_TO_DOUBLE(ceil); 1418 break; 1419 } 1420 case kMips64Float32RoundUp: { 1421 ASSEMBLE_ROUND_FLOAT_TO_FLOAT(ceil); 1422 break; 1423 } 1424 case kMips64Float64RoundTiesEven: { 1425 ASSEMBLE_ROUND_DOUBLE_TO_DOUBLE(round); 1426 break; 1427 } 1428 case kMips64Float32RoundTiesEven: { 1429 ASSEMBLE_ROUND_FLOAT_TO_FLOAT(round); 1430 break; 1431 } 1432 case kMips64Float32Max: { 1433 Label compare_nan, done_compare; 1434 __ MaxNaNCheck_s(i.OutputSingleRegister(), i.InputSingleRegister(0), 1435 i.InputSingleRegister(1), &compare_nan); 1436 __ Branch(&done_compare); 1437 __ bind(&compare_nan); 1438 __ Move(i.OutputSingleRegister(), 1439 std::numeric_limits<float>::quiet_NaN()); 1440 __ bind(&done_compare); 1441 break; 1442 } 1443 case kMips64Float64Max: { 1444 Label compare_nan, done_compare; 1445 __ MaxNaNCheck_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0), 1446 i.InputDoubleRegister(1), &compare_nan); 1447 __ Branch(&done_compare); 1448 __ bind(&compare_nan); 1449 __ Move(i.OutputDoubleRegister(), 1450 std::numeric_limits<double>::quiet_NaN()); 1451 __ bind(&done_compare); 1452 break; 1453 } 1454 case kMips64Float32Min: { 1455 Label compare_nan, done_compare; 1456 __ MinNaNCheck_s(i.OutputSingleRegister(), i.InputSingleRegister(0), 1457 i.InputSingleRegister(1), &compare_nan); 1458 __ Branch(&done_compare); 1459 __ bind(&compare_nan); 1460 __ Move(i.OutputSingleRegister(), 1461 std::numeric_limits<float>::quiet_NaN()); 1462 __ bind(&done_compare); 1463 break; 1464 } 1465 case kMips64Float64Min: { 1466 Label compare_nan, done_compare; 1467 __ MinNaNCheck_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0), 1468 i.InputDoubleRegister(1), &compare_nan); 1469 __ Branch(&done_compare); 1470 __ bind(&compare_nan); 1471 __ Move(i.OutputDoubleRegister(), 1472 std::numeric_limits<double>::quiet_NaN()); 1473 __ bind(&done_compare); 1474 break; 1475 } 1476 case kMips64Float64SilenceNaN: 1477 __ FPUCanonicalizeNaN(i.OutputDoubleRegister(), i.InputDoubleRegister(0)); 1478 break; 1479 case kMips64CvtSD: 1480 __ cvt_s_d(i.OutputSingleRegister(), i.InputDoubleRegister(0)); 1481 break; 1482 case kMips64CvtDS: 1483 __ cvt_d_s(i.OutputDoubleRegister(), i.InputSingleRegister(0)); 1484 break; 1485 case kMips64CvtDW: { 1486 FPURegister scratch = kScratchDoubleReg; 1487 __ mtc1(i.InputRegister(0), scratch); 1488 __ cvt_d_w(i.OutputDoubleRegister(), scratch); 1489 break; 1490 } 1491 case kMips64CvtSW: { 1492 FPURegister scratch = kScratchDoubleReg; 1493 __ mtc1(i.InputRegister(0), scratch); 1494 __ cvt_s_w(i.OutputDoubleRegister(), scratch); 1495 break; 1496 } 1497 case kMips64CvtSUw: { 1498 __ Cvt_s_uw(i.OutputDoubleRegister(), i.InputRegister(0)); 1499 break; 1500 } 1501 case kMips64CvtSL: { 1502 FPURegister scratch = kScratchDoubleReg; 1503 __ dmtc1(i.InputRegister(0), scratch); 1504 __ cvt_s_l(i.OutputDoubleRegister(), scratch); 1505 break; 1506 } 1507 case kMips64CvtDL: { 1508 FPURegister scratch = kScratchDoubleReg; 1509 __ dmtc1(i.InputRegister(0), scratch); 1510 __ cvt_d_l(i.OutputDoubleRegister(), scratch); 1511 break; 1512 } 1513 case kMips64CvtDUw: { 1514 __ Cvt_d_uw(i.OutputDoubleRegister(), i.InputRegister(0)); 1515 break; 1516 } 1517 case kMips64CvtDUl: { 1518 __ Cvt_d_ul(i.OutputDoubleRegister(), i.InputRegister(0)); 1519 break; 1520 } 1521 case kMips64CvtSUl: { 1522 __ Cvt_s_ul(i.OutputDoubleRegister(), i.InputRegister(0)); 1523 break; 1524 } 1525 case kMips64FloorWD: { 1526 FPURegister scratch = kScratchDoubleReg; 1527 __ floor_w_d(scratch, i.InputDoubleRegister(0)); 1528 __ mfc1(i.OutputRegister(), scratch); 1529 break; 1530 } 1531 case kMips64CeilWD: { 1532 FPURegister scratch = kScratchDoubleReg; 1533 __ ceil_w_d(scratch, i.InputDoubleRegister(0)); 1534 __ mfc1(i.OutputRegister(), scratch); 1535 break; 1536 } 1537 case kMips64RoundWD: { 1538 FPURegister scratch = kScratchDoubleReg; 1539 __ round_w_d(scratch, i.InputDoubleRegister(0)); 1540 __ mfc1(i.OutputRegister(), scratch); 1541 break; 1542 } 1543 case kMips64TruncWD: { 1544 FPURegister scratch = kScratchDoubleReg; 1545 // Other arches use round to zero here, so we follow. 1546 __ trunc_w_d(scratch, i.InputDoubleRegister(0)); 1547 __ mfc1(i.OutputRegister(), scratch); 1548 break; 1549 } 1550 case kMips64FloorWS: { 1551 FPURegister scratch = kScratchDoubleReg; 1552 __ floor_w_s(scratch, i.InputDoubleRegister(0)); 1553 __ mfc1(i.OutputRegister(), scratch); 1554 break; 1555 } 1556 case kMips64CeilWS: { 1557 FPURegister scratch = kScratchDoubleReg; 1558 __ ceil_w_s(scratch, i.InputDoubleRegister(0)); 1559 __ mfc1(i.OutputRegister(), scratch); 1560 break; 1561 } 1562 case kMips64RoundWS: { 1563 FPURegister scratch = kScratchDoubleReg; 1564 __ round_w_s(scratch, i.InputDoubleRegister(0)); 1565 __ mfc1(i.OutputRegister(), scratch); 1566 break; 1567 } 1568 case kMips64TruncWS: { 1569 FPURegister scratch = kScratchDoubleReg; 1570 __ trunc_w_s(scratch, i.InputDoubleRegister(0)); 1571 __ mfc1(i.OutputRegister(), scratch); 1572 // Avoid INT32_MAX as an overflow indicator and use INT32_MIN instead, 1573 // because INT32_MIN allows easier out-of-bounds detection. 1574 __ addiu(kScratchReg, i.OutputRegister(), 1); 1575 __ slt(kScratchReg2, kScratchReg, i.OutputRegister()); 1576 __ Movn(i.OutputRegister(), kScratchReg, kScratchReg2); 1577 break; 1578 } 1579 case kMips64TruncLS: { 1580 FPURegister scratch = kScratchDoubleReg; 1581 Register tmp_fcsr = kScratchReg; 1582 Register result = kScratchReg2; 1583 1584 bool load_status = instr->OutputCount() > 1; 1585 if (load_status) { 1586 // Save FCSR. 1587 __ cfc1(tmp_fcsr, FCSR); 1588 // Clear FPU flags. 1589 __ ctc1(zero_reg, FCSR); 1590 } 1591 // Other arches use round to zero here, so we follow. 1592 __ trunc_l_s(scratch, i.InputDoubleRegister(0)); 1593 __ dmfc1(i.OutputRegister(), scratch); 1594 if (load_status) { 1595 __ cfc1(result, FCSR); 1596 // Check for overflow and NaNs. 1597 __ andi(result, result, 1598 (kFCSROverflowFlagMask | kFCSRInvalidOpFlagMask)); 1599 __ Slt(result, zero_reg, result); 1600 __ xori(result, result, 1); 1601 __ mov(i.OutputRegister(1), result); 1602 // Restore FCSR 1603 __ ctc1(tmp_fcsr, FCSR); 1604 } 1605 break; 1606 } 1607 case kMips64TruncLD: { 1608 FPURegister scratch = kScratchDoubleReg; 1609 Register tmp_fcsr = kScratchReg; 1610 Register result = kScratchReg2; 1611 1612 bool load_status = instr->OutputCount() > 1; 1613 if (load_status) { 1614 // Save FCSR. 1615 __ cfc1(tmp_fcsr, FCSR); 1616 // Clear FPU flags. 1617 __ ctc1(zero_reg, FCSR); 1618 } 1619 // Other arches use round to zero here, so we follow. 1620 __ trunc_l_d(scratch, i.InputDoubleRegister(0)); 1621 __ dmfc1(i.OutputRegister(0), scratch); 1622 if (load_status) { 1623 __ cfc1(result, FCSR); 1624 // Check for overflow and NaNs. 1625 __ andi(result, result, 1626 (kFCSROverflowFlagMask | kFCSRInvalidOpFlagMask)); 1627 __ Slt(result, zero_reg, result); 1628 __ xori(result, result, 1); 1629 __ mov(i.OutputRegister(1), result); 1630 // Restore FCSR 1631 __ ctc1(tmp_fcsr, FCSR); 1632 } 1633 break; 1634 } 1635 case kMips64TruncUwD: { 1636 FPURegister scratch = kScratchDoubleReg; 1637 // TODO(plind): Fix wrong param order of Trunc_uw_d() macro-asm function. 1638 __ Trunc_uw_d(i.InputDoubleRegister(0), i.OutputRegister(), scratch); 1639 break; 1640 } 1641 case kMips64TruncUwS: { 1642 FPURegister scratch = kScratchDoubleReg; 1643 // TODO(plind): Fix wrong param order of Trunc_uw_d() macro-asm function. 1644 __ Trunc_uw_s(i.InputDoubleRegister(0), i.OutputRegister(), scratch); 1645 // Avoid UINT32_MAX as an overflow indicator and use 0 instead, 1646 // because 0 allows easier out-of-bounds detection. 1647 __ addiu(kScratchReg, i.OutputRegister(), 1); 1648 __ Movz(i.OutputRegister(), zero_reg, kScratchReg); 1649 break; 1650 } 1651 case kMips64TruncUlS: { 1652 FPURegister scratch = kScratchDoubleReg; 1653 Register result = instr->OutputCount() > 1 ? i.OutputRegister(1) : no_reg; 1654 // TODO(plind): Fix wrong param order of Trunc_ul_s() macro-asm function. 1655 __ Trunc_ul_s(i.InputDoubleRegister(0), i.OutputRegister(), scratch, 1656 result); 1657 break; 1658 } 1659 case kMips64TruncUlD: { 1660 FPURegister scratch = kScratchDoubleReg; 1661 Register result = instr->OutputCount() > 1 ? i.OutputRegister(1) : no_reg; 1662 // TODO(plind): Fix wrong param order of Trunc_ul_d() macro-asm function. 1663 __ Trunc_ul_d(i.InputDoubleRegister(0), i.OutputRegister(0), scratch, 1664 result); 1665 break; 1666 } 1667 case kMips64BitcastDL: 1668 __ dmfc1(i.OutputRegister(), i.InputDoubleRegister(0)); 1669 break; 1670 case kMips64BitcastLD: 1671 __ dmtc1(i.InputRegister(0), i.OutputDoubleRegister()); 1672 break; 1673 case kMips64Float64ExtractLowWord32: 1674 __ FmoveLow(i.OutputRegister(), i.InputDoubleRegister(0)); 1675 break; 1676 case kMips64Float64ExtractHighWord32: 1677 __ FmoveHigh(i.OutputRegister(), i.InputDoubleRegister(0)); 1678 break; 1679 case kMips64Float64InsertLowWord32: 1680 __ FmoveLow(i.OutputDoubleRegister(), i.InputRegister(1)); 1681 break; 1682 case kMips64Float64InsertHighWord32: 1683 __ FmoveHigh(i.OutputDoubleRegister(), i.InputRegister(1)); 1684 break; 1685 // ... more basic instructions ... 1686 1687 case kMips64Seb: 1688 __ seb(i.OutputRegister(), i.InputRegister(0)); 1689 break; 1690 case kMips64Seh: 1691 __ seh(i.OutputRegister(), i.InputRegister(0)); 1692 break; 1693 case kMips64Lbu: 1694 __ lbu(i.OutputRegister(), i.MemoryOperand()); 1695 break; 1696 case kMips64Lb: 1697 __ lb(i.OutputRegister(), i.MemoryOperand()); 1698 break; 1699 case kMips64Sb: 1700 __ sb(i.InputOrZeroRegister(2), i.MemoryOperand()); 1701 break; 1702 case kMips64Lhu: 1703 __ lhu(i.OutputRegister(), i.MemoryOperand()); 1704 break; 1705 case kMips64Ulhu: 1706 __ Ulhu(i.OutputRegister(), i.MemoryOperand()); 1707 break; 1708 case kMips64Lh: 1709 __ lh(i.OutputRegister(), i.MemoryOperand()); 1710 break; 1711 case kMips64Ulh: 1712 __ Ulh(i.OutputRegister(), i.MemoryOperand()); 1713 break; 1714 case kMips64Sh: 1715 __ sh(i.InputOrZeroRegister(2), i.MemoryOperand()); 1716 break; 1717 case kMips64Ush: 1718 __ Ush(i.InputOrZeroRegister(2), i.MemoryOperand(), kScratchReg); 1719 break; 1720 case kMips64Lw: 1721 __ lw(i.OutputRegister(), i.MemoryOperand()); 1722 break; 1723 case kMips64Ulw: 1724 __ Ulw(i.OutputRegister(), i.MemoryOperand()); 1725 break; 1726 case kMips64Lwu: 1727 __ lwu(i.OutputRegister(), i.MemoryOperand()); 1728 break; 1729 case kMips64Ulwu: 1730 __ Ulwu(i.OutputRegister(), i.MemoryOperand()); 1731 break; 1732 case kMips64Ld: 1733 __ ld(i.OutputRegister(), i.MemoryOperand()); 1734 break; 1735 case kMips64Uld: 1736 __ Uld(i.OutputRegister(), i.MemoryOperand()); 1737 break; 1738 case kMips64Sw: 1739 __ sw(i.InputOrZeroRegister(2), i.MemoryOperand()); 1740 break; 1741 case kMips64Usw: 1742 __ Usw(i.InputOrZeroRegister(2), i.MemoryOperand()); 1743 break; 1744 case kMips64Sd: 1745 __ sd(i.InputOrZeroRegister(2), i.MemoryOperand()); 1746 break; 1747 case kMips64Usd: 1748 __ Usd(i.InputOrZeroRegister(2), i.MemoryOperand()); 1749 break; 1750 case kMips64Lwc1: { 1751 __ lwc1(i.OutputSingleRegister(), i.MemoryOperand()); 1752 break; 1753 } 1754 case kMips64Ulwc1: { 1755 __ Ulwc1(i.OutputSingleRegister(), i.MemoryOperand(), kScratchReg); 1756 break; 1757 } 1758 case kMips64Swc1: { 1759 size_t index = 0; 1760 MemOperand operand = i.MemoryOperand(&index); 1761 FPURegister ft = i.InputOrZeroSingleRegister(index); 1762 if (ft.is(kDoubleRegZero) && !__ IsDoubleZeroRegSet()) { 1763 __ Move(kDoubleRegZero, 0.0); 1764 } 1765 __ swc1(ft, operand); 1766 break; 1767 } 1768 case kMips64Uswc1: { 1769 size_t index = 0; 1770 MemOperand operand = i.MemoryOperand(&index); 1771 FPURegister ft = i.InputOrZeroSingleRegister(index); 1772 if (ft.is(kDoubleRegZero) && !__ IsDoubleZeroRegSet()) { 1773 __ Move(kDoubleRegZero, 0.0); 1774 } 1775 __ Uswc1(ft, operand, kScratchReg); 1776 break; 1777 } 1778 case kMips64Ldc1: 1779 __ ldc1(i.OutputDoubleRegister(), i.MemoryOperand()); 1780 break; 1781 case kMips64Uldc1: 1782 __ Uldc1(i.OutputDoubleRegister(), i.MemoryOperand(), kScratchReg); 1783 break; 1784 case kMips64Sdc1: { 1785 FPURegister ft = i.InputOrZeroDoubleRegister(2); 1786 if (ft.is(kDoubleRegZero) && !__ IsDoubleZeroRegSet()) { 1787 __ Move(kDoubleRegZero, 0.0); 1788 } 1789 __ sdc1(ft, i.MemoryOperand()); 1790 break; 1791 } 1792 case kMips64Usdc1: { 1793 FPURegister ft = i.InputOrZeroDoubleRegister(2); 1794 if (ft.is(kDoubleRegZero) && !__ IsDoubleZeroRegSet()) { 1795 __ Move(kDoubleRegZero, 0.0); 1796 } 1797 __ Usdc1(ft, i.MemoryOperand(), kScratchReg); 1798 break; 1799 } 1800 case kMips64Push: 1801 if (instr->InputAt(0)->IsFPRegister()) { 1802 __ sdc1(i.InputDoubleRegister(0), MemOperand(sp, -kDoubleSize)); 1803 __ Subu(sp, sp, Operand(kDoubleSize)); 1804 frame_access_state()->IncreaseSPDelta(kDoubleSize / kPointerSize); 1805 } else { 1806 __ Push(i.InputRegister(0)); 1807 frame_access_state()->IncreaseSPDelta(1); 1808 } 1809 break; 1810 case kMips64StackClaim: { 1811 __ Dsubu(sp, sp, Operand(i.InputInt32(0))); 1812 frame_access_state()->IncreaseSPDelta(i.InputInt32(0) / kPointerSize); 1813 break; 1814 } 1815 case kMips64StoreToStackSlot: { 1816 if (instr->InputAt(0)->IsFPRegister()) { 1817 __ sdc1(i.InputDoubleRegister(0), MemOperand(sp, i.InputInt32(1))); 1818 } else { 1819 __ sd(i.InputRegister(0), MemOperand(sp, i.InputInt32(1))); 1820 } 1821 break; 1822 } 1823 case kMips64ByteSwap64: { 1824 __ ByteSwapSigned(i.OutputRegister(0), i.InputRegister(0), 8); 1825 break; 1826 } 1827 case kMips64ByteSwap32: { 1828 __ ByteSwapUnsigned(i.OutputRegister(0), i.InputRegister(0), 4); 1829 __ dsrl32(i.OutputRegister(0), i.OutputRegister(0), 0); 1830 break; 1831 } 1832 case kCheckedLoadInt8: 1833 ASSEMBLE_CHECKED_LOAD_INTEGER(lb); 1834 break; 1835 case kCheckedLoadUint8: 1836 ASSEMBLE_CHECKED_LOAD_INTEGER(lbu); 1837 break; 1838 case kCheckedLoadInt16: 1839 ASSEMBLE_CHECKED_LOAD_INTEGER(lh); 1840 break; 1841 case kCheckedLoadUint16: 1842 ASSEMBLE_CHECKED_LOAD_INTEGER(lhu); 1843 break; 1844 case kCheckedLoadWord32: 1845 ASSEMBLE_CHECKED_LOAD_INTEGER(lw); 1846 break; 1847 case kCheckedLoadWord64: 1848 ASSEMBLE_CHECKED_LOAD_INTEGER(ld); 1849 break; 1850 case kCheckedLoadFloat32: 1851 ASSEMBLE_CHECKED_LOAD_FLOAT(Single, lwc1); 1852 break; 1853 case kCheckedLoadFloat64: 1854 ASSEMBLE_CHECKED_LOAD_FLOAT(Double, ldc1); 1855 break; 1856 case kCheckedStoreWord8: 1857 ASSEMBLE_CHECKED_STORE_INTEGER(sb); 1858 break; 1859 case kCheckedStoreWord16: 1860 ASSEMBLE_CHECKED_STORE_INTEGER(sh); 1861 break; 1862 case kCheckedStoreWord32: 1863 ASSEMBLE_CHECKED_STORE_INTEGER(sw); 1864 break; 1865 case kCheckedStoreWord64: 1866 ASSEMBLE_CHECKED_STORE_INTEGER(sd); 1867 break; 1868 case kCheckedStoreFloat32: 1869 ASSEMBLE_CHECKED_STORE_FLOAT(Single, swc1); 1870 break; 1871 case kCheckedStoreFloat64: 1872 ASSEMBLE_CHECKED_STORE_FLOAT(Double, sdc1); 1873 break; 1874 case kAtomicLoadInt8: 1875 ASSEMBLE_ATOMIC_LOAD_INTEGER(lb); 1876 break; 1877 case kAtomicLoadUint8: 1878 ASSEMBLE_ATOMIC_LOAD_INTEGER(lbu); 1879 break; 1880 case kAtomicLoadInt16: 1881 ASSEMBLE_ATOMIC_LOAD_INTEGER(lh); 1882 break; 1883 case kAtomicLoadUint16: 1884 ASSEMBLE_ATOMIC_LOAD_INTEGER(lhu); 1885 break; 1886 case kAtomicLoadWord32: 1887 ASSEMBLE_ATOMIC_LOAD_INTEGER(lw); 1888 break; 1889 case kAtomicStoreWord8: 1890 ASSEMBLE_ATOMIC_STORE_INTEGER(sb); 1891 break; 1892 case kAtomicStoreWord16: 1893 ASSEMBLE_ATOMIC_STORE_INTEGER(sh); 1894 break; 1895 case kAtomicStoreWord32: 1896 ASSEMBLE_ATOMIC_STORE_INTEGER(sw); 1897 break; 1898 case kMips64AssertEqual: 1899 __ Assert(eq, static_cast<BailoutReason>(i.InputOperand(2).immediate()), 1900 i.InputRegister(0), Operand(i.InputRegister(1))); 1901 break; 1902 } 1903 return kSuccess; 1904 } // NOLINT(readability/fn_size) 1905 1906 1907 #define UNSUPPORTED_COND(opcode, condition) \ 1908 OFStream out(stdout); \ 1909 out << "Unsupported " << #opcode << " condition: \"" << condition << "\""; \ 1910 UNIMPLEMENTED(); 1911 1912 static bool convertCondition(FlagsCondition condition, Condition& cc) { 1913 switch (condition) { 1914 case kEqual: 1915 cc = eq; 1916 return true; 1917 case kNotEqual: 1918 cc = ne; 1919 return true; 1920 case kUnsignedLessThan: 1921 cc = lt; 1922 return true; 1923 case kUnsignedGreaterThanOrEqual: 1924 cc = uge; 1925 return true; 1926 case kUnsignedLessThanOrEqual: 1927 cc = le; 1928 return true; 1929 case kUnsignedGreaterThan: 1930 cc = ugt; 1931 return true; 1932 default: 1933 break; 1934 } 1935 return false; 1936 } 1937 1938 1939 // Assembles branches after an instruction. 1940 void CodeGenerator::AssembleArchBranch(Instruction* instr, BranchInfo* branch) { 1941 MipsOperandConverter i(this, instr); 1942 Label* tlabel = branch->true_label; 1943 Label* flabel = branch->false_label; 1944 Condition cc = kNoCondition; 1945 // MIPS does not have condition code flags, so compare and branch are 1946 // implemented differently than on the other arch's. The compare operations 1947 // emit mips psuedo-instructions, which are handled here by branch 1948 // instructions that do the actual comparison. Essential that the input 1949 // registers to compare pseudo-op are not modified before this branch op, as 1950 // they are tested here. 1951 1952 if (instr->arch_opcode() == kMips64Tst) { 1953 cc = FlagsConditionToConditionTst(branch->condition); 1954 __ And(at, i.InputRegister(0), i.InputOperand(1)); 1955 __ Branch(tlabel, cc, at, Operand(zero_reg)); 1956 } else if (instr->arch_opcode() == kMips64Dadd || 1957 instr->arch_opcode() == kMips64Dsub) { 1958 cc = FlagsConditionToConditionOvf(branch->condition); 1959 __ dsra32(kScratchReg, i.OutputRegister(), 0); 1960 __ sra(at, i.OutputRegister(), 31); 1961 __ Branch(tlabel, cc, at, Operand(kScratchReg)); 1962 } else if (instr->arch_opcode() == kMips64DaddOvf) { 1963 switch (branch->condition) { 1964 case kOverflow: 1965 __ DaddBranchOvf(i.OutputRegister(), i.InputRegister(0), 1966 i.InputOperand(1), tlabel, flabel); 1967 break; 1968 case kNotOverflow: 1969 __ DaddBranchOvf(i.OutputRegister(), i.InputRegister(0), 1970 i.InputOperand(1), flabel, tlabel); 1971 break; 1972 default: 1973 UNSUPPORTED_COND(kMips64DaddOvf, branch->condition); 1974 break; 1975 } 1976 } else if (instr->arch_opcode() == kMips64DsubOvf) { 1977 switch (branch->condition) { 1978 case kOverflow: 1979 __ DsubBranchOvf(i.OutputRegister(), i.InputRegister(0), 1980 i.InputOperand(1), tlabel, flabel); 1981 break; 1982 case kNotOverflow: 1983 __ DsubBranchOvf(i.OutputRegister(), i.InputRegister(0), 1984 i.InputOperand(1), flabel, tlabel); 1985 break; 1986 default: 1987 UNSUPPORTED_COND(kMips64DsubOvf, branch->condition); 1988 break; 1989 } 1990 } else if (instr->arch_opcode() == kMips64MulOvf) { 1991 switch (branch->condition) { 1992 case kOverflow: { 1993 __ MulBranchOvf(i.OutputRegister(), i.InputRegister(0), 1994 i.InputOperand(1), tlabel, flabel, kScratchReg); 1995 } break; 1996 case kNotOverflow: { 1997 __ MulBranchOvf(i.OutputRegister(), i.InputRegister(0), 1998 i.InputOperand(1), flabel, tlabel, kScratchReg); 1999 } break; 2000 default: 2001 UNSUPPORTED_COND(kMips64MulOvf, branch->condition); 2002 break; 2003 } 2004 } else if (instr->arch_opcode() == kMips64Cmp) { 2005 cc = FlagsConditionToConditionCmp(branch->condition); 2006 __ Branch(tlabel, cc, i.InputRegister(0), i.InputOperand(1)); 2007 } else if (instr->arch_opcode() == kMips64CmpS) { 2008 if (!convertCondition(branch->condition, cc)) { 2009 UNSUPPORTED_COND(kMips64CmpS, branch->condition); 2010 } 2011 FPURegister left = i.InputOrZeroSingleRegister(0); 2012 FPURegister right = i.InputOrZeroSingleRegister(1); 2013 if ((left.is(kDoubleRegZero) || right.is(kDoubleRegZero)) && 2014 !__ IsDoubleZeroRegSet()) { 2015 __ Move(kDoubleRegZero, 0.0); 2016 } 2017 __ BranchF32(tlabel, nullptr, cc, left, right); 2018 } else if (instr->arch_opcode() == kMips64CmpD) { 2019 if (!convertCondition(branch->condition, cc)) { 2020 UNSUPPORTED_COND(kMips64CmpD, branch->condition); 2021 } 2022 FPURegister left = i.InputOrZeroDoubleRegister(0); 2023 FPURegister right = i.InputOrZeroDoubleRegister(1); 2024 if ((left.is(kDoubleRegZero) || right.is(kDoubleRegZero)) && 2025 !__ IsDoubleZeroRegSet()) { 2026 __ Move(kDoubleRegZero, 0.0); 2027 } 2028 __ BranchF64(tlabel, nullptr, cc, left, right); 2029 } else { 2030 PrintF("AssembleArchBranch Unimplemented arch_opcode: %d\n", 2031 instr->arch_opcode()); 2032 UNIMPLEMENTED(); 2033 } 2034 if (!branch->fallthru) __ Branch(flabel); // no fallthru to flabel. 2035 } 2036 2037 2038 void CodeGenerator::AssembleArchJump(RpoNumber target) { 2039 if (!IsNextInAssemblyOrder(target)) __ Branch(GetLabel(target)); 2040 } 2041 2042 2043 // Assembles boolean materializations after an instruction. 2044 void CodeGenerator::AssembleArchBoolean(Instruction* instr, 2045 FlagsCondition condition) { 2046 MipsOperandConverter i(this, instr); 2047 Label done; 2048 2049 // Materialize a full 32-bit 1 or 0 value. The result register is always the 2050 // last output of the instruction. 2051 Label false_value; 2052 DCHECK_NE(0u, instr->OutputCount()); 2053 Register result = i.OutputRegister(instr->OutputCount() - 1); 2054 Condition cc = kNoCondition; 2055 // MIPS does not have condition code flags, so compare and branch are 2056 // implemented differently than on the other arch's. The compare operations 2057 // emit mips pseudo-instructions, which are checked and handled here. 2058 2059 if (instr->arch_opcode() == kMips64Tst) { 2060 cc = FlagsConditionToConditionTst(condition); 2061 if (instr->InputAt(1)->IsImmediate() && 2062 base::bits::IsPowerOfTwo64(i.InputOperand(1).immediate())) { 2063 uint16_t pos = 2064 base::bits::CountTrailingZeros64(i.InputOperand(1).immediate()); 2065 __ ExtractBits(result, i.InputRegister(0), pos, 1); 2066 } else { 2067 __ And(kScratchReg, i.InputRegister(0), i.InputOperand(1)); 2068 __ Sltu(result, zero_reg, kScratchReg); 2069 } 2070 if (cc == eq) { 2071 // Sltu produces 0 for equality, invert the result. 2072 __ xori(result, result, 1); 2073 } 2074 return; 2075 } else if (instr->arch_opcode() == kMips64Dadd || 2076 instr->arch_opcode() == kMips64Dsub) { 2077 cc = FlagsConditionToConditionOvf(condition); 2078 // Check for overflow creates 1 or 0 for result. 2079 __ dsrl32(kScratchReg, i.OutputRegister(), 31); 2080 __ srl(at, i.OutputRegister(), 31); 2081 __ xor_(result, kScratchReg, at); 2082 if (cc == eq) // Toggle result for not overflow. 2083 __ xori(result, result, 1); 2084 return; 2085 } else if (instr->arch_opcode() == kMips64DaddOvf || 2086 instr->arch_opcode() == kMips64DsubOvf || 2087 instr->arch_opcode() == kMips64MulOvf) { 2088 Label flabel, tlabel; 2089 switch (instr->arch_opcode()) { 2090 case kMips64DaddOvf: 2091 __ DaddBranchNoOvf(i.OutputRegister(), i.InputRegister(0), 2092 i.InputOperand(1), &flabel); 2093 2094 break; 2095 case kMips64DsubOvf: 2096 __ DsubBranchNoOvf(i.OutputRegister(), i.InputRegister(0), 2097 i.InputOperand(1), &flabel); 2098 break; 2099 case kMips64MulOvf: 2100 __ MulBranchNoOvf(i.OutputRegister(), i.InputRegister(0), 2101 i.InputOperand(1), &flabel, kScratchReg); 2102 break; 2103 default: 2104 UNREACHABLE(); 2105 break; 2106 } 2107 __ li(result, 1); 2108 __ Branch(&tlabel); 2109 __ bind(&flabel); 2110 __ li(result, 0); 2111 __ bind(&tlabel); 2112 } else if (instr->arch_opcode() == kMips64Cmp) { 2113 cc = FlagsConditionToConditionCmp(condition); 2114 switch (cc) { 2115 case eq: 2116 case ne: { 2117 Register left = i.InputRegister(0); 2118 Operand right = i.InputOperand(1); 2119 Register select; 2120 if (instr->InputAt(1)->IsImmediate() && right.immediate() == 0) { 2121 // Pass left operand if right is zero. 2122 select = left; 2123 } else { 2124 __ Dsubu(kScratchReg, left, right); 2125 select = kScratchReg; 2126 } 2127 __ Sltu(result, zero_reg, select); 2128 if (cc == eq) { 2129 // Sltu produces 0 for equality, invert the result. 2130 __ xori(result, result, 1); 2131 } 2132 } break; 2133 case lt: 2134 case ge: { 2135 Register left = i.InputRegister(0); 2136 Operand right = i.InputOperand(1); 2137 __ Slt(result, left, right); 2138 if (cc == ge) { 2139 __ xori(result, result, 1); 2140 } 2141 } break; 2142 case gt: 2143 case le: { 2144 Register left = i.InputRegister(1); 2145 Operand right = i.InputOperand(0); 2146 __ Slt(result, left, right); 2147 if (cc == le) { 2148 __ xori(result, result, 1); 2149 } 2150 } break; 2151 case lo: 2152 case hs: { 2153 Register left = i.InputRegister(0); 2154 Operand right = i.InputOperand(1); 2155 __ Sltu(result, left, right); 2156 if (cc == hs) { 2157 __ xori(result, result, 1); 2158 } 2159 } break; 2160 case hi: 2161 case ls: { 2162 Register left = i.InputRegister(1); 2163 Operand right = i.InputOperand(0); 2164 __ Sltu(result, left, right); 2165 if (cc == ls) { 2166 __ xori(result, result, 1); 2167 } 2168 } break; 2169 default: 2170 UNREACHABLE(); 2171 } 2172 return; 2173 } else if (instr->arch_opcode() == kMips64CmpD || 2174 instr->arch_opcode() == kMips64CmpS) { 2175 FPURegister left = i.InputOrZeroDoubleRegister(0); 2176 FPURegister right = i.InputOrZeroDoubleRegister(1); 2177 if ((left.is(kDoubleRegZero) || right.is(kDoubleRegZero)) && 2178 !__ IsDoubleZeroRegSet()) { 2179 __ Move(kDoubleRegZero, 0.0); 2180 } 2181 bool predicate; 2182 FPUCondition cc = FlagsConditionToConditionCmpFPU(predicate, condition); 2183 if (kArchVariant != kMips64r6) { 2184 __ li(result, Operand(1)); 2185 if (instr->arch_opcode() == kMips64CmpD) { 2186 __ c(cc, D, left, right); 2187 } else { 2188 DCHECK(instr->arch_opcode() == kMips64CmpS); 2189 __ c(cc, S, left, right); 2190 } 2191 if (predicate) { 2192 __ Movf(result, zero_reg); 2193 } else { 2194 __ Movt(result, zero_reg); 2195 } 2196 } else { 2197 if (instr->arch_opcode() == kMips64CmpD) { 2198 __ cmp(cc, L, kDoubleCompareReg, left, right); 2199 } else { 2200 DCHECK(instr->arch_opcode() == kMips64CmpS); 2201 __ cmp(cc, W, kDoubleCompareReg, left, right); 2202 } 2203 __ dmfc1(result, kDoubleCompareReg); 2204 __ andi(result, result, 1); // Cmp returns all 1's/0's, use only LSB. 2205 2206 if (!predicate) // Toggle result for not equal. 2207 __ xori(result, result, 1); 2208 } 2209 return; 2210 } else { 2211 PrintF("AssembleArchBranch Unimplemented arch_opcode is : %d\n", 2212 instr->arch_opcode()); 2213 TRACE_UNIMPL(); 2214 UNIMPLEMENTED(); 2215 } 2216 } 2217 2218 2219 void CodeGenerator::AssembleArchLookupSwitch(Instruction* instr) { 2220 MipsOperandConverter i(this, instr); 2221 Register input = i.InputRegister(0); 2222 for (size_t index = 2; index < instr->InputCount(); index += 2) { 2223 __ li(at, Operand(i.InputInt32(index + 0))); 2224 __ beq(input, at, GetLabel(i.InputRpo(index + 1))); 2225 } 2226 __ nop(); // Branch delay slot of the last beq. 2227 AssembleArchJump(i.InputRpo(1)); 2228 } 2229 2230 void CodeGenerator::AssembleArchTableSwitch(Instruction* instr) { 2231 MipsOperandConverter i(this, instr); 2232 Register input = i.InputRegister(0); 2233 size_t const case_count = instr->InputCount() - 2; 2234 2235 __ Branch(GetLabel(i.InputRpo(1)), hs, input, Operand(case_count)); 2236 __ GenerateSwitchTable(input, case_count, [&i, this](size_t index) { 2237 return GetLabel(i.InputRpo(index + 2)); 2238 }); 2239 } 2240 2241 CodeGenerator::CodeGenResult CodeGenerator::AssembleDeoptimizerCall( 2242 int deoptimization_id, Deoptimizer::BailoutType bailout_type, 2243 SourcePosition pos) { 2244 Address deopt_entry = Deoptimizer::GetDeoptimizationEntry( 2245 isolate(), deoptimization_id, bailout_type); 2246 if (deopt_entry == nullptr) return kTooManyDeoptimizationBailouts; 2247 DeoptimizeReason deoptimization_reason = 2248 GetDeoptimizationReason(deoptimization_id); 2249 __ RecordDeoptReason(deoptimization_reason, pos, deoptimization_id); 2250 __ Call(deopt_entry, RelocInfo::RUNTIME_ENTRY); 2251 return kSuccess; 2252 } 2253 2254 void CodeGenerator::FinishFrame(Frame* frame) { 2255 CallDescriptor* descriptor = linkage()->GetIncomingDescriptor(); 2256 2257 const RegList saves_fpu = descriptor->CalleeSavedFPRegisters(); 2258 if (saves_fpu != 0) { 2259 int count = base::bits::CountPopulation32(saves_fpu); 2260 DCHECK(kNumCalleeSavedFPU == count); 2261 frame->AllocateSavedCalleeRegisterSlots(count * 2262 (kDoubleSize / kPointerSize)); 2263 } 2264 2265 const RegList saves = descriptor->CalleeSavedRegisters(); 2266 if (saves != 0) { 2267 int count = base::bits::CountPopulation32(saves); 2268 DCHECK(kNumCalleeSaved == count + 1); 2269 frame->AllocateSavedCalleeRegisterSlots(count); 2270 } 2271 } 2272 2273 void CodeGenerator::AssembleConstructFrame() { 2274 CallDescriptor* descriptor = linkage()->GetIncomingDescriptor(); 2275 if (frame_access_state()->has_frame()) { 2276 if (descriptor->IsCFunctionCall()) { 2277 __ Push(ra, fp); 2278 __ mov(fp, sp); 2279 } else if (descriptor->IsJSFunctionCall()) { 2280 __ Prologue(this->info()->GeneratePreagedPrologue()); 2281 if (descriptor->PushArgumentCount()) { 2282 __ Push(kJavaScriptCallArgCountRegister); 2283 } 2284 } else { 2285 __ StubPrologue(info()->GetOutputStackFrameType()); 2286 } 2287 } 2288 2289 int shrink_slots = 2290 frame()->GetTotalFrameSlotCount() - descriptor->CalculateFixedFrameSize(); 2291 2292 if (info()->is_osr()) { 2293 // TurboFan OSR-compiled functions cannot be entered directly. 2294 __ Abort(kShouldNotDirectlyEnterOsrFunction); 2295 2296 // Unoptimized code jumps directly to this entrypoint while the unoptimized 2297 // frame is still on the stack. Optimized code uses OSR values directly from 2298 // the unoptimized frame. Thus, all that needs to be done is to allocate the 2299 // remaining stack slots. 2300 if (FLAG_code_comments) __ RecordComment("-- OSR entrypoint --"); 2301 osr_pc_offset_ = __ pc_offset(); 2302 shrink_slots -= OsrHelper(info()).UnoptimizedFrameSlots(); 2303 } 2304 2305 if (shrink_slots > 0) { 2306 __ Dsubu(sp, sp, Operand(shrink_slots * kPointerSize)); 2307 } 2308 2309 const RegList saves_fpu = descriptor->CalleeSavedFPRegisters(); 2310 if (saves_fpu != 0) { 2311 // Save callee-saved FPU registers. 2312 __ MultiPushFPU(saves_fpu); 2313 DCHECK(kNumCalleeSavedFPU == base::bits::CountPopulation32(saves_fpu)); 2314 } 2315 2316 const RegList saves = descriptor->CalleeSavedRegisters(); 2317 if (saves != 0) { 2318 // Save callee-saved registers. 2319 __ MultiPush(saves); 2320 DCHECK(kNumCalleeSaved == base::bits::CountPopulation32(saves) + 1); 2321 } 2322 } 2323 2324 void CodeGenerator::AssembleReturn(InstructionOperand* pop) { 2325 CallDescriptor* descriptor = linkage()->GetIncomingDescriptor(); 2326 2327 // Restore GP registers. 2328 const RegList saves = descriptor->CalleeSavedRegisters(); 2329 if (saves != 0) { 2330 __ MultiPop(saves); 2331 } 2332 2333 // Restore FPU registers. 2334 const RegList saves_fpu = descriptor->CalleeSavedFPRegisters(); 2335 if (saves_fpu != 0) { 2336 __ MultiPopFPU(saves_fpu); 2337 } 2338 2339 MipsOperandConverter g(this, nullptr); 2340 if (descriptor->IsCFunctionCall()) { 2341 AssembleDeconstructFrame(); 2342 } else if (frame_access_state()->has_frame()) { 2343 // Canonicalize JSFunction return sites for now unless they have an variable 2344 // number of stack slot pops. 2345 if (pop->IsImmediate() && g.ToConstant(pop).ToInt32() == 0) { 2346 if (return_label_.is_bound()) { 2347 __ Branch(&return_label_); 2348 return; 2349 } else { 2350 __ bind(&return_label_); 2351 AssembleDeconstructFrame(); 2352 } 2353 } else { 2354 AssembleDeconstructFrame(); 2355 } 2356 } 2357 int pop_count = static_cast<int>(descriptor->StackParameterCount()); 2358 if (pop->IsImmediate()) { 2359 DCHECK_EQ(Constant::kInt32, g.ToConstant(pop).type()); 2360 pop_count += g.ToConstant(pop).ToInt32(); 2361 } else { 2362 Register pop_reg = g.ToRegister(pop); 2363 __ dsll(pop_reg, pop_reg, kPointerSizeLog2); 2364 __ Daddu(sp, sp, pop_reg); 2365 } 2366 if (pop_count != 0) { 2367 __ DropAndRet(pop_count); 2368 } else { 2369 __ Ret(); 2370 } 2371 } 2372 2373 2374 void CodeGenerator::AssembleMove(InstructionOperand* source, 2375 InstructionOperand* destination) { 2376 MipsOperandConverter g(this, nullptr); 2377 // Dispatch on the source and destination operand kinds. Not all 2378 // combinations are possible. 2379 if (source->IsRegister()) { 2380 DCHECK(destination->IsRegister() || destination->IsStackSlot()); 2381 Register src = g.ToRegister(source); 2382 if (destination->IsRegister()) { 2383 __ mov(g.ToRegister(destination), src); 2384 } else { 2385 __ sd(src, g.ToMemOperand(destination)); 2386 } 2387 } else if (source->IsStackSlot()) { 2388 DCHECK(destination->IsRegister() || destination->IsStackSlot()); 2389 MemOperand src = g.ToMemOperand(source); 2390 if (destination->IsRegister()) { 2391 __ ld(g.ToRegister(destination), src); 2392 } else { 2393 Register temp = kScratchReg; 2394 __ ld(temp, src); 2395 __ sd(temp, g.ToMemOperand(destination)); 2396 } 2397 } else if (source->IsConstant()) { 2398 Constant src = g.ToConstant(source); 2399 if (destination->IsRegister() || destination->IsStackSlot()) { 2400 Register dst = 2401 destination->IsRegister() ? g.ToRegister(destination) : kScratchReg; 2402 switch (src.type()) { 2403 case Constant::kInt32: 2404 if (src.rmode() == RelocInfo::WASM_MEMORY_SIZE_REFERENCE) { 2405 __ li(dst, Operand(src.ToInt32(), src.rmode())); 2406 } else { 2407 __ li(dst, Operand(src.ToInt32())); 2408 } 2409 break; 2410 case Constant::kFloat32: 2411 __ li(dst, isolate()->factory()->NewNumber(src.ToFloat32(), TENURED)); 2412 break; 2413 case Constant::kInt64: 2414 if (src.rmode() == RelocInfo::WASM_MEMORY_REFERENCE || 2415 src.rmode() == RelocInfo::WASM_GLOBAL_REFERENCE) { 2416 __ li(dst, Operand(src.ToInt64(), src.rmode())); 2417 } else { 2418 DCHECK(src.rmode() != RelocInfo::WASM_MEMORY_SIZE_REFERENCE); 2419 __ li(dst, Operand(src.ToInt64())); 2420 } 2421 break; 2422 case Constant::kFloat64: 2423 __ li(dst, isolate()->factory()->NewNumber(src.ToFloat64(), TENURED)); 2424 break; 2425 case Constant::kExternalReference: 2426 __ li(dst, Operand(src.ToExternalReference())); 2427 break; 2428 case Constant::kHeapObject: { 2429 Handle<HeapObject> src_object = src.ToHeapObject(); 2430 Heap::RootListIndex index; 2431 if (IsMaterializableFromRoot(src_object, &index)) { 2432 __ LoadRoot(dst, index); 2433 } else { 2434 __ li(dst, src_object); 2435 } 2436 break; 2437 } 2438 case Constant::kRpoNumber: 2439 UNREACHABLE(); // TODO(titzer): loading RPO numbers on mips64. 2440 break; 2441 } 2442 if (destination->IsStackSlot()) __ sd(dst, g.ToMemOperand(destination)); 2443 } else if (src.type() == Constant::kFloat32) { 2444 if (destination->IsFPStackSlot()) { 2445 MemOperand dst = g.ToMemOperand(destination); 2446 if (bit_cast<int32_t>(src.ToFloat32()) == 0) { 2447 __ sw(zero_reg, dst); 2448 } else { 2449 __ li(at, Operand(bit_cast<int32_t>(src.ToFloat32()))); 2450 __ sw(at, dst); 2451 } 2452 } else { 2453 DCHECK(destination->IsFPRegister()); 2454 FloatRegister dst = g.ToSingleRegister(destination); 2455 __ Move(dst, src.ToFloat32()); 2456 } 2457 } else { 2458 DCHECK_EQ(Constant::kFloat64, src.type()); 2459 DoubleRegister dst = destination->IsFPRegister() 2460 ? g.ToDoubleRegister(destination) 2461 : kScratchDoubleReg; 2462 __ Move(dst, src.ToFloat64()); 2463 if (destination->IsFPStackSlot()) { 2464 __ sdc1(dst, g.ToMemOperand(destination)); 2465 } 2466 } 2467 } else if (source->IsFPRegister()) { 2468 FPURegister src = g.ToDoubleRegister(source); 2469 if (destination->IsFPRegister()) { 2470 FPURegister dst = g.ToDoubleRegister(destination); 2471 __ Move(dst, src); 2472 } else { 2473 DCHECK(destination->IsFPStackSlot()); 2474 __ sdc1(src, g.ToMemOperand(destination)); 2475 } 2476 } else if (source->IsFPStackSlot()) { 2477 DCHECK(destination->IsFPRegister() || destination->IsFPStackSlot()); 2478 MemOperand src = g.ToMemOperand(source); 2479 if (destination->IsFPRegister()) { 2480 __ ldc1(g.ToDoubleRegister(destination), src); 2481 } else { 2482 FPURegister temp = kScratchDoubleReg; 2483 __ ldc1(temp, src); 2484 __ sdc1(temp, g.ToMemOperand(destination)); 2485 } 2486 } else { 2487 UNREACHABLE(); 2488 } 2489 } 2490 2491 2492 void CodeGenerator::AssembleSwap(InstructionOperand* source, 2493 InstructionOperand* destination) { 2494 MipsOperandConverter g(this, nullptr); 2495 // Dispatch on the source and destination operand kinds. Not all 2496 // combinations are possible. 2497 if (source->IsRegister()) { 2498 // Register-register. 2499 Register temp = kScratchReg; 2500 Register src = g.ToRegister(source); 2501 if (destination->IsRegister()) { 2502 Register dst = g.ToRegister(destination); 2503 __ Move(temp, src); 2504 __ Move(src, dst); 2505 __ Move(dst, temp); 2506 } else { 2507 DCHECK(destination->IsStackSlot()); 2508 MemOperand dst = g.ToMemOperand(destination); 2509 __ mov(temp, src); 2510 __ ld(src, dst); 2511 __ sd(temp, dst); 2512 } 2513 } else if (source->IsStackSlot()) { 2514 DCHECK(destination->IsStackSlot()); 2515 Register temp_0 = kScratchReg; 2516 Register temp_1 = kScratchReg2; 2517 MemOperand src = g.ToMemOperand(source); 2518 MemOperand dst = g.ToMemOperand(destination); 2519 __ ld(temp_0, src); 2520 __ ld(temp_1, dst); 2521 __ sd(temp_0, dst); 2522 __ sd(temp_1, src); 2523 } else if (source->IsFPRegister()) { 2524 FPURegister temp = kScratchDoubleReg; 2525 FPURegister src = g.ToDoubleRegister(source); 2526 if (destination->IsFPRegister()) { 2527 FPURegister dst = g.ToDoubleRegister(destination); 2528 __ Move(temp, src); 2529 __ Move(src, dst); 2530 __ Move(dst, temp); 2531 } else { 2532 DCHECK(destination->IsFPStackSlot()); 2533 MemOperand dst = g.ToMemOperand(destination); 2534 __ Move(temp, src); 2535 __ ldc1(src, dst); 2536 __ sdc1(temp, dst); 2537 } 2538 } else if (source->IsFPStackSlot()) { 2539 DCHECK(destination->IsFPStackSlot()); 2540 Register temp_0 = kScratchReg; 2541 FPURegister temp_1 = kScratchDoubleReg; 2542 MemOperand src0 = g.ToMemOperand(source); 2543 MemOperand src1(src0.rm(), src0.offset() + kIntSize); 2544 MemOperand dst0 = g.ToMemOperand(destination); 2545 MemOperand dst1(dst0.rm(), dst0.offset() + kIntSize); 2546 __ ldc1(temp_1, dst0); // Save destination in temp_1. 2547 __ lw(temp_0, src0); // Then use temp_0 to copy source to destination. 2548 __ sw(temp_0, dst0); 2549 __ lw(temp_0, src1); 2550 __ sw(temp_0, dst1); 2551 __ sdc1(temp_1, src0); 2552 } else { 2553 // No other combinations are possible. 2554 UNREACHABLE(); 2555 } 2556 } 2557 2558 2559 void CodeGenerator::AssembleJumpTable(Label** targets, size_t target_count) { 2560 // On 64-bit MIPS we emit the jump tables inline. 2561 UNREACHABLE(); 2562 } 2563 2564 2565 void CodeGenerator::EnsureSpaceForLazyDeopt() { 2566 if (!info()->ShouldEnsureSpaceForLazyDeopt()) { 2567 return; 2568 } 2569 2570 int space_needed = Deoptimizer::patch_size(); 2571 // Ensure that we have enough space after the previous lazy-bailout 2572 // instruction for patching the code here. 2573 int current_pc = masm()->pc_offset(); 2574 if (current_pc < last_lazy_deopt_pc_ + space_needed) { 2575 // Block tramoline pool emission for duration of padding. 2576 v8::internal::Assembler::BlockTrampolinePoolScope block_trampoline_pool( 2577 masm()); 2578 int padding_size = last_lazy_deopt_pc_ + space_needed - current_pc; 2579 DCHECK_EQ(0, padding_size % v8::internal::Assembler::kInstrSize); 2580 while (padding_size > 0) { 2581 __ nop(); 2582 padding_size -= v8::internal::Assembler::kInstrSize; 2583 } 2584 } 2585 } 2586 2587 #undef __ 2588 2589 } // namespace compiler 2590 } // namespace internal 2591 } // namespace v8 2592