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

5 6 7 8 9
#include "src/mips/simulator-mips.h"

// Only build the simulator if not compiling for real MIPS hardware.
#if defined(USE_SIMULATOR)

10
#include <limits.h>
11 12
#include <stdarg.h>
#include <stdlib.h>
13
#include <cmath>
14

15
#include "src/base/bits.h"
16
#include "src/base/lazy-instance.h"
17 18
#include "src/codegen/assembler-inl.h"
#include "src/codegen/macro-assembler.h"
19
#include "src/diagnostics/disasm.h"
20
#include "src/heap/combined-heap.h"
21
#include "src/mips/constants-mips.h"
22
#include "src/ostreams.h"
23
#include "src/runtime/runtime-utils.h"
24
#include "src/vector.h"
25

26 27
namespace v8 {
namespace internal {
28

29
DEFINE_LAZY_LEAKY_OBJECT_GETTER(Simulator::GlobalMonitor,
Yu Yin's avatar
Yu Yin committed
30
                                Simulator::GlobalMonitor::Get)
31

32
// Utils functions.
33
bool HaveSameSign(int32_t a, int32_t b) {
34 35 36 37 38 39 40 41 42 43
  return ((a ^ b) >= 0);
}


uint32_t get_fcsr_condition_bit(uint32_t cc) {
  if (cc == 0) {
    return 23;
  } else {
    return 24 + cc;
  }
44 45 46 47 48 49 50 51 52
}


// This macro provides a platform independent use of sscanf. The reason for
// SScanF not being implemented in a platform independent was through
// ::v8::internal::OS in the same way as SNPrintF is that the Windows C Run-Time
// Library does not provide vsscanf.
#define SScanF sscanf  // NOLINT

53
// The MipsDebugger class is used by the simulator while debugging simulated
54
// code.
55
class MipsDebugger {
56
 public:
57
  explicit MipsDebugger(Simulator* sim) : sim_(sim) { }
58 59 60

  void Stop(Instruction* instr);
  void Debug();
61 62 63
  // Print all registers with a nice formatting.
  void PrintAllRegs();
  void PrintAllRegsIncludingFPU();
64 65

 private:
66 67
  // We set the breakpoint code to 0xFFFFF to easily recognize it.
  static const Instr kBreakpointInstr = SPECIAL | BREAK | 0xFFFFF << 6;
68 69 70 71 72
  static const Instr kNopInstr =  0x0;

  Simulator* sim_;

  int32_t GetRegisterValue(int regnum);
73 74
  int32_t GetFPURegisterValue32(int regnum);
  int64_t GetFPURegisterValue64(int regnum);
75 76
  float GetFPURegisterValueFloat(int regnum);
  double GetFPURegisterValueDouble(int regnum);
77
  bool GetValue(const char* desc, int32_t* value);
78
  bool GetValue(const char* desc, int64_t* value);
79 80 81 82 83 84 85 86 87 88 89

  // Set or delete a breakpoint. Returns true if successful.
  bool SetBreakpoint(Instruction* breakpc);
  bool DeleteBreakpoint(Instruction* breakpc);

  // Undo and redo all breakpoints. This is needed to bracket disassembly and
  // execution to skip past breakpoints when run from the debugger.
  void UndoBreakpoints();
  void RedoBreakpoints();
};

90

91
#define UNSUPPORTED() printf("Sim: Unsupported instruction.\n");
92 93


94
void MipsDebugger::Stop(Instruction* instr) {
95 96
  // Get the stop code.
  uint32_t code = instr->Bits(25, 6);
97
  PrintF("Simulator hit (%u)\n", code);
98 99 100 101
  Debug();
}


102
int32_t MipsDebugger::GetRegisterValue(int regnum) {
103 104 105 106 107 108 109 110
  if (regnum == kNumSimuRegisters) {
    return sim_->get_pc();
  } else {
    return sim_->get_register(regnum);
  }
}


111
int32_t MipsDebugger::GetFPURegisterValue32(int regnum) {
112 113 114
  if (regnum == kNumFPURegisters) {
    return sim_->get_pc();
  } else {
115
    return sim_->get_fpu_register_word(regnum);
116 117 118 119
  }
}


120
int64_t MipsDebugger::GetFPURegisterValue64(int regnum) {
121 122 123
  if (regnum == kNumFPURegisters) {
    return sim_->get_pc();
  } else {
124
    return sim_->get_fpu_register(regnum);
125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147
  }
}


float MipsDebugger::GetFPURegisterValueFloat(int regnum) {
  if (regnum == kNumFPURegisters) {
    return sim_->get_pc();
  } else {
    return sim_->get_fpu_register_float(regnum);
  }
}


double MipsDebugger::GetFPURegisterValueDouble(int regnum) {
  if (regnum == kNumFPURegisters) {
    return sim_->get_pc();
  } else {
    return sim_->get_fpu_register_double(regnum);
  }
}


bool MipsDebugger::GetValue(const char* desc, int32_t* value) {
148
  int regnum = Registers::Number(desc);
149 150
  int fpuregnum = FPURegisters::Number(desc);

151 152 153
  if (regnum != kInvalidRegister) {
    *value = GetRegisterValue(regnum);
    return true;
154
  } else if (fpuregnum != kInvalidFPURegister) {
155
    *value = GetFPURegisterValue32(fpuregnum);
156 157 158
    return true;
  } else if (strncmp(desc, "0x", 2) == 0) {
    return SScanF(desc, "%x", reinterpret_cast<uint32_t*>(value)) == 1;
159 160 161 162 163 164 165
  } else {
    return SScanF(desc, "%i", value) == 1;
  }
  return false;
}


166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185
bool MipsDebugger::GetValue(const char* desc, int64_t* value) {
  int regnum = Registers::Number(desc);
  int fpuregnum = FPURegisters::Number(desc);

  if (regnum != kInvalidRegister) {
    *value = GetRegisterValue(regnum);
    return true;
  } else if (fpuregnum != kInvalidFPURegister) {
    *value = GetFPURegisterValue64(fpuregnum);
    return true;
  } else if (strncmp(desc, "0x", 2) == 0) {
    return SScanF(desc + 2, "%" SCNx64,
                  reinterpret_cast<uint64_t*>(value)) == 1;
  } else {
    return SScanF(desc, "%" SCNu64, reinterpret_cast<uint64_t*>(value)) == 1;
  }
  return false;
}


186
bool MipsDebugger::SetBreakpoint(Instruction* breakpc) {
187
  // Check if a breakpoint can be set. If not return without any side-effects.
188
  if (sim_->break_pc_ != nullptr) {
189 190 191 192 193 194 195 196 197 198 199 200
    return false;
  }

  // Set the breakpoint.
  sim_->break_pc_ = breakpc;
  sim_->break_instr_ = breakpc->InstructionBits();
  // Not setting the breakpoint instruction in the code itself. It will be set
  // when the debugger shell continues.
  return true;
}


201
bool MipsDebugger::DeleteBreakpoint(Instruction* breakpc) {
202
  if (sim_->break_pc_ != nullptr) {
203 204 205
    sim_->break_pc_->SetInstructionBits(sim_->break_instr_);
  }

206
  sim_->break_pc_ = nullptr;
207 208 209 210 211
  sim_->break_instr_ = 0;
  return true;
}


212
void MipsDebugger::UndoBreakpoints() {
213
  if (sim_->break_pc_ != nullptr) {
214 215 216 217 218
    sim_->break_pc_->SetInstructionBits(sim_->break_instr_);
  }
}


219
void MipsDebugger::RedoBreakpoints() {
220
  if (sim_->break_pc_ != nullptr) {
221 222 223 224
    sim_->break_pc_->SetInstructionBits(kBreakpointInstr);
  }
}

225 226

void MipsDebugger::PrintAllRegs() {
227 228 229
#define REG_INFO(n) Registers::Name(n), GetRegisterValue(n), GetRegisterValue(n)

  PrintF("\n");
230
  // at, v0, a0.
231 232
  PrintF("%3s: 0x%08x %10d\t%3s: 0x%08x %10d\t%3s: 0x%08x %10d\n",
         REG_INFO(1), REG_INFO(2), REG_INFO(4));
233
  // v1, a1.
234 235
  PrintF("%26s\t%3s: 0x%08x %10d\t%3s: 0x%08x %10d\n",
         "", REG_INFO(3), REG_INFO(5));
236
  // a2.
237
  PrintF("%26s\t%26s\t%3s: 0x%08x %10d\n", "", "", REG_INFO(6));
238
  // a3.
239 240 241 242 243 244 245 246
  PrintF("%26s\t%26s\t%3s: 0x%08x %10d\n", "", "", REG_INFO(7));
  PrintF("\n");
  // t0-t7, s0-s7
  for (int i = 0; i < 8; i++) {
    PrintF("%3s: 0x%08x %10d\t%3s: 0x%08x %10d\n",
           REG_INFO(8+i), REG_INFO(16+i));
  }
  PrintF("\n");
247
  // t8, k0, LO.
248 249
  PrintF("%3s: 0x%08x %10d\t%3s: 0x%08x %10d\t%3s: 0x%08x %10d\n",
         REG_INFO(24), REG_INFO(26), REG_INFO(32));
250
  // t9, k1, HI.
251 252
  PrintF("%3s: 0x%08x %10d\t%3s: 0x%08x %10d\t%3s: 0x%08x %10d\n",
         REG_INFO(25), REG_INFO(27), REG_INFO(33));
253
  // sp, fp, gp.
254 255
  PrintF("%3s: 0x%08x %10d\t%3s: 0x%08x %10d\t%3s: 0x%08x %10d\n",
         REG_INFO(29), REG_INFO(30), REG_INFO(28));
256
  // pc.
257 258
  PrintF("%3s: 0x%08x %10d\t%3s: 0x%08x %10d\n",
         REG_INFO(31), REG_INFO(34));
259 260 261 262 263 264 265

#undef REG_INFO
#undef FPU_REG_INFO
}


void MipsDebugger::PrintAllRegsIncludingFPU() {
266 267 268 269 270 271 272 273
#define FPU_REG_INFO32(n) FPURegisters::Name(n), FPURegisters::Name(n+1), \
        GetFPURegisterValue32(n+1), \
        GetFPURegisterValue32(n), \
        GetFPURegisterValueDouble(n)

#define FPU_REG_INFO64(n) FPURegisters::Name(n), \
        GetFPURegisterValue64(n), \
        GetFPURegisterValueDouble(n)
274 275 276 277

  PrintAllRegs();

  PrintF("\n\n");
278
  // f0, f1, f2, ... f31.
279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331
  // This must be a compile-time switch,
  // compiler will throw out warnings otherwise.
  if (kFpuMode == kFP64) {
    PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(0) );
    PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(1) );
    PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(2) );
    PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(3) );
    PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(4) );
    PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(5) );
    PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(6) );
    PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(7) );
    PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(8) );
    PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(9) );
    PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(10));
    PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(11));
    PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(12));
    PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(13));
    PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(14));
    PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(15));
    PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(16));
    PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(17));
    PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(18));
    PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(19));
    PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(20));
    PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(21));
    PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(22));
    PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(23));
    PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(24));
    PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(25));
    PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(26));
    PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(27));
    PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(28));
    PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(29));
    PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(30));
    PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(31));
  } else {
    PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO32(0) );
    PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO32(2) );
    PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO32(4) );
    PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO32(6) );
    PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO32(8) );
    PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO32(10));
    PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO32(12));
    PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO32(14));
    PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO32(16));
    PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO32(18));
    PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO32(20));
    PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO32(22));
    PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO32(24));
    PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO32(26));
    PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO32(28));
    PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO32(30));
  }
332

333
#undef REG_INFO
334 335
#undef FPU_REG_INFO32
#undef FPU_REG_INFO64
336 337
}

338 339

void MipsDebugger::Debug() {
340 341 342 343 344 345 346 347 348 349 350 351
  intptr_t last_pc = -1;
  bool done = false;

#define COMMAND_SIZE 63
#define ARG_SIZE 255

#define STR(a) #a
#define XSTR(a) STR(a)

  char cmd[COMMAND_SIZE + 1];
  char arg1[ARG_SIZE + 1];
  char arg2[ARG_SIZE + 1];
352
  char* argv[3] = { cmd, arg1, arg2 };
353

354
  // Make sure to have a proper terminating character if reaching the limit.
355 356 357 358 359 360 361 362 363 364 365 366
  cmd[COMMAND_SIZE] = 0;
  arg1[ARG_SIZE] = 0;
  arg2[ARG_SIZE] = 0;

  // Undo all set breakpoints while running in the debugger shell. This will
  // make them invisible to all commands.
  UndoBreakpoints();

  while (!done && (sim_->get_pc() != Simulator::end_sim_pc)) {
    if (last_pc != sim_->get_pc()) {
      disasm::NameConverter converter;
      disasm::Disassembler dasm(converter);
367
      // Use a reasonably large buffer.
368 369
      v8::internal::EmbeddedVector<char, 256> buffer;
      dasm.InstructionDecode(buffer,
370
                             reinterpret_cast<byte*>(sim_->get_pc()));
371
      PrintF("  0x%08x  %s\n", sim_->get_pc(), buffer.begin());
372 373 374
      last_pc = sim_->get_pc();
    }
    char* line = ReadLine("sim> ");
375
    if (line == nullptr) {
376 377
      break;
    } else {
378
      char* last_input = sim_->last_debugger_input();
379
      if (strcmp(line, "\n") == 0 && last_input != nullptr) {
380 381 382 383 384
        line = last_input;
      } else {
        // Ownership is transferred to sim_;
        sim_->set_last_debugger_input(line);
      }
385 386
      // Use sscanf to parse the individual parts of the command line. At the
      // moment no command expects more than two parameters.
387
      int argc = SScanF(line,
388 389 390 391 392
                        "%" XSTR(COMMAND_SIZE) "s "
                        "%" XSTR(ARG_SIZE) "s "
                        "%" XSTR(ARG_SIZE) "s",
                        cmd, arg1, arg2);
      if ((strcmp(cmd, "si") == 0) || (strcmp(cmd, "stepi") == 0)) {
393 394 395
        Instruction* instr = reinterpret_cast<Instruction*>(sim_->get_pc());
        if (!(instr->IsTrap()) ||
            instr->InstructionBits() == rtCallRedirInstr) {
396
          sim_->InstructionDecode(
397
              reinterpret_cast<Instruction*>(sim_->get_pc()));
398 399 400
        } else {
          // Allow si to jump over generated breakpoints.
          PrintF("/!\\ Jumping over generated breakpoint.\n");
401
          sim_->set_pc(sim_->get_pc() + kInstrSize);
402 403 404 405 406 407 408
        }
      } else if ((strcmp(cmd, "c") == 0) || (strcmp(cmd, "cont") == 0)) {
        // Execute the one instruction we broke at with breakpoints disabled.
        sim_->InstructionDecode(reinterpret_cast<Instruction*>(sim_->get_pc()));
        // Leave the debugger shell.
        done = true;
      } else if ((strcmp(cmd, "p") == 0) || (strcmp(cmd, "print") == 0)) {
409
        if (argc == 2) {
410 411
          if (strcmp(arg1, "all") == 0) {
            PrintAllRegs();
412 413
          } else if (strcmp(arg1, "allf") == 0) {
            PrintAllRegsIncludingFPU();
414
          } else {
415 416 417 418
            int regnum = Registers::Number(arg1);
            int fpuregnum = FPURegisters::Number(arg1);

            if (regnum != kInvalidRegister) {
419
              int32_t value;
420
              value = GetRegisterValue(regnum);
421
              PrintF("%s: 0x%08x %d \n", arg1, value, value);
422
            } else if (fpuregnum != kInvalidFPURegister) {
423 424 425 426 427 428 429
              if (IsFp64Mode()) {
                int64_t value;
                double dvalue;
                value = GetFPURegisterValue64(fpuregnum);
                dvalue = GetFPURegisterValueDouble(fpuregnum);
                PrintF("%3s: 0x%016llx %16.4e\n",
                       FPURegisters::Name(fpuregnum), value, dvalue);
430
              } else {
431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448
                if (fpuregnum % 2 == 1) {
                  int32_t value;
                  float fvalue;
                  value = GetFPURegisterValue32(fpuregnum);
                  fvalue = GetFPURegisterValueFloat(fpuregnum);
                  PrintF("%s: 0x%08x %11.4e\n", arg1, value, fvalue);
                } else {
                  double dfvalue;
                  int32_t lvalue1 = GetFPURegisterValue32(fpuregnum);
                  int32_t lvalue2 = GetFPURegisterValue32(fpuregnum + 1);
                  dfvalue = GetFPURegisterValueDouble(fpuregnum);
                  PrintF("%3s,%3s: 0x%08x%08x %16.4e\n",
                         FPURegisters::Name(fpuregnum+1),
                         FPURegisters::Name(fpuregnum),
                         lvalue1,
                         lvalue2,
                         dfvalue);
                }
449
              }
450 451 452 453 454
            } else {
              PrintF("%s unrecognized\n", arg1);
            }
          }
        } else {
455 456 457 458 459 460 461
          if (argc == 3) {
            if (strcmp(arg2, "single") == 0) {
              int32_t value;
              float fvalue;
              int fpuregnum = FPURegisters::Number(arg1);

              if (fpuregnum != kInvalidFPURegister) {
462
                value = GetFPURegisterValue32(fpuregnum);
463 464 465 466 467 468 469 470 471 472 473
                fvalue = GetFPURegisterValueFloat(fpuregnum);
                PrintF("%s: 0x%08x %11.4e\n", arg1, value, fvalue);
              } else {
                PrintF("%s unrecognized\n", arg1);
              }
            } else {
              PrintF("print <fpu register> single\n");
            }
          } else {
            PrintF("print <register> or print <fpu register> single\n");
          }
474 475 476
        }
      } else if ((strcmp(cmd, "po") == 0)
                 || (strcmp(cmd, "printobject") == 0)) {
477
        if (argc == 2) {
478
          int32_t value;
479
          StdoutStream os;
480
          if (GetValue(arg1, &value)) {
481
            Object obj(value);
482
            os << arg1 << ": \n";
483
#ifdef DEBUG
484
            obj->Print(os);
485
            os << "\n";
486
#else
487
            os << Brief(obj) << "\n";
488 489
#endif
          } else {
490
            os << arg1 << " unrecognized\n";
491 492 493 494
          }
        } else {
          PrintF("printobject <value>\n");
        }
495
      } else if (strcmp(cmd, "stack") == 0 || strcmp(cmd, "mem") == 0) {
496 497
        int32_t* cur = nullptr;
        int32_t* end = nullptr;
498 499 500 501
        int next_arg = 1;

        if (strcmp(cmd, "stack") == 0) {
          cur = reinterpret_cast<int32_t*>(sim_->get_register(Simulator::sp));
502
        } else {  // Command "mem".
503 504 505 506 507 508 509 510 511
          int32_t value;
          if (!GetValue(arg1, &value)) {
            PrintF("%s unrecognized\n", arg1);
            continue;
          }
          cur = reinterpret_cast<int32_t*>(value);
          next_arg++;
        }

512 513 514 515 516 517 518 519 520 521 522
        // TODO(palfia): optimize this.
        if (IsFp64Mode()) {
          int64_t words;
          if (argc == next_arg) {
            words = 10;
          } else {
            if (!GetValue(argv[next_arg], &words)) {
              words = 10;
            }
          }
          end = cur + words;
523
        } else {
524 525
          int32_t words;
          if (argc == next_arg) {
526
            words = 10;
527 528 529 530
          } else {
            if (!GetValue(argv[next_arg], &words)) {
              words = 10;
            }
531
          }
532
          end = cur + words;
533 534 535
        }

        while (cur < end) {
536
          PrintF("  0x%08" PRIxPTR ":  0x%08x %10d",
537
                 reinterpret_cast<intptr_t>(cur), *cur, *cur);
538
          Object obj(*cur);
539
          Heap* current_heap = sim_->isolate_->heap();
540 541
          if (obj.IsSmi() ||
              IsValidHeapObject(current_heap, HeapObject::cast(obj))) {
542
            PrintF(" (");
543 544
            if (obj.IsSmi()) {
              PrintF("smi %d", Smi::ToInt(obj));
545 546 547 548 549 550
            } else {
              obj->ShortPrint();
            }
            PrintF(")");
          }
          PrintF("\n");
551 552 553
          cur++;
        }

554 555 556
      } else if ((strcmp(cmd, "disasm") == 0) ||
                 (strcmp(cmd, "dpc") == 0) ||
                 (strcmp(cmd, "di") == 0)) {
557 558
        disasm::NameConverter converter;
        disasm::Disassembler dasm(converter);
559
        // Use a reasonably large buffer.
560 561
        v8::internal::EmbeddedVector<char, 256> buffer;

562 563
        byte* cur = nullptr;
        byte* end = nullptr;
564

565
        if (argc == 1) {
566
          cur = reinterpret_cast<byte*>(sim_->get_pc());
567
          end = cur + (10 * kInstrSize);
568
        } else if (argc == 2) {
569 570 571 572 573 574 575
          int regnum = Registers::Number(arg1);
          if (regnum != kInvalidRegister || strncmp(arg1, "0x", 2) == 0) {
            // The argument is an address or a register name.
            int32_t value;
            if (GetValue(arg1, &value)) {
              cur = reinterpret_cast<byte*>(value);
              // Disassemble 10 instructions at <arg1>.
576
              end = cur + (10 * kInstrSize);
577 578 579 580 581 582 583
            }
          } else {
            // The argument is the number of instructions.
            int32_t value;
            if (GetValue(arg1, &value)) {
              cur = reinterpret_cast<byte*>(sim_->get_pc());
              // Disassemble <arg1> instructions.
584
              end = cur + (value * kInstrSize);
585
            }
586 587 588 589 590
          }
        } else {
          int32_t value1;
          int32_t value2;
          if (GetValue(arg1, &value1) && GetValue(arg2, &value2)) {
591
            cur = reinterpret_cast<byte*>(value1);
592
            end = cur + (value2 * kInstrSize);
593 594 595 596 597
          }
        }

        while (cur < end) {
          dasm.InstructionDecode(buffer, cur);
598
          PrintF("  0x%08" PRIxPTR "  %s\n", reinterpret_cast<intptr_t>(cur),
599
                 buffer.begin());
600
          cur += kInstrSize;
601 602 603
        }
      } else if (strcmp(cmd, "gdb") == 0) {
        PrintF("relinquishing control to gdb\n");
604
        v8::base::OS::DebugBreak();
605 606
        PrintF("regaining control from gdb\n");
      } else if (strcmp(cmd, "break") == 0) {
607
        if (argc == 2) {
608 609 610 611 612 613 614 615 616 617 618 619
          int32_t value;
          if (GetValue(arg1, &value)) {
            if (!SetBreakpoint(reinterpret_cast<Instruction*>(value))) {
              PrintF("setting breakpoint failed\n");
            }
          } else {
            PrintF("%s unrecognized\n", arg1);
          }
        } else {
          PrintF("break <address>\n");
        }
      } else if (strcmp(cmd, "del") == 0) {
620
        if (!DeleteBreakpoint(nullptr)) {
621 622 623 624
          PrintF("deleting breakpoint failed\n");
        }
      } else if (strcmp(cmd, "flags") == 0) {
        PrintF("No flags on MIPS !\n");
625 626
      } else if (strcmp(cmd, "stop") == 0) {
        int32_t value;
627
        intptr_t stop_pc = sim_->get_pc() - 2 * kInstrSize;
628 629
        Instruction* stop_instr = reinterpret_cast<Instruction*>(stop_pc);
        Instruction* msg_address =
630
            reinterpret_cast<Instruction*>(stop_pc + kInstrSize);
631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683
        if ((argc == 2) && (strcmp(arg1, "unstop") == 0)) {
          // Remove the current stop.
          if (sim_->IsStopInstruction(stop_instr)) {
            stop_instr->SetInstructionBits(kNopInstr);
            msg_address->SetInstructionBits(kNopInstr);
          } else {
            PrintF("Not at debugger stop.\n");
          }
        } else if (argc == 3) {
          // Print information about all/the specified breakpoint(s).
          if (strcmp(arg1, "info") == 0) {
            if (strcmp(arg2, "all") == 0) {
              PrintF("Stop information:\n");
              for (uint32_t i = kMaxWatchpointCode + 1;
                   i <= kMaxStopCode;
                   i++) {
                sim_->PrintStopInfo(i);
              }
            } else if (GetValue(arg2, &value)) {
              sim_->PrintStopInfo(value);
            } else {
              PrintF("Unrecognized argument.\n");
            }
          } else if (strcmp(arg1, "enable") == 0) {
            // Enable all/the specified breakpoint(s).
            if (strcmp(arg2, "all") == 0) {
              for (uint32_t i = kMaxWatchpointCode + 1;
                   i <= kMaxStopCode;
                   i++) {
                sim_->EnableStop(i);
              }
            } else if (GetValue(arg2, &value)) {
              sim_->EnableStop(value);
            } else {
              PrintF("Unrecognized argument.\n");
            }
          } else if (strcmp(arg1, "disable") == 0) {
            // Disable all/the specified breakpoint(s).
            if (strcmp(arg2, "all") == 0) {
              for (uint32_t i = kMaxWatchpointCode + 1;
                   i <= kMaxStopCode;
                   i++) {
                sim_->DisableStop(i);
              }
            } else if (GetValue(arg2, &value)) {
              sim_->DisableStop(value);
            } else {
              PrintF("Unrecognized argument.\n");
            }
          }
        } else {
          PrintF("Wrong usage. Use help command for more information.\n");
        }
684
      } else if ((strcmp(cmd, "stat") == 0) || (strcmp(cmd, "st") == 0)) {
685
        // Print registers and disassemble.
686 687 688 689 690
        PrintAllRegs();
        PrintF("\n");

        disasm::NameConverter converter;
        disasm::Disassembler dasm(converter);
691
        // Use a reasonably large buffer.
692 693
        v8::internal::EmbeddedVector<char, 256> buffer;

694 695
        byte* cur = nullptr;
        byte* end = nullptr;
696

697
        if (argc == 1) {
698
          cur = reinterpret_cast<byte*>(sim_->get_pc());
699
          end = cur + (10 * kInstrSize);
700
        } else if (argc == 2) {
701 702
          int32_t value;
          if (GetValue(arg1, &value)) {
703
            cur = reinterpret_cast<byte*>(value);
704
            // no length parameter passed, assume 10 instructions
705
            end = cur + (10 * kInstrSize);
706 707 708 709 710
          }
        } else {
          int32_t value1;
          int32_t value2;
          if (GetValue(arg1, &value1) && GetValue(arg2, &value2)) {
711
            cur = reinterpret_cast<byte*>(value1);
712
            end = cur + (value2 * kInstrSize);
713 714 715 716 717
          }
        }

        while (cur < end) {
          dasm.InstructionDecode(buffer, cur);
718
          PrintF("  0x%08" PRIxPTR "  %s\n", reinterpret_cast<intptr_t>(cur),
719
                 buffer.begin());
720
          cur += kInstrSize;
721 722 723 724 725 726 727 728 729 730 731
        }
      } else if ((strcmp(cmd, "h") == 0) || (strcmp(cmd, "help") == 0)) {
        PrintF("cont\n");
        PrintF("  continue execution (alias 'c')\n");
        PrintF("stepi\n");
        PrintF("  step one instruction (alias 'si')\n");
        PrintF("print <register>\n");
        PrintF("  print register content (alias 'p')\n");
        PrintF("  use register name 'all' to print all registers\n");
        PrintF("printobject <register>\n");
        PrintF("  print an object from a register (alias 'po')\n");
732 733 734 735
        PrintF("stack [<words>]\n");
        PrintF("  dump stack content, default dump 10 words)\n");
        PrintF("mem <address> [<words>]\n");
        PrintF("  dump memory content, default dump 10 words)\n");
736 737 738
        PrintF("flags\n");
        PrintF("  print flags\n");
        PrintF("disasm [<instructions>]\n");
739 740 741 742
        PrintF("disasm [<address/register>]\n");
        PrintF("disasm [[<address/register>] <instructions>]\n");
        PrintF("  disassemble code, default is 10 instructions\n");
        PrintF("  from pc (alias 'di')\n");
743 744 745 746 747 748
        PrintF("gdb\n");
        PrintF("  enter gdb\n");
        PrintF("break <address>\n");
        PrintF("  set a break point on the address\n");
        PrintF("del\n");
        PrintF("  delete the breakpoint\n");
749 750 751 752 753
        PrintF("stop feature:\n");
        PrintF("  Description:\n");
        PrintF("    Stops are debug instructions inserted by\n");
        PrintF("    the Assembler::stop() function.\n");
        PrintF("    When hitting a stop, the Simulator will\n");
754
        PrintF("    stop and give control to the Debugger.\n");
755 756 757 758 759 760 761 762 763 764 765 766 767 768
        PrintF("    All stop codes are watched:\n");
        PrintF("    - They can be enabled / disabled: the Simulator\n");
        PrintF("       will / won't stop when hitting them.\n");
        PrintF("    - The Simulator keeps track of how many times they \n");
        PrintF("      are met. (See the info command.) Going over a\n");
        PrintF("      disabled stop still increases its counter. \n");
        PrintF("  Commands:\n");
        PrintF("    stop info all/<code> : print infos about number <code>\n");
        PrintF("      or all stop(s).\n");
        PrintF("    stop enable/disable all/<code> : enables / disables\n");
        PrintF("      all or number <code> stop(s)\n");
        PrintF("    stop unstop\n");
        PrintF("      ignore the stop instruction at the current location\n");
        PrintF("      from now on\n");
769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785
      } else {
        PrintF("Unknown command: %s\n", cmd);
      }
    }
  }

  // Add all the breakpoints back to stop execution and enter the debugger
  // shell when hit.
  RedoBreakpoints();

#undef COMMAND_SIZE
#undef ARG_SIZE

#undef STR
#undef XSTR
}

786
bool Simulator::ICacheMatch(void* one, void* two) {
787 788
  DCHECK_EQ(reinterpret_cast<intptr_t>(one) & CachePage::kPageMask, 0);
  DCHECK_EQ(reinterpret_cast<intptr_t>(two) & CachePage::kPageMask, 0);
789 790 791
  return one == two;
}

792

793 794 795
static uint32_t ICacheHash(void* key) {
  return static_cast<uint32_t>(reinterpret_cast<uintptr_t>(key)) >> 2;
}
796

797 798 799 800 801 802 803 804

static bool AllOnOnePage(uintptr_t start, int size) {
  intptr_t start_page = (start & ~CachePage::kPageMask);
  intptr_t end_page = ((start + size) & ~CachePage::kPageMask);
  return start_page == end_page;
}


805 806 807 808 809
void Simulator::set_last_debugger_input(char* input) {
  DeleteArray(last_debugger_input_);
  last_debugger_input_ = input;
}

810 811 812 813
void Simulator::SetRedirectInstruction(Instruction* instruction) {
  instruction->SetInstructionBits(rtCallRedirInstr);
}

814 815
void Simulator::FlushICache(base::CustomMatcherHashMap* i_cache,
                            void* start_addr, size_t size) {
816 817 818 819 820 821 822 823 824 825 826
  intptr_t start = reinterpret_cast<intptr_t>(start_addr);
  int intra_line = (start & CachePage::kLineMask);
  start -= intra_line;
  size += intra_line;
  size = ((size - 1) | CachePage::kLineMask) + 1;
  int offset = (start & CachePage::kPageMask);
  while (!AllOnOnePage(start, size - 1)) {
    int bytes_to_flush = CachePage::kPageSize - offset;
    FlushOnePage(i_cache, start, bytes_to_flush);
    start += bytes_to_flush;
    size -= bytes_to_flush;
827
    DCHECK_EQ(0, start & CachePage::kPageMask);
828 829 830 831 832 833 834
    offset = 0;
  }
  if (size != 0) {
    FlushOnePage(i_cache, start, size);
  }
}

835 836 837 838
CachePage* Simulator::GetCachePage(base::CustomMatcherHashMap* i_cache,
                                   void* page) {
  base::CustomMatcherHashMap::Entry* entry =
      i_cache->LookupOrInsert(page, ICacheHash(page));
839
  if (entry->value == nullptr) {
840 841 842 843 844 845 846 847
    CachePage* new_page = new CachePage();
    entry->value = new_page;
  }
  return reinterpret_cast<CachePage*>(entry->value);
}


// Flush from start up to and not including start + size.
848 849
void Simulator::FlushOnePage(base::CustomMatcherHashMap* i_cache,
                             intptr_t start, int size) {
850
  DCHECK_LE(size, CachePage::kPageSize);
851
  DCHECK(AllOnOnePage(start, size - 1));
852 853
  DCHECK_EQ(start & CachePage::kLineMask, 0);
  DCHECK_EQ(size & CachePage::kLineMask, 0);
854 855 856 857 858 859 860
  void* page = reinterpret_cast<void*>(start & (~CachePage::kPageMask));
  int offset = (start & CachePage::kPageMask);
  CachePage* cache_page = GetCachePage(i_cache, page);
  char* valid_bytemap = cache_page->ValidityByte(offset);
  memset(valid_bytemap, CachePage::LINE_INVALID, size >> CachePage::kLineShift);
}

861 862
void Simulator::CheckICache(base::CustomMatcherHashMap* i_cache,
                            Instruction* instr) {
863 864 865 866 867 868 869 870 871 872
  intptr_t address = reinterpret_cast<intptr_t>(instr);
  void* page = reinterpret_cast<void*>(address & (~CachePage::kPageMask));
  void* line = reinterpret_cast<void*>(address & (~CachePage::kLineMask));
  int offset = (address & CachePage::kPageMask);
  CachePage* cache_page = GetCachePage(i_cache, page);
  char* cache_valid_byte = cache_page->ValidityByte(offset);
  bool cache_hit = (*cache_valid_byte == CachePage::LINE_VALID);
  char* cached_line = cache_page->CachedData(offset & ~CachePage::kLineMask);
  if (cache_hit) {
    // Check that the data in memory matches the contents of the I-cache.
873
    CHECK_EQ(0, memcmp(reinterpret_cast<void*>(instr),
874
                       cache_page->CachedData(offset), kInstrSize));
875 876
  } else {
    // Cache miss.  Load memory into the cache.
877
    memcpy(cached_line, line, CachePage::kLineLength);
878 879 880
    *cache_valid_byte = CachePage::LINE_VALID;
  }
}
881 882


883
Simulator::Simulator(Isolate* isolate) : isolate_(isolate) {
884
  // Set up simulator support first. Some of this information is needed to
885
  // setup the architecture state.
886
  stack_ = reinterpret_cast<char*>(malloc(stack_size_));
887 888
  pc_modified_ = false;
  icount_ = 0;
889
  break_count_ = 0;
890
  break_pc_ = nullptr;
891 892
  break_instr_ = 0;

893
  // Set up architecture state.
894 895 896 897
  // All registers are initialized to zero to start with.
  for (int i = 0; i < kNumSimuRegisters; i++) {
    registers_[i] = 0;
  }
898
  for (int i = 0; i < kNumFPURegisters; i++) {
899 900
    FPUregisters_[2 * i] = 0;
    FPUregisters_[2 * i + 1] = 0;  // upper part for MSA ASE
901
  }
902 903
  if (IsMipsArchVariant(kMips32r6)) {
    FCSR_ = kFCSRNaN2008FlagMask;
904
    MSACSR_ = 0;
905 906 907 908
  } else {
    DCHECK(IsMipsArchVariant(kMips32r1) || IsMipsArchVariant(kMips32r2));
    FCSR_ = 0;
  }
909 910 911 912

  // The sp is initialized to point to the bottom (high address) of the
  // allocated stack area. To be safe in potential stack underflows we leave
  // some buffer below.
913
  registers_[sp] = reinterpret_cast<int32_t>(stack_) + stack_size_ - 64;
914 915 916 917
  // The ra and pc are initialized to a known bad value that will cause an
  // access violation if the simulator ever tries to execute it.
  registers_[pc] = bad_ra;
  registers_[ra] = bad_ra;
918
  last_debugger_input_ = nullptr;
919
}
920

921
Simulator::~Simulator() {
922
  GlobalMonitor::Get()->RemoveLinkedAddress(&global_monitor_thread_);
923 924
  free(stack_);
}
925 926

// Get the active Simulator for the current thread.
927 928
Simulator* Simulator::current(Isolate* isolate) {
  v8::internal::Isolate::PerIsolateThreadData* isolate_data =
929
       isolate->FindOrAllocatePerThreadDataForThisThread();
930
  DCHECK_NOT_NULL(isolate_data);
931 932

  Simulator* sim = isolate_data->simulator();
933
  if (sim == nullptr) {
934
    // TODO(146): delete the simulator object when a thread/isolate goes away.
935
    sim = new Simulator(isolate);
936
    isolate_data->set_simulator(sim);
937 938 939 940 941 942 943 944
  }
  return sim;
}


// Sets the register in the architecture state. It will also deal with updating
// Simulator internal state for special registers such as PC.
void Simulator::set_register(int reg, int32_t value) {
945
  DCHECK((reg >= 0) && (reg < kNumSimuRegisters));
946 947 948 949
  if (reg == pc) {
    pc_modified_ = true;
  }

950
  // Zero register always holds 0.
951 952 953
  registers_[reg] = (reg == 0) ? 0 : value;
}

954

955
void Simulator::set_dw_register(int reg, const int* dbl) {
956
  DCHECK((reg >= 0) && (reg < kNumSimuRegisters));
957 958 959 960 961
  registers_[reg] = dbl[0];
  registers_[reg + 1] = dbl[1];
}


962 963
void Simulator::set_fpu_register(int fpureg, int64_t value) {
  DCHECK(IsFp64Mode());
964
  DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
965
  FPUregisters_[fpureg * 2] = value;
966 967
}

968

969 970 971 972
void Simulator::set_fpu_register_word(int fpureg, int32_t value) {
  // Set ONLY lower 32-bits, leaving upper bits untouched.
  // TODO(plind): big endian issue.
  DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
973
  int32_t* pword = reinterpret_cast<int32_t*>(&FPUregisters_[fpureg * 2]);
974 975 976 977 978 979 980 981
  *pword = value;
}


void Simulator::set_fpu_register_hi_word(int fpureg, int32_t value) {
  // Set ONLY upper 32-bits, leaving lower bits untouched.
  // TODO(plind): big endian issue.
  DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
982 983
  int32_t* phiword =
      (reinterpret_cast<int32_t*>(&FPUregisters_[fpureg * 2])) + 1;
984 985 986 987
  *phiword = value;
}


988
void Simulator::set_fpu_register_float(int fpureg, float value) {
989
  DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
990
  *bit_cast<float*>(&FPUregisters_[fpureg * 2]) = value;
991 992 993
}


