diff options
Diffstat (limited to 'disas/libvixl/a64')
-rw-r--r-- | disas/libvixl/a64/assembler-a64.h | 290 | ||||
-rw-r--r-- | disas/libvixl/a64/constants-a64.h | 61 | ||||
-rw-r--r-- | disas/libvixl/a64/decoder-a64.h | 2 | ||||
-rw-r--r-- | disas/libvixl/a64/disasm-a64.cc | 142 | ||||
-rw-r--r-- | disas/libvixl/a64/disasm-a64.h | 48 | ||||
-rw-r--r-- | disas/libvixl/a64/instructions-a64.cc | 63 | ||||
-rw-r--r-- | disas/libvixl/a64/instructions-a64.h | 110 |
7 files changed, 514 insertions, 202 deletions
diff --git a/disas/libvixl/a64/assembler-a64.h b/disas/libvixl/a64/assembler-a64.h index 16a704b7d4..35aaf20f72 100644 --- a/disas/libvixl/a64/assembler-a64.h +++ b/disas/libvixl/a64/assembler-a64.h @@ -151,21 +151,21 @@ class CPURegister { return Aliases(other) && (size_ == other.size_); } - inline bool IsZero() const { + bool IsZero() const { VIXL_ASSERT(IsValid()); return IsRegister() && (code_ == kZeroRegCode); } - inline bool IsSP() const { + bool IsSP() const { VIXL_ASSERT(IsValid()); return IsRegister() && (code_ == kSPRegInternalCode); } - inline bool IsRegister() const { + bool IsRegister() const { return type_ == kRegister; } - inline bool IsFPRegister() const { + bool IsFPRegister() const { return type_ == kFPRegister; } @@ -179,7 +179,7 @@ class CPURegister { const FPRegister& S() const; const FPRegister& D() const; - inline bool IsSameSizeAndType(const CPURegister& other) const { + bool IsSameSizeAndType(const CPURegister& other) const { return (size_ == other.size_) && (type_ == other.type_); } @@ -198,7 +198,7 @@ class CPURegister { class Register : public CPURegister { public: Register() : CPURegister() {} - inline explicit Register(const CPURegister& other) + explicit Register(const CPURegister& other) : CPURegister(other.code(), other.size(), other.type()) { VIXL_ASSERT(IsValidRegister()); } @@ -213,10 +213,6 @@ class Register : public CPURegister { static const Register& WRegFromCode(unsigned code); static const Register& XRegFromCode(unsigned code); - // V8 compatibility. - static const int kNumRegisters = kNumberOfRegisters; - static const int kNumAllocatableRegisters = kNumberOfRegisters - 1; - private: static const Register wregisters[]; static const Register xregisters[]; @@ -225,12 +221,12 @@ class Register : public CPURegister { class FPRegister : public CPURegister { public: - inline FPRegister() : CPURegister() {} - inline explicit FPRegister(const CPURegister& other) + FPRegister() : CPURegister() {} + explicit FPRegister(const CPURegister& other) : CPURegister(other.code(), other.size(), other.type()) { VIXL_ASSERT(IsValidFPRegister()); } - inline FPRegister(unsigned code, unsigned size) + FPRegister(unsigned code, unsigned size) : CPURegister(code, size, kFPRegister) {} bool IsValid() const { @@ -241,10 +237,6 @@ class FPRegister : public CPURegister { static const FPRegister& SRegFromCode(unsigned code); static const FPRegister& DRegFromCode(unsigned code); - // V8 compatibility. - static const int kNumRegisters = kNumberOfFPRegisters; - static const int kNumAllocatableRegisters = kNumberOfFPRegisters - 1; - private: static const FPRegister sregisters[]; static const FPRegister dregisters[]; @@ -312,23 +304,23 @@ bool AreSameSizeAndType(const CPURegister& reg1, // Lists of registers. class CPURegList { public: - inline explicit CPURegList(CPURegister reg1, - CPURegister reg2 = NoCPUReg, - CPURegister reg3 = NoCPUReg, - CPURegister reg4 = NoCPUReg) + explicit CPURegList(CPURegister reg1, + CPURegister reg2 = NoCPUReg, + CPURegister reg3 = NoCPUReg, + CPURegister reg4 = NoCPUReg) : list_(reg1.Bit() | reg2.Bit() | reg3.Bit() | reg4.Bit()), size_(reg1.size()), type_(reg1.type()) { VIXL_ASSERT(AreSameSizeAndType(reg1, reg2, reg3, reg4)); VIXL_ASSERT(IsValid()); } - inline CPURegList(CPURegister::RegisterType type, unsigned size, RegList list) + CPURegList(CPURegister::RegisterType type, unsigned size, RegList list) : list_(list), size_(size), type_(type) { VIXL_ASSERT(IsValid()); } - inline CPURegList(CPURegister::RegisterType type, unsigned size, - unsigned first_reg, unsigned last_reg) + CPURegList(CPURegister::RegisterType type, unsigned size, + unsigned first_reg, unsigned last_reg) : size_(size), type_(type) { VIXL_ASSERT(((type == CPURegister::kRegister) && (last_reg < kNumberOfRegisters)) || @@ -340,7 +332,7 @@ class CPURegList { VIXL_ASSERT(IsValid()); } - inline CPURegister::RegisterType type() const { + CPURegister::RegisterType type() const { VIXL_ASSERT(IsValid()); return type_; } @@ -366,13 +358,13 @@ class CPURegList { } // Variants of Combine and Remove which take a single register. - inline void Combine(const CPURegister& other) { + void Combine(const CPURegister& other) { VIXL_ASSERT(other.type() == type_); VIXL_ASSERT(other.size() == size_); Combine(other.code()); } - inline void Remove(const CPURegister& other) { + void Remove(const CPURegister& other) { VIXL_ASSERT(other.type() == type_); VIXL_ASSERT(other.size() == size_); Remove(other.code()); @@ -380,24 +372,51 @@ class CPURegList { // Variants of Combine and Remove which take a single register by its code; // the type and size of the register is inferred from this list. - inline void Combine(int code) { + void Combine(int code) { VIXL_ASSERT(IsValid()); VIXL_ASSERT(CPURegister(code, size_, type_).IsValid()); list_ |= (UINT64_C(1) << code); } - inline void Remove(int code) { + void Remove(int code) { VIXL_ASSERT(IsValid()); VIXL_ASSERT(CPURegister(code, size_, type_).IsValid()); list_ &= ~(UINT64_C(1) << code); } - inline RegList list() const { + static CPURegList Union(const CPURegList& list_1, const CPURegList& list_2) { + VIXL_ASSERT(list_1.type_ == list_2.type_); + VIXL_ASSERT(list_1.size_ == list_2.size_); + return CPURegList(list_1.type_, list_1.size_, list_1.list_ | list_2.list_); + } + static CPURegList Union(const CPURegList& list_1, + const CPURegList& list_2, + const CPURegList& list_3); + static CPURegList Union(const CPURegList& list_1, + const CPURegList& list_2, + const CPURegList& list_3, + const CPURegList& list_4); + + static CPURegList Intersection(const CPURegList& list_1, + const CPURegList& list_2) { + VIXL_ASSERT(list_1.type_ == list_2.type_); + VIXL_ASSERT(list_1.size_ == list_2.size_); + return CPURegList(list_1.type_, list_1.size_, list_1.list_ & list_2.list_); + } + static CPURegList Intersection(const CPURegList& list_1, + const CPURegList& list_2, + const CPURegList& list_3); + static CPURegList Intersection(const CPURegList& list_1, + const CPURegList& list_2, + const CPURegList& list_3, + const CPURegList& list_4); + + RegList list() const { VIXL_ASSERT(IsValid()); return list_; } - inline void set_list(RegList new_list) { + void set_list(RegList new_list) { VIXL_ASSERT(IsValid()); list_ = new_list; } @@ -417,38 +436,38 @@ class CPURegList { static CPURegList GetCallerSaved(unsigned size = kXRegSize); static CPURegList GetCallerSavedFP(unsigned size = kDRegSize); - inline bool IsEmpty() const { + bool IsEmpty() const { VIXL_ASSERT(IsValid()); return list_ == 0; } - inline bool IncludesAliasOf(const CPURegister& other) const { + bool IncludesAliasOf(const CPURegister& other) const { VIXL_ASSERT(IsValid()); return (type_ == other.type()) && ((other.Bit() & list_) != 0); } - inline bool IncludesAliasOf(int code) const { + bool IncludesAliasOf(int code) const { VIXL_ASSERT(IsValid()); return ((code & list_) != 0); } - inline int Count() const { + int Count() const { VIXL_ASSERT(IsValid()); return CountSetBits(list_, kRegListSizeInBits); } - inline unsigned RegisterSizeInBits() const { + unsigned RegisterSizeInBits() const { VIXL_ASSERT(IsValid()); return size_; } - inline unsigned RegisterSizeInBytes() const { + unsigned RegisterSizeInBytes() const { int size_in_bits = RegisterSizeInBits(); VIXL_ASSERT((size_in_bits % 8) == 0); return size_in_bits / 8; } - inline unsigned TotalSizeInBytes() const { + unsigned TotalSizeInBytes() const { VIXL_ASSERT(IsValid()); return RegisterSizeInBytes() * Count(); } @@ -587,8 +606,10 @@ class Label { VIXL_ASSERT(!IsLinked() || IsBound()); } - inline bool IsBound() const { return location_ >= 0; } - inline bool IsLinked() const { return !links_.empty(); } + bool IsBound() const { return location_ >= 0; } + bool IsLinked() const { return !links_.empty(); } + + ptrdiff_t location() const { return location_; } private: // The list of linked instructions is stored in a stack-like structure. We @@ -647,22 +668,20 @@ class Label { std::stack<ptrdiff_t> * links_extended_; }; - inline ptrdiff_t location() const { return location_; } - - inline void Bind(ptrdiff_t location) { + void Bind(ptrdiff_t location) { // Labels can only be bound once. VIXL_ASSERT(!IsBound()); location_ = location; } - inline void AddLink(ptrdiff_t instruction) { + void AddLink(ptrdiff_t instruction) { // If a label is bound, the assembler already has the information it needs // to write the instruction, so there is no need to add it to links_. VIXL_ASSERT(!IsBound()); links_.push(instruction); } - inline ptrdiff_t GetAndRemoveNextLink() { + ptrdiff_t GetAndRemoveNextLink() { VIXL_ASSERT(IsLinked()); ptrdiff_t link = links_.top(); links_.pop(); @@ -845,14 +864,14 @@ class Assembler { // Return the address of an offset in the buffer. template <typename T> - inline T GetOffsetAddress(ptrdiff_t offset) { + T GetOffsetAddress(ptrdiff_t offset) { VIXL_STATIC_ASSERT(sizeof(T) >= sizeof(uintptr_t)); return buffer_->GetOffsetAddress<T>(offset); } // Return the address of a bound label. template <typename T> - inline T GetLabelAddress(const Label * label) { + T GetLabelAddress(const Label * label) { VIXL_ASSERT(label->IsBound()); VIXL_STATIC_ASSERT(sizeof(T) >= sizeof(uintptr_t)); return GetOffsetAddress<T>(label->location()); @@ -860,14 +879,14 @@ class Assembler { // Return the address of the cursor. template <typename T> - inline T GetCursorAddress() { + T GetCursorAddress() { VIXL_STATIC_ASSERT(sizeof(T) >= sizeof(uintptr_t)); return GetOffsetAddress<T>(CursorOffset()); } // Return the address of the start of the buffer. template <typename T> - inline T GetStartAddress() { + T GetStartAddress() { VIXL_STATIC_ASSERT(sizeof(T) >= sizeof(uintptr_t)); return GetOffsetAddress<T>(0); } @@ -1074,20 +1093,20 @@ class Assembler { // Bfm aliases. // Bitfield insert. - inline void bfi(const Register& rd, - const Register& rn, - unsigned lsb, - unsigned width) { + void bfi(const Register& rd, + const Register& rn, + unsigned lsb, + unsigned width) { VIXL_ASSERT(width >= 1); VIXL_ASSERT(lsb + width <= rn.size()); bfm(rd, rn, (rd.size() - lsb) & (rd.size() - 1), width - 1); } // Bitfield extract and insert low. - inline void bfxil(const Register& rd, - const Register& rn, - unsigned lsb, - unsigned width) { + void bfxil(const Register& rd, + const Register& rn, + unsigned lsb, + unsigned width) { VIXL_ASSERT(width >= 1); VIXL_ASSERT(lsb + width <= rn.size()); bfm(rd, rn, lsb, lsb + width - 1); @@ -1095,92 +1114,92 @@ class Assembler { // Sbfm aliases. // Arithmetic shift right. - inline void asr(const Register& rd, const Register& rn, unsigned shift) { + void asr(const Register& rd, const Register& rn, unsigned shift) { VIXL_ASSERT(shift < rd.size()); sbfm(rd, rn, shift, rd.size() - 1); } // Signed bitfield insert with zero at right. - inline void sbfiz(const Register& rd, - const Register& rn, - unsigned lsb, - unsigned width) { + void sbfiz(const Register& rd, + const Register& rn, + unsigned lsb, + unsigned width) { VIXL_ASSERT(width >= 1); VIXL_ASSERT(lsb + width <= rn.size()); sbfm(rd, rn, (rd.size() - lsb) & (rd.size() - 1), width - 1); } // Signed bitfield extract. - inline void sbfx(const Register& rd, - const Register& rn, - unsigned lsb, - unsigned width) { + void sbfx(const Register& rd, + const Register& rn, + unsigned lsb, + unsigned width) { VIXL_ASSERT(width >= 1); VIXL_ASSERT(lsb + width <= rn.size()); sbfm(rd, rn, lsb, lsb + width - 1); } // Signed extend byte. - inline void sxtb(const Register& rd, const Register& rn) { + void sxtb(const Register& rd, const Register& rn) { sbfm(rd, rn, 0, 7); } // Signed extend halfword. - inline void sxth(const Register& rd, const Register& rn) { + void sxth(const Register& rd, const Register& rn) { sbfm(rd, rn, 0, 15); } // Signed extend word. - inline void sxtw(const Register& rd, const Register& rn) { + void sxtw(const Register& rd, const Register& rn) { sbfm(rd, rn, 0, 31); } // Ubfm aliases. // Logical shift left. - inline void lsl(const Register& rd, const Register& rn, unsigned shift) { + void lsl(const Register& rd, const Register& rn, unsigned shift) { unsigned reg_size = rd.size(); VIXL_ASSERT(shift < reg_size); ubfm(rd, rn, (reg_size - shift) % reg_size, reg_size - shift - 1); } // Logical shift right. - inline void lsr(const Register& rd, const Register& rn, unsigned shift) { + void lsr(const Register& rd, const Register& rn, unsigned shift) { VIXL_ASSERT(shift < rd.size()); ubfm(rd, rn, shift, rd.size() - 1); } // Unsigned bitfield insert with zero at right. - inline void ubfiz(const Register& rd, - const Register& rn, - unsigned lsb, - unsigned width) { + void ubfiz(const Register& rd, + const Register& rn, + unsigned lsb, + unsigned width) { VIXL_ASSERT(width >= 1); VIXL_ASSERT(lsb + width <= rn.size()); ubfm(rd, rn, (rd.size() - lsb) & (rd.size() - 1), width - 1); } // Unsigned bitfield extract. - inline void ubfx(const Register& rd, - const Register& rn, - unsigned lsb, - unsigned width) { + void ubfx(const Register& rd, + const Register& rn, + unsigned lsb, + unsigned width) { VIXL_ASSERT(width >= 1); VIXL_ASSERT(lsb + width <= rn.size()); ubfm(rd, rn, lsb, lsb + width - 1); } // Unsigned extend byte. - inline void uxtb(const Register& rd, const Register& rn) { + void uxtb(const Register& rd, const Register& rn) { ubfm(rd, rn, 0, 7); } // Unsigned extend halfword. - inline void uxth(const Register& rd, const Register& rn) { + void uxth(const Register& rd, const Register& rn) { ubfm(rd, rn, 0, 15); } // Unsigned extend word. - inline void uxtw(const Register& rd, const Register& rn) { + void uxtw(const Register& rd, const Register& rn) { ubfm(rd, rn, 0, 31); } @@ -1230,7 +1249,7 @@ class Assembler { void cneg(const Register& rd, const Register& rn, Condition cond); // Rotate right. - inline void ror(const Register& rd, const Register& rs, unsigned shift) { + void ror(const Register& rd, const Register& rs, unsigned shift) { extr(rd, rs, rs, shift); } @@ -1495,6 +1514,19 @@ class Assembler { // Load-acquire register. void ldar(const Register& rt, const MemOperand& src); + // Prefetch memory. + void prfm(PrefetchOperation op, const MemOperand& addr, + LoadStoreScalingOption option = PreferScaledOffset); + + // Prefetch memory (with unscaled offset). + void prfum(PrefetchOperation op, const MemOperand& addr, + LoadStoreScalingOption option = PreferUnscaledOffset); + + // Prefetch memory in the literal pool. + void prfm(PrefetchOperation op, RawLiteral* literal); + + // Prefetch from pc + imm19 << 2. + void prfm(PrefetchOperation op, int imm19); // Move instructions. The default shift of -1 indicates that the move // instruction will calculate an appropriate 16-bit immediate and left shift @@ -1638,12 +1670,21 @@ class Assembler { // FP round to integer (nearest with ties to away). void frinta(const FPRegister& fd, const FPRegister& fn); + // FP round to integer (implicit rounding). + void frinti(const FPRegister& fd, const FPRegister& fn); + // FP round to integer (toward minus infinity). void frintm(const FPRegister& fd, const FPRegister& fn); // FP round to integer (nearest with ties to even). void frintn(const FPRegister& fd, const FPRegister& fn); + // FP round to integer (toward plus infinity). + void frintp(const FPRegister& fd, const FPRegister& fn); + + // FP round to integer (exact, implicit rounding). + void frintx(const FPRegister& fd, const FPRegister& fn); + // FP round to integer (towards zero). void frintz(const FPRegister& fd, const FPRegister& fn); @@ -1705,16 +1746,16 @@ class Assembler { // Emit generic instructions. // Emit raw instructions into the instruction stream. - inline void dci(Instr raw_inst) { Emit(raw_inst); } + void dci(Instr raw_inst) { Emit(raw_inst); } // Emit 32 bits of data into the instruction stream. - inline void dc32(uint32_t data) { + void dc32(uint32_t data) { VIXL_ASSERT(buffer_monitor_ > 0); buffer_->Emit32(data); } // Emit 64 bits of data into the instruction stream. - inline void dc64(uint64_t data) { + void dc64(uint64_t data) { VIXL_ASSERT(buffer_monitor_ > 0); buffer_->Emit64(data); } @@ -1849,14 +1890,14 @@ class Assembler { } } - static inline Instr ImmS(unsigned imms, unsigned reg_size) { + static Instr ImmS(unsigned imms, unsigned reg_size) { VIXL_ASSERT(((reg_size == kXRegSize) && is_uint6(imms)) || ((reg_size == kWRegSize) && is_uint5(imms))); USE(reg_size); return imms << ImmS_offset; } - static inline Instr ImmR(unsigned immr, unsigned reg_size) { + static Instr ImmR(unsigned immr, unsigned reg_size) { VIXL_ASSERT(((reg_size == kXRegSize) && is_uint6(immr)) || ((reg_size == kWRegSize) && is_uint5(immr))); USE(reg_size); @@ -1864,7 +1905,7 @@ class Assembler { return immr << ImmR_offset; } - static inline Instr ImmSetBits(unsigned imms, unsigned reg_size) { + static Instr ImmSetBits(unsigned imms, unsigned reg_size) { VIXL_ASSERT((reg_size == kWRegSize) || (reg_size == kXRegSize)); VIXL_ASSERT(is_uint6(imms)); VIXL_ASSERT((reg_size == kXRegSize) || is_uint6(imms + 3)); @@ -1872,7 +1913,7 @@ class Assembler { return imms << ImmSetBits_offset; } - static inline Instr ImmRotate(unsigned immr, unsigned reg_size) { + static Instr ImmRotate(unsigned immr, unsigned reg_size) { VIXL_ASSERT((reg_size == kWRegSize) || (reg_size == kXRegSize)); VIXL_ASSERT(((reg_size == kXRegSize) && is_uint6(immr)) || ((reg_size == kWRegSize) && is_uint5(immr))); @@ -1880,12 +1921,12 @@ class Assembler { return immr << ImmRotate_offset; } - static inline Instr ImmLLiteral(int imm19) { + static Instr ImmLLiteral(int imm19) { VIXL_ASSERT(is_int19(imm19)); return truncate_to_int19(imm19) << ImmLLiteral_offset; } - static inline Instr BitN(unsigned bitn, unsigned reg_size) { + static Instr BitN(unsigned bitn, unsigned reg_size) { VIXL_ASSERT((reg_size == kWRegSize) || (reg_size == kXRegSize)); VIXL_ASSERT((reg_size == kXRegSize) || (bitn == 0)); USE(reg_size); @@ -1943,6 +1984,11 @@ class Assembler { return shift_amount << ImmShiftLS_offset; } + static Instr ImmPrefetchOperation(int imm5) { + VIXL_ASSERT(is_uint5(imm5)); + return imm5 << ImmPrefetchOperation_offset; + } + static Instr ImmException(int imm16) { VIXL_ASSERT(is_uint16(imm16)); return imm16 << ImmException_offset; @@ -2003,12 +2049,32 @@ class Assembler { return scale << FPScale_offset; } + // Immediate field checking helpers. + static bool IsImmAddSub(int64_t immediate); + static bool IsImmConditionalCompare(int64_t immediate); + static bool IsImmFP32(float imm); + static bool IsImmFP64(double imm); + static bool IsImmLogical(uint64_t value, + unsigned width, + unsigned* n = NULL, + unsigned* imm_s = NULL, + unsigned* imm_r = NULL); + static bool IsImmLSPair(int64_t offset, LSDataSize size); + static bool IsImmLSScaled(int64_t offset, LSDataSize size); + static bool IsImmLSUnscaled(int64_t offset); + static bool IsImmMovn(uint64_t imm, unsigned reg_size); + static bool IsImmMovz(uint64_t imm, unsigned reg_size); + // Size of the code generated since label to the current position. size_t SizeOfCodeGeneratedSince(Label* label) const { VIXL_ASSERT(label->IsBound()); return buffer_->OffsetFrom(label->location()); } + size_t SizeOfCodeGenerated() const { + return buffer_->CursorOffset(); + } + size_t BufferCapacity() const { return buffer_->capacity(); } size_t RemainingBufferSpace() const { return buffer_->RemainingBytes(); } @@ -2025,7 +2091,7 @@ class Assembler { } } -#ifdef DEBUG +#ifdef VIXL_DEBUG void AcquireBuffer() { VIXL_ASSERT(buffer_monitor_ >= 0); buffer_monitor_++; @@ -2037,16 +2103,16 @@ class Assembler { } #endif - inline PositionIndependentCodeOption pic() { + PositionIndependentCodeOption pic() const { return pic_; } - inline bool AllowPageOffsetDependentCode() { + bool AllowPageOffsetDependentCode() const { return (pic() == PageOffsetDependentCode) || (pic() == PositionDependentCode); } - static inline const Register& AppropriateZeroRegFor(const CPURegister& reg) { + static const Register& AppropriateZeroRegFor(const CPURegister& reg) { return reg.Is64Bits() ? xzr : wzr; } @@ -2056,14 +2122,15 @@ class Assembler { const MemOperand& addr, LoadStoreOp op, LoadStoreScalingOption option = PreferScaledOffset); - static bool IsImmLSUnscaled(int64_t offset); - static bool IsImmLSScaled(int64_t offset, LSDataSize size); void LoadStorePair(const CPURegister& rt, const CPURegister& rt2, const MemOperand& addr, LoadStorePairOp op); - static bool IsImmLSPair(int64_t offset, LSDataSize size); + + void Prefetch(PrefetchOperation op, + const MemOperand& addr, + LoadStoreScalingOption option = PreferScaledOffset); // TODO(all): The third parameter should be passed by reference but gcc 4.8.2 // reports a bogus uninitialised warning then. @@ -2077,18 +2144,12 @@ class Assembler { unsigned imm_s, unsigned imm_r, LogicalOp op); - static bool IsImmLogical(uint64_t value, - unsigned width, - unsigned* n = NULL, - unsigned* imm_s = NULL, - unsigned* imm_r = NULL); void ConditionalCompare(const Register& rn, const Operand& operand, StatusFlags nzcv, Condition cond, ConditionalCompareOp op); - static bool IsImmConditionalCompare(int64_t immediate); void AddSubWithCarry(const Register& rd, const Register& rn, @@ -2096,8 +2157,6 @@ class Assembler { FlagsUpdate S, AddSubWithCarryOp op); - static bool IsImmFP32(float imm); - static bool IsImmFP64(double imm); // Functions for emulating operands not directly supported by the instruction // set. @@ -2115,7 +2174,6 @@ class Assembler { const Operand& operand, FlagsUpdate S, AddSubOp op); - static bool IsImmAddSub(int64_t immediate); // Find an appropriate LoadStoreOp or LoadStorePairOp for the specified // registers. Only simple loads are supported; sign- and zero-extension (such @@ -2180,6 +2238,12 @@ class Assembler { const FPRegister& fa, FPDataProcessing3SourceOp op); + // Encode the specified MemOperand for the specified access size and scaling + // preference. + Instr LoadStoreMemOperand(const MemOperand& addr, + LSDataSize size, + LoadStoreScalingOption option); + // Link the current (not-yet-emitted) instruction to the specified label, then // return an offset to be encoded in the instruction. If the label is not yet // bound, an offset of 0 is returned. @@ -2205,7 +2269,7 @@ class Assembler { CodeBuffer* buffer_; PositionIndependentCodeOption pic_; -#ifdef DEBUG +#ifdef VIXL_DEBUG int64_t buffer_monitor_; #endif }; @@ -2239,7 +2303,7 @@ class CodeBufferCheckScope { AssertPolicy assert_policy = kMaximumSize) : assm_(assm) { if (check_policy == kCheck) assm->EnsureSpaceFor(size); -#ifdef DEBUG +#ifdef VIXL_DEBUG assm->bind(&start_); size_ = size; assert_policy_ = assert_policy; @@ -2251,7 +2315,7 @@ class CodeBufferCheckScope { // This is a shortcut for CodeBufferCheckScope(assm, 0, kNoCheck, kNoAssert). explicit CodeBufferCheckScope(Assembler* assm) : assm_(assm) { -#ifdef DEBUG +#ifdef VIXL_DEBUG size_ = 0; assert_policy_ = kNoAssert; assm->AcquireBuffer(); @@ -2259,7 +2323,7 @@ class CodeBufferCheckScope { } ~CodeBufferCheckScope() { -#ifdef DEBUG +#ifdef VIXL_DEBUG assm_->ReleaseBuffer(); switch (assert_policy_) { case kNoAssert: break; @@ -2277,7 +2341,7 @@ class CodeBufferCheckScope { protected: Assembler* assm_; -#ifdef DEBUG +#ifdef VIXL_DEBUG Label start_; size_t size_; AssertPolicy assert_policy_; diff --git a/disas/libvixl/a64/constants-a64.h b/disas/libvixl/a64/constants-a64.h index 7a14f85f59..bc1a2c4b9b 100644 --- a/disas/libvixl/a64/constants-a64.h +++ b/disas/libvixl/a64/constants-a64.h @@ -31,12 +31,6 @@ namespace vixl { const unsigned kNumberOfRegisters = 32; const unsigned kNumberOfFPRegisters = 32; -// Callee saved registers are x21-x30(lr). -const int kNumberOfCalleeSavedRegisters = 10; -const int kFirstCalleeSavedRegisterIndex = 21; -// Callee saved FP registers are d8-d15. -const int kNumberOfCalleeSavedFPRegisters = 8; -const int kFirstCalleeSavedFPRegisterIndex = 8; #define REGISTER_CODE_LIST(R) \ R(0) R(1) R(2) R(3) R(4) R(5) R(6) R(7) \ @@ -53,7 +47,6 @@ V_(Ra, 14, 10, Bits) /* Third source register. */ \ V_(Rt, 4, 0, Bits) /* Load/store register. */ \ V_(Rt2, 14, 10, Bits) /* Load/store second register. */ \ V_(Rs, 20, 16, Bits) /* Exclusive access status. */ \ -V_(PrefetchMode, 4, 0, Bits) \ \ /* Common bits */ \ V_(SixtyFourBits, 31, 31, Bits) \ @@ -109,6 +102,10 @@ V_(ImmLSUnsigned, 21, 10, Bits) \ V_(ImmLSPair, 21, 15, SignedBits) \ V_(SizeLS, 31, 30, Bits) \ V_(ImmShiftLS, 12, 12, Bits) \ +V_(ImmPrefetchOperation, 4, 0, Bits) \ +V_(PrefetchHint, 4, 3, Bits) \ +V_(PrefetchTarget, 2, 1, Bits) \ +V_(PrefetchStream, 0, 0, Bits) \ \ /* Other immediates */ \ V_(ImmUncondBranch, 25, 0, SignedBits) \ @@ -269,6 +266,29 @@ enum BarrierType { BarrierAll = 3 }; +enum PrefetchOperation { + PLDL1KEEP = 0x00, + PLDL1STRM = 0x01, + PLDL2KEEP = 0x02, + PLDL2STRM = 0x03, + PLDL3KEEP = 0x04, + PLDL3STRM = 0x05, + + PLIL1KEEP = 0x08, + PLIL1STRM = 0x09, + PLIL2KEEP = 0x0a, + PLIL2STRM = 0x0b, + PLIL3KEEP = 0x0c, + PLIL3STRM = 0x0d, + + PSTL1KEEP = 0x10, + PSTL1STRM = 0x11, + PSTL2KEEP = 0x12, + PSTL2STRM = 0x13, + PSTL3KEEP = 0x14, + PSTL3STRM = 0x15 +}; + // System/special register names. // This information is not encoded as one field but as the concatenation of // multiple fields (Op0<0>, Op1, Crn, Crm, Op2). @@ -605,6 +625,12 @@ enum LoadStoreAnyOp { LoadStoreAnyFixed = 0x08000000 }; +// Any load pair or store pair. +enum LoadStorePairAnyOp { + LoadStorePairAnyFMask = 0x3a000000, + LoadStorePairAnyFixed = 0x28000000 +}; + #define LOAD_STORE_PAIR_OP_LIST(V) \ V(STP, w, 0x00000000), \ V(LDP, w, 0x00400000), \ @@ -703,27 +729,28 @@ enum LoadLiteralOp { V(LD, R, d, 0xC4400000) +// Load/store (post, pre, offset and unsigned.) +enum LoadStoreOp { + LoadStoreOpMask = 0xC4C00000, + #define LOAD_STORE(A, B, C, D) \ + A##B##_##C = D + LOAD_STORE_OP_LIST(LOAD_STORE), + #undef LOAD_STORE + PRFM = 0xC0800000 +}; + // Load/store unscaled offset. enum LoadStoreUnscaledOffsetOp { LoadStoreUnscaledOffsetFixed = 0x38000000, LoadStoreUnscaledOffsetFMask = 0x3B200C00, LoadStoreUnscaledOffsetMask = 0xFFE00C00, + PRFUM = LoadStoreUnscaledOffsetFixed | PRFM, #define LOAD_STORE_UNSCALED(A, B, C, D) \ A##U##B##_##C = LoadStoreUnscaledOffsetFixed | D LOAD_STORE_OP_LIST(LOAD_STORE_UNSCALED) #undef LOAD_STORE_UNSCALED }; -// Load/store (post, pre, offset and unsigned.) -enum LoadStoreOp { - LoadStoreOpMask = 0xC4C00000, - #define LOAD_STORE(A, B, C, D) \ - A##B##_##C = D - LOAD_STORE_OP_LIST(LOAD_STORE), - #undef LOAD_STORE - PRFM = 0xC0800000 -}; - // Load/store post index. enum LoadStorePostIndex { LoadStorePostIndexFixed = 0x38000400, diff --git a/disas/libvixl/a64/decoder-a64.h b/disas/libvixl/a64/decoder-a64.h index 172594c89b..fd08d6c1f4 100644 --- a/disas/libvixl/a64/decoder-a64.h +++ b/disas/libvixl/a64/decoder-a64.h @@ -108,7 +108,7 @@ class DecoderVisitor { } private: - VisitorConstness constness_; + const VisitorConstness constness_; }; diff --git a/disas/libvixl/a64/disasm-a64.cc b/disas/libvixl/a64/disasm-a64.cc index e4a74aa57c..f7bc2468bb 100644 --- a/disas/libvixl/a64/disasm-a64.cc +++ b/disas/libvixl/a64/disasm-a64.cc @@ -34,6 +34,7 @@ Disassembler::Disassembler() { buffer_ = reinterpret_cast<char*>(malloc(buffer_size_)); buffer_pos_ = 0; own_buffer_ = true; + code_address_offset_ = 0; } @@ -42,6 +43,7 @@ Disassembler::Disassembler(char* text_buffer, int buffer_size) { buffer_ = text_buffer; buffer_pos_ = 0; own_buffer_ = false; + code_address_offset_ = 0; } @@ -739,9 +741,25 @@ void Disassembler::VisitMoveWideImmediate(const Instruction* instr) { // shift calculation. switch (instr->Mask(MoveWideImmediateMask)) { case MOVN_w: - case MOVN_x: mnemonic = "movn"; break; + case MOVN_x: + if ((instr->ImmMoveWide()) || (instr->ShiftMoveWide() == 0)) { + if ((instr->SixtyFourBits() == 0) && (instr->ImmMoveWide() == 0xffff)) { + mnemonic = "movn"; + } else { + mnemonic = "mov"; + form = "'Rd, 'IMoveNeg"; + } + } else { + mnemonic = "movn"; + } + break; case MOVZ_w: - case MOVZ_x: mnemonic = "movz"; break; + case MOVZ_x: + if ((instr->ImmMoveWide()) || (instr->ShiftMoveWide() == 0)) + mnemonic = "mov"; + else + mnemonic = "movz"; + break; case MOVK_w: case MOVK_x: mnemonic = "movk"; form = "'Rd, 'IMoveLSL"; break; default: VIXL_UNREACHABLE(); @@ -806,7 +824,7 @@ void Disassembler::VisitLoadStoreUnsignedOffset(const Instruction* instr) { case A##_unsigned: mnemonic = B; form = C ", ['Xns'ILU]"; break; LOAD_STORE_LIST(LS_UNSIGNEDOFFSET) #undef LS_UNSIGNEDOFFSET - case PRFM_unsigned: mnemonic = "prfm"; form = "'PrefOp, ['Xn'ILU]"; + case PRFM_unsigned: mnemonic = "prfm"; form = "'PrefOp, ['Xns'ILU]"; } Format(instr, mnemonic, form); } @@ -833,6 +851,7 @@ void Disassembler::VisitLoadStoreUnscaledOffset(const Instruction* instr) { const char *form_x = "'Xt, ['Xns'ILS]"; const char *form_s = "'St, ['Xns'ILS]"; const char *form_d = "'Dt, ['Xns'ILS]"; + const char *form_prefetch = "'PrefOp, ['Xns'ILS]"; switch (instr->Mask(LoadStoreUnscaledOffsetMask)) { case STURB_w: mnemonic = "sturb"; break; @@ -852,6 +871,7 @@ void Disassembler::VisitLoadStoreUnscaledOffset(const Instruction* instr) { case LDURSH_x: form = form_x; // Fall through. case LDURSH_w: mnemonic = "ldursh"; break; case LDURSW_x: mnemonic = "ldursw"; form = form_x; break; + case PRFUM: mnemonic = "prfum"; form = form_prefetch; break; default: form = "(LoadStoreUnscaledOffset)"; } Format(instr, mnemonic, form); @@ -872,6 +892,11 @@ void Disassembler::VisitLoadLiteral(const Instruction* instr) { form = "'Xt, 'ILLiteral 'LValue"; break; } + case PRFM_lit: { + mnemonic = "prfm"; + form = "'PrefOp, 'ILLiteral 'LValue"; + break; + } default: mnemonic = "unimplemented"; } Format(instr, mnemonic, form); @@ -1344,7 +1369,7 @@ void Disassembler::AppendPCRelativeOffsetToOutput(const Instruction* instr, void Disassembler::AppendAddressToOutput(const Instruction* instr, const void* addr) { USE(instr); - AppendToOutput("(addr %p)", addr); + AppendToOutput("(addr 0x%" PRIxPTR ")", reinterpret_cast<uintptr_t>(addr)); } @@ -1360,6 +1385,40 @@ void Disassembler::AppendDataAddressToOutput(const Instruction* instr, } +void Disassembler::AppendCodeRelativeAddressToOutput(const Instruction* instr, + const void* addr) { + USE(instr); + int64_t rel_addr = CodeRelativeAddress(addr); + if (rel_addr >= 0) { + AppendToOutput("(addr 0x%" PRIx64 ")", rel_addr); + } else { + AppendToOutput("(addr -0x%" PRIx64 ")", -rel_addr); + } +} + + +void Disassembler::AppendCodeRelativeCodeAddressToOutput( + const Instruction* instr, const void* addr) { + AppendCodeRelativeAddressToOutput(instr, addr); +} + + +void Disassembler::AppendCodeRelativeDataAddressToOutput( + const Instruction* instr, const void* addr) { + AppendCodeRelativeAddressToOutput(instr, addr); +} + + +void Disassembler::MapCodeAddress(int64_t base_address, + const Instruction* instr_address) { + set_code_address_offset( + base_address - reinterpret_cast<intptr_t>(instr_address)); +} +int64_t Disassembler::CodeRelativeAddress(const void* addr) { + return reinterpret_cast<intptr_t>(addr) + code_address_offset(); +} + + void Disassembler::Format(const Instruction* instr, const char* mnemonic, const char* format) { VIXL_ASSERT(mnemonic != NULL); @@ -1486,16 +1545,20 @@ int Disassembler::SubstituteImmediateField(const Instruction* instr, VIXL_ASSERT(format[0] == 'I'); switch (format[1]) { - case 'M': { // IMoveImm or IMoveLSL. - if (format[5] == 'I') { - uint64_t imm = instr->ImmMoveWide() << (16 * instr->ShiftMoveWide()); - AppendToOutput("#0x%" PRIx64, imm); - } else { - VIXL_ASSERT(format[5] == 'L'); + case 'M': { // IMoveImm, IMoveNeg or IMoveLSL. + if (format[5] == 'L') { AppendToOutput("#0x%" PRIx64, instr->ImmMoveWide()); if (instr->ShiftMoveWide() > 0) { AppendToOutput(", lsl #%" PRId64, 16 * instr->ShiftMoveWide()); } + } else { + VIXL_ASSERT((format[5] == 'I') || (format[5] == 'N')); + uint64_t imm = instr->ImmMoveWide() << (16 * instr->ShiftMoveWide()); + if (format[5] == 'N') + imm = ~imm; + if (!instr->SixtyFourBits()) + imm &= UINT64_C(0xffffffff); + AppendToOutput("#0x%" PRIx64, imm); } return 8; } @@ -1634,14 +1697,31 @@ int Disassembler::SubstituteLiteralField(const Instruction* instr, VIXL_ASSERT(strncmp(format, "LValue", 6) == 0); USE(format); + const void * address = instr->LiteralAddress<const void *>(); switch (instr->Mask(LoadLiteralMask)) { case LDR_w_lit: case LDR_x_lit: case LDRSW_x_lit: case LDR_s_lit: case LDR_d_lit: - AppendDataAddressToOutput(instr, instr->LiteralAddress()); + AppendCodeRelativeDataAddressToOutput(instr, address); break; + case PRFM_lit: { + // Use the prefetch hint to decide how to print the address. + switch (instr->PrefetchHint()) { + case 0x0: // PLD: prefetch for load. + case 0x2: // PST: prepare for store. + AppendCodeRelativeDataAddressToOutput(instr, address); + break; + case 0x1: // PLI: preload instructions. + AppendCodeRelativeCodeAddressToOutput(instr, address); + break; + case 0x3: // Unallocated hint. + AppendCodeRelativeAddressToOutput(instr, address); + break; + } + break; + } default: VIXL_UNREACHABLE(); } @@ -1701,17 +1781,22 @@ int Disassembler::SubstitutePCRelAddressField(const Instruction* instr, (strcmp(format, "AddrPCRelPage") == 0)); // Used by `adrp`. int64_t offset = instr->ImmPCRel(); - const Instruction * base = instr; + // Compute the target address based on the effective address (after applying + // code_address_offset). This is required for correct behaviour of adrp. + const Instruction* base = instr + code_address_offset(); if (format[9] == 'P') { offset *= kPageSize; base = AlignDown(base, kPageSize); } + // Strip code_address_offset before printing, so we can use the + // semantically-correct AppendCodeRelativeAddressToOutput. + const void* target = + reinterpret_cast<const void*>(base + offset - code_address_offset()); - const void* target = reinterpret_cast<const void*>(base + offset); AppendPCRelativeOffsetToOutput(instr, offset); AppendToOutput(" "); - AppendAddressToOutput(instr, target); + AppendCodeRelativeAddressToOutput(instr, target); return 13; } @@ -1738,7 +1823,7 @@ int Disassembler::SubstituteBranchTargetField(const Instruction* instr, AppendPCRelativeOffsetToOutput(instr, offset); AppendToOutput(" "); - AppendCodeAddressToOutput(instr, target_address); + AppendCodeRelativeCodeAddressToOutput(instr, target_address); return 8; } @@ -1805,13 +1890,26 @@ int Disassembler::SubstitutePrefetchField(const Instruction* instr, VIXL_ASSERT(format[0] == 'P'); USE(format); - int prefetch_mode = instr->PrefetchMode(); - - const char* ls = (prefetch_mode & 0x10) ? "st" : "ld"; - int level = (prefetch_mode >> 1) + 1; - const char* ks = (prefetch_mode & 1) ? "strm" : "keep"; - - AppendToOutput("p%sl%d%s", ls, level, ks); + static const char* hints[] = {"ld", "li", "st"}; + static const char* stream_options[] = {"keep", "strm"}; + + unsigned hint = instr->PrefetchHint(); + unsigned target = instr->PrefetchTarget() + 1; + unsigned stream = instr->PrefetchStream(); + + if ((hint >= (sizeof(hints) / sizeof(hints[0]))) || (target > 3)) { + // Unallocated prefetch operations. + int prefetch_mode = instr->ImmPrefetchOperation(); + AppendToOutput("#0b%c%c%c%c%c", + (prefetch_mode & (1 << 4)) ? '1' : '0', + (prefetch_mode & (1 << 3)) ? '1' : '0', + (prefetch_mode & (1 << 2)) ? '1' : '0', + (prefetch_mode & (1 << 1)) ? '1' : '0', + (prefetch_mode & (1 << 0)) ? '1' : '0'); + } else { + VIXL_ASSERT(stream < (sizeof(stream_options) / sizeof(stream_options[0]))); + AppendToOutput("p%sl%d%s", hints[hint], target, stream_options[stream]); + } return 6; } diff --git a/disas/libvixl/a64/disasm-a64.h b/disas/libvixl/a64/disasm-a64.h index db043375c5..ddfe98be19 100644 --- a/disas/libvixl/a64/disasm-a64.h +++ b/disas/libvixl/a64/disasm-a64.h @@ -43,7 +43,7 @@ class Disassembler: public DecoderVisitor { char* GetOutput(); // Declare all Visitor functions. - #define DECLARE(A) void Visit##A(const Instruction* instr); + #define DECLARE(A) virtual void Visit##A(const Instruction* instr); VISITOR_LIST(DECLARE) #undef DECLARE @@ -65,23 +65,45 @@ class Disassembler: public DecoderVisitor { // Prints an address, in the general case. It can be code or data. This is // used for example to print the target address of an ADR instruction. - virtual void AppendAddressToOutput(const Instruction* instr, - const void* addr); + virtual void AppendCodeRelativeAddressToOutput(const Instruction* instr, + const void* addr); // Prints the address of some code. // This is used for example to print the target address of a branch to an // immediate offset. // A sub-class can for example override this method to lookup the address and // print an appropriate name. - virtual void AppendCodeAddressToOutput(const Instruction* instr, - const void* addr); + virtual void AppendCodeRelativeCodeAddressToOutput(const Instruction* instr, + const void* addr); // Prints the address of some data. // This is used for example to print the source address of a load literal // instruction. + virtual void AppendCodeRelativeDataAddressToOutput(const Instruction* instr, + const void* addr); + + // Same as the above, but for addresses that are not relative to the code + // buffer. They are currently not used by VIXL. + virtual void AppendAddressToOutput(const Instruction* instr, + const void* addr); + virtual void AppendCodeAddressToOutput(const Instruction* instr, + const void* addr); virtual void AppendDataAddressToOutput(const Instruction* instr, const void* addr); + public: + // Get/Set the offset that should be added to code addresses when printing + // code-relative addresses in the AppendCodeRelative<Type>AddressToOutput() + // helpers. + // Below is an example of how a branch immediate instruction in memory at + // address 0xb010200 would disassemble with different offsets. + // Base address | Disassembly + // 0x0 | 0xb010200: b #+0xcc (addr 0xb0102cc) + // 0x10000 | 0xb000200: b #+0xcc (addr 0xb0002cc) + // 0xb010200 | 0x0: b #+0xcc (addr 0xcc) + void MapCodeAddress(int64_t base_address, const Instruction* instr_address); + int64_t CodeRelativeAddress(const void* instr); + private: void Format( const Instruction* instr, const char* mnemonic, const char* format); @@ -101,32 +123,40 @@ class Disassembler: public DecoderVisitor { int SubstitutePrefetchField(const Instruction* instr, const char* format); int SubstituteBarrierField(const Instruction* instr, const char* format); - inline bool RdIsZROrSP(const Instruction* instr) const { + bool RdIsZROrSP(const Instruction* instr) const { return (instr->Rd() == kZeroRegCode); } - inline bool RnIsZROrSP(const Instruction* instr) const { + bool RnIsZROrSP(const Instruction* instr) const { return (instr->Rn() == kZeroRegCode); } - inline bool RmIsZROrSP(const Instruction* instr) const { + bool RmIsZROrSP(const Instruction* instr) const { return (instr->Rm() == kZeroRegCode); } - inline bool RaIsZROrSP(const Instruction* instr) const { + bool RaIsZROrSP(const Instruction* instr) const { return (instr->Ra() == kZeroRegCode); } bool IsMovzMovnImm(unsigned reg_size, uint64_t value); + int64_t code_address_offset() const { return code_address_offset_; } + protected: void ResetOutput(); void AppendToOutput(const char* string, ...) PRINTF_CHECK(2, 3); + void set_code_address_offset(int64_t code_address_offset) { + code_address_offset_ = code_address_offset; + } + char* buffer_; uint32_t buffer_pos_; uint32_t buffer_size_; bool own_buffer_; + + int64_t code_address_offset_; }; diff --git a/disas/libvixl/a64/instructions-a64.cc b/disas/libvixl/a64/instructions-a64.cc index 1f08c781eb..b091886838 100644 --- a/disas/libvixl/a64/instructions-a64.cc +++ b/disas/libvixl/a64/instructions-a64.cc @@ -30,6 +30,20 @@ namespace vixl { +// Floating-point infinity values. +const float kFP32PositiveInfinity = rawbits_to_float(0x7f800000); +const float kFP32NegativeInfinity = rawbits_to_float(0xff800000); +const double kFP64PositiveInfinity = + rawbits_to_double(UINT64_C(0x7ff0000000000000)); +const double kFP64NegativeInfinity = + rawbits_to_double(UINT64_C(0xfff0000000000000)); + + +// The default NaN values (for FPCR.DN=1). +const double kFP64DefaultNaN = rawbits_to_double(UINT64_C(0x7ff8000000000000)); +const float kFP32DefaultNaN = rawbits_to_float(0x7fc00000); + + static uint64_t RotateRight(uint64_t value, unsigned int rotate, unsigned int width) { @@ -54,6 +68,55 @@ static uint64_t RepeatBitsAcrossReg(unsigned reg_size, } +bool Instruction::IsLoad() const { + if (Mask(LoadStoreAnyFMask) != LoadStoreAnyFixed) { + return false; + } + + if (Mask(LoadStorePairAnyFMask) == LoadStorePairAnyFixed) { + return Mask(LoadStorePairLBit) != 0; + } else { + LoadStoreOp op = static_cast<LoadStoreOp>(Mask(LoadStoreOpMask)); + switch (op) { + case LDRB_w: + case LDRH_w: + case LDR_w: + case LDR_x: + case LDRSB_w: + case LDRSB_x: + case LDRSH_w: + case LDRSH_x: + case LDRSW_x: + case LDR_s: + case LDR_d: return true; + default: return false; + } + } +} + + +bool Instruction::IsStore() const { + if (Mask(LoadStoreAnyFMask) != LoadStoreAnyFixed) { + return false; + } + + if (Mask(LoadStorePairAnyFMask) == LoadStorePairAnyFixed) { + return Mask(LoadStorePairLBit) == 0; + } else { + LoadStoreOp op = static_cast<LoadStoreOp>(Mask(LoadStoreOpMask)); + switch (op) { + case STRB_w: + case STRH_w: + case STR_w: + case STR_x: + case STR_s: + case STR_d: return true; + default: return false; + } + } +} + + // Logical immediates can't encode zero, so a return value of zero is used to // indicate a failure case. Specifically, where the constraints on imm_s are // not met. diff --git a/disas/libvixl/a64/instructions-a64.h b/disas/libvixl/a64/instructions-a64.h index 29f972291b..f1d883ccc7 100644 --- a/disas/libvixl/a64/instructions-a64.h +++ b/disas/libvixl/a64/instructions-a64.h @@ -96,6 +96,17 @@ const unsigned kDoubleExponentBits = 11; const unsigned kFloatMantissaBits = 23; const unsigned kFloatExponentBits = 8; +// Floating-point infinity values. +extern const float kFP32PositiveInfinity; +extern const float kFP32NegativeInfinity; +extern const double kFP64PositiveInfinity; +extern const double kFP64NegativeInfinity; + +// The default NaN values (for FPCR.DN=1). +extern const double kFP64DefaultNaN; +extern const float kFP32DefaultNaN; + + enum LSDataSize { LSByte = 0, LSHalfword = 1, @@ -140,33 +151,33 @@ enum Reg31Mode { class Instruction { public: - inline Instr InstructionBits() const { + Instr InstructionBits() const { return *(reinterpret_cast<const Instr*>(this)); } - inline void SetInstructionBits(Instr new_instr) { + void SetInstructionBits(Instr new_instr) { *(reinterpret_cast<Instr*>(this)) = new_instr; } - inline int Bit(int pos) const { + int Bit(int pos) const { return (InstructionBits() >> pos) & 1; } - inline uint32_t Bits(int msb, int lsb) const { + uint32_t Bits(int msb, int lsb) const { return unsigned_bitextract_32(msb, lsb, InstructionBits()); } - inline int32_t SignedBits(int msb, int lsb) const { + int32_t SignedBits(int msb, int lsb) const { int32_t bits = *(reinterpret_cast<const int32_t*>(this)); return signed_bitextract_32(msb, lsb, bits); } - inline Instr Mask(uint32_t mask) const { + Instr Mask(uint32_t mask) const { return InstructionBits() & mask; } #define DEFINE_GETTER(Name, HighBit, LowBit, Func) \ - inline int64_t Name() const { return Func(HighBit, LowBit); } + int64_t Name() const { return Func(HighBit, LowBit); } INSTRUCTION_FIELDS_LIST(DEFINE_GETTER) #undef DEFINE_GETTER @@ -182,56 +193,64 @@ class Instruction { float ImmFP32() const; double ImmFP64() const; - inline LSDataSize SizeLSPair() const { + LSDataSize SizeLSPair() const { return CalcLSPairDataSize( static_cast<LoadStorePairOp>(Mask(LoadStorePairMask))); } // Helpers. - inline bool IsCondBranchImm() const { + bool IsCondBranchImm() const { return Mask(ConditionalBranchFMask) == ConditionalBranchFixed; } - inline bool IsUncondBranchImm() const { + bool IsUncondBranchImm() const { return Mask(UnconditionalBranchFMask) == UnconditionalBranchFixed; } - inline bool IsCompareBranch() const { + bool IsCompareBranch() const { return Mask(CompareBranchFMask) == CompareBranchFixed; } - inline bool IsTestBranch() const { + bool IsTestBranch() const { return Mask(TestBranchFMask) == TestBranchFixed; } - inline bool IsPCRelAddressing() const { + bool IsPCRelAddressing() const { return Mask(PCRelAddressingFMask) == PCRelAddressingFixed; } - inline bool IsLogicalImmediate() const { + bool IsLogicalImmediate() const { return Mask(LogicalImmediateFMask) == LogicalImmediateFixed; } - inline bool IsAddSubImmediate() const { + bool IsAddSubImmediate() const { return Mask(AddSubImmediateFMask) == AddSubImmediateFixed; } - inline bool IsAddSubExtended() const { + bool IsAddSubExtended() const { return Mask(AddSubExtendedFMask) == AddSubExtendedFixed; } - inline bool IsLoadOrStore() const { + bool IsLoadOrStore() const { return Mask(LoadStoreAnyFMask) == LoadStoreAnyFixed; } - inline bool IsMovn() const { + bool IsLoad() const; + bool IsStore() const; + + bool IsLoadLiteral() const { + // This includes PRFM_lit. + return Mask(LoadLiteralFMask) == LoadLiteralFixed; + } + + bool IsMovn() const { return (Mask(MoveWideImmediateMask) == MOVN_x) || (Mask(MoveWideImmediateMask) == MOVN_w); } // Indicate whether Rd can be the stack pointer or the zero register. This // does not check that the instruction actually has an Rd field. - inline Reg31Mode RdMode() const { + Reg31Mode RdMode() const { // The following instructions use sp or wsp as Rd: // Add/sub (immediate) when not setting the flags. // Add/sub (extended) when not setting the flags. @@ -260,7 +279,7 @@ class Instruction { // Indicate whether Rn can be the stack pointer or the zero register. This // does not check that the instruction actually has an Rn field. - inline Reg31Mode RnMode() const { + Reg31Mode RnMode() const { // The following instructions use sp or wsp as Rn: // All loads and stores. // Add/sub (immediate). @@ -272,7 +291,7 @@ class Instruction { return Reg31IsZeroRegister; } - inline ImmBranchType BranchType() const { + ImmBranchType BranchType() const { if (IsCondBranchImm()) { return CondBranchType; } else if (IsUncondBranchImm()) { @@ -296,55 +315,66 @@ class Instruction { // Patch a literal load instruction to load from 'source'. void SetImmLLiteral(const Instruction* source); - inline uint8_t* LiteralAddress() const { - int offset = ImmLLiteral() << kLiteralEntrySizeLog2; - const uint8_t* address = reinterpret_cast<const uint8_t*>(this) + offset; - // Note that the result is safely mutable only if the backing buffer is - // safely mutable. - return const_cast<uint8_t*>(address); + // Calculate the address of a literal referred to by a load-literal + // instruction, and return it as the specified type. + // + // The literal itself is safely mutable only if the backing buffer is safely + // mutable. + template <typename T> + T LiteralAddress() const { + uint64_t base_raw = reinterpret_cast<uintptr_t>(this); + ptrdiff_t offset = ImmLLiteral() << kLiteralEntrySizeLog2; + uint64_t address_raw = base_raw + offset; + + // Cast the address using a C-style cast. A reinterpret_cast would be + // appropriate, but it can't cast one integral type to another. + T address = (T)(address_raw); + + // Assert that the address can be represented by the specified type. + VIXL_ASSERT((uint64_t)(address) == address_raw); + + return address; } - inline uint32_t Literal32() const { + uint32_t Literal32() const { uint32_t literal; - memcpy(&literal, LiteralAddress(), sizeof(literal)); - + memcpy(&literal, LiteralAddress<const void*>(), sizeof(literal)); return literal; } - inline uint64_t Literal64() const { + uint64_t Literal64() const { uint64_t literal; - memcpy(&literal, LiteralAddress(), sizeof(literal)); - + memcpy(&literal, LiteralAddress<const void*>(), sizeof(literal)); return literal; } - inline float LiteralFP32() const { + float LiteralFP32() const { return rawbits_to_float(Literal32()); } - inline double LiteralFP64() const { + double LiteralFP64() const { return rawbits_to_double(Literal64()); } - inline const Instruction* NextInstruction() const { + const Instruction* NextInstruction() const { return this + kInstructionSize; } - inline const Instruction* InstructionAtOffset(int64_t offset) const { + const Instruction* InstructionAtOffset(int64_t offset) const { VIXL_ASSERT(IsWordAligned(this + offset)); return this + offset; } - template<typename T> static inline Instruction* Cast(T src) { + template<typename T> static Instruction* Cast(T src) { return reinterpret_cast<Instruction*>(src); } - template<typename T> static inline const Instruction* CastConst(T src) { + template<typename T> static const Instruction* CastConst(T src) { return reinterpret_cast<const Instruction*>(src); } private: - inline int ImmBranch() const; + int ImmBranch() const; void SetPCRelImmTarget(const Instruction* target); void SetBranchImmTarget(const Instruction* target); |