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 if ((instr->Bit(23) == 0) && (instr->Bits(20, 16) != 0)) { | |
bbudge
2017/01/31 01:41:31
DCHECK_IMPLIES ?
martyn.capewell
2017/02/03 11:01:31
Done.
| |
4540 UNREACHABLE(); | |
4541 } | |
4542 | |
4543 bool do_load = false; | |
4544 | |
4545 NEONFormatDecoder nfd(instr, NEONFormatDecoder::LoadStoreFormatMap()); | |
4546 VectorFormat vf_t = nfd.GetVectorFormat(); | |
4547 | |
4548 VectorFormat vf = kFormat16B; | |
4549 // We use the PostIndex mask here, as it works in this case for both Offset | |
4550 // and PostIndex addressing. | |
4551 switch (instr->Mask(NEONLoadStoreSingleStructPostIndexMask)) { | |
4552 case NEON_LD1_b: | |
4553 case NEON_LD1_b_post: | |
4554 case NEON_LD2_b: | |
4555 case NEON_LD2_b_post: | |
4556 case NEON_LD3_b: | |
4557 case NEON_LD3_b_post: | |
4558 case NEON_LD4_b: | |
4559 case NEON_LD4_b_post: | |
4560 do_load = true; // Fall through. | |
4561 case NEON_ST1_b: | |
4562 case NEON_ST1_b_post: | |
4563 case NEON_ST2_b: | |
4564 case NEON_ST2_b_post: | |
4565 case NEON_ST3_b: | |
4566 case NEON_ST3_b_post: | |
4567 case NEON_ST4_b: | |
4568 case NEON_ST4_b_post: | |
4569 break; | |
4570 | |
4571 case NEON_LD1_h: | |
4572 case NEON_LD1_h_post: | |
4573 case NEON_LD2_h: | |
4574 case NEON_LD2_h_post: | |
4575 case NEON_LD3_h: | |
4576 case NEON_LD3_h_post: | |
4577 case NEON_LD4_h: | |
4578 case NEON_LD4_h_post: | |
4579 do_load = true; // Fall through. | |
4580 case NEON_ST1_h: | |
4581 case NEON_ST1_h_post: | |
4582 case NEON_ST2_h: | |
4583 case NEON_ST2_h_post: | |
4584 case NEON_ST3_h: | |
4585 case NEON_ST3_h_post: | |
4586 case NEON_ST4_h: | |
4587 case NEON_ST4_h_post: | |
4588 vf = kFormat8H; | |
4589 break; | |
4590 | |
4591 case NEON_LD1_s: | |
4592 case NEON_LD1_s_post: | |
4593 case NEON_LD2_s: | |
4594 case NEON_LD2_s_post: | |
4595 case NEON_LD3_s: | |
4596 case NEON_LD3_s_post: | |
4597 case NEON_LD4_s: | |
4598 case NEON_LD4_s_post: | |
4599 do_load = true; // Fall through. | |
4600 case NEON_ST1_s: | |
4601 case NEON_ST1_s_post: | |
4602 case NEON_ST2_s: | |
4603 case NEON_ST2_s_post: | |
4604 case NEON_ST3_s: | |
4605 case NEON_ST3_s_post: | |
4606 case NEON_ST4_s: | |
4607 case NEON_ST4_s_post: { | |
4608 static_assert((NEON_LD1_s | (1 << NEONLSSize_offset)) == NEON_LD1_d, | |
4609 "LSB of size distinguishes S and D registers."); | |
4610 static_assert( | |
4611 (NEON_LD1_s_post | (1 << NEONLSSize_offset)) == NEON_LD1_d_post, | |
4612 "LSB of size distinguishes S and D registers."); | |
4613 static_assert((NEON_ST1_s | (1 << NEONLSSize_offset)) == NEON_ST1_d, | |
4614 "LSB of size distinguishes S and D registers."); | |
4615 static_assert( | |
4616 (NEON_ST1_s_post | (1 << NEONLSSize_offset)) == NEON_ST1_d_post, | |
4617 "LSB of size distinguishes S and D registers."); | |
4618 vf = ((instr->NEONLSSize() & 1) == 0) ? kFormat4S : kFormat2D; | |
4619 break; | |
4620 } | |
4621 | |
4622 case NEON_LD1R: | |
4623 case NEON_LD1R_post: { | |
4624 vf = vf_t; | |
4625 ld1r(vf, vreg(rt), addr); | |
4626 do_load = true; | |
4627 break; | |
4628 } | |
4629 | |
4630 case NEON_LD2R: | |
4631 case NEON_LD2R_post: { | |
4632 vf = vf_t; | |
4633 int rt2 = (rt + 1) % kNumberOfVRegisters; | |
4634 ld2r(vf, vreg(rt), vreg(rt2), addr); | |
4635 do_load = true; | |
4636 break; | |
4637 } | |
4638 | |
4639 case NEON_LD3R: | |
4640 case NEON_LD3R_post: { | |
4641 vf = vf_t; | |
4642 int rt2 = (rt + 1) % kNumberOfVRegisters; | |
4643 int rt3 = (rt2 + 1) % kNumberOfVRegisters; | |
4644 ld3r(vf, vreg(rt), vreg(rt2), vreg(rt3), addr); | |
4645 do_load = true; | |
4646 break; | |
4647 } | |
4648 | |
4649 case NEON_LD4R: | |
4650 case NEON_LD4R_post: { | |
4651 vf = vf_t; | |
4652 int rt2 = (rt + 1) % kNumberOfVRegisters; | |
4653 int rt3 = (rt2 + 1) % kNumberOfVRegisters; | |
4654 int rt4 = (rt3 + 1) % kNumberOfVRegisters; | |
4655 ld4r(vf, vreg(rt), vreg(rt2), vreg(rt3), vreg(rt4), addr); | |
4656 do_load = true; | |
4657 break; | |
4658 } | |
4659 default: | |
4660 UNIMPLEMENTED(); | |
4661 } | |
4662 | |
4663 PrintRegisterFormat print_format = | |
4664 GetPrintRegisterFormatTryFP(GetPrintRegisterFormat(vf)); | |
4665 // Make sure that the print_format only includes a single lane. | |
4666 print_format = | |
4667 static_cast<PrintRegisterFormat>(print_format & ~kPrintRegAsVectorMask); | |
4668 | |
4669 int esize = LaneSizeInBytesFromFormat(vf); | |
4670 int index_shift = LaneSizeInBytesLog2FromFormat(vf); | |
4671 int lane = instr->NEONLSIndex(index_shift); | |
4672 int scale = 0; | |
4673 int rt2 = (rt + 1) % kNumberOfVRegisters; | |
4674 int rt3 = (rt2 + 1) % kNumberOfVRegisters; | |
4675 int rt4 = (rt3 + 1) % kNumberOfVRegisters; | |
4676 switch (instr->Mask(NEONLoadStoreSingleLenMask)) { | |
4677 case NEONLoadStoreSingle1: | |
4678 scale = 1; | |
4679 if (do_load) { | |
4680 ld1(vf, vreg(rt), lane, addr); | |
4681 LogVRead(addr, rt, print_format, lane); | |
4682 } else { | |
4683 st1(vf, vreg(rt), lane, addr); | |
4684 LogVWrite(addr, rt, print_format, lane); | |
4685 } | |
4686 break; | |
4687 case NEONLoadStoreSingle2: | |
4688 scale = 2; | |
4689 if (do_load) { | |
4690 ld2(vf, vreg(rt), vreg(rt2), lane, addr); | |
4691 LogVRead(addr, rt, print_format, lane); | |
4692 LogVRead(addr + esize, rt2, print_format, lane); | |
4693 } else { | |
4694 st2(vf, vreg(rt), vreg(rt2), lane, addr); | |
4695 LogVWrite(addr, rt, print_format, lane); | |
4696 LogVWrite(addr + esize, rt2, print_format, lane); | |
4697 } | |
4698 break; | |
4699 case NEONLoadStoreSingle3: | |
4700 scale = 3; | |
4701 if (do_load) { | |
4702 ld3(vf, vreg(rt), vreg(rt2), vreg(rt3), lane, addr); | |
4703 LogVRead(addr, rt, print_format, lane); | |
4704 LogVRead(addr + esize, rt2, print_format, lane); | |
4705 LogVRead(addr + (2 * esize), rt3, print_format, lane); | |
4706 } else { | |
4707 st3(vf, vreg(rt), vreg(rt2), vreg(rt3), lane, addr); | |
4708 LogVWrite(addr, rt, print_format, lane); | |
4709 LogVWrite(addr + esize, rt2, print_format, lane); | |
4710 LogVWrite(addr + (2 * esize), rt3, print_format, lane); | |
4711 } | |
4712 break; | |
4713 case NEONLoadStoreSingle4: | |
4714 scale = 4; | |
4715 if (do_load) { | |
4716 ld4(vf, vreg(rt), vreg(rt2), vreg(rt3), vreg(rt4), lane, addr); | |
4717 LogVRead(addr, rt, print_format, lane); | |
4718 LogVRead(addr + esize, rt2, print_format, lane); | |
4719 LogVRead(addr + (2 * esize), rt3, print_format, lane); | |
4720 LogVRead(addr + (3 * esize), rt4, print_format, lane); | |
4721 } else { | |
4722 st4(vf, vreg(rt), vreg(rt2), vreg(rt3), vreg(rt4), lane, addr); | |
4723 LogVWrite(addr, rt, print_format, lane); | |
4724 LogVWrite(addr + esize, rt2, print_format, lane); | |
4725 LogVWrite(addr + (2 * esize), rt3, print_format, lane); | |
4726 LogVWrite(addr + (3 * esize), rt4, print_format, lane); | |
4727 } | |
4728 break; | |
4729 default: | |
4730 UNIMPLEMENTED(); | |
4731 } | |
4732 | |
4733 if (addr_mode == PostIndex) { | |
4734 int rm = instr->Rm(); | |
4735 int lane_size = LaneSizeInBytesFromFormat(vf); | |
4736 set_xreg(instr->Rn(), addr + ((rm == 31) ? (scale * lane_size) : xreg(rm))); | |
4737 } | |
4738 } | |
4739 | |
4740 void Simulator::VisitNEONLoadStoreSingleStruct(Instruction* instr) { | |
4741 NEONLoadStoreSingleStructHelper(instr, Offset); | |
4742 } | |
4743 | |
4744 void Simulator::VisitNEONLoadStoreSingleStructPostIndex(Instruction* instr) { | |
4745 NEONLoadStoreSingleStructHelper(instr, PostIndex); | |
4746 } | |
4747 | |
4748 void Simulator::VisitNEONModifiedImmediate(Instruction* instr) { | |
4749 SimVRegister& rd = vreg(instr->Rd()); | |
4750 int cmode = instr->NEONCmode(); | |
4751 int cmode_3_1 = (cmode >> 1) & 7; | |
4752 int cmode_3 = (cmode >> 3) & 1; | |
4753 int cmode_2 = (cmode >> 2) & 1; | |
4754 int cmode_1 = (cmode >> 1) & 1; | |
4755 int cmode_0 = cmode & 1; | |
4756 int q = instr->NEONQ(); | |
4757 int op_bit = instr->NEONModImmOp(); | |
4758 uint64_t imm8 = instr->ImmNEONabcdefgh(); | |
4759 | |
4760 // Find the format and immediate value | |
4761 uint64_t imm = 0; | |
4762 VectorFormat vform = kFormatUndefined; | |
4763 switch (cmode_3_1) { | |
4764 case 0x0: | |
4765 case 0x1: | |
4766 case 0x2: | |
4767 case 0x3: | |
4768 vform = (q == 1) ? kFormat4S : kFormat2S; | |
4769 imm = imm8 << (8 * cmode_3_1); | |
4770 break; | |
4771 case 0x4: | |
4772 case 0x5: | |
4773 vform = (q == 1) ? kFormat8H : kFormat4H; | |
4774 imm = imm8 << (8 * cmode_1); | |
4775 break; | |
4776 case 0x6: | |
4777 vform = (q == 1) ? kFormat4S : kFormat2S; | |
4778 if (cmode_0 == 0) { | |
4779 imm = imm8 << 8 | 0x000000ff; | |
4780 } else { | |
4781 imm = imm8 << 16 | 0x0000ffff; | |
4782 } | |
4783 break; | |
4784 case 0x7: | |
4785 if (cmode_0 == 0 && op_bit == 0) { | |
4786 vform = q ? kFormat16B : kFormat8B; | |
4787 imm = imm8; | |
4788 } else if (cmode_0 == 0 && op_bit == 1) { | |
4789 vform = q ? kFormat2D : kFormat1D; | |
4790 imm = 0; | |
4791 for (int i = 0; i < 8; ++i) { | |
4792 if (imm8 & (1 << i)) { | |
4793 imm |= (UINT64_C(0xff) << (8 * i)); | |
4794 } | |
4795 } | |
4796 } else { // cmode_0 == 1, cmode == 0xf. | |
4797 if (op_bit == 0) { | |
4798 vform = q ? kFormat4S : kFormat2S; | |
4799 imm = bit_cast<uint32_t>(instr->ImmNEONFP32()); | |
4800 } else if (q == 1) { | |
4801 vform = kFormat2D; | |
4802 imm = bit_cast<uint64_t>(instr->ImmNEONFP64()); | |
4803 } else { | |
4804 DCHECK((q == 0) && (op_bit == 1) && (cmode == 0xf)); | |
4805 VisitUnallocated(instr); | |
4806 } | |
4807 } | |
4808 break; | |
4809 default: | |
4810 UNREACHABLE(); | |
4811 break; | |
4812 } | |
4813 | |
4814 // Find the operation. | |
4815 NEONModifiedImmediateOp op; | |
4816 if (cmode_3 == 0) { | |
4817 if (cmode_0 == 0) { | |
4818 op = op_bit ? NEONModifiedImmediate_MVNI : NEONModifiedImmediate_MOVI; | |
4819 } else { // cmode<0> == '1' | |
4820 op = op_bit ? NEONModifiedImmediate_BIC : NEONModifiedImmediate_ORR; | |
4821 } | |
4822 } else { // cmode<3> == '1' | |
4823 if (cmode_2 == 0) { | |
4824 if (cmode_0 == 0) { | |
4825 op = op_bit ? NEONModifiedImmediate_MVNI : NEONModifiedImmediate_MOVI; | |
4826 } else { // cmode<0> == '1' | |
4827 op = op_bit ? NEONModifiedImmediate_BIC : NEONModifiedImmediate_ORR; | |
4828 } | |
4829 } else { // cmode<2> == '1' | |
4830 if (cmode_1 == 0) { | |
4831 op = op_bit ? NEONModifiedImmediate_MVNI : NEONModifiedImmediate_MOVI; | |
4832 } else { // cmode<1> == '1' | |
4833 if (cmode_0 == 0) { | |
4834 op = NEONModifiedImmediate_MOVI; | |
4835 } else { // cmode<0> == '1' | |
4836 op = NEONModifiedImmediate_MOVI; | |
4837 } | |
4838 } | |
4839 } | |
4840 } | |
4841 | |
4842 // Call the logic function. | |
4843 switch (op) { | |
4844 case NEONModifiedImmediate_ORR: | |
4845 orr(vform, rd, rd, imm); | |
4846 break; | |
4847 case NEONModifiedImmediate_BIC: | |
4848 bic(vform, rd, rd, imm); | |
4849 break; | |
4850 case NEONModifiedImmediate_MOVI: | |
4851 movi(vform, rd, imm); | |
4852 break; | |
4853 case NEONModifiedImmediate_MVNI: | |
4854 mvni(vform, rd, imm); | |
4855 break; | |
4856 default: | |
4857 VisitUnimplemented(instr); | |
4858 } | |
4859 } | |
4860 | |
4861 void Simulator::VisitNEONScalar2RegMisc(Instruction* instr) { | |
4862 NEONFormatDecoder nfd(instr, NEONFormatDecoder::ScalarFormatMap()); | |
4863 VectorFormat vf = nfd.GetVectorFormat(); | |
4864 | |
4865 SimVRegister& rd = vreg(instr->Rd()); | |
4866 SimVRegister& rn = vreg(instr->Rn()); | |
4867 | |
4868 if (instr->Mask(NEON2RegMiscOpcode) <= NEON_NEG_scalar_opcode) { | |
4869 // These instructions all use a two bit size field, except NOT and RBIT, | |
4870 // which use the field to encode the operation. | |
4871 switch (instr->Mask(NEONScalar2RegMiscMask)) { | |
4872 case NEON_CMEQ_zero_scalar: | |
4873 cmp(vf, rd, rn, 0, eq); | |
4874 break; | |
4875 case NEON_CMGE_zero_scalar: | |
4876 cmp(vf, rd, rn, 0, ge); | |
4877 break; | |
4878 case NEON_CMGT_zero_scalar: | |
4879 cmp(vf, rd, rn, 0, gt); | |
4880 break; | |
4881 case NEON_CMLT_zero_scalar: | |
4882 cmp(vf, rd, rn, 0, lt); | |
4883 break; | |
4884 case NEON_CMLE_zero_scalar: | |
4885 cmp(vf, rd, rn, 0, le); | |
4886 break; | |
4887 case NEON_ABS_scalar: | |
4888 abs(vf, rd, rn); | |
4889 break; | |
4890 case NEON_SQABS_scalar: | |
4891 abs(vf, rd, rn).SignedSaturate(vf); | |
4892 break; | |
4893 case NEON_NEG_scalar: | |
4894 neg(vf, rd, rn); | |
4895 break; | |
4896 case NEON_SQNEG_scalar: | |
4897 neg(vf, rd, rn).SignedSaturate(vf); | |
4898 break; | |
4899 case NEON_SUQADD_scalar: | |
4900 suqadd(vf, rd, rn); | |
4901 break; | |
4902 case NEON_USQADD_scalar: | |
4903 usqadd(vf, rd, rn); | |
4904 break; | |
4905 default: | |
4906 UNIMPLEMENTED(); | |
4907 break; | |
4908 } | |
4909 } else { | |
4910 VectorFormat fpf = nfd.GetVectorFormat(nfd.FPScalarFormatMap()); | |
4911 FPRounding fpcr_rounding = static_cast<FPRounding>(fpcr().RMode()); | |
4912 | |
4913 // These instructions all use a one bit size field, except SQXTUN, SQXTN | |
4914 // and UQXTN, which use a two bit size field. | |
4915 switch (instr->Mask(NEONScalar2RegMiscFPMask)) { | |
4916 case NEON_FRECPE_scalar: | |
4917 frecpe(fpf, rd, rn, fpcr_rounding); | |
4918 break; | |
4919 case NEON_FRECPX_scalar: | |
4920 frecpx(fpf, rd, rn); | |
4921 break; | |
4922 case NEON_FRSQRTE_scalar: | |
4923 frsqrte(fpf, rd, rn); | |
4924 break; | |
4925 case NEON_FCMGT_zero_scalar: | |
4926 fcmp_zero(fpf, rd, rn, gt); | |
4927 break; | |
4928 case NEON_FCMGE_zero_scalar: | |
4929 fcmp_zero(fpf, rd, rn, ge); | |
4930 break; | |
4931 case NEON_FCMEQ_zero_scalar: | |
4932 fcmp_zero(fpf, rd, rn, eq); | |
4933 break; | |
4934 case NEON_FCMLE_zero_scalar: | |
4935 fcmp_zero(fpf, rd, rn, le); | |
4936 break; | |
4937 case NEON_FCMLT_zero_scalar: | |
4938 fcmp_zero(fpf, rd, rn, lt); | |
4939 break; | |
4940 case NEON_SCVTF_scalar: | |
4941 scvtf(fpf, rd, rn, 0, fpcr_rounding); | |
4942 break; | |
4943 case NEON_UCVTF_scalar: | |
4944 ucvtf(fpf, rd, rn, 0, fpcr_rounding); | |
4945 break; | |
4946 case NEON_FCVTNS_scalar: | |
4947 fcvts(fpf, rd, rn, FPTieEven); | |
4948 break; | |
4949 case NEON_FCVTNU_scalar: | |
4950 fcvtu(fpf, rd, rn, FPTieEven); | |
4951 break; | |
4952 case NEON_FCVTPS_scalar: | |
4953 fcvts(fpf, rd, rn, FPPositiveInfinity); | |
4954 break; | |
4955 case NEON_FCVTPU_scalar: | |
4956 fcvtu(fpf, rd, rn, FPPositiveInfinity); | |
4957 break; | |
4958 case NEON_FCVTMS_scalar: | |
4959 fcvts(fpf, rd, rn, FPNegativeInfinity); | |
4960 break; | |
4961 case NEON_FCVTMU_scalar: | |
4962 fcvtu(fpf, rd, rn, FPNegativeInfinity); | |
4963 break; | |
4964 case NEON_FCVTZS_scalar: | |
4965 fcvts(fpf, rd, rn, FPZero); | |
4966 break; | |
4967 case NEON_FCVTZU_scalar: | |
4968 fcvtu(fpf, rd, rn, FPZero); | |
4969 break; | |
4970 case NEON_FCVTAS_scalar: | |
4971 fcvts(fpf, rd, rn, FPTieAway); | |
4972 break; | |
4973 case NEON_FCVTAU_scalar: | |
4974 fcvtu(fpf, rd, rn, FPTieAway); | |
4975 break; | |
4976 case NEON_FCVTXN_scalar: | |
4977 // Unlike all of the other FP instructions above, fcvtxn encodes dest | |
4978 // size S as size<0>=1. There's only one case, so we ignore the form. | |
4979 DCHECK_EQ(instr->Bit(22), 1); | |
4980 fcvtxn(kFormatS, rd, rn); | |
4981 break; | |
4982 default: | |
4983 switch (instr->Mask(NEONScalar2RegMiscMask)) { | |
4984 case NEON_SQXTN_scalar: | |
4985 sqxtn(vf, rd, rn); | |
4986 break; | |
4987 case NEON_UQXTN_scalar: | |
4988 uqxtn(vf, rd, rn); | |
4989 break; | |
4990 case NEON_SQXTUN_scalar: | |
4991 sqxtun(vf, rd, rn); | |
4992 break; | |
4993 default: | |
4994 UNIMPLEMENTED(); | |
4995 } | |
4996 } | |
4997 } | |
4998 } | |
4999 | |
5000 void Simulator::VisitNEONScalar3Diff(Instruction* instr) { | |
5001 NEONFormatDecoder nfd(instr, NEONFormatDecoder::LongScalarFormatMap()); | |
5002 VectorFormat vf = nfd.GetVectorFormat(); | |
5003 | |
5004 SimVRegister& rd = vreg(instr->Rd()); | |
5005 SimVRegister& rn = vreg(instr->Rn()); | |
5006 SimVRegister& rm = vreg(instr->Rm()); | |
5007 switch (instr->Mask(NEONScalar3DiffMask)) { | |
5008 case NEON_SQDMLAL_scalar: | |
5009 sqdmlal(vf, rd, rn, rm); | |
5010 break; | |
5011 case NEON_SQDMLSL_scalar: | |
5012 sqdmlsl(vf, rd, rn, rm); | |
5013 break; | |
5014 case NEON_SQDMULL_scalar: | |
5015 sqdmull(vf, rd, rn, rm); | |
5016 break; | |
5017 default: | |
5018 UNIMPLEMENTED(); | |
5019 } | |
5020 } | |
5021 | |
5022 void Simulator::VisitNEONScalar3Same(Instruction* instr) { | |
5023 NEONFormatDecoder nfd(instr, NEONFormatDecoder::ScalarFormatMap()); | |
5024 VectorFormat vf = nfd.GetVectorFormat(); | |
5025 | |
5026 SimVRegister& rd = vreg(instr->Rd()); | |
5027 SimVRegister& rn = vreg(instr->Rn()); | |
5028 SimVRegister& rm = vreg(instr->Rm()); | |
5029 | |
5030 if (instr->Mask(NEONScalar3SameFPFMask) == NEONScalar3SameFPFixed) { | |
5031 vf = nfd.GetVectorFormat(nfd.FPScalarFormatMap()); | |
5032 switch (instr->Mask(NEONScalar3SameFPMask)) { | |
5033 case NEON_FMULX_scalar: | |
5034 fmulx(vf, rd, rn, rm); | |
5035 break; | |
5036 case NEON_FACGE_scalar: | |
5037 fabscmp(vf, rd, rn, rm, ge); | |
5038 break; | |
5039 case NEON_FACGT_scalar: | |
5040 fabscmp(vf, rd, rn, rm, gt); | |
5041 break; | |
5042 case NEON_FCMEQ_scalar: | |
5043 fcmp(vf, rd, rn, rm, eq); | |
5044 break; | |
5045 case NEON_FCMGE_scalar: | |
5046 fcmp(vf, rd, rn, rm, ge); | |
5047 break; | |
5048 case NEON_FCMGT_scalar: | |
5049 fcmp(vf, rd, rn, rm, gt); | |
5050 break; | |
5051 case NEON_FRECPS_scalar: | |
5052 frecps(vf, rd, rn, rm); | |
5053 break; | |
5054 case NEON_FRSQRTS_scalar: | |
5055 frsqrts(vf, rd, rn, rm); | |
5056 break; | |
5057 case NEON_FABD_scalar: | |
5058 fabd(vf, rd, rn, rm); | |
5059 break; | |
5060 default: | |
5061 UNIMPLEMENTED(); | |
5062 } | |
5063 } else { | |
5064 switch (instr->Mask(NEONScalar3SameMask)) { | |
5065 case NEON_ADD_scalar: | |
5066 add(vf, rd, rn, rm); | |
5067 break; | |
5068 case NEON_SUB_scalar: | |
5069 sub(vf, rd, rn, rm); | |
5070 break; | |
5071 case NEON_CMEQ_scalar: | |
5072 cmp(vf, rd, rn, rm, eq); | |
5073 break; | |
5074 case NEON_CMGE_scalar: | |
5075 cmp(vf, rd, rn, rm, ge); | |
5076 break; | |
5077 case NEON_CMGT_scalar: | |
5078 cmp(vf, rd, rn, rm, gt); | |
5079 break; | |
5080 case NEON_CMHI_scalar: | |
5081 cmp(vf, rd, rn, rm, hi); | |
5082 break; | |
5083 case NEON_CMHS_scalar: | |
5084 cmp(vf, rd, rn, rm, hs); | |
5085 break; | |
5086 case NEON_CMTST_scalar: | |
5087 cmptst(vf, rd, rn, rm); | |
5088 break; | |
5089 case NEON_USHL_scalar: | |
5090 ushl(vf, rd, rn, rm); | |
5091 break; | |
5092 case NEON_SSHL_scalar: | |
5093 sshl(vf, rd, rn, rm); | |
5094 break; | |
5095 case NEON_SQDMULH_scalar: | |
5096 sqdmulh(vf, rd, rn, rm); | |
5097 break; | |
5098 case NEON_SQRDMULH_scalar: | |
5099 sqrdmulh(vf, rd, rn, rm); | |
5100 break; | |
5101 case NEON_UQADD_scalar: | |
5102 add(vf, rd, rn, rm).UnsignedSaturate(vf); | |
5103 break; | |
5104 case NEON_SQADD_scalar: | |
5105 add(vf, rd, rn, rm).SignedSaturate(vf); | |
5106 break; | |
5107 case NEON_UQSUB_scalar: | |
5108 sub(vf, rd, rn, rm).UnsignedSaturate(vf); | |
5109 break; | |
5110 case NEON_SQSUB_scalar: | |
5111 sub(vf, rd, rn, rm).SignedSaturate(vf); | |
5112 break; | |
5113 case NEON_UQSHL_scalar: | |
5114 ushl(vf, rd, rn, rm).UnsignedSaturate(vf); | |
5115 break; | |
5116 case NEON_SQSHL_scalar: | |
5117 sshl(vf, rd, rn, rm).SignedSaturate(vf); | |
5118 break; | |
5119 case NEON_URSHL_scalar: | |
5120 ushl(vf, rd, rn, rm).Round(vf); | |
5121 break; | |
5122 case NEON_SRSHL_scalar: | |
5123 sshl(vf, rd, rn, rm).Round(vf); | |
5124 break; | |
5125 case NEON_UQRSHL_scalar: | |
5126 ushl(vf, rd, rn, rm).Round(vf).UnsignedSaturate(vf); | |
5127 break; | |
5128 case NEON_SQRSHL_scalar: | |
5129 sshl(vf, rd, rn, rm).Round(vf).SignedSaturate(vf); | |
5130 break; | |
5131 default: | |
5132 UNIMPLEMENTED(); | |
5133 } | |
5134 } | |
5135 } | |
5136 | |
5137 void Simulator::VisitNEONScalarByIndexedElement(Instruction* instr) { | |
5138 NEONFormatDecoder nfd(instr, NEONFormatDecoder::LongScalarFormatMap()); | |
5139 VectorFormat vf = nfd.GetVectorFormat(); | |
5140 VectorFormat vf_r = nfd.GetVectorFormat(nfd.ScalarFormatMap()); | |
5141 | |
5142 SimVRegister& rd = vreg(instr->Rd()); | |
5143 SimVRegister& rn = vreg(instr->Rn()); | |
5144 ByElementOp Op = NULL; | |
5145 | |
5146 int rm_reg = instr->Rm(); | |
5147 int index = (instr->NEONH() << 1) | instr->NEONL(); | |
5148 if (instr->NEONSize() == 1) { | |
5149 rm_reg &= 0xf; | |
5150 index = (index << 1) | instr->NEONM(); | |
5151 } | |
5152 | |
5153 switch (instr->Mask(NEONScalarByIndexedElementMask)) { | |
5154 case NEON_SQDMULL_byelement_scalar: | |
5155 Op = &Simulator::sqdmull; | |
5156 break; | |
5157 case NEON_SQDMLAL_byelement_scalar: | |
5158 Op = &Simulator::sqdmlal; | |
5159 break; | |
5160 case NEON_SQDMLSL_byelement_scalar: | |
5161 Op = &Simulator::sqdmlsl; | |
5162 break; | |
5163 case NEON_SQDMULH_byelement_scalar: | |
5164 Op = &Simulator::sqdmulh; | |
5165 vf = vf_r; | |
5166 break; | |
5167 case NEON_SQRDMULH_byelement_scalar: | |
5168 Op = &Simulator::sqrdmulh; | |
5169 vf = vf_r; | |
5170 break; | |
5171 default: | |
5172 vf = nfd.GetVectorFormat(nfd.FPScalarFormatMap()); | |
5173 index = instr->NEONH(); | |
5174 if ((instr->FPType() & 1) == 0) { | |
5175 index = (index << 1) | instr->NEONL(); | |
5176 } | |
5177 switch (instr->Mask(NEONScalarByIndexedElementFPMask)) { | |
5178 case NEON_FMUL_byelement_scalar: | |
5179 Op = &Simulator::fmul; | |
5180 break; | |
5181 case NEON_FMLA_byelement_scalar: | |
5182 Op = &Simulator::fmla; | |
5183 break; | |
5184 case NEON_FMLS_byelement_scalar: | |
5185 Op = &Simulator::fmls; | |
5186 break; | |
5187 case NEON_FMULX_byelement_scalar: | |
5188 Op = &Simulator::fmulx; | |
5189 break; | |
5190 default: | |
5191 UNIMPLEMENTED(); | |
5192 } | |
5193 } | |
5194 | |
5195 (this->*Op)(vf, rd, rn, vreg(rm_reg), index); | |
5196 } | |
5197 | |
5198 void Simulator::VisitNEONScalarCopy(Instruction* instr) { | |
5199 NEONFormatDecoder nfd(instr, NEONFormatDecoder::TriangularScalarFormatMap()); | |
5200 VectorFormat vf = nfd.GetVectorFormat(); | |
5201 | |
5202 SimVRegister& rd = vreg(instr->Rd()); | |
5203 SimVRegister& rn = vreg(instr->Rn()); | |
5204 | |
5205 if (instr->Mask(NEONScalarCopyMask) == NEON_DUP_ELEMENT_scalar) { | |
5206 int imm5 = instr->ImmNEON5(); | |
5207 int lsb = LowestSetBitPosition(imm5); | |
5208 int rn_index = imm5 >> lsb; | |
5209 dup_element(vf, rd, rn, rn_index); | |
5210 } else { | |
5211 UNIMPLEMENTED(); | |
5212 } | |
5213 } | |
5214 | |
5215 void Simulator::VisitNEONScalarPairwise(Instruction* instr) { | |
5216 NEONFormatDecoder nfd(instr, NEONFormatDecoder::FPScalarFormatMap()); | |
5217 VectorFormat vf = nfd.GetVectorFormat(); | |
5218 | |
5219 SimVRegister& rd = vreg(instr->Rd()); | |
5220 SimVRegister& rn = vreg(instr->Rn()); | |
5221 switch (instr->Mask(NEONScalarPairwiseMask)) { | |
5222 case NEON_ADDP_scalar: | |
5223 addp(vf, rd, rn); | |
5224 break; | |
5225 case NEON_FADDP_scalar: | |
5226 faddp(vf, rd, rn); | |
5227 break; | |
5228 case NEON_FMAXP_scalar: | |
5229 fmaxp(vf, rd, rn); | |
5230 break; | |
5231 case NEON_FMAXNMP_scalar: | |
5232 fmaxnmp(vf, rd, rn); | |
5233 break; | |
5234 case NEON_FMINP_scalar: | |
5235 fminp(vf, rd, rn); | |
5236 break; | |
5237 case NEON_FMINNMP_scalar: | |
5238 fminnmp(vf, rd, rn); | |
5239 break; | |
5240 default: | |
5241 UNIMPLEMENTED(); | |
5242 } | |
5243 } | |
5244 | |
5245 void Simulator::VisitNEONScalarShiftImmediate(Instruction* instr) { | |
5246 SimVRegister& rd = vreg(instr->Rd()); | |
5247 SimVRegister& rn = vreg(instr->Rn()); | |
5248 FPRounding fpcr_rounding = static_cast<FPRounding>(fpcr().RMode()); | |
5249 | |
5250 static const NEONFormatMap map = { | |
5251 {22, 21, 20, 19}, | |
5252 {NF_UNDEF, NF_B, NF_H, NF_H, NF_S, NF_S, NF_S, NF_S, NF_D, NF_D, NF_D, | |
5253 NF_D, NF_D, NF_D, NF_D, NF_D}}; | |
5254 NEONFormatDecoder nfd(instr, &map); | |
5255 VectorFormat vf = nfd.GetVectorFormat(); | |
5256 | |
5257 int highestSetBit = HighestSetBitPosition(instr->ImmNEONImmh()); | |
5258 int immhimmb = instr->ImmNEONImmhImmb(); | |
5259 int right_shift = (16 << highestSetBit) - immhimmb; | |
5260 int left_shift = immhimmb - (8 << highestSetBit); | |
5261 switch (instr->Mask(NEONScalarShiftImmediateMask)) { | |
5262 case NEON_SHL_scalar: | |
5263 shl(vf, rd, rn, left_shift); | |
5264 break; | |
5265 case NEON_SLI_scalar: | |
5266 sli(vf, rd, rn, left_shift); | |
5267 break; | |
5268 case NEON_SQSHL_imm_scalar: | |
5269 sqshl(vf, rd, rn, left_shift); | |
5270 break; | |
5271 case NEON_UQSHL_imm_scalar: | |
5272 uqshl(vf, rd, rn, left_shift); | |
5273 break; | |
5274 case NEON_SQSHLU_scalar: | |
5275 sqshlu(vf, rd, rn, left_shift); | |
5276 break; | |
5277 case NEON_SRI_scalar: | |
5278 sri(vf, rd, rn, right_shift); | |
5279 break; | |
5280 case NEON_SSHR_scalar: | |
5281 sshr(vf, rd, rn, right_shift); | |
5282 break; | |
5283 case NEON_USHR_scalar: | |
5284 ushr(vf, rd, rn, right_shift); | |
5285 break; | |
5286 case NEON_SRSHR_scalar: | |
5287 sshr(vf, rd, rn, right_shift).Round(vf); | |
5288 break; | |
5289 case NEON_URSHR_scalar: | |
5290 ushr(vf, rd, rn, right_shift).Round(vf); | |
5291 break; | |
5292 case NEON_SSRA_scalar: | |
5293 ssra(vf, rd, rn, right_shift); | |
5294 break; | |
5295 case NEON_USRA_scalar: | |
5296 usra(vf, rd, rn, right_shift); | |
5297 break; | |
5298 case NEON_SRSRA_scalar: | |
5299 srsra(vf, rd, rn, right_shift); | |
5300 break; | |
5301 case NEON_URSRA_scalar: | |
5302 ursra(vf, rd, rn, right_shift); | |
5303 break; | |
5304 case NEON_UQSHRN_scalar: | |
5305 uqshrn(vf, rd, rn, right_shift); | |
5306 break; | |
5307 case NEON_UQRSHRN_scalar: | |
5308 uqrshrn(vf, rd, rn, right_shift); | |
5309 break; | |
5310 case NEON_SQSHRN_scalar: | |
5311 sqshrn(vf, rd, rn, right_shift); | |
5312 break; | |
5313 case NEON_SQRSHRN_scalar: | |
5314 sqrshrn(vf, rd, rn, right_shift); | |
5315 break; | |
5316 case NEON_SQSHRUN_scalar: | |
5317 sqshrun(vf, rd, rn, right_shift); | |
5318 break; | |
5319 case NEON_SQRSHRUN_scalar: | |
5320 sqrshrun(vf, rd, rn, right_shift); | |
5321 break; | |
5322 case NEON_FCVTZS_imm_scalar: | |
5323 fcvts(vf, rd, rn, FPZero, right_shift); | |
5324 break; | |
5325 case NEON_FCVTZU_imm_scalar: | |
5326 fcvtu(vf, rd, rn, FPZero, right_shift); | |
5327 break; | |
5328 case NEON_SCVTF_imm_scalar: | |
5329 scvtf(vf, rd, rn, right_shift, fpcr_rounding); | |
5330 break; | |
5331 case NEON_UCVTF_imm_scalar: | |
5332 ucvtf(vf, rd, rn, right_shift, fpcr_rounding); | |
5333 break; | |
5334 default: | |
5335 UNIMPLEMENTED(); | |
5336 } | |
5337 } | |
5338 | |
5339 void Simulator::VisitNEONShiftImmediate(Instruction* instr) { | |
5340 SimVRegister& rd = vreg(instr->Rd()); | |
5341 SimVRegister& rn = vreg(instr->Rn()); | |
5342 FPRounding fpcr_rounding = static_cast<FPRounding>(fpcr().RMode()); | |
5343 | |
5344 // 00010->8B, 00011->16B, 001x0->4H, 001x1->8H, | |
5345 // 01xx0->2S, 01xx1->4S, 1xxx1->2D, all others undefined. | |
5346 static const NEONFormatMap map = { | |
5347 {22, 21, 20, 19, 30}, | |
5348 {NF_UNDEF, NF_UNDEF, NF_8B, NF_16B, NF_4H, NF_8H, NF_4H, NF_8H, | |
5349 NF_2S, NF_4S, NF_2S, NF_4S, NF_2S, NF_4S, NF_2S, NF_4S, | |
5350 NF_UNDEF, NF_2D, NF_UNDEF, NF_2D, NF_UNDEF, NF_2D, NF_UNDEF, NF_2D, | |
5351 NF_UNDEF, NF_2D, NF_UNDEF, NF_2D, NF_UNDEF, NF_2D, NF_UNDEF, NF_2D}}; | |
5352 NEONFormatDecoder nfd(instr, &map); | |
5353 VectorFormat vf = nfd.GetVectorFormat(); | |
5354 | |
5355 // 0001->8H, 001x->4S, 01xx->2D, all others undefined. | |
5356 static const NEONFormatMap map_l = { | |
5357 {22, 21, 20, 19}, | |
5358 {NF_UNDEF, NF_8H, NF_4S, NF_4S, NF_2D, NF_2D, NF_2D, NF_2D}}; | |
5359 VectorFormat vf_l = nfd.GetVectorFormat(&map_l); | |
5360 | |
5361 int highestSetBit = HighestSetBitPosition(instr->ImmNEONImmh()); | |
5362 int immhimmb = instr->ImmNEONImmhImmb(); | |
5363 int right_shift = (16 << highestSetBit) - immhimmb; | |
5364 int left_shift = immhimmb - (8 << highestSetBit); | |
5365 | |
5366 switch (instr->Mask(NEONShiftImmediateMask)) { | |
5367 case NEON_SHL: | |
5368 shl(vf, rd, rn, left_shift); | |
5369 break; | |
5370 case NEON_SLI: | |
5371 sli(vf, rd, rn, left_shift); | |
5372 break; | |
5373 case NEON_SQSHLU: | |
5374 sqshlu(vf, rd, rn, left_shift); | |
5375 break; | |
5376 case NEON_SRI: | |
5377 sri(vf, rd, rn, right_shift); | |
5378 break; | |
5379 case NEON_SSHR: | |
5380 sshr(vf, rd, rn, right_shift); | |
5381 break; | |
5382 case NEON_USHR: | |
5383 ushr(vf, rd, rn, right_shift); | |
5384 break; | |
5385 case NEON_SRSHR: | |
5386 sshr(vf, rd, rn, right_shift).Round(vf); | |
5387 break; | |
5388 case NEON_URSHR: | |
5389 ushr(vf, rd, rn, right_shift).Round(vf); | |
5390 break; | |
5391 case NEON_SSRA: | |
5392 ssra(vf, rd, rn, right_shift); | |
5393 break; | |
5394 case NEON_USRA: | |
5395 usra(vf, rd, rn, right_shift); | |
5396 break; | |
5397 case NEON_SRSRA: | |
5398 srsra(vf, rd, rn, right_shift); | |
5399 break; | |
5400 case NEON_URSRA: | |
5401 ursra(vf, rd, rn, right_shift); | |
5402 break; | |
5403 case NEON_SQSHL_imm: | |
5404 sqshl(vf, rd, rn, left_shift); | |
5405 break; | |
5406 case NEON_UQSHL_imm: | |
5407 uqshl(vf, rd, rn, left_shift); | |
5408 break; | |
5409 case NEON_SCVTF_imm: | |
5410 scvtf(vf, rd, rn, right_shift, fpcr_rounding); | |
5411 break; | |
5412 case NEON_UCVTF_imm: | |
5413 ucvtf(vf, rd, rn, right_shift, fpcr_rounding); | |
5414 break; | |
5415 case NEON_FCVTZS_imm: | |
5416 fcvts(vf, rd, rn, FPZero, right_shift); | |
5417 break; | |
5418 case NEON_FCVTZU_imm: | |
5419 fcvtu(vf, rd, rn, FPZero, right_shift); | |
5420 break; | |
5421 case NEON_SSHLL: | |
5422 vf = vf_l; | |
5423 if (instr->Mask(NEON_Q)) { | |
5424 sshll2(vf, rd, rn, left_shift); | |
5425 } else { | |
5426 sshll(vf, rd, rn, left_shift); | |
5427 } | |
5428 break; | |
5429 case NEON_USHLL: | |
5430 vf = vf_l; | |
5431 if (instr->Mask(NEON_Q)) { | |
5432 ushll2(vf, rd, rn, left_shift); | |
5433 } else { | |
5434 ushll(vf, rd, rn, left_shift); | |
5435 } | |
5436 break; | |
5437 case NEON_SHRN: | |
5438 if (instr->Mask(NEON_Q)) { | |
5439 shrn2(vf, rd, rn, right_shift); | |
5440 } else { | |
5441 shrn(vf, rd, rn, right_shift); | |
5442 } | |
5443 break; | |
5444 case NEON_RSHRN: | |
5445 if (instr->Mask(NEON_Q)) { | |
5446 rshrn2(vf, rd, rn, right_shift); | |
5447 } else { | |
5448 rshrn(vf, rd, rn, right_shift); | |
5449 } | |
5450 break; | |
5451 case NEON_UQSHRN: | |
5452 if (instr->Mask(NEON_Q)) { | |
5453 uqshrn2(vf, rd, rn, right_shift); | |
5454 } else { | |
5455 uqshrn(vf, rd, rn, right_shift); | |
5456 } | |
5457 break; | |
5458 case NEON_UQRSHRN: | |
5459 if (instr->Mask(NEON_Q)) { | |
5460 uqrshrn2(vf, rd, rn, right_shift); | |
5461 } else { | |
5462 uqrshrn(vf, rd, rn, right_shift); | |
5463 } | |
5464 break; | |
5465 case NEON_SQSHRN: | |
5466 if (instr->Mask(NEON_Q)) { | |
5467 sqshrn2(vf, rd, rn, right_shift); | |
5468 } else { | |
5469 sqshrn(vf, rd, rn, right_shift); | |
5470 } | |
5471 break; | |
5472 case NEON_SQRSHRN: | |
5473 if (instr->Mask(NEON_Q)) { | |
5474 sqrshrn2(vf, rd, rn, right_shift); | |
5475 } else { | |
5476 sqrshrn(vf, rd, rn, right_shift); | |
5477 } | |
5478 break; | |
5479 case NEON_SQSHRUN: | |
5480 if (instr->Mask(NEON_Q)) { | |
5481 sqshrun2(vf, rd, rn, right_shift); | |
5482 } else { | |
5483 sqshrun(vf, rd, rn, right_shift); | |
5484 } | |
5485 break; | |
5486 case NEON_SQRSHRUN: | |
5487 if (instr->Mask(NEON_Q)) { | |
5488 sqrshrun2(vf, rd, rn, right_shift); | |
5489 } else { | |
5490 sqrshrun(vf, rd, rn, right_shift); | |
5491 } | |
5492 break; | |
5493 default: | |
5494 UNIMPLEMENTED(); | |
5495 } | |
5496 } | |
5497 | |
5498 void Simulator::VisitNEONTable(Instruction* instr) { | |
5499 NEONFormatDecoder nfd(instr, NEONFormatDecoder::LogicalFormatMap()); | |
5500 VectorFormat vf = nfd.GetVectorFormat(); | |
5501 | |
5502 SimVRegister& rd = vreg(instr->Rd()); | |
5503 SimVRegister& rn = vreg(instr->Rn()); | |
5504 SimVRegister& rn2 = vreg((instr->Rn() + 1) % kNumberOfVRegisters); | |
5505 SimVRegister& rn3 = vreg((instr->Rn() + 2) % kNumberOfVRegisters); | |
5506 SimVRegister& rn4 = vreg((instr->Rn() + 3) % kNumberOfVRegisters); | |
5507 SimVRegister& rm = vreg(instr->Rm()); | |
5508 | |
5509 switch (instr->Mask(NEONTableMask)) { | |
5510 case NEON_TBL_1v: | |
5511 tbl(vf, rd, rn, rm); | |
5512 break; | |
5513 case NEON_TBL_2v: | |
5514 tbl(vf, rd, rn, rn2, rm); | |
5515 break; | |
5516 case NEON_TBL_3v: | |
5517 tbl(vf, rd, rn, rn2, rn3, rm); | |
5518 break; | |
5519 case NEON_TBL_4v: | |
5520 tbl(vf, rd, rn, rn2, rn3, rn4, rm); | |
5521 break; | |
5522 case NEON_TBX_1v: | |
5523 tbx(vf, rd, rn, rm); | |
5524 break; | |
5525 case NEON_TBX_2v: | |
5526 tbx(vf, rd, rn, rn2, rm); | |
5527 break; | |
5528 case NEON_TBX_3v: | |
5529 tbx(vf, rd, rn, rn2, rn3, rm); | |
5530 break; | |
5531 case NEON_TBX_4v: | |
5532 tbx(vf, rd, rn, rn2, rn3, rn4, rm); | |
5533 break; | |
5534 default: | |
5535 UNIMPLEMENTED(); | |
5536 } | |
5537 } | |
5538 | |
5539 void Simulator::VisitNEONPerm(Instruction* instr) { | |
5540 NEONFormatDecoder nfd(instr); | |
5541 VectorFormat vf = nfd.GetVectorFormat(); | |
5542 | |
5543 SimVRegister& rd = vreg(instr->Rd()); | |
5544 SimVRegister& rn = vreg(instr->Rn()); | |
5545 SimVRegister& rm = vreg(instr->Rm()); | |
5546 | |
5547 switch (instr->Mask(NEONPermMask)) { | |
5548 case NEON_TRN1: | |
5549 trn1(vf, rd, rn, rm); | |
5550 break; | |
5551 case NEON_TRN2: | |
5552 trn2(vf, rd, rn, rm); | |
5553 break; | |
5554 case NEON_UZP1: | |
5555 uzp1(vf, rd, rn, rm); | |
5556 break; | |
5557 case NEON_UZP2: | |
5558 uzp2(vf, rd, rn, rm); | |
5559 break; | |
5560 case NEON_ZIP1: | |
5561 zip1(vf, rd, rn, rm); | |
5562 break; | |
5563 case NEON_ZIP2: | |
5564 zip2(vf, rd, rn, rm); | |
5565 break; | |
5566 default: | |
5567 UNIMPLEMENTED(); | |
5568 } | |
5569 } | |
3754 | 5570 |
3755 void Simulator::DoPrintf(Instruction* instr) { | 5571 void Simulator::DoPrintf(Instruction* instr) { |
3756 DCHECK((instr->Mask(ExceptionMask) == HLT) && | 5572 DCHECK((instr->Mask(ExceptionMask) == HLT) && |
3757 (instr->ImmException() == kImmExceptionIsPrintf)); | 5573 (instr->ImmException() == kImmExceptionIsPrintf)); |
3758 | 5574 |
3759 // Read the arguments encoded inline in the instruction stream. | 5575 // Read the arguments encoded inline in the instruction stream. |
3760 uint32_t arg_count; | 5576 uint32_t arg_count; |
3761 uint32_t arg_pattern_list; | 5577 uint32_t arg_pattern_list; |
3762 STATIC_ASSERT(sizeof(*instr) == 1); | 5578 STATIC_ASSERT(sizeof(*instr) == 1); |
3763 memcpy(&arg_count, | 5579 memcpy(&arg_count, |
(...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3877 delete[] format; | 5693 delete[] format; |
3878 } | 5694 } |
3879 | 5695 |
3880 | 5696 |
3881 #endif // USE_SIMULATOR | 5697 #endif // USE_SIMULATOR |
3882 | 5698 |
3883 } // namespace internal | 5699 } // namespace internal |
3884 } // namespace v8 | 5700 } // namespace v8 |
3885 | 5701 |
3886 #endif // V8_TARGET_ARCH_ARM64 | 5702 #endif // V8_TARGET_ARCH_ARM64 |
OLD | NEW |