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