Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(335)

Side by Side Diff: src/arm64/macro-assembler-arm64.cc

Issue 2622643005: ARM64: Add NEON support (Closed)
Patch Set: Fix Math.abs properly Created 3 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/arm64/macro-assembler-arm64.h ('k') | src/arm64/macro-assembler-arm64-inl.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
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
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
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
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
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
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
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
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
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
OLDNEW
« no previous file with comments | « src/arm64/macro-assembler-arm64.h ('k') | src/arm64/macro-assembler-arm64-inl.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698