| 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 #if V8_TARGET_ARCH_ARM64 | 5 #if V8_TARGET_ARCH_ARM64 |
| 6 | 6 |
| 7 #include "src/arm64/frames-arm64.h" | 7 #include "src/arm64/frames-arm64.h" |
| 8 #include "src/assembler.h" | 8 #include "src/assembler.h" |
| 9 #include "src/base/bits.h" | 9 #include "src/base/bits.h" |
| 10 #include "src/base/division-by-constant.h" | 10 #include "src/base/division-by-constant.h" |
| (...skipping 277 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 288 dst = rd; | 288 dst = rd; |
| 289 } | 289 } |
| 290 | 290 |
| 291 // Copy the result to the system stack pointer. | 291 // Copy the result to the system stack pointer. |
| 292 if (!dst.Is(rd)) { | 292 if (!dst.Is(rd)) { |
| 293 DCHECK(rd.IsSP()); | 293 DCHECK(rd.IsSP()); |
| 294 Assembler::mov(rd, dst); | 294 Assembler::mov(rd, dst); |
| 295 } | 295 } |
| 296 } | 296 } |
| 297 | 297 |
| 298 void MacroAssembler::Movi16bitHelper(const VRegister& vd, uint64_t imm) { |
| 299 DCHECK(is_uint16(imm)); |
| 300 int byte1 = (imm & 0xff); |
| 301 int byte2 = ((imm >> 8) & 0xff); |
| 302 if (byte1 == byte2) { |
| 303 movi(vd.Is64Bits() ? vd.V8B() : vd.V16B(), byte1); |
| 304 } else if (byte1 == 0) { |
| 305 movi(vd, byte2, LSL, 8); |
| 306 } else if (byte2 == 0) { |
| 307 movi(vd, byte1); |
| 308 } else if (byte1 == 0xff) { |
| 309 mvni(vd, ~byte2 & 0xff, LSL, 8); |
| 310 } else if (byte2 == 0xff) { |
| 311 mvni(vd, ~byte1 & 0xff); |
| 312 } else { |
| 313 UseScratchRegisterScope temps(this); |
| 314 Register temp = temps.AcquireW(); |
| 315 movz(temp, imm); |
| 316 dup(vd, temp); |
| 317 } |
| 318 } |
| 319 |
| 320 void MacroAssembler::Movi32bitHelper(const VRegister& vd, uint64_t imm) { |
| 321 DCHECK(is_uint32(imm)); |
| 322 |
| 323 uint8_t bytes[sizeof(imm)]; |
| 324 memcpy(bytes, &imm, sizeof(imm)); |
| 325 |
| 326 // All bytes are either 0x00 or 0xff. |
| 327 { |
| 328 bool all0orff = true; |
| 329 for (int i = 0; i < 4; ++i) { |
| 330 if ((bytes[i] != 0) && (bytes[i] != 0xff)) { |
| 331 all0orff = false; |
| 332 break; |
| 333 } |
| 334 } |
| 335 |
| 336 if (all0orff == true) { |
| 337 movi(vd.Is64Bits() ? vd.V1D() : vd.V2D(), ((imm << 32) | imm)); |
| 338 return; |
| 339 } |
| 340 } |
| 341 |
| 342 // Of the 4 bytes, only one byte is non-zero. |
| 343 for (int i = 0; i < 4; i++) { |
| 344 if ((imm & (0xff << (i * 8))) == imm) { |
| 345 movi(vd, bytes[i], LSL, i * 8); |
| 346 return; |
| 347 } |
| 348 } |
| 349 |
| 350 // Of the 4 bytes, only one byte is not 0xff. |
| 351 for (int i = 0; i < 4; i++) { |
| 352 uint32_t mask = ~(0xff << (i * 8)); |
| 353 if ((imm & mask) == mask) { |
| 354 mvni(vd, ~bytes[i] & 0xff, LSL, i * 8); |
| 355 return; |
| 356 } |
| 357 } |
| 358 |
| 359 // Immediate is of the form 0x00MMFFFF. |
| 360 if ((imm & 0xff00ffff) == 0x0000ffff) { |
| 361 movi(vd, bytes[2], MSL, 16); |
| 362 return; |
| 363 } |
| 364 |
| 365 // Immediate is of the form 0x0000MMFF. |
| 366 if ((imm & 0xffff00ff) == 0x000000ff) { |
| 367 movi(vd, bytes[1], MSL, 8); |
| 368 return; |
| 369 } |
| 370 |
| 371 // Immediate is of the form 0xFFMM0000. |
| 372 if ((imm & 0xff00ffff) == 0xff000000) { |
| 373 mvni(vd, ~bytes[2] & 0xff, MSL, 16); |
| 374 return; |
| 375 } |
| 376 // Immediate is of the form 0xFFFFMM00. |
| 377 if ((imm & 0xffff00ff) == 0xffff0000) { |
| 378 mvni(vd, ~bytes[1] & 0xff, MSL, 8); |
| 379 return; |
| 380 } |
| 381 |
| 382 // Top and bottom 16-bits are equal. |
| 383 if (((imm >> 16) & 0xffff) == (imm & 0xffff)) { |
| 384 Movi16bitHelper(vd.Is64Bits() ? vd.V4H() : vd.V8H(), imm & 0xffff); |
| 385 return; |
| 386 } |
| 387 |
| 388 // Default case. |
| 389 { |
| 390 UseScratchRegisterScope temps(this); |
| 391 Register temp = temps.AcquireW(); |
| 392 Mov(temp, imm); |
| 393 dup(vd, temp); |
| 394 } |
| 395 } |
| 396 |
| 397 void MacroAssembler::Movi64bitHelper(const VRegister& vd, uint64_t imm) { |
| 398 // All bytes are either 0x00 or 0xff. |
| 399 { |
| 400 bool all0orff = true; |
| 401 for (int i = 0; i < 8; ++i) { |
| 402 int byteval = (imm >> (i * 8)) & 0xff; |
| 403 if (byteval != 0 && byteval != 0xff) { |
| 404 all0orff = false; |
| 405 break; |
| 406 } |
| 407 } |
| 408 if (all0orff == true) { |
| 409 movi(vd, imm); |
| 410 return; |
| 411 } |
| 412 } |
| 413 |
| 414 // Top and bottom 32-bits are equal. |
| 415 if (((imm >> 32) & 0xffffffff) == (imm & 0xffffffff)) { |
| 416 Movi32bitHelper(vd.Is64Bits() ? vd.V2S() : vd.V4S(), imm & 0xffffffff); |
| 417 return; |
| 418 } |
| 419 |
| 420 // Default case. |
| 421 { |
| 422 UseScratchRegisterScope temps(this); |
| 423 Register temp = temps.AcquireX(); |
| 424 Mov(temp, imm); |
| 425 if (vd.Is1D()) { |
| 426 mov(vd.D(), 0, temp); |
| 427 } else { |
| 428 dup(vd.V2D(), temp); |
| 429 } |
| 430 } |
| 431 } |
| 432 |
| 433 void MacroAssembler::Movi(const VRegister& vd, uint64_t imm, Shift shift, |
| 434 int shift_amount) { |
| 435 DCHECK(allow_macro_instructions_); |
| 436 if (shift_amount != 0 || shift != LSL) { |
| 437 movi(vd, imm, shift, shift_amount); |
| 438 } else if (vd.Is8B() || vd.Is16B()) { |
| 439 // 8-bit immediate. |
| 440 DCHECK(is_uint8(imm)); |
| 441 movi(vd, imm); |
| 442 } else if (vd.Is4H() || vd.Is8H()) { |
| 443 // 16-bit immediate. |
| 444 Movi16bitHelper(vd, imm); |
| 445 } else if (vd.Is2S() || vd.Is4S()) { |
| 446 // 32-bit immediate. |
| 447 Movi32bitHelper(vd, imm); |
| 448 } else { |
| 449 // 64-bit immediate. |
| 450 Movi64bitHelper(vd, imm); |
| 451 } |
| 452 } |
| 453 |
| 454 void MacroAssembler::Movi(const VRegister& vd, uint64_t hi, uint64_t lo) { |
| 455 // TODO(all): Move 128-bit values in a more efficient way. |
| 456 DCHECK(vd.Is128Bits()); |
| 457 UseScratchRegisterScope temps(this); |
| 458 Movi(vd.V2D(), lo); |
| 459 Register temp = temps.AcquireX(); |
| 460 Mov(temp, hi); |
| 461 Ins(vd.V2D(), 1, temp); |
| 462 } |
| 298 | 463 |
| 299 void MacroAssembler::Mvn(const Register& rd, const Operand& operand) { | 464 void MacroAssembler::Mvn(const Register& rd, const Operand& operand) { |
| 300 DCHECK(allow_macro_instructions_); | 465 DCHECK(allow_macro_instructions_); |
| 301 | 466 |
| 302 if (operand.NeedsRelocation(this)) { | 467 if (operand.NeedsRelocation(this)) { |
| 303 Ldr(rd, operand.immediate()); | 468 Ldr(rd, operand.immediate()); |
| 304 mvn(rd, rd); | 469 mvn(rd, rd); |
| 305 | 470 |
| 306 } else if (operand.IsImmediate()) { | 471 } else if (operand.IsImmediate()) { |
| 307 // Call the macro assembler for generic immediates. | 472 // Call the macro assembler for generic immediates. |
| (...skipping 251 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 559 // The addressing mode is directly supported by the instruction. | 724 // The addressing mode is directly supported by the instruction. |
| 560 AddSubWithCarry(rd, rn, operand, S, op); | 725 AddSubWithCarry(rd, rn, operand, S, op); |
| 561 } | 726 } |
| 562 } | 727 } |
| 563 | 728 |
| 564 | 729 |
| 565 void MacroAssembler::LoadStoreMacro(const CPURegister& rt, | 730 void MacroAssembler::LoadStoreMacro(const CPURegister& rt, |
| 566 const MemOperand& addr, | 731 const MemOperand& addr, |
| 567 LoadStoreOp op) { | 732 LoadStoreOp op) { |
| 568 int64_t offset = addr.offset(); | 733 int64_t offset = addr.offset(); |
| 569 LSDataSize size = CalcLSDataSize(op); | 734 unsigned size = CalcLSDataSize(op); |
| 570 | 735 |
| 571 // Check if an immediate offset fits in the immediate field of the | 736 // Check if an immediate offset fits in the immediate field of the |
| 572 // appropriate instruction. If not, emit two instructions to perform | 737 // appropriate instruction. If not, emit two instructions to perform |
| 573 // the operation. | 738 // the operation. |
| 574 if (addr.IsImmediateOffset() && !IsImmLSScaled(offset, size) && | 739 if (addr.IsImmediateOffset() && !IsImmLSScaled(offset, size) && |
| 575 !IsImmLSUnscaled(offset)) { | 740 !IsImmLSUnscaled(offset)) { |
| 576 // Immediate offset that can't be encoded using unsigned or unscaled | 741 // Immediate offset that can't be encoded using unsigned or unscaled |
| 577 // addressing modes. | 742 // addressing modes. |
| 578 UseScratchRegisterScope temps(this); | 743 UseScratchRegisterScope temps(this); |
| 579 Register temp = temps.AcquireSameSizeAs(addr.base()); | 744 Register temp = temps.AcquireSameSizeAs(addr.base()); |
| (...skipping 14 matching lines...) Expand all Loading... |
| 594 } | 759 } |
| 595 | 760 |
| 596 void MacroAssembler::LoadStorePairMacro(const CPURegister& rt, | 761 void MacroAssembler::LoadStorePairMacro(const CPURegister& rt, |
| 597 const CPURegister& rt2, | 762 const CPURegister& rt2, |
| 598 const MemOperand& addr, | 763 const MemOperand& addr, |
| 599 LoadStorePairOp op) { | 764 LoadStorePairOp op) { |
| 600 // TODO(all): Should we support register offset for load-store-pair? | 765 // TODO(all): Should we support register offset for load-store-pair? |
| 601 DCHECK(!addr.IsRegisterOffset()); | 766 DCHECK(!addr.IsRegisterOffset()); |
| 602 | 767 |
| 603 int64_t offset = addr.offset(); | 768 int64_t offset = addr.offset(); |
| 604 LSDataSize size = CalcLSPairDataSize(op); | 769 unsigned size = CalcLSPairDataSize(op); |
| 605 | 770 |
| 606 // Check if the offset fits in the immediate field of the appropriate | 771 // Check if the offset fits in the immediate field of the appropriate |
| 607 // instruction. If not, emit two instructions to perform the operation. | 772 // instruction. If not, emit two instructions to perform the operation. |
| 608 if (IsImmLSPair(offset, size)) { | 773 if (IsImmLSPair(offset, size)) { |
| 609 // Encodable in one load/store pair instruction. | 774 // Encodable in one load/store pair instruction. |
| 610 LoadStorePair(rt, rt2, addr, op); | 775 LoadStorePair(rt, rt2, addr, op); |
| 611 } else { | 776 } else { |
| 612 Register base = addr.base(); | 777 Register base = addr.base(); |
| 613 if (addr.IsImmediateOffset()) { | 778 if (addr.IsImmediateOffset()) { |
| 614 UseScratchRegisterScope temps(this); | 779 UseScratchRegisterScope temps(this); |
| (...skipping 307 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 922 DCHECK(dst0.IsValid()); | 1087 DCHECK(dst0.IsValid()); |
| 923 | 1088 |
| 924 int count = 5 + dst5.IsValid() + dst6.IsValid() + dst7.IsValid(); | 1089 int count = 5 + dst5.IsValid() + dst6.IsValid() + dst7.IsValid(); |
| 925 int size = dst0.SizeInBytes(); | 1090 int size = dst0.SizeInBytes(); |
| 926 | 1091 |
| 927 PopHelper(4, size, dst0, dst1, dst2, dst3); | 1092 PopHelper(4, size, dst0, dst1, dst2, dst3); |
| 928 PopHelper(count - 4, size, dst4, dst5, dst6, dst7); | 1093 PopHelper(count - 4, size, dst4, dst5, dst6, dst7); |
| 929 PopPostamble(count, size); | 1094 PopPostamble(count, size); |
| 930 } | 1095 } |
| 931 | 1096 |
| 932 | 1097 void MacroAssembler::Push(const Register& src0, const VRegister& src1) { |
| 933 void MacroAssembler::Push(const Register& src0, const FPRegister& src1) { | |
| 934 int size = src0.SizeInBytes() + src1.SizeInBytes(); | 1098 int size = src0.SizeInBytes() + src1.SizeInBytes(); |
| 935 | 1099 |
| 936 PushPreamble(size); | 1100 PushPreamble(size); |
| 937 // Reserve room for src0 and push src1. | 1101 // Reserve room for src0 and push src1. |
| 938 str(src1, MemOperand(StackPointer(), -size, PreIndex)); | 1102 str(src1, MemOperand(StackPointer(), -size, PreIndex)); |
| 939 // Fill the gap with src0. | 1103 // Fill the gap with src0. |
| 940 str(src0, MemOperand(StackPointer(), src1.SizeInBytes())); | 1104 str(src0, MemOperand(StackPointer(), src1.SizeInBytes())); |
| 941 } | 1105 } |
| 942 | 1106 |
| 943 | 1107 |
| (...skipping 446 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1390 Tst(fpcr, RMode_mask); | 1554 Tst(fpcr, RMode_mask); |
| 1391 B(eq, &done); | 1555 B(eq, &done); |
| 1392 | 1556 |
| 1393 Bind(&unexpected_mode); | 1557 Bind(&unexpected_mode); |
| 1394 Abort(kUnexpectedFPCRMode); | 1558 Abort(kUnexpectedFPCRMode); |
| 1395 | 1559 |
| 1396 Bind(&done); | 1560 Bind(&done); |
| 1397 } | 1561 } |
| 1398 } | 1562 } |
| 1399 | 1563 |
| 1400 | 1564 void MacroAssembler::CanonicalizeNaN(const VRegister& dst, |
| 1401 void MacroAssembler::CanonicalizeNaN(const FPRegister& dst, | 1565 const VRegister& src) { |
| 1402 const FPRegister& src) { | |
| 1403 AssertFPCRState(); | 1566 AssertFPCRState(); |
| 1404 | 1567 |
| 1405 // Subtracting 0.0 preserves all inputs except for signalling NaNs, which | 1568 // Subtracting 0.0 preserves all inputs except for signalling NaNs, which |
| 1406 // become quiet NaNs. We use fsub rather than fadd because fsub preserves -0.0 | 1569 // become quiet NaNs. We use fsub rather than fadd because fsub preserves -0.0 |
| 1407 // inputs: -0.0 + 0.0 = 0.0, but -0.0 - 0.0 = -0.0. | 1570 // inputs: -0.0 + 0.0 = 0.0, but -0.0 - 0.0 = -0.0. |
| 1408 Fsub(dst, src, fp_zero); | 1571 Fsub(dst, src, fp_zero); |
| 1409 } | 1572 } |
| 1410 | 1573 |
| 1411 | 1574 |
| 1412 void MacroAssembler::LoadRoot(CPURegister destination, | 1575 void MacroAssembler::LoadRoot(CPURegister destination, |
| (...skipping 612 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2025 } | 2188 } |
| 2026 | 2189 |
| 2027 AssertNotSmi(object); | 2190 AssertNotSmi(object); |
| 2028 | 2191 |
| 2029 UseScratchRegisterScope temps(this); | 2192 UseScratchRegisterScope temps(this); |
| 2030 Register temp = temps.AcquireX(); | 2193 Register temp = temps.AcquireX(); |
| 2031 Ldr(temp, FieldMemOperand(object, HeapObject::kMapOffset)); | 2194 Ldr(temp, FieldMemOperand(object, HeapObject::kMapOffset)); |
| 2032 JumpIfNotRoot(temp, Heap::kHeapNumberMapRootIndex, on_not_heap_number); | 2195 JumpIfNotRoot(temp, Heap::kHeapNumberMapRootIndex, on_not_heap_number); |
| 2033 } | 2196 } |
| 2034 | 2197 |
| 2035 | 2198 void MacroAssembler::TryRepresentDoubleAsInt(Register as_int, VRegister value, |
| 2036 void MacroAssembler::TryRepresentDoubleAsInt(Register as_int, | 2199 VRegister scratch_d, |
| 2037 FPRegister value, | |
| 2038 FPRegister scratch_d, | |
| 2039 Label* on_successful_conversion, | 2200 Label* on_successful_conversion, |
| 2040 Label* on_failed_conversion) { | 2201 Label* on_failed_conversion) { |
| 2041 // Convert to an int and back again, then compare with the original value. | 2202 // Convert to an int and back again, then compare with the original value. |
| 2042 Fcvtzs(as_int, value); | 2203 Fcvtzs(as_int, value); |
| 2043 Scvtf(scratch_d, as_int); | 2204 Scvtf(scratch_d, as_int); |
| 2044 Fcmp(value, scratch_d); | 2205 Fcmp(value, scratch_d); |
| 2045 | 2206 |
| 2046 if (on_successful_conversion) { | 2207 if (on_successful_conversion) { |
| 2047 B(on_successful_conversion, eq); | 2208 B(on_successful_conversion, eq); |
| 2048 } | 2209 } |
| (...skipping 593 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2642 // Drop the execution stack down to the frame pointer and restore | 2803 // Drop the execution stack down to the frame pointer and restore |
| 2643 // the caller frame pointer and return address. | 2804 // the caller frame pointer and return address. |
| 2644 Mov(jssp, fp); | 2805 Mov(jssp, fp); |
| 2645 AssertStackConsistency(); | 2806 AssertStackConsistency(); |
| 2646 Pop(fp, lr); | 2807 Pop(fp, lr); |
| 2647 } | 2808 } |
| 2648 } | 2809 } |
| 2649 | 2810 |
| 2650 | 2811 |
| 2651 void MacroAssembler::ExitFramePreserveFPRegs() { | 2812 void MacroAssembler::ExitFramePreserveFPRegs() { |
| 2652 PushCPURegList(kCallerSavedFP); | 2813 PushCPURegList(kCallerSavedV); |
| 2653 } | 2814 } |
| 2654 | 2815 |
| 2655 | 2816 |
| 2656 void MacroAssembler::ExitFrameRestoreFPRegs() { | 2817 void MacroAssembler::ExitFrameRestoreFPRegs() { |
| 2657 // Read the registers from the stack without popping them. The stack pointer | 2818 // Read the registers from the stack without popping them. The stack pointer |
| 2658 // will be reset as part of the unwinding process. | 2819 // will be reset as part of the unwinding process. |
| 2659 CPURegList saved_fp_regs = kCallerSavedFP; | 2820 CPURegList saved_fp_regs = kCallerSavedV; |
| 2660 DCHECK(saved_fp_regs.Count() % 2 == 0); | 2821 DCHECK(saved_fp_regs.Count() % 2 == 0); |
| 2661 | 2822 |
| 2662 int offset = ExitFrameConstants::kLastExitFrameField; | 2823 int offset = ExitFrameConstants::kLastExitFrameField; |
| 2663 while (!saved_fp_regs.IsEmpty()) { | 2824 while (!saved_fp_regs.IsEmpty()) { |
| 2664 const CPURegister& dst0 = saved_fp_regs.PopHighestIndex(); | 2825 const CPURegister& dst0 = saved_fp_regs.PopHighestIndex(); |
| 2665 const CPURegister& dst1 = saved_fp_regs.PopHighestIndex(); | 2826 const CPURegister& dst1 = saved_fp_regs.PopHighestIndex(); |
| 2666 offset -= 2 * kDRegSize; | 2827 offset -= 2 * kDRegSize; |
| 2667 Ldp(dst1, dst0, MemOperand(fp, offset)); | 2828 Ldp(dst1, dst0, MemOperand(fp, offset)); |
| 2668 } | 2829 } |
| 2669 } | 2830 } |
| (...skipping 458 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3128 NO_ALLOCATION_FLAGS); | 3289 NO_ALLOCATION_FLAGS); |
| 3129 | 3290 |
| 3130 Heap::RootListIndex map_index = mode == MUTABLE | 3291 Heap::RootListIndex map_index = mode == MUTABLE |
| 3131 ? Heap::kMutableHeapNumberMapRootIndex | 3292 ? Heap::kMutableHeapNumberMapRootIndex |
| 3132 : Heap::kHeapNumberMapRootIndex; | 3293 : Heap::kHeapNumberMapRootIndex; |
| 3133 | 3294 |
| 3134 // Prepare the heap number map. | 3295 // Prepare the heap number map. |
| 3135 if (!heap_number_map.IsValid()) { | 3296 if (!heap_number_map.IsValid()) { |
| 3136 // If we have a valid value register, use the same type of register to store | 3297 // If we have a valid value register, use the same type of register to store |
| 3137 // the map so we can use STP to store both in one instruction. | 3298 // the map so we can use STP to store both in one instruction. |
| 3138 if (value.IsValid() && value.IsFPRegister()) { | 3299 if (value.IsValid() && value.IsVRegister()) { |
| 3139 heap_number_map = temps.AcquireD(); | 3300 heap_number_map = temps.AcquireD(); |
| 3140 } else { | 3301 } else { |
| 3141 heap_number_map = scratch1; | 3302 heap_number_map = scratch1; |
| 3142 } | 3303 } |
| 3143 LoadRoot(heap_number_map, map_index); | 3304 LoadRoot(heap_number_map, map_index); |
| 3144 } | 3305 } |
| 3145 if (emit_debug_code()) { | 3306 if (emit_debug_code()) { |
| 3146 Register map; | 3307 Register map; |
| 3147 if (heap_number_map.IsFPRegister()) { | 3308 if (heap_number_map.IsVRegister()) { |
| 3148 map = scratch1; | 3309 map = scratch1; |
| 3149 Fmov(map, DoubleRegister(heap_number_map)); | 3310 Fmov(map, DoubleRegister(heap_number_map)); |
| 3150 } else { | 3311 } else { |
| 3151 map = Register(heap_number_map); | 3312 map = Register(heap_number_map); |
| 3152 } | 3313 } |
| 3153 AssertRegisterIsRoot(map, map_index); | 3314 AssertRegisterIsRoot(map, map_index); |
| 3154 } | 3315 } |
| 3155 | 3316 |
| 3156 // Store the heap number map and the value in the allocated object. | 3317 // Store the heap number map and the value in the allocated object. |
| 3157 if (value.IsSameSizeAndType(heap_number_map)) { | 3318 if (value.IsSameSizeAndType(heap_number_map)) { |
| (...skipping 441 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3599 const int num_unsaved = kNumSafepointRegisters - kNumSafepointSavedRegisters; | 3760 const int num_unsaved = kNumSafepointRegisters - kNumSafepointSavedRegisters; |
| 3600 DCHECK(num_unsaved >= 0); | 3761 DCHECK(num_unsaved >= 0); |
| 3601 Claim(num_unsaved); | 3762 Claim(num_unsaved); |
| 3602 PushXRegList(kSafepointSavedRegisters); | 3763 PushXRegList(kSafepointSavedRegisters); |
| 3603 } | 3764 } |
| 3604 | 3765 |
| 3605 | 3766 |
| 3606 void MacroAssembler::PushSafepointRegistersAndDoubles() { | 3767 void MacroAssembler::PushSafepointRegistersAndDoubles() { |
| 3607 PushSafepointRegisters(); | 3768 PushSafepointRegisters(); |
| 3608 PushCPURegList(CPURegList( | 3769 PushCPURegList(CPURegList( |
| 3609 CPURegister::kFPRegister, kDRegSizeInBits, | 3770 CPURegister::kVRegister, kDRegSizeInBits, |
| 3610 RegisterConfiguration::Crankshaft()->allocatable_double_codes_mask())); | 3771 RegisterConfiguration::Crankshaft()->allocatable_double_codes_mask())); |
| 3611 } | 3772 } |
| 3612 | 3773 |
| 3613 | 3774 |
| 3614 void MacroAssembler::PopSafepointRegistersAndDoubles() { | 3775 void MacroAssembler::PopSafepointRegistersAndDoubles() { |
| 3615 PopCPURegList(CPURegList( | 3776 PopCPURegList(CPURegList( |
| 3616 CPURegister::kFPRegister, kDRegSizeInBits, | 3777 CPURegister::kVRegister, kDRegSizeInBits, |
| 3617 RegisterConfiguration::Crankshaft()->allocatable_double_codes_mask())); | 3778 RegisterConfiguration::Crankshaft()->allocatable_double_codes_mask())); |
| 3618 PopSafepointRegisters(); | 3779 PopSafepointRegisters(); |
| 3619 } | 3780 } |
| 3620 | 3781 |
| 3621 void MacroAssembler::StoreToSafepointRegisterSlot(Register src, Register dst) { | 3782 void MacroAssembler::StoreToSafepointRegisterSlot(Register src, Register dst) { |
| 3622 Poke(src, SafepointRegisterStackIndex(dst.code()) * kPointerSize); | 3783 Poke(src, SafepointRegisterStackIndex(dst.code()) * kPointerSize); |
| 3623 } | 3784 } |
| 3624 | 3785 |
| 3625 void MacroAssembler::LoadFromSafepointRegisterSlot(Register dst, Register src) { | 3786 void MacroAssembler::LoadFromSafepointRegisterSlot(Register dst, Register src) { |
| 3626 Peek(src, SafepointRegisterStackIndex(dst.code()) * kPointerSize); | 3787 Peek(src, SafepointRegisterStackIndex(dst.code()) * kPointerSize); |
| (...skipping 531 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4158 CPURegister args[kPrintfMaxArgCount] = {arg0, arg1, arg2, arg3}; | 4319 CPURegister args[kPrintfMaxArgCount] = {arg0, arg1, arg2, arg3}; |
| 4159 CPURegister pcs[kPrintfMaxArgCount] = {NoReg, NoReg, NoReg, NoReg}; | 4320 CPURegister pcs[kPrintfMaxArgCount] = {NoReg, NoReg, NoReg, NoReg}; |
| 4160 | 4321 |
| 4161 int arg_count = kPrintfMaxArgCount; | 4322 int arg_count = kPrintfMaxArgCount; |
| 4162 | 4323 |
| 4163 // The PCS varargs registers for printf. Note that x0 is used for the printf | 4324 // The PCS varargs registers for printf. Note that x0 is used for the printf |
| 4164 // format string. | 4325 // format string. |
| 4165 static const CPURegList kPCSVarargs = | 4326 static const CPURegList kPCSVarargs = |
| 4166 CPURegList(CPURegister::kRegister, kXRegSizeInBits, 1, arg_count); | 4327 CPURegList(CPURegister::kRegister, kXRegSizeInBits, 1, arg_count); |
| 4167 static const CPURegList kPCSVarargsFP = | 4328 static const CPURegList kPCSVarargsFP = |
| 4168 CPURegList(CPURegister::kFPRegister, kDRegSizeInBits, 0, arg_count - 1); | 4329 CPURegList(CPURegister::kVRegister, kDRegSizeInBits, 0, arg_count - 1); |
| 4169 | 4330 |
| 4170 // We can use caller-saved registers as scratch values, except for the | 4331 // We can use caller-saved registers as scratch values, except for the |
| 4171 // arguments and the PCS registers where they might need to go. | 4332 // arguments and the PCS registers where they might need to go. |
| 4172 CPURegList tmp_list = kCallerSaved; | 4333 CPURegList tmp_list = kCallerSaved; |
| 4173 tmp_list.Remove(x0); // Used to pass the format string. | 4334 tmp_list.Remove(x0); // Used to pass the format string. |
| 4174 tmp_list.Remove(kPCSVarargs); | 4335 tmp_list.Remove(kPCSVarargs); |
| 4175 tmp_list.Remove(arg0, arg1, arg2, arg3); | 4336 tmp_list.Remove(arg0, arg1, arg2, arg3); |
| 4176 | 4337 |
| 4177 CPURegList fp_tmp_list = kCallerSavedFP; | 4338 CPURegList fp_tmp_list = kCallerSavedV; |
| 4178 fp_tmp_list.Remove(kPCSVarargsFP); | 4339 fp_tmp_list.Remove(kPCSVarargsFP); |
| 4179 fp_tmp_list.Remove(arg0, arg1, arg2, arg3); | 4340 fp_tmp_list.Remove(arg0, arg1, arg2, arg3); |
| 4180 | 4341 |
| 4181 // Override the MacroAssembler's scratch register list. The lists will be | 4342 // Override the MacroAssembler's scratch register list. The lists will be |
| 4182 // reset automatically at the end of the UseScratchRegisterScope. | 4343 // reset automatically at the end of the UseScratchRegisterScope. |
| 4183 UseScratchRegisterScope temps(this); | 4344 UseScratchRegisterScope temps(this); |
| 4184 TmpList()->set_list(tmp_list.list()); | 4345 TmpList()->set_list(tmp_list.list()); |
| 4185 FPTmpList()->set_list(fp_tmp_list.list()); | 4346 FPTmpList()->set_list(fp_tmp_list.list()); |
| 4186 | 4347 |
| 4187 // Copies of the printf vararg registers that we can pop from. | 4348 // Copies of the printf vararg registers that we can pop from. |
| 4188 CPURegList pcs_varargs = kPCSVarargs; | 4349 CPURegList pcs_varargs = kPCSVarargs; |
| 4189 CPURegList pcs_varargs_fp = kPCSVarargsFP; | 4350 CPURegList pcs_varargs_fp = kPCSVarargsFP; |
| 4190 | 4351 |
| 4191 // Place the arguments. There are lots of clever tricks and optimizations we | 4352 // Place the arguments. There are lots of clever tricks and optimizations we |
| 4192 // could use here, but Printf is a debug tool so instead we just try to keep | 4353 // could use here, but Printf is a debug tool so instead we just try to keep |
| 4193 // it simple: Move each input that isn't already in the right place to a | 4354 // it simple: Move each input that isn't already in the right place to a |
| 4194 // scratch register, then move everything back. | 4355 // scratch register, then move everything back. |
| 4195 for (unsigned i = 0; i < kPrintfMaxArgCount; i++) { | 4356 for (unsigned i = 0; i < kPrintfMaxArgCount; i++) { |
| 4196 // Work out the proper PCS register for this argument. | 4357 // Work out the proper PCS register for this argument. |
| 4197 if (args[i].IsRegister()) { | 4358 if (args[i].IsRegister()) { |
| 4198 pcs[i] = pcs_varargs.PopLowestIndex().X(); | 4359 pcs[i] = pcs_varargs.PopLowestIndex().X(); |
| 4199 // We might only need a W register here. We need to know the size of the | 4360 // We might only need a W register here. We need to know the size of the |
| 4200 // argument so we can properly encode it for the simulator call. | 4361 // argument so we can properly encode it for the simulator call. |
| 4201 if (args[i].Is32Bits()) pcs[i] = pcs[i].W(); | 4362 if (args[i].Is32Bits()) pcs[i] = pcs[i].W(); |
| 4202 } else if (args[i].IsFPRegister()) { | 4363 } else if (args[i].IsVRegister()) { |
| 4203 // In C, floats are always cast to doubles for varargs calls. | 4364 // In C, floats are always cast to doubles for varargs calls. |
| 4204 pcs[i] = pcs_varargs_fp.PopLowestIndex().D(); | 4365 pcs[i] = pcs_varargs_fp.PopLowestIndex().D(); |
| 4205 } else { | 4366 } else { |
| 4206 DCHECK(args[i].IsNone()); | 4367 DCHECK(args[i].IsNone()); |
| 4207 arg_count = i; | 4368 arg_count = i; |
| 4208 break; | 4369 break; |
| 4209 } | 4370 } |
| 4210 | 4371 |
| 4211 // If the argument is already in the right place, leave it where it is. | 4372 // If the argument is already in the right place, leave it where it is. |
| 4212 if (args[i].Aliases(pcs[i])) continue; | 4373 if (args[i].Aliases(pcs[i])) continue; |
| 4213 | 4374 |
| 4214 // Otherwise, if the argument is in a PCS argument register, allocate an | 4375 // Otherwise, if the argument is in a PCS argument register, allocate an |
| 4215 // appropriate scratch register and then move it out of the way. | 4376 // appropriate scratch register and then move it out of the way. |
| 4216 if (kPCSVarargs.IncludesAliasOf(args[i]) || | 4377 if (kPCSVarargs.IncludesAliasOf(args[i]) || |
| 4217 kPCSVarargsFP.IncludesAliasOf(args[i])) { | 4378 kPCSVarargsFP.IncludesAliasOf(args[i])) { |
| 4218 if (args[i].IsRegister()) { | 4379 if (args[i].IsRegister()) { |
| 4219 Register old_arg = Register(args[i]); | 4380 Register old_arg = Register(args[i]); |
| 4220 Register new_arg = temps.AcquireSameSizeAs(old_arg); | 4381 Register new_arg = temps.AcquireSameSizeAs(old_arg); |
| 4221 Mov(new_arg, old_arg); | 4382 Mov(new_arg, old_arg); |
| 4222 args[i] = new_arg; | 4383 args[i] = new_arg; |
| 4223 } else { | 4384 } else { |
| 4224 FPRegister old_arg = FPRegister(args[i]); | 4385 VRegister old_arg = VRegister(args[i]); |
| 4225 FPRegister new_arg = temps.AcquireSameSizeAs(old_arg); | 4386 VRegister new_arg = temps.AcquireSameSizeAs(old_arg); |
| 4226 Fmov(new_arg, old_arg); | 4387 Fmov(new_arg, old_arg); |
| 4227 args[i] = new_arg; | 4388 args[i] = new_arg; |
| 4228 } | 4389 } |
| 4229 } | 4390 } |
| 4230 } | 4391 } |
| 4231 | 4392 |
| 4232 // Do a second pass to move values into their final positions and perform any | 4393 // Do a second pass to move values into their final positions and perform any |
| 4233 // conversions that may be required. | 4394 // conversions that may be required. |
| 4234 for (int i = 0; i < arg_count; i++) { | 4395 for (int i = 0; i < arg_count; i++) { |
| 4235 DCHECK(pcs[i].type() == args[i].type()); | 4396 DCHECK(pcs[i].type() == args[i].type()); |
| 4236 if (pcs[i].IsRegister()) { | 4397 if (pcs[i].IsRegister()) { |
| 4237 Mov(Register(pcs[i]), Register(args[i]), kDiscardForSameWReg); | 4398 Mov(Register(pcs[i]), Register(args[i]), kDiscardForSameWReg); |
| 4238 } else { | 4399 } else { |
| 4239 DCHECK(pcs[i].IsFPRegister()); | 4400 DCHECK(pcs[i].IsVRegister()); |
| 4240 if (pcs[i].SizeInBytes() == args[i].SizeInBytes()) { | 4401 if (pcs[i].SizeInBytes() == args[i].SizeInBytes()) { |
| 4241 Fmov(FPRegister(pcs[i]), FPRegister(args[i])); | 4402 Fmov(VRegister(pcs[i]), VRegister(args[i])); |
| 4242 } else { | 4403 } else { |
| 4243 Fcvt(FPRegister(pcs[i]), FPRegister(args[i])); | 4404 Fcvt(VRegister(pcs[i]), VRegister(args[i])); |
| 4244 } | 4405 } |
| 4245 } | 4406 } |
| 4246 } | 4407 } |
| 4247 | 4408 |
| 4248 // Load the format string into x0, as per the procedure-call standard. | 4409 // Load the format string into x0, as per the procedure-call standard. |
| 4249 // | 4410 // |
| 4250 // To make the code as portable as possible, the format string is encoded | 4411 // To make the code as portable as possible, the format string is encoded |
| 4251 // directly in the instruction stream. It might be cleaner to encode it in a | 4412 // directly in the instruction stream. It might be cleaner to encode it in a |
| 4252 // literal pool, but since Printf is usually used for debugging, it is | 4413 // literal pool, but since Printf is usually used for debugging, it is |
| 4253 // beneficial for it to be minimally dependent on other features. | 4414 // beneficial for it to be minimally dependent on other features. |
| (...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4321 // available as scratch registers until we've preserved them. | 4482 // available as scratch registers until we've preserved them. |
| 4322 RegList old_tmp_list = TmpList()->list(); | 4483 RegList old_tmp_list = TmpList()->list(); |
| 4323 RegList old_fp_tmp_list = FPTmpList()->list(); | 4484 RegList old_fp_tmp_list = FPTmpList()->list(); |
| 4324 TmpList()->set_list(0); | 4485 TmpList()->set_list(0); |
| 4325 FPTmpList()->set_list(0); | 4486 FPTmpList()->set_list(0); |
| 4326 | 4487 |
| 4327 // Preserve all caller-saved registers as well as NZCV. | 4488 // Preserve all caller-saved registers as well as NZCV. |
| 4328 // If csp is the stack pointer, PushCPURegList asserts that the size of each | 4489 // If csp is the stack pointer, PushCPURegList asserts that the size of each |
| 4329 // list is a multiple of 16 bytes. | 4490 // list is a multiple of 16 bytes. |
| 4330 PushCPURegList(kCallerSaved); | 4491 PushCPURegList(kCallerSaved); |
| 4331 PushCPURegList(kCallerSavedFP); | 4492 PushCPURegList(kCallerSavedV); |
| 4332 | 4493 |
| 4333 // We can use caller-saved registers as scratch values (except for argN). | 4494 // We can use caller-saved registers as scratch values (except for argN). |
| 4334 CPURegList tmp_list = kCallerSaved; | 4495 CPURegList tmp_list = kCallerSaved; |
| 4335 CPURegList fp_tmp_list = kCallerSavedFP; | 4496 CPURegList fp_tmp_list = kCallerSavedV; |
| 4336 tmp_list.Remove(arg0, arg1, arg2, arg3); | 4497 tmp_list.Remove(arg0, arg1, arg2, arg3); |
| 4337 fp_tmp_list.Remove(arg0, arg1, arg2, arg3); | 4498 fp_tmp_list.Remove(arg0, arg1, arg2, arg3); |
| 4338 TmpList()->set_list(tmp_list.list()); | 4499 TmpList()->set_list(tmp_list.list()); |
| 4339 FPTmpList()->set_list(fp_tmp_list.list()); | 4500 FPTmpList()->set_list(fp_tmp_list.list()); |
| 4340 | 4501 |
| 4341 { UseScratchRegisterScope temps(this); | 4502 { UseScratchRegisterScope temps(this); |
| 4342 // If any of the arguments are the current stack pointer, allocate a new | 4503 // If any of the arguments are the current stack pointer, allocate a new |
| 4343 // register for them, and adjust the value to compensate for pushing the | 4504 // register for them, and adjust the value to compensate for pushing the |
| 4344 // caller-saved registers. | 4505 // caller-saved registers. |
| 4345 bool arg0_sp = StackPointer().Aliases(arg0); | 4506 bool arg0_sp = StackPointer().Aliases(arg0); |
| 4346 bool arg1_sp = StackPointer().Aliases(arg1); | 4507 bool arg1_sp = StackPointer().Aliases(arg1); |
| 4347 bool arg2_sp = StackPointer().Aliases(arg2); | 4508 bool arg2_sp = StackPointer().Aliases(arg2); |
| 4348 bool arg3_sp = StackPointer().Aliases(arg3); | 4509 bool arg3_sp = StackPointer().Aliases(arg3); |
| 4349 if (arg0_sp || arg1_sp || arg2_sp || arg3_sp) { | 4510 if (arg0_sp || arg1_sp || arg2_sp || arg3_sp) { |
| 4350 // Allocate a register to hold the original stack pointer value, to pass | 4511 // Allocate a register to hold the original stack pointer value, to pass |
| 4351 // to PrintfNoPreserve as an argument. | 4512 // to PrintfNoPreserve as an argument. |
| 4352 Register arg_sp = temps.AcquireX(); | 4513 Register arg_sp = temps.AcquireX(); |
| 4353 Add(arg_sp, StackPointer(), | 4514 Add(arg_sp, StackPointer(), |
| 4354 kCallerSaved.TotalSizeInBytes() + kCallerSavedFP.TotalSizeInBytes()); | 4515 kCallerSaved.TotalSizeInBytes() + kCallerSavedV.TotalSizeInBytes()); |
| 4355 if (arg0_sp) arg0 = Register::Create(arg_sp.code(), arg0.SizeInBits()); | 4516 if (arg0_sp) arg0 = Register::Create(arg_sp.code(), arg0.SizeInBits()); |
| 4356 if (arg1_sp) arg1 = Register::Create(arg_sp.code(), arg1.SizeInBits()); | 4517 if (arg1_sp) arg1 = Register::Create(arg_sp.code(), arg1.SizeInBits()); |
| 4357 if (arg2_sp) arg2 = Register::Create(arg_sp.code(), arg2.SizeInBits()); | 4518 if (arg2_sp) arg2 = Register::Create(arg_sp.code(), arg2.SizeInBits()); |
| 4358 if (arg3_sp) arg3 = Register::Create(arg_sp.code(), arg3.SizeInBits()); | 4519 if (arg3_sp) arg3 = Register::Create(arg_sp.code(), arg3.SizeInBits()); |
| 4359 } | 4520 } |
| 4360 | 4521 |
| 4361 // Preserve NZCV. | 4522 // Preserve NZCV. |
| 4362 { UseScratchRegisterScope temps(this); | 4523 { UseScratchRegisterScope temps(this); |
| 4363 Register tmp = temps.AcquireX(); | 4524 Register tmp = temps.AcquireX(); |
| 4364 Mrs(tmp, NZCV); | 4525 Mrs(tmp, NZCV); |
| 4365 Push(tmp, xzr); | 4526 Push(tmp, xzr); |
| 4366 } | 4527 } |
| 4367 | 4528 |
| 4368 PrintfNoPreserve(format, arg0, arg1, arg2, arg3); | 4529 PrintfNoPreserve(format, arg0, arg1, arg2, arg3); |
| 4369 | 4530 |
| 4370 // Restore NZCV. | 4531 // Restore NZCV. |
| 4371 { UseScratchRegisterScope temps(this); | 4532 { UseScratchRegisterScope temps(this); |
| 4372 Register tmp = temps.AcquireX(); | 4533 Register tmp = temps.AcquireX(); |
| 4373 Pop(xzr, tmp); | 4534 Pop(xzr, tmp); |
| 4374 Msr(NZCV, tmp); | 4535 Msr(NZCV, tmp); |
| 4375 } | 4536 } |
| 4376 } | 4537 } |
| 4377 | 4538 |
| 4378 PopCPURegList(kCallerSavedFP); | 4539 PopCPURegList(kCallerSavedV); |
| 4379 PopCPURegList(kCallerSaved); | 4540 PopCPURegList(kCallerSaved); |
| 4380 | 4541 |
| 4381 TmpList()->set_list(old_tmp_list); | 4542 TmpList()->set_list(old_tmp_list); |
| 4382 FPTmpList()->set_list(old_fp_tmp_list); | 4543 FPTmpList()->set_list(old_fp_tmp_list); |
| 4383 } | 4544 } |
| 4384 | 4545 |
| 4385 | 4546 |
| 4386 void MacroAssembler::EmitFrameSetupForCodeAgePatching() { | 4547 void MacroAssembler::EmitFrameSetupForCodeAgePatching() { |
| 4387 // TODO(jbramley): Other architectures use the internal memcpy to copy the | 4548 // TODO(jbramley): Other architectures use the internal memcpy to copy the |
| 4388 // sequence. If this is a performance bottleneck, we should consider caching | 4549 // sequence. If this is a performance bottleneck, we should consider caching |
| (...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4482 available_->set_list(old_available_); | 4643 available_->set_list(old_available_); |
| 4483 availablefp_->set_list(old_availablefp_); | 4644 availablefp_->set_list(old_availablefp_); |
| 4484 } | 4645 } |
| 4485 | 4646 |
| 4486 | 4647 |
| 4487 Register UseScratchRegisterScope::AcquireSameSizeAs(const Register& reg) { | 4648 Register UseScratchRegisterScope::AcquireSameSizeAs(const Register& reg) { |
| 4488 int code = AcquireNextAvailable(available_).code(); | 4649 int code = AcquireNextAvailable(available_).code(); |
| 4489 return Register::Create(code, reg.SizeInBits()); | 4650 return Register::Create(code, reg.SizeInBits()); |
| 4490 } | 4651 } |
| 4491 | 4652 |
| 4492 | 4653 VRegister UseScratchRegisterScope::AcquireSameSizeAs(const VRegister& reg) { |
| 4493 FPRegister UseScratchRegisterScope::AcquireSameSizeAs(const FPRegister& reg) { | |
| 4494 int code = AcquireNextAvailable(availablefp_).code(); | 4654 int code = AcquireNextAvailable(availablefp_).code(); |
| 4495 return FPRegister::Create(code, reg.SizeInBits()); | 4655 return VRegister::Create(code, reg.SizeInBits()); |
| 4496 } | 4656 } |
| 4497 | 4657 |
| 4498 | 4658 |
| 4499 CPURegister UseScratchRegisterScope::AcquireNextAvailable( | 4659 CPURegister UseScratchRegisterScope::AcquireNextAvailable( |
| 4500 CPURegList* available) { | 4660 CPURegList* available) { |
| 4501 CHECK(!available->IsEmpty()); | 4661 CHECK(!available->IsEmpty()); |
| 4502 CPURegister result = available->PopLowestIndex(); | 4662 CPURegister result = available->PopLowestIndex(); |
| 4503 DCHECK(!AreAliased(result, xzr, csp)); | 4663 DCHECK(!AreAliased(result, xzr, csp)); |
| 4504 return result; | 4664 return result; |
| 4505 } | 4665 } |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4566 } | 4726 } |
| 4567 | 4727 |
| 4568 | 4728 |
| 4569 #undef __ | 4729 #undef __ |
| 4570 | 4730 |
| 4571 | 4731 |
| 4572 } // namespace internal | 4732 } // namespace internal |
| 4573 } // namespace v8 | 4733 } // namespace v8 |
| 4574 | 4734 |
| 4575 #endif // V8_TARGET_ARCH_ARM64 | 4735 #endif // V8_TARGET_ARCH_ARM64 |
| OLD | NEW |