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

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

Issue 2819093002: Revert "Reland "ARM64: Add NEON support"" (Closed)
Patch Set: 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 }
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
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
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
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
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
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
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
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
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
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
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
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
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
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