994
void Simulator::set_fpu_register_double(int fpureg, double value) {
995 996
  if (IsFp64Mode()) {
    DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
997
    *bit_cast<double*>(&FPUregisters_[fpureg * 2]) = value;
998 999
  } else {
    DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters) && ((fpureg % 2) == 0));
1000
    int64_t i64 = bit_cast<int64_t>(value);
1001
    set_fpu_register_word(fpureg, i64 & 0xFFFFFFFF);
1002 1003
    set_fpu_register_word(fpureg + 1, i64 >> 32);
  }
1004 1005 1006 1007 1008 1009
}


// Get the register from the architecture state. This function does handle
// the special case of accessing the PC register.
int32_t Simulator::get_register(int reg) const {
1010
  DCHECK((reg >= 0) && (reg < kNumSimuRegisters));
1011 1012 1013 1014 1015 1016
  if (reg == 0)
    return 0;
  else
    return registers_[reg] + ((reg == pc) ? Instruction::kPCReadOffset : 0);
}

1017

1018
double Simulator::get_double_from_register_pair(int reg) {
1019
  // TODO(plind): bad ABI stuff, refactor or remove.
1020
  DCHECK((reg >= 0) && (reg < kNumSimuRegisters) && ((reg % 2) == 0));
1021 1022 1023 1024 1025

  double dm_val = 0.0;
  // Read the bits from the unsigned integer register_[] array
  // into the double precision floating point value and return it.
  char buffer[2 * sizeof(registers_[0])];
1026 1027
  memcpy(buffer, &registers_[reg], 2 * sizeof(registers_[0]));
  memcpy(&dm_val, buffer, 2 * sizeof(registers_[0]));
1028 1029 1030 1031
  return(dm_val);
}


1032
int64_t Simulator::get_fpu_register(int fpureg) const {
1033 1034
  if (IsFp64Mode()) {
    DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
1035
    return FPUregisters_[fpureg * 2];
1036 1037 1038 1039 1040 1041 1042
  } else {
    DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters) && ((fpureg % 2) == 0));
    uint64_t i64;
    i64 = static_cast<uint32_t>(get_fpu_register_word(fpureg));
    i64 |= static_cast<uint64_t>(get_fpu_register_word(fpureg + 1)) << 32;
    return static_cast<int64_t>(i64);
  }
1043 1044
}

1045

1046 1047
int32_t Simulator::get_fpu_register_word(int fpureg) const {
  DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
1048
  return static_cast<int32_t>(FPUregisters_[fpureg * 2] & 0xFFFFFFFF);
1049 1050 1051 1052 1053
}


int32_t Simulator::get_fpu_register_signed_word(int fpureg) const {
  DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
1054
  return static_cast<int32_t>(FPUregisters_[fpureg * 2] & 0xFFFFFFFF);
1055 1056 1057 1058 1059
}


int32_t Simulator::get_fpu_register_hi_word(int fpureg) const {
  DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
1060
  return static_cast<int32_t>((FPUregisters_[fpureg * 2] >> 32) & 0xFFFFFFFF);
1061 1062 1063 1064
}


float Simulator::get_fpu_register_float(int fpureg) const {
1065
  DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
1066
  return *bit_cast<float*>(const_cast<int64_t*>(&FPUregisters_[fpureg * 2]));
1067 1068 1069
}


1070
double Simulator::get_fpu_register_double(int fpureg) const {
1071 1072
  if (IsFp64Mode()) {
    DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
1073
    return *bit_cast<double*>(&FPUregisters_[fpureg * 2]);
1074 1075 1076 1077 1078
  } else {
    DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters) && ((fpureg % 2) == 0));
    int64_t i64;
    i64 = static_cast<uint32_t>(get_fpu_register_word(fpureg));
    i64 |= static_cast<uint64_t>(get_fpu_register_word(fpureg + 1)) << 32;
1079
    return bit_cast<double>(i64);
1080
  }
1081 1082
}

1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093
template <typename T>
void Simulator::get_msa_register(int wreg, T* value) {
  DCHECK((wreg >= 0) && (wreg < kNumMSARegisters));
  memcpy(value, FPUregisters_ + wreg * 2, kSimd128Size);
}

template <typename T>
void Simulator::set_msa_register(int wreg, const T* value) {
  DCHECK((wreg >= 0) && (wreg < kNumMSARegisters));
  memcpy(FPUregisters_ + wreg * 2, value, kSimd128Size);
}
1094

1095 1096
// Runtime FP routines take up to two double arguments and zero
// or one integer arguments. All are constructed here,
1097
// from a0-a3 or f12 and f14.
1098
void Simulator::GetFpArgs(double* x, double* y, int32_t* z) {
1099 1100 1101
  if (!IsMipsSoftFloatABI) {
    *x = get_fpu_register_double(12);
    *y = get_fpu_register_double(14);
1102
    *z = get_register(a2);
1103
  } else {
1104
    // TODO(plind): bad ABI stuff, refactor or remove.
1105 1106 1107 1108 1109 1110 1111 1112
    // We use a char buffer to get around the strict-aliasing rules which
    // otherwise allow the compiler to optimize away the copy.
    char buffer[sizeof(*x)];
    int32_t* reg_buffer = reinterpret_cast<int32_t*>(buffer);

    // Registers a0 and a1 -> x.
    reg_buffer[0] = get_register(a0);
    reg_buffer[1] = get_register(a1);
1113
    memcpy(x, buffer, sizeof(buffer));
1114 1115 1116
    // Registers a2 and a3 -> y.
    reg_buffer[0] = get_register(a2);
    reg_buffer[1] = get_register(a3);
1117
    memcpy(y, buffer, sizeof(buffer));
1118
    // Register 2 -> z.
1119
    reg_buffer[0] = get_register(a2);
1120
    memcpy(z, buffer, sizeof(*z));
1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131
  }
}


// The return value is either in v0/v1 or f0.
void Simulator::SetFpResult(const double& result) {
  if (!IsMipsSoftFloatABI) {
    set_fpu_register_double(0, result);
  } else {
    char buffer[2 * sizeof(registers_[0])];
    int32_t* reg_buffer = reinterpret_cast<int32_t*>(buffer);
1132
    memcpy(buffer, &result, sizeof(buffer));
1133 1134 1135 1136 1137 1138 1139
    // Copy result to v0 and v1.
    set_register(v0, reg_buffer[0]);
    set_register(v1, reg_buffer[1]);
  }
}


1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151
// Helper functions for setting and testing the FCSR register's bits.
void Simulator::set_fcsr_bit(uint32_t cc, bool value) {
  if (value) {
    FCSR_ |= (1 << cc);
  } else {
    FCSR_ &= ~(1 << cc);
  }
}


bool Simulator::test_fcsr_bit(uint32_t cc) {
  return FCSR_ & (1 << cc);
1152 1153
}

1154

1155 1156 1157 1158
void Simulator::set_fcsr_rounding_mode(FPURoundingMode mode) {
  FCSR_ |= mode & kFPURoundingModeMask;
}

1159 1160 1161
void Simulator::set_msacsr_rounding_mode(FPURoundingMode mode) {
  MSACSR_ |= mode & kFPURoundingModeMask;
}
1162 1163 1164 1165 1166

unsigned int Simulator::get_fcsr_rounding_mode() {
  return FCSR_ & kFPURoundingModeMask;
}

1167 1168 1169
unsigned int Simulator::get_msacsr_rounding_mode() {
  return MSACSR_ & kFPURoundingModeMask;
}
1170

1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212
void Simulator::set_fpu_register_word_invalid_result(float original,
                                                     float rounded) {
  if (FCSR_ & kFCSRNaN2008FlagMask) {
    double max_int32 = std::numeric_limits<int32_t>::max();
    double min_int32 = std::numeric_limits<int32_t>::min();
    if (std::isnan(original)) {
      set_fpu_register_word(fd_reg(), 0);
    } else if (rounded > max_int32) {
      set_fpu_register_word(fd_reg(), kFPUInvalidResult);
    } else if (rounded < min_int32) {
      set_fpu_register_word(fd_reg(), kFPUInvalidResultNegative);
    } else {
      UNREACHABLE();
    }
  } else {
    set_fpu_register_word(fd_reg(), kFPUInvalidResult);
  }
}


void Simulator::set_fpu_register_invalid_result(float original, float rounded) {
  if (FCSR_ & kFCSRNaN2008FlagMask) {
    double max_int32 = std::numeric_limits<int32_t>::max();
    double min_int32 = std::numeric_limits<int32_t>::min();
    if (std::isnan(original)) {
      set_fpu_register(fd_reg(), 0);
    } else if (rounded > max_int32) {
      set_fpu_register(fd_reg(), kFPUInvalidResult);
    } else if (rounded < min_int32) {
      set_fpu_register(fd_reg(), kFPUInvalidResultNegative);
    } else {
      UNREACHABLE();
    }
  } else {
    set_fpu_register(fd_reg(), kFPUInvalidResult);
  }
}


void Simulator::set_fpu_register_invalid_result64(float original,
                                                  float rounded) {
  if (FCSR_ & kFCSRNaN2008FlagMask) {
1213 1214
    // The value of INT64_MAX (2^63-1) can't be represented as double exactly,
    // loading the most accurate representation into max_int64, which is 2^63.
1215 1216 1217 1218
    double max_int64 = std::numeric_limits<int64_t>::max();
    double min_int64 = std::numeric_limits<int64_t>::min();
    if (std::isnan(original)) {
      set_fpu_register(fd_reg(), 0);
1219
    } else if (rounded >= max_int64) {
1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274
      set_fpu_register(fd_reg(), kFPU64InvalidResult);
    } else if (rounded < min_int64) {
      set_fpu_register(fd_reg(), kFPU64InvalidResultNegative);
    } else {
      UNREACHABLE();
    }
  } else {
    set_fpu_register(fd_reg(), kFPU64InvalidResult);
  }
}


void Simulator::set_fpu_register_word_invalid_result(double original,
                                                     double rounded) {
  if (FCSR_ & kFCSRNaN2008FlagMask) {
    double max_int32 = std::numeric_limits<int32_t>::max();
    double min_int32 = std::numeric_limits<int32_t>::min();
    if (std::isnan(original)) {
      set_fpu_register_word(fd_reg(), 0);
    } else if (rounded > max_int32) {
      set_fpu_register_word(fd_reg(), kFPUInvalidResult);
    } else if (rounded < min_int32) {
      set_fpu_register_word(fd_reg(), kFPUInvalidResultNegative);
    } else {
      UNREACHABLE();
    }
  } else {
    set_fpu_register_word(fd_reg(), kFPUInvalidResult);
  }
}


void Simulator::set_fpu_register_invalid_result(double original,
                                                double rounded) {
  if (FCSR_ & kFCSRNaN2008FlagMask) {
    double max_int32 = std::numeric_limits<int32_t>::max();
    double min_int32 = std::numeric_limits<int32_t>::min();
    if (std::isnan(original)) {
      set_fpu_register(fd_reg(), 0);
    } else if (rounded > max_int32) {
      set_fpu_register(fd_reg(), kFPUInvalidResult);
    } else if (rounded < min_int32) {
      set_fpu_register(fd_reg(), kFPUInvalidResultNegative);
    } else {
      UNREACHABLE();
    }
  } else {
    set_fpu_register(fd_reg(), kFPUInvalidResult);
  }
}


void Simulator::set_fpu_register_invalid_result64(double original,
                                                  double rounded) {
  if (FCSR_ & kFCSRNaN2008FlagMask) {
1275 1276
    // The value of INT64_MAX (2^63-1) can't be represented as double exactly,
    // loading the most accurate representation into max_int64, which is 2^63.
1277 1278 1279 1280
    double max_int64 = std::numeric_limits<int64_t>::max();
    double min_int64 = std::numeric_limits<int64_t>::min();
    if (std::isnan(original)) {
      set_fpu_register(fd_reg(), 0);
1281
    } else if (rounded >= max_int64) {
1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293
      set_fpu_register(fd_reg(), kFPU64InvalidResult);
    } else if (rounded < min_int64) {
      set_fpu_register(fd_reg(), kFPU64InvalidResultNegative);
    } else {
      UNREACHABLE();
    }
  } else {
    set_fpu_register(fd_reg(), kFPU64InvalidResult);
  }
}


1294 1295
// Sets the rounding error codes in FCSR based on the result of the rounding.
// Returns true if the operation was invalid.
1296
bool Simulator::set_fcsr_round_error(double original, double rounded) {
1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309
  bool ret = false;
  double max_int32 = std::numeric_limits<int32_t>::max();
  double min_int32 = std::numeric_limits<int32_t>::min();

  if (!std::isfinite(original) || !std::isfinite(rounded)) {
    set_fcsr_bit(kFCSRInvalidOpFlagBit, true);
    ret = true;
  }

  if (original != rounded) {
    set_fcsr_bit(kFCSRInexactFlagBit, true);
  }

1310
  if (rounded < DBL_MIN && rounded > -DBL_MIN && rounded != 0) {
1311 1312 1313 1314
    set_fcsr_bit(kFCSRUnderflowFlagBit, true);
    ret = true;
  }

1315
  if (rounded > max_int32 || rounded < min_int32) {
1316 1317 1318 1319 1320 1321 1322
    set_fcsr_bit(kFCSROverflowFlagBit, true);
    // The reference is not really clear but it seems this is required:
    set_fcsr_bit(kFCSRInvalidOpFlagBit, true);
    ret = true;
  }

  return ret;
1323 1324 1325
}


1326 1327 1328 1329
// Sets the rounding error codes in FCSR based on the result of the rounding.
// Returns true if the operation was invalid.
bool Simulator::set_fcsr_round64_error(double original, double rounded) {
  bool ret = false;
1330 1331
  // The value of INT64_MAX (2^63-1) can't be represented as double exactly,
  // loading the most accurate representation into max_int64, which is 2^63.
1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348
  double max_int64 = std::numeric_limits<int64_t>::max();
  double min_int64 = std::numeric_limits<int64_t>::min();

  if (!std::isfinite(original) || !std::isfinite(rounded)) {
    set_fcsr_bit(kFCSRInvalidOpFlagBit, true);
    ret = true;
  }

  if (original != rounded) {
    set_fcsr_bit(kFCSRInexactFlagBit, true);
  }

  if (rounded < DBL_MIN && rounded > -DBL_MIN && rounded != 0) {
    set_fcsr_bit(kFCSRUnderflowFlagBit, true);
    ret = true;
  }

1349
  if (rounded >= max_int64 || rounded < min_int64) {
1350 1351 1352 1353 1354 1355 1356 1357 1358 1359
    set_fcsr_bit(kFCSROverflowFlagBit, true);
    // The reference is not really clear but it seems this is required:
    set_fcsr_bit(kFCSRInvalidOpFlagBit, true);
    ret = true;
  }

  return ret;
}


1360 1361
// Sets the rounding error codes in FCSR based on the result of the rounding.
// Returns true if the operation was invalid.
1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380
bool Simulator::set_fcsr_round_error(float original, float rounded) {
  bool ret = false;
  double max_int32 = std::numeric_limits<int32_t>::max();
  double min_int32 = std::numeric_limits<int32_t>::min();

  if (!std::isfinite(original) || !std::isfinite(rounded)) {
    set_fcsr_bit(kFCSRInvalidOpFlagBit, true);
    ret = true;
  }

  if (original != rounded) {
    set_fcsr_bit(kFCSRInexactFlagBit, true);
  }

  if (rounded < FLT_MIN && rounded > -FLT_MIN && rounded != 0) {
    set_fcsr_bit(kFCSRUnderflowFlagBit, true);
    ret = true;
  }

1381
  if (rounded > max_int32 || rounded < min_int32) {
1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395
    set_fcsr_bit(kFCSROverflowFlagBit, true);
    // The reference is not really clear but it seems this is required:
    set_fcsr_bit(kFCSRInvalidOpFlagBit, true);
    ret = true;
  }

  return ret;
}


// Sets the rounding error codes in FCSR based on the result of the rounding.
// Returns true if the operation was invalid.
bool Simulator::set_fcsr_round64_error(float original, float rounded) {
  bool ret = false;
1396 1397
  // The value of INT64_MAX (2^63-1) can't be represented as double exactly,
  // loading the most accurate representation into max_int64, which is 2^63.
1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414
  double max_int64 = std::numeric_limits<int64_t>::max();
  double min_int64 = std::numeric_limits<int64_t>::min();

  if (!std::isfinite(original) || !std::isfinite(rounded)) {
    set_fcsr_bit(kFCSRInvalidOpFlagBit, true);
    ret = true;
  }

  if (original != rounded) {
    set_fcsr_bit(kFCSRInexactFlagBit, true);
  }

  if (rounded < FLT_MIN && rounded > -FLT_MIN && rounded != 0) {
    set_fcsr_bit(kFCSRUnderflowFlagBit, true);
    ret = true;
  }

1415
  if (rounded >= max_int64 || rounded < min_int64) {
1416 1417 1418 1419 1420 1421 1422 1423 1424 1425
    set_fcsr_bit(kFCSROverflowFlagBit, true);
    // The reference is not really clear but it seems this is required:
    set_fcsr_bit(kFCSRInvalidOpFlagBit, true);
    ret = true;
  }

  return ret;
}


1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448
void Simulator::round_according_to_fcsr(double toRound, double& rounded,
                                        int32_t& rounded_int, double fs) {
  // 0 RN (round to nearest): Round a result to the nearest
  // representable value; if the result is exactly halfway between
  // two representable values, round to zero. Behave like round_w_d.

  // 1 RZ (round toward zero): Round a result to the closest
  // representable value whose absolute value is less than or
  // equal to the infinitely accurate result. Behave like trunc_w_d.

  // 2 RP (round up, or toward  infinity): Round a result to the
  // next representable value up. Behave like ceil_w_d.

  // 3 RD (round down, or toward −infinity): Round a result to
  // the next representable value down. Behave like floor_w_d.
  switch (get_fcsr_rounding_mode()) {
    case kRoundToNearest:
      rounded = std::floor(fs + 0.5);
      rounded_int = static_cast<int32_t>(rounded);
      if ((rounded_int & 1) != 0 && rounded_int - fs == 0.5) {
        // If the number is halfway between two integers,
        // round to the even one.
        rounded_int--;
1449
        rounded -= 1.;
1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467
      }
      break;
    case kRoundToZero:
      rounded = trunc(fs);
      rounded_int = static_cast<int32_t>(rounded);
      break;
    case kRoundToPlusInf:
      rounded = std::ceil(fs);
      rounded_int = static_cast<int32_t>(rounded);
      break;
    case kRoundToMinusInf:
      rounded = std::floor(fs);
      rounded_int = static_cast<int32_t>(rounded);
      break;
  }
}


1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490
void Simulator::round_according_to_fcsr(float toRound, float& rounded,
                                        int32_t& rounded_int, float fs) {
  // 0 RN (round to nearest): Round a result to the nearest
  // representable value; if the result is exactly halfway between
  // two representable values, round to zero. Behave like round_w_d.

  // 1 RZ (round toward zero): Round a result to the closest
  // representable value whose absolute value is less than or
  // equal to the infinitely accurate result. Behave like trunc_w_d.

  // 2 RP (round up, or toward  infinity): Round a result to the
  // next representable value up. Behave like ceil_w_d.

  // 3 RD (round down, or toward −infinity): Round a result to
  // the next representable value down. Behave like floor_w_d.
  switch (get_fcsr_rounding_mode()) {
    case kRoundToNearest:
      rounded = std::floor(fs + 0.5);
      rounded_int = static_cast<int32_t>(rounded);
      if ((rounded_int & 1) != 0 && rounded_int - fs == 0.5) {
        // If the number is halfway between two integers,
        // round to the even one.
        rounded_int--;
1491
        rounded -= 1.f;
1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508
      }
      break;
    case kRoundToZero:
      rounded = trunc(fs);
      rounded_int = static_cast<int32_t>(rounded);
      break;
    case kRoundToPlusInf:
      rounded = std::ceil(fs);
      rounded_int = static_cast<int32_t>(rounded);
      break;
    case kRoundToMinusInf:
      rounded = std::floor(fs);
      rounded_int = static_cast<int32_t>(rounded);
      break;
  }
}

1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549
template <typename T_fp, typename T_int>
void Simulator::round_according_to_msacsr(T_fp toRound, T_fp& rounded,
                                          T_int& rounded_int) {
  // 0 RN (round to nearest): Round a result to the nearest
  // representable value; if the result is exactly halfway between
  // two representable values, round to zero. Behave like round_w_d.

  // 1 RZ (round toward zero): Round a result to the closest
  // representable value whose absolute value is less than or
  // equal to the infinitely accurate result. Behave like trunc_w_d.

  // 2 RP (round up, or toward  infinity): Round a result to the
  // next representable value up. Behave like ceil_w_d.

  // 3 RD (round down, or toward −infinity): Round a result to
  // the next representable value down. Behave like floor_w_d.
  switch (get_msacsr_rounding_mode()) {
    case kRoundToNearest:
      rounded = std::floor(toRound + 0.5);
      rounded_int = static_cast<T_int>(rounded);
      if ((rounded_int & 1) != 0 && rounded_int - toRound == 0.5) {
        // If the number is halfway between two integers,
        // round to the even one.
        rounded_int--;
        rounded -= 1;
      }
      break;
    case kRoundToZero:
      rounded = trunc(toRound);
      rounded_int = static_cast<T_int>(rounded);
      break;
    case kRoundToPlusInf:
      rounded = std::ceil(toRound);
      rounded_int = static_cast<T_int>(rounded);
      break;
    case kRoundToMinusInf:
      rounded = std::floor(toRound);
      rounded_int = static_cast<T_int>(rounded);
      break;
  }
}
1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573

void Simulator::round64_according_to_fcsr(double toRound, double& rounded,
                                          int64_t& rounded_int, double fs) {
  // 0 RN (round to nearest): Round a result to the nearest
  // representable value; if the result is exactly halfway between
  // two representable values, round to zero. Behave like round_w_d.

  // 1 RZ (round toward zero): Round a result to the closest
  // representable value whose absolute value is less than or.
  // equal to the infinitely accurate result. Behave like trunc_w_d.

  // 2 RP (round up, or toward +infinity): Round a result to the
  // next representable value up. Behave like ceil_w_d.

  // 3 RN (round down, or toward −infinity): Round a result to
  // the next representable value down. Behave like floor_w_d.
  switch (FCSR_ & 3) {
    case kRoundToNearest:
      rounded = std::floor(fs + 0.5);
      rounded_int = static_cast<int64_t>(rounded);
      if ((rounded_int & 1) != 0 && rounded_int - fs == 0.5) {
        // If the number is halfway between two integers,
        // round to the even one.
        rounded_int--;
1574
        rounded -= 1.;
1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615
      }
      break;
    case kRoundToZero:
      rounded = trunc(fs);
      rounded_int = static_cast<int64_t>(rounded);
      break;
    case kRoundToPlusInf:
      rounded = std::ceil(fs);
      rounded_int = static_cast<int64_t>(rounded);
      break;
    case kRoundToMinusInf:
      rounded = std::floor(fs);
      rounded_int = static_cast<int64_t>(rounded);
      break;
  }
}


void Simulator::round64_according_to_fcsr(float toRound, float& rounded,
                                          int64_t& rounded_int, float fs) {
  // 0 RN (round to nearest): Round a result to the nearest
  // representable value; if the result is exactly halfway between
  // two representable values, round to zero. Behave like round_w_d.

  // 1 RZ (round toward zero): Round a result to the closest
  // representable value whose absolute value is less than or.
  // equal to the infinitely accurate result. Behave like trunc_w_d.

  // 2 RP (round up, or toward +infinity): Round a result to the
  // next representable value up. Behave like ceil_w_d.

  // 3 RN (round down, or toward −infinity): Round a result to
  // the next representable value down. Behave like floor_w_d.
  switch (FCSR_ & 3) {
    case kRoundToNearest:
      rounded = std::floor(fs + 0.5);
      rounded_int = static_cast<int64_t>(rounded);
      if ((rounded_int & 1) != 0 && rounded_int - fs == 0.5) {
        // If the number is halfway between two integers,
        // round to the even one.
        rounded_int--;
1616
        rounded -= 1.f;
1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634
      }
      break;
    case kRoundToZero:
      rounded = trunc(fs);
      rounded_int = static_cast<int64_t>(rounded);
      break;
    case kRoundToPlusInf:
      rounded = std::ceil(fs);
      rounded_int = static_cast<int64_t>(rounded);
      break;
    case kRoundToMinusInf:
      rounded = std::floor(fs);
      rounded_int = static_cast<int64_t>(rounded);
      break;
  }
}


1635 1636 1637 1638 1639 1640
// Raw access to the PC register.
void Simulator::set_pc(int32_t value) {
  pc_modified_ = true;
  registers_[pc] = value;
}

1641 1642 1643 1644 1645 1646

bool Simulator::has_bad_pc() const {
  return ((registers_[pc] == bad_ra) || (registers_[pc] == end_sim_pc));
}


1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660
// Raw access to the PC register without the special adjustment when reading.
int32_t Simulator::get_pc() const {
  return registers_[pc];
}


// The MIPS cannot do unaligned reads and writes.  On some MIPS platforms an
// interrupt is caused.  On others it does a funky rotation thing.  For now we
// simply disallow unaligned reads, but at some point we may want to move to
// emulating the rotate behaviour.  Note that simulator runs have the runtime
// system running directly on the host system and only generated code is
// executed in the simulator.  Since the host is typically IA32 we will not
// get the correct MIPS-like behaviour on unaligned accesses.

1661
void Simulator::TraceRegWr(int32_t value, TraceType t) {
1662
  if (::v8::internal::FLAG_trace_sim) {
1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681
    union {
      int32_t fmt_int32;
      float fmt_float;
    } v;
    v.fmt_int32 = value;

    switch (t) {
      case WORD:
        SNPrintF(trace_buf_, "%08" PRIx32 "    (%" PRIu64 ")    int32:%" PRId32
                             " uint32:%" PRIu32,
                 value, icount_, value, value);
        break;
      case FLOAT:
        SNPrintF(trace_buf_, "%08" PRIx32 "    (%" PRIu64 ")    flt:%e",
                 v.fmt_int32, icount_, v.fmt_float);
        break;
      default:
        UNREACHABLE();
    }
1682 1683 1684
  }
}

1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707
void Simulator::TraceRegWr(int64_t value, TraceType t) {
  if (::v8::internal::FLAG_trace_sim) {
    union {
      int64_t fmt_int64;
      double fmt_double;
    } v;
    v.fmt_int64 = value;

    switch (t) {
      case DWORD:
        SNPrintF(trace_buf_, "%016" PRIx64 "    (%" PRIu64 ")    int64:%" PRId64
                             " uint64:%" PRIu64,
                 value, icount_, value, value);
        break;
      case DOUBLE:
        SNPrintF(trace_buf_, "%016" PRIx64 "    (%" PRIu64 ")    dbl:%e",
                 v.fmt_int64, icount_, v.fmt_double);
        break;
      default:
        UNREACHABLE();
    }
  }
}
1708

1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761
template <typename T>
void Simulator::TraceMSARegWr(T* value, TraceType t) {
  if (::v8::internal::FLAG_trace_sim) {
    union {
      uint8_t b[16];
      uint16_t h[8];
      uint32_t w[4];
      uint64_t d[2];
      float f[4];
      double df[2];
    } v;
    memcpy(v.b, value, kSimd128Size);
    switch (t) {
      case BYTE:
        SNPrintF(trace_buf_,
                 "LO: %016" PRIx64 "  HI: %016" PRIx64 "    (%" PRIu64 ")",
                 v.d[0], v.d[1], icount_);
        break;
      case HALF:
        SNPrintF(trace_buf_,
                 "LO: %016" PRIx64 "  HI: %016" PRIx64 "    (%" PRIu64 ")",
                 v.d[0], v.d[1], icount_);
        break;
      case WORD:
        SNPrintF(trace_buf_,
                 "LO: %016" PRIx64 "  HI: %016" PRIx64 "    (%" PRIu64
                 ")    int32[0..3]:%" PRId32 "  %" PRId32 "  %" PRId32
                 "  %" PRId32,
                 v.d[0], v.d[1], icount_, v.w[0], v.w[1], v.w[2], v.w[3]);
        break;
      case DWORD:
        SNPrintF(trace_buf_,
                 "LO: %016" PRIx64 "  HI: %016" PRIx64 "    (%" PRIu64 ")",
                 v.d[0], v.d[1], icount_);
        break;
      case FLOAT:
        SNPrintF(trace_buf_,
                 "LO: %016" PRIx64 "  HI: %016" PRIx64 "    (%" PRIu64
                 ")    flt[0..3]:%e  %e  %e  %e",
                 v.d[0], v.d[1], icount_, v.f[0], v.f[1], v.f[2], v.f[3]);
        break;
      case DOUBLE:
        SNPrintF(trace_buf_,
                 "LO: %016" PRIx64 "  HI: %016" PRIx64 "    (%" PRIu64
                 ")    dbl[0..1]:%e  %e",
                 v.d[0], v.d[1], icount_, v.df[0], v.df[1]);
        break;
      default:
        UNREACHABLE();
    }
  }
}

1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798
template <typename T>
void Simulator::TraceMSARegWr(T* value) {
  if (::v8::internal::FLAG_trace_sim) {
    union {
      uint8_t b[kMSALanesByte];
      uint16_t h[kMSALanesHalf];
      uint32_t w[kMSALanesWord];
      uint64_t d[kMSALanesDword];
      float f[kMSALanesWord];
      double df[kMSALanesDword];
    } v;
    memcpy(v.b, value, kMSALanesByte);

    if (std::is_same<T, int32_t>::value) {
      SNPrintF(trace_buf_,
               "LO: %016" PRIx64 "  HI: %016" PRIx64 "    (%" PRIu64
               ")    int32[0..3]:%" PRId32 "  %" PRId32 "  %" PRId32
               "  %" PRId32,
               v.d[0], v.d[1], icount_, v.w[0], v.w[1], v.w[2], v.w[3]);
    } else if (std::is_same<T, float>::value) {
      SNPrintF(trace_buf_,
               "LO: %016" PRIx64 "  HI: %016" PRIx64 "    (%" PRIu64
               ")    flt[0..3]:%e  %e  %e  %e",
               v.d[0], v.d[1], icount_, v.f[0], v.f[1], v.f[2], v.f[3]);
    } else if (std::is_same<T, double>::value) {
      SNPrintF(trace_buf_,
               "LO: %016" PRIx64 "  HI: %016" PRIx64 "    (%" PRIu64
               ")    dbl[0..1]:%e  %e",
               v.d[0], v.d[1], icount_, v.df[0], v.df[1]);
    } else {
      SNPrintF(trace_buf_,
               "LO: %016" PRIx64 "  HI: %016" PRIx64 "    (%" PRIu64 ")",
               v.d[0], v.d[1], icount_);
    }
  }
}

1799
// TODO(plind): consider making icount_ printing a flag option.
1800
void Simulator::TraceMemRd(int32_t addr, int32_t value, TraceType t) {
1801
  if (::v8::internal::FLAG_trace_sim) {
1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821
    union {
      int32_t fmt_int32;
      float fmt_float;
    } v;
    v.fmt_int32 = value;

    switch (t) {
      case WORD:
        SNPrintF(trace_buf_, "%08" PRIx32 " <-- [%08" PRIx32 "]    (%" PRIu64
                             ")    int32:%" PRId32 " uint32:%" PRIu32,
                 value, addr, icount_, value, value);
        break;
      case FLOAT:
        SNPrintF(trace_buf_,
                 "%08" PRIx32 " <-- [%08" PRIx32 "]    (%" PRIu64 ")    flt:%e",
                 v.fmt_int32, addr, icount_, v.fmt_float);
        break;
      default:
        UNREACHABLE();
    }
1822 1823 1824 1825 1826 1827 1828 1829
  }
}


void Simulator::TraceMemWr(int32_t addr, int32_t value, TraceType t) {
  if (::v8::internal::FLAG_trace_sim) {
    switch (t) {
      case BYTE:
1830 1831 1832
        SNPrintF(trace_buf_,
                 "      %02" PRIx8 " --> [%08" PRIx32 "]    (%" PRIu64 ")",
                 static_cast<uint8_t>(value), addr, icount_);
1833 1834
        break;
      case HALF:
1835 1836 1837
        SNPrintF(trace_buf_,
                 "    %04" PRIx16 " --> [%08" PRIx32 "]    (%" PRIu64 ")",
                 static_cast<uint16_t>(value), addr, icount_);
1838 1839
        break;
      case WORD:
1840 1841 1842 1843 1844 1845 1846 1847 1848 1849
        SNPrintF(trace_buf_,
                 "%08" PRIx32 " --> [%08" PRIx32 "]    (%" PRIu64 ")", value,
                 addr, icount_);
        break;
      default:
        UNREACHABLE();
    }
  }
}

1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917
template <typename T>
void Simulator::TraceMemRd(int32_t addr, T value) {
  if (::v8::internal::FLAG_trace_sim) {
    switch (sizeof(T)) {
      case 1:
        SNPrintF(trace_buf_,
                 "%08" PRIx8 " <-- [%08" PRIx32 "]    (%" PRIu64
                 ")    int8:%" PRId8 " uint8:%" PRIu8,
                 static_cast<uint8_t>(value), addr, icount_,
                 static_cast<int8_t>(value), static_cast<uint8_t>(value));
        break;
      case 2:
        SNPrintF(trace_buf_,
                 "%08" PRIx16 " <-- [%08" PRIx32 "]    (%" PRIu64
                 ")    int16:%" PRId16 " uint16:%" PRIu16,
                 static_cast<uint16_t>(value), addr, icount_,
                 static_cast<int16_t>(value), static_cast<uint16_t>(value));
        break;
      case 4:
        SNPrintF(trace_buf_,
                 "%08" PRIx32 " <-- [%08" PRIx32 "]    (%" PRIu64
                 ")    int32:%" PRId32 " uint32:%" PRIu32,
                 static_cast<uint32_t>(value), addr, icount_,
                 static_cast<int32_t>(value), static_cast<uint32_t>(value));
        break;
      case 8:
        SNPrintF(trace_buf_,
                 "%08" PRIx64 " <-- [%08" PRIx32 "]    (%" PRIu64
                 ")    int64:%" PRId64 " uint64:%" PRIu64,
                 static_cast<uint64_t>(value), addr, icount_,
                 static_cast<int64_t>(value), static_cast<uint64_t>(value));
        break;
      default:
        UNREACHABLE();
    }
  }
}

template <typename T>
void Simulator::TraceMemWr(int32_t addr, T value) {
  if (::v8::internal::FLAG_trace_sim) {
    switch (sizeof(T)) {
      case 1:
        SNPrintF(trace_buf_,
                 "      %02" PRIx8 " --> [%08" PRIx32 "]    (%" PRIu64 ")",
                 static_cast<uint8_t>(value), addr, icount_);
        break;
      case 2:
        SNPrintF(trace_buf_,
                 "    %04" PRIx16 " --> [%08" PRIx32 "]    (%" PRIu64 ")",
                 static_cast<uint16_t>(value), addr, icount_);
        break;
      case 4:
        SNPrintF(trace_buf_,
                 "%08" PRIx32 " --> [%08" PRIx32 "]    (%" PRIu64 ")",
                 static_cast<uint32_t>(value), addr, icount_);
        break;
      case 8:
        SNPrintF(trace_buf_,
                 "%16" PRIx64 " --> [%08" PRIx32 "]    (%" PRIu64 ")",
                 static_cast<uint64_t>(value), addr, icount_);
        break;
      default:
        UNREACHABLE();
    }
  }
}

1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942
void Simulator::TraceMemRd(int32_t addr, int64_t value, TraceType t) {
  if (::v8::internal::FLAG_trace_sim) {
    union {
      int64_t fmt_int64;
      int32_t fmt_int32[2];
      float fmt_float[2];
      double fmt_double;
    } v;
    v.fmt_int64 = value;

    switch (t) {
      case DWORD:
        SNPrintF(trace_buf_, "%016" PRIx64 " <-- [%08" PRIx32 "]    (%" PRIu64
                             ")    int64:%" PRId64 " uint64:%" PRIu64,
                 v.fmt_int64, addr, icount_, v.fmt_int64, v.fmt_int64);
        break;
      case DOUBLE:
        SNPrintF(trace_buf_, "%016" PRIx64 " <-- [%08" PRIx32 "]    (%" PRIu64
                             ")    dbl:%e",
                 v.fmt_int64, addr, icount_, v.fmt_double);
        break;
      case FLOAT_DOUBLE:
        SNPrintF(trace_buf_, "%08" PRIx32 " <-- [%08" PRIx32 "]    (%" PRIu64
                             ")    flt:%e dbl:%e",
                 v.fmt_int32[1], addr, icount_, v.fmt_float[1], v.fmt_double);
1943
        break;
1944 1945
      default:
        UNREACHABLE();
1946 1947 1948 1949
    }
  }
}

1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962
void Simulator::TraceMemWr(int32_t addr, int64_t value, TraceType t) {
  if (::v8::internal::FLAG_trace_sim) {
    switch (t) {
      case DWORD:
        SNPrintF(trace_buf_,
                 "%016" PRIx64 " --> [%08" PRIx32 "]    (%" PRIu64 ")", value,
                 addr, icount_);
        break;
      default:
        UNREACHABLE();
    }
  }
}
1963

1964
int Simulator::ReadW(int32_t addr, Instruction* instr, TraceType t) {
1965
  if (addr >=0 && addr < 0x400) {
1966
    // This has to be a nullptr-dereference, drop into debugger.
1967 1968
    PrintF("Memory read from bad address: 0x%08x, pc=0x%08" PRIxPTR "\n", addr,
           reinterpret_cast<intptr_t>(instr));
1969 1970 1971
    MipsDebugger dbg(this);
    dbg.Debug();
  }
1972
  if ((addr & kPointerAlignmentMask) == 0 || IsMipsArchVariant(kMips32r6)) {
1973
    local_monitor_.NotifyLoad();
1974
    intptr_t* ptr = reinterpret_cast<intptr_t*>(addr);
1975 1976 1977 1978 1979 1980 1981 1982 1983 1984
    switch (t) {
      case WORD:
        TraceMemRd(addr, static_cast<int32_t>(*ptr), t);
        break;
      case FLOAT:
        // This TraceType is allowed but tracing for this value will be omitted.
        break;
      default:
        UNREACHABLE();
    }
1985 1986
    return *ptr;
  }
1987 1988 1989
  PrintF("Unaligned read at 0x%08x, pc=0x%08" V8PRIxPTR "\n",
         addr,
         reinterpret_cast<intptr_t>(instr));
1990 1991
  MipsDebugger dbg(this);
  dbg.Debug();
1992 1993 1994 1995
  return 0;
}

