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