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 "vixl/globals.h" |
31 | #include "vixl/utils.h" |
32 | #include "vixl/a64/constants-a64.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 kWMaxUInt = UINT64_C(0xffffffff); |
90 | const int64_t kXMaxInt = INT64_C(0x7fffffffffffffff); |
91 | const int64_t kXMinInt = INT64_C(0x8000000000000000); |
92 | const int32_t kWMaxInt = INT32_C(0x7fffffff); |
93 | const int32_t kWMinInt = INT32_C(0x80000000); |
94 | const unsigned kLinkRegCode = 30; |
95 | const unsigned kZeroRegCode = 31; |
96 | const unsigned kSPRegInternalCode = 63; |
97 | const unsigned kRegCodeMask = 0x1f; |
98 | |
99 | const unsigned kAddressTagOffset = 56; |
100 | const unsigned kAddressTagWidth = 8; |
101 | const uint64_t kAddressTagMask = |
102 | ((UINT64_C(1) << kAddressTagWidth) - 1) << kAddressTagOffset; |
103 | VIXL_STATIC_ASSERT(kAddressTagMask == UINT64_C(0xff00000000000000)); |
104 | |
105 | // AArch64 floating-point specifics. These match IEEE-754. |
106 | const unsigned kDoubleMantissaBits = 52; |
107 | const unsigned kDoubleExponentBits = 11; |
108 | const unsigned kFloatMantissaBits = 23; |
109 | const unsigned kFloatExponentBits = 8; |
110 | const unsigned kFloat16MantissaBits = 10; |
111 | const unsigned kFloat16ExponentBits = 5; |
112 | |
113 | // Floating-point infinity values. |
114 | extern const float16 kFP16PositiveInfinity; |
115 | extern const float16 kFP16NegativeInfinity; |
116 | extern const float kFP32PositiveInfinity; |
117 | extern const float kFP32NegativeInfinity; |
118 | extern const double kFP64PositiveInfinity; |
119 | extern const double kFP64NegativeInfinity; |
120 | |
121 | // The default NaN values (for FPCR.DN=1). |
122 | extern const float16 kFP16DefaultNaN; |
123 | extern const float kFP32DefaultNaN; |
124 | extern const double kFP64DefaultNaN; |
125 | |
126 | unsigned CalcLSDataSize(LoadStoreOp op); |
127 | unsigned CalcLSPairDataSize(LoadStorePairOp op); |
128 | |
129 | enum ImmBranchType { |
130 | UnknownBranchType = 0, |
131 | CondBranchType = 1, |
132 | UncondBranchType = 2, |
133 | CompareBranchType = 3, |
134 | TestBranchType = 4 |
135 | }; |
136 | |
137 | enum AddrMode { |
138 | Offset, |
139 | PreIndex, |
140 | PostIndex |
141 | }; |
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 { |
157 | Reg31IsStackPointer, |
158 | Reg31IsZeroRegister |
159 | }; |
160 | |
161 | // Instructions. --------------------------------------------------------------- |
162 | |
163 | class Instruction { |
164 | public: |
165 | Instr InstructionBits() const { |
166 | return *(reinterpret_cast<const Instr*>(this)); |
167 | } |
168 | |
169 | void SetInstructionBits(Instr new_instr) { |
170 | *(reinterpret_cast<Instr*>(this)) = new_instr; |
171 | } |
172 | |
173 | int Bit(int pos) const { |
174 | return (InstructionBits() >> pos) & 1; |
175 | } |
176 | |
177 | uint32_t Bits(int msb, int lsb) const { |
178 | return unsigned_bitextract_32(msb, lsb, InstructionBits()); |
179 | } |
180 | |
181 | int32_t SignedBits(int msb, int lsb) const { |
182 | int32_t bits = *(reinterpret_cast<const int32_t*>(this)); |
183 | return signed_bitextract_32(msb, lsb, bits); |
184 | } |
185 | |
186 | Instr Mask(uint32_t mask) const { |
187 | return InstructionBits() & mask; |
188 | } |
189 | |
190 | #define DEFINE_GETTER(Name, HighBit, LowBit, Func) \ |
191 | int32_t Name() const { return Func(HighBit, LowBit); } |
192 | INSTRUCTION_FIELDS_LIST(DEFINE_GETTER) |
193 | #undef DEFINE_GETTER |
194 | |
195 | // ImmPCRel is a compound field (not present in INSTRUCTION_FIELDS_LIST), |
196 | // formed from ImmPCRelLo and ImmPCRelHi. |
197 | int ImmPCRel() const { |
198 | int offset = |
199 | static_cast<int>((ImmPCRelHi() << ImmPCRelLo_width) | ImmPCRelLo()); |
200 | int width = ImmPCRelLo_width + ImmPCRelHi_width; |
201 | return signed_bitextract_32(width - 1, 0, offset); |
202 | } |
203 | |
204 | uint64_t ImmLogical() const; |
205 | unsigned ImmNEONabcdefgh() const; |
206 | float ImmFP32() const; |
207 | double ImmFP64() const; |
208 | float ImmNEONFP32() const; |
209 | double ImmNEONFP64() const; |
210 | |
211 | unsigned SizeLS() const { |
212 | return CalcLSDataSize(static_cast<LoadStoreOp>(Mask(LoadStoreMask))); |
213 | } |
214 | |
215 | unsigned SizeLSPair() const { |
216 | return CalcLSPairDataSize( |
217 | static_cast<LoadStorePairOp>(Mask(LoadStorePairMask))); |
218 | } |
219 | |
220 | int NEONLSIndex(int access_size_shift) const { |
221 | int64_t q = NEONQ(); |
222 | int64_t s = NEONS(); |
223 | int64_t size = NEONLSSize(); |
224 | int64_t index = (q << 3) | (s << 2) | size; |
225 | return static_cast<int>(index >> access_size_shift); |
226 | } |
227 | |
228 | // Helpers. |
229 | bool IsCondBranchImm() const { |
230 | return Mask(ConditionalBranchFMask) == ConditionalBranchFixed; |
231 | } |
232 | |
233 | bool IsUncondBranchImm() const { |
234 | return Mask(UnconditionalBranchFMask) == UnconditionalBranchFixed; |
235 | } |
236 | |
237 | bool IsCompareBranch() const { |
238 | return Mask(CompareBranchFMask) == CompareBranchFixed; |
239 | } |
240 | |
241 | bool IsTestBranch() const { |
242 | return Mask(TestBranchFMask) == TestBranchFixed; |
243 | } |
244 | |
245 | bool IsImmBranch() const { |
246 | return BranchType() != UnknownBranchType; |
247 | } |
248 | |
249 | bool IsPCRelAddressing() const { |
250 | return Mask(PCRelAddressingFMask) == PCRelAddressingFixed; |
251 | } |
252 | |
253 | bool IsLogicalImmediate() const { |
254 | return Mask(LogicalImmediateFMask) == LogicalImmediateFixed; |
255 | } |
256 | |
257 | bool IsAddSubImmediate() const { |
258 | return Mask(AddSubImmediateFMask) == AddSubImmediateFixed; |
259 | } |
260 | |
261 | bool IsAddSubExtended() const { |
262 | return Mask(AddSubExtendedFMask) == AddSubExtendedFixed; |
263 | } |
264 | |
265 | bool IsLoadOrStore() const { |
266 | return Mask(LoadStoreAnyFMask) == LoadStoreAnyFixed; |
267 | } |
268 | |
269 | bool IsLoad() const; |
270 | bool IsStore() const; |
271 | |
272 | bool IsLoadLiteral() const { |
273 | // This includes PRFM_lit. |
274 | return Mask(LoadLiteralFMask) == LoadLiteralFixed; |
275 | } |
276 | |
277 | bool IsMovn() const { |
278 | return (Mask(MoveWideImmediateMask) == MOVN_x) || |
279 | (Mask(MoveWideImmediateMask) == MOVN_w); |
280 | } |
281 | |
282 | static int ImmBranchRangeBitwidth(ImmBranchType branch_type); |
283 | static int32_t ImmBranchForwardRange(ImmBranchType branch_type); |
284 | static bool IsValidImmPCOffset(ImmBranchType branch_type, int64_t offset); |
285 | |
286 | // Indicate whether Rd can be the stack pointer or the zero register. This |
287 | // does not check that the instruction actually has an Rd field. |
288 | Reg31Mode RdMode() const { |
289 | // The following instructions use sp or wsp as Rd: |
290 | // Add/sub (immediate) when not setting the flags. |
291 | // Add/sub (extended) when not setting the flags. |
292 | // Logical (immediate) when not setting the flags. |
293 | // Otherwise, r31 is the zero register. |
294 | if (IsAddSubImmediate() || IsAddSubExtended()) { |
295 | if (Mask(AddSubSetFlagsBit)) { |
296 | return Reg31IsZeroRegister; |
297 | } else { |
298 | return Reg31IsStackPointer; |
299 | } |
300 | } |
301 | if (IsLogicalImmediate()) { |
302 | // Of the logical (immediate) instructions, only ANDS (and its aliases) |
303 | // can set the flags. The others can all write into sp. |
304 | // Note that some logical operations are not available to |
305 | // immediate-operand instructions, so we have to combine two masks here. |
306 | if (Mask(LogicalImmediateMask & LogicalOpMask) == ANDS) { |
307 | return Reg31IsZeroRegister; |
308 | } else { |
309 | return Reg31IsStackPointer; |
310 | } |
311 | } |
312 | return Reg31IsZeroRegister; |
313 | } |
314 | |
315 | // Indicate whether Rn can be the stack pointer or the zero register. This |
316 | // does not check that the instruction actually has an Rn field. |
317 | Reg31Mode RnMode() const { |
318 | // The following instructions use sp or wsp as Rn: |
319 | // All loads and stores. |
320 | // Add/sub (immediate). |
321 | // Add/sub (extended). |
322 | // Otherwise, r31 is the zero register. |
323 | if (IsLoadOrStore() || IsAddSubImmediate() || IsAddSubExtended()) { |
324 | return Reg31IsStackPointer; |
325 | } |
326 | return Reg31IsZeroRegister; |
327 | } |
328 | |
329 | ImmBranchType BranchType() const { |
330 | if (IsCondBranchImm()) { |
331 | return CondBranchType; |
332 | } else if (IsUncondBranchImm()) { |
333 | return UncondBranchType; |
334 | } else if (IsCompareBranch()) { |
335 | return CompareBranchType; |
336 | } else if (IsTestBranch()) { |
337 | return TestBranchType; |
338 | } else { |
339 | return UnknownBranchType; |
340 | } |
341 | } |
342 | |
343 | // Find the target of this instruction. 'this' may be a branch or a |
344 | // PC-relative addressing instruction. |
345 | const Instruction* ImmPCOffsetTarget() const; |
346 | |
347 | // Patch a PC-relative offset to refer to 'target'. 'this' may be a branch or |
348 | // a PC-relative addressing instruction. |
349 | void SetImmPCOffsetTarget(const Instruction* target); |
350 | // Patch a literal load instruction to load from 'source'. |
351 | void SetImmLLiteral(const Instruction* source); |
352 | |
353 | // The range of a load literal instruction, expressed as 'instr +- range'. |
354 | // The range is actually the 'positive' range; the branch instruction can |
355 | // target [instr - range - kInstructionSize, instr + range]. |
356 | static const int kLoadLiteralImmBitwidth = 19; |
357 | static const int kLoadLiteralRange = |
358 | (1 << kLoadLiteralImmBitwidth) / 2 - kInstructionSize; |
359 | |
360 | // Calculate the address of a literal referred to by a load-literal |
361 | // instruction, and return it as the specified type. |
362 | // |
363 | // The literal itself is safely mutable only if the backing buffer is safely |
364 | // mutable. |
365 | template <typename T> |
366 | T LiteralAddress() const { |
367 | uint64_t base_raw = reinterpret_cast<uint64_t>(this); |
368 | int64_t offset = ImmLLiteral() << kLiteralEntrySizeLog2; |
369 | uint64_t address_raw = base_raw + offset; |
370 | |
371 | // Cast the address using a C-style cast. A reinterpret_cast would be |
372 | // appropriate, but it can't cast one integral type to another. |
373 | T address = (T)(address_raw); |
374 | |
375 | // Assert that the address can be represented by the specified type. |
376 | VIXL_ASSERT((uint64_t)(address) == address_raw); |
377 | |
378 | return address; |
379 | } |
380 | |
381 | uint32_t Literal32() const { |
382 | uint32_t literal; |
383 | memcpy(&literal, LiteralAddress<const void*>(), sizeof(literal)); |
384 | return literal; |
385 | } |
386 | |
387 | uint64_t Literal64() const { |
388 | uint64_t literal; |
389 | memcpy(&literal, LiteralAddress<const void*>(), sizeof(literal)); |
390 | return literal; |
391 | } |
392 | |
393 | float LiteralFP32() const { |
394 | return rawbits_to_float(Literal32()); |
395 | } |
396 | |
397 | double LiteralFP64() const { |
398 | return rawbits_to_double(Literal64()); |
399 | } |
400 | |
401 | const Instruction* NextInstruction() const { |
402 | return this + kInstructionSize; |
403 | } |
404 | |
405 | const Instruction* InstructionAtOffset(int64_t offset) const { |
406 | VIXL_ASSERT(IsWordAligned(this + offset)); |
407 | return this + offset; |
408 | } |
409 | |
410 | template<typename T> static Instruction* Cast(T src) { |
411 | return reinterpret_cast<Instruction*>(src); |
412 | } |
413 | |
414 | template<typename T> static const Instruction* CastConst(T src) { |
415 | return reinterpret_cast<const Instruction*>(src); |
416 | } |
417 | |
418 | private: |
419 | int ImmBranch() const; |
420 | |
421 | static float Imm8ToFP32(uint32_t imm8); |
422 | static double Imm8ToFP64(uint32_t imm8); |
423 | |
424 | void SetPCRelImmTarget(const Instruction* target); |
425 | void SetBranchImmTarget(const Instruction* target); |
426 | }; |
427 | |
428 | |
429 | // Functions for handling NEON vector format information. |
430 | enum VectorFormat { |
431 | kFormatUndefined = 0xffffffff, |
432 | kFormat8B = NEON_8B, |
433 | kFormat16B = NEON_16B, |
434 | kFormat4H = NEON_4H, |
435 | kFormat8H = NEON_8H, |
436 | kFormat2S = NEON_2S, |
437 | kFormat4S = NEON_4S, |
438 | kFormat1D = NEON_1D, |
439 | kFormat2D = NEON_2D, |
440 | |
441 | // Scalar formats. We add the scalar bit to distinguish between scalar and |
442 | // vector enumerations; the bit is always set in the encoding of scalar ops |
443 | // and always clear for vector ops. Although kFormatD and kFormat1D appear |
444 | // to be the same, their meaning is subtly different. The first is a scalar |
445 | // operation, the second a vector operation that only affects one lane. |
446 | kFormatB = NEON_B | NEONScalar, |
447 | kFormatH = NEON_H | NEONScalar, |
448 | kFormatS = NEON_S | NEONScalar, |
449 | kFormatD = NEON_D | NEONScalar |
450 | }; |
451 | |
452 | VectorFormat VectorFormatHalfWidth(const VectorFormat vform); |
453 | VectorFormat VectorFormatDoubleWidth(const VectorFormat vform); |
454 | VectorFormat VectorFormatDoubleLanes(const VectorFormat vform); |
455 | VectorFormat VectorFormatHalfLanes(const VectorFormat vform); |
456 | VectorFormat ScalarFormatFromLaneSize(int lanesize); |
457 | VectorFormat VectorFormatHalfWidthDoubleLanes(const VectorFormat vform); |
458 | VectorFormat VectorFormatFillQ(const VectorFormat vform); |
459 | unsigned RegisterSizeInBitsFromFormat(VectorFormat vform); |
460 | unsigned RegisterSizeInBytesFromFormat(VectorFormat vform); |
461 | // TODO: Make the return types of these functions consistent. |
462 | unsigned LaneSizeInBitsFromFormat(VectorFormat vform); |
463 | int LaneSizeInBytesFromFormat(VectorFormat vform); |
464 | int LaneSizeInBytesLog2FromFormat(VectorFormat vform); |
465 | int LaneCountFromFormat(VectorFormat vform); |
466 | int MaxLaneCountFromFormat(VectorFormat vform); |
467 | bool IsVectorFormat(VectorFormat vform); |
468 | int64_t MaxIntFromFormat(VectorFormat vform); |
469 | int64_t MinIntFromFormat(VectorFormat vform); |
470 | uint64_t MaxUintFromFormat(VectorFormat vform); |
471 | |
472 | |
473 | enum NEONFormat { |
474 | NF_UNDEF = 0, |
475 | NF_8B = 1, |
476 | NF_16B = 2, |
477 | NF_4H = 3, |
478 | NF_8H = 4, |
479 | NF_2S = 5, |
480 | NF_4S = 6, |
481 | NF_1D = 7, |
482 | NF_2D = 8, |
483 | NF_B = 9, |
484 | NF_H = 10, |
485 | NF_S = 11, |
486 | NF_D = 12 |
487 | }; |
488 | |
489 | static const unsigned kNEONFormatMaxBits = 6; |
490 | |
491 | struct NEONFormatMap { |
492 | // The bit positions in the instruction to consider. |
493 | uint8_t bits[kNEONFormatMaxBits]; |
494 | |
495 | // Mapping from concatenated bits to format. |
496 | NEONFormat map[1 << kNEONFormatMaxBits]; |
497 | }; |
498 | |
499 | class NEONFormatDecoder { |
500 | public: |
501 | enum SubstitutionMode { |
502 | kPlaceholder, |
503 | kFormat |
504 | }; |
505 | |
506 | // Construct a format decoder with increasingly specific format maps for each |
507 | // subsitution. If no format map is specified, the default is the integer |
508 | // format map. |
509 | explicit NEONFormatDecoder(const Instruction* instr) { |
510 | instrbits_ = instr->InstructionBits(); |
511 | SetFormatMaps(IntegerFormatMap()); |
512 | } |
513 | NEONFormatDecoder(const Instruction* instr, |
514 | const NEONFormatMap* format) { |
515 | instrbits_ = instr->InstructionBits(); |
516 | SetFormatMaps(format); |
517 | } |
518 | NEONFormatDecoder(const Instruction* instr, |
519 | const NEONFormatMap* format0, |
520 | const NEONFormatMap* format1) { |
521 | instrbits_ = instr->InstructionBits(); |
522 | SetFormatMaps(format0, format1); |
523 | } |
524 | NEONFormatDecoder(const Instruction* instr, |
525 | const NEONFormatMap* format0, |
526 | const NEONFormatMap* format1, |
527 | const NEONFormatMap* format2) { |
528 | instrbits_ = instr->InstructionBits(); |
529 | SetFormatMaps(format0, format1, format2); |
530 | } |
531 | |
532 | // Set the format mapping for all or individual substitutions. |
533 | void SetFormatMaps(const NEONFormatMap* format0, |
534 | const NEONFormatMap* format1 = NULL, |
535 | const NEONFormatMap* format2 = NULL) { |
536 | VIXL_ASSERT(format0 != NULL); |
537 | formats_[0] = format0; |
538 | formats_[1] = (format1 == NULL) ? formats_[0] : format1; |
539 | formats_[2] = (format2 == NULL) ? formats_[1] : format2; |
540 | } |
541 | void SetFormatMap(unsigned index, const NEONFormatMap* format) { |
542 | VIXL_ASSERT(index <= (sizeof(formats_) / sizeof(formats_[0]))); |
543 | VIXL_ASSERT(format != NULL); |
544 | formats_[index] = format; |
545 | } |
546 | |
547 | // Substitute %s in the input string with the placeholder string for each |
548 | // register, ie. "'B", "'H", etc. |
549 | const char* SubstitutePlaceholders(const char* string) { |
550 | return Substitute(string, kPlaceholder, kPlaceholder, kPlaceholder); |
551 | } |
552 | |
553 | // Substitute %s in the input string with a new string based on the |
554 | // substitution mode. |
555 | const char* Substitute(const char* string, |
556 | SubstitutionMode mode0 = kFormat, |
557 | SubstitutionMode mode1 = kFormat, |
558 | SubstitutionMode mode2 = kFormat) { |
559 | snprintf(form_buffer_, sizeof(form_buffer_), string, |
560 | GetSubstitute(0, mode0), |
561 | GetSubstitute(1, mode1), |
562 | GetSubstitute(2, mode2)); |
563 | return form_buffer_; |
564 | } |
565 | |
566 | // Append a "2" to a mnemonic string based of the state of the Q bit. |
567 | const char* Mnemonic(const char* mnemonic) { |
568 | if ((instrbits_ & NEON_Q) != 0) { |
569 | snprintf(mne_buffer_, sizeof(mne_buffer_), "%s2" , mnemonic); |
570 | return mne_buffer_; |
571 | } |
572 | return mnemonic; |
573 | } |
574 | |
575 | VectorFormat GetVectorFormat(int format_index = 0) { |
576 | return GetVectorFormat(formats_[format_index]); |
577 | } |
578 | |
579 | VectorFormat GetVectorFormat(const NEONFormatMap* format_map) { |
580 | static const VectorFormat vform[] = { |
581 | kFormatUndefined, |
582 | kFormat8B, kFormat16B, kFormat4H, kFormat8H, |
583 | kFormat2S, kFormat4S, kFormat1D, kFormat2D, |
584 | kFormatB, kFormatH, kFormatS, kFormatD |
585 | }; |
586 | VIXL_ASSERT(GetNEONFormat(format_map) < (sizeof(vform) / sizeof(vform[0]))); |
587 | return vform[GetNEONFormat(format_map)]; |
588 | } |
589 | |
590 | // Built in mappings for common cases. |
591 | |
592 | // The integer format map uses three bits (Q, size<1:0>) to encode the |
593 | // "standard" set of NEON integer vector formats. |
594 | static const NEONFormatMap* IntegerFormatMap() { |
595 | static const NEONFormatMap map = { |
596 | {23, 22, 30}, |
597 | {NF_8B, NF_16B, NF_4H, NF_8H, NF_2S, NF_4S, NF_UNDEF, NF_2D} |
598 | }; |
599 | return ↦ |
600 | } |
601 | |
602 | // The long integer format map uses two bits (size<1:0>) to encode the |
603 | // long set of NEON integer vector formats. These are used in narrow, wide |
604 | // and long operations. |
605 | static const NEONFormatMap* LongIntegerFormatMap() { |
606 | static const NEONFormatMap map = { |
607 | {23, 22}, {NF_8H, NF_4S, NF_2D} |
608 | }; |
609 | return ↦ |
610 | } |
611 | |
612 | // The FP format map uses two bits (Q, size<0>) to encode the NEON FP vector |
613 | // formats: NF_2S, NF_4S, NF_2D. |
614 | static const NEONFormatMap* FPFormatMap() { |
615 | // The FP format map assumes two bits (Q, size<0>) are used to encode the |
616 | // NEON FP vector formats: NF_2S, NF_4S, NF_2D. |
617 | static const NEONFormatMap map = { |
618 | {22, 30}, {NF_2S, NF_4S, NF_UNDEF, NF_2D} |
619 | }; |
620 | return ↦ |
621 | } |
622 | |
623 | // The load/store format map uses three bits (Q, 11, 10) to encode the |
624 | // set of NEON vector formats. |
625 | static const NEONFormatMap* LoadStoreFormatMap() { |
626 | static const NEONFormatMap map = { |
627 | {11, 10, 30}, |
628 | {NF_8B, NF_16B, NF_4H, NF_8H, NF_2S, NF_4S, NF_1D, NF_2D} |
629 | }; |
630 | return ↦ |
631 | } |
632 | |
633 | // The logical format map uses one bit (Q) to encode the NEON vector format: |
634 | // NF_8B, NF_16B. |
635 | static const NEONFormatMap* LogicalFormatMap() { |
636 | static const NEONFormatMap map = { |
637 | {30}, {NF_8B, NF_16B} |
638 | }; |
639 | return ↦ |
640 | } |
641 | |
642 | // The triangular format map uses between two and five bits to encode the NEON |
643 | // vector format: |
644 | // xxx10->8B, xxx11->16B, xx100->4H, xx101->8H |
645 | // x1000->2S, x1001->4S, 10001->2D, all others undefined. |
646 | static const NEONFormatMap* TriangularFormatMap() { |
647 | static const NEONFormatMap map = { |
648 | {19, 18, 17, 16, 30}, |
649 | {NF_UNDEF, NF_UNDEF, NF_8B, NF_16B, NF_4H, NF_8H, NF_8B, NF_16B, NF_2S, |
650 | NF_4S, NF_8B, NF_16B, NF_4H, NF_8H, NF_8B, NF_16B, NF_UNDEF, NF_2D, |
651 | NF_8B, NF_16B, NF_4H, NF_8H, NF_8B, NF_16B, NF_2S, NF_4S, NF_8B, NF_16B, |
652 | NF_4H, NF_8H, NF_8B, NF_16B} |
653 | }; |
654 | return ↦ |
655 | } |
656 | |
657 | // The scalar format map uses two bits (size<1:0>) to encode the NEON scalar |
658 | // formats: NF_B, NF_H, NF_S, NF_D. |
659 | static const NEONFormatMap* ScalarFormatMap() { |
660 | static const NEONFormatMap map = { |
661 | {23, 22}, {NF_B, NF_H, NF_S, NF_D} |
662 | }; |
663 | return ↦ |
664 | } |
665 | |
666 | // The long scalar format map uses two bits (size<1:0>) to encode the longer |
667 | // NEON scalar formats: NF_H, NF_S, NF_D. |
668 | static const NEONFormatMap* LongScalarFormatMap() { |
669 | static const NEONFormatMap map = { |
670 | {23, 22}, {NF_H, NF_S, NF_D} |
671 | }; |
672 | return ↦ |
673 | } |
674 | |
675 | // The FP scalar format map assumes one bit (size<0>) is used to encode the |
676 | // NEON FP scalar formats: NF_S, NF_D. |
677 | static const NEONFormatMap* FPScalarFormatMap() { |
678 | static const NEONFormatMap map = { |
679 | {22}, {NF_S, NF_D} |
680 | }; |
681 | return ↦ |
682 | } |
683 | |
684 | // The triangular scalar format map uses between one and four bits to encode |
685 | // the NEON FP scalar formats: |
686 | // xxx1->B, xx10->H, x100->S, 1000->D, all others undefined. |
687 | static const NEONFormatMap* TriangularScalarFormatMap() { |
688 | static const NEONFormatMap map = { |
689 | {19, 18, 17, 16}, |
690 | {NF_UNDEF, NF_B, NF_H, NF_B, NF_S, NF_B, NF_H, NF_B, |
691 | NF_D, NF_B, NF_H, NF_B, NF_S, NF_B, NF_H, NF_B} |
692 | }; |
693 | return ↦ |
694 | } |
695 | |
696 | private: |
697 | // Get a pointer to a string that represents the format or placeholder for |
698 | // the specified substitution index, based on the format map and instruction. |
699 | const char* GetSubstitute(int index, SubstitutionMode mode) { |
700 | if (mode == kFormat) { |
701 | return NEONFormatAsString(GetNEONFormat(formats_[index])); |
702 | } |
703 | VIXL_ASSERT(mode == kPlaceholder); |
704 | return NEONFormatAsPlaceholder(GetNEONFormat(formats_[index])); |
705 | } |
706 | |
707 | // Get the NEONFormat enumerated value for bits obtained from the |
708 | // instruction based on the specified format mapping. |
709 | NEONFormat GetNEONFormat(const NEONFormatMap* format_map) { |
710 | return format_map->map[PickBits(format_map->bits)]; |
711 | } |
712 | |
713 | // Convert a NEONFormat into a string. |
714 | static const char* NEONFormatAsString(NEONFormat format) { |
715 | static const char* formats[] = { |
716 | "undefined" , |
717 | "8b" , "16b" , "4h" , "8h" , "2s" , "4s" , "1d" , "2d" , |
718 | "b" , "h" , "s" , "d" |
719 | }; |
720 | VIXL_ASSERT(format < (sizeof(formats) / sizeof(formats[0]))); |
721 | return formats[format]; |
722 | } |
723 | |
724 | // Convert a NEONFormat into a register placeholder string. |
725 | static const char* NEONFormatAsPlaceholder(NEONFormat format) { |
726 | VIXL_ASSERT((format == NF_B) || (format == NF_H) || |
727 | (format == NF_S) || (format == NF_D) || |
728 | (format == NF_UNDEF)); |
729 | static const char* formats[] = { |
730 | "undefined" , |
731 | "undefined" , "undefined" , "undefined" , "undefined" , |
732 | "undefined" , "undefined" , "undefined" , "undefined" , |
733 | "'B" , "'H" , "'S" , "'D" |
734 | }; |
735 | return formats[format]; |
736 | } |
737 | |
738 | // Select bits from instrbits_ defined by the bits array, concatenate them, |
739 | // and return the value. |
740 | uint8_t PickBits(const uint8_t bits[]) { |
741 | uint8_t result = 0; |
742 | for (unsigned b = 0; b < kNEONFormatMaxBits; b++) { |
743 | if (bits[b] == 0) break; |
744 | result <<= 1; |
745 | result |= ((instrbits_ & (1 << bits[b])) == 0) ? 0 : 1; |
746 | } |
747 | return result; |
748 | } |
749 | |
750 | Instr instrbits_; |
751 | const NEONFormatMap* formats_[3]; |
752 | char form_buffer_[64]; |
753 | char mne_buffer_[16]; |
754 | }; |
755 | } // namespace vixl |
756 | |
757 | #endif // VIXL_A64_INSTRUCTIONS_A64_H_ |
758 | |