void Simulator::WriteW(int32_t addr, int value, Instruction* instr) {
1996
  if (addr >= 0 && addr < 0x400) {
1997
    // This has to be a nullptr-dereference, drop into debugger.
1998 1999
    PrintF("Memory write to bad address: 0x%08x, pc=0x%08" PRIxPTR "\n", addr,
           reinterpret_cast<intptr_t>(instr));
2000 2001 2002
    MipsDebugger dbg(this);
    dbg.Debug();
  }
2003
  if ((addr & kPointerAlignmentMask) == 0 || IsMipsArchVariant(kMips32r6)) {
2004
    local_monitor_.NotifyStore();
2005 2006
    base::MutexGuard lock_guard(&GlobalMonitor::Get()->mutex);
    GlobalMonitor::Get()->NotifyStore_Locked(&global_monitor_thread_);
2007
    intptr_t* ptr = reinterpret_cast<intptr_t*>(addr);
2008
    TraceMemWr(addr, value, WORD);
2009 2010 2011
    *ptr = value;
    return;
  }
2012 2013 2014
  PrintF("Unaligned write at 0x%08x, pc=0x%08" V8PRIxPTR "\n",
         addr,
         reinterpret_cast<intptr_t>(instr));
2015 2016
  MipsDebugger dbg(this);
  dbg.Debug();
2017 2018
}

2019 2020 2021 2022 2023 2024 2025 2026 2027 2028
void Simulator::WriteConditionalW(int32_t addr, int32_t value,
                                  Instruction* instr, int32_t rt_reg) {
  if (addr >= 0 && addr < 0x400) {
    // This has to be a nullptr-dereference, drop into debugger.
    PrintF("Memory write to bad address: 0x%08x, pc=0x%08" PRIxPTR "\n", addr,
           reinterpret_cast<intptr_t>(instr));
    MipsDebugger dbg(this);
    dbg.Debug();
  }
  if ((addr & kPointerAlignmentMask) == 0 || IsMipsArchVariant(kMips32r6)) {
2029
    base::MutexGuard lock_guard(&GlobalMonitor::Get()->mutex);
2030
    if (local_monitor_.NotifyStoreConditional(addr, TransactionSize::Word) &&
2031
        GlobalMonitor::Get()->NotifyStoreConditional_Locked(
2032 2033
            addr, &global_monitor_thread_)) {
      local_monitor_.NotifyStore();
2034
      GlobalMonitor::Get()->NotifyStore_Locked(&global_monitor_thread_);
2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049
      TraceMemWr(addr, value, WORD);
      int* ptr = reinterpret_cast<int*>(addr);
      *ptr = value;
      set_register(rt_reg, 1);
    } else {
      set_register(rt_reg, 0);
    }
    return;
  }
  PrintF("Unaligned write at 0x%08x, pc=0x%08" V8PRIxPTR "\n", addr,
         reinterpret_cast<intptr_t>(instr));
  MipsDebugger dbg(this);
  dbg.Debug();
}

2050
double Simulator::ReadD(int32_t addr, Instruction* instr) {
2051
  if ((addr & kDoubleAlignmentMask) == 0 || IsMipsArchVariant(kMips32r6)) {
2052
    local_monitor_.NotifyLoad();
2053 2054 2055
    double* ptr = reinterpret_cast<double*>(addr);
    return *ptr;
  }
2056 2057 2058
  PrintF("Unaligned (double) read at 0x%08x, pc=0x%08" V8PRIxPTR "\n",
         addr,
         reinterpret_cast<intptr_t>(instr));
2059
  base::OS::Abort();
2060 2061 2062 2063 2064
  return 0;
}


void Simulator::WriteD(int32_t addr, double value, Instruction* instr) {
2065
  if ((addr & kDoubleAlignmentMask) == 0 || IsMipsArchVariant(kMips32r6)) {
2066
    local_monitor_.NotifyStore();
2067 2068
    base::MutexGuard lock_guard(&GlobalMonitor::Get()->mutex);
    GlobalMonitor::Get()->NotifyStore_Locked(&global_monitor_thread_);
2069 2070 2071 2072
    double* ptr = reinterpret_cast<double*>(addr);
    *ptr = value;
    return;
  }
2073 2074 2075
  PrintF("Unaligned (double) write at 0x%08x, pc=0x%08" V8PRIxPTR "\n",
         addr,
         reinterpret_cast<intptr_t>(instr));
2076
  base::OS::Abort();
2077 2078 2079 2080
}


uint16_t Simulator::ReadHU(int32_t addr, Instruction* instr) {
2081
  if ((addr & 1) == 0 || IsMipsArchVariant(kMips32r6)) {
2082
    local_monitor_.NotifyLoad();
2083
    uint16_t* ptr = reinterpret_cast<uint16_t*>(addr);
2084
    TraceMemRd(addr, static_cast<int32_t>(*ptr));
2085 2086
    return *ptr;
  }
2087 2088 2089
  PrintF("Unaligned unsigned halfword read at 0x%08x, pc=0x%08" V8PRIxPTR "\n",
         addr,
         reinterpret_cast<intptr_t>(instr));
2090
  base::OS::Abort();
2091 2092 2093 2094 2095
  return 0;
}


int16_t Simulator::ReadH(int32_t addr, Instruction* instr) {
2096
  if ((addr & 1) == 0 || IsMipsArchVariant(kMips32r6)) {
2097
    local_monitor_.NotifyLoad();
2098
    int16_t* ptr = reinterpret_cast<int16_t*>(addr);
2099
    TraceMemRd(addr, static_cast<int32_t>(*ptr));
2100 2101
    return *ptr;
  }
2102 2103 2104
  PrintF("Unaligned signed halfword read at 0x%08x, pc=0x%08" V8PRIxPTR "\n",
         addr,
         reinterpret_cast<intptr_t>(instr));
2105
  base::OS::Abort();
2106 2107 2108 2109 2110
  return 0;
}


void Simulator::WriteH(int32_t addr, uint16_t value, Instruction* instr) {
2111
  if ((addr & 1) == 0 || IsMipsArchVariant(kMips32r6)) {
2112
    local_monitor_.NotifyStore();
2113 2114
    base::MutexGuard lock_guard(&GlobalMonitor::Get()->mutex);
    GlobalMonitor::Get()->NotifyStore_Locked(&global_monitor_thread_);
2115
    uint16_t* ptr = reinterpret_cast<uint16_t*>(addr);
2116
    TraceMemWr(addr, value, HALF);
2117 2118 2119
    *ptr = value;
    return;
  }
2120 2121 2122
  PrintF("Unaligned unsigned halfword write at 0x%08x, pc=0x%08" V8PRIxPTR "\n",
         addr,
         reinterpret_cast<intptr_t>(instr));
2123
  base::OS::Abort();
2124 2125 2126 2127
}


void Simulator::WriteH(int32_t addr, int16_t value, Instruction* instr) {
2128
  if ((addr & 1) == 0 || IsMipsArchVariant(kMips32r6)) {
2129
    local_monitor_.NotifyStore();
2130 2131
    base::MutexGuard lock_guard(&GlobalMonitor::Get()->mutex);
    GlobalMonitor::Get()->NotifyStore_Locked(&global_monitor_thread_);
2132
    int16_t* ptr = reinterpret_cast<int16_t*>(addr);
2133
    TraceMemWr(addr, value, HALF);
2134 2135 2136
    *ptr = value;
    return;
  }
2137 2138 2139
  PrintF("Unaligned halfword write at 0x%08x, pc=0x%08" V8PRIxPTR "\n",
         addr,
         reinterpret_cast<intptr_t>(instr));
2140
  base::OS::Abort();
2141 2142 2143 2144
}


uint32_t Simulator::ReadBU(int32_t addr) {
2145
  local_monitor_.NotifyLoad();
2146
  uint8_t* ptr = reinterpret_cast<uint8_t*>(addr);
2147
  TraceMemRd(addr, static_cast<int32_t>(*ptr));
2148
  return *ptr & 0xFF;
2149 2150 2151 2152
}


int32_t Simulator::ReadB(int32_t addr) {
2153
  local_monitor_.NotifyLoad();
2154
  int8_t* ptr = reinterpret_cast<int8_t*>(addr);
2155
  TraceMemRd(addr, static_cast<int32_t>(*ptr));
2156
  return *ptr;
2157 2158 2159 2160
}


void Simulator::WriteB(int32_t addr, uint8_t value) {
2161
  local_monitor_.NotifyStore();
2162 2163
  base::MutexGuard lock_guard(&GlobalMonitor::Get()->mutex);
  GlobalMonitor::Get()->NotifyStore_Locked(&global_monitor_thread_);
2164
  uint8_t* ptr = reinterpret_cast<uint8_t*>(addr);
2165
  TraceMemWr(addr, value, BYTE);
2166 2167 2168 2169 2170
  *ptr = value;
}


void Simulator::WriteB(int32_t addr, int8_t value) {
2171
  local_monitor_.NotifyStore();
2172 2173
  base::MutexGuard lock_guard(&GlobalMonitor::Get()->mutex);
  GlobalMonitor::Get()->NotifyStore_Locked(&global_monitor_thread_);
2174
  int8_t* ptr = reinterpret_cast<int8_t*>(addr);
2175
  TraceMemWr(addr, value, BYTE);
2176 2177 2178
  *ptr = value;
}

2179 2180 2181 2182
template <typename T>
T Simulator::ReadMem(int32_t addr, Instruction* instr) {
  int alignment_mask = (1 << sizeof(T)) - 1;
  if ((addr & alignment_mask) == 0 || IsMipsArchVariant(kMips32r6)) {
2183
    local_monitor_.NotifyLoad();
2184 2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195
    T* ptr = reinterpret_cast<T*>(addr);
    TraceMemRd(addr, *ptr);
    return *ptr;
  }
  PrintF("Unaligned read of type sizeof(%d) at 0x%08x, pc=0x%08" V8PRIxPTR "\n",
         sizeof(T), addr, reinterpret_cast<intptr_t>(instr));
  base::OS::Abort();
  return 0;
}

template <typename T>
void Simulator::WriteMem(int32_t addr, T value, Instruction* instr) {
2196
  local_monitor_.NotifyStore();
2197 2198
  base::MutexGuard lock_guard(&GlobalMonitor::Get()->mutex);
  GlobalMonitor::Get()->NotifyStore_Locked(&global_monitor_thread_);
2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 2209 2210
  int alignment_mask = (1 << sizeof(T)) - 1;
  if ((addr & alignment_mask) == 0 || IsMipsArchVariant(kMips32r6)) {
    T* ptr = reinterpret_cast<T*>(addr);
    *ptr = value;
    TraceMemWr(addr, value);
    return;
  }
  PrintF("Unaligned write of type sizeof(%d) at 0x%08x, pc=0x%08" V8PRIxPTR
         "\n",
         sizeof(T), addr, reinterpret_cast<intptr_t>(instr));
  base::OS::Abort();
}
2211 2212

// Returns the limit of the stack area to enable checking for stack overflows.
2213 2214 2215 2216 2217 2218 2219 2220 2221
uintptr_t Simulator::StackLimit(uintptr_t c_limit) const {
  // The simulator uses a separate JS stack. If we have exhausted the C stack,
  // we also drop down the JS limit to reflect the exhaustion on the JS stack.
  if (GetCurrentStackPosition() < c_limit) {
    return reinterpret_cast<uintptr_t>(get_sp());
  }

  // Otherwise the limit is the JS stack. Leave a safety margin of 1024 bytes
  // to prevent overrunning the stack when pushing values.
2222
  return reinterpret_cast<uintptr_t>(stack_) + 1024;
2223 2224 2225 2226 2227
}


// Unsupported instructions use Format to print an error and stop execution.
void Simulator::Format(Instruction* instr, const char* format) {
2228
  PrintF("Simulator found unsupported instruction:\n 0x%08" PRIxPTR ": %s\n",
2229
         reinterpret_cast<intptr_t>(instr), format);
2230 2231 2232 2233 2234 2235 2236 2237
  UNIMPLEMENTED_MIPS();
}


// Calls into the V8 runtime are based on this very simple interface.
// Note: To be able to return two values from some calls the code in runtime.cc
// uses the ObjectPair which is essentially two 32-bit values stuffed into a
// 64-bit value. With the code below we assume that all runtime calls return
2238
// 64 bits of result. If they don't, the v1 result register contains a bogus
2239
// value, which is fine because it is caller-saved.
2240 2241 2242 2243 2244
typedef int64_t (*SimulatorRuntimeCall)(int32_t arg0, int32_t arg1,
                                        int32_t arg2, int32_t arg3,
                                        int32_t arg4, int32_t arg5,
                                        int32_t arg6, int32_t arg7,
                                        int32_t arg8);
2245 2246 2247 2248 2249 2250

// These prototypes handle the four types of FP calls.
typedef int64_t (*SimulatorRuntimeCompareCall)(double darg0, double darg1);
typedef double (*SimulatorRuntimeFPFPCall)(double darg0, double darg1);
typedef double (*SimulatorRuntimeFPCall)(double darg0);
typedef double (*SimulatorRuntimeFPIntCall)(double darg0, int32_t arg0);
2251

2252 2253
// This signature supports direct call in to API function native callback
// (refer to InvocationCallback in v8.h).
2254
typedef void (*SimulatorRuntimeDirectApiCall)(int32_t arg0);
2255
typedef void (*SimulatorRuntimeProfilingApiCall)(int32_t arg0, void* arg1);
2256 2257

// This signature supports direct call to accessor getter callback.
2258 2259
typedef void (*SimulatorRuntimeDirectGetterCall)(int32_t arg0, int32_t arg1);
typedef void (*SimulatorRuntimeProfilingGetterCall)(
2260
    int32_t arg0, int32_t arg1, void* arg2);
2261

2262
// Software interrupt instructions are used by the simulator to call into the
2263
// C-based V8 runtime. They are also used for debugging with simulator.
2264
void Simulator::SoftwareInterrupt() {
2265 2266 2267
  // There are several instructions that could get us here,
  // the break_ instruction, or several variants of traps. All
  // Are "SPECIAL" class opcode, and are distinuished by function.
2268 2269
  int32_t func = instr_.FunctionFieldRaw();
  uint32_t code = (func == BREAK) ? instr_.Bits(25, 6) : -1;
2270

2271
  // We first check if we met a call_rt_redirected.
2272
  if (instr_.InstructionBits() == rtCallRedirInstr) {
2273
    Redirection* redirection = Redirection::FromInstruction(instr_.instr());
2274 2275 2276 2277
    int32_t arg0 = get_register(a0);
    int32_t arg1 = get_register(a1);
    int32_t arg2 = get_register(a2);
    int32_t arg3 = get_register(a3);
2278 2279

    int32_t* stack_pointer = reinterpret_cast<int32_t*>(get_register(sp));
2280 2281 2282
    // Args 4 and 5 are on the stack after the reserved space for args 0..3.
    int32_t arg4 = stack_pointer[4];
    int32_t arg5 = stack_pointer[5];
2283 2284 2285 2286
    int32_t arg6 = stack_pointer[6];
    int32_t arg7 = stack_pointer[7];
    int32_t arg8 = stack_pointer[8];
    STATIC_ASSERT(kMaxCParameters == 9);
2287 2288 2289 2290 2291 2292 2293

    bool fp_call =
         (redirection->type() == ExternalReference::BUILTIN_FP_FP_CALL) ||
         (redirection->type() == ExternalReference::BUILTIN_COMPARE_CALL) ||
         (redirection->type() == ExternalReference::BUILTIN_FP_CALL) ||
         (redirection->type() == ExternalReference::BUILTIN_FP_INT_CALL);

2294 2295 2296 2297 2298 2299 2300 2301
    if (!IsMipsSoftFloatABI) {
      // With the hard floating point calling convention, double
      // arguments are passed in FPU registers. Fetch the arguments
      // from there and call the builtin using soft floating point
      // convention.
      switch (redirection->type()) {
      case ExternalReference::BUILTIN_FP_FP_CALL:
      case ExternalReference::BUILTIN_COMPARE_CALL:
2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312
        if (IsFp64Mode()) {
          arg0 = get_fpu_register_word(f12);
          arg1 = get_fpu_register_hi_word(f12);
          arg2 = get_fpu_register_word(f14);
          arg3 = get_fpu_register_hi_word(f14);
        } else {
          arg0 = get_fpu_register_word(f12);
          arg1 = get_fpu_register_word(f13);
          arg2 = get_fpu_register_word(f14);
          arg3 = get_fpu_register_word(f15);
        }
2313 2314
        break;
      case ExternalReference::BUILTIN_FP_CALL:
2315 2316 2317 2318 2319 2320 2321
        if (IsFp64Mode()) {
          arg0 = get_fpu_register_word(f12);
          arg1 = get_fpu_register_hi_word(f12);
        } else {
          arg0 = get_fpu_register_word(f12);
          arg1 = get_fpu_register_word(f13);
        }
2322 2323
        break;
      case ExternalReference::BUILTIN_FP_INT_CALL:
2324 2325 2326 2327 2328 2329 2330
        if (IsFp64Mode()) {
          arg0 = get_fpu_register_word(f12);
          arg1 = get_fpu_register_hi_word(f12);
        } else {
          arg0 = get_fpu_register_word(f12);
          arg1 = get_fpu_register_word(f13);
        }
2331 2332 2333 2334 2335 2336 2337
        arg2 = get_register(a2);
        break;
      default:
        break;
      }
    }

2338 2339 2340
    // This is dodgy but it works because the C entry stubs are never moved.
    // See comment in codegen-arm.cc and bug 1242173.
    int32_t saved_ra = get_register(ra);
2341 2342

    intptr_t external =
2343
          reinterpret_cast<intptr_t>(redirection->external_function());
2344 2345 2346 2347

    // Based on CpuFeatures::IsSupported(FPU), Mips will use either hardware
    // FPU, or gcc soft-float routines. Hardware FPU is simulated in this
    // simulator. Soft-float has additional abstraction of ExternalReference,
2348
    // to support serialization.
2349
    if (fp_call) {
2350 2351 2352 2353 2354 2355 2356
      double dval0, dval1;  // one or two double parameters
      int32_t ival;         // zero or one integer parameters
      int64_t iresult = 0;  // integer return value
      double dresult = 0;   // double return value
      GetFpArgs(&dval0, &dval1, &ival);
      SimulatorRuntimeCall generic_target =
          reinterpret_cast<SimulatorRuntimeCall>(external);
2357
      if (::v8::internal::FLAG_trace_sim) {
2358 2359 2360 2361
        switch (redirection->type()) {
          case ExternalReference::BUILTIN_FP_FP_CALL:
          case ExternalReference::BUILTIN_COMPARE_CALL:
            PrintF("Call to host function at %p with args %f, %f",
2362 2363
                   reinterpret_cast<void*>(FUNCTION_ADDR(generic_target)),
                   dval0, dval1);
2364 2365 2366
            break;
          case ExternalReference::BUILTIN_FP_CALL:
            PrintF("Call to host function at %p with arg %f",
2367 2368
                   reinterpret_cast<void*>(FUNCTION_ADDR(generic_target)),
                   dval0);
2369 2370 2371
            break;
          case ExternalReference::BUILTIN_FP_INT_CALL:
            PrintF("Call to host function at %p with args %f, %d",
2372 2373
                   reinterpret_cast<void*>(FUNCTION_ADDR(generic_target)),
                   dval0, ival);
2374 2375 2376 2377 2378 2379
            break;
          default:
            UNREACHABLE();
            break;
        }
      }
2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 2396
      switch (redirection->type()) {
      case ExternalReference::BUILTIN_COMPARE_CALL: {
        SimulatorRuntimeCompareCall target =
          reinterpret_cast<SimulatorRuntimeCompareCall>(external);
        iresult = target(dval0, dval1);
        set_register(v0, static_cast<int32_t>(iresult));
        set_register(v1, static_cast<int32_t>(iresult >> 32));
        break;
      }
      case ExternalReference::BUILTIN_FP_FP_CALL: {
        SimulatorRuntimeFPFPCall target =
          reinterpret_cast<SimulatorRuntimeFPFPCall>(external);
        dresult = target(dval0, dval1);
        SetFpResult(dresult);
        break;
      }
      case ExternalReference::BUILTIN_FP_CALL: {
2397
        SimulatorRuntimeFPCall target =
2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427
          reinterpret_cast<SimulatorRuntimeFPCall>(external);
        dresult = target(dval0);
        SetFpResult(dresult);
        break;
      }
      case ExternalReference::BUILTIN_FP_INT_CALL: {
        SimulatorRuntimeFPIntCall target =
          reinterpret_cast<SimulatorRuntimeFPIntCall>(external);
        dresult = target(dval0, ival);
        SetFpResult(dresult);
        break;
      }
      default:
        UNREACHABLE();
        break;
      }
      if (::v8::internal::FLAG_trace_sim) {
        switch (redirection->type()) {
        case ExternalReference::BUILTIN_COMPARE_CALL:
          PrintF("Returned %08x\n", static_cast<int32_t>(iresult));
          break;
        case ExternalReference::BUILTIN_FP_FP_CALL:
        case ExternalReference::BUILTIN_FP_CALL:
        case ExternalReference::BUILTIN_FP_INT_CALL:
          PrintF("Returned %f\n", dresult);
          break;
        default:
          UNREACHABLE();
          break;
        }
2428
      }
2429 2430 2431 2432
    } else if (redirection->type() == ExternalReference::DIRECT_API_CALL) {
      if (::v8::internal::FLAG_trace_sim) {
        PrintF("Call to host function at %p args %08x\n",
            reinterpret_cast<void*>(external), arg0);
2433
      }
2434 2435 2436
      SimulatorRuntimeDirectApiCall target =
          reinterpret_cast<SimulatorRuntimeDirectApiCall>(external);
      target(arg0);
2437
    } else if (
2438 2439 2440 2441
        redirection->type() == ExternalReference::PROFILING_API_CALL) {
      if (::v8::internal::FLAG_trace_sim) {
        PrintF("Call to host function at %p args %08x %08x\n",
            reinterpret_cast<void*>(external), arg0, arg1);
2442
      }
2443 2444
      SimulatorRuntimeProfilingApiCall target =
          reinterpret_cast<SimulatorRuntimeProfilingApiCall>(external);
2445
      target(arg0, Redirection::ReverseRedirection(arg1));
2446
    } else if (
2447 2448 2449 2450
        redirection->type() == ExternalReference::DIRECT_GETTER_CALL) {
      if (::v8::internal::FLAG_trace_sim) {
        PrintF("Call to host function at %p args %08x %08x\n",
            reinterpret_cast<void*>(external), arg0, arg1);
2451
      }
2452 2453 2454
      SimulatorRuntimeDirectGetterCall target =
          reinterpret_cast<SimulatorRuntimeDirectGetterCall>(external);
      target(arg0, arg1);
2455
    } else if (
2456 2457 2458 2459
        redirection->type() == ExternalReference::PROFILING_GETTER_CALL) {
      if (::v8::internal::FLAG_trace_sim) {
        PrintF("Call to host function at %p args %08x %08x %08x\n",
            reinterpret_cast<void*>(external), arg0, arg1, arg2);
2460
      }
2461 2462
      SimulatorRuntimeProfilingGetterCall target =
          reinterpret_cast<SimulatorRuntimeProfilingGetterCall>(external);
2463
      target(arg0, arg1, Redirection::ReverseRedirection(arg2));
2464
    } else {
2465 2466
      DCHECK(redirection->type() == ExternalReference::BUILTIN_CALL ||
             redirection->type() == ExternalReference::BUILTIN_CALL_PAIR);
2467
      SimulatorRuntimeCall target =
2468 2469
                  reinterpret_cast<SimulatorRuntimeCall>(external);
      if (::v8::internal::FLAG_trace_sim) {
2470
        PrintF(
2471
            "Call to host function at %p "
2472
            "args %08x, %08x, %08x, %08x, %08x, %08x, %08x, %08x, %08x\n",
2473 2474
            reinterpret_cast<void*>(FUNCTION_ADDR(target)), arg0, arg1, arg2,
            arg3, arg4, arg5, arg6, arg7, arg8);
2475
      }
2476 2477
      int64_t result =
          target(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8);
2478 2479 2480 2481 2482
      set_register(v0, static_cast<int32_t>(result));
      set_register(v1, static_cast<int32_t>(result >> 32));
    }
    if (::v8::internal::FLAG_trace_sim) {
      PrintF("Returned %08x : %08x\n", get_register(v1), get_register(v0));
2483 2484 2485
    }
    set_register(ra, saved_ra);
    set_pc(get_register(ra));
2486

2487 2488 2489 2490 2491
  } else if (func == BREAK && code <= kMaxStopCode) {
    if (IsWatchpoint(code)) {
      PrintWatchpoint(code);
    } else {
      IncreaseStopCounter(code);
2492
      HandleStop(code, instr_.instr());
2493
    }
2494
  } else {
2495 2496
    // All remaining break_ codes, and all traps are handled here.
    MipsDebugger dbg(this);
2497 2498 2499 2500
    dbg.Debug();
  }
}

2501

2502 2503 2504 2505 2506 2507 2508 2509 2510
// Stop helper functions.
bool Simulator::IsWatchpoint(uint32_t code) {
  return (code <= kMaxWatchpointCode);
}


void Simulator::PrintWatchpoint(uint32_t code) {
  MipsDebugger dbg(this);
  ++break_count_;
2511 2512
  PrintF("\n---- break %d marker: %3d  (instr count: %" PRIu64
         ") ----------"
2513 2514 2515 2516 2517 2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536
         "----------------------------------",
         code, break_count_, icount_);
  dbg.PrintAllRegs();  // Print registers and continue running.
}


void Simulator::HandleStop(uint32_t code, Instruction* instr) {
  // Stop if it is enabled, otherwise go on jumping over the stop
  // and the message address.
  if (IsEnabledStop(code)) {
    MipsDebugger dbg(this);
    dbg.Stop(instr);
  }
}


bool Simulator::IsStopInstruction(Instruction* instr) {
  int32_t func = instr->FunctionFieldRaw();
  uint32_t code = static_cast<uint32_t>(instr->Bits(25, 6));
  return (func == BREAK) && code > kMaxWatchpointCode && code <= kMaxStopCode;
}


bool Simulator::IsEnabledStop(uint32_t code) {
2537 2538
  DCHECK_LE(code, kMaxStopCode);
  DCHECK_GT(code, kMaxWatchpointCode);
2539
  return !(watched_stops_[code].count & kStopDisabledBit);
2540 2541 2542 2543 2544
}


void Simulator::EnableStop(uint32_t code) {
  if (!IsEnabledStop(code)) {
2545
    watched_stops_[code].count &= ~kStopDisabledBit;
2546 2547 2548 2549 2550 2551
  }
}


void Simulator::DisableStop(uint32_t code) {
  if (IsEnabledStop(code)) {
2552
    watched_stops_[code].count |= kStopDisabledBit;
2553 2554 2555 2556 2557
  }
}


void Simulator::IncreaseStopCounter(uint32_t code) {
2558
  DCHECK_LE(code, kMaxStopCode);
2559
  if ((watched_stops_[code].count & ~(1 << 31)) == 0x7FFFFFFF) {
2560 2561
    PrintF("Stop counter for code %i has overflowed.\n"
           "Enabling this code and reseting the counter to 0.\n", code);
2562
    watched_stops_[code].count = 0;
2563 2564
    EnableStop(code);
  } else {
2565
    watched_stops_[code].count++;
2566 2567 2568 2569 2570 2571 2572 2573 2574 2575 2576 2577 2578 2579
  }
}


// Print a stop status.
void Simulator::PrintStopInfo(uint32_t code) {
  if (code <= kMaxWatchpointCode) {
    PrintF("That is a watchpoint, not a stop.\n");
    return;
  } else if (code > kMaxStopCode) {
    PrintF("Code too large, only %u stops can be used\n", kMaxStopCode + 1);
    return;
  }
  const char* state = IsEnabledStop(code) ? "Enabled" : "Disabled";
2580
  int32_t count = watched_stops_[code].count & ~kStopDisabledBit;
2581 2582
  // Don't print the state of unused breakpoints.
  if (count != 0) {
2583
    if (watched_stops_[code].desc) {
2584
      PrintF("stop %i - 0x%x: \t%s, \tcounter = %i, \t%s\n",
2585
             code, code, state, count, watched_stops_[code].desc);
2586 2587 2588 2589 2590 2591 2592 2593
    } else {
      PrintF("stop %i - 0x%x: \t%s, \tcounter = %i\n",
             code, code, state, count);
    }
  }
}


2594
void Simulator::SignalException(Exception e) {
2595
  FATAL("Error: Exception %i raised.", static_cast<int>(e));
2596 2597
}

2598 2599
// Min/Max template functions for Double and Single arguments.

2600
template <typename T>
2601
static T FPAbs(T a);
2602 2603 2604 2605 2606 2607 2608 2609 2610 2611 2612 2613

template <>
double FPAbs<double>(double a) {
  return fabs(a);
}

template <>
float FPAbs<float>(float a) {
  return fabsf(a);
}

template <typename T>
2614
static bool FPUProcessNaNsAndZeros(T a, T b, MaxMinKind kind, T& result) {
2615 2616 2617 2618 2619 2620 2621 2622
  if (std::isnan(a) && std::isnan(b)) {
    result = a;
  } else if (std::isnan(a)) {
    result = b;
  } else if (std::isnan(b)) {
    result = a;
  } else if (b == a) {
    // Handle -0.0 == 0.0 case.
2623
    // std::signbit() returns int 0 or 1 so subtracting MaxMinKind::kMax
2624 2625
    // negates the result.
    result = std::signbit(b) - static_cast<int>(kind) ? b : a;
2626 2627 2628 2629 2630 2631 2632
  } else {
    return false;
  }
  return true;
}

template <typename T>
2633
static T FPUMin(T a, T b) {
2634
  T result;
2635
  if (FPUProcessNaNsAndZeros(a, b, MaxMinKind::kMin, result)) {
2636 2637 2638 2639 2640 2641 2642
    return result;
  } else {
    return b < a ? b : a;
  }
}

template <typename T>
2643
static T FPUMax(T a, T b) {
2644
  T result;
2645
  if (FPUProcessNaNsAndZeros(a, b, MaxMinKind::kMax, result)) {
2646 2647 2648 2649 2650 2651 2652
    return result;
  } else {
    return b > a ? b : a;
  }
}

template <typename T>
2653
static T FPUMinA(T a, T b) {
2654
  T result;
2655
  if (!FPUProcessNaNsAndZeros(a, b, MaxMinKind::kMin, result)) {
2656 2657 2658 2659 2660 2661 2662 2663 2664 2665 2666 2667
    if (FPAbs(a) < FPAbs(b)) {
      result = a;
    } else if (FPAbs(b) < FPAbs(a)) {
      result = b;
    } else {
      result = a < b ? a : b;
    }
  }
  return result;
}

template <typename T>
2668
static T FPUMaxA(T a, T b) {
2669
  T result;
2670
  if (!FPUProcessNaNsAndZeros(a, b, MaxMinKind::kMin, result)) {
2671 2672 2673 2674 2675 2676 2677 2678 2679 2680 2681
    if (FPAbs(a) > FPAbs(b)) {
      result = a;
    } else if (FPAbs(b) > FPAbs(a)) {
      result = b;
    } else {
      result = a > b ? a : b;
    }
  }
  return result;
}

2682 2683 2684 2685 2686 2687 2688 2689 2690 2691 2692 2693 2694 2695 2696 2697 2698 2699 2700 2701 2702 2703 2704 2705 2706 2707 2708 2709 2710 2711 2712 2713 2714 2715 2716 2717 2718 2719 2720 2721 2722 2723 2724
enum class KeepSign : bool { no = false, yes };

template <typename T, typename std::enable_if<std::is_floating_point<T>::value,
                                              int>::type = 0>
T FPUCanonalizeNaNArg(T result, T arg, KeepSign keepSign = KeepSign::no) {
  DCHECK(std::isnan(arg));
  T qNaN = std::numeric_limits<T>::quiet_NaN();
  if (keepSign == KeepSign::yes) {
    return std::copysign(qNaN, result);
  }
  return qNaN;
}

template <typename T>
T FPUCanonalizeNaNArgs(T result, KeepSign keepSign, T first) {
  if (std::isnan(first)) {
    return FPUCanonalizeNaNArg(result, first, keepSign);
  }
  return result;
}

template <typename T, typename... Args>
T FPUCanonalizeNaNArgs(T result, KeepSign keepSign, T first, Args... args) {
  if (std::isnan(first)) {
    return FPUCanonalizeNaNArg(result, first, keepSign);
  }
  return FPUCanonalizeNaNArgs(result, keepSign, args...);
}

template <typename Func, typename T, typename... Args>
T FPUCanonalizeOperation(Func f, T first, Args... args) {
  return FPUCanonalizeOperation(f, KeepSign::no, first, args...);
}

template <typename Func, typename T, typename... Args>
T FPUCanonalizeOperation(Func f, KeepSign keepSign, T first, Args... args) {
  T result = f(first, args...);
  if (std::isnan(result)) {
    result = FPUCanonalizeNaNArgs(result, keepSign, first, args...);
  }
  return result;
}

2725
// Handle execution based on instruction types.
2726

