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

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

Issue 2896303003: Reland of Reland of "ARM64: Add NEON support" (Closed)
Patch Set: Created 3 years, 7 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 656 matching lines...) Expand 10 before | Expand all | Expand 10 after
2069 } 2232 }
2070 2233
2071 AssertNotSmi(object); 2234 AssertNotSmi(object);
2072 2235
2073 UseScratchRegisterScope temps(this); 2236 UseScratchRegisterScope temps(this);
2074 Register temp = temps.AcquireX(); 2237 Register temp = temps.AcquireX();
2075 Ldr(temp, FieldMemOperand(object, HeapObject::kMapOffset)); 2238 Ldr(temp, FieldMemOperand(object, HeapObject::kMapOffset));
2076 JumpIfNotRoot(temp, Heap::kHeapNumberMapRootIndex, on_not_heap_number); 2239 JumpIfNotRoot(temp, Heap::kHeapNumberMapRootIndex, on_not_heap_number);
2077 } 2240 }
2078 2241
2079 2242 void MacroAssembler::TryRepresentDoubleAsInt(Register as_int, VRegister value,
2080 void MacroAssembler::TryRepresentDoubleAsInt(Register as_int, 2243 VRegister scratch_d,
2081 FPRegister value,
2082 FPRegister scratch_d,
2083 Label* on_successful_conversion, 2244 Label* on_successful_conversion,
2084 Label* on_failed_conversion) { 2245 Label* on_failed_conversion) {
2085 // Convert to an int and back again, then compare with the original value. 2246 // Convert to an int and back again, then compare with the original value.
2086 Fcvtzs(as_int, value); 2247 Fcvtzs(as_int, value);
2087 Scvtf(scratch_d, as_int); 2248 Scvtf(scratch_d, as_int);
2088 Fcmp(value, scratch_d); 2249 Fcmp(value, scratch_d);
2089 2250
2090 if (on_successful_conversion) { 2251 if (on_successful_conversion) {
2091 B(on_successful_conversion, eq); 2252 B(on_successful_conversion, eq);
2092 } 2253 }
(...skipping 593 matching lines...) Expand 10 before | Expand all | Expand 10 after
2686 // Drop the execution stack down to the frame pointer and restore 2847 // Drop the execution stack down to the frame pointer and restore
2687 // the caller frame pointer and return address. 2848 // the caller frame pointer and return address.
2688 Mov(jssp, fp); 2849 Mov(jssp, fp);
2689 AssertStackConsistency(); 2850 AssertStackConsistency();
2690 Pop(fp, lr); 2851 Pop(fp, lr);
2691 } 2852 }
2692 } 2853 }
2693 2854
2694 2855
2695 void MacroAssembler::ExitFramePreserveFPRegs() { 2856 void MacroAssembler::ExitFramePreserveFPRegs() {
2696 PushCPURegList(kCallerSavedFP); 2857 PushCPURegList(kCallerSavedV);
2697 } 2858 }
2698 2859
2699 2860
2700 void MacroAssembler::ExitFrameRestoreFPRegs() { 2861 void MacroAssembler::ExitFrameRestoreFPRegs() {
2701 // Read the registers from the stack without popping them. The stack pointer 2862 // Read the registers from the stack without popping them. The stack pointer
2702 // will be reset as part of the unwinding process. 2863 // will be reset as part of the unwinding process.
2703 CPURegList saved_fp_regs = kCallerSavedFP; 2864 CPURegList saved_fp_regs = kCallerSavedV;
2704 DCHECK(saved_fp_regs.Count() % 2 == 0); 2865 DCHECK(saved_fp_regs.Count() % 2 == 0);
2705 2866
2706 int offset = ExitFrameConstants::kLastExitFrameField; 2867 int offset = ExitFrameConstants::kLastExitFrameField;
2707 while (!saved_fp_regs.IsEmpty()) { 2868 while (!saved_fp_regs.IsEmpty()) {
2708 const CPURegister& dst0 = saved_fp_regs.PopHighestIndex(); 2869 const CPURegister& dst0 = saved_fp_regs.PopHighestIndex();
2709 const CPURegister& dst1 = saved_fp_regs.PopHighestIndex(); 2870 const CPURegister& dst1 = saved_fp_regs.PopHighestIndex();
2710 offset -= 2 * kDRegSize; 2871 offset -= 2 * kDRegSize;
2711 Ldp(dst1, dst0, MemOperand(fp, offset)); 2872 Ldp(dst1, dst0, MemOperand(fp, offset));
2712 } 2873 }
2713 } 2874 }
(...skipping 458 matching lines...) Expand 10 before | Expand all | Expand 10 after
3172 NO_ALLOCATION_FLAGS); 3333 NO_ALLOCATION_FLAGS);
3173 3334
3174 Heap::RootListIndex map_index = mode == MUTABLE 3335 Heap::RootListIndex map_index = mode == MUTABLE
3175 ? Heap::kMutableHeapNumberMapRootIndex 3336 ? Heap::kMutableHeapNumberMapRootIndex
3176 : Heap::kHeapNumberMapRootIndex; 3337 : Heap::kHeapNumberMapRootIndex;
3177 3338
3178 // Prepare the heap number map. 3339 // Prepare the heap number map.
3179 if (!heap_number_map.IsValid()) { 3340 if (!heap_number_map.IsValid()) {
3180 // If we have a valid value register, use the same type of register to store 3341 // If we have a valid value register, use the same type of register to store
3181 // the map so we can use STP to store both in one instruction. 3342 // the map so we can use STP to store both in one instruction.
3182 if (value.IsValid() && value.IsFPRegister()) { 3343 if (value.IsValid() && value.IsVRegister()) {
3183 heap_number_map = temps.AcquireD(); 3344 heap_number_map = temps.AcquireD();
3184 } else { 3345 } else {
3185 heap_number_map = scratch1; 3346 heap_number_map = scratch1;
3186 } 3347 }
3187 LoadRoot(heap_number_map, map_index); 3348 LoadRoot(heap_number_map, map_index);
3188 } 3349 }
3189 if (emit_debug_code()) { 3350 if (emit_debug_code()) {
3190 Register map; 3351 Register map;
3191 if (heap_number_map.IsFPRegister()) { 3352 if (heap_number_map.IsVRegister()) {
3192 map = scratch1; 3353 map = scratch1;
3193 Fmov(map, DoubleRegister(heap_number_map)); 3354 Fmov(map, DoubleRegister(heap_number_map));
3194 } else { 3355 } else {
3195 map = Register(heap_number_map); 3356 map = Register(heap_number_map);
3196 } 3357 }
3197 AssertRegisterIsRoot(map, map_index); 3358 AssertRegisterIsRoot(map, map_index);
3198 } 3359 }
3199 3360
3200 // Store the heap number map and the value in the allocated object. 3361 // Store the heap number map and the value in the allocated object.
3201 if (value.IsSameSizeAndType(heap_number_map)) { 3362 if (value.IsSameSizeAndType(heap_number_map)) {
(...skipping 441 matching lines...) Expand 10 before | Expand all | Expand 10 after
3643 const int num_unsaved = kNumSafepointRegisters - kNumSafepointSavedRegisters; 3804 const int num_unsaved = kNumSafepointRegisters - kNumSafepointSavedRegisters;
3644 DCHECK(num_unsaved >= 0); 3805 DCHECK(num_unsaved >= 0);
3645 Claim(num_unsaved); 3806 Claim(num_unsaved);
3646 PushXRegList(kSafepointSavedRegisters); 3807 PushXRegList(kSafepointSavedRegisters);
3647 } 3808 }
3648 3809
3649 3810
3650 void MacroAssembler::PushSafepointRegistersAndDoubles() { 3811 void MacroAssembler::PushSafepointRegistersAndDoubles() {
3651 PushSafepointRegisters(); 3812 PushSafepointRegisters();
3652 PushCPURegList(CPURegList( 3813 PushCPURegList(CPURegList(
3653 CPURegister::kFPRegister, kDRegSizeInBits, 3814 CPURegister::kVRegister, kDRegSizeInBits,
3654 RegisterConfiguration::Crankshaft()->allocatable_double_codes_mask())); 3815 RegisterConfiguration::Crankshaft()->allocatable_double_codes_mask()));
3655 } 3816 }
3656 3817
3657 3818
3658 void MacroAssembler::PopSafepointRegistersAndDoubles() { 3819 void MacroAssembler::PopSafepointRegistersAndDoubles() {
3659 PopCPURegList(CPURegList( 3820 PopCPURegList(CPURegList(
3660 CPURegister::kFPRegister, kDRegSizeInBits, 3821 CPURegister::kVRegister, kDRegSizeInBits,
3661 RegisterConfiguration::Crankshaft()->allocatable_double_codes_mask())); 3822 RegisterConfiguration::Crankshaft()->allocatable_double_codes_mask()));
3662 PopSafepointRegisters(); 3823 PopSafepointRegisters();
3663 } 3824 }
3664 3825
3665 void MacroAssembler::StoreToSafepointRegisterSlot(Register src, Register dst) { 3826 void MacroAssembler::StoreToSafepointRegisterSlot(Register src, Register dst) {
3666 Poke(src, SafepointRegisterStackIndex(dst.code()) * kPointerSize); 3827 Poke(src, SafepointRegisterStackIndex(dst.code()) * kPointerSize);
3667 } 3828 }
3668 3829
3669 void MacroAssembler::LoadFromSafepointRegisterSlot(Register dst, Register src) { 3830 void MacroAssembler::LoadFromSafepointRegisterSlot(Register dst, Register src) {
3670 Peek(src, SafepointRegisterStackIndex(dst.code()) * kPointerSize); 3831 Peek(src, SafepointRegisterStackIndex(dst.code()) * kPointerSize);
(...skipping 530 matching lines...) Expand 10 before | Expand all | Expand 10 after
4201 CPURegister args[kPrintfMaxArgCount] = {arg0, arg1, arg2, arg3}; 4362 CPURegister args[kPrintfMaxArgCount] = {arg0, arg1, arg2, arg3};
4202 CPURegister pcs[kPrintfMaxArgCount] = {NoReg, NoReg, NoReg, NoReg}; 4363 CPURegister pcs[kPrintfMaxArgCount] = {NoReg, NoReg, NoReg, NoReg};
4203 4364
4204 int arg_count = kPrintfMaxArgCount; 4365 int arg_count = kPrintfMaxArgCount;
4205 4366
4206 // The PCS varargs registers for printf. Note that x0 is used for the printf 4367 // The PCS varargs registers for printf. Note that x0 is used for the printf
4207 // format string. 4368 // format string.
4208 static const CPURegList kPCSVarargs = 4369 static const CPURegList kPCSVarargs =
4209 CPURegList(CPURegister::kRegister, kXRegSizeInBits, 1, arg_count); 4370 CPURegList(CPURegister::kRegister, kXRegSizeInBits, 1, arg_count);
4210 static const CPURegList kPCSVarargsFP = 4371 static const CPURegList kPCSVarargsFP =
4211 CPURegList(CPURegister::kFPRegister, kDRegSizeInBits, 0, arg_count - 1); 4372 CPURegList(CPURegister::kVRegister, kDRegSizeInBits, 0, arg_count - 1);
4212 4373
4213 // We can use caller-saved registers as scratch values, except for the 4374 // We can use caller-saved registers as scratch values, except for the
4214 // arguments and the PCS registers where they might need to go. 4375 // arguments and the PCS registers where they might need to go.
4215 CPURegList tmp_list = kCallerSaved; 4376 CPURegList tmp_list = kCallerSaved;
4216 tmp_list.Remove(x0); // Used to pass the format string. 4377 tmp_list.Remove(x0); // Used to pass the format string.
4217 tmp_list.Remove(kPCSVarargs); 4378 tmp_list.Remove(kPCSVarargs);
4218 tmp_list.Remove(arg0, arg1, arg2, arg3); 4379 tmp_list.Remove(arg0, arg1, arg2, arg3);
4219 4380
4220 CPURegList fp_tmp_list = kCallerSavedFP; 4381 CPURegList fp_tmp_list = kCallerSavedV;
4221 fp_tmp_list.Remove(kPCSVarargsFP); 4382 fp_tmp_list.Remove(kPCSVarargsFP);
4222 fp_tmp_list.Remove(arg0, arg1, arg2, arg3); 4383 fp_tmp_list.Remove(arg0, arg1, arg2, arg3);
4223 4384
4224 // Override the MacroAssembler's scratch register list. The lists will be 4385 // Override the MacroAssembler's scratch register list. The lists will be
4225 // reset automatically at the end of the UseScratchRegisterScope. 4386 // reset automatically at the end of the UseScratchRegisterScope.
4226 UseScratchRegisterScope temps(this); 4387 UseScratchRegisterScope temps(this);
4227 TmpList()->set_list(tmp_list.list()); 4388 TmpList()->set_list(tmp_list.list());
4228 FPTmpList()->set_list(fp_tmp_list.list()); 4389 FPTmpList()->set_list(fp_tmp_list.list());
4229 4390
4230 // Copies of the printf vararg registers that we can pop from. 4391 // Copies of the printf vararg registers that we can pop from.
4231 CPURegList pcs_varargs = kPCSVarargs; 4392 CPURegList pcs_varargs = kPCSVarargs;
4232 CPURegList pcs_varargs_fp = kPCSVarargsFP; 4393 CPURegList pcs_varargs_fp = kPCSVarargsFP;
4233 4394
4234 // Place the arguments. There are lots of clever tricks and optimizations we 4395 // Place the arguments. There are lots of clever tricks and optimizations we
4235 // could use here, but Printf is a debug tool so instead we just try to keep 4396 // could use here, but Printf is a debug tool so instead we just try to keep
4236 // it simple: Move each input that isn't already in the right place to a 4397 // it simple: Move each input that isn't already in the right place to a
4237 // scratch register, then move everything back. 4398 // scratch register, then move everything back.
4238 for (unsigned i = 0; i < kPrintfMaxArgCount; i++) { 4399 for (unsigned i = 0; i < kPrintfMaxArgCount; i++) {
4239 // Work out the proper PCS register for this argument. 4400 // Work out the proper PCS register for this argument.
4240 if (args[i].IsRegister()) { 4401 if (args[i].IsRegister()) {
4241 pcs[i] = pcs_varargs.PopLowestIndex().X(); 4402 pcs[i] = pcs_varargs.PopLowestIndex().X();
4242 // We might only need a W register here. We need to know the size of the 4403 // We might only need a W register here. We need to know the size of the
4243 // argument so we can properly encode it for the simulator call. 4404 // argument so we can properly encode it for the simulator call.
4244 if (args[i].Is32Bits()) pcs[i] = pcs[i].W(); 4405 if (args[i].Is32Bits()) pcs[i] = pcs[i].W();
4245 } else if (args[i].IsFPRegister()) { 4406 } else if (args[i].IsVRegister()) {
4246 // In C, floats are always cast to doubles for varargs calls. 4407 // In C, floats are always cast to doubles for varargs calls.
4247 pcs[i] = pcs_varargs_fp.PopLowestIndex().D(); 4408 pcs[i] = pcs_varargs_fp.PopLowestIndex().D();
4248 } else { 4409 } else {
4249 DCHECK(args[i].IsNone()); 4410 DCHECK(args[i].IsNone());
4250 arg_count = i; 4411 arg_count = i;
4251 break; 4412 break;
4252 } 4413 }
4253 4414
4254 // If the argument is already in the right place, leave it where it is. 4415 // If the argument is already in the right place, leave it where it is.
4255 if (args[i].Aliases(pcs[i])) continue; 4416 if (args[i].Aliases(pcs[i])) continue;
4256 4417
4257 // Otherwise, if the argument is in a PCS argument register, allocate an 4418 // Otherwise, if the argument is in a PCS argument register, allocate an
4258 // appropriate scratch register and then move it out of the way. 4419 // appropriate scratch register and then move it out of the way.
4259 if (kPCSVarargs.IncludesAliasOf(args[i]) || 4420 if (kPCSVarargs.IncludesAliasOf(args[i]) ||
4260 kPCSVarargsFP.IncludesAliasOf(args[i])) { 4421 kPCSVarargsFP.IncludesAliasOf(args[i])) {
4261 if (args[i].IsRegister()) { 4422 if (args[i].IsRegister()) {
4262 Register old_arg = Register(args[i]); 4423 Register old_arg = Register(args[i]);
4263 Register new_arg = temps.AcquireSameSizeAs(old_arg); 4424 Register new_arg = temps.AcquireSameSizeAs(old_arg);
4264 Mov(new_arg, old_arg); 4425 Mov(new_arg, old_arg);
4265 args[i] = new_arg; 4426 args[i] = new_arg;
4266 } else { 4427 } else {
4267 FPRegister old_arg = FPRegister(args[i]); 4428 VRegister old_arg = VRegister(args[i]);
4268 FPRegister new_arg = temps.AcquireSameSizeAs(old_arg); 4429 VRegister new_arg = temps.AcquireSameSizeAs(old_arg);
4269 Fmov(new_arg, old_arg); 4430 Fmov(new_arg, old_arg);
4270 args[i] = new_arg; 4431 args[i] = new_arg;
4271 } 4432 }
4272 } 4433 }
4273 } 4434 }
4274 4435
4275 // Do a second pass to move values into their final positions and perform any 4436 // Do a second pass to move values into their final positions and perform any
4276 // conversions that may be required. 4437 // conversions that may be required.
4277 for (int i = 0; i < arg_count; i++) { 4438 for (int i = 0; i < arg_count; i++) {
4278 DCHECK(pcs[i].type() == args[i].type()); 4439 DCHECK(pcs[i].type() == args[i].type());
4279 if (pcs[i].IsRegister()) { 4440 if (pcs[i].IsRegister()) {
4280 Mov(Register(pcs[i]), Register(args[i]), kDiscardForSameWReg); 4441 Mov(Register(pcs[i]), Register(args[i]), kDiscardForSameWReg);
4281 } else { 4442 } else {
4282 DCHECK(pcs[i].IsFPRegister()); 4443 DCHECK(pcs[i].IsVRegister());
4283 if (pcs[i].SizeInBytes() == args[i].SizeInBytes()) { 4444 if (pcs[i].SizeInBytes() == args[i].SizeInBytes()) {
4284 Fmov(FPRegister(pcs[i]), FPRegister(args[i])); 4445 Fmov(VRegister(pcs[i]), VRegister(args[i]));
4285 } else { 4446 } else {
4286 Fcvt(FPRegister(pcs[i]), FPRegister(args[i])); 4447 Fcvt(VRegister(pcs[i]), VRegister(args[i]));
4287 } 4448 }
4288 } 4449 }
4289 } 4450 }
4290 4451
4291 // Load the format string into x0, as per the procedure-call standard. 4452 // Load the format string into x0, as per the procedure-call standard.
4292 // 4453 //
4293 // To make the code as portable as possible, the format string is encoded 4454 // To make the code as portable as possible, the format string is encoded
4294 // directly in the instruction stream. It might be cleaner to encode it in a 4455 // directly in the instruction stream. It might be cleaner to encode it in a
4295 // literal pool, but since Printf is usually used for debugging, it is 4456 // literal pool, but since Printf is usually used for debugging, it is
4296 // beneficial for it to be minimally dependent on other features. 4457 // beneficial for it to be minimally dependent on other features.
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after
4364 // available as scratch registers until we've preserved them. 4525 // available as scratch registers until we've preserved them.
4365 RegList old_tmp_list = TmpList()->list(); 4526 RegList old_tmp_list = TmpList()->list();
4366 RegList old_fp_tmp_list = FPTmpList()->list(); 4527 RegList old_fp_tmp_list = FPTmpList()->list();
4367 TmpList()->set_list(0); 4528 TmpList()->set_list(0);
4368 FPTmpList()->set_list(0); 4529 FPTmpList()->set_list(0);
4369 4530
4370 // Preserve all caller-saved registers as well as NZCV. 4531 // Preserve all caller-saved registers as well as NZCV.
4371 // If csp is the stack pointer, PushCPURegList asserts that the size of each 4532 // If csp is the stack pointer, PushCPURegList asserts that the size of each
4372 // list is a multiple of 16 bytes. 4533 // list is a multiple of 16 bytes.
4373 PushCPURegList(kCallerSaved); 4534 PushCPURegList(kCallerSaved);
4374 PushCPURegList(kCallerSavedFP); 4535 PushCPURegList(kCallerSavedV);
4375 4536
4376 // We can use caller-saved registers as scratch values (except for argN). 4537 // We can use caller-saved registers as scratch values (except for argN).
4377 CPURegList tmp_list = kCallerSaved; 4538 CPURegList tmp_list = kCallerSaved;
4378 CPURegList fp_tmp_list = kCallerSavedFP; 4539 CPURegList fp_tmp_list = kCallerSavedV;
4379 tmp_list.Remove(arg0, arg1, arg2, arg3); 4540 tmp_list.Remove(arg0, arg1, arg2, arg3);
4380 fp_tmp_list.Remove(arg0, arg1, arg2, arg3); 4541 fp_tmp_list.Remove(arg0, arg1, arg2, arg3);
4381 TmpList()->set_list(tmp_list.list()); 4542 TmpList()->set_list(tmp_list.list());
4382 FPTmpList()->set_list(fp_tmp_list.list()); 4543 FPTmpList()->set_list(fp_tmp_list.list());
4383 4544
4384 { UseScratchRegisterScope temps(this); 4545 { UseScratchRegisterScope temps(this);
4385 // If any of the arguments are the current stack pointer, allocate a new 4546 // If any of the arguments are the current stack pointer, allocate a new
4386 // register for them, and adjust the value to compensate for pushing the 4547 // register for them, and adjust the value to compensate for pushing the
4387 // caller-saved registers. 4548 // caller-saved registers.
4388 bool arg0_sp = StackPointer().Aliases(arg0); 4549 bool arg0_sp = StackPointer().Aliases(arg0);
4389 bool arg1_sp = StackPointer().Aliases(arg1); 4550 bool arg1_sp = StackPointer().Aliases(arg1);
4390 bool arg2_sp = StackPointer().Aliases(arg2); 4551 bool arg2_sp = StackPointer().Aliases(arg2);
4391 bool arg3_sp = StackPointer().Aliases(arg3); 4552 bool arg3_sp = StackPointer().Aliases(arg3);
4392 if (arg0_sp || arg1_sp || arg2_sp || arg3_sp) { 4553 if (arg0_sp || arg1_sp || arg2_sp || arg3_sp) {
4393 // Allocate a register to hold the original stack pointer value, to pass 4554 // Allocate a register to hold the original stack pointer value, to pass
4394 // to PrintfNoPreserve as an argument. 4555 // to PrintfNoPreserve as an argument.
4395 Register arg_sp = temps.AcquireX(); 4556 Register arg_sp = temps.AcquireX();
4396 Add(arg_sp, StackPointer(), 4557 Add(arg_sp, StackPointer(),
4397 kCallerSaved.TotalSizeInBytes() + kCallerSavedFP.TotalSizeInBytes()); 4558 kCallerSaved.TotalSizeInBytes() + kCallerSavedV.TotalSizeInBytes());
4398 if (arg0_sp) arg0 = Register::Create(arg_sp.code(), arg0.SizeInBits()); 4559 if (arg0_sp) arg0 = Register::Create(arg_sp.code(), arg0.SizeInBits());
4399 if (arg1_sp) arg1 = Register::Create(arg_sp.code(), arg1.SizeInBits()); 4560 if (arg1_sp) arg1 = Register::Create(arg_sp.code(), arg1.SizeInBits());
4400 if (arg2_sp) arg2 = Register::Create(arg_sp.code(), arg2.SizeInBits()); 4561 if (arg2_sp) arg2 = Register::Create(arg_sp.code(), arg2.SizeInBits());
4401 if (arg3_sp) arg3 = Register::Create(arg_sp.code(), arg3.SizeInBits()); 4562 if (arg3_sp) arg3 = Register::Create(arg_sp.code(), arg3.SizeInBits());
4402 } 4563 }
4403 4564
4404 // Preserve NZCV. 4565 // Preserve NZCV.
4405 { UseScratchRegisterScope temps(this); 4566 { UseScratchRegisterScope temps(this);
4406 Register tmp = temps.AcquireX(); 4567 Register tmp = temps.AcquireX();
4407 Mrs(tmp, NZCV); 4568 Mrs(tmp, NZCV);
4408 Push(tmp, xzr); 4569 Push(tmp, xzr);
4409 } 4570 }
4410 4571
4411 PrintfNoPreserve(format, arg0, arg1, arg2, arg3); 4572 PrintfNoPreserve(format, arg0, arg1, arg2, arg3);
4412 4573
4413 // Restore NZCV. 4574 // Restore NZCV.
4414 { UseScratchRegisterScope temps(this); 4575 { UseScratchRegisterScope temps(this);
4415 Register tmp = temps.AcquireX(); 4576 Register tmp = temps.AcquireX();
4416 Pop(xzr, tmp); 4577 Pop(xzr, tmp);
4417 Msr(NZCV, tmp); 4578 Msr(NZCV, tmp);
4418 } 4579 }
4419 } 4580 }
4420 4581
4421 PopCPURegList(kCallerSavedFP); 4582 PopCPURegList(kCallerSavedV);
4422 PopCPURegList(kCallerSaved); 4583 PopCPURegList(kCallerSaved);
4423 4584
4424 TmpList()->set_list(old_tmp_list); 4585 TmpList()->set_list(old_tmp_list);
4425 FPTmpList()->set_list(old_fp_tmp_list); 4586 FPTmpList()->set_list(old_fp_tmp_list);
4426 } 4587 }
4427 4588
4428 4589
4429 void MacroAssembler::EmitFrameSetupForCodeAgePatching() { 4590 void MacroAssembler::EmitFrameSetupForCodeAgePatching() {
4430 // TODO(jbramley): Other architectures use the internal memcpy to copy the 4591 // TODO(jbramley): Other architectures use the internal memcpy to copy the
4431 // sequence. If this is a performance bottleneck, we should consider caching 4592 // sequence. If this is a performance bottleneck, we should consider caching
(...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after
4525 available_->set_list(old_available_); 4686 available_->set_list(old_available_);
4526 availablefp_->set_list(old_availablefp_); 4687 availablefp_->set_list(old_availablefp_);
4527 } 4688 }
4528 4689
4529 4690
4530 Register UseScratchRegisterScope::AcquireSameSizeAs(const Register& reg) { 4691 Register UseScratchRegisterScope::AcquireSameSizeAs(const Register& reg) {
4531 int code = AcquireNextAvailable(available_).code(); 4692 int code = AcquireNextAvailable(available_).code();
4532 return Register::Create(code, reg.SizeInBits()); 4693 return Register::Create(code, reg.SizeInBits());
4533 } 4694 }
4534 4695
4535 4696 VRegister UseScratchRegisterScope::AcquireSameSizeAs(const VRegister& reg) {
4536 FPRegister UseScratchRegisterScope::AcquireSameSizeAs(const FPRegister& reg) {
4537 int code = AcquireNextAvailable(availablefp_).code(); 4697 int code = AcquireNextAvailable(availablefp_).code();
4538 return FPRegister::Create(code, reg.SizeInBits()); 4698 return VRegister::Create(code, reg.SizeInBits());
4539 } 4699 }
4540 4700
4541 4701
4542 CPURegister UseScratchRegisterScope::AcquireNextAvailable( 4702 CPURegister UseScratchRegisterScope::AcquireNextAvailable(
4543 CPURegList* available) { 4703 CPURegList* available) {
4544 CHECK(!available->IsEmpty()); 4704 CHECK(!available->IsEmpty());
4545 CPURegister result = available->PopLowestIndex(); 4705 CPURegister result = available->PopLowestIndex();
4546 DCHECK(!AreAliased(result, xzr, csp)); 4706 DCHECK(!AreAliased(result, xzr, csp));
4547 return result; 4707 return result;
4548 } 4708 }
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after
4609 } 4769 }
4610 4770
4611 4771
4612 #undef __ 4772 #undef __
4613 4773
4614 4774
4615 } // namespace internal 4775 } // namespace internal
4616 } // namespace v8 4776 } // namespace v8
4617 4777
4618 #endif // V8_TARGET_ARCH_ARM64 4778 #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