| OLD | NEW |
| 1 // Copyright 2013 the V8 project authors. All rights reserved. | 1 // Copyright 2013 the V8 project authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #ifndef V8_ARM64_MACRO_ASSEMBLER_ARM64_H_ | 5 #ifndef V8_ARM64_MACRO_ASSEMBLER_ARM64_H_ |
| 6 #define V8_ARM64_MACRO_ASSEMBLER_ARM64_H_ | 6 #define V8_ARM64_MACRO_ASSEMBLER_ARM64_H_ |
| 7 | 7 |
| 8 #include <vector> | 8 #include <vector> |
| 9 | 9 |
| 10 #include "src/globals.h" | 10 #include "src/globals.h" |
| (...skipping 348 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 359 inline void Fmov(FPRegister fd, Register rn); | 359 inline void Fmov(FPRegister fd, Register rn); |
| 360 // Provide explicit double and float interfaces for FP immediate moves, rather | 360 // Provide explicit double and float interfaces for FP immediate moves, rather |
| 361 // than relying on implicit C++ casts. This allows signalling NaNs to be | 361 // than relying on implicit C++ casts. This allows signalling NaNs to be |
| 362 // preserved when the immediate matches the format of fd. Most systems convert | 362 // preserved when the immediate matches the format of fd. Most systems convert |
| 363 // signalling NaNs to quiet NaNs when converting between float and double. | 363 // signalling NaNs to quiet NaNs when converting between float and double. |
| 364 inline void Fmov(FPRegister fd, double imm); | 364 inline void Fmov(FPRegister fd, double imm); |
| 365 inline void Fmov(FPRegister fd, float imm); | 365 inline void Fmov(FPRegister fd, float imm); |
| 366 // Provide a template to allow other types to be converted automatically. | 366 // Provide a template to allow other types to be converted automatically. |
| 367 template<typename T> | 367 template<typename T> |
| 368 void Fmov(FPRegister fd, T imm) { | 368 void Fmov(FPRegister fd, T imm) { |
| 369 ASSERT(allow_macro_instructions_); | 369 DCHECK(allow_macro_instructions_); |
| 370 Fmov(fd, static_cast<double>(imm)); | 370 Fmov(fd, static_cast<double>(imm)); |
| 371 } | 371 } |
| 372 inline void Fmov(Register rd, FPRegister fn); | 372 inline void Fmov(Register rd, FPRegister fn); |
| 373 inline void Fmsub(const FPRegister& fd, | 373 inline void Fmsub(const FPRegister& fd, |
| 374 const FPRegister& fn, | 374 const FPRegister& fn, |
| 375 const FPRegister& fm, | 375 const FPRegister& fm, |
| 376 const FPRegister& fa); | 376 const FPRegister& fa); |
| 377 inline void Fmul(const FPRegister& fd, | 377 inline void Fmul(const FPRegister& fd, |
| 378 const FPRegister& fn, | 378 const FPRegister& fn, |
| 379 const FPRegister& fm); | 379 const FPRegister& fm); |
| (...skipping 232 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 612 // allows push requests to be queued up, then flushed at once. The | 612 // allows push requests to be queued up, then flushed at once. The |
| 613 // MacroAssembler will try to generate the most efficient sequence required. | 613 // MacroAssembler will try to generate the most efficient sequence required. |
| 614 // | 614 // |
| 615 // Unlike the other Push and Pop macros, PushPopQueue can handle mixed sets of | 615 // Unlike the other Push and Pop macros, PushPopQueue can handle mixed sets of |
| 616 // register sizes and types. | 616 // register sizes and types. |
| 617 class PushPopQueue { | 617 class PushPopQueue { |
| 618 public: | 618 public: |
| 619 explicit PushPopQueue(MacroAssembler* masm) : masm_(masm), size_(0) { } | 619 explicit PushPopQueue(MacroAssembler* masm) : masm_(masm), size_(0) { } |
| 620 | 620 |
| 621 ~PushPopQueue() { | 621 ~PushPopQueue() { |
| 622 ASSERT(queued_.empty()); | 622 DCHECK(queued_.empty()); |
| 623 } | 623 } |
| 624 | 624 |
| 625 void Queue(const CPURegister& rt) { | 625 void Queue(const CPURegister& rt) { |
| 626 size_ += rt.SizeInBytes(); | 626 size_ += rt.SizeInBytes(); |
| 627 queued_.push_back(rt); | 627 queued_.push_back(rt); |
| 628 } | 628 } |
| 629 | 629 |
| 630 enum PreambleDirective { | 630 enum PreambleDirective { |
| 631 WITH_PREAMBLE, | 631 WITH_PREAMBLE, |
| 632 SKIP_PREAMBLE | 632 SKIP_PREAMBLE |
| (...skipping 131 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 764 // Floating-point registers are popped after general-purpose registers, and | 764 // Floating-point registers are popped after general-purpose registers, and |
| 765 // thus come from higher addresses. | 765 // thus come from higher addresses. |
| 766 // | 766 // |
| 767 // This method must not be called unless the current stack pointer (as set by | 767 // This method must not be called unless the current stack pointer (as set by |
| 768 // SetStackPointer) is the system stack pointer (csp), and is aligned to | 768 // SetStackPointer) is the system stack pointer (csp), and is aligned to |
| 769 // ActivationFrameAlignment(). | 769 // ActivationFrameAlignment(). |
| 770 void PopCalleeSavedRegisters(); | 770 void PopCalleeSavedRegisters(); |
| 771 | 771 |
| 772 // Set the current stack pointer, but don't generate any code. | 772 // Set the current stack pointer, but don't generate any code. |
| 773 inline void SetStackPointer(const Register& stack_pointer) { | 773 inline void SetStackPointer(const Register& stack_pointer) { |
| 774 ASSERT(!TmpList()->IncludesAliasOf(stack_pointer)); | 774 DCHECK(!TmpList()->IncludesAliasOf(stack_pointer)); |
| 775 sp_ = stack_pointer; | 775 sp_ = stack_pointer; |
| 776 } | 776 } |
| 777 | 777 |
| 778 // Return the current stack pointer, as set by SetStackPointer. | 778 // Return the current stack pointer, as set by SetStackPointer. |
| 779 inline const Register& StackPointer() const { | 779 inline const Register& StackPointer() const { |
| 780 return sp_; | 780 return sp_; |
| 781 } | 781 } |
| 782 | 782 |
| 783 // Align csp for a frame, as per ActivationFrameAlignment, and make it the | 783 // Align csp for a frame, as per ActivationFrameAlignment, and make it the |
| 784 // current stack pointer. | 784 // current stack pointer. |
| 785 inline void AlignAndSetCSPForFrame() { | 785 inline void AlignAndSetCSPForFrame() { |
| 786 int sp_alignment = ActivationFrameAlignment(); | 786 int sp_alignment = ActivationFrameAlignment(); |
| 787 // AAPCS64 mandates at least 16-byte alignment. | 787 // AAPCS64 mandates at least 16-byte alignment. |
| 788 ASSERT(sp_alignment >= 16); | 788 DCHECK(sp_alignment >= 16); |
| 789 ASSERT(IsPowerOf2(sp_alignment)); | 789 DCHECK(IsPowerOf2(sp_alignment)); |
| 790 Bic(csp, StackPointer(), sp_alignment - 1); | 790 Bic(csp, StackPointer(), sp_alignment - 1); |
| 791 SetStackPointer(csp); | 791 SetStackPointer(csp); |
| 792 } | 792 } |
| 793 | 793 |
| 794 // Push the system stack pointer (csp) down to allow the same to be done to | 794 // Push the system stack pointer (csp) down to allow the same to be done to |
| 795 // the current stack pointer (according to StackPointer()). This must be | 795 // the current stack pointer (according to StackPointer()). This must be |
| 796 // called _before_ accessing the memory. | 796 // called _before_ accessing the memory. |
| 797 // | 797 // |
| 798 // This is necessary when pushing or otherwise adding things to the stack, to | 798 // This is necessary when pushing or otherwise adding things to the stack, to |
| 799 // satisfy the AAPCS64 constraint that the memory below the system stack | 799 // satisfy the AAPCS64 constraint that the memory below the system stack |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 834 // Load both TrueValue and FalseValue roots. | 834 // Load both TrueValue and FalseValue roots. |
| 835 void LoadTrueFalseRoots(Register true_root, Register false_root); | 835 void LoadTrueFalseRoots(Register true_root, Register false_root); |
| 836 | 836 |
| 837 void LoadHeapObject(Register dst, Handle<HeapObject> object); | 837 void LoadHeapObject(Register dst, Handle<HeapObject> object); |
| 838 | 838 |
| 839 void LoadObject(Register result, Handle<Object> object) { | 839 void LoadObject(Register result, Handle<Object> object) { |
| 840 AllowDeferredHandleDereference heap_object_check; | 840 AllowDeferredHandleDereference heap_object_check; |
| 841 if (object->IsHeapObject()) { | 841 if (object->IsHeapObject()) { |
| 842 LoadHeapObject(result, Handle<HeapObject>::cast(object)); | 842 LoadHeapObject(result, Handle<HeapObject>::cast(object)); |
| 843 } else { | 843 } else { |
| 844 ASSERT(object->IsSmi()); | 844 DCHECK(object->IsSmi()); |
| 845 Mov(result, Operand(object)); | 845 Mov(result, Operand(object)); |
| 846 } | 846 } |
| 847 } | 847 } |
| 848 | 848 |
| 849 static int SafepointRegisterStackIndex(int reg_code); | 849 static int SafepointRegisterStackIndex(int reg_code); |
| 850 | 850 |
| 851 // This is required for compatibility with architecture independant code. | 851 // This is required for compatibility with architecture independant code. |
| 852 // Remove if not needed. | 852 // Remove if not needed. |
| 853 inline void Move(Register dst, Register src) { Mov(dst, src); } | 853 inline void Move(Register dst, Register src) { Mov(dst, src); } |
| 854 | 854 |
| (...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 974 // Try to represent a double as a signed 32-bit int. | 974 // Try to represent a double as a signed 32-bit int. |
| 975 // This succeeds if the result compares equal to the input, so inputs of -0.0 | 975 // This succeeds if the result compares equal to the input, so inputs of -0.0 |
| 976 // are represented as 0 and handled as a success. | 976 // are represented as 0 and handled as a success. |
| 977 // | 977 // |
| 978 // On output the Z flag is set if the operation was successful. | 978 // On output the Z flag is set if the operation was successful. |
| 979 void TryRepresentDoubleAsInt32(Register as_int, | 979 void TryRepresentDoubleAsInt32(Register as_int, |
| 980 FPRegister value, | 980 FPRegister value, |
| 981 FPRegister scratch_d, | 981 FPRegister scratch_d, |
| 982 Label* on_successful_conversion = NULL, | 982 Label* on_successful_conversion = NULL, |
| 983 Label* on_failed_conversion = NULL) { | 983 Label* on_failed_conversion = NULL) { |
| 984 ASSERT(as_int.Is32Bits()); | 984 DCHECK(as_int.Is32Bits()); |
| 985 TryRepresentDoubleAsInt(as_int, value, scratch_d, on_successful_conversion, | 985 TryRepresentDoubleAsInt(as_int, value, scratch_d, on_successful_conversion, |
| 986 on_failed_conversion); | 986 on_failed_conversion); |
| 987 } | 987 } |
| 988 | 988 |
| 989 // Try to represent a double as a signed 64-bit int. | 989 // Try to represent a double as a signed 64-bit int. |
| 990 // This succeeds if the result compares equal to the input, so inputs of -0.0 | 990 // This succeeds if the result compares equal to the input, so inputs of -0.0 |
| 991 // are represented as 0 and handled as a success. | 991 // are represented as 0 and handled as a success. |
| 992 // | 992 // |
| 993 // On output the Z flag is set if the operation was successful. | 993 // On output the Z flag is set if the operation was successful. |
| 994 void TryRepresentDoubleAsInt64(Register as_int, | 994 void TryRepresentDoubleAsInt64(Register as_int, |
| 995 FPRegister value, | 995 FPRegister value, |
| 996 FPRegister scratch_d, | 996 FPRegister scratch_d, |
| 997 Label* on_successful_conversion = NULL, | 997 Label* on_successful_conversion = NULL, |
| 998 Label* on_failed_conversion = NULL) { | 998 Label* on_failed_conversion = NULL) { |
| 999 ASSERT(as_int.Is64Bits()); | 999 DCHECK(as_int.Is64Bits()); |
| 1000 TryRepresentDoubleAsInt(as_int, value, scratch_d, on_successful_conversion, | 1000 TryRepresentDoubleAsInt(as_int, value, scratch_d, on_successful_conversion, |
| 1001 on_failed_conversion); | 1001 on_failed_conversion); |
| 1002 } | 1002 } |
| 1003 | 1003 |
| 1004 // ---- Object Utilities ---- | 1004 // ---- Object Utilities ---- |
| 1005 | 1005 |
| 1006 // Copy fields from 'src' to 'dst', where both are tagged objects. | 1006 // Copy fields from 'src' to 'dst', where both are tagged objects. |
| 1007 // The 'temps' list is a list of X registers which can be used for scratch | 1007 // The 'temps' list is a list of X registers which can be used for scratch |
| 1008 // values. The temps list must include at least one register. | 1008 // values. The temps list must include at least one register. |
| 1009 // | 1009 // |
| (...skipping 1187 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2197 } | 2197 } |
| 2198 previous_allow_macro_instructions_ = masm_->allow_macro_instructions(); | 2198 previous_allow_macro_instructions_ = masm_->allow_macro_instructions(); |
| 2199 masm_->set_allow_macro_instructions(false); | 2199 masm_->set_allow_macro_instructions(false); |
| 2200 #endif | 2200 #endif |
| 2201 } | 2201 } |
| 2202 | 2202 |
| 2203 ~InstructionAccurateScope() { | 2203 ~InstructionAccurateScope() { |
| 2204 masm_->EndBlockPools(); | 2204 masm_->EndBlockPools(); |
| 2205 #ifdef DEBUG | 2205 #ifdef DEBUG |
| 2206 if (start_.is_bound()) { | 2206 if (start_.is_bound()) { |
| 2207 ASSERT(masm_->SizeOfCodeGeneratedSince(&start_) == size_); | 2207 DCHECK(masm_->SizeOfCodeGeneratedSince(&start_) == size_); |
| 2208 } | 2208 } |
| 2209 masm_->set_allow_macro_instructions(previous_allow_macro_instructions_); | 2209 masm_->set_allow_macro_instructions(previous_allow_macro_instructions_); |
| 2210 #endif | 2210 #endif |
| 2211 } | 2211 } |
| 2212 | 2212 |
| 2213 private: | 2213 private: |
| 2214 MacroAssembler* masm_; | 2214 MacroAssembler* masm_; |
| 2215 #ifdef DEBUG | 2215 #ifdef DEBUG |
| 2216 size_t size_; | 2216 size_t size_; |
| 2217 Label start_; | 2217 Label start_; |
| 2218 bool previous_allow_macro_instructions_; | 2218 bool previous_allow_macro_instructions_; |
| 2219 #endif | 2219 #endif |
| 2220 }; | 2220 }; |
| 2221 | 2221 |
| 2222 | 2222 |
| 2223 // This scope utility allows scratch registers to be managed safely. The | 2223 // This scope utility allows scratch registers to be managed safely. The |
| 2224 // MacroAssembler's TmpList() (and FPTmpList()) is used as a pool of scratch | 2224 // MacroAssembler's TmpList() (and FPTmpList()) is used as a pool of scratch |
| 2225 // registers. These registers can be allocated on demand, and will be returned | 2225 // registers. These registers can be allocated on demand, and will be returned |
| 2226 // at the end of the scope. | 2226 // at the end of the scope. |
| 2227 // | 2227 // |
| 2228 // When the scope ends, the MacroAssembler's lists will be restored to their | 2228 // When the scope ends, the MacroAssembler's lists will be restored to their |
| 2229 // original state, even if the lists were modified by some other means. | 2229 // original state, even if the lists were modified by some other means. |
| 2230 class UseScratchRegisterScope { | 2230 class UseScratchRegisterScope { |
| 2231 public: | 2231 public: |
| 2232 explicit UseScratchRegisterScope(MacroAssembler* masm) | 2232 explicit UseScratchRegisterScope(MacroAssembler* masm) |
| 2233 : available_(masm->TmpList()), | 2233 : available_(masm->TmpList()), |
| 2234 availablefp_(masm->FPTmpList()), | 2234 availablefp_(masm->FPTmpList()), |
| 2235 old_available_(available_->list()), | 2235 old_available_(available_->list()), |
| 2236 old_availablefp_(availablefp_->list()) { | 2236 old_availablefp_(availablefp_->list()) { |
| 2237 ASSERT(available_->type() == CPURegister::kRegister); | 2237 DCHECK(available_->type() == CPURegister::kRegister); |
| 2238 ASSERT(availablefp_->type() == CPURegister::kFPRegister); | 2238 DCHECK(availablefp_->type() == CPURegister::kFPRegister); |
| 2239 } | 2239 } |
| 2240 | 2240 |
| 2241 ~UseScratchRegisterScope(); | 2241 ~UseScratchRegisterScope(); |
| 2242 | 2242 |
| 2243 // Take a register from the appropriate temps list. It will be returned | 2243 // Take a register from the appropriate temps list. It will be returned |
| 2244 // automatically when the scope ends. | 2244 // automatically when the scope ends. |
| 2245 Register AcquireW() { return AcquireNextAvailable(available_).W(); } | 2245 Register AcquireW() { return AcquireNextAvailable(available_).W(); } |
| 2246 Register AcquireX() { return AcquireNextAvailable(available_).X(); } | 2246 Register AcquireX() { return AcquireNextAvailable(available_).X(); } |
| 2247 FPRegister AcquireS() { return AcquireNextAvailable(availablefp_).S(); } | 2247 FPRegister AcquireS() { return AcquireNextAvailable(availablefp_).S(); } |
| 2248 FPRegister AcquireD() { return AcquireNextAvailable(availablefp_).D(); } | 2248 FPRegister AcquireD() { return AcquireNextAvailable(availablefp_).D(); } |
| (...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2332 #error "Unsupported option" | 2332 #error "Unsupported option" |
| 2333 #define CODE_COVERAGE_STRINGIFY(x) #x | 2333 #define CODE_COVERAGE_STRINGIFY(x) #x |
| 2334 #define CODE_COVERAGE_TOSTRING(x) CODE_COVERAGE_STRINGIFY(x) | 2334 #define CODE_COVERAGE_TOSTRING(x) CODE_COVERAGE_STRINGIFY(x) |
| 2335 #define __FILE_LINE__ __FILE__ ":" CODE_COVERAGE_TOSTRING(__LINE__) | 2335 #define __FILE_LINE__ __FILE__ ":" CODE_COVERAGE_TOSTRING(__LINE__) |
| 2336 #define ACCESS_MASM(masm) masm->stop(__FILE_LINE__); masm-> | 2336 #define ACCESS_MASM(masm) masm->stop(__FILE_LINE__); masm-> |
| 2337 #else | 2337 #else |
| 2338 #define ACCESS_MASM(masm) masm-> | 2338 #define ACCESS_MASM(masm) masm-> |
| 2339 #endif | 2339 #endif |
| 2340 | 2340 |
| 2341 #endif // V8_ARM64_MACRO_ASSEMBLER_ARM64_H_ | 2341 #endif // V8_ARM64_MACRO_ASSEMBLER_ARM64_H_ |
| OLD | NEW |