2727
void Simulator::DecodeTypeRegisterDRsType() {
2728
  double ft, fs, fd;
2729 2730
  uint32_t cc, fcsr_cc;
  int64_t i64;
2731
  fs = get_fpu_register_double(fs_reg());
2732 2733
  ft = (instr_.FunctionFieldRaw() != MOVF) ? get_fpu_register_double(ft_reg())
                                           : 0.0;
2734
  fd = get_fpu_register_double(fd_reg());
2735 2736
  int64_t ft_int = bit_cast<int64_t>(ft);
  int64_t fd_int = bit_cast<int64_t>(fd);
2737
  cc = instr_.FCccValue();
2738
  fcsr_cc = get_fcsr_condition_bit(cc);
2739
  switch (instr_.FunctionFieldRaw()) {
2740 2741 2742 2743 2744 2745 2746 2747 2748 2749 2750 2751 2752 2753 2754 2755 2756 2757 2758 2759 2760 2761 2762 2763 2764 2765 2766 2767 2768 2769 2770
    case RINT: {
      DCHECK(IsMipsArchVariant(kMips32r6));
      double result, temp, temp_result;
      double upper = std::ceil(fs);
      double lower = std::floor(fs);
      switch (get_fcsr_rounding_mode()) {
        case kRoundToNearest:
          if (upper - fs < fs - lower) {
            result = upper;
          } else if (upper - fs > fs - lower) {
            result = lower;
          } else {
            temp_result = upper / 2;
            double reminder = modf(temp_result, &temp);
            if (reminder == 0) {
              result = upper;
            } else {
              result = lower;
            }
          }
          break;
        case kRoundToZero:
          result = (fs > 0 ? lower : upper);
          break;
        case kRoundToPlusInf:
          result = upper;
          break;
        case kRoundToMinusInf:
          result = lower;
          break;
      }
2771
      SetFPUDoubleResult(fd_reg(), result);
2772 2773 2774 2775 2776
      if (result != fs) {
        set_fcsr_bit(kFCSRInexactFlagBit, true);
      }
      break;
    }
2777 2778
    case SEL:
      DCHECK(IsMipsArchVariant(kMips32r6));
2779
      SetFPUDoubleResult(fd_reg(), (fd_int & 0x1) == 0 ? fs : ft);
2780
      break;
2781 2782
    case SELEQZ_C:
      DCHECK(IsMipsArchVariant(kMips32r6));
2783
      SetFPUDoubleResult(fd_reg(), (ft_int & 0x1) == 0 ? fs : 0.0);
2784 2785 2786
      break;
    case SELNEZ_C:
      DCHECK(IsMipsArchVariant(kMips32r6));
2787
      SetFPUDoubleResult(fd_reg(), (ft_int & 0x1) != 0 ? fs : 0.0);
2788
      break;
2789 2790
    case MOVZ_C: {
      DCHECK(IsMipsArchVariant(kMips32r2));
2791
      if (rt() == 0) {
2792
        SetFPUDoubleResult(fd_reg(), fs);
2793 2794 2795 2796 2797
      }
      break;
    }
    case MOVN_C: {
      DCHECK(IsMipsArchVariant(kMips32r2));
2798
      int32_t rt_reg = instr_.RtValue();
2799 2800
      int32_t rt = get_register(rt_reg);
      if (rt != 0) {
2801
        SetFPUDoubleResult(fd_reg(), fs);
2802 2803 2804 2805 2806
      }
      break;
    }
    case MOVF: {
      // Same function field for MOVT.D and MOVF.D
2807
      uint32_t ft_cc = (ft_reg() >> 2) & 0x7;
2808
      ft_cc = get_fcsr_condition_bit(ft_cc);
2809
      if (instr_.Bit(16)) {  // Read Tf bit.
2810
        // MOVT.D
2811
        if (test_fcsr_bit(ft_cc)) SetFPUDoubleResult(fd_reg(), fs);
2812 2813
      } else {
        // MOVF.D
2814
        if (!test_fcsr_bit(ft_cc)) SetFPUDoubleResult(fd_reg(), fs);
2815 2816 2817
      }
      break;
    }
2818 2819
    case MIN:
      DCHECK(IsMipsArchVariant(kMips32r6));
2820
      SetFPUDoubleResult(fd_reg(), FPUMin(ft, fs));
2821
      break;
2822
    case MAX:
2823
      DCHECK(IsMipsArchVariant(kMips32r6));
2824
      SetFPUDoubleResult(fd_reg(), FPUMax(ft, fs));
2825
      break;
2826
    case MINA:
2827
      DCHECK(IsMipsArchVariant(kMips32r6));
2828
      SetFPUDoubleResult(fd_reg(), FPUMinA(ft, fs));
2829
      break;
2830
    case MAXA:
2831
      DCHECK(IsMipsArchVariant(kMips32r6));
2832
      SetFPUDoubleResult(fd_reg(), FPUMaxA(ft, fs));
2833
      break;
2834
    case ADD_D:
2835
      SetFPUDoubleResult(
2836 2837 2838
          fd_reg(),
          FPUCanonalizeOperation(
              [](double lhs, double rhs) { return lhs + rhs; }, fs, ft));
2839 2840
      break;
    case SUB_D:
2841
      SetFPUDoubleResult(
2842 2843 2844
          fd_reg(),
          FPUCanonalizeOperation(
              [](double lhs, double rhs) { return lhs - rhs; }, fs, ft));
2845
      break;
2846 2847
    case MADDF_D:
      DCHECK(IsMipsArchVariant(kMips32r6));
2848
      SetFPUDoubleResult(fd_reg(), std::fma(fs, ft, fd));
2849 2850 2851
      break;
    case MSUBF_D:
      DCHECK(IsMipsArchVariant(kMips32r6));
2852
      SetFPUDoubleResult(fd_reg(), std::fma(-fs, ft, fd));
2853
      break;
2854
    case MUL_D:
2855
      SetFPUDoubleResult(
2856 2857 2858
          fd_reg(),
          FPUCanonalizeOperation(
              [](double lhs, double rhs) { return lhs * rhs; }, fs, ft));
2859 2860
      break;
    case DIV_D:
2861
      SetFPUDoubleResult(
2862 2863 2864
          fd_reg(),
          FPUCanonalizeOperation(
              [](double lhs, double rhs) { return lhs / rhs; }, fs, ft));
2865 2866
      break;
    case ABS_D:
2867
      SetFPUDoubleResult(
2868 2869
          fd_reg(),
          FPUCanonalizeOperation([](double fs) { return FPAbs(fs); }, fs));
2870 2871
      break;
    case MOV_D:
2872
      SetFPUDoubleResult(fd_reg(), fs);
2873 2874
      break;
    case NEG_D:
2875 2876 2877
      SetFPUDoubleResult(fd_reg(),
                         FPUCanonalizeOperation([](double src) { return -src; },
                                                KeepSign::yes, fs));
2878 2879
      break;
    case SQRT_D:
2880
      SetFPUDoubleResult(
2881 2882
          fd_reg(),
          FPUCanonalizeOperation([](double fs) { return std::sqrt(fs); }, fs));
2883
      break;
2884
    case RSQRT_D:
2885
      SetFPUDoubleResult(
2886 2887
          fd_reg(), FPUCanonalizeOperation(
                        [](double fs) { return 1.0 / std::sqrt(fs); }, fs));
2888
      break;
2889
    case RECIP_D:
2890 2891
      SetFPUDoubleResult(fd_reg(), FPUCanonalizeOperation(
                                       [](double fs) { return 1.0 / fs; }, fs));
2892
      break;
2893 2894
    case C_UN_D:
      set_fcsr_bit(fcsr_cc, std::isnan(fs) || std::isnan(ft));
2895
      TraceRegWr(test_fcsr_bit(fcsr_cc));
2896 2897 2898
      break;
    case C_EQ_D:
      set_fcsr_bit(fcsr_cc, (fs == ft));
2899
      TraceRegWr(test_fcsr_bit(fcsr_cc));
2900 2901 2902
      break;
    case C_UEQ_D:
      set_fcsr_bit(fcsr_cc, (fs == ft) || (std::isnan(fs) || std::isnan(ft)));
2903
      TraceRegWr(test_fcsr_bit(fcsr_cc));
2904 2905 2906
      break;
    case C_OLT_D:
      set_fcsr_bit(fcsr_cc, (fs < ft));
2907
      TraceRegWr(test_fcsr_bit(fcsr_cc));
2908 2909 2910
      break;
    case C_ULT_D:
      set_fcsr_bit(fcsr_cc, (fs < ft) || (std::isnan(fs) || std::isnan(ft)));
2911
      TraceRegWr(test_fcsr_bit(fcsr_cc));
2912 2913 2914
      break;
    case C_OLE_D:
      set_fcsr_bit(fcsr_cc, (fs <= ft));
2915
      TraceRegWr(test_fcsr_bit(fcsr_cc));
2916 2917 2918
      break;
    case C_ULE_D:
      set_fcsr_bit(fcsr_cc, (fs <= ft) || (std::isnan(fs) || std::isnan(ft)));
2919
      TraceRegWr(test_fcsr_bit(fcsr_cc));
2920
      break;
2921 2922 2923 2924
    case CVT_W_D: {  // Convert double to word.
      double rounded;
      int32_t result;
      round_according_to_fcsr(fs, rounded, result, fs);
2925
      SetFPUWordResult(fd_reg(), result);
2926
      if (set_fcsr_round_error(fs, rounded)) {
2927
        set_fpu_register_word_invalid_result(fs, rounded);
2928 2929
      }
    } break;
2930 2931 2932 2933 2934 2935 2936 2937 2938
    case ROUND_W_D:  // Round double to word (round half to even).
    {
      double rounded = std::floor(fs + 0.5);
      int32_t result = static_cast<int32_t>(rounded);
      if ((result & 1) != 0 && result - fs == 0.5) {
        // If the number is halfway between two integers,
        // round to the even one.
        result--;
      }
2939
      SetFPUWordResult(fd_reg(), result);
2940
      if (set_fcsr_round_error(fs, rounded)) {
2941
        set_fpu_register_word_invalid_result(fs, rounded);
2942 2943 2944 2945 2946 2947
      }
    } break;
    case TRUNC_W_D:  // Truncate double to word (round towards 0).
    {
      double rounded = trunc(fs);
      int32_t result = static_cast<int32_t>(rounded);
2948
      SetFPUWordResult(fd_reg(), result);
2949
      if (set_fcsr_round_error(fs, rounded)) {
2950
        set_fpu_register_word_invalid_result(fs, rounded);
2951 2952 2953 2954 2955 2956
      }
    } break;
    case FLOOR_W_D:  // Round double to word towards negative infinity.
    {
      double rounded = std::floor(fs);
      int32_t result = static_cast<int32_t>(rounded);
2957
      SetFPUWordResult(fd_reg(), result);
2958
      if (set_fcsr_round_error(fs, rounded)) {
2959
        set_fpu_register_word_invalid_result(fs, rounded);
2960 2961 2962 2963 2964 2965
      }
    } break;
    case CEIL_W_D:  // Round double to word towards positive infinity.
    {
      double rounded = std::ceil(fs);
      int32_t result = static_cast<int32_t>(rounded);
2966
      SetFPUWordResult(fd_reg(), result);
2967
      if (set_fcsr_round_error(fs, rounded)) {
2968
        set_fpu_register_word_invalid_result(fs, rounded);
2969 2970 2971
      }
    } break;
    case CVT_S_D:  // Convert double to float (single).
2972
      SetFPUFloatResult(fd_reg(), static_cast<float>(fs));
2973 2974 2975
      break;
    case CVT_L_D: {  // Mips32r2: Truncate double to 64-bit long-word.
      if (IsFp64Mode()) {
2976 2977 2978
        int64_t result;
        double rounded;
        round64_according_to_fcsr(fs, rounded, result, fs);
2979
        SetFPUResult(fd_reg(), result);
2980
        if (set_fcsr_round64_error(fs, rounded)) {
2981
          set_fpu_register_invalid_result64(fs, rounded);
2982
        }
2983
      } else {
2984
        UNSUPPORTED();
2985 2986
      }
      break;
2987
      break;
2988 2989
    }
    case TRUNC_L_D: {  // Mips32r2 instruction.
2990
      DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6));
2991 2992 2993
      double rounded = trunc(fs);
      i64 = static_cast<int64_t>(rounded);
      if (IsFp64Mode()) {
2994
        SetFPUResult(fd_reg(), i64);
2995
        if (set_fcsr_round64_error(fs, rounded)) {
2996
          set_fpu_register_invalid_result64(fs, rounded);
2997
        }
2998
      } else {
2999
        UNSUPPORTED();
3000 3001 3002 3003
      }
      break;
    }
    case ROUND_L_D: {  // Mips32r2 instruction.
3004 3005 3006 3007 3008 3009 3010 3011 3012
      DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6));
      double rounded = std::floor(fs + 0.5);
      int64_t result = static_cast<int64_t>(rounded);
      if ((result & 1) != 0 && result - fs == 0.5) {
        // If the number is halfway between two integers,
        // round to the even one.
        result--;
      }
      int64_t i64 = static_cast<int64_t>(result);
3013
      if (IsFp64Mode()) {
3014
        SetFPUResult(fd_reg(), i64);
3015
        if (set_fcsr_round64_error(fs, rounded)) {
3016
          set_fpu_register_invalid_result64(fs, rounded);
3017
        }
3018
      } else {
3019
        UNSUPPORTED();
3020 3021 3022
      }
      break;
    }
3023 3024 3025 3026
    case FLOOR_L_D: {  // Mips32r2 instruction.
      DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6));
      double rounded = std::floor(fs);
      int64_t i64 = static_cast<int64_t>(rounded);
3027
      if (IsFp64Mode()) {
3028
        SetFPUResult(fd_reg(), i64);
3029
        if (set_fcsr_round64_error(fs, rounded)) {
3030
          set_fpu_register_invalid_result64(fs, rounded);
3031
        }
3032
      } else {
3033
        UNSUPPORTED();
3034 3035
      }
      break;
3036 3037 3038 3039 3040
    }
    case CEIL_L_D: {  // Mips32r2 instruction.
      DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6));
      double rounded = std::ceil(fs);
      int64_t i64 = static_cast<int64_t>(rounded);
3041
      if (IsFp64Mode()) {
3042
        SetFPUResult(fd_reg(), i64);
3043
        if (set_fcsr_round64_error(fs, rounded)) {
3044
          set_fpu_register_invalid_result64(fs, rounded);
3045
        }
3046
      } else {
3047
        UNSUPPORTED();
3048 3049
      }
      break;
3050
    }
3051 3052 3053 3054 3055 3056
    case CLASS_D: {  // Mips32r6 instruction
      // Convert double input to uint64_t for easier bit manipulation
      uint64_t classed = bit_cast<uint64_t>(fs);

      // Extracting sign, exponent and mantissa from the input double
      uint32_t sign = (classed >> 63) & 1;
3057 3058
      uint32_t exponent = (classed >> 52) & 0x00000000000007FF;
      uint64_t mantissa = classed & 0x000FFFFFFFFFFFFF;
3059 3060 3061 3062 3063 3064 3065 3066 3067 3068 3069 3070 3071 3072 3073 3074 3075 3076 3077 3078
      uint64_t result;
      double dResult;

      // Setting flags if input double is negative infinity,
      // positive infinity, negative zero or positive zero
      bool negInf = (classed == 0xFFF0000000000000);
      bool posInf = (classed == 0x7FF0000000000000);
      bool negZero = (classed == 0x8000000000000000);
      bool posZero = (classed == 0x0000000000000000);

      bool signalingNan;
      bool quietNan;
      bool negSubnorm;
      bool posSubnorm;
      bool negNorm;
      bool posNorm;

      // Setting flags if double is NaN
      signalingNan = false;
      quietNan = false;
3079
      if (!negInf && !posInf && exponent == 0x7FF) {
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 3108
        quietNan = ((mantissa & 0x0008000000000000) != 0) &&
                   ((mantissa & (0x0008000000000000 - 1)) == 0);
        signalingNan = !quietNan;
      }

      // Setting flags if double is subnormal number
      posSubnorm = false;
      negSubnorm = false;
      if ((exponent == 0) && (mantissa != 0)) {
        DCHECK(sign == 0 || sign == 1);
        posSubnorm = (sign == 0);
        negSubnorm = (sign == 1);
      }

      // Setting flags if double is normal number
      posNorm = false;
      negNorm = false;
      if (!posSubnorm && !negSubnorm && !posInf && !negInf && !signalingNan &&
          !quietNan && !negZero && !posZero) {
        DCHECK(sign == 0 || sign == 1);
        posNorm = (sign == 0);
        negNorm = (sign == 1);
      }

      // Calculating result according to description of CLASS.D instruction
      result = (posZero << 9) | (posSubnorm << 8) | (posNorm << 7) |
               (posInf << 6) | (negZero << 5) | (negSubnorm << 4) |
               (negNorm << 3) | (negInf << 2) | (quietNan << 1) | signalingNan;

3109
      DCHECK_NE(result, 0);
3110 3111

      dResult = bit_cast<double>(result);
3112
      SetFPUDoubleResult(fd_reg(), dResult);
3113

3114
      break;
3115 3116 3117
    }
    case C_F_D: {
      set_fcsr_bit(fcsr_cc, false);
3118
      TraceRegWr(test_fcsr_bit(fcsr_cc));
3119 3120
      break;
    }
3121 3122 3123 3124
    default:
      UNREACHABLE();
  }
}
3125 3126


3127 3128 3129 3130
void Simulator::DecodeTypeRegisterWRsType() {
  float fs = get_fpu_register_float(fs_reg());
  float ft = get_fpu_register_float(ft_reg());
  int32_t alu_out = 0x12345678;
3131
  switch (instr_.FunctionFieldRaw()) {
3132
    case CVT_S_W:  // Convert word to float (single).
3133
      alu_out = get_fpu_register_signed_word(fs_reg());
3134
      SetFPUFloatResult(fd_reg(), static_cast<float>(alu_out));
3135 3136
      break;
    case CVT_D_W:  // Convert word to double.
3137
      alu_out = get_fpu_register_signed_word(fs_reg());
3138
      SetFPUDoubleResult(fd_reg(), static_cast<double>(alu_out));
3139
      break;
3140
    case CMP_AF:
3141
      SetFPUWordResult(fd_reg(), 0);
3142 3143 3144
      break;
    case CMP_UN:
      if (std::isnan(fs) || std::isnan(ft)) {
3145
        SetFPUWordResult(fd_reg(), -1);
3146
      } else {
3147
        SetFPUWordResult(fd_reg(), 0);
3148 3149 3150 3151
      }
      break;
    case CMP_EQ:
      if (fs == ft) {
3152
        SetFPUWordResult(fd_reg(), -1);
3153
      } else {
3154
        SetFPUWordResult(fd_reg(), 0);
3155 3156 3157 3158
      }
      break;
    case CMP_UEQ:
      if ((fs == ft) || (std::isnan(fs) || std::isnan(ft))) {
3159
        SetFPUWordResult(fd_reg(), -1);
3160
      } else {
3161
        SetFPUWordResult(fd_reg(), 0);
3162 3163 3164 3165
      }
      break;
    case CMP_LT:
      if (fs < ft) {
3166
        SetFPUWordResult(fd_reg(), -1);
3167
      } else {
3168
        SetFPUWordResult(fd_reg(), 0);
3169 3170 3171 3172
      }
      break;
    case CMP_ULT:
      if ((fs < ft) || (std::isnan(fs) || std::isnan(ft))) {
3173
        SetFPUWordResult(fd_reg(), -1);
3174
      } else {
3175
        SetFPUWordResult(fd_reg(), 0);
3176 3177 3178 3179
      }
      break;
    case CMP_LE:
      if (fs <= ft) {
3180
        SetFPUWordResult(fd_reg(), -1);
3181
      } else {
3182
        SetFPUWordResult(fd_reg(), 0);
3183 3184 3185 3186
      }
      break;
    case CMP_ULE:
      if ((fs <= ft) || (std::isnan(fs) || std::isnan(ft))) {
3187
        SetFPUWordResult(fd_reg(), -1);
3188
      } else {
3189
        SetFPUWordResult(fd_reg(), 0);
3190 3191 3192 3193
      }
      break;
    case CMP_OR:
      if (!std::isnan(fs) && !std::isnan(ft)) {
3194
        SetFPUWordResult(fd_reg(), -1);
3195
      } else {
3196
        SetFPUWordResult(fd_reg(), 0);
3197 3198 3199 3200
      }
      break;
    case CMP_UNE:
      if ((fs != ft) || (std::isnan(fs) || std::isnan(ft))) {
3201
        SetFPUWordResult(fd_reg(), -1);
3202
      } else {
3203
        SetFPUWordResult(fd_reg(), 0);
3204 3205 3206 3207
      }
      break;
    case CMP_NE:
      if (fs != ft) {
3208
        SetFPUWordResult(fd_reg(), -1);
3209
      } else {
3210
        SetFPUWordResult(fd_reg(), 0);
3211 3212 3213
      }
      break;
    default:
3214 3215 3216
      UNREACHABLE();
  }
}
3217 3218


3219
void Simulator::DecodeTypeRegisterSRsType() {
3220
  float fs, ft, fd;
3221 3222 3223
  fs = get_fpu_register_float(fs_reg());
  ft = get_fpu_register_float(ft_reg());
  fd = get_fpu_register_float(fd_reg());
3224 3225
  int32_t ft_int = bit_cast<int32_t>(ft);
  int32_t fd_int = bit_cast<int32_t>(fd);
3226
  uint32_t cc, fcsr_cc;
3227
  cc = instr_.FCccValue();
3228
  fcsr_cc = get_fcsr_condition_bit(cc);
3229
  switch (instr_.FunctionFieldRaw()) {
3230 3231 3232 3233 3234 3235 3236 3237 3238 3239 3240 3241 3242 3243 3244 3245 3246 3247 3248 3249 3250 3251 3252 3253 3254 3255 3256 3257 3258 3259 3260 3261
    case RINT: {
      DCHECK(IsMipsArchVariant(kMips32r6));
      float result, temp_result;
      double temp;
      float upper = std::ceil(fs);
      float lower = std::floor(fs);
      switch (get_fcsr_rounding_mode()) {
        case kRoundToNearest:
          if (upper - fs < fs - lower) {
            result = upper;
          } else if (upper - fs > fs - lower) {
            result = lower;
          } else {
            temp_result = upper / 2;
            float reminder = modf(temp_result, &temp);
            if (reminder == 0) {
              result = upper;
            } else {
              result = lower;
            }
          }
          break;
        case kRoundToZero:
          result = (fs > 0 ? lower : upper);
          break;
        case kRoundToPlusInf:
          result = upper;
          break;
        case kRoundToMinusInf:
          result = lower;
          break;
      }
3262
      SetFPUFloatResult(fd_reg(), result);
3263 3264 3265 3266 3267 3268
      if (result != fs) {
        set_fcsr_bit(kFCSRInexactFlagBit, true);
      }
      break;
    }
    case ADD_S:
3269
      SetFPUFloatResult(
3270 3271 3272
          fd_reg(),
          FPUCanonalizeOperation([](float lhs, float rhs) { return lhs + rhs; },
                                 fs, ft));
3273
      break;
3274
    case SUB_S:
3275
      SetFPUFloatResult(
3276 3277 3278
          fd_reg(),
          FPUCanonalizeOperation([](float lhs, float rhs) { return lhs - rhs; },
                                 fs, ft));
3279
      break;
3280 3281
    case MADDF_S:
      DCHECK(IsMipsArchVariant(kMips32r6));
3282
      SetFPUFloatResult(fd_reg(), std::fma(fs, ft, fd));
3283 3284 3285
      break;
    case MSUBF_S:
      DCHECK(IsMipsArchVariant(kMips32r6));
3286
      SetFPUFloatResult(fd_reg(), std::fma(-fs, ft, fd));
3287
      break;
3288
    case MUL_S:
3289
      SetFPUFloatResult(
3290 3291 3292
          fd_reg(),
          FPUCanonalizeOperation([](float lhs, float rhs) { return lhs * rhs; },
                                 fs, ft));
3293
      break;
3294
    case DIV_S:
3295
      SetFPUFloatResult(
3296 3297 3298
          fd_reg(),
          FPUCanonalizeOperation([](float lhs, float rhs) { return lhs / rhs; },
                                 fs, ft));
3299
      break;
3300
    case ABS_S:
3301 3302
      SetFPUFloatResult(fd_reg(), FPUCanonalizeOperation(
                                      [](float fs) { return FPAbs(fs); }, fs));
3303
      break;
3304
    case MOV_S:
3305
      SetFPUFloatResult(fd_reg(), fs);
3306
      break;
3307
    case NEG_S:
3308 3309 3310
      SetFPUFloatResult(fd_reg(),
                        FPUCanonalizeOperation([](float src) { return -src; },
                                               KeepSign::yes, fs));
3311
      break;
3312
    case SQRT_S:
3313
      SetFPUFloatResult(
3314 3315
          fd_reg(),
          FPUCanonalizeOperation([](float src) { return std::sqrt(src); }, fs));
3316
      break;
3317
    case RSQRT_S:
3318
      SetFPUFloatResult(
3319 3320
          fd_reg(), FPUCanonalizeOperation(
                        [](float src) { return 1.0 / std::sqrt(src); }, fs));
3321
      break;
3322
    case RECIP_S:
3323 3324
      SetFPUFloatResult(fd_reg(), FPUCanonalizeOperation(
                                      [](float src) { return 1.0 / src; }, fs));
3325
      break;
3326 3327
    case C_F_D:
      set_fcsr_bit(fcsr_cc, false);
3328
      TraceRegWr(test_fcsr_bit(fcsr_cc));
3329
      break;
3330 3331
    case C_UN_D:
      set_fcsr_bit(fcsr_cc, std::isnan(fs) || std::isnan(ft));
3332
      TraceRegWr(test_fcsr_bit(fcsr_cc));
3333 3334 3335
      break;
    case C_EQ_D:
      set_fcsr_bit(fcsr_cc, (fs == ft));
3336
      TraceRegWr(test_fcsr_bit(fcsr_cc));
3337 3338 3339
      break;
    case C_UEQ_D:
      set_fcsr_bit(fcsr_cc, (fs == ft) || (std::isnan(fs) || std::isnan(ft)));
3340
      TraceRegWr(test_fcsr_bit(fcsr_cc));
3341 3342 3343
      break;
    case C_OLT_D:
      set_fcsr_bit(fcsr_cc, (fs < ft));
3344
      TraceRegWr(test_fcsr_bit(fcsr_cc));
3345 3346 3347
      break;
    case C_ULT_D:
      set_fcsr_bit(fcsr_cc, (fs < ft) || (std::isnan(fs) || std::isnan(ft)));
3348
      TraceRegWr(test_fcsr_bit(fcsr_cc));
3349 3350 3351
      break;
    case C_OLE_D:
      set_fcsr_bit(fcsr_cc, (fs <= ft));
3352
      TraceRegWr(test_fcsr_bit(fcsr_cc));
3353 3354 3355
      break;
    case C_ULE_D:
      set_fcsr_bit(fcsr_cc, (fs <= ft) || (std::isnan(fs) || std::isnan(ft)));
3356
      TraceRegWr(test_fcsr_bit(fcsr_cc));
3357
      break;
3358
    case CVT_D_S:
3359
      SetFPUDoubleResult(fd_reg(), static_cast<double>(fs));
3360
      break;
3361 3362
    case SEL:
      DCHECK(IsMipsArchVariant(kMips32r6));
3363
      SetFPUFloatResult(fd_reg(), (fd_int & 0x1) == 0 ? fs : ft);
3364
      break;
3365 3366
    case CLASS_S: {  // Mips32r6 instruction
      // Convert float input to uint32_t for easier bit manipulation
3367
      float fs = get_fpu_register_float(fs_reg());
3368 3369 3370 3371
      uint32_t classed = bit_cast<uint32_t>(fs);

      // Extracting sign, exponent and mantissa from the input float
      uint32_t sign = (classed >> 31) & 1;
3372 3373
      uint32_t exponent = (classed >> 23) & 0x000000FF;
      uint32_t mantissa = classed & 0x007FFFFF;
3374 3375 3376 3377 3378 3379 3380 3381 3382 3383 3384 3385 3386 3387 3388 3389 3390 3391 3392 3393
      uint32_t result;
      float fResult;

      // Setting flags if input float is negative infinity,
      // positive infinity, negative zero or positive zero
      bool negInf = (classed == 0xFF800000);
      bool posInf = (classed == 0x7F800000);
      bool negZero = (classed == 0x80000000);
      bool posZero = (classed == 0x00000000);

      bool signalingNan;
      bool quietNan;
      bool negSubnorm;
      bool posSubnorm;
      bool negNorm;
      bool posNorm;

      // Setting flags if float is NaN
      signalingNan = false;
      quietNan = false;
3394
      if (!negInf && !posInf && (exponent == 0xFF)) {
3395 3396 3397 3398 3399 3400 3401 3402 3403 3404 3405 3406 3407 3408 3409 3410 3411 3412 3413 3414 3415 3416 3417 3418 3419 3420 3421 3422 3423
        quietNan = ((mantissa & 0x00200000) == 0) &&
                   ((mantissa & (0x00200000 - 1)) == 0);
        signalingNan = !quietNan;
      }

      // Setting flags if float is subnormal number
      posSubnorm = false;
      negSubnorm = false;
      if ((exponent == 0) && (mantissa != 0)) {
        DCHECK(sign == 0 || sign == 1);
        posSubnorm = (sign == 0);
        negSubnorm = (sign == 1);
      }

      // Setting flags if float is normal number
      posNorm = false;
      negNorm = false;
      if (!posSubnorm && !negSubnorm && !posInf && !negInf && !signalingNan &&
          !quietNan && !negZero && !posZero) {
        DCHECK(sign == 0 || sign == 1);
        posNorm = (sign == 0);
        negNorm = (sign == 1);
      }

      // Calculating result according to description of CLASS.S instruction
      result = (posZero << 9) | (posSubnorm << 8) | (posNorm << 7) |
               (posInf << 6) | (negZero << 5) | (negSubnorm << 4) |
               (negNorm << 3) | (negInf << 2) | (quietNan << 1) | signalingNan;

3424
      DCHECK_NE(result, 0);
3425 3426

      fResult = bit_cast<float>(result);
3427
      SetFPUFloatResult(fd_reg(), fResult);
3428 3429 3430

      break;
    }
3431 3432
    case SELEQZ_C:
      DCHECK(IsMipsArchVariant(kMips32r6));
3433 3434 3435
      SetFPUFloatResult(
          fd_reg(),
          (ft_int & 0x1) == 0 ? get_fpu_register_float(fs_reg()) : 0.0);
3436 3437 3438
      break;
    case SELNEZ_C:
      DCHECK(IsMipsArchVariant(kMips32r6));
3439 3440 3441
      SetFPUFloatResult(
          fd_reg(),
          (ft_int & 0x1) != 0 ? get_fpu_register_float(fs_reg()) : 0.0);
3442 3443 3444
      break;
    case MOVZ_C: {
      DCHECK(IsMipsArchVariant(kMips32r2));
3445
      if (rt() == 0) {
3446
        SetFPUFloatResult(fd_reg(), fs);
3447 3448 3449 3450 3451
      }
      break;
    }
    case MOVN_C: {
      DCHECK(IsMipsArchVariant(kMips32r2));
3452
      if (rt() != 0) {
3453
        SetFPUFloatResult(fd_reg(), fs);
3454 3455 3456 3457 3458
      }
      break;
    }
    case MOVF: {
      // Same function field for MOVT.D and MOVF.D
3459
      uint32_t ft_cc = (ft_reg() >> 2) & 0x7;
3460 3461
      ft_cc = get_fcsr_condition_bit(ft_cc);

3462
      if (instr_.Bit(16)) {  // Read Tf bit.
3463
        // MOVT.D
3464
        if (test_fcsr_bit(ft_cc)) SetFPUFloatResult(fd_reg(), fs);
3465 3466
      } else {
        // MOVF.D
3467
        if (!test_fcsr_bit(ft_cc)) SetFPUFloatResult(fd_reg(), fs);
3468 3469 3470 3471 3472 3473
      }
      break;
    }
    case TRUNC_W_S: {  // Truncate single to word (round towards 0).
      float rounded = trunc(fs);
      int32_t result = static_cast<int32_t>(rounded);
3474
      SetFPUWordResult(fd_reg(), result);
3475
      if (set_fcsr_round_error(fs, rounded)) {
3476
        set_fpu_register_word_invalid_result(fs, rounded);
3477 3478 3479 3480 3481 3482 3483
      }
    } break;
    case TRUNC_L_S: {  // Mips32r2 instruction.
      DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6));
      float rounded = trunc(fs);
      int64_t i64 = static_cast<int64_t>(rounded);
      if (IsFp64Mode()) {
3484
        SetFPUResult(fd_reg(), i64);
3485
        if (set_fcsr_round64_error(fs, rounded)) {
3486
          set_fpu_register_invalid_result64(fs, rounded);
3487 3488 3489 3490 3491 3492 3493 3494 3495 3496
        }
      } else {
        UNSUPPORTED();
      }
      break;
    }
    case FLOOR_W_S:  // Round double to word towards negative infinity.
    {
      float rounded = std::floor(fs);
      int32_t result = static_cast<int32_t>(rounded);
3497
      SetFPUWordResult(fd_reg(), result);
3498
      if (set_fcsr_round_error(fs, rounded)) {
3499
        set_fpu_register_word_invalid_result(fs, rounded);
3500 3501 3502 3503 3504 3505 3506
      }
    } break;
    case FLOOR_L_S: {  // Mips32r2 instruction.
      DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6));
      float rounded = std::floor(fs);
      int64_t i64 = static_cast<int64_t>(rounded);
      if (IsFp64Mode()) {
3507
        SetFPUResult(fd_reg(), i64);
3508
        if (set_fcsr_round64_error(fs, rounded)) {
3509
          set_fpu_register_invalid_result64(fs, rounded);
3510 3511 3512 3513 3514 3515 3516 3517 3518 3519 3520 3521 3522 3523
        }
      } else {
        UNSUPPORTED();
      }
      break;
    }
    case ROUND_W_S: {
      float rounded = std::floor(fs + 0.5);
      int32_t result = static_cast<int32_t>(rounded);
      if ((result & 1) != 0 && result - fs == 0.5) {
        // If the number is halfway between two integers,
        // round to the even one.
        result--;
      }
3524
      SetFPUWordResult(fd_reg(), result);
3525
      if (set_fcsr_round_error(fs, rounded)) {
3526
        set_fpu_register_word_invalid_result(fs, rounded);
3527 3528 3529 3530 3531 3532 3533 3534 3535 3536 3537 3538 3539 3540
      }
      break;
    }
    case ROUND_L_S: {  // Mips32r2 instruction.
      DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6));
      float rounded = std::floor(fs + 0.5);
      int64_t result = static_cast<int64_t>(rounded);
      if ((result & 1) != 0 && result - fs == 0.5) {
        // If the number is halfway between two integers,
        // round to the even one.
        result--;
      }
      int64_t i64 = static_cast<int64_t>(result);
      if (IsFp64Mode()) {
3541
        SetFPUResult(fd_reg(), i64);
3542
        if (set_fcsr_round64_error(fs, rounded)) {
3543
          set_fpu_register_invalid_result64(fs, rounded);
3544 3545 3546 3547 3548 3549 3550 3551 3552 3553
        }
      } else {
        UNSUPPORTED();
      }
      break;
    }
    case CEIL_W_S:  // Round double to word towards positive infinity.
    {
      float rounded = std::ceil(fs);
      int32_t result = static_cast<int32_t>(rounded);
3554
      SetFPUWordResult(fd_reg(), result);
3555
      if (set_fcsr_round_error(fs, rounded)) {
3556
        set_fpu_register_word_invalid_result(fs, rounded);
3557 3558 3559 3560 3561 3562 3563
      }
    } break;
    case CEIL_L_S: {  // Mips32r2 instruction.
      DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6));
      float rounded = std::ceil(fs);
      int64_t i64 = static_cast<int64_t>(rounded);
      if (IsFp64Mode()) {
3564
        SetFPUResult(fd_reg(), i64);
3565
        if (set_fcsr_round64_error(fs, rounded)) {
3566
          set_fpu_register_invalid_result64(fs, rounded);
3567 3568 3569 3570 3571 3572 3573 3574
        }
      } else {
        UNSUPPORTED();
      }
      break;
    }
    case MIN:
      DCHECK(IsMipsArchVariant(kMips32r6));
3575
      SetFPUFloatResult(fd_reg(), FPUMin(ft, fs));
3576 3577 3578
      break;
    case MAX:
      DCHECK(IsMipsArchVariant(kMips32r6));
3579
      SetFPUFloatResult(fd_reg(), FPUMax(ft, fs));
3580 3581 3582
      break;
    case MINA:
      DCHECK(IsMipsArchVariant(kMips32r6));
3583
      SetFPUFloatResult(fd_reg(), FPUMinA(ft, fs));
3584 3585 3586
      break;
    case MAXA:
      DCHECK(IsMipsArchVariant(kMips32r6));
3587
      SetFPUFloatResult(fd_reg(), FPUMaxA(ft, fs));
3588
      break;
3589 3590 3591 3592 3593
    case CVT_L_S: {
      if (IsFp64Mode()) {
        int64_t result;
        float rounded;
        round64_according_to_fcsr(fs, rounded, result, fs);
3594
        SetFPUResult(fd_reg(), result);
3595
        if (set_fcsr_round64_error(fs, rounded)) {
3596
          set_fpu_register_invalid_result64(fs, rounded);
3597 3598 3599 3600 3601 3602 3603 3604 3605 3606
        }
      } else {
        UNSUPPORTED();
      }
      break;
    }
    case CVT_W_S: {
      float rounded;
      int32_t result;
      round_according_to_fcsr(fs, rounded, result, fs);
3607
      SetFPUWordResult(fd_reg(), result);
3608
      if (set_fcsr_round_error(fs, rounded)) {
3609
        set_fpu_register_word_invalid_result(fs, rounded);
3610 3611 3612
      }
      break;
    }
3613
    default:
3614
      // CVT_W_S CVT_L_S  ROUND_W_S ROUND_L_S FLOOR_W_S FLOOR_L_S
3615 3616 3617 3618
      // CEIL_W_S CEIL_L_S CVT_PS_S are unimplemented.
      UNREACHABLE();
  }
}
3619 3620


3621 3622 3623
void Simulator::DecodeTypeRegisterLRsType() {
  double fs = get_fpu_register_double(fs_reg());
  double ft = get_fpu_register_double(ft_reg());
3624
  switch (instr_.FunctionFieldRaw()) {
3625 3626 3627 3628 3629
    case CVT_D_L:  // Mips32r2 instruction.
      // Watch the signs here, we want 2 32-bit vals
      // to make a sign-64.
      int64_t i64;
      if (IsFp64Mode()) {
3630
        i64 = get_fpu_register(fs_reg());
3631
      } else {
3632 3633
        i64 = static_cast<uint32_t>(get_fpu_register_word(fs_reg()));
        i64 |= static_cast<int64_t>(get_fpu_register_word(fs_reg() + 1)) << 32;
3634
      }
3635
      SetFPUDoubleResult(fd_reg(), static_cast<double>(i64));
3636
      break;
3637
    case CVT_S_L:
3638
      if (IsFp64Mode()) {
3639
        i64 = get_fpu_register(fs_reg());
3640
      } else {
3641 3642
        i64 = static_cast<uint32_t>(get_fpu_register_word(fs_reg()));
        i64 |= static_cast<int64_t>(get_fpu_register_word(fs_reg() + 1)) << 32;
3643
      }
3644
      SetFPUFloatResult(fd_reg(), static_cast<float>(i64));
3645 3646
      break;
    case CMP_AF:  // Mips64r6 CMP.D instructions.
3647
      SetFPUResult(fd_reg(), 0);
3648 3649 3650
      break;
    case CMP_UN:
      if (std::isnan(fs) || std::isnan(ft)) {
3651
        SetFPUResult(fd_reg(), -1);
3652
      } else {
3653
        SetFPUResult(fd_reg(), 0);
3654
      }
3655
      break;
3656 3657
    case CMP_EQ:
      if (fs == ft) {
3658
        SetFPUResult(fd_reg(), -1);
3659
      } else {
3660
        SetFPUResult(fd_reg(), 0);
3661 3662 3663 3664
      }
      break;
    case CMP_UEQ:
      if ((fs == ft) || (std::isnan(fs) || std::isnan(ft))) {
3665
        SetFPUResult(fd_reg(), -1);
3666
      } else {
3667
        SetFPUResult(fd_reg(), 0);
3668 3669 3670 3671
      }
      break;
    case CMP_LT:
      if (fs < ft) {
3672
        SetFPUResult(fd_reg(), -1);
3673
      } else {
3674
        SetFPUResult(fd_reg(), 0);
3675 3676 3677 3678
      }
      break;
    case CMP_ULT:
      if ((fs < ft) || (std::isnan(fs) || std::isnan(ft))) {
3679
        SetFPUResult(fd_reg(), -1);
3680
      } else {
3681
        SetFPUResult(fd_reg(), 0);
3682 3683 3684 3685
      }
      break;
    case CMP_LE:
      if (fs <= ft) {
3686
        SetFPUResult(fd_reg(), -1);
3687
      } else {
3688
        SetFPUResult(fd_reg(), 0);
3689 3690 3691 3692
      }
      break;
    case CMP_ULE:
      if ((fs <= ft) || (std::isnan(fs) || std::isnan(ft))) {
3693
        SetFPUResult(fd_reg(), -1);
3694
      } else {
3695
        SetFPUResult(fd_reg(), 0);
3696 3697
      }
      break;
3698 3699
    case CMP_OR:
      if (!std::isnan(fs) && !std::isnan(ft)) {
3700
        SetFPUResult(fd_reg(), -1);
3701
      } else {
3702
        SetFPUResult(fd_reg(), 0);
3703 3704 3705 3706
      }
      break;
    case CMP_UNE:
      if ((fs != ft) || (std::isnan(fs) || std::isnan(ft))) {
3707
        SetFPUResult(fd_reg(), -1);
3708
      } else {
3709
        SetFPUResult(fd_reg(), 0);
3710 3711 3712 3713
      }
      break;
    case CMP_NE:
      if (fs != ft && (!std::isnan(fs) && !std::isnan(ft))) {
3714
        SetFPUResult(fd_reg(), -1);
3715
      } else {
3716
        SetFPUResult(fd_reg(), 0);
3717 3718 3719
      }
      break;
    default:
3720 3721 3722 3723 3724
      UNREACHABLE();
  }
}


