• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2013 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #if V8_TARGET_ARCH_ARM64
6 
7 #include "src/arm64/assembler-arm64-inl.h"
8 #include "src/arm64/instructions-arm64.h"
9 
10 namespace v8 {
11 namespace internal {
12 
IsLoad() const13 bool Instruction::IsLoad() const {
14   if (Mask(LoadStoreAnyFMask) != LoadStoreAnyFixed) {
15     return false;
16   }
17 
18   if (Mask(LoadStorePairAnyFMask) == LoadStorePairAnyFixed) {
19     return Mask(LoadStorePairLBit) != 0;
20   } else {
21     LoadStoreOp op = static_cast<LoadStoreOp>(Mask(LoadStoreMask));
22     switch (op) {
23       case LDRB_w:
24       case LDRH_w:
25       case LDR_w:
26       case LDR_x:
27       case LDRSB_w:
28       case LDRSB_x:
29       case LDRSH_w:
30       case LDRSH_x:
31       case LDRSW_x:
32       case LDR_b:
33       case LDR_h:
34       case LDR_s:
35       case LDR_d:
36       case LDR_q:
37         return true;
38       default: return false;
39     }
40   }
41 }
42 
43 
IsStore() const44 bool Instruction::IsStore() const {
45   if (Mask(LoadStoreAnyFMask) != LoadStoreAnyFixed) {
46     return false;
47   }
48 
49   if (Mask(LoadStorePairAnyFMask) == LoadStorePairAnyFixed) {
50     return Mask(LoadStorePairLBit) == 0;
51   } else {
52     LoadStoreOp op = static_cast<LoadStoreOp>(Mask(LoadStoreMask));
53     switch (op) {
54       case STRB_w:
55       case STRH_w:
56       case STR_w:
57       case STR_x:
58       case STR_b:
59       case STR_h:
60       case STR_s:
61       case STR_d:
62       case STR_q:
63         return true;
64       default: return false;
65     }
66   }
67 }
68 
69 
RotateRight(uint64_t value,unsigned int rotate,unsigned int width)70 static uint64_t RotateRight(uint64_t value,
71                             unsigned int rotate,
72                             unsigned int width) {
73   DCHECK_LE(width, 64);
74   rotate &= 63;
75   return ((value & ((1UL << rotate) - 1UL)) << (width - rotate)) |
76          (value >> rotate);
77 }
78 
79 
RepeatBitsAcrossReg(unsigned reg_size,uint64_t value,unsigned width)80 static uint64_t RepeatBitsAcrossReg(unsigned reg_size,
81                                     uint64_t value,
82                                     unsigned width) {
83   DCHECK((width == 2) || (width == 4) || (width == 8) || (width == 16) ||
84          (width == 32));
85   DCHECK((reg_size == kWRegSizeInBits) || (reg_size == kXRegSizeInBits));
86   uint64_t result = value & ((1UL << width) - 1UL);
87   for (unsigned i = width; i < reg_size; i *= 2) {
88     result |= (result << i);
89   }
90   return result;
91 }
92 
93 
94 // Logical immediates can't encode zero, so a return value of zero is used to
95 // indicate a failure case. Specifically, where the constraints on imm_s are not
96 // met.
ImmLogical()97 uint64_t Instruction::ImmLogical() {
98   unsigned reg_size = SixtyFourBits() ? kXRegSizeInBits : kWRegSizeInBits;
99   int32_t n = BitN();
100   int32_t imm_s = ImmSetBits();
101   int32_t imm_r = ImmRotate();
102 
103   // An integer is constructed from the n, imm_s and imm_r bits according to
104   // the following table:
105   //
106   //  N   imms    immr    size        S             R
107   //  1  ssssss  rrrrrr    64    UInt(ssssss)  UInt(rrrrrr)
108   //  0  0sssss  xrrrrr    32    UInt(sssss)   UInt(rrrrr)
109   //  0  10ssss  xxrrrr    16    UInt(ssss)    UInt(rrrr)
110   //  0  110sss  xxxrrr     8    UInt(sss)     UInt(rrr)
111   //  0  1110ss  xxxxrr     4    UInt(ss)      UInt(rr)
112   //  0  11110s  xxxxxr     2    UInt(s)       UInt(r)
113   // (s bits must not be all set)
114   //
115   // A pattern is constructed of size bits, where the least significant S+1
116   // bits are set. The pattern is rotated right by R, and repeated across a
117   // 32 or 64-bit value, depending on destination register width.
118   //
119 
120   if (n == 1) {
121     if (imm_s == 0x3F) {
122       return 0;
123     }
124     uint64_t bits = (1UL << (imm_s + 1)) - 1;
125     return RotateRight(bits, imm_r, 64);
126   } else {
127     if ((imm_s >> 1) == 0x1F) {
128       return 0;
129     }
130     for (int width = 0x20; width >= 0x2; width >>= 1) {
131       if ((imm_s & width) == 0) {
132         int mask = width - 1;
133         if ((imm_s & mask) == mask) {
134           return 0;
135         }
136         uint64_t bits = (1UL << ((imm_s & mask) + 1)) - 1;
137         return RepeatBitsAcrossReg(reg_size,
138                                    RotateRight(bits, imm_r & mask, width),
139                                    width);
140       }
141     }
142   }
143   UNREACHABLE();
144 }
145 
ImmNEONabcdefgh() const146 uint32_t Instruction::ImmNEONabcdefgh() const {
147   return ImmNEONabc() << 5 | ImmNEONdefgh();
148 }
149 
ImmFP32()150 float Instruction::ImmFP32() { return Imm8ToFP32(ImmFP()); }
151 
ImmFP64()152 double Instruction::ImmFP64() { return Imm8ToFP64(ImmFP()); }
153 
ImmNEONFP32() const154 float Instruction::ImmNEONFP32() const { return Imm8ToFP32(ImmNEONabcdefgh()); }
155 
ImmNEONFP64() const156 double Instruction::ImmNEONFP64() const {
157   return Imm8ToFP64(ImmNEONabcdefgh());
158 }
159 
CalcLSDataSize(LoadStoreOp op)160 unsigned CalcLSDataSize(LoadStoreOp op) {
161   DCHECK_EQ(static_cast<unsigned>(LSSize_offset + LSSize_width),
162             kInstrSize * 8);
163   unsigned size = static_cast<Instr>(op) >> LSSize_offset;
164   if ((op & LSVector_mask) != 0) {
165     // Vector register memory operations encode the access size in the "size"
166     // and "opc" fields.
167     if ((size == 0) && ((op & LSOpc_mask) >> LSOpc_offset) >= 2) {
168       size = kQRegSizeLog2;
169     }
170   }
171   return size;
172 }
173 
CalcLSPairDataSize(LoadStorePairOp op)174 unsigned CalcLSPairDataSize(LoadStorePairOp op) {
175   static_assert(kXRegSize == kDRegSize, "X and D registers must be same size.");
176   static_assert(kWRegSize == kSRegSize, "W and S registers must be same size.");
177   switch (op) {
178     case STP_q:
179     case LDP_q:
180       return kQRegSizeLog2;
181     case STP_x:
182     case LDP_x:
183     case STP_d:
184     case LDP_d:
185       return kXRegSizeLog2;
186     default:
187       return kWRegSizeLog2;
188   }
189 }
190 
191 
ImmPCOffset()192 int64_t Instruction::ImmPCOffset() {
193   int64_t offset;
194   if (IsPCRelAddressing()) {
195     // PC-relative addressing. Only ADR is supported.
196     offset = ImmPCRel();
197   } else if (BranchType() != UnknownBranchType) {
198     // All PC-relative branches.
199     // Relative branch offsets are instruction-size-aligned.
200     offset = ImmBranch() << kInstrSizeLog2;
201   } else if (IsUnresolvedInternalReference()) {
202     // Internal references are always word-aligned.
203     offset = ImmUnresolvedInternalReference() << kInstrSizeLog2;
204   } else {
205     // Load literal (offset from PC).
206     DCHECK(IsLdrLiteral());
207     // The offset is always shifted by 2 bits, even for loads to 64-bits
208     // registers.
209     offset = ImmLLiteral() << kInstrSizeLog2;
210   }
211   return offset;
212 }
213 
214 
ImmPCOffsetTarget()215 Instruction* Instruction::ImmPCOffsetTarget() {
216   return InstructionAtOffset(ImmPCOffset());
217 }
218 
219 
IsValidImmPCOffset(ImmBranchType branch_type,ptrdiff_t offset)220 bool Instruction::IsValidImmPCOffset(ImmBranchType branch_type,
221                                      ptrdiff_t offset) {
222   return is_intn(offset, ImmBranchRangeBitwidth(branch_type));
223 }
224 
225 
IsTargetInImmPCOffsetRange(Instruction * target)226 bool Instruction::IsTargetInImmPCOffsetRange(Instruction* target) {
227   return IsValidImmPCOffset(BranchType(), DistanceTo(target));
228 }
229 
SetImmPCOffsetTarget(const AssemblerOptions & options,Instruction * target)230 void Instruction::SetImmPCOffsetTarget(const AssemblerOptions& options,
231                                        Instruction* target) {
232   if (IsPCRelAddressing()) {
233     SetPCRelImmTarget(options, target);
234   } else if (BranchType() != UnknownBranchType) {
235     SetBranchImmTarget(target);
236   } else if (IsUnresolvedInternalReference()) {
237     SetUnresolvedInternalReferenceImmTarget(options, target);
238   } else {
239     // Load literal (offset from PC).
240     SetImmLLiteral(target);
241   }
242 }
243 
SetPCRelImmTarget(const AssemblerOptions & options,Instruction * target)244 void Instruction::SetPCRelImmTarget(const AssemblerOptions& options,
245                                     Instruction* target) {
246   // ADRP is not supported, so 'this' must point to an ADR instruction.
247   DCHECK(IsAdr());
248 
249   ptrdiff_t target_offset = DistanceTo(target);
250   Instr imm;
251   if (Instruction::IsValidPCRelOffset(target_offset)) {
252     imm = Assembler::ImmPCRelAddress(static_cast<int>(target_offset));
253     SetInstructionBits(Mask(~ImmPCRel_mask) | imm);
254   } else {
255     PatchingAssembler patcher(options, reinterpret_cast<byte*>(this),
256                               PatchingAssembler::kAdrFarPatchableNInstrs);
257     patcher.PatchAdrFar(target_offset);
258   }
259 }
260 
261 
SetBranchImmTarget(Instruction * target)262 void Instruction::SetBranchImmTarget(Instruction* target) {
263   DCHECK(IsAligned(DistanceTo(target), kInstrSize));
264   DCHECK(
265       IsValidImmPCOffset(BranchType(), DistanceTo(target) >> kInstrSizeLog2));
266   int offset = static_cast<int>(DistanceTo(target) >> kInstrSizeLog2);
267   Instr branch_imm = 0;
268   uint32_t imm_mask = 0;
269   switch (BranchType()) {
270     case CondBranchType: {
271       branch_imm = Assembler::ImmCondBranch(offset);
272       imm_mask = ImmCondBranch_mask;
273       break;
274     }
275     case UncondBranchType: {
276       branch_imm = Assembler::ImmUncondBranch(offset);
277       imm_mask = ImmUncondBranch_mask;
278       break;
279     }
280     case CompareBranchType: {
281       branch_imm = Assembler::ImmCmpBranch(offset);
282       imm_mask = ImmCmpBranch_mask;
283       break;
284     }
285     case TestBranchType: {
286       branch_imm = Assembler::ImmTestBranch(offset);
287       imm_mask = ImmTestBranch_mask;
288       break;
289     }
290     default: UNREACHABLE();
291   }
292   SetInstructionBits(Mask(~imm_mask) | branch_imm);
293 }
294 
SetUnresolvedInternalReferenceImmTarget(const AssemblerOptions & options,Instruction * target)295 void Instruction::SetUnresolvedInternalReferenceImmTarget(
296     const AssemblerOptions& options, Instruction* target) {
297   DCHECK(IsUnresolvedInternalReference());
298   DCHECK(IsAligned(DistanceTo(target), kInstrSize));
299   DCHECK(is_int32(DistanceTo(target) >> kInstrSizeLog2));
300   int32_t target_offset =
301       static_cast<int32_t>(DistanceTo(target) >> kInstrSizeLog2);
302   uint32_t high16 = unsigned_bitextract_32(31, 16, target_offset);
303   uint32_t low16 = unsigned_bitextract_32(15, 0, target_offset);
304 
305   PatchingAssembler patcher(options, reinterpret_cast<byte*>(this), 2);
306   patcher.brk(high16);
307   patcher.brk(low16);
308 }
309 
310 
SetImmLLiteral(Instruction * source)311 void Instruction::SetImmLLiteral(Instruction* source) {
312   DCHECK(IsLdrLiteral());
313   DCHECK(IsAligned(DistanceTo(source), kInstrSize));
314   DCHECK(Assembler::IsImmLLiteral(DistanceTo(source)));
315   Instr imm = Assembler::ImmLLiteral(
316       static_cast<int>(DistanceTo(source) >> kLoadLiteralScaleLog2));
317   Instr mask = ImmLLiteral_mask;
318 
319   SetInstructionBits(Mask(~mask) | imm);
320 }
321 
322 
323 // TODO(jbramley): We can't put this inline in the class because things like
324 // xzr and Register are not defined in that header. Consider adding
325 // instructions-arm64-inl.h to work around this.
IsInlineData() const326 bool InstructionSequence::IsInlineData() const {
327   // Inline data is encoded as a single movz instruction which writes to xzr
328   // (x31).
329   return IsMovz() && SixtyFourBits() && (Rd() == kZeroRegCode);
330   // TODO(all): If we extend ::InlineData() to support bigger data, we need
331   // to update this method too.
332 }
333 
334 
335 // TODO(jbramley): We can't put this inline in the class because things like
336 // xzr and Register are not defined in that header. Consider adding
337 // instructions-arm64-inl.h to work around this.
InlineData() const338 uint64_t InstructionSequence::InlineData() const {
339   DCHECK(IsInlineData());
340   uint64_t payload = ImmMoveWide();
341   // TODO(all): If we extend ::InlineData() to support bigger data, we need
342   // to update this method too.
343   return payload;
344 }
345 
VectorFormatHalfWidth(VectorFormat vform)346 VectorFormat VectorFormatHalfWidth(VectorFormat vform) {
347   DCHECK(vform == kFormat8H || vform == kFormat4S || vform == kFormat2D ||
348          vform == kFormatH || vform == kFormatS || vform == kFormatD);
349   switch (vform) {
350     case kFormat8H:
351       return kFormat8B;
352     case kFormat4S:
353       return kFormat4H;
354     case kFormat2D:
355       return kFormat2S;
356     case kFormatH:
357       return kFormatB;
358     case kFormatS:
359       return kFormatH;
360     case kFormatD:
361       return kFormatS;
362     default:
363       UNREACHABLE();
364   }
365 }
366 
VectorFormatDoubleWidth(VectorFormat vform)367 VectorFormat VectorFormatDoubleWidth(VectorFormat vform) {
368   DCHECK(vform == kFormat8B || vform == kFormat4H || vform == kFormat2S ||
369          vform == kFormatB || vform == kFormatH || vform == kFormatS);
370   switch (vform) {
371     case kFormat8B:
372       return kFormat8H;
373     case kFormat4H:
374       return kFormat4S;
375     case kFormat2S:
376       return kFormat2D;
377     case kFormatB:
378       return kFormatH;
379     case kFormatH:
380       return kFormatS;
381     case kFormatS:
382       return kFormatD;
383     default:
384       UNREACHABLE();
385   }
386 }
387 
VectorFormatFillQ(VectorFormat vform)388 VectorFormat VectorFormatFillQ(VectorFormat vform) {
389   switch (vform) {
390     case kFormatB:
391     case kFormat8B:
392     case kFormat16B:
393       return kFormat16B;
394     case kFormatH:
395     case kFormat4H:
396     case kFormat8H:
397       return kFormat8H;
398     case kFormatS:
399     case kFormat2S:
400     case kFormat4S:
401       return kFormat4S;
402     case kFormatD:
403     case kFormat1D:
404     case kFormat2D:
405       return kFormat2D;
406     default:
407       UNREACHABLE();
408   }
409 }
410 
VectorFormatHalfWidthDoubleLanes(VectorFormat vform)411 VectorFormat VectorFormatHalfWidthDoubleLanes(VectorFormat vform) {
412   switch (vform) {
413     case kFormat4H:
414       return kFormat8B;
415     case kFormat8H:
416       return kFormat16B;
417     case kFormat2S:
418       return kFormat4H;
419     case kFormat4S:
420       return kFormat8H;
421     case kFormat1D:
422       return kFormat2S;
423     case kFormat2D:
424       return kFormat4S;
425     default:
426       UNREACHABLE();
427   }
428 }
429 
VectorFormatDoubleLanes(VectorFormat vform)430 VectorFormat VectorFormatDoubleLanes(VectorFormat vform) {
431   DCHECK(vform == kFormat8B || vform == kFormat4H || vform == kFormat2S);
432   switch (vform) {
433     case kFormat8B:
434       return kFormat16B;
435     case kFormat4H:
436       return kFormat8H;
437     case kFormat2S:
438       return kFormat4S;
439     default:
440       UNREACHABLE();
441   }
442 }
443 
VectorFormatHalfLanes(VectorFormat vform)444 VectorFormat VectorFormatHalfLanes(VectorFormat vform) {
445   DCHECK(vform == kFormat16B || vform == kFormat8H || vform == kFormat4S);
446   switch (vform) {
447     case kFormat16B:
448       return kFormat8B;
449     case kFormat8H:
450       return kFormat4H;
451     case kFormat4S:
452       return kFormat2S;
453     default:
454       UNREACHABLE();
455   }
456 }
457 
ScalarFormatFromLaneSize(int laneSize)458 VectorFormat ScalarFormatFromLaneSize(int laneSize) {
459   switch (laneSize) {
460     case 8:
461       return kFormatB;
462     case 16:
463       return kFormatH;
464     case 32:
465       return kFormatS;
466     case 64:
467       return kFormatD;
468     default:
469       UNREACHABLE();
470   }
471 }
472 
ScalarFormatFromFormat(VectorFormat vform)473 VectorFormat ScalarFormatFromFormat(VectorFormat vform) {
474   return ScalarFormatFromLaneSize(LaneSizeInBitsFromFormat(vform));
475 }
476 
RegisterSizeInBytesFromFormat(VectorFormat vform)477 unsigned RegisterSizeInBytesFromFormat(VectorFormat vform) {
478   return RegisterSizeInBitsFromFormat(vform) / 8;
479 }
480 
RegisterSizeInBitsFromFormat(VectorFormat vform)481 unsigned RegisterSizeInBitsFromFormat(VectorFormat vform) {
482   DCHECK_NE(vform, kFormatUndefined);
483   switch (vform) {
484     case kFormatB:
485       return kBRegSizeInBits;
486     case kFormatH:
487       return kHRegSizeInBits;
488     case kFormatS:
489       return kSRegSizeInBits;
490     case kFormatD:
491       return kDRegSizeInBits;
492     case kFormat8B:
493     case kFormat4H:
494     case kFormat2S:
495     case kFormat1D:
496       return kDRegSizeInBits;
497     default:
498       return kQRegSizeInBits;
499   }
500 }
501 
LaneSizeInBitsFromFormat(VectorFormat vform)502 unsigned LaneSizeInBitsFromFormat(VectorFormat vform) {
503   DCHECK_NE(vform, kFormatUndefined);
504   switch (vform) {
505     case kFormatB:
506     case kFormat8B:
507     case kFormat16B:
508       return 8;
509     case kFormatH:
510     case kFormat4H:
511     case kFormat8H:
512       return 16;
513     case kFormatS:
514     case kFormat2S:
515     case kFormat4S:
516       return 32;
517     case kFormatD:
518     case kFormat1D:
519     case kFormat2D:
520       return 64;
521     default:
522       UNREACHABLE();
523   }
524 }
525 
LaneSizeInBytesFromFormat(VectorFormat vform)526 int LaneSizeInBytesFromFormat(VectorFormat vform) {
527   return LaneSizeInBitsFromFormat(vform) / 8;
528 }
529 
LaneSizeInBytesLog2FromFormat(VectorFormat vform)530 int LaneSizeInBytesLog2FromFormat(VectorFormat vform) {
531   DCHECK_NE(vform, kFormatUndefined);
532   switch (vform) {
533     case kFormatB:
534     case kFormat8B:
535     case kFormat16B:
536       return 0;
537     case kFormatH:
538     case kFormat4H:
539     case kFormat8H:
540       return 1;
541     case kFormatS:
542     case kFormat2S:
543     case kFormat4S:
544       return 2;
545     case kFormatD:
546     case kFormat1D:
547     case kFormat2D:
548       return 3;
549     default:
550       UNREACHABLE();
551   }
552 }
553 
LaneCountFromFormat(VectorFormat vform)554 int LaneCountFromFormat(VectorFormat vform) {
555   DCHECK_NE(vform, kFormatUndefined);
556   switch (vform) {
557     case kFormat16B:
558       return 16;
559     case kFormat8B:
560     case kFormat8H:
561       return 8;
562     case kFormat4H:
563     case kFormat4S:
564       return 4;
565     case kFormat2S:
566     case kFormat2D:
567       return 2;
568     case kFormat1D:
569     case kFormatB:
570     case kFormatH:
571     case kFormatS:
572     case kFormatD:
573       return 1;
574     default:
575       UNREACHABLE();
576   }
577 }
578 
MaxLaneCountFromFormat(VectorFormat vform)579 int MaxLaneCountFromFormat(VectorFormat vform) {
580   DCHECK_NE(vform, kFormatUndefined);
581   switch (vform) {
582     case kFormatB:
583     case kFormat8B:
584     case kFormat16B:
585       return 16;
586     case kFormatH:
587     case kFormat4H:
588     case kFormat8H:
589       return 8;
590     case kFormatS:
591     case kFormat2S:
592     case kFormat4S:
593       return 4;
594     case kFormatD:
595     case kFormat1D:
596     case kFormat2D:
597       return 2;
598     default:
599       UNREACHABLE();
600   }
601 }
602 
603 // Does 'vform' indicate a vector format or a scalar format?
IsVectorFormat(VectorFormat vform)604 bool IsVectorFormat(VectorFormat vform) {
605   DCHECK_NE(vform, kFormatUndefined);
606   switch (vform) {
607     case kFormatB:
608     case kFormatH:
609     case kFormatS:
610     case kFormatD:
611       return false;
612     default:
613       return true;
614   }
615 }
616 
MaxIntFromFormat(VectorFormat vform)617 int64_t MaxIntFromFormat(VectorFormat vform) {
618   return INT64_MAX >> (64 - LaneSizeInBitsFromFormat(vform));
619 }
620 
MinIntFromFormat(VectorFormat vform)621 int64_t MinIntFromFormat(VectorFormat vform) {
622   return INT64_MIN >> (64 - LaneSizeInBitsFromFormat(vform));
623 }
624 
MaxUintFromFormat(VectorFormat vform)625 uint64_t MaxUintFromFormat(VectorFormat vform) {
626   return UINT64_MAX >> (64 - LaneSizeInBitsFromFormat(vform));
627 }
628 
NEONFormatDecoder(const Instruction * instr)629 NEONFormatDecoder::NEONFormatDecoder(const Instruction* instr) {
630   instrbits_ = instr->InstructionBits();
631   SetFormatMaps(IntegerFormatMap());
632 }
633 
NEONFormatDecoder(const Instruction * instr,const NEONFormatMap * format)634 NEONFormatDecoder::NEONFormatDecoder(const Instruction* instr,
635                                      const NEONFormatMap* format) {
636   instrbits_ = instr->InstructionBits();
637   SetFormatMaps(format);
638 }
639 
NEONFormatDecoder(const Instruction * instr,const NEONFormatMap * format0,const NEONFormatMap * format1)640 NEONFormatDecoder::NEONFormatDecoder(const Instruction* instr,
641                                      const NEONFormatMap* format0,
642                                      const NEONFormatMap* format1) {
643   instrbits_ = instr->InstructionBits();
644   SetFormatMaps(format0, format1);
645 }
646 
NEONFormatDecoder(const Instruction * instr,const NEONFormatMap * format0,const NEONFormatMap * format1,const NEONFormatMap * format2)647 NEONFormatDecoder::NEONFormatDecoder(const Instruction* instr,
648                                      const NEONFormatMap* format0,
649                                      const NEONFormatMap* format1,
650                                      const NEONFormatMap* format2) {
651   instrbits_ = instr->InstructionBits();
652   SetFormatMaps(format0, format1, format2);
653 }
654 
SetFormatMaps(const NEONFormatMap * format0,const NEONFormatMap * format1,const NEONFormatMap * format2)655 void NEONFormatDecoder::SetFormatMaps(const NEONFormatMap* format0,
656                                       const NEONFormatMap* format1,
657                                       const NEONFormatMap* format2) {
658   DCHECK_NOT_NULL(format0);
659   formats_[0] = format0;
660   formats_[1] = (format1 == nullptr) ? formats_[0] : format1;
661   formats_[2] = (format2 == nullptr) ? formats_[1] : format2;
662 }
663 
SetFormatMap(unsigned index,const NEONFormatMap * format)664 void NEONFormatDecoder::SetFormatMap(unsigned index,
665                                      const NEONFormatMap* format) {
666   DCHECK_LT(index, arraysize(formats_));
667   DCHECK_NOT_NULL(format);
668   formats_[index] = format;
669 }
670 
SubstitutePlaceholders(const char * string)671 const char* NEONFormatDecoder::SubstitutePlaceholders(const char* string) {
672   return Substitute(string, kPlaceholder, kPlaceholder, kPlaceholder);
673 }
674 
Substitute(const char * string,SubstitutionMode mode0,SubstitutionMode mode1,SubstitutionMode mode2)675 const char* NEONFormatDecoder::Substitute(const char* string,
676                                           SubstitutionMode mode0,
677                                           SubstitutionMode mode1,
678                                           SubstitutionMode mode2) {
679   snprintf(form_buffer_, sizeof(form_buffer_), string, GetSubstitute(0, mode0),
680            GetSubstitute(1, mode1), GetSubstitute(2, mode2));
681   return form_buffer_;
682 }
683 
Mnemonic(const char * mnemonic)684 const char* NEONFormatDecoder::Mnemonic(const char* mnemonic) {
685   if ((instrbits_ & NEON_Q) != 0) {
686     snprintf(mne_buffer_, sizeof(mne_buffer_), "%s2", mnemonic);
687     return mne_buffer_;
688   }
689   return mnemonic;
690 }
691 
GetVectorFormat(int format_index)692 VectorFormat NEONFormatDecoder::GetVectorFormat(int format_index) {
693   return GetVectorFormat(formats_[format_index]);
694 }
695 
GetVectorFormat(const NEONFormatMap * format_map)696 VectorFormat NEONFormatDecoder::GetVectorFormat(
697     const NEONFormatMap* format_map) {
698   static const VectorFormat vform[] = {
699       kFormatUndefined, kFormat8B, kFormat16B, kFormat4H, kFormat8H,
700       kFormat2S,        kFormat4S, kFormat1D,  kFormat2D, kFormatB,
701       kFormatH,         kFormatS,  kFormatD};
702   DCHECK_LT(GetNEONFormat(format_map), arraysize(vform));
703   return vform[GetNEONFormat(format_map)];
704 }
705 
GetSubstitute(int index,SubstitutionMode mode)706 const char* NEONFormatDecoder::GetSubstitute(int index, SubstitutionMode mode) {
707   if (mode == kFormat) {
708     return NEONFormatAsString(GetNEONFormat(formats_[index]));
709   }
710   DCHECK_EQ(mode, kPlaceholder);
711   return NEONFormatAsPlaceholder(GetNEONFormat(formats_[index]));
712 }
713 
GetNEONFormat(const NEONFormatMap * format_map)714 NEONFormat NEONFormatDecoder::GetNEONFormat(const NEONFormatMap* format_map) {
715   return format_map->map[PickBits(format_map->bits)];
716 }
717 
NEONFormatAsString(NEONFormat format)718 const char* NEONFormatDecoder::NEONFormatAsString(NEONFormat format) {
719   static const char* formats[] = {"undefined", "8b", "16b", "4h", "8h",
720                                   "2s",        "4s", "1d",  "2d", "b",
721                                   "h",         "s",  "d"};
722   DCHECK_LT(format, arraysize(formats));
723   return formats[format];
724 }
725 
NEONFormatAsPlaceholder(NEONFormat format)726 const char* NEONFormatDecoder::NEONFormatAsPlaceholder(NEONFormat format) {
727   DCHECK((format == NF_B) || (format == NF_H) || (format == NF_S) ||
728          (format == NF_D) || (format == NF_UNDEF));
729   static const char* formats[] = {
730       "undefined", "undefined", "undefined", "undefined", "undefined",
731       "undefined", "undefined", "undefined", "undefined", "'B",
732       "'H",        "'S",        "'D"};
733   return formats[format];
734 }
735 
PickBits(const uint8_t bits[])736 uint8_t NEONFormatDecoder::PickBits(const uint8_t bits[]) {
737   uint8_t result = 0;
738   for (unsigned b = 0; b < kNEONFormatMaxBits; b++) {
739     if (bits[b] == 0) break;
740     result <<= 1;
741     result |= ((instrbits_ & (1 << bits[b])) == 0) ? 0 : 1;
742   }
743   return result;
744 }
745 }  // namespace internal
746 }  // namespace v8
747 
748 #endif  // V8_TARGET_ARCH_ARM64
749