OLD | NEW |
1 // Copyright 2013 the V8 project authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include <stdlib.h> | 5 #include <stdlib.h> |
6 #include <cmath> | 6 #include <cmath> |
7 #include <cstdarg> | 7 #include <cstdarg> |
8 | 8 |
9 #if V8_TARGET_ARCH_ARM64 | 9 #if V8_TARGET_ARCH_ARM64 |
10 | 10 |
(...skipping 25 matching lines...) Expand all Loading... |
36 #define COLOUR_BOLD(colour_code) "\033[1;" colour_code "m" | 36 #define COLOUR_BOLD(colour_code) "\033[1;" colour_code "m" |
37 #define NORMAL "" | 37 #define NORMAL "" |
38 #define GREY "30" | 38 #define GREY "30" |
39 #define RED "31" | 39 #define RED "31" |
40 #define GREEN "32" | 40 #define GREEN "32" |
41 #define YELLOW "33" | 41 #define YELLOW "33" |
42 #define BLUE "34" | 42 #define BLUE "34" |
43 #define MAGENTA "35" | 43 #define MAGENTA "35" |
44 #define CYAN "36" | 44 #define CYAN "36" |
45 #define WHITE "37" | 45 #define WHITE "37" |
| 46 |
46 typedef char const * const TEXT_COLOUR; | 47 typedef char const * const TEXT_COLOUR; |
47 TEXT_COLOUR clr_normal = FLAG_log_colour ? COLOUR(NORMAL) : ""; | 48 TEXT_COLOUR clr_normal = FLAG_log_colour ? COLOUR(NORMAL) : ""; |
48 TEXT_COLOUR clr_flag_name = FLAG_log_colour ? COLOUR_BOLD(WHITE) : ""; | 49 TEXT_COLOUR clr_flag_name = FLAG_log_colour ? COLOUR_BOLD(WHITE) : ""; |
49 TEXT_COLOUR clr_flag_value = FLAG_log_colour ? COLOUR(NORMAL) : ""; | 50 TEXT_COLOUR clr_flag_value = FLAG_log_colour ? COLOUR(NORMAL) : ""; |
50 TEXT_COLOUR clr_reg_name = FLAG_log_colour ? COLOUR_BOLD(CYAN) : ""; | 51 TEXT_COLOUR clr_reg_name = FLAG_log_colour ? COLOUR_BOLD(CYAN) : ""; |
51 TEXT_COLOUR clr_reg_value = FLAG_log_colour ? COLOUR(CYAN) : ""; | 52 TEXT_COLOUR clr_reg_value = FLAG_log_colour ? COLOUR(CYAN) : ""; |
52 TEXT_COLOUR clr_fpreg_name = FLAG_log_colour ? COLOUR_BOLD(MAGENTA) : ""; | 53 TEXT_COLOUR clr_vreg_name = FLAG_log_colour ? COLOUR_BOLD(MAGENTA) : ""; |
53 TEXT_COLOUR clr_fpreg_value = FLAG_log_colour ? COLOUR(MAGENTA) : ""; | 54 TEXT_COLOUR clr_vreg_value = FLAG_log_colour ? COLOUR(MAGENTA) : ""; |
54 TEXT_COLOUR clr_memory_address = FLAG_log_colour ? COLOUR_BOLD(BLUE) : ""; | 55 TEXT_COLOUR clr_memory_address = FLAG_log_colour ? COLOUR_BOLD(BLUE) : ""; |
55 TEXT_COLOUR clr_debug_number = FLAG_log_colour ? COLOUR_BOLD(YELLOW) : ""; | 56 TEXT_COLOUR clr_debug_number = FLAG_log_colour ? COLOUR_BOLD(YELLOW) : ""; |
56 TEXT_COLOUR clr_debug_message = FLAG_log_colour ? COLOUR(YELLOW) : ""; | 57 TEXT_COLOUR clr_debug_message = FLAG_log_colour ? COLOUR(YELLOW) : ""; |
57 TEXT_COLOUR clr_printf = FLAG_log_colour ? COLOUR(GREEN) : ""; | 58 TEXT_COLOUR clr_printf = FLAG_log_colour ? COLOUR(GREEN) : ""; |
58 | 59 |
59 // static | 60 // static |
60 base::LazyInstance<Simulator::GlobalMonitor>::type Simulator::global_monitor_ = | 61 base::LazyInstance<Simulator::GlobalMonitor>::type Simulator::global_monitor_ = |
61 LAZY_INSTANCE_INITIALIZER; | 62 LAZY_INSTANCE_INITIALIZER; |
62 | 63 |
63 // This is basically the same as PrintF, with a guard for FLAG_trace_sim. | 64 // This is basically the same as PrintF, with a guard for FLAG_trace_sim. |
(...skipping 159 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
223 return CallInt64(entry, args); | 224 return CallInt64(entry, args); |
224 } | 225 } |
225 | 226 |
226 | 227 |
227 void Simulator::CheckPCSComplianceAndRun() { | 228 void Simulator::CheckPCSComplianceAndRun() { |
228 // Adjust JS-based stack limit to C-based stack limit. | 229 // Adjust JS-based stack limit to C-based stack limit. |
229 isolate_->stack_guard()->AdjustStackLimitForSimulator(); | 230 isolate_->stack_guard()->AdjustStackLimitForSimulator(); |
230 | 231 |
231 #ifdef DEBUG | 232 #ifdef DEBUG |
232 CHECK_EQ(kNumberOfCalleeSavedRegisters, kCalleeSaved.Count()); | 233 CHECK_EQ(kNumberOfCalleeSavedRegisters, kCalleeSaved.Count()); |
233 CHECK_EQ(kNumberOfCalleeSavedFPRegisters, kCalleeSavedFP.Count()); | 234 CHECK_EQ(kNumberOfCalleeSavedVRegisters, kCalleeSavedV.Count()); |
234 | 235 |
235 int64_t saved_registers[kNumberOfCalleeSavedRegisters]; | 236 int64_t saved_registers[kNumberOfCalleeSavedRegisters]; |
236 uint64_t saved_fpregisters[kNumberOfCalleeSavedFPRegisters]; | 237 uint64_t saved_fpregisters[kNumberOfCalleeSavedVRegisters]; |
237 | 238 |
238 CPURegList register_list = kCalleeSaved; | 239 CPURegList register_list = kCalleeSaved; |
239 CPURegList fpregister_list = kCalleeSavedFP; | 240 CPURegList fpregister_list = kCalleeSavedV; |
240 | 241 |
241 for (int i = 0; i < kNumberOfCalleeSavedRegisters; i++) { | 242 for (int i = 0; i < kNumberOfCalleeSavedRegisters; i++) { |
242 // x31 is not a caller saved register, so no need to specify if we want | 243 // x31 is not a caller saved register, so no need to specify if we want |
243 // the stack or zero. | 244 // the stack or zero. |
244 saved_registers[i] = xreg(register_list.PopLowestIndex().code()); | 245 saved_registers[i] = xreg(register_list.PopLowestIndex().code()); |
245 } | 246 } |
246 for (int i = 0; i < kNumberOfCalleeSavedFPRegisters; i++) { | 247 for (int i = 0; i < kNumberOfCalleeSavedVRegisters; i++) { |
247 saved_fpregisters[i] = | 248 saved_fpregisters[i] = |
248 dreg_bits(fpregister_list.PopLowestIndex().code()); | 249 dreg_bits(fpregister_list.PopLowestIndex().code()); |
249 } | 250 } |
250 int64_t original_stack = sp(); | 251 int64_t original_stack = sp(); |
251 #endif | 252 #endif |
252 // Start the simulation! | 253 // Start the simulation! |
253 Run(); | 254 Run(); |
254 #ifdef DEBUG | 255 #ifdef DEBUG |
255 CHECK_EQ(original_stack, sp()); | 256 CHECK_EQ(original_stack, sp()); |
256 // Check that callee-saved registers have been preserved. | 257 // Check that callee-saved registers have been preserved. |
257 register_list = kCalleeSaved; | 258 register_list = kCalleeSaved; |
258 fpregister_list = kCalleeSavedFP; | 259 fpregister_list = kCalleeSavedV; |
259 for (int i = 0; i < kNumberOfCalleeSavedRegisters; i++) { | 260 for (int i = 0; i < kNumberOfCalleeSavedRegisters; i++) { |
260 CHECK_EQ(saved_registers[i], xreg(register_list.PopLowestIndex().code())); | 261 CHECK_EQ(saved_registers[i], xreg(register_list.PopLowestIndex().code())); |
261 } | 262 } |
262 for (int i = 0; i < kNumberOfCalleeSavedFPRegisters; i++) { | 263 for (int i = 0; i < kNumberOfCalleeSavedVRegisters; i++) { |
263 DCHECK(saved_fpregisters[i] == | 264 DCHECK(saved_fpregisters[i] == |
264 dreg_bits(fpregister_list.PopLowestIndex().code())); | 265 dreg_bits(fpregister_list.PopLowestIndex().code())); |
265 } | 266 } |
266 | 267 |
267 // Corrupt caller saved register minus the return regiters. | 268 // Corrupt caller saved register minus the return regiters. |
268 | 269 |
269 // In theory x0 to x7 can be used for return values, but V8 only uses x0, x1 | 270 // In theory x0 to x7 can be used for return values, but V8 only uses x0, x1 |
270 // for now . | 271 // for now . |
271 register_list = kCallerSaved; | 272 register_list = kCallerSaved; |
272 register_list.Remove(x0); | 273 register_list.Remove(x0); |
273 register_list.Remove(x1); | 274 register_list.Remove(x1); |
274 | 275 |
275 // In theory d0 to d7 can be used for return values, but V8 only uses d0 | 276 // In theory d0 to d7 can be used for return values, but V8 only uses d0 |
276 // for now . | 277 // for now . |
277 fpregister_list = kCallerSavedFP; | 278 fpregister_list = kCallerSavedV; |
278 fpregister_list.Remove(d0); | 279 fpregister_list.Remove(d0); |
279 | 280 |
280 CorruptRegisters(®ister_list, kCallerSavedRegisterCorruptionValue); | 281 CorruptRegisters(®ister_list, kCallerSavedRegisterCorruptionValue); |
281 CorruptRegisters(&fpregister_list, kCallerSavedFPRegisterCorruptionValue); | 282 CorruptRegisters(&fpregister_list, kCallerSavedVRegisterCorruptionValue); |
282 #endif | 283 #endif |
283 } | 284 } |
284 | 285 |
285 | 286 |
286 #ifdef DEBUG | 287 #ifdef DEBUG |
287 // The least significant byte of the curruption value holds the corresponding | 288 // The least significant byte of the curruption value holds the corresponding |
288 // register's code. | 289 // register's code. |
289 void Simulator::CorruptRegisters(CPURegList* list, uint64_t value) { | 290 void Simulator::CorruptRegisters(CPURegList* list, uint64_t value) { |
290 if (list->type() == CPURegister::kRegister) { | 291 if (list->type() == CPURegister::kRegister) { |
291 while (!list->IsEmpty()) { | 292 while (!list->IsEmpty()) { |
292 unsigned code = list->PopLowestIndex().code(); | 293 unsigned code = list->PopLowestIndex().code(); |
293 set_xreg(code, value | code); | 294 set_xreg(code, value | code); |
294 } | 295 } |
295 } else { | 296 } else { |
296 DCHECK(list->type() == CPURegister::kFPRegister); | 297 DCHECK_EQ(list->type(), CPURegister::kVRegister); |
297 while (!list->IsEmpty()) { | 298 while (!list->IsEmpty()) { |
298 unsigned code = list->PopLowestIndex().code(); | 299 unsigned code = list->PopLowestIndex().code(); |
299 set_dreg_bits(code, value | code); | 300 set_dreg_bits(code, value | code); |
300 } | 301 } |
301 } | 302 } |
302 } | 303 } |
303 | 304 |
304 | 305 |
305 void Simulator::CorruptAllCallerSavedCPURegisters() { | 306 void Simulator::CorruptAllCallerSavedCPURegisters() { |
306 // Corrupt alters its parameter so copy them first. | 307 // Corrupt alters its parameter so copy them first. |
307 CPURegList register_list = kCallerSaved; | 308 CPURegList register_list = kCallerSaved; |
308 CPURegList fpregister_list = kCallerSavedFP; | 309 CPURegList fpregister_list = kCallerSavedV; |
309 | 310 |
310 CorruptRegisters(®ister_list, kCallerSavedRegisterCorruptionValue); | 311 CorruptRegisters(®ister_list, kCallerSavedRegisterCorruptionValue); |
311 CorruptRegisters(&fpregister_list, kCallerSavedFPRegisterCorruptionValue); | 312 CorruptRegisters(&fpregister_list, kCallerSavedVRegisterCorruptionValue); |
312 } | 313 } |
313 #endif | 314 #endif |
314 | 315 |
315 | 316 |
316 // Extending the stack by 2 * 64 bits is required for stack alignment purposes. | 317 // Extending the stack by 2 * 64 bits is required for stack alignment purposes. |
317 uintptr_t Simulator::PushAddress(uintptr_t address) { | 318 uintptr_t Simulator::PushAddress(uintptr_t address) { |
318 DCHECK(sizeof(uintptr_t) < 2 * kXRegSize); | 319 DCHECK(sizeof(uintptr_t) < 2 * kXRegSize); |
319 intptr_t new_sp = sp() - 2 * kXRegSize; | 320 intptr_t new_sp = sp() - 2 * kXRegSize; |
320 uintptr_t* alignment_slot = | 321 uintptr_t* alignment_slot = |
321 reinterpret_cast<uintptr_t*>(new_sp + kXRegSize); | 322 reinterpret_cast<uintptr_t*>(new_sp + kXRegSize); |
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
409 void Simulator::ResetState() { | 410 void Simulator::ResetState() { |
410 // Reset the system registers. | 411 // Reset the system registers. |
411 nzcv_ = SimSystemRegister::DefaultValueFor(NZCV); | 412 nzcv_ = SimSystemRegister::DefaultValueFor(NZCV); |
412 fpcr_ = SimSystemRegister::DefaultValueFor(FPCR); | 413 fpcr_ = SimSystemRegister::DefaultValueFor(FPCR); |
413 | 414 |
414 // Reset registers to 0. | 415 // Reset registers to 0. |
415 pc_ = NULL; | 416 pc_ = NULL; |
416 for (unsigned i = 0; i < kNumberOfRegisters; i++) { | 417 for (unsigned i = 0; i < kNumberOfRegisters; i++) { |
417 set_xreg(i, 0xbadbeef); | 418 set_xreg(i, 0xbadbeef); |
418 } | 419 } |
419 for (unsigned i = 0; i < kNumberOfFPRegisters; i++) { | 420 for (unsigned i = 0; i < kNumberOfVRegisters; i++) { |
420 // Set FP registers to a value that is NaN in both 32-bit and 64-bit FP. | 421 // Set FP registers to a value that is NaN in both 32-bit and 64-bit FP. |
421 set_dreg_bits(i, 0x7ff000007f800001UL); | 422 set_dreg_bits(i, 0x7ff000007f800001UL); |
422 } | 423 } |
423 // Returning to address 0 exits the Simulator. | 424 // Returning to address 0 exits the Simulator. |
424 set_lr(kEndOfSimAddress); | 425 set_lr(kEndOfSimAddress); |
425 | 426 |
426 // Reset debug helpers. | 427 // Reset debug helpers. |
427 breakpoints_.empty(); | 428 breakpoints_.empty(); |
428 break_on_next_ = false; | 429 break_on_next_ = false; |
429 } | 430 } |
430 | 431 |
431 | 432 |
432 Simulator::~Simulator() { | 433 Simulator::~Simulator() { |
433 global_monitor_.Pointer()->RemoveProcessor(&global_monitor_processor_); | 434 global_monitor_.Pointer()->RemoveProcessor(&global_monitor_processor_); |
434 delete[] reinterpret_cast<byte*>(stack_); | 435 delete[] reinterpret_cast<byte*>(stack_); |
435 if (FLAG_log_instruction_stats) { | 436 if (FLAG_log_instruction_stats) { |
436 delete instrument_; | 437 delete instrument_; |
437 } | 438 } |
438 delete disassembler_decoder_; | 439 delete disassembler_decoder_; |
439 delete print_disasm_; | 440 delete print_disasm_; |
440 DeleteArray(last_debugger_input_); | 441 DeleteArray(last_debugger_input_); |
441 delete decoder_; | 442 delete decoder_; |
442 } | 443 } |
443 | 444 |
444 | 445 |
445 void Simulator::Run() { | 446 void Simulator::Run() { |
| 447 // Flush any written registers before executing anything, so that |
| 448 // manually-set registers are logged _before_ the first instruction. |
| 449 LogAllWrittenRegisters(); |
| 450 |
446 pc_modified_ = false; | 451 pc_modified_ = false; |
447 while (pc_ != kEndOfSimAddress) { | 452 while (pc_ != kEndOfSimAddress) { |
448 ExecuteInstruction(); | 453 ExecuteInstruction(); |
449 } | 454 } |
450 } | 455 } |
451 | 456 |
452 | 457 |
453 void Simulator::RunFrom(Instruction* start) { | 458 void Simulator::RunFrom(Instruction* start) { |
454 set_pc(start); | 459 set_pc(start); |
455 Run(); | 460 Run(); |
(...skipping 376 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
832 "d24", "d25", "d26", "d27", "d28", "d29", "d30", "d31"}; | 837 "d24", "d25", "d26", "d27", "d28", "d29", "d30", "d31"}; |
833 | 838 |
834 const char* Simulator::vreg_names[] = { | 839 const char* Simulator::vreg_names[] = { |
835 "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", | 840 "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", |
836 "v8", "v9", "v10", "v11", "v12", "v13", "v14", "v15", | 841 "v8", "v9", "v10", "v11", "v12", "v13", "v14", "v15", |
837 "v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23", | 842 "v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23", |
838 "v24", "v25", "v26", "v27", "v28", "v29", "v30", "v31"}; | 843 "v24", "v25", "v26", "v27", "v28", "v29", "v30", "v31"}; |
839 | 844 |
840 | 845 |
841 const char* Simulator::WRegNameForCode(unsigned code, Reg31Mode mode) { | 846 const char* Simulator::WRegNameForCode(unsigned code, Reg31Mode mode) { |
842 STATIC_ASSERT(arraysize(Simulator::wreg_names) == (kNumberOfRegisters + 1)); | 847 static_assert(arraysize(Simulator::wreg_names) == (kNumberOfRegisters + 1), |
843 DCHECK(code < kNumberOfRegisters); | 848 "Array must be large enough to hold all register names."); |
| 849 DCHECK_LT(code, static_cast<unsigned>(kNumberOfRegisters)); |
844 // The modulo operator has no effect here, but it silences a broken GCC | 850 // The modulo operator has no effect here, but it silences a broken GCC |
845 // warning about out-of-bounds array accesses. | 851 // warning about out-of-bounds array accesses. |
846 code %= kNumberOfRegisters; | 852 code %= kNumberOfRegisters; |
847 | 853 |
848 // If the code represents the stack pointer, index the name after zr. | 854 // If the code represents the stack pointer, index the name after zr. |
849 if ((code == kZeroRegCode) && (mode == Reg31IsStackPointer)) { | 855 if ((code == kZeroRegCode) && (mode == Reg31IsStackPointer)) { |
850 code = kZeroRegCode + 1; | 856 code = kZeroRegCode + 1; |
851 } | 857 } |
852 return wreg_names[code]; | 858 return wreg_names[code]; |
853 } | 859 } |
854 | 860 |
855 | 861 |
856 const char* Simulator::XRegNameForCode(unsigned code, Reg31Mode mode) { | 862 const char* Simulator::XRegNameForCode(unsigned code, Reg31Mode mode) { |
857 STATIC_ASSERT(arraysize(Simulator::xreg_names) == (kNumberOfRegisters + 1)); | 863 static_assert(arraysize(Simulator::xreg_names) == (kNumberOfRegisters + 1), |
858 DCHECK(code < kNumberOfRegisters); | 864 "Array must be large enough to hold all register names."); |
| 865 DCHECK_LT(code, static_cast<unsigned>(kNumberOfRegisters)); |
859 code %= kNumberOfRegisters; | 866 code %= kNumberOfRegisters; |
860 | 867 |
861 // If the code represents the stack pointer, index the name after zr. | 868 // If the code represents the stack pointer, index the name after zr. |
862 if ((code == kZeroRegCode) && (mode == Reg31IsStackPointer)) { | 869 if ((code == kZeroRegCode) && (mode == Reg31IsStackPointer)) { |
863 code = kZeroRegCode + 1; | 870 code = kZeroRegCode + 1; |
864 } | 871 } |
865 return xreg_names[code]; | 872 return xreg_names[code]; |
866 } | 873 } |
867 | 874 |
868 | 875 |
869 const char* Simulator::SRegNameForCode(unsigned code) { | 876 const char* Simulator::SRegNameForCode(unsigned code) { |
870 STATIC_ASSERT(arraysize(Simulator::sreg_names) == kNumberOfFPRegisters); | 877 static_assert(arraysize(Simulator::sreg_names) == kNumberOfVRegisters, |
871 DCHECK(code < kNumberOfFPRegisters); | 878 "Array must be large enough to hold all register names."); |
872 return sreg_names[code % kNumberOfFPRegisters]; | 879 DCHECK_LT(code, static_cast<unsigned>(kNumberOfVRegisters)); |
| 880 return sreg_names[code % kNumberOfVRegisters]; |
873 } | 881 } |
874 | 882 |
875 | 883 |
876 const char* Simulator::DRegNameForCode(unsigned code) { | 884 const char* Simulator::DRegNameForCode(unsigned code) { |
877 STATIC_ASSERT(arraysize(Simulator::dreg_names) == kNumberOfFPRegisters); | 885 static_assert(arraysize(Simulator::dreg_names) == kNumberOfVRegisters, |
878 DCHECK(code < kNumberOfFPRegisters); | 886 "Array must be large enough to hold all register names."); |
879 return dreg_names[code % kNumberOfFPRegisters]; | 887 DCHECK_LT(code, static_cast<unsigned>(kNumberOfVRegisters)); |
| 888 return dreg_names[code % kNumberOfVRegisters]; |
880 } | 889 } |
881 | 890 |
882 | 891 |
883 const char* Simulator::VRegNameForCode(unsigned code) { | 892 const char* Simulator::VRegNameForCode(unsigned code) { |
884 STATIC_ASSERT(arraysize(Simulator::vreg_names) == kNumberOfFPRegisters); | 893 static_assert(arraysize(Simulator::vreg_names) == kNumberOfVRegisters, |
885 DCHECK(code < kNumberOfFPRegisters); | 894 "Array must be large enough to hold all register names."); |
886 return vreg_names[code % kNumberOfFPRegisters]; | 895 DCHECK_LT(code, static_cast<unsigned>(kNumberOfVRegisters)); |
| 896 return vreg_names[code % kNumberOfVRegisters]; |
| 897 } |
| 898 |
| 899 void LogicVRegister::ReadUintFromMem(VectorFormat vform, int index, |
| 900 uint64_t addr) const { |
| 901 switch (LaneSizeInBitsFromFormat(vform)) { |
| 902 case 8: |
| 903 register_.Insert(index, SimMemory::Read<uint8_t>(addr)); |
| 904 break; |
| 905 case 16: |
| 906 register_.Insert(index, SimMemory::Read<uint16_t>(addr)); |
| 907 break; |
| 908 case 32: |
| 909 register_.Insert(index, SimMemory::Read<uint32_t>(addr)); |
| 910 break; |
| 911 case 64: |
| 912 register_.Insert(index, SimMemory::Read<uint64_t>(addr)); |
| 913 break; |
| 914 default: |
| 915 UNREACHABLE(); |
| 916 return; |
| 917 } |
| 918 } |
| 919 |
| 920 void LogicVRegister::WriteUintToMem(VectorFormat vform, int index, |
| 921 uint64_t addr) const { |
| 922 switch (LaneSizeInBitsFromFormat(vform)) { |
| 923 case 8: |
| 924 SimMemory::Write<uint8_t>(addr, static_cast<uint8_t>(Uint(vform, index))); |
| 925 break; |
| 926 case 16: |
| 927 SimMemory::Write<uint16_t>(addr, |
| 928 static_cast<uint16_t>(Uint(vform, index))); |
| 929 break; |
| 930 case 32: |
| 931 SimMemory::Write<uint32_t>(addr, |
| 932 static_cast<uint32_t>(Uint(vform, index))); |
| 933 break; |
| 934 case 64: |
| 935 SimMemory::Write<uint64_t>(addr, Uint(vform, index)); |
| 936 break; |
| 937 default: |
| 938 UNREACHABLE(); |
| 939 return; |
| 940 } |
887 } | 941 } |
888 | 942 |
889 | 943 |
890 int Simulator::CodeFromName(const char* name) { | 944 int Simulator::CodeFromName(const char* name) { |
891 for (unsigned i = 0; i < kNumberOfRegisters; i++) { | 945 for (unsigned i = 0; i < kNumberOfRegisters; i++) { |
892 if ((strcmp(xreg_names[i], name) == 0) || | 946 if ((strcmp(xreg_names[i], name) == 0) || |
893 (strcmp(wreg_names[i], name) == 0)) { | 947 (strcmp(wreg_names[i], name) == 0)) { |
894 return i; | 948 return i; |
895 } | 949 } |
896 } | 950 } |
897 for (unsigned i = 0; i < kNumberOfFPRegisters; i++) { | 951 for (unsigned i = 0; i < kNumberOfVRegisters; i++) { |
898 if ((strcmp(vreg_names[i], name) == 0) || | 952 if ((strcmp(vreg_names[i], name) == 0) || |
899 (strcmp(dreg_names[i], name) == 0) || | 953 (strcmp(dreg_names[i], name) == 0) || |
900 (strcmp(sreg_names[i], name) == 0)) { | 954 (strcmp(sreg_names[i], name) == 0)) { |
901 return i; | 955 return i; |
902 } | 956 } |
903 } | 957 } |
904 if ((strcmp("csp", name) == 0) || (strcmp("wcsp", name) == 0)) { | 958 if ((strcmp("csp", name) == 0) || (strcmp("wcsp", name) == 0)) { |
905 return kSPRegInternalCode; | 959 return kSPRegInternalCode; |
906 } | 960 } |
907 return -1; | 961 return -1; |
(...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1030 T result = op2; | 1084 T result = op2; |
1031 | 1085 |
1032 if (lsb) { | 1086 if (lsb) { |
1033 T op1 = reg<T>(instr->Rn()); | 1087 T op1 = reg<T>(instr->Rn()); |
1034 result = op2 >> lsb | (op1 << ((sizeof(T) * 8) - lsb)); | 1088 result = op2 >> lsb | (op1 << ((sizeof(T) * 8) - lsb)); |
1035 } | 1089 } |
1036 set_reg<T>(instr->Rd(), result); | 1090 set_reg<T>(instr->Rd(), result); |
1037 } | 1091 } |
1038 | 1092 |
1039 | 1093 |
1040 template<> double Simulator::FPDefaultNaN<double>() const { | |
1041 return kFP64DefaultNaN; | |
1042 } | |
1043 | |
1044 | |
1045 template<> float Simulator::FPDefaultNaN<float>() const { | |
1046 return kFP32DefaultNaN; | |
1047 } | |
1048 | |
1049 | |
1050 void Simulator::FPCompare(double val0, double val1) { | 1094 void Simulator::FPCompare(double val0, double val1) { |
1051 AssertSupportedFPCR(); | 1095 AssertSupportedFPCR(); |
1052 | 1096 |
1053 // TODO(jbramley): This assumes that the C++ implementation handles | 1097 // TODO(jbramley): This assumes that the C++ implementation handles |
1054 // comparisons in the way that we expect (as per AssertSupportedFPCR()). | 1098 // comparisons in the way that we expect (as per AssertSupportedFPCR()). |
1055 if ((std::isnan(val0) != 0) || (std::isnan(val1) != 0)) { | 1099 if ((std::isnan(val0) != 0) || (std::isnan(val1) != 0)) { |
1056 nzcv().SetRawValue(FPUnorderedFlag); | 1100 nzcv().SetRawValue(FPUnorderedFlag); |
1057 } else if (val0 < val1) { | 1101 } else if (val0 < val1) { |
1058 nzcv().SetRawValue(FPLessThanFlag); | 1102 nzcv().SetRawValue(FPLessThanFlag); |
1059 } else if (val0 > val1) { | 1103 } else if (val0 > val1) { |
1060 nzcv().SetRawValue(FPGreaterThanFlag); | 1104 nzcv().SetRawValue(FPGreaterThanFlag); |
1061 } else if (val0 == val1) { | 1105 } else if (val0 == val1) { |
1062 nzcv().SetRawValue(FPEqualFlag); | 1106 nzcv().SetRawValue(FPEqualFlag); |
1063 } else { | 1107 } else { |
1064 UNREACHABLE(); | 1108 UNREACHABLE(); |
1065 } | 1109 } |
1066 LogSystemRegister(NZCV); | 1110 LogSystemRegister(NZCV); |
1067 } | 1111 } |
1068 | 1112 |
| 1113 Simulator::PrintRegisterFormat Simulator::GetPrintRegisterFormatForSize( |
| 1114 size_t reg_size, size_t lane_size) { |
| 1115 DCHECK_GE(reg_size, lane_size); |
| 1116 |
| 1117 uint32_t format = 0; |
| 1118 if (reg_size != lane_size) { |
| 1119 switch (reg_size) { |
| 1120 default: |
| 1121 UNREACHABLE(); |
| 1122 case kQRegSize: |
| 1123 format = kPrintRegAsQVector; |
| 1124 break; |
| 1125 case kDRegSize: |
| 1126 format = kPrintRegAsDVector; |
| 1127 break; |
| 1128 } |
| 1129 } |
| 1130 |
| 1131 switch (lane_size) { |
| 1132 default: |
| 1133 UNREACHABLE(); |
| 1134 case kQRegSize: |
| 1135 format |= kPrintReg1Q; |
| 1136 break; |
| 1137 case kDRegSize: |
| 1138 format |= kPrintReg1D; |
| 1139 break; |
| 1140 case kSRegSize: |
| 1141 format |= kPrintReg1S; |
| 1142 break; |
| 1143 case kHRegSize: |
| 1144 format |= kPrintReg1H; |
| 1145 break; |
| 1146 case kBRegSize: |
| 1147 format |= kPrintReg1B; |
| 1148 break; |
| 1149 } |
| 1150 |
| 1151 // These sizes would be duplicate case labels. |
| 1152 static_assert(kXRegSize == kDRegSize, "X and D registers must be same size."); |
| 1153 static_assert(kWRegSize == kSRegSize, "W and S registers must be same size."); |
| 1154 static_assert(kPrintXReg == kPrintReg1D, |
| 1155 "X and D register printing code is shared."); |
| 1156 static_assert(kPrintWReg == kPrintReg1S, |
| 1157 "W and S register printing code is shared."); |
| 1158 |
| 1159 return static_cast<PrintRegisterFormat>(format); |
| 1160 } |
| 1161 |
| 1162 Simulator::PrintRegisterFormat Simulator::GetPrintRegisterFormat( |
| 1163 VectorFormat vform) { |
| 1164 switch (vform) { |
| 1165 default: |
| 1166 UNREACHABLE(); |
| 1167 case kFormat16B: |
| 1168 return kPrintReg16B; |
| 1169 case kFormat8B: |
| 1170 return kPrintReg8B; |
| 1171 case kFormat8H: |
| 1172 return kPrintReg8H; |
| 1173 case kFormat4H: |
| 1174 return kPrintReg4H; |
| 1175 case kFormat4S: |
| 1176 return kPrintReg4S; |
| 1177 case kFormat2S: |
| 1178 return kPrintReg2S; |
| 1179 case kFormat2D: |
| 1180 return kPrintReg2D; |
| 1181 case kFormat1D: |
| 1182 return kPrintReg1D; |
| 1183 |
| 1184 case kFormatB: |
| 1185 return kPrintReg1B; |
| 1186 case kFormatH: |
| 1187 return kPrintReg1H; |
| 1188 case kFormatS: |
| 1189 return kPrintReg1S; |
| 1190 case kFormatD: |
| 1191 return kPrintReg1D; |
| 1192 } |
| 1193 } |
| 1194 |
| 1195 Simulator::PrintRegisterFormat Simulator::GetPrintRegisterFormatFP( |
| 1196 VectorFormat vform) { |
| 1197 switch (vform) { |
| 1198 default: |
| 1199 UNREACHABLE(); |
| 1200 case kFormat4S: |
| 1201 return kPrintReg4SFP; |
| 1202 case kFormat2S: |
| 1203 return kPrintReg2SFP; |
| 1204 case kFormat2D: |
| 1205 return kPrintReg2DFP; |
| 1206 case kFormat1D: |
| 1207 return kPrintReg1DFP; |
| 1208 |
| 1209 case kFormatS: |
| 1210 return kPrintReg1SFP; |
| 1211 case kFormatD: |
| 1212 return kPrintReg1DFP; |
| 1213 } |
| 1214 } |
1069 | 1215 |
1070 void Simulator::SetBreakpoint(Instruction* location) { | 1216 void Simulator::SetBreakpoint(Instruction* location) { |
1071 for (unsigned i = 0; i < breakpoints_.size(); i++) { | 1217 for (unsigned i = 0; i < breakpoints_.size(); i++) { |
1072 if (breakpoints_.at(i).location == location) { | 1218 if (breakpoints_.at(i).location == location) { |
1073 PrintF(stream_, | 1219 PrintF(stream_, |
1074 "Existing breakpoint at %p was %s\n", | 1220 "Existing breakpoint at %p was %s\n", |
1075 reinterpret_cast<void*>(location), | 1221 reinterpret_cast<void*>(location), |
1076 breakpoints_.at(i).enabled ? "disabled" : "enabled"); | 1222 breakpoints_.at(i).enabled ? "disabled" : "enabled"); |
1077 breakpoints_.at(i).enabled = !breakpoints_.at(i).enabled; | 1223 breakpoints_.at(i).enabled = !breakpoints_.at(i).enabled; |
1078 return; | 1224 return; |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1122 } | 1268 } |
1123 | 1269 |
1124 | 1270 |
1125 void Simulator::PrintInstructionsAt(Instruction* start, uint64_t count) { | 1271 void Simulator::PrintInstructionsAt(Instruction* start, uint64_t count) { |
1126 Instruction* end = start->InstructionAtOffset(count * kInstructionSize); | 1272 Instruction* end = start->InstructionAtOffset(count * kInstructionSize); |
1127 for (Instruction* pc = start; pc < end; pc = pc->following()) { | 1273 for (Instruction* pc = start; pc < end; pc = pc->following()) { |
1128 disassembler_decoder_->Decode(pc); | 1274 disassembler_decoder_->Decode(pc); |
1129 } | 1275 } |
1130 } | 1276 } |
1131 | 1277 |
| 1278 void Simulator::PrintWrittenRegisters() { |
| 1279 for (unsigned i = 0; i < kNumberOfRegisters; i++) { |
| 1280 if (registers_[i].WrittenSinceLastLog()) PrintRegister(i); |
| 1281 } |
| 1282 } |
| 1283 |
| 1284 void Simulator::PrintWrittenVRegisters() { |
| 1285 for (unsigned i = 0; i < kNumberOfVRegisters; i++) { |
| 1286 // At this point there is no type information, so print as a raw 1Q. |
| 1287 if (vregisters_[i].WrittenSinceLastLog()) PrintVRegister(i, kPrintReg1Q); |
| 1288 } |
| 1289 } |
1132 | 1290 |
1133 void Simulator::PrintSystemRegisters() { | 1291 void Simulator::PrintSystemRegisters() { |
1134 PrintSystemRegister(NZCV); | 1292 PrintSystemRegister(NZCV); |
1135 PrintSystemRegister(FPCR); | 1293 PrintSystemRegister(FPCR); |
1136 } | 1294 } |
1137 | 1295 |
1138 | 1296 |
1139 void Simulator::PrintRegisters() { | 1297 void Simulator::PrintRegisters() { |
1140 for (unsigned i = 0; i < kNumberOfRegisters; i++) { | 1298 for (unsigned i = 0; i < kNumberOfRegisters; i++) { |
1141 PrintRegister(i); | 1299 PrintRegister(i); |
1142 } | 1300 } |
1143 } | 1301 } |
1144 | 1302 |
1145 | 1303 void Simulator::PrintVRegisters() { |
1146 void Simulator::PrintFPRegisters() { | 1304 for (unsigned i = 0; i < kNumberOfVRegisters; i++) { |
1147 for (unsigned i = 0; i < kNumberOfFPRegisters; i++) { | 1305 // At this point there is no type information, so print as a raw 1Q. |
1148 PrintFPRegister(i); | 1306 PrintVRegister(i, kPrintReg1Q); |
1149 } | 1307 } |
1150 } | 1308 } |
1151 | 1309 |
1152 | 1310 |
1153 void Simulator::PrintRegister(unsigned code, Reg31Mode r31mode) { | 1311 void Simulator::PrintRegister(unsigned code, Reg31Mode r31mode) { |
| 1312 registers_[code].NotifyRegisterLogged(); |
| 1313 |
1154 // Don't print writes into xzr. | 1314 // Don't print writes into xzr. |
1155 if ((code == kZeroRegCode) && (r31mode == Reg31IsZeroRegister)) { | 1315 if ((code == kZeroRegCode) && (r31mode == Reg31IsZeroRegister)) { |
1156 return; | 1316 return; |
1157 } | 1317 } |
1158 | 1318 |
1159 // The template is "# x<code>:value". | 1319 // The template for all x and w registers: |
1160 fprintf(stream_, "# %s%5s: %s0x%016" PRIx64 "%s\n", | 1320 // "# x{code}: 0x{value}" |
1161 clr_reg_name, XRegNameForCode(code, r31mode), | 1321 // "# w{code}: 0x{value}" |
1162 clr_reg_value, reg<uint64_t>(code, r31mode), clr_normal); | 1322 |
1163 } | 1323 PrintRegisterRawHelper(code, r31mode); |
1164 | 1324 fprintf(stream_, "\n"); |
1165 | 1325 } |
1166 void Simulator::PrintFPRegister(unsigned code, PrintFPRegisterSizes sizes) { | 1326 |
1167 // The template is "# v<code>:bits (d<code>:value, ...)". | 1327 // Print a register's name and raw value. |
1168 | 1328 // |
1169 DCHECK(sizes != 0); | 1329 // The `bytes` and `lsb` arguments can be used to limit the bytes that are |
1170 DCHECK((sizes & kPrintAllFPRegValues) == sizes); | 1330 // printed. These arguments are intended for use in cases where register hasn't |
1171 | 1331 // actually been updated (such as in PrintVWrite). |
1172 // Print the raw bits. | 1332 // |
1173 fprintf(stream_, "# %s%5s: %s0x%016" PRIx64 "%s (", | 1333 // No newline is printed. This allows the caller to print more details (such as |
1174 clr_fpreg_name, VRegNameForCode(code), | 1334 // a floating-point interpretation or a memory access annotation). |
1175 clr_fpreg_value, fpreg<uint64_t>(code), clr_normal); | 1335 void Simulator::PrintVRegisterRawHelper(unsigned code, int bytes, int lsb) { |
1176 | 1336 // The template for vector types: |
1177 // Print all requested value interpretations. | 1337 // "# v{code}: 0xffeeddccbbaa99887766554433221100". |
1178 bool need_separator = false; | 1338 // An example with bytes=4 and lsb=8: |
1179 if (sizes & kPrintDRegValue) { | 1339 // "# v{code}: 0xbbaa9988 ". |
1180 fprintf(stream_, "%s%s%s: %s%g%s", | 1340 fprintf(stream_, "# %s%5s: %s", clr_vreg_name, VRegNameForCode(code), |
1181 need_separator ? ", " : "", | 1341 clr_vreg_value); |
1182 clr_fpreg_name, DRegNameForCode(code), | 1342 |
1183 clr_fpreg_value, fpreg<double>(code), clr_normal); | 1343 int msb = lsb + bytes - 1; |
1184 need_separator = true; | 1344 int byte = kQRegSize - 1; |
1185 } | 1345 |
1186 | 1346 // Print leading padding spaces. (Two spaces per byte.) |
1187 if (sizes & kPrintSRegValue) { | 1347 while (byte > msb) { |
1188 fprintf(stream_, "%s%s%s: %s%g%s", | 1348 fprintf(stream_, " "); |
1189 need_separator ? ", " : "", | 1349 byte--; |
1190 clr_fpreg_name, SRegNameForCode(code), | 1350 } |
1191 clr_fpreg_value, fpreg<float>(code), clr_normal); | 1351 |
1192 need_separator = true; | 1352 // Print the specified part of the value, byte by byte. |
1193 } | 1353 qreg_t rawbits = qreg(code); |
1194 | 1354 fprintf(stream_, "0x"); |
1195 // End the value list. | 1355 while (byte >= lsb) { |
1196 fprintf(stream_, ")\n"); | 1356 fprintf(stream_, "%02x", rawbits.val[byte]); |
1197 } | 1357 byte--; |
1198 | 1358 } |
1199 | 1359 |
| 1360 // Print trailing padding spaces. |
| 1361 while (byte >= 0) { |
| 1362 fprintf(stream_, " "); |
| 1363 byte--; |
| 1364 } |
| 1365 fprintf(stream_, "%s", clr_normal); |
| 1366 } |
| 1367 |
| 1368 // Print each of the specified lanes of a register as a float or double value. |
| 1369 // |
| 1370 // The `lane_count` and `lslane` arguments can be used to limit the lanes that |
| 1371 // are printed. These arguments are intended for use in cases where register |
| 1372 // hasn't actually been updated (such as in PrintVWrite). |
| 1373 // |
| 1374 // No newline is printed. This allows the caller to print more details (such as |
| 1375 // a memory access annotation). |
| 1376 void Simulator::PrintVRegisterFPHelper(unsigned code, |
| 1377 unsigned lane_size_in_bytes, |
| 1378 int lane_count, int rightmost_lane) { |
| 1379 DCHECK((lane_size_in_bytes == kSRegSize) || |
| 1380 (lane_size_in_bytes == kDRegSize)); |
| 1381 |
| 1382 unsigned msb = (lane_count + rightmost_lane) * lane_size_in_bytes; |
| 1383 DCHECK_LE(msb, static_cast<unsigned>(kQRegSize)); |
| 1384 |
| 1385 // For scalar types ((lane_count == 1) && (rightmost_lane == 0)), a register |
| 1386 // name is used: |
| 1387 // " (s{code}: {value})" |
| 1388 // " (d{code}: {value})" |
| 1389 // For vector types, "..." is used to represent one or more omitted lanes. |
| 1390 // " (..., {value}, {value}, ...)" |
| 1391 if ((lane_count == 1) && (rightmost_lane == 0)) { |
| 1392 const char* name = (lane_size_in_bytes == kSRegSize) |
| 1393 ? SRegNameForCode(code) |
| 1394 : DRegNameForCode(code); |
| 1395 fprintf(stream_, " (%s%s: ", clr_vreg_name, name); |
| 1396 } else { |
| 1397 if (msb < (kQRegSize - 1)) { |
| 1398 fprintf(stream_, " (..., "); |
| 1399 } else { |
| 1400 fprintf(stream_, " ("); |
| 1401 } |
| 1402 } |
| 1403 |
| 1404 // Print the list of values. |
| 1405 const char* separator = ""; |
| 1406 int leftmost_lane = rightmost_lane + lane_count - 1; |
| 1407 for (int lane = leftmost_lane; lane >= rightmost_lane; lane--) { |
| 1408 double value = (lane_size_in_bytes == kSRegSize) |
| 1409 ? vreg(code).Get<float>(lane) |
| 1410 : vreg(code).Get<double>(lane); |
| 1411 fprintf(stream_, "%s%s%#g%s", separator, clr_vreg_value, value, clr_normal); |
| 1412 separator = ", "; |
| 1413 } |
| 1414 |
| 1415 if (rightmost_lane > 0) { |
| 1416 fprintf(stream_, ", ..."); |
| 1417 } |
| 1418 fprintf(stream_, ")"); |
| 1419 } |
| 1420 |
| 1421 // Print a register's name and raw value. |
| 1422 // |
| 1423 // Only the least-significant `size_in_bytes` bytes of the register are printed, |
| 1424 // but the value is aligned as if the whole register had been printed. |
| 1425 // |
| 1426 // For typical register updates, size_in_bytes should be set to kXRegSize |
| 1427 // -- the default -- so that the whole register is printed. Other values of |
| 1428 // size_in_bytes are intended for use when the register hasn't actually been |
| 1429 // updated (such as in PrintWrite). |
| 1430 // |
| 1431 // No newline is printed. This allows the caller to print more details (such as |
| 1432 // a memory access annotation). |
| 1433 void Simulator::PrintRegisterRawHelper(unsigned code, Reg31Mode r31mode, |
| 1434 int size_in_bytes) { |
| 1435 // The template for all supported sizes. |
| 1436 // "# x{code}: 0xffeeddccbbaa9988" |
| 1437 // "# w{code}: 0xbbaa9988" |
| 1438 // "# w{code}<15:0>: 0x9988" |
| 1439 // "# w{code}<7:0>: 0x88" |
| 1440 unsigned padding_chars = (kXRegSize - size_in_bytes) * 2; |
| 1441 |
| 1442 const char* name = ""; |
| 1443 const char* suffix = ""; |
| 1444 switch (size_in_bytes) { |
| 1445 case kXRegSize: |
| 1446 name = XRegNameForCode(code, r31mode); |
| 1447 break; |
| 1448 case kWRegSize: |
| 1449 name = WRegNameForCode(code, r31mode); |
| 1450 break; |
| 1451 case 2: |
| 1452 name = WRegNameForCode(code, r31mode); |
| 1453 suffix = "<15:0>"; |
| 1454 padding_chars -= strlen(suffix); |
| 1455 break; |
| 1456 case 1: |
| 1457 name = WRegNameForCode(code, r31mode); |
| 1458 suffix = "<7:0>"; |
| 1459 padding_chars -= strlen(suffix); |
| 1460 break; |
| 1461 default: |
| 1462 UNREACHABLE(); |
| 1463 } |
| 1464 fprintf(stream_, "# %s%5s%s: ", clr_reg_name, name, suffix); |
| 1465 |
| 1466 // Print leading padding spaces. |
| 1467 DCHECK_LT(padding_chars, kXRegSize * 2U); |
| 1468 for (unsigned i = 0; i < padding_chars; i++) { |
| 1469 putc(' ', stream_); |
| 1470 } |
| 1471 |
| 1472 // Print the specified bits in hexadecimal format. |
| 1473 uint64_t bits = reg<uint64_t>(code, r31mode); |
| 1474 bits &= kXRegMask >> ((kXRegSize - size_in_bytes) * 8); |
| 1475 static_assert(sizeof(bits) == kXRegSize, |
| 1476 "X registers and uint64_t must be the same size."); |
| 1477 |
| 1478 int chars = size_in_bytes * 2; |
| 1479 fprintf(stream_, "%s0x%0*" PRIx64 "%s", clr_reg_value, chars, bits, |
| 1480 clr_normal); |
| 1481 } |
| 1482 |
| 1483 void Simulator::PrintVRegister(unsigned code, PrintRegisterFormat format) { |
| 1484 vregisters_[code].NotifyRegisterLogged(); |
| 1485 |
| 1486 int lane_size_log2 = format & kPrintRegLaneSizeMask; |
| 1487 |
| 1488 int reg_size_log2; |
| 1489 if (format & kPrintRegAsQVector) { |
| 1490 reg_size_log2 = kQRegSizeLog2; |
| 1491 } else if (format & kPrintRegAsDVector) { |
| 1492 reg_size_log2 = kDRegSizeLog2; |
| 1493 } else { |
| 1494 // Scalar types. |
| 1495 reg_size_log2 = lane_size_log2; |
| 1496 } |
| 1497 |
| 1498 int lane_count = 1 << (reg_size_log2 - lane_size_log2); |
| 1499 int lane_size = 1 << lane_size_log2; |
| 1500 |
| 1501 // The template for vector types: |
| 1502 // "# v{code}: 0x{rawbits} (..., {value}, ...)". |
| 1503 // The template for scalar types: |
| 1504 // "# v{code}: 0x{rawbits} ({reg}:{value})". |
| 1505 // The values in parentheses after the bit representations are floating-point |
| 1506 // interpretations. They are displayed only if the kPrintVRegAsFP bit is set. |
| 1507 |
| 1508 PrintVRegisterRawHelper(code); |
| 1509 if (format & kPrintRegAsFP) { |
| 1510 PrintVRegisterFPHelper(code, lane_size, lane_count); |
| 1511 } |
| 1512 |
| 1513 fprintf(stream_, "\n"); |
| 1514 } |
| 1515 |
| 1516 |
1200 void Simulator::PrintSystemRegister(SystemRegister id) { | 1517 void Simulator::PrintSystemRegister(SystemRegister id) { |
1201 switch (id) { | 1518 switch (id) { |
1202 case NZCV: | 1519 case NZCV: |
1203 fprintf(stream_, "# %sNZCV: %sN:%d Z:%d C:%d V:%d%s\n", | 1520 fprintf(stream_, "# %sNZCV: %sN:%d Z:%d C:%d V:%d%s\n", |
1204 clr_flag_name, clr_flag_value, | 1521 clr_flag_name, clr_flag_value, |
1205 nzcv().N(), nzcv().Z(), nzcv().C(), nzcv().V(), | 1522 nzcv().N(), nzcv().Z(), nzcv().C(), nzcv().V(), |
1206 clr_normal); | 1523 clr_normal); |
1207 break; | 1524 break; |
1208 case FPCR: { | 1525 case FPCR: { |
1209 static const char * rmode[] = { | 1526 static const char * rmode[] = { |
1210 "0b00 (Round to Nearest)", | 1527 "0b00 (Round to Nearest)", |
1211 "0b01 (Round towards Plus Infinity)", | 1528 "0b01 (Round towards Plus Infinity)", |
1212 "0b10 (Round towards Minus Infinity)", | 1529 "0b10 (Round towards Minus Infinity)", |
1213 "0b11 (Round towards Zero)" | 1530 "0b11 (Round towards Zero)" |
1214 }; | 1531 }; |
1215 DCHECK(fpcr().RMode() < arraysize(rmode)); | 1532 DCHECK(fpcr().RMode() < arraysize(rmode)); |
1216 fprintf(stream_, | 1533 fprintf(stream_, |
1217 "# %sFPCR: %sAHP:%d DN:%d FZ:%d RMode:%s%s\n", | 1534 "# %sFPCR: %sAHP:%d DN:%d FZ:%d RMode:%s%s\n", |
1218 clr_flag_name, clr_flag_value, | 1535 clr_flag_name, clr_flag_value, |
1219 fpcr().AHP(), fpcr().DN(), fpcr().FZ(), rmode[fpcr().RMode()], | 1536 fpcr().AHP(), fpcr().DN(), fpcr().FZ(), rmode[fpcr().RMode()], |
1220 clr_normal); | 1537 clr_normal); |
1221 break; | 1538 break; |
1222 } | 1539 } |
1223 default: | 1540 default: |
1224 UNREACHABLE(); | 1541 UNREACHABLE(); |
1225 } | 1542 } |
1226 } | 1543 } |
1227 | 1544 |
| 1545 void Simulator::PrintRead(uintptr_t address, unsigned reg_code, |
| 1546 PrintRegisterFormat format) { |
| 1547 registers_[reg_code].NotifyRegisterLogged(); |
1228 | 1548 |
1229 void Simulator::PrintRead(uintptr_t address, | 1549 USE(format); |
1230 size_t size, | |
1231 unsigned reg_code) { | |
1232 USE(size); // Size is unused here. | |
1233 | 1550 |
1234 // The template is "# x<code>:value <- address". | 1551 // The template is "# {reg}: 0x{value} <- {address}". |
1235 fprintf(stream_, "# %s%5s: %s0x%016" PRIx64 "%s", | 1552 PrintRegisterRawHelper(reg_code, Reg31IsZeroRegister); |
1236 clr_reg_name, XRegNameForCode(reg_code), | |
1237 clr_reg_value, reg<uint64_t>(reg_code), clr_normal); | |
1238 | |
1239 fprintf(stream_, " <- %s0x%016" PRIxPTR "%s\n", | 1553 fprintf(stream_, " <- %s0x%016" PRIxPTR "%s\n", |
1240 clr_memory_address, address, clr_normal); | 1554 clr_memory_address, address, clr_normal); |
1241 } | 1555 } |
1242 | 1556 |
| 1557 void Simulator::PrintVRead(uintptr_t address, unsigned reg_code, |
| 1558 PrintRegisterFormat format, unsigned lane) { |
| 1559 vregisters_[reg_code].NotifyRegisterLogged(); |
1243 | 1560 |
1244 void Simulator::PrintReadFP(uintptr_t address, | 1561 // The template is "# v{code}: 0x{rawbits} <- address". |
1245 size_t size, | 1562 PrintVRegisterRawHelper(reg_code); |
1246 unsigned reg_code) { | 1563 if (format & kPrintRegAsFP) { |
1247 // The template is "# reg:bits (reg:value) <- address". | 1564 PrintVRegisterFPHelper(reg_code, GetPrintRegLaneSizeInBytes(format), |
1248 switch (size) { | 1565 GetPrintRegLaneCount(format), lane); |
1249 case kSRegSize: | |
1250 fprintf(stream_, "# %s%5s: %s0x%016" PRIx64 "%s (%s%s: %s%gf%s)", | |
1251 clr_fpreg_name, VRegNameForCode(reg_code), | |
1252 clr_fpreg_value, fpreg<uint64_t>(reg_code), clr_normal, | |
1253 clr_fpreg_name, SRegNameForCode(reg_code), | |
1254 clr_fpreg_value, fpreg<float>(reg_code), clr_normal); | |
1255 break; | |
1256 case kDRegSize: | |
1257 fprintf(stream_, "# %s%5s: %s0x%016" PRIx64 "%s (%s%s: %s%g%s)", | |
1258 clr_fpreg_name, VRegNameForCode(reg_code), | |
1259 clr_fpreg_value, fpreg<uint64_t>(reg_code), clr_normal, | |
1260 clr_fpreg_name, DRegNameForCode(reg_code), | |
1261 clr_fpreg_value, fpreg<double>(reg_code), clr_normal); | |
1262 break; | |
1263 default: | |
1264 UNREACHABLE(); | |
1265 } | 1566 } |
1266 | |
1267 fprintf(stream_, " <- %s0x%016" PRIxPTR "%s\n", | 1567 fprintf(stream_, " <- %s0x%016" PRIxPTR "%s\n", |
1268 clr_memory_address, address, clr_normal); | 1568 clr_memory_address, address, clr_normal); |
1269 } | 1569 } |
1270 | 1570 |
| 1571 void Simulator::PrintWrite(uintptr_t address, unsigned reg_code, |
| 1572 PrintRegisterFormat format) { |
| 1573 DCHECK_EQ(GetPrintRegLaneCount(format), 1U); |
1271 | 1574 |
1272 void Simulator::PrintWrite(uintptr_t address, | 1575 // The template is "# v{code}: 0x{value} -> {address}". To keep the trace tidy |
1273 size_t size, | 1576 // and readable, the value is aligned with the values in the register trace. |
1274 unsigned reg_code) { | 1577 PrintRegisterRawHelper(reg_code, Reg31IsZeroRegister, |
1275 // The template is "# reg:value -> address". To keep the trace tidy and | 1578 GetPrintRegSizeInBytes(format)); |
1276 // readable, the value is aligned with the values in the register trace. | |
1277 switch (size) { | |
1278 case kByteSizeInBytes: | |
1279 fprintf(stream_, "# %s%5s<7:0>: %s0x%02" PRIx8 "%s", | |
1280 clr_reg_name, WRegNameForCode(reg_code), | |
1281 clr_reg_value, reg<uint8_t>(reg_code), clr_normal); | |
1282 break; | |
1283 case kHalfWordSizeInBytes: | |
1284 fprintf(stream_, "# %s%5s<15:0>: %s0x%04" PRIx16 "%s", | |
1285 clr_reg_name, WRegNameForCode(reg_code), | |
1286 clr_reg_value, reg<uint16_t>(reg_code), clr_normal); | |
1287 break; | |
1288 case kWRegSize: | |
1289 fprintf(stream_, "# %s%5s: %s0x%08" PRIx32 "%s", | |
1290 clr_reg_name, WRegNameForCode(reg_code), | |
1291 clr_reg_value, reg<uint32_t>(reg_code), clr_normal); | |
1292 break; | |
1293 case kXRegSize: | |
1294 fprintf(stream_, "# %s%5s: %s0x%016" PRIx64 "%s", | |
1295 clr_reg_name, XRegNameForCode(reg_code), | |
1296 clr_reg_value, reg<uint64_t>(reg_code), clr_normal); | |
1297 break; | |
1298 default: | |
1299 UNREACHABLE(); | |
1300 } | |
1301 | |
1302 fprintf(stream_, " -> %s0x%016" PRIxPTR "%s\n", | 1579 fprintf(stream_, " -> %s0x%016" PRIxPTR "%s\n", |
1303 clr_memory_address, address, clr_normal); | 1580 clr_memory_address, address, clr_normal); |
1304 } | 1581 } |
1305 | 1582 |
1306 | 1583 void Simulator::PrintVWrite(uintptr_t address, unsigned reg_code, |
1307 void Simulator::PrintWriteFP(uintptr_t address, | 1584 PrintRegisterFormat format, unsigned lane) { |
1308 size_t size, | 1585 // The templates: |
1309 unsigned reg_code) { | 1586 // "# v{code}: 0x{rawbits} -> {address}" |
1310 // The template is "# reg:bits (reg:value) -> address". To keep the trace tidy | 1587 // "# v{code}: 0x{rawbits} (..., {value}, ...) -> {address}". |
1311 // and readable, the value is aligned with the values in the register trace. | 1588 // "# v{code}: 0x{rawbits} ({reg}:{value}) -> {address}" |
1312 switch (size) { | 1589 // Because this trace doesn't represent a change to the source register's |
1313 case kSRegSize: | 1590 // value, only the relevant part of the value is printed. To keep the trace |
1314 fprintf(stream_, "# %s%5s<31:0>: %s0x%08" PRIx32 "%s (%s%s: %s%gf%s)", | 1591 // tidy and readable, the raw value is aligned with the other values in the |
1315 clr_fpreg_name, VRegNameForCode(reg_code), | 1592 // register trace. |
1316 clr_fpreg_value, fpreg<uint32_t>(reg_code), clr_normal, | 1593 int lane_count = GetPrintRegLaneCount(format); |
1317 clr_fpreg_name, SRegNameForCode(reg_code), | 1594 int lane_size = GetPrintRegLaneSizeInBytes(format); |
1318 clr_fpreg_value, fpreg<float>(reg_code), clr_normal); | 1595 int reg_size = GetPrintRegSizeInBytes(format); |
1319 break; | 1596 PrintVRegisterRawHelper(reg_code, reg_size, lane_size * lane); |
1320 case kDRegSize: | 1597 if (format & kPrintRegAsFP) { |
1321 fprintf(stream_, "# %s%5s: %s0x%016" PRIx64 "%s (%s%s: %s%g%s)", | 1598 PrintVRegisterFPHelper(reg_code, lane_size, lane_count, lane); |
1322 clr_fpreg_name, VRegNameForCode(reg_code), | |
1323 clr_fpreg_value, fpreg<uint64_t>(reg_code), clr_normal, | |
1324 clr_fpreg_name, DRegNameForCode(reg_code), | |
1325 clr_fpreg_value, fpreg<double>(reg_code), clr_normal); | |
1326 break; | |
1327 default: | |
1328 UNREACHABLE(); | |
1329 } | 1599 } |
1330 | |
1331 fprintf(stream_, " -> %s0x%016" PRIxPTR "%s\n", | 1600 fprintf(stream_, " -> %s0x%016" PRIxPTR "%s\n", |
1332 clr_memory_address, address, clr_normal); | 1601 clr_memory_address, address, clr_normal); |
1333 } | 1602 } |
1334 | 1603 |
1335 | 1604 |
1336 // Visitors--------------------------------------------------------------------- | 1605 // Visitors--------------------------------------------------------------------- |
1337 | 1606 |
1338 void Simulator::VisitUnimplemented(Instruction* instr) { | 1607 void Simulator::VisitUnimplemented(Instruction* instr) { |
1339 fprintf(stream_, "Unimplemented instruction at %p: 0x%08" PRIx32 "\n", | 1608 fprintf(stream_, "Unimplemented instruction at %p: 0x%08" PRIx32 "\n", |
1340 reinterpret_cast<void*>(instr), instr->InstructionBits()); | 1609 reinterpret_cast<void*>(instr), instr->InstructionBits()); |
(...skipping 325 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1666 // below ensures that push operations are safe even when interrupted: the | 1935 // below ensures that push operations are safe even when interrupted: the |
1667 // stack pointer will be decremented before adding an element to the stack. | 1936 // stack pointer will be decremented before adding an element to the stack. |
1668 if (instr->IsStore()) { | 1937 if (instr->IsStore()) { |
1669 LoadStoreWriteBack(addr_reg, offset, addrmode); | 1938 LoadStoreWriteBack(addr_reg, offset, addrmode); |
1670 | 1939 |
1671 // For store the address post writeback is used to check access below the | 1940 // For store the address post writeback is used to check access below the |
1672 // stack. | 1941 // stack. |
1673 stack = sp(); | 1942 stack = sp(); |
1674 } | 1943 } |
1675 | 1944 |
1676 LoadStoreOp op = static_cast<LoadStoreOp>(instr->Mask(LoadStoreOpMask)); | 1945 LoadStoreOp op = static_cast<LoadStoreOp>(instr->Mask(LoadStoreMask)); |
1677 switch (op) { | 1946 switch (op) { |
1678 // Use _no_log variants to suppress the register trace (LOG_REGS, | 1947 // Use _no_log variants to suppress the register trace (LOG_REGS, |
1679 // LOG_FP_REGS). We will print a more detailed log. | 1948 // LOG_VREGS). We will print a more detailed log. |
1680 case LDRB_w: set_wreg_no_log(srcdst, MemoryRead<uint8_t>(address)); break; | 1949 case LDRB_w: set_wreg_no_log(srcdst, MemoryRead<uint8_t>(address)); break; |
1681 case LDRH_w: set_wreg_no_log(srcdst, MemoryRead<uint16_t>(address)); break; | 1950 case LDRH_w: set_wreg_no_log(srcdst, MemoryRead<uint16_t>(address)); break; |
1682 case LDR_w: set_wreg_no_log(srcdst, MemoryRead<uint32_t>(address)); break; | 1951 case LDR_w: set_wreg_no_log(srcdst, MemoryRead<uint32_t>(address)); break; |
1683 case LDR_x: set_xreg_no_log(srcdst, MemoryRead<uint64_t>(address)); break; | 1952 case LDR_x: set_xreg_no_log(srcdst, MemoryRead<uint64_t>(address)); break; |
1684 case LDRSB_w: set_wreg_no_log(srcdst, MemoryRead<int8_t>(address)); break; | 1953 case LDRSB_w: set_wreg_no_log(srcdst, MemoryRead<int8_t>(address)); break; |
1685 case LDRSH_w: set_wreg_no_log(srcdst, MemoryRead<int16_t>(address)); break; | 1954 case LDRSH_w: set_wreg_no_log(srcdst, MemoryRead<int16_t>(address)); break; |
1686 case LDRSB_x: set_xreg_no_log(srcdst, MemoryRead<int8_t>(address)); break; | 1955 case LDRSB_x: set_xreg_no_log(srcdst, MemoryRead<int8_t>(address)); break; |
1687 case LDRSH_x: set_xreg_no_log(srcdst, MemoryRead<int16_t>(address)); break; | 1956 case LDRSH_x: set_xreg_no_log(srcdst, MemoryRead<int16_t>(address)); break; |
1688 case LDRSW_x: set_xreg_no_log(srcdst, MemoryRead<int32_t>(address)); break; | 1957 case LDRSW_x: set_xreg_no_log(srcdst, MemoryRead<int32_t>(address)); break; |
| 1958 case LDR_b: |
| 1959 set_breg_no_log(srcdst, MemoryRead<uint8_t>(address)); |
| 1960 break; |
| 1961 case LDR_h: |
| 1962 set_hreg_no_log(srcdst, MemoryRead<uint16_t>(address)); |
| 1963 break; |
1689 case LDR_s: set_sreg_no_log(srcdst, MemoryRead<float>(address)); break; | 1964 case LDR_s: set_sreg_no_log(srcdst, MemoryRead<float>(address)); break; |
1690 case LDR_d: set_dreg_no_log(srcdst, MemoryRead<double>(address)); break; | 1965 case LDR_d: set_dreg_no_log(srcdst, MemoryRead<double>(address)); break; |
| 1966 case LDR_q: |
| 1967 set_qreg_no_log(srcdst, MemoryRead<qreg_t>(address)); |
| 1968 break; |
1691 | 1969 |
1692 case STRB_w: MemoryWrite<uint8_t>(address, wreg(srcdst)); break; | 1970 case STRB_w: MemoryWrite<uint8_t>(address, wreg(srcdst)); break; |
1693 case STRH_w: MemoryWrite<uint16_t>(address, wreg(srcdst)); break; | 1971 case STRH_w: MemoryWrite<uint16_t>(address, wreg(srcdst)); break; |
1694 case STR_w: MemoryWrite<uint32_t>(address, wreg(srcdst)); break; | 1972 case STR_w: MemoryWrite<uint32_t>(address, wreg(srcdst)); break; |
1695 case STR_x: MemoryWrite<uint64_t>(address, xreg(srcdst)); break; | 1973 case STR_x: MemoryWrite<uint64_t>(address, xreg(srcdst)); break; |
| 1974 case STR_b: |
| 1975 MemoryWrite<uint8_t>(address, breg(srcdst)); |
| 1976 break; |
| 1977 case STR_h: |
| 1978 MemoryWrite<uint16_t>(address, hreg(srcdst)); |
| 1979 break; |
1696 case STR_s: MemoryWrite<float>(address, sreg(srcdst)); break; | 1980 case STR_s: MemoryWrite<float>(address, sreg(srcdst)); break; |
1697 case STR_d: MemoryWrite<double>(address, dreg(srcdst)); break; | 1981 case STR_d: MemoryWrite<double>(address, dreg(srcdst)); break; |
| 1982 case STR_q: |
| 1983 MemoryWrite<qreg_t>(address, qreg(srcdst)); |
| 1984 break; |
1698 | 1985 |
1699 default: UNIMPLEMENTED(); | 1986 default: UNIMPLEMENTED(); |
1700 } | 1987 } |
1701 | 1988 |
1702 // Print a detailed trace (including the memory address) instead of the basic | 1989 // Print a detailed trace (including the memory address) instead of the basic |
1703 // register:value trace generated by set_*reg(). | 1990 // register:value trace generated by set_*reg(). |
1704 size_t access_size = 1 << instr->SizeLS(); | 1991 unsigned access_size = 1 << instr->SizeLS(); |
1705 if (instr->IsLoad()) { | 1992 if (instr->IsLoad()) { |
1706 if ((op == LDR_s) || (op == LDR_d)) { | 1993 if ((op == LDR_s) || (op == LDR_d)) { |
1707 LogReadFP(address, access_size, srcdst); | 1994 LogVRead(address, srcdst, GetPrintRegisterFormatForSizeFP(access_size)); |
| 1995 } else if ((op == LDR_b) || (op == LDR_h) || (op == LDR_q)) { |
| 1996 LogVRead(address, srcdst, GetPrintRegisterFormatForSize(access_size)); |
1708 } else { | 1997 } else { |
1709 LogRead(address, access_size, srcdst); | 1998 LogRead(address, srcdst, GetPrintRegisterFormatForSize(access_size)); |
1710 } | 1999 } |
1711 } else { | 2000 } else { |
1712 if ((op == STR_s) || (op == STR_d)) { | 2001 if ((op == STR_s) || (op == STR_d)) { |
1713 LogWriteFP(address, access_size, srcdst); | 2002 LogVWrite(address, srcdst, GetPrintRegisterFormatForSizeFP(access_size)); |
| 2003 } else if ((op == STR_b) || (op == STR_h) || (op == STR_q)) { |
| 2004 LogVWrite(address, srcdst, GetPrintRegisterFormatForSize(access_size)); |
1714 } else { | 2005 } else { |
1715 LogWrite(address, access_size, srcdst); | 2006 LogWrite(address, srcdst, GetPrintRegisterFormatForSize(access_size)); |
1716 } | 2007 } |
1717 } | 2008 } |
1718 | 2009 |
1719 // Handle the writeback for loads after the load to ensure safe pop | 2010 // Handle the writeback for loads after the load to ensure safe pop |
1720 // operation even when interrupted in the middle of it. The stack pointer | 2011 // operation even when interrupted in the middle of it. The stack pointer |
1721 // is only updated after the load so pop(fp) will never break the invariant | 2012 // is only updated after the load so pop(fp) will never break the invariant |
1722 // sp <= fp expected while walking the stack in the sampler. | 2013 // sp <= fp expected while walking the stack in the sampler. |
1723 if (instr->IsLoad()) { | 2014 if (instr->IsLoad()) { |
1724 // For loads the address pre writeback is used to check access below the | 2015 // For loads the address pre writeback is used to check access below the |
1725 // stack. | 2016 // stack. |
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1789 } | 2080 } |
1790 | 2081 |
1791 LoadStorePairOp op = | 2082 LoadStorePairOp op = |
1792 static_cast<LoadStorePairOp>(instr->Mask(LoadStorePairMask)); | 2083 static_cast<LoadStorePairOp>(instr->Mask(LoadStorePairMask)); |
1793 | 2084 |
1794 // 'rt' and 'rt2' can only be aliased for stores. | 2085 // 'rt' and 'rt2' can only be aliased for stores. |
1795 DCHECK(((op & LoadStorePairLBit) == 0) || (rt != rt2)); | 2086 DCHECK(((op & LoadStorePairLBit) == 0) || (rt != rt2)); |
1796 | 2087 |
1797 switch (op) { | 2088 switch (op) { |
1798 // Use _no_log variants to suppress the register trace (LOG_REGS, | 2089 // Use _no_log variants to suppress the register trace (LOG_REGS, |
1799 // LOG_FP_REGS). We will print a more detailed log. | 2090 // LOG_VREGS). We will print a more detailed log. |
1800 case LDP_w: { | 2091 case LDP_w: { |
1801 DCHECK(access_size == kWRegSize); | 2092 DCHECK_EQ(access_size, static_cast<unsigned>(kWRegSize)); |
1802 set_wreg_no_log(rt, MemoryRead<uint32_t>(address)); | 2093 set_wreg_no_log(rt, MemoryRead<uint32_t>(address)); |
1803 set_wreg_no_log(rt2, MemoryRead<uint32_t>(address2)); | 2094 set_wreg_no_log(rt2, MemoryRead<uint32_t>(address2)); |
1804 break; | 2095 break; |
1805 } | 2096 } |
1806 case LDP_s: { | 2097 case LDP_s: { |
1807 DCHECK(access_size == kSRegSize); | 2098 DCHECK_EQ(access_size, static_cast<unsigned>(kSRegSize)); |
1808 set_sreg_no_log(rt, MemoryRead<float>(address)); | 2099 set_sreg_no_log(rt, MemoryRead<float>(address)); |
1809 set_sreg_no_log(rt2, MemoryRead<float>(address2)); | 2100 set_sreg_no_log(rt2, MemoryRead<float>(address2)); |
1810 break; | 2101 break; |
1811 } | 2102 } |
1812 case LDP_x: { | 2103 case LDP_x: { |
1813 DCHECK(access_size == kXRegSize); | 2104 DCHECK_EQ(access_size, static_cast<unsigned>(kXRegSize)); |
1814 set_xreg_no_log(rt, MemoryRead<uint64_t>(address)); | 2105 set_xreg_no_log(rt, MemoryRead<uint64_t>(address)); |
1815 set_xreg_no_log(rt2, MemoryRead<uint64_t>(address2)); | 2106 set_xreg_no_log(rt2, MemoryRead<uint64_t>(address2)); |
1816 break; | 2107 break; |
1817 } | 2108 } |
1818 case LDP_d: { | 2109 case LDP_d: { |
1819 DCHECK(access_size == kDRegSize); | 2110 DCHECK_EQ(access_size, static_cast<unsigned>(kDRegSize)); |
1820 set_dreg_no_log(rt, MemoryRead<double>(address)); | 2111 set_dreg_no_log(rt, MemoryRead<double>(address)); |
1821 set_dreg_no_log(rt2, MemoryRead<double>(address2)); | 2112 set_dreg_no_log(rt2, MemoryRead<double>(address2)); |
1822 break; | 2113 break; |
1823 } | 2114 } |
| 2115 case LDP_q: { |
| 2116 DCHECK_EQ(access_size, static_cast<unsigned>(kQRegSize)); |
| 2117 set_qreg(rt, MemoryRead<qreg_t>(address), NoRegLog); |
| 2118 set_qreg(rt2, MemoryRead<qreg_t>(address2), NoRegLog); |
| 2119 break; |
| 2120 } |
1824 case LDPSW_x: { | 2121 case LDPSW_x: { |
1825 DCHECK(access_size == kWRegSize); | 2122 DCHECK_EQ(access_size, static_cast<unsigned>(kWRegSize)); |
1826 set_xreg_no_log(rt, MemoryRead<int32_t>(address)); | 2123 set_xreg_no_log(rt, MemoryRead<int32_t>(address)); |
1827 set_xreg_no_log(rt2, MemoryRead<int32_t>(address2)); | 2124 set_xreg_no_log(rt2, MemoryRead<int32_t>(address2)); |
1828 break; | 2125 break; |
1829 } | 2126 } |
1830 case STP_w: { | 2127 case STP_w: { |
1831 DCHECK(access_size == kWRegSize); | 2128 DCHECK_EQ(access_size, static_cast<unsigned>(kWRegSize)); |
1832 MemoryWrite<uint32_t>(address, wreg(rt)); | 2129 MemoryWrite<uint32_t>(address, wreg(rt)); |
1833 MemoryWrite<uint32_t>(address2, wreg(rt2)); | 2130 MemoryWrite<uint32_t>(address2, wreg(rt2)); |
1834 break; | 2131 break; |
1835 } | 2132 } |
1836 case STP_s: { | 2133 case STP_s: { |
1837 DCHECK(access_size == kSRegSize); | 2134 DCHECK_EQ(access_size, static_cast<unsigned>(kSRegSize)); |
1838 MemoryWrite<float>(address, sreg(rt)); | 2135 MemoryWrite<float>(address, sreg(rt)); |
1839 MemoryWrite<float>(address2, sreg(rt2)); | 2136 MemoryWrite<float>(address2, sreg(rt2)); |
1840 break; | 2137 break; |
1841 } | 2138 } |
1842 case STP_x: { | 2139 case STP_x: { |
1843 DCHECK(access_size == kXRegSize); | 2140 DCHECK_EQ(access_size, static_cast<unsigned>(kXRegSize)); |
1844 MemoryWrite<uint64_t>(address, xreg(rt)); | 2141 MemoryWrite<uint64_t>(address, xreg(rt)); |
1845 MemoryWrite<uint64_t>(address2, xreg(rt2)); | 2142 MemoryWrite<uint64_t>(address2, xreg(rt2)); |
1846 break; | 2143 break; |
1847 } | 2144 } |
1848 case STP_d: { | 2145 case STP_d: { |
1849 DCHECK(access_size == kDRegSize); | 2146 DCHECK_EQ(access_size, static_cast<unsigned>(kDRegSize)); |
1850 MemoryWrite<double>(address, dreg(rt)); | 2147 MemoryWrite<double>(address, dreg(rt)); |
1851 MemoryWrite<double>(address2, dreg(rt2)); | 2148 MemoryWrite<double>(address2, dreg(rt2)); |
1852 break; | 2149 break; |
1853 } | 2150 } |
| 2151 case STP_q: { |
| 2152 DCHECK_EQ(access_size, static_cast<unsigned>(kQRegSize)); |
| 2153 MemoryWrite<qreg_t>(address, qreg(rt)); |
| 2154 MemoryWrite<qreg_t>(address2, qreg(rt2)); |
| 2155 break; |
| 2156 } |
1854 default: UNREACHABLE(); | 2157 default: UNREACHABLE(); |
1855 } | 2158 } |
1856 | 2159 |
1857 // Print a detailed trace (including the memory address) instead of the basic | 2160 // Print a detailed trace (including the memory address) instead of the basic |
1858 // register:value trace generated by set_*reg(). | 2161 // register:value trace generated by set_*reg(). |
1859 if (instr->IsLoad()) { | 2162 if (instr->IsLoad()) { |
1860 if ((op == LDP_s) || (op == LDP_d)) { | 2163 if ((op == LDP_s) || (op == LDP_d)) { |
1861 LogReadFP(address, access_size, rt); | 2164 LogVRead(address, rt, GetPrintRegisterFormatForSizeFP(access_size)); |
1862 LogReadFP(address2, access_size, rt2); | 2165 LogVRead(address2, rt2, GetPrintRegisterFormatForSizeFP(access_size)); |
| 2166 } else if (op == LDP_q) { |
| 2167 LogVRead(address, rt, GetPrintRegisterFormatForSize(access_size)); |
| 2168 LogVRead(address2, rt2, GetPrintRegisterFormatForSize(access_size)); |
1863 } else { | 2169 } else { |
1864 LogRead(address, access_size, rt); | 2170 LogRead(address, rt, GetPrintRegisterFormatForSize(access_size)); |
1865 LogRead(address2, access_size, rt2); | 2171 LogRead(address2, rt2, GetPrintRegisterFormatForSize(access_size)); |
1866 } | 2172 } |
1867 } else { | 2173 } else { |
1868 if ((op == STP_s) || (op == STP_d)) { | 2174 if ((op == STP_s) || (op == STP_d)) { |
1869 LogWriteFP(address, access_size, rt); | 2175 LogVWrite(address, rt, GetPrintRegisterFormatForSizeFP(access_size)); |
1870 LogWriteFP(address2, access_size, rt2); | 2176 LogVWrite(address2, rt2, GetPrintRegisterFormatForSizeFP(access_size)); |
| 2177 } else if (op == STP_q) { |
| 2178 LogVWrite(address, rt, GetPrintRegisterFormatForSize(access_size)); |
| 2179 LogVWrite(address2, rt2, GetPrintRegisterFormatForSize(access_size)); |
1871 } else { | 2180 } else { |
1872 LogWrite(address, access_size, rt); | 2181 LogWrite(address, rt, GetPrintRegisterFormatForSize(access_size)); |
1873 LogWrite(address2, access_size, rt2); | 2182 LogWrite(address2, rt2, GetPrintRegisterFormatForSize(access_size)); |
1874 } | 2183 } |
1875 } | 2184 } |
1876 | 2185 |
1877 // Handle the writeback for loads after the load to ensure safe pop | 2186 // Handle the writeback for loads after the load to ensure safe pop |
1878 // operation even when interrupted in the middle of it. The stack pointer | 2187 // operation even when interrupted in the middle of it. The stack pointer |
1879 // is only updated after the load so pop(fp) will never break the invariant | 2188 // is only updated after the load so pop(fp) will never break the invariant |
1880 // sp <= fp expected while walking the stack in the sampler. | 2189 // sp <= fp expected while walking the stack in the sampler. |
1881 if (instr->IsLoad()) { | 2190 if (instr->IsLoad()) { |
1882 // For loads the address pre writeback is used to check access below the | 2191 // For loads the address pre writeback is used to check access below the |
1883 // stack. | 2192 // stack. |
(...skipping 10 matching lines...) Expand all Loading... |
1894 | 2203 |
1895 void Simulator::VisitLoadLiteral(Instruction* instr) { | 2204 void Simulator::VisitLoadLiteral(Instruction* instr) { |
1896 uintptr_t address = instr->LiteralAddress(); | 2205 uintptr_t address = instr->LiteralAddress(); |
1897 unsigned rt = instr->Rt(); | 2206 unsigned rt = instr->Rt(); |
1898 | 2207 |
1899 base::LockGuard<base::Mutex> lock_guard(&global_monitor_.Pointer()->mutex); | 2208 base::LockGuard<base::Mutex> lock_guard(&global_monitor_.Pointer()->mutex); |
1900 local_monitor_.NotifyLoad(address); | 2209 local_monitor_.NotifyLoad(address); |
1901 | 2210 |
1902 switch (instr->Mask(LoadLiteralMask)) { | 2211 switch (instr->Mask(LoadLiteralMask)) { |
1903 // Use _no_log variants to suppress the register trace (LOG_REGS, | 2212 // Use _no_log variants to suppress the register trace (LOG_REGS, |
1904 // LOG_FP_REGS), then print a more detailed log. | 2213 // LOG_VREGS), then print a more detailed log. |
1905 case LDR_w_lit: | 2214 case LDR_w_lit: |
1906 set_wreg_no_log(rt, MemoryRead<uint32_t>(address)); | 2215 set_wreg_no_log(rt, MemoryRead<uint32_t>(address)); |
1907 LogRead(address, kWRegSize, rt); | 2216 LogRead(address, rt, kPrintWReg); |
1908 break; | 2217 break; |
1909 case LDR_x_lit: | 2218 case LDR_x_lit: |
1910 set_xreg_no_log(rt, MemoryRead<uint64_t>(address)); | 2219 set_xreg_no_log(rt, MemoryRead<uint64_t>(address)); |
1911 LogRead(address, kXRegSize, rt); | 2220 LogRead(address, rt, kPrintXReg); |
1912 break; | 2221 break; |
1913 case LDR_s_lit: | 2222 case LDR_s_lit: |
1914 set_sreg_no_log(rt, MemoryRead<float>(address)); | 2223 set_sreg_no_log(rt, MemoryRead<float>(address)); |
1915 LogReadFP(address, kSRegSize, rt); | 2224 LogVRead(address, rt, kPrintSReg); |
1916 break; | 2225 break; |
1917 case LDR_d_lit: | 2226 case LDR_d_lit: |
1918 set_dreg_no_log(rt, MemoryRead<double>(address)); | 2227 set_dreg_no_log(rt, MemoryRead<double>(address)); |
1919 LogReadFP(address, kDRegSize, rt); | 2228 LogVRead(address, rt, kPrintDReg); |
1920 break; | 2229 break; |
1921 default: UNREACHABLE(); | 2230 default: UNREACHABLE(); |
1922 } | 2231 } |
1923 } | 2232 } |
1924 | 2233 |
1925 | 2234 |
1926 uintptr_t Simulator::LoadStoreAddress(unsigned addr_reg, int64_t offset, | 2235 uintptr_t Simulator::LoadStoreAddress(unsigned addr_reg, int64_t offset, |
1927 AddrMode addrmode) { | 2236 AddrMode addrmode) { |
1928 const unsigned kSPRegCode = kSPRegInternalCode & kRegCodeMask; | 2237 const unsigned kSPRegCode = kSPRegInternalCode & kRegCodeMask; |
1929 uint64_t address = xreg(addr_reg, Reg31IsStackPointer); | 2238 uint64_t address = xreg(addr_reg, Reg31IsStackPointer); |
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2002 case LDAXR_h: | 2311 case LDAXR_h: |
2003 set_wreg_no_log(rt, MemoryRead<uint16_t>(address)); | 2312 set_wreg_no_log(rt, MemoryRead<uint16_t>(address)); |
2004 break; | 2313 break; |
2005 case LDAR_w: | 2314 case LDAR_w: |
2006 case LDAXR_w: | 2315 case LDAXR_w: |
2007 set_wreg_no_log(rt, MemoryRead<uint32_t>(address)); | 2316 set_wreg_no_log(rt, MemoryRead<uint32_t>(address)); |
2008 break; | 2317 break; |
2009 default: | 2318 default: |
2010 UNIMPLEMENTED(); | 2319 UNIMPLEMENTED(); |
2011 } | 2320 } |
2012 LogRead(address, access_size, rt); | 2321 LogRead(address, rt, GetPrintRegisterFormatForSize(access_size)); |
2013 } else { | 2322 } else { |
2014 if (is_exclusive) { | 2323 if (is_exclusive) { |
2015 unsigned rs = instr->Rs(); | 2324 unsigned rs = instr->Rs(); |
2016 if (local_monitor_.NotifyStoreExcl(address, | 2325 if (local_monitor_.NotifyStoreExcl(address, |
2017 get_transaction_size(access_size)) && | 2326 get_transaction_size(access_size)) && |
2018 global_monitor_.Pointer()->NotifyStoreExcl_Locked( | 2327 global_monitor_.Pointer()->NotifyStoreExcl_Locked( |
2019 address, &global_monitor_processor_)) { | 2328 address, &global_monitor_processor_)) { |
2020 switch (op) { | 2329 switch (op) { |
2021 case STLXR_b: | 2330 case STLXR_b: |
2022 MemoryWrite<uint8_t>(address, wreg(rt)); | 2331 MemoryWrite<uint8_t>(address, wreg(rt)); |
2023 break; | 2332 break; |
2024 case STLXR_h: | 2333 case STLXR_h: |
2025 MemoryWrite<uint16_t>(address, wreg(rt)); | 2334 MemoryWrite<uint16_t>(address, wreg(rt)); |
2026 break; | 2335 break; |
2027 case STLXR_w: | 2336 case STLXR_w: |
2028 MemoryWrite<uint32_t>(address, wreg(rt)); | 2337 MemoryWrite<uint32_t>(address, wreg(rt)); |
2029 break; | 2338 break; |
2030 default: | 2339 default: |
2031 UNIMPLEMENTED(); | 2340 UNIMPLEMENTED(); |
2032 } | 2341 } |
2033 LogWrite(address, access_size, rt); | 2342 LogWrite(address, rt, GetPrintRegisterFormatForSize(access_size)); |
2034 set_wreg(rs, 0); | 2343 set_wreg(rs, 0); |
2035 } else { | 2344 } else { |
2036 set_wreg(rs, 1); | 2345 set_wreg(rs, 1); |
2037 } | 2346 } |
2038 } else { | 2347 } else { |
2039 local_monitor_.NotifyStore(address); | 2348 local_monitor_.NotifyStore(address); |
2040 global_monitor_.Pointer()->NotifyStore_Locked(address, | 2349 global_monitor_.Pointer()->NotifyStore_Locked(address, |
2041 &global_monitor_processor_); | 2350 &global_monitor_processor_); |
2042 switch (op) { | 2351 switch (op) { |
2043 case STLR_b: | 2352 case STLR_b: |
(...skipping 476 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2520 case UCVTF_sw_fixed: { | 2829 case UCVTF_sw_fixed: { |
2521 set_sreg(dst, | 2830 set_sreg(dst, |
2522 UFixedToFloat(reg<uint32_t>(src), fbits, round)); | 2831 UFixedToFloat(reg<uint32_t>(src), fbits, round)); |
2523 break; | 2832 break; |
2524 } | 2833 } |
2525 default: UNREACHABLE(); | 2834 default: UNREACHABLE(); |
2526 } | 2835 } |
2527 } | 2836 } |
2528 | 2837 |
2529 | 2838 |
2530 int32_t Simulator::FPToInt32(double value, FPRounding rmode) { | |
2531 value = FPRoundInt(value, rmode); | |
2532 if (value >= kWMaxInt) { | |
2533 return kWMaxInt; | |
2534 } else if (value < kWMinInt) { | |
2535 return kWMinInt; | |
2536 } | |
2537 return std::isnan(value) ? 0 : static_cast<int32_t>(value); | |
2538 } | |
2539 | |
2540 | |
2541 int64_t Simulator::FPToInt64(double value, FPRounding rmode) { | |
2542 value = FPRoundInt(value, rmode); | |
2543 if (value >= kXMaxInt) { | |
2544 return kXMaxInt; | |
2545 } else if (value < kXMinInt) { | |
2546 return kXMinInt; | |
2547 } | |
2548 return std::isnan(value) ? 0 : static_cast<int64_t>(value); | |
2549 } | |
2550 | |
2551 | |
2552 uint32_t Simulator::FPToUInt32(double value, FPRounding rmode) { | |
2553 value = FPRoundInt(value, rmode); | |
2554 if (value >= kWMaxUInt) { | |
2555 return kWMaxUInt; | |
2556 } else if (value < 0.0) { | |
2557 return 0; | |
2558 } | |
2559 return std::isnan(value) ? 0 : static_cast<uint32_t>(value); | |
2560 } | |
2561 | |
2562 | |
2563 uint64_t Simulator::FPToUInt64(double value, FPRounding rmode) { | |
2564 value = FPRoundInt(value, rmode); | |
2565 if (value >= kXMaxUInt) { | |
2566 return kXMaxUInt; | |
2567 } else if (value < 0.0) { | |
2568 return 0; | |
2569 } | |
2570 return std::isnan(value) ? 0 : static_cast<uint64_t>(value); | |
2571 } | |
2572 | |
2573 | |
2574 void Simulator::VisitFPCompare(Instruction* instr) { | 2839 void Simulator::VisitFPCompare(Instruction* instr) { |
2575 AssertSupportedFPCR(); | 2840 AssertSupportedFPCR(); |
2576 | 2841 |
2577 unsigned reg_size = (instr->Mask(FP64) == FP64) ? kDRegSizeInBits | |
2578 : kSRegSizeInBits; | |
2579 double fn_val = fpreg(reg_size, instr->Rn()); | |
2580 | |
2581 switch (instr->Mask(FPCompareMask)) { | 2842 switch (instr->Mask(FPCompareMask)) { |
2582 case FCMP_s: | 2843 case FCMP_s: |
2583 case FCMP_d: FPCompare(fn_val, fpreg(reg_size, instr->Rm())); break; | 2844 FPCompare(sreg(instr->Rn()), sreg(instr->Rm())); |
| 2845 break; |
| 2846 case FCMP_d: |
| 2847 FPCompare(dreg(instr->Rn()), dreg(instr->Rm())); |
| 2848 break; |
2584 case FCMP_s_zero: | 2849 case FCMP_s_zero: |
2585 case FCMP_d_zero: FPCompare(fn_val, 0.0); break; | 2850 FPCompare(sreg(instr->Rn()), 0.0f); |
| 2851 break; |
| 2852 case FCMP_d_zero: |
| 2853 FPCompare(dreg(instr->Rn()), 0.0); |
| 2854 break; |
2586 default: UNIMPLEMENTED(); | 2855 default: UNIMPLEMENTED(); |
2587 } | 2856 } |
2588 } | 2857 } |
2589 | 2858 |
2590 | 2859 |
2591 void Simulator::VisitFPConditionalCompare(Instruction* instr) { | 2860 void Simulator::VisitFPConditionalCompare(Instruction* instr) { |
2592 AssertSupportedFPCR(); | 2861 AssertSupportedFPCR(); |
2593 | 2862 |
2594 switch (instr->Mask(FPConditionalCompareMask)) { | 2863 switch (instr->Mask(FPConditionalCompareMask)) { |
2595 case FCCMP_s: | 2864 case FCCMP_s: |
| 2865 if (ConditionPassed(static_cast<Condition>(instr->Condition()))) { |
| 2866 FPCompare(sreg(instr->Rn()), sreg(instr->Rm())); |
| 2867 } else { |
| 2868 nzcv().SetFlags(instr->Nzcv()); |
| 2869 LogSystemRegister(NZCV); |
| 2870 } |
| 2871 break; |
2596 case FCCMP_d: { | 2872 case FCCMP_d: { |
2597 if (ConditionPassed(static_cast<Condition>(instr->Condition()))) { | 2873 if (ConditionPassed(static_cast<Condition>(instr->Condition()))) { |
2598 // If the condition passes, set the status flags to the result of | 2874 FPCompare(dreg(instr->Rn()), dreg(instr->Rm())); |
2599 // comparing the operands. | |
2600 unsigned reg_size = (instr->Mask(FP64) == FP64) ? kDRegSizeInBits | |
2601 : kSRegSizeInBits; | |
2602 FPCompare(fpreg(reg_size, instr->Rn()), fpreg(reg_size, instr->Rm())); | |
2603 } else { | 2875 } else { |
2604 // If the condition fails, set the status flags to the nzcv immediate. | 2876 // If the condition fails, set the status flags to the nzcv immediate. |
2605 nzcv().SetFlags(instr->Nzcv()); | 2877 nzcv().SetFlags(instr->Nzcv()); |
2606 LogSystemRegister(NZCV); | 2878 LogSystemRegister(NZCV); |
2607 } | 2879 } |
2608 break; | 2880 break; |
2609 } | 2881 } |
2610 default: UNIMPLEMENTED(); | 2882 default: UNIMPLEMENTED(); |
2611 } | 2883 } |
2612 } | 2884 } |
(...skipping 13 matching lines...) Expand all Loading... |
2626 case FCSEL_s: set_sreg(instr->Rd(), sreg(selected)); break; | 2898 case FCSEL_s: set_sreg(instr->Rd(), sreg(selected)); break; |
2627 case FCSEL_d: set_dreg(instr->Rd(), dreg(selected)); break; | 2899 case FCSEL_d: set_dreg(instr->Rd(), dreg(selected)); break; |
2628 default: UNIMPLEMENTED(); | 2900 default: UNIMPLEMENTED(); |
2629 } | 2901 } |
2630 } | 2902 } |
2631 | 2903 |
2632 | 2904 |
2633 void Simulator::VisitFPDataProcessing1Source(Instruction* instr) { | 2905 void Simulator::VisitFPDataProcessing1Source(Instruction* instr) { |
2634 AssertSupportedFPCR(); | 2906 AssertSupportedFPCR(); |
2635 | 2907 |
| 2908 FPRounding fpcr_rounding = static_cast<FPRounding>(fpcr().RMode()); |
| 2909 VectorFormat vform = (instr->Mask(FP64) == FP64) ? kFormatD : kFormatS; |
| 2910 SimVRegister& rd = vreg(instr->Rd()); |
| 2911 SimVRegister& rn = vreg(instr->Rn()); |
| 2912 bool inexact_exception = false; |
| 2913 |
2636 unsigned fd = instr->Rd(); | 2914 unsigned fd = instr->Rd(); |
2637 unsigned fn = instr->Rn(); | 2915 unsigned fn = instr->Rn(); |
2638 | 2916 |
2639 switch (instr->Mask(FPDataProcessing1SourceMask)) { | 2917 switch (instr->Mask(FPDataProcessing1SourceMask)) { |
2640 case FMOV_s: set_sreg(fd, sreg(fn)); break; | 2918 case FMOV_s: |
2641 case FMOV_d: set_dreg(fd, dreg(fn)); break; | 2919 set_sreg(fd, sreg(fn)); |
2642 case FABS_s: set_sreg(fd, std::fabs(sreg(fn))); break; | 2920 return; |
2643 case FABS_d: set_dreg(fd, std::fabs(dreg(fn))); break; | 2921 case FMOV_d: |
2644 case FNEG_s: set_sreg(fd, -sreg(fn)); break; | 2922 set_dreg(fd, dreg(fn)); |
2645 case FNEG_d: set_dreg(fd, -dreg(fn)); break; | 2923 return; |
2646 case FSQRT_s: set_sreg(fd, FPSqrt(sreg(fn))); break; | 2924 case FABS_s: |
2647 case FSQRT_d: set_dreg(fd, FPSqrt(dreg(fn))); break; | 2925 case FABS_d: |
2648 case FRINTA_s: set_sreg(fd, FPRoundInt(sreg(fn), FPTieAway)); break; | 2926 fabs_(vform, vreg(fd), vreg(fn)); |
2649 case FRINTA_d: set_dreg(fd, FPRoundInt(dreg(fn), FPTieAway)); break; | 2927 // Explicitly log the register update whilst we have type information. |
| 2928 LogVRegister(fd, GetPrintRegisterFormatFP(vform)); |
| 2929 return; |
| 2930 case FNEG_s: |
| 2931 case FNEG_d: |
| 2932 fneg(vform, vreg(fd), vreg(fn)); |
| 2933 // Explicitly log the register update whilst we have type information. |
| 2934 LogVRegister(fd, GetPrintRegisterFormatFP(vform)); |
| 2935 return; |
| 2936 case FCVT_ds: |
| 2937 set_dreg(fd, FPToDouble(sreg(fn))); |
| 2938 return; |
| 2939 case FCVT_sd: |
| 2940 set_sreg(fd, FPToFloat(dreg(fn), FPTieEven)); |
| 2941 return; |
| 2942 case FCVT_hs: |
| 2943 set_hreg(fd, FPToFloat16(sreg(fn), FPTieEven)); |
| 2944 return; |
| 2945 case FCVT_sh: |
| 2946 set_sreg(fd, FPToFloat(hreg(fn))); |
| 2947 return; |
| 2948 case FCVT_dh: |
| 2949 set_dreg(fd, FPToDouble(FPToFloat(hreg(fn)))); |
| 2950 return; |
| 2951 case FCVT_hd: |
| 2952 set_hreg(fd, FPToFloat16(dreg(fn), FPTieEven)); |
| 2953 return; |
| 2954 case FSQRT_s: |
| 2955 case FSQRT_d: |
| 2956 fsqrt(vform, rd, rn); |
| 2957 // Explicitly log the register update whilst we have type information. |
| 2958 LogVRegister(fd, GetPrintRegisterFormatFP(vform)); |
| 2959 return; |
| 2960 case FRINTI_s: |
| 2961 case FRINTI_d: |
| 2962 break; // Use FPCR rounding mode. |
| 2963 case FRINTX_s: |
| 2964 case FRINTX_d: |
| 2965 inexact_exception = true; |
| 2966 break; |
| 2967 case FRINTA_s: |
| 2968 case FRINTA_d: |
| 2969 fpcr_rounding = FPTieAway; |
| 2970 break; |
2650 case FRINTM_s: | 2971 case FRINTM_s: |
2651 set_sreg(fd, FPRoundInt(sreg(fn), FPNegativeInfinity)); break; | |
2652 case FRINTM_d: | 2972 case FRINTM_d: |
2653 set_dreg(fd, FPRoundInt(dreg(fn), FPNegativeInfinity)); break; | 2973 fpcr_rounding = FPNegativeInfinity; |
| 2974 break; |
| 2975 case FRINTN_s: |
| 2976 case FRINTN_d: |
| 2977 fpcr_rounding = FPTieEven; |
| 2978 break; |
2654 case FRINTP_s: | 2979 case FRINTP_s: |
2655 set_sreg(fd, FPRoundInt(sreg(fn), FPPositiveInfinity)); | 2980 case FRINTP_d: |
| 2981 fpcr_rounding = FPPositiveInfinity; |
2656 break; | 2982 break; |
2657 case FRINTP_d: | 2983 case FRINTZ_s: |
2658 set_dreg(fd, FPRoundInt(dreg(fn), FPPositiveInfinity)); | 2984 case FRINTZ_d: |
| 2985 fpcr_rounding = FPZero; |
2659 break; | 2986 break; |
2660 case FRINTN_s: set_sreg(fd, FPRoundInt(sreg(fn), FPTieEven)); break; | 2987 default: |
2661 case FRINTN_d: set_dreg(fd, FPRoundInt(dreg(fn), FPTieEven)); break; | 2988 UNIMPLEMENTED(); |
2662 case FRINTZ_s: set_sreg(fd, FPRoundInt(sreg(fn), FPZero)); break; | |
2663 case FRINTZ_d: set_dreg(fd, FPRoundInt(dreg(fn), FPZero)); break; | |
2664 case FCVT_ds: set_dreg(fd, FPToDouble(sreg(fn))); break; | |
2665 case FCVT_sd: set_sreg(fd, FPToFloat(dreg(fn), FPTieEven)); break; | |
2666 default: UNIMPLEMENTED(); | |
2667 } | |
2668 } | |
2669 | |
2670 | |
2671 // Assemble the specified IEEE-754 components into the target type and apply | |
2672 // appropriate rounding. | |
2673 // sign: 0 = positive, 1 = negative | |
2674 // exponent: Unbiased IEEE-754 exponent. | |
2675 // mantissa: The mantissa of the input. The top bit (which is not encoded for | |
2676 // normal IEEE-754 values) must not be omitted. This bit has the | |
2677 // value 'pow(2, exponent)'. | |
2678 // | |
2679 // The input value is assumed to be a normalized value. That is, the input may | |
2680 // not be infinity or NaN. If the source value is subnormal, it must be | |
2681 // normalized before calling this function such that the highest set bit in the | |
2682 // mantissa has the value 'pow(2, exponent)'. | |
2683 // | |
2684 // Callers should use FPRoundToFloat or FPRoundToDouble directly, rather than | |
2685 // calling a templated FPRound. | |
2686 template <class T, int ebits, int mbits> | |
2687 static T FPRound(int64_t sign, int64_t exponent, uint64_t mantissa, | |
2688 FPRounding round_mode) { | |
2689 DCHECK((sign == 0) || (sign == 1)); | |
2690 | |
2691 // Only the FPTieEven rounding mode is implemented. | |
2692 DCHECK(round_mode == FPTieEven); | |
2693 USE(round_mode); | |
2694 | |
2695 // Rounding can promote subnormals to normals, and normals to infinities. For | |
2696 // example, a double with exponent 127 (FLT_MAX_EXP) would appear to be | |
2697 // encodable as a float, but rounding based on the low-order mantissa bits | |
2698 // could make it overflow. With ties-to-even rounding, this value would become | |
2699 // an infinity. | |
2700 | |
2701 // ---- Rounding Method ---- | |
2702 // | |
2703 // The exponent is irrelevant in the rounding operation, so we treat the | |
2704 // lowest-order bit that will fit into the result ('onebit') as having | |
2705 // the value '1'. Similarly, the highest-order bit that won't fit into | |
2706 // the result ('halfbit') has the value '0.5'. The 'point' sits between | |
2707 // 'onebit' and 'halfbit': | |
2708 // | |
2709 // These bits fit into the result. | |
2710 // |---------------------| | |
2711 // mantissa = 0bxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx | |
2712 // || | |
2713 // / | | |
2714 // / halfbit | |
2715 // onebit | |
2716 // | |
2717 // For subnormal outputs, the range of representable bits is smaller and | |
2718 // the position of onebit and halfbit depends on the exponent of the | |
2719 // input, but the method is otherwise similar. | |
2720 // | |
2721 // onebit(frac) | |
2722 // | | |
2723 // | halfbit(frac) halfbit(adjusted) | |
2724 // | / / | |
2725 // | | | | |
2726 // 0b00.0 (exact) -> 0b00.0 (exact) -> 0b00 | |
2727 // 0b00.0... -> 0b00.0... -> 0b00 | |
2728 // 0b00.1 (exact) -> 0b00.0111..111 -> 0b00 | |
2729 // 0b00.1... -> 0b00.1... -> 0b01 | |
2730 // 0b01.0 (exact) -> 0b01.0 (exact) -> 0b01 | |
2731 // 0b01.0... -> 0b01.0... -> 0b01 | |
2732 // 0b01.1 (exact) -> 0b01.1 (exact) -> 0b10 | |
2733 // 0b01.1... -> 0b01.1... -> 0b10 | |
2734 // 0b10.0 (exact) -> 0b10.0 (exact) -> 0b10 | |
2735 // 0b10.0... -> 0b10.0... -> 0b10 | |
2736 // 0b10.1 (exact) -> 0b10.0111..111 -> 0b10 | |
2737 // 0b10.1... -> 0b10.1... -> 0b11 | |
2738 // 0b11.0 (exact) -> 0b11.0 (exact) -> 0b11 | |
2739 // ... / | / | | |
2740 // / | / | | |
2741 // / | | |
2742 // adjusted = frac - (halfbit(mantissa) & ~onebit(frac)); / | | |
2743 // | |
2744 // mantissa = (mantissa >> shift) + halfbit(adjusted); | |
2745 | |
2746 static const int mantissa_offset = 0; | |
2747 static const int exponent_offset = mantissa_offset + mbits; | |
2748 static const int sign_offset = exponent_offset + ebits; | |
2749 STATIC_ASSERT(sign_offset == (sizeof(T) * kByteSize - 1)); | |
2750 | |
2751 // Bail out early for zero inputs. | |
2752 if (mantissa == 0) { | |
2753 return static_cast<T>(sign << sign_offset); | |
2754 } | 2989 } |
2755 | 2990 |
2756 // If all bits in the exponent are set, the value is infinite or NaN. | 2991 // Only FRINT* instructions fall through the switch above. |
2757 // This is true for all binary IEEE-754 formats. | 2992 frint(vform, rd, rn, fpcr_rounding, inexact_exception); |
2758 static const int infinite_exponent = (1 << ebits) - 1; | 2993 // Explicitly log the register update whilst we have type information |
2759 static const int max_normal_exponent = infinite_exponent - 1; | 2994 LogVRegister(fd, GetPrintRegisterFormatFP(vform)); |
2760 | |
2761 // Apply the exponent bias to encode it for the result. Doing this early makes | |
2762 // it easy to detect values that will be infinite or subnormal. | |
2763 exponent += max_normal_exponent >> 1; | |
2764 | |
2765 if (exponent > max_normal_exponent) { | |
2766 // Overflow: The input is too large for the result type to represent. The | |
2767 // FPTieEven rounding mode handles overflows using infinities. | |
2768 exponent = infinite_exponent; | |
2769 mantissa = 0; | |
2770 return static_cast<T>((sign << sign_offset) | | |
2771 (exponent << exponent_offset) | | |
2772 (mantissa << mantissa_offset)); | |
2773 } | |
2774 | |
2775 // Calculate the shift required to move the top mantissa bit to the proper | |
2776 // place in the destination type. | |
2777 const int highest_significant_bit = 63 - CountLeadingZeros(mantissa, 64); | |
2778 int shift = highest_significant_bit - mbits; | |
2779 | |
2780 if (exponent <= 0) { | |
2781 // The output will be subnormal (before rounding). | |
2782 | |
2783 // For subnormal outputs, the shift must be adjusted by the exponent. The +1 | |
2784 // is necessary because the exponent of a subnormal value (encoded as 0) is | |
2785 // the same as the exponent of the smallest normal value (encoded as 1). | |
2786 shift += -exponent + 1; | |
2787 | |
2788 // Handle inputs that would produce a zero output. | |
2789 // | |
2790 // Shifts higher than highest_significant_bit+1 will always produce a zero | |
2791 // result. A shift of exactly highest_significant_bit+1 might produce a | |
2792 // non-zero result after rounding. | |
2793 if (shift > (highest_significant_bit + 1)) { | |
2794 // The result will always be +/-0.0. | |
2795 return static_cast<T>(sign << sign_offset); | |
2796 } | |
2797 | |
2798 // Properly encode the exponent for a subnormal output. | |
2799 exponent = 0; | |
2800 } else { | |
2801 // Clear the topmost mantissa bit, since this is not encoded in IEEE-754 | |
2802 // normal values. | |
2803 mantissa &= ~(1UL << highest_significant_bit); | |
2804 } | |
2805 | |
2806 if (shift > 0) { | |
2807 // We have to shift the mantissa to the right. Some precision is lost, so we | |
2808 // need to apply rounding. | |
2809 uint64_t onebit_mantissa = (mantissa >> (shift)) & 1; | |
2810 uint64_t halfbit_mantissa = (mantissa >> (shift-1)) & 1; | |
2811 uint64_t adjusted = mantissa - (halfbit_mantissa & ~onebit_mantissa); | |
2812 T halfbit_adjusted = (adjusted >> (shift-1)) & 1; | |
2813 | |
2814 T result = | |
2815 static_cast<T>((sign << sign_offset) | (exponent << exponent_offset) | | |
2816 ((mantissa >> shift) << mantissa_offset)); | |
2817 | |
2818 // A very large mantissa can overflow during rounding. If this happens, the | |
2819 // exponent should be incremented and the mantissa set to 1.0 (encoded as | |
2820 // 0). Applying halfbit_adjusted after assembling the float has the nice | |
2821 // side-effect that this case is handled for free. | |
2822 // | |
2823 // This also handles cases where a very large finite value overflows to | |
2824 // infinity, or where a very large subnormal value overflows to become | |
2825 // normal. | |
2826 return result + halfbit_adjusted; | |
2827 } else { | |
2828 // We have to shift the mantissa to the left (or not at all). The input | |
2829 // mantissa is exactly representable in the output mantissa, so apply no | |
2830 // rounding correction. | |
2831 return static_cast<T>((sign << sign_offset) | | |
2832 (exponent << exponent_offset) | | |
2833 ((mantissa << -shift) << mantissa_offset)); | |
2834 } | |
2835 } | 2995 } |
2836 | 2996 |
2837 | |
2838 // See FPRound for a description of this function. | |
2839 static inline double FPRoundToDouble(int64_t sign, int64_t exponent, | |
2840 uint64_t mantissa, FPRounding round_mode) { | |
2841 int64_t bits = | |
2842 FPRound<int64_t, kDoubleExponentBits, kDoubleMantissaBits>(sign, | |
2843 exponent, | |
2844 mantissa, | |
2845 round_mode); | |
2846 return rawbits_to_double(bits); | |
2847 } | |
2848 | |
2849 | |
2850 // See FPRound for a description of this function. | |
2851 static inline float FPRoundToFloat(int64_t sign, int64_t exponent, | |
2852 uint64_t mantissa, FPRounding round_mode) { | |
2853 int32_t bits = | |
2854 FPRound<int32_t, kFloatExponentBits, kFloatMantissaBits>(sign, | |
2855 exponent, | |
2856 mantissa, | |
2857 round_mode); | |
2858 return rawbits_to_float(bits); | |
2859 } | |
2860 | |
2861 | |
2862 double Simulator::FixedToDouble(int64_t src, int fbits, FPRounding round) { | |
2863 if (src >= 0) { | |
2864 return UFixedToDouble(src, fbits, round); | |
2865 } else { | |
2866 // This works for all negative values, including INT64_MIN. | |
2867 return -UFixedToDouble(-src, fbits, round); | |
2868 } | |
2869 } | |
2870 | |
2871 | |
2872 double Simulator::UFixedToDouble(uint64_t src, int fbits, FPRounding round) { | |
2873 // An input of 0 is a special case because the result is effectively | |
2874 // subnormal: The exponent is encoded as 0 and there is no implicit 1 bit. | |
2875 if (src == 0) { | |
2876 return 0.0; | |
2877 } | |
2878 | |
2879 // Calculate the exponent. The highest significant bit will have the value | |
2880 // 2^exponent. | |
2881 const int highest_significant_bit = 63 - CountLeadingZeros(src, 64); | |
2882 const int64_t exponent = highest_significant_bit - fbits; | |
2883 | |
2884 return FPRoundToDouble(0, exponent, src, round); | |
2885 } | |
2886 | |
2887 | |
2888 float Simulator::FixedToFloat(int64_t src, int fbits, FPRounding round) { | |
2889 if (src >= 0) { | |
2890 return UFixedToFloat(src, fbits, round); | |
2891 } else { | |
2892 // This works for all negative values, including INT64_MIN. | |
2893 return -UFixedToFloat(-src, fbits, round); | |
2894 } | |
2895 } | |
2896 | |
2897 | |
2898 float Simulator::UFixedToFloat(uint64_t src, int fbits, FPRounding round) { | |
2899 // An input of 0 is a special case because the result is effectively | |
2900 // subnormal: The exponent is encoded as 0 and there is no implicit 1 bit. | |
2901 if (src == 0) { | |
2902 return 0.0f; | |
2903 } | |
2904 | |
2905 // Calculate the exponent. The highest significant bit will have the value | |
2906 // 2^exponent. | |
2907 const int highest_significant_bit = 63 - CountLeadingZeros(src, 64); | |
2908 const int32_t exponent = highest_significant_bit - fbits; | |
2909 | |
2910 return FPRoundToFloat(0, exponent, src, round); | |
2911 } | |
2912 | |
2913 | |
2914 double Simulator::FPRoundInt(double value, FPRounding round_mode) { | |
2915 if ((value == 0.0) || (value == kFP64PositiveInfinity) || | |
2916 (value == kFP64NegativeInfinity)) { | |
2917 return value; | |
2918 } else if (std::isnan(value)) { | |
2919 return FPProcessNaN(value); | |
2920 } | |
2921 | |
2922 double int_result = floor(value); | |
2923 double error = value - int_result; | |
2924 switch (round_mode) { | |
2925 case FPTieAway: { | |
2926 // Take care of correctly handling the range ]-0.5, -0.0], which must | |
2927 // yield -0.0. | |
2928 if ((-0.5 < value) && (value < 0.0)) { | |
2929 int_result = -0.0; | |
2930 | |
2931 } else if ((error > 0.5) || ((error == 0.5) && (int_result >= 0.0))) { | |
2932 // If the error is greater than 0.5, or is equal to 0.5 and the integer | |
2933 // result is positive, round up. | |
2934 int_result++; | |
2935 } | |
2936 break; | |
2937 } | |
2938 case FPTieEven: { | |
2939 // Take care of correctly handling the range [-0.5, -0.0], which must | |
2940 // yield -0.0. | |
2941 if ((-0.5 <= value) && (value < 0.0)) { | |
2942 int_result = -0.0; | |
2943 | |
2944 // If the error is greater than 0.5, or is equal to 0.5 and the integer | |
2945 // result is odd, round up. | |
2946 } else if ((error > 0.5) || | |
2947 ((error == 0.5) && (modulo(int_result, 2) != 0))) { | |
2948 int_result++; | |
2949 } | |
2950 break; | |
2951 } | |
2952 case FPZero: { | |
2953 // If value > 0 then we take floor(value) | |
2954 // otherwise, ceil(value) | |
2955 if (value < 0) { | |
2956 int_result = ceil(value); | |
2957 } | |
2958 break; | |
2959 } | |
2960 case FPNegativeInfinity: { | |
2961 // We always use floor(value). | |
2962 break; | |
2963 } | |
2964 case FPPositiveInfinity: { | |
2965 int_result = ceil(value); | |
2966 break; | |
2967 } | |
2968 default: UNIMPLEMENTED(); | |
2969 } | |
2970 return int_result; | |
2971 } | |
2972 | |
2973 | |
2974 double Simulator::FPToDouble(float value) { | |
2975 switch (std::fpclassify(value)) { | |
2976 case FP_NAN: { | |
2977 if (fpcr().DN()) return kFP64DefaultNaN; | |
2978 | |
2979 // Convert NaNs as the processor would: | |
2980 // - The sign is propagated. | |
2981 // - The payload (mantissa) is transferred entirely, except that the top | |
2982 // bit is forced to '1', making the result a quiet NaN. The unused | |
2983 // (low-order) payload bits are set to 0. | |
2984 uint32_t raw = float_to_rawbits(value); | |
2985 | |
2986 uint64_t sign = raw >> 31; | |
2987 uint64_t exponent = (1 << 11) - 1; | |
2988 uint64_t payload = unsigned_bitextract_64(21, 0, raw); | |
2989 payload <<= (52 - 23); // The unused low-order bits should be 0. | |
2990 payload |= (1L << 51); // Force a quiet NaN. | |
2991 | |
2992 return rawbits_to_double((sign << 63) | (exponent << 52) | payload); | |
2993 } | |
2994 | |
2995 case FP_ZERO: | |
2996 case FP_NORMAL: | |
2997 case FP_SUBNORMAL: | |
2998 case FP_INFINITE: { | |
2999 // All other inputs are preserved in a standard cast, because every value | |
3000 // representable using an IEEE-754 float is also representable using an | |
3001 // IEEE-754 double. | |
3002 return static_cast<double>(value); | |
3003 } | |
3004 } | |
3005 | |
3006 UNREACHABLE(); | |
3007 } | |
3008 | |
3009 | |
3010 float Simulator::FPToFloat(double value, FPRounding round_mode) { | |
3011 // Only the FPTieEven rounding mode is implemented. | |
3012 DCHECK(round_mode == FPTieEven); | |
3013 USE(round_mode); | |
3014 | |
3015 switch (std::fpclassify(value)) { | |
3016 case FP_NAN: { | |
3017 if (fpcr().DN()) return kFP32DefaultNaN; | |
3018 | |
3019 // Convert NaNs as the processor would: | |
3020 // - The sign is propagated. | |
3021 // - The payload (mantissa) is transferred as much as possible, except | |
3022 // that the top bit is forced to '1', making the result a quiet NaN. | |
3023 uint64_t raw = double_to_rawbits(value); | |
3024 | |
3025 uint32_t sign = raw >> 63; | |
3026 uint32_t exponent = (1 << 8) - 1; | |
3027 uint32_t payload = | |
3028 static_cast<uint32_t>(unsigned_bitextract_64(50, 52 - 23, raw)); | |
3029 payload |= (1 << 22); // Force a quiet NaN. | |
3030 | |
3031 return rawbits_to_float((sign << 31) | (exponent << 23) | payload); | |
3032 } | |
3033 | |
3034 case FP_ZERO: | |
3035 case FP_INFINITE: { | |
3036 // In a C++ cast, any value representable in the target type will be | |
3037 // unchanged. This is always the case for +/-0.0 and infinities. | |
3038 return static_cast<float>(value); | |
3039 } | |
3040 | |
3041 case FP_NORMAL: | |
3042 case FP_SUBNORMAL: { | |
3043 // Convert double-to-float as the processor would, assuming that FPCR.FZ | |
3044 // (flush-to-zero) is not set. | |
3045 uint64_t raw = double_to_rawbits(value); | |
3046 // Extract the IEEE-754 double components. | |
3047 uint32_t sign = raw >> 63; | |
3048 // Extract the exponent and remove the IEEE-754 encoding bias. | |
3049 int32_t exponent = | |
3050 static_cast<int32_t>(unsigned_bitextract_64(62, 52, raw)) - 1023; | |
3051 // Extract the mantissa and add the implicit '1' bit. | |
3052 uint64_t mantissa = unsigned_bitextract_64(51, 0, raw); | |
3053 if (std::fpclassify(value) == FP_NORMAL) { | |
3054 mantissa |= (1UL << 52); | |
3055 } | |
3056 return FPRoundToFloat(sign, exponent, mantissa, round_mode); | |
3057 } | |
3058 } | |
3059 | |
3060 UNREACHABLE(); | |
3061 } | |
3062 | |
3063 | |
3064 void Simulator::VisitFPDataProcessing2Source(Instruction* instr) { | 2997 void Simulator::VisitFPDataProcessing2Source(Instruction* instr) { |
3065 AssertSupportedFPCR(); | 2998 AssertSupportedFPCR(); |
3066 | 2999 |
3067 unsigned fd = instr->Rd(); | 3000 VectorFormat vform = (instr->Mask(FP64) == FP64) ? kFormatD : kFormatS; |
3068 unsigned fn = instr->Rn(); | 3001 SimVRegister& rd = vreg(instr->Rd()); |
3069 unsigned fm = instr->Rm(); | 3002 SimVRegister& rn = vreg(instr->Rn()); |
3070 | 3003 SimVRegister& rm = vreg(instr->Rm()); |
3071 // Fmaxnm and Fminnm have special NaN handling. | |
3072 switch (instr->Mask(FPDataProcessing2SourceMask)) { | |
3073 case FMAXNM_s: set_sreg(fd, FPMaxNM(sreg(fn), sreg(fm))); return; | |
3074 case FMAXNM_d: set_dreg(fd, FPMaxNM(dreg(fn), dreg(fm))); return; | |
3075 case FMINNM_s: set_sreg(fd, FPMinNM(sreg(fn), sreg(fm))); return; | |
3076 case FMINNM_d: set_dreg(fd, FPMinNM(dreg(fn), dreg(fm))); return; | |
3077 default: | |
3078 break; // Fall through. | |
3079 } | |
3080 | |
3081 if (FPProcessNaNs(instr)) return; | |
3082 | 3004 |
3083 switch (instr->Mask(FPDataProcessing2SourceMask)) { | 3005 switch (instr->Mask(FPDataProcessing2SourceMask)) { |
3084 case FADD_s: set_sreg(fd, FPAdd(sreg(fn), sreg(fm))); break; | 3006 case FADD_s: |
3085 case FADD_d: set_dreg(fd, FPAdd(dreg(fn), dreg(fm))); break; | 3007 case FADD_d: |
3086 case FSUB_s: set_sreg(fd, FPSub(sreg(fn), sreg(fm))); break; | 3008 fadd(vform, rd, rn, rm); |
3087 case FSUB_d: set_dreg(fd, FPSub(dreg(fn), dreg(fm))); break; | 3009 break; |
3088 case FMUL_s: set_sreg(fd, FPMul(sreg(fn), sreg(fm))); break; | 3010 case FSUB_s: |
3089 case FMUL_d: set_dreg(fd, FPMul(dreg(fn), dreg(fm))); break; | 3011 case FSUB_d: |
3090 case FDIV_s: set_sreg(fd, FPDiv(sreg(fn), sreg(fm))); break; | 3012 fsub(vform, rd, rn, rm); |
3091 case FDIV_d: set_dreg(fd, FPDiv(dreg(fn), dreg(fm))); break; | 3013 break; |
3092 case FMAX_s: set_sreg(fd, FPMax(sreg(fn), sreg(fm))); break; | 3014 case FMUL_s: |
3093 case FMAX_d: set_dreg(fd, FPMax(dreg(fn), dreg(fm))); break; | 3015 case FMUL_d: |
3094 case FMIN_s: set_sreg(fd, FPMin(sreg(fn), sreg(fm))); break; | 3016 fmul(vform, rd, rn, rm); |
3095 case FMIN_d: set_dreg(fd, FPMin(dreg(fn), dreg(fm))); break; | 3017 break; |
| 3018 case FNMUL_s: |
| 3019 case FNMUL_d: |
| 3020 fnmul(vform, rd, rn, rm); |
| 3021 break; |
| 3022 case FDIV_s: |
| 3023 case FDIV_d: |
| 3024 fdiv(vform, rd, rn, rm); |
| 3025 break; |
| 3026 case FMAX_s: |
| 3027 case FMAX_d: |
| 3028 fmax(vform, rd, rn, rm); |
| 3029 break; |
| 3030 case FMIN_s: |
| 3031 case FMIN_d: |
| 3032 fmin(vform, rd, rn, rm); |
| 3033 break; |
3096 case FMAXNM_s: | 3034 case FMAXNM_s: |
3097 case FMAXNM_d: | 3035 case FMAXNM_d: |
| 3036 fmaxnm(vform, rd, rn, rm); |
| 3037 break; |
3098 case FMINNM_s: | 3038 case FMINNM_s: |
3099 case FMINNM_d: | 3039 case FMINNM_d: |
3100 // These were handled before the standard FPProcessNaNs() stage. | 3040 fminnm(vform, rd, rn, rm); |
| 3041 break; |
| 3042 default: |
3101 UNREACHABLE(); | 3043 UNREACHABLE(); |
3102 default: UNIMPLEMENTED(); | |
3103 } | 3044 } |
| 3045 // Explicitly log the register update whilst we have type information. |
| 3046 LogVRegister(instr->Rd(), GetPrintRegisterFormatFP(vform)); |
3104 } | 3047 } |
3105 | 3048 |
3106 | |
3107 void Simulator::VisitFPDataProcessing3Source(Instruction* instr) { | 3049 void Simulator::VisitFPDataProcessing3Source(Instruction* instr) { |
3108 AssertSupportedFPCR(); | 3050 AssertSupportedFPCR(); |
3109 | 3051 |
3110 unsigned fd = instr->Rd(); | 3052 unsigned fd = instr->Rd(); |
3111 unsigned fn = instr->Rn(); | 3053 unsigned fn = instr->Rn(); |
3112 unsigned fm = instr->Rm(); | 3054 unsigned fm = instr->Rm(); |
3113 unsigned fa = instr->Ra(); | 3055 unsigned fa = instr->Ra(); |
3114 | 3056 |
3115 switch (instr->Mask(FPDataProcessing3SourceMask)) { | 3057 switch (instr->Mask(FPDataProcessing3SourceMask)) { |
3116 // fd = fa +/- (fn * fm) | 3058 // fd = fa +/- (fn * fm) |
3117 case FMADD_s: set_sreg(fd, FPMulAdd(sreg(fa), sreg(fn), sreg(fm))); break; | 3059 case FMADD_s: |
3118 case FMSUB_s: set_sreg(fd, FPMulAdd(sreg(fa), -sreg(fn), sreg(fm))); break; | 3060 set_sreg(fd, FPMulAdd(sreg(fa), sreg(fn), sreg(fm))); |
3119 case FMADD_d: set_dreg(fd, FPMulAdd(dreg(fa), dreg(fn), dreg(fm))); break; | 3061 break; |
3120 case FMSUB_d: set_dreg(fd, FPMulAdd(dreg(fa), -dreg(fn), dreg(fm))); break; | 3062 case FMSUB_s: |
| 3063 set_sreg(fd, FPMulAdd(sreg(fa), -sreg(fn), sreg(fm))); |
| 3064 break; |
| 3065 case FMADD_d: |
| 3066 set_dreg(fd, FPMulAdd(dreg(fa), dreg(fn), dreg(fm))); |
| 3067 break; |
| 3068 case FMSUB_d: |
| 3069 set_dreg(fd, FPMulAdd(dreg(fa), -dreg(fn), dreg(fm))); |
| 3070 break; |
3121 // Negated variants of the above. | 3071 // Negated variants of the above. |
3122 case FNMADD_s: | 3072 case FNMADD_s: |
3123 set_sreg(fd, FPMulAdd(-sreg(fa), -sreg(fn), sreg(fm))); | 3073 set_sreg(fd, FPMulAdd(-sreg(fa), -sreg(fn), sreg(fm))); |
3124 break; | 3074 break; |
3125 case FNMSUB_s: | 3075 case FNMSUB_s: |
3126 set_sreg(fd, FPMulAdd(-sreg(fa), sreg(fn), sreg(fm))); | 3076 set_sreg(fd, FPMulAdd(-sreg(fa), sreg(fn), sreg(fm))); |
3127 break; | 3077 break; |
3128 case FNMADD_d: | 3078 case FNMADD_d: |
3129 set_dreg(fd, FPMulAdd(-dreg(fa), -dreg(fn), dreg(fm))); | 3079 set_dreg(fd, FPMulAdd(-dreg(fa), -dreg(fn), dreg(fm))); |
3130 break; | 3080 break; |
3131 case FNMSUB_d: | 3081 case FNMSUB_d: |
3132 set_dreg(fd, FPMulAdd(-dreg(fa), dreg(fn), dreg(fm))); | 3082 set_dreg(fd, FPMulAdd(-dreg(fa), dreg(fn), dreg(fm))); |
3133 break; | 3083 break; |
3134 default: UNIMPLEMENTED(); | 3084 default: |
| 3085 UNIMPLEMENTED(); |
3135 } | 3086 } |
3136 } | 3087 } |
3137 | 3088 |
3138 | |
3139 template <typename T> | |
3140 T Simulator::FPAdd(T op1, T op2) { | |
3141 // NaNs should be handled elsewhere. | |
3142 DCHECK(!std::isnan(op1) && !std::isnan(op2)); | |
3143 | |
3144 if (std::isinf(op1) && std::isinf(op2) && (op1 != op2)) { | |
3145 // inf + -inf returns the default NaN. | |
3146 return FPDefaultNaN<T>(); | |
3147 } else { | |
3148 // Other cases should be handled by standard arithmetic. | |
3149 return op1 + op2; | |
3150 } | |
3151 } | |
3152 | |
3153 | |
3154 template <typename T> | |
3155 T Simulator::FPDiv(T op1, T op2) { | |
3156 // NaNs should be handled elsewhere. | |
3157 DCHECK(!std::isnan(op1) && !std::isnan(op2)); | |
3158 | |
3159 if ((std::isinf(op1) && std::isinf(op2)) || ((op1 == 0.0) && (op2 == 0.0))) { | |
3160 // inf / inf and 0.0 / 0.0 return the default NaN. | |
3161 return FPDefaultNaN<T>(); | |
3162 } else { | |
3163 // Other cases should be handled by standard arithmetic. | |
3164 return op1 / op2; | |
3165 } | |
3166 } | |
3167 | |
3168 | |
3169 template <typename T> | |
3170 T Simulator::FPMax(T a, T b) { | |
3171 // NaNs should be handled elsewhere. | |
3172 DCHECK(!std::isnan(a) && !std::isnan(b)); | |
3173 | |
3174 if ((a == 0.0) && (b == 0.0) && | |
3175 (copysign(1.0, a) != copysign(1.0, b))) { | |
3176 // a and b are zero, and the sign differs: return +0.0. | |
3177 return 0.0; | |
3178 } else { | |
3179 return (a > b) ? a : b; | |
3180 } | |
3181 } | |
3182 | |
3183 | |
3184 template <typename T> | |
3185 T Simulator::FPMaxNM(T a, T b) { | |
3186 if (IsQuietNaN(a) && !IsQuietNaN(b)) { | |
3187 a = kFP64NegativeInfinity; | |
3188 } else if (!IsQuietNaN(a) && IsQuietNaN(b)) { | |
3189 b = kFP64NegativeInfinity; | |
3190 } | |
3191 | |
3192 T result = FPProcessNaNs(a, b); | |
3193 return std::isnan(result) ? result : FPMax(a, b); | |
3194 } | |
3195 | |
3196 template <typename T> | |
3197 T Simulator::FPMin(T a, T b) { | |
3198 // NaNs should be handled elsewhere. | |
3199 DCHECK(!std::isnan(a) && !std::isnan(b)); | |
3200 | |
3201 if ((a == 0.0) && (b == 0.0) && | |
3202 (copysign(1.0, a) != copysign(1.0, b))) { | |
3203 // a and b are zero, and the sign differs: return -0.0. | |
3204 return -0.0; | |
3205 } else { | |
3206 return (a < b) ? a : b; | |
3207 } | |
3208 } | |
3209 | |
3210 | |
3211 template <typename T> | |
3212 T Simulator::FPMinNM(T a, T b) { | |
3213 if (IsQuietNaN(a) && !IsQuietNaN(b)) { | |
3214 a = kFP64PositiveInfinity; | |
3215 } else if (!IsQuietNaN(a) && IsQuietNaN(b)) { | |
3216 b = kFP64PositiveInfinity; | |
3217 } | |
3218 | |
3219 T result = FPProcessNaNs(a, b); | |
3220 return std::isnan(result) ? result : FPMin(a, b); | |
3221 } | |
3222 | |
3223 | |
3224 template <typename T> | |
3225 T Simulator::FPMul(T op1, T op2) { | |
3226 // NaNs should be handled elsewhere. | |
3227 DCHECK(!std::isnan(op1) && !std::isnan(op2)); | |
3228 | |
3229 if ((std::isinf(op1) && (op2 == 0.0)) || (std::isinf(op2) && (op1 == 0.0))) { | |
3230 // inf * 0.0 returns the default NaN. | |
3231 return FPDefaultNaN<T>(); | |
3232 } else { | |
3233 // Other cases should be handled by standard arithmetic. | |
3234 return op1 * op2; | |
3235 } | |
3236 } | |
3237 | |
3238 | |
3239 template<typename T> | |
3240 T Simulator::FPMulAdd(T a, T op1, T op2) { | |
3241 T result = FPProcessNaNs3(a, op1, op2); | |
3242 | |
3243 T sign_a = copysign(1.0, a); | |
3244 T sign_prod = copysign(1.0, op1) * copysign(1.0, op2); | |
3245 bool isinf_prod = std::isinf(op1) || std::isinf(op2); | |
3246 bool operation_generates_nan = | |
3247 (std::isinf(op1) && (op2 == 0.0)) || // inf * 0.0 | |
3248 (std::isinf(op2) && (op1 == 0.0)) || // 0.0 * inf | |
3249 (std::isinf(a) && isinf_prod && (sign_a != sign_prod)); // inf - inf | |
3250 | |
3251 if (std::isnan(result)) { | |
3252 // Generated NaNs override quiet NaNs propagated from a. | |
3253 if (operation_generates_nan && IsQuietNaN(a)) { | |
3254 return FPDefaultNaN<T>(); | |
3255 } else { | |
3256 return result; | |
3257 } | |
3258 } | |
3259 | |
3260 // If the operation would produce a NaN, return the default NaN. | |
3261 if (operation_generates_nan) { | |
3262 return FPDefaultNaN<T>(); | |
3263 } | |
3264 | |
3265 // Work around broken fma implementations for exact zero results: The sign of | |
3266 // exact 0.0 results is positive unless both a and op1 * op2 are negative. | |
3267 if (((op1 == 0.0) || (op2 == 0.0)) && (a == 0.0)) { | |
3268 return ((sign_a < 0) && (sign_prod < 0)) ? -0.0 : 0.0; | |
3269 } | |
3270 | |
3271 result = FusedMultiplyAdd(op1, op2, a); | |
3272 DCHECK(!std::isnan(result)); | |
3273 | |
3274 // Work around broken fma implementations for rounded zero results: If a is | |
3275 // 0.0, the sign of the result is the sign of op1 * op2 before rounding. | |
3276 if ((a == 0.0) && (result == 0.0)) { | |
3277 return copysign(0.0, sign_prod); | |
3278 } | |
3279 | |
3280 return result; | |
3281 } | |
3282 | |
3283 | |
3284 template <typename T> | |
3285 T Simulator::FPSqrt(T op) { | |
3286 if (std::isnan(op)) { | |
3287 return FPProcessNaN(op); | |
3288 } else if (op < 0.0) { | |
3289 return FPDefaultNaN<T>(); | |
3290 } else { | |
3291 lazily_initialize_fast_sqrt(isolate_); | |
3292 return fast_sqrt(op, isolate_); | |
3293 } | |
3294 } | |
3295 | |
3296 | |
3297 template <typename T> | |
3298 T Simulator::FPSub(T op1, T op2) { | |
3299 // NaNs should be handled elsewhere. | |
3300 DCHECK(!std::isnan(op1) && !std::isnan(op2)); | |
3301 | |
3302 if (std::isinf(op1) && std::isinf(op2) && (op1 == op2)) { | |
3303 // inf - inf returns the default NaN. | |
3304 return FPDefaultNaN<T>(); | |
3305 } else { | |
3306 // Other cases should be handled by standard arithmetic. | |
3307 return op1 - op2; | |
3308 } | |
3309 } | |
3310 | |
3311 | |
3312 template <typename T> | |
3313 T Simulator::FPProcessNaN(T op) { | |
3314 DCHECK(std::isnan(op)); | |
3315 return fpcr().DN() ? FPDefaultNaN<T>() : ToQuietNaN(op); | |
3316 } | |
3317 | |
3318 | |
3319 template <typename T> | |
3320 T Simulator::FPProcessNaNs(T op1, T op2) { | |
3321 if (IsSignallingNaN(op1)) { | |
3322 return FPProcessNaN(op1); | |
3323 } else if (IsSignallingNaN(op2)) { | |
3324 return FPProcessNaN(op2); | |
3325 } else if (std::isnan(op1)) { | |
3326 DCHECK(IsQuietNaN(op1)); | |
3327 return FPProcessNaN(op1); | |
3328 } else if (std::isnan(op2)) { | |
3329 DCHECK(IsQuietNaN(op2)); | |
3330 return FPProcessNaN(op2); | |
3331 } else { | |
3332 return 0.0; | |
3333 } | |
3334 } | |
3335 | |
3336 | |
3337 template <typename T> | |
3338 T Simulator::FPProcessNaNs3(T op1, T op2, T op3) { | |
3339 if (IsSignallingNaN(op1)) { | |
3340 return FPProcessNaN(op1); | |
3341 } else if (IsSignallingNaN(op2)) { | |
3342 return FPProcessNaN(op2); | |
3343 } else if (IsSignallingNaN(op3)) { | |
3344 return FPProcessNaN(op3); | |
3345 } else if (std::isnan(op1)) { | |
3346 DCHECK(IsQuietNaN(op1)); | |
3347 return FPProcessNaN(op1); | |
3348 } else if (std::isnan(op2)) { | |
3349 DCHECK(IsQuietNaN(op2)); | |
3350 return FPProcessNaN(op2); | |
3351 } else if (std::isnan(op3)) { | |
3352 DCHECK(IsQuietNaN(op3)); | |
3353 return FPProcessNaN(op3); | |
3354 } else { | |
3355 return 0.0; | |
3356 } | |
3357 } | |
3358 | |
3359 | |
3360 bool Simulator::FPProcessNaNs(Instruction* instr) { | 3089 bool Simulator::FPProcessNaNs(Instruction* instr) { |
3361 unsigned fd = instr->Rd(); | 3090 unsigned fd = instr->Rd(); |
3362 unsigned fn = instr->Rn(); | 3091 unsigned fn = instr->Rn(); |
3363 unsigned fm = instr->Rm(); | 3092 unsigned fm = instr->Rm(); |
3364 bool done = false; | 3093 bool done = false; |
3365 | 3094 |
3366 if (instr->Mask(FP64) == FP64) { | 3095 if (instr->Mask(FP64) == FP64) { |
3367 double result = FPProcessNaNs(dreg(fn), dreg(fm)); | 3096 double result = FPProcessNaNs(dreg(fn), dreg(fm)); |
3368 if (std::isnan(result)) { | 3097 if (std::isnan(result)) { |
3369 set_dreg(fd, result); | 3098 set_dreg(fd, result); |
(...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3459 clr_reg_name, clr_reg_value, xreg(31, Reg31IsStackPointer), clr_normal); | 3188 clr_reg_name, clr_reg_value, xreg(31, Reg31IsStackPointer), clr_normal); |
3460 return true; | 3189 return true; |
3461 } else if (strcmp(desc, "wcsp") == 0) { | 3190 } else if (strcmp(desc, "wcsp") == 0) { |
3462 DCHECK(CodeFromName(desc) == static_cast<int>(kSPRegInternalCode)); | 3191 DCHECK(CodeFromName(desc) == static_cast<int>(kSPRegInternalCode)); |
3463 PrintF(stream_, "%s wcsp:%s 0x%08" PRIx32 "%s\n", | 3192 PrintF(stream_, "%s wcsp:%s 0x%08" PRIx32 "%s\n", |
3464 clr_reg_name, clr_reg_value, wreg(31, Reg31IsStackPointer), clr_normal); | 3193 clr_reg_name, clr_reg_value, wreg(31, Reg31IsStackPointer), clr_normal); |
3465 return true; | 3194 return true; |
3466 } | 3195 } |
3467 | 3196 |
3468 int i = CodeFromName(desc); | 3197 int i = CodeFromName(desc); |
3469 STATIC_ASSERT(kNumberOfRegisters == kNumberOfFPRegisters); | 3198 static_assert(kNumberOfRegisters == kNumberOfVRegisters, |
3470 if (i < 0 || static_cast<unsigned>(i) >= kNumberOfFPRegisters) return false; | 3199 "Must be same number of Registers as VRegisters."); |
| 3200 if (i < 0 || static_cast<unsigned>(i) >= kNumberOfVRegisters) return false; |
3471 | 3201 |
3472 if (desc[0] == 'v') { | 3202 if (desc[0] == 'v') { |
3473 PrintF(stream_, "%s %s:%s 0x%016" PRIx64 "%s (%s%s:%s %g%s %s:%s %g%s)\n", | 3203 PrintF(stream_, "%s %s:%s 0x%016" PRIx64 "%s (%s%s:%s %g%s %s:%s %g%s)\n", |
3474 clr_fpreg_name, VRegNameForCode(i), | 3204 clr_vreg_name, VRegNameForCode(i), clr_vreg_value, |
3475 clr_fpreg_value, double_to_rawbits(dreg(i)), | 3205 bit_cast<uint64_t>(dreg(i)), clr_normal, clr_vreg_name, |
3476 clr_normal, | 3206 DRegNameForCode(i), clr_vreg_value, dreg(i), clr_vreg_name, |
3477 clr_fpreg_name, DRegNameForCode(i), | 3207 SRegNameForCode(i), clr_vreg_value, sreg(i), clr_normal); |
3478 clr_fpreg_value, dreg(i), | |
3479 clr_fpreg_name, SRegNameForCode(i), | |
3480 clr_fpreg_value, sreg(i), | |
3481 clr_normal); | |
3482 return true; | 3208 return true; |
3483 } else if (desc[0] == 'd') { | 3209 } else if (desc[0] == 'd') { |
3484 PrintF(stream_, "%s %s:%s %g%s\n", | 3210 PrintF(stream_, "%s %s:%s %g%s\n", clr_vreg_name, DRegNameForCode(i), |
3485 clr_fpreg_name, DRegNameForCode(i), | 3211 clr_vreg_value, dreg(i), clr_normal); |
3486 clr_fpreg_value, dreg(i), | |
3487 clr_normal); | |
3488 return true; | 3212 return true; |
3489 } else if (desc[0] == 's') { | 3213 } else if (desc[0] == 's') { |
3490 PrintF(stream_, "%s %s:%s %g%s\n", | 3214 PrintF(stream_, "%s %s:%s %g%s\n", clr_vreg_name, SRegNameForCode(i), |
3491 clr_fpreg_name, SRegNameForCode(i), | 3215 clr_vreg_value, sreg(i), clr_normal); |
3492 clr_fpreg_value, sreg(i), | |
3493 clr_normal); | |
3494 return true; | 3216 return true; |
3495 } else if (desc[0] == 'w') { | 3217 } else if (desc[0] == 'w') { |
3496 PrintF(stream_, "%s %s:%s 0x%08" PRIx32 "%s\n", | 3218 PrintF(stream_, "%s %s:%s 0x%08" PRIx32 "%s\n", |
3497 clr_reg_name, WRegNameForCode(i), clr_reg_value, wreg(i), clr_normal); | 3219 clr_reg_name, WRegNameForCode(i), clr_reg_value, wreg(i), clr_normal); |
3498 return true; | 3220 return true; |
3499 } else { | 3221 } else { |
3500 // X register names have a wide variety of starting characters, but anything | 3222 // X register names have a wide variety of starting characters, but anything |
3501 // else will be an X register. | 3223 // else will be an X register. |
3502 PrintF(stream_, "%s %s:%s 0x%016" PRIx64 "%s\n", | 3224 PrintF(stream_, "%s %s:%s 0x%016" PRIx64 "%s\n", |
3503 clr_reg_name, XRegNameForCode(i), clr_reg_value, xreg(i), clr_normal); | 3225 clr_reg_name, XRegNameForCode(i), clr_reg_value, xreg(i), clr_normal); |
(...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3609 // Disassemble. | 3331 // Disassemble. |
3610 PrintInstructionsAt(reinterpret_cast<Instruction*>(address), | 3332 PrintInstructionsAt(reinterpret_cast<Instruction*>(address), |
3611 n_of_instrs_to_disasm); | 3333 n_of_instrs_to_disasm); |
3612 PrintF("\n"); | 3334 PrintF("\n"); |
3613 | 3335 |
3614 // print / p ------------------------------------------------------------- | 3336 // print / p ------------------------------------------------------------- |
3615 } else if ((strcmp(cmd, "print") == 0) || (strcmp(cmd, "p") == 0)) { | 3337 } else if ((strcmp(cmd, "print") == 0) || (strcmp(cmd, "p") == 0)) { |
3616 if (argc == 2) { | 3338 if (argc == 2) { |
3617 if (strcmp(arg1, "all") == 0) { | 3339 if (strcmp(arg1, "all") == 0) { |
3618 PrintRegisters(); | 3340 PrintRegisters(); |
3619 PrintFPRegisters(); | 3341 PrintVRegisters(); |
3620 } else { | 3342 } else { |
3621 if (!PrintValue(arg1)) { | 3343 if (!PrintValue(arg1)) { |
3622 PrintF("%s unrecognized\n", arg1); | 3344 PrintF("%s unrecognized\n", arg1); |
3623 } | 3345 } |
3624 } | 3346 } |
3625 } else { | 3347 } else { |
3626 PrintF( | 3348 PrintF( |
3627 "print <register>\n" | 3349 "print <register>\n" |
3628 " Print the content of a register. (alias 'p')\n" | 3350 " Print the content of a register. (alias 'p')\n" |
3629 " 'print all' will print all registers.\n" | 3351 " 'print all' will print all registers.\n" |
(...skipping 205 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3835 clr_normal); | 3557 clr_normal); |
3836 } | 3558 } |
3837 } | 3559 } |
3838 | 3560 |
3839 // Other options. | 3561 // Other options. |
3840 switch (parameters & kDebuggerTracingDirectivesMask) { | 3562 switch (parameters & kDebuggerTracingDirectivesMask) { |
3841 case TRACE_ENABLE: | 3563 case TRACE_ENABLE: |
3842 set_log_parameters(log_parameters() | parameters); | 3564 set_log_parameters(log_parameters() | parameters); |
3843 if (parameters & LOG_SYS_REGS) { PrintSystemRegisters(); } | 3565 if (parameters & LOG_SYS_REGS) { PrintSystemRegisters(); } |
3844 if (parameters & LOG_REGS) { PrintRegisters(); } | 3566 if (parameters & LOG_REGS) { PrintRegisters(); } |
3845 if (parameters & LOG_FP_REGS) { PrintFPRegisters(); } | 3567 if (parameters & LOG_VREGS) { |
| 3568 PrintVRegisters(); |
| 3569 } |
3846 break; | 3570 break; |
3847 case TRACE_DISABLE: | 3571 case TRACE_DISABLE: |
3848 set_log_parameters(log_parameters() & ~parameters); | 3572 set_log_parameters(log_parameters() & ~parameters); |
3849 break; | 3573 break; |
3850 case TRACE_OVERRIDE: | 3574 case TRACE_OVERRIDE: |
3851 set_log_parameters(parameters); | 3575 set_log_parameters(parameters); |
3852 break; | 3576 break; |
3853 default: | 3577 default: |
3854 // We don't support a one-shot LOG_DISASM. | 3578 // We don't support a one-shot LOG_DISASM. |
3855 DCHECK((parameters & LOG_DISASM) == 0); | 3579 DCHECK((parameters & LOG_DISASM) == 0); |
3856 // Don't print information that is already being traced. | 3580 // Don't print information that is already being traced. |
3857 parameters &= ~log_parameters(); | 3581 parameters &= ~log_parameters(); |
3858 // Print the requested information. | 3582 // Print the requested information. |
3859 if (parameters & LOG_SYS_REGS) PrintSystemRegisters(); | 3583 if (parameters & LOG_SYS_REGS) PrintSystemRegisters(); |
3860 if (parameters & LOG_REGS) PrintRegisters(); | 3584 if (parameters & LOG_REGS) PrintRegisters(); |
3861 if (parameters & LOG_FP_REGS) PrintFPRegisters(); | 3585 if (parameters & LOG_VREGS) PrintVRegisters(); |
3862 } | 3586 } |
3863 | 3587 |
3864 // The stop parameters are inlined in the code. Skip them: | 3588 // The stop parameters are inlined in the code. Skip them: |
3865 // - Skip to the end of the message string. | 3589 // - Skip to the end of the message string. |
3866 size_t size = kDebugMessageOffset + strlen(message) + 1; | 3590 size_t size = kDebugMessageOffset + strlen(message) + 1; |
3867 pc_ = pc_->InstructionAtOffset(RoundUp(size, kInstructionSize)); | 3591 pc_ = pc_->InstructionAtOffset(RoundUp(size, kInstructionSize)); |
3868 // - Verify that the unreachable marker is present. | 3592 // - Verify that the unreachable marker is present. |
3869 DCHECK(pc_->Mask(ExceptionMask) == HLT); | 3593 DCHECK(pc_->Mask(ExceptionMask) == HLT); |
3870 DCHECK(pc_->ImmException() == kImmExceptionIsUnreachable); | 3594 DCHECK(pc_->ImmException() == kImmExceptionIsUnreachable); |
3871 // - Skip past the unreachable marker. | 3595 // - Skip past the unreachable marker. |
(...skipping 16 matching lines...) Expand all Loading... |
3888 base::OS::DebugBreak(); | 3612 base::OS::DebugBreak(); |
3889 } | 3613 } |
3890 break; | 3614 break; |
3891 } | 3615 } |
3892 | 3616 |
3893 default: | 3617 default: |
3894 UNIMPLEMENTED(); | 3618 UNIMPLEMENTED(); |
3895 } | 3619 } |
3896 } | 3620 } |
3897 | 3621 |
| 3622 void Simulator::VisitNEON2RegMisc(Instruction* instr) { |
| 3623 NEONFormatDecoder nfd(instr); |
| 3624 VectorFormat vf = nfd.GetVectorFormat(); |
| 3625 |
| 3626 // Format mapping for "long pair" instructions, [su]addlp, [su]adalp. |
| 3627 static const NEONFormatMap map_lp = { |
| 3628 {23, 22, 30}, {NF_4H, NF_8H, NF_2S, NF_4S, NF_1D, NF_2D}}; |
| 3629 VectorFormat vf_lp = nfd.GetVectorFormat(&map_lp); |
| 3630 |
| 3631 static const NEONFormatMap map_fcvtl = {{22}, {NF_4S, NF_2D}}; |
| 3632 VectorFormat vf_fcvtl = nfd.GetVectorFormat(&map_fcvtl); |
| 3633 |
| 3634 static const NEONFormatMap map_fcvtn = {{22, 30}, |
| 3635 {NF_4H, NF_8H, NF_2S, NF_4S}}; |
| 3636 VectorFormat vf_fcvtn = nfd.GetVectorFormat(&map_fcvtn); |
| 3637 |
| 3638 SimVRegister& rd = vreg(instr->Rd()); |
| 3639 SimVRegister& rn = vreg(instr->Rn()); |
| 3640 |
| 3641 if (instr->Mask(NEON2RegMiscOpcode) <= NEON_NEG_opcode) { |
| 3642 // These instructions all use a two bit size field, except NOT and RBIT, |
| 3643 // which use the field to encode the operation. |
| 3644 switch (instr->Mask(NEON2RegMiscMask)) { |
| 3645 case NEON_REV64: |
| 3646 rev64(vf, rd, rn); |
| 3647 break; |
| 3648 case NEON_REV32: |
| 3649 rev32(vf, rd, rn); |
| 3650 break; |
| 3651 case NEON_REV16: |
| 3652 rev16(vf, rd, rn); |
| 3653 break; |
| 3654 case NEON_SUQADD: |
| 3655 suqadd(vf, rd, rn); |
| 3656 break; |
| 3657 case NEON_USQADD: |
| 3658 usqadd(vf, rd, rn); |
| 3659 break; |
| 3660 case NEON_CLS: |
| 3661 cls(vf, rd, rn); |
| 3662 break; |
| 3663 case NEON_CLZ: |
| 3664 clz(vf, rd, rn); |
| 3665 break; |
| 3666 case NEON_CNT: |
| 3667 cnt(vf, rd, rn); |
| 3668 break; |
| 3669 case NEON_SQABS: |
| 3670 abs(vf, rd, rn).SignedSaturate(vf); |
| 3671 break; |
| 3672 case NEON_SQNEG: |
| 3673 neg(vf, rd, rn).SignedSaturate(vf); |
| 3674 break; |
| 3675 case NEON_CMGT_zero: |
| 3676 cmp(vf, rd, rn, 0, gt); |
| 3677 break; |
| 3678 case NEON_CMGE_zero: |
| 3679 cmp(vf, rd, rn, 0, ge); |
| 3680 break; |
| 3681 case NEON_CMEQ_zero: |
| 3682 cmp(vf, rd, rn, 0, eq); |
| 3683 break; |
| 3684 case NEON_CMLE_zero: |
| 3685 cmp(vf, rd, rn, 0, le); |
| 3686 break; |
| 3687 case NEON_CMLT_zero: |
| 3688 cmp(vf, rd, rn, 0, lt); |
| 3689 break; |
| 3690 case NEON_ABS: |
| 3691 abs(vf, rd, rn); |
| 3692 break; |
| 3693 case NEON_NEG: |
| 3694 neg(vf, rd, rn); |
| 3695 break; |
| 3696 case NEON_SADDLP: |
| 3697 saddlp(vf_lp, rd, rn); |
| 3698 break; |
| 3699 case NEON_UADDLP: |
| 3700 uaddlp(vf_lp, rd, rn); |
| 3701 break; |
| 3702 case NEON_SADALP: |
| 3703 sadalp(vf_lp, rd, rn); |
| 3704 break; |
| 3705 case NEON_UADALP: |
| 3706 uadalp(vf_lp, rd, rn); |
| 3707 break; |
| 3708 case NEON_RBIT_NOT: |
| 3709 vf = nfd.GetVectorFormat(nfd.LogicalFormatMap()); |
| 3710 switch (instr->FPType()) { |
| 3711 case 0: |
| 3712 not_(vf, rd, rn); |
| 3713 break; |
| 3714 case 1: |
| 3715 rbit(vf, rd, rn); |
| 3716 break; |
| 3717 default: |
| 3718 UNIMPLEMENTED(); |
| 3719 } |
| 3720 break; |
| 3721 } |
| 3722 } else { |
| 3723 VectorFormat fpf = nfd.GetVectorFormat(nfd.FPFormatMap()); |
| 3724 FPRounding fpcr_rounding = static_cast<FPRounding>(fpcr().RMode()); |
| 3725 bool inexact_exception = false; |
| 3726 |
| 3727 // These instructions all use a one bit size field, except XTN, SQXTUN, |
| 3728 // SHLL, SQXTN and UQXTN, which use a two bit size field. |
| 3729 switch (instr->Mask(NEON2RegMiscFPMask)) { |
| 3730 case NEON_FABS: |
| 3731 fabs_(fpf, rd, rn); |
| 3732 return; |
| 3733 case NEON_FNEG: |
| 3734 fneg(fpf, rd, rn); |
| 3735 return; |
| 3736 case NEON_FSQRT: |
| 3737 fsqrt(fpf, rd, rn); |
| 3738 return; |
| 3739 case NEON_FCVTL: |
| 3740 if (instr->Mask(NEON_Q)) { |
| 3741 fcvtl2(vf_fcvtl, rd, rn); |
| 3742 } else { |
| 3743 fcvtl(vf_fcvtl, rd, rn); |
| 3744 } |
| 3745 return; |
| 3746 case NEON_FCVTN: |
| 3747 if (instr->Mask(NEON_Q)) { |
| 3748 fcvtn2(vf_fcvtn, rd, rn); |
| 3749 } else { |
| 3750 fcvtn(vf_fcvtn, rd, rn); |
| 3751 } |
| 3752 return; |
| 3753 case NEON_FCVTXN: |
| 3754 if (instr->Mask(NEON_Q)) { |
| 3755 fcvtxn2(vf_fcvtn, rd, rn); |
| 3756 } else { |
| 3757 fcvtxn(vf_fcvtn, rd, rn); |
| 3758 } |
| 3759 return; |
| 3760 |
| 3761 // The following instructions break from the switch statement, rather |
| 3762 // than return. |
| 3763 case NEON_FRINTI: |
| 3764 break; // Use FPCR rounding mode. |
| 3765 case NEON_FRINTX: |
| 3766 inexact_exception = true; |
| 3767 break; |
| 3768 case NEON_FRINTA: |
| 3769 fpcr_rounding = FPTieAway; |
| 3770 break; |
| 3771 case NEON_FRINTM: |
| 3772 fpcr_rounding = FPNegativeInfinity; |
| 3773 break; |
| 3774 case NEON_FRINTN: |
| 3775 fpcr_rounding = FPTieEven; |
| 3776 break; |
| 3777 case NEON_FRINTP: |
| 3778 fpcr_rounding = FPPositiveInfinity; |
| 3779 break; |
| 3780 case NEON_FRINTZ: |
| 3781 fpcr_rounding = FPZero; |
| 3782 break; |
| 3783 |
| 3784 // The remaining cases return to the caller. |
| 3785 case NEON_FCVTNS: |
| 3786 fcvts(fpf, rd, rn, FPTieEven); |
| 3787 return; |
| 3788 case NEON_FCVTNU: |
| 3789 fcvtu(fpf, rd, rn, FPTieEven); |
| 3790 return; |
| 3791 case NEON_FCVTPS: |
| 3792 fcvts(fpf, rd, rn, FPPositiveInfinity); |
| 3793 return; |
| 3794 case NEON_FCVTPU: |
| 3795 fcvtu(fpf, rd, rn, FPPositiveInfinity); |
| 3796 return; |
| 3797 case NEON_FCVTMS: |
| 3798 fcvts(fpf, rd, rn, FPNegativeInfinity); |
| 3799 return; |
| 3800 case NEON_FCVTMU: |
| 3801 fcvtu(fpf, rd, rn, FPNegativeInfinity); |
| 3802 return; |
| 3803 case NEON_FCVTZS: |
| 3804 fcvts(fpf, rd, rn, FPZero); |
| 3805 return; |
| 3806 case NEON_FCVTZU: |
| 3807 fcvtu(fpf, rd, rn, FPZero); |
| 3808 return; |
| 3809 case NEON_FCVTAS: |
| 3810 fcvts(fpf, rd, rn, FPTieAway); |
| 3811 return; |
| 3812 case NEON_FCVTAU: |
| 3813 fcvtu(fpf, rd, rn, FPTieAway); |
| 3814 return; |
| 3815 case NEON_SCVTF: |
| 3816 scvtf(fpf, rd, rn, 0, fpcr_rounding); |
| 3817 return; |
| 3818 case NEON_UCVTF: |
| 3819 ucvtf(fpf, rd, rn, 0, fpcr_rounding); |
| 3820 return; |
| 3821 case NEON_URSQRTE: |
| 3822 ursqrte(fpf, rd, rn); |
| 3823 return; |
| 3824 case NEON_URECPE: |
| 3825 urecpe(fpf, rd, rn); |
| 3826 return; |
| 3827 case NEON_FRSQRTE: |
| 3828 frsqrte(fpf, rd, rn); |
| 3829 return; |
| 3830 case NEON_FRECPE: |
| 3831 frecpe(fpf, rd, rn, fpcr_rounding); |
| 3832 return; |
| 3833 case NEON_FCMGT_zero: |
| 3834 fcmp_zero(fpf, rd, rn, gt); |
| 3835 return; |
| 3836 case NEON_FCMGE_zero: |
| 3837 fcmp_zero(fpf, rd, rn, ge); |
| 3838 return; |
| 3839 case NEON_FCMEQ_zero: |
| 3840 fcmp_zero(fpf, rd, rn, eq); |
| 3841 return; |
| 3842 case NEON_FCMLE_zero: |
| 3843 fcmp_zero(fpf, rd, rn, le); |
| 3844 return; |
| 3845 case NEON_FCMLT_zero: |
| 3846 fcmp_zero(fpf, rd, rn, lt); |
| 3847 return; |
| 3848 default: |
| 3849 if ((NEON_XTN_opcode <= instr->Mask(NEON2RegMiscOpcode)) && |
| 3850 (instr->Mask(NEON2RegMiscOpcode) <= NEON_UQXTN_opcode)) { |
| 3851 switch (instr->Mask(NEON2RegMiscMask)) { |
| 3852 case NEON_XTN: |
| 3853 xtn(vf, rd, rn); |
| 3854 return; |
| 3855 case NEON_SQXTN: |
| 3856 sqxtn(vf, rd, rn); |
| 3857 return; |
| 3858 case NEON_UQXTN: |
| 3859 uqxtn(vf, rd, rn); |
| 3860 return; |
| 3861 case NEON_SQXTUN: |
| 3862 sqxtun(vf, rd, rn); |
| 3863 return; |
| 3864 case NEON_SHLL: |
| 3865 vf = nfd.GetVectorFormat(nfd.LongIntegerFormatMap()); |
| 3866 if (instr->Mask(NEON_Q)) { |
| 3867 shll2(vf, rd, rn); |
| 3868 } else { |
| 3869 shll(vf, rd, rn); |
| 3870 } |
| 3871 return; |
| 3872 default: |
| 3873 UNIMPLEMENTED(); |
| 3874 } |
| 3875 } else { |
| 3876 UNIMPLEMENTED(); |
| 3877 } |
| 3878 } |
| 3879 |
| 3880 // Only FRINT* instructions fall through the switch above. |
| 3881 frint(fpf, rd, rn, fpcr_rounding, inexact_exception); |
| 3882 } |
| 3883 } |
| 3884 |
| 3885 void Simulator::VisitNEON3Same(Instruction* instr) { |
| 3886 NEONFormatDecoder nfd(instr); |
| 3887 SimVRegister& rd = vreg(instr->Rd()); |
| 3888 SimVRegister& rn = vreg(instr->Rn()); |
| 3889 SimVRegister& rm = vreg(instr->Rm()); |
| 3890 |
| 3891 if (instr->Mask(NEON3SameLogicalFMask) == NEON3SameLogicalFixed) { |
| 3892 VectorFormat vf = nfd.GetVectorFormat(nfd.LogicalFormatMap()); |
| 3893 switch (instr->Mask(NEON3SameLogicalMask)) { |
| 3894 case NEON_AND: |
| 3895 and_(vf, rd, rn, rm); |
| 3896 break; |
| 3897 case NEON_ORR: |
| 3898 orr(vf, rd, rn, rm); |
| 3899 break; |
| 3900 case NEON_ORN: |
| 3901 orn(vf, rd, rn, rm); |
| 3902 break; |
| 3903 case NEON_EOR: |
| 3904 eor(vf, rd, rn, rm); |
| 3905 break; |
| 3906 case NEON_BIC: |
| 3907 bic(vf, rd, rn, rm); |
| 3908 break; |
| 3909 case NEON_BIF: |
| 3910 bif(vf, rd, rn, rm); |
| 3911 break; |
| 3912 case NEON_BIT: |
| 3913 bit(vf, rd, rn, rm); |
| 3914 break; |
| 3915 case NEON_BSL: |
| 3916 bsl(vf, rd, rn, rm); |
| 3917 break; |
| 3918 default: |
| 3919 UNIMPLEMENTED(); |
| 3920 } |
| 3921 } else if (instr->Mask(NEON3SameFPFMask) == NEON3SameFPFixed) { |
| 3922 VectorFormat vf = nfd.GetVectorFormat(nfd.FPFormatMap()); |
| 3923 switch (instr->Mask(NEON3SameFPMask)) { |
| 3924 case NEON_FADD: |
| 3925 fadd(vf, rd, rn, rm); |
| 3926 break; |
| 3927 case NEON_FSUB: |
| 3928 fsub(vf, rd, rn, rm); |
| 3929 break; |
| 3930 case NEON_FMUL: |
| 3931 fmul(vf, rd, rn, rm); |
| 3932 break; |
| 3933 case NEON_FDIV: |
| 3934 fdiv(vf, rd, rn, rm); |
| 3935 break; |
| 3936 case NEON_FMAX: |
| 3937 fmax(vf, rd, rn, rm); |
| 3938 break; |
| 3939 case NEON_FMIN: |
| 3940 fmin(vf, rd, rn, rm); |
| 3941 break; |
| 3942 case NEON_FMAXNM: |
| 3943 fmaxnm(vf, rd, rn, rm); |
| 3944 break; |
| 3945 case NEON_FMINNM: |
| 3946 fminnm(vf, rd, rn, rm); |
| 3947 break; |
| 3948 case NEON_FMLA: |
| 3949 fmla(vf, rd, rn, rm); |
| 3950 break; |
| 3951 case NEON_FMLS: |
| 3952 fmls(vf, rd, rn, rm); |
| 3953 break; |
| 3954 case NEON_FMULX: |
| 3955 fmulx(vf, rd, rn, rm); |
| 3956 break; |
| 3957 case NEON_FACGE: |
| 3958 fabscmp(vf, rd, rn, rm, ge); |
| 3959 break; |
| 3960 case NEON_FACGT: |
| 3961 fabscmp(vf, rd, rn, rm, gt); |
| 3962 break; |
| 3963 case NEON_FCMEQ: |
| 3964 fcmp(vf, rd, rn, rm, eq); |
| 3965 break; |
| 3966 case NEON_FCMGE: |
| 3967 fcmp(vf, rd, rn, rm, ge); |
| 3968 break; |
| 3969 case NEON_FCMGT: |
| 3970 fcmp(vf, rd, rn, rm, gt); |
| 3971 break; |
| 3972 case NEON_FRECPS: |
| 3973 frecps(vf, rd, rn, rm); |
| 3974 break; |
| 3975 case NEON_FRSQRTS: |
| 3976 frsqrts(vf, rd, rn, rm); |
| 3977 break; |
| 3978 case NEON_FABD: |
| 3979 fabd(vf, rd, rn, rm); |
| 3980 break; |
| 3981 case NEON_FADDP: |
| 3982 faddp(vf, rd, rn, rm); |
| 3983 break; |
| 3984 case NEON_FMAXP: |
| 3985 fmaxp(vf, rd, rn, rm); |
| 3986 break; |
| 3987 case NEON_FMAXNMP: |
| 3988 fmaxnmp(vf, rd, rn, rm); |
| 3989 break; |
| 3990 case NEON_FMINP: |
| 3991 fminp(vf, rd, rn, rm); |
| 3992 break; |
| 3993 case NEON_FMINNMP: |
| 3994 fminnmp(vf, rd, rn, rm); |
| 3995 break; |
| 3996 default: |
| 3997 UNIMPLEMENTED(); |
| 3998 } |
| 3999 } else { |
| 4000 VectorFormat vf = nfd.GetVectorFormat(); |
| 4001 switch (instr->Mask(NEON3SameMask)) { |
| 4002 case NEON_ADD: |
| 4003 add(vf, rd, rn, rm); |
| 4004 break; |
| 4005 case NEON_ADDP: |
| 4006 addp(vf, rd, rn, rm); |
| 4007 break; |
| 4008 case NEON_CMEQ: |
| 4009 cmp(vf, rd, rn, rm, eq); |
| 4010 break; |
| 4011 case NEON_CMGE: |
| 4012 cmp(vf, rd, rn, rm, ge); |
| 4013 break; |
| 4014 case NEON_CMGT: |
| 4015 cmp(vf, rd, rn, rm, gt); |
| 4016 break; |
| 4017 case NEON_CMHI: |
| 4018 cmp(vf, rd, rn, rm, hi); |
| 4019 break; |
| 4020 case NEON_CMHS: |
| 4021 cmp(vf, rd, rn, rm, hs); |
| 4022 break; |
| 4023 case NEON_CMTST: |
| 4024 cmptst(vf, rd, rn, rm); |
| 4025 break; |
| 4026 case NEON_MLS: |
| 4027 mls(vf, rd, rn, rm); |
| 4028 break; |
| 4029 case NEON_MLA: |
| 4030 mla(vf, rd, rn, rm); |
| 4031 break; |
| 4032 case NEON_MUL: |
| 4033 mul(vf, rd, rn, rm); |
| 4034 break; |
| 4035 case NEON_PMUL: |
| 4036 pmul(vf, rd, rn, rm); |
| 4037 break; |
| 4038 case NEON_SMAX: |
| 4039 smax(vf, rd, rn, rm); |
| 4040 break; |
| 4041 case NEON_SMAXP: |
| 4042 smaxp(vf, rd, rn, rm); |
| 4043 break; |
| 4044 case NEON_SMIN: |
| 4045 smin(vf, rd, rn, rm); |
| 4046 break; |
| 4047 case NEON_SMINP: |
| 4048 sminp(vf, rd, rn, rm); |
| 4049 break; |
| 4050 case NEON_SUB: |
| 4051 sub(vf, rd, rn, rm); |
| 4052 break; |
| 4053 case NEON_UMAX: |
| 4054 umax(vf, rd, rn, rm); |
| 4055 break; |
| 4056 case NEON_UMAXP: |
| 4057 umaxp(vf, rd, rn, rm); |
| 4058 break; |
| 4059 case NEON_UMIN: |
| 4060 umin(vf, rd, rn, rm); |
| 4061 break; |
| 4062 case NEON_UMINP: |
| 4063 uminp(vf, rd, rn, rm); |
| 4064 break; |
| 4065 case NEON_SSHL: |
| 4066 sshl(vf, rd, rn, rm); |
| 4067 break; |
| 4068 case NEON_USHL: |
| 4069 ushl(vf, rd, rn, rm); |
| 4070 break; |
| 4071 case NEON_SABD: |
| 4072 AbsDiff(vf, rd, rn, rm, true); |
| 4073 break; |
| 4074 case NEON_UABD: |
| 4075 AbsDiff(vf, rd, rn, rm, false); |
| 4076 break; |
| 4077 case NEON_SABA: |
| 4078 saba(vf, rd, rn, rm); |
| 4079 break; |
| 4080 case NEON_UABA: |
| 4081 uaba(vf, rd, rn, rm); |
| 4082 break; |
| 4083 case NEON_UQADD: |
| 4084 add(vf, rd, rn, rm).UnsignedSaturate(vf); |
| 4085 break; |
| 4086 case NEON_SQADD: |
| 4087 add(vf, rd, rn, rm).SignedSaturate(vf); |
| 4088 break; |
| 4089 case NEON_UQSUB: |
| 4090 sub(vf, rd, rn, rm).UnsignedSaturate(vf); |
| 4091 break; |
| 4092 case NEON_SQSUB: |
| 4093 sub(vf, rd, rn, rm).SignedSaturate(vf); |
| 4094 break; |
| 4095 case NEON_SQDMULH: |
| 4096 sqdmulh(vf, rd, rn, rm); |
| 4097 break; |
| 4098 case NEON_SQRDMULH: |
| 4099 sqrdmulh(vf, rd, rn, rm); |
| 4100 break; |
| 4101 case NEON_UQSHL: |
| 4102 ushl(vf, rd, rn, rm).UnsignedSaturate(vf); |
| 4103 break; |
| 4104 case NEON_SQSHL: |
| 4105 sshl(vf, rd, rn, rm).SignedSaturate(vf); |
| 4106 break; |
| 4107 case NEON_URSHL: |
| 4108 ushl(vf, rd, rn, rm).Round(vf); |
| 4109 break; |
| 4110 case NEON_SRSHL: |
| 4111 sshl(vf, rd, rn, rm).Round(vf); |
| 4112 break; |
| 4113 case NEON_UQRSHL: |
| 4114 ushl(vf, rd, rn, rm).Round(vf).UnsignedSaturate(vf); |
| 4115 break; |
| 4116 case NEON_SQRSHL: |
| 4117 sshl(vf, rd, rn, rm).Round(vf).SignedSaturate(vf); |
| 4118 break; |
| 4119 case NEON_UHADD: |
| 4120 add(vf, rd, rn, rm).Uhalve(vf); |
| 4121 break; |
| 4122 case NEON_URHADD: |
| 4123 add(vf, rd, rn, rm).Uhalve(vf).Round(vf); |
| 4124 break; |
| 4125 case NEON_SHADD: |
| 4126 add(vf, rd, rn, rm).Halve(vf); |
| 4127 break; |
| 4128 case NEON_SRHADD: |
| 4129 add(vf, rd, rn, rm).Halve(vf).Round(vf); |
| 4130 break; |
| 4131 case NEON_UHSUB: |
| 4132 sub(vf, rd, rn, rm).Uhalve(vf); |
| 4133 break; |
| 4134 case NEON_SHSUB: |
| 4135 sub(vf, rd, rn, rm).Halve(vf); |
| 4136 break; |
| 4137 default: |
| 4138 UNIMPLEMENTED(); |
| 4139 } |
| 4140 } |
| 4141 } |
| 4142 |
| 4143 void Simulator::VisitNEON3Different(Instruction* instr) { |
| 4144 NEONFormatDecoder nfd(instr); |
| 4145 VectorFormat vf = nfd.GetVectorFormat(); |
| 4146 VectorFormat vf_l = nfd.GetVectorFormat(nfd.LongIntegerFormatMap()); |
| 4147 |
| 4148 SimVRegister& rd = vreg(instr->Rd()); |
| 4149 SimVRegister& rn = vreg(instr->Rn()); |
| 4150 SimVRegister& rm = vreg(instr->Rm()); |
| 4151 |
| 4152 switch (instr->Mask(NEON3DifferentMask)) { |
| 4153 case NEON_PMULL: |
| 4154 pmull(vf_l, rd, rn, rm); |
| 4155 break; |
| 4156 case NEON_PMULL2: |
| 4157 pmull2(vf_l, rd, rn, rm); |
| 4158 break; |
| 4159 case NEON_UADDL: |
| 4160 uaddl(vf_l, rd, rn, rm); |
| 4161 break; |
| 4162 case NEON_UADDL2: |
| 4163 uaddl2(vf_l, rd, rn, rm); |
| 4164 break; |
| 4165 case NEON_SADDL: |
| 4166 saddl(vf_l, rd, rn, rm); |
| 4167 break; |
| 4168 case NEON_SADDL2: |
| 4169 saddl2(vf_l, rd, rn, rm); |
| 4170 break; |
| 4171 case NEON_USUBL: |
| 4172 usubl(vf_l, rd, rn, rm); |
| 4173 break; |
| 4174 case NEON_USUBL2: |
| 4175 usubl2(vf_l, rd, rn, rm); |
| 4176 break; |
| 4177 case NEON_SSUBL: |
| 4178 ssubl(vf_l, rd, rn, rm); |
| 4179 break; |
| 4180 case NEON_SSUBL2: |
| 4181 ssubl2(vf_l, rd, rn, rm); |
| 4182 break; |
| 4183 case NEON_SABAL: |
| 4184 sabal(vf_l, rd, rn, rm); |
| 4185 break; |
| 4186 case NEON_SABAL2: |
| 4187 sabal2(vf_l, rd, rn, rm); |
| 4188 break; |
| 4189 case NEON_UABAL: |
| 4190 uabal(vf_l, rd, rn, rm); |
| 4191 break; |
| 4192 case NEON_UABAL2: |
| 4193 uabal2(vf_l, rd, rn, rm); |
| 4194 break; |
| 4195 case NEON_SABDL: |
| 4196 sabdl(vf_l, rd, rn, rm); |
| 4197 break; |
| 4198 case NEON_SABDL2: |
| 4199 sabdl2(vf_l, rd, rn, rm); |
| 4200 break; |
| 4201 case NEON_UABDL: |
| 4202 uabdl(vf_l, rd, rn, rm); |
| 4203 break; |
| 4204 case NEON_UABDL2: |
| 4205 uabdl2(vf_l, rd, rn, rm); |
| 4206 break; |
| 4207 case NEON_SMLAL: |
| 4208 smlal(vf_l, rd, rn, rm); |
| 4209 break; |
| 4210 case NEON_SMLAL2: |
| 4211 smlal2(vf_l, rd, rn, rm); |
| 4212 break; |
| 4213 case NEON_UMLAL: |
| 4214 umlal(vf_l, rd, rn, rm); |
| 4215 break; |
| 4216 case NEON_UMLAL2: |
| 4217 umlal2(vf_l, rd, rn, rm); |
| 4218 break; |
| 4219 case NEON_SMLSL: |
| 4220 smlsl(vf_l, rd, rn, rm); |
| 4221 break; |
| 4222 case NEON_SMLSL2: |
| 4223 smlsl2(vf_l, rd, rn, rm); |
| 4224 break; |
| 4225 case NEON_UMLSL: |
| 4226 umlsl(vf_l, rd, rn, rm); |
| 4227 break; |
| 4228 case NEON_UMLSL2: |
| 4229 umlsl2(vf_l, rd, rn, rm); |
| 4230 break; |
| 4231 case NEON_SMULL: |
| 4232 smull(vf_l, rd, rn, rm); |
| 4233 break; |
| 4234 case NEON_SMULL2: |
| 4235 smull2(vf_l, rd, rn, rm); |
| 4236 break; |
| 4237 case NEON_UMULL: |
| 4238 umull(vf_l, rd, rn, rm); |
| 4239 break; |
| 4240 case NEON_UMULL2: |
| 4241 umull2(vf_l, rd, rn, rm); |
| 4242 break; |
| 4243 case NEON_SQDMLAL: |
| 4244 sqdmlal(vf_l, rd, rn, rm); |
| 4245 break; |
| 4246 case NEON_SQDMLAL2: |
| 4247 sqdmlal2(vf_l, rd, rn, rm); |
| 4248 break; |
| 4249 case NEON_SQDMLSL: |
| 4250 sqdmlsl(vf_l, rd, rn, rm); |
| 4251 break; |
| 4252 case NEON_SQDMLSL2: |
| 4253 sqdmlsl2(vf_l, rd, rn, rm); |
| 4254 break; |
| 4255 case NEON_SQDMULL: |
| 4256 sqdmull(vf_l, rd, rn, rm); |
| 4257 break; |
| 4258 case NEON_SQDMULL2: |
| 4259 sqdmull2(vf_l, rd, rn, rm); |
| 4260 break; |
| 4261 case NEON_UADDW: |
| 4262 uaddw(vf_l, rd, rn, rm); |
| 4263 break; |
| 4264 case NEON_UADDW2: |
| 4265 uaddw2(vf_l, rd, rn, rm); |
| 4266 break; |
| 4267 case NEON_SADDW: |
| 4268 saddw(vf_l, rd, rn, rm); |
| 4269 break; |
| 4270 case NEON_SADDW2: |
| 4271 saddw2(vf_l, rd, rn, rm); |
| 4272 break; |
| 4273 case NEON_USUBW: |
| 4274 usubw(vf_l, rd, rn, rm); |
| 4275 break; |
| 4276 case NEON_USUBW2: |
| 4277 usubw2(vf_l, rd, rn, rm); |
| 4278 break; |
| 4279 case NEON_SSUBW: |
| 4280 ssubw(vf_l, rd, rn, rm); |
| 4281 break; |
| 4282 case NEON_SSUBW2: |
| 4283 ssubw2(vf_l, rd, rn, rm); |
| 4284 break; |
| 4285 case NEON_ADDHN: |
| 4286 addhn(vf, rd, rn, rm); |
| 4287 break; |
| 4288 case NEON_ADDHN2: |
| 4289 addhn2(vf, rd, rn, rm); |
| 4290 break; |
| 4291 case NEON_RADDHN: |
| 4292 raddhn(vf, rd, rn, rm); |
| 4293 break; |
| 4294 case NEON_RADDHN2: |
| 4295 raddhn2(vf, rd, rn, rm); |
| 4296 break; |
| 4297 case NEON_SUBHN: |
| 4298 subhn(vf, rd, rn, rm); |
| 4299 break; |
| 4300 case NEON_SUBHN2: |
| 4301 subhn2(vf, rd, rn, rm); |
| 4302 break; |
| 4303 case NEON_RSUBHN: |
| 4304 rsubhn(vf, rd, rn, rm); |
| 4305 break; |
| 4306 case NEON_RSUBHN2: |
| 4307 rsubhn2(vf, rd, rn, rm); |
| 4308 break; |
| 4309 default: |
| 4310 UNIMPLEMENTED(); |
| 4311 } |
| 4312 } |
| 4313 |
| 4314 void Simulator::VisitNEONAcrossLanes(Instruction* instr) { |
| 4315 NEONFormatDecoder nfd(instr); |
| 4316 |
| 4317 SimVRegister& rd = vreg(instr->Rd()); |
| 4318 SimVRegister& rn = vreg(instr->Rn()); |
| 4319 |
| 4320 // The input operand's VectorFormat is passed for these instructions. |
| 4321 if (instr->Mask(NEONAcrossLanesFPFMask) == NEONAcrossLanesFPFixed) { |
| 4322 VectorFormat vf = nfd.GetVectorFormat(nfd.FPFormatMap()); |
| 4323 |
| 4324 switch (instr->Mask(NEONAcrossLanesFPMask)) { |
| 4325 case NEON_FMAXV: |
| 4326 fmaxv(vf, rd, rn); |
| 4327 break; |
| 4328 case NEON_FMINV: |
| 4329 fminv(vf, rd, rn); |
| 4330 break; |
| 4331 case NEON_FMAXNMV: |
| 4332 fmaxnmv(vf, rd, rn); |
| 4333 break; |
| 4334 case NEON_FMINNMV: |
| 4335 fminnmv(vf, rd, rn); |
| 4336 break; |
| 4337 default: |
| 4338 UNIMPLEMENTED(); |
| 4339 } |
| 4340 } else { |
| 4341 VectorFormat vf = nfd.GetVectorFormat(); |
| 4342 |
| 4343 switch (instr->Mask(NEONAcrossLanesMask)) { |
| 4344 case NEON_ADDV: |
| 4345 addv(vf, rd, rn); |
| 4346 break; |
| 4347 case NEON_SMAXV: |
| 4348 smaxv(vf, rd, rn); |
| 4349 break; |
| 4350 case NEON_SMINV: |
| 4351 sminv(vf, rd, rn); |
| 4352 break; |
| 4353 case NEON_UMAXV: |
| 4354 umaxv(vf, rd, rn); |
| 4355 break; |
| 4356 case NEON_UMINV: |
| 4357 uminv(vf, rd, rn); |
| 4358 break; |
| 4359 case NEON_SADDLV: |
| 4360 saddlv(vf, rd, rn); |
| 4361 break; |
| 4362 case NEON_UADDLV: |
| 4363 uaddlv(vf, rd, rn); |
| 4364 break; |
| 4365 default: |
| 4366 UNIMPLEMENTED(); |
| 4367 } |
| 4368 } |
| 4369 } |
| 4370 |
| 4371 void Simulator::VisitNEONByIndexedElement(Instruction* instr) { |
| 4372 NEONFormatDecoder nfd(instr); |
| 4373 VectorFormat vf_r = nfd.GetVectorFormat(); |
| 4374 VectorFormat vf = nfd.GetVectorFormat(nfd.LongIntegerFormatMap()); |
| 4375 |
| 4376 SimVRegister& rd = vreg(instr->Rd()); |
| 4377 SimVRegister& rn = vreg(instr->Rn()); |
| 4378 |
| 4379 ByElementOp Op = NULL; |
| 4380 |
| 4381 int rm_reg = instr->Rm(); |
| 4382 int index = (instr->NEONH() << 1) | instr->NEONL(); |
| 4383 if (instr->NEONSize() == 1) { |
| 4384 rm_reg &= 0xf; |
| 4385 index = (index << 1) | instr->NEONM(); |
| 4386 } |
| 4387 |
| 4388 switch (instr->Mask(NEONByIndexedElementMask)) { |
| 4389 case NEON_MUL_byelement: |
| 4390 Op = &Simulator::mul; |
| 4391 vf = vf_r; |
| 4392 break; |
| 4393 case NEON_MLA_byelement: |
| 4394 Op = &Simulator::mla; |
| 4395 vf = vf_r; |
| 4396 break; |
| 4397 case NEON_MLS_byelement: |
| 4398 Op = &Simulator::mls; |
| 4399 vf = vf_r; |
| 4400 break; |
| 4401 case NEON_SQDMULH_byelement: |
| 4402 Op = &Simulator::sqdmulh; |
| 4403 vf = vf_r; |
| 4404 break; |
| 4405 case NEON_SQRDMULH_byelement: |
| 4406 Op = &Simulator::sqrdmulh; |
| 4407 vf = vf_r; |
| 4408 break; |
| 4409 case NEON_SMULL_byelement: |
| 4410 if (instr->Mask(NEON_Q)) { |
| 4411 Op = &Simulator::smull2; |
| 4412 } else { |
| 4413 Op = &Simulator::smull; |
| 4414 } |
| 4415 break; |
| 4416 case NEON_UMULL_byelement: |
| 4417 if (instr->Mask(NEON_Q)) { |
| 4418 Op = &Simulator::umull2; |
| 4419 } else { |
| 4420 Op = &Simulator::umull; |
| 4421 } |
| 4422 break; |
| 4423 case NEON_SMLAL_byelement: |
| 4424 if (instr->Mask(NEON_Q)) { |
| 4425 Op = &Simulator::smlal2; |
| 4426 } else { |
| 4427 Op = &Simulator::smlal; |
| 4428 } |
| 4429 break; |
| 4430 case NEON_UMLAL_byelement: |
| 4431 if (instr->Mask(NEON_Q)) { |
| 4432 Op = &Simulator::umlal2; |
| 4433 } else { |
| 4434 Op = &Simulator::umlal; |
| 4435 } |
| 4436 break; |
| 4437 case NEON_SMLSL_byelement: |
| 4438 if (instr->Mask(NEON_Q)) { |
| 4439 Op = &Simulator::smlsl2; |
| 4440 } else { |
| 4441 Op = &Simulator::smlsl; |
| 4442 } |
| 4443 break; |
| 4444 case NEON_UMLSL_byelement: |
| 4445 if (instr->Mask(NEON_Q)) { |
| 4446 Op = &Simulator::umlsl2; |
| 4447 } else { |
| 4448 Op = &Simulator::umlsl; |
| 4449 } |
| 4450 break; |
| 4451 case NEON_SQDMULL_byelement: |
| 4452 if (instr->Mask(NEON_Q)) { |
| 4453 Op = &Simulator::sqdmull2; |
| 4454 } else { |
| 4455 Op = &Simulator::sqdmull; |
| 4456 } |
| 4457 break; |
| 4458 case NEON_SQDMLAL_byelement: |
| 4459 if (instr->Mask(NEON_Q)) { |
| 4460 Op = &Simulator::sqdmlal2; |
| 4461 } else { |
| 4462 Op = &Simulator::sqdmlal; |
| 4463 } |
| 4464 break; |
| 4465 case NEON_SQDMLSL_byelement: |
| 4466 if (instr->Mask(NEON_Q)) { |
| 4467 Op = &Simulator::sqdmlsl2; |
| 4468 } else { |
| 4469 Op = &Simulator::sqdmlsl; |
| 4470 } |
| 4471 break; |
| 4472 default: |
| 4473 index = instr->NEONH(); |
| 4474 if ((instr->FPType() & 1) == 0) { |
| 4475 index = (index << 1) | instr->NEONL(); |
| 4476 } |
| 4477 |
| 4478 vf = nfd.GetVectorFormat(nfd.FPFormatMap()); |
| 4479 |
| 4480 switch (instr->Mask(NEONByIndexedElementFPMask)) { |
| 4481 case NEON_FMUL_byelement: |
| 4482 Op = &Simulator::fmul; |
| 4483 break; |
| 4484 case NEON_FMLA_byelement: |
| 4485 Op = &Simulator::fmla; |
| 4486 break; |
| 4487 case NEON_FMLS_byelement: |
| 4488 Op = &Simulator::fmls; |
| 4489 break; |
| 4490 case NEON_FMULX_byelement: |
| 4491 Op = &Simulator::fmulx; |
| 4492 break; |
| 4493 default: |
| 4494 UNIMPLEMENTED(); |
| 4495 } |
| 4496 } |
| 4497 |
| 4498 (this->*Op)(vf, rd, rn, vreg(rm_reg), index); |
| 4499 } |
| 4500 |
| 4501 void Simulator::VisitNEONCopy(Instruction* instr) { |
| 4502 NEONFormatDecoder nfd(instr, NEONFormatDecoder::TriangularFormatMap()); |
| 4503 VectorFormat vf = nfd.GetVectorFormat(); |
| 4504 |
| 4505 SimVRegister& rd = vreg(instr->Rd()); |
| 4506 SimVRegister& rn = vreg(instr->Rn()); |
| 4507 int imm5 = instr->ImmNEON5(); |
| 4508 int lsb = LowestSetBitPosition(imm5); |
| 4509 int reg_index = imm5 >> lsb; |
| 4510 |
| 4511 if (instr->Mask(NEONCopyInsElementMask) == NEON_INS_ELEMENT) { |
| 4512 int imm4 = instr->ImmNEON4(); |
| 4513 DCHECK_GE(lsb, 1); |
| 4514 int rn_index = imm4 >> (lsb - 1); |
| 4515 ins_element(vf, rd, reg_index, rn, rn_index); |
| 4516 } else if (instr->Mask(NEONCopyInsGeneralMask) == NEON_INS_GENERAL) { |
| 4517 ins_immediate(vf, rd, reg_index, xreg(instr->Rn())); |
| 4518 } else if (instr->Mask(NEONCopyUmovMask) == NEON_UMOV) { |
| 4519 uint64_t value = LogicVRegister(rn).Uint(vf, reg_index); |
| 4520 value &= MaxUintFromFormat(vf); |
| 4521 set_xreg(instr->Rd(), value); |
| 4522 } else if (instr->Mask(NEONCopyUmovMask) == NEON_SMOV) { |
| 4523 int64_t value = LogicVRegister(rn).Int(vf, reg_index); |
| 4524 if (instr->NEONQ()) { |
| 4525 set_xreg(instr->Rd(), value); |
| 4526 } else { |
| 4527 DCHECK(is_int32(value)); |
| 4528 set_wreg(instr->Rd(), static_cast<int32_t>(value)); |
| 4529 } |
| 4530 } else if (instr->Mask(NEONCopyDupElementMask) == NEON_DUP_ELEMENT) { |
| 4531 dup_element(vf, rd, rn, reg_index); |
| 4532 } else if (instr->Mask(NEONCopyDupGeneralMask) == NEON_DUP_GENERAL) { |
| 4533 dup_immediate(vf, rd, xreg(instr->Rn())); |
| 4534 } else { |
| 4535 UNIMPLEMENTED(); |
| 4536 } |
| 4537 } |
| 4538 |
| 4539 void Simulator::VisitNEONExtract(Instruction* instr) { |
| 4540 NEONFormatDecoder nfd(instr, NEONFormatDecoder::LogicalFormatMap()); |
| 4541 VectorFormat vf = nfd.GetVectorFormat(); |
| 4542 SimVRegister& rd = vreg(instr->Rd()); |
| 4543 SimVRegister& rn = vreg(instr->Rn()); |
| 4544 SimVRegister& rm = vreg(instr->Rm()); |
| 4545 if (instr->Mask(NEONExtractMask) == NEON_EXT) { |
| 4546 int index = instr->ImmNEONExt(); |
| 4547 ext(vf, rd, rn, rm, index); |
| 4548 } else { |
| 4549 UNIMPLEMENTED(); |
| 4550 } |
| 4551 } |
| 4552 |
| 4553 void Simulator::NEONLoadStoreMultiStructHelper(const Instruction* instr, |
| 4554 AddrMode addr_mode) { |
| 4555 NEONFormatDecoder nfd(instr, NEONFormatDecoder::LoadStoreFormatMap()); |
| 4556 VectorFormat vf = nfd.GetVectorFormat(); |
| 4557 |
| 4558 uint64_t addr_base = xreg(instr->Rn(), Reg31IsStackPointer); |
| 4559 int reg_size = RegisterSizeInBytesFromFormat(vf); |
| 4560 |
| 4561 int reg[4]; |
| 4562 uint64_t addr[4]; |
| 4563 for (int i = 0; i < 4; i++) { |
| 4564 reg[i] = (instr->Rt() + i) % kNumberOfVRegisters; |
| 4565 addr[i] = addr_base + (i * reg_size); |
| 4566 } |
| 4567 int count = 1; |
| 4568 bool log_read = true; |
| 4569 |
| 4570 // Bit 23 determines whether this is an offset or post-index addressing mode. |
| 4571 // In offset mode, bits 20 to 16 should be zero; these bits encode the |
| 4572 // register of immediate in post-index mode. |
| 4573 if ((instr->Bit(23) == 0) && (instr->Bits(20, 16) != 0)) { |
| 4574 UNREACHABLE(); |
| 4575 } |
| 4576 |
| 4577 // We use the PostIndex mask here, as it works in this case for both Offset |
| 4578 // and PostIndex addressing. |
| 4579 switch (instr->Mask(NEONLoadStoreMultiStructPostIndexMask)) { |
| 4580 case NEON_LD1_4v: |
| 4581 case NEON_LD1_4v_post: |
| 4582 ld1(vf, vreg(reg[3]), addr[3]); |
| 4583 count++; // Fall through. |
| 4584 case NEON_LD1_3v: |
| 4585 case NEON_LD1_3v_post: |
| 4586 ld1(vf, vreg(reg[2]), addr[2]); |
| 4587 count++; // Fall through. |
| 4588 case NEON_LD1_2v: |
| 4589 case NEON_LD1_2v_post: |
| 4590 ld1(vf, vreg(reg[1]), addr[1]); |
| 4591 count++; // Fall through. |
| 4592 case NEON_LD1_1v: |
| 4593 case NEON_LD1_1v_post: |
| 4594 ld1(vf, vreg(reg[0]), addr[0]); |
| 4595 break; |
| 4596 case NEON_ST1_4v: |
| 4597 case NEON_ST1_4v_post: |
| 4598 st1(vf, vreg(reg[3]), addr[3]); |
| 4599 count++; // Fall through. |
| 4600 case NEON_ST1_3v: |
| 4601 case NEON_ST1_3v_post: |
| 4602 st1(vf, vreg(reg[2]), addr[2]); |
| 4603 count++; // Fall through. |
| 4604 case NEON_ST1_2v: |
| 4605 case NEON_ST1_2v_post: |
| 4606 st1(vf, vreg(reg[1]), addr[1]); |
| 4607 count++; // Fall through. |
| 4608 case NEON_ST1_1v: |
| 4609 case NEON_ST1_1v_post: |
| 4610 st1(vf, vreg(reg[0]), addr[0]); |
| 4611 log_read = false; |
| 4612 break; |
| 4613 case NEON_LD2_post: |
| 4614 case NEON_LD2: |
| 4615 ld2(vf, vreg(reg[0]), vreg(reg[1]), addr[0]); |
| 4616 count = 2; |
| 4617 break; |
| 4618 case NEON_ST2: |
| 4619 case NEON_ST2_post: |
| 4620 st2(vf, vreg(reg[0]), vreg(reg[1]), addr[0]); |
| 4621 count = 2; |
| 4622 log_read = false; |
| 4623 break; |
| 4624 case NEON_LD3_post: |
| 4625 case NEON_LD3: |
| 4626 ld3(vf, vreg(reg[0]), vreg(reg[1]), vreg(reg[2]), addr[0]); |
| 4627 count = 3; |
| 4628 break; |
| 4629 case NEON_ST3: |
| 4630 case NEON_ST3_post: |
| 4631 st3(vf, vreg(reg[0]), vreg(reg[1]), vreg(reg[2]), addr[0]); |
| 4632 count = 3; |
| 4633 log_read = false; |
| 4634 break; |
| 4635 case NEON_LD4_post: |
| 4636 case NEON_LD4: |
| 4637 ld4(vf, vreg(reg[0]), vreg(reg[1]), vreg(reg[2]), vreg(reg[3]), addr[0]); |
| 4638 count = 4; |
| 4639 break; |
| 4640 case NEON_ST4: |
| 4641 case NEON_ST4_post: |
| 4642 st4(vf, vreg(reg[0]), vreg(reg[1]), vreg(reg[2]), vreg(reg[3]), addr[0]); |
| 4643 count = 4; |
| 4644 log_read = false; |
| 4645 break; |
| 4646 default: |
| 4647 UNIMPLEMENTED(); |
| 4648 } |
| 4649 |
| 4650 // Explicitly log the register update whilst we have type information. |
| 4651 for (int i = 0; i < count; i++) { |
| 4652 // For de-interleaving loads, only print the base address. |
| 4653 int lane_size = LaneSizeInBytesFromFormat(vf); |
| 4654 PrintRegisterFormat format = GetPrintRegisterFormatTryFP( |
| 4655 GetPrintRegisterFormatForSize(reg_size, lane_size)); |
| 4656 if (log_read) { |
| 4657 LogVRead(addr_base, reg[i], format); |
| 4658 } else { |
| 4659 LogVWrite(addr_base, reg[i], format); |
| 4660 } |
| 4661 } |
| 4662 |
| 4663 if (addr_mode == PostIndex) { |
| 4664 int rm = instr->Rm(); |
| 4665 // The immediate post index addressing mode is indicated by rm = 31. |
| 4666 // The immediate is implied by the number of vector registers used. |
| 4667 addr_base += |
| 4668 (rm == 31) ? RegisterSizeInBytesFromFormat(vf) * count : xreg(rm); |
| 4669 set_xreg(instr->Rn(), addr_base); |
| 4670 } else { |
| 4671 DCHECK_EQ(addr_mode, Offset); |
| 4672 } |
| 4673 } |
| 4674 |
| 4675 void Simulator::VisitNEONLoadStoreMultiStruct(Instruction* instr) { |
| 4676 NEONLoadStoreMultiStructHelper(instr, Offset); |
| 4677 } |
| 4678 |
| 4679 void Simulator::VisitNEONLoadStoreMultiStructPostIndex(Instruction* instr) { |
| 4680 NEONLoadStoreMultiStructHelper(instr, PostIndex); |
| 4681 } |
| 4682 |
| 4683 void Simulator::NEONLoadStoreSingleStructHelper(const Instruction* instr, |
| 4684 AddrMode addr_mode) { |
| 4685 uint64_t addr = xreg(instr->Rn(), Reg31IsStackPointer); |
| 4686 int rt = instr->Rt(); |
| 4687 |
| 4688 // Bit 23 determines whether this is an offset or post-index addressing mode. |
| 4689 // In offset mode, bits 20 to 16 should be zero; these bits encode the |
| 4690 // register of immediate in post-index mode. |
| 4691 DCHECK_IMPLIES(instr->Bit(23) == 0, instr->Bits(20, 16) == 0); |
| 4692 |
| 4693 bool do_load = false; |
| 4694 |
| 4695 NEONFormatDecoder nfd(instr, NEONFormatDecoder::LoadStoreFormatMap()); |
| 4696 VectorFormat vf_t = nfd.GetVectorFormat(); |
| 4697 |
| 4698 VectorFormat vf = kFormat16B; |
| 4699 // We use the PostIndex mask here, as it works in this case for both Offset |
| 4700 // and PostIndex addressing. |
| 4701 switch (instr->Mask(NEONLoadStoreSingleStructPostIndexMask)) { |
| 4702 case NEON_LD1_b: |
| 4703 case NEON_LD1_b_post: |
| 4704 case NEON_LD2_b: |
| 4705 case NEON_LD2_b_post: |
| 4706 case NEON_LD3_b: |
| 4707 case NEON_LD3_b_post: |
| 4708 case NEON_LD4_b: |
| 4709 case NEON_LD4_b_post: |
| 4710 do_load = true; // Fall through. |
| 4711 case NEON_ST1_b: |
| 4712 case NEON_ST1_b_post: |
| 4713 case NEON_ST2_b: |
| 4714 case NEON_ST2_b_post: |
| 4715 case NEON_ST3_b: |
| 4716 case NEON_ST3_b_post: |
| 4717 case NEON_ST4_b: |
| 4718 case NEON_ST4_b_post: |
| 4719 break; |
| 4720 |
| 4721 case NEON_LD1_h: |
| 4722 case NEON_LD1_h_post: |
| 4723 case NEON_LD2_h: |
| 4724 case NEON_LD2_h_post: |
| 4725 case NEON_LD3_h: |
| 4726 case NEON_LD3_h_post: |
| 4727 case NEON_LD4_h: |
| 4728 case NEON_LD4_h_post: |
| 4729 do_load = true; // Fall through. |
| 4730 case NEON_ST1_h: |
| 4731 case NEON_ST1_h_post: |
| 4732 case NEON_ST2_h: |
| 4733 case NEON_ST2_h_post: |
| 4734 case NEON_ST3_h: |
| 4735 case NEON_ST3_h_post: |
| 4736 case NEON_ST4_h: |
| 4737 case NEON_ST4_h_post: |
| 4738 vf = kFormat8H; |
| 4739 break; |
| 4740 |
| 4741 case NEON_LD1_s: |
| 4742 case NEON_LD1_s_post: |
| 4743 case NEON_LD2_s: |
| 4744 case NEON_LD2_s_post: |
| 4745 case NEON_LD3_s: |
| 4746 case NEON_LD3_s_post: |
| 4747 case NEON_LD4_s: |
| 4748 case NEON_LD4_s_post: |
| 4749 do_load = true; // Fall through. |
| 4750 case NEON_ST1_s: |
| 4751 case NEON_ST1_s_post: |
| 4752 case NEON_ST2_s: |
| 4753 case NEON_ST2_s_post: |
| 4754 case NEON_ST3_s: |
| 4755 case NEON_ST3_s_post: |
| 4756 case NEON_ST4_s: |
| 4757 case NEON_ST4_s_post: { |
| 4758 static_assert((NEON_LD1_s | (1 << NEONLSSize_offset)) == NEON_LD1_d, |
| 4759 "LSB of size distinguishes S and D registers."); |
| 4760 static_assert( |
| 4761 (NEON_LD1_s_post | (1 << NEONLSSize_offset)) == NEON_LD1_d_post, |
| 4762 "LSB of size distinguishes S and D registers."); |
| 4763 static_assert((NEON_ST1_s | (1 << NEONLSSize_offset)) == NEON_ST1_d, |
| 4764 "LSB of size distinguishes S and D registers."); |
| 4765 static_assert( |
| 4766 (NEON_ST1_s_post | (1 << NEONLSSize_offset)) == NEON_ST1_d_post, |
| 4767 "LSB of size distinguishes S and D registers."); |
| 4768 vf = ((instr->NEONLSSize() & 1) == 0) ? kFormat4S : kFormat2D; |
| 4769 break; |
| 4770 } |
| 4771 |
| 4772 case NEON_LD1R: |
| 4773 case NEON_LD1R_post: { |
| 4774 vf = vf_t; |
| 4775 ld1r(vf, vreg(rt), addr); |
| 4776 do_load = true; |
| 4777 break; |
| 4778 } |
| 4779 |
| 4780 case NEON_LD2R: |
| 4781 case NEON_LD2R_post: { |
| 4782 vf = vf_t; |
| 4783 int rt2 = (rt + 1) % kNumberOfVRegisters; |
| 4784 ld2r(vf, vreg(rt), vreg(rt2), addr); |
| 4785 do_load = true; |
| 4786 break; |
| 4787 } |
| 4788 |
| 4789 case NEON_LD3R: |
| 4790 case NEON_LD3R_post: { |
| 4791 vf = vf_t; |
| 4792 int rt2 = (rt + 1) % kNumberOfVRegisters; |
| 4793 int rt3 = (rt2 + 1) % kNumberOfVRegisters; |
| 4794 ld3r(vf, vreg(rt), vreg(rt2), vreg(rt3), addr); |
| 4795 do_load = true; |
| 4796 break; |
| 4797 } |
| 4798 |
| 4799 case NEON_LD4R: |
| 4800 case NEON_LD4R_post: { |
| 4801 vf = vf_t; |
| 4802 int rt2 = (rt + 1) % kNumberOfVRegisters; |
| 4803 int rt3 = (rt2 + 1) % kNumberOfVRegisters; |
| 4804 int rt4 = (rt3 + 1) % kNumberOfVRegisters; |
| 4805 ld4r(vf, vreg(rt), vreg(rt2), vreg(rt3), vreg(rt4), addr); |
| 4806 do_load = true; |
| 4807 break; |
| 4808 } |
| 4809 default: |
| 4810 UNIMPLEMENTED(); |
| 4811 } |
| 4812 |
| 4813 PrintRegisterFormat print_format = |
| 4814 GetPrintRegisterFormatTryFP(GetPrintRegisterFormat(vf)); |
| 4815 // Make sure that the print_format only includes a single lane. |
| 4816 print_format = |
| 4817 static_cast<PrintRegisterFormat>(print_format & ~kPrintRegAsVectorMask); |
| 4818 |
| 4819 int esize = LaneSizeInBytesFromFormat(vf); |
| 4820 int index_shift = LaneSizeInBytesLog2FromFormat(vf); |
| 4821 int lane = instr->NEONLSIndex(index_shift); |
| 4822 int scale = 0; |
| 4823 int rt2 = (rt + 1) % kNumberOfVRegisters; |
| 4824 int rt3 = (rt2 + 1) % kNumberOfVRegisters; |
| 4825 int rt4 = (rt3 + 1) % kNumberOfVRegisters; |
| 4826 switch (instr->Mask(NEONLoadStoreSingleLenMask)) { |
| 4827 case NEONLoadStoreSingle1: |
| 4828 scale = 1; |
| 4829 if (do_load) { |
| 4830 ld1(vf, vreg(rt), lane, addr); |
| 4831 LogVRead(addr, rt, print_format, lane); |
| 4832 } else { |
| 4833 st1(vf, vreg(rt), lane, addr); |
| 4834 LogVWrite(addr, rt, print_format, lane); |
| 4835 } |
| 4836 break; |
| 4837 case NEONLoadStoreSingle2: |
| 4838 scale = 2; |
| 4839 if (do_load) { |
| 4840 ld2(vf, vreg(rt), vreg(rt2), lane, addr); |
| 4841 LogVRead(addr, rt, print_format, lane); |
| 4842 LogVRead(addr + esize, rt2, print_format, lane); |
| 4843 } else { |
| 4844 st2(vf, vreg(rt), vreg(rt2), lane, addr); |
| 4845 LogVWrite(addr, rt, print_format, lane); |
| 4846 LogVWrite(addr + esize, rt2, print_format, lane); |
| 4847 } |
| 4848 break; |
| 4849 case NEONLoadStoreSingle3: |
| 4850 scale = 3; |
| 4851 if (do_load) { |
| 4852 ld3(vf, vreg(rt), vreg(rt2), vreg(rt3), lane, addr); |
| 4853 LogVRead(addr, rt, print_format, lane); |
| 4854 LogVRead(addr + esize, rt2, print_format, lane); |
| 4855 LogVRead(addr + (2 * esize), rt3, print_format, lane); |
| 4856 } else { |
| 4857 st3(vf, vreg(rt), vreg(rt2), vreg(rt3), lane, addr); |
| 4858 LogVWrite(addr, rt, print_format, lane); |
| 4859 LogVWrite(addr + esize, rt2, print_format, lane); |
| 4860 LogVWrite(addr + (2 * esize), rt3, print_format, lane); |
| 4861 } |
| 4862 break; |
| 4863 case NEONLoadStoreSingle4: |
| 4864 scale = 4; |
| 4865 if (do_load) { |
| 4866 ld4(vf, vreg(rt), vreg(rt2), vreg(rt3), vreg(rt4), lane, addr); |
| 4867 LogVRead(addr, rt, print_format, lane); |
| 4868 LogVRead(addr + esize, rt2, print_format, lane); |
| 4869 LogVRead(addr + (2 * esize), rt3, print_format, lane); |
| 4870 LogVRead(addr + (3 * esize), rt4, print_format, lane); |
| 4871 } else { |
| 4872 st4(vf, vreg(rt), vreg(rt2), vreg(rt3), vreg(rt4), lane, addr); |
| 4873 LogVWrite(addr, rt, print_format, lane); |
| 4874 LogVWrite(addr + esize, rt2, print_format, lane); |
| 4875 LogVWrite(addr + (2 * esize), rt3, print_format, lane); |
| 4876 LogVWrite(addr + (3 * esize), rt4, print_format, lane); |
| 4877 } |
| 4878 break; |
| 4879 default: |
| 4880 UNIMPLEMENTED(); |
| 4881 } |
| 4882 |
| 4883 if (addr_mode == PostIndex) { |
| 4884 int rm = instr->Rm(); |
| 4885 int lane_size = LaneSizeInBytesFromFormat(vf); |
| 4886 set_xreg(instr->Rn(), addr + ((rm == 31) ? (scale * lane_size) : xreg(rm))); |
| 4887 } |
| 4888 } |
| 4889 |
| 4890 void Simulator::VisitNEONLoadStoreSingleStruct(Instruction* instr) { |
| 4891 NEONLoadStoreSingleStructHelper(instr, Offset); |
| 4892 } |
| 4893 |
| 4894 void Simulator::VisitNEONLoadStoreSingleStructPostIndex(Instruction* instr) { |
| 4895 NEONLoadStoreSingleStructHelper(instr, PostIndex); |
| 4896 } |
| 4897 |
| 4898 void Simulator::VisitNEONModifiedImmediate(Instruction* instr) { |
| 4899 SimVRegister& rd = vreg(instr->Rd()); |
| 4900 int cmode = instr->NEONCmode(); |
| 4901 int cmode_3_1 = (cmode >> 1) & 7; |
| 4902 int cmode_3 = (cmode >> 3) & 1; |
| 4903 int cmode_2 = (cmode >> 2) & 1; |
| 4904 int cmode_1 = (cmode >> 1) & 1; |
| 4905 int cmode_0 = cmode & 1; |
| 4906 int q = instr->NEONQ(); |
| 4907 int op_bit = instr->NEONModImmOp(); |
| 4908 uint64_t imm8 = instr->ImmNEONabcdefgh(); |
| 4909 |
| 4910 // Find the format and immediate value |
| 4911 uint64_t imm = 0; |
| 4912 VectorFormat vform = kFormatUndefined; |
| 4913 switch (cmode_3_1) { |
| 4914 case 0x0: |
| 4915 case 0x1: |
| 4916 case 0x2: |
| 4917 case 0x3: |
| 4918 vform = (q == 1) ? kFormat4S : kFormat2S; |
| 4919 imm = imm8 << (8 * cmode_3_1); |
| 4920 break; |
| 4921 case 0x4: |
| 4922 case 0x5: |
| 4923 vform = (q == 1) ? kFormat8H : kFormat4H; |
| 4924 imm = imm8 << (8 * cmode_1); |
| 4925 break; |
| 4926 case 0x6: |
| 4927 vform = (q == 1) ? kFormat4S : kFormat2S; |
| 4928 if (cmode_0 == 0) { |
| 4929 imm = imm8 << 8 | 0x000000ff; |
| 4930 } else { |
| 4931 imm = imm8 << 16 | 0x0000ffff; |
| 4932 } |
| 4933 break; |
| 4934 case 0x7: |
| 4935 if (cmode_0 == 0 && op_bit == 0) { |
| 4936 vform = q ? kFormat16B : kFormat8B; |
| 4937 imm = imm8; |
| 4938 } else if (cmode_0 == 0 && op_bit == 1) { |
| 4939 vform = q ? kFormat2D : kFormat1D; |
| 4940 imm = 0; |
| 4941 for (int i = 0; i < 8; ++i) { |
| 4942 if (imm8 & (1 << i)) { |
| 4943 imm |= (UINT64_C(0xff) << (8 * i)); |
| 4944 } |
| 4945 } |
| 4946 } else { // cmode_0 == 1, cmode == 0xf. |
| 4947 if (op_bit == 0) { |
| 4948 vform = q ? kFormat4S : kFormat2S; |
| 4949 imm = bit_cast<uint32_t>(instr->ImmNEONFP32()); |
| 4950 } else if (q == 1) { |
| 4951 vform = kFormat2D; |
| 4952 imm = bit_cast<uint64_t>(instr->ImmNEONFP64()); |
| 4953 } else { |
| 4954 DCHECK((q == 0) && (op_bit == 1) && (cmode == 0xf)); |
| 4955 VisitUnallocated(instr); |
| 4956 } |
| 4957 } |
| 4958 break; |
| 4959 default: |
| 4960 UNREACHABLE(); |
| 4961 } |
| 4962 |
| 4963 // Find the operation. |
| 4964 NEONModifiedImmediateOp op; |
| 4965 if (cmode_3 == 0) { |
| 4966 if (cmode_0 == 0) { |
| 4967 op = op_bit ? NEONModifiedImmediate_MVNI : NEONModifiedImmediate_MOVI; |
| 4968 } else { // cmode<0> == '1' |
| 4969 op = op_bit ? NEONModifiedImmediate_BIC : NEONModifiedImmediate_ORR; |
| 4970 } |
| 4971 } else { // cmode<3> == '1' |
| 4972 if (cmode_2 == 0) { |
| 4973 if (cmode_0 == 0) { |
| 4974 op = op_bit ? NEONModifiedImmediate_MVNI : NEONModifiedImmediate_MOVI; |
| 4975 } else { // cmode<0> == '1' |
| 4976 op = op_bit ? NEONModifiedImmediate_BIC : NEONModifiedImmediate_ORR; |
| 4977 } |
| 4978 } else { // cmode<2> == '1' |
| 4979 if (cmode_1 == 0) { |
| 4980 op = op_bit ? NEONModifiedImmediate_MVNI : NEONModifiedImmediate_MOVI; |
| 4981 } else { // cmode<1> == '1' |
| 4982 if (cmode_0 == 0) { |
| 4983 op = NEONModifiedImmediate_MOVI; |
| 4984 } else { // cmode<0> == '1' |
| 4985 op = NEONModifiedImmediate_MOVI; |
| 4986 } |
| 4987 } |
| 4988 } |
| 4989 } |
| 4990 |
| 4991 // Call the logic function. |
| 4992 switch (op) { |
| 4993 case NEONModifiedImmediate_ORR: |
| 4994 orr(vform, rd, rd, imm); |
| 4995 break; |
| 4996 case NEONModifiedImmediate_BIC: |
| 4997 bic(vform, rd, rd, imm); |
| 4998 break; |
| 4999 case NEONModifiedImmediate_MOVI: |
| 5000 movi(vform, rd, imm); |
| 5001 break; |
| 5002 case NEONModifiedImmediate_MVNI: |
| 5003 mvni(vform, rd, imm); |
| 5004 break; |
| 5005 default: |
| 5006 VisitUnimplemented(instr); |
| 5007 } |
| 5008 } |
| 5009 |
| 5010 void Simulator::VisitNEONScalar2RegMisc(Instruction* instr) { |
| 5011 NEONFormatDecoder nfd(instr, NEONFormatDecoder::ScalarFormatMap()); |
| 5012 VectorFormat vf = nfd.GetVectorFormat(); |
| 5013 |
| 5014 SimVRegister& rd = vreg(instr->Rd()); |
| 5015 SimVRegister& rn = vreg(instr->Rn()); |
| 5016 |
| 5017 if (instr->Mask(NEON2RegMiscOpcode) <= NEON_NEG_scalar_opcode) { |
| 5018 // These instructions all use a two bit size field, except NOT and RBIT, |
| 5019 // which use the field to encode the operation. |
| 5020 switch (instr->Mask(NEONScalar2RegMiscMask)) { |
| 5021 case NEON_CMEQ_zero_scalar: |
| 5022 cmp(vf, rd, rn, 0, eq); |
| 5023 break; |
| 5024 case NEON_CMGE_zero_scalar: |
| 5025 cmp(vf, rd, rn, 0, ge); |
| 5026 break; |
| 5027 case NEON_CMGT_zero_scalar: |
| 5028 cmp(vf, rd, rn, 0, gt); |
| 5029 break; |
| 5030 case NEON_CMLT_zero_scalar: |
| 5031 cmp(vf, rd, rn, 0, lt); |
| 5032 break; |
| 5033 case NEON_CMLE_zero_scalar: |
| 5034 cmp(vf, rd, rn, 0, le); |
| 5035 break; |
| 5036 case NEON_ABS_scalar: |
| 5037 abs(vf, rd, rn); |
| 5038 break; |
| 5039 case NEON_SQABS_scalar: |
| 5040 abs(vf, rd, rn).SignedSaturate(vf); |
| 5041 break; |
| 5042 case NEON_NEG_scalar: |
| 5043 neg(vf, rd, rn); |
| 5044 break; |
| 5045 case NEON_SQNEG_scalar: |
| 5046 neg(vf, rd, rn).SignedSaturate(vf); |
| 5047 break; |
| 5048 case NEON_SUQADD_scalar: |
| 5049 suqadd(vf, rd, rn); |
| 5050 break; |
| 5051 case NEON_USQADD_scalar: |
| 5052 usqadd(vf, rd, rn); |
| 5053 break; |
| 5054 default: |
| 5055 UNIMPLEMENTED(); |
| 5056 break; |
| 5057 } |
| 5058 } else { |
| 5059 VectorFormat fpf = nfd.GetVectorFormat(nfd.FPScalarFormatMap()); |
| 5060 FPRounding fpcr_rounding = static_cast<FPRounding>(fpcr().RMode()); |
| 5061 |
| 5062 // These instructions all use a one bit size field, except SQXTUN, SQXTN |
| 5063 // and UQXTN, which use a two bit size field. |
| 5064 switch (instr->Mask(NEONScalar2RegMiscFPMask)) { |
| 5065 case NEON_FRECPE_scalar: |
| 5066 frecpe(fpf, rd, rn, fpcr_rounding); |
| 5067 break; |
| 5068 case NEON_FRECPX_scalar: |
| 5069 frecpx(fpf, rd, rn); |
| 5070 break; |
| 5071 case NEON_FRSQRTE_scalar: |
| 5072 frsqrte(fpf, rd, rn); |
| 5073 break; |
| 5074 case NEON_FCMGT_zero_scalar: |
| 5075 fcmp_zero(fpf, rd, rn, gt); |
| 5076 break; |
| 5077 case NEON_FCMGE_zero_scalar: |
| 5078 fcmp_zero(fpf, rd, rn, ge); |
| 5079 break; |
| 5080 case NEON_FCMEQ_zero_scalar: |
| 5081 fcmp_zero(fpf, rd, rn, eq); |
| 5082 break; |
| 5083 case NEON_FCMLE_zero_scalar: |
| 5084 fcmp_zero(fpf, rd, rn, le); |
| 5085 break; |
| 5086 case NEON_FCMLT_zero_scalar: |
| 5087 fcmp_zero(fpf, rd, rn, lt); |
| 5088 break; |
| 5089 case NEON_SCVTF_scalar: |
| 5090 scvtf(fpf, rd, rn, 0, fpcr_rounding); |
| 5091 break; |
| 5092 case NEON_UCVTF_scalar: |
| 5093 ucvtf(fpf, rd, rn, 0, fpcr_rounding); |
| 5094 break; |
| 5095 case NEON_FCVTNS_scalar: |
| 5096 fcvts(fpf, rd, rn, FPTieEven); |
| 5097 break; |
| 5098 case NEON_FCVTNU_scalar: |
| 5099 fcvtu(fpf, rd, rn, FPTieEven); |
| 5100 break; |
| 5101 case NEON_FCVTPS_scalar: |
| 5102 fcvts(fpf, rd, rn, FPPositiveInfinity); |
| 5103 break; |
| 5104 case NEON_FCVTPU_scalar: |
| 5105 fcvtu(fpf, rd, rn, FPPositiveInfinity); |
| 5106 break; |
| 5107 case NEON_FCVTMS_scalar: |
| 5108 fcvts(fpf, rd, rn, FPNegativeInfinity); |
| 5109 break; |
| 5110 case NEON_FCVTMU_scalar: |
| 5111 fcvtu(fpf, rd, rn, FPNegativeInfinity); |
| 5112 break; |
| 5113 case NEON_FCVTZS_scalar: |
| 5114 fcvts(fpf, rd, rn, FPZero); |
| 5115 break; |
| 5116 case NEON_FCVTZU_scalar: |
| 5117 fcvtu(fpf, rd, rn, FPZero); |
| 5118 break; |
| 5119 case NEON_FCVTAS_scalar: |
| 5120 fcvts(fpf, rd, rn, FPTieAway); |
| 5121 break; |
| 5122 case NEON_FCVTAU_scalar: |
| 5123 fcvtu(fpf, rd, rn, FPTieAway); |
| 5124 break; |
| 5125 case NEON_FCVTXN_scalar: |
| 5126 // Unlike all of the other FP instructions above, fcvtxn encodes dest |
| 5127 // size S as size<0>=1. There's only one case, so we ignore the form. |
| 5128 DCHECK_EQ(instr->Bit(22), 1); |
| 5129 fcvtxn(kFormatS, rd, rn); |
| 5130 break; |
| 5131 default: |
| 5132 switch (instr->Mask(NEONScalar2RegMiscMask)) { |
| 5133 case NEON_SQXTN_scalar: |
| 5134 sqxtn(vf, rd, rn); |
| 5135 break; |
| 5136 case NEON_UQXTN_scalar: |
| 5137 uqxtn(vf, rd, rn); |
| 5138 break; |
| 5139 case NEON_SQXTUN_scalar: |
| 5140 sqxtun(vf, rd, rn); |
| 5141 break; |
| 5142 default: |
| 5143 UNIMPLEMENTED(); |
| 5144 } |
| 5145 } |
| 5146 } |
| 5147 } |
| 5148 |
| 5149 void Simulator::VisitNEONScalar3Diff(Instruction* instr) { |
| 5150 NEONFormatDecoder nfd(instr, NEONFormatDecoder::LongScalarFormatMap()); |
| 5151 VectorFormat vf = nfd.GetVectorFormat(); |
| 5152 |
| 5153 SimVRegister& rd = vreg(instr->Rd()); |
| 5154 SimVRegister& rn = vreg(instr->Rn()); |
| 5155 SimVRegister& rm = vreg(instr->Rm()); |
| 5156 switch (instr->Mask(NEONScalar3DiffMask)) { |
| 5157 case NEON_SQDMLAL_scalar: |
| 5158 sqdmlal(vf, rd, rn, rm); |
| 5159 break; |
| 5160 case NEON_SQDMLSL_scalar: |
| 5161 sqdmlsl(vf, rd, rn, rm); |
| 5162 break; |
| 5163 case NEON_SQDMULL_scalar: |
| 5164 sqdmull(vf, rd, rn, rm); |
| 5165 break; |
| 5166 default: |
| 5167 UNIMPLEMENTED(); |
| 5168 } |
| 5169 } |
| 5170 |
| 5171 void Simulator::VisitNEONScalar3Same(Instruction* instr) { |
| 5172 NEONFormatDecoder nfd(instr, NEONFormatDecoder::ScalarFormatMap()); |
| 5173 VectorFormat vf = nfd.GetVectorFormat(); |
| 5174 |
| 5175 SimVRegister& rd = vreg(instr->Rd()); |
| 5176 SimVRegister& rn = vreg(instr->Rn()); |
| 5177 SimVRegister& rm = vreg(instr->Rm()); |
| 5178 |
| 5179 if (instr->Mask(NEONScalar3SameFPFMask) == NEONScalar3SameFPFixed) { |
| 5180 vf = nfd.GetVectorFormat(nfd.FPScalarFormatMap()); |
| 5181 switch (instr->Mask(NEONScalar3SameFPMask)) { |
| 5182 case NEON_FMULX_scalar: |
| 5183 fmulx(vf, rd, rn, rm); |
| 5184 break; |
| 5185 case NEON_FACGE_scalar: |
| 5186 fabscmp(vf, rd, rn, rm, ge); |
| 5187 break; |
| 5188 case NEON_FACGT_scalar: |
| 5189 fabscmp(vf, rd, rn, rm, gt); |
| 5190 break; |
| 5191 case NEON_FCMEQ_scalar: |
| 5192 fcmp(vf, rd, rn, rm, eq); |
| 5193 break; |
| 5194 case NEON_FCMGE_scalar: |
| 5195 fcmp(vf, rd, rn, rm, ge); |
| 5196 break; |
| 5197 case NEON_FCMGT_scalar: |
| 5198 fcmp(vf, rd, rn, rm, gt); |
| 5199 break; |
| 5200 case NEON_FRECPS_scalar: |
| 5201 frecps(vf, rd, rn, rm); |
| 5202 break; |
| 5203 case NEON_FRSQRTS_scalar: |
| 5204 frsqrts(vf, rd, rn, rm); |
| 5205 break; |
| 5206 case NEON_FABD_scalar: |
| 5207 fabd(vf, rd, rn, rm); |
| 5208 break; |
| 5209 default: |
| 5210 UNIMPLEMENTED(); |
| 5211 } |
| 5212 } else { |
| 5213 switch (instr->Mask(NEONScalar3SameMask)) { |
| 5214 case NEON_ADD_scalar: |
| 5215 add(vf, rd, rn, rm); |
| 5216 break; |
| 5217 case NEON_SUB_scalar: |
| 5218 sub(vf, rd, rn, rm); |
| 5219 break; |
| 5220 case NEON_CMEQ_scalar: |
| 5221 cmp(vf, rd, rn, rm, eq); |
| 5222 break; |
| 5223 case NEON_CMGE_scalar: |
| 5224 cmp(vf, rd, rn, rm, ge); |
| 5225 break; |
| 5226 case NEON_CMGT_scalar: |
| 5227 cmp(vf, rd, rn, rm, gt); |
| 5228 break; |
| 5229 case NEON_CMHI_scalar: |
| 5230 cmp(vf, rd, rn, rm, hi); |
| 5231 break; |
| 5232 case NEON_CMHS_scalar: |
| 5233 cmp(vf, rd, rn, rm, hs); |
| 5234 break; |
| 5235 case NEON_CMTST_scalar: |
| 5236 cmptst(vf, rd, rn, rm); |
| 5237 break; |
| 5238 case NEON_USHL_scalar: |
| 5239 ushl(vf, rd, rn, rm); |
| 5240 break; |
| 5241 case NEON_SSHL_scalar: |
| 5242 sshl(vf, rd, rn, rm); |
| 5243 break; |
| 5244 case NEON_SQDMULH_scalar: |
| 5245 sqdmulh(vf, rd, rn, rm); |
| 5246 break; |
| 5247 case NEON_SQRDMULH_scalar: |
| 5248 sqrdmulh(vf, rd, rn, rm); |
| 5249 break; |
| 5250 case NEON_UQADD_scalar: |
| 5251 add(vf, rd, rn, rm).UnsignedSaturate(vf); |
| 5252 break; |
| 5253 case NEON_SQADD_scalar: |
| 5254 add(vf, rd, rn, rm).SignedSaturate(vf); |
| 5255 break; |
| 5256 case NEON_UQSUB_scalar: |
| 5257 sub(vf, rd, rn, rm).UnsignedSaturate(vf); |
| 5258 break; |
| 5259 case NEON_SQSUB_scalar: |
| 5260 sub(vf, rd, rn, rm).SignedSaturate(vf); |
| 5261 break; |
| 5262 case NEON_UQSHL_scalar: |
| 5263 ushl(vf, rd, rn, rm).UnsignedSaturate(vf); |
| 5264 break; |
| 5265 case NEON_SQSHL_scalar: |
| 5266 sshl(vf, rd, rn, rm).SignedSaturate(vf); |
| 5267 break; |
| 5268 case NEON_URSHL_scalar: |
| 5269 ushl(vf, rd, rn, rm).Round(vf); |
| 5270 break; |
| 5271 case NEON_SRSHL_scalar: |
| 5272 sshl(vf, rd, rn, rm).Round(vf); |
| 5273 break; |
| 5274 case NEON_UQRSHL_scalar: |
| 5275 ushl(vf, rd, rn, rm).Round(vf).UnsignedSaturate(vf); |
| 5276 break; |
| 5277 case NEON_SQRSHL_scalar: |
| 5278 sshl(vf, rd, rn, rm).Round(vf).SignedSaturate(vf); |
| 5279 break; |
| 5280 default: |
| 5281 UNIMPLEMENTED(); |
| 5282 } |
| 5283 } |
| 5284 } |
| 5285 |
| 5286 void Simulator::VisitNEONScalarByIndexedElement(Instruction* instr) { |
| 5287 NEONFormatDecoder nfd(instr, NEONFormatDecoder::LongScalarFormatMap()); |
| 5288 VectorFormat vf = nfd.GetVectorFormat(); |
| 5289 VectorFormat vf_r = nfd.GetVectorFormat(nfd.ScalarFormatMap()); |
| 5290 |
| 5291 SimVRegister& rd = vreg(instr->Rd()); |
| 5292 SimVRegister& rn = vreg(instr->Rn()); |
| 5293 ByElementOp Op = NULL; |
| 5294 |
| 5295 int rm_reg = instr->Rm(); |
| 5296 int index = (instr->NEONH() << 1) | instr->NEONL(); |
| 5297 if (instr->NEONSize() == 1) { |
| 5298 rm_reg &= 0xf; |
| 5299 index = (index << 1) | instr->NEONM(); |
| 5300 } |
| 5301 |
| 5302 switch (instr->Mask(NEONScalarByIndexedElementMask)) { |
| 5303 case NEON_SQDMULL_byelement_scalar: |
| 5304 Op = &Simulator::sqdmull; |
| 5305 break; |
| 5306 case NEON_SQDMLAL_byelement_scalar: |
| 5307 Op = &Simulator::sqdmlal; |
| 5308 break; |
| 5309 case NEON_SQDMLSL_byelement_scalar: |
| 5310 Op = &Simulator::sqdmlsl; |
| 5311 break; |
| 5312 case NEON_SQDMULH_byelement_scalar: |
| 5313 Op = &Simulator::sqdmulh; |
| 5314 vf = vf_r; |
| 5315 break; |
| 5316 case NEON_SQRDMULH_byelement_scalar: |
| 5317 Op = &Simulator::sqrdmulh; |
| 5318 vf = vf_r; |
| 5319 break; |
| 5320 default: |
| 5321 vf = nfd.GetVectorFormat(nfd.FPScalarFormatMap()); |
| 5322 index = instr->NEONH(); |
| 5323 if ((instr->FPType() & 1) == 0) { |
| 5324 index = (index << 1) | instr->NEONL(); |
| 5325 } |
| 5326 switch (instr->Mask(NEONScalarByIndexedElementFPMask)) { |
| 5327 case NEON_FMUL_byelement_scalar: |
| 5328 Op = &Simulator::fmul; |
| 5329 break; |
| 5330 case NEON_FMLA_byelement_scalar: |
| 5331 Op = &Simulator::fmla; |
| 5332 break; |
| 5333 case NEON_FMLS_byelement_scalar: |
| 5334 Op = &Simulator::fmls; |
| 5335 break; |
| 5336 case NEON_FMULX_byelement_scalar: |
| 5337 Op = &Simulator::fmulx; |
| 5338 break; |
| 5339 default: |
| 5340 UNIMPLEMENTED(); |
| 5341 } |
| 5342 } |
| 5343 |
| 5344 (this->*Op)(vf, rd, rn, vreg(rm_reg), index); |
| 5345 } |
| 5346 |
| 5347 void Simulator::VisitNEONScalarCopy(Instruction* instr) { |
| 5348 NEONFormatDecoder nfd(instr, NEONFormatDecoder::TriangularScalarFormatMap()); |
| 5349 VectorFormat vf = nfd.GetVectorFormat(); |
| 5350 |
| 5351 SimVRegister& rd = vreg(instr->Rd()); |
| 5352 SimVRegister& rn = vreg(instr->Rn()); |
| 5353 |
| 5354 if (instr->Mask(NEONScalarCopyMask) == NEON_DUP_ELEMENT_scalar) { |
| 5355 int imm5 = instr->ImmNEON5(); |
| 5356 int lsb = LowestSetBitPosition(imm5); |
| 5357 int rn_index = imm5 >> lsb; |
| 5358 dup_element(vf, rd, rn, rn_index); |
| 5359 } else { |
| 5360 UNIMPLEMENTED(); |
| 5361 } |
| 5362 } |
| 5363 |
| 5364 void Simulator::VisitNEONScalarPairwise(Instruction* instr) { |
| 5365 NEONFormatDecoder nfd(instr, NEONFormatDecoder::FPScalarFormatMap()); |
| 5366 VectorFormat vf = nfd.GetVectorFormat(); |
| 5367 |
| 5368 SimVRegister& rd = vreg(instr->Rd()); |
| 5369 SimVRegister& rn = vreg(instr->Rn()); |
| 5370 switch (instr->Mask(NEONScalarPairwiseMask)) { |
| 5371 case NEON_ADDP_scalar: |
| 5372 addp(vf, rd, rn); |
| 5373 break; |
| 5374 case NEON_FADDP_scalar: |
| 5375 faddp(vf, rd, rn); |
| 5376 break; |
| 5377 case NEON_FMAXP_scalar: |
| 5378 fmaxp(vf, rd, rn); |
| 5379 break; |
| 5380 case NEON_FMAXNMP_scalar: |
| 5381 fmaxnmp(vf, rd, rn); |
| 5382 break; |
| 5383 case NEON_FMINP_scalar: |
| 5384 fminp(vf, rd, rn); |
| 5385 break; |
| 5386 case NEON_FMINNMP_scalar: |
| 5387 fminnmp(vf, rd, rn); |
| 5388 break; |
| 5389 default: |
| 5390 UNIMPLEMENTED(); |
| 5391 } |
| 5392 } |
| 5393 |
| 5394 void Simulator::VisitNEONScalarShiftImmediate(Instruction* instr) { |
| 5395 SimVRegister& rd = vreg(instr->Rd()); |
| 5396 SimVRegister& rn = vreg(instr->Rn()); |
| 5397 FPRounding fpcr_rounding = static_cast<FPRounding>(fpcr().RMode()); |
| 5398 |
| 5399 static const NEONFormatMap map = { |
| 5400 {22, 21, 20, 19}, |
| 5401 {NF_UNDEF, NF_B, NF_H, NF_H, NF_S, NF_S, NF_S, NF_S, NF_D, NF_D, NF_D, |
| 5402 NF_D, NF_D, NF_D, NF_D, NF_D}}; |
| 5403 NEONFormatDecoder nfd(instr, &map); |
| 5404 VectorFormat vf = nfd.GetVectorFormat(); |
| 5405 |
| 5406 int highestSetBit = HighestSetBitPosition(instr->ImmNEONImmh()); |
| 5407 int immhimmb = instr->ImmNEONImmhImmb(); |
| 5408 int right_shift = (16 << highestSetBit) - immhimmb; |
| 5409 int left_shift = immhimmb - (8 << highestSetBit); |
| 5410 switch (instr->Mask(NEONScalarShiftImmediateMask)) { |
| 5411 case NEON_SHL_scalar: |
| 5412 shl(vf, rd, rn, left_shift); |
| 5413 break; |
| 5414 case NEON_SLI_scalar: |
| 5415 sli(vf, rd, rn, left_shift); |
| 5416 break; |
| 5417 case NEON_SQSHL_imm_scalar: |
| 5418 sqshl(vf, rd, rn, left_shift); |
| 5419 break; |
| 5420 case NEON_UQSHL_imm_scalar: |
| 5421 uqshl(vf, rd, rn, left_shift); |
| 5422 break; |
| 5423 case NEON_SQSHLU_scalar: |
| 5424 sqshlu(vf, rd, rn, left_shift); |
| 5425 break; |
| 5426 case NEON_SRI_scalar: |
| 5427 sri(vf, rd, rn, right_shift); |
| 5428 break; |
| 5429 case NEON_SSHR_scalar: |
| 5430 sshr(vf, rd, rn, right_shift); |
| 5431 break; |
| 5432 case NEON_USHR_scalar: |
| 5433 ushr(vf, rd, rn, right_shift); |
| 5434 break; |
| 5435 case NEON_SRSHR_scalar: |
| 5436 sshr(vf, rd, rn, right_shift).Round(vf); |
| 5437 break; |
| 5438 case NEON_URSHR_scalar: |
| 5439 ushr(vf, rd, rn, right_shift).Round(vf); |
| 5440 break; |
| 5441 case NEON_SSRA_scalar: |
| 5442 ssra(vf, rd, rn, right_shift); |
| 5443 break; |
| 5444 case NEON_USRA_scalar: |
| 5445 usra(vf, rd, rn, right_shift); |
| 5446 break; |
| 5447 case NEON_SRSRA_scalar: |
| 5448 srsra(vf, rd, rn, right_shift); |
| 5449 break; |
| 5450 case NEON_URSRA_scalar: |
| 5451 ursra(vf, rd, rn, right_shift); |
| 5452 break; |
| 5453 case NEON_UQSHRN_scalar: |
| 5454 uqshrn(vf, rd, rn, right_shift); |
| 5455 break; |
| 5456 case NEON_UQRSHRN_scalar: |
| 5457 uqrshrn(vf, rd, rn, right_shift); |
| 5458 break; |
| 5459 case NEON_SQSHRN_scalar: |
| 5460 sqshrn(vf, rd, rn, right_shift); |
| 5461 break; |
| 5462 case NEON_SQRSHRN_scalar: |
| 5463 sqrshrn(vf, rd, rn, right_shift); |
| 5464 break; |
| 5465 case NEON_SQSHRUN_scalar: |
| 5466 sqshrun(vf, rd, rn, right_shift); |
| 5467 break; |
| 5468 case NEON_SQRSHRUN_scalar: |
| 5469 sqrshrun(vf, rd, rn, right_shift); |
| 5470 break; |
| 5471 case NEON_FCVTZS_imm_scalar: |
| 5472 fcvts(vf, rd, rn, FPZero, right_shift); |
| 5473 break; |
| 5474 case NEON_FCVTZU_imm_scalar: |
| 5475 fcvtu(vf, rd, rn, FPZero, right_shift); |
| 5476 break; |
| 5477 case NEON_SCVTF_imm_scalar: |
| 5478 scvtf(vf, rd, rn, right_shift, fpcr_rounding); |
| 5479 break; |
| 5480 case NEON_UCVTF_imm_scalar: |
| 5481 ucvtf(vf, rd, rn, right_shift, fpcr_rounding); |
| 5482 break; |
| 5483 default: |
| 5484 UNIMPLEMENTED(); |
| 5485 } |
| 5486 } |
| 5487 |
| 5488 void Simulator::VisitNEONShiftImmediate(Instruction* instr) { |
| 5489 SimVRegister& rd = vreg(instr->Rd()); |
| 5490 SimVRegister& rn = vreg(instr->Rn()); |
| 5491 FPRounding fpcr_rounding = static_cast<FPRounding>(fpcr().RMode()); |
| 5492 |
| 5493 // 00010->8B, 00011->16B, 001x0->4H, 001x1->8H, |
| 5494 // 01xx0->2S, 01xx1->4S, 1xxx1->2D, all others undefined. |
| 5495 static const NEONFormatMap map = { |
| 5496 {22, 21, 20, 19, 30}, |
| 5497 {NF_UNDEF, NF_UNDEF, NF_8B, NF_16B, NF_4H, NF_8H, NF_4H, NF_8H, |
| 5498 NF_2S, NF_4S, NF_2S, NF_4S, NF_2S, NF_4S, NF_2S, NF_4S, |
| 5499 NF_UNDEF, NF_2D, NF_UNDEF, NF_2D, NF_UNDEF, NF_2D, NF_UNDEF, NF_2D, |
| 5500 NF_UNDEF, NF_2D, NF_UNDEF, NF_2D, NF_UNDEF, NF_2D, NF_UNDEF, NF_2D}}; |
| 5501 NEONFormatDecoder nfd(instr, &map); |
| 5502 VectorFormat vf = nfd.GetVectorFormat(); |
| 5503 |
| 5504 // 0001->8H, 001x->4S, 01xx->2D, all others undefined. |
| 5505 static const NEONFormatMap map_l = { |
| 5506 {22, 21, 20, 19}, |
| 5507 {NF_UNDEF, NF_8H, NF_4S, NF_4S, NF_2D, NF_2D, NF_2D, NF_2D}}; |
| 5508 VectorFormat vf_l = nfd.GetVectorFormat(&map_l); |
| 5509 |
| 5510 int highestSetBit = HighestSetBitPosition(instr->ImmNEONImmh()); |
| 5511 int immhimmb = instr->ImmNEONImmhImmb(); |
| 5512 int right_shift = (16 << highestSetBit) - immhimmb; |
| 5513 int left_shift = immhimmb - (8 << highestSetBit); |
| 5514 |
| 5515 switch (instr->Mask(NEONShiftImmediateMask)) { |
| 5516 case NEON_SHL: |
| 5517 shl(vf, rd, rn, left_shift); |
| 5518 break; |
| 5519 case NEON_SLI: |
| 5520 sli(vf, rd, rn, left_shift); |
| 5521 break; |
| 5522 case NEON_SQSHLU: |
| 5523 sqshlu(vf, rd, rn, left_shift); |
| 5524 break; |
| 5525 case NEON_SRI: |
| 5526 sri(vf, rd, rn, right_shift); |
| 5527 break; |
| 5528 case NEON_SSHR: |
| 5529 sshr(vf, rd, rn, right_shift); |
| 5530 break; |
| 5531 case NEON_USHR: |
| 5532 ushr(vf, rd, rn, right_shift); |
| 5533 break; |
| 5534 case NEON_SRSHR: |
| 5535 sshr(vf, rd, rn, right_shift).Round(vf); |
| 5536 break; |
| 5537 case NEON_URSHR: |
| 5538 ushr(vf, rd, rn, right_shift).Round(vf); |
| 5539 break; |
| 5540 case NEON_SSRA: |
| 5541 ssra(vf, rd, rn, right_shift); |
| 5542 break; |
| 5543 case NEON_USRA: |
| 5544 usra(vf, rd, rn, right_shift); |
| 5545 break; |
| 5546 case NEON_SRSRA: |
| 5547 srsra(vf, rd, rn, right_shift); |
| 5548 break; |
| 5549 case NEON_URSRA: |
| 5550 ursra(vf, rd, rn, right_shift); |
| 5551 break; |
| 5552 case NEON_SQSHL_imm: |
| 5553 sqshl(vf, rd, rn, left_shift); |
| 5554 break; |
| 5555 case NEON_UQSHL_imm: |
| 5556 uqshl(vf, rd, rn, left_shift); |
| 5557 break; |
| 5558 case NEON_SCVTF_imm: |
| 5559 scvtf(vf, rd, rn, right_shift, fpcr_rounding); |
| 5560 break; |
| 5561 case NEON_UCVTF_imm: |
| 5562 ucvtf(vf, rd, rn, right_shift, fpcr_rounding); |
| 5563 break; |
| 5564 case NEON_FCVTZS_imm: |
| 5565 fcvts(vf, rd, rn, FPZero, right_shift); |
| 5566 break; |
| 5567 case NEON_FCVTZU_imm: |
| 5568 fcvtu(vf, rd, rn, FPZero, right_shift); |
| 5569 break; |
| 5570 case NEON_SSHLL: |
| 5571 vf = vf_l; |
| 5572 if (instr->Mask(NEON_Q)) { |
| 5573 sshll2(vf, rd, rn, left_shift); |
| 5574 } else { |
| 5575 sshll(vf, rd, rn, left_shift); |
| 5576 } |
| 5577 break; |
| 5578 case NEON_USHLL: |
| 5579 vf = vf_l; |
| 5580 if (instr->Mask(NEON_Q)) { |
| 5581 ushll2(vf, rd, rn, left_shift); |
| 5582 } else { |
| 5583 ushll(vf, rd, rn, left_shift); |
| 5584 } |
| 5585 break; |
| 5586 case NEON_SHRN: |
| 5587 if (instr->Mask(NEON_Q)) { |
| 5588 shrn2(vf, rd, rn, right_shift); |
| 5589 } else { |
| 5590 shrn(vf, rd, rn, right_shift); |
| 5591 } |
| 5592 break; |
| 5593 case NEON_RSHRN: |
| 5594 if (instr->Mask(NEON_Q)) { |
| 5595 rshrn2(vf, rd, rn, right_shift); |
| 5596 } else { |
| 5597 rshrn(vf, rd, rn, right_shift); |
| 5598 } |
| 5599 break; |
| 5600 case NEON_UQSHRN: |
| 5601 if (instr->Mask(NEON_Q)) { |
| 5602 uqshrn2(vf, rd, rn, right_shift); |
| 5603 } else { |
| 5604 uqshrn(vf, rd, rn, right_shift); |
| 5605 } |
| 5606 break; |
| 5607 case NEON_UQRSHRN: |
| 5608 if (instr->Mask(NEON_Q)) { |
| 5609 uqrshrn2(vf, rd, rn, right_shift); |
| 5610 } else { |
| 5611 uqrshrn(vf, rd, rn, right_shift); |
| 5612 } |
| 5613 break; |
| 5614 case NEON_SQSHRN: |
| 5615 if (instr->Mask(NEON_Q)) { |
| 5616 sqshrn2(vf, rd, rn, right_shift); |
| 5617 } else { |
| 5618 sqshrn(vf, rd, rn, right_shift); |
| 5619 } |
| 5620 break; |
| 5621 case NEON_SQRSHRN: |
| 5622 if (instr->Mask(NEON_Q)) { |
| 5623 sqrshrn2(vf, rd, rn, right_shift); |
| 5624 } else { |
| 5625 sqrshrn(vf, rd, rn, right_shift); |
| 5626 } |
| 5627 break; |
| 5628 case NEON_SQSHRUN: |
| 5629 if (instr->Mask(NEON_Q)) { |
| 5630 sqshrun2(vf, rd, rn, right_shift); |
| 5631 } else { |
| 5632 sqshrun(vf, rd, rn, right_shift); |
| 5633 } |
| 5634 break; |
| 5635 case NEON_SQRSHRUN: |
| 5636 if (instr->Mask(NEON_Q)) { |
| 5637 sqrshrun2(vf, rd, rn, right_shift); |
| 5638 } else { |
| 5639 sqrshrun(vf, rd, rn, right_shift); |
| 5640 } |
| 5641 break; |
| 5642 default: |
| 5643 UNIMPLEMENTED(); |
| 5644 } |
| 5645 } |
| 5646 |
| 5647 void Simulator::VisitNEONTable(Instruction* instr) { |
| 5648 NEONFormatDecoder nfd(instr, NEONFormatDecoder::LogicalFormatMap()); |
| 5649 VectorFormat vf = nfd.GetVectorFormat(); |
| 5650 |
| 5651 SimVRegister& rd = vreg(instr->Rd()); |
| 5652 SimVRegister& rn = vreg(instr->Rn()); |
| 5653 SimVRegister& rn2 = vreg((instr->Rn() + 1) % kNumberOfVRegisters); |
| 5654 SimVRegister& rn3 = vreg((instr->Rn() + 2) % kNumberOfVRegisters); |
| 5655 SimVRegister& rn4 = vreg((instr->Rn() + 3) % kNumberOfVRegisters); |
| 5656 SimVRegister& rm = vreg(instr->Rm()); |
| 5657 |
| 5658 switch (instr->Mask(NEONTableMask)) { |
| 5659 case NEON_TBL_1v: |
| 5660 tbl(vf, rd, rn, rm); |
| 5661 break; |
| 5662 case NEON_TBL_2v: |
| 5663 tbl(vf, rd, rn, rn2, rm); |
| 5664 break; |
| 5665 case NEON_TBL_3v: |
| 5666 tbl(vf, rd, rn, rn2, rn3, rm); |
| 5667 break; |
| 5668 case NEON_TBL_4v: |
| 5669 tbl(vf, rd, rn, rn2, rn3, rn4, rm); |
| 5670 break; |
| 5671 case NEON_TBX_1v: |
| 5672 tbx(vf, rd, rn, rm); |
| 5673 break; |
| 5674 case NEON_TBX_2v: |
| 5675 tbx(vf, rd, rn, rn2, rm); |
| 5676 break; |
| 5677 case NEON_TBX_3v: |
| 5678 tbx(vf, rd, rn, rn2, rn3, rm); |
| 5679 break; |
| 5680 case NEON_TBX_4v: |
| 5681 tbx(vf, rd, rn, rn2, rn3, rn4, rm); |
| 5682 break; |
| 5683 default: |
| 5684 UNIMPLEMENTED(); |
| 5685 } |
| 5686 } |
| 5687 |
| 5688 void Simulator::VisitNEONPerm(Instruction* instr) { |
| 5689 NEONFormatDecoder nfd(instr); |
| 5690 VectorFormat vf = nfd.GetVectorFormat(); |
| 5691 |
| 5692 SimVRegister& rd = vreg(instr->Rd()); |
| 5693 SimVRegister& rn = vreg(instr->Rn()); |
| 5694 SimVRegister& rm = vreg(instr->Rm()); |
| 5695 |
| 5696 switch (instr->Mask(NEONPermMask)) { |
| 5697 case NEON_TRN1: |
| 5698 trn1(vf, rd, rn, rm); |
| 5699 break; |
| 5700 case NEON_TRN2: |
| 5701 trn2(vf, rd, rn, rm); |
| 5702 break; |
| 5703 case NEON_UZP1: |
| 5704 uzp1(vf, rd, rn, rm); |
| 5705 break; |
| 5706 case NEON_UZP2: |
| 5707 uzp2(vf, rd, rn, rm); |
| 5708 break; |
| 5709 case NEON_ZIP1: |
| 5710 zip1(vf, rd, rn, rm); |
| 5711 break; |
| 5712 case NEON_ZIP2: |
| 5713 zip2(vf, rd, rn, rm); |
| 5714 break; |
| 5715 default: |
| 5716 UNIMPLEMENTED(); |
| 5717 } |
| 5718 } |
3898 | 5719 |
3899 void Simulator::DoPrintf(Instruction* instr) { | 5720 void Simulator::DoPrintf(Instruction* instr) { |
3900 DCHECK((instr->Mask(ExceptionMask) == HLT) && | 5721 DCHECK((instr->Mask(ExceptionMask) == HLT) && |
3901 (instr->ImmException() == kImmExceptionIsPrintf)); | 5722 (instr->ImmException() == kImmExceptionIsPrintf)); |
3902 | 5723 |
3903 // Read the arguments encoded inline in the instruction stream. | 5724 // Read the arguments encoded inline in the instruction stream. |
3904 uint32_t arg_count; | 5725 uint32_t arg_count; |
3905 uint32_t arg_pattern_list; | 5726 uint32_t arg_pattern_list; |
3906 STATIC_ASSERT(sizeof(*instr) == 1); | 5727 STATIC_ASSERT(sizeof(*instr) == 1); |
3907 memcpy(&arg_count, | 5728 memcpy(&arg_count, |
(...skipping 293 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4201 processor->prev_ = nullptr; | 6022 processor->prev_ = nullptr; |
4202 processor->next_ = nullptr; | 6023 processor->next_ = nullptr; |
4203 } | 6024 } |
4204 | 6025 |
4205 #endif // USE_SIMULATOR | 6026 #endif // USE_SIMULATOR |
4206 | 6027 |
4207 } // namespace internal | 6028 } // namespace internal |
4208 } // namespace v8 | 6029 } // namespace v8 |
4209 | 6030 |
4210 #endif // V8_TARGET_ARCH_ARM64 | 6031 #endif // V8_TARGET_ARCH_ARM64 |
OLD | NEW |