3725
void Simulator::DecodeTypeRegisterCOP1() {
3726
  switch (instr_.RsFieldRaw()) {
3727
    case CFC1:
3728
      // At the moment only FCSR is supported.
3729
      DCHECK_EQ(fs_reg(), kFCSRRegister);
3730
      SetResult(rt_reg(), FCSR_);
3731 3732
      break;
    case MFC1:
3733
      SetResult(rt_reg(), get_fpu_register_word(fs_reg()));
3734 3735
      break;
    case MFHC1:
3736
      if (IsFp64Mode()) {
3737
        SetResult(rt_reg(), get_fpu_register_hi_word(fs_reg()));
3738
      } else {
3739
        SetResult(rt_reg(), get_fpu_register_word(fs_reg() + 1));
3740
      }
3741
      break;
3742
    case CTC1: {
3743
      // At the moment only FCSR is supported.
3744
      DCHECK_EQ(fs_reg(), kFCSRRegister);
3745 3746 3747 3748 3749 3750 3751
      int32_t reg = registers_[rt_reg()];
      if (IsMipsArchVariant(kMips32r6)) {
        FCSR_ = reg | kFCSRNaN2008FlagMask;
      } else {
        DCHECK(IsMipsArchVariant(kMips32r1) || IsMipsArchVariant(kMips32r2));
        FCSR_ = reg & ~kFCSRNaN2008FlagMask;
      }
3752
      TraceRegWr(static_cast<int32_t>(FCSR_));
3753
      break;
3754
    }
3755 3756
    case MTC1:
      // Hardware writes upper 32-bits to zero on mtc1.
3757 3758
      set_fpu_register_hi_word(fs_reg(), 0);
      set_fpu_register_word(fs_reg(), registers_[rt_reg()]);
3759
      TraceRegWr(get_fpu_register_word(fs_reg()), FLOAT);
3760 3761
      break;
    case MTHC1:
3762 3763
      if (IsFp64Mode()) {
        set_fpu_register_hi_word(fs_reg(), registers_[rt_reg()]);
3764
        TraceRegWr(get_fpu_register(fs_reg()), DOUBLE);
3765 3766
      } else {
        set_fpu_register_word(fs_reg() + 1, registers_[rt_reg()]);
3767 3768 3769 3770 3771
        if (fs_reg() % 2) {
          TraceRegWr(get_fpu_register_word(fs_reg() + 1), FLOAT);
        } else {
          TraceRegWr(get_fpu_register(fs_reg()), DOUBLE);
        }
3772
      }
3773 3774
      break;
    case S: {
3775
      DecodeTypeRegisterSRsType();
3776 3777 3778
      break;
    }
    case D:
3779
      DecodeTypeRegisterDRsType();
3780 3781
      break;
    case W:
3782
      DecodeTypeRegisterWRsType();
3783 3784
      break;
    case L:
3785
      DecodeTypeRegisterLRsType();
3786
      break;
3787 3788 3789
    case PS:
      // Not implemented.
      UNREACHABLE();
3790 3791 3792 3793 3794 3795
    default:
      UNREACHABLE();
  }
}


3796
void Simulator::DecodeTypeRegisterCOP1X() {
3797
  switch (instr_.FunctionFieldRaw()) {
3798 3799 3800 3801 3802 3803
    case MADD_S: {
      DCHECK(IsMipsArchVariant(kMips32r2));
      float fr, ft, fs;
      fr = get_fpu_register_float(fr_reg());
      fs = get_fpu_register_float(fs_reg());
      ft = get_fpu_register_float(ft_reg());
3804
      SetFPUFloatResult(fd_reg(), fs * ft + fr);
3805 3806 3807 3808 3809 3810 3811 3812
      break;
    }
    case MSUB_S: {
      DCHECK(IsMipsArchVariant(kMips32r2));
      float fr, ft, fs;
      fr = get_fpu_register_float(fr_reg());
      fs = get_fpu_register_float(fs_reg());
      ft = get_fpu_register_float(ft_reg());
3813
      SetFPUFloatResult(fd_reg(), fs * ft - fr);
3814 3815 3816 3817
      break;
    }
    case MADD_D: {
      DCHECK(IsMipsArchVariant(kMips32r2));
3818
      double fr, ft, fs;
3819 3820 3821
      fr = get_fpu_register_double(fr_reg());
      fs = get_fpu_register_double(fs_reg());
      ft = get_fpu_register_double(ft_reg());
3822
      SetFPUDoubleResult(fd_reg(), fs * ft + fr);
3823
      break;
3824 3825 3826 3827 3828 3829 3830
    }
    case MSUB_D: {
      DCHECK(IsMipsArchVariant(kMips32r2));
      double fr, ft, fs;
      fr = get_fpu_register_double(fr_reg());
      fs = get_fpu_register_double(fs_reg());
      ft = get_fpu_register_double(ft_reg());
3831
      SetFPUDoubleResult(fd_reg(), fs * ft - fr);
3832 3833
      break;
    }
3834 3835 3836 3837 3838 3839
    default:
      UNREACHABLE();
  }
}


3840 3841 3842 3843 3844 3845
void Simulator::DecodeTypeRegisterSPECIAL() {
  int64_t alu_out = 0x12345678;
  int64_t i64hilo = 0;
  uint64_t u64hilo = 0;
  bool do_interrupt = false;

3846
  switch (instr_.FunctionFieldRaw()) {
3847 3848
    case SELEQZ_S:
      DCHECK(IsMipsArchVariant(kMips32r6));
3849
      SetResult(rd_reg(), rt() == 0 ? rs() : 0);
3850 3851 3852
      break;
    case SELNEZ_S:
      DCHECK(IsMipsArchVariant(kMips32r6));
3853
      SetResult(rd_reg(), rt() != 0 ? rs() : 0);
3854 3855 3856 3857 3858
      break;
    case JR: {
      int32_t next_pc = rs();
      int32_t current_pc = get_pc();
      Instruction* branch_delay_instr =
3859
          reinterpret_cast<Instruction*>(current_pc + kInstrSize);
3860 3861 3862 3863 3864 3865 3866 3867 3868 3869
      BranchDelayInstructionDecode(branch_delay_instr);
      set_pc(next_pc);
      pc_modified_ = true;
      break;
    }
    case JALR: {
      int32_t next_pc = rs();
      int32_t return_addr_reg = rd_reg();
      int32_t current_pc = get_pc();
      Instruction* branch_delay_instr =
3870
          reinterpret_cast<Instruction*>(current_pc + kInstrSize);
3871
      BranchDelayInstructionDecode(branch_delay_instr);
3872
      set_register(return_addr_reg, current_pc + 2 * kInstrSize);
3873 3874 3875 3876 3877 3878 3879 3880 3881 3882 3883 3884 3885 3886 3887 3888 3889 3890 3891 3892 3893 3894 3895 3896 3897 3898 3899 3900 3901 3902 3903 3904 3905 3906 3907 3908 3909 3910 3911 3912 3913 3914 3915
      set_pc(next_pc);
      pc_modified_ = true;
      break;
    }
    case SLL:
      alu_out = rt() << sa();
      SetResult(rd_reg(), static_cast<int32_t>(alu_out));
      break;
    case SRL:
      if (rs_reg() == 0) {
        // Regular logical right shift of a word by a fixed number of
        // bits instruction. RS field is always equal to 0.
        alu_out = rt_u() >> sa();
      } else {
        // Logical right-rotate of a word by a fixed number of bits. This
        // is special case of SRL instruction, added in MIPS32 Release 2.
        // RS field is equal to 00001.
        alu_out = base::bits::RotateRight32(rt_u(), sa());
      }
      SetResult(rd_reg(), static_cast<int32_t>(alu_out));
      break;
    case SRA:
      alu_out = rt() >> sa();
      SetResult(rd_reg(), static_cast<int32_t>(alu_out));
      break;
    case SLLV:
      alu_out = rt() << rs();
      SetResult(rd_reg(), static_cast<int32_t>(alu_out));
      break;
    case SRLV:
      if (sa() == 0) {
        // Regular logical right-shift of a word by a variable number of
        // bits instruction. SA field is always equal to 0.
        alu_out = rt_u() >> rs();
      } else {
        // Logical right-rotate of a word by a variable number of bits.
        // This is special case od SRLV instruction, added in MIPS32
        // Release 2. SA field is equal to 00001.
        alu_out = base::bits::RotateRight32(rt_u(), rs_u());
      }
      SetResult(rd_reg(), static_cast<int32_t>(alu_out));
      break;
    case SRAV:
3916 3917 3918 3919 3920 3921 3922 3923 3924 3925 3926
      SetResult(rd_reg(), rt() >> rs());
      break;
    case LSA: {
      DCHECK(IsMipsArchVariant(kMips32r6));
      int8_t sa = lsa_sa() + 1;
      int32_t _rt = rt();
      int32_t _rs = rs();
      int32_t res = _rs << sa;
      res += _rt;
      DCHECK_EQ(res, (rs() << (lsa_sa() + 1)) + rt());
      SetResult(rd_reg(), (rs() << (lsa_sa() + 1)) + rt());
3927
      break;
3928
    }
3929 3930
    case MFHI:  // MFHI == CLZ on R6.
      if (!IsMipsArchVariant(kMips32r6)) {
3931
        DCHECK_EQ(sa(), 0);
3932 3933 3934 3935
        alu_out = get_register(HI);
      } else {
        // MIPS spec: If no bits were set in GPR rs, the result written to
        // GPR rd is 32.
3936
        DCHECK_EQ(sa(), 1);
3937 3938 3939 3940 3941 3942 3943 3944 3945 3946 3947 3948
        alu_out = base::bits::CountLeadingZeros32(rs_u());
      }
      SetResult(rd_reg(), static_cast<int32_t>(alu_out));
      break;
    case MFLO:
      alu_out = get_register(LO);
      SetResult(rd_reg(), static_cast<int32_t>(alu_out));
      break;
    // Instructions using HI and LO registers.
    case MULT:
      i64hilo = static_cast<int64_t>(rs()) * static_cast<int64_t>(rt());
      if (!IsMipsArchVariant(kMips32r6)) {
3949
        set_register(LO, static_cast<int32_t>(i64hilo & 0xFFFFFFFF));
3950 3951 3952 3953
        set_register(HI, static_cast<int32_t>(i64hilo >> 32));
      } else {
        switch (sa()) {
          case MUL_OP:
3954
            SetResult(rd_reg(), static_cast<int32_t>(i64hilo & 0xFFFFFFFF));
3955 3956
            break;
          case MUH_OP:
3957
            SetResult(rd_reg(), static_cast<int32_t>(i64hilo >> 32));
3958 3959 3960 3961
            break;
          default:
            UNIMPLEMENTED_MIPS();
            break;
3962
        }
3963 3964 3965 3966 3967
      }
      break;
    case MULTU:
      u64hilo = static_cast<uint64_t>(rs_u()) * static_cast<uint64_t>(rt_u());
      if (!IsMipsArchVariant(kMips32r6)) {
3968
        set_register(LO, static_cast<int32_t>(u64hilo & 0xFFFFFFFF));
3969 3970 3971 3972
        set_register(HI, static_cast<int32_t>(u64hilo >> 32));
      } else {
        switch (sa()) {
          case MUL_OP:
3973
            SetResult(rd_reg(), static_cast<int32_t>(u64hilo & 0xFFFFFFFF));
3974 3975
            break;
          case MUH_OP:
3976
            SetResult(rd_reg(), static_cast<int32_t>(u64hilo >> 32));
3977 3978 3979 3980
            break;
          default:
            UNIMPLEMENTED_MIPS();
            break;
3981
        }
3982 3983 3984 3985
      }
      break;
    case DIV:
      if (IsMipsArchVariant(kMips32r6)) {
3986
        switch (sa()) {
3987 3988
          case DIV_OP:
            if (rs() == INT_MIN && rt() == -1) {
3989
              SetResult(rd_reg(), INT_MIN);
3990
            } else if (rt() != 0) {
3991
              SetResult(rd_reg(), rs() / rt());
3992
            }
3993 3994 3995
            break;
          case MOD_OP:
            if (rs() == INT_MIN && rt() == -1) {
3996
              SetResult(rd_reg(), 0);
3997
            } else if (rt() != 0) {
3998
              SetResult(rd_reg(), rs() % rt());
3999
            }
4000 4001 4002 4003 4004 4005 4006 4007 4008 4009 4010 4011 4012 4013 4014 4015 4016 4017 4018 4019 4020
            break;
          default:
            UNIMPLEMENTED_MIPS();
            break;
        }
      } else {
        // Divide by zero and overflow was not checked in the
        // configuration step - div and divu do not raise exceptions. On
        // division by 0 the result will be UNPREDICTABLE. On overflow
        // (INT_MIN/-1), return INT_MIN which is what the hardware does.
        if (rs() == INT_MIN && rt() == -1) {
          set_register(LO, INT_MIN);
          set_register(HI, 0);
        } else if (rt() != 0) {
          set_register(LO, rs() / rt());
          set_register(HI, rs() % rt());
        }
      }
      break;
    case DIVU:
      if (IsMipsArchVariant(kMips32r6)) {
4021
        switch (sa()) {
4022 4023
          case DIV_OP:
            if (rt_u() != 0) {
4024
              SetResult(rd_reg(), rs_u() / rt_u());
4025
            }
4026 4027 4028
            break;
          case MOD_OP:
            if (rt_u() != 0) {
4029
              SetResult(rd_reg(), rs_u() % rt_u());
4030
            }
4031 4032 4033 4034 4035 4036 4037 4038 4039 4040 4041 4042 4043 4044 4045 4046 4047
            break;
          default:
            UNIMPLEMENTED_MIPS();
            break;
        }
      } else {
        if (rt_u() != 0) {
          set_register(LO, rs_u() / rt_u());
          set_register(HI, rs_u() % rt_u());
        }
      }
      break;
    case ADD:
      if (HaveSameSign(rs(), rt())) {
        if (rs() > 0) {
          if (rs() <= (Registers::kMaxValue - rt())) {
            SignalException(kIntegerOverflow);
4048
          }
4049 4050 4051
        } else if (rs() < 0) {
          if (rs() >= (Registers::kMinValue - rt())) {
            SignalException(kIntegerUnderflow);
4052
          }
4053 4054 4055 4056 4057 4058 4059 4060 4061 4062 4063 4064
        }
      }
      SetResult(rd_reg(), rs() + rt());
      break;
    case ADDU:
      SetResult(rd_reg(), rs() + rt());
      break;
    case SUB:
      if (!HaveSameSign(rs(), rt())) {
        if (rs() > 0) {
          if (rs() <= (Registers::kMaxValue + rt())) {
            SignalException(kIntegerOverflow);
4065
          }
4066 4067 4068
        } else if (rs() < 0) {
          if (rs() >= (Registers::kMinValue + rt())) {
            SignalException(kIntegerUnderflow);
4069 4070
          }
        }
4071
      }
4072 4073 4074 4075 4076 4077 4078 4079 4080 4081 4082 4083 4084 4085 4086 4087 4088 4089 4090 4091 4092 4093 4094 4095 4096 4097 4098 4099 4100 4101 4102 4103 4104 4105 4106 4107 4108 4109 4110 4111 4112 4113 4114 4115 4116
      SetResult(rd_reg(), rs() - rt());
      break;
    case SUBU:
      SetResult(rd_reg(), rs() - rt());
      break;
    case AND:
      SetResult(rd_reg(), rs() & rt());
      break;
    case OR:
      SetResult(rd_reg(), rs() | rt());
      break;
    case XOR:
      SetResult(rd_reg(), rs() ^ rt());
      break;
    case NOR:
      SetResult(rd_reg(), ~(rs() | rt()));
      break;
    case SLT:
      SetResult(rd_reg(), rs() < rt() ? 1 : 0);
      break;
    case SLTU:
      SetResult(rd_reg(), rs_u() < rt_u() ? 1 : 0);
      break;
    // Break and trap instructions.
    case BREAK:
      do_interrupt = true;
      break;
    case TGE:
      do_interrupt = rs() >= rt();
      break;
    case TGEU:
      do_interrupt = rs_u() >= rt_u();
      break;
    case TLT:
      do_interrupt = rs() < rt();
      break;
    case TLTU:
      do_interrupt = rs_u() < rt_u();
      break;
    case TEQ:
      do_interrupt = rs() == rt();
      break;
    case TNE:
      do_interrupt = rs() != rt();
      break;
4117 4118 4119
    case SYNC:
      // TODO(palfia): Ignore sync instruction for now.
      break;
4120 4121 4122
    // Conditional moves.
    case MOVN:
      if (rt()) {
4123
        SetResult(rd_reg(), rs());
4124 4125 4126
      }
      break;
    case MOVCI: {
4127
      uint32_t cc = instr_.FBccValue();
4128
      uint32_t fcsr_cc = get_fcsr_condition_bit(cc);
4129
      if (instr_.Bit(16)) {  // Read Tf bit.
4130 4131 4132 4133 4134 4135 4136 4137
        if (test_fcsr_bit(fcsr_cc)) set_register(rd_reg(), rs());
      } else {
        if (!test_fcsr_bit(fcsr_cc)) set_register(rd_reg(), rs());
      }
      break;
    }
    case MOVZ:
      if (!rt()) {
4138
        SetResult(rd_reg(), rs());
4139 4140 4141 4142 4143 4144
      }
      break;
    default:
      UNREACHABLE();
  }
  if (do_interrupt) {
4145
    SoftwareInterrupt();
4146
  }
4147 4148 4149
}


4150 4151
void Simulator::DecodeTypeRegisterSPECIAL2() {
  int32_t alu_out;
4152
  switch (instr_.FunctionFieldRaw()) {
4153
    case MUL:
4154 4155
      // Only the lower 32 bits are kept.
      alu_out = rs_u() * rt_u();
4156 4157 4158 4159
      // HI and LO are UNPREDICTABLE after the operation.
      set_register(LO, Unpredictable);
      set_register(HI, Unpredictable);
      break;
4160 4161 4162 4163 4164 4165 4166 4167
    case CLZ:
      // MIPS32 spec: If no bits were set in GPR rs, the result written to
      // GPR rd is 32.
      alu_out = base::bits::CountLeadingZeros32(rs_u());
      break;
    default:
      alu_out = 0x12345678;
      UNREACHABLE();
4168
  }
4169
  SetResult(rd_reg(), alu_out);
4170 4171 4172
}


4173 4174
void Simulator::DecodeTypeRegisterSPECIAL3() {
  int32_t alu_out;
4175
  switch (instr_.FunctionFieldRaw()) {
4176 4177 4178 4179 4180 4181
    case INS: {  // Mips32r2 instruction.
      // Interpret rd field as 5-bit msb of insert.
      uint16_t msb = rd_reg();
      // Interpret sa field as 5-bit lsb of insert.
      uint16_t lsb = sa();
      uint16_t size = msb - lsb + 1;
4182 4183 4184 4185 4186 4187
      uint32_t mask;
      if (size < 32) {
        mask = (1 << size) - 1;
      } else {
        mask = std::numeric_limits<uint32_t>::max();
      }
4188
      alu_out = (rt_u() & ~(mask << lsb)) | ((rs_u() & mask) << lsb);
4189
      // Ins instr leaves result in Rt, rather than Rd.
4190
      SetResult(rt_reg(), alu_out);
4191
      break;
4192 4193 4194 4195 4196 4197 4198
    }
    case EXT: {  // Mips32r2 instruction.
      // Interpret rd field as 5-bit msb of extract.
      uint16_t msb = rd_reg();
      // Interpret sa field as 5-bit lsb of extract.
      uint16_t lsb = sa();
      uint16_t size = msb + 1;
4199 4200 4201 4202 4203 4204
      uint32_t mask;
      if (size < 32) {
        mask = (1 << size) - 1;
      } else {
        mask = std::numeric_limits<uint32_t>::max();
      }
4205 4206
      alu_out = (rs_u() & (mask << lsb)) >> lsb;
      SetResult(rt_reg(), alu_out);
4207
      break;
4208 4209
    }
    case BSHFL: {
4210
      int sa = instr_.SaFieldRaw() >> kSaShift;
4211 4212 4213 4214 4215 4216 4217 4218 4219
      switch (sa) {
        case BITSWAP: {
          uint32_t input = static_cast<uint32_t>(rt());
          uint32_t output = 0;
          uint8_t i_byte, o_byte;

          // Reverse the bit in byte for each individual byte
          for (int i = 0; i < 4; i++) {
            output = output >> 8;
4220
            i_byte = input & 0xFF;
4221 4222 4223 4224 4225 4226 4227 4228 4229 4230 4231 4232 4233 4234 4235

            // Fast way to reverse bits in byte
            // Devised by Sean Anderson, July 13, 2001
            o_byte = static_cast<uint8_t>(((i_byte * 0x0802LU & 0x22110LU) |
                                           (i_byte * 0x8020LU & 0x88440LU)) *
                                              0x10101LU >>
                                          16);

            output = output | (static_cast<uint32_t>(o_byte << 24));
            input = input >> 8;
          }

          alu_out = static_cast<int32_t>(output);
          break;
        }
4236 4237 4238 4239 4240 4241 4242 4243 4244 4245 4246
        case SEB: {
          uint8_t input = static_cast<uint8_t>(rt());
          uint32_t output = input;
          uint32_t mask = 0x00000080;

          // Extending sign
          if (mask & input) {
            output |= 0xFFFFFF00;
          }

          alu_out = static_cast<int32_t>(output);
4247
          break;
4248 4249 4250 4251 4252 4253 4254 4255 4256 4257 4258 4259 4260 4261 4262 4263 4264 4265 4266 4267 4268 4269 4270 4271 4272 4273 4274 4275 4276 4277 4278 4279 4280
        }
        case SEH: {
          uint16_t input = static_cast<uint16_t>(rt());
          uint32_t output = input;
          uint32_t mask = 0x00008000;

          // Extending sign
          if (mask & input) {
            output |= 0xFFFF0000;
          }

          alu_out = static_cast<int32_t>(output);
          break;
        }
        case WSBH: {
          uint32_t input = static_cast<uint32_t>(rt());
          uint32_t output = 0;

          uint32_t mask = 0xFF000000;
          for (int i = 0; i < 4; i++) {
            uint32_t tmp = mask & input;
            if (i % 2 == 0) {
              tmp = tmp >> 8;
            } else {
              tmp = tmp << 8;
            }
            output = output | tmp;
            mask = mask >> 8;
          }

          alu_out = static_cast<int32_t>(output);
          break;
        }
4281
        default: {
4282
          const uint8_t bp = instr_.Bp2Value();
4283 4284 4285 4286 4287 4288 4289 4290 4291 4292 4293 4294 4295 4296 4297 4298 4299 4300 4301 4302
          sa >>= kBp2Bits;
          switch (sa) {
            case ALIGN: {
              if (bp == 0) {
                alu_out = static_cast<int32_t>(rt());
              } else {
                uint32_t rt_hi = rt() << (8 * bp);
                uint32_t rs_lo = rs() >> (8 * (4 - bp));
                alu_out = static_cast<int32_t>(rt_hi | rs_lo);
              }
              break;
            }
            default:
              alu_out = 0x12345678;
              UNREACHABLE();
              break;
          }
        }
      }
      SetResult(rd_reg(), alu_out);
4303
      break;
4304
    }
4305 4306 4307 4308 4309
    default:
      UNREACHABLE();
  }
}

4310 4311 4312 4313 4314 4315 4316 4317 4318 4319 4320 4321 4322 4323 4324 4325 4326 4327 4328 4329 4330 4331 4332 4333 4334 4335 4336 4337 4338 4339 4340 4341 4342 4343 4344 4345 4346 4347 4348 4349 4350 4351 4352 4353 4354 4355 4356 4357 4358 4359 4360 4361 4362 4363 4364 4365 4366 4367 4368 4369 4370 4371 4372 4373 4374 4375 4376 4377 4378 4379 4380 4381 4382 4383 4384 4385 4386 4387 4388 4389 4390
int Simulator::DecodeMsaDataFormat() {
  int df = -1;
  if (instr_.IsMSABranchInstr()) {
    switch (instr_.RsFieldRaw()) {
      case BZ_V:
      case BNZ_V:
        df = MSA_VECT;
        break;
      case BZ_B:
      case BNZ_B:
        df = MSA_BYTE;
        break;
      case BZ_H:
      case BNZ_H:
        df = MSA_HALF;
        break;
      case BZ_W:
      case BNZ_W:
        df = MSA_WORD;
        break;
      case BZ_D:
      case BNZ_D:
        df = MSA_DWORD;
        break;
      default:
        UNREACHABLE();
        break;
    }
  } else {
    int DF[] = {MSA_BYTE, MSA_HALF, MSA_WORD, MSA_DWORD};
    switch (instr_.MSAMinorOpcodeField()) {
      case kMsaMinorI5:
      case kMsaMinorI10:
      case kMsaMinor3R:
        df = DF[instr_.Bits(22, 21)];
        break;
      case kMsaMinorMI10:
        df = DF[instr_.Bits(1, 0)];
        break;
      case kMsaMinorBIT:
        df = DF[instr_.MsaBitDf()];
        break;
      case kMsaMinorELM:
        df = DF[instr_.MsaElmDf()];
        break;
      case kMsaMinor3RF: {
        uint32_t opcode = instr_.InstructionBits() & kMsa3RFMask;
        switch (opcode) {
          case FEXDO:
          case FTQ:
          case MUL_Q:
          case MADD_Q:
          case MSUB_Q:
          case MULR_Q:
          case MADDR_Q:
          case MSUBR_Q:
            df = DF[1 + instr_.Bit(21)];
            break;
          default:
            df = DF[2 + instr_.Bit(21)];
            break;
        }
      } break;
      case kMsaMinor2R:
        df = DF[instr_.Bits(17, 16)];
        break;
      case kMsaMinor2RF:
        df = DF[2 + instr_.Bit(16)];
        break;
      default:
        UNREACHABLE();
        break;
    }
  }
  return df;
}

void Simulator::DecodeTypeMsaI8() {
  DCHECK(IsMipsArchVariant(kMips32r6));
  DCHECK(CpuFeatures::IsSupported(MIPS_SIMD));
  uint32_t opcode = instr_.InstructionBits() & kMsaI8Mask;
4391 4392
  int8_t i8 = instr_.MsaImm8Value();
  msa_reg_t ws, wd;
4393 4394 4395

  switch (opcode) {
    case ANDI_B:
4396 4397 4398 4399 4400 4401 4402
      get_msa_register(instr_.WsValue(), ws.b);
      for (int i = 0; i < kMSALanesByte; i++) {
        wd.b[i] = ws.b[i] & i8;
      }
      set_msa_register(instr_.WdValue(), wd.b);
      TraceMSARegWr(wd.b);
      break;
4403
    case ORI_B:
4404 4405 4406 4407 4408 4409 4410
      get_msa_register(instr_.WsValue(), ws.b);
      for (int i = 0; i < kMSALanesByte; i++) {
        wd.b[i] = ws.b[i] | i8;
      }
      set_msa_register(instr_.WdValue(), wd.b);
      TraceMSARegWr(wd.b);
      break;
4411
    case NORI_B:
4412 4413 4414 4415 4416 4417 4418
      get_msa_register(instr_.WsValue(), ws.b);
      for (int i = 0; i < kMSALanesByte; i++) {
        wd.b[i] = ~(ws.b[i] | i8);
      }
      set_msa_register(instr_.WdValue(), wd.b);
      TraceMSARegWr(wd.b);
      break;
4419
    case XORI_B:
4420 4421 4422 4423 4424 4425 4426
      get_msa_register(instr_.WsValue(), ws.b);
      for (int i = 0; i < kMSALanesByte; i++) {
        wd.b[i] = ws.b[i] ^ i8;
      }
      set_msa_register(instr_.WdValue(), wd.b);
      TraceMSARegWr(wd.b);
      break;
4427
    case BMNZI_B:
4428 4429 4430 4431 4432 4433 4434 4435
      get_msa_register(instr_.WsValue(), ws.b);
      get_msa_register(instr_.WdValue(), wd.b);
      for (int i = 0; i < kMSALanesByte; i++) {
        wd.b[i] = (ws.b[i] & i8) | (wd.b[i] & ~i8);
      }
      set_msa_register(instr_.WdValue(), wd.b);
      TraceMSARegWr(wd.b);
      break;
4436
    case BMZI_B:
4437 4438 4439 4440 4441 4442 4443 4444
      get_msa_register(instr_.WsValue(), ws.b);
      get_msa_register(instr_.WdValue(), wd.b);
      for (int i = 0; i < kMSALanesByte; i++) {
        wd.b[i] = (ws.b[i] & ~i8) | (wd.b[i] & i8);
      }
      set_msa_register(instr_.WdValue(), wd.b);
      TraceMSARegWr(wd.b);
      break;
4445
    case BSELI_B:
4446 4447 4448 4449 4450 4451 4452 4453
      get_msa_register(instr_.WsValue(), ws.b);
      get_msa_register(instr_.WdValue(), wd.b);
      for (int i = 0; i < kMSALanesByte; i++) {
        wd.b[i] = (ws.b[i] & ~wd.b[i]) | (wd.b[i] & i8);
      }
      set_msa_register(instr_.WdValue(), wd.b);
      TraceMSARegWr(wd.b);
      break;
4454
    case SHF_B:
4455 4456 4457 4458 4459 4460 4461 4462 4463
      get_msa_register(instr_.WsValue(), ws.b);
      for (int i = 0; i < kMSALanesByte; i++) {
        int j = i % 4;
        int k = (i8 >> (2 * j)) & 0x3;
        wd.b[i] = ws.b[i - j + k];
      }
      set_msa_register(instr_.WdValue(), wd.b);
      TraceMSARegWr(wd.b);
      break;
4464
    case SHF_H:
4465 4466 4467 4468 4469 4470 4471 4472 4473
      get_msa_register(instr_.WsValue(), ws.h);
      for (int i = 0; i < kMSALanesHalf; i++) {
        int j = i % 4;
        int k = (i8 >> (2 * j)) & 0x3;
        wd.h[i] = ws.h[i - j + k];
      }
      set_msa_register(instr_.WdValue(), wd.h);
      TraceMSARegWr(wd.h);
      break;
4474
    case SHF_W:
4475 4476 4477 4478 4479 4480 4481
      get_msa_register(instr_.WsValue(), ws.w);
      for (int i = 0; i < kMSALanesWord; i++) {
        int j = (i8 >> (2 * i)) & 0x3;
        wd.w[i] = ws.w[j];
      }
      set_msa_register(instr_.WdValue(), wd.w);
      TraceMSARegWr(wd.w);
4482 4483 4484 4485 4486 4487
      break;
    default:
      UNREACHABLE();
  }
}

4488 4489 4490 4491 4492 4493
template <typename T>
T Simulator::MsaI5InstrHelper(uint32_t opcode, T ws, int32_t i5) {
  T res;
  uint32_t ui5 = i5 & 0x1Fu;
  uint64_t ws_u64 = static_cast<uint64_t>(ws);
  uint64_t ui5_u64 = static_cast<uint64_t>(ui5);
4494 4495 4496

  switch (opcode) {
    case ADDVI:
4497 4498
      res = static_cast<T>(ws + ui5);
      break;
4499
    case SUBVI:
4500 4501
      res = static_cast<T>(ws - ui5);
      break;
4502
    case MAXI_S:
4503 4504
      res = static_cast<T>(Max(ws, static_cast<T>(i5)));
      break;
4505
    case MINI_S:
4506 4507 4508 4509 4510
      res = static_cast<T>(Min(ws, static_cast<T>(i5)));
      break;
    case MAXI_U:
      res = static_cast<T>(Max(ws_u64, ui5_u64));
      break;
4511
    case MINI_U:
4512 4513
      res = static_cast<T>(Min(ws_u64, ui5_u64));
      break;
4514
    case CEQI:
4515 4516
      res = static_cast<T>(!Compare(ws, static_cast<T>(i5)) ? -1ull : 0ull);
      break;
4517
    case CLTI_S:
4518 4519 4520
      res = static_cast<T>((Compare(ws, static_cast<T>(i5)) == -1) ? -1ull
                                                                   : 0ull);
      break;
4521
    case CLTI_U:
4522 4523
      res = static_cast<T>((Compare(ws_u64, ui5_u64) == -1) ? -1ull : 0ull);
      break;
4524
    case CLEI_S:
4525 4526 4527
      res =
          static_cast<T>((Compare(ws, static_cast<T>(i5)) != 1) ? -1ull : 0ull);
      break;
4528
    case CLEI_U:
4529 4530 4531 4532 4533 4534 4535 4536 4537 4538 4539 4540 4541 4542 4543 4544 4545 4546 4547 4548 4549 4550 4551 4552 4553 4554 4555 4556 4557 4558 4559 4560 4561 4562 4563 4564 4565
      res = static_cast<T>((Compare(ws_u64, ui5_u64) != 1) ? -1ull : 0ull);
      break;
    default:
      UNREACHABLE();
  }
  return res;
}

void Simulator::DecodeTypeMsaI5() {
  DCHECK(IsMipsArchVariant(kMips32r6));
  DCHECK(CpuFeatures::IsSupported(MIPS_SIMD));
  uint32_t opcode = instr_.InstructionBits() & kMsaI5Mask;
  msa_reg_t ws, wd;

  // sign extend 5bit value to int32_t
  int32_t i5 = static_cast<int32_t>(instr_.MsaImm5Value() << 27) >> 27;

#define MSA_I5_DF(elem, num_of_lanes)                      \
  get_msa_register(instr_.WsValue(), ws.elem);             \
  for (int i = 0; i < num_of_lanes; i++) {                 \
    wd.elem[i] = MsaI5InstrHelper(opcode, ws.elem[i], i5); \
  }                                                        \
  set_msa_register(instr_.WdValue(), wd.elem);             \
  TraceMSARegWr(wd.elem)

  switch (DecodeMsaDataFormat()) {
    case MSA_BYTE:
      MSA_I5_DF(b, kMSALanesByte);
      break;
    case MSA_HALF:
      MSA_I5_DF(h, kMSALanesHalf);
      break;
    case MSA_WORD:
      MSA_I5_DF(w, kMSALanesWord);
      break;
    case MSA_DWORD:
      MSA_I5_DF(d, kMSALanesDword);
4566 4567 4568 4569
      break;
    default:
      UNREACHABLE();
  }
4570
#undef MSA_I5_DF
4571 4572 4573 4574 4575 4576
}

void Simulator::DecodeTypeMsaI10() {
  DCHECK(IsMipsArchVariant(kMips32r6));
  DCHECK(CpuFeatures::IsSupported(MIPS_SIMD));
  uint32_t opcode = instr_.InstructionBits() & kMsaI5Mask;
4577 4578 4579 4580 4581 4582 4583 4584 4585 4586
  int64_t s10 = (static_cast<int64_t>(instr_.MsaImm10Value()) << 54) >> 54;
  msa_reg_t wd;

#define MSA_I10_DF(elem, num_of_lanes, T)      \
  for (int i = 0; i < num_of_lanes; ++i) {     \
    wd.elem[i] = static_cast<T>(s10);          \
  }                                            \
  set_msa_register(instr_.WdValue(), wd.elem); \
  TraceMSARegWr(wd.elem)

4587
  if (opcode == LDI) {
4588 4589 4590 4591 4592 4593 4594 4595 4596 4597 4598 4599 4600 4601 4602 4603
    switch (DecodeMsaDataFormat()) {
      case MSA_BYTE:
        MSA_I10_DF(b, kMSALanesByte, int8_t);
        break;
      case MSA_HALF:
        MSA_I10_DF(h, kMSALanesHalf, int16_t);
        break;
      case MSA_WORD:
        MSA_I10_DF(w, kMSALanesWord, int32_t);
        break;
      case MSA_DWORD:
        MSA_I10_DF(d, kMSALanesDword, int64_t);
        break;
      default:
        UNREACHABLE();
    }
4604 4605 4606
  } else {
    UNREACHABLE();
  }
4607
#undef MSA_I10_DF
4608 4609 4610 4611 4612
}

void Simulator::DecodeTypeMsaELM() {
  DCHECK(IsMipsArchVariant(kMips32r6));
  DCHECK(CpuFeatures::IsSupported(MIPS_SIMD));
4613
  uint32_t opcode = instr_.InstructionBits() & kMsaLongerELMMask;
4614 4615 4616
  int32_t n = instr_.MsaElmNValue();
  int32_t alu_out;
  switch (opcode) {
4617
    case CTCMSA:
4618
      DCHECK_EQ(sa(), kMSACSRRegister);
4619 4620 4621 4622
      MSACSR_ = bit_cast<uint32_t>(registers_[rd_reg()]);
      TraceRegWr(static_cast<int32_t>(MSACSR_));
      break;
    case CFCMSA:
4623
      DCHECK_EQ(rd_reg(), kMSACSRRegister);
4624 4625
      SetResult(sa(), bit_cast<int32_t>(MSACSR_));
      break;
4626 4627 4628 4629 4630 4631
    case MOVE_V: {
      msa_reg_t ws;
      get_msa_register(ws_reg(), &ws);
      set_msa_register(wd_reg(), &ws);
      TraceMSARegWr(&ws);
    } break;
4632 4633 4634 4635 4636 4637 4638 4639
    default:
      opcode &= kMsaELMMask;
      switch (opcode) {
        case COPY_S:
        case COPY_U: {
          msa_reg_t ws;
          switch (DecodeMsaDataFormat()) {
            case MSA_BYTE: {
4640
              DCHECK_LT(n, kMSALanesByte);
4641 4642 4643 4644 4645 4646 4647
              get_msa_register(instr_.WsValue(), ws.b);
              alu_out = static_cast<int32_t>(ws.b[n]);
              SetResult(wd_reg(),
                        (opcode == COPY_U) ? alu_out & 0xFFu : alu_out);
              break;
            }
            case MSA_HALF: {
4648
              DCHECK_LT(n, kMSALanesHalf);
4649 4650 4651 4652 4653 4654 4655
              get_msa_register(instr_.WsValue(), ws.h);
              alu_out = static_cast<int32_t>(ws.h[n]);
              SetResult(wd_reg(),
                        (opcode == COPY_U) ? alu_out & 0xFFFFu : alu_out);
              break;
            }
            case MSA_WORD: {
4656
              DCHECK_LT(n, kMSALanesWord);
4657 4658 4659 4660 4661 4662 4663 4664 4665 4666 4667 4668 4669
              get_msa_register(instr_.WsValue(), ws.w);
              alu_out = static_cast<int32_t>(ws.w[n]);
              SetResult(wd_reg(), alu_out);
              break;
            }
            default:
              UNREACHABLE();
          }
        } break;
        case INSERT: {
          msa_reg_t wd;
          switch (DecodeMsaDataFormat()) {
            case MSA_BYTE: {
4670
              DCHECK_LT(n, kMSALanesByte);
4671 4672 4673 4674 4675 4676 4677 4678
              int32_t rs = get_register(instr_.WsValue());
              get_msa_register(instr_.WdValue(), wd.b);
              wd.b[n] = rs & 0xFFu;
              set_msa_register(instr_.WdValue(), wd.b);
              TraceMSARegWr(wd.b);
              break;
            }
            case MSA_HALF: {
4679
              DCHECK_LT(n, kMSALanesHalf);
4680 4681 4682 4683 4684 4685 4686 4687
              int32_t rs = get_register(instr_.WsValue());
              get_msa_register(instr_.WdValue(), wd.h);
              wd.h[n] = rs & 0xFFFFu;
              set_msa_register(instr_.WdValue(), wd.h);
              TraceMSARegWr(wd.h);
              break;
            }
            case MSA_WORD: {
4688
              DCHECK_LT(n, kMSALanesWord);
4689 4690 4691 4692 4693 4694 4695 4696 4697 4698 4699
              int32_t rs = get_register(instr_.WsValue());
              get_msa_register(instr_.WdValue(), wd.w);
              wd.w[n] = rs;
              set_msa_register(instr_.WdValue(), wd.w);
              TraceMSARegWr(wd.w);
              break;
            }
            default:
              UNREACHABLE();
          }
        } break;
4700 4701 4702 4703 4704 4705 4706 4707 4708 4709 4710 4711 4712 4713 4714 4715 4716 4717 4718 4719 4720 4721 4722 4723 4724 4725 4726 4727 4728 4729 4730 4731 4732 4733 4734 4735 4736 4737 4738 4739 4740 4741 4742 4743
        case SLDI: {
          uint8_t v[32];
          msa_reg_t ws;
          msa_reg_t wd;
          get_msa_register(ws_reg(), &ws);
          get_msa_register(wd_reg(), &wd);
#define SLDI_DF(s, k)                \
  for (unsigned i = 0; i < s; i++) { \
    v[i] = ws.b[s * k + i];          \
    v[i + s] = wd.b[s * k + i];      \
  }                                  \
  for (unsigned i = 0; i < s; i++) { \
    wd.b[s * k + i] = v[i + n];      \
  }
          switch (DecodeMsaDataFormat()) {
            case MSA_BYTE:
              DCHECK(n < kMSALanesByte);
              SLDI_DF(kMSARegSize / sizeof(int8_t) / kBitsPerByte, 0)
              break;
            case MSA_HALF:
              DCHECK(n < kMSALanesHalf);
              for (int k = 0; k < 2; ++k) {
                SLDI_DF(kMSARegSize / sizeof(int16_t) / kBitsPerByte, k)
              }
              break;
            case MSA_WORD:
              DCHECK(n < kMSALanesWord);
              for (int k = 0; k < 4; ++k) {
                SLDI_DF(kMSARegSize / sizeof(int32_t) / kBitsPerByte, k)
              }
              break;
            case MSA_DWORD:
              DCHECK(n < kMSALanesDword);
              for (int k = 0; k < 8; ++k) {
                SLDI_DF(kMSARegSize / sizeof(int64_t) / kBitsPerByte, k)
              }
              break;
            default:
              UNREACHABLE();
          }
          set_msa_register(wd_reg(), &wd);
          TraceMSARegWr(&wd);
        } break;
#undef SLDI_DF
4744 4745 4746
        case SPLATI:
        case INSVE:
          UNIMPLEMENTED();
4747 4748 4749 4750
          break;
        default:
          UNREACHABLE();
      }
4751 4752 4753 4754
      break;
  }
}

