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/ast/scopes.h" 6 #include "src/compiler/code-generator.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 kCompareReg kLithiumScratchReg2 23 #define kScratchReg2 kLithiumScratchReg2 24 #define kScratchDoubleReg kLithiumScratchDouble 25 26 27 // TODO(plind): consider renaming these macros. 28 #define TRACE_MSG(msg) \ 29 PrintF("code_gen: \'%s\' in function %s at line %d\n", msg, __FUNCTION__, \ 30 __LINE__) 31 32 #define TRACE_UNIMPL() \ 33 PrintF("UNIMPLEMENTED code_generator_mips: %s at line %d\n", __FUNCTION__, \ 34 __LINE__) 35 36 37 // Adds Mips-specific methods to convert InstructionOperands. 38 class MipsOperandConverter final : public InstructionOperandConverter { 39 public: 40 MipsOperandConverter(CodeGenerator* gen, Instruction* instr) 41 : InstructionOperandConverter(gen, instr) {} 42 43 FloatRegister OutputSingleRegister(size_t index = 0) { 44 return ToSingleRegister(instr_->OutputAt(index)); 45 } 46 47 FloatRegister InputSingleRegister(size_t index) { 48 return ToSingleRegister(instr_->InputAt(index)); 49 } 50 51 FloatRegister ToSingleRegister(InstructionOperand* op) { 52 // Single (Float) and Double register namespace is same on MIPS, 53 // both are typedefs of FPURegister. 54 return ToDoubleRegister(op); 55 } 56 57 DoubleRegister InputOrZeroDoubleRegister(size_t index) { 58 if (instr_->InputAt(index)->IsImmediate()) return kDoubleRegZero; 59 60 return InputDoubleRegister(index); 61 } 62 63 DoubleRegister InputOrZeroSingleRegister(size_t index) { 64 if (instr_->InputAt(index)->IsImmediate()) return kDoubleRegZero; 65 66 return InputSingleRegister(index); 67 } 68 69 Operand InputImmediate(size_t index) { 70 Constant constant = ToConstant(instr_->InputAt(index)); 71 switch (constant.type()) { 72 case Constant::kInt32: 73 return Operand(constant.ToInt32()); 74 case Constant::kFloat32: 75 return Operand( 76 isolate()->factory()->NewNumber(constant.ToFloat32(), TENURED)); 77 case Constant::kFloat64: 78 return Operand( 79 isolate()->factory()->NewNumber(constant.ToFloat64(), TENURED)); 80 case Constant::kInt64: 81 case Constant::kExternalReference: 82 case Constant::kHeapObject: 83 // TODO(plind): Maybe we should handle ExtRef & HeapObj here? 84 // maybe not done on arm due to const pool ?? 85 break; 86 case Constant::kRpoNumber: 87 UNREACHABLE(); // TODO(titzer): RPO immediates on mips? 88 break; 89 } 90 UNREACHABLE(); 91 return Operand(zero_reg); 92 } 93 94 Operand InputOperand(size_t index) { 95 InstructionOperand* op = instr_->InputAt(index); 96 if (op->IsRegister()) { 97 return Operand(ToRegister(op)); 98 } 99 return InputImmediate(index); 100 } 101 102 MemOperand MemoryOperand(size_t* first_index) { 103 const size_t index = *first_index; 104 switch (AddressingModeField::decode(instr_->opcode())) { 105 case kMode_None: 106 break; 107 case kMode_MRI: 108 *first_index += 2; 109 return MemOperand(InputRegister(index + 0), InputInt32(index + 1)); 110 case kMode_MRR: 111 // TODO(plind): r6 address mode, to be implemented ... 112 UNREACHABLE(); 113 } 114 UNREACHABLE(); 115 return MemOperand(no_reg); 116 } 117 118 MemOperand MemoryOperand(size_t index = 0) { return MemoryOperand(&index); } 119 120 MemOperand ToMemOperand(InstructionOperand* op) const { 121 DCHECK_NOT_NULL(op); 122 DCHECK(op->IsStackSlot() || op->IsFPStackSlot()); 123 return SlotToMemOperand(AllocatedOperand::cast(op)->index()); 124 } 125 126 MemOperand SlotToMemOperand(int slot) const { 127 FrameOffset offset = frame_access_state()->GetFrameOffset(slot); 128 return MemOperand(offset.from_stack_pointer() ? sp : fp, offset.offset()); 129 } 130 }; 131 132 133 static inline bool HasRegisterInput(Instruction* instr, size_t index) { 134 return instr->InputAt(index)->IsRegister(); 135 } 136 137 138 namespace { 139 140 class OutOfLineLoadSingle final : public OutOfLineCode { 141 public: 142 OutOfLineLoadSingle(CodeGenerator* gen, FloatRegister result) 143 : OutOfLineCode(gen), result_(result) {} 144 145 void Generate() final { 146 __ Move(result_, std::numeric_limits<float>::quiet_NaN()); 147 } 148 149 private: 150 FloatRegister const result_; 151 }; 152 153 154 class OutOfLineLoadDouble final : public OutOfLineCode { 155 public: 156 OutOfLineLoadDouble(CodeGenerator* gen, DoubleRegister result) 157 : OutOfLineCode(gen), result_(result) {} 158 159 void Generate() final { 160 __ Move(result_, std::numeric_limits<double>::quiet_NaN()); 161 } 162 163 private: 164 DoubleRegister const result_; 165 }; 166 167 168 class OutOfLineLoadInteger final : public OutOfLineCode { 169 public: 170 OutOfLineLoadInteger(CodeGenerator* gen, Register result) 171 : OutOfLineCode(gen), result_(result) {} 172 173 void Generate() final { __ mov(result_, zero_reg); } 174 175 private: 176 Register const result_; 177 }; 178 179 180 class OutOfLineRound : public OutOfLineCode { 181 public: 182 OutOfLineRound(CodeGenerator* gen, DoubleRegister result) 183 : OutOfLineCode(gen), result_(result) {} 184 185 void Generate() final { 186 // Handle rounding to zero case where sign has to be preserved. 187 // High bits of double input already in kScratchReg. 188 __ srl(at, kScratchReg, 31); 189 __ sll(at, at, 31); 190 __ Mthc1(at, result_); 191 } 192 193 private: 194 DoubleRegister const result_; 195 }; 196 197 198 class OutOfLineRound32 : public OutOfLineCode { 199 public: 200 OutOfLineRound32(CodeGenerator* gen, DoubleRegister result) 201 : OutOfLineCode(gen), result_(result) {} 202 203 void Generate() final { 204 // Handle rounding to zero case where sign has to be preserved. 205 // High bits of float input already in kScratchReg. 206 __ srl(at, kScratchReg, 31); 207 __ sll(at, at, 31); 208 __ mtc1(at, result_); 209 } 210 211 private: 212 DoubleRegister const result_; 213 }; 214 215 216 class OutOfLineRecordWrite final : public OutOfLineCode { 217 public: 218 OutOfLineRecordWrite(CodeGenerator* gen, Register object, Register index, 219 Register value, Register scratch0, Register scratch1, 220 RecordWriteMode mode) 221 : OutOfLineCode(gen), 222 object_(object), 223 index_(index), 224 value_(value), 225 scratch0_(scratch0), 226 scratch1_(scratch1), 227 mode_(mode), 228 must_save_lr_(!gen->frame_access_state()->has_frame()) {} 229 230 void Generate() final { 231 if (mode_ > RecordWriteMode::kValueIsPointer) { 232 __ JumpIfSmi(value_, exit()); 233 } 234 __ CheckPageFlag(value_, scratch0_, 235 MemoryChunk::kPointersToHereAreInterestingMask, eq, 236 exit()); 237 RememberedSetAction const remembered_set_action = 238 mode_ > RecordWriteMode::kValueIsMap ? EMIT_REMEMBERED_SET 239 : OMIT_REMEMBERED_SET; 240 SaveFPRegsMode const save_fp_mode = 241 frame()->DidAllocateDoubleRegisters() ? kSaveFPRegs : kDontSaveFPRegs; 242 if (must_save_lr_) { 243 // We need to save and restore ra if the frame was elided. 244 __ Push(ra); 245 } 246 RecordWriteStub stub(isolate(), object_, scratch0_, scratch1_, 247 remembered_set_action, save_fp_mode); 248 __ Addu(scratch1_, object_, index_); 249 __ CallStub(&stub); 250 if (must_save_lr_) { 251 __ Pop(ra); 252 } 253 } 254 255 private: 256 Register const object_; 257 Register const index_; 258 Register const value_; 259 Register const scratch0_; 260 Register const scratch1_; 261 RecordWriteMode const mode_; 262 bool must_save_lr_; 263 }; 264 265 266 Condition FlagsConditionToConditionCmp(FlagsCondition condition) { 267 switch (condition) { 268 case kEqual: 269 return eq; 270 case kNotEqual: 271 return ne; 272 case kSignedLessThan: 273 return lt; 274 case kSignedGreaterThanOrEqual: 275 return ge; 276 case kSignedLessThanOrEqual: 277 return le; 278 case kSignedGreaterThan: 279 return gt; 280 case kUnsignedLessThan: 281 return lo; 282 case kUnsignedGreaterThanOrEqual: 283 return hs; 284 case kUnsignedLessThanOrEqual: 285 return ls; 286 case kUnsignedGreaterThan: 287 return hi; 288 case kUnorderedEqual: 289 case kUnorderedNotEqual: 290 break; 291 default: 292 break; 293 } 294 UNREACHABLE(); 295 return kNoCondition; 296 } 297 298 299 Condition FlagsConditionToConditionTst(FlagsCondition condition) { 300 switch (condition) { 301 case kNotEqual: 302 return ne; 303 case kEqual: 304 return eq; 305 default: 306 break; 307 } 308 UNREACHABLE(); 309 return kNoCondition; 310 } 311 312 313 FPUCondition FlagsConditionToConditionCmpFPU(bool& predicate, 314 FlagsCondition condition) { 315 switch (condition) { 316 case kEqual: 317 predicate = true; 318 return EQ; 319 case kNotEqual: 320 predicate = false; 321 return EQ; 322 case kUnsignedLessThan: 323 predicate = true; 324 return OLT; 325 case kUnsignedGreaterThanOrEqual: 326 predicate = false; 327 return ULT; 328 case kUnsignedLessThanOrEqual: 329 predicate = true; 330 return OLE; 331 case kUnsignedGreaterThan: 332 predicate = false; 333 return ULE; 334 case kUnorderedEqual: 335 case kUnorderedNotEqual: 336 predicate = true; 337 break; 338 default: 339 predicate = true; 340 break; 341 } 342 UNREACHABLE(); 343 return kNoFPUCondition; 344 } 345 346 } // namespace 347 348 349 #define ASSEMBLE_CHECKED_LOAD_FLOAT(width, asm_instr) \ 350 do { \ 351 auto result = i.Output##width##Register(); \ 352 auto ool = new (zone()) OutOfLineLoad##width(this, result); \ 353 if (instr->InputAt(0)->IsRegister()) { \ 354 auto offset = i.InputRegister(0); \ 355 __ Branch(USE_DELAY_SLOT, ool->entry(), hs, offset, i.InputOperand(1)); \ 356 __ addu(kScratchReg, i.InputRegister(2), offset); \ 357 __ asm_instr(result, MemOperand(kScratchReg, 0)); \ 358 } else { \ 359 auto offset = i.InputOperand(0).immediate(); \ 360 __ Branch(ool->entry(), ls, i.InputRegister(1), Operand(offset)); \ 361 __ asm_instr(result, MemOperand(i.InputRegister(2), offset)); \ 362 } \ 363 __ bind(ool->exit()); \ 364 } while (0) 365 366 367 #define ASSEMBLE_CHECKED_LOAD_INTEGER(asm_instr) \ 368 do { \ 369 auto result = i.OutputRegister(); \ 370 auto ool = new (zone()) OutOfLineLoadInteger(this, result); \ 371 if (instr->InputAt(0)->IsRegister()) { \ 372 auto offset = i.InputRegister(0); \ 373 __ Branch(USE_DELAY_SLOT, ool->entry(), hs, offset, i.InputOperand(1)); \ 374 __ addu(kScratchReg, i.InputRegister(2), offset); \ 375 __ asm_instr(result, MemOperand(kScratchReg, 0)); \ 376 } else { \ 377 auto offset = i.InputOperand(0).immediate(); \ 378 __ Branch(ool->entry(), ls, i.InputRegister(1), Operand(offset)); \ 379 __ asm_instr(result, MemOperand(i.InputRegister(2), offset)); \ 380 } \ 381 __ bind(ool->exit()); \ 382 } while (0) 383 384 385 #define ASSEMBLE_CHECKED_STORE_FLOAT(width, asm_instr) \ 386 do { \ 387 Label done; \ 388 if (instr->InputAt(0)->IsRegister()) { \ 389 auto offset = i.InputRegister(0); \ 390 auto value = i.Input##width##Register(2); \ 391 __ Branch(USE_DELAY_SLOT, &done, hs, offset, i.InputOperand(1)); \ 392 __ addu(kScratchReg, i.InputRegister(3), offset); \ 393 __ asm_instr(value, MemOperand(kScratchReg, 0)); \ 394 } else { \ 395 auto offset = i.InputOperand(0).immediate(); \ 396 auto value = i.Input##width##Register(2); \ 397 __ Branch(&done, ls, i.InputRegister(1), Operand(offset)); \ 398 __ asm_instr(value, MemOperand(i.InputRegister(3), offset)); \ 399 } \ 400 __ bind(&done); \ 401 } while (0) 402 403 404 #define ASSEMBLE_CHECKED_STORE_INTEGER(asm_instr) \ 405 do { \ 406 Label done; \ 407 if (instr->InputAt(0)->IsRegister()) { \ 408 auto offset = i.InputRegister(0); \ 409 auto value = i.InputRegister(2); \ 410 __ Branch(USE_DELAY_SLOT, &done, hs, offset, i.InputOperand(1)); \ 411 __ addu(kScratchReg, i.InputRegister(3), offset); \ 412 __ asm_instr(value, MemOperand(kScratchReg, 0)); \ 413 } else { \ 414 auto offset = i.InputOperand(0).immediate(); \ 415 auto value = i.InputRegister(2); \ 416 __ Branch(&done, ls, i.InputRegister(1), Operand(offset)); \ 417 __ asm_instr(value, MemOperand(i.InputRegister(3), offset)); \ 418 } \ 419 __ bind(&done); \ 420 } while (0) 421 422 423 #define ASSEMBLE_ROUND_DOUBLE_TO_DOUBLE(mode) \ 424 if (IsMipsArchVariant(kMips32r6)) { \ 425 __ cfc1(kScratchReg, FCSR); \ 426 __ li(at, Operand(mode_##mode)); \ 427 __ ctc1(at, FCSR); \ 428 __ rint_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0)); \ 429 __ ctc1(kScratchReg, FCSR); \ 430 } else { \ 431 auto ool = new (zone()) OutOfLineRound(this, i.OutputDoubleRegister()); \ 432 Label done; \ 433 __ Mfhc1(kScratchReg, i.InputDoubleRegister(0)); \ 434 __ Ext(at, kScratchReg, HeapNumber::kExponentShift, \ 435 HeapNumber::kExponentBits); \ 436 __ Branch(USE_DELAY_SLOT, &done, hs, at, \ 437 Operand(HeapNumber::kExponentBias + HeapNumber::kMantissaBits)); \ 438 __ mov_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0)); \ 439 __ mode##_l_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0)); \ 440 __ Move(at, kScratchReg2, i.OutputDoubleRegister()); \ 441 __ or_(at, at, kScratchReg2); \ 442 __ Branch(USE_DELAY_SLOT, ool->entry(), eq, at, Operand(zero_reg)); \ 443 __ cvt_d_l(i.OutputDoubleRegister(), i.OutputDoubleRegister()); \ 444 __ bind(ool->exit()); \ 445 __ bind(&done); \ 446 } 447 448 449 #define ASSEMBLE_ROUND_FLOAT_TO_FLOAT(mode) \ 450 if (IsMipsArchVariant(kMips32r6)) { \ 451 __ cfc1(kScratchReg, FCSR); \ 452 __ li(at, Operand(mode_##mode)); \ 453 __ ctc1(at, FCSR); \ 454 __ rint_s(i.OutputDoubleRegister(), i.InputDoubleRegister(0)); \ 455 __ ctc1(kScratchReg, FCSR); \ 456 } else { \ 457 int32_t kFloat32ExponentBias = 127; \ 458 int32_t kFloat32MantissaBits = 23; \ 459 int32_t kFloat32ExponentBits = 8; \ 460 auto ool = new (zone()) OutOfLineRound32(this, i.OutputDoubleRegister()); \ 461 Label done; \ 462 __ mfc1(kScratchReg, i.InputDoubleRegister(0)); \ 463 __ Ext(at, kScratchReg, kFloat32MantissaBits, kFloat32ExponentBits); \ 464 __ Branch(USE_DELAY_SLOT, &done, hs, at, \ 465 Operand(kFloat32ExponentBias + kFloat32MantissaBits)); \ 466 __ mov_s(i.OutputDoubleRegister(), i.InputDoubleRegister(0)); \ 467 __ mode##_w_s(i.OutputDoubleRegister(), i.InputDoubleRegister(0)); \ 468 __ mfc1(at, i.OutputDoubleRegister()); \ 469 __ Branch(USE_DELAY_SLOT, ool->entry(), eq, at, Operand(zero_reg)); \ 470 __ cvt_s_w(i.OutputDoubleRegister(), i.OutputDoubleRegister()); \ 471 __ bind(ool->exit()); \ 472 __ bind(&done); \ 473 } 474 475 #define ASSEMBLE_ATOMIC_LOAD_INTEGER(asm_instr) \ 476 do { \ 477 __ asm_instr(i.OutputRegister(), i.MemoryOperand()); \ 478 __ sync(); \ 479 } while (0) 480 481 #define ASSEMBLE_ATOMIC_STORE_INTEGER(asm_instr) \ 482 do { \ 483 __ sync(); \ 484 __ asm_instr(i.InputRegister(2), i.MemoryOperand()); \ 485 __ sync(); \ 486 } while (0) 487 488 #define ASSEMBLE_IEEE754_BINOP(name) \ 489 do { \ 490 FrameScope scope(masm(), StackFrame::MANUAL); \ 491 __ PrepareCallCFunction(0, 2, kScratchReg); \ 492 __ MovToFloatParameters(i.InputDoubleRegister(0), \ 493 i.InputDoubleRegister(1)); \ 494 __ CallCFunction(ExternalReference::ieee754_##name##_function(isolate()), \ 495 0, 2); \ 496 /* Move the result in the double result register. */ \ 497 __ MovFromFloatResult(i.OutputDoubleRegister()); \ 498 } while (0) 499 500 #define ASSEMBLE_IEEE754_UNOP(name) \ 501 do { \ 502 FrameScope scope(masm(), StackFrame::MANUAL); \ 503 __ PrepareCallCFunction(0, 1, kScratchReg); \ 504 __ MovToFloatParameter(i.InputDoubleRegister(0)); \ 505 __ CallCFunction(ExternalReference::ieee754_##name##_function(isolate()), \ 506 0, 1); \ 507 /* Move the result in the double result register. */ \ 508 __ MovFromFloatResult(i.OutputDoubleRegister()); \ 509 } while (0) 510 511 void CodeGenerator::AssembleDeconstructFrame() { 512 __ mov(sp, fp); 513 __ Pop(ra, fp); 514 } 515 516 void CodeGenerator::AssembleDeconstructActivationRecord(int stack_param_delta) { 517 int sp_slot_delta = TailCallFrameStackSlotDelta(stack_param_delta); 518 if (sp_slot_delta > 0) { 519 __ addiu(sp, sp, sp_slot_delta * kPointerSize); 520 } 521 frame_access_state()->SetFrameAccessToDefault(); 522 } 523 524 525 void CodeGenerator::AssemblePrepareTailCall(int stack_param_delta) { 526 int sp_slot_delta = TailCallFrameStackSlotDelta(stack_param_delta); 527 if (sp_slot_delta < 0) { 528 __ Subu(sp, sp, Operand(-sp_slot_delta * kPointerSize)); 529 frame_access_state()->IncreaseSPDelta(-sp_slot_delta); 530 } 531 if (frame_access_state()->has_frame()) { 532 __ lw(ra, MemOperand(fp, StandardFrameConstants::kCallerPCOffset)); 533 __ lw(fp, MemOperand(fp, StandardFrameConstants::kCallerFPOffset)); 534 } 535 frame_access_state()->SetFrameAccessToSP(); 536 } 537 538 void CodeGenerator::AssemblePopArgumentsAdaptorFrame(Register args_reg, 539 Register scratch1, 540 Register scratch2, 541 Register scratch3) { 542 DCHECK(!AreAliased(args_reg, scratch1, scratch2, scratch3)); 543 Label done; 544 545 // Check if current frame is an arguments adaptor frame. 546 __ lw(scratch1, MemOperand(fp, StandardFrameConstants::kContextOffset)); 547 __ Branch(&done, ne, scratch1, 548 Operand(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR))); 549 550 // Load arguments count from current arguments adaptor frame (note, it 551 // does not include receiver). 552 Register caller_args_count_reg = scratch1; 553 __ lw(caller_args_count_reg, 554 MemOperand(fp, ArgumentsAdaptorFrameConstants::kLengthOffset)); 555 __ SmiUntag(caller_args_count_reg); 556 557 ParameterCount callee_args_count(args_reg); 558 __ PrepareForTailCall(callee_args_count, caller_args_count_reg, scratch2, 559 scratch3); 560 __ bind(&done); 561 } 562 563 // Assembles an instruction after register allocation, producing machine code. 564 CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction( 565 Instruction* instr) { 566 MipsOperandConverter i(this, instr); 567 InstructionCode opcode = instr->opcode(); 568 ArchOpcode arch_opcode = ArchOpcodeField::decode(opcode); 569 switch (arch_opcode) { 570 case kArchCallCodeObject: { 571 EnsureSpaceForLazyDeopt(); 572 if (instr->InputAt(0)->IsImmediate()) { 573 __ Call(Handle<Code>::cast(i.InputHeapObject(0)), 574 RelocInfo::CODE_TARGET); 575 } else { 576 __ addiu(at, i.InputRegister(0), Code::kHeaderSize - kHeapObjectTag); 577 __ Call(at); 578 } 579 RecordCallPosition(instr); 580 frame_access_state()->ClearSPDelta(); 581 break; 582 } 583 case kArchTailCallCodeObjectFromJSFunction: 584 case kArchTailCallCodeObject: { 585 int stack_param_delta = i.InputInt32(instr->InputCount() - 1); 586 AssembleDeconstructActivationRecord(stack_param_delta); 587 if (arch_opcode == kArchTailCallCodeObjectFromJSFunction) { 588 AssemblePopArgumentsAdaptorFrame(kJavaScriptCallArgCountRegister, 589 i.TempRegister(0), i.TempRegister(1), 590 i.TempRegister(2)); 591 } 592 if (instr->InputAt(0)->IsImmediate()) { 593 __ Jump(Handle<Code>::cast(i.InputHeapObject(0)), 594 RelocInfo::CODE_TARGET); 595 } else { 596 __ addiu(at, i.InputRegister(0), Code::kHeaderSize - kHeapObjectTag); 597 __ Jump(at); 598 } 599 frame_access_state()->ClearSPDelta(); 600 break; 601 } 602 case kArchTailCallAddress: { 603 int stack_param_delta = i.InputInt32(instr->InputCount() - 1); 604 AssembleDeconstructActivationRecord(stack_param_delta); 605 CHECK(!instr->InputAt(0)->IsImmediate()); 606 __ Jump(i.InputRegister(0)); 607 frame_access_state()->ClearSPDelta(); 608 break; 609 } 610 case kArchCallJSFunction: { 611 EnsureSpaceForLazyDeopt(); 612 Register func = i.InputRegister(0); 613 if (FLAG_debug_code) { 614 // Check the function's context matches the context argument. 615 __ lw(kScratchReg, FieldMemOperand(func, JSFunction::kContextOffset)); 616 __ Assert(eq, kWrongFunctionContext, cp, Operand(kScratchReg)); 617 } 618 619 __ lw(at, FieldMemOperand(func, JSFunction::kCodeEntryOffset)); 620 __ Call(at); 621 RecordCallPosition(instr); 622 frame_access_state()->ClearSPDelta(); 623 break; 624 } 625 case kArchTailCallJSFunctionFromJSFunction: 626 case kArchTailCallJSFunction: { 627 Register func = i.InputRegister(0); 628 if (FLAG_debug_code) { 629 // Check the function's context matches the context argument. 630 __ lw(kScratchReg, FieldMemOperand(func, JSFunction::kContextOffset)); 631 __ Assert(eq, kWrongFunctionContext, cp, Operand(kScratchReg)); 632 } 633 634 int stack_param_delta = i.InputInt32(instr->InputCount() - 1); 635 AssembleDeconstructActivationRecord(stack_param_delta); 636 if (arch_opcode == kArchTailCallJSFunctionFromJSFunction) { 637 AssemblePopArgumentsAdaptorFrame(kJavaScriptCallArgCountRegister, 638 i.TempRegister(0), i.TempRegister(1), 639 i.TempRegister(2)); 640 } 641 __ lw(at, FieldMemOperand(func, JSFunction::kCodeEntryOffset)); 642 __ Jump(at); 643 frame_access_state()->ClearSPDelta(); 644 break; 645 } 646 case kArchPrepareCallCFunction: { 647 int const num_parameters = MiscField::decode(instr->opcode()); 648 __ PrepareCallCFunction(num_parameters, kScratchReg); 649 // Frame alignment requires using FP-relative frame addressing. 650 frame_access_state()->SetFrameAccessToFP(); 651 break; 652 } 653 case kArchPrepareTailCall: 654 AssemblePrepareTailCall(i.InputInt32(instr->InputCount() - 1)); 655 break; 656 case kArchCallCFunction: { 657 int const num_parameters = MiscField::decode(instr->opcode()); 658 if (instr->InputAt(0)->IsImmediate()) { 659 ExternalReference ref = i.InputExternalReference(0); 660 __ CallCFunction(ref, num_parameters); 661 } else { 662 Register func = i.InputRegister(0); 663 __ CallCFunction(func, num_parameters); 664 } 665 frame_access_state()->SetFrameAccessToDefault(); 666 frame_access_state()->ClearSPDelta(); 667 break; 668 } 669 case kArchJmp: 670 AssembleArchJump(i.InputRpo(0)); 671 break; 672 case kArchLookupSwitch: 673 AssembleArchLookupSwitch(instr); 674 break; 675 case kArchTableSwitch: 676 AssembleArchTableSwitch(instr); 677 break; 678 case kArchDebugBreak: 679 __ stop("kArchDebugBreak"); 680 break; 681 case kArchComment: { 682 Address comment_string = i.InputExternalReference(0).address(); 683 __ RecordComment(reinterpret_cast<const char*>(comment_string)); 684 break; 685 } 686 case kArchNop: 687 case kArchThrowTerminator: 688 // don't emit code for nops. 689 break; 690 case kArchDeoptimize: { 691 int deopt_state_id = 692 BuildTranslation(instr, -1, 0, OutputFrameStateCombine::Ignore()); 693 Deoptimizer::BailoutType bailout_type = 694 Deoptimizer::BailoutType(MiscField::decode(instr->opcode())); 695 CodeGenResult result = 696 AssembleDeoptimizerCall(deopt_state_id, bailout_type); 697 if (result != kSuccess) return result; 698 break; 699 } 700 case kArchRet: 701 AssembleReturn(); 702 break; 703 case kArchStackPointer: 704 __ mov(i.OutputRegister(), sp); 705 break; 706 case kArchFramePointer: 707 __ mov(i.OutputRegister(), fp); 708 break; 709 case kArchParentFramePointer: 710 if (frame_access_state()->has_frame()) { 711 __ lw(i.OutputRegister(), MemOperand(fp, 0)); 712 } else { 713 __ mov(i.OutputRegister(), fp); 714 } 715 break; 716 case kArchTruncateDoubleToI: 717 __ TruncateDoubleToI(i.OutputRegister(), i.InputDoubleRegister(0)); 718 break; 719 case kArchStoreWithWriteBarrier: { 720 RecordWriteMode mode = 721 static_cast<RecordWriteMode>(MiscField::decode(instr->opcode())); 722 Register object = i.InputRegister(0); 723 Register index = i.InputRegister(1); 724 Register value = i.InputRegister(2); 725 Register scratch0 = i.TempRegister(0); 726 Register scratch1 = i.TempRegister(1); 727 auto ool = new (zone()) OutOfLineRecordWrite(this, object, index, value, 728 scratch0, scratch1, mode); 729 __ Addu(at, object, index); 730 __ sw(value, MemOperand(at)); 731 __ CheckPageFlag(object, scratch0, 732 MemoryChunk::kPointersFromHereAreInterestingMask, ne, 733 ool->entry()); 734 __ bind(ool->exit()); 735 break; 736 } 737 case kArchStackSlot: { 738 FrameOffset offset = 739 frame_access_state()->GetFrameOffset(i.InputInt32(0)); 740 __ Addu(i.OutputRegister(), offset.from_stack_pointer() ? sp : fp, 741 Operand(offset.offset())); 742 break; 743 } 744 case kIeee754Float64Atan: 745 ASSEMBLE_IEEE754_UNOP(atan); 746 break; 747 case kIeee754Float64Atan2: 748 ASSEMBLE_IEEE754_BINOP(atan2); 749 break; 750 case kIeee754Float64Cos: 751 ASSEMBLE_IEEE754_UNOP(cos); 752 break; 753 case kIeee754Float64Cbrt: 754 ASSEMBLE_IEEE754_UNOP(cbrt); 755 break; 756 case kIeee754Float64Exp: 757 ASSEMBLE_IEEE754_UNOP(exp); 758 break; 759 case kIeee754Float64Expm1: 760 ASSEMBLE_IEEE754_UNOP(expm1); 761 break; 762 case kIeee754Float64Atanh: 763 ASSEMBLE_IEEE754_UNOP(atanh); 764 break; 765 case kIeee754Float64Log: 766 ASSEMBLE_IEEE754_UNOP(log); 767 break; 768 case kIeee754Float64Log1p: 769 ASSEMBLE_IEEE754_UNOP(log1p); 770 break; 771 case kIeee754Float64Log10: 772 ASSEMBLE_IEEE754_UNOP(log10); 773 break; 774 case kIeee754Float64Log2: 775 ASSEMBLE_IEEE754_UNOP(log2); 776 break; 777 case kIeee754Float64Sin: 778 ASSEMBLE_IEEE754_UNOP(sin); 779 break; 780 case kIeee754Float64Tan: 781 ASSEMBLE_IEEE754_UNOP(tan); 782 break; 783 case kMipsAdd: 784 __ Addu(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1)); 785 break; 786 case kMipsAddOvf: 787 // Pseudo-instruction used for overflow/branch. No opcode emitted here. 788 break; 789 case kMipsSub: 790 __ Subu(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1)); 791 break; 792 case kMipsSubOvf: 793 // Pseudo-instruction used for overflow/branch. No opcode emitted here. 794 break; 795 case kMipsMul: 796 __ Mul(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1)); 797 break; 798 case kMipsMulHigh: 799 __ Mulh(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1)); 800 break; 801 case kMipsMulHighU: 802 __ Mulhu(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1)); 803 break; 804 case kMipsDiv: 805 __ Div(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1)); 806 if (IsMipsArchVariant(kMips32r6)) { 807 __ selnez(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1)); 808 } else { 809 __ Movz(i.OutputRegister(), i.InputRegister(1), i.InputRegister(1)); 810 } 811 break; 812 case kMipsDivU: 813 __ Divu(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1)); 814 if (IsMipsArchVariant(kMips32r6)) { 815 __ selnez(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1)); 816 } else { 817 __ Movz(i.OutputRegister(), i.InputRegister(1), i.InputRegister(1)); 818 } 819 break; 820 case kMipsMod: 821 __ Mod(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1)); 822 break; 823 case kMipsModU: 824 __ Modu(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1)); 825 break; 826 case kMipsAnd: 827 __ And(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1)); 828 break; 829 case kMipsOr: 830 __ Or(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1)); 831 break; 832 case kMipsNor: 833 if (instr->InputAt(1)->IsRegister()) { 834 __ Nor(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1)); 835 } else { 836 DCHECK(i.InputOperand(1).immediate() == 0); 837 __ Nor(i.OutputRegister(), i.InputRegister(0), zero_reg); 838 } 839 break; 840 case kMipsXor: 841 __ Xor(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1)); 842 break; 843 case kMipsClz: 844 __ Clz(i.OutputRegister(), i.InputRegister(0)); 845 break; 846 case kMipsCtz: { 847 Register reg1 = kScratchReg; 848 Register reg2 = kScratchReg2; 849 Label skip_for_zero; 850 Label end; 851 // Branch if the operand is zero 852 __ Branch(&skip_for_zero, eq, i.InputRegister(0), Operand(zero_reg)); 853 // Find the number of bits before the last bit set to 1. 854 __ Subu(reg2, zero_reg, i.InputRegister(0)); 855 __ And(reg2, reg2, i.InputRegister(0)); 856 __ clz(reg2, reg2); 857 // Get the number of bits after the last bit set to 1. 858 __ li(reg1, 0x1F); 859 __ Subu(i.OutputRegister(), reg1, reg2); 860 __ Branch(&end); 861 __ bind(&skip_for_zero); 862 // If the operand is zero, return word length as the result. 863 __ li(i.OutputRegister(), 0x20); 864 __ bind(&end); 865 } break; 866 case kMipsPopcnt: { 867 Register reg1 = kScratchReg; 868 Register reg2 = kScratchReg2; 869 uint32_t m1 = 0x55555555; 870 uint32_t m2 = 0x33333333; 871 uint32_t m4 = 0x0f0f0f0f; 872 uint32_t m8 = 0x00ff00ff; 873 uint32_t m16 = 0x0000ffff; 874 875 // Put count of ones in every 2 bits into those 2 bits. 876 __ li(at, m1); 877 __ srl(reg1, i.InputRegister(0), 1); 878 __ And(reg2, i.InputRegister(0), at); 879 __ And(reg1, reg1, at); 880 __ addu(reg1, reg1, reg2); 881 882 // Put count of ones in every 4 bits into those 4 bits. 883 __ li(at, m2); 884 __ srl(reg2, reg1, 2); 885 __ And(reg2, reg2, at); 886 __ And(reg1, reg1, at); 887 __ addu(reg1, reg1, reg2); 888 889 // Put count of ones in every 8 bits into those 8 bits. 890 __ li(at, m4); 891 __ srl(reg2, reg1, 4); 892 __ And(reg2, reg2, at); 893 __ And(reg1, reg1, at); 894 __ addu(reg1, reg1, reg2); 895 896 // Put count of ones in every 16 bits into those 16 bits. 897 __ li(at, m8); 898 __ srl(reg2, reg1, 8); 899 __ And(reg2, reg2, at); 900 __ And(reg1, reg1, at); 901 __ addu(reg1, reg1, reg2); 902 903 // Calculate total number of ones. 904 __ li(at, m16); 905 __ srl(reg2, reg1, 16); 906 __ And(reg2, reg2, at); 907 __ And(reg1, reg1, at); 908 __ addu(i.OutputRegister(), reg1, reg2); 909 } break; 910 case kMipsShl: 911 if (instr->InputAt(1)->IsRegister()) { 912 __ sllv(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1)); 913 } else { 914 int32_t imm = i.InputOperand(1).immediate(); 915 __ sll(i.OutputRegister(), i.InputRegister(0), imm); 916 } 917 break; 918 case kMipsShr: 919 if (instr->InputAt(1)->IsRegister()) { 920 __ srlv(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1)); 921 } else { 922 int32_t imm = i.InputOperand(1).immediate(); 923 __ srl(i.OutputRegister(), i.InputRegister(0), imm); 924 } 925 break; 926 case kMipsSar: 927 if (instr->InputAt(1)->IsRegister()) { 928 __ srav(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1)); 929 } else { 930 int32_t imm = i.InputOperand(1).immediate(); 931 __ sra(i.OutputRegister(), i.InputRegister(0), imm); 932 } 933 break; 934 case kMipsShlPair: { 935 if (instr->InputAt(2)->IsRegister()) { 936 __ ShlPair(i.OutputRegister(0), i.OutputRegister(1), i.InputRegister(0), 937 i.InputRegister(1), i.InputRegister(2)); 938 } else { 939 uint32_t imm = i.InputOperand(2).immediate(); 940 __ ShlPair(i.OutputRegister(0), i.OutputRegister(1), i.InputRegister(0), 941 i.InputRegister(1), imm); 942 } 943 } break; 944 case kMipsShrPair: { 945 if (instr->InputAt(2)->IsRegister()) { 946 __ ShrPair(i.OutputRegister(0), i.OutputRegister(1), i.InputRegister(0), 947 i.InputRegister(1), i.InputRegister(2)); 948 } else { 949 uint32_t imm = i.InputOperand(2).immediate(); 950 __ ShrPair(i.OutputRegister(0), i.OutputRegister(1), i.InputRegister(0), 951 i.InputRegister(1), imm); 952 } 953 } break; 954 case kMipsSarPair: { 955 if (instr->InputAt(2)->IsRegister()) { 956 __ SarPair(i.OutputRegister(0), i.OutputRegister(1), i.InputRegister(0), 957 i.InputRegister(1), i.InputRegister(2)); 958 } else { 959 uint32_t imm = i.InputOperand(2).immediate(); 960 __ SarPair(i.OutputRegister(0), i.OutputRegister(1), i.InputRegister(0), 961 i.InputRegister(1), imm); 962 } 963 } break; 964 case kMipsExt: 965 __ Ext(i.OutputRegister(), i.InputRegister(0), i.InputInt8(1), 966 i.InputInt8(2)); 967 break; 968 case kMipsIns: 969 if (instr->InputAt(1)->IsImmediate() && i.InputInt8(1) == 0) { 970 __ Ins(i.OutputRegister(), zero_reg, i.InputInt8(1), i.InputInt8(2)); 971 } else { 972 __ Ins(i.OutputRegister(), i.InputRegister(0), i.InputInt8(1), 973 i.InputInt8(2)); 974 } 975 break; 976 case kMipsRor: 977 __ Ror(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1)); 978 break; 979 case kMipsTst: 980 // Pseudo-instruction used for tst/branch. No opcode emitted here. 981 break; 982 case kMipsCmp: 983 // Pseudo-instruction used for cmp/branch. No opcode emitted here. 984 break; 985 case kMipsMov: 986 // TODO(plind): Should we combine mov/li like this, or use separate instr? 987 // - Also see x64 ASSEMBLE_BINOP & RegisterOrOperandType 988 if (HasRegisterInput(instr, 0)) { 989 __ mov(i.OutputRegister(), i.InputRegister(0)); 990 } else { 991 __ li(i.OutputRegister(), i.InputOperand(0)); 992 } 993 break; 994 case kMipsLsa: 995 DCHECK(instr->InputAt(2)->IsImmediate()); 996 __ Lsa(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1), 997 i.InputInt8(2)); 998 break; 999 case kMipsCmpS: 1000 // Psuedo-instruction used for FP cmp/branch. No opcode emitted here. 1001 break; 1002 case kMipsAddS: 1003 // TODO(plind): add special case: combine mult & add. 1004 __ add_s(i.OutputDoubleRegister(), i.InputDoubleRegister(0), 1005 i.InputDoubleRegister(1)); 1006 break; 1007 case kMipsSubS: 1008 __ sub_s(i.OutputDoubleRegister(), i.InputDoubleRegister(0), 1009 i.InputDoubleRegister(1)); 1010 break; 1011 case kMipsSubPreserveNanS: 1012 __ SubNanPreservePayloadAndSign_s(i.OutputDoubleRegister(), 1013 i.InputDoubleRegister(0), 1014 i.InputDoubleRegister(1)); 1015 break; 1016 case kMipsMulS: 1017 // TODO(plind): add special case: right op is -1.0, see arm port. 1018 __ mul_s(i.OutputDoubleRegister(), i.InputDoubleRegister(0), 1019 i.InputDoubleRegister(1)); 1020 break; 1021 case kMipsDivS: 1022 __ div_s(i.OutputDoubleRegister(), i.InputDoubleRegister(0), 1023 i.InputDoubleRegister(1)); 1024 break; 1025 case kMipsModS: { 1026 // TODO(bmeurer): We should really get rid of this special instruction, 1027 // and generate a CallAddress instruction instead. 1028 FrameScope scope(masm(), StackFrame::MANUAL); 1029 __ PrepareCallCFunction(0, 2, kScratchReg); 1030 __ MovToFloatParameters(i.InputDoubleRegister(0), 1031 i.InputDoubleRegister(1)); 1032 // TODO(balazs.kilvady): implement mod_two_floats_operation(isolate()) 1033 __ CallCFunction(ExternalReference::mod_two_doubles_operation(isolate()), 1034 0, 2); 1035 // Move the result in the double result register. 1036 __ MovFromFloatResult(i.OutputSingleRegister()); 1037 break; 1038 } 1039 case kMipsAbsS: 1040 __ abs_s(i.OutputSingleRegister(), i.InputSingleRegister(0)); 1041 break; 1042 case kMipsSqrtS: { 1043 __ sqrt_s(i.OutputDoubleRegister(), i.InputDoubleRegister(0)); 1044 break; 1045 } 1046 case kMipsMaxS: 1047 __ max_s(i.OutputDoubleRegister(), i.InputDoubleRegister(0), 1048 i.InputDoubleRegister(1)); 1049 break; 1050 case kMipsMinS: 1051 __ min_s(i.OutputDoubleRegister(), i.InputDoubleRegister(0), 1052 i.InputDoubleRegister(1)); 1053 break; 1054 case kMipsCmpD: 1055 // Psuedo-instruction used for FP cmp/branch. No opcode emitted here. 1056 break; 1057 case kMipsAddPair: 1058 __ AddPair(i.OutputRegister(0), i.OutputRegister(1), i.InputRegister(0), 1059 i.InputRegister(1), i.InputRegister(2), i.InputRegister(3)); 1060 break; 1061 case kMipsSubPair: 1062 __ SubPair(i.OutputRegister(0), i.OutputRegister(1), i.InputRegister(0), 1063 i.InputRegister(1), i.InputRegister(2), i.InputRegister(3)); 1064 break; 1065 case kMipsMulPair: { 1066 __ Mulu(i.OutputRegister(1), i.OutputRegister(0), i.InputRegister(0), 1067 i.InputRegister(2)); 1068 __ mul(kScratchReg, i.InputRegister(0), i.InputRegister(3)); 1069 __ mul(kScratchReg2, i.InputRegister(1), i.InputRegister(2)); 1070 __ Addu(i.OutputRegister(1), i.OutputRegister(1), kScratchReg); 1071 __ Addu(i.OutputRegister(1), i.OutputRegister(1), kScratchReg2); 1072 } break; 1073 case kMipsAddD: 1074 // TODO(plind): add special case: combine mult & add. 1075 __ add_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0), 1076 i.InputDoubleRegister(1)); 1077 break; 1078 case kMipsSubD: 1079 __ sub_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0), 1080 i.InputDoubleRegister(1)); 1081 break; 1082 case kMipsSubPreserveNanD: 1083 __ SubNanPreservePayloadAndSign_d(i.OutputDoubleRegister(), 1084 i.InputDoubleRegister(0), 1085 i.InputDoubleRegister(1)); 1086 break; 1087 case kMipsMulD: 1088 // TODO(plind): add special case: right op is -1.0, see arm port. 1089 __ mul_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0), 1090 i.InputDoubleRegister(1)); 1091 break; 1092 case kMipsDivD: 1093 __ div_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0), 1094 i.InputDoubleRegister(1)); 1095 break; 1096 case kMipsModD: { 1097 // TODO(bmeurer): We should really get rid of this special instruction, 1098 // and generate a CallAddress instruction instead. 1099 FrameScope scope(masm(), StackFrame::MANUAL); 1100 __ PrepareCallCFunction(0, 2, kScratchReg); 1101 __ MovToFloatParameters(i.InputDoubleRegister(0), 1102 i.InputDoubleRegister(1)); 1103 __ CallCFunction(ExternalReference::mod_two_doubles_operation(isolate()), 1104 0, 2); 1105 // Move the result in the double result register. 1106 __ MovFromFloatResult(i.OutputDoubleRegister()); 1107 break; 1108 } 1109 case kMipsAbsD: 1110 __ abs_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0)); 1111 break; 1112 case kMipsSqrtD: { 1113 __ sqrt_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0)); 1114 break; 1115 } 1116 case kMipsMaxD: 1117 __ max_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0), 1118 i.InputDoubleRegister(1)); 1119 break; 1120 case kMipsMinD: 1121 __ min_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0), 1122 i.InputDoubleRegister(1)); 1123 break; 1124 case kMipsFloat64RoundDown: { 1125 ASSEMBLE_ROUND_DOUBLE_TO_DOUBLE(floor); 1126 break; 1127 } 1128 case kMipsFloat32RoundDown: { 1129 ASSEMBLE_ROUND_FLOAT_TO_FLOAT(floor); 1130 break; 1131 } 1132 case kMipsFloat64RoundTruncate: { 1133 ASSEMBLE_ROUND_DOUBLE_TO_DOUBLE(trunc); 1134 break; 1135 } 1136 case kMipsFloat32RoundTruncate: { 1137 ASSEMBLE_ROUND_FLOAT_TO_FLOAT(trunc); 1138 break; 1139 } 1140 case kMipsFloat64RoundUp: { 1141 ASSEMBLE_ROUND_DOUBLE_TO_DOUBLE(ceil); 1142 break; 1143 } 1144 case kMipsFloat32RoundUp: { 1145 ASSEMBLE_ROUND_FLOAT_TO_FLOAT(ceil); 1146 break; 1147 } 1148 case kMipsFloat64RoundTiesEven: { 1149 ASSEMBLE_ROUND_DOUBLE_TO_DOUBLE(round); 1150 break; 1151 } 1152 case kMipsFloat32RoundTiesEven: { 1153 ASSEMBLE_ROUND_FLOAT_TO_FLOAT(round); 1154 break; 1155 } 1156 case kMipsFloat64Max: { 1157 // (b < a) ? a : b 1158 if (IsMipsArchVariant(kMips32r6)) { 1159 __ cmp_d(OLT, i.OutputDoubleRegister(), i.InputDoubleRegister(1), 1160 i.InputDoubleRegister(0)); 1161 __ sel_d(i.OutputDoubleRegister(), i.InputDoubleRegister(1), 1162 i.InputDoubleRegister(0)); 1163 } else { 1164 __ c_d(OLT, i.InputDoubleRegister(0), i.InputDoubleRegister(1)); 1165 // Left operand is result, passthrough if false. 1166 __ movt_d(i.OutputDoubleRegister(), i.InputDoubleRegister(1)); 1167 } 1168 break; 1169 } 1170 case kMipsFloat64Min: { 1171 // (a < b) ? a : b 1172 if (IsMipsArchVariant(kMips32r6)) { 1173 __ cmp_d(OLT, i.OutputDoubleRegister(), i.InputDoubleRegister(0), 1174 i.InputDoubleRegister(1)); 1175 __ sel_d(i.OutputDoubleRegister(), i.InputDoubleRegister(1), 1176 i.InputDoubleRegister(0)); 1177 } else { 1178 __ c_d(OLT, i.InputDoubleRegister(1), i.InputDoubleRegister(0)); 1179 // Right operand is result, passthrough if false. 1180 __ movt_d(i.OutputDoubleRegister(), i.InputDoubleRegister(1)); 1181 } 1182 break; 1183 } 1184 case kMipsFloat32Max: { 1185 // (b < a) ? a : b 1186 if (IsMipsArchVariant(kMips32r6)) { 1187 __ cmp_s(OLT, i.OutputDoubleRegister(), i.InputDoubleRegister(1), 1188 i.InputDoubleRegister(0)); 1189 __ sel_s(i.OutputDoubleRegister(), i.InputDoubleRegister(1), 1190 i.InputDoubleRegister(0)); 1191 } else { 1192 __ c_s(OLT, i.InputDoubleRegister(0), i.InputDoubleRegister(1)); 1193 // Left operand is result, passthrough if false. 1194 __ movt_s(i.OutputDoubleRegister(), i.InputDoubleRegister(1)); 1195 } 1196 break; 1197 } 1198 case kMipsFloat32Min: { 1199 // (a < b) ? a : b 1200 if (IsMipsArchVariant(kMips32r6)) { 1201 __ cmp_s(OLT, i.OutputDoubleRegister(), i.InputDoubleRegister(0), 1202 i.InputDoubleRegister(1)); 1203 __ sel_s(i.OutputDoubleRegister(), i.InputDoubleRegister(1), 1204 i.InputDoubleRegister(0)); 1205 } else { 1206 __ c_s(OLT, i.InputDoubleRegister(1), i.InputDoubleRegister(0)); 1207 // Right operand is result, passthrough if false. 1208 __ movt_s(i.OutputDoubleRegister(), i.InputDoubleRegister(1)); 1209 } 1210 break; 1211 } 1212 case kMipsCvtSD: { 1213 __ cvt_s_d(i.OutputSingleRegister(), i.InputDoubleRegister(0)); 1214 break; 1215 } 1216 case kMipsCvtDS: { 1217 __ cvt_d_s(i.OutputDoubleRegister(), i.InputSingleRegister(0)); 1218 break; 1219 } 1220 case kMipsCvtDW: { 1221 FPURegister scratch = kScratchDoubleReg; 1222 __ mtc1(i.InputRegister(0), scratch); 1223 __ cvt_d_w(i.OutputDoubleRegister(), scratch); 1224 break; 1225 } 1226 case kMipsCvtSW: { 1227 FPURegister scratch = kScratchDoubleReg; 1228 __ mtc1(i.InputRegister(0), scratch); 1229 __ cvt_s_w(i.OutputDoubleRegister(), scratch); 1230 break; 1231 } 1232 case kMipsCvtSUw: { 1233 FPURegister scratch = kScratchDoubleReg; 1234 __ Cvt_d_uw(i.OutputDoubleRegister(), i.InputRegister(0), scratch); 1235 __ cvt_s_d(i.OutputDoubleRegister(), i.OutputDoubleRegister()); 1236 break; 1237 } 1238 case kMipsCvtDUw: { 1239 FPURegister scratch = kScratchDoubleReg; 1240 __ Cvt_d_uw(i.OutputDoubleRegister(), i.InputRegister(0), scratch); 1241 break; 1242 } 1243 case kMipsFloorWD: { 1244 FPURegister scratch = kScratchDoubleReg; 1245 __ floor_w_d(scratch, i.InputDoubleRegister(0)); 1246 __ mfc1(i.OutputRegister(), scratch); 1247 break; 1248 } 1249 case kMipsCeilWD: { 1250 FPURegister scratch = kScratchDoubleReg; 1251 __ ceil_w_d(scratch, i.InputDoubleRegister(0)); 1252 __ mfc1(i.OutputRegister(), scratch); 1253 break; 1254 } 1255 case kMipsRoundWD: { 1256 FPURegister scratch = kScratchDoubleReg; 1257 __ round_w_d(scratch, i.InputDoubleRegister(0)); 1258 __ mfc1(i.OutputRegister(), scratch); 1259 break; 1260 } 1261 case kMipsTruncWD: { 1262 FPURegister scratch = kScratchDoubleReg; 1263 // Other arches use round to zero here, so we follow. 1264 __ trunc_w_d(scratch, i.InputDoubleRegister(0)); 1265 __ mfc1(i.OutputRegister(), scratch); 1266 break; 1267 } 1268 case kMipsFloorWS: { 1269 FPURegister scratch = kScratchDoubleReg; 1270 __ floor_w_s(scratch, i.InputDoubleRegister(0)); 1271 __ mfc1(i.OutputRegister(), scratch); 1272 break; 1273 } 1274 case kMipsCeilWS: { 1275 FPURegister scratch = kScratchDoubleReg; 1276 __ ceil_w_s(scratch, i.InputDoubleRegister(0)); 1277 __ mfc1(i.OutputRegister(), scratch); 1278 break; 1279 } 1280 case kMipsRoundWS: { 1281 FPURegister scratch = kScratchDoubleReg; 1282 __ round_w_s(scratch, i.InputDoubleRegister(0)); 1283 __ mfc1(i.OutputRegister(), scratch); 1284 break; 1285 } 1286 case kMipsTruncWS: { 1287 FPURegister scratch = kScratchDoubleReg; 1288 __ trunc_w_s(scratch, i.InputDoubleRegister(0)); 1289 __ mfc1(i.OutputRegister(), scratch); 1290 break; 1291 } 1292 case kMipsTruncUwD: { 1293 FPURegister scratch = kScratchDoubleReg; 1294 // TODO(plind): Fix wrong param order of Trunc_uw_d() macro-asm function. 1295 __ Trunc_uw_d(i.InputDoubleRegister(0), i.OutputRegister(), scratch); 1296 break; 1297 } 1298 case kMipsTruncUwS: { 1299 FPURegister scratch = kScratchDoubleReg; 1300 // TODO(plind): Fix wrong param order of Trunc_uw_s() macro-asm function. 1301 __ Trunc_uw_s(i.InputDoubleRegister(0), i.OutputRegister(), scratch); 1302 break; 1303 } 1304 case kMipsFloat64ExtractLowWord32: 1305 __ FmoveLow(i.OutputRegister(), i.InputDoubleRegister(0)); 1306 break; 1307 case kMipsFloat64ExtractHighWord32: 1308 __ FmoveHigh(i.OutputRegister(), i.InputDoubleRegister(0)); 1309 break; 1310 case kMipsFloat64InsertLowWord32: 1311 __ FmoveLow(i.OutputDoubleRegister(), i.InputRegister(1)); 1312 break; 1313 case kMipsFloat64InsertHighWord32: 1314 __ FmoveHigh(i.OutputDoubleRegister(), i.InputRegister(1)); 1315 break; 1316 case kMipsFloat64SilenceNaN: { 1317 FPURegister value = i.InputDoubleRegister(0); 1318 FPURegister result = i.OutputDoubleRegister(); 1319 Register scratch0 = i.TempRegister(0); 1320 Label is_nan, not_nan; 1321 __ BranchF(NULL, &is_nan, eq, value, value); 1322 __ Branch(¬_nan); 1323 __ bind(&is_nan); 1324 __ LoadRoot(scratch0, Heap::kNanValueRootIndex); 1325 __ ldc1(result, FieldMemOperand(scratch0, HeapNumber::kValueOffset)); 1326 __ bind(¬_nan); 1327 break; 1328 } 1329 1330 // ... more basic instructions ... 1331 1332 case kMipsLbu: 1333 __ lbu(i.OutputRegister(), i.MemoryOperand()); 1334 break; 1335 case kMipsLb: 1336 __ lb(i.OutputRegister(), i.MemoryOperand()); 1337 break; 1338 case kMipsSb: 1339 __ sb(i.InputRegister(2), i.MemoryOperand()); 1340 break; 1341 case kMipsLhu: 1342 __ lhu(i.OutputRegister(), i.MemoryOperand()); 1343 break; 1344 case kMipsLh: 1345 __ lh(i.OutputRegister(), i.MemoryOperand()); 1346 break; 1347 case kMipsSh: 1348 __ sh(i.InputRegister(2), i.MemoryOperand()); 1349 break; 1350 case kMipsLw: 1351 __ lw(i.OutputRegister(), i.MemoryOperand()); 1352 break; 1353 case kMipsSw: 1354 __ sw(i.InputRegister(2), i.MemoryOperand()); 1355 break; 1356 case kMipsLwc1: { 1357 __ lwc1(i.OutputSingleRegister(), i.MemoryOperand()); 1358 break; 1359 } 1360 case kMipsSwc1: { 1361 size_t index = 0; 1362 MemOperand operand = i.MemoryOperand(&index); 1363 __ swc1(i.InputSingleRegister(index), operand); 1364 break; 1365 } 1366 case kMipsLdc1: 1367 __ ldc1(i.OutputDoubleRegister(), i.MemoryOperand()); 1368 break; 1369 case kMipsSdc1: 1370 __ sdc1(i.InputDoubleRegister(2), i.MemoryOperand()); 1371 break; 1372 case kMipsPush: 1373 if (instr->InputAt(0)->IsFPRegister()) { 1374 __ sdc1(i.InputDoubleRegister(0), MemOperand(sp, -kDoubleSize)); 1375 __ Subu(sp, sp, Operand(kDoubleSize)); 1376 frame_access_state()->IncreaseSPDelta(kDoubleSize / kPointerSize); 1377 } else { 1378 __ Push(i.InputRegister(0)); 1379 frame_access_state()->IncreaseSPDelta(1); 1380 } 1381 break; 1382 case kMipsStackClaim: { 1383 __ Subu(sp, sp, Operand(i.InputInt32(0))); 1384 frame_access_state()->IncreaseSPDelta(i.InputInt32(0) / kPointerSize); 1385 break; 1386 } 1387 case kMipsStoreToStackSlot: { 1388 if (instr->InputAt(0)->IsFPRegister()) { 1389 LocationOperand* op = LocationOperand::cast(instr->InputAt(0)); 1390 if (op->representation() == MachineRepresentation::kFloat64) { 1391 __ sdc1(i.InputDoubleRegister(0), MemOperand(sp, i.InputInt32(1))); 1392 } else { 1393 DCHECK_EQ(MachineRepresentation::kFloat32, op->representation()); 1394 __ swc1(i.InputSingleRegister(0), MemOperand(sp, i.InputInt32(1))); 1395 } 1396 } else { 1397 __ sw(i.InputRegister(0), MemOperand(sp, i.InputInt32(1))); 1398 } 1399 break; 1400 } 1401 case kCheckedLoadInt8: 1402 ASSEMBLE_CHECKED_LOAD_INTEGER(lb); 1403 break; 1404 case kCheckedLoadUint8: 1405 ASSEMBLE_CHECKED_LOAD_INTEGER(lbu); 1406 break; 1407 case kCheckedLoadInt16: 1408 ASSEMBLE_CHECKED_LOAD_INTEGER(lh); 1409 break; 1410 case kCheckedLoadUint16: 1411 ASSEMBLE_CHECKED_LOAD_INTEGER(lhu); 1412 break; 1413 case kCheckedLoadWord32: 1414 ASSEMBLE_CHECKED_LOAD_INTEGER(lw); 1415 break; 1416 case kCheckedLoadFloat32: 1417 ASSEMBLE_CHECKED_LOAD_FLOAT(Single, lwc1); 1418 break; 1419 case kCheckedLoadFloat64: 1420 ASSEMBLE_CHECKED_LOAD_FLOAT(Double, ldc1); 1421 break; 1422 case kCheckedStoreWord8: 1423 ASSEMBLE_CHECKED_STORE_INTEGER(sb); 1424 break; 1425 case kCheckedStoreWord16: 1426 ASSEMBLE_CHECKED_STORE_INTEGER(sh); 1427 break; 1428 case kCheckedStoreWord32: 1429 ASSEMBLE_CHECKED_STORE_INTEGER(sw); 1430 break; 1431 case kCheckedStoreFloat32: 1432 ASSEMBLE_CHECKED_STORE_FLOAT(Single, swc1); 1433 break; 1434 case kCheckedStoreFloat64: 1435 ASSEMBLE_CHECKED_STORE_FLOAT(Double, sdc1); 1436 break; 1437 case kCheckedLoadWord64: 1438 case kCheckedStoreWord64: 1439 UNREACHABLE(); // currently unsupported checked int64 load/store. 1440 break; 1441 case kAtomicLoadInt8: 1442 ASSEMBLE_ATOMIC_LOAD_INTEGER(lb); 1443 break; 1444 case kAtomicLoadUint8: 1445 ASSEMBLE_ATOMIC_LOAD_INTEGER(lbu); 1446 break; 1447 case kAtomicLoadInt16: 1448 ASSEMBLE_ATOMIC_LOAD_INTEGER(lh); 1449 break; 1450 case kAtomicLoadUint16: 1451 ASSEMBLE_ATOMIC_LOAD_INTEGER(lhu); 1452 break; 1453 case kAtomicLoadWord32: 1454 ASSEMBLE_ATOMIC_LOAD_INTEGER(lw); 1455 break; 1456 case kAtomicStoreWord8: 1457 ASSEMBLE_ATOMIC_STORE_INTEGER(sb); 1458 break; 1459 case kAtomicStoreWord16: 1460 ASSEMBLE_ATOMIC_STORE_INTEGER(sh); 1461 break; 1462 case kAtomicStoreWord32: 1463 ASSEMBLE_ATOMIC_STORE_INTEGER(sw); 1464 break; 1465 } 1466 return kSuccess; 1467 } // NOLINT(readability/fn_size) 1468 1469 1470 #define UNSUPPORTED_COND(opcode, condition) \ 1471 OFStream out(stdout); \ 1472 out << "Unsupported " << #opcode << " condition: \"" << condition << "\""; \ 1473 UNIMPLEMENTED(); 1474 1475 static bool convertCondition(FlagsCondition condition, Condition& cc) { 1476 switch (condition) { 1477 case kEqual: 1478 cc = eq; 1479 return true; 1480 case kNotEqual: 1481 cc = ne; 1482 return true; 1483 case kUnsignedLessThan: 1484 cc = lt; 1485 return true; 1486 case kUnsignedGreaterThanOrEqual: 1487 cc = uge; 1488 return true; 1489 case kUnsignedLessThanOrEqual: 1490 cc = le; 1491 return true; 1492 case kUnsignedGreaterThan: 1493 cc = ugt; 1494 return true; 1495 default: 1496 break; 1497 } 1498 return false; 1499 } 1500 1501 1502 // Assembles branches after an instruction. 1503 void CodeGenerator::AssembleArchBranch(Instruction* instr, BranchInfo* branch) { 1504 MipsOperandConverter i(this, instr); 1505 Label* tlabel = branch->true_label; 1506 Label* flabel = branch->false_label; 1507 Condition cc = kNoCondition; 1508 // MIPS does not have condition code flags, so compare and branch are 1509 // implemented differently than on the other arch's. The compare operations 1510 // emit mips pseudo-instructions, which are handled here by branch 1511 // instructions that do the actual comparison. Essential that the input 1512 // registers to compare pseudo-op are not modified before this branch op, as 1513 // they are tested here. 1514 1515 if (instr->arch_opcode() == kMipsTst) { 1516 cc = FlagsConditionToConditionTst(branch->condition); 1517 __ And(at, i.InputRegister(0), i.InputOperand(1)); 1518 __ Branch(tlabel, cc, at, Operand(zero_reg)); 1519 } else if (instr->arch_opcode() == kMipsAddOvf) { 1520 switch (branch->condition) { 1521 case kOverflow: 1522 __ AddBranchOvf(i.OutputRegister(), i.InputRegister(0), 1523 i.InputOperand(1), tlabel, flabel); 1524 break; 1525 case kNotOverflow: 1526 __ AddBranchOvf(i.OutputRegister(), i.InputRegister(0), 1527 i.InputOperand(1), flabel, tlabel); 1528 break; 1529 default: 1530 UNSUPPORTED_COND(kMipsAddOvf, branch->condition); 1531 break; 1532 } 1533 } else if (instr->arch_opcode() == kMipsSubOvf) { 1534 switch (branch->condition) { 1535 case kOverflow: 1536 __ SubBranchOvf(i.OutputRegister(), i.InputRegister(0), 1537 i.InputOperand(1), tlabel, flabel); 1538 break; 1539 case kNotOverflow: 1540 __ SubBranchOvf(i.OutputRegister(), i.InputRegister(0), 1541 i.InputOperand(1), flabel, tlabel); 1542 break; 1543 default: 1544 UNSUPPORTED_COND(kMipsAddOvf, branch->condition); 1545 break; 1546 } 1547 } else if (instr->arch_opcode() == kMipsCmp) { 1548 cc = FlagsConditionToConditionCmp(branch->condition); 1549 __ Branch(tlabel, cc, i.InputRegister(0), i.InputOperand(1)); 1550 } else if (instr->arch_opcode() == kMipsCmpS) { 1551 if (!convertCondition(branch->condition, cc)) { 1552 UNSUPPORTED_COND(kMips64CmpS, branch->condition); 1553 } 1554 FPURegister left = i.InputOrZeroSingleRegister(0); 1555 FPURegister right = i.InputOrZeroSingleRegister(1); 1556 if ((left.is(kDoubleRegZero) || right.is(kDoubleRegZero)) && 1557 !__ IsDoubleZeroRegSet()) { 1558 __ Move(kDoubleRegZero, 0.0); 1559 } 1560 __ BranchF32(tlabel, nullptr, cc, left, right); 1561 } else if (instr->arch_opcode() == kMipsCmpD) { 1562 if (!convertCondition(branch->condition, cc)) { 1563 UNSUPPORTED_COND(kMips64CmpD, branch->condition); 1564 } 1565 FPURegister left = i.InputOrZeroDoubleRegister(0); 1566 FPURegister right = i.InputOrZeroDoubleRegister(1); 1567 if ((left.is(kDoubleRegZero) || right.is(kDoubleRegZero)) && 1568 !__ IsDoubleZeroRegSet()) { 1569 __ Move(kDoubleRegZero, 0.0); 1570 } 1571 __ BranchF64(tlabel, nullptr, cc, left, right); 1572 } else { 1573 PrintF("AssembleArchBranch Unimplemented arch_opcode: %d\n", 1574 instr->arch_opcode()); 1575 UNIMPLEMENTED(); 1576 } 1577 if (!branch->fallthru) __ Branch(flabel); // no fallthru to flabel. 1578 } 1579 1580 1581 void CodeGenerator::AssembleArchJump(RpoNumber target) { 1582 if (!IsNextInAssemblyOrder(target)) __ Branch(GetLabel(target)); 1583 } 1584 1585 1586 // Assembles boolean materializations after an instruction. 1587 void CodeGenerator::AssembleArchBoolean(Instruction* instr, 1588 FlagsCondition condition) { 1589 MipsOperandConverter i(this, instr); 1590 Label done; 1591 1592 // Materialize a full 32-bit 1 or 0 value. The result register is always the 1593 // last output of the instruction. 1594 Label false_value; 1595 DCHECK_NE(0u, instr->OutputCount()); 1596 Register result = i.OutputRegister(instr->OutputCount() - 1); 1597 Condition cc = kNoCondition; 1598 // MIPS does not have condition code flags, so compare and branch are 1599 // implemented differently than on the other arch's. The compare operations 1600 // emit mips psuedo-instructions, which are checked and handled here. 1601 1602 if (instr->arch_opcode() == kMipsTst) { 1603 cc = FlagsConditionToConditionTst(condition); 1604 __ And(kScratchReg, i.InputRegister(0), i.InputOperand(1)); 1605 __ Sltu(result, zero_reg, kScratchReg); 1606 if (cc == eq) { 1607 // Sltu produces 0 for equality, invert the result. 1608 __ xori(result, result, 1); 1609 } 1610 return; 1611 } else if (instr->arch_opcode() == kMipsAddOvf || 1612 instr->arch_opcode() == kMipsSubOvf) { 1613 Label flabel, tlabel; 1614 switch (instr->arch_opcode()) { 1615 case kMipsAddOvf: 1616 __ AddBranchNoOvf(i.OutputRegister(), i.InputRegister(0), 1617 i.InputOperand(1), &flabel); 1618 1619 break; 1620 case kMipsSubOvf: 1621 __ SubBranchNoOvf(i.OutputRegister(), i.InputRegister(0), 1622 i.InputOperand(1), &flabel); 1623 break; 1624 default: 1625 UNREACHABLE(); 1626 break; 1627 } 1628 __ li(result, 1); 1629 __ Branch(&tlabel); 1630 __ bind(&flabel); 1631 __ li(result, 0); 1632 __ bind(&tlabel); 1633 } else if (instr->arch_opcode() == kMipsCmp) { 1634 cc = FlagsConditionToConditionCmp(condition); 1635 switch (cc) { 1636 case eq: 1637 case ne: { 1638 Register left = i.InputRegister(0); 1639 Operand right = i.InputOperand(1); 1640 Register select; 1641 if (instr->InputAt(1)->IsImmediate() && right.immediate() == 0) { 1642 // Pass left operand if right is zero. 1643 select = left; 1644 } else { 1645 __ Subu(kScratchReg, left, right); 1646 select = kScratchReg; 1647 } 1648 __ Sltu(result, zero_reg, select); 1649 if (cc == eq) { 1650 // Sltu produces 0 for equality, invert the result. 1651 __ xori(result, result, 1); 1652 } 1653 } break; 1654 case lt: 1655 case ge: { 1656 Register left = i.InputRegister(0); 1657 Operand right = i.InputOperand(1); 1658 __ Slt(result, left, right); 1659 if (cc == ge) { 1660 __ xori(result, result, 1); 1661 } 1662 } break; 1663 case gt: 1664 case le: { 1665 Register left = i.InputRegister(1); 1666 Operand right = i.InputOperand(0); 1667 __ Slt(result, left, right); 1668 if (cc == le) { 1669 __ xori(result, result, 1); 1670 } 1671 } break; 1672 case lo: 1673 case hs: { 1674 Register left = i.InputRegister(0); 1675 Operand right = i.InputOperand(1); 1676 __ Sltu(result, left, right); 1677 if (cc == hs) { 1678 __ xori(result, result, 1); 1679 } 1680 } break; 1681 case hi: 1682 case ls: { 1683 Register left = i.InputRegister(1); 1684 Operand right = i.InputOperand(0); 1685 __ Sltu(result, left, right); 1686 if (cc == ls) { 1687 __ xori(result, result, 1); 1688 } 1689 } break; 1690 default: 1691 UNREACHABLE(); 1692 } 1693 return; 1694 } else if (instr->arch_opcode() == kMipsCmpD || 1695 instr->arch_opcode() == kMipsCmpS) { 1696 FPURegister left = i.InputOrZeroDoubleRegister(0); 1697 FPURegister right = i.InputOrZeroDoubleRegister(1); 1698 if ((left.is(kDoubleRegZero) || right.is(kDoubleRegZero)) && 1699 !__ IsDoubleZeroRegSet()) { 1700 __ Move(kDoubleRegZero, 0.0); 1701 } 1702 bool predicate; 1703 FPUCondition cc = FlagsConditionToConditionCmpFPU(predicate, condition); 1704 if (!IsMipsArchVariant(kMips32r6)) { 1705 __ li(result, Operand(1)); 1706 if (instr->arch_opcode() == kMipsCmpD) { 1707 __ c(cc, D, left, right); 1708 } else { 1709 DCHECK(instr->arch_opcode() == kMipsCmpS); 1710 __ c(cc, S, left, right); 1711 } 1712 if (predicate) { 1713 __ Movf(result, zero_reg); 1714 } else { 1715 __ Movt(result, zero_reg); 1716 } 1717 } else { 1718 if (instr->arch_opcode() == kMipsCmpD) { 1719 __ cmp(cc, L, kDoubleCompareReg, left, right); 1720 } else { 1721 DCHECK(instr->arch_opcode() == kMipsCmpS); 1722 __ cmp(cc, W, kDoubleCompareReg, left, right); 1723 } 1724 __ mfc1(result, kDoubleCompareReg); 1725 __ andi(result, result, 1); // Cmp returns all 1's/0's, use only LSB. 1726 if (!predicate) // Toggle result for not equal. 1727 __ xori(result, result, 1); 1728 } 1729 return; 1730 } else { 1731 PrintF("AssembleArchBranch Unimplemented arch_opcode is : %d\n", 1732 instr->arch_opcode()); 1733 TRACE_UNIMPL(); 1734 UNIMPLEMENTED(); 1735 } 1736 } 1737 1738 1739 void CodeGenerator::AssembleArchLookupSwitch(Instruction* instr) { 1740 MipsOperandConverter i(this, instr); 1741 Register input = i.InputRegister(0); 1742 for (size_t index = 2; index < instr->InputCount(); index += 2) { 1743 __ li(at, Operand(i.InputInt32(index + 0))); 1744 __ beq(input, at, GetLabel(i.InputRpo(index + 1))); 1745 } 1746 __ nop(); // Branch delay slot of the last beq. 1747 AssembleArchJump(i.InputRpo(1)); 1748 } 1749 1750 1751 void CodeGenerator::AssembleArchTableSwitch(Instruction* instr) { 1752 MipsOperandConverter i(this, instr); 1753 Register input = i.InputRegister(0); 1754 size_t const case_count = instr->InputCount() - 2; 1755 __ Branch(GetLabel(i.InputRpo(1)), hs, input, Operand(case_count)); 1756 __ GenerateSwitchTable(input, case_count, [&i, this](size_t index) { 1757 return GetLabel(i.InputRpo(index + 2)); 1758 }); 1759 } 1760 1761 CodeGenerator::CodeGenResult CodeGenerator::AssembleDeoptimizerCall( 1762 int deoptimization_id, Deoptimizer::BailoutType bailout_type) { 1763 Address deopt_entry = Deoptimizer::GetDeoptimizationEntry( 1764 isolate(), deoptimization_id, bailout_type); 1765 if (deopt_entry == nullptr) return kTooManyDeoptimizationBailouts; 1766 __ Call(deopt_entry, RelocInfo::RUNTIME_ENTRY); 1767 return kSuccess; 1768 } 1769 1770 void CodeGenerator::FinishFrame(Frame* frame) { 1771 CallDescriptor* descriptor = linkage()->GetIncomingDescriptor(); 1772 1773 const RegList saves_fpu = descriptor->CalleeSavedFPRegisters(); 1774 if (saves_fpu != 0) { 1775 frame->AlignSavedCalleeRegisterSlots(); 1776 } 1777 1778 if (saves_fpu != 0) { 1779 int count = base::bits::CountPopulation32(saves_fpu); 1780 DCHECK(kNumCalleeSavedFPU == count); 1781 frame->AllocateSavedCalleeRegisterSlots(count * 1782 (kDoubleSize / kPointerSize)); 1783 } 1784 1785 const RegList saves = descriptor->CalleeSavedRegisters(); 1786 if (saves != 0) { 1787 int count = base::bits::CountPopulation32(saves); 1788 DCHECK(kNumCalleeSaved == count + 1); 1789 frame->AllocateSavedCalleeRegisterSlots(count); 1790 } 1791 } 1792 1793 void CodeGenerator::AssembleConstructFrame() { 1794 CallDescriptor* descriptor = linkage()->GetIncomingDescriptor(); 1795 if (frame_access_state()->has_frame()) { 1796 if (descriptor->IsCFunctionCall()) { 1797 __ Push(ra, fp); 1798 __ mov(fp, sp); 1799 } else if (descriptor->IsJSFunctionCall()) { 1800 __ Prologue(this->info()->GeneratePreagedPrologue()); 1801 } else { 1802 __ StubPrologue(info()->GetOutputStackFrameType()); 1803 } 1804 } 1805 1806 int shrink_slots = frame()->GetSpillSlotCount(); 1807 1808 if (info()->is_osr()) { 1809 // TurboFan OSR-compiled functions cannot be entered directly. 1810 __ Abort(kShouldNotDirectlyEnterOsrFunction); 1811 1812 // Unoptimized code jumps directly to this entrypoint while the unoptimized 1813 // frame is still on the stack. Optimized code uses OSR values directly from 1814 // the unoptimized frame. Thus, all that needs to be done is to allocate the 1815 // remaining stack slots. 1816 if (FLAG_code_comments) __ RecordComment("-- OSR entrypoint --"); 1817 osr_pc_offset_ = __ pc_offset(); 1818 shrink_slots -= OsrHelper(info()).UnoptimizedFrameSlots(); 1819 } 1820 1821 const RegList saves_fpu = descriptor->CalleeSavedFPRegisters(); 1822 if (shrink_slots > 0) { 1823 __ Subu(sp, sp, Operand(shrink_slots * kPointerSize)); 1824 } 1825 1826 // Save callee-saved FPU registers. 1827 if (saves_fpu != 0) { 1828 __ MultiPushFPU(saves_fpu); 1829 } 1830 1831 const RegList saves = descriptor->CalleeSavedRegisters(); 1832 if (saves != 0) { 1833 // Save callee-saved registers. 1834 __ MultiPush(saves); 1835 DCHECK(kNumCalleeSaved == base::bits::CountPopulation32(saves) + 1); 1836 } 1837 } 1838 1839 1840 void CodeGenerator::AssembleReturn() { 1841 CallDescriptor* descriptor = linkage()->GetIncomingDescriptor(); 1842 int pop_count = static_cast<int>(descriptor->StackParameterCount()); 1843 1844 // Restore GP registers. 1845 const RegList saves = descriptor->CalleeSavedRegisters(); 1846 if (saves != 0) { 1847 __ MultiPop(saves); 1848 } 1849 1850 // Restore FPU registers. 1851 const RegList saves_fpu = descriptor->CalleeSavedFPRegisters(); 1852 if (saves_fpu != 0) { 1853 __ MultiPopFPU(saves_fpu); 1854 } 1855 1856 if (descriptor->IsCFunctionCall()) { 1857 AssembleDeconstructFrame(); 1858 } else if (frame_access_state()->has_frame()) { 1859 // Canonicalize JSFunction return sites for now. 1860 if (return_label_.is_bound()) { 1861 __ Branch(&return_label_); 1862 return; 1863 } else { 1864 __ bind(&return_label_); 1865 AssembleDeconstructFrame(); 1866 } 1867 } 1868 if (pop_count != 0) { 1869 __ DropAndRet(pop_count); 1870 } else { 1871 __ Ret(); 1872 } 1873 } 1874 1875 1876 void CodeGenerator::AssembleMove(InstructionOperand* source, 1877 InstructionOperand* destination) { 1878 MipsOperandConverter g(this, nullptr); 1879 // Dispatch on the source and destination operand kinds. Not all 1880 // combinations are possible. 1881 if (source->IsRegister()) { 1882 DCHECK(destination->IsRegister() || destination->IsStackSlot()); 1883 Register src = g.ToRegister(source); 1884 if (destination->IsRegister()) { 1885 __ mov(g.ToRegister(destination), src); 1886 } else { 1887 __ sw(src, g.ToMemOperand(destination)); 1888 } 1889 } else if (source->IsStackSlot()) { 1890 DCHECK(destination->IsRegister() || destination->IsStackSlot()); 1891 MemOperand src = g.ToMemOperand(source); 1892 if (destination->IsRegister()) { 1893 __ lw(g.ToRegister(destination), src); 1894 } else { 1895 Register temp = kScratchReg; 1896 __ lw(temp, src); 1897 __ sw(temp, g.ToMemOperand(destination)); 1898 } 1899 } else if (source->IsConstant()) { 1900 Constant src = g.ToConstant(source); 1901 if (destination->IsRegister() || destination->IsStackSlot()) { 1902 Register dst = 1903 destination->IsRegister() ? g.ToRegister(destination) : kScratchReg; 1904 switch (src.type()) { 1905 case Constant::kInt32: 1906 if (src.rmode() == RelocInfo::WASM_MEMORY_REFERENCE || 1907 src.rmode() == RelocInfo::WASM_GLOBAL_REFERENCE || 1908 src.rmode() == RelocInfo::WASM_MEMORY_SIZE_REFERENCE) { 1909 __ li(dst, Operand(src.ToInt32(), src.rmode())); 1910 } else { 1911 __ li(dst, Operand(src.ToInt32())); 1912 } 1913 break; 1914 case Constant::kFloat32: 1915 __ li(dst, isolate()->factory()->NewNumber(src.ToFloat32(), TENURED)); 1916 break; 1917 case Constant::kInt64: 1918 UNREACHABLE(); 1919 break; 1920 case Constant::kFloat64: 1921 __ li(dst, isolate()->factory()->NewNumber(src.ToFloat64(), TENURED)); 1922 break; 1923 case Constant::kExternalReference: 1924 __ li(dst, Operand(src.ToExternalReference())); 1925 break; 1926 case Constant::kHeapObject: { 1927 Handle<HeapObject> src_object = src.ToHeapObject(); 1928 Heap::RootListIndex index; 1929 int slot; 1930 if (IsMaterializableFromFrame(src_object, &slot)) { 1931 __ lw(dst, g.SlotToMemOperand(slot)); 1932 } else if (IsMaterializableFromRoot(src_object, &index)) { 1933 __ LoadRoot(dst, index); 1934 } else { 1935 __ li(dst, src_object); 1936 } 1937 break; 1938 } 1939 case Constant::kRpoNumber: 1940 UNREACHABLE(); // TODO(titzer): loading RPO numbers on mips. 1941 break; 1942 } 1943 if (destination->IsStackSlot()) __ sw(dst, g.ToMemOperand(destination)); 1944 } else if (src.type() == Constant::kFloat32) { 1945 if (destination->IsFPStackSlot()) { 1946 MemOperand dst = g.ToMemOperand(destination); 1947 __ li(at, Operand(bit_cast<int32_t>(src.ToFloat32()))); 1948 __ sw(at, dst); 1949 } else { 1950 FloatRegister dst = g.ToSingleRegister(destination); 1951 __ Move(dst, src.ToFloat32()); 1952 } 1953 } else { 1954 DCHECK_EQ(Constant::kFloat64, src.type()); 1955 DoubleRegister dst = destination->IsFPRegister() 1956 ? g.ToDoubleRegister(destination) 1957 : kScratchDoubleReg; 1958 __ Move(dst, src.ToFloat64()); 1959 if (destination->IsFPStackSlot()) { 1960 __ sdc1(dst, g.ToMemOperand(destination)); 1961 } 1962 } 1963 } else if (source->IsFPRegister()) { 1964 FPURegister src = g.ToDoubleRegister(source); 1965 if (destination->IsFPRegister()) { 1966 FPURegister dst = g.ToDoubleRegister(destination); 1967 __ Move(dst, src); 1968 } else { 1969 DCHECK(destination->IsFPStackSlot()); 1970 __ sdc1(src, g.ToMemOperand(destination)); 1971 } 1972 } else if (source->IsFPStackSlot()) { 1973 DCHECK(destination->IsFPRegister() || destination->IsFPStackSlot()); 1974 MemOperand src = g.ToMemOperand(source); 1975 if (destination->IsFPRegister()) { 1976 LocationOperand* op = LocationOperand::cast(source); 1977 if (op->representation() == MachineRepresentation::kFloat64) { 1978 __ ldc1(g.ToDoubleRegister(destination), src); 1979 } else { 1980 DCHECK_EQ(MachineRepresentation::kFloat32, op->representation()); 1981 __ lwc1(g.ToDoubleRegister(destination), src); 1982 } 1983 } else { 1984 FPURegister temp = kScratchDoubleReg; 1985 __ ldc1(temp, src); 1986 __ sdc1(temp, g.ToMemOperand(destination)); 1987 } 1988 } else { 1989 UNREACHABLE(); 1990 } 1991 } 1992 1993 1994 void CodeGenerator::AssembleSwap(InstructionOperand* source, 1995 InstructionOperand* destination) { 1996 MipsOperandConverter g(this, nullptr); 1997 // Dispatch on the source and destination operand kinds. Not all 1998 // combinations are possible. 1999 if (source->IsRegister()) { 2000 // Register-register. 2001 Register temp = kScratchReg; 2002 Register src = g.ToRegister(source); 2003 if (destination->IsRegister()) { 2004 Register dst = g.ToRegister(destination); 2005 __ Move(temp, src); 2006 __ Move(src, dst); 2007 __ Move(dst, temp); 2008 } else { 2009 DCHECK(destination->IsStackSlot()); 2010 MemOperand dst = g.ToMemOperand(destination); 2011 __ mov(temp, src); 2012 __ lw(src, dst); 2013 __ sw(temp, dst); 2014 } 2015 } else if (source->IsStackSlot()) { 2016 DCHECK(destination->IsStackSlot()); 2017 Register temp_0 = kScratchReg; 2018 Register temp_1 = kCompareReg; 2019 MemOperand src = g.ToMemOperand(source); 2020 MemOperand dst = g.ToMemOperand(destination); 2021 __ lw(temp_0, src); 2022 __ lw(temp_1, dst); 2023 __ sw(temp_0, dst); 2024 __ sw(temp_1, src); 2025 } else if (source->IsFPRegister()) { 2026 FPURegister temp = kScratchDoubleReg; 2027 FPURegister src = g.ToDoubleRegister(source); 2028 if (destination->IsFPRegister()) { 2029 FPURegister dst = g.ToDoubleRegister(destination); 2030 __ Move(temp, src); 2031 __ Move(src, dst); 2032 __ Move(dst, temp); 2033 } else { 2034 DCHECK(destination->IsFPStackSlot()); 2035 MemOperand dst = g.ToMemOperand(destination); 2036 __ Move(temp, src); 2037 __ ldc1(src, dst); 2038 __ sdc1(temp, dst); 2039 } 2040 } else if (source->IsFPStackSlot()) { 2041 DCHECK(destination->IsFPStackSlot()); 2042 Register temp_0 = kScratchReg; 2043 FPURegister temp_1 = kScratchDoubleReg; 2044 MemOperand src0 = g.ToMemOperand(source); 2045 MemOperand src1(src0.rm(), src0.offset() + kIntSize); 2046 MemOperand dst0 = g.ToMemOperand(destination); 2047 MemOperand dst1(dst0.rm(), dst0.offset() + kIntSize); 2048 __ ldc1(temp_1, dst0); // Save destination in temp_1. 2049 __ lw(temp_0, src0); // Then use temp_0 to copy source to destination. 2050 __ sw(temp_0, dst0); 2051 __ lw(temp_0, src1); 2052 __ sw(temp_0, dst1); 2053 __ sdc1(temp_1, src0); 2054 } else { 2055 // No other combinations are possible. 2056 UNREACHABLE(); 2057 } 2058 } 2059 2060 2061 void CodeGenerator::AssembleJumpTable(Label** targets, size_t target_count) { 2062 // On 32-bit MIPS we emit the jump tables inline. 2063 UNREACHABLE(); 2064 } 2065 2066 2067 void CodeGenerator::EnsureSpaceForLazyDeopt() { 2068 if (!info()->ShouldEnsureSpaceForLazyDeopt()) { 2069 return; 2070 } 2071 2072 int space_needed = Deoptimizer::patch_size(); 2073 // Ensure that we have enough space after the previous lazy-bailout 2074 // instruction for patching the code here. 2075 int current_pc = masm()->pc_offset(); 2076 if (current_pc < last_lazy_deopt_pc_ + space_needed) { 2077 // Block tramoline pool emission for duration of padding. 2078 v8::internal::Assembler::BlockTrampolinePoolScope block_trampoline_pool( 2079 masm()); 2080 int padding_size = last_lazy_deopt_pc_ + space_needed - current_pc; 2081 DCHECK_EQ(0, padding_size % v8::internal::Assembler::kInstrSize); 2082 while (padding_size > 0) { 2083 __ nop(); 2084 padding_size -= v8::internal::Assembler::kInstrSize; 2085 } 2086 } 2087 } 2088 2089 #undef __ 2090 2091 } // namespace compiler 2092 } // namespace internal 2093 } // namespace v8 2094