1 // Copyright 2015, ARM Limited
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_A64_INSTRUCTIONS_A64_H_
28 #define VIXL_A64_INSTRUCTIONS_A64_H_
29 
30 #include "jit/arm64/vixl/Constants-vixl.h"
31 #include "jit/arm64/vixl/Globals-vixl.h"
32 #include "jit/arm64/vixl/Utils-vixl.h"
33 
34 namespace vixl {
35 // ISA constants. --------------------------------------------------------------
36 
37 typedef uint32_t Instr;
38 const unsigned kInstructionSize = 4;
39 const unsigned kInstructionSizeLog2 = 2;
40 const unsigned kLiteralEntrySize = 4;
41 const unsigned kLiteralEntrySizeLog2 = 2;
42 const unsigned kMaxLoadLiteralRange = 1 * MBytes;
43 
44 // This is the nominal page size (as used by the adrp instruction); the actual
45 // size of the memory pages allocated by the kernel is likely to differ.
46 const unsigned kPageSize = 4 * KBytes;
47 const unsigned kPageSizeLog2 = 12;
48 
49 const unsigned kBRegSize = 8;
50 const unsigned kBRegSizeLog2 = 3;
51 const unsigned kBRegSizeInBytes = kBRegSize / 8;
52 const unsigned kBRegSizeInBytesLog2 = kBRegSizeLog2 - 3;
53 const unsigned kHRegSize = 16;
54 const unsigned kHRegSizeLog2 = 4;
55 const unsigned kHRegSizeInBytes = kHRegSize / 8;
56 const unsigned kHRegSizeInBytesLog2 = kHRegSizeLog2 - 3;
57 const unsigned kWRegSize = 32;
58 const unsigned kWRegSizeLog2 = 5;
59 const unsigned kWRegSizeInBytes = kWRegSize / 8;
60 const unsigned kWRegSizeInBytesLog2 = kWRegSizeLog2 - 3;
61 const unsigned kXRegSize = 64;
62 const unsigned kXRegSizeLog2 = 6;
63 const unsigned kXRegSizeInBytes = kXRegSize / 8;
64 const unsigned kXRegSizeInBytesLog2 = kXRegSizeLog2 - 3;
65 const unsigned kSRegSize = 32;
66 const unsigned kSRegSizeLog2 = 5;
67 const unsigned kSRegSizeInBytes = kSRegSize / 8;
68 const unsigned kSRegSizeInBytesLog2 = kSRegSizeLog2 - 3;
69 const unsigned kDRegSize = 64;
70 const unsigned kDRegSizeLog2 = 6;
71 const unsigned kDRegSizeInBytes = kDRegSize / 8;
72 const unsigned kDRegSizeInBytesLog2 = kDRegSizeLog2 - 3;
73 const unsigned kQRegSize = 128;
74 const unsigned kQRegSizeLog2 = 7;
75 const unsigned kQRegSizeInBytes = kQRegSize / 8;
76 const unsigned kQRegSizeInBytesLog2 = kQRegSizeLog2 - 3;
77 const uint64_t kWRegMask = UINT64_C(0xffffffff);
78 const uint64_t kXRegMask = UINT64_C(0xffffffffffffffff);
79 const uint64_t kSRegMask = UINT64_C(0xffffffff);
80 const uint64_t kDRegMask = UINT64_C(0xffffffffffffffff);
81 const uint64_t kSSignMask = UINT64_C(0x80000000);
82 const uint64_t kDSignMask = UINT64_C(0x8000000000000000);
83 const uint64_t kWSignMask = UINT64_C(0x80000000);
84 const uint64_t kXSignMask = UINT64_C(0x8000000000000000);
85 const uint64_t kByteMask = UINT64_C(0xff);
86 const uint64_t kHalfWordMask = UINT64_C(0xffff);
87 const uint64_t kWordMask = UINT64_C(0xffffffff);
88 const uint64_t kXMaxUInt = UINT64_C(0xffffffffffffffff);
89 const uint64_t kXMaxExactUInt = UINT64_C(0xfffffffffffff800);
90 const uint64_t kWMaxUInt = UINT64_C(0xffffffff);
91 const int64_t kXMaxInt = INT64_C(0x7fffffffffffffff);
92 const int64_t kXMaxExactInt = UINT64_C(0x7ffffffffffffc00);
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 kLinkRegCode = 30;
97 const unsigned kZeroRegCode = 31;
98 const unsigned kSPRegInternalCode = 63;
99 const unsigned kRegCodeMask = 0x1f;
100 
101 const unsigned kAddressTagOffset = 56;
102 const unsigned kAddressTagWidth = 8;
103 const uint64_t kAddressTagMask =
104     ((UINT64_C(1) << kAddressTagWidth) - 1) << kAddressTagOffset;
105 VIXL_STATIC_ASSERT(kAddressTagMask == UINT64_C(0xff00000000000000));
106 
107 unsigned CalcLSDataSize(LoadStoreOp op);
108 unsigned CalcLSPairDataSize(LoadStorePairOp op);
109 
110 enum ImmBranchType {
111   UnknownBranchType = 0,
112   CondBranchType    = 1,
113   UncondBranchType  = 2,
114   CompareBranchType = 3,
115   TestBranchType    = 4
116 };
117 
118 // The classes of immediate branch ranges, in order of increasing range.
119 // Note that CondBranchType and CompareBranchType have the same range.
120 enum ImmBranchRangeType {
121   TestBranchRangeType,   // tbz/tbnz: imm14 = +/- 32KB.
122   CondBranchRangeType,   // b.cond/cbz/cbnz: imm19 = +/- 1MB.
123   UncondBranchRangeType, // b/bl: imm26 = +/- 128MB.
124   UnknownBranchRangeType,
125 
126   // Number of 'short-range' branch range types.
127   // We don't consider unconditional branches 'short-range'.
128   NumShortBranchRangeTypes = UncondBranchRangeType
129 };
130 
131 enum AddrMode {
132   Offset,
133   PreIndex,
134   PostIndex
135 };
136 
137 enum Reg31Mode {
138   Reg31IsStackPointer,
139   Reg31IsZeroRegister
140 };
141 
142 // Instructions. ---------------------------------------------------------------
143 
144 class Instruction {
145  public:
InstructionBits()146   Instr InstructionBits() const {
147     return *(reinterpret_cast<const Instr*>(this));
148   }
149 
SetInstructionBits(Instr new_instr)150   void SetInstructionBits(Instr new_instr) {
151     *(reinterpret_cast<Instr*>(this)) = new_instr;
152   }
153 
Bit(int pos)154   int Bit(int pos) const {
155     return (InstructionBits() >> pos) & 1;
156   }
157 
Bits(int msb,int lsb)158   uint32_t Bits(int msb, int lsb) const {
159     return ExtractUnsignedBitfield32(msb, lsb, InstructionBits());
160   }
161 
SignedBits(int msb,int lsb)162   int32_t SignedBits(int msb, int lsb) const {
163     int32_t bits = *(reinterpret_cast<const int32_t*>(this));
164     return ExtractSignedBitfield32(msb, lsb, bits);
165   }
166 
Mask(uint32_t mask)167   Instr Mask(uint32_t mask) const {
168     return InstructionBits() & mask;
169   }
170 
171   #define DEFINE_GETTER(Name, HighBit, LowBit, Func)             \
172   int32_t Name() const { return Func(HighBit, LowBit); }
173   INSTRUCTION_FIELDS_LIST(DEFINE_GETTER)
174   #undef DEFINE_GETTER
175 
176   #define DEFINE_SETTER(Name, HighBit, LowBit, Func)             \
177   inline void Set##Name(unsigned n) { SetBits32(HighBit, LowBit, n); }
INSTRUCTION_FIELDS_LIST(DEFINE_SETTER)178   INSTRUCTION_FIELDS_LIST(DEFINE_SETTER)
179   #undef DEFINE_SETTER
180 
181   // ImmPCRel is a compound field (not present in INSTRUCTION_FIELDS_LIST),
182   // formed from ImmPCRelLo and ImmPCRelHi.
183   int ImmPCRel() const {
184     int offset =
185         static_cast<int>((ImmPCRelHi() << ImmPCRelLo_width) | ImmPCRelLo());
186     int width = ImmPCRelLo_width + ImmPCRelHi_width;
187     return ExtractSignedBitfield32(width - 1, 0, offset);
188   }
189 
190   uint64_t ImmLogical() const;
191   unsigned ImmNEONabcdefgh() const;
192   float ImmFP32() const;
193   double ImmFP64() const;
194   float ImmNEONFP32() const;
195   double ImmNEONFP64() const;
196 
SizeLS()197   unsigned SizeLS() const {
198     return CalcLSDataSize(static_cast<LoadStoreOp>(Mask(LoadStoreMask)));
199   }
200 
SizeLSPair()201   unsigned SizeLSPair() const {
202     return CalcLSPairDataSize(
203         static_cast<LoadStorePairOp>(Mask(LoadStorePairMask)));
204   }
205 
NEONLSIndex(int access_size_shift)206   int NEONLSIndex(int access_size_shift) const {
207     int64_t q = NEONQ();
208     int64_t s = NEONS();
209     int64_t size = NEONLSSize();
210     int64_t index = (q << 3) | (s << 2) | size;
211     return static_cast<int>(index >> access_size_shift);
212   }
213 
214   // Helpers.
IsCondBranchImm()215   bool IsCondBranchImm() const {
216     return Mask(ConditionalBranchFMask) == ConditionalBranchFixed;
217   }
218 
IsUncondBranchImm()219   bool IsUncondBranchImm() const {
220     return Mask(UnconditionalBranchFMask) == UnconditionalBranchFixed;
221   }
222 
IsCompareBranch()223   bool IsCompareBranch() const {
224     return Mask(CompareBranchFMask) == CompareBranchFixed;
225   }
226 
IsTestBranch()227   bool IsTestBranch() const {
228     return Mask(TestBranchFMask) == TestBranchFixed;
229   }
230 
IsImmBranch()231   bool IsImmBranch() const {
232     return BranchType() != UnknownBranchType;
233   }
234 
IsPCRelAddressing()235   bool IsPCRelAddressing() const {
236     return Mask(PCRelAddressingFMask) == PCRelAddressingFixed;
237   }
238 
IsLogicalImmediate()239   bool IsLogicalImmediate() const {
240     return Mask(LogicalImmediateFMask) == LogicalImmediateFixed;
241   }
242 
IsAddSubImmediate()243   bool IsAddSubImmediate() const {
244     return Mask(AddSubImmediateFMask) == AddSubImmediateFixed;
245   }
246 
IsAddSubExtended()247   bool IsAddSubExtended() const {
248     return Mask(AddSubExtendedFMask) == AddSubExtendedFixed;
249   }
250 
IsLoadOrStore()251   bool IsLoadOrStore() const {
252     return Mask(LoadStoreAnyFMask) == LoadStoreAnyFixed;
253   }
254 
255   bool IsLoad() const;
256   bool IsStore() const;
257 
IsLoadLiteral()258   bool IsLoadLiteral() const {
259     // This includes PRFM_lit.
260     return Mask(LoadLiteralFMask) == LoadLiteralFixed;
261   }
262 
IsMovn()263   bool IsMovn() const {
264     return (Mask(MoveWideImmediateMask) == MOVN_x) ||
265            (Mask(MoveWideImmediateMask) == MOVN_w);
266   }
267 
268   // Mozilla modifications.
269   bool IsUncondB() const;
270   bool IsCondB() const;
271   bool IsBL() const;
272   bool IsBR() const;
273   bool IsBLR() const;
274   bool IsTBZ() const;
275   bool IsTBNZ() const;
276   bool IsCBZ() const;
277   bool IsCBNZ() const;
278   bool IsLDR() const;
279   bool IsNOP() const;
280   bool IsCSDB() const;
281   bool IsADR() const;
282   bool IsADRP() const;
283   bool IsMovz() const;
284   bool IsMovk() const;
285   bool IsBranchLinkImm() const;
286   bool IsTargetReachable(const Instruction* target) const;
287   ptrdiff_t ImmPCRawOffset() const;
288   void SetImmPCRawOffset(ptrdiff_t offset);
289   void SetBits32(int msb, int lsb, unsigned value);
290 
291   // Is this a stack pointer synchronization instruction as inserted by
292   // MacroAssembler::syncStackPtr()?
293   bool IsStackPtrSync() const;
294 
295   static int ImmBranchRangeBitwidth(ImmBranchType branch_type);
296   static int32_t ImmBranchForwardRange(ImmBranchType branch_type);
297 
298   // Check if offset can be encoded as a RAW offset in a branch_type
299   // instruction. The offset must be encodeable directly as the immediate field
300   // in the instruction, it is not scaled by kInstructionSize first.
301   static bool IsValidImmPCOffset(ImmBranchType branch_type, int64_t offset);
302 
303   // Get the range type corresponding to a branch type.
304   static ImmBranchRangeType ImmBranchTypeToRange(ImmBranchType);
305 
306   // Get the maximum realizable forward PC offset (in bytes) for an immediate
307   // branch of the given range type.
308   // This is the largest positive multiple of kInstructionSize, offset, such
309   // that:
310   //
311   //    IsValidImmPCOffset(xxx, offset / kInstructionSize)
312   //
313   // returns true for the same branch type.
314   static int32_t ImmBranchMaxForwardOffset(ImmBranchRangeType range_type);
315 
316   // Get the minimuum realizable backward PC offset (in bytes) for an immediate
317   // branch of the given range type.
318   // This is the smallest (i.e., largest in magnitude) negative multiple of
319   // kInstructionSize, offset, such that:
320   //
321   //    IsValidImmPCOffset(xxx, offset / kInstructionSize)
322   //
323   // returns true for the same branch type.
324   static int32_t ImmBranchMinBackwardOffset(ImmBranchRangeType range_type);
325 
326   // Indicate whether Rd can be the stack pointer or the zero register. This
327   // does not check that the instruction actually has an Rd field.
RdMode()328   Reg31Mode RdMode() const {
329     // The following instructions use sp or wsp as Rd:
330     //  Add/sub (immediate) when not setting the flags.
331     //  Add/sub (extended) when not setting the flags.
332     //  Logical (immediate) when not setting the flags.
333     // Otherwise, r31 is the zero register.
334     if (IsAddSubImmediate() || IsAddSubExtended()) {
335       if (Mask(AddSubSetFlagsBit)) {
336         return Reg31IsZeroRegister;
337       } else {
338         return Reg31IsStackPointer;
339       }
340     }
341     if (IsLogicalImmediate()) {
342       // Of the logical (immediate) instructions, only ANDS (and its aliases)
343       // can set the flags. The others can all write into sp.
344       // Note that some logical operations are not available to
345       // immediate-operand instructions, so we have to combine two masks here.
346       if (Mask(LogicalImmediateMask & LogicalOpMask) == ANDS) {
347         return Reg31IsZeroRegister;
348       } else {
349         return Reg31IsStackPointer;
350       }
351     }
352     return Reg31IsZeroRegister;
353   }
354 
355   // Indicate whether Rn can be the stack pointer or the zero register. This
356   // does not check that the instruction actually has an Rn field.
RnMode()357   Reg31Mode RnMode() const {
358     // The following instructions use sp or wsp as Rn:
359     //  All loads and stores.
360     //  Add/sub (immediate).
361     //  Add/sub (extended).
362     // Otherwise, r31 is the zero register.
363     if (IsLoadOrStore() || IsAddSubImmediate() || IsAddSubExtended()) {
364       return Reg31IsStackPointer;
365     }
366     return Reg31IsZeroRegister;
367   }
368 
BranchType()369   ImmBranchType BranchType() const {
370     if (IsCondBranchImm()) {
371       return CondBranchType;
372     } else if (IsUncondBranchImm()) {
373       return UncondBranchType;
374     } else if (IsCompareBranch()) {
375       return CompareBranchType;
376     } else if (IsTestBranch()) {
377       return TestBranchType;
378     } else {
379       return UnknownBranchType;
380     }
381   }
382 
383   // Find the target of this instruction. 'this' may be a branch or a
384   // PC-relative addressing instruction.
385   const Instruction* ImmPCOffsetTarget() const;
386 
387   // Patch a PC-relative offset to refer to 'target'. 'this' may be a branch or
388   // a PC-relative addressing instruction.
389   void SetImmPCOffsetTarget(const Instruction* target);
390   // Patch a literal load instruction to load from 'source'.
391   void SetImmLLiteral(const Instruction* source);
392 
393   // The range of a load literal instruction, expressed as 'instr +- range'.
394   // The range is actually the 'positive' range; the branch instruction can
395   // target [instr - range - kInstructionSize, instr + range].
396   static const int kLoadLiteralImmBitwidth = 19;
397   static const int kLoadLiteralRange =
398       (1 << kLoadLiteralImmBitwidth) / 2 - kInstructionSize;
399 
400   // Calculate the address of a literal referred to by a load-literal
401   // instruction, and return it as the specified type.
402   //
403   // The literal itself is safely mutable only if the backing buffer is safely
404   // mutable.
405   template <typename T>
LiteralAddress()406   T LiteralAddress() const {
407     uint64_t base_raw = reinterpret_cast<uint64_t>(this);
408     int64_t offset = ImmLLiteral() << kLiteralEntrySizeLog2;
409     uint64_t address_raw = base_raw + offset;
410 
411     // Cast the address using a C-style cast. A reinterpret_cast would be
412     // appropriate, but it can't cast one integral type to another.
413     T address = (T)(address_raw);
414 
415     // Assert that the address can be represented by the specified type.
416     VIXL_ASSERT((uint64_t)(address) == address_raw);
417 
418     return address;
419   }
420 
Literal32()421   uint32_t Literal32() const {
422     uint32_t literal;
423     memcpy(&literal, LiteralAddress<const void*>(), sizeof(literal));
424     return literal;
425   }
426 
Literal64()427   uint64_t Literal64() const {
428     uint64_t literal;
429     memcpy(&literal, LiteralAddress<const void*>(), sizeof(literal));
430     return literal;
431   }
432 
SetLiteral64(uint64_t literal)433   void SetLiteral64(uint64_t literal) const {
434     memcpy(LiteralAddress<void*>(), &literal, sizeof(literal));
435   }
436 
LiteralFP32()437   float LiteralFP32() const {
438     return RawbitsToFloat(Literal32());
439   }
440 
LiteralFP64()441   double LiteralFP64() const {
442     return RawbitsToDouble(Literal64());
443   }
444 
NextInstruction()445   const Instruction* NextInstruction() const {
446     return this + kInstructionSize;
447   }
448 
449   // Skip any constant pools with artificial guards at this point.
450   // Return either |this| or the first instruction after the pool.
451   const Instruction* skipPool() const;
452 
InstructionAtOffset(int64_t offset)453   const Instruction* InstructionAtOffset(int64_t offset) const {
454     VIXL_ASSERT(IsWordAligned(this + offset));
455     return this + offset;
456   }
457 
Cast(T src)458   template<typename T> static Instruction* Cast(T src) {
459     return reinterpret_cast<Instruction*>(src);
460   }
461 
CastConst(T src)462   template<typename T> static const Instruction* CastConst(T src) {
463     return reinterpret_cast<const Instruction*>(src);
464   }
465 
466  private:
467   int ImmBranch() const;
468 
469   static float Imm8ToFP32(uint32_t imm8);
470   static double Imm8ToFP64(uint32_t imm8);
471 
472   void SetPCRelImmTarget(const Instruction* target);
473   void SetBranchImmTarget(const Instruction* target);
474 };
475 
476 
477 // Functions for handling NEON vector format information.
478 enum VectorFormat {
479   kFormatUndefined = 0xffffffff,
480   kFormat8B  = NEON_8B,
481   kFormat16B = NEON_16B,
482   kFormat4H  = NEON_4H,
483   kFormat8H  = NEON_8H,
484   kFormat2S  = NEON_2S,
485   kFormat4S  = NEON_4S,
486   kFormat1D  = NEON_1D,
487   kFormat2D  = NEON_2D,
488 
489   // Scalar formats. We add the scalar bit to distinguish between scalar and
490   // vector enumerations; the bit is always set in the encoding of scalar ops
491   // and always clear for vector ops. Although kFormatD and kFormat1D appear
492   // to be the same, their meaning is subtly different. The first is a scalar
493   // operation, the second a vector operation that only affects one lane.
494   kFormatB = NEON_B | NEONScalar,
495   kFormatH = NEON_H | NEONScalar,
496   kFormatS = NEON_S | NEONScalar,
497   kFormatD = NEON_D | NEONScalar
498 };
499 
500 VectorFormat VectorFormatHalfWidth(const VectorFormat vform);
501 VectorFormat VectorFormatDoubleWidth(const VectorFormat vform);
502 VectorFormat VectorFormatDoubleLanes(const VectorFormat vform);
503 VectorFormat VectorFormatHalfLanes(const VectorFormat vform);
504 VectorFormat ScalarFormatFromLaneSize(int lanesize);
505 VectorFormat VectorFormatHalfWidthDoubleLanes(const VectorFormat vform);
506 VectorFormat VectorFormatFillQ(const VectorFormat vform);
507 unsigned RegisterSizeInBitsFromFormat(VectorFormat vform);
508 unsigned RegisterSizeInBytesFromFormat(VectorFormat vform);
509 // TODO: Make the return types of these functions consistent.
510 unsigned LaneSizeInBitsFromFormat(VectorFormat vform);
511 int LaneSizeInBytesFromFormat(VectorFormat vform);
512 int LaneSizeInBytesLog2FromFormat(VectorFormat vform);
513 int LaneCountFromFormat(VectorFormat vform);
514 int MaxLaneCountFromFormat(VectorFormat vform);
515 bool IsVectorFormat(VectorFormat vform);
516 int64_t MaxIntFromFormat(VectorFormat vform);
517 int64_t MinIntFromFormat(VectorFormat vform);
518 uint64_t MaxUintFromFormat(VectorFormat vform);
519 
520 
521 enum NEONFormat {
522   NF_UNDEF = 0,
523   NF_8B    = 1,
524   NF_16B   = 2,
525   NF_4H    = 3,
526   NF_8H    = 4,
527   NF_2S    = 5,
528   NF_4S    = 6,
529   NF_1D    = 7,
530   NF_2D    = 8,
531   NF_B     = 9,
532   NF_H     = 10,
533   NF_S     = 11,
534   NF_D     = 12
535 };
536 
537 static const unsigned kNEONFormatMaxBits = 6;
538 
539 struct NEONFormatMap {
540   // The bit positions in the instruction to consider.
541   uint8_t bits[kNEONFormatMaxBits];
542 
543   // Mapping from concatenated bits to format.
544   NEONFormat map[1 << kNEONFormatMaxBits];
545 };
546 
547 class NEONFormatDecoder {
548  public:
549   enum SubstitutionMode {
550     kPlaceholder,
551     kFormat
552   };
553 
554   // Construct a format decoder with increasingly specific format maps for each
555   // subsitution. If no format map is specified, the default is the integer
556   // format map.
NEONFormatDecoder(const Instruction * instr)557   explicit NEONFormatDecoder(const Instruction* instr) {
558     instrbits_ = instr->InstructionBits();
559     SetFormatMaps(IntegerFormatMap());
560   }
NEONFormatDecoder(const Instruction * instr,const NEONFormatMap * format)561   NEONFormatDecoder(const Instruction* instr,
562                     const NEONFormatMap* format) {
563     instrbits_ = instr->InstructionBits();
564     SetFormatMaps(format);
565   }
NEONFormatDecoder(const Instruction * instr,const NEONFormatMap * format0,const NEONFormatMap * format1)566   NEONFormatDecoder(const Instruction* instr,
567                     const NEONFormatMap* format0,
568                     const NEONFormatMap* format1) {
569     instrbits_ = instr->InstructionBits();
570     SetFormatMaps(format0, format1);
571   }
NEONFormatDecoder(const Instruction * instr,const NEONFormatMap * format0,const NEONFormatMap * format1,const NEONFormatMap * format2)572   NEONFormatDecoder(const Instruction* instr,
573                     const NEONFormatMap* format0,
574                     const NEONFormatMap* format1,
575                     const NEONFormatMap* format2) {
576     instrbits_ = instr->InstructionBits();
577     SetFormatMaps(format0, format1, format2);
578   }
579 
580   // Set the format mapping for all or individual substitutions.
581   void SetFormatMaps(const NEONFormatMap* format0,
582                      const NEONFormatMap* format1 = NULL,
583                      const NEONFormatMap* format2 = NULL) {
584     VIXL_ASSERT(format0 != NULL);
585     formats_[0] = format0;
586     formats_[1] = (format1 == NULL) ? formats_[0] : format1;
587     formats_[2] = (format2 == NULL) ? formats_[1] : format2;
588   }
SetFormatMap(unsigned index,const NEONFormatMap * format)589   void SetFormatMap(unsigned index, const NEONFormatMap* format) {
590     VIXL_ASSERT(index <= (sizeof(formats_) / sizeof(formats_[0])));
591     VIXL_ASSERT(format != NULL);
592     formats_[index] = format;
593   }
594 
595   // Substitute %s in the input string with the placeholder string for each
596   // register, ie. "'B", "'H", etc.
SubstitutePlaceholders(const char * string)597   const char* SubstitutePlaceholders(const char* string) {
598     return Substitute(string, kPlaceholder, kPlaceholder, kPlaceholder);
599   }
600 
601   // Substitute %s in the input string with a new string based on the
602   // substitution mode.
603   const char* Substitute(const char* string,
604                          SubstitutionMode mode0 = kFormat,
605                          SubstitutionMode mode1 = kFormat,
606                          SubstitutionMode mode2 = kFormat) {
607     snprintf(form_buffer_, sizeof(form_buffer_), string,
608              GetSubstitute(0, mode0),
609              GetSubstitute(1, mode1),
610              GetSubstitute(2, mode2));
611     return form_buffer_;
612   }
613 
614   // Append a "2" to a mnemonic string based of the state of the Q bit.
Mnemonic(const char * mnemonic)615   const char* Mnemonic(const char* mnemonic) {
616     if ((instrbits_ & NEON_Q) != 0) {
617       snprintf(mne_buffer_, sizeof(mne_buffer_), "%s2", mnemonic);
618       return mne_buffer_;
619     }
620     return mnemonic;
621   }
622 
623   VectorFormat GetVectorFormat(int format_index = 0) {
624     return GetVectorFormat(formats_[format_index]);
625   }
626 
GetVectorFormat(const NEONFormatMap * format_map)627   VectorFormat GetVectorFormat(const NEONFormatMap* format_map) {
628     static const VectorFormat vform[] = {
629       kFormatUndefined,
630       kFormat8B, kFormat16B, kFormat4H, kFormat8H,
631       kFormat2S, kFormat4S, kFormat1D, kFormat2D,
632       kFormatB, kFormatH, kFormatS, kFormatD
633     };
634     VIXL_ASSERT(GetNEONFormat(format_map) < (sizeof(vform) / sizeof(vform[0])));
635     return vform[GetNEONFormat(format_map)];
636   }
637 
638   // Built in mappings for common cases.
639 
640   // The integer format map uses three bits (Q, size<1:0>) to encode the
641   // "standard" set of NEON integer vector formats.
IntegerFormatMap()642   static const NEONFormatMap* IntegerFormatMap() {
643     static const NEONFormatMap map = {
644       {23, 22, 30},
645       {NF_8B, NF_16B, NF_4H, NF_8H, NF_2S, NF_4S, NF_UNDEF, NF_2D}
646     };
647     return &map;
648   }
649 
650   // The long integer format map uses two bits (size<1:0>) to encode the
651   // long set of NEON integer vector formats. These are used in narrow, wide
652   // and long operations.
LongIntegerFormatMap()653   static const NEONFormatMap* LongIntegerFormatMap() {
654     static const NEONFormatMap map = {
655       {23, 22}, {NF_8H, NF_4S, NF_2D}
656     };
657     return &map;
658   }
659 
660   // The FP format map uses two bits (Q, size<0>) to encode the NEON FP vector
661   // formats: NF_2S, NF_4S, NF_2D.
FPFormatMap()662   static const NEONFormatMap* FPFormatMap() {
663     // The FP format map assumes two bits (Q, size<0>) are used to encode the
664     // NEON FP vector formats: NF_2S, NF_4S, NF_2D.
665     static const NEONFormatMap map = {
666       {22, 30}, {NF_2S, NF_4S, NF_UNDEF, NF_2D}
667     };
668     return &map;
669   }
670 
671   // The load/store format map uses three bits (Q, 11, 10) to encode the
672   // set of NEON vector formats.
LoadStoreFormatMap()673   static const NEONFormatMap* LoadStoreFormatMap() {
674     static const NEONFormatMap map = {
675       {11, 10, 30},
676       {NF_8B, NF_16B, NF_4H, NF_8H, NF_2S, NF_4S, NF_1D, NF_2D}
677     };
678     return &map;
679   }
680 
681   // The logical format map uses one bit (Q) to encode the NEON vector format:
682   // NF_8B, NF_16B.
LogicalFormatMap()683   static const NEONFormatMap* LogicalFormatMap() {
684     static const NEONFormatMap map = {
685       {30}, {NF_8B, NF_16B}
686     };
687     return &map;
688   }
689 
690   // The triangular format map uses between two and five bits to encode the NEON
691   // vector format:
692   // xxx10->8B, xxx11->16B, xx100->4H, xx101->8H
693   // x1000->2S, x1001->4S,  10001->2D, all others undefined.
TriangularFormatMap()694   static const NEONFormatMap* TriangularFormatMap() {
695     static const NEONFormatMap map = {
696       {19, 18, 17, 16, 30},
697       {NF_UNDEF, NF_UNDEF, NF_8B, NF_16B, NF_4H, NF_8H, NF_8B, NF_16B, NF_2S,
698        NF_4S, NF_8B, NF_16B, NF_4H, NF_8H, NF_8B, NF_16B, NF_UNDEF, NF_2D,
699        NF_8B, NF_16B, NF_4H, NF_8H, NF_8B, NF_16B, NF_2S, NF_4S, NF_8B, NF_16B,
700        NF_4H, NF_8H, NF_8B, NF_16B}
701     };
702     return &map;
703   }
704 
705   // The scalar format map uses two bits (size<1:0>) to encode the NEON scalar
706   // formats: NF_B, NF_H, NF_S, NF_D.
ScalarFormatMap()707   static const NEONFormatMap* ScalarFormatMap() {
708     static const NEONFormatMap map = {
709       {23, 22}, {NF_B, NF_H, NF_S, NF_D}
710     };
711     return &map;
712   }
713 
714   // The long scalar format map uses two bits (size<1:0>) to encode the longer
715   // NEON scalar formats: NF_H, NF_S, NF_D.
LongScalarFormatMap()716   static const NEONFormatMap* LongScalarFormatMap() {
717     static const NEONFormatMap map = {
718       {23, 22}, {NF_H, NF_S, NF_D}
719     };
720     return &map;
721   }
722 
723   // The FP scalar format map assumes one bit (size<0>) is used to encode the
724   // NEON FP scalar formats: NF_S, NF_D.
FPScalarFormatMap()725   static const NEONFormatMap* FPScalarFormatMap() {
726     static const NEONFormatMap map = {
727       {22}, {NF_S, NF_D}
728     };
729     return &map;
730   }
731 
732   // The triangular scalar format map uses between one and four bits to encode
733   // the NEON FP scalar formats:
734   // xxx1->B, xx10->H, x100->S, 1000->D, all others undefined.
TriangularScalarFormatMap()735   static const NEONFormatMap* TriangularScalarFormatMap() {
736     static const NEONFormatMap map = {
737       {19, 18, 17, 16},
738       {NF_UNDEF, NF_B, NF_H, NF_B, NF_S, NF_B, NF_H, NF_B,
739        NF_D,     NF_B, NF_H, NF_B, NF_S, NF_B, NF_H, NF_B}
740     };
741     return &map;
742   }
743 
744  private:
745   // Get a pointer to a string that represents the format or placeholder for
746   // the specified substitution index, based on the format map and instruction.
GetSubstitute(int index,SubstitutionMode mode)747   const char* GetSubstitute(int index, SubstitutionMode mode) {
748     if (mode == kFormat) {
749       return NEONFormatAsString(GetNEONFormat(formats_[index]));
750     }
751     VIXL_ASSERT(mode == kPlaceholder);
752     return NEONFormatAsPlaceholder(GetNEONFormat(formats_[index]));
753   }
754 
755   // Get the NEONFormat enumerated value for bits obtained from the
756   // instruction based on the specified format mapping.
GetNEONFormat(const NEONFormatMap * format_map)757   NEONFormat GetNEONFormat(const NEONFormatMap* format_map) {
758     return format_map->map[PickBits(format_map->bits)];
759   }
760 
761   // Convert a NEONFormat into a string.
NEONFormatAsString(NEONFormat format)762   static const char* NEONFormatAsString(NEONFormat format) {
763     static const char* formats[] = {
764       "undefined",
765       "8b", "16b", "4h", "8h", "2s", "4s", "1d", "2d",
766       "b", "h", "s", "d"
767     };
768     VIXL_ASSERT(format < (sizeof(formats) / sizeof(formats[0])));
769     return formats[format];
770   }
771 
772   // Convert a NEONFormat into a register placeholder string.
NEONFormatAsPlaceholder(NEONFormat format)773   static const char* NEONFormatAsPlaceholder(NEONFormat format) {
774     VIXL_ASSERT((format == NF_B) || (format == NF_H) ||
775                 (format == NF_S) || (format == NF_D) ||
776                 (format == NF_UNDEF));
777     static const char* formats[] = {
778       "undefined",
779       "undefined", "undefined", "undefined", "undefined",
780       "undefined", "undefined", "undefined", "undefined",
781       "'B", "'H", "'S", "'D"
782     };
783     return formats[format];
784   }
785 
786   // Select bits from instrbits_ defined by the bits array, concatenate them,
787   // and return the value.
PickBits(const uint8_t bits[])788   uint8_t PickBits(const uint8_t bits[]) {
789     uint8_t result = 0;
790     for (unsigned b = 0; b < kNEONFormatMaxBits; b++) {
791       if (bits[b] == 0) break;
792       result <<= 1;
793       result |= ((instrbits_ & (1 << bits[b])) == 0) ? 0 : 1;
794     }
795     return result;
796   }
797 
798   Instr instrbits_;
799   const NEONFormatMap* formats_[3];
800   char form_buffer_[64];
801   char mne_buffer_[16];
802 };
803 }  // namespace vixl
804 
805 #endif  // VIXL_A64_INSTRUCTIONS_A64_H_
806