code-generator-mips.cc 132 KB
Newer Older
1 2 3 4
// Copyright 2014 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

5
#include "src/assembler-inl.h"
6
#include "src/callable.h"
7
#include "src/compiler/code-generator-impl.h"
8
#include "src/compiler/code-generator.h"
9 10
#include "src/compiler/gap-resolver.h"
#include "src/compiler/node-matchers.h"
11
#include "src/compiler/osr.h"
12
#include "src/heap/heap-inl.h"
13
#include "src/mips/macro-assembler-mips.h"
14
#include "src/optimized-compilation-info.h"
15 16 17 18 19

namespace v8 {
namespace internal {
namespace compiler {

20
#define __ tasm()->
21 22 23 24 25 26 27 28 29 30 31 32

// TODO(plind): consider renaming these macros.
#define TRACE_MSG(msg)                                                      \
  PrintF("code_gen: \'%s\' in function %s at line %d\n", msg, __FUNCTION__, \
         __LINE__)

#define TRACE_UNIMPL()                                                       \
  PrintF("UNIMPLEMENTED code_generator_mips: %s at line %d\n", __FUNCTION__, \
         __LINE__)


// Adds Mips-specific methods to convert InstructionOperands.
33
class MipsOperandConverter final : public InstructionOperandConverter {
34 35 36 37
 public:
  MipsOperandConverter(CodeGenerator* gen, Instruction* instr)
      : InstructionOperandConverter(gen, instr) {}

38
  FloatRegister OutputSingleRegister(size_t index = 0) {
39 40 41
    return ToSingleRegister(instr_->OutputAt(index));
  }

42
  FloatRegister InputSingleRegister(size_t index) {
43 44 45 46 47 48 49 50 51
    return ToSingleRegister(instr_->InputAt(index));
  }

  FloatRegister ToSingleRegister(InstructionOperand* op) {
    // Single (Float) and Double register namespace is same on MIPS,
    // both are typedefs of FPURegister.
    return ToDoubleRegister(op);
  }

52 53
  Register InputOrZeroRegister(size_t index) {
    if (instr_->InputAt(index)->IsImmediate()) {
54
      DCHECK_EQ(0, InputInt32(index));
55 56 57 58 59
      return zero_reg;
    }
    return InputRegister(index);
  }

60 61 62 63 64 65 66 67 68 69 70 71
  DoubleRegister InputOrZeroDoubleRegister(size_t index) {
    if (instr_->InputAt(index)->IsImmediate()) return kDoubleRegZero;

    return InputDoubleRegister(index);
  }

  DoubleRegister InputOrZeroSingleRegister(size_t index) {
    if (instr_->InputAt(index)->IsImmediate()) return kDoubleRegZero;

    return InputSingleRegister(index);
  }

72
  Operand InputImmediate(size_t index) {
73 74 75 76 77
    Constant constant = ToConstant(instr_->InputAt(index));
    switch (constant.type()) {
      case Constant::kInt32:
        return Operand(constant.ToInt32());
      case Constant::kFloat32:
78
        return Operand::EmbeddedNumber(constant.ToFloat32());
79
      case Constant::kFloat64:
80
        return Operand::EmbeddedNumber(constant.ToFloat64().value());
81 82 83 84 85 86
      case Constant::kInt64:
      case Constant::kExternalReference:
      case Constant::kHeapObject:
        // TODO(plind): Maybe we should handle ExtRef & HeapObj here?
        //    maybe not done on arm due to const pool ??
        break;
87 88 89
      case Constant::kRpoNumber:
        UNREACHABLE();  // TODO(titzer): RPO immediates on mips?
        break;
90 91 92 93
    }
    UNREACHABLE();
  }

94
  Operand InputOperand(size_t index) {
95 96 97 98 99 100 101
    InstructionOperand* op = instr_->InputAt(index);
    if (op->IsRegister()) {
      return Operand(ToRegister(op));
    }
    return InputImmediate(index);
  }

102 103
  MemOperand MemoryOperand(size_t* first_index) {
    const size_t index = *first_index;
104 105 106 107 108 109 110 111 112 113 114 115 116
    switch (AddressingModeField::decode(instr_->opcode())) {
      case kMode_None:
        break;
      case kMode_MRI:
        *first_index += 2;
        return MemOperand(InputRegister(index + 0), InputInt32(index + 1));
      case kMode_MRR:
        // TODO(plind): r6 address mode, to be implemented ...
        UNREACHABLE();
    }
    UNREACHABLE();
  }

117
  MemOperand MemoryOperand(size_t index = 0) { return MemoryOperand(&index); }
118 119

  MemOperand ToMemOperand(InstructionOperand* op) const {
120
    DCHECK_NOT_NULL(op);
121
    DCHECK(op->IsStackSlot() || op->IsFPStackSlot());
122 123 124 125 126
    return SlotToMemOperand(AllocatedOperand::cast(op)->index());
  }

  MemOperand SlotToMemOperand(int slot) const {
    FrameOffset offset = frame_access_state()->GetFrameOffset(slot);
127 128 129 130 131
    return MemOperand(offset.from_stack_pointer() ? sp : fp, offset.offset());
  }
};


132
static inline bool HasRegisterInput(Instruction* instr, size_t index) {
133 134 135 136
  return instr->InputAt(index)->IsRegister();
}


137 138
namespace {

139

140 141 142 143 144 145 146 147 148 149 150
class OutOfLineRecordWrite final : public OutOfLineCode {
 public:
  OutOfLineRecordWrite(CodeGenerator* gen, Register object, Register index,
                       Register value, Register scratch0, Register scratch1,
                       RecordWriteMode mode)
      : OutOfLineCode(gen),
        object_(object),
        index_(index),
        value_(value),
        scratch0_(scratch0),
        scratch1_(scratch1),
151
        mode_(mode),
152 153
        must_save_lr_(!gen->frame_access_state()->has_frame()),
        zone_(gen->zone()) {}
154

155
  void SaveRegisters(RegList registers) {
156
    DCHECK_LT(0, NumRegs(registers));
157 158 159 160 161 162 163 164 165 166
    RegList regs = 0;
    for (int i = 0; i < Register::kNumRegisters; ++i) {
      if ((registers >> i) & 1u) {
        regs |= Register::from_code(i).bit();
      }
    }
    __ MultiPush(regs | ra.bit());
  }

  void RestoreRegisters(RegList registers) {
167
    DCHECK_LT(0, NumRegs(registers));
168 169 170 171 172 173 174 175 176
    RegList regs = 0;
    for (int i = 0; i < Register::kNumRegisters; ++i) {
      if ((registers >> i) & 1u) {
        regs |= Register::from_code(i).bit();
      }
    }
    __ MultiPop(regs | ra.bit());
  }

177 178 179 180
  void Generate() final {
    if (mode_ > RecordWriteMode::kValueIsPointer) {
      __ JumpIfSmi(value_, exit());
    }
181 182 183
    __ CheckPageFlag(value_, scratch0_,
                     MemoryChunk::kPointersToHereAreInterestingMask, eq,
                     exit());
184
    __ Addu(scratch1_, object_, index_);
185 186 187
    RememberedSetAction const remembered_set_action =
        mode_ > RecordWriteMode::kValueIsMap ? EMIT_REMEMBERED_SET
                                             : OMIT_REMEMBERED_SET;
188 189
    SaveFPRegsMode const save_fp_mode =
        frame()->DidAllocateDoubleRegisters() ? kSaveFPRegs : kDontSaveFPRegs;
190
    if (must_save_lr_) {
191 192 193
      // We need to save and restore ra if the frame was elided.
      __ Push(ra);
    }
194 195
    __ CallRecordWriteStub(object_, scratch1_, remembered_set_action,
                           save_fp_mode);
196
    if (must_save_lr_) {
197 198
      __ Pop(ra);
    }
199 200 201 202 203 204 205 206 207
  }

