• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2015, VIXL authors
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are met:
6 //
7 //   * Redistributions of source code must retain the above copyright notice,
8 //     this list of conditions and the following disclaimer.
9 //   * Redistributions in binary form must reproduce the above copyright notice,
10 //     this list of conditions and the following disclaimer in the documentation
11 //     and/or other materials provided with the distribution.
12 //   * Neither the name of ARM Limited nor the names of its contributors may be
13 //     used to endorse or promote products derived from this software without
14 //     specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS CONTRIBUTORS "AS IS" AND
17 // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
20 // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22 // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
23 // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24 // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 
27 #ifndef VIXL_AARCH64_INSTRUCTIONS_AARCH64_H_
28 #define VIXL_AARCH64_INSTRUCTIONS_AARCH64_H_
29 
30 #include "../globals-vixl.h"
31 #include "../utils-vixl.h"
32 
33 #include "constants-aarch64.h"
34 
35 namespace vixl {
36 namespace aarch64 {
37 // ISA constants. --------------------------------------------------------------
38 
39 typedef uint32_t Instr;
40 const unsigned kInstructionSize = 4;
41 const unsigned kInstructionSizeLog2 = 2;
42 const unsigned kLiteralEntrySize = 4;
43 const unsigned kLiteralEntrySizeLog2 = 2;
44 const unsigned kMaxLoadLiteralRange = 1 * MBytes;
45 
46 // This is the nominal page size (as used by the adrp instruction); the actual
47 // size of the memory pages allocated by the kernel is likely to differ.
48 const unsigned kPageSize = 4 * KBytes;
49 const unsigned kPageSizeLog2 = 12;
50 
51 const unsigned kBRegSize = 8;
52 const unsigned kBRegSizeLog2 = 3;
53 const unsigned kBRegSizeInBytes = kBRegSize / 8;
54 const unsigned kBRegSizeInBytesLog2 = kBRegSizeLog2 - 3;
55 const unsigned kHRegSize = 16;
56 const unsigned kHRegSizeLog2 = 4;
57 const unsigned kHRegSizeInBytes = kHRegSize / 8;
58 const unsigned kHRegSizeInBytesLog2 = kHRegSizeLog2 - 3;
59 const unsigned kWRegSize = 32;
60 const unsigned kWRegSizeLog2 = 5;
61 const unsigned kWRegSizeInBytes = kWRegSize / 8;
62 const unsigned kWRegSizeInBytesLog2 = kWRegSizeLog2 - 3;
63 const unsigned kXRegSize = 64;
64 const unsigned kXRegSizeLog2 = 6;
65 const unsigned kXRegSizeInBytes = kXRegSize / 8;
66 const unsigned kXRegSizeInBytesLog2 = kXRegSizeLog2 - 3;
67 const unsigned kSRegSize = 32;
68 const unsigned kSRegSizeLog2 = 5;
69 const unsigned kSRegSizeInBytes = kSRegSize / 8;
70 const unsigned kSRegSizeInBytesLog2 = kSRegSizeLog2 - 3;
71 const unsigned kDRegSize = 64;
72 const unsigned kDRegSizeLog2 = 6;
73 const unsigned kDRegSizeInBytes = kDRegSize / 8;
74 const unsigned kDRegSizeInBytesLog2 = kDRegSizeLog2 - 3;
75 const unsigned kQRegSize = 128;
76 const unsigned kQRegSizeLog2 = 7;
77 const unsigned kQRegSizeInBytes = kQRegSize / 8;
78 const unsigned kQRegSizeInBytesLog2 = kQRegSizeLog2 - 3;
79 const uint64_t kWRegMask = UINT64_C(0xffffffff);
80 const uint64_t kXRegMask = UINT64_C(0xffffffffffffffff);
81 const uint64_t kSRegMask = UINT64_C(0xffffffff);
82 const uint64_t kDRegMask = UINT64_C(0xffffffffffffffff);
83 const uint64_t kSSignMask = UINT64_C(0x80000000);
84 const uint64_t kDSignMask = UINT64_C(0x8000000000000000);
85 const uint64_t kWSignMask = UINT64_C(0x80000000);
86 const uint64_t kXSignMask = UINT64_C(0x8000000000000000);
87 const uint64_t kByteMask = UINT64_C(0xff);
88 const uint64_t kHalfWordMask = UINT64_C(0xffff);
89 const uint64_t kWordMask = UINT64_C(0xffffffff);
90 const uint64_t kXMaxUInt = UINT64_C(0xffffffffffffffff);
91 const uint64_t kWMaxUInt = UINT64_C(0xffffffff);
92 const int64_t kXMaxInt = INT64_C(0x7fffffffffffffff);
93 const int64_t kXMinInt = INT64_C(0x8000000000000000);
94 const int32_t kWMaxInt = INT32_C(0x7fffffff);
95 const int32_t kWMinInt = INT32_C(0x80000000);
96 const unsigned kFpRegCode = 29;
97 const unsigned kLinkRegCode = 30;
98 const unsigned kSpRegCode = 31;
99 const unsigned kZeroRegCode = 31;
100 const unsigned kSPRegInternalCode = 63;
101 const unsigned kRegCodeMask = 0x1f;
102 
103 const unsigned kAddressTagOffset = 56;
104 const unsigned kAddressTagWidth = 8;
105 const uint64_t kAddressTagMask = ((UINT64_C(1) << kAddressTagWidth) - 1)
106                                  << kAddressTagOffset;
107 VIXL_STATIC_ASSERT(kAddressTagMask == UINT64_C(0xff00000000000000));
108 
109 // AArch64 floating-point specifics. These match IEEE-754.
110 const unsigned kDoubleMantissaBits = 52;
111 const unsigned kDoubleExponentBits = 11;
112 const unsigned kFloatMantissaBits = 23;
113 const unsigned kFloatExponentBits = 8;
114 const unsigned kFloat16MantissaBits = 10;
115 const unsigned kFloat16ExponentBits = 5;
116 
117 // Floating-point infinity values.
118 extern const float16 kFP16PositiveInfinity;
119 extern const float16 kFP16NegativeInfinity;
120 extern const float kFP32PositiveInfinity;
121 extern const float kFP32NegativeInfinity;
122 extern const double kFP64PositiveInfinity;
123 extern const double kFP64NegativeInfinity;
124 
125 // The default NaN values (for FPCR.DN=1).
126 extern const float16 kFP16DefaultNaN;
127 extern const float kFP32DefaultNaN;
128 extern const double kFP64DefaultNaN;
129 
130 unsigned CalcLSDataSize(LoadStoreOp op);
131 unsigned CalcLSPairDataSize(LoadStorePairOp op);
132 
133 enum ImmBranchType {
134   UnknownBranchType = 0,
135   CondBranchType = 1,
136   UncondBranchType = 2,
137   CompareBranchType = 3,
138   TestBranchType = 4
139 };
140 
141 enum AddrMode { Offset, PreIndex, PostIndex };
142 
143 enum FPRounding {
144   // The first four values are encodable directly by FPCR<RMode>.
145   FPTieEven = 0x0,
146   FPPositiveInfinity = 0x1,
147   FPNegativeInfinity = 0x2,
148   FPZero = 0x3,
149 
150   // The final rounding modes are only available when explicitly specified by
151   // the instruction (such as with fcvta). It cannot be set in FPCR.
152   FPTieAway,
153   FPRoundOdd
154 };
155 
156 enum Reg31Mode { Reg31IsStackPointer, Reg31IsZeroRegister };
157 
158 // Instructions. ---------------------------------------------------------------
159 
160 class Instruction {
161  public:
GetInstructionBits()162   Instr GetInstructionBits() const {
163     return *(reinterpret_cast<const Instr*>(this));
164   }
165   VIXL_DEPRECATED("GetInstructionBits", Instr InstructionBits() const) {
166     return GetInstructionBits();
167   }
168 
SetInstructionBits(Instr new_instr)169   void SetInstructionBits(Instr new_instr) {
170     *(reinterpret_cast<Instr*>(this)) = new_instr;
171   }
172 
ExtractBit(int pos)173   int ExtractBit(int pos) const { return (GetInstructionBits() >> pos) & 1; }
Bit(int pos)174   VIXL_DEPRECATED("ExtractBit", int Bit(int pos) const) {
175     return ExtractBit(pos);
176   }
177 
ExtractBits(int msb,int lsb)178   uint32_t ExtractBits(int msb, int lsb) const {
179     return ExtractUnsignedBitfield32(msb, lsb, GetInstructionBits());
180   }
181   VIXL_DEPRECATED("ExtractBits", uint32_t Bits(int msb, int lsb) const) {
182     return ExtractBits(msb, lsb);
183   }
184 
ExtractSignedBits(int msb,int lsb)185   int32_t ExtractSignedBits(int msb, int lsb) const {
186     int32_t bits = *(reinterpret_cast<const int32_t*>(this));
187     return ExtractSignedBitfield32(msb, lsb, bits);
188   }
189   VIXL_DEPRECATED("ExtractSignedBits",
190                   int32_t SignedBits(int msb, int lsb) const) {
191     return ExtractSignedBits(msb, lsb);
192   }
193 
Mask(uint32_t mask)194   Instr Mask(uint32_t mask) const { return GetInstructionBits() & mask; }
195 
196 #define DEFINE_GETTER(Name, HighBit, LowBit, Func)                  \
197   int32_t Get##Name() const { return this->Func(HighBit, LowBit); } \
198   VIXL_DEPRECATED("Get" #Name, int32_t Name() const) { return Get##Name(); }
INSTRUCTION_FIELDS_LIST(DEFINE_GETTER)199   INSTRUCTION_FIELDS_LIST(DEFINE_GETTER)
200 #undef DEFINE_GETTER
201 
202   // ImmPCRel is a compound field (not present in INSTRUCTION_FIELDS_LIST),
203   // formed from ImmPCRelLo and ImmPCRelHi.
204   int GetImmPCRel() const {
205     uint32_t hi = static_cast<uint32_t>(GetImmPCRelHi());
206     uint32_t lo = GetImmPCRelLo();
207     uint32_t offset = (hi << ImmPCRelLo_width) | lo;
208     int width = ImmPCRelLo_width + ImmPCRelHi_width;
209     return ExtractSignedBitfield32(width - 1, 0, offset);
210   }
ImmPCRel()211   VIXL_DEPRECATED("GetImmPCRel", int ImmPCRel() const) { return GetImmPCRel(); }
212 
213   uint64_t GetImmLogical() const;
214   VIXL_DEPRECATED("GetImmLogical", uint64_t ImmLogical() const) {
215     return GetImmLogical();
216   }
217 
218   unsigned GetImmNEONabcdefgh() const;
ImmNEONabcdefgh()219   VIXL_DEPRECATED("GetImmNEONabcdefgh", unsigned ImmNEONabcdefgh() const) {
220     return GetImmNEONabcdefgh();
221   }
222 
223   float GetImmFP32() const;
ImmFP32()224   VIXL_DEPRECATED("GetImmFP32", float ImmFP32() const) { return GetImmFP32(); }
225 
226   double GetImmFP64() const;
ImmFP64()227   VIXL_DEPRECATED("GetImmFP64", double ImmFP64() const) { return GetImmFP64(); }
228 
229   float GetImmNEONFP32() const;
ImmNEONFP32()230   VIXL_DEPRECATED("GetImmNEONFP32", float ImmNEONFP32() const) {
231     return GetImmNEONFP32();
232   }
233 
234   double GetImmNEONFP64() const;
ImmNEONFP64()235   VIXL_DEPRECATED("GetImmNEONFP64", double ImmNEONFP64() const) {
236     return GetImmNEONFP64();
237   }
238 
GetSizeLS()239   unsigned GetSizeLS() const {
240     return CalcLSDataSize(static_cast<LoadStoreOp>(Mask(LoadStoreMask)));
241   }
SizeLS()242   VIXL_DEPRECATED("GetSizeLS", unsigned SizeLS() const) { return GetSizeLS(); }
243 
GetSizeLSPair()244   unsigned GetSizeLSPair() const {
245     return CalcLSPairDataSize(
246         static_cast<LoadStorePairOp>(Mask(LoadStorePairMask)));
247   }
SizeLSPair()248   VIXL_DEPRECATED("GetSizeLSPair", unsigned SizeLSPair() const) {
249     return GetSizeLSPair();
250   }
251 
GetNEONLSIndex(int access_size_shift)252   int GetNEONLSIndex(int access_size_shift) const {
253     int64_t q = GetNEONQ();
254     int64_t s = GetNEONS();
255     int64_t size = GetNEONLSSize();
256     int64_t index = (q << 3) | (s << 2) | size;
257     return static_cast<int>(index >> access_size_shift);
258   }
259   VIXL_DEPRECATED("GetNEONLSIndex",
NEONLSIndex(int access_size_shift)260                   int NEONLSIndex(int access_size_shift) const) {
261     return GetNEONLSIndex(access_size_shift);
262   }
263 
264   // Helpers.
IsCondBranchImm()265   bool IsCondBranchImm() const {
266     return Mask(ConditionalBranchFMask) == ConditionalBranchFixed;
267   }
268 
IsUncondBranchImm()269   bool IsUncondBranchImm() const {
270     return Mask(UnconditionalBranchFMask) == UnconditionalBranchFixed;
271   }
272 
IsCompareBranch()273   bool IsCompareBranch() const {
274     return Mask(CompareBranchFMask) == CompareBranchFixed;
275   }
276 
IsTestBranch()277   bool IsTestBranch() const { return Mask(TestBranchFMask) == TestBranchFixed; }
278 
IsImmBranch()279   bool IsImmBranch() const { return GetBranchType() != UnknownBranchType; }
280 
IsPCRelAddressing()281   bool IsPCRelAddressing() const {
282     return Mask(PCRelAddressingFMask) == PCRelAddressingFixed;
283   }
284 
IsLogicalImmediate()285   bool IsLogicalImmediate() const {
286     return Mask(LogicalImmediateFMask) == LogicalImmediateFixed;
287   }
288 
IsAddSubImmediate()289   bool IsAddSubImmediate() const {
290     return Mask(AddSubImmediateFMask) == AddSubImmediateFixed;
291   }
292 
IsAddSubExtended()293   bool IsAddSubExtended() const {
294     return Mask(AddSubExtendedFMask) == AddSubExtendedFixed;
295   }
296 
IsLoadOrStore()297   bool IsLoadOrStore() const {
298     return Mask(LoadStoreAnyFMask) == LoadStoreAnyFixed;
299   }
300 
301   bool IsLoad() const;
302   bool IsStore() const;
303 
IsLoadLiteral()304   bool IsLoadLiteral() const {
305     // This includes PRFM_lit.
306     return Mask(LoadLiteralFMask) == LoadLiteralFixed;
307   }
308 
IsMovn()309   bool IsMovn() const {
310     return (Mask(MoveWideImmediateMask) == MOVN_x) ||
311            (Mask(MoveWideImmediateMask) == MOVN_w);
312   }
313 
314   static int GetImmBranchRangeBitwidth(ImmBranchType branch_type);
315   VIXL_DEPRECATED(
316       "GetImmBranchRangeBitwidth",
ImmBranchRangeBitwidth(ImmBranchType branch_type)317       static int ImmBranchRangeBitwidth(ImmBranchType branch_type)) {
318     return GetImmBranchRangeBitwidth(branch_type);
319   }
320 
321   static int32_t GetImmBranchForwardRange(ImmBranchType branch_type);
322   VIXL_DEPRECATED(
323       "GetImmBranchForwardRange",
324       static int32_t ImmBranchForwardRange(ImmBranchType branch_type)) {
325     return GetImmBranchForwardRange(branch_type);
326   }
327 
328   static bool IsValidImmPCOffset(ImmBranchType branch_type, int64_t offset);
329 
330   // Indicate whether Rd can be the stack pointer or the zero register. This
331   // does not check that the instruction actually has an Rd field.
GetRdMode()332   Reg31Mode GetRdMode() const {
333     // The following instructions use sp or wsp as Rd:
334     //  Add/sub (immediate) when not setting the flags.
335     //  Add/sub (extended) when not setting the flags.
336     //  Logical (immediate) when not setting the flags.
337     // Otherwise, r31 is the zero register.
338     if (IsAddSubImmediate() || IsAddSubExtended()) {
339       if (Mask(AddSubSetFlagsBit)) {
340         return Reg31IsZeroRegister;
341       } else {
342         return Reg31IsStackPointer;
343       }
344     }
345     if (IsLogicalImmediate()) {
346       // Of the logical (immediate) instructions, only ANDS (and its aliases)
347       // can set the flags. The others can all write into sp.
348       // Note that some logical operations are not available to
349       // immediate-operand instructions, so we have to combine two masks here.
350       if (Mask(LogicalImmediateMask & LogicalOpMask) == ANDS) {
351         return Reg31IsZeroRegister;
352       } else {
353         return Reg31IsStackPointer;
354       }
355     }
356     return Reg31IsZeroRegister;
357   }
358   VIXL_DEPRECATED("GetRdMode", Reg31Mode RdMode() const) { return GetRdMode(); }
359 
360   // Indicate whether Rn can be the stack pointer or the zero register. This
361   // does not check that the instruction actually has an Rn field.
GetRnMode()362   Reg31Mode GetRnMode() const {
363     // The following instructions use sp or wsp as Rn:
364     //  All loads and stores.
365     //  Add/sub (immediate).
366     //  Add/sub (extended).
367     // Otherwise, r31 is the zero register.
368     if (IsLoadOrStore() || IsAddSubImmediate() || IsAddSubExtended()) {
369       return Reg31IsStackPointer;
370     }
371     return Reg31IsZeroRegister;
372   }
373   VIXL_DEPRECATED("GetRnMode", Reg31Mode RnMode() const) { return GetRnMode(); }
374 
GetBranchType()375   ImmBranchType GetBranchType() const {
376     if (IsCondBranchImm()) {
377       return CondBranchType;
378     } else if (IsUncondBranchImm()) {
379       return UncondBranchType;
380     } else if (IsCompareBranch()) {
381       return CompareBranchType;
382     } else if (IsTestBranch()) {
383       return TestBranchType;
384     } else {
385       return UnknownBranchType;
386     }
387   }
388   VIXL_DEPRECATED("GetBranchType", ImmBranchType BranchType() const) {
389     return GetBranchType();
390   }
391 
392   // Find the target of this instruction. 'this' may be a branch or a
393   // PC-relative addressing instruction.
394   const Instruction* GetImmPCOffsetTarget() const;
395   VIXL_DEPRECATED("GetImmPCOffsetTarget",
396                   const Instruction* ImmPCOffsetTarget() const) {
397     return GetImmPCOffsetTarget();
398   }
399 
400   // Patch a PC-relative offset to refer to 'target'. 'this' may be a branch or
401   // a PC-relative addressing instruction.
402   void SetImmPCOffsetTarget(const Instruction* target);
403   // Patch a literal load instruction to load from 'source'.
404   void SetImmLLiteral(const Instruction* source);
405 
406   // The range of a load literal instruction, expressed as 'instr +- range'.
407   // The range is actually the 'positive' range; the branch instruction can
408   // target [instr - range - kInstructionSize, instr + range].
409   static const int kLoadLiteralImmBitwidth = 19;
410   static const int kLoadLiteralRange =
411       (1 << kLoadLiteralImmBitwidth) / 2 - kInstructionSize;
412 
413   // Calculate the address of a literal referred to by a load-literal
414   // instruction, and return it as the specified type.
415   //
416   // The literal itself is safely mutable only if the backing buffer is safely
417   // mutable.
418   template <typename T>
GetLiteralAddress()419   T GetLiteralAddress() const {
420     uint64_t base_raw = reinterpret_cast<uint64_t>(this);
421     int64_t offset = GetImmLLiteral() * static_cast<int>(kLiteralEntrySize);
422     uint64_t address_raw = base_raw + offset;
423 
424     // Cast the address using a C-style cast. A reinterpret_cast would be
425     // appropriate, but it can't cast one integral type to another.
426     T address = (T)(address_raw);
427 
428     // Assert that the address can be represented by the specified type.
429     VIXL_ASSERT((uint64_t)(address) == address_raw);
430 
431     return address;
432   }
433   template <typename T>
434   VIXL_DEPRECATED("GetLiteralAddress", T LiteralAddress() const) {
435     return GetLiteralAddress<T>();
436   }
437 
GetLiteral32()438   uint32_t GetLiteral32() const {
439     uint32_t literal;
440     memcpy(&literal, GetLiteralAddress<const void*>(), sizeof(literal));
441     return literal;
442   }
443   VIXL_DEPRECATED("GetLiteral32", uint32_t Literal32() const) {
444     return GetLiteral32();
445   }
446 
GetLiteral64()447   uint64_t GetLiteral64() const {
448     uint64_t literal;
449     memcpy(&literal, GetLiteralAddress<const void*>(), sizeof(literal));
450     return literal;
451   }
452   VIXL_DEPRECATED("GetLiteral64", uint64_t Literal64() const) {
453     return GetLiteral64();
454   }
455 
GetLiteralFP32()456   float GetLiteralFP32() const { return RawbitsToFloat(GetLiteral32()); }
LiteralFP32()457   VIXL_DEPRECATED("GetLiteralFP32", float LiteralFP32() const) {
458     return GetLiteralFP32();
459   }
460 
GetLiteralFP64()461   double GetLiteralFP64() const { return RawbitsToDouble(GetLiteral64()); }
LiteralFP64()462   VIXL_DEPRECATED("GetLiteralFP64", double LiteralFP64() const) {
463     return GetLiteralFP64();
464   }
465 
GetNextInstruction()466   const Instruction* GetNextInstruction() const {
467     return this + kInstructionSize;
468   }
469   VIXL_DEPRECATED("GetNextInstruction",
470                   const Instruction* NextInstruction() const) {
471     return GetNextInstruction();
472   }
473 
GetInstructionAtOffset(int64_t offset)474   const Instruction* GetInstructionAtOffset(int64_t offset) const {
475     VIXL_ASSERT(IsWordAligned(this + offset));
476     return this + offset;
477   }
478   VIXL_DEPRECATED("GetInstructionAtOffset",
479                   const Instruction* InstructionAtOffset(int64_t offset)
480                       const) {
481     return GetInstructionAtOffset(offset);
482   }
483 
484   template <typename T>
Cast(T src)485   static Instruction* Cast(T src) {
486     return reinterpret_cast<Instruction*>(src);
487   }
488 
489   template <typename T>
CastConst(T src)490   static const Instruction* CastConst(T src) {
491     return reinterpret_cast<const Instruction*>(src);
492   }
493 
494  private:
495   int GetImmBranch() const;
496 
497   static float Imm8ToFP32(uint32_t imm8);
498   static double Imm8ToFP64(uint32_t imm8);
499 
500   void SetPCRelImmTarget(const Instruction* target);
501   void SetBranchImmTarget(const Instruction* target);
502 };
503 
504 
505 // Functions for handling NEON vector format information.
506 enum VectorFormat {
507   kFormatUndefined = 0xffffffff,
508   kFormat8B = NEON_8B,
509   kFormat16B = NEON_16B,
510   kFormat4H = NEON_4H,
511   kFormat8H = NEON_8H,
512   kFormat2S = NEON_2S,
513   kFormat4S = NEON_4S,
514   kFormat1D = NEON_1D,
515   kFormat2D = NEON_2D,
516 
517   // Scalar formats. We add the scalar bit to distinguish between scalar and
518   // vector enumerations; the bit is always set in the encoding of scalar ops
519   // and always clear for vector ops. Although kFormatD and kFormat1D appear
520   // to be the same, their meaning is subtly different. The first is a scalar
521   // operation, the second a vector operation that only affects one lane.
522   kFormatB = NEON_B | NEONScalar,
523   kFormatH = NEON_H | NEONScalar,
524   kFormatS = NEON_S | NEONScalar,
525   kFormatD = NEON_D | NEONScalar
526 };
527 
528 const int kMaxLanesPerVector = 16;
529 
530 VectorFormat VectorFormatHalfWidth(VectorFormat vform);
531 VectorFormat VectorFormatDoubleWidth(VectorFormat vform);
532 VectorFormat VectorFormatDoubleLanes(VectorFormat vform);
533 VectorFormat VectorFormatHalfLanes(VectorFormat vform);
534 VectorFormat ScalarFormatFromLaneSize(int lanesize);
535 VectorFormat VectorFormatHalfWidthDoubleLanes(VectorFormat vform);
536 VectorFormat VectorFormatFillQ(VectorFormat vform);
537 VectorFormat ScalarFormatFromFormat(VectorFormat vform);
538 unsigned RegisterSizeInBitsFromFormat(VectorFormat vform);
539 unsigned RegisterSizeInBytesFromFormat(VectorFormat vform);
540 // TODO: Make the return types of these functions consistent.
541 unsigned LaneSizeInBitsFromFormat(VectorFormat vform);
542 int LaneSizeInBytesFromFormat(VectorFormat vform);
543 int LaneSizeInBytesLog2FromFormat(VectorFormat vform);
544 int LaneCountFromFormat(VectorFormat vform);
545 int MaxLaneCountFromFormat(VectorFormat vform);
546 bool IsVectorFormat(VectorFormat vform);
547 int64_t MaxIntFromFormat(VectorFormat vform);
548 int64_t MinIntFromFormat(VectorFormat vform);
549 uint64_t MaxUintFromFormat(VectorFormat vform);
550 
551 
552 // clang-format off
553 enum NEONFormat {
554   NF_UNDEF = 0,
555   NF_8B    = 1,
556   NF_16B   = 2,
557   NF_4H    = 3,
558   NF_8H    = 4,
559   NF_2S    = 5,
560   NF_4S    = 6,
561   NF_1D    = 7,
562   NF_2D    = 8,
563   NF_B     = 9,
564   NF_H     = 10,
565   NF_S     = 11,
566   NF_D     = 12
567 };
568 // clang-format on
569 
570 static const unsigned kNEONFormatMaxBits = 6;
571 
572 struct NEONFormatMap {
573   // The bit positions in the instruction to consider.
574   uint8_t bits[kNEONFormatMaxBits];
575 
576   // Mapping from concatenated bits to format.
577   NEONFormat map[1 << kNEONFormatMaxBits];
578 };
579 
580 class NEONFormatDecoder {
581  public:
582   enum SubstitutionMode { kPlaceholder, kFormat };
583 
584   // Construct a format decoder with increasingly specific format maps for each
585   // subsitution. If no format map is specified, the default is the integer
586   // format map.
NEONFormatDecoder(const Instruction * instr)587   explicit NEONFormatDecoder(const Instruction* instr) {
588     instrbits_ = instr->GetInstructionBits();
589     SetFormatMaps(IntegerFormatMap());
590   }
NEONFormatDecoder(const Instruction * instr,const NEONFormatMap * format)591   NEONFormatDecoder(const Instruction* instr, const NEONFormatMap* format) {
592     instrbits_ = instr->GetInstructionBits();
593     SetFormatMaps(format);
594   }
NEONFormatDecoder(const Instruction * instr,const NEONFormatMap * format0,const NEONFormatMap * format1)595   NEONFormatDecoder(const Instruction* instr,
596                     const NEONFormatMap* format0,
597                     const NEONFormatMap* format1) {
598     instrbits_ = instr->GetInstructionBits();
599     SetFormatMaps(format0, format1);
600   }
NEONFormatDecoder(const Instruction * instr,const NEONFormatMap * format0,const NEONFormatMap * format1,const NEONFormatMap * format2)601   NEONFormatDecoder(const Instruction* instr,
602                     const NEONFormatMap* format0,
603                     const NEONFormatMap* format1,
604                     const NEONFormatMap* format2) {
605     instrbits_ = instr->GetInstructionBits();
606     SetFormatMaps(format0, format1, format2);
607   }
608 
609   // Set the format mapping for all or individual substitutions.
610   void SetFormatMaps(const NEONFormatMap* format0,
611                      const NEONFormatMap* format1 = NULL,
612                      const NEONFormatMap* format2 = NULL) {
613     VIXL_ASSERT(format0 != NULL);
614     formats_[0] = format0;
615     formats_[1] = (format1 == NULL) ? formats_[0] : format1;
616     formats_[2] = (format2 == NULL) ? formats_[1] : format2;
617   }
SetFormatMap(unsigned index,const NEONFormatMap * format)618   void SetFormatMap(unsigned index, const NEONFormatMap* format) {
619     VIXL_ASSERT(index <= (sizeof(formats_) / sizeof(formats_[0])));
620     VIXL_ASSERT(format != NULL);
621     formats_[index] = format;
622   }
623 
624   // Substitute %s in the input string with the placeholder string for each
625   // register, ie. "'B", "'H", etc.
SubstitutePlaceholders(const char * string)626   const char* SubstitutePlaceholders(const char* string) {
627     return Substitute(string, kPlaceholder, kPlaceholder, kPlaceholder);
628   }
629 
630   // Substitute %s in the input string with a new string based on the
631   // substitution mode.
632   const char* Substitute(const char* string,
633                          SubstitutionMode mode0 = kFormat,
634                          SubstitutionMode mode1 = kFormat,
635                          SubstitutionMode mode2 = kFormat) {
636     snprintf(form_buffer_,
637              sizeof(form_buffer_),
638              string,
639              GetSubstitute(0, mode0),
640              GetSubstitute(1, mode1),
641              GetSubstitute(2, mode2));
642     return form_buffer_;
643   }
644 
645   // Append a "2" to a mnemonic string based of the state of the Q bit.
Mnemonic(const char * mnemonic)646   const char* Mnemonic(const char* mnemonic) {
647     if ((instrbits_ & NEON_Q) != 0) {
648       snprintf(mne_buffer_, sizeof(mne_buffer_), "%s2", mnemonic);
649       return mne_buffer_;
650     }
651     return mnemonic;
652   }
653 
654   VectorFormat GetVectorFormat(int format_index = 0) {
655     return GetVectorFormat(formats_[format_index]);
656   }
657 
GetVectorFormat(const NEONFormatMap * format_map)658   VectorFormat GetVectorFormat(const NEONFormatMap* format_map) {
659     static const VectorFormat vform[] = {kFormatUndefined,
660                                          kFormat8B,
661                                          kFormat16B,
662                                          kFormat4H,
663                                          kFormat8H,
664                                          kFormat2S,
665                                          kFormat4S,
666                                          kFormat1D,
667                                          kFormat2D,
668                                          kFormatB,
669                                          kFormatH,
670                                          kFormatS,
671                                          kFormatD};
672     VIXL_ASSERT(GetNEONFormat(format_map) < (sizeof(vform) / sizeof(vform[0])));
673     return vform[GetNEONFormat(format_map)];
674   }
675 
676   // Built in mappings for common cases.
677 
678   // The integer format map uses three bits (Q, size<1:0>) to encode the
679   // "standard" set of NEON integer vector formats.
IntegerFormatMap()680   static const NEONFormatMap* IntegerFormatMap() {
681     static const NEONFormatMap map =
682         {{23, 22, 30},
683          {NF_8B, NF_16B, NF_4H, NF_8H, NF_2S, NF_4S, NF_UNDEF, NF_2D}};
684     return &map;
685   }
686 
687   // The long integer format map uses two bits (size<1:0>) to encode the
688   // long set of NEON integer vector formats. These are used in narrow, wide
689   // and long operations.
LongIntegerFormatMap()690   static const NEONFormatMap* LongIntegerFormatMap() {
691     static const NEONFormatMap map = {{23, 22}, {NF_8H, NF_4S, NF_2D}};
692     return &map;
693   }
694 
695   // The FP format map uses two bits (Q, size<0>) to encode the NEON FP vector
696   // formats: NF_2S, NF_4S, NF_2D.
FPFormatMap()697   static const NEONFormatMap* FPFormatMap() {
698     // The FP format map assumes two bits (Q, size<0>) are used to encode the
699     // NEON FP vector formats: NF_2S, NF_4S, NF_2D.
700     static const NEONFormatMap map = {{22, 30},
701                                       {NF_2S, NF_4S, NF_UNDEF, NF_2D}};
702     return &map;
703   }
704 
705   // The load/store format map uses three bits (Q, 11, 10) to encode the
706   // set of NEON vector formats.
LoadStoreFormatMap()707   static const NEONFormatMap* LoadStoreFormatMap() {
708     static const NEONFormatMap map =
709         {{11, 10, 30},
710          {NF_8B, NF_16B, NF_4H, NF_8H, NF_2S, NF_4S, NF_1D, NF_2D}};
711     return &map;
712   }
713 
714   // The logical format map uses one bit (Q) to encode the NEON vector format:
715   // NF_8B, NF_16B.
LogicalFormatMap()716   static const NEONFormatMap* LogicalFormatMap() {
717     static const NEONFormatMap map = {{30}, {NF_8B, NF_16B}};
718     return &map;
719   }
720 
721   // The triangular format map uses between two and five bits to encode the NEON
722   // vector format:
723   // xxx10->8B, xxx11->16B, xx100->4H, xx101->8H
724   // x1000->2S, x1001->4S,  10001->2D, all others undefined.
TriangularFormatMap()725   static const NEONFormatMap* TriangularFormatMap() {
726     static const NEONFormatMap map =
727         {{19, 18, 17, 16, 30},
728          {NF_UNDEF, NF_UNDEF, NF_8B, NF_16B, NF_4H, NF_8H, NF_8B, NF_16B,
729           NF_2S,    NF_4S,    NF_8B, NF_16B, NF_4H, NF_8H, NF_8B, NF_16B,
730           NF_UNDEF, NF_2D,    NF_8B, NF_16B, NF_4H, NF_8H, NF_8B, NF_16B,
731           NF_2S,    NF_4S,    NF_8B, NF_16B, NF_4H, NF_8H, NF_8B, NF_16B}};
732     return &map;
733   }
734 
735   // The scalar format map uses two bits (size<1:0>) to encode the NEON scalar
736   // formats: NF_B, NF_H, NF_S, NF_D.
ScalarFormatMap()737   static const NEONFormatMap* ScalarFormatMap() {
738     static const NEONFormatMap map = {{23, 22}, {NF_B, NF_H, NF_S, NF_D}};
739     return &map;
740   }
741 
742   // The long scalar format map uses two bits (size<1:0>) to encode the longer
743   // NEON scalar formats: NF_H, NF_S, NF_D.
LongScalarFormatMap()744   static const NEONFormatMap* LongScalarFormatMap() {
745     static const NEONFormatMap map = {{23, 22}, {NF_H, NF_S, NF_D}};
746     return &map;
747   }
748 
749   // The FP scalar format map assumes one bit (size<0>) is used to encode the
750   // NEON FP scalar formats: NF_S, NF_D.
FPScalarFormatMap()751   static const NEONFormatMap* FPScalarFormatMap() {
752     static const NEONFormatMap map = {{22}, {NF_S, NF_D}};
753     return &map;
754   }
755 
756   // The triangular scalar format map uses between one and four bits to encode
757   // the NEON FP scalar formats:
758   // xxx1->B, xx10->H, x100->S, 1000->D, all others undefined.
TriangularScalarFormatMap()759   static const NEONFormatMap* TriangularScalarFormatMap() {
760     static const NEONFormatMap map = {{19, 18, 17, 16},
761                                       {NF_UNDEF,
762                                        NF_B,
763                                        NF_H,
764                                        NF_B,
765                                        NF_S,
766                                        NF_B,
767                                        NF_H,
768                                        NF_B,
769                                        NF_D,
770                                        NF_B,
771                                        NF_H,
772                                        NF_B,
773                                        NF_S,
774                                        NF_B,
775                                        NF_H,
776                                        NF_B}};
777     return &map;
778   }
779 
780  private:
781   // Get a pointer to a string that represents the format or placeholder for
782   // the specified substitution index, based on the format map and instruction.
GetSubstitute(int index,SubstitutionMode mode)783   const char* GetSubstitute(int index, SubstitutionMode mode) {
784     if (mode == kFormat) {
785       return NEONFormatAsString(GetNEONFormat(formats_[index]));
786     }
787     VIXL_ASSERT(mode == kPlaceholder);
788     return NEONFormatAsPlaceholder(GetNEONFormat(formats_[index]));
789   }
790 
791   // Get the NEONFormat enumerated value for bits obtained from the
792   // instruction based on the specified format mapping.
GetNEONFormat(const NEONFormatMap * format_map)793   NEONFormat GetNEONFormat(const NEONFormatMap* format_map) {
794     return format_map->map[PickBits(format_map->bits)];
795   }
796 
797   // Convert a NEONFormat into a string.
NEONFormatAsString(NEONFormat format)798   static const char* NEONFormatAsString(NEONFormat format) {
799     // clang-format off
800     static const char* formats[] = {
801       "undefined",
802       "8b", "16b", "4h", "8h", "2s", "4s", "1d", "2d",
803       "b", "h", "s", "d"
804     };
805     // clang-format on
806     VIXL_ASSERT(format < (sizeof(formats) / sizeof(formats[0])));
807     return formats[format];
808   }
809 
810   // Convert a NEONFormat into a register placeholder string.
NEONFormatAsPlaceholder(NEONFormat format)811   static const char* NEONFormatAsPlaceholder(NEONFormat format) {
812     VIXL_ASSERT((format == NF_B) || (format == NF_H) || (format == NF_S) ||
813                 (format == NF_D) || (format == NF_UNDEF));
814     // clang-format off
815     static const char* formats[] = {
816       "undefined",
817       "undefined", "undefined", "undefined", "undefined",
818       "undefined", "undefined", "undefined", "undefined",
819       "'B", "'H", "'S", "'D"
820     };
821     // clang-format on
822     return formats[format];
823   }
824 
825   // Select bits from instrbits_ defined by the bits array, concatenate them,
826   // and return the value.
PickBits(const uint8_t bits[])827   uint8_t PickBits(const uint8_t bits[]) {
828     uint8_t result = 0;
829     for (unsigned b = 0; b < kNEONFormatMaxBits; b++) {
830       if (bits[b] == 0) break;
831       result <<= 1;
832       result |= ((instrbits_ & (1 << bits[b])) == 0) ? 0 : 1;
833     }
834     return result;
835   }
836 
837   Instr instrbits_;
838   const NEONFormatMap* formats_[3];
839   char form_buffer_[64];
840   char mne_buffer_[16];
841 };
842 }  // namespace aarch64
843 }  // namespace vixl
844 
845 #endif  // VIXL_AARCH64_INSTRUCTIONS_AARCH64_H_
846