simulator-arm64.cc 177 KB
Newer Older
1
// Copyright 2013 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

#include <stdlib.h>
#include <cmath>
#include <cstdarg>
8
#include <type_traits>
9

10
#if V8_TARGET_ARCH_ARM64
11

12 13
#include "src/arm64/decoder-arm64-inl.h"
#include "src/arm64/simulator-arm64.h"
14
#include "src/assembler-inl.h"
15
#include "src/codegen.h"
16
#include "src/disasm.h"
17
#include "src/macro-assembler.h"
18
#include "src/objects-inl.h"
19
#include "src/ostreams.h"
20
#include "src/runtime/runtime-utils.h"
21 22 23 24 25 26 27 28 29 30 31 32 33 34

namespace v8 {
namespace internal {

#if defined(USE_SIMULATOR)


// This macro provides a platform independent use of sscanf. The reason for
// SScanF not being implemented in a platform independent way 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


35
// Helpers for colors.
36 37 38 39 40 41 42 43 44 45 46
#define COLOUR(colour_code)       "\033[0;" colour_code "m"
#define COLOUR_BOLD(colour_code)  "\033[1;" colour_code "m"
#define NORMAL  ""
#define GREY    "30"
#define RED     "31"
#define GREEN   "32"
#define YELLOW  "33"
#define BLUE    "34"
#define MAGENTA "35"
#define CYAN    "36"
#define WHITE   "37"
47

48 49
typedef char const * const TEXT_COLOUR;
TEXT_COLOUR clr_normal         = FLAG_log_colour ? COLOUR(NORMAL)       : "";
50 51 52 53
TEXT_COLOUR clr_flag_name      = FLAG_log_colour ? COLOUR_BOLD(WHITE)   : "";
TEXT_COLOUR clr_flag_value     = FLAG_log_colour ? COLOUR(NORMAL)       : "";
TEXT_COLOUR clr_reg_name       = FLAG_log_colour ? COLOUR_BOLD(CYAN)    : "";
TEXT_COLOUR clr_reg_value      = FLAG_log_colour ? COLOUR(CYAN)         : "";
54 55
TEXT_COLOUR clr_vreg_name = FLAG_log_colour ? COLOUR_BOLD(MAGENTA) : "";
TEXT_COLOUR clr_vreg_value = FLAG_log_colour ? COLOUR(MAGENTA) : "";
56 57 58
TEXT_COLOUR clr_memory_address = FLAG_log_colour ? COLOUR_BOLD(BLUE)    : "";
TEXT_COLOUR clr_debug_number   = FLAG_log_colour ? COLOUR_BOLD(YELLOW)  : "";
TEXT_COLOUR clr_debug_message  = FLAG_log_colour ? COLOUR(YELLOW)       : "";
59 60
TEXT_COLOUR clr_printf         = FLAG_log_colour ? COLOUR(GREEN)        : "";

61 62 63
// static
base::LazyInstance<Simulator::GlobalMonitor>::type Simulator::global_monitor_ =
    LAZY_INSTANCE_INITIALIZER;
64

65
// This is basically the same as PrintF, with a guard for FLAG_trace_sim.
66
void Simulator::TraceSim(const char* format, ...) {
67 68 69
  if (FLAG_trace_sim) {
    va_list arguments;
    va_start(arguments, format);
70
    base::OS::VFPrint(stream_, format, arguments);
71 72 73 74
    va_end(arguments);
  }
}

75
const Instruction* Simulator::kEndOfSimAddress = nullptr;
76 77 78

void SimSystemRegister::SetBits(int msb, int lsb, uint32_t bits) {
  int width = msb - lsb + 1;
79
  DCHECK(is_uintn(bits, width) || is_intn(bits, width));
80 81 82

  bits <<= lsb;
  uint32_t mask = ((1 << width) - 1) << lsb;
83
  DCHECK_EQ(mask & write_ignore_mask_, 0);
84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104

  value_ = (value_ & ~mask) | (bits & mask);
}


SimSystemRegister SimSystemRegister::DefaultValueFor(SystemRegister id) {
  switch (id) {
    case NZCV:
      return SimSystemRegister(0x00000000, NZCVWriteIgnoreMask);
    case FPCR:
      return SimSystemRegister(0x00000000, FPCRWriteIgnoreMask);
    default:
      UNREACHABLE();
  }
}


// Get the active Simulator for the current thread.
Simulator* Simulator::current(Isolate* isolate) {
  Isolate::PerIsolateThreadData* isolate_data =
      isolate->FindOrAllocatePerThreadDataForThisThread();
105
  DCHECK_NOT_NULL(isolate_data);
106 107

  Simulator* sim = isolate_data->simulator();
108
  if (sim == nullptr) {
109 110 111 112 113 114
    if (FLAG_trace_sim || FLAG_log_instruction_stats || FLAG_debug_sim) {
      sim = new Simulator(new Decoder<DispatchingDecoderVisitor>(), isolate);
    } else {
      sim = new Decoder<Simulator>();
      sim->isolate_ = isolate;
    }
115 116 117 118 119
    isolate_data->set_simulator(sim);
  }
  return sim;
}

120
void Simulator::CallImpl(Address entry, CallArgument* args) {
121 122 123 124
  int index_x = 0;
  int index_d = 0;

  std::vector<int64_t> stack_args(0);
125 126
  for (int i = 0; !args[i].IsEnd(); i++) {
    CallArgument arg = args[i];
127 128 129 130 131
    if (arg.IsX() && (index_x < 8)) {
      set_xreg(index_x++, arg.bits());
    } else if (arg.IsD() && (index_d < 8)) {
      set_dreg_bits(index_d++, arg.bits());
    } else {
132
      DCHECK(arg.IsD() || arg.IsX());
133 134 135 136 137 138 139 140
      stack_args.push_back(arg.bits());
    }
  }

  // Process stack arguments, and make sure the stack is suitably aligned.
  uintptr_t original_stack = sp();
  uintptr_t entry_stack = original_stack -
                          stack_args.size() * sizeof(stack_args[0]);
141 142
  if (base::OS::ActivationFrameAlignment() != 0) {
    entry_stack &= -base::OS::ActivationFrameAlignment();
143 144 145 146 147 148 149 150
  }
  char * stack = reinterpret_cast<char*>(entry_stack);
  std::vector<int64_t>::const_iterator it;
  for (it = stack_args.begin(); it != stack_args.end(); it++) {
    memcpy(stack, &(*it), sizeof(*it));
    stack += sizeof(*it);
  }

151
  DCHECK(reinterpret_cast<uintptr_t>(stack) <= original_stack);
152 153 154 155 156 157 158 159 160 161 162
  set_sp(entry_stack);

  // Call the generated code.
  set_pc(entry);
  set_lr(kEndOfSimAddress);
  CheckPCSComplianceAndRun();

  set_sp(original_stack);
}

void Simulator::CheckPCSComplianceAndRun() {
163 164 165
  // Adjust JS-based stack limit to C-based stack limit.
  isolate_->stack_guard()->AdjustStackLimitForSimulator();

166
#ifdef DEBUG
167 168
  DCHECK_EQ(kNumberOfCalleeSavedRegisters, kCalleeSaved.Count());
  DCHECK_EQ(kNumberOfCalleeSavedVRegisters, kCalleeSavedV.Count());
169 170

  int64_t saved_registers[kNumberOfCalleeSavedRegisters];
171
  uint64_t saved_fpregisters[kNumberOfCalleeSavedVRegisters];
172 173

  CPURegList register_list = kCalleeSaved;
174
  CPURegList fpregister_list = kCalleeSavedV;
175 176 177 178 179 180

  for (int i = 0; i < kNumberOfCalleeSavedRegisters; i++) {
    // x31 is not a caller saved register, so no need to specify if we want
    // the stack or zero.
    saved_registers[i] = xreg(register_list.PopLowestIndex().code());
  }
181
  for (int i = 0; i < kNumberOfCalleeSavedVRegisters; i++) {
182 183 184 185 186 187 188 189
    saved_fpregisters[i] =
        dreg_bits(fpregister_list.PopLowestIndex().code());
  }
  int64_t original_stack = sp();
#endif
  // Start the simulation!
  Run();
#ifdef DEBUG
190
  DCHECK_EQ(original_stack, sp());
191 192
  // Check that callee-saved registers have been preserved.
  register_list = kCalleeSaved;
193
  fpregister_list = kCalleeSavedV;
194
  for (int i = 0; i < kNumberOfCalleeSavedRegisters; i++) {
195
    DCHECK_EQ(saved_registers[i], xreg(register_list.PopLowestIndex().code()));
196
  }
197
  for (int i = 0; i < kNumberOfCalleeSavedVRegisters; i++) {
198
    DCHECK(saved_fpregisters[i] ==
199 200 201 202 203 204 205 206 207 208 209 210 211
           dreg_bits(fpregister_list.PopLowestIndex().code()));
  }

  // Corrupt caller saved register minus the return regiters.

  // In theory x0 to x7 can be used for return values, but V8 only uses x0, x1
  // for now .
  register_list = kCallerSaved;
  register_list.Remove(x0);
  register_list.Remove(x1);

  // In theory d0 to d7 can be used for return values, but V8 only uses d0
  // for now .
212
  fpregister_list = kCallerSavedV;
213 214 215
  fpregister_list.Remove(d0);

  CorruptRegisters(&register_list, kCallerSavedRegisterCorruptionValue);
216
  CorruptRegisters(&fpregister_list, kCallerSavedVRegisterCorruptionValue);
217 218 219 220 221 222 223 224 225 226 227 228 229 230
#endif
}


#ifdef DEBUG
// The least significant byte of the curruption value holds the corresponding
// register's code.
void Simulator::CorruptRegisters(CPURegList* list, uint64_t value) {
  if (list->type() == CPURegister::kRegister) {
    while (!list->IsEmpty()) {
      unsigned code = list->PopLowestIndex().code();
      set_xreg(code, value | code);
    }
  } else {
231
    DCHECK_EQ(list->type(), CPURegister::kVRegister);
232 233 234 235 236 237 238 239 240 241 242
    while (!list->IsEmpty()) {
      unsigned code = list->PopLowestIndex().code();
      set_dreg_bits(code, value | code);
    }
  }
}


void Simulator::CorruptAllCallerSavedCPURegisters() {
  // Corrupt alters its parameter so copy them first.
  CPURegList register_list = kCallerSaved;
243
  CPURegList fpregister_list = kCallerSavedV;
244 245

  CorruptRegisters(&register_list, kCallerSavedRegisterCorruptionValue);
246
  CorruptRegisters(&fpregister_list, kCallerSavedVRegisterCorruptionValue);
247 248 249 250 251 252
}
#endif


// Extending the stack by 2 * 64 bits is required for stack alignment purposes.
uintptr_t Simulator::PushAddress(uintptr_t address) {
253
  DCHECK(sizeof(uintptr_t) < 2 * kXRegSize);
254
  intptr_t new_sp = sp() - 2 * kXRegSize;
255 256 257
  uintptr_t* alignment_slot =
    reinterpret_cast<uintptr_t*>(new_sp + kXRegSize);
  memcpy(alignment_slot, &kSlotsZapValue, kPointerSize);
258
  uintptr_t* stack_slot = reinterpret_cast<uintptr_t*>(new_sp);
259
  memcpy(stack_slot, &address, kPointerSize);
260 261 262 263 264 265 266 267 268
  set_sp(new_sp);
  return new_sp;
}


uintptr_t Simulator::PopAddress() {
  intptr_t current_sp = sp();
  uintptr_t* stack_slot = reinterpret_cast<uintptr_t*>(current_sp);
  uintptr_t address = *stack_slot;
269
  DCHECK_LT(sizeof(uintptr_t), 2 * kXRegSize);
270
  set_sp(current_sp + 2 * kXRegSize);
271 272 273 274 275
  return address;
}


// Returns the limit of the stack area to enable checking for stack overflows.
276 277 278 279 280 281 282 283 284
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.
285
  return stack_limit_ + 1024;
286 287
}

288 289 290 291 292
void Simulator::SetRedirectInstruction(Instruction* instruction) {
  instruction->SetInstructionBits(
      HLT | Assembler::ImmException(kImmExceptionIsRedirectedCall));
}

293 294 295
Simulator::Simulator(Decoder<DispatchingDecoderVisitor>* decoder,
                     Isolate* isolate, FILE* stream)
    : decoder_(decoder),
296
      last_debugger_input_(nullptr),
297
      log_parameters_(NO_PARAM),
298 299 300 301
      isolate_(isolate) {
  // Setup the decoder.
  decoder_->AppendVisitor(this);

302 303 304 305 306 307 308 309 310 311 312 313 314 315 316
  Init(stream);

  if (FLAG_trace_sim) {
    decoder_->InsertVisitorBefore(print_disasm_, this);
    log_parameters_ = LOG_ALL;
  }

  if (FLAG_log_instruction_stats) {
    instrument_ = new Instrument(FLAG_log_instruction_file,
                                 FLAG_log_instruction_period);
    decoder_->AppendVisitor(instrument_);
  }
}

Simulator::Simulator()
317 318
    : decoder_(nullptr),
      last_debugger_input_(nullptr),
319
      log_parameters_(NO_PARAM),
320
      isolate_(nullptr) {
321
  Init(stdout);
322 323 324 325 326
  CHECK(!FLAG_trace_sim && !FLAG_log_instruction_stats);
}


void Simulator::Init(FILE* stream) {
327 328 329 330
  ResetState();

  // Allocate and setup the simulator stack.
  stack_size_ = (FLAG_sim_stack_size * KB) + (2 * stack_protection_size_);
331
  stack_ = reinterpret_cast<uintptr_t>(new byte[stack_size_]);
332
  stack_limit_ = stack_ + stack_protection_size_;
333 334
  uintptr_t tos = stack_ + stack_size_ - stack_protection_size_;
  // The stack pointer must be 16-byte aligned.
335
  set_sp(tos & ~0xFUL);
336 337 338 339 340 341

  stream_ = stream;
  print_disasm_ = new PrintDisassembler(stream_);

  // The debugger needs to disassemble code without the simulator executing an
  // instruction, so we create a dedicated decoder.
342
  disassembler_decoder_ = new Decoder<DispatchingDecoderVisitor>();
343 344 345 346 347 348 349 350 351 352
  disassembler_decoder_->AppendVisitor(print_disasm_);
}


void Simulator::ResetState() {
  // Reset the system registers.
  nzcv_ = SimSystemRegister::DefaultValueFor(NZCV);
  fpcr_ = SimSystemRegister::DefaultValueFor(FPCR);

  // Reset registers to 0.
353
  pc_ = nullptr;
354
  for (unsigned i = 0; i < kNumberOfRegisters; i++) {
355
    set_xreg(i, 0xBADBEEF);
356
  }
357
  for (unsigned i = 0; i < kNumberOfVRegisters; i++) {
358
    // Set FP registers to a value that is NaN in both 32-bit and 64-bit FP.
359
    set_dreg_bits(i, 0x7FF000007F800001UL);
360 361 362 363 364 365
  }
  // Returning to address 0 exits the Simulator.
  set_lr(kEndOfSimAddress);

  // Reset debug helpers.
  breakpoints_.empty();
Benedikt Meurer's avatar
Benedikt Meurer committed
366
  break_on_next_ = false;
367 368 369 370
}


Simulator::~Simulator() {
371
  global_monitor_.Pointer()->RemoveProcessor(&global_monitor_processor_);
372
  delete[] reinterpret_cast<byte*>(stack_);
373 374 375 376 377 378
  if (FLAG_log_instruction_stats) {
    delete instrument_;
  }
  delete disassembler_decoder_;
  delete print_disasm_;
  DeleteArray(last_debugger_input_);
379
  delete decoder_;
380 381 382 383
}


void Simulator::Run() {
384 385 386 387
  // Flush any written registers before executing anything, so that
  // manually-set registers are logged _before_ the first instruction.
  LogAllWrittenRegisters();

388 389 390 391 392 393 394 395 396 397 398 399 400
  pc_modified_ = false;
  while (pc_ != kEndOfSimAddress) {
    ExecuteInstruction();
  }
}


void Simulator::RunFrom(Instruction* start) {
  set_pc(start);
  Run();
}


401 402 403 404 405
// 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 structure.
// The simulator assumes all runtime calls return two 64-bits values. If they
// don't, register x1 is clobbered. This is fine because x1 is caller-saved.
406 407 408 409 410
typedef ObjectPair (*SimulatorRuntimeCall)(int64_t arg0, int64_t arg1,
                                           int64_t arg2, int64_t arg3,
                                           int64_t arg4, int64_t arg5,
                                           int64_t arg6, int64_t arg7,
                                           int64_t arg8);
411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427

typedef int64_t (*SimulatorRuntimeCompareCall)(double arg1, double arg2);
typedef double (*SimulatorRuntimeFPFPCall)(double arg1, double arg2);
typedef double (*SimulatorRuntimeFPCall)(double arg1);
typedef double (*SimulatorRuntimeFPIntCall)(double arg1, int32_t arg2);

// This signature supports direct call in to API function native callback
// (refer to InvocationCallback in v8.h).
typedef void (*SimulatorRuntimeDirectApiCall)(int64_t arg0);
typedef void (*SimulatorRuntimeProfilingApiCall)(int64_t arg0, void* arg1);

// This signature supports direct call to accessor getter callback.
typedef void (*SimulatorRuntimeDirectGetterCall)(int64_t arg0, int64_t arg1);
typedef void (*SimulatorRuntimeProfilingGetterCall)(int64_t arg0, int64_t arg1,
                                                    void* arg2);

void Simulator::DoRuntimeCall(Instruction* instr) {
428
  Redirection* redirection = Redirection::FromInstruction(instr);
429 430 431 432 433 434

  // The called C code might itself call simulated code, so any
  // caller-saved registers (including lr) could still be clobbered by a
  // redirected call.
  Instruction* return_address = lr();

435 436
  int64_t external =
      reinterpret_cast<int64_t>(redirection->external_function());
437

438
  TraceSim("Call to host function at %p\n", redirection->external_function());
439 440

  // SP must be 16-byte-aligned at the call interface.
441
  bool stack_alignment_exception = ((sp() & 0xF) != 0);
442 443 444 445 446
  if (stack_alignment_exception) {
    TraceSim("  with unaligned stack 0x%016" PRIx64 ".\n", sp());
    FATAL("ALIGNMENT EXCEPTION");
  }

447 448 449 450 451 452 453 454 455 456 457 458 459
  int64_t* stack_pointer = reinterpret_cast<int64_t*>(sp());

  const int64_t arg0 = xreg(0);
  const int64_t arg1 = xreg(1);
  const int64_t arg2 = xreg(2);
  const int64_t arg3 = xreg(3);
  const int64_t arg4 = xreg(4);
  const int64_t arg5 = xreg(5);
  const int64_t arg6 = xreg(6);
  const int64_t arg7 = xreg(7);
  const int64_t arg8 = stack_pointer[0];
  STATIC_ASSERT(kMaxCParameters == 9);

460 461 462 463 464 465
  switch (redirection->type()) {
    default:
      TraceSim("Type: Unknown.\n");
      UNREACHABLE();
      break;

mbrandy's avatar
mbrandy committed
466 467
    case ExternalReference::BUILTIN_CALL:
    case ExternalReference::BUILTIN_CALL_PAIR: {
468 469
      // Object* f(v8::internal::Arguments) or
      // ObjectPair f(v8::internal::Arguments).
470 471 472 473 474 475 476
      TraceSim("Type: BUILTIN_CALL\n");
      SimulatorRuntimeCall target =
        reinterpret_cast<SimulatorRuntimeCall>(external);

      // We don't know how many arguments are being passed, but we can
      // pass 8 without touching the stack. They will be ignored by the
      // host function if they aren't used.
477 478 479 480 481 482 483 484 485 486 487 488 489 490
      TraceSim(
          "Arguments: "
          "0x%016" PRIx64 ", 0x%016" PRIx64
          ", "
          "0x%016" PRIx64 ", 0x%016" PRIx64
          ", "
          "0x%016" PRIx64 ", 0x%016" PRIx64
          ", "
          "0x%016" PRIx64 ", 0x%016" PRIx64
          ", "
          "0x%016" PRIx64,
          arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8);
      ObjectPair result =
          target(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8);
491 492
      TraceSim("Returned: {%p, %p}\n", static_cast<void*>(result.x),
               static_cast<void*>(result.y));
493 494 495 496 497 498 499 500
#ifdef DEBUG
      CorruptAllCallerSavedCPURegisters();
#endif
      set_xreg(0, reinterpret_cast<int64_t>(result.x));
      set_xreg(1, reinterpret_cast<int64_t>(result.y));
      break;
    }

501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606
    case ExternalReference::DIRECT_API_CALL: {
      // void f(v8::FunctionCallbackInfo&)
      TraceSim("Type: DIRECT_API_CALL\n");
      SimulatorRuntimeDirectApiCall target =
        reinterpret_cast<SimulatorRuntimeDirectApiCall>(external);
      TraceSim("Arguments: 0x%016" PRIx64 "\n", xreg(0));
      target(xreg(0));
      TraceSim("No return value.");
#ifdef DEBUG
      CorruptAllCallerSavedCPURegisters();
#endif
      break;
    }

    case ExternalReference::BUILTIN_COMPARE_CALL: {
      // int f(double, double)
      TraceSim("Type: BUILTIN_COMPARE_CALL\n");
      SimulatorRuntimeCompareCall target =
        reinterpret_cast<SimulatorRuntimeCompareCall>(external);
      TraceSim("Arguments: %f, %f\n", dreg(0), dreg(1));
      int64_t result = target(dreg(0), dreg(1));
      TraceSim("Returned: %" PRId64 "\n", result);
#ifdef DEBUG
      CorruptAllCallerSavedCPURegisters();
#endif
      set_xreg(0, result);
      break;
    }

    case ExternalReference::BUILTIN_FP_CALL: {
      // double f(double)
      TraceSim("Type: BUILTIN_FP_CALL\n");
      SimulatorRuntimeFPCall target =
        reinterpret_cast<SimulatorRuntimeFPCall>(external);
      TraceSim("Argument: %f\n", dreg(0));
      double result = target(dreg(0));
      TraceSim("Returned: %f\n", result);
#ifdef DEBUG
      CorruptAllCallerSavedCPURegisters();
#endif
      set_dreg(0, result);
      break;
    }

    case ExternalReference::BUILTIN_FP_FP_CALL: {
      // double f(double, double)
      TraceSim("Type: BUILTIN_FP_FP_CALL\n");
      SimulatorRuntimeFPFPCall target =
        reinterpret_cast<SimulatorRuntimeFPFPCall>(external);
      TraceSim("Arguments: %f, %f\n", dreg(0), dreg(1));
      double result = target(dreg(0), dreg(1));
      TraceSim("Returned: %f\n", result);
#ifdef DEBUG
      CorruptAllCallerSavedCPURegisters();
#endif
      set_dreg(0, result);
      break;
    }

    case ExternalReference::BUILTIN_FP_INT_CALL: {
      // double f(double, int)
      TraceSim("Type: BUILTIN_FP_INT_CALL\n");
      SimulatorRuntimeFPIntCall target =
        reinterpret_cast<SimulatorRuntimeFPIntCall>(external);
      TraceSim("Arguments: %f, %d\n", dreg(0), wreg(0));
      double result = target(dreg(0), wreg(0));
      TraceSim("Returned: %f\n", result);
#ifdef DEBUG
      CorruptAllCallerSavedCPURegisters();
#endif
      set_dreg(0, result);
      break;
    }

    case ExternalReference::DIRECT_GETTER_CALL: {
      // void f(Local<String> property, PropertyCallbackInfo& info)
      TraceSim("Type: DIRECT_GETTER_CALL\n");
      SimulatorRuntimeDirectGetterCall target =
        reinterpret_cast<SimulatorRuntimeDirectGetterCall>(external);
      TraceSim("Arguments: 0x%016" PRIx64 ", 0x%016" PRIx64 "\n",
               xreg(0), xreg(1));
      target(xreg(0), xreg(1));
      TraceSim("No return value.");
#ifdef DEBUG
      CorruptAllCallerSavedCPURegisters();
#endif
      break;
    }

    case ExternalReference::PROFILING_API_CALL: {
      // void f(v8::FunctionCallbackInfo&, v8::FunctionCallback)
      TraceSim("Type: PROFILING_API_CALL\n");
      SimulatorRuntimeProfilingApiCall target =
        reinterpret_cast<SimulatorRuntimeProfilingApiCall>(external);
      void* arg1 = Redirection::ReverseRedirection(xreg(1));
      TraceSim("Arguments: 0x%016" PRIx64 ", %p\n", xreg(0), arg1);
      target(xreg(0), arg1);
      TraceSim("No return value.");
#ifdef DEBUG
      CorruptAllCallerSavedCPURegisters();
#endif
      break;
    }

    case ExternalReference::PROFILING_GETTER_CALL: {
      // void f(Local<String> property, PropertyCallbackInfo& info,
607
      //        AccessorNameGetterCallback callback)
608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627
      TraceSim("Type: PROFILING_GETTER_CALL\n");
      SimulatorRuntimeProfilingGetterCall target =
        reinterpret_cast<SimulatorRuntimeProfilingGetterCall>(
            external);
      void* arg2 = Redirection::ReverseRedirection(xreg(2));
      TraceSim("Arguments: 0x%016" PRIx64 ", 0x%016" PRIx64 ", %p\n",
               xreg(0), xreg(1), arg2);
      target(xreg(0), xreg(1), arg2);
      TraceSim("No return value.");
#ifdef DEBUG
      CorruptAllCallerSavedCPURegisters();
#endif
      break;
    }
  }

  set_lr(return_address);
  set_pc(return_address);
}

628
const char* Simulator::xreg_names[] = {
629 630 631
    "x0",  "x1",  "x2",  "x3",  "x4",  "x5",  "x6",  "x7",  "x8",  "x9",  "x10",
    "x11", "x12", "x13", "x14", "x15", "ip0", "ip1", "x18", "x19", "x20", "x21",
    "x22", "x23", "x24", "x25", "x26", "cp",  "x28", "fp",  "lr",  "xzr", "sp"};
632 633

const char* Simulator::wreg_names[] = {
634 635 636
    "w0",  "w1",  "w2",  "w3",  "w4",  "w5",  "w6",  "w7",  "w8",
    "w9",  "w10", "w11", "w12", "w13", "w14", "w15", "w16", "w17",
    "w18", "w19", "w20", "w21", "w22", "w23", "w24", "w25", "w26",
637
    "wcp", "w28", "wfp", "wlr", "wzr", "wsp"};
638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658

const char* Simulator::sreg_names[] = {
"s0",  "s1",  "s2",  "s3",  "s4",  "s5",  "s6",  "s7",
"s8",  "s9",  "s10", "s11", "s12", "s13", "s14", "s15",
"s16", "s17", "s18", "s19", "s20", "s21", "s22", "s23",
"s24", "s25", "s26", "s27", "s28", "s29", "s30", "s31"};

const char* Simulator::dreg_names[] = {
"d0",  "d1",  "d2",  "d3",  "d4",  "d5",  "d6",  "d7",
"d8",  "d9",  "d10", "d11", "d12", "d13", "d14", "d15",
"d16", "d17", "d18", "d19", "d20", "d21", "d22", "d23",
"d24", "d25", "d26", "d27", "d28", "d29", "d30", "d31"};

const char* Simulator::vreg_names[] = {
"v0",  "v1",  "v2",  "v3",  "v4",  "v5",  "v6",  "v7",
"v8",  "v9",  "v10", "v11", "v12", "v13", "v14", "v15",
"v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23",
"v24", "v25", "v26", "v27", "v28", "v29", "v30", "v31"};


const char* Simulator::WRegNameForCode(unsigned code, Reg31Mode mode) {
659 660 661
  static_assert(arraysize(Simulator::wreg_names) == (kNumberOfRegisters + 1),
                "Array must be large enough to hold all register names.");
  DCHECK_LT(code, static_cast<unsigned>(kNumberOfRegisters));
662 663 664 665
  // The modulo operator has no effect here, but it silences a broken GCC
  // warning about out-of-bounds array accesses.
  code %= kNumberOfRegisters;

666 667 668 669
  // If the code represents the stack pointer, index the name after zr.
  if ((code == kZeroRegCode) && (mode == Reg31IsStackPointer)) {
    code = kZeroRegCode + 1;
  }
670
  return wreg_names[code];
671 672 673 674
}


const char* Simulator::XRegNameForCode(unsigned code, Reg31Mode mode) {
675 676 677
  static_assert(arraysize(Simulator::xreg_names) == (kNumberOfRegisters + 1),
                "Array must be large enough to hold all register names.");
  DCHECK_LT(code, static_cast<unsigned>(kNumberOfRegisters));
678 679
  code %= kNumberOfRegisters;

680 681 682 683
  // If the code represents the stack pointer, index the name after zr.
  if ((code == kZeroRegCode) && (mode == Reg31IsStackPointer)) {
    code = kZeroRegCode + 1;
  }
684
  return xreg_names[code];
685 686 687 688
}


const char* Simulator::SRegNameForCode(unsigned code) {
689 690 691 692
  static_assert(arraysize(Simulator::sreg_names) == kNumberOfVRegisters,
                "Array must be large enough to hold all register names.");
  DCHECK_LT(code, static_cast<unsigned>(kNumberOfVRegisters));
  return sreg_names[code % kNumberOfVRegisters];
693 694 695 696
}


const char* Simulator::DRegNameForCode(unsigned code) {
697 698 699 700
  static_assert(arraysize(Simulator::dreg_names) == kNumberOfVRegisters,
                "Array must be large enough to hold all register names.");
  DCHECK_LT(code, static_cast<unsigned>(kNumberOfVRegisters));
  return dreg_names[code % kNumberOfVRegisters];
701 702 703 704
}


const char* Simulator::VRegNameForCode(unsigned code) {
705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752
  static_assert(arraysize(Simulator::vreg_names) == kNumberOfVRegisters,
                "Array must be large enough to hold all register names.");
  DCHECK_LT(code, static_cast<unsigned>(kNumberOfVRegisters));
  return vreg_names[code % kNumberOfVRegisters];
}

void LogicVRegister::ReadUintFromMem(VectorFormat vform, int index,
                                     uint64_t addr) const {
  switch (LaneSizeInBitsFromFormat(vform)) {
    case 8:
      register_.Insert(index, SimMemory::Read<uint8_t>(addr));
      break;
    case 16:
      register_.Insert(index, SimMemory::Read<uint16_t>(addr));
      break;
    case 32:
      register_.Insert(index, SimMemory::Read<uint32_t>(addr));
      break;
    case 64:
      register_.Insert(index, SimMemory::Read<uint64_t>(addr));
      break;
    default:
      UNREACHABLE();
      return;
  }
}

void LogicVRegister::WriteUintToMem(VectorFormat vform, int index,
                                    uint64_t addr) const {
  switch (LaneSizeInBitsFromFormat(vform)) {
    case 8:
      SimMemory::Write<uint8_t>(addr, static_cast<uint8_t>(Uint(vform, index)));
      break;
    case 16:
      SimMemory::Write<uint16_t>(addr,
                                 static_cast<uint16_t>(Uint(vform, index)));
      break;
    case 32:
      SimMemory::Write<uint32_t>(addr,
                                 static_cast<uint32_t>(Uint(vform, index)));
      break;
    case 64:
      SimMemory::Write<uint64_t>(addr, Uint(vform, index));
      break;
    default:
      UNREACHABLE();
      return;
  }
753 754 755 756 757 758 759 760 761 762
}


int Simulator::CodeFromName(const char* name) {
  for (unsigned i = 0; i < kNumberOfRegisters; i++) {
    if ((strcmp(xreg_names[i], name) == 0) ||
        (strcmp(wreg_names[i], name) == 0)) {
      return i;
    }
  }
763
  for (unsigned i = 0; i < kNumberOfVRegisters; i++) {
764 765 766 767 768 769
    if ((strcmp(vreg_names[i], name) == 0) ||
        (strcmp(dreg_names[i], name) == 0) ||
        (strcmp(sreg_names[i], name) == 0)) {
      return i;
    }
  }
770
  if ((strcmp("sp", name) == 0) || (strcmp("wsp", name) == 0)) {
771 772 773 774 775 776 777
    return kSPRegInternalCode;
  }
  return -1;
}


// Helpers ---------------------------------------------------------------------
778
template <typename T>
779 780 781 782 783
T Simulator::AddWithCarry(bool set_flags, T left, T right, int carry_in) {
  // Use unsigned types to avoid implementation-defined overflow behaviour.
  static_assert(std::is_unsigned<T>::value, "operands must be unsigned");
  static_assert((sizeof(T) == kWRegSize) || (sizeof(T) == kXRegSize),
                "Only W- or X-sized operands are tested");
784

785 786
  DCHECK((carry_in == 0) || (carry_in == 1));
  T result = left + right + carry_in;
787

788 789 790
  if (set_flags) {
    nzcv().SetN(CalcNFlag(result));
    nzcv().SetZ(CalcZFlag(result));
791

792 793 794
    // Compute the C flag by comparing the result to the max unsigned integer.
    T max_uint_2op = std::numeric_limits<T>::max() - carry_in;
    nzcv().SetC((left > max_uint_2op) || ((max_uint_2op - left) < right));
795

796 797 798 799 800 801 802
    // Overflow iff the sign bit is the same for the two inputs and different
    // for the result.
    T sign_mask = T(1) << (sizeof(T) * 8 - 1);
    T left_sign = left & sign_mask;
    T right_sign = right & sign_mask;
    T result_sign = result & sign_mask;
    nzcv().SetV((left_sign == right_sign) && (left_sign != result_sign));
803

804
    LogSystemRegister(NZCV);
805 806 807 808 809
  }
  return result;
}


810 811
template<typename T>
void Simulator::AddSubWithCarry(Instruction* instr) {
812 813 814
  // Use unsigned types to avoid implementation-defined overflow behaviour.
  static_assert(std::is_unsigned<T>::value, "operands must be unsigned");

815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831
  T op2 = reg<T>(instr->Rm());
  T new_val;

  if ((instr->Mask(AddSubOpMask) == SUB) || instr->Mask(AddSubOpMask) == SUBS) {
    op2 = ~op2;
  }

  new_val = AddWithCarry<T>(instr->FlagsUpdate(),
                            reg<T>(instr->Rn()),
                            op2,
                            nzcv().C());

  set_reg<T>(instr->Rd(), new_val);
}

template <typename T>
T Simulator::ShiftOperand(T value, Shift shift_type, unsigned amount) {
832
  typedef typename std::make_unsigned<T>::type unsignedT;
833

834 835 836
  if (amount == 0) {
    return value;
  }
837

838 839
  switch (shift_type) {
    case LSL:
840
      return value << amount;
841
    case LSR:
842 843 844
      return static_cast<unsignedT>(value) >> amount;
    case ASR:
      return value >> amount;
845 846
    case ROR: {
      unsignedT mask = (static_cast<unsignedT>(1) << amount) - 1;
847
      return (static_cast<unsignedT>(value) >> amount) |
848 849
             ((value & mask) << (sizeof(mask) * 8 - amount));
    }
850 851 852 853 854 855 856
    default:
      UNIMPLEMENTED();
      return 0;
  }
}


857 858 859 860 861 862
template <typename T>
T Simulator::ExtendValue(T value, Extend extend_type, unsigned left_shift) {
  const unsigned kSignExtendBShift = (sizeof(T) - 1) * 8;
  const unsigned kSignExtendHShift = (sizeof(T) - 2) * 8;
  const unsigned kSignExtendWShift = (sizeof(T) - 4) * 8;

863 864 865 866 867 868 869 870 871 872 873
  switch (extend_type) {
    case UXTB:
      value &= kByteMask;
      break;
    case UXTH:
      value &= kHalfWordMask;
      break;
    case UXTW:
      value &= kWordMask;
      break;
    case SXTB:
874
      value = (value << kSignExtendBShift) >> kSignExtendBShift;
875 876
      break;
    case SXTH:
877
      value = (value << kSignExtendHShift) >> kSignExtendHShift;
878 879
      break;
    case SXTW:
880
      value = (value << kSignExtendWShift) >> kSignExtendWShift;
881 882 883 884 885 886 887
      break;
    case UXTX:
    case SXTX:
      break;
    default:
      UNREACHABLE();
  }
888 889 890 891 892 893 894 895 896 897 898 899 900 901 902
  return value << left_shift;
}


template <typename T>
void Simulator::Extract(Instruction* instr) {
  unsigned lsb = instr->ImmS();
  T op2 = reg<T>(instr->Rm());
  T result = op2;

  if (lsb) {
    T op1 = reg<T>(instr->Rn());
    result = op2 >> lsb | (op1 << ((sizeof(T) * 8) - lsb));
  }
  set_reg<T>(instr->Rd(), result);
903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921
}


void Simulator::FPCompare(double val0, double val1) {
  AssertSupportedFPCR();

  // TODO(jbramley): This assumes that the C++ implementation handles
  // comparisons in the way that we expect (as per AssertSupportedFPCR()).
  if ((std::isnan(val0) != 0) || (std::isnan(val1) != 0)) {
    nzcv().SetRawValue(FPUnorderedFlag);
  } else if (val0 < val1) {
    nzcv().SetRawValue(FPLessThanFlag);
  } else if (val0 > val1) {
    nzcv().SetRawValue(FPGreaterThanFlag);
  } else if (val0 == val1) {
    nzcv().SetRawValue(FPEqualFlag);
  } else {
    UNREACHABLE();
  }
922
  LogSystemRegister(NZCV);
923 924
}

925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026
Simulator::PrintRegisterFormat Simulator::GetPrintRegisterFormatForSize(
    size_t reg_size, size_t lane_size) {
  DCHECK_GE(reg_size, lane_size);

  uint32_t format = 0;
  if (reg_size != lane_size) {
    switch (reg_size) {
      default:
        UNREACHABLE();
      case kQRegSize:
        format = kPrintRegAsQVector;
        break;
      case kDRegSize:
        format = kPrintRegAsDVector;
        break;
    }
  }

  switch (lane_size) {
    default:
      UNREACHABLE();
    case kQRegSize:
      format |= kPrintReg1Q;
      break;
    case kDRegSize:
      format |= kPrintReg1D;
      break;
    case kSRegSize:
      format |= kPrintReg1S;
      break;
    case kHRegSize:
      format |= kPrintReg1H;
      break;
    case kBRegSize:
      format |= kPrintReg1B;
      break;
  }

  // These sizes would be duplicate case labels.
  static_assert(kXRegSize == kDRegSize, "X and D registers must be same size.");
  static_assert(kWRegSize == kSRegSize, "W and S registers must be same size.");
  static_assert(kPrintXReg == kPrintReg1D,
                "X and D register printing code is shared.");
  static_assert(kPrintWReg == kPrintReg1S,
                "W and S register printing code is shared.");

  return static_cast<PrintRegisterFormat>(format);
}

Simulator::PrintRegisterFormat Simulator::GetPrintRegisterFormat(
    VectorFormat vform) {
  switch (vform) {
    default:
      UNREACHABLE();
    case kFormat16B:
      return kPrintReg16B;
    case kFormat8B:
      return kPrintReg8B;
    case kFormat8H:
      return kPrintReg8H;
    case kFormat4H:
      return kPrintReg4H;
    case kFormat4S:
      return kPrintReg4S;
    case kFormat2S:
      return kPrintReg2S;
    case kFormat2D:
      return kPrintReg2D;
    case kFormat1D:
      return kPrintReg1D;

    case kFormatB:
      return kPrintReg1B;
    case kFormatH:
      return kPrintReg1H;
    case kFormatS:
      return kPrintReg1S;
    case kFormatD:
      return kPrintReg1D;
  }
}

Simulator::PrintRegisterFormat Simulator::GetPrintRegisterFormatFP(
    VectorFormat vform) {
  switch (vform) {
    default:
      UNREACHABLE();
    case kFormat4S:
      return kPrintReg4SFP;
    case kFormat2S:
      return kPrintReg2SFP;
    case kFormat2D:
      return kPrintReg2DFP;
    case kFormat1D:
      return kPrintReg1DFP;

    case kFormatS:
      return kPrintReg1SFP;
    case kFormatD:
      return kPrintReg1DFP;
  }
}
1027 1028 1029 1030

void Simulator::SetBreakpoint(Instruction* location) {
  for (unsigned i = 0; i < breakpoints_.size(); i++) {
    if (breakpoints_.at(i).location == location) {
1031 1032
      PrintF(stream_,
             "Existing breakpoint at %p was %s\n",
1033 1034 1035 1036 1037 1038 1039 1040
             reinterpret_cast<void*>(location),
             breakpoints_.at(i).enabled ? "disabled" : "enabled");
      breakpoints_.at(i).enabled = !breakpoints_.at(i).enabled;
      return;
    }
  }
  Breakpoint new_breakpoint = {location, true};
  breakpoints_.push_back(new_breakpoint);
1041 1042
  PrintF(stream_,
         "Set a breakpoint at %p\n", reinterpret_cast<void*>(location));
1043 1044 1045 1046
}


void Simulator::ListBreakpoints() {
1047
  PrintF(stream_, "Breakpoints:\n");
1048
  for (unsigned i = 0; i < breakpoints_.size(); i++) {
1049
    PrintF(stream_, "%p  : %s\n",
1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066
           reinterpret_cast<void*>(breakpoints_.at(i).location),
           breakpoints_.at(i).enabled ? "enabled" : "disabled");
  }
}


void Simulator::CheckBreakpoints() {
  bool hit_a_breakpoint = false;
  for (unsigned i = 0; i < breakpoints_.size(); i++) {
    if ((breakpoints_.at(i).location == pc_) &&
        breakpoints_.at(i).enabled) {
      hit_a_breakpoint = true;
      // Disable this breakpoint.
      breakpoints_.at(i).enabled = false;
    }
  }
  if (hit_a_breakpoint) {
1067
    PrintF(stream_, "Hit and disabled a breakpoint at %p.\n",
1068 1069 1070 1071 1072 1073 1074 1075 1076
           reinterpret_cast<void*>(pc_));
    Debug();
  }
}


void Simulator::CheckBreakNext() {
  // If the current instruction is a BL, insert a breakpoint just after it.
  if (break_on_next_ && pc_->IsBranchAndLinkToRegister()) {
1077
    SetBreakpoint(pc_->following());
1078 1079 1080 1081 1082 1083
    break_on_next_ = false;
  }
}


void Simulator::PrintInstructionsAt(Instruction* start, uint64_t count) {
1084
  Instruction* end = start->InstructionAtOffset(count * kInstrSize);
1085
  for (Instruction* pc = start; pc < end; pc = pc->following()) {
1086 1087 1088 1089
    disassembler_decoder_->Decode(pc);
  }
}

1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101
void Simulator::PrintWrittenRegisters() {
  for (unsigned i = 0; i < kNumberOfRegisters; i++) {
    if (registers_[i].WrittenSinceLastLog()) PrintRegister(i);
  }
}

void Simulator::PrintWrittenVRegisters() {
  for (unsigned i = 0; i < kNumberOfVRegisters; i++) {
    // At this point there is no type information, so print as a raw 1Q.
    if (vregisters_[i].WrittenSinceLastLog()) PrintVRegister(i, kPrintReg1Q);
  }
}
1102

1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113
void Simulator::PrintSystemRegisters() {
  PrintSystemRegister(NZCV);
  PrintSystemRegister(FPCR);
}


void Simulator::PrintRegisters() {
  for (unsigned i = 0; i < kNumberOfRegisters; i++) {
    PrintRegister(i);
  }
}
1114

1115 1116 1117 1118
void Simulator::PrintVRegisters() {
  for (unsigned i = 0; i < kNumberOfVRegisters; i++) {
    // At this point there is no type information, so print as a raw 1Q.
    PrintVRegister(i, kPrintReg1Q);
1119
  }
1120 1121
}

1122

1123
void Simulator::PrintRegister(unsigned code, Reg31Mode r31mode) {
1124 1125
  registers_[code].NotifyRegisterLogged();

1126 1127 1128
  // Don't print writes into xzr.
  if ((code == kZeroRegCode) && (r31mode == Reg31IsZeroRegister)) {
    return;
1129 1130
  }

1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148
  // The template for all x and w registers:
  //   "# x{code}: 0x{value}"
  //   "# w{code}: 0x{value}"

  PrintRegisterRawHelper(code, r31mode);
  fprintf(stream_, "\n");
}

// Print a register's name and raw value.
//
// The `bytes` and `lsb` arguments can be used to limit the bytes that are
// printed. These arguments are intended for use in cases where register hasn't
// actually been updated (such as in PrintVWrite).
//
// No newline is printed. This allows the caller to print more details (such as
// a floating-point interpretation or a memory access annotation).
void Simulator::PrintVRegisterRawHelper(unsigned code, int bytes, int lsb) {
  // The template for vector types:
1149
  //   "# v{code}: 0xFFEEDDCCBBAA99887766554433221100".
1150
  // An example with bytes=4 and lsb=8:
1151
  //   "# v{code}:         0xBBAA9988                ".
1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 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 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230
  fprintf(stream_, "# %s%5s: %s", clr_vreg_name, VRegNameForCode(code),
          clr_vreg_value);

  int msb = lsb + bytes - 1;
  int byte = kQRegSize - 1;

  // Print leading padding spaces. (Two spaces per byte.)
  while (byte > msb) {
    fprintf(stream_, "  ");
    byte--;
  }

  // Print the specified part of the value, byte by byte.
  qreg_t rawbits = qreg(code);
  fprintf(stream_, "0x");
  while (byte >= lsb) {
    fprintf(stream_, "%02x", rawbits.val[byte]);
    byte--;
  }

  // Print trailing padding spaces.
  while (byte >= 0) {
    fprintf(stream_, "  ");
    byte--;
  }
  fprintf(stream_, "%s", clr_normal);
}

// Print each of the specified lanes of a register as a float or double value.
//
// The `lane_count` and `lslane` arguments can be used to limit the lanes that
// are printed. These arguments are intended for use in cases where register
// hasn't actually been updated (such as in PrintVWrite).
//
// No newline is printed. This allows the caller to print more details (such as
// a memory access annotation).
void Simulator::PrintVRegisterFPHelper(unsigned code,
                                       unsigned lane_size_in_bytes,
                                       int lane_count, int rightmost_lane) {
  DCHECK((lane_size_in_bytes == kSRegSize) ||
         (lane_size_in_bytes == kDRegSize));

  unsigned msb = (lane_count + rightmost_lane) * lane_size_in_bytes;
  DCHECK_LE(msb, static_cast<unsigned>(kQRegSize));

  // For scalar types ((lane_count == 1) && (rightmost_lane == 0)), a register
  // name is used:
  //   " (s{code}: {value})"
  //   " (d{code}: {value})"
  // For vector types, "..." is used to represent one or more omitted lanes.
  //   " (..., {value}, {value}, ...)"
  if ((lane_count == 1) && (rightmost_lane == 0)) {
    const char* name = (lane_size_in_bytes == kSRegSize)
                           ? SRegNameForCode(code)
                           : DRegNameForCode(code);
    fprintf(stream_, " (%s%s: ", clr_vreg_name, name);
  } else {
    if (msb < (kQRegSize - 1)) {
      fprintf(stream_, " (..., ");
    } else {
      fprintf(stream_, " (");
    }
  }

  // Print the list of values.
  const char* separator = "";
  int leftmost_lane = rightmost_lane + lane_count - 1;
  for (int lane = leftmost_lane; lane >= rightmost_lane; lane--) {
    double value = (lane_size_in_bytes == kSRegSize)
                       ? vreg(code).Get<float>(lane)
                       : vreg(code).Get<double>(lane);
    fprintf(stream_, "%s%s%#g%s", separator, clr_vreg_value, value, clr_normal);
    separator = ", ";
  }

  if (rightmost_lane > 0) {
    fprintf(stream_, ", ...");
  }
  fprintf(stream_, ")");
1231 1232
}

1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247
// Print a register's name and raw value.
//
// Only the least-significant `size_in_bytes` bytes of the register are printed,
// but the value is aligned as if the whole register had been printed.
//
// For typical register updates, size_in_bytes should be set to kXRegSize
// -- the default -- so that the whole register is printed. Other values of
// size_in_bytes are intended for use when the register hasn't actually been
// updated (such as in PrintWrite).
//
// No newline is printed. This allows the caller to print more details (such as
// a memory access annotation).
void Simulator::PrintRegisterRawHelper(unsigned code, Reg31Mode r31mode,
                                       int size_in_bytes) {
  // The template for all supported sizes.
1248 1249
  //   "# x{code}: 0xFFEEDDCCBBAA9988"
  //   "# w{code}:         0xBBAA9988"
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 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288
  //   "# w{code}<15:0>:       0x9988"
  //   "# w{code}<7:0>:          0x88"
  unsigned padding_chars = (kXRegSize - size_in_bytes) * 2;

  const char* name = "";
  const char* suffix = "";
  switch (size_in_bytes) {
    case kXRegSize:
      name = XRegNameForCode(code, r31mode);
      break;
    case kWRegSize:
      name = WRegNameForCode(code, r31mode);
      break;
    case 2:
      name = WRegNameForCode(code, r31mode);
      suffix = "<15:0>";
      padding_chars -= strlen(suffix);
      break;
    case 1:
      name = WRegNameForCode(code, r31mode);
      suffix = "<7:0>";
      padding_chars -= strlen(suffix);
      break;
    default:
      UNREACHABLE();
  }
  fprintf(stream_, "# %s%5s%s: ", clr_reg_name, name, suffix);

  // Print leading padding spaces.
  DCHECK_LT(padding_chars, kXRegSize * 2U);
  for (unsigned i = 0; i < padding_chars; i++) {
    putc(' ', stream_);
  }

  // Print the specified bits in hexadecimal format.
  uint64_t bits = reg<uint64_t>(code, r31mode);
  bits &= kXRegMask >> ((kXRegSize - size_in_bytes) * 8);
  static_assert(sizeof(bits) == kXRegSize,
                "X registers and uint64_t must be the same size.");
1289

1290 1291 1292 1293
  int chars = size_in_bytes * 2;
  fprintf(stream_, "%s0x%0*" PRIx64 "%s", clr_reg_value, chars, bits,
          clr_normal);
}
1294

1295 1296
void Simulator::PrintVRegister(unsigned code, PrintRegisterFormat format) {
  vregisters_[code].NotifyRegisterLogged();
1297

1298
  int lane_size_log2 = format & kPrintRegLaneSizeMask;
1299

1300 1301 1302 1303 1304 1305 1306 1307
  int reg_size_log2;
  if (format & kPrintRegAsQVector) {
    reg_size_log2 = kQRegSizeLog2;
  } else if (format & kPrintRegAsDVector) {
    reg_size_log2 = kDRegSizeLog2;
  } else {
    // Scalar types.
    reg_size_log2 = lane_size_log2;
1308 1309
  }

1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322
  int lane_count = 1 << (reg_size_log2 - lane_size_log2);
  int lane_size = 1 << lane_size_log2;

  // The template for vector types:
  //   "# v{code}: 0x{rawbits} (..., {value}, ...)".
  // The template for scalar types:
  //   "# v{code}: 0x{rawbits} ({reg}:{value})".
  // The values in parentheses after the bit representations are floating-point
  // interpretations. They are displayed only if the kPrintVRegAsFP bit is set.

  PrintVRegisterRawHelper(code);
  if (format & kPrintRegAsFP) {
    PrintVRegisterFPHelper(code, lane_size, lane_count);
1323 1324
  }

1325
  fprintf(stream_, "\n");
1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344
}


void Simulator::PrintSystemRegister(SystemRegister id) {
  switch (id) {
    case NZCV:
      fprintf(stream_, "# %sNZCV: %sN:%d Z:%d C:%d V:%d%s\n",
              clr_flag_name, clr_flag_value,
              nzcv().N(), nzcv().Z(), nzcv().C(), nzcv().V(),
              clr_normal);
      break;
    case FPCR: {
      static const char * rmode[] = {
        "0b00 (Round to Nearest)",
        "0b01 (Round towards Plus Infinity)",
        "0b10 (Round towards Minus Infinity)",
        "0b11 (Round towards Zero)"
      };
      DCHECK(fpcr().RMode() < arraysize(rmode));
1345
      fprintf(stream_,
1346 1347 1348
              "# %sFPCR: %sAHP:%d DN:%d FZ:%d RMode:%s%s\n",
              clr_flag_name, clr_flag_value,
              fpcr().AHP(), fpcr().DN(), fpcr().FZ(), rmode[fpcr().RMode()],
1349
              clr_normal);
1350
      break;
1351
    }
1352 1353
    default:
      UNREACHABLE();
1354 1355 1356
  }
}

1357 1358 1359
void Simulator::PrintRead(uintptr_t address, unsigned reg_code,
                          PrintRegisterFormat format) {
  registers_[reg_code].NotifyRegisterLogged();
1360

1361
  USE(format);
1362

1363 1364
  // The template is "# {reg}: 0x{value} <- {address}".
  PrintRegisterRawHelper(reg_code, Reg31IsZeroRegister);
1365 1366 1367 1368
  fprintf(stream_, " <- %s0x%016" PRIxPTR "%s\n",
          clr_memory_address, address, clr_normal);
}

1369 1370 1371
void Simulator::PrintVRead(uintptr_t address, unsigned reg_code,
                           PrintRegisterFormat format, unsigned lane) {
  vregisters_[reg_code].NotifyRegisterLogged();
1372

1373 1374 1375 1376 1377
  // The template is "# v{code}: 0x{rawbits} <- address".
  PrintVRegisterRawHelper(reg_code);
  if (format & kPrintRegAsFP) {
    PrintVRegisterFPHelper(reg_code, GetPrintRegLaneSizeInBytes(format),
                           GetPrintRegLaneCount(format), lane);
1378
  }
1379 1380
  fprintf(stream_, " <- %s0x%016" PRIxPTR "%s\n",
          clr_memory_address, address, clr_normal);
1381 1382
}

1383 1384 1385
void Simulator::PrintWrite(uintptr_t address, unsigned reg_code,
                           PrintRegisterFormat format) {
  DCHECK_EQ(GetPrintRegLaneCount(format), 1U);
1386

1387 1388 1389 1390
  // The template is "# v{code}: 0x{value} -> {address}". To keep the trace tidy
  // and readable, the value is aligned with the values in the register trace.
  PrintRegisterRawHelper(reg_code, Reg31IsZeroRegister,
                         GetPrintRegSizeInBytes(format));
1391 1392
  fprintf(stream_, " -> %s0x%016" PRIxPTR "%s\n",
          clr_memory_address, address, clr_normal);
1393 1394
}

1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410
void Simulator::PrintVWrite(uintptr_t address, unsigned reg_code,
                            PrintRegisterFormat format, unsigned lane) {
  // The templates:
  //   "# v{code}: 0x{rawbits} -> {address}"
  //   "# v{code}: 0x{rawbits} (..., {value}, ...) -> {address}".
  //   "# v{code}: 0x{rawbits} ({reg}:{value}) -> {address}"
  // Because this trace doesn't represent a change to the source register's
  // value, only the relevant part of the value is printed. To keep the trace
  // tidy and readable, the raw value is aligned with the other values in the
  // register trace.
  int lane_count = GetPrintRegLaneCount(format);
  int lane_size = GetPrintRegLaneSizeInBytes(format);
  int reg_size = GetPrintRegSizeInBytes(format);
  PrintVRegisterRawHelper(reg_code, reg_size, lane_size * lane);
  if (format & kPrintRegAsFP) {
    PrintVRegisterFPHelper(reg_code, lane_size, lane_count, lane);
1411 1412 1413
  }
  fprintf(stream_, " -> %s0x%016" PRIxPTR "%s\n",
          clr_memory_address, address, clr_normal);
1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450
}


// Visitors---------------------------------------------------------------------

void Simulator::VisitUnimplemented(Instruction* instr) {
  fprintf(stream_, "Unimplemented instruction at %p: 0x%08" PRIx32 "\n",
          reinterpret_cast<void*>(instr), instr->InstructionBits());
  UNIMPLEMENTED();
}


void Simulator::VisitUnallocated(Instruction* instr) {
  fprintf(stream_, "Unallocated instruction at %p: 0x%08" PRIx32 "\n",
          reinterpret_cast<void*>(instr), instr->InstructionBits());
  UNIMPLEMENTED();
}


void Simulator::VisitPCRelAddressing(Instruction* instr) {
  switch (instr->Mask(PCRelAddressingMask)) {
    case ADR:
      set_reg(instr->Rd(), instr->ImmPCOffsetTarget());
      break;
    case ADRP:  // Not implemented in the assembler.
      UNIMPLEMENTED();
      break;
    default:
      UNREACHABLE();
      break;
  }
}


void Simulator::VisitUnconditionalBranch(Instruction* instr) {
  switch (instr->Mask(UnconditionalBranchMask)) {
    case BL:
1451
      set_lr(instr->following());
1452
      V8_FALLTHROUGH;
1453 1454 1455 1456 1457 1458 1459 1460 1461 1462
    case B:
      set_pc(instr->ImmPCOffsetTarget());
      break;
    default:
      UNREACHABLE();
  }
}


void Simulator::VisitConditionalBranch(Instruction* instr) {
1463
  DCHECK(instr->Mask(ConditionalBranchMask) == B_cond);
1464 1465 1466 1467 1468 1469 1470 1471 1472 1473
  if (ConditionPassed(static_cast<Condition>(instr->ConditionBranch()))) {
    set_pc(instr->ImmPCOffsetTarget());
  }
}


void Simulator::VisitUnconditionalBranchToRegister(Instruction* instr) {
  Instruction* target = reg<Instruction*>(instr->Rn());
  switch (instr->Mask(UnconditionalBranchToRegisterMask)) {
    case BLR: {
1474
      set_lr(instr->following());
1475 1476 1477 1478 1479
      if (instr->Rn() == 31) {
        // BLR XZR is used as a guard for the constant pool. We should never hit
        // this, but if we do trap to allow debugging.
        Debug();
      }
1480
      V8_FALLTHROUGH;
1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519
    }
    case BR:
    case RET: set_pc(target); break;
    default: UNIMPLEMENTED();
  }
}


void Simulator::VisitTestBranch(Instruction* instr) {
  unsigned bit_pos = (instr->ImmTestBranchBit5() << 5) |
                     instr->ImmTestBranchBit40();
  bool take_branch = ((xreg(instr->Rt()) & (1UL << bit_pos)) == 0);
  switch (instr->Mask(TestBranchMask)) {
    case TBZ: break;
    case TBNZ: take_branch = !take_branch; break;
    default: UNIMPLEMENTED();
  }
  if (take_branch) {
    set_pc(instr->ImmPCOffsetTarget());
  }
}


void Simulator::VisitCompareBranch(Instruction* instr) {
  unsigned rt = instr->Rt();
  bool take_branch = false;
  switch (instr->Mask(CompareBranchMask)) {
    case CBZ_w: take_branch = (wreg(rt) == 0); break;
    case CBZ_x: take_branch = (xreg(rt) == 0); break;
    case CBNZ_w: take_branch = (wreg(rt) != 0); break;
    case CBNZ_x: take_branch = (xreg(rt) != 0); break;
    default: UNIMPLEMENTED();
  }
  if (take_branch) {
    set_pc(instr->ImmPCOffsetTarget());
  }
}


1520 1521
template<typename T>
void Simulator::AddSubHelper(Instruction* instr, T op2) {
1522 1523 1524
  // Use unsigned types to avoid implementation-defined overflow behaviour.
  static_assert(std::is_unsigned<T>::value, "operands must be unsigned");

1525
  bool set_flags = instr->FlagsUpdate();
1526
  T new_val = 0;
1527 1528 1529 1530 1531
  Instr operation = instr->Mask(AddSubOpMask);

  switch (operation) {
    case ADD:
    case ADDS: {
1532 1533 1534
      new_val = AddWithCarry<T>(set_flags,
                                reg<T>(instr->Rn(), instr->RnMode()),
                                op2);
1535 1536 1537 1538
      break;
    }
    case SUB:
    case SUBS: {
1539 1540 1541 1542
      new_val = AddWithCarry<T>(set_flags,
                                reg<T>(instr->Rn(), instr->RnMode()),
                                ~op2,
                                1);
1543 1544 1545 1546 1547
      break;
    }
    default: UNREACHABLE();
  }

1548
  set_reg<T>(instr->Rd(), new_val, instr->RdMode());
1549 1550 1551 1552
}


void Simulator::VisitAddSubShifted(Instruction* instr) {
1553 1554 1555 1556
  Shift shift_type = static_cast<Shift>(instr->ShiftDP());
  unsigned shift_amount = instr->ImmDPShift();

  if (instr->SixtyFourBits()) {
1557
    uint64_t op2 = ShiftOperand(xreg(instr->Rm()), shift_type, shift_amount);
1558 1559
    AddSubHelper(instr, op2);
  } else {
1560
    uint32_t op2 = ShiftOperand(wreg(instr->Rm()), shift_type, shift_amount);
1561 1562
    AddSubHelper(instr, op2);
  }
1563 1564 1565 1566 1567
}


void Simulator::VisitAddSubImmediate(Instruction* instr) {
  int64_t op2 = instr->ImmAddSub() << ((instr->ShiftAddSub() == 1) ? 12 : 0);
1568
  if (instr->SixtyFourBits()) {
1569
    AddSubHelper(instr, static_cast<uint64_t>(op2));
1570
  } else {
1571
    AddSubHelper(instr, static_cast<uint32_t>(op2));
1572
  }
1573 1574 1575 1576
}


void Simulator::VisitAddSubExtended(Instruction* instr) {
1577 1578 1579
  Extend ext = static_cast<Extend>(instr->ExtendMode());
  unsigned left_shift = instr->ImmExtendShift();
  if (instr->SixtyFourBits()) {
1580
    uint64_t op2 = ExtendValue(xreg(instr->Rm()), ext, left_shift);
1581 1582
    AddSubHelper(instr, op2);
  } else {
1583
    uint32_t op2 = ExtendValue(wreg(instr->Rm()), ext, left_shift);
1584 1585
    AddSubHelper(instr, op2);
  }
1586 1587 1588 1589
}


void Simulator::VisitAddSubWithCarry(Instruction* instr) {
1590
  if (instr->SixtyFourBits()) {
1591
    AddSubWithCarry<uint64_t>(instr);
1592
  } else {
1593
    AddSubWithCarry<uint32_t>(instr);
1594 1595 1596 1597 1598 1599 1600
  }
}


void Simulator::VisitLogicalShifted(Instruction* instr) {
  Shift shift_type = static_cast<Shift>(instr->ShiftDP());
  unsigned shift_amount = instr->ImmDPShift();
1601 1602

  if (instr->SixtyFourBits()) {
1603
    uint64_t op2 = ShiftOperand(xreg(instr->Rm()), shift_type, shift_amount);
1604
    op2 = (instr->Mask(NOT) == NOT) ? ~op2 : op2;
1605
    LogicalHelper(instr, op2);
1606
  } else {
1607
    uint32_t op2 = ShiftOperand(wreg(instr->Rm()), shift_type, shift_amount);
1608
    op2 = (instr->Mask(NOT) == NOT) ? ~op2 : op2;
1609
    LogicalHelper(instr, op2);
1610 1611 1612 1613 1614
  }
}


void Simulator::VisitLogicalImmediate(Instruction* instr) {
1615
  if (instr->SixtyFourBits()) {
1616
    LogicalHelper(instr, static_cast<uint64_t>(instr->ImmLogical()));
1617
  } else {
1618
    LogicalHelper(instr, static_cast<uint32_t>(instr->ImmLogical()));
1619
  }
1620 1621 1622
}


1623 1624 1625 1626
template<typename T>
void Simulator::LogicalHelper(Instruction* instr, T op2) {
  T op1 = reg<T>(instr->Rn());
  T result = 0;
1627 1628 1629 1630 1631
  bool update_flags = false;

  // Switch on the logical operation, stripping out the NOT bit, as it has a
  // different meaning for logical immediate instructions.
  switch (instr->Mask(LogicalOpMask & ~NOT)) {
1632
    case ANDS: update_flags = true; V8_FALLTHROUGH;
1633 1634 1635 1636 1637 1638 1639 1640
    case AND: result = op1 & op2; break;
    case ORR: result = op1 | op2; break;
    case EOR: result = op1 ^ op2; break;
    default:
      UNIMPLEMENTED();
  }

  if (update_flags) {
1641
    nzcv().SetN(CalcNFlag(result));
1642 1643 1644
    nzcv().SetZ(CalcZFlag(result));
    nzcv().SetC(0);
    nzcv().SetV(0);
1645
    LogSystemRegister(NZCV);
1646 1647
  }

1648
  set_reg<T>(instr->Rd(), result, instr->RdMode());
1649 1650 1651 1652
}


void Simulator::VisitConditionalCompareRegister(Instruction* instr) {
1653
  if (instr->SixtyFourBits()) {
1654
    ConditionalCompareHelper(instr, static_cast<uint64_t>(xreg(instr->Rm())));
1655
  } else {
1656
    ConditionalCompareHelper(instr, static_cast<uint32_t>(wreg(instr->Rm())));
1657
  }
1658 1659 1660 1661
}


void Simulator::VisitConditionalCompareImmediate(Instruction* instr) {
1662
  if (instr->SixtyFourBits()) {
1663
    ConditionalCompareHelper(instr, static_cast<uint64_t>(instr->ImmCondCmp()));
1664
  } else {
1665
    ConditionalCompareHelper(instr, static_cast<uint32_t>(instr->ImmCondCmp()));
1666
  }
1667 1668 1669
}


1670 1671
template<typename T>
void Simulator::ConditionalCompareHelper(Instruction* instr, T op2) {
1672 1673 1674
  // Use unsigned types to avoid implementation-defined overflow behaviour.
  static_assert(std::is_unsigned<T>::value, "operands must be unsigned");

1675
  T op1 = reg<T>(instr->Rn());
1676 1677 1678 1679 1680

  if (ConditionPassed(static_cast<Condition>(instr->Condition()))) {
    // If the condition passes, set the status flags to the result of comparing
    // the operands.
    if (instr->Mask(ConditionalCompareMask) == CCMP) {
1681
      AddWithCarry<T>(true, op1, ~op2, 1);
1682
    } else {
1683
      DCHECK(instr->Mask(ConditionalCompareMask) == CCMN);
1684
      AddWithCarry<T>(true, op1, op2, 0);
1685 1686 1687 1688
    }
  } else {
    // If the condition fails, set the status flags to the nzcv immediate.
    nzcv().SetFlags(instr->Nzcv());
1689
    LogSystemRegister(NZCV);
1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716
  }
}


void Simulator::VisitLoadStoreUnsignedOffset(Instruction* instr) {
  int offset = instr->ImmLSUnsigned() << instr->SizeLS();
  LoadStoreHelper(instr, offset, Offset);
}


void Simulator::VisitLoadStoreUnscaledOffset(Instruction* instr) {
  LoadStoreHelper(instr, instr->ImmLS(), Offset);
}


void Simulator::VisitLoadStorePreIndex(Instruction* instr) {
  LoadStoreHelper(instr, instr->ImmLS(), PreIndex);
}


void Simulator::VisitLoadStorePostIndex(Instruction* instr) {
  LoadStoreHelper(instr, instr->ImmLS(), PostIndex);
}


void Simulator::VisitLoadStoreRegisterOffset(Instruction* instr) {
  Extend ext = static_cast<Extend>(instr->ExtendMode());
1717
  DCHECK((ext == UXTW) || (ext == UXTX) || (ext == SXTW) || (ext == SXTX));
1718 1719
  unsigned shift_amount = instr->ImmShiftLS() * instr->SizeLS();

1720
  int64_t offset = ExtendValue(xreg(instr->Rm()), ext, shift_amount);
1721 1722 1723 1724 1725 1726 1727 1728 1729
  LoadStoreHelper(instr, offset, Offset);
}


void Simulator::LoadStoreHelper(Instruction* instr,
                                int64_t offset,
                                AddrMode addrmode) {
  unsigned srcdst = instr->Rt();
  unsigned addr_reg = instr->Rn();
1730 1731
  uintptr_t address = LoadStoreAddress(addr_reg, offset, addrmode);
  uintptr_t stack = 0;
1732

1733 1734 1735 1736 1737 1738 1739 1740
  {
    base::LockGuard<base::Mutex> lock_guard(&global_monitor_.Pointer()->mutex);
    if (instr->IsLoad()) {
      local_monitor_.NotifyLoad();
    } else {
      local_monitor_.NotifyStore();
      global_monitor_.Pointer()->NotifyStore_Locked(&global_monitor_processor_);
    }
1741 1742
  }

1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754
  // Handle the writeback for stores before the store. On a CPU the writeback
  // and the store are atomic, but when running on the simulator it is possible
  // to be interrupted in between. The simulator is not thread safe and V8 does
  // not require it to be to run JavaScript therefore the profiler may sample
  // the "simulated" CPU in the middle of load/store with writeback. The code
  // below ensures that push operations are safe even when interrupted: the
  // stack pointer will be decremented before adding an element to the stack.
  if (instr->IsStore()) {
    LoadStoreWriteBack(addr_reg, offset, addrmode);

    // For store the address post writeback is used to check access below the
    // stack.
1755
    stack = sp();
1756 1757
  }

1758
  LoadStoreOp op = static_cast<LoadStoreOp>(instr->Mask(LoadStoreMask));
1759
  switch (op) {
1760
    // Use _no_log variants to suppress the register trace (LOG_REGS,
1761
    // LOG_VREGS). We will print a more detailed log.
1762 1763 1764 1765 1766 1767 1768 1769 1770
    case LDRB_w:  set_wreg_no_log(srcdst, MemoryRead<uint8_t>(address)); break;
    case LDRH_w:  set_wreg_no_log(srcdst, MemoryRead<uint16_t>(address)); break;
    case LDR_w:   set_wreg_no_log(srcdst, MemoryRead<uint32_t>(address)); break;
    case LDR_x:   set_xreg_no_log(srcdst, MemoryRead<uint64_t>(address)); break;
    case LDRSB_w: set_wreg_no_log(srcdst, MemoryRead<int8_t>(address)); break;
    case LDRSH_w: set_wreg_no_log(srcdst, MemoryRead<int16_t>(address)); break;
    case LDRSB_x: set_xreg_no_log(srcdst, MemoryRead<int8_t>(address)); break;
    case LDRSH_x: set_xreg_no_log(srcdst, MemoryRead<int16_t>(address)); break;
    case LDRSW_x: set_xreg_no_log(srcdst, MemoryRead<int32_t>(address)); break;
1771 1772 1773 1774 1775 1776
    case LDR_b:
      set_breg_no_log(srcdst, MemoryRead<uint8_t>(address));
      break;
    case LDR_h:
      set_hreg_no_log(srcdst, MemoryRead<uint16_t>(address));
      break;
1777 1778
    case LDR_s:   set_sreg_no_log(srcdst, MemoryRead<float>(address)); break;
    case LDR_d:   set_dreg_no_log(srcdst, MemoryRead<double>(address)); break;
1779 1780 1781
    case LDR_q:
      set_qreg_no_log(srcdst, MemoryRead<qreg_t>(address));
      break;
1782 1783 1784 1785 1786

    case STRB_w:  MemoryWrite<uint8_t>(address, wreg(srcdst)); break;
    case STRH_w:  MemoryWrite<uint16_t>(address, wreg(srcdst)); break;
    case STR_w:   MemoryWrite<uint32_t>(address, wreg(srcdst)); break;
    case STR_x:   MemoryWrite<uint64_t>(address, xreg(srcdst)); break;
1787 1788 1789 1790 1791 1792
    case STR_b:
      MemoryWrite<uint8_t>(address, breg(srcdst));
      break;
    case STR_h:
      MemoryWrite<uint16_t>(address, hreg(srcdst));
      break;
1793 1794
    case STR_s:   MemoryWrite<float>(address, sreg(srcdst)); break;
    case STR_d:   MemoryWrite<double>(address, dreg(srcdst)); break;
1795 1796 1797
    case STR_q:
      MemoryWrite<qreg_t>(address, qreg(srcdst));
      break;
1798

1799 1800 1801
    default: UNIMPLEMENTED();
  }

1802 1803
  // Print a detailed trace (including the memory address) instead of the basic
  // register:value trace generated by set_*reg().
1804
  unsigned access_size = 1 << instr->SizeLS();
1805 1806
  if (instr->IsLoad()) {
    if ((op == LDR_s) || (op == LDR_d)) {
1807 1808 1809
      LogVRead(address, srcdst, GetPrintRegisterFormatForSizeFP(access_size));
    } else if ((op == LDR_b) || (op == LDR_h) || (op == LDR_q)) {
      LogVRead(address, srcdst, GetPrintRegisterFormatForSize(access_size));
1810
    } else {
1811
      LogRead(address, srcdst, GetPrintRegisterFormatForSize(access_size));
1812 1813 1814
    }
  } else {
    if ((op == STR_s) || (op == STR_d)) {
1815 1816 1817
      LogVWrite(address, srcdst, GetPrintRegisterFormatForSizeFP(access_size));
    } else if ((op == STR_b) || (op == STR_h) || (op == STR_q)) {
      LogVWrite(address, srcdst, GetPrintRegisterFormatForSize(access_size));
1818
    } else {
1819
      LogWrite(address, srcdst, GetPrintRegisterFormatForSize(access_size));
1820 1821 1822
    }
  }

1823 1824 1825 1826 1827 1828 1829
  // Handle the writeback for loads after the load to ensure safe pop
  // operation even when interrupted in the middle of it. The stack pointer
  // is only updated after the load so pop(fp) will never break the invariant
  // sp <= fp expected while walking the stack in the sampler.
  if (instr->IsLoad()) {
    // For loads the address pre writeback is used to check access below the
    // stack.
1830
    stack = sp();
1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860

    LoadStoreWriteBack(addr_reg, offset, addrmode);
  }

  // Accesses below the stack pointer (but above the platform stack limit) are
  // not allowed in the ABI.
  CheckMemoryAccess(address, stack);
}


void Simulator::VisitLoadStorePairOffset(Instruction* instr) {
  LoadStorePairHelper(instr, Offset);
}


void Simulator::VisitLoadStorePairPreIndex(Instruction* instr) {
  LoadStorePairHelper(instr, PreIndex);
}


void Simulator::VisitLoadStorePairPostIndex(Instruction* instr) {
  LoadStorePairHelper(instr, PostIndex);
}


void Simulator::LoadStorePairHelper(Instruction* instr,
                                    AddrMode addrmode) {
  unsigned rt = instr->Rt();
  unsigned rt2 = instr->Rt2();
  unsigned addr_reg = instr->Rn();
1861 1862 1863 1864 1865
  size_t access_size = 1 << instr->SizeLSPair();
  int64_t offset = instr->ImmLSPair() * access_size;
  uintptr_t address = LoadStoreAddress(addr_reg, offset, addrmode);
  uintptr_t address2 = address + access_size;
  uintptr_t stack = 0;
1866

1867 1868 1869 1870 1871 1872 1873 1874
  {
    base::LockGuard<base::Mutex> lock_guard(&global_monitor_.Pointer()->mutex);
    if (instr->IsLoad()) {
      local_monitor_.NotifyLoad();
    } else {
      local_monitor_.NotifyStore();
      global_monitor_.Pointer()->NotifyStore_Locked(&global_monitor_processor_);
    }
1875 1876
  }

1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888
  // Handle the writeback for stores before the store. On a CPU the writeback
  // and the store are atomic, but when running on the simulator it is possible
  // to be interrupted in between. The simulator is not thread safe and V8 does
  // not require it to be to run JavaScript therefore the profiler may sample
  // the "simulated" CPU in the middle of load/store with writeback. The code
  // below ensures that push operations are safe even when interrupted: the
  // stack pointer will be decremented before adding an element to the stack.
  if (instr->IsStore()) {
    LoadStoreWriteBack(addr_reg, offset, addrmode);

    // For store the address post writeback is used to check access below the
    // stack.
1889
    stack = sp();
1890 1891 1892 1893 1894 1895
  }

  LoadStorePairOp op =
    static_cast<LoadStorePairOp>(instr->Mask(LoadStorePairMask));

  // 'rt' and 'rt2' can only be aliased for stores.
1896
  DCHECK(((op & LoadStorePairLBit) == 0) || (rt != rt2));
1897 1898

  switch (op) {
1899
    // Use _no_log variants to suppress the register trace (LOG_REGS,
1900
    // LOG_VREGS). We will print a more detailed log.
1901
    case LDP_w: {
1902
      DCHECK_EQ(access_size, static_cast<unsigned>(kWRegSize));
1903 1904
      set_wreg_no_log(rt, MemoryRead<uint32_t>(address));
      set_wreg_no_log(rt2, MemoryRead<uint32_t>(address2));
1905 1906 1907
      break;
    }
    case LDP_s: {
1908
      DCHECK_EQ(access_size, static_cast<unsigned>(kSRegSize));
1909 1910
      set_sreg_no_log(rt, MemoryRead<float>(address));
      set_sreg_no_log(rt2, MemoryRead<float>(address2));
1911 1912 1913
      break;
    }
    case LDP_x: {
1914
      DCHECK_EQ(access_size, static_cast<unsigned>(kXRegSize));
1915 1916
      set_xreg_no_log(rt, MemoryRead<uint64_t>(address));
      set_xreg_no_log(rt2, MemoryRead<uint64_t>(address2));
1917 1918 1919
      break;
    }
    case LDP_d: {
1920
      DCHECK_EQ(access_size, static_cast<unsigned>(kDRegSize));
1921 1922
      set_dreg_no_log(rt, MemoryRead<double>(address));
      set_dreg_no_log(rt2, MemoryRead<double>(address2));
1923 1924
      break;
    }
1925 1926 1927 1928 1929 1930
    case LDP_q: {
      DCHECK_EQ(access_size, static_cast<unsigned>(kQRegSize));
      set_qreg(rt, MemoryRead<qreg_t>(address), NoRegLog);
      set_qreg(rt2, MemoryRead<qreg_t>(address2), NoRegLog);
      break;
    }
1931
    case LDPSW_x: {
1932
      DCHECK_EQ(access_size, static_cast<unsigned>(kWRegSize));
1933 1934
      set_xreg_no_log(rt, MemoryRead<int32_t>(address));
      set_xreg_no_log(rt2, MemoryRead<int32_t>(address2));
1935 1936 1937
      break;
    }
    case STP_w: {
1938
      DCHECK_EQ(access_size, static_cast<unsigned>(kWRegSize));
1939
      MemoryWrite<uint32_t>(address, wreg(rt));
1940
      MemoryWrite<uint32_t>(address2, wreg(rt2));
1941 1942 1943
      break;
    }
    case STP_s: {
1944
      DCHECK_EQ(access_size, static_cast<unsigned>(kSRegSize));
1945
      MemoryWrite<float>(address, sreg(rt));
1946
      MemoryWrite<float>(address2, sreg(rt2));
1947 1948 1949
      break;
    }
    case STP_x: {
1950
      DCHECK_EQ(access_size, static_cast<unsigned>(kXRegSize));
1951
      MemoryWrite<uint64_t>(address, xreg(rt));
1952
      MemoryWrite<uint64_t>(address2, xreg(rt2));
1953 1954 1955
      break;
    }
    case STP_d: {
1956
      DCHECK_EQ(access_size, static_cast<unsigned>(kDRegSize));
1957
      MemoryWrite<double>(address, dreg(rt));
1958
      MemoryWrite<double>(address2, dreg(rt2));
1959 1960
      break;
    }
1961 1962 1963 1964 1965 1966
    case STP_q: {
      DCHECK_EQ(access_size, static_cast<unsigned>(kQRegSize));
      MemoryWrite<qreg_t>(address, qreg(rt));
      MemoryWrite<qreg_t>(address2, qreg(rt2));
      break;
    }
1967 1968 1969
    default: UNREACHABLE();
  }

1970 1971 1972 1973
  // Print a detailed trace (including the memory address) instead of the basic
  // register:value trace generated by set_*reg().
  if (instr->IsLoad()) {
    if ((op == LDP_s) || (op == LDP_d)) {
1974 1975 1976 1977 1978
      LogVRead(address, rt, GetPrintRegisterFormatForSizeFP(access_size));
      LogVRead(address2, rt2, GetPrintRegisterFormatForSizeFP(access_size));
    } else if (op == LDP_q) {
      LogVRead(address, rt, GetPrintRegisterFormatForSize(access_size));
      LogVRead(address2, rt2, GetPrintRegisterFormatForSize(access_size));
1979
    } else {
1980 1981
      LogRead(address, rt, GetPrintRegisterFormatForSize(access_size));
      LogRead(address2, rt2, GetPrintRegisterFormatForSize(access_size));
1982 1983 1984
    }
  } else {
    if ((op == STP_s) || (op == STP_d)) {
1985 1986 1987 1988 1989
      LogVWrite(address, rt, GetPrintRegisterFormatForSizeFP(access_size));
      LogVWrite(address2, rt2, GetPrintRegisterFormatForSizeFP(access_size));
    } else if (op == STP_q) {
      LogVWrite(address, rt, GetPrintRegisterFormatForSize(access_size));
      LogVWrite(address2, rt2, GetPrintRegisterFormatForSize(access_size));
1990
    } else {
1991 1992
      LogWrite(address, rt, GetPrintRegisterFormatForSize(access_size));
      LogWrite(address2, rt2, GetPrintRegisterFormatForSize(access_size));
1993 1994 1995
    }
  }

1996 1997 1998 1999 2000 2001 2002
  // Handle the writeback for loads after the load to ensure safe pop
  // operation even when interrupted in the middle of it. The stack pointer
  // is only updated after the load so pop(fp) will never break the invariant
  // sp <= fp expected while walking the stack in the sampler.
  if (instr->IsLoad()) {
    // For loads the address pre writeback is used to check access below the
    // stack.
2003
    stack = sp();
2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014

    LoadStoreWriteBack(addr_reg, offset, addrmode);
  }

  // Accesses below the stack pointer (but above the platform stack limit) are
  // not allowed in the ABI.
  CheckMemoryAccess(address, stack);
}


void Simulator::VisitLoadLiteral(Instruction* instr) {
2015
  uintptr_t address = instr->LiteralAddress();
2016 2017
  unsigned rt = instr->Rt();

2018 2019 2020 2021
  {
    base::LockGuard<base::Mutex> lock_guard(&global_monitor_.Pointer()->mutex);
    local_monitor_.NotifyLoad();
  }
2022

2023
  switch (instr->Mask(LoadLiteralMask)) {
2024
    // Use _no_log variants to suppress the register trace (LOG_REGS,
2025
    // LOG_VREGS), then print a more detailed log.
2026 2027
    case LDR_w_lit:
      set_wreg_no_log(rt, MemoryRead<uint32_t>(address));
2028
      LogRead(address, rt, kPrintWReg);
2029 2030 2031
      break;
    case LDR_x_lit:
      set_xreg_no_log(rt, MemoryRead<uint64_t>(address));
2032
      LogRead(address, rt, kPrintXReg);
2033 2034 2035
      break;
    case LDR_s_lit:
      set_sreg_no_log(rt, MemoryRead<float>(address));
2036
      LogVRead(address, rt, kPrintSReg);
2037 2038 2039
      break;
    case LDR_d_lit:
      set_dreg_no_log(rt, MemoryRead<double>(address));
2040
      LogVRead(address, rt, kPrintDReg);
2041
      break;
2042 2043 2044 2045 2046
    default: UNREACHABLE();
  }
}


2047 2048
uintptr_t Simulator::LoadStoreAddress(unsigned addr_reg, int64_t offset,
                                      AddrMode addrmode) {
2049
  const unsigned kSPRegCode = kSPRegInternalCode & kRegCodeMask;
2050
  uint64_t address = xreg(addr_reg, Reg31IsStackPointer);
2051 2052 2053 2054
  if ((addr_reg == kSPRegCode) && ((address % 16) != 0)) {
    // When the base register is SP the stack pointer is required to be
    // quadword aligned prior to the address calculation and write-backs.
    // Misalignment will cause a stack alignment fault.
2055
    FATAL("ALIGNMENT EXCEPTION");
2056 2057 2058 2059 2060 2061
  }

  if ((addrmode == Offset) || (addrmode == PreIndex)) {
    address += offset;
  }

2062
  return address;
2063 2064 2065 2066 2067 2068 2069
}


void Simulator::LoadStoreWriteBack(unsigned addr_reg,
                                   int64_t offset,
                                   AddrMode addrmode) {
  if ((addrmode == PreIndex) || (addrmode == PostIndex)) {
2070
    DCHECK_NE(offset, 0);
2071 2072 2073 2074 2075
    uint64_t address = xreg(addr_reg, Reg31IsStackPointer);
    set_reg(addr_reg, address + offset, Reg31IsStackPointer);
  }
}

2076 2077 2078 2079 2080 2081 2082 2083 2084 2085
Simulator::TransactionSize Simulator::get_transaction_size(unsigned size) {
  switch (size) {
    case 0:
      return TransactionSize::None;
    case 1:
      return TransactionSize::Byte;
    case 2:
      return TransactionSize::HalfWord;
    case 4:
      return TransactionSize::Word;
2086 2087
    case 8:
      return TransactionSize::DoubleWord;
2088 2089 2090 2091 2092 2093
    default:
      UNREACHABLE();
  }
  return TransactionSize::None;
}

2094
void Simulator::VisitLoadStoreAcquireRelease(Instruction* instr) {
2095 2096 2097 2098 2099
  unsigned rt = instr->Rt();
  unsigned rn = instr->Rn();
  LoadStoreAcquireReleaseOp op = static_cast<LoadStoreAcquireReleaseOp>(
      instr->Mask(LoadStoreAcquireReleaseMask));
  int32_t is_acquire_release = instr->LoadStoreXAcquireRelease();
2100
  int32_t is_exclusive = (instr->LoadStoreXNotExclusive() == 0);
2101 2102
  int32_t is_load = instr->LoadStoreXLoad();
  int32_t is_pair = instr->LoadStoreXPair();
2103 2104
  USE(is_acquire_release);
  USE(is_pair);
2105 2106
  DCHECK_NE(is_acquire_release, 0);  // Non-acquire/release unimplemented.
  DCHECK_EQ(is_pair, 0);             // Pair unimplemented.
2107 2108
  unsigned access_size = 1 << instr->LoadStoreXSizeLog2();
  uintptr_t address = LoadStoreAddress(rn, 0, AddrMode::Offset);
2109
  DCHECK_EQ(address % access_size, 0);
2110 2111
  base::LockGuard<base::Mutex> lock_guard(&global_monitor_.Pointer()->mutex);
  if (is_load != 0) {
2112 2113 2114 2115 2116
    if (is_exclusive) {
      local_monitor_.NotifyLoadExcl(address, get_transaction_size(access_size));
      global_monitor_.Pointer()->NotifyLoadExcl_Locked(
          address, &global_monitor_processor_);
    } else {
2117
      local_monitor_.NotifyLoad();
2118
    }
2119
    switch (op) {
2120
      case LDAR_b:
2121 2122 2123
      case LDAXR_b:
        set_wreg_no_log(rt, MemoryRead<uint8_t>(address));
        break;
2124
      case LDAR_h:
2125 2126 2127
      case LDAXR_h:
        set_wreg_no_log(rt, MemoryRead<uint16_t>(address));
        break;
2128
      case LDAR_w:
2129 2130 2131
      case LDAXR_w:
        set_wreg_no_log(rt, MemoryRead<uint32_t>(address));
        break;
2132 2133 2134 2135
      case LDAR_x:
      case LDAXR_x:
        set_xreg_no_log(rt, MemoryRead<uint64_t>(address));
        break;
2136 2137 2138
      default:
        UNIMPLEMENTED();
    }
2139
    LogRead(address, rt, GetPrintRegisterFormatForSize(access_size));
2140
  } else {
2141 2142
    if (is_exclusive) {
      unsigned rs = instr->Rs();
2143 2144
      DCHECK_NE(rs, rt);
      DCHECK_NE(rs, rn);
2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158
      if (local_monitor_.NotifyStoreExcl(address,
                                         get_transaction_size(access_size)) &&
          global_monitor_.Pointer()->NotifyStoreExcl_Locked(
              address, &global_monitor_processor_)) {
        switch (op) {
          case STLXR_b:
            MemoryWrite<uint8_t>(address, wreg(rt));
            break;
          case STLXR_h:
            MemoryWrite<uint16_t>(address, wreg(rt));
            break;
          case STLXR_w:
            MemoryWrite<uint32_t>(address, wreg(rt));
            break;
2159 2160 2161
          case STLXR_x:
            MemoryWrite<uint64_t>(address, xreg(rt));
            break;
2162 2163 2164
          default:
            UNIMPLEMENTED();
        }
2165
        LogWrite(address, rt, GetPrintRegisterFormatForSize(access_size));
2166 2167 2168 2169 2170
        set_wreg(rs, 0);
      } else {
        set_wreg(rs, 1);
      }
    } else {
2171 2172
      local_monitor_.NotifyStore();
      global_monitor_.Pointer()->NotifyStore_Locked(&global_monitor_processor_);
2173
      switch (op) {
2174
        case STLR_b:
2175 2176
          MemoryWrite<uint8_t>(address, wreg(rt));
          break;
2177
        case STLR_h:
2178 2179
          MemoryWrite<uint16_t>(address, wreg(rt));
          break;
2180
        case STLR_w:
2181 2182
          MemoryWrite<uint32_t>(address, wreg(rt));
          break;
2183 2184 2185
        case STLR_x:
          MemoryWrite<uint64_t>(address, xreg(rt));
          break;
2186 2187 2188 2189 2190
        default:
          UNIMPLEMENTED();
      }
    }
  }
2191
}
2192

2193
void Simulator::CheckMemoryAccess(uintptr_t address, uintptr_t stack) {
2194 2195
  if ((address >= stack_limit_) && (address < stack)) {
    fprintf(stream_, "ACCESS BELOW STACK POINTER:\n");
2196 2197 2198 2199 2200 2201
    fprintf(stream_, "  sp is here:          0x%016" PRIx64 "\n",
            static_cast<uint64_t>(stack));
    fprintf(stream_, "  access was here:     0x%016" PRIx64 "\n",
            static_cast<uint64_t>(address));
    fprintf(stream_, "  stack limit is here: 0x%016" PRIx64 "\n",
            static_cast<uint64_t>(stack_limit_));
2202
    fprintf(stream_, "\n");
2203
    FATAL("ACCESS BELOW STACK POINTER");
2204 2205 2206 2207 2208 2209 2210 2211 2212 2213 2214
  }
}


void Simulator::VisitMoveWideImmediate(Instruction* instr) {
  MoveWideImmediateOp mov_op =
    static_cast<MoveWideImmediateOp>(instr->Mask(MoveWideImmediateMask));
  int64_t new_xn_val = 0;

  bool is_64_bits = instr->SixtyFourBits() == 1;
  // Shift is limited for W operations.
2215
  DCHECK(is_64_bits || (instr->ShiftMoveWide() < 2));
2216 2217 2218

  // Get the shifted immediate.
  int64_t shift = instr->ShiftMoveWide() * 16;
2219
  int64_t shifted_imm16 = static_cast<int64_t>(instr->ImmMoveWide()) << shift;
2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233

  // Compute the new value.
  switch (mov_op) {
    case MOVN_w:
    case MOVN_x: {
        new_xn_val = ~shifted_imm16;
        if (!is_64_bits) new_xn_val &= kWRegMask;
      break;
    }
    case MOVK_w:
    case MOVK_x: {
        unsigned reg_code = instr->Rd();
        int64_t prev_xn_val = is_64_bits ? xreg(reg_code)
                                         : wreg(reg_code);
2234 2235
        new_xn_val = (prev_xn_val & ~(0xFFFFL << shift)) | shifted_imm16;
        break;
2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 2246 2247 2248 2249 2250 2251
    }
    case MOVZ_w:
    case MOVZ_x: {
        new_xn_val = shifted_imm16;
      break;
    }
    default:
      UNREACHABLE();
  }

  // Update the destination register.
  set_xreg(instr->Rd(), new_xn_val);
}


void Simulator::VisitConditionalSelect(Instruction* instr) {
2252
  uint64_t new_val = xreg(instr->Rn());
2253
  if (ConditionFailed(static_cast<Condition>(instr->Condition()))) {
2254
    new_val = xreg(instr->Rm());
2255
    switch (instr->Mask(ConditionalSelectMask)) {
2256 2257 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270
      case CSEL_w:
      case CSEL_x:
        break;
      case CSINC_w:
      case CSINC_x:
        new_val++;
        break;
      case CSINV_w:
      case CSINV_x:
        new_val = ~new_val;
        break;
      case CSNEG_w:
      case CSNEG_x:
        new_val = -new_val;
        break;
2271 2272
      default: UNIMPLEMENTED();
    }
2273 2274 2275
  }
  if (instr->SixtyFourBits()) {
    set_xreg(instr->Rd(), new_val);
2276
  } else {
2277
    set_wreg(instr->Rd(), static_cast<uint32_t>(new_val));
2278 2279 2280 2281 2282 2283 2284 2285 2286
  }
}


void Simulator::VisitDataProcessing1Source(Instruction* instr) {
  unsigned dst = instr->Rd();
  unsigned src = instr->Rn();

  switch (instr->Mask(DataProcessing1SourceMask)) {
2287
    case RBIT_w:
2288
      set_wreg(dst, base::bits::ReverseBits(wreg(src)));
2289 2290
      break;
    case RBIT_x:
2291
      set_xreg(dst, base::bits::ReverseBits(xreg(src)));
2292 2293 2294 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307
      break;
    case REV16_w:
      set_wreg(dst, ReverseBytes(wreg(src), 1));
      break;
    case REV16_x:
      set_xreg(dst, ReverseBytes(xreg(src), 1));
      break;
    case REV_w:
      set_wreg(dst, ReverseBytes(wreg(src), 2));
      break;
    case REV32_x:
      set_xreg(dst, ReverseBytes(xreg(src), 2));
      break;
    case REV_x:
      set_xreg(dst, ReverseBytes(xreg(src), 3));
      break;
2308 2309 2310 2311
    case CLZ_w: set_wreg(dst, CountLeadingZeros(wreg(src), kWRegSizeInBits));
                break;
    case CLZ_x: set_xreg(dst, CountLeadingZeros(xreg(src), kXRegSizeInBits));
                break;
2312
    case CLS_w: {
2313
      set_wreg(dst, CountLeadingSignBits(wreg(src), kWRegSizeInBits));
2314 2315 2316
      break;
    }
    case CLS_x: {
2317
      set_xreg(dst, CountLeadingSignBits(xreg(src), kXRegSizeInBits));
2318 2319 2320 2321 2322 2323 2324
      break;
    }
    default: UNIMPLEMENTED();
  }
}


2325 2326
template <typename T>
void Simulator::DataProcessing2Source(Instruction* instr) {
2327
  Shift shift_op = NO_SHIFT;
2328
  T result = 0;
2329
  switch (instr->Mask(DataProcessing2SourceMask)) {
2330
    case SDIV_w:
2331
    case SDIV_x: {
2332 2333 2334 2335
      T rn = reg<T>(instr->Rn());
      T rm = reg<T>(instr->Rm());
      if ((rn == std::numeric_limits<T>::min()) && (rm == -1)) {
        result = std::numeric_limits<T>::min();
2336 2337 2338 2339 2340 2341 2342 2343
      } else if (rm == 0) {
        // Division by zero can be trapped, but not on A-class processors.
        result = 0;
      } else {
        result = rn / rm;
      }
      break;
    }
2344
    case UDIV_w:
2345
    case UDIV_x: {
2346
      typedef typename std::make_unsigned<T>::type unsignedT;
2347 2348
      unsignedT rn = static_cast<unsignedT>(reg<T>(instr->Rn()));
      unsignedT rm = static_cast<unsignedT>(reg<T>(instr->Rm()));
2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370
      if (rm == 0) {
        // Division by zero can be trapped, but not on A-class processors.
        result = 0;
      } else {
        result = rn / rm;
      }
      break;
    }
    case LSLV_w:
    case LSLV_x: shift_op = LSL; break;
    case LSRV_w:
    case LSRV_x: shift_op = LSR; break;
    case ASRV_w:
    case ASRV_x: shift_op = ASR; break;
    case RORV_w:
    case RORV_x: shift_op = ROR; break;
    default: UNIMPLEMENTED();
  }

  if (shift_op != NO_SHIFT) {
    // Shift distance encoded in the least-significant five/six bits of the
    // register.
2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387
    unsigned shift = wreg(instr->Rm());
    if (sizeof(T) == kWRegSize) {
      shift &= kShiftAmountWRegMask;
    } else {
      shift &= kShiftAmountXRegMask;
    }
    result = ShiftOperand(reg<T>(instr->Rn()), shift_op, shift);
  }
  set_reg<T>(instr->Rd(), result);
}


void Simulator::VisitDataProcessing2Source(Instruction* instr) {
  if (instr->SixtyFourBits()) {
    DataProcessing2Source<int64_t>(instr);
  } else {
    DataProcessing2Source<int32_t>(instr);
2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398
  }
}


// The algorithm used is described in section 8.2 of
//   Hacker's Delight, by Henry S. Warren, Jr.
// It assumes that a right shift on a signed integer is an arithmetic shift.
static int64_t MultiplyHighSigned(int64_t u, int64_t v) {
  uint64_t u0, v0, w0;
  int64_t u1, v1, w1, w2, t;

2399
  u0 = u & 0xFFFFFFFFL;
2400
  u1 = u >> 32;
2401
  v0 = v & 0xFFFFFFFFL;
2402 2403 2404 2405
  v1 = v >> 32;

  w0 = u0 * v0;
  t = u1 * v0 + (w0 >> 32);
2406
  w1 = t & 0xFFFFFFFFL;
2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434
  w2 = t >> 32;
  w1 = u0 * v1 + w1;

  return u1 * v1 + w2 + (w1 >> 32);
}


void Simulator::VisitDataProcessing3Source(Instruction* instr) {
  int64_t result = 0;
  // Extract and sign- or zero-extend 32-bit arguments for widening operations.
  uint64_t rn_u32 = reg<uint32_t>(instr->Rn());
  uint64_t rm_u32 = reg<uint32_t>(instr->Rm());
  int64_t rn_s32 = reg<int32_t>(instr->Rn());
  int64_t rm_s32 = reg<int32_t>(instr->Rm());
  switch (instr->Mask(DataProcessing3SourceMask)) {
    case MADD_w:
    case MADD_x:
      result = xreg(instr->Ra()) + (xreg(instr->Rn()) * xreg(instr->Rm()));
      break;
    case MSUB_w:
    case MSUB_x:
      result = xreg(instr->Ra()) - (xreg(instr->Rn()) * xreg(instr->Rm()));
      break;
    case SMADDL_x: result = xreg(instr->Ra()) + (rn_s32 * rm_s32); break;
    case SMSUBL_x: result = xreg(instr->Ra()) - (rn_s32 * rm_s32); break;
    case UMADDL_x: result = xreg(instr->Ra()) + (rn_u32 * rm_u32); break;
    case UMSUBL_x: result = xreg(instr->Ra()) - (rn_u32 * rm_u32); break;
    case SMULH_x:
2435
      DCHECK_EQ(instr->Ra(), kZeroRegCode);
2436 2437 2438 2439
      result = MultiplyHighSigned(xreg(instr->Rn()), xreg(instr->Rm()));
      break;
    default: UNIMPLEMENTED();
  }
2440 2441 2442 2443

  if (instr->SixtyFourBits()) {
    set_xreg(instr->Rd(), result);
  } else {
2444
    set_wreg(instr->Rd(), static_cast<int32_t>(result));
2445
  }
2446 2447 2448
}


2449 2450
template <typename T>
void Simulator::BitfieldHelper(Instruction* instr) {
2451
  typedef typename std::make_unsigned<T>::type unsignedT;
2452 2453 2454 2455 2456
  T reg_size = sizeof(T) * 8;
  T R = instr->ImmR();
  T S = instr->ImmS();
  T diff = S - R;
  T mask;
2457
  if (diff >= 0) {
2458 2459
    mask = diff < reg_size - 1 ? (static_cast<T>(1) << (diff + 1)) - 1
                               : static_cast<T>(-1);
2460
  } else {
2461 2462 2463
    uint64_t umask = ((1L << (S + 1)) - 1);
    umask = (umask >> R) | (umask << (reg_size - R));
    mask = static_cast<T>(umask);
2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 2480 2481 2482 2483 2484 2485 2486 2487 2488
    diff += reg_size;
  }

  // inzero indicates if the extracted bitfield is inserted into the
  // destination register value or in zero.
  // If extend is true, extend the sign of the extracted bitfield.
  bool inzero = false;
  bool extend = false;
  switch (instr->Mask(BitfieldMask)) {
    case BFM_x:
    case BFM_w:
      break;
    case SBFM_x:
    case SBFM_w:
      inzero = true;
      extend = true;
      break;
    case UBFM_x:
    case UBFM_w:
      inzero = true;
      break;
    default:
      UNIMPLEMENTED();
  }

2489 2490
  T dst = inzero ? 0 : reg<T>(instr->Rd());
  T src = reg<T>(instr->Rn());
2491
  // Rotate source bitfield into place.
2492
  T result = (static_cast<unsignedT>(src) >> R) | (src << (reg_size - R));
2493
  // Determine the sign extension.
2494 2495 2496
  T topbits_preshift = (static_cast<T>(1) << (reg_size - diff - 1)) - 1;
  T signbits = (extend && ((src >> S) & 1) ? topbits_preshift : 0)
               << (diff + 1);
2497 2498 2499 2500

  // Merge sign extension, dest/zero and bitfield.
  result = signbits | (result & mask) | (dst & ~mask);

2501
  set_reg<T>(instr->Rd(), result);
2502 2503 2504
}


2505 2506 2507 2508 2509
void Simulator::VisitBitfield(Instruction* instr) {
  if (instr->SixtyFourBits()) {
    BitfieldHelper<int64_t>(instr);
  } else {
    BitfieldHelper<int32_t>(instr);
2510
  }
2511 2512
}

2513

2514 2515 2516 2517 2518 2519
void Simulator::VisitExtract(Instruction* instr) {
  if (instr->SixtyFourBits()) {
    Extract<uint64_t>(instr);
  } else {
    Extract<uint32_t>(instr);
  }
2520 2521 2522 2523 2524 2525 2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 2537 2538 2539 2540
}


void Simulator::VisitFPImmediate(Instruction* instr) {
  AssertSupportedFPCR();

  unsigned dest = instr->Rd();
  switch (instr->Mask(FPImmediateMask)) {
    case FMOV_s_imm: set_sreg(dest, instr->ImmFP32()); break;
    case FMOV_d_imm: set_dreg(dest, instr->ImmFP64()); break;
    default: UNREACHABLE();
  }
}


void Simulator::VisitFPIntegerConvert(Instruction* instr) {
  AssertSupportedFPCR();

  unsigned dst = instr->Rd();
  unsigned src = instr->Rn();

2541
  FPRounding round = fpcr().RMode();
2542 2543 2544 2545 2546 2547 2548 2549 2550 2551 2552 2553 2554 2555 2556 2557 2558 2559 2560 2561 2562 2563 2564 2565 2566 2567 2568 2569 2570 2571 2572 2573 2574 2575 2576 2577 2578 2579 2580 2581 2582 2583 2584 2585 2586 2587 2588 2589 2590 2591 2592 2593 2594 2595 2596 2597 2598 2599 2600 2601 2602 2603 2604 2605 2606 2607 2608 2609 2610 2611 2612 2613 2614 2615 2616 2617 2618 2619 2620 2621 2622 2623 2624 2625

  switch (instr->Mask(FPIntegerConvertMask)) {
    case FCVTAS_ws: set_wreg(dst, FPToInt32(sreg(src), FPTieAway)); break;
    case FCVTAS_xs: set_xreg(dst, FPToInt64(sreg(src), FPTieAway)); break;
    case FCVTAS_wd: set_wreg(dst, FPToInt32(dreg(src), FPTieAway)); break;
    case FCVTAS_xd: set_xreg(dst, FPToInt64(dreg(src), FPTieAway)); break;
    case FCVTAU_ws: set_wreg(dst, FPToUInt32(sreg(src), FPTieAway)); break;
    case FCVTAU_xs: set_xreg(dst, FPToUInt64(sreg(src), FPTieAway)); break;
    case FCVTAU_wd: set_wreg(dst, FPToUInt32(dreg(src), FPTieAway)); break;
    case FCVTAU_xd: set_xreg(dst, FPToUInt64(dreg(src), FPTieAway)); break;
    case FCVTMS_ws:
      set_wreg(dst, FPToInt32(sreg(src), FPNegativeInfinity));
      break;
    case FCVTMS_xs:
      set_xreg(dst, FPToInt64(sreg(src), FPNegativeInfinity));
      break;
    case FCVTMS_wd:
      set_wreg(dst, FPToInt32(dreg(src), FPNegativeInfinity));
      break;
    case FCVTMS_xd:
      set_xreg(dst, FPToInt64(dreg(src), FPNegativeInfinity));
      break;
    case FCVTMU_ws:
      set_wreg(dst, FPToUInt32(sreg(src), FPNegativeInfinity));
      break;
    case FCVTMU_xs:
      set_xreg(dst, FPToUInt64(sreg(src), FPNegativeInfinity));
      break;
    case FCVTMU_wd:
      set_wreg(dst, FPToUInt32(dreg(src), FPNegativeInfinity));
      break;
    case FCVTMU_xd:
      set_xreg(dst, FPToUInt64(dreg(src), FPNegativeInfinity));
      break;
    case FCVTNS_ws: set_wreg(dst, FPToInt32(sreg(src), FPTieEven)); break;
    case FCVTNS_xs: set_xreg(dst, FPToInt64(sreg(src), FPTieEven)); break;
    case FCVTNS_wd: set_wreg(dst, FPToInt32(dreg(src), FPTieEven)); break;
    case FCVTNS_xd: set_xreg(dst, FPToInt64(dreg(src), FPTieEven)); break;
    case FCVTNU_ws: set_wreg(dst, FPToUInt32(sreg(src), FPTieEven)); break;
    case FCVTNU_xs: set_xreg(dst, FPToUInt64(sreg(src), FPTieEven)); break;
    case FCVTNU_wd: set_wreg(dst, FPToUInt32(dreg(src), FPTieEven)); break;
    case FCVTNU_xd: set_xreg(dst, FPToUInt64(dreg(src), FPTieEven)); break;
    case FCVTZS_ws: set_wreg(dst, FPToInt32(sreg(src), FPZero)); break;
    case FCVTZS_xs: set_xreg(dst, FPToInt64(sreg(src), FPZero)); break;
    case FCVTZS_wd: set_wreg(dst, FPToInt32(dreg(src), FPZero)); break;
    case FCVTZS_xd: set_xreg(dst, FPToInt64(dreg(src), FPZero)); break;
    case FCVTZU_ws: set_wreg(dst, FPToUInt32(sreg(src), FPZero)); break;
    case FCVTZU_xs: set_xreg(dst, FPToUInt64(sreg(src), FPZero)); break;
    case FCVTZU_wd: set_wreg(dst, FPToUInt32(dreg(src), FPZero)); break;
    case FCVTZU_xd: set_xreg(dst, FPToUInt64(dreg(src), FPZero)); break;
    case FMOV_ws: set_wreg(dst, sreg_bits(src)); break;
    case FMOV_xd: set_xreg(dst, dreg_bits(src)); break;
    case FMOV_sw: set_sreg_bits(dst, wreg(src)); break;
    case FMOV_dx: set_dreg_bits(dst, xreg(src)); break;

    // A 32-bit input can be handled in the same way as a 64-bit input, since
    // the sign- or zero-extension will not affect the conversion.
    case SCVTF_dx: set_dreg(dst, FixedToDouble(xreg(src), 0, round)); break;
    case SCVTF_dw: set_dreg(dst, FixedToDouble(wreg(src), 0, round)); break;
    case UCVTF_dx: set_dreg(dst, UFixedToDouble(xreg(src), 0, round)); break;
    case UCVTF_dw: {
      set_dreg(dst, UFixedToDouble(reg<uint32_t>(src), 0, round));
      break;
    }
    case SCVTF_sx: set_sreg(dst, FixedToFloat(xreg(src), 0, round)); break;
    case SCVTF_sw: set_sreg(dst, FixedToFloat(wreg(src), 0, round)); break;
    case UCVTF_sx: set_sreg(dst, UFixedToFloat(xreg(src), 0, round)); break;
    case UCVTF_sw: {
      set_sreg(dst, UFixedToFloat(reg<uint32_t>(src), 0, round));
      break;
    }

    default: UNREACHABLE();
  }
}


void Simulator::VisitFPFixedPointConvert(Instruction* instr) {
  AssertSupportedFPCR();

  unsigned dst = instr->Rd();
  unsigned src = instr->Rn();
  int fbits = 64 - instr->FPScale();

2626
  FPRounding round = fpcr().RMode();
2627 2628 2629 2630 2631 2632 2633 2634 2635 2636 2637 2638 2639 2640 2641 2642 2643 2644 2645 2646 2647 2648 2649 2650 2651 2652 2653 2654 2655 2656 2657 2658 2659 2660 2661 2662 2663 2664 2665 2666 2667 2668

  switch (instr->Mask(FPFixedPointConvertMask)) {
    // A 32-bit input can be handled in the same way as a 64-bit input, since
    // the sign- or zero-extension will not affect the conversion.
    case SCVTF_dx_fixed:
      set_dreg(dst, FixedToDouble(xreg(src), fbits, round));
      break;
    case SCVTF_dw_fixed:
      set_dreg(dst, FixedToDouble(wreg(src), fbits, round));
      break;
    case UCVTF_dx_fixed:
      set_dreg(dst, UFixedToDouble(xreg(src), fbits, round));
      break;
    case UCVTF_dw_fixed: {
      set_dreg(dst,
               UFixedToDouble(reg<uint32_t>(src), fbits, round));
      break;
    }
    case SCVTF_sx_fixed:
      set_sreg(dst, FixedToFloat(xreg(src), fbits, round));
      break;
    case SCVTF_sw_fixed:
      set_sreg(dst, FixedToFloat(wreg(src), fbits, round));
      break;
    case UCVTF_sx_fixed:
      set_sreg(dst, UFixedToFloat(xreg(src), fbits, round));
      break;
    case UCVTF_sw_fixed: {
      set_sreg(dst,
               UFixedToFloat(reg<uint32_t>(src), fbits, round));
      break;
    }
    default: UNREACHABLE();
  }
}


void Simulator::VisitFPCompare(Instruction* instr) {
  AssertSupportedFPCR();

  switch (instr->Mask(FPCompareMask)) {
    case FCMP_s:
2669 2670 2671 2672 2673
      FPCompare(sreg(instr->Rn()), sreg(instr->Rm()));
      break;
    case FCMP_d:
      FPCompare(dreg(instr->Rn()), dreg(instr->Rm()));
      break;
2674
    case FCMP_s_zero:
2675 2676 2677 2678 2679
      FPCompare(sreg(instr->Rn()), 0.0f);
      break;
    case FCMP_d_zero:
      FPCompare(dreg(instr->Rn()), 0.0);
      break;
2680 2681 2682 2683 2684 2685 2686 2687 2688 2689
    default: UNIMPLEMENTED();
  }
}


void Simulator::VisitFPConditionalCompare(Instruction* instr) {
  AssertSupportedFPCR();

  switch (instr->Mask(FPConditionalCompareMask)) {
    case FCCMP_s:
2690 2691 2692 2693 2694 2695 2696
      if (ConditionPassed(static_cast<Condition>(instr->Condition()))) {
        FPCompare(sreg(instr->Rn()), sreg(instr->Rm()));
      } else {
        nzcv().SetFlags(instr->Nzcv());
        LogSystemRegister(NZCV);
      }
      break;
2697 2698
    case FCCMP_d: {
      if (ConditionPassed(static_cast<Condition>(instr->Condition()))) {
2699
        FPCompare(dreg(instr->Rn()), dreg(instr->Rm()));
2700 2701 2702
      } else {
        // If the condition fails, set the status flags to the nzcv immediate.
        nzcv().SetFlags(instr->Nzcv());
2703
        LogSystemRegister(NZCV);
2704 2705 2706 2707 2708 2709 2710 2711 2712 2713 2714 2715 2716 2717 2718 2719 2720 2721 2722 2723 2724 2725 2726 2727 2728 2729 2730 2731 2732
      }
      break;
    }
    default: UNIMPLEMENTED();
  }
}


void Simulator::VisitFPConditionalSelect(Instruction* instr) {
  AssertSupportedFPCR();

  Instr selected;
  if (ConditionPassed(static_cast<Condition>(instr->Condition()))) {
    selected = instr->Rn();
  } else {
    selected = instr->Rm();
  }

  switch (instr->Mask(FPConditionalSelectMask)) {
    case FCSEL_s: set_sreg(instr->Rd(), sreg(selected)); break;
    case FCSEL_d: set_dreg(instr->Rd(), dreg(selected)); break;
    default: UNIMPLEMENTED();
  }
}


void Simulator::VisitFPDataProcessing1Source(Instruction* instr) {
  AssertSupportedFPCR();

2733 2734 2735 2736 2737 2738
  FPRounding fpcr_rounding = static_cast<FPRounding>(fpcr().RMode());
  VectorFormat vform = (instr->Mask(FP64) == FP64) ? kFormatD : kFormatS;
  SimVRegister& rd = vreg(instr->Rd());
  SimVRegister& rn = vreg(instr->Rn());
  bool inexact_exception = false;

2739 2740 2741 2742
  unsigned fd = instr->Rd();
  unsigned fn = instr->Rn();

  switch (instr->Mask(FPDataProcessing1SourceMask)) {
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 2771 2772 2773 2774 2775 2776 2777 2778 2779 2780 2781 2782 2783 2784 2785 2786 2787 2788 2789 2790 2791 2792 2793 2794 2795
    case FMOV_s:
      set_sreg(fd, sreg(fn));
      return;
    case FMOV_d:
      set_dreg(fd, dreg(fn));
      return;
    case FABS_s:
    case FABS_d:
      fabs_(vform, vreg(fd), vreg(fn));
      // Explicitly log the register update whilst we have type information.
      LogVRegister(fd, GetPrintRegisterFormatFP(vform));
      return;
    case FNEG_s:
    case FNEG_d:
      fneg(vform, vreg(fd), vreg(fn));
      // Explicitly log the register update whilst we have type information.
      LogVRegister(fd, GetPrintRegisterFormatFP(vform));
      return;
    case FCVT_ds:
      set_dreg(fd, FPToDouble(sreg(fn)));
      return;
    case FCVT_sd:
      set_sreg(fd, FPToFloat(dreg(fn), FPTieEven));
      return;
    case FCVT_hs:
      set_hreg(fd, FPToFloat16(sreg(fn), FPTieEven));
      return;
    case FCVT_sh:
      set_sreg(fd, FPToFloat(hreg(fn)));
      return;
    case FCVT_dh:
      set_dreg(fd, FPToDouble(FPToFloat(hreg(fn))));
      return;
    case FCVT_hd:
      set_hreg(fd, FPToFloat16(dreg(fn), FPTieEven));
      return;
    case FSQRT_s:
    case FSQRT_d:
      fsqrt(vform, rd, rn);
      // Explicitly log the register update whilst we have type information.
      LogVRegister(fd, GetPrintRegisterFormatFP(vform));
      return;
    case FRINTI_s:
    case FRINTI_d:
      break;  // Use FPCR rounding mode.
    case FRINTX_s:
    case FRINTX_d:
      inexact_exception = true;
      break;
    case FRINTA_s:
    case FRINTA_d:
      fpcr_rounding = FPTieAway;
      break;
2796 2797
    case FRINTM_s:
    case FRINTM_d:
2798
      fpcr_rounding = FPNegativeInfinity;
2799
      break;
2800 2801 2802 2803 2804
    case FRINTN_s:
    case FRINTN_d:
      fpcr_rounding = FPTieEven;
      break;
    case FRINTP_s:
2805
    case FRINTP_d:
2806 2807 2808 2809 2810 2811 2812 2813
      fpcr_rounding = FPPositiveInfinity;
      break;
    case FRINTZ_s:
    case FRINTZ_d:
      fpcr_rounding = FPZero;
      break;
    default:
      UNIMPLEMENTED();
2814 2815
  }

2816 2817 2818 2819
  // Only FRINT* instructions fall through the switch above.
  frint(vform, rd, rn, fpcr_rounding, inexact_exception);
  // Explicitly log the register update whilst we have type information
  LogVRegister(fd, GetPrintRegisterFormatFP(vform));
2820 2821
}

2822 2823
void Simulator::VisitFPDataProcessing2Source(Instruction* instr) {
  AssertSupportedFPCR();
2824

2825 2826 2827 2828
  VectorFormat vform = (instr->Mask(FP64) == FP64) ? kFormatD : kFormatS;
  SimVRegister& rd = vreg(instr->Rd());
  SimVRegister& rn = vreg(instr->Rn());
  SimVRegister& rm = vreg(instr->Rm());
2829

2830 2831 2832 2833 2834 2835 2836 2837 2838 2839 2840 2841 2842 2843 2844 2845 2846 2847 2848 2849 2850 2851 2852 2853 2854 2855 2856 2857 2858 2859 2860 2861 2862 2863 2864 2865 2866 2867 2868
  switch (instr->Mask(FPDataProcessing2SourceMask)) {
    case FADD_s:
    case FADD_d:
      fadd(vform, rd, rn, rm);
      break;
    case FSUB_s:
    case FSUB_d:
      fsub(vform, rd, rn, rm);
      break;
    case FMUL_s:
    case FMUL_d:
      fmul(vform, rd, rn, rm);
      break;
    case FNMUL_s:
    case FNMUL_d:
      fnmul(vform, rd, rn, rm);
      break;
    case FDIV_s:
    case FDIV_d:
      fdiv(vform, rd, rn, rm);
      break;
    case FMAX_s:
    case FMAX_d:
      fmax(vform, rd, rn, rm);
      break;
    case FMIN_s:
    case FMIN_d:
      fmin(vform, rd, rn, rm);
      break;
    case FMAXNM_s:
    case FMAXNM_d:
      fmaxnm(vform, rd, rn, rm);
      break;
    case FMINNM_s:
    case FMINNM_d:
      fminnm(vform, rd, rn, rm);
      break;
    default:
      UNREACHABLE();
2869
  }
2870 2871
  // Explicitly log the register update whilst we have type information.
  LogVRegister(instr->Rd(), GetPrintRegisterFormatFP(vform));
2872 2873
}

2874 2875
void Simulator::VisitFPDataProcessing3Source(Instruction* instr) {
  AssertSupportedFPCR();
2876

2877 2878 2879 2880
  unsigned fd = instr->Rd();
  unsigned fn = instr->Rn();
  unsigned fm = instr->Rm();
  unsigned fa = instr->Ra();
2881

2882 2883 2884 2885
  switch (instr->Mask(FPDataProcessing3SourceMask)) {
    // fd = fa +/- (fn * fm)
    case FMADD_s:
      set_sreg(fd, FPMulAdd(sreg(fa), sreg(fn), sreg(fm)));
2886
      break;
2887 2888
    case FMSUB_s:
      set_sreg(fd, FPMulAdd(sreg(fa), -sreg(fn), sreg(fm)));
2889
      break;
2890 2891
    case FMADD_d:
      set_dreg(fd, FPMulAdd(dreg(fa), dreg(fn), dreg(fm)));
2892
      break;
2893 2894
    case FMSUB_d:
      set_dreg(fd, FPMulAdd(dreg(fa), -dreg(fn), dreg(fm)));
2895 2896 2897 2898 2899 2900 2901 2902 2903 2904 2905 2906 2907 2908
      break;
    // Negated variants of the above.
    case FNMADD_s:
      set_sreg(fd, FPMulAdd(-sreg(fa), -sreg(fn), sreg(fm)));
      break;
    case FNMSUB_s:
      set_sreg(fd, FPMulAdd(-sreg(fa), sreg(fn), sreg(fm)));
      break;
    case FNMADD_d:
      set_dreg(fd, FPMulAdd(-dreg(fa), -dreg(fn), dreg(fm)));
      break;
    case FNMSUB_d:
      set_dreg(fd, FPMulAdd(-dreg(fa), dreg(fn), dreg(fm)));
      break;
2909 2910
    default:
      UNIMPLEMENTED();
2911 2912 2913 2914 2915
  }
}

bool Simulator::FPProcessNaNs(Instruction* instr) {
  unsigned fd = instr->Rd();
2916 2917 2918 2919 2920 2921 2922 2923 2924 2925 2926 2927 2928 2929 2930 2931 2932 2933 2934
  unsigned fn = instr->Rn();
  unsigned fm = instr->Rm();
  bool done = false;

  if (instr->Mask(FP64) == FP64) {
    double result = FPProcessNaNs(dreg(fn), dreg(fm));
    if (std::isnan(result)) {
      set_dreg(fd, result);
      done = true;
    }
  } else {
    float result = FPProcessNaNs(sreg(fn), sreg(fm));
    if (std::isnan(result)) {
      set_sreg(fd, result);
      done = true;
    }
  }

  return done;
2935 2936 2937 2938 2939 2940 2941 2942 2943 2944 2945 2946 2947 2948 2949 2950 2951 2952 2953
}


void Simulator::VisitSystem(Instruction* instr) {
  // Some system instructions hijack their Op and Cp fields to represent a
  // range of immediates instead of indicating a different instruction. This
  // makes the decoding tricky.
  if (instr->Mask(SystemSysRegFMask) == SystemSysRegFixed) {
    switch (instr->Mask(SystemSysRegMask)) {
      case MRS: {
        switch (instr->ImmSystemRegister()) {
          case NZCV: set_xreg(instr->Rt(), nzcv().RawValue()); break;
          case FPCR: set_xreg(instr->Rt(), fpcr().RawValue()); break;
          default: UNIMPLEMENTED();
        }
        break;
      }
      case MSR: {
        switch (instr->ImmSystemRegister()) {
2954
          case NZCV:
2955
            nzcv().SetRawValue(wreg(instr->Rt()));
2956 2957 2958
            LogSystemRegister(NZCV);
            break;
          case FPCR:
2959
            fpcr().SetRawValue(wreg(instr->Rt()));
2960 2961
            LogSystemRegister(FPCR);
            break;
2962 2963 2964 2965 2966 2967
          default: UNIMPLEMENTED();
        }
        break;
      }
    }
  } else if (instr->Mask(SystemHintFMask) == SystemHintFixed) {
2968
    DCHECK(instr->Mask(SystemHintMask) == HINT);
2969
    switch (instr->ImmHint()) {
2970 2971 2972
      case NOP:
      case CSDB:
        break;
2973 2974 2975 2976 2977 2978 2979 2980 2981 2982 2983 2984 2985 2986 2987 2988 2989 2990 2991 2992 2993 2994 2995 2996 2997 2998 2999 3000 3001 3002 3003 3004 3005 3006 3007 3008 3009 3010 3011
      default: UNIMPLEMENTED();
    }
  } else if (instr->Mask(MemBarrierFMask) == MemBarrierFixed) {
    __sync_synchronize();
  } else {
    UNIMPLEMENTED();
  }
}


bool Simulator::GetValue(const char* desc, int64_t* value) {
  int regnum = CodeFromName(desc);
  if (regnum >= 0) {
    unsigned code = regnum;
    if (code == kZeroRegCode) {
      // Catch the zero register and return 0.
      *value = 0;
      return true;
    } else if (code == kSPRegInternalCode) {
      // Translate the stack pointer code to 31, for Reg31IsStackPointer.
      code = 31;
    }
    if (desc[0] == 'w') {
      *value = wreg(code, Reg31IsStackPointer);
    } else {
      *value = xreg(code, Reg31IsStackPointer);
    }
    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;
  }
}


bool Simulator::PrintValue(const char* desc) {
3012
  if (strcmp(desc, "sp") == 0) {
3013
    DCHECK(CodeFromName(desc) == static_cast<int>(kSPRegInternalCode));
3014 3015
    PrintF(stream_, "%s sp:%s 0x%016" PRIx64 "%s\n", clr_reg_name,
           clr_reg_value, xreg(31, Reg31IsStackPointer), clr_normal);
3016
    return true;
3017
  } else if (strcmp(desc, "wsp") == 0) {
3018
    DCHECK(CodeFromName(desc) == static_cast<int>(kSPRegInternalCode));
3019 3020
    PrintF(stream_, "%s wsp:%s 0x%08" PRIx32 "%s\n", clr_reg_name,
           clr_reg_value, wreg(31, Reg31IsStackPointer), clr_normal);
3021 3022 3023 3024
    return true;
  }

  int i = CodeFromName(desc);
3025 3026 3027
  static_assert(kNumberOfRegisters == kNumberOfVRegisters,
                "Must be same number of Registers as VRegisters.");
  if (i < 0 || static_cast<unsigned>(i) >= kNumberOfVRegisters) return false;
3028 3029

  if (desc[0] == 'v') {
3030
    PrintF(stream_, "%s %s:%s 0x%016" PRIx64 "%s (%s%s:%s %g%s %s:%s %g%s)\n",
3031 3032 3033 3034
           clr_vreg_name, VRegNameForCode(i), clr_vreg_value,
           bit_cast<uint64_t>(dreg(i)), clr_normal, clr_vreg_name,
           DRegNameForCode(i), clr_vreg_value, dreg(i), clr_vreg_name,
           SRegNameForCode(i), clr_vreg_value, sreg(i), clr_normal);
3035 3036
    return true;
  } else if (desc[0] == 'd') {
3037 3038
    PrintF(stream_, "%s %s:%s %g%s\n", clr_vreg_name, DRegNameForCode(i),
           clr_vreg_value, dreg(i), clr_normal);
3039 3040
    return true;
  } else if (desc[0] == 's') {
3041 3042
    PrintF(stream_, "%s %s:%s %g%s\n", clr_vreg_name, SRegNameForCode(i),
           clr_vreg_value, sreg(i), clr_normal);
3043 3044
    return true;
  } else if (desc[0] == 'w') {
3045
    PrintF(stream_, "%s %s:%s 0x%08" PRIx32 "%s\n",
3046 3047 3048 3049 3050
        clr_reg_name, WRegNameForCode(i), clr_reg_value, wreg(i), clr_normal);
    return true;
  } else {
    // X register names have a wide variety of starting characters, but anything
    // else will be an X register.
3051
    PrintF(stream_, "%s %s:%s 0x%016" PRIx64 "%s\n",
3052 3053 3054 3055 3056 3057 3058 3059 3060 3061 3062 3063 3064 3065 3066 3067 3068 3069 3070 3071 3072 3073 3074 3075 3076 3077 3078 3079 3080 3081 3082
        clr_reg_name, XRegNameForCode(i), clr_reg_value, xreg(i), clr_normal);
    return true;
  }
}


void Simulator::Debug() {
#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];
  char* argv[3] = { cmd, arg1, arg2 };

  // Make sure to have a proper terminating character if reaching the limit.
  cmd[COMMAND_SIZE] = 0;
  arg1[ARG_SIZE] = 0;
  arg2[ARG_SIZE] = 0;

  bool done = false;
  bool cleared_log_disasm_bit = false;

  while (!done) {
    // Disassemble the next instruction to execute before doing anything else.
    PrintInstructionsAt(pc_, 1);
    // Read the command line.
    char* line = ReadLine("sim> ");
3083
    if (line == nullptr) {
3084 3085 3086 3087
      break;
    } else {
      // Repeat last command by default.
      char* last_input = last_debugger_input();
3088
      if (strcmp(line, "\n") == 0 && (last_input != nullptr)) {
3089 3090 3091 3092 3093 3094 3095 3096 3097 3098 3099 3100 3101 3102 3103 3104 3105 3106 3107 3108 3109 3110 3111 3112 3113 3114 3115 3116 3117 3118 3119 3120 3121 3122 3123 3124 3125 3126 3127 3128 3129 3130 3131 3132 3133 3134 3135 3136 3137 3138 3139 3140 3141 3142 3143 3144 3145 3146 3147 3148 3149 3150 3151 3152 3153 3154 3155 3156 3157 3158 3159 3160 3161 3162 3163 3164 3165 3166
        DeleteArray(line);
        line = last_input;
      } else {
        // Update the latest command ran
        set_last_debugger_input(line);
      }

      // Use sscanf to parse the individual parts of the command line. At the
      // moment no command expects more than two parameters.
      int argc = SScanF(line,
                        "%" XSTR(COMMAND_SIZE) "s "
                        "%" XSTR(ARG_SIZE) "s "
                        "%" XSTR(ARG_SIZE) "s",
                        cmd, arg1, arg2);

      // stepi / si ------------------------------------------------------------
      if ((strcmp(cmd, "si") == 0) || (strcmp(cmd, "stepi") == 0)) {
        // We are about to execute instructions, after which by default we
        // should increment the pc_. If it was set when reaching this debug
        // instruction, it has not been cleared because this instruction has not
        // completed yet. So clear it manually.
        pc_modified_ = false;

        if (argc == 1) {
          ExecuteInstruction();
        } else {
          int64_t number_of_instructions_to_execute = 1;
          GetValue(arg1, &number_of_instructions_to_execute);

          set_log_parameters(log_parameters() | LOG_DISASM);
          while (number_of_instructions_to_execute-- > 0) {
            ExecuteInstruction();
          }
          set_log_parameters(log_parameters() & ~LOG_DISASM);
          PrintF("\n");
        }

        // If it was necessary, the pc has already been updated or incremented
        // when executing the instruction. So we do not want it to be updated
        // again. It will be cleared when exiting.
        pc_modified_ = true;

      // next / n --------------------------------------------------------------
      } else if ((strcmp(cmd, "next") == 0) || (strcmp(cmd, "n") == 0)) {
        // Tell the simulator to break after the next executed BL.
        break_on_next_ = true;
        // Continue.
        done = true;

      // continue / cont / c ---------------------------------------------------
      } else if ((strcmp(cmd, "continue") == 0) ||
                 (strcmp(cmd, "cont") == 0) ||
                 (strcmp(cmd, "c") == 0)) {
        // Leave the debugger shell.
        done = true;

      // disassemble / disasm / di ---------------------------------------------
      } else if (strcmp(cmd, "disassemble") == 0 ||
                 strcmp(cmd, "disasm") == 0 ||
                 strcmp(cmd, "di") == 0) {
        int64_t n_of_instrs_to_disasm = 10;  // default value.
        int64_t address = reinterpret_cast<int64_t>(pc_);  // default value.
        if (argc >= 2) {  // disasm <n of instrs>
          GetValue(arg1, &n_of_instrs_to_disasm);
        }
        if (argc >= 3) {  // disasm <n of instrs> <address>
          GetValue(arg2, &address);
        }

        // Disassemble.
        PrintInstructionsAt(reinterpret_cast<Instruction*>(address),
                            n_of_instrs_to_disasm);
        PrintF("\n");

      // print / p -------------------------------------------------------------
      } else if ((strcmp(cmd, "print") == 0) || (strcmp(cmd, "p") == 0)) {
        if (argc == 2) {
          if (strcmp(arg1, "all") == 0) {
3167
            PrintRegisters();
3168
            PrintVRegisters();
3169 3170 3171 3172 3173 3174 3175 3176 3177 3178 3179 3180 3181 3182 3183 3184 3185 3186
          } else {
            if (!PrintValue(arg1)) {
              PrintF("%s unrecognized\n", arg1);
            }
          }
        } else {
          PrintF(
            "print <register>\n"
            "    Print the content of a register. (alias 'p')\n"
            "    'print all' will print all registers.\n"
            "    Use 'printobject' to get more details about the value.\n");
        }

      // printobject / po ------------------------------------------------------
      } else if ((strcmp(cmd, "printobject") == 0) ||
                 (strcmp(cmd, "po") == 0)) {
        if (argc == 2) {
          int64_t value;
3187
          StdoutStream os;
3188 3189
          if (GetValue(arg1, &value)) {
            Object* obj = reinterpret_cast<Object*>(value);
3190
            os << arg1 << ": \n";
3191
#ifdef DEBUG
3192
            obj->Print(os);
3193
            os << "\n";
3194
#else
3195
            os << Brief(obj) << "\n";
3196 3197
#endif
          } else {
3198
            os << arg1 << " unrecognized\n";
3199 3200 3201 3202 3203 3204 3205 3206 3207
          }
        } else {
          PrintF("printobject <value>\n"
                 "printobject <register>\n"
                 "    Print details about the value. (alias 'po')\n");
        }

      // stack / mem ----------------------------------------------------------
      } else if (strcmp(cmd, "stack") == 0 || strcmp(cmd, "mem") == 0) {
3208 3209
        int64_t* cur = nullptr;
        int64_t* end = nullptr;
3210 3211 3212
        int next_arg = 1;

        if (strcmp(cmd, "stack") == 0) {
3213
          cur = reinterpret_cast<int64_t*>(sp());
3214 3215 3216 3217 3218 3219 3220 3221 3222 3223 3224

        } else {  // "mem"
          int64_t value;
          if (!GetValue(arg1, &value)) {
            PrintF("%s unrecognized\n", arg1);
            continue;
          }
          cur = reinterpret_cast<int64_t*>(value);
          next_arg++;
        }

3225
        int64_t words = 0;
3226 3227 3228 3229 3230 3231 3232 3233
        if (argc == next_arg) {
          words = 10;
        } else if (argc == next_arg + 1) {
          if (!GetValue(argv[next_arg], &words)) {
            PrintF("%s unrecognized\n", argv[next_arg]);
            PrintF("Printing 10 double words by default");
            words = 10;
          }
3234 3235
        } else {
          UNREACHABLE();
3236 3237 3238 3239 3240 3241 3242 3243
        }
        end = cur + words;

        while (cur < end) {
          PrintF("  0x%016" PRIx64 ":  0x%016" PRIx64 " %10" PRId64,
                 reinterpret_cast<uint64_t>(cur), *cur, *cur);
          HeapObject* obj = reinterpret_cast<HeapObject*>(*cur);
          int64_t value = *cur;
3244
          Heap* current_heap = isolate_->heap();
3245 3246
          if (((value & 1) == 0) ||
              current_heap->ContainsSlow(obj->address())) {
3247 3248
            PrintF(" (");
            if ((value & kSmiTagMask) == 0) {
3249
              DCHECK(SmiValuesAre32Bits() || SmiValuesAre31Bits());
3250
              int32_t untagged = (value >> kSmiShift) & 0xFFFFFFFF;
3251 3252 3253 3254 3255 3256 3257 3258 3259 3260 3261 3262 3263 3264 3265 3266 3267 3268 3269 3270 3271 3272 3273 3274 3275 3276 3277 3278 3279 3280 3281 3282 3283 3284 3285 3286 3287 3288
              PrintF("smi %" PRId32, untagged);
            } else {
              obj->ShortPrint();
            }
            PrintF(")");
          }
          PrintF("\n");
          cur++;
        }

      // trace / t -------------------------------------------------------------
      } else if (strcmp(cmd, "trace") == 0 || strcmp(cmd, "t") == 0) {
        if ((log_parameters() & (LOG_DISASM | LOG_REGS)) !=
            (LOG_DISASM | LOG_REGS)) {
          PrintF("Enabling disassembly and registers tracing\n");
          set_log_parameters(log_parameters() | LOG_DISASM | LOG_REGS);
        } else {
          PrintF("Disabling disassembly and registers tracing\n");
          set_log_parameters(log_parameters() & ~(LOG_DISASM | LOG_REGS));
        }

      // break / b -------------------------------------------------------------
      } else if (strcmp(cmd, "break") == 0 || strcmp(cmd, "b") == 0) {
        if (argc == 2) {
          int64_t value;
          if (GetValue(arg1, &value)) {
            SetBreakpoint(reinterpret_cast<Instruction*>(value));
          } else {
            PrintF("%s unrecognized\n", arg1);
          }
        } else {
          ListBreakpoints();
          PrintF("Use `break <address>` to set or disable a breakpoint\n");
        }

      // gdb -------------------------------------------------------------------
      } else if (strcmp(cmd, "gdb") == 0) {
        PrintF("Relinquishing control to gdb.\n");
3289
        base::OS::DebugBreak();
3290 3291 3292 3293 3294 3295 3296 3297 3298 3299 3300 3301 3302 3303 3304 3305 3306 3307 3308 3309 3310 3311 3312 3313 3314 3315 3316 3317 3318 3319 3320 3321 3322 3323 3324 3325 3326 3327 3328 3329 3330 3331 3332 3333 3334 3335 3336 3337 3338 3339 3340 3341 3342 3343 3344 3345 3346 3347 3348 3349 3350 3351 3352 3353 3354 3355 3356
        PrintF("Regaining control from gdb.\n");

      // sysregs ---------------------------------------------------------------
      } else if (strcmp(cmd, "sysregs") == 0) {
        PrintSystemRegisters();

      // help / h --------------------------------------------------------------
      } else if (strcmp(cmd, "help") == 0 || strcmp(cmd, "h") == 0) {
        PrintF(
          "stepi / si\n"
          "    stepi <n>\n"
          "    Step <n> instructions.\n"
          "next / n\n"
          "    Continue execution until a BL instruction is reached.\n"
          "    At this point a breakpoint is set just after this BL.\n"
          "    Then execution is resumed. It will probably later hit the\n"
          "    breakpoint just set.\n"
          "continue / cont / c\n"
          "    Continue execution from here.\n"
          "disassemble / disasm / di\n"
          "    disassemble <n> <address>\n"
          "    Disassemble <n> instructions from current <address>.\n"
          "    By default <n> is 20 and <address> is the current pc.\n"
          "print / p\n"
          "    print <register>\n"
          "    Print the content of a register.\n"
          "    'print all' will print all registers.\n"
          "    Use 'printobject' to get more details about the value.\n"
          "printobject / po\n"
          "    printobject <value>\n"
          "    printobject <register>\n"
          "    Print details about the value.\n"
          "stack\n"
          "    stack [<words>]\n"
          "    Dump stack content, default dump 10 words\n"
          "mem\n"
          "    mem <address> [<words>]\n"
          "    Dump memory content, default dump 10 words\n"
          "trace / t\n"
          "    Toggle disassembly and register tracing\n"
          "break / b\n"
          "    break : list all breakpoints\n"
          "    break <address> : set / enable / disable a breakpoint.\n"
          "gdb\n"
          "    Enter gdb.\n"
          "sysregs\n"
          "    Print all system registers (including NZCV).\n");
      } else {
        PrintF("Unknown command: %s\n", cmd);
        PrintF("Use 'help' for more information.\n");
      }
    }
    if (cleared_log_disasm_bit == true) {
      set_log_parameters(log_parameters_ | LOG_DISASM);
    }
  }
}


void Simulator::VisitException(Instruction* instr) {
  switch (instr->Mask(ExceptionMask)) {
    case HLT: {
      if (instr->ImmException() == kImmExceptionIsDebug) {
        // Read the arguments encoded inline in the instruction stream.
        uint32_t code;
        uint32_t parameters;

3357 3358 3359 3360 3361 3362 3363 3364 3365
        memcpy(&code,
               pc_->InstructionAtOffset(kDebugCodeOffset),
               sizeof(code));
        memcpy(&parameters,
               pc_->InstructionAtOffset(kDebugParamsOffset),
               sizeof(parameters));
        char const *message =
            reinterpret_cast<char const*>(
                pc_->InstructionAtOffset(kDebugMessageOffset));
3366 3367 3368 3369 3370

        // Always print something when we hit a debug point that breaks.
        // We are going to break, so printing something is not an issue in
        // terms of speed.
        if (FLAG_trace_sim_messages || FLAG_trace_sim || (parameters & BREAK)) {
3371
          if (message != nullptr) {
3372
            PrintF(stream_,
3373
                   "# %sDebugger hit %d: %s%s%s\n",
3374 3375 3376 3377 3378 3379
                   clr_debug_number,
                   code,
                   clr_debug_message,
                   message,
                   clr_normal);
          } else {
3380
            PrintF(stream_,
3381
                   "# %sDebugger hit %d.%s\n",
3382 3383 3384 3385 3386 3387 3388 3389 3390 3391 3392 3393
                   clr_debug_number,
                   code,
                   clr_normal);
          }
        }

        // Other options.
        switch (parameters & kDebuggerTracingDirectivesMask) {
          case TRACE_ENABLE:
            set_log_parameters(log_parameters() | parameters);
            if (parameters & LOG_SYS_REGS) { PrintSystemRegisters(); }
            if (parameters & LOG_REGS) { PrintRegisters(); }
3394 3395 3396
            if (parameters & LOG_VREGS) {
              PrintVRegisters();
            }
3397 3398 3399 3400 3401 3402 3403 3404 3405
            break;
          case TRACE_DISABLE:
            set_log_parameters(log_parameters() & ~parameters);
            break;
          case TRACE_OVERRIDE:
            set_log_parameters(parameters);
            break;
          default:
            // We don't support a one-shot LOG_DISASM.
3406
            DCHECK_EQ(parameters & LOG_DISASM, 0);
3407 3408 3409
            // Don't print information that is already being traced.
            parameters &= ~log_parameters();
            // Print the requested information.
3410 3411
            if (parameters & LOG_SYS_REGS) PrintSystemRegisters();
            if (parameters & LOG_REGS) PrintRegisters();
3412
            if (parameters & LOG_VREGS) PrintVRegisters();
3413 3414 3415 3416
        }

        // The stop parameters are inlined in the code. Skip them:
        //  - Skip to the end of the message string.
3417
        size_t size = kDebugMessageOffset + strlen(message) + 1;
3418
        pc_ = pc_->InstructionAtOffset(RoundUp(size, kInstrSize));
3419
        //  - Verify that the unreachable marker is present.
3420
        DCHECK(pc_->Mask(ExceptionMask) == HLT);
3421
        DCHECK_EQ(pc_->ImmException(), kImmExceptionIsUnreachable);
3422
        //  - Skip past the unreachable marker.
3423
        set_pc(pc_->following());
3424 3425 3426 3427 3428

        // Check if the debugger should break.
        if (parameters & BREAK) Debug();

      } else if (instr->ImmException() == kImmExceptionIsRedirectedCall) {
3429
        DoRuntimeCall(instr);
3430
      } else if (instr->ImmException() == kImmExceptionIsPrintf) {
3431
        DoPrintf(instr);
3432 3433 3434 3435 3436 3437 3438

      } else if (instr->ImmException() == kImmExceptionIsUnreachable) {
        fprintf(stream_, "Hit UNREACHABLE marker at PC=%p.\n",
                reinterpret_cast<void*>(pc_));
        abort();

      } else {
3439
        base::OS::DebugBreak();
3440 3441 3442
      }
      break;
    }
3443 3444 3445
    case BRK:
      base::OS::DebugBreak();
      break;
3446 3447 3448 3449 3450
    default:
      UNIMPLEMENTED();
  }
}

3451 3452 3453 3454 3455 3456 3457 3458 3459 3460 3461 3462 3463 3464 3465 3466 3467 3468 3469 3470 3471 3472 3473 3474 3475 3476 3477 3478 3479 3480 3481 3482 3483 3484 3485 3486 3487 3488 3489 3490 3491 3492 3493 3494 3495 3496 3497 3498 3499 3500 3501 3502 3503 3504 3505 3506 3507 3508 3509 3510 3511 3512 3513 3514 3515 3516 3517 3518 3519 3520 3521 3522 3523 3524 3525 3526 3527 3528 3529 3530 3531 3532 3533 3534 3535 3536 3537 3538 3539 3540 3541 3542 3543 3544 3545 3546 3547 3548 3549 3550 3551 3552 3553 3554 3555 3556 3557 3558 3559 3560 3561 3562 3563 3564 3565 3566 3567 3568 3569 3570 3571 3572 3573 3574 3575 3576 3577 3578 3579 3580 3581 3582 3583 3584 3585 3586 3587 3588 3589 3590 3591 3592 3593 3594 3595 3596 3597 3598 3599 3600 3601 3602 3603 3604 3605 3606 3607 3608 3609 3610 3611 3612 3613 3614 3615 3616 3617 3618 3619 3620 3621 3622 3623 3624 3625 3626 3627 3628 3629 3630 3631 3632 3633 3634 3635 3636 3637 3638 3639 3640 3641 3642 3643 3644 3645 3646 3647 3648 3649 3650 3651 3652 3653 3654 3655 3656 3657 3658 3659 3660 3661 3662 3663 3664 3665 3666 3667 3668 3669 3670 3671 3672 3673 3674 3675 3676 3677 3678 3679 3680 3681 3682 3683 3684 3685 3686 3687 3688 3689 3690 3691 3692 3693 3694 3695 3696 3697 3698 3699 3700 3701 3702 3703 3704 3705 3706 3707 3708 3709 3710 3711 3712 3713 3714 3715 3716 3717 3718 3719 3720 3721 3722 3723 3724 3725 3726 3727 3728 3729 3730 3731 3732 3733 3734 3735 3736 3737 3738 3739 3740 3741 3742 3743 3744 3745 3746 3747 3748 3749 3750 3751 3752 3753 3754 3755 3756 3757 3758 3759 3760 3761 3762 3763 3764 3765 3766 3767 3768 3769 3770 3771 3772 3773 3774 3775 3776 3777 3778 3779 3780 3781 3782 3783 3784 3785 3786 3787 3788 3789 3790 3791 3792 3793 3794 3795 3796 3797 3798 3799 3800 3801 3802 3803 3804 3805 3806 3807 3808 3809 3810 3811 3812 3813 3814 3815 3816 3817 3818 3819 3820 3821 3822 3823 3824 3825 3826 3827 3828 3829 3830 3831 3832 3833 3834 3835 3836 3837 3838 3839 3840 3841 3842 3843 3844 3845 3846 3847 3848 3849 3850 3851 3852 3853 3854 3855 3856 3857 3858 3859 3860 3861 3862 3863 3864 3865 3866 3867 3868 3869 3870 3871 3872 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 3916 3917 3918 3919 3920 3921 3922 3923 3924 3925 3926 3927 3928 3929 3930 3931 3932 3933 3934 3935 3936 3937 3938 3939 3940 3941 3942 3943 3944 3945 3946 3947 3948 3949 3950 3951 3952 3953 3954 3955 3956 3957 3958 3959 3960 3961 3962 3963 3964 3965 3966 3967 3968 3969 3970 3971 3972 3973 3974 3975 3976 3977 3978 3979 3980 3981 3982 3983 3984 3985 3986 3987 3988 3989 3990 3991 3992 3993 3994 3995 3996 3997 3998 3999 4000 4001 4002 4003 4004 4005 4006 4007 4008 4009 4010 4011 4012 4013 4014 4015 4016 4017 4018 4019 4020 4021 4022 4023 4024 4025 4026 4027 4028 4029 4030 4031 4032 4033 4034 4035 4036 4037 4038 4039 4040 4041 4042 4043 4044 4045 4046 4047 4048 4049 4050 4051 4052 4053 4054 4055 4056 4057 4058 4059 4060 4061 4062 4063 4064 4065 4066 4067 4068 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 4117 4118 4119 4120 4121 4122 4123 4124 4125 4126 4127 4128 4129 4130 4131 4132 4133 4134 4135 4136 4137 4138 4139 4140 4141 4142 4143 4144 4145 4146 4147 4148 4149 4150 4151 4152 4153 4154 4155 4156 4157 4158 4159 4160 4161 4162 4163 4164 4165 4166 4167 4168 4169 4170 4171 4172 4173 4174 4175 4176 4177 4178 4179 4180 4181 4182 4183 4184 4185 4186 4187 4188 4189 4190 4191 4192 4193 4194 4195 4196 4197 4198 4199 4200 4201 4202 4203 4204 4205 4206 4207
void Simulator::VisitNEON2RegMisc(Instruction* instr) {
  NEONFormatDecoder nfd(instr);
  VectorFormat vf = nfd.GetVectorFormat();

  // Format mapping for "long pair" instructions, [su]addlp, [su]adalp.
  static const NEONFormatMap map_lp = {
      {23, 22, 30}, {NF_4H, NF_8H, NF_2S, NF_4S, NF_1D, NF_2D}};
  VectorFormat vf_lp = nfd.GetVectorFormat(&map_lp);

  static const NEONFormatMap map_fcvtl = {{22}, {NF_4S, NF_2D}};
  VectorFormat vf_fcvtl = nfd.GetVectorFormat(&map_fcvtl);

  static const NEONFormatMap map_fcvtn = {{22, 30},
                                          {NF_4H, NF_8H, NF_2S, NF_4S}};
  VectorFormat vf_fcvtn = nfd.GetVectorFormat(&map_fcvtn);

  SimVRegister& rd = vreg(instr->Rd());
  SimVRegister& rn = vreg(instr->Rn());

  if (instr->Mask(NEON2RegMiscOpcode) <= NEON_NEG_opcode) {
    // These instructions all use a two bit size field, except NOT and RBIT,
    // which use the field to encode the operation.
    switch (instr->Mask(NEON2RegMiscMask)) {
      case NEON_REV64:
        rev64(vf, rd, rn);
        break;
      case NEON_REV32:
        rev32(vf, rd, rn);
        break;
      case NEON_REV16:
        rev16(vf, rd, rn);
        break;
      case NEON_SUQADD:
        suqadd(vf, rd, rn);
        break;
      case NEON_USQADD:
        usqadd(vf, rd, rn);
        break;
      case NEON_CLS:
        cls(vf, rd, rn);
        break;
      case NEON_CLZ:
        clz(vf, rd, rn);
        break;
      case NEON_CNT:
        cnt(vf, rd, rn);
        break;
      case NEON_SQABS:
        abs(vf, rd, rn).SignedSaturate(vf);
        break;
      case NEON_SQNEG:
        neg(vf, rd, rn).SignedSaturate(vf);
        break;
      case NEON_CMGT_zero:
        cmp(vf, rd, rn, 0, gt);
        break;
      case NEON_CMGE_zero:
        cmp(vf, rd, rn, 0, ge);
        break;
      case NEON_CMEQ_zero:
        cmp(vf, rd, rn, 0, eq);
        break;
      case NEON_CMLE_zero:
        cmp(vf, rd, rn, 0, le);
        break;
      case NEON_CMLT_zero:
        cmp(vf, rd, rn, 0, lt);
        break;
      case NEON_ABS:
        abs(vf, rd, rn);
        break;
      case NEON_NEG:
        neg(vf, rd, rn);
        break;
      case NEON_SADDLP:
        saddlp(vf_lp, rd, rn);
        break;
      case NEON_UADDLP:
        uaddlp(vf_lp, rd, rn);
        break;
      case NEON_SADALP:
        sadalp(vf_lp, rd, rn);
        break;
      case NEON_UADALP:
        uadalp(vf_lp, rd, rn);
        break;
      case NEON_RBIT_NOT:
        vf = nfd.GetVectorFormat(nfd.LogicalFormatMap());
        switch (instr->FPType()) {
          case 0:
            not_(vf, rd, rn);
            break;
          case 1:
            rbit(vf, rd, rn);
            break;
          default:
            UNIMPLEMENTED();
        }
        break;
    }
  } else {
    VectorFormat fpf = nfd.GetVectorFormat(nfd.FPFormatMap());
    FPRounding fpcr_rounding = static_cast<FPRounding>(fpcr().RMode());
    bool inexact_exception = false;

    // These instructions all use a one bit size field, except XTN, SQXTUN,
    // SHLL, SQXTN and UQXTN, which use a two bit size field.
    switch (instr->Mask(NEON2RegMiscFPMask)) {
      case NEON_FABS:
        fabs_(fpf, rd, rn);
        return;
      case NEON_FNEG:
        fneg(fpf, rd, rn);
        return;
      case NEON_FSQRT:
        fsqrt(fpf, rd, rn);
        return;
      case NEON_FCVTL:
        if (instr->Mask(NEON_Q)) {
          fcvtl2(vf_fcvtl, rd, rn);
        } else {
          fcvtl(vf_fcvtl, rd, rn);
        }
        return;
      case NEON_FCVTN:
        if (instr->Mask(NEON_Q)) {
          fcvtn2(vf_fcvtn, rd, rn);
        } else {
          fcvtn(vf_fcvtn, rd, rn);
        }
        return;
      case NEON_FCVTXN:
        if (instr->Mask(NEON_Q)) {
          fcvtxn2(vf_fcvtn, rd, rn);
        } else {
          fcvtxn(vf_fcvtn, rd, rn);
        }
        return;

      // The following instructions break from the switch statement, rather
      // than return.
      case NEON_FRINTI:
        break;  // Use FPCR rounding mode.
      case NEON_FRINTX:
        inexact_exception = true;
        break;
      case NEON_FRINTA:
        fpcr_rounding = FPTieAway;
        break;
      case NEON_FRINTM:
        fpcr_rounding = FPNegativeInfinity;
        break;
      case NEON_FRINTN:
        fpcr_rounding = FPTieEven;
        break;
      case NEON_FRINTP:
        fpcr_rounding = FPPositiveInfinity;
        break;
      case NEON_FRINTZ:
        fpcr_rounding = FPZero;
        break;

      // The remaining cases return to the caller.
      case NEON_FCVTNS:
        fcvts(fpf, rd, rn, FPTieEven);
        return;
      case NEON_FCVTNU:
        fcvtu(fpf, rd, rn, FPTieEven);
        return;
      case NEON_FCVTPS:
        fcvts(fpf, rd, rn, FPPositiveInfinity);
        return;
      case NEON_FCVTPU:
        fcvtu(fpf, rd, rn, FPPositiveInfinity);
        return;
      case NEON_FCVTMS:
        fcvts(fpf, rd, rn, FPNegativeInfinity);
        return;
      case NEON_FCVTMU:
        fcvtu(fpf, rd, rn, FPNegativeInfinity);
        return;
      case NEON_FCVTZS:
        fcvts(fpf, rd, rn, FPZero);
        return;
      case NEON_FCVTZU:
        fcvtu(fpf, rd, rn, FPZero);
        return;
      case NEON_FCVTAS:
        fcvts(fpf, rd, rn, FPTieAway);
        return;
      case NEON_FCVTAU:
        fcvtu(fpf, rd, rn, FPTieAway);
        return;
      case NEON_SCVTF:
        scvtf(fpf, rd, rn, 0, fpcr_rounding);
        return;
      case NEON_UCVTF:
        ucvtf(fpf, rd, rn, 0, fpcr_rounding);
        return;
      case NEON_URSQRTE:
        ursqrte(fpf, rd, rn);
        return;
      case NEON_URECPE:
        urecpe(fpf, rd, rn);
        return;
      case NEON_FRSQRTE:
        frsqrte(fpf, rd, rn);
        return;
      case NEON_FRECPE:
        frecpe(fpf, rd, rn, fpcr_rounding);
        return;
      case NEON_FCMGT_zero:
        fcmp_zero(fpf, rd, rn, gt);
        return;
      case NEON_FCMGE_zero:
        fcmp_zero(fpf, rd, rn, ge);
        return;
      case NEON_FCMEQ_zero:
        fcmp_zero(fpf, rd, rn, eq);
        return;
      case NEON_FCMLE_zero:
        fcmp_zero(fpf, rd, rn, le);
        return;
      case NEON_FCMLT_zero:
        fcmp_zero(fpf, rd, rn, lt);
        return;
      default:
        if ((NEON_XTN_opcode <= instr->Mask(NEON2RegMiscOpcode)) &&
            (instr->Mask(NEON2RegMiscOpcode) <= NEON_UQXTN_opcode)) {
          switch (instr->Mask(NEON2RegMiscMask)) {
            case NEON_XTN:
              xtn(vf, rd, rn);
              return;
            case NEON_SQXTN:
              sqxtn(vf, rd, rn);
              return;
            case NEON_UQXTN:
              uqxtn(vf, rd, rn);
              return;
            case NEON_SQXTUN:
              sqxtun(vf, rd, rn);
              return;
            case NEON_SHLL:
              vf = nfd.GetVectorFormat(nfd.LongIntegerFormatMap());
              if (instr->Mask(NEON_Q)) {
                shll2(vf, rd, rn);
              } else {
                shll(vf, rd, rn);
              }
              return;
            default:
              UNIMPLEMENTED();
          }
        } else {
          UNIMPLEMENTED();
        }
    }

    // Only FRINT* instructions fall through the switch above.
    frint(fpf, rd, rn, fpcr_rounding, inexact_exception);
  }
}

void Simulator::VisitNEON3Same(Instruction* instr) {
  NEONFormatDecoder nfd(instr);
  SimVRegister& rd = vreg(instr->Rd());
  SimVRegister& rn = vreg(instr->Rn());
  SimVRegister& rm = vreg(instr->Rm());

  if (instr->Mask(NEON3SameLogicalFMask) == NEON3SameLogicalFixed) {
    VectorFormat vf = nfd.GetVectorFormat(nfd.LogicalFormatMap());
    switch (instr->Mask(NEON3SameLogicalMask)) {
      case NEON_AND:
        and_(vf, rd, rn, rm);
        break;
      case NEON_ORR:
        orr(vf, rd, rn, rm);
        break;
      case NEON_ORN:
        orn(vf, rd, rn, rm);
        break;
      case NEON_EOR:
        eor(vf, rd, rn, rm);
        break;
      case NEON_BIC:
        bic(vf, rd, rn, rm);
        break;
      case NEON_BIF:
        bif(vf, rd, rn, rm);
        break;
      case NEON_BIT:
        bit(vf, rd, rn, rm);
        break;
      case NEON_BSL:
        bsl(vf, rd, rn, rm);
        break;
      default:
        UNIMPLEMENTED();
    }
  } else if (instr->Mask(NEON3SameFPFMask) == NEON3SameFPFixed) {
    VectorFormat vf = nfd.GetVectorFormat(nfd.FPFormatMap());
    switch (instr->Mask(NEON3SameFPMask)) {
      case NEON_FADD:
        fadd(vf, rd, rn, rm);
        break;
      case NEON_FSUB:
        fsub(vf, rd, rn, rm);
        break;
      case NEON_FMUL:
        fmul(vf, rd, rn, rm);
        break;
      case NEON_FDIV:
        fdiv(vf, rd, rn, rm);
        break;
      case NEON_FMAX:
        fmax(vf, rd, rn, rm);
        break;
      case NEON_FMIN:
        fmin(vf, rd, rn, rm);
        break;
      case NEON_FMAXNM:
        fmaxnm(vf, rd, rn, rm);
        break;
      case NEON_FMINNM:
        fminnm(vf, rd, rn, rm);
        break;
      case NEON_FMLA:
        fmla(vf, rd, rn, rm);
        break;
      case NEON_FMLS:
        fmls(vf, rd, rn, rm);
        break;
      case NEON_FMULX:
        fmulx(vf, rd, rn, rm);
        break;
      case NEON_FACGE:
        fabscmp(vf, rd, rn, rm, ge);
        break;
      case NEON_FACGT:
        fabscmp(vf, rd, rn, rm, gt);
        break;
      case NEON_FCMEQ:
        fcmp(vf, rd, rn, rm, eq);
        break;
      case NEON_FCMGE:
        fcmp(vf, rd, rn, rm, ge);
        break;
      case NEON_FCMGT:
        fcmp(vf, rd, rn, rm, gt);
        break;
      case NEON_FRECPS:
        frecps(vf, rd, rn, rm);
        break;
      case NEON_FRSQRTS:
        frsqrts(vf, rd, rn, rm);
        break;
      case NEON_FABD:
        fabd(vf, rd, rn, rm);
        break;
      case NEON_FADDP:
        faddp(vf, rd, rn, rm);
        break;
      case NEON_FMAXP:
        fmaxp(vf, rd, rn, rm);
        break;
      case NEON_FMAXNMP:
        fmaxnmp(vf, rd, rn, rm);
        break;
      case NEON_FMINP:
        fminp(vf, rd, rn, rm);
        break;
      case NEON_FMINNMP:
        fminnmp(vf, rd, rn, rm);
        break;
      default:
        UNIMPLEMENTED();
    }
  } else {
    VectorFormat vf = nfd.GetVectorFormat();
    switch (instr->Mask(NEON3SameMask)) {
      case NEON_ADD:
        add(vf, rd, rn, rm);
        break;
      case NEON_ADDP:
        addp(vf, rd, rn, rm);
        break;
      case NEON_CMEQ:
        cmp(vf, rd, rn, rm, eq);
        break;
      case NEON_CMGE:
        cmp(vf, rd, rn, rm, ge);
        break;
      case NEON_CMGT:
        cmp(vf, rd, rn, rm, gt);
        break;
      case NEON_CMHI:
        cmp(vf, rd, rn, rm, hi);
        break;
      case NEON_CMHS:
        cmp(vf, rd, rn, rm, hs);
        break;
      case NEON_CMTST:
        cmptst(vf, rd, rn, rm);
        break;
      case NEON_MLS:
        mls(vf, rd, rn, rm);
        break;
      case NEON_MLA:
        mla(vf, rd, rn, rm);
        break;
      case NEON_MUL:
        mul(vf, rd, rn, rm);
        break;
      case NEON_PMUL:
        pmul(vf, rd, rn, rm);
        break;
      case NEON_SMAX:
        smax(vf, rd, rn, rm);
        break;
      case NEON_SMAXP:
        smaxp(vf, rd, rn, rm);
        break;
      case NEON_SMIN:
        smin(vf, rd, rn, rm);
        break;
      case NEON_SMINP:
        sminp(vf, rd, rn, rm);
        break;
      case NEON_SUB:
        sub(vf, rd, rn, rm);
        break;
      case NEON_UMAX:
        umax(vf, rd, rn, rm);
        break;
      case NEON_UMAXP:
        umaxp(vf, rd, rn, rm);
        break;
      case NEON_UMIN:
        umin(vf, rd, rn, rm);
        break;
      case NEON_UMINP:
        uminp(vf, rd, rn, rm);
        break;
      case NEON_SSHL:
        sshl(vf, rd, rn, rm);
        break;
      case NEON_USHL:
        ushl(vf, rd, rn, rm);
        break;
      case NEON_SABD:
        AbsDiff(vf, rd, rn, rm, true);
        break;
      case NEON_UABD:
        AbsDiff(vf, rd, rn, rm, false);
        break;
      case NEON_SABA:
        saba(vf, rd, rn, rm);
        break;
      case NEON_UABA:
        uaba(vf, rd, rn, rm);
        break;
      case NEON_UQADD:
        add(vf, rd, rn, rm).UnsignedSaturate(vf);
        break;
      case NEON_SQADD:
        add(vf, rd, rn, rm).SignedSaturate(vf);
        break;
      case NEON_UQSUB:
        sub(vf, rd, rn, rm).UnsignedSaturate(vf);
        break;
      case NEON_SQSUB:
        sub(vf, rd, rn, rm).SignedSaturate(vf);
        break;
      case NEON_SQDMULH:
        sqdmulh(vf, rd, rn, rm);
        break;
      case NEON_SQRDMULH:
        sqrdmulh(vf, rd, rn, rm);
        break;
      case NEON_UQSHL:
        ushl(vf, rd, rn, rm).UnsignedSaturate(vf);
        break;
      case NEON_SQSHL:
        sshl(vf, rd, rn, rm).SignedSaturate(vf);
        break;
      case NEON_URSHL:
        ushl(vf, rd, rn, rm).Round(vf);
        break;
      case NEON_SRSHL:
        sshl(vf, rd, rn, rm).Round(vf);
        break;
      case NEON_UQRSHL:
        ushl(vf, rd, rn, rm).Round(vf).UnsignedSaturate(vf);
        break;
      case NEON_SQRSHL:
        sshl(vf, rd, rn, rm).Round(vf).SignedSaturate(vf);
        break;
      case NEON_UHADD:
        add(vf, rd, rn, rm).Uhalve(vf);
        break;
      case NEON_URHADD:
        add(vf, rd, rn, rm).Uhalve(vf).Round(vf);
        break;
      case NEON_SHADD:
        add(vf, rd, rn, rm).Halve(vf);
        break;
      case NEON_SRHADD:
        add(vf, rd, rn, rm).Halve(vf).Round(vf);
        break;
      case NEON_UHSUB:
        sub(vf, rd, rn, rm).Uhalve(vf);
        break;
      case NEON_SHSUB:
        sub(vf, rd, rn, rm).Halve(vf);
        break;
      default:
        UNIMPLEMENTED();
    }
  }
}

void Simulator::VisitNEON3Different(Instruction* instr) {
  NEONFormatDecoder nfd(instr);
  VectorFormat vf = nfd.GetVectorFormat();
  VectorFormat vf_l = nfd.GetVectorFormat(nfd.LongIntegerFormatMap());

  SimVRegister& rd = vreg(instr->Rd());
  SimVRegister& rn = vreg(instr->Rn());
  SimVRegister& rm = vreg(instr->Rm());

  switch (instr->Mask(NEON3DifferentMask)) {
    case NEON_PMULL:
      pmull(vf_l, rd, rn, rm);
      break;
    case NEON_PMULL2:
      pmull2(vf_l, rd, rn, rm);
      break;
    case NEON_UADDL:
      uaddl(vf_l, rd, rn, rm);
      break;
    case NEON_UADDL2:
      uaddl2(vf_l, rd, rn, rm);
      break;
    case NEON_SADDL:
      saddl(vf_l, rd, rn, rm);
      break;
    case NEON_SADDL2:
      saddl2(vf_l, rd, rn, rm);
      break;
    case NEON_USUBL:
      usubl(vf_l, rd, rn, rm);
      break;
    case NEON_USUBL2:
      usubl2(vf_l, rd, rn, rm);
      break;
    case NEON_SSUBL:
      ssubl(vf_l, rd, rn, rm);
      break;
    case NEON_SSUBL2:
      ssubl2(vf_l, rd, rn, rm);
      break;
    case NEON_SABAL:
      sabal(vf_l, rd, rn, rm);
      break;
    case NEON_SABAL2:
      sabal2(vf_l, rd, rn, rm);
      break;
    case NEON_UABAL:
      uabal(vf_l, rd, rn, rm);
      break;
    case NEON_UABAL2:
      uabal2(vf_l, rd, rn, rm);
      break;
    case NEON_SABDL:
      sabdl(vf_l, rd, rn, rm);
      break;
    case NEON_SABDL2:
      sabdl2(vf_l, rd, rn, rm);
      break;
    case NEON_UABDL:
      uabdl(vf_l, rd, rn, rm);
      break;
    case NEON_UABDL2:
      uabdl2(vf_l, rd, rn, rm);
      break;
    case NEON_SMLAL:
      smlal(vf_l, rd, rn, rm);
      break;
    case NEON_SMLAL2:
      smlal2(vf_l, rd, rn, rm);
      break;
    case NEON_UMLAL:
      umlal(vf_l, rd, rn, rm);
      break;
    case NEON_UMLAL2:
      umlal2(vf_l, rd, rn, rm);
      break;
    case NEON_SMLSL:
      smlsl(vf_l, rd, rn, rm);
      break;
    case NEON_SMLSL2:
      smlsl2(vf_l, rd, rn, rm);
      break;
    case NEON_UMLSL:
      umlsl(vf_l, rd, rn, rm);
      break;
    case NEON_UMLSL2:
      umlsl2(vf_l, rd, rn, rm);
      break;
    case NEON_SMULL:
      smull(vf_l, rd, rn, rm);
      break;
    case NEON_SMULL2:
      smull2(vf_l, rd, rn, rm);
      break;
    case NEON_UMULL:
      umull(vf_l, rd, rn, rm);
      break;
    case NEON_UMULL2:
      umull2(vf_l, rd, rn, rm);
      break;
    case NEON_SQDMLAL:
      sqdmlal(vf_l, rd, rn, rm);
      break;
    case NEON_SQDMLAL2:
      sqdmlal2(vf_l, rd, rn, rm);
      break;
    case NEON_SQDMLSL:
      sqdmlsl(vf_l, rd, rn, rm);
      break;
    case NEON_SQDMLSL2:
      sqdmlsl2(vf_l, rd, rn, rm);
      break;
    case NEON_SQDMULL:
      sqdmull(vf_l, rd, rn, rm);
      break;
    case NEON_SQDMULL2:
      sqdmull2(vf_l, rd, rn, rm);
      break;
    case NEON_UADDW:
      uaddw(vf_l, rd, rn, rm);
      break;
    case NEON_UADDW2:
      uaddw2(vf_l, rd, rn, rm);
      break;
    case NEON_SADDW:
      saddw(vf_l, rd, rn, rm);
      break;
    case NEON_SADDW2:
      saddw2(vf_l, rd, rn, rm);
      break;
    case NEON_USUBW:
      usubw(vf_l, rd, rn, rm);
      break;
    case NEON_USUBW2:
      usubw2(vf_l, rd, rn, rm);
      break;
    case NEON_SSUBW:
      ssubw(vf_l, rd, rn, rm);
      break;
    case NEON_SSUBW2:
      ssubw2(vf_l, rd, rn, rm);
      break;
    case NEON_ADDHN:
      addhn(vf, rd, rn, rm);
      break;
    case NEON_ADDHN2:
      addhn2(vf, rd, rn, rm);
      break;
    case NEON_RADDHN:
      raddhn(vf, rd, rn, rm);
      break;
    case NEON_RADDHN2:
      raddhn2(vf, rd, rn, rm);
      break;
    case NEON_SUBHN:
      subhn(vf, rd, rn, rm);
      break;
    case NEON_SUBHN2:
      subhn2(vf, rd, rn, rm);
      break;
    case NEON_RSUBHN:
      rsubhn(vf, rd, rn, rm);
      break;
    case NEON_RSUBHN2:
      rsubhn2(vf, rd, rn, rm);
      break;
    default:
      UNIMPLEMENTED();
  }
}

void Simulator::VisitNEONAcrossLanes(Instruction* instr) {
  NEONFormatDecoder nfd(instr);

  SimVRegister& rd = vreg(instr->Rd());
  SimVRegister& rn = vreg(instr->Rn());

  // The input operand's VectorFormat is passed for these instructions.
  if (instr->Mask(NEONAcrossLanesFPFMask) == NEONAcrossLanesFPFixed) {
    VectorFormat vf = nfd.GetVectorFormat(nfd.FPFormatMap());

    switch (instr->Mask(NEONAcrossLanesFPMask)) {
      case NEON_FMAXV:
        fmaxv(vf, rd, rn);
        break;
      case NEON_FMINV:
        fminv(vf, rd, rn);
        break;
      case NEON_FMAXNMV:
        fmaxnmv(vf, rd, rn);
        break;
      case NEON_FMINNMV:
        fminnmv(vf, rd, rn);
        break;
      default:
        UNIMPLEMENTED();
    }
  } else {
    VectorFormat vf = nfd.GetVectorFormat();

    switch (instr->Mask(NEONAcrossLanesMask)) {
      case NEON_ADDV:
        addv(vf, rd, rn);
        break;
      case NEON_SMAXV:
        smaxv(vf, rd, rn);
        break;
      case NEON_SMINV:
        sminv(vf, rd, rn);
        break;
      case NEON_UMAXV:
        umaxv(vf, rd, rn);
        break;
      case NEON_UMINV:
        uminv(vf, rd, rn);
        break;
      case NEON_SADDLV:
        saddlv(vf, rd, rn);
        break;
      case NEON_UADDLV:
        uaddlv(vf, rd, rn);
        break;
      default:
        UNIMPLEMENTED();
    }
  }
}

void Simulator::VisitNEONByIndexedElement(Instruction* instr) {
  NEONFormatDecoder nfd(instr);
  VectorFormat vf_r = nfd.GetVectorFormat();
  VectorFormat vf = nfd.GetVectorFormat(nfd.LongIntegerFormatMap());

  SimVRegister& rd = vreg(instr->Rd());
  SimVRegister& rn = vreg(instr->Rn());

4208
  ByElementOp Op = nullptr;
4209 4210 4211 4212

  int rm_reg = instr->Rm();
  int index = (instr->NEONH() << 1) | instr->NEONL();
  if (instr->NEONSize() == 1) {
4213
    rm_reg &= 0xF;
4214 4215 4216 4217 4218 4219 4220 4221 4222 4223 4224 4225 4226 4227 4228 4229 4230 4231 4232 4233 4234 4235 4236 4237 4238 4239 4240 4241 4242 4243 4244 4245 4246 4247 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 4281 4282 4283 4284 4285 4286 4287 4288 4289 4290 4291 4292 4293 4294 4295 4296 4297 4298 4299 4300 4301 4302 4303 4304 4305 4306 4307 4308 4309 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 4391 4392 4393 4394 4395 4396 4397 4398 4399 4400 4401 4402 4403 4404 4405 4406 4407 4408 4409 4410 4411
    index = (index << 1) | instr->NEONM();
  }

  switch (instr->Mask(NEONByIndexedElementMask)) {
    case NEON_MUL_byelement:
      Op = &Simulator::mul;
      vf = vf_r;
      break;
    case NEON_MLA_byelement:
      Op = &Simulator::mla;
      vf = vf_r;
      break;
    case NEON_MLS_byelement:
      Op = &Simulator::mls;
      vf = vf_r;
      break;
    case NEON_SQDMULH_byelement:
      Op = &Simulator::sqdmulh;
      vf = vf_r;
      break;
    case NEON_SQRDMULH_byelement:
      Op = &Simulator::sqrdmulh;
      vf = vf_r;
      break;
    case NEON_SMULL_byelement:
      if (instr->Mask(NEON_Q)) {
        Op = &Simulator::smull2;
      } else {
        Op = &Simulator::smull;
      }
      break;
    case NEON_UMULL_byelement:
      if (instr->Mask(NEON_Q)) {
        Op = &Simulator::umull2;
      } else {
        Op = &Simulator::umull;
      }
      break;
    case NEON_SMLAL_byelement:
      if (instr->Mask(NEON_Q)) {
        Op = &Simulator::smlal2;
      } else {
        Op = &Simulator::smlal;
      }
      break;
    case NEON_UMLAL_byelement:
      if (instr->Mask(NEON_Q)) {
        Op = &Simulator::umlal2;
      } else {
        Op = &Simulator::umlal;
      }
      break;
    case NEON_SMLSL_byelement:
      if (instr->Mask(NEON_Q)) {
        Op = &Simulator::smlsl2;
      } else {
        Op = &Simulator::smlsl;
      }
      break;
    case NEON_UMLSL_byelement:
      if (instr->Mask(NEON_Q)) {
        Op = &Simulator::umlsl2;
      } else {
        Op = &Simulator::umlsl;
      }
      break;
    case NEON_SQDMULL_byelement:
      if (instr->Mask(NEON_Q)) {
        Op = &Simulator::sqdmull2;
      } else {
        Op = &Simulator::sqdmull;
      }
      break;
    case NEON_SQDMLAL_byelement:
      if (instr->Mask(NEON_Q)) {
        Op = &Simulator::sqdmlal2;
      } else {
        Op = &Simulator::sqdmlal;
      }
      break;
    case NEON_SQDMLSL_byelement:
      if (instr->Mask(NEON_Q)) {
        Op = &Simulator::sqdmlsl2;
      } else {
        Op = &Simulator::sqdmlsl;
      }
      break;
    default:
      index = instr->NEONH();
      if ((instr->FPType() & 1) == 0) {
        index = (index << 1) | instr->NEONL();
      }

      vf = nfd.GetVectorFormat(nfd.FPFormatMap());

      switch (instr->Mask(NEONByIndexedElementFPMask)) {
        case NEON_FMUL_byelement:
          Op = &Simulator::fmul;
          break;
        case NEON_FMLA_byelement:
          Op = &Simulator::fmla;
          break;
        case NEON_FMLS_byelement:
          Op = &Simulator::fmls;
          break;
        case NEON_FMULX_byelement:
          Op = &Simulator::fmulx;
          break;
        default:
          UNIMPLEMENTED();
      }
  }

  (this->*Op)(vf, rd, rn, vreg(rm_reg), index);
}

void Simulator::VisitNEONCopy(Instruction* instr) {
  NEONFormatDecoder nfd(instr, NEONFormatDecoder::TriangularFormatMap());
  VectorFormat vf = nfd.GetVectorFormat();

  SimVRegister& rd = vreg(instr->Rd());
  SimVRegister& rn = vreg(instr->Rn());
  int imm5 = instr->ImmNEON5();
  int lsb = LowestSetBitPosition(imm5);
  int reg_index = imm5 >> lsb;

  if (instr->Mask(NEONCopyInsElementMask) == NEON_INS_ELEMENT) {
    int imm4 = instr->ImmNEON4();
    DCHECK_GE(lsb, 1);
    int rn_index = imm4 >> (lsb - 1);
    ins_element(vf, rd, reg_index, rn, rn_index);
  } else if (instr->Mask(NEONCopyInsGeneralMask) == NEON_INS_GENERAL) {
    ins_immediate(vf, rd, reg_index, xreg(instr->Rn()));
  } else if (instr->Mask(NEONCopyUmovMask) == NEON_UMOV) {
    uint64_t value = LogicVRegister(rn).Uint(vf, reg_index);
    value &= MaxUintFromFormat(vf);
    set_xreg(instr->Rd(), value);
  } else if (instr->Mask(NEONCopyUmovMask) == NEON_SMOV) {
    int64_t value = LogicVRegister(rn).Int(vf, reg_index);
    if (instr->NEONQ()) {
      set_xreg(instr->Rd(), value);
    } else {
      DCHECK(is_int32(value));
      set_wreg(instr->Rd(), static_cast<int32_t>(value));
    }
  } else if (instr->Mask(NEONCopyDupElementMask) == NEON_DUP_ELEMENT) {
    dup_element(vf, rd, rn, reg_index);
  } else if (instr->Mask(NEONCopyDupGeneralMask) == NEON_DUP_GENERAL) {
    dup_immediate(vf, rd, xreg(instr->Rn()));
  } else {
    UNIMPLEMENTED();
  }
}

void Simulator::VisitNEONExtract(Instruction* instr) {
  NEONFormatDecoder nfd(instr, NEONFormatDecoder::LogicalFormatMap());
  VectorFormat vf = nfd.GetVectorFormat();
  SimVRegister& rd = vreg(instr->Rd());
  SimVRegister& rn = vreg(instr->Rn());
  SimVRegister& rm = vreg(instr->Rm());
  if (instr->Mask(NEONExtractMask) == NEON_EXT) {
    int index = instr->ImmNEONExt();
    ext(vf, rd, rn, rm, index);
  } else {
    UNIMPLEMENTED();
  }
}

void Simulator::NEONLoadStoreMultiStructHelper(const Instruction* instr,
                                               AddrMode addr_mode) {
  NEONFormatDecoder nfd(instr, NEONFormatDecoder::LoadStoreFormatMap());
  VectorFormat vf = nfd.GetVectorFormat();

  uint64_t addr_base = xreg(instr->Rn(), Reg31IsStackPointer);
  int reg_size = RegisterSizeInBytesFromFormat(vf);

  int reg[4];
  uint64_t addr[4];
  for (int i = 0; i < 4; i++) {
    reg[i] = (instr->Rt() + i) % kNumberOfVRegisters;
    addr[i] = addr_base + (i * reg_size);
  }
  int count = 1;
  bool log_read = true;

  // Bit 23 determines whether this is an offset or post-index addressing mode.
  // In offset mode, bits 20 to 16 should be zero; these bits encode the
  // register of immediate in post-index mode.
  if ((instr->Bit(23) == 0) && (instr->Bits(20, 16) != 0)) {
    UNREACHABLE();
  }

  // We use the PostIndex mask here, as it works in this case for both Offset
  // and PostIndex addressing.
  switch (instr->Mask(NEONLoadStoreMultiStructPostIndexMask)) {
    case NEON_LD1_4v:
    case NEON_LD1_4v_post:
      ld1(vf, vreg(reg[3]), addr[3]);
4412 4413
      count++;
      V8_FALLTHROUGH;
4414 4415 4416
    case NEON_LD1_3v:
    case NEON_LD1_3v_post:
      ld1(vf, vreg(reg[2]), addr[2]);
4417 4418
      count++;
      V8_FALLTHROUGH;
4419 4420 4421
    case NEON_LD1_2v:
    case NEON_LD1_2v_post:
      ld1(vf, vreg(reg[1]), addr[1]);
4422 4423
      count++;
      V8_FALLTHROUGH;
4424 4425 4426 4427 4428 4429 4430
    case NEON_LD1_1v:
    case NEON_LD1_1v_post:
      ld1(vf, vreg(reg[0]), addr[0]);
      break;
    case NEON_ST1_4v:
    case NEON_ST1_4v_post:
      st1(vf, vreg(reg[3]), addr[3]);
4431 4432
      count++;
      V8_FALLTHROUGH;
4433 4434 4435
    case NEON_ST1_3v:
    case NEON_ST1_3v_post:
      st1(vf, vreg(reg[2]), addr[2]);
4436 4437
      count++;
      V8_FALLTHROUGH;
4438 4439 4440
    case NEON_ST1_2v:
    case NEON_ST1_2v_post:
      st1(vf, vreg(reg[1]), addr[1]);
4441 4442
      count++;
      V8_FALLTHROUGH;
4443 4444 4445 4446 4447 4448 4449 4450 4451 4452 4453 4454 4455 4456 4457 4458 4459 4460 4461 4462 4463 4464 4465 4466 4467 4468 4469 4470 4471 4472 4473 4474 4475 4476 4477 4478 4479 4480 4481 4482 4483 4484
    case NEON_ST1_1v:
    case NEON_ST1_1v_post:
      st1(vf, vreg(reg[0]), addr[0]);
      log_read = false;
      break;
    case NEON_LD2_post:
    case NEON_LD2:
      ld2(vf, vreg(reg[0]), vreg(reg[1]), addr[0]);
      count = 2;
      break;
    case NEON_ST2:
    case NEON_ST2_post:
      st2(vf, vreg(reg[0]), vreg(reg[1]), addr[0]);
      count = 2;
      log_read = false;
      break;
    case NEON_LD3_post:
    case NEON_LD3:
      ld3(vf, vreg(reg[0]), vreg(reg[1]), vreg(reg[2]), addr[0]);
      count = 3;
      break;
    case NEON_ST3:
    case NEON_ST3_post:
      st3(vf, vreg(reg[0]), vreg(reg[1]), vreg(reg[2]), addr[0]);
      count = 3;
      log_read = false;
      break;
    case NEON_LD4_post:
    case NEON_LD4:
      ld4(vf, vreg(reg[0]), vreg(reg[1]), vreg(reg[2]), vreg(reg[3]), addr[0]);
      count = 4;
      break;
    case NEON_ST4:
    case NEON_ST4_post:
      st4(vf, vreg(reg[0]), vreg(reg[1]), vreg(reg[2]), vreg(reg[3]), addr[0]);
      count = 4;
      log_read = false;
      break;
    default:
      UNIMPLEMENTED();
  }

4485 4486 4487 4488 4489 4490 4491 4492 4493 4494
  {
    base::LockGuard<base::Mutex> lock_guard(&global_monitor_.Pointer()->mutex);
    if (log_read) {
      local_monitor_.NotifyLoad();
    } else {
      local_monitor_.NotifyStore();
      global_monitor_.Pointer()->NotifyStore_Locked(&global_monitor_processor_);
    }
  }

4495 4496 4497 4498 4499 4500 4501 4502 4503 4504 4505 4506 4507 4508 4509 4510 4511 4512 4513 4514 4515 4516 4517 4518 4519 4520 4521 4522 4523 4524 4525 4526 4527 4528 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
  // Explicitly log the register update whilst we have type information.
  for (int i = 0; i < count; i++) {
    // For de-interleaving loads, only print the base address.
    int lane_size = LaneSizeInBytesFromFormat(vf);
    PrintRegisterFormat format = GetPrintRegisterFormatTryFP(
        GetPrintRegisterFormatForSize(reg_size, lane_size));
    if (log_read) {
      LogVRead(addr_base, reg[i], format);
    } else {
      LogVWrite(addr_base, reg[i], format);
    }
  }

  if (addr_mode == PostIndex) {
    int rm = instr->Rm();
    // The immediate post index addressing mode is indicated by rm = 31.
    // The immediate is implied by the number of vector registers used.
    addr_base +=
        (rm == 31) ? RegisterSizeInBytesFromFormat(vf) * count : xreg(rm);
    set_xreg(instr->Rn(), addr_base);
  } else {
    DCHECK_EQ(addr_mode, Offset);
  }
}

void Simulator::VisitNEONLoadStoreMultiStruct(Instruction* instr) {
  NEONLoadStoreMultiStructHelper(instr, Offset);
}

void Simulator::VisitNEONLoadStoreMultiStructPostIndex(Instruction* instr) {
  NEONLoadStoreMultiStructHelper(instr, PostIndex);
}

void Simulator::NEONLoadStoreSingleStructHelper(const Instruction* instr,
                                                AddrMode addr_mode) {
  uint64_t addr = xreg(instr->Rn(), Reg31IsStackPointer);
  int rt = instr->Rt();

  // Bit 23 determines whether this is an offset or post-index addressing mode.
  // In offset mode, bits 20 to 16 should be zero; these bits encode the
  // register of immediate in post-index mode.
  DCHECK_IMPLIES(instr->Bit(23) == 0, instr->Bits(20, 16) == 0);

  bool do_load = false;

  NEONFormatDecoder nfd(instr, NEONFormatDecoder::LoadStoreFormatMap());
  VectorFormat vf_t = nfd.GetVectorFormat();

  VectorFormat vf = kFormat16B;
  // We use the PostIndex mask here, as it works in this case for both Offset
  // and PostIndex addressing.
  switch (instr->Mask(NEONLoadStoreSingleStructPostIndexMask)) {
    case NEON_LD1_b:
    case NEON_LD1_b_post:
    case NEON_LD2_b:
    case NEON_LD2_b_post:
    case NEON_LD3_b:
    case NEON_LD3_b_post:
    case NEON_LD4_b:
    case NEON_LD4_b_post:
4555 4556
      do_load = true;
      V8_FALLTHROUGH;
4557 4558 4559 4560 4561 4562 4563 4564 4565 4566 4567 4568 4569 4570 4571 4572 4573 4574
    case NEON_ST1_b:
    case NEON_ST1_b_post:
    case NEON_ST2_b:
    case NEON_ST2_b_post:
    case NEON_ST3_b:
    case NEON_ST3_b_post:
    case NEON_ST4_b:
    case NEON_ST4_b_post:
      break;

    case NEON_LD1_h:
    case NEON_LD1_h_post:
    case NEON_LD2_h:
    case NEON_LD2_h_post:
    case NEON_LD3_h:
    case NEON_LD3_h_post:
    case NEON_LD4_h:
    case NEON_LD4_h_post:
4575 4576
      do_load = true;
      V8_FALLTHROUGH;
4577 4578 4579 4580 4581 4582 4583 4584 4585 4586 4587 4588 4589 4590 4591 4592 4593 4594 4595
    case NEON_ST1_h:
    case NEON_ST1_h_post:
    case NEON_ST2_h:
    case NEON_ST2_h_post:
    case NEON_ST3_h:
    case NEON_ST3_h_post:
    case NEON_ST4_h:
    case NEON_ST4_h_post:
      vf = kFormat8H;
      break;

    case NEON_LD1_s:
    case NEON_LD1_s_post:
    case NEON_LD2_s:
    case NEON_LD2_s_post:
    case NEON_LD3_s:
    case NEON_LD3_s_post:
    case NEON_LD4_s:
    case NEON_LD4_s_post:
4596 4597
      do_load = true;
      V8_FALLTHROUGH;
4598 4599 4600 4601 4602 4603 4604 4605 4606 4607 4608 4609 4610 4611 4612 4613 4614 4615 4616 4617 4618 4619 4620 4621 4622 4623 4624 4625 4626 4627 4628 4629 4630 4631 4632 4633 4634 4635 4636 4637 4638 4639 4640 4641 4642 4643 4644 4645 4646 4647 4648 4649 4650 4651 4652 4653 4654 4655 4656 4657 4658 4659 4660 4661 4662 4663 4664 4665 4666 4667 4668 4669 4670 4671 4672 4673 4674 4675 4676 4677 4678 4679 4680 4681 4682 4683 4684 4685 4686 4687 4688 4689 4690 4691 4692 4693 4694 4695 4696 4697 4698 4699 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
    case NEON_ST1_s:
    case NEON_ST1_s_post:
    case NEON_ST2_s:
    case NEON_ST2_s_post:
    case NEON_ST3_s:
    case NEON_ST3_s_post:
    case NEON_ST4_s:
    case NEON_ST4_s_post: {
      static_assert((NEON_LD1_s | (1 << NEONLSSize_offset)) == NEON_LD1_d,
                    "LSB of size distinguishes S and D registers.");
      static_assert(
          (NEON_LD1_s_post | (1 << NEONLSSize_offset)) == NEON_LD1_d_post,
          "LSB of size distinguishes S and D registers.");
      static_assert((NEON_ST1_s | (1 << NEONLSSize_offset)) == NEON_ST1_d,
                    "LSB of size distinguishes S and D registers.");
      static_assert(
          (NEON_ST1_s_post | (1 << NEONLSSize_offset)) == NEON_ST1_d_post,
          "LSB of size distinguishes S and D registers.");
      vf = ((instr->NEONLSSize() & 1) == 0) ? kFormat4S : kFormat2D;
      break;
    }

    case NEON_LD1R:
    case NEON_LD1R_post: {
      vf = vf_t;
      ld1r(vf, vreg(rt), addr);
      do_load = true;
      break;
    }

    case NEON_LD2R:
    case NEON_LD2R_post: {
      vf = vf_t;
      int rt2 = (rt + 1) % kNumberOfVRegisters;
      ld2r(vf, vreg(rt), vreg(rt2), addr);
      do_load = true;
      break;
    }

    case NEON_LD3R:
    case NEON_LD3R_post: {
      vf = vf_t;
      int rt2 = (rt + 1) % kNumberOfVRegisters;
      int rt3 = (rt2 + 1) % kNumberOfVRegisters;
      ld3r(vf, vreg(rt), vreg(rt2), vreg(rt3), addr);
      do_load = true;
      break;
    }

    case NEON_LD4R:
    case NEON_LD4R_post: {
      vf = vf_t;
      int rt2 = (rt + 1) % kNumberOfVRegisters;
      int rt3 = (rt2 + 1) % kNumberOfVRegisters;
      int rt4 = (rt3 + 1) % kNumberOfVRegisters;
      ld4r(vf, vreg(rt), vreg(rt2), vreg(rt3), vreg(rt4), addr);
      do_load = true;
      break;
    }
    default:
      UNIMPLEMENTED();
  }

  PrintRegisterFormat print_format =
      GetPrintRegisterFormatTryFP(GetPrintRegisterFormat(vf));
  // Make sure that the print_format only includes a single lane.
  print_format =
      static_cast<PrintRegisterFormat>(print_format & ~kPrintRegAsVectorMask);

  int esize = LaneSizeInBytesFromFormat(vf);
  int index_shift = LaneSizeInBytesLog2FromFormat(vf);
  int lane = instr->NEONLSIndex(index_shift);
  int scale = 0;
  int rt2 = (rt + 1) % kNumberOfVRegisters;
  int rt3 = (rt2 + 1) % kNumberOfVRegisters;
  int rt4 = (rt3 + 1) % kNumberOfVRegisters;
  switch (instr->Mask(NEONLoadStoreSingleLenMask)) {
    case NEONLoadStoreSingle1:
      scale = 1;
      if (do_load) {
        ld1(vf, vreg(rt), lane, addr);
        LogVRead(addr, rt, print_format, lane);
      } else {
        st1(vf, vreg(rt), lane, addr);
        LogVWrite(addr, rt, print_format, lane);
      }
      break;
    case NEONLoadStoreSingle2:
      scale = 2;
      if (do_load) {
        ld2(vf, vreg(rt), vreg(rt2), lane, addr);
        LogVRead(addr, rt, print_format, lane);
        LogVRead(addr + esize, rt2, print_format, lane);
      } else {
        st2(vf, vreg(rt), vreg(rt2), lane, addr);
        LogVWrite(addr, rt, print_format, lane);
        LogVWrite(addr + esize, rt2, print_format, lane);
      }
      break;
    case NEONLoadStoreSingle3:
      scale = 3;
      if (do_load) {
        ld3(vf, vreg(rt), vreg(rt2), vreg(rt3), lane, addr);
        LogVRead(addr, rt, print_format, lane);
        LogVRead(addr + esize, rt2, print_format, lane);
        LogVRead(addr + (2 * esize), rt3, print_format, lane);
      } else {
        st3(vf, vreg(rt), vreg(rt2), vreg(rt3), lane, addr);
        LogVWrite(addr, rt, print_format, lane);
        LogVWrite(addr + esize, rt2, print_format, lane);
        LogVWrite(addr + (2 * esize), rt3, print_format, lane);
      }
      break;
    case NEONLoadStoreSingle4:
      scale = 4;
      if (do_load) {
        ld4(vf, vreg(rt), vreg(rt2), vreg(rt3), vreg(rt4), lane, addr);
        LogVRead(addr, rt, print_format, lane);
        LogVRead(addr + esize, rt2, print_format, lane);
        LogVRead(addr + (2 * esize), rt3, print_format, lane);
        LogVRead(addr + (3 * esize), rt4, print_format, lane);
      } else {
        st4(vf, vreg(rt), vreg(rt2), vreg(rt3), vreg(rt4), lane, addr);
        LogVWrite(addr, rt, print_format, lane);
        LogVWrite(addr + esize, rt2, print_format, lane);
        LogVWrite(addr + (2 * esize), rt3, print_format, lane);
        LogVWrite(addr + (3 * esize), rt4, print_format, lane);
      }
      break;
    default:
      UNIMPLEMENTED();
  }

4731 4732 4733 4734 4735 4736 4737 4738 4739 4740
  {
    base::LockGuard<base::Mutex> lock_guard(&global_monitor_.Pointer()->mutex);
    if (do_load) {
      local_monitor_.NotifyLoad();
    } else {
      local_monitor_.NotifyStore();
      global_monitor_.Pointer()->NotifyStore_Locked(&global_monitor_processor_);
    }
  }

4741 4742 4743 4744 4745 4746 4747 4748 4749 4750 4751 4752 4753 4754 4755 4756 4757 4758 4759 4760 4761 4762 4763 4764 4765 4766 4767 4768 4769 4770 4771 4772 4773 4774 4775 4776 4777 4778 4779 4780 4781 4782 4783 4784 4785 4786
  if (addr_mode == PostIndex) {
    int rm = instr->Rm();
    int lane_size = LaneSizeInBytesFromFormat(vf);
    set_xreg(instr->Rn(), addr + ((rm == 31) ? (scale * lane_size) : xreg(rm)));
  }
}

void Simulator::VisitNEONLoadStoreSingleStruct(Instruction* instr) {
  NEONLoadStoreSingleStructHelper(instr, Offset);
}

void Simulator::VisitNEONLoadStoreSingleStructPostIndex(Instruction* instr) {
  NEONLoadStoreSingleStructHelper(instr, PostIndex);
}

void Simulator::VisitNEONModifiedImmediate(Instruction* instr) {
  SimVRegister& rd = vreg(instr->Rd());
  int cmode = instr->NEONCmode();
  int cmode_3_1 = (cmode >> 1) & 7;
  int cmode_3 = (cmode >> 3) & 1;
  int cmode_2 = (cmode >> 2) & 1;
  int cmode_1 = (cmode >> 1) & 1;
  int cmode_0 = cmode & 1;
  int q = instr->NEONQ();
  int op_bit = instr->NEONModImmOp();
  uint64_t imm8 = instr->ImmNEONabcdefgh();

  // Find the format and immediate value
  uint64_t imm = 0;
  VectorFormat vform = kFormatUndefined;
  switch (cmode_3_1) {
    case 0x0:
    case 0x1:
    case 0x2:
    case 0x3:
      vform = (q == 1) ? kFormat4S : kFormat2S;
      imm = imm8 << (8 * cmode_3_1);
      break;
    case 0x4:
    case 0x5:
      vform = (q == 1) ? kFormat8H : kFormat4H;
      imm = imm8 << (8 * cmode_1);
      break;
    case 0x6:
      vform = (q == 1) ? kFormat4S : kFormat2S;
      if (cmode_0 == 0) {
4787
        imm = imm8 << 8 | 0x000000FF;
4788
      } else {
4789
        imm = imm8 << 16 | 0x0000FFFF;
4790 4791 4792 4793 4794 4795 4796 4797 4798 4799 4800
      }
      break;
    case 0x7:
      if (cmode_0 == 0 && op_bit == 0) {
        vform = q ? kFormat16B : kFormat8B;
        imm = imm8;
      } else if (cmode_0 == 0 && op_bit == 1) {
        vform = q ? kFormat2D : kFormat1D;
        imm = 0;
        for (int i = 0; i < 8; ++i) {
          if (imm8 & (1 << i)) {
4801
            imm |= (UINT64_C(0xFF) << (8 * i));
4802 4803
          }
        }
4804
      } else {  // cmode_0 == 1, cmode == 0xF.
4805 4806 4807 4808 4809 4810 4811
        if (op_bit == 0) {
          vform = q ? kFormat4S : kFormat2S;
          imm = bit_cast<uint32_t>(instr->ImmNEONFP32());
        } else if (q == 1) {
          vform = kFormat2D;
          imm = bit_cast<uint64_t>(instr->ImmNEONFP64());
        } else {
4812
          DCHECK((q == 0) && (op_bit == 1) && (cmode == 0xF));
4813 4814 4815 4816 4817 4818 4819 4820 4821 4822 4823 4824 4825 4826 4827 4828 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 4876 4877 4878 4879 4880 4881 4882 4883 4884 4885 4886 4887 4888 4889 4890 4891 4892 4893 4894 4895 4896 4897 4898 4899 4900 4901 4902 4903 4904 4905 4906 4907 4908 4909 4910 4911 4912 4913 4914 4915 4916 4917 4918 4919 4920 4921 4922 4923 4924 4925 4926 4927 4928 4929 4930 4931 4932 4933 4934 4935 4936 4937 4938 4939 4940 4941 4942 4943 4944 4945 4946 4947 4948 4949 4950 4951 4952 4953 4954 4955 4956 4957 4958 4959 4960 4961 4962 4963 4964 4965 4966 4967 4968 4969 4970 4971 4972 4973 4974 4975 4976 4977 4978 4979 4980 4981 4982 4983 4984 4985 4986 4987 4988 4989 4990 4991 4992 4993 4994 4995 4996 4997 4998 4999 5000 5001 5002 5003 5004 5005 5006 5007 5008 5009 5010 5011 5012 5013 5014 5015 5016 5017 5018 5019 5020 5021 5022 5023 5024 5025 5026 5027 5028 5029 5030 5031 5032 5033 5034 5035 5036 5037 5038 5039 5040 5041 5042 5043 5044 5045 5046 5047 5048 5049 5050 5051 5052 5053 5054 5055 5056 5057 5058 5059 5060 5061 5062 5063 5064 5065 5066 5067 5068 5069 5070 5071 5072 5073 5074 5075 5076 5077 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 5124 5125 5126 5127 5128 5129 5130 5131 5132 5133 5134 5135 5136 5137 5138 5139 5140 5141 5142 5143 5144 5145 5146 5147 5148 5149 5150
          VisitUnallocated(instr);
        }
      }
      break;
    default:
      UNREACHABLE();
  }

  // Find the operation.
  NEONModifiedImmediateOp op;
  if (cmode_3 == 0) {
    if (cmode_0 == 0) {
      op = op_bit ? NEONModifiedImmediate_MVNI : NEONModifiedImmediate_MOVI;
    } else {  // cmode<0> == '1'
      op = op_bit ? NEONModifiedImmediate_BIC : NEONModifiedImmediate_ORR;
    }
  } else {  // cmode<3> == '1'
    if (cmode_2 == 0) {
      if (cmode_0 == 0) {
        op = op_bit ? NEONModifiedImmediate_MVNI : NEONModifiedImmediate_MOVI;
      } else {  // cmode<0> == '1'
        op = op_bit ? NEONModifiedImmediate_BIC : NEONModifiedImmediate_ORR;
      }
    } else {  // cmode<2> == '1'
      if (cmode_1 == 0) {
        op = op_bit ? NEONModifiedImmediate_MVNI : NEONModifiedImmediate_MOVI;
      } else {  // cmode<1> == '1'
        if (cmode_0 == 0) {
          op = NEONModifiedImmediate_MOVI;
        } else {  // cmode<0> == '1'
          op = NEONModifiedImmediate_MOVI;
        }
      }
    }
  }

  // Call the logic function.
  switch (op) {
    case NEONModifiedImmediate_ORR:
      orr(vform, rd, rd, imm);
      break;
    case NEONModifiedImmediate_BIC:
      bic(vform, rd, rd, imm);
      break;
    case NEONModifiedImmediate_MOVI:
      movi(vform, rd, imm);
      break;
    case NEONModifiedImmediate_MVNI:
      mvni(vform, rd, imm);
      break;
    default:
      VisitUnimplemented(instr);
  }
}

void Simulator::VisitNEONScalar2RegMisc(Instruction* instr) {
  NEONFormatDecoder nfd(instr, NEONFormatDecoder::ScalarFormatMap());
  VectorFormat vf = nfd.GetVectorFormat();

  SimVRegister& rd = vreg(instr->Rd());
  SimVRegister& rn = vreg(instr->Rn());

  if (instr->Mask(NEON2RegMiscOpcode) <= NEON_NEG_scalar_opcode) {
    // These instructions all use a two bit size field, except NOT and RBIT,
    // which use the field to encode the operation.
    switch (instr->Mask(NEONScalar2RegMiscMask)) {
      case NEON_CMEQ_zero_scalar:
        cmp(vf, rd, rn, 0, eq);
        break;
      case NEON_CMGE_zero_scalar:
        cmp(vf, rd, rn, 0, ge);
        break;
      case NEON_CMGT_zero_scalar:
        cmp(vf, rd, rn, 0, gt);
        break;
      case NEON_CMLT_zero_scalar:
        cmp(vf, rd, rn, 0, lt);
        break;
      case NEON_CMLE_zero_scalar:
        cmp(vf, rd, rn, 0, le);
        break;
      case NEON_ABS_scalar:
        abs(vf, rd, rn);
        break;
      case NEON_SQABS_scalar:
        abs(vf, rd, rn).SignedSaturate(vf);
        break;
      case NEON_NEG_scalar:
        neg(vf, rd, rn);
        break;
      case NEON_SQNEG_scalar:
        neg(vf, rd, rn).SignedSaturate(vf);
        break;
      case NEON_SUQADD_scalar:
        suqadd(vf, rd, rn);
        break;
      case NEON_USQADD_scalar:
        usqadd(vf, rd, rn);
        break;
      default:
        UNIMPLEMENTED();
        break;
    }
  } else {
    VectorFormat fpf = nfd.GetVectorFormat(nfd.FPScalarFormatMap());
    FPRounding fpcr_rounding = static_cast<FPRounding>(fpcr().RMode());

    // These instructions all use a one bit size field, except SQXTUN, SQXTN
    // and UQXTN, which use a two bit size field.
    switch (instr->Mask(NEONScalar2RegMiscFPMask)) {
      case NEON_FRECPE_scalar:
        frecpe(fpf, rd, rn, fpcr_rounding);
        break;
      case NEON_FRECPX_scalar:
        frecpx(fpf, rd, rn);
        break;
      case NEON_FRSQRTE_scalar:
        frsqrte(fpf, rd, rn);
        break;
      case NEON_FCMGT_zero_scalar:
        fcmp_zero(fpf, rd, rn, gt);
        break;
      case NEON_FCMGE_zero_scalar:
        fcmp_zero(fpf, rd, rn, ge);
        break;
      case NEON_FCMEQ_zero_scalar:
        fcmp_zero(fpf, rd, rn, eq);
        break;
      case NEON_FCMLE_zero_scalar:
        fcmp_zero(fpf, rd, rn, le);
        break;
      case NEON_FCMLT_zero_scalar:
        fcmp_zero(fpf, rd, rn, lt);
        break;
      case NEON_SCVTF_scalar:
        scvtf(fpf, rd, rn, 0, fpcr_rounding);
        break;
      case NEON_UCVTF_scalar:
        ucvtf(fpf, rd, rn, 0, fpcr_rounding);
        break;
      case NEON_FCVTNS_scalar:
        fcvts(fpf, rd, rn, FPTieEven);
        break;
      case NEON_FCVTNU_scalar:
        fcvtu(fpf, rd, rn, FPTieEven);
        break;
      case NEON_FCVTPS_scalar:
        fcvts(fpf, rd, rn, FPPositiveInfinity);
        break;
      case NEON_FCVTPU_scalar:
        fcvtu(fpf, rd, rn, FPPositiveInfinity);
        break;
      case NEON_FCVTMS_scalar:
        fcvts(fpf, rd, rn, FPNegativeInfinity);
        break;
      case NEON_FCVTMU_scalar:
        fcvtu(fpf, rd, rn, FPNegativeInfinity);
        break;
      case NEON_FCVTZS_scalar:
        fcvts(fpf, rd, rn, FPZero);
        break;
      case NEON_FCVTZU_scalar:
        fcvtu(fpf, rd, rn, FPZero);
        break;
      case NEON_FCVTAS_scalar:
        fcvts(fpf, rd, rn, FPTieAway);
        break;
      case NEON_FCVTAU_scalar:
        fcvtu(fpf, rd, rn, FPTieAway);
        break;
      case NEON_FCVTXN_scalar:
        // Unlike all of the other FP instructions above, fcvtxn encodes dest
        // size S as size<0>=1. There's only one case, so we ignore the form.
        DCHECK_EQ(instr->Bit(22), 1);
        fcvtxn(kFormatS, rd, rn);
        break;
      default:
        switch (instr->Mask(NEONScalar2RegMiscMask)) {
          case NEON_SQXTN_scalar:
            sqxtn(vf, rd, rn);
            break;
          case NEON_UQXTN_scalar:
            uqxtn(vf, rd, rn);
            break;
          case NEON_SQXTUN_scalar:
            sqxtun(vf, rd, rn);
            break;
          default:
            UNIMPLEMENTED();
        }
    }
  }
}

void Simulator::VisitNEONScalar3Diff(Instruction* instr) {
  NEONFormatDecoder nfd(instr, NEONFormatDecoder::LongScalarFormatMap());
  VectorFormat vf = nfd.GetVectorFormat();

  SimVRegister& rd = vreg(instr->Rd());
  SimVRegister& rn = vreg(instr->Rn());
  SimVRegister& rm = vreg(instr->Rm());
  switch (instr->Mask(NEONScalar3DiffMask)) {
    case NEON_SQDMLAL_scalar:
      sqdmlal(vf, rd, rn, rm);
      break;
    case NEON_SQDMLSL_scalar:
      sqdmlsl(vf, rd, rn, rm);
      break;
    case NEON_SQDMULL_scalar:
      sqdmull(vf, rd, rn, rm);
      break;
    default:
      UNIMPLEMENTED();
  }
}

void Simulator::VisitNEONScalar3Same(Instruction* instr) {
  NEONFormatDecoder nfd(instr, NEONFormatDecoder::ScalarFormatMap());
  VectorFormat vf = nfd.GetVectorFormat();

  SimVRegister& rd = vreg(instr->Rd());
  SimVRegister& rn = vreg(instr->Rn());
  SimVRegister& rm = vreg(instr->Rm());

  if (instr->Mask(NEONScalar3SameFPFMask) == NEONScalar3SameFPFixed) {
    vf = nfd.GetVectorFormat(nfd.FPScalarFormatMap());
    switch (instr->Mask(NEONScalar3SameFPMask)) {
      case NEON_FMULX_scalar:
        fmulx(vf, rd, rn, rm);
        break;
      case NEON_FACGE_scalar:
        fabscmp(vf, rd, rn, rm, ge);
        break;
      case NEON_FACGT_scalar:
        fabscmp(vf, rd, rn, rm, gt);
        break;
      case NEON_FCMEQ_scalar:
        fcmp(vf, rd, rn, rm, eq);
        break;
      case NEON_FCMGE_scalar:
        fcmp(vf, rd, rn, rm, ge);
        break;
      case NEON_FCMGT_scalar:
        fcmp(vf, rd, rn, rm, gt);
        break;
      case NEON_FRECPS_scalar:
        frecps(vf, rd, rn, rm);
        break;
      case NEON_FRSQRTS_scalar:
        frsqrts(vf, rd, rn, rm);
        break;
      case NEON_FABD_scalar:
        fabd(vf, rd, rn, rm);
        break;
      default:
        UNIMPLEMENTED();
    }
  } else {
    switch (instr->Mask(NEONScalar3SameMask)) {
      case NEON_ADD_scalar:
        add(vf, rd, rn, rm);
        break;
      case NEON_SUB_scalar:
        sub(vf, rd, rn, rm);
        break;
      case NEON_CMEQ_scalar:
        cmp(vf, rd, rn, rm, eq);
        break;
      case NEON_CMGE_scalar:
        cmp(vf, rd, rn, rm, ge);
        break;
      case NEON_CMGT_scalar:
        cmp(vf, rd, rn, rm, gt);
        break;
      case NEON_CMHI_scalar:
        cmp(vf, rd, rn, rm, hi);
        break;
      case NEON_CMHS_scalar:
        cmp(vf, rd, rn, rm, hs);
        break;
      case NEON_CMTST_scalar:
        cmptst(vf, rd, rn, rm);
        break;
      case NEON_USHL_scalar:
        ushl(vf, rd, rn, rm);
        break;
      case NEON_SSHL_scalar:
        sshl(vf, rd, rn, rm);
        break;
      case NEON_SQDMULH_scalar:
        sqdmulh(vf, rd, rn, rm);
        break;
      case NEON_SQRDMULH_scalar:
        sqrdmulh(vf, rd, rn, rm);
        break;
      case NEON_UQADD_scalar:
        add(vf, rd, rn, rm).UnsignedSaturate(vf);
        break;
      case NEON_SQADD_scalar:
        add(vf, rd, rn, rm).SignedSaturate(vf);
        break;
      case NEON_UQSUB_scalar:
        sub(vf, rd, rn, rm).UnsignedSaturate(vf);
        break;
      case NEON_SQSUB_scalar:
        sub(vf, rd, rn, rm).SignedSaturate(vf);
        break;
      case NEON_UQSHL_scalar:
        ushl(vf, rd, rn, rm).UnsignedSaturate(vf);
        break;
      case NEON_SQSHL_scalar:
        sshl(vf, rd, rn, rm).SignedSaturate(vf);
        break;
      case NEON_URSHL_scalar:
        ushl(vf, rd, rn, rm).Round(vf);
        break;
      case NEON_SRSHL_scalar:
        sshl(vf, rd, rn, rm).Round(vf);
        break;
      case NEON_UQRSHL_scalar:
        ushl(vf, rd, rn, rm).Round(vf).UnsignedSaturate(vf);
        break;
      case NEON_SQRSHL_scalar:
        sshl(vf, rd, rn, rm).Round(vf).SignedSaturate(vf);
        break;
      default:
        UNIMPLEMENTED();
    }
  }
}

void Simulator::VisitNEONScalarByIndexedElement(Instruction* instr) {
  NEONFormatDecoder nfd(instr, NEONFormatDecoder::LongScalarFormatMap());
  VectorFormat vf = nfd.GetVectorFormat();
  VectorFormat vf_r = nfd.GetVectorFormat(nfd.ScalarFormatMap());

  SimVRegister& rd = vreg(instr->Rd());
  SimVRegister& rn = vreg(instr->Rn());
5151
  ByElementOp Op = nullptr;
5152 5153 5154 5155

  int rm_reg = instr->Rm();
  int index = (instr->NEONH() << 1) | instr->NEONL();
  if (instr->NEONSize() == 1) {
5156
    rm_reg &= 0xF;
5157 5158 5159 5160 5161 5162 5163 5164 5165 5166 5167 5168 5169 5170 5171 5172 5173 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 5213 5214 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 5244 5245 5246 5247 5248 5249 5250 5251 5252 5253 5254 5255 5256 5257 5258 5259 5260 5261 5262 5263 5264 5265 5266 5267 5268 5269 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 5352 5353 5354 5355 5356 5357 5358 5359 5360 5361 5362 5363 5364 5365 5366 5367 5368 5369 5370 5371 5372 5373 5374 5375 5376 5377 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 5475 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 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 5560 5561 5562 5563 5564 5565 5566 5567 5568 5569 5570 5571 5572 5573 5574 5575 5576
    index = (index << 1) | instr->NEONM();
  }

  switch (instr->Mask(NEONScalarByIndexedElementMask)) {
    case NEON_SQDMULL_byelement_scalar:
      Op = &Simulator::sqdmull;
      break;
    case NEON_SQDMLAL_byelement_scalar:
      Op = &Simulator::sqdmlal;
      break;
    case NEON_SQDMLSL_byelement_scalar:
      Op = &Simulator::sqdmlsl;
      break;
    case NEON_SQDMULH_byelement_scalar:
      Op = &Simulator::sqdmulh;
      vf = vf_r;
      break;
    case NEON_SQRDMULH_byelement_scalar:
      Op = &Simulator::sqrdmulh;
      vf = vf_r;
      break;
    default:
      vf = nfd.GetVectorFormat(nfd.FPScalarFormatMap());
      index = instr->NEONH();
      if ((instr->FPType() & 1) == 0) {
        index = (index << 1) | instr->NEONL();
      }
      switch (instr->Mask(NEONScalarByIndexedElementFPMask)) {
        case NEON_FMUL_byelement_scalar:
          Op = &Simulator::fmul;
          break;
        case NEON_FMLA_byelement_scalar:
          Op = &Simulator::fmla;
          break;
        case NEON_FMLS_byelement_scalar:
          Op = &Simulator::fmls;
          break;
        case NEON_FMULX_byelement_scalar:
          Op = &Simulator::fmulx;
          break;
        default:
          UNIMPLEMENTED();
      }
  }

  (this->*Op)(vf, rd, rn, vreg(rm_reg), index);
}

void Simulator::VisitNEONScalarCopy(Instruction* instr) {
  NEONFormatDecoder nfd(instr, NEONFormatDecoder::TriangularScalarFormatMap());
  VectorFormat vf = nfd.GetVectorFormat();

  SimVRegister& rd = vreg(instr->Rd());
  SimVRegister& rn = vreg(instr->Rn());

  if (instr->Mask(NEONScalarCopyMask) == NEON_DUP_ELEMENT_scalar) {
    int imm5 = instr->ImmNEON5();
    int lsb = LowestSetBitPosition(imm5);
    int rn_index = imm5 >> lsb;
    dup_element(vf, rd, rn, rn_index);
  } else {
    UNIMPLEMENTED();
  }
}

void Simulator::VisitNEONScalarPairwise(Instruction* instr) {
  NEONFormatDecoder nfd(instr, NEONFormatDecoder::FPScalarFormatMap());
  VectorFormat vf = nfd.GetVectorFormat();

  SimVRegister& rd = vreg(instr->Rd());
  SimVRegister& rn = vreg(instr->Rn());
  switch (instr->Mask(NEONScalarPairwiseMask)) {
    case NEON_ADDP_scalar:
      addp(vf, rd, rn);
      break;
    case NEON_FADDP_scalar:
      faddp(vf, rd, rn);
      break;
    case NEON_FMAXP_scalar:
      fmaxp(vf, rd, rn);
      break;
    case NEON_FMAXNMP_scalar:
      fmaxnmp(vf, rd, rn);
      break;
    case NEON_FMINP_scalar:
      fminp(vf, rd, rn);
      break;
    case NEON_FMINNMP_scalar:
      fminnmp(vf, rd, rn);
      break;
    default:
      UNIMPLEMENTED();
  }
}

void Simulator::VisitNEONScalarShiftImmediate(Instruction* instr) {
  SimVRegister& rd = vreg(instr->Rd());
  SimVRegister& rn = vreg(instr->Rn());
  FPRounding fpcr_rounding = static_cast<FPRounding>(fpcr().RMode());

  static const NEONFormatMap map = {
      {22, 21, 20, 19},
      {NF_UNDEF, NF_B, NF_H, NF_H, NF_S, NF_S, NF_S, NF_S, NF_D, NF_D, NF_D,
       NF_D, NF_D, NF_D, NF_D, NF_D}};
  NEONFormatDecoder nfd(instr, &map);
  VectorFormat vf = nfd.GetVectorFormat();

  int highestSetBit = HighestSetBitPosition(instr->ImmNEONImmh());
  int immhimmb = instr->ImmNEONImmhImmb();
  int right_shift = (16 << highestSetBit) - immhimmb;
  int left_shift = immhimmb - (8 << highestSetBit);
  switch (instr->Mask(NEONScalarShiftImmediateMask)) {
    case NEON_SHL_scalar:
      shl(vf, rd, rn, left_shift);
      break;
    case NEON_SLI_scalar:
      sli(vf, rd, rn, left_shift);
      break;
    case NEON_SQSHL_imm_scalar:
      sqshl(vf, rd, rn, left_shift);
      break;
    case NEON_UQSHL_imm_scalar:
      uqshl(vf, rd, rn, left_shift);
      break;
    case NEON_SQSHLU_scalar:
      sqshlu(vf, rd, rn, left_shift);
      break;
    case NEON_SRI_scalar:
      sri(vf, rd, rn, right_shift);
      break;
    case NEON_SSHR_scalar:
      sshr(vf, rd, rn, right_shift);
      break;
    case NEON_USHR_scalar:
      ushr(vf, rd, rn, right_shift);
      break;
    case NEON_SRSHR_scalar:
      sshr(vf, rd, rn, right_shift).Round(vf);
      break;
    case NEON_URSHR_scalar:
      ushr(vf, rd, rn, right_shift).Round(vf);
      break;
    case NEON_SSRA_scalar:
      ssra(vf, rd, rn, right_shift);
      break;
    case NEON_USRA_scalar:
      usra(vf, rd, rn, right_shift);
      break;
    case NEON_SRSRA_scalar:
      srsra(vf, rd, rn, right_shift);
      break;
    case NEON_URSRA_scalar:
      ursra(vf, rd, rn, right_shift);
      break;
    case NEON_UQSHRN_scalar:
      uqshrn(vf, rd, rn, right_shift);
      break;
    case NEON_UQRSHRN_scalar:
      uqrshrn(vf, rd, rn, right_shift);
      break;
    case NEON_SQSHRN_scalar:
      sqshrn(vf, rd, rn, right_shift);
      break;
    case NEON_SQRSHRN_scalar:
      sqrshrn(vf, rd, rn, right_shift);
      break;
    case NEON_SQSHRUN_scalar:
      sqshrun(vf, rd, rn, right_shift);
      break;
    case NEON_SQRSHRUN_scalar:
      sqrshrun(vf, rd, rn, right_shift);
      break;
    case NEON_FCVTZS_imm_scalar:
      fcvts(vf, rd, rn, FPZero, right_shift);
      break;
    case NEON_FCVTZU_imm_scalar:
      fcvtu(vf, rd, rn, FPZero, right_shift);
      break;
    case NEON_SCVTF_imm_scalar:
      scvtf(vf, rd, rn, right_shift, fpcr_rounding);
      break;
    case NEON_UCVTF_imm_scalar:
      ucvtf(vf, rd, rn, right_shift, fpcr_rounding);
      break;
    default:
      UNIMPLEMENTED();
  }
}

void Simulator::VisitNEONShiftImmediate(Instruction* instr) {
  SimVRegister& rd = vreg(instr->Rd());
  SimVRegister& rn = vreg(instr->Rn());
  FPRounding fpcr_rounding = static_cast<FPRounding>(fpcr().RMode());

  // 00010->8B, 00011->16B, 001x0->4H, 001x1->8H,
  // 01xx0->2S, 01xx1->4S, 1xxx1->2D, all others undefined.
  static const NEONFormatMap map = {
      {22, 21, 20, 19, 30},
      {NF_UNDEF, NF_UNDEF, NF_8B,    NF_16B, NF_4H,    NF_8H, NF_4H,    NF_8H,
       NF_2S,    NF_4S,    NF_2S,    NF_4S,  NF_2S,    NF_4S, NF_2S,    NF_4S,
       NF_UNDEF, NF_2D,    NF_UNDEF, NF_2D,  NF_UNDEF, NF_2D, NF_UNDEF, NF_2D,
       NF_UNDEF, NF_2D,    NF_UNDEF, NF_2D,  NF_UNDEF, NF_2D, NF_UNDEF, NF_2D}};
  NEONFormatDecoder nfd(instr, &map);
  VectorFormat vf = nfd.GetVectorFormat();

  // 0001->8H, 001x->4S, 01xx->2D, all others undefined.
  static const NEONFormatMap map_l = {
      {22, 21, 20, 19},
      {NF_UNDEF, NF_8H, NF_4S, NF_4S, NF_2D, NF_2D, NF_2D, NF_2D}};
  VectorFormat vf_l = nfd.GetVectorFormat(&map_l);

  int highestSetBit = HighestSetBitPosition(instr->ImmNEONImmh());
  int immhimmb = instr->ImmNEONImmhImmb();
  int right_shift = (16 << highestSetBit) - immhimmb;
  int left_shift = immhimmb - (8 << highestSetBit);

  switch (instr->Mask(NEONShiftImmediateMask)) {
    case NEON_SHL:
      shl(vf, rd, rn, left_shift);
      break;
    case NEON_SLI:
      sli(vf, rd, rn, left_shift);
      break;
    case NEON_SQSHLU:
      sqshlu(vf, rd, rn, left_shift);
      break;
    case NEON_SRI:
      sri(vf, rd, rn, right_shift);
      break;
    case NEON_SSHR:
      sshr(vf, rd, rn, right_shift);
      break;
    case NEON_USHR:
      ushr(vf, rd, rn, right_shift);
      break;
    case NEON_SRSHR:
      sshr(vf, rd, rn, right_shift).Round(vf);
      break;
    case NEON_URSHR:
      ushr(vf, rd, rn, right_shift).Round(vf);
      break;
    case NEON_SSRA:
      ssra(vf, rd, rn, right_shift);
      break;
    case NEON_USRA:
      usra(vf, rd, rn, right_shift);
      break;
    case NEON_SRSRA:
      srsra(vf, rd, rn, right_shift);
      break;
    case NEON_URSRA:
      ursra(vf, rd, rn, right_shift);
      break;
    case NEON_SQSHL_imm:
      sqshl(vf, rd, rn, left_shift);
      break;
    case NEON_UQSHL_imm:
      uqshl(vf, rd, rn, left_shift);
      break;
    case NEON_SCVTF_imm:
      scvtf(vf, rd, rn, right_shift, fpcr_rounding);
      break;
    case NEON_UCVTF_imm:
      ucvtf(vf, rd, rn, right_shift, fpcr_rounding);
      break;
    case NEON_FCVTZS_imm:
      fcvts(vf, rd, rn, FPZero, right_shift);
      break;
    case NEON_FCVTZU_imm:
      fcvtu(vf, rd, rn, FPZero, right_shift);
      break;
    case NEON_SSHLL:
      vf = vf_l;
      if (instr->Mask(NEON_Q)) {
        sshll2(vf, rd, rn, left_shift);
      } else {
        sshll(vf, rd, rn, left_shift);
      }
      break;
    case NEON_USHLL:
      vf = vf_l;
      if (instr->Mask(NEON_Q)) {
        ushll2(vf, rd, rn, left_shift);
      } else {
        ushll(vf, rd, rn, left_shift);
      }
      break;
    case NEON_SHRN:
      if (instr->Mask(NEON_Q)) {
        shrn2(vf, rd, rn, right_shift);
      } else {
        shrn(vf, rd, rn, right_shift);
      }
      break;
    case NEON_RSHRN:
      if (instr->Mask(NEON_Q)) {
        rshrn2(vf, rd, rn, right_shift);
      } else {
        rshrn(vf, rd, rn, right_shift);
      }
      break;
    case NEON_UQSHRN:
      if (instr->Mask(NEON_Q)) {
        uqshrn2(vf, rd, rn, right_shift);
      } else {
        uqshrn(vf, rd, rn, right_shift);
      }
      break;
    case NEON_UQRSHRN:
      if (instr->Mask(NEON_Q)) {
        uqrshrn2(vf, rd, rn, right_shift);
      } else {
        uqrshrn(vf, rd, rn, right_shift);
      }
      break;
    case NEON_SQSHRN:
      if (instr->Mask(NEON_Q)) {
        sqshrn2(vf, rd, rn, right_shift);
      } else {
        sqshrn(vf, rd, rn, right_shift);
      }
      break;
    case NEON_SQRSHRN:
      if (instr->Mask(NEON_Q)) {
        sqrshrn2(vf, rd, rn, right_shift);
      } else {
        sqrshrn(vf, rd, rn, right_shift);
      }
      break;
    case NEON_SQSHRUN:
      if (instr->Mask(NEON_Q)) {
        sqshrun2(vf, rd, rn, right_shift);
      } else {
        sqshrun(vf, rd, rn, right_shift);
      }
      break;
    case NEON_SQRSHRUN:
      if (instr->Mask(NEON_Q)) {
        sqrshrun2(vf, rd, rn, right_shift);
      } else {
        sqrshrun(vf, rd, rn, right_shift);
      }
      break;
    default:
      UNIMPLEMENTED();
  }
}

void Simulator::VisitNEONTable(Instruction* instr) {
  NEONFormatDecoder nfd(instr, NEONFormatDecoder::LogicalFormatMap());
  VectorFormat vf = nfd.GetVectorFormat();

  SimVRegister& rd = vreg(instr->Rd());
  SimVRegister& rn = vreg(instr->Rn());
  SimVRegister& rn2 = vreg((instr->Rn() + 1) % kNumberOfVRegisters);
  SimVRegister& rn3 = vreg((instr->Rn() + 2) % kNumberOfVRegisters);
  SimVRegister& rn4 = vreg((instr->Rn() + 3) % kNumberOfVRegisters);
  SimVRegister& rm = vreg(instr->Rm());

  switch (instr->Mask(NEONTableMask)) {
    case NEON_TBL_1v:
      tbl(vf, rd, rn, rm);
      break;
    case NEON_TBL_2v:
      tbl(vf, rd, rn, rn2, rm);
      break;
    case NEON_TBL_3v:
      tbl(vf, rd, rn, rn2, rn3, rm);
      break;
    case NEON_TBL_4v:
      tbl(vf, rd, rn, rn2, rn3, rn4, rm);
      break;
    case NEON_TBX_1v:
      tbx(vf, rd, rn, rm);
      break;
    case NEON_TBX_2v:
      tbx(vf, rd, rn, rn2, rm);
      break;
    case NEON_TBX_3v:
      tbx(vf, rd, rn, rn2, rn3, rm);
      break;
    case NEON_TBX_4v:
      tbx(vf, rd, rn, rn2, rn3, rn4, rm);
      break;
    default:
      UNIMPLEMENTED();
  }
}

void Simulator::VisitNEONPerm(Instruction* instr) {
  NEONFormatDecoder nfd(instr);
  VectorFormat vf = nfd.GetVectorFormat();

  SimVRegister& rd = vreg(instr->Rd());
  SimVRegister& rn = vreg(instr->Rn());
  SimVRegister& rm = vreg(instr->Rm());

  switch (instr->Mask(NEONPermMask)) {
    case NEON_TRN1:
      trn1(vf, rd, rn, rm);
      break;
    case NEON_TRN2:
      trn2(vf, rd, rn, rm);
      break;
    case NEON_UZP1:
      uzp1(vf, rd, rn, rm);
      break;
    case NEON_UZP2:
      uzp2(vf, rd, rn, rm);
      break;
    case NEON_ZIP1:
      zip1(vf, rd, rn, rm);
      break;
    case NEON_ZIP2:
      zip2(vf, rd, rn, rm);
      break;
    default:
      UNIMPLEMENTED();
  }
}
5577 5578

void Simulator::DoPrintf(Instruction* instr) {
5579
  DCHECK((instr->Mask(ExceptionMask) == HLT) &&
5580 5581 5582 5583 5584 5585 5586 5587 5588 5589 5590 5591 5592
              (instr->ImmException() == kImmExceptionIsPrintf));

  // Read the arguments encoded inline in the instruction stream.
  uint32_t arg_count;
  uint32_t arg_pattern_list;
  STATIC_ASSERT(sizeof(*instr) == 1);
  memcpy(&arg_count,
         instr + kPrintfArgCountOffset,
         sizeof(arg_count));
  memcpy(&arg_pattern_list,
         instr + kPrintfArgPatternListOffset,
         sizeof(arg_pattern_list));

5593 5594
  DCHECK_LE(arg_count, kPrintfMaxArgCount);
  DCHECK_EQ(arg_pattern_list >> (kPrintfArgPatternBits * arg_count), 0);
5595 5596 5597 5598 5599 5600 5601 5602 5603 5604 5605

  // We need to call the host printf function with a set of arguments defined by
  // arg_pattern_list. Because we don't know the types and sizes of the
  // arguments, this is very difficult to do in a robust and portable way. To
  // work around the problem, we pick apart the format string, and print one
  // format placeholder at a time.

  // Allocate space for the format string. We take a copy, so we can modify it.
  // Leave enough space for one extra character per expected argument (plus the
  // '\0' termination).
  const char * format_base = reg<const char *>(0);
5606
  DCHECK_NOT_NULL(format_base);
5607 5608 5609 5610 5611 5612 5613 5614 5615 5616 5617 5618 5619 5620 5621 5622 5623 5624 5625 5626 5627 5628 5629 5630 5631 5632 5633 5634 5635 5636 5637 5638 5639 5640
  size_t length = strlen(format_base) + 1;
  char * const format = new char[length + arg_count];

  // A list of chunks, each with exactly one format placeholder.
  const char * chunks[kPrintfMaxArgCount];

  // Copy the format string and search for format placeholders.
  uint32_t placeholder_count = 0;
  char * format_scratch = format;
  for (size_t i = 0; i < length; i++) {
    if (format_base[i] != '%') {
      *format_scratch++ = format_base[i];
    } else {
      if (format_base[i + 1] == '%') {
        // Ignore explicit "%%" sequences.
        *format_scratch++ = format_base[i];

        if (placeholder_count == 0) {
          // The first chunk is passed to printf using "%s", so we need to
          // unescape "%%" sequences in this chunk. (Just skip the next '%'.)
          i++;
        } else {
          // Otherwise, pass through "%%" unchanged.
          *format_scratch++ = format_base[++i];
        }
      } else {
        CHECK(placeholder_count < arg_count);
        // Insert '\0' before placeholders, and store their locations.
        *format_scratch++ = '\0';
        chunks[placeholder_count++] = format_scratch;
        *format_scratch++ = format_base[i];
      }
    }
  }
5641
  DCHECK(format_scratch <= (format + length + arg_count));
5642 5643 5644 5645 5646 5647 5648 5649 5650 5651 5652 5653 5654 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 5682 5683 5684 5685 5686 5687 5688 5689 5690 5691 5692 5693 5694 5695 5696 5697 5698 5699 5700 5701 5702
  CHECK(placeholder_count == arg_count);

  // Finally, call printf with each chunk, passing the appropriate register
  // argument. Normally, printf returns the number of bytes transmitted, so we
  // can emulate a single printf call by adding the result from each chunk. If
  // any call returns a negative (error) value, though, just return that value.

  fprintf(stream_, "%s", clr_printf);

  // Because '\0' is inserted before each placeholder, the first string in
  // 'format' contains no format placeholders and should be printed literally.
  int result = fprintf(stream_, "%s", format);
  int pcs_r = 1;      // Start at x1. x0 holds the format string.
  int pcs_f = 0;      // Start at d0.
  if (result >= 0) {
    for (uint32_t i = 0; i < placeholder_count; i++) {
      int part_result = -1;

      uint32_t arg_pattern = arg_pattern_list >> (i * kPrintfArgPatternBits);
      arg_pattern &= (1 << kPrintfArgPatternBits) - 1;
      switch (arg_pattern) {
        case kPrintfArgW:
          part_result = fprintf(stream_, chunks[i], wreg(pcs_r++));
          break;
        case kPrintfArgX:
          part_result = fprintf(stream_, chunks[i], xreg(pcs_r++));
          break;
        case kPrintfArgD:
          part_result = fprintf(stream_, chunks[i], dreg(pcs_f++));
          break;
        default: UNREACHABLE();
      }

      if (part_result < 0) {
        // Handle error values.
        result = part_result;
        break;
      }

      result += part_result;
    }
  }

  fprintf(stream_, "%s", clr_normal);

#ifdef DEBUG
  CorruptAllCallerSavedCPURegisters();
#endif

  // Printf returns its result in x0 (just like the C library's printf).
  set_xreg(0, result);

  // The printf parameters are inlined in the code, so skip them.
  set_pc(instr->InstructionAtOffset(kPrintfLength));

  // Set LR as if we'd just called a native printf function.
  set_lr(pc());

  delete[] format;
}

5703 5704 5705 5706 5707 5708 5709 5710 5711 5712 5713
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;
}