 private:
  Register const object_;
  Register const index_;
  Register const value_;
  Register const scratch0_;
  Register const scratch1_;
  RecordWriteMode const mode_;
208
  bool must_save_lr_;
209
  Zone* zone_;
210 211
};

212
#define CREATE_OOL_CLASS(ool_name, tasm_ool_name, T)                 \
213 214 215 216 217
  class ool_name final : public OutOfLineCode {                      \
   public:                                                           \
    ool_name(CodeGenerator* gen, T dst, T src1, T src2)              \
        : OutOfLineCode(gen), dst_(dst), src1_(src1), src2_(src2) {} \
                                                                     \
218
    void Generate() final { __ tasm_ool_name(dst_, src1_, src2_); }  \
219 220 221 222 223 224 225 226 227 228 229 230 231
                                                                     \
   private:                                                          \
    T const dst_;                                                    \
    T const src1_;                                                   \
    T const src2_;                                                   \
  }

CREATE_OOL_CLASS(OutOfLineFloat32Max, Float32MaxOutOfLine, FPURegister);
CREATE_OOL_CLASS(OutOfLineFloat32Min, Float32MinOutOfLine, FPURegister);
CREATE_OOL_CLASS(OutOfLineFloat64Max, Float64MaxOutOfLine, DoubleRegister);
CREATE_OOL_CLASS(OutOfLineFloat64Min, Float64MinOutOfLine, DoubleRegister);

#undef CREATE_OOL_CLASS
232

233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277
Condition FlagsConditionToConditionCmp(FlagsCondition condition) {
  switch (condition) {
    case kEqual:
      return eq;
    case kNotEqual:
      return ne;
    case kSignedLessThan:
      return lt;
    case kSignedGreaterThanOrEqual:
      return ge;
    case kSignedLessThanOrEqual:
      return le;
    case kSignedGreaterThan:
      return gt;
    case kUnsignedLessThan:
      return lo;
    case kUnsignedGreaterThanOrEqual:
      return hs;
    case kUnsignedLessThanOrEqual:
      return ls;
    case kUnsignedGreaterThan:
      return hi;
    case kUnorderedEqual:
    case kUnorderedNotEqual:
      break;
    default:
      break;
  }
  UNREACHABLE();
}


Condition FlagsConditionToConditionTst(FlagsCondition condition) {
  switch (condition) {
    case kNotEqual:
      return ne;
    case kEqual:
      return eq;
    default:
      break;
  }
  UNREACHABLE();
}


278 279
FPUCondition FlagsConditionToConditionCmpFPU(bool& predicate,
                                             FlagsCondition condition) {
280 281 282 283 284 285 286 287 288 289 290 291
  switch (condition) {
    case kEqual:
      predicate = true;
      return EQ;
    case kNotEqual:
      predicate = false;
      return EQ;
    case kUnsignedLessThan:
      predicate = true;
      return OLT;
    case kUnsignedGreaterThanOrEqual:
      predicate = false;
292
      return OLT;
293 294 295 296 297
    case kUnsignedLessThanOrEqual:
      predicate = true;
      return OLE;
    case kUnsignedGreaterThan:
      predicate = false;
298
      return OLE;
299 300 301 302 303 304 305 306 307 308 309
    case kUnorderedEqual:
    case kUnorderedNotEqual:
      predicate = true;
      break;
    default:
      predicate = true;
      break;
  }
  UNREACHABLE();
}

310 311 312 313 314
#define UNSUPPORTED_COND(opcode, condition)                                  \
  OFStream out(stdout);                                                      \
  out << "Unsupported " << #opcode << " condition: \"" << condition << "\""; \
  UNIMPLEMENTED();

315 316 317 318 319 320 321 322 323 324 325
void EmitWordLoadPoisoningIfNeeded(CodeGenerator* codegen,
                                   InstructionCode opcode, Instruction* instr,
                                   MipsOperandConverter& i) {
  const MemoryAccessMode access_mode =
      static_cast<MemoryAccessMode>(MiscField::decode(opcode));
  if (access_mode == kMemoryAccessPoisoned) {
    Register value = i.OutputRegister();
    codegen->tasm()->And(value, value, kSpeculationPoisonRegister);
  }
}

326 327
}  // namespace

328

329 330 331 332 333 334
#define ASSEMBLE_ATOMIC_LOAD_INTEGER(asm_instr)          \
  do {                                                   \
    __ asm_instr(i.OutputRegister(), i.MemoryOperand()); \
    __ sync();                                           \
  } while (0)

335 336 337 338 339
#define ASSEMBLE_ATOMIC_STORE_INTEGER(asm_instr)               \
  do {                                                         \
    __ sync();                                                 \
    __ asm_instr(i.InputOrZeroRegister(2), i.MemoryOperand()); \
    __ sync();                                                 \
340 341
  } while (0)

342 343 344
#define ASSEMBLE_ATOMIC_BINOP(bin_instr)                                \
  do {                                                                  \
    Label binop;                                                        \
345
    __ Addu(i.TempRegister(0), i.InputRegister(0), i.InputRegister(1)); \
346 347 348 349 350 351 352 353 354 355 356 357 358
    __ sync();                                                          \
    __ bind(&binop);                                                    \
    __ Ll(i.OutputRegister(0), MemOperand(i.TempRegister(0), 0));       \
    __ bin_instr(i.TempRegister(1), i.OutputRegister(0),                \
                 Operand(i.InputRegister(2)));                          \
    __ Sc(i.TempRegister(1), MemOperand(i.TempRegister(0), 0));         \
    __ BranchShort(&binop, eq, i.TempRegister(1), Operand(zero_reg));   \
    __ sync();                                                          \
  } while (0)

#define ASSEMBLE_ATOMIC_BINOP_EXT(sign_extend, size, bin_instr)                \
  do {                                                                         \
    Label binop;                                                               \
359
    __ Addu(i.TempRegister(0), i.InputRegister(0), i.InputRegister(1));        \
360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376
    __ andi(i.TempRegister(3), i.TempRegister(0), 0x3);                        \
    __ Subu(i.TempRegister(0), i.TempRegister(0), Operand(i.TempRegister(3))); \
    __ sll(i.TempRegister(3), i.TempRegister(3), 3);                           \
    __ sync();                                                                 \
    __ bind(&binop);                                                           \
    __ Ll(i.TempRegister(1), MemOperand(i.TempRegister(0), 0));                \
    __ ExtractBits(i.OutputRegister(0), i.TempRegister(1), i.TempRegister(3),  \
                   size, sign_extend);                                         \
    __ bin_instr(i.TempRegister(2), i.OutputRegister(0),                       \
                 Operand(i.InputRegister(2)));                                 \
    __ InsertBits(i.TempRegister(1), i.TempRegister(2), i.TempRegister(3),     \
                  size);                                                       \
    __ Sc(i.TempRegister(1), MemOperand(i.TempRegister(0), 0));                \
    __ BranchShort(&binop, eq, i.TempRegister(1), Operand(zero_reg));          \
    __ sync();                                                                 \
  } while (0)

377 378 379 380 381
#define ASSEMBLE_ATOMIC_EXCHANGE_INTEGER()                               \
  do {                                                                   \
    Label exchange;                                                      \
    __ sync();                                                           \
    __ bind(&exchange);                                                  \
382
    __ Addu(i.TempRegister(0), i.InputRegister(0), i.InputRegister(1));  \
383 384 385 386 387
    __ Ll(i.OutputRegister(0), MemOperand(i.TempRegister(0), 0));        \
    __ mov(i.TempRegister(1), i.InputRegister(2));                       \
    __ Sc(i.TempRegister(1), MemOperand(i.TempRegister(0), 0));          \
    __ BranchShort(&exchange, eq, i.TempRegister(1), Operand(zero_reg)); \
    __ sync();                                                           \
388 389 390 391 392
  } while (0)

#define ASSEMBLE_ATOMIC_EXCHANGE_INTEGER_EXT(sign_extend, size)                \
  do {                                                                         \
    Label exchange;                                                            \
393
    __ Addu(i.TempRegister(0), i.InputRegister(0), i.InputRegister(1));        \
394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412
    __ andi(i.TempRegister(1), i.TempRegister(0), 0x3);                        \
    __ Subu(i.TempRegister(0), i.TempRegister(0), Operand(i.TempRegister(1))); \
    __ sll(i.TempRegister(1), i.TempRegister(1), 3);                           \
    __ sync();                                                                 \
    __ bind(&exchange);                                                        \
    __ Ll(i.TempRegister(2), MemOperand(i.TempRegister(0), 0));                \
    __ ExtractBits(i.OutputRegister(0), i.TempRegister(2), i.TempRegister(1),  \
                   size, sign_extend);                                         \
    __ InsertBits(i.TempRegister(2), i.InputRegister(2), i.TempRegister(1),    \
                  size);                                                       \
    __ Sc(i.TempRegister(2), MemOperand(i.TempRegister(0), 0));                \
    __ BranchShort(&exchange, eq, i.TempRegister(2), Operand(zero_reg));       \
    __ sync();                                                                 \
  } while (0)

#define ASSEMBLE_ATOMIC_COMPARE_EXCHANGE_INTEGER()                      \
  do {                                                                  \
    Label compareExchange;                                              \
    Label exit;                                                         \
413
    __ Addu(i.TempRegister(0), i.InputRegister(0), i.InputRegister(1)); \
414 415 416 417 418
    __ sync();                                                          \
    __ bind(&compareExchange);                                          \
    __ Ll(i.OutputRegister(0), MemOperand(i.TempRegister(0), 0));       \
    __ BranchShort(&exit, ne, i.InputRegister(2),                       \
                   Operand(i.OutputRegister(0)));                       \
419 420 421
    __ mov(i.TempRegister(2), i.InputRegister(3));                      \
    __ Sc(i.TempRegister(2), MemOperand(i.TempRegister(0), 0));         \
    __ BranchShort(&compareExchange, eq, i.TempRegister(2),             \
422 423 424 425 426 427 428 429 430
                   Operand(zero_reg));                                  \
    __ bind(&exit);                                                     \
    __ sync();                                                          \
  } while (0)

#define ASSEMBLE_ATOMIC_COMPARE_EXCHANGE_INTEGER_EXT(sign_extend, size)        \
  do {                                                                         \
    Label compareExchange;                                                     \
    Label exit;                                                                \
431
    __ Addu(i.TempRegister(0), i.InputRegister(0), i.InputRegister(1));        \
432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450
    __ andi(i.TempRegister(1), i.TempRegister(0), 0x3);                        \
    __ Subu(i.TempRegister(0), i.TempRegister(0), Operand(i.TempRegister(1))); \
    __ sll(i.TempRegister(1), i.TempRegister(1), 3);                           \
    __ sync();                                                                 \
    __ bind(&compareExchange);                                                 \
    __ Ll(i.TempRegister(2), MemOperand(i.TempRegister(0), 0));                \
    __ ExtractBits(i.OutputRegister(0), i.TempRegister(2), i.TempRegister(1),  \
                   size, sign_extend);                                         \
    __ BranchShort(&exit, ne, i.InputRegister(2),                              \
                   Operand(i.OutputRegister(0)));                              \
    __ InsertBits(i.TempRegister(2), i.InputRegister(3), i.TempRegister(1),    \
                  size);                                                       \
    __ Sc(i.TempRegister(2), MemOperand(i.TempRegister(0), 0));                \
    __ BranchShort(&compareExchange, eq, i.TempRegister(2),                    \
                   Operand(zero_reg));                                         \
    __ bind(&exit);                                                            \
    __ sync();                                                                 \
  } while (0)

451 452 453 454 455 456 457 458 459
#define ASSEMBLE_IEEE754_BINOP(name)                                        \
  do {                                                                      \
    FrameScope scope(tasm(), StackFrame::MANUAL);                           \
    __ PrepareCallCFunction(0, 2, kScratchReg);                             \
    __ MovToFloatParameters(i.InputDoubleRegister(0),                       \
                            i.InputDoubleRegister(1));                      \
    __ CallCFunction(ExternalReference::ieee754_##name##_function(), 0, 2); \
    /* Move the result in the double result register. */                    \
    __ MovFromFloatResult(i.OutputDoubleRegister());                        \
460 461
  } while (0)

462 463 464 465 466 467 468 469
#define ASSEMBLE_IEEE754_UNOP(name)                                         \
  do {                                                                      \
    FrameScope scope(tasm(), StackFrame::MANUAL);                           \
    __ PrepareCallCFunction(0, 1, kScratchReg);                             \
    __ MovToFloatParameter(i.InputDoubleRegister(0));                       \
    __ CallCFunction(ExternalReference::ieee754_##name##_function(), 0, 1); \
    /* Move the result in the double result register. */                    \
    __ MovFromFloatResult(i.OutputDoubleRegister());                        \
470 471
  } while (0)

472 473 474 475 476
void CodeGenerator::AssembleDeconstructFrame() {
  __ mov(sp, fp);
  __ Pop(ra, fp);
}

477
void CodeGenerator::AssemblePrepareTailCall() {
478
  if (frame_access_state()->has_frame()) {
479 480 481
    __ lw(ra, MemOperand(fp, StandardFrameConstants::kCallerPCOffset));
    __ lw(fp, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
  }
482
  frame_access_state()->SetFrameAccessToSP();
svenpanne's avatar
svenpanne committed
483 484
}

485 486 487 488 489 490 491 492 493 494
void CodeGenerator::AssemblePopArgumentsAdaptorFrame(Register args_reg,
                                                     Register scratch1,
                                                     Register scratch2,
                                                     Register scratch3) {
  DCHECK(!AreAliased(args_reg, scratch1, scratch2, scratch3));
  Label done;

  // Check if current frame is an arguments adaptor frame.
  __ lw(scratch1, MemOperand(fp, StandardFrameConstants::kContextOffset));
  __ Branch(&done, ne, scratch1,
495
            Operand(StackFrame::TypeToMarker(StackFrame::ARGUMENTS_ADAPTOR)));
496 497 498 499 500 501 502 503 504 505 506 507 508

  // Load arguments count from current arguments adaptor frame (note, it
  // does not include receiver).
  Register caller_args_count_reg = scratch1;
  __ lw(caller_args_count_reg,
        MemOperand(fp, ArgumentsAdaptorFrameConstants::kLengthOffset));
  __ SmiUntag(caller_args_count_reg);

  ParameterCount callee_args_count(args_reg);
  __ PrepareForTailCall(callee_args_count, caller_args_count_reg, scratch2,
                        scratch3);
  __ bind(&done);
}
svenpanne's avatar
svenpanne committed
509

510 511
namespace {

512
void AdjustStackPointerForTailCall(TurboAssembler* tasm,
513 514 515 516 517 518 519
                                   FrameAccessState* state,
                                   int new_slot_above_sp,
                                   bool allow_shrinkage = true) {
  int current_sp_offset = state->GetSPToFPSlotCount() +
                          StandardFrameConstants::kFixedSlotCountAboveFp;
  int stack_slot_delta = new_slot_above_sp - current_sp_offset;
  if (stack_slot_delta > 0) {
520
    tasm->Subu(sp, sp, stack_slot_delta * kPointerSize);
521 522
    state->IncreaseSPDelta(stack_slot_delta);
  } else if (allow_shrinkage && stack_slot_delta < 0) {
523
    tasm->Addu(sp, sp, -stack_slot_delta * kPointerSize);
524 525 526 527 528 529 530 531
    state->IncreaseSPDelta(stack_slot_delta);
  }
}

}  // namespace

void CodeGenerator::AssembleTailCallBeforeGap(Instruction* instr,
                                              int first_unused_stack_slot) {
532
  AdjustStackPointerForTailCall(tasm(), frame_access_state(),
533 534 535 536 537
                                first_unused_stack_slot, false);
}

void CodeGenerator::AssembleTailCallAfterGap(Instruction* instr,
                                             int first_unused_stack_slot) {
538
  AdjustStackPointerForTailCall(tasm(), frame_access_state(),
539 540 541
                                first_unused_stack_slot);
}

542 543
// Check that {kJavaScriptCallCodeStartRegister} is correct.
void CodeGenerator::AssembleCodeStartRegisterCheck() {
544
  __ ComputeCodeStartAddress(kScratchReg);
545
  __ Assert(eq, AbortReason::kWrongFunctionCodeStart,
546
            kJavaScriptCallCodeStartRegister, Operand(kScratchReg));
547 548
}

549 550 551
// Check if the code object is marked for deoptimization. If it is, then it
// jumps to the CompileLazyDeoptimizedCode builtin. In order to do this we need
// to:
552
//    1. read from memory the word that contains that bit, which can be found in
553
//       the flags in the referenced {CodeDataContainer} object;
554 555
//    2. test kMarkedForDeoptimizationBit in those flags; and
//    3. if it is not zero then it jumps to the builtin.
556
void CodeGenerator::BailoutIfDeoptimized() {
557
  int offset = Code::kCodeDataContainerOffset - Code::kHeaderSize;
558 559 560 561 562 563
  __ lw(kScratchReg, MemOperand(kJavaScriptCallCodeStartRegister, offset));
  __ lw(kScratchReg,
        FieldMemOperand(kScratchReg,
                        CodeDataContainer::kKindSpecificFlagsOffset));
  __ And(kScratchReg, kScratchReg,
         Operand(1 << Code::kMarkedForDeoptimizationBit));
564 565 566
  // Ensure we're not serializing (otherwise we'd need to use an indirection to
  // access the builtin below).
  DCHECK(!isolate()->ShouldLoadConstantsFromRootList());
567 568
  Handle<Code> code = isolate()->builtins()->builtin_handle(
      Builtins::kCompileLazyDeoptimizedCode);
569
  __ Jump(code, RelocInfo::CODE_TARGET, ne, kScratchReg, Operand(zero_reg));
570 571
}

572
void CodeGenerator::GenerateSpeculationPoisonFromCodeStartRegister() {
573 574 575 576
  // Calculate a mask which has all bits set in the normal case, but has all
  // bits cleared if we are speculatively executing the wrong PC.
  //    difference = (current - expected) | (expected - current)
  //    poison = ~(difference >> (kBitsPerPointer - 1))
577 578
  __ ComputeCodeStartAddress(kScratchReg);
  __ Move(kSpeculationPoisonRegister, kScratchReg);
579 580 581
  __ subu(kSpeculationPoisonRegister, kSpeculationPoisonRegister,
          kJavaScriptCallCodeStartRegister);
  __ subu(kJavaScriptCallCodeStartRegister, kJavaScriptCallCodeStartRegister,
582
          kScratchReg);
583 584 585 586 587 588 589 590
  __ or_(kSpeculationPoisonRegister, kSpeculationPoisonRegister,
         kJavaScriptCallCodeStartRegister);
  __ sra(kSpeculationPoisonRegister, kSpeculationPoisonRegister,
         kBitsPerPointer - 1);
  __ nor(kSpeculationPoisonRegister, kSpeculationPoisonRegister,
         kSpeculationPoisonRegister);
}

591 592 593 594 595 596
void CodeGenerator::AssembleRegisterArgumentPoisoning() {
  __ And(kJSFunctionRegister, kJSFunctionRegister, kSpeculationPoisonRegister);
  __ And(kContextRegister, kContextRegister, kSpeculationPoisonRegister);
  __ And(sp, sp, kSpeculationPoisonRegister);
}

597
// Assembles an instruction after register allocation, producing machine code.
598 599
CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
    Instruction* instr) {
600 601
  MipsOperandConverter i(this, instr);
  InstructionCode opcode = instr->opcode();
602 603
  ArchOpcode arch_opcode = ArchOpcodeField::decode(opcode);
  switch (arch_opcode) {
604 605
    case kArchCallCodeObject: {
      if (instr->InputAt(0)->IsImmediate()) {
606
        __ Call(i.InputCode(0), RelocInfo::CODE_TARGET);
607
      } else {
608 609
        __ Call(kScratchReg, i.InputRegister(0),
                Code::kHeaderSize - kHeapObjectTag);
610
      }
611
      RecordCallPosition(instr);
612
      frame_access_state()->ClearSPDelta();
613 614
      break;
    }
615 616
    case kArchCallWasmFunction: {
      if (instr->InputAt(0)->IsImmediate()) {
617 618
        Address wasm_code =
            static_cast<Address>(i.ToConstant(instr->InputAt(0)).ToInt32());
619 620 621
        __ Call(wasm_code, info()->IsWasm() ? RelocInfo::WASM_CALL
                                            : RelocInfo::JS_TO_WASM_CALL);
      } else {
622
        __ Call(i.InputRegister(0));
623 624 625 626 627
      }
      RecordCallPosition(instr);
      frame_access_state()->ClearSPDelta();
      break;
    }
628
    case kArchTailCallCodeObjectFromJSFunction:
svenpanne's avatar
svenpanne committed
629
    case kArchTailCallCodeObject: {
630 631 632 633 634
      if (arch_opcode == kArchTailCallCodeObjectFromJSFunction) {
        AssemblePopArgumentsAdaptorFrame(kJavaScriptCallArgCountRegister,
                                         i.TempRegister(0), i.TempRegister(1),
                                         i.TempRegister(2));
      }
svenpanne's avatar
svenpanne committed
635
      if (instr->InputAt(0)->IsImmediate()) {
636
        __ Jump(i.InputCode(0), RelocInfo::CODE_TARGET);
svenpanne's avatar
svenpanne committed
637
      } else {
638 639
        __ Jump(kScratchReg, i.InputRegister(0),
                Code::kHeaderSize - kHeapObjectTag);
svenpanne's avatar
svenpanne committed
640
      }
641
      frame_access_state()->ClearSPDelta();
642
      frame_access_state()->SetFrameAccessToDefault();
svenpanne's avatar
svenpanne committed
643 644
      break;
    }
645 646
    case kArchTailCallWasm: {
      if (instr->InputAt(0)->IsImmediate()) {
647 648
        Address wasm_code =
            static_cast<Address>(i.ToConstant(instr->InputAt(0)).ToInt32());
649 650 651
        __ Jump(wasm_code, info()->IsWasm() ? RelocInfo::WASM_CALL
                                            : RelocInfo::JS_TO_WASM_CALL);
      } else {
652
        __ Jump(i.InputRegister(0));
653 654 655 656 657
      }
      frame_access_state()->ClearSPDelta();
      frame_access_state()->SetFrameAccessToDefault();
      break;
    }
658 659 660 661
    case kArchTailCallAddress: {
      CHECK(!instr->InputAt(0)->IsImmediate());
      __ Jump(i.InputRegister(0));
      frame_access_state()->ClearSPDelta();
662
      frame_access_state()->SetFrameAccessToDefault();
663 664
      break;
    }
665 666 667 668 669
    case kArchCallJSFunction: {
      Register func = i.InputRegister(0);
      if (FLAG_debug_code) {
        // Check the function's context matches the context argument.
        __ lw(kScratchReg, FieldMemOperand(func, JSFunction::kContextOffset));
670 671
        __ Assert(eq, AbortReason::kWrongFunctionContext, cp,
                  Operand(kScratchReg));
672
      }
673 674
      static_assert(kJavaScriptCallCodeStartRegister == a2, "ABI mismatch");
      __ lw(a2, FieldMemOperand(func, JSFunction::kCodeOffset));
675 676
      __ Addu(a2, a2, Code::kHeaderSize - kHeapObjectTag);
      __ Call(a2);
677
      RecordCallPosition(instr);
678
      frame_access_state()->ClearSPDelta();
679
      frame_access_state()->SetFrameAccessToDefault();
680
      break;
svenpanne's avatar
svenpanne committed
681
    }
682 683 684
    case kArchPrepareCallCFunction: {
      int const num_parameters = MiscField::decode(instr->opcode());
      __ PrepareCallCFunction(num_parameters, kScratchReg);
685 686
      // Frame alignment requires using FP-relative frame addressing.
      frame_access_state()->SetFrameAccessToFP();
687 688
      break;
    }
689
    case kArchSaveCallerRegisters: {
690 691 692
      fp_mode_ =
          static_cast<SaveFPRegsMode>(MiscField::decode(instr->opcode()));
      DCHECK(fp_mode_ == kDontSaveFPRegs || fp_mode_ == kSaveFPRegs);
693
      // kReturnRegister0 should have been saved before entering the stub.
694
      int bytes = __ PushCallerSaved(fp_mode_, kReturnRegister0);
695 696
      DCHECK_EQ(0, bytes % kPointerSize);
      DCHECK_EQ(0, frame_access_state()->sp_delta());
697 698 699
      frame_access_state()->IncreaseSPDelta(bytes / kPointerSize);
      DCHECK(!caller_registers_saved_);
      caller_registers_saved_ = true;
700 701 702
      break;
    }
    case kArchRestoreCallerRegisters: {
703 704 705
      DCHECK(fp_mode_ ==
             static_cast<SaveFPRegsMode>(MiscField::decode(instr->opcode())));
      DCHECK(fp_mode_ == kDontSaveFPRegs || fp_mode_ == kSaveFPRegs);
706
      // Don't overwrite the returned value.
707
      int bytes = __ PopCallerSaved(fp_mode_, kReturnRegister0);
708
      frame_access_state()->IncreaseSPDelta(-(bytes / kPointerSize));
709
      DCHECK_EQ(0, frame_access_state()->sp_delta());
710 711
      DCHECK(caller_registers_saved_);
      caller_registers_saved_ = false;
712 713
      break;
    }
714
    case kArchPrepareTailCall:
715
      AssemblePrepareTailCall();
716
      break;
717 718 719 720 721 722 723 724 725
    case kArchCallCFunction: {
      int const num_parameters = MiscField::decode(instr->opcode());
      if (instr->InputAt(0)->IsImmediate()) {
        ExternalReference ref = i.InputExternalReference(0);
        __ CallCFunction(ref, num_parameters);
      } else {
        Register func = i.InputRegister(0);
        __ CallCFunction(func, num_parameters);
      }
726
      frame_access_state()->SetFrameAccessToDefault();
727 728 729 730 731
      // Ideally, we should decrement SP delta to match the change of stack
      // pointer in CallCFunction. However, for certain architectures (e.g.
      // ARM), there may be more strict alignment requirement, causing old SP
      // to be saved on the stack. In those cases, we can not calculate the SP
      // delta statically.
732
      frame_access_state()->ClearSPDelta();
733 734
      if (caller_registers_saved_) {
        // Need to re-sync SP delta introduced in kArchSaveCallerRegisters.
735 736 737 738
        // Here, we assume the sequence to be:
        //   kArchSaveCallerRegisters;
        //   kArchCallCFunction;
        //   kArchRestoreCallerRegisters;
739
        int bytes =
740
            __ RequiredStackSizeForCallerSaved(fp_mode_, kReturnRegister0);
741 742
        frame_access_state()->IncreaseSPDelta(bytes / kPointerSize);
      }
743 744
      break;
    }
745
    case kArchJmp:
746
      AssembleArchJump(i.InputRpo(0));
747
      break;
748 749 750 751 752
    case kArchLookupSwitch:
      AssembleArchLookupSwitch(instr);
      break;
    case kArchTableSwitch:
      AssembleArchTableSwitch(instr);
753
      break;
754
    case kArchDebugAbort:
755
      DCHECK(i.InputRegister(0) == a0);
756 757 758 759 760 761 762 763 764 765 766 767
      if (!frame_access_state()->has_frame()) {
        // We don't actually want to generate a pile of code for this, so just
        // claim there is a stack frame, without generating one.
        FrameScope scope(tasm(), StackFrame::NONE);
        __ Call(isolate()->builtins()->builtin_handle(Builtins::kAbortJS),
                RelocInfo::CODE_TARGET);
      } else {
        __ Call(isolate()->builtins()->builtin_handle(Builtins::kAbortJS),
                RelocInfo::CODE_TARGET);
      }
      __ stop("kArchDebugAbort");
      break;
768 769 770
    case kArchDebugBreak:
      __ stop("kArchDebugBreak");
      break;
771 772
    case kArchComment:
      __ RecordComment(reinterpret_cast<const char*>(i.InputInt32(0)));
773
      break;
774
    case kArchNop:
775
    case kArchThrowTerminator:
776 777
      // don't emit code for nops.
      break;
778 779 780
    case kArchDeoptimize: {
      int deopt_state_id =
          BuildTranslation(instr, -1, 0, OutputFrameStateCombine::Ignore());
781 782
      CodeGenResult result =
          AssembleDeoptimizerCall(deopt_state_id, current_source_position_);
783
      if (result != kSuccess) return result;
784 785
      break;
    }
786
    case kArchRet:
787
      AssembleReturn(instr->InputAt(0));
788 789 790 791
      break;
    case kArchStackPointer:
      __ mov(i.OutputRegister(), sp);
      break;
792 793 794
    case kArchFramePointer:
      __ mov(i.OutputRegister(), fp);
      break;
795
    case kArchParentFramePointer:
796
      if (frame_access_state()->has_frame()) {
797 798 799 800 801
        __ lw(i.OutputRegister(), MemOperand(fp, 0));
      } else {
        __ mov(i.OutputRegister(), fp);
      }
      break;
802 803 804
    case kArchRootsPointer:
      __ mov(i.OutputRegister(), kRootRegister);
      break;
805
    case kArchTruncateDoubleToI:
806 807
      __ TruncateDoubleToI(isolate(), zone(), i.OutputRegister(),
                           i.InputDoubleRegister(0));
808
      break;
809 810 811 812 813 814 815 816 817 818
    case kArchStoreWithWriteBarrier: {
      RecordWriteMode mode =
          static_cast<RecordWriteMode>(MiscField::decode(instr->opcode()));
      Register object = i.InputRegister(0);
      Register index = i.InputRegister(1);
      Register value = i.InputRegister(2);
      Register scratch0 = i.TempRegister(0);
      Register scratch1 = i.TempRegister(1);
      auto ool = new (zone()) OutOfLineRecordWrite(this, object, index, value,
                                                   scratch0, scratch1, mode);
819 820
      __ Addu(kScratchReg, object, index);
      __ sw(value, MemOperand(kScratchReg));
821 822 823 824 825 826
      __ CheckPageFlag(object, scratch0,
                       MemoryChunk::kPointersFromHereAreInterestingMask, ne,
                       ool->entry());
      __ bind(ool->exit());
      break;
    }
827 828 829
    case kArchStackSlot: {
      FrameOffset offset =
          frame_access_state()->GetFrameOffset(i.InputInt32(0));
830 831 832 833 834 835 836 837
      Register base_reg = offset.from_stack_pointer() ? sp : fp;
      __ Addu(i.OutputRegister(), base_reg, Operand(offset.offset()));
      int alignment = i.InputInt32(1);
      DCHECK(alignment == 0 || alignment == 4 || alignment == 8 ||
             alignment == 16);
      if (FLAG_debug_code && alignment > 0) {
        // Verify that the output_register is properly aligned
        __ And(kScratchReg, i.OutputRegister(), Operand(kPointerSize - 1));
838
        __ Assert(eq, AbortReason::kAllocationIsNotDoubleAligned, kScratchReg,
839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858
                  Operand(zero_reg));
      }

      if (alignment == 2 * kPointerSize) {
        Label done;
        __ Addu(kScratchReg, base_reg, Operand(offset.offset()));
        __ And(kScratchReg, kScratchReg, Operand(alignment - 1));
        __ BranchShort(&done, eq, kScratchReg, Operand(zero_reg));
        __ Addu(i.OutputRegister(), i.OutputRegister(), kPointerSize);
        __ bind(&done);
      } else if (alignment > 2 * kPointerSize) {
        Label done;
        __ Addu(kScratchReg, base_reg, Operand(offset.offset()));
        __ And(kScratchReg, kScratchReg, Operand(alignment - 1));
        __ BranchShort(&done, eq, kScratchReg, Operand(zero_reg));
        __ li(kScratchReg2, alignment);
        __ Subu(kScratchReg2, kScratchReg2, Operand(kScratchReg));
        __ Addu(i.OutputRegister(), i.OutputRegister(), kScratchReg2);
        __ bind(&done);
      }
859 860
      break;
    }
861
    case kArchWordPoisonOnSpeculation:
862 863 864
      __ And(i.OutputRegister(), i.InputRegister(0),
             kSpeculationPoisonRegister);
      break;
865 866 867 868 869 870 871 872 873 874 875 876
    case kIeee754Float64Acos:
      ASSEMBLE_IEEE754_UNOP(acos);
      break;
    case kIeee754Float64Acosh:
      ASSEMBLE_IEEE754_UNOP(acosh);
      break;
    case kIeee754Float64Asin:
      ASSEMBLE_IEEE754_UNOP(asin);
      break;
    case kIeee754Float64Asinh:
      ASSEMBLE_IEEE754_UNOP(asinh);
      break;
877 878 879
    case kIeee754Float64Atan:
      ASSEMBLE_IEEE754_UNOP(atan);
      break;
880 881 882
    case kIeee754Float64Atanh:
      ASSEMBLE_IEEE754_UNOP(atanh);
      break;
883 884 885
    case kIeee754Float64Atan2:
      ASSEMBLE_IEEE754_BINOP(atan2);
      break;
886 887 888
    case kIeee754Float64Cos:
      ASSEMBLE_IEEE754_UNOP(cos);
      break;
889 890 891
    case kIeee754Float64Cosh:
      ASSEMBLE_IEEE754_UNOP(cosh);
      break;
892 893 894
    case kIeee754Float64Cbrt:
      ASSEMBLE_IEEE754_UNOP(cbrt);
      break;
895 896 897
    case kIeee754Float64Exp:
      ASSEMBLE_IEEE754_UNOP(exp);
      break;
898 899 900
    case kIeee754Float64Expm1:
      ASSEMBLE_IEEE754_UNOP(expm1);
      break;
901 902 903 904 905
    case kIeee754Float64Log:
      ASSEMBLE_IEEE754_UNOP(log);
      break;
    case kIeee754Float64Log1p:
      ASSEMBLE_IEEE754_UNOP(log1p);
906
      break;
907 908 909
    case kIeee754Float64Log10:
      ASSEMBLE_IEEE754_UNOP(log10);
      break;
910 911 912
    case kIeee754Float64Log2:
      ASSEMBLE_IEEE754_UNOP(log2);
      break;
913
    case kIeee754Float64Pow: {
914
      __ Call(BUILTIN_CODE(isolate(), MathPowInternal), RelocInfo::CODE_TARGET);
915 916
      break;
    }
917 918
    case kIeee754Float64Sin:
      ASSEMBLE_IEEE754_UNOP(sin);
919
      break;
920 921 922
    case kIeee754Float64Sinh:
      ASSEMBLE_IEEE754_UNOP(sinh);
      break;
923 924 925
    case kIeee754Float64Tan:
      ASSEMBLE_IEEE754_UNOP(tan);
      break;
926 927 928
    case kIeee754Float64Tanh:
      ASSEMBLE_IEEE754_UNOP(tanh);
      break;
929 930 931 932
    case kMipsAdd:
      __ Addu(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
      break;
    case kMipsAddOvf:
933 934
      __ AddOverflow(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1),
                     kScratchReg);
935 936 937 938 939
      break;
    case kMipsSub:
      __ Subu(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
      break;
    case kMipsSubOvf:
940 941
      __ SubOverflow(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1),
                     kScratchReg);
942 943 944 945
      break;
    case kMipsMul:
      __ Mul(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
      break;
946
    case kMipsMulOvf:
947 948
      __ MulOverflow(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1),
                     kScratchReg);
949
      break;
950 951 952
    case kMipsMulHigh:
      __ Mulh(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
      break;
953 954 955
    case kMipsMulHighU:
      __ Mulhu(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
      break;
956 957
    case kMipsDiv:
      __ Div(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
958
      if (IsMipsArchVariant(kMips32r6)) {
959
        __ selnez(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
960 961 962
      } else {
        __ Movz(i.OutputRegister(), i.InputRegister(1), i.InputRegister(1));
      }
963 964 965
      break;
    case kMipsDivU:
      __ Divu(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
966
      if (IsMipsArchVariant(kMips32r6)) {
967
        __ selnez(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
968 969 970
      } else {
        __ Movz(i.OutputRegister(), i.InputRegister(1), i.InputRegister(1));
      }
971 972 973 974 975 976 977 978 979 980 981 982 983
      break;
    case kMipsMod:
      __ Mod(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
      break;
    case kMipsModU:
      __ Modu(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
      break;
    case kMipsAnd:
      __ And(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
      break;
    case kMipsOr:
      __ Or(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
      break;
984
    case kMipsNor:
985 986 987
      if (instr->InputAt(1)->IsRegister()) {
        __ Nor(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
      } else {
988
        DCHECK_EQ(0, i.InputOperand(1).immediate());
989 990
        __ Nor(i.OutputRegister(), i.InputRegister(0), zero_reg);
      }
991
      break;
992 993 994
    case kMipsXor:
      __ Xor(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
      break;
995 996 997
    case kMipsClz:
      __ Clz(i.OutputRegister(), i.InputRegister(0));
      break;
998
    case kMipsCtz: {
999 1000
      Register src = i.InputRegister(0);
      Register dst = i.OutputRegister();
1001
      __ Ctz(dst, src);
1002 1003
    } break;
    case kMipsPopcnt: {
1004 1005
      Register src = i.InputRegister(0);
      Register dst = i.OutputRegister();
1006
      __ Popcnt(dst, src);
1007
    } break;
1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031
    case kMipsShl:
      if (instr->InputAt(1)->IsRegister()) {
        __ sllv(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
      } else {
        int32_t imm = i.InputOperand(1).immediate();
        __ sll(i.OutputRegister(), i.InputRegister(0), imm);
      }
      break;
    case kMipsShr:
      if (instr->InputAt(1)->IsRegister()) {
        __ srlv(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
      } else {
        int32_t imm = i.InputOperand(1).immediate();
        __ srl(i.OutputRegister(), i.InputRegister(0), imm);
      }
      break;
    case kMipsSar:
      if (instr->InputAt(1)->IsRegister()) {
        __ srav(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
      } else {
        int32_t imm = i.InputOperand(1).immediate();
        __ sra(i.OutputRegister(), i.InputRegister(0), imm);
      }
      break;
1032
    case kMipsShlPair: {
1033 1034
      Register second_output =
          instr->OutputCount() >= 2 ? i.OutputRegister(1) : i.TempRegister(0);
1035
      if (instr->InputAt(2)->IsRegister()) {
1036
        __ ShlPair(i.OutputRegister(0), second_output, i.InputRegister(0),
1037 1038
                   i.InputRegister(1), i.InputRegister(2), kScratchReg,
                   kScratchReg2);
1039 1040
      } else {
        uint32_t imm = i.InputOperand(2).immediate();
1041
        __ ShlPair(i.OutputRegister(0), second_output, i.InputRegister(0),
1042
                   i.InputRegister(1), imm, kScratchReg);
1043 1044 1045
      }
    } break;
    case kMipsShrPair: {
1046 1047
      Register second_output =
          instr->OutputCount() >= 2 ? i.OutputRegister(1) : i.TempRegister(0);
1048
      if (instr->InputAt(2)->IsRegister()) {
1049
        __ ShrPair(i.OutputRegister(0), second_output, i.InputRegister(0),
1050 1051
                   i.InputRegister(1), i.InputRegister(2), kScratchReg,
                   kScratchReg2);
1052 1053
      } else {
        uint32_t imm = i.InputOperand(2).immediate();
1054
        __ ShrPair(i.OutputRegister(0), second_output, i.InputRegister(0),
1055
                   i.InputRegister(1), imm, kScratchReg);
1056 1057 1058
      }
    } break;
    case kMipsSarPair: {
1059 1060
      Register second_output =
          instr->OutputCount() >= 2 ? i.OutputRegister(1) : i.TempRegister(0);
1061
      if (instr->InputAt(2)->IsRegister()) {
1062
        __ SarPair(i.OutputRegister(0), second_output, i.InputRegister(0),
1063 1064
                   i.InputRegister(1), i.InputRegister(2), kScratchReg,
                   kScratchReg2);
1065 1066
      } else {
        uint32_t imm = i.InputOperand(2).immediate();
1067
        __ SarPair(i.OutputRegister(0), second_output, i.InputRegister(0),
1068
                   i.InputRegister(1), imm, kScratchReg);
1069 1070
      }
    } break;
1071 1072 1073 1074
    case kMipsExt:
      __ Ext(i.OutputRegister(), i.InputRegister(0), i.InputInt8(1),
             i.InputInt8(2));
      break;
1075 1076 1077 1078 1079 1080 1081 1082
    case kMipsIns:
      if (instr->InputAt(1)->IsImmediate() && i.InputInt8(1) == 0) {
        __ Ins(i.OutputRegister(), zero_reg, i.InputInt8(1), i.InputInt8(2));
      } else {
        __ Ins(i.OutputRegister(), i.InputRegister(0), i.InputInt8(1),
               i.InputInt8(2));
      }
      break;
1083 1084 1085 1086
    case kMipsRor:
      __ Ror(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
      break;
    case kMipsTst:
1087
      __ And(kScratchReg, i.InputRegister(0), i.InputOperand(1));
1088 1089
      break;
    case kMipsCmp:
1090
      // Pseudo-instruction used for cmp/branch. No opcode emitted here.
1091 1092 1093 1094 1095 1096 1097 1098 1099 1100
      break;
    case kMipsMov:
      // TODO(plind): Should we combine mov/li like this, or use separate instr?
      //    - Also see x64 ASSEMBLE_BINOP & RegisterOrOperandType
      if (HasRegisterInput(instr, 0)) {
        __ mov(i.OutputRegister(), i.InputRegister(0));
      } else {
        __ li(i.OutputRegister(), i.InputOperand(0));
      }
      break;
1101 1102 1103 1104 1105
    case kMipsLsa:
      DCHECK(instr->InputAt(2)->IsImmediate());
      __ Lsa(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1),
             i.InputInt8(2));
      break;
1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119
    case kMipsCmpS: {
      FPURegister left = i.InputOrZeroSingleRegister(0);
      FPURegister right = i.InputOrZeroSingleRegister(1);
      bool predicate;
      FPUCondition cc =
          FlagsConditionToConditionCmpFPU(predicate, instr->flags_condition());

      if ((left == kDoubleRegZero || right == kDoubleRegZero) &&
          !__ IsDoubleZeroRegSet()) {
        __ Move(kDoubleRegZero, 0.0);
      }

      __ CompareF32(cc, left, right);
    } break;
1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140
    case kMipsAddS:
      // TODO(plind): add special case: combine mult & add.
      __ add_s(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
               i.InputDoubleRegister(1));
      break;
    case kMipsSubS:
      __ sub_s(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
               i.InputDoubleRegister(1));
      break;
    case kMipsMulS:
      // TODO(plind): add special case: right op is -1.0, see arm port.
      __ mul_s(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
               i.InputDoubleRegister(1));
      break;
    case kMipsDivS:
      __ div_s(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
               i.InputDoubleRegister(1));
      break;
    case kMipsModS: {
      // TODO(bmeurer): We should really get rid of this special instruction,
      // and generate a CallAddress instruction instead.
1141
      FrameScope scope(tasm(), StackFrame::MANUAL);
1142 1143 1144 1145
      __ PrepareCallCFunction(0, 2, kScratchReg);
      __ MovToFloatParameters(i.InputDoubleRegister(0),
                              i.InputDoubleRegister(1));
      // TODO(balazs.kilvady): implement mod_two_floats_operation(isolate())
1146
      __ CallCFunction(ExternalReference::mod_two_doubles_operation(), 0, 2);
1147 1148 1149 1150
      // Move the result in the double result register.
      __ MovFromFloatResult(i.OutputSingleRegister());
      break;
    }
1151 1152 1153
    case kMipsAbsS:
      __ abs_s(i.OutputSingleRegister(), i.InputSingleRegister(0));
      break;
1154 1155 1156 1157
    case kMipsSqrtS: {
      __ sqrt_s(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
      break;
    }
1158 1159 1160 1161 1162 1163 1164 1165
    case kMipsMaxS:
      __ max_s(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
               i.InputDoubleRegister(1));
      break;
    case kMipsMinS:
      __ min_s(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
               i.InputDoubleRegister(1));
      break;
1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177
    case kMipsCmpD: {
      FPURegister left = i.InputOrZeroDoubleRegister(0);
      FPURegister right = i.InputOrZeroDoubleRegister(1);
      bool predicate;
      FPUCondition cc =
          FlagsConditionToConditionCmpFPU(predicate, instr->flags_condition());
      if ((left == kDoubleRegZero || right == kDoubleRegZero) &&
          !__ IsDoubleZeroRegSet()) {
        __ Move(kDoubleRegZero, 0.0);
      }
      __ CompareF64(cc, left, right);
    } break;
1178 1179
    case kMipsAddPair:
      __ AddPair(i.OutputRegister(0), i.OutputRegister(1), i.InputRegister(0),
1180 1181
                 i.InputRegister(1), i.InputRegister(2), i.InputRegister(3),
                 kScratchReg, kScratchReg2);
1182 1183 1184
      break;
    case kMipsSubPair:
      __ SubPair(i.OutputRegister(0), i.OutputRegister(1), i.InputRegister(0),
1185 1186
                 i.InputRegister(1), i.InputRegister(2), i.InputRegister(3),
                 kScratchReg, kScratchReg2);
1187
      break;
1188
    case kMipsMulPair: {
1189 1190 1191
      __ MulPair(i.OutputRegister(0), i.OutputRegister(1), i.InputRegister(0),
                 i.InputRegister(1), i.InputRegister(2), i.InputRegister(3),
                 kScratchReg, kScratchReg2);
1192
    } break;
1193 1194 1195 1196 1197 1198 1199 1200 1201
    case kMipsAddD:
      // TODO(plind): add special case: combine mult & add.
      __ add_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
               i.InputDoubleRegister(1));
      break;
    case kMipsSubD:
      __ sub_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
               i.InputDoubleRegister(1));
      break;
1202
    case kMipsMaddS:
1203 1204 1205
      __ Madd_s(i.OutputFloatRegister(), i.InputFloatRegister(0),
                i.InputFloatRegister(1), i.InputFloatRegister(2),
                kScratchDoubleReg);
1206 1207
      break;
    case kMipsMaddD:
1208 1209 1210
      __ Madd_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
                i.InputDoubleRegister(1), i.InputDoubleRegister(2),
                kScratchDoubleReg);
1211 1212
      break;
    case kMipsMsubS:
1213 1214 1215
      __ Msub_s(i.OutputFloatRegister(), i.InputFloatRegister(0),
                i.InputFloatRegister(1), i.InputFloatRegister(2),
                kScratchDoubleReg);
1216 1217
      break;
    case kMipsMsubD:
1218 1219 1220
      __ Msub_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
                i.InputDoubleRegister(1), i.InputDoubleRegister(2),
                kScratchDoubleReg);
1221
      break;
1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233
    case kMipsMulD:
      // TODO(plind): add special case: right op is -1.0, see arm port.
      __ mul_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
               i.InputDoubleRegister(1));
      break;
    case kMipsDivD:
      __ div_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
               i.InputDoubleRegister(1));
      break;
    case kMipsModD: {
      // TODO(bmeurer): We should really get rid of this special instruction,
      // and generate a CallAddress instruction instead.
1234
      FrameScope scope(tasm(), StackFrame::MANUAL);
1235 1236 1237
      __ PrepareCallCFunction(0, 2, kScratchReg);
      __ MovToFloatParameters(i.InputDoubleRegister(0),
                              i.InputDoubleRegister(1));
1238
      __ CallCFunction(ExternalReference::mod_two_doubles_operation(), 0, 2);
1239 1240 1241 1242
      // Move the result in the double result register.
      __ MovFromFloatResult(i.OutputDoubleRegister());
      break;
    }
1243 1244 1245
    case kMipsAbsD:
      __ abs_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
      break;
1246
    case kMipsNegS:
1247
      __ Neg_s(i.OutputSingleRegister(), i.InputSingleRegister(0));
1248 1249
      break;
    case kMipsNegD:
1250
      __ Neg_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
1251
      break;
1252 1253 1254 1255
    case kMipsSqrtD: {
      __ sqrt_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
      break;
    }
1256 1257 1258 1259 1260 1261 1262 1263
    case kMipsMaxD:
      __ max_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
               i.InputDoubleRegister(1));
      break;
    case kMipsMinD:
      __ min_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
               i.InputDoubleRegister(1));
      break;
1264
    case kMipsFloat64RoundDown: {
1265
      __ Floor_d_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
1266 1267 1268
      break;
    }
    case kMipsFloat32RoundDown: {
1269
      __ Floor_s_s(i.OutputSingleRegister(), i.InputSingleRegister(0));
1270 1271 1272
      break;
    }
    case kMipsFloat64RoundTruncate: {
1273
      __ Trunc_d_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
1274 1275 1276
      break;
    }
    case kMipsFloat32RoundTruncate: {
1277
      __ Trunc_s_s(i.OutputSingleRegister(), i.InputSingleRegister(0));
1278 1279
      break;
    }
1280
    case kMipsFloat64RoundUp: {
1281
      __ Ceil_d_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
1282 1283 1284
      break;
    }
    case kMipsFloat32RoundUp: {
1285
      __ Ceil_s_s(i.OutputSingleRegister(), i.InputSingleRegister(0));
1286 1287
      break;
    }
1288
    case kMipsFloat64RoundTiesEven: {
1289
      __ Round_d_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
1290 1291 1292
      break;
    }
    case kMipsFloat32RoundTiesEven: {
1293
      __ Round_s_s(i.OutputSingleRegister(), i.InputSingleRegister(0));
1294 1295
      break;
    }
1296
    case kMipsFloat32Max: {
1297 1298 1299
      FPURegister dst = i.OutputSingleRegister();
      FPURegister src1 = i.InputSingleRegister(0);
      FPURegister src2 = i.InputSingleRegister(1);
1300 1301 1302
      auto ool = new (zone()) OutOfLineFloat32Max(this, dst, src1, src2);
      __ Float32Max(dst, src1, src2, ool->entry());
      __ bind(ool->exit());
1303 1304
      break;
    }
1305
    case kMipsFloat64Max: {
1306 1307 1308
      DoubleRegister dst = i.OutputDoubleRegister();
      DoubleRegister src1 = i.InputDoubleRegister(0);
      DoubleRegister src2 = i.InputDoubleRegister(1);
1309 1310 1311
      auto ool = new (zone()) OutOfLineFloat64Max(this, dst, src1, src2);
      __ Float64Max(dst, src1, src2, ool->entry());
      __ bind(ool->exit());
1312 1313
      break;
    }
1314
    case kMipsFloat32Min: {
1315 1316 1317
      FPURegister dst = i.OutputSingleRegister();
      FPURegister src1 = i.InputSingleRegister(0);
      FPURegister src2 = i.InputSingleRegister(1);
1318 1319 1320
      auto ool = new (zone()) OutOfLineFloat32Min(this, dst, src1, src2);
      __ Float32Min(dst, src1, src2, ool->entry());
      __ bind(ool->exit());
1321 1322
      break;
    }
1323
    case kMipsFloat64Min: {
1324 1325 1326
      DoubleRegister dst = i.OutputDoubleRegister();
      DoubleRegister src1 = i.InputDoubleRegister(0);
      DoubleRegister src2 = i.InputDoubleRegister(1);
1327 1328 1329
      auto ool = new (zone()) OutOfLineFloat64Min(this, dst, src1, src2);
      __ Float64Min(dst, src1, src2, ool->entry());
      __ bind(ool->exit());
1330 1331
      break;
    }
1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345
    case kMipsCvtSD: {
      __ cvt_s_d(i.OutputSingleRegister(), i.InputDoubleRegister(0));
      break;
    }
    case kMipsCvtDS: {
      __ cvt_d_s(i.OutputDoubleRegister(), i.InputSingleRegister(0));
      break;
    }
    case kMipsCvtDW: {
      FPURegister scratch = kScratchDoubleReg;
      __ mtc1(i.InputRegister(0), scratch);
      __ cvt_d_w(i.OutputDoubleRegister(), scratch);
      break;
    }
1346 1347 1348 1349 1350 1351
    case kMipsCvtSW: {
      FPURegister scratch = kScratchDoubleReg;
      __ mtc1(i.InputRegister(0), scratch);
      __ cvt_s_w(i.OutputDoubleRegister(), scratch);
      break;
    }
1352 1353 1354 1355 1356 1357
    case kMipsCvtSUw: {
      FPURegister scratch = kScratchDoubleReg;
      __ Cvt_d_uw(i.OutputDoubleRegister(), i.InputRegister(0), scratch);
      __ cvt_s_d(i.OutputDoubleRegister(), i.OutputDoubleRegister());
      break;
    }
1358 1359 1360 1361 1362
    case kMipsCvtDUw: {
      FPURegister scratch = kScratchDoubleReg;
      __ Cvt_d_uw(i.OutputDoubleRegister(), i.InputRegister(0), scratch);
      break;
    }
1363 1364
    case kMipsFloorWD: {
      FPURegister scratch = kScratchDoubleReg;
1365
      __ Floor_w_d(scratch, i.InputDoubleRegister(0));
1366 1367 1368 1369 1370
      __ mfc1(i.OutputRegister(), scratch);
      break;
    }
    case kMipsCeilWD: {
      FPURegister scratch = kScratchDoubleReg;
1371
      __ Ceil_w_d(scratch, i.InputDoubleRegister(0));
1372 1373 1374 1375 1376
      __ mfc1(i.OutputRegister(), scratch);
      break;
    }
    case kMipsRoundWD: {
      FPURegister scratch = kScratchDoubleReg;
1377
      __ Round_w_d(scratch, i.InputDoubleRegister(0));
1378 1379 1380
      __ mfc1(i.OutputRegister(), scratch);
      break;
    }
1381 1382 1383
    case kMipsTruncWD: {
      FPURegister scratch = kScratchDoubleReg;
      // Other arches use round to zero here, so we follow.
1384
      __ Trunc_w_d(scratch, i.InputDoubleRegister(0));
1385 1386 1387
      __ mfc1(i.OutputRegister(), scratch);
      break;
    }
1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409
    case kMipsFloorWS: {
      FPURegister scratch = kScratchDoubleReg;
      __ floor_w_s(scratch, i.InputDoubleRegister(0));
      __ mfc1(i.OutputRegister(), scratch);
      break;
    }
    case kMipsCeilWS: {
      FPURegister scratch = kScratchDoubleReg;
      __ ceil_w_s(scratch, i.InputDoubleRegister(0));
      __ mfc1(i.OutputRegister(), scratch);
      break;
    }
    case kMipsRoundWS: {
      FPURegister scratch = kScratchDoubleReg;
      __ round_w_s(scratch, i.InputDoubleRegister(0));
      __ mfc1(i.OutputRegister(), scratch);
      break;
    }
    case kMipsTruncWS: {
      FPURegister scratch = kScratchDoubleReg;
      __ trunc_w_s(scratch, i.InputDoubleRegister(0));
      __ mfc1(i.OutputRegister(), scratch);
1410 1411
      // Avoid INT32_MAX as an overflow indicator and use INT32_MIN instead,
      // because INT32_MIN allows easier out-of-bounds detection.
1412 1413
      __ Addu(kScratchReg, i.OutputRegister(), 1);
      __ Slt(kScratchReg2, kScratchReg, i.OutputRegister());
1414
      __ Movn(i.OutputRegister(), kScratchReg, kScratchReg2);
1415 1416
      break;
    }
1417 1418
    case kMipsTruncUwD: {
      FPURegister scratch = kScratchDoubleReg;
1419
      __ Trunc_uw_d(i.OutputRegister(), i.InputDoubleRegister(0), scratch);
1420 1421
      break;
    }
1422 1423
    case kMipsTruncUwS: {
      FPURegister scratch = kScratchDoubleReg;
1424
      __ Trunc_uw_s(i.OutputRegister(), i.InputDoubleRegister(0), scratch);
1425 1426
      // Avoid UINT32_MAX as an overflow indicator and use 0 instead,
      // because 0 allows easier out-of-bounds detection.
1427
      __ Addu(kScratchReg, i.OutputRegister(), 1);
1428
      __ Movz(i.OutputRegister(), zero_reg, kScratchReg);
1429 1430
      break;
    }
1431
    case kMipsFloat64ExtractLowWord32:
1432 1433
      __ FmoveLow(i.OutputRegister(), i.InputDoubleRegister(0));
      break;
1434
    case kMipsFloat64ExtractHighWord32:
1435 1436
      __ FmoveHigh(i.OutputRegister(), i.InputDoubleRegister(0));
      break;
1437 1438 1439 1440
    case kMipsFloat64InsertLowWord32:
      __ FmoveLow(i.OutputDoubleRegister(), i.InputRegister(1));
      break;
    case kMipsFloat64InsertHighWord32:
1441 1442
      __ FmoveHigh(i.OutputDoubleRegister(), i.InputRegister(1));
      break;
1443 1444
    case kMipsFloat64SilenceNaN:
      __ FPUCanonicalizeNaN(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
1445 1446
      break;

1447
    // ... more basic instructions ...
1448
    case kMipsSeb:
1449
      __ Seb(i.OutputRegister(), i.InputRegister(0));
1450 1451
      break;
    case kMipsSeh:
1452
      __ Seh(i.OutputRegister(), i.InputRegister(0));
1453
      break;
1454 1455
    case kMipsLbu:
      __ lbu(i.OutputRegister(), i.MemoryOperand());
1456
      EmitWordLoadPoisoningIfNeeded(this, opcode, instr, i);
1457 1458 1459
      break;
    case kMipsLb:
      __ lb(i.OutputRegister(), i.MemoryOperand());
1460
      EmitWordLoadPoisoningIfNeeded(this, opcode, instr, i);
1461 1462
      break;
    case kMipsSb:
1463
      __ sb(i.InputOrZeroRegister(2), i.MemoryOperand());
1464 1465 1466
      break;
    case kMipsLhu:
      __ lhu(i.OutputRegister(), i.MemoryOperand());
1467
      EmitWordLoadPoisoningIfNeeded(this, opcode, instr, i);
1468
      break;
1469 1470
    case kMipsUlhu:
      __ Ulhu(i.OutputRegister(), i.MemoryOperand());
1471
      EmitWordLoadPoisoningIfNeeded(this, opcode, instr, i);
1472
      break;
1473 1474
    case kMipsLh:
      __ lh(i.OutputRegister(), i.MemoryOperand());
1475
      EmitWordLoadPoisoningIfNeeded(this, opcode, instr, i);
1476
      break;
1477 1478
    case kMipsUlh:
      __ Ulh(i.OutputRegister(), i.MemoryOperand());
1479
      EmitWordLoadPoisoningIfNeeded(this, opcode, instr, i);
1480
      break;
1481
    case kMipsSh:
1482
      __ sh(i.InputOrZeroRegister(2), i.MemoryOperand());
1483
      break;
1484
    case kMipsUsh:
1485
      __ Ush(i.InputOrZeroRegister(2), i.MemoryOperand(), kScratchReg);
1486
      break;
1487 1488
    case kMipsLw:
      __ lw(i.OutputRegister(), i.MemoryOperand());
1489
      EmitWordLoadPoisoningIfNeeded(this, opcode, instr, i);
1490
      break;
1491 1492
    case kMipsUlw:
      __ Ulw(i.OutputRegister(), i.MemoryOperand());
1493
      EmitWordLoadPoisoningIfNeeded(this, opcode, instr, i);
1494
      break;
1495
    case kMipsSw:
1496
      __ sw(i.InputOrZeroRegister(2), i.MemoryOperand());
1497
      break;
1498
    case kMipsUsw:
1499
      __ Usw(i.InputOrZeroRegister(2), i.MemoryOperand());
1500
      break;
1501 1502 1503 1504
    case kMipsLwc1: {
      __ lwc1(i.OutputSingleRegister(), i.MemoryOperand());
      break;
    }
1505 1506 1507 1508
    case kMipsUlwc1: {
      __ Ulwc1(i.OutputSingleRegister(), i.MemoryOperand(), kScratchReg);
      break;
    }
1509
    case kMipsSwc1: {
1510
      size_t index = 0;
1511
      MemOperand operand = i.MemoryOperand(&index);
1512
      FPURegister ft = i.InputOrZeroSingleRegister(index);
1513
      if (ft == kDoubleRegZero && !__ IsDoubleZeroRegSet()) {
1514 1515 1516
        __ Move(kDoubleRegZero, 0.0);
      }
      __ swc1(ft, operand);
1517 1518
      break;
    }
1519 1520 1521
    case kMipsUswc1: {
      size_t index = 0;
      MemOperand operand = i.MemoryOperand(&index);
1522
      FPURegister ft = i.InputOrZeroSingleRegister(index);
1523
      if (ft == kDoubleRegZero && !__ IsDoubleZeroRegSet()) {
1524 1525 1526
        __ Move(kDoubleRegZero, 0.0);
      }
      __ Uswc1(ft, operand, kScratchReg);
1527 1528
      break;
    }
1529
    case kMipsLdc1:
1530
      __ Ldc1(i.OutputDoubleRegister(), i.MemoryOperand());
1531
      break;
1532 1533 1534
    case kMipsUldc1:
      __ Uldc1(i.OutputDoubleRegister(), i.MemoryOperand(), kScratchReg);
      break;
1535 1536
    case kMipsSdc1: {
      FPURegister ft = i.InputOrZeroDoubleRegister(2);
1537
      if (ft == kDoubleRegZero && !__ IsDoubleZeroRegSet()) {
1538 1539
        __ Move(kDoubleRegZero, 0.0);
      }
1540
      __ Sdc1(ft, i.MemoryOperand());
1541
      break;
1542 1543 1544
    }
    case kMipsUsdc1: {
      FPURegister ft = i.InputOrZeroDoubleRegister(2);
1545
      if (ft == kDoubleRegZero && !__ IsDoubleZeroRegSet()) {
1546 1547 1548
        __ Move(kDoubleRegZero, 0.0);
      }
      __ Usdc1(ft, i.MemoryOperand(), kScratchReg);
1549
      break;
1550
    }
1551
    case kMipsPush:
1552
      if (instr->InputAt(0)->IsFPRegister()) {
1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569
        LocationOperand* op = LocationOperand::cast(instr->InputAt(0));
        switch (op->representation()) {
          case MachineRepresentation::kFloat32:
            __ swc1(i.InputFloatRegister(0), MemOperand(sp, -kFloatSize));
            __ Subu(sp, sp, Operand(kFloatSize));
            frame_access_state()->IncreaseSPDelta(kFloatSize / kPointerSize);
            break;
          case MachineRepresentation::kFloat64:
            __ Sdc1(i.InputDoubleRegister(0), MemOperand(sp, -kDoubleSize));
            __ Subu(sp, sp, Operand(kDoubleSize));
            frame_access_state()->IncreaseSPDelta(kDoubleSize / kPointerSize);
            break;
          default: {
            UNREACHABLE();
            break;
          }
        }
1570 1571
      } else {
        __ Push(i.InputRegister(0));
1572
        frame_access_state()->IncreaseSPDelta(1);
1573
      }
1574
      break;
1575
    case kMipsPeek: {
1576 1577
      // The incoming value is 0-based, but we need a 1-based value.
      int reverse_slot = i.InputInt32(0) + 1;
1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592
      int offset =
          FrameSlotToFPOffset(frame()->GetTotalFrameSlotCount() - reverse_slot);
      if (instr->OutputAt(0)->IsFPRegister()) {
        LocationOperand* op = LocationOperand::cast(instr->OutputAt(0));
        if (op->representation() == MachineRepresentation::kFloat64) {
          __ Ldc1(i.OutputDoubleRegister(), MemOperand(fp, offset));
        } else {
          DCHECK_EQ(op->representation(), MachineRepresentation::kFloat32);
          __ lwc1(i.OutputSingleRegister(0), MemOperand(fp, offset));
        }
      } else {
        __ lw(i.OutputRegister(0), MemOperand(fp, offset));
      }
      break;
    }
1593
    case kMipsStackClaim: {
1594
      __ Subu(sp, sp, Operand(i.InputInt32(0)));
1595
      frame_access_state()->IncreaseSPDelta(i.InputInt32(0) / kPointerSize);
1596 1597 1598
      break;
    }
    case kMipsStoreToStackSlot: {
1599
      if (instr->InputAt(0)->IsFPRegister()) {
1600 1601
        LocationOperand* op = LocationOperand::cast(instr->InputAt(0));
        if (op->representation() == MachineRepresentation::kFloat64) {
1602
          __ Sdc1(i.InputDoubleRegister(0), MemOperand(sp, i.InputInt32(1)));
1603
        } else if (op->representation() == MachineRepresentation::kFloat32) {
1604
          __ swc1(i.InputSingleRegister(0), MemOperand(sp, i.InputInt32(1)));
1605 1606 1607 1608
        } else {
          DCHECK_EQ(MachineRepresentation::kSimd128, op->representation());
          CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
          __ st_b(i.InputSimd128Register(0), MemOperand(sp, i.InputInt32(1)));
1609
        }
1610 1611 1612
      } else {
        __ sw(i.InputRegister(0), MemOperand(sp, i.InputInt32(1)));
      }
1613 1614
      break;
    }
1615 1616 1617 1618
    case kMipsByteSwap32: {
      __ ByteSwapSigned(i.OutputRegister(0), i.InputRegister(0), 4);
      break;
    }
1619
    case kWord32AtomicLoadInt8:
1620 1621
      ASSEMBLE_ATOMIC_LOAD_INTEGER(lb);
      break;
1622
    case kWord32AtomicLoadUint8:
1623 1624
      ASSEMBLE_ATOMIC_LOAD_INTEGER(lbu);
      break;
1625
    case kWord32AtomicLoadInt16:
1626 1627
      ASSEMBLE_ATOMIC_LOAD_INTEGER(lh);
      break;
1628
    case kWord32AtomicLoadUint16:
1629 1630
      ASSEMBLE_ATOMIC_LOAD_INTEGER(lhu);
      break;
1631
    case kWord32AtomicLoadWord32:
1632
      ASSEMBLE_ATOMIC_LOAD_INTEGER(lw);
1633
      break;
1634
    case kWord32AtomicStoreWord8:
1635 1636
      ASSEMBLE_ATOMIC_STORE_INTEGER(sb);
      break;
1637
    case kWord32AtomicStoreWord16:
1638 1639
      ASSEMBLE_ATOMIC_STORE_INTEGER(sh);
      break;
1640
    case kWord32AtomicStoreWord32:
1641
      ASSEMBLE_ATOMIC_STORE_INTEGER(sw);
1642
      break;
1643
    case kWord32AtomicExchangeInt8:
1644 1645
      ASSEMBLE_ATOMIC_EXCHANGE_INTEGER_EXT(true, 8);
      break;
1646
    case kWord32AtomicExchangeUint8:
1647 1648
      ASSEMBLE_ATOMIC_EXCHANGE_INTEGER_EXT(false, 8);
      break;
1649
    case kWord32AtomicExchangeInt16:
1650 1651
      ASSEMBLE_ATOMIC_EXCHANGE_INTEGER_EXT(true, 16);
      break;
1652
    case kWord32AtomicExchangeUint16:
1653 1654
      ASSEMBLE_ATOMIC_EXCHANGE_INTEGER_EXT(false, 16);
      break;
1655
    case kWord32AtomicExchangeWord32:
1656 1657
      ASSEMBLE_ATOMIC_EXCHANGE_INTEGER();
      break;
1658
    case kWord32AtomicCompareExchangeInt8:
1659 1660
      ASSEMBLE_ATOMIC_COMPARE_EXCHANGE_INTEGER_EXT(true, 8);
      break;
1661
    case kWord32AtomicCompareExchangeUint8:
1662 1663
      ASSEMBLE_ATOMIC_COMPARE_EXCHANGE_INTEGER_EXT(false, 8);
      break;
1664
    case kWord32AtomicCompareExchangeInt16:
1665 1666
      ASSEMBLE_ATOMIC_COMPARE_EXCHANGE_INTEGER_EXT(true, 16);
      break;
1667
    case kWord32AtomicCompareExchangeUint16:
1668 1669
      ASSEMBLE_ATOMIC_COMPARE_EXCHANGE_INTEGER_EXT(false, 16);
      break;
1670
    case kWord32AtomicCompareExchangeWord32:
1671
      ASSEMBLE_ATOMIC_COMPARE_EXCHANGE_INTEGER();
1672
      break;
1673
#define ATOMIC_BINOP_CASE(op, inst)             \
1674
  case kWord32Atomic##op##Int8:                 \
1675 1676
    ASSEMBLE_ATOMIC_BINOP_EXT(true, 8, inst);   \
    break;                                      \
1677
  case kWord32Atomic##op##Uint8:                \
1678 1679
    ASSEMBLE_ATOMIC_BINOP_EXT(false, 8, inst);  \
    break;                                      \
1680
  case kWord32Atomic##op##Int16:                \
1681 1682
    ASSEMBLE_ATOMIC_BINOP_EXT(true, 16, inst);  \
    break;                                      \
1683
  case kWord32Atomic##op##Uint16:               \
1684 1685
    ASSEMBLE_ATOMIC_BINOP_EXT(false, 16, inst); \
    break;                                      \
1686
  case kWord32Atomic##op##Word32:               \
1687 1688 1689 1690 1691 1692 1693 1694
    ASSEMBLE_ATOMIC_BINOP(inst);                \
    break;
      ATOMIC_BINOP_CASE(Add, Addu)
      ATOMIC_BINOP_CASE(Sub, Subu)
      ATOMIC_BINOP_CASE(And, And)
      ATOMIC_BINOP_CASE(Or, Or)
      ATOMIC_BINOP_CASE(Xor, Xor)
#undef ATOMIC_BINOP_CASE
1695
    case kMipsS128Zero: {
1696
      CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
1697 1698 1699 1700 1701
      __ xor_v(i.OutputSimd128Register(), i.OutputSimd128Register(),
               i.OutputSimd128Register());
      break;
    }
    case kMipsI32x4Splat: {
1702
      CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
1703 1704 1705 1706
      __ fill_w(i.OutputSimd128Register(), i.InputRegister(0));
      break;
    }
    case kMipsI32x4ExtractLane: {
1707
      CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
1708 1709 1710 1711 1712
      __ copy_s_w(i.OutputRegister(), i.InputSimd128Register(0),
                  i.InputInt8(1));
      break;
    }
    case kMipsI32x4ReplaceLane: {
1713
      CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
1714 1715
      Simd128Register src = i.InputSimd128Register(0);
      Simd128Register dst = i.OutputSimd128Register();
1716
      if (src != dst) {
1717 1718 1719 1720 1721 1722
        __ move_v(dst, src);
      }
      __ insert_w(dst, i.InputInt8(1), i.InputRegister(2));
      break;
    }
    case kMipsI32x4Add: {
1723
      CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
1724 1725 1726 1727 1728
      __ addv_w(i.OutputSimd128Register(), i.InputSimd128Register(0),
                i.InputSimd128Register(1));
      break;
    }
    case kMipsI32x4Sub: {
1729
      CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
1730 1731 1732 1733
      __ subv_w(i.OutputSimd128Register(), i.InputSimd128Register(0),
                i.InputSimd128Register(1));
      break;
    }
1734
    case kMipsF32x4Splat: {
1735
      CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
1736 1737 1738 1739 1740
      __ FmoveLow(kScratchReg, i.InputSingleRegister(0));
      __ fill_w(i.OutputSimd128Register(), kScratchReg);
      break;
    }
    case kMipsF32x4ExtractLane: {
1741
      CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
1742 1743 1744 1745 1746
      __ copy_u_w(kScratchReg, i.InputSimd128Register(0), i.InputInt8(1));
      __ FmoveLow(i.OutputSingleRegister(), kScratchReg);
      break;
    }
    case kMipsF32x4ReplaceLane: {
1747
      CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
1748 1749
      Simd128Register src = i.InputSimd128Register(0);
      Simd128Register dst = i.OutputSimd128Register();
1750
      if (src != dst) {
1751 1752 1753 1754 1755 1756 1757
        __ move_v(dst, src);
      }
      __ FmoveLow(kScratchReg, i.InputSingleRegister(2));
      __ insert_w(dst, i.InputInt8(1), kScratchReg);
      break;
    }
    case kMipsF32x4SConvertI32x4: {
1758
      CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
1759 1760 1761 1762
      __ ffint_s_w(i.OutputSimd128Register(), i.InputSimd128Register(0));
      break;
    }
    case kMipsF32x4UConvertI32x4: {
1763
      CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
1764 1765 1766
      __ ffint_u_w(i.OutputSimd128Register(), i.InputSimd128Register(0));
      break;
    }
1767
    case kMipsI32x4Mul: {
1768
      CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
1769 1770 1771 1772 1773
      __ mulv_w(i.OutputSimd128Register(), i.InputSimd128Register(0),
                i.InputSimd128Register(1));
      break;
    }
    case kMipsI32x4MaxS: {
1774
      CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
1775 1776 1777 1778 1779
      __ max_s_w(i.OutputSimd128Register(), i.InputSimd128Register(0),
                 i.InputSimd128Register(1));
      break;
    }
    case kMipsI32x4MinS: {
1780
      CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
1781 1782 1783 1784 1785
      __ min_s_w(i.OutputSimd128Register(), i.InputSimd128Register(0),
                 i.InputSimd128Register(1));
      break;
    }
    case kMipsI32x4Eq: {
1786
      CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
1787 1788 1789 1790 1791
      __ ceq_w(i.OutputSimd128Register(), i.InputSimd128Register(0),
               i.InputSimd128Register(1));
      break;
    }
    case kMipsI32x4Ne: {
1792
      CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
1793 1794 1795 1796 1797 1798
      Simd128Register dst = i.OutputSimd128Register();
      __ ceq_w(dst, i.InputSimd128Register(0), i.InputSimd128Register(1));
      __ nor_v(dst, dst, dst);
      break;
    }
    case kMipsI32x4Shl: {
1799
      CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
1800 1801 1802 1803 1804
      __ slli_w(i.OutputSimd128Register(), i.InputSimd128Register(0),
                i.InputInt5(1));
      break;
    }
    case kMipsI32x4ShrS: {
1805
      CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
1806 1807 1808 1809 1810
      __ srai_w(i.OutputSimd128Register(), i.InputSimd128Register(0),
                i.InputInt5(1));
      break;
    }
    case kMipsI32x4ShrU: {
1811
      CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
1812 1813 1814 1815 1816
      __ srli_w(i.OutputSimd128Register(), i.InputSimd128Register(0),
                i.InputInt5(1));
      break;
    }
    case kMipsI32x4MaxU: {
1817
      CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
1818 1819 1820 1821 1822
      __ max_u_w(i.OutputSimd128Register(), i.InputSimd128Register(0),
                 i.InputSimd128Register(1));
      break;
    }
    case kMipsI32x4MinU: {
1823
      CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
1824 1825 1826 1827
      __ min_u_w(i.OutputSimd128Register(), i.InputSimd128Register(0),
                 i.InputSimd128Register(1));
      break;
    }
1828
    case kMipsS128Select: {
1829
      CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
1830
      DCHECK(i.OutputSimd128Register() == i.InputSimd128Register(0));
1831 1832 1833 1834
      __ bsel_v(i.OutputSimd128Register(), i.InputSimd128Register(2),
                i.InputSimd128Register(1));
      break;
    }
1835
    case kMipsF32x4Abs: {
1836
      CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
1837 1838 1839 1840
      __ bclri_w(i.OutputSimd128Register(), i.InputSimd128Register(0), 31);
      break;
    }
    case kMipsF32x4Neg: {
1841
      CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
1842 1843 1844 1845
      __ bnegi_w(i.OutputSimd128Register(), i.InputSimd128Register(0), 31);
      break;
    }
    case kMipsF32x4RecipApprox: {
1846
      CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
1847 1848 1849 1850
      __ frcp_w(i.OutputSimd128Register(), i.InputSimd128Register(0));
      break;
    }
    case kMipsF32x4RecipSqrtApprox: {
1851
      CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
1852 1853 1854 1855
      __ frsqrt_w(i.OutputSimd128Register(), i.InputSimd128Register(0));
      break;
    }
    case kMipsF32x4Add: {
1856
      CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
1857 1858 1859 1860 1861
      __ fadd_w(i.OutputSimd128Register(), i.InputSimd128Register(0),
                i.InputSimd128Register(1));
      break;
    }
    case kMipsF32x4Sub: {
1862
      CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
1863 1864 1865 1866 1867
      __ fsub_w(i.OutputSimd128Register(), i.InputSimd128Register(0),
                i.InputSimd128Register(1));
      break;
    }
    case kMipsF32x4Mul: {
1868
      CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
1869 1870 1871 1872 1873
      __ fmul_w(i.OutputSimd128Register(), i.InputSimd128Register(0),
                i.InputSimd128Register(1));
      break;
    }
    case kMipsF32x4Max: {
1874
      CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
1875 1876 1877 1878 1879
      __ fmax_w(i.OutputSimd128Register(), i.InputSimd128Register(0),
                i.InputSimd128Register(1));
      break;
    }
    case kMipsF32x4Min: {
1880
      CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
1881 1882 1883 1884 1885
      __ fmin_w(i.OutputSimd128Register(), i.InputSimd128Register(0),
                i.InputSimd128Register(1));
      break;
    }
    case kMipsF32x4Eq: {
1886
      CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
1887 1888 1889 1890 1891
      __ fceq_w(i.OutputSimd128Register(), i.InputSimd128Register(0),
                i.InputSimd128Register(1));
      break;
    }
    case kMipsF32x4Ne: {
1892
      CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
1893 1894 1895 1896 1897
      __ fcne_w(i.OutputSimd128Register(), i.InputSimd128Register(0),
                i.InputSimd128Register(1));
      break;
    }
    case kMipsF32x4Lt: {
1898
      CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
1899 1900 1901 1902 1903
      __ fclt_w(i.OutputSimd128Register(), i.InputSimd128Register(0),
                i.InputSimd128Register(1));
      break;
    }
    case kMipsF32x4Le: {
1904
      CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
1905 1906 1907 1908 1909
      __ fcle_w(i.OutputSimd128Register(), i.InputSimd128Register(0),
                i.InputSimd128Register(1));
      break;
    }
    case kMipsI32x4SConvertF32x4: {
1910
      CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
1911 1912 1913 1914
      __ ftrunc_s_w(i.OutputSimd128Register(), i.InputSimd128Register(0));
      break;
    }
    case kMipsI32x4UConvertF32x4: {
1915
      CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
1916 1917 1918
      __ ftrunc_u_w(i.OutputSimd128Register(), i.InputSimd128Register(0));
      break;
    }
1919
    case kMipsI32x4Neg: {
1920
      CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
1921 1922 1923 1924 1925
      __ xor_v(kSimd128RegZero, kSimd128RegZero, kSimd128RegZero);
      __ subv_w(i.OutputSimd128Register(), kSimd128RegZero,
                i.InputSimd128Register(0));
      break;
    }
1926
    case kMipsI32x4GtS: {
1927
      CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
1928 1929
      __ clt_s_w(i.OutputSimd128Register(), i.InputSimd128Register(1),
                 i.InputSimd128Register(0));
1930 1931
      break;
    }
1932
    case kMipsI32x4GeS: {
1933
      CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
1934 1935
      __ cle_s_w(i.OutputSimd128Register(), i.InputSimd128Register(1),
                 i.InputSimd128Register(0));
1936 1937
      break;
    }
1938
    case kMipsI32x4GtU: {
1939
      CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
1940 1941
      __ clt_u_w(i.OutputSimd128Register(), i.InputSimd128Register(1),
                 i.InputSimd128Register(0));
1942 1943
      break;
    }
1944
    case kMipsI32x4GeU: {
1945
      CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
1946 1947
      __ cle_u_w(i.OutputSimd128Register(), i.InputSimd128Register(1),
                 i.InputSimd128Register(0));
1948 1949 1950
      break;
    }
    case kMipsI16x8Splat: {
1951
      CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
1952 1953 1954 1955
      __ fill_h(i.OutputSimd128Register(), i.InputRegister(0));
      break;
    }
    case kMipsI16x8ExtractLane: {
1956
      CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
1957 1958 1959 1960 1961
      __ copy_s_h(i.OutputRegister(), i.InputSimd128Register(0),
                  i.InputInt8(1));
      break;
    }
    case kMipsI16x8ReplaceLane: {
1962
      CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
1963 1964
      Simd128Register src = i.InputSimd128Register(0);
      Simd128Register dst = i.OutputSimd128Register();
1965
      if (src != dst) {
1966 1967 1968 1969 1970 1971
        __ move_v(dst, src);
      }
      __ insert_h(dst, i.InputInt8(1), i.InputRegister(2));
      break;
    }
    case kMipsI16x8Neg: {
1972
      CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
1973 1974 1975 1976 1977 1978
      __ xor_v(kSimd128RegZero, kSimd128RegZero, kSimd128RegZero);
      __ subv_h(i.OutputSimd128Register(), kSimd128RegZero,
                i.InputSimd128Register(0));
      break;
    }
    case kMipsI16x8Shl: {
1979
      CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
1980 1981 1982 1983 1984
      __ slli_h(i.OutputSimd128Register(), i.InputSimd128Register(0),
                i.InputInt4(1));
      break;
    }
    case kMipsI16x8ShrS: {
1985
      CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
1986 1987 1988 1989 1990
      __ srai_h(i.OutputSimd128Register(), i.InputSimd128Register(0),
                i.InputInt4(1));
      break;
    }
    case kMipsI16x8ShrU: {
1991
      CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
1992 1993 1994 1995 1996
      __ srli_h(i.OutputSimd128Register(), i.InputSimd128Register(0),
                i.InputInt4(1));
      break;
    }
    case kMipsI16x8Add: {
1997
      CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
1998 1999 2000 2001 2002
      __ addv_h(i.OutputSimd128Register(), i.InputSimd128Register(0),
                i.InputSimd128Register(1));
      break;
    }
    case kMipsI16x8AddSaturateS: {
2003
      CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2004 2005 2006 2007 2008
      __ adds_s_h(i.OutputSimd128Register(), i.InputSimd128Register(0),
                  i.InputSimd128Register(1));
      break;
    }
    case kMipsI16x8Sub: {
2009
      CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2010 2011 2012 2013 2014
      __ subv_h(i.OutputSimd128Register(), i.InputSimd128Register(0),
                i.InputSimd128Register(1));
      break;
    }
    case kMipsI16x8SubSaturateS: {
2015
      CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2016 2017 2018 2019
      __ subs_s_h(i.OutputSimd128Register(), i.InputSimd128Register(0),
                  i.InputSimd128Register(1));
      break;
    }
2020
    case kMipsI16x8Mul: {
2021
      CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2022 2023 2024 2025 2026
      __ mulv_h(i.OutputSimd128Register(), i.InputSimd128Register(0),
                i.InputSimd128Register(1));
      break;
    }
    case kMipsI16x8MaxS: {
2027
      CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2028 2029 2030 2031 2032
      __ max_s_h(i.OutputSimd128Register(), i.InputSimd128Register(0),
                 i.InputSimd128Register(1));
      break;
    }
    case kMipsI16x8MinS: {
2033
      CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2034 2035 2036 2037 2038
      __ min_s_h(i.OutputSimd128Register(), i.InputSimd128Register(0),
                 i.InputSimd128Register(1));
      break;
    }
    case kMipsI16x8Eq: {
2039
      CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2040 2041 2042 2043 2044
      __ ceq_h(i.OutputSimd128Register(), i.InputSimd128Register(0),
               i.InputSimd128Register(1));
      break;
    }
    case kMipsI16x8Ne: {
2045
      CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2046 2047 2048 2049 2050
      Simd128Register dst = i.OutputSimd128Register();
      __ ceq_h(dst, i.InputSimd128Register(0), i.InputSimd128Register(1));
      __ nor_v(dst, dst, dst);
      break;
    }
2051
    case kMipsI16x8GtS: {
2052
      CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2053 2054
      __ clt_s_h(i.OutputSimd128Register(), i.InputSimd128Register(1),
                 i.InputSimd128Register(0));
2055 2056
      break;
    }
2057
    case kMipsI16x8GeS: {
2058
      CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2059 2060
      __ cle_s_h(i.OutputSimd128Register(), i.InputSimd128Register(1),
                 i.InputSimd128Register(0));
2061 2062 2063
      break;
    }
    case kMipsI16x8AddSaturateU: {
2064
      CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2065 2066 2067 2068 2069
      __ adds_u_h(i.OutputSimd128Register(), i.InputSimd128Register(0),
                  i.InputSimd128Register(1));
      break;
    }
    case kMipsI16x8SubSaturateU: {
2070
      CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2071 2072 2073 2074 2075
      __ subs_u_h(i.OutputSimd128Register(), i.InputSimd128Register(0),
                  i.InputSimd128Register(1));
      break;
    }
    case kMipsI16x8MaxU: {
2076
      CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2077 2078 2079 2080 2081
      __ max_u_h(i.OutputSimd128Register(), i.InputSimd128Register(0),
                 i.InputSimd128Register(1));
      break;
    }
    case kMipsI16x8MinU: {
2082
      CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2083 2084 2085 2086
      __ min_u_h(i.OutputSimd128Register(), i.InputSimd128Register(0),
                 i.InputSimd128Register(1));
      break;
    }
2087
    case kMipsI16x8GtU: {
2088
      CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2089 2090
      __ clt_u_h(i.OutputSimd128Register(), i.InputSimd128Register(1),
                 i.InputSimd128Register(0));
2091 2092
      break;
    }
2093
    case kMipsI16x8GeU: {
2094
      CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2095 2096
      __ cle_u_h(i.OutputSimd128Register(), i.InputSimd128Register(1),
                 i.InputSimd128Register(0));
2097 2098 2099
      break;
    }
    case kMipsI8x16Splat: {
2100
      CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2101 2102 2103 2104
      __ fill_b(i.OutputSimd128Register(), i.InputRegister(0));
      break;
    }
    case kMipsI8x16ExtractLane: {
2105
      CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2106 2107 2108 2109 2110
      __ copy_s_b(i.OutputRegister(), i.InputSimd128Register(0),
                  i.InputInt8(1));
      break;
    }
    case kMipsI8x16ReplaceLane: {
2111
      CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2112 2113
      Simd128Register src = i.InputSimd128Register(0);
      Simd128Register dst = i.OutputSimd128Register();
2114
      if (src != dst) {
2115 2116 2117 2118 2119 2120
        __ move_v(dst, src);
      }
      __ insert_b(dst, i.InputInt8(1), i.InputRegister(2));
      break;
    }
    case kMipsI8x16Neg: {
2121
      CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2122 2123 2124 2125 2126 2127
      __ xor_v(kSimd128RegZero, kSimd128RegZero, kSimd128RegZero);
      __ subv_b(i.OutputSimd128Register(), kSimd128RegZero,
                i.InputSimd128Register(0));
      break;
    }
    case kMipsI8x16Shl: {
2128
      CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2129 2130 2131 2132 2133
      __ slli_b(i.OutputSimd128Register(), i.InputSimd128Register(0),
                i.InputInt3(1));
      break;
    }
    case kMipsI8x16ShrS: {
2134
      CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2135 2136 2137 2138
      __ srai_b(i.OutputSimd128Register(), i.InputSimd128Register(0),
                i.InputInt3(1));
      break;
    }
2139
    case kMipsI8x16Add: {
2140
      CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2141 2142 2143 2144 2145
      __ addv_b(i.OutputSimd128Register(), i.InputSimd128Register(0),
                i.InputSimd128Register(1));
      break;
    }
    case kMipsI8x16AddSaturateS: {
2146
      CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2147 2148 2149 2150 2151
      __ adds_s_b(i.OutputSimd128Register(), i.InputSimd128Register(0),
                  i.InputSimd128Register(1));
      break;
    }
    case kMipsI8x16Sub: {
2152
      CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2153 2154 2155 2156 2157
      __ subv_b(i.OutputSimd128Register(), i.InputSimd128Register(0),
                i.InputSimd128Register(1));
      break;
    }
    case kMipsI8x16SubSaturateS: {
2158
      CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2159 2160 2161 2162 2163
      __ subs_s_b(i.OutputSimd128Register(), i.InputSimd128Register(0),
                  i.InputSimd128Register(1));
      break;
    }
    case kMipsI8x16Mul: {
2164
      CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2165 2166 2167 2168 2169
      __ mulv_b(i.OutputSimd128Register(), i.InputSimd128Register(0),
                i.InputSimd128Register(1));
      break;
    }
    case kMipsI8x16MaxS: {
2170
      CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2171 2172 2173 2174 2175
      __ max_s_b(i.OutputSimd128Register(), i.InputSimd128Register(0),
                 i.InputSimd128Register(1));
      break;
    }
    case kMipsI8x16MinS: {
2176
      CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2177 2178 2179 2180 2181
      __ min_s_b(i.OutputSimd128Register(), i.InputSimd128Register(0),
                 i.InputSimd128Register(1));
      break;
    }
    case kMipsI8x16Eq: {
2182
      CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2183 2184 2185 2186 2187
      __ ceq_b(i.OutputSimd128Register(), i.InputSimd128Register(0),
               i.InputSimd128Register(1));
      break;
    }
    case kMipsI8x16Ne: {
2188
      CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2189 2190 2191 2192 2193 2194
      Simd128Register dst = i.OutputSimd128Register();
      __ ceq_b(dst, i.InputSimd128Register(0), i.InputSimd128Register(1));
      __ nor_v(dst, dst, dst);
      break;
    }
    case kMipsI8x16GtS: {
2195
      CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2196 2197 2198 2199 2200
      __ clt_s_b(i.OutputSimd128Register(), i.InputSimd128Register(1),
                 i.InputSimd128Register(0));
      break;
    }
    case kMipsI8x16GeS: {
2201
      CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2202 2203 2204 2205 2206
      __ cle_s_b(i.OutputSimd128Register(), i.InputSimd128Register(1),
                 i.InputSimd128Register(0));
      break;
    }
    case kMipsI8x16ShrU: {
2207
      CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2208 2209 2210 2211 2212
      __ srli_b(i.OutputSimd128Register(), i.InputSimd128Register(0),
                i.InputInt3(1));
      break;
    }
    case kMipsI8x16AddSaturateU: {
2213
      CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2214 2215 2216 2217 2218
      __ adds_u_b(i.OutputSimd128Register(), i.InputSimd128Register(0),
                  i.InputSimd128Register(1));
      break;
    }
    case kMipsI8x16SubSaturateU: {
2219
      CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2220 2221 2222 2223 2224
      __ subs_u_b(i.OutputSimd128Register(), i.InputSimd128Register(0),
                  i.InputSimd128Register(1));
      break;
    }
    case kMipsI8x16MaxU: {
2225
      CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2226 2227 2228 2229 2230
      __ max_u_b(i.OutputSimd128Register(), i.InputSimd128Register(0),
                 i.InputSimd128Register(1));
      break;
    }
    case kMipsI8x16MinU: {
2231
      CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2232 2233 2234 2235 2236
      __ min_u_b(i.OutputSimd128Register(), i.InputSimd128Register(0),
                 i.InputSimd128Register(1));
      break;
    }
    case kMipsI8x16GtU: {
2237
      CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2238 2239 2240 2241 2242
      __ clt_u_b(i.OutputSimd128Register(), i.InputSimd128Register(1),
                 i.InputSimd128Register(0));
      break;
    }
    case kMipsI8x16GeU: {
2243
      CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2244 2245 2246 2247 2248
      __ cle_u_b(i.OutputSimd128Register(), i.InputSimd128Register(1),
                 i.InputSimd128Register(0));
      break;
    }
    case kMipsS128And: {
2249
      CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2250 2251 2252 2253 2254
      __ and_v(i.OutputSimd128Register(), i.InputSimd128Register(0),
               i.InputSimd128Register(1));
      break;
    }
    case kMipsS128Or: {
2255
      CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2256 2257 2258 2259 2260
      __ or_v(i.OutputSimd128Register(), i.InputSimd128Register(0),
              i.InputSimd128Register(1));
      break;
    }
    case kMipsS128Xor: {
2261
      CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2262 2263 2264 2265 2266
      __ xor_v(i.OutputSimd128Register(), i.InputSimd128Register(0),
               i.InputSimd128Register(1));
      break;
    }
    case kMipsS128Not: {
2267
      CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2268 2269 2270 2271
      __ nor_v(i.OutputSimd128Register(), i.InputSimd128Register(0),
               i.InputSimd128Register(0));
      break;
    }
2272 2273 2274
    case kMipsS1x4AnyTrue:
    case kMipsS1x8AnyTrue:
    case kMipsS1x16AnyTrue: {
2275
      CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286
      Register dst = i.OutputRegister();
      Label all_false;

      __ BranchMSA(&all_false, MSA_BRANCH_V, all_zero,
                   i.InputSimd128Register(0), USE_DELAY_SLOT);
      __ li(dst, 0);  // branch delay slot
      __ li(dst, -1);
      __ bind(&all_false);
      break;
    }
    case kMipsS1x4AllTrue: {
2287
      CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2288 2289 2290 2291 2292 2293 2294 2295 2296 2297
      Register dst = i.OutputRegister();
      Label all_true;
      __ BranchMSA(&all_true, MSA_BRANCH_W, all_not_zero,
                   i.InputSimd128Register(0), USE_DELAY_SLOT);
      __ li(dst, -1);  // branch delay slot
      __ li(dst, 0);
      __ bind(&all_true);
      break;
    }
    case kMipsS1x8AllTrue: {
2298
      CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2299 2300 2301 2302 2303 2304 2305 2306 2307 2308
      Register dst = i.OutputRegister();
      Label all_true;
      __ BranchMSA(&all_true, MSA_BRANCH_H, all_not_zero,
                   i.InputSimd128Register(0), USE_DELAY_SLOT);
      __ li(dst, -1);  // branch delay slot
      __ li(dst, 0);
      __ bind(&all_true);
      break;
    }
    case kMipsS1x16AllTrue: {
2309
      CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2310 2311 2312 2313 2314 2315 2316 2317 2318 2319
      Register dst = i.OutputRegister();
      Label all_true;
      __ BranchMSA(&all_true, MSA_BRANCH_B, all_not_zero,
                   i.InputSimd128Register(0), USE_DELAY_SLOT);
      __ li(dst, -1);  // branch delay slot
      __ li(dst, 0);
      __ bind(&all_true);
      break;
    }
    case kMipsMsaLd: {
2320
      CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2321 2322 2323 2324
      __ ld_b(i.OutputSimd128Register(), i.MemoryOperand());
      break;
    }
    case kMipsMsaSt: {
2325
      CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2326 2327 2328
      __ st_b(i.InputSimd128Register(2), i.MemoryOperand());
      break;
    }
2329
    case kMipsS32x4InterleaveRight: {
2330
      CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2331 2332 2333 2334 2335 2336 2337 2338 2339
      Simd128Register dst = i.OutputSimd128Register(),
                      src0 = i.InputSimd128Register(0),
                      src1 = i.InputSimd128Register(1);
      // src1 = [7, 6, 5, 4], src0 = [3, 2, 1, 0]
      // dst = [5, 1, 4, 0]
      __ ilvr_w(dst, src1, src0);
      break;
    }
    case kMipsS32x4InterleaveLeft: {
2340
      CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2341 2342 2343 2344 2345 2346 2347 2348 2349
      Simd128Register dst = i.OutputSimd128Register(),
                      src0 = i.InputSimd128Register(0),
                      src1 = i.InputSimd128Register(1);
      // src1 = [7, 6, 5, 4], src0 = [3, 2, 1, 0]
      // dst = [7, 3, 6, 2]
      __ ilvl_w(dst, src1, src0);
      break;
    }
    case kMipsS32x4PackEven: {
2350
      CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2351 2352 2353 2354 2355 2356 2357 2358 2359
      Simd128Register dst = i.OutputSimd128Register(),
                      src0 = i.InputSimd128Register(0),
                      src1 = i.InputSimd128Register(1);
      // src1 = [7, 6, 5, 4], src0 = [3, 2, 1, 0]
      // dst = [6, 4, 2, 0]
      __ pckev_w(dst, src1, src0);
      break;
    }
    case kMipsS32x4PackOdd: {
2360
      CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2361 2362 2363 2364 2365 2366 2367 2368 2369
      Simd128Register dst = i.OutputSimd128Register(),
                      src0 = i.InputSimd128Register(0),
                      src1 = i.InputSimd128Register(1);
      // src1 = [7, 6, 5, 4], src0 = [3, 2, 1, 0]
      // dst = [7, 5, 3, 1]
      __ pckod_w(dst, src1, src0);
      break;
    }
    case kMipsS32x4InterleaveEven: {
2370
      CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2371 2372 2373 2374 2375 2376 2377 2378 2379
      Simd128Register dst = i.OutputSimd128Register(),
                      src0 = i.InputSimd128Register(0),
                      src1 = i.InputSimd128Register(1);
      // src1 = [7, 6, 5, 4], src0 = [3, 2, 1, 0]
      // dst = [6, 2, 4, 0]
      __ ilvev_w(dst, src1, src0);
      break;
    }
    case kMipsS32x4InterleaveOdd: {
2380
      CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2381 2382 2383 2384 2385 2386 2387 2388 2389
      Simd128Register dst = i.OutputSimd128Register(),
                      src0 = i.InputSimd128Register(0),
                      src1 = i.InputSimd128Register(1);
      // src1 = [7, 6, 5, 4], src0 = [3, 2, 1, 0]
      // dst = [7, 3, 5, 1]
      __ ilvod_w(dst, src1, src0);
      break;
    }
    case kMipsS32x4Shuffle: {
2390
      CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2391 2392 2393 2394 2395 2396
      Simd128Register dst = i.OutputSimd128Register(),
                      src0 = i.InputSimd128Register(0),
                      src1 = i.InputSimd128Register(1);

      int32_t shuffle = i.InputInt32(2);

2397
      if (src0 == src1) {
2398
        // Unary S32x4 shuffles are handled with shf.w instruction
2399
        unsigned lane = shuffle & 0xFF;
2400 2401 2402 2403 2404 2405 2406
        if (FLAG_debug_code) {
          // range of all four lanes, for unary instruction,
          // should belong to the same range, which can be one of these:
          // [0, 3] or [4, 7]
          if (lane >= 4) {
            int32_t shuffle_helper = shuffle;
            for (int i = 0; i < 4; ++i) {
2407
              lane = shuffle_helper & 0xFF;
2408 2409 2410 2411 2412
              CHECK_GE(lane, 4);
              shuffle_helper >>= 8;
            }
          }
        }
2413 2414
        uint32_t i8 = 0;
        for (int i = 0; i < 4; i++) {
2415
          lane = shuffle & 0xFF;
2416 2417 2418
          if (lane >= 4) {
            lane -= 4;
          }
2419
          DCHECK_GT(4, lane);
2420 2421 2422 2423 2424 2425
          i8 |= lane << (2 * i);
          shuffle >>= 8;
        }
        __ shf_w(dst, src0, i8);
      } else {
        // For binary shuffles use vshf.w instruction
2426
        if (dst == src0) {
2427 2428
          __ move_v(kSimd128ScratchReg, src0);
          src0 = kSimd128ScratchReg;
2429
        } else if (dst == src1) {
2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443
          __ move_v(kSimd128ScratchReg, src1);
          src1 = kSimd128ScratchReg;
        }

        __ li(kScratchReg, i.InputInt32(2));
        __ insert_w(dst, 0, kScratchReg);
        __ xor_v(kSimd128RegZero, kSimd128RegZero, kSimd128RegZero);
        __ ilvr_b(dst, kSimd128RegZero, dst);
        __ ilvr_h(dst, kSimd128RegZero, dst);
        __ vshf_w(dst, src1, src0);
      }
      break;
    }
    case kMipsS16x8InterleaveRight: {
2444
      CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2445 2446 2447 2448 2449 2450 2451 2452 2453
      Simd128Register dst = i.OutputSimd128Register(),
                      src0 = i.InputSimd128Register(0),
                      src1 = i.InputSimd128Register(1);
      // src1 = [15, ... 11, 10, 9, 8], src0 = [7, ... 3, 2, 1, 0]
      // dst = [11, 3, 10, 2, 9, 1, 8, 0]
      __ ilvr_h(dst, src1, src0);
      break;
    }
    case kMipsS16x8InterleaveLeft: {
2454
      CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2455 2456 2457 2458 2459 2460 2461 2462 2463
      Simd128Register dst = i.OutputSimd128Register(),
                      src0 = i.InputSimd128Register(0),
                      src1 = i.InputSimd128Register(1);
      // src1 = [15, ... 11, 10, 9, 8], src0 = [7, ... 3, 2, 1, 0]
      // dst = [15, 7, 14, 6, 13, 5, 12, 4]
      __ ilvl_h(dst, src1, src0);
      break;
    }
    case kMipsS16x8PackEven: {
2464
      CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2465 2466 2467 2468 2469 2470 2471 2472 2473
      Simd128Register dst = i.OutputSimd128Register(),
                      src0 = i.InputSimd128Register(0),
                      src1 = i.InputSimd128Register(1);
      // src1 = [15, ... 11, 10, 9, 8], src0 = [7, ... 3, 2, 1, 0]
      // dst = [14, 12, 10, 8, 6, 4, 2, 0]
      __ pckev_h(dst, src1, src0);
      break;
    }
    case kMipsS16x8PackOdd: {
2474
      CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2475 2476 2477 2478 2479 2480 2481 2482 2483
      Simd128Register dst = i.OutputSimd128Register(),
                      src0 = i.InputSimd128Register(0),
                      src1 = i.InputSimd128Register(1);
      // src1 = [15, ... 11, 10, 9, 8], src0 = [7, ... 3, 2, 1, 0]
      // dst = [15, 13, 11, 9, 7, 5, 3, 1]
      __ pckod_h(dst, src1, src0);
      break;
    }
    case kMipsS16x8InterleaveEven: {
2484
      CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2485 2486 2487 2488 2489 2490 2491 2492 2493
      Simd128Register dst = i.OutputSimd128Register(),
                      src0 = i.InputSimd128Register(0),
                      src1 = i.InputSimd128Register(1);
      // src1 = [15, ... 11, 10, 9, 8], src0 = [7, ... 3, 2, 1, 0]
      // dst = [14, 6, 12, 4, 10, 2, 8, 0]
      __ ilvev_h(dst, src1, src0);
      break;
    }
    case kMipsS16x8InterleaveOdd: {
2494
      CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2495 2496 2497 2498 2499 2500 2501 2502 2503
      Simd128Register dst = i.OutputSimd128Register(),
                      src0 = i.InputSimd128Register(0),
                      src1 = i.InputSimd128Register(1);
      // src1 = [15, ... 11, 10, 9, 8], src0 = [7, ... 3, 2, 1, 0]
      // dst = [15, 7, ... 11, 3, 9, 1]
      __ ilvod_h(dst, src1, src0);
      break;
    }
    case kMipsS16x4Reverse: {
2504
      CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2505 2506 2507 2508 2509 2510
      // src = [7, 6, 5, 4, 3, 2, 1, 0], dst = [4, 5, 6, 7, 0, 1, 2, 3]
      // shf.df imm field: 0 1 2 3 = 00011011 = 0x1B
      __ shf_h(i.OutputSimd128Register(), i.InputSimd128Register(0), 0x1B);
      break;
    }
    case kMipsS16x2Reverse: {
2511
      CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2512 2513 2514 2515 2516 2517
      // src = [7, 6, 5, 4, 3, 2, 1, 0], dst = [6, 7, 4, 5, 3, 2, 0, 1]
      // shf.df imm field: 2 3 0 1 = 10110001 = 0xB1
      __ shf_h(i.OutputSimd128Register(), i.InputSimd128Register(0), 0xB1);
      break;
    }
    case kMipsS8x16InterleaveRight: {
2518
      CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2519 2520 2521 2522 2523 2524 2525 2526 2527
      Simd128Register dst = i.OutputSimd128Register(),
                      src0 = i.InputSimd128Register(0),
                      src1 = i.InputSimd128Register(1);
      // src1 = [31, ... 19, 18, 17, 16], src0 = [15, ... 3, 2, 1, 0]
      // dst = [23, 7, ... 17, 1, 16, 0]
      __ ilvr_b(dst, src1, src0);
      break;
    }
    case kMipsS8x16InterleaveLeft: {
2528
      CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2529 2530 2531 2532 2533 2534 2535 2536 2537
      Simd128Register dst = i.OutputSimd128Register(),
                      src0 = i.InputSimd128Register(0),
                      src1 = i.InputSimd128Register(1);
      // src1 = [31, ... 19, 18, 17, 16], src0 = [15, ... 3, 2, 1, 0]
      // dst = [31, 15, ... 25, 9, 24, 8]
      __ ilvl_b(dst, src1, src0);
      break;
    }
    case kMipsS8x16PackEven: {
2538
      CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2539 2540 2541 2542 2543 2544 2545 2546 2547
      Simd128Register dst = i.OutputSimd128Register(),
                      src0 = i.InputSimd128Register(0),
                      src1 = i.InputSimd128Register(1);
      // src1 = [31, ... 19, 18, 17, 16], src0 = [15, ... 3, 2, 1, 0]
      // dst = [30, 28, ... 6, 4, 2, 0]
      __ pckev_b(dst, src1, src0);
      break;
    }
    case kMipsS8x16PackOdd: {
2548
      CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2549 2550 2551 2552 2553 2554 2555 2556 2557
      Simd128Register dst = i.OutputSimd128Register(),
                      src0 = i.InputSimd128Register(0),
                      src1 = i.InputSimd128Register(1);
      // src1 = [31, ... 19, 18, 17, 16], src0 = [15, ... 3, 2, 1, 0]
      // dst = [31, 29, ... 7, 5, 3, 1]
      __ pckod_b(dst, src1, src0);
      break;
    }
    case kMipsS8x16InterleaveEven: {
2558
      CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2559 2560 2561 2562 2563 2564 2565 2566 2567
      Simd128Register dst = i.OutputSimd128Register(),
                      src0 = i.InputSimd128Register(0),
                      src1 = i.InputSimd128Register(1);
      // src1 = [31, ... 19, 18, 17, 16], src0 = [15, ... 3, 2, 1, 0]
      // dst = [30, 14, ... 18, 2, 16, 0]
      __ ilvev_b(dst, src1, src0);
      break;
    }
    case kMipsS8x16InterleaveOdd: {
2568
      CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2569 2570 2571 2572 2573 2574 2575 2576 2577
      Simd128Register dst = i.OutputSimd128Register(),
                      src0 = i.InputSimd128Register(0),
                      src1 = i.InputSimd128Register(1);
      // src1 = [31, ... 19, 18, 17, 16], src0 = [15, ... 3, 2, 1, 0]
      // dst = [31, 15, ... 19, 3, 17, 1]
      __ ilvod_b(dst, src1, src0);
      break;
    }
    case kMipsS8x16Concat: {
2578
      CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2579
      Simd128Register dst = i.OutputSimd128Register();
2580
      DCHECK(dst == i.InputSimd128Register(0));
2581 2582 2583 2584
      __ sldi_b(dst, i.InputSimd128Register(1), i.InputInt4(2));
      break;
    }
    case kMipsS8x16Shuffle: {
2585
      CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2586 2587 2588 2589
      Simd128Register dst = i.OutputSimd128Register(),
                      src0 = i.InputSimd128Register(0),
                      src1 = i.InputSimd128Register(1);

2590
      if (dst == src0) {
2591 2592
        __ move_v(kSimd128ScratchReg, src0);
        src0 = kSimd128ScratchReg;
2593
      } else if (dst == src1) {
2594 2595 2596 2597 2598 2599 2600 2601 2602 2603 2604 2605 2606 2607 2608 2609
        __ move_v(kSimd128ScratchReg, src1);
        src1 = kSimd128ScratchReg;
      }

      __ li(kScratchReg, i.InputInt32(2));
      __ insert_w(dst, 0, kScratchReg);
      __ li(kScratchReg, i.InputInt32(3));
      __ insert_w(dst, 1, kScratchReg);
      __ li(kScratchReg, i.InputInt32(4));
      __ insert_w(dst, 2, kScratchReg);
      __ li(kScratchReg, i.InputInt32(5));
      __ insert_w(dst, 3, kScratchReg);
      __ vshf_b(dst, src1, src0);
      break;
    }
    case kMipsS8x8Reverse: {
2610
      CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2611 2612 2613 2614 2615 2616 2617 2618 2619
      // src = [15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
      // dst = [8, 9, 10, 11, 12, 13, 14, 15, 0, 1, 2, 3, 4, 5, 6, 7]
      // [A B C D] => [B A D C]: shf.w imm: 2 3 0 1 = 10110001 = 0xB1
      // C: [7, 6, 5, 4] => A': [4, 5, 6, 7]: shf.b imm: 00011011 = 0x1B
      __ shf_w(kSimd128ScratchReg, i.InputSimd128Register(0), 0xB1);
      __ shf_b(i.OutputSimd128Register(), kSimd128ScratchReg, 0x1B);
      break;
    }
    case kMipsS8x4Reverse: {
2620
      CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2621 2622 2623 2624 2625 2626
      // src = [15, 14, ... 3, 2, 1, 0], dst = [12, 13, 14, 15, ... 0, 1, 2, 3]
      // shf.df imm field: 0 1 2 3 = 00011011 = 0x1B
      __ shf_b(i.OutputSimd128Register(), i.InputSimd128Register(0), 0x1B);
      break;
    }
    case kMipsS8x2Reverse: {
2627
      CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2628 2629 2630 2631 2632
      // src = [15, 14, ... 3, 2, 1, 0], dst = [14, 15, 12, 13, ... 2, 3, 0, 1]
      // shf.df imm field: 2 3 0 1 = 10110001 = 0xB1
      __ shf_b(i.OutputSimd128Register(), i.InputSimd128Register(0), 0xB1);
      break;
    }
2633
    case kMipsI32x4SConvertI16x8Low: {
2634
      CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2635 2636 2637 2638 2639 2640 2641 2642
      Simd128Register dst = i.OutputSimd128Register();
      Simd128Register src = i.InputSimd128Register(0);
      __ ilvr_h(kSimd128ScratchReg, src, src);
      __ slli_w(dst, kSimd128ScratchReg, 16);
      __ srai_w(dst, dst, 16);
      break;
    }
    case kMipsI32x4SConvertI16x8High: {
2643
      CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2644 2645 2646 2647 2648 2649 2650 2651
      Simd128Register dst = i.OutputSimd128Register();
      Simd128Register src = i.InputSimd128Register(0);
      __ ilvl_h(kSimd128ScratchReg, src, src);
      __ slli_w(dst, kSimd128ScratchReg, 16);
      __ srai_w(dst, dst, 16);
      break;
    }
    case kMipsI32x4UConvertI16x8Low: {
2652
      CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2653 2654 2655 2656 2657 2658
      __ xor_v(kSimd128RegZero, kSimd128RegZero, kSimd128RegZero);
      __ ilvr_h(i.OutputSimd128Register(), kSimd128RegZero,
                i.InputSimd128Register(0));
      break;
    }
    case kMipsI32x4UConvertI16x8High: {
2659
      CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2660 2661 2662 2663 2664 2665
      __ xor_v(kSimd128RegZero, kSimd128RegZero, kSimd128RegZero);
      __ ilvl_h(i.OutputSimd128Register(), kSimd128RegZero,
                i.InputSimd128Register(0));
      break;
    }
    case kMipsI16x8SConvertI8x16Low: {
2666
      CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2667 2668 2669 2670 2671 2672 2673 2674
      Simd128Register dst = i.OutputSimd128Register();
      Simd128Register src = i.InputSimd128Register(0);
      __ ilvr_b(kSimd128ScratchReg, src, src);
      __ slli_h(dst, kSimd128ScratchReg, 8);
      __ srai_h(dst, dst, 8);
      break;
    }
    case kMipsI16x8SConvertI8x16High: {
2675
      CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2676 2677 2678 2679 2680 2681 2682 2683
      Simd128Register dst = i.OutputSimd128Register();
      Simd128Register src = i.InputSimd128Register(0);
      __ ilvl_b(kSimd128ScratchReg, src, src);
      __ slli_h(dst, kSimd128ScratchReg, 8);
      __ srai_h(dst, dst, 8);
      break;
    }
    case kMipsI16x8SConvertI32x4: {
2684
      CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2685 2686 2687 2688 2689 2690 2691 2692 2693
      Simd128Register dst = i.OutputSimd128Register();
      Simd128Register src0 = i.InputSimd128Register(0);
      Simd128Register src1 = i.InputSimd128Register(1);
      __ sat_s_w(kSimd128ScratchReg, src0, 15);
      __ sat_s_w(kSimd128RegZero, src1, 15);  // kSimd128RegZero as scratch
      __ pckev_h(dst, kSimd128RegZero, kSimd128ScratchReg);
      break;
    }
    case kMipsI16x8UConvertI32x4: {
2694
      CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2695 2696 2697 2698 2699 2700 2701 2702 2703
      Simd128Register dst = i.OutputSimd128Register();
      Simd128Register src0 = i.InputSimd128Register(0);
      Simd128Register src1 = i.InputSimd128Register(1);
      __ sat_u_w(kSimd128ScratchReg, src0, 15);
      __ sat_u_w(kSimd128RegZero, src1, 15);  // kSimd128RegZero as scratch
      __ pckev_h(dst, kSimd128RegZero, kSimd128ScratchReg);
      break;
    }
    case kMipsI16x8UConvertI8x16Low: {
2704
      CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2705 2706 2707 2708 2709 2710
      __ xor_v(kSimd128RegZero, kSimd128RegZero, kSimd128RegZero);
      __ ilvr_b(i.OutputSimd128Register(), kSimd128RegZero,
                i.InputSimd128Register(0));
      break;
    }
    case kMipsI16x8UConvertI8x16High: {
2711
      CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2712 2713 2714 2715 2716 2717
      __ xor_v(kSimd128RegZero, kSimd128RegZero, kSimd128RegZero);
      __ ilvl_b(i.OutputSimd128Register(), kSimd128RegZero,
                i.InputSimd128Register(0));
      break;
    }
    case kMipsI8x16SConvertI16x8: {
2718
      CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2719 2720 2721 2722 2723 2724 2725 2726 2727
      Simd128Register dst = i.OutputSimd128Register();
      Simd128Register src0 = i.InputSimd128Register(0);
      Simd128Register src1 = i.InputSimd128Register(1);
      __ sat_s_h(kSimd128ScratchReg, src0, 7);
      __ sat_s_h(kSimd128RegZero, src1, 7);  // kSimd128RegZero as scratch
      __ pckev_b(dst, kSimd128RegZero, kSimd128ScratchReg);
      break;
    }
    case kMipsI8x16UConvertI16x8: {
2728
      CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2729 2730 2731 2732 2733 2734 2735 2736
      Simd128Register dst = i.OutputSimd128Register();
      Simd128Register src0 = i.InputSimd128Register(0);
      Simd128Register src1 = i.InputSimd128Register(1);
      __ sat_u_h(kSimd128ScratchReg, src0, 7);
      __ sat_u_h(kSimd128RegZero, src1, 7);  // kSimd128RegZero as scratch
      __ pckev_b(dst, kSimd128RegZero, kSimd128ScratchReg);
      break;
    }
2737
    case kMipsF32x4AddHoriz: {
2738
      CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2739 2740 2741 2742 2743 2744 2745 2746 2747 2748 2749
      Simd128Register src0 = i.InputSimd128Register(0);
      Simd128Register src1 = i.InputSimd128Register(1);
      Simd128Register dst = i.OutputSimd128Register();
      __ shf_w(kSimd128ScratchReg, src0, 0xB1);  // 2 3 0 1 : 10110001 : 0xB1
      __ shf_w(kSimd128RegZero, src1, 0xB1);     // kSimd128RegZero as scratch
      __ fadd_w(kSimd128ScratchReg, kSimd128ScratchReg, src0);
      __ fadd_w(kSimd128RegZero, kSimd128RegZero, src1);
      __ pckev_w(dst, kSimd128RegZero, kSimd128ScratchReg);
      break;
    }
    case kMipsI32x4AddHoriz: {
2750
      CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2751 2752 2753 2754 2755 2756 2757 2758 2759
      Simd128Register src0 = i.InputSimd128Register(0);
      Simd128Register src1 = i.InputSimd128Register(1);
      Simd128Register dst = i.OutputSimd128Register();
      __ hadd_s_d(kSimd128ScratchReg, src0, src0);
      __ hadd_s_d(kSimd128RegZero, src1, src1);  // kSimd128RegZero as scratch
      __ pckev_w(dst, kSimd128RegZero, kSimd128ScratchReg);
      break;
    }
    case kMipsI16x8AddHoriz: {
2760
      CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
2761 2762 2763 2764 2765 2766 2767 2768
      Simd128Register src0 = i.InputSimd128Register(0);
      Simd128Register src1 = i.InputSimd128Register(1);
      Simd128Register dst = i.OutputSimd128Register();
      __ hadd_s_w(kSimd128ScratchReg, src0, src0);
      __ hadd_s_w(kSimd128RegZero, src1, src1);  // kSimd128RegZero as scratch
      __ pckev_h(dst, kSimd128RegZero, kSimd128ScratchReg);
      break;
    }
2769
  }
2770
  return kSuccess;
2771
}  // NOLINT(readability/fn_size)
2772 2773


2774
void AssembleBranchToLabels(CodeGenerator* gen, TurboAssembler* tasm,
2775 2776 2777
                            Instruction* instr, FlagsCondition condition,
                            Label* tlabel, Label* flabel, bool fallthru) {
#undef __
2778
#define __ tasm->
2779

2780 2781 2782
  Condition cc = kNoCondition;
  // MIPS does not have condition code flags, so compare and branch are
  // implemented differently than on the other arch's. The compare operations
2783
  // emit mips pseudo-instructions, which are handled here by branch
2784
  // instructions that do the actual comparison. Essential that the input
2785
  // registers to compare pseudo-op are not modified before this branch op, as
2786 2787
  // they are tested here.

2788
  MipsOperandConverter i(gen, instr);
2789
  if (instr->arch_opcode() == kMipsTst) {
2790
    cc = FlagsConditionToConditionTst(condition);
2791
    __ Branch(tlabel, cc, kScratchReg, Operand(zero_reg));
2792 2793 2794
  } else if (instr->arch_opcode() == kMipsAddOvf ||
             instr->arch_opcode() == kMipsSubOvf) {
    // Overflow occurs if overflow register is negative
2795
    switch (condition) {
2796
      case kOverflow:
2797
        __ Branch(tlabel, lt, kScratchReg, Operand(zero_reg));
2798 2799
        break;
      case kNotOverflow:
2800
        __ Branch(tlabel, ge, kScratchReg, Operand(zero_reg));
2801 2802
        break;
      default:
2803
        UNSUPPORTED_COND(instr->arch_opcode(), condition);
2804 2805
        break;
    }
2806
  } else if (instr->arch_opcode() == kMipsMulOvf) {
2807
    // Overflow occurs if overflow register is not zero
2808
    switch (condition) {
2809
      case kOverflow:
2810
        __ Branch(tlabel, ne, kScratchReg, Operand(zero_reg));
2811 2812
        break;
      case kNotOverflow:
2813
        __ Branch(tlabel, eq, kScratchReg, Operand(zero_reg));
2814 2815
        break;
      default:
2816
        UNSUPPORTED_COND(kMipsMulOvf, condition);
2817 2818
        break;
    }
2819
  } else if (instr->arch_opcode() == kMipsCmp) {
2820
    cc = FlagsConditionToConditionCmp(condition);
2821
    __ Branch(tlabel, cc, i.InputRegister(0), i.InputOperand(1));
2822 2823 2824 2825 2826 2827 2828 2829
  } else if (instr->arch_opcode() == kMipsCmpS ||
             instr->arch_opcode() == kMipsCmpD) {
    bool predicate;
    FlagsConditionToConditionCmpFPU(predicate, condition);
    if (predicate) {
      __ BranchTrueF(tlabel);
    } else {
      __ BranchFalseF(tlabel);
2830
    }
2831 2832 2833 2834 2835
  } else {
    PrintF("AssembleArchBranch Unimplemented arch_opcode: %d\n",
           instr->arch_opcode());
    UNIMPLEMENTED();
  }
2836 2837
  if (!fallthru) __ Branch(flabel);  // no fallthru to flabel.
#undef __
2838
#define __ tasm()->
2839 2840 2841 2842 2843 2844
}

// Assembles branches after an instruction.
void CodeGenerator::AssembleArchBranch(Instruction* instr, BranchInfo* branch) {
  Label* tlabel = branch->true_label;
  Label* flabel = branch->false_label;
2845
  AssembleBranchToLabels(this, tasm(), instr, branch->condition, tlabel, flabel,
2846
                         branch->fallthru);
2847 2848
}

2849 2850
void CodeGenerator::AssembleBranchPoisoning(FlagsCondition condition,
                                            Instruction* instr) {
2851 2852 2853 2854 2855
  // TODO(jarin) Handle float comparisons (kUnordered[Not]Equal).
  if (condition == kUnorderedEqual || condition == kUnorderedNotEqual) {
    return;
  }

2856 2857 2858 2859 2860 2861 2862 2863 2864 2865 2866 2867 2868 2869 2870 2871 2872 2873 2874 2875 2876 2877 2878 2879 2880 2881 2882 2883 2884 2885 2886 2887 2888 2889 2890 2891 2892 2893 2894 2895 2896 2897 2898 2899 2900 2901 2902 2903 2904 2905 2906 2907 2908 2909 2910 2911 2912 2913 2914
  MipsOperandConverter i(this, instr);
  condition = NegateFlagsCondition(condition);

  switch (instr->arch_opcode()) {
    case kMipsCmp: {
      __ LoadZeroOnCondition(kSpeculationPoisonRegister, i.InputRegister(0),
                             i.InputOperand(1),
                             FlagsConditionToConditionCmp(condition));
    }
      return;
    case kMipsTst: {
      switch (condition) {
        case kEqual:
          __ LoadZeroIfConditionZero(kSpeculationPoisonRegister, kScratchReg);
          break;
        case kNotEqual:
          __ LoadZeroIfConditionNotZero(kSpeculationPoisonRegister,
                                        kScratchReg);
          break;
        default:
          UNREACHABLE();
      }
    }
      return;
    case kMipsAddOvf:
    case kMipsSubOvf: {
      // Overflow occurs if overflow register is negative
      __ Slt(kScratchReg2, kScratchReg, zero_reg);
      switch (condition) {
        case kOverflow:
          __ LoadZeroIfConditionNotZero(kSpeculationPoisonRegister,
                                        kScratchReg2);
          break;
        case kNotOverflow:
          __ LoadZeroIfConditionZero(kSpeculationPoisonRegister, kScratchReg2);
          break;
        default:
          UNSUPPORTED_COND(instr->arch_opcode(), condition);
      }
    }
      return;
    case kMipsMulOvf: {
      // Overflow occurs if overflow register is not zero
      switch (condition) {
        case kOverflow:
          __ LoadZeroIfConditionNotZero(kSpeculationPoisonRegister,
                                        kScratchReg);
          break;
        case kNotOverflow:
          __ LoadZeroIfConditionZero(kSpeculationPoisonRegister, kScratchReg);
          break;
        default:
          UNSUPPORTED_COND(instr->arch_opcode(), condition);
      }
    }
      return;
    default:
      break;
  }
2915 2916
}

2917 2918 2919 2920
void CodeGenerator::AssembleArchDeoptBranch(Instruction* instr,
                                            BranchInfo* branch) {
  AssembleArchBranch(instr, branch);
}
2921

2922
void CodeGenerator::AssembleArchJump(RpoNumber target) {
2923 2924 2925
  if (!IsNextInAssemblyOrder(target)) __ Branch(GetLabel(target));
}

2926 2927
void CodeGenerator::AssembleArchTrap(Instruction* instr,
                                     FlagsCondition condition) {
2928 2929 2930 2931 2932 2933 2934 2935 2936 2937 2938
  class OutOfLineTrap final : public OutOfLineCode {
   public:
    OutOfLineTrap(CodeGenerator* gen, bool frame_elided, Instruction* instr)
        : OutOfLineCode(gen),
          frame_elided_(frame_elided),
          instr_(instr),
          gen_(gen) {}

    void Generate() final {
      MipsOperandConverter i(gen_, instr_);

2939 2940
      Builtins::Name trap_id =
          static_cast<Builtins::Name>(i.InputInt32(instr_->InputCount() - 1));
2941 2942 2943 2944 2945 2946 2947 2948 2949 2950 2951 2952
      bool old_has_frame = __ has_frame();
      if (frame_elided_) {
        __ set_has_frame(true);
        __ EnterFrame(StackFrame::WASM_COMPILED);
      }
      GenerateCallToTrap(trap_id);
      if (frame_elided_) {
        __ set_has_frame(old_has_frame);
      }
    }

   private:
2953 2954
    void GenerateCallToTrap(Builtins::Name trap_id) {
      if (trap_id == Builtins::builtin_count) {
2955 2956 2957 2958 2959
        // We cannot test calls to the runtime in cctest/test-run-wasm.
        // Therefore we emit a call to C here instead of a call to the runtime.
        // We use the context register as the scratch register, because we do
        // not have a context here.
        __ PrepareCallCFunction(0, 0, cp);
2960 2961
        __ CallCFunction(
            ExternalReference::wasm_call_trap_callback_for_testing(), 0);
2962
        __ LeaveFrame(StackFrame::WASM_COMPILED);
2963 2964 2965
        auto call_descriptor = gen_->linkage()->GetIncomingDescriptor();
        int pop_count =
            static_cast<int>(call_descriptor->StackParameterCount());
2966
        __ Drop(pop_count);
2967
        __ Ret();
2968 2969
      } else {
        gen_->AssembleSourcePosition(instr_);
2970
        __ Call(tasm()->isolate()->builtins()->builtin_handle(trap_id),
2971
                RelocInfo::CODE_TARGET);
2972 2973 2974 2975 2976
        ReferenceMap* reference_map =
            new (gen_->zone()) ReferenceMap(gen_->zone());
        gen_->RecordSafepoint(reference_map, Safepoint::kSimple, 0,
                              Safepoint::kNoLazyDeopt);
        if (FLAG_debug_code) {
2977
          __ stop(GetAbortReason(AbortReason::kUnexpectedReturnFromWasmTrap));
2978
        }
2979 2980 2981 2982 2983 2984 2985 2986 2987 2988
      }
    }

    bool frame_elided_;
    Instruction* instr_;
    CodeGenerator* gen_;
  };
  bool frame_elided = !frame_access_state()->has_frame();
  auto ool = new (zone()) OutOfLineTrap(this, frame_elided, instr);
  Label* tlabel = ool->entry();
2989
  AssembleBranchToLabels(this, tasm(), instr, condition, tlabel, nullptr, true);
2990
}
2991

2992 2993 2994 2995 2996 2997 2998 2999 3000
// Assembles boolean materializations after an instruction.
void CodeGenerator::AssembleArchBoolean(Instruction* instr,
                                        FlagsCondition condition) {
  MipsOperandConverter i(this, instr);
  Label done;

  // Materialize a full 32-bit 1 or 0 value. The result register is always the
  // last output of the instruction.
  Label false_value;
3001
  DCHECK_NE(0u, instr->OutputCount());
3002 3003 3004 3005
  Register result = i.OutputRegister(instr->OutputCount() - 1);
  Condition cc = kNoCondition;
  // MIPS does not have condition code flags, so compare and branch are
  // implemented differently than on the other arch's. The compare operations
3006
  // emit mips pseudo-instructions, which are checked and handled here.
3007 3008

  if (instr->arch_opcode() == kMipsTst) {
3009
    cc = FlagsConditionToConditionTst(condition);
3010 3011
    if (cc == eq) {
      __ Sltu(result, kScratchReg, 1);
3012
    } else {
3013
      __ Sltu(result, zero_reg, kScratchReg);
3014 3015
    }
    return;
3016
  } else if (instr->arch_opcode() == kMipsAddOvf ||
3017 3018 3019 3020 3021 3022
             instr->arch_opcode() == kMipsSubOvf) {
    // Overflow occurs if overflow register is negative
    __ slt(result, kScratchReg, zero_reg);
  } else if (instr->arch_opcode() == kMipsMulOvf) {
    // Overflow occurs if overflow register is not zero
    __ Sgtu(result, kScratchReg, zero_reg);
3023
  } else if (instr->arch_opcode() == kMipsCmp) {
3024
    cc = FlagsConditionToConditionCmp(condition);
3025 3026 3027 3028 3029
    switch (cc) {
      case eq:
      case ne: {
        Register left = i.InputRegister(0);
        Operand right = i.InputOperand(1);
3030 3031 3032 3033 3034 3035 3036 3037 3038 3039 3040 3041 3042 3043 3044 3045 3046 3047 3048 3049 3050 3051 3052 3053 3054 3055 3056 3057 3058
        if (instr->InputAt(1)->IsImmediate()) {
          if (is_int16(-right.immediate())) {
            if (right.immediate() == 0) {
              if (cc == eq) {
                __ Sltu(result, left, 1);
              } else {
                __ Sltu(result, zero_reg, left);
              }
            } else {
              __ Addu(result, left, -right.immediate());
              if (cc == eq) {
                __ Sltu(result, result, 1);
              } else {
                __ Sltu(result, zero_reg, result);
              }
            }
          } else {
            if (is_uint16(right.immediate())) {
              __ Xor(result, left, right);
            } else {
              __ li(kScratchReg, right);
              __ Xor(result, left, kScratchReg);
            }
            if (cc == eq) {
              __ Sltu(result, result, 1);
            } else {
              __ Sltu(result, zero_reg, result);
            }
          }
3059
        } else {
3060 3061 3062 3063 3064 3065
          __ Xor(result, left, right);
          if (cc == eq) {
            __ Sltu(result, result, 1);
          } else {
            __ Sltu(result, zero_reg, result);
          }
3066 3067 3068 3069 3070 3071 3072 3073 3074 3075 3076 3077 3078 3079 3080 3081 3082 3083 3084 3085 3086 3087 3088 3089 3090 3091 3092 3093 3094 3095 3096 3097 3098 3099 3100 3101 3102 3103 3104 3105 3106 3107
        }
      } break;
      case lt:
      case ge: {
        Register left = i.InputRegister(0);
        Operand right = i.InputOperand(1);
        __ Slt(result, left, right);
        if (cc == ge) {
          __ xori(result, result, 1);
        }
      } break;
      case gt:
      case le: {
        Register left = i.InputRegister(1);
        Operand right = i.InputOperand(0);
        __ Slt(result, left, right);
        if (cc == le) {
          __ xori(result, result, 1);
        }
      } break;
      case lo:
      case hs: {
        Register left = i.InputRegister(0);
        Operand right = i.InputOperand(1);
        __ Sltu(result, left, right);
        if (cc == hs) {
          __ xori(result, result, 1);
        }
      } break;
      case hi:
      case ls: {
        Register left = i.InputRegister(1);
        Operand right = i.InputOperand(0);
        __ Sltu(result, left, right);
        if (cc == ls) {
          __ xori(result, result, 1);
        }
      } break;
      default:
        UNREACHABLE();
    }
    return;
3108 3109
  } else if (instr->arch_opcode() == kMipsCmpD ||
             instr->arch_opcode() == kMipsCmpS) {
3110 3111
    FPURegister left = i.InputOrZeroDoubleRegister(0);
    FPURegister right = i.InputOrZeroDoubleRegister(1);
3112
    if ((left == kDoubleRegZero || right == kDoubleRegZero) &&
3113 3114 3115
        !__ IsDoubleZeroRegSet()) {
      __ Move(kDoubleRegZero, 0.0);
    }
3116
    bool predicate;
3117
    FlagsConditionToConditionCmpFPU(predicate, condition);
3118 3119 3120 3121 3122 3123 3124 3125
    if (!IsMipsArchVariant(kMips32r6)) {
      __ li(result, Operand(1));
      if (predicate) {
        __ Movf(result, zero_reg);
      } else {
        __ Movt(result, zero_reg);
      }
    } else {
3126
      __ mfc1(result, kDoubleCompareReg);
3127 3128 3129 3130 3131
      if (predicate) {
        __ And(result, result, 1);  // cmp returns all 1's/0's, use only LSB.
      } else {
        __ Addu(result, result, 1);  // Toggle result for not equal.
      }
3132 3133
    }
    return;
3134
  } else {
3135
    PrintF("AssembleArchBoolean Unimplemented arch_opcode is : %d\n",
3136 3137 3138 3139 3140 3141 3142
           instr->arch_opcode());
    TRACE_UNIMPL();
    UNIMPLEMENTED();
  }
}


3143 3144 3145 3146
void CodeGenerator::AssembleArchLookupSwitch(Instruction* instr) {
  MipsOperandConverter i(this, instr);
  Register input = i.InputRegister(0);
  for (size_t index = 2; index < instr->InputCount(); index += 2) {
3147 3148
    __ li(kScratchReg, Operand(i.InputInt32(index + 0)));
    __ Branch(GetLabel(i.InputRpo(index + 1)), eq, input, Operand(kScratchReg));
3149 3150 3151 3152 3153 3154 3155 3156 3157 3158
  }
  AssembleArchJump(i.InputRpo(1));
}


void CodeGenerator::AssembleArchTableSwitch(Instruction* instr) {
  MipsOperandConverter i(this, instr);
  Register input = i.InputRegister(0);
  size_t const case_count = instr->InputCount() - 2;
  __ Branch(GetLabel(i.InputRpo(1)), hs, input, Operand(case_count));
3159 3160 3161
  __ GenerateSwitchTable(input, case_count, [&i, this](size_t index) {
    return GetLabel(i.InputRpo(index + 2));
  });
3162 3163
}

3164
void CodeGenerator::FinishFrame(Frame* frame) {
3165
  auto call_descriptor = linkage()->GetIncomingDescriptor();
3166

3167
  const RegList saves_fpu = call_descriptor->CalleeSavedFPRegisters();
3168
  if (saves_fpu != 0) {
3169 3170 3171 3172
    frame->AlignSavedCalleeRegisterSlots();
  }

  if (saves_fpu != 0) {
3173
    int count = base::bits::CountPopulation(saves_fpu);
3174
    DCHECK_EQ(kNumCalleeSavedFPU, count);
3175 3176 3177 3178
    frame->AllocateSavedCalleeRegisterSlots(count *
                                            (kDoubleSize / kPointerSize));
  }

3179
  const RegList saves = call_descriptor->CalleeSavedRegisters();
3180
  if (saves != 0) {
3181
    int count = base::bits::CountPopulation(saves);
3182
    DCHECK_EQ(kNumCalleeSaved, count + 1);
3183 3184 3185 3186 3187
    frame->AllocateSavedCalleeRegisterSlots(count);
  }
}

void CodeGenerator::AssembleConstructFrame() {
3188
  auto call_descriptor = linkage()->GetIncomingDescriptor();
3189
  if (frame_access_state()->has_frame()) {
3190
    if (call_descriptor->IsCFunctionCall()) {
3191 3192
      __ Push(ra, fp);
      __ mov(fp, sp);
3193
    } else if (call_descriptor->IsJSFunctionCall()) {
3194
      __ Prologue();
3195
      if (call_descriptor->PushArgumentCount()) {
3196 3197
        __ Push(kJavaScriptCallArgCountRegister);
      }
3198 3199
    } else {
      __ StubPrologue(info()->GetOutputStackFrameType());
3200 3201 3202
      if (call_descriptor->IsWasmFunctionCall()) {
        __ Push(kWasmInstanceRegister);
      }
3203
    }
3204
  }
3205

3206 3207
  int shrink_slots = frame()->GetTotalFrameSlotCount() -
                     call_descriptor->CalculateFixedFrameSize();
3208

3209 3210
  if (info()->is_osr()) {
    // TurboFan OSR-compiled functions cannot be entered directly.
3211
    __ Abort(AbortReason::kShouldNotDirectlyEnterOsrFunction);
3212 3213 3214 3215 3216 3217 3218

    // Unoptimized code jumps directly to this entrypoint while the unoptimized
    // frame is still on the stack. Optimized code uses OSR values directly from
    // the unoptimized frame. Thus, all that needs to be done is to allocate the
    // remaining stack slots.
    if (FLAG_code_comments) __ RecordComment("-- OSR entrypoint --");
    osr_pc_offset_ = __ pc_offset();
3219
    shrink_slots -= osr_helper()->UnoptimizedFrameSlots();
3220
    ResetSpeculationPoison();
3221 3222
  }

3223 3224
  const RegList saves = call_descriptor->CalleeSavedRegisters();
  const RegList saves_fpu = call_descriptor->CalleeSavedFPRegisters();
3225
  const int returns = frame()->GetReturnSlotCount();
3226

3227
  // Skip callee-saved and return slots, which are pushed below.
3228 3229
  shrink_slots -= base::bits::CountPopulation(saves);
  shrink_slots -= 2 * base::bits::CountPopulation(saves_fpu);
3230
  shrink_slots -= returns;
3231 3232
  if (shrink_slots > 0) {
    __ Subu(sp, sp, Operand(shrink_slots * kPointerSize));
3233 3234 3235 3236 3237
  }

  // Save callee-saved FPU registers.
  if (saves_fpu != 0) {
    __ MultiPushFPU(saves_fpu);
3238 3239
  }

3240 3241 3242
  if (saves != 0) {
    // Save callee-saved registers.
    __ MultiPush(saves);
3243
    DCHECK_EQ(kNumCalleeSaved, base::bits::CountPopulation(saves) + 1);
3244
  }
3245 3246 3247 3248 3249

  if (returns != 0) {
    // Create space for returns.
    __ Subu(sp, sp, Operand(returns * kPointerSize));
  }
3250 3251
}

3252
void CodeGenerator::AssembleReturn(InstructionOperand* pop) {
3253 3254
  auto call_descriptor = linkage()->GetIncomingDescriptor();
  int pop_count = static_cast<int>(call_descriptor->StackParameterCount());
3255

3256 3257 3258 3259 3260
  const int returns = frame()->GetReturnSlotCount();
  if (returns != 0) {
    __ Addu(sp, sp, Operand(returns * kPointerSize));
  }

3261
  // Restore GP registers.
3262
  const RegList saves = call_descriptor->CalleeSavedRegisters();
3263 3264 3265 3266 3267
  if (saves != 0) {
    __ MultiPop(saves);
  }

  // Restore FPU registers.
3268
  const RegList saves_fpu = call_descriptor->CalleeSavedFPRegisters();
3269 3270 3271 3272
  if (saves_fpu != 0) {
    __ MultiPopFPU(saves_fpu);
  }

3273
  MipsOperandConverter g(this, nullptr);
3274
  if (call_descriptor->IsCFunctionCall()) {
3275 3276
    AssembleDeconstructFrame();
  } else if (frame_access_state()->has_frame()) {
3277 3278 3279 3280 3281 3282 3283 3284 3285 3286
    // Canonicalize JSFunction return sites for now unless they have an variable
    // number of stack slot pops.
    if (pop->IsImmediate() && g.ToConstant(pop).ToInt32() == 0) {
      if (return_label_.is_bound()) {
        __ Branch(&return_label_);
        return;
      } else {
        __ bind(&return_label_);
        AssembleDeconstructFrame();
      }
3287
    } else {
3288
      AssembleDeconstructFrame();
3289
    }
3290
  }
3291 3292 3293 3294 3295 3296 3297 3298
  if (pop->IsImmediate()) {
    DCHECK_EQ(Constant::kInt32, g.ToConstant(pop).type());
    pop_count += g.ToConstant(pop).ToInt32();
  } else {
    Register pop_reg = g.ToRegister(pop);
    __ sll(pop_reg, pop_reg, kPointerSizeLog2);
    __ Addu(sp, sp, Operand(pop_reg));
  }
3299 3300
  if (pop_count != 0) {
    __ DropAndRet(pop_count);
3301 3302
  } else {
    __ Ret();
3303 3304 3305
  }
}

3306
void CodeGenerator::FinishCode() {}
3307 3308 3309

void CodeGenerator::AssembleMove(InstructionOperand* source,
                                 InstructionOperand* destination) {
3310
  MipsOperandConverter g(this, nullptr);
3311 3312 3313 3314 3315 3316 3317 3318 3319 3320 3321 3322 3323 3324 3325 3326 3327 3328 3329 3330 3331 3332 3333 3334 3335 3336 3337
  // Dispatch on the source and destination operand kinds.  Not all
  // combinations are possible.
  if (source->IsRegister()) {
    DCHECK(destination->IsRegister() || destination->IsStackSlot());
    Register src = g.ToRegister(source);
    if (destination->IsRegister()) {
      __ mov(g.ToRegister(destination), src);
    } else {
      __ sw(src, g.ToMemOperand(destination));
    }
  } else if (source->IsStackSlot()) {
    DCHECK(destination->IsRegister() || destination->IsStackSlot());
    MemOperand src = g.ToMemOperand(source);
    if (destination->IsRegister()) {
      __ lw(g.ToRegister(destination), src);
    } else {
      Register temp = kScratchReg;
      __ lw(temp, src);
      __ sw(temp, g.ToMemOperand(destination));
    }
  } else if (source->IsConstant()) {
    Constant src = g.ToConstant(source);
    if (destination->IsRegister() || destination->IsStackSlot()) {
      Register dst =
          destination->IsRegister() ? g.ToRegister(destination) : kScratchReg;
      switch (src.type()) {
        case Constant::kInt32:
3338
          if (RelocInfo::IsWasmReference(src.rmode())) {
3339 3340 3341 3342
            __ li(dst, Operand(src.ToInt32(), src.rmode()));
          } else {
            __ li(dst, Operand(src.ToInt32()));
          }
3343 3344
          break;
        case Constant::kFloat32:
3345
          __ li(dst, Operand::EmbeddedNumber(src.ToFloat32()));
3346 3347 3348 3349 3350
          break;
        case Constant::kInt64:
          UNREACHABLE();
          break;
        case Constant::kFloat64:
3351
          __ li(dst, Operand::EmbeddedNumber(src.ToFloat64().value()));
3352 3353 3354 3355
          break;
        case Constant::kExternalReference:
          __ li(dst, Operand(src.ToExternalReference()));
          break;
3356 3357
        case Constant::kHeapObject: {
          Handle<HeapObject> src_object = src.ToHeapObject();
3358
          Heap::RootListIndex index;
3359
          if (IsMaterializableFromRoot(src_object, &index)) {
3360
            __ LoadRoot(dst, index);
3361 3362 3363
          } else {
            __ li(dst, src_object);
          }
3364
          break;
3365
        }
3366 3367 3368
        case Constant::kRpoNumber:
          UNREACHABLE();  // TODO(titzer): loading RPO numbers on mips.
          break;
3369 3370 3371
      }
      if (destination->IsStackSlot()) __ sw(dst, g.ToMemOperand(destination));
    } else if (src.type() == Constant::kFloat32) {
3372
      if (destination->IsFPStackSlot()) {
3373
        MemOperand dst = g.ToMemOperand(destination);
3374 3375 3376
        if (bit_cast<int32_t>(src.ToFloat32()) == 0) {
          __ sw(zero_reg, dst);
        } else {
3377 3378
          __ li(kScratchReg, Operand(bit_cast<int32_t>(src.ToFloat32())));
          __ sw(kScratchReg, dst);
3379
        }
3380
      } else {
3381
        DCHECK(destination->IsFPRegister());
3382 3383
        FloatRegister dst = g.ToSingleRegister(destination);
        __ Move(dst, src.ToFloat32());
3384 3385 3386
      }
    } else {
      DCHECK_EQ(Constant::kFloat64, src.type());
3387
      DoubleRegister dst = destination->IsFPRegister()
3388 3389
                               ? g.ToDoubleRegister(destination)
                               : kScratchDoubleReg;
3390
      __ Move(dst, src.ToFloat64().value());
3391
      if (destination->IsFPStackSlot()) {
3392
        __ Sdc1(dst, g.ToMemOperand(destination));
3393 3394
      }
    }
3395
  } else if (source->IsFPRegister()) {
3396 3397 3398 3399 3400 3401 3402 3403 3404 3405 3406
    MachineRepresentation rep = LocationOperand::cast(source)->representation();
    if (rep == MachineRepresentation::kSimd128) {
      CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
      MSARegister src = g.ToSimd128Register(source);
      if (destination->IsSimd128Register()) {
        MSARegister dst = g.ToSimd128Register(destination);
        __ move_v(dst, src);
      } else {
        DCHECK(destination->IsSimd128StackSlot());
        __ st_b(src, g.ToMemOperand(destination));
      }
3407
    } else {
3408 3409 3410 3411
      FPURegister src = g.ToDoubleRegister(source);
      if (destination->IsFPRegister()) {
        FPURegister dst = g.ToDoubleRegister(destination);
        __ Move(dst, src);
3412
      } else {
3413 3414 3415 3416 3417 3418 3419 3420 3421 3422
        DCHECK(destination->IsFPStackSlot());
        MachineRepresentation rep =
            LocationOperand::cast(source)->representation();
        if (rep == MachineRepresentation::kFloat64) {
          __ Sdc1(src, g.ToMemOperand(destination));
        } else if (rep == MachineRepresentation::kFloat32) {
          __ swc1(src, g.ToMemOperand(destination));
        } else {
          UNREACHABLE();
        }
3423
      }
3424
    }
3425 3426
  } else if (source->IsFPStackSlot()) {
    DCHECK(destination->IsFPRegister() || destination->IsFPStackSlot());
3427
    MemOperand src = g.ToMemOperand(source);
3428
    MachineRepresentation rep = LocationOperand::cast(source)->representation();
3429
    if (destination->IsFPRegister()) {
3430
      if (rep == MachineRepresentation::kFloat64) {
3431
        __ Ldc1(g.ToDoubleRegister(destination), src);
3432
      } else if (rep == MachineRepresentation::kFloat32) {
3433
        __ lwc1(g.ToDoubleRegister(destination), src);
3434 3435
      } else {
        DCHECK_EQ(MachineRepresentation::kSimd128, rep);
3436 3437
        CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
        __ ld_b(g.ToSimd128Register(destination), src);
3438
      }
3439 3440
    } else {
      FPURegister temp = kScratchDoubleReg;
3441
      if (rep == MachineRepresentation::kFloat64) {
3442 3443
        __ Ldc1(temp, src);
        __ Sdc1(temp, g.ToMemOperand(destination));
3444 3445 3446 3447 3448
      } else if (rep == MachineRepresentation::kFloat32) {
        __ lwc1(temp, src);
        __ swc1(temp, g.ToMemOperand(destination));
      } else {
        DCHECK_EQ(MachineRepresentation::kSimd128, rep);
3449 3450 3451 3452
        CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
        MSARegister temp = kSimd128ScratchReg;
        __ ld_b(temp, src);
        __ st_b(temp, g.ToMemOperand(destination));
3453
      }
3454 3455 3456 3457 3458 3459 3460 3461 3462
    }
  } else {
    UNREACHABLE();
  }
}


void CodeGenerator::AssembleSwap(InstructionOperand* source,
                                 InstructionOperand* destination) {
3463
  MipsOperandConverter g(this, nullptr);
3464 3465 3466 3467 3468 3469 3470 3471 3472 3473 3474 3475 3476 3477 3478 3479 3480 3481 3482 3483 3484
  // Dispatch on the source and destination operand kinds.  Not all
  // combinations are possible.
  if (source->IsRegister()) {
    // Register-register.
    Register temp = kScratchReg;
    Register src = g.ToRegister(source);
    if (destination->IsRegister()) {
      Register dst = g.ToRegister(destination);
      __ Move(temp, src);
      __ Move(src, dst);
      __ Move(dst, temp);
    } else {
      DCHECK(destination->IsStackSlot());
      MemOperand dst = g.ToMemOperand(destination);
      __ mov(temp, src);
      __ lw(src, dst);
      __ sw(temp, dst);
    }
  } else if (source->IsStackSlot()) {
    DCHECK(destination->IsStackSlot());
    Register temp_0 = kScratchReg;
3485
    Register temp_1 = kScratchReg2;
3486 3487 3488 3489 3490 3491
    MemOperand src = g.ToMemOperand(source);
    MemOperand dst = g.ToMemOperand(destination);
    __ lw(temp_0, src);
    __ lw(temp_1, dst);
    __ sw(temp_0, dst);
    __ sw(temp_1, src);
3492 3493
  } else if (source->IsFPRegister()) {
    if (destination->IsFPRegister()) {
3494 3495 3496 3497 3498 3499 3500 3501 3502 3503 3504 3505 3506 3507 3508 3509 3510 3511
      MachineRepresentation rep =
          LocationOperand::cast(source)->representation();
      if (rep == MachineRepresentation::kSimd128) {
        CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
        MSARegister temp = kSimd128ScratchReg;
        MSARegister src = g.ToSimd128Register(source);
        MSARegister dst = g.ToSimd128Register(destination);
        __ move_v(temp, src);
        __ move_v(src, dst);
        __ move_v(dst, temp);
      } else {
        FPURegister temp = kScratchDoubleReg;
        FPURegister src = g.ToDoubleRegister(source);
        FPURegister dst = g.ToDoubleRegister(destination);
        __ Move(temp, src);
        __ Move(src, dst);
        __ Move(dst, temp);
      }
3512
    } else {
3513
      DCHECK(destination->IsFPStackSlot());
3514
      MemOperand dst = g.ToMemOperand(destination);
3515 3516 3517
      MachineRepresentation rep =
          LocationOperand::cast(source)->representation();
      if (rep == MachineRepresentation::kFloat64) {
3518 3519
        FPURegister temp = kScratchDoubleReg;
        FPURegister src = g.ToDoubleRegister(source);
3520
        __ Move(temp, src);
3521 3522
        __ Ldc1(src, dst);
        __ Sdc1(temp, dst);
3523
      } else if (rep == MachineRepresentation::kFloat32) {
3524 3525
        FPURegister temp = kScratchDoubleReg;
        FPURegister src = g.ToFloatRegister(source);
3526 3527 3528 3529 3530
        __ Move(temp, src);
        __ lwc1(src, dst);
        __ swc1(temp, dst);
      } else {
        DCHECK_EQ(MachineRepresentation::kSimd128, rep);
3531 3532 3533 3534 3535 3536
        CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
        MSARegister temp = kSimd128ScratchReg;
        MSARegister src = g.ToSimd128Register(source);
        __ move_v(temp, src);
        __ ld_b(src, dst);
        __ st_b(temp, dst);
3537
      }
3538
    }
3539 3540
  } else if (source->IsFPStackSlot()) {
    DCHECK(destination->IsFPStackSlot());
3541 3542 3543 3544
    Register temp_0 = kScratchReg;
    FPURegister temp_1 = kScratchDoubleReg;
    MemOperand src0 = g.ToMemOperand(source);
    MemOperand dst0 = g.ToMemOperand(destination);
3545 3546 3547 3548
    MachineRepresentation rep = LocationOperand::cast(source)->representation();
    if (rep == MachineRepresentation::kFloat64) {
      MemOperand src1(src0.rm(), src0.offset() + kIntSize);
      MemOperand dst1(dst0.rm(), dst0.offset() + kIntSize);
3549
      __ Ldc1(temp_1, dst0);  // Save destination in temp_1.
3550 3551 3552 3553
      __ lw(temp_0, src0);    // Then use temp_0 to copy source to destination.
      __ sw(temp_0, dst0);
      __ lw(temp_0, src1);
      __ sw(temp_0, dst1);
3554
      __ Sdc1(temp_1, src0);
3555 3556 3557 3558 3559 3560 3561
    } else if (rep == MachineRepresentation::kFloat32) {
      __ lwc1(temp_1, dst0);  // Save destination in temp_1.
      __ lw(temp_0, src0);    // Then use temp_0 to copy source to destination.
      __ sw(temp_0, dst0);
      __ swc1(temp_1, src0);
    } else {
      DCHECK_EQ(MachineRepresentation::kSimd128, rep);
3562 3563 3564 3565 3566 3567 3568 3569 3570 3571 3572 3573 3574 3575 3576 3577 3578 3579
      MemOperand src1(src0.rm(), src0.offset() + kIntSize);
      MemOperand dst1(dst0.rm(), dst0.offset() + kIntSize);
      MemOperand src2(src0.rm(), src0.offset() + 2 * kIntSize);
      MemOperand dst2(dst0.rm(), dst0.offset() + 2 * kIntSize);
      MemOperand src3(src0.rm(), src0.offset() + 3 * kIntSize);
      MemOperand dst3(dst0.rm(), dst0.offset() + 3 * kIntSize);
      CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
      MSARegister temp_1 = kSimd128ScratchReg;
      __ ld_b(temp_1, dst0);  // Save destination in temp_1.
      __ lw(temp_0, src0);    // Then use temp_0 to copy source to destination.
      __ sw(temp_0, dst0);
      __ lw(temp_0, src1);
      __ sw(temp_0, dst1);
      __ lw(temp_0, src2);
      __ sw(temp_0, dst2);
      __ lw(temp_0, src3);
      __ sw(temp_0, dst3);
      __ st_b(temp_1, src0);
3580
    }
3581 3582 3583 3584 3585 3586 3587
  } else {
    // No other combinations are possible.
    UNREACHABLE();
  }
}


3588 3589 3590 3591 3592
void CodeGenerator::AssembleJumpTable(Label** targets, size_t target_count) {
  // On 32-bit MIPS we emit the jump tables inline.
  UNREACHABLE();
}

3593 3594 3595 3596 3597
#undef __

}  // namespace compiler
}  // namespace internal
}  // namespace v8