4755 4756 4757 4758
template <typename T>
T Simulator::MsaBitInstrHelper(uint32_t opcode, T wd, T ws, int32_t m) {
  typedef typename std::make_unsigned<T>::type uT;
  T res;
4759 4760
  switch (opcode) {
    case SLLI:
4761 4762
      res = static_cast<T>(ws << m);
      break;
4763
    case SRAI:
4764 4765
      res = static_cast<T>(ArithmeticShiftRight(ws, m));
      break;
4766
    case SRLI:
4767 4768
      res = static_cast<T>(static_cast<uT>(ws) >> m);
      break;
4769
    case BCLRI:
4770 4771
      res = static_cast<T>(static_cast<T>(~(1ull << m)) & ws);
      break;
4772
    case BSETI:
4773 4774
      res = static_cast<T>(static_cast<T>(1ull << m) | ws);
      break;
4775
    case BNEGI:
4776 4777 4778 4779 4780 4781 4782 4783 4784 4785 4786 4787 4788 4789 4790 4791 4792 4793 4794 4795 4796 4797 4798 4799 4800 4801 4802 4803 4804 4805 4806 4807 4808 4809 4810 4811 4812 4813 4814 4815 4816 4817 4818 4819
      res = static_cast<T>(static_cast<T>(1ull << m) ^ ws);
      break;
    case BINSLI: {
      int elem_size = 8 * sizeof(T);
      int bits = m + 1;
      if (bits == elem_size) {
        res = static_cast<T>(ws);
      } else {
        uint64_t mask = ((1ull << bits) - 1) << (elem_size - bits);
        res = static_cast<T>((static_cast<T>(mask) & ws) |
                             (static_cast<T>(~mask) & wd));
      }
    } break;
    case BINSRI: {
      int elem_size = 8 * sizeof(T);
      int bits = m + 1;
      if (bits == elem_size) {
        res = static_cast<T>(ws);
      } else {
        uint64_t mask = (1ull << bits) - 1;
        res = static_cast<T>((static_cast<T>(mask) & ws) |
                             (static_cast<T>(~mask) & wd));
      }
    } break;
    case SAT_S: {
#define M_MAX_INT(x) static_cast<int64_t>((1LL << ((x)-1)) - 1)
#define M_MIN_INT(x) static_cast<int64_t>(-(1LL << ((x)-1)))
      int shift = 64 - 8 * sizeof(T);
      int64_t ws_i64 = (static_cast<int64_t>(ws) << shift) >> shift;
      res = static_cast<T>(ws_i64 < M_MIN_INT(m + 1)
                               ? M_MIN_INT(m + 1)
                               : ws_i64 > M_MAX_INT(m + 1) ? M_MAX_INT(m + 1)
                                                           : ws_i64);
#undef M_MAX_INT
#undef M_MIN_INT
    } break;
    case SAT_U: {
#define M_MAX_UINT(x) static_cast<uint64_t>(-1ULL >> (64 - (x)))
      uint64_t mask = static_cast<uint64_t>(-1ULL >> (64 - 8 * sizeof(T)));
      uint64_t ws_u64 = static_cast<uint64_t>(ws) & mask;
      res = static_cast<T>(ws_u64 < M_MAX_UINT(m + 1) ? ws_u64
                                                      : M_MAX_UINT(m + 1));
#undef M_MAX_UINT
    } break;
4820
    case SRARI:
4821 4822 4823 4824 4825 4826 4827
      if (!m) {
        res = static_cast<T>(ws);
      } else {
        res = static_cast<T>(ArithmeticShiftRight(ws, m)) +
              static_cast<T>((ws >> (m - 1)) & 0x1);
      }
      break;
4828
    case SRLRI:
4829 4830 4831 4832 4833 4834 4835 4836 4837 4838 4839 4840 4841 4842 4843 4844 4845 4846 4847 4848 4849 4850 4851 4852 4853 4854 4855 4856 4857 4858 4859 4860 4861 4862 4863 4864 4865 4866 4867 4868 4869 4870 4871 4872 4873 4874 4875
      if (!m) {
        res = static_cast<T>(ws);
      } else {
        res = static_cast<T>(static_cast<uT>(ws) >> m) +
              static_cast<T>((ws >> (m - 1)) & 0x1);
      }
      break;
    default:
      UNREACHABLE();
  }
  return res;
}

void Simulator::DecodeTypeMsaBIT() {
  DCHECK(IsMipsArchVariant(kMips32r6));
  DCHECK(CpuFeatures::IsSupported(MIPS_SIMD));
  uint32_t opcode = instr_.InstructionBits() & kMsaBITMask;
  int32_t m = instr_.MsaBitMValue();
  msa_reg_t wd, ws;

#define MSA_BIT_DF(elem, num_of_lanes)                                 \
  get_msa_register(instr_.WsValue(), ws.elem);                         \
  if (opcode == BINSLI || opcode == BINSRI) {                          \
    get_msa_register(instr_.WdValue(), wd.elem);                       \
  }                                                                    \
  for (int i = 0; i < num_of_lanes; i++) {                             \
    wd.elem[i] = MsaBitInstrHelper(opcode, wd.elem[i], ws.elem[i], m); \
  }                                                                    \
  set_msa_register(instr_.WdValue(), wd.elem);                         \
  TraceMSARegWr(wd.elem)

  switch (DecodeMsaDataFormat()) {
    case MSA_BYTE:
      DCHECK(m < kMSARegSize / kMSALanesByte);
      MSA_BIT_DF(b, kMSALanesByte);
      break;
    case MSA_HALF:
      DCHECK(m < kMSARegSize / kMSALanesHalf);
      MSA_BIT_DF(h, kMSALanesHalf);
      break;
    case MSA_WORD:
      DCHECK(m < kMSARegSize / kMSALanesWord);
      MSA_BIT_DF(w, kMSALanesWord);
      break;
    case MSA_DWORD:
      DCHECK(m < kMSARegSize / kMSALanesDword);
      MSA_BIT_DF(d, kMSALanesDword);
4876 4877 4878 4879
      break;
    default:
      UNREACHABLE();
  }
4880
#undef MSA_BIT_DF
4881 4882 4883 4884 4885 4886
}

void Simulator::DecodeTypeMsaMI10() {
  DCHECK(IsMipsArchVariant(kMips32r6));
  DCHECK(CpuFeatures::IsSupported(MIPS_SIMD));
  uint32_t opcode = instr_.InstructionBits() & kMsaMI10Mask;
4887 4888 4889 4890 4891 4892 4893 4894 4895 4896 4897 4898 4899 4900 4901 4902 4903 4904 4905
  int32_t s10 = (static_cast<int32_t>(instr_.MsaImmMI10Value()) << 22) >> 22;
  int32_t rs = get_register(instr_.WsValue());
  int32_t addr;
  msa_reg_t wd;

#define MSA_MI10_LOAD(elem, num_of_lanes, T)       \
  for (int i = 0; i < num_of_lanes; ++i) {         \
    addr = rs + (s10 + i) * sizeof(T);             \
    wd.elem[i] = ReadMem<T>(addr, instr_.instr()); \
  }                                                \
  set_msa_register(instr_.WdValue(), wd.elem);

#define MSA_MI10_STORE(elem, num_of_lanes, T)      \
  get_msa_register(instr_.WdValue(), wd.elem);     \
  for (int i = 0; i < num_of_lanes; ++i) {         \
    addr = rs + (s10 + i) * sizeof(T);             \
    WriteMem<T>(addr, wd.elem[i], instr_.instr()); \
  }

4906
  if (opcode == MSA_LD) {
4907 4908 4909 4910 4911 4912 4913 4914 4915 4916 4917 4918 4919 4920 4921 4922
    switch (DecodeMsaDataFormat()) {
      case MSA_BYTE:
        MSA_MI10_LOAD(b, kMSALanesByte, int8_t);
        break;
      case MSA_HALF:
        MSA_MI10_LOAD(h, kMSALanesHalf, int16_t);
        break;
      case MSA_WORD:
        MSA_MI10_LOAD(w, kMSALanesWord, int32_t);
        break;
      case MSA_DWORD:
        MSA_MI10_LOAD(d, kMSALanesDword, int64_t);
        break;
      default:
        UNREACHABLE();
    }
4923
  } else if (opcode == MSA_ST) {
4924 4925 4926 4927 4928 4929 4930 4931 4932 4933 4934 4935 4936 4937 4938 4939
    switch (DecodeMsaDataFormat()) {
      case MSA_BYTE:
        MSA_MI10_STORE(b, kMSALanesByte, int8_t);
        break;
      case MSA_HALF:
        MSA_MI10_STORE(h, kMSALanesHalf, int16_t);
        break;
      case MSA_WORD:
        MSA_MI10_STORE(w, kMSALanesWord, int32_t);
        break;
      case MSA_DWORD:
        MSA_MI10_STORE(d, kMSALanesDword, int64_t);
        break;
      default:
        UNREACHABLE();
    }
4940 4941 4942
  } else {
    UNREACHABLE();
  }
4943 4944 4945

#undef MSA_MI10_LOAD
#undef MSA_MI10_STORE
4946 4947
}

4948 4949 4950 4951 4952
template <typename T>
T Simulator::Msa3RInstrHelper(uint32_t opcode, T wd, T ws, T wt) {
  typedef typename std::make_unsigned<T>::type uT;
  T res;
  T wt_modulo = wt % (sizeof(T) * 8);
4953 4954
  switch (opcode) {
    case SLL_MSA:
4955 4956
      res = static_cast<T>(ws << wt_modulo);
      break;
4957
    case SRA_MSA:
4958 4959
      res = static_cast<T>(ArithmeticShiftRight(ws, wt_modulo));
      break;
4960
    case SRL_MSA:
4961 4962
      res = static_cast<T>(static_cast<uT>(ws) >> wt_modulo);
      break;
4963
    case BCLR:
4964 4965
      res = static_cast<T>(static_cast<T>(~(1ull << wt_modulo)) & ws);
      break;
4966
    case BSET:
4967 4968
      res = static_cast<T>(static_cast<T>(1ull << wt_modulo) | ws);
      break;
4969
    case BNEG:
4970 4971 4972 4973 4974 4975 4976 4977 4978 4979 4980 4981 4982 4983 4984 4985 4986 4987 4988 4989 4990 4991 4992 4993
      res = static_cast<T>(static_cast<T>(1ull << wt_modulo) ^ ws);
      break;
    case BINSL: {
      int elem_size = 8 * sizeof(T);
      int bits = wt_modulo + 1;
      if (bits == elem_size) {
        res = static_cast<T>(ws);
      } else {
        uint64_t mask = ((1ull << bits) - 1) << (elem_size - bits);
        res = static_cast<T>((static_cast<T>(mask) & ws) |
                             (static_cast<T>(~mask) & wd));
      }
    } break;
    case BINSR: {
      int elem_size = 8 * sizeof(T);
      int bits = wt_modulo + 1;
      if (bits == elem_size) {
        res = static_cast<T>(ws);
      } else {
        uint64_t mask = (1ull << bits) - 1;
        res = static_cast<T>((static_cast<T>(mask) & ws) |
                             (static_cast<T>(~mask) & wd));
      }
    } break;
4994
    case ADDV:
4995 4996
      res = ws + wt;
      break;
4997
    case SUBV:
4998 4999
      res = ws - wt;
      break;
5000
    case MAX_S:
5001 5002
      res = Max(ws, wt);
      break;
5003
    case MAX_U:
5004 5005
      res = static_cast<T>(Max(static_cast<uT>(ws), static_cast<uT>(wt)));
      break;
5006
    case MIN_S:
5007 5008
      res = Min(ws, wt);
      break;
5009
    case MIN_U:
5010 5011
      res = static_cast<T>(Min(static_cast<uT>(ws), static_cast<uT>(wt)));
      break;
5012
    case MAX_A:
5013 5014 5015 5016
      // We use negative abs in order to avoid problems
      // with corner case for MIN_INT
      res = Nabs(ws) < Nabs(wt) ? ws : wt;
      break;
5017
    case MIN_A:
5018 5019 5020 5021
      // We use negative abs in order to avoid problems
      // with corner case for MIN_INT
      res = Nabs(ws) > Nabs(wt) ? ws : wt;
      break;
5022
    case CEQ:
5023 5024
      res = static_cast<T>(!Compare(ws, wt) ? -1ull : 0ull);
      break;
5025
    case CLT_S:
5026 5027
      res = static_cast<T>((Compare(ws, wt) == -1) ? -1ull : 0ull);
      break;
5028
    case CLT_U:
5029 5030 5031 5032
      res = static_cast<T>(
          (Compare(static_cast<uT>(ws), static_cast<uT>(wt)) == -1) ? -1ull
                                                                    : 0ull);
      break;
5033
    case CLE_S:
5034 5035
      res = static_cast<T>((Compare(ws, wt) != 1) ? -1ull : 0ull);
      break;
5036
    case CLE_U:
5037 5038 5039 5040
      res = static_cast<T>(
          (Compare(static_cast<uT>(ws), static_cast<uT>(wt)) != 1) ? -1ull
                                                                   : 0ull);
      break;
5041
    case ADD_A:
5042 5043 5044 5045 5046 5047 5048 5049 5050 5051 5052
      res = static_cast<T>(Abs(ws) + Abs(wt));
      break;
    case ADDS_A: {
      T ws_nabs = Nabs(ws);
      T wt_nabs = Nabs(wt);
      if (ws_nabs < -std::numeric_limits<T>::max() - wt_nabs) {
        res = std::numeric_limits<T>::max();
      } else {
        res = -(ws_nabs + wt_nabs);
      }
    } break;
5053
    case ADDS_S:
5054 5055 5056 5057 5058 5059 5060
      res = SaturateAdd(ws, wt);
      break;
    case ADDS_U: {
      uT ws_u = static_cast<uT>(ws);
      uT wt_u = static_cast<uT>(wt);
      res = static_cast<T>(SaturateAdd(ws_u, wt_u));
    } break;
5061
    case AVE_S:
5062 5063 5064 5065 5066 5067 5068
      res = static_cast<T>((wt & ws) + ((wt ^ ws) >> 1));
      break;
    case AVE_U: {
      uT ws_u = static_cast<uT>(ws);
      uT wt_u = static_cast<uT>(wt);
      res = static_cast<T>((wt_u & ws_u) + ((wt_u ^ ws_u) >> 1));
    } break;
5069
    case AVER_S:
5070 5071 5072 5073 5074 5075 5076
      res = static_cast<T>((wt | ws) - ((wt ^ ws) >> 1));
      break;
    case AVER_U: {
      uT ws_u = static_cast<uT>(ws);
      uT wt_u = static_cast<uT>(wt);
      res = static_cast<T>((wt_u | ws_u) - ((wt_u ^ ws_u) >> 1));
    } break;
5077
    case SUBS_S:
5078 5079 5080 5081 5082 5083 5084 5085 5086 5087 5088 5089 5090 5091 5092 5093 5094 5095 5096 5097 5098 5099 5100 5101 5102 5103 5104 5105 5106 5107 5108 5109 5110 5111 5112 5113 5114 5115 5116 5117 5118 5119 5120 5121 5122 5123
      res = SaturateSub(ws, wt);
      break;
    case SUBS_U: {
      uT ws_u = static_cast<uT>(ws);
      uT wt_u = static_cast<uT>(wt);
      res = static_cast<T>(SaturateSub(ws_u, wt_u));
    } break;
    case SUBSUS_U: {
      uT wsu = static_cast<uT>(ws);
      if (wt > 0) {
        uT wtu = static_cast<uT>(wt);
        if (wtu > wsu) {
          res = 0;
        } else {
          res = static_cast<T>(wsu - wtu);
        }
      } else {
        if (wsu > std::numeric_limits<uT>::max() + wt) {
          res = static_cast<T>(std::numeric_limits<uT>::max());
        } else {
          res = static_cast<T>(wsu - wt);
        }
      }
    } break;
    case SUBSUU_S: {
      uT wsu = static_cast<uT>(ws);
      uT wtu = static_cast<uT>(wt);
      uT wdu;
      if (wsu > wtu) {
        wdu = wsu - wtu;
        if (wdu > std::numeric_limits<T>::max()) {
          res = std::numeric_limits<T>::max();
        } else {
          res = static_cast<T>(wdu);
        }
      } else {
        wdu = wtu - wsu;
        CHECK(-std::numeric_limits<T>::max() ==
              std::numeric_limits<T>::min() + 1);
        if (wdu <= std::numeric_limits<T>::max()) {
          res = -static_cast<T>(wdu);
        } else {
          res = std::numeric_limits<T>::min();
        }
      }
    } break;
5124
    case ASUB_S:
5125 5126 5127 5128 5129 5130 5131
      res = static_cast<T>(Abs(ws - wt));
      break;
    case ASUB_U: {
      uT wsu = static_cast<uT>(ws);
      uT wtu = static_cast<uT>(wt);
      res = static_cast<T>(wsu > wtu ? wsu - wtu : wtu - wsu);
    } break;
5132
    case MULV:
5133 5134
      res = ws * wt;
      break;
5135
    case MADDV:
5136 5137
      res = wd + ws * wt;
      break;
5138
    case MSUBV:
5139 5140
      res = wd - ws * wt;
      break;
5141
    case DIV_S_MSA:
5142 5143
      res = wt != 0 ? ws / wt : static_cast<T>(Unpredictable);
      break;
5144
    case DIV_U:
5145 5146 5147
      res = wt != 0 ? static_cast<T>(static_cast<uT>(ws) / static_cast<uT>(wt))
                    : static_cast<T>(Unpredictable);
      break;
5148
    case MOD_S:
5149 5150
      res = wt != 0 ? ws % wt : static_cast<T>(Unpredictable);
      break;
5151
    case MOD_U:
5152 5153 5154
      res = wt != 0 ? static_cast<T>(static_cast<uT>(ws) % static_cast<uT>(wt))
                    : static_cast<T>(Unpredictable);
      break;
5155 5156 5157 5158 5159 5160 5161 5162
    case DOTP_S:
    case DOTP_U:
    case DPADD_S:
    case DPADD_U:
    case DPSUB_S:
    case DPSUB_U:
    case SLD:
    case SPLAT:
5163 5164 5165 5166 5167 5168 5169 5170 5171 5172 5173
      UNIMPLEMENTED();
      break;
    case SRAR: {
      int bit = wt_modulo == 0 ? 0 : (ws >> (wt_modulo - 1)) & 1;
      res = static_cast<T>(ArithmeticShiftRight(ws, wt_modulo) + bit);
    } break;
    case SRLR: {
      uT wsu = static_cast<uT>(ws);
      int bit = wt_modulo == 0 ? 0 : (wsu >> (wt_modulo - 1)) & 1;
      res = static_cast<T>((wsu >> wt_modulo) + bit);
    } break;
5174 5175 5176 5177 5178 5179 5180 5181 5182 5183 5184 5185 5186 5187 5188 5189 5190 5191 5192 5193 5194 5195 5196 5197 5198 5199 5200 5201 5202 5203 5204 5205 5206 5207 5208 5209 5210 5211 5212
    default:
      UNREACHABLE();
  }
  return res;
}

template <typename T_int, typename T_reg>
void Msa3RInstrHelper_shuffle(const uint32_t opcode, T_reg ws, T_reg wt,
                              T_reg wd, const int i, const int num_of_lanes) {
  T_int *ws_p, *wt_p, *wd_p;
  ws_p = reinterpret_cast<T_int*>(ws);
  wt_p = reinterpret_cast<T_int*>(wt);
  wd_p = reinterpret_cast<T_int*>(wd);
  switch (opcode) {
    case PCKEV:
      wd_p[i] = wt_p[2 * i];
      wd_p[i + num_of_lanes / 2] = ws_p[2 * i];
      break;
    case PCKOD:
      wd_p[i] = wt_p[2 * i + 1];
      wd_p[i + num_of_lanes / 2] = ws_p[2 * i + 1];
      break;
    case ILVL:
      wd_p[2 * i] = wt_p[i + num_of_lanes / 2];
      wd_p[2 * i + 1] = ws_p[i + num_of_lanes / 2];
      break;
    case ILVR:
      wd_p[2 * i] = wt_p[i];
      wd_p[2 * i + 1] = ws_p[i];
      break;
    case ILVEV:
      wd_p[2 * i] = wt_p[2 * i];
      wd_p[2 * i + 1] = ws_p[2 * i];
      break;
    case ILVOD:
      wd_p[2 * i] = wt_p[2 * i + 1];
      wd_p[2 * i + 1] = ws_p[2 * i + 1];
      break;
    case VSHF: {
5213 5214
      const int mask_not_valid = 0xC0;
      const int mask_6_bits = 0x3F;
5215 5216 5217 5218 5219 5220 5221 5222 5223 5224 5225 5226 5227 5228 5229 5230 5231 5232 5233 5234 5235 5236 5237 5238 5239 5240 5241 5242 5243
      if ((wd_p[i] & mask_not_valid)) {
        wd_p[i] = 0;
      } else {
        int k = (wd_p[i] & mask_6_bits) % (num_of_lanes * 2);
        wd_p[i] = k >= num_of_lanes ? ws_p[k - num_of_lanes] : wt_p[k];
      }
    } break;
    default:
      UNREACHABLE();
  }
}

template <typename T_int, typename T_smaller_int, typename T_reg>
void Msa3RInstrHelper_horizontal(const uint32_t opcode, T_reg ws, T_reg wt,
                                 T_reg wd, const int i,
                                 const int num_of_lanes) {
  typedef typename std::make_unsigned<T_int>::type T_uint;
  typedef typename std::make_unsigned<T_smaller_int>::type T_smaller_uint;
  T_int* wd_p;
  T_smaller_int *ws_p, *wt_p;
  ws_p = reinterpret_cast<T_smaller_int*>(ws);
  wt_p = reinterpret_cast<T_smaller_int*>(wt);
  wd_p = reinterpret_cast<T_int*>(wd);
  T_uint* wd_pu;
  T_smaller_uint *ws_pu, *wt_pu;
  ws_pu = reinterpret_cast<T_smaller_uint*>(ws);
  wt_pu = reinterpret_cast<T_smaller_uint*>(wt);
  wd_pu = reinterpret_cast<T_uint*>(wd);
  switch (opcode) {
5244
    case HADD_S:
5245 5246 5247
      wd_p[i] =
          static_cast<T_int>(ws_p[2 * i + 1]) + static_cast<T_int>(wt_p[2 * i]);
      break;
5248
    case HADD_U:
5249 5250 5251
      wd_pu[i] = static_cast<T_uint>(ws_pu[2 * i + 1]) +
                 static_cast<T_uint>(wt_pu[2 * i]);
      break;
5252
    case HSUB_S:
5253 5254 5255
      wd_p[i] =
          static_cast<T_int>(ws_p[2 * i + 1]) - static_cast<T_int>(wt_p[2 * i]);
      break;
5256
    case HSUB_U:
5257 5258
      wd_pu[i] = static_cast<T_uint>(ws_pu[2 * i + 1]) -
                 static_cast<T_uint>(wt_pu[2 * i]);
5259 5260 5261 5262
      break;
    default:
      UNREACHABLE();
  }
5263
}
5264

5265 5266 5267 5268 5269
void Simulator::DecodeTypeMsa3R() {
  DCHECK(IsMipsArchVariant(kMips32r6));
  DCHECK(CpuFeatures::IsSupported(MIPS_SIMD));
  uint32_t opcode = instr_.InstructionBits() & kMsa3RMask;
  msa_reg_t ws, wd, wt;
5270 5271 5272 5273 5274 5275 5276 5277 5278 5279 5280 5281 5282 5283 5284 5285 5286 5287 5288 5289 5290 5291 5292 5293 5294 5295 5296 5297 5298 5299 5300 5301 5302 5303 5304 5305 5306 5307 5308 5309 5310 5311 5312 5313 5314 5315 5316 5317 5318 5319 5320 5321 5322 5323 5324 5325 5326 5327 5328 5329 5330 5331 5332 5333 5334 5335 5336 5337 5338 5339 5340 5341 5342 5343 5344 5345 5346 5347 5348 5349 5350 5351
  get_msa_register(ws_reg(), &ws);
  get_msa_register(wt_reg(), &wt);
  get_msa_register(wd_reg(), &wd);
  switch (opcode) {
    case HADD_S:
    case HADD_U:
    case HSUB_S:
    case HSUB_U:
#define HORIZONTAL_ARITHMETIC_DF(num_of_lanes, int_type, lesser_int_type) \
  for (int i = 0; i < num_of_lanes; ++i) {                                \
    Msa3RInstrHelper_horizontal<int_type, lesser_int_type>(               \
        opcode, &ws, &wt, &wd, i, num_of_lanes);                          \
  }
      switch (DecodeMsaDataFormat()) {
        case MSA_HALF:
          HORIZONTAL_ARITHMETIC_DF(kMSALanesHalf, int16_t, int8_t);
          break;
        case MSA_WORD:
          HORIZONTAL_ARITHMETIC_DF(kMSALanesWord, int32_t, int16_t);
          break;
        case MSA_DWORD:
          HORIZONTAL_ARITHMETIC_DF(kMSALanesDword, int64_t, int32_t);
          break;
        default:
          UNREACHABLE();
      }
      break;
#undef HORIZONTAL_ARITHMETIC_DF
    case VSHF:
#define VSHF_DF(num_of_lanes, int_type)                          \
  for (int i = 0; i < num_of_lanes; ++i) {                       \
    Msa3RInstrHelper_shuffle<int_type>(opcode, &ws, &wt, &wd, i, \
                                       num_of_lanes);            \
  }
      switch (DecodeMsaDataFormat()) {
        case MSA_BYTE:
          VSHF_DF(kMSALanesByte, int8_t);
          break;
        case MSA_HALF:
          VSHF_DF(kMSALanesHalf, int16_t);
          break;
        case MSA_WORD:
          VSHF_DF(kMSALanesWord, int32_t);
          break;
        case MSA_DWORD:
          VSHF_DF(kMSALanesDword, int64_t);
          break;
        default:
          UNREACHABLE();
      }
#undef VSHF_DF
      break;
    case PCKEV:
    case PCKOD:
    case ILVL:
    case ILVR:
    case ILVEV:
    case ILVOD:
#define INTERLEAVE_PACK_DF(num_of_lanes, int_type)               \
  for (int i = 0; i < num_of_lanes / 2; ++i) {                   \
    Msa3RInstrHelper_shuffle<int_type>(opcode, &ws, &wt, &wd, i, \
                                       num_of_lanes);            \
  }
      switch (DecodeMsaDataFormat()) {
        case MSA_BYTE:
          INTERLEAVE_PACK_DF(kMSALanesByte, int8_t);
          break;
        case MSA_HALF:
          INTERLEAVE_PACK_DF(kMSALanesHalf, int16_t);
          break;
        case MSA_WORD:
          INTERLEAVE_PACK_DF(kMSALanesWord, int32_t);
          break;
        case MSA_DWORD:
          INTERLEAVE_PACK_DF(kMSALanesDword, int64_t);
          break;
        default:
          UNREACHABLE();
      }
      break;
#undef INTERLEAVE_PACK_DF
    default:
5352 5353 5354
#define MSA_3R_DF(elem, num_of_lanes)                                          \
  for (int i = 0; i < num_of_lanes; i++) {                                     \
    wd.elem[i] = Msa3RInstrHelper(opcode, wd.elem[i], ws.elem[i], wt.elem[i]); \
5355
  }
5356

5357 5358 5359 5360 5361 5362 5363 5364 5365 5366 5367 5368 5369 5370 5371 5372
      switch (DecodeMsaDataFormat()) {
        case MSA_BYTE:
          MSA_3R_DF(b, kMSALanesByte);
          break;
        case MSA_HALF:
          MSA_3R_DF(h, kMSALanesHalf);
          break;
        case MSA_WORD:
          MSA_3R_DF(w, kMSALanesWord);
          break;
        case MSA_DWORD:
          MSA_3R_DF(d, kMSALanesDword);
          break;
        default:
          UNREACHABLE();
      }
5373
#undef MSA_3R_DF
5374 5375 5376 5377
      break;
  }
  set_msa_register(wd_reg(), &wd);
  TraceMSARegWr(&wd);
5378 5379 5380 5381 5382 5383 5384 5385 5386 5387 5388 5389 5390 5391 5392 5393 5394 5395 5396 5397 5398 5399 5400 5401 5402 5403 5404 5405 5406 5407 5408 5409 5410 5411 5412 5413 5414 5415 5416 5417 5418 5419 5420 5421 5422 5423 5424 5425 5426 5427 5428 5429 5430 5431 5432 5433 5434 5435 5436 5437 5438 5439 5440 5441 5442 5443 5444 5445 5446 5447 5448 5449 5450 5451 5452 5453 5454 5455 5456 5457 5458 5459 5460 5461 5462 5463 5464 5465 5466 5467 5468 5469 5470 5471 5472 5473 5474
}

template <typename T_int, typename T_fp, typename T_reg>
void Msa3RFInstrHelper(uint32_t opcode, T_reg ws, T_reg wt, T_reg& wd) {
  const T_int all_ones = static_cast<T_int>(-1);
  const T_fp s_element = *reinterpret_cast<T_fp*>(&ws);
  const T_fp t_element = *reinterpret_cast<T_fp*>(&wt);
  switch (opcode) {
    case FCUN: {
      if (std::isnan(s_element) || std::isnan(t_element)) {
        wd = all_ones;
      } else {
        wd = 0;
      }
    } break;
    case FCEQ: {
      if (s_element != t_element || std::isnan(s_element) ||
          std::isnan(t_element)) {
        wd = 0;
      } else {
        wd = all_ones;
      }
    } break;
    case FCUEQ: {
      if (s_element == t_element || std::isnan(s_element) ||
          std::isnan(t_element)) {
        wd = all_ones;
      } else {
        wd = 0;
      }
    } break;
    case FCLT: {
      if (s_element >= t_element || std::isnan(s_element) ||
          std::isnan(t_element)) {
        wd = 0;
      } else {
        wd = all_ones;
      }
    } break;
    case FCULT: {
      if (s_element < t_element || std::isnan(s_element) ||
          std::isnan(t_element)) {
        wd = all_ones;
      } else {
        wd = 0;
      }
    } break;
    case FCLE: {
      if (s_element > t_element || std::isnan(s_element) ||
          std::isnan(t_element)) {
        wd = 0;
      } else {
        wd = all_ones;
      }
    } break;
    case FCULE: {
      if (s_element <= t_element || std::isnan(s_element) ||
          std::isnan(t_element)) {
        wd = all_ones;
      } else {
        wd = 0;
      }
    } break;
    case FCOR: {
      if (std::isnan(s_element) || std::isnan(t_element)) {
        wd = 0;
      } else {
        wd = all_ones;
      }
    } break;
    case FCUNE: {
      if (s_element != t_element || std::isnan(s_element) ||
          std::isnan(t_element)) {
        wd = all_ones;
      } else {
        wd = 0;
      }
    } break;
    case FCNE: {
      if (s_element == t_element || std::isnan(s_element) ||
          std::isnan(t_element)) {
        wd = 0;
      } else {
        wd = all_ones;
      }
    } break;
    case FADD:
      wd = bit_cast<T_int>(s_element + t_element);
      break;
    case FSUB:
      wd = bit_cast<T_int>(s_element - t_element);
      break;
    case FMUL:
      wd = bit_cast<T_int>(s_element * t_element);
      break;
    case FDIV: {
      if (t_element == 0) {
5475
        wd = bit_cast<T_int>(std::numeric_limits<T_fp>::quiet_NaN());
5476 5477 5478 5479 5480 5481 5482 5483 5484 5485 5486 5487 5488 5489 5490 5491 5492 5493 5494 5495 5496 5497 5498 5499 5500 5501 5502 5503 5504 5505 5506 5507 5508 5509 5510 5511 5512 5513 5514 5515 5516 5517 5518 5519
      } else {
        wd = bit_cast<T_int>(s_element / t_element);
      }
    } break;
    case FMADD:
      wd = bit_cast<T_int>(
          std::fma(s_element, t_element, *reinterpret_cast<T_fp*>(&wd)));
      break;
    case FMSUB:
      wd = bit_cast<T_int>(
          std::fma(s_element, -t_element, *reinterpret_cast<T_fp*>(&wd)));
      break;
    case FEXP2:
      wd = bit_cast<T_int>(std::ldexp(s_element, static_cast<int>(wt)));
      break;
    case FMIN:
      wd = bit_cast<T_int>(std::min(s_element, t_element));
      break;
    case FMAX:
      wd = bit_cast<T_int>(std::max(s_element, t_element));
      break;
    case FMIN_A: {
      wd = bit_cast<T_int>(
          std::fabs(s_element) < std::fabs(t_element) ? s_element : t_element);
    } break;
    case FMAX_A: {
      wd = bit_cast<T_int>(
          std::fabs(s_element) > std::fabs(t_element) ? s_element : t_element);
    } break;
    case FSOR:
    case FSUNE:
    case FSNE:
    case FSAF:
    case FSUN:
    case FSEQ:
    case FSUEQ:
    case FSLT:
    case FSULT:
    case FSLE:
    case FSULE:
      UNIMPLEMENTED();
      break;
    default:
      UNREACHABLE();
5520
  }
5521
}
5522

5523 5524 5525 5526 5527 5528 5529 5530 5531 5532 5533 5534 5535 5536 5537 5538 5539 5540 5541 5542 5543 5544 5545 5546 5547 5548 5549 5550 5551 5552 5553 5554 5555 5556 5557 5558 5559
template <typename T_int, typename T_int_dbl, typename T_reg>
void Msa3RFInstrHelper2(uint32_t opcode, T_reg ws, T_reg wt, T_reg& wd) {
  // typedef typename std::make_unsigned<T_int>::type T_uint;
  typedef typename std::make_unsigned<T_int_dbl>::type T_uint_dbl;
  const T_int max_int = std::numeric_limits<T_int>::max();
  const T_int min_int = std::numeric_limits<T_int>::min();
  const int shift = kBitsPerByte * sizeof(T_int) - 1;
  const T_int_dbl reg_s = ws;
  const T_int_dbl reg_t = wt;
  T_int_dbl product, result;
  product = reg_s * reg_t;
  switch (opcode) {
    case MUL_Q: {
      const T_int_dbl min_fix_dbl =
          bit_cast<T_uint_dbl>(std::numeric_limits<T_int_dbl>::min()) >> 1U;
      const T_int_dbl max_fix_dbl = std::numeric_limits<T_int_dbl>::max() >> 1U;
      if (product == min_fix_dbl) {
        product = max_fix_dbl;
      }
      wd = static_cast<T_int>(product >> shift);
    } break;
    case MADD_Q: {
      result = (product + (static_cast<T_int_dbl>(wd) << shift)) >> shift;
      wd = static_cast<T_int>(
          result > max_int ? max_int : result < min_int ? min_int : result);
    } break;
    case MSUB_Q: {
      result = (-product + (static_cast<T_int_dbl>(wd) << shift)) >> shift;
      wd = static_cast<T_int>(
          result > max_int ? max_int : result < min_int ? min_int : result);
    } break;
    case MULR_Q: {
      const T_int_dbl min_fix_dbl =
          bit_cast<T_uint_dbl>(std::numeric_limits<T_int_dbl>::min()) >> 1U;
      const T_int_dbl max_fix_dbl = std::numeric_limits<T_int_dbl>::max() >> 1U;
      if (product == min_fix_dbl) {
        wd = static_cast<T_int>(max_fix_dbl >> shift);
5560
        break;
5561 5562 5563 5564 5565 5566 5567 5568 5569 5570 5571 5572 5573 5574 5575 5576 5577 5578 5579
      }
      wd = static_cast<T_int>((product + (1 << (shift - 1))) >> shift);
    } break;
    case MADDR_Q: {
      result = (product + (static_cast<T_int_dbl>(wd) << shift) +
                (1 << (shift - 1))) >>
               shift;
      wd = static_cast<T_int>(
          result > max_int ? max_int : result < min_int ? min_int : result);
    } break;
    case MSUBR_Q: {
      result = (-product + (static_cast<T_int_dbl>(wd) << shift) +
                (1 << (shift - 1))) >>
               shift;
      wd = static_cast<T_int>(
          result > max_int ? max_int : result < min_int ? min_int : result);
    } break;
    default:
      UNREACHABLE();
5580
  }
5581
}
5582

