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