10 #if V8_TARGET_ARCH_ARM64
22 #if defined(USE_SIMULATOR)
33 #define COLOUR(colour_code) "\033[0;" colour_code "m"
34 #define COLOUR_BOLD(colour_code) "\033[1;" colour_code "m"
44 typedef char const *
const TEXT_COLOUR;
45 TEXT_COLOUR clr_normal = FLAG_log_colour ? COLOUR(
NORMAL) :
"";
46 TEXT_COLOUR clr_flag_name = FLAG_log_colour ? COLOUR_BOLD(WHITE) :
"";
47 TEXT_COLOUR clr_flag_value = FLAG_log_colour ? COLOUR(
NORMAL) :
"";
48 TEXT_COLOUR clr_reg_name = FLAG_log_colour ? COLOUR_BOLD(CYAN) :
"";
49 TEXT_COLOUR clr_reg_value = FLAG_log_colour ? COLOUR(CYAN) :
"";
50 TEXT_COLOUR clr_fpreg_name = FLAG_log_colour ? COLOUR_BOLD(MAGENTA) :
"";
51 TEXT_COLOUR clr_fpreg_value = FLAG_log_colour ? COLOUR(MAGENTA) :
"";
52 TEXT_COLOUR clr_memory_address = FLAG_log_colour ? COLOUR_BOLD(BLUE) :
"";
53 TEXT_COLOUR clr_debug_number = FLAG_log_colour ? COLOUR_BOLD(YELLOW) :
"";
54 TEXT_COLOUR clr_debug_message = FLAG_log_colour ? COLOUR(YELLOW) :
"";
55 TEXT_COLOUR clr_printf = FLAG_log_colour ? COLOUR(GREEN) :
"";
59 void Simulator::TraceSim(
const char* format, ...) {
62 va_start(arguments, format);
69 const Instruction* Simulator::kEndOfSimAddress =
NULL;
72 void SimSystemRegister::SetBits(
int msb,
int lsb,
uint32_t bits) {
73 int width = msb - lsb + 1;
77 uint32_t mask = ((1 << width) - 1) << lsb;
78 DCHECK((mask & write_ignore_mask_) == 0);
80 value_ = (value_ & ~mask) | (bits & mask);
84 SimSystemRegister SimSystemRegister::DefaultValueFor(
SystemRegister id) {
87 return SimSystemRegister(0x00000000, NZCVWriteIgnoreMask);
89 return SimSystemRegister(0x00000000, FPCRWriteIgnoreMask);
92 return SimSystemRegister();
97 void Simulator::Initialize(Isolate* isolate) {
98 if (isolate->simulator_initialized())
return;
99 isolate->set_simulator_initialized(
true);
100 ExternalReference::set_redirector(isolate, &RedirectExternalReference);
105 Simulator* Simulator::current(Isolate* isolate) {
106 Isolate::PerIsolateThreadData* isolate_data =
107 isolate->FindOrAllocatePerThreadDataForThisThread();
110 Simulator* sim = isolate_data->simulator();
112 if (FLAG_trace_sim || FLAG_log_instruction_stats || FLAG_debug_sim) {
113 sim =
new Simulator(
new Decoder<DispatchingDecoderVisitor>(), isolate);
115 sim =
new Decoder<Simulator>();
116 sim->isolate_ = isolate;
118 isolate_data->set_simulator(sim);
124 void Simulator::CallVoid(
byte* entry, CallArgument* args) {
128 std::vector<int64_t> stack_args(0);
129 for (
int i = 0; !args[
i].IsEnd();
i++) {
130 CallArgument arg = args[
i];
131 if (arg.IsX() && (index_x < 8)) {
132 set_xreg(index_x++, arg.bits());
133 }
else if (arg.IsD() && (index_d < 8)) {
134 set_dreg_bits(index_d++, arg.bits());
136 DCHECK(arg.IsD() || arg.IsX());
137 stack_args.push_back(arg.bits());
144 stack_args.size() *
sizeof(stack_args[0]);
148 char * stack =
reinterpret_cast<char*
>(entry_stack);
149 std::vector<int64_t>::const_iterator it;
150 for (it = stack_args.begin(); it != stack_args.end(); it++) {
151 memcpy(stack, &(*it),
sizeof(*it));
152 stack +=
sizeof(*it);
160 set_lr(kEndOfSimAddress);
161 CheckPCSComplianceAndRun();
163 set_sp(original_stack);
167 int64_t Simulator::CallInt64(
byte* entry, CallArgument* args) {
168 CallVoid(entry, args);
173 double Simulator::CallDouble(
byte* entry, CallArgument* args) {
174 CallVoid(entry, args);
179 int64_t Simulator::CallJS(
byte* entry,
180 byte* function_entry,
185 CallArgument args[] = {
186 CallArgument(function_entry),
193 return CallInt64(entry, args);
196 int64_t Simulator::CallRegExp(
byte* entry,
198 int64_t start_offset,
199 const byte* input_start,
200 const byte* input_end,
205 void* return_address,
207 CallArgument args[] = {
209 CallArgument(start_offset),
210 CallArgument(input_start),
211 CallArgument(input_end),
212 CallArgument(output),
213 CallArgument(output_size),
214 CallArgument(stack_base),
215 CallArgument(direct_call),
216 CallArgument(return_address),
217 CallArgument(isolate),
220 return CallInt64(entry, args);
224 void Simulator::CheckPCSComplianceAndRun() {
238 saved_registers[
i] = xreg(register_list.PopLowestIndex().code());
241 saved_fpregisters[
i] =
242 dreg_bits(fpregister_list.PopLowestIndex().code());
244 int64_t original_stack =
sp();
254 CHECK_EQ(saved_registers[
i], xreg(register_list.PopLowestIndex().code()));
258 dreg_bits(fpregister_list.PopLowestIndex().code()));
266 register_list.Remove(x0);
267 register_list.Remove(x1);
272 fpregister_list.Remove(
d0);
274 CorruptRegisters(®ister_list, kCallerSavedRegisterCorruptionValue);
275 CorruptRegisters(&fpregister_list, kCallerSavedFPRegisterCorruptionValue);
283 void Simulator::CorruptRegisters(CPURegList* list, uint64_t value) {
285 while (!list->IsEmpty()) {
286 unsigned code = list->PopLowestIndex().code();
287 set_xreg(code, value | code);
291 while (!list->IsEmpty()) {
292 unsigned code = list->PopLowestIndex().code();
293 set_dreg_bits(code, value | code);
299 void Simulator::CorruptAllCallerSavedCPURegisters() {
304 CorruptRegisters(®ister_list, kCallerSavedRegisterCorruptionValue);
305 CorruptRegisters(&fpregister_list, kCallerSavedFPRegisterCorruptionValue);
325 intptr_t current_sp =
sp();
335 uintptr_t Simulator::StackLimit()
const {
338 return stack_limit_ + 1024;
342 Simulator::Simulator(Decoder<DispatchingDecoderVisitor>* decoder,
343 Isolate* isolate, FILE* stream)
345 last_debugger_input_(
NULL),
349 decoder_->AppendVisitor(
this);
353 if (FLAG_trace_sim) {
354 decoder_->InsertVisitorBefore(print_disasm_,
this);
358 if (FLAG_log_instruction_stats) {
359 instrument_ =
new Instrument(FLAG_log_instruction_file,
360 FLAG_log_instruction_period);
361 decoder_->AppendVisitor(instrument_);
366 Simulator::Simulator()
368 last_debugger_input_(
NULL),
372 CHECK(!FLAG_trace_sim && !FLAG_log_instruction_stats);
376 void Simulator::Init(FILE* stream) {
380 stack_size_ = (FLAG_sim_stack_size *
KB) + (2 * stack_protection_size_);
381 stack_ =
reinterpret_cast<uintptr_t>(
new byte[stack_size_]);
382 stack_limit_ = stack_ + stack_protection_size_;
383 uintptr_t tos = stack_ + stack_size_ - stack_protection_size_;
385 set_sp(tos & ~0xfUL);
388 print_disasm_ =
new PrintDisassembler(stream_);
392 disassembler_decoder_ =
new Decoder<DispatchingDecoderVisitor>();
393 disassembler_decoder_->AppendVisitor(print_disasm_);
397 void Simulator::ResetState() {
399 nzcv_ = SimSystemRegister::DefaultValueFor(
NZCV);
400 fpcr_ = SimSystemRegister::DefaultValueFor(
FPCR);
405 set_xreg(
i, 0xbadbeef);
409 set_dreg_bits(
i, 0x7ff000007f800001UL);
412 set_lr(kEndOfSimAddress);
415 breakpoints_.empty();
416 break_on_next_=
false;
420 Simulator::~Simulator() {
421 delete[]
reinterpret_cast<byte*
>(stack_);
422 if (FLAG_log_instruction_stats) {
425 delete disassembler_decoder_;
426 delete print_disasm_;
432 void Simulator::Run() {
433 pc_modified_ =
false;
434 while (pc_ != kEndOfSimAddress) {
435 ExecuteInstruction();
440 void Simulator::RunFrom(Instruction* start) {
456 : external_function_(external_function),
459 redirect_call_.SetInstructionBits(
461 Isolate* isolate = Isolate::Current();
462 next_ = isolate->simulator_redirection();
464 isolate->set_simulator_redirection(
this);
467 void* address_of_redirect_call() {
468 return reinterpret_cast<void*
>(&redirect_call_);
471 template <
typename T>
472 T external_function() {
return reinterpret_cast<T>(external_function_); }
476 static Redirection* Get(
void* external_function,
478 Isolate* isolate = Isolate::Current();
479 Redirection* current = isolate->simulator_redirection();
480 for (; current !=
NULL; current = current->next_) {
481 if (current->external_function_ == external_function) {
486 return new Redirection(external_function, type);
489 static Redirection* FromHltInstruction(Instruction* redirect_call) {
490 char* addr_of_hlt =
reinterpret_cast<char*
>(redirect_call);
491 char* addr_of_redirection =
492 addr_of_hlt -
OFFSET_OF(Redirection, redirect_call_);
493 return reinterpret_cast<Redirection*
>(addr_of_redirection);
496 static void* ReverseRedirection(int64_t reg) {
497 Redirection* redirection =
498 FromHltInstruction(
reinterpret_cast<Instruction*
>(reg));
499 return redirection->external_function<
void*>();
503 void* external_function_;
504 Instruction redirect_call_;
521 typedef ObjectPair (*SimulatorRuntimeCall)(int64_t arg0,
530 typedef int64_t (*SimulatorRuntimeCompareCall)(
double arg1,
double arg2);
531 typedef double (*SimulatorRuntimeFPFPCall)(
double arg1,
double arg2);
532 typedef double (*SimulatorRuntimeFPCall)(
double arg1);
533 typedef double (*SimulatorRuntimeFPIntCall)(
double arg1,
int32_t arg2);
537 typedef void (*SimulatorRuntimeDirectApiCall)(int64_t arg0);
538 typedef void (*SimulatorRuntimeProfilingApiCall)(int64_t arg0,
void* arg1);
541 typedef void (*SimulatorRuntimeDirectGetterCall)(int64_t arg0, int64_t arg1);
542 typedef void (*SimulatorRuntimeProfilingGetterCall)(int64_t arg0, int64_t arg1,
545 void Simulator::DoRuntimeCall(Instruction* instr) {
546 Redirection* redirection = Redirection::FromHltInstruction(instr);
551 Instruction* return_address =
lr();
553 int64_t external = redirection->external_function<int64_t>();
555 TraceSim(
"Call to host function at %p\n",
556 redirection->external_function<
void*>());
559 bool stack_alignment_exception = ((
sp() & 0xf) != 0);
560 if (stack_alignment_exception) {
561 TraceSim(
" with unaligned stack 0x%016" PRIx64
".\n",
sp());
562 FATAL(
"ALIGNMENT EXCEPTION");
565 switch (redirection->type()) {
567 TraceSim(
"Type: Unknown.\n");
571 case ExternalReference::BUILTIN_CALL: {
573 TraceSim(
"Type: BUILTIN_CALL\n");
574 SimulatorRuntimeCall target =
575 reinterpret_cast<SimulatorRuntimeCall
>(external);
580 TraceSim(
"Arguments: "
581 "0x%016" PRIx64
", 0x%016" PRIx64
", "
582 "0x%016" PRIx64
", 0x%016" PRIx64
", "
583 "0x%016" PRIx64
", 0x%016" PRIx64
", "
584 "0x%016" PRIx64
", 0x%016" PRIx64,
585 xreg(0), xreg(1), xreg(2), xreg(3),
586 xreg(4), xreg(5), xreg(6), xreg(7));
587 ObjectPair result = target(xreg(0), xreg(1), xreg(2), xreg(3),
588 xreg(4), xreg(5), xreg(6), xreg(7));
589 TraceSim(
"Returned: {0x%" PRIx64
", 0x%" PRIx64
"}\n",
590 result.res0, result.res1);
592 CorruptAllCallerSavedCPURegisters();
594 set_xreg(0, result.res0);
595 set_xreg(1, result.res1);
599 case ExternalReference::DIRECT_API_CALL: {
601 TraceSim(
"Type: DIRECT_API_CALL\n");
602 SimulatorRuntimeDirectApiCall target =
603 reinterpret_cast<SimulatorRuntimeDirectApiCall
>(external);
604 TraceSim(
"Arguments: 0x%016" PRIx64
"\n", xreg(0));
606 TraceSim(
"No return value.");
608 CorruptAllCallerSavedCPURegisters();
613 case ExternalReference::BUILTIN_COMPARE_CALL: {
615 TraceSim(
"Type: BUILTIN_COMPARE_CALL\n");
616 SimulatorRuntimeCompareCall target =
617 reinterpret_cast<SimulatorRuntimeCompareCall
>(external);
618 TraceSim(
"Arguments: %f, %f\n", dreg(0), dreg(1));
619 int64_t result = target(dreg(0), dreg(1));
620 TraceSim(
"Returned: %" PRId64
"\n", result);
622 CorruptAllCallerSavedCPURegisters();
628 case ExternalReference::BUILTIN_FP_CALL: {
630 TraceSim(
"Type: BUILTIN_FP_CALL\n");
631 SimulatorRuntimeFPCall target =
632 reinterpret_cast<SimulatorRuntimeFPCall
>(external);
633 TraceSim(
"Argument: %f\n", dreg(0));
634 double result = target(dreg(0));
635 TraceSim(
"Returned: %f\n", result);
637 CorruptAllCallerSavedCPURegisters();
643 case ExternalReference::BUILTIN_FP_FP_CALL: {
645 TraceSim(
"Type: BUILTIN_FP_FP_CALL\n");
646 SimulatorRuntimeFPFPCall target =
647 reinterpret_cast<SimulatorRuntimeFPFPCall
>(external);
648 TraceSim(
"Arguments: %f, %f\n", dreg(0), dreg(1));
649 double result = target(dreg(0), dreg(1));
650 TraceSim(
"Returned: %f\n", result);
652 CorruptAllCallerSavedCPURegisters();
658 case ExternalReference::BUILTIN_FP_INT_CALL: {
660 TraceSim(
"Type: BUILTIN_FP_INT_CALL\n");
661 SimulatorRuntimeFPIntCall target =
662 reinterpret_cast<SimulatorRuntimeFPIntCall
>(external);
663 TraceSim(
"Arguments: %f, %d\n", dreg(0), wreg(0));
664 double result = target(dreg(0), wreg(0));
665 TraceSim(
"Returned: %f\n", result);
667 CorruptAllCallerSavedCPURegisters();
673 case ExternalReference::DIRECT_GETTER_CALL: {
675 TraceSim(
"Type: DIRECT_GETTER_CALL\n");
676 SimulatorRuntimeDirectGetterCall target =
677 reinterpret_cast<SimulatorRuntimeDirectGetterCall
>(external);
678 TraceSim(
"Arguments: 0x%016" PRIx64
", 0x%016" PRIx64
"\n",
680 target(xreg(0), xreg(1));
681 TraceSim(
"No return value.");
683 CorruptAllCallerSavedCPURegisters();
688 case ExternalReference::PROFILING_API_CALL: {
690 TraceSim(
"Type: PROFILING_API_CALL\n");
691 SimulatorRuntimeProfilingApiCall target =
692 reinterpret_cast<SimulatorRuntimeProfilingApiCall
>(external);
693 void* arg1 = Redirection::ReverseRedirection(xreg(1));
694 TraceSim(
"Arguments: 0x%016" PRIx64
", %p\n", xreg(0), arg1);
695 target(xreg(0), arg1);
696 TraceSim(
"No return value.");
698 CorruptAllCallerSavedCPURegisters();
703 case ExternalReference::PROFILING_GETTER_CALL: {
706 TraceSim(
"Type: PROFILING_GETTER_CALL\n");
707 SimulatorRuntimeProfilingGetterCall target =
708 reinterpret_cast<SimulatorRuntimeProfilingGetterCall
>(
710 void* arg2 = Redirection::ReverseRedirection(xreg(2));
711 TraceSim(
"Arguments: 0x%016" PRIx64
", 0x%016" PRIx64
", %p\n",
712 xreg(0), xreg(1), arg2);
713 target(xreg(0), xreg(1), arg2);
714 TraceSim(
"No return value.");
716 CorruptAllCallerSavedCPURegisters();
722 set_lr(return_address);
723 set_pc(return_address);
727 void* Simulator::RedirectExternalReference(
void* external_function,
729 Redirection* redirection = Redirection::Get(external_function, type);
730 return redirection->address_of_redirect_call();
734 const char* Simulator::xreg_names[] = {
735 "x0",
"x1",
"x2",
"x3",
"x4",
"x5",
"x6",
"x7",
736 "x8",
"x9",
"x10",
"x11",
"x12",
"x13",
"x14",
"x15",
737 "ip0",
"ip1",
"x18",
"x19",
"x20",
"x21",
"x22",
"x23",
738 "x24",
"x25",
"x26",
"cp",
"jssp",
"fp",
"lr",
"xzr",
"csp"};
740 const char* Simulator::wreg_names[] = {
741 "w0",
"w1",
"w2",
"w3",
"w4",
"w5",
"w6",
"w7",
742 "w8",
"w9",
"w10",
"w11",
"w12",
"w13",
"w14",
"w15",
743 "w16",
"w17",
"w18",
"w19",
"w20",
"w21",
"w22",
"w23",
744 "w24",
"w25",
"w26",
"wcp",
"wjssp",
"wfp",
"wlr",
"wzr",
"wcsp"};
746 const char* Simulator::sreg_names[] = {
747 "s0",
"s1",
"s2",
"s3",
"s4",
"s5",
"s6",
"s7",
748 "s8",
"s9",
"s10",
"s11",
"s12",
"s13",
"s14",
"s15",
749 "s16",
"s17",
"s18",
"s19",
"s20",
"s21",
"s22",
"s23",
750 "s24",
"s25",
"s26",
"s27",
"s28",
"s29",
"s30",
"s31"};
752 const char* Simulator::dreg_names[] = {
753 "d0",
"d1",
"d2",
"d3",
"d4",
"d5",
"d6",
"d7",
754 "d8",
"d9",
"d10",
"d11",
"d12",
"d13",
"d14",
"d15",
755 "d16",
"d17",
"d18",
"d19",
"d20",
"d21",
"d22",
"d23",
756 "d24",
"d25",
"d26",
"d27",
"d28",
"d29",
"d30",
"d31"};
758 const char* Simulator::vreg_names[] = {
759 "v0",
"v1",
"v2",
"v3",
"v4",
"v5",
"v6",
"v7",
760 "v8",
"v9",
"v10",
"v11",
"v12",
"v13",
"v14",
"v15",
761 "v16",
"v17",
"v18",
"v19",
"v20",
"v21",
"v22",
"v23",
762 "v24",
"v25",
"v26",
"v27",
"v28",
"v29",
"v30",
"v31"};
765 const char* Simulator::WRegNameForCode(
unsigned code,
Reg31Mode mode) {
776 return wreg_names[code];
780 const char* Simulator::XRegNameForCode(
unsigned code,
Reg31Mode mode) {
789 return xreg_names[code];
793 const char* Simulator::SRegNameForCode(
unsigned code) {
800 const char* Simulator::DRegNameForCode(
unsigned code) {
807 const char* Simulator::VRegNameForCode(
unsigned code) {
814 int Simulator::CodeFromName(
const char*
name) {
816 if ((strcmp(xreg_names[
i],
name) == 0) ||
817 (strcmp(wreg_names[
i],
name) == 0)) {
822 if ((strcmp(vreg_names[
i],
name) == 0) ||
823 (strcmp(dreg_names[
i],
name) == 0) ||
824 (strcmp(sreg_names[
i],
name) == 0)) {
828 if ((strcmp(
"csp",
name) == 0) || (strcmp(
"wcsp",
name) == 0)) {
836 template <
typename T>
837 T Simulator::AddWithCarry(
bool set_flags,
841 typedef typename make_unsigned<T>::type unsignedT;
842 DCHECK((carry_in == 0) || (carry_in == 1));
844 T signed_sum = src1 + src2 + carry_in;
845 T result = signed_sum;
850 unsignedT u1 =
static_cast<unsignedT
>(src1);
851 unsignedT u2 =
static_cast<unsignedT
>(src2);
852 unsignedT urest = std::numeric_limits<unsignedT>::max() - u1;
853 C = (u2 > urest) || (carry_in && (((u2 + 1) > urest) || (u2 > (urest - 1))));
857 V = ((src1 ^ src2) >= 0) && ((src1 ^ result) < 0);
859 N = CalcNFlag(result);
860 Z = CalcZFlag(result);
867 LogSystemRegister(
NZCV);
874 void Simulator::AddSubWithCarry(Instruction* instr) {
875 T op2 = reg<T>(instr->Rm());
882 new_val = AddWithCarry<T>(instr->FlagsUpdate(),
887 set_reg<T>(instr->Rd(), new_val);
890 template <
typename T>
891 T Simulator::ShiftOperand(
T value,
Shift shift_type,
unsigned amount) {
892 typedef typename make_unsigned<T>::type unsignedT;
898 switch (shift_type) {
900 return value << amount;
902 return static_cast<unsignedT
>(value) >> amount;
904 return value >> amount;
906 return (
static_cast<unsignedT
>(value) >> amount) |
907 ((value & ((1L << amount) - 1L)) <<
908 (
sizeof(unsignedT) * 8 - amount));
916 template <
typename T>
917 T Simulator::ExtendValue(
T value,
Extend extend_type,
unsigned left_shift) {
918 const unsigned kSignExtendBShift = (
sizeof(
T) - 1) * 8;
919 const unsigned kSignExtendHShift = (
sizeof(
T) - 2) * 8;
920 const unsigned kSignExtendWShift = (
sizeof(
T) - 4) * 8;
922 switch (extend_type) {
933 value = (value << kSignExtendBShift) >> kSignExtendBShift;
936 value = (value << kSignExtendHShift) >> kSignExtendHShift;
939 value = (value << kSignExtendWShift) >> kSignExtendWShift;
947 return value << left_shift;
951 template <
typename T>
952 void Simulator::Extract(Instruction* instr) {
953 unsigned lsb = instr->ImmS();
954 T op2 = reg<T>(instr->Rm());
958 T op1 = reg<T>(instr->Rn());
959 result = op2 >> lsb | (op1 << ((
sizeof(
T) * 8) - lsb));
961 set_reg<T>(instr->Rd(), result);
965 template<>
double Simulator::FPDefaultNaN<double>()
const {
966 return kFP64DefaultNaN;
970 template<>
float Simulator::FPDefaultNaN<float>()
const {
971 return kFP32DefaultNaN;
975 void Simulator::FPCompare(
double val0,
double val1) {
976 AssertSupportedFPCR();
980 if ((std::isnan(val0) != 0) || (std::isnan(val1) != 0)) {
982 }
else if (val0 < val1) {
984 }
else if (val0 > val1) {
986 }
else if (val0 == val1) {
991 LogSystemRegister(
NZCV);
995 void Simulator::SetBreakpoint(Instruction* location) {
996 for (
unsigned i = 0;
i < breakpoints_.size();
i++) {
997 if (breakpoints_.at(
i).location == location) {
999 "Existing breakpoint at %p was %s\n",
1000 reinterpret_cast<void*
>(location),
1001 breakpoints_.at(
i).enabled ?
"disabled" :
"enabled");
1002 breakpoints_.at(
i).enabled = !breakpoints_.at(
i).enabled;
1006 Breakpoint new_breakpoint = {location,
true};
1007 breakpoints_.push_back(new_breakpoint);
1009 "Set a breakpoint at %p\n",
reinterpret_cast<void*
>(location));
1013 void Simulator::ListBreakpoints() {
1014 PrintF(stream_,
"Breakpoints:\n");
1015 for (
unsigned i = 0;
i < breakpoints_.size();
i++) {
1016 PrintF(stream_,
"%p : %s\n",
1017 reinterpret_cast<void*
>(breakpoints_.at(
i).location),
1018 breakpoints_.at(
i).enabled ?
"enabled" :
"disabled");
1023 void Simulator::CheckBreakpoints() {
1024 bool hit_a_breakpoint =
false;
1025 for (
unsigned i = 0;
i < breakpoints_.size();
i++) {
1026 if ((breakpoints_.at(
i).location == pc_) &&
1027 breakpoints_.at(
i).enabled) {
1028 hit_a_breakpoint =
true;
1030 breakpoints_.at(
i).enabled =
false;
1033 if (hit_a_breakpoint) {
1034 PrintF(stream_,
"Hit and disabled a breakpoint at %p.\n",
1035 reinterpret_cast<void*
>(pc_));
1041 void Simulator::CheckBreakNext() {
1043 if (break_on_next_ && pc_->IsBranchAndLinkToRegister()) {
1044 SetBreakpoint(pc_->following());
1045 break_on_next_ =
false;
1050 void Simulator::PrintInstructionsAt(Instruction* start, uint64_t count) {
1052 for (Instruction*
pc = start;
pc < end;
pc =
pc->following()) {
1053 disassembler_decoder_->Decode(
pc);
1058 void Simulator::PrintSystemRegisters() {
1059 PrintSystemRegister(
NZCV);
1060 PrintSystemRegister(
FPCR);
1064 void Simulator::PrintRegisters() {
1071 void Simulator::PrintFPRegisters() {
1078 void Simulator::PrintRegister(
unsigned code,
Reg31Mode r31mode) {
1085 fprintf(stream_,
"# %s%5s: %s0x%016" PRIx64
"%s\n",
1086 clr_reg_name, XRegNameForCode(code, r31mode),
1087 clr_reg_value, reg<uint64_t>(code, r31mode), clr_normal);
1091 void Simulator::PrintFPRegister(
unsigned code, PrintFPRegisterSizes sizes) {
1095 DCHECK((sizes & kPrintAllFPRegValues) == sizes);
1098 fprintf(stream_,
"# %s%5s: %s0x%016" PRIx64
"%s (",
1099 clr_fpreg_name, VRegNameForCode(code),
1100 clr_fpreg_value, fpreg<uint64_t>(code), clr_normal);
1103 bool need_separator =
false;
1104 if (sizes & kPrintDRegValue) {
1105 fprintf(stream_,
"%s%s%s: %s%g%s",
1106 need_separator ?
", " :
"",
1107 clr_fpreg_name, DRegNameForCode(code),
1108 clr_fpreg_value, fpreg<double>(code), clr_normal);
1109 need_separator =
true;
1112 if (sizes & kPrintSRegValue) {
1113 fprintf(stream_,
"%s%s%s: %s%g%s",
1114 need_separator ?
", " :
"",
1115 clr_fpreg_name, SRegNameForCode(code),
1116 clr_fpreg_value, fpreg<float>(code), clr_normal);
1117 need_separator =
true;
1121 fprintf(stream_,
")\n");
1128 fprintf(stream_,
"# %sNZCV: %sN:%d Z:%d C:%d V:%d%s\n",
1129 clr_flag_name, clr_flag_value,
1130 nzcv().
N(), nzcv().Z(), nzcv().C(), nzcv().
V(),
1134 static const char * rmode[] = {
1135 "0b00 (Round to Nearest)",
1136 "0b01 (Round towards Plus Infinity)",
1137 "0b10 (Round towards Minus Infinity)",
1138 "0b11 (Round towards Zero)"
1142 "# %sFPCR: %sAHP:%d DN:%d FZ:%d RMode:%s%s\n",
1143 clr_flag_name, clr_flag_value,
1144 fpcr().AHP(), fpcr().DN(), fpcr().FZ(), rmode[fpcr().RMode()],
1154 void Simulator::PrintRead(
uintptr_t address,
1156 unsigned reg_code) {
1160 fprintf(stream_,
"# %s%5s: %s0x%016" PRIx64
"%s",
1161 clr_reg_name, XRegNameForCode(reg_code),
1162 clr_reg_value, reg<uint64_t>(reg_code), clr_normal);
1164 fprintf(stream_,
" <- %s0x%016" PRIxPTR
"%s\n",
1165 clr_memory_address, address, clr_normal);
1169 void Simulator::PrintReadFP(
uintptr_t address,
1171 unsigned reg_code) {
1175 fprintf(stream_,
"# %s%5s: %s0x%016" PRIx64
"%s (%s%s: %s%gf%s)",
1176 clr_fpreg_name, VRegNameForCode(reg_code),
1177 clr_fpreg_value, fpreg<uint64_t>(reg_code), clr_normal,
1178 clr_fpreg_name, SRegNameForCode(reg_code),
1179 clr_fpreg_value, fpreg<float>(reg_code), clr_normal);
1182 fprintf(stream_,
"# %s%5s: %s0x%016" PRIx64
"%s (%s%s: %s%g%s)",
1183 clr_fpreg_name, VRegNameForCode(reg_code),
1184 clr_fpreg_value, fpreg<uint64_t>(reg_code), clr_normal,
1185 clr_fpreg_name, DRegNameForCode(reg_code),
1186 clr_fpreg_value, fpreg<double>(reg_code), clr_normal);
1192 fprintf(stream_,
" <- %s0x%016" PRIxPTR
"%s\n",
1193 clr_memory_address, address, clr_normal);
1197 void Simulator::PrintWrite(
uintptr_t address,
1199 unsigned reg_code) {
1204 fprintf(stream_,
"# %s%5s<7:0>: %s0x%02" PRIx8
"%s",
1205 clr_reg_name, WRegNameForCode(reg_code),
1206 clr_reg_value, reg<uint8_t>(reg_code), clr_normal);
1209 fprintf(stream_,
"# %s%5s<15:0>: %s0x%04" PRIx16
"%s",
1210 clr_reg_name, WRegNameForCode(reg_code),
1211 clr_reg_value, reg<uint16_t>(reg_code), clr_normal);
1214 fprintf(stream_,
"# %s%5s: %s0x%08" PRIx32
"%s",
1215 clr_reg_name, WRegNameForCode(reg_code),
1216 clr_reg_value, reg<uint32_t>(reg_code), clr_normal);
1219 fprintf(stream_,
"# %s%5s: %s0x%016" PRIx64
"%s",
1220 clr_reg_name, XRegNameForCode(reg_code),
1221 clr_reg_value, reg<uint64_t>(reg_code), clr_normal);
1227 fprintf(stream_,
" -> %s0x%016" PRIxPTR
"%s\n",
1228 clr_memory_address, address, clr_normal);
1232 void Simulator::PrintWriteFP(
uintptr_t address,
1234 unsigned reg_code) {
1239 fprintf(stream_,
"# %s%5s<31:0>: %s0x%08" PRIx32
"%s (%s%s: %s%gf%s)",
1240 clr_fpreg_name, VRegNameForCode(reg_code),
1241 clr_fpreg_value, fpreg<uint32_t>(reg_code), clr_normal,
1242 clr_fpreg_name, SRegNameForCode(reg_code),
1243 clr_fpreg_value, fpreg<float>(reg_code), clr_normal);
1246 fprintf(stream_,
"# %s%5s: %s0x%016" PRIx64
"%s (%s%s: %s%g%s)",
1247 clr_fpreg_name, VRegNameForCode(reg_code),
1248 clr_fpreg_value, fpreg<uint64_t>(reg_code), clr_normal,
1249 clr_fpreg_name, DRegNameForCode(reg_code),
1250 clr_fpreg_value, fpreg<double>(reg_code), clr_normal);
1256 fprintf(stream_,
" -> %s0x%016" PRIxPTR
"%s\n",
1257 clr_memory_address, address, clr_normal);
1263 void Simulator::VisitUnimplemented(Instruction* instr) {
1264 fprintf(stream_,
"Unimplemented instruction at %p: 0x%08" PRIx32
"\n",
1265 reinterpret_cast<void*
>(instr), instr->InstructionBits());
1270 void Simulator::VisitUnallocated(Instruction* instr) {
1271 fprintf(stream_,
"Unallocated instruction at %p: 0x%08" PRIx32
"\n",
1272 reinterpret_cast<void*
>(instr), instr->InstructionBits());
1277 void Simulator::VisitPCRelAddressing(Instruction* instr) {
1280 set_reg(instr->Rd(), instr->ImmPCOffsetTarget());
1292 void Simulator::VisitUnconditionalBranch(Instruction* instr) {
1295 set_lr(instr->following());
1298 set_pc(instr->ImmPCOffsetTarget());
1306 void Simulator::VisitConditionalBranch(Instruction* instr) {
1308 if (ConditionPassed(
static_cast<Condition>(instr->ConditionBranch()))) {
1309 set_pc(instr->ImmPCOffsetTarget());
1314 void Simulator::VisitUnconditionalBranchToRegister(Instruction* instr) {
1315 Instruction* target = reg<Instruction*>(instr->Rn());
1318 set_lr(instr->following());
1319 if (instr->Rn() == 31) {
1327 case RET: set_pc(target);
break;
1333 void Simulator::VisitTestBranch(Instruction* instr) {
1334 unsigned bit_pos = (instr->ImmTestBranchBit5() << 5) |
1335 instr->ImmTestBranchBit40();
1336 bool take_branch = ((xreg(instr->Rt()) & (1UL << bit_pos)) == 0);
1339 case TBNZ: take_branch = !take_branch;
break;
1343 set_pc(instr->ImmPCOffsetTarget());
1348 void Simulator::VisitCompareBranch(Instruction* instr) {
1349 unsigned rt = instr->Rt();
1350 bool take_branch =
false;
1352 case CBZ_w: take_branch = (wreg(rt) == 0);
break;
1353 case CBZ_x: take_branch = (xreg(rt) == 0);
break;
1354 case CBNZ_w: take_branch = (wreg(rt) != 0);
break;
1355 case CBNZ_x: take_branch = (xreg(rt) != 0);
break;
1359 set_pc(instr->ImmPCOffsetTarget());
1364 template<
typename T>
1365 void Simulator::AddSubHelper(Instruction* instr,
T op2) {
1366 bool set_flags = instr->FlagsUpdate();
1370 switch (operation) {
1373 new_val = AddWithCarry<T>(set_flags,
1374 reg<T>(instr->Rn(), instr->RnMode()),
1380 new_val = AddWithCarry<T>(set_flags,
1381 reg<T>(instr->Rn(), instr->RnMode()),
1389 set_reg<T>(instr->Rd(), new_val, instr->RdMode());
1393 void Simulator::VisitAddSubShifted(Instruction* instr) {
1394 Shift shift_type =
static_cast<Shift>(instr->ShiftDP());
1395 unsigned shift_amount = instr->ImmDPShift();
1397 if (instr->SixtyFourBits()) {
1398 int64_t op2 = ShiftOperand(xreg(instr->Rm()), shift_type, shift_amount);
1399 AddSubHelper(instr, op2);
1401 int32_t op2 = ShiftOperand(wreg(instr->Rm()), shift_type, shift_amount);
1402 AddSubHelper(instr, op2);
1407 void Simulator::VisitAddSubImmediate(Instruction* instr) {
1408 int64_t op2 = instr->ImmAddSub() << ((instr->ShiftAddSub() == 1) ? 12 : 0);
1409 if (instr->SixtyFourBits()) {
1410 AddSubHelper<int64_t>(instr, op2);
1412 AddSubHelper<int32_t>(instr, op2);
1417 void Simulator::VisitAddSubExtended(Instruction* instr) {
1419 unsigned left_shift = instr->ImmExtendShift();
1420 if (instr->SixtyFourBits()) {
1421 int64_t op2 = ExtendValue(xreg(instr->Rm()), ext, left_shift);
1422 AddSubHelper(instr, op2);
1424 int32_t op2 = ExtendValue(wreg(instr->Rm()), ext, left_shift);
1425 AddSubHelper(instr, op2);
1430 void Simulator::VisitAddSubWithCarry(Instruction* instr) {
1431 if (instr->SixtyFourBits()) {
1432 AddSubWithCarry<int64_t>(instr);
1434 AddSubWithCarry<int32_t>(instr);
1439 void Simulator::VisitLogicalShifted(Instruction* instr) {
1440 Shift shift_type =
static_cast<Shift>(instr->ShiftDP());
1441 unsigned shift_amount = instr->ImmDPShift();
1443 if (instr->SixtyFourBits()) {
1444 int64_t op2 = ShiftOperand(xreg(instr->Rm()), shift_type, shift_amount);
1445 op2 = (instr->Mask(
NOT) ==
NOT) ? ~op2 : op2;
1446 LogicalHelper<int64_t>(instr, op2);
1448 int32_t op2 = ShiftOperand(wreg(instr->Rm()), shift_type, shift_amount);
1449 op2 = (instr->Mask(
NOT) ==
NOT) ? ~op2 : op2;
1450 LogicalHelper<int32_t>(instr, op2);
1455 void Simulator::VisitLogicalImmediate(Instruction* instr) {
1456 if (instr->SixtyFourBits()) {
1457 LogicalHelper<int64_t>(instr, instr->ImmLogical());
1459 LogicalHelper<int32_t>(instr, instr->ImmLogical());
1464 template<
typename T>
1465 void Simulator::LogicalHelper(Instruction* instr,
T op2) {
1466 T op1 = reg<T>(instr->Rn());
1468 bool update_flags =
false;
1473 case ANDS: update_flags =
true;
1474 case AND: result = op1 & op2;
break;
1475 case ORR: result = op1 | op2;
break;
1476 case EOR: result = op1 ^ op2;
break;
1482 nzcv().SetN(CalcNFlag(result));
1483 nzcv().SetZ(CalcZFlag(result));
1486 LogSystemRegister(
NZCV);
1489 set_reg<T>(instr->Rd(), result, instr->RdMode());
1493 void Simulator::VisitConditionalCompareRegister(Instruction* instr) {
1494 if (instr->SixtyFourBits()) {
1495 ConditionalCompareHelper(instr, xreg(instr->Rm()));
1497 ConditionalCompareHelper(instr, wreg(instr->Rm()));
1502 void Simulator::VisitConditionalCompareImmediate(Instruction* instr) {
1503 if (instr->SixtyFourBits()) {
1504 ConditionalCompareHelper<int64_t>(instr, instr->ImmCondCmp());
1506 ConditionalCompareHelper<int32_t>(instr, instr->ImmCondCmp());
1511 template<
typename T>
1512 void Simulator::ConditionalCompareHelper(Instruction* instr,
T op2) {
1513 T op1 = reg<T>(instr->Rn());
1515 if (ConditionPassed(
static_cast<Condition>(instr->Condition()))) {
1519 AddWithCarry<T>(
true, op1, ~op2, 1);
1522 AddWithCarry<T>(
true, op1, op2, 0);
1526 nzcv().SetFlags(instr->Nzcv());
1527 LogSystemRegister(
NZCV);
1532 void Simulator::VisitLoadStoreUnsignedOffset(Instruction* instr) {
1533 int offset = instr->ImmLSUnsigned() << instr->SizeLS();
1534 LoadStoreHelper(instr, offset,
Offset);
1538 void Simulator::VisitLoadStoreUnscaledOffset(Instruction* instr) {
1539 LoadStoreHelper(instr, instr->ImmLS(),
Offset);
1543 void Simulator::VisitLoadStorePreIndex(Instruction* instr) {
1544 LoadStoreHelper(instr, instr->ImmLS(),
PreIndex);
1548 void Simulator::VisitLoadStorePostIndex(Instruction* instr) {
1549 LoadStoreHelper(instr, instr->ImmLS(),
PostIndex);
1553 void Simulator::VisitLoadStoreRegisterOffset(Instruction* instr) {
1556 unsigned shift_amount = instr->ImmShiftLS() * instr->SizeLS();
1558 int64_t offset = ExtendValue(xreg(instr->Rm()), ext, shift_amount);
1559 LoadStoreHelper(instr, offset,
Offset);
1563 void Simulator::LoadStoreHelper(Instruction* instr,
1566 unsigned srcdst = instr->Rt();
1567 unsigned addr_reg = instr->Rn();
1568 uintptr_t address = LoadStoreAddress(addr_reg, offset, addrmode);
1578 if (instr->IsStore()) {
1579 LoadStoreWriteBack(addr_reg, offset, addrmode);
1590 case LDRB_w: set_wreg_no_log(srcdst, MemoryRead<uint8_t>(address));
break;
1591 case LDRH_w: set_wreg_no_log(srcdst, MemoryRead<uint16_t>(address));
break;
1592 case LDR_w: set_wreg_no_log(srcdst, MemoryRead<uint32_t>(address));
break;
1593 case LDR_x: set_xreg_no_log(srcdst, MemoryRead<uint64_t>(address));
break;
1594 case LDRSB_w: set_wreg_no_log(srcdst, MemoryRead<int8_t>(address));
break;
1595 case LDRSH_w: set_wreg_no_log(srcdst, MemoryRead<int16_t>(address));
break;
1596 case LDRSB_x: set_xreg_no_log(srcdst, MemoryRead<int8_t>(address));
break;
1597 case LDRSH_x: set_xreg_no_log(srcdst, MemoryRead<int16_t>(address));
break;
1598 case LDRSW_x: set_xreg_no_log(srcdst, MemoryRead<int32_t>(address));
break;
1599 case LDR_s: set_sreg_no_log(srcdst, MemoryRead<float>(address));
break;
1600 case LDR_d: set_dreg_no_log(srcdst, MemoryRead<double>(address));
break;
1602 case STRB_w: MemoryWrite<uint8_t>(address, wreg(srcdst));
break;
1603 case STRH_w: MemoryWrite<uint16_t>(address, wreg(srcdst));
break;
1604 case STR_w: MemoryWrite<uint32_t>(address, wreg(srcdst));
break;
1605 case STR_x: MemoryWrite<uint64_t>(address, xreg(srcdst));
break;
1606 case STR_s: MemoryWrite<float>(address, sreg(srcdst));
break;
1607 case STR_d: MemoryWrite<double>(address, dreg(srcdst));
break;
1614 size_t access_size = 1 << instr->SizeLS();
1615 if (instr->IsLoad()) {
1616 if ((op == LDR_s) || (op == LDR_d)) {
1617 LogReadFP(address, access_size, srcdst);
1619 LogRead(address, access_size, srcdst);
1622 if ((op == STR_s) || (op == STR_d)) {
1623 LogWriteFP(address, access_size, srcdst);
1625 LogWrite(address, access_size, srcdst);
1633 if (instr->IsLoad()) {
1638 LoadStoreWriteBack(addr_reg, offset, addrmode);
1643 CheckMemoryAccess(address, stack);
1647 void Simulator::VisitLoadStorePairOffset(Instruction* instr) {
1648 LoadStorePairHelper(instr,
Offset);
1652 void Simulator::VisitLoadStorePairPreIndex(Instruction* instr) {
1653 LoadStorePairHelper(instr,
PreIndex);
1657 void Simulator::VisitLoadStorePairPostIndex(Instruction* instr) {
1662 void Simulator::VisitLoadStorePairNonTemporal(Instruction* instr) {
1663 LoadStorePairHelper(instr,
Offset);
1667 void Simulator::LoadStorePairHelper(Instruction* instr,
1669 unsigned rt = instr->Rt();
1670 unsigned rt2 = instr->Rt2();
1671 unsigned addr_reg = instr->Rn();
1672 size_t access_size = 1 << instr->SizeLSPair();
1673 int64_t offset = instr->ImmLSPair() * access_size;
1674 uintptr_t address = LoadStoreAddress(addr_reg, offset, addrmode);
1675 uintptr_t address2 = address + access_size;
1685 if (instr->IsStore()) {
1686 LoadStoreWriteBack(addr_reg, offset, addrmode);
1704 set_wreg_no_log(rt, MemoryRead<uint32_t>(address));
1705 set_wreg_no_log(rt2, MemoryRead<uint32_t>(address2));
1710 set_sreg_no_log(rt, MemoryRead<float>(address));
1711 set_sreg_no_log(rt2, MemoryRead<float>(address2));
1716 set_xreg_no_log(rt, MemoryRead<uint64_t>(address));
1717 set_xreg_no_log(rt2, MemoryRead<uint64_t>(address2));
1722 set_dreg_no_log(rt, MemoryRead<double>(address));
1723 set_dreg_no_log(rt2, MemoryRead<double>(address2));
1728 set_xreg_no_log(rt, MemoryRead<int32_t>(address));
1729 set_xreg_no_log(rt2, MemoryRead<int32_t>(address2));
1734 MemoryWrite<uint32_t>(address, wreg(rt));
1735 MemoryWrite<uint32_t>(address2, wreg(rt2));
1740 MemoryWrite<float>(address, sreg(rt));
1741 MemoryWrite<float>(address2, sreg(rt2));
1746 MemoryWrite<uint64_t>(address, xreg(rt));
1747 MemoryWrite<uint64_t>(address2, xreg(rt2));
1752 MemoryWrite<double>(address, dreg(rt));
1753 MemoryWrite<double>(address2, dreg(rt2));
1761 if (instr->IsLoad()) {
1762 if ((op == LDP_s) || (op == LDP_d)) {
1763 LogReadFP(address, access_size, rt);
1764 LogReadFP(address2, access_size, rt2);
1766 LogRead(address, access_size, rt);
1767 LogRead(address2, access_size, rt2);
1770 if ((op == STP_s) || (op == STP_d)) {
1771 LogWriteFP(address, access_size, rt);
1772 LogWriteFP(address2, access_size, rt2);
1774 LogWrite(address, access_size, rt);
1775 LogWrite(address2, access_size, rt2);
1783 if (instr->IsLoad()) {
1788 LoadStoreWriteBack(addr_reg, offset, addrmode);
1793 CheckMemoryAccess(address, stack);
1797 void Simulator::VisitLoadLiteral(Instruction* instr) {
1798 uintptr_t address = instr->LiteralAddress();
1799 unsigned rt = instr->Rt();
1805 set_wreg_no_log(rt, MemoryRead<uint32_t>(address));
1809 set_xreg_no_log(rt, MemoryRead<uint64_t>(address));
1813 set_sreg_no_log(rt, MemoryRead<float>(address));
1817 set_dreg_no_log(rt, MemoryRead<double>(address));
1825 uintptr_t Simulator::LoadStoreAddress(
unsigned addr_reg, int64_t offset,
1829 if ((addr_reg == kSPRegCode) && ((address % 16) != 0)) {
1833 FATAL(
"ALIGNMENT EXCEPTION");
1844 void Simulator::LoadStoreWriteBack(
unsigned addr_reg,
1856 if ((address >= stack_limit_) && (address < stack)) {
1857 fprintf(stream_,
"ACCESS BELOW STACK POINTER:\n");
1858 fprintf(stream_,
" sp is here: 0x%016" PRIx64
"\n",
1859 static_cast<uint64_t
>(stack));
1860 fprintf(stream_,
" access was here: 0x%016" PRIx64
"\n",
1861 static_cast<uint64_t
>(address));
1862 fprintf(stream_,
" stack limit is here: 0x%016" PRIx64
"\n",
1863 static_cast<uint64_t
>(stack_limit_));
1864 fprintf(stream_,
"\n");
1865 FATAL(
"ACCESS BELOW STACK POINTER");
1870 void Simulator::VisitMoveWideImmediate(Instruction* instr) {
1873 int64_t new_xn_val = 0;
1875 bool is_64_bits = instr->SixtyFourBits() == 1;
1877 DCHECK(is_64_bits || (instr->ShiftMoveWide() < 2));
1880 int64_t
shift = instr->ShiftMoveWide() * 16;
1881 int64_t shifted_imm16 = instr->ImmMoveWide() <<
shift;
1887 new_xn_val = ~shifted_imm16;
1888 if (!is_64_bits) new_xn_val &=
kWRegMask;
1893 unsigned reg_code = instr->Rd();
1894 int64_t prev_xn_val = is_64_bits ? xreg(reg_code)
1896 new_xn_val = (prev_xn_val & ~(0xffffL <<
shift)) | shifted_imm16;
1901 new_xn_val = shifted_imm16;
1909 set_xreg(instr->Rd(), new_xn_val);
1913 void Simulator::VisitConditionalSelect(Instruction* instr) {
1914 if (ConditionFailed(
static_cast<Condition>(instr->Condition()))) {
1915 uint64_t new_val = xreg(instr->Rm());
1917 case CSEL_w: set_wreg(instr->Rd(), new_val);
break;
1918 case CSEL_x: set_xreg(instr->Rd(), new_val);
break;
1919 case CSINC_w: set_wreg(instr->Rd(), new_val + 1);
break;
1920 case CSINC_x: set_xreg(instr->Rd(), new_val + 1);
break;
1921 case CSINV_w: set_wreg(instr->Rd(), ~new_val);
break;
1922 case CSINV_x: set_xreg(instr->Rd(), ~new_val);
break;
1923 case CSNEG_w: set_wreg(instr->Rd(), -new_val);
break;
1924 case CSNEG_x: set_xreg(instr->Rd(), -new_val);
break;
1928 if (instr->SixtyFourBits()) {
1929 set_xreg(instr->Rd(), xreg(instr->Rn()));
1931 set_wreg(instr->Rd(), wreg(instr->Rn()));
1937 void Simulator::VisitDataProcessing1Source(Instruction* instr) {
1938 unsigned dst = instr->Rd();
1939 unsigned src = instr->Rn();
1944 case REV16_w: set_wreg(dst, ReverseBytes(wreg(src), Reverse16));
break;
1945 case REV16_x: set_xreg(dst, ReverseBytes(xreg(src), Reverse16));
break;
1946 case REV_w: set_wreg(dst, ReverseBytes(wreg(src), Reverse32));
break;
1947 case REV32_x: set_xreg(dst, ReverseBytes(xreg(src), Reverse32));
break;
1948 case REV_x: set_xreg(dst, ReverseBytes(xreg(src), Reverse64));
break;
1966 uint64_t Simulator::ReverseBits(uint64_t value,
unsigned num_bits) {
1968 uint64_t result = 0;
1969 for (
unsigned i = 0;
i < num_bits;
i++) {
1970 result = (result << 1) | (value & 1);
1977 uint64_t Simulator::ReverseBytes(uint64_t value, ReverseByteMode
mode) {
1981 uint64_t mask = 0xff00000000000000UL;
1982 for (
int i = 7;
i >= 0;
i--) {
1983 bytes[
i] = (value & mask) >> (
i * 8);
1991 DCHECK((Reverse16 == 0) && (Reverse32 == 1) && (Reverse64 == 2));
1992 static const uint8_t permute_table[3][8] = { {6, 7, 4, 5, 2, 3, 0, 1},
1993 {4, 5, 6, 7, 0, 1, 2, 3},
1994 {0, 1, 2, 3, 4, 5, 6, 7} };
1995 uint64_t result = 0;
1996 for (
int i = 0;
i < 8;
i++) {
1998 result |= bytes[permute_table[
mode][
i]];
2004 template <
typename T>
2005 void Simulator::DataProcessing2Source(Instruction* instr) {
2011 T rn = reg<T>(instr->Rn());
2012 T rm = reg<T>(instr->Rm());
2015 }
else if (rm == 0) {
2025 typedef typename make_unsigned<T>::type unsignedT;
2026 unsignedT rn =
static_cast<unsignedT
>(reg<T>(instr->Rn()));
2027 unsignedT rm =
static_cast<unsignedT
>(reg<T>(instr->Rm()));
2050 unsigned shift = wreg(instr->Rm());
2056 result = ShiftOperand(reg<T>(instr->Rn()), shift_op,
shift);
2058 set_reg<T>(instr->Rd(), result);
2062 void Simulator::VisitDataProcessing2Source(Instruction* instr) {
2063 if (instr->SixtyFourBits()) {
2064 DataProcessing2Source<int64_t>(instr);
2066 DataProcessing2Source<int32_t>(instr);
2074 static int64_t MultiplyHighSigned(int64_t u, int64_t v) {
2075 uint64_t u0, v0, w0;
2076 int64_t u1, v1, w1, w2, t;
2078 u0 = u & 0xffffffffL;
2080 v0 = v & 0xffffffffL;
2084 t = u1 * v0 + (w0 >> 32);
2085 w1 = t & 0xffffffffL;
2089 return u1 * v1 + w2 + (w1 >> 32);
2093 void Simulator::VisitDataProcessing3Source(Instruction* instr) {
2096 uint64_t rn_u32 = reg<uint32_t>(instr->Rn());
2097 uint64_t rm_u32 = reg<uint32_t>(instr->Rm());
2098 int64_t rn_s32 = reg<int32_t>(instr->Rn());
2099 int64_t rm_s32 = reg<int32_t>(instr->Rm());
2103 result = xreg(instr->Ra()) + (xreg(instr->Rn()) * xreg(instr->Rm()));
2107 result = xreg(instr->Ra()) - (xreg(instr->Rn()) * xreg(instr->Rm()));
2109 case SMADDL_x: result = xreg(instr->Ra()) + (rn_s32 * rm_s32);
break;
2110 case SMSUBL_x: result = xreg(instr->Ra()) - (rn_s32 * rm_s32);
break;
2111 case UMADDL_x: result = xreg(instr->Ra()) + (rn_u32 * rm_u32);
break;
2112 case UMSUBL_x: result = xreg(instr->Ra()) - (rn_u32 * rm_u32);
break;
2115 result = MultiplyHighSigned(xreg(instr->Rn()), xreg(instr->Rm()));
2120 if (instr->SixtyFourBits()) {
2121 set_xreg(instr->Rd(), result);
2123 set_wreg(instr->Rd(), result);
2128 template <
typename T>
2129 void Simulator::BitfieldHelper(Instruction* instr) {
2130 typedef typename make_unsigned<T>::type unsignedT;
2131 T reg_size =
sizeof(
T) * 8;
2132 T R = instr->ImmR();
2133 T S = instr->ImmS();
2137 mask = diff < reg_size - 1 ? (
static_cast<T>(1) << (diff + 1)) - 1
2138 :
static_cast<T>(-1);
2140 mask = ((1L << (
S + 1)) - 1);
2141 mask = (
static_cast<uint64_t
>(mask) >> R) | (mask << (reg_size - R));
2148 bool inzero =
false;
2149 bool extend =
false;
2167 T dst = inzero ? 0 : reg<T>(instr->Rd());
2168 T src = reg<T>(instr->Rn());
2170 T result = (
static_cast<unsignedT
>(src) >> R) | (src << (reg_size - R));
2172 T topbits_preshift = (
static_cast<T>(1) << (reg_size - diff - 1)) - 1;
2173 T signbits = (extend && ((src >>
S) & 1) ? topbits_preshift : 0)
2177 result = signbits | (result & mask) | (dst & ~mask);
2179 set_reg<T>(instr->Rd(), result);
2183 void Simulator::VisitBitfield(Instruction* instr) {
2184 if (instr->SixtyFourBits()) {
2185 BitfieldHelper<int64_t>(instr);
2187 BitfieldHelper<int32_t>(instr);
2192 void Simulator::VisitExtract(Instruction* instr) {
2193 if (instr->SixtyFourBits()) {
2194 Extract<uint64_t>(instr);
2196 Extract<uint32_t>(instr);
2201 void Simulator::VisitFPImmediate(Instruction* instr) {
2202 AssertSupportedFPCR();
2204 unsigned dest = instr->Rd();
2206 case FMOV_s_imm: set_sreg(dest, instr->ImmFP32());
break;
2207 case FMOV_d_imm: set_dreg(dest, instr->ImmFP64());
break;
2213 void Simulator::VisitFPIntegerConvert(Instruction* instr) {
2214 AssertSupportedFPCR();
2216 unsigned dst = instr->Rd();
2217 unsigned src = instr->Rn();
2270 case FMOV_ws: set_wreg(dst, sreg_bits(src));
break;
2271 case FMOV_xd: set_xreg(dst, dreg_bits(src));
break;
2272 case FMOV_sw: set_sreg_bits(dst, wreg(src));
break;
2273 case FMOV_dx: set_dreg_bits(dst, xreg(src));
break;
2277 case SCVTF_dx: set_dreg(dst, FixedToDouble(xreg(src), 0, round));
break;
2278 case SCVTF_dw: set_dreg(dst, FixedToDouble(wreg(src), 0, round));
break;
2279 case UCVTF_dx: set_dreg(dst, UFixedToDouble(xreg(src), 0, round));
break;
2281 set_dreg(dst, UFixedToDouble(reg<uint32_t>(src), 0, round));
2284 case SCVTF_sx: set_sreg(dst, FixedToFloat(xreg(src), 0, round));
break;
2285 case SCVTF_sw: set_sreg(dst, FixedToFloat(wreg(src), 0, round));
break;
2286 case UCVTF_sx: set_sreg(dst, UFixedToFloat(xreg(src), 0, round));
break;
2288 set_sreg(dst, UFixedToFloat(reg<uint32_t>(src), 0, round));
2297 void Simulator::VisitFPFixedPointConvert(Instruction* instr) {
2298 AssertSupportedFPCR();
2300 unsigned dst = instr->Rd();
2301 unsigned src = instr->Rn();
2302 int fbits = 64 - instr->FPScale();
2310 set_dreg(dst, FixedToDouble(xreg(src), fbits, round));
2313 set_dreg(dst, FixedToDouble(wreg(src), fbits, round));
2316 set_dreg(dst, UFixedToDouble(xreg(src), fbits, round));
2320 UFixedToDouble(reg<uint32_t>(src), fbits, round));
2324 set_sreg(dst, FixedToFloat(xreg(src), fbits, round));
2327 set_sreg(dst, FixedToFloat(wreg(src), fbits, round));
2330 set_sreg(dst, UFixedToFloat(xreg(src), fbits, round));
2334 UFixedToFloat(reg<uint32_t>(src), fbits, round));
2343 value = FPRoundInt(value, rmode);
2353 int64_t Simulator::FPToInt64(
double value,
FPRounding rmode) {
2354 value = FPRoundInt(value, rmode);
2360 return std::isnan(value) ? 0 :
static_cast<int64_t
>(value);
2365 value = FPRoundInt(value, rmode);
2368 }
else if (value < 0.0) {
2375 uint64_t Simulator::FPToUInt64(
double value,
FPRounding rmode) {
2376 value = FPRoundInt(value, rmode);
2379 }
else if (value < 0.0) {
2382 return std::isnan(value) ? 0 :
static_cast<uint64_t
>(value);
2386 void Simulator::VisitFPCompare(Instruction* instr) {
2387 AssertSupportedFPCR();
2391 double fn_val = fpreg(reg_size, instr->Rn());
2395 case FCMP_d: FPCompare(fn_val, fpreg(reg_size, instr->Rm()));
break;
2403 void Simulator::VisitFPConditionalCompare(Instruction* instr) {
2404 AssertSupportedFPCR();
2409 if (ConditionPassed(
static_cast<Condition>(instr->Condition()))) {
2414 FPCompare(fpreg(reg_size, instr->Rn()), fpreg(reg_size, instr->Rm()));
2417 nzcv().SetFlags(instr->Nzcv());
2418 LogSystemRegister(
NZCV);
2427 void Simulator::VisitFPConditionalSelect(Instruction* instr) {
2428 AssertSupportedFPCR();
2431 if (ConditionPassed(
static_cast<Condition>(instr->Condition()))) {
2432 selected = instr->Rn();
2434 selected = instr->Rm();
2438 case FCSEL_s: set_sreg(instr->Rd(), sreg(selected));
break;
2439 case FCSEL_d: set_dreg(instr->Rd(), dreg(selected));
break;
2445 void Simulator::VisitFPDataProcessing1Source(Instruction* instr) {
2446 AssertSupportedFPCR();
2448 unsigned fd = instr->Rd();
2449 unsigned fn = instr->Rn();
2452 case FMOV_s: set_sreg(fd, sreg(fn));
break;
2453 case FMOV_d: set_dreg(fd, dreg(fn));
break;
2454 case FABS_s: set_sreg(fd, std::fabs(sreg(fn)));
break;
2455 case FABS_d: set_dreg(fd, std::fabs(dreg(fn)));
break;
2456 case FNEG_s: set_sreg(fd, -sreg(fn));
break;
2457 case FNEG_d: set_dreg(fd, -dreg(fn));
break;
2458 case FSQRT_s: set_sreg(fd, FPSqrt(sreg(fn)));
break;
2459 case FSQRT_d: set_dreg(fd, FPSqrt(dreg(fn)));
break;
2468 case FRINTZ_s: set_sreg(fd, FPRoundInt(sreg(fn),
FPZero));
break;
2469 case FRINTZ_d: set_dreg(fd, FPRoundInt(dreg(fn),
FPZero));
break;
2470 case FCVT_ds: set_dreg(fd, FPToDouble(sreg(fn)));
break;
2492 template <
class T,
int ebits,
int mbits>
2493 static T FPRound(int64_t
sign, int64_t exponent, uint64_t mantissa,
2552 static const int mantissa_offset = 0;
2553 static const int exponent_offset = mantissa_offset + mbits;
2554 static const int sign_offset = exponent_offset + ebits;
2558 if (mantissa == 0) {
2559 return sign << sign_offset;
2564 static const int infinite_exponent = (1 << ebits) - 1;
2565 static const int max_normal_exponent = infinite_exponent - 1;
2569 exponent += max_normal_exponent >> 1;
2571 if (exponent > max_normal_exponent) {
2574 exponent = infinite_exponent;
2576 return (
sign << sign_offset) |
2577 (exponent << exponent_offset) |
2578 (mantissa << mantissa_offset);
2584 int shift = highest_significant_bit - mbits;
2586 if (exponent <= 0) {
2592 shift += -exponent + 1;
2599 if (
shift > (highest_significant_bit + 1)) {
2601 return sign << sign_offset;
2609 mantissa &= ~(1UL << highest_significant_bit);
2615 uint64_t onebit_mantissa = (mantissa >> (
shift)) & 1;
2616 uint64_t halfbit_mantissa = (mantissa >> (
shift-1)) & 1;
2617 uint64_t adjusted = mantissa - (halfbit_mantissa & ~onebit_mantissa);
2618 T halfbit_adjusted = (adjusted >> (
shift-1)) & 1;
2620 T result = (
sign << sign_offset) |
2621 (exponent << exponent_offset) |
2622 ((mantissa >>
shift) << mantissa_offset);
2632 return result + halfbit_adjusted;
2637 return (
sign << sign_offset) |
2638 (exponent << exponent_offset) |
2639 ((mantissa << -
shift) << mantissa_offset);
2645 static inline double FPRoundToDouble(int64_t
sign, int64_t exponent,
2648 FPRound<int64_t, kDoubleExponentBits, kDoubleMantissaBits>(
sign,
2657 static inline float FPRoundToFloat(int64_t
sign, int64_t exponent,
2660 FPRound<int32_t, kFloatExponentBits, kFloatMantissaBits>(
sign,
2668 double Simulator::FixedToDouble(int64_t src,
int fbits,
FPRounding round) {
2670 return UFixedToDouble(src, fbits, round);
2673 return -UFixedToDouble(-src, fbits, round);
2678 double Simulator::UFixedToDouble(uint64_t src,
int fbits,
FPRounding round) {
2688 const int64_t exponent = highest_significant_bit - fbits;
2690 return FPRoundToDouble(0, exponent, src, round);
2694 float Simulator::FixedToFloat(int64_t src,
int fbits,
FPRounding round) {
2696 return UFixedToFloat(src, fbits, round);
2699 return -UFixedToFloat(-src, fbits, round);
2704 float Simulator::UFixedToFloat(uint64_t src,
int fbits,
FPRounding round) {
2714 const int32_t exponent = highest_significant_bit - fbits;
2716 return FPRoundToFloat(0, exponent, src, round);
2720 double Simulator::FPRoundInt(
double value,
FPRounding round_mode) {
2721 if ((value == 0.0) || (value == kFP64PositiveInfinity) ||
2722 (value == kFP64NegativeInfinity)) {
2724 }
else if (std::isnan(value)) {
2725 return FPProcessNaN(value);
2728 double int_result = floor(value);
2729 double error = value - int_result;
2730 switch (round_mode) {
2734 if ((-0.5 < value) && (value < 0.0)) {
2737 }
else if ((error > 0.5) || ((error == 0.5) && (int_result >= 0.0))) {
2747 if ((-0.5 <= value) && (value < 0.0)) {
2752 }
else if ((error > 0.5) ||
2753 ((error == 0.5) && (fmod(int_result, 2) != 0))) {
2762 int_result = ceil(value);
2776 double Simulator::FPToDouble(
float value) {
2777 switch (std::fpclassify(value)) {
2779 if (fpcr().DN())
return kFP64DefaultNaN;
2788 uint64_t
sign = raw >> 31;
2789 uint64_t exponent = (1 << 11) - 1;
2791 payload <<= (52 - 23);
2792 payload |= (1L << 51);
2804 return static_cast<double>(value);
2809 return static_cast<double>(value);
2813 float Simulator::FPToFloat(
double value,
FPRounding round_mode) {
2818 switch (std::fpclassify(value)) {
2820 if (fpcr().DN())
return kFP32DefaultNaN;
2831 payload |= (1 << 22);
2840 return static_cast<float>(value);
2854 if (std::fpclassify(value) ==
FP_NORMAL) {
2855 mantissa |= (1UL << 52);
2857 return FPRoundToFloat(
sign, exponent, mantissa, round_mode);
2866 void Simulator::VisitFPDataProcessing2Source(Instruction* instr) {
2867 AssertSupportedFPCR();
2869 unsigned fd = instr->Rd();
2870 unsigned fn = instr->Rn();
2871 unsigned fm = instr->Rm();
2875 case FMAXNM_s: set_sreg(fd, FPMaxNM(sreg(fn), sreg(fm)));
return;
2876 case FMAXNM_d: set_dreg(fd, FPMaxNM(dreg(fn), dreg(fm)));
return;
2877 case FMINNM_s: set_sreg(fd, FPMinNM(sreg(fn), sreg(fm)));
return;
2878 case FMINNM_d: set_dreg(fd, FPMinNM(dreg(fn), dreg(fm)));
return;
2883 if (FPProcessNaNs(instr))
return;
2886 case FADD_s: set_sreg(fd, FPAdd(sreg(fn), sreg(fm)));
break;
2887 case FADD_d: set_dreg(fd, FPAdd(dreg(fn), dreg(fm)));
break;
2888 case FSUB_s: set_sreg(fd, FPSub(sreg(fn), sreg(fm)));
break;
2889 case FSUB_d: set_dreg(fd, FPSub(dreg(fn), dreg(fm)));
break;
2890 case FMUL_s: set_sreg(fd, FPMul(sreg(fn), sreg(fm)));
break;
2891 case FMUL_d: set_dreg(fd, FPMul(dreg(fn), dreg(fm)));
break;
2892 case FDIV_s: set_sreg(fd, FPDiv(sreg(fn), sreg(fm)));
break;
2893 case FDIV_d: set_dreg(fd, FPDiv(dreg(fn), dreg(fm)));
break;
2894 case FMAX_s: set_sreg(fd, FPMax(sreg(fn), sreg(fm)));
break;
2895 case FMAX_d: set_dreg(fd, FPMax(dreg(fn), dreg(fm)));
break;
2896 case FMIN_s: set_sreg(fd, FPMin(sreg(fn), sreg(fm)));
break;
2897 case FMIN_d: set_dreg(fd, FPMin(dreg(fn), dreg(fm)));
break;
2909 void Simulator::VisitFPDataProcessing3Source(Instruction* instr) {
2910 AssertSupportedFPCR();
2912 unsigned fd = instr->Rd();
2913 unsigned fn = instr->Rn();
2914 unsigned fm = instr->Rm();
2915 unsigned fa = instr->Ra();
2919 case FMADD_s: set_sreg(fd, FPMulAdd(sreg(fa), sreg(fn), sreg(fm)));
break;
2920 case FMSUB_s: set_sreg(fd, FPMulAdd(sreg(fa), -sreg(fn), sreg(fm)));
break;
2921 case FMADD_d: set_dreg(fd, FPMulAdd(dreg(fa), dreg(fn), dreg(fm)));
break;
2922 case FMSUB_d: set_dreg(fd, FPMulAdd(dreg(fa), -dreg(fn), dreg(fm)));
break;
2925 set_sreg(fd, FPMulAdd(-sreg(fa), -sreg(fn), sreg(fm)));
2928 set_sreg(fd, FPMulAdd(-sreg(fa), sreg(fn), sreg(fm)));
2931 set_dreg(fd, FPMulAdd(-dreg(fa), -dreg(fn), dreg(fm)));
2934 set_dreg(fd, FPMulAdd(-dreg(fa), dreg(fn), dreg(fm)));
2941 template <
typename T>
2942 T Simulator::FPAdd(
T op1,
T op2) {
2944 DCHECK(!std::isnan(op1) && !std::isnan(op2));
2946 if (std::isinf(op1) && std::isinf(op2) && (op1 != op2)) {
2948 return FPDefaultNaN<T>();
2956 template <
typename T>
2957 T Simulator::FPDiv(
T op1,
T op2) {
2959 DCHECK(!std::isnan(op1) && !std::isnan(op2));
2961 if ((std::isinf(op1) && std::isinf(op2)) || ((op1 == 0.0) && (op2 == 0.0))) {
2963 return FPDefaultNaN<T>();
2971 template <
typename T>
2972 T Simulator::FPMax(
T a,
T b) {
2974 DCHECK(!std::isnan(a) && !std::isnan(b));
2976 if ((a == 0.0) && (b == 0.0) &&
2977 (copysign(1.0, a) != copysign(1.0, b))) {
2981 return (a > b) ? a : b;
2986 template <
typename T>
2987 T Simulator::FPMaxNM(
T a,
T b) {
2989 a = kFP64NegativeInfinity;
2991 b = kFP64NegativeInfinity;
2994 T result = FPProcessNaNs(a, b);
2995 return std::isnan(result) ? result : FPMax(a, b);
2998 template <
typename T>
2999 T Simulator::FPMin(
T a,
T b) {
3001 DCHECK(!std::isnan(a) && !std::isnan(b));
3003 if ((a == 0.0) && (b == 0.0) &&
3004 (copysign(1.0, a) != copysign(1.0, b))) {
3008 return (a < b) ? a : b;
3013 template <
typename T>
3014 T Simulator::FPMinNM(
T a,
T b) {
3016 a = kFP64PositiveInfinity;
3018 b = kFP64PositiveInfinity;
3021 T result = FPProcessNaNs(a, b);
3022 return std::isnan(result) ? result : FPMin(a, b);
3026 template <
typename T>
3027 T Simulator::FPMul(
T op1,
T op2) {
3029 DCHECK(!std::isnan(op1) && !std::isnan(op2));
3031 if ((std::isinf(op1) && (op2 == 0.0)) || (std::isinf(op2) && (op1 == 0.0))) {
3033 return FPDefaultNaN<T>();
3041 template<
typename T>
3042 T Simulator::FPMulAdd(
T a,
T op1,
T op2) {
3043 T result = FPProcessNaNs3(a, op1, op2);
3045 T sign_a = copysign(1.0, a);
3046 T sign_prod = copysign(1.0, op1) * copysign(1.0, op2);
3048 bool operation_generates_nan =
3051 (
std::isinf(a) && isinf_prod && (sign_a != sign_prod));
3053 if (std::isnan(result)) {
3055 if (operation_generates_nan &&
IsQuietNaN(a)) {
3056 return FPDefaultNaN<T>();
3063 if (operation_generates_nan) {
3064 return FPDefaultNaN<T>();
3069 if (((op1 == 0.0) || (op2 == 0.0)) && (a == 0.0)) {
3070 return ((sign_a < 0) && (sign_prod < 0)) ? -0.0 : 0.0;
3074 DCHECK(!std::isnan(result));
3078 if ((a == 0.0) && (result == 0.0)) {
3079 return copysign(0.0, sign_prod);
3086 template <
typename T>
3087 T Simulator::FPSqrt(
T op) {
3088 if (std::isnan(op)) {
3089 return FPProcessNaN(op);
3090 }
else if (op < 0.0) {
3091 return FPDefaultNaN<T>();
3093 return std::sqrt(op);
3098 template <
typename T>
3099 T Simulator::FPSub(
T op1,
T op2) {
3101 DCHECK(!std::isnan(op1) && !std::isnan(op2));
3103 if (std::isinf(op1) && std::isinf(op2) && (op1 == op2)) {
3105 return FPDefaultNaN<T>();
3113 template <
typename T>
3114 T Simulator::FPProcessNaN(
T op) {
3116 return fpcr().DN() ? FPDefaultNaN<T>() :
ToQuietNaN(op);
3120 template <
typename T>
3121 T Simulator::FPProcessNaNs(
T op1,
T op2) {
3123 return FPProcessNaN(op1);
3125 return FPProcessNaN(op2);
3126 }
else if (std::isnan(op1)) {
3128 return FPProcessNaN(op1);
3129 }
else if (std::isnan(op2)) {
3131 return FPProcessNaN(op2);
3138 template <
typename T>
3139 T Simulator::FPProcessNaNs3(
T op1,
T op2,
T op3) {
3141 return FPProcessNaN(op1);
3143 return FPProcessNaN(op2);
3145 return FPProcessNaN(op3);
3146 }
else if (std::isnan(op1)) {
3148 return FPProcessNaN(op1);
3149 }
else if (std::isnan(op2)) {
3151 return FPProcessNaN(op2);
3152 }
else if (std::isnan(op3)) {
3154 return FPProcessNaN(op3);
3161 bool Simulator::FPProcessNaNs(Instruction* instr) {
3162 unsigned fd = instr->Rd();
3163 unsigned fn = instr->Rn();
3164 unsigned fm = instr->Rm();
3168 double result = FPProcessNaNs(dreg(fn), dreg(fm));
3169 if (std::isnan(result)) {
3170 set_dreg(fd, result);
3174 float result = FPProcessNaNs(sreg(fn), sreg(fm));
3175 if (std::isnan(result)) {
3176 set_sreg(fd, result);
3185 void Simulator::VisitSystem(Instruction* instr) {
3192 switch (instr->ImmSystemRegister()) {
3193 case NZCV: set_xreg(instr->Rt(), nzcv().RawValue());
break;
3194 case FPCR: set_xreg(instr->Rt(), fpcr().RawValue());
break;
3200 switch (instr->ImmSystemRegister()) {
3202 nzcv().SetRawValue(xreg(instr->Rt()));
3203 LogSystemRegister(
NZCV);
3206 fpcr().SetRawValue(xreg(instr->Rt()));
3207 LogSystemRegister(
FPCR);
3216 switch (instr->ImmHint()) {
3221 __sync_synchronize();
3228 bool Simulator::GetValue(
const char* desc, int64_t* value) {
3229 int regnum = CodeFromName(desc);
3231 unsigned code = regnum;
3240 if (desc[0] ==
'w') {
3246 }
else if (strncmp(desc,
"0x", 2) == 0) {
3247 return SScanF(desc + 2,
"%" SCNx64,
3248 reinterpret_cast<uint64_t*
>(value)) == 1;
3250 return SScanF(desc,
"%" SCNu64,
3251 reinterpret_cast<uint64_t*
>(value)) == 1;
3256 bool Simulator::PrintValue(
const char* desc) {
3257 if (strcmp(desc,
"csp") == 0) {
3259 PrintF(stream_,
"%s csp:%s 0x%016" PRIx64
"%s\n",
3262 }
else if (strcmp(desc,
"wcsp") == 0) {
3264 PrintF(stream_,
"%s wcsp:%s 0x%08" PRIx32
"%s\n",
3269 int i = CodeFromName(desc);
3273 if (desc[0] ==
'v') {
3274 PrintF(stream_,
"%s %s:%s 0x%016" PRIx64
"%s (%s%s:%s %g%s %s:%s %g%s)\n",
3275 clr_fpreg_name, VRegNameForCode(
i),
3278 clr_fpreg_name, DRegNameForCode(
i),
3279 clr_fpreg_value, dreg(
i),
3280 clr_fpreg_name, SRegNameForCode(
i),
3281 clr_fpreg_value, sreg(
i),
3284 }
else if (desc[0] ==
'd') {
3285 PrintF(stream_,
"%s %s:%s %g%s\n",
3286 clr_fpreg_name, DRegNameForCode(
i),
3287 clr_fpreg_value, dreg(
i),
3290 }
else if (desc[0] ==
's') {
3291 PrintF(stream_,
"%s %s:%s %g%s\n",
3292 clr_fpreg_name, SRegNameForCode(
i),
3293 clr_fpreg_value, sreg(
i),
3296 }
else if (desc[0] ==
'w') {
3297 PrintF(stream_,
"%s %s:%s 0x%08" PRIx32
"%s\n",
3298 clr_reg_name, WRegNameForCode(
i), clr_reg_value, wreg(
i), clr_normal);
3303 PrintF(stream_,
"%s %s:%s 0x%016" PRIx64
"%s\n",
3304 clr_reg_name, XRegNameForCode(
i), clr_reg_value, xreg(
i), clr_normal);
3310 void Simulator::Debug() {
3311 #define COMMAND_SIZE 63
3312 #define ARG_SIZE 255
3315 #define XSTR(a) STR(a)
3317 char cmd[COMMAND_SIZE + 1];
3318 char arg1[ARG_SIZE + 1];
3319 char arg2[ARG_SIZE + 1];
3320 char* argv[3] = { cmd, arg1, arg2 };
3323 cmd[COMMAND_SIZE] = 0;
3328 bool cleared_log_disasm_bit =
false;
3332 PrintInstructionsAt(pc_, 1);
3339 char* last_input = last_debugger_input();
3340 if (strcmp(line,
"\n") == 0 && (last_input !=
NULL)) {
3345 set_last_debugger_input(line);
3350 int argc = SScanF(line,
3351 "%" XSTR(COMMAND_SIZE)
"s "
3352 "%" XSTR(ARG_SIZE)
"s "
3353 "%" XSTR(ARG_SIZE)
"s",
3357 if ((strcmp(cmd,
"si") == 0) || (strcmp(cmd,
"stepi") == 0)) {
3362 pc_modified_ =
false;
3365 ExecuteInstruction();
3367 int64_t number_of_instructions_to_execute = 1;
3368 GetValue(arg1, &number_of_instructions_to_execute);
3370 set_log_parameters(log_parameters() |
LOG_DISASM);
3371 while (number_of_instructions_to_execute-- > 0) {
3372 ExecuteInstruction();
3374 set_log_parameters(log_parameters() & ~
LOG_DISASM);
3381 pc_modified_ =
true;
3384 }
else if ((strcmp(cmd,
"next") == 0) || (strcmp(cmd,
"n") == 0)) {
3386 break_on_next_ =
true;
3391 }
else if ((strcmp(cmd,
"continue") == 0) ||
3392 (strcmp(cmd,
"cont") == 0) ||
3393 (strcmp(cmd,
"c") == 0)) {
3398 }
else if (strcmp(cmd,
"disassemble") == 0 ||
3399 strcmp(cmd,
"disasm") == 0 ||
3400 strcmp(cmd,
"di") == 0) {
3401 int64_t n_of_instrs_to_disasm = 10;
3402 int64_t address =
reinterpret_cast<int64_t
>(pc_);
3404 GetValue(arg1, &n_of_instrs_to_disasm);
3407 GetValue(arg2, &address);
3411 PrintInstructionsAt(
reinterpret_cast<Instruction*
>(address),
3412 n_of_instrs_to_disasm);
3416 }
else if ((strcmp(cmd,
"print") == 0) || (strcmp(cmd,
"p") == 0)) {
3418 if (strcmp(arg1,
"all") == 0) {
3422 if (!PrintValue(arg1)) {
3423 PrintF(
"%s unrecognized\n", arg1);
3428 "print <register>\n"
3429 " Print the content of a register. (alias 'p')\n"
3430 " 'print all' will print all registers.\n"
3431 " Use 'printobject' to get more details about the value.\n");
3435 }
else if ((strcmp(cmd,
"printobject") == 0) ||
3436 (strcmp(cmd,
"po") == 0)) {
3439 OFStream os(stdout);
3440 if (GetValue(arg1, &value)) {
3442 os << arg1 <<
": \n";
3447 os << Brief(obj) <<
"\n";
3450 os << arg1 <<
" unrecognized\n";
3453 PrintF(
"printobject <value>\n"
3454 "printobject <register>\n"
3455 " Print details about the value. (alias 'po')\n");
3459 }
else if (strcmp(cmd,
"stack") == 0 || strcmp(cmd,
"mem") == 0) {
3460 int64_t* cur =
NULL;
3461 int64_t* end =
NULL;
3464 if (strcmp(cmd,
"stack") == 0) {
3465 cur =
reinterpret_cast<int64_t*
>(jssp());
3469 if (!GetValue(arg1, &value)) {
3470 PrintF(
"%s unrecognized\n", arg1);
3473 cur =
reinterpret_cast<int64_t*
>(value);
3478 if (argc == next_arg) {
3480 }
else if (argc == next_arg + 1) {
3481 if (!GetValue(argv[next_arg], &words)) {
3482 PrintF(
"%s unrecognized\n", argv[next_arg]);
3483 PrintF(
"Printing 10 double words by default");
3492 PrintF(
" 0x%016" PRIx64
": 0x%016" PRIx64
" %10" PRId64,
3493 reinterpret_cast<uint64_t
>(cur), *cur, *cur);
3494 HeapObject* obj =
reinterpret_cast<HeapObject*
>(*cur);
3495 int64_t value = *cur;
3496 Heap* current_heap = v8::internal::Isolate::Current()->heap();
3497 if (((value & 1) == 0) || current_heap->Contains(obj)) {
3502 PrintF(
"smi %" PRId32, untagged);
3513 }
else if (strcmp(cmd,
"trace") == 0 || strcmp(cmd,
"t") == 0) {
3516 PrintF(
"Enabling disassembly and registers tracing\n");
3519 PrintF(
"Disabling disassembly and registers tracing\n");
3524 }
else if (strcmp(cmd,
"break") == 0 || strcmp(cmd,
"b") == 0) {
3527 if (GetValue(arg1, &value)) {
3528 SetBreakpoint(
reinterpret_cast<Instruction*
>(value));
3530 PrintF(
"%s unrecognized\n", arg1);
3534 PrintF(
"Use `break <address>` to set or disable a breakpoint\n");
3538 }
else if (strcmp(cmd,
"gdb") == 0) {
3539 PrintF(
"Relinquishing control to gdb.\n");
3540 base::OS::DebugBreak();
3541 PrintF(
"Regaining control from gdb.\n");
3544 }
else if (strcmp(cmd,
"sysregs") == 0) {
3545 PrintSystemRegisters();
3548 }
else if (strcmp(cmd,
"help") == 0 || strcmp(cmd,
"h") == 0) {
3552 " Step <n> instructions.\n"
3554 " Continue execution until a BL instruction is reached.\n"
3555 " At this point a breakpoint is set just after this BL.\n"
3556 " Then execution is resumed. It will probably later hit the\n"
3557 " breakpoint just set.\n"
3558 "continue / cont / c\n"
3559 " Continue execution from here.\n"
3560 "disassemble / disasm / di\n"
3561 " disassemble <n> <address>\n"
3562 " Disassemble <n> instructions from current <address>.\n"
3563 " By default <n> is 20 and <address> is the current pc.\n"
3565 " print <register>\n"
3566 " Print the content of a register.\n"
3567 " 'print all' will print all registers.\n"
3568 " Use 'printobject' to get more details about the value.\n"
3569 "printobject / po\n"
3570 " printobject <value>\n"
3571 " printobject <register>\n"
3572 " Print details about the value.\n"
3574 " stack [<words>]\n"
3575 " Dump stack content, default dump 10 words\n"
3577 " mem <address> [<words>]\n"
3578 " Dump memory content, default dump 10 words\n"
3580 " Toggle disassembly and register tracing\n"
3582 " break : list all breakpoints\n"
3583 " break <address> : set / enable / disable a breakpoint.\n"
3587 " Print all system registers (including NZCV).\n");
3589 PrintF(
"Unknown command: %s\n", cmd);
3590 PrintF(
"Use 'help' for more information.\n");
3593 if (cleared_log_disasm_bit ==
true) {
3594 set_log_parameters(log_parameters_ |
LOG_DISASM);
3600 void Simulator::VisitException(Instruction* instr) {
3613 sizeof(parameters));
3614 char const *message =
3615 reinterpret_cast<char const*
>(
3621 if (FLAG_trace_sim_messages || FLAG_trace_sim || (parameters &
BREAK)) {
3622 if (message !=
NULL) {
3624 "# %sDebugger hit %d: %s%s%s\n",
3632 "# %sDebugger hit %d.%s\n",
3642 set_log_parameters(log_parameters() | parameters);
3643 if (parameters &
LOG_SYS_REGS) { PrintSystemRegisters(); }
3644 if (parameters &
LOG_REGS) { PrintRegisters(); }
3645 if (parameters &
LOG_FP_REGS) { PrintFPRegisters(); }
3648 set_log_parameters(log_parameters() & ~parameters);
3651 set_log_parameters(parameters);
3657 parameters &= ~log_parameters();
3660 if (parameters &
LOG_REGS) PrintRegisters();
3672 set_pc(pc_->following());
3675 if (parameters &
BREAK) Debug();
3678 DoRuntimeCall(instr);
3683 fprintf(stream_,
"Hit UNREACHABLE marker at PC=%p.\n",
3684 reinterpret_cast<void*
>(pc_));
3688 base::OS::DebugBreak();
3699 void Simulator::DoPrintf(Instruction* instr) {
3710 memcpy(&arg_pattern_list,
3712 sizeof(arg_pattern_list));
3726 const char * format_base = reg<const char *>(0);
3728 size_t length = strlen(format_base) + 1;
3729 char *
const format =
new char[length + arg_count];
3736 char * format_scratch = format;
3737 for (
size_t i = 0;
i < length;
i++) {
3738 if (format_base[
i] !=
'%') {
3739 *format_scratch++ = format_base[
i];
3741 if (format_base[
i + 1] ==
'%') {
3743 *format_scratch++ = format_base[
i];
3745 if (placeholder_count == 0) {
3751 *format_scratch++ = format_base[++
i];
3754 CHECK(placeholder_count < arg_count);
3756 *format_scratch++ =
'\0';
3757 chunks[placeholder_count++] = format_scratch;
3758 *format_scratch++ = format_base[
i];
3762 DCHECK(format_scratch <= (format + length + arg_count));
3763 CHECK(placeholder_count == arg_count);
3770 fprintf(stream_,
"%s", clr_printf);
3774 int result = fprintf(stream_,
"%s", format);
3778 for (
uint32_t i = 0;
i < placeholder_count;
i++) {
3779 int part_result = -1;
3783 switch (arg_pattern) {
3785 part_result = fprintf(stream_, chunks[
i], wreg(pcs_r++));
3788 part_result = fprintf(stream_, chunks[
i], xreg(pcs_r++));
3791 part_result = fprintf(stream_, chunks[
i], dreg(pcs_f++));
3796 if (part_result < 0) {
3798 result = part_result;
3802 result += part_result;
3806 fprintf(stream_,
"%s", clr_normal);
3809 CorruptAllCallerSavedCPURegisters();
3813 set_xreg(0, result);
static int ActivationFrameAlignment()
static void VFPrint(FILE *out, const char *format, va_list args)
#define V(NAME, Name, id)
enable harmony numeric enable harmony object literal extensions Optimize object size
enable harmony numeric enable harmony object literal extensions Optimize object Array DOM strings and string trace pretenuring decisions of HAllocate instructions Enables optimizations which favor memory size over execution speed maximum source size in bytes considered for a single inlining maximum cumulative number of AST nodes considered for inlining trace the tracking of allocation sites deoptimize every n garbage collections perform array bounds checks elimination analyze liveness of environment slots and zap dead values flushes the cache of optimized code for closures on every GC allow uint32 values on optimize frames if they are used only in safe operations track concurrent recompilation artificial compilation delay in ms do not emit check maps for constant values that have a leaf deoptimize the optimized code if the layout of the maps changes enable context specialization in TurboFan execution budget before interrupt is triggered max percentage of megamorphic generic ICs to allow optimization enable use of SAHF instruction if enable use of VFP3 instructions if available enable use of NEON instructions if enable use of SDIV and UDIV instructions if enable use of MLS instructions if enable loading bit constant by means of movw movt instruction enable unaligned accesses for enable use of d16 d31 registers on ARM this requires VFP3 force all emitted branches to be in long enable alignment of csp to bytes on platforms which prefer the register to always be expose gc extension under the specified name show built in functions in stack traces use random jit cookie to mask large constants minimum length for automatic enable preparsing CPU profiler sampling interval in microseconds trace out of bounds accesses to external arrays default size of stack region v8 is allowed to maximum length of function source code printed in a stack trace min size of a semi the new space consists of two semi spaces print one trace line following each garbage collection do not print trace line after scavenger collection print cumulative GC statistics in name
enable harmony numeric enable harmony object literal extensions Optimize object Array DOM strings and string trace pretenuring decisions of HAllocate instructions Enables optimizations which favor memory size over execution speed maximum source size in bytes considered for a single inlining maximum cumulative number of AST nodes considered for inlining trace the tracking of allocation sites deoptimize every n garbage collections perform array bounds checks elimination analyze liveness of environment slots and zap dead values flushes the cache of optimized code for closures on every GC allow uint32 values on optimize frames if they are used only in safe operations track concurrent recompilation artificial compilation delay in ms do not emit check maps for constant values that have a leaf deoptimize the optimized code if the layout of the maps changes enable context specialization in TurboFan execution budget before interrupt is triggered max percentage of megamorphic generic ICs to allow optimization enable use of SAHF instruction if enable use of VFP3 instructions if available enable use of NEON instructions if enable use of SDIV and UDIV instructions if enable use of MLS instructions if enable loading bit constant by means of movw movt instruction enable unaligned accesses for enable use of d16 d31 registers on ARM this requires VFP3 force all emitted branches to be in long mode(MIPS only)") DEFINE_BOOL(enable_always_align_csp
enable harmony numeric enable harmony object literal extensions Optimize object Array DOM strings and string trace pretenuring decisions of HAllocate instructions Enables optimizations which favor memory size over execution speed maximum source size in bytes considered for a single inlining maximum cumulative number of AST nodes considered for inlining trace the tracking of allocation sites deoptimize every n garbage collections perform array bounds checks elimination analyze liveness of environment slots and zap dead values flushes the cache of optimized code for closures on every GC allow uint32 values on optimize frames if they are used only in safe operations track concurrent recompilation artificial compilation delay in ms do not emit check maps for constant values that have a leaf deoptimize the optimized code if the layout of the maps changes enable context specialization in TurboFan execution budget before interrupt is triggered max percentage of megamorphic generic ICs to allow optimization enable use of SAHF instruction if enable use of VFP3 instructions if available enable use of NEON instructions if enable use of SDIV and UDIV instructions if enable use of MLS instructions if enable loading bit constant by means of movw movt instruction enable unaligned accesses for enable use of d16 d31 registers on ARM this requires VFP3 force all emitted branches to be in long enable alignment of csp to bytes on platforms which prefer the register to always be NULL
enable harmony numeric enable harmony object literal extensions Optimize object Array shift
#define CHECK_EQ(expected, value)
#define DCHECK(condition)
#define DCHECK_EQ(v1, v2)
#define STATIC_ASSERT(test)
#define OFFSET_OF(type, field)
T RoundUp(T x, intptr_t m)
int CountLeadingSignBits(int64_t value, int width)
void DeleteArray(T *array)
const int kNumberOfCalleeSavedFPRegisters
char * ReadLine(const char *prompt)
@ UnconditionalBranchMask
@ DataProcessing1SourceMask
bool IsSignallingNaN(double num)
@ FPDataProcessing2SourceMask
const unsigned kDRegSizeInBits
const Instr kImmExceptionIsRedirectedCall
const unsigned kDebuggerTracingDirectivesMask
const unsigned kXRegSizeInBits
TypeImpl< ZoneTypeConfig > Type
static int min(int a, int b)
const unsigned kShiftAmountXRegMask
bool is_uintn(int64_t x, unsigned n)
const unsigned kSPRegInternalCode
static uint32_t float_to_rawbits(float value)
const RegList kCalleeSaved
static const unsigned kPrintfArgPatternBits
const unsigned kShiftAmountWRegMask
const LowDwVfpRegister d0
@ FPFixedPointConvertMask
const unsigned kPrintfLength
const unsigned kDebugParamsOffset
const unsigned kWRegSizeInBits
kSerializedDataOffset Object
double ToQuietNaN(double num)
@ FPDataProcessing3SourceMask
const unsigned kSRegSizeInBits
const unsigned kPrintfMaxArgCount
@ FPDataProcessing1SourceMask
const unsigned kNumberOfFPRegisters
const int64_t kHalfWordMask
const Instr kImmExceptionIsPrintf
double FusedMultiplyAdd(double op1, double op2, double a)
static float rawbits_to_float(uint32_t bits)
const unsigned kPrintfArgPatternListOffset
const unsigned kRegCodeMask
static double rawbits_to_double(uint64_t bits)
static uint64_t double_to_rawbits(double value)
@ DataProcessing3SourceMask
void PrintF(const char *format,...)
int CountLeadingZeros(uint64_t value, int width)
@ DataProcessing2SourceMask
const Instr kImmExceptionIsDebug
const int kNumberOfCalleeSavedRegisters
@ FPConditionalSelectMask
const unsigned kZeroRegCode
const intptr_t kSmiTagMask
uint64_t unsigned_bitextract_64(int msb, int lsb, uint64_t x)
bool is_intn(int64_t x, unsigned n)
const unsigned kNumberOfRegisters
const unsigned kByteSizeInBytes
@ FPConditionalCompareMask
const uint32_t kSlotsZapValue
const Instr kImmExceptionIsUnreachable
const unsigned kDebugCodeOffset
const unsigned kInstructionSize
@ UnconditionalBranchToRegisterMask
const unsigned kHalfWordSizeInBytes
const unsigned kPrintfArgCountOffset
const RegList kCallerSaved
const unsigned kDebugMessageOffset
Debugger support for the V8 JavaScript engine.
#define T(name, string, precedence)