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 } | |
463 | 298 |
464 void MacroAssembler::Mvn(const Register& rd, const Operand& operand) { | 299 void MacroAssembler::Mvn(const Register& rd, const Operand& operand) { |
465 DCHECK(allow_macro_instructions_); | 300 DCHECK(allow_macro_instructions_); |
466 | 301 |
467 if (operand.NeedsRelocation(this)) { | 302 if (operand.NeedsRelocation(this)) { |
468 Ldr(rd, operand.immediate()); | 303 Ldr(rd, operand.immediate()); |
469 mvn(rd, rd); | 304 mvn(rd, rd); |
470 | 305 |
471 } else if (operand.IsImmediate()) { | 306 } else if (operand.IsImmediate()) { |
472 // Call the macro assembler for generic immediates. | 307 // Call the macro assembler for generic immediates. |
(...skipping 251 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
724 // The addressing mode is directly supported by the instruction. | 559 // The addressing mode is directly supported by the instruction. |
725 AddSubWithCarry(rd, rn, operand, S, op); | 560 AddSubWithCarry(rd, rn, operand, S, op); |
726 } | 561 } |
727 } | 562 } |
728 | 563 |
729 | 564 |
730 void MacroAssembler::LoadStoreMacro(const CPURegister& rt, | 565 void MacroAssembler::LoadStoreMacro(const CPURegister& rt, |
731 const MemOperand& addr, | 566 const MemOperand& addr, |
732 LoadStoreOp op) { | 567 LoadStoreOp op) { |
733 int64_t offset = addr.offset(); | 568 int64_t offset = addr.offset(); |
734 unsigned size = CalcLSDataSize(op); | 569 LSDataSize size = CalcLSDataSize(op); |
735 | 570 |
736 // Check if an immediate offset fits in the immediate field of the | 571 // Check if an immediate offset fits in the immediate field of the |
737 // appropriate instruction. If not, emit two instructions to perform | 572 // appropriate instruction. If not, emit two instructions to perform |
738 // the operation. | 573 // the operation. |
739 if (addr.IsImmediateOffset() && !IsImmLSScaled(offset, size) && | 574 if (addr.IsImmediateOffset() && !IsImmLSScaled(offset, size) && |
740 !IsImmLSUnscaled(offset)) { | 575 !IsImmLSUnscaled(offset)) { |
741 // Immediate offset that can't be encoded using unsigned or unscaled | 576 // Immediate offset that can't be encoded using unsigned or unscaled |
742 // addressing modes. | 577 // addressing modes. |
743 UseScratchRegisterScope temps(this); | 578 UseScratchRegisterScope temps(this); |
744 Register temp = temps.AcquireSameSizeAs(addr.base()); | 579 Register temp = temps.AcquireSameSizeAs(addr.base()); |
(...skipping 14 matching lines...) Expand all Loading... |
759 } | 594 } |
760 | 595 |
761 void MacroAssembler::LoadStorePairMacro(const CPURegister& rt, | 596 void MacroAssembler::LoadStorePairMacro(const CPURegister& rt, |
762 const CPURegister& rt2, | 597 const CPURegister& rt2, |
763 const MemOperand& addr, | 598 const MemOperand& addr, |
764 LoadStorePairOp op) { | 599 LoadStorePairOp op) { |
765 // TODO(all): Should we support register offset for load-store-pair? | 600 // TODO(all): Should we support register offset for load-store-pair? |
766 DCHECK(!addr.IsRegisterOffset()); | 601 DCHECK(!addr.IsRegisterOffset()); |
767 | 602 |
768 int64_t offset = addr.offset(); | 603 int64_t offset = addr.offset(); |
769 unsigned size = CalcLSPairDataSize(op); | 604 LSDataSize size = CalcLSPairDataSize(op); |
770 | 605 |
771 // Check if the offset fits in the immediate field of the appropriate | 606 // Check if the offset fits in the immediate field of the appropriate |
772 // instruction. If not, emit two instructions to perform the operation. | 607 // instruction. If not, emit two instructions to perform the operation. |
773 if (IsImmLSPair(offset, size)) { | 608 if (IsImmLSPair(offset, size)) { |
774 // Encodable in one load/store pair instruction. | 609 // Encodable in one load/store pair instruction. |
775 LoadStorePair(rt, rt2, addr, op); | 610 LoadStorePair(rt, rt2, addr, op); |
776 } else { | 611 } else { |
777 Register base = addr.base(); | 612 Register base = addr.base(); |
778 if (addr.IsImmediateOffset()) { | 613 if (addr.IsImmediateOffset()) { |
779 UseScratchRegisterScope temps(this); | 614 UseScratchRegisterScope temps(this); |
(...skipping 307 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1087 DCHECK(dst0.IsValid()); | 922 DCHECK(dst0.IsValid()); |
1088 | 923 |
1089 int count = 5 + dst5.IsValid() + dst6.IsValid() + dst7.IsValid(); | 924 int count = 5 + dst5.IsValid() + dst6.IsValid() + dst7.IsValid(); |
1090 int size = dst0.SizeInBytes(); | 925 int size = dst0.SizeInBytes(); |
1091 | 926 |
1092 PopHelper(4, size, dst0, dst1, dst2, dst3); | 927 PopHelper(4, size, dst0, dst1, dst2, dst3); |
1093 PopHelper(count - 4, size, dst4, dst5, dst6, dst7); | 928 PopHelper(count - 4, size, dst4, dst5, dst6, dst7); |
1094 PopPostamble(count, size); | 929 PopPostamble(count, size); |
1095 } | 930 } |
1096 | 931 |
1097 void MacroAssembler::Push(const Register& src0, const VRegister& src1) { | 932 |
| 933 void MacroAssembler::Push(const Register& src0, const FPRegister& src1) { |
1098 int size = src0.SizeInBytes() + src1.SizeInBytes(); | 934 int size = src0.SizeInBytes() + src1.SizeInBytes(); |
1099 | 935 |
1100 PushPreamble(size); | 936 PushPreamble(size); |
1101 // Reserve room for src0 and push src1. | 937 // Reserve room for src0 and push src1. |
1102 str(src1, MemOperand(StackPointer(), -size, PreIndex)); | 938 str(src1, MemOperand(StackPointer(), -size, PreIndex)); |
1103 // Fill the gap with src0. | 939 // Fill the gap with src0. |
1104 str(src0, MemOperand(StackPointer(), src1.SizeInBytes())); | 940 str(src0, MemOperand(StackPointer(), src1.SizeInBytes())); |
1105 } | 941 } |
1106 | 942 |
1107 | 943 |
(...skipping 446 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1554 Tst(fpcr, RMode_mask); | 1390 Tst(fpcr, RMode_mask); |
1555 B(eq, &done); | 1391 B(eq, &done); |
1556 | 1392 |
1557 Bind(&unexpected_mode); | 1393 Bind(&unexpected_mode); |
1558 Abort(kUnexpectedFPCRMode); | 1394 Abort(kUnexpectedFPCRMode); |
1559 | 1395 |
1560 Bind(&done); | 1396 Bind(&done); |
1561 } | 1397 } |
1562 } | 1398 } |
1563 | 1399 |
1564 void MacroAssembler::CanonicalizeNaN(const VRegister& dst, | 1400 |
1565 const VRegister& src) { | 1401 void MacroAssembler::CanonicalizeNaN(const FPRegister& dst, |
| 1402 const FPRegister& src) { |
1566 AssertFPCRState(); | 1403 AssertFPCRState(); |
1567 | 1404 |
1568 // Subtracting 0.0 preserves all inputs except for signalling NaNs, which | 1405 // Subtracting 0.0 preserves all inputs except for signalling NaNs, which |
1569 // become quiet NaNs. We use fsub rather than fadd because fsub preserves -0.0 | 1406 // become quiet NaNs. We use fsub rather than fadd because fsub preserves -0.0 |
1570 // inputs: -0.0 + 0.0 = 0.0, but -0.0 - 0.0 = -0.0. | 1407 // inputs: -0.0 + 0.0 = 0.0, but -0.0 - 0.0 = -0.0. |
1571 Fsub(dst, src, fp_zero); | 1408 Fsub(dst, src, fp_zero); |
1572 } | 1409 } |
1573 | 1410 |
1574 | 1411 |
1575 void MacroAssembler::LoadRoot(CPURegister destination, | 1412 void MacroAssembler::LoadRoot(CPURegister destination, |
(...skipping 631 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2207 } | 2044 } |
2208 | 2045 |
2209 AssertNotSmi(object); | 2046 AssertNotSmi(object); |
2210 | 2047 |
2211 UseScratchRegisterScope temps(this); | 2048 UseScratchRegisterScope temps(this); |
2212 Register temp = temps.AcquireX(); | 2049 Register temp = temps.AcquireX(); |
2213 Ldr(temp, FieldMemOperand(object, HeapObject::kMapOffset)); | 2050 Ldr(temp, FieldMemOperand(object, HeapObject::kMapOffset)); |
2214 JumpIfNotRoot(temp, Heap::kHeapNumberMapRootIndex, on_not_heap_number); | 2051 JumpIfNotRoot(temp, Heap::kHeapNumberMapRootIndex, on_not_heap_number); |
2215 } | 2052 } |
2216 | 2053 |
2217 void MacroAssembler::TryRepresentDoubleAsInt(Register as_int, VRegister value, | 2054 |
2218 VRegister scratch_d, | 2055 void MacroAssembler::TryRepresentDoubleAsInt(Register as_int, |
| 2056 FPRegister value, |
| 2057 FPRegister scratch_d, |
2219 Label* on_successful_conversion, | 2058 Label* on_successful_conversion, |
2220 Label* on_failed_conversion) { | 2059 Label* on_failed_conversion) { |
2221 // Convert to an int and back again, then compare with the original value. | 2060 // Convert to an int and back again, then compare with the original value. |
2222 Fcvtzs(as_int, value); | 2061 Fcvtzs(as_int, value); |
2223 Scvtf(scratch_d, as_int); | 2062 Scvtf(scratch_d, as_int); |
2224 Fcmp(value, scratch_d); | 2063 Fcmp(value, scratch_d); |
2225 | 2064 |
2226 if (on_successful_conversion) { | 2065 if (on_successful_conversion) { |
2227 B(on_successful_conversion, eq); | 2066 B(on_successful_conversion, eq); |
2228 } | 2067 } |
(...skipping 593 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2822 // Drop the execution stack down to the frame pointer and restore | 2661 // Drop the execution stack down to the frame pointer and restore |
2823 // the caller frame pointer and return address. | 2662 // the caller frame pointer and return address. |
2824 Mov(jssp, fp); | 2663 Mov(jssp, fp); |
2825 AssertStackConsistency(); | 2664 AssertStackConsistency(); |
2826 Pop(fp, lr); | 2665 Pop(fp, lr); |
2827 } | 2666 } |
2828 } | 2667 } |
2829 | 2668 |
2830 | 2669 |
2831 void MacroAssembler::ExitFramePreserveFPRegs() { | 2670 void MacroAssembler::ExitFramePreserveFPRegs() { |
2832 PushCPURegList(kCallerSavedV); | 2671 PushCPURegList(kCallerSavedFP); |
2833 } | 2672 } |
2834 | 2673 |
2835 | 2674 |
2836 void MacroAssembler::ExitFrameRestoreFPRegs() { | 2675 void MacroAssembler::ExitFrameRestoreFPRegs() { |
2837 // Read the registers from the stack without popping them. The stack pointer | 2676 // Read the registers from the stack without popping them. The stack pointer |
2838 // will be reset as part of the unwinding process. | 2677 // will be reset as part of the unwinding process. |
2839 CPURegList saved_fp_regs = kCallerSavedV; | 2678 CPURegList saved_fp_regs = kCallerSavedFP; |
2840 DCHECK(saved_fp_regs.Count() % 2 == 0); | 2679 DCHECK(saved_fp_regs.Count() % 2 == 0); |
2841 | 2680 |
2842 int offset = ExitFrameConstants::kLastExitFrameField; | 2681 int offset = ExitFrameConstants::kLastExitFrameField; |
2843 while (!saved_fp_regs.IsEmpty()) { | 2682 while (!saved_fp_regs.IsEmpty()) { |
2844 const CPURegister& dst0 = saved_fp_regs.PopHighestIndex(); | 2683 const CPURegister& dst0 = saved_fp_regs.PopHighestIndex(); |
2845 const CPURegister& dst1 = saved_fp_regs.PopHighestIndex(); | 2684 const CPURegister& dst1 = saved_fp_regs.PopHighestIndex(); |
2846 offset -= 2 * kDRegSize; | 2685 offset -= 2 * kDRegSize; |
2847 Ldp(dst1, dst0, MemOperand(fp, offset)); | 2686 Ldp(dst1, dst0, MemOperand(fp, offset)); |
2848 } | 2687 } |
2849 } | 2688 } |
(...skipping 458 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3308 NO_ALLOCATION_FLAGS); | 3147 NO_ALLOCATION_FLAGS); |
3309 | 3148 |
3310 Heap::RootListIndex map_index = mode == MUTABLE | 3149 Heap::RootListIndex map_index = mode == MUTABLE |
3311 ? Heap::kMutableHeapNumberMapRootIndex | 3150 ? Heap::kMutableHeapNumberMapRootIndex |
3312 : Heap::kHeapNumberMapRootIndex; | 3151 : Heap::kHeapNumberMapRootIndex; |
3313 | 3152 |
3314 // Prepare the heap number map. | 3153 // Prepare the heap number map. |
3315 if (!heap_number_map.IsValid()) { | 3154 if (!heap_number_map.IsValid()) { |
3316 // If we have a valid value register, use the same type of register to store | 3155 // If we have a valid value register, use the same type of register to store |
3317 // the map so we can use STP to store both in one instruction. | 3156 // the map so we can use STP to store both in one instruction. |
3318 if (value.IsValid() && value.IsVRegister()) { | 3157 if (value.IsValid() && value.IsFPRegister()) { |
3319 heap_number_map = temps.AcquireD(); | 3158 heap_number_map = temps.AcquireD(); |
3320 } else { | 3159 } else { |
3321 heap_number_map = scratch1; | 3160 heap_number_map = scratch1; |
3322 } | 3161 } |
3323 LoadRoot(heap_number_map, map_index); | 3162 LoadRoot(heap_number_map, map_index); |
3324 } | 3163 } |
3325 if (emit_debug_code()) { | 3164 if (emit_debug_code()) { |
3326 Register map; | 3165 Register map; |
3327 if (heap_number_map.IsVRegister()) { | 3166 if (heap_number_map.IsFPRegister()) { |
3328 map = scratch1; | 3167 map = scratch1; |
3329 Fmov(map, DoubleRegister(heap_number_map)); | 3168 Fmov(map, DoubleRegister(heap_number_map)); |
3330 } else { | 3169 } else { |
3331 map = Register(heap_number_map); | 3170 map = Register(heap_number_map); |
3332 } | 3171 } |
3333 AssertRegisterIsRoot(map, map_index); | 3172 AssertRegisterIsRoot(map, map_index); |
3334 } | 3173 } |
3335 | 3174 |
3336 // Store the heap number map and the value in the allocated object. | 3175 // Store the heap number map and the value in the allocated object. |
3337 if (value.IsSameSizeAndType(heap_number_map)) { | 3176 if (value.IsSameSizeAndType(heap_number_map)) { |
(...skipping 441 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3779 const int num_unsaved = kNumSafepointRegisters - kNumSafepointSavedRegisters; | 3618 const int num_unsaved = kNumSafepointRegisters - kNumSafepointSavedRegisters; |
3780 DCHECK(num_unsaved >= 0); | 3619 DCHECK(num_unsaved >= 0); |
3781 Claim(num_unsaved); | 3620 Claim(num_unsaved); |
3782 PushXRegList(kSafepointSavedRegisters); | 3621 PushXRegList(kSafepointSavedRegisters); |
3783 } | 3622 } |
3784 | 3623 |
3785 | 3624 |
3786 void MacroAssembler::PushSafepointRegistersAndDoubles() { | 3625 void MacroAssembler::PushSafepointRegistersAndDoubles() { |
3787 PushSafepointRegisters(); | 3626 PushSafepointRegisters(); |
3788 PushCPURegList(CPURegList( | 3627 PushCPURegList(CPURegList( |
3789 CPURegister::kVRegister, kDRegSizeInBits, | 3628 CPURegister::kFPRegister, kDRegSizeInBits, |
3790 RegisterConfiguration::Crankshaft()->allocatable_double_codes_mask())); | 3629 RegisterConfiguration::Crankshaft()->allocatable_double_codes_mask())); |
3791 } | 3630 } |
3792 | 3631 |
3793 | 3632 |
3794 void MacroAssembler::PopSafepointRegistersAndDoubles() { | 3633 void MacroAssembler::PopSafepointRegistersAndDoubles() { |
3795 PopCPURegList(CPURegList( | 3634 PopCPURegList(CPURegList( |
3796 CPURegister::kVRegister, kDRegSizeInBits, | 3635 CPURegister::kFPRegister, kDRegSizeInBits, |
3797 RegisterConfiguration::Crankshaft()->allocatable_double_codes_mask())); | 3636 RegisterConfiguration::Crankshaft()->allocatable_double_codes_mask())); |
3798 PopSafepointRegisters(); | 3637 PopSafepointRegisters(); |
3799 } | 3638 } |
3800 | 3639 |
3801 void MacroAssembler::StoreToSafepointRegisterSlot(Register src, Register dst) { | 3640 void MacroAssembler::StoreToSafepointRegisterSlot(Register src, Register dst) { |
3802 Poke(src, SafepointRegisterStackIndex(dst.code()) * kPointerSize); | 3641 Poke(src, SafepointRegisterStackIndex(dst.code()) * kPointerSize); |
3803 } | 3642 } |
3804 | 3643 |
3805 void MacroAssembler::LoadFromSafepointRegisterSlot(Register dst, Register src) { | 3644 void MacroAssembler::LoadFromSafepointRegisterSlot(Register dst, Register src) { |
3806 Peek(src, SafepointRegisterStackIndex(dst.code()) * kPointerSize); | 3645 Peek(src, SafepointRegisterStackIndex(dst.code()) * kPointerSize); |
(...skipping 531 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4338 CPURegister args[kPrintfMaxArgCount] = {arg0, arg1, arg2, arg3}; | 4177 CPURegister args[kPrintfMaxArgCount] = {arg0, arg1, arg2, arg3}; |
4339 CPURegister pcs[kPrintfMaxArgCount] = {NoReg, NoReg, NoReg, NoReg}; | 4178 CPURegister pcs[kPrintfMaxArgCount] = {NoReg, NoReg, NoReg, NoReg}; |
4340 | 4179 |
4341 int arg_count = kPrintfMaxArgCount; | 4180 int arg_count = kPrintfMaxArgCount; |
4342 | 4181 |
4343 // The PCS varargs registers for printf. Note that x0 is used for the printf | 4182 // The PCS varargs registers for printf. Note that x0 is used for the printf |
4344 // format string. | 4183 // format string. |
4345 static const CPURegList kPCSVarargs = | 4184 static const CPURegList kPCSVarargs = |
4346 CPURegList(CPURegister::kRegister, kXRegSizeInBits, 1, arg_count); | 4185 CPURegList(CPURegister::kRegister, kXRegSizeInBits, 1, arg_count); |
4347 static const CPURegList kPCSVarargsFP = | 4186 static const CPURegList kPCSVarargsFP = |
4348 CPURegList(CPURegister::kVRegister, kDRegSizeInBits, 0, arg_count - 1); | 4187 CPURegList(CPURegister::kFPRegister, kDRegSizeInBits, 0, arg_count - 1); |
4349 | 4188 |
4350 // We can use caller-saved registers as scratch values, except for the | 4189 // We can use caller-saved registers as scratch values, except for the |
4351 // arguments and the PCS registers where they might need to go. | 4190 // arguments and the PCS registers where they might need to go. |
4352 CPURegList tmp_list = kCallerSaved; | 4191 CPURegList tmp_list = kCallerSaved; |
4353 tmp_list.Remove(x0); // Used to pass the format string. | 4192 tmp_list.Remove(x0); // Used to pass the format string. |
4354 tmp_list.Remove(kPCSVarargs); | 4193 tmp_list.Remove(kPCSVarargs); |
4355 tmp_list.Remove(arg0, arg1, arg2, arg3); | 4194 tmp_list.Remove(arg0, arg1, arg2, arg3); |
4356 | 4195 |
4357 CPURegList fp_tmp_list = kCallerSavedV; | 4196 CPURegList fp_tmp_list = kCallerSavedFP; |
4358 fp_tmp_list.Remove(kPCSVarargsFP); | 4197 fp_tmp_list.Remove(kPCSVarargsFP); |
4359 fp_tmp_list.Remove(arg0, arg1, arg2, arg3); | 4198 fp_tmp_list.Remove(arg0, arg1, arg2, arg3); |
4360 | 4199 |
4361 // Override the MacroAssembler's scratch register list. The lists will be | 4200 // Override the MacroAssembler's scratch register list. The lists will be |
4362 // reset automatically at the end of the UseScratchRegisterScope. | 4201 // reset automatically at the end of the UseScratchRegisterScope. |
4363 UseScratchRegisterScope temps(this); | 4202 UseScratchRegisterScope temps(this); |
4364 TmpList()->set_list(tmp_list.list()); | 4203 TmpList()->set_list(tmp_list.list()); |
4365 FPTmpList()->set_list(fp_tmp_list.list()); | 4204 FPTmpList()->set_list(fp_tmp_list.list()); |
4366 | 4205 |
4367 // Copies of the printf vararg registers that we can pop from. | 4206 // Copies of the printf vararg registers that we can pop from. |
4368 CPURegList pcs_varargs = kPCSVarargs; | 4207 CPURegList pcs_varargs = kPCSVarargs; |
4369 CPURegList pcs_varargs_fp = kPCSVarargsFP; | 4208 CPURegList pcs_varargs_fp = kPCSVarargsFP; |
4370 | 4209 |
4371 // Place the arguments. There are lots of clever tricks and optimizations we | 4210 // Place the arguments. There are lots of clever tricks and optimizations we |
4372 // could use here, but Printf is a debug tool so instead we just try to keep | 4211 // could use here, but Printf is a debug tool so instead we just try to keep |
4373 // it simple: Move each input that isn't already in the right place to a | 4212 // it simple: Move each input that isn't already in the right place to a |
4374 // scratch register, then move everything back. | 4213 // scratch register, then move everything back. |
4375 for (unsigned i = 0; i < kPrintfMaxArgCount; i++) { | 4214 for (unsigned i = 0; i < kPrintfMaxArgCount; i++) { |
4376 // Work out the proper PCS register for this argument. | 4215 // Work out the proper PCS register for this argument. |
4377 if (args[i].IsRegister()) { | 4216 if (args[i].IsRegister()) { |
4378 pcs[i] = pcs_varargs.PopLowestIndex().X(); | 4217 pcs[i] = pcs_varargs.PopLowestIndex().X(); |
4379 // We might only need a W register here. We need to know the size of the | 4218 // We might only need a W register here. We need to know the size of the |
4380 // argument so we can properly encode it for the simulator call. | 4219 // argument so we can properly encode it for the simulator call. |
4381 if (args[i].Is32Bits()) pcs[i] = pcs[i].W(); | 4220 if (args[i].Is32Bits()) pcs[i] = pcs[i].W(); |
4382 } else if (args[i].IsVRegister()) { | 4221 } else if (args[i].IsFPRegister()) { |
4383 // In C, floats are always cast to doubles for varargs calls. | 4222 // In C, floats are always cast to doubles for varargs calls. |
4384 pcs[i] = pcs_varargs_fp.PopLowestIndex().D(); | 4223 pcs[i] = pcs_varargs_fp.PopLowestIndex().D(); |
4385 } else { | 4224 } else { |
4386 DCHECK(args[i].IsNone()); | 4225 DCHECK(args[i].IsNone()); |
4387 arg_count = i; | 4226 arg_count = i; |
4388 break; | 4227 break; |
4389 } | 4228 } |
4390 | 4229 |
4391 // If the argument is already in the right place, leave it where it is. | 4230 // If the argument is already in the right place, leave it where it is. |
4392 if (args[i].Aliases(pcs[i])) continue; | 4231 if (args[i].Aliases(pcs[i])) continue; |
4393 | 4232 |
4394 // Otherwise, if the argument is in a PCS argument register, allocate an | 4233 // Otherwise, if the argument is in a PCS argument register, allocate an |
4395 // appropriate scratch register and then move it out of the way. | 4234 // appropriate scratch register and then move it out of the way. |
4396 if (kPCSVarargs.IncludesAliasOf(args[i]) || | 4235 if (kPCSVarargs.IncludesAliasOf(args[i]) || |
4397 kPCSVarargsFP.IncludesAliasOf(args[i])) { | 4236 kPCSVarargsFP.IncludesAliasOf(args[i])) { |
4398 if (args[i].IsRegister()) { | 4237 if (args[i].IsRegister()) { |
4399 Register old_arg = Register(args[i]); | 4238 Register old_arg = Register(args[i]); |
4400 Register new_arg = temps.AcquireSameSizeAs(old_arg); | 4239 Register new_arg = temps.AcquireSameSizeAs(old_arg); |
4401 Mov(new_arg, old_arg); | 4240 Mov(new_arg, old_arg); |
4402 args[i] = new_arg; | 4241 args[i] = new_arg; |
4403 } else { | 4242 } else { |
4404 VRegister old_arg = VRegister(args[i]); | 4243 FPRegister old_arg = FPRegister(args[i]); |
4405 VRegister new_arg = temps.AcquireSameSizeAs(old_arg); | 4244 FPRegister new_arg = temps.AcquireSameSizeAs(old_arg); |
4406 Fmov(new_arg, old_arg); | 4245 Fmov(new_arg, old_arg); |
4407 args[i] = new_arg; | 4246 args[i] = new_arg; |
4408 } | 4247 } |
4409 } | 4248 } |
4410 } | 4249 } |
4411 | 4250 |
4412 // Do a second pass to move values into their final positions and perform any | 4251 // Do a second pass to move values into their final positions and perform any |
4413 // conversions that may be required. | 4252 // conversions that may be required. |
4414 for (int i = 0; i < arg_count; i++) { | 4253 for (int i = 0; i < arg_count; i++) { |
4415 DCHECK(pcs[i].type() == args[i].type()); | 4254 DCHECK(pcs[i].type() == args[i].type()); |
4416 if (pcs[i].IsRegister()) { | 4255 if (pcs[i].IsRegister()) { |
4417 Mov(Register(pcs[i]), Register(args[i]), kDiscardForSameWReg); | 4256 Mov(Register(pcs[i]), Register(args[i]), kDiscardForSameWReg); |
4418 } else { | 4257 } else { |
4419 DCHECK(pcs[i].IsVRegister()); | 4258 DCHECK(pcs[i].IsFPRegister()); |
4420 if (pcs[i].SizeInBytes() == args[i].SizeInBytes()) { | 4259 if (pcs[i].SizeInBytes() == args[i].SizeInBytes()) { |
4421 Fmov(VRegister(pcs[i]), VRegister(args[i])); | 4260 Fmov(FPRegister(pcs[i]), FPRegister(args[i])); |
4422 } else { | 4261 } else { |
4423 Fcvt(VRegister(pcs[i]), VRegister(args[i])); | 4262 Fcvt(FPRegister(pcs[i]), FPRegister(args[i])); |
4424 } | 4263 } |
4425 } | 4264 } |
4426 } | 4265 } |
4427 | 4266 |
4428 // Load the format string into x0, as per the procedure-call standard. | 4267 // Load the format string into x0, as per the procedure-call standard. |
4429 // | 4268 // |
4430 // To make the code as portable as possible, the format string is encoded | 4269 // To make the code as portable as possible, the format string is encoded |
4431 // directly in the instruction stream. It might be cleaner to encode it in a | 4270 // directly in the instruction stream. It might be cleaner to encode it in a |
4432 // literal pool, but since Printf is usually used for debugging, it is | 4271 // literal pool, but since Printf is usually used for debugging, it is |
4433 // beneficial for it to be minimally dependent on other features. | 4272 // beneficial for it to be minimally dependent on other features. |
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4501 // available as scratch registers until we've preserved them. | 4340 // available as scratch registers until we've preserved them. |
4502 RegList old_tmp_list = TmpList()->list(); | 4341 RegList old_tmp_list = TmpList()->list(); |
4503 RegList old_fp_tmp_list = FPTmpList()->list(); | 4342 RegList old_fp_tmp_list = FPTmpList()->list(); |
4504 TmpList()->set_list(0); | 4343 TmpList()->set_list(0); |
4505 FPTmpList()->set_list(0); | 4344 FPTmpList()->set_list(0); |
4506 | 4345 |
4507 // Preserve all caller-saved registers as well as NZCV. | 4346 // Preserve all caller-saved registers as well as NZCV. |
4508 // If csp is the stack pointer, PushCPURegList asserts that the size of each | 4347 // If csp is the stack pointer, PushCPURegList asserts that the size of each |
4509 // list is a multiple of 16 bytes. | 4348 // list is a multiple of 16 bytes. |
4510 PushCPURegList(kCallerSaved); | 4349 PushCPURegList(kCallerSaved); |
4511 PushCPURegList(kCallerSavedV); | 4350 PushCPURegList(kCallerSavedFP); |
4512 | 4351 |
4513 // We can use caller-saved registers as scratch values (except for argN). | 4352 // We can use caller-saved registers as scratch values (except for argN). |
4514 CPURegList tmp_list = kCallerSaved; | 4353 CPURegList tmp_list = kCallerSaved; |
4515 CPURegList fp_tmp_list = kCallerSavedV; | 4354 CPURegList fp_tmp_list = kCallerSavedFP; |
4516 tmp_list.Remove(arg0, arg1, arg2, arg3); | 4355 tmp_list.Remove(arg0, arg1, arg2, arg3); |
4517 fp_tmp_list.Remove(arg0, arg1, arg2, arg3); | 4356 fp_tmp_list.Remove(arg0, arg1, arg2, arg3); |
4518 TmpList()->set_list(tmp_list.list()); | 4357 TmpList()->set_list(tmp_list.list()); |
4519 FPTmpList()->set_list(fp_tmp_list.list()); | 4358 FPTmpList()->set_list(fp_tmp_list.list()); |
4520 | 4359 |
4521 { UseScratchRegisterScope temps(this); | 4360 { UseScratchRegisterScope temps(this); |
4522 // If any of the arguments are the current stack pointer, allocate a new | 4361 // If any of the arguments are the current stack pointer, allocate a new |
4523 // register for them, and adjust the value to compensate for pushing the | 4362 // register for them, and adjust the value to compensate for pushing the |
4524 // caller-saved registers. | 4363 // caller-saved registers. |
4525 bool arg0_sp = StackPointer().Aliases(arg0); | 4364 bool arg0_sp = StackPointer().Aliases(arg0); |
4526 bool arg1_sp = StackPointer().Aliases(arg1); | 4365 bool arg1_sp = StackPointer().Aliases(arg1); |
4527 bool arg2_sp = StackPointer().Aliases(arg2); | 4366 bool arg2_sp = StackPointer().Aliases(arg2); |
4528 bool arg3_sp = StackPointer().Aliases(arg3); | 4367 bool arg3_sp = StackPointer().Aliases(arg3); |
4529 if (arg0_sp || arg1_sp || arg2_sp || arg3_sp) { | 4368 if (arg0_sp || arg1_sp || arg2_sp || arg3_sp) { |
4530 // Allocate a register to hold the original stack pointer value, to pass | 4369 // Allocate a register to hold the original stack pointer value, to pass |
4531 // to PrintfNoPreserve as an argument. | 4370 // to PrintfNoPreserve as an argument. |
4532 Register arg_sp = temps.AcquireX(); | 4371 Register arg_sp = temps.AcquireX(); |
4533 Add(arg_sp, StackPointer(), | 4372 Add(arg_sp, StackPointer(), |
4534 kCallerSaved.TotalSizeInBytes() + kCallerSavedV.TotalSizeInBytes()); | 4373 kCallerSaved.TotalSizeInBytes() + kCallerSavedFP.TotalSizeInBytes()); |
4535 if (arg0_sp) arg0 = Register::Create(arg_sp.code(), arg0.SizeInBits()); | 4374 if (arg0_sp) arg0 = Register::Create(arg_sp.code(), arg0.SizeInBits()); |
4536 if (arg1_sp) arg1 = Register::Create(arg_sp.code(), arg1.SizeInBits()); | 4375 if (arg1_sp) arg1 = Register::Create(arg_sp.code(), arg1.SizeInBits()); |
4537 if (arg2_sp) arg2 = Register::Create(arg_sp.code(), arg2.SizeInBits()); | 4376 if (arg2_sp) arg2 = Register::Create(arg_sp.code(), arg2.SizeInBits()); |
4538 if (arg3_sp) arg3 = Register::Create(arg_sp.code(), arg3.SizeInBits()); | 4377 if (arg3_sp) arg3 = Register::Create(arg_sp.code(), arg3.SizeInBits()); |
4539 } | 4378 } |
4540 | 4379 |
4541 // Preserve NZCV. | 4380 // Preserve NZCV. |
4542 { UseScratchRegisterScope temps(this); | 4381 { UseScratchRegisterScope temps(this); |
4543 Register tmp = temps.AcquireX(); | 4382 Register tmp = temps.AcquireX(); |
4544 Mrs(tmp, NZCV); | 4383 Mrs(tmp, NZCV); |
4545 Push(tmp, xzr); | 4384 Push(tmp, xzr); |
4546 } | 4385 } |
4547 | 4386 |
4548 PrintfNoPreserve(format, arg0, arg1, arg2, arg3); | 4387 PrintfNoPreserve(format, arg0, arg1, arg2, arg3); |
4549 | 4388 |
4550 // Restore NZCV. | 4389 // Restore NZCV. |
4551 { UseScratchRegisterScope temps(this); | 4390 { UseScratchRegisterScope temps(this); |
4552 Register tmp = temps.AcquireX(); | 4391 Register tmp = temps.AcquireX(); |
4553 Pop(xzr, tmp); | 4392 Pop(xzr, tmp); |
4554 Msr(NZCV, tmp); | 4393 Msr(NZCV, tmp); |
4555 } | 4394 } |
4556 } | 4395 } |
4557 | 4396 |
4558 PopCPURegList(kCallerSavedV); | 4397 PopCPURegList(kCallerSavedFP); |
4559 PopCPURegList(kCallerSaved); | 4398 PopCPURegList(kCallerSaved); |
4560 | 4399 |
4561 TmpList()->set_list(old_tmp_list); | 4400 TmpList()->set_list(old_tmp_list); |
4562 FPTmpList()->set_list(old_fp_tmp_list); | 4401 FPTmpList()->set_list(old_fp_tmp_list); |
4563 } | 4402 } |
4564 | 4403 |
4565 | 4404 |
4566 void MacroAssembler::EmitFrameSetupForCodeAgePatching() { | 4405 void MacroAssembler::EmitFrameSetupForCodeAgePatching() { |
4567 // TODO(jbramley): Other architectures use the internal memcpy to copy the | 4406 // TODO(jbramley): Other architectures use the internal memcpy to copy the |
4568 // sequence. If this is a performance bottleneck, we should consider caching | 4407 // sequence. If this is a performance bottleneck, we should consider caching |
(...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4662 available_->set_list(old_available_); | 4501 available_->set_list(old_available_); |
4663 availablefp_->set_list(old_availablefp_); | 4502 availablefp_->set_list(old_availablefp_); |
4664 } | 4503 } |
4665 | 4504 |
4666 | 4505 |
4667 Register UseScratchRegisterScope::AcquireSameSizeAs(const Register& reg) { | 4506 Register UseScratchRegisterScope::AcquireSameSizeAs(const Register& reg) { |
4668 int code = AcquireNextAvailable(available_).code(); | 4507 int code = AcquireNextAvailable(available_).code(); |
4669 return Register::Create(code, reg.SizeInBits()); | 4508 return Register::Create(code, reg.SizeInBits()); |
4670 } | 4509 } |
4671 | 4510 |
4672 VRegister UseScratchRegisterScope::AcquireSameSizeAs(const VRegister& reg) { | 4511 |
| 4512 FPRegister UseScratchRegisterScope::AcquireSameSizeAs(const FPRegister& reg) { |
4673 int code = AcquireNextAvailable(availablefp_).code(); | 4513 int code = AcquireNextAvailable(availablefp_).code(); |
4674 return VRegister::Create(code, reg.SizeInBits()); | 4514 return FPRegister::Create(code, reg.SizeInBits()); |
4675 } | 4515 } |
4676 | 4516 |
4677 | 4517 |
4678 CPURegister UseScratchRegisterScope::AcquireNextAvailable( | 4518 CPURegister UseScratchRegisterScope::AcquireNextAvailable( |
4679 CPURegList* available) { | 4519 CPURegList* available) { |
4680 CHECK(!available->IsEmpty()); | 4520 CHECK(!available->IsEmpty()); |
4681 CPURegister result = available->PopLowestIndex(); | 4521 CPURegister result = available->PopLowestIndex(); |
4682 DCHECK(!AreAliased(result, xzr, csp)); | 4522 DCHECK(!AreAliased(result, xzr, csp)); |
4683 return result; | 4523 return result; |
4684 } | 4524 } |
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4745 } | 4585 } |
4746 | 4586 |
4747 | 4587 |
4748 #undef __ | 4588 #undef __ |
4749 | 4589 |
4750 | 4590 |
4751 } // namespace internal | 4591 } // namespace internal |
4752 } // namespace v8 | 4592 } // namespace v8 |
4753 | 4593 |
4754 #endif // V8_TARGET_ARCH_ARM64 | 4594 #endif // V8_TARGET_ARCH_ARM64 |
OLD | NEW |