5583 5584 5585 5586 5587 5588 5589 5590 5591 5592 5593 5594 5595 5596 5597 5598 5599 5600 5601 5602 5603 5604 5605 5606 5607 5608 5609 5610 5611 5612
void Simulator::DecodeTypeMsa3RF() {
  DCHECK(IsMipsArchVariant(kMips32r6));
  DCHECK(CpuFeatures::IsSupported(MIPS_SIMD));
  uint32_t opcode = instr_.InstructionBits() & kMsa3RFMask;
  msa_reg_t wd, ws, wt;
  if (opcode != FCAF) {
    get_msa_register(ws_reg(), &ws);
    get_msa_register(wt_reg(), &wt);
  }
  switch (opcode) {
    case FCAF:
      wd.d[0] = 0;
      wd.d[1] = 0;
      break;
    case FEXDO:
#define PACK_FLOAT16(sign, exp, frac) \
  static_cast<uint16_t>(((sign) << 15) + ((exp) << 10) + (frac))
#define FEXDO_DF(source, dst)                                        \
  do {                                                               \
    element = source;                                                \
    aSign = element >> 31;                                           \
    aExp = element >> 23 & 0xFF;                                     \
    aFrac = element & 0x007FFFFF;                                    \
    if (aExp == 0xFF) {                                              \
      if (aFrac) {                                                   \
        /* Input is a NaN */                                         \
        dst = 0x7DFFU;                                               \
        break;                                                       \
      }                                                              \
      /* Infinity */                                                 \
5613
      dst = PACK_FLOAT16(aSign, 0x1F, 0);                            \
5614 5615 5616 5617 5618 5619 5620 5621 5622 5623 5624 5625 5626
      break;                                                         \
    } else if (aExp == 0 && aFrac == 0) {                            \
      dst = PACK_FLOAT16(aSign, 0, 0);                               \
      break;                                                         \
    } else {                                                         \
      int maxexp = 29;                                               \
      uint32_t mask;                                                 \
      uint32_t increment;                                            \
      bool rounding_bumps_exp;                                       \
      aFrac |= 0x00800000;                                           \
      aExp -= 0x71;                                                  \
      if (aExp < 1) {                                                \
        /* Will be denormal in halfprec */                           \
5627
        mask = 0x00FFFFFF;                                           \
5628 5629 5630 5631 5632
        if (aExp >= -11) {                                           \
          mask >>= 11 + aExp;                                        \
        }                                                            \
      } else {                                                       \
        /* Normal number in halfprec */                              \
5633
        mask = 0x00001FFF;                                           \
5634 5635 5636 5637 5638 5639 5640 5641 5642 5643 5644 5645 5646 5647 5648 5649 5650 5651 5652 5653
      }                                                              \
      switch (MSACSR_ & 3) {                                         \
        case kRoundToNearest:                                        \
          increment = (mask + 1) >> 1;                               \
          if ((aFrac & mask) == increment) {                         \
            increment = aFrac & (increment << 1);                    \
          }                                                          \
          break;                                                     \
        case kRoundToPlusInf:                                        \
          increment = aSign ? 0 : mask;                              \
          break;                                                     \
        case kRoundToMinusInf:                                       \
          increment = aSign ? mask : 0;                              \
          break;                                                     \
        case kRoundToZero:                                           \
          increment = 0;                                             \
          break;                                                     \
      }                                                              \
      rounding_bumps_exp = (aFrac + increment >= 0x01000000);        \
      if (aExp > maxexp || (aExp == maxexp && rounding_bumps_exp)) { \
5654
        dst = PACK_FLOAT16(aSign, 0x1F, 0);                          \
5655 5656 5657 5658 5659 5660 5661 5662 5663 5664 5665 5666 5667 5668 5669 5670 5671 5672 5673 5674 5675 5676 5677 5678 5679 5680 5681
        break;                                                       \
      }                                                              \
      aFrac += increment;                                            \
      if (rounding_bumps_exp) {                                      \
        aFrac >>= 1;                                                 \
        aExp++;                                                      \
      }                                                              \
      if (aExp < -10) {                                              \
        dst = PACK_FLOAT16(aSign, 0, 0);                             \
        break;                                                       \
      }                                                              \
      if (aExp < 0) {                                                \
        aFrac >>= -aExp;                                             \
        aExp = 0;                                                    \
      }                                                              \
      dst = PACK_FLOAT16(aSign, aExp, aFrac >> 13);                  \
    }                                                                \
  } while (0);
      switch (DecodeMsaDataFormat()) {
        case MSA_HALF:
          for (int i = 0; i < kMSALanesWord; i++) {
            uint_fast32_t element;
            uint_fast32_t aSign, aFrac;
            int_fast32_t aExp;
            FEXDO_DF(ws.uw[i], wd.uh[i + kMSALanesHalf / 2])
            FEXDO_DF(wt.uw[i], wd.uh[i])
          }
5682
          break;
5683 5684 5685 5686 5687 5688 5689
        case MSA_WORD:
          for (int i = 0; i < kMSALanesDword; i++) {
            wd.w[i + kMSALanesWord / 2] = bit_cast<int32_t>(
                static_cast<float>(bit_cast<double>(ws.d[i])));
            wd.w[i] = bit_cast<int32_t>(
                static_cast<float>(bit_cast<double>(wt.d[i])));
          }
5690
          break;
5691 5692 5693 5694
        default:
          UNREACHABLE();
      }
      break;
5695
#undef PACK_FLOAT16
5696 5697 5698 5699 5700 5701 5702 5703 5704 5705 5706 5707 5708 5709 5710 5711 5712 5713 5714 5715 5716 5717 5718 5719
#undef FEXDO_DF
    case FTQ:
#define FTQ_DF(source, dst, fp_type, int_type)                 \
  element = bit_cast<fp_type>(source) *                        \
            (1U << (sizeof(int_type) * kBitsPerByte - 1));     \
  if (element > std::numeric_limits<int_type>::max()) {        \
    dst = std::numeric_limits<int_type>::max();                \
  } else if (element < std::numeric_limits<int_type>::min()) { \
    dst = std::numeric_limits<int_type>::min();                \
  } else if (std::isnan(element)) {                            \
    dst = 0;                                                   \
  } else {                                                     \
    int_type fixed_point;                                      \
    round_according_to_msacsr(element, element, fixed_point);  \
    dst = fixed_point;                                         \
  }

      switch (DecodeMsaDataFormat()) {
        case MSA_HALF:
          for (int i = 0; i < kMSALanesWord; i++) {
            float element;
            FTQ_DF(ws.w[i], wd.h[i + kMSALanesHalf / 2], float, int16_t)
            FTQ_DF(wt.w[i], wd.h[i], float, int16_t)
          }
5720
          break;
5721 5722 5723 5724 5725 5726
        case MSA_WORD:
          double element;
          for (int i = 0; i < kMSALanesDword; i++) {
            FTQ_DF(ws.d[i], wd.w[i + kMSALanesWord / 2], double, int32_t)
            FTQ_DF(wt.d[i], wd.w[i], double, int32_t)
          }
5727
          break;
5728 5729 5730 5731 5732 5733 5734 5735 5736 5737 5738 5739 5740 5741 5742 5743 5744
        default:
          UNREACHABLE();
      }
      break;
#undef FTQ_DF
#define MSA_3RF_DF(T1, T2, Lanes, ws, wt, wd)      \
  for (int i = 0; i < Lanes; i++) {                \
    Msa3RFInstrHelper<T1, T2>(opcode, ws, wt, wd); \
  }
#define MSA_3RF_DF2(T1, T2, Lanes, ws, wt, wd)      \
  for (int i = 0; i < Lanes; i++) {                 \
    Msa3RFInstrHelper2<T1, T2>(opcode, ws, wt, wd); \
  }
    case MADD_Q:
    case MSUB_Q:
    case MADDR_Q:
    case MSUBR_Q:
5745 5746
      get_msa_register(wd_reg(), &wd);
      V8_FALLTHROUGH;
5747 5748 5749 5750 5751 5752
    case MUL_Q:
    case MULR_Q:
      switch (DecodeMsaDataFormat()) {
        case MSA_HALF:
          MSA_3RF_DF2(int16_t, int32_t, kMSALanesHalf, ws.h[i], wt.h[i],
                      wd.h[i])
5753
          break;
5754 5755 5756
        case MSA_WORD:
          MSA_3RF_DF2(int32_t, int64_t, kMSALanesWord, ws.w[i], wt.w[i],
                      wd.w[i])
5757
          break;
5758 5759 5760 5761 5762 5763 5764 5765 5766 5767 5768 5769 5770 5771
        default:
          UNREACHABLE();
      }
      break;
    default:
      if (opcode == FMADD || opcode == FMSUB) {
        get_msa_register(wd_reg(), &wd);
      }
      switch (DecodeMsaDataFormat()) {
        case MSA_WORD:
          MSA_3RF_DF(int32_t, float, kMSALanesWord, ws.w[i], wt.w[i], wd.w[i])
          break;
        case MSA_DWORD:
          MSA_3RF_DF(int64_t, double, kMSALanesDword, ws.d[i], wt.d[i], wd.d[i])
5772 5773 5774 5775
          break;
        default:
          UNREACHABLE();
      }
5776 5777 5778 5779 5780 5781 5782 5783 5784 5785 5786 5787 5788 5789 5790 5791 5792 5793
      break;
#undef MSA_3RF_DF
#undef MSA_3RF_DF2
  }
  set_msa_register(wd_reg(), &wd);
  TraceMSARegWr(&wd);
}

void Simulator::DecodeTypeMsaVec() {
  DCHECK(IsMipsArchVariant(kMips32r6));
  DCHECK(CpuFeatures::IsSupported(MIPS_SIMD));
  uint32_t opcode = instr_.InstructionBits() & kMsaVECMask;
  msa_reg_t wd, ws, wt;

  get_msa_register(instr_.WsValue(), ws.w);
  get_msa_register(instr_.WtValue(), wt.w);
  if (opcode == BMNZ_V || opcode == BMZ_V || opcode == BSEL_V) {
    get_msa_register(instr_.WdValue(), wd.w);
5794 5795
  }

5796
  for (int i = 0; i < kMSALanesWord; i++) {
5797
    switch (opcode) {
5798 5799 5800 5801 5802 5803 5804 5805 5806 5807 5808 5809 5810 5811 5812 5813 5814 5815 5816 5817 5818 5819 5820 5821 5822 5823 5824 5825 5826 5827 5828 5829 5830 5831 5832 5833 5834 5835 5836 5837 5838
      case AND_V:
        wd.w[i] = ws.w[i] & wt.w[i];
        break;
      case OR_V:
        wd.w[i] = ws.w[i] | wt.w[i];
        break;
      case NOR_V:
        wd.w[i] = ~(ws.w[i] | wt.w[i]);
        break;
      case XOR_V:
        wd.w[i] = ws.w[i] ^ wt.w[i];
        break;
      case BMNZ_V:
        wd.w[i] = (wt.w[i] & ws.w[i]) | (~wt.w[i] & wd.w[i]);
        break;
      case BMZ_V:
        wd.w[i] = (~wt.w[i] & ws.w[i]) | (wt.w[i] & wd.w[i]);
        break;
      case BSEL_V:
        wd.w[i] = (~wd.w[i] & ws.w[i]) | (wd.w[i] & wt.w[i]);
        break;
      default:
        UNREACHABLE();
    }
  }
  set_msa_register(instr_.WdValue(), wd.w);
  TraceMSARegWr(wd.d);
}

void Simulator::DecodeTypeMsa2R() {
  DCHECK(IsMipsArchVariant(kMips32r6));
  DCHECK(CpuFeatures::IsSupported(MIPS_SIMD));
  uint32_t opcode = instr_.InstructionBits() & kMsa2RMask;
  msa_reg_t wd, ws;
  switch (opcode) {
    case FILL:
      switch (DecodeMsaDataFormat()) {
        case MSA_BYTE: {
          int32_t rs = get_register(instr_.WsValue());
          for (int i = 0; i < kMSALanesByte; i++) {
            wd.b[i] = rs & 0xFFu;
5839
          }
5840 5841 5842 5843 5844 5845 5846 5847
          set_msa_register(instr_.WdValue(), wd.b);
          TraceMSARegWr(wd.b);
          break;
        }
        case MSA_HALF: {
          int32_t rs = get_register(instr_.WsValue());
          for (int i = 0; i < kMSALanesHalf; i++) {
            wd.h[i] = rs & 0xFFFFu;
5848
          }
5849 5850 5851 5852 5853 5854 5855 5856
          set_msa_register(instr_.WdValue(), wd.h);
          TraceMSARegWr(wd.h);
          break;
        }
        case MSA_WORD: {
          int32_t rs = get_register(instr_.WsValue());
          for (int i = 0; i < kMSALanesWord; i++) {
            wd.w[i] = rs;
5857
          }
5858 5859 5860
          set_msa_register(instr_.WdValue(), wd.w);
          TraceMSARegWr(wd.w);
          break;
5861
        }
5862 5863 5864 5865 5866
        default:
          UNREACHABLE();
      }
      break;
    case PCNT:
5867 5868 5869 5870
#define PCNT_DF(elem, num_of_lanes)                       \
  get_msa_register(instr_.WsValue(), ws.elem);            \
  for (int i = 0; i < num_of_lanes; i++) {                \
    uint64_t u64elem = static_cast<uint64_t>(ws.elem[i]); \
5871
    wd.elem[i] = base::bits::CountPopulation(u64elem);    \
5872 5873 5874 5875 5876 5877 5878 5879 5880 5881 5882 5883 5884 5885 5886 5887 5888 5889 5890 5891 5892 5893
  }                                                       \
  set_msa_register(instr_.WdValue(), wd.elem);            \
  TraceMSARegWr(wd.elem)

      switch (DecodeMsaDataFormat()) {
        case MSA_BYTE:
          PCNT_DF(ub, kMSALanesByte);
          break;
        case MSA_HALF:
          PCNT_DF(uh, kMSALanesHalf);
          break;
        case MSA_WORD:
          PCNT_DF(uw, kMSALanesWord);
          break;
        case MSA_DWORD:
          PCNT_DF(ud, kMSALanesDword);
          break;
        default:
          UNREACHABLE();
      }
#undef PCNT_DF
      break;
5894
    case NLOC:
5895 5896 5897 5898 5899 5900 5901 5902 5903 5904 5905 5906 5907 5908 5909 5910 5911 5912 5913 5914 5915 5916 5917 5918 5919 5920 5921 5922 5923 5924 5925
#define NLOC_DF(elem, num_of_lanes)                                         \
  get_msa_register(instr_.WsValue(), ws.elem);                              \
  for (int i = 0; i < num_of_lanes; i++) {                                  \
    const uint64_t mask = (num_of_lanes == kMSALanesDword)                  \
                              ? UINT64_MAX                                  \
                              : (1ULL << (kMSARegSize / num_of_lanes)) - 1; \
    uint64_t u64elem = static_cast<uint64_t>(~ws.elem[i]) & mask;           \
    wd.elem[i] = base::bits::CountLeadingZeros64(u64elem) -                 \
                 (64 - kMSARegSize / num_of_lanes);                         \
  }                                                                         \
  set_msa_register(instr_.WdValue(), wd.elem);                              \
  TraceMSARegWr(wd.elem)

      switch (DecodeMsaDataFormat()) {
        case MSA_BYTE:
          NLOC_DF(ub, kMSALanesByte);
          break;
        case MSA_HALF:
          NLOC_DF(uh, kMSALanesHalf);
          break;
        case MSA_WORD:
          NLOC_DF(uw, kMSALanesWord);
          break;
        case MSA_DWORD:
          NLOC_DF(ud, kMSALanesDword);
          break;
        default:
          UNREACHABLE();
      }
#undef NLOC_DF
      break;
5926
    case NLZC:
5927 5928 5929 5930 5931 5932 5933 5934 5935 5936 5937 5938 5939 5940 5941 5942 5943 5944 5945 5946 5947 5948 5949 5950 5951 5952 5953
#define NLZC_DF(elem, num_of_lanes)                         \
  get_msa_register(instr_.WsValue(), ws.elem);              \
  for (int i = 0; i < num_of_lanes; i++) {                  \
    uint64_t u64elem = static_cast<uint64_t>(ws.elem[i]);   \
    wd.elem[i] = base::bits::CountLeadingZeros64(u64elem) - \
                 (64 - kMSARegSize / num_of_lanes);         \
  }                                                         \
  set_msa_register(instr_.WdValue(), wd.elem);              \
  TraceMSARegWr(wd.elem)

      switch (DecodeMsaDataFormat()) {
        case MSA_BYTE:
          NLZC_DF(ub, kMSALanesByte);
          break;
        case MSA_HALF:
          NLZC_DF(uh, kMSALanesHalf);
          break;
        case MSA_WORD:
          NLZC_DF(uw, kMSALanesWord);
          break;
        case MSA_DWORD:
          NLZC_DF(ud, kMSALanesDword);
          break;
        default:
          UNREACHABLE();
      }
#undef NLZC_DF
5954 5955 5956 5957 5958 5959
      break;
    default:
      UNREACHABLE();
  }
}

5960 5961 5962 5963 5964 5965 5966 5967 5968 5969 5970 5971
#define BIT(n) (0x1LL << n)
#define QUIET_BIT_S(nan) (bit_cast<int32_t>(nan) & BIT(22))
#define QUIET_BIT_D(nan) (bit_cast<int64_t>(nan) & BIT(51))
static inline bool isSnan(float fp) { return !QUIET_BIT_S(fp); }
static inline bool isSnan(double fp) { return !QUIET_BIT_D(fp); }
#undef QUIET_BIT_S
#undef QUIET_BIT_D

template <typename T_int, typename T_fp, typename T_src, typename T_dst>
T_int Msa2RFInstrHelper(uint32_t opcode, T_src src, T_dst& dst,
                        Simulator* sim) {
  typedef typename std::make_unsigned<T_int>::type T_uint;
5972
  switch (opcode) {
5973 5974 5975 5976 5977 5978 5979 5980 5981 5982 5983 5984 5985 5986 5987 5988 5989 5990 5991 5992 5993 5994 5995 5996 5997 5998 5999 6000 6001 6002 6003 6004 6005 6006 6007 6008 6009 6010 6011 6012 6013 6014 6015 6016 6017 6018 6019 6020 6021 6022 6023 6024 6025 6026 6027 6028 6029 6030 6031 6032 6033 6034 6035 6036 6037 6038 6039 6040 6041 6042
    case FCLASS: {
#define SNAN_BIT BIT(0)
#define QNAN_BIT BIT(1)
#define NEG_INFINITY_BIT BIT(2)
#define NEG_NORMAL_BIT BIT(3)
#define NEG_SUBNORMAL_BIT BIT(4)
#define NEG_ZERO_BIT BIT(5)
#define POS_INFINITY_BIT BIT(6)
#define POS_NORMAL_BIT BIT(7)
#define POS_SUBNORMAL_BIT BIT(8)
#define POS_ZERO_BIT BIT(9)
      T_fp element = *reinterpret_cast<T_fp*>(&src);
      switch (std::fpclassify(element)) {
        case FP_INFINITE:
          if (std::signbit(element)) {
            dst = NEG_INFINITY_BIT;
          } else {
            dst = POS_INFINITY_BIT;
          }
          break;
        case FP_NAN:
          if (isSnan(element)) {
            dst = SNAN_BIT;
          } else {
            dst = QNAN_BIT;
          }
          break;
        case FP_NORMAL:
          if (std::signbit(element)) {
            dst = NEG_NORMAL_BIT;
          } else {
            dst = POS_NORMAL_BIT;
          }
          break;
        case FP_SUBNORMAL:
          if (std::signbit(element)) {
            dst = NEG_SUBNORMAL_BIT;
          } else {
            dst = POS_SUBNORMAL_BIT;
          }
          break;
        case FP_ZERO:
          if (std::signbit(element)) {
            dst = NEG_ZERO_BIT;
          } else {
            dst = POS_ZERO_BIT;
          }
          break;
        default:
          UNREACHABLE();
      }
      break;
    }
#undef BIT
#undef SNAN_BIT
#undef QNAN_BIT
#undef NEG_INFINITY_BIT
#undef NEG_NORMAL_BIT
#undef NEG_SUBNORMAL_BIT
#undef NEG_ZERO_BIT
#undef POS_INFINITY_BIT
#undef POS_NORMAL_BIT
#undef POS_SUBNORMAL_BIT
#undef POS_ZERO_BIT
    case FTRUNC_S: {
      T_fp element = bit_cast<T_fp>(src);
      const T_int max_int = std::numeric_limits<T_int>::max();
      const T_int min_int = std::numeric_limits<T_int>::min();
      if (std::isnan(element)) {
        dst = 0;
6043 6044
      } else if (element >= max_int || element <= min_int) {
        dst = element >= max_int ? max_int : min_int;
6045 6046 6047 6048 6049 6050 6051 6052 6053 6054
      } else {
        dst = static_cast<T_int>(std::trunc(element));
      }
      break;
    }
    case FTRUNC_U: {
      T_fp element = bit_cast<T_fp>(src);
      const T_uint max_int = std::numeric_limits<T_uint>::max();
      if (std::isnan(element)) {
        dst = 0;
6055 6056
      } else if (element >= max_int || element <= 0) {
        dst = element >= max_int ? max_int : 0;
6057 6058 6059 6060 6061 6062 6063 6064 6065 6066 6067 6068 6069 6070 6071 6072 6073 6074 6075 6076 6077 6078 6079 6080 6081 6082 6083 6084 6085 6086 6087 6088 6089 6090 6091 6092 6093 6094 6095 6096 6097 6098 6099 6100 6101 6102 6103 6104 6105 6106 6107 6108 6109 6110 6111 6112 6113 6114 6115 6116 6117 6118 6119 6120 6121 6122 6123 6124 6125 6126 6127 6128 6129 6130 6131 6132 6133 6134 6135 6136 6137 6138 6139 6140 6141 6142 6143 6144 6145 6146 6147 6148 6149 6150 6151
      } else {
        dst = static_cast<T_uint>(std::trunc(element));
      }
      break;
    }
    case FSQRT: {
      T_fp element = bit_cast<T_fp>(src);
      if (element < 0 || std::isnan(element)) {
        dst = bit_cast<T_int>(std::numeric_limits<T_fp>::quiet_NaN());
      } else {
        dst = bit_cast<T_int>(std::sqrt(element));
      }
      break;
    }
    case FRSQRT: {
      T_fp element = bit_cast<T_fp>(src);
      if (element < 0 || std::isnan(element)) {
        dst = bit_cast<T_int>(std::numeric_limits<T_fp>::quiet_NaN());
      } else {
        dst = bit_cast<T_int>(1 / std::sqrt(element));
      }
      break;
    }
    case FRCP: {
      T_fp element = bit_cast<T_fp>(src);
      if (std::isnan(element)) {
        dst = bit_cast<T_int>(std::numeric_limits<T_fp>::quiet_NaN());
      } else {
        dst = bit_cast<T_int>(1 / element);
      }
      break;
    }
    case FRINT: {
      T_fp element = bit_cast<T_fp>(src);
      if (std::isnan(element)) {
        dst = bit_cast<T_int>(std::numeric_limits<T_fp>::quiet_NaN());
      } else {
        T_int dummy;
        sim->round_according_to_msacsr<T_fp, T_int>(element, element, dummy);
        dst = bit_cast<T_int>(element);
      }
      break;
    }
    case FLOG2: {
      T_fp element = bit_cast<T_fp>(src);
      switch (std::fpclassify(element)) {
        case FP_NORMAL:
        case FP_SUBNORMAL:
          dst = bit_cast<T_int>(std::logb(element));
          break;
        case FP_ZERO:
          dst = bit_cast<T_int>(-std::numeric_limits<T_fp>::infinity());
          break;
        case FP_NAN:
          dst = bit_cast<T_int>(std::numeric_limits<T_fp>::quiet_NaN());
          break;
        case FP_INFINITE:
          if (element < 0) {
            dst = bit_cast<T_int>(std::numeric_limits<T_fp>::quiet_NaN());
          } else {
            dst = bit_cast<T_int>(std::numeric_limits<T_fp>::infinity());
          }
          break;
        default:
          UNREACHABLE();
      }
      break;
    }
    case FTINT_S: {
      T_fp element = bit_cast<T_fp>(src);
      const T_int max_int = std::numeric_limits<T_int>::max();
      const T_int min_int = std::numeric_limits<T_int>::min();
      if (std::isnan(element)) {
        dst = 0;
      } else if (element < min_int || element > max_int) {
        dst = element > max_int ? max_int : min_int;
      } else {
        sim->round_according_to_msacsr<T_fp, T_int>(element, element, dst);
      }
      break;
    }
    case FTINT_U: {
      T_fp element = bit_cast<T_fp>(src);
      const T_uint max_uint = std::numeric_limits<T_uint>::max();
      if (std::isnan(element)) {
        dst = 0;
      } else if (element < 0 || element > max_uint) {
        dst = element > max_uint ? max_uint : 0;
      } else {
        T_uint res;
        sim->round_according_to_msacsr<T_fp, T_uint>(element, element, res);
        dst = *reinterpret_cast<T_int*>(&res);
      }
      break;
    }
6152
    case FFINT_S:
6153 6154
      dst = bit_cast<T_int>(static_cast<T_fp>(src));
      break;
6155
    case FFINT_U:
6156 6157
      typedef typename std::make_unsigned<T_src>::type uT_src;
      dst = bit_cast<T_int>(static_cast<T_fp>(bit_cast<uT_src>(src)));
6158 6159 6160 6161
      break;
    default:
      UNREACHABLE();
  }
6162 6163 6164
  return 0;
}

6165 6166
template <typename T_int, typename T_fp, typename T_reg>
T_int Msa2RFInstrHelper2(uint32_t opcode, T_reg ws, int i) {
6167 6168
  switch (opcode) {
#define EXTRACT_FLOAT16_SIGN(fp16) (fp16 >> 15)
6169 6170
#define EXTRACT_FLOAT16_EXP(fp16) (fp16 >> 10 & 0x1F)
#define EXTRACT_FLOAT16_FRAC(fp16) (fp16 & 0x3FF)
6171 6172 6173 6174 6175 6176 6177 6178 6179
#define PACK_FLOAT32(sign, exp, frac) \
  static_cast<uint32_t>(((sign) << 31) + ((exp) << 23) + (frac))
#define FEXUP_DF(src_index)                                                   \
  uint_fast16_t element = ws.uh[src_index];                                   \
  uint_fast32_t aSign, aFrac;                                                 \
  int_fast32_t aExp;                                                          \
  aSign = EXTRACT_FLOAT16_SIGN(element);                                      \
  aExp = EXTRACT_FLOAT16_EXP(element);                                        \
  aFrac = EXTRACT_FLOAT16_FRAC(element);                                      \
6180
  if (V8_LIKELY(aExp && aExp != 0x1F)) {                                      \
6181
    return PACK_FLOAT32(aSign, aExp + 0x70, aFrac << 13);                     \
6182
  } else if (aExp == 0x1F) {                                                  \
6183 6184 6185 6186 6187 6188 6189 6190 6191 6192 6193 6194 6195 6196 6197 6198 6199 6200 6201 6202 6203 6204 6205 6206 6207 6208 6209 6210 6211 6212 6213 6214 6215 6216 6217 6218 6219 6220 6221 6222 6223 6224 6225 6226 6227 6228 6229 6230 6231 6232 6233 6234 6235 6236 6237 6238 6239 6240 6241 6242 6243 6244 6245 6246 6247 6248 6249 6250 6251 6252 6253 6254 6255 6256 6257 6258 6259 6260 6261 6262 6263 6264 6265 6266 6267 6268 6269 6270 6271 6272 6273 6274 6275 6276 6277 6278 6279 6280
    if (aFrac) {                                                              \
      return bit_cast<int32_t>(std::numeric_limits<float>::quiet_NaN());      \
    } else {                                                                  \
      return bit_cast<uint32_t>(std::numeric_limits<float>::infinity()) |     \
             static_cast<uint32_t>(aSign) << 31;                              \
    }                                                                         \
  } else {                                                                    \
    if (aFrac == 0) {                                                         \
      return PACK_FLOAT32(aSign, 0, 0);                                       \
    } else {                                                                  \
      int_fast16_t shiftCount =                                               \
          base::bits::CountLeadingZeros32(static_cast<uint32_t>(aFrac)) - 21; \
      aFrac <<= shiftCount;                                                   \
      aExp = -shiftCount;                                                     \
      return PACK_FLOAT32(aSign, aExp + 0x70, aFrac << 13);                   \
    }                                                                         \
  }
    case FEXUPL:
      if (std::is_same<int32_t, T_int>::value) {
        FEXUP_DF(i + kMSALanesWord)
      } else {
        return bit_cast<int64_t>(
            static_cast<double>(bit_cast<float>(ws.w[i + kMSALanesDword])));
      }
    case FEXUPR:
      if (std::is_same<int32_t, T_int>::value) {
        FEXUP_DF(i)
      } else {
        return bit_cast<int64_t>(static_cast<double>(bit_cast<float>(ws.w[i])));
      }
    case FFQL: {
      if (std::is_same<int32_t, T_int>::value) {
        return bit_cast<int32_t>(static_cast<float>(ws.h[i + kMSALanesWord]) /
                                 (1U << 15));
      } else {
        return bit_cast<int64_t>(static_cast<double>(ws.w[i + kMSALanesDword]) /
                                 (1U << 31));
      }
      break;
    }
    case FFQR: {
      if (std::is_same<int32_t, T_int>::value) {
        return bit_cast<int32_t>(static_cast<float>(ws.h[i]) / (1U << 15));
      } else {
        return bit_cast<int64_t>(static_cast<double>(ws.w[i]) / (1U << 31));
      }
      break;
      default:
        UNREACHABLE();
    }
  }
#undef EXTRACT_FLOAT16_SIGN
#undef EXTRACT_FLOAT16_EXP
#undef EXTRACT_FLOAT16_FRAC
#undef PACK_FLOAT32
#undef FEXUP_DF
}

void Simulator::DecodeTypeMsa2RF() {
  DCHECK(IsMipsArchVariant(kMips32r6));
  DCHECK(CpuFeatures::IsSupported(MIPS_SIMD));
  uint32_t opcode = instr_.InstructionBits() & kMsa2RFMask;
  msa_reg_t wd, ws;
  get_msa_register(ws_reg(), &ws);
  if (opcode == FEXUPL || opcode == FEXUPR || opcode == FFQL ||
      opcode == FFQR) {
    switch (DecodeMsaDataFormat()) {
      case MSA_WORD:
        for (int i = 0; i < kMSALanesWord; i++) {
          wd.w[i] = Msa2RFInstrHelper2<int32_t, float>(opcode, ws, i);
        }
        break;
      case MSA_DWORD:
        for (int i = 0; i < kMSALanesDword; i++) {
          wd.d[i] = Msa2RFInstrHelper2<int64_t, double>(opcode, ws, i);
        }
        break;
      default:
        UNREACHABLE();
    }
  } else {
    switch (DecodeMsaDataFormat()) {
      case MSA_WORD:
        for (int i = 0; i < kMSALanesWord; i++) {
          Msa2RFInstrHelper<int32_t, float>(opcode, ws.w[i], wd.w[i], this);
        }
        break;
      case MSA_DWORD:
        for (int i = 0; i < kMSALanesDword; i++) {
          Msa2RFInstrHelper<int64_t, double>(opcode, ws.d[i], wd.d[i], this);
        }
        break;
      default:
        UNREACHABLE();
    }
  }
  set_msa_register(wd_reg(), &wd);
  TraceMSARegWr(&wd);
6281 6282
}

6283
void Simulator::DecodeTypeRegister() {
6284
  // ---------- Execution.
6285
  switch (instr_.OpcodeFieldRaw()) {
6286
    case COP1:
6287
      DecodeTypeRegisterCOP1();
6288 6289
      break;
    case COP1X:
6290
      DecodeTypeRegisterCOP1X();
6291 6292
      break;
    case SPECIAL:
6293
      DecodeTypeRegisterSPECIAL();
6294 6295
      break;
    case SPECIAL2:
6296
      DecodeTypeRegisterSPECIAL2();
6297 6298
      break;
    case SPECIAL3:
6299
      DecodeTypeRegisterSPECIAL3();
6300
      break;
6301 6302 6303 6304 6305 6306 6307 6308 6309 6310 6311 6312 6313 6314 6315 6316 6317
    case MSA:
      switch (instr_.MSAMinorOpcodeField()) {
        case kMsaMinor3R:
          DecodeTypeMsa3R();
          break;
        case kMsaMinor3RF:
          DecodeTypeMsa3RF();
          break;
        case kMsaMinorVEC:
          DecodeTypeMsaVec();
          break;
        case kMsaMinor2R:
          DecodeTypeMsa2R();
          break;
        case kMsaMinor2RF:
          DecodeTypeMsa2RF();
          break;
6318 6319 6320
        case kMsaMinorELM:
          DecodeTypeMsaELM();
          break;
6321 6322 6323 6324
        default:
          UNREACHABLE();
      }
      break;
6325
    default:
6326
      UNREACHABLE();
6327
  }
6328 6329
}

6330

