1 // Copyright 2013 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "src/execution/arm64/simulator-arm64.h"
6
7 #include "src/execution/isolate.h"
8
9 #if defined(USE_SIMULATOR)
10
11 #include <stdlib.h>
12
13 #include <cmath>
14 #include <cstdarg>
15 #include <type_traits>
16
17 #include "src/base/overflowing-math.h"
18 #include "src/base/platform/platform.h"
19 #include "src/base/platform/wrappers.h"
20 #include "src/codegen/arm64/decoder-arm64-inl.h"
21 #include "src/codegen/assembler-inl.h"
22 #include "src/codegen/macro-assembler.h"
23 #include "src/diagnostics/disasm.h"
24 #include "src/heap/combined-heap.h"
25 #include "src/objects/objects-inl.h"
26 #include "src/runtime/runtime-utils.h"
27 #include "src/utils/ostreams.h"
28
29 #if V8_OS_WIN
30 #include <windows.h>
31 #endif
32
33 #if V8_ENABLE_WEBASSEMBLY
34 #include "src/trap-handler/trap-handler-simulator.h"
35 #endif // V8_ENABLE_WEBASSEMBLY
36
37 namespace v8 {
38 namespace internal {
39
40 // This macro provides a platform independent use of sscanf. The reason for
41 // SScanF not being implemented in a platform independent way through
42 // ::v8::internal::OS in the same way as SNPrintF is that the
43 // Windows C Run-Time Library does not provide vsscanf.
44 #define SScanF sscanf
45
46 // Helpers for colors.
47 #define COLOUR(colour_code) "\033[0;" colour_code "m"
48 #define COLOUR_BOLD(colour_code) "\033[1;" colour_code "m"
49 #define NORMAL ""
50 #define GREY "30"
51 #define RED "31"
52 #define GREEN "32"
53 #define YELLOW "33"
54 #define BLUE "34"
55 #define MAGENTA "35"
56 #define CYAN "36"
57 #define WHITE "37"
58
59 using TEXT_COLOUR = char const* const;
60 TEXT_COLOUR clr_normal = FLAG_log_colour ? COLOUR(NORMAL) : "";
61 TEXT_COLOUR clr_flag_name = FLAG_log_colour ? COLOUR_BOLD(WHITE) : "";
62 TEXT_COLOUR clr_flag_value = FLAG_log_colour ? COLOUR(NORMAL) : "";
63 TEXT_COLOUR clr_reg_name = FLAG_log_colour ? COLOUR_BOLD(CYAN) : "";
64 TEXT_COLOUR clr_reg_value = FLAG_log_colour ? COLOUR(CYAN) : "";
65 TEXT_COLOUR clr_vreg_name = FLAG_log_colour ? COLOUR_BOLD(MAGENTA) : "";
66 TEXT_COLOUR clr_vreg_value = FLAG_log_colour ? COLOUR(MAGENTA) : "";
67 TEXT_COLOUR clr_memory_address = FLAG_log_colour ? COLOUR_BOLD(BLUE) : "";
68 TEXT_COLOUR clr_debug_number = FLAG_log_colour ? COLOUR_BOLD(YELLOW) : "";
69 TEXT_COLOUR clr_debug_message = FLAG_log_colour ? COLOUR(YELLOW) : "";
70 TEXT_COLOUR clr_printf = FLAG_log_colour ? COLOUR(GREEN) : "";
71
DEFINE_LAZY_LEAKY_OBJECT_GETTER(Simulator::GlobalMonitor,Simulator::GlobalMonitor::Get)72 DEFINE_LAZY_LEAKY_OBJECT_GETTER(Simulator::GlobalMonitor,
73 Simulator::GlobalMonitor::Get)
74
75 bool Simulator::ProbeMemory(uintptr_t address, uintptr_t access_size) {
76 #if V8_ENABLE_WEBASSEMBLY && V8_TRAP_HANDLER_SUPPORTED
77 uintptr_t last_accessed_byte = address + access_size - 1;
78 uintptr_t current_pc = reinterpret_cast<uintptr_t>(pc_);
79 uintptr_t landing_pad =
80 trap_handler::ProbeMemory(last_accessed_byte, current_pc);
81 if (!landing_pad) return true;
82 set_pc(landing_pad);
83 return false;
84 #else
85 return true;
86 #endif
87 }
88
89 // This is basically the same as PrintF, with a guard for FLAG_trace_sim.
TraceSim(const char * format,...)90 void Simulator::TraceSim(const char* format, ...) {
91 if (FLAG_trace_sim) {
92 va_list arguments;
93 va_start(arguments, format);
94 base::OS::VFPrint(stream_, format, arguments);
95 va_end(arguments);
96 }
97 }
98
99 const Instruction* Simulator::kEndOfSimAddress = nullptr;
100
SetBits(int msb,int lsb,uint32_t bits)101 void SimSystemRegister::SetBits(int msb, int lsb, uint32_t bits) {
102 int width = msb - lsb + 1;
103 DCHECK(is_uintn(bits, width) || is_intn(bits, width));
104
105 bits <<= lsb;
106 uint32_t mask = ((1 << width) - 1) << lsb;
107 DCHECK_EQ(mask & write_ignore_mask_, 0);
108
109 value_ = (value_ & ~mask) | (bits & mask);
110 }
111
DefaultValueFor(SystemRegister id)112 SimSystemRegister SimSystemRegister::DefaultValueFor(SystemRegister id) {
113 switch (id) {
114 case NZCV:
115 return SimSystemRegister(0x00000000, NZCVWriteIgnoreMask);
116 case FPCR:
117 return SimSystemRegister(0x00000000, FPCRWriteIgnoreMask);
118 default:
119 UNREACHABLE();
120 }
121 }
122
123 // Get the active Simulator for the current thread.
current(Isolate * isolate)124 Simulator* Simulator::current(Isolate* isolate) {
125 Isolate::PerIsolateThreadData* isolate_data =
126 isolate->FindOrAllocatePerThreadDataForThisThread();
127 DCHECK_NOT_NULL(isolate_data);
128
129 Simulator* sim = isolate_data->simulator();
130 if (sim == nullptr) {
131 if (FLAG_trace_sim || FLAG_debug_sim) {
132 sim = new Simulator(new Decoder<DispatchingDecoderVisitor>(), isolate);
133 } else {
134 sim = new Decoder<Simulator>();
135 sim->isolate_ = isolate;
136 }
137 isolate_data->set_simulator(sim);
138 }
139 return sim;
140 }
141
CallImpl(Address entry,CallArgument * args)142 void Simulator::CallImpl(Address entry, CallArgument* args) {
143 int index_x = 0;
144 int index_d = 0;
145
146 std::vector<int64_t> stack_args(0);
147 for (int i = 0; !args[i].IsEnd(); i++) {
148 CallArgument arg = args[i];
149 if (arg.IsX() && (index_x < 8)) {
150 set_xreg(index_x++, arg.bits());
151 } else if (arg.IsD() && (index_d < 8)) {
152 set_dreg_bits(index_d++, arg.bits());
153 } else {
154 DCHECK(arg.IsD() || arg.IsX());
155 stack_args.push_back(arg.bits());
156 }
157 }
158
159 // Process stack arguments, and make sure the stack is suitably aligned.
160 uintptr_t original_stack = sp();
161 uintptr_t entry_stack =
162 original_stack - stack_args.size() * sizeof(stack_args[0]);
163 if (base::OS::ActivationFrameAlignment() != 0) {
164 entry_stack &= -base::OS::ActivationFrameAlignment();
165 }
166 char* stack = reinterpret_cast<char*>(entry_stack);
167 std::vector<int64_t>::const_iterator it;
168 for (it = stack_args.begin(); it != stack_args.end(); it++) {
169 memcpy(stack, &(*it), sizeof(*it));
170 stack += sizeof(*it);
171 }
172
173 DCHECK(reinterpret_cast<uintptr_t>(stack) <= original_stack);
174 set_sp(entry_stack);
175
176 // Call the generated code.
177 set_pc(entry);
178 set_lr(kEndOfSimAddress);
179 CheckPCSComplianceAndRun();
180
181 set_sp(original_stack);
182 }
183
184 #ifdef DEBUG
185 namespace {
PopLowestIndexAsCode(CPURegList * list)186 int PopLowestIndexAsCode(CPURegList* list) {
187 if (list->IsEmpty()) {
188 return -1;
189 }
190 uint64_t reg_list = list->bits();
191 int index = base::bits::CountTrailingZeros(reg_list);
192 DCHECK((1LL << index) & reg_list);
193 list->Remove(index);
194
195 return index;
196 }
197 } // namespace
198 #endif
199
CheckPCSComplianceAndRun()200 void Simulator::CheckPCSComplianceAndRun() {
201 // Adjust JS-based stack limit to C-based stack limit.
202 isolate_->stack_guard()->AdjustStackLimitForSimulator();
203
204 #ifdef DEBUG
205 DCHECK_EQ(kNumberOfCalleeSavedRegisters, kCalleeSaved.Count());
206 DCHECK_EQ(kNumberOfCalleeSavedVRegisters, kCalleeSavedV.Count());
207
208 int64_t saved_registers[kNumberOfCalleeSavedRegisters];
209 uint64_t saved_fpregisters[kNumberOfCalleeSavedVRegisters];
210
211 CPURegList register_list = kCalleeSaved;
212 CPURegList fpregister_list = kCalleeSavedV;
213
214 for (int i = 0; i < kNumberOfCalleeSavedRegisters; i++) {
215 // x31 is not a caller saved register, so no need to specify if we want
216 // the stack or zero.
217 saved_registers[i] = xreg(PopLowestIndexAsCode(®ister_list));
218 }
219 for (int i = 0; i < kNumberOfCalleeSavedVRegisters; i++) {
220 saved_fpregisters[i] = dreg_bits(PopLowestIndexAsCode(&fpregister_list));
221 }
222 int64_t original_stack = sp();
223 int64_t original_fp = fp();
224 #endif
225 // Start the simulation!
226 Run();
227 #ifdef DEBUG
228 DCHECK_EQ(original_stack, sp());
229 DCHECK_EQ(original_fp, fp());
230 // Check that callee-saved registers have been preserved.
231 register_list = kCalleeSaved;
232 fpregister_list = kCalleeSavedV;
233 for (int i = 0; i < kNumberOfCalleeSavedRegisters; i++) {
234 DCHECK_EQ(saved_registers[i], xreg(PopLowestIndexAsCode(®ister_list)));
235 }
236 for (int i = 0; i < kNumberOfCalleeSavedVRegisters; i++) {
237 DCHECK(saved_fpregisters[i] ==
238 dreg_bits(PopLowestIndexAsCode(&fpregister_list)));
239 }
240
241 // Corrupt caller saved register minus the return regiters.
242
243 // In theory x0 to x7 can be used for return values, but V8 only uses x0, x1
244 // for now .
245 register_list = kCallerSaved;
246 register_list.Remove(x0);
247 register_list.Remove(x1);
248
249 // In theory d0 to d7 can be used for return values, but V8 only uses d0
250 // for now .
251 fpregister_list = kCallerSavedV;
252 fpregister_list.Remove(d0);
253
254 CorruptRegisters(®ister_list, kCallerSavedRegisterCorruptionValue);
255 CorruptRegisters(&fpregister_list, kCallerSavedVRegisterCorruptionValue);
256 #endif
257 }
258
259 #ifdef DEBUG
260 // The least significant byte of the curruption value holds the corresponding
261 // register's code.
CorruptRegisters(CPURegList * list,uint64_t value)262 void Simulator::CorruptRegisters(CPURegList* list, uint64_t value) {
263 if (list->type() == CPURegister::kRegister) {
264 while (!list->IsEmpty()) {
265 unsigned code = PopLowestIndexAsCode(list);
266 set_xreg(code, value | code);
267 }
268 } else {
269 DCHECK_EQ(list->type(), CPURegister::kVRegister);
270 while (!list->IsEmpty()) {
271 unsigned code = PopLowestIndexAsCode(list);
272 set_dreg_bits(code, value | code);
273 }
274 }
275 }
276
CorruptAllCallerSavedCPURegisters()277 void Simulator::CorruptAllCallerSavedCPURegisters() {
278 // Corrupt alters its parameter so copy them first.
279 CPURegList register_list = kCallerSaved;
280 CPURegList fpregister_list = kCallerSavedV;
281
282 CorruptRegisters(®ister_list, kCallerSavedRegisterCorruptionValue);
283 CorruptRegisters(&fpregister_list, kCallerSavedVRegisterCorruptionValue);
284 }
285 #endif
286
287 // Extending the stack by 2 * 64 bits is required for stack alignment purposes.
PushAddress(uintptr_t address)288 uintptr_t Simulator::PushAddress(uintptr_t address) {
289 DCHECK(sizeof(uintptr_t) < 2 * kXRegSize);
290 intptr_t new_sp = sp() - 2 * kXRegSize;
291 uintptr_t* alignment_slot = reinterpret_cast<uintptr_t*>(new_sp + kXRegSize);
292 memcpy(alignment_slot, &kSlotsZapValue, kSystemPointerSize);
293 uintptr_t* stack_slot = reinterpret_cast<uintptr_t*>(new_sp);
294 memcpy(stack_slot, &address, kSystemPointerSize);
295 set_sp(new_sp);
296 return new_sp;
297 }
298
PopAddress()299 uintptr_t Simulator::PopAddress() {
300 intptr_t current_sp = sp();
301 uintptr_t* stack_slot = reinterpret_cast<uintptr_t*>(current_sp);
302 uintptr_t address = *stack_slot;
303 DCHECK_LT(sizeof(uintptr_t), 2 * kXRegSize);
304 set_sp(current_sp + 2 * kXRegSize);
305 return address;
306 }
307
308 // Returns the limit of the stack area to enable checking for stack overflows.
StackLimit(uintptr_t c_limit) const309 uintptr_t Simulator::StackLimit(uintptr_t c_limit) const {
310 // The simulator uses a separate JS stack. If we have exhausted the C stack,
311 // we also drop down the JS limit to reflect the exhaustion on the JS stack.
312 if (base::Stack::GetCurrentStackPosition() < c_limit) {
313 return get_sp();
314 }
315
316 // Otherwise the limit is the JS stack. Leave a safety margin of 4 KiB
317 // to prevent overrunning the stack when pushing values.
318 return stack_limit_ + 4 * KB;
319 }
320
SetRedirectInstruction(Instruction * instruction)321 void Simulator::SetRedirectInstruction(Instruction* instruction) {
322 instruction->SetInstructionBits(
323 HLT | Assembler::ImmException(kImmExceptionIsRedirectedCall));
324 }
325
Simulator(Decoder<DispatchingDecoderVisitor> * decoder,Isolate * isolate,FILE * stream)326 Simulator::Simulator(Decoder<DispatchingDecoderVisitor>* decoder,
327 Isolate* isolate, FILE* stream)
328 : decoder_(decoder),
329 guard_pages_(ENABLE_CONTROL_FLOW_INTEGRITY_BOOL),
330 last_debugger_input_(nullptr),
331 log_parameters_(NO_PARAM),
332 icount_for_stop_sim_at_(0),
333 isolate_(isolate) {
334 // Setup the decoder.
335 decoder_->AppendVisitor(this);
336
337 Init(stream);
338
339 if (FLAG_trace_sim) {
340 decoder_->InsertVisitorBefore(print_disasm_, this);
341 log_parameters_ = LOG_ALL;
342 }
343 }
344
Simulator()345 Simulator::Simulator()
346 : decoder_(nullptr),
347 guard_pages_(ENABLE_CONTROL_FLOW_INTEGRITY_BOOL),
348 last_debugger_input_(nullptr),
349 log_parameters_(NO_PARAM),
350 isolate_(nullptr) {
351 Init(stdout);
352 CHECK(!FLAG_trace_sim);
353 }
354
Init(FILE * stream)355 void Simulator::Init(FILE* stream) {
356 ResetState();
357
358 // Allocate and setup the simulator stack.
359 stack_size_ = (FLAG_sim_stack_size * KB) + (2 * stack_protection_size_);
360 stack_ = reinterpret_cast<uintptr_t>(new byte[stack_size_]);
361 stack_limit_ = stack_ + stack_protection_size_;
362 uintptr_t tos = stack_ + stack_size_ - stack_protection_size_;
363 // The stack pointer must be 16-byte aligned.
364 set_sp(tos & ~0xFULL);
365
366 stream_ = stream;
367 print_disasm_ = new PrintDisassembler(stream_);
368
369 // The debugger needs to disassemble code without the simulator executing an
370 // instruction, so we create a dedicated decoder.
371 disassembler_decoder_ = new Decoder<DispatchingDecoderVisitor>();
372 disassembler_decoder_->AppendVisitor(print_disasm_);
373 }
374
ResetState()375 void Simulator::ResetState() {
376 // Reset the system registers.
377 nzcv_ = SimSystemRegister::DefaultValueFor(NZCV);
378 fpcr_ = SimSystemRegister::DefaultValueFor(FPCR);
379
380 // Reset registers to 0.
381 pc_ = nullptr;
382 for (unsigned i = 0; i < kNumberOfRegisters; i++) {
383 set_xreg(i, 0xBADBEEF);
384 }
385 for (unsigned i = 0; i < kNumberOfVRegisters; i++) {
386 // Set FP registers to a value that is NaN in both 32-bit and 64-bit FP.
387 set_dreg_bits(i, 0x7FF000007F800001UL);
388 }
389 // Returning to address 0 exits the Simulator.
390 set_lr(kEndOfSimAddress);
391
392 // Reset debug helpers.
393 breakpoints_.clear();
394 break_on_next_ = false;
395
396 btype_ = DefaultBType;
397 }
398
~Simulator()399 Simulator::~Simulator() {
400 GlobalMonitor::Get()->RemoveProcessor(&global_monitor_processor_);
401 delete[] reinterpret_cast<byte*>(stack_);
402 delete disassembler_decoder_;
403 delete print_disasm_;
404 delete decoder_;
405 }
406
Run()407 void Simulator::Run() {
408 // Flush any written registers before executing anything, so that
409 // manually-set registers are logged _before_ the first instruction.
410 LogAllWrittenRegisters();
411
412 pc_modified_ = false;
413
414 if (::v8::internal::FLAG_stop_sim_at == 0) {
415 // Fast version of the dispatch loop without checking whether the simulator
416 // should be stopping at a particular executed instruction.
417 while (pc_ != kEndOfSimAddress) {
418 ExecuteInstruction();
419 }
420 } else {
421 // FLAG_stop_sim_at is at the non-default value. Stop in the debugger when
422 // we reach the particular instruction count.
423 while (pc_ != kEndOfSimAddress) {
424 icount_for_stop_sim_at_ =
425 base::AddWithWraparound(icount_for_stop_sim_at_, 1);
426 if (icount_for_stop_sim_at_ == ::v8::internal::FLAG_stop_sim_at) {
427 Debug();
428 }
429 ExecuteInstruction();
430 }
431 }
432 }
433
RunFrom(Instruction * start)434 void Simulator::RunFrom(Instruction* start) {
435 set_pc(start);
436 Run();
437 }
438
439 // Calls into the V8 runtime are based on this very simple interface.
440 // Note: To be able to return two values from some calls the code in runtime.cc
441 // uses the ObjectPair structure.
442 // The simulator assumes all runtime calls return two 64-bits values. If they
443 // don't, register x1 is clobbered. This is fine because x1 is caller-saved.
444 #if defined(V8_OS_WIN)
445 using SimulatorRuntimeCall_ReturnPtr = int64_t (*)(
446 int64_t arg0, int64_t arg1, int64_t arg2, int64_t arg3, int64_t arg4,
447 int64_t arg5, int64_t arg6, int64_t arg7, int64_t arg8, int64_t arg9,
448 int64_t arg10, int64_t arg11, int64_t arg12, int64_t arg13, int64_t arg14,
449 int64_t arg15, int64_t arg16, int64_t arg17, int64_t arg18, int64_t arg19);
450 #endif
451
452 using SimulatorRuntimeCall = ObjectPair (*)(
453 int64_t arg0, int64_t arg1, int64_t arg2, int64_t arg3, int64_t arg4,
454 int64_t arg5, int64_t arg6, int64_t arg7, int64_t arg8, int64_t arg9,
455 int64_t arg10, int64_t arg11, int64_t arg12, int64_t arg13, int64_t arg14,
456 int64_t arg15, int64_t arg16, int64_t arg17, int64_t arg18, int64_t arg19);
457
458 using SimulatorRuntimeCompareCall = int64_t (*)(double arg1, double arg2);
459 using SimulatorRuntimeFPFPCall = double (*)(double arg1, double arg2);
460 using SimulatorRuntimeFPCall = double (*)(double arg1);
461 using SimulatorRuntimeFPIntCall = double (*)(double arg1, int32_t arg2);
462
463 // This signature supports direct call in to API function native callback
464 // (refer to InvocationCallback in v8.h).
465 using SimulatorRuntimeDirectApiCall = void (*)(int64_t arg0);
466 using SimulatorRuntimeProfilingApiCall = void (*)(int64_t arg0, void* arg1);
467
468 // This signature supports direct call to accessor getter callback.
469 using SimulatorRuntimeDirectGetterCall = void (*)(int64_t arg0, int64_t arg1);
470 using SimulatorRuntimeProfilingGetterCall = void (*)(int64_t arg0, int64_t arg1,
471 void* arg2);
472
473 // Separate for fine-grained UBSan blocklisting. Casting any given C++
474 // function to {SimulatorRuntimeCall} is undefined behavior; but since
475 // the target function can indeed be any function that's exposed via
476 // the "fast C call" mechanism, we can't reconstruct its signature here.
UnsafeGenericFunctionCall(int64_t function,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,int64_t arg9,int64_t arg10,int64_t arg11,int64_t arg12,int64_t arg13,int64_t arg14,int64_t arg15,int64_t arg16,int64_t arg17,int64_t arg18,int64_t arg19)477 ObjectPair UnsafeGenericFunctionCall(
478 int64_t function, int64_t arg0, int64_t arg1, int64_t arg2, int64_t arg3,
479 int64_t arg4, int64_t arg5, int64_t arg6, int64_t arg7, int64_t arg8,
480 int64_t arg9, int64_t arg10, int64_t arg11, int64_t arg12, int64_t arg13,
481 int64_t arg14, int64_t arg15, int64_t arg16, int64_t arg17, int64_t arg18,
482 int64_t arg19) {
483 SimulatorRuntimeCall target =
484 reinterpret_cast<SimulatorRuntimeCall>(function);
485 return target(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9,
486 arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17, arg18,
487 arg19);
488 }
UnsafeDirectApiCall(int64_t function,int64_t arg0)489 void UnsafeDirectApiCall(int64_t function, int64_t arg0) {
490 SimulatorRuntimeDirectApiCall target =
491 reinterpret_cast<SimulatorRuntimeDirectApiCall>(function);
492 target(arg0);
493 }
UnsafeProfilingApiCall(int64_t function,int64_t arg0,void * arg1)494 void UnsafeProfilingApiCall(int64_t function, int64_t arg0, void* arg1) {
495 SimulatorRuntimeProfilingApiCall target =
496 reinterpret_cast<SimulatorRuntimeProfilingApiCall>(function);
497 target(arg0, arg1);
498 }
UnsafeDirectGetterCall(int64_t function,int64_t arg0,int64_t arg1)499 void UnsafeDirectGetterCall(int64_t function, int64_t arg0, int64_t arg1) {
500 SimulatorRuntimeDirectGetterCall target =
501 reinterpret_cast<SimulatorRuntimeDirectGetterCall>(function);
502 target(arg0, arg1);
503 }
504
505 using MixedRuntimeCall_0 = AnyCType (*)();
506
507 #define BRACKETS(ident, N) ident[N]
508
509 #define REP_0(expr, FMT)
510 #define REP_1(expr, FMT) FMT(expr, 0)
511 #define REP_2(expr, FMT) REP_1(expr, FMT), FMT(expr, 1)
512 #define REP_3(expr, FMT) REP_2(expr, FMT), FMT(expr, 2)
513 #define REP_4(expr, FMT) REP_3(expr, FMT), FMT(expr, 3)
514 #define REP_5(expr, FMT) REP_4(expr, FMT), FMT(expr, 4)
515 #define REP_6(expr, FMT) REP_5(expr, FMT), FMT(expr, 5)
516 #define REP_7(expr, FMT) REP_6(expr, FMT), FMT(expr, 6)
517 #define REP_8(expr, FMT) REP_7(expr, FMT), FMT(expr, 7)
518 #define REP_9(expr, FMT) REP_8(expr, FMT), FMT(expr, 8)
519 #define REP_10(expr, FMT) REP_9(expr, FMT), FMT(expr, 9)
520 #define REP_11(expr, FMT) REP_10(expr, FMT), FMT(expr, 10)
521 #define REP_12(expr, FMT) REP_11(expr, FMT), FMT(expr, 11)
522 #define REP_13(expr, FMT) REP_12(expr, FMT), FMT(expr, 12)
523 #define REP_14(expr, FMT) REP_13(expr, FMT), FMT(expr, 13)
524 #define REP_15(expr, FMT) REP_14(expr, FMT), FMT(expr, 14)
525 #define REP_16(expr, FMT) REP_15(expr, FMT), FMT(expr, 15)
526 #define REP_17(expr, FMT) REP_16(expr, FMT), FMT(expr, 16)
527 #define REP_18(expr, FMT) REP_17(expr, FMT), FMT(expr, 17)
528 #define REP_19(expr, FMT) REP_18(expr, FMT), FMT(expr, 18)
529 #define REP_20(expr, FMT) REP_19(expr, FMT), FMT(expr, 19)
530
531 #define GEN_MAX_PARAM_COUNT(V) \
532 V(0) \
533 V(1) \
534 V(2) \
535 V(3) \
536 V(4) \
537 V(5) \
538 V(6) \
539 V(7) \
540 V(8) \
541 V(9) \
542 V(10) \
543 V(11) \
544 V(12) \
545 V(13) \
546 V(14) \
547 V(15) \
548 V(16) \
549 V(17) \
550 V(18) \
551 V(19) \
552 V(20)
553
554 #define MIXED_RUNTIME_CALL(N) \
555 using MixedRuntimeCall_##N = AnyCType (*)(REP_##N(AnyCType arg, CONCAT));
556
GEN_MAX_PARAM_COUNT(MIXED_RUNTIME_CALL)557 GEN_MAX_PARAM_COUNT(MIXED_RUNTIME_CALL)
558 #undef MIXED_RUNTIME_CALL
559
560 #define CALL_ARGS(N) REP_##N(args, BRACKETS)
561 #define CALL_TARGET_VARARG(N) \
562 if (signature.ParameterCount() == N) { /* NOLINT */ \
563 MixedRuntimeCall_##N target = \
564 reinterpret_cast<MixedRuntimeCall_##N>(target_address); \
565 result = target(CALL_ARGS(N)); \
566 } else /* NOLINT */
567
568 void Simulator::CallAnyCTypeFunction(Address target_address,
569 const EncodedCSignature& signature) {
570 TraceSim("Type: mixed types BUILTIN_CALL\n");
571
572 const int64_t* stack_pointer = reinterpret_cast<int64_t*>(sp());
573 const double* double_stack_pointer = reinterpret_cast<double*>(sp());
574 int num_gp_params = 0, num_fp_params = 0, num_stack_params = 0;
575
576 CHECK_LE(signature.ParameterCount(), kMaxCParameters);
577 static_assert(sizeof(AnyCType) == 8, "AnyCType is assumed to be 64-bit.");
578 AnyCType args[kMaxCParameters];
579 // The first 8 parameters of each type (GP or FP) are placed in corresponding
580 // registers. The rest are expected to be on the stack, where each parameter
581 // type counts on its own. For example a function like:
582 // foo(int i1, ..., int i9, float f1, float f2) will use up all 8 GP
583 // registers, place i9 on the stack, and place f1 and f2 in FP registers.
584 // Source: https://developer.arm.com/documentation/ihi0055/d/, section
585 // "Parameter Passing".
586 for (int i = 0; i < signature.ParameterCount(); ++i) {
587 if (signature.IsFloat(i)) {
588 if (num_fp_params < 8) {
589 args[i].double_value = dreg(num_fp_params++);
590 } else {
591 args[i].double_value = double_stack_pointer[num_stack_params++];
592 }
593 } else {
594 if (num_gp_params < 8) {
595 args[i].int64_value = xreg(num_gp_params++);
596 } else {
597 args[i].int64_value = stack_pointer[num_stack_params++];
598 }
599 }
600 }
601 AnyCType result;
602 GEN_MAX_PARAM_COUNT(CALL_TARGET_VARARG)
603 /* else */ {
604 UNREACHABLE();
605 }
606 static_assert(20 == kMaxCParameters,
607 "If you've changed kMaxCParameters, please change the "
608 "GEN_MAX_PARAM_COUNT macro.");
609
610 #undef CALL_TARGET_VARARG
611 #undef CALL_ARGS
612 #undef GEN_MAX_PARAM_COUNT
613
614 #ifdef DEBUG
615 CorruptAllCallerSavedCPURegisters();
616 #endif
617
618 if (signature.IsReturnFloat()) {
619 set_dreg(0, result.double_value);
620 } else {
621 set_xreg(0, result.int64_value);
622 }
623 }
624
DoRuntimeCall(Instruction * instr)625 void Simulator::DoRuntimeCall(Instruction* instr) {
626 Redirection* redirection = Redirection::FromInstruction(instr);
627
628 // The called C code might itself call simulated code, so any
629 // caller-saved registers (including lr) could still be clobbered by a
630 // redirected call.
631 Instruction* return_address = lr();
632
633 int64_t external =
634 reinterpret_cast<int64_t>(redirection->external_function());
635
636 TraceSim("Call to host function at %p\n", redirection->external_function());
637
638 // SP must be 16-byte-aligned at the call interface.
639 bool stack_alignment_exception = ((sp() & 0xF) != 0);
640 if (stack_alignment_exception) {
641 TraceSim(" with unaligned stack 0x%016" PRIx64 ".\n", sp());
642 FATAL("ALIGNMENT EXCEPTION");
643 }
644
645 Address func_addr =
646 reinterpret_cast<Address>(redirection->external_function());
647 SimulatorData* simulator_data = isolate_->simulator_data();
648 DCHECK_NOT_NULL(simulator_data);
649 const EncodedCSignature& signature =
650 simulator_data->GetSignatureForTarget(func_addr);
651 if (signature.IsValid()) {
652 CHECK(redirection->type() == ExternalReference::FAST_C_CALL);
653 CallAnyCTypeFunction(external, signature);
654 set_lr(return_address);
655 set_pc(return_address);
656 return;
657 }
658
659 int64_t* stack_pointer = reinterpret_cast<int64_t*>(sp());
660
661 const int64_t arg0 = xreg(0);
662 const int64_t arg1 = xreg(1);
663 const int64_t arg2 = xreg(2);
664 const int64_t arg3 = xreg(3);
665 const int64_t arg4 = xreg(4);
666 const int64_t arg5 = xreg(5);
667 const int64_t arg6 = xreg(6);
668 const int64_t arg7 = xreg(7);
669 const int64_t arg8 = stack_pointer[0];
670 const int64_t arg9 = stack_pointer[1];
671 const int64_t arg10 = stack_pointer[2];
672 const int64_t arg11 = stack_pointer[3];
673 const int64_t arg12 = stack_pointer[4];
674 const int64_t arg13 = stack_pointer[5];
675 const int64_t arg14 = stack_pointer[6];
676 const int64_t arg15 = stack_pointer[7];
677 const int64_t arg16 = stack_pointer[8];
678 const int64_t arg17 = stack_pointer[9];
679 const int64_t arg18 = stack_pointer[10];
680 const int64_t arg19 = stack_pointer[11];
681 STATIC_ASSERT(kMaxCParameters == 20);
682
683 switch (redirection->type()) {
684 default:
685 TraceSim("Type: Unknown.\n");
686 UNREACHABLE();
687
688 case ExternalReference::BUILTIN_CALL:
689 #if defined(V8_OS_WIN)
690 {
691 // Object f(v8::internal::Arguments).
692 TraceSim("Type: BUILTIN_CALL\n");
693
694 // When this simulator runs on Windows x64 host, function with ObjectPair
695 // return type accepts an implicit pointer to caller allocated memory for
696 // ObjectPair as return value. This diverges the calling convention from
697 // function which returns primitive type, so function returns ObjectPair
698 // and primitive type cannot share implementation.
699
700 // We don't know how many arguments are being passed, but we can
701 // pass 8 without touching the stack. They will be ignored by the
702 // host function if they aren't used.
703 TraceSim(
704 "Arguments: "
705 "0x%016" PRIx64 ", 0x%016" PRIx64
706 ", "
707 "0x%016" PRIx64 ", 0x%016" PRIx64
708 ", "
709 "0x%016" PRIx64 ", 0x%016" PRIx64
710 ", "
711 "0x%016" PRIx64 ", 0x%016" PRIx64
712 ", "
713 "0x%016" PRIx64 ", 0x%016" PRIx64
714 ", "
715 "0x%016" PRIx64 ", 0x%016" PRIx64
716 ", "
717 "0x%016" PRIx64 ", 0x%016" PRIx64
718 ", "
719 "0x%016" PRIx64 ", 0x%016" PRIx64
720 ", "
721 "0x%016" PRIx64 ", 0x%016" PRIx64
722 ", "
723 "0x%016" PRIx64 ", 0x%016" PRIx64,
724 arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10,
725 arg11, arg12, arg13, arg14, arg15, arg16, arg17, arg18, arg19);
726
727 SimulatorRuntimeCall_ReturnPtr target =
728 reinterpret_cast<SimulatorRuntimeCall_ReturnPtr>(external);
729
730 int64_t result = target(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7,
731 arg8, arg9, arg10, arg11, arg12, arg13, arg14,
732 arg15, arg16, arg17, arg18, arg19);
733 TraceSim("Returned: 0x%16\n", result);
734 #ifdef DEBUG
735 CorruptAllCallerSavedCPURegisters();
736 #endif
737 set_xreg(0, result);
738
739 break;
740 }
741 #endif
742 case ExternalReference::BUILTIN_CALL_PAIR: {
743 // Object f(v8::internal::Arguments) or
744 // ObjectPair f(v8::internal::Arguments).
745 TraceSim("Type: BUILTIN_CALL\n");
746
747 // We don't know how many arguments are being passed, but we can
748 // pass 8 without touching the stack. They will be ignored by the
749 // host function if they aren't used.
750 TraceSim(
751 "Arguments: "
752 "0x%016" PRIx64 ", 0x%016" PRIx64
753 ", "
754 "0x%016" PRIx64 ", 0x%016" PRIx64
755 ", "
756 "0x%016" PRIx64 ", 0x%016" PRIx64
757 ", "
758 "0x%016" PRIx64 ", 0x%016" PRIx64
759 ", "
760 "0x%016" PRIx64 ", 0x%016" PRIx64
761 ", "
762 "0x%016" PRIx64 ", 0x%016" PRIx64
763 ", "
764 "0x%016" PRIx64 ", 0x%016" PRIx64
765 ", "
766 "0x%016" PRIx64 ", 0x%016" PRIx64
767 ", "
768 "0x%016" PRIx64 ", 0x%016" PRIx64
769 ", "
770 "0x%016" PRIx64 ", 0x%016" PRIx64,
771 arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10,
772 arg11, arg12, arg13, arg14, arg15, arg16, arg17, arg18, arg19);
773
774 ObjectPair result = UnsafeGenericFunctionCall(
775 external, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9,
776 arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17, arg18, arg19);
777 TraceSim("Returned: {%p, %p}\n", reinterpret_cast<void*>(result.x),
778 reinterpret_cast<void*>(result.y));
779 #ifdef DEBUG
780 CorruptAllCallerSavedCPURegisters();
781 #endif
782 set_xreg(0, static_cast<int64_t>(result.x));
783 set_xreg(1, static_cast<int64_t>(result.y));
784 break;
785 }
786
787 case ExternalReference::DIRECT_API_CALL: {
788 // void f(v8::FunctionCallbackInfo&)
789 TraceSim("Type: DIRECT_API_CALL\n");
790 TraceSim("Arguments: 0x%016" PRIx64 "\n", xreg(0));
791 UnsafeDirectApiCall(external, xreg(0));
792 TraceSim("No return value.");
793 #ifdef DEBUG
794 CorruptAllCallerSavedCPURegisters();
795 #endif
796 break;
797 }
798
799 case ExternalReference::BUILTIN_COMPARE_CALL: {
800 // int f(double, double)
801 TraceSim("Type: BUILTIN_COMPARE_CALL\n");
802 SimulatorRuntimeCompareCall target =
803 reinterpret_cast<SimulatorRuntimeCompareCall>(external);
804 TraceSim("Arguments: %f, %f\n", dreg(0), dreg(1));
805 int64_t result = target(dreg(0), dreg(1));
806 TraceSim("Returned: %" PRId64 "\n", result);
807 #ifdef DEBUG
808 CorruptAllCallerSavedCPURegisters();
809 #endif
810 set_xreg(0, result);
811 break;
812 }
813
814 case ExternalReference::BUILTIN_FP_CALL: {
815 // double f(double)
816 TraceSim("Type: BUILTIN_FP_CALL\n");
817 SimulatorRuntimeFPCall target =
818 reinterpret_cast<SimulatorRuntimeFPCall>(external);
819 TraceSim("Argument: %f\n", dreg(0));
820 double result = target(dreg(0));
821 TraceSim("Returned: %f\n", result);
822 #ifdef DEBUG
823 CorruptAllCallerSavedCPURegisters();
824 #endif
825 set_dreg(0, result);
826 break;
827 }
828
829 case ExternalReference::BUILTIN_FP_FP_CALL: {
830 // double f(double, double)
831 TraceSim("Type: BUILTIN_FP_FP_CALL\n");
832 SimulatorRuntimeFPFPCall target =
833 reinterpret_cast<SimulatorRuntimeFPFPCall>(external);
834 TraceSim("Arguments: %f, %f\n", dreg(0), dreg(1));
835 double result = target(dreg(0), dreg(1));
836 TraceSim("Returned: %f\n", result);
837 #ifdef DEBUG
838 CorruptAllCallerSavedCPURegisters();
839 #endif
840 set_dreg(0, result);
841 break;
842 }
843
844 case ExternalReference::BUILTIN_FP_INT_CALL: {
845 // double f(double, int)
846 TraceSim("Type: BUILTIN_FP_INT_CALL\n");
847 SimulatorRuntimeFPIntCall target =
848 reinterpret_cast<SimulatorRuntimeFPIntCall>(external);
849 TraceSim("Arguments: %f, %d\n", dreg(0), wreg(0));
850 double result = target(dreg(0), wreg(0));
851 TraceSim("Returned: %f\n", result);
852 #ifdef DEBUG
853 CorruptAllCallerSavedCPURegisters();
854 #endif
855 set_dreg(0, result);
856 break;
857 }
858
859 case ExternalReference::DIRECT_GETTER_CALL: {
860 // void f(Local<String> property, PropertyCallbackInfo& info)
861 TraceSim("Type: DIRECT_GETTER_CALL\n");
862 TraceSim("Arguments: 0x%016" PRIx64 ", 0x%016" PRIx64 "\n", xreg(0),
863 xreg(1));
864 UnsafeDirectGetterCall(external, xreg(0), xreg(1));
865 TraceSim("No return value.");
866 #ifdef DEBUG
867 CorruptAllCallerSavedCPURegisters();
868 #endif
869 break;
870 }
871
872 case ExternalReference::PROFILING_API_CALL: {
873 // void f(v8::FunctionCallbackInfo&, v8::FunctionCallback)
874 TraceSim("Type: PROFILING_API_CALL\n");
875 void* arg1 = Redirection::ReverseRedirection(xreg(1));
876 TraceSim("Arguments: 0x%016" PRIx64 ", %p\n", xreg(0), arg1);
877 UnsafeProfilingApiCall(external, xreg(0), arg1);
878 TraceSim("No return value.");
879 #ifdef DEBUG
880 CorruptAllCallerSavedCPURegisters();
881 #endif
882 break;
883 }
884
885 case ExternalReference::PROFILING_GETTER_CALL: {
886 // void f(Local<String> property, PropertyCallbackInfo& info,
887 // AccessorNameGetterCallback callback)
888 TraceSim("Type: PROFILING_GETTER_CALL\n");
889 SimulatorRuntimeProfilingGetterCall target =
890 reinterpret_cast<SimulatorRuntimeProfilingGetterCall>(external);
891 void* arg2 = Redirection::ReverseRedirection(xreg(2));
892 TraceSim("Arguments: 0x%016" PRIx64 ", 0x%016" PRIx64 ", %p\n", xreg(0),
893 xreg(1), arg2);
894 target(xreg(0), xreg(1), arg2);
895 TraceSim("No return value.");
896 #ifdef DEBUG
897 CorruptAllCallerSavedCPURegisters();
898 #endif
899 break;
900 }
901 }
902
903 set_lr(return_address);
904 set_pc(return_address);
905 }
906
907 const char* Simulator::xreg_names[] = {
908 "x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7", "x8", "x9", "x10",
909 "x11", "x12", "x13", "x14", "x15", "ip0", "ip1", "x18", "x19", "x20", "x21",
910 "x22", "x23", "x24", "x25", "x26", "cp", "x28", "fp", "lr", "xzr", "sp"};
911
912 const char* Simulator::wreg_names[] = {
913 "w0", "w1", "w2", "w3", "w4", "w5", "w6", "w7", "w8",
914 "w9", "w10", "w11", "w12", "w13", "w14", "w15", "w16", "w17",
915 "w18", "w19", "w20", "w21", "w22", "w23", "w24", "w25", "w26",
916 "wcp", "w28", "wfp", "wlr", "wzr", "wsp"};
917
918 const char* Simulator::sreg_names[] = {
919 "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7", "s8", "s9", "s10",
920 "s11", "s12", "s13", "s14", "s15", "s16", "s17", "s18", "s19", "s20", "s21",
921 "s22", "s23", "s24", "s25", "s26", "s27", "s28", "s29", "s30", "s31"};
922
923 const char* Simulator::dreg_names[] = {
924 "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "d8", "d9", "d10",
925 "d11", "d12", "d13", "d14", "d15", "d16", "d17", "d18", "d19", "d20", "d21",
926 "d22", "d23", "d24", "d25", "d26", "d27", "d28", "d29", "d30", "d31"};
927
928 const char* Simulator::vreg_names[] = {
929 "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v8", "v9", "v10",
930 "v11", "v12", "v13", "v14", "v15", "v16", "v17", "v18", "v19", "v20", "v21",
931 "v22", "v23", "v24", "v25", "v26", "v27", "v28", "v29", "v30", "v31"};
932
WRegNameForCode(unsigned code,Reg31Mode mode)933 const char* Simulator::WRegNameForCode(unsigned code, Reg31Mode mode) {
934 static_assert(arraysize(Simulator::wreg_names) == (kNumberOfRegisters + 1),
935 "Array must be large enough to hold all register names.");
936 DCHECK_LT(code, static_cast<unsigned>(kNumberOfRegisters));
937 // The modulo operator has no effect here, but it silences a broken GCC
938 // warning about out-of-bounds array accesses.
939 code %= kNumberOfRegisters;
940
941 // If the code represents the stack pointer, index the name after zr.
942 if ((code == kZeroRegCode) && (mode == Reg31IsStackPointer)) {
943 code = kZeroRegCode + 1;
944 }
945 return wreg_names[code];
946 }
947
XRegNameForCode(unsigned code,Reg31Mode mode)948 const char* Simulator::XRegNameForCode(unsigned code, Reg31Mode mode) {
949 static_assert(arraysize(Simulator::xreg_names) == (kNumberOfRegisters + 1),
950 "Array must be large enough to hold all register names.");
951 DCHECK_LT(code, static_cast<unsigned>(kNumberOfRegisters));
952 code %= kNumberOfRegisters;
953
954 // If the code represents the stack pointer, index the name after zr.
955 if ((code == kZeroRegCode) && (mode == Reg31IsStackPointer)) {
956 code = kZeroRegCode + 1;
957 }
958 return xreg_names[code];
959 }
960
SRegNameForCode(unsigned code)961 const char* Simulator::SRegNameForCode(unsigned code) {
962 static_assert(arraysize(Simulator::sreg_names) == kNumberOfVRegisters,
963 "Array must be large enough to hold all register names.");
964 DCHECK_LT(code, static_cast<unsigned>(kNumberOfVRegisters));
965 return sreg_names[code % kNumberOfVRegisters];
966 }
967
DRegNameForCode(unsigned code)968 const char* Simulator::DRegNameForCode(unsigned code) {
969 static_assert(arraysize(Simulator::dreg_names) == kNumberOfVRegisters,
970 "Array must be large enough to hold all register names.");
971 DCHECK_LT(code, static_cast<unsigned>(kNumberOfVRegisters));
972 return dreg_names[code % kNumberOfVRegisters];
973 }
974
VRegNameForCode(unsigned code)975 const char* Simulator::VRegNameForCode(unsigned code) {
976 static_assert(arraysize(Simulator::vreg_names) == kNumberOfVRegisters,
977 "Array must be large enough to hold all register names.");
978 DCHECK_LT(code, static_cast<unsigned>(kNumberOfVRegisters));
979 return vreg_names[code % kNumberOfVRegisters];
980 }
981
ReadUintFromMem(VectorFormat vform,int index,uint64_t addr) const982 void LogicVRegister::ReadUintFromMem(VectorFormat vform, int index,
983 uint64_t addr) const {
984 switch (LaneSizeInBitsFromFormat(vform)) {
985 case 8:
986 register_.Insert(index, SimMemory::Read<uint8_t>(addr));
987 break;
988 case 16:
989 register_.Insert(index, SimMemory::Read<uint16_t>(addr));
990 break;
991 case 32:
992 register_.Insert(index, SimMemory::Read<uint32_t>(addr));
993 break;
994 case 64:
995 register_.Insert(index, SimMemory::Read<uint64_t>(addr));
996 break;
997 default:
998 UNREACHABLE();
999 }
1000 }
1001
WriteUintToMem(VectorFormat vform,int index,uint64_t addr) const1002 void LogicVRegister::WriteUintToMem(VectorFormat vform, int index,
1003 uint64_t addr) const {
1004 switch (LaneSizeInBitsFromFormat(vform)) {
1005 case 8:
1006 SimMemory::Write<uint8_t>(addr, static_cast<uint8_t>(Uint(vform, index)));
1007 break;
1008 case 16:
1009 SimMemory::Write<uint16_t>(addr,
1010 static_cast<uint16_t>(Uint(vform, index)));
1011 break;
1012 case 32:
1013 SimMemory::Write<uint32_t>(addr,
1014 static_cast<uint32_t>(Uint(vform, index)));
1015 break;
1016 case 64:
1017 SimMemory::Write<uint64_t>(addr, Uint(vform, index));
1018 break;
1019 default:
1020 UNREACHABLE();
1021 }
1022 }
1023
CodeFromName(const char * name)1024 int Simulator::CodeFromName(const char* name) {
1025 for (unsigned i = 0; i < kNumberOfRegisters; i++) {
1026 if ((strcmp(xreg_names[i], name) == 0) ||
1027 (strcmp(wreg_names[i], name) == 0)) {
1028 return i;
1029 }
1030 }
1031 for (unsigned i = 0; i < kNumberOfVRegisters; i++) {
1032 if ((strcmp(vreg_names[i], name) == 0) ||
1033 (strcmp(dreg_names[i], name) == 0) ||
1034 (strcmp(sreg_names[i], name) == 0)) {
1035 return i;
1036 }
1037 }
1038 if ((strcmp("sp", name) == 0) || (strcmp("wsp", name) == 0)) {
1039 return kSPRegInternalCode;
1040 }
1041 return -1;
1042 }
1043
1044 // Helpers ---------------------------------------------------------------------
1045 template <typename T>
AddWithCarry(bool set_flags,T left,T right,int carry_in)1046 T Simulator::AddWithCarry(bool set_flags, T left, T right, int carry_in) {
1047 // Use unsigned types to avoid implementation-defined overflow behaviour.
1048 static_assert(std::is_unsigned<T>::value, "operands must be unsigned");
1049 static_assert((sizeof(T) == kWRegSize) || (sizeof(T) == kXRegSize),
1050 "Only W- or X-sized operands are tested");
1051
1052 DCHECK((carry_in == 0) || (carry_in == 1));
1053 T result = left + right + carry_in;
1054
1055 if (set_flags) {
1056 nzcv().SetN(CalcNFlag(result));
1057 nzcv().SetZ(CalcZFlag(result));
1058
1059 // Compute the C flag by comparing the result to the max unsigned integer.
1060 T max_uint_2op = std::numeric_limits<T>::max() - carry_in;
1061 nzcv().SetC((left > max_uint_2op) || ((max_uint_2op - left) < right));
1062
1063 // Overflow iff the sign bit is the same for the two inputs and different
1064 // for the result.
1065 T sign_mask = T(1) << (sizeof(T) * 8 - 1);
1066 T left_sign = left & sign_mask;
1067 T right_sign = right & sign_mask;
1068 T result_sign = result & sign_mask;
1069 nzcv().SetV((left_sign == right_sign) && (left_sign != result_sign));
1070
1071 LogSystemRegister(NZCV);
1072 }
1073 return result;
1074 }
1075
1076 template <typename T>
AddSubWithCarry(Instruction * instr)1077 void Simulator::AddSubWithCarry(Instruction* instr) {
1078 // Use unsigned types to avoid implementation-defined overflow behaviour.
1079 static_assert(std::is_unsigned<T>::value, "operands must be unsigned");
1080
1081 T op2 = reg<T>(instr->Rm());
1082 T new_val;
1083
1084 if ((instr->Mask(AddSubOpMask) == SUB) || instr->Mask(AddSubOpMask) == SUBS) {
1085 op2 = ~op2;
1086 }
1087
1088 new_val = AddWithCarry<T>(instr->FlagsUpdate(), reg<T>(instr->Rn()), op2,
1089 nzcv().C());
1090
1091 set_reg<T>(instr->Rd(), new_val);
1092 }
1093
1094 template <typename T>
ShiftOperand(T value,Shift shift_type,unsigned amount)1095 T Simulator::ShiftOperand(T value, Shift shift_type, unsigned amount) {
1096 using unsignedT = typename std::make_unsigned<T>::type;
1097
1098 if (amount == 0) {
1099 return value;
1100 }
1101 // Larger shift {amount}s would be undefined behavior in C++.
1102 DCHECK(amount < sizeof(value) * kBitsPerByte);
1103
1104 switch (shift_type) {
1105 case LSL:
1106 return static_cast<unsignedT>(value) << amount;
1107 case LSR:
1108 return static_cast<unsignedT>(value) >> amount;
1109 case ASR:
1110 return value >> amount;
1111 case ROR: {
1112 unsignedT mask = (static_cast<unsignedT>(1) << amount) - 1;
1113 return (static_cast<unsignedT>(value) >> amount) |
1114 ((value & mask) << (sizeof(mask) * 8 - amount));
1115 }
1116 default:
1117 UNIMPLEMENTED();
1118 return 0;
1119 }
1120 }
1121
1122 template <typename T>
ExtendValue(T value,Extend extend_type,unsigned left_shift)1123 T Simulator::ExtendValue(T value, Extend extend_type, unsigned left_shift) {
1124 const unsigned kSignExtendBShift = (sizeof(T) - 1) * 8;
1125 const unsigned kSignExtendHShift = (sizeof(T) - 2) * 8;
1126 const unsigned kSignExtendWShift = (sizeof(T) - 4) * 8;
1127 using unsignedT = typename std::make_unsigned<T>::type;
1128
1129 switch (extend_type) {
1130 case UXTB:
1131 value &= kByteMask;
1132 break;
1133 case UXTH:
1134 value &= kHalfWordMask;
1135 break;
1136 case UXTW:
1137 value &= kWordMask;
1138 break;
1139 case SXTB:
1140 value =
1141 static_cast<T>(static_cast<unsignedT>(value) << kSignExtendBShift) >>
1142 kSignExtendBShift;
1143 break;
1144 case SXTH:
1145 value =
1146 static_cast<T>(static_cast<unsignedT>(value) << kSignExtendHShift) >>
1147 kSignExtendHShift;
1148 break;
1149 case SXTW:
1150 value =
1151 static_cast<T>(static_cast<unsignedT>(value) << kSignExtendWShift) >>
1152 kSignExtendWShift;
1153 break;
1154 case UXTX:
1155 case SXTX:
1156 break;
1157 default:
1158 UNREACHABLE();
1159 }
1160 return static_cast<T>(static_cast<unsignedT>(value) << left_shift);
1161 }
1162
1163 template <typename T>
Extract(Instruction * instr)1164 void Simulator::Extract(Instruction* instr) {
1165 unsigned lsb = instr->ImmS();
1166 T op2 = reg<T>(instr->Rm());
1167 T result = op2;
1168
1169 if (lsb) {
1170 T op1 = reg<T>(instr->Rn());
1171 result = op2 >> lsb | (op1 << ((sizeof(T) * 8) - lsb));
1172 }
1173 set_reg<T>(instr->Rd(), result);
1174 }
1175
FPCompare(double val0,double val1)1176 void Simulator::FPCompare(double val0, double val1) {
1177 AssertSupportedFPCR();
1178
1179 // TODO(jbramley): This assumes that the C++ implementation handles
1180 // comparisons in the way that we expect (as per AssertSupportedFPCR()).
1181 if ((std::isnan(val0) != 0) || (std::isnan(val1) != 0)) {
1182 nzcv().SetRawValue(FPUnorderedFlag);
1183 } else if (val0 < val1) {
1184 nzcv().SetRawValue(FPLessThanFlag);
1185 } else if (val0 > val1) {
1186 nzcv().SetRawValue(FPGreaterThanFlag);
1187 } else if (val0 == val1) {
1188 nzcv().SetRawValue(FPEqualFlag);
1189 } else {
1190 UNREACHABLE();
1191 }
1192 LogSystemRegister(NZCV);
1193 }
1194
GetPrintRegisterFormatForSize(size_t reg_size,size_t lane_size)1195 Simulator::PrintRegisterFormat Simulator::GetPrintRegisterFormatForSize(
1196 size_t reg_size, size_t lane_size) {
1197 DCHECK_GE(reg_size, lane_size);
1198
1199 uint32_t format = 0;
1200 if (reg_size != lane_size) {
1201 switch (reg_size) {
1202 default:
1203 UNREACHABLE();
1204 case kQRegSize:
1205 format = kPrintRegAsQVector;
1206 break;
1207 case kDRegSize:
1208 format = kPrintRegAsDVector;
1209 break;
1210 }
1211 }
1212
1213 switch (lane_size) {
1214 default:
1215 UNREACHABLE();
1216 case kQRegSize:
1217 format |= kPrintReg1Q;
1218 break;
1219 case kDRegSize:
1220 format |= kPrintReg1D;
1221 break;
1222 case kSRegSize:
1223 format |= kPrintReg1S;
1224 break;
1225 case kHRegSize:
1226 format |= kPrintReg1H;
1227 break;
1228 case kBRegSize:
1229 format |= kPrintReg1B;
1230 break;
1231 }
1232
1233 // These sizes would be duplicate case labels.
1234 static_assert(kXRegSize == kDRegSize, "X and D registers must be same size.");
1235 static_assert(kWRegSize == kSRegSize, "W and S registers must be same size.");
1236 static_assert(kPrintXReg == kPrintReg1D,
1237 "X and D register printing code is shared.");
1238 static_assert(kPrintWReg == kPrintReg1S,
1239 "W and S register printing code is shared.");
1240
1241 return static_cast<PrintRegisterFormat>(format);
1242 }
1243
GetPrintRegisterFormat(VectorFormat vform)1244 Simulator::PrintRegisterFormat Simulator::GetPrintRegisterFormat(
1245 VectorFormat vform) {
1246 switch (vform) {
1247 default:
1248 UNREACHABLE();
1249 case kFormat16B:
1250 return kPrintReg16B;
1251 case kFormat8B:
1252 return kPrintReg8B;
1253 case kFormat8H:
1254 return kPrintReg8H;
1255 case kFormat4H:
1256 return kPrintReg4H;
1257 case kFormat4S:
1258 return kPrintReg4S;
1259 case kFormat2S:
1260 return kPrintReg2S;
1261 case kFormat2D:
1262 return kPrintReg2D;
1263 case kFormat1D:
1264 return kPrintReg1D;
1265
1266 case kFormatB:
1267 return kPrintReg1B;
1268 case kFormatH:
1269 return kPrintReg1H;
1270 case kFormatS:
1271 return kPrintReg1S;
1272 case kFormatD:
1273 return kPrintReg1D;
1274 }
1275 }
1276
GetPrintRegisterFormatFP(VectorFormat vform)1277 Simulator::PrintRegisterFormat Simulator::GetPrintRegisterFormatFP(
1278 VectorFormat vform) {
1279 switch (vform) {
1280 default:
1281 UNREACHABLE();
1282 case kFormat4S:
1283 return kPrintReg4SFP;
1284 case kFormat2S:
1285 return kPrintReg2SFP;
1286 case kFormat2D:
1287 return kPrintReg2DFP;
1288 case kFormat1D:
1289 return kPrintReg1DFP;
1290
1291 case kFormatS:
1292 return kPrintReg1SFP;
1293 case kFormatD:
1294 return kPrintReg1DFP;
1295 }
1296 }
1297
SetBreakpoint(Instruction * location)1298 void Simulator::SetBreakpoint(Instruction* location) {
1299 for (unsigned i = 0; i < breakpoints_.size(); i++) {
1300 if (breakpoints_.at(i).location == location) {
1301 PrintF(stream_, "Existing breakpoint at %p was %s\n",
1302 reinterpret_cast<void*>(location),
1303 breakpoints_.at(i).enabled ? "disabled" : "enabled");
1304 breakpoints_.at(i).enabled = !breakpoints_.at(i).enabled;
1305 return;
1306 }
1307 }
1308 Breakpoint new_breakpoint = {location, true};
1309 breakpoints_.push_back(new_breakpoint);
1310 PrintF(stream_, "Set a breakpoint at %p\n",
1311 reinterpret_cast<void*>(location));
1312 }
1313
ListBreakpoints()1314 void Simulator::ListBreakpoints() {
1315 PrintF(stream_, "Breakpoints:\n");
1316 for (unsigned i = 0; i < breakpoints_.size(); i++) {
1317 PrintF(stream_, "%p : %s\n",
1318 reinterpret_cast<void*>(breakpoints_.at(i).location),
1319 breakpoints_.at(i).enabled ? "enabled" : "disabled");
1320 }
1321 }
1322
CheckBreakpoints()1323 void Simulator::CheckBreakpoints() {
1324 bool hit_a_breakpoint = false;
1325 for (unsigned i = 0; i < breakpoints_.size(); i++) {
1326 if ((breakpoints_.at(i).location == pc_) && breakpoints_.at(i).enabled) {
1327 hit_a_breakpoint = true;
1328 // Disable this breakpoint.
1329 breakpoints_.at(i).enabled = false;
1330 }
1331 }
1332 if (hit_a_breakpoint) {
1333 PrintF(stream_, "Hit and disabled a breakpoint at %p.\n",
1334 reinterpret_cast<void*>(pc_));
1335 Debug();
1336 }
1337 }
1338
CheckBreakNext()1339 void Simulator::CheckBreakNext() {
1340 // If the current instruction is a BL, insert a breakpoint just after it.
1341 if (break_on_next_ && pc_->IsBranchAndLinkToRegister()) {
1342 SetBreakpoint(pc_->following());
1343 break_on_next_ = false;
1344 }
1345 }
1346
PrintInstructionsAt(Instruction * start,uint64_t count)1347 void Simulator::PrintInstructionsAt(Instruction* start, uint64_t count) {
1348 Instruction* end = start->InstructionAtOffset(count * kInstrSize);
1349 for (Instruction* pc = start; pc < end; pc = pc->following()) {
1350 disassembler_decoder_->Decode(pc);
1351 }
1352 }
1353
PrintWrittenRegisters()1354 void Simulator::PrintWrittenRegisters() {
1355 for (unsigned i = 0; i < kNumberOfRegisters; i++) {
1356 if (registers_[i].WrittenSinceLastLog()) PrintRegister(i);
1357 }
1358 }
1359
PrintWrittenVRegisters()1360 void Simulator::PrintWrittenVRegisters() {
1361 for (unsigned i = 0; i < kNumberOfVRegisters; i++) {
1362 // At this point there is no type information, so print as a raw 1Q.
1363 if (vregisters_[i].WrittenSinceLastLog()) PrintVRegister(i, kPrintReg1Q);
1364 }
1365 }
1366
PrintSystemRegisters()1367 void Simulator::PrintSystemRegisters() {
1368 PrintSystemRegister(NZCV);
1369 PrintSystemRegister(FPCR);
1370 }
1371
PrintRegisters()1372 void Simulator::PrintRegisters() {
1373 for (unsigned i = 0; i < kNumberOfRegisters; i++) {
1374 PrintRegister(i);
1375 }
1376 }
1377
PrintVRegisters()1378 void Simulator::PrintVRegisters() {
1379 for (unsigned i = 0; i < kNumberOfVRegisters; i++) {
1380 // At this point there is no type information, so print as a raw 1Q.
1381 PrintVRegister(i, kPrintReg1Q);
1382 }
1383 }
1384
PrintRegister(unsigned code,Reg31Mode r31mode)1385 void Simulator::PrintRegister(unsigned code, Reg31Mode r31mode) {
1386 registers_[code].NotifyRegisterLogged();
1387
1388 // Don't print writes into xzr.
1389 if ((code == kZeroRegCode) && (r31mode == Reg31IsZeroRegister)) {
1390 return;
1391 }
1392
1393 // The template for all x and w registers:
1394 // "# x{code}: 0x{value}"
1395 // "# w{code}: 0x{value}"
1396
1397 PrintRegisterRawHelper(code, r31mode);
1398 fprintf(stream_, "\n");
1399 }
1400
1401 // Print a register's name and raw value.
1402 //
1403 // The `bytes` and `lsb` arguments can be used to limit the bytes that are
1404 // printed. These arguments are intended for use in cases where register hasn't
1405 // actually been updated (such as in PrintVWrite).
1406 //
1407 // No newline is printed. This allows the caller to print more details (such as
1408 // a floating-point interpretation or a memory access annotation).
PrintVRegisterRawHelper(unsigned code,int bytes,int lsb)1409 void Simulator::PrintVRegisterRawHelper(unsigned code, int bytes, int lsb) {
1410 // The template for vector types:
1411 // "# v{code}: 0xFFEEDDCCBBAA99887766554433221100".
1412 // An example with bytes=4 and lsb=8:
1413 // "# v{code}: 0xBBAA9988 ".
1414 fprintf(stream_, "# %s%5s: %s", clr_vreg_name, VRegNameForCode(code),
1415 clr_vreg_value);
1416
1417 int msb = lsb + bytes - 1;
1418 int byte = kQRegSize - 1;
1419
1420 // Print leading padding spaces. (Two spaces per byte.)
1421 while (byte > msb) {
1422 fprintf(stream_, " ");
1423 byte--;
1424 }
1425
1426 // Print the specified part of the value, byte by byte.
1427 qreg_t rawbits = qreg(code);
1428 fprintf(stream_, "0x");
1429 while (byte >= lsb) {
1430 fprintf(stream_, "%02x", rawbits.val[byte]);
1431 byte--;
1432 }
1433
1434 // Print trailing padding spaces.
1435 while (byte >= 0) {
1436 fprintf(stream_, " ");
1437 byte--;
1438 }
1439 fprintf(stream_, "%s", clr_normal);
1440 }
1441
1442 // Print each of the specified lanes of a register as a float or double value.
1443 //
1444 // The `lane_count` and `lslane` arguments can be used to limit the lanes that
1445 // are printed. These arguments are intended for use in cases where register
1446 // hasn't actually been updated (such as in PrintVWrite).
1447 //
1448 // No newline is printed. This allows the caller to print more details (such as
1449 // a memory access annotation).
PrintVRegisterFPHelper(unsigned code,unsigned lane_size_in_bytes,int lane_count,int rightmost_lane)1450 void Simulator::PrintVRegisterFPHelper(unsigned code,
1451 unsigned lane_size_in_bytes,
1452 int lane_count, int rightmost_lane) {
1453 DCHECK((lane_size_in_bytes == kSRegSize) ||
1454 (lane_size_in_bytes == kDRegSize));
1455
1456 unsigned msb = (lane_count + rightmost_lane) * lane_size_in_bytes;
1457 DCHECK_LE(msb, static_cast<unsigned>(kQRegSize));
1458
1459 // For scalar types ((lane_count == 1) && (rightmost_lane == 0)), a register
1460 // name is used:
1461 // " (s{code}: {value})"
1462 // " (d{code}: {value})"
1463 // For vector types, "..." is used to represent one or more omitted lanes.
1464 // " (..., {value}, {value}, ...)"
1465 if ((lane_count == 1) && (rightmost_lane == 0)) {
1466 const char* name = (lane_size_in_bytes == kSRegSize)
1467 ? SRegNameForCode(code)
1468 : DRegNameForCode(code);
1469 fprintf(stream_, " (%s%s: ", clr_vreg_name, name);
1470 } else {
1471 if (msb < (kQRegSize - 1)) {
1472 fprintf(stream_, " (..., ");
1473 } else {
1474 fprintf(stream_, " (");
1475 }
1476 }
1477
1478 // Print the list of values.
1479 const char* separator = "";
1480 int leftmost_lane = rightmost_lane + lane_count - 1;
1481 for (int lane = leftmost_lane; lane >= rightmost_lane; lane--) {
1482 double value = (lane_size_in_bytes == kSRegSize)
1483 ? vreg(code).Get<float>(lane)
1484 : vreg(code).Get<double>(lane);
1485 fprintf(stream_, "%s%s%#g%s", separator, clr_vreg_value, value, clr_normal);
1486 separator = ", ";
1487 }
1488
1489 if (rightmost_lane > 0) {
1490 fprintf(stream_, ", ...");
1491 }
1492 fprintf(stream_, ")");
1493 }
1494
1495 // Print a register's name and raw value.
1496 //
1497 // Only the least-significant `size_in_bytes` bytes of the register are printed,
1498 // but the value is aligned as if the whole register had been printed.
1499 //
1500 // For typical register updates, size_in_bytes should be set to kXRegSize
1501 // -- the default -- so that the whole register is printed. Other values of
1502 // size_in_bytes are intended for use when the register hasn't actually been
1503 // updated (such as in PrintWrite).
1504 //
1505 // No newline is printed. This allows the caller to print more details (such as
1506 // a memory access annotation).
PrintRegisterRawHelper(unsigned code,Reg31Mode r31mode,int size_in_bytes)1507 void Simulator::PrintRegisterRawHelper(unsigned code, Reg31Mode r31mode,
1508 int size_in_bytes) {
1509 // The template for all supported sizes.
1510 // "# x{code}: 0xFFEEDDCCBBAA9988"
1511 // "# w{code}: 0xBBAA9988"
1512 // "# w{code}<15:0>: 0x9988"
1513 // "# w{code}<7:0>: 0x88"
1514 unsigned padding_chars = (kXRegSize - size_in_bytes) * 2;
1515
1516 const char* name = "";
1517 const char* suffix = "";
1518 switch (size_in_bytes) {
1519 case kXRegSize:
1520 name = XRegNameForCode(code, r31mode);
1521 break;
1522 case kWRegSize:
1523 name = WRegNameForCode(code, r31mode);
1524 break;
1525 case 2:
1526 name = WRegNameForCode(code, r31mode);
1527 suffix = "<15:0>";
1528 padding_chars -= strlen(suffix);
1529 break;
1530 case 1:
1531 name = WRegNameForCode(code, r31mode);
1532 suffix = "<7:0>";
1533 padding_chars -= strlen(suffix);
1534 break;
1535 default:
1536 UNREACHABLE();
1537 }
1538 fprintf(stream_, "# %s%5s%s: ", clr_reg_name, name, suffix);
1539
1540 // Print leading padding spaces.
1541 DCHECK_LT(padding_chars, kXRegSize * 2U);
1542 for (unsigned i = 0; i < padding_chars; i++) {
1543 putc(' ', stream_);
1544 }
1545
1546 // Print the specified bits in hexadecimal format.
1547 uint64_t bits = reg<uint64_t>(code, r31mode);
1548 bits &= kXRegMask >> ((kXRegSize - size_in_bytes) * 8);
1549 static_assert(sizeof(bits) == kXRegSize,
1550 "X registers and uint64_t must be the same size.");
1551
1552 int chars = size_in_bytes * 2;
1553 fprintf(stream_, "%s0x%0*" PRIx64 "%s", clr_reg_value, chars, bits,
1554 clr_normal);
1555 }
1556
PrintVRegister(unsigned code,PrintRegisterFormat format)1557 void Simulator::PrintVRegister(unsigned code, PrintRegisterFormat format) {
1558 vregisters_[code].NotifyRegisterLogged();
1559
1560 int lane_size_log2 = format & kPrintRegLaneSizeMask;
1561
1562 int reg_size_log2;
1563 if (format & kPrintRegAsQVector) {
1564 reg_size_log2 = kQRegSizeLog2;
1565 } else if (format & kPrintRegAsDVector) {
1566 reg_size_log2 = kDRegSizeLog2;
1567 } else {
1568 // Scalar types.
1569 reg_size_log2 = lane_size_log2;
1570 }
1571
1572 int lane_count = 1 << (reg_size_log2 - lane_size_log2);
1573 int lane_size = 1 << lane_size_log2;
1574
1575 // The template for vector types:
1576 // "# v{code}: 0x{rawbits} (..., {value}, ...)".
1577 // The template for scalar types:
1578 // "# v{code}: 0x{rawbits} ({reg}:{value})".
1579 // The values in parentheses after the bit representations are floating-point
1580 // interpretations. They are displayed only if the kPrintVRegAsFP bit is set.
1581
1582 PrintVRegisterRawHelper(code);
1583 if (format & kPrintRegAsFP) {
1584 PrintVRegisterFPHelper(code, lane_size, lane_count);
1585 }
1586
1587 fprintf(stream_, "\n");
1588 }
1589
PrintSystemRegister(SystemRegister id)1590 void Simulator::PrintSystemRegister(SystemRegister id) {
1591 switch (id) {
1592 case NZCV:
1593 fprintf(stream_, "# %sNZCV: %sN:%d Z:%d C:%d V:%d%s\n", clr_flag_name,
1594 clr_flag_value, nzcv().N(), nzcv().Z(), nzcv().C(), nzcv().V(),
1595 clr_normal);
1596 break;
1597 case FPCR: {
1598 static const char* rmode[] = {
1599 "0b00 (Round to Nearest)", "0b01 (Round towards Plus Infinity)",
1600 "0b10 (Round towards Minus Infinity)", "0b11 (Round towards Zero)"};
1601 DCHECK(fpcr().RMode() < arraysize(rmode));
1602 fprintf(stream_, "# %sFPCR: %sAHP:%d DN:%d FZ:%d RMode:%s%s\n",
1603 clr_flag_name, clr_flag_value, fpcr().AHP(), fpcr().DN(),
1604 fpcr().FZ(), rmode[fpcr().RMode()], clr_normal);
1605 break;
1606 }
1607 default:
1608 UNREACHABLE();
1609 }
1610 }
1611
PrintRead(uintptr_t address,unsigned reg_code,PrintRegisterFormat format)1612 void Simulator::PrintRead(uintptr_t address, unsigned reg_code,
1613 PrintRegisterFormat format) {
1614 registers_[reg_code].NotifyRegisterLogged();
1615
1616 USE(format);
1617
1618 // The template is "# {reg}: 0x{value} <- {address}".
1619 PrintRegisterRawHelper(reg_code, Reg31IsZeroRegister);
1620 fprintf(stream_, " <- %s0x%016" PRIxPTR "%s\n", clr_memory_address, address,
1621 clr_normal);
1622 }
1623
PrintVRead(uintptr_t address,unsigned reg_code,PrintRegisterFormat format,unsigned lane)1624 void Simulator::PrintVRead(uintptr_t address, unsigned reg_code,
1625 PrintRegisterFormat format, unsigned lane) {
1626 vregisters_[reg_code].NotifyRegisterLogged();
1627
1628 // The template is "# v{code}: 0x{rawbits} <- address".
1629 PrintVRegisterRawHelper(reg_code);
1630 if (format & kPrintRegAsFP) {
1631 PrintVRegisterFPHelper(reg_code, GetPrintRegLaneSizeInBytes(format),
1632 GetPrintRegLaneCount(format), lane);
1633 }
1634 fprintf(stream_, " <- %s0x%016" PRIxPTR "%s\n", clr_memory_address, address,
1635 clr_normal);
1636 }
1637
PrintWrite(uintptr_t address,unsigned reg_code,PrintRegisterFormat format)1638 void Simulator::PrintWrite(uintptr_t address, unsigned reg_code,
1639 PrintRegisterFormat format) {
1640 DCHECK_EQ(GetPrintRegLaneCount(format), 1U);
1641
1642 // The template is "# v{code}: 0x{value} -> {address}". To keep the trace tidy
1643 // and readable, the value is aligned with the values in the register trace.
1644 PrintRegisterRawHelper(reg_code, Reg31IsZeroRegister,
1645 GetPrintRegSizeInBytes(format));
1646 fprintf(stream_, " -> %s0x%016" PRIxPTR "%s\n", clr_memory_address, address,
1647 clr_normal);
1648 }
1649
PrintVWrite(uintptr_t address,unsigned reg_code,PrintRegisterFormat format,unsigned lane)1650 void Simulator::PrintVWrite(uintptr_t address, unsigned reg_code,
1651 PrintRegisterFormat format, unsigned lane) {
1652 // The templates:
1653 // "# v{code}: 0x{rawbits} -> {address}"
1654 // "# v{code}: 0x{rawbits} (..., {value}, ...) -> {address}".
1655 // "# v{code}: 0x{rawbits} ({reg}:{value}) -> {address}"
1656 // Because this trace doesn't represent a change to the source register's
1657 // value, only the relevant part of the value is printed. To keep the trace
1658 // tidy and readable, the raw value is aligned with the other values in the
1659 // register trace.
1660 int lane_count = GetPrintRegLaneCount(format);
1661 int lane_size = GetPrintRegLaneSizeInBytes(format);
1662 int reg_size = GetPrintRegSizeInBytes(format);
1663 PrintVRegisterRawHelper(reg_code, reg_size, lane_size * lane);
1664 if (format & kPrintRegAsFP) {
1665 PrintVRegisterFPHelper(reg_code, lane_size, lane_count, lane);
1666 }
1667 fprintf(stream_, " -> %s0x%016" PRIxPTR "%s\n", clr_memory_address, address,
1668 clr_normal);
1669 }
1670
1671 // Visitors---------------------------------------------------------------------
1672
VisitUnimplemented(Instruction * instr)1673 void Simulator::VisitUnimplemented(Instruction* instr) {
1674 fprintf(stream_, "Unimplemented instruction at %p: 0x%08" PRIx32 "\n",
1675 reinterpret_cast<void*>(instr), instr->InstructionBits());
1676 UNIMPLEMENTED();
1677 }
1678
VisitUnallocated(Instruction * instr)1679 void Simulator::VisitUnallocated(Instruction* instr) {
1680 fprintf(stream_, "Unallocated instruction at %p: 0x%08" PRIx32 "\n",
1681 reinterpret_cast<void*>(instr), instr->InstructionBits());
1682 UNIMPLEMENTED();
1683 }
1684
VisitPCRelAddressing(Instruction * instr)1685 void Simulator::VisitPCRelAddressing(Instruction* instr) {
1686 switch (instr->Mask(PCRelAddressingMask)) {
1687 case ADR:
1688 set_reg(instr->Rd(), instr->ImmPCOffsetTarget());
1689 break;
1690 case ADRP: // Not implemented in the assembler.
1691 UNIMPLEMENTED();
1692 default:
1693 UNREACHABLE();
1694 }
1695 }
1696
VisitUnconditionalBranch(Instruction * instr)1697 void Simulator::VisitUnconditionalBranch(Instruction* instr) {
1698 switch (instr->Mask(UnconditionalBranchMask)) {
1699 case BL:
1700 set_lr(instr->following());
1701 V8_FALLTHROUGH;
1702 case B:
1703 set_pc(instr->ImmPCOffsetTarget());
1704 break;
1705 default:
1706 UNREACHABLE();
1707 }
1708 }
1709
VisitConditionalBranch(Instruction * instr)1710 void Simulator::VisitConditionalBranch(Instruction* instr) {
1711 DCHECK(instr->Mask(ConditionalBranchMask) == B_cond);
1712 if (ConditionPassed(static_cast<Condition>(instr->ConditionBranch()))) {
1713 set_pc(instr->ImmPCOffsetTarget());
1714 }
1715 }
1716
GetBTypeFromInstruction(const Instruction * instr) const1717 Simulator::BType Simulator::GetBTypeFromInstruction(
1718 const Instruction* instr) const {
1719 switch (instr->Mask(UnconditionalBranchToRegisterMask)) {
1720 case BLR:
1721 return BranchAndLink;
1722 case BR:
1723 if (!PcIsInGuardedPage() || (instr->Rn() == 16) || (instr->Rn() == 17)) {
1724 return BranchFromUnguardedOrToIP;
1725 }
1726 return BranchFromGuardedNotToIP;
1727 }
1728 return DefaultBType;
1729 }
1730
VisitUnconditionalBranchToRegister(Instruction * instr)1731 void Simulator::VisitUnconditionalBranchToRegister(Instruction* instr) {
1732 Instruction* target = reg<Instruction*>(instr->Rn());
1733 switch (instr->Mask(UnconditionalBranchToRegisterMask)) {
1734 case BLR: {
1735 set_lr(instr->following());
1736 if (instr->Rn() == 31) {
1737 // BLR XZR is used as a guard for the constant pool. We should never hit
1738 // this, but if we do trap to allow debugging.
1739 Debug();
1740 }
1741 V8_FALLTHROUGH;
1742 }
1743 case BR:
1744 case RET:
1745 set_pc(target);
1746 break;
1747 default:
1748 UNIMPLEMENTED();
1749 }
1750 set_btype(GetBTypeFromInstruction(instr));
1751 }
1752
VisitTestBranch(Instruction * instr)1753 void Simulator::VisitTestBranch(Instruction* instr) {
1754 unsigned bit_pos =
1755 (instr->ImmTestBranchBit5() << 5) | instr->ImmTestBranchBit40();
1756 bool take_branch = ((xreg(instr->Rt()) & (1ULL << bit_pos)) == 0);
1757 switch (instr->Mask(TestBranchMask)) {
1758 case TBZ:
1759 break;
1760 case TBNZ:
1761 take_branch = !take_branch;
1762 break;
1763 default:
1764 UNIMPLEMENTED();
1765 }
1766 if (take_branch) {
1767 set_pc(instr->ImmPCOffsetTarget());
1768 }
1769 }
1770
VisitCompareBranch(Instruction * instr)1771 void Simulator::VisitCompareBranch(Instruction* instr) {
1772 unsigned rt = instr->Rt();
1773 bool take_branch = false;
1774 switch (instr->Mask(CompareBranchMask)) {
1775 case CBZ_w:
1776 take_branch = (wreg(rt) == 0);
1777 break;
1778 case CBZ_x:
1779 take_branch = (xreg(rt) == 0);
1780 break;
1781 case CBNZ_w:
1782 take_branch = (wreg(rt) != 0);
1783 break;
1784 case CBNZ_x:
1785 take_branch = (xreg(rt) != 0);
1786 break;
1787 default:
1788 UNIMPLEMENTED();
1789 }
1790 if (take_branch) {
1791 set_pc(instr->ImmPCOffsetTarget());
1792 }
1793 }
1794
1795 template <typename T>
AddSubHelper(Instruction * instr,T op2)1796 void Simulator::AddSubHelper(Instruction* instr, T op2) {
1797 // Use unsigned types to avoid implementation-defined overflow behaviour.
1798 static_assert(std::is_unsigned<T>::value, "operands must be unsigned");
1799
1800 bool set_flags = instr->FlagsUpdate();
1801 T new_val = 0;
1802 Instr operation = instr->Mask(AddSubOpMask);
1803
1804 switch (operation) {
1805 case ADD:
1806 case ADDS: {
1807 new_val =
1808 AddWithCarry<T>(set_flags, reg<T>(instr->Rn(), instr->RnMode()), op2);
1809 break;
1810 }
1811 case SUB:
1812 case SUBS: {
1813 new_val = AddWithCarry<T>(set_flags, reg<T>(instr->Rn(), instr->RnMode()),
1814 ~op2, 1);
1815 break;
1816 }
1817 default:
1818 UNREACHABLE();
1819 }
1820
1821 set_reg<T>(instr->Rd(), new_val, instr->RdMode());
1822 }
1823
VisitAddSubShifted(Instruction * instr)1824 void Simulator::VisitAddSubShifted(Instruction* instr) {
1825 Shift shift_type = static_cast<Shift>(instr->ShiftDP());
1826 unsigned shift_amount = instr->ImmDPShift();
1827
1828 if (instr->SixtyFourBits()) {
1829 uint64_t op2 = ShiftOperand(xreg(instr->Rm()), shift_type, shift_amount);
1830 AddSubHelper(instr, op2);
1831 } else {
1832 uint32_t op2 = ShiftOperand(wreg(instr->Rm()), shift_type, shift_amount);
1833 AddSubHelper(instr, op2);
1834 }
1835 }
1836
VisitAddSubImmediate(Instruction * instr)1837 void Simulator::VisitAddSubImmediate(Instruction* instr) {
1838 int64_t op2 = instr->ImmAddSub() << ((instr->ShiftAddSub() == 1) ? 12 : 0);
1839 if (instr->SixtyFourBits()) {
1840 AddSubHelper(instr, static_cast<uint64_t>(op2));
1841 } else {
1842 AddSubHelper(instr, static_cast<uint32_t>(op2));
1843 }
1844 }
1845
VisitAddSubExtended(Instruction * instr)1846 void Simulator::VisitAddSubExtended(Instruction* instr) {
1847 Extend ext = static_cast<Extend>(instr->ExtendMode());
1848 unsigned left_shift = instr->ImmExtendShift();
1849 if (instr->SixtyFourBits()) {
1850 uint64_t op2 = ExtendValue(xreg(instr->Rm()), ext, left_shift);
1851 AddSubHelper(instr, op2);
1852 } else {
1853 uint32_t op2 = ExtendValue(wreg(instr->Rm()), ext, left_shift);
1854 AddSubHelper(instr, op2);
1855 }
1856 }
1857
VisitAddSubWithCarry(Instruction * instr)1858 void Simulator::VisitAddSubWithCarry(Instruction* instr) {
1859 if (instr->SixtyFourBits()) {
1860 AddSubWithCarry<uint64_t>(instr);
1861 } else {
1862 AddSubWithCarry<uint32_t>(instr);
1863 }
1864 }
1865
VisitLogicalShifted(Instruction * instr)1866 void Simulator::VisitLogicalShifted(Instruction* instr) {
1867 Shift shift_type = static_cast<Shift>(instr->ShiftDP());
1868 unsigned shift_amount = instr->ImmDPShift();
1869
1870 if (instr->SixtyFourBits()) {
1871 uint64_t op2 = ShiftOperand(xreg(instr->Rm()), shift_type, shift_amount);
1872 op2 = (instr->Mask(NOT) == NOT) ? ~op2 : op2;
1873 LogicalHelper(instr, op2);
1874 } else {
1875 uint32_t op2 = ShiftOperand(wreg(instr->Rm()), shift_type, shift_amount);
1876 op2 = (instr->Mask(NOT) == NOT) ? ~op2 : op2;
1877 LogicalHelper(instr, op2);
1878 }
1879 }
1880
VisitLogicalImmediate(Instruction * instr)1881 void Simulator::VisitLogicalImmediate(Instruction* instr) {
1882 if (instr->SixtyFourBits()) {
1883 LogicalHelper(instr, static_cast<uint64_t>(instr->ImmLogical()));
1884 } else {
1885 LogicalHelper(instr, static_cast<uint32_t>(instr->ImmLogical()));
1886 }
1887 }
1888
1889 template <typename T>
LogicalHelper(Instruction * instr,T op2)1890 void Simulator::LogicalHelper(Instruction* instr, T op2) {
1891 T op1 = reg<T>(instr->Rn());
1892 T result = 0;
1893 bool update_flags = false;
1894
1895 // Switch on the logical operation, stripping out the NOT bit, as it has a
1896 // different meaning for logical immediate instructions.
1897 switch (instr->Mask(LogicalOpMask & ~NOT)) {
1898 case ANDS:
1899 update_flags = true;
1900 V8_FALLTHROUGH;
1901 case AND:
1902 result = op1 & op2;
1903 break;
1904 case ORR:
1905 result = op1 | op2;
1906 break;
1907 case EOR:
1908 result = op1 ^ op2;
1909 break;
1910 default:
1911 UNIMPLEMENTED();
1912 }
1913
1914 if (update_flags) {
1915 nzcv().SetN(CalcNFlag(result));
1916 nzcv().SetZ(CalcZFlag(result));
1917 nzcv().SetC(0);
1918 nzcv().SetV(0);
1919 LogSystemRegister(NZCV);
1920 }
1921
1922 set_reg<T>(instr->Rd(), result, instr->RdMode());
1923 }
1924
VisitConditionalCompareRegister(Instruction * instr)1925 void Simulator::VisitConditionalCompareRegister(Instruction* instr) {
1926 if (instr->SixtyFourBits()) {
1927 ConditionalCompareHelper(instr, static_cast<uint64_t>(xreg(instr->Rm())));
1928 } else {
1929 ConditionalCompareHelper(instr, static_cast<uint32_t>(wreg(instr->Rm())));
1930 }
1931 }
1932
VisitConditionalCompareImmediate(Instruction * instr)1933 void Simulator::VisitConditionalCompareImmediate(Instruction* instr) {
1934 if (instr->SixtyFourBits()) {
1935 ConditionalCompareHelper(instr, static_cast<uint64_t>(instr->ImmCondCmp()));
1936 } else {
1937 ConditionalCompareHelper(instr, static_cast<uint32_t>(instr->ImmCondCmp()));
1938 }
1939 }
1940
1941 template <typename T>
ConditionalCompareHelper(Instruction * instr,T op2)1942 void Simulator::ConditionalCompareHelper(Instruction* instr, T op2) {
1943 // Use unsigned types to avoid implementation-defined overflow behaviour.
1944 static_assert(std::is_unsigned<T>::value, "operands must be unsigned");
1945
1946 T op1 = reg<T>(instr->Rn());
1947
1948 if (ConditionPassed(static_cast<Condition>(instr->Condition()))) {
1949 // If the condition passes, set the status flags to the result of comparing
1950 // the operands.
1951 if (instr->Mask(ConditionalCompareMask) == CCMP) {
1952 AddWithCarry<T>(true, op1, ~op2, 1);
1953 } else {
1954 DCHECK(instr->Mask(ConditionalCompareMask) == CCMN);
1955 AddWithCarry<T>(true, op1, op2, 0);
1956 }
1957 } else {
1958 // If the condition fails, set the status flags to the nzcv immediate.
1959 nzcv().SetFlags(instr->Nzcv());
1960 LogSystemRegister(NZCV);
1961 }
1962 }
1963
VisitLoadStoreUnsignedOffset(Instruction * instr)1964 void Simulator::VisitLoadStoreUnsignedOffset(Instruction* instr) {
1965 int offset = instr->ImmLSUnsigned() << instr->SizeLS();
1966 LoadStoreHelper(instr, offset, Offset);
1967 }
1968
VisitLoadStoreUnscaledOffset(Instruction * instr)1969 void Simulator::VisitLoadStoreUnscaledOffset(Instruction* instr) {
1970 LoadStoreHelper(instr, instr->ImmLS(), Offset);
1971 }
1972
VisitLoadStorePreIndex(Instruction * instr)1973 void Simulator::VisitLoadStorePreIndex(Instruction* instr) {
1974 LoadStoreHelper(instr, instr->ImmLS(), PreIndex);
1975 }
1976
VisitLoadStorePostIndex(Instruction * instr)1977 void Simulator::VisitLoadStorePostIndex(Instruction* instr) {
1978 LoadStoreHelper(instr, instr->ImmLS(), PostIndex);
1979 }
1980
VisitLoadStoreRegisterOffset(Instruction * instr)1981 void Simulator::VisitLoadStoreRegisterOffset(Instruction* instr) {
1982 Extend ext = static_cast<Extend>(instr->ExtendMode());
1983 DCHECK((ext == UXTW) || (ext == UXTX) || (ext == SXTW) || (ext == SXTX));
1984 unsigned shift_amount = instr->ImmShiftLS() * instr->SizeLS();
1985
1986 int64_t offset = ExtendValue(xreg(instr->Rm()), ext, shift_amount);
1987 LoadStoreHelper(instr, offset, Offset);
1988 }
1989
LoadStoreHelper(Instruction * instr,int64_t offset,AddrMode addrmode)1990 void Simulator::LoadStoreHelper(Instruction* instr, int64_t offset,
1991 AddrMode addrmode) {
1992 unsigned srcdst = instr->Rt();
1993 unsigned addr_reg = instr->Rn();
1994 uintptr_t address = LoadStoreAddress(addr_reg, offset, addrmode);
1995 uintptr_t stack = 0;
1996
1997 unsigned access_size = 1 << instr->SizeLS();
1998 // First, check whether the memory is accessible (for wasm trap handling).
1999 if (!ProbeMemory(address, access_size)) return;
2000
2001 {
2002 base::MutexGuard lock_guard(&GlobalMonitor::Get()->mutex);
2003 if (instr->IsLoad()) {
2004 local_monitor_.NotifyLoad();
2005 } else {
2006 local_monitor_.NotifyStore();
2007 GlobalMonitor::Get()->NotifyStore_Locked(&global_monitor_processor_);
2008 }
2009 }
2010
2011 // Handle the writeback for stores before the store. On a CPU the writeback
2012 // and the store are atomic, but when running on the simulator it is possible
2013 // to be interrupted in between. The simulator is not thread safe and V8 does
2014 // not require it to be to run JavaScript therefore the profiler may sample
2015 // the "simulated" CPU in the middle of load/store with writeback. The code
2016 // below ensures that push operations are safe even when interrupted: the
2017 // stack pointer will be decremented before adding an element to the stack.
2018 if (instr->IsStore()) {
2019 LoadStoreWriteBack(addr_reg, offset, addrmode);
2020
2021 // For store the address post writeback is used to check access below the
2022 // stack.
2023 stack = sp();
2024 }
2025
2026 LoadStoreOp op = static_cast<LoadStoreOp>(instr->Mask(LoadStoreMask));
2027 switch (op) {
2028 // Use _no_log variants to suppress the register trace (LOG_REGS,
2029 // LOG_VREGS). We will print a more detailed log.
2030 case LDRB_w:
2031 set_wreg_no_log(srcdst, MemoryRead<uint8_t>(address));
2032 break;
2033 case LDRH_w:
2034 set_wreg_no_log(srcdst, MemoryRead<uint16_t>(address));
2035 break;
2036 case LDR_w:
2037 set_wreg_no_log(srcdst, MemoryRead<uint32_t>(address));
2038 break;
2039 case LDR_x:
2040 set_xreg_no_log(srcdst, MemoryRead<uint64_t>(address));
2041 break;
2042 case LDRSB_w:
2043 set_wreg_no_log(srcdst, MemoryRead<int8_t>(address));
2044 break;
2045 case LDRSH_w:
2046 set_wreg_no_log(srcdst, MemoryRead<int16_t>(address));
2047 break;
2048 case LDRSB_x:
2049 set_xreg_no_log(srcdst, MemoryRead<int8_t>(address));
2050 break;
2051 case LDRSH_x:
2052 set_xreg_no_log(srcdst, MemoryRead<int16_t>(address));
2053 break;
2054 case LDRSW_x:
2055 set_xreg_no_log(srcdst, MemoryRead<int32_t>(address));
2056 break;
2057 case LDR_b:
2058 set_breg_no_log(srcdst, MemoryRead<uint8_t>(address));
2059 break;
2060 case LDR_h:
2061 set_hreg_no_log(srcdst, MemoryRead<uint16_t>(address));
2062 break;
2063 case LDR_s:
2064 set_sreg_no_log(srcdst, MemoryRead<float>(address));
2065 break;
2066 case LDR_d:
2067 set_dreg_no_log(srcdst, MemoryRead<double>(address));
2068 break;
2069 case LDR_q:
2070 set_qreg_no_log(srcdst, MemoryRead<qreg_t>(address));
2071 break;
2072
2073 case STRB_w:
2074 MemoryWrite<uint8_t>(address, wreg(srcdst));
2075 break;
2076 case STRH_w:
2077 MemoryWrite<uint16_t>(address, wreg(srcdst));
2078 break;
2079 case STR_w:
2080 MemoryWrite<uint32_t>(address, wreg(srcdst));
2081 break;
2082 case STR_x:
2083 MemoryWrite<uint64_t>(address, xreg(srcdst));
2084 break;
2085 case STR_b:
2086 MemoryWrite<uint8_t>(address, breg(srcdst));
2087 break;
2088 case STR_h:
2089 MemoryWrite<uint16_t>(address, hreg(srcdst));
2090 break;
2091 case STR_s:
2092 MemoryWrite<float>(address, sreg(srcdst));
2093 break;
2094 case STR_d:
2095 MemoryWrite<double>(address, dreg(srcdst));
2096 break;
2097 case STR_q:
2098 MemoryWrite<qreg_t>(address, qreg(srcdst));
2099 break;
2100
2101 default:
2102 UNIMPLEMENTED();
2103 }
2104
2105 // Print a detailed trace (including the memory address) instead of the basic
2106 // register:value trace generated by set_*reg().
2107 if (instr->IsLoad()) {
2108 if ((op == LDR_s) || (op == LDR_d)) {
2109 LogVRead(address, srcdst, GetPrintRegisterFormatForSizeFP(access_size));
2110 } else if ((op == LDR_b) || (op == LDR_h) || (op == LDR_q)) {
2111 LogVRead(address, srcdst, GetPrintRegisterFormatForSize(access_size));
2112 } else {
2113 LogRead(address, srcdst, GetPrintRegisterFormatForSize(access_size));
2114 }
2115 } else {
2116 if ((op == STR_s) || (op == STR_d)) {
2117 LogVWrite(address, srcdst, GetPrintRegisterFormatForSizeFP(access_size));
2118 } else if ((op == STR_b) || (op == STR_h) || (op == STR_q)) {
2119 LogVWrite(address, srcdst, GetPrintRegisterFormatForSize(access_size));
2120 } else {
2121 LogWrite(address, srcdst, GetPrintRegisterFormatForSize(access_size));
2122 }
2123 }
2124
2125 // Handle the writeback for loads after the load to ensure safe pop
2126 // operation even when interrupted in the middle of it. The stack pointer
2127 // is only updated after the load so pop(fp) will never break the invariant
2128 // sp <= fp expected while walking the stack in the sampler.
2129 if (instr->IsLoad()) {
2130 // For loads the address pre writeback is used to check access below the
2131 // stack.
2132 stack = sp();
2133
2134 LoadStoreWriteBack(addr_reg, offset, addrmode);
2135 }
2136
2137 // Accesses below the stack pointer (but above the platform stack limit) are
2138 // not allowed in the ABI.
2139 CheckMemoryAccess(address, stack);
2140 }
2141
VisitLoadStorePairOffset(Instruction * instr)2142 void Simulator::VisitLoadStorePairOffset(Instruction* instr) {
2143 LoadStorePairHelper(instr, Offset);
2144 }
2145
VisitLoadStorePairPreIndex(Instruction * instr)2146 void Simulator::VisitLoadStorePairPreIndex(Instruction* instr) {
2147 LoadStorePairHelper(instr, PreIndex);
2148 }
2149
VisitLoadStorePairPostIndex(Instruction * instr)2150 void Simulator::VisitLoadStorePairPostIndex(Instruction* instr) {
2151 LoadStorePairHelper(instr, PostIndex);
2152 }
2153
LoadStorePairHelper(Instruction * instr,AddrMode addrmode)2154 void Simulator::LoadStorePairHelper(Instruction* instr, AddrMode addrmode) {
2155 unsigned rt = instr->Rt();
2156 unsigned rt2 = instr->Rt2();
2157 unsigned addr_reg = instr->Rn();
2158 size_t access_size = 1ULL << instr->SizeLSPair();
2159 int64_t offset = instr->ImmLSPair() * access_size;
2160 uintptr_t address = LoadStoreAddress(addr_reg, offset, addrmode);
2161 uintptr_t address2 = address + access_size;
2162 uintptr_t stack = 0;
2163
2164 {
2165 base::MutexGuard lock_guard(&GlobalMonitor::Get()->mutex);
2166 if (instr->IsLoad()) {
2167 local_monitor_.NotifyLoad();
2168 } else {
2169 local_monitor_.NotifyStore();
2170 GlobalMonitor::Get()->NotifyStore_Locked(&global_monitor_processor_);
2171 }
2172 }
2173
2174 // Handle the writeback for stores before the store. On a CPU the writeback
2175 // and the store are atomic, but when running on the simulator it is possible
2176 // to be interrupted in between. The simulator is not thread safe and V8 does
2177 // not require it to be to run JavaScript therefore the profiler may sample
2178 // the "simulated" CPU in the middle of load/store with writeback. The code
2179 // below ensures that push operations are safe even when interrupted: the
2180 // stack pointer will be decremented before adding an element to the stack.
2181 if (instr->IsStore()) {
2182 LoadStoreWriteBack(addr_reg, offset, addrmode);
2183
2184 // For store the address post writeback is used to check access below the
2185 // stack.
2186 stack = sp();
2187 }
2188
2189 LoadStorePairOp op =
2190 static_cast<LoadStorePairOp>(instr->Mask(LoadStorePairMask));
2191
2192 // 'rt' and 'rt2' can only be aliased for stores.
2193 DCHECK(((op & LoadStorePairLBit) == 0) || (rt != rt2));
2194
2195 switch (op) {
2196 // Use _no_log variants to suppress the register trace (LOG_REGS,
2197 // LOG_VREGS). We will print a more detailed log.
2198 case LDP_w: {
2199 DCHECK_EQ(access_size, static_cast<unsigned>(kWRegSize));
2200 set_wreg_no_log(rt, MemoryRead<uint32_t>(address));
2201 set_wreg_no_log(rt2, MemoryRead<uint32_t>(address2));
2202 break;
2203 }
2204 case LDP_s: {
2205 DCHECK_EQ(access_size, static_cast<unsigned>(kSRegSize));
2206 set_sreg_no_log(rt, MemoryRead<float>(address));
2207 set_sreg_no_log(rt2, MemoryRead<float>(address2));
2208 break;
2209 }
2210 case LDP_x: {
2211 DCHECK_EQ(access_size, static_cast<unsigned>(kXRegSize));
2212 set_xreg_no_log(rt, MemoryRead<uint64_t>(address));
2213 set_xreg_no_log(rt2, MemoryRead<uint64_t>(address2));
2214 break;
2215 }
2216 case LDP_d: {
2217 DCHECK_EQ(access_size, static_cast<unsigned>(kDRegSize));
2218 set_dreg_no_log(rt, MemoryRead<double>(address));
2219 set_dreg_no_log(rt2, MemoryRead<double>(address2));
2220 break;
2221 }
2222 case LDP_q: {
2223 DCHECK_EQ(access_size, static_cast<unsigned>(kQRegSize));
2224 set_qreg(rt, MemoryRead<qreg_t>(address), NoRegLog);
2225 set_qreg(rt2, MemoryRead<qreg_t>(address2), NoRegLog);
2226 break;
2227 }
2228 case LDPSW_x: {
2229 DCHECK_EQ(access_size, static_cast<unsigned>(kWRegSize));
2230 set_xreg_no_log(rt, MemoryRead<int32_t>(address));
2231 set_xreg_no_log(rt2, MemoryRead<int32_t>(address2));
2232 break;
2233 }
2234 case STP_w: {
2235 DCHECK_EQ(access_size, static_cast<unsigned>(kWRegSize));
2236 MemoryWrite<uint32_t>(address, wreg(rt));
2237 MemoryWrite<uint32_t>(address2, wreg(rt2));
2238 break;
2239 }
2240 case STP_s: {
2241 DCHECK_EQ(access_size, static_cast<unsigned>(kSRegSize));
2242 MemoryWrite<float>(address, sreg(rt));
2243 MemoryWrite<float>(address2, sreg(rt2));
2244 break;
2245 }
2246 case STP_x: {
2247 DCHECK_EQ(access_size, static_cast<unsigned>(kXRegSize));
2248 MemoryWrite<uint64_t>(address, xreg(rt));
2249 MemoryWrite<uint64_t>(address2, xreg(rt2));
2250 break;
2251 }
2252 case STP_d: {
2253 DCHECK_EQ(access_size, static_cast<unsigned>(kDRegSize));
2254 MemoryWrite<double>(address, dreg(rt));
2255 MemoryWrite<double>(address2, dreg(rt2));
2256 break;
2257 }
2258 case STP_q: {
2259 DCHECK_EQ(access_size, static_cast<unsigned>(kQRegSize));
2260 MemoryWrite<qreg_t>(address, qreg(rt));
2261 MemoryWrite<qreg_t>(address2, qreg(rt2));
2262 break;
2263 }
2264 default:
2265 UNREACHABLE();
2266 }
2267
2268 // Print a detailed trace (including the memory address) instead of the basic
2269 // register:value trace generated by set_*reg().
2270 if (instr->IsLoad()) {
2271 if ((op == LDP_s) || (op == LDP_d)) {
2272 LogVRead(address, rt, GetPrintRegisterFormatForSizeFP(access_size));
2273 LogVRead(address2, rt2, GetPrintRegisterFormatForSizeFP(access_size));
2274 } else if (op == LDP_q) {
2275 LogVRead(address, rt, GetPrintRegisterFormatForSize(access_size));
2276 LogVRead(address2, rt2, GetPrintRegisterFormatForSize(access_size));
2277 } else {
2278 LogRead(address, rt, GetPrintRegisterFormatForSize(access_size));
2279 LogRead(address2, rt2, GetPrintRegisterFormatForSize(access_size));
2280 }
2281 } else {
2282 if ((op == STP_s) || (op == STP_d)) {
2283 LogVWrite(address, rt, GetPrintRegisterFormatForSizeFP(access_size));
2284 LogVWrite(address2, rt2, GetPrintRegisterFormatForSizeFP(access_size));
2285 } else if (op == STP_q) {
2286 LogVWrite(address, rt, GetPrintRegisterFormatForSize(access_size));
2287 LogVWrite(address2, rt2, GetPrintRegisterFormatForSize(access_size));
2288 } else {
2289 LogWrite(address, rt, GetPrintRegisterFormatForSize(access_size));
2290 LogWrite(address2, rt2, GetPrintRegisterFormatForSize(access_size));
2291 }
2292 }
2293
2294 // Handle the writeback for loads after the load to ensure safe pop
2295 // operation even when interrupted in the middle of it. The stack pointer
2296 // is only updated after the load so pop(fp) will never break the invariant
2297 // sp <= fp expected while walking the stack in the sampler.
2298 if (instr->IsLoad()) {
2299 // For loads the address pre writeback is used to check access below the
2300 // stack.
2301 stack = sp();
2302
2303 LoadStoreWriteBack(addr_reg, offset, addrmode);
2304 }
2305
2306 // Accesses below the stack pointer (but above the platform stack limit) are
2307 // not allowed in the ABI.
2308 CheckMemoryAccess(address, stack);
2309 }
2310
VisitLoadLiteral(Instruction * instr)2311 void Simulator::VisitLoadLiteral(Instruction* instr) {
2312 uintptr_t address = instr->LiteralAddress();
2313 unsigned rt = instr->Rt();
2314
2315 {
2316 base::MutexGuard lock_guard(&GlobalMonitor::Get()->mutex);
2317 local_monitor_.NotifyLoad();
2318 }
2319
2320 switch (instr->Mask(LoadLiteralMask)) {
2321 // Use _no_log variants to suppress the register trace (LOG_REGS,
2322 // LOG_VREGS), then print a more detailed log.
2323 case LDR_w_lit:
2324 set_wreg_no_log(rt, MemoryRead<uint32_t>(address));
2325 LogRead(address, rt, kPrintWReg);
2326 break;
2327 case LDR_x_lit:
2328 set_xreg_no_log(rt, MemoryRead<uint64_t>(address));
2329 LogRead(address, rt, kPrintXReg);
2330 break;
2331 case LDR_s_lit:
2332 set_sreg_no_log(rt, MemoryRead<float>(address));
2333 LogVRead(address, rt, kPrintSReg);
2334 break;
2335 case LDR_d_lit:
2336 set_dreg_no_log(rt, MemoryRead<double>(address));
2337 LogVRead(address, rt, kPrintDReg);
2338 break;
2339 default:
2340 UNREACHABLE();
2341 }
2342 }
2343
LoadStoreAddress(unsigned addr_reg,int64_t offset,AddrMode addrmode)2344 uintptr_t Simulator::LoadStoreAddress(unsigned addr_reg, int64_t offset,
2345 AddrMode addrmode) {
2346 const unsigned kSPRegCode = kSPRegInternalCode & kRegCodeMask;
2347 uint64_t address = xreg(addr_reg, Reg31IsStackPointer);
2348 if ((addr_reg == kSPRegCode) && ((address % 16) != 0)) {
2349 // When the base register is SP the stack pointer is required to be
2350 // quadword aligned prior to the address calculation and write-backs.
2351 // Misalignment will cause a stack alignment fault.
2352 FATAL("ALIGNMENT EXCEPTION");
2353 }
2354
2355 if ((addrmode == Offset) || (addrmode == PreIndex)) {
2356 address += offset;
2357 }
2358
2359 return address;
2360 }
2361
LoadStoreWriteBack(unsigned addr_reg,int64_t offset,AddrMode addrmode)2362 void Simulator::LoadStoreWriteBack(unsigned addr_reg, int64_t offset,
2363 AddrMode addrmode) {
2364 if ((addrmode == PreIndex) || (addrmode == PostIndex)) {
2365 DCHECK_NE(offset, 0);
2366 uint64_t address = xreg(addr_reg, Reg31IsStackPointer);
2367 set_reg(addr_reg, address + offset, Reg31IsStackPointer);
2368 }
2369 }
2370
get_transaction_size(unsigned size)2371 Simulator::TransactionSize Simulator::get_transaction_size(unsigned size) {
2372 switch (size) {
2373 case 0:
2374 return TransactionSize::None;
2375 case 1:
2376 return TransactionSize::Byte;
2377 case 2:
2378 return TransactionSize::HalfWord;
2379 case 4:
2380 return TransactionSize::Word;
2381 case 8:
2382 return TransactionSize::DoubleWord;
2383 default:
2384 UNREACHABLE();
2385 }
2386 }
2387
VisitLoadStoreAcquireRelease(Instruction * instr)2388 void Simulator::VisitLoadStoreAcquireRelease(Instruction* instr) {
2389 unsigned rt = instr->Rt();
2390 unsigned rn = instr->Rn();
2391 LoadStoreAcquireReleaseOp op = static_cast<LoadStoreAcquireReleaseOp>(
2392 instr->Mask(LoadStoreAcquireReleaseMask));
2393 int32_t is_acquire_release = instr->LoadStoreXAcquireRelease();
2394 int32_t is_exclusive = (instr->LoadStoreXNotExclusive() == 0);
2395 int32_t is_load = instr->LoadStoreXLoad();
2396 int32_t is_pair = instr->LoadStoreXPair();
2397 USE(is_acquire_release);
2398 USE(is_pair);
2399 DCHECK_NE(is_acquire_release, 0); // Non-acquire/release unimplemented.
2400 DCHECK_EQ(is_pair, 0); // Pair unimplemented.
2401 unsigned access_size = 1 << instr->LoadStoreXSizeLog2();
2402 uintptr_t address = LoadStoreAddress(rn, 0, AddrMode::Offset);
2403 DCHECK_EQ(address % access_size, 0);
2404 base::MutexGuard lock_guard(&GlobalMonitor::Get()->mutex);
2405 if (is_load != 0) {
2406 if (is_exclusive) {
2407 local_monitor_.NotifyLoadExcl(address, get_transaction_size(access_size));
2408 GlobalMonitor::Get()->NotifyLoadExcl_Locked(address,
2409 &global_monitor_processor_);
2410 } else {
2411 local_monitor_.NotifyLoad();
2412 }
2413 switch (op) {
2414 case LDAR_b:
2415 case LDAXR_b:
2416 set_wreg_no_log(rt, MemoryRead<uint8_t>(address));
2417 break;
2418 case LDAR_h:
2419 case LDAXR_h:
2420 set_wreg_no_log(rt, MemoryRead<uint16_t>(address));
2421 break;
2422 case LDAR_w:
2423 case LDAXR_w:
2424 set_wreg_no_log(rt, MemoryRead<uint32_t>(address));
2425 break;
2426 case LDAR_x:
2427 case LDAXR_x:
2428 set_xreg_no_log(rt, MemoryRead<uint64_t>(address));
2429 break;
2430 default:
2431 UNIMPLEMENTED();
2432 }
2433 LogRead(address, rt, GetPrintRegisterFormatForSize(access_size));
2434 } else {
2435 if (is_exclusive) {
2436 unsigned rs = instr->Rs();
2437 DCHECK_NE(rs, rt);
2438 DCHECK_NE(rs, rn);
2439 if (local_monitor_.NotifyStoreExcl(address,
2440 get_transaction_size(access_size)) &&
2441 GlobalMonitor::Get()->NotifyStoreExcl_Locked(
2442 address, &global_monitor_processor_)) {
2443 switch (op) {
2444 case STLXR_b:
2445 MemoryWrite<uint8_t>(address, wreg(rt));
2446 break;
2447 case STLXR_h:
2448 MemoryWrite<uint16_t>(address, wreg(rt));
2449 break;
2450 case STLXR_w:
2451 MemoryWrite<uint32_t>(address, wreg(rt));
2452 break;
2453 case STLXR_x:
2454 MemoryWrite<uint64_t>(address, xreg(rt));
2455 break;
2456 default:
2457 UNIMPLEMENTED();
2458 }
2459 LogWrite(address, rt, GetPrintRegisterFormatForSize(access_size));
2460 set_wreg(rs, 0);
2461 } else {
2462 set_wreg(rs, 1);
2463 }
2464 } else {
2465 local_monitor_.NotifyStore();
2466 GlobalMonitor::Get()->NotifyStore_Locked(&global_monitor_processor_);
2467 switch (op) {
2468 case STLR_b:
2469 MemoryWrite<uint8_t>(address, wreg(rt));
2470 break;
2471 case STLR_h:
2472 MemoryWrite<uint16_t>(address, wreg(rt));
2473 break;
2474 case STLR_w:
2475 MemoryWrite<uint32_t>(address, wreg(rt));
2476 break;
2477 case STLR_x:
2478 MemoryWrite<uint64_t>(address, xreg(rt));
2479 break;
2480 default:
2481 UNIMPLEMENTED();
2482 }
2483 }
2484 }
2485 }
2486
CheckMemoryAccess(uintptr_t address,uintptr_t stack)2487 void Simulator::CheckMemoryAccess(uintptr_t address, uintptr_t stack) {
2488 if ((address >= stack_limit_) && (address < stack)) {
2489 fprintf(stream_, "ACCESS BELOW STACK POINTER:\n");
2490 fprintf(stream_, " sp is here: 0x%016" PRIx64 "\n",
2491 static_cast<uint64_t>(stack));
2492 fprintf(stream_, " access was here: 0x%016" PRIx64 "\n",
2493 static_cast<uint64_t>(address));
2494 fprintf(stream_, " stack limit is here: 0x%016" PRIx64 "\n",
2495 static_cast<uint64_t>(stack_limit_));
2496 fprintf(stream_, "\n");
2497 FATAL("ACCESS BELOW STACK POINTER");
2498 }
2499 }
2500
VisitMoveWideImmediate(Instruction * instr)2501 void Simulator::VisitMoveWideImmediate(Instruction* instr) {
2502 MoveWideImmediateOp mov_op =
2503 static_cast<MoveWideImmediateOp>(instr->Mask(MoveWideImmediateMask));
2504 int64_t new_xn_val = 0;
2505
2506 bool is_64_bits = instr->SixtyFourBits() == 1;
2507 // Shift is limited for W operations.
2508 DCHECK(is_64_bits || (instr->ShiftMoveWide() < 2));
2509
2510 // Get the shifted immediate.
2511 int64_t shift = instr->ShiftMoveWide() * 16;
2512 int64_t shifted_imm16 = static_cast<int64_t>(instr->ImmMoveWide()) << shift;
2513
2514 // Compute the new value.
2515 switch (mov_op) {
2516 case MOVN_w:
2517 case MOVN_x: {
2518 new_xn_val = ~shifted_imm16;
2519 if (!is_64_bits) new_xn_val &= kWRegMask;
2520 break;
2521 }
2522 case MOVK_w:
2523 case MOVK_x: {
2524 unsigned reg_code = instr->Rd();
2525 int64_t prev_xn_val = is_64_bits ? xreg(reg_code) : wreg(reg_code);
2526 new_xn_val = (prev_xn_val & ~(INT64_C(0xFFFF) << shift)) | shifted_imm16;
2527 break;
2528 }
2529 case MOVZ_w:
2530 case MOVZ_x: {
2531 new_xn_val = shifted_imm16;
2532 break;
2533 }
2534 default:
2535 UNREACHABLE();
2536 }
2537
2538 // Update the destination register.
2539 set_xreg(instr->Rd(), new_xn_val);
2540 }
2541
VisitConditionalSelect(Instruction * instr)2542 void Simulator::VisitConditionalSelect(Instruction* instr) {
2543 uint64_t new_val = xreg(instr->Rn());
2544 if (ConditionFailed(static_cast<Condition>(instr->Condition()))) {
2545 new_val = xreg(instr->Rm());
2546 switch (instr->Mask(ConditionalSelectMask)) {
2547 case CSEL_w:
2548 case CSEL_x:
2549 break;
2550 case CSINC_w:
2551 case CSINC_x:
2552 new_val++;
2553 break;
2554 case CSINV_w:
2555 case CSINV_x:
2556 new_val = ~new_val;
2557 break;
2558 case CSNEG_w:
2559 case CSNEG_x:
2560 // Simulate two's complement (instead of casting to signed and negating)
2561 // to avoid undefined behavior on signed overflow.
2562 new_val = (~new_val) + 1;
2563 break;
2564 default:
2565 UNIMPLEMENTED();
2566 }
2567 }
2568 if (instr->SixtyFourBits()) {
2569 set_xreg(instr->Rd(), new_val);
2570 } else {
2571 set_wreg(instr->Rd(), static_cast<uint32_t>(new_val));
2572 }
2573 }
2574
VisitDataProcessing1Source(Instruction * instr)2575 void Simulator::VisitDataProcessing1Source(Instruction* instr) {
2576 unsigned dst = instr->Rd();
2577 unsigned src = instr->Rn();
2578
2579 switch (instr->Mask(DataProcessing1SourceMask)) {
2580 case RBIT_w:
2581 set_wreg(dst, base::bits::ReverseBits(wreg(src)));
2582 break;
2583 case RBIT_x:
2584 set_xreg(dst, base::bits::ReverseBits(xreg(src)));
2585 break;
2586 case REV16_w:
2587 set_wreg(dst, ReverseBytes(wreg(src), 1));
2588 break;
2589 case REV16_x:
2590 set_xreg(dst, ReverseBytes(xreg(src), 1));
2591 break;
2592 case REV_w:
2593 set_wreg(dst, ReverseBytes(wreg(src), 2));
2594 break;
2595 case REV32_x:
2596 set_xreg(dst, ReverseBytes(xreg(src), 2));
2597 break;
2598 case REV_x:
2599 set_xreg(dst, ReverseBytes(xreg(src), 3));
2600 break;
2601 case CLZ_w:
2602 set_wreg(dst, CountLeadingZeros(wreg(src), kWRegSizeInBits));
2603 break;
2604 case CLZ_x:
2605 set_xreg(dst, CountLeadingZeros(xreg(src), kXRegSizeInBits));
2606 break;
2607 case CLS_w: {
2608 set_wreg(dst, CountLeadingSignBits(wreg(src), kWRegSizeInBits));
2609 break;
2610 }
2611 case CLS_x: {
2612 set_xreg(dst, CountLeadingSignBits(xreg(src), kXRegSizeInBits));
2613 break;
2614 }
2615 default:
2616 UNIMPLEMENTED();
2617 }
2618 }
2619
2620 template <typename T>
DataProcessing2Source(Instruction * instr)2621 void Simulator::DataProcessing2Source(Instruction* instr) {
2622 Shift shift_op = NO_SHIFT;
2623 T result = 0;
2624 switch (instr->Mask(DataProcessing2SourceMask)) {
2625 case SDIV_w:
2626 case SDIV_x: {
2627 T rn = reg<T>(instr->Rn());
2628 T rm = reg<T>(instr->Rm());
2629 if ((rn == std::numeric_limits<T>::min()) && (rm == -1)) {
2630 result = std::numeric_limits<T>::min();
2631 } else if (rm == 0) {
2632 // Division by zero can be trapped, but not on A-class processors.
2633 result = 0;
2634 } else {
2635 result = rn / rm;
2636 }
2637 break;
2638 }
2639 case UDIV_w:
2640 case UDIV_x: {
2641 using unsignedT = typename std::make_unsigned<T>::type;
2642 unsignedT rn = static_cast<unsignedT>(reg<T>(instr->Rn()));
2643 unsignedT rm = static_cast<unsignedT>(reg<T>(instr->Rm()));
2644 if (rm == 0) {
2645 // Division by zero can be trapped, but not on A-class processors.
2646 result = 0;
2647 } else {
2648 result = rn / rm;
2649 }
2650 break;
2651 }
2652 case LSLV_w:
2653 case LSLV_x:
2654 shift_op = LSL;
2655 break;
2656 case LSRV_w:
2657 case LSRV_x:
2658 shift_op = LSR;
2659 break;
2660 case ASRV_w:
2661 case ASRV_x:
2662 shift_op = ASR;
2663 break;
2664 case RORV_w:
2665 case RORV_x:
2666 shift_op = ROR;
2667 break;
2668 default:
2669 UNIMPLEMENTED();
2670 }
2671
2672 if (shift_op != NO_SHIFT) {
2673 // Shift distance encoded in the least-significant five/six bits of the
2674 // register.
2675 unsigned shift = wreg(instr->Rm());
2676 if (sizeof(T) == kWRegSize) {
2677 shift &= kShiftAmountWRegMask;
2678 } else {
2679 shift &= kShiftAmountXRegMask;
2680 }
2681 result = ShiftOperand(reg<T>(instr->Rn()), shift_op, shift);
2682 }
2683 set_reg<T>(instr->Rd(), result);
2684 }
2685
VisitDataProcessing2Source(Instruction * instr)2686 void Simulator::VisitDataProcessing2Source(Instruction* instr) {
2687 if (instr->SixtyFourBits()) {
2688 DataProcessing2Source<int64_t>(instr);
2689 } else {
2690 DataProcessing2Source<int32_t>(instr);
2691 }
2692 }
2693
2694 // The algorithm used is described in section 8.2 of
2695 // Hacker's Delight, by Henry S. Warren, Jr.
2696 // It assumes that a right shift on a signed integer is an arithmetic shift.
MultiplyHighSigned(int64_t u,int64_t v)2697 static int64_t MultiplyHighSigned(int64_t u, int64_t v) {
2698 uint64_t u0, v0, w0;
2699 int64_t u1, v1, w1, w2, t;
2700
2701 u0 = u & 0xFFFFFFFFLL;
2702 u1 = u >> 32;
2703 v0 = v & 0xFFFFFFFFLL;
2704 v1 = v >> 32;
2705
2706 w0 = u0 * v0;
2707 t = u1 * v0 + (w0 >> 32);
2708 w1 = t & 0xFFFFFFFFLL;
2709 w2 = t >> 32;
2710 w1 = u0 * v1 + w1;
2711
2712 return u1 * v1 + w2 + (w1 >> 32);
2713 }
2714
VisitDataProcessing3Source(Instruction * instr)2715 void Simulator::VisitDataProcessing3Source(Instruction* instr) {
2716 int64_t result = 0;
2717 // Extract and sign- or zero-extend 32-bit arguments for widening operations.
2718 uint64_t rn_u32 = reg<uint32_t>(instr->Rn());
2719 uint64_t rm_u32 = reg<uint32_t>(instr->Rm());
2720 int64_t rn_s32 = reg<int32_t>(instr->Rn());
2721 int64_t rm_s32 = reg<int32_t>(instr->Rm());
2722 switch (instr->Mask(DataProcessing3SourceMask)) {
2723 case MADD_w:
2724 case MADD_x:
2725 result = base::AddWithWraparound(
2726 xreg(instr->Ra()),
2727 base::MulWithWraparound(xreg(instr->Rn()), xreg(instr->Rm())));
2728 break;
2729 case MSUB_w:
2730 case MSUB_x:
2731 result = base::SubWithWraparound(
2732 xreg(instr->Ra()),
2733 base::MulWithWraparound(xreg(instr->Rn()), xreg(instr->Rm())));
2734 break;
2735 case SMADDL_x:
2736 result = base::AddWithWraparound(xreg(instr->Ra()), (rn_s32 * rm_s32));
2737 break;
2738 case SMSUBL_x:
2739 result = base::SubWithWraparound(xreg(instr->Ra()), (rn_s32 * rm_s32));
2740 break;
2741 case UMADDL_x:
2742 result = static_cast<uint64_t>(xreg(instr->Ra())) + (rn_u32 * rm_u32);
2743 break;
2744 case UMSUBL_x:
2745 result = static_cast<uint64_t>(xreg(instr->Ra())) - (rn_u32 * rm_u32);
2746 break;
2747 case SMULH_x:
2748 DCHECK_EQ(instr->Ra(), kZeroRegCode);
2749 result = MultiplyHighSigned(xreg(instr->Rn()), xreg(instr->Rm()));
2750 break;
2751 default:
2752 UNIMPLEMENTED();
2753 }
2754
2755 if (instr->SixtyFourBits()) {
2756 set_xreg(instr->Rd(), result);
2757 } else {
2758 set_wreg(instr->Rd(), static_cast<int32_t>(result));
2759 }
2760 }
2761
2762 template <typename T>
BitfieldHelper(Instruction * instr)2763 void Simulator::BitfieldHelper(Instruction* instr) {
2764 using unsignedT = typename std::make_unsigned<T>::type;
2765 T reg_size = sizeof(T) * 8;
2766 T R = instr->ImmR();
2767 T S = instr->ImmS();
2768 T diff = S - R;
2769 T mask;
2770 if (diff >= 0) {
2771 mask = diff < reg_size - 1 ? (static_cast<unsignedT>(1) << (diff + 1)) - 1
2772 : static_cast<T>(-1);
2773 } else {
2774 uint64_t umask = ((1ULL << (S + 1)) - 1);
2775 umask = (umask >> R) | (umask << (reg_size - R));
2776 mask = static_cast<T>(umask);
2777 diff += reg_size;
2778 }
2779
2780 // inzero indicates if the extracted bitfield is inserted into the
2781 // destination register value or in zero.
2782 // If extend is true, extend the sign of the extracted bitfield.
2783 bool inzero = false;
2784 bool extend = false;
2785 switch (instr->Mask(BitfieldMask)) {
2786 case BFM_x:
2787 case BFM_w:
2788 break;
2789 case SBFM_x:
2790 case SBFM_w:
2791 inzero = true;
2792 extend = true;
2793 break;
2794 case UBFM_x:
2795 case UBFM_w:
2796 inzero = true;
2797 break;
2798 default:
2799 UNIMPLEMENTED();
2800 }
2801
2802 T dst = inzero ? 0 : reg<T>(instr->Rd());
2803 T src = reg<T>(instr->Rn());
2804 // Rotate source bitfield into place.
2805 T result = R == 0 ? src
2806 : (static_cast<unsignedT>(src) >> R) |
2807 (static_cast<unsignedT>(src) << (reg_size - R));
2808 // Determine the sign extension.
2809 T topbits_preshift = (static_cast<unsignedT>(1) << (reg_size - diff - 1)) - 1;
2810 T signbits =
2811 diff >= reg_size - 1
2812 ? 0
2813 : ((extend && ((src >> S) & 1) ? topbits_preshift : 0) << (diff + 1));
2814
2815 // Merge sign extension, dest/zero and bitfield.
2816 result = signbits | (result & mask) | (dst & ~mask);
2817
2818 set_reg<T>(instr->Rd(), result);
2819 }
2820
VisitBitfield(Instruction * instr)2821 void Simulator::VisitBitfield(Instruction* instr) {
2822 if (instr->SixtyFourBits()) {
2823 BitfieldHelper<int64_t>(instr);
2824 } else {
2825 BitfieldHelper<int32_t>(instr);
2826 }
2827 }
2828
VisitExtract(Instruction * instr)2829 void Simulator::VisitExtract(Instruction* instr) {
2830 if (instr->SixtyFourBits()) {
2831 Extract<uint64_t>(instr);
2832 } else {
2833 Extract<uint32_t>(instr);
2834 }
2835 }
2836
VisitFPImmediate(Instruction * instr)2837 void Simulator::VisitFPImmediate(Instruction* instr) {
2838 AssertSupportedFPCR();
2839
2840 unsigned dest = instr->Rd();
2841 switch (instr->Mask(FPImmediateMask)) {
2842 case FMOV_s_imm:
2843 set_sreg(dest, instr->ImmFP32());
2844 break;
2845 case FMOV_d_imm:
2846 set_dreg(dest, instr->ImmFP64());
2847 break;
2848 default:
2849 UNREACHABLE();
2850 }
2851 }
2852
VisitFPIntegerConvert(Instruction * instr)2853 void Simulator::VisitFPIntegerConvert(Instruction* instr) {
2854 AssertSupportedFPCR();
2855
2856 unsigned dst = instr->Rd();
2857 unsigned src = instr->Rn();
2858
2859 FPRounding round = fpcr().RMode();
2860
2861 switch (instr->Mask(FPIntegerConvertMask)) {
2862 case FCVTAS_ws:
2863 set_wreg(dst, FPToInt32(sreg(src), FPTieAway));
2864 break;
2865 case FCVTAS_xs:
2866 set_xreg(dst, FPToInt64(sreg(src), FPTieAway));
2867 break;
2868 case FCVTAS_wd:
2869 set_wreg(dst, FPToInt32(dreg(src), FPTieAway));
2870 break;
2871 case FCVTAS_xd:
2872 set_xreg(dst, FPToInt64(dreg(src), FPTieAway));
2873 break;
2874 case FCVTAU_ws:
2875 set_wreg(dst, FPToUInt32(sreg(src), FPTieAway));
2876 break;
2877 case FCVTAU_xs:
2878 set_xreg(dst, FPToUInt64(sreg(src), FPTieAway));
2879 break;
2880 case FCVTAU_wd:
2881 set_wreg(dst, FPToUInt32(dreg(src), FPTieAway));
2882 break;
2883 case FCVTAU_xd:
2884 set_xreg(dst, FPToUInt64(dreg(src), FPTieAway));
2885 break;
2886 case FCVTMS_ws:
2887 set_wreg(dst, FPToInt32(sreg(src), FPNegativeInfinity));
2888 break;
2889 case FCVTMS_xs:
2890 set_xreg(dst, FPToInt64(sreg(src), FPNegativeInfinity));
2891 break;
2892 case FCVTMS_wd:
2893 set_wreg(dst, FPToInt32(dreg(src), FPNegativeInfinity));
2894 break;
2895 case FCVTMS_xd:
2896 set_xreg(dst, FPToInt64(dreg(src), FPNegativeInfinity));
2897 break;
2898 case FCVTMU_ws:
2899 set_wreg(dst, FPToUInt32(sreg(src), FPNegativeInfinity));
2900 break;
2901 case FCVTMU_xs:
2902 set_xreg(dst, FPToUInt64(sreg(src), FPNegativeInfinity));
2903 break;
2904 case FCVTMU_wd:
2905 set_wreg(dst, FPToUInt32(dreg(src), FPNegativeInfinity));
2906 break;
2907 case FCVTMU_xd:
2908 set_xreg(dst, FPToUInt64(dreg(src), FPNegativeInfinity));
2909 break;
2910 case FCVTNS_ws:
2911 set_wreg(dst, FPToInt32(sreg(src), FPTieEven));
2912 break;
2913 case FCVTNS_xs:
2914 set_xreg(dst, FPToInt64(sreg(src), FPTieEven));
2915 break;
2916 case FCVTNS_wd:
2917 set_wreg(dst, FPToInt32(dreg(src), FPTieEven));
2918 break;
2919 case FCVTNS_xd:
2920 set_xreg(dst, FPToInt64(dreg(src), FPTieEven));
2921 break;
2922 case FCVTNU_ws:
2923 set_wreg(dst, FPToUInt32(sreg(src), FPTieEven));
2924 break;
2925 case FCVTNU_xs:
2926 set_xreg(dst, FPToUInt64(sreg(src), FPTieEven));
2927 break;
2928 case FCVTNU_wd:
2929 set_wreg(dst, FPToUInt32(dreg(src), FPTieEven));
2930 break;
2931 case FCVTNU_xd:
2932 set_xreg(dst, FPToUInt64(dreg(src), FPTieEven));
2933 break;
2934 case FCVTZS_ws:
2935 set_wreg(dst, FPToInt32(sreg(src), FPZero));
2936 break;
2937 case FCVTZS_xs:
2938 set_xreg(dst, FPToInt64(sreg(src), FPZero));
2939 break;
2940 case FCVTZS_wd:
2941 set_wreg(dst, FPToInt32(dreg(src), FPZero));
2942 break;
2943 case FCVTZS_xd:
2944 set_xreg(dst, FPToInt64(dreg(src), FPZero));
2945 break;
2946 case FCVTZU_ws:
2947 set_wreg(dst, FPToUInt32(sreg(src), FPZero));
2948 break;
2949 case FCVTZU_xs:
2950 set_xreg(dst, FPToUInt64(sreg(src), FPZero));
2951 break;
2952 case FCVTZU_wd:
2953 set_wreg(dst, FPToUInt32(dreg(src), FPZero));
2954 break;
2955 case FCVTZU_xd:
2956 set_xreg(dst, FPToUInt64(dreg(src), FPZero));
2957 break;
2958 case FJCVTZS:
2959 set_wreg(dst, FPToFixedJS(dreg(src)));
2960 break;
2961 case FMOV_ws:
2962 set_wreg(dst, sreg_bits(src));
2963 break;
2964 case FMOV_xd:
2965 set_xreg(dst, dreg_bits(src));
2966 break;
2967 case FMOV_sw:
2968 set_sreg_bits(dst, wreg(src));
2969 break;
2970 case FMOV_dx:
2971 set_dreg_bits(dst, xreg(src));
2972 break;
2973
2974 // A 32-bit input can be handled in the same way as a 64-bit input, since
2975 // the sign- or zero-extension will not affect the conversion.
2976 case SCVTF_dx:
2977 set_dreg(dst, FixedToDouble(xreg(src), 0, round));
2978 break;
2979 case SCVTF_dw:
2980 set_dreg(dst, FixedToDouble(wreg(src), 0, round));
2981 break;
2982 case UCVTF_dx:
2983 set_dreg(dst, UFixedToDouble(xreg(src), 0, round));
2984 break;
2985 case UCVTF_dw: {
2986 set_dreg(dst, UFixedToDouble(reg<uint32_t>(src), 0, round));
2987 break;
2988 }
2989 case SCVTF_sx:
2990 set_sreg(dst, FixedToFloat(xreg(src), 0, round));
2991 break;
2992 case SCVTF_sw:
2993 set_sreg(dst, FixedToFloat(wreg(src), 0, round));
2994 break;
2995 case UCVTF_sx:
2996 set_sreg(dst, UFixedToFloat(xreg(src), 0, round));
2997 break;
2998 case UCVTF_sw: {
2999 set_sreg(dst, UFixedToFloat(reg<uint32_t>(src), 0, round));
3000 break;
3001 }
3002
3003 default:
3004 UNREACHABLE();
3005 }
3006 }
3007
VisitFPFixedPointConvert(Instruction * instr)3008 void Simulator::VisitFPFixedPointConvert(Instruction* instr) {
3009 AssertSupportedFPCR();
3010
3011 unsigned dst = instr->Rd();
3012 unsigned src = instr->Rn();
3013 int fbits = 64 - instr->FPScale();
3014
3015 FPRounding round = fpcr().RMode();
3016
3017 switch (instr->Mask(FPFixedPointConvertMask)) {
3018 // A 32-bit input can be handled in the same way as a 64-bit input, since
3019 // the sign- or zero-extension will not affect the conversion.
3020 case SCVTF_dx_fixed:
3021 set_dreg(dst, FixedToDouble(xreg(src), fbits, round));
3022 break;
3023 case SCVTF_dw_fixed:
3024 set_dreg(dst, FixedToDouble(wreg(src), fbits, round));
3025 break;
3026 case UCVTF_dx_fixed:
3027 set_dreg(dst, UFixedToDouble(xreg(src), fbits, round));
3028 break;
3029 case UCVTF_dw_fixed: {
3030 set_dreg(dst, UFixedToDouble(reg<uint32_t>(src), fbits, round));
3031 break;
3032 }
3033 case SCVTF_sx_fixed:
3034 set_sreg(dst, FixedToFloat(xreg(src), fbits, round));
3035 break;
3036 case SCVTF_sw_fixed:
3037 set_sreg(dst, FixedToFloat(wreg(src), fbits, round));
3038 break;
3039 case UCVTF_sx_fixed:
3040 set_sreg(dst, UFixedToFloat(xreg(src), fbits, round));
3041 break;
3042 case UCVTF_sw_fixed: {
3043 set_sreg(dst, UFixedToFloat(reg<uint32_t>(src), fbits, round));
3044 break;
3045 }
3046 default:
3047 UNREACHABLE();
3048 }
3049 }
3050
VisitFPCompare(Instruction * instr)3051 void Simulator::VisitFPCompare(Instruction* instr) {
3052 AssertSupportedFPCR();
3053
3054 switch (instr->Mask(FPCompareMask)) {
3055 case FCMP_s:
3056 FPCompare(sreg(instr->Rn()), sreg(instr->Rm()));
3057 break;
3058 case FCMP_d:
3059 FPCompare(dreg(instr->Rn()), dreg(instr->Rm()));
3060 break;
3061 case FCMP_s_zero:
3062 FPCompare(sreg(instr->Rn()), 0.0f);
3063 break;
3064 case FCMP_d_zero:
3065 FPCompare(dreg(instr->Rn()), 0.0);
3066 break;
3067 default:
3068 UNIMPLEMENTED();
3069 }
3070 }
3071
VisitFPConditionalCompare(Instruction * instr)3072 void Simulator::VisitFPConditionalCompare(Instruction* instr) {
3073 AssertSupportedFPCR();
3074
3075 switch (instr->Mask(FPConditionalCompareMask)) {
3076 case FCCMP_s:
3077 if (ConditionPassed(static_cast<Condition>(instr->Condition()))) {
3078 FPCompare(sreg(instr->Rn()), sreg(instr->Rm()));
3079 } else {
3080 nzcv().SetFlags(instr->Nzcv());
3081 LogSystemRegister(NZCV);
3082 }
3083 break;
3084 case FCCMP_d: {
3085 if (ConditionPassed(static_cast<Condition>(instr->Condition()))) {
3086 FPCompare(dreg(instr->Rn()), dreg(instr->Rm()));
3087 } else {
3088 // If the condition fails, set the status flags to the nzcv immediate.
3089 nzcv().SetFlags(instr->Nzcv());
3090 LogSystemRegister(NZCV);
3091 }
3092 break;
3093 }
3094 default:
3095 UNIMPLEMENTED();
3096 }
3097 }
3098
VisitFPConditionalSelect(Instruction * instr)3099 void Simulator::VisitFPConditionalSelect(Instruction* instr) {
3100 AssertSupportedFPCR();
3101
3102 Instr selected;
3103 if (ConditionPassed(static_cast<Condition>(instr->Condition()))) {
3104 selected = instr->Rn();
3105 } else {
3106 selected = instr->Rm();
3107 }
3108
3109 switch (instr->Mask(FPConditionalSelectMask)) {
3110 case FCSEL_s:
3111 set_sreg(instr->Rd(), sreg(selected));
3112 break;
3113 case FCSEL_d:
3114 set_dreg(instr->Rd(), dreg(selected));
3115 break;
3116 default:
3117 UNIMPLEMENTED();
3118 }
3119 }
3120
VisitFPDataProcessing1Source(Instruction * instr)3121 void Simulator::VisitFPDataProcessing1Source(Instruction* instr) {
3122 AssertSupportedFPCR();
3123
3124 FPRounding fpcr_rounding = static_cast<FPRounding>(fpcr().RMode());
3125 VectorFormat vform = (instr->Mask(FP64) == FP64) ? kFormatD : kFormatS;
3126 SimVRegister& rd = vreg(instr->Rd());
3127 SimVRegister& rn = vreg(instr->Rn());
3128 bool inexact_exception = false;
3129
3130 unsigned fd = instr->Rd();
3131 unsigned fn = instr->Rn();
3132
3133 switch (instr->Mask(FPDataProcessing1SourceMask)) {
3134 case FMOV_s:
3135 set_sreg(fd, sreg(fn));
3136 return;
3137 case FMOV_d:
3138 set_dreg(fd, dreg(fn));
3139 return;
3140 case FABS_s:
3141 case FABS_d:
3142 fabs_(vform, vreg(fd), vreg(fn));
3143 // Explicitly log the register update whilst we have type information.
3144 LogVRegister(fd, GetPrintRegisterFormatFP(vform));
3145 return;
3146 case FNEG_s:
3147 case FNEG_d:
3148 fneg(vform, vreg(fd), vreg(fn));
3149 // Explicitly log the register update whilst we have type information.
3150 LogVRegister(fd, GetPrintRegisterFormatFP(vform));
3151 return;
3152 case FCVT_ds:
3153 set_dreg(fd, FPToDouble(sreg(fn)));
3154 return;
3155 case FCVT_sd:
3156 set_sreg(fd, FPToFloat(dreg(fn), FPTieEven));
3157 return;
3158 case FCVT_hs:
3159 set_hreg(fd, FPToFloat16(sreg(fn), FPTieEven));
3160 return;
3161 case FCVT_sh:
3162 set_sreg(fd, FPToFloat(hreg(fn)));
3163 return;
3164 case FCVT_dh:
3165 set_dreg(fd, FPToDouble(FPToFloat(hreg(fn))));
3166 return;
3167 case FCVT_hd:
3168 set_hreg(fd, FPToFloat16(dreg(fn), FPTieEven));
3169 return;
3170 case FSQRT_s:
3171 case FSQRT_d:
3172 fsqrt(vform, rd, rn);
3173 // Explicitly log the register update whilst we have type information.
3174 LogVRegister(fd, GetPrintRegisterFormatFP(vform));
3175 return;
3176 case FRINTI_s:
3177 case FRINTI_d:
3178 break; // Use FPCR rounding mode.
3179 case FRINTX_s:
3180 case FRINTX_d:
3181 inexact_exception = true;
3182 break;
3183 case FRINTA_s:
3184 case FRINTA_d:
3185 fpcr_rounding = FPTieAway;
3186 break;
3187 case FRINTM_s:
3188 case FRINTM_d:
3189 fpcr_rounding = FPNegativeInfinity;
3190 break;
3191 case FRINTN_s:
3192 case FRINTN_d:
3193 fpcr_rounding = FPTieEven;
3194 break;
3195 case FRINTP_s:
3196 case FRINTP_d:
3197 fpcr_rounding = FPPositiveInfinity;
3198 break;
3199 case FRINTZ_s:
3200 case FRINTZ_d:
3201 fpcr_rounding = FPZero;
3202 break;
3203 default:
3204 UNIMPLEMENTED();
3205 }
3206
3207 // Only FRINT* instructions fall through the switch above.
3208 frint(vform, rd, rn, fpcr_rounding, inexact_exception);
3209 // Explicitly log the register update whilst we have type information
3210 LogVRegister(fd, GetPrintRegisterFormatFP(vform));
3211 }
3212
VisitFPDataProcessing2Source(Instruction * instr)3213 void Simulator::VisitFPDataProcessing2Source(Instruction* instr) {
3214 AssertSupportedFPCR();
3215
3216 VectorFormat vform = (instr->Mask(FP64) == FP64) ? kFormatD : kFormatS;
3217 SimVRegister& rd = vreg(instr->Rd());
3218 SimVRegister& rn = vreg(instr->Rn());
3219 SimVRegister& rm = vreg(instr->Rm());
3220
3221 switch (instr->Mask(FPDataProcessing2SourceMask)) {
3222 case FADD_s:
3223 case FADD_d:
3224 fadd(vform, rd, rn, rm);
3225 break;
3226 case FSUB_s:
3227 case FSUB_d:
3228 fsub(vform, rd, rn, rm);
3229 break;
3230 case FMUL_s:
3231 case FMUL_d:
3232 fmul(vform, rd, rn, rm);
3233 break;
3234 case FNMUL_s:
3235 case FNMUL_d:
3236 fnmul(vform, rd, rn, rm);
3237 break;
3238 case FDIV_s:
3239 case FDIV_d:
3240 fdiv(vform, rd, rn, rm);
3241 break;
3242 case FMAX_s:
3243 case FMAX_d:
3244 fmax(vform, rd, rn, rm);
3245 break;
3246 case FMIN_s:
3247 case FMIN_d:
3248 fmin(vform, rd, rn, rm);
3249 break;
3250 case FMAXNM_s:
3251 case FMAXNM_d:
3252 fmaxnm(vform, rd, rn, rm);
3253 break;
3254 case FMINNM_s:
3255 case FMINNM_d:
3256 fminnm(vform, rd, rn, rm);
3257 break;
3258 default:
3259 UNREACHABLE();
3260 }
3261 // Explicitly log the register update whilst we have type information.
3262 LogVRegister(instr->Rd(), GetPrintRegisterFormatFP(vform));
3263 }
3264
VisitFPDataProcessing3Source(Instruction * instr)3265 void Simulator::VisitFPDataProcessing3Source(Instruction* instr) {
3266 AssertSupportedFPCR();
3267
3268 unsigned fd = instr->Rd();
3269 unsigned fn = instr->Rn();
3270 unsigned fm = instr->Rm();
3271 unsigned fa = instr->Ra();
3272
3273 switch (instr->Mask(FPDataProcessing3SourceMask)) {
3274 // fd = fa +/- (fn * fm)
3275 case FMADD_s:
3276 set_sreg(fd, FPMulAdd(sreg(fa), sreg(fn), sreg(fm)));
3277 break;
3278 case FMSUB_s:
3279 set_sreg(fd, FPMulAdd(sreg(fa), -sreg(fn), sreg(fm)));
3280 break;
3281 case FMADD_d:
3282 set_dreg(fd, FPMulAdd(dreg(fa), dreg(fn), dreg(fm)));
3283 break;
3284 case FMSUB_d:
3285 set_dreg(fd, FPMulAdd(dreg(fa), -dreg(fn), dreg(fm)));
3286 break;
3287 // Negated variants of the above.
3288 case FNMADD_s:
3289 set_sreg(fd, FPMulAdd(-sreg(fa), -sreg(fn), sreg(fm)));
3290 break;
3291 case FNMSUB_s:
3292 set_sreg(fd, FPMulAdd(-sreg(fa), sreg(fn), sreg(fm)));
3293 break;
3294 case FNMADD_d:
3295 set_dreg(fd, FPMulAdd(-dreg(fa), -dreg(fn), dreg(fm)));
3296 break;
3297 case FNMSUB_d:
3298 set_dreg(fd, FPMulAdd(-dreg(fa), dreg(fn), dreg(fm)));
3299 break;
3300 default:
3301 UNIMPLEMENTED();
3302 }
3303 }
3304
FPProcessNaNs(Instruction * instr)3305 bool Simulator::FPProcessNaNs(Instruction* instr) {
3306 unsigned fd = instr->Rd();
3307 unsigned fn = instr->Rn();
3308 unsigned fm = instr->Rm();
3309 bool done = false;
3310
3311 if (instr->Mask(FP64) == FP64) {
3312 double result = FPProcessNaNs(dreg(fn), dreg(fm));
3313 if (std::isnan(result)) {
3314 set_dreg(fd, result);
3315 done = true;
3316 }
3317 } else {
3318 float result = FPProcessNaNs(sreg(fn), sreg(fm));
3319 if (std::isnan(result)) {
3320 set_sreg(fd, result);
3321 done = true;
3322 }
3323 }
3324
3325 return done;
3326 }
3327
3328 // clang-format off
3329 #define PAUTH_SYSTEM_MODES(V) \
3330 V(B1716, 17, xreg(16), kPACKeyIB) \
3331 V(BSP, 30, xreg(31, Reg31IsStackPointer), kPACKeyIB)
3332 // clang-format on
3333
VisitSystem(Instruction * instr)3334 void Simulator::VisitSystem(Instruction* instr) {
3335 // Some system instructions hijack their Op and Cp fields to represent a
3336 // range of immediates instead of indicating a different instruction. This
3337 // makes the decoding tricky.
3338 if (instr->Mask(SystemPAuthFMask) == SystemPAuthFixed) {
3339 // The BType check for PACIBSP happens in CheckBType().
3340 switch (instr->Mask(SystemPAuthMask)) {
3341 #define DEFINE_PAUTH_FUNCS(SUFFIX, DST, MOD, KEY) \
3342 case PACI##SUFFIX: \
3343 set_xreg(DST, AddPAC(xreg(DST), MOD, KEY, kInstructionPointer)); \
3344 break; \
3345 case AUTI##SUFFIX: \
3346 set_xreg(DST, AuthPAC(xreg(DST), MOD, KEY, kInstructionPointer)); \
3347 break;
3348
3349 PAUTH_SYSTEM_MODES(DEFINE_PAUTH_FUNCS)
3350 #undef DEFINE_PAUTH_FUNCS
3351 #undef PAUTH_SYSTEM_MODES
3352 }
3353 } else if (instr->Mask(SystemSysRegFMask) == SystemSysRegFixed) {
3354 switch (instr->Mask(SystemSysRegMask)) {
3355 case MRS: {
3356 switch (instr->ImmSystemRegister()) {
3357 case NZCV:
3358 set_xreg(instr->Rt(), nzcv().RawValue());
3359 break;
3360 case FPCR:
3361 set_xreg(instr->Rt(), fpcr().RawValue());
3362 break;
3363 default:
3364 UNIMPLEMENTED();
3365 }
3366 break;
3367 }
3368 case MSR: {
3369 switch (instr->ImmSystemRegister()) {
3370 case NZCV:
3371 nzcv().SetRawValue(wreg(instr->Rt()));
3372 LogSystemRegister(NZCV);
3373 break;
3374 case FPCR:
3375 fpcr().SetRawValue(wreg(instr->Rt()));
3376 LogSystemRegister(FPCR);
3377 break;
3378 default:
3379 UNIMPLEMENTED();
3380 }
3381 break;
3382 }
3383 }
3384 } else if (instr->Mask(SystemHintFMask) == SystemHintFixed) {
3385 DCHECK(instr->Mask(SystemHintMask) == HINT);
3386 switch (instr->ImmHint()) {
3387 case NOP:
3388 case CSDB:
3389 case BTI_jc:
3390 case BTI:
3391 case BTI_c:
3392 case BTI_j:
3393 // The BType checks happen in CheckBType().
3394 break;
3395 default:
3396 UNIMPLEMENTED();
3397 }
3398 } else if (instr->Mask(MemBarrierFMask) == MemBarrierFixed) {
3399 #if defined(V8_OS_WIN)
3400 MemoryBarrier();
3401 #else
3402 __sync_synchronize();
3403 #endif
3404 } else {
3405 UNIMPLEMENTED();
3406 }
3407 }
3408
GetValue(const char * desc,int64_t * value)3409 bool Simulator::GetValue(const char* desc, int64_t* value) {
3410 int regnum = CodeFromName(desc);
3411 if (regnum >= 0) {
3412 unsigned code = regnum;
3413 if (code == kZeroRegCode) {
3414 // Catch the zero register and return 0.
3415 *value = 0;
3416 return true;
3417 } else if (code == kSPRegInternalCode) {
3418 // Translate the stack pointer code to 31, for Reg31IsStackPointer.
3419 code = 31;
3420 }
3421 if (desc[0] == 'w') {
3422 *value = wreg(code, Reg31IsStackPointer);
3423 } else {
3424 *value = xreg(code, Reg31IsStackPointer);
3425 }
3426 return true;
3427 } else if (strncmp(desc, "0x", 2) == 0) {
3428 return SScanF(desc + 2, "%" SCNx64, reinterpret_cast<uint64_t*>(value)) ==
3429 1;
3430 } else {
3431 return SScanF(desc, "%" SCNu64, reinterpret_cast<uint64_t*>(value)) == 1;
3432 }
3433 }
3434
PrintValue(const char * desc)3435 bool Simulator::PrintValue(const char* desc) {
3436 if (strcmp(desc, "sp") == 0) {
3437 DCHECK(CodeFromName(desc) == static_cast<int>(kSPRegInternalCode));
3438 PrintF(stream_, "%s sp:%s 0x%016" PRIx64 "%s\n", clr_reg_name,
3439 clr_reg_value, xreg(31, Reg31IsStackPointer), clr_normal);
3440 return true;
3441 } else if (strcmp(desc, "wsp") == 0) {
3442 DCHECK(CodeFromName(desc) == static_cast<int>(kSPRegInternalCode));
3443 PrintF(stream_, "%s wsp:%s 0x%08" PRIx32 "%s\n", clr_reg_name,
3444 clr_reg_value, wreg(31, Reg31IsStackPointer), clr_normal);
3445 return true;
3446 }
3447
3448 int i = CodeFromName(desc);
3449 static_assert(kNumberOfRegisters == kNumberOfVRegisters,
3450 "Must be same number of Registers as VRegisters.");
3451 if (i < 0 || static_cast<unsigned>(i) >= kNumberOfVRegisters) return false;
3452
3453 if (desc[0] == 'v') {
3454 PrintF(stream_, "%s %s:%s 0x%016" PRIx64 "%s (%s%s:%s %g%s %s:%s %g%s)\n",
3455 clr_vreg_name, VRegNameForCode(i), clr_vreg_value,
3456 bit_cast<uint64_t>(dreg(i)), clr_normal, clr_vreg_name,
3457 DRegNameForCode(i), clr_vreg_value, dreg(i), clr_vreg_name,
3458 SRegNameForCode(i), clr_vreg_value, sreg(i), clr_normal);
3459 return true;
3460 } else if (desc[0] == 'd') {
3461 PrintF(stream_, "%s %s:%s %g%s\n", clr_vreg_name, DRegNameForCode(i),
3462 clr_vreg_value, dreg(i), clr_normal);
3463 return true;
3464 } else if (desc[0] == 's') {
3465 PrintF(stream_, "%s %s:%s %g%s\n", clr_vreg_name, SRegNameForCode(i),
3466 clr_vreg_value, sreg(i), clr_normal);
3467 return true;
3468 } else if (desc[0] == 'w') {
3469 PrintF(stream_, "%s %s:%s 0x%08" PRIx32 "%s\n", clr_reg_name,
3470 WRegNameForCode(i), clr_reg_value, wreg(i), clr_normal);
3471 return true;
3472 } else {
3473 // X register names have a wide variety of starting characters, but anything
3474 // else will be an X register.
3475 PrintF(stream_, "%s %s:%s 0x%016" PRIx64 "%s\n", clr_reg_name,
3476 XRegNameForCode(i), clr_reg_value, xreg(i), clr_normal);
3477 return true;
3478 }
3479 }
3480
Debug()3481 void Simulator::Debug() {
3482 bool done = false;
3483 while (!done) {
3484 // Disassemble the next instruction to execute before doing anything else.
3485 PrintInstructionsAt(pc_, 1);
3486 // Read the command line.
3487 ArrayUniquePtr<char> line(ReadLine("sim> "));
3488 done = ExecDebugCommand(std::move(line));
3489 }
3490 }
3491
ExecDebugCommand(ArrayUniquePtr<char> line_ptr)3492 bool Simulator::ExecDebugCommand(ArrayUniquePtr<char> line_ptr) {
3493 #define COMMAND_SIZE 63
3494 #define ARG_SIZE 255
3495
3496 #define STR(a) #a
3497 #define XSTR(a) STR(a)
3498
3499 char cmd[COMMAND_SIZE + 1];
3500 char arg1[ARG_SIZE + 1];
3501 char arg2[ARG_SIZE + 1];
3502 char* argv[3] = {cmd, arg1, arg2};
3503
3504 // Make sure to have a proper terminating character if reaching the limit.
3505 cmd[COMMAND_SIZE] = 0;
3506 arg1[ARG_SIZE] = 0;
3507 arg2[ARG_SIZE] = 0;
3508
3509 bool cleared_log_disasm_bit = false;
3510
3511 if (line_ptr == nullptr) return false;
3512
3513 // Repeat last command by default.
3514 const char* line = line_ptr.get();
3515 const char* last_input = last_debugger_input();
3516 if (strcmp(line, "\n") == 0 && (last_input != nullptr)) {
3517 line_ptr.reset();
3518 line = last_input;
3519 } else {
3520 // Update the latest command ran
3521 set_last_debugger_input(std::move(line_ptr));
3522 }
3523
3524 // Use sscanf to parse the individual parts of the command line. At the
3525 // moment no command expects more than two parameters.
3526 int argc = SScanF(line,
3527 "%" XSTR(COMMAND_SIZE) "s "
3528 "%" XSTR(ARG_SIZE) "s "
3529 "%" XSTR(ARG_SIZE) "s",
3530 cmd, arg1, arg2);
3531
3532 // stepi / si ------------------------------------------------------------
3533 if ((strcmp(cmd, "si") == 0) || (strcmp(cmd, "stepi") == 0)) {
3534 // We are about to execute instructions, after which by default we
3535 // should increment the pc_. If it was set when reaching this debug
3536 // instruction, it has not been cleared because this instruction has not
3537 // completed yet. So clear it manually.
3538 pc_modified_ = false;
3539
3540 if (argc == 1) {
3541 ExecuteInstruction();
3542 } else {
3543 int64_t number_of_instructions_to_execute = 1;
3544 GetValue(arg1, &number_of_instructions_to_execute);
3545
3546 set_log_parameters(log_parameters() | LOG_DISASM);
3547 while (number_of_instructions_to_execute-- > 0) {
3548 ExecuteInstruction();
3549 }
3550 set_log_parameters(log_parameters() & ~LOG_DISASM);
3551 PrintF("\n");
3552 }
3553
3554 // If it was necessary, the pc has already been updated or incremented
3555 // when executing the instruction. So we do not want it to be updated
3556 // again. It will be cleared when exiting.
3557 pc_modified_ = true;
3558
3559 // next / n
3560 // --------------------------------------------------------------
3561 } else if ((strcmp(cmd, "next") == 0) || (strcmp(cmd, "n") == 0)) {
3562 // Tell the simulator to break after the next executed BL.
3563 break_on_next_ = true;
3564 // Continue.
3565 return true;
3566
3567 // continue / cont / c
3568 // ---------------------------------------------------
3569 } else if ((strcmp(cmd, "continue") == 0) || (strcmp(cmd, "cont") == 0) ||
3570 (strcmp(cmd, "c") == 0)) {
3571 // Leave the debugger shell.
3572 return true;
3573
3574 // disassemble / disasm / di
3575 // ---------------------------------------------
3576 } else if (strcmp(cmd, "disassemble") == 0 || strcmp(cmd, "disasm") == 0 ||
3577 strcmp(cmd, "di") == 0) {
3578 int64_t n_of_instrs_to_disasm = 10; // default value.
3579 int64_t address = reinterpret_cast<int64_t>(pc_); // default value.
3580 if (argc >= 2) { // disasm <n of instrs>
3581 GetValue(arg1, &n_of_instrs_to_disasm);
3582 }
3583 if (argc >= 3) { // disasm <n of instrs> <address>
3584 GetValue(arg2, &address);
3585 }
3586
3587 // Disassemble.
3588 PrintInstructionsAt(reinterpret_cast<Instruction*>(address),
3589 n_of_instrs_to_disasm);
3590 PrintF("\n");
3591
3592 // print / p
3593 // -------------------------------------------------------------
3594 } else if ((strcmp(cmd, "print") == 0) || (strcmp(cmd, "p") == 0)) {
3595 if (argc == 2) {
3596 if (strcmp(arg1, "all") == 0) {
3597 PrintRegisters();
3598 PrintVRegisters();
3599 } else {
3600 if (!PrintValue(arg1)) {
3601 PrintF("%s unrecognized\n", arg1);
3602 }
3603 }
3604 } else {
3605 PrintF(
3606 "print <register>\n"
3607 " Print the content of a register. (alias 'p')\n"
3608 " 'print all' will print all registers.\n"
3609 " Use 'printobject' to get more details about the value.\n");
3610 }
3611
3612 // printobject / po
3613 // ------------------------------------------------------
3614 } else if ((strcmp(cmd, "printobject") == 0) || (strcmp(cmd, "po") == 0)) {
3615 if (argc == 2) {
3616 int64_t value;
3617 StdoutStream os;
3618 if (GetValue(arg1, &value)) {
3619 Object obj(value);
3620 os << arg1 << ": \n";
3621 #ifdef DEBUG
3622 obj.Print(os);
3623 os << "\n";
3624 #else
3625 os << Brief(obj) << "\n";
3626 #endif
3627 } else {
3628 os << arg1 << " unrecognized\n";
3629 }
3630 } else {
3631 PrintF(
3632 "printobject <value>\n"
3633 "printobject <register>\n"
3634 " Print details about the value. (alias 'po')\n");
3635 }
3636
3637 // stack / mem
3638 // ----------------------------------------------------------
3639 } else if (strcmp(cmd, "stack") == 0 || strcmp(cmd, "mem") == 0 ||
3640 strcmp(cmd, "dump") == 0) {
3641 int64_t* cur = nullptr;
3642 int64_t* end = nullptr;
3643 int next_arg = 1;
3644
3645 if (strcmp(cmd, "stack") == 0) {
3646 cur = reinterpret_cast<int64_t*>(sp());
3647
3648 } else { // "mem"
3649 int64_t value;
3650 if (!GetValue(arg1, &value)) {
3651 PrintF("%s unrecognized\n", arg1);
3652 return false;
3653 }
3654 cur = reinterpret_cast<int64_t*>(value);
3655 next_arg++;
3656 }
3657
3658 int64_t words = 0;
3659 if (argc == next_arg) {
3660 words = 10;
3661 } else if (argc == next_arg + 1) {
3662 if (!GetValue(argv[next_arg], &words)) {
3663 PrintF("%s unrecognized\n", argv[next_arg]);
3664 PrintF("Printing 10 double words by default");
3665 words = 10;
3666 }
3667 } else {
3668 UNREACHABLE();
3669 }
3670 end = cur + words;
3671
3672 bool skip_obj_print = (strcmp(cmd, "dump") == 0);
3673 while (cur < end) {
3674 PrintF(" 0x%016" PRIx64 ": 0x%016" PRIx64 " %10" PRId64,
3675 reinterpret_cast<uint64_t>(cur), *cur, *cur);
3676 if (!skip_obj_print) {
3677 Object obj(*cur);
3678 Heap* current_heap = isolate_->heap();
3679 if (obj.IsSmi() ||
3680 IsValidHeapObject(current_heap, HeapObject::cast(obj))) {
3681 PrintF(" (");
3682 if (obj.IsSmi()) {
3683 PrintF("smi %" PRId32, Smi::ToInt(obj));
3684 } else {
3685 obj.ShortPrint();
3686 }
3687 PrintF(")");
3688 }
3689 }
3690 PrintF("\n");
3691 cur++;
3692 }
3693
3694 // trace / t
3695 // -------------------------------------------------------------
3696 } else if (strcmp(cmd, "trace") == 0 || strcmp(cmd, "t") == 0) {
3697 if ((log_parameters() & LOG_ALL) != LOG_ALL) {
3698 PrintF("Enabling disassembly, registers and memory write tracing\n");
3699 set_log_parameters(log_parameters() | LOG_ALL);
3700 } else {
3701 PrintF("Disabling disassembly, registers and memory write tracing\n");
3702 set_log_parameters(log_parameters() & ~LOG_ALL);
3703 }
3704
3705 // break / b
3706 // -------------------------------------------------------------
3707 } else if (strcmp(cmd, "break") == 0 || strcmp(cmd, "b") == 0) {
3708 if (argc == 2) {
3709 int64_t value;
3710 if (GetValue(arg1, &value)) {
3711 SetBreakpoint(reinterpret_cast<Instruction*>(value));
3712 } else {
3713 PrintF("%s unrecognized\n", arg1);
3714 }
3715 } else {
3716 ListBreakpoints();
3717 PrintF("Use `break <address>` to set or disable a breakpoint\n");
3718 }
3719
3720 // backtrace / bt
3721 // ---------------------------------------------------------------
3722 } else if (strcmp(cmd, "backtrace") == 0 || strcmp(cmd, "bt") == 0) {
3723 Address pc = reinterpret_cast<Address>(pc_);
3724 Address lr = reinterpret_cast<Address>(this->lr());
3725 Address sp = static_cast<Address>(this->sp());
3726 Address fp = static_cast<Address>(this->fp());
3727
3728 int i = 0;
3729 while (true) {
3730 PrintF("#%d: " V8PRIxPTR_FMT " (sp=" V8PRIxPTR_FMT ", fp=" V8PRIxPTR_FMT
3731 ")\n",
3732 i, pc, sp, fp);
3733 pc = lr;
3734 sp = fp;
3735 if (pc == reinterpret_cast<Address>(kEndOfSimAddress)) {
3736 break;
3737 }
3738 lr = *(reinterpret_cast<Address*>(fp) + 1);
3739 fp = *reinterpret_cast<Address*>(fp);
3740 i++;
3741 if (i > 100) {
3742 PrintF("Too many frames\n");
3743 break;
3744 }
3745 }
3746
3747 // gdb
3748 // -------------------------------------------------------------------
3749 } else if (strcmp(cmd, "gdb") == 0) {
3750 PrintF("Relinquishing control to gdb.\n");
3751 base::OS::DebugBreak();
3752 PrintF("Regaining control from gdb.\n");
3753
3754 // sysregs
3755 // ---------------------------------------------------------------
3756 } else if (strcmp(cmd, "sysregs") == 0) {
3757 PrintSystemRegisters();
3758
3759 // help / h
3760 // --------------------------------------------------------------
3761 } else if (strcmp(cmd, "help") == 0 || strcmp(cmd, "h") == 0) {
3762 PrintF(
3763 "stepi / si\n"
3764 " stepi <n>\n"
3765 " Step <n> instructions.\n"
3766 "next / n\n"
3767 " Continue execution until a BL instruction is reached.\n"
3768 " At this point a breakpoint is set just after this BL.\n"
3769 " Then execution is resumed. It will probably later hit the\n"
3770 " breakpoint just set.\n"
3771 "continue / cont / c\n"
3772 " Continue execution from here.\n"
3773 "disassemble / disasm / di\n"
3774 " disassemble <n> <address>\n"
3775 " Disassemble <n> instructions from current <address>.\n"
3776 " By default <n> is 20 and <address> is the current pc.\n"
3777 "print / p\n"
3778 " print <register>\n"
3779 " Print the content of a register.\n"
3780 " 'print all' will print all registers.\n"
3781 " Use 'printobject' to get more details about the value.\n"
3782 "printobject / po\n"
3783 " printobject <value>\n"
3784 " printobject <register>\n"
3785 " Print details about the value.\n"
3786 "stack\n"
3787 " stack [<words>]\n"
3788 " Dump stack content, default dump 10 words\n"
3789 "mem\n"
3790 " mem <address> [<words>]\n"
3791 " Dump memory content, default dump 10 words\n"
3792 "dump\n"
3793 " dump <address> [<words>]\n"
3794 " Dump memory content without pretty printing JS objects, "
3795 "default dump 10 words\n"
3796 "trace / t\n"
3797 " Toggle disassembly and register tracing\n"
3798 "break / b\n"
3799 " break : list all breakpoints\n"
3800 " break <address> : set / enable / disable a breakpoint.\n"
3801 "backtrace / bt\n"
3802 " Walk the frame pointers, dumping the pc/sp/fp for each frame.\n"
3803 "gdb\n"
3804 " Enter gdb.\n"
3805 "sysregs\n"
3806 " Print all system registers (including NZCV).\n");
3807 } else {
3808 PrintF("Unknown command: %s\n", cmd);
3809 PrintF("Use 'help' for more information.\n");
3810 }
3811
3812 if (cleared_log_disasm_bit == true) {
3813 set_log_parameters(log_parameters_ | LOG_DISASM);
3814 }
3815 return false;
3816 }
3817
VisitException(Instruction * instr)3818 void Simulator::VisitException(Instruction* instr) {
3819 switch (instr->Mask(ExceptionMask)) {
3820 case HLT: {
3821 if (instr->ImmException() == kImmExceptionIsDebug) {
3822 // Read the arguments encoded inline in the instruction stream.
3823 uint32_t code;
3824 uint32_t parameters;
3825
3826 memcpy(&code, pc_->InstructionAtOffset(kDebugCodeOffset), sizeof(code));
3827 memcpy(¶meters, pc_->InstructionAtOffset(kDebugParamsOffset),
3828 sizeof(parameters));
3829 char const* message = reinterpret_cast<char const*>(
3830 pc_->InstructionAtOffset(kDebugMessageOffset));
3831
3832 // Always print something when we hit a debug point that breaks.
3833 // We are going to break, so printing something is not an issue in
3834 // terms of speed.
3835 if (FLAG_trace_sim_messages || FLAG_trace_sim || (parameters & BREAK)) {
3836 if (message != nullptr) {
3837 PrintF(stream_, "# %sDebugger hit %d: %s%s%s\n", clr_debug_number,
3838 code, clr_debug_message, message, clr_normal);
3839 } else {
3840 PrintF(stream_, "# %sDebugger hit %d.%s\n", clr_debug_number, code,
3841 clr_normal);
3842 }
3843 }
3844
3845 // Other options.
3846 switch (parameters & kDebuggerTracingDirectivesMask) {
3847 case TRACE_ENABLE:
3848 set_log_parameters(log_parameters() | parameters);
3849 if (parameters & LOG_SYS_REGS) {
3850 PrintSystemRegisters();
3851 }
3852 if (parameters & LOG_REGS) {
3853 PrintRegisters();
3854 }
3855 if (parameters & LOG_VREGS) {
3856 PrintVRegisters();
3857 }
3858 break;
3859 case TRACE_DISABLE:
3860 set_log_parameters(log_parameters() & ~parameters);
3861 break;
3862 case TRACE_OVERRIDE:
3863 set_log_parameters(parameters);
3864 break;
3865 default:
3866 // We don't support a one-shot LOG_DISASM.
3867 DCHECK_EQ(parameters & LOG_DISASM, 0);
3868 // Don't print information that is already being traced.
3869 parameters &= ~log_parameters();
3870 // Print the requested information.
3871 if (parameters & LOG_SYS_REGS) PrintSystemRegisters();
3872 if (parameters & LOG_REGS) PrintRegisters();
3873 if (parameters & LOG_VREGS) PrintVRegisters();
3874 }
3875
3876 // The stop parameters are inlined in the code. Skip them:
3877 // - Skip to the end of the message string.
3878 size_t size = kDebugMessageOffset + strlen(message) + 1;
3879 pc_ = pc_->InstructionAtOffset(RoundUp(size, kInstrSize));
3880 // - Verify that the unreachable marker is present.
3881 DCHECK(pc_->Mask(ExceptionMask) == HLT);
3882 DCHECK_EQ(pc_->ImmException(), kImmExceptionIsUnreachable);
3883 // - Skip past the unreachable marker.
3884 set_pc(pc_->following());
3885
3886 // Check if the debugger should break.
3887 if (parameters & BREAK) Debug();
3888
3889 } else if (instr->ImmException() == kImmExceptionIsRedirectedCall) {
3890 DoRuntimeCall(instr);
3891 } else if (instr->ImmException() == kImmExceptionIsPrintf) {
3892 DoPrintf(instr);
3893
3894 } else if (instr->ImmException() == kImmExceptionIsUnreachable) {
3895 fprintf(stream_, "Hit UNREACHABLE marker at PC=%p.\n",
3896 reinterpret_cast<void*>(pc_));
3897 abort();
3898
3899 } else {
3900 base::OS::DebugBreak();
3901 }
3902 break;
3903 }
3904 case BRK:
3905 base::OS::DebugBreak();
3906 break;
3907 default:
3908 UNIMPLEMENTED();
3909 }
3910 }
3911
VisitNEON2RegMisc(Instruction * instr)3912 void Simulator::VisitNEON2RegMisc(Instruction* instr) {
3913 NEONFormatDecoder nfd(instr);
3914 VectorFormat vf = nfd.GetVectorFormat();
3915
3916 // Format mapping for "long pair" instructions, [su]addlp, [su]adalp.
3917 static const NEONFormatMap map_lp = {
3918 {23, 22, 30}, {NF_4H, NF_8H, NF_2S, NF_4S, NF_1D, NF_2D}};
3919 VectorFormat vf_lp = nfd.GetVectorFormat(&map_lp);
3920
3921 static const NEONFormatMap map_fcvtl = {{22}, {NF_4S, NF_2D}};
3922 VectorFormat vf_fcvtl = nfd.GetVectorFormat(&map_fcvtl);
3923
3924 static const NEONFormatMap map_fcvtn = {{22, 30},
3925 {NF_4H, NF_8H, NF_2S, NF_4S}};
3926 VectorFormat vf_fcvtn = nfd.GetVectorFormat(&map_fcvtn);
3927
3928 SimVRegister& rd = vreg(instr->Rd());
3929 SimVRegister& rn = vreg(instr->Rn());
3930
3931 if (instr->Mask(NEON2RegMiscOpcode) <= NEON_NEG_opcode) {
3932 // These instructions all use a two bit size field, except NOT and RBIT,
3933 // which use the field to encode the operation.
3934 switch (instr->Mask(NEON2RegMiscMask)) {
3935 case NEON_REV64:
3936 rev64(vf, rd, rn);
3937 break;
3938 case NEON_REV32:
3939 rev32(vf, rd, rn);
3940 break;
3941 case NEON_REV16:
3942 rev16(vf, rd, rn);
3943 break;
3944 case NEON_SUQADD:
3945 suqadd(vf, rd, rn);
3946 break;
3947 case NEON_USQADD:
3948 usqadd(vf, rd, rn);
3949 break;
3950 case NEON_CLS:
3951 cls(vf, rd, rn);
3952 break;
3953 case NEON_CLZ:
3954 clz(vf, rd, rn);
3955 break;
3956 case NEON_CNT:
3957 cnt(vf, rd, rn);
3958 break;
3959 case NEON_SQABS:
3960 abs(vf, rd, rn).SignedSaturate(vf);
3961 break;
3962 case NEON_SQNEG:
3963 neg(vf, rd, rn).SignedSaturate(vf);
3964 break;
3965 case NEON_CMGT_zero:
3966 cmp(vf, rd, rn, 0, gt);
3967 break;
3968 case NEON_CMGE_zero:
3969 cmp(vf, rd, rn, 0, ge);
3970 break;
3971 case NEON_CMEQ_zero:
3972 cmp(vf, rd, rn, 0, eq);
3973 break;
3974 case NEON_CMLE_zero:
3975 cmp(vf, rd, rn, 0, le);
3976 break;
3977 case NEON_CMLT_zero:
3978 cmp(vf, rd, rn, 0, lt);
3979 break;
3980 case NEON_ABS:
3981 abs(vf, rd, rn);
3982 break;
3983 case NEON_NEG:
3984 neg(vf, rd, rn);
3985 break;
3986 case NEON_SADDLP:
3987 saddlp(vf_lp, rd, rn);
3988 break;
3989 case NEON_UADDLP:
3990 uaddlp(vf_lp, rd, rn);
3991 break;
3992 case NEON_SADALP:
3993 sadalp(vf_lp, rd, rn);
3994 break;
3995 case NEON_UADALP:
3996 uadalp(vf_lp, rd, rn);
3997 break;
3998 case NEON_RBIT_NOT:
3999 vf = nfd.GetVectorFormat(nfd.LogicalFormatMap());
4000 switch (instr->FPType()) {
4001 case 0:
4002 not_(vf, rd, rn);
4003 break;
4004 case 1:
4005 rbit(vf, rd, rn);
4006 break;
4007 default:
4008 UNIMPLEMENTED();
4009 }
4010 break;
4011 }
4012 } else {
4013 VectorFormat fpf = nfd.GetVectorFormat(nfd.FPFormatMap());
4014 FPRounding fpcr_rounding = static_cast<FPRounding>(fpcr().RMode());
4015 bool inexact_exception = false;
4016
4017 // These instructions all use a one bit size field, except XTN, SQXTUN,
4018 // SHLL, SQXTN and UQXTN, which use a two bit size field.
4019 switch (instr->Mask(NEON2RegMiscFPMask)) {
4020 case NEON_FABS:
4021 fabs_(fpf, rd, rn);
4022 return;
4023 case NEON_FNEG:
4024 fneg(fpf, rd, rn);
4025 return;
4026 case NEON_FSQRT:
4027 fsqrt(fpf, rd, rn);
4028 return;
4029 case NEON_FCVTL:
4030 if (instr->Mask(NEON_Q)) {
4031 fcvtl2(vf_fcvtl, rd, rn);
4032 } else {
4033 fcvtl(vf_fcvtl, rd, rn);
4034 }
4035 return;
4036 case NEON_FCVTN:
4037 if (instr->Mask(NEON_Q)) {
4038 fcvtn2(vf_fcvtn, rd, rn);
4039 } else {
4040 fcvtn(vf_fcvtn, rd, rn);
4041 }
4042 return;
4043 case NEON_FCVTXN:
4044 if (instr->Mask(NEON_Q)) {
4045 fcvtxn2(vf_fcvtn, rd, rn);
4046 } else {
4047 fcvtxn(vf_fcvtn, rd, rn);
4048 }
4049 return;
4050
4051 // The following instructions break from the switch statement, rather
4052 // than return.
4053 case NEON_FRINTI:
4054 break; // Use FPCR rounding mode.
4055 case NEON_FRINTX:
4056 inexact_exception = true;
4057 break;
4058 case NEON_FRINTA:
4059 fpcr_rounding = FPTieAway;
4060 break;
4061 case NEON_FRINTM:
4062 fpcr_rounding = FPNegativeInfinity;
4063 break;
4064 case NEON_FRINTN:
4065 fpcr_rounding = FPTieEven;
4066 break;
4067 case NEON_FRINTP:
4068 fpcr_rounding = FPPositiveInfinity;
4069 break;
4070 case NEON_FRINTZ:
4071 fpcr_rounding = FPZero;
4072 break;
4073
4074 // The remaining cases return to the caller.
4075 case NEON_FCVTNS:
4076 fcvts(fpf, rd, rn, FPTieEven);
4077 return;
4078 case NEON_FCVTNU:
4079 fcvtu(fpf, rd, rn, FPTieEven);
4080 return;
4081 case NEON_FCVTPS:
4082 fcvts(fpf, rd, rn, FPPositiveInfinity);
4083 return;
4084 case NEON_FCVTPU:
4085 fcvtu(fpf, rd, rn, FPPositiveInfinity);
4086 return;
4087 case NEON_FCVTMS:
4088 fcvts(fpf, rd, rn, FPNegativeInfinity);
4089 return;
4090 case NEON_FCVTMU:
4091 fcvtu(fpf, rd, rn, FPNegativeInfinity);
4092 return;
4093 case NEON_FCVTZS:
4094 fcvts(fpf, rd, rn, FPZero);
4095 return;
4096 case NEON_FCVTZU:
4097 fcvtu(fpf, rd, rn, FPZero);
4098 return;
4099 case NEON_FCVTAS:
4100 fcvts(fpf, rd, rn, FPTieAway);
4101 return;
4102 case NEON_FCVTAU:
4103 fcvtu(fpf, rd, rn, FPTieAway);
4104 return;
4105 case NEON_SCVTF:
4106 scvtf(fpf, rd, rn, 0, fpcr_rounding);
4107 return;
4108 case NEON_UCVTF:
4109 ucvtf(fpf, rd, rn, 0, fpcr_rounding);
4110 return;
4111 case NEON_URSQRTE:
4112 ursqrte(fpf, rd, rn);
4113 return;
4114 case NEON_URECPE:
4115 urecpe(fpf, rd, rn);
4116 return;
4117 case NEON_FRSQRTE:
4118 frsqrte(fpf, rd, rn);
4119 return;
4120 case NEON_FRECPE:
4121 frecpe(fpf, rd, rn, fpcr_rounding);
4122 return;
4123 case NEON_FCMGT_zero:
4124 fcmp_zero(fpf, rd, rn, gt);
4125 return;
4126 case NEON_FCMGE_zero:
4127 fcmp_zero(fpf, rd, rn, ge);
4128 return;
4129 case NEON_FCMEQ_zero:
4130 fcmp_zero(fpf, rd, rn, eq);
4131 return;
4132 case NEON_FCMLE_zero:
4133 fcmp_zero(fpf, rd, rn, le);
4134 return;
4135 case NEON_FCMLT_zero:
4136 fcmp_zero(fpf, rd, rn, lt);
4137 return;
4138 default:
4139 if ((NEON_XTN_opcode <= instr->Mask(NEON2RegMiscOpcode)) &&
4140 (instr->Mask(NEON2RegMiscOpcode) <= NEON_UQXTN_opcode)) {
4141 switch (instr->Mask(NEON2RegMiscMask)) {
4142 case NEON_XTN:
4143 xtn(vf, rd, rn);
4144 return;
4145 case NEON_SQXTN:
4146 sqxtn(vf, rd, rn);
4147 return;
4148 case NEON_UQXTN:
4149 uqxtn(vf, rd, rn);
4150 return;
4151 case NEON_SQXTUN:
4152 sqxtun(vf, rd, rn);
4153 return;
4154 case NEON_SHLL:
4155 vf = nfd.GetVectorFormat(nfd.LongIntegerFormatMap());
4156 if (instr->Mask(NEON_Q)) {
4157 shll2(vf, rd, rn);
4158 } else {
4159 shll(vf, rd, rn);
4160 }
4161 return;
4162 default:
4163 UNIMPLEMENTED();
4164 }
4165 } else {
4166 UNIMPLEMENTED();
4167 }
4168 }
4169
4170 // Only FRINT* instructions fall through the switch above.
4171 frint(fpf, rd, rn, fpcr_rounding, inexact_exception);
4172 }
4173 }
4174
VisitNEON3Same(Instruction * instr)4175 void Simulator::VisitNEON3Same(Instruction* instr) {
4176 NEONFormatDecoder nfd(instr);
4177 SimVRegister& rd = vreg(instr->Rd());
4178 SimVRegister& rn = vreg(instr->Rn());
4179 SimVRegister& rm = vreg(instr->Rm());
4180
4181 if (instr->Mask(NEON3SameLogicalFMask) == NEON3SameLogicalFixed) {
4182 VectorFormat vf = nfd.GetVectorFormat(nfd.LogicalFormatMap());
4183 switch (instr->Mask(NEON3SameLogicalMask)) {
4184 case NEON_AND:
4185 and_(vf, rd, rn, rm);
4186 break;
4187 case NEON_ORR:
4188 orr(vf, rd, rn, rm);
4189 break;
4190 case NEON_ORN:
4191 orn(vf, rd, rn, rm);
4192 break;
4193 case NEON_EOR:
4194 eor(vf, rd, rn, rm);
4195 break;
4196 case NEON_BIC:
4197 bic(vf, rd, rn, rm);
4198 break;
4199 case NEON_BIF:
4200 bif(vf, rd, rn, rm);
4201 break;
4202 case NEON_BIT:
4203 bit(vf, rd, rn, rm);
4204 break;
4205 case NEON_BSL:
4206 bsl(vf, rd, rn, rm);
4207 break;
4208 default:
4209 UNIMPLEMENTED();
4210 }
4211 } else if (instr->Mask(NEON3SameFPFMask) == NEON3SameFPFixed) {
4212 VectorFormat vf = nfd.GetVectorFormat(nfd.FPFormatMap());
4213 switch (instr->Mask(NEON3SameFPMask)) {
4214 case NEON_FADD:
4215 fadd(vf, rd, rn, rm);
4216 break;
4217 case NEON_FSUB:
4218 fsub(vf, rd, rn, rm);
4219 break;
4220 case NEON_FMUL:
4221 fmul(vf, rd, rn, rm);
4222 break;
4223 case NEON_FDIV:
4224 fdiv(vf, rd, rn, rm);
4225 break;
4226 case NEON_FMAX:
4227 fmax(vf, rd, rn, rm);
4228 break;
4229 case NEON_FMIN:
4230 fmin(vf, rd, rn, rm);
4231 break;
4232 case NEON_FMAXNM:
4233 fmaxnm(vf, rd, rn, rm);
4234 break;
4235 case NEON_FMINNM:
4236 fminnm(vf, rd, rn, rm);
4237 break;
4238 case NEON_FMLA:
4239 fmla(vf, rd, rn, rm);
4240 break;
4241 case NEON_FMLS:
4242 fmls(vf, rd, rn, rm);
4243 break;
4244 case NEON_FMULX:
4245 fmulx(vf, rd, rn, rm);
4246 break;
4247 case NEON_FACGE:
4248 fabscmp(vf, rd, rn, rm, ge);
4249 break;
4250 case NEON_FACGT:
4251 fabscmp(vf, rd, rn, rm, gt);
4252 break;
4253 case NEON_FCMEQ:
4254 fcmp(vf, rd, rn, rm, eq);
4255 break;
4256 case NEON_FCMGE:
4257 fcmp(vf, rd, rn, rm, ge);
4258 break;
4259 case NEON_FCMGT:
4260 fcmp(vf, rd, rn, rm, gt);
4261 break;
4262 case NEON_FRECPS:
4263 frecps(vf, rd, rn, rm);
4264 break;
4265 case NEON_FRSQRTS:
4266 frsqrts(vf, rd, rn, rm);
4267 break;
4268 case NEON_FABD:
4269 fabd(vf, rd, rn, rm);
4270 break;
4271 case NEON_FADDP:
4272 faddp(vf, rd, rn, rm);
4273 break;
4274 case NEON_FMAXP:
4275 fmaxp(vf, rd, rn, rm);
4276 break;
4277 case NEON_FMAXNMP:
4278 fmaxnmp(vf, rd, rn, rm);
4279 break;
4280 case NEON_FMINP:
4281 fminp(vf, rd, rn, rm);
4282 break;
4283 case NEON_FMINNMP:
4284 fminnmp(vf, rd, rn, rm);
4285 break;
4286 default:
4287 UNIMPLEMENTED();
4288 }
4289 } else {
4290 VectorFormat vf = nfd.GetVectorFormat();
4291 switch (instr->Mask(NEON3SameMask)) {
4292 case NEON_ADD:
4293 add(vf, rd, rn, rm);
4294 break;
4295 case NEON_ADDP:
4296 addp(vf, rd, rn, rm);
4297 break;
4298 case NEON_CMEQ:
4299 cmp(vf, rd, rn, rm, eq);
4300 break;
4301 case NEON_CMGE:
4302 cmp(vf, rd, rn, rm, ge);
4303 break;
4304 case NEON_CMGT:
4305 cmp(vf, rd, rn, rm, gt);
4306 break;
4307 case NEON_CMHI:
4308 cmp(vf, rd, rn, rm, hi);
4309 break;
4310 case NEON_CMHS:
4311 cmp(vf, rd, rn, rm, hs);
4312 break;
4313 case NEON_CMTST:
4314 cmptst(vf, rd, rn, rm);
4315 break;
4316 case NEON_MLS:
4317 mls(vf, rd, rn, rm);
4318 break;
4319 case NEON_MLA:
4320 mla(vf, rd, rn, rm);
4321 break;
4322 case NEON_MUL:
4323 mul(vf, rd, rn, rm);
4324 break;
4325 case NEON_PMUL:
4326 pmul(vf, rd, rn, rm);
4327 break;
4328 case NEON_SMAX:
4329 smax(vf, rd, rn, rm);
4330 break;
4331 case NEON_SMAXP:
4332 smaxp(vf, rd, rn, rm);
4333 break;
4334 case NEON_SMIN:
4335 smin(vf, rd, rn, rm);
4336 break;
4337 case NEON_SMINP:
4338 sminp(vf, rd, rn, rm);
4339 break;
4340 case NEON_SUB:
4341 sub(vf, rd, rn, rm);
4342 break;
4343 case NEON_UMAX:
4344 umax(vf, rd, rn, rm);
4345 break;
4346 case NEON_UMAXP:
4347 umaxp(vf, rd, rn, rm);
4348 break;
4349 case NEON_UMIN:
4350 umin(vf, rd, rn, rm);
4351 break;
4352 case NEON_UMINP:
4353 uminp(vf, rd, rn, rm);
4354 break;
4355 case NEON_SSHL:
4356 sshl(vf, rd, rn, rm);
4357 break;
4358 case NEON_USHL:
4359 ushl(vf, rd, rn, rm);
4360 break;
4361 case NEON_SABD:
4362 AbsDiff(vf, rd, rn, rm, true);
4363 break;
4364 case NEON_UABD:
4365 AbsDiff(vf, rd, rn, rm, false);
4366 break;
4367 case NEON_SABA:
4368 saba(vf, rd, rn, rm);
4369 break;
4370 case NEON_UABA:
4371 uaba(vf, rd, rn, rm);
4372 break;
4373 case NEON_UQADD:
4374 add(vf, rd, rn, rm).UnsignedSaturate(vf);
4375 break;
4376 case NEON_SQADD:
4377 add(vf, rd, rn, rm).SignedSaturate(vf);
4378 break;
4379 case NEON_UQSUB:
4380 sub(vf, rd, rn, rm).UnsignedSaturate(vf);
4381 break;
4382 case NEON_SQSUB:
4383 sub(vf, rd, rn, rm).SignedSaturate(vf);
4384 break;
4385 case NEON_SQDMULH:
4386 sqdmulh(vf, rd, rn, rm);
4387 break;
4388 case NEON_SQRDMULH:
4389 sqrdmulh(vf, rd, rn, rm);
4390 break;
4391 case NEON_UQSHL:
4392 ushl(vf, rd, rn, rm).UnsignedSaturate(vf);
4393 break;
4394 case NEON_SQSHL:
4395 sshl(vf, rd, rn, rm).SignedSaturate(vf);
4396 break;
4397 case NEON_URSHL:
4398 ushl(vf, rd, rn, rm).Round(vf);
4399 break;
4400 case NEON_SRSHL:
4401 sshl(vf, rd, rn, rm).Round(vf);
4402 break;
4403 case NEON_UQRSHL:
4404 ushl(vf, rd, rn, rm).Round(vf).UnsignedSaturate(vf);
4405 break;
4406 case NEON_SQRSHL:
4407 sshl(vf, rd, rn, rm).Round(vf).SignedSaturate(vf);
4408 break;
4409 case NEON_UHADD:
4410 add(vf, rd, rn, rm).Uhalve(vf);
4411 break;
4412 case NEON_URHADD:
4413 add(vf, rd, rn, rm).Uhalve(vf).Round(vf);
4414 break;
4415 case NEON_SHADD:
4416 add(vf, rd, rn, rm).Halve(vf);
4417 break;
4418 case NEON_SRHADD:
4419 add(vf, rd, rn, rm).Halve(vf).Round(vf);
4420 break;
4421 case NEON_UHSUB:
4422 sub(vf, rd, rn, rm).Uhalve(vf);
4423 break;
4424 case NEON_SHSUB:
4425 sub(vf, rd, rn, rm).Halve(vf);
4426 break;
4427 default:
4428 UNIMPLEMENTED();
4429 }
4430 }
4431 }
4432
VisitNEON3Different(Instruction * instr)4433 void Simulator::VisitNEON3Different(Instruction* instr) {
4434 NEONFormatDecoder nfd(instr);
4435 VectorFormat vf = nfd.GetVectorFormat();
4436 VectorFormat vf_l = nfd.GetVectorFormat(nfd.LongIntegerFormatMap());
4437
4438 SimVRegister& rd = vreg(instr->Rd());
4439 SimVRegister& rn = vreg(instr->Rn());
4440 SimVRegister& rm = vreg(instr->Rm());
4441
4442 switch (instr->Mask(NEON3DifferentMask)) {
4443 case NEON_PMULL:
4444 pmull(vf_l, rd, rn, rm);
4445 break;
4446 case NEON_PMULL2:
4447 pmull2(vf_l, rd, rn, rm);
4448 break;
4449 case NEON_UADDL:
4450 uaddl(vf_l, rd, rn, rm);
4451 break;
4452 case NEON_UADDL2:
4453 uaddl2(vf_l, rd, rn, rm);
4454 break;
4455 case NEON_SADDL:
4456 saddl(vf_l, rd, rn, rm);
4457 break;
4458 case NEON_SADDL2:
4459 saddl2(vf_l, rd, rn, rm);
4460 break;
4461 case NEON_USUBL:
4462 usubl(vf_l, rd, rn, rm);
4463 break;
4464 case NEON_USUBL2:
4465 usubl2(vf_l, rd, rn, rm);
4466 break;
4467 case NEON_SSUBL:
4468 ssubl(vf_l, rd, rn, rm);
4469 break;
4470 case NEON_SSUBL2:
4471 ssubl2(vf_l, rd, rn, rm);
4472 break;
4473 case NEON_SABAL:
4474 sabal(vf_l, rd, rn, rm);
4475 break;
4476 case NEON_SABAL2:
4477 sabal2(vf_l, rd, rn, rm);
4478 break;
4479 case NEON_UABAL:
4480 uabal(vf_l, rd, rn, rm);
4481 break;
4482 case NEON_UABAL2:
4483 uabal2(vf_l, rd, rn, rm);
4484 break;
4485 case NEON_SABDL:
4486 sabdl(vf_l, rd, rn, rm);
4487 break;
4488 case NEON_SABDL2:
4489 sabdl2(vf_l, rd, rn, rm);
4490 break;
4491 case NEON_UABDL:
4492 uabdl(vf_l, rd, rn, rm);
4493 break;
4494 case NEON_UABDL2:
4495 uabdl2(vf_l, rd, rn, rm);
4496 break;
4497 case NEON_SMLAL:
4498 smlal(vf_l, rd, rn, rm);
4499 break;
4500 case NEON_SMLAL2:
4501 smlal2(vf_l, rd, rn, rm);
4502 break;
4503 case NEON_UMLAL:
4504 umlal(vf_l, rd, rn, rm);
4505 break;
4506 case NEON_UMLAL2:
4507 umlal2(vf_l, rd, rn, rm);
4508 break;
4509 case NEON_SMLSL:
4510 smlsl(vf_l, rd, rn, rm);
4511 break;
4512 case NEON_SMLSL2:
4513 smlsl2(vf_l, rd, rn, rm);
4514 break;
4515 case NEON_UMLSL:
4516 umlsl(vf_l, rd, rn, rm);
4517 break;
4518 case NEON_UMLSL2:
4519 umlsl2(vf_l, rd, rn, rm);
4520 break;
4521 case NEON_SMULL:
4522 smull(vf_l, rd, rn, rm);
4523 break;
4524 case NEON_SMULL2:
4525 smull2(vf_l, rd, rn, rm);
4526 break;
4527 case NEON_UMULL:
4528 umull(vf_l, rd, rn, rm);
4529 break;
4530 case NEON_UMULL2:
4531 umull2(vf_l, rd, rn, rm);
4532 break;
4533 case NEON_SQDMLAL:
4534 sqdmlal(vf_l, rd, rn, rm);
4535 break;
4536 case NEON_SQDMLAL2:
4537 sqdmlal2(vf_l, rd, rn, rm);
4538 break;
4539 case NEON_SQDMLSL:
4540 sqdmlsl(vf_l, rd, rn, rm);
4541 break;
4542 case NEON_SQDMLSL2:
4543 sqdmlsl2(vf_l, rd, rn, rm);
4544 break;
4545 case NEON_SQDMULL:
4546 sqdmull(vf_l, rd, rn, rm);
4547 break;
4548 case NEON_SQDMULL2:
4549 sqdmull2(vf_l, rd, rn, rm);
4550 break;
4551 case NEON_UADDW:
4552 uaddw(vf_l, rd, rn, rm);
4553 break;
4554 case NEON_UADDW2:
4555 uaddw2(vf_l, rd, rn, rm);
4556 break;
4557 case NEON_SADDW:
4558 saddw(vf_l, rd, rn, rm);
4559 break;
4560 case NEON_SADDW2:
4561 saddw2(vf_l, rd, rn, rm);
4562 break;
4563 case NEON_USUBW:
4564 usubw(vf_l, rd, rn, rm);
4565 break;
4566 case NEON_USUBW2:
4567 usubw2(vf_l, rd, rn, rm);
4568 break;
4569 case NEON_SSUBW:
4570 ssubw(vf_l, rd, rn, rm);
4571 break;
4572 case NEON_SSUBW2:
4573 ssubw2(vf_l, rd, rn, rm);
4574 break;
4575 case NEON_ADDHN:
4576 addhn(vf, rd, rn, rm);
4577 break;
4578 case NEON_ADDHN2:
4579 addhn2(vf, rd, rn, rm);
4580 break;
4581 case NEON_RADDHN:
4582 raddhn(vf, rd, rn, rm);
4583 break;
4584 case NEON_RADDHN2:
4585 raddhn2(vf, rd, rn, rm);
4586 break;
4587 case NEON_SUBHN:
4588 subhn(vf, rd, rn, rm);
4589 break;
4590 case NEON_SUBHN2:
4591 subhn2(vf, rd, rn, rm);
4592 break;
4593 case NEON_RSUBHN:
4594 rsubhn(vf, rd, rn, rm);
4595 break;
4596 case NEON_RSUBHN2:
4597 rsubhn2(vf, rd, rn, rm);
4598 break;
4599 default:
4600 UNIMPLEMENTED();
4601 }
4602 }
4603
VisitNEONAcrossLanes(Instruction * instr)4604 void Simulator::VisitNEONAcrossLanes(Instruction* instr) {
4605 NEONFormatDecoder nfd(instr);
4606
4607 SimVRegister& rd = vreg(instr->Rd());
4608 SimVRegister& rn = vreg(instr->Rn());
4609
4610 // The input operand's VectorFormat is passed for these instructions.
4611 if (instr->Mask(NEONAcrossLanesFPFMask) == NEONAcrossLanesFPFixed) {
4612 VectorFormat vf = nfd.GetVectorFormat(nfd.FPFormatMap());
4613
4614 switch (instr->Mask(NEONAcrossLanesFPMask)) {
4615 case NEON_FMAXV:
4616 fmaxv(vf, rd, rn);
4617 break;
4618 case NEON_FMINV:
4619 fminv(vf, rd, rn);
4620 break;
4621 case NEON_FMAXNMV:
4622 fmaxnmv(vf, rd, rn);
4623 break;
4624 case NEON_FMINNMV:
4625 fminnmv(vf, rd, rn);
4626 break;
4627 default:
4628 UNIMPLEMENTED();
4629 }
4630 } else {
4631 VectorFormat vf = nfd.GetVectorFormat();
4632
4633 switch (instr->Mask(NEONAcrossLanesMask)) {
4634 case NEON_ADDV:
4635 addv(vf, rd, rn);
4636 break;
4637 case NEON_SMAXV:
4638 smaxv(vf, rd, rn);
4639 break;
4640 case NEON_SMINV:
4641 sminv(vf, rd, rn);
4642 break;
4643 case NEON_UMAXV:
4644 umaxv(vf, rd, rn);
4645 break;
4646 case NEON_UMINV:
4647 uminv(vf, rd, rn);
4648 break;
4649 case NEON_SADDLV:
4650 saddlv(vf, rd, rn);
4651 break;
4652 case NEON_UADDLV:
4653 uaddlv(vf, rd, rn);
4654 break;
4655 default:
4656 UNIMPLEMENTED();
4657 }
4658 }
4659 }
4660
VisitNEONByIndexedElement(Instruction * instr)4661 void Simulator::VisitNEONByIndexedElement(Instruction* instr) {
4662 NEONFormatDecoder nfd(instr);
4663 VectorFormat vf_r = nfd.GetVectorFormat();
4664 VectorFormat vf = nfd.GetVectorFormat(nfd.LongIntegerFormatMap());
4665
4666 SimVRegister& rd = vreg(instr->Rd());
4667 SimVRegister& rn = vreg(instr->Rn());
4668
4669 ByElementOp Op = nullptr;
4670
4671 int rm_reg = instr->Rm();
4672 int index = (instr->NEONH() << 1) | instr->NEONL();
4673 if (instr->NEONSize() == 1) {
4674 rm_reg &= 0xF;
4675 index = (index << 1) | instr->NEONM();
4676 }
4677
4678 switch (instr->Mask(NEONByIndexedElementMask)) {
4679 case NEON_MUL_byelement:
4680 Op = &Simulator::mul;
4681 vf = vf_r;
4682 break;
4683 case NEON_MLA_byelement:
4684 Op = &Simulator::mla;
4685 vf = vf_r;
4686 break;
4687 case NEON_MLS_byelement:
4688 Op = &Simulator::mls;
4689 vf = vf_r;
4690 break;
4691 case NEON_SQDMULH_byelement:
4692 Op = &Simulator::sqdmulh;
4693 vf = vf_r;
4694 break;
4695 case NEON_SQRDMULH_byelement:
4696 Op = &Simulator::sqrdmulh;
4697 vf = vf_r;
4698 break;
4699 case NEON_SMULL_byelement:
4700 if (instr->Mask(NEON_Q)) {
4701 Op = &Simulator::smull2;
4702 } else {
4703 Op = &Simulator::smull;
4704 }
4705 break;
4706 case NEON_UMULL_byelement:
4707 if (instr->Mask(NEON_Q)) {
4708 Op = &Simulator::umull2;
4709 } else {
4710 Op = &Simulator::umull;
4711 }
4712 break;
4713 case NEON_SMLAL_byelement:
4714 if (instr->Mask(NEON_Q)) {
4715 Op = &Simulator::smlal2;
4716 } else {
4717 Op = &Simulator::smlal;
4718 }
4719 break;
4720 case NEON_UMLAL_byelement:
4721 if (instr->Mask(NEON_Q)) {
4722 Op = &Simulator::umlal2;
4723 } else {
4724 Op = &Simulator::umlal;
4725 }
4726 break;
4727 case NEON_SMLSL_byelement:
4728 if (instr->Mask(NEON_Q)) {
4729 Op = &Simulator::smlsl2;
4730 } else {
4731 Op = &Simulator::smlsl;
4732 }
4733 break;
4734 case NEON_UMLSL_byelement:
4735 if (instr->Mask(NEON_Q)) {
4736 Op = &Simulator::umlsl2;
4737 } else {
4738 Op = &Simulator::umlsl;
4739 }
4740 break;
4741 case NEON_SQDMULL_byelement:
4742 if (instr->Mask(NEON_Q)) {
4743 Op = &Simulator::sqdmull2;
4744 } else {
4745 Op = &Simulator::sqdmull;
4746 }
4747 break;
4748 case NEON_SQDMLAL_byelement:
4749 if (instr->Mask(NEON_Q)) {
4750 Op = &Simulator::sqdmlal2;
4751 } else {
4752 Op = &Simulator::sqdmlal;
4753 }
4754 break;
4755 case NEON_SQDMLSL_byelement:
4756 if (instr->Mask(NEON_Q)) {
4757 Op = &Simulator::sqdmlsl2;
4758 } else {
4759 Op = &Simulator::sqdmlsl;
4760 }
4761 break;
4762 default:
4763 index = instr->NEONH();
4764 if ((instr->FPType() & 1) == 0) {
4765 index = (index << 1) | instr->NEONL();
4766 }
4767
4768 vf = nfd.GetVectorFormat(nfd.FPFormatMap());
4769
4770 switch (instr->Mask(NEONByIndexedElementFPMask)) {
4771 case NEON_FMUL_byelement:
4772 Op = &Simulator::fmul;
4773 break;
4774 case NEON_FMLA_byelement:
4775 Op = &Simulator::fmla;
4776 break;
4777 case NEON_FMLS_byelement:
4778 Op = &Simulator::fmls;
4779 break;
4780 case NEON_FMULX_byelement:
4781 Op = &Simulator::fmulx;
4782 break;
4783 default:
4784 UNIMPLEMENTED();
4785 }
4786 }
4787
4788 (this->*Op)(vf, rd, rn, vreg(rm_reg), index);
4789 }
4790
VisitNEONCopy(Instruction * instr)4791 void Simulator::VisitNEONCopy(Instruction* instr) {
4792 NEONFormatDecoder nfd(instr, NEONFormatDecoder::TriangularFormatMap());
4793 VectorFormat vf = nfd.GetVectorFormat();
4794
4795 SimVRegister& rd = vreg(instr->Rd());
4796 SimVRegister& rn = vreg(instr->Rn());
4797 int imm5 = instr->ImmNEON5();
4798 int lsb = LowestSetBitPosition(imm5);
4799 int reg_index = imm5 >> lsb;
4800
4801 if (instr->Mask(NEONCopyInsElementMask) == NEON_INS_ELEMENT) {
4802 int imm4 = instr->ImmNEON4();
4803 DCHECK_GE(lsb, 1);
4804 int rn_index = imm4 >> (lsb - 1);
4805 ins_element(vf, rd, reg_index, rn, rn_index);
4806 } else if (instr->Mask(NEONCopyInsGeneralMask) == NEON_INS_GENERAL) {
4807 ins_immediate(vf, rd, reg_index, xreg(instr->Rn()));
4808 } else if (instr->Mask(NEONCopyUmovMask) == NEON_UMOV) {
4809 uint64_t value = LogicVRegister(rn).Uint(vf, reg_index);
4810 value &= MaxUintFromFormat(vf);
4811 set_xreg(instr->Rd(), value);
4812 } else if (instr->Mask(NEONCopyUmovMask) == NEON_SMOV) {
4813 int64_t value = LogicVRegister(rn).Int(vf, reg_index);
4814 if (instr->NEONQ()) {
4815 set_xreg(instr->Rd(), value);
4816 } else {
4817 DCHECK(is_int32(value));
4818 set_wreg(instr->Rd(), static_cast<int32_t>(value));
4819 }
4820 } else if (instr->Mask(NEONCopyDupElementMask) == NEON_DUP_ELEMENT) {
4821 dup_element(vf, rd, rn, reg_index);
4822 } else if (instr->Mask(NEONCopyDupGeneralMask) == NEON_DUP_GENERAL) {
4823 dup_immediate(vf, rd, xreg(instr->Rn()));
4824 } else {
4825 UNIMPLEMENTED();
4826 }
4827 }
4828
VisitNEONExtract(Instruction * instr)4829 void Simulator::VisitNEONExtract(Instruction* instr) {
4830 NEONFormatDecoder nfd(instr, NEONFormatDecoder::LogicalFormatMap());
4831 VectorFormat vf = nfd.GetVectorFormat();
4832 SimVRegister& rd = vreg(instr->Rd());
4833 SimVRegister& rn = vreg(instr->Rn());
4834 SimVRegister& rm = vreg(instr->Rm());
4835 if (instr->Mask(NEONExtractMask) == NEON_EXT) {
4836 int index = instr->ImmNEONExt();
4837 ext(vf, rd, rn, rm, index);
4838 } else {
4839 UNIMPLEMENTED();
4840 }
4841 }
4842
NEONLoadStoreMultiStructHelper(const Instruction * instr,AddrMode addr_mode)4843 void Simulator::NEONLoadStoreMultiStructHelper(const Instruction* instr,
4844 AddrMode addr_mode) {
4845 NEONFormatDecoder nfd(instr, NEONFormatDecoder::LoadStoreFormatMap());
4846 VectorFormat vf = nfd.GetVectorFormat();
4847
4848 uint64_t addr_base = xreg(instr->Rn(), Reg31IsStackPointer);
4849 int reg_size = RegisterSizeInBytesFromFormat(vf);
4850
4851 int reg[4];
4852 uint64_t addr[4];
4853 for (int i = 0; i < 4; i++) {
4854 reg[i] = (instr->Rt() + i) % kNumberOfVRegisters;
4855 addr[i] = addr_base + (i * reg_size);
4856 }
4857 int count = 1;
4858 bool log_read = true;
4859
4860 // Bit 23 determines whether this is an offset or post-index addressing mode.
4861 // In offset mode, bits 20 to 16 should be zero; these bits encode the
4862 // register of immediate in post-index mode.
4863 if ((instr->Bit(23) == 0) && (instr->Bits(20, 16) != 0)) {
4864 UNREACHABLE();
4865 }
4866
4867 // We use the PostIndex mask here, as it works in this case for both Offset
4868 // and PostIndex addressing.
4869 switch (instr->Mask(NEONLoadStoreMultiStructPostIndexMask)) {
4870 case NEON_LD1_4v:
4871 case NEON_LD1_4v_post:
4872 ld1(vf, vreg(reg[3]), addr[3]);
4873 count++;
4874 V8_FALLTHROUGH;
4875 case NEON_LD1_3v:
4876 case NEON_LD1_3v_post:
4877 ld1(vf, vreg(reg[2]), addr[2]);
4878 count++;
4879 V8_FALLTHROUGH;
4880 case NEON_LD1_2v:
4881 case NEON_LD1_2v_post:
4882 ld1(vf, vreg(reg[1]), addr[1]);
4883 count++;
4884 V8_FALLTHROUGH;
4885 case NEON_LD1_1v:
4886 case NEON_LD1_1v_post:
4887 ld1(vf, vreg(reg[0]), addr[0]);
4888 break;
4889 case NEON_ST1_4v:
4890 case NEON_ST1_4v_post:
4891 st1(vf, vreg(reg[3]), addr[3]);
4892 count++;
4893 V8_FALLTHROUGH;
4894 case NEON_ST1_3v:
4895 case NEON_ST1_3v_post:
4896 st1(vf, vreg(reg[2]), addr[2]);
4897 count++;
4898 V8_FALLTHROUGH;
4899 case NEON_ST1_2v:
4900 case NEON_ST1_2v_post:
4901 st1(vf, vreg(reg[1]), addr[1]);
4902 count++;
4903 V8_FALLTHROUGH;
4904 case NEON_ST1_1v:
4905 case NEON_ST1_1v_post:
4906 st1(vf, vreg(reg[0]), addr[0]);
4907 log_read = false;
4908 break;
4909 case NEON_LD2_post:
4910 case NEON_LD2:
4911 ld2(vf, vreg(reg[0]), vreg(reg[1]), addr[0]);
4912 count = 2;
4913 break;
4914 case NEON_ST2:
4915 case NEON_ST2_post:
4916 st2(vf, vreg(reg[0]), vreg(reg[1]), addr[0]);
4917 count = 2;
4918 log_read = false;
4919 break;
4920 case NEON_LD3_post:
4921 case NEON_LD3:
4922 ld3(vf, vreg(reg[0]), vreg(reg[1]), vreg(reg[2]), addr[0]);
4923 count = 3;
4924 break;
4925 case NEON_ST3:
4926 case NEON_ST3_post:
4927 st3(vf, vreg(reg[0]), vreg(reg[1]), vreg(reg[2]), addr[0]);
4928 count = 3;
4929 log_read = false;
4930 break;
4931 case NEON_LD4_post:
4932 case NEON_LD4:
4933 ld4(vf, vreg(reg[0]), vreg(reg[1]), vreg(reg[2]), vreg(reg[3]), addr[0]);
4934 count = 4;
4935 break;
4936 case NEON_ST4:
4937 case NEON_ST4_post:
4938 st4(vf, vreg(reg[0]), vreg(reg[1]), vreg(reg[2]), vreg(reg[3]), addr[0]);
4939 count = 4;
4940 log_read = false;
4941 break;
4942 default:
4943 UNIMPLEMENTED();
4944 }
4945
4946 {
4947 base::MutexGuard lock_guard(&GlobalMonitor::Get()->mutex);
4948 if (log_read) {
4949 local_monitor_.NotifyLoad();
4950 } else {
4951 local_monitor_.NotifyStore();
4952 GlobalMonitor::Get()->NotifyStore_Locked(&global_monitor_processor_);
4953 }
4954 }
4955
4956 // Explicitly log the register update whilst we have type information.
4957 for (int i = 0; i < count; i++) {
4958 // For de-interleaving loads, only print the base address.
4959 int lane_size = LaneSizeInBytesFromFormat(vf);
4960 PrintRegisterFormat format = GetPrintRegisterFormatTryFP(
4961 GetPrintRegisterFormatForSize(reg_size, lane_size));
4962 if (log_read) {
4963 LogVRead(addr_base, reg[i], format);
4964 } else {
4965 LogVWrite(addr_base, reg[i], format);
4966 }
4967 }
4968
4969 if (addr_mode == PostIndex) {
4970 int rm = instr->Rm();
4971 // The immediate post index addressing mode is indicated by rm = 31.
4972 // The immediate is implied by the number of vector registers used.
4973 addr_base +=
4974 (rm == 31) ? RegisterSizeInBytesFromFormat(vf) * count : xreg(rm);
4975 set_xreg(instr->Rn(), addr_base);
4976 } else {
4977 DCHECK_EQ(addr_mode, Offset);
4978 }
4979 }
4980
VisitNEONLoadStoreMultiStruct(Instruction * instr)4981 void Simulator::VisitNEONLoadStoreMultiStruct(Instruction* instr) {
4982 NEONLoadStoreMultiStructHelper(instr, Offset);
4983 }
4984
VisitNEONLoadStoreMultiStructPostIndex(Instruction * instr)4985 void Simulator::VisitNEONLoadStoreMultiStructPostIndex(Instruction* instr) {
4986 NEONLoadStoreMultiStructHelper(instr, PostIndex);
4987 }
4988
NEONLoadStoreSingleStructHelper(const Instruction * instr,AddrMode addr_mode)4989 void Simulator::NEONLoadStoreSingleStructHelper(const Instruction* instr,
4990 AddrMode addr_mode) {
4991 uint64_t addr = xreg(instr->Rn(), Reg31IsStackPointer);
4992 int rt = instr->Rt();
4993
4994 // Bit 23 determines whether this is an offset or post-index addressing mode.
4995 // In offset mode, bits 20 to 16 should be zero; these bits encode the
4996 // register of immediate in post-index mode.
4997 DCHECK_IMPLIES(instr->Bit(23) == 0, instr->Bits(20, 16) == 0);
4998
4999 bool do_load = false;
5000
5001 NEONFormatDecoder nfd(instr, NEONFormatDecoder::LoadStoreFormatMap());
5002 VectorFormat vf_t = nfd.GetVectorFormat();
5003
5004 VectorFormat vf = kFormat16B;
5005 // We use the PostIndex mask here, as it works in this case for both Offset
5006 // and PostIndex addressing.
5007 switch (instr->Mask(NEONLoadStoreSingleStructPostIndexMask)) {
5008 case NEON_LD1_b:
5009 case NEON_LD1_b_post:
5010 case NEON_LD2_b:
5011 case NEON_LD2_b_post:
5012 case NEON_LD3_b:
5013 case NEON_LD3_b_post:
5014 case NEON_LD4_b:
5015 case NEON_LD4_b_post:
5016 do_load = true;
5017 V8_FALLTHROUGH;
5018 case NEON_ST1_b:
5019 case NEON_ST1_b_post:
5020 case NEON_ST2_b:
5021 case NEON_ST2_b_post:
5022 case NEON_ST3_b:
5023 case NEON_ST3_b_post:
5024 case NEON_ST4_b:
5025 case NEON_ST4_b_post:
5026 break;
5027
5028 case NEON_LD1_h:
5029 case NEON_LD1_h_post:
5030 case NEON_LD2_h:
5031 case NEON_LD2_h_post:
5032 case NEON_LD3_h:
5033 case NEON_LD3_h_post:
5034 case NEON_LD4_h:
5035 case NEON_LD4_h_post:
5036 do_load = true;
5037 V8_FALLTHROUGH;
5038 case NEON_ST1_h:
5039 case NEON_ST1_h_post:
5040 case NEON_ST2_h:
5041 case NEON_ST2_h_post:
5042 case NEON_ST3_h:
5043 case NEON_ST3_h_post:
5044 case NEON_ST4_h:
5045 case NEON_ST4_h_post:
5046 vf = kFormat8H;
5047 break;
5048
5049 case NEON_LD1_s:
5050 case NEON_LD1_s_post:
5051 case NEON_LD2_s:
5052 case NEON_LD2_s_post:
5053 case NEON_LD3_s:
5054 case NEON_LD3_s_post:
5055 case NEON_LD4_s:
5056 case NEON_LD4_s_post:
5057 do_load = true;
5058 V8_FALLTHROUGH;
5059 case NEON_ST1_s:
5060 case NEON_ST1_s_post:
5061 case NEON_ST2_s:
5062 case NEON_ST2_s_post:
5063 case NEON_ST3_s:
5064 case NEON_ST3_s_post:
5065 case NEON_ST4_s:
5066 case NEON_ST4_s_post: {
5067 static_assert((NEON_LD1_s | (1 << NEONLSSize_offset)) == NEON_LD1_d,
5068 "LSB of size distinguishes S and D registers.");
5069 static_assert(
5070 (NEON_LD1_s_post | (1 << NEONLSSize_offset)) == NEON_LD1_d_post,
5071 "LSB of size distinguishes S and D registers.");
5072 static_assert((NEON_ST1_s | (1 << NEONLSSize_offset)) == NEON_ST1_d,
5073 "LSB of size distinguishes S and D registers.");
5074 static_assert(
5075 (NEON_ST1_s_post | (1 << NEONLSSize_offset)) == NEON_ST1_d_post,
5076 "LSB of size distinguishes S and D registers.");
5077 vf = ((instr->NEONLSSize() & 1) == 0) ? kFormat4S : kFormat2D;
5078 break;
5079 }
5080
5081 case NEON_LD1R:
5082 case NEON_LD1R_post: {
5083 vf = vf_t;
5084 if (!ProbeMemory(addr, LaneSizeInBytesFromFormat(vf))) return;
5085 ld1r(vf, vreg(rt), addr);
5086 do_load = true;
5087 break;
5088 }
5089
5090 case NEON_LD2R:
5091 case NEON_LD2R_post: {
5092 vf = vf_t;
5093 if (!ProbeMemory(addr, 2 * LaneSizeInBytesFromFormat(vf))) return;
5094 int rt2 = (rt + 1) % kNumberOfVRegisters;
5095 ld2r(vf, vreg(rt), vreg(rt2), addr);
5096 do_load = true;
5097 break;
5098 }
5099
5100 case NEON_LD3R:
5101 case NEON_LD3R_post: {
5102 vf = vf_t;
5103 if (!ProbeMemory(addr, 3 * LaneSizeInBytesFromFormat(vf))) return;
5104 int rt2 = (rt + 1) % kNumberOfVRegisters;
5105 int rt3 = (rt2 + 1) % kNumberOfVRegisters;
5106 ld3r(vf, vreg(rt), vreg(rt2), vreg(rt3), addr);
5107 do_load = true;
5108 break;
5109 }
5110
5111 case NEON_LD4R:
5112 case NEON_LD4R_post: {
5113 vf = vf_t;
5114 if (!ProbeMemory(addr, 4 * LaneSizeInBytesFromFormat(vf))) return;
5115 int rt2 = (rt + 1) % kNumberOfVRegisters;
5116 int rt3 = (rt2 + 1) % kNumberOfVRegisters;
5117 int rt4 = (rt3 + 1) % kNumberOfVRegisters;
5118 ld4r(vf, vreg(rt), vreg(rt2), vreg(rt3), vreg(rt4), addr);
5119 do_load = true;
5120 break;
5121 }
5122 default:
5123 UNIMPLEMENTED();
5124 }
5125
5126 PrintRegisterFormat print_format =
5127 GetPrintRegisterFormatTryFP(GetPrintRegisterFormat(vf));
5128 // Make sure that the print_format only includes a single lane.
5129 print_format =
5130 static_cast<PrintRegisterFormat>(print_format & ~kPrintRegAsVectorMask);
5131
5132 int esize = LaneSizeInBytesFromFormat(vf);
5133 int index_shift = LaneSizeInBytesLog2FromFormat(vf);
5134 int lane = instr->NEONLSIndex(index_shift);
5135 int scale = 0;
5136 int rt2 = (rt + 1) % kNumberOfVRegisters;
5137 int rt3 = (rt2 + 1) % kNumberOfVRegisters;
5138 int rt4 = (rt3 + 1) % kNumberOfVRegisters;
5139 switch (instr->Mask(NEONLoadStoreSingleLenMask)) {
5140 case NEONLoadStoreSingle1:
5141 scale = 1;
5142 if (!ProbeMemory(addr, scale * esize)) return;
5143 if (do_load) {
5144 ld1(vf, vreg(rt), lane, addr);
5145 LogVRead(addr, rt, print_format, lane);
5146 } else {
5147 st1(vf, vreg(rt), lane, addr);
5148 LogVWrite(addr, rt, print_format, lane);
5149 }
5150 break;
5151 case NEONLoadStoreSingle2:
5152 scale = 2;
5153 if (!ProbeMemory(addr, scale * esize)) return;
5154 if (do_load) {
5155 ld2(vf, vreg(rt), vreg(rt2), lane, addr);
5156 LogVRead(addr, rt, print_format, lane);
5157 LogVRead(addr + esize, rt2, print_format, lane);
5158 } else {
5159 st2(vf, vreg(rt), vreg(rt2), lane, addr);
5160 LogVWrite(addr, rt, print_format, lane);
5161 LogVWrite(addr + esize, rt2, print_format, lane);
5162 }
5163 break;
5164 case NEONLoadStoreSingle3:
5165 scale = 3;
5166 if (!ProbeMemory(addr, scale * esize)) return;
5167 if (do_load) {
5168 ld3(vf, vreg(rt), vreg(rt2), vreg(rt3), lane, addr);
5169 LogVRead(addr, rt, print_format, lane);
5170 LogVRead(addr + esize, rt2, print_format, lane);
5171 LogVRead(addr + (2 * esize), rt3, print_format, lane);
5172 } else {
5173 st3(vf, vreg(rt), vreg(rt2), vreg(rt3), lane, addr);
5174 LogVWrite(addr, rt, print_format, lane);
5175 LogVWrite(addr + esize, rt2, print_format, lane);
5176 LogVWrite(addr + (2 * esize), rt3, print_format, lane);
5177 }
5178 break;
5179 case NEONLoadStoreSingle4:
5180 scale = 4;
5181 if (!ProbeMemory(addr, scale * esize)) return;
5182 if (do_load) {
5183 ld4(vf, vreg(rt), vreg(rt2), vreg(rt3), vreg(rt4), lane, addr);
5184 LogVRead(addr, rt, print_format, lane);
5185 LogVRead(addr + esize, rt2, print_format, lane);
5186 LogVRead(addr + (2 * esize), rt3, print_format, lane);
5187 LogVRead(addr + (3 * esize), rt4, print_format, lane);
5188 } else {
5189 st4(vf, vreg(rt), vreg(rt2), vreg(rt3), vreg(rt4), lane, addr);
5190 LogVWrite(addr, rt, print_format, lane);
5191 LogVWrite(addr + esize, rt2, print_format, lane);
5192 LogVWrite(addr + (2 * esize), rt3, print_format, lane);
5193 LogVWrite(addr + (3 * esize), rt4, print_format, lane);
5194 }
5195 break;
5196 default:
5197 UNIMPLEMENTED();
5198 }
5199
5200 {
5201 base::MutexGuard lock_guard(&GlobalMonitor::Get()->mutex);
5202 if (do_load) {
5203 local_monitor_.NotifyLoad();
5204 } else {
5205 local_monitor_.NotifyStore();
5206 GlobalMonitor::Get()->NotifyStore_Locked(&global_monitor_processor_);
5207 }
5208 }
5209
5210 if (addr_mode == PostIndex) {
5211 int rm = instr->Rm();
5212 int lane_size = LaneSizeInBytesFromFormat(vf);
5213 set_xreg(instr->Rn(), addr + ((rm == 31) ? (scale * lane_size) : xreg(rm)));
5214 }
5215 }
5216
VisitNEONLoadStoreSingleStruct(Instruction * instr)5217 void Simulator::VisitNEONLoadStoreSingleStruct(Instruction* instr) {
5218 NEONLoadStoreSingleStructHelper(instr, Offset);
5219 }
5220
VisitNEONLoadStoreSingleStructPostIndex(Instruction * instr)5221 void Simulator::VisitNEONLoadStoreSingleStructPostIndex(Instruction* instr) {
5222 NEONLoadStoreSingleStructHelper(instr, PostIndex);
5223 }
5224
VisitNEONModifiedImmediate(Instruction * instr)5225 void Simulator::VisitNEONModifiedImmediate(Instruction* instr) {
5226 SimVRegister& rd = vreg(instr->Rd());
5227 int cmode = instr->NEONCmode();
5228 int cmode_3_1 = (cmode >> 1) & 7;
5229 int cmode_3 = (cmode >> 3) & 1;
5230 int cmode_2 = (cmode >> 2) & 1;
5231 int cmode_1 = (cmode >> 1) & 1;
5232 int cmode_0 = cmode & 1;
5233 int q = instr->NEONQ();
5234 int op_bit = instr->NEONModImmOp();
5235 uint64_t imm8 = instr->ImmNEONabcdefgh();
5236
5237 // Find the format and immediate value
5238 uint64_t imm = 0;
5239 VectorFormat vform = kFormatUndefined;
5240 switch (cmode_3_1) {
5241 case 0x0:
5242 case 0x1:
5243 case 0x2:
5244 case 0x3:
5245 vform = (q == 1) ? kFormat4S : kFormat2S;
5246 imm = imm8 << (8 * cmode_3_1);
5247 break;
5248 case 0x4:
5249 case 0x5:
5250 vform = (q == 1) ? kFormat8H : kFormat4H;
5251 imm = imm8 << (8 * cmode_1);
5252 break;
5253 case 0x6:
5254 vform = (q == 1) ? kFormat4S : kFormat2S;
5255 if (cmode_0 == 0) {
5256 imm = imm8 << 8 | 0x000000FF;
5257 } else {
5258 imm = imm8 << 16 | 0x0000FFFF;
5259 }
5260 break;
5261 case 0x7:
5262 if (cmode_0 == 0 && op_bit == 0) {
5263 vform = q ? kFormat16B : kFormat8B;
5264 imm = imm8;
5265 } else if (cmode_0 == 0 && op_bit == 1) {
5266 vform = q ? kFormat2D : kFormat1D;
5267 imm = 0;
5268 for (int i = 0; i < 8; ++i) {
5269 if (imm8 & (1ULL << i)) {
5270 imm |= (UINT64_C(0xFF) << (8 * i));
5271 }
5272 }
5273 } else { // cmode_0 == 1, cmode == 0xF.
5274 if (op_bit == 0) {
5275 vform = q ? kFormat4S : kFormat2S;
5276 imm = bit_cast<uint32_t>(instr->ImmNEONFP32());
5277 } else if (q == 1) {
5278 vform = kFormat2D;
5279 imm = bit_cast<uint64_t>(instr->ImmNEONFP64());
5280 } else {
5281 DCHECK((q == 0) && (op_bit == 1) && (cmode == 0xF));
5282 VisitUnallocated(instr);
5283 }
5284 }
5285 break;
5286 default:
5287 UNREACHABLE();
5288 }
5289
5290 // Find the operation.
5291 NEONModifiedImmediateOp op;
5292 if (cmode_3 == 0) {
5293 if (cmode_0 == 0) {
5294 op = op_bit ? NEONModifiedImmediate_MVNI : NEONModifiedImmediate_MOVI;
5295 } else { // cmode<0> == '1'
5296 op = op_bit ? NEONModifiedImmediate_BIC : NEONModifiedImmediate_ORR;
5297 }
5298 } else { // cmode<3> == '1'
5299 if (cmode_2 == 0) {
5300 if (cmode_0 == 0) {
5301 op = op_bit ? NEONModifiedImmediate_MVNI : NEONModifiedImmediate_MOVI;
5302 } else { // cmode<0> == '1'
5303 op = op_bit ? NEONModifiedImmediate_BIC : NEONModifiedImmediate_ORR;
5304 }
5305 } else { // cmode<2> == '1'
5306 if (cmode_1 == 0) {
5307 op = op_bit ? NEONModifiedImmediate_MVNI : NEONModifiedImmediate_MOVI;
5308 } else { // cmode<1> == '1'
5309 if (cmode_0 == 0) {
5310 op = NEONModifiedImmediate_MOVI;
5311 } else { // cmode<0> == '1'
5312 op = NEONModifiedImmediate_MOVI;
5313 }
5314 }
5315 }
5316 }
5317
5318 // Call the logic function.
5319 switch (op) {
5320 case NEONModifiedImmediate_ORR:
5321 orr(vform, rd, rd, imm);
5322 break;
5323 case NEONModifiedImmediate_BIC:
5324 bic(vform, rd, rd, imm);
5325 break;
5326 case NEONModifiedImmediate_MOVI:
5327 movi(vform, rd, imm);
5328 break;
5329 case NEONModifiedImmediate_MVNI:
5330 mvni(vform, rd, imm);
5331 break;
5332 default:
5333 VisitUnimplemented(instr);
5334 }
5335 }
5336
VisitNEONScalar2RegMisc(Instruction * instr)5337 void Simulator::VisitNEONScalar2RegMisc(Instruction* instr) {
5338 NEONFormatDecoder nfd(instr, NEONFormatDecoder::ScalarFormatMap());
5339 VectorFormat vf = nfd.GetVectorFormat();
5340
5341 SimVRegister& rd = vreg(instr->Rd());
5342 SimVRegister& rn = vreg(instr->Rn());
5343
5344 if (instr->Mask(NEON2RegMiscOpcode) <= NEON_NEG_scalar_opcode) {
5345 // These instructions all use a two bit size field, except NOT and RBIT,
5346 // which use the field to encode the operation.
5347 switch (instr->Mask(NEONScalar2RegMiscMask)) {
5348 case NEON_CMEQ_zero_scalar:
5349 cmp(vf, rd, rn, 0, eq);
5350 break;
5351 case NEON_CMGE_zero_scalar:
5352 cmp(vf, rd, rn, 0, ge);
5353 break;
5354 case NEON_CMGT_zero_scalar:
5355 cmp(vf, rd, rn, 0, gt);
5356 break;
5357 case NEON_CMLT_zero_scalar:
5358 cmp(vf, rd, rn, 0, lt);
5359 break;
5360 case NEON_CMLE_zero_scalar:
5361 cmp(vf, rd, rn, 0, le);
5362 break;
5363 case NEON_ABS_scalar:
5364 abs(vf, rd, rn);
5365 break;
5366 case NEON_SQABS_scalar:
5367 abs(vf, rd, rn).SignedSaturate(vf);
5368 break;
5369 case NEON_NEG_scalar:
5370 neg(vf, rd, rn);
5371 break;
5372 case NEON_SQNEG_scalar:
5373 neg(vf, rd, rn).SignedSaturate(vf);
5374 break;
5375 case NEON_SUQADD_scalar:
5376 suqadd(vf, rd, rn);
5377 break;
5378 case NEON_USQADD_scalar:
5379 usqadd(vf, rd, rn);
5380 break;
5381 default:
5382 UNIMPLEMENTED();
5383 }
5384 } else {
5385 VectorFormat fpf = nfd.GetVectorFormat(nfd.FPScalarFormatMap());
5386 FPRounding fpcr_rounding = static_cast<FPRounding>(fpcr().RMode());
5387
5388 // These instructions all use a one bit size field, except SQXTUN, SQXTN
5389 // and UQXTN, which use a two bit size field.
5390 switch (instr->Mask(NEONScalar2RegMiscFPMask)) {
5391 case NEON_FRECPE_scalar:
5392 frecpe(fpf, rd, rn, fpcr_rounding);
5393 break;
5394 case NEON_FRECPX_scalar:
5395 frecpx(fpf, rd, rn);
5396 break;
5397 case NEON_FRSQRTE_scalar:
5398 frsqrte(fpf, rd, rn);
5399 break;
5400 case NEON_FCMGT_zero_scalar:
5401 fcmp_zero(fpf, rd, rn, gt);
5402 break;
5403 case NEON_FCMGE_zero_scalar:
5404 fcmp_zero(fpf, rd, rn, ge);
5405 break;
5406 case NEON_FCMEQ_zero_scalar:
5407 fcmp_zero(fpf, rd, rn, eq);
5408 break;
5409 case NEON_FCMLE_zero_scalar:
5410 fcmp_zero(fpf, rd, rn, le);
5411 break;
5412 case NEON_FCMLT_zero_scalar:
5413 fcmp_zero(fpf, rd, rn, lt);
5414 break;
5415 case NEON_SCVTF_scalar:
5416 scvtf(fpf, rd, rn, 0, fpcr_rounding);
5417 break;
5418 case NEON_UCVTF_scalar:
5419 ucvtf(fpf, rd, rn, 0, fpcr_rounding);
5420 break;
5421 case NEON_FCVTNS_scalar:
5422 fcvts(fpf, rd, rn, FPTieEven);
5423 break;
5424 case NEON_FCVTNU_scalar:
5425 fcvtu(fpf, rd, rn, FPTieEven);
5426 break;
5427 case NEON_FCVTPS_scalar:
5428 fcvts(fpf, rd, rn, FPPositiveInfinity);
5429 break;
5430 case NEON_FCVTPU_scalar:
5431 fcvtu(fpf, rd, rn, FPPositiveInfinity);
5432 break;
5433 case NEON_FCVTMS_scalar:
5434 fcvts(fpf, rd, rn, FPNegativeInfinity);
5435 break;
5436 case NEON_FCVTMU_scalar:
5437 fcvtu(fpf, rd, rn, FPNegativeInfinity);
5438 break;
5439 case NEON_FCVTZS_scalar:
5440 fcvts(fpf, rd, rn, FPZero);
5441 break;
5442 case NEON_FCVTZU_scalar:
5443 fcvtu(fpf, rd, rn, FPZero);
5444 break;
5445 case NEON_FCVTAS_scalar:
5446 fcvts(fpf, rd, rn, FPTieAway);
5447 break;
5448 case NEON_FCVTAU_scalar:
5449 fcvtu(fpf, rd, rn, FPTieAway);
5450 break;
5451 case NEON_FCVTXN_scalar:
5452 // Unlike all of the other FP instructions above, fcvtxn encodes dest
5453 // size S as size<0>=1. There's only one case, so we ignore the form.
5454 DCHECK_EQ(instr->Bit(22), 1);
5455 fcvtxn(kFormatS, rd, rn);
5456 break;
5457 default:
5458 switch (instr->Mask(NEONScalar2RegMiscMask)) {
5459 case NEON_SQXTN_scalar:
5460 sqxtn(vf, rd, rn);
5461 break;
5462 case NEON_UQXTN_scalar:
5463 uqxtn(vf, rd, rn);
5464 break;
5465 case NEON_SQXTUN_scalar:
5466 sqxtun(vf, rd, rn);
5467 break;
5468 default:
5469 UNIMPLEMENTED();
5470 }
5471 }
5472 }
5473 }
5474
VisitNEONScalar3Diff(Instruction * instr)5475 void Simulator::VisitNEONScalar3Diff(Instruction* instr) {
5476 NEONFormatDecoder nfd(instr, NEONFormatDecoder::LongScalarFormatMap());
5477 VectorFormat vf = nfd.GetVectorFormat();
5478
5479 SimVRegister& rd = vreg(instr->Rd());
5480 SimVRegister& rn = vreg(instr->Rn());
5481 SimVRegister& rm = vreg(instr->Rm());
5482 switch (instr->Mask(NEONScalar3DiffMask)) {
5483 case NEON_SQDMLAL_scalar:
5484 sqdmlal(vf, rd, rn, rm);
5485 break;
5486 case NEON_SQDMLSL_scalar:
5487 sqdmlsl(vf, rd, rn, rm);
5488 break;
5489 case NEON_SQDMULL_scalar:
5490 sqdmull(vf, rd, rn, rm);
5491 break;
5492 default:
5493 UNIMPLEMENTED();
5494 }
5495 }
5496
VisitNEONScalar3Same(Instruction * instr)5497 void Simulator::VisitNEONScalar3Same(Instruction* instr) {
5498 NEONFormatDecoder nfd(instr, NEONFormatDecoder::ScalarFormatMap());
5499 VectorFormat vf = nfd.GetVectorFormat();
5500
5501 SimVRegister& rd = vreg(instr->Rd());
5502 SimVRegister& rn = vreg(instr->Rn());
5503 SimVRegister& rm = vreg(instr->Rm());
5504
5505 if (instr->Mask(NEONScalar3SameFPFMask) == NEONScalar3SameFPFixed) {
5506 vf = nfd.GetVectorFormat(nfd.FPScalarFormatMap());
5507 switch (instr->Mask(NEONScalar3SameFPMask)) {
5508 case NEON_FMULX_scalar:
5509 fmulx(vf, rd, rn, rm);
5510 break;
5511 case NEON_FACGE_scalar:
5512 fabscmp(vf, rd, rn, rm, ge);
5513 break;
5514 case NEON_FACGT_scalar:
5515 fabscmp(vf, rd, rn, rm, gt);
5516 break;
5517 case NEON_FCMEQ_scalar:
5518 fcmp(vf, rd, rn, rm, eq);
5519 break;
5520 case NEON_FCMGE_scalar:
5521 fcmp(vf, rd, rn, rm, ge);
5522 break;
5523 case NEON_FCMGT_scalar:
5524 fcmp(vf, rd, rn, rm, gt);
5525 break;
5526 case NEON_FRECPS_scalar:
5527 frecps(vf, rd, rn, rm);
5528 break;
5529 case NEON_FRSQRTS_scalar:
5530 frsqrts(vf, rd, rn, rm);
5531 break;
5532 case NEON_FABD_scalar:
5533 fabd(vf, rd, rn, rm);
5534 break;
5535 default:
5536 UNIMPLEMENTED();
5537 }
5538 } else {
5539 switch (instr->Mask(NEONScalar3SameMask)) {
5540 case NEON_ADD_scalar:
5541 add(vf, rd, rn, rm);
5542 break;
5543 case NEON_SUB_scalar:
5544 sub(vf, rd, rn, rm);
5545 break;
5546 case NEON_CMEQ_scalar:
5547 cmp(vf, rd, rn, rm, eq);
5548 break;
5549 case NEON_CMGE_scalar:
5550 cmp(vf, rd, rn, rm, ge);
5551 break;
5552 case NEON_CMGT_scalar:
5553 cmp(vf, rd, rn, rm, gt);
5554 break;
5555 case NEON_CMHI_scalar:
5556 cmp(vf, rd, rn, rm, hi);
5557 break;
5558 case NEON_CMHS_scalar:
5559 cmp(vf, rd, rn, rm, hs);
5560 break;
5561 case NEON_CMTST_scalar:
5562 cmptst(vf, rd, rn, rm);
5563 break;
5564 case NEON_USHL_scalar:
5565 ushl(vf, rd, rn, rm);
5566 break;
5567 case NEON_SSHL_scalar:
5568 sshl(vf, rd, rn, rm);
5569 break;
5570 case NEON_SQDMULH_scalar:
5571 sqdmulh(vf, rd, rn, rm);
5572 break;
5573 case NEON_SQRDMULH_scalar:
5574 sqrdmulh(vf, rd, rn, rm);
5575 break;
5576 case NEON_UQADD_scalar:
5577 add(vf, rd, rn, rm).UnsignedSaturate(vf);
5578 break;
5579 case NEON_SQADD_scalar:
5580 add(vf, rd, rn, rm).SignedSaturate(vf);
5581 break;
5582 case NEON_UQSUB_scalar:
5583 sub(vf, rd, rn, rm).UnsignedSaturate(vf);
5584 break;
5585 case NEON_SQSUB_scalar:
5586 sub(vf, rd, rn, rm).SignedSaturate(vf);
5587 break;
5588 case NEON_UQSHL_scalar:
5589 ushl(vf, rd, rn, rm).UnsignedSaturate(vf);
5590 break;
5591 case NEON_SQSHL_scalar:
5592 sshl(vf, rd, rn, rm).SignedSaturate(vf);
5593 break;
5594 case NEON_URSHL_scalar:
5595 ushl(vf, rd, rn, rm).Round(vf);
5596 break;
5597 case NEON_SRSHL_scalar:
5598 sshl(vf, rd, rn, rm).Round(vf);
5599 break;
5600 case NEON_UQRSHL_scalar:
5601 ushl(vf, rd, rn, rm).Round(vf).UnsignedSaturate(vf);
5602 break;
5603 case NEON_SQRSHL_scalar:
5604 sshl(vf, rd, rn, rm).Round(vf).SignedSaturate(vf);
5605 break;
5606 default:
5607 UNIMPLEMENTED();
5608 }
5609 }
5610 }
5611
VisitNEONScalarByIndexedElement(Instruction * instr)5612 void Simulator::VisitNEONScalarByIndexedElement(Instruction* instr) {
5613 NEONFormatDecoder nfd(instr, NEONFormatDecoder::LongScalarFormatMap());
5614 VectorFormat vf = nfd.GetVectorFormat();
5615 VectorFormat vf_r = nfd.GetVectorFormat(nfd.ScalarFormatMap());
5616
5617 SimVRegister& rd = vreg(instr->Rd());
5618 SimVRegister& rn = vreg(instr->Rn());
5619 ByElementOp Op = nullptr;
5620
5621 int rm_reg = instr->Rm();
5622 int index = (instr->NEONH() << 1) | instr->NEONL();
5623 if (instr->NEONSize() == 1) {
5624 rm_reg &= 0xF;
5625 index = (index << 1) | instr->NEONM();
5626 }
5627
5628 switch (instr->Mask(NEONScalarByIndexedElementMask)) {
5629 case NEON_SQDMULL_byelement_scalar:
5630 Op = &Simulator::sqdmull;
5631 break;
5632 case NEON_SQDMLAL_byelement_scalar:
5633 Op = &Simulator::sqdmlal;
5634 break;
5635 case NEON_SQDMLSL_byelement_scalar:
5636 Op = &Simulator::sqdmlsl;
5637 break;
5638 case NEON_SQDMULH_byelement_scalar:
5639 Op = &Simulator::sqdmulh;
5640 vf = vf_r;
5641 break;
5642 case NEON_SQRDMULH_byelement_scalar:
5643 Op = &Simulator::sqrdmulh;
5644 vf = vf_r;
5645 break;
5646 default:
5647 vf = nfd.GetVectorFormat(nfd.FPScalarFormatMap());
5648 index = instr->NEONH();
5649 if ((instr->FPType() & 1) == 0) {
5650 index = (index << 1) | instr->NEONL();
5651 }
5652 switch (instr->Mask(NEONScalarByIndexedElementFPMask)) {
5653 case NEON_FMUL_byelement_scalar:
5654 Op = &Simulator::fmul;
5655 break;
5656 case NEON_FMLA_byelement_scalar:
5657 Op = &Simulator::fmla;
5658 break;
5659 case NEON_FMLS_byelement_scalar:
5660 Op = &Simulator::fmls;
5661 break;
5662 case NEON_FMULX_byelement_scalar:
5663 Op = &Simulator::fmulx;
5664 break;
5665 default:
5666 UNIMPLEMENTED();
5667 }
5668 }
5669
5670 (this->*Op)(vf, rd, rn, vreg(rm_reg), index);
5671 }
5672
VisitNEONScalarCopy(Instruction * instr)5673 void Simulator::VisitNEONScalarCopy(Instruction* instr) {
5674 NEONFormatDecoder nfd(instr, NEONFormatDecoder::TriangularScalarFormatMap());
5675 VectorFormat vf = nfd.GetVectorFormat();
5676
5677 SimVRegister& rd = vreg(instr->Rd());
5678 SimVRegister& rn = vreg(instr->Rn());
5679
5680 if (instr->Mask(NEONScalarCopyMask) == NEON_DUP_ELEMENT_scalar) {
5681 int imm5 = instr->ImmNEON5();
5682 int lsb = LowestSetBitPosition(imm5);
5683 int rn_index = imm5 >> lsb;
5684 dup_element(vf, rd, rn, rn_index);
5685 } else {
5686 UNIMPLEMENTED();
5687 }
5688 }
5689
VisitNEONScalarPairwise(Instruction * instr)5690 void Simulator::VisitNEONScalarPairwise(Instruction* instr) {
5691 NEONFormatDecoder nfd(instr, NEONFormatDecoder::FPScalarFormatMap());
5692 VectorFormat vf = nfd.GetVectorFormat();
5693
5694 SimVRegister& rd = vreg(instr->Rd());
5695 SimVRegister& rn = vreg(instr->Rn());
5696 switch (instr->Mask(NEONScalarPairwiseMask)) {
5697 case NEON_ADDP_scalar:
5698 addp(vf, rd, rn);
5699 break;
5700 case NEON_FADDP_scalar:
5701 faddp(vf, rd, rn);
5702 break;
5703 case NEON_FMAXP_scalar:
5704 fmaxp(vf, rd, rn);
5705 break;
5706 case NEON_FMAXNMP_scalar:
5707 fmaxnmp(vf, rd, rn);
5708 break;
5709 case NEON_FMINP_scalar:
5710 fminp(vf, rd, rn);
5711 break;
5712 case NEON_FMINNMP_scalar:
5713 fminnmp(vf, rd, rn);
5714 break;
5715 default:
5716 UNIMPLEMENTED();
5717 }
5718 }
5719
VisitNEONScalarShiftImmediate(Instruction * instr)5720 void Simulator::VisitNEONScalarShiftImmediate(Instruction* instr) {
5721 SimVRegister& rd = vreg(instr->Rd());
5722 SimVRegister& rn = vreg(instr->Rn());
5723 FPRounding fpcr_rounding = static_cast<FPRounding>(fpcr().RMode());
5724
5725 static const NEONFormatMap map = {
5726 {22, 21, 20, 19},
5727 {NF_UNDEF, NF_B, NF_H, NF_H, NF_S, NF_S, NF_S, NF_S, NF_D, NF_D, NF_D,
5728 NF_D, NF_D, NF_D, NF_D, NF_D}};
5729 NEONFormatDecoder nfd(instr, &map);
5730 VectorFormat vf = nfd.GetVectorFormat();
5731
5732 int highestSetBit = HighestSetBitPosition(instr->ImmNEONImmh());
5733 int immhimmb = instr->ImmNEONImmhImmb();
5734 int right_shift = (16 << highestSetBit) - immhimmb;
5735 int left_shift = immhimmb - (8 << highestSetBit);
5736 switch (instr->Mask(NEONScalarShiftImmediateMask)) {
5737 case NEON_SHL_scalar:
5738 shl(vf, rd, rn, left_shift);
5739 break;
5740 case NEON_SLI_scalar:
5741 sli(vf, rd, rn, left_shift);
5742 break;
5743 case NEON_SQSHL_imm_scalar:
5744 sqshl(vf, rd, rn, left_shift);
5745 break;
5746 case NEON_UQSHL_imm_scalar:
5747 uqshl(vf, rd, rn, left_shift);
5748 break;
5749 case NEON_SQSHLU_scalar:
5750 sqshlu(vf, rd, rn, left_shift);
5751 break;
5752 case NEON_SRI_scalar:
5753 sri(vf, rd, rn, right_shift);
5754 break;
5755 case NEON_SSHR_scalar:
5756 sshr(vf, rd, rn, right_shift);
5757 break;
5758 case NEON_USHR_scalar:
5759 ushr(vf, rd, rn, right_shift);
5760 break;
5761 case NEON_SRSHR_scalar:
5762 sshr(vf, rd, rn, right_shift).Round(vf);
5763 break;
5764 case NEON_URSHR_scalar:
5765 ushr(vf, rd, rn, right_shift).Round(vf);
5766 break;
5767 case NEON_SSRA_scalar:
5768 ssra(vf, rd, rn, right_shift);
5769 break;
5770 case NEON_USRA_scalar:
5771 usra(vf, rd, rn, right_shift);
5772 break;
5773 case NEON_SRSRA_scalar:
5774 srsra(vf, rd, rn, right_shift);
5775 break;
5776 case NEON_URSRA_scalar:
5777 ursra(vf, rd, rn, right_shift);
5778 break;
5779 case NEON_UQSHRN_scalar:
5780 uqshrn(vf, rd, rn, right_shift);
5781 break;
5782 case NEON_UQRSHRN_scalar:
5783 uqrshrn(vf, rd, rn, right_shift);
5784 break;
5785 case NEON_SQSHRN_scalar:
5786 sqshrn(vf, rd, rn, right_shift);
5787 break;
5788 case NEON_SQRSHRN_scalar:
5789 sqrshrn(vf, rd, rn, right_shift);
5790 break;
5791 case NEON_SQSHRUN_scalar:
5792 sqshrun(vf, rd, rn, right_shift);
5793 break;
5794 case NEON_SQRSHRUN_scalar:
5795 sqrshrun(vf, rd, rn, right_shift);
5796 break;
5797 case NEON_FCVTZS_imm_scalar:
5798 fcvts(vf, rd, rn, FPZero, right_shift);
5799 break;
5800 case NEON_FCVTZU_imm_scalar:
5801 fcvtu(vf, rd, rn, FPZero, right_shift);
5802 break;
5803 case NEON_SCVTF_imm_scalar:
5804 scvtf(vf, rd, rn, right_shift, fpcr_rounding);
5805 break;
5806 case NEON_UCVTF_imm_scalar:
5807 ucvtf(vf, rd, rn, right_shift, fpcr_rounding);
5808 break;
5809 default:
5810 UNIMPLEMENTED();
5811 }
5812 }
5813
VisitNEONShiftImmediate(Instruction * instr)5814 void Simulator::VisitNEONShiftImmediate(Instruction* instr) {
5815 SimVRegister& rd = vreg(instr->Rd());
5816 SimVRegister& rn = vreg(instr->Rn());
5817 FPRounding fpcr_rounding = static_cast<FPRounding>(fpcr().RMode());
5818
5819 // 00010->8B, 00011->16B, 001x0->4H, 001x1->8H,
5820 // 01xx0->2S, 01xx1->4S, 1xxx1->2D, all others undefined.
5821 static const NEONFormatMap map = {
5822 {22, 21, 20, 19, 30},
5823 {NF_UNDEF, NF_UNDEF, NF_8B, NF_16B, NF_4H, NF_8H, NF_4H, NF_8H,
5824 NF_2S, NF_4S, NF_2S, NF_4S, NF_2S, NF_4S, NF_2S, NF_4S,
5825 NF_UNDEF, NF_2D, NF_UNDEF, NF_2D, NF_UNDEF, NF_2D, NF_UNDEF, NF_2D,
5826 NF_UNDEF, NF_2D, NF_UNDEF, NF_2D, NF_UNDEF, NF_2D, NF_UNDEF, NF_2D}};
5827 NEONFormatDecoder nfd(instr, &map);
5828 VectorFormat vf = nfd.GetVectorFormat();
5829
5830 // 0001->8H, 001x->4S, 01xx->2D, all others undefined.
5831 static const NEONFormatMap map_l = {
5832 {22, 21, 20, 19},
5833 {NF_UNDEF, NF_8H, NF_4S, NF_4S, NF_2D, NF_2D, NF_2D, NF_2D}};
5834 VectorFormat vf_l = nfd.GetVectorFormat(&map_l);
5835
5836 int highestSetBit = HighestSetBitPosition(instr->ImmNEONImmh());
5837 int immhimmb = instr->ImmNEONImmhImmb();
5838 int right_shift = (16 << highestSetBit) - immhimmb;
5839 int left_shift = immhimmb - (8 << highestSetBit);
5840
5841 switch (instr->Mask(NEONShiftImmediateMask)) {
5842 case NEON_SHL:
5843 shl(vf, rd, rn, left_shift);
5844 break;
5845 case NEON_SLI:
5846 sli(vf, rd, rn, left_shift);
5847 break;
5848 case NEON_SQSHLU:
5849 sqshlu(vf, rd, rn, left_shift);
5850 break;
5851 case NEON_SRI:
5852 sri(vf, rd, rn, right_shift);
5853 break;
5854 case NEON_SSHR:
5855 sshr(vf, rd, rn, right_shift);
5856 break;
5857 case NEON_USHR:
5858 ushr(vf, rd, rn, right_shift);
5859 break;
5860 case NEON_SRSHR:
5861 sshr(vf, rd, rn, right_shift).Round(vf);
5862 break;
5863 case NEON_URSHR:
5864 ushr(vf, rd, rn, right_shift).Round(vf);
5865 break;
5866 case NEON_SSRA:
5867 ssra(vf, rd, rn, right_shift);
5868 break;
5869 case NEON_USRA:
5870 usra(vf, rd, rn, right_shift);
5871 break;
5872 case NEON_SRSRA:
5873 srsra(vf, rd, rn, right_shift);
5874 break;
5875 case NEON_URSRA:
5876 ursra(vf, rd, rn, right_shift);
5877 break;
5878 case NEON_SQSHL_imm:
5879 sqshl(vf, rd, rn, left_shift);
5880 break;
5881 case NEON_UQSHL_imm:
5882 uqshl(vf, rd, rn, left_shift);
5883 break;
5884 case NEON_SCVTF_imm:
5885 scvtf(vf, rd, rn, right_shift, fpcr_rounding);
5886 break;
5887 case NEON_UCVTF_imm:
5888 ucvtf(vf, rd, rn, right_shift, fpcr_rounding);
5889 break;
5890 case NEON_FCVTZS_imm:
5891 fcvts(vf, rd, rn, FPZero, right_shift);
5892 break;
5893 case NEON_FCVTZU_imm:
5894 fcvtu(vf, rd, rn, FPZero, right_shift);
5895 break;
5896 case NEON_SSHLL:
5897 vf = vf_l;
5898 if (instr->Mask(NEON_Q)) {
5899 sshll2(vf, rd, rn, left_shift);
5900 } else {
5901 sshll(vf, rd, rn, left_shift);
5902 }
5903 break;
5904 case NEON_USHLL:
5905 vf = vf_l;
5906 if (instr->Mask(NEON_Q)) {
5907 ushll2(vf, rd, rn, left_shift);
5908 } else {
5909 ushll(vf, rd, rn, left_shift);
5910 }
5911 break;
5912 case NEON_SHRN:
5913 if (instr->Mask(NEON_Q)) {
5914 shrn2(vf, rd, rn, right_shift);
5915 } else {
5916 shrn(vf, rd, rn, right_shift);
5917 }
5918 break;
5919 case NEON_RSHRN:
5920 if (instr->Mask(NEON_Q)) {
5921 rshrn2(vf, rd, rn, right_shift);
5922 } else {
5923 rshrn(vf, rd, rn, right_shift);
5924 }
5925 break;
5926 case NEON_UQSHRN:
5927 if (instr->Mask(NEON_Q)) {
5928 uqshrn2(vf, rd, rn, right_shift);
5929 } else {
5930 uqshrn(vf, rd, rn, right_shift);
5931 }
5932 break;
5933 case NEON_UQRSHRN:
5934 if (instr->Mask(NEON_Q)) {
5935 uqrshrn2(vf, rd, rn, right_shift);
5936 } else {
5937 uqrshrn(vf, rd, rn, right_shift);
5938 }
5939 break;
5940 case NEON_SQSHRN:
5941 if (instr->Mask(NEON_Q)) {
5942 sqshrn2(vf, rd, rn, right_shift);
5943 } else {
5944 sqshrn(vf, rd, rn, right_shift);
5945 }
5946 break;
5947 case NEON_SQRSHRN:
5948 if (instr->Mask(NEON_Q)) {
5949 sqrshrn2(vf, rd, rn, right_shift);
5950 } else {
5951 sqrshrn(vf, rd, rn, right_shift);
5952 }
5953 break;
5954 case NEON_SQSHRUN:
5955 if (instr->Mask(NEON_Q)) {
5956 sqshrun2(vf, rd, rn, right_shift);
5957 } else {
5958 sqshrun(vf, rd, rn, right_shift);
5959 }
5960 break;
5961 case NEON_SQRSHRUN:
5962 if (instr->Mask(NEON_Q)) {
5963 sqrshrun2(vf, rd, rn, right_shift);
5964 } else {
5965 sqrshrun(vf, rd, rn, right_shift);
5966 }
5967 break;
5968 default:
5969 UNIMPLEMENTED();
5970 }
5971 }
5972
VisitNEONTable(Instruction * instr)5973 void Simulator::VisitNEONTable(Instruction* instr) {
5974 NEONFormatDecoder nfd(instr, NEONFormatDecoder::LogicalFormatMap());
5975 VectorFormat vf = nfd.GetVectorFormat();
5976
5977 SimVRegister& rd = vreg(instr->Rd());
5978 SimVRegister& rn = vreg(instr->Rn());
5979 SimVRegister& rn2 = vreg((instr->Rn() + 1) % kNumberOfVRegisters);
5980 SimVRegister& rn3 = vreg((instr->Rn() + 2) % kNumberOfVRegisters);
5981 SimVRegister& rn4 = vreg((instr->Rn() + 3) % kNumberOfVRegisters);
5982 SimVRegister& rm = vreg(instr->Rm());
5983
5984 switch (instr->Mask(NEONTableMask)) {
5985 case NEON_TBL_1v:
5986 tbl(vf, rd, rn, rm);
5987 break;
5988 case NEON_TBL_2v:
5989 tbl(vf, rd, rn, rn2, rm);
5990 break;
5991 case NEON_TBL_3v:
5992 tbl(vf, rd, rn, rn2, rn3, rm);
5993 break;
5994 case NEON_TBL_4v:
5995 tbl(vf, rd, rn, rn2, rn3, rn4, rm);
5996 break;
5997 case NEON_TBX_1v:
5998 tbx(vf, rd, rn, rm);
5999 break;
6000 case NEON_TBX_2v:
6001 tbx(vf, rd, rn, rn2, rm);
6002 break;
6003 case NEON_TBX_3v:
6004 tbx(vf, rd, rn, rn2, rn3, rm);
6005 break;
6006 case NEON_TBX_4v:
6007 tbx(vf, rd, rn, rn2, rn3, rn4, rm);
6008 break;
6009 default:
6010 UNIMPLEMENTED();
6011 }
6012 }
6013
VisitNEONPerm(Instruction * instr)6014 void Simulator::VisitNEONPerm(Instruction* instr) {
6015 NEONFormatDecoder nfd(instr);
6016 VectorFormat vf = nfd.GetVectorFormat();
6017
6018 SimVRegister& rd = vreg(instr->Rd());
6019 SimVRegister& rn = vreg(instr->Rn());
6020 SimVRegister& rm = vreg(instr->Rm());
6021
6022 switch (instr->Mask(NEONPermMask)) {
6023 case NEON_TRN1:
6024 trn1(vf, rd, rn, rm);
6025 break;
6026 case NEON_TRN2:
6027 trn2(vf, rd, rn, rm);
6028 break;
6029 case NEON_UZP1:
6030 uzp1(vf, rd, rn, rm);
6031 break;
6032 case NEON_UZP2:
6033 uzp2(vf, rd, rn, rm);
6034 break;
6035 case NEON_ZIP1:
6036 zip1(vf, rd, rn, rm);
6037 break;
6038 case NEON_ZIP2:
6039 zip2(vf, rd, rn, rm);
6040 break;
6041 default:
6042 UNIMPLEMENTED();
6043 }
6044 }
6045
DoPrintf(Instruction * instr)6046 void Simulator::DoPrintf(Instruction* instr) {
6047 DCHECK((instr->Mask(ExceptionMask) == HLT) &&
6048 (instr->ImmException() == kImmExceptionIsPrintf));
6049
6050 // Read the arguments encoded inline in the instruction stream.
6051 uint32_t arg_count;
6052 uint32_t arg_pattern_list;
6053 STATIC_ASSERT(sizeof(*instr) == 1);
6054 memcpy(&arg_count, instr + kPrintfArgCountOffset, sizeof(arg_count));
6055 memcpy(&arg_pattern_list, instr + kPrintfArgPatternListOffset,
6056 sizeof(arg_pattern_list));
6057
6058 DCHECK_LE(arg_count, kPrintfMaxArgCount);
6059 DCHECK_EQ(arg_pattern_list >> (kPrintfArgPatternBits * arg_count), 0);
6060
6061 // We need to call the host printf function with a set of arguments defined by
6062 // arg_pattern_list. Because we don't know the types and sizes of the
6063 // arguments, this is very difficult to do in a robust and portable way. To
6064 // work around the problem, we pick apart the format string, and print one
6065 // format placeholder at a time.
6066
6067 // Allocate space for the format string. We take a copy, so we can modify it.
6068 // Leave enough space for one extra character per expected argument (plus the
6069 // '\0' termination).
6070 const char* format_base = reg<const char*>(0);
6071 DCHECK_NOT_NULL(format_base);
6072 size_t length = strlen(format_base) + 1;
6073 char* const format = new char[length + arg_count];
6074
6075 // A list of chunks, each with exactly one format placeholder.
6076 const char* chunks[kPrintfMaxArgCount];
6077
6078 // Copy the format string and search for format placeholders.
6079 uint32_t placeholder_count = 0;
6080 char* format_scratch = format;
6081 for (size_t i = 0; i < length; i++) {
6082 if (format_base[i] != '%') {
6083 *format_scratch++ = format_base[i];
6084 } else {
6085 if (format_base[i + 1] == '%') {
6086 // Ignore explicit "%%" sequences.
6087 *format_scratch++ = format_base[i];
6088
6089 if (placeholder_count == 0) {
6090 // The first chunk is passed to printf using "%s", so we need to
6091 // unescape "%%" sequences in this chunk. (Just skip the next '%'.)
6092 i++;
6093 } else {
6094 // Otherwise, pass through "%%" unchanged.
6095 *format_scratch++ = format_base[++i];
6096 }
6097 } else {
6098 CHECK(placeholder_count < arg_count);
6099 // Insert '\0' before placeholders, and store their locations.
6100 *format_scratch++ = '\0';
6101 chunks[placeholder_count++] = format_scratch;
6102 *format_scratch++ = format_base[i];
6103 }
6104 }
6105 }
6106 DCHECK(format_scratch <= (format + length + arg_count));
6107 CHECK(placeholder_count == arg_count);
6108
6109 // Finally, call printf with each chunk, passing the appropriate register
6110 // argument. Normally, printf returns the number of bytes transmitted, so we
6111 // can emulate a single printf call by adding the result from each chunk. If
6112 // any call returns a negative (error) value, though, just return that value.
6113
6114 fprintf(stream_, "%s", clr_printf);
6115
6116 // Because '\0' is inserted before each placeholder, the first string in
6117 // 'format' contains no format placeholders and should be printed literally.
6118 int result = fprintf(stream_, "%s", format);
6119 int pcs_r = 1; // Start at x1. x0 holds the format string.
6120 int pcs_f = 0; // Start at d0.
6121 if (result >= 0) {
6122 for (uint32_t i = 0; i < placeholder_count; i++) {
6123 int part_result = -1;
6124
6125 uint32_t arg_pattern = arg_pattern_list >> (i * kPrintfArgPatternBits);
6126 arg_pattern &= (1 << kPrintfArgPatternBits) - 1;
6127 switch (arg_pattern) {
6128 case kPrintfArgW:
6129 part_result = fprintf(stream_, chunks[i], wreg(pcs_r++));
6130 break;
6131 case kPrintfArgX:
6132 part_result = fprintf(stream_, chunks[i], xreg(pcs_r++));
6133 break;
6134 case kPrintfArgD:
6135 part_result = fprintf(stream_, chunks[i], dreg(pcs_f++));
6136 break;
6137 default:
6138 UNREACHABLE();
6139 }
6140
6141 if (part_result < 0) {
6142 // Handle error values.
6143 result = part_result;
6144 break;
6145 }
6146
6147 result += part_result;
6148 }
6149 }
6150
6151 fprintf(stream_, "%s", clr_normal);
6152
6153 #ifdef DEBUG
6154 CorruptAllCallerSavedCPURegisters();
6155 #endif
6156
6157 // Printf returns its result in x0 (just like the C library's printf).
6158 set_xreg(0, result);
6159
6160 // The printf parameters are inlined in the code, so skip them.
6161 set_pc(instr->InstructionAtOffset(kPrintfLength));
6162
6163 // Set LR as if we'd just called a native printf function.
6164 set_lr(pc());
6165
6166 delete[] format;
6167 }
6168
LocalMonitor()6169 Simulator::LocalMonitor::LocalMonitor()
6170 : access_state_(MonitorAccess::Open),
6171 tagged_addr_(0),
6172 size_(TransactionSize::None) {}
6173
Clear()6174 void Simulator::LocalMonitor::Clear() {
6175 access_state_ = MonitorAccess::Open;
6176 tagged_addr_ = 0;
6177 size_ = TransactionSize::None;
6178 }
6179
NotifyLoad()6180 void Simulator::LocalMonitor::NotifyLoad() {
6181 if (access_state_ == MonitorAccess::Exclusive) {
6182 // A non exclusive load could clear the local monitor. As a result, it's
6183 // most strict to unconditionally clear the local monitor on load.
6184 Clear();
6185 }
6186 }
6187
NotifyLoadExcl(uintptr_t addr,TransactionSize size)6188 void Simulator::LocalMonitor::NotifyLoadExcl(uintptr_t addr,
6189 TransactionSize size) {
6190 access_state_ = MonitorAccess::Exclusive;
6191 tagged_addr_ = addr;
6192 size_ = size;
6193 }
6194
NotifyStore()6195 void Simulator::LocalMonitor::NotifyStore() {
6196 if (access_state_ == MonitorAccess::Exclusive) {
6197 // A non exclusive store could clear the local monitor. As a result, it's
6198 // most strict to unconditionally clear the local monitor on store.
6199 Clear();
6200 }
6201 }
6202
NotifyStoreExcl(uintptr_t addr,TransactionSize size)6203 bool Simulator::LocalMonitor::NotifyStoreExcl(uintptr_t addr,
6204 TransactionSize size) {
6205 if (access_state_ == MonitorAccess::Exclusive) {
6206 // It is allowed for a processor to require that the address matches
6207 // exactly (B2.10.1), so this comparison does not mask addr.
6208 if (addr == tagged_addr_ && size_ == size) {
6209 Clear();
6210 return true;
6211 } else {
6212 // It is implementation-defined whether an exclusive store to a
6213 // non-tagged address will update memory. As a result, it's most strict
6214 // to unconditionally clear the local monitor.
6215 Clear();
6216 return false;
6217 }
6218 } else {
6219 DCHECK(access_state_ == MonitorAccess::Open);
6220 return false;
6221 }
6222 }
6223
Processor()6224 Simulator::GlobalMonitor::Processor::Processor()
6225 : access_state_(MonitorAccess::Open),
6226 tagged_addr_(0),
6227 next_(nullptr),
6228 prev_(nullptr),
6229 failure_counter_(0) {}
6230
Clear_Locked()6231 void Simulator::GlobalMonitor::Processor::Clear_Locked() {
6232 access_state_ = MonitorAccess::Open;
6233 tagged_addr_ = 0;
6234 }
6235
NotifyLoadExcl_Locked(uintptr_t addr)6236 void Simulator::GlobalMonitor::Processor::NotifyLoadExcl_Locked(
6237 uintptr_t addr) {
6238 access_state_ = MonitorAccess::Exclusive;
6239 tagged_addr_ = addr;
6240 }
6241
NotifyStore_Locked(bool is_requesting_processor)6242 void Simulator::GlobalMonitor::Processor::NotifyStore_Locked(
6243 bool is_requesting_processor) {
6244 if (access_state_ == MonitorAccess::Exclusive) {
6245 // A non exclusive store could clear the global monitor. As a result, it's
6246 // most strict to unconditionally clear global monitors on store.
6247 Clear_Locked();
6248 }
6249 }
6250
NotifyStoreExcl_Locked(uintptr_t addr,bool is_requesting_processor)6251 bool Simulator::GlobalMonitor::Processor::NotifyStoreExcl_Locked(
6252 uintptr_t addr, bool is_requesting_processor) {
6253 if (access_state_ == MonitorAccess::Exclusive) {
6254 if (is_requesting_processor) {
6255 // It is allowed for a processor to require that the address matches
6256 // exactly (B2.10.2), so this comparison does not mask addr.
6257 if (addr == tagged_addr_) {
6258 Clear_Locked();
6259 // Introduce occasional stxr failures. This is to simulate the
6260 // behavior of hardware, which can randomly fail due to background
6261 // cache evictions.
6262 if (failure_counter_++ >= kMaxFailureCounter) {
6263 failure_counter_ = 0;
6264 return false;
6265 } else {
6266 return true;
6267 }
6268 }
6269 } else if ((addr & kExclusiveTaggedAddrMask) ==
6270 (tagged_addr_ & kExclusiveTaggedAddrMask)) {
6271 // Check the masked addresses when responding to a successful lock by
6272 // another processor so the implementation is more conservative (i.e. the
6273 // granularity of locking is as large as possible.)
6274 Clear_Locked();
6275 return false;
6276 }
6277 }
6278 return false;
6279 }
6280
NotifyLoadExcl_Locked(uintptr_t addr,Processor * processor)6281 void Simulator::GlobalMonitor::NotifyLoadExcl_Locked(uintptr_t addr,
6282 Processor* processor) {
6283 processor->NotifyLoadExcl_Locked(addr);
6284 PrependProcessor_Locked(processor);
6285 }
6286
NotifyStore_Locked(Processor * processor)6287 void Simulator::GlobalMonitor::NotifyStore_Locked(Processor* processor) {
6288 // Notify each processor of the store operation.
6289 for (Processor* iter = head_; iter; iter = iter->next_) {
6290 bool is_requesting_processor = iter == processor;
6291 iter->NotifyStore_Locked(is_requesting_processor);
6292 }
6293 }
6294
NotifyStoreExcl_Locked(uintptr_t addr,Processor * processor)6295 bool Simulator::GlobalMonitor::NotifyStoreExcl_Locked(uintptr_t addr,
6296 Processor* processor) {
6297 DCHECK(IsProcessorInLinkedList_Locked(processor));
6298 if (processor->NotifyStoreExcl_Locked(addr, true)) {
6299 // Notify the other processors that this StoreExcl succeeded.
6300 for (Processor* iter = head_; iter; iter = iter->next_) {
6301 if (iter != processor) {
6302 iter->NotifyStoreExcl_Locked(addr, false);
6303 }
6304 }
6305 return true;
6306 } else {
6307 return false;
6308 }
6309 }
6310
IsProcessorInLinkedList_Locked(Processor * processor) const6311 bool Simulator::GlobalMonitor::IsProcessorInLinkedList_Locked(
6312 Processor* processor) const {
6313 return head_ == processor || processor->next_ || processor->prev_;
6314 }
6315
PrependProcessor_Locked(Processor * processor)6316 void Simulator::GlobalMonitor::PrependProcessor_Locked(Processor* processor) {
6317 if (IsProcessorInLinkedList_Locked(processor)) {
6318 return;
6319 }
6320
6321 if (head_) {
6322 head_->prev_ = processor;
6323 }
6324 processor->prev_ = nullptr;
6325 processor->next_ = head_;
6326 head_ = processor;
6327 }
6328
RemoveProcessor(Processor * processor)6329 void Simulator::GlobalMonitor::RemoveProcessor(Processor* processor) {
6330 base::MutexGuard lock_guard(&mutex);
6331 if (!IsProcessorInLinkedList_Locked(processor)) {
6332 return;
6333 }
6334
6335 if (processor->prev_) {
6336 processor->prev_->next_ = processor->next_;
6337 } else {
6338 head_ = processor->next_;
6339 }
6340 if (processor->next_) {
6341 processor->next_->prev_ = processor->prev_;
6342 }
6343 processor->prev_ = nullptr;
6344 processor->next_ = nullptr;
6345 }
6346
6347 #undef SScanF
6348 #undef COLOUR
6349 #undef COLOUR_BOLD
6350 #undef NORMAL
6351 #undef GREY
6352 #undef RED
6353 #undef GREEN
6354 #undef YELLOW
6355 #undef BLUE
6356 #undef MAGENTA
6357 #undef CYAN
6358 #undef WHITE
6359 #undef COMMAND_SIZE
6360 #undef ARG_SIZE
6361 #undef STR
6362 #undef XSTR
6363
6364 } // namespace internal
6365 } // namespace v8
6366
6367 //
6368 // The following functions are used by our gdb macros.
6369 //
_v8_internal_Simulator_ExecDebugCommand(const char * command)6370 V8_EXPORT_PRIVATE extern bool _v8_internal_Simulator_ExecDebugCommand(
6371 const char* command) {
6372 i::Isolate* isolate = i::Isolate::Current();
6373 if (!isolate) {
6374 fprintf(stderr, "No V8 Isolate found\n");
6375 return false;
6376 }
6377 i::Simulator* simulator = i::Simulator::current(isolate);
6378 if (!simulator) {
6379 fprintf(stderr, "No Arm64 simulator found\n");
6380 return false;
6381 }
6382 // Copy the command so that the simulator can take ownership of it.
6383 size_t len = strlen(command);
6384 i::ArrayUniquePtr<char> command_copy(i::NewArray<char>(len + 1));
6385 i::MemCopy(command_copy.get(), command, len + 1);
6386 return simulator->ExecDebugCommand(std::move(command_copy));
6387 }
6388
6389 #undef BRACKETS
6390
6391 #endif // USE_SIMULATOR
6392