• 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 
28 #include <cmath>
29 
30 #include "assembler-aarch64.h"
31 #include "macro-assembler-aarch64.h"
32 
33 namespace vixl {
34 namespace aarch64 {
35 
RawLiteral(size_t size,LiteralPool * literal_pool,DeletionPolicy deletion_policy)36 RawLiteral::RawLiteral(size_t size,
37                        LiteralPool* literal_pool,
38                        DeletionPolicy deletion_policy)
39     : size_(size),
40       offset_(0),
41       low64_(0),
42       high64_(0),
43       literal_pool_(literal_pool),
44       deletion_policy_(deletion_policy) {
45   VIXL_ASSERT((deletion_policy == kManuallyDeleted) || (literal_pool_ != NULL));
46   if (deletion_policy == kDeletedOnPoolDestruction) {
47     literal_pool_->DeleteOnDestruction(this);
48   }
49 }
50 
51 
Reset()52 void Assembler::Reset() { GetBuffer()->Reset(); }
53 
54 
bind(Label * label)55 void Assembler::bind(Label* label) {
56   BindToOffset(label, GetBuffer()->GetCursorOffset());
57 }
58 
59 
BindToOffset(Label * label,ptrdiff_t offset)60 void Assembler::BindToOffset(Label* label, ptrdiff_t offset) {
61   VIXL_ASSERT((offset >= 0) && (offset <= GetBuffer()->GetCursorOffset()));
62   VIXL_ASSERT(offset % kInstructionSize == 0);
63 
64   label->Bind(offset);
65 
66   for (Label::LabelLinksIterator it(label); !it.Done(); it.Advance()) {
67     Instruction* link =
68         GetBuffer()->GetOffsetAddress<Instruction*>(*it.Current());
69     link->SetImmPCOffsetTarget(GetLabelAddress<Instruction*>(label));
70   }
71   label->ClearAllLinks();
72 }
73 
74 
75 // A common implementation for the LinkAndGet<Type>OffsetTo helpers.
76 //
77 // The offset is calculated by aligning the PC and label addresses down to a
78 // multiple of 1 << element_shift, then calculating the (scaled) offset between
79 // them. This matches the semantics of adrp, for example.
80 template <int element_shift>
LinkAndGetOffsetTo(Label * label)81 ptrdiff_t Assembler::LinkAndGetOffsetTo(Label* label) {
82   VIXL_STATIC_ASSERT(element_shift < (sizeof(ptrdiff_t) * 8));
83 
84   if (label->IsBound()) {
85     uintptr_t pc_offset = GetCursorAddress<uintptr_t>() >> element_shift;
86     uintptr_t label_offset = GetLabelAddress<uintptr_t>(label) >> element_shift;
87     return label_offset - pc_offset;
88   } else {
89     label->AddLink(GetBuffer()->GetCursorOffset());
90     return 0;
91   }
92 }
93 
94 
LinkAndGetByteOffsetTo(Label * label)95 ptrdiff_t Assembler::LinkAndGetByteOffsetTo(Label* label) {
96   return LinkAndGetOffsetTo<0>(label);
97 }
98 
99 
LinkAndGetInstructionOffsetTo(Label * label)100 ptrdiff_t Assembler::LinkAndGetInstructionOffsetTo(Label* label) {
101   return LinkAndGetOffsetTo<kInstructionSizeLog2>(label);
102 }
103 
104 
LinkAndGetPageOffsetTo(Label * label)105 ptrdiff_t Assembler::LinkAndGetPageOffsetTo(Label* label) {
106   return LinkAndGetOffsetTo<kPageSizeLog2>(label);
107 }
108 
109 
place(RawLiteral * literal)110 void Assembler::place(RawLiteral* literal) {
111   VIXL_ASSERT(!literal->IsPlaced());
112 
113   // Patch instructions using this literal.
114   if (literal->IsUsed()) {
115     Instruction* target = GetCursorAddress<Instruction*>();
116     ptrdiff_t offset = literal->GetLastUse();
117     bool done;
118     do {
119       Instruction* ldr = GetBuffer()->GetOffsetAddress<Instruction*>(offset);
120       VIXL_ASSERT(ldr->IsLoadLiteral());
121 
122       ptrdiff_t imm19 = ldr->GetImmLLiteral();
123       VIXL_ASSERT(imm19 <= 0);
124       done = (imm19 == 0);
125       offset += imm19 * kLiteralEntrySize;
126 
127       ldr->SetImmLLiteral(target);
128     } while (!done);
129   }
130 
131   // "bind" the literal.
132   literal->SetOffset(GetCursorOffset());
133   // Copy the data into the pool.
134   switch (literal->GetSize()) {
135     case kSRegSizeInBytes:
136       dc32(literal->GetRawValue32());
137       break;
138     case kDRegSizeInBytes:
139       dc64(literal->GetRawValue64());
140       break;
141     default:
142       VIXL_ASSERT(literal->GetSize() == kQRegSizeInBytes);
143       dc64(literal->GetRawValue128Low64());
144       dc64(literal->GetRawValue128High64());
145   }
146 
147   literal->literal_pool_ = NULL;
148 }
149 
150 
LinkAndGetWordOffsetTo(RawLiteral * literal)151 ptrdiff_t Assembler::LinkAndGetWordOffsetTo(RawLiteral* literal) {
152   VIXL_ASSERT(IsWordAligned(GetCursorOffset()));
153 
154   bool register_first_use =
155       (literal->GetLiteralPool() != NULL) && !literal->IsUsed();
156 
157   if (literal->IsPlaced()) {
158     // The literal is "behind", the offset will be negative.
159     VIXL_ASSERT((literal->GetOffset() - GetCursorOffset()) <= 0);
160     return (literal->GetOffset() - GetCursorOffset()) >> kLiteralEntrySizeLog2;
161   }
162 
163   ptrdiff_t offset = 0;
164   // Link all uses together.
165   if (literal->IsUsed()) {
166     offset =
167         (literal->GetLastUse() - GetCursorOffset()) >> kLiteralEntrySizeLog2;
168   }
169   literal->SetLastUse(GetCursorOffset());
170 
171   if (register_first_use) {
172     literal->GetLiteralPool()->AddEntry(literal);
173   }
174 
175   return offset;
176 }
177 
178 
179 // Code generation.
br(const Register & xn)180 void Assembler::br(const Register& xn) {
181   VIXL_ASSERT(xn.Is64Bits());
182   Emit(BR | Rn(xn));
183 }
184 
185 
blr(const Register & xn)186 void Assembler::blr(const Register& xn) {
187   VIXL_ASSERT(xn.Is64Bits());
188   Emit(BLR | Rn(xn));
189 }
190 
191 
ret(const Register & xn)192 void Assembler::ret(const Register& xn) {
193   VIXL_ASSERT(xn.Is64Bits());
194   Emit(RET | Rn(xn));
195 }
196 
197 
braaz(const Register & xn)198 void Assembler::braaz(const Register& xn) {
199   VIXL_ASSERT(CPUHas(CPUFeatures::kPAuth));
200   VIXL_ASSERT(xn.Is64Bits());
201   Emit(BRAAZ | Rn(xn) | Rd_mask);
202 }
203 
brabz(const Register & xn)204 void Assembler::brabz(const Register& xn) {
205   VIXL_ASSERT(CPUHas(CPUFeatures::kPAuth));
206   VIXL_ASSERT(xn.Is64Bits());
207   Emit(BRABZ | Rn(xn) | Rd_mask);
208 }
209 
blraaz(const Register & xn)210 void Assembler::blraaz(const Register& xn) {
211   VIXL_ASSERT(CPUHas(CPUFeatures::kPAuth));
212   VIXL_ASSERT(xn.Is64Bits());
213   Emit(BLRAAZ | Rn(xn) | Rd_mask);
214 }
215 
blrabz(const Register & xn)216 void Assembler::blrabz(const Register& xn) {
217   VIXL_ASSERT(CPUHas(CPUFeatures::kPAuth));
218   VIXL_ASSERT(xn.Is64Bits());
219   Emit(BLRABZ | Rn(xn) | Rd_mask);
220 }
221 
retaa()222 void Assembler::retaa() {
223   VIXL_ASSERT(CPUHas(CPUFeatures::kPAuth));
224   Emit(RETAA | Rn_mask | Rd_mask);
225 }
226 
retab()227 void Assembler::retab() {
228   VIXL_ASSERT(CPUHas(CPUFeatures::kPAuth));
229   Emit(RETAB | Rn_mask | Rd_mask);
230 }
231 
232 // The Arm ARM names the register Xm but encodes it in the Xd bitfield.
braa(const Register & xn,const Register & xm)233 void Assembler::braa(const Register& xn, const Register& xm) {
234   VIXL_ASSERT(CPUHas(CPUFeatures::kPAuth));
235   VIXL_ASSERT(xn.Is64Bits() && xm.Is64Bits());
236   Emit(BRAA | Rn(xn) | RdSP(xm));
237 }
238 
brab(const Register & xn,const Register & xm)239 void Assembler::brab(const Register& xn, const Register& xm) {
240   VIXL_ASSERT(CPUHas(CPUFeatures::kPAuth));
241   VIXL_ASSERT(xn.Is64Bits() && xm.Is64Bits());
242   Emit(BRAB | Rn(xn) | RdSP(xm));
243 }
244 
blraa(const Register & xn,const Register & xm)245 void Assembler::blraa(const Register& xn, const Register& xm) {
246   VIXL_ASSERT(CPUHas(CPUFeatures::kPAuth));
247   VIXL_ASSERT(xn.Is64Bits() && xm.Is64Bits());
248   Emit(BLRAA | Rn(xn) | RdSP(xm));
249 }
250 
blrab(const Register & xn,const Register & xm)251 void Assembler::blrab(const Register& xn, const Register& xm) {
252   VIXL_ASSERT(CPUHas(CPUFeatures::kPAuth));
253   VIXL_ASSERT(xn.Is64Bits() && xm.Is64Bits());
254   Emit(BLRAB | Rn(xn) | RdSP(xm));
255 }
256 
257 
b(int64_t imm26)258 void Assembler::b(int64_t imm26) { Emit(B | ImmUncondBranch(imm26)); }
259 
260 
b(int64_t imm19,Condition cond)261 void Assembler::b(int64_t imm19, Condition cond) {
262   Emit(B_cond | ImmCondBranch(imm19) | cond);
263 }
264 
265 
b(Label * label)266 void Assembler::b(Label* label) {
267   int64_t offset = LinkAndGetInstructionOffsetTo(label);
268   VIXL_ASSERT(Instruction::IsValidImmPCOffset(UncondBranchType, offset));
269   b(static_cast<int>(offset));
270 }
271 
272 
b(Label * label,Condition cond)273 void Assembler::b(Label* label, Condition cond) {
274   int64_t offset = LinkAndGetInstructionOffsetTo(label);
275   VIXL_ASSERT(Instruction::IsValidImmPCOffset(CondBranchType, offset));
276   b(static_cast<int>(offset), cond);
277 }
278 
279 
bl(int64_t imm26)280 void Assembler::bl(int64_t imm26) { Emit(BL | ImmUncondBranch(imm26)); }
281 
282 
bl(Label * label)283 void Assembler::bl(Label* label) {
284   int64_t offset = LinkAndGetInstructionOffsetTo(label);
285   VIXL_ASSERT(Instruction::IsValidImmPCOffset(UncondBranchType, offset));
286   bl(static_cast<int>(offset));
287 }
288 
289 
cbz(const Register & rt,int64_t imm19)290 void Assembler::cbz(const Register& rt, int64_t imm19) {
291   Emit(SF(rt) | CBZ | ImmCmpBranch(imm19) | Rt(rt));
292 }
293 
294 
cbz(const Register & rt,Label * label)295 void Assembler::cbz(const Register& rt, Label* label) {
296   int64_t offset = LinkAndGetInstructionOffsetTo(label);
297   VIXL_ASSERT(Instruction::IsValidImmPCOffset(CompareBranchType, offset));
298   cbz(rt, static_cast<int>(offset));
299 }
300 
301 
cbnz(const Register & rt,int64_t imm19)302 void Assembler::cbnz(const Register& rt, int64_t imm19) {
303   Emit(SF(rt) | CBNZ | ImmCmpBranch(imm19) | Rt(rt));
304 }
305 
306 
cbnz(const Register & rt,Label * label)307 void Assembler::cbnz(const Register& rt, Label* label) {
308   int64_t offset = LinkAndGetInstructionOffsetTo(label);
309   VIXL_ASSERT(Instruction::IsValidImmPCOffset(CompareBranchType, offset));
310   cbnz(rt, static_cast<int>(offset));
311 }
312 
313 
NEONTable(const VRegister & vd,const VRegister & vn,const VRegister & vm,NEONTableOp op)314 void Assembler::NEONTable(const VRegister& vd,
315                           const VRegister& vn,
316                           const VRegister& vm,
317                           NEONTableOp op) {
318   VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));
319   VIXL_ASSERT(vd.Is16B() || vd.Is8B());
320   VIXL_ASSERT(vn.Is16B());
321   VIXL_ASSERT(AreSameFormat(vd, vm));
322   Emit(op | (vd.IsQ() ? NEON_Q : 0) | Rm(vm) | Rn(vn) | Rd(vd));
323 }
324 
325 
tbl(const VRegister & vd,const VRegister & vn,const VRegister & vm)326 void Assembler::tbl(const VRegister& vd,
327                     const VRegister& vn,
328                     const VRegister& vm) {
329   VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));
330   NEONTable(vd, vn, vm, NEON_TBL_1v);
331 }
332 
333 
tbl(const VRegister & vd,const VRegister & vn,const VRegister & vn2,const VRegister & vm)334 void Assembler::tbl(const VRegister& vd,
335                     const VRegister& vn,
336                     const VRegister& vn2,
337                     const VRegister& vm) {
338   USE(vn2);
339   VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));
340   VIXL_ASSERT(AreSameFormat(vn, vn2));
341   VIXL_ASSERT(AreConsecutive(vn, vn2));
342   NEONTable(vd, vn, vm, NEON_TBL_2v);
343 }
344 
345 
tbl(const VRegister & vd,const VRegister & vn,const VRegister & vn2,const VRegister & vn3,const VRegister & vm)346 void Assembler::tbl(const VRegister& vd,
347                     const VRegister& vn,
348                     const VRegister& vn2,
349                     const VRegister& vn3,
350                     const VRegister& vm) {
351   USE(vn2, vn3);
352   VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));
353   VIXL_ASSERT(AreSameFormat(vn, vn2, vn3));
354   VIXL_ASSERT(AreConsecutive(vn, vn2, vn3));
355   NEONTable(vd, vn, vm, NEON_TBL_3v);
356 }
357 
358 
tbl(const VRegister & vd,const VRegister & vn,const VRegister & vn2,const VRegister & vn3,const VRegister & vn4,const VRegister & vm)359 void Assembler::tbl(const VRegister& vd,
360                     const VRegister& vn,
361                     const VRegister& vn2,
362                     const VRegister& vn3,
363                     const VRegister& vn4,
364                     const VRegister& vm) {
365   USE(vn2, vn3, vn4);
366   VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));
367   VIXL_ASSERT(AreSameFormat(vn, vn2, vn3, vn4));
368   VIXL_ASSERT(AreConsecutive(vn, vn2, vn3, vn4));
369   NEONTable(vd, vn, vm, NEON_TBL_4v);
370 }
371 
372 
tbx(const VRegister & vd,const VRegister & vn,const VRegister & vm)373 void Assembler::tbx(const VRegister& vd,
374                     const VRegister& vn,
375                     const VRegister& vm) {
376   VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));
377   NEONTable(vd, vn, vm, NEON_TBX_1v);
378 }
379 
380 
tbx(const VRegister & vd,const VRegister & vn,const VRegister & vn2,const VRegister & vm)381 void Assembler::tbx(const VRegister& vd,
382                     const VRegister& vn,
383                     const VRegister& vn2,
384                     const VRegister& vm) {
385   USE(vn2);
386   VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));
387   VIXL_ASSERT(AreSameFormat(vn, vn2));
388   VIXL_ASSERT(AreConsecutive(vn, vn2));
389   NEONTable(vd, vn, vm, NEON_TBX_2v);
390 }
391 
392 
tbx(const VRegister & vd,const VRegister & vn,const VRegister & vn2,const VRegister & vn3,const VRegister & vm)393 void Assembler::tbx(const VRegister& vd,
394                     const VRegister& vn,
395                     const VRegister& vn2,
396                     const VRegister& vn3,
397                     const VRegister& vm) {
398   USE(vn2, vn3);
399   VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));
400   VIXL_ASSERT(AreSameFormat(vn, vn2, vn3));
401   VIXL_ASSERT(AreConsecutive(vn, vn2, vn3));
402   NEONTable(vd, vn, vm, NEON_TBX_3v);
403 }
404 
405 
tbx(const VRegister & vd,const VRegister & vn,const VRegister & vn2,const VRegister & vn3,const VRegister & vn4,const VRegister & vm)406 void Assembler::tbx(const VRegister& vd,
407                     const VRegister& vn,
408                     const VRegister& vn2,
409                     const VRegister& vn3,
410                     const VRegister& vn4,
411                     const VRegister& vm) {
412   USE(vn2, vn3, vn4);
413   VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));
414   VIXL_ASSERT(AreSameFormat(vn, vn2, vn3, vn4));
415   VIXL_ASSERT(AreConsecutive(vn, vn2, vn3, vn4));
416   NEONTable(vd, vn, vm, NEON_TBX_4v);
417 }
418 
419 
tbz(const Register & rt,unsigned bit_pos,int64_t imm14)420 void Assembler::tbz(const Register& rt, unsigned bit_pos, int64_t imm14) {
421   VIXL_ASSERT(rt.Is64Bits() || (rt.Is32Bits() && (bit_pos < kWRegSize)));
422   Emit(TBZ | ImmTestBranchBit(bit_pos) | ImmTestBranch(imm14) | Rt(rt));
423 }
424 
425 
tbz(const Register & rt,unsigned bit_pos,Label * label)426 void Assembler::tbz(const Register& rt, unsigned bit_pos, Label* label) {
427   ptrdiff_t offset = LinkAndGetInstructionOffsetTo(label);
428   VIXL_ASSERT(Instruction::IsValidImmPCOffset(TestBranchType, offset));
429   tbz(rt, bit_pos, static_cast<int>(offset));
430 }
431 
432 
tbnz(const Register & rt,unsigned bit_pos,int64_t imm14)433 void Assembler::tbnz(const Register& rt, unsigned bit_pos, int64_t imm14) {
434   VIXL_ASSERT(rt.Is64Bits() || (rt.Is32Bits() && (bit_pos < kWRegSize)));
435   Emit(TBNZ | ImmTestBranchBit(bit_pos) | ImmTestBranch(imm14) | Rt(rt));
436 }
437 
438 
tbnz(const Register & rt,unsigned bit_pos,Label * label)439 void Assembler::tbnz(const Register& rt, unsigned bit_pos, Label* label) {
440   ptrdiff_t offset = LinkAndGetInstructionOffsetTo(label);
441   VIXL_ASSERT(Instruction::IsValidImmPCOffset(TestBranchType, offset));
442   tbnz(rt, bit_pos, static_cast<int>(offset));
443 }
444 
445 
adr(const Register & xd,int64_t imm21)446 void Assembler::adr(const Register& xd, int64_t imm21) {
447   VIXL_ASSERT(xd.Is64Bits());
448   Emit(ADR | ImmPCRelAddress(imm21) | Rd(xd));
449 }
450 
451 
adr(const Register & xd,Label * label)452 void Assembler::adr(const Register& xd, Label* label) {
453   adr(xd, static_cast<int>(LinkAndGetByteOffsetTo(label)));
454 }
455 
456 
adrp(const Register & xd,int64_t imm21)457 void Assembler::adrp(const Register& xd, int64_t imm21) {
458   VIXL_ASSERT(xd.Is64Bits());
459   Emit(ADRP | ImmPCRelAddress(imm21) | Rd(xd));
460 }
461 
462 
adrp(const Register & xd,Label * label)463 void Assembler::adrp(const Register& xd, Label* label) {
464   VIXL_ASSERT(AllowPageOffsetDependentCode());
465   adrp(xd, static_cast<int>(LinkAndGetPageOffsetTo(label)));
466 }
467 
468 
add(const Register & rd,const Register & rn,const Operand & operand)469 void Assembler::add(const Register& rd,
470                     const Register& rn,
471                     const Operand& operand) {
472   AddSub(rd, rn, operand, LeaveFlags, ADD);
473 }
474 
475 
adds(const Register & rd,const Register & rn,const Operand & operand)476 void Assembler::adds(const Register& rd,
477                      const Register& rn,
478                      const Operand& operand) {
479   AddSub(rd, rn, operand, SetFlags, ADD);
480 }
481 
482 
cmn(const Register & rn,const Operand & operand)483 void Assembler::cmn(const Register& rn, const Operand& operand) {
484   Register zr = AppropriateZeroRegFor(rn);
485   adds(zr, rn, operand);
486 }
487 
488 
sub(const Register & rd,const Register & rn,const Operand & operand)489 void Assembler::sub(const Register& rd,
490                     const Register& rn,
491                     const Operand& operand) {
492   AddSub(rd, rn, operand, LeaveFlags, SUB);
493 }
494 
495 
subs(const Register & rd,const Register & rn,const Operand & operand)496 void Assembler::subs(const Register& rd,
497                      const Register& rn,
498                      const Operand& operand) {
499   AddSub(rd, rn, operand, SetFlags, SUB);
500 }
501 
502 
cmp(const Register & rn,const Operand & operand)503 void Assembler::cmp(const Register& rn, const Operand& operand) {
504   Register zr = AppropriateZeroRegFor(rn);
505   subs(zr, rn, operand);
506 }
507 
508 
neg(const Register & rd,const Operand & operand)509 void Assembler::neg(const Register& rd, const Operand& operand) {
510   Register zr = AppropriateZeroRegFor(rd);
511   sub(rd, zr, operand);
512 }
513 
514 
negs(const Register & rd,const Operand & operand)515 void Assembler::negs(const Register& rd, const Operand& operand) {
516   Register zr = AppropriateZeroRegFor(rd);
517   subs(rd, zr, operand);
518 }
519 
520 
adc(const Register & rd,const Register & rn,const Operand & operand)521 void Assembler::adc(const Register& rd,
522                     const Register& rn,
523                     const Operand& operand) {
524   AddSubWithCarry(rd, rn, operand, LeaveFlags, ADC);
525 }
526 
527 
adcs(const Register & rd,const Register & rn,const Operand & operand)528 void Assembler::adcs(const Register& rd,
529                      const Register& rn,
530                      const Operand& operand) {
531   AddSubWithCarry(rd, rn, operand, SetFlags, ADC);
532 }
533 
534 
sbc(const Register & rd,const Register & rn,const Operand & operand)535 void Assembler::sbc(const Register& rd,
536                     const Register& rn,
537                     const Operand& operand) {
538   AddSubWithCarry(rd, rn, operand, LeaveFlags, SBC);
539 }
540 
541 
sbcs(const Register & rd,const Register & rn,const Operand & operand)542 void Assembler::sbcs(const Register& rd,
543                      const Register& rn,
544                      const Operand& operand) {
545   AddSubWithCarry(rd, rn, operand, SetFlags, SBC);
546 }
547 
548 
rmif(const Register & xn,unsigned rotation,StatusFlags flags)549 void Assembler::rmif(const Register& xn, unsigned rotation, StatusFlags flags) {
550   VIXL_ASSERT(CPUHas(CPUFeatures::kFlagM));
551   VIXL_ASSERT(xn.Is64Bits());
552   Emit(RMIF | Rn(xn) | ImmRMIFRotation(rotation) | Nzcv(flags));
553 }
554 
555 
setf8(const Register & rn)556 void Assembler::setf8(const Register& rn) {
557   VIXL_ASSERT(CPUHas(CPUFeatures::kFlagM));
558   Emit(SETF8 | Rn(rn));
559 }
560 
561 
setf16(const Register & rn)562 void Assembler::setf16(const Register& rn) {
563   VIXL_ASSERT(CPUHas(CPUFeatures::kFlagM));
564   Emit(SETF16 | Rn(rn));
565 }
566 
567 
ngc(const Register & rd,const Operand & operand)568 void Assembler::ngc(const Register& rd, const Operand& operand) {
569   Register zr = AppropriateZeroRegFor(rd);
570   sbc(rd, zr, operand);
571 }
572 
573 
ngcs(const Register & rd,const Operand & operand)574 void Assembler::ngcs(const Register& rd, const Operand& operand) {
575   Register zr = AppropriateZeroRegFor(rd);
576   sbcs(rd, zr, operand);
577 }
578 
579 
580 // Logical instructions.
and_(const Register & rd,const Register & rn,const Operand & operand)581 void Assembler::and_(const Register& rd,
582                      const Register& rn,
583                      const Operand& operand) {
584   Logical(rd, rn, operand, AND);
585 }
586 
587 
ands(const Register & rd,const Register & rn,const Operand & operand)588 void Assembler::ands(const Register& rd,
589                      const Register& rn,
590                      const Operand& operand) {
591   Logical(rd, rn, operand, ANDS);
592 }
593 
594 
tst(const Register & rn,const Operand & operand)595 void Assembler::tst(const Register& rn, const Operand& operand) {
596   ands(AppropriateZeroRegFor(rn), rn, operand);
597 }
598 
599 
bic(const Register & rd,const Register & rn,const Operand & operand)600 void Assembler::bic(const Register& rd,
601                     const Register& rn,
602                     const Operand& operand) {
603   Logical(rd, rn, operand, BIC);
604 }
605 
606 
bics(const Register & rd,const Register & rn,const Operand & operand)607 void Assembler::bics(const Register& rd,
608                      const Register& rn,
609                      const Operand& operand) {
610   Logical(rd, rn, operand, BICS);
611 }
612 
613 
orr(const Register & rd,const Register & rn,const Operand & operand)614 void Assembler::orr(const Register& rd,
615                     const Register& rn,
616                     const Operand& operand) {
617   Logical(rd, rn, operand, ORR);
618 }
619 
620 
orn(const Register & rd,const Register & rn,const Operand & operand)621 void Assembler::orn(const Register& rd,
622                     const Register& rn,
623                     const Operand& operand) {
624   Logical(rd, rn, operand, ORN);
625 }
626 
627 
eor(const Register & rd,const Register & rn,const Operand & operand)628 void Assembler::eor(const Register& rd,
629                     const Register& rn,
630                     const Operand& operand) {
631   Logical(rd, rn, operand, EOR);
632 }
633 
634 
eon(const Register & rd,const Register & rn,const Operand & operand)635 void Assembler::eon(const Register& rd,
636                     const Register& rn,
637                     const Operand& operand) {
638   Logical(rd, rn, operand, EON);
639 }
640 
641 
lslv(const Register & rd,const Register & rn,const Register & rm)642 void Assembler::lslv(const Register& rd,
643                      const Register& rn,
644                      const Register& rm) {
645   VIXL_ASSERT(rd.GetSizeInBits() == rn.GetSizeInBits());
646   VIXL_ASSERT(rd.GetSizeInBits() == rm.GetSizeInBits());
647   Emit(SF(rd) | LSLV | Rm(rm) | Rn(rn) | Rd(rd));
648 }
649 
650 
lsrv(const Register & rd,const Register & rn,const Register & rm)651 void Assembler::lsrv(const Register& rd,
652                      const Register& rn,
653                      const Register& rm) {
654   VIXL_ASSERT(rd.GetSizeInBits() == rn.GetSizeInBits());
655   VIXL_ASSERT(rd.GetSizeInBits() == rm.GetSizeInBits());
656   Emit(SF(rd) | LSRV | Rm(rm) | Rn(rn) | Rd(rd));
657 }
658 
659 
asrv(const Register & rd,const Register & rn,const Register & rm)660 void Assembler::asrv(const Register& rd,
661                      const Register& rn,
662                      const Register& rm) {
663   VIXL_ASSERT(rd.GetSizeInBits() == rn.GetSizeInBits());
664   VIXL_ASSERT(rd.GetSizeInBits() == rm.GetSizeInBits());
665   Emit(SF(rd) | ASRV | Rm(rm) | Rn(rn) | Rd(rd));
666 }
667 
668 
rorv(const Register & rd,const Register & rn,const Register & rm)669 void Assembler::rorv(const Register& rd,
670                      const Register& rn,
671                      const Register& rm) {
672   VIXL_ASSERT(rd.GetSizeInBits() == rn.GetSizeInBits());
673   VIXL_ASSERT(rd.GetSizeInBits() == rm.GetSizeInBits());
674   Emit(SF(rd) | RORV | Rm(rm) | Rn(rn) | Rd(rd));
675 }
676 
677 
678 // Bitfield operations.
bfm(const Register & rd,const Register & rn,unsigned immr,unsigned imms)679 void Assembler::bfm(const Register& rd,
680                     const Register& rn,
681                     unsigned immr,
682                     unsigned imms) {
683   VIXL_ASSERT(rd.GetSizeInBits() == rn.GetSizeInBits());
684   Instr N = SF(rd) >> (kSFOffset - kBitfieldNOffset);
685   Emit(SF(rd) | BFM | N | ImmR(immr, rd.GetSizeInBits()) |
686        ImmS(imms, rn.GetSizeInBits()) | Rn(rn) | Rd(rd));
687 }
688 
689 
sbfm(const Register & rd,const Register & rn,unsigned immr,unsigned imms)690 void Assembler::sbfm(const Register& rd,
691                      const Register& rn,
692                      unsigned immr,
693                      unsigned imms) {
694   VIXL_ASSERT(rd.Is64Bits() || rn.Is32Bits());
695   Instr N = SF(rd) >> (kSFOffset - kBitfieldNOffset);
696   Emit(SF(rd) | SBFM | N | ImmR(immr, rd.GetSizeInBits()) |
697        ImmS(imms, rn.GetSizeInBits()) | Rn(rn) | Rd(rd));
698 }
699 
700 
ubfm(const Register & rd,const Register & rn,unsigned immr,unsigned imms)701 void Assembler::ubfm(const Register& rd,
702                      const Register& rn,
703                      unsigned immr,
704                      unsigned imms) {
705   VIXL_ASSERT(rd.GetSizeInBits() == rn.GetSizeInBits());
706   Instr N = SF(rd) >> (kSFOffset - kBitfieldNOffset);
707   Emit(SF(rd) | UBFM | N | ImmR(immr, rd.GetSizeInBits()) |
708        ImmS(imms, rn.GetSizeInBits()) | Rn(rn) | Rd(rd));
709 }
710 
711 
extr(const Register & rd,const Register & rn,const Register & rm,unsigned lsb)712 void Assembler::extr(const Register& rd,
713                      const Register& rn,
714                      const Register& rm,
715                      unsigned lsb) {
716   VIXL_ASSERT(rd.GetSizeInBits() == rn.GetSizeInBits());
717   VIXL_ASSERT(rd.GetSizeInBits() == rm.GetSizeInBits());
718   Instr N = SF(rd) >> (kSFOffset - kBitfieldNOffset);
719   Emit(SF(rd) | EXTR | N | Rm(rm) | ImmS(lsb, rn.GetSizeInBits()) | Rn(rn) |
720        Rd(rd));
721 }
722 
723 
csel(const Register & rd,const Register & rn,const Register & rm,Condition cond)724 void Assembler::csel(const Register& rd,
725                      const Register& rn,
726                      const Register& rm,
727                      Condition cond) {
728   ConditionalSelect(rd, rn, rm, cond, CSEL);
729 }
730 
731 
csinc(const Register & rd,const Register & rn,const Register & rm,Condition cond)732 void Assembler::csinc(const Register& rd,
733                       const Register& rn,
734                       const Register& rm,
735                       Condition cond) {
736   ConditionalSelect(rd, rn, rm, cond, CSINC);
737 }
738 
739 
csinv(const Register & rd,const Register & rn,const Register & rm,Condition cond)740 void Assembler::csinv(const Register& rd,
741                       const Register& rn,
742                       const Register& rm,
743                       Condition cond) {
744   ConditionalSelect(rd, rn, rm, cond, CSINV);
745 }
746 
747 
csneg(const Register & rd,const Register & rn,const Register & rm,Condition cond)748 void Assembler::csneg(const Register& rd,
749                       const Register& rn,
750                       const Register& rm,
751                       Condition cond) {
752   ConditionalSelect(rd, rn, rm, cond, CSNEG);
753 }
754 
755 
cset(const Register & rd,Condition cond)756 void Assembler::cset(const Register& rd, Condition cond) {
757   VIXL_ASSERT((cond != al) && (cond != nv));
758   Register zr = AppropriateZeroRegFor(rd);
759   csinc(rd, zr, zr, InvertCondition(cond));
760 }
761 
762 
csetm(const Register & rd,Condition cond)763 void Assembler::csetm(const Register& rd, Condition cond) {
764   VIXL_ASSERT((cond != al) && (cond != nv));
765   Register zr = AppropriateZeroRegFor(rd);
766   csinv(rd, zr, zr, InvertCondition(cond));
767 }
768 
769 
cinc(const Register & rd,const Register & rn,Condition cond)770 void Assembler::cinc(const Register& rd, const Register& rn, Condition cond) {
771   VIXL_ASSERT((cond != al) && (cond != nv));
772   csinc(rd, rn, rn, InvertCondition(cond));
773 }
774 
775 
cinv(const Register & rd,const Register & rn,Condition cond)776 void Assembler::cinv(const Register& rd, const Register& rn, Condition cond) {
777   VIXL_ASSERT((cond != al) && (cond != nv));
778   csinv(rd, rn, rn, InvertCondition(cond));
779 }
780 
781 
cneg(const Register & rd,const Register & rn,Condition cond)782 void Assembler::cneg(const Register& rd, const Register& rn, Condition cond) {
783   VIXL_ASSERT((cond != al) && (cond != nv));
784   csneg(rd, rn, rn, InvertCondition(cond));
785 }
786 
787 
ConditionalSelect(const Register & rd,const Register & rn,const Register & rm,Condition cond,ConditionalSelectOp op)788 void Assembler::ConditionalSelect(const Register& rd,
789                                   const Register& rn,
790                                   const Register& rm,
791                                   Condition cond,
792                                   ConditionalSelectOp op) {
793   VIXL_ASSERT(rd.GetSizeInBits() == rn.GetSizeInBits());
794   VIXL_ASSERT(rd.GetSizeInBits() == rm.GetSizeInBits());
795   Emit(SF(rd) | op | Rm(rm) | Cond(cond) | Rn(rn) | Rd(rd));
796 }
797 
798 
ccmn(const Register & rn,const Operand & operand,StatusFlags nzcv,Condition cond)799 void Assembler::ccmn(const Register& rn,
800                      const Operand& operand,
801                      StatusFlags nzcv,
802                      Condition cond) {
803   ConditionalCompare(rn, operand, nzcv, cond, CCMN);
804 }
805 
806 
ccmp(const Register & rn,const Operand & operand,StatusFlags nzcv,Condition cond)807 void Assembler::ccmp(const Register& rn,
808                      const Operand& operand,
809                      StatusFlags nzcv,
810                      Condition cond) {
811   ConditionalCompare(rn, operand, nzcv, cond, CCMP);
812 }
813 
814 
DataProcessing3Source(const Register & rd,const Register & rn,const Register & rm,const Register & ra,DataProcessing3SourceOp op)815 void Assembler::DataProcessing3Source(const Register& rd,
816                                       const Register& rn,
817                                       const Register& rm,
818                                       const Register& ra,
819                                       DataProcessing3SourceOp op) {
820   Emit(SF(rd) | op | Rm(rm) | Ra(ra) | Rn(rn) | Rd(rd));
821 }
822 
823 
crc32b(const Register & wd,const Register & wn,const Register & wm)824 void Assembler::crc32b(const Register& wd,
825                        const Register& wn,
826                        const Register& wm) {
827   VIXL_ASSERT(CPUHas(CPUFeatures::kCRC32));
828   VIXL_ASSERT(wd.Is32Bits() && wn.Is32Bits() && wm.Is32Bits());
829   Emit(SF(wm) | Rm(wm) | CRC32B | Rn(wn) | Rd(wd));
830 }
831 
832 
crc32h(const Register & wd,const Register & wn,const Register & wm)833 void Assembler::crc32h(const Register& wd,
834                        const Register& wn,
835                        const Register& wm) {
836   VIXL_ASSERT(CPUHas(CPUFeatures::kCRC32));
837   VIXL_ASSERT(wd.Is32Bits() && wn.Is32Bits() && wm.Is32Bits());
838   Emit(SF(wm) | Rm(wm) | CRC32H | Rn(wn) | Rd(wd));
839 }
840 
841 
crc32w(const Register & wd,const Register & wn,const Register & wm)842 void Assembler::crc32w(const Register& wd,
843                        const Register& wn,
844                        const Register& wm) {
845   VIXL_ASSERT(CPUHas(CPUFeatures::kCRC32));
846   VIXL_ASSERT(wd.Is32Bits() && wn.Is32Bits() && wm.Is32Bits());
847   Emit(SF(wm) | Rm(wm) | CRC32W | Rn(wn) | Rd(wd));
848 }
849 
850 
crc32x(const Register & wd,const Register & wn,const Register & xm)851 void Assembler::crc32x(const Register& wd,
852                        const Register& wn,
853                        const Register& xm) {
854   VIXL_ASSERT(CPUHas(CPUFeatures::kCRC32));
855   VIXL_ASSERT(wd.Is32Bits() && wn.Is32Bits() && xm.Is64Bits());
856   Emit(SF(xm) | Rm(xm) | CRC32X | Rn(wn) | Rd(wd));
857 }
858 
859 
crc32cb(const Register & wd,const Register & wn,const Register & wm)860 void Assembler::crc32cb(const Register& wd,
861                         const Register& wn,
862                         const Register& wm) {
863   VIXL_ASSERT(CPUHas(CPUFeatures::kCRC32));
864   VIXL_ASSERT(wd.Is32Bits() && wn.Is32Bits() && wm.Is32Bits());
865   Emit(SF(wm) | Rm(wm) | CRC32CB | Rn(wn) | Rd(wd));
866 }
867 
868 
crc32ch(const Register & wd,const Register & wn,const Register & wm)869 void Assembler::crc32ch(const Register& wd,
870                         const Register& wn,
871                         const Register& wm) {
872   VIXL_ASSERT(CPUHas(CPUFeatures::kCRC32));
873   VIXL_ASSERT(wd.Is32Bits() && wn.Is32Bits() && wm.Is32Bits());
874   Emit(SF(wm) | Rm(wm) | CRC32CH | Rn(wn) | Rd(wd));
875 }
876 
877 
crc32cw(const Register & wd,const Register & wn,const Register & wm)878 void Assembler::crc32cw(const Register& wd,
879                         const Register& wn,
880                         const Register& wm) {
881   VIXL_ASSERT(CPUHas(CPUFeatures::kCRC32));
882   VIXL_ASSERT(wd.Is32Bits() && wn.Is32Bits() && wm.Is32Bits());
883   Emit(SF(wm) | Rm(wm) | CRC32CW | Rn(wn) | Rd(wd));
884 }
885 
886 
crc32cx(const Register & wd,const Register & wn,const Register & xm)887 void Assembler::crc32cx(const Register& wd,
888                         const Register& wn,
889                         const Register& xm) {
890   VIXL_ASSERT(CPUHas(CPUFeatures::kCRC32));
891   VIXL_ASSERT(wd.Is32Bits() && wn.Is32Bits() && xm.Is64Bits());
892   Emit(SF(xm) | Rm(xm) | CRC32CX | Rn(wn) | Rd(wd));
893 }
894 
895 
mul(const Register & rd,const Register & rn,const Register & rm)896 void Assembler::mul(const Register& rd,
897                     const Register& rn,
898                     const Register& rm) {
899   VIXL_ASSERT(AreSameSizeAndType(rd, rn, rm));
900   DataProcessing3Source(rd, rn, rm, AppropriateZeroRegFor(rd), MADD);
901 }
902 
903 
madd(const Register & rd,const Register & rn,const Register & rm,const Register & ra)904 void Assembler::madd(const Register& rd,
905                      const Register& rn,
906                      const Register& rm,
907                      const Register& ra) {
908   DataProcessing3Source(rd, rn, rm, ra, MADD);
909 }
910 
911 
mneg(const Register & rd,const Register & rn,const Register & rm)912 void Assembler::mneg(const Register& rd,
913                      const Register& rn,
914                      const Register& rm) {
915   VIXL_ASSERT(AreSameSizeAndType(rd, rn, rm));
916   DataProcessing3Source(rd, rn, rm, AppropriateZeroRegFor(rd), MSUB);
917 }
918 
919 
msub(const Register & rd,const Register & rn,const Register & rm,const Register & ra)920 void Assembler::msub(const Register& rd,
921                      const Register& rn,
922                      const Register& rm,
923                      const Register& ra) {
924   DataProcessing3Source(rd, rn, rm, ra, MSUB);
925 }
926 
927 
umaddl(const Register & xd,const Register & wn,const Register & wm,const Register & xa)928 void Assembler::umaddl(const Register& xd,
929                        const Register& wn,
930                        const Register& wm,
931                        const Register& xa) {
932   VIXL_ASSERT(xd.Is64Bits() && xa.Is64Bits());
933   VIXL_ASSERT(wn.Is32Bits() && wm.Is32Bits());
934   DataProcessing3Source(xd, wn, wm, xa, UMADDL_x);
935 }
936 
937 
smaddl(const Register & xd,const Register & wn,const Register & wm,const Register & xa)938 void Assembler::smaddl(const Register& xd,
939                        const Register& wn,
940                        const Register& wm,
941                        const Register& xa) {
942   VIXL_ASSERT(xd.Is64Bits() && xa.Is64Bits());
943   VIXL_ASSERT(wn.Is32Bits() && wm.Is32Bits());
944   DataProcessing3Source(xd, wn, wm, xa, SMADDL_x);
945 }
946 
947 
umsubl(const Register & xd,const Register & wn,const Register & wm,const Register & xa)948 void Assembler::umsubl(const Register& xd,
949                        const Register& wn,
950                        const Register& wm,
951                        const Register& xa) {
952   VIXL_ASSERT(xd.Is64Bits() && xa.Is64Bits());
953   VIXL_ASSERT(wn.Is32Bits() && wm.Is32Bits());
954   DataProcessing3Source(xd, wn, wm, xa, UMSUBL_x);
955 }
956 
957 
smsubl(const Register & xd,const Register & wn,const Register & wm,const Register & xa)958 void Assembler::smsubl(const Register& xd,
959                        const Register& wn,
960                        const Register& wm,
961                        const Register& xa) {
962   VIXL_ASSERT(xd.Is64Bits() && xa.Is64Bits());
963   VIXL_ASSERT(wn.Is32Bits() && wm.Is32Bits());
964   DataProcessing3Source(xd, wn, wm, xa, SMSUBL_x);
965 }
966 
967 
smull(const Register & xd,const Register & wn,const Register & wm)968 void Assembler::smull(const Register& xd,
969                       const Register& wn,
970                       const Register& wm) {
971   VIXL_ASSERT(xd.Is64Bits());
972   VIXL_ASSERT(wn.Is32Bits() && wm.Is32Bits());
973   DataProcessing3Source(xd, wn, wm, xzr, SMADDL_x);
974 }
975 
976 
sdiv(const Register & rd,const Register & rn,const Register & rm)977 void Assembler::sdiv(const Register& rd,
978                      const Register& rn,
979                      const Register& rm) {
980   VIXL_ASSERT(rd.GetSizeInBits() == rn.GetSizeInBits());
981   VIXL_ASSERT(rd.GetSizeInBits() == rm.GetSizeInBits());
982   Emit(SF(rd) | SDIV | Rm(rm) | Rn(rn) | Rd(rd));
983 }
984 
985 
smulh(const Register & xd,const Register & xn,const Register & xm)986 void Assembler::smulh(const Register& xd,
987                       const Register& xn,
988                       const Register& xm) {
989   VIXL_ASSERT(xd.Is64Bits() && xn.Is64Bits() && xm.Is64Bits());
990   DataProcessing3Source(xd, xn, xm, xzr, SMULH_x);
991 }
992 
993 
umulh(const Register & xd,const Register & xn,const Register & xm)994 void Assembler::umulh(const Register& xd,
995                       const Register& xn,
996                       const Register& xm) {
997   VIXL_ASSERT(xd.Is64Bits() && xn.Is64Bits() && xm.Is64Bits());
998   DataProcessing3Source(xd, xn, xm, xzr, UMULH_x);
999 }
1000 
1001 
udiv(const Register & rd,const Register & rn,const Register & rm)1002 void Assembler::udiv(const Register& rd,
1003                      const Register& rn,
1004                      const Register& rm) {
1005   VIXL_ASSERT(rd.GetSizeInBits() == rn.GetSizeInBits());
1006   VIXL_ASSERT(rd.GetSizeInBits() == rm.GetSizeInBits());
1007   Emit(SF(rd) | UDIV | Rm(rm) | Rn(rn) | Rd(rd));
1008 }
1009 
1010 
rbit(const Register & rd,const Register & rn)1011 void Assembler::rbit(const Register& rd, const Register& rn) {
1012   DataProcessing1Source(rd, rn, RBIT);
1013 }
1014 
1015 
rev16(const Register & rd,const Register & rn)1016 void Assembler::rev16(const Register& rd, const Register& rn) {
1017   DataProcessing1Source(rd, rn, REV16);
1018 }
1019 
1020 
rev32(const Register & xd,const Register & xn)1021 void Assembler::rev32(const Register& xd, const Register& xn) {
1022   VIXL_ASSERT(xd.Is64Bits());
1023   DataProcessing1Source(xd, xn, REV);
1024 }
1025 
1026 
rev(const Register & rd,const Register & rn)1027 void Assembler::rev(const Register& rd, const Register& rn) {
1028   DataProcessing1Source(rd, rn, rd.Is64Bits() ? REV_x : REV_w);
1029 }
1030 
1031 
clz(const Register & rd,const Register & rn)1032 void Assembler::clz(const Register& rd, const Register& rn) {
1033   DataProcessing1Source(rd, rn, CLZ);
1034 }
1035 
1036 
cls(const Register & rd,const Register & rn)1037 void Assembler::cls(const Register& rd, const Register& rn) {
1038   DataProcessing1Source(rd, rn, CLS);
1039 }
1040 
1041 #define PAUTH_VARIATIONS(V) \
1042   V(paci, PACI)             \
1043   V(pacd, PACD)             \
1044   V(auti, AUTI)             \
1045   V(autd, AUTD)
1046 
1047 #define DEFINE_ASM_FUNCS(PRE, OP)                                  \
1048   void Assembler::PRE##a(const Register& xd, const Register& xn) { \
1049     VIXL_ASSERT(CPUHas(CPUFeatures::kPAuth));                      \
1050     VIXL_ASSERT(xd.Is64Bits() && xn.Is64Bits());                   \
1051     Emit(SF(xd) | OP##A | Rd(xd) | RnSP(xn));                      \
1052   }                                                                \
1053                                                                    \
1054   void Assembler::PRE##za(const Register& xd) {                    \
1055     VIXL_ASSERT(CPUHas(CPUFeatures::kPAuth));                      \
1056     VIXL_ASSERT(xd.Is64Bits());                                    \
1057     Emit(SF(xd) | OP##ZA | Rd(xd));                                \
1058   }                                                                \
1059                                                                    \
1060   void Assembler::PRE##b(const Register& xd, const Register& xn) { \
1061     VIXL_ASSERT(CPUHas(CPUFeatures::kPAuth));                      \
1062     VIXL_ASSERT(xd.Is64Bits() && xn.Is64Bits());                   \
1063     Emit(SF(xd) | OP##B | Rd(xd) | RnSP(xn));                      \
1064   }                                                                \
1065                                                                    \
1066   void Assembler::PRE##zb(const Register& xd) {                    \
1067     VIXL_ASSERT(CPUHas(CPUFeatures::kPAuth));                      \
1068     VIXL_ASSERT(xd.Is64Bits());                                    \
1069     Emit(SF(xd) | OP##ZB | Rd(xd));                                \
1070   }
1071 
PAUTH_VARIATIONS(DEFINE_ASM_FUNCS)1072 PAUTH_VARIATIONS(DEFINE_ASM_FUNCS)
1073 #undef DEFINE_ASM_FUNCS
1074 
1075 void Assembler::pacga(const Register& xd,
1076                       const Register& xn,
1077                       const Register& xm) {
1078   VIXL_ASSERT(CPUHas(CPUFeatures::kPAuth, CPUFeatures::kPAuthGeneric));
1079   VIXL_ASSERT(xd.Is64Bits() && xn.Is64Bits() && xm.Is64Bits());
1080   Emit(SF(xd) | PACGA | Rd(xd) | Rn(xn) | RmSP(xm));
1081 }
1082 
xpaci(const Register & xd)1083 void Assembler::xpaci(const Register& xd) {
1084   VIXL_ASSERT(CPUHas(CPUFeatures::kPAuth));
1085   VIXL_ASSERT(xd.Is64Bits());
1086   Emit(SF(xd) | XPACI | Rd(xd));
1087 }
1088 
xpacd(const Register & xd)1089 void Assembler::xpacd(const Register& xd) {
1090   VIXL_ASSERT(CPUHas(CPUFeatures::kPAuth));
1091   VIXL_ASSERT(xd.Is64Bits());
1092   Emit(SF(xd) | XPACD | Rd(xd));
1093 }
1094 
1095 
ldp(const CPURegister & rt,const CPURegister & rt2,const MemOperand & src)1096 void Assembler::ldp(const CPURegister& rt,
1097                     const CPURegister& rt2,
1098                     const MemOperand& src) {
1099   LoadStorePair(rt, rt2, src, LoadPairOpFor(rt, rt2));
1100 }
1101 
1102 
stp(const CPURegister & rt,const CPURegister & rt2,const MemOperand & dst)1103 void Assembler::stp(const CPURegister& rt,
1104                     const CPURegister& rt2,
1105                     const MemOperand& dst) {
1106   LoadStorePair(rt, rt2, dst, StorePairOpFor(rt, rt2));
1107 }
1108 
1109 
ldpsw(const Register & xt,const Register & xt2,const MemOperand & src)1110 void Assembler::ldpsw(const Register& xt,
1111                       const Register& xt2,
1112                       const MemOperand& src) {
1113   VIXL_ASSERT(xt.Is64Bits() && xt2.Is64Bits());
1114   LoadStorePair(xt, xt2, src, LDPSW_x);
1115 }
1116 
1117 
LoadStorePair(const CPURegister & rt,const CPURegister & rt2,const MemOperand & addr,LoadStorePairOp op)1118 void Assembler::LoadStorePair(const CPURegister& rt,
1119                               const CPURegister& rt2,
1120                               const MemOperand& addr,
1121                               LoadStorePairOp op) {
1122   VIXL_ASSERT(CPUHas(rt, rt2));
1123 
1124   // 'rt' and 'rt2' can only be aliased for stores.
1125   VIXL_ASSERT(((op & LoadStorePairLBit) == 0) || !rt.Is(rt2));
1126   VIXL_ASSERT(AreSameSizeAndType(rt, rt2));
1127   VIXL_ASSERT(IsImmLSPair(addr.GetOffset(), CalcLSPairDataSize(op)));
1128 
1129   int offset = static_cast<int>(addr.GetOffset());
1130   Instr memop = op | Rt(rt) | Rt2(rt2) | RnSP(addr.GetBaseRegister()) |
1131                 ImmLSPair(offset, CalcLSPairDataSize(op));
1132 
1133   Instr addrmodeop;
1134   if (addr.IsImmediateOffset()) {
1135     addrmodeop = LoadStorePairOffsetFixed;
1136   } else {
1137     if (addr.IsPreIndex()) {
1138       addrmodeop = LoadStorePairPreIndexFixed;
1139     } else {
1140       VIXL_ASSERT(addr.IsPostIndex());
1141       addrmodeop = LoadStorePairPostIndexFixed;
1142     }
1143   }
1144   Emit(addrmodeop | memop);
1145 }
1146 
1147 
ldnp(const CPURegister & rt,const CPURegister & rt2,const MemOperand & src)1148 void Assembler::ldnp(const CPURegister& rt,
1149                      const CPURegister& rt2,
1150                      const MemOperand& src) {
1151   LoadStorePairNonTemporal(rt, rt2, src, LoadPairNonTemporalOpFor(rt, rt2));
1152 }
1153 
1154 
stnp(const CPURegister & rt,const CPURegister & rt2,const MemOperand & dst)1155 void Assembler::stnp(const CPURegister& rt,
1156                      const CPURegister& rt2,
1157                      const MemOperand& dst) {
1158   LoadStorePairNonTemporal(rt, rt2, dst, StorePairNonTemporalOpFor(rt, rt2));
1159 }
1160 
1161 
LoadStorePairNonTemporal(const CPURegister & rt,const CPURegister & rt2,const MemOperand & addr,LoadStorePairNonTemporalOp op)1162 void Assembler::LoadStorePairNonTemporal(const CPURegister& rt,
1163                                          const CPURegister& rt2,
1164                                          const MemOperand& addr,
1165                                          LoadStorePairNonTemporalOp op) {
1166   VIXL_ASSERT(CPUHas(rt, rt2));
1167 
1168   VIXL_ASSERT(!rt.Is(rt2));
1169   VIXL_ASSERT(AreSameSizeAndType(rt, rt2));
1170   VIXL_ASSERT(addr.IsImmediateOffset());
1171 
1172   unsigned size =
1173       CalcLSPairDataSize(static_cast<LoadStorePairOp>(op & LoadStorePairMask));
1174   VIXL_ASSERT(IsImmLSPair(addr.GetOffset(), size));
1175   int offset = static_cast<int>(addr.GetOffset());
1176   Emit(op | Rt(rt) | Rt2(rt2) | RnSP(addr.GetBaseRegister()) |
1177        ImmLSPair(offset, size));
1178 }
1179 
1180 
1181 // Memory instructions.
ldrb(const Register & rt,const MemOperand & src,LoadStoreScalingOption option)1182 void Assembler::ldrb(const Register& rt,
1183                      const MemOperand& src,
1184                      LoadStoreScalingOption option) {
1185   VIXL_ASSERT(option != RequireUnscaledOffset);
1186   VIXL_ASSERT(option != PreferUnscaledOffset);
1187   LoadStore(rt, src, LDRB_w, option);
1188 }
1189 
1190 
strb(const Register & rt,const MemOperand & dst,LoadStoreScalingOption option)1191 void Assembler::strb(const Register& rt,
1192                      const MemOperand& dst,
1193                      LoadStoreScalingOption option) {
1194   VIXL_ASSERT(option != RequireUnscaledOffset);
1195   VIXL_ASSERT(option != PreferUnscaledOffset);
1196   LoadStore(rt, dst, STRB_w, option);
1197 }
1198 
1199 
ldrsb(const Register & rt,const MemOperand & src,LoadStoreScalingOption option)1200 void Assembler::ldrsb(const Register& rt,
1201                       const MemOperand& src,
1202                       LoadStoreScalingOption option) {
1203   VIXL_ASSERT(option != RequireUnscaledOffset);
1204   VIXL_ASSERT(option != PreferUnscaledOffset);
1205   LoadStore(rt, src, rt.Is64Bits() ? LDRSB_x : LDRSB_w, option);
1206 }
1207 
1208 
ldrh(const Register & rt,const MemOperand & src,LoadStoreScalingOption option)1209 void Assembler::ldrh(const Register& rt,
1210                      const MemOperand& src,
1211                      LoadStoreScalingOption option) {
1212   VIXL_ASSERT(option != RequireUnscaledOffset);
1213   VIXL_ASSERT(option != PreferUnscaledOffset);
1214   LoadStore(rt, src, LDRH_w, option);
1215 }
1216 
1217 
strh(const Register & rt,const MemOperand & dst,LoadStoreScalingOption option)1218 void Assembler::strh(const Register& rt,
1219                      const MemOperand& dst,
1220                      LoadStoreScalingOption option) {
1221   VIXL_ASSERT(option != RequireUnscaledOffset);
1222   VIXL_ASSERT(option != PreferUnscaledOffset);
1223   LoadStore(rt, dst, STRH_w, option);
1224 }
1225 
1226 
ldrsh(const Register & rt,const MemOperand & src,LoadStoreScalingOption option)1227 void Assembler::ldrsh(const Register& rt,
1228                       const MemOperand& src,
1229                       LoadStoreScalingOption option) {
1230   VIXL_ASSERT(option != RequireUnscaledOffset);
1231   VIXL_ASSERT(option != PreferUnscaledOffset);
1232   LoadStore(rt, src, rt.Is64Bits() ? LDRSH_x : LDRSH_w, option);
1233 }
1234 
1235 
ldr(const CPURegister & rt,const MemOperand & src,LoadStoreScalingOption option)1236 void Assembler::ldr(const CPURegister& rt,
1237                     const MemOperand& src,
1238                     LoadStoreScalingOption option) {
1239   VIXL_ASSERT(option != RequireUnscaledOffset);
1240   VIXL_ASSERT(option != PreferUnscaledOffset);
1241   LoadStore(rt, src, LoadOpFor(rt), option);
1242 }
1243 
1244 
str(const CPURegister & rt,const MemOperand & dst,LoadStoreScalingOption option)1245 void Assembler::str(const CPURegister& rt,
1246                     const MemOperand& dst,
1247                     LoadStoreScalingOption option) {
1248   VIXL_ASSERT(option != RequireUnscaledOffset);
1249   VIXL_ASSERT(option != PreferUnscaledOffset);
1250   LoadStore(rt, dst, StoreOpFor(rt), option);
1251 }
1252 
1253 
ldrsw(const Register & xt,const MemOperand & src,LoadStoreScalingOption option)1254 void Assembler::ldrsw(const Register& xt,
1255                       const MemOperand& src,
1256                       LoadStoreScalingOption option) {
1257   VIXL_ASSERT(xt.Is64Bits());
1258   VIXL_ASSERT(option != RequireUnscaledOffset);
1259   VIXL_ASSERT(option != PreferUnscaledOffset);
1260   LoadStore(xt, src, LDRSW_x, option);
1261 }
1262 
1263 
ldurb(const Register & rt,const MemOperand & src,LoadStoreScalingOption option)1264 void Assembler::ldurb(const Register& rt,
1265                       const MemOperand& src,
1266                       LoadStoreScalingOption option) {
1267   VIXL_ASSERT(option != RequireScaledOffset);
1268   VIXL_ASSERT(option != PreferScaledOffset);
1269   LoadStore(rt, src, LDRB_w, option);
1270 }
1271 
1272 
sturb(const Register & rt,const MemOperand & dst,LoadStoreScalingOption option)1273 void Assembler::sturb(const Register& rt,
1274                       const MemOperand& dst,
1275                       LoadStoreScalingOption option) {
1276   VIXL_ASSERT(option != RequireScaledOffset);
1277   VIXL_ASSERT(option != PreferScaledOffset);
1278   LoadStore(rt, dst, STRB_w, option);
1279 }
1280 
1281 
ldursb(const Register & rt,const MemOperand & src,LoadStoreScalingOption option)1282 void Assembler::ldursb(const Register& rt,
1283                        const MemOperand& src,
1284                        LoadStoreScalingOption option) {
1285   VIXL_ASSERT(option != RequireScaledOffset);
1286   VIXL_ASSERT(option != PreferScaledOffset);
1287   LoadStore(rt, src, rt.Is64Bits() ? LDRSB_x : LDRSB_w, option);
1288 }
1289 
1290 
ldurh(const Register & rt,const MemOperand & src,LoadStoreScalingOption option)1291 void Assembler::ldurh(const Register& rt,
1292                       const MemOperand& src,
1293                       LoadStoreScalingOption option) {
1294   VIXL_ASSERT(option != RequireScaledOffset);
1295   VIXL_ASSERT(option != PreferScaledOffset);
1296   LoadStore(rt, src, LDRH_w, option);
1297 }
1298 
1299 
sturh(const Register & rt,const MemOperand & dst,LoadStoreScalingOption option)1300 void Assembler::sturh(const Register& rt,
1301                       const MemOperand& dst,
1302                       LoadStoreScalingOption option) {
1303   VIXL_ASSERT(option != RequireScaledOffset);
1304   VIXL_ASSERT(option != PreferScaledOffset);
1305   LoadStore(rt, dst, STRH_w, option);
1306 }
1307 
1308 
ldursh(const Register & rt,const MemOperand & src,LoadStoreScalingOption option)1309 void Assembler::ldursh(const Register& rt,
1310                        const MemOperand& src,
1311                        LoadStoreScalingOption option) {
1312   VIXL_ASSERT(option != RequireScaledOffset);
1313   VIXL_ASSERT(option != PreferScaledOffset);
1314   LoadStore(rt, src, rt.Is64Bits() ? LDRSH_x : LDRSH_w, option);
1315 }
1316 
1317 
ldur(const CPURegister & rt,const MemOperand & src,LoadStoreScalingOption option)1318 void Assembler::ldur(const CPURegister& rt,
1319                      const MemOperand& src,
1320                      LoadStoreScalingOption option) {
1321   VIXL_ASSERT(option != RequireScaledOffset);
1322   VIXL_ASSERT(option != PreferScaledOffset);
1323   LoadStore(rt, src, LoadOpFor(rt), option);
1324 }
1325 
1326 
stur(const CPURegister & rt,const MemOperand & dst,LoadStoreScalingOption option)1327 void Assembler::stur(const CPURegister& rt,
1328                      const MemOperand& dst,
1329                      LoadStoreScalingOption option) {
1330   VIXL_ASSERT(option != RequireScaledOffset);
1331   VIXL_ASSERT(option != PreferScaledOffset);
1332   LoadStore(rt, dst, StoreOpFor(rt), option);
1333 }
1334 
1335 
ldursw(const Register & xt,const MemOperand & src,LoadStoreScalingOption option)1336 void Assembler::ldursw(const Register& xt,
1337                        const MemOperand& src,
1338                        LoadStoreScalingOption option) {
1339   VIXL_ASSERT(xt.Is64Bits());
1340   VIXL_ASSERT(option != RequireScaledOffset);
1341   VIXL_ASSERT(option != PreferScaledOffset);
1342   LoadStore(xt, src, LDRSW_x, option);
1343 }
1344 
1345 
ldraa(const Register & xt,const MemOperand & src)1346 void Assembler::ldraa(const Register& xt, const MemOperand& src) {
1347   VIXL_ASSERT(CPUHas(CPUFeatures::kPAuth));
1348   LoadStorePAC(xt, src, LDRAA);
1349 }
1350 
1351 
ldrab(const Register & xt,const MemOperand & src)1352 void Assembler::ldrab(const Register& xt, const MemOperand& src) {
1353   VIXL_ASSERT(CPUHas(CPUFeatures::kPAuth));
1354   LoadStorePAC(xt, src, LDRAB);
1355 }
1356 
1357 
ldrsw(const Register & xt,RawLiteral * literal)1358 void Assembler::ldrsw(const Register& xt, RawLiteral* literal) {
1359   VIXL_ASSERT(xt.Is64Bits());
1360   VIXL_ASSERT(literal->GetSize() == kWRegSizeInBytes);
1361   ldrsw(xt, static_cast<int>(LinkAndGetWordOffsetTo(literal)));
1362 }
1363 
1364 
ldr(const CPURegister & rt,RawLiteral * literal)1365 void Assembler::ldr(const CPURegister& rt, RawLiteral* literal) {
1366   VIXL_ASSERT(CPUHas(rt));
1367   VIXL_ASSERT(literal->GetSize() == static_cast<size_t>(rt.GetSizeInBytes()));
1368   ldr(rt, static_cast<int>(LinkAndGetWordOffsetTo(literal)));
1369 }
1370 
1371 
ldrsw(const Register & rt,int64_t imm19)1372 void Assembler::ldrsw(const Register& rt, int64_t imm19) {
1373   Emit(LDRSW_x_lit | ImmLLiteral(imm19) | Rt(rt));
1374 }
1375 
1376 
ldr(const CPURegister & rt,int64_t imm19)1377 void Assembler::ldr(const CPURegister& rt, int64_t imm19) {
1378   VIXL_ASSERT(CPUHas(rt));
1379   LoadLiteralOp op = LoadLiteralOpFor(rt);
1380   Emit(op | ImmLLiteral(imm19) | Rt(rt));
1381 }
1382 
1383 
prfm(PrefetchOperation op,int64_t imm19)1384 void Assembler::prfm(PrefetchOperation op, int64_t imm19) {
1385   Emit(PRFM_lit | ImmPrefetchOperation(op) | ImmLLiteral(imm19));
1386 }
1387 
1388 
1389 // Exclusive-access instructions.
stxrb(const Register & rs,const Register & rt,const MemOperand & dst)1390 void Assembler::stxrb(const Register& rs,
1391                       const Register& rt,
1392                       const MemOperand& dst) {
1393   VIXL_ASSERT(dst.IsImmediateOffset() && (dst.GetOffset() == 0));
1394   Emit(STXRB_w | Rs(rs) | Rt(rt) | Rt2_mask | RnSP(dst.GetBaseRegister()));
1395 }
1396 
1397 
stxrh(const Register & rs,const Register & rt,const MemOperand & dst)1398 void Assembler::stxrh(const Register& rs,
1399                       const Register& rt,
1400                       const MemOperand& dst) {
1401   VIXL_ASSERT(dst.IsImmediateOffset() && (dst.GetOffset() == 0));
1402   Emit(STXRH_w | Rs(rs) | Rt(rt) | Rt2_mask | RnSP(dst.GetBaseRegister()));
1403 }
1404 
1405 
stxr(const Register & rs,const Register & rt,const MemOperand & dst)1406 void Assembler::stxr(const Register& rs,
1407                      const Register& rt,
1408                      const MemOperand& dst) {
1409   VIXL_ASSERT(dst.IsImmediateOffset() && (dst.GetOffset() == 0));
1410   LoadStoreExclusive op = rt.Is64Bits() ? STXR_x : STXR_w;
1411   Emit(op | Rs(rs) | Rt(rt) | Rt2_mask | RnSP(dst.GetBaseRegister()));
1412 }
1413 
1414 
ldxrb(const Register & rt,const MemOperand & src)1415 void Assembler::ldxrb(const Register& rt, const MemOperand& src) {
1416   VIXL_ASSERT(src.IsImmediateOffset() && (src.GetOffset() == 0));
1417   Emit(LDXRB_w | Rs_mask | Rt(rt) | Rt2_mask | RnSP(src.GetBaseRegister()));
1418 }
1419 
1420 
ldxrh(const Register & rt,const MemOperand & src)1421 void Assembler::ldxrh(const Register& rt, const MemOperand& src) {
1422   VIXL_ASSERT(src.IsImmediateOffset() && (src.GetOffset() == 0));
1423   Emit(LDXRH_w | Rs_mask | Rt(rt) | Rt2_mask | RnSP(src.GetBaseRegister()));
1424 }
1425 
1426 
ldxr(const Register & rt,const MemOperand & src)1427 void Assembler::ldxr(const Register& rt, const MemOperand& src) {
1428   VIXL_ASSERT(src.IsImmediateOffset() && (src.GetOffset() == 0));
1429   LoadStoreExclusive op = rt.Is64Bits() ? LDXR_x : LDXR_w;
1430   Emit(op | Rs_mask | Rt(rt) | Rt2_mask | RnSP(src.GetBaseRegister()));
1431 }
1432 
1433 
stxp(const Register & rs,const Register & rt,const Register & rt2,const MemOperand & dst)1434 void Assembler::stxp(const Register& rs,
1435                      const Register& rt,
1436                      const Register& rt2,
1437                      const MemOperand& dst) {
1438   VIXL_ASSERT(rt.GetSizeInBits() == rt2.GetSizeInBits());
1439   VIXL_ASSERT(dst.IsImmediateOffset() && (dst.GetOffset() == 0));
1440   LoadStoreExclusive op = rt.Is64Bits() ? STXP_x : STXP_w;
1441   Emit(op | Rs(rs) | Rt(rt) | Rt2(rt2) | RnSP(dst.GetBaseRegister()));
1442 }
1443 
1444 
ldxp(const Register & rt,const Register & rt2,const MemOperand & src)1445 void Assembler::ldxp(const Register& rt,
1446                      const Register& rt2,
1447                      const MemOperand& src) {
1448   VIXL_ASSERT(rt.GetSizeInBits() == rt2.GetSizeInBits());
1449   VIXL_ASSERT(src.IsImmediateOffset() && (src.GetOffset() == 0));
1450   LoadStoreExclusive op = rt.Is64Bits() ? LDXP_x : LDXP_w;
1451   Emit(op | Rs_mask | Rt(rt) | Rt2(rt2) | RnSP(src.GetBaseRegister()));
1452 }
1453 
1454 
stlxrb(const Register & rs,const Register & rt,const MemOperand & dst)1455 void Assembler::stlxrb(const Register& rs,
1456                        const Register& rt,
1457                        const MemOperand& dst) {
1458   VIXL_ASSERT(dst.IsImmediateOffset() && (dst.GetOffset() == 0));
1459   Emit(STLXRB_w | Rs(rs) | Rt(rt) | Rt2_mask | RnSP(dst.GetBaseRegister()));
1460 }
1461 
1462 
stlxrh(const Register & rs,const Register & rt,const MemOperand & dst)1463 void Assembler::stlxrh(const Register& rs,
1464                        const Register& rt,
1465                        const MemOperand& dst) {
1466   VIXL_ASSERT(dst.IsImmediateOffset() && (dst.GetOffset() == 0));
1467   Emit(STLXRH_w | Rs(rs) | Rt(rt) | Rt2_mask | RnSP(dst.GetBaseRegister()));
1468 }
1469 
1470 
stlxr(const Register & rs,const Register & rt,const MemOperand & dst)1471 void Assembler::stlxr(const Register& rs,
1472                       const Register& rt,
1473                       const MemOperand& dst) {
1474   VIXL_ASSERT(dst.IsImmediateOffset() && (dst.GetOffset() == 0));
1475   LoadStoreExclusive op = rt.Is64Bits() ? STLXR_x : STLXR_w;
1476   Emit(op | Rs(rs) | Rt(rt) | Rt2_mask | RnSP(dst.GetBaseRegister()));
1477 }
1478 
1479 
ldaxrb(const Register & rt,const MemOperand & src)1480 void Assembler::ldaxrb(const Register& rt, const MemOperand& src) {
1481   VIXL_ASSERT(src.IsImmediateOffset() && (src.GetOffset() == 0));
1482   Emit(LDAXRB_w | Rs_mask | Rt(rt) | Rt2_mask | RnSP(src.GetBaseRegister()));
1483 }
1484 
1485 
ldaxrh(const Register & rt,const MemOperand & src)1486 void Assembler::ldaxrh(const Register& rt, const MemOperand& src) {
1487   VIXL_ASSERT(src.IsImmediateOffset() && (src.GetOffset() == 0));
1488   Emit(LDAXRH_w | Rs_mask | Rt(rt) | Rt2_mask | RnSP(src.GetBaseRegister()));
1489 }
1490 
1491 
ldaxr(const Register & rt,const MemOperand & src)1492 void Assembler::ldaxr(const Register& rt, const MemOperand& src) {
1493   VIXL_ASSERT(src.IsImmediateOffset() && (src.GetOffset() == 0));
1494   LoadStoreExclusive op = rt.Is64Bits() ? LDAXR_x : LDAXR_w;
1495   Emit(op | Rs_mask | Rt(rt) | Rt2_mask | RnSP(src.GetBaseRegister()));
1496 }
1497 
1498 
stlxp(const Register & rs,const Register & rt,const Register & rt2,const MemOperand & dst)1499 void Assembler::stlxp(const Register& rs,
1500                       const Register& rt,
1501                       const Register& rt2,
1502                       const MemOperand& dst) {
1503   VIXL_ASSERT(rt.GetSizeInBits() == rt2.GetSizeInBits());
1504   VIXL_ASSERT(dst.IsImmediateOffset() && (dst.GetOffset() == 0));
1505   LoadStoreExclusive op = rt.Is64Bits() ? STLXP_x : STLXP_w;
1506   Emit(op | Rs(rs) | Rt(rt) | Rt2(rt2) | RnSP(dst.GetBaseRegister()));
1507 }
1508 
1509 
ldaxp(const Register & rt,const Register & rt2,const MemOperand & src)1510 void Assembler::ldaxp(const Register& rt,
1511                       const Register& rt2,
1512                       const MemOperand& src) {
1513   VIXL_ASSERT(rt.GetSizeInBits() == rt2.GetSizeInBits());
1514   VIXL_ASSERT(src.IsImmediateOffset() && (src.GetOffset() == 0));
1515   LoadStoreExclusive op = rt.Is64Bits() ? LDAXP_x : LDAXP_w;
1516   Emit(op | Rs_mask | Rt(rt) | Rt2(rt2) | RnSP(src.GetBaseRegister()));
1517 }
1518 
1519 
stlrb(const Register & rt,const MemOperand & dst)1520 void Assembler::stlrb(const Register& rt, const MemOperand& dst) {
1521   VIXL_ASSERT(dst.IsImmediateOffset() && (dst.GetOffset() == 0));
1522   Emit(STLRB_w | Rs_mask | Rt(rt) | Rt2_mask | RnSP(dst.GetBaseRegister()));
1523 }
1524 
stlurb(const Register & rt,const MemOperand & dst)1525 void Assembler::stlurb(const Register& rt, const MemOperand& dst) {
1526   VIXL_ASSERT(CPUHas(CPUFeatures::kRCpc, CPUFeatures::kRCpcImm));
1527   VIXL_ASSERT(dst.IsImmediateOffset() && IsImmLSUnscaled(dst.GetOffset()));
1528 
1529   Instr base = RnSP(dst.GetBaseRegister());
1530   int64_t offset = dst.GetOffset();
1531   Emit(STLURB | Rt(rt) | base | ImmLS(static_cast<int>(offset)));
1532 }
1533 
1534 
stlrh(const Register & rt,const MemOperand & dst)1535 void Assembler::stlrh(const Register& rt, const MemOperand& dst) {
1536   VIXL_ASSERT(dst.IsImmediateOffset() && (dst.GetOffset() == 0));
1537   Emit(STLRH_w | Rs_mask | Rt(rt) | Rt2_mask | RnSP(dst.GetBaseRegister()));
1538 }
1539 
stlurh(const Register & rt,const MemOperand & dst)1540 void Assembler::stlurh(const Register& rt, const MemOperand& dst) {
1541   VIXL_ASSERT(CPUHas(CPUFeatures::kRCpc, CPUFeatures::kRCpcImm));
1542   VIXL_ASSERT(dst.IsImmediateOffset() && IsImmLSUnscaled(dst.GetOffset()));
1543 
1544   Instr base = RnSP(dst.GetBaseRegister());
1545   int64_t offset = dst.GetOffset();
1546   Emit(STLURH | Rt(rt) | base | ImmLS(static_cast<int>(offset)));
1547 }
1548 
1549 
stlr(const Register & rt,const MemOperand & dst)1550 void Assembler::stlr(const Register& rt, const MemOperand& dst) {
1551   VIXL_ASSERT(dst.IsImmediateOffset() && (dst.GetOffset() == 0));
1552   LoadStoreExclusive op = rt.Is64Bits() ? STLR_x : STLR_w;
1553   Emit(op | Rs_mask | Rt(rt) | Rt2_mask | RnSP(dst.GetBaseRegister()));
1554 }
1555 
stlur(const Register & rt,const MemOperand & dst)1556 void Assembler::stlur(const Register& rt, const MemOperand& dst) {
1557   VIXL_ASSERT(CPUHas(CPUFeatures::kRCpc, CPUFeatures::kRCpcImm));
1558   VIXL_ASSERT(dst.IsImmediateOffset() && IsImmLSUnscaled(dst.GetOffset()));
1559 
1560   Instr base = RnSP(dst.GetBaseRegister());
1561   int64_t offset = dst.GetOffset();
1562   Instr op = rt.Is64Bits() ? STLUR_x : STLUR_w;
1563   Emit(op | Rt(rt) | base | ImmLS(static_cast<int>(offset)));
1564 }
1565 
1566 
ldarb(const Register & rt,const MemOperand & src)1567 void Assembler::ldarb(const Register& rt, const MemOperand& src) {
1568   VIXL_ASSERT(src.IsImmediateOffset() && (src.GetOffset() == 0));
1569   Emit(LDARB_w | Rs_mask | Rt(rt) | Rt2_mask | RnSP(src.GetBaseRegister()));
1570 }
1571 
1572 
ldarh(const Register & rt,const MemOperand & src)1573 void Assembler::ldarh(const Register& rt, const MemOperand& src) {
1574   VIXL_ASSERT(src.IsImmediateOffset() && (src.GetOffset() == 0));
1575   Emit(LDARH_w | Rs_mask | Rt(rt) | Rt2_mask | RnSP(src.GetBaseRegister()));
1576 }
1577 
1578 
ldar(const Register & rt,const MemOperand & src)1579 void Assembler::ldar(const Register& rt, const MemOperand& src) {
1580   VIXL_ASSERT(src.IsImmediateOffset() && (src.GetOffset() == 0));
1581   LoadStoreExclusive op = rt.Is64Bits() ? LDAR_x : LDAR_w;
1582   Emit(op | Rs_mask | Rt(rt) | Rt2_mask | RnSP(src.GetBaseRegister()));
1583 }
1584 
1585 
stllrb(const Register & rt,const MemOperand & dst)1586 void Assembler::stllrb(const Register& rt, const MemOperand& dst) {
1587   VIXL_ASSERT(CPUHas(CPUFeatures::kLORegions));
1588   VIXL_ASSERT(dst.IsImmediateOffset() && (dst.GetOffset() == 0));
1589   Emit(STLLRB | Rs_mask | Rt(rt) | Rt2_mask | RnSP(dst.GetBaseRegister()));
1590 }
1591 
1592 
stllrh(const Register & rt,const MemOperand & dst)1593 void Assembler::stllrh(const Register& rt, const MemOperand& dst) {
1594   VIXL_ASSERT(CPUHas(CPUFeatures::kLORegions));
1595   VIXL_ASSERT(dst.IsImmediateOffset() && (dst.GetOffset() == 0));
1596   Emit(STLLRH | Rs_mask | Rt(rt) | Rt2_mask | RnSP(dst.GetBaseRegister()));
1597 }
1598 
1599 
stllr(const Register & rt,const MemOperand & dst)1600 void Assembler::stllr(const Register& rt, const MemOperand& dst) {
1601   VIXL_ASSERT(CPUHas(CPUFeatures::kLORegions));
1602   VIXL_ASSERT(dst.IsImmediateOffset() && (dst.GetOffset() == 0));
1603   LoadStoreExclusive op = rt.Is64Bits() ? STLLR_x : STLLR_w;
1604   Emit(op | Rs_mask | Rt(rt) | Rt2_mask | RnSP(dst.GetBaseRegister()));
1605 }
1606 
1607 
ldlarb(const Register & rt,const MemOperand & src)1608 void Assembler::ldlarb(const Register& rt, const MemOperand& src) {
1609   VIXL_ASSERT(CPUHas(CPUFeatures::kLORegions));
1610   VIXL_ASSERT(src.IsImmediateOffset() && (src.GetOffset() == 0));
1611   Emit(LDLARB | Rs_mask | Rt(rt) | Rt2_mask | RnSP(src.GetBaseRegister()));
1612 }
1613 
1614 
ldlarh(const Register & rt,const MemOperand & src)1615 void Assembler::ldlarh(const Register& rt, const MemOperand& src) {
1616   VIXL_ASSERT(CPUHas(CPUFeatures::kLORegions));
1617   VIXL_ASSERT(src.IsImmediateOffset() && (src.GetOffset() == 0));
1618   Emit(LDLARH | Rs_mask | Rt(rt) | Rt2_mask | RnSP(src.GetBaseRegister()));
1619 }
1620 
1621 
ldlar(const Register & rt,const MemOperand & src)1622 void Assembler::ldlar(const Register& rt, const MemOperand& src) {
1623   VIXL_ASSERT(CPUHas(CPUFeatures::kLORegions));
1624   VIXL_ASSERT(src.IsImmediateOffset() && (src.GetOffset() == 0));
1625   LoadStoreExclusive op = rt.Is64Bits() ? LDLAR_x : LDLAR_w;
1626   Emit(op | Rs_mask | Rt(rt) | Rt2_mask | RnSP(src.GetBaseRegister()));
1627 }
1628 
1629 
1630 // clang-format off
1631 #define COMPARE_AND_SWAP_W_X_LIST(V) \
1632   V(cas,   CAS)                      \
1633   V(casa,  CASA)                     \
1634   V(casl,  CASL)                     \
1635   V(casal, CASAL)
1636 // clang-format on
1637 
1638 #define DEFINE_ASM_FUNC(FN, OP)                                          \
1639   void Assembler::FN(const Register& rs,                                 \
1640                      const Register& rt,                                 \
1641                      const MemOperand& src) {                            \
1642     VIXL_ASSERT(CPUHas(CPUFeatures::kAtomics));                          \
1643     VIXL_ASSERT(src.IsImmediateOffset() && (src.GetOffset() == 0));      \
1644     LoadStoreExclusive op = rt.Is64Bits() ? OP##_x : OP##_w;             \
1645     Emit(op | Rs(rs) | Rt(rt) | Rt2_mask | RnSP(src.GetBaseRegister())); \
1646   }
1647 COMPARE_AND_SWAP_W_X_LIST(DEFINE_ASM_FUNC)
1648 #undef DEFINE_ASM_FUNC
1649 
1650 // clang-format off
1651 #define COMPARE_AND_SWAP_W_LIST(V) \
1652   V(casb,   CASB)                  \
1653   V(casab,  CASAB)                 \
1654   V(caslb,  CASLB)                 \
1655   V(casalb, CASALB)                \
1656   V(cash,   CASH)                  \
1657   V(casah,  CASAH)                 \
1658   V(caslh,  CASLH)                 \
1659   V(casalh, CASALH)
1660 // clang-format on
1661 
1662 #define DEFINE_ASM_FUNC(FN, OP)                                          \
1663   void Assembler::FN(const Register& rs,                                 \
1664                      const Register& rt,                                 \
1665                      const MemOperand& src) {                            \
1666     VIXL_ASSERT(CPUHas(CPUFeatures::kAtomics));                          \
1667     VIXL_ASSERT(src.IsImmediateOffset() && (src.GetOffset() == 0));      \
1668     Emit(OP | Rs(rs) | Rt(rt) | Rt2_mask | RnSP(src.GetBaseRegister())); \
1669   }
COMPARE_AND_SWAP_W_LIST(DEFINE_ASM_FUNC)1670 COMPARE_AND_SWAP_W_LIST(DEFINE_ASM_FUNC)
1671 #undef DEFINE_ASM_FUNC
1672 
1673 
1674 // clang-format off
1675 #define COMPARE_AND_SWAP_PAIR_LIST(V) \
1676   V(casp,   CASP)                     \
1677   V(caspa,  CASPA)                    \
1678   V(caspl,  CASPL)                    \
1679   V(caspal, CASPAL)
1680 // clang-format on
1681 
1682 #define DEFINE_ASM_FUNC(FN, OP)                                          \
1683   void Assembler::FN(const Register& rs,                                 \
1684                      const Register& rs1,                                \
1685                      const Register& rt,                                 \
1686                      const Register& rt1,                                \
1687                      const MemOperand& src) {                            \
1688     VIXL_ASSERT(CPUHas(CPUFeatures::kAtomics));                          \
1689     USE(rs1, rt1);                                                       \
1690     VIXL_ASSERT(src.IsImmediateOffset() && (src.GetOffset() == 0));      \
1691     VIXL_ASSERT(AreEven(rs, rt));                                        \
1692     VIXL_ASSERT(AreConsecutive(rs, rs1));                                \
1693     VIXL_ASSERT(AreConsecutive(rt, rt1));                                \
1694     LoadStoreExclusive op = rt.Is64Bits() ? OP##_x : OP##_w;             \
1695     Emit(op | Rs(rs) | Rt(rt) | Rt2_mask | RnSP(src.GetBaseRegister())); \
1696   }
1697 COMPARE_AND_SWAP_PAIR_LIST(DEFINE_ASM_FUNC)
1698 #undef DEFINE_ASM_FUNC
1699 
1700 // These macros generate all the variations of the atomic memory operations,
1701 // e.g. ldadd, ldadda, ldaddb, staddl, etc.
1702 // For a full list of the methods with comments, see the assembler header file.
1703 
1704 // clang-format off
1705 #define ATOMIC_MEMORY_SIMPLE_OPERATION_LIST(V, DEF) \
1706   V(DEF, add,  LDADD)                               \
1707   V(DEF, clr,  LDCLR)                               \
1708   V(DEF, eor,  LDEOR)                               \
1709   V(DEF, set,  LDSET)                               \
1710   V(DEF, smax, LDSMAX)                              \
1711   V(DEF, smin, LDSMIN)                              \
1712   V(DEF, umax, LDUMAX)                              \
1713   V(DEF, umin, LDUMIN)
1714 
1715 #define ATOMIC_MEMORY_STORE_MODES(V, NAME, OP) \
1716   V(NAME,     OP##_x,   OP##_w)                \
1717   V(NAME##l,  OP##L_x,  OP##L_w)               \
1718   V(NAME##b,  OP##B,    OP##B)                 \
1719   V(NAME##lb, OP##LB,   OP##LB)                \
1720   V(NAME##h,  OP##H,    OP##H)                 \
1721   V(NAME##lh, OP##LH,   OP##LH)
1722 
1723 #define ATOMIC_MEMORY_LOAD_MODES(V, NAME, OP) \
1724   ATOMIC_MEMORY_STORE_MODES(V, NAME, OP)      \
1725   V(NAME##a,   OP##A_x,  OP##A_w)             \
1726   V(NAME##al,  OP##AL_x, OP##AL_w)            \
1727   V(NAME##ab,  OP##AB,   OP##AB)              \
1728   V(NAME##alb, OP##ALB,  OP##ALB)             \
1729   V(NAME##ah,  OP##AH,   OP##AH)              \
1730   V(NAME##alh, OP##ALH,  OP##ALH)
1731 // clang-format on
1732 
1733 #define DEFINE_ASM_LOAD_FUNC(FN, OP_X, OP_W)                        \
1734   void Assembler::ld##FN(const Register& rs,                        \
1735                          const Register& rt,                        \
1736                          const MemOperand& src) {                   \
1737     VIXL_ASSERT(CPUHas(CPUFeatures::kAtomics));                     \
1738     VIXL_ASSERT(src.IsImmediateOffset() && (src.GetOffset() == 0)); \
1739     AtomicMemoryOp op = rt.Is64Bits() ? OP_X : OP_W;                \
1740     Emit(op | Rs(rs) | Rt(rt) | RnSP(src.GetBaseRegister()));       \
1741   }
1742 #define DEFINE_ASM_STORE_FUNC(FN, OP_X, OP_W)                         \
1743   void Assembler::st##FN(const Register& rs, const MemOperand& src) { \
1744     VIXL_ASSERT(CPUHas(CPUFeatures::kAtomics));                       \
1745     ld##FN(rs, AppropriateZeroRegFor(rs), src);                       \
1746   }
1747 
1748 ATOMIC_MEMORY_SIMPLE_OPERATION_LIST(ATOMIC_MEMORY_LOAD_MODES,
1749                                     DEFINE_ASM_LOAD_FUNC)
1750 ATOMIC_MEMORY_SIMPLE_OPERATION_LIST(ATOMIC_MEMORY_STORE_MODES,
1751                                     DEFINE_ASM_STORE_FUNC)
1752 
1753 #define DEFINE_ASM_SWP_FUNC(FN, OP_X, OP_W)                         \
1754   void Assembler::FN(const Register& rs,                            \
1755                      const Register& rt,                            \
1756                      const MemOperand& src) {                       \
1757     VIXL_ASSERT(CPUHas(CPUFeatures::kAtomics));                     \
1758     VIXL_ASSERT(src.IsImmediateOffset() && (src.GetOffset() == 0)); \
1759     AtomicMemoryOp op = rt.Is64Bits() ? OP_X : OP_W;                \
1760     Emit(op | Rs(rs) | Rt(rt) | RnSP(src.GetBaseRegister()));       \
1761   }
1762 
1763 ATOMIC_MEMORY_LOAD_MODES(DEFINE_ASM_SWP_FUNC, swp, SWP)
1764 
1765 #undef DEFINE_ASM_LOAD_FUNC
1766 #undef DEFINE_ASM_STORE_FUNC
1767 #undef DEFINE_ASM_SWP_FUNC
1768 
1769 
1770 void Assembler::ldaprb(const Register& rt, const MemOperand& src) {
1771   VIXL_ASSERT(CPUHas(CPUFeatures::kRCpc));
1772   VIXL_ASSERT(src.IsImmediateOffset() && (src.GetOffset() == 0));
1773   AtomicMemoryOp op = LDAPRB;
1774   Emit(op | Rs(xzr) | Rt(rt) | RnSP(src.GetBaseRegister()));
1775 }
1776 
ldapurb(const Register & rt,const MemOperand & src)1777 void Assembler::ldapurb(const Register& rt, const MemOperand& src) {
1778   VIXL_ASSERT(CPUHas(CPUFeatures::kRCpc, CPUFeatures::kRCpcImm));
1779   VIXL_ASSERT(src.IsImmediateOffset() && IsImmLSUnscaled(src.GetOffset()));
1780 
1781   Instr base = RnSP(src.GetBaseRegister());
1782   int64_t offset = src.GetOffset();
1783   Emit(LDAPURB | Rt(rt) | base | ImmLS(static_cast<int>(offset)));
1784 }
1785 
ldapursb(const Register & rt,const MemOperand & src)1786 void Assembler::ldapursb(const Register& rt, const MemOperand& src) {
1787   VIXL_ASSERT(CPUHas(CPUFeatures::kRCpc, CPUFeatures::kRCpcImm));
1788   VIXL_ASSERT(src.IsImmediateOffset() && IsImmLSUnscaled(src.GetOffset()));
1789 
1790   Instr base = RnSP(src.GetBaseRegister());
1791   int64_t offset = src.GetOffset();
1792   Instr op = rt.Is64Bits() ? LDAPURSB_x : LDAPURSB_w;
1793   Emit(op | Rt(rt) | base | ImmLS(static_cast<int>(offset)));
1794 }
1795 
ldaprh(const Register & rt,const MemOperand & src)1796 void Assembler::ldaprh(const Register& rt, const MemOperand& src) {
1797   VIXL_ASSERT(CPUHas(CPUFeatures::kRCpc));
1798   VIXL_ASSERT(src.IsImmediateOffset() && (src.GetOffset() == 0));
1799   AtomicMemoryOp op = LDAPRH;
1800   Emit(op | Rs(xzr) | Rt(rt) | RnSP(src.GetBaseRegister()));
1801 }
1802 
ldapurh(const Register & rt,const MemOperand & src)1803 void Assembler::ldapurh(const Register& rt, const MemOperand& src) {
1804   VIXL_ASSERT(CPUHas(CPUFeatures::kRCpc, CPUFeatures::kRCpcImm));
1805   VIXL_ASSERT(src.IsImmediateOffset() && IsImmLSUnscaled(src.GetOffset()));
1806 
1807   Instr base = RnSP(src.GetBaseRegister());
1808   int64_t offset = src.GetOffset();
1809   Emit(LDAPURH | Rt(rt) | base | ImmLS(static_cast<int>(offset)));
1810 }
1811 
ldapursh(const Register & rt,const MemOperand & src)1812 void Assembler::ldapursh(const Register& rt, const MemOperand& src) {
1813   VIXL_ASSERT(CPUHas(CPUFeatures::kRCpc, CPUFeatures::kRCpcImm));
1814   VIXL_ASSERT(src.IsImmediateOffset() && IsImmLSUnscaled(src.GetOffset()));
1815 
1816   Instr base = RnSP(src.GetBaseRegister());
1817   int64_t offset = src.GetOffset();
1818   LoadStoreRCpcUnscaledOffsetOp op = rt.Is64Bits() ? LDAPURSH_x : LDAPURSH_w;
1819   Emit(op | Rt(rt) | base | ImmLS(static_cast<int>(offset)));
1820 }
1821 
ldapr(const Register & rt,const MemOperand & src)1822 void Assembler::ldapr(const Register& rt, const MemOperand& src) {
1823   VIXL_ASSERT(CPUHas(CPUFeatures::kRCpc));
1824   VIXL_ASSERT(src.IsImmediateOffset() && (src.GetOffset() == 0));
1825   AtomicMemoryOp op = rt.Is64Bits() ? LDAPR_x : LDAPR_w;
1826   Emit(op | Rs(xzr) | Rt(rt) | RnSP(src.GetBaseRegister()));
1827 }
1828 
ldapur(const Register & rt,const MemOperand & src)1829 void Assembler::ldapur(const Register& rt, const MemOperand& src) {
1830   VIXL_ASSERT(CPUHas(CPUFeatures::kRCpc, CPUFeatures::kRCpcImm));
1831   VIXL_ASSERT(src.IsImmediateOffset() && IsImmLSUnscaled(src.GetOffset()));
1832 
1833   Instr base = RnSP(src.GetBaseRegister());
1834   int64_t offset = src.GetOffset();
1835   LoadStoreRCpcUnscaledOffsetOp op = rt.Is64Bits() ? LDAPUR_x : LDAPUR_w;
1836   Emit(op | Rt(rt) | base | ImmLS(static_cast<int>(offset)));
1837 }
1838 
ldapursw(const Register & rt,const MemOperand & src)1839 void Assembler::ldapursw(const Register& rt, const MemOperand& src) {
1840   VIXL_ASSERT(CPUHas(CPUFeatures::kRCpc, CPUFeatures::kRCpcImm));
1841   VIXL_ASSERT(rt.Is64Bits());
1842   VIXL_ASSERT(src.IsImmediateOffset() && IsImmLSUnscaled(src.GetOffset()));
1843 
1844   Instr base = RnSP(src.GetBaseRegister());
1845   int64_t offset = src.GetOffset();
1846   Emit(LDAPURSW | Rt(rt) | base | ImmLS(static_cast<int>(offset)));
1847 }
1848 
prfm(PrefetchOperation op,const MemOperand & address,LoadStoreScalingOption option)1849 void Assembler::prfm(PrefetchOperation op,
1850                      const MemOperand& address,
1851                      LoadStoreScalingOption option) {
1852   VIXL_ASSERT(option != RequireUnscaledOffset);
1853   VIXL_ASSERT(option != PreferUnscaledOffset);
1854   Prefetch(op, address, option);
1855 }
1856 
1857 
prfum(PrefetchOperation op,const MemOperand & address,LoadStoreScalingOption option)1858 void Assembler::prfum(PrefetchOperation op,
1859                       const MemOperand& address,
1860                       LoadStoreScalingOption option) {
1861   VIXL_ASSERT(option != RequireScaledOffset);
1862   VIXL_ASSERT(option != PreferScaledOffset);
1863   Prefetch(op, address, option);
1864 }
1865 
1866 
prfm(PrefetchOperation op,RawLiteral * literal)1867 void Assembler::prfm(PrefetchOperation op, RawLiteral* literal) {
1868   prfm(op, static_cast<int>(LinkAndGetWordOffsetTo(literal)));
1869 }
1870 
1871 
sys(int op1,int crn,int crm,int op2,const Register & xt)1872 void Assembler::sys(int op1, int crn, int crm, int op2, const Register& xt) {
1873   VIXL_ASSERT(xt.Is64Bits());
1874   Emit(SYS | ImmSysOp1(op1) | CRn(crn) | CRm(crm) | ImmSysOp2(op2) | Rt(xt));
1875 }
1876 
1877 
sys(int op,const Register & xt)1878 void Assembler::sys(int op, const Register& xt) {
1879   VIXL_ASSERT(xt.Is64Bits());
1880   Emit(SYS | SysOp(op) | Rt(xt));
1881 }
1882 
1883 
dc(DataCacheOp op,const Register & rt)1884 void Assembler::dc(DataCacheOp op, const Register& rt) {
1885   if (op == CVAP) VIXL_ASSERT(CPUHas(CPUFeatures::kDCPoP));
1886   if (op == CVADP) VIXL_ASSERT(CPUHas(CPUFeatures::kDCCVADP));
1887   sys(op, rt);
1888 }
1889 
1890 
ic(InstructionCacheOp op,const Register & rt)1891 void Assembler::ic(InstructionCacheOp op, const Register& rt) {
1892   VIXL_ASSERT(op == IVAU);
1893   sys(op, rt);
1894 }
1895 
1896 
hint(SystemHint code)1897 void Assembler::hint(SystemHint code) { hint(static_cast<int>(code)); }
1898 
1899 
hint(int imm7)1900 void Assembler::hint(int imm7) {
1901   VIXL_ASSERT(IsUint7(imm7));
1902   Emit(HINT | ImmHint(imm7) | Rt(xzr));
1903 }
1904 
1905 
1906 // NEON structure loads and stores.
LoadStoreStructAddrModeField(const MemOperand & addr)1907 Instr Assembler::LoadStoreStructAddrModeField(const MemOperand& addr) {
1908   Instr addr_field = RnSP(addr.GetBaseRegister());
1909 
1910   if (addr.IsPostIndex()) {
1911     VIXL_STATIC_ASSERT(NEONLoadStoreMultiStructPostIndex ==
1912                        static_cast<NEONLoadStoreMultiStructPostIndexOp>(
1913                            NEONLoadStoreSingleStructPostIndex));
1914 
1915     addr_field |= NEONLoadStoreMultiStructPostIndex;
1916     if (addr.GetOffset() == 0) {
1917       addr_field |= RmNot31(addr.GetRegisterOffset());
1918     } else {
1919       // The immediate post index addressing mode is indicated by rm = 31.
1920       // The immediate is implied by the number of vector registers used.
1921       addr_field |= (0x1f << Rm_offset);
1922     }
1923   } else {
1924     VIXL_ASSERT(addr.IsImmediateOffset() && (addr.GetOffset() == 0));
1925   }
1926   return addr_field;
1927 }
1928 
LoadStoreStructVerify(const VRegister & vt,const MemOperand & addr,Instr op)1929 void Assembler::LoadStoreStructVerify(const VRegister& vt,
1930                                       const MemOperand& addr,
1931                                       Instr op) {
1932 #ifdef VIXL_DEBUG
1933   // Assert that addressing mode is either offset (with immediate 0), post
1934   // index by immediate of the size of the register list, or post index by a
1935   // value in a core register.
1936   if (addr.IsImmediateOffset()) {
1937     VIXL_ASSERT(addr.GetOffset() == 0);
1938   } else {
1939     int offset = vt.GetSizeInBytes();
1940     switch (op) {
1941       case NEON_LD1_1v:
1942       case NEON_ST1_1v:
1943         offset *= 1;
1944         break;
1945       case NEONLoadStoreSingleStructLoad1:
1946       case NEONLoadStoreSingleStructStore1:
1947       case NEON_LD1R:
1948         offset = (offset / vt.GetLanes()) * 1;
1949         break;
1950 
1951       case NEON_LD1_2v:
1952       case NEON_ST1_2v:
1953       case NEON_LD2:
1954       case NEON_ST2:
1955         offset *= 2;
1956         break;
1957       case NEONLoadStoreSingleStructLoad2:
1958       case NEONLoadStoreSingleStructStore2:
1959       case NEON_LD2R:
1960         offset = (offset / vt.GetLanes()) * 2;
1961         break;
1962 
1963       case NEON_LD1_3v:
1964       case NEON_ST1_3v:
1965       case NEON_LD3:
1966       case NEON_ST3:
1967         offset *= 3;
1968         break;
1969       case NEONLoadStoreSingleStructLoad3:
1970       case NEONLoadStoreSingleStructStore3:
1971       case NEON_LD3R:
1972         offset = (offset / vt.GetLanes()) * 3;
1973         break;
1974 
1975       case NEON_LD1_4v:
1976       case NEON_ST1_4v:
1977       case NEON_LD4:
1978       case NEON_ST4:
1979         offset *= 4;
1980         break;
1981       case NEONLoadStoreSingleStructLoad4:
1982       case NEONLoadStoreSingleStructStore4:
1983       case NEON_LD4R:
1984         offset = (offset / vt.GetLanes()) * 4;
1985         break;
1986       default:
1987         VIXL_UNREACHABLE();
1988     }
1989     VIXL_ASSERT(!addr.GetRegisterOffset().Is(NoReg) ||
1990                 addr.GetOffset() == offset);
1991   }
1992 #else
1993   USE(vt, addr, op);
1994 #endif
1995 }
1996 
LoadStoreStruct(const VRegister & vt,const MemOperand & addr,NEONLoadStoreMultiStructOp op)1997 void Assembler::LoadStoreStruct(const VRegister& vt,
1998                                 const MemOperand& addr,
1999                                 NEONLoadStoreMultiStructOp op) {
2000   LoadStoreStructVerify(vt, addr, op);
2001   VIXL_ASSERT(vt.IsVector() || vt.Is1D());
2002   Emit(op | LoadStoreStructAddrModeField(addr) | LSVFormat(vt) | Rt(vt));
2003 }
2004 
2005 
LoadStoreStructSingleAllLanes(const VRegister & vt,const MemOperand & addr,NEONLoadStoreSingleStructOp op)2006 void Assembler::LoadStoreStructSingleAllLanes(const VRegister& vt,
2007                                               const MemOperand& addr,
2008                                               NEONLoadStoreSingleStructOp op) {
2009   LoadStoreStructVerify(vt, addr, op);
2010   Emit(op | LoadStoreStructAddrModeField(addr) | LSVFormat(vt) | Rt(vt));
2011 }
2012 
2013 
ld1(const VRegister & vt,const MemOperand & src)2014 void Assembler::ld1(const VRegister& vt, const MemOperand& src) {
2015   VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));
2016   LoadStoreStruct(vt, src, NEON_LD1_1v);
2017 }
2018 
2019 
ld1(const VRegister & vt,const VRegister & vt2,const MemOperand & src)2020 void Assembler::ld1(const VRegister& vt,
2021                     const VRegister& vt2,
2022                     const MemOperand& src) {
2023   USE(vt2);
2024   VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));
2025   VIXL_ASSERT(AreSameFormat(vt, vt2));
2026   VIXL_ASSERT(AreConsecutive(vt, vt2));
2027   LoadStoreStruct(vt, src, NEON_LD1_2v);
2028 }
2029 
2030 
ld1(const VRegister & vt,const VRegister & vt2,const VRegister & vt3,const MemOperand & src)2031 void Assembler::ld1(const VRegister& vt,
2032                     const VRegister& vt2,
2033                     const VRegister& vt3,
2034                     const MemOperand& src) {
2035   USE(vt2, vt3);
2036   VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));
2037   VIXL_ASSERT(AreSameFormat(vt, vt2, vt3));
2038   VIXL_ASSERT(AreConsecutive(vt, vt2, vt3));
2039   LoadStoreStruct(vt, src, NEON_LD1_3v);
2040 }
2041 
2042 
ld1(const VRegister & vt,const VRegister & vt2,const VRegister & vt3,const VRegister & vt4,const MemOperand & src)2043 void Assembler::ld1(const VRegister& vt,
2044                     const VRegister& vt2,
2045                     const VRegister& vt3,
2046                     const VRegister& vt4,
2047                     const MemOperand& src) {
2048   USE(vt2, vt3, vt4);
2049   VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));
2050   VIXL_ASSERT(AreSameFormat(vt, vt2, vt3, vt4));
2051   VIXL_ASSERT(AreConsecutive(vt, vt2, vt3, vt4));
2052   LoadStoreStruct(vt, src, NEON_LD1_4v);
2053 }
2054 
2055 
ld2(const VRegister & vt,const VRegister & vt2,const MemOperand & src)2056 void Assembler::ld2(const VRegister& vt,
2057                     const VRegister& vt2,
2058                     const MemOperand& src) {
2059   USE(vt2);
2060   VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));
2061   VIXL_ASSERT(AreSameFormat(vt, vt2));
2062   VIXL_ASSERT(AreConsecutive(vt, vt2));
2063   LoadStoreStruct(vt, src, NEON_LD2);
2064 }
2065 
2066 
ld2(const VRegister & vt,const VRegister & vt2,int lane,const MemOperand & src)2067 void Assembler::ld2(const VRegister& vt,
2068                     const VRegister& vt2,
2069                     int lane,
2070                     const MemOperand& src) {
2071   USE(vt2);
2072   VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));
2073   VIXL_ASSERT(AreSameFormat(vt, vt2));
2074   VIXL_ASSERT(AreConsecutive(vt, vt2));
2075   LoadStoreStructSingle(vt, lane, src, NEONLoadStoreSingleStructLoad2);
2076 }
2077 
2078 
ld2r(const VRegister & vt,const VRegister & vt2,const MemOperand & src)2079 void Assembler::ld2r(const VRegister& vt,
2080                      const VRegister& vt2,
2081                      const MemOperand& src) {
2082   USE(vt2);
2083   VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));
2084   VIXL_ASSERT(AreSameFormat(vt, vt2));
2085   VIXL_ASSERT(AreConsecutive(vt, vt2));
2086   LoadStoreStructSingleAllLanes(vt, src, NEON_LD2R);
2087 }
2088 
2089 
ld3(const VRegister & vt,const VRegister & vt2,const VRegister & vt3,const MemOperand & src)2090 void Assembler::ld3(const VRegister& vt,
2091                     const VRegister& vt2,
2092                     const VRegister& vt3,
2093                     const MemOperand& src) {
2094   USE(vt2, vt3);
2095   VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));
2096   VIXL_ASSERT(AreSameFormat(vt, vt2, vt3));
2097   VIXL_ASSERT(AreConsecutive(vt, vt2, vt3));
2098   LoadStoreStruct(vt, src, NEON_LD3);
2099 }
2100 
2101 
ld3(const VRegister & vt,const VRegister & vt2,const VRegister & vt3,int lane,const MemOperand & src)2102 void Assembler::ld3(const VRegister& vt,
2103                     const VRegister& vt2,
2104                     const VRegister& vt3,
2105                     int lane,
2106                     const MemOperand& src) {
2107   USE(vt2, vt3);
2108   VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));
2109   VIXL_ASSERT(AreSameFormat(vt, vt2, vt3));
2110   VIXL_ASSERT(AreConsecutive(vt, vt2, vt3));
2111   LoadStoreStructSingle(vt, lane, src, NEONLoadStoreSingleStructLoad3);
2112 }
2113 
2114 
ld3r(const VRegister & vt,const VRegister & vt2,const VRegister & vt3,const MemOperand & src)2115 void Assembler::ld3r(const VRegister& vt,
2116                      const VRegister& vt2,
2117                      const VRegister& vt3,
2118                      const MemOperand& src) {
2119   USE(vt2, vt3);
2120   VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));
2121   VIXL_ASSERT(AreSameFormat(vt, vt2, vt3));
2122   VIXL_ASSERT(AreConsecutive(vt, vt2, vt3));
2123   LoadStoreStructSingleAllLanes(vt, src, NEON_LD3R);
2124 }
2125 
2126 
ld4(const VRegister & vt,const VRegister & vt2,const VRegister & vt3,const VRegister & vt4,const MemOperand & src)2127 void Assembler::ld4(const VRegister& vt,
2128                     const VRegister& vt2,
2129                     const VRegister& vt3,
2130                     const VRegister& vt4,
2131                     const MemOperand& src) {
2132   USE(vt2, vt3, vt4);
2133   VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));
2134   VIXL_ASSERT(AreSameFormat(vt, vt2, vt3, vt4));
2135   VIXL_ASSERT(AreConsecutive(vt, vt2, vt3, vt4));
2136   LoadStoreStruct(vt, src, NEON_LD4);
2137 }
2138 
2139 
ld4(const VRegister & vt,const VRegister & vt2,const VRegister & vt3,const VRegister & vt4,int lane,const MemOperand & src)2140 void Assembler::ld4(const VRegister& vt,
2141                     const VRegister& vt2,
2142                     const VRegister& vt3,
2143                     const VRegister& vt4,
2144                     int lane,
2145                     const MemOperand& src) {
2146   USE(vt2, vt3, vt4);
2147   VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));
2148   VIXL_ASSERT(AreSameFormat(vt, vt2, vt3, vt4));
2149   VIXL_ASSERT(AreConsecutive(vt, vt2, vt3, vt4));
2150   LoadStoreStructSingle(vt, lane, src, NEONLoadStoreSingleStructLoad4);
2151 }
2152 
2153 
ld4r(const VRegister & vt,const VRegister & vt2,const VRegister & vt3,const VRegister & vt4,const MemOperand & src)2154 void Assembler::ld4r(const VRegister& vt,
2155                      const VRegister& vt2,
2156                      const VRegister& vt3,
2157                      const VRegister& vt4,
2158                      const MemOperand& src) {
2159   USE(vt2, vt3, vt4);
2160   VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));
2161   VIXL_ASSERT(AreSameFormat(vt, vt2, vt3, vt4));
2162   VIXL_ASSERT(AreConsecutive(vt, vt2, vt3, vt4));
2163   LoadStoreStructSingleAllLanes(vt, src, NEON_LD4R);
2164 }
2165 
2166 
st1(const VRegister & vt,const MemOperand & src)2167 void Assembler::st1(const VRegister& vt, const MemOperand& src) {
2168   VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));
2169   LoadStoreStruct(vt, src, NEON_ST1_1v);
2170 }
2171 
2172 
st1(const VRegister & vt,const VRegister & vt2,const MemOperand & src)2173 void Assembler::st1(const VRegister& vt,
2174                     const VRegister& vt2,
2175                     const MemOperand& src) {
2176   USE(vt2);
2177   VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));
2178   VIXL_ASSERT(AreSameFormat(vt, vt2));
2179   VIXL_ASSERT(AreConsecutive(vt, vt2));
2180   LoadStoreStruct(vt, src, NEON_ST1_2v);
2181 }
2182 
2183 
st1(const VRegister & vt,const VRegister & vt2,const VRegister & vt3,const MemOperand & src)2184 void Assembler::st1(const VRegister& vt,
2185                     const VRegister& vt2,
2186                     const VRegister& vt3,
2187                     const MemOperand& src) {
2188   USE(vt2, vt3);
2189   VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));
2190   VIXL_ASSERT(AreSameFormat(vt, vt2, vt3));
2191   VIXL_ASSERT(AreConsecutive(vt, vt2, vt3));
2192   LoadStoreStruct(vt, src, NEON_ST1_3v);
2193 }
2194 
2195 
st1(const VRegister & vt,const VRegister & vt2,const VRegister & vt3,const VRegister & vt4,const MemOperand & src)2196 void Assembler::st1(const VRegister& vt,
2197                     const VRegister& vt2,
2198                     const VRegister& vt3,
2199                     const VRegister& vt4,
2200                     const MemOperand& src) {
2201   USE(vt2, vt3, vt4);
2202   VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));
2203   VIXL_ASSERT(AreSameFormat(vt, vt2, vt3, vt4));
2204   VIXL_ASSERT(AreConsecutive(vt, vt2, vt3, vt4));
2205   LoadStoreStruct(vt, src, NEON_ST1_4v);
2206 }
2207 
2208 
st2(const VRegister & vt,const VRegister & vt2,const MemOperand & dst)2209 void Assembler::st2(const VRegister& vt,
2210                     const VRegister& vt2,
2211                     const MemOperand& dst) {
2212   USE(vt2);
2213   VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));
2214   VIXL_ASSERT(AreSameFormat(vt, vt2));
2215   VIXL_ASSERT(AreConsecutive(vt, vt2));
2216   LoadStoreStruct(vt, dst, NEON_ST2);
2217 }
2218 
2219 
st2(const VRegister & vt,const VRegister & vt2,int lane,const MemOperand & dst)2220 void Assembler::st2(const VRegister& vt,
2221                     const VRegister& vt2,
2222                     int lane,
2223                     const MemOperand& dst) {
2224   USE(vt2);
2225   VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));
2226   VIXL_ASSERT(AreSameFormat(vt, vt2));
2227   VIXL_ASSERT(AreConsecutive(vt, vt2));
2228   LoadStoreStructSingle(vt, lane, dst, NEONLoadStoreSingleStructStore2);
2229 }
2230 
2231 
st3(const VRegister & vt,const VRegister & vt2,const VRegister & vt3,const MemOperand & dst)2232 void Assembler::st3(const VRegister& vt,
2233                     const VRegister& vt2,
2234                     const VRegister& vt3,
2235                     const MemOperand& dst) {
2236   USE(vt2, vt3);
2237   VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));
2238   VIXL_ASSERT(AreSameFormat(vt, vt2, vt3));
2239   VIXL_ASSERT(AreConsecutive(vt, vt2, vt3));
2240   LoadStoreStruct(vt, dst, NEON_ST3);
2241 }
2242 
2243 
st3(const VRegister & vt,const VRegister & vt2,const VRegister & vt3,int lane,const MemOperand & dst)2244 void Assembler::st3(const VRegister& vt,
2245                     const VRegister& vt2,
2246                     const VRegister& vt3,
2247                     int lane,
2248                     const MemOperand& dst) {
2249   USE(vt2, vt3);
2250   VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));
2251   VIXL_ASSERT(AreSameFormat(vt, vt2, vt3));
2252   VIXL_ASSERT(AreConsecutive(vt, vt2, vt3));
2253   LoadStoreStructSingle(vt, lane, dst, NEONLoadStoreSingleStructStore3);
2254 }
2255 
2256 
st4(const VRegister & vt,const VRegister & vt2,const VRegister & vt3,const VRegister & vt4,const MemOperand & dst)2257 void Assembler::st4(const VRegister& vt,
2258                     const VRegister& vt2,
2259                     const VRegister& vt3,
2260                     const VRegister& vt4,
2261                     const MemOperand& dst) {
2262   USE(vt2, vt3, vt4);
2263   VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));
2264   VIXL_ASSERT(AreSameFormat(vt, vt2, vt3, vt4));
2265   VIXL_ASSERT(AreConsecutive(vt, vt2, vt3, vt4));
2266   LoadStoreStruct(vt, dst, NEON_ST4);
2267 }
2268 
2269 
st4(const VRegister & vt,const VRegister & vt2,const VRegister & vt3,const VRegister & vt4,int lane,const MemOperand & dst)2270 void Assembler::st4(const VRegister& vt,
2271                     const VRegister& vt2,
2272                     const VRegister& vt3,
2273                     const VRegister& vt4,
2274                     int lane,
2275                     const MemOperand& dst) {
2276   USE(vt2, vt3, vt4);
2277   VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));
2278   VIXL_ASSERT(AreSameFormat(vt, vt2, vt3, vt4));
2279   VIXL_ASSERT(AreConsecutive(vt, vt2, vt3, vt4));
2280   LoadStoreStructSingle(vt, lane, dst, NEONLoadStoreSingleStructStore4);
2281 }
2282 
2283 
LoadStoreStructSingle(const VRegister & vt,uint32_t lane,const MemOperand & addr,NEONLoadStoreSingleStructOp op)2284 void Assembler::LoadStoreStructSingle(const VRegister& vt,
2285                                       uint32_t lane,
2286                                       const MemOperand& addr,
2287                                       NEONLoadStoreSingleStructOp op) {
2288   LoadStoreStructVerify(vt, addr, op);
2289 
2290   // We support vt arguments of the form vt.VxT() or vt.T(), where x is the
2291   // number of lanes, and T is b, h, s or d.
2292   unsigned lane_size = vt.GetLaneSizeInBytes();
2293   VIXL_ASSERT(lane < (kQRegSizeInBytes / lane_size));
2294 
2295   // Lane size is encoded in the opcode field. Lane index is encoded in the Q,
2296   // S and size fields.
2297   lane *= lane_size;
2298   if (lane_size == 8) lane++;
2299 
2300   Instr size = (lane << NEONLSSize_offset) & NEONLSSize_mask;
2301   Instr s = (lane << (NEONS_offset - 2)) & NEONS_mask;
2302   Instr q = (lane << (NEONQ_offset - 3)) & NEONQ_mask;
2303 
2304   Instr instr = op;
2305   switch (lane_size) {
2306     case 1:
2307       instr |= NEONLoadStoreSingle_b;
2308       break;
2309     case 2:
2310       instr |= NEONLoadStoreSingle_h;
2311       break;
2312     case 4:
2313       instr |= NEONLoadStoreSingle_s;
2314       break;
2315     default:
2316       VIXL_ASSERT(lane_size == 8);
2317       instr |= NEONLoadStoreSingle_d;
2318   }
2319 
2320   Emit(instr | LoadStoreStructAddrModeField(addr) | q | size | s | Rt(vt));
2321 }
2322 
2323 
ld1(const VRegister & vt,int lane,const MemOperand & src)2324 void Assembler::ld1(const VRegister& vt, int lane, const MemOperand& src) {
2325   VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));
2326   LoadStoreStructSingle(vt, lane, src, NEONLoadStoreSingleStructLoad1);
2327 }
2328 
2329 
ld1r(const VRegister & vt,const MemOperand & src)2330 void Assembler::ld1r(const VRegister& vt, const MemOperand& src) {
2331   VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));
2332   LoadStoreStructSingleAllLanes(vt, src, NEON_LD1R);
2333 }
2334 
2335 
st1(const VRegister & vt,int lane,const MemOperand & dst)2336 void Assembler::st1(const VRegister& vt, int lane, const MemOperand& dst) {
2337   VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));
2338   LoadStoreStructSingle(vt, lane, dst, NEONLoadStoreSingleStructStore1);
2339 }
2340 
2341 
NEON3DifferentL(const VRegister & vd,const VRegister & vn,const VRegister & vm,NEON3DifferentOp vop)2342 void Assembler::NEON3DifferentL(const VRegister& vd,
2343                                 const VRegister& vn,
2344                                 const VRegister& vm,
2345                                 NEON3DifferentOp vop) {
2346   VIXL_ASSERT(AreSameFormat(vn, vm));
2347   VIXL_ASSERT((vn.Is1H() && vd.Is1S()) || (vn.Is1S() && vd.Is1D()) ||
2348               (vn.Is8B() && vd.Is8H()) || (vn.Is4H() && vd.Is4S()) ||
2349               (vn.Is2S() && vd.Is2D()) || (vn.Is16B() && vd.Is8H()) ||
2350               (vn.Is8H() && vd.Is4S()) || (vn.Is4S() && vd.Is2D()));
2351   Instr format, op = vop;
2352   if (vd.IsScalar()) {
2353     op |= NEON_Q | NEONScalar;
2354     format = SFormat(vn);
2355   } else {
2356     format = VFormat(vn);
2357   }
2358   Emit(format | op | Rm(vm) | Rn(vn) | Rd(vd));
2359 }
2360 
2361 
NEON3DifferentW(const VRegister & vd,const VRegister & vn,const VRegister & vm,NEON3DifferentOp vop)2362 void Assembler::NEON3DifferentW(const VRegister& vd,
2363                                 const VRegister& vn,
2364                                 const VRegister& vm,
2365                                 NEON3DifferentOp vop) {
2366   VIXL_ASSERT(AreSameFormat(vd, vn));
2367   VIXL_ASSERT((vm.Is8B() && vd.Is8H()) || (vm.Is4H() && vd.Is4S()) ||
2368               (vm.Is2S() && vd.Is2D()) || (vm.Is16B() && vd.Is8H()) ||
2369               (vm.Is8H() && vd.Is4S()) || (vm.Is4S() && vd.Is2D()));
2370   Emit(VFormat(vm) | vop | Rm(vm) | Rn(vn) | Rd(vd));
2371 }
2372 
2373 
NEON3DifferentHN(const VRegister & vd,const VRegister & vn,const VRegister & vm,NEON3DifferentOp vop)2374 void Assembler::NEON3DifferentHN(const VRegister& vd,
2375                                  const VRegister& vn,
2376                                  const VRegister& vm,
2377                                  NEON3DifferentOp vop) {
2378   VIXL_ASSERT(AreSameFormat(vm, vn));
2379   VIXL_ASSERT((vd.Is8B() && vn.Is8H()) || (vd.Is4H() && vn.Is4S()) ||
2380               (vd.Is2S() && vn.Is2D()) || (vd.Is16B() && vn.Is8H()) ||
2381               (vd.Is8H() && vn.Is4S()) || (vd.Is4S() && vn.Is2D()));
2382   Emit(VFormat(vd) | vop | Rm(vm) | Rn(vn) | Rd(vd));
2383 }
2384 
2385 
2386 // clang-format off
2387 #define NEON_3DIFF_LONG_LIST(V) \
2388   V(pmull,  NEON_PMULL,  vn.IsVector() && vn.Is8B())                           \
2389   V(pmull2, NEON_PMULL2, vn.IsVector() && vn.Is16B())                          \
2390   V(saddl,  NEON_SADDL,  vn.IsVector() && vn.IsD())                            \
2391   V(saddl2, NEON_SADDL2, vn.IsVector() && vn.IsQ())                            \
2392   V(sabal,  NEON_SABAL,  vn.IsVector() && vn.IsD())                            \
2393   V(sabal2, NEON_SABAL2, vn.IsVector() && vn.IsQ())                            \
2394   V(uabal,  NEON_UABAL,  vn.IsVector() && vn.IsD())                            \
2395   V(uabal2, NEON_UABAL2, vn.IsVector() && vn.IsQ())                            \
2396   V(sabdl,  NEON_SABDL,  vn.IsVector() && vn.IsD())                            \
2397   V(sabdl2, NEON_SABDL2, vn.IsVector() && vn.IsQ())                            \
2398   V(uabdl,  NEON_UABDL,  vn.IsVector() && vn.IsD())                            \
2399   V(uabdl2, NEON_UABDL2, vn.IsVector() && vn.IsQ())                            \
2400   V(smlal,  NEON_SMLAL,  vn.IsVector() && vn.IsD())                            \
2401   V(smlal2, NEON_SMLAL2, vn.IsVector() && vn.IsQ())                            \
2402   V(umlal,  NEON_UMLAL,  vn.IsVector() && vn.IsD())                            \
2403   V(umlal2, NEON_UMLAL2, vn.IsVector() && vn.IsQ())                            \
2404   V(smlsl,  NEON_SMLSL,  vn.IsVector() && vn.IsD())                            \
2405   V(smlsl2, NEON_SMLSL2, vn.IsVector() && vn.IsQ())                            \
2406   V(umlsl,  NEON_UMLSL,  vn.IsVector() && vn.IsD())                            \
2407   V(umlsl2, NEON_UMLSL2, vn.IsVector() && vn.IsQ())                            \
2408   V(smull,  NEON_SMULL,  vn.IsVector() && vn.IsD())                            \
2409   V(smull2, NEON_SMULL2, vn.IsVector() && vn.IsQ())                            \
2410   V(umull,  NEON_UMULL,  vn.IsVector() && vn.IsD())                            \
2411   V(umull2, NEON_UMULL2, vn.IsVector() && vn.IsQ())                            \
2412   V(ssubl,  NEON_SSUBL,  vn.IsVector() && vn.IsD())                            \
2413   V(ssubl2, NEON_SSUBL2, vn.IsVector() && vn.IsQ())                            \
2414   V(uaddl,  NEON_UADDL,  vn.IsVector() && vn.IsD())                            \
2415   V(uaddl2, NEON_UADDL2, vn.IsVector() && vn.IsQ())                            \
2416   V(usubl,  NEON_USUBL,  vn.IsVector() && vn.IsD())                            \
2417   V(usubl2, NEON_USUBL2, vn.IsVector() && vn.IsQ())                            \
2418   V(sqdmlal,  NEON_SQDMLAL,  vn.Is1H() || vn.Is1S() || vn.Is4H() || vn.Is2S()) \
2419   V(sqdmlal2, NEON_SQDMLAL2, vn.Is1H() || vn.Is1S() || vn.Is8H() || vn.Is4S()) \
2420   V(sqdmlsl,  NEON_SQDMLSL,  vn.Is1H() || vn.Is1S() || vn.Is4H() || vn.Is2S()) \
2421   V(sqdmlsl2, NEON_SQDMLSL2, vn.Is1H() || vn.Is1S() || vn.Is8H() || vn.Is4S()) \
2422   V(sqdmull,  NEON_SQDMULL,  vn.Is1H() || vn.Is1S() || vn.Is4H() || vn.Is2S()) \
2423   V(sqdmull2, NEON_SQDMULL2, vn.Is1H() || vn.Is1S() || vn.Is8H() || vn.Is4S()) \
2424 // clang-format on
2425 
2426 
2427 #define DEFINE_ASM_FUNC(FN, OP, AS)                   \
2428 void Assembler::FN(const VRegister& vd,               \
2429                    const VRegister& vn,               \
2430                    const VRegister& vm) {             \
2431   VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));            \
2432   VIXL_ASSERT(AS);                                    \
2433   NEON3DifferentL(vd, vn, vm, OP);                    \
2434 }
2435 NEON_3DIFF_LONG_LIST(DEFINE_ASM_FUNC)
2436 #undef DEFINE_ASM_FUNC
2437 
2438 // clang-format off
2439 #define NEON_3DIFF_HN_LIST(V)         \
2440   V(addhn,   NEON_ADDHN,   vd.IsD())  \
2441   V(addhn2,  NEON_ADDHN2,  vd.IsQ())  \
2442   V(raddhn,  NEON_RADDHN,  vd.IsD())  \
2443   V(raddhn2, NEON_RADDHN2, vd.IsQ())  \
2444   V(subhn,   NEON_SUBHN,   vd.IsD())  \
2445   V(subhn2,  NEON_SUBHN2,  vd.IsQ())  \
2446   V(rsubhn,  NEON_RSUBHN,  vd.IsD())  \
2447   V(rsubhn2, NEON_RSUBHN2, vd.IsQ())
2448 // clang-format on
2449 
2450 #define DEFINE_ASM_FUNC(FN, OP, AS)          \
2451   void Assembler::FN(const VRegister& vd,    \
2452                      const VRegister& vn,    \
2453                      const VRegister& vm) {  \
2454     VIXL_ASSERT(CPUHas(CPUFeatures::kNEON)); \
2455     VIXL_ASSERT(AS);                         \
2456     NEON3DifferentHN(vd, vn, vm, OP);        \
2457   }
NEON_3DIFF_HN_LIST(DEFINE_ASM_FUNC)2458 NEON_3DIFF_HN_LIST(DEFINE_ASM_FUNC)
2459 #undef DEFINE_ASM_FUNC
2460 
2461 void Assembler::uaddw(const VRegister& vd,
2462                       const VRegister& vn,
2463                       const VRegister& vm) {
2464   VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));
2465   VIXL_ASSERT(vm.IsD());
2466   NEON3DifferentW(vd, vn, vm, NEON_UADDW);
2467 }
2468 
2469 
uaddw2(const VRegister & vd,const VRegister & vn,const VRegister & vm)2470 void Assembler::uaddw2(const VRegister& vd,
2471                        const VRegister& vn,
2472                        const VRegister& vm) {
2473   VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));
2474   VIXL_ASSERT(vm.IsQ());
2475   NEON3DifferentW(vd, vn, vm, NEON_UADDW2);
2476 }
2477 
2478 
saddw(const VRegister & vd,const VRegister & vn,const VRegister & vm)2479 void Assembler::saddw(const VRegister& vd,
2480                       const VRegister& vn,
2481                       const VRegister& vm) {
2482   VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));
2483   VIXL_ASSERT(vm.IsD());
2484   NEON3DifferentW(vd, vn, vm, NEON_SADDW);
2485 }
2486 
2487 
saddw2(const VRegister & vd,const VRegister & vn,const VRegister & vm)2488 void Assembler::saddw2(const VRegister& vd,
2489                        const VRegister& vn,
2490                        const VRegister& vm) {
2491   VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));
2492   VIXL_ASSERT(vm.IsQ());
2493   NEON3DifferentW(vd, vn, vm, NEON_SADDW2);
2494 }
2495 
2496 
usubw(const VRegister & vd,const VRegister & vn,const VRegister & vm)2497 void Assembler::usubw(const VRegister& vd,
2498                       const VRegister& vn,
2499                       const VRegister& vm) {
2500   VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));
2501   VIXL_ASSERT(vm.IsD());
2502   NEON3DifferentW(vd, vn, vm, NEON_USUBW);
2503 }
2504 
2505 
usubw2(const VRegister & vd,const VRegister & vn,const VRegister & vm)2506 void Assembler::usubw2(const VRegister& vd,
2507                        const VRegister& vn,
2508                        const VRegister& vm) {
2509   VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));
2510   VIXL_ASSERT(vm.IsQ());
2511   NEON3DifferentW(vd, vn, vm, NEON_USUBW2);
2512 }
2513 
2514 
ssubw(const VRegister & vd,const VRegister & vn,const VRegister & vm)2515 void Assembler::ssubw(const VRegister& vd,
2516                       const VRegister& vn,
2517                       const VRegister& vm) {
2518   VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));
2519   VIXL_ASSERT(vm.IsD());
2520   NEON3DifferentW(vd, vn, vm, NEON_SSUBW);
2521 }
2522 
2523 
ssubw2(const VRegister & vd,const VRegister & vn,const VRegister & vm)2524 void Assembler::ssubw2(const VRegister& vd,
2525                        const VRegister& vn,
2526                        const VRegister& vm) {
2527   VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));
2528   VIXL_ASSERT(vm.IsQ());
2529   NEON3DifferentW(vd, vn, vm, NEON_SSUBW2);
2530 }
2531 
2532 
mov(const Register & rd,const Register & rm)2533 void Assembler::mov(const Register& rd, const Register& rm) {
2534   // Moves involving the stack pointer are encoded as add immediate with
2535   // second operand of zero. Otherwise, orr with first operand zr is
2536   // used.
2537   if (rd.IsSP() || rm.IsSP()) {
2538     add(rd, rm, 0);
2539   } else {
2540     orr(rd, AppropriateZeroRegFor(rd), rm);
2541   }
2542 }
2543 
xpaclri()2544 void Assembler::xpaclri() {
2545   VIXL_ASSERT(CPUHas(CPUFeatures::kPAuth));
2546   Emit(XPACLRI);
2547 }
2548 
pacia1716()2549 void Assembler::pacia1716() {
2550   VIXL_ASSERT(CPUHas(CPUFeatures::kPAuth));
2551   Emit(PACIA1716);
2552 }
2553 
pacib1716()2554 void Assembler::pacib1716() {
2555   VIXL_ASSERT(CPUHas(CPUFeatures::kPAuth));
2556   Emit(PACIB1716);
2557 }
2558 
autia1716()2559 void Assembler::autia1716() {
2560   VIXL_ASSERT(CPUHas(CPUFeatures::kPAuth));
2561   Emit(AUTIA1716);
2562 }
2563 
autib1716()2564 void Assembler::autib1716() {
2565   VIXL_ASSERT(CPUHas(CPUFeatures::kPAuth));
2566   Emit(AUTIB1716);
2567 }
2568 
paciaz()2569 void Assembler::paciaz() {
2570   VIXL_ASSERT(CPUHas(CPUFeatures::kPAuth));
2571   Emit(PACIAZ);
2572 }
2573 
pacibz()2574 void Assembler::pacibz() {
2575   VIXL_ASSERT(CPUHas(CPUFeatures::kPAuth));
2576   Emit(PACIBZ);
2577 }
2578 
autiaz()2579 void Assembler::autiaz() {
2580   VIXL_ASSERT(CPUHas(CPUFeatures::kPAuth));
2581   Emit(AUTIAZ);
2582 }
2583 
autibz()2584 void Assembler::autibz() {
2585   VIXL_ASSERT(CPUHas(CPUFeatures::kPAuth));
2586   Emit(AUTIBZ);
2587 }
2588 
paciasp()2589 void Assembler::paciasp() {
2590   VIXL_ASSERT(CPUHas(CPUFeatures::kPAuth));
2591   Emit(PACIASP);
2592 }
2593 
pacibsp()2594 void Assembler::pacibsp() {
2595   VIXL_ASSERT(CPUHas(CPUFeatures::kPAuth));
2596   Emit(PACIBSP);
2597 }
2598 
autiasp()2599 void Assembler::autiasp() {
2600   VIXL_ASSERT(CPUHas(CPUFeatures::kPAuth));
2601   Emit(AUTIASP);
2602 }
2603 
autibsp()2604 void Assembler::autibsp() {
2605   VIXL_ASSERT(CPUHas(CPUFeatures::kPAuth));
2606   Emit(AUTIBSP);
2607 }
2608 
bti(BranchTargetIdentifier id)2609 void Assembler::bti(BranchTargetIdentifier id) {
2610   VIXL_ASSERT((id != EmitPACIASP) && (id != EmitPACIBSP));  // Not modes of Bti.
2611   VIXL_ASSERT(id != EmitBTI_none);  // Always generate an instruction.
2612   VIXL_ASSERT(CPUHas(CPUFeatures::kBTI));
2613   hint(static_cast<SystemHint>(id));
2614 }
2615 
mvn(const Register & rd,const Operand & operand)2616 void Assembler::mvn(const Register& rd, const Operand& operand) {
2617   orn(rd, AppropriateZeroRegFor(rd), operand);
2618 }
2619 
2620 
mrs(const Register & xt,SystemRegister sysreg)2621 void Assembler::mrs(const Register& xt, SystemRegister sysreg) {
2622   VIXL_ASSERT(xt.Is64Bits());
2623   VIXL_ASSERT(CPUHas(sysreg));
2624   Emit(MRS | ImmSystemRegister(sysreg) | Rt(xt));
2625 }
2626 
2627 
msr(SystemRegister sysreg,const Register & xt)2628 void Assembler::msr(SystemRegister sysreg, const Register& xt) {
2629   VIXL_ASSERT(xt.Is64Bits());
2630   VIXL_ASSERT(CPUHas(sysreg));
2631   Emit(MSR | Rt(xt) | ImmSystemRegister(sysreg));
2632 }
2633 
2634 
cfinv()2635 void Assembler::cfinv() {
2636   VIXL_ASSERT(CPUHas(CPUFeatures::kFlagM));
2637   Emit(CFINV);
2638 }
2639 
2640 
axflag()2641 void Assembler::axflag() {
2642   VIXL_ASSERT(CPUHas(CPUFeatures::kAXFlag));
2643   Emit(AXFLAG);
2644 }
2645 
2646 
xaflag()2647 void Assembler::xaflag() {
2648   VIXL_ASSERT(CPUHas(CPUFeatures::kAXFlag));
2649   Emit(XAFLAG);
2650 }
2651 
2652 
clrex(int imm4)2653 void Assembler::clrex(int imm4) { Emit(CLREX | CRm(imm4)); }
2654 
2655 
dmb(BarrierDomain domain,BarrierType type)2656 void Assembler::dmb(BarrierDomain domain, BarrierType type) {
2657   Emit(DMB | ImmBarrierDomain(domain) | ImmBarrierType(type));
2658 }
2659 
2660 
dsb(BarrierDomain domain,BarrierType type)2661 void Assembler::dsb(BarrierDomain domain, BarrierType type) {
2662   Emit(DSB | ImmBarrierDomain(domain) | ImmBarrierType(type));
2663 }
2664 
2665 
isb()2666 void Assembler::isb() {
2667   Emit(ISB | ImmBarrierDomain(FullSystem) | ImmBarrierType(BarrierAll));
2668 }
2669 
esb()2670 void Assembler::esb() {
2671   VIXL_ASSERT(CPUHas(CPUFeatures::kRAS));
2672   hint(ESB);
2673 }
2674 
csdb()2675 void Assembler::csdb() { hint(CSDB); }
2676 
fmov(const VRegister & vd,double imm)2677 void Assembler::fmov(const VRegister& vd, double imm) {
2678   VIXL_ASSERT(CPUHas(CPUFeatures::kFP));
2679   if (vd.IsScalar()) {
2680     VIXL_ASSERT(vd.Is1D());
2681     Emit(FMOV_d_imm | Rd(vd) | ImmFP64(imm));
2682   } else {
2683     VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));
2684     VIXL_ASSERT(vd.Is2D());
2685     Instr op = NEONModifiedImmediate_MOVI | NEONModifiedImmediateOpBit;
2686     Instr q = NEON_Q;
2687     uint32_t encoded_imm = FP64ToImm8(imm);
2688     Emit(q | op | ImmNEONabcdefgh(encoded_imm) | NEONCmode(0xf) | Rd(vd));
2689   }
2690 }
2691 
2692 
fmov(const VRegister & vd,float imm)2693 void Assembler::fmov(const VRegister& vd, float imm) {
2694   VIXL_ASSERT(CPUHas(CPUFeatures::kFP));
2695   if (vd.IsScalar()) {
2696     VIXL_ASSERT(vd.Is1S());
2697     Emit(FMOV_s_imm | Rd(vd) | ImmFP32(imm));
2698   } else {
2699     VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));
2700     VIXL_ASSERT(vd.Is2S() | vd.Is4S());
2701     Instr op = NEONModifiedImmediate_MOVI;
2702     Instr q = vd.Is4S() ? NEON_Q : 0;
2703     uint32_t encoded_imm = FP32ToImm8(imm);
2704     Emit(q | op | ImmNEONabcdefgh(encoded_imm) | NEONCmode(0xf) | Rd(vd));
2705   }
2706 }
2707 
2708 
fmov(const VRegister & vd,Float16 imm)2709 void Assembler::fmov(const VRegister& vd, Float16 imm) {
2710   VIXL_ASSERT(CPUHas(CPUFeatures::kFP));
2711   if (vd.IsScalar()) {
2712     VIXL_ASSERT(CPUHas(CPUFeatures::kFPHalf));
2713     VIXL_ASSERT(vd.Is1H());
2714     Emit(FMOV_h_imm | Rd(vd) | ImmFP16(imm));
2715   } else {
2716     VIXL_ASSERT(CPUHas(CPUFeatures::kNEON, CPUFeatures::kNEONHalf));
2717     VIXL_ASSERT(vd.Is4H() | vd.Is8H());
2718     Instr q = vd.Is8H() ? NEON_Q : 0;
2719     uint32_t encoded_imm = FP16ToImm8(imm);
2720     Emit(q | NEONModifiedImmediate_FMOV | ImmNEONabcdefgh(encoded_imm) |
2721          NEONCmode(0xf) | Rd(vd));
2722   }
2723 }
2724 
2725 
fmov(const Register & rd,const VRegister & vn)2726 void Assembler::fmov(const Register& rd, const VRegister& vn) {
2727   VIXL_ASSERT(CPUHas(CPUFeatures::kFP));
2728   VIXL_ASSERT(vn.Is1H() || vn.Is1S() || vn.Is1D());
2729   VIXL_ASSERT((rd.GetSizeInBits() == vn.GetSizeInBits()) || vn.Is1H());
2730   FPIntegerConvertOp op;
2731   switch (vn.GetSizeInBits()) {
2732     case 16:
2733       VIXL_ASSERT(CPUHas(CPUFeatures::kFPHalf));
2734       op = rd.Is64Bits() ? FMOV_xh : FMOV_wh;
2735       break;
2736     case 32:
2737       op = FMOV_ws;
2738       break;
2739     default:
2740       op = FMOV_xd;
2741   }
2742   Emit(op | Rd(rd) | Rn(vn));
2743 }
2744 
2745 
fmov(const VRegister & vd,const Register & rn)2746 void Assembler::fmov(const VRegister& vd, const Register& rn) {
2747   VIXL_ASSERT(CPUHas(CPUFeatures::kFP));
2748   VIXL_ASSERT(vd.Is1H() || vd.Is1S() || vd.Is1D());
2749   VIXL_ASSERT((vd.GetSizeInBits() == rn.GetSizeInBits()) || vd.Is1H());
2750   FPIntegerConvertOp op;
2751   switch (vd.GetSizeInBits()) {
2752     case 16:
2753       VIXL_ASSERT(CPUHas(CPUFeatures::kFPHalf));
2754       op = rn.Is64Bits() ? FMOV_hx : FMOV_hw;
2755       break;
2756     case 32:
2757       op = FMOV_sw;
2758       break;
2759     default:
2760       op = FMOV_dx;
2761   }
2762   Emit(op | Rd(vd) | Rn(rn));
2763 }
2764 
2765 
fmov(const VRegister & vd,const VRegister & vn)2766 void Assembler::fmov(const VRegister& vd, const VRegister& vn) {
2767   VIXL_ASSERT(CPUHas(CPUFeatures::kFP));
2768   if (vd.Is1H()) {
2769     VIXL_ASSERT(CPUHas(CPUFeatures::kFPHalf));
2770   }
2771   VIXL_ASSERT(vd.Is1H() || vd.Is1S() || vd.Is1D());
2772   VIXL_ASSERT(vd.IsSameFormat(vn));
2773   Emit(FPType(vd) | FMOV | Rd(vd) | Rn(vn));
2774 }
2775 
2776 
fmov(const VRegister & vd,int index,const Register & rn)2777 void Assembler::fmov(const VRegister& vd, int index, const Register& rn) {
2778   VIXL_ASSERT(CPUHas(CPUFeatures::kNEON, CPUFeatures::kFP));
2779   VIXL_ASSERT((index == 1) && vd.Is1D() && rn.IsX());
2780   USE(index);
2781   Emit(FMOV_d1_x | Rd(vd) | Rn(rn));
2782 }
2783 
2784 
fmov(const Register & rd,const VRegister & vn,int index)2785 void Assembler::fmov(const Register& rd, const VRegister& vn, int index) {
2786   VIXL_ASSERT(CPUHas(CPUFeatures::kNEON, CPUFeatures::kFP));
2787   VIXL_ASSERT((index == 1) && vn.Is1D() && rd.IsX());
2788   USE(index);
2789   Emit(FMOV_x_d1 | Rd(rd) | Rn(vn));
2790 }
2791 
2792 
fmadd(const VRegister & vd,const VRegister & vn,const VRegister & vm,const VRegister & va)2793 void Assembler::fmadd(const VRegister& vd,
2794                       const VRegister& vn,
2795                       const VRegister& vm,
2796                       const VRegister& va) {
2797   VIXL_ASSERT(CPUHas(CPUFeatures::kFP));
2798   FPDataProcessing3SourceOp op;
2799   if (vd.Is1H()) {
2800     VIXL_ASSERT(CPUHas(CPUFeatures::kFPHalf));
2801     op = FMADD_h;
2802   } else if (vd.Is1S()) {
2803     op = FMADD_s;
2804   } else {
2805     VIXL_ASSERT(vd.Is1D());
2806     op = FMADD_d;
2807   }
2808   FPDataProcessing3Source(vd, vn, vm, va, op);
2809 }
2810 
2811 
fmsub(const VRegister & vd,const VRegister & vn,const VRegister & vm,const VRegister & va)2812 void Assembler::fmsub(const VRegister& vd,
2813                       const VRegister& vn,
2814                       const VRegister& vm,
2815                       const VRegister& va) {
2816   VIXL_ASSERT(CPUHas(CPUFeatures::kFP));
2817   FPDataProcessing3SourceOp op;
2818   if (vd.Is1H()) {
2819     VIXL_ASSERT(CPUHas(CPUFeatures::kFPHalf));
2820     op = FMSUB_h;
2821   } else if (vd.Is1S()) {
2822     op = FMSUB_s;
2823   } else {
2824     VIXL_ASSERT(vd.Is1D());
2825     op = FMSUB_d;
2826   }
2827   FPDataProcessing3Source(vd, vn, vm, va, op);
2828 }
2829 
2830 
fnmadd(const VRegister & vd,const VRegister & vn,const VRegister & vm,const VRegister & va)2831 void Assembler::fnmadd(const VRegister& vd,
2832                        const VRegister& vn,
2833                        const VRegister& vm,
2834                        const VRegister& va) {
2835   VIXL_ASSERT(CPUHas(CPUFeatures::kFP));
2836   FPDataProcessing3SourceOp op;
2837   if (vd.Is1H()) {
2838     VIXL_ASSERT(CPUHas(CPUFeatures::kFPHalf));
2839     op = FNMADD_h;
2840   } else if (vd.Is1S()) {
2841     op = FNMADD_s;
2842   } else {
2843     VIXL_ASSERT(vd.Is1D());
2844     op = FNMADD_d;
2845   }
2846   FPDataProcessing3Source(vd, vn, vm, va, op);
2847 }
2848 
2849 
fnmsub(const VRegister & vd,const VRegister & vn,const VRegister & vm,const VRegister & va)2850 void Assembler::fnmsub(const VRegister& vd,
2851                        const VRegister& vn,
2852                        const VRegister& vm,
2853                        const VRegister& va) {
2854   VIXL_ASSERT(CPUHas(CPUFeatures::kFP));
2855   FPDataProcessing3SourceOp op;
2856   if (vd.Is1H()) {
2857     VIXL_ASSERT(CPUHas(CPUFeatures::kFPHalf));
2858     op = FNMSUB_h;
2859   } else if (vd.Is1S()) {
2860     op = FNMSUB_s;
2861   } else {
2862     VIXL_ASSERT(vd.Is1D());
2863     op = FNMSUB_d;
2864   }
2865   FPDataProcessing3Source(vd, vn, vm, va, op);
2866 }
2867 
2868 
fnmul(const VRegister & vd,const VRegister & vn,const VRegister & vm)2869 void Assembler::fnmul(const VRegister& vd,
2870                       const VRegister& vn,
2871                       const VRegister& vm) {
2872   VIXL_ASSERT(CPUHas(CPUFeatures::kFP));
2873   VIXL_ASSERT(AreSameSizeAndType(vd, vn, vm));
2874   Instr op;
2875   if (vd.Is1H()) {
2876     VIXL_ASSERT(CPUHas(CPUFeatures::kFPHalf));
2877     op = FNMUL_h;
2878   } else if (vd.Is1S()) {
2879     op = FNMUL_s;
2880   } else {
2881     VIXL_ASSERT(vd.Is1D());
2882     op = FNMUL_d;
2883   }
2884   Emit(FPType(vd) | op | Rm(vm) | Rn(vn) | Rd(vd));
2885 }
2886 
2887 
FPCompareMacro(const VRegister & vn,double value,FPTrapFlags trap)2888 void Assembler::FPCompareMacro(const VRegister& vn,
2889                                double value,
2890                                FPTrapFlags trap) {
2891   USE(value);
2892   // Although the fcmp{e} instructions can strictly only take an immediate
2893   // value of +0.0, we don't need to check for -0.0 because the sign of 0.0
2894   // doesn't affect the result of the comparison.
2895   VIXL_ASSERT(value == 0.0);
2896   VIXL_ASSERT(vn.Is1H() || vn.Is1S() || vn.Is1D());
2897   Instr op = (trap == EnableTrap) ? FCMPE_zero : FCMP_zero;
2898   Emit(FPType(vn) | op | Rn(vn));
2899 }
2900 
2901 
FPCompareMacro(const VRegister & vn,const VRegister & vm,FPTrapFlags trap)2902 void Assembler::FPCompareMacro(const VRegister& vn,
2903                                const VRegister& vm,
2904                                FPTrapFlags trap) {
2905   VIXL_ASSERT(vn.Is1H() || vn.Is1S() || vn.Is1D());
2906   VIXL_ASSERT(vn.IsSameSizeAndType(vm));
2907   Instr op = (trap == EnableTrap) ? FCMPE : FCMP;
2908   Emit(FPType(vn) | op | Rm(vm) | Rn(vn));
2909 }
2910 
2911 
fcmp(const VRegister & vn,const VRegister & vm)2912 void Assembler::fcmp(const VRegister& vn, const VRegister& vm) {
2913   VIXL_ASSERT(CPUHas(CPUFeatures::kFP));
2914   if (vn.Is1H()) VIXL_ASSERT(CPUHas(CPUFeatures::kFPHalf));
2915   FPCompareMacro(vn, vm, DisableTrap);
2916 }
2917 
2918 
fcmpe(const VRegister & vn,const VRegister & vm)2919 void Assembler::fcmpe(const VRegister& vn, const VRegister& vm) {
2920   VIXL_ASSERT(CPUHas(CPUFeatures::kFP));
2921   if (vn.Is1H()) VIXL_ASSERT(CPUHas(CPUFeatures::kFPHalf));
2922   FPCompareMacro(vn, vm, EnableTrap);
2923 }
2924 
2925 
fcmp(const VRegister & vn,double value)2926 void Assembler::fcmp(const VRegister& vn, double value) {
2927   VIXL_ASSERT(CPUHas(CPUFeatures::kFP));
2928   if (vn.Is1H()) VIXL_ASSERT(CPUHas(CPUFeatures::kFPHalf));
2929   FPCompareMacro(vn, value, DisableTrap);
2930 }
2931 
2932 
fcmpe(const VRegister & vn,double value)2933 void Assembler::fcmpe(const VRegister& vn, double value) {
2934   VIXL_ASSERT(CPUHas(CPUFeatures::kFP));
2935   if (vn.Is1H()) VIXL_ASSERT(CPUHas(CPUFeatures::kFPHalf));
2936   FPCompareMacro(vn, value, EnableTrap);
2937 }
2938 
2939 
FPCCompareMacro(const VRegister & vn,const VRegister & vm,StatusFlags nzcv,Condition cond,FPTrapFlags trap)2940 void Assembler::FPCCompareMacro(const VRegister& vn,
2941                                 const VRegister& vm,
2942                                 StatusFlags nzcv,
2943                                 Condition cond,
2944                                 FPTrapFlags trap) {
2945   VIXL_ASSERT(vn.Is1H() || vn.Is1S() || vn.Is1D());
2946   VIXL_ASSERT(vn.IsSameSizeAndType(vm));
2947   Instr op = (trap == EnableTrap) ? FCCMPE : FCCMP;
2948   Emit(FPType(vn) | op | Rm(vm) | Cond(cond) | Rn(vn) | Nzcv(nzcv));
2949 }
2950 
fccmp(const VRegister & vn,const VRegister & vm,StatusFlags nzcv,Condition cond)2951 void Assembler::fccmp(const VRegister& vn,
2952                       const VRegister& vm,
2953                       StatusFlags nzcv,
2954                       Condition cond) {
2955   VIXL_ASSERT(CPUHas(CPUFeatures::kFP));
2956   if (vn.Is1H()) VIXL_ASSERT(CPUHas(CPUFeatures::kFPHalf));
2957   FPCCompareMacro(vn, vm, nzcv, cond, DisableTrap);
2958 }
2959 
2960 
fccmpe(const VRegister & vn,const VRegister & vm,StatusFlags nzcv,Condition cond)2961 void Assembler::fccmpe(const VRegister& vn,
2962                        const VRegister& vm,
2963                        StatusFlags nzcv,
2964                        Condition cond) {
2965   VIXL_ASSERT(CPUHas(CPUFeatures::kFP));
2966   if (vn.Is1H()) VIXL_ASSERT(CPUHas(CPUFeatures::kFPHalf));
2967   FPCCompareMacro(vn, vm, nzcv, cond, EnableTrap);
2968 }
2969 
2970 
fcsel(const VRegister & vd,const VRegister & vn,const VRegister & vm,Condition cond)2971 void Assembler::fcsel(const VRegister& vd,
2972                       const VRegister& vn,
2973                       const VRegister& vm,
2974                       Condition cond) {
2975   VIXL_ASSERT(CPUHas(CPUFeatures::kFP));
2976   if (vd.Is1H()) VIXL_ASSERT(CPUHas(CPUFeatures::kFPHalf));
2977   VIXL_ASSERT(vd.Is1H() || vd.Is1S() || vd.Is1D());
2978   VIXL_ASSERT(AreSameFormat(vd, vn, vm));
2979   Emit(FPType(vd) | FCSEL | Rm(vm) | Cond(cond) | Rn(vn) | Rd(vd));
2980 }
2981 
2982 
fcvt(const VRegister & vd,const VRegister & vn)2983 void Assembler::fcvt(const VRegister& vd, const VRegister& vn) {
2984   VIXL_ASSERT(CPUHas(CPUFeatures::kFP));
2985   FPDataProcessing1SourceOp op;
2986   // The half-precision variants belong to base FP, and do not require kFPHalf.
2987   if (vd.Is1D()) {
2988     VIXL_ASSERT(vn.Is1S() || vn.Is1H());
2989     op = vn.Is1S() ? FCVT_ds : FCVT_dh;
2990   } else if (vd.Is1S()) {
2991     VIXL_ASSERT(vn.Is1D() || vn.Is1H());
2992     op = vn.Is1D() ? FCVT_sd : FCVT_sh;
2993   } else {
2994     VIXL_ASSERT(vd.Is1H());
2995     VIXL_ASSERT(vn.Is1D() || vn.Is1S());
2996     op = vn.Is1D() ? FCVT_hd : FCVT_hs;
2997   }
2998   FPDataProcessing1Source(vd, vn, op);
2999 }
3000 
3001 
fcvtl(const VRegister & vd,const VRegister & vn)3002 void Assembler::fcvtl(const VRegister& vd, const VRegister& vn) {
3003   VIXL_ASSERT(CPUHas(CPUFeatures::kFP, CPUFeatures::kNEON));
3004   VIXL_ASSERT((vd.Is4S() && vn.Is4H()) || (vd.Is2D() && vn.Is2S()));
3005   // The half-precision variants belong to base FP, and do not require kFPHalf.
3006   Instr format = vd.Is2D() ? (1 << NEONSize_offset) : 0;
3007   Emit(format | NEON_FCVTL | Rn(vn) | Rd(vd));
3008 }
3009 
3010 
fcvtl2(const VRegister & vd,const VRegister & vn)3011 void Assembler::fcvtl2(const VRegister& vd, const VRegister& vn) {
3012   VIXL_ASSERT(CPUHas(CPUFeatures::kFP, CPUFeatures::kNEON));
3013   VIXL_ASSERT((vd.Is4S() && vn.Is8H()) || (vd.Is2D() && vn.Is4S()));
3014   // The half-precision variants belong to base FP, and do not require kFPHalf.
3015   Instr format = vd.Is2D() ? (1 << NEONSize_offset) : 0;
3016   Emit(NEON_Q | format | NEON_FCVTL | Rn(vn) | Rd(vd));
3017 }
3018 
3019 
fcvtn(const VRegister & vd,const VRegister & vn)3020 void Assembler::fcvtn(const VRegister& vd, const VRegister& vn) {
3021   VIXL_ASSERT(CPUHas(CPUFeatures::kFP, CPUFeatures::kNEON));
3022   VIXL_ASSERT((vn.Is4S() && vd.Is4H()) || (vn.Is2D() && vd.Is2S()));
3023   // The half-precision variants belong to base FP, and do not require kFPHalf.
3024   Instr format = vn.Is2D() ? (1 << NEONSize_offset) : 0;
3025   Emit(format | NEON_FCVTN | Rn(vn) | Rd(vd));
3026 }
3027 
3028 
fcvtn2(const VRegister & vd,const VRegister & vn)3029 void Assembler::fcvtn2(const VRegister& vd, const VRegister& vn) {
3030   VIXL_ASSERT(CPUHas(CPUFeatures::kFP, CPUFeatures::kNEON));
3031   VIXL_ASSERT((vn.Is4S() && vd.Is8H()) || (vn.Is2D() && vd.Is4S()));
3032   // The half-precision variants belong to base FP, and do not require kFPHalf.
3033   Instr format = vn.Is2D() ? (1 << NEONSize_offset) : 0;
3034   Emit(NEON_Q | format | NEON_FCVTN | Rn(vn) | Rd(vd));
3035 }
3036 
3037 
fcvtxn(const VRegister & vd,const VRegister & vn)3038 void Assembler::fcvtxn(const VRegister& vd, const VRegister& vn) {
3039   VIXL_ASSERT(CPUHas(CPUFeatures::kFP, CPUFeatures::kNEON));
3040   Instr format = 1 << NEONSize_offset;
3041   if (vd.IsScalar()) {
3042     VIXL_ASSERT(vd.Is1S() && vn.Is1D());
3043     Emit(format | NEON_FCVTXN_scalar | Rn(vn) | Rd(vd));
3044   } else {
3045     VIXL_ASSERT(vd.Is2S() && vn.Is2D());
3046     Emit(format | NEON_FCVTXN | Rn(vn) | Rd(vd));
3047   }
3048 }
3049 
3050 
fcvtxn2(const VRegister & vd,const VRegister & vn)3051 void Assembler::fcvtxn2(const VRegister& vd, const VRegister& vn) {
3052   VIXL_ASSERT(CPUHas(CPUFeatures::kFP, CPUFeatures::kNEON));
3053   VIXL_ASSERT(vd.Is4S() && vn.Is2D());
3054   Instr format = 1 << NEONSize_offset;
3055   Emit(NEON_Q | format | NEON_FCVTXN | Rn(vn) | Rd(vd));
3056 }
3057 
fjcvtzs(const Register & rd,const VRegister & vn)3058 void Assembler::fjcvtzs(const Register& rd, const VRegister& vn) {
3059   VIXL_ASSERT(CPUHas(CPUFeatures::kFP, CPUFeatures::kJSCVT));
3060   VIXL_ASSERT(rd.IsW() && vn.Is1D());
3061   Emit(FJCVTZS | Rn(vn) | Rd(rd));
3062 }
3063 
3064 
NEONFPConvertToInt(const Register & rd,const VRegister & vn,Instr op)3065 void Assembler::NEONFPConvertToInt(const Register& rd,
3066                                    const VRegister& vn,
3067                                    Instr op) {
3068   Emit(SF(rd) | FPType(vn) | op | Rn(vn) | Rd(rd));
3069 }
3070 
3071 
NEONFPConvertToInt(const VRegister & vd,const VRegister & vn,Instr op)3072 void Assembler::NEONFPConvertToInt(const VRegister& vd,
3073                                    const VRegister& vn,
3074                                    Instr op) {
3075   if (vn.IsScalar()) {
3076     VIXL_ASSERT((vd.Is1S() && vn.Is1S()) || (vd.Is1D() && vn.Is1D()));
3077     op |= NEON_Q | NEONScalar;
3078   }
3079   Emit(FPFormat(vn) | op | Rn(vn) | Rd(vd));
3080 }
3081 
3082 
NEONFP16ConvertToInt(const VRegister & vd,const VRegister & vn,Instr op)3083 void Assembler::NEONFP16ConvertToInt(const VRegister& vd,
3084                                      const VRegister& vn,
3085                                      Instr op) {
3086   VIXL_ASSERT(AreSameFormat(vd, vn));
3087   VIXL_ASSERT(vn.IsLaneSizeH());
3088   if (vn.IsScalar()) {
3089     op |= NEON_Q | NEONScalar;
3090   } else if (vn.Is8H()) {
3091     op |= NEON_Q;
3092   }
3093   Emit(op | Rn(vn) | Rd(vd));
3094 }
3095 
3096 
3097 #define NEON_FP2REGMISC_FCVT_LIST(V) \
3098   V(fcvtnu, NEON_FCVTNU, FCVTNU)     \
3099   V(fcvtns, NEON_FCVTNS, FCVTNS)     \
3100   V(fcvtpu, NEON_FCVTPU, FCVTPU)     \
3101   V(fcvtps, NEON_FCVTPS, FCVTPS)     \
3102   V(fcvtmu, NEON_FCVTMU, FCVTMU)     \
3103   V(fcvtms, NEON_FCVTMS, FCVTMS)     \
3104   V(fcvtau, NEON_FCVTAU, FCVTAU)     \
3105   V(fcvtas, NEON_FCVTAS, FCVTAS)
3106 
3107 #define DEFINE_ASM_FUNCS(FN, VEC_OP, SCA_OP)                     \
3108   void Assembler::FN(const Register& rd, const VRegister& vn) {  \
3109     VIXL_ASSERT(CPUHas(CPUFeatures::kFP));                       \
3110     if (vn.IsH()) VIXL_ASSERT(CPUHas(CPUFeatures::kFPHalf));     \
3111     NEONFPConvertToInt(rd, vn, SCA_OP);                          \
3112   }                                                              \
3113   void Assembler::FN(const VRegister& vd, const VRegister& vn) { \
3114     VIXL_ASSERT(CPUHas(CPUFeatures::kFP, CPUFeatures::kNEON));   \
3115     if (vd.IsLaneSizeH()) {                                      \
3116       VIXL_ASSERT(CPUHas(CPUFeatures::kNEONHalf));               \
3117       NEONFP16ConvertToInt(vd, vn, VEC_OP##_H);                  \
3118     } else {                                                     \
3119       NEONFPConvertToInt(vd, vn, VEC_OP);                        \
3120     }                                                            \
3121   }
NEON_FP2REGMISC_FCVT_LIST(DEFINE_ASM_FUNCS)3122 NEON_FP2REGMISC_FCVT_LIST(DEFINE_ASM_FUNCS)
3123 #undef DEFINE_ASM_FUNCS
3124 
3125 
3126 void Assembler::fcvtzs(const Register& rd, const VRegister& vn, int fbits) {
3127   VIXL_ASSERT(CPUHas(CPUFeatures::kFP));
3128   if (vn.Is1H()) VIXL_ASSERT(CPUHas(CPUFeatures::kFPHalf));
3129   VIXL_ASSERT(vn.Is1H() || vn.Is1S() || vn.Is1D());
3130   VIXL_ASSERT((fbits >= 0) && (fbits <= rd.GetSizeInBits()));
3131   if (fbits == 0) {
3132     Emit(SF(rd) | FPType(vn) | FCVTZS | Rn(vn) | Rd(rd));
3133   } else {
3134     Emit(SF(rd) | FPType(vn) | FCVTZS_fixed | FPScale(64 - fbits) | Rn(vn) |
3135          Rd(rd));
3136   }
3137 }
3138 
3139 
fcvtzs(const VRegister & vd,const VRegister & vn,int fbits)3140 void Assembler::fcvtzs(const VRegister& vd, const VRegister& vn, int fbits) {
3141   // This form is a NEON scalar FP instruction.
3142   VIXL_ASSERT(CPUHas(CPUFeatures::kFP, CPUFeatures::kNEON));
3143   if (vn.IsLaneSizeH()) VIXL_ASSERT(CPUHas(CPUFeatures::kNEONHalf));
3144   VIXL_ASSERT(fbits >= 0);
3145   if (fbits == 0) {
3146     if (vd.IsLaneSizeH()) {
3147       NEONFP2RegMiscFP16(vd, vn, NEON_FCVTZS_H);
3148     } else {
3149       NEONFP2RegMisc(vd, vn, NEON_FCVTZS);
3150     }
3151   } else {
3152     VIXL_ASSERT(vd.Is1D() || vd.Is1S() || vd.Is2D() || vd.Is2S() || vd.Is4S() ||
3153                 vd.Is1H() || vd.Is4H() || vd.Is8H());
3154     NEONShiftRightImmediate(vd, vn, fbits, NEON_FCVTZS_imm);
3155   }
3156 }
3157 
3158 
fcvtzu(const Register & rd,const VRegister & vn,int fbits)3159 void Assembler::fcvtzu(const Register& rd, const VRegister& vn, int fbits) {
3160   VIXL_ASSERT(CPUHas(CPUFeatures::kFP));
3161   if (vn.Is1H()) VIXL_ASSERT(CPUHas(CPUFeatures::kFPHalf));
3162   VIXL_ASSERT(vn.Is1H() || vn.Is1S() || vn.Is1D());
3163   VIXL_ASSERT((fbits >= 0) && (fbits <= rd.GetSizeInBits()));
3164   if (fbits == 0) {
3165     Emit(SF(rd) | FPType(vn) | FCVTZU | Rn(vn) | Rd(rd));
3166   } else {
3167     Emit(SF(rd) | FPType(vn) | FCVTZU_fixed | FPScale(64 - fbits) | Rn(vn) |
3168          Rd(rd));
3169   }
3170 }
3171 
3172 
fcvtzu(const VRegister & vd,const VRegister & vn,int fbits)3173 void Assembler::fcvtzu(const VRegister& vd, const VRegister& vn, int fbits) {
3174   // This form is a NEON scalar FP instruction.
3175   VIXL_ASSERT(CPUHas(CPUFeatures::kFP, CPUFeatures::kNEON));
3176   if (vn.IsLaneSizeH()) VIXL_ASSERT(CPUHas(CPUFeatures::kNEONHalf));
3177   VIXL_ASSERT(fbits >= 0);
3178   if (fbits == 0) {
3179     if (vd.IsLaneSizeH()) {
3180       NEONFP2RegMiscFP16(vd, vn, NEON_FCVTZU_H);
3181     } else {
3182       NEONFP2RegMisc(vd, vn, NEON_FCVTZU);
3183     }
3184   } else {
3185     VIXL_ASSERT(vd.Is1D() || vd.Is1S() || vd.Is2D() || vd.Is2S() || vd.Is4S() ||
3186                 vd.Is1H() || vd.Is4H() || vd.Is8H());
3187     NEONShiftRightImmediate(vd, vn, fbits, NEON_FCVTZU_imm);
3188   }
3189 }
3190 
ucvtf(const VRegister & vd,const VRegister & vn,int fbits)3191 void Assembler::ucvtf(const VRegister& vd, const VRegister& vn, int fbits) {
3192   // This form is a NEON scalar FP instruction.
3193   VIXL_ASSERT(CPUHas(CPUFeatures::kFP, CPUFeatures::kNEON));
3194   if (vn.IsLaneSizeH()) VIXL_ASSERT(CPUHas(CPUFeatures::kNEONHalf));
3195   VIXL_ASSERT(fbits >= 0);
3196   if (fbits == 0) {
3197     if (vd.IsLaneSizeH()) {
3198       NEONFP2RegMiscFP16(vd, vn, NEON_UCVTF_H);
3199     } else {
3200       NEONFP2RegMisc(vd, vn, NEON_UCVTF);
3201     }
3202   } else {
3203     VIXL_ASSERT(vd.Is1D() || vd.Is1S() || vd.Is2D() || vd.Is2S() || vd.Is4S() ||
3204                 vd.Is1H() || vd.Is4H() || vd.Is8H());
3205     NEONShiftRightImmediate(vd, vn, fbits, NEON_UCVTF_imm);
3206   }
3207 }
3208 
scvtf(const VRegister & vd,const VRegister & vn,int fbits)3209 void Assembler::scvtf(const VRegister& vd, const VRegister& vn, int fbits) {
3210   // This form is a NEON scalar FP instruction.
3211   VIXL_ASSERT(CPUHas(CPUFeatures::kFP, CPUFeatures::kNEON));
3212   if (vn.IsLaneSizeH()) VIXL_ASSERT(CPUHas(CPUFeatures::kNEONHalf));
3213   VIXL_ASSERT(fbits >= 0);
3214   if (fbits == 0) {
3215     if (vd.IsLaneSizeH()) {
3216       NEONFP2RegMiscFP16(vd, vn, NEON_SCVTF_H);
3217     } else {
3218       NEONFP2RegMisc(vd, vn, NEON_SCVTF);
3219     }
3220   } else {
3221     VIXL_ASSERT(vd.Is1D() || vd.Is1S() || vd.Is2D() || vd.Is2S() || vd.Is4S() ||
3222                 vd.Is1H() || vd.Is4H() || vd.Is8H());
3223     NEONShiftRightImmediate(vd, vn, fbits, NEON_SCVTF_imm);
3224   }
3225 }
3226 
3227 
scvtf(const VRegister & vd,const Register & rn,int fbits)3228 void Assembler::scvtf(const VRegister& vd, const Register& rn, int fbits) {
3229   VIXL_ASSERT(CPUHas(CPUFeatures::kFP));
3230   if (vd.Is1H()) VIXL_ASSERT(CPUHas(CPUFeatures::kFPHalf));
3231   VIXL_ASSERT(vd.Is1H() || vd.Is1S() || vd.Is1D());
3232   VIXL_ASSERT(fbits >= 0);
3233   if (fbits == 0) {
3234     Emit(SF(rn) | FPType(vd) | SCVTF | Rn(rn) | Rd(vd));
3235   } else {
3236     Emit(SF(rn) | FPType(vd) | SCVTF_fixed | FPScale(64 - fbits) | Rn(rn) |
3237          Rd(vd));
3238   }
3239 }
3240 
3241 
ucvtf(const VRegister & vd,const Register & rn,int fbits)3242 void Assembler::ucvtf(const VRegister& vd, const Register& rn, int fbits) {
3243   VIXL_ASSERT(CPUHas(CPUFeatures::kFP));
3244   if (vd.Is1H()) VIXL_ASSERT(CPUHas(CPUFeatures::kFPHalf));
3245   VIXL_ASSERT(vd.Is1H() || vd.Is1S() || vd.Is1D());
3246   VIXL_ASSERT(fbits >= 0);
3247   if (fbits == 0) {
3248     Emit(SF(rn) | FPType(vd) | UCVTF | Rn(rn) | Rd(vd));
3249   } else {
3250     Emit(SF(rn) | FPType(vd) | UCVTF_fixed | FPScale(64 - fbits) | Rn(rn) |
3251          Rd(vd));
3252   }
3253 }
3254 
3255 
NEON3Same(const VRegister & vd,const VRegister & vn,const VRegister & vm,NEON3SameOp vop)3256 void Assembler::NEON3Same(const VRegister& vd,
3257                           const VRegister& vn,
3258                           const VRegister& vm,
3259                           NEON3SameOp vop) {
3260   VIXL_ASSERT(AreSameFormat(vd, vn, vm));
3261   VIXL_ASSERT(vd.IsVector() || !vd.IsQ());
3262 
3263   Instr format, op = vop;
3264   if (vd.IsScalar()) {
3265     op |= NEON_Q | NEONScalar;
3266     format = SFormat(vd);
3267   } else {
3268     format = VFormat(vd);
3269   }
3270 
3271   Emit(format | op | Rm(vm) | Rn(vn) | Rd(vd));
3272 }
3273 
3274 
NEONFP3Same(const VRegister & vd,const VRegister & vn,const VRegister & vm,Instr op)3275 void Assembler::NEONFP3Same(const VRegister& vd,
3276                             const VRegister& vn,
3277                             const VRegister& vm,
3278                             Instr op) {
3279   VIXL_ASSERT(AreSameFormat(vd, vn, vm));
3280   Emit(FPFormat(vd) | op | Rm(vm) | Rn(vn) | Rd(vd));
3281 }
3282 
3283 
NEON3SameFP16(const VRegister & vd,const VRegister & vn,const VRegister & vm,Instr op)3284 void Assembler::NEON3SameFP16(const VRegister& vd,
3285                               const VRegister& vn,
3286                               const VRegister& vm,
3287                               Instr op) {
3288   VIXL_ASSERT(AreSameFormat(vd, vn, vm));
3289   VIXL_ASSERT(vd.GetLaneSizeInBytes() == kHRegSizeInBytes);
3290   if (vd.Is8H()) op |= NEON_Q;
3291   Emit(op | Rm(vm) | Rn(vn) | Rd(vd));
3292 }
3293 
3294 
3295 // clang-format off
3296 #define NEON_FP2REGMISC_LIST(V)                                        \
3297   V(fabs,    NEON_FABS,    FABS,                FABS_h)                \
3298   V(fneg,    NEON_FNEG,    FNEG,                FNEG_h)                \
3299   V(fsqrt,   NEON_FSQRT,   FSQRT,               FSQRT_h)               \
3300   V(frintn,  NEON_FRINTN,  FRINTN,              FRINTN_h)              \
3301   V(frinta,  NEON_FRINTA,  FRINTA,              FRINTA_h)              \
3302   V(frintp,  NEON_FRINTP,  FRINTP,              FRINTP_h)              \
3303   V(frintm,  NEON_FRINTM,  FRINTM,              FRINTM_h)              \
3304   V(frintx,  NEON_FRINTX,  FRINTX,              FRINTX_h)              \
3305   V(frintz,  NEON_FRINTZ,  FRINTZ,              FRINTZ_h)              \
3306   V(frinti,  NEON_FRINTI,  FRINTI,              FRINTI_h)              \
3307   V(frsqrte, NEON_FRSQRTE, NEON_FRSQRTE_scalar, NEON_FRSQRTE_H_scalar) \
3308   V(frecpe,  NEON_FRECPE,  NEON_FRECPE_scalar,  NEON_FRECPE_H_scalar)
3309 // clang-format on
3310 
3311 #define DEFINE_ASM_FUNC(FN, VEC_OP, SCA_OP, SCA_OP_H)                        \
3312   void Assembler::FN(const VRegister& vd, const VRegister& vn) {             \
3313     VIXL_ASSERT(CPUHas(CPUFeatures::kFP));                                   \
3314     Instr op;                                                                \
3315     if (vd.IsScalar()) {                                                     \
3316       if (vd.Is1H()) {                                                       \
3317         if ((SCA_OP_H & NEONScalar2RegMiscFP16FMask) ==                      \
3318             NEONScalar2RegMiscFP16Fixed) {                                   \
3319           VIXL_ASSERT(CPUHas(CPUFeatures::kNEON, CPUFeatures::kNEONHalf));   \
3320         } else {                                                             \
3321           VIXL_ASSERT(CPUHas(CPUFeatures::kFPHalf));                         \
3322         }                                                                    \
3323         op = SCA_OP_H;                                                       \
3324       } else {                                                               \
3325         if ((SCA_OP & NEONScalar2RegMiscFMask) == NEONScalar2RegMiscFixed) { \
3326           VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));                           \
3327         }                                                                    \
3328         VIXL_ASSERT(vd.Is1S() || vd.Is1D());                                 \
3329         op = SCA_OP;                                                         \
3330       }                                                                      \
3331     } else {                                                                 \
3332       VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));                               \
3333       VIXL_ASSERT(vd.Is4H() || vd.Is8H() || vd.Is2S() || vd.Is2D() ||        \
3334                   vd.Is4S());                                                \
3335       if (vd.IsLaneSizeH()) {                                                \
3336         VIXL_ASSERT(CPUHas(CPUFeatures::kNEONHalf));                         \
3337         op = VEC_OP##_H;                                                     \
3338         if (vd.Is8H()) {                                                     \
3339           op |= NEON_Q;                                                      \
3340         }                                                                    \
3341       } else {                                                               \
3342         op = VEC_OP;                                                         \
3343       }                                                                      \
3344     }                                                                        \
3345     if (vd.IsLaneSizeH()) {                                                  \
3346       NEONFP2RegMiscFP16(vd, vn, op);                                        \
3347     } else {                                                                 \
3348       NEONFP2RegMisc(vd, vn, op);                                            \
3349     }                                                                        \
3350   }
3351 NEON_FP2REGMISC_LIST(DEFINE_ASM_FUNC)
3352 #undef DEFINE_ASM_FUNC
3353 
3354 // clang-format off
3355 #define NEON_FP2REGMISC_V85_LIST(V)       \
3356   V(frint32x,  NEON_FRINT32X,  FRINT32X)  \
3357   V(frint32z,  NEON_FRINT32Z,  FRINT32Z)  \
3358   V(frint64x,  NEON_FRINT64X,  FRINT64X)  \
3359   V(frint64z,  NEON_FRINT64Z,  FRINT64Z)
3360 // clang-format on
3361 
3362 #define DEFINE_ASM_FUNC(FN, VEC_OP, SCA_OP)                                    \
3363   void Assembler::FN(const VRegister& vd, const VRegister& vn) {               \
3364     VIXL_ASSERT(CPUHas(CPUFeatures::kFP, CPUFeatures::kFrintToFixedSizedInt)); \
3365     Instr op;                                                                  \
3366     if (vd.IsScalar()) {                                                       \
3367       VIXL_ASSERT(vd.Is1S() || vd.Is1D());                                     \
3368       op = SCA_OP;                                                             \
3369     } else {                                                                   \
3370       VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));                                 \
3371       VIXL_ASSERT(vd.Is2S() || vd.Is2D() || vd.Is4S());                        \
3372       op = VEC_OP;                                                             \
3373     }                                                                          \
3374     NEONFP2RegMisc(vd, vn, op);                                                \
3375   }
NEON_FP2REGMISC_V85_LIST(DEFINE_ASM_FUNC)3376 NEON_FP2REGMISC_V85_LIST(DEFINE_ASM_FUNC)
3377 #undef DEFINE_ASM_FUNC
3378 
3379 void Assembler::NEONFP2RegMiscFP16(const VRegister& vd,
3380                                    const VRegister& vn,
3381                                    Instr op) {
3382   VIXL_ASSERT(AreSameFormat(vd, vn));
3383   Emit(op | Rn(vn) | Rd(vd));
3384 }
3385 
3386 
NEONFP2RegMisc(const VRegister & vd,const VRegister & vn,Instr op)3387 void Assembler::NEONFP2RegMisc(const VRegister& vd,
3388                                const VRegister& vn,
3389                                Instr op) {
3390   VIXL_ASSERT(AreSameFormat(vd, vn));
3391   Emit(FPFormat(vd) | op | Rn(vn) | Rd(vd));
3392 }
3393 
3394 
NEON2RegMisc(const VRegister & vd,const VRegister & vn,NEON2RegMiscOp vop,int value)3395 void Assembler::NEON2RegMisc(const VRegister& vd,
3396                              const VRegister& vn,
3397                              NEON2RegMiscOp vop,
3398                              int value) {
3399   VIXL_ASSERT(AreSameFormat(vd, vn));
3400   VIXL_ASSERT(value == 0);
3401   USE(value);
3402 
3403   Instr format, op = vop;
3404   if (vd.IsScalar()) {
3405     op |= NEON_Q | NEONScalar;
3406     format = SFormat(vd);
3407   } else {
3408     format = VFormat(vd);
3409   }
3410 
3411   Emit(format | op | Rn(vn) | Rd(vd));
3412 }
3413 
3414 
cmeq(const VRegister & vd,const VRegister & vn,int value)3415 void Assembler::cmeq(const VRegister& vd, const VRegister& vn, int value) {
3416   VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));
3417   VIXL_ASSERT(vd.IsVector() || vd.Is1D());
3418   NEON2RegMisc(vd, vn, NEON_CMEQ_zero, value);
3419 }
3420 
3421 
cmge(const VRegister & vd,const VRegister & vn,int value)3422 void Assembler::cmge(const VRegister& vd, const VRegister& vn, int value) {
3423   VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));
3424   VIXL_ASSERT(vd.IsVector() || vd.Is1D());
3425   NEON2RegMisc(vd, vn, NEON_CMGE_zero, value);
3426 }
3427 
3428 
cmgt(const VRegister & vd,const VRegister & vn,int value)3429 void Assembler::cmgt(const VRegister& vd, const VRegister& vn, int value) {
3430   VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));
3431   VIXL_ASSERT(vd.IsVector() || vd.Is1D());
3432   NEON2RegMisc(vd, vn, NEON_CMGT_zero, value);
3433 }
3434 
3435 
cmle(const VRegister & vd,const VRegister & vn,int value)3436 void Assembler::cmle(const VRegister& vd, const VRegister& vn, int value) {
3437   VIXL_ASSERT(vd.IsVector() || vd.Is1D());
3438   VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));
3439   NEON2RegMisc(vd, vn, NEON_CMLE_zero, value);
3440 }
3441 
3442 
cmlt(const VRegister & vd,const VRegister & vn,int value)3443 void Assembler::cmlt(const VRegister& vd, const VRegister& vn, int value) {
3444   VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));
3445   VIXL_ASSERT(vd.IsVector() || vd.Is1D());
3446   NEON2RegMisc(vd, vn, NEON_CMLT_zero, value);
3447 }
3448 
3449 
shll(const VRegister & vd,const VRegister & vn,int shift)3450 void Assembler::shll(const VRegister& vd, const VRegister& vn, int shift) {
3451   USE(shift);
3452   VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));
3453   VIXL_ASSERT((vd.Is8H() && vn.Is8B() && shift == 8) ||
3454               (vd.Is4S() && vn.Is4H() && shift == 16) ||
3455               (vd.Is2D() && vn.Is2S() && shift == 32));
3456   Emit(VFormat(vn) | NEON_SHLL | Rn(vn) | Rd(vd));
3457 }
3458 
3459 
shll2(const VRegister & vd,const VRegister & vn,int shift)3460 void Assembler::shll2(const VRegister& vd, const VRegister& vn, int shift) {
3461   USE(shift);
3462   VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));
3463   VIXL_ASSERT((vd.Is8H() && vn.Is16B() && shift == 8) ||
3464               (vd.Is4S() && vn.Is8H() && shift == 16) ||
3465               (vd.Is2D() && vn.Is4S() && shift == 32));
3466   Emit(VFormat(vn) | NEON_SHLL | Rn(vn) | Rd(vd));
3467 }
3468 
3469 
NEONFP2RegMisc(const VRegister & vd,const VRegister & vn,NEON2RegMiscOp vop,double value)3470 void Assembler::NEONFP2RegMisc(const VRegister& vd,
3471                                const VRegister& vn,
3472                                NEON2RegMiscOp vop,
3473                                double value) {
3474   VIXL_ASSERT(AreSameFormat(vd, vn));
3475   VIXL_ASSERT(value == 0.0);
3476   USE(value);
3477 
3478   Instr op = vop;
3479   if (vd.IsScalar()) {
3480     VIXL_ASSERT(vd.Is1S() || vd.Is1D());
3481     op |= NEON_Q | NEONScalar;
3482   } else {
3483     VIXL_ASSERT(vd.Is2S() || vd.Is2D() || vd.Is4S());
3484   }
3485 
3486   Emit(FPFormat(vd) | op | Rn(vn) | Rd(vd));
3487 }
3488 
3489 
NEONFP2RegMiscFP16(const VRegister & vd,const VRegister & vn,NEON2RegMiscFP16Op vop,double value)3490 void Assembler::NEONFP2RegMiscFP16(const VRegister& vd,
3491                                    const VRegister& vn,
3492                                    NEON2RegMiscFP16Op vop,
3493                                    double value) {
3494   VIXL_ASSERT(AreSameFormat(vd, vn));
3495   VIXL_ASSERT(value == 0.0);
3496   USE(value);
3497 
3498   Instr op = vop;
3499   if (vd.IsScalar()) {
3500     VIXL_ASSERT(vd.Is1H());
3501     op |= NEON_Q | NEONScalar;
3502   } else {
3503     VIXL_ASSERT(vd.Is4H() || vd.Is8H());
3504     if (vd.Is8H()) {
3505       op |= NEON_Q;
3506     }
3507   }
3508 
3509   Emit(op | Rn(vn) | Rd(vd));
3510 }
3511 
3512 
fcmeq(const VRegister & vd,const VRegister & vn,double value)3513 void Assembler::fcmeq(const VRegister& vd, const VRegister& vn, double value) {
3514   VIXL_ASSERT(CPUHas(CPUFeatures::kFP, CPUFeatures::kNEON));
3515   if (vd.IsLaneSizeH()) {
3516     VIXL_ASSERT(CPUHas(CPUFeatures::kNEONHalf));
3517     NEONFP2RegMiscFP16(vd, vn, NEON_FCMEQ_H_zero, value);
3518   } else {
3519     NEONFP2RegMisc(vd, vn, NEON_FCMEQ_zero, value);
3520   }
3521 }
3522 
3523 
fcmge(const VRegister & vd,const VRegister & vn,double value)3524 void Assembler::fcmge(const VRegister& vd, const VRegister& vn, double value) {
3525   VIXL_ASSERT(CPUHas(CPUFeatures::kFP, CPUFeatures::kNEON));
3526   if (vd.IsLaneSizeH()) {
3527     VIXL_ASSERT(CPUHas(CPUFeatures::kNEONHalf));
3528     NEONFP2RegMiscFP16(vd, vn, NEON_FCMGE_H_zero, value);
3529   } else {
3530     NEONFP2RegMisc(vd, vn, NEON_FCMGE_zero, value);
3531   }
3532 }
3533 
3534 
fcmgt(const VRegister & vd,const VRegister & vn,double value)3535 void Assembler::fcmgt(const VRegister& vd, const VRegister& vn, double value) {
3536   VIXL_ASSERT(CPUHas(CPUFeatures::kFP, CPUFeatures::kNEON));
3537   if (vd.IsLaneSizeH()) {
3538     VIXL_ASSERT(CPUHas(CPUFeatures::kNEONHalf));
3539     NEONFP2RegMiscFP16(vd, vn, NEON_FCMGT_H_zero, value);
3540   } else {
3541     NEONFP2RegMisc(vd, vn, NEON_FCMGT_zero, value);
3542   }
3543 }
3544 
3545 
fcmle(const VRegister & vd,const VRegister & vn,double value)3546 void Assembler::fcmle(const VRegister& vd, const VRegister& vn, double value) {
3547   VIXL_ASSERT(CPUHas(CPUFeatures::kFP, CPUFeatures::kNEON));
3548   if (vd.IsLaneSizeH()) {
3549     VIXL_ASSERT(CPUHas(CPUFeatures::kNEONHalf));
3550     NEONFP2RegMiscFP16(vd, vn, NEON_FCMLE_H_zero, value);
3551   } else {
3552     NEONFP2RegMisc(vd, vn, NEON_FCMLE_zero, value);
3553   }
3554 }
3555 
3556 
fcmlt(const VRegister & vd,const VRegister & vn,double value)3557 void Assembler::fcmlt(const VRegister& vd, const VRegister& vn, double value) {
3558   VIXL_ASSERT(CPUHas(CPUFeatures::kFP, CPUFeatures::kNEON));
3559   if (vd.IsLaneSizeH()) {
3560     VIXL_ASSERT(CPUHas(CPUFeatures::kNEONHalf));
3561     NEONFP2RegMiscFP16(vd, vn, NEON_FCMLT_H_zero, value);
3562   } else {
3563     NEONFP2RegMisc(vd, vn, NEON_FCMLT_zero, value);
3564   }
3565 }
3566 
3567 
frecpx(const VRegister & vd,const VRegister & vn)3568 void Assembler::frecpx(const VRegister& vd, const VRegister& vn) {
3569   VIXL_ASSERT(CPUHas(CPUFeatures::kFP, CPUFeatures::kNEON));
3570   VIXL_ASSERT(vd.IsScalar());
3571   VIXL_ASSERT(AreSameFormat(vd, vn));
3572   Instr op;
3573   if (vd.Is1H()) {
3574     VIXL_ASSERT(CPUHas(CPUFeatures::kNEONHalf));
3575     op = NEON_FRECPX_H_scalar;
3576   } else {
3577     VIXL_ASSERT(vd.Is1S() || vd.Is1D());
3578     op = NEON_FRECPX_scalar;
3579   }
3580   Emit(FPFormat(vd) | op | Rn(vn) | Rd(vd));
3581 }
3582 
3583 
3584 // clang-format off
3585 #define NEON_3SAME_LIST(V) \
3586   V(add,      NEON_ADD,      vd.IsVector() || vd.Is1D())            \
3587   V(addp,     NEON_ADDP,     vd.IsVector() || vd.Is1D())            \
3588   V(sub,      NEON_SUB,      vd.IsVector() || vd.Is1D())            \
3589   V(cmeq,     NEON_CMEQ,     vd.IsVector() || vd.Is1D())            \
3590   V(cmge,     NEON_CMGE,     vd.IsVector() || vd.Is1D())            \
3591   V(cmgt,     NEON_CMGT,     vd.IsVector() || vd.Is1D())            \
3592   V(cmhi,     NEON_CMHI,     vd.IsVector() || vd.Is1D())            \
3593   V(cmhs,     NEON_CMHS,     vd.IsVector() || vd.Is1D())            \
3594   V(cmtst,    NEON_CMTST,    vd.IsVector() || vd.Is1D())            \
3595   V(sshl,     NEON_SSHL,     vd.IsVector() || vd.Is1D())            \
3596   V(ushl,     NEON_USHL,     vd.IsVector() || vd.Is1D())            \
3597   V(srshl,    NEON_SRSHL,    vd.IsVector() || vd.Is1D())            \
3598   V(urshl,    NEON_URSHL,    vd.IsVector() || vd.Is1D())            \
3599   V(sqdmulh,  NEON_SQDMULH,  vd.IsLaneSizeH() || vd.IsLaneSizeS())  \
3600   V(sqrdmulh, NEON_SQRDMULH, vd.IsLaneSizeH() || vd.IsLaneSizeS())  \
3601   V(shadd,    NEON_SHADD,    vd.IsVector() && !vd.IsLaneSizeD())    \
3602   V(uhadd,    NEON_UHADD,    vd.IsVector() && !vd.IsLaneSizeD())    \
3603   V(srhadd,   NEON_SRHADD,   vd.IsVector() && !vd.IsLaneSizeD())    \
3604   V(urhadd,   NEON_URHADD,   vd.IsVector() && !vd.IsLaneSizeD())    \
3605   V(shsub,    NEON_SHSUB,    vd.IsVector() && !vd.IsLaneSizeD())    \
3606   V(uhsub,    NEON_UHSUB,    vd.IsVector() && !vd.IsLaneSizeD())    \
3607   V(smax,     NEON_SMAX,     vd.IsVector() && !vd.IsLaneSizeD())    \
3608   V(smaxp,    NEON_SMAXP,    vd.IsVector() && !vd.IsLaneSizeD())    \
3609   V(smin,     NEON_SMIN,     vd.IsVector() && !vd.IsLaneSizeD())    \
3610   V(sminp,    NEON_SMINP,    vd.IsVector() && !vd.IsLaneSizeD())    \
3611   V(umax,     NEON_UMAX,     vd.IsVector() && !vd.IsLaneSizeD())    \
3612   V(umaxp,    NEON_UMAXP,    vd.IsVector() && !vd.IsLaneSizeD())    \
3613   V(umin,     NEON_UMIN,     vd.IsVector() && !vd.IsLaneSizeD())    \
3614   V(uminp,    NEON_UMINP,    vd.IsVector() && !vd.IsLaneSizeD())    \
3615   V(saba,     NEON_SABA,     vd.IsVector() && !vd.IsLaneSizeD())    \
3616   V(sabd,     NEON_SABD,     vd.IsVector() && !vd.IsLaneSizeD())    \
3617   V(uaba,     NEON_UABA,     vd.IsVector() && !vd.IsLaneSizeD())    \
3618   V(uabd,     NEON_UABD,     vd.IsVector() && !vd.IsLaneSizeD())    \
3619   V(mla,      NEON_MLA,      vd.IsVector() && !vd.IsLaneSizeD())    \
3620   V(mls,      NEON_MLS,      vd.IsVector() && !vd.IsLaneSizeD())    \
3621   V(mul,      NEON_MUL,      vd.IsVector() && !vd.IsLaneSizeD())    \
3622   V(and_,     NEON_AND,      vd.Is8B() || vd.Is16B())               \
3623   V(orr,      NEON_ORR,      vd.Is8B() || vd.Is16B())               \
3624   V(orn,      NEON_ORN,      vd.Is8B() || vd.Is16B())               \
3625   V(eor,      NEON_EOR,      vd.Is8B() || vd.Is16B())               \
3626   V(bic,      NEON_BIC,      vd.Is8B() || vd.Is16B())               \
3627   V(bit,      NEON_BIT,      vd.Is8B() || vd.Is16B())               \
3628   V(bif,      NEON_BIF,      vd.Is8B() || vd.Is16B())               \
3629   V(bsl,      NEON_BSL,      vd.Is8B() || vd.Is16B())               \
3630   V(pmul,     NEON_PMUL,     vd.Is8B() || vd.Is16B())               \
3631   V(uqadd,    NEON_UQADD,    true)                                  \
3632   V(sqadd,    NEON_SQADD,    true)                                  \
3633   V(uqsub,    NEON_UQSUB,    true)                                  \
3634   V(sqsub,    NEON_SQSUB,    true)                                  \
3635   V(sqshl,    NEON_SQSHL,    true)                                  \
3636   V(uqshl,    NEON_UQSHL,    true)                                  \
3637   V(sqrshl,   NEON_SQRSHL,   true)                                  \
3638   V(uqrshl,   NEON_UQRSHL,   true)
3639 // clang-format on
3640 
3641 #define DEFINE_ASM_FUNC(FN, OP, AS)          \
3642   void Assembler::FN(const VRegister& vd,    \
3643                      const VRegister& vn,    \
3644                      const VRegister& vm) {  \
3645     VIXL_ASSERT(CPUHas(CPUFeatures::kNEON)); \
3646     VIXL_ASSERT(AS);                         \
3647     NEON3Same(vd, vn, vm, OP);               \
3648   }
3649 NEON_3SAME_LIST(DEFINE_ASM_FUNC)
3650 #undef DEFINE_ASM_FUNC
3651 
3652 // clang-format off
3653 #define NEON_FP3SAME_OP_LIST(V)                                        \
3654   V(fmulx,   NEON_FMULX,   NEON_FMULX_scalar,   NEON_FMULX_H_scalar)   \
3655   V(frecps,  NEON_FRECPS,  NEON_FRECPS_scalar,  NEON_FRECPS_H_scalar)  \
3656   V(frsqrts, NEON_FRSQRTS, NEON_FRSQRTS_scalar, NEON_FRSQRTS_H_scalar) \
3657   V(fabd,    NEON_FABD,    NEON_FABD_scalar,    NEON_FABD_H_scalar)    \
3658   V(fmla,    NEON_FMLA,    0,                   0)                     \
3659   V(fmls,    NEON_FMLS,    0,                   0)                     \
3660   V(facge,   NEON_FACGE,   NEON_FACGE_scalar,   NEON_FACGE_H_scalar)   \
3661   V(facgt,   NEON_FACGT,   NEON_FACGT_scalar,   NEON_FACGT_H_scalar)   \
3662   V(fcmeq,   NEON_FCMEQ,   NEON_FCMEQ_scalar,   NEON_FCMEQ_H_scalar)   \
3663   V(fcmge,   NEON_FCMGE,   NEON_FCMGE_scalar,   NEON_FCMGE_H_scalar)   \
3664   V(fcmgt,   NEON_FCMGT,   NEON_FCMGT_scalar,   NEON_FCMGT_H_scalar)   \
3665   V(faddp,   NEON_FADDP,   0,                   0)                     \
3666   V(fmaxp,   NEON_FMAXP,   0,                   0)                     \
3667   V(fminp,   NEON_FMINP,   0,                   0)                     \
3668   V(fmaxnmp, NEON_FMAXNMP, 0,                   0)                     \
3669   V(fadd,    NEON_FADD,    FADD,                0)                     \
3670   V(fsub,    NEON_FSUB,    FSUB,                0)                     \
3671   V(fmul,    NEON_FMUL,    FMUL,                0)                     \
3672   V(fdiv,    NEON_FDIV,    FDIV,                0)                     \
3673   V(fmax,    NEON_FMAX,    FMAX,                0)                     \
3674   V(fmin,    NEON_FMIN,    FMIN,                0)                     \
3675   V(fmaxnm,  NEON_FMAXNM,  FMAXNM,              0)                     \
3676   V(fminnm,  NEON_FMINNM,  FMINNM,              0)                     \
3677   V(fminnmp, NEON_FMINNMP, 0,                   0)
3678 // clang-format on
3679 
3680 // TODO: This macro is complicated because it classifies the instructions in the
3681 // macro list above, and treats each case differently. It could be somewhat
3682 // simpler if we were to split the macro, at the cost of some duplication.
3683 #define DEFINE_ASM_FUNC(FN, VEC_OP, SCA_OP, SCA_OP_H)                    \
3684   void Assembler::FN(const VRegister& vd,                                \
3685                      const VRegister& vn,                                \
3686                      const VRegister& vm) {                              \
3687     VIXL_ASSERT(CPUHas(CPUFeatures::kFP));                               \
3688     Instr op;                                                            \
3689     bool is_fp16 = false;                                                \
3690     if ((SCA_OP != 0) && vd.IsScalar()) {                                \
3691       if ((SCA_OP_H != 0) && vd.Is1H()) {                                \
3692         VIXL_ASSERT(CPUHas(CPUFeatures::kNEON, CPUFeatures::kNEONHalf)); \
3693         is_fp16 = true;                                                  \
3694         op = SCA_OP_H;                                                   \
3695       } else {                                                           \
3696         VIXL_ASSERT(vd.Is1H() || vd.Is1S() || vd.Is1D());                \
3697         if ((SCA_OP & NEONScalar3SameFMask) == NEONScalar3SameFixed) {   \
3698           VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));                       \
3699           if (vd.Is1H()) VIXL_ASSERT(CPUHas(CPUFeatures::kNEONHalf));    \
3700         } else if (vd.Is1H()) {                                          \
3701           VIXL_ASSERT(CPUHas(CPUFeatures::kFPHalf));                     \
3702         }                                                                \
3703         op = SCA_OP;                                                     \
3704       }                                                                  \
3705     } else {                                                             \
3706       VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));                           \
3707       VIXL_ASSERT(vd.IsVector());                                        \
3708       if (vd.Is4H() || vd.Is8H()) {                                      \
3709         VIXL_ASSERT(CPUHas(CPUFeatures::kNEONHalf));                     \
3710         is_fp16 = true;                                                  \
3711         op = VEC_OP##_H;                                                 \
3712       } else {                                                           \
3713         VIXL_ASSERT(vd.Is2S() || vd.Is2D() || vd.Is4S());                \
3714         op = VEC_OP;                                                     \
3715       }                                                                  \
3716     }                                                                    \
3717     if (is_fp16) {                                                       \
3718       NEON3SameFP16(vd, vn, vm, op);                                     \
3719     } else {                                                             \
3720       NEONFP3Same(vd, vn, vm, op);                                       \
3721     }                                                                    \
3722   }
NEON_FP3SAME_OP_LIST(DEFINE_ASM_FUNC)3723 NEON_FP3SAME_OP_LIST(DEFINE_ASM_FUNC)
3724 #undef DEFINE_ASM_FUNC
3725 
3726 
3727 // clang-format off
3728 #define NEON_FHM_LIST(V) \
3729   V(fmlal,   NEON_FMLAL)   \
3730   V(fmlal2,  NEON_FMLAL2)  \
3731   V(fmlsl,   NEON_FMLSL)   \
3732   V(fmlsl2,  NEON_FMLSL2)
3733 // clang-format on
3734 
3735 #define DEFINE_ASM_FUNC(FN, VEC_OP)                         \
3736   void Assembler::FN(const VRegister& vd,                   \
3737                      const VRegister& vn,                   \
3738                      const VRegister& vm) {                 \
3739     VIXL_ASSERT(CPUHas(CPUFeatures::kNEON,                  \
3740                        CPUFeatures::kFP,                    \
3741                        CPUFeatures::kNEONHalf,              \
3742                        CPUFeatures::kFHM));                 \
3743     VIXL_ASSERT((vd.Is2S() && vn.Is2H() && vm.Is2H()) ||    \
3744                 (vd.Is4S() && vn.Is4H() && vm.Is4H()));     \
3745     Emit(FPFormat(vd) | VEC_OP | Rm(vm) | Rn(vn) | Rd(vd)); \
3746   }
3747 NEON_FHM_LIST(DEFINE_ASM_FUNC)
3748 #undef DEFINE_ASM_FUNC
3749 
3750 
3751 void Assembler::addp(const VRegister& vd, const VRegister& vn) {
3752   VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));
3753   VIXL_ASSERT((vd.Is1D() && vn.Is2D()));
3754   Emit(SFormat(vd) | NEON_ADDP_scalar | Rn(vn) | Rd(vd));
3755 }
3756 
3757 
sqrdmlah(const VRegister & vd,const VRegister & vn,const VRegister & vm)3758 void Assembler::sqrdmlah(const VRegister& vd,
3759                          const VRegister& vn,
3760                          const VRegister& vm) {
3761   VIXL_ASSERT(CPUHas(CPUFeatures::kNEON, CPUFeatures::kRDM));
3762   VIXL_ASSERT(AreSameFormat(vd, vn, vm));
3763   VIXL_ASSERT(vd.IsVector() || !vd.IsQ());
3764 
3765   Instr format, op = NEON_SQRDMLAH;
3766   if (vd.IsScalar()) {
3767     op |= NEON_Q | NEONScalar;
3768     format = SFormat(vd);
3769   } else {
3770     format = VFormat(vd);
3771   }
3772 
3773   Emit(format | op | Rm(vm) | Rn(vn) | Rd(vd));
3774 }
3775 
3776 
sqrdmlsh(const VRegister & vd,const VRegister & vn,const VRegister & vm)3777 void Assembler::sqrdmlsh(const VRegister& vd,
3778                          const VRegister& vn,
3779                          const VRegister& vm) {
3780   VIXL_ASSERT(CPUHas(CPUFeatures::kNEON, CPUFeatures::kRDM));
3781   VIXL_ASSERT(AreSameFormat(vd, vn, vm));
3782   VIXL_ASSERT(vd.IsVector() || !vd.IsQ());
3783 
3784   Instr format, op = NEON_SQRDMLSH;
3785   if (vd.IsScalar()) {
3786     op |= NEON_Q | NEONScalar;
3787     format = SFormat(vd);
3788   } else {
3789     format = VFormat(vd);
3790   }
3791 
3792   Emit(format | op | Rm(vm) | Rn(vn) | Rd(vd));
3793 }
3794 
3795 
sdot(const VRegister & vd,const VRegister & vn,const VRegister & vm)3796 void Assembler::sdot(const VRegister& vd,
3797                      const VRegister& vn,
3798                      const VRegister& vm) {
3799   VIXL_ASSERT(CPUHas(CPUFeatures::kNEON, CPUFeatures::kDotProduct));
3800   VIXL_ASSERT(AreSameFormat(vn, vm));
3801   VIXL_ASSERT((vd.Is2S() && vn.Is8B()) || (vd.Is4S() && vn.Is16B()));
3802 
3803   Emit(VFormat(vd) | NEON_SDOT | Rm(vm) | Rn(vn) | Rd(vd));
3804 }
3805 
3806 
udot(const VRegister & vd,const VRegister & vn,const VRegister & vm)3807 void Assembler::udot(const VRegister& vd,
3808                      const VRegister& vn,
3809                      const VRegister& vm) {
3810   VIXL_ASSERT(CPUHas(CPUFeatures::kNEON, CPUFeatures::kDotProduct));
3811   VIXL_ASSERT(AreSameFormat(vn, vm));
3812   VIXL_ASSERT((vd.Is2S() && vn.Is8B()) || (vd.Is4S() && vn.Is16B()));
3813 
3814   Emit(VFormat(vd) | NEON_UDOT | Rm(vm) | Rn(vn) | Rd(vd));
3815 }
3816 
3817 
faddp(const VRegister & vd,const VRegister & vn)3818 void Assembler::faddp(const VRegister& vd, const VRegister& vn) {
3819   VIXL_ASSERT(CPUHas(CPUFeatures::kFP, CPUFeatures::kNEON));
3820   VIXL_ASSERT((vd.Is1S() && vn.Is2S()) || (vd.Is1D() && vn.Is2D()) ||
3821               (vd.Is1H() && vn.Is2H()));
3822   if (vd.Is1H()) {
3823     VIXL_ASSERT(CPUHas(CPUFeatures::kNEONHalf));
3824     Emit(NEON_FADDP_h_scalar | Rn(vn) | Rd(vd));
3825   } else {
3826     Emit(FPFormat(vd) | NEON_FADDP_scalar | Rn(vn) | Rd(vd));
3827   }
3828 }
3829 
3830 
fmaxp(const VRegister & vd,const VRegister & vn)3831 void Assembler::fmaxp(const VRegister& vd, const VRegister& vn) {
3832   VIXL_ASSERT(CPUHas(CPUFeatures::kFP, CPUFeatures::kNEON));
3833   VIXL_ASSERT((vd.Is1S() && vn.Is2S()) || (vd.Is1D() && vn.Is2D()) ||
3834               (vd.Is1H() && vn.Is2H()));
3835   if (vd.Is1H()) {
3836     VIXL_ASSERT(CPUHas(CPUFeatures::kNEONHalf));
3837     Emit(NEON_FMAXP_h_scalar | Rn(vn) | Rd(vd));
3838   } else {
3839     Emit(FPFormat(vd) | NEON_FMAXP_scalar | Rn(vn) | Rd(vd));
3840   }
3841 }
3842 
3843 
fminp(const VRegister & vd,const VRegister & vn)3844 void Assembler::fminp(const VRegister& vd, const VRegister& vn) {
3845   VIXL_ASSERT(CPUHas(CPUFeatures::kFP, CPUFeatures::kNEON));
3846   VIXL_ASSERT((vd.Is1S() && vn.Is2S()) || (vd.Is1D() && vn.Is2D()) ||
3847               (vd.Is1H() && vn.Is2H()));
3848   if (vd.Is1H()) {
3849     VIXL_ASSERT(CPUHas(CPUFeatures::kNEONHalf));
3850     Emit(NEON_FMINP_h_scalar | Rn(vn) | Rd(vd));
3851   } else {
3852     Emit(FPFormat(vd) | NEON_FMINP_scalar | Rn(vn) | Rd(vd));
3853   }
3854 }
3855 
3856 
fmaxnmp(const VRegister & vd,const VRegister & vn)3857 void Assembler::fmaxnmp(const VRegister& vd, const VRegister& vn) {
3858   VIXL_ASSERT(CPUHas(CPUFeatures::kFP, CPUFeatures::kNEON));
3859   VIXL_ASSERT((vd.Is1S() && vn.Is2S()) || (vd.Is1D() && vn.Is2D()) ||
3860               (vd.Is1H() && vn.Is2H()));
3861   if (vd.Is1H()) {
3862     VIXL_ASSERT(CPUHas(CPUFeatures::kNEONHalf));
3863     Emit(NEON_FMAXNMP_h_scalar | Rn(vn) | Rd(vd));
3864   } else {
3865     Emit(FPFormat(vd) | NEON_FMAXNMP_scalar | Rn(vn) | Rd(vd));
3866   }
3867 }
3868 
3869 
fminnmp(const VRegister & vd,const VRegister & vn)3870 void Assembler::fminnmp(const VRegister& vd, const VRegister& vn) {
3871   VIXL_ASSERT(CPUHas(CPUFeatures::kFP, CPUFeatures::kNEON));
3872   VIXL_ASSERT((vd.Is1S() && vn.Is2S()) || (vd.Is1D() && vn.Is2D()) ||
3873               (vd.Is1H() && vn.Is2H()));
3874   if (vd.Is1H()) {
3875     VIXL_ASSERT(CPUHas(CPUFeatures::kNEONHalf));
3876     Emit(NEON_FMINNMP_h_scalar | Rn(vn) | Rd(vd));
3877   } else {
3878     Emit(FPFormat(vd) | NEON_FMINNMP_scalar | Rn(vn) | Rd(vd));
3879   }
3880 }
3881 
3882 
3883 // v8.3 complex numbers - floating-point complex multiply accumulate.
fcmla(const VRegister & vd,const VRegister & vn,const VRegister & vm,int vm_index,int rot)3884 void Assembler::fcmla(const VRegister& vd,
3885                       const VRegister& vn,
3886                       const VRegister& vm,
3887                       int vm_index,
3888                       int rot) {
3889   VIXL_ASSERT(CPUHas(CPUFeatures::kFP, CPUFeatures::kNEON, CPUFeatures::kFcma));
3890   VIXL_ASSERT(vd.IsVector() && AreSameFormat(vd, vn));
3891   VIXL_ASSERT((vm.IsH() && (vd.Is8H() || vd.Is4H())) ||
3892               (vm.IsS() && vd.Is4S()));
3893   if (vd.IsLaneSizeH()) VIXL_ASSERT(CPUHas(CPUFeatures::kNEONHalf));
3894   int index_num_bits = vd.Is4S() ? 1 : 2;
3895   Emit(VFormat(vd) | Rm(vm) | NEON_FCMLA_byelement |
3896        ImmNEONHLM(vm_index, index_num_bits) | ImmRotFcmlaSca(rot) | Rn(vn) |
3897        Rd(vd));
3898 }
3899 
3900 
fcmla(const VRegister & vd,const VRegister & vn,const VRegister & vm,int rot)3901 void Assembler::fcmla(const VRegister& vd,
3902                       const VRegister& vn,
3903                       const VRegister& vm,
3904                       int rot) {
3905   VIXL_ASSERT(CPUHas(CPUFeatures::kFP, CPUFeatures::kNEON, CPUFeatures::kFcma));
3906   VIXL_ASSERT(AreSameFormat(vd, vn, vm));
3907   VIXL_ASSERT(vd.IsVector() && !vd.IsLaneSizeB());
3908   if (vd.IsLaneSizeH()) VIXL_ASSERT(CPUHas(CPUFeatures::kNEONHalf));
3909   Emit(VFormat(vd) | Rm(vm) | NEON_FCMLA | ImmRotFcmlaVec(rot) | Rn(vn) |
3910        Rd(vd));
3911 }
3912 
3913 
3914 // v8.3 complex numbers - floating-point complex add.
fcadd(const VRegister & vd,const VRegister & vn,const VRegister & vm,int rot)3915 void Assembler::fcadd(const VRegister& vd,
3916                       const VRegister& vn,
3917                       const VRegister& vm,
3918                       int rot) {
3919   VIXL_ASSERT(CPUHas(CPUFeatures::kFP, CPUFeatures::kNEON, CPUFeatures::kFcma));
3920   VIXL_ASSERT(AreSameFormat(vd, vn, vm));
3921   VIXL_ASSERT(vd.IsVector() && !vd.IsLaneSizeB());
3922   if (vd.IsLaneSizeH()) VIXL_ASSERT(CPUHas(CPUFeatures::kNEONHalf));
3923   Emit(VFormat(vd) | Rm(vm) | NEON_FCADD | ImmRotFcadd(rot) | Rn(vn) | Rd(vd));
3924 }
3925 
3926 
orr(const VRegister & vd,const int imm8,const int left_shift)3927 void Assembler::orr(const VRegister& vd, const int imm8, const int left_shift) {
3928   VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));
3929   NEONModifiedImmShiftLsl(vd, imm8, left_shift, NEONModifiedImmediate_ORR);
3930 }
3931 
3932 
mov(const VRegister & vd,const VRegister & vn)3933 void Assembler::mov(const VRegister& vd, const VRegister& vn) {
3934   VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));
3935   VIXL_ASSERT(AreSameFormat(vd, vn));
3936   if (vd.IsD()) {
3937     orr(vd.V8B(), vn.V8B(), vn.V8B());
3938   } else {
3939     VIXL_ASSERT(vd.IsQ());
3940     orr(vd.V16B(), vn.V16B(), vn.V16B());
3941   }
3942 }
3943 
3944 
bic(const VRegister & vd,const int imm8,const int left_shift)3945 void Assembler::bic(const VRegister& vd, const int imm8, const int left_shift) {
3946   VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));
3947   NEONModifiedImmShiftLsl(vd, imm8, left_shift, NEONModifiedImmediate_BIC);
3948 }
3949 
3950 
movi(const VRegister & vd,const uint64_t imm,Shift shift,const int shift_amount)3951 void Assembler::movi(const VRegister& vd,
3952                      const uint64_t imm,
3953                      Shift shift,
3954                      const int shift_amount) {
3955   VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));
3956   VIXL_ASSERT((shift == LSL) || (shift == MSL));
3957   if (vd.Is2D() || vd.Is1D()) {
3958     VIXL_ASSERT(shift_amount == 0);
3959     int imm8 = 0;
3960     for (int i = 0; i < 8; ++i) {
3961       int byte = (imm >> (i * 8)) & 0xff;
3962       VIXL_ASSERT((byte == 0) || (byte == 0xff));
3963       if (byte == 0xff) {
3964         imm8 |= (1 << i);
3965       }
3966     }
3967     int q = vd.Is2D() ? NEON_Q : 0;
3968     Emit(q | NEONModImmOp(1) | NEONModifiedImmediate_MOVI |
3969          ImmNEONabcdefgh(imm8) | NEONCmode(0xe) | Rd(vd));
3970   } else if (shift == LSL) {
3971     VIXL_ASSERT(IsUint8(imm));
3972     NEONModifiedImmShiftLsl(vd,
3973                             static_cast<int>(imm),
3974                             shift_amount,
3975                             NEONModifiedImmediate_MOVI);
3976   } else {
3977     VIXL_ASSERT(IsUint8(imm));
3978     NEONModifiedImmShiftMsl(vd,
3979                             static_cast<int>(imm),
3980                             shift_amount,
3981                             NEONModifiedImmediate_MOVI);
3982   }
3983 }
3984 
3985 
mvn(const VRegister & vd,const VRegister & vn)3986 void Assembler::mvn(const VRegister& vd, const VRegister& vn) {
3987   VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));
3988   VIXL_ASSERT(AreSameFormat(vd, vn));
3989   if (vd.IsD()) {
3990     not_(vd.V8B(), vn.V8B());
3991   } else {
3992     VIXL_ASSERT(vd.IsQ());
3993     not_(vd.V16B(), vn.V16B());
3994   }
3995 }
3996 
3997 
mvni(const VRegister & vd,const int imm8,Shift shift,const int shift_amount)3998 void Assembler::mvni(const VRegister& vd,
3999                      const int imm8,
4000                      Shift shift,
4001                      const int shift_amount) {
4002   VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));
4003   VIXL_ASSERT((shift == LSL) || (shift == MSL));
4004   if (shift == LSL) {
4005     NEONModifiedImmShiftLsl(vd, imm8, shift_amount, NEONModifiedImmediate_MVNI);
4006   } else {
4007     NEONModifiedImmShiftMsl(vd, imm8, shift_amount, NEONModifiedImmediate_MVNI);
4008   }
4009 }
4010 
4011 
NEONFPByElement(const VRegister & vd,const VRegister & vn,const VRegister & vm,int vm_index,NEONByIndexedElementOp vop,NEONByIndexedElementOp vop_half)4012 void Assembler::NEONFPByElement(const VRegister& vd,
4013                                 const VRegister& vn,
4014                                 const VRegister& vm,
4015                                 int vm_index,
4016                                 NEONByIndexedElementOp vop,
4017                                 NEONByIndexedElementOp vop_half) {
4018   VIXL_ASSERT(AreSameFormat(vd, vn));
4019   VIXL_ASSERT((vd.Is2S() && vm.Is1S()) || (vd.Is4S() && vm.Is1S()) ||
4020               (vd.Is1S() && vm.Is1S()) || (vd.Is2D() && vm.Is1D()) ||
4021               (vd.Is1D() && vm.Is1D()) || (vd.Is4H() && vm.Is1H()) ||
4022               (vd.Is8H() && vm.Is1H()) || (vd.Is1H() && vm.Is1H()));
4023   VIXL_ASSERT((vm.Is1S() && (vm_index < 4)) || (vm.Is1D() && (vm_index < 2)) ||
4024               (vm.Is1H() && (vm.GetCode() < 16) && (vm_index < 8)));
4025 
4026   Instr op = vop;
4027   int index_num_bits;
4028   if (vm.Is1D()) {
4029     index_num_bits = 1;
4030   } else if (vm.Is1S()) {
4031     index_num_bits = 2;
4032   } else {
4033     index_num_bits = 3;
4034     op = vop_half;
4035   }
4036 
4037   if (vd.IsScalar()) {
4038     op |= NEON_Q | NEONScalar;
4039   }
4040 
4041   if (!vm.Is1H()) {
4042     op |= FPFormat(vd);
4043   } else if (vd.Is8H()) {
4044     op |= NEON_Q;
4045   }
4046 
4047   Emit(op | ImmNEONHLM(vm_index, index_num_bits) | Rm(vm) | Rn(vn) | Rd(vd));
4048 }
4049 
4050 
NEONByElement(const VRegister & vd,const VRegister & vn,const VRegister & vm,int vm_index,NEONByIndexedElementOp vop)4051 void Assembler::NEONByElement(const VRegister& vd,
4052                               const VRegister& vn,
4053                               const VRegister& vm,
4054                               int vm_index,
4055                               NEONByIndexedElementOp vop) {
4056   VIXL_ASSERT(AreSameFormat(vd, vn));
4057   VIXL_ASSERT((vd.Is4H() && vm.Is1H()) || (vd.Is8H() && vm.Is1H()) ||
4058               (vd.Is1H() && vm.Is1H()) || (vd.Is2S() && vm.Is1S()) ||
4059               (vd.Is4S() && vm.Is1S()) || (vd.Is1S() && vm.Is1S()));
4060   VIXL_ASSERT((vm.Is1H() && (vm.GetCode() < 16) && (vm_index < 8)) ||
4061               (vm.Is1S() && (vm_index < 4)));
4062 
4063   Instr format, op = vop;
4064   int index_num_bits = vm.Is1H() ? 3 : 2;
4065   if (vd.IsScalar()) {
4066     op |= NEONScalar | NEON_Q;
4067     format = SFormat(vn);
4068   } else {
4069     format = VFormat(vn);
4070   }
4071   Emit(format | op | ImmNEONHLM(vm_index, index_num_bits) | Rm(vm) | Rn(vn) |
4072        Rd(vd));
4073 }
4074 
4075 
NEONByElementL(const VRegister & vd,const VRegister & vn,const VRegister & vm,int vm_index,NEONByIndexedElementOp vop)4076 void Assembler::NEONByElementL(const VRegister& vd,
4077                                const VRegister& vn,
4078                                const VRegister& vm,
4079                                int vm_index,
4080                                NEONByIndexedElementOp vop) {
4081   VIXL_ASSERT((vd.Is4S() && vn.Is4H() && vm.Is1H()) ||
4082               (vd.Is4S() && vn.Is8H() && vm.Is1H()) ||
4083               (vd.Is1S() && vn.Is1H() && vm.Is1H()) ||
4084               (vd.Is2D() && vn.Is2S() && vm.Is1S()) ||
4085               (vd.Is2D() && vn.Is4S() && vm.Is1S()) ||
4086               (vd.Is1D() && vn.Is1S() && vm.Is1S()));
4087 
4088   VIXL_ASSERT((vm.Is1H() && (vm.GetCode() < 16) && (vm_index < 8)) ||
4089               (vm.Is1S() && (vm_index < 4)));
4090 
4091   Instr format, op = vop;
4092   int index_num_bits = vm.Is1H() ? 3 : 2;
4093   if (vd.IsScalar()) {
4094     op |= NEONScalar | NEON_Q;
4095     format = SFormat(vn);
4096   } else {
4097     format = VFormat(vn);
4098   }
4099   Emit(format | op | ImmNEONHLM(vm_index, index_num_bits) | Rm(vm) | Rn(vn) |
4100        Rd(vd));
4101 }
4102 
4103 
sdot(const VRegister & vd,const VRegister & vn,const VRegister & vm,int vm_index)4104 void Assembler::sdot(const VRegister& vd,
4105                      const VRegister& vn,
4106                      const VRegister& vm,
4107                      int vm_index) {
4108   VIXL_ASSERT(CPUHas(CPUFeatures::kNEON, CPUFeatures::kDotProduct));
4109   VIXL_ASSERT((vd.Is2S() && vn.Is8B() && vm.Is1S4B()) ||
4110               (vd.Is4S() && vn.Is16B() && vm.Is1S4B()));
4111 
4112   int index_num_bits = 2;
4113   Emit(VFormat(vd) | NEON_SDOT_byelement |
4114        ImmNEONHLM(vm_index, index_num_bits) | Rm(vm) | Rn(vn) | Rd(vd));
4115 }
4116 
4117 
udot(const VRegister & vd,const VRegister & vn,const VRegister & vm,int vm_index)4118 void Assembler::udot(const VRegister& vd,
4119                      const VRegister& vn,
4120                      const VRegister& vm,
4121                      int vm_index) {
4122   VIXL_ASSERT(CPUHas(CPUFeatures::kNEON, CPUFeatures::kDotProduct));
4123   VIXL_ASSERT((vd.Is2S() && vn.Is8B() && vm.Is1S4B()) ||
4124               (vd.Is4S() && vn.Is16B() && vm.Is1S4B()));
4125 
4126   int index_num_bits = 2;
4127   Emit(VFormat(vd) | NEON_UDOT_byelement |
4128        ImmNEONHLM(vm_index, index_num_bits) | Rm(vm) | Rn(vn) | Rd(vd));
4129 }
4130 
4131 
4132 // clang-format off
4133 #define NEON_BYELEMENT_LIST(V)                        \
4134   V(mul,      NEON_MUL_byelement,      vn.IsVector()) \
4135   V(mla,      NEON_MLA_byelement,      vn.IsVector()) \
4136   V(mls,      NEON_MLS_byelement,      vn.IsVector()) \
4137   V(sqdmulh,  NEON_SQDMULH_byelement,  true)          \
4138   V(sqrdmulh, NEON_SQRDMULH_byelement, true)          \
4139 // clang-format on
4140 
4141 #define DEFINE_ASM_FUNC(FN, OP, AS)                     \
4142   void Assembler::FN(const VRegister& vd,               \
4143                      const VRegister& vn,               \
4144                      const VRegister& vm,               \
4145                      int vm_index) {                    \
4146     VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));            \
4147     VIXL_ASSERT(AS);                                    \
4148     NEONByElement(vd, vn, vm, vm_index, OP);            \
4149   }
4150 NEON_BYELEMENT_LIST(DEFINE_ASM_FUNC)
4151 #undef DEFINE_ASM_FUNC
4152 
4153 
4154 // clang-format off
4155 #define NEON_BYELEMENT_RDM_LIST(V)     \
4156   V(sqrdmlah, NEON_SQRDMLAH_byelement) \
4157   V(sqrdmlsh, NEON_SQRDMLSH_byelement)
4158 // clang-format on
4159 
4160 #define DEFINE_ASM_FUNC(FN, OP)                                 \
4161   void Assembler::FN(const VRegister& vd,                       \
4162                      const VRegister& vn,                       \
4163                      const VRegister& vm,                       \
4164                      int vm_index) {                            \
4165     VIXL_ASSERT(CPUHas(CPUFeatures::kNEON, CPUFeatures::kRDM)); \
4166     NEONByElement(vd, vn, vm, vm_index, OP);                    \
4167   }
NEON_BYELEMENT_RDM_LIST(DEFINE_ASM_FUNC)4168 NEON_BYELEMENT_RDM_LIST(DEFINE_ASM_FUNC)
4169 #undef DEFINE_ASM_FUNC
4170 
4171 
4172 // clang-format off
4173 #define NEON_FPBYELEMENT_LIST(V) \
4174   V(fmul,  NEON_FMUL_byelement,  NEON_FMUL_H_byelement)  \
4175   V(fmla,  NEON_FMLA_byelement,  NEON_FMLA_H_byelement)  \
4176   V(fmls,  NEON_FMLS_byelement,  NEON_FMLS_H_byelement)  \
4177   V(fmulx, NEON_FMULX_byelement, NEON_FMULX_H_byelement)
4178 // clang-format on
4179 
4180 #define DEFINE_ASM_FUNC(FN, OP, OP_H)                                  \
4181   void Assembler::FN(const VRegister& vd,                              \
4182                      const VRegister& vn,                              \
4183                      const VRegister& vm,                              \
4184                      int vm_index) {                                   \
4185     VIXL_ASSERT(CPUHas(CPUFeatures::kFP, CPUFeatures::kNEON));         \
4186     if (vd.IsLaneSizeH()) VIXL_ASSERT(CPUHas(CPUFeatures::kNEONHalf)); \
4187     NEONFPByElement(vd, vn, vm, vm_index, OP, OP_H);                   \
4188   }
4189 NEON_FPBYELEMENT_LIST(DEFINE_ASM_FUNC)
4190 #undef DEFINE_ASM_FUNC
4191 
4192 
4193 // clang-format off
4194 #define NEON_BYELEMENT_LONG_LIST(V)                               \
4195   V(sqdmull,  NEON_SQDMULL_byelement, vn.IsScalar() || vn.IsD())  \
4196   V(sqdmull2, NEON_SQDMULL_byelement, vn.IsVector() && vn.IsQ())  \
4197   V(sqdmlal,  NEON_SQDMLAL_byelement, vn.IsScalar() || vn.IsD())  \
4198   V(sqdmlal2, NEON_SQDMLAL_byelement, vn.IsVector() && vn.IsQ())  \
4199   V(sqdmlsl,  NEON_SQDMLSL_byelement, vn.IsScalar() || vn.IsD())  \
4200   V(sqdmlsl2, NEON_SQDMLSL_byelement, vn.IsVector() && vn.IsQ())  \
4201   V(smull,    NEON_SMULL_byelement,   vn.IsVector() && vn.IsD())  \
4202   V(smull2,   NEON_SMULL_byelement,   vn.IsVector() && vn.IsQ())  \
4203   V(umull,    NEON_UMULL_byelement,   vn.IsVector() && vn.IsD())  \
4204   V(umull2,   NEON_UMULL_byelement,   vn.IsVector() && vn.IsQ())  \
4205   V(smlal,    NEON_SMLAL_byelement,   vn.IsVector() && vn.IsD())  \
4206   V(smlal2,   NEON_SMLAL_byelement,   vn.IsVector() && vn.IsQ())  \
4207   V(umlal,    NEON_UMLAL_byelement,   vn.IsVector() && vn.IsD())  \
4208   V(umlal2,   NEON_UMLAL_byelement,   vn.IsVector() && vn.IsQ())  \
4209   V(smlsl,    NEON_SMLSL_byelement,   vn.IsVector() && vn.IsD())  \
4210   V(smlsl2,   NEON_SMLSL_byelement,   vn.IsVector() && vn.IsQ())  \
4211   V(umlsl,    NEON_UMLSL_byelement,   vn.IsVector() && vn.IsD())  \
4212   V(umlsl2,   NEON_UMLSL_byelement,   vn.IsVector() && vn.IsQ())
4213 // clang-format on
4214 
4215 
4216 #define DEFINE_ASM_FUNC(FN, OP, AS)           \
4217   void Assembler::FN(const VRegister& vd,     \
4218                      const VRegister& vn,     \
4219                      const VRegister& vm,     \
4220                      int vm_index) {          \
4221     VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));  \
4222     VIXL_ASSERT(AS);                          \
4223     NEONByElementL(vd, vn, vm, vm_index, OP); \
4224   }
4225 NEON_BYELEMENT_LONG_LIST(DEFINE_ASM_FUNC)
4226 #undef DEFINE_ASM_FUNC
4227 
4228 
4229 // clang-format off
4230 #define NEON_BYELEMENT_FHM_LIST(V)    \
4231   V(fmlal, NEON_FMLAL_H_byelement)    \
4232   V(fmlal2, NEON_FMLAL2_H_byelement)  \
4233   V(fmlsl, NEON_FMLSL_H_byelement)    \
4234   V(fmlsl2, NEON_FMLSL2_H_byelement)
4235 // clang-format on
4236 
4237 
4238 #define DEFINE_ASM_FUNC(FN, OP)                                        \
4239   void Assembler::FN(const VRegister& vd,                              \
4240                      const VRegister& vn,                              \
4241                      const VRegister& vm,                              \
4242                      int vm_index) {                                   \
4243     VIXL_ASSERT(CPUHas(CPUFeatures::kNEON,                             \
4244                        CPUFeatures::kFP,                               \
4245                        CPUFeatures::kNEONHalf,                         \
4246                        CPUFeatures::kFHM));                            \
4247     VIXL_ASSERT((vd.Is2S() && vn.Is2H()) || (vd.Is4S() && vn.Is4H())); \
4248     VIXL_ASSERT(vm.IsH());                                             \
4249     VIXL_ASSERT((vm_index >= 0) && (vm_index < 8));                    \
4250     /* Vm itself can only be in the bottom 16 registers. */            \
4251     VIXL_ASSERT(vm.GetCode() < 16);                                    \
4252     Emit(FPFormat(vd) | OP | Rd(vd) | Rn(vn) | Rm(vm) |                \
4253          ImmNEONHLM(vm_index, 3));                                     \
4254   }
4255 NEON_BYELEMENT_FHM_LIST(DEFINE_ASM_FUNC)
4256 #undef DEFINE_ASM_FUNC
4257 
4258 void Assembler::suqadd(const VRegister& vd, const VRegister& vn) {
4259   VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));
4260   NEON2RegMisc(vd, vn, NEON_SUQADD);
4261 }
4262 
4263 
usqadd(const VRegister & vd,const VRegister & vn)4264 void Assembler::usqadd(const VRegister& vd, const VRegister& vn) {
4265   VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));
4266   NEON2RegMisc(vd, vn, NEON_USQADD);
4267 }
4268 
4269 
abs(const VRegister & vd,const VRegister & vn)4270 void Assembler::abs(const VRegister& vd, const VRegister& vn) {
4271   VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));
4272   VIXL_ASSERT(vd.IsVector() || vd.Is1D());
4273   NEON2RegMisc(vd, vn, NEON_ABS);
4274 }
4275 
4276 
sqabs(const VRegister & vd,const VRegister & vn)4277 void Assembler::sqabs(const VRegister& vd, const VRegister& vn) {
4278   VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));
4279   NEON2RegMisc(vd, vn, NEON_SQABS);
4280 }
4281 
4282 
neg(const VRegister & vd,const VRegister & vn)4283 void Assembler::neg(const VRegister& vd, const VRegister& vn) {
4284   VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));
4285   VIXL_ASSERT(vd.IsVector() || vd.Is1D());
4286   NEON2RegMisc(vd, vn, NEON_NEG);
4287 }
4288 
4289 
sqneg(const VRegister & vd,const VRegister & vn)4290 void Assembler::sqneg(const VRegister& vd, const VRegister& vn) {
4291   VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));
4292   NEON2RegMisc(vd, vn, NEON_SQNEG);
4293 }
4294 
4295 
NEONXtn(const VRegister & vd,const VRegister & vn,NEON2RegMiscOp vop)4296 void Assembler::NEONXtn(const VRegister& vd,
4297                         const VRegister& vn,
4298                         NEON2RegMiscOp vop) {
4299   VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));
4300   Instr format, op = vop;
4301   if (vd.IsScalar()) {
4302     VIXL_ASSERT((vd.Is1B() && vn.Is1H()) || (vd.Is1H() && vn.Is1S()) ||
4303                 (vd.Is1S() && vn.Is1D()));
4304     op |= NEON_Q | NEONScalar;
4305     format = SFormat(vd);
4306   } else {
4307     VIXL_ASSERT((vd.Is8B() && vn.Is8H()) || (vd.Is4H() && vn.Is4S()) ||
4308                 (vd.Is2S() && vn.Is2D()) || (vd.Is16B() && vn.Is8H()) ||
4309                 (vd.Is8H() && vn.Is4S()) || (vd.Is4S() && vn.Is2D()));
4310     format = VFormat(vd);
4311   }
4312   Emit(format | op | Rn(vn) | Rd(vd));
4313 }
4314 
4315 
xtn(const VRegister & vd,const VRegister & vn)4316 void Assembler::xtn(const VRegister& vd, const VRegister& vn) {
4317   VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));
4318   VIXL_ASSERT(vd.IsVector() && vd.IsD());
4319   NEONXtn(vd, vn, NEON_XTN);
4320 }
4321 
4322 
xtn2(const VRegister & vd,const VRegister & vn)4323 void Assembler::xtn2(const VRegister& vd, const VRegister& vn) {
4324   VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));
4325   VIXL_ASSERT(vd.IsVector() && vd.IsQ());
4326   NEONXtn(vd, vn, NEON_XTN);
4327 }
4328 
4329 
sqxtn(const VRegister & vd,const VRegister & vn)4330 void Assembler::sqxtn(const VRegister& vd, const VRegister& vn) {
4331   VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));
4332   VIXL_ASSERT(vd.IsScalar() || vd.IsD());
4333   NEONXtn(vd, vn, NEON_SQXTN);
4334 }
4335 
4336 
sqxtn2(const VRegister & vd,const VRegister & vn)4337 void Assembler::sqxtn2(const VRegister& vd, const VRegister& vn) {
4338   VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));
4339   VIXL_ASSERT(vd.IsVector() && vd.IsQ());
4340   NEONXtn(vd, vn, NEON_SQXTN);
4341 }
4342 
4343 
sqxtun(const VRegister & vd,const VRegister & vn)4344 void Assembler::sqxtun(const VRegister& vd, const VRegister& vn) {
4345   VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));
4346   VIXL_ASSERT(vd.IsScalar() || vd.IsD());
4347   NEONXtn(vd, vn, NEON_SQXTUN);
4348 }
4349 
4350 
sqxtun2(const VRegister & vd,const VRegister & vn)4351 void Assembler::sqxtun2(const VRegister& vd, const VRegister& vn) {
4352   VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));
4353   VIXL_ASSERT(vd.IsVector() && vd.IsQ());
4354   NEONXtn(vd, vn, NEON_SQXTUN);
4355 }
4356 
4357 
uqxtn(const VRegister & vd,const VRegister & vn)4358 void Assembler::uqxtn(const VRegister& vd, const VRegister& vn) {
4359   VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));
4360   VIXL_ASSERT(vd.IsScalar() || vd.IsD());
4361   NEONXtn(vd, vn, NEON_UQXTN);
4362 }
4363 
4364 
uqxtn2(const VRegister & vd,const VRegister & vn)4365 void Assembler::uqxtn2(const VRegister& vd, const VRegister& vn) {
4366   VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));
4367   VIXL_ASSERT(vd.IsVector() && vd.IsQ());
4368   NEONXtn(vd, vn, NEON_UQXTN);
4369 }
4370 
4371 
4372 // NEON NOT and RBIT are distinguised by bit 22, the bottom bit of "size".
not_(const VRegister & vd,const VRegister & vn)4373 void Assembler::not_(const VRegister& vd, const VRegister& vn) {
4374   VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));
4375   VIXL_ASSERT(AreSameFormat(vd, vn));
4376   VIXL_ASSERT(vd.Is8B() || vd.Is16B());
4377   Emit(VFormat(vd) | NEON_RBIT_NOT | Rn(vn) | Rd(vd));
4378 }
4379 
4380 
rbit(const VRegister & vd,const VRegister & vn)4381 void Assembler::rbit(const VRegister& vd, const VRegister& vn) {
4382   VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));
4383   VIXL_ASSERT(AreSameFormat(vd, vn));
4384   VIXL_ASSERT(vd.Is8B() || vd.Is16B());
4385   Emit(VFormat(vn) | (1 << NEONSize_offset) | NEON_RBIT_NOT | Rn(vn) | Rd(vd));
4386 }
4387 
4388 
ext(const VRegister & vd,const VRegister & vn,const VRegister & vm,int index)4389 void Assembler::ext(const VRegister& vd,
4390                     const VRegister& vn,
4391                     const VRegister& vm,
4392                     int index) {
4393   VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));
4394   VIXL_ASSERT(AreSameFormat(vd, vn, vm));
4395   VIXL_ASSERT(vd.Is8B() || vd.Is16B());
4396   VIXL_ASSERT((0 <= index) && (index < vd.GetLanes()));
4397   Emit(VFormat(vd) | NEON_EXT | Rm(vm) | ImmNEONExt(index) | Rn(vn) | Rd(vd));
4398 }
4399 
4400 
dup(const VRegister & vd,const VRegister & vn,int vn_index)4401 void Assembler::dup(const VRegister& vd, const VRegister& vn, int vn_index) {
4402   VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));
4403   Instr q, scalar;
4404 
4405   // We support vn arguments of the form vn.VxT() or vn.T(), where x is the
4406   // number of lanes, and T is b, h, s or d.
4407   int lane_size = vn.GetLaneSizeInBytes();
4408   NEONFormatField format;
4409   switch (lane_size) {
4410     case 1:
4411       format = NEON_16B;
4412       break;
4413     case 2:
4414       format = NEON_8H;
4415       break;
4416     case 4:
4417       format = NEON_4S;
4418       break;
4419     default:
4420       VIXL_ASSERT(lane_size == 8);
4421       format = NEON_2D;
4422       break;
4423   }
4424 
4425   if (vd.IsScalar()) {
4426     q = NEON_Q;
4427     scalar = NEONScalar;
4428   } else {
4429     VIXL_ASSERT(!vd.Is1D());
4430     q = vd.IsD() ? 0 : NEON_Q;
4431     scalar = 0;
4432   }
4433   Emit(q | scalar | NEON_DUP_ELEMENT | ImmNEON5(format, vn_index) | Rn(vn) |
4434        Rd(vd));
4435 }
4436 
4437 
mov(const VRegister & vd,const VRegister & vn,int vn_index)4438 void Assembler::mov(const VRegister& vd, const VRegister& vn, int vn_index) {
4439   VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));
4440   VIXL_ASSERT(vd.IsScalar());
4441   dup(vd, vn, vn_index);
4442 }
4443 
4444 
dup(const VRegister & vd,const Register & rn)4445 void Assembler::dup(const VRegister& vd, const Register& rn) {
4446   VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));
4447   VIXL_ASSERT(!vd.Is1D());
4448   VIXL_ASSERT(vd.Is2D() == rn.IsX());
4449   int q = vd.IsD() ? 0 : NEON_Q;
4450   Emit(q | NEON_DUP_GENERAL | ImmNEON5(VFormat(vd), 0) | Rn(rn) | Rd(vd));
4451 }
4452 
4453 
ins(const VRegister & vd,int vd_index,const VRegister & vn,int vn_index)4454 void Assembler::ins(const VRegister& vd,
4455                     int vd_index,
4456                     const VRegister& vn,
4457                     int vn_index) {
4458   VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));
4459   VIXL_ASSERT(AreSameFormat(vd, vn));
4460   // We support vd arguments of the form vd.VxT() or vd.T(), where x is the
4461   // number of lanes, and T is b, h, s or d.
4462   int lane_size = vd.GetLaneSizeInBytes();
4463   NEONFormatField format;
4464   switch (lane_size) {
4465     case 1:
4466       format = NEON_16B;
4467       break;
4468     case 2:
4469       format = NEON_8H;
4470       break;
4471     case 4:
4472       format = NEON_4S;
4473       break;
4474     default:
4475       VIXL_ASSERT(lane_size == 8);
4476       format = NEON_2D;
4477       break;
4478   }
4479 
4480   VIXL_ASSERT(
4481       (0 <= vd_index) &&
4482       (vd_index < LaneCountFromFormat(static_cast<VectorFormat>(format))));
4483   VIXL_ASSERT(
4484       (0 <= vn_index) &&
4485       (vn_index < LaneCountFromFormat(static_cast<VectorFormat>(format))));
4486   Emit(NEON_INS_ELEMENT | ImmNEON5(format, vd_index) |
4487        ImmNEON4(format, vn_index) | Rn(vn) | Rd(vd));
4488 }
4489 
4490 
mov(const VRegister & vd,int vd_index,const VRegister & vn,int vn_index)4491 void Assembler::mov(const VRegister& vd,
4492                     int vd_index,
4493                     const VRegister& vn,
4494                     int vn_index) {
4495   VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));
4496   ins(vd, vd_index, vn, vn_index);
4497 }
4498 
4499 
ins(const VRegister & vd,int vd_index,const Register & rn)4500 void Assembler::ins(const VRegister& vd, int vd_index, const Register& rn) {
4501   VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));
4502   // We support vd arguments of the form vd.VxT() or vd.T(), where x is the
4503   // number of lanes, and T is b, h, s or d.
4504   int lane_size = vd.GetLaneSizeInBytes();
4505   NEONFormatField format;
4506   switch (lane_size) {
4507     case 1:
4508       format = NEON_16B;
4509       VIXL_ASSERT(rn.IsW());
4510       break;
4511     case 2:
4512       format = NEON_8H;
4513       VIXL_ASSERT(rn.IsW());
4514       break;
4515     case 4:
4516       format = NEON_4S;
4517       VIXL_ASSERT(rn.IsW());
4518       break;
4519     default:
4520       VIXL_ASSERT(lane_size == 8);
4521       VIXL_ASSERT(rn.IsX());
4522       format = NEON_2D;
4523       break;
4524   }
4525 
4526   VIXL_ASSERT(
4527       (0 <= vd_index) &&
4528       (vd_index < LaneCountFromFormat(static_cast<VectorFormat>(format))));
4529   Emit(NEON_INS_GENERAL | ImmNEON5(format, vd_index) | Rn(rn) | Rd(vd));
4530 }
4531 
4532 
mov(const VRegister & vd,int vd_index,const Register & rn)4533 void Assembler::mov(const VRegister& vd, int vd_index, const Register& rn) {
4534   VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));
4535   ins(vd, vd_index, rn);
4536 }
4537 
4538 
umov(const Register & rd,const VRegister & vn,int vn_index)4539 void Assembler::umov(const Register& rd, const VRegister& vn, int vn_index) {
4540   VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));
4541   // We support vn arguments of the form vn.VxT() or vn.T(), where x is the
4542   // number of lanes, and T is b, h, s or d.
4543   int lane_size = vn.GetLaneSizeInBytes();
4544   NEONFormatField format;
4545   Instr q = 0;
4546   switch (lane_size) {
4547     case 1:
4548       format = NEON_16B;
4549       VIXL_ASSERT(rd.IsW());
4550       break;
4551     case 2:
4552       format = NEON_8H;
4553       VIXL_ASSERT(rd.IsW());
4554       break;
4555     case 4:
4556       format = NEON_4S;
4557       VIXL_ASSERT(rd.IsW());
4558       break;
4559     default:
4560       VIXL_ASSERT(lane_size == 8);
4561       VIXL_ASSERT(rd.IsX());
4562       format = NEON_2D;
4563       q = NEON_Q;
4564       break;
4565   }
4566 
4567   VIXL_ASSERT(
4568       (0 <= vn_index) &&
4569       (vn_index < LaneCountFromFormat(static_cast<VectorFormat>(format))));
4570   Emit(q | NEON_UMOV | ImmNEON5(format, vn_index) | Rn(vn) | Rd(rd));
4571 }
4572 
4573 
mov(const Register & rd,const VRegister & vn,int vn_index)4574 void Assembler::mov(const Register& rd, const VRegister& vn, int vn_index) {
4575   VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));
4576   VIXL_ASSERT(vn.GetSizeInBytes() >= 4);
4577   umov(rd, vn, vn_index);
4578 }
4579 
4580 
smov(const Register & rd,const VRegister & vn,int vn_index)4581 void Assembler::smov(const Register& rd, const VRegister& vn, int vn_index) {
4582   VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));
4583   // We support vn arguments of the form vn.VxT() or vn.T(), where x is the
4584   // number of lanes, and T is b, h, s.
4585   int lane_size = vn.GetLaneSizeInBytes();
4586   NEONFormatField format;
4587   Instr q = 0;
4588   VIXL_ASSERT(lane_size != 8);
4589   switch (lane_size) {
4590     case 1:
4591       format = NEON_16B;
4592       break;
4593     case 2:
4594       format = NEON_8H;
4595       break;
4596     default:
4597       VIXL_ASSERT(lane_size == 4);
4598       VIXL_ASSERT(rd.IsX());
4599       format = NEON_4S;
4600       break;
4601   }
4602   q = rd.IsW() ? 0 : NEON_Q;
4603   VIXL_ASSERT(
4604       (0 <= vn_index) &&
4605       (vn_index < LaneCountFromFormat(static_cast<VectorFormat>(format))));
4606   Emit(q | NEON_SMOV | ImmNEON5(format, vn_index) | Rn(vn) | Rd(rd));
4607 }
4608 
4609 
cls(const VRegister & vd,const VRegister & vn)4610 void Assembler::cls(const VRegister& vd, const VRegister& vn) {
4611   VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));
4612   VIXL_ASSERT(AreSameFormat(vd, vn));
4613   VIXL_ASSERT(!vd.Is1D() && !vd.Is2D());
4614   Emit(VFormat(vn) | NEON_CLS | Rn(vn) | Rd(vd));
4615 }
4616 
4617 
clz(const VRegister & vd,const VRegister & vn)4618 void Assembler::clz(const VRegister& vd, const VRegister& vn) {
4619   VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));
4620   VIXL_ASSERT(AreSameFormat(vd, vn));
4621   VIXL_ASSERT(!vd.Is1D() && !vd.Is2D());
4622   Emit(VFormat(vn) | NEON_CLZ | Rn(vn) | Rd(vd));
4623 }
4624 
4625 
cnt(const VRegister & vd,const VRegister & vn)4626 void Assembler::cnt(const VRegister& vd, const VRegister& vn) {
4627   VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));
4628   VIXL_ASSERT(AreSameFormat(vd, vn));
4629   VIXL_ASSERT(vd.Is8B() || vd.Is16B());
4630   Emit(VFormat(vn) | NEON_CNT | Rn(vn) | Rd(vd));
4631 }
4632 
4633 
rev16(const VRegister & vd,const VRegister & vn)4634 void Assembler::rev16(const VRegister& vd, const VRegister& vn) {
4635   VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));
4636   VIXL_ASSERT(AreSameFormat(vd, vn));
4637   VIXL_ASSERT(vd.Is8B() || vd.Is16B());
4638   Emit(VFormat(vn) | NEON_REV16 | Rn(vn) | Rd(vd));
4639 }
4640 
4641 
rev32(const VRegister & vd,const VRegister & vn)4642 void Assembler::rev32(const VRegister& vd, const VRegister& vn) {
4643   VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));
4644   VIXL_ASSERT(AreSameFormat(vd, vn));
4645   VIXL_ASSERT(vd.Is8B() || vd.Is16B() || vd.Is4H() || vd.Is8H());
4646   Emit(VFormat(vn) | NEON_REV32 | Rn(vn) | Rd(vd));
4647 }
4648 
4649 
rev64(const VRegister & vd,const VRegister & vn)4650 void Assembler::rev64(const VRegister& vd, const VRegister& vn) {
4651   VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));
4652   VIXL_ASSERT(AreSameFormat(vd, vn));
4653   VIXL_ASSERT(!vd.Is1D() && !vd.Is2D());
4654   Emit(VFormat(vn) | NEON_REV64 | Rn(vn) | Rd(vd));
4655 }
4656 
4657 
ursqrte(const VRegister & vd,const VRegister & vn)4658 void Assembler::ursqrte(const VRegister& vd, const VRegister& vn) {
4659   VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));
4660   VIXL_ASSERT(AreSameFormat(vd, vn));
4661   VIXL_ASSERT(vd.Is2S() || vd.Is4S());
4662   Emit(VFormat(vn) | NEON_URSQRTE | Rn(vn) | Rd(vd));
4663 }
4664 
4665 
urecpe(const VRegister & vd,const VRegister & vn)4666 void Assembler::urecpe(const VRegister& vd, const VRegister& vn) {
4667   VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));
4668   VIXL_ASSERT(AreSameFormat(vd, vn));
4669   VIXL_ASSERT(vd.Is2S() || vd.Is4S());
4670   Emit(VFormat(vn) | NEON_URECPE | Rn(vn) | Rd(vd));
4671 }
4672 
4673 
NEONAddlp(const VRegister & vd,const VRegister & vn,NEON2RegMiscOp op)4674 void Assembler::NEONAddlp(const VRegister& vd,
4675                           const VRegister& vn,
4676                           NEON2RegMiscOp op) {
4677   VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));
4678   VIXL_ASSERT((op == NEON_SADDLP) || (op == NEON_UADDLP) ||
4679               (op == NEON_SADALP) || (op == NEON_UADALP));
4680 
4681   VIXL_ASSERT((vn.Is8B() && vd.Is4H()) || (vn.Is4H() && vd.Is2S()) ||
4682               (vn.Is2S() && vd.Is1D()) || (vn.Is16B() && vd.Is8H()) ||
4683               (vn.Is8H() && vd.Is4S()) || (vn.Is4S() && vd.Is2D()));
4684   Emit(VFormat(vn) | op | Rn(vn) | Rd(vd));
4685 }
4686 
4687 
saddlp(const VRegister & vd,const VRegister & vn)4688 void Assembler::saddlp(const VRegister& vd, const VRegister& vn) {
4689   VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));
4690   NEONAddlp(vd, vn, NEON_SADDLP);
4691 }
4692 
4693 
uaddlp(const VRegister & vd,const VRegister & vn)4694 void Assembler::uaddlp(const VRegister& vd, const VRegister& vn) {
4695   VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));
4696   NEONAddlp(vd, vn, NEON_UADDLP);
4697 }
4698 
4699 
sadalp(const VRegister & vd,const VRegister & vn)4700 void Assembler::sadalp(const VRegister& vd, const VRegister& vn) {
4701   VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));
4702   NEONAddlp(vd, vn, NEON_SADALP);
4703 }
4704 
4705 
uadalp(const VRegister & vd,const VRegister & vn)4706 void Assembler::uadalp(const VRegister& vd, const VRegister& vn) {
4707   VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));
4708   NEONAddlp(vd, vn, NEON_UADALP);
4709 }
4710 
4711 
NEONAcrossLanesL(const VRegister & vd,const VRegister & vn,NEONAcrossLanesOp op)4712 void Assembler::NEONAcrossLanesL(const VRegister& vd,
4713                                  const VRegister& vn,
4714                                  NEONAcrossLanesOp op) {
4715   VIXL_ASSERT((vn.Is8B() && vd.Is1H()) || (vn.Is16B() && vd.Is1H()) ||
4716               (vn.Is4H() && vd.Is1S()) || (vn.Is8H() && vd.Is1S()) ||
4717               (vn.Is4S() && vd.Is1D()));
4718   Emit(VFormat(vn) | op | Rn(vn) | Rd(vd));
4719 }
4720 
4721 
saddlv(const VRegister & vd,const VRegister & vn)4722 void Assembler::saddlv(const VRegister& vd, const VRegister& vn) {
4723   VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));
4724   NEONAcrossLanesL(vd, vn, NEON_SADDLV);
4725 }
4726 
4727 
uaddlv(const VRegister & vd,const VRegister & vn)4728 void Assembler::uaddlv(const VRegister& vd, const VRegister& vn) {
4729   VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));
4730   NEONAcrossLanesL(vd, vn, NEON_UADDLV);
4731 }
4732 
4733 
NEONAcrossLanes(const VRegister & vd,const VRegister & vn,NEONAcrossLanesOp op,Instr op_half)4734 void Assembler::NEONAcrossLanes(const VRegister& vd,
4735                                 const VRegister& vn,
4736                                 NEONAcrossLanesOp op,
4737                                 Instr op_half) {
4738   VIXL_ASSERT((vn.Is8B() && vd.Is1B()) || (vn.Is16B() && vd.Is1B()) ||
4739               (vn.Is4H() && vd.Is1H()) || (vn.Is8H() && vd.Is1H()) ||
4740               (vn.Is4S() && vd.Is1S()));
4741   if ((op & NEONAcrossLanesFPFMask) == NEONAcrossLanesFPFixed) {
4742     if (vd.Is1H()) {
4743       VIXL_ASSERT(op_half != 0);
4744       Instr vop = op_half;
4745       if (vn.Is8H()) {
4746         vop |= NEON_Q;
4747       }
4748       Emit(vop | Rn(vn) | Rd(vd));
4749     } else {
4750       Emit(FPFormat(vn) | op | Rn(vn) | Rd(vd));
4751     }
4752   } else {
4753     Emit(VFormat(vn) | op | Rn(vn) | Rd(vd));
4754   }
4755 }
4756 
4757 // clang-format off
4758 #define NEON_ACROSSLANES_LIST(V)           \
4759   V(addv,    NEON_ADDV)                    \
4760   V(smaxv,   NEON_SMAXV)                   \
4761   V(sminv,   NEON_SMINV)                   \
4762   V(umaxv,   NEON_UMAXV)                   \
4763   V(uminv,   NEON_UMINV)
4764 // clang-format on
4765 
4766 #define DEFINE_ASM_FUNC(FN, OP)                                  \
4767   void Assembler::FN(const VRegister& vd, const VRegister& vn) { \
4768     VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));                     \
4769     NEONAcrossLanes(vd, vn, OP, 0);                              \
4770   }
4771 NEON_ACROSSLANES_LIST(DEFINE_ASM_FUNC)
4772 #undef DEFINE_ASM_FUNC
4773 
4774 
4775 // clang-format off
4776 #define NEON_ACROSSLANES_FP_LIST(V)   \
4777   V(fmaxv,   NEON_FMAXV,   NEON_FMAXV_H) \
4778   V(fminv,   NEON_FMINV,   NEON_FMINV_H) \
4779   V(fmaxnmv, NEON_FMAXNMV, NEON_FMAXNMV_H) \
4780   V(fminnmv, NEON_FMINNMV, NEON_FMINNMV_H) \
4781 // clang-format on
4782 
4783 #define DEFINE_ASM_FUNC(FN, OP, OP_H)                            \
4784   void Assembler::FN(const VRegister& vd, const VRegister& vn) { \
4785     VIXL_ASSERT(CPUHas(CPUFeatures::kFP, CPUFeatures::kNEON));   \
4786     if (vd.Is1H()) VIXL_ASSERT(CPUHas(CPUFeatures::kNEONHalf));  \
4787     VIXL_ASSERT(vd.Is1S() || vd.Is1H());                         \
4788     NEONAcrossLanes(vd, vn, OP, OP_H);                           \
4789   }
NEON_ACROSSLANES_FP_LIST(DEFINE_ASM_FUNC)4790 NEON_ACROSSLANES_FP_LIST(DEFINE_ASM_FUNC)
4791 #undef DEFINE_ASM_FUNC
4792 
4793 
4794 void Assembler::NEONPerm(const VRegister& vd,
4795                          const VRegister& vn,
4796                          const VRegister& vm,
4797                          NEONPermOp op) {
4798   VIXL_ASSERT(AreSameFormat(vd, vn, vm));
4799   VIXL_ASSERT(!vd.Is1D());
4800   Emit(VFormat(vd) | op | Rm(vm) | Rn(vn) | Rd(vd));
4801 }
4802 
4803 
trn1(const VRegister & vd,const VRegister & vn,const VRegister & vm)4804 void Assembler::trn1(const VRegister& vd,
4805                      const VRegister& vn,
4806                      const VRegister& vm) {
4807   VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));
4808   NEONPerm(vd, vn, vm, NEON_TRN1);
4809 }
4810 
4811 
trn2(const VRegister & vd,const VRegister & vn,const VRegister & vm)4812 void Assembler::trn2(const VRegister& vd,
4813                      const VRegister& vn,
4814                      const VRegister& vm) {
4815   VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));
4816   NEONPerm(vd, vn, vm, NEON_TRN2);
4817 }
4818 
4819 
uzp1(const VRegister & vd,const VRegister & vn,const VRegister & vm)4820 void Assembler::uzp1(const VRegister& vd,
4821                      const VRegister& vn,
4822                      const VRegister& vm) {
4823   VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));
4824   NEONPerm(vd, vn, vm, NEON_UZP1);
4825 }
4826 
4827 
uzp2(const VRegister & vd,const VRegister & vn,const VRegister & vm)4828 void Assembler::uzp2(const VRegister& vd,
4829                      const VRegister& vn,
4830                      const VRegister& vm) {
4831   VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));
4832   NEONPerm(vd, vn, vm, NEON_UZP2);
4833 }
4834 
4835 
zip1(const VRegister & vd,const VRegister & vn,const VRegister & vm)4836 void Assembler::zip1(const VRegister& vd,
4837                      const VRegister& vn,
4838                      const VRegister& vm) {
4839   VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));
4840   NEONPerm(vd, vn, vm, NEON_ZIP1);
4841 }
4842 
4843 
zip2(const VRegister & vd,const VRegister & vn,const VRegister & vm)4844 void Assembler::zip2(const VRegister& vd,
4845                      const VRegister& vn,
4846                      const VRegister& vm) {
4847   VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));
4848   NEONPerm(vd, vn, vm, NEON_ZIP2);
4849 }
4850 
4851 
NEONShiftImmediate(const VRegister & vd,const VRegister & vn,NEONShiftImmediateOp op,int immh_immb)4852 void Assembler::NEONShiftImmediate(const VRegister& vd,
4853                                    const VRegister& vn,
4854                                    NEONShiftImmediateOp op,
4855                                    int immh_immb) {
4856   VIXL_ASSERT(AreSameFormat(vd, vn));
4857   Instr q, scalar;
4858   if (vn.IsScalar()) {
4859     q = NEON_Q;
4860     scalar = NEONScalar;
4861   } else {
4862     q = vd.IsD() ? 0 : NEON_Q;
4863     scalar = 0;
4864   }
4865   Emit(q | op | scalar | immh_immb | Rn(vn) | Rd(vd));
4866 }
4867 
4868 
NEONShiftLeftImmediate(const VRegister & vd,const VRegister & vn,int shift,NEONShiftImmediateOp op)4869 void Assembler::NEONShiftLeftImmediate(const VRegister& vd,
4870                                        const VRegister& vn,
4871                                        int shift,
4872                                        NEONShiftImmediateOp op) {
4873   int laneSizeInBits = vn.GetLaneSizeInBits();
4874   VIXL_ASSERT((shift >= 0) && (shift < laneSizeInBits));
4875   NEONShiftImmediate(vd, vn, op, (laneSizeInBits + shift) << 16);
4876 }
4877 
4878 
NEONShiftRightImmediate(const VRegister & vd,const VRegister & vn,int shift,NEONShiftImmediateOp op)4879 void Assembler::NEONShiftRightImmediate(const VRegister& vd,
4880                                         const VRegister& vn,
4881                                         int shift,
4882                                         NEONShiftImmediateOp op) {
4883   int laneSizeInBits = vn.GetLaneSizeInBits();
4884   VIXL_ASSERT((shift >= 1) && (shift <= laneSizeInBits));
4885   NEONShiftImmediate(vd, vn, op, ((2 * laneSizeInBits) - shift) << 16);
4886 }
4887 
4888 
NEONShiftImmediateL(const VRegister & vd,const VRegister & vn,int shift,NEONShiftImmediateOp op)4889 void Assembler::NEONShiftImmediateL(const VRegister& vd,
4890                                     const VRegister& vn,
4891                                     int shift,
4892                                     NEONShiftImmediateOp op) {
4893   int laneSizeInBits = vn.GetLaneSizeInBits();
4894   VIXL_ASSERT((shift >= 0) && (shift < laneSizeInBits));
4895   int immh_immb = (laneSizeInBits + shift) << 16;
4896 
4897   VIXL_ASSERT((vn.Is8B() && vd.Is8H()) || (vn.Is4H() && vd.Is4S()) ||
4898               (vn.Is2S() && vd.Is2D()) || (vn.Is16B() && vd.Is8H()) ||
4899               (vn.Is8H() && vd.Is4S()) || (vn.Is4S() && vd.Is2D()));
4900   Instr q;
4901   q = vn.IsD() ? 0 : NEON_Q;
4902   Emit(q | op | immh_immb | Rn(vn) | Rd(vd));
4903 }
4904 
4905 
NEONShiftImmediateN(const VRegister & vd,const VRegister & vn,int shift,NEONShiftImmediateOp op)4906 void Assembler::NEONShiftImmediateN(const VRegister& vd,
4907                                     const VRegister& vn,
4908                                     int shift,
4909                                     NEONShiftImmediateOp op) {
4910   Instr q, scalar;
4911   int laneSizeInBits = vd.GetLaneSizeInBits();
4912   VIXL_ASSERT((shift >= 1) && (shift <= laneSizeInBits));
4913   int immh_immb = (2 * laneSizeInBits - shift) << 16;
4914 
4915   if (vn.IsScalar()) {
4916     VIXL_ASSERT((vd.Is1B() && vn.Is1H()) || (vd.Is1H() && vn.Is1S()) ||
4917                 (vd.Is1S() && vn.Is1D()));
4918     q = NEON_Q;
4919     scalar = NEONScalar;
4920   } else {
4921     VIXL_ASSERT((vd.Is8B() && vn.Is8H()) || (vd.Is4H() && vn.Is4S()) ||
4922                 (vd.Is2S() && vn.Is2D()) || (vd.Is16B() && vn.Is8H()) ||
4923                 (vd.Is8H() && vn.Is4S()) || (vd.Is4S() && vn.Is2D()));
4924     scalar = 0;
4925     q = vd.IsD() ? 0 : NEON_Q;
4926   }
4927   Emit(q | op | scalar | immh_immb | Rn(vn) | Rd(vd));
4928 }
4929 
4930 
shl(const VRegister & vd,const VRegister & vn,int shift)4931 void Assembler::shl(const VRegister& vd, const VRegister& vn, int shift) {
4932   VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));
4933   VIXL_ASSERT(vd.IsVector() || vd.Is1D());
4934   NEONShiftLeftImmediate(vd, vn, shift, NEON_SHL);
4935 }
4936 
4937 
sli(const VRegister & vd,const VRegister & vn,int shift)4938 void Assembler::sli(const VRegister& vd, const VRegister& vn, int shift) {
4939   VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));
4940   VIXL_ASSERT(vd.IsVector() || vd.Is1D());
4941   NEONShiftLeftImmediate(vd, vn, shift, NEON_SLI);
4942 }
4943 
4944 
sqshl(const VRegister & vd,const VRegister & vn,int shift)4945 void Assembler::sqshl(const VRegister& vd, const VRegister& vn, int shift) {
4946   VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));
4947   NEONShiftLeftImmediate(vd, vn, shift, NEON_SQSHL_imm);
4948 }
4949 
4950 
sqshlu(const VRegister & vd,const VRegister & vn,int shift)4951 void Assembler::sqshlu(const VRegister& vd, const VRegister& vn, int shift) {
4952   VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));
4953   NEONShiftLeftImmediate(vd, vn, shift, NEON_SQSHLU);
4954 }
4955 
4956 
uqshl(const VRegister & vd,const VRegister & vn,int shift)4957 void Assembler::uqshl(const VRegister& vd, const VRegister& vn, int shift) {
4958   VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));
4959   NEONShiftLeftImmediate(vd, vn, shift, NEON_UQSHL_imm);
4960 }
4961 
4962 
sshll(const VRegister & vd,const VRegister & vn,int shift)4963 void Assembler::sshll(const VRegister& vd, const VRegister& vn, int shift) {
4964   VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));
4965   VIXL_ASSERT(vn.IsD());
4966   NEONShiftImmediateL(vd, vn, shift, NEON_SSHLL);
4967 }
4968 
4969 
sshll2(const VRegister & vd,const VRegister & vn,int shift)4970 void Assembler::sshll2(const VRegister& vd, const VRegister& vn, int shift) {
4971   VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));
4972   VIXL_ASSERT(vn.IsQ());
4973   NEONShiftImmediateL(vd, vn, shift, NEON_SSHLL);
4974 }
4975 
4976 
sxtl(const VRegister & vd,const VRegister & vn)4977 void Assembler::sxtl(const VRegister& vd, const VRegister& vn) {
4978   VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));
4979   sshll(vd, vn, 0);
4980 }
4981 
4982 
sxtl2(const VRegister & vd,const VRegister & vn)4983 void Assembler::sxtl2(const VRegister& vd, const VRegister& vn) {
4984   VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));
4985   sshll2(vd, vn, 0);
4986 }
4987 
4988 
ushll(const VRegister & vd,const VRegister & vn,int shift)4989 void Assembler::ushll(const VRegister& vd, const VRegister& vn, int shift) {
4990   VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));
4991   VIXL_ASSERT(vn.IsD());
4992   NEONShiftImmediateL(vd, vn, shift, NEON_USHLL);
4993 }
4994 
4995 
ushll2(const VRegister & vd,const VRegister & vn,int shift)4996 void Assembler::ushll2(const VRegister& vd, const VRegister& vn, int shift) {
4997   VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));
4998   VIXL_ASSERT(vn.IsQ());
4999   NEONShiftImmediateL(vd, vn, shift, NEON_USHLL);
5000 }
5001 
5002 
uxtl(const VRegister & vd,const VRegister & vn)5003 void Assembler::uxtl(const VRegister& vd, const VRegister& vn) {
5004   VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));
5005   ushll(vd, vn, 0);
5006 }
5007 
5008 
uxtl2(const VRegister & vd,const VRegister & vn)5009 void Assembler::uxtl2(const VRegister& vd, const VRegister& vn) {
5010   VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));
5011   ushll2(vd, vn, 0);
5012 }
5013 
5014 
sri(const VRegister & vd,const VRegister & vn,int shift)5015 void Assembler::sri(const VRegister& vd, const VRegister& vn, int shift) {
5016   VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));
5017   VIXL_ASSERT(vd.IsVector() || vd.Is1D());
5018   NEONShiftRightImmediate(vd, vn, shift, NEON_SRI);
5019 }
5020 
5021 
sshr(const VRegister & vd,const VRegister & vn,int shift)5022 void Assembler::sshr(const VRegister& vd, const VRegister& vn, int shift) {
5023   VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));
5024   VIXL_ASSERT(vd.IsVector() || vd.Is1D());
5025   NEONShiftRightImmediate(vd, vn, shift, NEON_SSHR);
5026 }
5027 
5028 
ushr(const VRegister & vd,const VRegister & vn,int shift)5029 void Assembler::ushr(const VRegister& vd, const VRegister& vn, int shift) {
5030   VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));
5031   VIXL_ASSERT(vd.IsVector() || vd.Is1D());
5032   NEONShiftRightImmediate(vd, vn, shift, NEON_USHR);
5033 }
5034 
5035 
srshr(const VRegister & vd,const VRegister & vn,int shift)5036 void Assembler::srshr(const VRegister& vd, const VRegister& vn, int shift) {
5037   VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));
5038   VIXL_ASSERT(vd.IsVector() || vd.Is1D());
5039   NEONShiftRightImmediate(vd, vn, shift, NEON_SRSHR);
5040 }
5041 
5042 
urshr(const VRegister & vd,const VRegister & vn,int shift)5043 void Assembler::urshr(const VRegister& vd, const VRegister& vn, int shift) {
5044   VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));
5045   VIXL_ASSERT(vd.IsVector() || vd.Is1D());
5046   NEONShiftRightImmediate(vd, vn, shift, NEON_URSHR);
5047 }
5048 
5049 
ssra(const VRegister & vd,const VRegister & vn,int shift)5050 void Assembler::ssra(const VRegister& vd, const VRegister& vn, int shift) {
5051   VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));
5052   VIXL_ASSERT(vd.IsVector() || vd.Is1D());
5053   NEONShiftRightImmediate(vd, vn, shift, NEON_SSRA);
5054 }
5055 
5056 
usra(const VRegister & vd,const VRegister & vn,int shift)5057 void Assembler::usra(const VRegister& vd, const VRegister& vn, int shift) {
5058   VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));
5059   VIXL_ASSERT(vd.IsVector() || vd.Is1D());
5060   NEONShiftRightImmediate(vd, vn, shift, NEON_USRA);
5061 }
5062 
5063 
srsra(const VRegister & vd,const VRegister & vn,int shift)5064 void Assembler::srsra(const VRegister& vd, const VRegister& vn, int shift) {
5065   VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));
5066   VIXL_ASSERT(vd.IsVector() || vd.Is1D());
5067   NEONShiftRightImmediate(vd, vn, shift, NEON_SRSRA);
5068 }
5069 
5070 
ursra(const VRegister & vd,const VRegister & vn,int shift)5071 void Assembler::ursra(const VRegister& vd, const VRegister& vn, int shift) {
5072   VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));
5073   VIXL_ASSERT(vd.IsVector() || vd.Is1D());
5074   NEONShiftRightImmediate(vd, vn, shift, NEON_URSRA);
5075 }
5076 
5077 
shrn(const VRegister & vd,const VRegister & vn,int shift)5078 void Assembler::shrn(const VRegister& vd, const VRegister& vn, int shift) {
5079   VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));
5080   VIXL_ASSERT(vn.IsVector() && vd.IsD());
5081   NEONShiftImmediateN(vd, vn, shift, NEON_SHRN);
5082 }
5083 
5084 
shrn2(const VRegister & vd,const VRegister & vn,int shift)5085 void Assembler::shrn2(const VRegister& vd, const VRegister& vn, int shift) {
5086   VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));
5087   VIXL_ASSERT(vn.IsVector() && vd.IsQ());
5088   NEONShiftImmediateN(vd, vn, shift, NEON_SHRN);
5089 }
5090 
5091 
rshrn(const VRegister & vd,const VRegister & vn,int shift)5092 void Assembler::rshrn(const VRegister& vd, const VRegister& vn, int shift) {
5093   VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));
5094   VIXL_ASSERT(vn.IsVector() && vd.IsD());
5095   NEONShiftImmediateN(vd, vn, shift, NEON_RSHRN);
5096 }
5097 
5098 
rshrn2(const VRegister & vd,const VRegister & vn,int shift)5099 void Assembler::rshrn2(const VRegister& vd, const VRegister& vn, int shift) {
5100   VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));
5101   VIXL_ASSERT(vn.IsVector() && vd.IsQ());
5102   NEONShiftImmediateN(vd, vn, shift, NEON_RSHRN);
5103 }
5104 
5105 
sqshrn(const VRegister & vd,const VRegister & vn,int shift)5106 void Assembler::sqshrn(const VRegister& vd, const VRegister& vn, int shift) {
5107   VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));
5108   VIXL_ASSERT(vd.IsD() || (vn.IsScalar() && vd.IsScalar()));
5109   NEONShiftImmediateN(vd, vn, shift, NEON_SQSHRN);
5110 }
5111 
5112 
sqshrn2(const VRegister & vd,const VRegister & vn,int shift)5113 void Assembler::sqshrn2(const VRegister& vd, const VRegister& vn, int shift) {
5114   VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));
5115   VIXL_ASSERT(vn.IsVector() && vd.IsQ());
5116   NEONShiftImmediateN(vd, vn, shift, NEON_SQSHRN);
5117 }
5118 
5119 
sqrshrn(const VRegister & vd,const VRegister & vn,int shift)5120 void Assembler::sqrshrn(const VRegister& vd, const VRegister& vn, int shift) {
5121   VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));
5122   VIXL_ASSERT(vd.IsD() || (vn.IsScalar() && vd.IsScalar()));
5123   NEONShiftImmediateN(vd, vn, shift, NEON_SQRSHRN);
5124 }
5125 
5126 
sqrshrn2(const VRegister & vd,const VRegister & vn,int shift)5127 void Assembler::sqrshrn2(const VRegister& vd, const VRegister& vn, int shift) {
5128   VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));
5129   VIXL_ASSERT(vn.IsVector() && vd.IsQ());
5130   NEONShiftImmediateN(vd, vn, shift, NEON_SQRSHRN);
5131 }
5132 
5133 
sqshrun(const VRegister & vd,const VRegister & vn,int shift)5134 void Assembler::sqshrun(const VRegister& vd, const VRegister& vn, int shift) {
5135   VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));
5136   VIXL_ASSERT(vd.IsD() || (vn.IsScalar() && vd.IsScalar()));
5137   NEONShiftImmediateN(vd, vn, shift, NEON_SQSHRUN);
5138 }
5139 
5140 
sqshrun2(const VRegister & vd,const VRegister & vn,int shift)5141 void Assembler::sqshrun2(const VRegister& vd, const VRegister& vn, int shift) {
5142   VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));
5143   VIXL_ASSERT(vn.IsVector() && vd.IsQ());
5144   NEONShiftImmediateN(vd, vn, shift, NEON_SQSHRUN);
5145 }
5146 
5147 
sqrshrun(const VRegister & vd,const VRegister & vn,int shift)5148 void Assembler::sqrshrun(const VRegister& vd, const VRegister& vn, int shift) {
5149   VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));
5150   VIXL_ASSERT(vd.IsD() || (vn.IsScalar() && vd.IsScalar()));
5151   NEONShiftImmediateN(vd, vn, shift, NEON_SQRSHRUN);
5152 }
5153 
5154 
sqrshrun2(const VRegister & vd,const VRegister & vn,int shift)5155 void Assembler::sqrshrun2(const VRegister& vd, const VRegister& vn, int shift) {
5156   VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));
5157   VIXL_ASSERT(vn.IsVector() && vd.IsQ());
5158   NEONShiftImmediateN(vd, vn, shift, NEON_SQRSHRUN);
5159 }
5160 
5161 
uqshrn(const VRegister & vd,const VRegister & vn,int shift)5162 void Assembler::uqshrn(const VRegister& vd, const VRegister& vn, int shift) {
5163   VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));
5164   VIXL_ASSERT(vd.IsD() || (vn.IsScalar() && vd.IsScalar()));
5165   NEONShiftImmediateN(vd, vn, shift, NEON_UQSHRN);
5166 }
5167 
5168 
uqshrn2(const VRegister & vd,const VRegister & vn,int shift)5169 void Assembler::uqshrn2(const VRegister& vd, const VRegister& vn, int shift) {
5170   VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));
5171   VIXL_ASSERT(vn.IsVector() && vd.IsQ());
5172   NEONShiftImmediateN(vd, vn, shift, NEON_UQSHRN);
5173 }
5174 
5175 
uqrshrn(const VRegister & vd,const VRegister & vn,int shift)5176 void Assembler::uqrshrn(const VRegister& vd, const VRegister& vn, int shift) {
5177   VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));
5178   VIXL_ASSERT(vd.IsD() || (vn.IsScalar() && vd.IsScalar()));
5179   NEONShiftImmediateN(vd, vn, shift, NEON_UQRSHRN);
5180 }
5181 
5182 
uqrshrn2(const VRegister & vd,const VRegister & vn,int shift)5183 void Assembler::uqrshrn2(const VRegister& vd, const VRegister& vn, int shift) {
5184   VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));
5185   VIXL_ASSERT(vn.IsVector() && vd.IsQ());
5186   NEONShiftImmediateN(vd, vn, shift, NEON_UQRSHRN);
5187 }
5188 
5189 
5190 // Note:
5191 // For all ToImm instructions below, a difference in case
5192 // for the same letter indicates a negated bit.
5193 // If b is 1, then B is 0.
FP16ToImm8(Float16 imm)5194 uint32_t Assembler::FP16ToImm8(Float16 imm) {
5195   VIXL_ASSERT(IsImmFP16(imm));
5196   // Half: aBbb.cdef.gh00.0000 (16 bits)
5197   uint16_t bits = Float16ToRawbits(imm);
5198   // bit7: a000.0000
5199   uint16_t bit7 = ((bits >> 15) & 0x1) << 7;
5200   // bit6: 0b00.0000
5201   uint16_t bit6 = ((bits >> 13) & 0x1) << 6;
5202   // bit5_to_0: 00cd.efgh
5203   uint16_t bit5_to_0 = (bits >> 6) & 0x3f;
5204   uint32_t result = static_cast<uint32_t>(bit7 | bit6 | bit5_to_0);
5205   return result;
5206 }
5207 
5208 
ImmFP16(Float16 imm)5209 Instr Assembler::ImmFP16(Float16 imm) {
5210   return FP16ToImm8(imm) << ImmFP_offset;
5211 }
5212 
5213 
FP32ToImm8(float imm)5214 uint32_t Assembler::FP32ToImm8(float imm) {
5215   VIXL_ASSERT(IsImmFP32(imm));
5216   // bits: aBbb.bbbc.defg.h000.0000.0000.0000.0000
5217   uint32_t bits = FloatToRawbits(imm);
5218   // bit7: a000.0000
5219   uint32_t bit7 = ((bits >> 31) & 0x1) << 7;
5220   // bit6: 0b00.0000
5221   uint32_t bit6 = ((bits >> 29) & 0x1) << 6;
5222   // bit5_to_0: 00cd.efgh
5223   uint32_t bit5_to_0 = (bits >> 19) & 0x3f;
5224 
5225   return bit7 | bit6 | bit5_to_0;
5226 }
5227 
5228 
ImmFP32(float imm)5229 Instr Assembler::ImmFP32(float imm) { return FP32ToImm8(imm) << ImmFP_offset; }
5230 
5231 
FP64ToImm8(double imm)5232 uint32_t Assembler::FP64ToImm8(double imm) {
5233   VIXL_ASSERT(IsImmFP64(imm));
5234   // bits: aBbb.bbbb.bbcd.efgh.0000.0000.0000.0000
5235   //       0000.0000.0000.0000.0000.0000.0000.0000
5236   uint64_t bits = DoubleToRawbits(imm);
5237   // bit7: a000.0000
5238   uint64_t bit7 = ((bits >> 63) & 0x1) << 7;
5239   // bit6: 0b00.0000
5240   uint64_t bit6 = ((bits >> 61) & 0x1) << 6;
5241   // bit5_to_0: 00cd.efgh
5242   uint64_t bit5_to_0 = (bits >> 48) & 0x3f;
5243 
5244   return static_cast<uint32_t>(bit7 | bit6 | bit5_to_0);
5245 }
5246 
5247 
ImmFP64(double imm)5248 Instr Assembler::ImmFP64(double imm) { return FP64ToImm8(imm) << ImmFP_offset; }
5249 
5250 
5251 // Code generation helpers.
MoveWide(const Register & rd,uint64_t imm,int shift,MoveWideImmediateOp mov_op)5252 void Assembler::MoveWide(const Register& rd,
5253                          uint64_t imm,
5254                          int shift,
5255                          MoveWideImmediateOp mov_op) {
5256   // Ignore the top 32 bits of an immediate if we're moving to a W register.
5257   if (rd.Is32Bits()) {
5258     // Check that the top 32 bits are zero (a positive 32-bit number) or top
5259     // 33 bits are one (a negative 32-bit number, sign extended to 64 bits).
5260     VIXL_ASSERT(((imm >> kWRegSize) == 0) ||
5261                 ((imm >> (kWRegSize - 1)) == 0x1ffffffff));
5262     imm &= kWRegMask;
5263   }
5264 
5265   if (shift >= 0) {
5266     // Explicit shift specified.
5267     VIXL_ASSERT((shift == 0) || (shift == 16) || (shift == 32) ||
5268                 (shift == 48));
5269     VIXL_ASSERT(rd.Is64Bits() || (shift == 0) || (shift == 16));
5270     shift /= 16;
5271   } else {
5272     // Calculate a new immediate and shift combination to encode the immediate
5273     // argument.
5274     shift = 0;
5275     if ((imm & 0xffffffffffff0000) == 0) {
5276       // Nothing to do.
5277     } else if ((imm & 0xffffffff0000ffff) == 0) {
5278       imm >>= 16;
5279       shift = 1;
5280     } else if ((imm & 0xffff0000ffffffff) == 0) {
5281       VIXL_ASSERT(rd.Is64Bits());
5282       imm >>= 32;
5283       shift = 2;
5284     } else if ((imm & 0x0000ffffffffffff) == 0) {
5285       VIXL_ASSERT(rd.Is64Bits());
5286       imm >>= 48;
5287       shift = 3;
5288     }
5289   }
5290 
5291   VIXL_ASSERT(IsUint16(imm));
5292 
5293   Emit(SF(rd) | MoveWideImmediateFixed | mov_op | Rd(rd) | ImmMoveWide(imm) |
5294        ShiftMoveWide(shift));
5295 }
5296 
5297 
AddSub(const Register & rd,const Register & rn,const Operand & operand,FlagsUpdate S,AddSubOp op)5298 void Assembler::AddSub(const Register& rd,
5299                        const Register& rn,
5300                        const Operand& operand,
5301                        FlagsUpdate S,
5302                        AddSubOp op) {
5303   VIXL_ASSERT(rd.GetSizeInBits() == rn.GetSizeInBits());
5304   if (operand.IsImmediate()) {
5305     int64_t immediate = operand.GetImmediate();
5306     VIXL_ASSERT(IsImmAddSub(immediate));
5307     Instr dest_reg = (S == SetFlags) ? Rd(rd) : RdSP(rd);
5308     Emit(SF(rd) | AddSubImmediateFixed | op | Flags(S) |
5309          ImmAddSub(static_cast<int>(immediate)) | dest_reg | RnSP(rn));
5310   } else if (operand.IsShiftedRegister()) {
5311     VIXL_ASSERT(operand.GetRegister().GetSizeInBits() == rd.GetSizeInBits());
5312     VIXL_ASSERT(operand.GetShift() != ROR);
5313 
5314     // For instructions of the form:
5315     //   add/sub   wsp, <Wn>, <Wm> [, LSL #0-3 ]
5316     //   add/sub   <Wd>, wsp, <Wm> [, LSL #0-3 ]
5317     //   add/sub   wsp, wsp, <Wm> [, LSL #0-3 ]
5318     //   adds/subs <Wd>, wsp, <Wm> [, LSL #0-3 ]
5319     // or their 64-bit register equivalents, convert the operand from shifted to
5320     // extended register mode, and emit an add/sub extended instruction.
5321     if (rn.IsSP() || rd.IsSP()) {
5322       VIXL_ASSERT(!(rd.IsSP() && (S == SetFlags)));
5323       DataProcExtendedRegister(rd,
5324                                rn,
5325                                operand.ToExtendedRegister(),
5326                                S,
5327                                AddSubExtendedFixed | op);
5328     } else {
5329       DataProcShiftedRegister(rd, rn, operand, S, AddSubShiftedFixed | op);
5330     }
5331   } else {
5332     VIXL_ASSERT(operand.IsExtendedRegister());
5333     DataProcExtendedRegister(rd, rn, operand, S, AddSubExtendedFixed | op);
5334   }
5335 }
5336 
5337 
AddSubWithCarry(const Register & rd,const Register & rn,const Operand & operand,FlagsUpdate S,AddSubWithCarryOp op)5338 void Assembler::AddSubWithCarry(const Register& rd,
5339                                 const Register& rn,
5340                                 const Operand& operand,
5341                                 FlagsUpdate S,
5342                                 AddSubWithCarryOp op) {
5343   VIXL_ASSERT(rd.GetSizeInBits() == rn.GetSizeInBits());
5344   VIXL_ASSERT(rd.GetSizeInBits() == operand.GetRegister().GetSizeInBits());
5345   VIXL_ASSERT(operand.IsShiftedRegister() && (operand.GetShiftAmount() == 0));
5346   Emit(SF(rd) | op | Flags(S) | Rm(operand.GetRegister()) | Rn(rn) | Rd(rd));
5347 }
5348 
5349 
hlt(int code)5350 void Assembler::hlt(int code) {
5351   VIXL_ASSERT(IsUint16(code));
5352   Emit(HLT | ImmException(code));
5353 }
5354 
5355 
brk(int code)5356 void Assembler::brk(int code) {
5357   VIXL_ASSERT(IsUint16(code));
5358   Emit(BRK | ImmException(code));
5359 }
5360 
5361 
svc(int code)5362 void Assembler::svc(int code) { Emit(SVC | ImmException(code)); }
5363 
udf(int code)5364 void Assembler::udf(int code) { Emit(UDF | ImmUdf(code)); }
5365 
5366 
5367 // TODO(all): The third parameter should be passed by reference but gcc 4.8.2
5368 // reports a bogus uninitialised warning then.
Logical(const Register & rd,const Register & rn,const Operand operand,LogicalOp op)5369 void Assembler::Logical(const Register& rd,
5370                         const Register& rn,
5371                         const Operand operand,
5372                         LogicalOp op) {
5373   VIXL_ASSERT(rd.GetSizeInBits() == rn.GetSizeInBits());
5374   if (operand.IsImmediate()) {
5375     int64_t immediate = operand.GetImmediate();
5376     unsigned reg_size = rd.GetSizeInBits();
5377 
5378     VIXL_ASSERT(immediate != 0);
5379     VIXL_ASSERT(immediate != -1);
5380     VIXL_ASSERT(rd.Is64Bits() || IsUint32(immediate));
5381 
5382     // If the operation is NOT, invert the operation and immediate.
5383     if ((op & NOT) == NOT) {
5384       op = static_cast<LogicalOp>(op & ~NOT);
5385       immediate = rd.Is64Bits() ? ~immediate : (~immediate & kWRegMask);
5386     }
5387 
5388     unsigned n, imm_s, imm_r;
5389     if (IsImmLogical(immediate, reg_size, &n, &imm_s, &imm_r)) {
5390       // Immediate can be encoded in the instruction.
5391       LogicalImmediate(rd, rn, n, imm_s, imm_r, op);
5392     } else {
5393       // This case is handled in the macro assembler.
5394       VIXL_UNREACHABLE();
5395     }
5396   } else {
5397     VIXL_ASSERT(operand.IsShiftedRegister());
5398     VIXL_ASSERT(operand.GetRegister().GetSizeInBits() == rd.GetSizeInBits());
5399     Instr dp_op = static_cast<Instr>(op | LogicalShiftedFixed);
5400     DataProcShiftedRegister(rd, rn, operand, LeaveFlags, dp_op);
5401   }
5402 }
5403 
5404 
LogicalImmediate(const Register & rd,const Register & rn,unsigned n,unsigned imm_s,unsigned imm_r,LogicalOp op)5405 void Assembler::LogicalImmediate(const Register& rd,
5406                                  const Register& rn,
5407                                  unsigned n,
5408                                  unsigned imm_s,
5409                                  unsigned imm_r,
5410                                  LogicalOp op) {
5411   unsigned reg_size = rd.GetSizeInBits();
5412   Instr dest_reg = (op == ANDS) ? Rd(rd) : RdSP(rd);
5413   Emit(SF(rd) | LogicalImmediateFixed | op | BitN(n, reg_size) |
5414        ImmSetBits(imm_s, reg_size) | ImmRotate(imm_r, reg_size) | dest_reg |
5415        Rn(rn));
5416 }
5417 
5418 
ConditionalCompare(const Register & rn,const Operand & operand,StatusFlags nzcv,Condition cond,ConditionalCompareOp op)5419 void Assembler::ConditionalCompare(const Register& rn,
5420                                    const Operand& operand,
5421                                    StatusFlags nzcv,
5422                                    Condition cond,
5423                                    ConditionalCompareOp op) {
5424   Instr ccmpop;
5425   if (operand.IsImmediate()) {
5426     int64_t immediate = operand.GetImmediate();
5427     VIXL_ASSERT(IsImmConditionalCompare(immediate));
5428     ccmpop = ConditionalCompareImmediateFixed | op |
5429              ImmCondCmp(static_cast<unsigned>(immediate));
5430   } else {
5431     VIXL_ASSERT(operand.IsShiftedRegister() && (operand.GetShiftAmount() == 0));
5432     ccmpop = ConditionalCompareRegisterFixed | op | Rm(operand.GetRegister());
5433   }
5434   Emit(SF(rn) | ccmpop | Cond(cond) | Rn(rn) | Nzcv(nzcv));
5435 }
5436 
5437 
DataProcessing1Source(const Register & rd,const Register & rn,DataProcessing1SourceOp op)5438 void Assembler::DataProcessing1Source(const Register& rd,
5439                                       const Register& rn,
5440                                       DataProcessing1SourceOp op) {
5441   VIXL_ASSERT(rd.GetSizeInBits() == rn.GetSizeInBits());
5442   Emit(SF(rn) | op | Rn(rn) | Rd(rd));
5443 }
5444 
5445 
FPDataProcessing1Source(const VRegister & vd,const VRegister & vn,FPDataProcessing1SourceOp op)5446 void Assembler::FPDataProcessing1Source(const VRegister& vd,
5447                                         const VRegister& vn,
5448                                         FPDataProcessing1SourceOp op) {
5449   VIXL_ASSERT(vd.Is1H() || vd.Is1S() || vd.Is1D());
5450   Emit(FPType(vn) | op | Rn(vn) | Rd(vd));
5451 }
5452 
5453 
FPDataProcessing3Source(const VRegister & vd,const VRegister & vn,const VRegister & vm,const VRegister & va,FPDataProcessing3SourceOp op)5454 void Assembler::FPDataProcessing3Source(const VRegister& vd,
5455                                         const VRegister& vn,
5456                                         const VRegister& vm,
5457                                         const VRegister& va,
5458                                         FPDataProcessing3SourceOp op) {
5459   VIXL_ASSERT(vd.Is1H() || vd.Is1S() || vd.Is1D());
5460   VIXL_ASSERT(AreSameSizeAndType(vd, vn, vm, va));
5461   Emit(FPType(vd) | op | Rm(vm) | Rn(vn) | Rd(vd) | Ra(va));
5462 }
5463 
5464 
NEONModifiedImmShiftLsl(const VRegister & vd,const int imm8,const int left_shift,NEONModifiedImmediateOp op)5465 void Assembler::NEONModifiedImmShiftLsl(const VRegister& vd,
5466                                         const int imm8,
5467                                         const int left_shift,
5468                                         NEONModifiedImmediateOp op) {
5469   VIXL_ASSERT(vd.Is8B() || vd.Is16B() || vd.Is4H() || vd.Is8H() || vd.Is2S() ||
5470               vd.Is4S());
5471   VIXL_ASSERT((left_shift == 0) || (left_shift == 8) || (left_shift == 16) ||
5472               (left_shift == 24));
5473   VIXL_ASSERT(IsUint8(imm8));
5474 
5475   int cmode_1, cmode_2, cmode_3;
5476   if (vd.Is8B() || vd.Is16B()) {
5477     VIXL_ASSERT(op == NEONModifiedImmediate_MOVI);
5478     cmode_1 = 1;
5479     cmode_2 = 1;
5480     cmode_3 = 1;
5481   } else {
5482     cmode_1 = (left_shift >> 3) & 1;
5483     cmode_2 = left_shift >> 4;
5484     cmode_3 = 0;
5485     if (vd.Is4H() || vd.Is8H()) {
5486       VIXL_ASSERT((left_shift == 0) || (left_shift == 8));
5487       cmode_3 = 1;
5488     }
5489   }
5490   int cmode = (cmode_3 << 3) | (cmode_2 << 2) | (cmode_1 << 1);
5491 
5492   int q = vd.IsQ() ? NEON_Q : 0;
5493 
5494   Emit(q | op | ImmNEONabcdefgh(imm8) | NEONCmode(cmode) | Rd(vd));
5495 }
5496 
5497 
NEONModifiedImmShiftMsl(const VRegister & vd,const int imm8,const int shift_amount,NEONModifiedImmediateOp op)5498 void Assembler::NEONModifiedImmShiftMsl(const VRegister& vd,
5499                                         const int imm8,
5500                                         const int shift_amount,
5501                                         NEONModifiedImmediateOp op) {
5502   VIXL_ASSERT(vd.Is2S() || vd.Is4S());
5503   VIXL_ASSERT((shift_amount == 8) || (shift_amount == 16));
5504   VIXL_ASSERT(IsUint8(imm8));
5505 
5506   int cmode_0 = (shift_amount >> 4) & 1;
5507   int cmode = 0xc | cmode_0;
5508 
5509   int q = vd.IsQ() ? NEON_Q : 0;
5510 
5511   Emit(q | op | ImmNEONabcdefgh(imm8) | NEONCmode(cmode) | Rd(vd));
5512 }
5513 
5514 
EmitShift(const Register & rd,const Register & rn,Shift shift,unsigned shift_amount)5515 void Assembler::EmitShift(const Register& rd,
5516                           const Register& rn,
5517                           Shift shift,
5518                           unsigned shift_amount) {
5519   switch (shift) {
5520     case LSL:
5521       lsl(rd, rn, shift_amount);
5522       break;
5523     case LSR:
5524       lsr(rd, rn, shift_amount);
5525       break;
5526     case ASR:
5527       asr(rd, rn, shift_amount);
5528       break;
5529     case ROR:
5530       ror(rd, rn, shift_amount);
5531       break;
5532     default:
5533       VIXL_UNREACHABLE();
5534   }
5535 }
5536 
5537 
EmitExtendShift(const Register & rd,const Register & rn,Extend extend,unsigned left_shift)5538 void Assembler::EmitExtendShift(const Register& rd,
5539                                 const Register& rn,
5540                                 Extend extend,
5541                                 unsigned left_shift) {
5542   VIXL_ASSERT(rd.GetSizeInBits() >= rn.GetSizeInBits());
5543   unsigned reg_size = rd.GetSizeInBits();
5544   // Use the correct size of register.
5545   Register rn_ = Register(rn.GetCode(), rd.GetSizeInBits());
5546   // Bits extracted are high_bit:0.
5547   unsigned high_bit = (8 << (extend & 0x3)) - 1;
5548   // Number of bits left in the result that are not introduced by the shift.
5549   unsigned non_shift_bits = (reg_size - left_shift) & (reg_size - 1);
5550 
5551   if ((non_shift_bits > high_bit) || (non_shift_bits == 0)) {
5552     switch (extend) {
5553       case UXTB:
5554       case UXTH:
5555       case UXTW:
5556         ubfm(rd, rn_, non_shift_bits, high_bit);
5557         break;
5558       case SXTB:
5559       case SXTH:
5560       case SXTW:
5561         sbfm(rd, rn_, non_shift_bits, high_bit);
5562         break;
5563       case UXTX:
5564       case SXTX: {
5565         VIXL_ASSERT(rn.GetSizeInBits() == kXRegSize);
5566         // Nothing to extend. Just shift.
5567         lsl(rd, rn_, left_shift);
5568         break;
5569       }
5570       default:
5571         VIXL_UNREACHABLE();
5572     }
5573   } else {
5574     // No need to extend as the extended bits would be shifted away.
5575     lsl(rd, rn_, left_shift);
5576   }
5577 }
5578 
5579 
DataProcShiftedRegister(const Register & rd,const Register & rn,const Operand & operand,FlagsUpdate S,Instr op)5580 void Assembler::DataProcShiftedRegister(const Register& rd,
5581                                         const Register& rn,
5582                                         const Operand& operand,
5583                                         FlagsUpdate S,
5584                                         Instr op) {
5585   VIXL_ASSERT(operand.IsShiftedRegister());
5586   VIXL_ASSERT(rn.Is64Bits() ||
5587               (rn.Is32Bits() && IsUint5(operand.GetShiftAmount())));
5588   Emit(SF(rd) | op | Flags(S) | ShiftDP(operand.GetShift()) |
5589        ImmDPShift(operand.GetShiftAmount()) | Rm(operand.GetRegister()) |
5590        Rn(rn) | Rd(rd));
5591 }
5592 
5593 
DataProcExtendedRegister(const Register & rd,const Register & rn,const Operand & operand,FlagsUpdate S,Instr op)5594 void Assembler::DataProcExtendedRegister(const Register& rd,
5595                                          const Register& rn,
5596                                          const Operand& operand,
5597                                          FlagsUpdate S,
5598                                          Instr op) {
5599   Instr dest_reg = (S == SetFlags) ? Rd(rd) : RdSP(rd);
5600   Emit(SF(rd) | op | Flags(S) | Rm(operand.GetRegister()) |
5601        ExtendMode(operand.GetExtend()) |
5602        ImmExtendShift(operand.GetShiftAmount()) | dest_reg | RnSP(rn));
5603 }
5604 
5605 
LoadStoreMemOperand(const MemOperand & addr,unsigned access_size,LoadStoreScalingOption option)5606 Instr Assembler::LoadStoreMemOperand(const MemOperand& addr,
5607                                      unsigned access_size,
5608                                      LoadStoreScalingOption option) {
5609   Instr base = RnSP(addr.GetBaseRegister());
5610   int64_t offset = addr.GetOffset();
5611 
5612   if (addr.IsImmediateOffset()) {
5613     bool prefer_unscaled =
5614         (option == PreferUnscaledOffset) || (option == RequireUnscaledOffset);
5615     if (prefer_unscaled && IsImmLSUnscaled(offset)) {
5616       // Use the unscaled addressing mode.
5617       return base | LoadStoreUnscaledOffsetFixed |
5618              ImmLS(static_cast<int>(offset));
5619     }
5620 
5621     if ((option != RequireUnscaledOffset) &&
5622         IsImmLSScaled(offset, access_size)) {
5623       // Use the scaled addressing mode.
5624       return base | LoadStoreUnsignedOffsetFixed |
5625              ImmLSUnsigned(static_cast<int>(offset) >> access_size);
5626     }
5627 
5628     if ((option != RequireScaledOffset) && IsImmLSUnscaled(offset)) {
5629       // Use the unscaled addressing mode.
5630       return base | LoadStoreUnscaledOffsetFixed |
5631              ImmLS(static_cast<int>(offset));
5632     }
5633   }
5634 
5635   // All remaining addressing modes are register-offset, pre-indexed or
5636   // post-indexed modes.
5637   VIXL_ASSERT((option != RequireUnscaledOffset) &&
5638               (option != RequireScaledOffset));
5639 
5640   if (addr.IsRegisterOffset()) {
5641     Extend ext = addr.GetExtend();
5642     Shift shift = addr.GetShift();
5643     unsigned shift_amount = addr.GetShiftAmount();
5644 
5645     // LSL is encoded in the option field as UXTX.
5646     if (shift == LSL) {
5647       ext = UXTX;
5648     }
5649 
5650     // Shifts are encoded in one bit, indicating a left shift by the memory
5651     // access size.
5652     VIXL_ASSERT((shift_amount == 0) || (shift_amount == access_size));
5653     return base | LoadStoreRegisterOffsetFixed | Rm(addr.GetRegisterOffset()) |
5654            ExtendMode(ext) | ImmShiftLS((shift_amount > 0) ? 1 : 0);
5655   }
5656 
5657   if (addr.IsPreIndex() && IsImmLSUnscaled(offset)) {
5658     return base | LoadStorePreIndexFixed | ImmLS(static_cast<int>(offset));
5659   }
5660 
5661   if (addr.IsPostIndex() && IsImmLSUnscaled(offset)) {
5662     return base | LoadStorePostIndexFixed | ImmLS(static_cast<int>(offset));
5663   }
5664 
5665   // If this point is reached, the MemOperand (addr) cannot be encoded.
5666   VIXL_UNREACHABLE();
5667   return 0;
5668 }
5669 
5670 
LoadStore(const CPURegister & rt,const MemOperand & addr,LoadStoreOp op,LoadStoreScalingOption option)5671 void Assembler::LoadStore(const CPURegister& rt,
5672                           const MemOperand& addr,
5673                           LoadStoreOp op,
5674                           LoadStoreScalingOption option) {
5675   VIXL_ASSERT(CPUHas(rt));
5676   Emit(op | Rt(rt) | LoadStoreMemOperand(addr, CalcLSDataSize(op), option));
5677 }
5678 
LoadStorePAC(const Register & xt,const MemOperand & addr,LoadStorePACOp op)5679 void Assembler::LoadStorePAC(const Register& xt,
5680                              const MemOperand& addr,
5681                              LoadStorePACOp op) {
5682   VIXL_ASSERT(xt.Is64Bits());
5683   VIXL_ASSERT(addr.IsImmediateOffset() || addr.IsPreIndex());
5684 
5685   Instr pac_op = op;
5686   if (addr.IsPreIndex()) {
5687     pac_op |= LoadStorePACPreBit;
5688   }
5689 
5690   Instr base = RnSP(addr.GetBaseRegister());
5691   int64_t offset = addr.GetOffset();
5692 
5693   Emit(pac_op | Rt(xt) | base | ImmLSPAC(static_cast<int>(offset)));
5694 }
5695 
5696 
Prefetch(PrefetchOperation op,const MemOperand & addr,LoadStoreScalingOption option)5697 void Assembler::Prefetch(PrefetchOperation op,
5698                          const MemOperand& addr,
5699                          LoadStoreScalingOption option) {
5700   VIXL_ASSERT(addr.IsRegisterOffset() || addr.IsImmediateOffset());
5701 
5702   Instr prfop = ImmPrefetchOperation(op);
5703   Emit(PRFM | prfop | LoadStoreMemOperand(addr, kXRegSizeInBytesLog2, option));
5704 }
5705 
5706 
IsImmAddSub(int64_t immediate)5707 bool Assembler::IsImmAddSub(int64_t immediate) {
5708   return IsUint12(immediate) ||
5709          (IsUint12(immediate >> 12) && ((immediate & 0xfff) == 0));
5710 }
5711 
5712 
IsImmConditionalCompare(int64_t immediate)5713 bool Assembler::IsImmConditionalCompare(int64_t immediate) {
5714   return IsUint5(immediate);
5715 }
5716 
5717 
IsImmFP16(Float16 imm)5718 bool Assembler::IsImmFP16(Float16 imm) {
5719   // Valid values will have the form:
5720   // aBbb.cdef.gh00.000
5721   uint16_t bits = Float16ToRawbits(imm);
5722   // bits[6..0] are cleared.
5723   if ((bits & 0x3f) != 0) {
5724     return false;
5725   }
5726 
5727   // bits[13..12] are all set or all cleared.
5728   uint16_t b_pattern = (bits >> 12) & 0x03;
5729   if (b_pattern != 0 && b_pattern != 0x03) {
5730     return false;
5731   }
5732 
5733   // bit[15] and bit[14] are opposite.
5734   if (((bits ^ (bits << 1)) & 0x4000) == 0) {
5735     return false;
5736   }
5737 
5738   return true;
5739 }
5740 
5741 
IsImmFP32(float imm)5742 bool Assembler::IsImmFP32(float imm) {
5743   // Valid values will have the form:
5744   // aBbb.bbbc.defg.h000.0000.0000.0000.0000
5745   uint32_t bits = FloatToRawbits(imm);
5746   // bits[19..0] are cleared.
5747   if ((bits & 0x7ffff) != 0) {
5748     return false;
5749   }
5750 
5751   // bits[29..25] are all set or all cleared.
5752   uint32_t b_pattern = (bits >> 16) & 0x3e00;
5753   if (b_pattern != 0 && b_pattern != 0x3e00) {
5754     return false;
5755   }
5756 
5757   // bit[30] and bit[29] are opposite.
5758   if (((bits ^ (bits << 1)) & 0x40000000) == 0) {
5759     return false;
5760   }
5761 
5762   return true;
5763 }
5764 
5765 
IsImmFP64(double imm)5766 bool Assembler::IsImmFP64(double imm) {
5767   // Valid values will have the form:
5768   // aBbb.bbbb.bbcd.efgh.0000.0000.0000.0000
5769   // 0000.0000.0000.0000.0000.0000.0000.0000
5770   uint64_t bits = DoubleToRawbits(imm);
5771   // bits[47..0] are cleared.
5772   if ((bits & 0x0000ffffffffffff) != 0) {
5773     return false;
5774   }
5775 
5776   // bits[61..54] are all set or all cleared.
5777   uint32_t b_pattern = (bits >> 48) & 0x3fc0;
5778   if ((b_pattern != 0) && (b_pattern != 0x3fc0)) {
5779     return false;
5780   }
5781 
5782   // bit[62] and bit[61] are opposite.
5783   if (((bits ^ (bits << 1)) & (UINT64_C(1) << 62)) == 0) {
5784     return false;
5785   }
5786 
5787   return true;
5788 }
5789 
5790 
IsImmLSPair(int64_t offset,unsigned access_size)5791 bool Assembler::IsImmLSPair(int64_t offset, unsigned access_size) {
5792   VIXL_ASSERT(access_size <= kQRegSizeInBytesLog2);
5793   return IsMultiple(offset, 1 << access_size) &&
5794          IsInt7(offset / (1 << access_size));
5795 }
5796 
5797 
IsImmLSScaled(int64_t offset,unsigned access_size)5798 bool Assembler::IsImmLSScaled(int64_t offset, unsigned access_size) {
5799   VIXL_ASSERT(access_size <= kQRegSizeInBytesLog2);
5800   return IsMultiple(offset, 1 << access_size) &&
5801          IsUint12(offset / (1 << access_size));
5802 }
5803 
5804 
IsImmLSUnscaled(int64_t offset)5805 bool Assembler::IsImmLSUnscaled(int64_t offset) { return IsInt9(offset); }
5806 
5807 
5808 // The movn instruction can generate immediates containing an arbitrary 16-bit
5809 // value, with remaining bits set, eg. 0xffff1234, 0xffff1234ffffffff.
IsImmMovn(uint64_t imm,unsigned reg_size)5810 bool Assembler::IsImmMovn(uint64_t imm, unsigned reg_size) {
5811   return IsImmMovz(~imm, reg_size);
5812 }
5813 
5814 
5815 // The movz instruction can generate immediates containing an arbitrary 16-bit
5816 // value, with remaining bits clear, eg. 0x00001234, 0x0000123400000000.
IsImmMovz(uint64_t imm,unsigned reg_size)5817 bool Assembler::IsImmMovz(uint64_t imm, unsigned reg_size) {
5818   VIXL_ASSERT((reg_size == kXRegSize) || (reg_size == kWRegSize));
5819   return CountClearHalfWords(imm, reg_size) >= ((reg_size / 16) - 1);
5820 }
5821 
5822 
5823 // Test if a given value can be encoded in the immediate field of a logical
5824 // instruction.
5825 // If it can be encoded, the function returns true, and values pointed to by n,
5826 // imm_s and imm_r are updated with immediates encoded in the format required
5827 // by the corresponding fields in the logical instruction.
5828 // If it can not be encoded, the function returns false, and the values pointed
5829 // to by n, imm_s and imm_r are undefined.
IsImmLogical(uint64_t value,unsigned width,unsigned * n,unsigned * imm_s,unsigned * imm_r)5830 bool Assembler::IsImmLogical(uint64_t value,
5831                              unsigned width,
5832                              unsigned* n,
5833                              unsigned* imm_s,
5834                              unsigned* imm_r) {
5835   VIXL_ASSERT((width == kWRegSize) || (width == kXRegSize));
5836 
5837   bool negate = false;
5838 
5839   // Logical immediates are encoded using parameters n, imm_s and imm_r using
5840   // the following table:
5841   //
5842   //    N   imms    immr    size        S             R
5843   //    1  ssssss  rrrrrr    64    UInt(ssssss)  UInt(rrrrrr)
5844   //    0  0sssss  xrrrrr    32    UInt(sssss)   UInt(rrrrr)
5845   //    0  10ssss  xxrrrr    16    UInt(ssss)    UInt(rrrr)
5846   //    0  110sss  xxxrrr     8    UInt(sss)     UInt(rrr)
5847   //    0  1110ss  xxxxrr     4    UInt(ss)      UInt(rr)
5848   //    0  11110s  xxxxxr     2    UInt(s)       UInt(r)
5849   // (s bits must not be all set)
5850   //
5851   // A pattern is constructed of size bits, where the least significant S+1 bits
5852   // are set. The pattern is rotated right by R, and repeated across a 32 or
5853   // 64-bit value, depending on destination register width.
5854   //
5855   // Put another way: the basic format of a logical immediate is a single
5856   // contiguous stretch of 1 bits, repeated across the whole word at intervals
5857   // given by a power of 2. To identify them quickly, we first locate the
5858   // lowest stretch of 1 bits, then the next 1 bit above that; that combination
5859   // is different for every logical immediate, so it gives us all the
5860   // information we need to identify the only logical immediate that our input
5861   // could be, and then we simply check if that's the value we actually have.
5862   //
5863   // (The rotation parameter does give the possibility of the stretch of 1 bits
5864   // going 'round the end' of the word. To deal with that, we observe that in
5865   // any situation where that happens the bitwise NOT of the value is also a
5866   // valid logical immediate. So we simply invert the input whenever its low bit
5867   // is set, and then we know that the rotated case can't arise.)
5868 
5869   if (value & 1) {
5870     // If the low bit is 1, negate the value, and set a flag to remember that we
5871     // did (so that we can adjust the return values appropriately).
5872     negate = true;
5873     value = ~value;
5874   }
5875 
5876   if (width == kWRegSize) {
5877     // To handle 32-bit logical immediates, the very easiest thing is to repeat
5878     // the input value twice to make a 64-bit word. The correct encoding of that
5879     // as a logical immediate will also be the correct encoding of the 32-bit
5880     // value.
5881 
5882     // Avoid making the assumption that the most-significant 32 bits are zero by
5883     // shifting the value left and duplicating it.
5884     value <<= kWRegSize;
5885     value |= value >> kWRegSize;
5886   }
5887 
5888   // The basic analysis idea: imagine our input word looks like this.
5889   //
5890   //    0011111000111110001111100011111000111110001111100011111000111110
5891   //                                                          c  b    a
5892   //                                                          |<--d-->|
5893   //
5894   // We find the lowest set bit (as an actual power-of-2 value, not its index)
5895   // and call it a. Then we add a to our original number, which wipes out the
5896   // bottommost stretch of set bits and replaces it with a 1 carried into the
5897   // next zero bit. Then we look for the new lowest set bit, which is in
5898   // position b, and subtract it, so now our number is just like the original
5899   // but with the lowest stretch of set bits completely gone. Now we find the
5900   // lowest set bit again, which is position c in the diagram above. Then we'll
5901   // measure the distance d between bit positions a and c (using CLZ), and that
5902   // tells us that the only valid logical immediate that could possibly be equal
5903   // to this number is the one in which a stretch of bits running from a to just
5904   // below b is replicated every d bits.
5905   uint64_t a = LowestSetBit(value);
5906   uint64_t value_plus_a = value + a;
5907   uint64_t b = LowestSetBit(value_plus_a);
5908   uint64_t value_plus_a_minus_b = value_plus_a - b;
5909   uint64_t c = LowestSetBit(value_plus_a_minus_b);
5910 
5911   int d, clz_a, out_n;
5912   uint64_t mask;
5913 
5914   if (c != 0) {
5915     // The general case, in which there is more than one stretch of set bits.
5916     // Compute the repeat distance d, and set up a bitmask covering the basic
5917     // unit of repetition (i.e. a word with the bottom d bits set). Also, in all
5918     // of these cases the N bit of the output will be zero.
5919     clz_a = CountLeadingZeros(a, kXRegSize);
5920     int clz_c = CountLeadingZeros(c, kXRegSize);
5921     d = clz_a - clz_c;
5922     mask = ((UINT64_C(1) << d) - 1);
5923     out_n = 0;
5924   } else {
5925     // Handle degenerate cases.
5926     //
5927     // If any of those 'find lowest set bit' operations didn't find a set bit at
5928     // all, then the word will have been zero thereafter, so in particular the
5929     // last lowest_set_bit operation will have returned zero. So we can test for
5930     // all the special case conditions in one go by seeing if c is zero.
5931     if (a == 0) {
5932       // The input was zero (or all 1 bits, which will come to here too after we
5933       // inverted it at the start of the function), for which we just return
5934       // false.
5935       return false;
5936     } else {
5937       // Otherwise, if c was zero but a was not, then there's just one stretch
5938       // of set bits in our word, meaning that we have the trivial case of
5939       // d == 64 and only one 'repetition'. Set up all the same variables as in
5940       // the general case above, and set the N bit in the output.
5941       clz_a = CountLeadingZeros(a, kXRegSize);
5942       d = 64;
5943       mask = ~UINT64_C(0);
5944       out_n = 1;
5945     }
5946   }
5947 
5948   // If the repeat period d is not a power of two, it can't be encoded.
5949   if (!IsPowerOf2(d)) {
5950     return false;
5951   }
5952 
5953   if (((b - a) & ~mask) != 0) {
5954     // If the bit stretch (b - a) does not fit within the mask derived from the
5955     // repeat period, then fail.
5956     return false;
5957   }
5958 
5959   // The only possible option is b - a repeated every d bits. Now we're going to
5960   // actually construct the valid logical immediate derived from that
5961   // specification, and see if it equals our original input.
5962   //
5963   // To repeat a value every d bits, we multiply it by a number of the form
5964   // (1 + 2^d + 2^(2d) + ...), i.e. 0x0001000100010001 or similar. These can
5965   // be derived using a table lookup on CLZ(d).
5966   static const uint64_t multipliers[] = {
5967       0x0000000000000001UL,
5968       0x0000000100000001UL,
5969       0x0001000100010001UL,
5970       0x0101010101010101UL,
5971       0x1111111111111111UL,
5972       0x5555555555555555UL,
5973   };
5974   uint64_t multiplier = multipliers[CountLeadingZeros(d, kXRegSize) - 57];
5975   uint64_t candidate = (b - a) * multiplier;
5976 
5977   if (value != candidate) {
5978     // The candidate pattern doesn't match our input value, so fail.
5979     return false;
5980   }
5981 
5982   // We have a match! This is a valid logical immediate, so now we have to
5983   // construct the bits and pieces of the instruction encoding that generates
5984   // it.
5985 
5986   // Count the set bits in our basic stretch. The special case of clz(0) == -1
5987   // makes the answer come out right for stretches that reach the very top of
5988   // the word (e.g. numbers like 0xffffc00000000000).
5989   int clz_b = (b == 0) ? -1 : CountLeadingZeros(b, kXRegSize);
5990   int s = clz_a - clz_b;
5991 
5992   // Decide how many bits to rotate right by, to put the low bit of that basic
5993   // stretch in position a.
5994   int r;
5995   if (negate) {
5996     // If we inverted the input right at the start of this function, here's
5997     // where we compensate: the number of set bits becomes the number of clear
5998     // bits, and the rotation count is based on position b rather than position
5999     // a (since b is the location of the 'lowest' 1 bit after inversion).
6000     s = d - s;
6001     r = (clz_b + 1) & (d - 1);
6002   } else {
6003     r = (clz_a + 1) & (d - 1);
6004   }
6005 
6006   // Now we're done, except for having to encode the S output in such a way that
6007   // it gives both the number of set bits and the length of the repeated
6008   // segment. The s field is encoded like this:
6009   //
6010   //     imms    size        S
6011   //    ssssss    64    UInt(ssssss)
6012   //    0sssss    32    UInt(sssss)
6013   //    10ssss    16    UInt(ssss)
6014   //    110sss     8    UInt(sss)
6015   //    1110ss     4    UInt(ss)
6016   //    11110s     2    UInt(s)
6017   //
6018   // So we 'or' (2 * -d) with our computed s to form imms.
6019   if ((n != NULL) || (imm_s != NULL) || (imm_r != NULL)) {
6020     *n = out_n;
6021     *imm_s = ((2 * -d) | (s - 1)) & 0x3f;
6022     *imm_r = r;
6023   }
6024 
6025   return true;
6026 }
6027 
6028 
LoadOpFor(const CPURegister & rt)6029 LoadStoreOp Assembler::LoadOpFor(const CPURegister& rt) {
6030   VIXL_ASSERT(rt.IsValid());
6031   if (rt.IsRegister()) {
6032     return rt.Is64Bits() ? LDR_x : LDR_w;
6033   } else {
6034     VIXL_ASSERT(rt.IsVRegister());
6035     switch (rt.GetSizeInBits()) {
6036       case kBRegSize:
6037         return LDR_b;
6038       case kHRegSize:
6039         return LDR_h;
6040       case kSRegSize:
6041         return LDR_s;
6042       case kDRegSize:
6043         return LDR_d;
6044       default:
6045         VIXL_ASSERT(rt.IsQ());
6046         return LDR_q;
6047     }
6048   }
6049 }
6050 
6051 
StoreOpFor(const CPURegister & rt)6052 LoadStoreOp Assembler::StoreOpFor(const CPURegister& rt) {
6053   VIXL_ASSERT(rt.IsValid());
6054   if (rt.IsRegister()) {
6055     return rt.Is64Bits() ? STR_x : STR_w;
6056   } else {
6057     VIXL_ASSERT(rt.IsVRegister());
6058     switch (rt.GetSizeInBits()) {
6059       case kBRegSize:
6060         return STR_b;
6061       case kHRegSize:
6062         return STR_h;
6063       case kSRegSize:
6064         return STR_s;
6065       case kDRegSize:
6066         return STR_d;
6067       default:
6068         VIXL_ASSERT(rt.IsQ());
6069         return STR_q;
6070     }
6071   }
6072 }
6073 
6074 
StorePairOpFor(const CPURegister & rt,const CPURegister & rt2)6075 LoadStorePairOp Assembler::StorePairOpFor(const CPURegister& rt,
6076                                           const CPURegister& rt2) {
6077   VIXL_ASSERT(AreSameSizeAndType(rt, rt2));
6078   USE(rt2);
6079   if (rt.IsRegister()) {
6080     return rt.Is64Bits() ? STP_x : STP_w;
6081   } else {
6082     VIXL_ASSERT(rt.IsVRegister());
6083     switch (rt.GetSizeInBytes()) {
6084       case kSRegSizeInBytes:
6085         return STP_s;
6086       case kDRegSizeInBytes:
6087         return STP_d;
6088       default:
6089         VIXL_ASSERT(rt.IsQ());
6090         return STP_q;
6091     }
6092   }
6093 }
6094 
6095 
LoadPairOpFor(const CPURegister & rt,const CPURegister & rt2)6096 LoadStorePairOp Assembler::LoadPairOpFor(const CPURegister& rt,
6097                                          const CPURegister& rt2) {
6098   VIXL_ASSERT((STP_w | LoadStorePairLBit) == LDP_w);
6099   return static_cast<LoadStorePairOp>(StorePairOpFor(rt, rt2) |
6100                                       LoadStorePairLBit);
6101 }
6102 
6103 
StorePairNonTemporalOpFor(const CPURegister & rt,const CPURegister & rt2)6104 LoadStorePairNonTemporalOp Assembler::StorePairNonTemporalOpFor(
6105     const CPURegister& rt, const CPURegister& rt2) {
6106   VIXL_ASSERT(AreSameSizeAndType(rt, rt2));
6107   USE(rt2);
6108   if (rt.IsRegister()) {
6109     return rt.Is64Bits() ? STNP_x : STNP_w;
6110   } else {
6111     VIXL_ASSERT(rt.IsVRegister());
6112     switch (rt.GetSizeInBytes()) {
6113       case kSRegSizeInBytes:
6114         return STNP_s;
6115       case kDRegSizeInBytes:
6116         return STNP_d;
6117       default:
6118         VIXL_ASSERT(rt.IsQ());
6119         return STNP_q;
6120     }
6121   }
6122 }
6123 
6124 
LoadPairNonTemporalOpFor(const CPURegister & rt,const CPURegister & rt2)6125 LoadStorePairNonTemporalOp Assembler::LoadPairNonTemporalOpFor(
6126     const CPURegister& rt, const CPURegister& rt2) {
6127   VIXL_ASSERT((STNP_w | LoadStorePairNonTemporalLBit) == LDNP_w);
6128   return static_cast<LoadStorePairNonTemporalOp>(
6129       StorePairNonTemporalOpFor(rt, rt2) | LoadStorePairNonTemporalLBit);
6130 }
6131 
6132 
LoadLiteralOpFor(const CPURegister & rt)6133 LoadLiteralOp Assembler::LoadLiteralOpFor(const CPURegister& rt) {
6134   if (rt.IsRegister()) {
6135     return rt.IsX() ? LDR_x_lit : LDR_w_lit;
6136   } else {
6137     VIXL_ASSERT(rt.IsVRegister());
6138     switch (rt.GetSizeInBytes()) {
6139       case kSRegSizeInBytes:
6140         return LDR_s_lit;
6141       case kDRegSizeInBytes:
6142         return LDR_d_lit;
6143       default:
6144         VIXL_ASSERT(rt.IsQ());
6145         return LDR_q_lit;
6146     }
6147   }
6148 }
6149 
6150 
CPUHas(const CPURegister & rt) const6151 bool Assembler::CPUHas(const CPURegister& rt) const {
6152   // Core registers are available without any particular CPU features.
6153   if (rt.IsRegister()) return true;
6154   VIXL_ASSERT(rt.IsVRegister());
6155   // The architecture does not allow FP and NEON to be implemented separately,
6156   // but we can crudely categorise them based on register size, since FP only
6157   // uses D, S and (occasionally) H registers.
6158   if (rt.IsH() || rt.IsS() || rt.IsD()) {
6159     return CPUHas(CPUFeatures::kFP) || CPUHas(CPUFeatures::kNEON);
6160   }
6161   VIXL_ASSERT(rt.IsB() || rt.IsQ());
6162   return CPUHas(CPUFeatures::kNEON);
6163 }
6164 
6165 
CPUHas(const CPURegister & rt,const CPURegister & rt2) const6166 bool Assembler::CPUHas(const CPURegister& rt, const CPURegister& rt2) const {
6167   // This is currently only used for loads and stores, where rt and rt2 must
6168   // have the same size and type. We could extend this to cover other cases if
6169   // necessary, but for now we can avoid checking both registers.
6170   VIXL_ASSERT(AreSameSizeAndType(rt, rt2));
6171   USE(rt2);
6172   return CPUHas(rt);
6173 }
6174 
6175 
CPUHas(SystemRegister sysreg) const6176 bool Assembler::CPUHas(SystemRegister sysreg) const {
6177   switch (sysreg) {
6178     case RNDR:
6179     case RNDRRS:
6180       return CPUHas(CPUFeatures::kRNG);
6181     case FPCR:
6182     case NZCV:
6183       break;
6184   }
6185   return true;
6186 }
6187 
6188 
AreAliased(const CPURegister & reg1,const CPURegister & reg2,const CPURegister & reg3,const CPURegister & reg4,const CPURegister & reg5,const CPURegister & reg6,const CPURegister & reg7,const CPURegister & reg8)6189 bool AreAliased(const CPURegister& reg1,
6190                 const CPURegister& reg2,
6191                 const CPURegister& reg3,
6192                 const CPURegister& reg4,
6193                 const CPURegister& reg5,
6194                 const CPURegister& reg6,
6195                 const CPURegister& reg7,
6196                 const CPURegister& reg8) {
6197   int number_of_valid_regs = 0;
6198   int number_of_valid_fpregs = 0;
6199 
6200   RegList unique_regs = 0;
6201   RegList unique_fpregs = 0;
6202 
6203   const CPURegister regs[] = {reg1, reg2, reg3, reg4, reg5, reg6, reg7, reg8};
6204 
6205   for (size_t i = 0; i < ArrayLength(regs); i++) {
6206     if (regs[i].IsRegister()) {
6207       number_of_valid_regs++;
6208       unique_regs |= regs[i].GetBit();
6209     } else if (regs[i].IsVRegister()) {
6210       number_of_valid_fpregs++;
6211       unique_fpregs |= regs[i].GetBit();
6212     } else {
6213       VIXL_ASSERT(!regs[i].IsValid());
6214     }
6215   }
6216 
6217   int number_of_unique_regs = CountSetBits(unique_regs);
6218   int number_of_unique_fpregs = CountSetBits(unique_fpregs);
6219 
6220   VIXL_ASSERT(number_of_valid_regs >= number_of_unique_regs);
6221   VIXL_ASSERT(number_of_valid_fpregs >= number_of_unique_fpregs);
6222 
6223   return (number_of_valid_regs != number_of_unique_regs) ||
6224          (number_of_valid_fpregs != number_of_unique_fpregs);
6225 }
6226 
6227 
AreSameSizeAndType(const CPURegister & reg1,const CPURegister & reg2,const CPURegister & reg3,const CPURegister & reg4,const CPURegister & reg5,const CPURegister & reg6,const CPURegister & reg7,const CPURegister & reg8)6228 bool AreSameSizeAndType(const CPURegister& reg1,
6229                         const CPURegister& reg2,
6230                         const CPURegister& reg3,
6231                         const CPURegister& reg4,
6232                         const CPURegister& reg5,
6233                         const CPURegister& reg6,
6234                         const CPURegister& reg7,
6235                         const CPURegister& reg8) {
6236   VIXL_ASSERT(reg1.IsValid());
6237   bool match = true;
6238   match &= !reg2.IsValid() || reg2.IsSameSizeAndType(reg1);
6239   match &= !reg3.IsValid() || reg3.IsSameSizeAndType(reg1);
6240   match &= !reg4.IsValid() || reg4.IsSameSizeAndType(reg1);
6241   match &= !reg5.IsValid() || reg5.IsSameSizeAndType(reg1);
6242   match &= !reg6.IsValid() || reg6.IsSameSizeAndType(reg1);
6243   match &= !reg7.IsValid() || reg7.IsSameSizeAndType(reg1);
6244   match &= !reg8.IsValid() || reg8.IsSameSizeAndType(reg1);
6245   return match;
6246 }
6247 
AreEven(const CPURegister & reg1,const CPURegister & reg2,const CPURegister & reg3,const CPURegister & reg4,const CPURegister & reg5,const CPURegister & reg6,const CPURegister & reg7,const CPURegister & reg8)6248 bool AreEven(const CPURegister& reg1,
6249              const CPURegister& reg2,
6250              const CPURegister& reg3,
6251              const CPURegister& reg4,
6252              const CPURegister& reg5,
6253              const CPURegister& reg6,
6254              const CPURegister& reg7,
6255              const CPURegister& reg8) {
6256   VIXL_ASSERT(reg1.IsValid());
6257   bool even = (reg1.GetCode() % 2) == 0;
6258   even &= !reg2.IsValid() || ((reg2.GetCode() % 2) == 0);
6259   even &= !reg3.IsValid() || ((reg3.GetCode() % 2) == 0);
6260   even &= !reg4.IsValid() || ((reg4.GetCode() % 2) == 0);
6261   even &= !reg5.IsValid() || ((reg5.GetCode() % 2) == 0);
6262   even &= !reg6.IsValid() || ((reg6.GetCode() % 2) == 0);
6263   even &= !reg7.IsValid() || ((reg7.GetCode() % 2) == 0);
6264   even &= !reg8.IsValid() || ((reg8.GetCode() % 2) == 0);
6265   return even;
6266 }
6267 
6268 
AreConsecutive(const CPURegister & reg1,const CPURegister & reg2,const CPURegister & reg3,const CPURegister & reg4)6269 bool AreConsecutive(const CPURegister& reg1,
6270                     const CPURegister& reg2,
6271                     const CPURegister& reg3,
6272                     const CPURegister& reg4) {
6273   VIXL_ASSERT(reg1.IsValid());
6274 
6275   if (!reg2.IsValid()) {
6276     return true;
6277   } else if (reg2.GetCode() != ((reg1.GetCode() + 1) % kNumberOfRegisters)) {
6278     return false;
6279   }
6280 
6281   if (!reg3.IsValid()) {
6282     return true;
6283   } else if (reg3.GetCode() != ((reg2.GetCode() + 1) % kNumberOfRegisters)) {
6284     return false;
6285   }
6286 
6287   if (!reg4.IsValid()) {
6288     return true;
6289   } else if (reg4.GetCode() != ((reg3.GetCode() + 1) % kNumberOfRegisters)) {
6290     return false;
6291   }
6292 
6293   return true;
6294 }
6295 
6296 
AreSameFormat(const VRegister & reg1,const VRegister & reg2,const VRegister & reg3,const VRegister & reg4)6297 bool AreSameFormat(const VRegister& reg1,
6298                    const VRegister& reg2,
6299                    const VRegister& reg3,
6300                    const VRegister& reg4) {
6301   VIXL_ASSERT(reg1.IsValid());
6302   bool match = true;
6303   match &= !reg2.IsValid() || reg2.IsSameFormat(reg1);
6304   match &= !reg3.IsValid() || reg3.IsSameFormat(reg1);
6305   match &= !reg4.IsValid() || reg4.IsSameFormat(reg1);
6306   return match;
6307 }
6308 
6309 
AreConsecutive(const VRegister & reg1,const VRegister & reg2,const VRegister & reg3,const VRegister & reg4)6310 bool AreConsecutive(const VRegister& reg1,
6311                     const VRegister& reg2,
6312                     const VRegister& reg3,
6313                     const VRegister& reg4) {
6314   VIXL_ASSERT(reg1.IsValid());
6315 
6316   if (!reg2.IsValid()) {
6317     return true;
6318   } else if (reg2.GetCode() != ((reg1.GetCode() + 1) % kNumberOfVRegisters)) {
6319     return false;
6320   }
6321 
6322   if (!reg3.IsValid()) {
6323     return true;
6324   } else if (reg3.GetCode() != ((reg2.GetCode() + 1) % kNumberOfVRegisters)) {
6325     return false;
6326   }
6327 
6328   if (!reg4.IsValid()) {
6329     return true;
6330   } else if (reg4.GetCode() != ((reg3.GetCode() + 1) % kNumberOfVRegisters)) {
6331     return false;
6332   }
6333 
6334   return true;
6335 }
6336 }  // namespace aarch64
6337 }  // namespace vixl
6338