6331
// Type 2: instructions using a 16, 21 or 26 bits immediate. (e.g. beq, beqc).
6332
void Simulator::DecodeTypeImmediate() {
6333
  // Instruction fields.
6334 6335 6336
  Opcode op = instr_.OpcodeFieldRaw();
  int32_t rs_reg = instr_.RsValue();
  int32_t rs = get_register(instr_.RsValue());
6337
  uint32_t rs_u = static_cast<uint32_t>(rs);
6338
  int32_t rt_reg = instr_.RtValue();  // Destination register.
6339
  int32_t rt = get_register(rt_reg);
6340
  int16_t imm16 = instr_.Imm16Value();
6341

6342
  int32_t ft_reg = instr_.FtValue();  // Destination register.
6343

6344
  // Zero extended immediate.
6345
  uint32_t oe_imm16 = 0xFFFF & imm16;
6346
  // Sign extended immediate.
6347 6348
  int32_t se_imm16 = imm16;

6349 6350 6351
  // Next pc.
  int32_t next_pc = bad_ra;

6352
  // Used for conditional branch instructions.
6353 6354
  bool execute_branch_delay_instruction = false;

6355
  // Used for arithmetic instructions.
6356 6357
  int32_t alu_out = 0;

6358
  // Used for memory instructions.
6359 6360
  int32_t addr = 0x0;

6361
  // Branch instructions common part.
6362 6363 6364 6365
  auto BranchAndLinkHelper =
      [this, &next_pc, &execute_branch_delay_instruction](bool do_branch) {
        execute_branch_delay_instruction = true;
        int32_t current_pc = get_pc();
6366
        set_register(31, current_pc + 2 * kInstrSize);
6367 6368
        if (do_branch) {
          int16_t imm16 = this->instr_.Imm16Value();
6369
          next_pc = current_pc + (imm16 << 2) + kInstrSize;
6370
        } else {
6371
          next_pc = current_pc + 2 * kInstrSize;
6372 6373
        }
      };
6374

6375
  auto BranchHelper = [this, &next_pc,
6376 6377 6378 6379
                       &execute_branch_delay_instruction](bool do_branch) {
    execute_branch_delay_instruction = true;
    int32_t current_pc = get_pc();
    if (do_branch) {
6380
      int16_t imm16 = this->instr_.Imm16Value();
6381
      next_pc = current_pc + (imm16 << 2) + kInstrSize;
6382
    } else {
6383
      next_pc = current_pc + 2 * kInstrSize;
6384 6385 6386
    }
  };

6387 6388 6389 6390 6391 6392 6393
  auto BranchHelper_MSA = [this, &next_pc, imm16,
                           &execute_branch_delay_instruction](bool do_branch) {
    execute_branch_delay_instruction = true;
    int32_t current_pc = get_pc();
    const int32_t bitsIn16Int = sizeof(int16_t) * kBitsPerByte;
    if (do_branch) {
      if (FLAG_debug_code) {
6394
        int16_t bits = imm16 & 0xFC;
6395 6396 6397
        if (imm16 >= 0) {
          CHECK_EQ(bits, 0);
        } else {
6398
          CHECK_EQ(bits ^ 0xFC, 0);
6399 6400 6401 6402 6403 6404
        }
      }
      // jump range :[pc + kInstrSize - 512 * kInstrSize,
      //              pc + kInstrSize + 511 * kInstrSize]
      int16_t offset = static_cast<int16_t>(imm16 << (bitsIn16Int - 10)) >>
                       (bitsIn16Int - 12);
6405
      next_pc = current_pc + offset + kInstrSize;
6406
    } else {
6407
      next_pc = current_pc + 2 * kInstrSize;
6408 6409 6410
    }
  };

6411
  auto BranchAndLinkCompactHelper = [this, &next_pc](bool do_branch, int bits) {
6412 6413 6414
    int32_t current_pc = get_pc();
    CheckForbiddenSlot(current_pc);
    if (do_branch) {
6415
      int32_t imm = this->instr_.ImmValue(bits);
6416 6417
      imm <<= 32 - bits;
      imm >>= 32 - bits;
6418 6419
      next_pc = current_pc + (imm << 2) + kInstrSize;
      set_register(31, current_pc + kInstrSize);
6420 6421 6422
    }
  };

6423
  auto BranchCompactHelper = [this, &next_pc](bool do_branch, int bits) {
6424 6425 6426
    int32_t current_pc = get_pc();
    CheckForbiddenSlot(current_pc);
    if (do_branch) {
6427
      int32_t imm = this->instr_.ImmValue(bits);
6428 6429
      imm <<= 32 - bits;
      imm >>= 32 - bits;
6430
      next_pc = get_pc() + (imm << 2) + kInstrSize;
6431 6432 6433
    }
  };

6434
  switch (op) {
6435
    // ------------- COP1. Coprocessor instructions.
6436
    case COP1:
6437
      switch (instr_.RsFieldRaw()) {
6438 6439
        case BC1: {  // Branch on coprocessor condition.
          // Floating point.
6440
          uint32_t cc = instr_.FBccValue();
6441 6442
          uint32_t fcsr_cc = get_fcsr_condition_bit(cc);
          uint32_t cc_value = test_fcsr_bit(fcsr_cc);
6443
          bool do_branch = (instr_.FBtrueValue()) ? cc_value : !cc_value;
6444
          BranchHelper(do_branch);
6445
          break;
6446
        }
6447
        case BC1EQZ:
6448
          BranchHelper(!(get_fpu_register(ft_reg) & 0x1));
6449 6450
          break;
        case BC1NEZ:
6451
          BranchHelper(get_fpu_register(ft_reg) & 0x1);
6452
          break;
6453 6454 6455 6456 6457 6458 6459 6460 6461 6462 6463 6464 6465 6466 6467 6468 6469
        case BZ_V: {
          msa_reg_t wt;
          get_msa_register(wt_reg(), &wt);
          BranchHelper_MSA(wt.d[0] == 0 && wt.d[1] == 0);
        } break;
#define BZ_DF(witdh, lanes)          \
  {                                  \
    msa_reg_t wt;                    \
    get_msa_register(wt_reg(), &wt); \
    int i;                           \
    for (i = 0; i < lanes; ++i) {    \
      if (wt.witdh[i] == 0) {        \
        break;                       \
      }                              \
    }                                \
    BranchHelper_MSA(i != lanes);    \
  }
6470
        case BZ_B:
6471 6472
          BZ_DF(b, kMSALanesByte)
          break;
6473
        case BZ_H:
6474 6475
          BZ_DF(h, kMSALanesHalf)
          break;
6476
        case BZ_W:
6477 6478
          BZ_DF(w, kMSALanesWord)
          break;
6479
        case BZ_D:
6480 6481 6482 6483 6484 6485 6486 6487 6488 6489 6490 6491 6492 6493 6494 6495 6496 6497 6498 6499
          BZ_DF(d, kMSALanesDword)
          break;
#undef BZ_DF
        case BNZ_V: {
          msa_reg_t wt;
          get_msa_register(wt_reg(), &wt);
          BranchHelper_MSA(wt.d[0] != 0 || wt.d[1] != 0);
        } break;
#define BNZ_DF(witdh, lanes)         \
  {                                  \
    msa_reg_t wt;                    \
    get_msa_register(wt_reg(), &wt); \
    int i;                           \
    for (i = 0; i < lanes; ++i) {    \
      if (wt.witdh[i] == 0) {        \
        break;                       \
      }                              \
    }                                \
    BranchHelper_MSA(i == lanes);    \
  }
6500
        case BNZ_B:
6501 6502
          BNZ_DF(b, kMSALanesByte)
          break;
6503
        case BNZ_H:
6504 6505
          BNZ_DF(h, kMSALanesHalf)
          break;
6506
        case BNZ_W:
6507 6508
          BNZ_DF(w, kMSALanesWord)
          break;
6509
        case BNZ_D:
6510
          BNZ_DF(d, kMSALanesDword)
6511
          break;
6512
#undef BNZ_DF
6513 6514
        default:
          UNREACHABLE();
6515
      }
6516
      break;
6517
    // ------------- REGIMM class.
6518
    case REGIMM:
6519
      switch (instr_.RtFieldRaw()) {
6520
        case BLTZ:
6521
          BranchHelper(rs < 0);
6522 6523
          break;
        case BGEZ:
6524 6525 6526 6527
          BranchHelper(rs >= 0);
          break;
        case BLTZAL:
          BranchAndLinkHelper(rs < 0);
6528 6529
          break;
        case BGEZAL:
6530
          BranchAndLinkHelper(rs >= 0);
6531 6532 6533
          break;
        default:
          UNREACHABLE();
6534
      }
6535
      break;  // case REGIMM.
6536
    // ------------- Branch instructions.
6537 6538 6539
    // When comparing to zero, the encoding of rt field is always 0, so we don't
    // need to replace rt with zero.
    case BEQ:
6540
      BranchHelper(rs == rt);
6541 6542
      break;
    case BNE:
6543
      BranchHelper(rs != rt);
6544
      break;
6545 6546 6547 6548 6549 6550 6551 6552 6553 6554 6555 6556 6557 6558 6559 6560 6561 6562 6563 6564 6565 6566 6567 6568 6569 6570 6571 6572 6573 6574 6575 6576 6577 6578 6579 6580 6581 6582 6583 6584 6585 6586 6587 6588 6589 6590 6591 6592 6593 6594 6595 6596 6597 6598 6599 6600 6601 6602 6603 6604 6605 6606 6607 6608 6609 6610 6611 6612 6613 6614 6615 6616 6617 6618 6619 6620 6621
    case POP06:  // BLEZALC, BGEZALC, BGEUC, BLEZ (pre-r6)
      if (IsMipsArchVariant(kMips32r6)) {
        if (rt_reg != 0) {
          if (rs_reg == 0) {  // BLEZALC
            BranchAndLinkCompactHelper(rt <= 0, 16);
          } else {
            if (rs_reg == rt_reg) {  // BGEZALC
              BranchAndLinkCompactHelper(rt >= 0, 16);
            } else {  // BGEUC
              BranchCompactHelper(
                  static_cast<uint32_t>(rs) >= static_cast<uint32_t>(rt), 16);
            }
          }
        } else {  // BLEZ
          BranchHelper(rs <= 0);
        }
      } else {  // BLEZ
        BranchHelper(rs <= 0);
      }
      break;
    case POP07:  // BGTZALC, BLTZALC, BLTUC, BGTZ (pre-r6)
      if (IsMipsArchVariant(kMips32r6)) {
        if (rt_reg != 0) {
          if (rs_reg == 0) {  // BGTZALC
            BranchAndLinkCompactHelper(rt > 0, 16);
          } else {
            if (rt_reg == rs_reg) {  // BLTZALC
              BranchAndLinkCompactHelper(rt < 0, 16);
            } else {  // BLTUC
              BranchCompactHelper(
                  static_cast<uint32_t>(rs) < static_cast<uint32_t>(rt), 16);
            }
          }
        } else {  // BGTZ
          BranchHelper(rs > 0);
        }
      } else {  // BGTZ
        BranchHelper(rs > 0);
      }
      break;
    case POP26:  // BLEZC, BGEZC, BGEC/BLEC / BLEZL (pre-r6)
      if (IsMipsArchVariant(kMips32r6)) {
        if (rt_reg != 0) {
          if (rs_reg == 0) {  // BLEZC
            BranchCompactHelper(rt <= 0, 16);
          } else {
            if (rs_reg == rt_reg) {  // BGEZC
              BranchCompactHelper(rt >= 0, 16);
            } else {  // BGEC/BLEC
              BranchCompactHelper(rs >= rt, 16);
            }
          }
        }
      } else {  // BLEZL
        BranchAndLinkHelper(rs <= 0);
      }
      break;
    case POP27:  // BGTZC, BLTZC, BLTC/BGTC / BGTZL (pre-r6)
      if (IsMipsArchVariant(kMips32r6)) {
        if (rt_reg != 0) {
          if (rs_reg == 0) {  // BGTZC
            BranchCompactHelper(rt > 0, 16);
          } else {
            if (rs_reg == rt_reg) {  // BLTZC
              BranchCompactHelper(rt < 0, 16);
            } else {  // BLTC/BGTC
              BranchCompactHelper(rs < rt, 16);
            }
          }
        }
      } else {  // BGTZL
        BranchAndLinkHelper(rs > 0);
      }
      break;
    case POP66:           // BEQZC, JIC
      if (rs_reg != 0) {  // BEQZC
        BranchCompactHelper(rs == 0, 21);
6622 6623 6624 6625
      } else {  // JIC
        next_pc = rt + imm16;
      }
      break;
6626 6627 6628 6629
    case POP76:           // BNEZC, JIALC
      if (rs_reg != 0) {  // BNEZC
        BranchCompactHelper(rs != 0, 21);
      } else {  // JIALC
6630
        set_register(31, get_pc() + kInstrSize);
6631 6632
        next_pc = rt + imm16;
      }
6633
      break;
6634 6635
    case BC:
      BranchCompactHelper(true, 26);
6636
      break;
6637 6638 6639 6640 6641 6642 6643 6644 6645 6646 6647 6648
    case BALC:
      BranchAndLinkCompactHelper(true, 26);
      break;
    case POP10:  // BOVC, BEQZALC, BEQC / ADDI (pre-r6)
      if (IsMipsArchVariant(kMips32r6)) {
        if (rs_reg >= rt_reg) {  // BOVC
          if (HaveSameSign(rs, rt)) {
            if (rs > 0) {
              BranchCompactHelper(rs > Registers::kMaxValue - rt, 16);
            } else if (rs < 0) {
              BranchCompactHelper(rs < Registers::kMinValue - rt, 16);
            }
6649
          }
6650 6651 6652 6653 6654
        } else {
          if (rs_reg == 0) {  // BEQZALC
            BranchAndLinkCompactHelper(rt == 0, 16);
          } else {  // BEQC
            BranchCompactHelper(rt == rs, 16);
6655
          }
6656
        }
6657 6658 6659 6660 6661 6662 6663 6664 6665 6666 6667 6668 6669
      } else {  // ADDI
        if (HaveSameSign(rs, se_imm16)) {
          if (rs > 0) {
            if (rs <= Registers::kMaxValue - se_imm16) {
              SignalException(kIntegerOverflow);
            }
          } else if (rs < 0) {
            if (rs >= Registers::kMinValue - se_imm16) {
              SignalException(kIntegerUnderflow);
            }
          }
        }
        SetResult(rt_reg, rs + se_imm16);
6670 6671
      }
      break;
6672 6673 6674 6675 6676 6677 6678 6679 6680 6681 6682 6683 6684 6685 6686 6687 6688 6689 6690 6691 6692 6693
    case POP30:  // BNVC, BNEZALC, BNEC / DADDI (pre-r6)
      if (IsMipsArchVariant(kMips32r6)) {
        if (rs_reg >= rt_reg) {  // BNVC
          if (!HaveSameSign(rs, rt) || rs == 0 || rt == 0) {
            BranchCompactHelper(true, 16);
          } else {
            if (rs > 0) {
              BranchCompactHelper(rs <= Registers::kMaxValue - rt, 16);
            } else if (rs < 0) {
              BranchCompactHelper(rs >= Registers::kMinValue - rt, 16);
            }
          }
        } else {
          if (rs_reg == 0) {  // BNEZALC
            BranchAndLinkCompactHelper(rt != 0, 16);
          } else {  // BNEC
            BranchCompactHelper(rt != rs, 16);
          }
        }
      }
      break;
    // ------------- Arithmetic instructions.
6694
    case ADDIU:
6695
      SetResult(rt_reg, rs + se_imm16);
6696 6697
      break;
    case SLTI:
6698
      SetResult(rt_reg, rs < se_imm16 ? 1 : 0);
6699 6700
      break;
    case SLTIU:
6701
      SetResult(rt_reg, rs_u < static_cast<uint32_t>(se_imm16) ? 1 : 0);
6702 6703
      break;
    case ANDI:
6704
      SetResult(rt_reg, rs & oe_imm16);
6705 6706
      break;
    case ORI:
6707
      SetResult(rt_reg, rs | oe_imm16);
6708 6709
      break;
    case XORI:
6710
      SetResult(rt_reg, rs ^ oe_imm16);
6711 6712
      break;
    case LUI:
6713 6714 6715 6716 6717 6718 6719 6720
      if (rs_reg != 0) {
        // AUI
        DCHECK(IsMipsArchVariant(kMips32r6));
        SetResult(rt_reg, rs + (se_imm16 << 16));
      } else {
        // LUI
        SetResult(rt_reg, oe_imm16 << 16);
      }
6721
      break;
6722
    // ------------- Memory instructions.
6723
    case LB:
6724
      set_register(rt_reg, ReadB(rs + se_imm16));
6725
      break;
6726
    case LH:
6727
      set_register(rt_reg, ReadH(rs + se_imm16, instr_.instr()));
6728 6729
      break;
    case LWL: {
6730
      // al_offset is offset of the effective address within an aligned word.
6731 6732 6733 6734
      uint8_t al_offset = (rs + se_imm16) & kPointerAlignmentMask;
      uint8_t byte_shift = kPointerAlignmentMask - al_offset;
      uint32_t mask = (1 << byte_shift * 8) - 1;
      addr = rs + se_imm16 - al_offset;
6735
      alu_out = ReadW(addr, instr_.instr());
6736 6737
      alu_out <<= byte_shift * 8;
      alu_out |= rt & mask;
6738
      set_register(rt_reg, alu_out);
6739 6740
      break;
    }
6741
    case LW:
6742
      set_register(rt_reg, ReadW(rs + se_imm16, instr_.instr()));
6743 6744
      break;
    case LBU:
6745
      set_register(rt_reg, ReadBU(rs + se_imm16));
6746
      break;
6747
    case LHU:
6748
      set_register(rt_reg, ReadHU(rs + se_imm16, instr_.instr()));
6749 6750
      break;
    case LWR: {
6751
      // al_offset is offset of the effective address within an aligned word.
6752 6753 6754 6755
      uint8_t al_offset = (rs + se_imm16) & kPointerAlignmentMask;
      uint8_t byte_shift = kPointerAlignmentMask - al_offset;
      uint32_t mask = al_offset ? (~0 << (byte_shift + 1) * 8) : 0;
      addr = rs + se_imm16 - al_offset;
6756
      alu_out = ReadW(addr, instr_.instr());
6757 6758
      alu_out = static_cast<uint32_t> (alu_out) >> al_offset * 8;
      alu_out |= rt & mask;
6759
      set_register(rt_reg, alu_out);
6760 6761
      break;
    }
6762
    case SB:
6763
      WriteB(rs + se_imm16, static_cast<int8_t>(rt));
6764
      break;
6765
    case SH:
6766
      WriteH(rs + se_imm16, static_cast<uint16_t>(rt), instr_.instr());
6767 6768 6769 6770 6771 6772
      break;
    case SWL: {
      uint8_t al_offset = (rs + se_imm16) & kPointerAlignmentMask;
      uint8_t byte_shift = kPointerAlignmentMask - al_offset;
      uint32_t mask = byte_shift ? (~0 << (al_offset + 1) * 8) : 0;
      addr = rs + se_imm16 - al_offset;
6773
      // Value to be written in memory.
6774
      uint32_t mem_value = ReadW(addr, instr_.instr()) & mask;
6775
      mem_value |= static_cast<uint32_t>(rt) >> byte_shift * 8;
6776
      WriteW(addr, mem_value, instr_.instr());
6777 6778
      break;
    }
6779
    case SW:
6780
      WriteW(rs + se_imm16, rt, instr_.instr());
6781
      break;
6782 6783 6784 6785
    case SWR: {
      uint8_t al_offset = (rs + se_imm16) & kPointerAlignmentMask;
      uint32_t mask = (1 << al_offset * 8) - 1;
      addr = rs + se_imm16 - al_offset;
6786
      uint32_t mem_value = ReadW(addr, instr_.instr());
6787
      mem_value = (rt << al_offset * 8) | (mem_value & mask);
6788
      WriteW(addr, mem_value, instr_.instr());
6789 6790
      break;
    }
6791 6792
    case LL: {
      DCHECK(!IsMipsArchVariant(kMips32r6));
6793
      base::MutexGuard lock_guard(&GlobalMonitor::Get()->mutex);
6794 6795 6796
      addr = rs + se_imm16;
      set_register(rt_reg, ReadW(addr, instr_.instr()));
      local_monitor_.NotifyLoadLinked(addr, TransactionSize::Word);
6797 6798
      GlobalMonitor::Get()->NotifyLoadLinked_Locked(addr,
                                                    &global_monitor_thread_);
6799 6800 6801 6802
      break;
    }
    case SC: {
      DCHECK(!IsMipsArchVariant(kMips32r6));
6803 6804
      addr = rs + se_imm16;
      WriteConditionalW(addr, rt, instr_.instr(), rt_reg);
6805 6806
      break;
    }
6807
    case LWC1:
6808
      set_fpu_register_hi_word(ft_reg, 0);
6809 6810 6811 6812 6813 6814 6815
      set_fpu_register_word(ft_reg,
                            ReadW(rs + se_imm16, instr_.instr(), FLOAT));
      if (ft_reg % 2) {
        TraceMemRd(rs + se_imm16, get_fpu_register(ft_reg - 1), FLOAT_DOUBLE);
      } else {
        TraceMemRd(rs + se_imm16, get_fpu_register_word(ft_reg), FLOAT);
      }
6816 6817
      break;
    case LDC1:
6818
      set_fpu_register_double(ft_reg, ReadD(rs + se_imm16, instr_.instr()));
6819
      TraceMemRd(rs + se_imm16, get_fpu_register(ft_reg), DOUBLE);
6820 6821
      break;
    case SWC1:
6822
      WriteW(rs + se_imm16, get_fpu_register_word(ft_reg), instr_.instr());
6823
      TraceMemWr(rs + se_imm16, get_fpu_register_word(ft_reg));
6824
      break;
6825
    case SDC1:
6826
      WriteD(rs + se_imm16, get_fpu_register_double(ft_reg), instr_.instr());
6827
      TraceMemWr(rs + se_imm16, get_fpu_register(ft_reg));
6828
      break;
6829 6830 6831
    // ------------- PC-Relative instructions.
    case PCREL: {
      // rt field: checking 5-bits.
6832
      int32_t imm21 = instr_.Imm21Value();
6833
      int32_t current_pc = get_pc();
6834 6835 6836 6837 6838 6839 6840 6841 6842 6843
      uint8_t rt = (imm21 >> kImm16Bits);
      switch (rt) {
        case ALUIPC:
          addr = current_pc + (se_imm16 << 16);
          alu_out = static_cast<int64_t>(~0x0FFFF) & addr;
          break;
        case AUIPC:
          alu_out = current_pc + (se_imm16 << 16);
          break;
        default: {
6844
          int32_t imm19 = instr_.Imm19Value();
6845 6846 6847 6848 6849
          // rt field: checking the most significant 2-bits.
          rt = (imm21 >> kImm19Bits);
          switch (rt) {
            case LWPC: {
              // Set sign.
6850 6851 6852
              imm19 <<= (kOpcodeBits + kRsBits + 2);
              imm19 >>= (kOpcodeBits + kRsBits + 2);
              addr = current_pc + (imm19 << 2);
6853 6854 6855 6856
              uint32_t* ptr = reinterpret_cast<uint32_t*>(addr);
              alu_out = *ptr;
              break;
            }
6857
            case ADDIUPC: {
6858
              int32_t se_imm19 = imm19 | ((imm19 & 0x40000) ? 0xFFF80000 : 0);
6859 6860
              alu_out = current_pc + (se_imm19 << 2);
              break;
6861
            }
6862 6863 6864 6865 6866 6867
            default:
              UNREACHABLE();
              break;
          }
        }
      }
6868
      SetResult(rs_reg, alu_out);
6869 6870
      break;
    }
6871 6872 6873 6874
    case SPECIAL3: {
      switch (instr_.FunctionFieldRaw()) {
        case LL_R6: {
          DCHECK(IsMipsArchVariant(kMips32r6));
6875
          base::MutexGuard lock_guard(&GlobalMonitor::Get()->mutex);
6876 6877
          int32_t base = get_register(instr_.BaseValue());
          int32_t offset9 = instr_.Imm9Value();
6878 6879
          addr = base + offset9;
          DCHECK_EQ(addr & kPointerAlignmentMask, 0);
6880
          set_register(rt_reg, ReadW(base + offset9, instr_.instr()));
6881
          local_monitor_.NotifyLoadLinked(addr, TransactionSize::Word);
6882
          GlobalMonitor::Get()->NotifyLoadLinked_Locked(
6883
              addr, &global_monitor_thread_);
6884 6885 6886 6887 6888 6889
          break;
        }
        case SC_R6: {
          DCHECK(IsMipsArchVariant(kMips32r6));
          int32_t base = get_register(instr_.BaseValue());
          int32_t offset9 = instr_.Imm9Value();
6890 6891 6892
          addr = base + offset9;
          DCHECK_EQ(addr & kPointerAlignmentMask, 0);
          WriteConditionalW(addr, rt, instr_.instr(), rt_reg);
6893 6894 6895 6896 6897 6898 6899
          break;
        }
        default:
          UNREACHABLE();
      }
      break;
    }
6900 6901 6902 6903 6904 6905 6906 6907 6908 6909 6910 6911 6912 6913 6914 6915 6916 6917 6918 6919 6920 6921 6922 6923 6924
    case MSA:
      switch (instr_.MSAMinorOpcodeField()) {
        case kMsaMinorI8:
          DecodeTypeMsaI8();
          break;
        case kMsaMinorI5:
          DecodeTypeMsaI5();
          break;
        case kMsaMinorI10:
          DecodeTypeMsaI10();
          break;
        case kMsaMinorELM:
          DecodeTypeMsaELM();
          break;
        case kMsaMinorBIT:
          DecodeTypeMsaBIT();
          break;
        case kMsaMinorMI10:
          DecodeTypeMsaMI10();
          break;
        default:
          UNREACHABLE();
          break;
      }
      break;
6925 6926
    default:
      UNREACHABLE();
6927
  }
6928 6929 6930 6931 6932 6933

  if (execute_branch_delay_instruction) {
    // Execute branch delay slot
    // We don't check for end_sim_pc. First it should not be met as the current
    // pc is valid. Secondly a jump should always execute its branch delay slot.
    Instruction* branch_delay_instr =
6934
        reinterpret_cast<Instruction*>(get_pc() + kInstrSize);
6935 6936 6937 6938 6939 6940 6941 6942 6943
    BranchDelayInstructionDecode(branch_delay_instr);
  }

  // If needed update pc after the branch delay execution.
  if (next_pc != bad_ra) {
    set_pc(next_pc);
  }
}

6944

6945
// Type 3: instructions using a 26 bytes immediate. (e.g. j, jal).
6946 6947
void Simulator::DecodeTypeJump() {
  SimInstruction simInstr = instr_;
6948 6949 6950
  // Get current pc.
  int32_t current_pc = get_pc();
  // Get unchanged bits of pc.
6951
  int32_t pc_high_bits = current_pc & 0xF0000000;
6952
  // Next pc.
6953 6954

  int32_t next_pc = pc_high_bits | (simInstr.Imm26Value() << 2);
6955

6956
  // Execute branch delay slot.
6957 6958 6959
  // We don't check for end_sim_pc. First it should not be met as the current pc
  // is valid. Secondly a jump should always execute its branch delay slot.
  Instruction* branch_delay_instr =
6960
      reinterpret_cast<Instruction*>(current_pc + kInstrSize);
6961 6962 6963 6964
  BranchDelayInstructionDecode(branch_delay_instr);

  // Update pc and ra if necessary.
  // Do this after the branch delay execution.
6965
  if (simInstr.IsLinkingInstruction()) {
6966
    set_register(31, current_pc + 2 * kInstrSize);
6967 6968 6969 6970 6971
  }
  set_pc(next_pc);
  pc_modified_ = true;
}

6972

6973 6974
// Executes the current instruction.
void Simulator::InstructionDecode(Instruction* instr) {
6975
  if (v8::internal::FLAG_check_icache) {
6976
    CheckICache(i_cache(), instr);
6977
  }
6978
  pc_modified_ = false;
6979
  v8::internal::EmbeddedVector<char, 256> buffer;
6980
  if (::v8::internal::FLAG_trace_sim) {
6981
    SNPrintF(trace_buf_, "%s", "");
6982 6983
    disasm::NameConverter converter;
    disasm::Disassembler dasm(converter);
6984
    dasm.InstructionDecode(buffer, reinterpret_cast<byte*>(instr));
6985 6986
  }

6987 6988
  instr_ = instr;
  switch (instr_.InstructionType()) {
6989
    case Instruction::kRegisterType:
6990
      DecodeTypeRegister();
6991 6992
      break;
    case Instruction::kImmediateType:
6993
      DecodeTypeImmediate();
6994 6995
      break;
    case Instruction::kJumpType:
6996
      DecodeTypeJump();
6997 6998 6999 7000
      break;
    default:
      UNSUPPORTED();
  }
7001
  if (::v8::internal::FLAG_trace_sim) {
7002
    PrintF("  0x%08" PRIxPTR "  %-44s   %s\n",
7003 7004
           reinterpret_cast<intptr_t>(instr), buffer.begin(),
           trace_buf_.begin());
7005
  }
7006
  if (!pc_modified_) {
7007
    set_register(pc, reinterpret_cast<int32_t>(instr) + kInstrSize);
7008 7009 7010 7011 7012 7013 7014 7015 7016 7017 7018 7019 7020 7021 7022 7023 7024 7025
  }
}

void Simulator::Execute() {
  // Get the PC to simulate. Cannot use the accessor here as we need the
  // raw PC value and not the one used as input to arithmetic instructions.
  int program_counter = get_pc();
  if (::v8::internal::FLAG_stop_sim_at == 0) {
    // Fast version of the dispatch loop without checking whether the simulator
    // should be stopping at a particular executed instruction.
    while (program_counter != end_sim_pc) {
      Instruction* instr = reinterpret_cast<Instruction*>(program_counter);
      icount_++;
      InstructionDecode(instr);
      program_counter = get_pc();
    }
  } else {
    // FLAG_stop_sim_at is at the non-default value. Stop in the debugger when
7026
    // we reach the particular instruction count.
7027 7028 7029
    while (program_counter != end_sim_pc) {
      Instruction* instr = reinterpret_cast<Instruction*>(program_counter);
      icount_++;
7030
      if (icount_ == static_cast<uint64_t>(::v8::internal::FLAG_stop_sim_at)) {
7031
        MipsDebugger dbg(this);
7032 7033 7034 7035 7036 7037 7038 7039 7040
        dbg.Debug();
      } else {
        InstructionDecode(instr);
      }
      program_counter = get_pc();
    }
  }
}

7041
void Simulator::CallInternal(Address entry) {
7042 7043 7044
  // Adjust JS-based stack limit to C-based stack limit.
  isolate_->stack_guard()->AdjustStackLimitForSimulator();

7045
  // Prepare to execute the code at entry.
7046
  set_register(pc, static_cast<int32_t>(entry));
7047 7048 7049 7050 7051 7052 7053 7054 7055 7056 7057 7058 7059 7060 7061 7062 7063 7064 7065 7066
  // Put down marker for end of simulation. The simulator will stop simulation
  // when the PC reaches this value. By saving the "end simulation" value into
  // the LR the simulation stops when returning to this call point.
  set_register(ra, end_sim_pc);

  // Remember the values of callee-saved registers.
  // The code below assumes that r9 is not used as sb (static base) in
  // simulator code and therefore is regarded as a callee-saved register.
  int32_t s0_val = get_register(s0);
  int32_t s1_val = get_register(s1);
  int32_t s2_val = get_register(s2);
  int32_t s3_val = get_register(s3);
  int32_t s4_val = get_register(s4);
  int32_t s5_val = get_register(s5);
  int32_t s6_val = get_register(s6);
  int32_t s7_val = get_register(s7);
  int32_t gp_val = get_register(gp);
  int32_t sp_val = get_register(sp);
  int32_t fp_val = get_register(fp);

7067
  // Set up the callee-saved registers with a known value. To be able to check
7068
  // that they are preserved properly across JS execution.
7069
  int32_t callee_saved_value = static_cast<int32_t>(icount_);
7070 7071 7072 7073 7074 7075 7076 7077 7078 7079 7080
  set_register(s0, callee_saved_value);
  set_register(s1, callee_saved_value);
  set_register(s2, callee_saved_value);
  set_register(s3, callee_saved_value);
  set_register(s4, callee_saved_value);
  set_register(s5, callee_saved_value);
  set_register(s6, callee_saved_value);
  set_register(s7, callee_saved_value);
  set_register(gp, callee_saved_value);
  set_register(fp, callee_saved_value);

7081
  // Start the simulation.
7082 7083 7084 7085 7086 7087 7088 7089 7090 7091 7092 7093 7094 7095 7096 7097 7098 7099 7100 7101 7102 7103 7104 7105 7106 7107
  Execute();

  // Check that the callee-saved registers have been preserved.
  CHECK_EQ(callee_saved_value, get_register(s0));
  CHECK_EQ(callee_saved_value, get_register(s1));
  CHECK_EQ(callee_saved_value, get_register(s2));
  CHECK_EQ(callee_saved_value, get_register(s3));
  CHECK_EQ(callee_saved_value, get_register(s4));
  CHECK_EQ(callee_saved_value, get_register(s5));
  CHECK_EQ(callee_saved_value, get_register(s6));
  CHECK_EQ(callee_saved_value, get_register(s7));
  CHECK_EQ(callee_saved_value, get_register(gp));
  CHECK_EQ(callee_saved_value, get_register(fp));

  // Restore callee-saved registers with the original value.
  set_register(s0, s0_val);
  set_register(s1, s1_val);
  set_register(s2, s2_val);
  set_register(s3, s3_val);
  set_register(s4, s4_val);
  set_register(s5, s5_val);
  set_register(s6, s6_val);
  set_register(s7, s7_val);
  set_register(gp, gp_val);
  set_register(sp, sp_val);
  set_register(fp, fp_val);
7108 7109
}

7110
intptr_t Simulator::CallImpl(Address entry, int argument_count,
7111
                             const intptr_t* arguments) {
7112 7113 7114
  // Set up arguments.

  // First four arguments passed in registers.
7115 7116 7117 7118 7119
  int reg_arg_count = std::min(4, argument_count);
  if (reg_arg_count > 0) set_register(a0, arguments[0]);
  if (reg_arg_count > 1) set_register(a1, arguments[1]);
  if (reg_arg_count > 2) set_register(a2, arguments[2]);
  if (reg_arg_count > 3) set_register(a3, arguments[3]);
7120 7121 7122 7123 7124 7125

  // Remaining arguments passed on stack.
  int original_stack = get_register(sp);
  // Compute position of stack on entry to generated code.
  int entry_stack = (original_stack - (argument_count - 4) * sizeof(int32_t)
                                    - kCArgsSlotsSize);
7126 7127
  if (base::OS::ActivationFrameAlignment() != 0) {
    entry_stack &= -base::OS::ActivationFrameAlignment();
7128 7129 7130
  }
  // Store remaining arguments on stack, from low to high memory.
  intptr_t* stack_argument = reinterpret_cast<intptr_t*>(entry_stack);
7131 7132
  memcpy(stack_argument + kCArgSlotCount, arguments + reg_arg_count,
         (argument_count - reg_arg_count) * sizeof(*arguments));
7133 7134 7135
  set_register(sp, entry_stack);

  CallInternal(entry);
7136 7137 7138 7139 7140

  // Pop stack passed arguments.
  CHECK_EQ(entry_stack, get_register(sp));
  set_register(sp, original_stack);

7141
  return get_register(v0);
7142 7143
}

7144
double Simulator::CallFP(Address entry, double d0, double d1) {
7145 7146 7147 7148 7149
  if (!IsMipsSoftFloatABI) {
    set_fpu_register_double(f12, d0);
    set_fpu_register_double(f14, d1);
  } else {
    int buffer[2];
7150
    DCHECK(sizeof(buffer[0]) * 2 == sizeof(d0));
7151
    memcpy(buffer, &d0, sizeof(d0));
7152
    set_dw_register(a0, buffer);
7153
    memcpy(buffer, &d1, sizeof(d1));
7154 7155 7156 7157 7158 7159 7160 7161 7162 7163 7164
    set_dw_register(a2, buffer);
  }
  CallInternal(entry);
  if (!IsMipsSoftFloatABI) {
    return get_fpu_register_double(f0);
  } else {
    return get_double_from_register_pair(v0);
  }
}


7165 7166 7167 7168 7169 7170 7171 7172 7173 7174 7175 7176 7177 7178 7179 7180 7181
uintptr_t Simulator::PushAddress(uintptr_t address) {
  int new_sp = get_register(sp) - sizeof(uintptr_t);
  uintptr_t* stack_slot = reinterpret_cast<uintptr_t*>(new_sp);
  *stack_slot = address;
  set_register(sp, new_sp);
  return new_sp;
}


uintptr_t Simulator::PopAddress() {
  int current_sp = get_register(sp);
  uintptr_t* stack_slot = reinterpret_cast<uintptr_t*>(current_sp);
  uintptr_t address = *stack_slot;
  set_register(sp, current_sp + sizeof(uintptr_t));
  return address;
}

7182 7183 7184 7185 7186 7187 7188 7189 7190 7191 7192 7193 7194 7195 7196 7197 7198 7199 7200 7201 7202 7203 7204 7205 7206 7207 7208 7209 7210 7211 7212 7213 7214 7215 7216 7217 7218 7219 7220 7221 7222 7223 7224 7225 7226 7227 7228 7229 7230 7231 7232 7233 7234 7235 7236 7237 7238 7239 7240 7241 7242 7243 7244 7245 7246 7247 7248 7249 7250 7251 7252 7253 7254 7255 7256 7257 7258 7259 7260 7261 7262 7263 7264 7265 7266 7267 7268 7269 7270 7271 7272 7273 7274 7275 7276 7277 7278 7279 7280 7281 7282 7283 7284 7285 7286 7287 7288 7289 7290 7291 7292 7293 7294 7295 7296 7297 7298 7299 7300 7301 7302 7303 7304 7305 7306 7307 7308 7309 7310 7311 7312 7313 7314 7315 7316 7317 7318 7319 7320 7321 7322 7323 7324 7325 7326 7327 7328 7329 7330 7331 7332 7333 7334 7335 7336 7337 7338 7339 7340 7341 7342 7343 7344 7345 7346 7347 7348 7349 7350 7351 7352
Simulator::LocalMonitor::LocalMonitor()
    : access_state_(MonitorAccess::Open),
      tagged_addr_(0),
      size_(TransactionSize::None) {}

void Simulator::LocalMonitor::Clear() {
  access_state_ = MonitorAccess::Open;
  tagged_addr_ = 0;
  size_ = TransactionSize::None;
}

void Simulator::LocalMonitor::NotifyLoad() {
  if (access_state_ == MonitorAccess::RMW) {
    // A non linked load could clear the local monitor. As a result, it's
    // most strict to unconditionally clear the local monitor on load.
    Clear();
  }
}

void Simulator::LocalMonitor::NotifyLoadLinked(uintptr_t addr,
                                               TransactionSize size) {
  access_state_ = MonitorAccess::RMW;
  tagged_addr_ = addr;
  size_ = size;
}

void Simulator::LocalMonitor::NotifyStore() {
  if (access_state_ == MonitorAccess::RMW) {
    // A non exclusive store could clear the local monitor. As a result, it's
    // most strict to unconditionally clear the local monitor on store.
    Clear();
  }
}

bool Simulator::LocalMonitor::NotifyStoreConditional(uintptr_t addr,
                                                     TransactionSize size) {
  if (access_state_ == MonitorAccess::RMW) {
    if (addr == tagged_addr_ && size_ == size) {
      Clear();
      return true;
    } else {
      return false;
    }
  } else {
    DCHECK(access_state_ == MonitorAccess::Open);
    return false;
  }
}

Simulator::GlobalMonitor::LinkedAddress::LinkedAddress()
    : access_state_(MonitorAccess::Open),
      tagged_addr_(0),
      next_(nullptr),
      prev_(nullptr),
      failure_counter_(0) {}

void Simulator::GlobalMonitor::LinkedAddress::Clear_Locked() {
  access_state_ = MonitorAccess::Open;
  tagged_addr_ = 0;
}

void Simulator::GlobalMonitor::LinkedAddress::NotifyLoadLinked_Locked(
    uintptr_t addr) {
  access_state_ = MonitorAccess::RMW;
  tagged_addr_ = addr;
}

void Simulator::GlobalMonitor::LinkedAddress::NotifyStore_Locked() {
  if (access_state_ == MonitorAccess::RMW) {
    // A non exclusive store could clear the global monitor. As a result, it's
    // most strict to unconditionally clear global monitors on store.
    Clear_Locked();
  }
}

bool Simulator::GlobalMonitor::LinkedAddress::NotifyStoreConditional_Locked(
    uintptr_t addr, bool is_requesting_processor) {
  if (access_state_ == MonitorAccess::RMW) {
    if (is_requesting_processor) {
      if (addr == tagged_addr_) {
        Clear_Locked();
        // Introduce occasional sc/scd failures. This is to simulate the
        // behavior of hardware, which can randomly fail due to background
        // cache evictions.
        if (failure_counter_++ >= kMaxFailureCounter) {
          failure_counter_ = 0;
          return false;
        } else {
          return true;
        }
      }
    } else if ((addr & kExclusiveTaggedAddrMask) ==
               (tagged_addr_ & kExclusiveTaggedAddrMask)) {
      // Check the masked addresses when responding to a successful lock by
      // another thread so the implementation is more conservative (i.e. the
      // granularity of locking is as large as possible.)
      Clear_Locked();
      return false;
    }
  }
  return false;
}

void Simulator::GlobalMonitor::NotifyLoadLinked_Locked(
    uintptr_t addr, LinkedAddress* linked_address) {
  linked_address->NotifyLoadLinked_Locked(addr);
  PrependProcessor_Locked(linked_address);
}

void Simulator::GlobalMonitor::NotifyStore_Locked(
    LinkedAddress* linked_address) {
  // Notify each thread of the store operation.
  for (LinkedAddress* iter = head_; iter; iter = iter->next_) {
    iter->NotifyStore_Locked();
  }
}

bool Simulator::GlobalMonitor::NotifyStoreConditional_Locked(
    uintptr_t addr, LinkedAddress* linked_address) {
  DCHECK(IsProcessorInLinkedList_Locked(linked_address));
  if (linked_address->NotifyStoreConditional_Locked(addr, true)) {
    // Notify the other processors that this StoreConditional succeeded.
    for (LinkedAddress* iter = head_; iter; iter = iter->next_) {
      if (iter != linked_address) {
        iter->NotifyStoreConditional_Locked(addr, false);
      }
    }
    return true;
  } else {
    return false;
  }
}

bool Simulator::GlobalMonitor::IsProcessorInLinkedList_Locked(
    LinkedAddress* linked_address) const {
  return head_ == linked_address || linked_address->next_ ||
         linked_address->prev_;
}

void Simulator::GlobalMonitor::PrependProcessor_Locked(
    LinkedAddress* linked_address) {
  if (IsProcessorInLinkedList_Locked(linked_address)) {
    return;
  }

  if (head_) {
    head_->prev_ = linked_address;
  }
  linked_address->prev_ = nullptr;
  linked_address->next_ = head_;
  head_ = linked_address;
}

void Simulator::GlobalMonitor::RemoveLinkedAddress(
    LinkedAddress* linked_address) {
  base::MutexGuard lock_guard(&mutex);
  if (!IsProcessorInLinkedList_Locked(linked_address)) {
    return;
  }

  if (linked_address->prev_) {
    linked_address->prev_->next_ = linked_address->next_;
  } else {
    head_ = linked_address->next_;
  }
  if (linked_address->next_) {
    linked_address->next_->prev_ = linked_address->prev_;
  }
  linked_address->prev_ = nullptr;
  linked_address->next_ = nullptr;
}
7353 7354 7355

#undef UNSUPPORTED

7356 7357
}  // namespace internal
}  // namespace v8
7358

7359
#endif  // USE_SIMULATOR