5714
void Simulator::LocalMonitor::NotifyLoad() {
5715 5716 5717 5718 5719 5720 5721 5722 5723 5724 5725 5726 5727 5728
  if (access_state_ == MonitorAccess::Exclusive) {
    // A non exclusive 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::NotifyLoadExcl(uintptr_t addr,
                                             TransactionSize size) {
  access_state_ = MonitorAccess::Exclusive;
  tagged_addr_ = addr;
  size_ = size;
}

5729
void Simulator::LocalMonitor::NotifyStore() {
5730 5731 5732 5733 5734 5735 5736 5737 5738 5739 5740 5741 5742 5743 5744 5745 5746 5747 5748 5749 5750 5751 5752 5753 5754 5755 5756 5757 5758 5759 5760 5761 5762 5763 5764 5765 5766 5767 5768 5769 5770 5771 5772 5773 5774 5775 5776
  if (access_state_ == MonitorAccess::Exclusive) {
    // 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::NotifyStoreExcl(uintptr_t addr,
                                              TransactionSize size) {
  if (access_state_ == MonitorAccess::Exclusive) {
    // It is allowed for a processor to require that the address matches
    // exactly (B2.10.1), so this comparison does not mask addr.
    if (addr == tagged_addr_ && size_ == size) {
      Clear();
      return true;
    } else {
      // It is implementation-defined whether an exclusive store to a
      // non-tagged address will update memory. As a result, it's most strict
      // to unconditionally clear the local monitor.
      Clear();
      return false;
    }
  } else {
    DCHECK(access_state_ == MonitorAccess::Open);
    return false;
  }
}

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

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

void Simulator::GlobalMonitor::Processor::NotifyLoadExcl_Locked(
    uintptr_t addr) {
  access_state_ = MonitorAccess::Exclusive;
  tagged_addr_ = addr;
}

void Simulator::GlobalMonitor::Processor::NotifyStore_Locked(
5777
    bool is_requesting_processor) {
5778 5779 5780 5781 5782 5783 5784 5785 5786 5787 5788 5789 5790 5791 5792 5793 5794 5795 5796 5797 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
  if (access_state_ == MonitorAccess::Exclusive) {
    // 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::Processor::NotifyStoreExcl_Locked(
    uintptr_t addr, bool is_requesting_processor) {
  if (access_state_ == MonitorAccess::Exclusive) {
    if (is_requesting_processor) {
      // It is allowed for a processor to require that the address matches
      // exactly (B2.10.2), so this comparison does not mask addr.
      if (addr == tagged_addr_) {
        Clear_Locked();
        // Introduce occasional stxr 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 processor so the implementation is more conservative (i.e. the
      // granularity of locking is as large as possible.)
      Clear_Locked();
      return false;
    }
  }
  return false;
}

Simulator::GlobalMonitor::GlobalMonitor() : head_(nullptr) {}

void Simulator::GlobalMonitor::NotifyLoadExcl_Locked(uintptr_t addr,
                                                     Processor* processor) {
  processor->NotifyLoadExcl_Locked(addr);
  PrependProcessor_Locked(processor);
}

5823
void Simulator::GlobalMonitor::NotifyStore_Locked(Processor* processor) {
5824 5825 5826
  // Notify each processor of the store operation.
  for (Processor* iter = head_; iter; iter = iter->next_) {
    bool is_requesting_processor = iter == processor;
5827
    iter->NotifyStore_Locked(is_requesting_processor);
5828 5829 5830 5831 5832 5833 5834 5835 5836 5837 5838 5839 5840 5841 5842 5843 5844 5845 5846 5847 5848 5849 5850 5851 5852 5853 5854 5855 5856 5857 5858 5859 5860 5861 5862 5863 5864 5865 5866 5867 5868 5869 5870 5871 5872 5873 5874 5875 5876 5877 5878 5879 5880 5881
  }
}

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

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

void Simulator::GlobalMonitor::PrependProcessor_Locked(Processor* processor) {
  if (IsProcessorInLinkedList_Locked(processor)) {
    return;
  }

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

void Simulator::GlobalMonitor::RemoveProcessor(Processor* processor) {
  base::LockGuard<base::Mutex> lock_guard(&mutex);
  if (!IsProcessorInLinkedList_Locked(processor)) {
    return;
  }

  if (processor->prev_) {
    processor->prev_->next_ = processor->next_;
  } else {
    head_ = processor->next_;
  }
  if (processor->next_) {
    processor->next_->prev_ = processor->prev_;
  }
  processor->prev_ = nullptr;
  processor->next_ = nullptr;
}
5882

5883 5884
#endif  // USE_SIMULATOR

5885 5886
}  // namespace internal
}  // namespace v8
5887

5888
#endif  // V8_TARGET_ARCH_ARM64