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